diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..2113e3d7 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,9 @@ +language: java +jdk: + - openjdk9 + - openjdk10 + - openjdk14 +# - oraclejdk9 + - oraclejdk11 +notifications: + email: false diff --git a/build.xml b/build.xml new file mode 100644 index 00000000..49f70b58 --- /dev/null +++ b/build.xml @@ -0,0 +1,103 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pom.xml b/pom.xml new file mode 100755 index 00000000..a3dcbc19 --- /dev/null +++ b/pom.xml @@ -0,0 +1,207 @@ + + 4.0.0 + + com.esri.geometry + esri-geometry-api + 2.2.3 + jar + + Esri Geometry API for Java + The Esri Geometry API for Java enables developers to write custom applications for analysis of spatial data. + + https://github.com/Esri/geometry-api-java + + + + The Apache Software License, Version 2.0 + http://www.apache.org/licenses/LICENSE-2.0.txt + repo + + + + + + stolstov + Sergey Tolstov + Esri + http://www.esri.com + + developer + + + + abalog + Aaron Balog + Esri + http://www.esri.com + + developer + + + + + + scm:git:git@github.com:Esri/geometry-api-java.git + scm:git:git@github.com:Esri/geometry-api-java.git + git@github.com:Esri/geometry-api-java.git + + + + + release-sign-artifacts + + + performRelease + true + + + + + + org.apache.maven.plugins + maven-gpg-plugin + + + sign-artifacts + verify + + sign + + + + + + + + + java8-disable-doclint + + [1.8,) + + + -Xdoclint:none + + + + + + + ossrh + https://oss.sonatype.org/content/repositories/snapshots + + + + + UTF-8 + + 1.7 + 1.7 + + + 2.9.6 + 4.12 + 0.9 + + + 2.3.1 + 2.2.1 + 3.0.0-M1 + + + + + com.fasterxml.jackson.core + jackson-core + ${jackson.version} + false + + + + + junit + junit + ${junit.version} + test + + + org.openjdk.jol + jol-core + ${jol.version} + test + + + + + ${project.basedir}/target + ${project.build.directory}/classes + ${project.artifactId}-${project.version} + ${project.build.directory}/test-classes + ${project.basedir}/src/main/java + src/main/scripts + ${project.basedir}/src/test/java + + + ${project.basedir}/src/main/resources + + + + + ${project.basedir}/src/test/resources + + + + + maven-compiler-plugin + ${compiler.plugin.version} + + ${java.source.version} + ${java.target.version} + + + + org.apache.maven.plugins + maven-source-plugin + ${source.plugin.version} + + + attach-sources + + jar + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + ${javadoc.plugin.version} + + http://help.arcgis.com/EN/sdk/10.0/Java_AO_ADF/api/arcobjects + http://docs.oracle.com/javase/6/docs/api/ + + + + attach-javadocs + + jar + + + ${javadoc.doclint.param} + + + + + + org.sonatype.plugins + nexus-staging-maven-plugin + 1.6.8 + true + + ossrh + https://oss.sonatype.org/ + true + + + + + diff --git a/src/main/java/com/esri/core/geometry/AttributeStreamBase.java b/src/main/java/com/esri/core/geometry/AttributeStreamBase.java index aac7b2a3..91e8464a 100644 --- a/src/main/java/com/esri/core/geometry/AttributeStreamBase.java +++ b/src/main/java/com/esri/core/geometry/AttributeStreamBase.java @@ -34,18 +34,18 @@ */ abstract class AttributeStreamBase { - protected boolean m_bLockedInSize; - protected boolean m_bReadonly; + protected boolean m_bLockedInSize; + protected boolean m_bReadonly; - public AttributeStreamBase() { - m_bReadonly = false; - m_bLockedInSize = false; - } + public AttributeStreamBase() { + m_bReadonly = false; + m_bLockedInSize = false; + } - /** - * Returns the number of elements in the stream. - */ - public abstract int virtualSize(); + /** + * Returns the number of elements in the stream. + */ + public abstract int virtualSize(); /** * Returns an estimate of this object size in bytes. @@ -59,399 +59,399 @@ public AttributeStreamBase() { */ public abstract int getPersistence(); - /** - * Reads given element and returns it as double. - */ - public abstract double readAsDbl(int offset); - - /** - * Writes given element as double. The double is cast to the internal - * representation (truncated when int). - */ - public abstract void writeAsDbl(int offset, double d); - - /** - * Reads given element and returns it as int (truncated if double). - */ - public abstract int readAsInt(int offset); - - /** - * Writes given element as int. The int is cast to the internal - * representation. - */ - public abstract void writeAsInt(int offset, int d); - - /** - * Reads given element and returns it as int (truncated if double). - */ - public abstract long readAsInt64(int offset); - - /** - * Writes given element as int. The int is cast to the internal - * representation. - */ - public abstract void writeAsInt64(int offset, long d); - - /** - * Resizes the AttributeStream to the new size. - */ - public abstract void resize(int newSize, double defaultValue); - - /** - * Resizes the AttributeStream to the new size. - */ - public abstract void resize(int newSize); - - /** - * Resizes the AttributeStream to the new size. Does not change the capacity - * of the stream. - */ - public abstract void resizePreserveCapacity(int newSize);// java only method - - /** - * Same as resize(0) - */ - void clear(boolean bFreeMemory) { - if (bFreeMemory) - resize(0); - else - resizePreserveCapacity(0); - } - - /** - * Adds a range of elements from the source stream. The streams must be of - * the same type. - * - * @param src The source stream to read elements from. - * @param srcStart The index of the element in the source stream to start reading - * from. - * @param count The number of elements to add. - * @param bForward True if adding the elements in order of the incoming source - * stream. False if adding the elements in reverse. - * @param stride The number of elements to be grouped together if adding the - * elements in reverse. - */ - public abstract void addRange(AttributeStreamBase src, int srcStart, - int count, boolean bForward, int stride); - - /** - * Inserts a range of elements from the source stream. The streams must be - * of the same type. - * - * @param start The index where to start the insert. - * @param src The source stream to read elements from. - * @param srcStart The index of the element in the source stream to start reading - * from. - * @param count The number of elements to read from the source stream. - * @param validSize The number of valid elements in this stream. - */ - public abstract void insertRange(int start, AttributeStreamBase src, - int srcStart, int count, boolean bForward, int stride, int validSize); - - /** - * Inserts a range of elements of the given value. - * - * @param start The index where to start the insert. - * @param value The value to be inserted. - * @param count The number of elements to be inserted. - * @param validSize The number of valid elements in this stream. - */ - public abstract void insertRange(int start, double value, int count, - int validSize); - - /** - * Inserts the attributes of a given semantics from a Point geometry. - * - * @param start The index where to start the insert. - * @param pt The Point geometry holding the attributes to be inserted. - * @param semantics The attribute semantics that are being inserted. - * @param validSize The number of valid elements in this stream. - */ - public abstract void insertAttributes(int start, Point pt, int semantics, - int validSize); - - /** - * Sets a range of values to given value. - * - * @param value The value to set stream elements to. - * @param start The index of the element to start writing to. - * @param count The number of elements to set. - */ - public abstract void setRange(double value, int start, int count); - - /** - * Adds a range of elements from the source byte buffer. This stream is - * resized automatically to accomodate required number of elements. - * - * @param startElement the index of the element in this stream to start setting - * elements from. - * @param count The number of AttributeStream elements to read. - * @param src The source ByteBuffer to read elements from. - * @param sourceStart The offset from the start of the ByteBuffer in bytes. - * @param bForward When False, the source is written in reversed order. - * @param stride Used for reversed writing only to indicate the unit of - * writing. elements inside a stride are not reversed. Only the - * strides are reversed. - */ - public abstract void writeRange(int startElement, int count, - AttributeStreamBase src, int sourceStart, boolean bForward, - int stride); - - /** - * Adds a range of elements from the source byte buffer. The stream is - * resized automatically to accomodate required number of elements. - * - * @param startElement the index of the element in this stream to start setting - * elements from. - * @param count The number of AttributeStream elements to read. - * @param src The source ByteBuffer to read elements from. - * @param offsetBytes The offset from the start of the ByteBuffer in bytes. - */ - public abstract void writeRange(int startElement, int count, - ByteBuffer src, int offsetBytes, boolean bForward); - - /** - * Write a range of elements to the source byte buffer. - * - * @param srcStart The element index to start writing from. - * @param count The number of AttributeStream elements to write. - * @param dst The destination ByteBuffer. The buffer must be large enough or - * it will throw. - * @param dstOffsetBytes The offset in the destination ByteBuffer to start write - * elements from. - */ - public abstract void readRange(int srcStart, int count, ByteBuffer dst, - int dstOffsetBytes, boolean bForward); - - /** - * Erases a range from the buffer and defragments the result. - * - * @param index The index in this stream where the erasing starts. - * @param count The number of elements to be erased. - * @param validSize The number of valid elements in this stream. - */ - public abstract void eraseRange(int index, int count, int validSize); - - /** - * Reverses a range from the buffer. - * - * @param index The index in this stream where the reversing starts. - * @param count The number of elements to be reversed. - * @param stride The number of elements to be grouped together when doing the - * reverse. - */ - public abstract void reverseRange(int index, int count, int stride); - - /** - * Creates a new attribute stream for storing bytes. - * - * @param size The number of elements in the stream. - */ - public static AttributeStreamBase createByteStream(int size) { - AttributeStreamBase newStream = new AttributeStreamOfInt8(size); - return newStream; - } - - /** - * Creates a new attribute stream for storing bytes. - * - * @param size The number of elements in the stream. - * @param defaultValue The default value to fill the stream with. - */ - public static AttributeStreamBase createByteStream(int size, - byte defaultValue) { - AttributeStreamBase newStream = new AttributeStreamOfInt8(size, - defaultValue); - return newStream; - - } - - /** - * Creates a new attribute stream for storing doubles. - * - * @param size The number of elements in the stream. - */ - public static AttributeStreamBase createDoubleStream(int size) { - AttributeStreamBase newStream = new AttributeStreamOfDbl(size); - return newStream; - } - - /** - * Creates a new attribute stream for storing doubles. - * - * @param size The number of elements in the stream. - * @param defaultValue The default value to fill the stream with. - */ - public static AttributeStreamBase createDoubleStream(int size, - double defaultValue) { - AttributeStreamBase newStream = new AttributeStreamOfDbl(size, - defaultValue); - return newStream; - } - - /** - * Creats a copy of the stream that contains upto maxsize elements. - */ - public abstract AttributeStreamBase restrictedClone(int maxsize); - - /** - * Makes the stream to be readonly. Any operation that changes the content - * or size of the stream will throw. - */ - public void setReadonly() { - m_bReadonly = true; - m_bLockedInSize = true; - } - - public boolean isReadonly() { - return m_bReadonly; - } - - /** - * Lock the size of the stream. Any operation that changes the size of the - * stream will throw. - */ - public void lockSize() { - m_bLockedInSize = true; - } - - public boolean isLockedSize() { - return m_bLockedInSize; - } - - /** - * Creates a new attribute stream of given persistence type and size. - * - * @param persistence The persistence type of the stream (see VertexDescription). - * @param size The number of elements (floats, doubles, or 32 bit integers) - * of the given type in the stream. - */ - public static AttributeStreamBase createAttributeStreamWithPersistence( - int persistence, int size) { - AttributeStreamBase newStream; - switch (persistence) { - case (Persistence.enumFloat): - newStream = new AttributeStreamOfFloat(size); - break; - case (Persistence.enumDouble): - newStream = new AttributeStreamOfDbl(size); - break; - case (Persistence.enumInt32): - newStream = new AttributeStreamOfInt32(size); - break; - case (Persistence.enumInt64): - newStream = new AttributeStreamOfInt64(size); - break; - case (Persistence.enumInt8): - newStream = new AttributeStreamOfInt8(size); - break; - case (Persistence.enumInt16): - newStream = new AttributeStreamOfInt16(size); - break; - default: - throw new GeometryException("Internal Error"); - } - return newStream; - } - - /** - * Creates a new attribute stream of given persistence type and size. - * - * @param persistence The persistence type of the stream (see VertexDescription). - * @param size The number of elements (floats, doubles, or 32 bit integers) - * of the given type in the stream. - * @param defaultValue The default value to fill the stream with. - */ - public static AttributeStreamBase createAttributeStreamWithPersistence( - int persistence, int size, double defaultValue) { - AttributeStreamBase newStream; - switch (persistence) { - case (Persistence.enumFloat): - newStream = new AttributeStreamOfFloat(size, (float) defaultValue); - break; - case (Persistence.enumDouble): - newStream = new AttributeStreamOfDbl(size, (double) defaultValue); - break; - case (Persistence.enumInt32): - newStream = new AttributeStreamOfInt32(size, (int) defaultValue); - break; - case (Persistence.enumInt64): - newStream = new AttributeStreamOfInt64(size, (long) defaultValue); - break; - case (Persistence.enumInt8): - newStream = new AttributeStreamOfInt8(size, (byte) defaultValue); - break; - case (Persistence.enumInt16): - newStream = new AttributeStreamOfInt16(size, (short) defaultValue); - break; - default: - throw new GeometryException("Internal Error"); - } - return newStream; - } - - /** - * Creates a new attribute stream for the given semantics and vertex count. - * - * @param semantics The semantics of the attribute (see VertexDescription). - * @param vertexCount The number of vertices in the geometry. The actual number of - * elements in the stream is vertexCount * ncomponents. - */ - public static AttributeStreamBase createAttributeStreamWithSemantics( - int semantics, int vertexCount) { - int ncomps = VertexDescription.getComponentCount(semantics); - int persistence = VertexDescription.getPersistence(semantics); - return createAttributeStreamWithPersistence(persistence, vertexCount - * ncomps, VertexDescription.getDefaultValue(semantics)); - } - - /** - * Creates a new attribute stream for storing vertex indices. - * - * @param size The number of elements in the stream. - */ - public static AttributeStreamBase createIndexStream(int size) { - int persistence = Persistence.enumInt32;// VertexDescription.getPersistenceFromInt(NumberUtils::SizeOf((int)0)); - AttributeStreamBase newStream; - switch (persistence) { - case (Persistence.enumInt32): - newStream = new AttributeStreamOfInt32(size); - break; - case (Persistence.enumInt64): - newStream = new AttributeStreamOfInt64(size); - break; - default: - throw new GeometryException("Internal Error"); - } - return newStream; - - } - - /** - * Creates a new attribute stream for storing vertex indices. - * - * @param size The number of elements in the stream. - * @param defaultValue The default value to fill the stream with. - */ - public static AttributeStreamBase createIndexStream(int size, - int defaultValue) { - int persistence = Persistence.enumInt32;// VertexDescription.getPersistenceFromInt(NumberUtils::SizeOf((int)0)); - AttributeStreamBase newStream; - switch (persistence) { - case (Persistence.enumInt32): - newStream = new AttributeStreamOfInt32(size, (int) defaultValue); - break; - case (Persistence.enumInt64): - newStream = new AttributeStreamOfInt64(size, (long) defaultValue); - break; - default: - throw new GeometryException("Internal Error"); - } - return newStream; - } - - public abstract int calculateHashImpl(int hashCode, int start, int end); - - public abstract boolean equals(AttributeStreamBase other, int start, int end); + /** + * Reads given element and returns it as double. + */ + public abstract double readAsDbl(int offset); + + /** + * Writes given element as double. The double is cast to the internal + * representation (truncated when int). + */ + public abstract void writeAsDbl(int offset, double d); + + /** + * Reads given element and returns it as int (truncated if double). + */ + public abstract int readAsInt(int offset); + + /** + * Writes given element as int. The int is cast to the internal + * representation. + */ + public abstract void writeAsInt(int offset, int d); + + /** + * Reads given element and returns it as int (truncated if double). + */ + public abstract long readAsInt64(int offset); + + /** + * Writes given element as int. The int is cast to the internal + * representation. + */ + public abstract void writeAsInt64(int offset, long d); + + /** + * Resizes the AttributeStream to the new size. + */ + public abstract void resize(int newSize, double defaultValue); + + /** + * Resizes the AttributeStream to the new size. + */ + public abstract void resize(int newSize); + + /** + * Resizes the AttributeStream to the new size. Does not change the capacity + * of the stream. + */ + public abstract void resizePreserveCapacity(int newSize);// java only method + + /** + * Same as resize(0) + */ + void clear(boolean bFreeMemory) { + if (bFreeMemory) + resize(0); + else + resizePreserveCapacity(0); + } + + /** + * Adds a range of elements from the source stream. The streams must be of + * the same type. + * + * @param src The source stream to read elements from. + * @param srcStart The index of the element in the source stream to start reading + * from. + * @param count The number of elements to add. + * @param bForward True if adding the elements in order of the incoming source + * stream. False if adding the elements in reverse. + * @param stride The number of elements to be grouped together if adding the + * elements in reverse. + */ + public abstract void addRange(AttributeStreamBase src, int srcStart, + int count, boolean bForward, int stride); + + /** + * Inserts a range of elements from the source stream. The streams must be + * of the same type. + * + * @param start The index where to start the insert. + * @param src The source stream to read elements from. + * @param srcStart The index of the element in the source stream to start reading + * from. + * @param count The number of elements to read from the source stream. + * @param validSize The number of valid elements in this stream. + */ + public abstract void insertRange(int start, AttributeStreamBase src, + int srcStart, int count, boolean bForward, int stride, int validSize); + + /** + * Inserts a range of elements of the given value. + * + * @param start The index where to start the insert. + * @param value The value to be inserted. + * @param count The number of elements to be inserted. + * @param validSize The number of valid elements in this stream. + */ + public abstract void insertRange(int start, double value, int count, + int validSize); + + /** + * Inserts the attributes of a given semantics from a Point geometry. + * + * @param start The index where to start the insert. + * @param pt The Point geometry holding the attributes to be inserted. + * @param semantics The attribute semantics that are being inserted. + * @param validSize The number of valid elements in this stream. + */ + public abstract void insertAttributes(int start, Point pt, int semantics, + int validSize); + + /** + * Sets a range of values to given value. + * + * @param value The value to set stream elements to. + * @param start The index of the element to start writing to. + * @param count The number of elements to set. + */ + public abstract void setRange(double value, int start, int count); + + /** + * Adds a range of elements from the source byte buffer. This stream is + * resized automatically to accomodate required number of elements. + * + * @param startElement the index of the element in this stream to start setting + * elements from. + * @param count The number of AttributeStream elements to read. + * @param src The source ByteBuffer to read elements from. + * @param sourceStart The offset from the start of the ByteBuffer in bytes. + * @param bForward When False, the source is written in reversed order. + * @param stride Used for reversed writing only to indicate the unit of + * writing. elements inside a stride are not reversed. Only the + * strides are reversed. + */ + public abstract void writeRange(int startElement, int count, + AttributeStreamBase src, int sourceStart, boolean bForward, + int stride); + + /** + * Adds a range of elements from the source byte buffer. The stream is + * resized automatically to accomodate required number of elements. + * + * @param startElement the index of the element in this stream to start setting + * elements from. + * @param count The number of AttributeStream elements to read. + * @param src The source ByteBuffer to read elements from. + * @param offsetBytes The offset from the start of the ByteBuffer in bytes. + */ + public abstract void writeRange(int startElement, int count, + ByteBuffer src, int offsetBytes, boolean bForward); + + /** + * Write a range of elements to the source byte buffer. + * + * @param srcStart The element index to start writing from. + * @param count The number of AttributeStream elements to write. + * @param dst The destination ByteBuffer. The buffer must be large enough or + * it will throw. + * @param dstOffsetBytes The offset in the destination ByteBuffer to start write + * elements from. + */ + public abstract void readRange(int srcStart, int count, ByteBuffer dst, + int dstOffsetBytes, boolean bForward); + + /** + * Erases a range from the buffer and defragments the result. + * + * @param index The index in this stream where the erasing starts. + * @param count The number of elements to be erased. + * @param validSize The number of valid elements in this stream. + */ + public abstract void eraseRange(int index, int count, int validSize); + + /** + * Reverses a range from the buffer. + * + * @param index The index in this stream where the reversing starts. + * @param count The number of elements to be reversed. + * @param stride The number of elements to be grouped together when doing the + * reverse. + */ + public abstract void reverseRange(int index, int count, int stride); + + /** + * Creates a new attribute stream for storing bytes. + * + * @param size The number of elements in the stream. + */ + public static AttributeStreamBase createByteStream(int size) { + AttributeStreamBase newStream = new AttributeStreamOfInt8(size); + return newStream; + } + + /** + * Creates a new attribute stream for storing bytes. + * + * @param size The number of elements in the stream. + * @param defaultValue The default value to fill the stream with. + */ + public static AttributeStreamBase createByteStream(int size, + byte defaultValue) { + AttributeStreamBase newStream = new AttributeStreamOfInt8(size, + defaultValue); + return newStream; + + } + + /** + * Creates a new attribute stream for storing doubles. + * + * @param size The number of elements in the stream. + */ + public static AttributeStreamBase createDoubleStream(int size) { + AttributeStreamBase newStream = new AttributeStreamOfDbl(size); + return newStream; + } + + /** + * Creates a new attribute stream for storing doubles. + * + * @param size The number of elements in the stream. + * @param defaultValue The default value to fill the stream with. + */ + public static AttributeStreamBase createDoubleStream(int size, + double defaultValue) { + AttributeStreamBase newStream = new AttributeStreamOfDbl(size, + defaultValue); + return newStream; + } + + /** + * Creats a copy of the stream that contains upto maxsize elements. + */ + public abstract AttributeStreamBase restrictedClone(int maxsize); + + /** + * Makes the stream to be readonly. Any operation that changes the content + * or size of the stream will throw. + */ + public void setReadonly() { + m_bReadonly = true; + m_bLockedInSize = true; + } + + public boolean isReadonly() { + return m_bReadonly; + } + + /** + * Lock the size of the stream. Any operation that changes the size of the + * stream will throw. + */ + public void lockSize() { + m_bLockedInSize = true; + } + + public boolean isLockedSize() { + return m_bLockedInSize; + } + + /** + * Creates a new attribute stream of given persistence type and size. + * + * @param persistence The persistence type of the stream (see VertexDescription). + * @param size The number of elements (floats, doubles, or 32 bit integers) + * of the given type in the stream. + */ + public static AttributeStreamBase createAttributeStreamWithPersistence( + int persistence, int size) { + AttributeStreamBase newStream; + switch (persistence) { + case (Persistence.enumFloat): + newStream = new AttributeStreamOfFloat(size); + break; + case (Persistence.enumDouble): + newStream = new AttributeStreamOfDbl(size); + break; + case (Persistence.enumInt32): + newStream = new AttributeStreamOfInt32(size); + break; + case (Persistence.enumInt64): + newStream = new AttributeStreamOfInt64(size); + break; + case (Persistence.enumInt8): + newStream = new AttributeStreamOfInt8(size); + break; + case (Persistence.enumInt16): + newStream = new AttributeStreamOfInt16(size); + break; + default: + throw new GeometryException("Internal Error"); + } + return newStream; + } + + /** + * Creates a new attribute stream of given persistence type and size. + * + * @param persistence The persistence type of the stream (see VertexDescription). + * @param size The number of elements (floats, doubles, or 32 bit integers) + * of the given type in the stream. + * @param defaultValue The default value to fill the stream with. + */ + public static AttributeStreamBase createAttributeStreamWithPersistence( + int persistence, int size, double defaultValue) { + AttributeStreamBase newStream; + switch (persistence) { + case (Persistence.enumFloat): + newStream = new AttributeStreamOfFloat(size, (float) defaultValue); + break; + case (Persistence.enumDouble): + newStream = new AttributeStreamOfDbl(size, (double) defaultValue); + break; + case (Persistence.enumInt32): + newStream = new AttributeStreamOfInt32(size, (int) defaultValue); + break; + case (Persistence.enumInt64): + newStream = new AttributeStreamOfInt64(size, (long) defaultValue); + break; + case (Persistence.enumInt8): + newStream = new AttributeStreamOfInt8(size, (byte) defaultValue); + break; + case (Persistence.enumInt16): + newStream = new AttributeStreamOfInt16(size, (short) defaultValue); + break; + default: + throw new GeometryException("Internal Error"); + } + return newStream; + } + + /** + * Creates a new attribute stream for the given semantics and vertex count. + * + * @param semantics The semantics of the attribute (see VertexDescription). + * @param vertexCount The number of vertices in the geometry. The actual number of + * elements in the stream is vertexCount * ncomponents. + */ + public static AttributeStreamBase createAttributeStreamWithSemantics( + int semantics, int vertexCount) { + int ncomps = VertexDescription.getComponentCount(semantics); + int persistence = VertexDescription.getPersistence(semantics); + return createAttributeStreamWithPersistence(persistence, vertexCount + * ncomps, VertexDescription.getDefaultValue(semantics)); + } + + /** + * Creates a new attribute stream for storing vertex indices. + * + * @param size The number of elements in the stream. + */ + public static AttributeStreamBase createIndexStream(int size) { + int persistence = Persistence.enumInt32;// VertexDescription.getPersistenceFromInt(NumberUtils::SizeOf((int)0)); + AttributeStreamBase newStream; + switch (persistence) { + case (Persistence.enumInt32): + newStream = new AttributeStreamOfInt32(size); + break; + case (Persistence.enumInt64): + newStream = new AttributeStreamOfInt64(size); + break; + default: + throw new GeometryException("Internal Error"); + } + return newStream; + + } + + /** + * Creates a new attribute stream for storing vertex indices. + * + * @param size The number of elements in the stream. + * @param defaultValue The default value to fill the stream with. + */ + public static AttributeStreamBase createIndexStream(int size, + int defaultValue) { + int persistence = Persistence.enumInt32;// VertexDescription.getPersistenceFromInt(NumberUtils::SizeOf((int)0)); + AttributeStreamBase newStream; + switch (persistence) { + case (Persistence.enumInt32): + newStream = new AttributeStreamOfInt32(size, (int) defaultValue); + break; + case (Persistence.enumInt64): + newStream = new AttributeStreamOfInt64(size, (long) defaultValue); + break; + default: + throw new GeometryException("Internal Error"); + } + return newStream; + } + + public abstract int calculateHashImpl(int hashCode, int start, int end); + + public abstract boolean equals(AttributeStreamBase other, int start, int end); } diff --git a/src/main/java/com/esri/core/geometry/AttributeStreamOfDbl.java b/src/main/java/com/esri/core/geometry/AttributeStreamOfDbl.java index 23b33941..2039d065 100644 --- a/src/main/java/com/esri/core/geometry/AttributeStreamOfDbl.java +++ b/src/main/java/com/esri/core/geometry/AttributeStreamOfDbl.java @@ -36,140 +36,146 @@ final class AttributeStreamOfDbl extends AttributeStreamBase { - protected double[] m_buffer = null; - private int m_size; - - public int size() { - return m_size; - } - - public void reserve(int reserve) { - if (reserve <= 0) - return; - if (m_buffer == null) - m_buffer = new double[reserve]; - else { - if (reserve <= m_buffer.length) - return; - double[] buf = new double[reserve]; - System.arraycopy(m_buffer, 0, buf, 0, m_size); - m_buffer = buf; - } - - } - - public int capacity() { - return m_buffer != null ? m_buffer.length : 0; - } - - public AttributeStreamOfDbl(int size) { - int sz = size; - if (sz < 2) - sz = 2; - m_buffer = new double[sz]; - m_size = size; - } - - public AttributeStreamOfDbl(int size, double defaultValue) { - int sz = size; - if (sz < 2) - sz = 2; - m_buffer = new double[sz]; - m_size = size; - Arrays.fill(m_buffer, 0, size, defaultValue); - } - - public AttributeStreamOfDbl(AttributeStreamOfDbl other) { - m_buffer = other.m_buffer.clone(); - m_size = other.m_size; - } - - public AttributeStreamOfDbl(AttributeStreamOfDbl other, int maxSize) { - m_size = other.size(); - if (m_size > maxSize) - m_size = maxSize; - int sz = m_size; - if (sz < 2) - sz = 2; - m_buffer = new double[sz]; - System.arraycopy(other.m_buffer, 0, m_buffer, 0, m_size); - } - - /** - * Reads a value from the buffer at given offset. - * - * @param offset is the element number in the stream. - */ - public double read(int offset) { - return m_buffer[offset]; - } - - public double get(int offset) { - return m_buffer[offset]; - } - - /** - * Overwrites given element with new value. - * - * @param offset is the element number in the stream. - * @param value is the value to write. - */ - public void write(int offset, double value) { - if (m_bReadonly) { - throw new RuntimeException("invalid_call"); - } - m_buffer[offset] = value; - } - - public void set(int offset, double value) { - if (m_bReadonly) { - throw new RuntimeException("invalid_call"); - } - m_buffer[offset] = value; - } - - /** - * Reads a value from the buffer at given offset. - * - * @param offset is the element number in the stream. - */ - public void read(int offset, Point2D outPoint) { - outPoint.x = m_buffer[offset]; - outPoint.y = m_buffer[offset + 1]; - } - - /** - * Overwrites given element with new value. - * - * @param offset is the element number in the stream. - * @param value is the value to write. - */ - void write(int offset, Point2D point) { - if (m_bReadonly) { - throw new RuntimeException("invalid_call"); - } - m_buffer[offset] = point.x; - m_buffer[offset + 1] = point.y; - } - - /** - * Adds a new value at the end of the stream. - */ - public void add(double v) { - resize(m_size + 1); - m_buffer[m_size - 1] = v; - } - - @Override - public AttributeStreamBase restrictedClone(int maxsize) { - AttributeStreamOfDbl clone = new AttributeStreamOfDbl(this, maxsize); - return clone; - } - - @Override - public int virtualSize() { - return size(); - } + protected double[] m_buffer = null; + private int m_size; + + public int size() { + return m_size; + } + + public void reserve(int reserve) { + if (reserve <= 0) + return; + if (m_buffer == null) + m_buffer = new double[reserve]; + else { + if (reserve <= m_buffer.length) + return; + double[] buf = new double[reserve]; + System.arraycopy(m_buffer, 0, buf, 0, m_size); + m_buffer = buf; + } + + } + + public int capacity() { + return m_buffer != null ? m_buffer.length : 0; + } + + public AttributeStreamOfDbl(int size) { + int sz = size; + if (sz < 2) + sz = 2; + m_buffer = new double[sz]; + m_size = size; + } + + public AttributeStreamOfDbl(int size, double defaultValue) { + int sz = size; + if (sz < 2) + sz = 2; + m_buffer = new double[sz]; + m_size = size; + Arrays.fill(m_buffer, 0, size, defaultValue); + } + + public AttributeStreamOfDbl(AttributeStreamOfDbl other) { + m_buffer = other.m_buffer.clone(); + m_size = other.m_size; + } + + public AttributeStreamOfDbl(AttributeStreamOfDbl other, int maxSize) { + m_size = other.size(); + if (m_size > maxSize) + m_size = maxSize; + int sz = m_size; + if (sz < 2) + sz = 2; + m_buffer = new double[sz]; + System.arraycopy(other.m_buffer, 0, m_buffer, 0, m_size); + } + + /** + * Reads a value from the buffer at given offset. + * + * @param offset + * is the element number in the stream. + */ + public double read(int offset) { + return m_buffer[offset]; + } + + public double get(int offset) { + return m_buffer[offset]; + } + + /** + * Overwrites given element with new value. + * + * @param offset + * is the element number in the stream. + * @param value + * is the value to write. + */ + public void write(int offset, double value) { + if (m_bReadonly) { + throw new RuntimeException("invalid_call"); + } + m_buffer[offset] = value; + } + + public void set(int offset, double value) { + if (m_bReadonly) { + throw new RuntimeException("invalid_call"); + } + m_buffer[offset] = value; + } + + /** + * Reads a value from the buffer at given offset. + * + * @param offset + * is the element number in the stream. + */ + public void read(int offset, Point2D outPoint) { + outPoint.x = m_buffer[offset]; + outPoint.y = m_buffer[offset + 1]; + } + + /** + * Overwrites given element with new value. + * + * @param offset + * is the element number in the stream. + * @param value + * is the value to write. + */ + void write(int offset, Point2D point) { + if (m_bReadonly) { + throw new RuntimeException("invalid_call"); + } + m_buffer[offset] = point.x; + m_buffer[offset + 1] = point.y; + } + + /** + * Adds a new value at the end of the stream. + */ + public void add(double v) { + resize(m_size + 1); + m_buffer[m_size - 1] = v; + } + + @Override + public AttributeStreamBase restrictedClone(int maxsize) { + AttributeStreamOfDbl clone = new AttributeStreamOfDbl(this, maxsize); + return clone; + } + + @Override + public int virtualSize() { + return size(); + } @Override public long estimateMemorySize() @@ -193,651 +199,651 @@ public long estimateMemorySize() // } // } - @Override - public int getPersistence() { - return Persistence.enumDouble; - } - - @Override - public double readAsDbl(int offset) { - return read(offset); - } - - @Override - public int readAsInt(int offset) { - return (int) read(offset); - } - - @Override - public long readAsInt64(int offset) { - return (long) read(offset); - } - - @Override - public void resize(int newSize) { - if (m_bLockedInSize) - throw new GeometryException( - "invalid call. Attribute Stream is locked and cannot be resized."); - - if (newSize <= m_size) { - if ((newSize * 5) / 4 < m_buffer.length) {// decrease when the 25% - // margin is exceeded - double[] newBuffer = new double[newSize]; - System.arraycopy(m_buffer, 0, newBuffer, 0, newSize); - m_buffer = newBuffer; - } - m_size = newSize; - } else { - if (newSize > m_buffer.length) { - int sz = (newSize < 64) ? Math.max(newSize * 2, 4) - : (newSize * 5) / 4; - double[] newBuffer = new double[sz]; - System.arraycopy(m_buffer, 0, newBuffer, 0, m_size); - m_buffer = newBuffer; - } - - m_size = newSize; - } - } - - @Override - public void resizePreserveCapacity(int newSize)// java only method - { - if (m_buffer == null || newSize > m_buffer.length) - resize(newSize); - if (m_bLockedInSize) - throw new GeometryException( - "invalid call. Attribute Stream is locked and cannot be resized."); - - m_size = newSize; - } - - @Override - public void resize(int newSize, double defaultValue) { - if (m_bLockedInSize) - throw new GeometryException( - "invalid call. Attribute Stream is locked and cannot be resized."); - if (newSize <= m_size) { - if ((newSize * 5) / 4 < m_buffer.length) {// decrease when the 25% - // margin is exceeded - double[] newBuffer = new double[newSize]; - System.arraycopy(m_buffer, 0, newBuffer, 0, newSize); - m_buffer = newBuffer; - } - m_size = newSize; - } else { - if (newSize > m_buffer.length) { - int sz = (newSize < 64) ? Math.max(newSize * 2, 4) - : (newSize * 5) / 4; - double[] newBuffer = new double[sz]; - System.arraycopy(m_buffer, 0, newBuffer, 0, m_size); - m_buffer = newBuffer; - } - - Arrays.fill(m_buffer, m_size, newSize, defaultValue); - - m_size = newSize; - } - } - - @Override - public void writeAsDbl(int offset, double d) { - write(offset, d); - } - - @Override - public void writeAsInt64(int offset, long d) { - write(offset, (double) d); - } - - @Override - public void writeAsInt(int offset, int d) { - write(offset, (double) d); - } - - /** - * Sets the envelope from the attribute stream. The attribute stream stores - * interleaved x and y. The envelope will be set to empty if the pointCount - * is zero. - */ - public void setEnvelopeFromPoints(int pointCount, Envelope2D inOutEnv) { - if (pointCount == 0) { - inOutEnv.setEmpty(); - return; - } - if (pointCount < 0) - pointCount = size() / 2; - else if (pointCount * 2 > size()) - throw new IllegalArgumentException(); - - inOutEnv.setCoords(read(0), read(1)); - for (int i = 1; i < pointCount; i++) { - inOutEnv.mergeNE(read(i * 2), read(i * 2 + 1)); - } - } - - @Override - public int calculateHashImpl(int hashCodeIn, int start, int end) { - int hashCode = hashCodeIn; - for (int i = start, n = size(); i < n && i < end; i++) - hashCode = NumberUtils.hash(hashCode, read(i)); - - return hashCode; - } - - @Override - public boolean equals(AttributeStreamBase other, int start, int end) { - if (other == null) - return false; - - if (!(other instanceof AttributeStreamOfDbl)) - return false; - - AttributeStreamOfDbl _other = (AttributeStreamOfDbl) other; - - int size = size(); - int sizeOther = _other.size(); - - if (end > size || end > sizeOther && (size != sizeOther)) - return false; - - if (end > size) - end = size; - - for (int i = start; i < end; i++) - if (read(i) != _other.read(i)) - return false; - - return true; - } - - @Override - public void addRange(AttributeStreamBase src, int start, int count, - boolean bForward, int stride) { - if (m_bReadonly) - throw new GeometryException("invalid_call"); - - if (!bForward && (stride < 1 || count % stride != 0)) - throw new IllegalArgumentException(); - - int oldSize = m_size; - int newSize = oldSize + count; - resize(newSize); - - if (bForward) { - System.arraycopy(((AttributeStreamOfDbl) src).m_buffer, start, - m_buffer, oldSize, count); - } else { - int n = count; - - for (int i = 0; i < count; i += stride) { - n -= stride; - - for (int s = 0; s < stride; s++) { - m_buffer[oldSize + i + s] = ((AttributeStreamOfDbl) src).m_buffer[start - + n + s]; - } - } - } - } - - // public void addRange(AttributeStreamBase src, int start, - // int count, boolean bForward, int stride) { - // - // if (m_bReadonly) - // throw new GeometryException("invalid_call"); - // - // if (!bForward && (stride < 1 || count % stride != 0)) - // throw new IllegalArgumentException(); - // - // if (bForward) - // { - // double[] otherbuffer = ((AttributeStreamOfDbl) src).m_buffer; - // // int newSize = size() + count; - // // resize(newSize); - // // System.arraycopy(otherbuffer, start, m_buffer, pos, count); - // for (int i = 0; i < count; i++) { - // add(otherbuffer[start + i]); - // } - // } else { - // throw new GeometryException("not implemented for reverse add"); - // } - // } - - @Override - public void insertRange(int start, AttributeStreamBase src, int srcStart, - int count, boolean bForward, int stride, int validSize) { - if (m_bReadonly) - throw new GeometryException("invalid_call"); - - if (!bForward && (stride < 1 || count % stride != 0)) - throw new IllegalArgumentException(); - - int excess_space = m_size - validSize; - - if (excess_space < count) { - int original_size = m_size; - resize(original_size + count - excess_space); - } - - System.arraycopy(m_buffer, start, m_buffer, start + count, validSize - - start); - - if (m_buffer == ((AttributeStreamOfDbl) src).m_buffer) { - if (start < srcStart) - srcStart += count; - } - - if (bForward) { - System.arraycopy(((AttributeStreamOfDbl) src).m_buffer, srcStart, - m_buffer, start, count); - } else { - int n = count; - - for (int i = 0; i < count; i += stride) { - n -= stride; - - for (int s = 0; s < stride; s++) { - m_buffer[start + i + s] = ((AttributeStreamOfDbl) src).m_buffer[srcStart - + n + s]; - } - } - } - } - - @Override - public void insertRange(int start, double value, int count, int validSize) { - if (m_bReadonly) - throw new GeometryException("invalid_call"); - - System.arraycopy(m_buffer, start, m_buffer, start + count, validSize - - start); - - for (int i = 0; i < count; i++) { - m_buffer[start + i] = value; - } - } - - @Override - public void insertAttributes(int start, Point pt, int semantics, - int validSize) { - if (m_bReadonly) - throw new GeometryException("invalid_call"); - - int comp = VertexDescription.getComponentCount(semantics); - - System.arraycopy(m_buffer, start, m_buffer, start + comp, validSize - - start); - - for (int c = 0; c < comp; c++) { - m_buffer[start + c] = pt.getAttributeAsDbl(semantics, c); - } - } - - public void insert(int index, Point2D point, int validSize) { - if (m_bReadonly) - throw new GeometryException("invalid_call"); - - System.arraycopy(m_buffer, index, m_buffer, index + 2, validSize - - index); - m_buffer[index] = point.x; - m_buffer[index + 1] = point.y; - } - - // special case for .net 2d array syntax [,] - // writes count doubles, 2 at a time, into this stream. count is assumed to - // be even, arrayOffset is an index of the zeroth dimension (i.e. you can't - // start writing from dst[0,1]) - public void writeRange(int streamOffset, int count, double[][] src, - int arrayOffset, boolean bForward) { - if (streamOffset < 0 || count < 0 || arrayOffset < 0 - || count > NumberUtils.intMax()) - throw new IllegalArgumentException(); - - if (src.length * 2 < (int) ((arrayOffset << 1) + count)) - throw new IllegalArgumentException(); - if (count == 0) - return; - - if (size() < count + streamOffset) - resize(count + streamOffset); - - int j = streamOffset; - if (!bForward) - j += count - 1; - - final int dj = bForward ? 2 : -2; - - int end = arrayOffset + (count >> 1); - for (int i = arrayOffset; i < end; i++) { - m_buffer[j] = (double) src[i][0]; - m_buffer[j + 1] = (double) src[i][1]; - j += dj; - } - } - - public void writeRange(int streamOffset, int count, double[] src, - int arrayOffset, boolean bForward) { - if (streamOffset < 0 || count < 0 || arrayOffset < 0) - throw new IllegalArgumentException(); - - if (src.length < arrayOffset + count) - throw new IllegalArgumentException(); - if (count == 0) - return; - - if (size() < count + streamOffset) - resize(count + streamOffset); - - if (bForward) { - System.arraycopy(src, arrayOffset, m_buffer, streamOffset, count); - } else { - int j = streamOffset; - if (!bForward) - j += count - 1; - - int end = arrayOffset + count; - for (int i = arrayOffset; i < end; i++) { - m_buffer[j] = src[i]; - j--; - } - } - } - - /** - * WARNING, this is like move semantics in C++, that means outside world could mess up a polygon if they still have - * a pointer to array. Only used internally for functions where array pointer never leaves scope of function - * - * @param src - */ - protected void writeRangeMove(double[] src) { - if (src.length == 0) - return; - - if (size() < src.length) - resize(src.length); - - m_buffer = src; - } - - // reads count doubles, 2 at a time, into dst. count is assumed to be even, - // arrayOffset is an index of the zeroth dimension (i.e. you can't start - // reading into dst[0,1]) - // void AttributeStreamOfDbl::ReadRange(int streamOffset, int count, - // array^ dst, int arrayOffset, bool bForward) - - public void readRange(int streamOffset, int count, double[][] dst, - int arrayOffset, boolean bForward) { - if (streamOffset < 0 || count < 0 || arrayOffset < 0 - || count > NumberUtils.intMax() - || size() < count + streamOffset) - throw new IllegalArgumentException(); - - if (dst.length * 2 < (int) ((arrayOffset << 1) + count)) - throw new IllegalArgumentException(); - - if (count == 0) - return; - - int j = streamOffset; - if (!bForward) - j += count - 1; - - final int dj = bForward ? 2 : -2; - - int end = arrayOffset + (count >> 1); - for (int i = arrayOffset; i < end; i++) { - dst[i][0] = m_buffer[j]; - dst[i][1] = m_buffer[j + 1]; - j += dj; - } - - } - - @Override - public void eraseRange(int index, int count, int validSize) { - if (m_bReadonly) - throw new GeometryException("invalid_call"); - - if (index + count > m_size) - throw new GeometryException("invalid_call"); - - if (validSize - (index + count) > 0) { - System.arraycopy(m_buffer, index + count, m_buffer, index, - validSize - (index + count)); - } - m_size -= count; - } - - @Override - public void readRange(int srcStart, int count, ByteBuffer dst, - int dstOffset, boolean bForward) { - if (srcStart < 0 || count < 0 || dstOffset < 0 - || size() < count + srcStart) - throw new IllegalArgumentException(); - - final int elmSize = NumberUtils.sizeOf((double) 0); - - if (dst.capacity() < (int) (dstOffset + elmSize * count)) - throw new IllegalArgumentException(); - - if (count == 0) - return; - - int j = srcStart; - if (!bForward) - j += count - 1; - - final int dj = bForward ? 1 : -1; - - int offset = dstOffset; - for (int i = 0; i < count; i++, offset += elmSize) { - dst.putDouble(offset, m_buffer[j]); - j += dj; - } - } - - @Override - public void reverseRange(int index, int count, int stride) { - if (m_bReadonly) - throw new GeometryException("invalid_call"); - - if (stride < 1 || count % stride != 0) - throw new GeometryException("invalid_call"); - - int cIterations = count >> 1; - int n = count; - - for (int i = 0; i < cIterations; i += stride) { - n -= stride; - - for (int s = 0; s < stride; s++) { - double temp = m_buffer[index + i + s]; - m_buffer[index + i + s] = m_buffer[index + n + s]; - m_buffer[index + n + s] = temp; - } - } - } - - @Override - public void setRange(double value, int start, int count) { - if (start < 0 || count < 0 || start < 0 || count + start > size()) - throw new IllegalArgumentException(); - - double v = value; - Arrays.fill(m_buffer, start, start + count, v); - // for (int i = start, n = start + count; i < n; i++) - // write(i, v); - } - - @Override - public void writeRange(int startElement, int count, - AttributeStreamBase _src, int srcStart, boolean bForward, int stride) { - if (startElement < 0 || count < 0 || srcStart < 0) - throw new IllegalArgumentException(); - - if (!bForward && (stride <= 0 || (count % stride != 0))) - throw new IllegalArgumentException(); - - AttributeStreamOfDbl src = (AttributeStreamOfDbl) _src; // the input - // type must - // match - - if (src.size() < (int) (srcStart + count)) - throw new IllegalArgumentException(); - - if (count == 0) - return; - - if (size() < count + startElement) - resize(count + startElement); - - if (_src == (AttributeStreamBase) this) { - _selfWriteRangeImpl(startElement, count, srcStart, bForward, stride); - return; - } - - if (bForward) { - int j = startElement; - int offset = srcStart; - for (int i = 0; i < count; i++) { - m_buffer[j] = src.m_buffer[offset]; - j++; - offset++; - } - } else { - int j = startElement; - int offset = srcStart + count - stride; - if (stride == 1) { - for (int i = 0; i < count; i++) { - m_buffer[j] = src.m_buffer[offset]; - j++; - offset--; - } - } else { - for (int i = 0, n = count / stride; i < n; i++) { - for (int k = 0; k < stride; k++) - m_buffer[j + k] = src.m_buffer[offset + k]; - - j += stride; - offset -= stride; - } - } - } - } - - private void _selfWriteRangeImpl(int toElement, int count, int fromElement, - boolean bForward, int stride) { - - // writing from to this stream. - if (bForward) { - if (toElement == fromElement) - return; - } - - System.arraycopy(m_buffer, fromElement, m_buffer, toElement, count); - - if (bForward) - return; - // reverse what we written - int j = toElement; - int offset = toElement + count - stride; - int dj = stride; - for (int i = 0, n = count / 2; i < n; i++) { - for (int k = 0; k < stride; k++) { - double v = m_buffer[j + k]; - m_buffer[j + k] = m_buffer[offset + k]; - m_buffer[offset + k] = v; - } - j += stride; - offset -= stride; - } - - } - - @Override - public void writeRange(int startElement, int count, ByteBuffer src, - int offsetBytes, boolean bForward) { - if (startElement < 0 || count < 0 || offsetBytes < 0) - throw new IllegalArgumentException(); - - final int elmSize = NumberUtils.sizeOf((double) 0); - if (src.capacity() < (int) (offsetBytes + elmSize * count)) - throw new IllegalArgumentException(); - - if (count == 0) - return; - - if (size() < count + startElement) - resize(count + startElement); - - int j = startElement; - if (!bForward) - j += count - 1; - - final int dj = bForward ? 1 : -1; - - int offset = offsetBytes; - for (int i = 0; i < count; i++, offset += elmSize) { - m_buffer[j] = src.getDouble(offset); - j += dj; - } - - } - - public void writeRange(int streamOffset, int pointCount, Point2D[] src, - int arrayOffset, boolean bForward) { - if (streamOffset < 0 || pointCount < 0 || arrayOffset < 0) - throw new IllegalArgumentException(); - - // if (src->Length < (int)(arrayOffset + pointCount)) jt: we have lost - // the length check, not sure about this - // GEOMTHROW(invalid_argument); - - if (pointCount == 0) - return; - - if (size() < (pointCount << 1) + streamOffset) - resize((pointCount << 1) + streamOffset); - - int j = streamOffset; - if (!bForward) - j += (pointCount - 1) << 1; - - final int dj = bForward ? 2 : -2; - - // TODO: refactor to take advantage of the known block array structure - - final int i0 = arrayOffset; - pointCount += i0; - for (int i = i0; i < pointCount; i++) { - m_buffer[j] = src[i].x; - m_buffer[j + 1] = src[i].y; - j += dj; - } - } - - // Less efficient as boolean bForward set to false, as it is looping through - // half - // of the elements of the array - public void readRange(int srcStart, int count, double[] dst, int dstOffset, - boolean bForward) { - if (srcStart < 0 || count < 0 || dstOffset < 0 - || size() < count + srcStart) - throw new IllegalArgumentException(); - - if (bForward) - System.arraycopy(m_buffer, srcStart, dst, dstOffset, count); - else { - int j = dstOffset + count - 1; - for (int i = srcStart; i < count; i++) { - dst[j] = m_buffer[i]; - j--; - } - } - } - - public void sort(int start, int end) { - Arrays.sort(m_buffer, start, end); - } + @Override + public int getPersistence() { + return Persistence.enumDouble; + } + + @Override + public double readAsDbl(int offset) { + return read(offset); + } + + @Override + public int readAsInt(int offset) { + return (int) read(offset); + } + + @Override + public long readAsInt64(int offset) { + return (long) read(offset); + } + + @Override + public void resize(int newSize) { + if (m_bLockedInSize) + throw new GeometryException( + "invalid call. Attribute Stream is locked and cannot be resized."); + + if (newSize <= m_size) { + if ((newSize * 5) / 4 < m_buffer.length) {// decrease when the 25% + // margin is exceeded + double[] newBuffer = new double[newSize]; + System.arraycopy(m_buffer, 0, newBuffer, 0, newSize); + m_buffer = newBuffer; + } + m_size = newSize; + } else { + if (newSize > m_buffer.length) { + int sz = (newSize < 64) ? Math.max(newSize * 2, 4) + : (newSize * 5) / 4; + double[] newBuffer = new double[sz]; + System.arraycopy(m_buffer, 0, newBuffer, 0, m_size); + m_buffer = newBuffer; + } + + m_size = newSize; + } + } + + @Override + public void resizePreserveCapacity(int newSize)// java only method + { + if (m_buffer == null || newSize > m_buffer.length) + resize(newSize); + if (m_bLockedInSize) + throw new GeometryException( + "invalid call. Attribute Stream is locked and cannot be resized."); + + m_size = newSize; + } + + @Override + public void resize(int newSize, double defaultValue) { + if (m_bLockedInSize) + throw new GeometryException( + "invalid call. Attribute Stream is locked and cannot be resized."); + if (newSize <= m_size) { + if ((newSize * 5) / 4 < m_buffer.length) {// decrease when the 25% + // margin is exceeded + double[] newBuffer = new double[newSize]; + System.arraycopy(m_buffer, 0, newBuffer, 0, newSize); + m_buffer = newBuffer; + } + m_size = newSize; + } else { + if (newSize > m_buffer.length) { + int sz = (newSize < 64) ? Math.max(newSize * 2, 4) + : (newSize * 5) / 4; + double[] newBuffer = new double[sz]; + System.arraycopy(m_buffer, 0, newBuffer, 0, m_size); + m_buffer = newBuffer; + } + + Arrays.fill(m_buffer, m_size, newSize, defaultValue); + + m_size = newSize; + } + } + + @Override + public void writeAsDbl(int offset, double d) { + write(offset, d); + } + + @Override + public void writeAsInt64(int offset, long d) { + write(offset, (double) d); + } + + @Override + public void writeAsInt(int offset, int d) { + write(offset, (double) d); + } + + /** + * Sets the envelope from the attribute stream. The attribute stream stores + * interleaved x and y. The envelope will be set to empty if the pointCount + * is zero. + */ + public void setEnvelopeFromPoints(int pointCount, Envelope2D inOutEnv) { + if (pointCount == 0) { + inOutEnv.setEmpty(); + return; + } + if (pointCount < 0) + pointCount = size() / 2; + else if (pointCount * 2 > size()) + throw new IllegalArgumentException(); + + inOutEnv.setCoords(read(0), read(1)); + for (int i = 1; i < pointCount; i++) { + inOutEnv.mergeNE(read(i * 2), read(i * 2 + 1)); + } + } + + @Override + public int calculateHashImpl(int hashCodeIn, int start, int end) { + int hashCode = hashCodeIn; + for (int i = start, n = size(); i < n && i < end; i++) + hashCode = NumberUtils.hash(hashCode, read(i)); + + return hashCode; + } + + @Override + public boolean equals(AttributeStreamBase other, int start, int end) { + if (other == null) + return false; + + if (!(other instanceof AttributeStreamOfDbl)) + return false; + + AttributeStreamOfDbl _other = (AttributeStreamOfDbl) other; + + int size = size(); + int sizeOther = _other.size(); + + if (end > size || end > sizeOther && (size != sizeOther)) + return false; + + if (end > size) + end = size; + + for (int i = start; i < end; i++) + if (!NumberUtils.isEqualNonIEEE(read(i), _other.read(i))) + return false; + + return true; + } + + @Override + public void addRange(AttributeStreamBase src, int start, int count, + boolean bForward, int stride) { + if (m_bReadonly) + throw new GeometryException("invalid_call"); + + if (!bForward && (stride < 1 || count % stride != 0)) + throw new IllegalArgumentException(); + + int oldSize = m_size; + int newSize = oldSize + count; + resize(newSize); + + if (bForward) { + System.arraycopy(((AttributeStreamOfDbl) src).m_buffer, start, + m_buffer, oldSize, count); + } else { + int n = count; + + for (int i = 0; i < count; i += stride) { + n -= stride; + + for (int s = 0; s < stride; s++) { + m_buffer[oldSize + i + s] = ((AttributeStreamOfDbl) src).m_buffer[start + + n + s]; + } + } + } + } + + // public void addRange(AttributeStreamBase src, int start, + // int count, boolean bForward, int stride) { + // + // if (m_bReadonly) + // throw new GeometryException("invalid_call"); + // + // if (!bForward && (stride < 1 || count % stride != 0)) + // throw new IllegalArgumentException(); + // + // if (bForward) + // { + // double[] otherbuffer = ((AttributeStreamOfDbl) src).m_buffer; + // // int newSize = size() + count; + // // resize(newSize); + // // System.arraycopy(otherbuffer, start, m_buffer, pos, count); + // for (int i = 0; i < count; i++) { + // add(otherbuffer[start + i]); + // } + // } else { + // throw new GeometryException("not implemented for reverse add"); + // } + // } + + @Override + public void insertRange(int start, AttributeStreamBase src, int srcStart, + int count, boolean bForward, int stride, int validSize) { + if (m_bReadonly) + throw new GeometryException("invalid_call"); + + if (!bForward && (stride < 1 || count % stride != 0)) + throw new IllegalArgumentException(); + + int excess_space = m_size - validSize; + + if (excess_space < count) { + int original_size = m_size; + resize(original_size + count - excess_space); + } + + System.arraycopy(m_buffer, start, m_buffer, start + count, validSize + - start); + + if (m_buffer == ((AttributeStreamOfDbl) src).m_buffer) { + if (start < srcStart) + srcStart += count; + } + + if (bForward) { + System.arraycopy(((AttributeStreamOfDbl) src).m_buffer, srcStart, + m_buffer, start, count); + } else { + int n = count; + + for (int i = 0; i < count; i += stride) { + n -= stride; + + for (int s = 0; s < stride; s++) { + m_buffer[start + i + s] = ((AttributeStreamOfDbl) src).m_buffer[srcStart + + n + s]; + } + } + } + } + + @Override + public void insertRange(int start, double value, int count, int validSize) { + if (m_bReadonly) + throw new GeometryException("invalid_call"); + + System.arraycopy(m_buffer, start, m_buffer, start + count, validSize + - start); + + for (int i = 0; i < count; i++) { + m_buffer[start + i] = value; + } + } + + @Override + public void insertAttributes(int start, Point pt, int semantics, + int validSize) { + if (m_bReadonly) + throw new GeometryException("invalid_call"); + + int comp = VertexDescription.getComponentCount(semantics); + + System.arraycopy(m_buffer, start, m_buffer, start + comp, validSize + - start); + + for (int c = 0; c < comp; c++) { + m_buffer[start + c] = pt.getAttributeAsDbl(semantics, c); + } + } + + public void insert(int index, Point2D point, int validSize) { + if (m_bReadonly) + throw new GeometryException("invalid_call"); + + System.arraycopy(m_buffer, index, m_buffer, index + 2, validSize + - index); + m_buffer[index] = point.x; + m_buffer[index + 1] = point.y; + } + + // special case for .net 2d array syntax [,] + // writes count doubles, 2 at a time, into this stream. count is assumed to + // be even, arrayOffset is an index of the zeroth dimension (i.e. you can't + // start writing from dst[0,1]) + public void writeRange(int streamOffset, int count, double[][] src, + int arrayOffset, boolean bForward) { + if (streamOffset < 0 || count < 0 || arrayOffset < 0 + || count > NumberUtils.intMax()) + throw new IllegalArgumentException(); + + if (src.length * 2 < (int) ((arrayOffset << 1) + count)) + throw new IllegalArgumentException(); + if (count == 0) + return; + + if (size() < count + streamOffset) + resize(count + streamOffset); + + int j = streamOffset; + if (!bForward) + j += count - 1; + + final int dj = bForward ? 2 : -2; + + int end = arrayOffset + (count >> 1); + for (int i = arrayOffset; i < end; i++) { + m_buffer[j] = (double) src[i][0]; + m_buffer[j + 1] = (double) src[i][1]; + j += dj; + } + } + + public void writeRange(int streamOffset, int count, double[] src, + int arrayOffset, boolean bForward) { + if (streamOffset < 0 || count < 0 || arrayOffset < 0) + throw new IllegalArgumentException(); + + if (src.length < arrayOffset + count) + throw new IllegalArgumentException(); + if (count == 0) + return; + + if (size() < count + streamOffset) + resize(count + streamOffset); + + if (bForward) { + System.arraycopy(src, arrayOffset, m_buffer, streamOffset, count); + } else { + int j = streamOffset; + if (!bForward) + j += count - 1; + + int end = arrayOffset + count; + for (int i = arrayOffset; i < end; i++) { + m_buffer[j] = src[i]; + j--; + } + } + } + + /** + * WARNING, this is like move semantics in C++, that means outside world could mess up a polygon if they still have + * a pointer to array. Only used internally for functions where array pointer never leaves scope of function + * + * @param src + */ + protected void writeRangeMove(double[] src) { + if (src.length == 0) + return; + + if (size() < src.length) + resize(src.length); + + m_buffer = src; + } + + // reads count doubles, 2 at a time, into dst. count is assumed to be even, + // arrayOffset is an index of the zeroth dimension (i.e. you can't start + // reading into dst[0,1]) + // void AttributeStreamOfDbl::ReadRange(int streamOffset, int count, + // array^ dst, int arrayOffset, bool bForward) + + public void readRange(int streamOffset, int count, double[][] dst, + int arrayOffset, boolean bForward) { + if (streamOffset < 0 || count < 0 || arrayOffset < 0 + || count > NumberUtils.intMax() + || size() < count + streamOffset) + throw new IllegalArgumentException(); + + if (dst.length * 2 < (int) ((arrayOffset << 1) + count)) + throw new IllegalArgumentException(); + + if (count == 0) + return; + + int j = streamOffset; + if (!bForward) + j += count - 1; + + final int dj = bForward ? 2 : -2; + + int end = arrayOffset + (count >> 1); + for (int i = arrayOffset; i < end; i++) { + dst[i][0] = m_buffer[j]; + dst[i][1] = m_buffer[j + 1]; + j += dj; + } + + } + + @Override + public void eraseRange(int index, int count, int validSize) { + if (m_bReadonly) + throw new GeometryException("invalid_call"); + + if (index + count > m_size) + throw new GeometryException("invalid_call"); + + if (validSize - (index + count) > 0) { + System.arraycopy(m_buffer, index + count, m_buffer, index, + validSize - (index + count)); + } + m_size -= count; + } + + @Override + public void readRange(int srcStart, int count, ByteBuffer dst, + int dstOffset, boolean bForward) { + if (srcStart < 0 || count < 0 || dstOffset < 0 + || size() < count + srcStart) + throw new IllegalArgumentException(); + + final int elmSize = NumberUtils.sizeOf((double) 0); + + if (dst.capacity() < (int) (dstOffset + elmSize * count)) + throw new IllegalArgumentException(); + + if (count == 0) + return; + + int j = srcStart; + if (!bForward) + j += count - 1; + + final int dj = bForward ? 1 : -1; + + int offset = dstOffset; + for (int i = 0; i < count; i++, offset += elmSize) { + dst.putDouble(offset, m_buffer[j]); + j += dj; + } + } + + @Override + public void reverseRange(int index, int count, int stride) { + if (m_bReadonly) + throw new GeometryException("invalid_call"); + + if (stride < 1 || count % stride != 0) + throw new GeometryException("invalid_call"); + + int cIterations = count >> 1; + int n = count; + + for (int i = 0; i < cIterations; i += stride) { + n -= stride; + + for (int s = 0; s < stride; s++) { + double temp = m_buffer[index + i + s]; + m_buffer[index + i + s] = m_buffer[index + n + s]; + m_buffer[index + n + s] = temp; + } + } + } + + @Override + public void setRange(double value, int start, int count) { + if (start < 0 || count < 0 || start < 0 || count + start > size()) + throw new IllegalArgumentException(); + + double v = value; + Arrays.fill(m_buffer, start, start + count, v); + // for (int i = start, n = start + count; i < n; i++) + // write(i, v); + } + + @Override + public void writeRange(int startElement, int count, + AttributeStreamBase _src, int srcStart, boolean bForward, int stride) { + if (startElement < 0 || count < 0 || srcStart < 0) + throw new IllegalArgumentException(); + + if (!bForward && (stride <= 0 || (count % stride != 0))) + throw new IllegalArgumentException(); + + AttributeStreamOfDbl src = (AttributeStreamOfDbl) _src; // the input + // type must + // match + + if (src.size() < (int) (srcStart + count)) + throw new IllegalArgumentException(); + + if (count == 0) + return; + + if (size() < count + startElement) + resize(count + startElement); + + if (_src == (AttributeStreamBase) this) { + _selfWriteRangeImpl(startElement, count, srcStart, bForward, stride); + return; + } + + if (bForward) { + int j = startElement; + int offset = srcStart; + for (int i = 0; i < count; i++) { + m_buffer[j] = src.m_buffer[offset]; + j++; + offset++; + } + } else { + int j = startElement; + int offset = srcStart + count - stride; + if (stride == 1) { + for (int i = 0; i < count; i++) { + m_buffer[j] = src.m_buffer[offset]; + j++; + offset--; + } + } else { + for (int i = 0, n = count / stride; i < n; i++) { + for (int k = 0; k < stride; k++) + m_buffer[j + k] = src.m_buffer[offset + k]; + + j += stride; + offset -= stride; + } + } + } + } + + private void _selfWriteRangeImpl(int toElement, int count, int fromElement, + boolean bForward, int stride) { + + // writing from to this stream. + if (bForward) { + if (toElement == fromElement) + return; + } + + System.arraycopy(m_buffer, fromElement, m_buffer, toElement, count); + + if (bForward) + return; + // reverse what we written + int j = toElement; + int offset = toElement + count - stride; + int dj = stride; + for (int i = 0, n = count / 2; i < n; i++) { + for (int k = 0; k < stride; k++) { + double v = m_buffer[j + k]; + m_buffer[j + k] = m_buffer[offset + k]; + m_buffer[offset + k] = v; + } + j += stride; + offset -= stride; + } + + } + + @Override + public void writeRange(int startElement, int count, ByteBuffer src, + int offsetBytes, boolean bForward) { + if (startElement < 0 || count < 0 || offsetBytes < 0) + throw new IllegalArgumentException(); + + final int elmSize = NumberUtils.sizeOf((double) 0); + if (src.capacity() < (int) (offsetBytes + elmSize * count)) + throw new IllegalArgumentException(); + + if (count == 0) + return; + + if (size() < count + startElement) + resize(count + startElement); + + int j = startElement; + if (!bForward) + j += count - 1; + + final int dj = bForward ? 1 : -1; + + int offset = offsetBytes; + for (int i = 0; i < count; i++, offset += elmSize) { + m_buffer[j] = src.getDouble(offset); + j += dj; + } + + } + + public void writeRange(int streamOffset, int pointCount, Point2D[] src, + int arrayOffset, boolean bForward) { + if (streamOffset < 0 || pointCount < 0 || arrayOffset < 0) + throw new IllegalArgumentException(); + + // if (src->Length < (int)(arrayOffset + pointCount)) jt: we have lost + // the length check, not sure about this + // GEOMTHROW(invalid_argument); + + if (pointCount == 0) + return; + + if (size() < (pointCount << 1) + streamOffset) + resize((pointCount << 1) + streamOffset); + + int j = streamOffset; + if (!bForward) + j += (pointCount - 1) << 1; + + final int dj = bForward ? 2 : -2; + + // TODO: refactor to take advantage of the known block array structure + + final int i0 = arrayOffset; + pointCount += i0; + for (int i = i0; i < pointCount; i++) { + m_buffer[j] = src[i].x; + m_buffer[j + 1] = src[i].y; + j += dj; + } + } + + // Less efficient as boolean bForward set to false, as it is looping through + // half + // of the elements of the array + public void readRange(int srcStart, int count, double[] dst, int dstOffset, + boolean bForward) { + if (srcStart < 0 || count < 0 || dstOffset < 0 + || size() < count + srcStart) + throw new IllegalArgumentException(); + + if (bForward) + System.arraycopy(m_buffer, srcStart, dst, dstOffset, count); + else { + int j = dstOffset + count - 1; + for (int i = srcStart; i < count; i++) { + dst[j] = m_buffer[i]; + j--; + } + } + } + + public void sort(int start, int end) { + Arrays.sort(m_buffer, start, end); + } } diff --git a/src/main/java/com/esri/core/geometry/AttributeStreamOfFloat.java b/src/main/java/com/esri/core/geometry/AttributeStreamOfFloat.java index 3d9cab23..9156363f 100644 --- a/src/main/java/com/esri/core/geometry/AttributeStreamOfFloat.java +++ b/src/main/java/com/esri/core/geometry/AttributeStreamOfFloat.java @@ -34,119 +34,118 @@ final class AttributeStreamOfFloat extends AttributeStreamBase { - private float[] m_buffer = null; - private int m_size; - - public int size() { - return m_size; - } - - public void reserve(int reserve)// only in Java - { - if (reserve <= 0) - return; - if (m_buffer == null) - m_buffer = new float[reserve]; - else { - if (reserve <= m_buffer.length) - return; - float[] buf = new float[reserve]; - System.arraycopy(m_buffer, 0, buf, 0, m_size); - m_buffer = buf; - } - - } - - public int capacity() { - return m_buffer != null ? m_buffer.length : 0; - } - - public AttributeStreamOfFloat(int size) { - int sz = size; - if (sz < 2) - sz = 2; - m_buffer = new float[sz]; - m_size = size; - } - - public AttributeStreamOfFloat(int size, float defaultValue) { - int sz = size; - if (sz < 2) - sz = 2; - m_buffer = new float[sz]; - m_size = size; - for (int i = 0; i < size; i++) - m_buffer[i] = defaultValue; - } - - public AttributeStreamOfFloat(AttributeStreamOfFloat other) { - m_buffer = other.m_buffer.clone(); - m_size = other.m_size; - } - - public AttributeStreamOfFloat(AttributeStreamOfFloat other, int maxSize) { - m_size = other.size(); - if (m_size > maxSize) - m_size = maxSize; - int sz = m_size; - if (sz < 2) - sz = 2; - m_buffer = new float[sz]; - System.arraycopy(other.m_buffer, 0, m_buffer, 0, m_size); - } - - /** - * Reads a value from the buffer at given offset. - * - * @param offset is the element number in the stream. - */ - public float read(int offset) { - return m_buffer[offset]; - } - - /** - * Overwrites given element with new value. - * - * @param offset is the element number in the stream. - * @param value is the value to write. - */ - public void write(int offset, float value) { - if (m_bReadonly) { - throw new RuntimeException("invalid_call"); - } - m_buffer[offset] = value; - } - - /** - * Adds a new value at the end of the stream. - * - * @param offset is the element number in the stream. - * @param value is the value to write. - */ - public void add(float v) { - resize(m_size + 1); - m_buffer[m_size - 1] = v; - } - - @Override - public AttributeStreamBase restrictedClone(int maxsize) { - int len = m_size; - int newSize = maxsize < len ? maxsize : len; - float[] newBuffer = new float[newSize]; - System.arraycopy(m_buffer, 0, newBuffer, 0, newSize); - m_buffer = newBuffer; - m_size = newSize; - return this; - } - - @Override - public int virtualSize() { - return size(); - } + private float[] m_buffer = null; + private int m_size; - @Override - public long estimateMemorySize() + public int size() { + return m_size; + } + + public void reserve(int reserve)// only in Java { + if (reserve <= 0) + return; + if (m_buffer == null) + m_buffer = new float[reserve]; + else { + if (reserve <= m_buffer.length) + return; + float[] buf = new float[reserve]; + System.arraycopy(m_buffer, 0, buf, 0, m_size); + m_buffer = buf; + } + + } + + public int capacity() { + return m_buffer != null ? m_buffer.length : 0; + } + + public AttributeStreamOfFloat(int size) { + int sz = size; + if (sz < 2) + sz = 2; + m_buffer = new float[sz]; + m_size = size; + } + + public AttributeStreamOfFloat(int size, float defaultValue) { + int sz = size; + if (sz < 2) + sz = 2; + m_buffer = new float[sz]; + m_size = size; + for (int i = 0; i < size; i++) + m_buffer[i] = defaultValue; + } + + public AttributeStreamOfFloat(AttributeStreamOfFloat other) { + m_buffer = other.m_buffer.clone(); + m_size = other.m_size; + } + + public AttributeStreamOfFloat(AttributeStreamOfFloat other, int maxSize) { + m_size = other.size(); + if (m_size > maxSize) + m_size = maxSize; + int sz = m_size; + if (sz < 2) + sz = 2; + m_buffer = new float[sz]; + System.arraycopy(other.m_buffer, 0, m_buffer, 0, m_size); + } + + /** + * Reads a value from the buffer at given offset. + * + * @param offset is the element number in the stream. + */ + public float read(int offset) { + return m_buffer[offset]; + } + + /** + * Overwrites given element with new value. + * + * @param offset is the element number in the stream. + * @param value is the value to write. + */ + public void write(int offset, float value) { + if (m_bReadonly) { + throw new RuntimeException("invalid_call"); + } + m_buffer[offset] = value; + } + + /** + * Adds a new value at the end of the stream. + * + * @param offset is the element number in the stream. + * @param value is the value to write. + */ + public void add(float v) { + resize(m_size + 1); + m_buffer[m_size - 1] = v; + } + + @Override + public AttributeStreamBase restrictedClone(int maxsize) { + int len = m_size; + int newSize = maxsize < len ? maxsize : len; + float[] newBuffer = new float[newSize]; + System.arraycopy(m_buffer, 0, newBuffer, 0, newSize); + m_buffer = newBuffer; + m_size = newSize; + return this; + } + + @Override + public int virtualSize() { + return size(); + } + + @Override + public long estimateMemorySize() { return SIZE_OF_ATTRIBUTE_STREAM_OF_FLOAT + sizeOfFloatArray(m_buffer.length); } @@ -155,462 +154,462 @@ public int getPersistence() { return Persistence.enumFloat; } - @Override - public double readAsDbl(int offset) { - return read(offset); - } - - @Override - public int readAsInt(int offset) { - return (int) read(offset); - } - - @Override - public long readAsInt64(int offset) { - return (long) read(offset); - } - - @Override - public void resize(int newSize) { - if (m_bLockedInSize) - throw new GeometryException( - "invalid call. Attribute Stream is locked and cannot be resized."); - - if (newSize <= m_size) { - if ((newSize * 5) / 4 < m_buffer.length) {// decrease when the 25% - // margin is exceeded - float[] newBuffer = new float[newSize]; - System.arraycopy(m_buffer, 0, newBuffer, 0, newSize); - m_buffer = newBuffer; - } - m_size = newSize; - } else { - if (newSize > m_buffer.length) { - int sz = (newSize < 64) ? Math.max(newSize * 2, 4) - : (newSize * 5) / 4; - float[] newBuffer = new float[sz]; - System.arraycopy(m_buffer, 0, newBuffer, 0, m_size); - m_buffer = newBuffer; - } - - m_size = newSize; - } - } - - @Override - public void resizePreserveCapacity(int newSize)// java only method - { - if (m_buffer == null || newSize > m_buffer.length) - resize(newSize); - if (m_bLockedInSize) - throw new GeometryException( - "invalid call. Attribute Stream is locked and cannot be resized."); - - m_size = newSize; - } - - @Override - public void resize(int newSize, double defaultValue) { - if (m_bLockedInSize) - throw new GeometryException( - "invalid call. Attribute Stream is locked and cannot be resized."); - if (newSize <= m_size) { - if ((newSize * 5) / 4 < m_buffer.length) {// decrease when the 25% - // margin is exceeded - float[] newBuffer = new float[newSize]; - System.arraycopy(m_buffer, 0, newBuffer, 0, newSize); - m_buffer = newBuffer; - } - m_size = newSize; - } else { - if (newSize > m_buffer.length) { - int sz = (newSize < 64) ? Math.max(newSize * 2, 4) - : (newSize * 5) / 4; - float[] newBuffer = new float[sz]; - System.arraycopy(m_buffer, 0, newBuffer, 0, m_size); - m_buffer = newBuffer; - } - - for (int i = m_size; i < newSize; i++) - m_buffer[i] = (float) defaultValue; - - m_size = newSize; - } - } - - @Override - public void writeAsDbl(int offset, double d) { - write(offset, (float) d); - } - - @Override - public void writeAsInt64(int offset, long d) { - write(offset, (float) d); - } - - @Override - public void writeAsInt(int offset, int d) { - write(offset, (float) d); - } - - // @Override - // public void writeRange(int srcStart, int count, ByteBuffer dst, - // int dstOffsetBytes) { - // // TODO Auto-generated method stub - // - // } - - @Override - public int calculateHashImpl(int hashCode, int start, int end) { - for (int i = start, n = size(); i < n && i < end; i++) - hashCode = NumberUtils.hash(hashCode, read(i)); - - return hashCode; - } - - @Override - public boolean equals(AttributeStreamBase other, int start, int end) { - if (other == null) - return false; - - if (!(other instanceof AttributeStreamOfFloat)) - return false; - - AttributeStreamOfFloat _other = (AttributeStreamOfFloat) other; - - int size = size(); - int sizeOther = _other.size(); - - if (end > size || end > sizeOther && (size != sizeOther)) - return false; - - if (end > size) - end = size; - - for (int i = start; i < end; i++) - if (read(i) != _other.read(i)) - return false; - - return true; - } - - // public void addRange(AttributeStreamBase src, int srcStartIndex, int - // count) { - // if ((src == this) || !(src instanceof AttributeStreamOfFloat)) - // throw new IllegalArgumentException(); - // - // AttributeStreamOfFloat as = (AttributeStreamOfFloat) src; - // - // int len = as.size(); - // int oldSize = m_size; - // resize(oldSize + len, 0); - // for (int i = 0; i < len; i++) { - // m_buffer[oldSize + i] = as.read(i); - // } - // } - - @Override - public void addRange(AttributeStreamBase src, int start, int count, - boolean bForward, int stride) { - if (m_bReadonly) - throw new GeometryException("invalid_call"); - - if (!bForward && (stride < 1 || count % stride != 0)) - throw new IllegalArgumentException(); - - int oldSize = m_size; - int newSize = oldSize + count; - resize(newSize); - - if (bForward) { - System.arraycopy(((AttributeStreamOfFloat) src).m_buffer, start, - m_buffer, oldSize, count); - } else { - int n = count; - - for (int i = 0; i < count; i += stride) { - n -= stride; - - for (int s = 0; s < stride; s++) { - m_buffer[oldSize + i + s] = ((AttributeStreamOfFloat) src).m_buffer[start - + n + s]; - } - } - } - } - - @Override - public void insertRange(int start, AttributeStreamBase src, int srcStart, - int count, boolean bForward, int stride, int validSize) { - if (m_bReadonly) - throw new GeometryException("invalid_call"); - - if (!bForward && (stride < 1 || count % stride != 0)) - throw new IllegalArgumentException(); - - System.arraycopy(m_buffer, start, m_buffer, start + count, validSize - - start); - - if (m_buffer == ((AttributeStreamOfFloat) src).m_buffer) { - if (start < srcStart) - srcStart += count; - } - - if (bForward) { - System.arraycopy(((AttributeStreamOfFloat) src).m_buffer, srcStart, - m_buffer, start, count); - } else { - int n = count; - - for (int i = 0; i < count; i += stride) { - n -= stride; - - for (int s = 0; s < stride; s++) { - m_buffer[start + i + s] = ((AttributeStreamOfFloat) src).m_buffer[srcStart - + n + s]; - } - } - } - } - - @Override - public void insertRange(int start, double value, int count, int validSize) { - if (m_bReadonly) - throw new GeometryException("invalid_call"); - - System.arraycopy(m_buffer, start, m_buffer, start + count, validSize - - start); - - float v = (float) value; - for (int i = 0; i < count; i++) { - m_buffer[start + i] = v; - } - } - - @Override - public void insertAttributes(int start, Point pt, int semantics, - int validSize) { - if (m_bReadonly) - throw new GeometryException("invalid_call"); - - int comp = VertexDescription.getComponentCount(semantics); - - System.arraycopy(m_buffer, start, m_buffer, start + comp, validSize - - start); - - for (int c = 0; c < comp; c++) { - m_buffer[start + c] = (float) pt.getAttributeAsDbl(semantics, c); - } - } - - @Override - public void eraseRange(int index, int count, int validSize) { - if (m_bReadonly) - throw new GeometryException("invalid_call"); - - if (index + count > m_size) - throw new GeometryException("invalid_call"); - - System.arraycopy(m_buffer, index + count, m_buffer, index, validSize - - (index + count)); - m_size -= count; - } - - @Override - public void readRange(int srcStart, int count, ByteBuffer dst, - int dstOffset, boolean bForward) { - if (srcStart < 0 || count < 0 || dstOffset < 0 - || size() < count + srcStart) - throw new IllegalArgumentException(); - - final int elmSize = NumberUtils.sizeOf((double) 0); - - if (dst.capacity() < (int) (dstOffset + elmSize * count)) - throw new IllegalArgumentException(); - - if (count == 0) - return; - - int j = srcStart; - if (!bForward) - j += count - 1; - - final int dj = bForward ? 1 : -1; - - int offset = dstOffset; - for (int i = 0; i < count; i++, offset += elmSize) { - dst.putFloat(offset, m_buffer[j]); - j += dj; - } - - } - - @Override - public void reverseRange(int index, int count, int stride) { - if (m_bReadonly) - throw new GeometryException("invalid_call"); - - if (stride < 1 || count % stride != 0) - throw new GeometryException("invalid_call"); - - int cIterations = count >> 1; - int n = count; - - for (int i = 0; i < cIterations; i += stride) { - n -= stride; - - for (int s = 0; s < stride; s++) { - float temp = m_buffer[index + i + s]; - m_buffer[index + i + s] = m_buffer[index + n + s]; - m_buffer[index + n + s] = temp; - } - } - } - - @Override - public void setRange(double value, int start, int count) { - if (start < 0 || count < 0 || start < 0 || count + start > size()) - throw new IllegalArgumentException(); - - float v = (float) value; - for (int i = start, n = start + count; i < n; i++) - write(i, v); - } - - @Override - public void writeRange(int startElement, int count, - AttributeStreamBase _src, int srcStart, boolean bForward, int stride) { - if (startElement < 0 || count < 0 || srcStart < 0) - throw new IllegalArgumentException(); - - if (!bForward && (stride <= 0 || (count % stride != 0))) - throw new IllegalArgumentException(); - - AttributeStreamOfFloat src = (AttributeStreamOfFloat) _src; // the input - // type must - // match - - if (src.size() < (int) (srcStart + count)) - throw new IllegalArgumentException(); - - if (count == 0) - return; - - if (size() < count + startElement) - resize(count + startElement); - - if (_src == (AttributeStreamBase) this) { - _selfWriteRangeImpl(startElement, count, srcStart, bForward, stride); - return; - } - - if (bForward) { - int j = startElement; - int offset = srcStart; - for (int i = 0; i < count; i++) { - m_buffer[j] = src.m_buffer[offset]; - j++; - offset++; - } - } else { - int j = startElement; - int offset = srcStart + count - stride; - if (stride == 1) { - for (int i = 0; i < count; i++) { - m_buffer[j] = src.m_buffer[offset]; - j++; - offset--; - } - } else { - for (int i = 0, n = count / stride; i < n; i++) { - for (int k = 0; k < stride; k++) - m_buffer[j + k] = src.m_buffer[offset + k]; - - j += stride; - offset -= stride; - } - } - } - } - - private void _selfWriteRangeImpl(int toElement, int count, int fromElement, - boolean bForward, int stride) { - - // writing from to this stream. - if (bForward) { - if (toElement == fromElement) - return; - } - - int offset; - int j; - int dj; - - if (fromElement < toElement) { - offset = fromElement + count - stride; - j = toElement + count - stride; - for (int i = 0, n = count / 2; i < n; i++) { - for (int k = 0; k < stride; k++) { - m_buffer[j + k] = m_buffer[offset + k]; - } - j -= stride; - offset -= stride; - } - } else { - offset = fromElement; - j = toElement; - dj = 1; - for (int i = 0; i < count; i++) { - m_buffer[j] = m_buffer[offset]; - j += 1; - offset++; - } - } - - if (!bForward) { - // reverse what we written - j = toElement; - offset = toElement + count - stride; - dj = stride; - for (int i = 0, n = count / 2; i < n; i++) { - for (int k = 0; k < stride; k++) { - float v = m_buffer[j + k]; - m_buffer[j + k] = m_buffer[offset + k]; - m_buffer[offset + k] = v; - } - j += stride; - offset -= stride; - } - } - } - - @Override - public void writeRange(int startElement, int count, ByteBuffer src, - int offsetBytes, boolean bForward) { - if (startElement < 0 || count < 0 || offsetBytes < 0) - throw new IllegalArgumentException(); - - final int elmSize = NumberUtils.sizeOf((double) 0); - if (src.capacity() < (int) (offsetBytes + elmSize * count)) - throw new IllegalArgumentException(); - - if (count == 0) - return; - - if (size() < count + startElement) - resize(count + startElement); - - int j = startElement; - if (!bForward) - j += count - 1; - - final int dj = bForward ? 1 : -1; - - int offset = offsetBytes; - for (int i = 0; i < count; i++, offset += elmSize) { - m_buffer[j] = src.getFloat(offset); - j += dj; - } - - } + @Override + public double readAsDbl(int offset) { + return read(offset); + } + + @Override + public int readAsInt(int offset) { + return (int) read(offset); + } + + @Override + public long readAsInt64(int offset) { + return (long) read(offset); + } + + @Override + public void resize(int newSize) { + if (m_bLockedInSize) + throw new GeometryException( + "invalid call. Attribute Stream is locked and cannot be resized."); + + if (newSize <= m_size) { + if ((newSize * 5) / 4 < m_buffer.length) {// decrease when the 25% + // margin is exceeded + float[] newBuffer = new float[newSize]; + System.arraycopy(m_buffer, 0, newBuffer, 0, newSize); + m_buffer = newBuffer; + } + m_size = newSize; + } else { + if (newSize > m_buffer.length) { + int sz = (newSize < 64) ? Math.max(newSize * 2, 4) + : (newSize * 5) / 4; + float[] newBuffer = new float[sz]; + System.arraycopy(m_buffer, 0, newBuffer, 0, m_size); + m_buffer = newBuffer; + } + + m_size = newSize; + } + } + + @Override + public void resizePreserveCapacity(int newSize)// java only method + { + if (m_buffer == null || newSize > m_buffer.length) + resize(newSize); + if (m_bLockedInSize) + throw new GeometryException( + "invalid call. Attribute Stream is locked and cannot be resized."); + + m_size = newSize; + } + + @Override + public void resize(int newSize, double defaultValue) { + if (m_bLockedInSize) + throw new GeometryException( + "invalid call. Attribute Stream is locked and cannot be resized."); + if (newSize <= m_size) { + if ((newSize * 5) / 4 < m_buffer.length) {// decrease when the 25% + // margin is exceeded + float[] newBuffer = new float[newSize]; + System.arraycopy(m_buffer, 0, newBuffer, 0, newSize); + m_buffer = newBuffer; + } + m_size = newSize; + } else { + if (newSize > m_buffer.length) { + int sz = (newSize < 64) ? Math.max(newSize * 2, 4) + : (newSize * 5) / 4; + float[] newBuffer = new float[sz]; + System.arraycopy(m_buffer, 0, newBuffer, 0, m_size); + m_buffer = newBuffer; + } + + for (int i = m_size; i < newSize; i++) + m_buffer[i] = (float) defaultValue; + + m_size = newSize; + } + } + + @Override + public void writeAsDbl(int offset, double d) { + write(offset, (float) d); + } + + @Override + public void writeAsInt64(int offset, long d) { + write(offset, (float) d); + } + + @Override + public void writeAsInt(int offset, int d) { + write(offset, (float) d); + } + + // @Override + // public void writeRange(int srcStart, int count, ByteBuffer dst, + // int dstOffsetBytes) { + // // TODO Auto-generated method stub + // + // } + + @Override + public int calculateHashImpl(int hashCode, int start, int end) { + for (int i = start, n = size(); i < n && i < end; i++) + hashCode = NumberUtils.hash(hashCode, read(i)); + + return hashCode; + } + + @Override + public boolean equals(AttributeStreamBase other, int start, int end) { + if (other == null) + return false; + + if (!(other instanceof AttributeStreamOfFloat)) + return false; + + AttributeStreamOfFloat _other = (AttributeStreamOfFloat) other; + + int size = size(); + int sizeOther = _other.size(); + + if (end > size || end > sizeOther && (size != sizeOther)) + return false; + + if (end > size) + end = size; + + for (int i = start; i < end; i++) + if (read(i) != _other.read(i)) + return false; + + return true; + } + + // public void addRange(AttributeStreamBase src, int srcStartIndex, int + // count) { + // if ((src == this) || !(src instanceof AttributeStreamOfFloat)) + // throw new IllegalArgumentException(); + // + // AttributeStreamOfFloat as = (AttributeStreamOfFloat) src; + // + // int len = as.size(); + // int oldSize = m_size; + // resize(oldSize + len, 0); + // for (int i = 0; i < len; i++) { + // m_buffer[oldSize + i] = as.read(i); + // } + // } + + @Override + public void addRange(AttributeStreamBase src, int start, int count, + boolean bForward, int stride) { + if (m_bReadonly) + throw new GeometryException("invalid_call"); + + if (!bForward && (stride < 1 || count % stride != 0)) + throw new IllegalArgumentException(); + + int oldSize = m_size; + int newSize = oldSize + count; + resize(newSize); + + if (bForward) { + System.arraycopy(((AttributeStreamOfFloat) src).m_buffer, start, + m_buffer, oldSize, count); + } else { + int n = count; + + for (int i = 0; i < count; i += stride) { + n -= stride; + + for (int s = 0; s < stride; s++) { + m_buffer[oldSize + i + s] = ((AttributeStreamOfFloat) src).m_buffer[start + + n + s]; + } + } + } + } + + @Override + public void insertRange(int start, AttributeStreamBase src, int srcStart, + int count, boolean bForward, int stride, int validSize) { + if (m_bReadonly) + throw new GeometryException("invalid_call"); + + if (!bForward && (stride < 1 || count % stride != 0)) + throw new IllegalArgumentException(); + + System.arraycopy(m_buffer, start, m_buffer, start + count, validSize + - start); + + if (m_buffer == ((AttributeStreamOfFloat) src).m_buffer) { + if (start < srcStart) + srcStart += count; + } + + if (bForward) { + System.arraycopy(((AttributeStreamOfFloat) src).m_buffer, srcStart, + m_buffer, start, count); + } else { + int n = count; + + for (int i = 0; i < count; i += stride) { + n -= stride; + + for (int s = 0; s < stride; s++) { + m_buffer[start + i + s] = ((AttributeStreamOfFloat) src).m_buffer[srcStart + + n + s]; + } + } + } + } + + @Override + public void insertRange(int start, double value, int count, int validSize) { + if (m_bReadonly) + throw new GeometryException("invalid_call"); + + System.arraycopy(m_buffer, start, m_buffer, start + count, validSize + - start); + + float v = (float) value; + for (int i = 0; i < count; i++) { + m_buffer[start + i] = v; + } + } + + @Override + public void insertAttributes(int start, Point pt, int semantics, + int validSize) { + if (m_bReadonly) + throw new GeometryException("invalid_call"); + + int comp = VertexDescription.getComponentCount(semantics); + + System.arraycopy(m_buffer, start, m_buffer, start + comp, validSize + - start); + + for (int c = 0; c < comp; c++) { + m_buffer[start + c] = (float) pt.getAttributeAsDbl(semantics, c); + } + } + + @Override + public void eraseRange(int index, int count, int validSize) { + if (m_bReadonly) + throw new GeometryException("invalid_call"); + + if (index + count > m_size) + throw new GeometryException("invalid_call"); + + System.arraycopy(m_buffer, index + count, m_buffer, index, validSize + - (index + count)); + m_size -= count; + } + + @Override + public void readRange(int srcStart, int count, ByteBuffer dst, + int dstOffset, boolean bForward) { + if (srcStart < 0 || count < 0 || dstOffset < 0 + || size() < count + srcStart) + throw new IllegalArgumentException(); + + final int elmSize = NumberUtils.sizeOf((double) 0); + + if (dst.capacity() < (int) (dstOffset + elmSize * count)) + throw new IllegalArgumentException(); + + if (count == 0) + return; + + int j = srcStart; + if (!bForward) + j += count - 1; + + final int dj = bForward ? 1 : -1; + + int offset = dstOffset; + for (int i = 0; i < count; i++, offset += elmSize) { + dst.putFloat(offset, m_buffer[j]); + j += dj; + } + + } + + @Override + public void reverseRange(int index, int count, int stride) { + if (m_bReadonly) + throw new GeometryException("invalid_call"); + + if (stride < 1 || count % stride != 0) + throw new GeometryException("invalid_call"); + + int cIterations = count >> 1; + int n = count; + + for (int i = 0; i < cIterations; i += stride) { + n -= stride; + + for (int s = 0; s < stride; s++) { + float temp = m_buffer[index + i + s]; + m_buffer[index + i + s] = m_buffer[index + n + s]; + m_buffer[index + n + s] = temp; + } + } + } + + @Override + public void setRange(double value, int start, int count) { + if (start < 0 || count < 0 || start < 0 || count + start > size()) + throw new IllegalArgumentException(); + + float v = (float) value; + for (int i = start, n = start + count; i < n; i++) + write(i, v); + } + + @Override + public void writeRange(int startElement, int count, + AttributeStreamBase _src, int srcStart, boolean bForward, int stride) { + if (startElement < 0 || count < 0 || srcStart < 0) + throw new IllegalArgumentException(); + + if (!bForward && (stride <= 0 || (count % stride != 0))) + throw new IllegalArgumentException(); + + AttributeStreamOfFloat src = (AttributeStreamOfFloat) _src; // the input + // type must + // match + + if (src.size() < (int) (srcStart + count)) + throw new IllegalArgumentException(); + + if (count == 0) + return; + + if (size() < count + startElement) + resize(count + startElement); + + if (_src == (AttributeStreamBase) this) { + _selfWriteRangeImpl(startElement, count, srcStart, bForward, stride); + return; + } + + if (bForward) { + int j = startElement; + int offset = srcStart; + for (int i = 0; i < count; i++) { + m_buffer[j] = src.m_buffer[offset]; + j++; + offset++; + } + } else { + int j = startElement; + int offset = srcStart + count - stride; + if (stride == 1) { + for (int i = 0; i < count; i++) { + m_buffer[j] = src.m_buffer[offset]; + j++; + offset--; + } + } else { + for (int i = 0, n = count / stride; i < n; i++) { + for (int k = 0; k < stride; k++) + m_buffer[j + k] = src.m_buffer[offset + k]; + + j += stride; + offset -= stride; + } + } + } + } + + private void _selfWriteRangeImpl(int toElement, int count, int fromElement, + boolean bForward, int stride) { + + // writing from to this stream. + if (bForward) { + if (toElement == fromElement) + return; + } + + int offset; + int j; + int dj; + + if (fromElement < toElement) { + offset = fromElement + count - stride; + j = toElement + count - stride; + for (int i = 0, n = count / 2; i < n; i++) { + for (int k = 0; k < stride; k++) { + m_buffer[j + k] = m_buffer[offset + k]; + } + j -= stride; + offset -= stride; + } + } else { + offset = fromElement; + j = toElement; + dj = 1; + for (int i = 0; i < count; i++) { + m_buffer[j] = m_buffer[offset]; + j += 1; + offset++; + } + } + + if (!bForward) { + // reverse what we written + j = toElement; + offset = toElement + count - stride; + dj = stride; + for (int i = 0, n = count / 2; i < n; i++) { + for (int k = 0; k < stride; k++) { + float v = m_buffer[j + k]; + m_buffer[j + k] = m_buffer[offset + k]; + m_buffer[offset + k] = v; + } + j += stride; + offset -= stride; + } + } + } + + @Override + public void writeRange(int startElement, int count, ByteBuffer src, + int offsetBytes, boolean bForward) { + if (startElement < 0 || count < 0 || offsetBytes < 0) + throw new IllegalArgumentException(); + + final int elmSize = NumberUtils.sizeOf((double) 0); + if (src.capacity() < (int) (offsetBytes + elmSize * count)) + throw new IllegalArgumentException(); + + if (count == 0) + return; + + if (size() < count + startElement) + resize(count + startElement); + + int j = startElement; + if (!bForward) + j += count - 1; + + final int dj = bForward ? 1 : -1; + + int offset = offsetBytes; + for (int i = 0; i < count; i++, offset += elmSize) { + m_buffer[j] = src.getFloat(offset); + j += dj; + } + + } } diff --git a/src/main/java/com/esri/core/geometry/AttributeStreamOfInt16.java b/src/main/java/com/esri/core/geometry/AttributeStreamOfInt16.java index a75ede20..b9400dd7 100644 --- a/src/main/java/com/esri/core/geometry/AttributeStreamOfInt16.java +++ b/src/main/java/com/esri/core/geometry/AttributeStreamOfInt16.java @@ -36,116 +36,115 @@ final class AttributeStreamOfInt16 extends AttributeStreamBase { private short[] m_buffer = null; private int m_size; - public int size() { - return m_size; - } - - public void reserve(int reserve)// only in Java - { - if (reserve <= 0) - return; - if (m_buffer == null) - m_buffer = new short[reserve]; - else { - if (reserve <= m_buffer.length) - return; - short[] buf = new short[reserve]; - System.arraycopy(m_buffer, 0, buf, 0, m_size); - m_buffer = buf; - } - - } - - public int capacity() { - return m_buffer != null ? m_buffer.length : 0; - } - - public AttributeStreamOfInt16(int size) { - int sz = size; - if (sz < 2) - sz = 2; - m_buffer = new short[sz]; - m_size = size; - } - - public AttributeStreamOfInt16(int size, short defaultValue) { - int sz = size; - if (sz < 2) - sz = 2; - m_buffer = new short[sz]; - m_size = size; - for (int i = 0; i < size; i++) - m_buffer[i] = defaultValue; - } - - public AttributeStreamOfInt16(AttributeStreamOfInt16 other) { - m_buffer = other.m_buffer.clone(); - m_size = other.m_size; - } - - public AttributeStreamOfInt16(AttributeStreamOfInt16 other, int maxSize) { - m_size = other.size(); - if (m_size > maxSize) - m_size = maxSize; - int sz = m_size; - if (sz < 2) - sz = 2; - m_buffer = new short[sz]; - System.arraycopy(other.m_buffer, 0, m_buffer, 0, m_size); - } - - /** - * Reads a value from the buffer at given offset. - * - * @param offset is the element number in the stream. - */ - public short read(int offset) { - return m_buffer[offset]; - } - - /** - * Overwrites given element with new value. - * - * @param offset is the element number in the stream. - * @param value is the value to write. - */ - public void write(int offset, short value) { - if (m_bReadonly) { - throw new RuntimeException("invalid_call"); - } - m_buffer[offset] = value; - } - - /** - * Adds a new value at the end of the stream. - * - * @param offset is the element number in the stream. - * @param value is the value to write. - */ - public void add(short v) { - resize(m_size + 1); - m_buffer[m_size - 1] = v; - } - - @Override - public AttributeStreamBase restrictedClone(int maxsize) { - int len = m_size; - int newSize = maxsize < len ? maxsize : len; - short[] newBuffer = new short[newSize]; - System.arraycopy(m_buffer, 0, newBuffer, 0, newSize); - m_buffer = newBuffer; - m_size = newSize; - return this; - } - - @Override - public int virtualSize() { - return size(); - } + public int size() { + return m_size; + } - @Override - public long estimateMemorySize() + public void reserve(int reserve)// only in Java { + if (reserve <= 0) + return; + if (m_buffer == null) + m_buffer = new short[reserve]; + else { + if (reserve <= m_buffer.length) + return; + short[] buf = new short[reserve]; + System.arraycopy(m_buffer, 0, buf, 0, m_size); + m_buffer = buf; + } + + } + + public int capacity() { + return m_buffer != null ? m_buffer.length : 0; + } + + public AttributeStreamOfInt16(int size) { + int sz = size; + if (sz < 2) + sz = 2; + m_buffer = new short[sz]; + m_size = size; + } + + public AttributeStreamOfInt16(int size, short defaultValue) { + int sz = size; + if (sz < 2) + sz = 2; + m_buffer = new short[sz]; + m_size = size; + for (int i = 0; i < size; i++) + m_buffer[i] = defaultValue; + } + + public AttributeStreamOfInt16(AttributeStreamOfInt16 other) { + m_buffer = other.m_buffer.clone(); + m_size = other.m_size; + } + + public AttributeStreamOfInt16(AttributeStreamOfInt16 other, int maxSize) { + m_size = other.size(); + if (m_size > maxSize) + m_size = maxSize; + int sz = m_size; + if (sz < 2) + sz = 2; + m_buffer = new short[sz]; + System.arraycopy(other.m_buffer, 0, m_buffer, 0, m_size); + } + + /** + * Reads a value from the buffer at given offset. + * + * @param offset is the element number in the stream. + */ + public short read(int offset) { + return m_buffer[offset]; + } + + /** + * Overwrites given element with new value. + * + * @param offset is the element number in the stream. + * @param value is the value to write. + */ + public void write(int offset, short value) { + if (m_bReadonly) { + throw new RuntimeException("invalid_call"); + } + m_buffer[offset] = value; + } + + /** + * Adds a new value at the end of the stream. + * + * @param offset is the element number in the stream. + * @param value is the value to write. + */ + public void add(short v) { + resize(m_size + 1); + m_buffer[m_size - 1] = v; + } + + @Override + public AttributeStreamBase restrictedClone(int maxsize) { + int len = m_size; + int newSize = maxsize < len ? maxsize : len; + short[] newBuffer = new short[newSize]; + System.arraycopy(m_buffer, 0, newBuffer, 0, newSize); + m_buffer = newBuffer; + m_size = newSize; + return this; + } + + @Override + public int virtualSize() { + return size(); + } + + @Override + public long estimateMemorySize() { return SIZE_OF_ATTRIBUTE_STREAM_OF_INT16 + sizeOfShortArray(m_buffer.length); } @@ -154,447 +153,447 @@ public int getPersistence() { return Persistence.enumInt16; } - @Override - public double readAsDbl(int offset) { - return read(offset); - } - - @Override - public int readAsInt(int offset) { - return (int) read(offset); - } - - @Override - public long readAsInt64(int offset) { - return (long) read(offset); - } - - @Override - public void resize(int newSize) { - if (m_bLockedInSize) - throw new GeometryException( - "invalid call. Attribute Stream is locked and cannot be resized."); - - if (newSize <= m_size) { - if ((newSize * 5) / 4 < m_buffer.length) {// decrease when the 25% - // margin is exceeded - short[] newBuffer = new short[newSize]; - System.arraycopy(m_buffer, 0, newBuffer, 0, newSize); - m_buffer = newBuffer; - } - m_size = newSize; - } else { - if (newSize > m_buffer.length) { - int sz = (newSize < 64) ? Math.max(newSize * 2, 4) - : (newSize * 5) / 4; - short[] newBuffer = new short[sz]; - System.arraycopy(m_buffer, 0, newBuffer, 0, m_size); - m_buffer = newBuffer; - } - - m_size = newSize; - } - } - - @Override - public void resizePreserveCapacity(int newSize)// java only method - { - if (m_buffer == null || newSize > m_buffer.length) - resize(newSize); - if (m_bLockedInSize) - throw new GeometryException( - "invalid call. Attribute Stream is locked and cannot be resized."); - - m_size = newSize; - } - - @Override - public void resize(int newSize, double defaultValue) { - if (m_bLockedInSize) - throw new GeometryException( - "invalid call. Attribute Stream is locked and cannot be resized."); - if (newSize <= m_size) { - if ((newSize * 5) / 4 < m_buffer.length) {// decrease when the 25% - // margin is exceeded - short[] newBuffer = new short[newSize]; - System.arraycopy(m_buffer, 0, newBuffer, 0, newSize); - m_buffer = newBuffer; - } - m_size = newSize; - } else { - if (newSize > m_buffer.length) { - int sz = (newSize < 64) ? Math.max(newSize * 2, 4) - : (newSize * 5) / 4; - short[] newBuffer = new short[sz]; - System.arraycopy(m_buffer, 0, newBuffer, 0, m_size); - m_buffer = newBuffer; - } - - for (int i = m_size; i < newSize; i++) - m_buffer[i] = (short) defaultValue; - - m_size = newSize; - } - } - - @Override - public void writeAsDbl(int offset, double d) { - write(offset, (short) d); - } - - @Override - public void writeAsInt64(int offset, long d) { - write(offset, (short) d); - } - - @Override - public void writeAsInt(int offset, int d) { - write(offset, (short) d); - } - - // @Override - // public void writeRange(int srcStart, int count, ByteBuffer dst, - // int dstOffsetBytes) { - // // TODO Auto-generated method stub - // - // } - - @Override - public int calculateHashImpl(int hashCode, int start, int end) { - for (int i = start, n = size(); i < n && i < end; i++) - hashCode = NumberUtils.hash(hashCode, read(i)); - - return hashCode; - } - - @Override - public boolean equals(AttributeStreamBase other, int start, int end) { - if (other == null) - return false; - - if (!(other instanceof AttributeStreamOfInt16)) - return false; - - AttributeStreamOfInt16 _other = (AttributeStreamOfInt16) other; - - int size = size(); - int sizeOther = _other.size(); - - if (end > size || end > sizeOther && (size != sizeOther)) - return false; - - if (end > size) - end = size; - - for (int i = start; i < end; i++) - if (read(i) != _other.read(i)) - return false; - - return true; - } - - @Override - public void addRange(AttributeStreamBase src, int start, int count, - boolean bForward, int stride) { - if (m_bReadonly) - throw new GeometryException("invalid_call"); - - if (!bForward && (stride < 1 || count % stride != 0)) - throw new IllegalArgumentException(); - - int oldSize = m_size; - int newSize = oldSize + count; - resize(newSize); - - if (bForward) { - System.arraycopy(((AttributeStreamOfInt16) src).m_buffer, start, - m_buffer, oldSize, count); - } else { - int n = count; - - for (int i = 0; i < count; i += stride) { - n -= stride; - - for (int s = 0; s < stride; s++) { - m_buffer[oldSize + i + s] = ((AttributeStreamOfInt16) src).m_buffer[start - + n + s]; - } - } - } - } - - @Override - public void insertRange(int start, AttributeStreamBase src, int srcStart, - int count, boolean bForward, int stride, int validSize) { - if (m_bReadonly) - throw new GeometryException("invalid_call"); - - if (!bForward && (stride < 1 || count % stride != 0)) - throw new IllegalArgumentException(); - - System.arraycopy(m_buffer, start, m_buffer, start + count, validSize - - start); - - if (m_buffer == ((AttributeStreamOfInt16) src).m_buffer) { - if (start < srcStart) - srcStart += count; - } - - if (bForward) { - System.arraycopy(((AttributeStreamOfInt16) src).m_buffer, srcStart, - m_buffer, start, count); - } else { - int n = count; - - for (int i = 0; i < count; i += stride) { - n -= stride; - - for (int s = 0; s < stride; s++) { - m_buffer[start + i + s] = ((AttributeStreamOfInt16) src).m_buffer[srcStart - + n + s]; - } - } - } - } - - @Override - public void insertRange(int start, double value, int count, int validSize) { - if (m_bReadonly) - throw new GeometryException("invalid_call"); - - System.arraycopy(m_buffer, start, m_buffer, start + count, validSize - - start); - - short v = (short) value; - for (int i = 0; i < count; i++) { - m_buffer[start + i] = v; - } - } - - @Override - public void insertAttributes(int start, Point pt, int semantics, - int validSize) { - if (m_bReadonly) - throw new GeometryException("invalid_call"); - - int comp = VertexDescription.getComponentCount(semantics); - - System.arraycopy(m_buffer, start, m_buffer, start + comp, validSize - - start); - - for (int c = 0; c < comp; c++) { - m_buffer[start + c] = (short) pt.getAttributeAsDbl(semantics, c); - } - } - - @Override - public void eraseRange(int index, int count, int validSize) { - if (m_bReadonly) - throw new GeometryException("invalid_call"); - - if (index + count > m_size) - throw new GeometryException("invalid_call"); - - System.arraycopy(m_buffer, index + count, m_buffer, index, validSize - - (index + count)); - m_size -= count; - } - - @Override - public void readRange(int srcStart, int count, ByteBuffer dst, - int dstOffset, boolean bForward) { - if (srcStart < 0 || count < 0 || dstOffset < 0 - || size() < count + srcStart) - throw new IllegalArgumentException(); - - final int elmSize = NumberUtils.sizeOf((double) 0); - - if (dst.capacity() < (int) (dstOffset + elmSize * count)) - throw new IllegalArgumentException(); - - if (count == 0) - return; - - int j = srcStart; - if (!bForward) - j += count - 1; - - final int dj = bForward ? 1 : -1; - - int offset = dstOffset; - for (int i = 0; i < count; i++, offset += elmSize) { - dst.putShort(offset, m_buffer[j]); - j += dj; - } - - } - - @Override - public void reverseRange(int index, int count, int stride) { - if (m_bReadonly) - throw new GeometryException("invalid_call"); - - if (stride < 1 || count % stride != 0) - throw new GeometryException("invalid_call"); - - int cIterations = count >> 1; - int n = count; - - for (int i = 0; i < cIterations; i += stride) { - n -= stride; - - for (int s = 0; s < stride; s++) { - short temp = m_buffer[index + i + s]; - m_buffer[index + i + s] = m_buffer[index + n + s]; - m_buffer[index + n + s] = temp; - } - } - } - - @Override - public void setRange(double value, int start, int count) { - if (start < 0 || count < 0 || start < 0 || count + start > size()) - throw new IllegalArgumentException(); - - short v = (short) value; - for (int i = start, n = start + count; i < n; i++) - write(i, v); - } - - @Override - public void writeRange(int startElement, int count, - AttributeStreamBase _src, int srcStart, boolean bForward, int stride) { - if (startElement < 0 || count < 0 || srcStart < 0) - throw new IllegalArgumentException(); - - if (!bForward && (stride <= 0 || (count % stride != 0))) - throw new IllegalArgumentException(); - - AttributeStreamOfInt16 src = (AttributeStreamOfInt16) _src; // the input - // type must - // match - - if (src.size() < (int) (srcStart + count)) - throw new IllegalArgumentException(); - - if (count == 0) - return; - - if (size() < count + startElement) - resize(count + startElement); - - if (_src == (AttributeStreamBase) this) { - _selfWriteRangeImpl(startElement, count, srcStart, bForward, stride); - return; - } - - if (bForward) { - int j = startElement; - int offset = srcStart; - for (int i = 0; i < count; i++) { - m_buffer[j] = src.m_buffer[offset]; - j++; - offset++; - } - } else { - int j = startElement; - int offset = srcStart + count - stride; - if (stride == 1) { - for (int i = 0; i < count; i++) { - m_buffer[j] = src.m_buffer[offset]; - j++; - offset--; - } - } else { - for (int i = 0, n = count / stride; i < n; i++) { - for (int k = 0; k < stride; k++) - m_buffer[j + k] = src.m_buffer[offset + k]; - - j += stride; - offset -= stride; - } - } - } - } - - private void _selfWriteRangeImpl(int toElement, int count, int fromElement, - boolean bForward, int stride) { - - // writing from to this stream. - if (bForward) { - if (toElement == fromElement) - return; - } - - int offset; - int j; - int dj; - - if (fromElement < toElement) { - offset = fromElement + count - stride; - j = toElement + count - stride; - for (int i = 0, n = count / 2; i < n; i++) { - for (int k = 0; k < stride; k++) { - m_buffer[j + k] = m_buffer[offset + k]; - } - j -= stride; - offset -= stride; - } - } else { - offset = fromElement; - j = toElement; - dj = 1; - for (int i = 0; i < count; i++) { - m_buffer[j] = m_buffer[offset]; - j += 1; - offset++; - } - } - - if (!bForward) { - // reverse what we written - j = toElement; - offset = toElement + count - stride; - dj = stride; - for (int i = 0, n = count / 2; i < n; i++) { - for (int k = 0; k < stride; k++) { - short v = m_buffer[j + k]; - m_buffer[j + k] = m_buffer[offset + k]; - m_buffer[offset + k] = v; - } - j += stride; - offset -= stride; - } - } - } - - @Override - public void writeRange(int startElement, int count, ByteBuffer src, - int offsetBytes, boolean bForward) { - if (startElement < 0 || count < 0 || offsetBytes < 0) - throw new IllegalArgumentException(); - - final int elmSize = NumberUtils.sizeOf((double) 0); - if (src.capacity() < (int) (offsetBytes + elmSize * count)) - throw new IllegalArgumentException(); - - if (count == 0) - return; - - if (size() < count + startElement) - resize(count + startElement); - - int j = startElement; - if (!bForward) - j += count - 1; - - final int dj = bForward ? 1 : -1; - - int offset = offsetBytes; - for (int i = 0; i < count; i++, offset += elmSize) { - m_buffer[j] = src.getShort(offset); - j += dj; - } - - } + @Override + public double readAsDbl(int offset) { + return read(offset); + } + + @Override + public int readAsInt(int offset) { + return (int) read(offset); + } + + @Override + public long readAsInt64(int offset) { + return (long) read(offset); + } + + @Override + public void resize(int newSize) { + if (m_bLockedInSize) + throw new GeometryException( + "invalid call. Attribute Stream is locked and cannot be resized."); + + if (newSize <= m_size) { + if ((newSize * 5) / 4 < m_buffer.length) {// decrease when the 25% + // margin is exceeded + short[] newBuffer = new short[newSize]; + System.arraycopy(m_buffer, 0, newBuffer, 0, newSize); + m_buffer = newBuffer; + } + m_size = newSize; + } else { + if (newSize > m_buffer.length) { + int sz = (newSize < 64) ? Math.max(newSize * 2, 4) + : (newSize * 5) / 4; + short[] newBuffer = new short[sz]; + System.arraycopy(m_buffer, 0, newBuffer, 0, m_size); + m_buffer = newBuffer; + } + + m_size = newSize; + } + } + + @Override + public void resizePreserveCapacity(int newSize)// java only method + { + if (m_buffer == null || newSize > m_buffer.length) + resize(newSize); + if (m_bLockedInSize) + throw new GeometryException( + "invalid call. Attribute Stream is locked and cannot be resized."); + + m_size = newSize; + } + + @Override + public void resize(int newSize, double defaultValue) { + if (m_bLockedInSize) + throw new GeometryException( + "invalid call. Attribute Stream is locked and cannot be resized."); + if (newSize <= m_size) { + if ((newSize * 5) / 4 < m_buffer.length) {// decrease when the 25% + // margin is exceeded + short[] newBuffer = new short[newSize]; + System.arraycopy(m_buffer, 0, newBuffer, 0, newSize); + m_buffer = newBuffer; + } + m_size = newSize; + } else { + if (newSize > m_buffer.length) { + int sz = (newSize < 64) ? Math.max(newSize * 2, 4) + : (newSize * 5) / 4; + short[] newBuffer = new short[sz]; + System.arraycopy(m_buffer, 0, newBuffer, 0, m_size); + m_buffer = newBuffer; + } + + for (int i = m_size; i < newSize; i++) + m_buffer[i] = (short) defaultValue; + + m_size = newSize; + } + } + + @Override + public void writeAsDbl(int offset, double d) { + write(offset, (short) d); + } + + @Override + public void writeAsInt64(int offset, long d) { + write(offset, (short) d); + } + + @Override + public void writeAsInt(int offset, int d) { + write(offset, (short) d); + } + + // @Override + // public void writeRange(int srcStart, int count, ByteBuffer dst, + // int dstOffsetBytes) { + // // TODO Auto-generated method stub + // + // } + + @Override + public int calculateHashImpl(int hashCode, int start, int end) { + for (int i = start, n = size(); i < n && i < end; i++) + hashCode = NumberUtils.hash(hashCode, read(i)); + + return hashCode; + } + + @Override + public boolean equals(AttributeStreamBase other, int start, int end) { + if (other == null) + return false; + + if (!(other instanceof AttributeStreamOfInt16)) + return false; + + AttributeStreamOfInt16 _other = (AttributeStreamOfInt16) other; + + int size = size(); + int sizeOther = _other.size(); + + if (end > size || end > sizeOther && (size != sizeOther)) + return false; + + if (end > size) + end = size; + + for (int i = start; i < end; i++) + if (read(i) != _other.read(i)) + return false; + + return true; + } + + @Override + public void addRange(AttributeStreamBase src, int start, int count, + boolean bForward, int stride) { + if (m_bReadonly) + throw new GeometryException("invalid_call"); + + if (!bForward && (stride < 1 || count % stride != 0)) + throw new IllegalArgumentException(); + + int oldSize = m_size; + int newSize = oldSize + count; + resize(newSize); + + if (bForward) { + System.arraycopy(((AttributeStreamOfInt16) src).m_buffer, start, + m_buffer, oldSize, count); + } else { + int n = count; + + for (int i = 0; i < count; i += stride) { + n -= stride; + + for (int s = 0; s < stride; s++) { + m_buffer[oldSize + i + s] = ((AttributeStreamOfInt16) src).m_buffer[start + + n + s]; + } + } + } + } + + @Override + public void insertRange(int start, AttributeStreamBase src, int srcStart, + int count, boolean bForward, int stride, int validSize) { + if (m_bReadonly) + throw new GeometryException("invalid_call"); + + if (!bForward && (stride < 1 || count % stride != 0)) + throw new IllegalArgumentException(); + + System.arraycopy(m_buffer, start, m_buffer, start + count, validSize + - start); + + if (m_buffer == ((AttributeStreamOfInt16) src).m_buffer) { + if (start < srcStart) + srcStart += count; + } + + if (bForward) { + System.arraycopy(((AttributeStreamOfInt16) src).m_buffer, srcStart, + m_buffer, start, count); + } else { + int n = count; + + for (int i = 0; i < count; i += stride) { + n -= stride; + + for (int s = 0; s < stride; s++) { + m_buffer[start + i + s] = ((AttributeStreamOfInt16) src).m_buffer[srcStart + + n + s]; + } + } + } + } + + @Override + public void insertRange(int start, double value, int count, int validSize) { + if (m_bReadonly) + throw new GeometryException("invalid_call"); + + System.arraycopy(m_buffer, start, m_buffer, start + count, validSize + - start); + + short v = (short) value; + for (int i = 0; i < count; i++) { + m_buffer[start + i] = v; + } + } + + @Override + public void insertAttributes(int start, Point pt, int semantics, + int validSize) { + if (m_bReadonly) + throw new GeometryException("invalid_call"); + + int comp = VertexDescription.getComponentCount(semantics); + + System.arraycopy(m_buffer, start, m_buffer, start + comp, validSize + - start); + + for (int c = 0; c < comp; c++) { + m_buffer[start + c] = (short) pt.getAttributeAsDbl(semantics, c); + } + } + + @Override + public void eraseRange(int index, int count, int validSize) { + if (m_bReadonly) + throw new GeometryException("invalid_call"); + + if (index + count > m_size) + throw new GeometryException("invalid_call"); + + System.arraycopy(m_buffer, index + count, m_buffer, index, validSize + - (index + count)); + m_size -= count; + } + + @Override + public void readRange(int srcStart, int count, ByteBuffer dst, + int dstOffset, boolean bForward) { + if (srcStart < 0 || count < 0 || dstOffset < 0 + || size() < count + srcStart) + throw new IllegalArgumentException(); + + final int elmSize = NumberUtils.sizeOf((double) 0); + + if (dst.capacity() < (int) (dstOffset + elmSize * count)) + throw new IllegalArgumentException(); + + if (count == 0) + return; + + int j = srcStart; + if (!bForward) + j += count - 1; + + final int dj = bForward ? 1 : -1; + + int offset = dstOffset; + for (int i = 0; i < count; i++, offset += elmSize) { + dst.putShort(offset, m_buffer[j]); + j += dj; + } + + } + + @Override + public void reverseRange(int index, int count, int stride) { + if (m_bReadonly) + throw new GeometryException("invalid_call"); + + if (stride < 1 || count % stride != 0) + throw new GeometryException("invalid_call"); + + int cIterations = count >> 1; + int n = count; + + for (int i = 0; i < cIterations; i += stride) { + n -= stride; + + for (int s = 0; s < stride; s++) { + short temp = m_buffer[index + i + s]; + m_buffer[index + i + s] = m_buffer[index + n + s]; + m_buffer[index + n + s] = temp; + } + } + } + + @Override + public void setRange(double value, int start, int count) { + if (start < 0 || count < 0 || start < 0 || count + start > size()) + throw new IllegalArgumentException(); + + short v = (short) value; + for (int i = start, n = start + count; i < n; i++) + write(i, v); + } + + @Override + public void writeRange(int startElement, int count, + AttributeStreamBase _src, int srcStart, boolean bForward, int stride) { + if (startElement < 0 || count < 0 || srcStart < 0) + throw new IllegalArgumentException(); + + if (!bForward && (stride <= 0 || (count % stride != 0))) + throw new IllegalArgumentException(); + + AttributeStreamOfInt16 src = (AttributeStreamOfInt16) _src; // the input + // type must + // match + + if (src.size() < (int) (srcStart + count)) + throw new IllegalArgumentException(); + + if (count == 0) + return; + + if (size() < count + startElement) + resize(count + startElement); + + if (_src == (AttributeStreamBase) this) { + _selfWriteRangeImpl(startElement, count, srcStart, bForward, stride); + return; + } + + if (bForward) { + int j = startElement; + int offset = srcStart; + for (int i = 0; i < count; i++) { + m_buffer[j] = src.m_buffer[offset]; + j++; + offset++; + } + } else { + int j = startElement; + int offset = srcStart + count - stride; + if (stride == 1) { + for (int i = 0; i < count; i++) { + m_buffer[j] = src.m_buffer[offset]; + j++; + offset--; + } + } else { + for (int i = 0, n = count / stride; i < n; i++) { + for (int k = 0; k < stride; k++) + m_buffer[j + k] = src.m_buffer[offset + k]; + + j += stride; + offset -= stride; + } + } + } + } + + private void _selfWriteRangeImpl(int toElement, int count, int fromElement, + boolean bForward, int stride) { + + // writing from to this stream. + if (bForward) { + if (toElement == fromElement) + return; + } + + int offset; + int j; + int dj; + + if (fromElement < toElement) { + offset = fromElement + count - stride; + j = toElement + count - stride; + for (int i = 0, n = count / 2; i < n; i++) { + for (int k = 0; k < stride; k++) { + m_buffer[j + k] = m_buffer[offset + k]; + } + j -= stride; + offset -= stride; + } + } else { + offset = fromElement; + j = toElement; + dj = 1; + for (int i = 0; i < count; i++) { + m_buffer[j] = m_buffer[offset]; + j += 1; + offset++; + } + } + + if (!bForward) { + // reverse what we written + j = toElement; + offset = toElement + count - stride; + dj = stride; + for (int i = 0, n = count / 2; i < n; i++) { + for (int k = 0; k < stride; k++) { + short v = m_buffer[j + k]; + m_buffer[j + k] = m_buffer[offset + k]; + m_buffer[offset + k] = v; + } + j += stride; + offset -= stride; + } + } + } + + @Override + public void writeRange(int startElement, int count, ByteBuffer src, + int offsetBytes, boolean bForward) { + if (startElement < 0 || count < 0 || offsetBytes < 0) + throw new IllegalArgumentException(); + + final int elmSize = NumberUtils.sizeOf((double) 0); + if (src.capacity() < (int) (offsetBytes + elmSize * count)) + throw new IllegalArgumentException(); + + if (count == 0) + return; + + if (size() < count + startElement) + resize(count + startElement); + + int j = startElement; + if (!bForward) + j += count - 1; + + final int dj = bForward ? 1 : -1; + + int offset = offsetBytes; + for (int i = 0; i < count; i++, offset += elmSize) { + m_buffer[j] = src.getShort(offset); + j += dj; + } + + } } diff --git a/src/main/java/com/esri/core/geometry/AttributeStreamOfInt32.java b/src/main/java/com/esri/core/geometry/AttributeStreamOfInt32.java index e8d9b492..e53e4689 100644 --- a/src/main/java/com/esri/core/geometry/AttributeStreamOfInt32.java +++ b/src/main/java/com/esri/core/geometry/AttributeStreamOfInt32.java @@ -1,5 +1,5 @@ /* - Copyright 1995-2017 Esri + Copyright 1995-2018 Esri Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -27,133 +27,145 @@ import com.esri.core.geometry.VertexDescription.Persistence; +import java.io.IOException; +import java.io.ObjectStreamException; +import java.io.Serializable; import java.nio.ByteBuffer; +import java.nio.IntBuffer; import java.util.Arrays; import static com.esri.core.geometry.SizeOf.SIZE_OF_ATTRIBUTE_STREAM_OF_INT32; import static com.esri.core.geometry.SizeOf.sizeOfIntArray; -final class AttributeStreamOfInt32 extends AttributeStreamBase { - private int[] m_buffer = null; +final class AttributeStreamOfInt32 extends AttributeStreamBase implements Serializable { + private static final long serialVersionUID = 1L; + + transient private int[] m_buffer = null; private int m_size; - public void reserve(int reserve) { - if (reserve <= 0) - return; - if (m_buffer == null) - m_buffer = new int[reserve]; - else { - if (reserve <= m_buffer.length) - return; - int[] buf = new int[reserve]; - System.arraycopy(m_buffer, 0, buf, 0, m_buffer.length); - m_buffer = buf; - } - - } - - public int size() { - return m_size; - } - - public int capacity() { - return m_buffer != null ? m_buffer.length : 0; - } - - public AttributeStreamOfInt32(int size) { - int sz = size; - if (sz < 2) - sz = 2; - m_buffer = new int[sz]; - m_size = size; - } - - public AttributeStreamOfInt32(int size, int defaultValue) { - int sz = size; - if (sz < 2) - sz = 2; - m_buffer = new int[sz]; - m_size = size; - Arrays.fill(m_buffer, 0, size, defaultValue); - // for (int i = 0; i < size; i++) - // m_buffer[i] = defaultValue; - } - - public AttributeStreamOfInt32(AttributeStreamOfInt32 other) { - m_buffer = other.m_buffer.clone(); - m_size = other.m_size; - } - - public AttributeStreamOfInt32(AttributeStreamOfInt32 other, int maxSize) { - m_size = other.size(); - if (m_size > maxSize) - m_size = maxSize; - int sz = m_size; - if (sz < 2) - sz = 2; - m_buffer = new int[sz]; - System.arraycopy(other.m_buffer, 0, m_buffer, 0, m_size); - } - - /** - * Reads a value from the buffer at given offset. - * - * @param offset is the element number in the stream. - */ - public int read(int offset) { - return m_buffer[offset]; - } - - public int get(int offset) { - return m_buffer[offset]; - } - - /** - * Overwrites given element with new value. - * - * @param offset is the element number in the stream. - * @param value is the value to write. - */ - public void write(int offset, int value) { - if (m_bReadonly) { - throw new RuntimeException("invalid_call"); - } - m_buffer[offset] = value; - } - - public void set(int offset, int value) { - if (m_bReadonly) { - throw new RuntimeException("invalid_call"); - } - m_buffer[offset] = value; - } - - /** - * Adds a new value at the end of the stream. - * - * @param offset is the element number in the stream. - * @param value is the value to write. - */ - public void add(int v) { - resize(m_size + 1); - m_buffer[m_size - 1] = v; - } - - @Override - public AttributeStreamBase restrictedClone(int maxsize) { - int len = m_size; - int newSize = maxsize < len ? maxsize : len; - int[] newBuffer = new int[newSize]; - System.arraycopy(m_buffer, 0, newBuffer, 0, newSize); - m_buffer = newBuffer; - m_size = newSize; - return this; - } - - @Override - public int virtualSize() { - return size(); - } + public void reserve(int reserve) + { + if (reserve <= 0) + return; + if (m_buffer == null) + m_buffer = new int[reserve]; + else { + if (reserve <= m_buffer.length) + return; + int[] buf = new int[reserve]; + System.arraycopy(m_buffer, 0, buf, 0, m_buffer.length); + m_buffer = buf; + } + + } + + public int size() { + return m_size; + } + + public int capacity() { + return m_buffer != null ? m_buffer.length : 0; + } + + public AttributeStreamOfInt32(int size) { + int sz = size; + if (sz < 2) + sz = 2; + m_buffer = new int[sz]; + m_size = size; + } + + public AttributeStreamOfInt32(int size, int defaultValue) { + int sz = size; + if (sz < 2) + sz = 2; + m_buffer = new int[sz]; + m_size = size; + Arrays.fill(m_buffer, 0, size, defaultValue); + // for (int i = 0; i < size; i++) + // m_buffer[i] = defaultValue; + } + + public AttributeStreamOfInt32(AttributeStreamOfInt32 other) { + m_buffer = other.m_buffer.clone(); + m_size = other.m_size; + } + + public AttributeStreamOfInt32(AttributeStreamOfInt32 other, int maxSize) { + m_size = other.size(); + if (m_size > maxSize) + m_size = maxSize; + int sz = m_size; + if (sz < 2) + sz = 2; + m_buffer = new int[sz]; + System.arraycopy(other.m_buffer, 0, m_buffer, 0, m_size); + } + + /** + * Reads a value from the buffer at given offset. + * + * @param offset + * is the element number in the stream. + */ + public int read(int offset) { + return m_buffer[offset]; + } + + public int get(int offset) { + return m_buffer[offset]; + } + + /** + * Overwrites given element with new value. + * + * @param offset + * is the element number in the stream. + * @param value + * is the value to write. + */ + public void write(int offset, int value) { + if (m_bReadonly) { + throw new RuntimeException("invalid_call"); + } + m_buffer[offset] = value; + } + + public void set(int offset, int value) { + if (m_bReadonly) { + throw new RuntimeException("invalid_call"); + } + m_buffer[offset] = value; + } + + /** + * Adds a new value at the end of the stream. + * + * @param offset + * is the element number in the stream. + * @param value + * is the value to write. + */ + public void add(int v) { + resize(m_size + 1); + m_buffer[m_size - 1] = v; + } + + @Override + public AttributeStreamBase restrictedClone(int maxsize) { + int len = m_size; + int newSize = maxsize < len ? maxsize : len; + int[] newBuffer = new int[newSize]; + System.arraycopy(m_buffer, 0, newBuffer, 0, newSize); + m_buffer = newBuffer; + m_size = newSize; + return this; + } + + @Override + public int virtualSize() { + return size(); + } @Override public long estimateMemorySize() @@ -166,562 +178,604 @@ public int getPersistence() { return Persistence.enumInt32; } - @Override - public double readAsDbl(int offset) { - return read(offset); - } - - @Override - public int readAsInt(int offset) { - return (int) read(offset); - } - - @Override - public long readAsInt64(int offset) { - return (long) read(offset); - } - - @Override - public void resize(int newSize) { - if (m_bLockedInSize) - throw new GeometryException( - "invalid call. Attribute Stream is locked and cannot be resized."); - - if (newSize <= m_size) { - if ((newSize * 5) / 4 < m_buffer.length) {// decrease when the 25% - // margin is exceeded - int[] newBuffer = new int[newSize]; - System.arraycopy(m_buffer, 0, newBuffer, 0, newSize); - m_buffer = newBuffer; - } - m_size = newSize; - } else { - if (newSize > m_buffer.length) { - int sz = (newSize < 64) ? Math.max(newSize * 2, 4) - : (newSize * 5) / 4; - int[] newBuffer = new int[sz]; - System.arraycopy(m_buffer, 0, newBuffer, 0, m_size); - m_buffer = newBuffer; - } - - m_size = newSize; - } - } - - @Override - public void resizePreserveCapacity(int newSize)// java only method - { - if (m_buffer == null || newSize > m_buffer.length) - resize(newSize); - if (m_bLockedInSize) - throw new GeometryException( - "invalid call. Attribute Stream is locked and cannot be resized."); - - m_size = newSize; - } - - @Override - public void resize(int newSize, double defaultValue) { - if (m_bLockedInSize) - throw new GeometryException( - "invalid call. Attribute Stream is locked and cannot be resized."); - if (newSize <= m_size) { - if ((newSize * 5) / 4 < m_buffer.length) {// decrease when the 25% - // margin is exceeded - int[] newBuffer = new int[newSize]; - System.arraycopy(m_buffer, 0, newBuffer, 0, newSize); - m_buffer = newBuffer; - } - m_size = newSize; - } else { - if (newSize > m_buffer.length) { - int sz = (newSize < 64) ? Math.max(newSize * 2, 4) - : (newSize * 5) / 4; - int[] newBuffer = new int[sz]; - System.arraycopy(m_buffer, 0, newBuffer, 0, m_size); - m_buffer = newBuffer; - } - - Arrays.fill(m_buffer, m_size, newSize, (int) defaultValue); - // for (int i = m_size; i < newSize; i++) - // m_buffer[i] = (int)defaultValue; - - m_size = newSize; - } - } - - @Override - public void writeAsDbl(int offset, double d) { - write(offset, (int) d); - } - - @Override - public void writeAsInt64(int offset, long d) { - write(offset, (int) d); - } - - @Override - public void writeAsInt(int offset, int d) { - write(offset, (int) d); - } - - // @Override - // public void writeRange(int srcStart, int count, ByteBuffer dst, - // int dstOffsetBytes) { - // // TODO Auto-generated method stub - // - // } - - @Override - public int calculateHashImpl(int hashCode, int start, int end) { - for (int i = start, n = size(); i < n && i < end; i++) - hashCode = NumberUtils.hash(hashCode, read(i)); - - return hashCode; - } - - @Override - public boolean equals(AttributeStreamBase other, int start, int end) { - if (other == null) - return false; - - if (!(other instanceof AttributeStreamOfInt32)) - return false; - - AttributeStreamOfInt32 _other = (AttributeStreamOfInt32) other; - - int size = size(); - int sizeOther = _other.size(); - - if (end > size || end > sizeOther && (size != sizeOther)) - return false; - - if (end > size) - end = size; - - for (int i = start; i < end; i++) - if (read(i) != _other.read(i)) - return false; - - return true; - } - - public int getLast() { - return m_buffer[m_size - 1]; - } - - public void setLast(int v) { - m_buffer[m_size - 1] = v; - } - - public void removeLast() { - resize(m_size - 1); - } - - // Finds element in the unsorted array and returns its index. Returns -1 if - // the element could not be found. - int findElement(int value) { - for (int i = 0, n = m_size; i < n; i++) { - if (m_buffer[i] == value) - return i; - } - return -1; - } - - // Returns True if element could be found in the array. - boolean hasElement(int value) { - return findElement(value) >= 0; - } - - // Removes the element from the array in constant time. - // It moves the last element of the array to the index and decrements the - // array size by 1. - void popElement(int index) { - assert (index >= 0 && index < m_size); - if (index < m_size - 1) { - m_buffer[index] = m_buffer[m_size - 1]; - } - - resize(m_size - 1); - } - - @Override - public void addRange(AttributeStreamBase src, int start, int count, - boolean bForward, int stride) { - if (m_bReadonly) - throw new GeometryException("invalid_call"); - - if (!bForward && (stride < 1 || count % stride != 0)) - throw new IllegalArgumentException(); - - int oldSize = m_size; - int newSize = oldSize + count; - resize(newSize); - - if (bForward) { - System.arraycopy(((AttributeStreamOfInt32) src).m_buffer, start, - m_buffer, oldSize, count); - } else { - int n = count; - - for (int i = 0; i < count; i += stride) { - n -= stride; - - for (int s = 0; s < stride; s++) { - m_buffer[oldSize + i + s] = ((AttributeStreamOfInt32) src).m_buffer[start - + n + s]; - } - } - } - } - - @Override - public void insertRange(int start, AttributeStreamBase src, int srcStart, - int count, boolean bForward, int stride, int validSize) { - if (m_bReadonly) - throw new GeometryException("invalid_call"); - - if (!bForward && (stride < 1 || count % stride != 0)) - throw new IllegalArgumentException(); - - System.arraycopy(m_buffer, start, m_buffer, start + count, validSize - - start); - - if (m_buffer == ((AttributeStreamOfInt32) src).m_buffer) { - if (start < srcStart) - srcStart += count; - } - - if (bForward) { - System.arraycopy(((AttributeStreamOfInt32) src).m_buffer, srcStart, - m_buffer, start, count); - } else { - int n = count; - - for (int i = 0; i < count; i += stride) { - n -= stride; - - for (int s = 0; s < stride; s++) { - m_buffer[start + i + s] = ((AttributeStreamOfInt32) src).m_buffer[srcStart - + n + s]; - } - } - } - } - - @Override - public void insertRange(int start, double value, int count, int validSize) { - if (m_bReadonly) - throw new GeometryException("invalid_call"); - - System.arraycopy(m_buffer, start, m_buffer, start + count, validSize - - start); - - int v = (int) value; - Arrays.fill(m_buffer, start, start + count, v); - // for (int i = 0; i < count; i++) - // { - // m_buffer[start + i] = v; - // } - } - - @Override - public void insertAttributes(int start, Point pt, int semantics, - int validSize) { - if (m_bReadonly) - throw new GeometryException("invalid_call"); - - int comp = VertexDescription.getComponentCount(semantics); - - System.arraycopy(m_buffer, start, m_buffer, start + comp, validSize - - start); - - for (int c = 0; c < comp; c++) { - m_buffer[start + c] = (int) pt.getAttributeAsDbl(semantics, c); - } - } - - @Override - public void eraseRange(int index, int count, int validSize) { - if (m_bReadonly) - throw new GeometryException("invalid_call"); - - if (index + count > m_size) - throw new GeometryException("invalid_call"); - - System.arraycopy(m_buffer, index + count, m_buffer, index, validSize - - (index + count)); - m_size -= count; - } - - @Override - public void readRange(int srcStart, int count, ByteBuffer dst, - int dstOffset, boolean bForward) { - if (srcStart < 0 || count < 0 || dstOffset < 0 - || size() < count + srcStart) - throw new IllegalArgumentException(); - - final int elmSize = NumberUtils.sizeOf((double) 0); - - if (dst.capacity() < (int) (dstOffset + elmSize * count)) - throw new IllegalArgumentException(); - - if (count == 0) - return; - - int j = srcStart; - if (!bForward) - j += count - 1; - final int dj = bForward ? 1 : -1; - int offset = dstOffset; - for (int i = 0; i < count; i++, offset += elmSize) { - dst.putInt(offset, m_buffer[j]); - j += dj; - } - } - - @Override - public void reverseRange(int index, int count, int stride) { - if (m_bReadonly) - throw new GeometryException("invalid_call"); - - if (stride < 1 || count % stride != 0) - throw new GeometryException("invalid_call"); - - int cIterations = count >> 1; - int n = count; - - for (int i = 0; i < cIterations; i += stride) { - n -= stride; - - for (int s = 0; s < stride; s++) { - int temp = m_buffer[index + i + s]; - m_buffer[index + i + s] = m_buffer[index + n + s]; - m_buffer[index + n + s] = temp; - } - } - } - - @Override - public void setRange(double value, int start, int count) { - if (start < 0 || count < 0 || start < 0 || count + start > size()) - throw new IllegalArgumentException(); - - int v = (int) value; - Arrays.fill(m_buffer, start, start + count, v); - // for (int i = start, n = start + count; i < n; i++) - // write(i, v); - } - - @Override - public void writeRange(int startElement, int count, - AttributeStreamBase _src, int srcStart, boolean bForward, int stride) { - if (startElement < 0 || count < 0 || srcStart < 0) - throw new IllegalArgumentException(); - - if (!bForward && (stride <= 0 || (count % stride != 0))) - throw new IllegalArgumentException(); - - AttributeStreamOfInt32 src = (AttributeStreamOfInt32) _src; // the input - // type must - // match - - if (src.size() < (int) (srcStart + count)) - throw new IllegalArgumentException(); - - if (count == 0) - return; - - if (size() < count + startElement) - resize(count + startElement); - - if (_src == (AttributeStreamBase) this) { - _selfWriteRangeImpl(startElement, count, srcStart, bForward, stride); - return; - } - - if (bForward) { - System.arraycopy(src.m_buffer, srcStart, m_buffer, startElement, - count); - // int j = startElement; - // int offset = srcStart; - // for (int i = 0; i < count; i++) - // { - // m_buffer[j] = src.m_buffer[offset]; - // j++; - // offset++; - // } - } else { - int j = startElement; - int offset = srcStart + count - stride; - if (stride == 1) { - for (int i = 0; i < count; i++) { - m_buffer[j] = src.m_buffer[offset]; - j++; - offset--; - } - } else { - for (int i = 0, n = count / stride; i < n; i++) { - for (int k = 0; k < stride; k++) - m_buffer[j + k] = src.m_buffer[offset + k]; - - j += stride; - offset -= stride; - } - } - } - } - - private void _selfWriteRangeImpl(int toElement, int count, int fromElement, - boolean bForward, int stride) { - - // writing from to this stream. - if (bForward) { - if (toElement == fromElement) - return; - } - - System.arraycopy(m_buffer, fromElement, m_buffer, toElement, count); - if (bForward) - return; - - // reverse what we written - int j = toElement; - int offset = toElement + count - stride; - int dj = stride; - for (int i = 0, n = count / 2; i < n; i++) { - for (int k = 0; k < stride; k++) { - int v = m_buffer[j + k]; - m_buffer[j + k] = m_buffer[offset + k]; - m_buffer[offset + k] = v; - } - j += stride; - offset -= stride; - } - } - - @Override - public void writeRange(int startElement, int count, ByteBuffer src, - int offsetBytes, boolean bForward) { - if (startElement < 0 || count < 0 || offsetBytes < 0) - throw new IllegalArgumentException(); - - final int elmSize = NumberUtils.sizeOf((double) 0); - if (src.capacity() < (int) (offsetBytes + elmSize * count)) - throw new IllegalArgumentException(); - - if (count == 0) - return; - - if (size() < count + startElement) - resize(count + startElement); - - int j = startElement; - if (!bForward) - j += count - 1; - - final int dj = bForward ? 1 : -1; - - int offset = offsetBytes; - for (int i = 0; i < count; i++, offset += elmSize) { - m_buffer[j] = src.getInt(offset); - j += dj; - } - - } - - static public abstract class IntComparator { - public abstract int compare(int v1, int v2); - } - - ; - - static class RandomSeed { - public int random; - - public RandomSeed() { - random = 1973; - } - } - - public void Sort(int start, int end, IntComparator compare) { - if (end - start < 10) - insertionsort(start, end, compare); - else { - quicksort(start, end - 1, compare, new RandomSeed()); - } - } - - void insertionsort(int start, int end, IntComparator compare) { - for (int j = start; j < end; j++)// insertion sort - { - int key = m_buffer[j]; - int i = j - 1; - while (i >= start && compare.compare(m_buffer[i], key) > 0) { - m_buffer[i + 1] = m_buffer[i]; - i--; - } - m_buffer[i + 1] = key; - } - } - - void swap(int left, int right) { - int tmp = m_buffer[right]; - m_buffer[right] = m_buffer[left]; - m_buffer[left] = tmp; - } - - void quicksort(int leftIn, int rightIn, IntComparator compare, - RandomSeed seed) { - if (leftIn >= rightIn) - return; - - int left = leftIn; - int right = rightIn; - - while (true)// tail recursion loop - { - if (right - left < 9) { - insertionsort(left, right + 1, compare); - return; - } - // Select random index for the pivot - seed.random = NumberUtils.nextRand(seed.random); - long nom = ((long) (right - left)) * seed.random; - int pivotIndex = (int) (nom / NumberUtils.intMax()) + left; - // Get the pivot value - int pivotValue = m_buffer[pivotIndex]; - - // Start partition - // Move pivot to the right - swap(pivotIndex, right); - int storeIndex = left; - for (int i = left; i < right; i++) { - int elm = m_buffer[i]; - if (compare.compare(elm, pivotValue) <= 0) { - swap(storeIndex, i); - storeIndex = storeIndex + 1; - } - } - - // Move pivot to its final place - swap(storeIndex, right); - // End partition - - // Shorter part is regular recursion - // Longer part is tail recursion - if (storeIndex - left < right - storeIndex) { - quicksort(left, storeIndex - 1, compare, seed); - left = storeIndex + 1; - } else { - quicksort(storeIndex + 1, right, compare, seed); - right = storeIndex - 1; - } - - } - } - - public void sort(int start, int end) { - Arrays.sort(m_buffer, start, end); - } + @Override + public double readAsDbl(int offset) { + return read(offset); + } + + @Override + public int readAsInt(int offset) { + return (int) read(offset); + } + + @Override + public long readAsInt64(int offset) { + return (long) read(offset); + } + + @Override + public void resize(int newSize) { + if (m_bLockedInSize) + throw new GeometryException( + "invalid call. Attribute Stream is locked and cannot be resized."); + + if (newSize <= m_size) { + if ((newSize * 5) / 4 < m_buffer.length) {// decrease when the 25% + // margin is exceeded + int[] newBuffer = new int[newSize]; + System.arraycopy(m_buffer, 0, newBuffer, 0, newSize); + m_buffer = newBuffer; + } + m_size = newSize; + } else { + if (newSize > m_buffer.length) { + int sz = (newSize < 64) ? Math.max(newSize * 2, 4) + : (newSize * 5) / 4; + int[] newBuffer = new int[sz]; + System.arraycopy(m_buffer, 0, newBuffer, 0, m_size); + m_buffer = newBuffer; + } + + m_size = newSize; + } + } + + @Override + public void resizePreserveCapacity(int newSize)// java only method + { + if (m_buffer == null || newSize > m_buffer.length) + resize(newSize); + if (m_bLockedInSize) + throw new GeometryException( + "invalid call. Attribute Stream is locked and cannot be resized."); + + m_size = newSize; + } + + @Override + public void resize(int newSize, double defaultValue) { + if (m_bLockedInSize) + throw new GeometryException( + "invalid call. Attribute Stream is locked and cannot be resized."); + if (newSize <= m_size) { + if ((newSize * 5) / 4 < m_buffer.length) {// decrease when the 25% + // margin is exceeded + int[] newBuffer = new int[newSize]; + System.arraycopy(m_buffer, 0, newBuffer, 0, newSize); + m_buffer = newBuffer; + } + m_size = newSize; + } else { + if (newSize > m_buffer.length) { + int sz = (newSize < 64) ? Math.max(newSize * 2, 4) + : (newSize * 5) / 4; + int[] newBuffer = new int[sz]; + System.arraycopy(m_buffer, 0, newBuffer, 0, m_size); + m_buffer = newBuffer; + } + + Arrays.fill(m_buffer, m_size, newSize, (int) defaultValue); + // for (int i = m_size; i < newSize; i++) + // m_buffer[i] = (int)defaultValue; + + m_size = newSize; + } + } + + @Override + public void writeAsDbl(int offset, double d) { + write(offset, (int) d); + } + + @Override + public void writeAsInt64(int offset, long d) { + write(offset, (int) d); + } + + @Override + public void writeAsInt(int offset, int d) { + write(offset, (int) d); + } + + // @Override + // public void writeRange(int srcStart, int count, ByteBuffer dst, + // int dstOffsetBytes) { + // // TODO Auto-generated method stub + // + // } + + @Override + public int calculateHashImpl(int hashCode, int start, int end) { + for (int i = start, n = size(); i < n && i < end; i++) + hashCode = NumberUtils.hash(hashCode, read(i)); + + return hashCode; + } + + @Override + public boolean equals(AttributeStreamBase other, int start, int end) { + if (other == null) + return false; + + if (!(other instanceof AttributeStreamOfInt32)) + return false; + + AttributeStreamOfInt32 _other = (AttributeStreamOfInt32) other; + + int size = size(); + int sizeOther = _other.size(); + + if (end > size || end > sizeOther && (size != sizeOther)) + return false; + + if (end > size) + end = size; + + for (int i = start; i < end; i++) + if (read(i) != _other.read(i)) + return false; + + return true; + } + + public int getLast() { + return m_buffer[m_size - 1]; + } + + public void setLast(int v) { + m_buffer[m_size - 1] = v; + } + + public void removeLast() { + resize(m_size - 1); + } + + // Finds element in the unsorted array and returns its index. Returns -1 if + // the element could not be found. + int findElement(int value) { + for (int i = 0, n = m_size; i < n; i++) { + if (m_buffer[i] == value) + return i; + } + return -1; + } + + // Returns True if element could be found in the array. + boolean hasElement(int value) { + return findElement(value) >= 0; + } + + // Removes the element from the array in constant time. + // It moves the last element of the array to the index and decrements the + // array size by 1. + void popElement(int index) { + assert (index >= 0 && index < m_size); + if (index < m_size - 1) { + m_buffer[index] = m_buffer[m_size - 1]; + } + + resize(m_size - 1); + } + + @Override + public void addRange(AttributeStreamBase src, int start, int count, + boolean bForward, int stride) { + if (m_bReadonly) + throw new GeometryException("invalid_call"); + + if (!bForward && (stride < 1 || count % stride != 0)) + throw new IllegalArgumentException(); + + int oldSize = m_size; + int newSize = oldSize + count; + resize(newSize); + + if (bForward) { + System.arraycopy(((AttributeStreamOfInt32) src).m_buffer, start, + m_buffer, oldSize, count); + } else { + int n = count; + + for (int i = 0; i < count; i += stride) { + n -= stride; + + for (int s = 0; s < stride; s++) { + m_buffer[oldSize + i + s] = ((AttributeStreamOfInt32) src).m_buffer[start + + n + s]; + } + } + } + } + + @Override + public void insertRange(int start, AttributeStreamBase src, int srcStart, + int count, boolean bForward, int stride, int validSize) { + if (m_bReadonly) + throw new GeometryException("invalid_call"); + + if (!bForward && (stride < 1 || count % stride != 0)) + throw new IllegalArgumentException(); + + System.arraycopy(m_buffer, start, m_buffer, start + count, validSize + - start); + + if (m_buffer == ((AttributeStreamOfInt32) src).m_buffer) { + if (start < srcStart) + srcStart += count; + } + + if (bForward) { + System.arraycopy(((AttributeStreamOfInt32) src).m_buffer, srcStart, + m_buffer, start, count); + } else { + int n = count; + + for (int i = 0; i < count; i += stride) { + n -= stride; + + for (int s = 0; s < stride; s++) { + m_buffer[start + i + s] = ((AttributeStreamOfInt32) src).m_buffer[srcStart + + n + s]; + } + } + } + } + + @Override + public void insertRange(int start, double value, int count, int validSize) { + if (m_bReadonly) + throw new GeometryException("invalid_call"); + + System.arraycopy(m_buffer, start, m_buffer, start + count, validSize + - start); + + int v = (int) value; + Arrays.fill(m_buffer, start, start + count, v); + // for (int i = 0; i < count; i++) + // { + // m_buffer[start + i] = v; + // } + } + + @Override + public void insertAttributes(int start, Point pt, int semantics, + int validSize) { + if (m_bReadonly) + throw new GeometryException("invalid_call"); + + int comp = VertexDescription.getComponentCount(semantics); + + System.arraycopy(m_buffer, start, m_buffer, start + comp, validSize + - start); + + for (int c = 0; c < comp; c++) { + m_buffer[start + c] = (int) pt.getAttributeAsDbl(semantics, c); + } + } + + @Override + public void eraseRange(int index, int count, int validSize) { + if (m_bReadonly) + throw new GeometryException("invalid_call"); + + if (index + count > m_size) + throw new GeometryException("invalid_call"); + + System.arraycopy(m_buffer, index + count, m_buffer, index, validSize + - (index + count)); + m_size -= count; + } + + @Override + public void readRange(int srcStart, int count, ByteBuffer dst, + int dstOffset, boolean bForward) { + if (srcStart < 0 || count < 0 || dstOffset < 0 + || size() < count + srcStart) + throw new IllegalArgumentException(); + + final int elmSize = NumberUtils.sizeOf((double) 0); + + if (dst.capacity() < (int) (dstOffset + elmSize * count)) + throw new IllegalArgumentException(); + + if (count == 0) + return; + + int j = srcStart; + if (!bForward) + j += count - 1; + final int dj = bForward ? 1 : -1; + int offset = dstOffset; + for (int i = 0; i < count; i++, offset += elmSize) { + dst.putInt(offset, m_buffer[j]); + j += dj; + } + } + + @Override + public void reverseRange(int index, int count, int stride) { + if (m_bReadonly) + throw new GeometryException("invalid_call"); + + if (stride < 1 || count % stride != 0) + throw new GeometryException("invalid_call"); + + int cIterations = count >> 1; + int n = count; + + for (int i = 0; i < cIterations; i += stride) { + n -= stride; + + for (int s = 0; s < stride; s++) { + int temp = m_buffer[index + i + s]; + m_buffer[index + i + s] = m_buffer[index + n + s]; + m_buffer[index + n + s] = temp; + } + } + } + + @Override + public void setRange(double value, int start, int count) { + if (start < 0 || count < 0 || start < 0 || count + start > size()) + throw new IllegalArgumentException(); + + int v = (int) value; + Arrays.fill(m_buffer, start, start + count, v); + // for (int i = start, n = start + count; i < n; i++) + // write(i, v); + } + + @Override + public void writeRange(int startElement, int count, + AttributeStreamBase _src, int srcStart, boolean bForward, int stride) { + if (startElement < 0 || count < 0 || srcStart < 0) + throw new IllegalArgumentException(); + + if (!bForward && (stride <= 0 || (count % stride != 0))) + throw new IllegalArgumentException(); + + AttributeStreamOfInt32 src = (AttributeStreamOfInt32) _src; // the input + // type must + // match + + if (src.size() < (int) (srcStart + count)) + throw new IllegalArgumentException(); + + if (count == 0) + return; + + if (size() < count + startElement) + resize(count + startElement); + + if (_src == (AttributeStreamBase) this) { + _selfWriteRangeImpl(startElement, count, srcStart, bForward, stride); + return; + } + + if (bForward) { + System.arraycopy(src.m_buffer, srcStart, m_buffer, startElement, + count); + // int j = startElement; + // int offset = srcStart; + // for (int i = 0; i < count; i++) + // { + // m_buffer[j] = src.m_buffer[offset]; + // j++; + // offset++; + // } + } else { + int j = startElement; + int offset = srcStart + count - stride; + if (stride == 1) { + for (int i = 0; i < count; i++) { + m_buffer[j] = src.m_buffer[offset]; + j++; + offset--; + } + } else { + for (int i = 0, n = count / stride; i < n; i++) { + for (int k = 0; k < stride; k++) + m_buffer[j + k] = src.m_buffer[offset + k]; + + j += stride; + offset -= stride; + } + } + } + } + + private void _selfWriteRangeImpl(int toElement, int count, int fromElement, + boolean bForward, int stride) { + + // writing from to this stream. + if (bForward) { + if (toElement == fromElement) + return; + } + + System.arraycopy(m_buffer, fromElement, m_buffer, toElement, count); + if (bForward) + return; + + // reverse what we written + int j = toElement; + int offset = toElement + count - stride; + for (int i = 0, n = count / 2; i < n; i++) { + for (int k = 0; k < stride; k++) { + int v = m_buffer[j + k]; + m_buffer[j + k] = m_buffer[offset + k]; + m_buffer[offset + k] = v; + } + j += stride; + offset -= stride; + } + } + + @Override + public void writeRange(int startElement, int count, ByteBuffer src, + int offsetBytes, boolean bForward) { + if (startElement < 0 || count < 0 || offsetBytes < 0) + throw new IllegalArgumentException(); + + final int elmSize = NumberUtils.sizeOf((double) 0); + if (src.capacity() < (int) (offsetBytes + elmSize * count)) + throw new IllegalArgumentException(); + + if (count == 0) + return; + + if (size() < count + startElement) + resize(count + startElement); + + int j = startElement; + if (!bForward) + j += count - 1; + + final int dj = bForward ? 1 : -1; + + int offset = offsetBytes; + for (int i = 0; i < count; i++, offset += elmSize) { + m_buffer[j] = src.getInt(offset); + j += dj; + } + + } + + static public abstract class IntComparator { + public abstract int compare(int v1, int v2); + }; + + static class RandomSeed { + public int random; + + public RandomSeed() { + random = 1973; + } + } + + public void Sort(int start, int end, IntComparator compare) { + if (end - start < 10) + insertionsort(start, end, compare); + else { + quicksort(start, end - 1, compare, new RandomSeed()); + } + } + + void insertionsort(int start, int end, IntComparator compare) { + for (int j = start; j < end; j++)// insertion sort + { + int key = m_buffer[j]; + int i = j - 1; + while (i >= start && compare.compare(m_buffer[i], key) > 0) { + m_buffer[i + 1] = m_buffer[i]; + i--; + } + m_buffer[i + 1] = key; + } + } + + void swap(int left, int right) { + int tmp = m_buffer[right]; + m_buffer[right] = m_buffer[left]; + m_buffer[left] = tmp; + } + + void quicksort(int leftIn, int rightIn, IntComparator compare, + RandomSeed seed) { + if (leftIn >= rightIn) + return; + + int left = leftIn; + int right = rightIn; + + while (true)// tail recursion loop + { + if (right - left < 9) { + insertionsort(left, right + 1, compare); + return; + } + // Select random index for the pivot + seed.random = NumberUtils.nextRand(seed.random); + long nom = ((long) (right - left)) * seed.random; + int pivotIndex = (int) (nom / NumberUtils.intMax()) + left; + // Get the pivot value + int pivotValue = m_buffer[pivotIndex]; + + // Start partition + // Move pivot to the right + swap(pivotIndex, right); + int storeIndex = left; + for (int i = left; i < right; i++) { + int elm = m_buffer[i]; + if (compare.compare(elm, pivotValue) <= 0) { + swap(storeIndex, i); + storeIndex = storeIndex + 1; + } + } + + // Move pivot to its final place + swap(storeIndex, right); + // End partition + + // Shorter part is regular recursion + // Longer part is tail recursion + if (storeIndex - left < right - storeIndex) { + quicksort(left, storeIndex - 1, compare, seed); + left = storeIndex + 1; + } else { + quicksort(storeIndex + 1, right, compare, seed); + right = storeIndex - 1; + } + + } + } + + public void sort(int start, int end) { + Arrays.sort(m_buffer, start, end); + } + + private void writeObject(java.io.ObjectOutputStream stream) + throws IOException { + stream.defaultWriteObject(); + IntBuffer intBuf = null; + byte[] bytes = null; + for (int i = 0; i < m_size;) { + int n = Math.min(32, m_size - i); + if (bytes == null) { + bytes = new byte[n * 4]; //32 elements at a time + ByteBuffer buf = ByteBuffer.wrap(bytes); + intBuf = buf.asIntBuffer(); + } + intBuf.rewind(); + intBuf.put(m_buffer, i, n); + stream.write(bytes, 0, n * 4); + i += n; + } + } + + private void readObject(java.io.ObjectInputStream stream) + throws IOException, ClassNotFoundException { + stream.defaultReadObject(); + m_buffer = new int[m_size]; + IntBuffer intBuf = null; + byte[] bytes = null; + for (int i = 0; i < m_size;) { + int n = Math.min(32, m_size - i); + if (bytes == null) { + bytes = new byte[n * 4]; //32 elements at a time + ByteBuffer buf = ByteBuffer.wrap(bytes); + intBuf = buf.asIntBuffer(); + } + stream.read(bytes, 0, n * 4); + intBuf.rewind(); + intBuf.get(m_buffer, i, n); + i += n; + } + } + + @SuppressWarnings("unused") + private void readObjectNoData() throws ObjectStreamException { + m_buffer = new int[2]; + m_size = 0; + } } diff --git a/src/main/java/com/esri/core/geometry/AttributeStreamOfInt64.java b/src/main/java/com/esri/core/geometry/AttributeStreamOfInt64.java index 1644b672..df216992 100644 --- a/src/main/java/com/esri/core/geometry/AttributeStreamOfInt64.java +++ b/src/main/java/com/esri/core/geometry/AttributeStreamOfInt64.java @@ -36,116 +36,115 @@ final class AttributeStreamOfInt64 extends AttributeStreamBase { private long[] m_buffer = null; private int m_size; - public int size() { - return m_size; - } - - public void reserve(int reserve)// only in Java - { - if (reserve <= 0) - return; - if (m_buffer == null) - m_buffer = new long[reserve]; - else { - if (reserve <= m_buffer.length) - return; - long[] buf = new long[reserve]; - System.arraycopy(m_buffer, 0, buf, 0, m_size); - m_buffer = buf; - } - - } - - public int capacity() { - return m_buffer != null ? m_buffer.length : 0; - } - - public AttributeStreamOfInt64(int size) { - int sz = size; - if (sz < 2) - sz = 2; - m_buffer = new long[sz]; - m_size = size; - } - - public AttributeStreamOfInt64(int size, long defaultValue) { - int sz = size; - if (sz < 2) - sz = 2; - m_buffer = new long[sz]; - m_size = size; - for (int i = 0; i < size; i++) - m_buffer[i] = defaultValue; - } - - public AttributeStreamOfInt64(AttributeStreamOfInt64 other) { - m_buffer = other.m_buffer.clone(); - m_size = other.m_size; - } - - public AttributeStreamOfInt64(AttributeStreamOfInt64 other, int maxSize) { - m_size = other.size(); - if (m_size > maxSize) - m_size = maxSize; - int sz = m_size; - if (sz < 2) - sz = 2; - m_buffer = new long[sz]; - System.arraycopy(other.m_buffer, 0, m_buffer, 0, m_size); - } - - /** - * Reads a value from the buffer at given offset. - * - * @param offset is the element number in the stream. - */ - public long read(int offset) { - return m_buffer[offset]; - } - - /** - * Overwrites given element with new value. - * - * @param offset is the element number in the stream. - * @param value is the value to write. - */ - public void write(int offset, long value) { - if (m_bReadonly) { - throw new RuntimeException("invalid_call"); - } - m_buffer[offset] = value; - } - - /** - * Adds a new value at the end of the stream. - * - * @param offset is the element number in the stream. - * @param value is the value to write. - */ - public void add(long v) { - resize(m_size + 1); - m_buffer[m_size - 1] = v; - } - - @Override - public AttributeStreamBase restrictedClone(int maxsize) { - int len = m_size; - int newSize = maxsize < len ? maxsize : len; - long[] newBuffer = new long[newSize]; - System.arraycopy(m_buffer, 0, newBuffer, 0, newSize); - m_buffer = newBuffer; - m_size = newSize; - return this; - } - - @Override - public int virtualSize() { - return size(); - } + public int size() { + return m_size; + } - @Override - public long estimateMemorySize() + public void reserve(int reserve)// only in Java { + if (reserve <= 0) + return; + if (m_buffer == null) + m_buffer = new long[reserve]; + else { + if (reserve <= m_buffer.length) + return; + long[] buf = new long[reserve]; + System.arraycopy(m_buffer, 0, buf, 0, m_size); + m_buffer = buf; + } + + } + + public int capacity() { + return m_buffer != null ? m_buffer.length : 0; + } + + public AttributeStreamOfInt64(int size) { + int sz = size; + if (sz < 2) + sz = 2; + m_buffer = new long[sz]; + m_size = size; + } + + public AttributeStreamOfInt64(int size, long defaultValue) { + int sz = size; + if (sz < 2) + sz = 2; + m_buffer = new long[sz]; + m_size = size; + for (int i = 0; i < size; i++) + m_buffer[i] = defaultValue; + } + + public AttributeStreamOfInt64(AttributeStreamOfInt64 other) { + m_buffer = other.m_buffer.clone(); + m_size = other.m_size; + } + + public AttributeStreamOfInt64(AttributeStreamOfInt64 other, int maxSize) { + m_size = other.size(); + if (m_size > maxSize) + m_size = maxSize; + int sz = m_size; + if (sz < 2) + sz = 2; + m_buffer = new long[sz]; + System.arraycopy(other.m_buffer, 0, m_buffer, 0, m_size); + } + + /** + * Reads a value from the buffer at given offset. + * + * @param offset is the element number in the stream. + */ + public long read(int offset) { + return m_buffer[offset]; + } + + /** + * Overwrites given element with new value. + * + * @param offset is the element number in the stream. + * @param value is the value to write. + */ + public void write(int offset, long value) { + if (m_bReadonly) { + throw new RuntimeException("invalid_call"); + } + m_buffer[offset] = value; + } + + /** + * Adds a new value at the end of the stream. + * + * @param offset is the element number in the stream. + * @param value is the value to write. + */ + public void add(long v) { + resize(m_size + 1); + m_buffer[m_size - 1] = v; + } + + @Override + public AttributeStreamBase restrictedClone(int maxsize) { + int len = m_size; + int newSize = maxsize < len ? maxsize : len; + long[] newBuffer = new long[newSize]; + System.arraycopy(m_buffer, 0, newBuffer, 0, newSize); + m_buffer = newBuffer; + m_size = newSize; + return this; + } + + @Override + public int virtualSize() { + return size(); + } + + @Override + public long estimateMemorySize() { return SIZE_OF_ATTRIBUTE_STREAM_OF_INT64 + sizeOfLongArray(m_buffer.length); } @@ -154,447 +153,447 @@ public int getPersistence() { return Persistence.enumInt64; } - @Override - public double readAsDbl(int offset) { - return read(offset); - } - - @Override - public int readAsInt(int offset) { - return (int) read(offset); - } - - @Override - public long readAsInt64(int offset) { - return (long) read(offset); - } - - @Override - public void resize(int newSize) { - if (m_bLockedInSize) - throw new GeometryException( - "invalid call. Attribute Stream is locked and cannot be resized."); - - if (newSize <= m_size) { - if ((newSize * 5) / 4 < m_buffer.length) {// decrease when the 25% - // margin is exceeded - long[] newBuffer = new long[newSize]; - System.arraycopy(m_buffer, 0, newBuffer, 0, newSize); - m_buffer = newBuffer; - } - m_size = newSize; - } else { - if (newSize > m_buffer.length) { - int sz = (newSize < 64) ? Math.max(newSize * 2, 4) - : (newSize * 5) / 4; - long[] newBuffer = new long[sz]; - System.arraycopy(m_buffer, 0, newBuffer, 0, m_size); - m_buffer = newBuffer; - } - - m_size = newSize; - } - } - - @Override - public void resizePreserveCapacity(int newSize)// java only method - { - if (m_buffer == null || newSize > m_buffer.length) - resize(newSize); - if (m_bLockedInSize) - throw new GeometryException( - "invalid call. Attribute Stream is locked and cannot be resized."); - - m_size = newSize; - } - - @Override - public void resize(int newSize, double defaultValue) { - if (m_bLockedInSize) - throw new GeometryException( - "invalid call. Attribute Stream is locked and cannot be resized."); - if (newSize <= m_size) { - if ((newSize * 5) / 4 < m_buffer.length) {// decrease when the 25% - // margin is exceeded - long[] newBuffer = new long[newSize]; - System.arraycopy(m_buffer, 0, newBuffer, 0, newSize); - m_buffer = newBuffer; - } - m_size = newSize; - } else { - if (newSize > m_buffer.length) { - int sz = (newSize < 64) ? Math.max(newSize * 2, 4) - : (newSize * 5) / 4; - long[] newBuffer = new long[sz]; - System.arraycopy(m_buffer, 0, newBuffer, 0, m_size); - m_buffer = newBuffer; - } - - for (int i = m_size; i < newSize; i++) - m_buffer[i] = (long) defaultValue; - - m_size = newSize; - } - } - - @Override - public void writeAsDbl(int offset, double d) { - write(offset, (long) d); - } - - @Override - public void writeAsInt64(int offset, long d) { - write(offset, (long) d); - } - - @Override - public void writeAsInt(int offset, int d) { - write(offset, (long) d); - } - - // @Override - // public void writeRange(int srcStart, int count, ByteBuffer dst, - // int dstOffsetBytes) { - // // TODO Auto-generated method stub - // - // } - - @Override - public int calculateHashImpl(int hashCode, int start, int end) { - for (int i = start, n = size(); i < n && i < end; i++) - hashCode = NumberUtils.hash(hashCode, read(i)); - - return hashCode; - } - - @Override - public boolean equals(AttributeStreamBase other, int start, int end) { - if (other == null) - return false; - - if (!(other instanceof AttributeStreamOfInt64)) - return false; - - AttributeStreamOfInt64 _other = (AttributeStreamOfInt64) other; - - int size = size(); - int sizeOther = _other.size(); - - if (end > size || end > sizeOther && (size != sizeOther)) - return false; - - if (end > size) - end = size; - - for (int i = start; i < end; i++) - if (read(i) != _other.read(i)) - return false; - - return true; - } - - @Override - public void addRange(AttributeStreamBase src, int start, int count, - boolean bForward, int stride) { - if (m_bReadonly) - throw new GeometryException("invalid_call"); - - if (!bForward && (stride < 1 || count % stride != 0)) - throw new IllegalArgumentException(); - - int oldSize = m_size; - int newSize = oldSize + count; - resize(newSize); - - if (bForward) { - System.arraycopy(((AttributeStreamOfInt64) src).m_buffer, start, - m_buffer, oldSize, count); - } else { - int n = count; - - for (int i = 0; i < count; i += stride) { - n -= stride; - - for (int s = 0; s < stride; s++) { - m_buffer[oldSize + i + s] = ((AttributeStreamOfInt64) src).m_buffer[start - + n + s]; - } - } - } - } - - @Override - public void insertRange(int start, AttributeStreamBase src, int srcStart, - int count, boolean bForward, int stride, int validSize) { - if (m_bReadonly) - throw new GeometryException("invalid_call"); - - if (!bForward && (stride < 1 || count % stride != 0)) - throw new IllegalArgumentException(); - - System.arraycopy(m_buffer, start, m_buffer, start + count, validSize - - start); - - if (m_buffer == ((AttributeStreamOfInt64) src).m_buffer) { - if (start < srcStart) - srcStart += count; - } - - if (bForward) { - System.arraycopy(((AttributeStreamOfInt64) src).m_buffer, srcStart, - m_buffer, start, count); - } else { - int n = count; - - for (int i = 0; i < count; i += stride) { - n -= stride; - - for (int s = 0; s < stride; s++) { - m_buffer[start + i + s] = ((AttributeStreamOfInt64) src).m_buffer[srcStart - + n + s]; - } - } - } - } - - @Override - public void insertRange(int start, double value, int count, int validSize) { - if (m_bReadonly) - throw new GeometryException("invalid_call"); - - System.arraycopy(m_buffer, start, m_buffer, start + count, validSize - - start); - - long v = (long) value; - for (int i = 0; i < count; i++) { - m_buffer[start + i] = v; - } - } - - @Override - public void insertAttributes(int start, Point pt, int semantics, - int validSize) { - if (m_bReadonly) - throw new GeometryException("invalid_call"); - - int comp = VertexDescription.getComponentCount(semantics); - - System.arraycopy(m_buffer, start, m_buffer, start + comp, validSize - - start); - - for (int c = 0; c < comp; c++) { - m_buffer[start + c] = (long) pt.getAttributeAsDbl(semantics, c); - } - } - - @Override - public void eraseRange(int index, int count, int validSize) { - if (m_bReadonly) - throw new GeometryException("invalid_call"); - - if (index + count > m_size) - throw new GeometryException("invalid_call"); - - System.arraycopy(m_buffer, index + count, m_buffer, index, validSize - - (index + count)); - m_size -= count; - } - - @Override - public void readRange(int srcStart, int count, ByteBuffer dst, - int dstOffset, boolean bForward) { - if (srcStart < 0 || count < 0 || dstOffset < 0 - || size() < count + srcStart) - throw new IllegalArgumentException(); - - final int elmSize = NumberUtils.sizeOf((double) 0); - - if (dst.capacity() < (int) (dstOffset + elmSize * count)) - throw new IllegalArgumentException(); - - if (count == 0) - return; - - int j = srcStart; - if (!bForward) - j += count - 1; - - final int dj = bForward ? 1 : -1; - - int offset = dstOffset; - for (int i = 0; i < count; i++, offset += elmSize) { - dst.putLong(offset, m_buffer[j]); - j += dj; - } - - } - - @Override - public void reverseRange(int index, int count, int stride) { - if (m_bReadonly) - throw new GeometryException("invalid_call"); - - if (stride < 1 || count % stride != 0) - throw new GeometryException("invalid_call"); - - int cIterations = count >> 1; - int n = count; - - for (int i = 0; i < cIterations; i += stride) { - n -= stride; - - for (int s = 0; s < stride; s++) { - long temp = m_buffer[index + i + s]; - m_buffer[index + i + s] = m_buffer[index + n + s]; - m_buffer[index + n + s] = temp; - } - } - } - - @Override - public void setRange(double value, int start, int count) { - if (start < 0 || count < 0 || start < 0 || count + start > size()) - throw new IllegalArgumentException(); - - long v = (long) value; - for (int i = start, n = start + count; i < n; i++) - write(i, v); - } - - @Override - public void writeRange(int startElement, int count, - AttributeStreamBase _src, int srcStart, boolean bForward, int stride) { - if (startElement < 0 || count < 0 || srcStart < 0) - throw new IllegalArgumentException(); - - if (!bForward && (stride <= 0 || (count % stride != 0))) - throw new IllegalArgumentException(); - - AttributeStreamOfInt64 src = (AttributeStreamOfInt64) _src; // the input - // type must - // match - - if (src.size() < (int) (srcStart + count)) - throw new IllegalArgumentException(); - - if (count == 0) - return; - - if (size() < count + startElement) - resize(count + startElement); - - if (_src == (AttributeStreamBase) this) { - _selfWriteRangeImpl(startElement, count, srcStart, bForward, stride); - return; - } - - if (bForward) { - int j = startElement; - int offset = srcStart; - for (int i = 0; i < count; i++) { - m_buffer[j] = src.m_buffer[offset]; - j++; - offset++; - } - } else { - int j = startElement; - int offset = srcStart + count - stride; - if (stride == 1) { - for (int i = 0; i < count; i++) { - m_buffer[j] = src.m_buffer[offset]; - j++; - offset--; - } - } else { - for (int i = 0, n = count / stride; i < n; i++) { - for (int k = 0; k < stride; k++) - m_buffer[j + k] = src.m_buffer[offset + k]; - - j += stride; - offset -= stride; - } - } - } - } - - private void _selfWriteRangeImpl(int toElement, int count, int fromElement, - boolean bForward, int stride) { - - // writing from to this stream. - if (bForward) { - if (toElement == fromElement) - return; - } - - int offset; - int j; - int dj; - - if (fromElement < toElement) { - offset = fromElement + count - stride; - j = toElement + count - stride; - for (int i = 0, n = count / 2; i < n; i++) { - for (int k = 0; k < stride; k++) { - m_buffer[j + k] = m_buffer[offset + k]; - } - j -= stride; - offset -= stride; - } - } else { - offset = fromElement; - j = toElement; - dj = 1; - for (int i = 0; i < count; i++) { - m_buffer[j] = m_buffer[offset]; - j += 1; - offset++; - } - } - - if (!bForward) { - // reverse what we written - j = toElement; - offset = toElement + count - stride; - dj = stride; - for (int i = 0, n = count / 2; i < n; i++) { - for (int k = 0; k < stride; k++) { - long v = m_buffer[j + k]; - m_buffer[j + k] = m_buffer[offset + k]; - m_buffer[offset + k] = v; - } - j += stride; - offset -= stride; - } - } - } - - @Override - public void writeRange(int startElement, int count, ByteBuffer src, - int offsetBytes, boolean bForward) { - if (startElement < 0 || count < 0 || offsetBytes < 0) - throw new IllegalArgumentException(); - - final int elmSize = NumberUtils.sizeOf((double) 0); - if (src.capacity() < (int) (offsetBytes + elmSize * count)) - throw new IllegalArgumentException(); - - if (count == 0) - return; - - if (size() < count + startElement) - resize(count + startElement); - - int j = startElement; - if (!bForward) - j += count - 1; - - final int dj = bForward ? 1 : -1; - - int offset = offsetBytes; - for (int i = 0; i < count; i++, offset += elmSize) { - m_buffer[j] = src.getLong(offset); - j += dj; - } - - } + @Override + public double readAsDbl(int offset) { + return read(offset); + } + + @Override + public int readAsInt(int offset) { + return (int) read(offset); + } + + @Override + public long readAsInt64(int offset) { + return (long) read(offset); + } + + @Override + public void resize(int newSize) { + if (m_bLockedInSize) + throw new GeometryException( + "invalid call. Attribute Stream is locked and cannot be resized."); + + if (newSize <= m_size) { + if ((newSize * 5) / 4 < m_buffer.length) {// decrease when the 25% + // margin is exceeded + long[] newBuffer = new long[newSize]; + System.arraycopy(m_buffer, 0, newBuffer, 0, newSize); + m_buffer = newBuffer; + } + m_size = newSize; + } else { + if (newSize > m_buffer.length) { + int sz = (newSize < 64) ? Math.max(newSize * 2, 4) + : (newSize * 5) / 4; + long[] newBuffer = new long[sz]; + System.arraycopy(m_buffer, 0, newBuffer, 0, m_size); + m_buffer = newBuffer; + } + + m_size = newSize; + } + } + + @Override + public void resizePreserveCapacity(int newSize)// java only method + { + if (m_buffer == null || newSize > m_buffer.length) + resize(newSize); + if (m_bLockedInSize) + throw new GeometryException( + "invalid call. Attribute Stream is locked and cannot be resized."); + + m_size = newSize; + } + + @Override + public void resize(int newSize, double defaultValue) { + if (m_bLockedInSize) + throw new GeometryException( + "invalid call. Attribute Stream is locked and cannot be resized."); + if (newSize <= m_size) { + if ((newSize * 5) / 4 < m_buffer.length) {// decrease when the 25% + // margin is exceeded + long[] newBuffer = new long[newSize]; + System.arraycopy(m_buffer, 0, newBuffer, 0, newSize); + m_buffer = newBuffer; + } + m_size = newSize; + } else { + if (newSize > m_buffer.length) { + int sz = (newSize < 64) ? Math.max(newSize * 2, 4) + : (newSize * 5) / 4; + long[] newBuffer = new long[sz]; + System.arraycopy(m_buffer, 0, newBuffer, 0, m_size); + m_buffer = newBuffer; + } + + for (int i = m_size; i < newSize; i++) + m_buffer[i] = (long) defaultValue; + + m_size = newSize; + } + } + + @Override + public void writeAsDbl(int offset, double d) { + write(offset, (long) d); + } + + @Override + public void writeAsInt64(int offset, long d) { + write(offset, (long) d); + } + + @Override + public void writeAsInt(int offset, int d) { + write(offset, (long) d); + } + + // @Override + // public void writeRange(int srcStart, int count, ByteBuffer dst, + // int dstOffsetBytes) { + // // TODO Auto-generated method stub + // + // } + + @Override + public int calculateHashImpl(int hashCode, int start, int end) { + for (int i = start, n = size(); i < n && i < end; i++) + hashCode = NumberUtils.hash(hashCode, read(i)); + + return hashCode; + } + + @Override + public boolean equals(AttributeStreamBase other, int start, int end) { + if (other == null) + return false; + + if (!(other instanceof AttributeStreamOfInt64)) + return false; + + AttributeStreamOfInt64 _other = (AttributeStreamOfInt64) other; + + int size = size(); + int sizeOther = _other.size(); + + if (end > size || end > sizeOther && (size != sizeOther)) + return false; + + if (end > size) + end = size; + + for (int i = start; i < end; i++) + if (read(i) != _other.read(i)) + return false; + + return true; + } + + @Override + public void addRange(AttributeStreamBase src, int start, int count, + boolean bForward, int stride) { + if (m_bReadonly) + throw new GeometryException("invalid_call"); + + if (!bForward && (stride < 1 || count % stride != 0)) + throw new IllegalArgumentException(); + + int oldSize = m_size; + int newSize = oldSize + count; + resize(newSize); + + if (bForward) { + System.arraycopy(((AttributeStreamOfInt64) src).m_buffer, start, + m_buffer, oldSize, count); + } else { + int n = count; + + for (int i = 0; i < count; i += stride) { + n -= stride; + + for (int s = 0; s < stride; s++) { + m_buffer[oldSize + i + s] = ((AttributeStreamOfInt64) src).m_buffer[start + + n + s]; + } + } + } + } + + @Override + public void insertRange(int start, AttributeStreamBase src, int srcStart, + int count, boolean bForward, int stride, int validSize) { + if (m_bReadonly) + throw new GeometryException("invalid_call"); + + if (!bForward && (stride < 1 || count % stride != 0)) + throw new IllegalArgumentException(); + + System.arraycopy(m_buffer, start, m_buffer, start + count, validSize + - start); + + if (m_buffer == ((AttributeStreamOfInt64) src).m_buffer) { + if (start < srcStart) + srcStart += count; + } + + if (bForward) { + System.arraycopy(((AttributeStreamOfInt64) src).m_buffer, srcStart, + m_buffer, start, count); + } else { + int n = count; + + for (int i = 0; i < count; i += stride) { + n -= stride; + + for (int s = 0; s < stride; s++) { + m_buffer[start + i + s] = ((AttributeStreamOfInt64) src).m_buffer[srcStart + + n + s]; + } + } + } + } + + @Override + public void insertRange(int start, double value, int count, int validSize) { + if (m_bReadonly) + throw new GeometryException("invalid_call"); + + System.arraycopy(m_buffer, start, m_buffer, start + count, validSize + - start); + + long v = (long) value; + for (int i = 0; i < count; i++) { + m_buffer[start + i] = v; + } + } + + @Override + public void insertAttributes(int start, Point pt, int semantics, + int validSize) { + if (m_bReadonly) + throw new GeometryException("invalid_call"); + + int comp = VertexDescription.getComponentCount(semantics); + + System.arraycopy(m_buffer, start, m_buffer, start + comp, validSize + - start); + + for (int c = 0; c < comp; c++) { + m_buffer[start + c] = (long) pt.getAttributeAsDbl(semantics, c); + } + } + + @Override + public void eraseRange(int index, int count, int validSize) { + if (m_bReadonly) + throw new GeometryException("invalid_call"); + + if (index + count > m_size) + throw new GeometryException("invalid_call"); + + System.arraycopy(m_buffer, index + count, m_buffer, index, validSize + - (index + count)); + m_size -= count; + } + + @Override + public void readRange(int srcStart, int count, ByteBuffer dst, + int dstOffset, boolean bForward) { + if (srcStart < 0 || count < 0 || dstOffset < 0 + || size() < count + srcStart) + throw new IllegalArgumentException(); + + final int elmSize = NumberUtils.sizeOf((double) 0); + + if (dst.capacity() < (int) (dstOffset + elmSize * count)) + throw new IllegalArgumentException(); + + if (count == 0) + return; + + int j = srcStart; + if (!bForward) + j += count - 1; + + final int dj = bForward ? 1 : -1; + + int offset = dstOffset; + for (int i = 0; i < count; i++, offset += elmSize) { + dst.putLong(offset, m_buffer[j]); + j += dj; + } + + } + + @Override + public void reverseRange(int index, int count, int stride) { + if (m_bReadonly) + throw new GeometryException("invalid_call"); + + if (stride < 1 || count % stride != 0) + throw new GeometryException("invalid_call"); + + int cIterations = count >> 1; + int n = count; + + for (int i = 0; i < cIterations; i += stride) { + n -= stride; + + for (int s = 0; s < stride; s++) { + long temp = m_buffer[index + i + s]; + m_buffer[index + i + s] = m_buffer[index + n + s]; + m_buffer[index + n + s] = temp; + } + } + } + + @Override + public void setRange(double value, int start, int count) { + if (start < 0 || count < 0 || start < 0 || count + start > size()) + throw new IllegalArgumentException(); + + long v = (long) value; + for (int i = start, n = start + count; i < n; i++) + write(i, v); + } + + @Override + public void writeRange(int startElement, int count, + AttributeStreamBase _src, int srcStart, boolean bForward, int stride) { + if (startElement < 0 || count < 0 || srcStart < 0) + throw new IllegalArgumentException(); + + if (!bForward && (stride <= 0 || (count % stride != 0))) + throw new IllegalArgumentException(); + + AttributeStreamOfInt64 src = (AttributeStreamOfInt64) _src; // the input + // type must + // match + + if (src.size() < (int) (srcStart + count)) + throw new IllegalArgumentException(); + + if (count == 0) + return; + + if (size() < count + startElement) + resize(count + startElement); + + if (_src == (AttributeStreamBase) this) { + _selfWriteRangeImpl(startElement, count, srcStart, bForward, stride); + return; + } + + if (bForward) { + int j = startElement; + int offset = srcStart; + for (int i = 0; i < count; i++) { + m_buffer[j] = src.m_buffer[offset]; + j++; + offset++; + } + } else { + int j = startElement; + int offset = srcStart + count - stride; + if (stride == 1) { + for (int i = 0; i < count; i++) { + m_buffer[j] = src.m_buffer[offset]; + j++; + offset--; + } + } else { + for (int i = 0, n = count / stride; i < n; i++) { + for (int k = 0; k < stride; k++) + m_buffer[j + k] = src.m_buffer[offset + k]; + + j += stride; + offset -= stride; + } + } + } + } + + private void _selfWriteRangeImpl(int toElement, int count, int fromElement, + boolean bForward, int stride) { + + // writing from to this stream. + if (bForward) { + if (toElement == fromElement) + return; + } + + int offset; + int j; + int dj; + + if (fromElement < toElement) { + offset = fromElement + count - stride; + j = toElement + count - stride; + for (int i = 0, n = count / 2; i < n; i++) { + for (int k = 0; k < stride; k++) { + m_buffer[j + k] = m_buffer[offset + k]; + } + j -= stride; + offset -= stride; + } + } else { + offset = fromElement; + j = toElement; + dj = 1; + for (int i = 0; i < count; i++) { + m_buffer[j] = m_buffer[offset]; + j += 1; + offset++; + } + } + + if (!bForward) { + // reverse what we written + j = toElement; + offset = toElement + count - stride; + dj = stride; + for (int i = 0, n = count / 2; i < n; i++) { + for (int k = 0; k < stride; k++) { + long v = m_buffer[j + k]; + m_buffer[j + k] = m_buffer[offset + k]; + m_buffer[offset + k] = v; + } + j += stride; + offset -= stride; + } + } + } + + @Override + public void writeRange(int startElement, int count, ByteBuffer src, + int offsetBytes, boolean bForward) { + if (startElement < 0 || count < 0 || offsetBytes < 0) + throw new IllegalArgumentException(); + + final int elmSize = NumberUtils.sizeOf((double) 0); + if (src.capacity() < (int) (offsetBytes + elmSize * count)) + throw new IllegalArgumentException(); + + if (count == 0) + return; + + if (size() < count + startElement) + resize(count + startElement); + + int j = startElement; + if (!bForward) + j += count - 1; + + final int dj = bForward ? 1 : -1; + + int offset = offsetBytes; + for (int i = 0; i < count; i++, offset += elmSize) { + m_buffer[j] = src.getLong(offset); + j += dj; + } + + } } diff --git a/src/main/java/com/esri/core/geometry/AttributeStreamOfInt8.java b/src/main/java/com/esri/core/geometry/AttributeStreamOfInt8.java index 8de6d38a..56d8f80d 100644 --- a/src/main/java/com/esri/core/geometry/AttributeStreamOfInt8.java +++ b/src/main/java/com/esri/core/geometry/AttributeStreamOfInt8.java @@ -34,126 +34,125 @@ final class AttributeStreamOfInt8 extends AttributeStreamBase { - private byte[] m_buffer = null; - private int m_size; - - public int size() { - return m_size; - } - - public void reserve(int reserve)// only in Java - { - if (reserve <= 0) - return; - if (m_buffer == null) - m_buffer = new byte[reserve]; - else { - if (reserve <= m_buffer.length) - return; - byte[] buf = new byte[reserve]; - System.arraycopy(m_buffer, 0, buf, 0, m_size); - m_buffer = buf; - } - - } - - public int capacity() { - return m_buffer != null ? m_buffer.length : 0; - } - - public AttributeStreamOfInt8(int size) { - int sz = size; - if (sz < 2) - sz = 2; - m_buffer = new byte[sz]; - m_size = size; - } - - public AttributeStreamOfInt8(int size, byte defaultValue) { - int sz = size; - if (sz < 2) - sz = 2; - m_buffer = new byte[sz]; - m_size = size; - for (int i = 0; i < size; i++) - m_buffer[i] = defaultValue; - } - - public AttributeStreamOfInt8(AttributeStreamOfInt8 other) { - m_buffer = other.m_buffer.clone(); - m_size = other.m_size; - } - - public AttributeStreamOfInt8(AttributeStreamOfInt8 other, int maxSize) { - m_size = other.size(); - if (m_size > maxSize) - m_size = maxSize; - int sz = m_size; - if (sz < 2) - sz = 2; - m_buffer = new byte[sz]; - System.arraycopy(other.m_buffer, 0, m_buffer, 0, m_size); - } - - /** - * Reads a value from the buffer at given offset. - * - * @param offset is the element number in the stream. - */ - public byte read(int offset) { - return m_buffer[offset]; - } - - /** - * Overwrites given element with new value. - * - * @param offset is the element number in the stream. - * @param value is the value to write. - */ - public void write(int offset, byte value) { - if (m_bReadonly) { - throw new RuntimeException("invalid_call"); - } - m_buffer[offset] = value; - } - - public void set(int offset, byte value) { - if (m_bReadonly) { - throw new RuntimeException("invalid_call"); - } - m_buffer[offset] = value; - } - - /** - * Adds a new value at the end of the stream. - * - * @param offset is the element number in the stream. - * @param value is the value to write. - */ - public void add(byte v) { - resize(m_size + 1); - m_buffer[m_size - 1] = v; - } - - @Override - public AttributeStreamBase restrictedClone(int maxsize) { - int len = m_size; - int newSize = maxsize < len ? maxsize : len; - byte[] newBuffer = new byte[newSize]; - System.arraycopy(m_buffer, 0, newBuffer, 0, newSize); - m_buffer = newBuffer; - m_size = newSize; - return this; - } - - @Override - public int virtualSize() { - return size(); - } + private byte[] m_buffer = null; + private int m_size; - @Override - public long estimateMemorySize() + public int size() { + return m_size; + } + + public void reserve(int reserve)// only in Java { + if (reserve <= 0) + return; + if (m_buffer == null) + m_buffer = new byte[reserve]; + else { + if (reserve <= m_buffer.length) + return; + byte[] buf = new byte[reserve]; + System.arraycopy(m_buffer, 0, buf, 0, m_size); + m_buffer = buf; + } + + } + + public int capacity() { + return m_buffer != null ? m_buffer.length : 0; + } + + public AttributeStreamOfInt8(int size) { + int sz = size; + if (sz < 2) + sz = 2; + m_buffer = new byte[sz]; + m_size = size; + } + + public AttributeStreamOfInt8(int size, byte defaultValue) { + int sz = size; + if (sz < 2) + sz = 2; + m_buffer = new byte[sz]; + m_size = size; + for (int i = 0; i < size; i++) + m_buffer[i] = defaultValue; + } + + public AttributeStreamOfInt8(AttributeStreamOfInt8 other) { + m_buffer = other.m_buffer.clone(); + m_size = other.m_size; + } + + public AttributeStreamOfInt8(AttributeStreamOfInt8 other, int maxSize) { + m_size = other.size(); + if (m_size > maxSize) + m_size = maxSize; + int sz = m_size; + if (sz < 2) + sz = 2; + m_buffer = new byte[sz]; + System.arraycopy(other.m_buffer, 0, m_buffer, 0, m_size); + } + + /** + * Reads a value from the buffer at given offset. + * + * @param offset is the element number in the stream. + */ + public byte read(int offset) { + return m_buffer[offset]; + } + + /** + * Overwrites given element with new value. + * + * @param offset is the element number in the stream. + * @param value is the value to write. + */ + public void write(int offset, byte value) { + if (m_bReadonly) { + throw new RuntimeException("invalid_call"); + } + m_buffer[offset] = value; + } + + public void set(int offset, byte value) { + if (m_bReadonly) { + throw new RuntimeException("invalid_call"); + } + m_buffer[offset] = value; + } + + /** + * Adds a new value at the end of the stream. + * + * @param offset is the element number in the stream. + * @param value is the value to write. + */ + public void add(byte v) { + resize(m_size + 1); + m_buffer[m_size - 1] = v; + } + + @Override + public AttributeStreamBase restrictedClone(int maxsize) { + int len = m_size; + int newSize = maxsize < len ? maxsize : len; + byte[] newBuffer = new byte[newSize]; + System.arraycopy(m_buffer, 0, newBuffer, 0, newSize); + m_buffer = newBuffer; + m_size = newSize; + return this; + } + + @Override + public int virtualSize() { + return size(); + } + + @Override + public long estimateMemorySize() { return SIZE_OF_ATTRIBUTE_STREAM_OF_INT8 + sizeOfByteArray(m_buffer.length); } @@ -162,488 +161,488 @@ public int getPersistence() { return Persistence.enumInt8; } - @Override - public double readAsDbl(int offset) { - return read(offset); - } - - int get(int offset) { - return m_buffer[offset]; - } - - @Override - public int readAsInt(int offset) { - return (int) read(offset); - } - - @Override - public long readAsInt64(int offset) { - return (long) read(offset); - } - - @Override - public void resize(int newSize) { - if (m_bLockedInSize) - throw new GeometryException( - "invalid call. Attribute Stream is locked and cannot be resized."); - - if (newSize <= m_size) { - if ((newSize * 5) / 4 < m_buffer.length) {// decrease when the 25% - // margin is exceeded - byte[] newBuffer = new byte[newSize]; - System.arraycopy(m_buffer, 0, newBuffer, 0, newSize); - m_buffer = newBuffer; - } - m_size = newSize; - } else { - if (newSize > m_buffer.length) { - int sz = (newSize < 64) ? Math.max(newSize * 2, 4) - : (newSize * 5) / 4; - byte[] newBuffer = new byte[sz]; - System.arraycopy(m_buffer, 0, newBuffer, 0, m_size); - m_buffer = newBuffer; - } - - m_size = newSize; - } - } - - @Override - public void resizePreserveCapacity(int newSize)// java only method - { - if (m_buffer == null || newSize > m_buffer.length) - resize(newSize); - if (m_bLockedInSize) - throw new GeometryException( - "invalid call. Attribute Stream is locked and cannot be resized."); - - m_size = newSize; - } - - @Override - public void resize(int newSize, double defaultValue) { - if (m_bLockedInSize) - throw new GeometryException( - "invalid call. Attribute Stream is locked and cannot be resized."); - if (newSize <= m_size) { - if ((newSize * 5) / 4 < m_buffer.length) {// decrease when the 25% - // margin is exceeded - byte[] newBuffer = new byte[newSize]; - System.arraycopy(m_buffer, 0, newBuffer, 0, newSize); - m_buffer = newBuffer; - } - m_size = newSize; - } else { - if (newSize > m_buffer.length) { - int sz = (newSize < 64) ? Math.max(newSize * 2, 4) - : (newSize * 5) / 4; - byte[] newBuffer = new byte[sz]; - System.arraycopy(m_buffer, 0, newBuffer, 0, m_size); - m_buffer = newBuffer; - } - - for (int i = m_size; i < newSize; i++) - m_buffer[i] = (byte) defaultValue; - - m_size = newSize; - } - } - - @Override - public void writeAsDbl(int offset, double d) { - write(offset, (byte) d); - } - - @Override - public void writeAsInt64(int offset, long d) { - write(offset, (byte) d); - } - - @Override - public void writeAsInt(int offset, int d) { - write(offset, (byte) d); - } - - // @Override - // public void writeRange(int srcStart, int count, ByteBuffer dst, - // int dstOffsetBytes) { - // // TODO Auto-generated method stub - // - // } - - /** - * OR's the given element with new value. - * - * @param offset is the element number in the stream. - * @param value is the value to OR. - */ - public void setBits(int offset, byte mask) { - if (m_bReadonly) - throw new GeometryException( - "invalid call. Attribute Stream is read only."); - - m_buffer[offset] = (byte) (m_buffer[offset] | mask); - } - - /** - * Clears bits in the given element that a set in the value param. - * - * @param offset is the element number in the stream. - * @param value is the mask to clear. - */ - void clearBits(int offset, byte mask) { - - if (m_bReadonly) - throw new GeometryException( - "invalid call. Attribute Stream is read only."); - - m_buffer[offset] = (byte) (m_buffer[offset] & (~mask)); - } - - @Override - public int calculateHashImpl(int hashCode, int start, int end) { - for (int i = start, n = size(); i < n && i < end; i++) - hashCode = NumberUtils.hash(hashCode, read(i)); - - return hashCode; - } - - @Override - public boolean equals(AttributeStreamBase other, int start, int end) { - if (other == null) - return false; - - if (!(other instanceof AttributeStreamOfInt8)) - return false; - - AttributeStreamOfInt8 _other = (AttributeStreamOfInt8) other; - - int size = size(); - int sizeOther = _other.size(); - - if (end > size || end > sizeOther && (size != sizeOther)) - return false; - - if (end > size) - end = size; - - for (int i = start; i < end; i++) - if (read(i) != _other.read(i)) - return false; - - return true; - } - - public byte getLast() { - return m_buffer[m_size - 1]; - } - - public void removeLast() { - resize(m_size - 1); - } - - @Override - public void addRange(AttributeStreamBase src, int start, int count, - boolean bForward, int stride) { - if (m_bReadonly) - throw new GeometryException("invalid_call"); - - if (!bForward && (stride < 1 || count % stride != 0)) - throw new IllegalArgumentException(); - - int oldSize = m_size; - int newSize = oldSize + count; - resize(newSize); - - if (bForward) { - System.arraycopy(((AttributeStreamOfInt8) src).m_buffer, start, - m_buffer, oldSize, count); - } else { - int n = count; - - for (int i = 0; i < count; i += stride) { - n -= stride; - - for (int s = 0; s < stride; s++) { - m_buffer[oldSize + i + s] = ((AttributeStreamOfInt8) src).m_buffer[start - + n + s]; - } - } - } - } - - @Override - public void insertRange(int start, AttributeStreamBase src, int srcStart, - int count, boolean bForward, int stride, int validSize) { - if (m_bReadonly) - throw new GeometryException("invalid_call"); - - if (!bForward && (stride < 1 || count % stride != 0)) - throw new IllegalArgumentException(); - - System.arraycopy(m_buffer, start, m_buffer, start + count, validSize - - start); - - if (m_buffer == ((AttributeStreamOfInt8) src).m_buffer) { - if (start < srcStart) - srcStart += count; - } - - if (bForward) { - System.arraycopy(((AttributeStreamOfInt8) src).m_buffer, srcStart, - m_buffer, start, count); - } else { - int n = count; - - for (int i = 0; i < count; i += stride) { - n -= stride; - - for (int s = 0; s < stride; s++) { - m_buffer[start + i + s] = ((AttributeStreamOfInt8) src).m_buffer[srcStart - + n + s]; - } - } - } - } - - @Override - public void insertRange(int start, double value, int count, int validSize) { - if (m_bReadonly) - throw new GeometryException("invalid_call"); - - System.arraycopy(m_buffer, start, m_buffer, start + count, validSize - - start); - - byte v = (byte) value; - for (int i = 0; i < count; i++) { - m_buffer[start + i] = v; - } - } - - @Override - public void insertAttributes(int start, Point pt, int semantics, - int validSize) { - if (m_bReadonly) - throw new GeometryException("invalid_call"); - - int comp = VertexDescription.getComponentCount(semantics); - - System.arraycopy(m_buffer, start, m_buffer, start + comp, validSize - - start); - - for (int c = 0; c < comp; c++) { - m_buffer[start + c] = (byte) pt.getAttributeAsDbl(semantics, c); - } - } - - @Override - public void eraseRange(int index, int count, int validSize) { - if (m_bReadonly) - throw new GeometryException("invalid_call"); - - if (index + count > m_size) - throw new GeometryException("invalid_call"); - - System.arraycopy(m_buffer, index + count, m_buffer, index, validSize - - (index + count)); - m_size -= count; - } - - @Override - public void readRange(int srcStart, int count, ByteBuffer dst, - int dstOffset, boolean bForward) { - if (srcStart < 0 || count < 0 || dstOffset < 0 - || size() < count + srcStart) - throw new IllegalArgumentException(); - - final int elmSize = NumberUtils.sizeOf((double) 0); - - if (dst.capacity() < (int) (dstOffset + elmSize * count)) - throw new IllegalArgumentException(); - - if (count == 0) - return; - - int j = srcStart; - if (!bForward) - j += count - 1; - - final int dj = bForward ? 1 : -1; - - int offset = dstOffset; - for (int i = 0; i < count; i++, offset += elmSize) { - dst.put(offset, m_buffer[j]); - j += dj; - } - - } - - @Override - public void reverseRange(int index, int count, int stride) { - if (m_bReadonly) - throw new GeometryException("invalid_call"); - - if (stride < 1 || count % stride != 0) - throw new GeometryException("invalid_call"); - - int cIterations = count >> 1; - int n = count; - - for (int i = 0; i < cIterations; i += stride) { - n -= stride; - - for (int s = 0; s < stride; s++) { - byte temp = m_buffer[index + i + s]; - m_buffer[index + i + s] = m_buffer[index + n + s]; - m_buffer[index + n + s] = temp; - } - } - } - - @Override - public void setRange(double value, int start, int count) { - if (start < 0 || count < 0 || start < 0 || count + start > size()) - throw new IllegalArgumentException(); - - byte v = (byte) value; - for (int i = start, n = start + count; i < n; i++) - write(i, v); - } - - @Override - public void writeRange(int startElement, int count, - AttributeStreamBase _src, int srcStart, boolean bForward, int stride) { - if (startElement < 0 || count < 0 || srcStart < 0) - throw new IllegalArgumentException(); - - if (!bForward && (stride <= 0 || (count % stride != 0))) - throw new IllegalArgumentException(); - - AttributeStreamOfInt8 src = (AttributeStreamOfInt8) _src; // the input - // type must - // match - - if (src.size() < (int) (srcStart + count)) - throw new IllegalArgumentException(); - - if (count == 0) - return; - - if (size() < count + startElement) - resize(count + startElement); - - if (_src == (AttributeStreamBase) this) { - _selfWriteRangeImpl(startElement, count, srcStart, bForward, stride); - return; - } - - if (bForward) { - int j = startElement; - int offset = srcStart; - for (int i = 0; i < count; i++) { - m_buffer[j] = src.m_buffer[offset]; - j++; - offset++; - } - } else { - int j = startElement; - int offset = srcStart + count - stride; - if (stride == 1) { - for (int i = 0; i < count; i++) { - m_buffer[j] = src.m_buffer[offset]; - j++; - offset--; - } - } else { - for (int i = 0, n = count / stride; i < n; i++) { - for (int k = 0; k < stride; k++) - m_buffer[j + k] = src.m_buffer[offset + k]; - - j += stride; - offset -= stride; - } - } - } - } - - private void _selfWriteRangeImpl(int toElement, int count, int fromElement, - boolean bForward, int stride) { - - // writing from to this stream. - if (bForward) { - if (toElement == fromElement) - return; - } - - int offset; - int j; - int dj; - - if (fromElement < toElement) { - offset = fromElement + count - stride; - j = toElement + count - stride; - for (int i = 0, n = count / 2; i < n; i++) { - for (int k = 0; k < stride; k++) { - m_buffer[j + k] = m_buffer[offset + k]; - } - j -= stride; - offset -= stride; - } - } else { - offset = fromElement; - j = toElement; - dj = 1; - for (int i = 0; i < count; i++) { - m_buffer[j] = m_buffer[offset]; - j += 1; - offset++; - } - } - - if (!bForward) { - // reverse what we written - j = toElement; - offset = toElement + count - stride; - dj = stride; - for (int i = 0, n = count / 2; i < n; i++) { - for (int k = 0; k < stride; k++) { - byte v = m_buffer[j + k]; - m_buffer[j + k] = m_buffer[offset + k]; - m_buffer[offset + k] = v; - } - j += stride; - offset -= stride; - } - } - } - - @Override - public void writeRange(int startElement, int count, ByteBuffer src, - int offsetBytes, boolean bForward) { - if (startElement < 0 || count < 0 || offsetBytes < 0) - throw new IllegalArgumentException(); - - final int elmSize = NumberUtils.sizeOf((double) 0); - if (src.capacity() < (int) (offsetBytes + elmSize * count)) - throw new IllegalArgumentException(); - - if (count == 0) - return; - - if (size() < count + startElement) - resize(count + startElement); - - int j = startElement; - if (!bForward) - j += count - 1; - - final int dj = bForward ? 1 : -1; - - int offset = offsetBytes; - for (int i = 0; i < count; i++, offset += elmSize) { - m_buffer[j] = src.get(offset); - j += dj; - } - - } + @Override + public double readAsDbl(int offset) { + return read(offset); + } + + int get(int offset) { + return m_buffer[offset]; + } + + @Override + public int readAsInt(int offset) { + return (int) read(offset); + } + + @Override + public long readAsInt64(int offset) { + return (long) read(offset); + } + + @Override + public void resize(int newSize) { + if (m_bLockedInSize) + throw new GeometryException( + "invalid call. Attribute Stream is locked and cannot be resized."); + + if (newSize <= m_size) { + if ((newSize * 5) / 4 < m_buffer.length) {// decrease when the 25% + // margin is exceeded + byte[] newBuffer = new byte[newSize]; + System.arraycopy(m_buffer, 0, newBuffer, 0, newSize); + m_buffer = newBuffer; + } + m_size = newSize; + } else { + if (newSize > m_buffer.length) { + int sz = (newSize < 64) ? Math.max(newSize * 2, 4) + : (newSize * 5) / 4; + byte[] newBuffer = new byte[sz]; + System.arraycopy(m_buffer, 0, newBuffer, 0, m_size); + m_buffer = newBuffer; + } + + m_size = newSize; + } + } + + @Override + public void resizePreserveCapacity(int newSize)// java only method + { + if (m_buffer == null || newSize > m_buffer.length) + resize(newSize); + if (m_bLockedInSize) + throw new GeometryException( + "invalid call. Attribute Stream is locked and cannot be resized."); + + m_size = newSize; + } + + @Override + public void resize(int newSize, double defaultValue) { + if (m_bLockedInSize) + throw new GeometryException( + "invalid call. Attribute Stream is locked and cannot be resized."); + if (newSize <= m_size) { + if ((newSize * 5) / 4 < m_buffer.length) {// decrease when the 25% + // margin is exceeded + byte[] newBuffer = new byte[newSize]; + System.arraycopy(m_buffer, 0, newBuffer, 0, newSize); + m_buffer = newBuffer; + } + m_size = newSize; + } else { + if (newSize > m_buffer.length) { + int sz = (newSize < 64) ? Math.max(newSize * 2, 4) + : (newSize * 5) / 4; + byte[] newBuffer = new byte[sz]; + System.arraycopy(m_buffer, 0, newBuffer, 0, m_size); + m_buffer = newBuffer; + } + + for (int i = m_size; i < newSize; i++) + m_buffer[i] = (byte) defaultValue; + + m_size = newSize; + } + } + + @Override + public void writeAsDbl(int offset, double d) { + write(offset, (byte) d); + } + + @Override + public void writeAsInt64(int offset, long d) { + write(offset, (byte) d); + } + + @Override + public void writeAsInt(int offset, int d) { + write(offset, (byte) d); + } + + // @Override + // public void writeRange(int srcStart, int count, ByteBuffer dst, + // int dstOffsetBytes) { + // // TODO Auto-generated method stub + // + // } + + /** + * OR's the given element with new value. + * + * @param offset is the element number in the stream. + * @param value is the value to OR. + */ + public void setBits(int offset, byte mask) { + if (m_bReadonly) + throw new GeometryException( + "invalid call. Attribute Stream is read only."); + + m_buffer[offset] = (byte) (m_buffer[offset] | mask); + } + + /** + * Clears bits in the given element that a set in the value param. + * + * @param offset is the element number in the stream. + * @param value is the mask to clear. + */ + void clearBits(int offset, byte mask) { + + if (m_bReadonly) + throw new GeometryException( + "invalid call. Attribute Stream is read only."); + + m_buffer[offset] = (byte) (m_buffer[offset] & (~mask)); + } + + @Override + public int calculateHashImpl(int hashCode, int start, int end) { + for (int i = start, n = size(); i < n && i < end; i++) + hashCode = NumberUtils.hash(hashCode, read(i)); + + return hashCode; + } + + @Override + public boolean equals(AttributeStreamBase other, int start, int end) { + if (other == null) + return false; + + if (!(other instanceof AttributeStreamOfInt8)) + return false; + + AttributeStreamOfInt8 _other = (AttributeStreamOfInt8) other; + + int size = size(); + int sizeOther = _other.size(); + + if (end > size || end > sizeOther && (size != sizeOther)) + return false; + + if (end > size) + end = size; + + for (int i = start; i < end; i++) + if (read(i) != _other.read(i)) + return false; + + return true; + } + + public byte getLast() { + return m_buffer[m_size - 1]; + } + + public void removeLast() { + resize(m_size - 1); + } + + @Override + public void addRange(AttributeStreamBase src, int start, int count, + boolean bForward, int stride) { + if (m_bReadonly) + throw new GeometryException("invalid_call"); + + if (!bForward && (stride < 1 || count % stride != 0)) + throw new IllegalArgumentException(); + + int oldSize = m_size; + int newSize = oldSize + count; + resize(newSize); + + if (bForward) { + System.arraycopy(((AttributeStreamOfInt8) src).m_buffer, start, + m_buffer, oldSize, count); + } else { + int n = count; + + for (int i = 0; i < count; i += stride) { + n -= stride; + + for (int s = 0; s < stride; s++) { + m_buffer[oldSize + i + s] = ((AttributeStreamOfInt8) src).m_buffer[start + + n + s]; + } + } + } + } + + @Override + public void insertRange(int start, AttributeStreamBase src, int srcStart, + int count, boolean bForward, int stride, int validSize) { + if (m_bReadonly) + throw new GeometryException("invalid_call"); + + if (!bForward && (stride < 1 || count % stride != 0)) + throw new IllegalArgumentException(); + + System.arraycopy(m_buffer, start, m_buffer, start + count, validSize + - start); + + if (m_buffer == ((AttributeStreamOfInt8) src).m_buffer) { + if (start < srcStart) + srcStart += count; + } + + if (bForward) { + System.arraycopy(((AttributeStreamOfInt8) src).m_buffer, srcStart, + m_buffer, start, count); + } else { + int n = count; + + for (int i = 0; i < count; i += stride) { + n -= stride; + + for (int s = 0; s < stride; s++) { + m_buffer[start + i + s] = ((AttributeStreamOfInt8) src).m_buffer[srcStart + + n + s]; + } + } + } + } + + @Override + public void insertRange(int start, double value, int count, int validSize) { + if (m_bReadonly) + throw new GeometryException("invalid_call"); + + System.arraycopy(m_buffer, start, m_buffer, start + count, validSize + - start); + + byte v = (byte) value; + for (int i = 0; i < count; i++) { + m_buffer[start + i] = v; + } + } + + @Override + public void insertAttributes(int start, Point pt, int semantics, + int validSize) { + if (m_bReadonly) + throw new GeometryException("invalid_call"); + + int comp = VertexDescription.getComponentCount(semantics); + + System.arraycopy(m_buffer, start, m_buffer, start + comp, validSize + - start); + + for (int c = 0; c < comp; c++) { + m_buffer[start + c] = (byte) pt.getAttributeAsDbl(semantics, c); + } + } + + @Override + public void eraseRange(int index, int count, int validSize) { + if (m_bReadonly) + throw new GeometryException("invalid_call"); + + if (index + count > m_size) + throw new GeometryException("invalid_call"); + + System.arraycopy(m_buffer, index + count, m_buffer, index, validSize + - (index + count)); + m_size -= count; + } + + @Override + public void readRange(int srcStart, int count, ByteBuffer dst, + int dstOffset, boolean bForward) { + if (srcStart < 0 || count < 0 || dstOffset < 0 + || size() < count + srcStart) + throw new IllegalArgumentException(); + + final int elmSize = NumberUtils.sizeOf((double) 0); + + if (dst.capacity() < (int) (dstOffset + elmSize * count)) + throw new IllegalArgumentException(); + + if (count == 0) + return; + + int j = srcStart; + if (!bForward) + j += count - 1; + + final int dj = bForward ? 1 : -1; + + int offset = dstOffset; + for (int i = 0; i < count; i++, offset += elmSize) { + dst.put(offset, m_buffer[j]); + j += dj; + } + + } + + @Override + public void reverseRange(int index, int count, int stride) { + if (m_bReadonly) + throw new GeometryException("invalid_call"); + + if (stride < 1 || count % stride != 0) + throw new GeometryException("invalid_call"); + + int cIterations = count >> 1; + int n = count; + + for (int i = 0; i < cIterations; i += stride) { + n -= stride; + + for (int s = 0; s < stride; s++) { + byte temp = m_buffer[index + i + s]; + m_buffer[index + i + s] = m_buffer[index + n + s]; + m_buffer[index + n + s] = temp; + } + } + } + + @Override + public void setRange(double value, int start, int count) { + if (start < 0 || count < 0 || start < 0 || count + start > size()) + throw new IllegalArgumentException(); + + byte v = (byte) value; + for (int i = start, n = start + count; i < n; i++) + write(i, v); + } + + @Override + public void writeRange(int startElement, int count, + AttributeStreamBase _src, int srcStart, boolean bForward, int stride) { + if (startElement < 0 || count < 0 || srcStart < 0) + throw new IllegalArgumentException(); + + if (!bForward && (stride <= 0 || (count % stride != 0))) + throw new IllegalArgumentException(); + + AttributeStreamOfInt8 src = (AttributeStreamOfInt8) _src; // the input + // type must + // match + + if (src.size() < (int) (srcStart + count)) + throw new IllegalArgumentException(); + + if (count == 0) + return; + + if (size() < count + startElement) + resize(count + startElement); + + if (_src == (AttributeStreamBase) this) { + _selfWriteRangeImpl(startElement, count, srcStart, bForward, stride); + return; + } + + if (bForward) { + int j = startElement; + int offset = srcStart; + for (int i = 0; i < count; i++) { + m_buffer[j] = src.m_buffer[offset]; + j++; + offset++; + } + } else { + int j = startElement; + int offset = srcStart + count - stride; + if (stride == 1) { + for (int i = 0; i < count; i++) { + m_buffer[j] = src.m_buffer[offset]; + j++; + offset--; + } + } else { + for (int i = 0, n = count / stride; i < n; i++) { + for (int k = 0; k < stride; k++) + m_buffer[j + k] = src.m_buffer[offset + k]; + + j += stride; + offset -= stride; + } + } + } + } + + private void _selfWriteRangeImpl(int toElement, int count, int fromElement, + boolean bForward, int stride) { + + // writing from to this stream. + if (bForward) { + if (toElement == fromElement) + return; + } + + int offset; + int j; + int dj; + + if (fromElement < toElement) { + offset = fromElement + count - stride; + j = toElement + count - stride; + for (int i = 0, n = count / 2; i < n; i++) { + for (int k = 0; k < stride; k++) { + m_buffer[j + k] = m_buffer[offset + k]; + } + j -= stride; + offset -= stride; + } + } else { + offset = fromElement; + j = toElement; + dj = 1; + for (int i = 0; i < count; i++) { + m_buffer[j] = m_buffer[offset]; + j += 1; + offset++; + } + } + + if (!bForward) { + // reverse what we written + j = toElement; + offset = toElement + count - stride; + dj = stride; + for (int i = 0, n = count / 2; i < n; i++) { + for (int k = 0; k < stride; k++) { + byte v = m_buffer[j + k]; + m_buffer[j + k] = m_buffer[offset + k]; + m_buffer[offset + k] = v; + } + j += stride; + offset -= stride; + } + } + } + + @Override + public void writeRange(int startElement, int count, ByteBuffer src, + int offsetBytes, boolean bForward) { + if (startElement < 0 || count < 0 || offsetBytes < 0) + throw new IllegalArgumentException(); + + final int elmSize = NumberUtils.sizeOf((double) 0); + if (src.capacity() < (int) (offsetBytes + elmSize * count)) + throw new IllegalArgumentException(); + + if (count == 0) + return; + + if (size() < count + startElement) + resize(count + startElement); + + int j = startElement; + if (!bForward) + j += count - 1; + + final int dj = bForward ? 1 : -1; + + int offset = offsetBytes; + for (int i = 0; i < count; i++, offset += elmSize) { + m_buffer[j] = src.get(offset); + j += dj; + } + + } } diff --git a/src/main/java/com/esri/core/geometry/Boundary.java b/src/main/java/com/esri/core/geometry/Boundary.java index 7dcfc243..f8ee242f 100644 --- a/src/main/java/com/esri/core/geometry/Boundary.java +++ b/src/main/java/com/esri/core/geometry/Boundary.java @@ -25,213 +25,213 @@ class Boundary { - static boolean hasNonEmptyBoundary(Geometry geom, - ProgressTracker progress_tracker) { - if (geom.isEmpty()) - return false; - - Geometry.Type gt = geom.getType(); - if (gt == Geometry.Type.Polygon) { - if (geom.calculateArea2D() == 0) - return false; - - return true; - } else if (gt == Geometry.Type.Polyline) { - boolean[] b = new boolean[1]; - b[0] = false; - calculatePolylineBoundary_(geom._getImpl(), progress_tracker, true, - b); - return b[0]; - } else if (gt == Geometry.Type.Envelope) { - return true; - } else if (Geometry.isSegment(gt.value())) { - if (!((Segment) geom).isClosed()) { - return true; - } - - return false; - } else if (Geometry.isPoint(gt.value())) { - return false; - } - - return false; - } - - static Geometry calculate(Geometry geom, ProgressTracker progress_tracker) { - int gt = geom.getType().value(); - if (gt == Geometry.GeometryType.Polygon) { - Polyline dst = new Polyline(geom.getDescription()); - if (!geom.isEmpty()) { - ((MultiPathImpl) geom._getImpl()) - ._copyToUnsafe((MultiPathImpl) dst._getImpl()); - } - - return dst; - } else if (gt == Geometry.GeometryType.Polyline) { - return calculatePolylineBoundary_(geom._getImpl(), - progress_tracker, false, null); - } else if (gt == Geometry.GeometryType.Envelope) { - Polyline dst = new Polyline(geom.getDescription()); - if (!geom.isEmpty()) - dst.addEnvelope((Envelope) geom, false); - - return dst; - } else if (Geometry.isSegment(gt)) { - MultiPoint mp = new MultiPoint(geom.getDescription()); - if (!geom.isEmpty() && !((Segment) geom).isClosed()) { - Point pt = new Point(); - ((Segment) geom).queryStart(pt); - mp.add(pt); - ((Segment) geom).queryEnd(pt); - mp.add(pt); - } - return mp; - } else if (Geometry.isPoint(gt)) { - // returns empty point for points and multipoints. - return null; - } - - throw new IllegalArgumentException(); - } - - private static final class MultiPathImplBoundarySorter extends ClassicSort { - AttributeStreamOfDbl m_xy; - - static final class CompareIndices extends - AttributeStreamOfInt32.IntComparator { - AttributeStreamOfDbl m_xy; - Point2D pt1_helper; - Point2D pt2_helper; - - CompareIndices(AttributeStreamOfDbl xy) { - m_xy = xy; - pt1_helper = new Point2D(); - pt2_helper = new Point2D(); - } - - @Override - public int compare(int v1, int v2) { - m_xy.read(2 * v1, pt1_helper); - m_xy.read(2 * v2, pt2_helper); - return pt1_helper.compare(pt2_helper); - } - } - - MultiPathImplBoundarySorter(AttributeStreamOfDbl xy) { - m_xy = xy; - } - - @Override - public void userSort(int begin, int end, AttributeStreamOfInt32 indices) { - indices.Sort(begin, end, new CompareIndices(m_xy)); - } - - @Override - public double getValue(int index) { - return m_xy.read(2 * index + 1); - } - } - - static MultiPoint calculatePolylineBoundary_(Object impl, - ProgressTracker progress_tracker, - boolean only_check_non_empty_boundary, boolean[] not_empty) { - if (not_empty != null) - not_empty[0] = false; - MultiPathImpl mpImpl = (MultiPathImpl) impl; - MultiPoint dst = null; - if (!only_check_non_empty_boundary) - dst = new MultiPoint(mpImpl.getDescription()); - - if (!mpImpl.isEmpty()) { - AttributeStreamOfInt32 indices = new AttributeStreamOfInt32(0); - indices.reserve(mpImpl.getPathCount() * 2); - for (int ipath = 0, nPathCount = mpImpl.getPathCount(); ipath < nPathCount; ipath++) { - int path_size = mpImpl.getPathSize(ipath); - if (path_size > 0 && !mpImpl.isClosedPathInXYPlane(ipath))// closed - // paths - // of - // polyline - // do - // not - // contribute - // to - // the - // boundary. - { - int start = mpImpl.getPathStart(ipath); - indices.add(start); - int end = mpImpl.getPathEnd(ipath) - 1; - indices.add(end); - } - } - if (indices.size() > 0) { - BucketSort sorter = new BucketSort(); - AttributeStreamOfDbl xy = (AttributeStreamOfDbl) (mpImpl - .getAttributeStreamRef(VertexDescription.Semantics.POSITION)); - sorter.sort(indices, 0, indices.size(), - new MultiPathImplBoundarySorter(xy)); - Point2D ptPrev = new Point2D(); - xy.read(2 * indices.get(0), ptPrev); - int ind = 0; - int counter = 1; - Point point = new Point(); - Point2D pt = new Point2D(); - for (int i = 1, n = indices.size(); i < n; i++) { - xy.read(2 * indices.get(i), pt); - if (pt.isEqual(ptPrev)) { - if (indices.get(ind) > indices.get(i)) { - // remove duplicate point - indices.set(ind, NumberUtils.intMax()); - ind = i;// just for the heck of it, have the first - // point in the order to be added to the - // boundary. - } else - indices.set(i, NumberUtils.intMax()); - - counter++; - } else { - if ((counter & 1) == 0) {// remove boundary point - indices.set(ind, NumberUtils.intMax()); - } else { - if (only_check_non_empty_boundary) { - if (not_empty != null) - not_empty[0] = true; - return null; - } - } - - ptPrev.setCoords(pt); - ind = i; - counter = 1; - } - } - - if ((counter & 1) == 0) {// remove the point - indices.set(ind, NumberUtils.intMax()); - } else { - if (only_check_non_empty_boundary) { - if (not_empty != null) - not_empty[0] = true; - return null; - } - } - if (!only_check_non_empty_boundary) { - indices.sort(0, indices.size()); - - for (int i = 0, n = indices.size(); i < n; i++) { - if (indices.get(i) == NumberUtils.intMax()) - break; - - mpImpl.getPointByVal(indices.get(i), point); - dst.add(point); - } - } - } - } - - if (only_check_non_empty_boundary) - return null; - - return dst; - } + static boolean hasNonEmptyBoundary(Geometry geom, + ProgressTracker progress_tracker) { + if (geom.isEmpty()) + return false; + + Geometry.Type gt = geom.getType(); + if (gt == Geometry.Type.Polygon) { + if (geom.calculateArea2D() == 0) + return false; + + return true; + } else if (gt == Geometry.Type.Polyline) { + boolean[] b = new boolean[1]; + b[0] = false; + calculatePolylineBoundary_(geom._getImpl(), progress_tracker, true, + b); + return b[0]; + } else if (gt == Geometry.Type.Envelope) { + return true; + } else if (Geometry.isSegment(gt.value())) { + if (!((Segment) geom).isClosed()) { + return true; + } + + return false; + } else if (Geometry.isPoint(gt.value())) { + return false; + } + + return false; + } + + static Geometry calculate(Geometry geom, ProgressTracker progress_tracker) { + int gt = geom.getType().value(); + if (gt == Geometry.GeometryType.Polygon) { + Polyline dst = new Polyline(geom.getDescription()); + if (!geom.isEmpty()) { + ((MultiPathImpl) geom._getImpl()) + ._copyToUnsafe((MultiPathImpl) dst._getImpl()); + } + + return dst; + } else if (gt == Geometry.GeometryType.Polyline) { + return calculatePolylineBoundary_(geom._getImpl(), + progress_tracker, false, null); + } else if (gt == Geometry.GeometryType.Envelope) { + Polyline dst = new Polyline(geom.getDescription()); + if (!geom.isEmpty()) + dst.addEnvelope((Envelope) geom, false); + + return dst; + } else if (Geometry.isSegment(gt)) { + MultiPoint mp = new MultiPoint(geom.getDescription()); + if (!geom.isEmpty() && !((Segment) geom).isClosed()) { + Point pt = new Point(); + ((Segment) geom).queryStart(pt); + mp.add(pt); + ((Segment) geom).queryEnd(pt); + mp.add(pt); + } + return mp; + } else if (Geometry.isPoint(gt)) { + // returns empty point for points and multipoints. + return null; + } + + throw new IllegalArgumentException(); + } + + private static final class MultiPathImplBoundarySorter extends ClassicSort { + AttributeStreamOfDbl m_xy; + + static final class CompareIndices extends + AttributeStreamOfInt32.IntComparator { + AttributeStreamOfDbl m_xy; + Point2D pt1_helper; + Point2D pt2_helper; + + CompareIndices(AttributeStreamOfDbl xy) { + m_xy = xy; + pt1_helper = new Point2D(); + pt2_helper = new Point2D(); + } + + @Override + public int compare(int v1, int v2) { + m_xy.read(2 * v1, pt1_helper); + m_xy.read(2 * v2, pt2_helper); + return pt1_helper.compare(pt2_helper); + } + } + + MultiPathImplBoundarySorter(AttributeStreamOfDbl xy) { + m_xy = xy; + } + + @Override + public void userSort(int begin, int end, AttributeStreamOfInt32 indices) { + indices.Sort(begin, end, new CompareIndices(m_xy)); + } + + @Override + public double getValue(int index) { + return m_xy.read(2 * index + 1); + } + } + + static MultiPoint calculatePolylineBoundary_(Object impl, + ProgressTracker progress_tracker, + boolean only_check_non_empty_boundary, boolean[] not_empty) { + if (not_empty != null) + not_empty[0] = false; + MultiPathImpl mpImpl = (MultiPathImpl) impl; + MultiPoint dst = null; + if (!only_check_non_empty_boundary) + dst = new MultiPoint(mpImpl.getDescription()); + + if (!mpImpl.isEmpty()) { + AttributeStreamOfInt32 indices = new AttributeStreamOfInt32(0); + indices.reserve(mpImpl.getPathCount() * 2); + for (int ipath = 0, nPathCount = mpImpl.getPathCount(); ipath < nPathCount; ipath++) { + int path_size = mpImpl.getPathSize(ipath); + if (path_size > 0 && !mpImpl.isClosedPathInXYPlane(ipath))// closed + // paths + // of + // polyline + // do + // not + // contribute + // to + // the + // boundary. + { + int start = mpImpl.getPathStart(ipath); + indices.add(start); + int end = mpImpl.getPathEnd(ipath) - 1; + indices.add(end); + } + } + if (indices.size() > 0) { + BucketSort sorter = new BucketSort(); + AttributeStreamOfDbl xy = (AttributeStreamOfDbl) (mpImpl + .getAttributeStreamRef(VertexDescription.Semantics.POSITION)); + sorter.sort(indices, 0, indices.size(), + new MultiPathImplBoundarySorter(xy)); + Point2D ptPrev = new Point2D(); + xy.read(2 * indices.get(0), ptPrev); + int ind = 0; + int counter = 1; + Point point = new Point(); + Point2D pt = new Point2D(); + for (int i = 1, n = indices.size(); i < n; i++) { + xy.read(2 * indices.get(i), pt); + if (pt.isEqual(ptPrev)) { + if (indices.get(ind) > indices.get(i)) { + // remove duplicate point + indices.set(ind, NumberUtils.intMax()); + ind = i;// just for the heck of it, have the first + // point in the order to be added to the + // boundary. + } else + indices.set(i, NumberUtils.intMax()); + + counter++; + } else { + if ((counter & 1) == 0) {// remove boundary point + indices.set(ind, NumberUtils.intMax()); + } else { + if (only_check_non_empty_boundary) { + if (not_empty != null) + not_empty[0] = true; + return null; + } + } + + ptPrev.setCoords(pt); + ind = i; + counter = 1; + } + } + + if ((counter & 1) == 0) {// remove the point + indices.set(ind, NumberUtils.intMax()); + } else { + if (only_check_non_empty_boundary) { + if (not_empty != null) + not_empty[0] = true; + return null; + } + } + if (!only_check_non_empty_boundary) { + indices.sort(0, indices.size()); + + for (int i = 0, n = indices.size(); i < n; i++) { + if (indices.get(i) == NumberUtils.intMax()) + break; + + mpImpl.getPointByVal(indices.get(i), point); + dst.add(point); + } + } + } + } + + if (only_check_non_empty_boundary) + return null; + + return dst; + } } diff --git a/src/main/java/com/esri/core/geometry/BucketSort.java b/src/main/java/com/esri/core/geometry/BucketSort.java index 17fadefe..94ced6df 100644 --- a/src/main/java/com/esri/core/geometry/BucketSort.java +++ b/src/main/java/com/esri/core/geometry/BucketSort.java @@ -24,155 +24,155 @@ package com.esri.core.geometry; final class BucketSort { - AttributeStreamOfInt32 m_buckets; - AttributeStreamOfInt32 m_bucketed_indices; - double m_min_value; - double m_max_value; - double m_dy; - - static int MAXBUCKETS = 65536; - - public BucketSort() { - m_buckets = new AttributeStreamOfInt32(0); - m_bucketed_indices = new AttributeStreamOfInt32(0); - m_min_value = 1; - m_max_value = -1; - m_dy = NumberUtils.TheNaN; - } - - /** - * Executes sort on the Bucket_sort. The result is fed into the indices - * array in the range between begin (inclusive) and end (exclusive). Uses - * user supplied sorter to execute sort on each bucket. Users either supply - * the sorter and use this method of Bucket_sort class, or use other methods - * to form the buckets and take care of bucket sorting themselves. - */ - public void sort(AttributeStreamOfInt32 indices, int begin, int end, - ClassicSort sorter) { - if (end - begin < 32) { - sorter.userSort(begin, end, indices); - return; - } - boolean b_fallback = true; - try { - double miny = NumberUtils.positiveInf(); - double maxy = NumberUtils.negativeInf(); - for (int i = begin; i < end; i++) { - double y = sorter.getValue(indices.get(i)); - if (y < miny) - miny = y; - if (y > maxy) - maxy = y; - } - - if (reset(end - begin, miny, maxy, end - begin)) { - for (int i = begin; i < end; i++) { - int vertex = indices.get(i); - double y = sorter.getValue(vertex); - int bucket = getBucket(y); - m_buckets.set(bucket, m_buckets.get(bucket) + 1);// counting - // values - // in a - // bucket. - m_bucketed_indices.write(i - begin, vertex); - } - - // Recalculate buckets to contain start positions of buckets. - int c = m_buckets.get(0); - m_buckets.set(0, 0); - for (int i = 1, n = m_buckets.size(); i < n; i++) { - int b = m_buckets.get(i); - m_buckets.set(i, c); - c += b; - } - - for (int i = begin; i < end; i++) { - int vertex = m_bucketed_indices.read(i - begin); - double y = sorter.getValue(vertex); - int bucket = getBucket(y); - int bucket_index = m_buckets.get(bucket); - indices.set(bucket_index + begin, vertex); - m_buckets.set(bucket, bucket_index + 1); - } - - b_fallback = false; - } - } catch (Exception e) { - m_buckets.resize(0); - m_bucketed_indices.resize(0); - } - - if (b_fallback) { - sorter.userSort(begin, end, indices); - return; - } - - int j = 0; - for (int i = 0, n = m_buckets.size(); i < n; i++) { - int j0 = j; - j = m_buckets.get(i); - if (j > j0) - sorter.userSort(begin + j0, begin + j, indices); - } - assert (j == end); - - if (getBucketCount() > 100) // some heuristics to preserve memory - { - m_buckets.resize(0); - m_bucketed_indices.resize(0); - } - } - - /** - * Clears and resets Bucket_sort to the new state, preparing for the - * accumulation of new data. - * - * @param bucket_count - the number of buckets. Usually equal to the number of - * elements to sort. - * @param min_value - the minimum value of elements to sort. - * @param max_value - the maximum value of elements to sort. - * @param capacity - the number of elements to sort (-1 if not known). The - * bucket_count are usually equal. - * @return Returns False, if the bucket sort cannot be used with the given - * parameters. The method also can throw out of memory exception. In - * the later case, one should fall back to the regular sort. - */ - private boolean reset(int bucket_count, double min_value, double max_value, - int capacity) { - if (bucket_count < 2 || max_value == min_value) - return false; - - int bc = Math.min(MAXBUCKETS, bucket_count); - m_buckets.reserve(bc); - m_buckets.resize(bc); - m_buckets.setRange(0, 0, m_buckets.size()); - m_min_value = min_value; - m_max_value = max_value; - m_bucketed_indices.resize(capacity); - - m_dy = (max_value - min_value) / (bc - 1); - return true; - } - - /** - * Adds new element to the bucket builder. The value must be between - * min_value and max_value. - * - * @param The value used for bucketing. - * @param The index of the element to store in the buffer. Usually it is an - * index into some array, where the real elements are stored. - */ - private int getBucket(double value) { - assert (value >= m_min_value && value <= m_max_value); - int bucket = (int) ((value - m_min_value) / m_dy); - return bucket; - } - - /** - * Returns the bucket count. - */ - private int getBucketCount() { - return m_buckets.size(); - } + AttributeStreamOfInt32 m_buckets; + AttributeStreamOfInt32 m_bucketed_indices; + double m_min_value; + double m_max_value; + double m_dy; + + static int MAXBUCKETS = 65536; + + public BucketSort() { + m_buckets = new AttributeStreamOfInt32(0); + m_bucketed_indices = new AttributeStreamOfInt32(0); + m_min_value = 1; + m_max_value = -1; + m_dy = NumberUtils.TheNaN; + } + + /** + * Executes sort on the Bucket_sort. The result is fed into the indices + * array in the range between begin (inclusive) and end (exclusive). Uses + * user supplied sorter to execute sort on each bucket. Users either supply + * the sorter and use this method of Bucket_sort class, or use other methods + * to form the buckets and take care of bucket sorting themselves. + */ + public void sort(AttributeStreamOfInt32 indices, int begin, int end, + ClassicSort sorter) { + if (end - begin < 32) { + sorter.userSort(begin, end, indices); + return; + } + boolean b_fallback = true; + try { + double miny = NumberUtils.positiveInf(); + double maxy = NumberUtils.negativeInf(); + for (int i = begin; i < end; i++) { + double y = sorter.getValue(indices.get(i)); + if (y < miny) + miny = y; + if (y > maxy) + maxy = y; + } + + if (reset(end - begin, miny, maxy, end - begin)) { + for (int i = begin; i < end; i++) { + int vertex = indices.get(i); + double y = sorter.getValue(vertex); + int bucket = getBucket(y); + m_buckets.set(bucket, m_buckets.get(bucket) + 1);// counting + // values + // in a + // bucket. + m_bucketed_indices.write(i - begin, vertex); + } + + // Recalculate buckets to contain start positions of buckets. + int c = m_buckets.get(0); + m_buckets.set(0, 0); + for (int i = 1, n = m_buckets.size(); i < n; i++) { + int b = m_buckets.get(i); + m_buckets.set(i, c); + c += b; + } + + for (int i = begin; i < end; i++) { + int vertex = m_bucketed_indices.read(i - begin); + double y = sorter.getValue(vertex); + int bucket = getBucket(y); + int bucket_index = m_buckets.get(bucket); + indices.set(bucket_index + begin, vertex); + m_buckets.set(bucket, bucket_index + 1); + } + + b_fallback = false; + } + } catch (Exception e) { + m_buckets.resize(0); + m_bucketed_indices.resize(0); + } + + if (b_fallback) { + sorter.userSort(begin, end, indices); + return; + } + + int j = 0; + for (int i = 0, n = m_buckets.size(); i < n; i++) { + int j0 = j; + j = m_buckets.get(i); + if (j > j0) + sorter.userSort(begin + j0, begin + j, indices); + } + assert (j == end); + + if (getBucketCount() > 100) // some heuristics to preserve memory + { + m_buckets.resize(0); + m_bucketed_indices.resize(0); + } + } + + /** + * Clears and resets Bucket_sort to the new state, preparing for the + * accumulation of new data. + * + * @param bucket_count - the number of buckets. Usually equal to the number of + * elements to sort. + * @param min_value - the minimum value of elements to sort. + * @param max_value - the maximum value of elements to sort. + * @param capacity - the number of elements to sort (-1 if not known). The + * bucket_count are usually equal. + * @return Returns False, if the bucket sort cannot be used with the given + * parameters. The method also can throw out of memory exception. In + * the later case, one should fall back to the regular sort. + */ + private boolean reset(int bucket_count, double min_value, double max_value, + int capacity) { + if (bucket_count < 2 || max_value == min_value) + return false; + + int bc = Math.min(MAXBUCKETS, bucket_count); + m_buckets.reserve(bc); + m_buckets.resize(bc); + m_buckets.setRange(0, 0, m_buckets.size()); + m_min_value = min_value; + m_max_value = max_value; + m_bucketed_indices.resize(capacity); + + m_dy = (max_value - min_value) / (bc - 1); + return true; + } + + /** + * Adds new element to the bucket builder. The value must be between + * min_value and max_value. + * + * @param The value used for bucketing. + * @param The index of the element to store in the buffer. Usually it is an + * index into some array, where the real elements are stored. + */ + private int getBucket(double value) { + assert (value >= m_min_value && value <= m_max_value); + int bucket = (int) ((value - m_min_value) / m_dy); + return bucket; + } + + /** + * Returns the bucket count. + */ + private int getBucketCount() { + return m_buckets.size(); + } } diff --git a/src/main/java/com/esri/core/geometry/Bufferer.java b/src/main/java/com/esri/core/geometry/Bufferer.java index 535b93e4..c21b2887 100755 --- a/src/main/java/com/esri/core/geometry/Bufferer.java +++ b/src/main/java/com/esri/core/geometry/Bufferer.java @@ -27,1908 +27,1920 @@ import java.util.List; class Bufferer { - Bufferer() { - m_buffer_commands = new ArrayList(128); - m_progress_tracker = null; - m_tolerance = 0; - m_small_tolerance = 0; - m_filter_tolerance = 0; - m_distance = 0; - m_original_geom_type = Geometry.GeometryType.Unknown; - m_abs_distance_reversed = 0; - m_abs_distance = 0; - m_densify_dist = -1; - m_dA = -1; - m_b_output_loops = true; - m_bfilter = true; - m_old_circle_template_size = 0; - } - - - /** - * Result is always a polygon. For non positive distance and non-areas - * returns an empty polygon. For points returns circles. - */ - Geometry buffer(Geometry geometry, double distance, - SpatialReference sr, double densify_dist, - int max_vertex_in_complete_circle, ProgressTracker progress_tracker) { - if (geometry == null) - throw new IllegalArgumentException(); - - if (densify_dist < 0) - throw new IllegalArgumentException(); - - if (geometry.isEmpty()) - return new Polygon(geometry.getDescription()); - - Envelope2D env2D = new Envelope2D(); - geometry.queryLooseEnvelope2D(env2D); - if (distance > 0) - env2D.inflate(distance, distance); - - m_progress_tracker = progress_tracker; - - m_original_geom_type = geometry.getType().value(); - m_geometry = geometry; - m_tolerance = InternalUtils.calculateToleranceFromGeometry(sr, - env2D, true);// conservative to have same effect as simplify - m_small_tolerance = InternalUtils - .calculateToleranceFromGeometry(null, env2D, true);// conservative - // to have - // same - // effect as - // simplify - - if (max_vertex_in_complete_circle <= 0) { - max_vertex_in_complete_circle = 96;// 96 is the value used by SG. - // This is the number of - // vertices in the full circle. - } - - m_spatialReference = sr; - m_distance = distance; - m_abs_distance = Math.abs(m_distance); - m_abs_distance_reversed = m_abs_distance != 0 ? 1.0 / m_abs_distance - : 0; - - if (NumberUtils.isNaN(densify_dist) || densify_dist == 0) { - densify_dist = m_abs_distance * 1e-5; - } else { - if (densify_dist > m_abs_distance * 0.5) - densify_dist = m_abs_distance * 0.5;// do not allow too - // large densify - // distance (the - // value will be - // adjusted - // anyway later) - } - - if (max_vertex_in_complete_circle < 12) - max_vertex_in_complete_circle = 12; - - - double max_dd = Math.abs(distance) - * (1 - Math.cos(Math.PI / max_vertex_in_complete_circle)); - - if (max_dd > densify_dist) - densify_dist = max_dd;// the densify distance has to agree with the - // max_vertex_in_complete_circle - else { - double vertex_count = Math.PI / Math.acos(1.0 - densify_dist / Math.abs(distance)); - if (vertex_count < (double) max_vertex_in_complete_circle - 1.0) { - max_vertex_in_complete_circle = (int) vertex_count; - if (max_vertex_in_complete_circle < 12) { - max_vertex_in_complete_circle = 12; - densify_dist = Math.abs(distance) * (1 - Math.cos(Math.PI / max_vertex_in_complete_circle)); - } - } - } - - m_densify_dist = densify_dist; - m_max_vertex_in_complete_circle = max_vertex_in_complete_circle; - // when filtering close points we do not want the filter to distort - // generated buffer too much. - m_filter_tolerance = Math.min(m_small_tolerance, - densify_dist * 0.25); - - - m_circle_template_size = calcN_(); - if (m_circle_template_size != m_old_circle_template_size) { - // we have an optimization for this method to be called several - // times. Here we detected too many changes and need to regenerate - // the data. - m_circle_template.clear(); - m_old_circle_template_size = m_circle_template_size; - } - - Geometry result_geom = buffer_(); - m_geometry = null; - return result_geom; - } - - private Geometry m_geometry; - - private static final class BufferCommand { - private interface Flags { - static final int enum_line = 1; - static final int enum_arc = 2; - static final int enum_connection = enum_arc | enum_line; - } - - private Point2D m_from; - private Point2D m_to; - private Point2D m_center; - private int m_next; - private int m_prev; - private int m_type; - - private BufferCommand(Point2D from, Point2D to, Point2D center, - int type, int next, int prev) { - m_from = new Point2D(); - m_to = new Point2D(); - m_center = new Point2D(); - m_from.setCoords(from); - m_to.setCoords(to); - m_center.setCoords(center); - m_type = type; - m_next = next; - m_prev = prev; - } - - private BufferCommand(Point2D from, Point2D to, int next, int prev, - String dummy) { - m_from = new Point2D(); - m_to = new Point2D(); - m_center = new Point2D(); - m_from.setCoords(from); - m_to.setCoords(to); - m_center.setNaN(); - m_type = 4; - m_next = next; - m_prev = prev; - } - } - - private ArrayList m_buffer_commands; - - private int m_original_geom_type; - private ProgressTracker m_progress_tracker; - private int m_max_vertex_in_complete_circle; - private SpatialReference m_spatialReference; - private double m_tolerance; - private double m_small_tolerance; - private double m_filter_tolerance; - private double m_densify_dist; - private double m_distance; - private double m_abs_distance; - private double m_abs_distance_reversed; - private double m_dA; - private boolean m_b_output_loops; - private boolean m_bfilter; - private ArrayList m_circle_template = new ArrayList(0); - private ArrayList m_left_stack; - private ArrayList m_middle_stack; - private Line m_helper_line_1; - private Line m_helper_line_2; - private Point2D[] m_helper_array; - private int m_progress_counter; - private int m_circle_template_size; - private int m_old_circle_template_size; - - private void generateCircleTemplate_() { - if (!m_circle_template.isEmpty()) { - return; - } - - int N = m_circle_template_size; - - assert (N >= 4); - int real_size = (N + 3) / 4; - double dA = (Math.PI * 0.5) / real_size; - m_dA = dA; - - for (int i = 0; i < real_size * 4; i++) - m_circle_template.add(null); - - double dcos = Math.cos(dA); - double dsin = Math.sin(dA); - Point2D pt = new Point2D(0.0, 1.0); - - for (int i = 0; i < real_size; i++) { - m_circle_template.set(i + real_size * 0, new Point2D(pt.y, -pt.x)); - m_circle_template.set(i + real_size * 1, new Point2D(-pt.x, -pt.y)); - m_circle_template.set(i + real_size * 2, new Point2D(-pt.y, pt.x)); - m_circle_template.set(i + real_size * 3, pt); - pt = new Point2D(pt.x, pt.y); - pt.rotateReverse(dcos, dsin); - } - // the template is filled with the index 0 corresponding to the point - // (0, 0), following clockwise direction (0, -1), (-1, 0), (1, 0) - } - - private static final class GeometryCursorForMultiPoint extends GeometryCursor { - private Bufferer m_parent; - private int m_index; - private Geometry m_buffered_polygon; - private MultiPoint m_mp; - private SpatialReference m_spatialReference; - private double m_distance; - private double m_densify_dist; - private double m_x; - private double m_y; - private int m_max_vertex_in_complete_circle; - private ProgressTracker m_progress_tracker; - - GeometryCursorForMultiPoint(Bufferer parent, MultiPoint mp, double distance, - SpatialReference sr, double densify_dist, - int max_vertex_in_complete_circle, - ProgressTracker progress_tracker) { - m_parent = parent; - m_index = 0; - m_mp = mp; - m_x = 0; - m_y = 0; - m_distance = distance; - m_spatialReference = sr; - m_densify_dist = densify_dist; - m_max_vertex_in_complete_circle = max_vertex_in_complete_circle; - m_progress_tracker = progress_tracker; - } - - @Override - public Geometry next() { - Point point = new Point(); - while (true) { - if (m_index == m_mp.getPointCount()) - return null; - - m_mp.getPointByVal(m_index, point); - m_index++; - if (point.isEmpty()) - continue; - break; - } - - boolean b_first = false; - if (m_buffered_polygon == null) { - m_x = point.getX(); - m_y = point.getY(); - - m_buffered_polygon = m_parent.buffer(point, m_distance, - m_spatialReference, m_densify_dist, - m_max_vertex_in_complete_circle, m_progress_tracker); - b_first = true; - } - - Geometry res; - if (m_index < m_mp.getPointCount()) { - res = new Polygon(); - m_buffered_polygon.copyTo(res); - } else { - res = m_buffered_polygon; // do not clone the last geometry. - } - - if (!b_first)// don't apply transformation unnecessary - { - Transformation2D transform = new Transformation2D(); - double dx = point.getX() - m_x; - double dy = point.getY() - m_y; - transform.setShift(dx, dy); - res.applyTransformation(transform); - } - - return res; - } - - @Override - // TODO unclear how this might work - public boolean hasNext() { return m_mp.getPointCount() > m_index; } - - @Override - public long getGeometryID() { - return 0; - } - } - - private static final class GlueingCursorForPolyline extends GeometryCursor { - private Polyline m_polyline; - private int m_current_path_index; - - GlueingCursorForPolyline(Polyline polyline) { - m_polyline = polyline; - m_current_path_index = 0; - } - - @Override - public Geometry next() { - if (m_polyline == null) - return null; - - MultiPathImpl mp = (MultiPathImpl) m_polyline._getImpl(); - int npaths = mp.getPathCount(); - if (m_current_path_index < npaths) { - int ind = m_current_path_index; - m_current_path_index++; - if (!mp.isClosedPathInXYPlane(ind)) { - // connect paths that follow one another as an optimization - // for buffering (helps when one polyline is split into many - // segments). - Point2D prev_end = mp.getXY(mp.getPathEnd(ind) - 1); - while (m_current_path_index < mp.getPathCount()) { - Point2D start = mp.getXY(mp - .getPathStart(m_current_path_index)); - if (mp.isClosedPathInXYPlane(m_current_path_index)) - break; - if (start != prev_end) - break; - - prev_end = mp - .getXY(mp.getPathEnd(m_current_path_index) - 1); - m_current_path_index++; - } - } - - if (ind == 0 - && m_current_path_index == m_polyline.getPathCount()) { - Polyline pol = m_polyline; - m_polyline = null; - return pol; - } - - Polyline tmp_polyline = new Polyline( - m_polyline.getDescription()); - tmp_polyline.addPath(m_polyline, ind, true); - for (int i = ind + 1; i < m_current_path_index; i++) { - tmp_polyline.addSegmentsFromPath(m_polyline, i, 0, - mp.getSegmentCount(i), false); - } - - if (false) { - OperatorFactoryLocal.saveGeometryToEsriShapeDbg( - "c:/temp/_geom.bin", tmp_polyline); - } - - if (m_current_path_index == m_polyline.getPathCount()) - m_polyline = null; - - return tmp_polyline; - } else { - return null; - } - } - - @Override - public boolean hasNext() { - return m_polyline != null && m_current_path_index < ((MultiPathImpl)m_polyline._getImpl()).getPathCount(); - } - - @Override - public long getGeometryID() { - return 0; - } - } - - private static final class GeometryCursorForPolyline extends GeometryCursor { - private Bufferer m_bufferer; - GeometryCursor m_geoms; - Geometry m_geometry; - private int m_index; - private boolean m_bfilter; - - GeometryCursorForPolyline(Bufferer bufferer, GeometryCursor geoms, - boolean bfilter) { - m_bufferer = bufferer; - m_geoms = geoms; - m_index = 0; - m_bfilter = bfilter; - } - - @Override - public Geometry next() { - if (m_geometry == null) { - m_index = 0; - m_geometry = m_geoms.next(); - if (m_geometry == null) - return null; - } - - MultiPath mp = (MultiPath) (m_geometry); - if (m_index < mp.getPathCount()) { - int ind = m_index; - m_index++; - return m_bufferer.bufferPolylinePath_((Polyline) m_geometry, - ind, m_bfilter); - } - - m_geometry = null; - return next(); - } - - @Override - public boolean hasNext() { - return (m_geoms != null && m_geoms.hasNext()) || (m_geometry != null && m_index < ((MultiPath)m_geometry).getPathCount()); - } - - @Override - public long getGeometryID() { - return 0; - } - } - - private static final class GeometryCursorForPolygon extends GeometryCursor { - private Bufferer m_bufferer; - private int m_index; - - GeometryCursorForPolygon(Bufferer bufferer) { - m_bufferer = bufferer; - m_index = 0; - } - - @Override - public Geometry next() { - Polygon input_polygon = (Polygon) (m_bufferer.m_geometry); - if (m_index < input_polygon.getPathCount()) { - int ind = m_index; - double area = input_polygon.calculateRingArea2D(m_index); - assert (area > 0); - m_index++; - while (m_index < input_polygon.getPathCount()) { - double hole_area = input_polygon - .calculateRingArea2D(m_index); - if (hole_area > 0) - break;// not a hole - m_index++; - } - - if (ind == 0 && m_index == input_polygon.getPathCount()) { - return m_bufferer.bufferPolygonImpl_(input_polygon, 0, - input_polygon.getPathCount()); - } else { - return m_bufferer.bufferPolygonImpl_(input_polygon, ind, - m_index); - } - } - - return null; - } - - @Override - public boolean hasNext() { - return m_index < ((Polygon)m_bufferer.m_geometry).getPathCount(); - } - - @Override - public long getGeometryID() { - return 0; - } - } - - private Geometry buffer_() { - int gt = m_geometry.getType().value(); - if (Geometry.isSegment(gt)) {// convert segment to a polyline and repeat - // the call - Polyline polyline = new Polyline(m_geometry.getDescription()); - polyline.addSegment((Segment) (m_geometry), true); - m_geometry = polyline; - return buffer_(); - } - - if (m_distance <= m_tolerance) { - if (Geometry.isArea(gt)) { - if (m_distance <= 0) { - // if the geometry is area type, then the negative distance - // may produce a degenerate shape. Check for this and return - // empty geometry. - Envelope2D env = new Envelope2D(); - m_geometry.queryEnvelope2D(env); - if (env.getWidth() <= -m_distance * 2 - || env.getHeight() <= m_distance * 2) - return new Polygon(m_geometry.getDescription()); - } - } else { - return new Polygon(m_geometry.getDescription());// return an - // empty polygon - // for distance - // <= - // m_tolerance - // and any input - // other than - // polygon. - } - } - - // Operator_factory_local::SaveJSONToTextFileDbg("c:/temp/buffer_input.txt", - // *m_geometry, nullptr); - - // Complex cases: - switch (m_geometry.getType().value()) { - case Geometry.GeometryType.Point: - return bufferPoint_(); - case Geometry.GeometryType.MultiPoint: - return bufferMultiPoint_(); - case Geometry.GeometryType.Polyline: - return bufferPolyline_(); - case Geometry.GeometryType.Polygon: - return bufferPolygon_(); - case Geometry.GeometryType.Envelope: - return bufferEnvelope_(); - default: - throw GeometryException.GeometryInternalError(); - } - } - - private Geometry bufferPolyline_() { - if (isDegenerateGeometry_(m_geometry)) { - Point point = new Point(); - ((MultiVertexGeometry) m_geometry).getPointByVal(0, point); - Envelope2D env2D = new Envelope2D(); - m_geometry.queryEnvelope2D(env2D); - point.setXY(env2D.getCenter()); - return bufferPoint_(point); - } - - assert (m_distance > 0); - Polyline poly = (Polyline) m_geometry; - m_geometry = null; - - GeometryCursor glueing_cursor = new GlueingCursorForPolyline(poly);//glues paths together if they connect at one point - poly = null; - GeometryCursor generalized_paths = OperatorGeneralize.local().execute(glueing_cursor, m_densify_dist * 0.25, false, m_progress_tracker); - GeometryCursor simple_paths = OperatorSimplifyOGC.local().execute(generalized_paths, null, true, m_progress_tracker);//make a planar graph. - generalized_paths = null; - GeometryCursor path_buffering_cursor = new GeometryCursorForPolyline(this, simple_paths, m_bfilter); - simple_paths = null; - GeometryCursor union_cursor = OperatorUnion.local().execute(path_buffering_cursor, m_spatialReference, m_progress_tracker);//(int)Operator_union::Options::enum_disable_edge_dissolver - Geometry result = union_cursor.next(); - return result; - } - - private Geometry bufferPolygon_() { - if (m_distance == 0) - return m_geometry;// return input to the output. - - OperatorSimplify simplify = (OperatorSimplify) OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Simplify); - - generateCircleTemplate_(); - m_geometry = simplify.execute(m_geometry, null, false, - m_progress_tracker); - - if (m_distance < 0) { - Polygon poly = (Polygon) (m_geometry); - Polygon buffered_result = bufferPolygonImpl_(poly, 0, - poly.getPathCount()); - return simplify.execute(buffered_result, m_spatialReference, false, - m_progress_tracker); - } else { - if (isDegenerateGeometry_(m_geometry)) { - Point point = new Point(); - ((MultiVertexGeometry) m_geometry).getPointByVal(0, point); - Envelope2D env2D = new Envelope2D(); - m_geometry.queryEnvelope2D(env2D); - point.setXY(env2D.getCenter()); - return bufferPoint_(point); - } - - // For the positive distance we need to process polygon in the parts - // such that each exterior ring with holes is processed separatelly. - GeometryCursorForPolygon cursor = new GeometryCursorForPolygon(this); - GeometryCursor union_cursor = ((OperatorUnion) OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Union)).execute( - cursor, m_spatialReference, m_progress_tracker); - Geometry result = union_cursor.next(); - return result; - } - } - - private Polygon bufferPolygonImpl_(Polygon input_geom, int ipath_begin, - int ipath_end) { - MultiPath input_mp = (MultiPath) (input_geom); - MultiPathImpl mp_impl = (MultiPathImpl) (input_mp._getImpl()); - Polygon intermediate_polygon = new Polygon(input_geom.getDescription()); - for (int ipath = ipath_begin; ipath < ipath_end; ipath++) { - if (mp_impl.getPathSize(ipath) < 1) - continue; - - double path_area = mp_impl.calculateRingArea2D(ipath); - Envelope2D env2D = new Envelope2D(); - mp_impl.queryPathEnvelope2D(ipath, env2D); - - if (m_distance > 0) { - if (path_area > 0) { - if (isDegeneratePath_(mp_impl, ipath)) {// if a path is - // degenerate - // (almost a point), - // then we can draw - // a circle instead - // of it as a buffer - // and nobody would - // notice :) - Point point = new Point(); - mp_impl.getPointByVal(mp_impl.getPathStart(ipath), - point); - point.setXY(env2D.getCenter()); - addCircle_( - (MultiPathImpl) intermediate_polygon._getImpl(), - point); - } else { - Polyline result_polyline = new Polyline( - input_geom.getDescription()); - MultiPathImpl result_mp = (MultiPathImpl) result_polyline - ._getImpl(); - - // We often see convex hulls, buffering those is an - // extremely simple task. - boolean bConvex = ConvexHull.isPathConvex( - (Polygon) (m_geometry), ipath, - m_progress_tracker); - if (bConvex - || bufferClosedPath_(m_geometry, ipath, - result_mp, true, 1) == 2) { - Polygon buffered_path = bufferConvexPath_(input_mp, - ipath); - intermediate_polygon.add(buffered_path, false); - } else { - Polygon buffered_path = bufferCleanup_( - result_polyline, false); - intermediate_polygon.add(buffered_path, false); - } - } - } else { - if (env2D.getWidth() + m_tolerance <= 2 * m_abs_distance - || env2D.getHeight() + m_tolerance <= 2 * m_abs_distance) // skip - // parts - // that - // will - // dissapear - continue; - - Polyline result_polyline = new Polyline( - input_geom.getDescription()); - MultiPathImpl result_mp = (MultiPathImpl) result_polyline - ._getImpl(); - bufferClosedPath_(m_geometry, ipath, result_mp, true, 1); - if (!result_polyline.isEmpty()) { - Envelope2D env = new Envelope2D(); - env.setCoords(env2D); - env.inflate(m_abs_distance, m_abs_distance); - result_mp.addEnvelope(env, false); - Polygon buffered_path = bufferCleanup_(result_polyline, - false); - // intermediate_polygon.reserve(intermediate_polygon.getPointCount() - // + buffered_path.getPointCount() - 4); - for (int i = 1, n = buffered_path.getPathCount(); i < n; i++) - intermediate_polygon - .addPath(buffered_path, i, true); - } - } - } else { - if (path_area > 0) { - if (env2D.getWidth() + m_tolerance <= 2 * m_abs_distance - || env2D.getHeight() + m_tolerance <= 2 * m_abs_distance) // skip - // parts - // that - // will - // dissapear - continue; - - Polyline result_polyline = new Polyline( - input_geom.getDescription()); - MultiPathImpl result_mp = (MultiPathImpl) result_polyline - ._getImpl(); - bufferClosedPath_(m_geometry, ipath, result_mp, true, -1);// this - // will - // provide - // a - // shape - // buffered - // inwards. - // It - // has - // counterclockwise - // orientation - if (!result_polyline.isEmpty()) { - Envelope2D env = new Envelope2D(); - result_mp.queryLooseEnvelope2D(env); - env.inflate(m_abs_distance, m_abs_distance); - result_mp.addEnvelope(env, false);// add an envelope - // exterior shell - Polygon buffered_path = bufferCleanup_(result_polyline, - false);// simplify with winding rule - // extract all parts but the first one (which is the - // envelope we added previously) - for (int i = 1, npaths = buffered_path.getPathCount(); i < npaths; i++) { - // the extracted parts have inverted orientation. - intermediate_polygon - .addPath(buffered_path, i, true); - } - } else { - // the path has been erased - } - } else { - // When buffering a hole with negative distance, buffer it - // as if it is an exterior ring buffered with positive - // distance - Polyline result_polyline = new Polyline( - input_geom.getDescription()); - MultiPathImpl result_mp = (MultiPathImpl) result_polyline - ._getImpl(); - bufferClosedPath_(m_geometry, ipath, result_mp, true, -1);// this - // will - // provide - // a - // shape - // buffered - // inwards. - Polygon buffered_path = bufferCleanup_(result_polyline, - false); - for (int i = 0, npaths = buffered_path.getPathCount(); i < npaths; i++) { - intermediate_polygon.addPath(buffered_path, i, true);// adds - // buffered - // hole - // reversed - // as - // if - // it - // is - // exteror - // ring - } - } - - // intermediate_polygon has inverted orientation. - } - } - - if (m_distance > 0) { - if (intermediate_polygon.getPathCount() > 1) { - Polygon cleaned_polygon = bufferCleanup_(intermediate_polygon, - false); - return cleaned_polygon; - } else { - return setWeakSimple_(intermediate_polygon); - } - } else { - Envelope2D polyenv = new Envelope2D(); - intermediate_polygon.queryLooseEnvelope2D(polyenv); - if (!intermediate_polygon.isEmpty()) { - // negative buffer distance. We got buffered holes and exterior - // rings. They all have wrong orientation. - // we need to apply winding simplify again to ensure all holes - // are unioned. - // For that create a big envelope and add all rings of the - // intermediate_polygon to it. - polyenv.inflate(m_abs_distance, m_abs_distance); - intermediate_polygon.addEnvelope(polyenv, false); - Polygon cleaned_polygon = bufferCleanup_(intermediate_polygon, - false); - // intermediate_polygon.reset();//free memory - - Polygon result_polygon = new Polygon( - cleaned_polygon.getDescription()); - for (int i = 1, n = cleaned_polygon.getPathCount(); i < n; i++) { - result_polygon.addPath(cleaned_polygon, i, false); - } - return setWeakSimple_(result_polygon); - } else { - return setWeakSimple_(intermediate_polygon); - } - } - } - - private Geometry bufferPoint_() { - return bufferPoint_((Point) (m_geometry)); - } - - private Geometry bufferPoint_(Point point) { - assert (m_distance > 0); - Polygon resultPolygon = new Polygon(point.getDescription()); - addCircle_((MultiPathImpl) resultPolygon._getImpl(), point); - return setStrongSimple_(resultPolygon); - } - - private Geometry bufferMultiPoint_() { - assert (m_distance > 0); - GeometryCursorForMultiPoint mpCursor = new GeometryCursorForMultiPoint(this, - (MultiPoint) (m_geometry), m_distance, m_spatialReference, - m_densify_dist, m_max_vertex_in_complete_circle, - m_progress_tracker); - GeometryCursor c = ((OperatorUnion) OperatorFactoryLocal.getInstance() - .getOperator(Operator.Type.Union)).execute(mpCursor, - m_spatialReference, m_progress_tracker); - return c.next(); - } - - private Geometry bufferEnvelope_() { - Polygon polygon = new Polygon(m_geometry.getDescription()); - if (m_distance <= 0) { - if (m_distance == 0) - polygon.addEnvelope((Envelope) (m_geometry), false); - else { - Envelope env = new Envelope(); - m_geometry.queryEnvelope(env); - env.inflate(m_distance, m_distance); - polygon.addEnvelope(env, false); - } - - return polygon;// nothing is easier than negative buffer on the - // envelope. - } - - polygon.addEnvelope((Envelope) (m_geometry), false); - m_geometry = polygon; - return bufferConvexPath_(polygon, 0); - } - - private Polygon bufferConvexPath_(MultiPath src, int ipath) { - generateCircleTemplate_(); - - Polygon resultPolygon = new Polygon(src.getDescription()); - MultiPathImpl result_mp = (MultiPathImpl) resultPolygon._getImpl(); - - // resultPolygon.reserve((m_circle_template.size() / 10 + 4) * - // src.getPathSize(ipath)); - - Point2D pt_1_tmp = new Point2D(), pt_1 = new Point2D(); - Point2D pt_2_tmp = new Point2D(), pt_2 = new Point2D(); - Point2D pt_3_tmp = new Point2D(), pt_3 = new Point2D(); - Point2D v_1 = new Point2D(); - Point2D v_2 = new Point2D(); - MultiPathImpl src_mp = (MultiPathImpl) src._getImpl(); - int path_size = src.getPathSize(ipath); - int path_start = src.getPathStart(ipath); - for (int i = 0, n = src.getPathSize(ipath); i < n; i++) { - src_mp.getXY(path_start + i, pt_1); - src_mp.getXY(path_start + (i + 1) % path_size, pt_2); - src_mp.getXY(path_start + (i + 2) % path_size, pt_3); - v_1.sub(pt_2, pt_1); - if (v_1.length() == 0) - throw GeometryException.GeometryInternalError(); - - v_1.leftPerpendicular(); - v_1.normalize(); - v_1.scale(m_abs_distance); - pt_1_tmp.add(v_1, pt_1); - pt_2_tmp.add(v_1, pt_2); - if (i == 0) - result_mp.startPath(pt_1_tmp); - else { - result_mp.lineTo(pt_1_tmp); - } - - result_mp.lineTo(pt_2_tmp); - - v_2.sub(pt_3, pt_2); - if (v_2.length() == 0) - throw GeometryException.GeometryInternalError(); - - v_2.leftPerpendicular(); - v_2.normalize(); - v_2.scale(m_abs_distance); - pt_3_tmp.add(v_2, pt_2); - - addJoin_(result_mp, pt_2, pt_2_tmp, pt_3_tmp, false, false); - } - - return setWeakSimple_(resultPolygon); - } - - private Polygon bufferPolylinePath_(Polyline polyline, int ipath, - boolean bfilter) { - assert (m_distance != 0); - generateCircleTemplate_(); - - MultiPath input_multi_path = polyline; - MultiPathImpl mp_impl = (MultiPathImpl) (input_multi_path._getImpl()); - - if (mp_impl.getPathSize(ipath) < 1) - return null; - - if (isDegeneratePath_(mp_impl, ipath) && m_distance > 0) {// if a path - // is - // degenerate - // (almost a - // point), - // then we - // can draw - // a circle - // instead - // of it as - // a buffer - // and - // nobody - // would - // notice :) - Point point = new Point(); - mp_impl.getPointByVal(mp_impl.getPathStart(ipath), point); - Envelope2D env2D = new Envelope2D(); - mp_impl.queryPathEnvelope2D(ipath, env2D); - point.setXY(env2D.getCenter()); - return (Polygon) (bufferPoint_(point)); - } - - Polyline result_polyline = new Polyline(polyline.getDescription()); - - MultiPathImpl result_mp = (MultiPathImpl) result_polyline._getImpl(); - boolean b_closed = mp_impl.isClosedPathInXYPlane(ipath); - - if (b_closed) { - bufferClosedPath_(input_multi_path, ipath, result_mp, bfilter, 1); - bufferClosedPath_(input_multi_path, ipath, result_mp, bfilter, -1); - } else { - Polyline tmpPoly = new Polyline(input_multi_path.getDescription()); - tmpPoly.addPath(input_multi_path, ipath, false); - ((MultiPathImpl) tmpPoly._getImpl()).addSegmentsFromPath( - (MultiPathImpl) input_multi_path._getImpl(), ipath, 0, - input_multi_path.getSegmentCount(ipath), false); - bufferClosedPath_(tmpPoly, 0, result_mp, bfilter, 1); - } - - return bufferCleanup_(result_polyline, false); - } - - private void progress_() { - m_progress_counter++; - if (m_progress_counter % 1024 == 0) { - if ((m_progress_tracker != null) - && !(m_progress_tracker.progress(-1, -1))) - throw new RuntimeException("user_canceled"); - } - } - - private Polygon bufferCleanup_(MultiPath multi_path, boolean simplify_result) { - double tol = simplify_result ? m_tolerance : m_small_tolerance; - Polygon resultPolygon = (Polygon) (TopologicalOperations - .planarSimplify(multi_path, tol, true, !simplify_result, - m_progress_tracker)); - assert (InternalUtils.isWeakSimple(resultPolygon, 0.0)); - return resultPolygon; - } - - private int calcN_() { - //this method should be called only once m_circle_template_size is set then; - final int minN = 4; - if (m_densify_dist == 0) - return m_max_vertex_in_complete_circle; - - double r = m_densify_dist * Math.abs(m_abs_distance_reversed); - double cos_a = 1 - r; - double N; - if (cos_a < -1) - N = minN; - else - N = 2.0 * Math.PI / Math.acos(cos_a) + 0.5; - - if (N < minN) - N = minN; - else if (N > m_max_vertex_in_complete_circle) - N = m_max_vertex_in_complete_circle; - - return (int) N; - } - - private void addJoin_(MultiPathImpl dst, Point2D center, Point2D fromPt, - Point2D toPt, boolean bStartPath, boolean bFinishAtToPt) { - generateCircleTemplate_(); - - Point2D v_1 = new Point2D(); - v_1.sub(fromPt, center); - v_1.scale(m_abs_distance_reversed); - Point2D v_2 = new Point2D(); - v_2.sub(toPt, center); - v_2.scale(m_abs_distance_reversed); - double angle_from = Math.atan2(v_1.y, v_1.x); - double dindex_from = angle_from / m_dA; - if (dindex_from < 0) - dindex_from = (double) m_circle_template.size() + dindex_from; - - dindex_from = (double) m_circle_template.size() - dindex_from; - - double angle_to = Math.atan2(v_2.y, v_2.x); - double dindex_to = angle_to / m_dA; - if (dindex_to < 0) - dindex_to = (double) m_circle_template.size() + dindex_to; - - dindex_to = (double) m_circle_template.size() - dindex_to; - - if (dindex_to < dindex_from) - dindex_to += (double) m_circle_template.size(); - assert (dindex_to >= dindex_from); - - int index_to = (int) dindex_to; - int index_from = (int) Math.ceil(dindex_from); - - if (bStartPath) { - dst.startPath(fromPt); - bStartPath = false; - } - - Point2D p = new Point2D(); - p.setCoords(m_circle_template.get(index_from % m_circle_template.size())); - p.scaleAdd(m_abs_distance, center); - double ddd = m_tolerance * 10; - p.sub(fromPt); - if (p.length() < ddd)// if too close to the fromPt, then use the next - // point - index_from += 1; - - p.setCoords(m_circle_template.get(index_to % m_circle_template.size())); - p.scaleAdd(m_abs_distance, center); - p.sub(toPt); - if (p.length() < ddd)// if too close to the toPt, then use the prev - // point - index_to -= 1; - - int count = index_to - index_from; - count++; - - for (int i = 0, j = index_from % m_circle_template.size(); i < count; i++, j = (j + 1) - % m_circle_template.size()) { - p.setCoords(m_circle_template.get(j)); - p.scaleAdd(m_abs_distance, center); - dst.lineTo(p); - progress_(); - } - - if (bFinishAtToPt) { - dst.lineTo(toPt); - } - } - - private int bufferClosedPath_(Geometry input_geom, int ipath, - MultiPathImpl result_mp, boolean bfilter, int dir) { - // Use temporary polyline for the path buffering. - EditShape edit_shape = new EditShape(); - int geom = edit_shape.addPathFromMultiPath((MultiPath) input_geom, - ipath, true); - edit_shape.filterClosePoints(m_filter_tolerance, false, false); - if (edit_shape.getPointCount(geom) < 2) {// Got degenerate output. - // Either bail out or - // produce a circle. - if (dir < 0) - return 1;// negative direction produces nothing. - - MultiPath mpIn = (MultiPath) input_geom; - // Add a circle - Point pt = new Point(); - mpIn.getPointByVal(mpIn.getPathStart(ipath), pt); - addCircle_(result_mp, pt); - return 1; - } - - assert (edit_shape.getFirstPath(geom) != -1); - assert (edit_shape.getFirstVertex(edit_shape.getFirstPath(geom)) != -1); - - Point2D origin = edit_shape.getXY(edit_shape.getFirstVertex(edit_shape - .getFirstPath(geom))); - Transformation2D tr = new Transformation2D(); - tr.setShift(-origin.x, -origin.y); - // move the path to origin for better accuracy in calculations. - edit_shape.applyTransformation(tr); - - if (bfilter) { - // try removing the noise that does not contribute to the buffer. - int res_filter = filterPath_(edit_shape, geom, dir, true, m_abs_distance, m_filter_tolerance, m_densify_dist); - assert (res_filter == 1); - // Operator_factory_local::SaveJSONToTextFileDbg("c:/temp/buffer_filter.txt", - // *edit_shape.get_geometry(geom), nullptr); - if (edit_shape.getPointCount(geom) < 2) {// got degenerate output. - // Wither bail out or - // produce a circle. - if (dir < 0) - return 1;// negative direction produces nothing. - - MultiPath mpIn = (MultiPath) input_geom; - // Add a circle - Point pt = new Point(); - mpIn.getPointByVal(mpIn.getPathStart(ipath), pt); - addCircle_(result_mp, pt); - return 1; - } - } - - m_buffer_commands.clear(); - int path = edit_shape.getFirstPath(geom); - int ivert = edit_shape.getFirstVertex(path); - int iprev = dir == 1 ? edit_shape.getPrevVertex(ivert) : edit_shape - .getNextVertex(ivert); - int inext = dir == 1 ? edit_shape.getNextVertex(ivert) : edit_shape - .getPrevVertex(ivert); - boolean b_first = true; - Point2D pt_current = new Point2D(), pt_after = new Point2D(), pt_before = new Point2D(), pt_left_prev = new Point2D(), pt = new Point2D(), pt1 = new Point2D(); - Point2D v_after = new Point2D(), v_before = new Point2D(), v_left = new Point2D(), v_left_prev = new Point2D(); - double abs_d = m_abs_distance; - int ncount = edit_shape.getPathSize(path); - - // write out buffer commands as a set of arcs and line segments. - // if we'd convert this directly to a polygon and draw using winding - // fill rule, we'd get the buffered result. - for (int index = 0; index < ncount; index++) { - edit_shape.getXY(inext, pt_after); - - if (b_first) { - edit_shape.getXY(ivert, pt_current); - edit_shape.getXY(iprev, pt_before); - v_before.sub(pt_current, pt_before); - v_before.normalize(); - v_left_prev.leftPerpendicular(v_before); - v_left_prev.scale(abs_d); - pt_left_prev.add(v_left_prev, pt_current); - } - - v_after.sub(pt_after, pt_current); - v_after.normalize(); - - v_left.leftPerpendicular(v_after); - v_left.scale(abs_d); - pt.add(pt_current, v_left); - double cross = v_before.crossProduct(v_after); - double dot = v_before.dotProduct(v_after); - boolean bDoJoin = cross < 0 || (dot < 0 && cross == 0); - if (bDoJoin) { - m_buffer_commands.add(new BufferCommand(pt_left_prev, pt, - pt_current, BufferCommand.Flags.enum_arc, - m_buffer_commands.size() + 1, - m_buffer_commands.size() - 1)); - } else if (!pt_left_prev.isEqual(pt)) { - m_buffer_commands.add(new BufferCommand(pt_left_prev, - pt_current, m_buffer_commands.size() + 1, - m_buffer_commands.size() - 1, "dummy")); - m_buffer_commands.add(new BufferCommand(pt_current, pt, - m_buffer_commands.size() + 1, - m_buffer_commands.size() - 1, "dummy")); - } - - pt1.add(pt_after, v_left); - m_buffer_commands - .add(new BufferCommand(pt, pt1, pt_current, - BufferCommand.Flags.enum_line, m_buffer_commands - .size() + 1, m_buffer_commands.size() - 1)); - - pt_left_prev.setCoords(pt1); - v_left_prev.setCoords(v_left); - pt_before.setCoords(pt_current); - pt_current.setCoords(pt_after); - v_before.setCoords(v_after); - iprev = ivert; - ivert = inext; - b_first = false; - inext = dir == 1 ? edit_shape.getNextVertex(ivert) : edit_shape - .getPrevVertex(ivert); - } - - m_buffer_commands.get(m_buffer_commands.size() - 1).m_next = 0; - m_buffer_commands.get(0).m_prev = m_buffer_commands.size() - 1; - processBufferCommands_(result_mp); - tr.setShift(origin.x, origin.y);// move the path to improve precision. - result_mp.applyTransformation(tr, result_mp.getPathCount() - 1); - return 1; - } - - private void processBufferCommands_(MultiPathImpl result_mp) { - int ifirst_seg = cleanupBufferCommands_(); - boolean first = true; - int iseg_next = ifirst_seg + 1; - for (int iseg = ifirst_seg; iseg_next != ifirst_seg; iseg = iseg_next) { - BufferCommand command = m_buffer_commands.get(iseg); - iseg_next = command.m_next != -1 ? command.m_next : (iseg + 1) - % m_buffer_commands.size(); - if (command.m_type == 0) - continue;// deleted segment - - if (first) { - result_mp.startPath(command.m_from); - first = false; - } - - if (command.m_type == BufferCommand.Flags.enum_arc) {// arc - addJoin_(result_mp, command.m_center, command.m_from, - command.m_to, false, true); - } else { - result_mp.lineTo(command.m_to); - } - first = false; - } - } - - private int cleanupBufferCommands_() { - // The purpose of this function is to remove as many self intersections - // from the buffered shape as possible. - // The buffer works without cleanup also, but slower. - - if (m_helper_array == null) - m_helper_array = new Point2D[9]; - - int istart = 0; - for (int iseg = 0, nseg = m_buffer_commands.size(); iseg < nseg; ) { - BufferCommand command = m_buffer_commands.get(iseg); - if ((command.m_type & BufferCommand.Flags.enum_connection) != 0) { - istart = iseg; - break; - } - - iseg = command.m_next; - } - - int iseg_next = istart + 1; - for (int iseg = istart; iseg_next != istart; iseg = iseg_next) { - BufferCommand command = m_buffer_commands.get(iseg); - iseg_next = command.m_next; - int count = 1; - BufferCommand command_next = null; - while (iseg_next != iseg) {// find next segement - command_next = m_buffer_commands.get(iseg_next); - if ((command_next.m_type & BufferCommand.Flags.enum_connection) != 0) - break; - - iseg_next = command_next.m_next; - count++; - } - - if (count == 1) { - // Next segment starts where this one ends. Skip this case as it - // is simple. - assert (command.m_to.isEqual(command_next.m_from)); - continue; - } - - if ((command.m_type & command_next.m_type) == BufferCommand.Flags.enum_line) {// simplest - // cleanup - // - - // intersect - // lines - if (m_helper_line_1 == null) { - m_helper_line_1 = new Line(); - m_helper_line_2 = new Line(); - } - m_helper_line_1.setStartXY(command.m_from); - m_helper_line_1.setEndXY(command.m_to); - m_helper_line_2.setStartXY(command_next.m_from); - m_helper_line_2.setEndXY(command_next.m_to); - - int count_ = m_helper_line_1.intersect(m_helper_line_2, - m_helper_array, null, null, m_small_tolerance); - if (count_ == 1) { - command.m_to.setCoords(m_helper_array[0]); - command_next.m_from.setCoords(m_helper_array[0]); - command.m_next = iseg_next;// skip until iseg_next - command_next.m_prev = iseg; - } else if (count_ == 2) {// TODO: this case needs improvement - } - } - } - - return istart; - } - - private static void protectExtremeVertices_(EditShape edit_shape, - int protection_index, int geom, int path) { - // detect very narrow corners and preserve them. We cannot reliably - // delete these. - int vprev = -1; - Point2D pt_prev = new Point2D(); - pt_prev.setNaN(); - Point2D pt = new Point2D(); - pt.setNaN(); - Point2D v_before = new Point2D(); - v_before.setNaN(); - Point2D pt_next = new Point2D(); - Point2D v_after = new Point2D(); - for (int i = 0, n = edit_shape.getPathSize(path), v = edit_shape - .getFirstVertex(path); i < n; ++i) { - if (vprev == -1) { - edit_shape.getXY(v, pt); - - vprev = edit_shape.getPrevVertex(v); - if (vprev != -1) { - edit_shape.getXY(vprev, pt_prev); - v_before.sub(pt, pt_prev); - v_before.normalize(); - } - } - - int vnext = edit_shape.getNextVertex(v); - if (vnext == -1) - break; - - edit_shape.getXY(vnext, pt_next); - v_after.sub(pt_next, pt); - v_after.normalize(); - - if (vprev != -1) { - double d = v_after.dotProduct(v_before); - if (d < -0.99 - && Math.abs(v_after.crossProduct(v_before)) < 1e-7) { - edit_shape.setUserIndex(v, protection_index, 1); - } - } - - vprev = v; - v = vnext; - pt_prev.setCoords(pt); - pt.setCoords(pt_next); - v_before.setCoords(v_after); - } - } - - static private int filterPath_(EditShape edit_shape, int geom, int dir, - boolean closed, double abs_distance, double filter_tolerance, - double densify_distance) { - int path = edit_shape.getFirstPath(geom); - - int concave_index = -1; - int fixed_vertices_index = edit_shape.createUserIndex(); - protectExtremeVertices_(edit_shape, fixed_vertices_index, geom, path); - - for (int iter = 0; iter < 100; ++iter) { - int isize = edit_shape.getPathSize(path); - if (isize == 0) { - edit_shape.removeUserIndex(fixed_vertices_index); - ; - return 1; - } - - int ivert = edit_shape.getFirstVertex(path); - int nvertices = edit_shape.getPathSize(path); - if (nvertices < 3) { - edit_shape.removeUserIndex(fixed_vertices_index); - ; - return 1; - } - - if (closed && !edit_shape.isClosedPath(path))// the path is closed - // only virtually - { - nvertices -= 1; - } - - double abs_d = abs_distance; - final int nfilter = 64; - boolean filtered = false; - int filtered_in_pass = 0; - boolean go_back = false; - for (int i = 0; i < nvertices && ivert != -1; i++) { - int filtered_now = 0; - int v = ivert; // filter == 0 - for (int filter = 1, n = (int) Math.min(nfilter, nvertices - i); filter < n; filter++) { - v = edit_shape.getNextVertex(v, dir); - if (filter > 1) { - int num = clipFilter_(edit_shape, - fixed_vertices_index, ivert, v, dir, - abs_distance, densify_distance, nfilter); - if (num == -1) - break; - - filtered |= num > 0; - filtered_now += num; - nvertices -= num; - } - } - - filtered_in_pass += filtered_now; - - go_back = filtered_now > 0; - - if (go_back) { - int prev = edit_shape.getPrevVertex(ivert, dir); - if (prev != -1) { - ivert = prev; - nvertices++; - continue; - } - } - - ivert = edit_shape.getNextVertex(ivert, dir); - } - - if (filtered_in_pass == 0) - break; - } - - edit_shape.removeUserIndex(fixed_vertices_index); - edit_shape.filterClosePoints(filter_tolerance, false, false); - - return 1; - } - - // This function clips out segments connecting from_vertiex to to_vertiex if - // they do not contribute to the buffer. - private static int clipFilter_(EditShape edit_shape, - int fixed_vertices_index, int from_vertex, int to_vertex, int dir, - double abs_distance, double densify_distance, final int max_filter) { - // Note: vertices marked with fixed_vertices_index cannot be deleted. - - Point2D pt1 = edit_shape.getXY(from_vertex); - Point2D pt2 = edit_shape.getXY(to_vertex); - if (pt1.equals(pt2)) - return -1; - - double densify_distance_delta = densify_distance * 0.25;// distance by - // which we can - // move the - // point closer - // to the chord - // (introducing - // an error into - // the buffer). - double erase_distance_delta = densify_distance * 0.25;// distance when - // we can erase - // the point - // (introducing - // an error into - // the buffer). - // This function goal is to modify or remove vertices between - // from_vertex and to_vertex in such a way that the result would not - // affect buffer to the left of the - // chain. - Point2D v_gap = new Point2D(); - v_gap.sub(pt2, pt1); - double gap_length = v_gap.length(); - double h2_4 = gap_length * gap_length * 0.25; - double sqr_center_to_chord = abs_distance * abs_distance - h2_4; // squared - // distance - // from - // the - // chord - // to - // the - // circle - // center - if (sqr_center_to_chord <= h2_4) - return -1;// center to chord distance is less than half gap, that - // means the gap is too wide for useful filtering (maybe - // this). - - double center_to_chord = Math.sqrt(sqr_center_to_chord); // distance - // from - // circle - // center to - // the - // chord. - - v_gap.normalize(); - Point2D v_gap_norm = new Point2D(v_gap); - v_gap_norm.rightPerpendicular(); - double chord_to_corner = h2_4 / center_to_chord; // cos(a) = - // center_to_chord / - // distance; - // chord_to_corner = - // distance / cos(a) - // - - // center_to_chord; - boolean can_erase_corner_point = chord_to_corner <= erase_distance_delta; - Point2D chord_midpoint = new Point2D(); - MathUtils.lerp(pt2, pt1, 0.5, chord_midpoint); - Point2D corner = new Point2D(v_gap_norm); - double corrected_chord_to_corner = chord_to_corner - - densify_distance_delta;// using slightly smaller than needed - // distance let us filter more. - corner.scaleAdd(Math.max(0.0, corrected_chord_to_corner), - chord_midpoint); - // corner = (p1 + p2) * 0.5 + v_gap_norm * chord_to_corner; - - Point2D center = new Point2D(v_gap_norm); - center.negate(); - center.scaleAdd(center_to_chord, chord_midpoint); - - double allowed_distance = abs_distance - erase_distance_delta; - double sqr_allowed_distance = MathUtils.sqr(allowed_distance); - double sqr_large_distance = sqr_allowed_distance * (1.9 * 1.9); - - Point2D co_p1 = new Point2D(); - co_p1.sub(corner, pt1); - Point2D co_p2 = new Point2D(); - co_p2.sub(corner, pt2); - - boolean large_distance = false;// set to true when distance - int cnt = 0; - char[] locations = new char[64]; - { - // check all vertices in the gap verifying that the gap can be - // clipped. - // - - Point2D pt = new Point2D(); - // firstly remove any duplicate vertices in the end. - for (int v = edit_shape.getPrevVertex(to_vertex, dir); v != from_vertex; ) { - if (edit_shape.getUserIndex(v, fixed_vertices_index) == 1) - return -1;// this range contains protected vertex - - edit_shape.getXY(v, pt); - if (pt.equals(pt2)) { - int v1 = edit_shape.getPrevVertex(v, dir); - edit_shape.removeVertex(v, false); - v = v1; - continue; - } else { - break; - } - } - - Point2D prev_prev_pt = new Point2D(); - prev_prev_pt.setNaN(); - Point2D prev_pt = new Point2D(); - prev_pt.setCoords(pt1); - locations[cnt++] = 1; - int prev_v = from_vertex; - Point2D dummyPt = new Point2D(); - for (int v = edit_shape.getNextVertex(from_vertex, dir); v != to_vertex; ) { - if (edit_shape.getUserIndex(v, fixed_vertices_index) == 1) - return -1;// this range contains protected vertex - - edit_shape.getXY(v, pt); - if (pt.equals(prev_pt)) { - int v1 = edit_shape.getNextVertex(v, dir); - edit_shape.removeVertex(v, false); - v = v1; - continue; - } - - locations[cnt++] = 0; - - Point2D v1 = new Point2D(); - v1.sub(pt, pt1); - if (v1.dotProduct(v_gap_norm) < 0)// we are crossing on the - // wrong site of the chord. - // Just bail out earlier. - // Maybe we could continue - // clipping though here, but - // it seems to be - // unnecessary complicated. - return 0; - - if (Point2D.sqrDistance(pt, pt1) > sqr_large_distance - || Point2D.sqrDistance(pt, pt2) > sqr_large_distance) - large_distance = true; // too far from points, may - // contribute to the outline (in - // case of a large loop) - - char next_location = 0; - - dummyPt.sub(pt, pt1); - double cs1 = dummyPt.crossProduct(co_p1); - if (cs1 >= 0) { - next_location = 1; - } - - dummyPt.sub(pt, pt2); - double cs2 = dummyPt.crossProduct(co_p2); - if (cs2 <= 0) { - next_location |= 2; - } - - if (next_location == 0) - return 0; - - locations[cnt - 1] = next_location; - prev_prev_pt.setCoords(prev_pt); - prev_pt.setCoords(pt); - prev_v = v; - v = edit_shape.getNextVertex(v, dir); - } - - if (cnt == 1) - return 0; - - assert (!pt2.equals(prev_pt)); - locations[cnt++] = 2; - } - - boolean can_clip_all = true; - // we can remove all points and replace them with a single corner point - // if we are moving from location 1 via location 3 to location 2 - for (int i = 1, k = 0; i < cnt; i++) { - if (locations[i] != locations[i - 1]) { - k++; - can_clip_all = k < 3 - && ((k == 1 && locations[i] == 3) || (k == 2 && locations[i] == 2)); - if (!can_clip_all) - return 0; - } - } - - if (cnt > 2 && can_clip_all && (cnt == 3 || !large_distance)) { - int clip_count = 0; - int v = edit_shape.getNextVertex(from_vertex, dir); - if (!can_erase_corner_point) { - edit_shape.setXY(v, corner); - v = edit_shape.getNextVertex(v, dir); - } - - // we can remove all vertices between from and to, because they - // don't contribute - while (v != to_vertex) { - int v1 = edit_shape.getNextVertex(v, dir); - edit_shape.removeVertex(v, false); - v = v1; - ++clip_count; - } - - return clip_count; - } - - if (cnt == 3) { - boolean case1 = (locations[0] == 1 && locations[1] == 2 && locations[2] == 2); - boolean case2 = (locations[0] == 1 && locations[1] == 1 && locations[2] == 2); - if (case1 || case2) { - // special case, when we cannot clip, but we can move the point - Point2D p1 = edit_shape.getXY(from_vertex); - int v = edit_shape.getNextVertex(from_vertex, dir); - Point2D p2 = edit_shape.getXY(v); - Point2D p3 = edit_shape.getXY(edit_shape.getNextVertex(v, dir)); - if (case2) { - Point2D temp = p1; - p1 = p3; - p3 = temp; - } - - Point2D vec = new Point2D(); - vec.sub(p1, p2); - p3.sub(p2); - double veclen = vec.length(); - double w = p3.length(); - double wcosa = vec.dotProduct(p3) / veclen; - double wsina = Math.abs(p3.crossProduct(vec) / veclen); - double z = 2 * abs_distance - wsina; - if (z < 0) - return 0; - - double x = wcosa + Math.sqrt(wsina * z); - if (x > veclen) - return 0; - - Point2D hvec = new Point2D(); - hvec.scaleAdd(-x / veclen, vec, p3); // hvec = p3 - vec * (x / - // veclen); - double h = hvec.length(); - double y = -(h * h * veclen) / (2 * hvec.dotProduct(vec)); - - double t = (x - y) / veclen; - MathUtils.lerp(p2, p1, t, p2); - edit_shape.setXY(v, p2); - return 0; - } - } - - if (large_distance && cnt > 3) { - // we are processing more than 3 points and there are some points - // further than the - return 0; - } - - int v_prev = -1; - Point2D pt_prev = new Point2D(); - int v_cur = from_vertex; - Point2D pt_cur = new Point2D(pt1); - int cur_location = 1; - int prev_location = -1; // 1 - semiplane to the right of [f,c]. 3 - - // semiplane to the right of [c,t], 2 - both - // above fc and ct, 0 - cannot clip, -1 - - // unknown - int v_next = v_cur; - int clip_count = 0; - cnt = 1; - while (v_next != to_vertex) { - v_next = edit_shape.getNextVertex(v_next, dir); - int next_location = locations[cnt++]; - if (next_location == 0) { - if (v_next == to_vertex) - break; - - continue; - } - - Point2D pt_next = edit_shape.getXY(v_next); - - if (prev_location != -1) { - int common_location = (prev_location & cur_location & next_location); - if ((common_location & 3) != 0) { - // prev and next are on the same semiplane as the current we - // can safely remove the current point. - edit_shape.removeVertex(v_cur, true); - clip_count++;// do not change prev point. - v_cur = v_next; - pt_cur.setCoords(pt_next); - cur_location = next_location; - continue; - } - - if (cur_location == 3 && prev_location != 0 - && next_location != 0) { - assert ((prev_location & next_location) == 0);// going from - // one semi - // plane to - // another - // via the - // mid. - pt_cur.setCoords(corner); - if (can_erase_corner_point || pt_cur.equals(pt_prev)) {// this - // point - // can - // be - // removed - edit_shape.removeVertex(v_cur, true); - clip_count++;// do not change prev point. - v_cur = v_next; - pt_cur.setCoords(pt_next); - cur_location = next_location; - continue; - } else { - edit_shape.setXY(v_cur, pt_cur); // snap to the corner - } - } else { - if (next_location == 0 - && cur_location != 0 - || next_location != 0 - && cur_location == 0 - || ((next_location | cur_location) == 3 - && next_location != 3 && cur_location != 3)) { - // clip - } - } - } - - prev_location = cur_location; - v_prev = v_cur; - pt_prev.setCoords(pt_cur); - v_cur = v_next; - cur_location = next_location; - pt_cur.setCoords(pt_next); - } - - return clip_count; - } - - private boolean isDegeneratePath_(MultiPathImpl mp_impl, int ipath) { - if (mp_impl.getPathSize(ipath) == 1) - return true; - Envelope2D env = new Envelope2D(); - mp_impl.queryPathEnvelope2D(ipath, env); - if (Math.max(env.getWidth(), env.getHeight()) < m_densify_dist * 0.5) - return true; - - return false; - } - - private boolean isDegenerateGeometry_(Geometry geom) { - Envelope2D env = new Envelope2D(); - geom.queryEnvelope2D(env); - if (Math.max(env.getWidth(), env.getHeight()) < m_densify_dist * 0.5) - return true; - - return false; - } - - private Polyline preparePolyline_(Polyline input_geom) { - // Generalize it firstly using 25% of the densification deviation as a - // criterion. - Polyline generalized_polyline = (Polyline) ((OperatorGeneralize) OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Generalize)).execute( - input_geom, m_densify_dist * 0.25, false, m_progress_tracker); - - int path_point_count = 0; - for (int i = 0, npath = generalized_polyline.getPathCount(); i < npath; i++) { - path_point_count = Math.max(generalized_polyline.getPathSize(i), - path_point_count); - } - - if (path_point_count < 32) { - m_bfilter = false; - return generalized_polyline; - } else { - m_bfilter = true; - // If we apply a filter to the polyline, then we have to resolve all - // self intersections. - Polyline simple_polyline = (Polyline) (TopologicalOperations - .planarSimplify(generalized_polyline, m_small_tolerance, - false, true, m_progress_tracker)); - // Operator_factory_local::SaveJSONToTextFileDbg("c:/temp/buffer_simplify.txt", - // *simple_polyline, nullptr); - return simple_polyline; - } - } - - private void addCircle_(MultiPathImpl result_mp, Point point) { - // Uses same calculations for each of the quadrants, generating a - // symmetric distribution of points. - Point2D center = point.getXY(); - if (m_circle_template != null && !m_circle_template.isEmpty()) {// use - // template - // if - // available. - Point2D p = new Point2D(); - p.setCoords(m_circle_template.get(0)); - p.scaleAdd(m_abs_distance, center); - result_mp.startPath(p); - for (int i = 1, n = (int) m_circle_template.size(); i < n; i++) { - p.setCoords(m_circle_template.get(i)); - p.scaleAdd(m_abs_distance, center); - result_mp.lineTo(p); - } - return; - } - - // avoid unnecessary memory allocation for the circle template. Just do - // the point here. - - int N = m_circle_template_size; - int real_size = (N + 3) / 4; - double dA = (Math.PI * 0.5) / real_size; - // result_mp.reserve(real_size * 4); - - double dcos = Math.cos(dA); - double dsin = Math.sin(dA); - Point2D pt = new Point2D(); - for (int quadrant = 3; quadrant >= 0; quadrant--) { - pt.setCoords(0.0, m_abs_distance); - switch (quadrant) { - case 0: {// upper left quadrant - for (int i = 0; i < real_size; i++) { - result_mp.lineTo(pt.x + center.x, pt.y + center.y); - pt.rotateReverse(dcos, dsin); - } - break; - } - case 1: {// upper left quadrant - for (int i = 0; i < real_size; i++) {// m_circle_template.set(i - // + real_size * 1, - // Point_2D::construct(-pt.y, - // pt.x)); - result_mp.lineTo(-pt.y + center.x, pt.x + center.y); - pt.rotateReverse(dcos, dsin); - } - break; - } - case 2: {// lower left quadrant - // m_circle_template.set(i + real_size * 2, - // Point_2D::construct(-pt.x, -pt.y)); - for (int i = 0; i < real_size; i++) { - result_mp.lineTo(-pt.x + center.x, -pt.y + center.y); - pt.rotateReverse(dcos, dsin); - } - break; - } - default:// case 3: - {// lower right quadrant - // m_circle_template.set(i + real_size * 3, - // Point_2D::construct(pt.y, -pt.x)); - result_mp.startPath(pt.y + center.x, -pt.x + center.y);// we - // start - // at - // the - // quadrant - // 3. - // The - // first - // point - // is - // (0, - // -m_distance) - // + - // center - for (int i = 1; i < real_size; i++) { - pt.rotateReverse(dcos, dsin); - result_mp.lineTo(pt.y + center.x, -pt.x + center.y); - } - break; - } - } - - progress_(); - } - } - - private static Polygon setWeakSimple_(Polygon poly) { - ((MultiPathImpl) poly._getImpl()).setIsSimple( - MultiVertexGeometryImpl.GeometryXSimple.Weak, 0.0, false); - return poly; - } - - private Polygon setStrongSimple_(Polygon poly) { - ((MultiPathImpl) poly._getImpl()).setIsSimple( - MultiVertexGeometryImpl.GeometryXSimple.Strong, m_tolerance, - false); - ((MultiPathImpl) poly._getImpl())._updateOGCFlags(); - return poly; - } + Bufferer() { + m_buffer_commands = new ArrayList(128); + m_progress_tracker = null; + m_tolerance = 0; + m_small_tolerance = 0; + m_filter_tolerance = 0; + m_distance = 0; + m_original_geom_type = Geometry.GeometryType.Unknown; + m_abs_distance_reversed = 0; + m_abs_distance = 0; + m_densify_dist = -1; + m_dA = -1; + m_b_output_loops = true; + m_bfilter = true; + m_old_circle_template_size = 0; + } + + + /** + * Result is always a polygon. For non positive distance and non-areas + * returns an empty polygon. For points returns circles. + */ + Geometry buffer(Geometry geometry, double distance, + SpatialReference sr, double densify_dist, + int max_vertex_in_complete_circle, ProgressTracker progress_tracker) { + if (geometry == null) + throw new IllegalArgumentException(); + + if (densify_dist < 0) + throw new IllegalArgumentException(); + + if (geometry.isEmpty()) + return new Polygon(geometry.getDescription()); + + Envelope2D env2D = new Envelope2D(); + geometry.queryLooseEnvelope2D(env2D); + if (distance > 0) + env2D.inflate(distance, distance); + + m_progress_tracker = progress_tracker; + + m_original_geom_type = geometry.getType().value(); + m_geometry = geometry; + m_tolerance = InternalUtils.calculateToleranceFromGeometry(sr, + env2D, true);// conservative to have same effect as simplify + m_small_tolerance = InternalUtils + .calculateToleranceFromGeometry(null, env2D, true);// conservative + // to have + // same + // effect as + // simplify + + if (max_vertex_in_complete_circle <= 0) { + max_vertex_in_complete_circle = 96;// 96 is the value used by SG. + // This is the number of + // vertices in the full circle. + } + + m_spatialReference = sr; + m_distance = distance; + m_abs_distance = Math.abs(m_distance); + m_abs_distance_reversed = m_abs_distance != 0 ? 1.0 / m_abs_distance + : 0; + + if (NumberUtils.isNaN(densify_dist) || densify_dist == 0) { + densify_dist = m_abs_distance * 1e-5; + } else { + if (densify_dist > m_abs_distance * 0.5) + densify_dist = m_abs_distance * 0.5;// do not allow too + // large densify + // distance (the + // value will be + // adjusted + // anyway later) + } + + if (max_vertex_in_complete_circle < 12) + max_vertex_in_complete_circle = 12; + + + double max_dd = Math.abs(distance) + * (1 - Math.cos(Math.PI / max_vertex_in_complete_circle)); + + if (max_dd > densify_dist) + densify_dist = max_dd;// the densify distance has to agree with the + // max_vertex_in_complete_circle + else { + double vertex_count = Math.PI + / Math.acos(1.0 - densify_dist / Math.abs(distance)); + if (vertex_count < (double) max_vertex_in_complete_circle - 1.0) { + max_vertex_in_complete_circle = (int) vertex_count; + if (max_vertex_in_complete_circle < 12) { + max_vertex_in_complete_circle = 12; + densify_dist = Math.abs(distance) * (1 - Math.cos(Math.PI / max_vertex_in_complete_circle)); + } + } + } + + m_densify_dist = densify_dist; + m_max_vertex_in_complete_circle = max_vertex_in_complete_circle; + // when filtering close points we do not want the filter to distort + // generated buffer too much. + m_filter_tolerance = Math.min(m_small_tolerance, + densify_dist * 0.25); + + + m_circle_template_size = calcN_(); + if (m_circle_template_size != m_old_circle_template_size) { + // we have an optimization for this method to be called several + // times. Here we detected too many changes and need to regenerate + // the data. + m_circle_template.clear(); + m_old_circle_template_size = m_circle_template_size; + } + + Geometry result_geom = buffer_(); + m_geometry = null; + return result_geom; + } + + private Geometry m_geometry; + + private static final class BufferCommand { + private interface Flags { + static final int enum_line = 1; + static final int enum_arc = 2; + static final int enum_connection = enum_arc | enum_line; + } + + private Point2D m_from; + private Point2D m_to; + private Point2D m_center; + private int m_next; + private int m_prev; + private int m_type; + + private BufferCommand(Point2D from, Point2D to, Point2D center, + int type, int next, int prev) { + m_from = new Point2D(); + m_to = new Point2D(); + m_center = new Point2D(); + m_from.setCoords(from); + m_to.setCoords(to); + m_center.setCoords(center); + m_type = type; + m_next = next; + m_prev = prev; + } + + private BufferCommand(Point2D from, Point2D to, int next, int prev, + String dummy) { + m_from = new Point2D(); + m_to = new Point2D(); + m_center = new Point2D(); + m_from.setCoords(from); + m_to.setCoords(to); + m_center.setNaN(); + m_type = 4; + m_next = next; + m_prev = prev; + } + } + + private ArrayList m_buffer_commands; + + private int m_original_geom_type; + private ProgressTracker m_progress_tracker; + private int m_max_vertex_in_complete_circle; + private SpatialReference m_spatialReference; + private double m_tolerance; + private double m_small_tolerance; + private double m_filter_tolerance; + private double m_densify_dist; + private double m_distance; + private double m_abs_distance; + private double m_abs_distance_reversed; + private double m_dA; + private boolean m_b_output_loops; + private boolean m_bfilter; + private ArrayList m_circle_template = new ArrayList(0); + private ArrayList m_left_stack; + private ArrayList m_middle_stack; + private Line m_helper_line_1; + private Line m_helper_line_2; + private Point2D[] m_helper_array; + private int m_progress_counter; + private int m_circle_template_size; + private int m_old_circle_template_size; + + private void generateCircleTemplate_() { + if (!m_circle_template.isEmpty()) { + return; + } + + int N = m_circle_template_size; + + assert (N >= 4); + int real_size = (N + 3) / 4; + double dA = (Math.PI * 0.5) / real_size; + m_dA = dA; + + for (int i = 0; i < real_size * 4; i++) + m_circle_template.add(null); + + double dcos = Math.cos(dA); + double dsin = Math.sin(dA); + Point2D pt = new Point2D(0.0, 1.0); + + for (int i = 0; i < real_size; i++) { + m_circle_template.set(i + real_size * 0, new Point2D(pt.y, -pt.x)); + m_circle_template.set(i + real_size * 1, new Point2D(-pt.x, -pt.y)); + m_circle_template.set(i + real_size * 2, new Point2D(-pt.y, pt.x)); + m_circle_template.set(i + real_size * 3, pt); + pt = new Point2D(pt.x, pt.y); + pt.rotateReverse(dcos, dsin); + } + // the template is filled with the index 0 corresponding to the point + // (0, 0), following clockwise direction (0, -1), (-1, 0), (1, 0) + } + + private static final class GeometryCursorForMultiPoint extends + GeometryCursor { + private Bufferer m_parent; + private int m_index; + private Geometry m_buffered_polygon; + private MultiPoint m_mp; + private SpatialReference m_spatialReference; + private double m_distance; + private double m_densify_dist; + private double m_x; + private double m_y; + private int m_max_vertex_in_complete_circle; + private ProgressTracker m_progress_tracker; + + GeometryCursorForMultiPoint(Bufferer parent, MultiPoint mp, double distance, + SpatialReference sr, double densify_dist, + int max_vertex_in_complete_circle, + ProgressTracker progress_tracker) { + m_parent = parent; + m_index = 0; + m_mp = mp; + m_x = 0; + m_y = 0; + m_distance = distance; + m_spatialReference = sr; + m_densify_dist = densify_dist; + m_max_vertex_in_complete_circle = max_vertex_in_complete_circle; + m_progress_tracker = progress_tracker; + } + + @Override + public Geometry next() { + Point point = new Point(); + while (true) { + if (m_index == m_mp.getPointCount()) + return null; + + m_mp.getPointByVal(m_index, point); + m_index++; + if (point.isEmpty()) + continue; + break; + } + + boolean b_first = false; + if (m_buffered_polygon == null) { + m_x = point.getX(); + m_y = point.getY(); + + m_buffered_polygon = m_parent.buffer(point, m_distance, + m_spatialReference, m_densify_dist, + m_max_vertex_in_complete_circle, m_progress_tracker); + b_first = true; + } + + Geometry res; + if (m_index < m_mp.getPointCount()) { + res = new Polygon(); + m_buffered_polygon.copyTo(res); + } else { + res = m_buffered_polygon; // do not clone the last geometry. + } + + if (!b_first)// don't apply transformation unnecessary + { + Transformation2D transform = new Transformation2D(); + double dx = point.getX() - m_x; + double dy = point.getY() - m_y; + transform.setShift(dx, dy); + res.applyTransformation(transform); + } + + return res; + } + + @Override + // TODO unclear how this might work + public boolean hasNext() { + return m_mp.getPointCount() > m_index; + } + + @Override + public long getGeometryID() { + return 0; + } + } + + private static final class GlueingCursorForPolyline extends GeometryCursor { + private Polyline m_polyline; + private int m_current_path_index; + + GlueingCursorForPolyline(Polyline polyline) { + m_polyline = polyline; + m_current_path_index = 0; + } + + @Override + public Geometry next() { + if (m_polyline == null) + return null; + + MultiPathImpl mp = (MultiPathImpl) m_polyline._getImpl(); + int npaths = mp.getPathCount(); + if (m_current_path_index < npaths) { + int ind = m_current_path_index; + m_current_path_index++; + if (!mp.isClosedPathInXYPlane(ind)) { + // connect paths that follow one another as an optimization + // for buffering (helps when one polyline is split into many + // segments). + Point2D prev_end = mp.getXY(mp.getPathEnd(ind) - 1); + while (m_current_path_index < mp.getPathCount()) { + Point2D start = mp.getXY(mp + .getPathStart(m_current_path_index)); + if (mp.isClosedPathInXYPlane(m_current_path_index)) + break; + if (start != prev_end) + break; + + prev_end = mp + .getXY(mp.getPathEnd(m_current_path_index) - 1); + m_current_path_index++; + } + } + + if (ind == 0 + && m_current_path_index == m_polyline.getPathCount()) { + Polyline pol = m_polyline; + m_polyline = null; + return pol; + } + + Polyline tmp_polyline = new Polyline( + m_polyline.getDescription()); + tmp_polyline.addPath(m_polyline, ind, true); + for (int i = ind + 1; i < m_current_path_index; i++) { + tmp_polyline.addSegmentsFromPath(m_polyline, i, 0, + mp.getSegmentCount(i), false); + } + + if (false) { + OperatorFactoryLocal.saveGeometryToEsriShapeDbg( + "c:/temp/_geom.bin", tmp_polyline); + } + + if (m_current_path_index == m_polyline.getPathCount()) + m_polyline = null; + + return tmp_polyline; + } else { + return null; + } + } + + @Override + public boolean hasNext() { + return m_polyline != null && m_current_path_index < ((MultiPathImpl) m_polyline._getImpl()).getPathCount(); + } + + @Override + public long getGeometryID() { + return 0; + } + } + + private static final class GeometryCursorForPolyline extends GeometryCursor { + private Bufferer m_bufferer; + GeometryCursor m_geoms; + Geometry m_geometry; + private int m_index; + private boolean m_bfilter; + + GeometryCursorForPolyline(Bufferer bufferer, GeometryCursor geoms, + boolean bfilter) { + m_bufferer = bufferer; + m_geoms = geoms; + m_index = 0; + m_bfilter = bfilter; + } + + @Override + public Geometry next() { + if (m_geometry == null) { + m_index = 0; + m_geometry = m_geoms.next(); + if (m_geometry == null) + return null; + } + + MultiPath mp = (MultiPath) (m_geometry); + if (m_index < mp.getPathCount()) { + int ind = m_index; + m_index++; + return m_bufferer.bufferPolylinePath_((Polyline) m_geometry, + ind, m_bfilter); + } + + m_geometry = null; + return next(); + } + + @Override + public boolean hasNext() { + return (m_geoms != null && m_geoms.hasNext()) || (m_geometry != null && m_index < ((MultiPath) m_geometry).getPathCount()); + } + + @Override + public long getGeometryID() { + return 0; + } + } + + private static final class GeometryCursorForPolygon extends GeometryCursor { + private Bufferer m_bufferer; + private int m_index; + + GeometryCursorForPolygon(Bufferer bufferer) { + m_bufferer = bufferer; + m_index = 0; + } + + @Override + public Geometry next() { + Polygon input_polygon = (Polygon) (m_bufferer.m_geometry); + if (m_index < input_polygon.getPathCount()) { + int ind = m_index; + double area = input_polygon.calculateRingArea2D(m_index); + assert (area > 0); + m_index++; + while (m_index < input_polygon.getPathCount()) { + double hole_area = input_polygon + .calculateRingArea2D(m_index); + if (hole_area > 0) + break;// not a hole + m_index++; + } + + if (ind == 0 && m_index == input_polygon.getPathCount()) { + return m_bufferer.bufferPolygonImpl_(input_polygon, 0, + input_polygon.getPathCount()); + } else { + return m_bufferer.bufferPolygonImpl_(input_polygon, ind, + m_index); + } + } + + return null; + } + + @Override + public boolean hasNext() { + return m_index < ((Polygon) m_bufferer.m_geometry).getPathCount(); + } + + @Override + public long getGeometryID() { + return 0; + } + } + + private Geometry buffer_() { + int gt = m_geometry.getType().value(); + if (Geometry.isSegment(gt)) {// convert segment to a polyline and repeat + // the call + Polyline polyline = new Polyline(m_geometry.getDescription()); + polyline.addSegment((Segment) (m_geometry), true); + m_geometry = polyline; + return buffer_(); + } + + if (m_distance <= m_tolerance) { + if (Geometry.isArea(gt)) { + if (m_distance <= 0) { + // if the geometry is area type, then the negative distance + // may produce a degenerate shape. Check for this and return + // empty geometry. + Envelope2D env = new Envelope2D(); + m_geometry.queryEnvelope2D(env); + if (env.getWidth() <= -m_distance * 2 + || env.getHeight() <= m_distance * 2) + return new Polygon(m_geometry.getDescription()); + } + } else { + return new Polygon(m_geometry.getDescription());// return an + // empty polygon + // for distance + // <= + // m_tolerance + // and any input + // other than + // polygon. + } + } + + // Operator_factory_local::SaveJSONToTextFileDbg("c:/temp/buffer_input.txt", + // *m_geometry, nullptr); + + // Complex cases: + switch (m_geometry.getType().value()) { + case Geometry.GeometryType.Point: + return bufferPoint_(); + case Geometry.GeometryType.MultiPoint: + return bufferMultiPoint_(); + case Geometry.GeometryType.Polyline: + return bufferPolyline_(); + case Geometry.GeometryType.Polygon: + return bufferPolygon_(); + case Geometry.GeometryType.Envelope: + return bufferEnvelope_(); + default: + throw GeometryException.GeometryInternalError(); + } + } + + private Geometry bufferPolyline_() { + if (isDegenerateGeometry_(m_geometry)) { + Point point = new Point(); + ((MultiVertexGeometry) m_geometry).getPointByVal(0, point); + Envelope2D env2D = new Envelope2D(); + m_geometry.queryEnvelope2D(env2D); + point.setXY(env2D.getCenter()); + return bufferPoint_(point); + } + + assert (m_distance > 0); + Polyline poly = (Polyline) m_geometry; + m_geometry = null; + + GeometryCursor glueing_cursor = new GlueingCursorForPolyline(poly);//glues paths together if they connect at one point + poly = null; + GeometryCursor generalized_paths = OperatorGeneralize.local().execute(glueing_cursor, m_densify_dist * 0.25, false, m_progress_tracker); + GeometryCursor simple_paths = OperatorSimplifyOGC.local().execute(generalized_paths, null, true, m_progress_tracker);//make a planar graph. + generalized_paths = null; + GeometryCursor path_buffering_cursor = new GeometryCursorForPolyline(this, simple_paths, m_bfilter); + simple_paths = null; + GeometryCursor union_cursor = OperatorUnion.local().execute(path_buffering_cursor, m_spatialReference, m_progress_tracker);//(int)Operator_union::Options::enum_disable_edge_dissolver + Geometry result = union_cursor.next(); + return result; + } + + private Geometry bufferPolygon_() { + if (m_distance == 0) + return m_geometry;// return input to the output. + + OperatorSimplify simplify = (OperatorSimplify) OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Simplify); + + generateCircleTemplate_(); + m_geometry = simplify.execute(m_geometry, null, false, + m_progress_tracker); + if(m_geometry.isEmpty()) { + return m_geometry; + } + + if (m_distance < 0) { + Polygon poly = (Polygon) (m_geometry); + Polygon buffered_result = bufferPolygonImpl_(poly, 0, + poly.getPathCount()); + return simplify.execute(buffered_result, m_spatialReference, false, + m_progress_tracker); + } else { + if (isDegenerateGeometry_(m_geometry)) { + Point point = new Point(); + ((MultiVertexGeometry) m_geometry).getPointByVal(0, point); + Envelope2D env2D = new Envelope2D(); + m_geometry.queryEnvelope2D(env2D); + point.setXY(env2D.getCenter()); + return bufferPoint_(point); + } + + // For the positive distance we need to process polygon in the parts + // such that each exterior ring with holes is processed separatelly. + GeometryCursorForPolygon cursor = new GeometryCursorForPolygon(this); + GeometryCursor union_cursor = ((OperatorUnion) OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Union)).execute( + cursor, m_spatialReference, m_progress_tracker); + Geometry result = union_cursor.next(); + if (result != null) { + return result; + } else { + //never return empty. + return new Polygon(m_geometry.getDescription()); + } + } + } + + private Polygon bufferPolygonImpl_(Polygon input_geom, int ipath_begin, + int ipath_end) { + MultiPath input_mp = (MultiPath) (input_geom); + MultiPathImpl mp_impl = (MultiPathImpl) (input_mp._getImpl()); + Polygon intermediate_polygon = new Polygon(input_geom.getDescription()); + for (int ipath = ipath_begin; ipath < ipath_end; ipath++) { + if (mp_impl.getPathSize(ipath) < 1) + continue; + + double path_area = mp_impl.calculateRingArea2D(ipath); + Envelope2D env2D = new Envelope2D(); + mp_impl.queryPathEnvelope2D(ipath, env2D); + + if (m_distance > 0) { + if (path_area > 0) { + if (isDegeneratePath_(mp_impl, ipath)) {// if a path is + // degenerate + // (almost a point), + // then we can draw + // a circle instead + // of it as a buffer + // and nobody would + // notice :) + Point point = new Point(); + mp_impl.getPointByVal(mp_impl.getPathStart(ipath), + point); + point.setXY(env2D.getCenter()); + addCircle_( + (MultiPathImpl) intermediate_polygon._getImpl(), + point); + } else { + Polyline result_polyline = new Polyline( + input_geom.getDescription()); + MultiPathImpl result_mp = (MultiPathImpl) result_polyline + ._getImpl(); + + // We often see convex hulls, buffering those is an + // extremely simple task. + boolean bConvex = ConvexHull.isPathConvex( + (Polygon) (m_geometry), ipath, + m_progress_tracker); + if (bConvex + || bufferClosedPath_(m_geometry, ipath, + result_mp, true, 1) == 2) { + Polygon buffered_path = bufferConvexPath_(input_mp, + ipath); + intermediate_polygon.add(buffered_path, false); + } else { + Polygon buffered_path = bufferCleanup_( + result_polyline, false); + intermediate_polygon.add(buffered_path, false); + } + } + } else { + if (env2D.getWidth() + m_tolerance <= 2 * m_abs_distance + || env2D.getHeight() + m_tolerance <= 2 * m_abs_distance) // skip + // parts + // that + // will + // dissapear + continue; + + Polyline result_polyline = new Polyline( + input_geom.getDescription()); + MultiPathImpl result_mp = (MultiPathImpl) result_polyline + ._getImpl(); + bufferClosedPath_(m_geometry, ipath, result_mp, true, 1); + if (!result_polyline.isEmpty()) { + Envelope2D env = new Envelope2D(); + env.setCoords(env2D); + env.inflate(m_abs_distance, m_abs_distance); + result_mp.addEnvelope(env, false); + Polygon buffered_path = bufferCleanup_(result_polyline, + false); + // intermediate_polygon.reserve(intermediate_polygon.getPointCount() + // + buffered_path.getPointCount() - 4); + for (int i = 1, n = buffered_path.getPathCount(); i < n; i++) + intermediate_polygon + .addPath(buffered_path, i, true); + } + } + } else { + if (path_area > 0) { + if (env2D.getWidth() + m_tolerance <= 2 * m_abs_distance + || env2D.getHeight() + m_tolerance <= 2 * m_abs_distance) // skip + // parts + // that + // will + // dissapear + continue; + + Polyline result_polyline = new Polyline( + input_geom.getDescription()); + MultiPathImpl result_mp = (MultiPathImpl) result_polyline + ._getImpl(); + bufferClosedPath_(m_geometry, ipath, result_mp, true, -1);// this + // will + // provide + // a + // shape + // buffered + // inwards. + // It + // has + // counterclockwise + // orientation + if (!result_polyline.isEmpty()) { + Envelope2D env = new Envelope2D(); + result_mp.queryLooseEnvelope2D(env); + env.inflate(m_abs_distance, m_abs_distance); + result_mp.addEnvelope(env, false);// add an envelope + // exterior shell + Polygon buffered_path = bufferCleanup_(result_polyline, + false);// simplify with winding rule + // extract all parts but the first one (which is the + // envelope we added previously) + for (int i = 1, npaths = buffered_path.getPathCount(); i < npaths; i++) { + // the extracted parts have inverted orientation. + intermediate_polygon + .addPath(buffered_path, i, true); + } + } else { + // the path has been erased + } + } else { + // When buffering a hole with negative distance, buffer it + // as if it is an exterior ring buffered with positive + // distance + Polyline result_polyline = new Polyline( + input_geom.getDescription()); + MultiPathImpl result_mp = (MultiPathImpl) result_polyline + ._getImpl(); + bufferClosedPath_(m_geometry, ipath, result_mp, true, -1);// this + // will + // provide + // a + // shape + // buffered + // inwards. + Polygon buffered_path = bufferCleanup_(result_polyline, + false); + for (int i = 0, npaths = buffered_path.getPathCount(); i < npaths; i++) { + intermediate_polygon.addPath(buffered_path, i, true);// adds + // buffered + // hole + // reversed + // as + // if + // it + // is + // exteror + // ring + } + } + + // intermediate_polygon has inverted orientation. + } + } + + if (m_distance > 0) { + if (intermediate_polygon.getPathCount() > 1) { + Polygon cleaned_polygon = bufferCleanup_(intermediate_polygon, + false); + return cleaned_polygon; + } else { + return setWeakSimple_(intermediate_polygon); + } + } else { + Envelope2D polyenv = new Envelope2D(); + intermediate_polygon.queryLooseEnvelope2D(polyenv); + if (!intermediate_polygon.isEmpty()) { + // negative buffer distance. We got buffered holes and exterior + // rings. They all have wrong orientation. + // we need to apply winding simplify again to ensure all holes + // are unioned. + // For that create a big envelope and add all rings of the + // intermediate_polygon to it. + polyenv.inflate(m_abs_distance, m_abs_distance); + intermediate_polygon.addEnvelope(polyenv, false); + Polygon cleaned_polygon = bufferCleanup_(intermediate_polygon, + false); + // intermediate_polygon.reset();//free memory + + Polygon result_polygon = new Polygon( + cleaned_polygon.getDescription()); + for (int i = 1, n = cleaned_polygon.getPathCount(); i < n; i++) { + result_polygon.addPath(cleaned_polygon, i, false); + } + return setWeakSimple_(result_polygon); + } else { + return setWeakSimple_(intermediate_polygon); + } + } + } + + private Geometry bufferPoint_() { + return bufferPoint_((Point) (m_geometry)); + } + + private Geometry bufferPoint_(Point point) { + assert (m_distance > 0); + Polygon resultPolygon = new Polygon(point.getDescription()); + addCircle_((MultiPathImpl) resultPolygon._getImpl(), point); + return setStrongSimple_(resultPolygon); + } + + private Geometry bufferMultiPoint_() { + assert (m_distance > 0); + GeometryCursorForMultiPoint mpCursor = new GeometryCursorForMultiPoint(this, + (MultiPoint) (m_geometry), m_distance, m_spatialReference, + m_densify_dist, m_max_vertex_in_complete_circle, + m_progress_tracker); + GeometryCursor c = ((OperatorUnion) OperatorFactoryLocal.getInstance() + .getOperator(Operator.Type.Union)).execute(mpCursor, + m_spatialReference, m_progress_tracker); + return c.next(); + } + + private Geometry bufferEnvelope_() { + Polygon polygon = new Polygon(m_geometry.getDescription()); + if (m_distance <= 0) { + if (m_distance == 0) + polygon.addEnvelope((Envelope) (m_geometry), false); + else { + Envelope env = new Envelope(); + m_geometry.queryEnvelope(env); + env.inflate(m_distance, m_distance); + polygon.addEnvelope(env, false); + } + + return polygon;// nothing is easier than negative buffer on the + // envelope. + } + + polygon.addEnvelope((Envelope) (m_geometry), false); + m_geometry = polygon; + return bufferConvexPath_(polygon, 0); + } + + private Polygon bufferConvexPath_(MultiPath src, int ipath) { + generateCircleTemplate_(); + + Polygon resultPolygon = new Polygon(src.getDescription()); + MultiPathImpl result_mp = (MultiPathImpl) resultPolygon._getImpl(); + + // resultPolygon.reserve((m_circle_template.size() / 10 + 4) * + // src.getPathSize(ipath)); + + Point2D pt_1_tmp = new Point2D(), pt_1 = new Point2D(); + Point2D pt_2_tmp = new Point2D(), pt_2 = new Point2D(); + Point2D pt_3_tmp = new Point2D(), pt_3 = new Point2D(); + Point2D v_1 = new Point2D(); + Point2D v_2 = new Point2D(); + MultiPathImpl src_mp = (MultiPathImpl) src._getImpl(); + int path_size = src.getPathSize(ipath); + int path_start = src.getPathStart(ipath); + for (int i = 0, n = src.getPathSize(ipath); i < n; i++) { + src_mp.getXY(path_start + i, pt_1); + src_mp.getXY(path_start + (i + 1) % path_size, pt_2); + src_mp.getXY(path_start + (i + 2) % path_size, pt_3); + v_1.sub(pt_2, pt_1); + if (v_1.length() == 0) + throw GeometryException.GeometryInternalError(); + + v_1.leftPerpendicular(); + v_1.normalize(); + v_1.scale(m_abs_distance); + pt_1_tmp.add(v_1, pt_1); + pt_2_tmp.add(v_1, pt_2); + if (i == 0) + result_mp.startPath(pt_1_tmp); + else { + result_mp.lineTo(pt_1_tmp); + } + + result_mp.lineTo(pt_2_tmp); + + v_2.sub(pt_3, pt_2); + if (v_2.length() == 0) + throw GeometryException.GeometryInternalError(); + + v_2.leftPerpendicular(); + v_2.normalize(); + v_2.scale(m_abs_distance); + pt_3_tmp.add(v_2, pt_2); + + addJoin_(result_mp, pt_2, pt_2_tmp, pt_3_tmp, false, false); + } + + return setWeakSimple_(resultPolygon); + } + + private Polygon bufferPolylinePath_(Polyline polyline, int ipath, + boolean bfilter) { + assert (m_distance != 0); + generateCircleTemplate_(); + + MultiPath input_multi_path = polyline; + MultiPathImpl mp_impl = (MultiPathImpl) (input_multi_path._getImpl()); + + if (mp_impl.getPathSize(ipath) < 1) + return null; + + if (isDegeneratePath_(mp_impl, ipath) && m_distance > 0) {// if a path + // is + // degenerate + // (almost a + // point), + // then we + // can draw + // a circle + // instead + // of it as + // a buffer + // and + // nobody + // would + // notice :) + Point point = new Point(); + mp_impl.getPointByVal(mp_impl.getPathStart(ipath), point); + Envelope2D env2D = new Envelope2D(); + mp_impl.queryPathEnvelope2D(ipath, env2D); + point.setXY(env2D.getCenter()); + return (Polygon) (bufferPoint_(point)); + } + + Polyline result_polyline = new Polyline(polyline.getDescription()); + + MultiPathImpl result_mp = (MultiPathImpl) result_polyline._getImpl(); + boolean b_closed = mp_impl.isClosedPathInXYPlane(ipath); + + if (b_closed) { + bufferClosedPath_(input_multi_path, ipath, result_mp, bfilter, 1); + bufferClosedPath_(input_multi_path, ipath, result_mp, bfilter, -1); + } else { + Polyline tmpPoly = new Polyline(input_multi_path.getDescription()); + tmpPoly.addPath(input_multi_path, ipath, false); + ((MultiPathImpl) tmpPoly._getImpl()).addSegmentsFromPath( + (MultiPathImpl) input_multi_path._getImpl(), ipath, 0, + input_multi_path.getSegmentCount(ipath), false); + bufferClosedPath_(tmpPoly, 0, result_mp, bfilter, 1); + } + + return bufferCleanup_(result_polyline, false); + } + + private void progress_() { + m_progress_counter++; + if (m_progress_counter % 1024 == 0) { + if ((m_progress_tracker != null) + && !(m_progress_tracker.progress(-1, -1))) + throw new RuntimeException("user_canceled"); + } + } + + private Polygon bufferCleanup_(MultiPath multi_path, boolean simplify_result) { + double tol = simplify_result ? m_tolerance : m_small_tolerance; + Polygon resultPolygon = (Polygon) (TopologicalOperations + .planarSimplify(multi_path, tol, true, !simplify_result, + m_progress_tracker)); + assert (InternalUtils.isWeakSimple(resultPolygon, 0.0)); + return resultPolygon; + } + + private int calcN_() { + //this method should be called only once m_circle_template_size is set then; + final int minN = 4; + if (m_densify_dist == 0) + return m_max_vertex_in_complete_circle; + + double r = m_densify_dist * Math.abs(m_abs_distance_reversed); + double cos_a = 1 - r; + double N; + if (cos_a < -1) + N = minN; + else + N = 2.0 * Math.PI / Math.acos(cos_a) + 0.5; + + if (N < minN) + N = minN; + else if (N > m_max_vertex_in_complete_circle) + N = m_max_vertex_in_complete_circle; + + return (int) N; + } + + private void addJoin_(MultiPathImpl dst, Point2D center, Point2D fromPt, + Point2D toPt, boolean bStartPath, boolean bFinishAtToPt) { + generateCircleTemplate_(); + + Point2D v_1 = new Point2D(); + v_1.sub(fromPt, center); + v_1.scale(m_abs_distance_reversed); + Point2D v_2 = new Point2D(); + v_2.sub(toPt, center); + v_2.scale(m_abs_distance_reversed); + double angle_from = Math.atan2(v_1.y, v_1.x); + double dindex_from = angle_from / m_dA; + if (dindex_from < 0) + dindex_from = (double) m_circle_template.size() + dindex_from; + + dindex_from = (double) m_circle_template.size() - dindex_from; + + double angle_to = Math.atan2(v_2.y, v_2.x); + double dindex_to = angle_to / m_dA; + if (dindex_to < 0) + dindex_to = (double) m_circle_template.size() + dindex_to; + + dindex_to = (double) m_circle_template.size() - dindex_to; + + if (dindex_to < dindex_from) + dindex_to += (double) m_circle_template.size(); + assert (dindex_to >= dindex_from); + + int index_to = (int) dindex_to; + int index_from = (int) Math.ceil(dindex_from); + + if (bStartPath) { + dst.startPath(fromPt); + bStartPath = false; + } + + Point2D p = new Point2D(); + p.setCoords(m_circle_template.get(index_from % m_circle_template.size())); + p.scaleAdd(m_abs_distance, center); + double ddd = m_tolerance * 10; + p.sub(fromPt); + if (p.length() < ddd)// if too close to the fromPt, then use the next + // point + index_from += 1; + + p.setCoords(m_circle_template.get(index_to % m_circle_template.size())); + p.scaleAdd(m_abs_distance, center); + p.sub(toPt); + if (p.length() < ddd)// if too close to the toPt, then use the prev + // point + index_to -= 1; + + int count = index_to - index_from; + count++; + + for (int i = 0, j = index_from % m_circle_template.size(); i < count; i++, j = (j + 1) + % m_circle_template.size()) { + p.setCoords(m_circle_template.get(j)); + p.scaleAdd(m_abs_distance, center); + dst.lineTo(p); + progress_(); + } + + if (bFinishAtToPt) { + dst.lineTo(toPt); + } + } + + private int bufferClosedPath_(Geometry input_geom, int ipath, + MultiPathImpl result_mp, boolean bfilter, int dir) { + // Use temporary polyline for the path buffering. + EditShape edit_shape = new EditShape(); + int geom = edit_shape.addPathFromMultiPath((MultiPath) input_geom, + ipath, true); + edit_shape.filterClosePoints(m_filter_tolerance, false, false); + if (edit_shape.getPointCount(geom) < 2) {// Got degenerate output. + // Either bail out or + // produce a circle. + if (dir < 0) + return 1;// negative direction produces nothing. + + MultiPath mpIn = (MultiPath) input_geom; + // Add a circle + Point pt = new Point(); + mpIn.getPointByVal(mpIn.getPathStart(ipath), pt); + addCircle_(result_mp, pt); + return 1; + } + + assert (edit_shape.getFirstPath(geom) != -1); + assert (edit_shape.getFirstVertex(edit_shape.getFirstPath(geom)) != -1); + + Point2D origin = edit_shape.getXY(edit_shape.getFirstVertex(edit_shape + .getFirstPath(geom))); + Transformation2D tr = new Transformation2D(); + tr.setShift(-origin.x, -origin.y); + // move the path to origin for better accuracy in calculations. + edit_shape.applyTransformation(tr); + + if (bfilter) { + // try removing the noise that does not contribute to the buffer. + int res_filter = filterPath_(edit_shape, geom, dir, true, m_abs_distance, m_filter_tolerance, m_densify_dist); + assert (res_filter == 1); + // Operator_factory_local::SaveJSONToTextFileDbg("c:/temp/buffer_filter.txt", + // *edit_shape.get_geometry(geom), nullptr); + if (edit_shape.getPointCount(geom) < 2) {// got degenerate output. + // Wither bail out or + // produce a circle. + if (dir < 0) + return 1;// negative direction produces nothing. + + MultiPath mpIn = (MultiPath) input_geom; + // Add a circle + Point pt = new Point(); + mpIn.getPointByVal(mpIn.getPathStart(ipath), pt); + addCircle_(result_mp, pt); + return 1; + } + } + + m_buffer_commands.clear(); + int path = edit_shape.getFirstPath(geom); + int ivert = edit_shape.getFirstVertex(path); + int iprev = dir == 1 ? edit_shape.getPrevVertex(ivert) : edit_shape + .getNextVertex(ivert); + int inext = dir == 1 ? edit_shape.getNextVertex(ivert) : edit_shape + .getPrevVertex(ivert); + boolean b_first = true; + Point2D pt_current = new Point2D(), pt_after = new Point2D(), pt_before = new Point2D(), pt_left_prev = new Point2D(), pt = new Point2D(), pt1 = new Point2D(); + Point2D v_after = new Point2D(), v_before = new Point2D(), v_left = new Point2D(), v_left_prev = new Point2D(); + double abs_d = m_abs_distance; + int ncount = edit_shape.getPathSize(path); + + // write out buffer commands as a set of arcs and line segments. + // if we'd convert this directly to a polygon and draw using winding + // fill rule, we'd get the buffered result. + for (int index = 0; index < ncount; index++) { + edit_shape.getXY(inext, pt_after); + + if (b_first) { + edit_shape.getXY(ivert, pt_current); + edit_shape.getXY(iprev, pt_before); + v_before.sub(pt_current, pt_before); + v_before.normalize(); + v_left_prev.leftPerpendicular(v_before); + v_left_prev.scale(abs_d); + pt_left_prev.add(v_left_prev, pt_current); + } + + v_after.sub(pt_after, pt_current); + v_after.normalize(); + + v_left.leftPerpendicular(v_after); + v_left.scale(abs_d); + pt.add(pt_current, v_left); + double cross = v_before.crossProduct(v_after); + double dot = v_before.dotProduct(v_after); + boolean bDoJoin = cross < 0 || (dot < 0 && cross == 0); + if (bDoJoin) { + m_buffer_commands.add(new BufferCommand(pt_left_prev, pt, + pt_current, BufferCommand.Flags.enum_arc, + m_buffer_commands.size() + 1, + m_buffer_commands.size() - 1)); + } else if (!pt_left_prev.isEqual(pt)) { + m_buffer_commands.add(new BufferCommand(pt_left_prev, + pt_current, m_buffer_commands.size() + 1, + m_buffer_commands.size() - 1, "dummy")); + m_buffer_commands.add(new BufferCommand(pt_current, pt, + m_buffer_commands.size() + 1, + m_buffer_commands.size() - 1, "dummy")); + } + + pt1.add(pt_after, v_left); + m_buffer_commands + .add(new BufferCommand(pt, pt1, pt_current, + BufferCommand.Flags.enum_line, m_buffer_commands + .size() + 1, m_buffer_commands.size() - 1)); + + pt_left_prev.setCoords(pt1); + v_left_prev.setCoords(v_left); + pt_before.setCoords(pt_current); + pt_current.setCoords(pt_after); + v_before.setCoords(v_after); + iprev = ivert; + ivert = inext; + b_first = false; + inext = dir == 1 ? edit_shape.getNextVertex(ivert) : edit_shape + .getPrevVertex(ivert); + } + + m_buffer_commands.get(m_buffer_commands.size() - 1).m_next = 0; + m_buffer_commands.get(0).m_prev = m_buffer_commands.size() - 1; + processBufferCommands_(result_mp); + tr.setShift(origin.x, origin.y);// move the path to improve precision. + result_mp.applyTransformation(tr, result_mp.getPathCount() - 1); + return 1; + } + + private void processBufferCommands_(MultiPathImpl result_mp) { + int ifirst_seg = cleanupBufferCommands_(); + boolean first = true; + int iseg_next = ifirst_seg + 1; + for (int iseg = ifirst_seg; iseg_next != ifirst_seg; iseg = iseg_next) { + BufferCommand command = m_buffer_commands.get(iseg); + iseg_next = command.m_next != -1 ? command.m_next : (iseg + 1) + % m_buffer_commands.size(); + if (command.m_type == 0) + continue;// deleted segment + + if (first) { + result_mp.startPath(command.m_from); + first = false; + } + + if (command.m_type == BufferCommand.Flags.enum_arc) {// arc + addJoin_(result_mp, command.m_center, command.m_from, + command.m_to, false, true); + } else { + result_mp.lineTo(command.m_to); + } + first = false; + } + } + + private int cleanupBufferCommands_() { + // The purpose of this function is to remove as many self intersections + // from the buffered shape as possible. + // The buffer works without cleanup also, but slower. + + if (m_helper_array == null) + m_helper_array = new Point2D[9]; + + int istart = 0; + for (int iseg = 0, nseg = m_buffer_commands.size(); iseg < nseg;) { + BufferCommand command = m_buffer_commands.get(iseg); + if ((command.m_type & BufferCommand.Flags.enum_connection) != 0) { + istart = iseg; + break; + } + + iseg = command.m_next; + } + + int iseg_next = istart + 1; + for (int iseg = istart; iseg_next != istart; iseg = iseg_next) { + BufferCommand command = m_buffer_commands.get(iseg); + iseg_next = command.m_next; + int count = 1; + BufferCommand command_next = null; + while (iseg_next != iseg) {// find next segement + command_next = m_buffer_commands.get(iseg_next); + if ((command_next.m_type & BufferCommand.Flags.enum_connection) != 0) + break; + + iseg_next = command_next.m_next; + count++; + } + + if (count == 1) { + // Next segment starts where this one ends. Skip this case as it + // is simple. + assert (command.m_to.isEqual(command_next.m_from)); + continue; + } + + if ((command.m_type & command_next.m_type) == BufferCommand.Flags.enum_line) {// simplest + // cleanup + // - + // intersect + // lines + if (m_helper_line_1 == null) { + m_helper_line_1 = new Line(); + m_helper_line_2 = new Line(); + } + m_helper_line_1.setStartXY(command.m_from); + m_helper_line_1.setEndXY(command.m_to); + m_helper_line_2.setStartXY(command_next.m_from); + m_helper_line_2.setEndXY(command_next.m_to); + + int count_ = m_helper_line_1.intersect(m_helper_line_2, + m_helper_array, null, null, m_small_tolerance); + if (count_ == 1) { + command.m_to.setCoords(m_helper_array[0]); + command_next.m_from.setCoords(m_helper_array[0]); + command.m_next = iseg_next;// skip until iseg_next + command_next.m_prev = iseg; + } else if (count_ == 2) {// TODO: this case needs improvement + } + } + } + + return istart; + } + + private static void protectExtremeVertices_(EditShape edit_shape, + int protection_index, int geom, int path) { + // detect very narrow corners and preserve them. We cannot reliably + // delete these. + int vprev = -1; + Point2D pt_prev = new Point2D(); + pt_prev.setNaN(); + Point2D pt = new Point2D(); + pt.setNaN(); + Point2D v_before = new Point2D(); + v_before.setNaN(); + Point2D pt_next = new Point2D(); + Point2D v_after = new Point2D(); + for (int i = 0, n = edit_shape.getPathSize(path), v = edit_shape + .getFirstVertex(path); i < n; ++i) { + if (vprev == -1) { + edit_shape.getXY(v, pt); + + vprev = edit_shape.getPrevVertex(v); + if (vprev != -1) { + edit_shape.getXY(vprev, pt_prev); + v_before.sub(pt, pt_prev); + v_before.normalize(); + } + } + + int vnext = edit_shape.getNextVertex(v); + if (vnext == -1) + break; + + edit_shape.getXY(vnext, pt_next); + v_after.sub(pt_next, pt); + v_after.normalize(); + + if (vprev != -1) { + double d = v_after.dotProduct(v_before); + if (d < -0.99 + && Math.abs(v_after.crossProduct(v_before)) < 1e-7) { + edit_shape.setUserIndex(v, protection_index, 1); + } + } + + vprev = v; + v = vnext; + pt_prev.setCoords(pt); + pt.setCoords(pt_next); + v_before.setCoords(v_after); + } + } + + static private int filterPath_(EditShape edit_shape, int geom, int dir, + boolean closed, double abs_distance, double filter_tolerance, + double densify_distance) { + int path = edit_shape.getFirstPath(geom); + + int concave_index = -1; + int fixed_vertices_index = edit_shape.createUserIndex(); + protectExtremeVertices_(edit_shape, fixed_vertices_index, geom, path); + + for (int iter = 0; iter < 100; ++iter) { + int isize = edit_shape.getPathSize(path); + if (isize == 0) { + edit_shape.removeUserIndex(fixed_vertices_index); + ; + return 1; + } + + int ivert = edit_shape.getFirstVertex(path); + int nvertices = edit_shape.getPathSize(path); + if (nvertices < 3) { + edit_shape.removeUserIndex(fixed_vertices_index); + ; + return 1; + } + + if (closed && !edit_shape.isClosedPath(path))// the path is closed + // only virtually + { + nvertices -= 1; + } + + double abs_d = abs_distance; + final int nfilter = 64; + boolean filtered = false; + int filtered_in_pass = 0; + boolean go_back = false; + for (int i = 0; i < nvertices && ivert != -1; i++) { + int filtered_now = 0; + int v = ivert; // filter == 0 + for (int filter = 1, n = (int) Math.min(nfilter, nvertices - i); filter < n; filter++) { + v = edit_shape.getNextVertex(v, dir); + if (filter > 1) { + int num = clipFilter_(edit_shape, + fixed_vertices_index, ivert, v, dir, + abs_distance, densify_distance, nfilter); + if (num == -1) + break; + + filtered |= num > 0; + filtered_now += num; + nvertices -= num; + } + } + + filtered_in_pass += filtered_now; + + go_back = filtered_now > 0; + + if (go_back) { + int prev = edit_shape.getPrevVertex(ivert, dir); + if (prev != -1) { + ivert = prev; + nvertices++; + continue; + } + } + + ivert = edit_shape.getNextVertex(ivert, dir); + } + + if (filtered_in_pass == 0) + break; + } + + edit_shape.removeUserIndex(fixed_vertices_index); + edit_shape.filterClosePoints(filter_tolerance, false, false); + + return 1; + } + + // This function clips out segments connecting from_vertiex to to_vertiex if + // they do not contribute to the buffer. + private static int clipFilter_(EditShape edit_shape, + int fixed_vertices_index, int from_vertex, int to_vertex, int dir, + double abs_distance, double densify_distance, final int max_filter) { + // Note: vertices marked with fixed_vertices_index cannot be deleted. + + Point2D pt1 = edit_shape.getXY(from_vertex); + Point2D pt2 = edit_shape.getXY(to_vertex); + if (pt1.equals(pt2)) + return -1; + + double densify_distance_delta = densify_distance * 0.25;// distance by + // which we can + // move the + // point closer + // to the chord + // (introducing + // an error into + // the buffer). + double erase_distance_delta = densify_distance * 0.25;// distance when + // we can erase + // the point + // (introducing + // an error into + // the buffer). + // This function goal is to modify or remove vertices between + // from_vertex and to_vertex in such a way that the result would not + // affect buffer to the left of the + // chain. + Point2D v_gap = new Point2D(); + v_gap.sub(pt2, pt1); + double gap_length = v_gap.length(); + double h2_4 = gap_length * gap_length * 0.25; + double sqr_center_to_chord = abs_distance * abs_distance - h2_4; // squared + // distance + // from + // the + // chord + // to + // the + // circle + // center + if (sqr_center_to_chord <= h2_4) + return -1;// center to chord distance is less than half gap, that + // means the gap is too wide for useful filtering (maybe + // this). + + double center_to_chord = Math.sqrt(sqr_center_to_chord); // distance + // from + // circle + // center to + // the + // chord. + + v_gap.normalize(); + Point2D v_gap_norm = new Point2D(v_gap); + v_gap_norm.rightPerpendicular(); + double chord_to_corner = h2_4 / center_to_chord; // cos(a) = + // center_to_chord / + // distance; + // chord_to_corner = + // distance / cos(a) + // - + // center_to_chord; + boolean can_erase_corner_point = chord_to_corner <= erase_distance_delta; + Point2D chord_midpoint = new Point2D(); + MathUtils.lerp(pt2, pt1, 0.5, chord_midpoint); + Point2D corner = new Point2D(v_gap_norm); + double corrected_chord_to_corner = chord_to_corner + - densify_distance_delta;// using slightly smaller than needed + // distance let us filter more. + corner.scaleAdd(Math.max(0.0, corrected_chord_to_corner), + chord_midpoint); + // corner = (p1 + p2) * 0.5 + v_gap_norm * chord_to_corner; + + Point2D center = new Point2D(v_gap_norm); + center.negate(); + center.scaleAdd(center_to_chord, chord_midpoint); + + double allowed_distance = abs_distance - erase_distance_delta; + double sqr_allowed_distance = MathUtils.sqr(allowed_distance); + double sqr_large_distance = sqr_allowed_distance * (1.9 * 1.9); + + Point2D co_p1 = new Point2D(); + co_p1.sub(corner, pt1); + Point2D co_p2 = new Point2D(); + co_p2.sub(corner, pt2); + + boolean large_distance = false;// set to true when distance + int cnt = 0; + char[] locations = new char[64]; + { + // check all vertices in the gap verifying that the gap can be + // clipped. + // + + Point2D pt = new Point2D(); + // firstly remove any duplicate vertices in the end. + for (int v = edit_shape.getPrevVertex(to_vertex, dir); v != from_vertex;) { + if (edit_shape.getUserIndex(v, fixed_vertices_index) == 1) + return -1;// this range contains protected vertex + + edit_shape.getXY(v, pt); + if (pt.equals(pt2)) { + int v1 = edit_shape.getPrevVertex(v, dir); + edit_shape.removeVertex(v, false); + v = v1; + continue; + } else { + break; + } + } + + Point2D prev_prev_pt = new Point2D(); + prev_prev_pt.setNaN(); + Point2D prev_pt = new Point2D(); + prev_pt.setCoords(pt1); + locations[cnt++] = 1; + int prev_v = from_vertex; + Point2D dummyPt = new Point2D(); + for (int v = edit_shape.getNextVertex(from_vertex, dir); v != to_vertex;) { + if (edit_shape.getUserIndex(v, fixed_vertices_index) == 1) + return -1;// this range contains protected vertex + + edit_shape.getXY(v, pt); + if (pt.equals(prev_pt)) { + int v1 = edit_shape.getNextVertex(v, dir); + edit_shape.removeVertex(v, false); + v = v1; + continue; + } + + locations[cnt++] = 0; + + Point2D v1 = new Point2D(); + v1.sub(pt, pt1); + if (v1.dotProduct(v_gap_norm) < 0)// we are crossing on the + // wrong site of the chord. + // Just bail out earlier. + // Maybe we could continue + // clipping though here, but + // it seems to be + // unnecessary complicated. + return 0; + + if (Point2D.sqrDistance(pt, pt1) > sqr_large_distance + || Point2D.sqrDistance(pt, pt2) > sqr_large_distance) + large_distance = true; // too far from points, may + // contribute to the outline (in + // case of a large loop) + + char next_location = 0; + + dummyPt.sub(pt, pt1); + double cs1 = dummyPt.crossProduct(co_p1); + if (cs1 >= 0) { + next_location = 1; + } + + dummyPt.sub(pt, pt2); + double cs2 = dummyPt.crossProduct(co_p2); + if (cs2 <= 0) { + next_location |= 2; + } + + if (next_location == 0) + return 0; + + locations[cnt - 1] = next_location; + prev_prev_pt.setCoords(prev_pt); + prev_pt.setCoords(pt); + prev_v = v; + v = edit_shape.getNextVertex(v, dir); + } + + if (cnt == 1) + return 0; + + assert (!pt2.equals(prev_pt)); + locations[cnt++] = 2; + } + + boolean can_clip_all = true; + // we can remove all points and replace them with a single corner point + // if we are moving from location 1 via location 3 to location 2 + for (int i = 1, k = 0; i < cnt; i++) { + if (locations[i] != locations[i - 1]) { + k++; + can_clip_all = k < 3 + && ((k == 1 && locations[i] == 3) || (k == 2 && locations[i] == 2)); + if (!can_clip_all) + return 0; + } + } + + if (cnt > 2 && can_clip_all && (cnt == 3 || !large_distance)) { + int clip_count = 0; + int v = edit_shape.getNextVertex(from_vertex, dir); + if (!can_erase_corner_point) { + edit_shape.setXY(v, corner); + v = edit_shape.getNextVertex(v, dir); + } + + // we can remove all vertices between from and to, because they + // don't contribute + while (v != to_vertex) { + int v1 = edit_shape.getNextVertex(v, dir); + edit_shape.removeVertex(v, false); + v = v1; + ++clip_count; + } + + return clip_count; + } + + if (cnt == 3) { + boolean case1 = (locations[0] == 1 && locations[1] == 2 && locations[2] == 2); + boolean case2 = (locations[0] == 1 && locations[1] == 1 && locations[2] == 2); + if (case1 || case2) { + // special case, when we cannot clip, but we can move the point + Point2D p1 = edit_shape.getXY(from_vertex); + int v = edit_shape.getNextVertex(from_vertex, dir); + Point2D p2 = edit_shape.getXY(v); + Point2D p3 = edit_shape.getXY(edit_shape.getNextVertex(v, dir)); + if (case2) { + Point2D temp = p1; + p1 = p3; + p3 = temp; + } + + Point2D vec = new Point2D(); + vec.sub(p1, p2); + p3.sub(p2); + double veclen = vec.length(); + double w = p3.length(); + double wcosa = vec.dotProduct(p3) / veclen; + double wsina = Math.abs(p3.crossProduct(vec) / veclen); + double z = 2 * abs_distance - wsina; + if (z < 0) + return 0; + + double x = wcosa + Math.sqrt(wsina * z); + if (x > veclen) + return 0; + + Point2D hvec = new Point2D(); + hvec.scaleAdd(-x / veclen, vec, p3); // hvec = p3 - vec * (x / + // veclen); + double h = hvec.length(); + double y = -(h * h * veclen) / (2 * hvec.dotProduct(vec)); + + double t = (x - y) / veclen; + MathUtils.lerp(p2, p1, t, p2); + edit_shape.setXY(v, p2); + return 0; + } + } + + if (large_distance && cnt > 3) { + // we are processing more than 3 points and there are some points + // further than the + return 0; + } + + int v_prev = -1; + Point2D pt_prev = new Point2D(); + int v_cur = from_vertex; + Point2D pt_cur = new Point2D(pt1); + int cur_location = 1; + int prev_location = -1; // 1 - semiplane to the right of [f,c]. 3 - + // semiplane to the right of [c,t], 2 - both + // above fc and ct, 0 - cannot clip, -1 - + // unknown + int v_next = v_cur; + int clip_count = 0; + cnt = 1; + while (v_next != to_vertex) { + v_next = edit_shape.getNextVertex(v_next, dir); + int next_location = locations[cnt++]; + if (next_location == 0) { + if (v_next == to_vertex) + break; + + continue; + } + + Point2D pt_next = edit_shape.getXY(v_next); + + if (prev_location != -1) { + int common_location = (prev_location & cur_location & next_location); + if ((common_location & 3) != 0) { + // prev and next are on the same semiplane as the current we + // can safely remove the current point. + edit_shape.removeVertex(v_cur, true); + clip_count++;// do not change prev point. + v_cur = v_next; + pt_cur.setCoords(pt_next); + cur_location = next_location; + continue; + } + + if (cur_location == 3 && prev_location != 0 + && next_location != 0) { + assert ((prev_location & next_location) == 0);// going from + // one semi + // plane to + // another + // via the + // mid. + pt_cur.setCoords(corner); + if (can_erase_corner_point || pt_cur.equals(pt_prev)) {// this + // point + // can + // be + // removed + edit_shape.removeVertex(v_cur, true); + clip_count++;// do not change prev point. + v_cur = v_next; + pt_cur.setCoords(pt_next); + cur_location = next_location; + continue; + } else { + edit_shape.setXY(v_cur, pt_cur); // snap to the corner + } + } else { + if (next_location == 0 + && cur_location != 0 + || next_location != 0 + && cur_location == 0 + || ((next_location | cur_location) == 3 + && next_location != 3 && cur_location != 3)) { + // clip + } + } + } + + prev_location = cur_location; + v_prev = v_cur; + pt_prev.setCoords(pt_cur); + v_cur = v_next; + cur_location = next_location; + pt_cur.setCoords(pt_next); + } + + return clip_count; + } + + private boolean isDegeneratePath_(MultiPathImpl mp_impl, int ipath) { + if (mp_impl.getPathSize(ipath) == 1) + return true; + Envelope2D env = new Envelope2D(); + mp_impl.queryPathEnvelope2D(ipath, env); + if (Math.max(env.getWidth(), env.getHeight()) < m_densify_dist * 0.5) + return true; + + return false; + } + + private boolean isDegenerateGeometry_(Geometry geom) { + Envelope2D env = new Envelope2D(); + geom.queryEnvelope2D(env); + if (Math.max(env.getWidth(), env.getHeight()) < m_densify_dist * 0.5) + return true; + + return false; + } + + private Polyline preparePolyline_(Polyline input_geom) { + // Generalize it firstly using 25% of the densification deviation as a + // criterion. + Polyline generalized_polyline = (Polyline) ((OperatorGeneralize) OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Generalize)).execute( + input_geom, m_densify_dist * 0.25, false, m_progress_tracker); + + int path_point_count = 0; + for (int i = 0, npath = generalized_polyline.getPathCount(); i < npath; i++) { + path_point_count = Math.max(generalized_polyline.getPathSize(i), + path_point_count); + } + + if (path_point_count < 32) { + m_bfilter = false; + return generalized_polyline; + } else { + m_bfilter = true; + // If we apply a filter to the polyline, then we have to resolve all + // self intersections. + Polyline simple_polyline = (Polyline) (TopologicalOperations + .planarSimplify(generalized_polyline, m_small_tolerance, + false, true, m_progress_tracker)); + // Operator_factory_local::SaveJSONToTextFileDbg("c:/temp/buffer_simplify.txt", + // *simple_polyline, nullptr); + return simple_polyline; + } + } + + private void addCircle_(MultiPathImpl result_mp, Point point) { + // Uses same calculations for each of the quadrants, generating a + // symmetric distribution of points. + Point2D center = point.getXY(); + if (m_circle_template != null && !m_circle_template.isEmpty()) {// use + // template + // if + // available. + Point2D p = new Point2D(); + p.setCoords(m_circle_template.get(0)); + p.scaleAdd(m_abs_distance, center); + result_mp.startPath(p); + for (int i = 1, n = (int) m_circle_template.size(); i < n; i++) { + p.setCoords(m_circle_template.get(i)); + p.scaleAdd(m_abs_distance, center); + result_mp.lineTo(p); + } + return; + } + + // avoid unnecessary memory allocation for the circle template. Just do + // the point here. + + int N = m_circle_template_size; + int real_size = (N + 3) / 4; + double dA = (Math.PI * 0.5) / real_size; + // result_mp.reserve(real_size * 4); + + double dcos = Math.cos(dA); + double dsin = Math.sin(dA); + Point2D pt = new Point2D(); + for (int quadrant = 3; quadrant >= 0; quadrant--) { + pt.setCoords(0.0, m_abs_distance); + switch (quadrant) { + case 0: {// upper left quadrant + for (int i = 0; i < real_size; i++) { + result_mp.lineTo(pt.x + center.x, pt.y + center.y); + pt.rotateReverse(dcos, dsin); + } + break; + } + case 1: {// upper left quadrant + for (int i = 0; i < real_size; i++) {// m_circle_template.set(i + // + real_size * 1, + // Point_2D::construct(-pt.y, + // pt.x)); + result_mp.lineTo(-pt.y + center.x, pt.x + center.y); + pt.rotateReverse(dcos, dsin); + } + break; + } + case 2: {// lower left quadrant + // m_circle_template.set(i + real_size * 2, + // Point_2D::construct(-pt.x, -pt.y)); + for (int i = 0; i < real_size; i++) { + result_mp.lineTo(-pt.x + center.x, -pt.y + center.y); + pt.rotateReverse(dcos, dsin); + } + break; + } + default:// case 3: + {// lower right quadrant + // m_circle_template.set(i + real_size * 3, + // Point_2D::construct(pt.y, -pt.x)); + result_mp.startPath(pt.y + center.x, -pt.x + center.y);// we + // start + // at + // the + // quadrant + // 3. + // The + // first + // point + // is + // (0, + // -m_distance) + // + + // center + for (int i = 1; i < real_size; i++) { + pt.rotateReverse(dcos, dsin); + result_mp.lineTo(pt.y + center.x, -pt.x + center.y); + } + break; + } + } + + progress_(); + } + } + + private static Polygon setWeakSimple_(Polygon poly) { + ((MultiPathImpl) poly._getImpl()).setIsSimple( + MultiVertexGeometryImpl.GeometryXSimple.Weak, 0.0, false); + return poly; + } + + private Polygon setStrongSimple_(Polygon poly) { + ((MultiPathImpl) poly._getImpl()).setIsSimple( + MultiVertexGeometryImpl.GeometryXSimple.Strong, m_tolerance, + false); + ((MultiPathImpl) poly._getImpl())._updateOGCFlags(); + return poly; + } } diff --git a/src/main/java/com/esri/core/geometry/ByteBufferCursor.java b/src/main/java/com/esri/core/geometry/ByteBufferCursor.java index 1e96a53c..7870ad4f 100644 --- a/src/main/java/com/esri/core/geometry/ByteBufferCursor.java +++ b/src/main/java/com/esri/core/geometry/ByteBufferCursor.java @@ -31,27 +31,27 @@ */ public abstract class ByteBufferCursor implements Iterator { - /** - * Moves the cursor to the next ByteBuffer. Returns null when reached the - * end. - */ - public abstract ByteBuffer next(); - - /** - * Returns the ID of the current ByteBuffer. The ID is propagated across the - * operations (when possible). - *

- * Returns an ID associated with the current Geometry. The ID is passed - * along and is returned by some operators to preserve relationship between - * the input and output geometry classes. It is not always possible to - * preserve an ID during an operation. - */ - public abstract long getByteBufferID(); - - public abstract SimpleStateEnum getSimpleState(); - - public abstract String getFeatureID(); - - public abstract boolean hasNext(); + /** + * Moves the cursor to the next ByteBuffer. Returns null when reached the + * end. + */ + public abstract ByteBuffer next(); + + /** + * Returns the ID of the current ByteBuffer. The ID is propagated across the + * operations (when possible). + *

+ * Returns an ID associated with the current Geometry. The ID is passed + * along and is returned by some operators to preserve relationship between + * the input and output geometry classes. It is not always possible to + * preserve an ID during an operation. + */ + public abstract long getByteBufferID(); + + public abstract SimpleStateEnum getSimpleState(); + + public abstract String getFeatureID(); + + public abstract boolean hasNext(); } diff --git a/src/main/java/com/esri/core/geometry/ClassicSort.java b/src/main/java/com/esri/core/geometry/ClassicSort.java index 8a5d0355..b6828897 100644 --- a/src/main/java/com/esri/core/geometry/ClassicSort.java +++ b/src/main/java/com/esri/core/geometry/ClassicSort.java @@ -28,8 +28,8 @@ package com.esri.core.geometry; abstract class ClassicSort { - public abstract void userSort(int begin, int end, - AttributeStreamOfInt32 indices); + public abstract void userSort(int begin, int end, + AttributeStreamOfInt32 indices); - public abstract double getValue(int index); + public abstract double getValue(int index); } diff --git a/src/main/java/com/esri/core/geometry/Clipper.java b/src/main/java/com/esri/core/geometry/Clipper.java index 08e19e8d..59dc9d1d 100644 --- a/src/main/java/com/esri/core/geometry/Clipper.java +++ b/src/main/java/com/esri/core/geometry/Clipper.java @@ -24,1249 +24,1249 @@ package com.esri.core.geometry; class Clipper { - Envelope2D m_extent; - EditShape m_shape; - int m_geometry; - int m_vertices_on_extent_index; - AttributeStreamOfInt32 m_vertices_on_extent; - - int checkSegmentIntersection_(Envelope2D seg_env, int side, - double clip_value) { - switch (side) { - case 0: - if (seg_env.xmin < clip_value && seg_env.xmax <= clip_value) { - return 0; // outside (or on the border) - } else if (seg_env.xmin >= clip_value) { - return 1;// inside - } else - return -1; // intersects - case 1: - if (seg_env.ymin < clip_value && seg_env.ymax <= clip_value) { - return 0; - } else if (seg_env.ymin >= clip_value) { - return 1; - } else - return -1; - case 2: - if (seg_env.xmin >= clip_value && seg_env.xmax > clip_value) { - return 0; - } else if (seg_env.xmax <= clip_value) { - return 1; - } else - return -1; - case 3: - if (seg_env.ymin >= clip_value && seg_env.ymax > clip_value) { - return 0; - } else if (seg_env.ymax <= clip_value) { - return 1; - } else - return -1; - } - assert (false);// cannot be here - return 0; - } - - MultiPath clipMultiPath2_(MultiPath multi_path_in, double tolerance, - double densify_dist) { - boolean b_is_polygon = multi_path_in.getType() == Geometry.Type.Polygon; - if (b_is_polygon) - return clipPolygon2_((Polygon) multi_path_in, tolerance, - densify_dist); - else - return clipPolyline_((Polyline) multi_path_in, tolerance); - } - - MultiPath clipPolygon2_(Polygon polygon_in, double tolerance, - double densify_dist) { - // If extent is degenerate, return 0. - if (m_extent.getWidth() == 0 || m_extent.getHeight() == 0) - return (MultiPath) polygon_in.createInstance(); - - Envelope2D orig_env2D = new Envelope2D(); - polygon_in.queryLooseEnvelope(orig_env2D); - - // m_shape = GCNEW Edit_shape(); - m_geometry = m_shape.addGeometry(polygon_in); - - // Forward decl for java port - Envelope2D seg_env = new Envelope2D(); - Envelope2D sub_seg_env = new Envelope2D(); - Point2D pt_1 = new Point2D(); - Point2D pt_2 = new Point2D(); - double[] result_ordinates = new double[9]; - double[] parameters = new double[9]; - SegmentBuffer sub_segment_buffer = new SegmentBuffer(); - Line line = new Line(); - AttributeStreamOfInt32 delete_candidates = new AttributeStreamOfInt32(0); - delete_candidates.reserve(Math.min(100, polygon_in.getPointCount())); - // clip the polygon successively by each plane - boolean b_all_outside = false; - for (int iclip_plane = 0; !b_all_outside && iclip_plane < 4; iclip_plane++) { - boolean b_intersects_plane = false; - boolean b_axis_x = (iclip_plane & 1) != 0; - double clip_value = 0; - switch (iclip_plane) { - case 0: - clip_value = m_extent.xmin; - b_intersects_plane = orig_env2D.xmin <= clip_value - && orig_env2D.xmax >= clip_value; - assert (b_intersects_plane || clip_value < orig_env2D.xmin); - break; - case 1: - clip_value = m_extent.ymin; - b_intersects_plane = orig_env2D.ymin <= clip_value - && orig_env2D.ymax >= clip_value; - assert (b_intersects_plane || clip_value < orig_env2D.ymin); - break; - case 2: - clip_value = m_extent.xmax; - b_intersects_plane = orig_env2D.xmin <= clip_value - && orig_env2D.xmax >= clip_value; - assert (b_intersects_plane || clip_value > orig_env2D.xmax); - break; - case 3: - clip_value = m_extent.ymax; - b_intersects_plane = orig_env2D.ymin <= clip_value - && orig_env2D.ymax >= clip_value; - assert (b_intersects_plane || clip_value > orig_env2D.ymax); - break; - } - - if (!b_intersects_plane) - continue;// Optimize for common case when only few sides of the - // clipper envelope intersect the geometry. - - b_all_outside = true; - for (int path = m_shape.getFirstPath(m_geometry); path != -1; ) { - int inside = -1; - int firstinside = -1; - int first = m_shape.getFirstVertex(path); - int vertex = first; - do { - Segment segment = m_shape.getSegment(vertex); - if (segment == null) { - segment = line; - m_shape.getXY(vertex, pt_1); - segment.setStartXY(pt_1); - m_shape.getXY(m_shape.getNextVertex(vertex), pt_2); - segment.setEndXY(pt_2); - } - segment.queryEnvelope2D(seg_env); - int seg_plane_intersection_status = checkSegmentIntersection_( - seg_env, iclip_plane, clip_value); - int split_count = 0; - int next_vertex = -1; - - if (seg_plane_intersection_status == -1) // intersects plane - { - int count = segment.intersectionWithAxis2D(b_axis_x, - clip_value, result_ordinates, parameters); - if (count > 0) { - split_count = m_shape.splitSegment(vertex, - parameters, count); - } else { - assert (count == 0);// might be -1 when the segment - // is almost parallel to the - // clip lane. Just to see this - // happens. - split_count = 0; - } - - // add +1 to ensure we check the original segment if no - // split produced due to degeneracy. - // Also +1 is necessary to check the last segment of the - // split - split_count += 1;// split_count will never be 0 after - // this if-block. - - int split_vert = vertex; - int next_split_vert = m_shape.getNextVertex(split_vert); - for (int i = 0; i < split_count; i++) { - m_shape.getXY(split_vert, pt_1); - m_shape.getXY(next_split_vert, pt_2); - - Segment sub_seg = m_shape.getSegment(split_vert); - if (sub_seg == null) { - sub_seg = line; - sub_seg.setStartXY(pt_1); - sub_seg.setEndXY(pt_2); - } - - sub_seg.queryEnvelope2D(sub_seg_env); - int sub_segment_plane_intersection_status = checkSegmentIntersection_( - sub_seg_env, iclip_plane, clip_value); - if (sub_segment_plane_intersection_status == -1) { - // subsegment is intertsecting the plane. We - // need to snap one of the endpoints to ensure - // no intersection. - // TODO: ensure this works for curves. For - // curves we have to adjust the curve shape. - if (!b_axis_x) { - assert ((pt_1.x < clip_value && pt_2.x > clip_value) || (pt_1.x > clip_value && pt_2.x < clip_value)); - double d_1 = Math.abs(pt_1.x - clip_value); - double d_2 = Math.abs(pt_2.x - clip_value); - if (d_1 < d_2) { - pt_1.x = clip_value; - m_shape.setXY(split_vert, pt_1); - } else { - pt_2.x = clip_value; - m_shape.setXY(next_split_vert, pt_2); - } - } else { - assert ((pt_1.y < clip_value && pt_2.y > clip_value) || (pt_1.y > clip_value && pt_2.y < clip_value)); - double d_1 = Math.abs(pt_1.y - clip_value); - double d_2 = Math.abs(pt_2.y - clip_value); - if (d_1 < d_2) { - pt_1.y = clip_value; - m_shape.setXY(split_vert, pt_1); - } else { - pt_2.y = clip_value; - m_shape.setXY(next_split_vert, pt_2); - } - } - - // after the endpoint has been adjusted, recheck - // the segment. - sub_seg = m_shape.getSegment(split_vert); - if (sub_seg == null) { - sub_seg = line; - sub_seg.setStartXY(pt_1); - sub_seg.setEndXY(pt_2); - } - sub_seg.queryEnvelope2D(sub_seg_env); - sub_segment_plane_intersection_status = checkSegmentIntersection_( - sub_seg_env, iclip_plane, clip_value); - } - - assert (sub_segment_plane_intersection_status != -1); - - int old_inside = inside; - inside = sub_segment_plane_intersection_status; - if (firstinside == -1) - firstinside = inside; - - // add connections along the clipping plane line - if (old_inside == 0 && inside == 1) { - // going from outside to inside. Do nothing - } else if (old_inside == 1 && inside == 0) { - // going from inside to outside - } else if (old_inside == 0 && inside == 0) { - // staying outside - // remember the start point of the outside - // segment to be deleted. - delete_candidates.add(split_vert); // is a - // candidate - // to be - // deleted - } - - if (inside == 1) { - b_all_outside = false; - } - - split_vert = next_split_vert; - next_vertex = split_vert; - next_split_vert = m_shape - .getNextVertex(next_split_vert); - } - } - - if (split_count == 0) { - assert (seg_plane_intersection_status != -1);// cannot - // happen. - int old_inside = inside; - inside = seg_plane_intersection_status; - if (firstinside == -1) - firstinside = inside; - - if (old_inside == 0 && inside == 1) { - // going from outside to inside. - } else if (old_inside == 1 && inside == 0) { - // going from inside to outside - } else if (old_inside == 0 && inside == 0) { - // remember the start point of the outside segment - // to be deleted. - delete_candidates.add(vertex); // is a candidate to - // be deleted - } - - if (inside == 1) { - b_all_outside = false; - } - - next_vertex = m_shape.getNextVertex(vertex); - } - vertex = next_vertex; - } while (vertex != first); - - if (firstinside == 0 && inside == 0) {// first vertex need to be - // deleted. - delete_candidates.add(first); // is a candidate to be - // deleted - } - - for (int i = 0, n = delete_candidates.size(); i < n; i++) { - int delete_vert = delete_candidates.get(i); - m_shape.removeVertex(delete_vert, false); - } - delete_candidates.clear(false); - if (m_shape.getPathSize(path) < 3) { - path = m_shape.removePath(path); - } else { - path = m_shape.getNextPath(path); - } - } - } - - if (b_all_outside) - return (MultiPath) polygon_in.createInstance(); - - // After the clipping, we could have produced unwanted segment overlaps - // along the clipping envelope boundary. - // Detect and resolve that case if possible. - resolveBoundaryOverlaps_(); - if (densify_dist > 0) - densifyAlongClipExtent_(densify_dist); - - return (MultiPath) m_shape.getGeometry(m_geometry); - } - - MultiPath clipPolyline_(Polyline polyline_in, double tolerance) { - // Forward decl for java port - Envelope2D seg_env = new Envelope2D(); - Envelope2D sub_seg_env = new Envelope2D(); - double[] result_ordinates = new double[9]; - double[] parameters = new double[9]; - SegmentBuffer sub_segment_buffer = new SegmentBuffer(); - MultiPath result_poly = polyline_in; - Envelope2D orig_env2D = new Envelope2D(); - polyline_in.queryLooseEnvelope(orig_env2D); - for (int iclip_plane = 0; iclip_plane < 4; iclip_plane++) { - boolean b_intersects_plane = false; - boolean b_axis_x = (iclip_plane & 1) != 0; - double clip_value = 0; - switch (iclip_plane) { - case 0: - clip_value = m_extent.xmin; - b_intersects_plane = orig_env2D.xmin <= clip_value - && orig_env2D.xmax >= clip_value; - assert (b_intersects_plane || clip_value < orig_env2D.xmin); - break; - case 1: - clip_value = m_extent.ymin; - b_intersects_plane = orig_env2D.ymin <= clip_value - && orig_env2D.ymax >= clip_value; - assert (b_intersects_plane || clip_value < orig_env2D.ymin); - break; - case 2: - clip_value = m_extent.xmax; - b_intersects_plane = orig_env2D.xmin <= clip_value - && orig_env2D.xmax >= clip_value; - assert (b_intersects_plane || clip_value > orig_env2D.xmax); - break; - case 3: - clip_value = m_extent.ymax; - b_intersects_plane = orig_env2D.ymin <= clip_value - && orig_env2D.ymax >= clip_value; - assert (b_intersects_plane || clip_value > orig_env2D.ymax); - break; - } - - if (!b_intersects_plane) - continue;// Optimize for common case when only few sides of the - // clipper envelope intersect the geometry. - - MultiPath src_poly = result_poly; - result_poly = (MultiPath) polyline_in.createInstance(); - - MultiPathImpl mp_impl_src = (MultiPathImpl) src_poly._getImpl(); - SegmentIteratorImpl seg_iter = mp_impl_src.querySegmentIterator(); - seg_iter.resetToFirstPath(); - Point2D pt_prev; - Point2D pt = new Point2D(); - while (seg_iter.nextPath()) { - int inside = -1; - boolean b_start_new_path = true; - while (seg_iter.hasNextSegment()) { - Segment segment = seg_iter.nextSegment(); - segment.queryEnvelope2D(seg_env); - int seg_plane_intersection_status = checkSegmentIntersection_( - seg_env, iclip_plane, clip_value); - if (seg_plane_intersection_status == -1) // intersects plane - { - int count = segment.intersectionWithAxis2D(b_axis_x, - clip_value, result_ordinates, parameters); - if (count > 0) { - double t0 = 0.0; - pt_prev = segment.getStartXY(); - for (int i = 0; i <= count; i++) { - double t = i < count ? parameters[i] : 1.0; - if (t0 == t) - continue; - - segment.cut(t0, t, sub_segment_buffer); - Segment sub_seg = sub_segment_buffer.get(); - sub_seg.setStartXY(pt_prev); - if (i < count) {// snap to plane - if (b_axis_x) { - pt.x = result_ordinates[i]; - pt.y = clip_value; - } else { - pt.x = clip_value; - pt.y = result_ordinates[i]; - } - sub_seg.setEndXY(pt); - } - - sub_seg.queryEnvelope2D(sub_seg_env); - int sub_segment_plane_intersection_status = checkSegmentIntersection_( - sub_seg_env, iclip_plane, clip_value); - - if (sub_segment_plane_intersection_status == -1) { - // subsegment is intertsecting the plane. We - // need to snap one of the endpoints to - // ensure no intersection. - // TODO: ensure this works for curves. For - // curves we have to adjust the curve shape. - Point2D pt_1 = sub_seg.getStartXY(); - Point2D pt_2 = sub_seg.getEndXY(); - if (!b_axis_x) { - assert ((pt_1.x < clip_value && pt_2.x > clip_value) || (pt_1.x > clip_value && pt_2.x < clip_value)); - double d_1 = Math.abs(pt_1.x - - clip_value); - double d_2 = Math.abs(pt_2.x - - clip_value); - if (d_1 < d_2) { - pt_1.x = clip_value; - sub_seg.setStartXY(pt_1); - } else { - pt_2.x = clip_value; - sub_seg.setEndXY(pt_2); - } - } else { - assert ((pt_1.y < clip_value && pt_2.y > clip_value) || (pt_1.y > clip_value && pt_2.y < clip_value)); - double d_1 = Math.abs(pt_1.y - - clip_value); - double d_2 = Math.abs(pt_2.y - - clip_value); - if (d_1 < d_2) { - pt_1.y = clip_value; - sub_seg.setStartXY(pt_1); - } else { - pt_2.y = clip_value; - sub_seg.setEndXY(pt_2); - } - } - - // after the endpoint has been adjusted, - // recheck the segment. - sub_seg.queryEnvelope2D(sub_seg_env); - sub_segment_plane_intersection_status = checkSegmentIntersection_( - sub_seg_env, iclip_plane, - clip_value); - } - - assert (sub_segment_plane_intersection_status != -1); - - pt_prev = sub_seg.getEndXY(); - t0 = t; - - inside = sub_segment_plane_intersection_status; - if (inside == 1) { - result_poly.addSegment(sub_seg, - b_start_new_path); - b_start_new_path = false; - } else - b_start_new_path = true; - } - } - } else { - inside = seg_plane_intersection_status; - if (inside == 1) { - result_poly.addSegment(segment, b_start_new_path); - b_start_new_path = false; - } else - b_start_new_path = true; - } - } - } - } - - return result_poly; - } - - void resolveBoundaryOverlaps_() { - m_vertices_on_extent_index = -1; - splitSegments_(false, m_extent.xmin); - splitSegments_(false, m_extent.xmax); - splitSegments_(true, m_extent.ymin); - splitSegments_(true, m_extent.ymax); - - m_vertices_on_extent.resize(0); - m_vertices_on_extent.reserve(100); - m_vertices_on_extent_index = m_shape.createUserIndex(); - - Point2D pt = new Point2D(); - for (int path = m_shape.getFirstPath(m_geometry); path != -1; path = m_shape - .getNextPath(path)) { - int vertex = m_shape.getFirstVertex(path); - for (int ivert = 0, nvert = m_shape.getPathSize(path); ivert < nvert; ivert++, vertex = m_shape - .getNextVertex(vertex)) { - m_shape.getXY(vertex, pt); - if (m_extent.xmin == pt.x || m_extent.xmax == pt.x - || m_extent.ymin == pt.y || m_extent.ymax == pt.y) { - m_shape.setUserIndex(vertex, m_vertices_on_extent_index, - m_vertices_on_extent.size()); - m_vertices_on_extent.add(vertex); - } - } - } - // dbg_check_path_first_(); - resolveOverlaps_(false, m_extent.xmin); - // dbg_check_path_first_(); - resolveOverlaps_(false, m_extent.xmax); - // dbg_check_path_first_(); - resolveOverlaps_(true, m_extent.ymin); - // dbg_check_path_first_(); - resolveOverlaps_(true, m_extent.ymax); - fixPaths_(); - } - - void densifyAlongClipExtent_(double densify_dist) { - assert (densify_dist > 0); - Point2D pt_1 = new Point2D(); - Point2D pt_2 = new Point2D(); - double[] split_scalars = new double[2048]; - for (int path = m_shape.getFirstPath(m_geometry); path != -1; path = m_shape - .getNextPath(path)) { - int first_vertex = m_shape.getFirstVertex(path); - int vertex = first_vertex; - do { - int next_vertex = m_shape.getNextVertex(vertex); - m_shape.getXY(vertex, pt_1); - int b_densify_x = -1; - if (pt_1.x == m_extent.xmin) { - m_shape.getXY(next_vertex, pt_2); - if (pt_2.x == m_extent.xmin) { - b_densify_x = 1; - } - } else if (pt_1.x == m_extent.xmax) { - m_shape.getXY(next_vertex, pt_2); - if (pt_2.x == m_extent.xmax) { - b_densify_x = 1; - } - } - - if (pt_1.y == m_extent.ymin) { - m_shape.getXY(next_vertex, pt_2); - if (pt_2.y == m_extent.ymin) { - b_densify_x = 0; - } - } else if (pt_1.y == m_extent.ymax) { - m_shape.getXY(next_vertex, pt_2); - if (pt_2.y == m_extent.ymax) { - b_densify_x = 0; - } - } - - if (b_densify_x == -1) { - vertex = next_vertex; - continue; - } - - double len = Point2D.distance(pt_1, pt_2); - int num = (int) Math.min(Math.ceil(len / densify_dist), 2048.0); - if (num <= 1) { - vertex = next_vertex; - continue; - } - - for (int i = 1; i < num; i++) { - split_scalars[i - 1] = (1.0 * i) / num; - } - - int actual_splits = m_shape.splitSegment(vertex, split_scalars, - num - 1); - assert (actual_splits == num - 1); - vertex = next_vertex; - } while (vertex != first_vertex); - } - } - - void splitSegments_(boolean b_axis_x, double clip_value) { - // After the clipping, we could have produced unwanted segment overlaps - // along the clipping envelope boundary. - // Detect and resolve that case if possible. - int usage_index = m_shape.createUserIndex(); - Point2D pt = new Point2D(); - AttributeStreamOfInt32 sorted_vertices = new AttributeStreamOfInt32(0); - sorted_vertices.reserve(100); - for (int path = m_shape.getFirstPath(m_geometry); path != -1; path = m_shape - .getNextPath(path)) { - int vertex = m_shape.getFirstVertex(path); - for (int ivert = 0, nvert = m_shape.getPathSize(path); ivert < nvert; ivert++) { - int next_vertex = m_shape.getNextVertex(vertex); - m_shape.getXY(vertex, pt); - if (b_axis_x ? pt.y == clip_value : pt.x == clip_value) { - m_shape.getXY(next_vertex, pt); - if (b_axis_x ? pt.y == clip_value : pt.x == clip_value) { - if (m_shape.getUserIndex(vertex, usage_index) != 1) { - sorted_vertices.add(vertex); - m_shape.setUserIndex(vertex, usage_index, 1); - } - - if (m_shape.getUserIndex(next_vertex, usage_index) != 1) { - sorted_vertices.add(next_vertex); - m_shape.setUserIndex(next_vertex, usage_index, 1); - } - } - } - vertex = next_vertex; - } - } - - m_shape.removeUserIndex(usage_index); - if (sorted_vertices.size() < 3) { - return; - } - - sorted_vertices.Sort(0, sorted_vertices.size(), - new ClipperVertexComparer(this)); - - Point2D pt_tmp = new Point2D(); // forward declare for java port - // optimization - Point2D pt_0 = new Point2D(); - Point2D pt_1 = new Point2D(); - pt_0.setNaN(); - int index_0 = -1; - AttributeStreamOfInt32 active_intervals = new AttributeStreamOfInt32(0); - AttributeStreamOfInt32 new_active_intervals = new AttributeStreamOfInt32( - 0); - - int node1 = m_shape.createUserIndex(); - int node2 = m_shape.createUserIndex(); - for (int index = 0, n = sorted_vertices.size(); index < n; index++) { - int vert = sorted_vertices.get(index); - m_shape.getXY(vert, pt); - if (!pt.isEqual(pt_0)) { - if (index_0 == -1) { - index_0 = index; - pt_0.setCoords(pt); - continue; - } - - // add new intervals, that started at pt_0 - for (int i = index_0; i < index; i++) { - int v = sorted_vertices.get(i); - int nextv = m_shape.getNextVertex(v); - int prevv = m_shape.getPrevVertex(v); - boolean bAdded = false; - if (compareVertices_(v, nextv) < 0) { - m_shape.getXY(nextv, pt_tmp); - if (b_axis_x ? pt_tmp.y == clip_value - : pt_tmp.x == clip_value) { - active_intervals.add(v); - bAdded = true; - m_shape.setUserIndex(v, node2, 1); - } - } - if (compareVertices_(v, prevv) < 0) { - m_shape.getXY(prevv, pt_tmp); - if (b_axis_x ? pt_tmp.y == clip_value - : pt_tmp.x == clip_value) { - if (!bAdded) - active_intervals.add(v); - m_shape.setUserIndex(v, node1, 1); - } - } - } - - // Split all active intervals at new point - for (int ia = 0, na = active_intervals.size(); ia < na; ia++) { - int v = active_intervals.get(ia); - int n_1 = m_shape.getUserIndex(v, node1); - int n_2 = m_shape.getUserIndex(v, node2); - if (n_1 == 1) { - int prevv = m_shape.getPrevVertex(v); - m_shape.getXY(prevv, pt_1); - double[] t = new double[1]; - t[0] = 0; - if (!pt_1.isEqual(pt)) {// Split the active segment - double active_segment_length = Point2D - .distance(pt_0, pt_1); - t[0] = Point2D.distance(pt_1, pt) - / active_segment_length; - assert (t[0] >= 0 && t[0] <= 1.0); - if (t[0] == 0) - t[0] = NumberUtils.doubleEps();// some - // roundoff - // issue. - // split - // anyway. - else if (t[0] == 1.0) { - t[0] = 1.0 - NumberUtils.doubleEps();// some - // roundoff - // issue. - // split - // anyway. - assert (t[0] != 1.0); - } - - int split_count = m_shape.splitSegment(prevv, - t, 1); - assert (split_count > 0); - int v_1 = m_shape.getPrevVertex(v); - m_shape.setXY(v_1, pt); - new_active_intervals.add(v_1); - m_shape.setUserIndex(v_1, node1, 1); - m_shape.setUserIndex(v_1, node2, -1); - } else { - // The active segment ends at the current point. - // We skip it, and it goes away. - } - } - if (n_2 == 1) { - int nextv = m_shape.getNextVertex(v); - m_shape.getXY(nextv, pt_1); - double[] t = new double[1]; - t[0] = 0; - if (!pt_1.isEqual(pt)) { - double active_segment_length = Point2D - .distance(pt_0, pt_1); - t[0] = Point2D.distance(pt_0, pt) - / active_segment_length; - assert (t[0] >= 0 && t[0] <= 1.0); - if (t[0] == 0) - t[0] = NumberUtils.doubleEps();// some - // roundoff - // issue. - // split - // anyway. - else if (t[0] == 1.0) { - t[0] = 1.0 - NumberUtils.doubleEps();// some - // roundoff - // issue. - // split - // anyway. - assert (t[0] != 1.0); - } - - int split_count = m_shape.splitSegment(v, t, 1); - assert (split_count > 0); - int v_1 = m_shape.getNextVertex(v); - m_shape.setXY(v_1, pt); - new_active_intervals.add(v_1); - m_shape.setUserIndex(v_1, node1, -1); - m_shape.setUserIndex(v_1, node2, 1); - } - } - } - - AttributeStreamOfInt32 tmp = active_intervals; - active_intervals = new_active_intervals; - new_active_intervals = tmp; - new_active_intervals.clear(false); - - index_0 = index; - pt_0.setCoords(pt); - } - } - - m_shape.removeUserIndex(node1); - m_shape.removeUserIndex(node2); - } - - void resolveOverlaps_(boolean b_axis_x, double clip_value) { - // Along the envelope boundary there could be overlapped segments. - // Example, exterior ring with a hole is cut with a line, that - // passes through the center of the hole. - // Detect pairs of opposite overlapping segments and get rid of them - Point2D pt = new Point2D(); - AttributeStreamOfInt32 sorted_vertices = new AttributeStreamOfInt32(0); - sorted_vertices.reserve(100); - int sorted_index = m_shape.createUserIndex(); - // DEBUGPRINTF(L"ee\n"); - for (int ivert = 0, nvert = m_vertices_on_extent.size(); ivert < nvert; ivert++) { - int vertex = m_vertices_on_extent.get(ivert); - if (vertex == -1) - continue; - - int next_vertex = m_shape.getNextVertex(vertex); - m_shape.getXY(vertex, pt); - // DEBUGPRINTF(L"%f\t%f\n", pt.x, pt.y); - if (b_axis_x ? pt.y == clip_value : pt.x == clip_value) { - m_shape.getXY(next_vertex, pt); - if (b_axis_x ? pt.y == clip_value : pt.x == clip_value) { - assert (m_shape.getUserIndex(next_vertex, - m_vertices_on_extent_index) != -1); - if (m_shape.getUserIndex(vertex, sorted_index) != -2) { - sorted_vertices.add(vertex);// remember the vertex. The - // attached segment belongs - // to the given clip plane. - m_shape.setUserIndex(vertex, sorted_index, -2); - } - - if (m_shape.getUserIndex(next_vertex, sorted_index) != -2) { - sorted_vertices.add(next_vertex); - m_shape.setUserIndex(next_vertex, sorted_index, -2); - } - } - } - } - - if (sorted_vertices.size() == 0) { - m_shape.removeUserIndex(sorted_index); - return; - } - - sorted_vertices.Sort(0, sorted_vertices.size(), - new ClipperVertexComparer(this)); - // std::sort(sorted_vertices.get_ptr(), sorted_vertices.get_ptr() + - // sorted_vertices.size(), Clipper_vertex_comparer(this)); - - // DEBUGPRINTF(L"**\n"); - for (int index = 0, n = sorted_vertices.size(); index < n; index++) { - int vert = sorted_vertices.get(index); - m_shape.setUserIndex(vert, sorted_index, index); - // Point_2D pt; - // m_shape.get_xy(vert, pt); - // DEBUGPRINTF(L"%f\t%f\t%d\n", pt.x, pt.y, vert); - } - - Point2D pt_tmp = new Point2D(); - Point2D pt_0 = new Point2D(); - pt_0.setNaN(); - int index_0 = -1; - for (int index = 0, n = sorted_vertices.size(); index < n; index++) { - int vert = sorted_vertices.get(index); - if (vert == -1) - continue; - - m_shape.getXY(vert, pt); - if (!pt.isEqual(pt_0)) { - if (index_0 != -1) { - while (true) { - boolean b_overlap_resolved = false; - int index_to = index - index_0 > 1 ? index - 1 : index; - for (int i = index_0; i < index_to; i++) { - int v = sorted_vertices.get(i); - if (v == -1) - continue; - int nextv = -1; - int nv = m_shape.getNextVertex(v); - if (compareVertices_(v, nv) < 0) { - m_shape.getXY(nv, pt_tmp); - if (b_axis_x ? pt_tmp.y == clip_value - : pt_tmp.x == clip_value) - nextv = nv; - } - int prevv = -1; - int pv = m_shape.getPrevVertex(v); - if (compareVertices_(v, pv) < 0) { - m_shape.getXY(pv, pt_tmp); - if (b_axis_x ? pt_tmp.y == clip_value - : pt_tmp.x == clip_value) - prevv = pv; - } - - if (nextv != -1 && prevv != -1) { - // we have a cusp here. remove the vertex. - beforeRemoveVertex_(v, sorted_vertices, - sorted_index); - m_shape.removeVertex(v, false); - beforeRemoveVertex_(nextv, sorted_vertices, - sorted_index); - m_shape.removeVertex(nextv, false); - b_overlap_resolved = true; - continue; - } - - if (nextv == -1 && prevv == -1) - continue; - - for (int j = i + 1; j < index; j++) { - int v_1 = sorted_vertices.get(j); - if (v_1 == -1) - continue; - int nv1 = m_shape.getNextVertex(v_1); - int nextv1 = -1; - if (compareVertices_(v_1, nv1) < 0) { - m_shape.getXY(nv1, pt_tmp); - if (b_axis_x ? pt_tmp.y == clip_value - : pt_tmp.x == clip_value) - nextv1 = nv1; - } - - int pv1 = m_shape.getPrevVertex(v_1); - int prevv_1 = -1; - if (compareVertices_(v_1, pv1) < 0) { - m_shape.getXY(pv1, pt_tmp); - if (b_axis_x ? pt_tmp.y == clip_value - : pt_tmp.x == clip_value) - prevv_1 = pv1; - } - if (nextv1 != -1 && prevv_1 != -1) { - // we have a cusp here. remove the vertex. - beforeRemoveVertex_(v_1, sorted_vertices, - sorted_index); - m_shape.removeVertex(v_1, false); - beforeRemoveVertex_(nextv1, - sorted_vertices, sorted_index); - m_shape.removeVertex(nextv1, false); - b_overlap_resolved = true; - break; - } - if (nextv != -1 && prevv_1 != -1) { - removeOverlap_(sorted_vertices, v, nextv, - v_1, prevv_1, sorted_index); - b_overlap_resolved = true; - break; - } else if (prevv != -1 && nextv1 != -1) { - removeOverlap_(sorted_vertices, v_1, - nextv1, v, prevv, sorted_index); - b_overlap_resolved = true; - break; - } - } - - if (b_overlap_resolved) - break; - } - - if (!b_overlap_resolved) - break; - } - } - - index_0 = index; - pt_0.setCoords(pt); - } - } - - m_shape.removeUserIndex(sorted_index); - } - - void beforeRemoveVertex_(int v_1, AttributeStreamOfInt32 sorted_vertices, - int sorted_index) { - int ind = m_shape.getUserIndex(v_1, sorted_index); - sorted_vertices.set(ind, -1); - ind = m_shape.getUserIndex(v_1, m_vertices_on_extent_index); - m_vertices_on_extent.set(ind, -1); - int path = m_shape.getPathFromVertex(v_1); - if (path != -1) { - int first = m_shape.getFirstVertex(path); - if (first == v_1) { - m_shape.setFirstVertex_(path, -1); - m_shape.setLastVertex_(path, -1); - } - } - } - - void removeOverlap_(AttributeStreamOfInt32 sorted_vertices, int v, - int nextv, int v_1, int prevv_1, int sorted_index) { - assert (m_shape.isEqualXY(v, v_1)); - assert (m_shape.isEqualXY(nextv, prevv_1)); - assert (m_shape.getNextVertex(v) == nextv); - assert (m_shape.getNextVertex(prevv_1) == v_1); - m_shape.setNextVertex_(v, v_1); - m_shape.setPrevVertex_(v_1, v); - m_shape.setPrevVertex_(nextv, prevv_1); - m_shape.setNextVertex_(prevv_1, nextv); - - beforeRemoveVertex_(v_1, sorted_vertices, sorted_index); - m_shape.removeVertexInternal_(v_1, false); - beforeRemoveVertex_(prevv_1, sorted_vertices, sorted_index); - m_shape.removeVertexInternal_(prevv_1, true); - } - - void fixPaths_() { - for (int ivert = 0, nvert = m_vertices_on_extent.size(); ivert < nvert; ivert++) { - int vertex = m_vertices_on_extent.get(ivert); - if (vertex != -1) - m_shape.setPathToVertex_(vertex, -1); - } - - int path_count = 0; - int geometry_size = 0; - for (int path = m_shape.getFirstPath(m_geometry); path != -1; ) { - int first = m_shape.getFirstVertex(path); - if (first == -1 || path != m_shape.getPathFromVertex(first)) { // The - // path's - // first - // vertex - // has - // been - // deleted. - // Or - // the - // path - // first - // vertex - // is - // now - // part - // of - // another - // path. - // We - // have - // to - // delete - // such - // path - // object. - int p = path; - path = m_shape.getNextPath(path); - m_shape.setFirstVertex_(p, -1); - m_shape.removePathOnly_(p); - continue; - } - assert (path == m_shape.getPathFromVertex(first)); - int vertex = first; - int path_size = 0; - do { - m_shape.setPathToVertex_(vertex, path); - path_size++; - vertex = m_shape.getNextVertex(vertex); - } while (vertex != first); - - if (path_size <= 2) { - int ind = m_shape.getUserIndex(first, - m_vertices_on_extent_index); - m_vertices_on_extent.set(ind, -1); - int nv = m_shape.removeVertex(first, false); - if (path_size == 2) { - ind = m_shape.getUserIndex(nv, m_vertices_on_extent_index); - m_vertices_on_extent.set(ind, -1); - m_shape.removeVertex(nv, false); - } - int p = path; - path = m_shape.getNextPath(path); - m_shape.setFirstVertex_(p, -1); - m_shape.removePathOnly_(p); - continue; - } - - m_shape.setRingAreaValid_(path, false); - m_shape.setLastVertex_(path, m_shape.getPrevVertex(first)); - m_shape.setPathSize_(path, path_size); - geometry_size += path_size; - path_count++; - path = m_shape.getNextPath(path); - } - - for (int ivert = 0, nvert = m_vertices_on_extent.size(); ivert < nvert; ivert++) { - int vertex = m_vertices_on_extent.get(ivert); - if (vertex == -1) - continue; - int path = m_shape.getPathFromVertex(vertex); - if (path != -1) - continue; - - path = m_shape.insertPath(m_geometry, -1); - int path_size = 0; - int first = vertex; - do { - m_shape.setPathToVertex_(vertex, path); - path_size++; - vertex = m_shape.getNextVertex(vertex); - } while (vertex != first); - - if (path_size <= 2) { - int ind = m_shape.getUserIndex(first, - m_vertices_on_extent_index); - m_vertices_on_extent.set(ind, -1); - int nv = m_shape.removeVertex(first, false); - if (path_size == 2) { - ind = m_shape.getUserIndex(nv, m_vertices_on_extent_index); - if (ind >= 0) - m_vertices_on_extent.set(ind, -1); - else { - // this vertex is not on the extent. - } - m_shape.removeVertex(nv, false); - } - - int p = path; - path = m_shape.getNextPath(path); - m_shape.setFirstVertex_(p, -1); - m_shape.removePathOnly_(p); - continue; - } - - m_shape.setClosedPath(path, true); - m_shape.setPathSize_(path, path_size); - m_shape.setFirstVertex_(path, first); - m_shape.setLastVertex_(path, m_shape.getPrevVertex(first)); - m_shape.setRingAreaValid_(path, false); - geometry_size += path_size; - path_count++; - } - - m_shape.setGeometryPathCount_(m_geometry, path_count); - m_shape.setGeometryVertexCount_(m_geometry, geometry_size); - - int total_point_count = 0; - for (int geometry = m_shape.getFirstGeometry(); geometry != -1; geometry = m_shape - .getNextGeometry(geometry)) { - total_point_count += m_shape.getPointCount(geometry); - } - - m_shape.setTotalPointCount_(total_point_count); - } - - static Geometry clipMultiPath_(MultiPath multipath, Envelope2D extent, - double tolerance, double densify_dist) { - Clipper clipper = new Clipper(extent); - return clipper.clipMultiPath2_(multipath, tolerance, densify_dist); - } - - Clipper(Envelope2D extent) { - m_extent = extent; - m_shape = new EditShape(); - m_vertices_on_extent = new AttributeStreamOfInt32(0); - } - - // static std::shared_ptr create_polygon_from_polyline(const - // std::shared_ptr& polyline, const Envelope_2D& env_2D, bool - // add_envelope, double tolerance, double densify_dist, int - // corner_is_inside); - static Geometry clip(Geometry geometry, Envelope2D extent, - double tolerance, double densify_dist) { - if (geometry.isEmpty()) - return geometry; - - if (extent.isEmpty()) - return geometry.createInstance(); // return an empty geometry - - int geomtype = geometry.getType().value(); - - // Test firstly the simplest geometry types point and envelope. - // After that we'll check the envelope intersection for the optimization - if (geomtype == Geometry.Type.Point.value()) { - Point2D pt = ((Point) geometry).getXY(); - if (extent.contains(pt)) - return geometry; - else - return geometry.createInstance(); // return an empty geometry - } else if (geomtype == Geometry.Type.Envelope.value()) { - Envelope2D env = new Envelope2D(); - geometry.queryEnvelope2D(env); - if (env.intersect(extent)) { - Envelope result_env = new Envelope(); - geometry.copyTo(result_env); - result_env.setEnvelope2D(env); - return result_env; - } else - return geometry.createInstance(); // return an empty geometry - } - - // Test the geometry envelope - Envelope2D env_2D = new Envelope2D(); - geometry.queryLooseEnvelope2D(env_2D); - if (extent.contains(env_2D)) - return geometry;// completely inside of bounds - if (!extent.isIntersecting(env_2D)) - return geometry.createInstance();// outside of bounds. return empty - // geometry. - - MultiVertexGeometryImpl impl = (MultiVertexGeometryImpl) geometry - ._getImpl(); - GeometryAccelerators accel = impl._getAccelerators(); - if (accel != null) { - RasterizedGeometry2D rgeom = accel.getRasterizedGeometry(); - if (rgeom != null) { - RasterizedGeometry2D.HitType hit = rgeom - .queryEnvelopeInGeometry(extent); - if (hit == RasterizedGeometry2D.HitType.Inside) { - if (geomtype != Geometry.Type.Polygon.value()) - throw GeometryException.GeometryInternalError(); - - Polygon poly = new Polygon(geometry.getDescription()); - poly.addEnvelope(extent, false); - return poly; - } else if (hit == RasterizedGeometry2D.HitType.Outside) { - return geometry.createInstance();// outside of bounds. - // return empty - // geometry. - } - } - } - - switch (geomtype) { - case Geometry.GeometryType.MultiPoint: { - MultiPoint multi_point = (MultiPoint) geometry; - MultiPoint multi_point_out = null; - int npoints = multi_point.getPointCount(); - AttributeStreamOfDbl xy = (AttributeStreamOfDbl) ((MultiPointImpl) multi_point - ._getImpl()) - .getAttributeStreamRef(VertexDescription.Semantics.POSITION); - // create the new geometry only if there are points that has been - // clipped out. - // If all vertices are inside of the envelope, it returns the input - // multipoint. - int ipoints0 = 0; - for (int ipoints = 0; ipoints < npoints; ipoints++) { - Point2D pt = new Point2D(); - xy.read(2 * ipoints, pt); - - if (!extent.contains(pt)) {// vertex is outside of the envelope - if (ipoints0 == 0) - multi_point_out = (MultiPoint) multi_point - .createInstance(); - - if (ipoints0 < ipoints) - multi_point_out.add(multi_point, ipoints0, ipoints); - - ipoints0 = ipoints + 1;// ipoints0 contains index of vertex - // right after the last clipped out - // vertex. - } - } - - // add the rest of the batch to the result multipoint (only if - // something has been already clipped out) - if (ipoints0 > 0) - multi_point_out.add(multi_point, ipoints0, npoints); - - if (ipoints0 == 0) - return multi_point;// everything is inside, so return the input - // geometry - else - return multi_point_out;// clipping has happend, return the - // clipped geometry - } - case Geometry.GeometryType.Polygon: - case Geometry.GeometryType.Polyline: - return clipMultiPath_((MultiPath) geometry, extent, tolerance, - densify_dist); - default: - assert (false); - throw GeometryException.GeometryInternalError(); - } - } - - int compareVertices_(int v_1, int v_2) { - Point2D pt_1 = new Point2D(); - m_shape.getXY(v_1, pt_1); - Point2D pt_2 = new Point2D(); - m_shape.getXY(v_2, pt_2); - int res = pt_1.compare(pt_2); - return res; - } - - static final class ClipperVertexComparer extends - AttributeStreamOfInt32.IntComparator { - Clipper m_clipper; - - ClipperVertexComparer(Clipper clipper) { - m_clipper = clipper; - } - - @Override - public int compare(int v1, int v2) { - return m_clipper.compareVertices_(v1, v2); - } - - } + Envelope2D m_extent; + EditShape m_shape; + int m_geometry; + int m_vertices_on_extent_index; + AttributeStreamOfInt32 m_vertices_on_extent; + + int checkSegmentIntersection_(Envelope2D seg_env, int side, + double clip_value) { + switch (side) { + case 0: + if (seg_env.xmin < clip_value && seg_env.xmax <= clip_value) { + return 0; // outside (or on the border) + } else if (seg_env.xmin >= clip_value) { + return 1;// inside + } else + return -1; // intersects + case 1: + if (seg_env.ymin < clip_value && seg_env.ymax <= clip_value) { + return 0; + } else if (seg_env.ymin >= clip_value) { + return 1; + } else + return -1; + case 2: + if (seg_env.xmin >= clip_value && seg_env.xmax > clip_value) { + return 0; + } else if (seg_env.xmax <= clip_value) { + return 1; + } else + return -1; + case 3: + if (seg_env.ymin >= clip_value && seg_env.ymax > clip_value) { + return 0; + } else if (seg_env.ymax <= clip_value) { + return 1; + } else + return -1; + } + assert (false);// cannot be here + return 0; + } + + MultiPath clipMultiPath2_(MultiPath multi_path_in, double tolerance, + double densify_dist) { + boolean b_is_polygon = multi_path_in.getType() == Geometry.Type.Polygon; + if (b_is_polygon) + return clipPolygon2_((Polygon) multi_path_in, tolerance, + densify_dist); + else + return clipPolyline_((Polyline) multi_path_in, tolerance); + } + + MultiPath clipPolygon2_(Polygon polygon_in, double tolerance, + double densify_dist) { + // If extent is degenerate, return 0. + if (m_extent.getWidth() == 0 || m_extent.getHeight() == 0) + return (MultiPath) polygon_in.createInstance(); + + Envelope2D orig_env2D = new Envelope2D(); + polygon_in.queryLooseEnvelope(orig_env2D); + + // m_shape = GCNEW Edit_shape(); + m_geometry = m_shape.addGeometry(polygon_in); + + // Forward decl for java port + Envelope2D seg_env = new Envelope2D(); + Envelope2D sub_seg_env = new Envelope2D(); + Point2D pt_1 = new Point2D(); + Point2D pt_2 = new Point2D(); + double[] result_ordinates = new double[9]; + double[] parameters = new double[9]; + SegmentBuffer sub_segment_buffer = new SegmentBuffer(); + Line line = new Line(); + AttributeStreamOfInt32 delete_candidates = new AttributeStreamOfInt32(0); + delete_candidates.reserve(Math.min(100, polygon_in.getPointCount())); + // clip the polygon successively by each plane + boolean b_all_outside = false; + for (int iclip_plane = 0; !b_all_outside && iclip_plane < 4; iclip_plane++) { + boolean b_intersects_plane = false; + boolean b_axis_x = (iclip_plane & 1) != 0; + double clip_value = 0; + switch (iclip_plane) { + case 0: + clip_value = m_extent.xmin; + b_intersects_plane = orig_env2D.xmin <= clip_value + && orig_env2D.xmax >= clip_value; + assert (b_intersects_plane || clip_value < orig_env2D.xmin); + break; + case 1: + clip_value = m_extent.ymin; + b_intersects_plane = orig_env2D.ymin <= clip_value + && orig_env2D.ymax >= clip_value; + assert (b_intersects_plane || clip_value < orig_env2D.ymin); + break; + case 2: + clip_value = m_extent.xmax; + b_intersects_plane = orig_env2D.xmin <= clip_value + && orig_env2D.xmax >= clip_value; + assert (b_intersects_plane || clip_value > orig_env2D.xmax); + break; + case 3: + clip_value = m_extent.ymax; + b_intersects_plane = orig_env2D.ymin <= clip_value + && orig_env2D.ymax >= clip_value; + assert (b_intersects_plane || clip_value > orig_env2D.ymax); + break; + } + + if (!b_intersects_plane) + continue;// Optimize for common case when only few sides of the + // clipper envelope intersect the geometry. + + b_all_outside = true; + for (int path = m_shape.getFirstPath(m_geometry); path != -1; ) { + int inside = -1; + int firstinside = -1; + int first = m_shape.getFirstVertex(path); + int vertex = first; + do { + Segment segment = m_shape.getSegment(vertex); + if (segment == null) { + segment = line; + m_shape.getXY(vertex, pt_1); + segment.setStartXY(pt_1); + m_shape.getXY(m_shape.getNextVertex(vertex), pt_2); + segment.setEndXY(pt_2); + } + segment.queryEnvelope2D(seg_env); + int seg_plane_intersection_status = checkSegmentIntersection_( + seg_env, iclip_plane, clip_value); + int split_count = 0; + int next_vertex = -1; + + if (seg_plane_intersection_status == -1) // intersects plane + { + int count = segment.intersectionWithAxis2D(b_axis_x, + clip_value, result_ordinates, parameters); + if (count > 0) { + split_count = m_shape.splitSegment(vertex, + parameters, count); + } else { + assert (count == 0);// might be -1 when the segment + // is almost parallel to the + // clip lane. Just to see this + // happens. + split_count = 0; + } + + // add +1 to ensure we check the original segment if no + // split produced due to degeneracy. + // Also +1 is necessary to check the last segment of the + // split + split_count += 1;// split_count will never be 0 after + // this if-block. + + int split_vert = vertex; + int next_split_vert = m_shape.getNextVertex(split_vert); + for (int i = 0; i < split_count; i++) { + m_shape.getXY(split_vert, pt_1); + m_shape.getXY(next_split_vert, pt_2); + + Segment sub_seg = m_shape.getSegment(split_vert); + if (sub_seg == null) { + sub_seg = line; + sub_seg.setStartXY(pt_1); + sub_seg.setEndXY(pt_2); + } + + sub_seg.queryEnvelope2D(sub_seg_env); + int sub_segment_plane_intersection_status = checkSegmentIntersection_( + sub_seg_env, iclip_plane, clip_value); + if (sub_segment_plane_intersection_status == -1) { + // subsegment is intertsecting the plane. We + // need to snap one of the endpoints to ensure + // no intersection. + // TODO: ensure this works for curves. For + // curves we have to adjust the curve shape. + if (!b_axis_x) { + assert ((pt_1.x < clip_value && pt_2.x > clip_value) || (pt_1.x > clip_value && pt_2.x < clip_value)); + double d_1 = Math.abs(pt_1.x - clip_value); + double d_2 = Math.abs(pt_2.x - clip_value); + if (d_1 < d_2) { + pt_1.x = clip_value; + m_shape.setXY(split_vert, pt_1); + } else { + pt_2.x = clip_value; + m_shape.setXY(next_split_vert, pt_2); + } + } else { + assert ((pt_1.y < clip_value && pt_2.y > clip_value) || (pt_1.y > clip_value && pt_2.y < clip_value)); + double d_1 = Math.abs(pt_1.y - clip_value); + double d_2 = Math.abs(pt_2.y - clip_value); + if (d_1 < d_2) { + pt_1.y = clip_value; + m_shape.setXY(split_vert, pt_1); + } else { + pt_2.y = clip_value; + m_shape.setXY(next_split_vert, pt_2); + } + } + + // after the endpoint has been adjusted, recheck + // the segment. + sub_seg = m_shape.getSegment(split_vert); + if (sub_seg == null) { + sub_seg = line; + sub_seg.setStartXY(pt_1); + sub_seg.setEndXY(pt_2); + } + sub_seg.queryEnvelope2D(sub_seg_env); + sub_segment_plane_intersection_status = checkSegmentIntersection_( + sub_seg_env, iclip_plane, clip_value); + } + + assert (sub_segment_plane_intersection_status != -1); + + int old_inside = inside; + inside = sub_segment_plane_intersection_status; + if (firstinside == -1) + firstinside = inside; + + // add connections along the clipping plane line + if (old_inside == 0 && inside == 1) { + // going from outside to inside. Do nothing + } else if (old_inside == 1 && inside == 0) { + // going from inside to outside + } else if (old_inside == 0 && inside == 0) { + // staying outside + // remember the start point of the outside + // segment to be deleted. + delete_candidates.add(split_vert); // is a + // candidate + // to be + // deleted + } + + if (inside == 1) { + b_all_outside = false; + } + + split_vert = next_split_vert; + next_vertex = split_vert; + next_split_vert = m_shape + .getNextVertex(next_split_vert); + } + } + + if (split_count == 0) { + assert (seg_plane_intersection_status != -1);// cannot + // happen. + int old_inside = inside; + inside = seg_plane_intersection_status; + if (firstinside == -1) + firstinside = inside; + + if (old_inside == 0 && inside == 1) { + // going from outside to inside. + } else if (old_inside == 1 && inside == 0) { + // going from inside to outside + } else if (old_inside == 0 && inside == 0) { + // remember the start point of the outside segment + // to be deleted. + delete_candidates.add(vertex); // is a candidate to + // be deleted + } + + if (inside == 1) { + b_all_outside = false; + } + + next_vertex = m_shape.getNextVertex(vertex); + } + vertex = next_vertex; + } while (vertex != first); + + if (firstinside == 0 && inside == 0) {// first vertex need to be + // deleted. + delete_candidates.add(first); // is a candidate to be + // deleted + } + + for (int i = 0, n = delete_candidates.size(); i < n; i++) { + int delete_vert = delete_candidates.get(i); + m_shape.removeVertex(delete_vert, false); + } + delete_candidates.clear(false); + if (m_shape.getPathSize(path) < 3) { + path = m_shape.removePath(path); + } else { + path = m_shape.getNextPath(path); + } + } + } + + if (b_all_outside) + return (MultiPath) polygon_in.createInstance(); + + // After the clipping, we could have produced unwanted segment overlaps + // along the clipping envelope boundary. + // Detect and resolve that case if possible. + resolveBoundaryOverlaps_(); + if (densify_dist > 0) + densifyAlongClipExtent_(densify_dist); + + return (MultiPath) m_shape.getGeometry(m_geometry); + } + + MultiPath clipPolyline_(Polyline polyline_in, double tolerance) { + // Forward decl for java port + Envelope2D seg_env = new Envelope2D(); + Envelope2D sub_seg_env = new Envelope2D(); + double[] result_ordinates = new double[9]; + double[] parameters = new double[9]; + SegmentBuffer sub_segment_buffer = new SegmentBuffer(); + MultiPath result_poly = polyline_in; + Envelope2D orig_env2D = new Envelope2D(); + polyline_in.queryLooseEnvelope(orig_env2D); + for (int iclip_plane = 0; iclip_plane < 4; iclip_plane++) { + boolean b_intersects_plane = false; + boolean b_axis_x = (iclip_plane & 1) != 0; + double clip_value = 0; + switch (iclip_plane) { + case 0: + clip_value = m_extent.xmin; + b_intersects_plane = orig_env2D.xmin <= clip_value + && orig_env2D.xmax >= clip_value; + assert (b_intersects_plane || clip_value < orig_env2D.xmin); + break; + case 1: + clip_value = m_extent.ymin; + b_intersects_plane = orig_env2D.ymin <= clip_value + && orig_env2D.ymax >= clip_value; + assert (b_intersects_plane || clip_value < orig_env2D.ymin); + break; + case 2: + clip_value = m_extent.xmax; + b_intersects_plane = orig_env2D.xmin <= clip_value + && orig_env2D.xmax >= clip_value; + assert (b_intersects_plane || clip_value > orig_env2D.xmax); + break; + case 3: + clip_value = m_extent.ymax; + b_intersects_plane = orig_env2D.ymin <= clip_value + && orig_env2D.ymax >= clip_value; + assert (b_intersects_plane || clip_value > orig_env2D.ymax); + break; + } + + if (!b_intersects_plane) + continue;// Optimize for common case when only few sides of the + // clipper envelope intersect the geometry. + + MultiPath src_poly = result_poly; + result_poly = (MultiPath) polyline_in.createInstance(); + + MultiPathImpl mp_impl_src = (MultiPathImpl) src_poly._getImpl(); + SegmentIteratorImpl seg_iter = mp_impl_src.querySegmentIterator(); + seg_iter.resetToFirstPath(); + Point2D pt_prev; + Point2D pt = new Point2D(); + while (seg_iter.nextPath()) { + int inside = -1; + boolean b_start_new_path = true; + while (seg_iter.hasNextSegment()) { + Segment segment = seg_iter.nextSegment(); + segment.queryEnvelope2D(seg_env); + int seg_plane_intersection_status = checkSegmentIntersection_( + seg_env, iclip_plane, clip_value); + if (seg_plane_intersection_status == -1) // intersects plane + { + int count = segment.intersectionWithAxis2D(b_axis_x, + clip_value, result_ordinates, parameters); + if (count > 0) { + double t0 = 0.0; + pt_prev = segment.getStartXY(); + for (int i = 0; i <= count; i++) { + double t = i < count ? parameters[i] : 1.0; + if (t0 == t) + continue; + + segment.cut(t0, t, sub_segment_buffer); + Segment sub_seg = sub_segment_buffer.get(); + sub_seg.setStartXY(pt_prev); + if (i < count) {// snap to plane + if (b_axis_x) { + pt.x = result_ordinates[i]; + pt.y = clip_value; + } else { + pt.x = clip_value; + pt.y = result_ordinates[i]; + } + sub_seg.setEndXY(pt); + } + + sub_seg.queryEnvelope2D(sub_seg_env); + int sub_segment_plane_intersection_status = checkSegmentIntersection_( + sub_seg_env, iclip_plane, clip_value); + + if (sub_segment_plane_intersection_status == -1) { + // subsegment is intertsecting the plane. We + // need to snap one of the endpoints to + // ensure no intersection. + // TODO: ensure this works for curves. For + // curves we have to adjust the curve shape. + Point2D pt_1 = sub_seg.getStartXY(); + Point2D pt_2 = sub_seg.getEndXY(); + if (!b_axis_x) { + assert ((pt_1.x < clip_value && pt_2.x > clip_value) || (pt_1.x > clip_value && pt_2.x < clip_value)); + double d_1 = Math.abs(pt_1.x + - clip_value); + double d_2 = Math.abs(pt_2.x + - clip_value); + if (d_1 < d_2) { + pt_1.x = clip_value; + sub_seg.setStartXY(pt_1); + } else { + pt_2.x = clip_value; + sub_seg.setEndXY(pt_2); + } + } else { + assert ((pt_1.y < clip_value && pt_2.y > clip_value) || (pt_1.y > clip_value && pt_2.y < clip_value)); + double d_1 = Math.abs(pt_1.y + - clip_value); + double d_2 = Math.abs(pt_2.y + - clip_value); + if (d_1 < d_2) { + pt_1.y = clip_value; + sub_seg.setStartXY(pt_1); + } else { + pt_2.y = clip_value; + sub_seg.setEndXY(pt_2); + } + } + + // after the endpoint has been adjusted, + // recheck the segment. + sub_seg.queryEnvelope2D(sub_seg_env); + sub_segment_plane_intersection_status = checkSegmentIntersection_( + sub_seg_env, iclip_plane, + clip_value); + } + + assert (sub_segment_plane_intersection_status != -1); + + pt_prev = sub_seg.getEndXY(); + t0 = t; + + inside = sub_segment_plane_intersection_status; + if (inside == 1) { + result_poly.addSegment(sub_seg, + b_start_new_path); + b_start_new_path = false; + } else + b_start_new_path = true; + } + } + } else { + inside = seg_plane_intersection_status; + if (inside == 1) { + result_poly.addSegment(segment, b_start_new_path); + b_start_new_path = false; + } else + b_start_new_path = true; + } + } + } + } + + return result_poly; + } + + void resolveBoundaryOverlaps_() { + m_vertices_on_extent_index = -1; + splitSegments_(false, m_extent.xmin); + splitSegments_(false, m_extent.xmax); + splitSegments_(true, m_extent.ymin); + splitSegments_(true, m_extent.ymax); + + m_vertices_on_extent.resize(0); + m_vertices_on_extent.reserve(100); + m_vertices_on_extent_index = m_shape.createUserIndex(); + + Point2D pt = new Point2D(); + for (int path = m_shape.getFirstPath(m_geometry); path != -1; path = m_shape + .getNextPath(path)) { + int vertex = m_shape.getFirstVertex(path); + for (int ivert = 0, nvert = m_shape.getPathSize(path); ivert < nvert; ivert++, vertex = m_shape + .getNextVertex(vertex)) { + m_shape.getXY(vertex, pt); + if (m_extent.xmin == pt.x || m_extent.xmax == pt.x + || m_extent.ymin == pt.y || m_extent.ymax == pt.y) { + m_shape.setUserIndex(vertex, m_vertices_on_extent_index, + m_vertices_on_extent.size()); + m_vertices_on_extent.add(vertex); + } + } + } + // dbg_check_path_first_(); + resolveOverlaps_(false, m_extent.xmin); + // dbg_check_path_first_(); + resolveOverlaps_(false, m_extent.xmax); + // dbg_check_path_first_(); + resolveOverlaps_(true, m_extent.ymin); + // dbg_check_path_first_(); + resolveOverlaps_(true, m_extent.ymax); + fixPaths_(); + } + + void densifyAlongClipExtent_(double densify_dist) { + assert (densify_dist > 0); + Point2D pt_1 = new Point2D(); + Point2D pt_2 = new Point2D(); + double[] split_scalars = new double[2048]; + for (int path = m_shape.getFirstPath(m_geometry); path != -1; path = m_shape + .getNextPath(path)) { + int first_vertex = m_shape.getFirstVertex(path); + int vertex = first_vertex; + do { + int next_vertex = m_shape.getNextVertex(vertex); + m_shape.getXY(vertex, pt_1); + int b_densify_x = -1; + if (pt_1.x == m_extent.xmin) { + m_shape.getXY(next_vertex, pt_2); + if (pt_2.x == m_extent.xmin) { + b_densify_x = 1; + } + } else if (pt_1.x == m_extent.xmax) { + m_shape.getXY(next_vertex, pt_2); + if (pt_2.x == m_extent.xmax) { + b_densify_x = 1; + } + } + + if (pt_1.y == m_extent.ymin) { + m_shape.getXY(next_vertex, pt_2); + if (pt_2.y == m_extent.ymin) { + b_densify_x = 0; + } + } else if (pt_1.y == m_extent.ymax) { + m_shape.getXY(next_vertex, pt_2); + if (pt_2.y == m_extent.ymax) { + b_densify_x = 0; + } + } + + if (b_densify_x == -1) { + vertex = next_vertex; + continue; + } + + double len = Point2D.distance(pt_1, pt_2); + int num = (int) Math.min(Math.ceil(len / densify_dist), 2048.0); + if (num <= 1) { + vertex = next_vertex; + continue; + } + + for (int i = 1; i < num; i++) { + split_scalars[i - 1] = (1.0 * i) / num; + } + + int actual_splits = m_shape.splitSegment(vertex, split_scalars, + num - 1); + assert (actual_splits == num - 1); + vertex = next_vertex; + } while (vertex != first_vertex); + } + } + + void splitSegments_(boolean b_axis_x, double clip_value) { + // After the clipping, we could have produced unwanted segment overlaps + // along the clipping envelope boundary. + // Detect and resolve that case if possible. + int usage_index = m_shape.createUserIndex(); + Point2D pt = new Point2D(); + AttributeStreamOfInt32 sorted_vertices = new AttributeStreamOfInt32(0); + sorted_vertices.reserve(100); + for (int path = m_shape.getFirstPath(m_geometry); path != -1; path = m_shape + .getNextPath(path)) { + int vertex = m_shape.getFirstVertex(path); + for (int ivert = 0, nvert = m_shape.getPathSize(path); ivert < nvert; ivert++) { + int next_vertex = m_shape.getNextVertex(vertex); + m_shape.getXY(vertex, pt); + if (b_axis_x ? pt.y == clip_value : pt.x == clip_value) { + m_shape.getXY(next_vertex, pt); + if (b_axis_x ? pt.y == clip_value : pt.x == clip_value) { + if (m_shape.getUserIndex(vertex, usage_index) != 1) { + sorted_vertices.add(vertex); + m_shape.setUserIndex(vertex, usage_index, 1); + } + + if (m_shape.getUserIndex(next_vertex, usage_index) != 1) { + sorted_vertices.add(next_vertex); + m_shape.setUserIndex(next_vertex, usage_index, 1); + } + } + } + vertex = next_vertex; + } + } + + m_shape.removeUserIndex(usage_index); + if (sorted_vertices.size() < 3) { + return; + } + + sorted_vertices.Sort(0, sorted_vertices.size(), + new ClipperVertexComparer(this)); + + Point2D pt_tmp = new Point2D(); // forward declare for java port + // optimization + Point2D pt_0 = new Point2D(); + Point2D pt_1 = new Point2D(); + pt_0.setNaN(); + int index_0 = -1; + AttributeStreamOfInt32 active_intervals = new AttributeStreamOfInt32(0); + AttributeStreamOfInt32 new_active_intervals = new AttributeStreamOfInt32( + 0); + + int node1 = m_shape.createUserIndex(); + int node2 = m_shape.createUserIndex(); + for (int index = 0, n = sorted_vertices.size(); index < n; index++) { + int vert = sorted_vertices.get(index); + m_shape.getXY(vert, pt); + if (!pt.isEqual(pt_0)) { + if (index_0 == -1) { + index_0 = index; + pt_0.setCoords(pt); + continue; + } + + // add new intervals, that started at pt_0 + for (int i = index_0; i < index; i++) { + int v = sorted_vertices.get(i); + int nextv = m_shape.getNextVertex(v); + int prevv = m_shape.getPrevVertex(v); + boolean bAdded = false; + if (compareVertices_(v, nextv) < 0) { + m_shape.getXY(nextv, pt_tmp); + if (b_axis_x ? pt_tmp.y == clip_value + : pt_tmp.x == clip_value) { + active_intervals.add(v); + bAdded = true; + m_shape.setUserIndex(v, node2, 1); + } + } + if (compareVertices_(v, prevv) < 0) { + m_shape.getXY(prevv, pt_tmp); + if (b_axis_x ? pt_tmp.y == clip_value + : pt_tmp.x == clip_value) { + if (!bAdded) + active_intervals.add(v); + m_shape.setUserIndex(v, node1, 1); + } + } + } + + // Split all active intervals at new point + for (int ia = 0, na = active_intervals.size(); ia < na; ia++) { + int v = active_intervals.get(ia); + int n_1 = m_shape.getUserIndex(v, node1); + int n_2 = m_shape.getUserIndex(v, node2); + if (n_1 == 1) { + int prevv = m_shape.getPrevVertex(v); + m_shape.getXY(prevv, pt_1); + double[] t = new double[1]; + t[0] = 0; + if (!pt_1.isEqual(pt)) {// Split the active segment + double active_segment_length = Point2D + .distance(pt_0, pt_1); + t[0] = Point2D.distance(pt_1, pt) + / active_segment_length; + assert (t[0] >= 0 && t[0] <= 1.0); + if (t[0] == 0) + t[0] = NumberUtils.doubleEps();// some + // roundoff + // issue. + // split + // anyway. + else if (t[0] == 1.0) { + t[0] = 1.0 - NumberUtils.doubleEps();// some + // roundoff + // issue. + // split + // anyway. + assert (t[0] != 1.0); + } + + int split_count = m_shape.splitSegment(prevv, + t, 1); + assert (split_count > 0); + int v_1 = m_shape.getPrevVertex(v); + m_shape.setXY(v_1, pt); + new_active_intervals.add(v_1); + m_shape.setUserIndex(v_1, node1, 1); + m_shape.setUserIndex(v_1, node2, -1); + } else { + // The active segment ends at the current point. + // We skip it, and it goes away. + } + } + if (n_2 == 1) { + int nextv = m_shape.getNextVertex(v); + m_shape.getXY(nextv, pt_1); + double[] t = new double[1]; + t[0] = 0; + if (!pt_1.isEqual(pt)) { + double active_segment_length = Point2D + .distance(pt_0, pt_1); + t[0] = Point2D.distance(pt_0, pt) + / active_segment_length; + assert (t[0] >= 0 && t[0] <= 1.0); + if (t[0] == 0) + t[0] = NumberUtils.doubleEps();// some + // roundoff + // issue. + // split + // anyway. + else if (t[0] == 1.0) { + t[0] = 1.0 - NumberUtils.doubleEps();// some + // roundoff + // issue. + // split + // anyway. + assert (t[0] != 1.0); + } + + int split_count = m_shape.splitSegment(v, t, 1); + assert (split_count > 0); + int v_1 = m_shape.getNextVertex(v); + m_shape.setXY(v_1, pt); + new_active_intervals.add(v_1); + m_shape.setUserIndex(v_1, node1, -1); + m_shape.setUserIndex(v_1, node2, 1); + } + } + } + + AttributeStreamOfInt32 tmp = active_intervals; + active_intervals = new_active_intervals; + new_active_intervals = tmp; + new_active_intervals.clear(false); + + index_0 = index; + pt_0.setCoords(pt); + } + } + + m_shape.removeUserIndex(node1); + m_shape.removeUserIndex(node2); + } + + void resolveOverlaps_(boolean b_axis_x, double clip_value) { + // Along the envelope boundary there could be overlapped segments. + // Example, exterior ring with a hole is cut with a line, that + // passes through the center of the hole. + // Detect pairs of opposite overlapping segments and get rid of them + Point2D pt = new Point2D(); + AttributeStreamOfInt32 sorted_vertices = new AttributeStreamOfInt32(0); + sorted_vertices.reserve(100); + int sorted_index = m_shape.createUserIndex(); + // DEBUGPRINTF(L"ee\n"); + for (int ivert = 0, nvert = m_vertices_on_extent.size(); ivert < nvert; ivert++) { + int vertex = m_vertices_on_extent.get(ivert); + if (vertex == -1) + continue; + + int next_vertex = m_shape.getNextVertex(vertex); + m_shape.getXY(vertex, pt); + // DEBUGPRINTF(L"%f\t%f\n", pt.x, pt.y); + if (b_axis_x ? pt.y == clip_value : pt.x == clip_value) { + m_shape.getXY(next_vertex, pt); + if (b_axis_x ? pt.y == clip_value : pt.x == clip_value) { + assert (m_shape.getUserIndex(next_vertex, + m_vertices_on_extent_index) != -1); + if (m_shape.getUserIndex(vertex, sorted_index) != -2) { + sorted_vertices.add(vertex);// remember the vertex. The + // attached segment belongs + // to the given clip plane. + m_shape.setUserIndex(vertex, sorted_index, -2); + } + + if (m_shape.getUserIndex(next_vertex, sorted_index) != -2) { + sorted_vertices.add(next_vertex); + m_shape.setUserIndex(next_vertex, sorted_index, -2); + } + } + } + } + + if (sorted_vertices.size() == 0) { + m_shape.removeUserIndex(sorted_index); + return; + } + + sorted_vertices.Sort(0, sorted_vertices.size(), + new ClipperVertexComparer(this)); + // std::sort(sorted_vertices.get_ptr(), sorted_vertices.get_ptr() + + // sorted_vertices.size(), Clipper_vertex_comparer(this)); + + // DEBUGPRINTF(L"**\n"); + for (int index = 0, n = sorted_vertices.size(); index < n; index++) { + int vert = sorted_vertices.get(index); + m_shape.setUserIndex(vert, sorted_index, index); + // Point_2D pt; + // m_shape.get_xy(vert, pt); + // DEBUGPRINTF(L"%f\t%f\t%d\n", pt.x, pt.y, vert); + } + + Point2D pt_tmp = new Point2D(); + Point2D pt_0 = new Point2D(); + pt_0.setNaN(); + int index_0 = -1; + for (int index = 0, n = sorted_vertices.size(); index < n; index++) { + int vert = sorted_vertices.get(index); + if (vert == -1) + continue; + + m_shape.getXY(vert, pt); + if (!pt.isEqual(pt_0)) { + if (index_0 != -1) { + while (true) { + boolean b_overlap_resolved = false; + int index_to = index - index_0 > 1 ? index - 1 : index; + for (int i = index_0; i < index_to; i++) { + int v = sorted_vertices.get(i); + if (v == -1) + continue; + int nextv = -1; + int nv = m_shape.getNextVertex(v); + if (compareVertices_(v, nv) < 0) { + m_shape.getXY(nv, pt_tmp); + if (b_axis_x ? pt_tmp.y == clip_value + : pt_tmp.x == clip_value) + nextv = nv; + } + int prevv = -1; + int pv = m_shape.getPrevVertex(v); + if (compareVertices_(v, pv) < 0) { + m_shape.getXY(pv, pt_tmp); + if (b_axis_x ? pt_tmp.y == clip_value + : pt_tmp.x == clip_value) + prevv = pv; + } + + if (nextv != -1 && prevv != -1) { + // we have a cusp here. remove the vertex. + beforeRemoveVertex_(v, sorted_vertices, + sorted_index); + m_shape.removeVertex(v, false); + beforeRemoveVertex_(nextv, sorted_vertices, + sorted_index); + m_shape.removeVertex(nextv, false); + b_overlap_resolved = true; + continue; + } + + if (nextv == -1 && prevv == -1) + continue; + + for (int j = i + 1; j < index; j++) { + int v_1 = sorted_vertices.get(j); + if (v_1 == -1) + continue; + int nv1 = m_shape.getNextVertex(v_1); + int nextv1 = -1; + if (compareVertices_(v_1, nv1) < 0) { + m_shape.getXY(nv1, pt_tmp); + if (b_axis_x ? pt_tmp.y == clip_value + : pt_tmp.x == clip_value) + nextv1 = nv1; + } + + int pv1 = m_shape.getPrevVertex(v_1); + int prevv_1 = -1; + if (compareVertices_(v_1, pv1) < 0) { + m_shape.getXY(pv1, pt_tmp); + if (b_axis_x ? pt_tmp.y == clip_value + : pt_tmp.x == clip_value) + prevv_1 = pv1; + } + if (nextv1 != -1 && prevv_1 != -1) { + // we have a cusp here. remove the vertex. + beforeRemoveVertex_(v_1, sorted_vertices, + sorted_index); + m_shape.removeVertex(v_1, false); + beforeRemoveVertex_(nextv1, + sorted_vertices, sorted_index); + m_shape.removeVertex(nextv1, false); + b_overlap_resolved = true; + break; + } + if (nextv != -1 && prevv_1 != -1) { + removeOverlap_(sorted_vertices, v, nextv, + v_1, prevv_1, sorted_index); + b_overlap_resolved = true; + break; + } else if (prevv != -1 && nextv1 != -1) { + removeOverlap_(sorted_vertices, v_1, + nextv1, v, prevv, sorted_index); + b_overlap_resolved = true; + break; + } + } + + if (b_overlap_resolved) + break; + } + + if (!b_overlap_resolved) + break; + } + } + + index_0 = index; + pt_0.setCoords(pt); + } + } + + m_shape.removeUserIndex(sorted_index); + } + + void beforeRemoveVertex_(int v_1, AttributeStreamOfInt32 sorted_vertices, + int sorted_index) { + int ind = m_shape.getUserIndex(v_1, sorted_index); + sorted_vertices.set(ind, -1); + ind = m_shape.getUserIndex(v_1, m_vertices_on_extent_index); + m_vertices_on_extent.set(ind, -1); + int path = m_shape.getPathFromVertex(v_1); + if (path != -1) { + int first = m_shape.getFirstVertex(path); + if (first == v_1) { + m_shape.setFirstVertex_(path, -1); + m_shape.setLastVertex_(path, -1); + } + } + } + + void removeOverlap_(AttributeStreamOfInt32 sorted_vertices, int v, + int nextv, int v_1, int prevv_1, int sorted_index) { + assert (m_shape.isEqualXY(v, v_1)); + assert (m_shape.isEqualXY(nextv, prevv_1)); + assert (m_shape.getNextVertex(v) == nextv); + assert (m_shape.getNextVertex(prevv_1) == v_1); + m_shape.setNextVertex_(v, v_1); + m_shape.setPrevVertex_(v_1, v); + m_shape.setPrevVertex_(nextv, prevv_1); + m_shape.setNextVertex_(prevv_1, nextv); + + beforeRemoveVertex_(v_1, sorted_vertices, sorted_index); + m_shape.removeVertexInternal_(v_1, false); + beforeRemoveVertex_(prevv_1, sorted_vertices, sorted_index); + m_shape.removeVertexInternal_(prevv_1, true); + } + + void fixPaths_() { + for (int ivert = 0, nvert = m_vertices_on_extent.size(); ivert < nvert; ivert++) { + int vertex = m_vertices_on_extent.get(ivert); + if (vertex != -1) + m_shape.setPathToVertex_(vertex, -1); + } + + int path_count = 0; + int geometry_size = 0; + for (int path = m_shape.getFirstPath(m_geometry); path != -1; ) { + int first = m_shape.getFirstVertex(path); + if (first == -1 || path != m_shape.getPathFromVertex(first)) { // The + // path's + // first + // vertex + // has + // been + // deleted. + // Or + // the + // path + // first + // vertex + // is + // now + // part + // of + // another + // path. + // We + // have + // to + // delete + // such + // path + // object. + int p = path; + path = m_shape.getNextPath(path); + m_shape.setFirstVertex_(p, -1); + m_shape.removePathOnly_(p); + continue; + } + assert (path == m_shape.getPathFromVertex(first)); + int vertex = first; + int path_size = 0; + do { + m_shape.setPathToVertex_(vertex, path); + path_size++; + vertex = m_shape.getNextVertex(vertex); + } while (vertex != first); + + if (path_size <= 2) { + int ind = m_shape.getUserIndex(first, + m_vertices_on_extent_index); + m_vertices_on_extent.set(ind, -1); + int nv = m_shape.removeVertex(first, false); + if (path_size == 2) { + ind = m_shape.getUserIndex(nv, m_vertices_on_extent_index); + m_vertices_on_extent.set(ind, -1); + m_shape.removeVertex(nv, false); + } + int p = path; + path = m_shape.getNextPath(path); + m_shape.setFirstVertex_(p, -1); + m_shape.removePathOnly_(p); + continue; + } + + m_shape.setRingAreaValid_(path, false); + m_shape.setLastVertex_(path, m_shape.getPrevVertex(first)); + m_shape.setPathSize_(path, path_size); + geometry_size += path_size; + path_count++; + path = m_shape.getNextPath(path); + } + + for (int ivert = 0, nvert = m_vertices_on_extent.size(); ivert < nvert; ivert++) { + int vertex = m_vertices_on_extent.get(ivert); + if (vertex == -1) + continue; + int path = m_shape.getPathFromVertex(vertex); + if (path != -1) + continue; + + path = m_shape.insertPath(m_geometry, -1); + int path_size = 0; + int first = vertex; + do { + m_shape.setPathToVertex_(vertex, path); + path_size++; + vertex = m_shape.getNextVertex(vertex); + } while (vertex != first); + + if (path_size <= 2) { + int ind = m_shape.getUserIndex(first, + m_vertices_on_extent_index); + m_vertices_on_extent.set(ind, -1); + int nv = m_shape.removeVertex(first, false); + if (path_size == 2) { + ind = m_shape.getUserIndex(nv, m_vertices_on_extent_index); + if (ind >= 0) + m_vertices_on_extent.set(ind, -1); + else { + // this vertex is not on the extent. + } + m_shape.removeVertex(nv, false); + } + + int p = path; + path = m_shape.getNextPath(path); + m_shape.setFirstVertex_(p, -1); + m_shape.removePathOnly_(p); + continue; + } + + m_shape.setClosedPath(path, true); + m_shape.setPathSize_(path, path_size); + m_shape.setFirstVertex_(path, first); + m_shape.setLastVertex_(path, m_shape.getPrevVertex(first)); + m_shape.setRingAreaValid_(path, false); + geometry_size += path_size; + path_count++; + } + + m_shape.setGeometryPathCount_(m_geometry, path_count); + m_shape.setGeometryVertexCount_(m_geometry, geometry_size); + + int total_point_count = 0; + for (int geometry = m_shape.getFirstGeometry(); geometry != -1; geometry = m_shape + .getNextGeometry(geometry)) { + total_point_count += m_shape.getPointCount(geometry); + } + + m_shape.setTotalPointCount_(total_point_count); + } + + static Geometry clipMultiPath_(MultiPath multipath, Envelope2D extent, + double tolerance, double densify_dist) { + Clipper clipper = new Clipper(extent); + return clipper.clipMultiPath2_(multipath, tolerance, densify_dist); + } + + Clipper(Envelope2D extent) { + m_extent = extent; + m_shape = new EditShape(); + m_vertices_on_extent = new AttributeStreamOfInt32(0); + } + + // static std::shared_ptr create_polygon_from_polyline(const + // std::shared_ptr& polyline, const Envelope_2D& env_2D, bool + // add_envelope, double tolerance, double densify_dist, int + // corner_is_inside); + static Geometry clip(Geometry geometry, Envelope2D extent, + double tolerance, double densify_dist) { + if (geometry.isEmpty()) + return geometry; + + if (extent.isEmpty()) + return geometry.createInstance(); // return an empty geometry + + int geomtype = geometry.getType().value(); + + // Test firstly the simplest geometry types point and envelope. + // After that we'll check the envelope intersection for the optimization + if (geomtype == Geometry.Type.Point.value()) { + Point2D pt = ((Point) geometry).getXY(); + if (extent.contains(pt)) + return geometry; + else + return geometry.createInstance(); // return an empty geometry + } else if (geomtype == Geometry.Type.Envelope.value()) { + Envelope2D env = new Envelope2D(); + geometry.queryEnvelope2D(env); + if (env.intersect(extent)) { + Envelope result_env = new Envelope(); + geometry.copyTo(result_env); + result_env.setEnvelope2D(env); + return result_env; + } else + return geometry.createInstance(); // return an empty geometry + } + + // Test the geometry envelope + Envelope2D env_2D = new Envelope2D(); + geometry.queryLooseEnvelope2D(env_2D); + if (extent.contains(env_2D)) + return geometry;// completely inside of bounds + if (!extent.isIntersecting(env_2D)) + return geometry.createInstance();// outside of bounds. return empty + // geometry. + + MultiVertexGeometryImpl impl = (MultiVertexGeometryImpl) geometry + ._getImpl(); + GeometryAccelerators accel = impl._getAccelerators(); + if (accel != null) { + RasterizedGeometry2D rgeom = accel.getRasterizedGeometry(); + if (rgeom != null) { + RasterizedGeometry2D.HitType hit = rgeom + .queryEnvelopeInGeometry(extent); + if (hit == RasterizedGeometry2D.HitType.Inside) { + if (geomtype != Geometry.Type.Polygon.value()) + throw GeometryException.GeometryInternalError(); + + Polygon poly = new Polygon(geometry.getDescription()); + poly.addEnvelope(extent, false); + return poly; + } else if (hit == RasterizedGeometry2D.HitType.Outside) { + return geometry.createInstance();// outside of bounds. + // return empty + // geometry. + } + } + } + + switch (geomtype) { + case Geometry.GeometryType.MultiPoint: { + MultiPoint multi_point = (MultiPoint) geometry; + MultiPoint multi_point_out = null; + int npoints = multi_point.getPointCount(); + AttributeStreamOfDbl xy = (AttributeStreamOfDbl) ((MultiPointImpl) multi_point + ._getImpl()) + .getAttributeStreamRef(VertexDescription.Semantics.POSITION); + // create the new geometry only if there are points that has been + // clipped out. + // If all vertices are inside of the envelope, it returns the input + // multipoint. + int ipoints0 = 0; + for (int ipoints = 0; ipoints < npoints; ipoints++) { + Point2D pt = new Point2D(); + xy.read(2 * ipoints, pt); + + if (!extent.contains(pt)) {// vertex is outside of the envelope + if (ipoints0 == 0) + multi_point_out = (MultiPoint) multi_point + .createInstance(); + + if (ipoints0 < ipoints) + multi_point_out.add(multi_point, ipoints0, ipoints); + + ipoints0 = ipoints + 1;// ipoints0 contains index of vertex + // right after the last clipped out + // vertex. + } + } + + // add the rest of the batch to the result multipoint (only if + // something has been already clipped out) + if (ipoints0 > 0) + multi_point_out.add(multi_point, ipoints0, npoints); + + if (ipoints0 == 0) + return multi_point;// everything is inside, so return the input + // geometry + else + return multi_point_out;// clipping has happend, return the + // clipped geometry + } + case Geometry.GeometryType.Polygon: + case Geometry.GeometryType.Polyline: + return clipMultiPath_((MultiPath) geometry, extent, tolerance, + densify_dist); + default: + assert (false); + throw GeometryException.GeometryInternalError(); + } + } + + int compareVertices_(int v_1, int v_2) { + Point2D pt_1 = new Point2D(); + m_shape.getXY(v_1, pt_1); + Point2D pt_2 = new Point2D(); + m_shape.getXY(v_2, pt_2); + int res = pt_1.compare(pt_2); + return res; + } + + static final class ClipperVertexComparer extends + AttributeStreamOfInt32.IntComparator { + Clipper m_clipper; + + ClipperVertexComparer(Clipper clipper) { + m_clipper = clipper; + } + + @Override + public int compare(int v1, int v2) { + return m_clipper.compareVertices_(v1, v2); + } + + } } diff --git a/src/main/java/com/esri/core/geometry/Clusterer.java b/src/main/java/com/esri/core/geometry/Clusterer.java index 891da967..fb595580 100644 --- a/src/main/java/com/esri/core/geometry/Clusterer.java +++ b/src/main/java/com/esri/core/geometry/Clusterer.java @@ -29,11 +29,11 @@ * Used by the TopoGraph and Simplify. */ final class Clusterer { - // Clusters vertices of the shape. Returns True, if some vertices were moved - // (clustered). - // Uses reciprocal clustering (cluster vertices that are mutual nearest - // neighbours) - /* + // Clusters vertices of the shape. Returns True, if some vertices were moved + // (clustered). + // Uses reciprocal clustering (cluster vertices that are mutual nearest + // neighbours) + /* * static boolean executeReciprocal(EditShape shape, double tolerance) { * Clusterer clusterer = new Clusterer(); clusterer.m_shape = shape; * clusterer.m_tolerance = tolerance; clusterer.m_sqr_tolerance = tolerance @@ -42,547 +42,547 @@ final class Clusterer { * clusterer.clusterReciprocal_(); } */ - // Clusters vertices of the shape. Returns True, if some vertices were moved - // (clustered). - // Uses non-reciprocal clustering (cluster any vertices that are closer than - // the tolerance in the first-found-first-clustered order) - static boolean executeNonReciprocal(EditShape shape, double tolerance) { - Clusterer clusterer = new Clusterer(); - clusterer.m_shape = shape; - clusterer.m_tolerance = tolerance; - clusterer.m_sqr_tolerance = tolerance * tolerance; - clusterer.m_cell_size = 2 * tolerance; - clusterer.m_inv_cell_size = 1.0 / clusterer.m_cell_size; - return clusterer.clusterNonReciprocal_(); - } - - // Use b_conservative == True for simplify, and False for IsSimple. This - // makes sure Simplified shape is more robust to transformations. - static boolean isClusterCandidate_(double x_1, double y1, double x2, - double y2, double sqr_tolerance) { - double dx = x_1 - x2; - double dy = y1 - y2; - return dx * dx + dy * dy <= sqr_tolerance; - } - - Point2D m_origin = new Point2D(); - double m_tolerance; - double m_sqr_tolerance; - double m_cell_size; - double m_inv_cell_size; - int[] m_bucket_array = new int[4];// temporary 4 element array - int[] m_bucket_hash = new int[4];// temporary 4 element array - int m_dbg_candidate_check_count = 0; - int m_hash_values = -1; - int m_new_clusters = -1; - - static int hashFunction_(int xi, int yi) { - int h = NumberUtils.hash(xi); - return NumberUtils.hash(h, yi); - } - - final class ClusterHashFunction extends IndexHashTable.HashFunction { - EditShape m_shape; - double m_sqr_tolerance; - double m_inv_cell_size; - Point2D m_origin = new Point2D(); - Point2D m_pt = new Point2D(); - Point2D m_pt_2 = new Point2D(); - int m_hash_values; - - public ClusterHashFunction(EditShape shape, Point2D origin, - double sqr_tolerance, double inv_cell_size, int hash_values) { - m_shape = shape; - m_sqr_tolerance = sqr_tolerance; - m_inv_cell_size = inv_cell_size; - m_origin = origin; - m_hash_values = hash_values; - m_pt.setNaN(); - m_pt_2.setNaN(); - } - - int calculate_hash(int element) { - return calculate_hash_from_vertex(element); - } - - int dbg_calculate_hash_from_xy(double x, double y) { - double dx = x - m_origin.x; - int xi = (int) (dx * m_inv_cell_size + 0.5); - double dy = y - m_origin.y; - int yi = (int) (dy * m_inv_cell_size + 0.5); - return hashFunction_(xi, yi); - } - - int calculate_hash_from_vertex(int vertex) { - m_shape.getXY(vertex, m_pt); - double dx = m_pt.x - m_origin.x; - int xi = (int) (dx * m_inv_cell_size + 0.5); - double dy = m_pt.y - m_origin.y; - int yi = (int) (dy * m_inv_cell_size + 0.5); - return hashFunction_(xi, yi); - } - - @Override - public int getHash(int element) { - return m_shape.getUserIndex(element, m_hash_values); - } - - @Override - public boolean equal(int element_1, int element_2) { - int xyindex_1 = element_1; - int xyindex_2 = element_2; - m_shape.getXY(xyindex_1, m_pt); - m_shape.getXY(xyindex_2, m_pt_2); - return isClusterCandidate_(m_pt.x, m_pt.y, m_pt_2.x, m_pt_2.y, - m_sqr_tolerance); - } - - @Override - public int getHash(Object element_descriptor) { - // UNUSED - return 0; - } - - @Override - public boolean equal(Object element_descriptor, int element) { - // UNUSED - return false; - } - } - - ; - - EditShape m_shape; - IndexMultiList m_clusters; - ClusterHashFunction m_hash_function; - IndexHashTable m_hash_table; - - static class ClusterCandidate { - public int vertex; - double distance; - } - - ; - - void getNearestNeighbourCandidate_(int xyindex, Point2D pointOfInterest, - int bucket_ptr, ClusterCandidate candidate) { - candidate.vertex = -1; - candidate.distance = NumberUtils.doubleMax(); - - Point2D pt = new Point2D(); - for (int node = bucket_ptr; node != -1; node = m_hash_table - .getNextInBucket(node)) { - int xyind = m_hash_table.getElement(node); - if (xyindex == xyind) - continue; - - m_shape.getXY(xyind, pt); - if (isClusterCandidate_(pointOfInterest.x, pointOfInterest.y, pt.x, - pt.y, m_sqr_tolerance)) { - pt.sub(pointOfInterest); - double l = pt.length(); - if (l < candidate.distance) { - candidate.distance = l; - candidate.vertex = xyind; - } - } - } - } - - void findClusterCandidate_(int xyindex, ClusterCandidate candidate) { - Point2D pointOfInterest = new Point2D(); - m_shape.getXY(xyindex, pointOfInterest); - double x_0 = pointOfInterest.x - m_origin.x; - double x = x_0 * m_inv_cell_size; - double y0 = pointOfInterest.y - m_origin.y; - double y = y0 * m_inv_cell_size; - - int xi = (int) x; - int yi = (int) y; - - // find the nearest neighbour in the 4 neigbouring cells. - - candidate.vertex = -1; - candidate.distance = NumberUtils.doubleMax(); - ClusterCandidate c = new ClusterCandidate(); - for (int dx = 0; dx <= 1; dx += 1) { - for (int dy = 0; dy <= 1; dy += 1) { - int bucket_ptr = m_hash_table.getFirstInBucket(hashFunction_(xi - + dx, yi + dy)); - if (bucket_ptr != IndexHashTable.nullNode()) { - getNearestNeighbourCandidate_(xyindex, pointOfInterest, - bucket_ptr, c); - if (c.vertex != IndexHashTable.nullNode() - && c.distance < candidate.distance) { - candidate = c; - } - } - } - } - } - - void collectClusterCandidates_(int xyindex, - AttributeStreamOfInt32 candidates) { - Point2D pointOfInterest = new Point2D(); - m_shape.getXY(xyindex, pointOfInterest); - double x_0 = pointOfInterest.x - m_origin.x; - double x = x_0 * m_inv_cell_size; - double y0 = pointOfInterest.y - m_origin.y; - double y = y0 * m_inv_cell_size; - - int xi = (int) x; - int yi = (int) y; - - int bucket_count = 0; - // find all nearest neighbours in the 4 neigbouring cells. - // Note, because we check four neighbours, there should be 4 times more - // bins in the hash table to reduce collision probability in this loop. - for (int dx = 0; dx <= 1; dx += 1) { - for (int dy = 0; dy <= 1; dy += 1) { - int hash = hashFunction_(xi + dx, yi + dy); - int bucket_ptr = m_hash_table.getFirstInBucket(hash); - if (bucket_ptr != -1) { - // Check if we already have this bucket. - // There could be a hash collision for neighbouring buckets. - m_bucket_array[bucket_count] = bucket_ptr; - m_bucket_hash[bucket_count] = hash; - - bucket_count++; - } - } - } - - // Clear duplicate buckets - // There could be a hash collision for neighboring buckets. - for (int j = bucket_count - 1; j >= 1; j--) { - int bucket_ptr = m_bucket_array[j]; - for (int i = j - 1; i >= 0; i--) { - if (bucket_ptr == m_bucket_array[i])// hash values for two - // neighbouring cells have - // collided. - { - m_bucket_hash[i] = -1; // forget collided hash - bucket_count--; - if (j != bucket_count) { - m_bucket_hash[j] = m_bucket_hash[bucket_count]; - m_bucket_array[j] = m_bucket_array[bucket_count]; - } - break;// duplicate - } - } - } - - for (int i = 0; i < bucket_count; i++) { - collectNearestNeighbourCandidates_(xyindex, m_bucket_hash[i], - pointOfInterest, m_bucket_array[i], candidates); - } - } - - void collectNearestNeighbourCandidates_(int xyindex, int hash, - Point2D pointOfInterest, int bucket_ptr, - AttributeStreamOfInt32 candidates) { - Point2D pt = new Point2D(); - for (int node = bucket_ptr; node != -1; node = m_hash_table - .getNextInBucket(node)) { - int xyind = m_hash_table.getElement(node); - if (xyindex == xyind || hash != -1 - && m_shape.getUserIndex(xyind, m_hash_values) != hash) - continue;// processing same vertex, or the bucket hash modulo - // bin count collides. - - m_shape.getXY(xyind, pt); - m_dbg_candidate_check_count++; - if (isClusterCandidate_(pointOfInterest.x, pointOfInterest.y, pt.x, - pt.y, m_sqr_tolerance)) { - candidates.add(node);// note that we add the cluster node - // instead of the cluster. - } - } - } - - boolean mergeClusters_(int vertex1, int vertex2, boolean update_hash) { - int cluster_1 = m_shape.getUserIndex(vertex1, m_new_clusters); - int cluster_2 = m_shape.getUserIndex(vertex2, m_new_clusters); - assert (cluster_1 != StridedIndexTypeCollection.impossibleIndex2()); - assert (cluster_2 != StridedIndexTypeCollection.impossibleIndex2()); - - if (cluster_1 == -1) { - cluster_1 = m_clusters.createList(); - m_clusters.addElement(cluster_1, vertex1); - m_shape.setUserIndex(vertex1, m_new_clusters, cluster_1); - } - - if (cluster_2 == -1) { - m_clusters.addElement(cluster_1, vertex2); - } else { - m_clusters.concatenateLists(cluster_1, cluster_2); - } - - // ensure only single vertex refers to the cluster. - m_shape.setUserIndex(vertex2, m_new_clusters, - StridedIndexTypeCollection.impossibleIndex2()); - - // merge cordinates - boolean res = mergeVertices_(vertex1, vertex2); - - if (update_hash) { - int hash = m_hash_function.calculate_hash_from_vertex(vertex1); - m_shape.setUserIndex(vertex1, m_hash_values, hash); - } else { - - } - - return res; - } - - // recalculate coordinates of the vertices by averaging them using weights. - // return true if the coordinates has changed. - static boolean mergeVertices(Point pt_1, Point pt_2, double w_1, - int rank_1, double w_2, int rank_2, Point pt_res, double[] w_res, - int[] rank_res) { - assert (!pt_1.isEmpty() && !pt_2.isEmpty()); - boolean res = pt_1.equals(pt_2); - - if (rank_1 > rank_2) { - pt_res = pt_1; - if (w_res != null) { - rank_res[0] = rank_1; - w_res[0] = w_1; - } - return res; - } else if (rank_2 > rank_1) { - pt_res = pt_2; - if (w_res != null) { - rank_res[0] = rank_1; - w_res[0] = w_1; - } - return res; - } - - pt_res = pt_1; - Point2D pt2d = new Point2D(); - mergeVertices2D(pt_1.getXY(), pt_2.getXY(), w_1, rank_1, w_2, rank_2, - pt2d, w_res, rank_res); - pt_res.setXY(pt2d); - return res; - } - - static boolean mergeVertices2D(Point2D pt_1, Point2D pt_2, double w_1, - int rank_1, double w_2, int rank_2, Point2D pt_res, double[] w_res, - int[] rank_res) { - double w = w_1 + w_2; - boolean r = false; - double x = pt_1.x; - if (pt_1.x != pt_2.x) { - if (rank_1 == rank_2) - x = (pt_1.x * w_1 + pt_2.x * w_2) / w; - - r = true; - } - double y = pt_1.y; - if (pt_1.y != pt_2.y) { - if (rank_1 == rank_2) - y = (pt_1.y * w_1 + pt_2.y * w_2) / w; - - r = true; - } - - if (rank_1 != rank_2) { - if (rank_1 > rank_2) { - if (w_res != null) { - rank_res[0] = rank_1; - w_res[0] = w_1; - } - pt_res = pt_1; - } else { - if (w_res != null) { - rank_res[0] = rank_2; - w_res[0] = w_2; - } - pt_res = pt_2; - } - } else { - pt_res.setCoords(x, y); - if (w_res != null) { - w_res[0] = w; - rank_res[0] = rank_1; - } - } - - return r; - } - - boolean mergeVertices_(int vert_1, int vert_2) { - Point2D pt_1 = new Point2D(); - m_shape.getXY(vert_1, pt_1); - Point2D pt_2 = new Point2D(); - m_shape.getXY(vert_2, pt_2); - - double w_1 = m_shape.getWeight(vert_1); - double w_2 = m_shape.getWeight(vert_2); - double w = w_1 + w_2; - int r = 0; - double x = pt_1.x; - if (pt_1.x != pt_2.x) { - x = (pt_1.x * w_1 + pt_2.x * w_2) / w; - r++; - } - double y = pt_1.y; - if (pt_1.y != pt_2.y) { - y = (pt_1.y * w_1 + pt_2.y * w_2) / w; - r++; - } - - if (r > 0) - m_shape.setXY(vert_1, x, y); - - m_shape.setWeight(vert_1, w); - return r != 0; - } - - boolean clusterNonReciprocal_() { - int point_count = m_shape.getTotalPointCount(); - Envelope2D env = m_shape.getEnvelope2D(); - m_origin = env.getLowerLeft(); - double dim = Math.max(env.getHeight(), env.getWidth()); - double mincell = dim / (NumberUtils.intMax() - 1); - if (m_cell_size < mincell) { - m_cell_size = mincell; - m_inv_cell_size = 1.0 / m_cell_size; - } - - // This holds clusters. - m_clusters = new IndexMultiList(); - m_clusters.reserveLists(m_shape.getTotalPointCount() / 3 + 1); - m_clusters.reserveNodes(m_shape.getTotalPointCount() / 3 + 1); - - m_hash_values = m_shape.createUserIndex(); - m_new_clusters = m_shape.createUserIndex(); - - // Make the hash table. It serves a purpose of fine grain grid. - // Make it 25% larger than the 4 times point count to reduce the chance - // of collision. - // The 4 times comes from the fact that we check four neighbouring cells - // in the grid for each point. - m_hash_function = new ClusterHashFunction(m_shape, m_origin, - m_sqr_tolerance, m_inv_cell_size, m_hash_values); - m_hash_table = new IndexHashTable(4 * point_count / 3, m_hash_function); - m_hash_table.reserveElements(m_shape.getTotalPointCount()); - boolean b_clustered = false; - - // Go through all vertices stored in the m_shape and put the handles of - // the vertices into the clusters and the hash table. - for (int geometry = m_shape.getFirstGeometry(); geometry != -1; geometry = m_shape - .getNextGeometry(geometry)) { - for (int path = m_shape.getFirstPath(geometry); path != -1; path = m_shape - .getNextPath(path)) { - int vertex = m_shape.getFirstVertex(path); - for (int index = 0, nindex = m_shape.getPathSize(path); index < nindex; index++) { - assert (vertex != -1); - int hash = m_hash_function - .calculate_hash_from_vertex(vertex); - m_shape.setUserIndex(vertex, m_hash_values, hash); - m_hash_table.addElement(vertex, hash); // add cluster to the - // hash table - assert (m_shape.getUserIndex(vertex, m_new_clusters) == -1); - vertex = m_shape.getNextVertex(vertex); - } - } - } - - // m_hash_table->dbg_print_bucket_histogram_(); - - {// scope for candidates array - AttributeStreamOfInt32 candidates = new AttributeStreamOfInt32(0); - candidates.reserve(10); - - for (int geometry = m_shape.getFirstGeometry(); geometry != -1; geometry = m_shape - .getNextGeometry(geometry)) { - for (int path = m_shape.getFirstPath(geometry); path != -1; path = m_shape - .getNextPath(path)) { - int vertex = m_shape.getFirstVertex(path); - for (int index = 0, nindex = m_shape.getPathSize(path); index < nindex; index++) { - if (m_shape.getUserIndex(vertex, m_new_clusters) == StridedIndexTypeCollection - .impossibleIndex2()) { - vertex = m_shape.getNextVertex(vertex); - continue;// this vertex was merged with another - // cluster. It also was removed from the - // hash table. - } - - int hash = m_shape.getUserIndex(vertex, m_hash_values); - m_hash_table.deleteElement(vertex, hash); - - while (true) { - collectClusterCandidates_(vertex, candidates); - if (candidates.size() == 0) {// no candidate for - // clustering has - // been found for - // the cluster_1. - break; - } - - boolean clustered = false; - for (int candidate_index = 0, ncandidates = candidates - .size(); candidate_index < ncandidates; candidate_index++) { - int cluster_node = candidates - .get(candidate_index); - int other_vertex = m_hash_table - .getElement(cluster_node); - m_hash_table.deleteNode(cluster_node); - clustered |= mergeClusters_(vertex, - other_vertex, - candidate_index + 1 == ncandidates); - } - - b_clustered |= clustered; - candidates.clear(false); - // repeat search for the cluster candidates for - // cluster_1 - if (!clustered) - break;// positions did not change - } - - // m_shape->set_user_index(vertex, m_new_clusters, - // Strided_index_type_collection::impossible_index_2()); - vertex = m_shape.getNextVertex(vertex); - } - } - } - } - - if (b_clustered) { - applyClusterPositions_(); - } - - m_hash_table = null; - m_hash_function = null; - m_shape.removeUserIndex(m_hash_values); - m_shape.removeUserIndex(m_new_clusters); - - // output_debug_printf("total: %d\n",m_shape->get_total_point_count()); - // output_debug_printf("clustered: %d\n",m_dbg_candidate_check_count); - return b_clustered; - } - - void applyClusterPositions_() { - Point2D cluster_pt = new Point2D(); - // move vertices to the clustered positions. - for (int list = m_clusters.getFirstList(); list != -1; list = m_clusters - .getNextList(list)) { - int node = m_clusters.getFirst(list); - assert (node != -1); - int vertex = m_clusters.getElement(node); - m_shape.getXY(vertex, cluster_pt); - for (node = m_clusters.getNext(node); node != -1; node = m_clusters - .getNext(node)) { - int vertex_1 = m_clusters.getElement(node); - m_shape.setXY(vertex_1, cluster_pt); - } - } - } - - Clusterer() { - } + // Clusters vertices of the shape. Returns True, if some vertices were moved + // (clustered). + // Uses non-reciprocal clustering (cluster any vertices that are closer than + // the tolerance in the first-found-first-clustered order) + static boolean executeNonReciprocal(EditShape shape, double tolerance) { + Clusterer clusterer = new Clusterer(); + clusterer.m_shape = shape; + clusterer.m_tolerance = tolerance; + clusterer.m_sqr_tolerance = tolerance * tolerance; + clusterer.m_cell_size = 2 * tolerance; + clusterer.m_inv_cell_size = 1.0 / clusterer.m_cell_size; + return clusterer.clusterNonReciprocal_(); + } + + // Use b_conservative == True for simplify, and False for IsSimple. This + // makes sure Simplified shape is more robust to transformations. + static boolean isClusterCandidate_(double x_1, double y1, double x2, + double y2, double sqr_tolerance) { + double dx = x_1 - x2; + double dy = y1 - y2; + return dx * dx + dy * dy <= sqr_tolerance; + } + + Point2D m_origin = new Point2D(); + double m_tolerance; + double m_sqr_tolerance; + double m_cell_size; + double m_inv_cell_size; + int[] m_bucket_array = new int[4];// temporary 4 element array + int[] m_bucket_hash = new int[4];// temporary 4 element array + int m_dbg_candidate_check_count = 0; + int m_hash_values = -1; + int m_new_clusters = -1; + + static int hashFunction_(int xi, int yi) { + int h = NumberUtils.hash(xi); + return NumberUtils.hash(h, yi); + } + + final class ClusterHashFunction extends IndexHashTable.HashFunction { + EditShape m_shape; + double m_sqr_tolerance; + double m_inv_cell_size; + Point2D m_origin = new Point2D(); + Point2D m_pt = new Point2D(); + Point2D m_pt_2 = new Point2D(); + int m_hash_values; + + public ClusterHashFunction(EditShape shape, Point2D origin, + double sqr_tolerance, double inv_cell_size, int hash_values) { + m_shape = shape; + m_sqr_tolerance = sqr_tolerance; + m_inv_cell_size = inv_cell_size; + m_origin = origin; + m_hash_values = hash_values; + m_pt.setNaN(); + m_pt_2.setNaN(); + } + + int calculate_hash(int element) { + return calculate_hash_from_vertex(element); + } + + int dbg_calculate_hash_from_xy(double x, double y) { + double dx = x - m_origin.x; + int xi = (int) (dx * m_inv_cell_size + 0.5); + double dy = y - m_origin.y; + int yi = (int) (dy * m_inv_cell_size + 0.5); + return hashFunction_(xi, yi); + } + + int calculate_hash_from_vertex(int vertex) { + m_shape.getXY(vertex, m_pt); + double dx = m_pt.x - m_origin.x; + int xi = (int) (dx * m_inv_cell_size + 0.5); + double dy = m_pt.y - m_origin.y; + int yi = (int) (dy * m_inv_cell_size + 0.5); + return hashFunction_(xi, yi); + } + + @Override + public int getHash(int element) { + return m_shape.getUserIndex(element, m_hash_values); + } + + @Override + public boolean equal(int element_1, int element_2) { + int xyindex_1 = element_1; + int xyindex_2 = element_2; + m_shape.getXY(xyindex_1, m_pt); + m_shape.getXY(xyindex_2, m_pt_2); + return isClusterCandidate_(m_pt.x, m_pt.y, m_pt_2.x, m_pt_2.y, + m_sqr_tolerance); + } + + @Override + public int getHash(Object element_descriptor) { + // UNUSED + return 0; + } + + @Override + public boolean equal(Object element_descriptor, int element) { + // UNUSED + return false; + } + } + + ; + + EditShape m_shape; + IndexMultiList m_clusters; + ClusterHashFunction m_hash_function; + IndexHashTable m_hash_table; + + static class ClusterCandidate { + public int vertex; + double distance; + } + + ; + + void getNearestNeighbourCandidate_(int xyindex, Point2D pointOfInterest, + int bucket_ptr, ClusterCandidate candidate) { + candidate.vertex = -1; + candidate.distance = NumberUtils.doubleMax(); + + Point2D pt = new Point2D(); + for (int node = bucket_ptr; node != -1; node = m_hash_table + .getNextInBucket(node)) { + int xyind = m_hash_table.getElement(node); + if (xyindex == xyind) + continue; + + m_shape.getXY(xyind, pt); + if (isClusterCandidate_(pointOfInterest.x, pointOfInterest.y, pt.x, + pt.y, m_sqr_tolerance)) { + pt.sub(pointOfInterest); + double l = pt.length(); + if (l < candidate.distance) { + candidate.distance = l; + candidate.vertex = xyind; + } + } + } + } + + void findClusterCandidate_(int xyindex, ClusterCandidate candidate) { + Point2D pointOfInterest = new Point2D(); + m_shape.getXY(xyindex, pointOfInterest); + double x_0 = pointOfInterest.x - m_origin.x; + double x = x_0 * m_inv_cell_size; + double y0 = pointOfInterest.y - m_origin.y; + double y = y0 * m_inv_cell_size; + + int xi = (int) x; + int yi = (int) y; + + // find the nearest neighbour in the 4 neigbouring cells. + + candidate.vertex = -1; + candidate.distance = NumberUtils.doubleMax(); + ClusterCandidate c = new ClusterCandidate(); + for (int dx = 0; dx <= 1; dx += 1) { + for (int dy = 0; dy <= 1; dy += 1) { + int bucket_ptr = m_hash_table.getFirstInBucket(hashFunction_(xi + + dx, yi + dy)); + if (bucket_ptr != IndexHashTable.nullNode()) { + getNearestNeighbourCandidate_(xyindex, pointOfInterest, + bucket_ptr, c); + if (c.vertex != IndexHashTable.nullNode() + && c.distance < candidate.distance) { + candidate = c; + } + } + } + } + } + + void collectClusterCandidates_(int xyindex, + AttributeStreamOfInt32 candidates) { + Point2D pointOfInterest = new Point2D(); + m_shape.getXY(xyindex, pointOfInterest); + double x_0 = pointOfInterest.x - m_origin.x; + double x = x_0 * m_inv_cell_size; + double y0 = pointOfInterest.y - m_origin.y; + double y = y0 * m_inv_cell_size; + + int xi = (int) x; + int yi = (int) y; + + int bucket_count = 0; + // find all nearest neighbours in the 4 neigbouring cells. + // Note, because we check four neighbours, there should be 4 times more + // bins in the hash table to reduce collision probability in this loop. + for (int dx = 0; dx <= 1; dx += 1) { + for (int dy = 0; dy <= 1; dy += 1) { + int hash = hashFunction_(xi + dx, yi + dy); + int bucket_ptr = m_hash_table.getFirstInBucket(hash); + if (bucket_ptr != -1) { + // Check if we already have this bucket. + // There could be a hash collision for neighbouring buckets. + m_bucket_array[bucket_count] = bucket_ptr; + m_bucket_hash[bucket_count] = hash; + + bucket_count++; + } + } + } + + // Clear duplicate buckets + // There could be a hash collision for neighboring buckets. + for (int j = bucket_count - 1; j >= 1; j--) { + int bucket_ptr = m_bucket_array[j]; + for (int i = j - 1; i >= 0; i--) { + if (bucket_ptr == m_bucket_array[i])// hash values for two + // neighbouring cells have + // collided. + { + m_bucket_hash[i] = -1; // forget collided hash + bucket_count--; + if (j != bucket_count) { + m_bucket_hash[j] = m_bucket_hash[bucket_count]; + m_bucket_array[j] = m_bucket_array[bucket_count]; + } + break;// duplicate + } + } + } + + for (int i = 0; i < bucket_count; i++) { + collectNearestNeighbourCandidates_(xyindex, m_bucket_hash[i], + pointOfInterest, m_bucket_array[i], candidates); + } + } + + void collectNearestNeighbourCandidates_(int xyindex, int hash, + Point2D pointOfInterest, int bucket_ptr, + AttributeStreamOfInt32 candidates) { + Point2D pt = new Point2D(); + for (int node = bucket_ptr; node != -1; node = m_hash_table + .getNextInBucket(node)) { + int xyind = m_hash_table.getElement(node); + if (xyindex == xyind || hash != -1 + && m_shape.getUserIndex(xyind, m_hash_values) != hash) + continue;// processing same vertex, or the bucket hash modulo + // bin count collides. + + m_shape.getXY(xyind, pt); + m_dbg_candidate_check_count++; + if (isClusterCandidate_(pointOfInterest.x, pointOfInterest.y, pt.x, + pt.y, m_sqr_tolerance)) { + candidates.add(node);// note that we add the cluster node + // instead of the cluster. + } + } + } + + boolean mergeClusters_(int vertex1, int vertex2, boolean update_hash) { + int cluster_1 = m_shape.getUserIndex(vertex1, m_new_clusters); + int cluster_2 = m_shape.getUserIndex(vertex2, m_new_clusters); + assert (cluster_1 != StridedIndexTypeCollection.impossibleIndex2()); + assert (cluster_2 != StridedIndexTypeCollection.impossibleIndex2()); + + if (cluster_1 == -1) { + cluster_1 = m_clusters.createList(); + m_clusters.addElement(cluster_1, vertex1); + m_shape.setUserIndex(vertex1, m_new_clusters, cluster_1); + } + + if (cluster_2 == -1) { + m_clusters.addElement(cluster_1, vertex2); + } else { + m_clusters.concatenateLists(cluster_1, cluster_2); + } + + // ensure only single vertex refers to the cluster. + m_shape.setUserIndex(vertex2, m_new_clusters, + StridedIndexTypeCollection.impossibleIndex2()); + + // merge cordinates + boolean res = mergeVertices_(vertex1, vertex2); + + if (update_hash) { + int hash = m_hash_function.calculate_hash_from_vertex(vertex1); + m_shape.setUserIndex(vertex1, m_hash_values, hash); + } else { + + } + + return res; + } + + // recalculate coordinates of the vertices by averaging them using weights. + // return true if the coordinates has changed. + static boolean mergeVertices(Point pt_1, Point pt_2, double w_1, + int rank_1, double w_2, int rank_2, Point pt_res, double[] w_res, + int[] rank_res) { + assert (!pt_1.isEmpty() && !pt_2.isEmpty()); + boolean res = pt_1.equals(pt_2); + + if (rank_1 > rank_2) { + pt_res = pt_1; + if (w_res != null) { + rank_res[0] = rank_1; + w_res[0] = w_1; + } + return res; + } else if (rank_2 > rank_1) { + pt_res = pt_2; + if (w_res != null) { + rank_res[0] = rank_1; + w_res[0] = w_1; + } + return res; + } + + pt_res = pt_1; + Point2D pt2d = new Point2D(); + mergeVertices2D(pt_1.getXY(), pt_2.getXY(), w_1, rank_1, w_2, rank_2, + pt2d, w_res, rank_res); + pt_res.setXY(pt2d); + return res; + } + + static boolean mergeVertices2D(Point2D pt_1, Point2D pt_2, double w_1, + int rank_1, double w_2, int rank_2, Point2D pt_res, double[] w_res, + int[] rank_res) { + double w = w_1 + w_2; + boolean r = false; + double x = pt_1.x; + if (pt_1.x != pt_2.x) { + if (rank_1 == rank_2) + x = (pt_1.x * w_1 + pt_2.x * w_2) / w; + + r = true; + } + double y = pt_1.y; + if (pt_1.y != pt_2.y) { + if (rank_1 == rank_2) + y = (pt_1.y * w_1 + pt_2.y * w_2) / w; + + r = true; + } + + if (rank_1 != rank_2) { + if (rank_1 > rank_2) { + if (w_res != null) { + rank_res[0] = rank_1; + w_res[0] = w_1; + } + pt_res = pt_1; + } else { + if (w_res != null) { + rank_res[0] = rank_2; + w_res[0] = w_2; + } + pt_res = pt_2; + } + } else { + pt_res.setCoords(x, y); + if (w_res != null) { + w_res[0] = w; + rank_res[0] = rank_1; + } + } + + return r; + } + + boolean mergeVertices_(int vert_1, int vert_2) { + Point2D pt_1 = new Point2D(); + m_shape.getXY(vert_1, pt_1); + Point2D pt_2 = new Point2D(); + m_shape.getXY(vert_2, pt_2); + + double w_1 = m_shape.getWeight(vert_1); + double w_2 = m_shape.getWeight(vert_2); + double w = w_1 + w_2; + int r = 0; + double x = pt_1.x; + if (pt_1.x != pt_2.x) { + x = (pt_1.x * w_1 + pt_2.x * w_2) / w; + r++; + } + double y = pt_1.y; + if (pt_1.y != pt_2.y) { + y = (pt_1.y * w_1 + pt_2.y * w_2) / w; + r++; + } + + if (r > 0) + m_shape.setXY(vert_1, x, y); + + m_shape.setWeight(vert_1, w); + return r != 0; + } + + boolean clusterNonReciprocal_() { + int point_count = m_shape.getTotalPointCount(); + Envelope2D env = m_shape.getEnvelope2D(); + m_origin = env.getLowerLeft(); + double dim = Math.max(env.getHeight(), env.getWidth()); + double mincell = dim / (NumberUtils.intMax() - 1); + if (m_cell_size < mincell) { + m_cell_size = mincell; + m_inv_cell_size = 1.0 / m_cell_size; + } + + // This holds clusters. + m_clusters = new IndexMultiList(); + m_clusters.reserveLists(m_shape.getTotalPointCount() / 3 + 1); + m_clusters.reserveNodes(m_shape.getTotalPointCount() / 3 + 1); + + m_hash_values = m_shape.createUserIndex(); + m_new_clusters = m_shape.createUserIndex(); + + // Make the hash table. It serves a purpose of fine grain grid. + // Make it 25% larger than the 4 times point count to reduce the chance + // of collision. + // The 4 times comes from the fact that we check four neighbouring cells + // in the grid for each point. + m_hash_function = new ClusterHashFunction(m_shape, m_origin, + m_sqr_tolerance, m_inv_cell_size, m_hash_values); + m_hash_table = new IndexHashTable(4 * point_count / 3, m_hash_function); + m_hash_table.reserveElements(m_shape.getTotalPointCount()); + boolean b_clustered = false; + + // Go through all vertices stored in the m_shape and put the handles of + // the vertices into the clusters and the hash table. + for (int geometry = m_shape.getFirstGeometry(); geometry != -1; geometry = m_shape + .getNextGeometry(geometry)) { + for (int path = m_shape.getFirstPath(geometry); path != -1; path = m_shape + .getNextPath(path)) { + int vertex = m_shape.getFirstVertex(path); + for (int index = 0, nindex = m_shape.getPathSize(path); index < nindex; index++) { + assert (vertex != -1); + int hash = m_hash_function + .calculate_hash_from_vertex(vertex); + m_shape.setUserIndex(vertex, m_hash_values, hash); + m_hash_table.addElement(vertex, hash); // add cluster to the + // hash table + assert (m_shape.getUserIndex(vertex, m_new_clusters) == -1); + vertex = m_shape.getNextVertex(vertex); + } + } + } + + // m_hash_table->dbg_print_bucket_histogram_(); + + {// scope for candidates array + AttributeStreamOfInt32 candidates = new AttributeStreamOfInt32(0); + candidates.reserve(10); + + for (int geometry = m_shape.getFirstGeometry(); geometry != -1; geometry = m_shape + .getNextGeometry(geometry)) { + for (int path = m_shape.getFirstPath(geometry); path != -1; path = m_shape + .getNextPath(path)) { + int vertex = m_shape.getFirstVertex(path); + for (int index = 0, nindex = m_shape.getPathSize(path); index < nindex; index++) { + if (m_shape.getUserIndex(vertex, m_new_clusters) == StridedIndexTypeCollection + .impossibleIndex2()) { + vertex = m_shape.getNextVertex(vertex); + continue;// this vertex was merged with another + // cluster. It also was removed from the + // hash table. + } + + int hash = m_shape.getUserIndex(vertex, m_hash_values); + m_hash_table.deleteElement(vertex, hash); + + while (true) { + collectClusterCandidates_(vertex, candidates); + if (candidates.size() == 0) {// no candidate for + // clustering has + // been found for + // the cluster_1. + break; + } + + boolean clustered = false; + for (int candidate_index = 0, ncandidates = candidates + .size(); candidate_index < ncandidates; candidate_index++) { + int cluster_node = candidates + .get(candidate_index); + int other_vertex = m_hash_table + .getElement(cluster_node); + m_hash_table.deleteNode(cluster_node); + clustered |= mergeClusters_(vertex, + other_vertex, + candidate_index + 1 == ncandidates); + } + + b_clustered |= clustered; + candidates.clear(false); + // repeat search for the cluster candidates for + // cluster_1 + if (!clustered) + break;// positions did not change + } + + // m_shape->set_user_index(vertex, m_new_clusters, + // Strided_index_type_collection::impossible_index_2()); + vertex = m_shape.getNextVertex(vertex); + } + } + } + } + + if (b_clustered) { + applyClusterPositions_(); + } + + m_hash_table = null; + m_hash_function = null; + m_shape.removeUserIndex(m_hash_values); + m_shape.removeUserIndex(m_new_clusters); + + // output_debug_printf("total: %d\n",m_shape->get_total_point_count()); + // output_debug_printf("clustered: %d\n",m_dbg_candidate_check_count); + return b_clustered; + } + + void applyClusterPositions_() { + Point2D cluster_pt = new Point2D(); + // move vertices to the clustered positions. + for (int list = m_clusters.getFirstList(); list != -1; list = m_clusters + .getNextList(list)) { + int node = m_clusters.getFirst(list); + assert (node != -1); + int vertex = m_clusters.getElement(node); + m_shape.getXY(vertex, cluster_pt); + for (node = m_clusters.getNext(node); node != -1; node = m_clusters + .getNext(node)) { + int vertex_1 = m_clusters.getElement(node); + m_shape.setXY(vertex_1, cluster_pt); + } + } + } + + Clusterer() { + } } diff --git a/src/main/java/com/esri/core/geometry/CombineOperator.java b/src/main/java/com/esri/core/geometry/CombineOperator.java index e3d1bcc1..4cbee26e 100644 --- a/src/main/java/com/esri/core/geometry/CombineOperator.java +++ b/src/main/java/com/esri/core/geometry/CombineOperator.java @@ -36,16 +36,16 @@ public interface CombineOperator { * Operation on two geometries, returning a third. Examples include * Intersection, Difference, and so forth. * - * @param geom1 is the geometry instance to be operated on. - * @param geom2 is the geometry instance to be operated on. - * @param sr The spatial reference to get the tolerance value from. - * When sr is null, the tolerance is calculated from the input geometries. + * @param geom1 is the geometry instance to be operated on. + * @param geom2 is the geometry instance to be operated on. + * @param sr The spatial reference to get the tolerance value from. + * When sr is null, the tolerance is calculated from the input geometries. * @param progressTracker ProgressTracker instance that is used to cancel the lengthy operation. Can be null. * @return Returns the result geoemtry. In some cases the returned value can point to geom1 or geom2 * instance. For example, the OperatorIntersection may return geom2 when it is completely * inside of the geom1. */ public Geometry execute(Geometry geom1, Geometry geom2, - SpatialReference sr, ProgressTracker progressTracker); + SpatialReference sr, ProgressTracker progressTracker); } diff --git a/src/main/java/com/esri/core/geometry/ConstructOffset.java b/src/main/java/com/esri/core/geometry/ConstructOffset.java index 4d31472b..e461be0a 100644 --- a/src/main/java/com/esri/core/geometry/ConstructOffset.java +++ b/src/main/java/com/esri/core/geometry/ConstructOffset.java @@ -28,980 +28,980 @@ // Note: m_distance<0 offsets to the left, m_distance>0 offsets to the right class ConstructOffset { - ProgressTracker m_progressTracker; - Geometry m_inputGeometry; - double m_distance; - double m_tolerance; - OperatorOffset.JoinType m_joins; - double m_miterLimit; - - // multipath offset - static class GraphicPoint { - double x, y; - int m_next, m_prev; - double m; - int type; - - GraphicPoint(double x_, double y_) { - x = x_; - y = y_; - type = 0; - m = 0; - } - - GraphicPoint(Point2D r) { - x = r.x; - y = r.y; - type = 0; - m = 0; - } - - GraphicPoint(GraphicPoint pt) { - x = pt.x; - y = pt.y; - type = pt.type; - m = pt.m; - } - - GraphicPoint(GraphicPoint srcPt, double d, double angle) { - x = srcPt.x + d * Math.cos(angle); - y = srcPt.y + d * Math.sin(angle); - type = srcPt.type; - m = srcPt.m; - } - - GraphicPoint(GraphicPoint pt1, GraphicPoint pt2) { - x = (pt1.x + pt2.x) * 0.5; - y = (pt1.y + pt2.y) * 0.5; - type = pt1.type; - m = pt1.m; - } - - GraphicPoint(GraphicPoint pt1, GraphicPoint pt2, double ratio) { - x = pt1.x + (pt2.x - pt1.x) * ratio; - y = pt1.y + (pt2.y - pt1.y) * ratio; - type = pt1.type; - m = pt1.m; - } - - } - - ; - - static class GraphicRect { - double x1, x2, y1, y2; - } - - ; - - static class IntersectionInfo { - GraphicPoint pt; - double rFirst; - double rSecond; - boolean atExistingPt; - } - - ; - - ArrayList m_srcPts; - int m_srcPtCount; - ArrayList m_offsetPts; - int m_offsetPtCount; - - MultiPath m_resultPath; - int m_resultPoints; - double m_a1, m_a2; - boolean m_bBadSegs; - - ConstructOffset(ProgressTracker progressTracker) { - m_progressTracker = progressTracker; - } - - // static - static Geometry execute(Geometry inputGeometry, double distance, - OperatorOffset.JoinType joins, double miterLimit, double tolerance, - ProgressTracker progressTracker) { - if (inputGeometry == null) - throw new IllegalArgumentException(); - if (inputGeometry.getDimension() < 1)// can offset Polygons and - // Polylines only - throw new IllegalArgumentException(); - if (distance == 0 || inputGeometry.isEmpty()) - return inputGeometry; - ConstructOffset offset = new ConstructOffset(progressTracker); - offset.m_inputGeometry = inputGeometry; - offset.m_distance = distance; - offset.m_tolerance = tolerance; - offset.m_joins = joins; - offset.m_miterLimit = miterLimit; - return offset._ConstructOffset(); - } - - Geometry _OffsetLine() { - Line line = (Line) m_inputGeometry; - Point2D start = line.getStartXY(); - Point2D end = line.getEndXY(); - Point2D v = new Point2D(); - v.sub(end, start); - v.normalize(); - v.leftPerpendicular(); - v.scale(m_distance); - start.add(v); - end.add(v); - Line resLine = (Line) line.createInstance(); - line.setStartXY(start); - line.setEndXY(end); - return resLine; - } - - Geometry _OffsetEnvelope() { - Envelope envelope = (Envelope) m_inputGeometry; - if ((m_distance > 0) && (m_joins != OperatorOffset.JoinType.Miter)) { - Polygon poly = new Polygon(); - poly.addEnvelope(envelope, false); - m_inputGeometry = poly; - return _ConstructOffset(); - } - - Envelope resEnv = new Envelope(envelope.m_envelope); - resEnv.inflate(m_distance, m_distance); - return resEnv; - } - - private final double pi = Math.PI;// GEOMETRYX_PI; - private final double two_pi = Math.PI * 2;// GEOMETRYX_2PI; - private final double half_pi = Math.PI / 2;// GEOMETRYX_HalfPI; - private final double sqrt2 = 1.4142135623730950488016887242097; - private final double oneDegree = 0.01745329251994329576923690768489; - - private final int BAD_SEG = 0x0100; - private final int IS_END = 0x0200; - private final int CLOSING_SEG = 0x0400; - - void addPoint(GraphicPoint pt) { - m_offsetPts.add(pt); - m_offsetPtCount++; - } - - double scal(GraphicPoint pt1, GraphicPoint pt2, GraphicPoint pt3, - GraphicPoint pt4) { - return (pt2.x - pt1.x) * (pt4.x - pt3.x) + (pt2.y - pt1.y) - * (pt4.y - pt3.y); - } - - // offPt is the point to add. - // this point corresponds to the offset version of the end of seg1. - // it could generate a segment going in the opposite direction of the - // original segment - // this situation is handled here by adding an additional "bad" segment - void addPoint(GraphicPoint offPt, int i_src) { - if (m_offsetPtCount == 0) // TODO: can we have this outside of this - // method? - { - addPoint(offPt); - return; - } - - int n_src = m_srcPtCount; - GraphicPoint pt1, pt; - pt1 = m_srcPts.get(i_src == 0 ? n_src - 1 : i_src - 1); - pt = m_srcPts.get(i_src); - - // calculate scalar product to determine if the offset segment goes in - // the same/opposite direction compared to the original one - double s = scal(pt1, pt, m_offsetPts.get(m_offsetPtCount - 1), offPt); - if (s > 0) - // original segment and offset segment go in the same direction. Just - // add the point - { - addPoint(offPt); - return; - } - - if (s < 0) { - // we will add a loop. We need to make sure the points we introduce - // don't generate a "reversed" segment - // let's project the first point of the reversed segment - // (m_offsetPts + m_offsetPtCount - 1) to check - // if it falls on the good side of the original segment (scalar - // product sign again) - if (scal(pt1, pt, pt, m_offsetPts.get(m_offsetPtCount - 1)) > 0) { - GraphicPoint p; - - // change value of m_offsetPts + m_offsetPtCount - 1 - int k; - if (i_src == 0) - k = n_src - 2; - else if (i_src == 1) - k = n_src - 1; - else - k = i_src - 2; - GraphicPoint pt0 = m_srcPts.get(k); - - double a = Math.atan2(pt1.y - pt0.y, pt1.x - pt0.x); - p = new GraphicPoint(pt1, m_distance, a - half_pi); - m_offsetPts.set(m_offsetPtCount - 1, p); - - if (m_joins == OperatorOffset.JoinType.Bevel - || m_joins == OperatorOffset.JoinType.Miter) { - // this block is added as well as the commented BAD_SEG in - // the next block - p = new GraphicPoint(p, pt1); - addPoint(p); - - // "bad" segment - p = new GraphicPoint(pt1, m_distance, m_a1 + half_pi); - - GraphicPoint p_ = new GraphicPoint(p, pt1); - p_.type |= BAD_SEG; - addPoint(p_); - - addPoint(p); - } else { - // the working stuff for round and square - - // "bad" segment - p = new GraphicPoint(pt1, m_distance, m_a1 + half_pi); - p.type |= BAD_SEG; - addPoint(p); - } - - // add offPt - addPoint(offPt, i_src); - } else { - GraphicPoint p; - - // we don't add offPt but the loop containing the "bad" segment - p = new GraphicPoint(pt, m_distance, m_a1 + half_pi); - addPoint(p); - - if (m_joins == OperatorOffset.JoinType.Bevel - || m_joins == OperatorOffset.JoinType.Miter) { - // this block is added as well as the commented BAD_SEG in - // the next block - p = new GraphicPoint(p, pt); - addPoint(p); - - p = new GraphicPoint(pt, m_distance, m_a2 - half_pi); - GraphicPoint p_ = new GraphicPoint(p, pt); - p_.type |= BAD_SEG; - addPoint(p_); - - addPoint(p); - } else { - // the working stuff for round and square - p = new GraphicPoint(pt, m_distance, m_a2 - half_pi); - p.type |= BAD_SEG; - addPoint(p); - } - } - } - } - - boolean buildOffset() { - // make sure we have at least three points and no identical points - int i; - double a1, a2; - GraphicPoint pt, pt1, pt2; - GraphicPoint p; - - // number of points to deal with - int n = m_srcPtCount; - - m_offsetPtCount = 0; - - double flattenTolerance = m_tolerance * 0.5; - - double a1_0 = 0; - double a2_0 = 0; - for (i = 0; i < n; i++) { - pt = m_srcPts.get(i); - - // point before - if (i == 0) - pt1 = m_srcPts.get(n - 1); - else - pt1 = m_srcPts.get(i - 1); - - // point after - if (i == n - 1) - pt2 = m_srcPts.get(0); - else - pt2 = m_srcPts.get(i + 1); - - // angles of enclosing segments - double dx1 = pt1.x - pt.x; - double dy1 = pt1.y - pt.y; - double dx2 = pt2.x - pt.x; - double dy2 = pt2.y - pt.y; - a1 = Math.atan2(dy1, dx1); - a2 = Math.atan2(dy2, dx2); - m_a1 = a1; - m_a2 = a2; - if (i == 0) { - a1_0 = a1; - a2_0 = a2; - } - - // double dot_product = dx1 * dx2 + dy1 * dy2; - double cross_product = dx1 * dy2 - dx2 * dy1; - // boolean bInnerAngle = (cross_product == 0) ? (m_distance > 0) : - // (cross_product * m_distance >= 0.0); - - // check for inner angles (always managed the same, whatever the - // type of join) - double saved_a2 = a2; - if (a2 < a1) - a2 += two_pi; // this guaranties that (a1 + a2) / 2 is on the - // right side of the curve - if (cross_product * m_distance > 0.0) // inner angle - { - // inner angle - if (m_joins == OperatorOffset.JoinType.Bevel - || m_joins == OperatorOffset.JoinType.Miter) { - p = new GraphicPoint(pt, m_distance, a1 + half_pi); - addPoint(p); - - // this block is added as well as the commented BAD_SEG in - // the next block - double ratio = 0.001; // TODO: the higher the ratio, the - // better the result (shorter - // segments) - p = new GraphicPoint(pt, p, ratio); - addPoint(p); - - // this is the "bad" segment - p = new GraphicPoint(pt, m_distance, a2 - half_pi); - - GraphicPoint p_ = new GraphicPoint(pt, p, ratio); - p_.type |= BAD_SEG; - addPoint(p_); - - addPoint(p); - } else { - // this method works for square and round, but not bevel - double r = (a2 - a1) * 0.5; - double d = m_distance / Math.abs(Math.sin(r)); - p = new GraphicPoint(pt, d, (a1 + a2) * 0.5); - addPoint(p, i); // will deal with reversed segments - } - continue; - } - - // outer angles - // check if we have an end point first - if ((pt.type & IS_END) != 0) { - // TODO: deal with other options. assume rounded and - // perpendicular for now - // we need to use the outer regular polygon of the round join - // TODO: explain this in a doc - - // calculate the number of points based on a flatten tolerance - double r = 1.0 - flattenTolerance / Math.abs(m_distance); - long na = 1; - double da = (m_distance < 0) ? -pi : pi; // da is negative when - // m_offset is - // negative (???) - if (r > -1.0 && r < 1.0) { - double a = Math.acos(r) * 2; // angle where "arrow?" is less - // than flattenTolerance - // do not consider an angle smaller than a degree - if (a < oneDegree) - a = oneDegree; - na = (long) (pi / a + 1.5); - if (na > 1) - da /= na; - } - // add first point - double a = a1 + half_pi; - p = new GraphicPoint(pt, m_distance, a); - if (i == 0) - p.type |= CLOSING_SEG; // TODO: should we simplify this by - // considering the last point - // instead of the first one?? - addPoint(p, i); // will deal with reversed segments - - double d = m_distance / Math.cos(da / 2); - a += da / 2; - p = new GraphicPoint(pt, d, a); - p.type |= CLOSING_SEG; - addPoint(p); - - while (--na > 0) { - a += da; - p = new GraphicPoint(pt, d, a); - p.type |= CLOSING_SEG; - addPoint(p); - } - - // last point (optional except for the first point) - p = new GraphicPoint(pt, m_distance, a2 - half_pi); // this one - // is - // optional - // except - // for the - // first - // point - p.type |= CLOSING_SEG; - addPoint(p); - - continue; - } else if (m_joins == OperatorOffset.JoinType.Bevel) // bevel - { - p = new GraphicPoint(pt, m_distance, a1 + half_pi); - addPoint(p, i); // will deal with reversed segments - p = new GraphicPoint(pt, m_distance, a2 - half_pi); - addPoint(p); - continue; - } else if (m_joins == OperatorOffset.JoinType.Round) { - // we need to use the outer regular polygon of the round join - // TODO: explain this in a doc - - // calculate the number of points based on a flatten tolerance - double r = 1.0 - flattenTolerance / Math.abs(m_distance); - long na = 1; - double da = (a2 - half_pi) - (a1 + half_pi); // da is negative - // when - // m_distance is - // negative - if (r > -1.0 && r < 1.0) { - double a = Math.acos(r) * 2.0; // angle where "arrow?" is - // less than - // flattenTolerance - // do not consider an angle smaller than a degree - if (a < oneDegree) - a = oneDegree; - na = (long) (Math.abs(da) / a + 1.5); - if (na > 1) - da /= na; - } - double d = m_distance / Math.cos(da * 0.5); - double a = a1 + half_pi + da * 0.5; - p = new GraphicPoint(pt, d, a); - addPoint(p, i); // will deal with reversed segments - while (--na > 0) { - a += da; - p = new GraphicPoint(pt, d, a); - addPoint(p); - } - continue; - } else if (m_joins == OperatorOffset.JoinType.Miter) { - dx1 = pt1.x - pt.x; - dy1 = pt1.y - pt.y; - dx2 = pt2.x - pt.x; - dy2 = pt2.y - pt.y; - double d1 = Math.sqrt(dx1 * dx1 + dy1 * dy1); - double d2 = Math.sqrt(dx2 * dx2 + dy2 * dy2); - double cosa = (dx1 * dx2 + dy1 * dy2) / d1 / d2; - if (cosa > 1.0 - 1.0e-8) { - // there's a spike in the polygon boundary; this could - // happen when filtering out short segments in Init() - p = new GraphicPoint(pt, sqrt2 * m_distance, a2 - pi * 0.25); - addPoint(p, i); - p = new GraphicPoint(pt, sqrt2 * m_distance, a2 + pi * 0.25); - addPoint(p); - continue; - } - // original miter code - // if (m_miterLimit * m_miterLimit * (1 - cosa) < 2) - // { - // // bevel join - // p = new GraphicPoint(pt, m_distance, a1 + half_pi); - // AddPoint(p, src_poly, srcPtCount, i); // will deal with - // reversed segments - // p = new GraphicPoint(pt, m_distance, a2 - half_pi); - // AddPoint(p); - // continue; - // } - double distanceFromCorner = Math.abs(m_distance - / Math.sin(Math.acos(cosa) * 0.5)); - double bevelDistance = Math.abs(m_miterLimit * m_distance); - if (distanceFromCorner > bevelDistance) { - double r = (a2 - a1) * 0.5; - double d = m_distance / Math.abs(Math.sin(r)); - p = new GraphicPoint(pt, d, (a1 + a2) * 0.5); - - // construct bevel points, see comment in - // c:\ArcGIS\System\Geometry\Geometry\ConstructCurveImpl.cpp, - // ESRI::OffsetCurve::EstimateBevelPoints - Point2D corner = new Point2D(p.x, p.y); - Point2D through = new Point2D(pt.x, pt.y); - Point2D delta = new Point2D(); - delta.sub(corner, through); - - // Point2D midPoint = through + delta * (bevelDistance / - // delta.Length()); - Point2D midPoint = new Point2D(); - midPoint.scaleAdd(bevelDistance / delta.length(), delta, - through); - - double sideLength = Math.sqrt(distanceFromCorner - * distanceFromCorner - m_distance * m_distance), halfWidth = (distanceFromCorner - bevelDistance) - * Math.abs(m_distance) / sideLength; - - // delta = delta.RotateDirect(0.0, m_distance > 0.0 ? -1.0 : - // 1.0) * (halfWidth/delta.Length()); - if (m_distance > 0.0) - delta.leftPerpendicular(); - else - delta.rightPerpendicular(); - delta.scale(halfWidth / delta.length()); - - Point2D from = new Point2D(); - from.add(midPoint, delta); - Point2D to = new Point2D(); - to.sub(midPoint, delta); - p = new GraphicPoint(from); - // _ASSERT(::_finite(p.x)); - // _ASSERT(::_finite(p.y)); - addPoint(p, i); - p = new GraphicPoint(to); - // _ASSERT(::_finite(p.x)); - // _ASSERT(::_finite(p.y)); - addPoint(p); - continue; - } - // miter join - double r = (a2 - a1) * 0.5; - double d = m_distance / Math.abs(Math.sin(r)); // r should not - // be null - // (trapped by - // the bevel - // case) - p = new GraphicPoint(pt, d, (a1 + a2) * 0.5); - addPoint(p, i); // will deal with reversed segments - continue; - } else // the new "square" join - { - a2 = saved_a2; - - // identify if angle is less than pi/2 - // in this case, we introduce a segment that is perpendicular to - // the bissector of the angle - // TODO: see figure X for details - boolean bAddSegment; - if (m_distance > 0.0) { - if (a2 > a1) // > and not >= - a2 -= two_pi; - bAddSegment = (a1 - a2 < half_pi); - } else { - if (a2 < a1) // < and not <= - a2 += two_pi; - bAddSegment = (a2 - a1 < half_pi); - } - if (bAddSegment) { - // make it continuous when angle is pi/2 (but not tangent to - // the round join) - double d = m_distance * sqrt2; - double a; - - if (d < 0.0) - a = a1 + pi * 0.25; - else - a = a1 + 3.0 * pi * 0.25; - p = new GraphicPoint(pt, d, a); - addPoint(p, i); - - if (d < 0) - a = a2 - pi * 0.25; - else - a = a2 - 3.0 * pi * 0.25; - p = new GraphicPoint(pt, d, a); - addPoint(p); - } else // standard case: we just add the intersection point of - // offset segments - { - double r = (a2 - a1) * 0.5; - double d = m_distance / Math.abs(Math.sin(r)); - if (a2 < a1) - a2 += two_pi; // this guaranties that (a1 + a2) / 2 is - // on the right side with a positive - // offset - p = new GraphicPoint(pt, d, (a1 + a2) / 2); - addPoint(p, i); - } - } - } - - // closing point - m_a1 = a1_0; - m_a2 = a2_0; - addPoint(m_offsetPts.get(0), 0); - - // make sure the first point matches the last (in case a problem of - // reversed segment happens there) - pt = new GraphicPoint(m_offsetPts.get(m_offsetPtCount - 1)); - m_offsetPts.set(0, pt); - - // remove loops - return removeBadSegsFast(); - } - - void addPart(int iStart, int cPts) { - if (cPts < 2) - return; - - for (int i = 0; i < cPts; i++) { - GraphicPoint pt = m_offsetPts.get(iStart + i); - if (i != 0) - m_resultPath.lineTo(new Point2D(pt.x, pt.y)); - else - m_resultPath.startPath(new Point2D(pt.x, pt.y)); - } - } - - void _OffsetPath(MultiPath multiPath, int pathIndex, MultiPath resultingPath) { - int startVertex = multiPath.getPathStart(pathIndex); - int endVertex = multiPath.getPathEnd(pathIndex); - - m_offsetPts = new ArrayList(); - - // test if part is closed - m_resultPath = resultingPath; - m_resultPoints = 0; - if (multiPath.isClosedPath(pathIndex)) { - // check if last point is a duplicate of first - Point2D ptStart = multiPath.getXY(startVertex); - while (multiPath.getXY(endVertex - 1).isEqual(ptStart)) - endVertex--; - - // we need at least three points for a polygon - if (endVertex - startVertex >= 2) { - m_srcPtCount = endVertex - startVertex; - m_srcPts = new ArrayList(m_srcPtCount); - // TODO: may throw std::bad:alloc() - for (int i = startVertex; i < endVertex; i++) - m_srcPts.add(new GraphicPoint(multiPath.getXY(i))); - - if (buildOffset()) - addPart(0, m_offsetPtCount - 1); // do not repeat closing - // point - } - } else { - // remove duplicate points at extremities - Point2D ptStart = multiPath.getXY(startVertex); - while ((startVertex < endVertex) - && multiPath.getXY(startVertex + 1).isEqual(ptStart)) - startVertex++; - Point2D ptEnd = multiPath.getXY(endVertex - 1); - while ((startVertex < endVertex) - && multiPath.getXY(endVertex - 2).isEqual(ptEnd)) - endVertex--; - - // we need at least two points for a polyline - if (endVertex - startVertex >= 2) { - // close the line and mark the opposite segments as non valid - m_srcPtCount = (endVertex - startVertex) * 2 - 2; - m_srcPts = new ArrayList(m_srcPtCount); - // TODO: may throw std::bad:alloc() - - GraphicPoint pt = new GraphicPoint(multiPath.getXY(startVertex)); - pt.type |= IS_END + CLOSING_SEG; - m_srcPts.add(pt); - - for (int i = startVertex + 1; i < endVertex - 1; i++) { - pt = new GraphicPoint(multiPath.getXY(i)); - m_srcPts.add(pt); - } - - pt = new GraphicPoint(multiPath.getXY(endVertex - 1)); - pt.type |= IS_END; - m_srcPts.add(pt); - - for (int i = endVertex - 2; i >= startVertex + 1; i--) { - pt = new GraphicPoint(multiPath.getXY(i)); - pt.type |= CLOSING_SEG; - m_srcPts.add(pt); - } - - if (buildOffset()) - - if (m_offsetPts.size() >= 2) { - // extract the part that doesn't have the CLOSING_SEG - // attribute - - int iStart = -1; - int iEnd = -1; - boolean prevClosed = (m_offsetPts - .get(m_offsetPtCount - 1).type & CLOSING_SEG) != 0; - if (!prevClosed) - iStart = 0; - for (int i = 1; i < m_offsetPtCount; i++) { - boolean closed = (m_offsetPts.get(i).type & CLOSING_SEG) != 0; - if (!closed) { - if (prevClosed) { - // if ((m_offsetPts[i - 1].type & MOVE_TO) - // == 0) - // m_offsetPts[i - 1].type += MOVE_TO - - // LINE_TO; - iStart = i - 1; - } - } else { - if (!prevClosed) { - iEnd = i - 1; - // for (long i = iStart; i <= iEnd; i++) - // m_offsetPts[i].type &= OUR_FLAGS_MASK; - if (iEnd - iStart + 1 > 1) - addPart(iStart, iEnd - iStart + 1); - } - } - prevClosed = closed; - } - if (!prevClosed) { - iEnd = m_offsetPtCount - 1; - // for (long i = iStart; i <= iEnd; i++) - // m_offsetPts[i].type &= OUR_FLAGS_MASK; - if (iEnd - iStart + 1 > 1) - addPart(iStart, iEnd - iStart + 1); - } - } else { - int iStart = 0; - int iEnd = m_offsetPtCount - 1; - if (iStart >= 0 && iEnd - iStart >= 1) { - // for (long i = iStart; i <= iEnd; i++) - // m_offsetPts[i].type &= OUR_FLAGS_MASK; - addPart(iStart, iEnd - iStart + 1); - } - } - } - } - - // clear source - m_srcPts = null; - m_srcPtCount = 0; - // free offset buffer - m_offsetPts = null; - m_offsetPtCount = 0; - } - - boolean removeBadSegsFast() { - boolean bWrong = false; - - // initialize circular doubly-linked list - // skip last point which is dup of first point - for (int i = 0; i < m_offsetPtCount; i++) { - GraphicPoint pt = m_offsetPts.get(i); - pt.m_next = i + 1; - pt.m_prev = i - 1; - m_offsetPts.set(i, pt); - } - - // need to update the first and last elements - GraphicPoint pt; - - pt = m_offsetPts.get(0); - pt.m_prev = m_offsetPtCount - 2; - m_offsetPts.set(0, pt); - - pt = m_offsetPts.get(m_offsetPtCount - 2); - pt.m_next = 0; - m_offsetPts.set(m_offsetPtCount - 2, pt); - - int w = 0; - for (int i = 0; i < m_offsetPtCount; i++) { - if ((m_offsetPts.get(w).type & BAD_SEG) != 0) { - int wNext = deleteClosedSeg(w); - if (wNext != -1) - w = wNext; - else { - bWrong = true; - break; - } - } else - w = m_offsetPts.get(w).m_next; - } - - if (bWrong) - return false; - - // w is the index of a known good (i.e. surviving ) point in the offset - // array - compressOffsetArray(w); - return true; - } - - int deleteClosedSeg(int seg) { - int n = m_offsetPtCount - 1; // number of segments - - // check combinations of segments - int ip0 = seg, ip, im; - - for (int i = 1; i <= n - 2; i++) { - ip0 = m_offsetPts.get(ip0).m_next; - - ip = ip0; - im = seg; - - for (int j = 1; j <= i; j++) { - im = m_offsetPts.get(im).m_prev; - - if ((m_offsetPts.get(im).type & BAD_SEG) == 0 - && (m_offsetPts.get(ip).type & BAD_SEG) == 0) { - int rSegNext = handleClosedIntersection(im, ip); - if (rSegNext != -1) - return rSegNext; - } - - ip = m_offsetPts.get(ip).m_prev; - } - } - - return -1; - } - - // line segments defined by (im-1, im) and (ip-1, ip) - int handleClosedIntersection(int im, int ip) { - GraphicPoint pt1, pt2, pt3, pt4; - pt1 = m_offsetPts.get(m_offsetPts.get(im).m_prev); - pt2 = m_offsetPts.get(im); - pt3 = m_offsetPts.get(m_offsetPts.get(ip).m_prev); - pt4 = m_offsetPts.get(ip); - - if (!sectGraphicRect(pt1, pt2, pt3, pt4)) - return -1; - - // intersection - IntersectionInfo ii = new IntersectionInfo(); - if (findIntersection(pt1, pt2, pt3, pt4, ii) && !ii.atExistingPt) - if (Math.signum((pt2.x - pt1.x) * (pt4.y - pt3.y) - (pt2.y - pt1.y) - * (pt4.x - pt3.x)) != Math.signum(m_distance)) { - int prev0 = m_offsetPts.get(im).m_prev; - - ii.pt.type = pt2.type; - ii.pt.m_next = ip; - ii.pt.m_prev = prev0; - m_offsetPts.set(im, ii.pt); - - ii.pt = m_offsetPts.get(ip); - ii.pt.m_prev = im; - m_offsetPts.set(ip, ii.pt); - - return ip; - } - return -1; - } - - boolean sectGraphicRect(GraphicPoint pt1, GraphicPoint pt2, - GraphicPoint pt3, GraphicPoint pt4) { - return (Math.max(pt1.x, pt2.x) >= Math.min(pt3.x, pt4.x) - && Math.max(pt3.x, pt4.x) >= Math.min(pt1.x, pt2.x) - && Math.max(pt1.y, pt2.y) >= Math.min(pt3.y, pt4.y) && Math - .max(pt3.y, pt4.y) >= Math.min(pt1.y, pt2.y)); - } - - boolean findIntersection(GraphicPoint bp1, GraphicPoint bp2, - GraphicPoint bp3, GraphicPoint bp4, - IntersectionInfo intersectionInfo) { - intersectionInfo.atExistingPt = false; - - // Note: test if rectangles intersect already done by caller - - // intersection - double i, j, r, r1; - i = (bp2.y - bp1.y) * (bp4.x - bp3.x) - (bp2.x - bp1.x) - * (bp4.y - bp3.y); - j = (bp3.y - bp1.y) * (bp2.x - bp1.x) - (bp3.x - bp1.x) - * (bp2.y - bp1.y); - if (i == 0.0) - r = 2.0; - else - r = j / i; - - if ((r >= 0.0) && (r <= 1.0)) { - r1 = r; - i = (bp4.y - bp3.y) * (bp2.x - bp1.x) - (bp4.x - bp3.x) - * (bp2.y - bp1.y); - j = (bp1.y - bp3.y) * (bp4.x - bp3.x) - (bp1.x - bp3.x) - * (bp4.y - bp3.y); - - if (i == 0.0) - r = 2.0; - else - r = j / i; - - if ((r >= 0.0) && (r <= 1.0)) { - intersectionInfo.pt = new GraphicPoint(bp1.x + r - * (bp2.x - bp1.x), bp1.y + r * (bp2.y - bp1.y)); - intersectionInfo.pt.m = bp3.m + r1 * (bp4.m - bp3.m); - if (((r1 == 0.0) || (r1 == 1.0)) && ((r == 0.0) || (r == 1.0))) - intersectionInfo.atExistingPt = true; - - intersectionInfo.rFirst = r; - intersectionInfo.rSecond = r1; - - if (((r1 == 0.0) || (r1 == 1.0)) && ((r > 0.0) && (r < 1.0)) - || ((r == 0.0) || (r == 1.0)) - && ((r1 > 0.0) && (r1 < 1.0))) { - return false; - } - - return true; - } - } - return false; - } - - // i0 is the index of a known good point in the offset points array; that - // is, its the index of a point that isn't part of a deleted loop - void compressOffsetArray(int i0) { - int i_ = i0; - while (m_offsetPts.get(i_).m_prev < i_) - i_ = m_offsetPts.get(i_).m_prev; - - int j = 0, i = i_; - - do { - GraphicPoint pt = m_offsetPts.get(i); - m_offsetPts.set(j, pt); - i = pt.m_next; - j++; - } while (i != i_); - - m_offsetPts.set(j, m_offsetPts.get(0)); // duplicate closing point - - m_offsetPtCount = j + 1; - } - - void _OffsetMultiPath(MultiPath resultingPath) { - // we process all path independently, then merge the results - MultiPath multiPath = (MultiPath) m_inputGeometry; - SegmentIterator segmentIterator = multiPath.querySegmentIterator(); - if (segmentIterator == null) - return; // TODO: strategy on error? - - segmentIterator.resetToFirstPath(); - int pathIndex = -1; - while (segmentIterator.nextPath()) { - pathIndex++; - _OffsetPath(multiPath, pathIndex, resultingPath); - } - } - - Geometry _ConstructOffset() { - int gt = m_inputGeometry.getType().value(); - if (gt == Geometry.GeometryType.Line) { - return _OffsetLine(); - } - if (gt == Geometry.GeometryType.Envelope) { - return _OffsetEnvelope(); - } - if (Geometry.isSegment(gt)) { - Polyline poly = new Polyline(); - poly.addSegment((Segment) m_inputGeometry, true); - m_inputGeometry = poly; - return _ConstructOffset(); - } - if (gt == Geometry.GeometryType.Polyline) { - Polyline polyline = new Polyline(); - _OffsetMultiPath(polyline); - return polyline; - } - if (gt == Geometry.GeometryType.Polygon) { - Polygon polygon = new Polygon(); - _OffsetMultiPath(polygon); - return polygon; - } - // throw new GeometryException("not implemented"); - return null; - } + ProgressTracker m_progressTracker; + Geometry m_inputGeometry; + double m_distance; + double m_tolerance; + OperatorOffset.JoinType m_joins; + double m_miterLimit; + + // multipath offset + static class GraphicPoint { + double x, y; + int m_next, m_prev; + double m; + int type; + + GraphicPoint(double x_, double y_) { + x = x_; + y = y_; + type = 0; + m = 0; + } + + GraphicPoint(Point2D r) { + x = r.x; + y = r.y; + type = 0; + m = 0; + } + + GraphicPoint(GraphicPoint pt) { + x = pt.x; + y = pt.y; + type = pt.type; + m = pt.m; + } + + GraphicPoint(GraphicPoint srcPt, double d, double angle) { + x = srcPt.x + d * Math.cos(angle); + y = srcPt.y + d * Math.sin(angle); + type = srcPt.type; + m = srcPt.m; + } + + GraphicPoint(GraphicPoint pt1, GraphicPoint pt2) { + x = (pt1.x + pt2.x) * 0.5; + y = (pt1.y + pt2.y) * 0.5; + type = pt1.type; + m = pt1.m; + } + + GraphicPoint(GraphicPoint pt1, GraphicPoint pt2, double ratio) { + x = pt1.x + (pt2.x - pt1.x) * ratio; + y = pt1.y + (pt2.y - pt1.y) * ratio; + type = pt1.type; + m = pt1.m; + } + + } + + ; + + static class GraphicRect { + double x1, x2, y1, y2; + } + + ; + + static class IntersectionInfo { + GraphicPoint pt; + double rFirst; + double rSecond; + boolean atExistingPt; + } + + ; + + ArrayList m_srcPts; + int m_srcPtCount; + ArrayList m_offsetPts; + int m_offsetPtCount; + + MultiPath m_resultPath; + int m_resultPoints; + double m_a1, m_a2; + boolean m_bBadSegs; + + ConstructOffset(ProgressTracker progressTracker) { + m_progressTracker = progressTracker; + } + + // static + static Geometry execute(Geometry inputGeometry, double distance, + OperatorOffset.JoinType joins, double miterLimit, double tolerance, + ProgressTracker progressTracker) { + if (inputGeometry == null) + throw new IllegalArgumentException(); + if (inputGeometry.getDimension() < 1)// can offset Polygons and + // Polylines only + throw new IllegalArgumentException(); + if (distance == 0 || inputGeometry.isEmpty()) + return inputGeometry; + ConstructOffset offset = new ConstructOffset(progressTracker); + offset.m_inputGeometry = inputGeometry; + offset.m_distance = distance; + offset.m_tolerance = tolerance; + offset.m_joins = joins; + offset.m_miterLimit = miterLimit; + return offset._ConstructOffset(); + } + + Geometry _OffsetLine() { + Line line = (Line) m_inputGeometry; + Point2D start = line.getStartXY(); + Point2D end = line.getEndXY(); + Point2D v = new Point2D(); + v.sub(end, start); + v.normalize(); + v.leftPerpendicular(); + v.scale(m_distance); + start.add(v); + end.add(v); + Line resLine = (Line) line.createInstance(); + line.setStartXY(start); + line.setEndXY(end); + return resLine; + } + + Geometry _OffsetEnvelope() { + Envelope envelope = (Envelope) m_inputGeometry; + if ((m_distance > 0) && (m_joins != OperatorOffset.JoinType.Miter)) { + Polygon poly = new Polygon(); + poly.addEnvelope(envelope, false); + m_inputGeometry = poly; + return _ConstructOffset(); + } + + Envelope resEnv = new Envelope(envelope.m_envelope); + resEnv.inflate(m_distance, m_distance); + return resEnv; + } + + private final double pi = Math.PI;// GEOMETRYX_PI; + private final double two_pi = Math.PI * 2;// GEOMETRYX_2PI; + private final double half_pi = Math.PI / 2;// GEOMETRYX_HalfPI; + private final double sqrt2 = 1.4142135623730950488016887242097; + private final double oneDegree = 0.01745329251994329576923690768489; + + private final int BAD_SEG = 0x0100; + private final int IS_END = 0x0200; + private final int CLOSING_SEG = 0x0400; + + void addPoint(GraphicPoint pt) { + m_offsetPts.add(pt); + m_offsetPtCount++; + } + + double scal(GraphicPoint pt1, GraphicPoint pt2, GraphicPoint pt3, + GraphicPoint pt4) { + return (pt2.x - pt1.x) * (pt4.x - pt3.x) + (pt2.y - pt1.y) + * (pt4.y - pt3.y); + } + + // offPt is the point to add. + // this point corresponds to the offset version of the end of seg1. + // it could generate a segment going in the opposite direction of the + // original segment + // this situation is handled here by adding an additional "bad" segment + void addPoint(GraphicPoint offPt, int i_src) { + if (m_offsetPtCount == 0) // TODO: can we have this outside of this + // method? + { + addPoint(offPt); + return; + } + + int n_src = m_srcPtCount; + GraphicPoint pt1, pt; + pt1 = m_srcPts.get(i_src == 0 ? n_src - 1 : i_src - 1); + pt = m_srcPts.get(i_src); + + // calculate scalar product to determine if the offset segment goes in + // the same/opposite direction compared to the original one + double s = scal(pt1, pt, m_offsetPts.get(m_offsetPtCount - 1), offPt); + if (s > 0) + // original segment and offset segment go in the same direction. Just + // add the point + { + addPoint(offPt); + return; + } + + if (s < 0) { + // we will add a loop. We need to make sure the points we introduce + // don't generate a "reversed" segment + // let's project the first point of the reversed segment + // (m_offsetPts + m_offsetPtCount - 1) to check + // if it falls on the good side of the original segment (scalar + // product sign again) + if (scal(pt1, pt, pt, m_offsetPts.get(m_offsetPtCount - 1)) > 0) { + GraphicPoint p; + + // change value of m_offsetPts + m_offsetPtCount - 1 + int k; + if (i_src == 0) + k = n_src - 2; + else if (i_src == 1) + k = n_src - 1; + else + k = i_src - 2; + GraphicPoint pt0 = m_srcPts.get(k); + + double a = Math.atan2(pt1.y - pt0.y, pt1.x - pt0.x); + p = new GraphicPoint(pt1, m_distance, a - half_pi); + m_offsetPts.set(m_offsetPtCount - 1, p); + + if (m_joins == OperatorOffset.JoinType.Bevel + || m_joins == OperatorOffset.JoinType.Miter) { + // this block is added as well as the commented BAD_SEG in + // the next block + p = new GraphicPoint(p, pt1); + addPoint(p); + + // "bad" segment + p = new GraphicPoint(pt1, m_distance, m_a1 + half_pi); + + GraphicPoint p_ = new GraphicPoint(p, pt1); + p_.type |= BAD_SEG; + addPoint(p_); + + addPoint(p); + } else { + // the working stuff for round and square + + // "bad" segment + p = new GraphicPoint(pt1, m_distance, m_a1 + half_pi); + p.type |= BAD_SEG; + addPoint(p); + } + + // add offPt + addPoint(offPt, i_src); + } else { + GraphicPoint p; + + // we don't add offPt but the loop containing the "bad" segment + p = new GraphicPoint(pt, m_distance, m_a1 + half_pi); + addPoint(p); + + if (m_joins == OperatorOffset.JoinType.Bevel + || m_joins == OperatorOffset.JoinType.Miter) { + // this block is added as well as the commented BAD_SEG in + // the next block + p = new GraphicPoint(p, pt); + addPoint(p); + + p = new GraphicPoint(pt, m_distance, m_a2 - half_pi); + GraphicPoint p_ = new GraphicPoint(p, pt); + p_.type |= BAD_SEG; + addPoint(p_); + + addPoint(p); + } else { + // the working stuff for round and square + p = new GraphicPoint(pt, m_distance, m_a2 - half_pi); + p.type |= BAD_SEG; + addPoint(p); + } + } + } + } + + boolean buildOffset() { + // make sure we have at least three points and no identical points + int i; + double a1, a2; + GraphicPoint pt, pt1, pt2; + GraphicPoint p; + + // number of points to deal with + int n = m_srcPtCount; + + m_offsetPtCount = 0; + + double flattenTolerance = m_tolerance * 0.5; + + double a1_0 = 0; + double a2_0 = 0; + for (i = 0; i < n; i++) { + pt = m_srcPts.get(i); + + // point before + if (i == 0) + pt1 = m_srcPts.get(n - 1); + else + pt1 = m_srcPts.get(i - 1); + + // point after + if (i == n - 1) + pt2 = m_srcPts.get(0); + else + pt2 = m_srcPts.get(i + 1); + + // angles of enclosing segments + double dx1 = pt1.x - pt.x; + double dy1 = pt1.y - pt.y; + double dx2 = pt2.x - pt.x; + double dy2 = pt2.y - pt.y; + a1 = Math.atan2(dy1, dx1); + a2 = Math.atan2(dy2, dx2); + m_a1 = a1; + m_a2 = a2; + if (i == 0) { + a1_0 = a1; + a2_0 = a2; + } + + // double dot_product = dx1 * dx2 + dy1 * dy2; + double cross_product = dx1 * dy2 - dx2 * dy1; + // boolean bInnerAngle = (cross_product == 0) ? (m_distance > 0) : + // (cross_product * m_distance >= 0.0); + + // check for inner angles (always managed the same, whatever the + // type of join) + double saved_a2 = a2; + if (a2 < a1) + a2 += two_pi; // this guaranties that (a1 + a2) / 2 is on the + // right side of the curve + if (cross_product * m_distance > 0.0) // inner angle + { + // inner angle + if (m_joins == OperatorOffset.JoinType.Bevel + || m_joins == OperatorOffset.JoinType.Miter) { + p = new GraphicPoint(pt, m_distance, a1 + half_pi); + addPoint(p); + + // this block is added as well as the commented BAD_SEG in + // the next block + double ratio = 0.001; // TODO: the higher the ratio, the + // better the result (shorter + // segments) + p = new GraphicPoint(pt, p, ratio); + addPoint(p); + + // this is the "bad" segment + p = new GraphicPoint(pt, m_distance, a2 - half_pi); + + GraphicPoint p_ = new GraphicPoint(pt, p, ratio); + p_.type |= BAD_SEG; + addPoint(p_); + + addPoint(p); + } else { + // this method works for square and round, but not bevel + double r = (a2 - a1) * 0.5; + double d = m_distance / Math.abs(Math.sin(r)); + p = new GraphicPoint(pt, d, (a1 + a2) * 0.5); + addPoint(p, i); // will deal with reversed segments + } + continue; + } + + // outer angles + // check if we have an end point first + if ((pt.type & IS_END) != 0) { + // TODO: deal with other options. assume rounded and + // perpendicular for now + // we need to use the outer regular polygon of the round join + // TODO: explain this in a doc + + // calculate the number of points based on a flatten tolerance + double r = 1.0 - flattenTolerance / Math.abs(m_distance); + long na = 1; + double da = (m_distance < 0) ? -pi : pi; // da is negative when + // m_offset is + // negative (???) + if (r > -1.0 && r < 1.0) { + double a = Math.acos(r) * 2; // angle where "arrow?" is less + // than flattenTolerance + // do not consider an angle smaller than a degree + if (a < oneDegree) + a = oneDegree; + na = (long) (pi / a + 1.5); + if (na > 1) + da /= na; + } + // add first point + double a = a1 + half_pi; + p = new GraphicPoint(pt, m_distance, a); + if (i == 0) + p.type |= CLOSING_SEG; // TODO: should we simplify this by + // considering the last point + // instead of the first one?? + addPoint(p, i); // will deal with reversed segments + + double d = m_distance / Math.cos(da / 2); + a += da / 2; + p = new GraphicPoint(pt, d, a); + p.type |= CLOSING_SEG; + addPoint(p); + + while (--na > 0) { + a += da; + p = new GraphicPoint(pt, d, a); + p.type |= CLOSING_SEG; + addPoint(p); + } + + // last point (optional except for the first point) + p = new GraphicPoint(pt, m_distance, a2 - half_pi); // this one + // is + // optional + // except + // for the + // first + // point + p.type |= CLOSING_SEG; + addPoint(p); + + continue; + } else if (m_joins == OperatorOffset.JoinType.Bevel) // bevel + { + p = new GraphicPoint(pt, m_distance, a1 + half_pi); + addPoint(p, i); // will deal with reversed segments + p = new GraphicPoint(pt, m_distance, a2 - half_pi); + addPoint(p); + continue; + } else if (m_joins == OperatorOffset.JoinType.Round) { + // we need to use the outer regular polygon of the round join + // TODO: explain this in a doc + + // calculate the number of points based on a flatten tolerance + double r = 1.0 - flattenTolerance / Math.abs(m_distance); + long na = 1; + double da = (a2 - half_pi) - (a1 + half_pi); // da is negative + // when + // m_distance is + // negative + if (r > -1.0 && r < 1.0) { + double a = Math.acos(r) * 2.0; // angle where "arrow?" is + // less than + // flattenTolerance + // do not consider an angle smaller than a degree + if (a < oneDegree) + a = oneDegree; + na = (long) (Math.abs(da) / a + 1.5); + if (na > 1) + da /= na; + } + double d = m_distance / Math.cos(da * 0.5); + double a = a1 + half_pi + da * 0.5; + p = new GraphicPoint(pt, d, a); + addPoint(p, i); // will deal with reversed segments + while (--na > 0) { + a += da; + p = new GraphicPoint(pt, d, a); + addPoint(p); + } + continue; + } else if (m_joins == OperatorOffset.JoinType.Miter) { + dx1 = pt1.x - pt.x; + dy1 = pt1.y - pt.y; + dx2 = pt2.x - pt.x; + dy2 = pt2.y - pt.y; + double d1 = Math.sqrt(dx1 * dx1 + dy1 * dy1); + double d2 = Math.sqrt(dx2 * dx2 + dy2 * dy2); + double cosa = (dx1 * dx2 + dy1 * dy2) / d1 / d2; + if (cosa > 1.0 - 1.0e-8) { + // there's a spike in the polygon boundary; this could + // happen when filtering out short segments in Init() + p = new GraphicPoint(pt, sqrt2 * m_distance, a2 - pi * 0.25); + addPoint(p, i); + p = new GraphicPoint(pt, sqrt2 * m_distance, a2 + pi * 0.25); + addPoint(p); + continue; + } + // original miter code + // if (m_miterLimit * m_miterLimit * (1 - cosa) < 2) + // { + // // bevel join + // p = new GraphicPoint(pt, m_distance, a1 + half_pi); + // AddPoint(p, src_poly, srcPtCount, i); // will deal with + // reversed segments + // p = new GraphicPoint(pt, m_distance, a2 - half_pi); + // AddPoint(p); + // continue; + // } + double distanceFromCorner = Math.abs(m_distance + / Math.sin(Math.acos(cosa) * 0.5)); + double bevelDistance = Math.abs(m_miterLimit * m_distance); + if (distanceFromCorner > bevelDistance) { + double r = (a2 - a1) * 0.5; + double d = m_distance / Math.abs(Math.sin(r)); + p = new GraphicPoint(pt, d, (a1 + a2) * 0.5); + + // construct bevel points, see comment in + // c:\ArcGIS\System\Geometry\Geometry\ConstructCurveImpl.cpp, + // ESRI::OffsetCurve::EstimateBevelPoints + Point2D corner = new Point2D(p.x, p.y); + Point2D through = new Point2D(pt.x, pt.y); + Point2D delta = new Point2D(); + delta.sub(corner, through); + + // Point2D midPoint = through + delta * (bevelDistance / + // delta.Length()); + Point2D midPoint = new Point2D(); + midPoint.scaleAdd(bevelDistance / delta.length(), delta, + through); + + double sideLength = Math.sqrt(distanceFromCorner + * distanceFromCorner - m_distance * m_distance), halfWidth = (distanceFromCorner - bevelDistance) + * Math.abs(m_distance) / sideLength; + + // delta = delta.RotateDirect(0.0, m_distance > 0.0 ? -1.0 : + // 1.0) * (halfWidth/delta.Length()); + if (m_distance > 0.0) + delta.leftPerpendicular(); + else + delta.rightPerpendicular(); + delta.scale(halfWidth / delta.length()); + + Point2D from = new Point2D(); + from.add(midPoint, delta); + Point2D to = new Point2D(); + to.sub(midPoint, delta); + p = new GraphicPoint(from); + // _ASSERT(::_finite(p.x)); + // _ASSERT(::_finite(p.y)); + addPoint(p, i); + p = new GraphicPoint(to); + // _ASSERT(::_finite(p.x)); + // _ASSERT(::_finite(p.y)); + addPoint(p); + continue; + } + // miter join + double r = (a2 - a1) * 0.5; + double d = m_distance / Math.abs(Math.sin(r)); // r should not + // be null + // (trapped by + // the bevel + // case) + p = new GraphicPoint(pt, d, (a1 + a2) * 0.5); + addPoint(p, i); // will deal with reversed segments + continue; + } else // the new "square" join + { + a2 = saved_a2; + + // identify if angle is less than pi/2 + // in this case, we introduce a segment that is perpendicular to + // the bissector of the angle + // TODO: see figure X for details + boolean bAddSegment; + if (m_distance > 0.0) { + if (a2 > a1) // > and not >= + a2 -= two_pi; + bAddSegment = (a1 - a2 < half_pi); + } else { + if (a2 < a1) // < and not <= + a2 += two_pi; + bAddSegment = (a2 - a1 < half_pi); + } + if (bAddSegment) { + // make it continuous when angle is pi/2 (but not tangent to + // the round join) + double d = m_distance * sqrt2; + double a; + + if (d < 0.0) + a = a1 + pi * 0.25; + else + a = a1 + 3.0 * pi * 0.25; + p = new GraphicPoint(pt, d, a); + addPoint(p, i); + + if (d < 0) + a = a2 - pi * 0.25; + else + a = a2 - 3.0 * pi * 0.25; + p = new GraphicPoint(pt, d, a); + addPoint(p); + } else // standard case: we just add the intersection point of + // offset segments + { + double r = (a2 - a1) * 0.5; + double d = m_distance / Math.abs(Math.sin(r)); + if (a2 < a1) + a2 += two_pi; // this guaranties that (a1 + a2) / 2 is + // on the right side with a positive + // offset + p = new GraphicPoint(pt, d, (a1 + a2) / 2); + addPoint(p, i); + } + } + } + + // closing point + m_a1 = a1_0; + m_a2 = a2_0; + addPoint(m_offsetPts.get(0), 0); + + // make sure the first point matches the last (in case a problem of + // reversed segment happens there) + pt = new GraphicPoint(m_offsetPts.get(m_offsetPtCount - 1)); + m_offsetPts.set(0, pt); + + // remove loops + return removeBadSegsFast(); + } + + void addPart(int iStart, int cPts) { + if (cPts < 2) + return; + + for (int i = 0; i < cPts; i++) { + GraphicPoint pt = m_offsetPts.get(iStart + i); + if (i != 0) + m_resultPath.lineTo(new Point2D(pt.x, pt.y)); + else + m_resultPath.startPath(new Point2D(pt.x, pt.y)); + } + } + + void _OffsetPath(MultiPath multiPath, int pathIndex, MultiPath resultingPath) { + int startVertex = multiPath.getPathStart(pathIndex); + int endVertex = multiPath.getPathEnd(pathIndex); + + m_offsetPts = new ArrayList(); + + // test if part is closed + m_resultPath = resultingPath; + m_resultPoints = 0; + if (multiPath.isClosedPath(pathIndex)) { + // check if last point is a duplicate of first + Point2D ptStart = multiPath.getXY(startVertex); + while (multiPath.getXY(endVertex - 1).isEqual(ptStart)) + endVertex--; + + // we need at least three points for a polygon + if (endVertex - startVertex >= 2) { + m_srcPtCount = endVertex - startVertex; + m_srcPts = new ArrayList(m_srcPtCount); + // TODO: may throw std::bad:alloc() + for (int i = startVertex; i < endVertex; i++) + m_srcPts.add(new GraphicPoint(multiPath.getXY(i))); + + if (buildOffset()) + addPart(0, m_offsetPtCount - 1); // do not repeat closing + // point + } + } else { + // remove duplicate points at extremities + Point2D ptStart = multiPath.getXY(startVertex); + while ((startVertex < endVertex) + && multiPath.getXY(startVertex + 1).isEqual(ptStart)) + startVertex++; + Point2D ptEnd = multiPath.getXY(endVertex - 1); + while ((startVertex < endVertex) + && multiPath.getXY(endVertex - 2).isEqual(ptEnd)) + endVertex--; + + // we need at least two points for a polyline + if (endVertex - startVertex >= 2) { + // close the line and mark the opposite segments as non valid + m_srcPtCount = (endVertex - startVertex) * 2 - 2; + m_srcPts = new ArrayList(m_srcPtCount); + // TODO: may throw std::bad:alloc() + + GraphicPoint pt = new GraphicPoint(multiPath.getXY(startVertex)); + pt.type |= IS_END + CLOSING_SEG; + m_srcPts.add(pt); + + for (int i = startVertex + 1; i < endVertex - 1; i++) { + pt = new GraphicPoint(multiPath.getXY(i)); + m_srcPts.add(pt); + } + + pt = new GraphicPoint(multiPath.getXY(endVertex - 1)); + pt.type |= IS_END; + m_srcPts.add(pt); + + for (int i = endVertex - 2; i >= startVertex + 1; i--) { + pt = new GraphicPoint(multiPath.getXY(i)); + pt.type |= CLOSING_SEG; + m_srcPts.add(pt); + } + + if (buildOffset()) + + if (m_offsetPts.size() >= 2) { + // extract the part that doesn't have the CLOSING_SEG + // attribute + + int iStart = -1; + int iEnd = -1; + boolean prevClosed = (m_offsetPts + .get(m_offsetPtCount - 1).type & CLOSING_SEG) != 0; + if (!prevClosed) + iStart = 0; + for (int i = 1; i < m_offsetPtCount; i++) { + boolean closed = (m_offsetPts.get(i).type & CLOSING_SEG) != 0; + if (!closed) { + if (prevClosed) { + // if ((m_offsetPts[i - 1].type & MOVE_TO) + // == 0) + // m_offsetPts[i - 1].type += MOVE_TO - + // LINE_TO; + iStart = i - 1; + } + } else { + if (!prevClosed) { + iEnd = i - 1; + // for (long i = iStart; i <= iEnd; i++) + // m_offsetPts[i].type &= OUR_FLAGS_MASK; + if (iEnd - iStart + 1 > 1) + addPart(iStart, iEnd - iStart + 1); + } + } + prevClosed = closed; + } + if (!prevClosed) { + iEnd = m_offsetPtCount - 1; + // for (long i = iStart; i <= iEnd; i++) + // m_offsetPts[i].type &= OUR_FLAGS_MASK; + if (iEnd - iStart + 1 > 1) + addPart(iStart, iEnd - iStart + 1); + } + } else { + int iStart = 0; + int iEnd = m_offsetPtCount - 1; + if (iStart >= 0 && iEnd - iStart >= 1) { + // for (long i = iStart; i <= iEnd; i++) + // m_offsetPts[i].type &= OUR_FLAGS_MASK; + addPart(iStart, iEnd - iStart + 1); + } + } + } + } + + // clear source + m_srcPts = null; + m_srcPtCount = 0; + // free offset buffer + m_offsetPts = null; + m_offsetPtCount = 0; + } + + boolean removeBadSegsFast() { + boolean bWrong = false; + + // initialize circular doubly-linked list + // skip last point which is dup of first point + for (int i = 0; i < m_offsetPtCount; i++) { + GraphicPoint pt = m_offsetPts.get(i); + pt.m_next = i + 1; + pt.m_prev = i - 1; + m_offsetPts.set(i, pt); + } + + // need to update the first and last elements + GraphicPoint pt; + + pt = m_offsetPts.get(0); + pt.m_prev = m_offsetPtCount - 2; + m_offsetPts.set(0, pt); + + pt = m_offsetPts.get(m_offsetPtCount - 2); + pt.m_next = 0; + m_offsetPts.set(m_offsetPtCount - 2, pt); + + int w = 0; + for (int i = 0; i < m_offsetPtCount; i++) { + if ((m_offsetPts.get(w).type & BAD_SEG) != 0) { + int wNext = deleteClosedSeg(w); + if (wNext != -1) + w = wNext; + else { + bWrong = true; + break; + } + } else + w = m_offsetPts.get(w).m_next; + } + + if (bWrong) + return false; + + // w is the index of a known good (i.e. surviving ) point in the offset + // array + compressOffsetArray(w); + return true; + } + + int deleteClosedSeg(int seg) { + int n = m_offsetPtCount - 1; // number of segments + + // check combinations of segments + int ip0 = seg, ip, im; + + for (int i = 1; i <= n - 2; i++) { + ip0 = m_offsetPts.get(ip0).m_next; + + ip = ip0; + im = seg; + + for (int j = 1; j <= i; j++) { + im = m_offsetPts.get(im).m_prev; + + if ((m_offsetPts.get(im).type & BAD_SEG) == 0 + && (m_offsetPts.get(ip).type & BAD_SEG) == 0) { + int rSegNext = handleClosedIntersection(im, ip); + if (rSegNext != -1) + return rSegNext; + } + + ip = m_offsetPts.get(ip).m_prev; + } + } + + return -1; + } + + // line segments defined by (im-1, im) and (ip-1, ip) + int handleClosedIntersection(int im, int ip) { + GraphicPoint pt1, pt2, pt3, pt4; + pt1 = m_offsetPts.get(m_offsetPts.get(im).m_prev); + pt2 = m_offsetPts.get(im); + pt3 = m_offsetPts.get(m_offsetPts.get(ip).m_prev); + pt4 = m_offsetPts.get(ip); + + if (!sectGraphicRect(pt1, pt2, pt3, pt4)) + return -1; + + // intersection + IntersectionInfo ii = new IntersectionInfo(); + if (findIntersection(pt1, pt2, pt3, pt4, ii) && !ii.atExistingPt) + if (Math.signum((pt2.x - pt1.x) * (pt4.y - pt3.y) - (pt2.y - pt1.y) + * (pt4.x - pt3.x)) != Math.signum(m_distance)) { + int prev0 = m_offsetPts.get(im).m_prev; + + ii.pt.type = pt2.type; + ii.pt.m_next = ip; + ii.pt.m_prev = prev0; + m_offsetPts.set(im, ii.pt); + + ii.pt = m_offsetPts.get(ip); + ii.pt.m_prev = im; + m_offsetPts.set(ip, ii.pt); + + return ip; + } + return -1; + } + + boolean sectGraphicRect(GraphicPoint pt1, GraphicPoint pt2, + GraphicPoint pt3, GraphicPoint pt4) { + return (Math.max(pt1.x, pt2.x) >= Math.min(pt3.x, pt4.x) + && Math.max(pt3.x, pt4.x) >= Math.min(pt1.x, pt2.x) + && Math.max(pt1.y, pt2.y) >= Math.min(pt3.y, pt4.y) && Math + .max(pt3.y, pt4.y) >= Math.min(pt1.y, pt2.y)); + } + + boolean findIntersection(GraphicPoint bp1, GraphicPoint bp2, + GraphicPoint bp3, GraphicPoint bp4, + IntersectionInfo intersectionInfo) { + intersectionInfo.atExistingPt = false; + + // Note: test if rectangles intersect already done by caller + + // intersection + double i, j, r, r1; + i = (bp2.y - bp1.y) * (bp4.x - bp3.x) - (bp2.x - bp1.x) + * (bp4.y - bp3.y); + j = (bp3.y - bp1.y) * (bp2.x - bp1.x) - (bp3.x - bp1.x) + * (bp2.y - bp1.y); + if (i == 0.0) + r = 2.0; + else + r = j / i; + + if ((r >= 0.0) && (r <= 1.0)) { + r1 = r; + i = (bp4.y - bp3.y) * (bp2.x - bp1.x) - (bp4.x - bp3.x) + * (bp2.y - bp1.y); + j = (bp1.y - bp3.y) * (bp4.x - bp3.x) - (bp1.x - bp3.x) + * (bp4.y - bp3.y); + + if (i == 0.0) + r = 2.0; + else + r = j / i; + + if ((r >= 0.0) && (r <= 1.0)) { + intersectionInfo.pt = new GraphicPoint(bp1.x + r + * (bp2.x - bp1.x), bp1.y + r * (bp2.y - bp1.y)); + intersectionInfo.pt.m = bp3.m + r1 * (bp4.m - bp3.m); + if (((r1 == 0.0) || (r1 == 1.0)) && ((r == 0.0) || (r == 1.0))) + intersectionInfo.atExistingPt = true; + + intersectionInfo.rFirst = r; + intersectionInfo.rSecond = r1; + + if (((r1 == 0.0) || (r1 == 1.0)) && ((r > 0.0) && (r < 1.0)) + || ((r == 0.0) || (r == 1.0)) + && ((r1 > 0.0) && (r1 < 1.0))) { + return false; + } + + return true; + } + } + return false; + } + + // i0 is the index of a known good point in the offset points array; that + // is, its the index of a point that isn't part of a deleted loop + void compressOffsetArray(int i0) { + int i_ = i0; + while (m_offsetPts.get(i_).m_prev < i_) + i_ = m_offsetPts.get(i_).m_prev; + + int j = 0, i = i_; + + do { + GraphicPoint pt = m_offsetPts.get(i); + m_offsetPts.set(j, pt); + i = pt.m_next; + j++; + } while (i != i_); + + m_offsetPts.set(j, m_offsetPts.get(0)); // duplicate closing point + + m_offsetPtCount = j + 1; + } + + void _OffsetMultiPath(MultiPath resultingPath) { + // we process all path independently, then merge the results + MultiPath multiPath = (MultiPath) m_inputGeometry; + SegmentIterator segmentIterator = multiPath.querySegmentIterator(); + if (segmentIterator == null) + return; // TODO: strategy on error? + + segmentIterator.resetToFirstPath(); + int pathIndex = -1; + while (segmentIterator.nextPath()) { + pathIndex++; + _OffsetPath(multiPath, pathIndex, resultingPath); + } + } + + Geometry _ConstructOffset() { + int gt = m_inputGeometry.getType().value(); + if (gt == Geometry.GeometryType.Line) { + return _OffsetLine(); + } + if (gt == Geometry.GeometryType.Envelope) { + return _OffsetEnvelope(); + } + if (Geometry.isSegment(gt)) { + Polyline poly = new Polyline(); + poly.addSegment((Segment) m_inputGeometry, true); + m_inputGeometry = poly; + return _ConstructOffset(); + } + if (gt == Geometry.GeometryType.Polyline) { + Polyline polyline = new Polyline(); + _OffsetMultiPath(polyline); + return polyline; + } + if (gt == Geometry.GeometryType.Polygon) { + Polygon polygon = new Polygon(); + _OffsetMultiPath(polygon); + return polygon; + } + // throw new GeometryException("not implemented"); + return null; + } } diff --git a/src/main/java/com/esri/core/geometry/ConvexHull.java b/src/main/java/com/esri/core/geometry/ConvexHull.java index 172ca92b..75a02f75 100644 --- a/src/main/java/com/esri/core/geometry/ConvexHull.java +++ b/src/main/java/com/esri/core/geometry/ConvexHull.java @@ -24,730 +24,736 @@ package com.esri.core.geometry; class ConvexHull { - /* - * Constructor for a Convex_hull object. Used for dynamic insertion of geometries to create a convex hull. - */ - ConvexHull() { - m_tree_hull = new Treap(); - m_tree_hull.setCapacity(20); - m_shape = new EditShape(); - m_geometry_handle = m_shape.createGeometry(Geometry.Type.MultiPoint); - m_path_handle = m_shape.insertPath(m_geometry_handle, -1); - m_call_back = new CallBackShape(this); - } - - private ConvexHull(AttributeStreamOfDbl stream, int n) { - m_tree_hull = new Treap(); - m_tree_hull.setCapacity(Math.min(20, n)); - m_stream = stream; - m_call_back = new CallBackStream(this); - } - - private ConvexHull(Point2D[] points, int n) { - m_tree_hull = new Treap(); - m_tree_hull.setCapacity(Math.min(20, n)); - m_points = points; - m_call_back = new CallBackPoints(this); - } - - /** - * Adds a geometry to the current bounding geometry using an incremental algorithm for dynamic insertion. - * \param geometry The geometry to add to the bounding geometry. - */ - - void addGeometry(Geometry geometry) { - int type = geometry.getType().value(); - - if (MultiVertexGeometry.isMultiVertex(type)) - addMultiVertexGeometry_((MultiVertexGeometry) geometry); - else if (MultiPath.isSegment(type)) - addSegment_((Segment) geometry); - else if (type == Geometry.GeometryType.Envelope) - addEnvelope_((Envelope) geometry); - else if (type == Geometry.GeometryType.Point) - addPoint_((Point) geometry); - else - throw new IllegalArgumentException("invalid shape type"); - } - - /** - * Gets the current bounding geometry. - * Returns a Geometry. - */ - - Geometry getBoundingGeometry() { - // Extracts the convex hull from the tree. Reading the tree in order from first to last is the resulting convex hull. - Point point = new Point(); - int first = m_tree_hull.getFirst(-1); - Polygon hull = new Polygon(m_shape.getVertexDescription()); - m_shape.queryPoint(m_tree_hull.getElement(first), point); - hull.startPath(point); - - for (int i = m_tree_hull.getNext(first); i != -1; i = m_tree_hull.getNext(i)) { - m_shape.queryPoint(m_tree_hull.getElement(i), point); - hull.lineTo(point); - } - - return hull; - } - - /** - * Static method to construct the convex hull of a Multi_vertex_geometry. - * Returns a Geometry. - * \param mvg The geometry used to create the convex hull. - */ - - static Geometry construct(MultiVertexGeometry mvg) { - if (mvg.isEmpty()) - return new Polygon(mvg.getDescription()); - - MultiVertexGeometryImpl mvg_impl = (MultiVertexGeometryImpl) mvg._getImpl(); - int N = mvg_impl.getPointCount(); - - if (N <= 2) { - if (N == 1 || mvg_impl.getXY(0).equals(mvg_impl.getXY(1))) { - Point point = new Point(mvg_impl.getDescription()); - mvg_impl.getPointByVal(0, point); - return point; - } else { - Point pt = new Point(); - Polyline polyline = new Polyline(mvg_impl.getDescription()); - mvg_impl.getPointByVal(0, pt); - polyline.startPath(pt); - mvg_impl.getPointByVal(1, pt); - polyline.lineTo(pt); - return polyline; - } - } - - AttributeStreamOfDbl stream = (AttributeStreamOfDbl) mvg_impl.getAttributeStreamRef(VertexDescription.Semantics.POSITION); - ConvexHull convex_hull = new ConvexHull(stream, N); - - int t0 = 0, tm = 1; - Point2D pt_0 = new Point2D(); - Point2D pt_m = new Point2D(); - Point2D pt_p = new Point2D(); - - stream.read(t0 << 1, pt_0); - - while (true) { - if (tm >= N) - break; - - stream.read(tm << 1, pt_m); - if (!pt_m.isEqual(pt_0, NumberUtils.doubleEps())) - break; - - tm++; // We don't want to close the gap between t0 and tm. - } - - convex_hull.m_tree_hull.addElement(t0, -1); - - if (tm < N) { - convex_hull.m_tree_hull.addBiggestElement(tm, -1); - - for (int tp = tm + 1; tp < mvg_impl.getPointCount(); tp++) {// Dynamically insert into the current convex hull - - stream.read(tp << 1, pt_p); - int p = convex_hull.treeHull_(pt_p); - - if (p != -1) - convex_hull.m_tree_hull.setElement(p, tp); // reset the place holder to the point index. - } - } - - // Extracts the convex hull from the tree. Reading the tree in order from first to last is the resulting convex hull. - - VertexDescription description = mvg_impl.getDescription(); - boolean b_has_attributes = (description.getAttributeCount() > 1); - int point_count = convex_hull.m_tree_hull.size(-1); - - Geometry hull; - - if (point_count >= 2) { - if (point_count >= 3) - hull = new Polygon(description); - else - hull = new Polyline(description); - - MultiPathImpl hull_impl = (MultiPathImpl) hull._getImpl(); - hull_impl.addPath((Point2D[]) null, 0, true); - - Point point = null; - if (b_has_attributes) - point = new Point(); - - for (int i = convex_hull.m_tree_hull.getFirst(-1); i != -1; i = convex_hull.m_tree_hull.getNext(i)) { - if (b_has_attributes) { - mvg_impl.getPointByVal(convex_hull.m_tree_hull.getElement(i), point); - hull_impl.insertPoint(0, -1, point); - } else { - stream.read(convex_hull.m_tree_hull.getElement(i) << 1, pt_p); - hull_impl.insertPoint(0, -1, pt_p); - } - } - } else { - assert (point_count == 1); - - if (b_has_attributes) { - Point point = new Point(description); - mvg_impl.getPointByVal(convex_hull.m_tree_hull.getElement(convex_hull.m_tree_hull.getFirst(-1)), point); - hull = point; - } else { - stream.read(convex_hull.m_tree_hull.getElement(convex_hull.m_tree_hull.getFirst(-1)) << 1, pt_p); - hull = new Point(pt_p); - } - } - - return hull; - } - - /** - * Static method to construct the convex hull from an array of points. The - * out_convex_hull array will be populated with the subset of index - * positions which contribute to the convex hull. - * Returns the number of points in the convex hull. - * \param points The points used to create the convex hull. - * \param count The number of points in the input Point2D array. - * \param out_convex_hull An index array allocated by the user at least as big as the size of the input points array. - */ - static int construct(Point2D[] points, int count, int[] out_convex_hull) { - ConvexHull convex_hull = new ConvexHull(points, count); + /* + * Constructor for a Convex_hull object. Used for dynamic insertion of geometries to create a convex hull. + */ + ConvexHull() { + m_tree_hull = new Treap(); + m_tree_hull.setCapacity(20); + m_shape = new EditShape(); + m_geometry_handle = m_shape.createGeometry(Geometry.Type.MultiPoint); + m_path_handle = m_shape.insertPath(m_geometry_handle, -1); + m_call_back = new CallBackShape(this); + } + + private ConvexHull(AttributeStreamOfDbl stream, int n) { + m_tree_hull = new Treap(); + m_tree_hull.setCapacity(Math.min(20, n)); + m_stream = stream; + m_call_back = new CallBackStream(this); + } + + private ConvexHull(Point2D[] points, int n) { + m_tree_hull = new Treap(); + m_tree_hull.setCapacity(Math.min(20, n)); + m_points = points; + m_call_back = new CallBackPoints(this); + } + + /** + * Adds a geometry to the current bounding geometry using an incremental algorithm for dynamic insertion. + * @param geometry The geometry to add to the bounding geometry. + */ + + void addGeometry(Geometry geometry) { + if (geometry.isEmpty()) + return; + + int type = geometry.getType().value(); + + if (MultiVertexGeometry.isMultiVertex(type)) + addMultiVertexGeometry_((MultiVertexGeometry) geometry); + else if (MultiPath.isSegment(type)) + addSegment_((Segment) geometry); + else if (type == Geometry.GeometryType.Envelope) + addEnvelope_((Envelope) geometry); + else if (type == Geometry.GeometryType.Point) + addPoint_((Point) geometry); + else + throw new IllegalArgumentException("invalid shape type"); + } + + /** + * Gets the current bounding geometry. + * Returns a Geometry. + */ + + Geometry getBoundingGeometry() { + // Extracts the convex hull from the tree. Reading the tree in order from first to last is the resulting convex hull. + Point point = new Point(); + int first = m_tree_hull.getFirst(-1); + Polygon hull = new Polygon(m_shape.getVertexDescription()); + if (m_tree_hull.size(-1) == 0) + return hull; + + m_shape.queryPoint(m_tree_hull.getElement(first), point); + hull.startPath(point); + + for (int i = m_tree_hull.getNext(first); i != -1; i = m_tree_hull.getNext(i)) { + m_shape.queryPoint(m_tree_hull.getElement(i), point); + hull.lineTo(point); + } + + return hull; + } + + /** + * Static method to construct the convex hull of a Multi_vertex_geometry. + * Returns a Geometry. + * \param mvg The geometry used to create the convex hull. + */ + + static Geometry construct(MultiVertexGeometry mvg) { + if (mvg.isEmpty()) + return new Polygon(mvg.getDescription()); + + MultiVertexGeometryImpl mvg_impl = (MultiVertexGeometryImpl) mvg._getImpl(); + int N = mvg_impl.getPointCount(); + + if (N <= 2) { + if (N == 1 || mvg_impl.getXY(0).equals(mvg_impl.getXY(1))) { + Point point = new Point(mvg_impl.getDescription()); + mvg_impl.getPointByVal(0, point); + return point; + } else { + Point pt = new Point(); + Polyline polyline = new Polyline(mvg_impl.getDescription()); + mvg_impl.getPointByVal(0, pt); + polyline.startPath(pt); + mvg_impl.getPointByVal(1, pt); + polyline.lineTo(pt); + return polyline; + } + } + + AttributeStreamOfDbl stream = (AttributeStreamOfDbl) mvg_impl.getAttributeStreamRef(VertexDescription.Semantics.POSITION); + ConvexHull convex_hull = new ConvexHull(stream, N); + + int t0 = 0, tm = 1; + Point2D pt_0 = new Point2D(); + Point2D pt_m = new Point2D(); + Point2D pt_p = new Point2D(); + + stream.read(t0 << 1, pt_0); + + while (true) { + if (tm >= N) + break; + + stream.read(tm << 1, pt_m); + if (!pt_m.isEqual(pt_0, NumberUtils.doubleEps())) + break; + + tm++; // We don't want to close the gap between t0 and tm. + } + + convex_hull.m_tree_hull.addElement(t0, -1); + + if (tm < N) { + convex_hull.m_tree_hull.addBiggestElement(tm, -1); + + for (int tp = tm + 1; tp < mvg_impl.getPointCount(); tp++) {// Dynamically insert into the current convex hull + + stream.read(tp << 1, pt_p); + int p = convex_hull.treeHull_(pt_p); + + if (p != -1) + convex_hull.m_tree_hull.setElement(p, tp); // reset the place holder to the point index. + } + } + + // Extracts the convex hull from the tree. Reading the tree in order from first to last is the resulting convex hull. + + VertexDescription description = mvg_impl.getDescription(); + boolean b_has_attributes = (description.getAttributeCount() > 1); + int point_count = convex_hull.m_tree_hull.size(-1); + + Geometry hull; + + if (point_count >= 2) { + if (point_count >= 3) + hull = new Polygon(description); + else + hull = new Polyline(description); + + MultiPathImpl hull_impl = (MultiPathImpl) hull._getImpl(); + hull_impl.addPath((Point2D[]) null, 0, true); + + Point point = null; + if (b_has_attributes) + point = new Point(); + + for (int i = convex_hull.m_tree_hull.getFirst(-1); i != -1; i = convex_hull.m_tree_hull.getNext(i)) { + if (b_has_attributes) { + mvg_impl.getPointByVal(convex_hull.m_tree_hull.getElement(i), point); + hull_impl.insertPoint(0, -1, point); + } else { + stream.read(convex_hull.m_tree_hull.getElement(i) << 1, pt_p); + hull_impl.insertPoint(0, -1, pt_p); + } + } + } else { + assert (point_count == 1); + + if (b_has_attributes) { + Point point = new Point(description); + mvg_impl.getPointByVal(convex_hull.m_tree_hull.getElement(convex_hull.m_tree_hull.getFirst(-1)), point); + hull = point; + } else { + stream.read(convex_hull.m_tree_hull.getElement(convex_hull.m_tree_hull.getFirst(-1)) << 1, pt_p); + hull = new Point(pt_p); + } + } + + return hull; + } + + /** + * Static method to construct the convex hull from an array of points. The + * out_convex_hull array will be populated with the subset of index + * positions which contribute to the convex hull. + * Returns the number of points in the convex hull. + * \param points The points used to create the convex hull. + * \param count The number of points in the input Point2D array. + * \param out_convex_hull An index array allocated by the user at least as big as the size of the input points array. + */ + static int construct(Point2D[] points, int count, int[] out_convex_hull) { + ConvexHull convex_hull = new ConvexHull(points, count); - int t0 = 0, tm = 1; - Point2D pt_0 = points[t0]; + int t0 = 0, tm = 1; + Point2D pt_0 = points[t0]; - while (tm < count && points[tm].isEqual(pt_0, NumberUtils.doubleEps())) - tm++; // We don't want to close the gap between t0 and tm. + while (tm < count && points[tm].isEqual(pt_0, NumberUtils.doubleEps())) + tm++; // We don't want to close the gap between t0 and tm. - convex_hull.m_tree_hull.addElement(t0, -1); + convex_hull.m_tree_hull.addElement(t0, -1); - if (tm < count) { - convex_hull.m_tree_hull.addBiggestElement(tm, -1); + if (tm < count) { + convex_hull.m_tree_hull.addBiggestElement(tm, -1); - for (int tp = tm + 1; tp < count; tp++) {// Dynamically insert into the current convex hull. + for (int tp = tm + 1; tp < count; tp++) {// Dynamically insert into the current convex hull. - Point2D pt_p = points[tp]; - int p = convex_hull.treeHull_(pt_p); + Point2D pt_p = points[tp]; + int p = convex_hull.treeHull_(pt_p); - if (p != -1) - convex_hull.m_tree_hull.setElement(p, tp); // reset the place holder to the point index. - } - } + if (p != -1) + convex_hull.m_tree_hull.setElement(p, tp); // reset the place holder to the point index. + } + } - // Extracts the convex hull from the tree. Reading the tree in order from first to last is the resulting convex hull. - int out_count = 0; - for (int i = convex_hull.m_tree_hull.getFirst(-1); i != -1; i = convex_hull.m_tree_hull.getNext(i)) - out_convex_hull[out_count++] = convex_hull.m_tree_hull.getElement(i); + // Extracts the convex hull from the tree. Reading the tree in order from first to last is the resulting convex hull. + int out_count = 0; + for (int i = convex_hull.m_tree_hull.getFirst(-1); i != -1; i = convex_hull.m_tree_hull.getNext(i)) + out_convex_hull[out_count++] = convex_hull.m_tree_hull.getElement(i); - return out_count; - } - - /** - * Returns true if the given path of the input MultiPath is convex. Returns false otherwise. - * \param multi_path The MultiPath to check if the path is convex. - * \param path_index The path of the MultiPath to check if its convex. - */ - static boolean isPathConvex(MultiPath multi_path, int path_index, ProgressTracker progress_tracker) { - MultiPathImpl mimpl = (MultiPathImpl) multi_path._getImpl(); - int path_start = mimpl.getPathStart(path_index); - int path_end = mimpl.getPathEnd(path_index); - - boolean bxyclosed = !mimpl.isClosedPath(path_index) && mimpl.isClosedPathInXYPlane(path_index); - - AttributeStreamOfDbl position = (AttributeStreamOfDbl) (mimpl.getAttributeStreamRef(VertexDescription.Semantics.POSITION)); - int position_start = 2 * path_start; - int position_end = 2 * path_end; - - if (bxyclosed) - position_end -= 2; - - if (position_end - position_start < 6) - return true; - - // This matches the logic for case 1 of the tree hull algorithm. The idea is inductive. We assume we have a convex hull pt_0,...,pt_m, and we see if - // a new point (pt_pivot) is among the transitive tournament for pt_0, knowing that pt_pivot comes after pt_m. - - // We check three conditions: - // 1) pt_m->pt_pivot->pt_0 is clockwise (closure across the boundary is convex) - // 2) pt_1->pt_pivot->pt_0 is clockwise (the first step forward is convex) (pt_1 is the next point after pt_0) - // 3) pt_m->pt_pivot->pt_m_prev is clockwise (the first step backwards is convex) (pt_m_prev is the previous point before pt_m) - - // If all three of the above conditions are clockwise, then pt_pivot is among the transitive tournament for pt_0, and therefore the polygon pt_0, ..., pt_m, pt_pivot is convex. - - Point2D pt_0 = new Point2D(), pt_m = new Point2D(), pt_pivot = new Point2D(); - position.read(position_start, pt_0); - position.read(position_start + 2, pt_m); - position.read(position_start + 4, pt_pivot); - - // Initial inductive step - ECoordinate det_ec = determinant_(pt_m, pt_pivot, pt_0); - - if (det_ec.isFuzzyZero() || !isClockwise_(det_ec.value())) - return false; - - Point2D pt_1 = new Point2D(pt_m.x, pt_m.y); - Point2D pt_m_prev = new Point2D(); - - // Assume that pt_0,...,pt_m is convex. Check if the next point, pt_pivot, maintains the convex invariant. - for (int i = position_start + 6; i < position_end; i += 2) { - pt_m_prev.setCoords(pt_m); - pt_m.setCoords(pt_pivot); - position.read(i, pt_pivot); - - det_ec = determinant_(pt_m, pt_pivot, pt_0); - - if (det_ec.isFuzzyZero() || !isClockwise_(det_ec.value())) - return false; - - det_ec = determinant_(pt_1, pt_pivot, pt_0); - - if (det_ec.isFuzzyZero() || !isClockwise_(det_ec.value())) - return false; - - det_ec = determinant_(pt_m, pt_pivot, pt_m_prev); + return out_count; + } + + /** + * Returns true if the given path of the input MultiPath is convex. Returns false otherwise. + * \param multi_path The MultiPath to check if the path is convex. + * \param path_index The path of the MultiPath to check if its convex. + */ + static boolean isPathConvex(MultiPath multi_path, int path_index, ProgressTracker progress_tracker) { + MultiPathImpl mimpl = (MultiPathImpl) multi_path._getImpl(); + int path_start = mimpl.getPathStart(path_index); + int path_end = mimpl.getPathEnd(path_index); + + boolean bxyclosed = !mimpl.isClosedPath(path_index) && mimpl.isClosedPathInXYPlane(path_index); + + AttributeStreamOfDbl position = (AttributeStreamOfDbl) (mimpl.getAttributeStreamRef(VertexDescription.Semantics.POSITION)); + int position_start = 2 * path_start; + int position_end = 2 * path_end; + + if (bxyclosed) + position_end -= 2; + + if (position_end - position_start < 6) + return true; + + // This matches the logic for case 1 of the tree hull algorithm. The idea is inductive. We assume we have a convex hull pt_0,...,pt_m, and we see if + // a new point (pt_pivot) is among the transitive tournament for pt_0, knowing that pt_pivot comes after pt_m. + + // We check three conditions: + // 1) pt_m->pt_pivot->pt_0 is clockwise (closure across the boundary is convex) + // 2) pt_1->pt_pivot->pt_0 is clockwise (the first step forward is convex) (pt_1 is the next point after pt_0) + // 3) pt_m->pt_pivot->pt_m_prev is clockwise (the first step backwards is convex) (pt_m_prev is the previous point before pt_m) + + // If all three of the above conditions are clockwise, then pt_pivot is among the transitive tournament for pt_0, and therefore the polygon pt_0, ..., pt_m, pt_pivot is convex. + + Point2D pt_0 = new Point2D(), pt_m = new Point2D(), pt_pivot = new Point2D(); + position.read(position_start, pt_0); + position.read(position_start + 2, pt_m); + position.read(position_start + 4, pt_pivot); + + // Initial inductive step + ECoordinate det_ec = determinant_(pt_m, pt_pivot, pt_0); + + if (det_ec.isFuzzyZero() || !isClockwise_(det_ec.value())) + return false; + + Point2D pt_1 = new Point2D(pt_m.x, pt_m.y); + Point2D pt_m_prev = new Point2D(); + + // Assume that pt_0,...,pt_m is convex. Check if the next point, pt_pivot, maintains the convex invariant. + for (int i = position_start + 6; i < position_end; i += 2) { + pt_m_prev.setCoords(pt_m); + pt_m.setCoords(pt_pivot); + position.read(i, pt_pivot); + + det_ec = determinant_(pt_m, pt_pivot, pt_0); + + if (det_ec.isFuzzyZero() || !isClockwise_(det_ec.value())) + return false; + + det_ec = determinant_(pt_1, pt_pivot, pt_0); + + if (det_ec.isFuzzyZero() || !isClockwise_(det_ec.value())) + return false; + + det_ec = determinant_(pt_m, pt_pivot, pt_m_prev); - if (det_ec.isFuzzyZero() || !isClockwise_(det_ec.value())) - return false; - } + if (det_ec.isFuzzyZero() || !isClockwise_(det_ec.value())) + return false; + } - return true; - } + return true; + } - // Dynamically inserts each geometry into the convex hull. - private void addMultiVertexGeometry_(MultiVertexGeometry mvg) { - Point point = new Point(); - Point2D pt_p = new Point2D(); + // Dynamically inserts each geometry into the convex hull. + private void addMultiVertexGeometry_(MultiVertexGeometry mvg) { + Point point = new Point(); + Point2D pt_p = new Point2D(); - for (int i = 0; i < mvg.getPointCount(); i++) { - mvg.getXY(i, pt_p); - int p = addPoint_(pt_p); + for (int i = 0; i < mvg.getPointCount(); i++) { + mvg.getXY(i, pt_p); + int p = addPoint_(pt_p); - if (p != -1) { - mvg.getPointByVal(i, point); - int tp = m_shape.addPoint(m_path_handle, point); - m_tree_hull.setElement(p, tp); // reset the place holder to tp - } - } - } + if (p != -1) { + mvg.getPointByVal(i, point); + int tp = m_shape.addPoint(m_path_handle, point); + m_tree_hull.setElement(p, tp); // reset the place holder to tp + } + } + } - private void addEnvelope_(Envelope envelope) { - Point point = new Point(); - Point2D pt_p = new Point2D(); + private void addEnvelope_(Envelope envelope) { + Point point = new Point(); + Point2D pt_p = new Point2D(); - for (int i = 0; i < 4; i++) { - envelope.queryCorner(i, pt_p); - int p = addPoint_(pt_p); + for (int i = 0; i < 4; i++) { + envelope.queryCorner(i, pt_p); + int p = addPoint_(pt_p); - if (p != -1) { - envelope.queryCornerByVal(i, point); - int tp = m_shape.addPoint(m_path_handle, point); - m_tree_hull.setElement(p, tp); // reset the place holder to tp - } - } - } + if (p != -1) { + envelope.queryCornerByVal(i, point); + int tp = m_shape.addPoint(m_path_handle, point); + m_tree_hull.setElement(p, tp); // reset the place holder to tp + } + } + } - private void addSegment_(Segment segment) { - Point point = new Point(); + private void addSegment_(Segment segment) { + Point point = new Point(); - Point2D pt_start = segment.getStartXY(); - int p_start = addPoint_(pt_start); + Point2D pt_start = segment.getStartXY(); + int p_start = addPoint_(pt_start); - if (p_start != -1) { - segment.queryStart(point); - int t_start = m_shape.addPoint(m_path_handle, point); - m_tree_hull.setElement(p_start, t_start); // reset the place holder - // to tp - } - - Point2D pt_end = segment.getEndXY(); - int p_end = addPoint_(pt_end); - - if (p_end != -1) { - segment.queryEnd(point); - int t_end = m_shape.addPoint(m_path_handle, point); - m_tree_hull.setElement(p_end, t_end); // reset the place holder to - // tp - } - } - - private void addPoint_(Point point) { - Point2D pt_p = point.getXY(); - int p = addPoint_(pt_p); - - if (p != -1) { - int tp = m_shape.addPoint(m_path_handle, point); - m_tree_hull.setElement(p, tp); // reset the place holder to tp - } - } - - private int addPoint_(Point2D pt_p) { - int p = -1; - - if (m_tree_hull.size(-1) == 0) { - p = m_tree_hull.addElement(-4, -1); // reset the place holder to tp - return p; - } - - if (m_tree_hull.size(-1) == 1) { - int t0 = m_tree_hull.getElement(m_tree_hull.getFirst(-1)); - Point2D pt_0 = m_shape.getXY(t0); - - if (!pt_p.isEqual(pt_0, NumberUtils.doubleEps())) // We don't want to close the gap between t0 and tm. - p = m_tree_hull.addBiggestElement(-5, -1); // set place holder to -5 to indicate the second element being added (tm). - - return p; - } - - p = treeHull_(pt_p); - return p; - } - - // Algorithm taken from "Axioms and Hulls" by D.E. Knuth, Lecture Notes in Computer Science 606, page 47. - private int treeHull_(Point2D pt_pivot) { - assert (m_tree_hull.size(-1) >= 2); - - int p = -1; - - do { - int first = m_tree_hull.getFirst(-1); - int last = m_tree_hull.getLast(-1); - int t0 = m_tree_hull.getElement(first); - int tm = m_tree_hull.getElement(last); - - Point2D pt_0 = new Point2D(); // should the memory be cached? - Point2D pt_m = new Point2D(); // should the memory be cached? - m_call_back.getXY(t0, pt_0); - m_call_back.getXY(tm, pt_m); - - assert (!pt_0.isEqual(pt_m, NumberUtils.doubleEps())); // assert that the gap is not closed - - int orient_m_p_0 = Point2D.orientationRobust(pt_m, pt_pivot, pt_0); // determines case 1, 2, 3 - - if (isClockwise_(orient_m_p_0)) {// Case 1: tp->t0->tm is clockwise - - p = m_tree_hull.addBiggestElement(-1, -1); // set place holder to -1 for case 1. - int l = treeHullWalkBackward_(pt_pivot, last, first); - - if (l != first) - treeHullWalkForward_(pt_pivot, first, m_tree_hull.getPrev(l)); - - continue; - } - - if (isCounterClockwise_(orient_m_p_0)) {// Case 2: tp->tm->t0 is clockwise - int k = m_tree_hull.getRoot(-1), k_min = m_tree_hull.getFirst(-1), k_max = m_tree_hull.getLast(-1), k_prev; - int tk, tk_prev; - Point2D pt_k = new Point2D(); - Point2D pt_k_prev = new Point2D(); - - while (k_min != m_tree_hull.getPrev(k_max)) {// binary search to find k such that t0->tp->tj holds (i.e. clockwise) for j >= k. Hence, tj->tp->t0 is clockwise (or degenerate) for j < k. - tk = m_tree_hull.getElement(k); - m_call_back.getXY(tk, pt_k); - int orient_k_p_0 = Point2D.orientationRobust(pt_k, pt_pivot, pt_0); - - if (isCounterClockwise_(orient_k_p_0)) { - k_max = k; - k = m_tree_hull.getLeft(k); - } else { - k_min = k; - k = m_tree_hull.getRight(k); - } - } - - k = k_max; - k_prev = k_min; - tk = m_tree_hull.getElement(k); - tk_prev = m_tree_hull.getElement(k_prev); - m_call_back.getXY(tk, pt_k); - m_call_back.getXY(tk_prev, pt_k_prev); - assert (isCounterClockwise_(Point2D.orientationRobust(pt_k, pt_pivot, pt_0)) && !isCounterClockwise_(Point2D.orientationRobust(pt_k_prev, pt_pivot, pt_0))); - assert (k_prev != first || isCounterClockwise_(Point2D.orientationRobust(pt_k, pt_pivot, pt_0))); - - if (k_prev != first) { - int orient_k_prev_p_k = Point2D.orientationRobust(pt_k_prev, pt_pivot, pt_k); + if (p_start != -1) { + segment.queryStart(point); + int t_start = m_shape.addPoint(m_path_handle, point); + m_tree_hull.setElement(p_start, t_start); // reset the place holder + // to tp + } + + Point2D pt_end = segment.getEndXY(); + int p_end = addPoint_(pt_end); + + if (p_end != -1) { + segment.queryEnd(point); + int t_end = m_shape.addPoint(m_path_handle, point); + m_tree_hull.setElement(p_end, t_end); // reset the place holder to + // tp + } + } + + private void addPoint_(Point point) { + Point2D pt_p = point.getXY(); + int p = addPoint_(pt_p); + + if (p != -1) { + int tp = m_shape.addPoint(m_path_handle, point); + m_tree_hull.setElement(p, tp); // reset the place holder to tp + } + } + + private int addPoint_(Point2D pt_p) { + int p = -1; + + if (m_tree_hull.size(-1) == 0) { + p = m_tree_hull.addElement(-4, -1); // reset the place holder to tp + return p; + } + + if (m_tree_hull.size(-1) == 1) { + int t0 = m_tree_hull.getElement(m_tree_hull.getFirst(-1)); + Point2D pt_0 = m_shape.getXY(t0); + + if (!pt_p.isEqual(pt_0, NumberUtils.doubleEps())) // We don't want to close the gap between t0 and tm. + p = m_tree_hull.addBiggestElement(-5, -1); // set place holder to -5 to indicate the second element being added (tm). + + return p; + } + + p = treeHull_(pt_p); + return p; + } + + // Algorithm taken from "Axioms and Hulls" by D.E. Knuth, Lecture Notes in Computer Science 606, page 47. + private int treeHull_(Point2D pt_pivot) { + assert (m_tree_hull.size(-1) >= 2); + + int p = -1; + + do { + int first = m_tree_hull.getFirst(-1); + int last = m_tree_hull.getLast(-1); + int t0 = m_tree_hull.getElement(first); + int tm = m_tree_hull.getElement(last); + + Point2D pt_0 = new Point2D(); // should the memory be cached? + Point2D pt_m = new Point2D(); // should the memory be cached? + m_call_back.getXY(t0, pt_0); + m_call_back.getXY(tm, pt_m); + + assert (!pt_0.isEqual(pt_m, NumberUtils.doubleEps())); // assert that the gap is not closed + + int orient_m_p_0 = Point2D.orientationRobust(pt_m, pt_pivot, pt_0); // determines case 1, 2, 3 + + if (isClockwise_(orient_m_p_0)) {// Case 1: tp->t0->tm is clockwise + + p = m_tree_hull.addBiggestElement(-1, -1); // set place holder to -1 for case 1. + int l = treeHullWalkBackward_(pt_pivot, last, first); + + if (l != first) + treeHullWalkForward_(pt_pivot, first, m_tree_hull.getPrev(l)); + + continue; + } + + if (isCounterClockwise_(orient_m_p_0)) {// Case 2: tp->tm->t0 is clockwise + int k = m_tree_hull.getRoot(-1), k_min = m_tree_hull.getFirst(-1), k_max = m_tree_hull.getLast(-1), k_prev; + int tk, tk_prev; + Point2D pt_k = new Point2D(); + Point2D pt_k_prev = new Point2D(); + + while (k_min != m_tree_hull.getPrev(k_max)) {// binary search to find k such that t0->tp->tj holds (i.e. clockwise) for j >= k. Hence, tj->tp->t0 is clockwise (or degenerate) for j < k. + tk = m_tree_hull.getElement(k); + m_call_back.getXY(tk, pt_k); + int orient_k_p_0 = Point2D.orientationRobust(pt_k, pt_pivot, pt_0); + + if (isCounterClockwise_(orient_k_p_0)) { + k_max = k; + k = m_tree_hull.getLeft(k); + } else { + k_min = k; + k = m_tree_hull.getRight(k); + } + } + + k = k_max; + k_prev = k_min; + tk = m_tree_hull.getElement(k); + tk_prev = m_tree_hull.getElement(k_prev); + m_call_back.getXY(tk, pt_k); + m_call_back.getXY(tk_prev, pt_k_prev); + assert (isCounterClockwise_(Point2D.orientationRobust(pt_k, pt_pivot, pt_0)) && !isCounterClockwise_(Point2D.orientationRobust(pt_k_prev, pt_pivot, pt_0))); + assert (k_prev != first || isCounterClockwise_(Point2D.orientationRobust(pt_k, pt_pivot, pt_0))); + + if (k_prev != first) { + int orient_k_prev_p_k = Point2D.orientationRobust(pt_k_prev, pt_pivot, pt_k); - if (!isClockwise_(orient_k_prev_p_k)) - continue; // pt_pivot is inside the hull (or on the boundary) - } + if (!isClockwise_(orient_k_prev_p_k)) + continue; // pt_pivot is inside the hull (or on the boundary) + } - p = m_tree_hull.addElementAtPosition(k_prev, k, -2, true, false, -1); // set place holder to -2 for case 2. - treeHullWalkForward_(pt_pivot, k, last); - treeHullWalkBackward_(pt_pivot, k_prev, first); + p = m_tree_hull.addElementAtPosition(k_prev, k, -2, true, false, -1); // set place holder to -2 for case 2. + treeHullWalkForward_(pt_pivot, k, last); + treeHullWalkBackward_(pt_pivot, k_prev, first); - continue; - } + continue; + } - assert (isDegenerate_(orient_m_p_0)); - {// Case 3: degenerate - int between = isBetween_(pt_pivot, pt_m, pt_0); + assert (isDegenerate_(orient_m_p_0)); + {// Case 3: degenerate + int between = isBetween_(pt_pivot, pt_m, pt_0); - if (between == -1) { - int l = m_tree_hull.getPrev(last); - m_tree_hull.deleteNode(last, -1); - p = m_tree_hull.addBiggestElement(-3, -1); // set place holder to -3 for case 3. - treeHullWalkBackward_(pt_pivot, l, first); - } else if (between == 1) { - int j = m_tree_hull.getNext(first); - m_tree_hull.deleteNode(first, -1); - p = m_tree_hull.addElementAtPosition(-1, j, -3, true, false, -1); // set place holder to -3 for case 3. - treeHullWalkForward_(pt_pivot, j, last); - } + if (between == -1) { + int l = m_tree_hull.getPrev(last); + m_tree_hull.deleteNode(last, -1); + p = m_tree_hull.addBiggestElement(-3, -1); // set place holder to -3 for case 3. + treeHullWalkBackward_(pt_pivot, l, first); + } else if (between == 1) { + int j = m_tree_hull.getNext(first); + m_tree_hull.deleteNode(first, -1); + p = m_tree_hull.addElementAtPosition(-1, j, -3, true, false, -1); // set place holder to -3 for case 3. + treeHullWalkForward_(pt_pivot, j, last); + } - continue; - } - - } while (false); + continue; + } + + } while (false); - return p; - } + return p; + } - private int treeHullWalkForward_(Point2D pt_pivot, int start, int end) { - if (start == end) - return end; + private int treeHullWalkForward_(Point2D pt_pivot, int start, int end) { + if (start == end) + return end; - int j = start; - int tj = m_tree_hull.getElement(j); - int j_next = m_tree_hull.getNext(j); - Point2D pt_j = new Point2D(); - Point2D pt_j_next = new Point2D(); - - m_call_back.getXY(tj, pt_j); + int j = start; + int tj = m_tree_hull.getElement(j); + int j_next = m_tree_hull.getNext(j); + Point2D pt_j = new Point2D(); + Point2D pt_j_next = new Point2D(); + + m_call_back.getXY(tj, pt_j); - while (j != end && m_tree_hull.size(-1) > 2) {//Stops when we find a clockwise triple containting the pivot point, or when the tree_hull size is 2. Deletes non-clockwise triples along the way. - int tj_next = m_tree_hull.getElement(j_next); - m_call_back.getXY(tj_next, pt_j_next); + while (j != end && m_tree_hull.size(-1) > 2) {//Stops when we find a clockwise triple containting the pivot point, or when the tree_hull size is 2. Deletes non-clockwise triples along the way. + int tj_next = m_tree_hull.getElement(j_next); + m_call_back.getXY(tj_next, pt_j_next); - int orient_j_next_p_j = Point2D.orientationRobust(pt_j_next, pt_pivot, pt_j); + int orient_j_next_p_j = Point2D.orientationRobust(pt_j_next, pt_pivot, pt_j); - if (isClockwise_(orient_j_next_p_j)) - break; - - int ccw = j; - - j = j_next; - pt_j.setCoords(pt_j_next); - j_next = m_tree_hull.getNext(j); - m_call_back.deleteNode(ccw); - } - - return j; - } - - private int treeHullWalkBackward_(Point2D pt_pivot, int start, int end) { - if (start == end) - return end; - - int l = start; - int tl = m_tree_hull.getElement(l); - int l_prev = m_tree_hull.getPrev(l); - Point2D pt_l = new Point2D(); - Point2D pt_l_prev = new Point2D(); - - m_call_back.getXY(tl, pt_l); - - while (l != end && m_tree_hull.size(-1) > 2) {//Stops when we find a clockwise triple containting the pivot point, or when the tree_hull size is 2. Deletes non-clockwise triples along the way. - int tl_prev = m_tree_hull.getElement(l_prev); - m_call_back.getXY(tl_prev, pt_l_prev); - - int orient_l_p_l_prev = Point2D.orientationRobust(pt_l, pt_pivot, pt_l_prev); - - if (isClockwise_(orient_l_p_l_prev)) - break; - - int ccw = l; - - l = l_prev; - pt_l.setCoords(pt_l_prev); - l_prev = m_tree_hull.getPrev(l); - m_call_back.deleteNode(ccw); - } - - return l; - } - - // Orientation predicates - private static ECoordinate determinant_(Point2D p, Point2D q, Point2D r) { - ECoordinate det_ec = new ECoordinate(); - det_ec.set(q.x); - det_ec.sub(p.x); - - ECoordinate rp_y_ec = new ECoordinate(); - rp_y_ec.set(r.y); - rp_y_ec.sub(p.y); - - ECoordinate qp_y_ec = new ECoordinate(); - qp_y_ec.set(q.y); - qp_y_ec.sub(p.y); - - ECoordinate rp_x_ec = new ECoordinate(); - rp_x_ec.set(r.x); - rp_x_ec.sub(p.x); - - det_ec.mul(rp_y_ec); - qp_y_ec.mul(rp_x_ec); - det_ec.sub(qp_y_ec); - return det_ec; - } - - private static boolean isClockwise_(double det) { - return det < 0.0; - } - - private static boolean isCounterClockwise_(double det) { - return det > 0.0; - } - - private static boolean isDegenerate_(double det) { - return det == 0.0; - } - - private static boolean isClockwise_(int orientation) { - return orientation < 0.0; - } - - private static boolean isCounterClockwise_(int orientation) { - return orientation > 0.0; - } - - private static boolean isDegenerate_(int orientation) { - return orientation == 0.0; - } - - private static int isBetween_(Point2D pt_pivot, Point2D pt_m, Point2D pt_0) { - int ordinate = -1; - - if (pt_m.y == pt_0.y) { - ordinate = 0; - } else if (pt_m.x == pt_0.x) { - ordinate = 1; - } else {// use bigger ordinate, but shouldn't matter - - double diff_x = Math.abs(pt_m.x - pt_0.x); - double diff_y = Math.abs(pt_m.y - pt_0.y); - - if (diff_x >= diff_y) - ordinate = 0; - else - ordinate = 1; - } - - int res = -1; - - if (ordinate == 0) { - assert (pt_m.x != pt_0.x); - - if (pt_m.x < pt_0.x) { - if (pt_pivot.x < pt_m.x) - res = -1; - else if (pt_0.x < pt_pivot.x) - res = 1; - else - res = 0; - } else { - assert (pt_0.x < pt_m.x); - - if (pt_m.x < pt_pivot.x) - res = -1; - else if (pt_pivot.x < pt_0.x) - res = 1; - else - res = 0; - } - } else { - assert (pt_m.y != pt_0.y); - - if (pt_m.y < pt_0.y) { - if (pt_pivot.y < pt_m.y) - res = -1; - else if (pt_0.y < pt_pivot.y) - res = 1; - else - res = 0; - } else { - assert (pt_0.y < pt_m.y); - - if (pt_m.y < pt_pivot.y) - res = -1; - else if (pt_pivot.y < pt_0.y) - res = 1; - else - res = 0; - } - } - - return res; - } - - private static abstract class CallBack { - abstract void getXY(int ti, Point2D pt); - - abstract void deleteNode(int i); - } - - private static final class CallBackShape extends CallBack { - private ConvexHull m_convex_hull; - - CallBackShape(ConvexHull convex_hull) { - m_convex_hull = convex_hull; - } - - @Override - void getXY(int ti, Point2D pt) { - m_convex_hull.m_shape.getXY(ti, pt); - } - - @Override - void deleteNode(int i) { - int ti = m_convex_hull.m_tree_hull.getElement(i); - m_convex_hull.m_tree_hull.deleteNode(i, -1); - m_convex_hull.m_shape.removeVertex(ti, false); - } - } - - private static final class CallBackStream extends CallBack { - private ConvexHull m_convex_hull; - - CallBackStream(ConvexHull convex_hull) { - m_convex_hull = convex_hull; - } - - @Override - void getXY(int ti, Point2D pt) { - m_convex_hull.m_stream.read(ti << 1, pt); - } - - @Override - void deleteNode(int i) { - m_convex_hull.m_tree_hull.deleteNode(i, -1); - } - } - - private static final class CallBackPoints extends CallBack { - private ConvexHull m_convex_hull; - - CallBackPoints(ConvexHull convex_hull) { - m_convex_hull = convex_hull; - } - - @Override - void getXY(int ti, Point2D pt) { - pt.setCoords(m_convex_hull.m_points[ti]); - } - - @Override - void deleteNode(int i) { - m_convex_hull.m_tree_hull.deleteNode(i, -1); - } - } - - // Members - private Treap m_tree_hull; - private EditShape m_shape; - private AttributeStreamOfDbl m_stream; - private Point2D[] m_points; - private int m_geometry_handle; - private int m_path_handle; - private Line m_line; - private CallBack m_call_back; + if (isClockwise_(orient_j_next_p_j)) + break; + + int ccw = j; + + j = j_next; + pt_j.setCoords(pt_j_next); + j_next = m_tree_hull.getNext(j); + m_call_back.deleteNode(ccw); + } + + return j; + } + + private int treeHullWalkBackward_(Point2D pt_pivot, int start, int end) { + if (start == end) + return end; + + int l = start; + int tl = m_tree_hull.getElement(l); + int l_prev = m_tree_hull.getPrev(l); + Point2D pt_l = new Point2D(); + Point2D pt_l_prev = new Point2D(); + + m_call_back.getXY(tl, pt_l); + + while (l != end && m_tree_hull.size(-1) > 2) {//Stops when we find a clockwise triple containting the pivot point, or when the tree_hull size is 2. Deletes non-clockwise triples along the way. + int tl_prev = m_tree_hull.getElement(l_prev); + m_call_back.getXY(tl_prev, pt_l_prev); + + int orient_l_p_l_prev = Point2D.orientationRobust(pt_l, pt_pivot, pt_l_prev); + + if (isClockwise_(orient_l_p_l_prev)) + break; + + int ccw = l; + + l = l_prev; + pt_l.setCoords(pt_l_prev); + l_prev = m_tree_hull.getPrev(l); + m_call_back.deleteNode(ccw); + } + + return l; + } + + // Orientation predicates + private static ECoordinate determinant_(Point2D p, Point2D q, Point2D r) { + ECoordinate det_ec = new ECoordinate(); + det_ec.set(q.x); + det_ec.sub(p.x); + + ECoordinate rp_y_ec = new ECoordinate(); + rp_y_ec.set(r.y); + rp_y_ec.sub(p.y); + + ECoordinate qp_y_ec = new ECoordinate(); + qp_y_ec.set(q.y); + qp_y_ec.sub(p.y); + + ECoordinate rp_x_ec = new ECoordinate(); + rp_x_ec.set(r.x); + rp_x_ec.sub(p.x); + + det_ec.mul(rp_y_ec); + qp_y_ec.mul(rp_x_ec); + det_ec.sub(qp_y_ec); + return det_ec; + } + + private static boolean isClockwise_(double det) { + return det < 0.0; + } + + private static boolean isCounterClockwise_(double det) { + return det > 0.0; + } + + private static boolean isDegenerate_(double det) { + return det == 0.0; + } + + private static boolean isClockwise_(int orientation) { + return orientation < 0.0; + } + + private static boolean isCounterClockwise_(int orientation) { + return orientation > 0.0; + } + + private static boolean isDegenerate_(int orientation) { + return orientation == 0.0; + } + + private static int isBetween_(Point2D pt_pivot, Point2D pt_m, Point2D pt_0) { + int ordinate = -1; + + if (pt_m.y == pt_0.y) { + ordinate = 0; + } else if (pt_m.x == pt_0.x) { + ordinate = 1; + } else {// use bigger ordinate, but shouldn't matter + + double diff_x = Math.abs(pt_m.x - pt_0.x); + double diff_y = Math.abs(pt_m.y - pt_0.y); + + if (diff_x >= diff_y) + ordinate = 0; + else + ordinate = 1; + } + + int res = -1; + + if (ordinate == 0) { + assert (pt_m.x != pt_0.x); + + if (pt_m.x < pt_0.x) { + if (pt_pivot.x < pt_m.x) + res = -1; + else if (pt_0.x < pt_pivot.x) + res = 1; + else + res = 0; + } else { + assert (pt_0.x < pt_m.x); + + if (pt_m.x < pt_pivot.x) + res = -1; + else if (pt_pivot.x < pt_0.x) + res = 1; + else + res = 0; + } + } else { + assert (pt_m.y != pt_0.y); + + if (pt_m.y < pt_0.y) { + if (pt_pivot.y < pt_m.y) + res = -1; + else if (pt_0.y < pt_pivot.y) + res = 1; + else + res = 0; + } else { + assert (pt_0.y < pt_m.y); + + if (pt_m.y < pt_pivot.y) + res = -1; + else if (pt_pivot.y < pt_0.y) + res = 1; + else + res = 0; + } + } + + return res; + } + + private static abstract class CallBack { + abstract void getXY(int ti, Point2D pt); + + abstract void deleteNode(int i); + } + + private static final class CallBackShape extends CallBack { + private ConvexHull m_convex_hull; + + CallBackShape(ConvexHull convex_hull) { + m_convex_hull = convex_hull; + } + + @Override + void getXY(int ti, Point2D pt) { + m_convex_hull.m_shape.getXY(ti, pt); + } + + @Override + void deleteNode(int i) { + int ti = m_convex_hull.m_tree_hull.getElement(i); + m_convex_hull.m_tree_hull.deleteNode(i, -1); + m_convex_hull.m_shape.removeVertex(ti, false); + } + } + + private static final class CallBackStream extends CallBack { + private ConvexHull m_convex_hull; + + CallBackStream(ConvexHull convex_hull) { + m_convex_hull = convex_hull; + } + + @Override + void getXY(int ti, Point2D pt) { + m_convex_hull.m_stream.read(ti << 1, pt); + } + + @Override + void deleteNode(int i) { + m_convex_hull.m_tree_hull.deleteNode(i, -1); + } + } + + private static final class CallBackPoints extends CallBack { + private ConvexHull m_convex_hull; + + CallBackPoints(ConvexHull convex_hull) { + m_convex_hull = convex_hull; + } + + @Override + void getXY(int ti, Point2D pt) { + pt.setCoords(m_convex_hull.m_points[ti]); + } + + @Override + void deleteNode(int i) { + m_convex_hull.m_tree_hull.deleteNode(i, -1); + } + } + + // Members + private Treap m_tree_hull; + private EditShape m_shape; + private AttributeStreamOfDbl m_stream; + private Point2D[] m_points; + private int m_geometry_handle; + private int m_path_handle; + private Line m_line; + private CallBack m_call_back; } diff --git a/src/main/java/com/esri/core/geometry/CrackAndCluster.java b/src/main/java/com/esri/core/geometry/CrackAndCluster.java index 68b920a9..f2bf559a 100644 --- a/src/main/java/com/esri/core/geometry/CrackAndCluster.java +++ b/src/main/java/com/esri/core/geometry/CrackAndCluster.java @@ -27,134 +27,134 @@ //Cracks and clusters all segments and vertices in the EditShape. final class CrackAndCluster { - private EditShape m_shape = null; - private ProgressTracker m_progressTracker = null; - private double m_tolerance; - private boolean m_filter_degenerate_segments = true; - - private CrackAndCluster(ProgressTracker progressTracker) { - m_progressTracker = progressTracker; - } - - static boolean non_empty_points_need_to_cluster(double tolerance, Point pt1, Point pt2) { - double tolerance_for_clustering = InternalUtils.adjust_tolerance_for_TE_clustering(tolerance); - return Clusterer.isClusterCandidate_(pt1.getX(), pt1.getY(), pt2.getX(), pt2.getY(), MathUtils.sqr(tolerance_for_clustering)); - } - - static Point cluster_non_empty_points(Point pt1, Point pt2, double w1, int rank1, double w2, int rank2) { - if (rank1 > rank2) { - return pt1; - } else if (rank2 < rank1) { - return pt2; - } - - int[] rank = null; - double[] w = null; - Point pt = new Point(); - Clusterer.mergeVertices(pt1, pt2, w1, rank1, w2, rank2, pt, w, rank); - return pt; - } - - public static boolean execute(EditShape shape, double tolerance, - ProgressTracker progressTracker, boolean filter_degenerate_segments) { - CrackAndCluster cracker = new CrackAndCluster(progressTracker); - cracker.m_shape = shape; - cracker.m_tolerance = tolerance; - cracker.m_filter_degenerate_segments = filter_degenerate_segments; - return cracker._do(); - } - - private boolean _cluster(double toleranceCluster) { - boolean res = Clusterer.executeNonReciprocal(m_shape, toleranceCluster); - return res; - } - - private boolean _crack(double tolerance_for_cracking) { - boolean res = Cracker.execute(m_shape, tolerance_for_cracking, m_progressTracker); - return res; - } - - private boolean _do() { - double tol = m_tolerance; - - // Use same tolerances as ArcObjects (2 * sqrt(2) * tolerance for - // clustering) - // sqrt(2) * tolerance for cracking. - // Also, inflate the tolerances slightly to insure the simplified result - // would not change after small rounding issues. - - final double c_factor = 1e-5; - final double c_factor_for_needs_cracking = 1e-6; - double tolerance_for_clustering = InternalUtils - .adjust_tolerance_for_TE_clustering(tol); - double tolerance_for_needs_cracking = InternalUtils - .adjust_tolerance_for_TE_cracking(tol); - double tolerance_for_cracking = tolerance_for_needs_cracking - * (1.0 + c_factor); - tolerance_for_needs_cracking *= (1.0 + c_factor_for_needs_cracking); - - // Require tolerance_for_clustering > tolerance_for_cracking > - // tolerance_for_needs_cracking - assert (tolerance_for_clustering > tolerance_for_cracking); - assert (tolerance_for_cracking > tolerance_for_needs_cracking); - - // double toleranceCluster = m_tolerance * Math.sqrt(2.0) * 1.00001; - boolean bChanged = false; - int max_iter = m_shape.getTotalPointCount() + 10 > 30 ? 1000 : (m_shape - .getTotalPointCount() + 10) - * (m_shape.getTotalPointCount() + 10); - int iter = 0; - boolean has_point_features = m_shape.hasPointFeatures(); - for (; ; iter++) { - if (iter > max_iter) - throw new GeometryException( - "Internal Error: max number of iterations exceeded");// too - // many - // iterations - - boolean bClustered = _cluster(tolerance_for_clustering); // find - // close - // vertices and - // clamp them - // together. - bChanged |= bClustered; - - if (m_filter_degenerate_segments) { - boolean bFiltered = (m_shape.filterClosePoints( - tolerance_for_clustering, true, false) != 0); // remove all - // degenerate - // segments. - bChanged |= bFiltered; - } - - boolean b_cracked = false; - if (iter == 0 - || has_point_features - || Cracker.needsCracking(true, m_shape, - tolerance_for_needs_cracking, null, - m_progressTracker)) { - // Cracks only if shape contains segments. - b_cracked = _crack(tolerance_for_cracking); // crack all - // segments at - // intersection - // points and touch - // points. If - // Cracked, then the - // iteration will be - // repeated. - bChanged |= b_cracked; - } - - if (!b_cracked) - break;// was not cracked, so we can bail out. - else { - // Loop while cracking happens. - } - - ProgressTracker.checkAndThrow(m_progressTracker); - } - - return bChanged; - } + private EditShape m_shape = null; + private ProgressTracker m_progressTracker = null; + private double m_tolerance; + private boolean m_filter_degenerate_segments = true; + + private CrackAndCluster(ProgressTracker progressTracker) { + m_progressTracker = progressTracker; + } + + static boolean non_empty_points_need_to_cluster(double tolerance, Point pt1, Point pt2) { + double tolerance_for_clustering = InternalUtils.adjust_tolerance_for_TE_clustering(tolerance); + return Clusterer.isClusterCandidate_(pt1.getX(), pt1.getY(), pt2.getX(), pt2.getY(), MathUtils.sqr(tolerance_for_clustering)); + } + + static Point cluster_non_empty_points(Point pt1, Point pt2, double w1, int rank1, double w2, int rank2) { + if (rank1 > rank2) { + return pt1; + } else if (rank2 < rank1) { + return pt2; + } + + int[] rank = null; + double[] w = null; + Point pt = new Point(); + Clusterer.mergeVertices(pt1, pt2, w1, rank1, w2, rank2, pt, w, rank); + return pt; + } + + public static boolean execute(EditShape shape, double tolerance, + ProgressTracker progressTracker, boolean filter_degenerate_segments) { + CrackAndCluster cracker = new CrackAndCluster(progressTracker); + cracker.m_shape = shape; + cracker.m_tolerance = tolerance; + cracker.m_filter_degenerate_segments = filter_degenerate_segments; + return cracker._do(); + } + + private boolean _cluster(double toleranceCluster) { + boolean res = Clusterer.executeNonReciprocal(m_shape, toleranceCluster); + return res; + } + + private boolean _crack(double tolerance_for_cracking) { + boolean res = Cracker.execute(m_shape, tolerance_for_cracking, m_progressTracker); + return res; + } + + private boolean _do() { + double tol = m_tolerance; + + // Use same tolerances as ArcObjects (2 * sqrt(2) * tolerance for + // clustering) + // sqrt(2) * tolerance for cracking. + // Also, inflate the tolerances slightly to insure the simplified result + // would not change after small rounding issues. + + final double c_factor = 1e-5; + final double c_factor_for_needs_cracking = 1e-6; + double tolerance_for_clustering = InternalUtils + .adjust_tolerance_for_TE_clustering(tol); + double tolerance_for_needs_cracking = InternalUtils + .adjust_tolerance_for_TE_cracking(tol); + double tolerance_for_cracking = tolerance_for_needs_cracking + * (1.0 + c_factor); + tolerance_for_needs_cracking *= (1.0 + c_factor_for_needs_cracking); + + // Require tolerance_for_clustering > tolerance_for_cracking > + // tolerance_for_needs_cracking + assert (tolerance_for_clustering > tolerance_for_cracking); + assert (tolerance_for_cracking > tolerance_for_needs_cracking); + + // double toleranceCluster = m_tolerance * Math.sqrt(2.0) * 1.00001; + boolean bChanged = false; + int max_iter = m_shape.getTotalPointCount() + 10 > 30 ? 1000 : (m_shape + .getTotalPointCount() + 10) + * (m_shape.getTotalPointCount() + 10); + int iter = 0; + boolean has_point_features = m_shape.hasPointFeatures(); + for (; ; iter++) { + if (iter > max_iter) + throw new GeometryException( + "Internal Error: max number of iterations exceeded");// too + // many + // iterations + + boolean bClustered = _cluster(tolerance_for_clustering); // find + // close + // vertices and + // clamp them + // together. + bChanged |= bClustered; + + if (m_filter_degenerate_segments) { + boolean bFiltered = (m_shape.filterClosePoints( + tolerance_for_clustering, true, false) != 0); // remove all + // degenerate + // segments. + bChanged |= bFiltered; + } + + boolean b_cracked = false; + if (iter == 0 + || has_point_features + || Cracker.needsCracking(true, m_shape, + tolerance_for_needs_cracking, null, + m_progressTracker)) { + // Cracks only if shape contains segments. + b_cracked = _crack(tolerance_for_cracking); // crack all + // segments at + // intersection + // points and touch + // points. If + // Cracked, then the + // iteration will be + // repeated. + bChanged |= b_cracked; + } + + if (!b_cracked) + break;// was not cracked, so we can bail out. + else { + // Loop while cracking happens. + } + + ProgressTracker.checkAndThrow(m_progressTracker); + } + + return bChanged; + } } diff --git a/src/main/java/com/esri/core/geometry/Cracker.java b/src/main/java/com/esri/core/geometry/Cracker.java index b0cd16f2..55d61ef4 100644 --- a/src/main/java/com/esri/core/geometry/Cracker.java +++ b/src/main/java/com/esri/core/geometry/Cracker.java @@ -31,516 +31,516 @@ * Simplify. */ final class Cracker { - private EditShape m_shape; - private ProgressTracker m_progress_tracker; - private NonSimpleResult m_non_simple_result; - private double m_tolerance; - private Treap m_sweep_structure; - private SweepComparator m_sweep_comparator; - private boolean m_bAllowCoincident; - - private Segment getSegment_(int vertex, Line lineHelper) { - Segment seg = m_shape.getSegment(vertex); - if (seg == null) { - if (!m_shape.queryLineConnector(vertex, lineHelper)) - return null; - - seg = (Segment) lineHelper; - } - - return seg; - } - - private boolean crackBruteForce_() { - EditShape.VertexIterator iter_1 = m_shape.queryVertexIterator(false); - boolean b_cracked = false; - Line line_1 = new Line(); - Line line_2 = new Line(); - Envelope2D seg_1_env = new Envelope2D(); - seg_1_env.setEmpty(); - Envelope2D seg_2_env = new Envelope2D(); - seg_2_env.setEmpty(); - boolean assume_intersecting = false; - Point helper_point = new Point(); - SegmentIntersector segment_intersector = new SegmentIntersector(); - - for (int vertex_1 = iter_1.next(); vertex_1 != -1; vertex_1 = iter_1 - .next()) { - ProgressTracker.checkAndThrow(m_progress_tracker); - - int GT_1 = m_shape.getGeometryType(iter_1.currentGeometry()); - - Segment seg_1 = null; - boolean seg_1_zero = false; - if (!Geometry.isPoint(GT_1)) { - seg_1 = getSegment_(vertex_1, line_1); - if (seg_1 == null) - continue; - - seg_1.queryEnvelope2D(seg_1_env); - seg_1_env.inflate(m_tolerance, m_tolerance); - - if (seg_1.isDegenerate(m_tolerance))// do not crack with - // degenerate segments - { - if (seg_1.isDegenerate(0)) { - seg_1_zero = true; - seg_1 = null; - } else { - continue; - } - } - } - - EditShape.VertexIterator iter_2 = m_shape - .queryVertexIterator(iter_1); - int vertex_2 = iter_2.next(); - if (vertex_2 != -1) - vertex_2 = iter_2.next(); - - for (; vertex_2 != -1; vertex_2 = iter_2.next()) { - int GT_2 = m_shape.getGeometryType(iter_2.currentGeometry()); - - Segment seg_2 = null; - boolean seg_2_zero = false; - if (!Geometry.isPoint(GT_2)) { - seg_2 = getSegment_(vertex_2, line_2); - if (seg_2 == null) { - continue; - } - - seg_2.queryEnvelope2D(seg_2_env); - if (seg_2.isDegenerate(m_tolerance))// do not crack with - // degenerate segments - { - if (seg_2.isDegenerate(0)) { - seg_2_zero = true; - seg_2 = null; - } else { - continue; - } - } - } - - int split_count_1 = 0; - int split_count_2 = 0; - if (seg_1 != null && seg_2 != null) { - if (seg_1_env.isIntersectingNE(seg_2_env)) { - segment_intersector.pushSegment(seg_1); - segment_intersector.pushSegment(seg_2); - segment_intersector.intersect(m_tolerance, - assume_intersecting); - split_count_1 = segment_intersector - .getResultSegmentCount(0); - split_count_2 = segment_intersector - .getResultSegmentCount(1); - if (split_count_1 + split_count_2 > 0) { - m_shape.splitSegment_(vertex_1, - segment_intersector, 0, true); - m_shape.splitSegment_(vertex_2, - segment_intersector, 1, true); - } - segment_intersector.clear(); - } - } else { - if (seg_1 != null) { - Point2D pt = new Point2D(); - m_shape.getXY(vertex_2, pt); - if (seg_1_env.contains(pt)) { - segment_intersector.pushSegment(seg_1); - m_shape.queryPoint(vertex_2, helper_point); - segment_intersector.intersect(m_tolerance, - helper_point, 0, 1.0, assume_intersecting); - split_count_1 = segment_intersector - .getResultSegmentCount(0); - if (split_count_1 > 0) { - m_shape.splitSegment_(vertex_1, - segment_intersector, 0, true); - if (seg_2_zero) { - //seg_2 was zero length. Need to change all coincident points - //segment at vertex_2 is dzero length, change all attached zero length segments - int v_to = -1; - for (int v = m_shape.getNextVertex(vertex_2); v != -1 && v != vertex_2; v = m_shape.getNextVertex(v)) { - seg_2 = getSegment_(v, line_2); - v_to = v; - if (seg_2 == null || !seg_2.isDegenerate(0)) - break; - } - //change from vertex_2 to v_to (inclusive). - for (int v = vertex_2; v != -1; v = m_shape.getNextVertex(v)) { - m_shape.setPoint(v, segment_intersector.getResultPoint()); - if (v == v_to) - break; - } - } else { - m_shape.setPoint(vertex_2, - segment_intersector.getResultPoint()); - } - } - segment_intersector.clear(); - } - } else if (seg_2 != null) { - Point2D pt = new Point2D(); - m_shape.getXY(vertex_1, pt); - seg_2_env.inflate(m_tolerance, m_tolerance); - if (seg_2_env.contains(pt)) { - segment_intersector.pushSegment(seg_2); - m_shape.queryPoint(vertex_1, helper_point); - segment_intersector.intersect(m_tolerance, - helper_point, 0, 1.0, assume_intersecting); - split_count_2 = segment_intersector - .getResultSegmentCount(0); - if (split_count_2 > 0) { - m_shape.splitSegment_(vertex_2, - segment_intersector, 0, true); - if (seg_1_zero) { - //seg_1 was zero length. Need to change all coincident points - //segment at vertex_2 is dzero length, change all attached zero length segments - int v_to = -1; - for (int v = m_shape.getNextVertex(vertex_1); v != -1 && v != vertex_1; v = m_shape.getNextVertex(v)) { - seg_2 = getSegment_(v, line_2);//using here seg_2 for seg_1 - v_to = v; - if (seg_2 == null || !seg_2.isDegenerate(0)) - break; - } - //change from vertex_2 to v_to (inclusive). - for (int v = vertex_1; v != -1; v = m_shape.getNextVertex(v)) { - m_shape.setPoint(v, segment_intersector.getResultPoint()); - if (v == v_to) - break; - } - } else { - m_shape.setPoint(vertex_1, - segment_intersector.getResultPoint()); - } - } - segment_intersector.clear(); - } - } else { - continue;// points on points - } - } - - if (split_count_1 + split_count_2 != 0) { - if (split_count_1 != 0) { - seg_1 = m_shape.getSegment(vertex_1);// reload segment - // after split - if (seg_1 == null) { - if (!m_shape.queryLineConnector(vertex_1, line_1)) - continue; - seg_1 = line_1; - line_1.queryEnvelope2D(seg_1_env); - } else - seg_1.queryEnvelope2D(seg_1_env); - - if (seg_1.isDegenerate(m_tolerance))// do not crack with - // degenerate - // segments - { - break; - } - } - - b_cracked = true; - } - } - } - - return b_cracked; - } - - boolean crackerPlaneSweep_() { - boolean b_cracked = planeSweep_(); - return b_cracked; - } - - boolean planeSweep_() { - PlaneSweepCrackerHelper plane_sweep = new PlaneSweepCrackerHelper(); - boolean b_cracked = plane_sweep.sweep(m_shape, m_tolerance); - return b_cracked; - } - - boolean needsCrackingImpl_() { - boolean b_needs_cracking = false; - - if (m_sweep_structure == null) - m_sweep_structure = new Treap(); - - AttributeStreamOfInt32 event_q = new AttributeStreamOfInt32(0); - event_q.reserve(m_shape.getTotalPointCount() + 1); - - EditShape.VertexIterator iter = m_shape.queryVertexIterator(); - for (int vert = iter.next(); vert != -1; vert = iter.next()) { - event_q.add(vert); - } - assert (m_shape.getTotalPointCount() == event_q.size()); - - m_shape.sortVerticesSimpleByY_(event_q, 0, event_q.size()); - event_q.add(-1);// for termination; - // create user indices to store edges that end at vertices. - int edge_index_1 = m_shape.createUserIndex(); - int edge_index_2 = m_shape.createUserIndex(); - m_sweep_comparator = new SweepComparator(m_shape, m_tolerance, !m_bAllowCoincident); - m_sweep_structure.setComparator(m_sweep_comparator); - - AttributeStreamOfInt32 swept_edges_to_delete = new AttributeStreamOfInt32( - 0); - AttributeStreamOfInt32 edges_to_insert = new AttributeStreamOfInt32(0); - - // Go throught the sorted vertices - int event_q_index = 0; - Point2D cluster_pt = new Point2D(); - - // sweep-line algorithm: - for (int vertex = event_q.get(event_q_index++); vertex != -1; ) { - m_shape.getXY(vertex, cluster_pt); - - do { - int next_vertex = m_shape.getNextVertex(vertex); - int prev_vertex = m_shape.getPrevVertex(vertex); - - if (next_vertex != -1 - && m_shape.compareVerticesSimpleY_(vertex, next_vertex) < 0) { - edges_to_insert.add(vertex); - edges_to_insert.add(next_vertex); - } - - if (prev_vertex != -1 - && m_shape.compareVerticesSimpleY_(vertex, prev_vertex) < 0) { - edges_to_insert.add(prev_vertex); - edges_to_insert.add(prev_vertex); - } - - // Continue accumulating current cluster - int attached_edge_1 = m_shape - .getUserIndex(vertex, edge_index_1); - if (attached_edge_1 != -1) { - swept_edges_to_delete.add(attached_edge_1); - m_shape.setUserIndex(vertex, edge_index_1, -1); - } - int attached_edge_2 = m_shape - .getUserIndex(vertex, edge_index_2); - if (attached_edge_2 != -1) { - swept_edges_to_delete.add(attached_edge_2); - m_shape.setUserIndex(vertex, edge_index_2, -1); - } - vertex = event_q.get(event_q_index++); - } while (vertex != -1 && m_shape.isEqualXY(vertex, cluster_pt)); - - boolean b_continuing_segment_chain_optimization = swept_edges_to_delete - .size() == 1 && edges_to_insert.size() == 2; - - int new_left = -1; - int new_right = -1; - // Process the cluster - for (int i = 0, n = swept_edges_to_delete.size(); i < n; i++) { - // Find left and right neighbour of the edges that terminate at - // the cluster (there will be atmost only one left and one - // right). - int edge = swept_edges_to_delete.get(i); - int left = m_sweep_structure.getPrev(edge); - if (left != -1 && !swept_edges_to_delete.hasElement(left))// Note: - // for - // some - // heavy - // cases, - // it - // could - // be - // better - // to - // use - // binary - // search. - { - assert (new_left == -1); - new_left = left; - } - - int right = m_sweep_structure.getNext(edge); - if (right != -1 && !swept_edges_to_delete.hasElement(right)) { - assert (new_right == -1); - new_right = right; - } + private EditShape m_shape; + private ProgressTracker m_progress_tracker; + private NonSimpleResult m_non_simple_result; + private double m_tolerance; + private Treap m_sweep_structure; + private SweepComparator m_sweep_comparator; + private boolean m_bAllowCoincident; + + private Segment getSegment_(int vertex, Line lineHelper) { + Segment seg = m_shape.getSegment(vertex); + if (seg == null) { + if (!m_shape.queryLineConnector(vertex, lineHelper)) + return null; + + seg = (Segment) lineHelper; + } + + return seg; + } + + private boolean crackBruteForce_() { + EditShape.VertexIterator iter_1 = m_shape.queryVertexIterator(false); + boolean b_cracked = false; + Line line_1 = new Line(); + Line line_2 = new Line(); + Envelope2D seg_1_env = new Envelope2D(); + seg_1_env.setEmpty(); + Envelope2D seg_2_env = new Envelope2D(); + seg_2_env.setEmpty(); + boolean assume_intersecting = false; + Point helper_point = new Point(); + SegmentIntersector segment_intersector = new SegmentIntersector(); + + for (int vertex_1 = iter_1.next(); vertex_1 != -1; vertex_1 = iter_1 + .next()) { + ProgressTracker.checkAndThrow(m_progress_tracker); + + int GT_1 = m_shape.getGeometryType(iter_1.currentGeometry()); + + Segment seg_1 = null; + boolean seg_1_zero = false; + if (!Geometry.isPoint(GT_1)) { + seg_1 = getSegment_(vertex_1, line_1); + if (seg_1 == null) + continue; + + seg_1.queryEnvelope2D(seg_1_env); + seg_1_env.inflate(m_tolerance, m_tolerance); + + if (seg_1.isDegenerate(m_tolerance))// do not crack with + // degenerate segments + { + if (seg_1.isDegenerate(0)) { + seg_1_zero = true; + seg_1 = null; + } else { + continue; + } + } + } + + EditShape.VertexIterator iter_2 = m_shape + .queryVertexIterator(iter_1); + int vertex_2 = iter_2.next(); + if (vertex_2 != -1) + vertex_2 = iter_2.next(); + + for (; vertex_2 != -1; vertex_2 = iter_2.next()) { + int GT_2 = m_shape.getGeometryType(iter_2.currentGeometry()); + + Segment seg_2 = null; + boolean seg_2_zero = false; + if (!Geometry.isPoint(GT_2)) { + seg_2 = getSegment_(vertex_2, line_2); + if (seg_2 == null) { + continue; + } + + seg_2.queryEnvelope2D(seg_2_env); + if (seg_2.isDegenerate(m_tolerance))// do not crack with + // degenerate segments + { + if (seg_2.isDegenerate(0)) { + seg_2_zero = true; + seg_2 = null; + } else { + continue; + } + } + } + + int split_count_1 = 0; + int split_count_2 = 0; + if (seg_1 != null && seg_2 != null) { + if (seg_1_env.isIntersectingNE(seg_2_env)) { + segment_intersector.pushSegment(seg_1); + segment_intersector.pushSegment(seg_2); + segment_intersector.intersect(m_tolerance, + assume_intersecting); + split_count_1 = segment_intersector + .getResultSegmentCount(0); + split_count_2 = segment_intersector + .getResultSegmentCount(1); + if (split_count_1 + split_count_2 > 0) { + m_shape.splitSegment_(vertex_1, + segment_intersector, 0, true); + m_shape.splitSegment_(vertex_2, + segment_intersector, 1, true); + } + segment_intersector.clear(); + } + } else { + if (seg_1 != null) { + Point2D pt = new Point2D(); + m_shape.getXY(vertex_2, pt); + if (seg_1_env.contains(pt)) { + segment_intersector.pushSegment(seg_1); + m_shape.queryPoint(vertex_2, helper_point); + segment_intersector.intersect(m_tolerance, + helper_point, 0, 1.0, assume_intersecting); + split_count_1 = segment_intersector + .getResultSegmentCount(0); + if (split_count_1 > 0) { + m_shape.splitSegment_(vertex_1, + segment_intersector, 0, true); + if (seg_2_zero) { + //seg_2 was zero length. Need to change all coincident points + //segment at vertex_2 is dzero length, change all attached zero length segments + int v_to = -1; + for (int v = m_shape.getNextVertex(vertex_2); v != -1 && v != vertex_2; v = m_shape.getNextVertex(v)) { + seg_2 = getSegment_(v, line_2); + v_to = v; + if (seg_2 == null || !seg_2.isDegenerate(0)) + break; + } + //change from vertex_2 to v_to (inclusive). + for (int v = vertex_2; v != -1; v = m_shape.getNextVertex(v)) { + m_shape.setPoint(v, segment_intersector.getResultPoint()); + if (v == v_to) + break; + } + } else { + m_shape.setPoint(vertex_2, + segment_intersector.getResultPoint()); + } + } + segment_intersector.clear(); + } + } else if (seg_2 != null) { + Point2D pt = new Point2D(); + m_shape.getXY(vertex_1, pt); + seg_2_env.inflate(m_tolerance, m_tolerance); + if (seg_2_env.contains(pt)) { + segment_intersector.pushSegment(seg_2); + m_shape.queryPoint(vertex_1, helper_point); + segment_intersector.intersect(m_tolerance, + helper_point, 0, 1.0, assume_intersecting); + split_count_2 = segment_intersector + .getResultSegmentCount(0); + if (split_count_2 > 0) { + m_shape.splitSegment_(vertex_2, + segment_intersector, 0, true); + if (seg_1_zero) { + //seg_1 was zero length. Need to change all coincident points + //segment at vertex_2 is dzero length, change all attached zero length segments + int v_to = -1; + for (int v = m_shape.getNextVertex(vertex_1); v != -1 && v != vertex_1; v = m_shape.getNextVertex(v)) { + seg_2 = getSegment_(v, line_2);//using here seg_2 for seg_1 + v_to = v; + if (seg_2 == null || !seg_2.isDegenerate(0)) + break; + } + //change from vertex_2 to v_to (inclusive). + for (int v = vertex_1; v != -1; v = m_shape.getNextVertex(v)) { + m_shape.setPoint(v, segment_intersector.getResultPoint()); + if (v == v_to) + break; + } + } else { + m_shape.setPoint(vertex_1, + segment_intersector.getResultPoint()); + } + } + segment_intersector.clear(); + } + } else { + continue;// points on points + } + } + + if (split_count_1 + split_count_2 != 0) { + if (split_count_1 != 0) { + seg_1 = m_shape.getSegment(vertex_1);// reload segment + // after split + if (seg_1 == null) { + if (!m_shape.queryLineConnector(vertex_1, line_1)) + continue; + seg_1 = line_1; + line_1.queryEnvelope2D(seg_1_env); + } else + seg_1.queryEnvelope2D(seg_1_env); + + if (seg_1.isDegenerate(m_tolerance))// do not crack with + // degenerate + // segments + { + break; + } + } + + b_cracked = true; + } + } + } + + return b_cracked; + } + + boolean crackerPlaneSweep_() { + boolean b_cracked = planeSweep_(); + return b_cracked; + } + + boolean planeSweep_() { + PlaneSweepCrackerHelper plane_sweep = new PlaneSweepCrackerHelper(); + boolean b_cracked = plane_sweep.sweep(m_shape, m_tolerance); + return b_cracked; + } + + boolean needsCrackingImpl_() { + boolean b_needs_cracking = false; + + if (m_sweep_structure == null) + m_sweep_structure = new Treap(); + + AttributeStreamOfInt32 event_q = new AttributeStreamOfInt32(0); + event_q.reserve(m_shape.getTotalPointCount() + 1); + + EditShape.VertexIterator iter = m_shape.queryVertexIterator(); + for (int vert = iter.next(); vert != -1; vert = iter.next()) { + event_q.add(vert); + } + assert (m_shape.getTotalPointCount() == event_q.size()); + + m_shape.sortVerticesSimpleByY_(event_q, 0, event_q.size()); + event_q.add(-1);// for termination; + // create user indices to store edges that end at vertices. + int edge_index_1 = m_shape.createUserIndex(); + int edge_index_2 = m_shape.createUserIndex(); + m_sweep_comparator = new SweepComparator(m_shape, m_tolerance, !m_bAllowCoincident); + m_sweep_structure.setComparator(m_sweep_comparator); + + AttributeStreamOfInt32 swept_edges_to_delete = new AttributeStreamOfInt32( + 0); + AttributeStreamOfInt32 edges_to_insert = new AttributeStreamOfInt32(0); + + // Go throught the sorted vertices + int event_q_index = 0; + Point2D cluster_pt = new Point2D(); + + // sweep-line algorithm: + for (int vertex = event_q.get(event_q_index++); vertex != -1; ) { + m_shape.getXY(vertex, cluster_pt); + + do { + int next_vertex = m_shape.getNextVertex(vertex); + int prev_vertex = m_shape.getPrevVertex(vertex); + + if (next_vertex != -1 + && m_shape.compareVerticesSimpleY_(vertex, next_vertex) < 0) { + edges_to_insert.add(vertex); + edges_to_insert.add(next_vertex); + } + + if (prev_vertex != -1 + && m_shape.compareVerticesSimpleY_(vertex, prev_vertex) < 0) { + edges_to_insert.add(prev_vertex); + edges_to_insert.add(prev_vertex); + } + + // Continue accumulating current cluster + int attached_edge_1 = m_shape + .getUserIndex(vertex, edge_index_1); + if (attached_edge_1 != -1) { + swept_edges_to_delete.add(attached_edge_1); + m_shape.setUserIndex(vertex, edge_index_1, -1); + } + int attached_edge_2 = m_shape + .getUserIndex(vertex, edge_index_2); + if (attached_edge_2 != -1) { + swept_edges_to_delete.add(attached_edge_2); + m_shape.setUserIndex(vertex, edge_index_2, -1); + } + vertex = event_q.get(event_q_index++); + } while (vertex != -1 && m_shape.isEqualXY(vertex, cluster_pt)); + + boolean b_continuing_segment_chain_optimization = swept_edges_to_delete + .size() == 1 && edges_to_insert.size() == 2; + + int new_left = -1; + int new_right = -1; + // Process the cluster + for (int i = 0, n = swept_edges_to_delete.size(); i < n; i++) { + // Find left and right neighbour of the edges that terminate at + // the cluster (there will be atmost only one left and one + // right). + int edge = swept_edges_to_delete.get(i); + int left = m_sweep_structure.getPrev(edge); + if (left != -1 && !swept_edges_to_delete.hasElement(left))// Note: + // for + // some + // heavy + // cases, + // it + // could + // be + // better + // to + // use + // binary + // search. + { + assert (new_left == -1); + new_left = left; + } + + int right = m_sweep_structure.getNext(edge); + if (right != -1 && !swept_edges_to_delete.hasElement(right)) { + assert (new_right == -1); + new_right = right; + } //#ifdef NDEBUG - if (new_left != -1 && new_right != -1) - break; + if (new_left != -1 && new_right != -1) + break; //#endif - } - - assert (new_left == -1 || new_left != new_right); - - m_sweep_comparator.setSweepY(cluster_pt.y, cluster_pt.x); - - // Delete the edges that terminate at the cluster. - for (int i = 0, n = swept_edges_to_delete.size(); i < n; i++) { - int edge = swept_edges_to_delete.get(i); - m_sweep_structure.deleteNode(edge, -1); - } - swept_edges_to_delete.clear(false); - - if (!b_continuing_segment_chain_optimization && new_left != -1 && new_right != -1) { - if (checkForIntersections_(new_left, new_right)) { - b_needs_cracking = true; - m_non_simple_result = m_sweep_comparator.getResult(); - break; - } - } - - for (int i = 0, n = edges_to_insert.size(); i < n; i += 2) { - int v = edges_to_insert.get(i); - int otherv = edges_to_insert.get(i + 1); - - int new_edge_1 = -1; - if (b_continuing_segment_chain_optimization) { - new_edge_1 = m_sweep_structure.addElementAtPosition( - new_left, new_right, v, true, true, -1); - b_continuing_segment_chain_optimization = false; - } else { - new_edge_1 = m_sweep_structure.addElement(v, -1); // the - // sweep - // structure - // consist - // of - // the - // origin - // vertices - // for - // edges. - // One - // can - // always - // get - // the - // other - // endpoint - // as - // the - // next - // vertex. - } - - if (m_sweep_comparator.intersectionDetected()) { - m_non_simple_result = m_sweep_comparator.getResult(); - b_needs_cracking = true; - break; - } - - int e_1 = m_shape.getUserIndex(otherv, edge_index_1); - if (e_1 == -1) - m_shape.setUserIndex(otherv, edge_index_1, new_edge_1); - else { - assert (m_shape.getUserIndex(otherv, edge_index_2) == -1); - m_shape.setUserIndex(otherv, edge_index_2, new_edge_1); - } - } - - if (b_needs_cracking) - break; - - // Start accumulating new cluster - edges_to_insert.resizePreserveCapacity(0); - } - - m_shape.removeUserIndex(edge_index_1); - m_shape.removeUserIndex(edge_index_2); - return b_needs_cracking; - } - - boolean checkForIntersections_(int sweep_edge_1, int sweep_edge_2) { - assert (sweep_edge_1 != sweep_edge_2); - int left = m_sweep_structure.getElement(sweep_edge_1); - assert (left != m_sweep_structure.getElement(sweep_edge_2)); - m_sweep_comparator.compare(m_sweep_structure, left, sweep_edge_2);// compare - // detects - // intersections - boolean b_intersects = m_sweep_comparator.intersectionDetected(); - m_sweep_comparator.clearIntersectionDetectedFlag(); - return b_intersects; - } - - // void dbg_print_sweep_edge_(int edge); - // void dbg_print_sweep_structure_(); - // void dbg_check_sweep_structure_(); - Cracker(ProgressTracker progress_tracker) { - m_progress_tracker = progress_tracker; - m_bAllowCoincident = true; - } - - static boolean canBeCracked(EditShape shape) { - for (int geometry = shape.getFirstGeometry(); geometry != -1; geometry = shape - .getNextGeometry(geometry)) { - if (!Geometry.isMultiPath(shape.getGeometryType(geometry))) - continue; - return true; - } - return false; - } - - static boolean execute(EditShape shape, Envelope2D extent, - double tolerance, ProgressTracker progress_tracker) { - if (!canBeCracked(shape)) // make sure it contains some segments, - // otherwise no need to crack. - return false; - - Cracker cracker = new Cracker(progress_tracker); - cracker.m_shape = shape; - cracker.m_tolerance = tolerance; - // Use brute force for smaller shapes, and a planesweep for bigger - // shapes. - boolean b_cracked = false; - if (shape.getTotalPointCount() < 15) // what is a good number? - { - b_cracked = cracker.crackBruteForce_(); - } else { - boolean b_cracked_1 = cracker.crackerPlaneSweep_(); - return b_cracked_1; - } - return b_cracked; - } - - static boolean execute(EditShape shape, double tolerance, - ProgressTracker progress_tracker) { - return Cracker.execute(shape, shape.getEnvelope2D(), tolerance, - progress_tracker); - } - - // Used for IsSimple. - static boolean needsCracking(boolean allowCoincident, EditShape shape, double tolerance, - NonSimpleResult result, ProgressTracker progress_tracker) { - if (!canBeCracked(shape)) - return false; - - Cracker cracker = new Cracker(progress_tracker); - cracker.m_shape = shape; - cracker.m_tolerance = tolerance; - cracker.m_bAllowCoincident = allowCoincident; - if (cracker.needsCrackingImpl_()) { - if (result != null) - result.Assign(cracker.m_non_simple_result); - return true; - } - - // Now swap the coordinates to catch horizontal cases. - Transformation2D transform = new Transformation2D(); - transform.setSwapCoordinates(); - shape.applyTransformation(transform); - - cracker = new Cracker(progress_tracker); - cracker.m_shape = shape; - cracker.m_tolerance = tolerance; - cracker.m_bAllowCoincident = allowCoincident; - boolean b_res = cracker.needsCrackingImpl_(); - - transform.setSwapCoordinates(); - shape.applyTransformation(transform);// restore shape - - if (b_res) { - if (result != null) - result.Assign(cracker.m_non_simple_result); - return true; - } - - return false; - } + } + + assert (new_left == -1 || new_left != new_right); + + m_sweep_comparator.setSweepY(cluster_pt.y, cluster_pt.x); + + // Delete the edges that terminate at the cluster. + for (int i = 0, n = swept_edges_to_delete.size(); i < n; i++) { + int edge = swept_edges_to_delete.get(i); + m_sweep_structure.deleteNode(edge, -1); + } + swept_edges_to_delete.clear(false); + + if (!b_continuing_segment_chain_optimization && new_left != -1 && new_right != -1) { + if (checkForIntersections_(new_left, new_right)) { + b_needs_cracking = true; + m_non_simple_result = m_sweep_comparator.getResult(); + break; + } + } + + for (int i = 0, n = edges_to_insert.size(); i < n; i += 2) { + int v = edges_to_insert.get(i); + int otherv = edges_to_insert.get(i + 1); + + int new_edge_1 = -1; + if (b_continuing_segment_chain_optimization) { + new_edge_1 = m_sweep_structure.addElementAtPosition( + new_left, new_right, v, true, true, -1); + b_continuing_segment_chain_optimization = false; + } else { + new_edge_1 = m_sweep_structure.addElement(v, -1); // the + // sweep + // structure + // consist + // of + // the + // origin + // vertices + // for + // edges. + // One + // can + // always + // get + // the + // other + // endpoint + // as + // the + // next + // vertex. + } + + if (m_sweep_comparator.intersectionDetected()) { + m_non_simple_result = m_sweep_comparator.getResult(); + b_needs_cracking = true; + break; + } + + int e_1 = m_shape.getUserIndex(otherv, edge_index_1); + if (e_1 == -1) + m_shape.setUserIndex(otherv, edge_index_1, new_edge_1); + else { + assert (m_shape.getUserIndex(otherv, edge_index_2) == -1); + m_shape.setUserIndex(otherv, edge_index_2, new_edge_1); + } + } + + if (b_needs_cracking) + break; + + // Start accumulating new cluster + edges_to_insert.resizePreserveCapacity(0); + } + + m_shape.removeUserIndex(edge_index_1); + m_shape.removeUserIndex(edge_index_2); + return b_needs_cracking; + } + + boolean checkForIntersections_(int sweep_edge_1, int sweep_edge_2) { + assert (sweep_edge_1 != sweep_edge_2); + int left = m_sweep_structure.getElement(sweep_edge_1); + assert (left != m_sweep_structure.getElement(sweep_edge_2)); + m_sweep_comparator.compare(m_sweep_structure, left, sweep_edge_2);// compare + // detects + // intersections + boolean b_intersects = m_sweep_comparator.intersectionDetected(); + m_sweep_comparator.clearIntersectionDetectedFlag(); + return b_intersects; + } + + // void dbg_print_sweep_edge_(int edge); + // void dbg_print_sweep_structure_(); + // void dbg_check_sweep_structure_(); + Cracker(ProgressTracker progress_tracker) { + m_progress_tracker = progress_tracker; + m_bAllowCoincident = true; + } + + static boolean canBeCracked(EditShape shape) { + for (int geometry = shape.getFirstGeometry(); geometry != -1; geometry = shape + .getNextGeometry(geometry)) { + if (!Geometry.isMultiPath(shape.getGeometryType(geometry))) + continue; + return true; + } + return false; + } + + static boolean execute(EditShape shape, Envelope2D extent, + double tolerance, ProgressTracker progress_tracker) { + if (!canBeCracked(shape)) // make sure it contains some segments, + // otherwise no need to crack. + return false; + + Cracker cracker = new Cracker(progress_tracker); + cracker.m_shape = shape; + cracker.m_tolerance = tolerance; + // Use brute force for smaller shapes, and a planesweep for bigger + // shapes. + boolean b_cracked = false; + if (shape.getTotalPointCount() < 15) // what is a good number? + { + b_cracked = cracker.crackBruteForce_(); + } else { + boolean b_cracked_1 = cracker.crackerPlaneSweep_(); + return b_cracked_1; + } + return b_cracked; + } + + static boolean execute(EditShape shape, double tolerance, + ProgressTracker progress_tracker) { + return Cracker.execute(shape, shape.getEnvelope2D(), tolerance, + progress_tracker); + } + + // Used for IsSimple. + static boolean needsCracking(boolean allowCoincident, EditShape shape, double tolerance, + NonSimpleResult result, ProgressTracker progress_tracker) { + if (!canBeCracked(shape)) + return false; + + Cracker cracker = new Cracker(progress_tracker); + cracker.m_shape = shape; + cracker.m_tolerance = tolerance; + cracker.m_bAllowCoincident = allowCoincident; + if (cracker.needsCrackingImpl_()) { + if (result != null) + result.Assign(cracker.m_non_simple_result); + return true; + } + + // Now swap the coordinates to catch horizontal cases. + Transformation2D transform = new Transformation2D(); + transform.setSwapCoordinates(); + shape.applyTransformation(transform); + + cracker = new Cracker(progress_tracker); + cracker.m_shape = shape; + cracker.m_tolerance = tolerance; + cracker.m_bAllowCoincident = allowCoincident; + boolean b_res = cracker.needsCrackingImpl_(); + + transform.setSwapCoordinates(); + shape.applyTransformation(transform);// restore shape + + if (b_res) { + if (result != null) + result.Assign(cracker.m_non_simple_result); + return true; + } + + return false; + } } diff --git a/src/main/java/com/esri/core/geometry/Cutter.java b/src/main/java/com/esri/core/geometry/Cutter.java index e4b106f4..5098fce9 100644 --- a/src/main/java/com/esri/core/geometry/Cutter.java +++ b/src/main/java/com/esri/core/geometry/Cutter.java @@ -32,1390 +32,1390 @@ import java.util.Arrays; class Cutter { - static class CompareVertices { - int m_orderIndex; - EditShape m_editShape; - - CompareVertices(int orderIndex, EditShape editShape) { - m_orderIndex = orderIndex; - m_editShape = editShape; - } - - int _compareVertices(int v1, int v2) { - Point2D pt1 = new Point2D(); - m_editShape.getXY(v1, pt1); - Point2D pt2 = new Point2D(); - m_editShape.getXY(v2, pt2); - int res = pt1.compare(pt2); - if (res != 0) - return res; - int z1 = m_editShape.getUserIndex(v1, m_orderIndex); - int z2 = m_editShape.getUserIndex(v2, m_orderIndex); - if (z1 < z2) - return -1; - if (z1 == z2) - return 0; - return 1; - } - } - - static class CutterVertexComparer extends - AttributeStreamOfInt32.IntComparator { - CompareVertices m_compareVertices; - - CutterVertexComparer(CompareVertices _compareVertices) { - m_compareVertices = _compareVertices; - } - - @Override - public int compare(int v1, int v2) { - return m_compareVertices._compareVertices(v1, v2); - } - } - - static class CutEvent { - int m_ivertexCuttee; - int m_ipartCuttee; - double m_scalarCuttee0; - double m_scalarCuttee1; - int m_count; - int m_ivertexCutter; - int m_ipartCutter; - double m_scalarCutter0; - double m_scalarCutter1; - - CutEvent(int ivertexCuttee, int ipartCuttee, double scalarCuttee0, - double scalarCuttee1, int count, int ivertexCutter, - int ipartCutter, double scalarCutter0, double scalarCutter1) { - m_ivertexCuttee = ivertexCuttee; - m_ipartCuttee = ipartCuttee; - m_scalarCuttee0 = scalarCuttee0; - m_scalarCuttee1 = scalarCuttee1; - m_count = count; - m_ivertexCutter = ivertexCutter; - m_ipartCutter = ipartCutter; - m_scalarCutter0 = scalarCutter0; - m_scalarCutter1 = scalarCutter1; - } - } - - static EditShape CutPolyline(boolean bConsiderTouch, Polyline cuttee, - Polyline cutter, double tolerance, - ArrayList cutPairs, - AttributeStreamOfInt32 segmentCounts, ProgressTracker progressTracker) { - if (cuttee.isEmpty()) { - OperatorCutLocal.CutPair cutPair; - cutPair = new OperatorCutLocal.CutPair(cuttee, - OperatorCutLocal.Side.Uncut, -1, -1, NumberUtils.NaN(), - OperatorCutLocal.Side.Uncut, -1, -1, NumberUtils.NaN(), -1, - -1, NumberUtils.NaN(), -1, -1, NumberUtils.NaN()); - cutPairs.add(cutPair); - return null; - } - - EditShape editShape = new EditShape(); - int cutteeHandle = editShape.addGeometry(cuttee); - int cutterHandle = editShape.addGeometry(cutter); - CrackAndCluster.execute(editShape, tolerance, progressTracker, true); - - int order = 0; - int orderIndex = editShape.createUserIndex(); - for (int igeometry = editShape.getFirstGeometry(); igeometry != -1; igeometry = editShape - .getNextGeometry(igeometry)) - for (int ipath = editShape.getFirstPath(igeometry); ipath != -1; ipath = editShape - .getNextPath(ipath)) - for (int ivertex = editShape.getFirstVertex(ipath), i = 0, n = editShape - .getPathSize(ipath); i < n; ivertex = editShape - .getNextVertex(ivertex), i++) - editShape.setUserIndex(ivertex, orderIndex, order++); - - ArrayList cutEvents = _getCutEvents(orderIndex, editShape); - _Cut(bConsiderTouch, false, cutEvents, editShape, cutPairs, - segmentCounts); - return editShape; - } - - private static ArrayList _getCutEvents(int orderIndex, - EditShape editShape) { - int pointCount = editShape.getTotalPointCount(); - - // Sort vertices lexicographically - // Firstly copy allvertices to an array. - AttributeStreamOfInt32 vertices = new AttributeStreamOfInt32(0); - - for (int igeometry = editShape.getFirstGeometry(); igeometry != -1; igeometry = editShape - .getNextGeometry(igeometry)) - for (int ipath = editShape.getFirstPath(igeometry); ipath != -1; ipath = editShape - .getNextPath(ipath)) - for (int ivertex = editShape.getFirstVertex(ipath), i = 0, n = editShape - .getPathSize(ipath); i < n; ivertex = editShape - .getNextVertex(ivertex), i++) - vertices.add(ivertex); - - // Sort - CompareVertices compareVertices = new CompareVertices(orderIndex, - editShape); - vertices.Sort(0, pointCount, new CutterVertexComparer(compareVertices)); - // SORTDYNAMICARRAYEX(vertices, index_type, 0, pointCount, - // CutterVertexComparer, compareVertices); - - // Find Cut Events - ArrayList cutEvents = new ArrayList(0); - ArrayList cutEventsTemp = new ArrayList(0); - - int eventIndex = editShape.createUserIndex(); - int eventIndexTemp = editShape.createUserIndex(); - - int cutteeHandle = editShape.getFirstGeometry(); - int cutterHandle = editShape.getNextGeometry(cutteeHandle); - - Point2D pointCuttee = new Point2D(); - Point2D pointCutter = new Point2D(); - - int ivertexCuttee = vertices.get(0); - ; - int ipartCuttee = editShape.getPathFromVertex(ivertexCuttee); - int igeometryCuttee = editShape.getGeometryFromPath(ipartCuttee); - editShape.getXY(ivertexCuttee, pointCuttee); - - int istart = 1; - int ivertex = 0; - while (istart < pointCount - 1) { - boolean bCutEvent = false; - for (int i = istart; i < pointCount; i++) { - if (i == ivertex) - continue; - - int ivertexCutter = vertices.get(i); - int ipartCutter = editShape.getPathFromVertex(ivertexCutter); - int igeometryCutter = editShape - .getGeometryFromPath(ipartCutter); - editShape.getXY(ivertexCutter, pointCutter); - - if (pointCuttee.isEqual(pointCutter)) { - boolean bCondition = igeometryCuttee == cutteeHandle - && igeometryCutter == cutterHandle; - - if (bCondition) - bCutEvent = _cutteeCutterEvents(eventIndex, - eventIndexTemp, editShape, cutEvents, - cutEventsTemp, ipartCuttee, ivertexCuttee, - ipartCutter, ivertexCutter); - } else - break; - } - - if (bCutEvent || ivertex == istart - 1) { - if (bCutEvent && (ivertex == istart - 1)) - istart--; - - if (++ivertex == pointCount) - break; - - ivertexCuttee = vertices.get(ivertex); - ipartCuttee = editShape.getPathFromVertex(ivertexCuttee); - igeometryCuttee = editShape.getGeometryFromPath(ipartCuttee); - editShape.getXY(ivertexCuttee, pointCuttee); - } - - if (!bCutEvent) - istart = ivertex + 1; - } - - ArrayList cutEventsSorted = new ArrayList(0); - - // Sort CutEvents - int icutEvent; - int icutEventTemp; - for (int igeometry = editShape.getFirstGeometry(); igeometry != -1; igeometry = editShape.getNextGeometry(igeometry)) { - for (int ipath = editShape.getFirstPath(igeometry); ipath != -1; ipath = editShape.getNextPath(ipath)) { - for (int iv = editShape.getFirstVertex(ipath), i = 0, n = editShape.getPathSize(ipath); i < n; iv = editShape.getNextVertex(iv), i++) { - icutEventTemp = editShape.getUserIndex(iv, eventIndexTemp); - if (icutEventTemp >= 0) { - // _ASSERT(cutEventsTemp.get(icutEventTemp).m_ivertexCuttee - // == iv); - while (icutEventTemp < cutEventsTemp.size() && cutEventsTemp.get(icutEventTemp).m_ivertexCuttee == iv) - cutEventsSorted.add(cutEventsTemp.get(icutEventTemp++)); - } - - icutEvent = editShape.getUserIndex(iv, eventIndex); - if (icutEvent >= 0) { - // _ASSERT(cutEvents->Get(icutEvent)->m_ivertexCuttee == - // iv); - while (icutEvent < cutEvents.size() && cutEvents.get(icutEvent).m_ivertexCuttee == iv) - cutEventsSorted.add(cutEvents.get(icutEvent++)); - } - } - } - } - - // _ASSERT(cutEvents->Size() + cutEventsTemp->Size() == - // cutEventsSorted->Size()); - editShape.removeUserIndex(eventIndex); - editShape.removeUserIndex(eventIndexTemp); - return cutEventsSorted; - } - - static boolean _cutteeCutterEvents(int eventIndex, int eventIndexTemp, - EditShape editShape, ArrayList cutEvents, - ArrayList cutEventsTemp, int ipartCuttee, - int ivertexCuttee, int ipartCutter, int ivertexCutter) { - int ilastVertexCuttee = editShape.getLastVertex(ipartCuttee); - int ilastVertexCutter = editShape.getLastVertex(ipartCutter); - int ifirstVertexCuttee = editShape.getFirstVertex(ipartCuttee); - int ifirstVertexCutter = editShape.getFirstVertex(ipartCutter); - int ivertexCutteePrev = editShape.getPrevVertex(ivertexCuttee); - int ivertexCutterPrev = editShape.getPrevVertex(ivertexCutter); - - boolean bEndEnd = false; - boolean bEndStart = false; - boolean bStartEnd = false; - boolean bStartStart = false; - - if (ivertexCuttee != ifirstVertexCuttee) { - if (ivertexCutter != ifirstVertexCutter) - bEndEnd = _cutteeEndCutterEndEvent(eventIndex, editShape, - cutEvents, ipartCuttee, ivertexCutteePrev, ipartCutter, - ivertexCutterPrev); - - if (ivertexCutter != ilastVertexCutter) - bEndStart = _cutteeEndCutterStartEvent(eventIndex, editShape, - cutEvents, ipartCuttee, ivertexCutteePrev, ipartCutter, - ivertexCutter); - } - - if (ivertexCuttee != ilastVertexCuttee) { - if (ivertexCutter != ifirstVertexCutter) - bStartEnd = _cutteeStartCutterEndEvent(eventIndexTemp, - editShape, cutEventsTemp, ipartCuttee, ivertexCuttee, - ipartCutter, ivertexCutterPrev, ifirstVertexCuttee); - - if (ivertexCutter != ilastVertexCutter) - bStartStart = _cutteeStartCutterStartEvent(eventIndexTemp, - editShape, cutEventsTemp, ipartCuttee, ivertexCuttee, - ipartCutter, ivertexCutter, ifirstVertexCuttee); - } - - if (bEndEnd && bEndStart && bStartEnd) { - int iendstart = cutEvents.size() - 1; - int istartend = (bStartStart ? cutEventsTemp.size() - 2 - : cutEventsTemp.size() - 1); - - if (cutEventsTemp.get(istartend).m_count == 2) { - // Replace bEndEnd with bEndStart, and remove duplicate - // bEndStart (get rid of bEndEnd) - cutEvents.set(iendstart - 1, cutEvents.get(iendstart)); - cutEvents.remove(cutEvents.size() - 1); - } - } else if (bEndEnd && bEndStart && bStartStart) { - int istartstart = cutEventsTemp.size() - 1; - - if (cutEventsTemp.get(istartstart).m_count == 2) { - // Remove bEndStart - CutEvent lastEvent = cutEvents.get(cutEvents.size() - 1); - cutEvents.remove(cutEvents.get(cutEvents.size() - 1)); - int icutEvent = editShape.getUserIndex( - lastEvent.m_ivertexCuttee, eventIndex); - if (icutEvent == cutEvents.size()) - editShape.setUserIndex(lastEvent.m_ivertexCuttee, - eventIndex, -1); - } - } - - return bEndEnd || bEndStart || bStartEnd || bStartStart; - } - - private static boolean _cutteeEndCutterEndEvent(int eventIndex, - EditShape editShape, ArrayList cutEvents, - int ipartCuttee, int ivertexCuttee, int ipartCutter, - int ivertexCutter) { - Segment segmentCuttee; - Segment segmentCutter; - Line lineCuttee = new Line(); - Line lineCutter = new Line(); - double[] scalarsCuttee = new double[2]; - double[] scalarsCutter = new double[2]; - - CutEvent cutEvent; - - segmentCuttee = editShape.getSegment(ivertexCuttee); - if (segmentCuttee == null) { - editShape.queryLineConnector(ivertexCuttee, lineCuttee); - segmentCuttee = lineCuttee; - } - - segmentCutter = editShape.getSegment(ivertexCutter); - if (segmentCutter == null) { - editShape.queryLineConnector(ivertexCutter, lineCutter); - segmentCutter = lineCutter; - } - - int count = segmentCuttee.intersect(segmentCutter, null, scalarsCuttee, - scalarsCutter, 0.0); - // _ASSERT(count > 0); - int icutEvent; - - // If count == 2 (i.e. when they overlap), this this event would have - // been discovered by _CutteeStartCutterStartEvent at the previous index - if (count < 2) { - cutEvent = new CutEvent(ivertexCuttee, ipartCuttee, - scalarsCuttee[0], NumberUtils.NaN(), count, ivertexCutter, - ipartCutter, scalarsCutter[0], NumberUtils.NaN()); - cutEvents.add(cutEvent); - icutEvent = editShape.getUserIndex(ivertexCuttee, eventIndex); - - if (icutEvent < 0) - editShape.setUserIndex(ivertexCuttee, eventIndex, - cutEvents.size() - 1); - } - - return true; - } - - private static boolean _cutteeEndCutterStartEvent(int eventIndex, - EditShape editShape, ArrayList cutEvents, - int ipartCuttee, int ivertexCuttee, int ipartCutter, - int ivertexCutter) { - Segment segmentCuttee; - Segment segmentCutter; - Line lineCuttee = new Line(); - Line lineCutter = new Line(); - double[] scalarsCuttee = new double[2]; - double[] scalarsCutter = new double[2]; - - CutEvent cutEvent; - - segmentCuttee = editShape.getSegment(ivertexCuttee); - if (segmentCuttee == null) { - editShape.queryLineConnector(ivertexCuttee, lineCuttee); - segmentCuttee = lineCuttee; - } - - segmentCutter = editShape.getSegment(ivertexCutter); - if (segmentCutter == null) { - editShape.queryLineConnector(ivertexCutter, lineCutter); - segmentCutter = lineCutter; - } - - int count = segmentCuttee.intersect(segmentCutter, null, scalarsCuttee, - scalarsCutter, 0.0); - // _ASSERT(count > 0); - int icutEvent; - - // If count == 2 (i.e. when they overlap), this this event would have - // been discovered by _CutteeStartCutterEndEvent at the previous index - if (count < 2) { - cutEvent = new CutEvent(ivertexCuttee, ipartCuttee, - scalarsCuttee[0], NumberUtils.NaN(), count, ivertexCutter, - ipartCutter, scalarsCutter[0], NumberUtils.NaN()); - cutEvents.add(cutEvent); - icutEvent = editShape.getUserIndex(ivertexCuttee, eventIndex); - - if (icutEvent < 0) - editShape.setUserIndex(ivertexCuttee, eventIndex, - cutEvents.size() - 1); - - return true; - } - - return false; - } - - private static boolean _cutteeStartCutterEndEvent(int eventIndex, - EditShape editShape, ArrayList cutEvents, - int ipartCuttee, int ivertexCuttee, int ipartCutter, - int ivertexCutter, int ifirstVertexCuttee) { - Segment segmentCuttee; - Segment segmentCutter; - Line lineCuttee = new Line(); - Line lineCutter = new Line(); - double[] scalarsCuttee = new double[2]; - double[] scalarsCutter = new double[2]; - - CutEvent cutEvent; - - segmentCuttee = editShape.getSegment(ivertexCuttee); - if (segmentCuttee == null) { - editShape.queryLineConnector(ivertexCuttee, lineCuttee); - segmentCuttee = lineCuttee; - } - - segmentCutter = editShape.getSegment(ivertexCutter); - if (segmentCutter == null) { - editShape.queryLineConnector(ivertexCutter, lineCutter); - segmentCutter = lineCutter; - } - - int count = segmentCuttee.intersect(segmentCutter, null, scalarsCuttee, - scalarsCutter, 0.0); - // _ASSERT(count > 0); - int icutEvent; - - if (count == 2) { - cutEvent = new CutEvent(ivertexCuttee, ipartCuttee, - scalarsCuttee[0], scalarsCuttee[1], count, ivertexCutter, - ipartCutter, scalarsCutter[0], scalarsCutter[1]); - cutEvents.add(cutEvent); - icutEvent = editShape.getUserIndex(ivertexCuttee, eventIndex); - - if (icutEvent < 0) - editShape.setUserIndex(ivertexCuttee, eventIndex, - cutEvents.size() - 1); - - return true; - } else { - boolean bCutEvent = false; - - if (ivertexCuttee == ifirstVertexCuttee) { - cutEvent = new CutEvent(ivertexCuttee, ipartCuttee, - scalarsCuttee[0], NumberUtils.NaN(), count, - ivertexCutter, ipartCutter, scalarsCutter[0], - NumberUtils.NaN()); - cutEvents.add(cutEvent); - icutEvent = editShape.getUserIndex(ivertexCuttee, eventIndex); - - if (icutEvent < 0) - editShape.setUserIndex(ivertexCuttee, eventIndex, - cutEvents.size() - 1); - - bCutEvent = true; - } - - return bCutEvent; - } - - } - - private static boolean _cutteeStartCutterStartEvent(int eventIndex, - EditShape editShape, ArrayList cutEvents, - int ipartCuttee, int ivertexCuttee, int ipartCutter, - int ivertexCutter, int ifirstVertexCuttee) { - Segment segmentCuttee; - Segment segmentCutter; - Line lineCuttee = new Line(); - Line lineCutter = new Line(); - double[] scalarsCuttee = new double[2]; - double[] scalarsCutter = new double[2]; - - CutEvent cutEvent; - - segmentCuttee = editShape.getSegment(ivertexCuttee); - if (segmentCuttee == null) { - editShape.queryLineConnector(ivertexCuttee, lineCuttee); - segmentCuttee = lineCuttee; - } - - segmentCutter = editShape.getSegment(ivertexCutter); - if (segmentCutter == null) { - editShape.queryLineConnector(ivertexCutter, lineCutter); - segmentCutter = lineCutter; - } - - int count = segmentCuttee.intersect(segmentCutter, null, scalarsCuttee, - scalarsCutter, 0.0); - // _ASSERT(count > 0); - int icutEvent; - - if (count == 2) { - cutEvent = new CutEvent(ivertexCuttee, ipartCuttee, - scalarsCuttee[0], scalarsCuttee[1], count, ivertexCutter, - ipartCutter, scalarsCutter[0], scalarsCutter[1]); - cutEvents.add(cutEvent); - icutEvent = editShape.getUserIndex(ivertexCuttee, eventIndex); - - if (icutEvent < 0) - editShape.setUserIndex(ivertexCuttee, eventIndex, - cutEvents.size() - 1); - - return true; - } else { - boolean bCutEvent = false; - - if (ivertexCuttee == ifirstVertexCuttee) { - cutEvent = new CutEvent(ivertexCuttee, ipartCuttee, - scalarsCuttee[0], NumberUtils.NaN(), count, - ivertexCutter, ipartCutter, scalarsCutter[0], - NumberUtils.NaN()); - cutEvents.add(cutEvent); - icutEvent = editShape.getUserIndex(ivertexCuttee, eventIndex); - - if (icutEvent < 0) - editShape.setUserIndex(ivertexCuttee, eventIndex, - cutEvents.size() - 1); - - bCutEvent = true; - } - - return bCutEvent; - } - - } - - static void _Cut(boolean bConsiderTouch, boolean bLocalCutsOnly, - ArrayList cutEvents, EditShape shape, - ArrayList cutPairs, - AttributeStreamOfInt32 segmentCounts) { - OperatorCutLocal.CutPair cutPair; - - Point2D[] tangents = new Point2D[4]; - tangents[0] = new Point2D(); - tangents[1] = new Point2D(); - tangents[2] = new Point2D(); - tangents[3] = new Point2D(); - Point2D tangent0 = new Point2D(); - Point2D tangent1 = new Point2D(); - Point2D tangent2 = new Point2D(); - Point2D tangent3 = new Point2D(); - - SegmentBuffer segmentBufferCuttee = null; - if (cutPairs != null) { - segmentBufferCuttee = new SegmentBuffer(); - segmentBufferCuttee.createLine(); - } - - Segment segmentCuttee = null; - int icutEvent = 0; - MultiPath multipath = null; - - Line lineCuttee = new Line(); - Line lineCutter = new Line(); - - int polyline = shape.getFirstGeometry(); - for (int ipath = shape.getFirstPath(polyline); ipath != -1; ipath = shape - .getNextPath(ipath)) { - int cut; - int cutPrev = OperatorCutLocal.Side.Uncut; - int ipartCuttee = -1; - int ivertexCuttee = -1; - double scalarCuttee = NumberUtils.NaN(); - int ipartCutteePrev = -1; - int ivertexCutteePrev = -1; - double scalarCutteePrev = NumberUtils.NaN(); - int ipartCutter = -1; - int ivertexCutter = -1; - double scalarCutter = NumberUtils.NaN(); - int ipartCutterPrev = -1; - int ivertexCutterPrev = -1; - double scalarCutterPrev = NumberUtils.NaN(); - boolean bNoCutYet = true; // Indicates whether a cut as occured for - // the current part - boolean bCoincidentNotAdded = false; // Indicates whether the - // current coincident - // multipath has been added - // to cutPairs - boolean bCurrentMultiPathNotAdded = true; // Indicates whether there - // is a multipath not - // yet added to cutPairs - // (left, right, or - // undefined) - boolean bStartNewPath = true; - boolean bCreateNewMultiPath = true; - int segmentCount = 0; - - ipartCutteePrev = ipath; - scalarCutteePrev = 0.0; - - for (int ivertex = shape.getFirstVertex(ipath), n = shape - .getPathSize(ipath), i = 0; i < n; ivertex = shape - .getNextVertex(ivertex), i++) { - segmentCuttee = shape.getSegment(ivertex); - if (segmentCuttee == null) { - if (!shape.queryLineConnector(ivertex, lineCuttee)) - continue; - segmentCuttee = lineCuttee; - } - - if (ivertexCutteePrev == -1) - ivertexCutteePrev = ivertex; - - double lastScalarCuttee = 0.0; // last scalar along the current - // segment - - while (icutEvent < cutEvents.size() - && ivertex == cutEvents.get(icutEvent).m_ivertexCuttee) { - ipartCuttee = cutEvents.get(icutEvent).m_ipartCuttee; - ivertexCuttee = cutEvents.get(icutEvent).m_ivertexCuttee; - scalarCuttee = cutEvents.get(icutEvent).m_scalarCuttee0; - ipartCutter = cutEvents.get(icutEvent).m_ipartCutter; - ivertexCutter = cutEvents.get(icutEvent).m_ivertexCutter; - scalarCutter = cutEvents.get(icutEvent).m_scalarCutter0; - - if (cutEvents.get(icutEvent).m_count == 2) { - // We have an overlap - - if (!bCoincidentNotAdded) { - ipartCutteePrev = ipartCuttee; - ivertexCutteePrev = ivertexCuttee; - scalarCutteePrev = scalarCuttee; - ipartCutterPrev = ipartCutter; - ivertexCutterPrev = ivertexCutter; - scalarCutterPrev = scalarCutter; - cutPrev = OperatorCutLocal.Side.Coincident; - - // Create new multipath - if (cutPairs != null) - multipath = new Polyline(); - else - segmentCount = 0; - - bCreateNewMultiPath = false; - bStartNewPath = true; - } - - scalarCuttee = cutEvents.get(icutEvent).m_scalarCuttee1; - scalarCutter = cutEvents.get(icutEvent).m_scalarCutter1; - - if (cutPairs != null) { - segmentCuttee.cut(lastScalarCuttee, - cutEvents.get(icutEvent).m_scalarCuttee1, - segmentBufferCuttee); - multipath.addSegment(segmentBufferCuttee.get(), - bStartNewPath); - } else - segmentCount++; - - lastScalarCuttee = scalarCuttee; - - bCoincidentNotAdded = true; - bNoCutYet = false; - bStartNewPath = false; - - if (icutEvent + 1 == cutEvents.size() - || cutEvents.get(icutEvent + 1).m_count != 2 - || cutEvents.get(icutEvent + 1).m_ivertexCuttee == ivertexCuttee - && cutEvents.get(icutEvent + 1).m_scalarCuttee0 != lastScalarCuttee) { - if (cutPairs != null) { - cutPair = new OperatorCutLocal.CutPair( - (Geometry) multipath, - OperatorCutLocal.Side.Coincident, - ipartCuttee, ivertexCuttee, - scalarCuttee, cutPrev, ipartCutteePrev, - ivertexCutteePrev, scalarCutteePrev, - ipartCutter, ivertexCutter, - scalarCutter, ipartCutterPrev, - ivertexCutterPrev, scalarCutterPrev); - cutPairs.add(cutPair); - } else { - segmentCounts.add(segmentCount); - } - - ipartCutteePrev = ipartCuttee; - ivertexCutteePrev = ivertexCuttee; - scalarCutteePrev = scalarCuttee; - ipartCutterPrev = ipartCutter; - ivertexCutterPrev = ivertexCutter; - scalarCutterPrev = scalarCutter; - cutPrev = OperatorCutLocal.Side.Coincident; - - bNoCutYet = false; - bCoincidentNotAdded = false; - bCreateNewMultiPath = true; - bStartNewPath = true; - } - - icutEvent++; - continue; - } - - int ivertexCutteePlus = shape.getNextVertex(ivertexCuttee); - int ivertexCutterPlus = shape.getNextVertex(ivertexCutter); - int ivertexCutterMinus = shape.getPrevVertex(ivertexCutter); - - if (icutEvent < cutEvents.size() - 1 - && cutEvents.get(icutEvent + 1).m_ivertexCuttee == ivertexCutteePlus - && cutEvents.get(icutEvent + 1).m_ivertexCutter == ivertexCutter - && cutEvents.get(icutEvent + 1).m_count == 2) { - if (scalarCuttee != lastScalarCuttee) { - if (bCreateNewMultiPath) { - if (cutPairs != null) - multipath = new Polyline(); - else - segmentCount = 0; - } - - if (icutEvent > 0 - && cutEvents.get(icutEvent - 1).m_ipartCuttee == ipartCuttee) { - if (cutPrev == OperatorCutLocal.Side.Right) - cut = OperatorCutLocal.Side.Left; - else if (cutPrev == OperatorCutLocal.Side.Left) - cut = OperatorCutLocal.Side.Right; - else - cut = OperatorCutLocal.Side.Undefined; - } else - cut = OperatorCutLocal.Side.Undefined; - - if (cutPairs != null) { - segmentCuttee.cut(lastScalarCuttee, - scalarCuttee, segmentBufferCuttee); - multipath.addSegment(segmentBufferCuttee.get(), - bStartNewPath); - cutPair = new OperatorCutLocal.CutPair( - multipath, cut, ipartCuttee, - ivertexCuttee, scalarCuttee, cutPrev, - ipartCutteePrev, ivertexCutteePrev, - scalarCutteePrev, ipartCutter, - ivertexCutter, scalarCutter, - ipartCutterPrev, ivertexCutterPrev, - scalarCutterPrev); - cutPairs.add(cutPair); - } else { - segmentCount++; - segmentCounts.add(segmentCount); - } - - lastScalarCuttee = scalarCuttee; - - ipartCutteePrev = ipartCuttee; - ivertexCutteePrev = ivertexCuttee; - scalarCutteePrev = scalarCuttee; - ipartCutterPrev = ipartCutter; - ivertexCutterPrev = ivertexCutter; - scalarCutterPrev = scalarCutter; - cutPrev = cut; - - bCurrentMultiPathNotAdded = false; - bNoCutYet = false; - bCreateNewMultiPath = true; - bStartNewPath = true; - } - - icutEvent++; - continue; - } - - boolean bContinue = _cutterTangents(bConsiderTouch, shape, - cutEvents, icutEvent, tangent0, tangent1); - if (bContinue) { - icutEvent++; - continue; - } - - _cutteeTangents(shape, cutEvents, icutEvent, ipath, - ivertex, tangent2, tangent3); - - boolean bCut = false; - boolean bTouch = false; - boolean bCutRight = true; - - if (!tangent0.isEqual(tangent2) - && !tangent1.isEqual(tangent2) - && !tangent0.isEqual(tangent3) - && !tangent1.isEqual(tangent3)) { - tangents[0].setCoords(tangent0); - tangents[1].setCoords(tangent1); - tangents[2].setCoords(tangent2); - tangents[3].setCoords(tangent3); - - Arrays.sort(tangents, new Point2D.CompareVectors()); - // SORTARRAY(tangents, Point2D, - // Point2D::_CompareVectors); - - Point2D value0 = (Point2D) tangents[0]; - Point2D value1 = (Point2D) tangents[1]; - Point2D value2 = (Point2D) tangents[2]; - Point2D value3 = (Point2D) tangents[3]; - - if (value0.isEqual(tangent0)) { - if (value1.isEqual(tangent1)) { - if (!bConsiderTouch) - bCut = false; - else { - bCut = true; - bTouch = true; - bCutRight = false; - } - } else if (value3.isEqual(tangent1)) { - if (!bConsiderTouch) - bCut = false; - else { - bCut = true; - bTouch = true; - bCutRight = true; - } - } else { - bCut = true; - bCutRight = value1.isEqual(tangent2); - } - } else if (value1.isEqual(tangent0)) { - if (value2.isEqual(tangent1)) { - if (!bConsiderTouch) - bCut = false; - else { - bCut = true; - bTouch = true; - bCutRight = false; - } - } else if (value0.isEqual(tangent1)) { - if (!bConsiderTouch) - bCut = false; - else { - bCut = true; - bTouch = true; - bCutRight = true; - } - } else { - bCut = true; - bCutRight = value2.isEqual(tangent2); - } - } else if (value2.isEqual(tangent0)) { - if (value3.isEqual(tangent1)) { - if (!bConsiderTouch) - bCut = false; - else { - bCut = true; - bTouch = true; - bCutRight = false; - } - } else if (value1.isEqual(tangent1)) { - if (!bConsiderTouch) - bCut = false; - else { - bCut = true; - bTouch = true; - bCutRight = true; - } - } else { - bCut = true; - bCutRight = value3.isEqual(tangent2); - } - } else { - if (value0.isEqual(tangent1)) { - if (!bConsiderTouch) - bCut = false; - else { - bCut = true; - bTouch = true; - bCutRight = false; - } - } else if (value2.isEqual(tangent1)) { - if (!bConsiderTouch) - bCut = false; - else { - bCut = true; - bTouch = true; - bCutRight = true; - } - } else { - bCut = true; - bCutRight = value0.isEqual(tangent2); - } - } - } - - if (bCut) { - boolean bIsFirstSegmentInPath = (ivertex == ivertexCuttee); - - if (scalarCuttee != lastScalarCuttee - || bIsFirstSegmentInPath - && lastScalarCuttee == 0.0) { - if (bCreateNewMultiPath) { - if (cutPairs != null) - multipath = new Polyline(); - else - segmentCount = 0; - } - - if (cutPairs != null) { - segmentCuttee.cut(lastScalarCuttee, - scalarCuttee, segmentBufferCuttee); - multipath.addSegment(segmentBufferCuttee.get(), - bStartNewPath); - } else - segmentCount++; - } - - if (bCutRight) { - if (cutPrev != OperatorCutLocal.Side.Right - || bLocalCutsOnly) { - if (scalarCuttee != lastScalarCuttee - || bIsFirstSegmentInPath - && lastScalarCuttee == 0.0 - || bLocalCutsOnly) { - if (cutPairs != null) { - cutPair = new OperatorCutLocal.CutPair( - multipath, - OperatorCutLocal.Side.Right, - ipartCuttee, ivertexCuttee, - scalarCuttee, cutPrev, - ipartCutteePrev, - ivertexCutteePrev, - scalarCutteePrev, ipartCutter, - ivertexCutter, scalarCutter, - ipartCutterPrev, - ivertexCutterPrev, - scalarCutterPrev); - cutPairs.add(cutPair); - } else { - segmentCounts.add(segmentCount); - } - } - - if (!bTouch) - cutPrev = OperatorCutLocal.Side.Right; - else if (icutEvent == cutEvents.size() - 2 - || cutEvents.get(icutEvent + 2).m_ipartCuttee != ipartCuttee) - cutPrev = OperatorCutLocal.Side.Left; - } else { - if (scalarCuttee != lastScalarCuttee - || bIsFirstSegmentInPath - && lastScalarCuttee == 0.0 - || bLocalCutsOnly) { - if (cutPairs != null) { - cutPair = new OperatorCutLocal.CutPair( - multipath, - OperatorCutLocal.Side.Undefined, - ipartCuttee, ivertexCuttee, - scalarCuttee, cutPrev, - ipartCutteePrev, - ivertexCutteePrev, - scalarCutteePrev, ipartCutter, - ivertexCutter, scalarCutter, - ipartCutterPrev, - ivertexCutterPrev, - scalarCutterPrev); - cutPairs.add(cutPair); - } else { - segmentCounts.add(segmentCount); - } - } - - cutPrev = OperatorCutLocal.Side.Right; - } - } else { - if (cutPrev != OperatorCutLocal.Side.Left - || bLocalCutsOnly) { - if (scalarCuttee != lastScalarCuttee - || bIsFirstSegmentInPath - && lastScalarCuttee == 0.0 - || bLocalCutsOnly) { - if (cutPairs != null) { - cutPair = new OperatorCutLocal.CutPair( - multipath, - OperatorCutLocal.Side.Left, - ipartCuttee, ivertexCuttee, - scalarCuttee, cutPrev, - ipartCutteePrev, - ivertexCutteePrev, - scalarCutteePrev, ipartCutter, - ivertexCutter, scalarCutter, - ipartCutterPrev, - ivertexCutterPrev, - scalarCutterPrev); - cutPairs.add(cutPair); - } else { - segmentCounts.add(segmentCount); - } - } - - if (!bTouch) - cutPrev = OperatorCutLocal.Side.Left; - else if (icutEvent == cutEvents.size() - 2 - || cutEvents.get(icutEvent + 2).m_ipartCuttee != ipartCuttee) - cutPrev = OperatorCutLocal.Side.Right; - } else { - if (scalarCuttee != lastScalarCuttee - || bIsFirstSegmentInPath - && lastScalarCuttee == 0.0 - || bLocalCutsOnly) { - if (cutPairs != null) { - cutPair = new OperatorCutLocal.CutPair( - multipath, - OperatorCutLocal.Side.Undefined, - ipartCuttee, ivertexCuttee, - scalarCuttee, cutPrev, - ipartCutteePrev, - ivertexCutteePrev, - scalarCutteePrev, ipartCutter, - ivertexCutter, scalarCutter, - ipartCutterPrev, - ivertexCutterPrev, - scalarCutterPrev); - cutPairs.add(cutPair); - } else { - segmentCounts.add(segmentCount); - } - } - - cutPrev = OperatorCutLocal.Side.Left; - } - } - - if (scalarCuttee != lastScalarCuttee - || bIsFirstSegmentInPath - && lastScalarCuttee == 0.0 || bLocalCutsOnly) { - lastScalarCuttee = scalarCuttee; - - ipartCutteePrev = ipartCuttee; - ivertexCutteePrev = ivertexCuttee; - scalarCutteePrev = scalarCuttee; - ipartCutterPrev = ipartCutter; - ivertexCutterPrev = ivertexCutter; - scalarCutterPrev = scalarCutter; - - bCurrentMultiPathNotAdded = false; - bNoCutYet = false; - bCreateNewMultiPath = true; - bStartNewPath = true; - } - } - - icutEvent++; - } - - if (lastScalarCuttee != 1.0) { - if (bCreateNewMultiPath) { - if (cutPairs != null) - multipath = new Polyline(); - else - segmentCount = 0; - } - - if (cutPairs != null) { - segmentCuttee.cut(lastScalarCuttee, 1.0, - segmentBufferCuttee); - multipath.addSegment(segmentBufferCuttee.get(), - bStartNewPath); - } else - segmentCount++; - - bCreateNewMultiPath = false; - bStartNewPath = false; - bCurrentMultiPathNotAdded = true; - } - } - - if (bCurrentMultiPathNotAdded) { - scalarCuttee = 1.0; - ivertexCuttee = shape.getLastVertex(ipath); - ivertexCuttee = shape.getPrevVertex(ivertexCuttee); - - ipartCutter = -1; - ivertexCutter = -1; - scalarCutter = NumberUtils.NaN(); - - if (bNoCutYet) { - if (cutPairs != null) { - cutPair = new OperatorCutLocal.CutPair(multipath, - OperatorCutLocal.Side.Uncut, ipartCuttee, - ivertexCuttee, scalarCuttee, cutPrev, - ipartCutteePrev, ivertexCutteePrev, - scalarCutteePrev, ipartCutter, ivertexCutter, - scalarCutter, ipartCutterPrev, - ivertexCutterPrev, scalarCutterPrev); - cutPairs.add(cutPair); - } else { - segmentCounts.add(segmentCount); - } - } else { - if (cutPrev == OperatorCutLocal.Side.Right) - cut = OperatorCutLocal.Side.Left; - else if (cutPrev == OperatorCutLocal.Side.Left) - cut = OperatorCutLocal.Side.Right; - else - cut = OperatorCutLocal.Side.Undefined; - - if (cutPairs != null) { - cutPair = new OperatorCutLocal.CutPair(multipath, cut, - ipartCuttee, ivertexCuttee, scalarCuttee, - cutPrev, ipartCutteePrev, ivertexCutteePrev, - scalarCutteePrev, ipartCutter, ivertexCutter, - scalarCutter, ipartCutterPrev, - ivertexCutterPrev, scalarCutterPrev); - cutPairs.add(cutPair); - } else { - segmentCounts.add(segmentCount); - } - } - } - } - } - - static boolean _cutterTangents(boolean bConsiderTouch, EditShape shape, - ArrayList cutEvents, int icutEvent, Point2D tangent0, - Point2D tangent1) { - double scalarCutter = cutEvents.get(icutEvent).m_scalarCutter0; - - if (scalarCutter == 1.0) - return _cutterEndTangents(bConsiderTouch, shape, cutEvents, - icutEvent, tangent0, tangent1); - - if (scalarCutter == 0.0) - return _cutterStartTangents(bConsiderTouch, shape, cutEvents, - icutEvent, tangent0, tangent1); - - throw GeometryException.GeometryInternalError(); - } - - static boolean _cutterEndTangents(boolean bConsiderTouch, EditShape shape, - ArrayList cutEvents, int icutEvent, Point2D tangent0, - Point2D tangent1) { - Line lineCutter = new Line(); - Segment segmentCutter; - - int ivertexCuttee = cutEvents.get(icutEvent).m_ivertexCuttee; - int ipartCutter = cutEvents.get(icutEvent).m_ipartCutter; - int ivertexCutter = cutEvents.get(icutEvent).m_ivertexCutter; - - int ivertexCutteePrev = -1; - int ipartCutterPrev = -1; - int ivertexCutterPrev = -1; - int countPrev = -1; - - if (!bConsiderTouch && icutEvent > 0) { - CutEvent cutEvent = cutEvents.get(icutEvent - 1); - ivertexCutteePrev = cutEvent.m_ivertexCuttee; - ipartCutterPrev = cutEvent.m_ipartCutter; - ivertexCutterPrev = cutEvent.m_ivertexCutter; - countPrev = cutEvent.m_count; - } - - int ivertexCutteeNext = -1; - int ipartCutterNext = -1; - int ivertexCutterNext = -1; - int countNext = -1; - - if (icutEvent < cutEvents.size() - 1) { - CutEvent cutEvent = cutEvents.get(icutEvent + 1); - ivertexCutteeNext = cutEvent.m_ivertexCuttee; - ipartCutterNext = cutEvent.m_ipartCutter; - ivertexCutterNext = cutEvent.m_ivertexCutter; - countNext = cutEvent.m_count; - } - - int ivertexCutteePlus = shape.getNextVertex(ivertexCuttee); - int ivertexCutterPlus = shape.getNextVertex(ivertexCutter); - - if (!bConsiderTouch) { - if ((icutEvent > 0 && ivertexCutteePrev == ivertexCuttee - && ipartCutterPrev == ipartCutter - && ivertexCutterPrev == ivertexCutterPlus && countPrev == 2) - || (icutEvent < cutEvents.size() - 1 - && ivertexCutteeNext == ivertexCutteePlus - && ipartCutterNext == ipartCutter - && ivertexCutterNext == ivertexCutterPlus && countNext == 2)) { - segmentCutter = shape.getSegment(ivertexCutter); - if (segmentCutter == null) { - shape.queryLineConnector(ivertexCutter, lineCutter); - segmentCutter = lineCutter; - } - - tangent1.setCoords(segmentCutter._getTangent(1.0)); - tangent0.negate(tangent1); - tangent1.normalize(); - tangent0.normalize(); - - return false; - } - - if (icutEvent < cutEvents.size() - 1 - && ivertexCutteeNext == ivertexCuttee - && ipartCutterNext == ipartCutter - && ivertexCutterNext == ivertexCutterPlus) { - segmentCutter = shape.getSegment(ivertexCutter); - if (segmentCutter == null) { - shape.queryLineConnector(ivertexCutter, lineCutter); - segmentCutter = lineCutter; - } - - tangent0.setCoords(segmentCutter._getTangent(1.0)); - - segmentCutter = shape.getSegment(ivertexCutterPlus); - if (segmentCutter == null) { - shape.queryLineConnector(ivertexCutterPlus, lineCutter); - segmentCutter = lineCutter; - } - - tangent1.setCoords(segmentCutter._getTangent(0.0)); - tangent0.negate(); - tangent1.normalize(); - tangent0.normalize(); - - return false; - } - - return true; - } - - if (icutEvent == cutEvents.size() - 1 - || ivertexCutteeNext != ivertexCuttee - || ipartCutterNext != ipartCutter - || ivertexCutterNext != ivertexCutterPlus || countNext == 2) { - segmentCutter = shape.getSegment(ivertexCutter); - if (segmentCutter == null) { - shape.queryLineConnector(ivertexCutter, lineCutter); - segmentCutter = lineCutter; - } - - tangent1.setCoords(segmentCutter._getTangent(1.0)); - tangent0.negate(tangent1); - tangent1.normalize(); - tangent0.normalize(); - - return false; - } - - segmentCutter = shape.getSegment(ivertexCutter); - if (segmentCutter == null) { - shape.queryLineConnector(ivertexCutter, lineCutter); - segmentCutter = lineCutter; - } - - tangent0.setCoords(segmentCutter._getTangent(1.0)); - - segmentCutter = shape.getSegment(ivertexCutterPlus); - if (segmentCutter == null) { - shape.queryLineConnector(ivertexCutterPlus, lineCutter); - segmentCutter = lineCutter; - } - - tangent1.setCoords(segmentCutter._getTangent(0.0)); - tangent0.negate(); - tangent1.normalize(); - tangent0.normalize(); - - return false; - } - - static boolean _cutterStartTangents(boolean bConsiderTouch, - EditShape shape, ArrayList cutEvents, int icutEvent, - Point2D tangent0, Point2D tangent1) { - Line lineCutter = new Line(); - Segment segmentCutter; - - int ivertexCuttee = cutEvents.get(icutEvent).m_ivertexCuttee; - int ipartCutter = cutEvents.get(icutEvent).m_ipartCutter; - int ivertexCutter = cutEvents.get(icutEvent).m_ivertexCutter; - - int ivertexCutteeNext = -1; - int ipartCutterNext = -1; - int ivertexCutterNext = -1; - int countNext = -1; - - if (!bConsiderTouch && icutEvent < cutEvents.size() - 1) { - CutEvent cutEvent = cutEvents.get(icutEvent + 1); - ivertexCutteeNext = cutEvent.m_ivertexCuttee; - ipartCutterNext = cutEvent.m_ipartCutter; - ivertexCutterNext = cutEvent.m_ivertexCutter; - countNext = cutEvent.m_count; - } - - int ivertexCutteePrev = -1; - int ipartCutterPrev = -1; - int ivertexCutterPrev = -1; - int countPrev = -1; - - if (icutEvent > 0) { - CutEvent cutEvent = cutEvents.get(icutEvent - 1); - ivertexCutteePrev = cutEvent.m_ivertexCuttee; - ipartCutterPrev = cutEvent.m_ipartCutter; - ivertexCutterPrev = cutEvent.m_ivertexCutter; - countPrev = cutEvent.m_count; - } - - int ivertexCutteePlus = shape.getNextVertex(ivertexCuttee); - int ivertexCutterMinus = shape.getPrevVertex(ivertexCutter); - - if (!bConsiderTouch) { - if ((icutEvent > 0 && ivertexCutteePrev == ivertexCuttee - && ipartCutterPrev == ipartCutter - && ivertexCutterPrev == ivertexCutterMinus && countPrev == 2) - || (icutEvent < cutEvents.size() - 1 - && ivertexCutteeNext == ivertexCutteePlus - && ipartCutterNext == ipartCutter - && ivertexCutterNext == ivertexCutterMinus && countNext == 2)) { - segmentCutter = shape.getSegment(ivertexCutter); - if (segmentCutter == null) { - shape.queryLineConnector(ivertexCutter, lineCutter); - segmentCutter = lineCutter; - } - - tangent1.setCoords(segmentCutter._getTangent(0.0)); - tangent0.negate(tangent1); - tangent1.normalize(); - tangent0.normalize(); - - return false; - } - - return true; - } - - if (icutEvent == 0 || ivertexCutteePrev != ivertexCuttee - || ipartCutterPrev != ipartCutter - || ivertexCutterPrev != ivertexCutterMinus || countPrev == 2) { - segmentCutter = shape.getSegment(ivertexCutter); - if (segmentCutter == null) { - shape.queryLineConnector(ivertexCutter, lineCutter); - segmentCutter = lineCutter; - } - - tangent1.setCoords(segmentCutter._getTangent(0.0)); - tangent0.negate(tangent1); - tangent1.normalize(); - tangent0.normalize(); - - return false; - } - - // Already processed the event - - return true; - } - - static boolean _cutteeTangents(EditShape shape, - ArrayList cutEvents, int icutEvent, int ipath, - int ivertex, Point2D tangent2, Point2D tangent3) { - Line lineCuttee = new Line(); - Segment segmentCuttee = shape.getSegment(ivertex); - if (segmentCuttee == null) { - shape.queryLineConnector(ivertex, lineCuttee); - segmentCuttee = lineCuttee; - } - - CutEvent cutEvent = cutEvents.get(icutEvent); - int ivertexCuttee = cutEvent.m_ivertexCuttee; - double scalarCuttee = cutEvent.m_scalarCuttee0; - - int ivertexCutteePlus = shape.getNextVertex(ivertexCuttee); - - if (scalarCuttee == 1.0) { - tangent2.setCoords(segmentCuttee._getTangent(1.0)); - - if (ivertexCutteePlus != -1 - && ivertexCutteePlus != shape.getLastVertex(ipath)) { - segmentCuttee = shape.getSegment(ivertexCutteePlus); - if (segmentCuttee == null) { - shape.queryLineConnector(ivertexCutteePlus, lineCuttee); - segmentCuttee = lineCuttee; - } - - tangent3.setCoords(segmentCuttee._getTangent(0.0)); - - segmentCuttee = shape.getSegment(ivertexCuttee); - if (segmentCuttee == null) { - shape.queryLineConnector(ivertexCuttee, lineCuttee); - segmentCuttee = lineCuttee; - } - } else - tangent3.setCoords(tangent2); - - tangent2.negate(); - - tangent3.normalize(); - tangent2.normalize(); - - return false; - } - - if (scalarCuttee == 0.0) { - tangent3.setCoords(segmentCuttee._getTangent(scalarCuttee)); - tangent2.negate(tangent3); - tangent3.normalize(); - tangent2.normalize(); - - return false; - } - - throw GeometryException.GeometryInternalError(); - } + static class CompareVertices { + int m_orderIndex; + EditShape m_editShape; + + CompareVertices(int orderIndex, EditShape editShape) { + m_orderIndex = orderIndex; + m_editShape = editShape; + } + + int _compareVertices(int v1, int v2) { + Point2D pt1 = new Point2D(); + m_editShape.getXY(v1, pt1); + Point2D pt2 = new Point2D(); + m_editShape.getXY(v2, pt2); + int res = pt1.compare(pt2); + if (res != 0) + return res; + int z1 = m_editShape.getUserIndex(v1, m_orderIndex); + int z2 = m_editShape.getUserIndex(v2, m_orderIndex); + if (z1 < z2) + return -1; + if (z1 == z2) + return 0; + return 1; + } + } + + static class CutterVertexComparer extends + AttributeStreamOfInt32.IntComparator { + CompareVertices m_compareVertices; + + CutterVertexComparer(CompareVertices _compareVertices) { + m_compareVertices = _compareVertices; + } + + @Override + public int compare(int v1, int v2) { + return m_compareVertices._compareVertices(v1, v2); + } + } + + static class CutEvent { + int m_ivertexCuttee; + int m_ipartCuttee; + double m_scalarCuttee0; + double m_scalarCuttee1; + int m_count; + int m_ivertexCutter; + int m_ipartCutter; + double m_scalarCutter0; + double m_scalarCutter1; + + CutEvent(int ivertexCuttee, int ipartCuttee, double scalarCuttee0, + double scalarCuttee1, int count, int ivertexCutter, + int ipartCutter, double scalarCutter0, double scalarCutter1) { + m_ivertexCuttee = ivertexCuttee; + m_ipartCuttee = ipartCuttee; + m_scalarCuttee0 = scalarCuttee0; + m_scalarCuttee1 = scalarCuttee1; + m_count = count; + m_ivertexCutter = ivertexCutter; + m_ipartCutter = ipartCutter; + m_scalarCutter0 = scalarCutter0; + m_scalarCutter1 = scalarCutter1; + } + } + + static EditShape CutPolyline(boolean bConsiderTouch, Polyline cuttee, + Polyline cutter, double tolerance, + ArrayList cutPairs, + AttributeStreamOfInt32 segmentCounts, ProgressTracker progressTracker) { + if (cuttee.isEmpty()) { + OperatorCutLocal.CutPair cutPair; + cutPair = new OperatorCutLocal.CutPair(cuttee, + OperatorCutLocal.Side.Uncut, -1, -1, NumberUtils.NaN(), + OperatorCutLocal.Side.Uncut, -1, -1, NumberUtils.NaN(), -1, + -1, NumberUtils.NaN(), -1, -1, NumberUtils.NaN()); + cutPairs.add(cutPair); + return null; + } + + EditShape editShape = new EditShape(); + int cutteeHandle = editShape.addGeometry(cuttee); + int cutterHandle = editShape.addGeometry(cutter); + CrackAndCluster.execute(editShape, tolerance, progressTracker, true); + + int order = 0; + int orderIndex = editShape.createUserIndex(); + for (int igeometry = editShape.getFirstGeometry(); igeometry != -1; igeometry = editShape + .getNextGeometry(igeometry)) + for (int ipath = editShape.getFirstPath(igeometry); ipath != -1; ipath = editShape + .getNextPath(ipath)) + for (int ivertex = editShape.getFirstVertex(ipath), i = 0, n = editShape + .getPathSize(ipath); i < n; ivertex = editShape + .getNextVertex(ivertex), i++) + editShape.setUserIndex(ivertex, orderIndex, order++); + + ArrayList cutEvents = _getCutEvents(orderIndex, editShape); + _Cut(bConsiderTouch, false, cutEvents, editShape, cutPairs, + segmentCounts); + return editShape; + } + + private static ArrayList _getCutEvents(int orderIndex, + EditShape editShape) { + int pointCount = editShape.getTotalPointCount(); + + // Sort vertices lexicographically + // Firstly copy allvertices to an array. + AttributeStreamOfInt32 vertices = new AttributeStreamOfInt32(0); + + for (int igeometry = editShape.getFirstGeometry(); igeometry != -1; igeometry = editShape + .getNextGeometry(igeometry)) + for (int ipath = editShape.getFirstPath(igeometry); ipath != -1; ipath = editShape + .getNextPath(ipath)) + for (int ivertex = editShape.getFirstVertex(ipath), i = 0, n = editShape + .getPathSize(ipath); i < n; ivertex = editShape + .getNextVertex(ivertex), i++) + vertices.add(ivertex); + + // Sort + CompareVertices compareVertices = new CompareVertices(orderIndex, + editShape); + vertices.Sort(0, pointCount, new CutterVertexComparer(compareVertices)); + // SORTDYNAMICARRAYEX(vertices, index_type, 0, pointCount, + // CutterVertexComparer, compareVertices); + + // Find Cut Events + ArrayList cutEvents = new ArrayList(0); + ArrayList cutEventsTemp = new ArrayList(0); + + int eventIndex = editShape.createUserIndex(); + int eventIndexTemp = editShape.createUserIndex(); + + int cutteeHandle = editShape.getFirstGeometry(); + int cutterHandle = editShape.getNextGeometry(cutteeHandle); + + Point2D pointCuttee = new Point2D(); + Point2D pointCutter = new Point2D(); + + int ivertexCuttee = vertices.get(0); + ; + int ipartCuttee = editShape.getPathFromVertex(ivertexCuttee); + int igeometryCuttee = editShape.getGeometryFromPath(ipartCuttee); + editShape.getXY(ivertexCuttee, pointCuttee); + + int istart = 1; + int ivertex = 0; + while (istart < pointCount - 1) { + boolean bCutEvent = false; + for (int i = istart; i < pointCount; i++) { + if (i == ivertex) + continue; + + int ivertexCutter = vertices.get(i); + int ipartCutter = editShape.getPathFromVertex(ivertexCutter); + int igeometryCutter = editShape + .getGeometryFromPath(ipartCutter); + editShape.getXY(ivertexCutter, pointCutter); + + if (pointCuttee.isEqual(pointCutter)) { + boolean bCondition = igeometryCuttee == cutteeHandle + && igeometryCutter == cutterHandle; + + if (bCondition) + bCutEvent = _cutteeCutterEvents(eventIndex, + eventIndexTemp, editShape, cutEvents, + cutEventsTemp, ipartCuttee, ivertexCuttee, + ipartCutter, ivertexCutter); + } else + break; + } + + if (bCutEvent || ivertex == istart - 1) { + if (bCutEvent && (ivertex == istart - 1)) + istart--; + + if (++ivertex == pointCount) + break; + + ivertexCuttee = vertices.get(ivertex); + ipartCuttee = editShape.getPathFromVertex(ivertexCuttee); + igeometryCuttee = editShape.getGeometryFromPath(ipartCuttee); + editShape.getXY(ivertexCuttee, pointCuttee); + } + + if (!bCutEvent) + istart = ivertex + 1; + } + + ArrayList cutEventsSorted = new ArrayList(0); + + // Sort CutEvents + int icutEvent; + int icutEventTemp; + for (int igeometry = editShape.getFirstGeometry(); igeometry != -1; igeometry = editShape.getNextGeometry(igeometry)) { + for (int ipath = editShape.getFirstPath(igeometry); ipath != -1; ipath = editShape.getNextPath(ipath)) { + for (int iv = editShape.getFirstVertex(ipath), i = 0, n = editShape.getPathSize(ipath); i < n; iv = editShape.getNextVertex(iv), i++) { + icutEventTemp = editShape.getUserIndex(iv, eventIndexTemp); + if (icutEventTemp >= 0) { + // _ASSERT(cutEventsTemp.get(icutEventTemp).m_ivertexCuttee + // == iv); + while (icutEventTemp < cutEventsTemp.size() && cutEventsTemp.get(icutEventTemp).m_ivertexCuttee == iv) + cutEventsSorted.add(cutEventsTemp.get(icutEventTemp++)); + } + + icutEvent = editShape.getUserIndex(iv, eventIndex); + if (icutEvent >= 0) { + // _ASSERT(cutEvents->Get(icutEvent)->m_ivertexCuttee == + // iv); + while (icutEvent < cutEvents.size() && cutEvents.get(icutEvent).m_ivertexCuttee == iv) + cutEventsSorted.add(cutEvents.get(icutEvent++)); + } + } + } + } + + // _ASSERT(cutEvents->Size() + cutEventsTemp->Size() == + // cutEventsSorted->Size()); + editShape.removeUserIndex(eventIndex); + editShape.removeUserIndex(eventIndexTemp); + return cutEventsSorted; + } + + static boolean _cutteeCutterEvents(int eventIndex, int eventIndexTemp, + EditShape editShape, ArrayList cutEvents, + ArrayList cutEventsTemp, int ipartCuttee, + int ivertexCuttee, int ipartCutter, int ivertexCutter) { + int ilastVertexCuttee = editShape.getLastVertex(ipartCuttee); + int ilastVertexCutter = editShape.getLastVertex(ipartCutter); + int ifirstVertexCuttee = editShape.getFirstVertex(ipartCuttee); + int ifirstVertexCutter = editShape.getFirstVertex(ipartCutter); + int ivertexCutteePrev = editShape.getPrevVertex(ivertexCuttee); + int ivertexCutterPrev = editShape.getPrevVertex(ivertexCutter); + + boolean bEndEnd = false; + boolean bEndStart = false; + boolean bStartEnd = false; + boolean bStartStart = false; + + if (ivertexCuttee != ifirstVertexCuttee) { + if (ivertexCutter != ifirstVertexCutter) + bEndEnd = _cutteeEndCutterEndEvent(eventIndex, editShape, + cutEvents, ipartCuttee, ivertexCutteePrev, ipartCutter, + ivertexCutterPrev); + + if (ivertexCutter != ilastVertexCutter) + bEndStart = _cutteeEndCutterStartEvent(eventIndex, editShape, + cutEvents, ipartCuttee, ivertexCutteePrev, ipartCutter, + ivertexCutter); + } + + if (ivertexCuttee != ilastVertexCuttee) { + if (ivertexCutter != ifirstVertexCutter) + bStartEnd = _cutteeStartCutterEndEvent(eventIndexTemp, + editShape, cutEventsTemp, ipartCuttee, ivertexCuttee, + ipartCutter, ivertexCutterPrev, ifirstVertexCuttee); + + if (ivertexCutter != ilastVertexCutter) + bStartStart = _cutteeStartCutterStartEvent(eventIndexTemp, + editShape, cutEventsTemp, ipartCuttee, ivertexCuttee, + ipartCutter, ivertexCutter, ifirstVertexCuttee); + } + + if (bEndEnd && bEndStart && bStartEnd) { + int iendstart = cutEvents.size() - 1; + int istartend = (bStartStart ? cutEventsTemp.size() - 2 + : cutEventsTemp.size() - 1); + + if (cutEventsTemp.get(istartend).m_count == 2) { + // Replace bEndEnd with bEndStart, and remove duplicate + // bEndStart (get rid of bEndEnd) + cutEvents.set(iendstart - 1, cutEvents.get(iendstart)); + cutEvents.remove(cutEvents.size() - 1); + } + } else if (bEndEnd && bEndStart && bStartStart) { + int istartstart = cutEventsTemp.size() - 1; + + if (cutEventsTemp.get(istartstart).m_count == 2) { + // Remove bEndStart + CutEvent lastEvent = cutEvents.get(cutEvents.size() - 1); + cutEvents.remove(cutEvents.get(cutEvents.size() - 1)); + int icutEvent = editShape.getUserIndex( + lastEvent.m_ivertexCuttee, eventIndex); + if (icutEvent == cutEvents.size()) + editShape.setUserIndex(lastEvent.m_ivertexCuttee, + eventIndex, -1); + } + } + + return bEndEnd || bEndStart || bStartEnd || bStartStart; + } + + private static boolean _cutteeEndCutterEndEvent(int eventIndex, + EditShape editShape, ArrayList cutEvents, + int ipartCuttee, int ivertexCuttee, int ipartCutter, + int ivertexCutter) { + Segment segmentCuttee; + Segment segmentCutter; + Line lineCuttee = new Line(); + Line lineCutter = new Line(); + double[] scalarsCuttee = new double[2]; + double[] scalarsCutter = new double[2]; + + CutEvent cutEvent; + + segmentCuttee = editShape.getSegment(ivertexCuttee); + if (segmentCuttee == null) { + editShape.queryLineConnector(ivertexCuttee, lineCuttee); + segmentCuttee = lineCuttee; + } + + segmentCutter = editShape.getSegment(ivertexCutter); + if (segmentCutter == null) { + editShape.queryLineConnector(ivertexCutter, lineCutter); + segmentCutter = lineCutter; + } + + int count = segmentCuttee.intersect(segmentCutter, null, scalarsCuttee, + scalarsCutter, 0.0); + // _ASSERT(count > 0); + int icutEvent; + + // If count == 2 (i.e. when they overlap), this this event would have + // been discovered by _CutteeStartCutterStartEvent at the previous index + if (count < 2) { + cutEvent = new CutEvent(ivertexCuttee, ipartCuttee, + scalarsCuttee[0], NumberUtils.NaN(), count, ivertexCutter, + ipartCutter, scalarsCutter[0], NumberUtils.NaN()); + cutEvents.add(cutEvent); + icutEvent = editShape.getUserIndex(ivertexCuttee, eventIndex); + + if (icutEvent < 0) + editShape.setUserIndex(ivertexCuttee, eventIndex, + cutEvents.size() - 1); + } + + return true; + } + + private static boolean _cutteeEndCutterStartEvent(int eventIndex, + EditShape editShape, ArrayList cutEvents, + int ipartCuttee, int ivertexCuttee, int ipartCutter, + int ivertexCutter) { + Segment segmentCuttee; + Segment segmentCutter; + Line lineCuttee = new Line(); + Line lineCutter = new Line(); + double[] scalarsCuttee = new double[2]; + double[] scalarsCutter = new double[2]; + + CutEvent cutEvent; + + segmentCuttee = editShape.getSegment(ivertexCuttee); + if (segmentCuttee == null) { + editShape.queryLineConnector(ivertexCuttee, lineCuttee); + segmentCuttee = lineCuttee; + } + + segmentCutter = editShape.getSegment(ivertexCutter); + if (segmentCutter == null) { + editShape.queryLineConnector(ivertexCutter, lineCutter); + segmentCutter = lineCutter; + } + + int count = segmentCuttee.intersect(segmentCutter, null, scalarsCuttee, + scalarsCutter, 0.0); + // _ASSERT(count > 0); + int icutEvent; + + // If count == 2 (i.e. when they overlap), this this event would have + // been discovered by _CutteeStartCutterEndEvent at the previous index + if (count < 2) { + cutEvent = new CutEvent(ivertexCuttee, ipartCuttee, + scalarsCuttee[0], NumberUtils.NaN(), count, ivertexCutter, + ipartCutter, scalarsCutter[0], NumberUtils.NaN()); + cutEvents.add(cutEvent); + icutEvent = editShape.getUserIndex(ivertexCuttee, eventIndex); + + if (icutEvent < 0) + editShape.setUserIndex(ivertexCuttee, eventIndex, + cutEvents.size() - 1); + + return true; + } + + return false; + } + + private static boolean _cutteeStartCutterEndEvent(int eventIndex, + EditShape editShape, ArrayList cutEvents, + int ipartCuttee, int ivertexCuttee, int ipartCutter, + int ivertexCutter, int ifirstVertexCuttee) { + Segment segmentCuttee; + Segment segmentCutter; + Line lineCuttee = new Line(); + Line lineCutter = new Line(); + double[] scalarsCuttee = new double[2]; + double[] scalarsCutter = new double[2]; + + CutEvent cutEvent; + + segmentCuttee = editShape.getSegment(ivertexCuttee); + if (segmentCuttee == null) { + editShape.queryLineConnector(ivertexCuttee, lineCuttee); + segmentCuttee = lineCuttee; + } + + segmentCutter = editShape.getSegment(ivertexCutter); + if (segmentCutter == null) { + editShape.queryLineConnector(ivertexCutter, lineCutter); + segmentCutter = lineCutter; + } + + int count = segmentCuttee.intersect(segmentCutter, null, scalarsCuttee, + scalarsCutter, 0.0); + // _ASSERT(count > 0); + int icutEvent; + + if (count == 2) { + cutEvent = new CutEvent(ivertexCuttee, ipartCuttee, + scalarsCuttee[0], scalarsCuttee[1], count, ivertexCutter, + ipartCutter, scalarsCutter[0], scalarsCutter[1]); + cutEvents.add(cutEvent); + icutEvent = editShape.getUserIndex(ivertexCuttee, eventIndex); + + if (icutEvent < 0) + editShape.setUserIndex(ivertexCuttee, eventIndex, + cutEvents.size() - 1); + + return true; + } else { + boolean bCutEvent = false; + + if (ivertexCuttee == ifirstVertexCuttee) { + cutEvent = new CutEvent(ivertexCuttee, ipartCuttee, + scalarsCuttee[0], NumberUtils.NaN(), count, + ivertexCutter, ipartCutter, scalarsCutter[0], + NumberUtils.NaN()); + cutEvents.add(cutEvent); + icutEvent = editShape.getUserIndex(ivertexCuttee, eventIndex); + + if (icutEvent < 0) + editShape.setUserIndex(ivertexCuttee, eventIndex, + cutEvents.size() - 1); + + bCutEvent = true; + } + + return bCutEvent; + } + + } + + private static boolean _cutteeStartCutterStartEvent(int eventIndex, + EditShape editShape, ArrayList cutEvents, + int ipartCuttee, int ivertexCuttee, int ipartCutter, + int ivertexCutter, int ifirstVertexCuttee) { + Segment segmentCuttee; + Segment segmentCutter; + Line lineCuttee = new Line(); + Line lineCutter = new Line(); + double[] scalarsCuttee = new double[2]; + double[] scalarsCutter = new double[2]; + + CutEvent cutEvent; + + segmentCuttee = editShape.getSegment(ivertexCuttee); + if (segmentCuttee == null) { + editShape.queryLineConnector(ivertexCuttee, lineCuttee); + segmentCuttee = lineCuttee; + } + + segmentCutter = editShape.getSegment(ivertexCutter); + if (segmentCutter == null) { + editShape.queryLineConnector(ivertexCutter, lineCutter); + segmentCutter = lineCutter; + } + + int count = segmentCuttee.intersect(segmentCutter, null, scalarsCuttee, + scalarsCutter, 0.0); + // _ASSERT(count > 0); + int icutEvent; + + if (count == 2) { + cutEvent = new CutEvent(ivertexCuttee, ipartCuttee, + scalarsCuttee[0], scalarsCuttee[1], count, ivertexCutter, + ipartCutter, scalarsCutter[0], scalarsCutter[1]); + cutEvents.add(cutEvent); + icutEvent = editShape.getUserIndex(ivertexCuttee, eventIndex); + + if (icutEvent < 0) + editShape.setUserIndex(ivertexCuttee, eventIndex, + cutEvents.size() - 1); + + return true; + } else { + boolean bCutEvent = false; + + if (ivertexCuttee == ifirstVertexCuttee) { + cutEvent = new CutEvent(ivertexCuttee, ipartCuttee, + scalarsCuttee[0], NumberUtils.NaN(), count, + ivertexCutter, ipartCutter, scalarsCutter[0], + NumberUtils.NaN()); + cutEvents.add(cutEvent); + icutEvent = editShape.getUserIndex(ivertexCuttee, eventIndex); + + if (icutEvent < 0) + editShape.setUserIndex(ivertexCuttee, eventIndex, + cutEvents.size() - 1); + + bCutEvent = true; + } + + return bCutEvent; + } + + } + + static void _Cut(boolean bConsiderTouch, boolean bLocalCutsOnly, + ArrayList cutEvents, EditShape shape, + ArrayList cutPairs, + AttributeStreamOfInt32 segmentCounts) { + OperatorCutLocal.CutPair cutPair; + + Point2D[] tangents = new Point2D[4]; + tangents[0] = new Point2D(); + tangents[1] = new Point2D(); + tangents[2] = new Point2D(); + tangents[3] = new Point2D(); + Point2D tangent0 = new Point2D(); + Point2D tangent1 = new Point2D(); + Point2D tangent2 = new Point2D(); + Point2D tangent3 = new Point2D(); + + SegmentBuffer segmentBufferCuttee = null; + if (cutPairs != null) { + segmentBufferCuttee = new SegmentBuffer(); + segmentBufferCuttee.createLine(); + } + + Segment segmentCuttee = null; + int icutEvent = 0; + MultiPath multipath = null; + + Line lineCuttee = new Line(); + Line lineCutter = new Line(); + + int polyline = shape.getFirstGeometry(); + for (int ipath = shape.getFirstPath(polyline); ipath != -1; ipath = shape + .getNextPath(ipath)) { + int cut; + int cutPrev = OperatorCutLocal.Side.Uncut; + int ipartCuttee = -1; + int ivertexCuttee = -1; + double scalarCuttee = NumberUtils.NaN(); + int ipartCutteePrev = -1; + int ivertexCutteePrev = -1; + double scalarCutteePrev = NumberUtils.NaN(); + int ipartCutter = -1; + int ivertexCutter = -1; + double scalarCutter = NumberUtils.NaN(); + int ipartCutterPrev = -1; + int ivertexCutterPrev = -1; + double scalarCutterPrev = NumberUtils.NaN(); + boolean bNoCutYet = true; // Indicates whether a cut as occured for + // the current part + boolean bCoincidentNotAdded = false; // Indicates whether the + // current coincident + // multipath has been added + // to cutPairs + boolean bCurrentMultiPathNotAdded = true; // Indicates whether there + // is a multipath not + // yet added to cutPairs + // (left, right, or + // undefined) + boolean bStartNewPath = true; + boolean bCreateNewMultiPath = true; + int segmentCount = 0; + + ipartCutteePrev = ipath; + scalarCutteePrev = 0.0; + + for (int ivertex = shape.getFirstVertex(ipath), n = shape + .getPathSize(ipath), i = 0; i < n; ivertex = shape + .getNextVertex(ivertex), i++) { + segmentCuttee = shape.getSegment(ivertex); + if (segmentCuttee == null) { + if (!shape.queryLineConnector(ivertex, lineCuttee)) + continue; + segmentCuttee = lineCuttee; + } + + if (ivertexCutteePrev == -1) + ivertexCutteePrev = ivertex; + + double lastScalarCuttee = 0.0; // last scalar along the current + // segment + + while (icutEvent < cutEvents.size() + && ivertex == cutEvents.get(icutEvent).m_ivertexCuttee) { + ipartCuttee = cutEvents.get(icutEvent).m_ipartCuttee; + ivertexCuttee = cutEvents.get(icutEvent).m_ivertexCuttee; + scalarCuttee = cutEvents.get(icutEvent).m_scalarCuttee0; + ipartCutter = cutEvents.get(icutEvent).m_ipartCutter; + ivertexCutter = cutEvents.get(icutEvent).m_ivertexCutter; + scalarCutter = cutEvents.get(icutEvent).m_scalarCutter0; + + if (cutEvents.get(icutEvent).m_count == 2) { + // We have an overlap + + if (!bCoincidentNotAdded) { + ipartCutteePrev = ipartCuttee; + ivertexCutteePrev = ivertexCuttee; + scalarCutteePrev = scalarCuttee; + ipartCutterPrev = ipartCutter; + ivertexCutterPrev = ivertexCutter; + scalarCutterPrev = scalarCutter; + cutPrev = OperatorCutLocal.Side.Coincident; + + // Create new multipath + if (cutPairs != null) + multipath = new Polyline(); + else + segmentCount = 0; + + bCreateNewMultiPath = false; + bStartNewPath = true; + } + + scalarCuttee = cutEvents.get(icutEvent).m_scalarCuttee1; + scalarCutter = cutEvents.get(icutEvent).m_scalarCutter1; + + if (cutPairs != null) { + segmentCuttee.cut(lastScalarCuttee, + cutEvents.get(icutEvent).m_scalarCuttee1, + segmentBufferCuttee); + multipath.addSegment(segmentBufferCuttee.get(), + bStartNewPath); + } else + segmentCount++; + + lastScalarCuttee = scalarCuttee; + + bCoincidentNotAdded = true; + bNoCutYet = false; + bStartNewPath = false; + + if (icutEvent + 1 == cutEvents.size() + || cutEvents.get(icutEvent + 1).m_count != 2 + || cutEvents.get(icutEvent + 1).m_ivertexCuttee == ivertexCuttee + && cutEvents.get(icutEvent + 1).m_scalarCuttee0 != lastScalarCuttee) { + if (cutPairs != null) { + cutPair = new OperatorCutLocal.CutPair( + (Geometry) multipath, + OperatorCutLocal.Side.Coincident, + ipartCuttee, ivertexCuttee, + scalarCuttee, cutPrev, ipartCutteePrev, + ivertexCutteePrev, scalarCutteePrev, + ipartCutter, ivertexCutter, + scalarCutter, ipartCutterPrev, + ivertexCutterPrev, scalarCutterPrev); + cutPairs.add(cutPair); + } else { + segmentCounts.add(segmentCount); + } + + ipartCutteePrev = ipartCuttee; + ivertexCutteePrev = ivertexCuttee; + scalarCutteePrev = scalarCuttee; + ipartCutterPrev = ipartCutter; + ivertexCutterPrev = ivertexCutter; + scalarCutterPrev = scalarCutter; + cutPrev = OperatorCutLocal.Side.Coincident; + + bNoCutYet = false; + bCoincidentNotAdded = false; + bCreateNewMultiPath = true; + bStartNewPath = true; + } + + icutEvent++; + continue; + } + + int ivertexCutteePlus = shape.getNextVertex(ivertexCuttee); + int ivertexCutterPlus = shape.getNextVertex(ivertexCutter); + int ivertexCutterMinus = shape.getPrevVertex(ivertexCutter); + + if (icutEvent < cutEvents.size() - 1 + && cutEvents.get(icutEvent + 1).m_ivertexCuttee == ivertexCutteePlus + && cutEvents.get(icutEvent + 1).m_ivertexCutter == ivertexCutter + && cutEvents.get(icutEvent + 1).m_count == 2) { + if (scalarCuttee != lastScalarCuttee) { + if (bCreateNewMultiPath) { + if (cutPairs != null) + multipath = new Polyline(); + else + segmentCount = 0; + } + + if (icutEvent > 0 + && cutEvents.get(icutEvent - 1).m_ipartCuttee == ipartCuttee) { + if (cutPrev == OperatorCutLocal.Side.Right) + cut = OperatorCutLocal.Side.Left; + else if (cutPrev == OperatorCutLocal.Side.Left) + cut = OperatorCutLocal.Side.Right; + else + cut = OperatorCutLocal.Side.Undefined; + } else + cut = OperatorCutLocal.Side.Undefined; + + if (cutPairs != null) { + segmentCuttee.cut(lastScalarCuttee, + scalarCuttee, segmentBufferCuttee); + multipath.addSegment(segmentBufferCuttee.get(), + bStartNewPath); + cutPair = new OperatorCutLocal.CutPair( + multipath, cut, ipartCuttee, + ivertexCuttee, scalarCuttee, cutPrev, + ipartCutteePrev, ivertexCutteePrev, + scalarCutteePrev, ipartCutter, + ivertexCutter, scalarCutter, + ipartCutterPrev, ivertexCutterPrev, + scalarCutterPrev); + cutPairs.add(cutPair); + } else { + segmentCount++; + segmentCounts.add(segmentCount); + } + + lastScalarCuttee = scalarCuttee; + + ipartCutteePrev = ipartCuttee; + ivertexCutteePrev = ivertexCuttee; + scalarCutteePrev = scalarCuttee; + ipartCutterPrev = ipartCutter; + ivertexCutterPrev = ivertexCutter; + scalarCutterPrev = scalarCutter; + cutPrev = cut; + + bCurrentMultiPathNotAdded = false; + bNoCutYet = false; + bCreateNewMultiPath = true; + bStartNewPath = true; + } + + icutEvent++; + continue; + } + + boolean bContinue = _cutterTangents(bConsiderTouch, shape, + cutEvents, icutEvent, tangent0, tangent1); + if (bContinue) { + icutEvent++; + continue; + } + + _cutteeTangents(shape, cutEvents, icutEvent, ipath, + ivertex, tangent2, tangent3); + + boolean bCut = false; + boolean bTouch = false; + boolean bCutRight = true; + + if (!tangent0.isEqual(tangent2) + && !tangent1.isEqual(tangent2) + && !tangent0.isEqual(tangent3) + && !tangent1.isEqual(tangent3)) { + tangents[0].setCoords(tangent0); + tangents[1].setCoords(tangent1); + tangents[2].setCoords(tangent2); + tangents[3].setCoords(tangent3); + + Arrays.sort(tangents, new Point2D.CompareVectors()); + // SORTARRAY(tangents, Point2D, + // Point2D::_CompareVectors); + + Point2D value0 = (Point2D) tangents[0]; + Point2D value1 = (Point2D) tangents[1]; + Point2D value2 = (Point2D) tangents[2]; + Point2D value3 = (Point2D) tangents[3]; + + if (value0.isEqual(tangent0)) { + if (value1.isEqual(tangent1)) { + if (!bConsiderTouch) + bCut = false; + else { + bCut = true; + bTouch = true; + bCutRight = false; + } + } else if (value3.isEqual(tangent1)) { + if (!bConsiderTouch) + bCut = false; + else { + bCut = true; + bTouch = true; + bCutRight = true; + } + } else { + bCut = true; + bCutRight = value1.isEqual(tangent2); + } + } else if (value1.isEqual(tangent0)) { + if (value2.isEqual(tangent1)) { + if (!bConsiderTouch) + bCut = false; + else { + bCut = true; + bTouch = true; + bCutRight = false; + } + } else if (value0.isEqual(tangent1)) { + if (!bConsiderTouch) + bCut = false; + else { + bCut = true; + bTouch = true; + bCutRight = true; + } + } else { + bCut = true; + bCutRight = value2.isEqual(tangent2); + } + } else if (value2.isEqual(tangent0)) { + if (value3.isEqual(tangent1)) { + if (!bConsiderTouch) + bCut = false; + else { + bCut = true; + bTouch = true; + bCutRight = false; + } + } else if (value1.isEqual(tangent1)) { + if (!bConsiderTouch) + bCut = false; + else { + bCut = true; + bTouch = true; + bCutRight = true; + } + } else { + bCut = true; + bCutRight = value3.isEqual(tangent2); + } + } else { + if (value0.isEqual(tangent1)) { + if (!bConsiderTouch) + bCut = false; + else { + bCut = true; + bTouch = true; + bCutRight = false; + } + } else if (value2.isEqual(tangent1)) { + if (!bConsiderTouch) + bCut = false; + else { + bCut = true; + bTouch = true; + bCutRight = true; + } + } else { + bCut = true; + bCutRight = value0.isEqual(tangent2); + } + } + } + + if (bCut) { + boolean bIsFirstSegmentInPath = (ivertex == ivertexCuttee); + + if (scalarCuttee != lastScalarCuttee + || bIsFirstSegmentInPath + && lastScalarCuttee == 0.0) { + if (bCreateNewMultiPath) { + if (cutPairs != null) + multipath = new Polyline(); + else + segmentCount = 0; + } + + if (cutPairs != null) { + segmentCuttee.cut(lastScalarCuttee, + scalarCuttee, segmentBufferCuttee); + multipath.addSegment(segmentBufferCuttee.get(), + bStartNewPath); + } else + segmentCount++; + } + + if (bCutRight) { + if (cutPrev != OperatorCutLocal.Side.Right + || bLocalCutsOnly) { + if (scalarCuttee != lastScalarCuttee + || bIsFirstSegmentInPath + && lastScalarCuttee == 0.0 + || bLocalCutsOnly) { + if (cutPairs != null) { + cutPair = new OperatorCutLocal.CutPair( + multipath, + OperatorCutLocal.Side.Right, + ipartCuttee, ivertexCuttee, + scalarCuttee, cutPrev, + ipartCutteePrev, + ivertexCutteePrev, + scalarCutteePrev, ipartCutter, + ivertexCutter, scalarCutter, + ipartCutterPrev, + ivertexCutterPrev, + scalarCutterPrev); + cutPairs.add(cutPair); + } else { + segmentCounts.add(segmentCount); + } + } + + if (!bTouch) + cutPrev = OperatorCutLocal.Side.Right; + else if (icutEvent == cutEvents.size() - 2 + || cutEvents.get(icutEvent + 2).m_ipartCuttee != ipartCuttee) + cutPrev = OperatorCutLocal.Side.Left; + } else { + if (scalarCuttee != lastScalarCuttee + || bIsFirstSegmentInPath + && lastScalarCuttee == 0.0 + || bLocalCutsOnly) { + if (cutPairs != null) { + cutPair = new OperatorCutLocal.CutPair( + multipath, + OperatorCutLocal.Side.Undefined, + ipartCuttee, ivertexCuttee, + scalarCuttee, cutPrev, + ipartCutteePrev, + ivertexCutteePrev, + scalarCutteePrev, ipartCutter, + ivertexCutter, scalarCutter, + ipartCutterPrev, + ivertexCutterPrev, + scalarCutterPrev); + cutPairs.add(cutPair); + } else { + segmentCounts.add(segmentCount); + } + } + + cutPrev = OperatorCutLocal.Side.Right; + } + } else { + if (cutPrev != OperatorCutLocal.Side.Left + || bLocalCutsOnly) { + if (scalarCuttee != lastScalarCuttee + || bIsFirstSegmentInPath + && lastScalarCuttee == 0.0 + || bLocalCutsOnly) { + if (cutPairs != null) { + cutPair = new OperatorCutLocal.CutPair( + multipath, + OperatorCutLocal.Side.Left, + ipartCuttee, ivertexCuttee, + scalarCuttee, cutPrev, + ipartCutteePrev, + ivertexCutteePrev, + scalarCutteePrev, ipartCutter, + ivertexCutter, scalarCutter, + ipartCutterPrev, + ivertexCutterPrev, + scalarCutterPrev); + cutPairs.add(cutPair); + } else { + segmentCounts.add(segmentCount); + } + } + + if (!bTouch) + cutPrev = OperatorCutLocal.Side.Left; + else if (icutEvent == cutEvents.size() - 2 + || cutEvents.get(icutEvent + 2).m_ipartCuttee != ipartCuttee) + cutPrev = OperatorCutLocal.Side.Right; + } else { + if (scalarCuttee != lastScalarCuttee + || bIsFirstSegmentInPath + && lastScalarCuttee == 0.0 + || bLocalCutsOnly) { + if (cutPairs != null) { + cutPair = new OperatorCutLocal.CutPair( + multipath, + OperatorCutLocal.Side.Undefined, + ipartCuttee, ivertexCuttee, + scalarCuttee, cutPrev, + ipartCutteePrev, + ivertexCutteePrev, + scalarCutteePrev, ipartCutter, + ivertexCutter, scalarCutter, + ipartCutterPrev, + ivertexCutterPrev, + scalarCutterPrev); + cutPairs.add(cutPair); + } else { + segmentCounts.add(segmentCount); + } + } + + cutPrev = OperatorCutLocal.Side.Left; + } + } + + if (scalarCuttee != lastScalarCuttee + || bIsFirstSegmentInPath + && lastScalarCuttee == 0.0 || bLocalCutsOnly) { + lastScalarCuttee = scalarCuttee; + + ipartCutteePrev = ipartCuttee; + ivertexCutteePrev = ivertexCuttee; + scalarCutteePrev = scalarCuttee; + ipartCutterPrev = ipartCutter; + ivertexCutterPrev = ivertexCutter; + scalarCutterPrev = scalarCutter; + + bCurrentMultiPathNotAdded = false; + bNoCutYet = false; + bCreateNewMultiPath = true; + bStartNewPath = true; + } + } + + icutEvent++; + } + + if (lastScalarCuttee != 1.0) { + if (bCreateNewMultiPath) { + if (cutPairs != null) + multipath = new Polyline(); + else + segmentCount = 0; + } + + if (cutPairs != null) { + segmentCuttee.cut(lastScalarCuttee, 1.0, + segmentBufferCuttee); + multipath.addSegment(segmentBufferCuttee.get(), + bStartNewPath); + } else + segmentCount++; + + bCreateNewMultiPath = false; + bStartNewPath = false; + bCurrentMultiPathNotAdded = true; + } + } + + if (bCurrentMultiPathNotAdded) { + scalarCuttee = 1.0; + ivertexCuttee = shape.getLastVertex(ipath); + ivertexCuttee = shape.getPrevVertex(ivertexCuttee); + + ipartCutter = -1; + ivertexCutter = -1; + scalarCutter = NumberUtils.NaN(); + + if (bNoCutYet) { + if (cutPairs != null) { + cutPair = new OperatorCutLocal.CutPair(multipath, + OperatorCutLocal.Side.Uncut, ipartCuttee, + ivertexCuttee, scalarCuttee, cutPrev, + ipartCutteePrev, ivertexCutteePrev, + scalarCutteePrev, ipartCutter, ivertexCutter, + scalarCutter, ipartCutterPrev, + ivertexCutterPrev, scalarCutterPrev); + cutPairs.add(cutPair); + } else { + segmentCounts.add(segmentCount); + } + } else { + if (cutPrev == OperatorCutLocal.Side.Right) + cut = OperatorCutLocal.Side.Left; + else if (cutPrev == OperatorCutLocal.Side.Left) + cut = OperatorCutLocal.Side.Right; + else + cut = OperatorCutLocal.Side.Undefined; + + if (cutPairs != null) { + cutPair = new OperatorCutLocal.CutPair(multipath, cut, + ipartCuttee, ivertexCuttee, scalarCuttee, + cutPrev, ipartCutteePrev, ivertexCutteePrev, + scalarCutteePrev, ipartCutter, ivertexCutter, + scalarCutter, ipartCutterPrev, + ivertexCutterPrev, scalarCutterPrev); + cutPairs.add(cutPair); + } else { + segmentCounts.add(segmentCount); + } + } + } + } + } + + static boolean _cutterTangents(boolean bConsiderTouch, EditShape shape, + ArrayList cutEvents, int icutEvent, Point2D tangent0, + Point2D tangent1) { + double scalarCutter = cutEvents.get(icutEvent).m_scalarCutter0; + + if (scalarCutter == 1.0) + return _cutterEndTangents(bConsiderTouch, shape, cutEvents, + icutEvent, tangent0, tangent1); + + if (scalarCutter == 0.0) + return _cutterStartTangents(bConsiderTouch, shape, cutEvents, + icutEvent, tangent0, tangent1); + + throw GeometryException.GeometryInternalError(); + } + + static boolean _cutterEndTangents(boolean bConsiderTouch, EditShape shape, + ArrayList cutEvents, int icutEvent, Point2D tangent0, + Point2D tangent1) { + Line lineCutter = new Line(); + Segment segmentCutter; + + int ivertexCuttee = cutEvents.get(icutEvent).m_ivertexCuttee; + int ipartCutter = cutEvents.get(icutEvent).m_ipartCutter; + int ivertexCutter = cutEvents.get(icutEvent).m_ivertexCutter; + + int ivertexCutteePrev = -1; + int ipartCutterPrev = -1; + int ivertexCutterPrev = -1; + int countPrev = -1; + + if (!bConsiderTouch && icutEvent > 0) { + CutEvent cutEvent = cutEvents.get(icutEvent - 1); + ivertexCutteePrev = cutEvent.m_ivertexCuttee; + ipartCutterPrev = cutEvent.m_ipartCutter; + ivertexCutterPrev = cutEvent.m_ivertexCutter; + countPrev = cutEvent.m_count; + } + + int ivertexCutteeNext = -1; + int ipartCutterNext = -1; + int ivertexCutterNext = -1; + int countNext = -1; + + if (icutEvent < cutEvents.size() - 1) { + CutEvent cutEvent = cutEvents.get(icutEvent + 1); + ivertexCutteeNext = cutEvent.m_ivertexCuttee; + ipartCutterNext = cutEvent.m_ipartCutter; + ivertexCutterNext = cutEvent.m_ivertexCutter; + countNext = cutEvent.m_count; + } + + int ivertexCutteePlus = shape.getNextVertex(ivertexCuttee); + int ivertexCutterPlus = shape.getNextVertex(ivertexCutter); + + if (!bConsiderTouch) { + if ((icutEvent > 0 && ivertexCutteePrev == ivertexCuttee + && ipartCutterPrev == ipartCutter + && ivertexCutterPrev == ivertexCutterPlus && countPrev == 2) + || (icutEvent < cutEvents.size() - 1 + && ivertexCutteeNext == ivertexCutteePlus + && ipartCutterNext == ipartCutter + && ivertexCutterNext == ivertexCutterPlus && countNext == 2)) { + segmentCutter = shape.getSegment(ivertexCutter); + if (segmentCutter == null) { + shape.queryLineConnector(ivertexCutter, lineCutter); + segmentCutter = lineCutter; + } + + tangent1.setCoords(segmentCutter._getTangent(1.0)); + tangent0.negate(tangent1); + tangent1.normalize(); + tangent0.normalize(); + + return false; + } + + if (icutEvent < cutEvents.size() - 1 + && ivertexCutteeNext == ivertexCuttee + && ipartCutterNext == ipartCutter + && ivertexCutterNext == ivertexCutterPlus) { + segmentCutter = shape.getSegment(ivertexCutter); + if (segmentCutter == null) { + shape.queryLineConnector(ivertexCutter, lineCutter); + segmentCutter = lineCutter; + } + + tangent0.setCoords(segmentCutter._getTangent(1.0)); + + segmentCutter = shape.getSegment(ivertexCutterPlus); + if (segmentCutter == null) { + shape.queryLineConnector(ivertexCutterPlus, lineCutter); + segmentCutter = lineCutter; + } + + tangent1.setCoords(segmentCutter._getTangent(0.0)); + tangent0.negate(); + tangent1.normalize(); + tangent0.normalize(); + + return false; + } + + return true; + } + + if (icutEvent == cutEvents.size() - 1 + || ivertexCutteeNext != ivertexCuttee + || ipartCutterNext != ipartCutter + || ivertexCutterNext != ivertexCutterPlus || countNext == 2) { + segmentCutter = shape.getSegment(ivertexCutter); + if (segmentCutter == null) { + shape.queryLineConnector(ivertexCutter, lineCutter); + segmentCutter = lineCutter; + } + + tangent1.setCoords(segmentCutter._getTangent(1.0)); + tangent0.negate(tangent1); + tangent1.normalize(); + tangent0.normalize(); + + return false; + } + + segmentCutter = shape.getSegment(ivertexCutter); + if (segmentCutter == null) { + shape.queryLineConnector(ivertexCutter, lineCutter); + segmentCutter = lineCutter; + } + + tangent0.setCoords(segmentCutter._getTangent(1.0)); + + segmentCutter = shape.getSegment(ivertexCutterPlus); + if (segmentCutter == null) { + shape.queryLineConnector(ivertexCutterPlus, lineCutter); + segmentCutter = lineCutter; + } + + tangent1.setCoords(segmentCutter._getTangent(0.0)); + tangent0.negate(); + tangent1.normalize(); + tangent0.normalize(); + + return false; + } + + static boolean _cutterStartTangents(boolean bConsiderTouch, + EditShape shape, ArrayList cutEvents, int icutEvent, + Point2D tangent0, Point2D tangent1) { + Line lineCutter = new Line(); + Segment segmentCutter; + + int ivertexCuttee = cutEvents.get(icutEvent).m_ivertexCuttee; + int ipartCutter = cutEvents.get(icutEvent).m_ipartCutter; + int ivertexCutter = cutEvents.get(icutEvent).m_ivertexCutter; + + int ivertexCutteeNext = -1; + int ipartCutterNext = -1; + int ivertexCutterNext = -1; + int countNext = -1; + + if (!bConsiderTouch && icutEvent < cutEvents.size() - 1) { + CutEvent cutEvent = cutEvents.get(icutEvent + 1); + ivertexCutteeNext = cutEvent.m_ivertexCuttee; + ipartCutterNext = cutEvent.m_ipartCutter; + ivertexCutterNext = cutEvent.m_ivertexCutter; + countNext = cutEvent.m_count; + } + + int ivertexCutteePrev = -1; + int ipartCutterPrev = -1; + int ivertexCutterPrev = -1; + int countPrev = -1; + + if (icutEvent > 0) { + CutEvent cutEvent = cutEvents.get(icutEvent - 1); + ivertexCutteePrev = cutEvent.m_ivertexCuttee; + ipartCutterPrev = cutEvent.m_ipartCutter; + ivertexCutterPrev = cutEvent.m_ivertexCutter; + countPrev = cutEvent.m_count; + } + + int ivertexCutteePlus = shape.getNextVertex(ivertexCuttee); + int ivertexCutterMinus = shape.getPrevVertex(ivertexCutter); + + if (!bConsiderTouch) { + if ((icutEvent > 0 && ivertexCutteePrev == ivertexCuttee + && ipartCutterPrev == ipartCutter + && ivertexCutterPrev == ivertexCutterMinus && countPrev == 2) + || (icutEvent < cutEvents.size() - 1 + && ivertexCutteeNext == ivertexCutteePlus + && ipartCutterNext == ipartCutter + && ivertexCutterNext == ivertexCutterMinus && countNext == 2)) { + segmentCutter = shape.getSegment(ivertexCutter); + if (segmentCutter == null) { + shape.queryLineConnector(ivertexCutter, lineCutter); + segmentCutter = lineCutter; + } + + tangent1.setCoords(segmentCutter._getTangent(0.0)); + tangent0.negate(tangent1); + tangent1.normalize(); + tangent0.normalize(); + + return false; + } + + return true; + } + + if (icutEvent == 0 || ivertexCutteePrev != ivertexCuttee + || ipartCutterPrev != ipartCutter + || ivertexCutterPrev != ivertexCutterMinus || countPrev == 2) { + segmentCutter = shape.getSegment(ivertexCutter); + if (segmentCutter == null) { + shape.queryLineConnector(ivertexCutter, lineCutter); + segmentCutter = lineCutter; + } + + tangent1.setCoords(segmentCutter._getTangent(0.0)); + tangent0.negate(tangent1); + tangent1.normalize(); + tangent0.normalize(); + + return false; + } + + // Already processed the event + + return true; + } + + static boolean _cutteeTangents(EditShape shape, + ArrayList cutEvents, int icutEvent, int ipath, + int ivertex, Point2D tangent2, Point2D tangent3) { + Line lineCuttee = new Line(); + Segment segmentCuttee = shape.getSegment(ivertex); + if (segmentCuttee == null) { + shape.queryLineConnector(ivertex, lineCuttee); + segmentCuttee = lineCuttee; + } + + CutEvent cutEvent = cutEvents.get(icutEvent); + int ivertexCuttee = cutEvent.m_ivertexCuttee; + double scalarCuttee = cutEvent.m_scalarCuttee0; + + int ivertexCutteePlus = shape.getNextVertex(ivertexCuttee); + + if (scalarCuttee == 1.0) { + tangent2.setCoords(segmentCuttee._getTangent(1.0)); + + if (ivertexCutteePlus != -1 + && ivertexCutteePlus != shape.getLastVertex(ipath)) { + segmentCuttee = shape.getSegment(ivertexCutteePlus); + if (segmentCuttee == null) { + shape.queryLineConnector(ivertexCutteePlus, lineCuttee); + segmentCuttee = lineCuttee; + } + + tangent3.setCoords(segmentCuttee._getTangent(0.0)); + + segmentCuttee = shape.getSegment(ivertexCuttee); + if (segmentCuttee == null) { + shape.queryLineConnector(ivertexCuttee, lineCuttee); + segmentCuttee = lineCuttee; + } + } else + tangent3.setCoords(tangent2); + + tangent2.negate(); + + tangent3.normalize(); + tangent2.normalize(); + + return false; + } + + if (scalarCuttee == 0.0) { + tangent3.setCoords(segmentCuttee._getTangent(scalarCuttee)); + tangent2.negate(tangent3); + tangent3.normalize(); + tangent2.normalize(); + + return false; + } + + throw GeometryException.GeometryInternalError(); + } } diff --git a/src/main/java/com/esri/core/geometry/DirtyFlags.java b/src/main/java/com/esri/core/geometry/DirtyFlags.java index 554edc71..67fddbca 100644 --- a/src/main/java/com/esri/core/geometry/DirtyFlags.java +++ b/src/main/java/com/esri/core/geometry/DirtyFlags.java @@ -24,41 +24,41 @@ package com.esri.core.geometry; interface DirtyFlags { - public static final int dirtyIsKnownSimple = 1; // !<0 when is_weak_simple - // or is_strong_simple flag - // is valid - public static final int isWeakSimple = 2; // ! 0.01 * fabsdivis) {// more accurate error calculation - // for very inaccurate divisor - double rr = divis.m_eps / fabsdivis; - e *= (1.0 + (1.0 + rr) * rr); - } - m_value = r; - m_eps = e + epsCoordinate() * Math.abs(r); - } - - void div(double v) { - double fabsdivis = Math.abs(v); - m_value /= v; - m_eps = m_eps / fabsdivis + epsCoordinate() * Math.abs(m_value); - } - - void div(ECoordinate v_1, ECoordinate v_2) { - set(v_1); - div(v_2); - } - - void div(double v_1, double v_2) { - m_value = v_1 / v_2; - m_eps = epsCoordinate() * Math.abs(m_value); - } - - void div(ECoordinate v_1, double v_2) { - set(v_1); - div(v_2); - } - - void div(double v_1, ECoordinate v_2) { - set(v_1); - div(v_2); - } - - void sqrt() { - double r, dr; - - if (m_value >= 0) { // assume non-negative input - r = Math.sqrt(m_value); - if (m_value > 10.0 * m_eps) { - dr = 0.5 * m_eps / r; - } else { - dr = (m_value > m_eps) ? r - Math.sqrt(m_value - m_eps) : Math - .max(r, Math.sqrt(m_value + m_eps) - r); - } - - dr += epsCoordinate() * Math.abs(r); - } else { - if (m_value < -m_eps) { // Assume negative input. Return value - // undefined - r = NumberUtils.TheNaN; - dr = NumberUtils.TheNaN; - } else { // assume zero input - r = 0.0; - dr = Math.sqrt(m_eps); - } - } - - m_value = r; - m_eps = dr; - } - - void sqr() { - double r = m_value * m_value; - m_eps = 2 * m_eps * m_value + m_eps * m_eps + epsCoordinate() * r; - m_value = r; - } - - // Assigns sin(angle) to this coordinate. - void sin(ECoordinate angle) { - double sinv = Math.sin(angle.m_value); - double cosv = Math.cos(angle.m_value); - m_value = sinv; - double absv = Math.abs(sinv); - m_eps = (Math.abs(cosv) + absv * 0.5 * angle.m_eps) * angle.m_eps - + epsCoordinate() * absv; - } - - // Assigns cos(angle) to this coordinate. - void cos(ECoordinate angle) { - double sinv = Math.sin(angle.m_value); - double cosv = Math.cos(angle.m_value); - m_value = cosv; - double absv = Math.abs(cosv); - m_eps = (Math.abs(sinv) + absv * 0.5 * angle.m_eps) * angle.m_eps - + epsCoordinate() * absv; - } - - // Calculates natural log of v and assigns to this coordinate - void log(ECoordinate v) { - double d = v.m_eps / v.m_value; - m_value = Math.log(v.m_value); - m_eps = d * (1.0 + 0.5 * d) + epsCoordinate() * Math.abs(m_value); - } - - // void SinAndCos(ECoordinate& _sin, ECoordinate& _cos); - // ECoordinate abs(); - // ECoordinate exp(); - // ECoordinate acos(); - // ECoordinate asin(); - // ECoordinate atan(); - - boolean eq(ECoordinate v) // == - { - return Math.abs(m_value - v.m_value) <= m_eps + v.m_eps; - } - - boolean ne(ECoordinate v) // != - { - return !eq(v); - } - - boolean GT(ECoordinate v) // > - { - return m_value - v.m_value > m_eps + v.m_eps; - } - - boolean lt(ECoordinate v) // < - { - return v.m_value - m_value > m_eps + v.m_eps; - } - - boolean ge(ECoordinate v) // >= - { - return !lt(v); - } - - boolean le(ECoordinate v) // <= - { - return !GT(v); - } - - // The following methods take into account the rounding erros as well as - // user defined tolerance. - boolean tolEq(ECoordinate v, double tolerance) // ! == with tolerance - { - return Math.abs(m_value - v.m_value) <= tolerance || eq(v); - } - - boolean tol_ne(ECoordinate v, double tolerance) // ! != - { - return !tolEq(v, tolerance); - } - - boolean tolGT(ECoordinate v, double tolerance) // ! > - { - return (m_value - v.m_value > tolerance) && GT(v); - } - - boolean tollt(ECoordinate v, double tolerance) // ! < - { - return (v.m_value - m_value > tolerance) && lt(v); - } - - boolean tolge(ECoordinate v, double tolerance) // ! >= - { - return !tollt(v, tolerance); - } - - boolean tolle(ECoordinate v, double tolerance) // ! <= - { - return !tolGT(v, tolerance); - } - - boolean isZero() { - return Math.abs(m_value) <= m_eps; - } - - boolean isFuzzyZero() { - return isZero() && m_eps != 0.0; - } - - boolean tolIsZero(double tolerance) { - return Math.abs(m_value) <= Math.max(m_eps, tolerance); - } - - void setPi() { - set(Math.PI, epsCoordinate()); - } - - void setE() { - set(2.71828182845904523536, epsCoordinate()); - } + private double m_value; + private double m_eps; + + ECoordinate() { + set(0.0, 0.0); + } + + ECoordinate(double v) { + set(v); + } + + ECoordinate(ECoordinate v) { + set(v); + } + + double epsCoordinate() { + return NumberUtils.doubleEps(); + } + + void scaleError(double f) { + m_eps *= f; + } + + void setError(double e) { + m_eps = e; + } + + void set(double v, double e) { + m_value = v; + m_eps = e; + } + + void set(double v) { + m_value = v; + m_eps = 0; + } + + void set(ECoordinate v) { + m_value = v.m_value; + m_eps = v.m_eps; + } + + double value() { + return m_value; + } + + double eps() { + return m_eps; + } + + void resetError() { + m_eps = 0; + } + + void add(ECoordinate v) // += + { + double r = m_value + v.m_value; + double e = m_eps + v.m_eps + epsCoordinate() * Math.abs(r); + m_value = r; + m_eps = e; + } + + void add(double v) // += + { + double r = m_value + v; + double e = m_eps + epsCoordinate() * Math.abs(r); + m_value = r; + m_eps = e; + } + + void sub(ECoordinate v) // -= + { + double r = m_value - v.m_value; + double e = m_eps + v.m_eps + epsCoordinate() * Math.abs(r); + m_value = r; + m_eps = e; + } + + void sub(double v) // -= + { + double r = m_value - v; + double e = m_eps + epsCoordinate() * Math.abs(r); + m_value = r; + m_eps = e; + } + + void add(ECoordinate v_1, ECoordinate v_2) // + + { + m_value = v_1.m_value + v_2.m_value; + m_eps = v_1.m_eps + v_2.m_eps + epsCoordinate() * Math.abs(m_value); + } + + void add(double v_1, double v_2) // + + { + m_value = v_1 + v_2; + m_eps = epsCoordinate() * Math.abs(m_value); + } + + void add(ECoordinate v_1, double v_2) // + + { + m_value = v_1.m_value + v_2; + m_eps = v_1.m_eps + epsCoordinate() * Math.abs(m_value); + } + + void add(double v_1, ECoordinate v_2) // + + { + m_value = v_1 + v_2.m_value; + m_eps = v_2.m_eps + epsCoordinate() * Math.abs(m_value); + } + + void sub(ECoordinate v_1, ECoordinate v_2) // - + { + m_value = v_1.m_value - v_2.m_value; + m_eps = v_1.m_eps + v_2.m_eps + epsCoordinate() * Math.abs(m_value); + } + + void sub(double v_1, double v_2) // - + { + m_value = v_1 - v_2; + m_eps = epsCoordinate() * Math.abs(m_value); + } + + void sub(ECoordinate v_1, double v_2) // - + { + m_value = v_1.m_value - v_2; + m_eps = v_1.m_eps + epsCoordinate() * Math.abs(m_value); + } + + void sub(double v_1, ECoordinate v_2) // - + { + m_value = v_1 - v_2.m_value; + m_eps = v_2.m_eps + epsCoordinate() * Math.abs(m_value); + } + + void mul(ECoordinate v) { + double r = m_value * v.m_value; + m_eps = m_eps * Math.abs(v.m_value) + v.m_eps * Math.abs(m_value) + + m_eps * v.m_eps + epsCoordinate() * Math.abs(r); + m_value = r; + } + + void mul(double v) { + double r = m_value * v; + m_eps = m_eps * Math.abs(v) + epsCoordinate() * Math.abs(r); + m_value = r; + } + + void mul(ECoordinate v_1, ECoordinate v_2) { + double r = v_1.m_value * v_2.m_value; + m_eps = v_1.m_eps * Math.abs(v_2.m_value) + v_2.m_eps + * Math.abs(v_1.m_value) + v_1.m_eps * v_2.m_eps + + epsCoordinate() * Math.abs(r); + m_value = r; + } + + void mul(double v_1, double v_2) { + m_value = v_1 * v_2; + m_eps = epsCoordinate() * Math.abs(m_value); + } + + void mul(ECoordinate v_1, double v_2) { + set(v_1); + mul(v_2); + } + + void mul(double v_1, ECoordinate v_2) { + set(v_2); + mul(v_1); + } + + void div(ECoordinate divis) { + double fabsdivis = Math.abs(divis.m_value); + double r = m_value / divis.m_value; + double e = (m_eps + Math.abs(r) * divis.m_eps) / fabsdivis; + if (divis.m_eps > 0.01 * fabsdivis) {// more accurate error calculation + // for very inaccurate divisor + double rr = divis.m_eps / fabsdivis; + e *= (1.0 + (1.0 + rr) * rr); + } + m_value = r; + m_eps = e + epsCoordinate() * Math.abs(r); + } + + void div(double v) { + double fabsdivis = Math.abs(v); + m_value /= v; + m_eps = m_eps / fabsdivis + epsCoordinate() * Math.abs(m_value); + } + + void div(ECoordinate v_1, ECoordinate v_2) { + set(v_1); + div(v_2); + } + + void div(double v_1, double v_2) { + m_value = v_1 / v_2; + m_eps = epsCoordinate() * Math.abs(m_value); + } + + void div(ECoordinate v_1, double v_2) { + set(v_1); + div(v_2); + } + + void div(double v_1, ECoordinate v_2) { + set(v_1); + div(v_2); + } + + void sqrt() { + double r, dr; + + if (m_value >= 0) { // assume non-negative input + r = Math.sqrt(m_value); + if (m_value > 10.0 * m_eps) { + dr = 0.5 * m_eps / r; + } else { + dr = (m_value > m_eps) ? r - Math.sqrt(m_value - m_eps) : Math + .max(r, Math.sqrt(m_value + m_eps) - r); + } + + dr += epsCoordinate() * Math.abs(r); + } else { + if (m_value < -m_eps) { // Assume negative input. Return value + // undefined + r = NumberUtils.TheNaN; + dr = NumberUtils.TheNaN; + } else { // assume zero input + r = 0.0; + dr = Math.sqrt(m_eps); + } + } + + m_value = r; + m_eps = dr; + } + + void sqr() { + double r = m_value * m_value; + m_eps = 2 * m_eps * m_value + m_eps * m_eps + epsCoordinate() * r; + m_value = r; + } + + // Assigns sin(angle) to this coordinate. + void sin(ECoordinate angle) { + double sinv = Math.sin(angle.m_value); + double cosv = Math.cos(angle.m_value); + m_value = sinv; + double absv = Math.abs(sinv); + m_eps = (Math.abs(cosv) + absv * 0.5 * angle.m_eps) * angle.m_eps + + epsCoordinate() * absv; + } + + // Assigns cos(angle) to this coordinate. + void cos(ECoordinate angle) { + double sinv = Math.sin(angle.m_value); + double cosv = Math.cos(angle.m_value); + m_value = cosv; + double absv = Math.abs(cosv); + m_eps = (Math.abs(sinv) + absv * 0.5 * angle.m_eps) * angle.m_eps + + epsCoordinate() * absv; + } + + // Calculates natural log of v and assigns to this coordinate + void log(ECoordinate v) { + double d = v.m_eps / v.m_value; + m_value = Math.log(v.m_value); + m_eps = d * (1.0 + 0.5 * d) + epsCoordinate() * Math.abs(m_value); + } + + // void SinAndCos(ECoordinate& _sin, ECoordinate& _cos); + // ECoordinate abs(); + // ECoordinate exp(); + // ECoordinate acos(); + // ECoordinate asin(); + // ECoordinate atan(); + + boolean eq(ECoordinate v) // == + { + return Math.abs(m_value - v.m_value) <= m_eps + v.m_eps; + } + + boolean ne(ECoordinate v) // != + { + return !eq(v); + } + + boolean GT(ECoordinate v) // > + { + return m_value - v.m_value > m_eps + v.m_eps; + } + + boolean lt(ECoordinate v) // < + { + return v.m_value - m_value > m_eps + v.m_eps; + } + + boolean ge(ECoordinate v) // >= + { + return !lt(v); + } + + boolean le(ECoordinate v) // <= + { + return !GT(v); + } + + // The following methods take into account the rounding erros as well as + // user defined tolerance. + boolean tolEq(ECoordinate v, double tolerance) // ! == with tolerance + { + return Math.abs(m_value - v.m_value) <= tolerance || eq(v); + } + + boolean tol_ne(ECoordinate v, double tolerance) // ! != + { + return !tolEq(v, tolerance); + } + + boolean tolGT(ECoordinate v, double tolerance) // ! > + { + return (m_value - v.m_value > tolerance) && GT(v); + } + + boolean tollt(ECoordinate v, double tolerance) // ! < + { + return (v.m_value - m_value > tolerance) && lt(v); + } + + boolean tolge(ECoordinate v, double tolerance) // ! >= + { + return !tollt(v, tolerance); + } + + boolean tolle(ECoordinate v, double tolerance) // ! <= + { + return !tolGT(v, tolerance); + } + + boolean isZero() { + return Math.abs(m_value) <= m_eps; + } + + boolean isFuzzyZero() { + return isZero() && m_eps != 0.0; + } + + boolean tolIsZero(double tolerance) { + return Math.abs(m_value) <= Math.max(m_eps, tolerance); + } + + void setPi() { + set(Math.PI, epsCoordinate()); + } + + void setE() { + set(2.71828182845904523536, epsCoordinate()); + } } diff --git a/src/main/java/com/esri/core/geometry/EditShape.java b/src/main/java/com/esri/core/geometry/EditShape.java index dfc93283..282ef3b7 100644 --- a/src/main/java/com/esri/core/geometry/EditShape.java +++ b/src/main/java/com/esri/core/geometry/EditShape.java @@ -33,2320 +33,2316 @@ * vertices. */ final class EditShape { - interface PathFlags_ { - static final int closedPath = 1; - static final int exteriorPath = 2; - static final int ringAreaValid = 4; - } - - private int m_geometryCount; - private int m_path_count; - private int m_point_count; - private int m_first_geometry; - private int m_last_geometry; - - private StridedIndexTypeCollection m_vertex_index_list; - - // ****************Vertex Data****************** - private MultiPoint m_vertices_mp; // vertex coordinates are stored here - // Attribute_stream_of_index_type::SPtr m_indexRemap; - private MultiPointImpl m_vertices; // Internals of m_vertices_mp - AttributeStreamOfDbl m_xy_stream; // The xy stream of the m_vertices. - VertexDescription m_vertex_description;// a shortcut to the vertex - // description. - boolean m_b_has_attributes; // a short cut to know if we have something in - // addition to x and y. - - ArrayList m_segments;// may be NULL if all segments a Lines, - // otherwise contains NULLs for Line - // segments. Curves are not NULL. - AttributeStreamOfDbl m_weights;// may be NULL if no weights are provided. - // NULL weights assumes weight value of 1. - ArrayList m_indices;// user indices are here - // ****************End Vertex Data************** - StridedIndexTypeCollection m_path_index_list; // doubly connected list. Path - // index into the Path Data - // arrays, Prev path, next - // path. - // ******************Path Data****************** - AttributeStreamOfDbl m_path_areas; - AttributeStreamOfDbl m_path_lengths; - // Block_array::SPtr m_path_envelopes; - ArrayList m_pathindices;// path user indices are - // here - // *****************End Path Data*************** - StridedIndexTypeCollection m_geometry_index_list; - ArrayList m_geometry_indices;// geometry user - // indices are here - - // *********** Helpers for Bucket sort************** - static class EditShapeBucketSortHelper extends ClassicSort { - EditShape m_shape; - - EditShapeBucketSortHelper(EditShape shape) { - m_shape = shape; - } - - @Override - public void userSort(int begin, int end, AttributeStreamOfInt32 indices) { - m_shape.sortVerticesSimpleByYHelper_(indices, begin, end); - } - - @Override - public double getValue(int index) { - return m_shape.getY(index); - } - } - - ; - - BucketSort m_bucket_sort; - - // Envelope::SPtr m_envelope; //the BBOX for all attributes - Point m_helper_point; // a helper point for intermediate operations - - Segment getSegmentFromIndex_(int vindex) { - return m_segments != null ? m_segments.get(vindex) : null; - } - - void setSegmentToIndex_(int vindex, Segment seg) { - if (m_segments == null) { - if (seg == null) - return; - m_segments = new ArrayList(); - for (int i = 0, n = m_vertices.getPointCount(); i < n; i++) - m_segments.add(null); - } - m_segments.set(vindex, seg); - } - - void setPrevPath_(int path, int prev) { - m_path_index_list.setField(path, 1, prev); - } - - void setNextPath_(int path, int next) { - m_path_index_list.setField(path, 2, next); - } - - void setPathFlags_(int path, int flags) { - m_path_index_list.setField(path, 6, flags); - } - - int getPathFlags_(int path) { - return m_path_index_list.getField(path, 6); - } - - void setPathGeometry_(int path, int geom) { - m_path_index_list.setField(path, 7, geom); - } - - int getPathIndex_(int path) { - return m_path_index_list.getField(path, 0); - } - - void setNextGeometry_(int geom, int next) { - m_geometry_index_list.setField(geom, 1, next); - } - - void setPrevGeometry_(int geom, int prev) { - m_geometry_index_list.setField(geom, 0, prev); - } - - int getGeometryIndex_(int geom) { - return m_geometry_index_list.getField(geom, 7); - } - - int getFirstPath_(int geom) { - return m_geometry_index_list.getField(geom, 3); - } - - void setFirstPath_(int geom, int firstPath) { - m_geometry_index_list.setField(geom, 3, firstPath); - } - - void setLastPath_(int geom, int path) { - m_geometry_index_list.setField(geom, 4, path); - } - - int newGeometry_(int gt) { - // Index_type index = m_first_free_geometry; - if (m_geometry_index_list == null) - m_geometry_index_list = new StridedIndexTypeCollection(8); - - int index = m_geometry_index_list.newElement(); - // m_geometry_index_list.set(index + 0, -1);//prev - // m_geometry_index_list.set(index + 1, -1);//next - m_geometry_index_list.setField(index, 2, gt);// Geometry_type - // m_geometry_index_list.set(index + 3, -1);//first path - // m_geometry_index_list.set(index + 4, -1);//last path - m_geometry_index_list.setField(index, 5, 0);// point count - m_geometry_index_list.setField(index, 6, 0);// path count - m_geometry_index_list.setField(index, 7, - m_geometry_index_list.elementToIndex(index));// geometry index - - return index; - } - - void freeGeometry_(int geom) { - m_geometry_index_list.deleteElement(geom); - } - - int newPath_(int geom) { - if (m_path_index_list == null) { - m_path_index_list = new StridedIndexTypeCollection(8); - m_vertex_index_list = new StridedIndexTypeCollection(5); - m_path_areas = new AttributeStreamOfDbl(0); - m_path_lengths = new AttributeStreamOfDbl(0); - } - - int index = m_path_index_list.newElement(); - int pindex = m_path_index_list.elementToIndex(index); - m_path_index_list.setField(index, 0, pindex);// size - // m_path_index_list.set(index + 1, -1);//prev - // m_path_index_list.set(index + 2, -1);//next - m_path_index_list.setField(index, 3, 0);// size - // m_path_index_list.set(index + 4, -1);//first vertex handle - // m_path_index_list.set(index + 5, -1);//last vertex handle - m_path_index_list.setField(index, 6, 0);// path flags - setPathGeometry_(index, geom); - if (pindex >= m_path_areas.size()) { - int sz = pindex < 16 ? 16 : (pindex * 3) / 2; - m_path_areas.resize(sz); - m_path_lengths.resize(sz); - // if (m_path_envelopes) - // m_path_envelopes.resize(sz); - } - m_path_areas.set(pindex, 0); - m_path_lengths.set(pindex, 0); - // if (m_path_envelopes) - // m_path_envelopes.set(pindex, nullptr); - - m_path_count++; - return index; - } - - void freePath_(int path) { - m_path_index_list.deleteElement(path); - m_path_count--; - } - - void freeVertex_(int vertex) { - m_vertex_index_list.deleteElement(vertex); - m_point_count--; - } - - int newVertex_(int vindex) { - assert (vindex >= 0 || vindex == -1);// vindex is not a handle - - if (m_path_index_list == null) { - m_path_index_list = new StridedIndexTypeCollection(8); - m_vertex_index_list = new StridedIndexTypeCollection(5); - m_path_areas = new AttributeStreamOfDbl(0); - m_path_lengths = new AttributeStreamOfDbl(0); - } - - int index = m_vertex_index_list.newElement(); - int vi = vindex >= 0 ? vindex : m_vertex_index_list - .elementToIndex(index); - m_vertex_index_list.setField(index, 0, vi); - if (vindex < 0) { - if (vi >= m_vertices.getPointCount()) { - int sz = vi < 16 ? 16 : (vi * 3) / 2; - // m_vertices.reserveRounded(sz); - m_vertices.resize(sz); - if (m_segments != null) { - for (int i = 0; i < sz; i++) - m_segments.add(null); - } - - if (m_weights != null) - m_weights.resize(sz); - - m_xy_stream = (AttributeStreamOfDbl) m_vertices - .getAttributeStreamRef(VertexDescription.Semantics.POSITION); - } - - m_vertices.setXY(vi, -1e38, -1e38); - - if (m_segments != null) - m_segments.set(vi, null); - - if (m_weights != null) - m_weights.write(vi, 1.0); - } else { - // We do not set vertices or segments here, because we assume those - // are set correctly already. - // We only here to create linked list of indices on existing vertex - // value. - // m_segments->set(m_point_count, nullptr); - } - - m_vertex_index_list.setField(index, 4, vi * 2); - m_point_count++; - return index; - } - - void free_vertex_(int vertex) { - m_vertex_index_list.deleteElement(vertex); - m_point_count--; - } - - int insertVertex_(int path, int before, Point point) { - int prev = before != -1 ? getPrevVertex(before) : getLastVertex(path); - int next = prev != -1 ? getNextVertex(prev) : -1; - - int vertex = newVertex_(point == null ? m_point_count : -1); - int vindex = getVertexIndex(vertex); - if (point != null) - m_vertices.setPointByVal(vindex, point); - - setPathToVertex_(vertex, path); - setNextVertex_(vertex, next); - setPrevVertex_(vertex, prev); - - if (next != -1) - setPrevVertex_(next, vertex); - - if (prev != -1) - setNextVertex_(prev, vertex); - - boolean b_closed = isClosedPath(path); - int first = getFirstVertex(path); - if (before == -1) - setLastVertex_(path, vertex); - - if (before == first) - setFirstVertex_(path, vertex); - - if (b_closed && next == -1) { - setNextVertex_(vertex, vertex); - setPrevVertex_(vertex, vertex); - } - - setPathSize_(path, getPathSize(path) + 1); - int geometry = getGeometryFromPath(path); - setGeometryVertexCount_(geometry, getPointCount(geometry) + 1); - - return vertex; - } - - Point getHelperPoint_() { - if (m_helper_point == null) - m_helper_point = new Point(m_vertices.getDescription()); - return m_helper_point; - } - - void setFillRule(int geom, int rule) { - int t = m_geometry_index_list.getField(geom, 2); - t &= ~(0x8000000); - t |= rule == Polygon.FillRule.enumFillRuleWinding ? 0x8000000 : 0; - m_geometry_index_list.setField(geom, 2, t);//fill rule combined with geometry type - } - - int getFillRule(int geom) { - int t = m_geometry_index_list.getField(geom, 2); - return (t & 0x8000000) != 0 ? Polygon.FillRule.enumFillRuleWinding : Polygon.FillRule.enumFillRuleOddEven; - } - - int addMultiPath_(MultiPath multi_path) { - int newgeom = createGeometry(multi_path.getType(), - multi_path.getDescription()); - if (multi_path.getType() == Geometry.Type.Polygon) - setFillRule(newgeom, ((Polygon) multi_path).getFillRule()); - - appendMultiPath_(newgeom, multi_path); - return newgeom; - } - - int addMultiPoint_(MultiPoint multi_point) { - int newgeometry = createGeometry(multi_point.getType(), - multi_point.getDescription()); - appendMultiPoint_(newgeometry, multi_point); - return newgeometry; - } - - void appendMultiPath_(int dstGeom, MultiPath multi_path) { - MultiPathImpl mp_impl = (MultiPathImpl) multi_path._getImpl(); - // m_vertices->reserve_rounded(m_vertices->get_point_count() + - // mp_impl->get_point_count());//ensure reallocation happens by blocks - // so that already allocated vertices do not get reallocated. - m_vertices_mp.add(multi_path, 0, mp_impl.getPointCount()); - m_xy_stream = (AttributeStreamOfDbl) m_vertices - .getAttributeStreamRef(VertexDescription.Semantics.POSITION); - boolean b_some_segments = m_segments != null - && mp_impl.getSegmentFlagsStreamRef() != null; - - for (int ipath = 0, npath = mp_impl.getPathCount(); ipath < npath; ipath++) { - if (mp_impl.getPathSize(ipath) < 2) // CR249862 - Clipping geometry - // which has empty part produces - // a crash - continue; - - int path = insertPath(dstGeom, -1); - setClosedPath(path, mp_impl.isClosedPath(ipath)); - for (int ivertex = mp_impl.getPathStart(ipath), iend = mp_impl - .getPathEnd(ipath); ivertex < iend; ivertex++) { - int vertex = insertVertex_(path, -1, null); - if (b_some_segments) { - int vindex = getVertexIndex(vertex); - if ((mp_impl.getSegmentFlags(ivertex) & (byte) SegmentFlags.enumLineSeg) != 0) { - setSegmentToIndex_(vindex, null); - } else { - SegmentBuffer seg_buffer = new SegmentBuffer(); - mp_impl.getSegment(ivertex, seg_buffer, true); - setSegmentToIndex_(vindex, seg_buffer.get()); - } - } - } - } - - // {//debug - // #ifdef DEBUG - // for (Index_type geometry = get_first_geometry(); geometry != -1; - // geometry = get_next_geometry(geometry)) - // { - // for (Index_type path = get_first_path(geometry); path != -1; path = - // get_next_path(path)) - // { - // Index_type first = get_first_vertex(path); - // Index_type v = first; - // for (get_next_vertex(v); v != first; v = get_next_vertex(v)) - // { - // assert(get_next_vertex(get_prev_vertex(v)) == v); - // } - // } - // } - // #endif - // } - } - - void appendMultiPoint_(int dstGeom, MultiPoint multi_point) { - // m_vertices->reserve_rounded(m_vertices->get_point_count() + - // multi_point.get_point_count());//ensure reallocation happens by - // blocks so that already allocated vertices do not get reallocated. - m_vertices_mp.add(multi_point, 0, multi_point.getPointCount()); - m_xy_stream = (AttributeStreamOfDbl) m_vertices - .getAttributeStreamRef(VertexDescription.Semantics.POSITION); - - int path = insertPath(dstGeom, -1); - for (int ivertex = 0, iend = multi_point.getPointCount(); ivertex < iend; ivertex++) { - insertVertex_(path, -1, null); - } - } - - void splitSegmentForward_(int origin_vertex, - SegmentIntersector intersector, int intersector_index) { - int last_vertex = getNextVertex(origin_vertex); - if (last_vertex == -1) - throw GeometryException.GeometryInternalError(); - Point point = getHelperPoint_(); - int path = getPathFromVertex(origin_vertex); - int vertex = origin_vertex; - for (int i = 0, n = intersector - .getResultSegmentCount(intersector_index); i < n; i++) { - int vindex = getVertexIndex(vertex); - int next_vertex = getNextVertex(vertex); - Segment seg = intersector.getResultSegment(intersector_index, i); - - if (i == 0) { - seg.queryStart(point); - // #ifdef DEBUG - // Point2D pt = new Point2D(); - // getXY(vertex, pt); - // assert(Point2D.distance(point.getXY(), pt) <= - // intersector.get_tolerance_()); - // #endif - setPoint(vertex, point); - } - - if (seg.getType().value() == Geometry.GeometryType.Line) - setSegmentToIndex_(vindex, null); - else - setSegmentToIndex_(vindex, (Segment) Geometry._clone(seg)); - - seg.queryEnd(point); - if (i < n - 1) { - int inserted_vertex = insertVertex_(path, next_vertex, point); - vertex = inserted_vertex; - } else { - // #ifdef DEBUG - // Point_2D pt; - // get_xy(last_vertex, pt); - // assert(Point_2D::distance(point->get_xy(), pt) <= - // intersector.getTolerance_()); - // #endif - setPoint(last_vertex, point); - assert (last_vertex == next_vertex); - } - } - } - - void splitSegmentBackward_(int origin_vertex, - SegmentIntersector intersector, int intersector_index) { - int last_vertex = getNextVertex(origin_vertex); - if (last_vertex == -1) - throw GeometryException.GeometryInternalError(); - - Point point = getHelperPoint_(); - int path = getPathFromVertex(origin_vertex); - int vertex = origin_vertex; - for (int i = 0, n = intersector - .getResultSegmentCount(intersector_index); i < n; i++) { - int vindex = getVertexIndex(vertex); - int next_vertex = getNextVertex(vertex); - Segment seg = intersector.getResultSegment(intersector_index, n - i - - 1); - - if (i == 0) { - seg.queryEnd(point); - // #ifdef DEBUG - // Point2D pt = new Point2D(); - // getXY(vertex, pt); - // assert(Point2D.distance(point.getXY(), pt) <= - // intersector.getTolerance_()); - // #endif - setPoint(vertex, point); - } - - if (seg.getType().value() == Geometry.GeometryType.Line) - setSegmentToIndex_(vindex, null); - else - setSegmentToIndex_(vindex, (Segment) Geometry._clone(seg)); - - seg.queryStart(point); - if (i < n - 1) { - int inserted_vertex = insertVertex_(path, next_vertex, point); - vertex = inserted_vertex; - } else { - // #ifdef DEBUG - // Point2D pt = new Point2D(); - // getXY(last_vertex, pt); - // assert(Point2D.distance(point.getXY(), pt) <= - // intersector.getTolerance_()); - // #endif - setPoint(last_vertex, point); - assert (last_vertex == next_vertex); - } - } - } - - EditShape() { - m_path_count = 0; - m_first_geometry = -1; - m_last_geometry = -1; - m_point_count = 0; - m_geometryCount = 0; - m_b_has_attributes = false; - m_vertices = null; - m_xy_stream = null; - m_vertex_description = null; - } - - // Total point count in all geometries - int getTotalPointCount() { - return m_point_count; - } - - // Returns envelope of all coordinates. - Envelope2D getEnvelope2D() { - Envelope2D env = new Envelope2D(); - env.setEmpty(); - VertexIterator vert_iter = queryVertexIterator(); - Point2D pt = new Point2D(); - boolean b_first = true; - for (int ivertex = vert_iter.next(); ivertex != -1; ivertex = vert_iter - .next()) { - getXY(ivertex, pt); - if (b_first) - env.merge(pt.x, pt.y); - else - env.mergeNE(pt.x, pt.y); - - b_first = false; - } - - return env; - } - - // Returns geometry count in the edit shape - int getGeometryCount() { - return m_geometryCount; - } - - // Adds a Geometry to the Edit_shape - int addGeometry(Geometry geometry) { - Geometry.Type gt = geometry.getType(); - if (Geometry.isMultiPath(gt.value())) - return addMultiPath_((MultiPath) geometry); - if (gt == Geometry.Type.MultiPoint) - return addMultiPoint_((MultiPoint) geometry); - - throw GeometryException.GeometryInternalError(); - } - - // Append a Geometry to the given geometry of the Edit_shape - void appendGeometry(int dstGeometry, Geometry srcGeometry) { - Geometry.Type gt = srcGeometry.getType(); - if (Geometry.isMultiPath(gt.value())) { - appendMultiPath_(dstGeometry, (MultiPath) srcGeometry); - return; - } else if (gt.value() == Geometry.GeometryType.MultiPoint) { - appendMultiPoint_(dstGeometry, (MultiPoint) srcGeometry); - return; - } - - throw GeometryException.GeometryInternalError(); - } - - // Adds a path - int addPathFromMultiPath(MultiPath multi_path, int ipath, boolean as_polygon) { - int newgeom = createGeometry(as_polygon ? Geometry.Type.Polygon - : Geometry.Type.Polyline, multi_path.getDescription()); - - MultiPathImpl mp_impl = (MultiPathImpl) multi_path._getImpl(); - if (multi_path.getPathSize(ipath) < 2) - return newgeom; //return empty geometry - - // m_vertices->reserve_rounded(m_vertices->get_point_count() + - // multi_path.get_path_size(ipath));//ensure reallocation happens by - // blocks so that already allocated vertices do not get reallocated. - m_vertices_mp.add(multi_path, multi_path.getPathStart(ipath), - mp_impl.getPathEnd(ipath)); - m_xy_stream = (AttributeStreamOfDbl) m_vertices - .getAttributeStreamRef(VertexDescription.Semantics.POSITION); - - int path = insertPath(newgeom, -1); - setClosedPath(path, mp_impl.isClosedPath(ipath) || as_polygon); - - boolean b_some_segments = m_segments != null - && mp_impl.getSegmentFlagsStreamRef() != null; - - for (int ivertex = mp_impl.getPathStart(ipath), iend = mp_impl - .getPathEnd(ipath); ivertex < iend; ivertex++) { - int vertex = insertVertex_(path, -1, null); - if (b_some_segments) { - int vindex = getVertexIndex(vertex); - if ((mp_impl.getSegmentFlags(ivertex) & SegmentFlags.enumLineSeg) != 0) { - setSegmentToIndex_(vindex, null); - } else { - SegmentBuffer seg_buffer = new SegmentBuffer(); - mp_impl.getSegment(ivertex, seg_buffer, true); - setSegmentToIndex_(vindex, seg_buffer.get()); - } - } - } - - return newgeom; - } - - // Extracts a geometry from the Edit_shape. The method creates a new - // Geometry instance and initializes it with the Edit_shape data for the - // given geometry. - Geometry getGeometry(int geometry) { - int gt = getGeometryType(geometry); - Geometry geom = InternalUtils.createGeometry(gt, - m_vertices_mp.getDescription()); - int point_count = getPointCount(geometry); - - if (point_count == 0) - return geom; - - if (Geometry.isMultiPath(gt)) { - MultiPathImpl mp_impl = (MultiPathImpl) geom._getImpl(); - int path_count = getPathCount(geometry); - AttributeStreamOfInt32 parts = (AttributeStreamOfInt32) (AttributeStreamBase - .createIndexStream(path_count + 1)); - AttributeStreamOfInt8 pathFlags = (AttributeStreamOfInt8) (AttributeStreamBase - .createByteStream(path_count + 1, (byte) 0)); - VertexDescription description = geom.getDescription(); - - for (int iattrib = 0, nattrib = description.getAttributeCount(); iattrib < nattrib; iattrib++) { - int semantics = description.getSemantics(iattrib); - int ncomps = VertexDescription.getComponentCount(semantics); - AttributeStreamBase dst_stream = AttributeStreamBase - .createAttributeStreamWithSemantics(semantics, - point_count); - AttributeStreamBase src_stream = m_vertices - .getAttributeStreamRef(semantics); - int dst_index = 0; - int ipath = 0; - int nvert = 0; - for (int path = getFirstPath(geometry); path != -1; path = getNextPath(path)) { - byte flag_mask = 0; - if (isClosedPath(path)) { - flag_mask |= (byte) PathFlags.enumClosed; - } else { - assert (gt != Geometry.GeometryType.Polygon); - } - - if (isExterior(path)) { - flag_mask |= (byte) PathFlags.enumOGCStartPolygon; - } - - if (flag_mask != 0) - pathFlags.setBits(ipath, flag_mask); - - int path_size = getPathSize(path); - parts.write(ipath++, nvert); - nvert += path_size; - if (semantics == VertexDescription.Semantics.POSITION) { - AttributeStreamOfDbl src_stream_dbl = (AttributeStreamOfDbl) (src_stream); - AttributeStreamOfDbl dst_stream_dbl = (AttributeStreamOfDbl) (dst_stream); - Point2D pt = new Point2D(); - for (int vertex = getFirstVertex(path); dst_index < nvert; vertex = getNextVertex(vertex), dst_index++) { - int src_index = getVertexIndex(vertex); - src_stream_dbl.read(src_index * 2, pt); - dst_stream_dbl.write(dst_index * 2, pt); - } - } else { - for (int vertex = getFirstVertex(path); dst_index < nvert; vertex = getNextVertex(vertex), dst_index++) { - int src_index = getVertexIndex(vertex); - for (int icomp = 0; icomp < ncomps; icomp++) { - double d = src_stream.readAsDbl(src_index - * ncomps + icomp); - dst_stream.writeAsDbl(dst_index * ncomps - + icomp, d); - } - } - } - } - - assert (nvert == point_count);// Inconsistent content in the - // Edit_shape. Please, fix. - assert (ipath == path_count); - mp_impl.setAttributeStreamRef(semantics, dst_stream); - parts.write(path_count, point_count); - } - - mp_impl.setPathFlagsStreamRef(pathFlags); - mp_impl.setPathStreamRef(parts); - mp_impl.notifyModified(DirtyFlags.dirtyAll); - } else if (gt == Geometry.GeometryType.MultiPoint) { - MultiPointImpl mp_impl = (MultiPointImpl) geom._getImpl(); - VertexDescription description = geom.getDescription(); - // mp_impl.reserve(point_count); - mp_impl.resize(point_count); - - for (int iattrib = 0, nattrib = description.getAttributeCount(); iattrib < nattrib; iattrib++) { - int semantics = description.getSemantics(iattrib); - int ncomps = VertexDescription.getComponentCount(semantics); - AttributeStreamBase dst_stream = mp_impl - .getAttributeStreamRef(semantics); - // std::shared_ptr dst_stream = - // Attribute_stream_base::create_attribute_stream(semantics, - // point_count); - AttributeStreamBase src_stream = m_vertices - .getAttributeStreamRef(semantics); - int dst_index = 0; - assert (getPathCount(geometry) == 1); - int path = getFirstPath(geometry); - int path_size = getPathSize(path); - for (int vertex = getFirstVertex(path); dst_index < path_size; vertex = getNextVertex(vertex), dst_index++) { - int src_index = getVertexIndex(vertex); - for (int icomp = 0; icomp < ncomps; icomp++) { - double d = src_stream.readAsDbl(src_index * ncomps - + icomp); - dst_stream.writeAsDbl(dst_index * ncomps + icomp, d); - } - } - - mp_impl.setAttributeStreamRef(semantics, dst_stream); - } - - mp_impl.notifyModified(DirtyFlags.dirtyAll); - } else { - assert (false); - } - - return geom; - } - - // create a new empty geometry of the given type - int createGeometry(Geometry.Type geometry_type) { - return createGeometry(geometry_type, - VertexDescriptionDesignerImpl.getDefaultDescriptor2D()); - } - - // Deletes existing geometry from the edit shape and returns the next one. - int removeGeometry(int geometry) { - for (int path = getFirstPath(geometry); path != -1; path = removePath(path)) { - // removing paths in a loop - } - - int prev = getPrevGeometry(geometry); - int next = getNextGeometry(geometry); - if (prev != -1) - setNextGeometry_(prev, next); - else { - m_first_geometry = next; - } - if (next != -1) - setPrevGeometry_(next, prev); - else { - m_last_geometry = prev; - } - - freeGeometry_(geometry); - return next; - } - - // create a new empty geometry of the given type and attribute set. - int createGeometry(Geometry.Type geometry_type, - VertexDescription description) { - int newgeom = newGeometry_(geometry_type.value()); - if (m_vertices == null) { - m_vertices_mp = new MultiPoint(description); - m_vertices = (MultiPointImpl) m_vertices_mp._getImpl(); - } else - m_vertices_mp.mergeVertexDescription(description); - - m_vertex_description = m_vertices_mp.getDescription();// this - // description - // will be a - // merge of - // existing - // description - // and the - // description - // of the - // multi_path - m_b_has_attributes = m_vertex_description.getAttributeCount() > 1; - - if (m_first_geometry == -1) { - m_first_geometry = newgeom; - m_last_geometry = newgeom; - } else { - setPrevGeometry_(newgeom, m_last_geometry); - setNextGeometry_(m_last_geometry, newgeom); - m_last_geometry = newgeom; - } - return newgeom; - } - - // Returns the first geometry in the Edit_shape. - int getFirstGeometry() { - return m_first_geometry; - } - - // Returns the next geometry in the Edit_shape. Returns -1 when there are no - // more geometries. - int getNextGeometry(int geom) { - return m_geometry_index_list.getField(geom, 1); - } - - // Returns the previous geometry in the Edit_shape. Returns -1 when there - // are no more geometries. - int getPrevGeometry(int geom) { - return m_geometry_index_list.getField(geom, 0); - } - - // Returns the type of the Geometry. - int getGeometryType(int geom) { - return m_geometry_index_list.getField(geom, 2) & 0x7FFFFFFF; - } - - // Sets value to the given user index on a geometry. - void setGeometryUserIndex(int geom, int index, int value) { - AttributeStreamOfInt32 stream = m_geometry_indices.get(index); - int pindex = getGeometryIndex_(geom); - if (pindex >= stream.size()) - stream.resize(Math.max((int) (pindex * 1.25), (int) 16), -1); - stream.write(pindex, value); - } - - // Returns the value of the given user index of a geometry - int getGeometryUserIndex(int geom, int index) { - int pindex = getGeometryIndex_(geom); - AttributeStreamOfInt32 stream = m_geometry_indices.get(index); - if (pindex < stream.size()) - return stream.read(pindex); - else - return -1; - } - - // Creates new user index on a geometry. The geometry index allows to store - // an integer user value on the geometry. - // Until set_geometry_user_index is called for a given geometry, the index - // stores -1 for that geometry. - int createGeometryUserIndex() { - if (m_geometry_indices == null) - m_geometry_indices = new ArrayList(4); - - // Try getting existing index. Use linear search. We do not expect many - // indices to be created. - for (int i = 0; i < m_geometry_indices.size(); i++) { - if (m_geometry_indices.get(i) == null) { - m_geometry_indices.set(i, - (AttributeStreamOfInt32) AttributeStreamBase - .createIndexStream(0)); - return i; - } - } - - m_geometry_indices.add((AttributeStreamOfInt32) AttributeStreamBase - .createIndexStream(0)); - return m_geometry_indices.size() - 1; - } - - // Removes the geometry user index. - void removeGeometryUserIndex(int index) { - m_geometry_indices.set(index, null); - } - - // Returns the first path of the geometry. - int getFirstPath(int geometry) { - return m_geometry_index_list.getField(geometry, 3); - } - - // Returns the first path of the geometry. - int getLastPath(int geometry) { - return m_geometry_index_list.getField(geometry, 4); - } - - // Point count in a geometry - int getPointCount(int geom) { - return m_geometry_index_list.getField(geom, 5); - } - - // Path count in a geometry - int getPathCount(int geom) { - return m_geometry_index_list.getField(geom, 6); - } - - // Filters degenerate segments in all multipath geometries - // Returns 1 if a non-zero length segment has been removed. -1, if only zero - // length segments have been removed. - // 0 if no segments have been removed. - // When b_remove_last_vertices and the result path is < 3 for polygon or < 2 - // for polyline, it'll be removed. - int filterClosePoints(double tolerance, boolean b_remove_last_vertices, boolean only_polygons) { - int res = 0; - for (int geometry = getFirstGeometry(); geometry != -1; geometry = getNextGeometry(geometry)) { - int gt = getGeometryType(geometry); - if (!Geometry.isMultiPath(gt)) - continue; - if (only_polygons && gt != GeometryType.Polygon) - continue; - - boolean b_polygon = getGeometryType(geometry) == Geometry.GeometryType.Polygon; - - for (int path = getFirstPath(geometry); path != -1; ) { - // We go from the start to the half of the path first, then we - // go from the end to the half of the path. - int vertex_counter = 0; - for (int vertex = getFirstVertex(path); vertex_counter < getPathSize(path) / 2; ) { - int next = getNextVertex(vertex); - if (next == -1) - break; - int vindex = getVertexIndex(vertex); - Segment seg = getSegmentFromIndex_(vindex); - double length = 0; - if (seg != null) { - length = seg.calculateLength2D(); - } else { - int vindex_next = getVertexIndex(next); - length = m_vertices._getShortestDistance(vindex, - vindex_next); - } - - if (length <= tolerance) { - if (length == 0) { - if (res == 0) - res = -1; - } else - res = 1; - - if (next != getLastVertex(path)) { - transferAllDataToTheVertex(next, vertex); - removeVertex(next, true); - } - } else { - vertex = getNextVertex(vertex); - } - vertex_counter++; - } - - int first_vertex = getFirstVertex(path); - for (int vertex = isClosedPath(path) ? first_vertex - : getLastVertex(path); getPathSize(path) > 0; ) { - int prev = getPrevVertex(vertex); - if (prev != -1) { - int vindex_prev = getVertexIndex(prev); - Segment seg = getSegmentFromIndex_(vindex_prev); - double length = 0; - if (seg != null) { - length = seg.calculateLength2D(); - } else { - int vindex = getVertexIndex(vertex); - length = m_vertices._getShortestDistance(vindex, - vindex_prev); - } - - if (length <= tolerance) { - if (length == 0) { - if (res == 0) - res = -1; - } else - res = 1; - - transferAllDataToTheVertex(prev, vertex); - removeVertex(prev, false); - if (first_vertex == prev) - first_vertex = getFirstVertex(path); - } else { - vertex = getPrevVertex(vertex); - if (vertex == first_vertex) - break; - } - } else { - removeVertex(vertex, true);// remove the last vertex in - // the path - if (res == 0) - res = -1; - break; - } - } - - int path_size = getPathSize(path); - if (b_remove_last_vertices - && (b_polygon ? path_size < 3 : path_size < 2)) { - path = removePath(path); - res = path_size > 0 ? 1 : (res == 0 ? -1 : res); - } else - path = getNextPath(path); - } - } - - return res; - } - - // Checks if there are degenerate segments in any of multipath geometries - boolean hasDegenerateSegments(double tolerance) { - for (int geometry = getFirstGeometry(); geometry != -1; geometry = getNextGeometry(geometry)) { - if (!Geometry.isMultiPath(getGeometryType(geometry))) - continue; - - boolean b_polygon = getGeometryType(geometry) == Geometry.GeometryType.Polygon; - - for (int path = getFirstPath(geometry); path != -1; ) { - int path_size = getPathSize(path); - if (b_polygon ? path_size < 3 : path_size < 2) - return true; - - int vertex = getFirstVertex(path); - for (int index = 0; index < path_size; index++) { - int next = getNextVertex(vertex); - if (next == -1) - break; - int vindex = getVertexIndex(vertex); - Segment seg = getSegmentFromIndex_(vindex); - double length = 0; - if (seg != null) { - length = seg.calculateLength2D(); - } else { - int vindex_next = getVertexIndex(next); - length = m_vertices._getShortestDistance(vindex, - vindex_next); - } - - if (length <= tolerance) - return true; - - vertex = next; - } - - path = getNextPath(path); - } - } - - return false; - } - - void transferAllDataToTheVertex(int from_vertex, int to_vertex) { - int vindexFrom = getVertexIndex(from_vertex); - int vindexTo = getVertexIndex(to_vertex); - if (m_weights != null) { - double weight = m_weights.read(vindexFrom); - m_weights.write(vindexTo, weight); - } - - if (m_b_has_attributes) { - // TODO: implement copying of attributes with exception of x and y - // - // for (int i = 0, nattrib = 0; i < nattrib; i++) - // { - // m_vertices->get_attribute - // } - } - // Copy user index data - if (m_indices != null) { - for (int i = 0, n = (int) m_indices.size(); i < n; i++) { - if (m_indices.get(i) != null) { - int value = getUserIndex(from_vertex, i); - if (value != -1) - setUserIndex(to_vertex, i, value); - } - } - } - } - - // Splits segment originating from the origingVertex split_count times at - // splitScalar points and inserts new vertices into the shape. - // The split is not done, when the splitScalar[i] is 0 or 1, or is equal to - // the splitScalar[i - 1]. - // Returns the number of splits actually happend (0 if no splits have - // happend). - int splitSegment(int origin_vertex, double[] split_scalars, int split_count) { - int actual_splits = 0; - int next_vertex = getNextVertex(origin_vertex); - if (next_vertex == -1) - throw GeometryException.GeometryInternalError(); - - int vindex = getVertexIndex(origin_vertex); - int vindex_next = getVertexIndex(next_vertex); - Segment seg = getSegmentFromIndex_(vindex); - double seg_length = seg == null ? m_vertices._getShortestDistance( - vindex, vindex_next) : seg.calculateLength2D(); - double told = 0.0; - for (int i = 0; i < split_count; i++) { - double t = split_scalars[i]; - if (told < t && t < 1.0) { - double f = t; - if (seg != null) { - f = seg_length > 0 ? seg._calculateSubLength(t) - / seg_length : 0.0; - } - - m_vertices._interpolateTwoVertices(vindex, vindex_next, f, - getHelperPoint_());// use this call mainly to - // interpolate the attributes. XYs - // are interpolated incorrectly for - // curves and are recalculated when - // segment is cut below. - int inserted_vertex = insertVertex_( - getPathFromVertex(origin_vertex), next_vertex, - getHelperPoint_()); - actual_splits++; - if (seg != null) { - Segment subseg = seg.cut(told, t); - int prev_vertex = getPrevVertex(inserted_vertex); - int vindex_prev = getVertexIndex(prev_vertex); - setSegmentToIndex_(vindex_prev, subseg); - setXY(inserted_vertex, subseg.getEndXY()); // fix XY - // coordinates - // to be - // parameter - // based - // (interpolate_two_vertices_) - if (i == split_count - 1 || split_scalars[i + 1] == 1.0) {// last - // chance - // to - // set - // last - // split - // segment - // here: - Segment subseg_end = seg.cut(t, 1.0); - setSegmentToIndex_(vindex_prev, subseg_end); - } - } - } - } - - return actual_splits; - } - - // interpolates the attributes for the specified path between from_vertex - // and to_vertex - void interpolateAttributesForClosedPath(int path, int from_vertex, - int to_vertex) { - assert (isClosedPath(path)); - - if (!m_b_has_attributes) - return; - - double sub_length = calculateSubLength2D(path, from_vertex, to_vertex); - - if (sub_length == 0.0) - return; - - int nattr = m_vertex_description.getAttributeCount(); - - for (int iattr = 1; iattr < nattr; iattr++) { - int semantics = m_vertex_description.getSemantics(iattr); - - int interpolation = VertexDescription.getInterpolation(semantics); - if (interpolation == VertexDescription.Interpolation.ANGULAR) - continue; - - int components = VertexDescription.getComponentCount(semantics); - - for (int ordinate = 0; ordinate < components; ordinate++) - interpolateAttributesForClosedPath_(semantics, path, - from_vertex, to_vertex, sub_length, ordinate); - } - - return; - } - - // calculates the length for the specified path between from_vertex and - // to_vertex - double calculateSubLength2D(int path, int from_vertex, int to_vertex) { - int shape_from_index = getVertexIndex(from_vertex); - int shape_to_index = getVertexIndex(to_vertex); - - if (shape_from_index < 0 || shape_to_index > getTotalPointCount() - 1) - throw new IllegalArgumentException("invalid call"); - - if (shape_from_index > shape_to_index) { - if (!isClosedPath(path)) - throw new IllegalArgumentException( - "cannot iterate across an open path"); - } - - double sub_length = 0.0; - - for (int vertex = from_vertex; vertex != to_vertex; vertex = getNextVertex(vertex)) { - int vertex_index = getVertexIndex(vertex); - Segment segment = getSegmentFromIndex_(vertex_index); - if (segment != null) { - sub_length += segment.calculateLength2D(); - } else { - int next_vertex_index = getVertexIndex(getNextVertex(vertex)); - sub_length += m_vertices._getShortestDistance(vertex_index, - next_vertex_index); - } - } - - return sub_length; - } - - // set_point modifies the vertex and associated segments. - void setPoint(int vertex, Point new_coord) { - int vindex = getVertexIndex(vertex); - m_vertices.setPointByVal(vindex, new_coord); - Segment seg = getSegmentFromIndex_(vindex); - if (seg != null) { - seg.setStart(new_coord); - } - int prev = getPrevVertex(vertex); - if (prev != -1) { - int vindex_p = getVertexIndex(prev); - Segment seg_p = getSegmentFromIndex_(vindex_p); - if (seg_p != null) { - seg.setEnd(new_coord); - } - } - } - - // Queries point for a given vertex. - void queryPoint(int vertex, Point point) { - int vindex = getVertexIndex(vertex); - m_vertices.getPointByVal(vindex, point); - // assert(getXY(vertex) == point.getXY()); - } - - // set_xy modifies the vertex and associated segments. - void setXY(int vertex, Point2D new_coord) { - setXY(vertex, new_coord.x, new_coord.y); - } - - // set_xy modifies the vertex and associated segments. - void setXY(int vertex, double new_x, double new_y) { - int vindex = getVertexIndex(vertex); - m_vertices.setXY(vindex, new_x, new_y); - Segment seg = getSegmentFromIndex_(vindex); - if (seg != null) { - seg.setStartXY(new_x, new_y); - } - int prev = getPrevVertex(vertex); - if (prev != -1) { - int vindex_p = getVertexIndex(prev); - Segment seg_p = getSegmentFromIndex_(vindex_p); - if (seg_p != null) { - seg.setEndXY(new_x, new_y); - } - } - } - - Point2D getXY(int vertex) { - Point2D pt = new Point2D(); - int vindex = getVertexIndex(vertex); - pt.setCoords(m_vertices.getXY(vindex)); - return pt; - } - - // Returns the coordinates of the vertex. - void getXY(int vertex, Point2D ptOut) { - int vindex = getVertexIndex(vertex); - ptOut.setCoords(m_vertices.getXY(vindex)); - } - - void getXYWithIndex(int index, Point2D ptOut) { - m_xy_stream.read(2 * index, ptOut); - } - - // Gets the attribute for the given semantics and ordinate. - double getAttributeAsDbl(int semantics, int vertex, int ordinate) { - return m_vertices.getAttributeAsDbl(semantics, getVertexIndex(vertex), - ordinate); - } - - // Sets the attribute for the given semantics and ordinate. - void setAttribute(int semantics, int vertex, int ordinate, double value) { - m_vertices.setAttribute(semantics, getVertexIndex(vertex), ordinate, - value); - } - - // Sets the attribute for the given semantics and ordinate. - void setAttribute(int semantics, int vertex, int ordinate, int value) { - m_vertices.setAttribute(semantics, getVertexIndex(vertex), ordinate, - value); - } - - // Returns a reference to the vertex description - VertexDescription getVertexDescription() { - return m_vertex_description; - } - - int getMinPathVertexY(int path) { - int first_vert = getFirstVertex(path); - int minv = first_vert; - int vert = getNextVertex(first_vert); - while (vert != -1 && vert != first_vert) { - if (compareVerticesSimpleY_(vert, minv) < 0) - minv = vert; - vert = getNextVertex(vert); - } - return minv; - } - - // Returns an index value for the vertex inside of the underlying array of - // vertices. - // This index is for the use with the get_xy_with_index. get_xy is - // equivalent to calling get_vertex_index and get_xy_with_index. - int getVertexIndex(int vertex) { - return m_vertex_index_list.getField(vertex, 0); - } - - // Returns the y coordinate of the vertex. - double getY(int vertex) { - Point2D pt = new Point2D(); - getXY(vertex, pt); - return pt.y; - } - - // returns True if xy coordinates at vertices are equal. - boolean isEqualXY(int vertex_1, int vertex_2) { - int vindex1 = getVertexIndex(vertex_1); - int vindex2 = getVertexIndex(vertex_2); - return m_vertices.getXY(vindex1).isEqual(m_vertices.getXY(vindex2)); - } - - // returns True if xy coordinates at vertices are equal. - boolean isEqualXY(int vertex, Point2D pt) { - int vindex = getVertexIndex(vertex); - return m_vertices.getXY(vindex).isEqual(pt); - } - - // Sets weight to the vertex. Weight is used by clustering and cracking. - void setWeight(int vertex, double weight) { - if (weight < 1.0) - weight = 1.0; - - if (m_weights == null) { - if (weight == 1.0) - return; - - m_weights = (AttributeStreamOfDbl) (AttributeStreamBase - .createDoubleStream(m_vertices.getPointCount(), 1.0)); - } - - int vindex = getVertexIndex(vertex); - if (vindex >= m_weights.size()) { - m_weights.resize(vindex + 1, 1.0); - } - - m_weights.write(vindex, weight); - } - - double getWeight(int vertex) { - int vindex = getVertexIndex(vertex); - if (m_weights == null || vindex >= m_weights.size()) - return 1.0; - - return m_weights.read(vindex); - } - - // Removes associated weights - void removeWeights() { - m_weights = null; - } - - // Sets value to the given user index. - void setUserIndex(int vertex, int index, int value) { - // CHECKVERTEXHANDLE(vertex); - AttributeStreamOfInt32 stream = m_indices.get(index); - // assert(get_prev_vertex(vertex) != -0x7eadbeaf);//using deleted vertex - int vindex = getVertexIndex(vertex); - if (stream.size() < m_vertices.getPointCount()) - stream.resize(m_vertices.getPointCount(), -1); - stream.write(vindex, value); - } - - int getUserIndex(int vertex, int index) { - // CHECKVERTEXHANDLE(vertex); - int vindex = getVertexIndex(vertex); - AttributeStreamOfInt32 stream = m_indices.get(index); - if (vindex < stream.size()) { - int val = stream.read(vindex); - return val; - } else - return -1; - } - - // Creates new user index. The index have random values. The index allows to - // store an integer user value on the vertex. - int createUserIndex() { - if (m_indices == null) - m_indices = new ArrayList(0); - - // Try getting existing index. Use linear search. We do not expect many - // indices to be created. - for (int i = 0; i < m_indices.size(); i++) { - if (m_indices.get(i) == null) { - m_indices.set(i, (AttributeStreamOfInt32) AttributeStreamBase - .createIndexStream(0, -1)); - return i; - } - } - - m_indices.add((AttributeStreamOfInt32) AttributeStreamBase - .createIndexStream(0, -1)); - return m_indices.size() - 1; - } - - // Removes the user index. - void removeUserIndex(int index) { - m_indices.set(index, null); - } - - // Returns segment, connecting currentVertex and next vertex. Returns NULL - // if it is a Line. - Segment getSegment(int vertex) { - if (m_segments != null) { - int vindex = getVertexIndex(vertex); - return m_segments.get(vindex); - } - return null; - } - - // Returns a straight line that connects this and next vertices. No - // attributes. Returns false if no next vertex exists (end of polyline - // part). - // Can be used together with get_segment. - boolean queryLineConnector(int vertex, Line line) { - int next = getNextVertex(vertex); - if (next == -1) - return false; - - if (!m_b_has_attributes) { - Point2D pt = new Point2D(); - getXY(vertex, pt); - line.setStartXY(pt); - getXY(next, pt); - line.setEndXY(pt); - } else { - Point pt = new Point(); - queryPoint(vertex, pt); - line.setStart(pt); - queryPoint(next, pt); - line.setEnd(pt); - } - - return true; - } - - // Inserts an empty path before the given one. If before_path is -1, adds - // path at the end. - int insertPath(int geometry, int before_path) { - int prev = -1; - - if (before_path != -1) { - if (geometry != getGeometryFromPath(before_path)) - throw GeometryException.GeometryInternalError(); - - prev = getPrevPath(before_path); - } else - prev = getLastPath(geometry); - - int newpath = newPath_(geometry); - if (before_path != -1) - setPrevPath_(before_path, newpath); - - setNextPath_(newpath, before_path); - setPrevPath_(newpath, prev); - if (prev != -1) - setNextPath_(prev, newpath); - else - setFirstPath_(geometry, newpath); - - if (before_path == -1) - setLastPath_(geometry, newpath); - - setGeometryPathCount_(geometry, getPathCount(geometry) + 1); - return newpath; - } - - int insertClosedPath_(int geometry, int before_path, int first_vertex, int checked_vertex, boolean[] contains_checked_vertex) { - int path = insertPath(geometry, -1); - int path_size = 0; - int vertex = first_vertex; - boolean contains = false; - - while (true) { - if (vertex == checked_vertex) - contains = true; - - setPathToVertex_(vertex, path); - path_size++; - int next = getNextVertex(vertex); - assert (getNextVertex(getPrevVertex(vertex)) == vertex); - if (next == first_vertex) - break; - - vertex = next; - } - - setClosedPath(path, true); - setPathSize_(path, path_size); - if (contains) - first_vertex = checked_vertex; - - setFirstVertex_(path, first_vertex); - setLastVertex_(path, getPrevVertex(first_vertex)); - setRingAreaValid_(path, false); - - if (contains_checked_vertex != null) { - contains_checked_vertex[0] = contains; - } - - return path; - } - - - // Removes a path, gets rid of all its vertices, and returns the next one - int removePath(int path) { - int prev = getPrevPath(path); - int next = getNextPath(path); - int geometry = getGeometryFromPath(path); - if (prev != -1) - setNextPath_(prev, next); - else { - setFirstPath_(geometry, next); - } - if (next != -1) - setPrevPath_(next, prev); - else { - setLastPath_(geometry, prev); - } - - clearPath(path); - - setGeometryPathCount_(geometry, getPathCount(geometry) - 1); - freePath_(path); - return next; - } - - // Clears all vertices from the path - void clearPath(int path) { - int first_vertex = getFirstVertex(path); - if (first_vertex != -1) { - // TODO: can ve do this in one shot? - int vertex = first_vertex; - for (int i = 0, n = getPathSize(path); i < n; i++) { - int v = vertex; - vertex = getNextVertex(vertex); - freeVertex_(v); - } - int geometry = getGeometryFromPath(path); - setGeometryVertexCount_(geometry, getPointCount(geometry) - - getPathSize(path)); - } - setPathSize_(path, 0); - } - - // Returns the next path (-1 if there are no more paths in the geometry). - int getNextPath(int currentPath) { - return m_path_index_list.getField(currentPath, 2); - } - - // Returns the previous path (-1 if there are no more paths in the - // geometry). - int getPrevPath(int currentPath) { - return m_path_index_list.getField(currentPath, 1); - } - - // Returns the number of vertices in the path. - int getPathSize(int path) { - return m_path_index_list.getField(path, 3); - } - - // Returns True if the path is closed. - boolean isClosedPath(int path) { - return (getPathFlags_(path) & PathFlags_.closedPath) != 0; - } - - // Makes path closed. Closed paths are circular lists. get_next_vertex - // always succeeds - void setClosedPath(int path, boolean b_yes_no) { - if (isClosedPath(path) == b_yes_no) - return; - if (getPathSize(path) > 0) { - int first = getFirstVertex(path); - int last = getLastVertex(path); - if (b_yes_no) { - // make a circular list - setNextVertex_(last, first); - setPrevVertex_(first, last); - // set segment to NULL (just in case) - int vindex = getVertexIndex(last); - setSegmentToIndex_(vindex, null); - } else { - setNextVertex_(last, -1); - setPrevVertex_(first, -1); - int vindex = getVertexIndex(last); - setSegmentToIndex_(vindex, null); - } - } - - int oldflags = getPathFlags_(path); - int flags = (oldflags | (int) PathFlags_.closedPath) - - (int) PathFlags_.closedPath;// clear the bit; - setPathFlags_(path, flags - | (b_yes_no ? (int) PathFlags_.closedPath : 0)); - } - - // Closes all paths of the geometry (has to be a polyline or polygon). - void closeAllPaths(int geometry) { - if (getGeometryType(geometry) == Geometry.GeometryType.Polygon) - return; - if (!Geometry.isLinear(getGeometryType(geometry))) - throw GeometryException.GeometryInternalError(); - - for (int path = getFirstPath(geometry); path != -1; path = getNextPath(path)) { - setClosedPath(path, true); - } - } - - // Returns geometry from path - int getGeometryFromPath(int path) { - return m_path_index_list.getField(path, 7); - } - - // Returns True if the path is exterior. - boolean isExterior(int path) { - return (getPathFlags_(path) & PathFlags_.exteriorPath) != 0; - } - - // Sets exterior flag - void setExterior(int path, boolean b_yes_no) { - int oldflags = getPathFlags_(path); - int flags = (oldflags | (int) PathFlags_.exteriorPath) - - (int) PathFlags_.exteriorPath;// clear the bit; - setPathFlags_(path, flags - | (b_yes_no ? (int) PathFlags_.exteriorPath : 0)); - } - - // Returns the ring area - double getRingArea(int path) { - if (isRingAreaValid_(path)) - return m_path_areas.get(getPathIndex_(path)); - - Line line = new Line(); - int vertex = getFirstVertex(path); - if (vertex == -1) - return 0; - Point2D pt0 = new Point2D(); - getXY(vertex, pt0); - double area = 0; - for (int i = 0, n = getPathSize(path); i < n; i++, vertex = getNextVertex(vertex)) { - Segment seg = getSegment(vertex); - if (seg == null) { - if (!queryLineConnector(vertex, line)) - continue; - - seg = line; - } - - double a = seg._calculateArea2DHelper(pt0.x, pt0.y); - area += a; - } - - setRingAreaValid_(path, true); - m_path_areas.set(getPathIndex_(path), area); - - return area; - } - - // Sets value to the given user index on a path. - void setPathUserIndex(int path, int index, int value) { - AttributeStreamOfInt32 stream = m_pathindices.get(index); - int pindex = getPathIndex_(path); - if (stream.size() < m_path_areas.size()) - stream.resize(m_path_areas.size(), -1); - stream.write(pindex, value); - } - - // Returns the value of the given user index of a path - int getPathUserIndex(int path, int index) { - int pindex = getPathIndex_(path); - AttributeStreamOfInt32 stream = m_pathindices.get(index); - if (pindex < stream.size()) - return stream.read(pindex); - else - return -1; - } - - // Creates new user index on a path. The index have random values. The path - // index allows to store an integer user value on the path. - int createPathUserIndex() { - if (m_pathindices == null) - m_pathindices = new ArrayList(0); - // Try getting existing index. Use linear search. We do not expect many - // indices to be created. - for (int i = 0; i < m_pathindices.size(); i++) { - if (m_pathindices.get(i) == null) { - m_pathindices.set(i, - (AttributeStreamOfInt32) (AttributeStreamBase - .createIndexStream(0))); - return i; - } - } - - m_pathindices.add((AttributeStreamOfInt32) (AttributeStreamBase - .createIndexStream(0))); - return (int) (m_pathindices.size() - 1); - } - - // Removes the path user index. - void removePathUserIndex(int index) { - m_pathindices.set(index, null); - } - - // Moves a path from any geometry before a given path in the dst_geom - // geometry. The path_handle do not change after the operation. - // before_path can be -1, then the path is moved to the end of the dst_geom. - void movePath(int geom, int before_path, int path_to_move) { - if (path_to_move == -1) - throw new IllegalArgumentException(); - - if (before_path == path_to_move) - return; - - int next = getNextPath(path_to_move); - int prev = getPrevPath(path_to_move); - int geom_src = getGeometryFromPath(path_to_move); - if (prev == -1) { - setFirstPath_(geom_src, next); - } else { - setNextPath_(prev, next); - } - - if (next == -1) { - setLastPath_(geom_src, prev); - } else { - setPrevPath_(next, prev); - } - - setGeometryVertexCount_(geom_src, getPointCount(geom_src) - - getPathSize(path_to_move)); - setGeometryPathCount_(geom_src, getPathCount(geom_src) - 1); - - if (before_path == -1) - prev = getLastPath(geom); - else - prev = getPrevPath(before_path); - - setPrevPath_(path_to_move, prev); - setNextPath_(path_to_move, before_path); - if (before_path == -1) - setLastPath_(geom, path_to_move); - else - setPrevPath_(before_path, path_to_move); - if (prev == -1) - setFirstPath_(geom, path_to_move); - else - setNextPath_(prev, path_to_move); - setGeometryVertexCount_(geom, getPointCount(geom) - + getPathSize(path_to_move)); - setGeometryPathCount_(geom, getPathCount(geom) + 1); - setPathGeometry_(path_to_move, geom); - } - - // Adds a copy of a vertex to a path. Connects with a straight line. - // Returns new vertex handle. - int addVertex(int path, int vertex) { - m_vertices.getPointByVal(getVertexIndex(vertex), getHelperPoint_()); - return insertVertex_(path, -1, getHelperPoint_()); - } - - // Removes vertex from path. Uses either left or right segments to - // reconnect. Returns next vertex after erased one. - int removeVertex(int vertex, boolean b_left_segment) { - int path = getPathFromVertex(vertex); - int prev = getPrevVertex(vertex); - int next = getNextVertex(vertex); - if (prev != -1) - setNextVertex_(prev, next); - - int path_size = getPathSize(path); - - if (vertex == getFirstVertex(path)) { - setFirstVertex_(path, path_size > 1 ? next : -1); - } - - if (next != -1) - setPrevVertex_(next, prev); - - if (vertex == getLastVertex(path)) { - setLastVertex_(path, path_size > 1 ? prev : -1); - } - - if (prev != -1 && next != -1) { - int vindex_prev = getVertexIndex(prev); - int vindex_next = getVertexIndex(next); - if (b_left_segment) { - Segment seg = getSegmentFromIndex_(vindex_prev); - if (seg != null) { - Point2D pt = new Point2D(); - m_vertices.getXY(vindex_next, pt); - seg.setEndXY(pt); - } - } else { - int vindex_erased = getVertexIndex(vertex); - Segment seg = getSegmentFromIndex_(vindex_erased); - setSegmentToIndex_(vindex_prev, seg); - if (seg != null) { - Point2D pt = m_vertices.getXY(vindex_prev); - seg.setStartXY(pt); - } - } - } - - setPathSize_(path, path_size - 1); - int geometry = getGeometryFromPath(path); - setGeometryVertexCount_(geometry, getPointCount(geometry) - 1); - freeVertex_(vertex); - return next; - } - - // Returns first vertex of the given path. - int getFirstVertex(int path) { - return m_path_index_list.getField(path, 4); - } - - // Returns last vertex of the given path. For the closed paths - // get_next_vertex for the last vertex returns the first vertex. - int getLastVertex(int path) { - return m_path_index_list.getField(path, 5); - } - - // Returns next vertex. Closed paths are circular lists, so get_next_vertex - // always returns vertex. Open paths return -1 for last vertex. - int getNextVertex(int currentVertex) { - return m_vertex_index_list.getField(currentVertex, 2); - } - - // Returns previous vertex. Closed paths are circular lists, so - // get_prev_vertex always returns vertex. Open paths return -1 for first - // vertex. - int getPrevVertex(int currentVertex) { - return m_vertex_index_list.getField(currentVertex, 1); - } - - int getPrevVertex(int currentVertex, int dir) { - return dir > 0 ? m_vertex_index_list.getField(currentVertex, 1) : m_vertex_index_list.getField(currentVertex, 2); - } - - int getNextVertex(int currentVertex, int dir) { - return dir > 0 ? m_vertex_index_list.getField(currentVertex, 2) : m_vertex_index_list.getField(currentVertex, 1); - } - - // Returns a path the vertex belongs to. - int getPathFromVertex(int vertex) { - return m_vertex_index_list.getField(vertex, 3); - } - - // Adds a copy of the point to a path. Connects with a straight line. - // Returns new vertex handle. - int addPoint(int path, Point point) { - return insertVertex_(path, -1, point); - } - - // Vertex iterator allows to go through all vertices of the Edit_shape. - static class VertexIterator { - private EditShape m_parent; - private int m_geometry; - private int m_path; - private int m_vertex; - private int m_first_vertex; - private int m_index; - boolean m_b_first; - boolean m_b_skip_mulit_points; - - private VertexIterator(EditShape parent, int geometry, int path, - int vertex, int first_vertex, int index, - boolean b_skip_mulit_points) { - m_parent = parent; - m_geometry = geometry; - m_path = path; - m_vertex = vertex; - m_index = index; - m_b_skip_mulit_points = b_skip_mulit_points; - m_first_vertex = first_vertex; - m_b_first = true; - } - - int moveToNext_() { - if (m_b_first) { - m_b_first = false; - return m_vertex; - } - - if (m_vertex != -1) { - m_vertex = m_parent.getNextVertex(m_vertex); - m_index++; - if (m_vertex != -1 && m_vertex != m_first_vertex) - return m_vertex; - - return moveToNextHelper_();// separate into another function for - // inlining - } - - return -1; - } - - int moveToNextHelper_() { - m_path = m_parent.getNextPath(m_path); - m_index = 0; - while (m_geometry != -1) { - for (; m_path != -1; m_path = m_parent.getNextPath(m_path)) { - m_vertex = m_parent.getFirstVertex(m_path); - m_first_vertex = m_vertex; - if (m_vertex != -1) - return m_vertex; - } - - m_geometry = m_parent.getNextGeometry(m_geometry); - if (m_geometry == -1) - break; - - if (m_b_skip_mulit_points - && !Geometry.isMultiPath(m_parent - .getGeometryType(m_geometry))) { - continue; - } - - m_path = m_parent.getFirstPath(m_geometry); - } - - return -1; - } - - // moves to next vertex. Returns -1 when there are no more vertices. - VertexIterator(VertexIterator source) { - m_parent = source.m_parent; - m_geometry = source.m_geometry; - m_path = source.m_path; - m_vertex = source.m_vertex; - m_index = source.m_index; - m_b_skip_mulit_points = source.m_b_skip_mulit_points; - m_first_vertex = source.m_first_vertex; - m_b_first = true; - } - - public int next() { - return moveToNext_(); - } - - public int currentGeometry() { - assert (m_vertex != -1); - return m_geometry; - } - - public int currentPath() { - assert (m_vertex != -1); - return m_path; - } - - public static VertexIterator create_(EditShape parent, int geometry, - int path, int vertex, int first_vertex, int index, - boolean b_skip_mulit_points) { - return new VertexIterator(parent, geometry, path, vertex, - first_vertex, index, b_skip_mulit_points); - } - } - - ; - - // Returns the vertex iterator that allows iteration through all vertices of - // all paths of all geometries. - VertexIterator queryVertexIterator() { - return queryVertexIterator(false); - } - - VertexIterator queryVertexIterator(VertexIterator source) { - return new VertexIterator(source); - } - - // Returns the vertex iterator that allows iteration through all vertices of - // all paths of all geometries. - // If bSkipMultiPoints is true, then the iterator will skip the Multi_point - // vertices - VertexIterator queryVertexIterator(boolean b_skip_multi_points) { - int geometry = -1; - int path = -1; - int vertex = -1; - int first_vertex = -1; - int index = 0; - boolean bFound = false; - - for (geometry = getFirstGeometry(); geometry != -1; geometry = getNextGeometry(geometry)) { - if (b_skip_multi_points - && !Geometry.isMultiPath(getGeometryType(geometry))) - continue; - - for (path = getFirstPath(geometry); path != -1; path = getNextPath(path)) { - vertex = getFirstVertex(path); - first_vertex = vertex; - index = 0; - if (vertex == -1) - continue; - - bFound = true; - break; - } - - if (bFound) - break; - } - - return VertexIterator.create_(this, geometry, path, vertex, - first_vertex, index, b_skip_multi_points); - } - - // Applies affine transformation - void applyTransformation(Transformation2D transform) { - m_vertices_mp.applyTransformation(transform); - if (m_segments != null) { - for (int i = 0, n = m_segments.size(); i < n; i++) { - if (m_segments.get(i) != null) { - m_segments.get(i).applyTransformation(transform); - } - } - } - } - - void interpolateAttributesForClosedPath_(int semantics, int path, - int from_vertex, int to_vertex, double sub_length, int ordinate) { - if (from_vertex == to_vertex) - return; - - double from_attribute = getAttributeAsDbl(semantics, from_vertex, - ordinate); - double to_attribute = getAttributeAsDbl(semantics, to_vertex, ordinate); - double cumulative_length = 0.0; - double prev_interpolated_attribute = from_attribute; - - for (int vertex = from_vertex; vertex != to_vertex; vertex = getNextVertex(vertex)) { - setAttribute(semantics, vertex, ordinate, - prev_interpolated_attribute); - - int vertex_index = getVertexIndex(vertex); - Segment segment = getSegmentFromIndex_(vertex_index); - double segment_length; - - if (segment != null) { - segment_length = segment.calculateLength2D(); - } else { - int next_vertex_index = getVertexIndex(getNextVertex(vertex)); - segment_length = m_vertices._getShortestDistance(vertex_index, - next_vertex_index); - } - cumulative_length += segment_length; - double t = cumulative_length / sub_length; - prev_interpolated_attribute = MathUtils.lerp(from_attribute, to_attribute, t); - } - - return; - } - - void SetGeometryType_(int geom, int gt) { - m_geometry_index_list.setField(geom, 2, gt); - } - - void splitSegment_(int origin_vertex, SegmentIntersector intersector, - int intersector_index, boolean b_forward) { - if (b_forward) { - splitSegmentForward_(origin_vertex, intersector, intersector_index); - } else { - splitSegmentBackward_(origin_vertex, intersector, intersector_index); - } - } - - void setPrevVertex_(int vertex, int prev) { - m_vertex_index_list.setField(vertex, 1, prev); - } - - void setNextVertex_(int vertex, int next) { - m_vertex_index_list.setField(vertex, 2, next); - } - - void setPathToVertex_(int vertex, int path) { - m_vertex_index_list.setField(vertex, 3, path); - } - - void setPathSize_(int path, int size) { - m_path_index_list.setField(path, 3, size); - } - - void setFirstVertex_(int path, int first_vertex) { - m_path_index_list.setField(path, 4, first_vertex); - } - - void setLastVertex_(int path, int last_vertex) { - m_path_index_list.setField(path, 5, last_vertex); - } - - void setGeometryPathCount_(int geom, int path_count) { - m_geometry_index_list.setField(geom, 6, path_count); - } - - void setGeometryVertexCount_(int geom, int vertex_count) { - m_geometry_index_list.setField(geom, 5, vertex_count); - } - - boolean ringParentageCheckInternal_(int vertex_1, int vertex_2) { - if (vertex_1 == vertex_2) - return true; - int vprev_1 = vertex_1; - int vprev_2 = vertex_2; - for (int v_1 = getNextVertex(vertex_1), v_2 = getNextVertex(vertex_2); v_1 != vertex_1 - && v_2 != vertex_2; v_1 = getNextVertex(v_1), v_2 = getNextVertex(v_2)) { - if (v_1 == vertex_2) - return true; - if (v_2 == vertex_1) - return true; - - assert (getPrevVertex(v_1) == vprev_1);// detect malformed list - assert (getPrevVertex(v_2) == vprev_2);// detect malformed list - vprev_1 = v_1; - vprev_2 = v_2; - } - - return false; - } - - void reverseRingInternal_(int vertex) { - int v = vertex; - do { - int prev = getPrevVertex(v); - int next = getNextVertex(v); - setNextVertex_(v, prev); - setPrevVertex_(v, next); - v = next; - } while (v != vertex); - // Path's last becomes invalid. Do not attempt to fix it here, because - // this is not the intent of the method - // Note: only last is invalid. other things sould not change. - } - - void setTotalPointCount_(int count) { - m_point_count = count; - } - - void removePathOnly_(int path) { - int prev = getPrevPath(path); - int next = getNextPath(path); - int geometry = getGeometryFromPath(path); - if (prev != -1) - setNextPath_(prev, next); - else { - setFirstPath_(geometry, next); - } - if (next != -1) - setPrevPath_(next, prev); - else { - setLastPath_(geometry, prev); - } - - setFirstVertex_(path, -1); - setLastVertex_(path, -1); - freePath_(path); - } - - // void DbgVerifyIntegrity(int vertex); - // void dbg_verify_vertex_counts(); - int removeVertexInternal_(int vertex, boolean b_left_segment) { - int prev = getPrevVertex(vertex); - int next = getNextVertex(vertex); - if (prev != -1) - setNextVertex_(prev, next); - - if (next != -1) - setPrevVertex_(next, prev); - - if (prev != -1 && next != -1) { - int vindex_prev = getVertexIndex(prev); - int vindex_next = getVertexIndex(next); - if (b_left_segment) { - Segment seg = getSegmentFromIndex_(vindex_prev); - if (seg != null) { - Point2D pt = new Point2D(); - m_vertices.getXY(vindex_next, pt); - seg.setEndXY(pt); - } - } else { - int vindex_erased = getVertexIndex(vertex); - Segment seg = getSegmentFromIndex_(vindex_erased); - setSegmentToIndex_(vindex_prev, seg); - if (seg != null) { - Point2D pt = new Point2D(); - m_vertices.getXY(vindex_prev, pt); - seg.setStartXY(pt); - } - } - } - freeVertex_(vertex); - return next; - } - - boolean isRingAreaValid_(int path) { - return (getPathFlags_(path) & PathFlags_.ringAreaValid) != 0; - } - - // Sets exterior flag - void setRingAreaValid_(int path, boolean b_yes_no) { - int oldflags = getPathFlags_(path); - int flags = (oldflags | (int) PathFlags_.ringAreaValid) - - (int) PathFlags_.ringAreaValid;// clear the bit; - setPathFlags_(path, flags - | (b_yes_no ? (int) PathFlags_.ringAreaValid : 0)); - } - - int compareVerticesSimpleY_(int v_1, int v_2) { - Point2D pt_1 = new Point2D(); - getXY(v_1, pt_1); - Point2D pt_2 = new Point2D(); - getXY(v_2, pt_2); - int res = pt_1.compare(pt_2); - return res; - } - - int compareVerticesSimpleX_(int v_1, int v_2) { - Point2D pt_1 = new Point2D(); - getXY(v_1, pt_1); - Point2D pt_2 = new Point2D(); - getXY(v_2, pt_2); - int res = pt_1.compare(pt_2); - return res; - } - - public static class SimplificatorVertexComparerY extends - AttributeStreamOfInt32.IntComparator { - EditShape parent; - - SimplificatorVertexComparerY(EditShape parent_) { - parent = parent_; - } - - @Override - public int compare(int i_1, int i_2) { - return parent.compareVerticesSimpleY_(i_1, i_2); - } - } - - public static class SimplificatorVertexComparerX extends - AttributeStreamOfInt32.IntComparator { - EditShape parent; - - SimplificatorVertexComparerX(EditShape parent_) { - parent = parent_; - } - - @Override - public int compare(int i_1, int i_2) { - return parent.compareVerticesSimpleX_(i_1, i_2); - } - } - - // void sort_vertices_simple_by_y_heap_merge(Dynamic_array& points, - // const Dynamic_array* geoms); - - void sortVerticesSimpleByY_(AttributeStreamOfInt32 points, int begin_, - int end_) { - if (m_bucket_sort == null) - m_bucket_sort = new BucketSort(); - m_bucket_sort.sort(points, begin_, end_, new EditShapeBucketSortHelper( - this)); - } - - void sortVerticesSimpleByYHelper_(AttributeStreamOfInt32 points, - int begin_, int end_) { - points.Sort(begin_, end_, new SimplificatorVertexComparerY(this)); - } - - void sortVerticesSimpleByX_(AttributeStreamOfInt32 points, int begin_, - int end_) { - points.Sort(begin_, end_, new SimplificatorVertexComparerX(this)); - } - - // Approximate size of the structure in memory. - // The estimated size can be very slightly less than the actual size. - // int estimate_memory_size() const; - - boolean hasPointFeatures() { - for (int geometry = getFirstGeometry(); geometry != -1; geometry = getNextGeometry(geometry)) { - if (!Geometry.isMultiPath(getGeometryType(geometry))) - return true; - } - return false; - } - - void swapGeometry(int geom1, int geom2) { - int first_path1 = getFirstPath(geom1); - int first_path2 = getFirstPath(geom2); - int last_path1 = getLastPath(geom1); - int last_path2 = getLastPath(geom2); - - for (int path = getFirstPath(geom1); path != -1; path = getNextPath(path)) { - setPathGeometry_(path, geom2); - } - - for (int path = getFirstPath(geom2); path != -1; path = getNextPath(path)) { - setPathGeometry_(path, geom1); - } - - setFirstPath_(geom1, first_path2); - setFirstPath_(geom2, first_path1); - setLastPath_(geom1, last_path2); - setLastPath_(geom2, last_path1); - - int vc1 = getPointCount(geom1); - int pc1 = getPathCount(geom1); - int vc2 = getPointCount(geom2); - int pc2 = getPathCount(geom2); - - setGeometryVertexCount_(geom1, vc2); - setGeometryVertexCount_(geom2, vc1); - setGeometryPathCount_(geom1, pc2); - setGeometryPathCount_(geom2, pc1); - - int gt1 = m_geometry_index_list.getField(geom1, 2); - int gt2 = m_geometry_index_list.getField(geom2, 2); - m_geometry_index_list.setField(geom1, 2, gt2); - m_geometry_index_list.setField(geom2, 2, gt1); - } + interface PathFlags_ { + static final int closedPath = 1; + static final int exteriorPath = 2; + static final int ringAreaValid = 4; + } + + private int m_geometryCount; + private int m_path_count; + private int m_point_count; + private int m_first_geometry; + private int m_last_geometry; + + private StridedIndexTypeCollection m_vertex_index_list; + + // ****************Vertex Data****************** + private MultiPoint m_vertices_mp; // vertex coordinates are stored here + // Attribute_stream_of_index_type::SPtr m_indexRemap; + private MultiPointImpl m_vertices; // Internals of m_vertices_mp + AttributeStreamOfDbl m_xy_stream; // The xy stream of the m_vertices. + VertexDescription m_vertex_description;// a shortcut to the vertex + // description. + boolean m_b_has_attributes; // a short cut to know if we have something in + // addition to x and y. + + ArrayList m_segments;// may be NULL if all segments a Lines, + // otherwise contains NULLs for Line + // segments. Curves are not NULL. + AttributeStreamOfDbl m_weights;// may be NULL if no weights are provided. + // NULL weights assumes weight value of 1. + ArrayList m_indices;// user indices are here + // ****************End Vertex Data************** + StridedIndexTypeCollection m_path_index_list; // doubly connected list. Path + // index into the Path Data + // arrays, Prev path, next + // path. + // ******************Path Data****************** + AttributeStreamOfDbl m_path_areas; + AttributeStreamOfDbl m_path_lengths; + // Block_array::SPtr m_path_envelopes; + ArrayList m_pathindices;// path user indices are + // here + // *****************End Path Data*************** + StridedIndexTypeCollection m_geometry_index_list; + ArrayList m_geometry_indices;// geometry user + // indices are here + + // *********** Helpers for Bucket sort************** + static class EditShapeBucketSortHelper extends ClassicSort { + EditShape m_shape; + + EditShapeBucketSortHelper(EditShape shape) { + m_shape = shape; + } + + @Override + public void userSort(int begin, int end, AttributeStreamOfInt32 indices) { + m_shape.sortVerticesSimpleByYHelper_(indices, begin, end); + } + + @Override + public double getValue(int index) { + return m_shape.getY(index); + } + }; + + BucketSort m_bucket_sort; + + // Envelope::SPtr m_envelope; //the BBOX for all attributes + Point m_helper_point; // a helper point for intermediate operations + + Segment getSegmentFromIndex_(int vindex) { + return m_segments != null ? m_segments.get(vindex) : null; + } + + void setSegmentToIndex_(int vindex, Segment seg) { + if (m_segments == null) { + if (seg == null) + return; + m_segments = new ArrayList(); + for (int i = 0, n = m_vertices.getPointCount(); i < n; i++) + m_segments.add(null); + } + m_segments.set(vindex, seg); + } + + void setPrevPath_(int path, int prev) { + m_path_index_list.setField(path, 1, prev); + } + + void setNextPath_(int path, int next) { + m_path_index_list.setField(path, 2, next); + } + + void setPathFlags_(int path, int flags) { + m_path_index_list.setField(path, 6, flags); + } + + int getPathFlags_(int path) { + return m_path_index_list.getField(path, 6); + } + + void setPathGeometry_(int path, int geom) { + m_path_index_list.setField(path, 7, geom); + } + + int getPathIndex_(int path) { + return m_path_index_list.getField(path, 0); + } + + void setNextGeometry_(int geom, int next) { + m_geometry_index_list.setField(geom, 1, next); + } + + void setPrevGeometry_(int geom, int prev) { + m_geometry_index_list.setField(geom, 0, prev); + } + + int getGeometryIndex_(int geom) { + return m_geometry_index_list.getField(geom, 7); + } + + int getFirstPath_(int geom) { + return m_geometry_index_list.getField(geom, 3); + } + + void setFirstPath_(int geom, int firstPath) { + m_geometry_index_list.setField(geom, 3, firstPath); + } + + void setLastPath_(int geom, int path) { + m_geometry_index_list.setField(geom, 4, path); + } + + int newGeometry_(int gt) { + // Index_type index = m_first_free_geometry; + if (m_geometry_index_list == null) + m_geometry_index_list = new StridedIndexTypeCollection(8); + + int index = m_geometry_index_list.newElement(); + // m_geometry_index_list.set(index + 0, -1);//prev + // m_geometry_index_list.set(index + 1, -1);//next + m_geometry_index_list.setField(index, 2, gt);// Geometry_type + // m_geometry_index_list.set(index + 3, -1);//first path + // m_geometry_index_list.set(index + 4, -1);//last path + m_geometry_index_list.setField(index, 5, 0);// point count + m_geometry_index_list.setField(index, 6, 0);// path count + m_geometry_index_list.setField(index, 7, + m_geometry_index_list.elementToIndex(index));// geometry index + + return index; + } + + void freeGeometry_(int geom) { + m_geometry_index_list.deleteElement(geom); + } + + int newPath_(int geom) { + if (m_path_index_list == null) { + m_path_index_list = new StridedIndexTypeCollection(8); + m_vertex_index_list = new StridedIndexTypeCollection(5); + m_path_areas = new AttributeStreamOfDbl(0); + m_path_lengths = new AttributeStreamOfDbl(0); + } + + int index = m_path_index_list.newElement(); + int pindex = m_path_index_list.elementToIndex(index); + m_path_index_list.setField(index, 0, pindex);// size + // m_path_index_list.set(index + 1, -1);//prev + // m_path_index_list.set(index + 2, -1);//next + m_path_index_list.setField(index, 3, 0);// size + // m_path_index_list.set(index + 4, -1);//first vertex handle + // m_path_index_list.set(index + 5, -1);//last vertex handle + m_path_index_list.setField(index, 6, 0);// path flags + setPathGeometry_(index, geom); + if (pindex >= m_path_areas.size()) { + int sz = pindex < 16 ? 16 : (pindex * 3) / 2; + m_path_areas.resize(sz); + m_path_lengths.resize(sz); + // if (m_path_envelopes) + // m_path_envelopes.resize(sz); + } + m_path_areas.set(pindex, 0); + m_path_lengths.set(pindex, 0); + // if (m_path_envelopes) + // m_path_envelopes.set(pindex, nullptr); + + m_path_count++; + return index; + } + + void freePath_(int path) { + m_path_index_list.deleteElement(path); + m_path_count--; + } + + void freeVertex_(int vertex) { + m_vertex_index_list.deleteElement(vertex); + m_point_count--; + } + + int newVertex_(int vindex) { + assert (vindex >= 0 || vindex == -1);// vindex is not a handle + + if (m_path_index_list == null) { + m_path_index_list = new StridedIndexTypeCollection(8); + m_vertex_index_list = new StridedIndexTypeCollection(5); + m_path_areas = new AttributeStreamOfDbl(0); + m_path_lengths = new AttributeStreamOfDbl(0); + } + + int index = m_vertex_index_list.newElement(); + int vi = vindex >= 0 ? vindex : m_vertex_index_list + .elementToIndex(index); + m_vertex_index_list.setField(index, 0, vi); + if (vindex < 0) { + if (vi >= m_vertices.getPointCount()) { + int sz = vi < 16 ? 16 : (vi * 3) / 2; + // m_vertices.reserveRounded(sz); + m_vertices.resize(sz); + if (m_segments != null) { + for (int i = 0; i < sz; i++) + m_segments.add(null); + } + + if (m_weights != null) + m_weights.resize(sz); + + m_xy_stream = (AttributeStreamOfDbl) m_vertices + .getAttributeStreamRef(VertexDescription.Semantics.POSITION); + } + + m_vertices.setXY(vi, -1e38, -1e38); + + if (m_segments != null) + m_segments.set(vi, null); + + if (m_weights != null) + m_weights.write(vi, 1.0); + } else { + // We do not set vertices or segments here, because we assume those + // are set correctly already. + // We only here to create linked list of indices on existing vertex + // value. + // m_segments->set(m_point_count, nullptr); + } + + m_vertex_index_list.setField(index, 4, vi * 2); + m_point_count++; + return index; + } + + void free_vertex_(int vertex) { + m_vertex_index_list.deleteElement(vertex); + m_point_count--; + } + + int insertVertex_(int path, int before, Point point) { + int prev = before != -1 ? getPrevVertex(before) : getLastVertex(path); + int next = prev != -1 ? getNextVertex(prev) : -1; + + int vertex = newVertex_(point == null ? m_point_count : -1); + int vindex = getVertexIndex(vertex); + if (point != null) + m_vertices.setPointByVal(vindex, point); + + setPathToVertex_(vertex, path); + setNextVertex_(vertex, next); + setPrevVertex_(vertex, prev); + + if (next != -1) + setPrevVertex_(next, vertex); + + if (prev != -1) + setNextVertex_(prev, vertex); + + boolean b_closed = isClosedPath(path); + int first = getFirstVertex(path); + if (before == -1) + setLastVertex_(path, vertex); + + if (before == first) + setFirstVertex_(path, vertex); + + if (b_closed && next == -1) { + setNextVertex_(vertex, vertex); + setPrevVertex_(vertex, vertex); + } + + setPathSize_(path, getPathSize(path) + 1); + int geometry = getGeometryFromPath(path); + setGeometryVertexCount_(geometry, getPointCount(geometry) + 1); + + return vertex; + } + + Point getHelperPoint_() { + if (m_helper_point == null) + m_helper_point = new Point(m_vertices.getDescription()); + return m_helper_point; + } + + void setFillRule(int geom, int rule) { + int t = m_geometry_index_list.getField(geom, 2); + t &= ~(0x8000000); + t |= rule == Polygon.FillRule.enumFillRuleWinding ? 0x8000000 : 0; + m_geometry_index_list.setField(geom, 2, t);//fill rule combined with geometry type + } + + int getFillRule(int geom) { + int t = m_geometry_index_list.getField(geom, 2); + return (t & 0x8000000) != 0 ? Polygon.FillRule.enumFillRuleWinding : Polygon.FillRule.enumFillRuleOddEven; + } + + int addMultiPath_(MultiPath multi_path) { + int newgeom = createGeometry(multi_path.getType(), + multi_path.getDescription()); + if (multi_path.getType() == Geometry.Type.Polygon) + setFillRule(newgeom, ((Polygon)multi_path).getFillRule()); + + appendMultiPath_(newgeom, multi_path); + return newgeom; + } + + int addMultiPoint_(MultiPoint multi_point) { + int newgeometry = createGeometry(multi_point.getType(), + multi_point.getDescription()); + appendMultiPoint_(newgeometry, multi_point); + return newgeometry; + } + + void appendMultiPath_(int dstGeom, MultiPath multi_path) { + MultiPathImpl mp_impl = (MultiPathImpl) multi_path._getImpl(); + // m_vertices->reserve_rounded(m_vertices->get_point_count() + + // mp_impl->get_point_count());//ensure reallocation happens by blocks + // so that already allocated vertices do not get reallocated. + m_vertices_mp.add(multi_path, 0, mp_impl.getPointCount()); + m_xy_stream = (AttributeStreamOfDbl) m_vertices + .getAttributeStreamRef(VertexDescription.Semantics.POSITION); + boolean b_some_segments = m_segments != null + && mp_impl.getSegmentFlagsStreamRef() != null; + + for (int ipath = 0, npath = mp_impl.getPathCount(); ipath < npath; ipath++) { + if (mp_impl.getPathSize(ipath) < 2) // CR249862 - Clipping geometry + // which has empty part produces + // a crash + continue; + + int path = insertPath(dstGeom, -1); + setClosedPath(path, mp_impl.isClosedPath(ipath)); + for (int ivertex = mp_impl.getPathStart(ipath), iend = mp_impl + .getPathEnd(ipath); ivertex < iend; ivertex++) { + int vertex = insertVertex_(path, -1, null); + if (b_some_segments) { + int vindex = getVertexIndex(vertex); + if ((mp_impl.getSegmentFlags(ivertex) & (byte) SegmentFlags.enumLineSeg) != 0) { + setSegmentToIndex_(vindex, null); + } else { + SegmentBuffer seg_buffer = new SegmentBuffer(); + mp_impl.getSegment(ivertex, seg_buffer, true); + setSegmentToIndex_(vindex, seg_buffer.get()); + } + } + } + } + + // {//debug + // #ifdef DEBUG + // for (Index_type geometry = get_first_geometry(); geometry != -1; + // geometry = get_next_geometry(geometry)) + // { + // for (Index_type path = get_first_path(geometry); path != -1; path = + // get_next_path(path)) + // { + // Index_type first = get_first_vertex(path); + // Index_type v = first; + // for (get_next_vertex(v); v != first; v = get_next_vertex(v)) + // { + // assert(get_next_vertex(get_prev_vertex(v)) == v); + // } + // } + // } + // #endif + // } + } + + void appendMultiPoint_(int dstGeom, MultiPoint multi_point) { + // m_vertices->reserve_rounded(m_vertices->get_point_count() + + // multi_point.get_point_count());//ensure reallocation happens by + // blocks so that already allocated vertices do not get reallocated. + m_vertices_mp.add(multi_point, 0, multi_point.getPointCount()); + m_xy_stream = (AttributeStreamOfDbl) m_vertices + .getAttributeStreamRef(VertexDescription.Semantics.POSITION); + + int path = insertPath(dstGeom, -1); + for (int ivertex = 0, iend = multi_point.getPointCount(); ivertex < iend; ivertex++) { + insertVertex_(path, -1, null); + } + } + + void splitSegmentForward_(int origin_vertex, + SegmentIntersector intersector, int intersector_index) { + int last_vertex = getNextVertex(origin_vertex); + if (last_vertex == -1) + throw GeometryException.GeometryInternalError(); + Point point = getHelperPoint_(); + int path = getPathFromVertex(origin_vertex); + int vertex = origin_vertex; + for (int i = 0, n = intersector + .getResultSegmentCount(intersector_index); i < n; i++) { + int vindex = getVertexIndex(vertex); + int next_vertex = getNextVertex(vertex); + Segment seg = intersector.getResultSegment(intersector_index, i); + + if (i == 0) { + seg.queryStart(point); + // #ifdef DEBUG + // Point2D pt = new Point2D(); + // getXY(vertex, pt); + // assert(Point2D.distance(point.getXY(), pt) <= + // intersector.get_tolerance_()); + // #endif + setPoint(vertex, point); + } + + if (seg.getType().value() == Geometry.GeometryType.Line) + setSegmentToIndex_(vindex, null); + else + setSegmentToIndex_(vindex, (Segment) Geometry._clone(seg)); + + seg.queryEnd(point); + if (i < n - 1) { + int inserted_vertex = insertVertex_(path, next_vertex, point); + vertex = inserted_vertex; + } else { + // #ifdef DEBUG + // Point_2D pt; + // get_xy(last_vertex, pt); + // assert(Point_2D::distance(point->get_xy(), pt) <= + // intersector.getTolerance_()); + // #endif + setPoint(last_vertex, point); + assert (last_vertex == next_vertex); + } + } + } + + void splitSegmentBackward_(int origin_vertex, + SegmentIntersector intersector, int intersector_index) { + int last_vertex = getNextVertex(origin_vertex); + if (last_vertex == -1) + throw GeometryException.GeometryInternalError(); + + Point point = getHelperPoint_(); + int path = getPathFromVertex(origin_vertex); + int vertex = origin_vertex; + for (int i = 0, n = intersector + .getResultSegmentCount(intersector_index); i < n; i++) { + int vindex = getVertexIndex(vertex); + int next_vertex = getNextVertex(vertex); + Segment seg = intersector.getResultSegment(intersector_index, n - i + - 1); + + if (i == 0) { + seg.queryEnd(point); + // #ifdef DEBUG + // Point2D pt = new Point2D(); + // getXY(vertex, pt); + // assert(Point2D.distance(point.getXY(), pt) <= + // intersector.getTolerance_()); + // #endif + setPoint(vertex, point); + } + + if (seg.getType().value() == Geometry.GeometryType.Line) + setSegmentToIndex_(vindex, null); + else + setSegmentToIndex_(vindex, (Segment) Geometry._clone(seg)); + + seg.queryStart(point); + if (i < n - 1) { + int inserted_vertex = insertVertex_(path, next_vertex, point); + vertex = inserted_vertex; + } else { + // #ifdef DEBUG + // Point2D pt = new Point2D(); + // getXY(last_vertex, pt); + // assert(Point2D.distance(point.getXY(), pt) <= + // intersector.getTolerance_()); + // #endif + setPoint(last_vertex, point); + assert (last_vertex == next_vertex); + } + } + } + + EditShape() { + m_path_count = 0; + m_first_geometry = -1; + m_last_geometry = -1; + m_point_count = 0; + m_geometryCount = 0; + m_b_has_attributes = false; + m_vertices = null; + m_xy_stream = null; + m_vertex_description = null; + } + + // Total point count in all geometries + int getTotalPointCount() { + return m_point_count; + } + + // Returns envelope of all coordinates. + Envelope2D getEnvelope2D() { + Envelope2D env = new Envelope2D(); + env.setEmpty(); + VertexIterator vert_iter = queryVertexIterator(); + Point2D pt = new Point2D(); + boolean b_first = true; + for (int ivertex = vert_iter.next(); ivertex != -1; ivertex = vert_iter + .next()) { + getXY(ivertex, pt); + if (b_first) + env.merge(pt.x, pt.y); + else + env.mergeNE(pt.x, pt.y); + + b_first = false; + } + + return env; + } + + // Returns geometry count in the edit shape + int getGeometryCount() { + return m_geometryCount; + } + + // Adds a Geometry to the Edit_shape + int addGeometry(Geometry geometry) { + Geometry.Type gt = geometry.getType(); + if (Geometry.isMultiPath(gt.value())) + return addMultiPath_((MultiPath) geometry); + if (gt == Geometry.Type.MultiPoint) + return addMultiPoint_((MultiPoint) geometry); + + throw GeometryException.GeometryInternalError(); + } + + // Append a Geometry to the given geometry of the Edit_shape + void appendGeometry(int dstGeometry, Geometry srcGeometry) { + Geometry.Type gt = srcGeometry.getType(); + if (Geometry.isMultiPath(gt.value())) { + appendMultiPath_(dstGeometry, (MultiPath) srcGeometry); + return; + } else if (gt.value() == Geometry.GeometryType.MultiPoint) { + appendMultiPoint_(dstGeometry, (MultiPoint) srcGeometry); + return; + } + + throw GeometryException.GeometryInternalError(); + } + + // Adds a path + int addPathFromMultiPath(MultiPath multi_path, int ipath, boolean as_polygon) { + int newgeom = createGeometry(as_polygon ? Geometry.Type.Polygon + : Geometry.Type.Polyline, multi_path.getDescription()); + + MultiPathImpl mp_impl = (MultiPathImpl) multi_path._getImpl(); + if (multi_path.getPathSize(ipath) < 2) + return newgeom; //return empty geometry + + // m_vertices->reserve_rounded(m_vertices->get_point_count() + + // multi_path.get_path_size(ipath));//ensure reallocation happens by + // blocks so that already allocated vertices do not get reallocated. + m_vertices_mp.add(multi_path, multi_path.getPathStart(ipath), + mp_impl.getPathEnd(ipath)); + m_xy_stream = (AttributeStreamOfDbl) m_vertices + .getAttributeStreamRef(VertexDescription.Semantics.POSITION); + + int path = insertPath(newgeom, -1); + setClosedPath(path, mp_impl.isClosedPath(ipath) || as_polygon); + + boolean b_some_segments = m_segments != null + && mp_impl.getSegmentFlagsStreamRef() != null; + + for (int ivertex = mp_impl.getPathStart(ipath), iend = mp_impl + .getPathEnd(ipath); ivertex < iend; ivertex++) { + int vertex = insertVertex_(path, -1, null); + if (b_some_segments) { + int vindex = getVertexIndex(vertex); + if ((mp_impl.getSegmentFlags(ivertex) & SegmentFlags.enumLineSeg) != 0) { + setSegmentToIndex_(vindex, null); + } else { + SegmentBuffer seg_buffer = new SegmentBuffer(); + mp_impl.getSegment(ivertex, seg_buffer, true); + setSegmentToIndex_(vindex, seg_buffer.get()); + } + } + } + + return newgeom; + } + + // Extracts a geometry from the Edit_shape. The method creates a new + // Geometry instance and initializes it with the Edit_shape data for the + // given geometry. + Geometry getGeometry(int geometry) { + int gt = getGeometryType(geometry); + Geometry geom = InternalUtils.createGeometry(gt, + m_vertices_mp.getDescription()); + int point_count = getPointCount(geometry); + + if (point_count == 0) + return geom; + + if (Geometry.isMultiPath(gt)) { + MultiPathImpl mp_impl = (MultiPathImpl) geom._getImpl(); + int path_count = getPathCount(geometry); + AttributeStreamOfInt32 parts = (AttributeStreamOfInt32) (AttributeStreamBase + .createIndexStream(path_count + 1)); + AttributeStreamOfInt8 pathFlags = (AttributeStreamOfInt8) (AttributeStreamBase + .createByteStream(path_count + 1, (byte) 0)); + VertexDescription description = geom.getDescription(); + + for (int iattrib = 0, nattrib = description.getAttributeCount(); iattrib < nattrib; iattrib++) { + int semantics = description.getSemantics(iattrib); + int ncomps = VertexDescription.getComponentCount(semantics); + AttributeStreamBase dst_stream = AttributeStreamBase + .createAttributeStreamWithSemantics(semantics, + point_count); + AttributeStreamBase src_stream = m_vertices + .getAttributeStreamRef(semantics); + int dst_index = 0; + int ipath = 0; + int nvert = 0; + for (int path = getFirstPath(geometry); path != -1; path = getNextPath(path)) { + byte flag_mask = 0; + if (isClosedPath(path)) { + flag_mask |= (byte) PathFlags.enumClosed; + } else { + assert (gt != Geometry.GeometryType.Polygon); + } + + if (isExterior(path)) { + flag_mask |= (byte) PathFlags.enumOGCStartPolygon; + } + + if (flag_mask != 0) + pathFlags.setBits(ipath, flag_mask); + + int path_size = getPathSize(path); + parts.write(ipath++, nvert); + nvert += path_size; + if (semantics == VertexDescription.Semantics.POSITION) { + AttributeStreamOfDbl src_stream_dbl = (AttributeStreamOfDbl) (src_stream); + AttributeStreamOfDbl dst_stream_dbl = (AttributeStreamOfDbl) (dst_stream); + Point2D pt = new Point2D(); + for (int vertex = getFirstVertex(path); dst_index < nvert; vertex = getNextVertex(vertex), dst_index++) { + int src_index = getVertexIndex(vertex); + src_stream_dbl.read(src_index * 2, pt); + dst_stream_dbl.write(dst_index * 2, pt); + } + } else { + for (int vertex = getFirstVertex(path); dst_index < nvert; vertex = getNextVertex(vertex), dst_index++) { + int src_index = getVertexIndex(vertex); + for (int icomp = 0; icomp < ncomps; icomp++) { + double d = src_stream.readAsDbl(src_index + * ncomps + icomp); + dst_stream.writeAsDbl(dst_index * ncomps + + icomp, d); + } + } + } + } + + assert (nvert == point_count);// Inconsistent content in the + // Edit_shape. Please, fix. + assert (ipath == path_count); + mp_impl.setAttributeStreamRef(semantics, dst_stream); + parts.write(path_count, point_count); + } + + mp_impl.setPathFlagsStreamRef(pathFlags); + mp_impl.setPathStreamRef(parts); + mp_impl.notifyModified(MultiVertexGeometryImpl.DirtyFlags.DirtyAll); + } else if (gt == Geometry.GeometryType.MultiPoint) { + MultiPointImpl mp_impl = (MultiPointImpl) geom._getImpl(); + VertexDescription description = geom.getDescription(); + // mp_impl.reserve(point_count); + mp_impl.resize(point_count); + + for (int iattrib = 0, nattrib = description.getAttributeCount(); iattrib < nattrib; iattrib++) { + int semantics = description.getSemantics(iattrib); + int ncomps = VertexDescription.getComponentCount(semantics); + AttributeStreamBase dst_stream = mp_impl + .getAttributeStreamRef(semantics); + // std::shared_ptr dst_stream = + // Attribute_stream_base::create_attribute_stream(semantics, + // point_count); + AttributeStreamBase src_stream = m_vertices + .getAttributeStreamRef(semantics); + int dst_index = 0; + assert (getPathCount(geometry) == 1); + int path = getFirstPath(geometry); + int path_size = getPathSize(path); + for (int vertex = getFirstVertex(path); dst_index < path_size; vertex = getNextVertex(vertex), dst_index++) { + int src_index = getVertexIndex(vertex); + for (int icomp = 0; icomp < ncomps; icomp++) { + double d = src_stream.readAsDbl(src_index * ncomps + + icomp); + dst_stream.writeAsDbl(dst_index * ncomps + icomp, d); + } + } + + mp_impl.setAttributeStreamRef(semantics, dst_stream); + } + + mp_impl.notifyModified(MultiVertexGeometryImpl.DirtyFlags.DirtyAll); + } else { + assert (false); + } + + return geom; + } + + // create a new empty geometry of the given type + int createGeometry(Geometry.Type geometry_type) { + return createGeometry(geometry_type, + VertexDescriptionDesignerImpl.getDefaultDescriptor2D()); + } + + // Deletes existing geometry from the edit shape and returns the next one. + int removeGeometry(int geometry) { + for (int path = getFirstPath(geometry); path != -1; path = removePath(path)) { + // removing paths in a loop + } + + int prev = getPrevGeometry(geometry); + int next = getNextGeometry(geometry); + if (prev != -1) + setNextGeometry_(prev, next); + else { + m_first_geometry = next; + } + if (next != -1) + setPrevGeometry_(next, prev); + else { + m_last_geometry = prev; + } + + freeGeometry_(geometry); + return next; + } + + // create a new empty geometry of the given type and attribute set. + int createGeometry(Geometry.Type geometry_type, + VertexDescription description) { + int newgeom = newGeometry_(geometry_type.value()); + if (m_vertices == null) { + m_vertices_mp = new MultiPoint(description); + m_vertices = (MultiPointImpl) m_vertices_mp._getImpl(); + } else + m_vertices_mp.mergeVertexDescription(description); + + m_vertex_description = m_vertices_mp.getDescription();// this + // description + // will be a + // merge of + // existing + // description + // and the + // description + // of the + // multi_path + m_b_has_attributes = m_vertex_description.getAttributeCount() > 1; + + if (m_first_geometry == -1) { + m_first_geometry = newgeom; + m_last_geometry = newgeom; + } else { + setPrevGeometry_(newgeom, m_last_geometry); + setNextGeometry_(m_last_geometry, newgeom); + m_last_geometry = newgeom; + } + return newgeom; + } + + // Returns the first geometry in the Edit_shape. + int getFirstGeometry() { + return m_first_geometry; + } + + // Returns the next geometry in the Edit_shape. Returns -1 when there are no + // more geometries. + int getNextGeometry(int geom) { + return m_geometry_index_list.getField(geom, 1); + } + + // Returns the previous geometry in the Edit_shape. Returns -1 when there + // are no more geometries. + int getPrevGeometry(int geom) { + return m_geometry_index_list.getField(geom, 0); + } + + // Returns the type of the Geometry. + int getGeometryType(int geom) { + return m_geometry_index_list.getField(geom, 2) & 0x7FFFFFFF; + } + + // Sets value to the given user index on a geometry. + void setGeometryUserIndex(int geom, int index, int value) { + AttributeStreamOfInt32 stream = m_geometry_indices.get(index); + int pindex = getGeometryIndex_(geom); + if (pindex >= stream.size()) + stream.resize(Math.max((int) (pindex * 1.25), (int) 16), -1); + stream.write(pindex, value); + } + + // Returns the value of the given user index of a geometry + int getGeometryUserIndex(int geom, int index) { + int pindex = getGeometryIndex_(geom); + AttributeStreamOfInt32 stream = m_geometry_indices.get(index); + if (pindex < stream.size()) + return stream.read(pindex); + else + return -1; + } + + // Creates new user index on a geometry. The geometry index allows to store + // an integer user value on the geometry. + // Until set_geometry_user_index is called for a given geometry, the index + // stores -1 for that geometry. + int createGeometryUserIndex() { + if (m_geometry_indices == null) + m_geometry_indices = new ArrayList(4); + + // Try getting existing index. Use linear search. We do not expect many + // indices to be created. + for (int i = 0; i < m_geometry_indices.size(); i++) { + if (m_geometry_indices.get(i) == null) { + m_geometry_indices.set(i, + (AttributeStreamOfInt32) AttributeStreamBase + .createIndexStream(0)); + return i; + } + } + + m_geometry_indices.add((AttributeStreamOfInt32) AttributeStreamBase + .createIndexStream(0)); + return m_geometry_indices.size() - 1; + } + + // Removes the geometry user index. + void removeGeometryUserIndex(int index) { + m_geometry_indices.set(index, null); + } + + // Returns the first path of the geometry. + int getFirstPath(int geometry) { + return m_geometry_index_list.getField(geometry, 3); + } + + // Returns the first path of the geometry. + int getLastPath(int geometry) { + return m_geometry_index_list.getField(geometry, 4); + } + + // Point count in a geometry + int getPointCount(int geom) { + return m_geometry_index_list.getField(geom, 5); + } + + // Path count in a geometry + int getPathCount(int geom) { + return m_geometry_index_list.getField(geom, 6); + } + + // Filters degenerate segments in all multipath geometries + // Returns 1 if a non-zero length segment has been removed. -1, if only zero + // length segments have been removed. + // 0 if no segments have been removed. + // When b_remove_last_vertices and the result path is < 3 for polygon or < 2 + // for polyline, it'll be removed. + int filterClosePoints(double tolerance, boolean b_remove_last_vertices, boolean only_polygons) { + int res = 0; + for (int geometry = getFirstGeometry(); geometry != -1; geometry = getNextGeometry(geometry)) { + int gt = getGeometryType(geometry); + if (!Geometry.isMultiPath(gt)) + continue; + if (only_polygons && gt != GeometryType.Polygon) + continue; + + boolean b_polygon = getGeometryType(geometry) == Geometry.GeometryType.Polygon; + + for (int path = getFirstPath(geometry); path != -1;) { + // We go from the start to the half of the path first, then we + // go from the end to the half of the path. + int vertex_counter = 0; + for (int vertex = getFirstVertex(path); vertex_counter < getPathSize(path) / 2;) { + int next = getNextVertex(vertex); + if (next == -1) + break; + int vindex = getVertexIndex(vertex); + Segment seg = getSegmentFromIndex_(vindex); + double length = 0; + if (seg != null) { + length = seg.calculateLength2D(); + } else { + int vindex_next = getVertexIndex(next); + length = m_vertices._getShortestDistance(vindex, + vindex_next); + } + + if (length <= tolerance) { + if (length == 0) { + if (res == 0) + res = -1; + } else + res = 1; + + if (next != getLastVertex(path)) { + transferAllDataToTheVertex(next, vertex); + removeVertex(next, true); + } + } else { + vertex = getNextVertex(vertex); + } + vertex_counter++; + } + + int first_vertex = getFirstVertex(path); + for (int vertex = isClosedPath(path) ? first_vertex + : getLastVertex(path); getPathSize(path) > 0;) { + int prev = getPrevVertex(vertex); + if (prev != -1) { + int vindex_prev = getVertexIndex(prev); + Segment seg = getSegmentFromIndex_(vindex_prev); + double length = 0; + if (seg != null) { + length = seg.calculateLength2D(); + } else { + int vindex = getVertexIndex(vertex); + length = m_vertices._getShortestDistance(vindex, + vindex_prev); + } + + if (length <= tolerance) { + if (length == 0) { + if (res == 0) + res = -1; + } else + res = 1; + + transferAllDataToTheVertex(prev, vertex); + removeVertex(prev, false); + if (first_vertex == prev) + first_vertex = getFirstVertex(path); + } else { + vertex = getPrevVertex(vertex); + if (vertex == first_vertex) + break; + } + } else { + removeVertex(vertex, true);// remove the last vertex in + // the path + if (res == 0) + res = -1; + break; + } + } + + int path_size = getPathSize(path); + if (b_remove_last_vertices + && (b_polygon ? path_size < 3 : path_size < 2)) { + path = removePath(path); + res = path_size > 0 ? 1 : (res == 0 ? -1 : res); + } else + path = getNextPath(path); + } + } + + return res; + } + + // Checks if there are degenerate segments in any of multipath geometries + boolean hasDegenerateSegments(double tolerance) { + for (int geometry = getFirstGeometry(); geometry != -1; geometry = getNextGeometry(geometry)) { + if (!Geometry.isMultiPath(getGeometryType(geometry))) + continue; + + boolean b_polygon = getGeometryType(geometry) == Geometry.GeometryType.Polygon; + + for (int path = getFirstPath(geometry); path != -1;) { + int path_size = getPathSize(path); + if (b_polygon ? path_size < 3 : path_size < 2) + return true; + + int vertex = getFirstVertex(path); + for (int index = 0; index < path_size; index++) { + int next = getNextVertex(vertex); + if (next == -1) + break; + int vindex = getVertexIndex(vertex); + Segment seg = getSegmentFromIndex_(vindex); + double length = 0; + if (seg != null) { + length = seg.calculateLength2D(); + } else { + int vindex_next = getVertexIndex(next); + length = m_vertices._getShortestDistance(vindex, + vindex_next); + } + + if (length <= tolerance) + return true; + + vertex = next; + } + + path = getNextPath(path); + } + } + + return false; + } + + void transferAllDataToTheVertex(int from_vertex, int to_vertex) { + int vindexFrom = getVertexIndex(from_vertex); + int vindexTo = getVertexIndex(to_vertex); + if (m_weights != null) { + double weight = m_weights.read(vindexFrom); + m_weights.write(vindexTo, weight); + } + + if (m_b_has_attributes) { + // TODO: implement copying of attributes with exception of x and y + // + // for (int i = 0, nattrib = 0; i < nattrib; i++) + // { + // m_vertices->get_attribute + // } + } + // Copy user index data + if (m_indices != null) { + for (int i = 0, n = (int) m_indices.size(); i < n; i++) { + if (m_indices.get(i) != null) { + int value = getUserIndex(from_vertex, i); + if (value != -1) + setUserIndex(to_vertex, i, value); + } + } + } + } + + // Splits segment originating from the origingVertex split_count times at + // splitScalar points and inserts new vertices into the shape. + // The split is not done, when the splitScalar[i] is 0 or 1, or is equal to + // the splitScalar[i - 1]. + // Returns the number of splits actually happend (0 if no splits have + // happend). + int splitSegment(int origin_vertex, double[] split_scalars, int split_count) { + int actual_splits = 0; + int next_vertex = getNextVertex(origin_vertex); + if (next_vertex == -1) + throw GeometryException.GeometryInternalError(); + + int vindex = getVertexIndex(origin_vertex); + int vindex_next = getVertexIndex(next_vertex); + Segment seg = getSegmentFromIndex_(vindex); + double seg_length = seg == null ? m_vertices._getShortestDistance( + vindex, vindex_next) : seg.calculateLength2D(); + double told = 0.0; + for (int i = 0; i < split_count; i++) { + double t = split_scalars[i]; + if (told < t && t < 1.0) { + double f = t; + if (seg != null) { + f = seg_length > 0 ? seg._calculateSubLength(t) + / seg_length : 0.0; + } + + m_vertices._interpolateTwoVertices(vindex, vindex_next, f, + getHelperPoint_());// use this call mainly to + // interpolate the attributes. XYs + // are interpolated incorrectly for + // curves and are recalculated when + // segment is cut below. + int inserted_vertex = insertVertex_( + getPathFromVertex(origin_vertex), next_vertex, + getHelperPoint_()); + actual_splits++; + if (seg != null) { + Segment subseg = seg.cut(told, t); + int prev_vertex = getPrevVertex(inserted_vertex); + int vindex_prev = getVertexIndex(prev_vertex); + setSegmentToIndex_(vindex_prev, subseg); + setXY(inserted_vertex, subseg.getEndXY()); // fix XY + // coordinates + // to be + // parameter + // based + // (interpolate_two_vertices_) + if (i == split_count - 1 || split_scalars[i + 1] == 1.0) {// last + // chance + // to + // set + // last + // split + // segment + // here: + Segment subseg_end = seg.cut(t, 1.0); + setSegmentToIndex_(vindex_prev, subseg_end); + } + } + } + } + + return actual_splits; + } + + // interpolates the attributes for the specified path between from_vertex + // and to_vertex + void interpolateAttributesForClosedPath(int path, int from_vertex, + int to_vertex) { + assert (isClosedPath(path)); + + if (!m_b_has_attributes) + return; + + double sub_length = calculateSubLength2D(path, from_vertex, to_vertex); + + if (sub_length == 0.0) + return; + + int nattr = m_vertex_description.getAttributeCount(); + + for (int iattr = 1; iattr < nattr; iattr++) { + int semantics = m_vertex_description.getSemantics(iattr); + + int interpolation = VertexDescription.getInterpolation(semantics); + if (interpolation == VertexDescription.Interpolation.ANGULAR) + continue; + + int components = VertexDescription.getComponentCount(semantics); + + for (int ordinate = 0; ordinate < components; ordinate++) + interpolateAttributesForClosedPath_(semantics, path, + from_vertex, to_vertex, sub_length, ordinate); + } + + return; + } + + // calculates the length for the specified path between from_vertex and + // to_vertex + double calculateSubLength2D(int path, int from_vertex, int to_vertex) { + int shape_from_index = getVertexIndex(from_vertex); + int shape_to_index = getVertexIndex(to_vertex); + + if (shape_from_index < 0 || shape_to_index > getTotalPointCount() - 1) + throw new IllegalArgumentException("invalid call"); + + if (shape_from_index > shape_to_index) { + if (!isClosedPath(path)) + throw new IllegalArgumentException( + "cannot iterate across an open path"); + } + + double sub_length = 0.0; + + for (int vertex = from_vertex; vertex != to_vertex; vertex = getNextVertex(vertex)) { + int vertex_index = getVertexIndex(vertex); + Segment segment = getSegmentFromIndex_(vertex_index); + if (segment != null) { + sub_length += segment.calculateLength2D(); + } else { + int next_vertex_index = getVertexIndex(getNextVertex(vertex)); + sub_length += m_vertices._getShortestDistance(vertex_index, + next_vertex_index); + } + } + + return sub_length; + } + + // set_point modifies the vertex and associated segments. + void setPoint(int vertex, Point new_coord) { + int vindex = getVertexIndex(vertex); + m_vertices.setPointByVal(vindex, new_coord); + Segment seg = getSegmentFromIndex_(vindex); + if (seg != null) { + seg.setStart(new_coord); + } + int prev = getPrevVertex(vertex); + if (prev != -1) { + int vindex_p = getVertexIndex(prev); + Segment seg_p = getSegmentFromIndex_(vindex_p); + if (seg_p != null) { + seg.setEnd(new_coord); + } + } + } + + // Queries point for a given vertex. + void queryPoint(int vertex, Point point) { + int vindex = getVertexIndex(vertex); + m_vertices.getPointByVal(vindex, point); + // assert(getXY(vertex) == point.getXY()); + } + + // set_xy modifies the vertex and associated segments. + void setXY(int vertex, Point2D new_coord) { + setXY(vertex, new_coord.x, new_coord.y); + } + + // set_xy modifies the vertex and associated segments. + void setXY(int vertex, double new_x, double new_y) { + int vindex = getVertexIndex(vertex); + m_vertices.setXY(vindex, new_x, new_y); + Segment seg = getSegmentFromIndex_(vindex); + if (seg != null) { + seg.setStartXY(new_x, new_y); + } + int prev = getPrevVertex(vertex); + if (prev != -1) { + int vindex_p = getVertexIndex(prev); + Segment seg_p = getSegmentFromIndex_(vindex_p); + if (seg_p != null) { + seg.setEndXY(new_x, new_y); + } + } + } + + Point2D getXY(int vertex) { + Point2D pt = new Point2D(); + int vindex = getVertexIndex(vertex); + pt.setCoords(m_vertices.getXY(vindex)); + return pt; + } + + // Returns the coordinates of the vertex. + void getXY(int vertex, Point2D ptOut) { + int vindex = getVertexIndex(vertex); + ptOut.setCoords(m_vertices.getXY(vindex)); + } + + void getXYWithIndex(int index, Point2D ptOut) { + m_xy_stream.read(2 * index, ptOut); + } + + // Gets the attribute for the given semantics and ordinate. + double getAttributeAsDbl(int semantics, int vertex, int ordinate) { + return m_vertices.getAttributeAsDbl(semantics, getVertexIndex(vertex), + ordinate); + } + + // Sets the attribute for the given semantics and ordinate. + void setAttribute(int semantics, int vertex, int ordinate, double value) { + m_vertices.setAttribute(semantics, getVertexIndex(vertex), ordinate, + value); + } + + // Sets the attribute for the given semantics and ordinate. + void setAttribute(int semantics, int vertex, int ordinate, int value) { + m_vertices.setAttribute(semantics, getVertexIndex(vertex), ordinate, + value); + } + + // Returns a reference to the vertex description + VertexDescription getVertexDescription() { + return m_vertex_description; + } + + int getMinPathVertexY(int path) { + int first_vert = getFirstVertex(path); + int minv = first_vert; + int vert = getNextVertex(first_vert); + while (vert != -1 && vert != first_vert) { + if (compareVerticesSimpleY_(vert, minv) < 0) + minv = vert; + vert = getNextVertex(vert); + } + return minv; + } + + // Returns an index value for the vertex inside of the underlying array of + // vertices. + // This index is for the use with the get_xy_with_index. get_xy is + // equivalent to calling get_vertex_index and get_xy_with_index. + int getVertexIndex(int vertex) { + return m_vertex_index_list.getField(vertex, 0); + } + + // Returns the y coordinate of the vertex. + double getY(int vertex) { + Point2D pt = new Point2D(); + getXY(vertex, pt); + return pt.y; + } + + // returns True if xy coordinates at vertices are equal. + boolean isEqualXY(int vertex_1, int vertex_2) { + int vindex1 = getVertexIndex(vertex_1); + int vindex2 = getVertexIndex(vertex_2); + return m_vertices.getXY(vindex1).isEqual(m_vertices.getXY(vindex2)); + } + + // returns True if xy coordinates at vertices are equal. + boolean isEqualXY(int vertex, Point2D pt) { + int vindex = getVertexIndex(vertex); + return m_vertices.getXY(vindex).isEqual(pt); + } + + // Sets weight to the vertex. Weight is used by clustering and cracking. + void setWeight(int vertex, double weight) { + if (weight < 1.0) + weight = 1.0; + + if (m_weights == null) { + if (weight == 1.0) + return; + + m_weights = (AttributeStreamOfDbl) (AttributeStreamBase + .createDoubleStream(m_vertices.getPointCount(), 1.0)); + } + + int vindex = getVertexIndex(vertex); + if (vindex >= m_weights.size()) { + m_weights.resize(vindex + 1, 1.0); + } + + m_weights.write(vindex, weight); + } + + double getWeight(int vertex) { + int vindex = getVertexIndex(vertex); + if (m_weights == null || vindex >= m_weights.size()) + return 1.0; + + return m_weights.read(vindex); + } + + // Removes associated weights + void removeWeights() { + m_weights = null; + } + + // Sets value to the given user index. + void setUserIndex(int vertex, int index, int value) { + // CHECKVERTEXHANDLE(vertex); + AttributeStreamOfInt32 stream = m_indices.get(index); + // assert(get_prev_vertex(vertex) != -0x7eadbeaf);//using deleted vertex + int vindex = getVertexIndex(vertex); + if (stream.size() < m_vertices.getPointCount()) + stream.resize(m_vertices.getPointCount(), -1); + stream.write(vindex, value); + } + + int getUserIndex(int vertex, int index) { + // CHECKVERTEXHANDLE(vertex); + int vindex = getVertexIndex(vertex); + AttributeStreamOfInt32 stream = m_indices.get(index); + if (vindex < stream.size()) { + int val = stream.read(vindex); + return val; + } else + return -1; + } + + // Creates new user index. The index have random values. The index allows to + // store an integer user value on the vertex. + int createUserIndex() { + if (m_indices == null) + m_indices = new ArrayList(0); + + // Try getting existing index. Use linear search. We do not expect many + // indices to be created. + for (int i = 0; i < m_indices.size(); i++) { + if (m_indices.get(i) == null) { + m_indices.set(i, (AttributeStreamOfInt32) AttributeStreamBase + .createIndexStream(0, -1)); + return i; + } + } + + m_indices.add((AttributeStreamOfInt32) AttributeStreamBase + .createIndexStream(0, -1)); + return m_indices.size() - 1; + } + + // Removes the user index. + void removeUserIndex(int index) { + m_indices.set(index, null); + } + + // Returns segment, connecting currentVertex and next vertex. Returns NULL + // if it is a Line. + Segment getSegment(int vertex) { + if (m_segments != null) { + int vindex = getVertexIndex(vertex); + return m_segments.get(vindex); + } + return null; + } + + // Returns a straight line that connects this and next vertices. No + // attributes. Returns false if no next vertex exists (end of polyline + // part). + // Can be used together with get_segment. + boolean queryLineConnector(int vertex, Line line) { + int next = getNextVertex(vertex); + if (next == -1) + return false; + + if (!m_b_has_attributes) { + Point2D pt = new Point2D(); + getXY(vertex, pt); + line.setStartXY(pt); + getXY(next, pt); + line.setEndXY(pt); + } else { + Point pt = new Point(); + queryPoint(vertex, pt); + line.setStart(pt); + queryPoint(next, pt); + line.setEnd(pt); + } + + return true; + } + + // Inserts an empty path before the given one. If before_path is -1, adds + // path at the end. + int insertPath(int geometry, int before_path) { + int prev = -1; + + if (before_path != -1) { + if (geometry != getGeometryFromPath(before_path)) + throw GeometryException.GeometryInternalError(); + + prev = getPrevPath(before_path); + } else + prev = getLastPath(geometry); + + int newpath = newPath_(geometry); + if (before_path != -1) + setPrevPath_(before_path, newpath); + + setNextPath_(newpath, before_path); + setPrevPath_(newpath, prev); + if (prev != -1) + setNextPath_(prev, newpath); + else + setFirstPath_(geometry, newpath); + + if (before_path == -1) + setLastPath_(geometry, newpath); + + setGeometryPathCount_(geometry, getPathCount(geometry) + 1); + return newpath; + } + + int insertClosedPath_(int geometry, int before_path, int first_vertex, int checked_vertex, boolean[] contains_checked_vertex) { + int path = insertPath(geometry, -1); + int path_size = 0; + int vertex = first_vertex; + boolean contains = false; + + while (true) { + if (vertex == checked_vertex) + contains = true; + + setPathToVertex_(vertex, path); + path_size++; + int next = getNextVertex(vertex); + assert (getNextVertex(getPrevVertex(vertex)) == vertex); + if (next == first_vertex) + break; + + vertex = next; + } + + setClosedPath(path, true); + setPathSize_(path, path_size); + if (contains) + first_vertex = checked_vertex; + + setFirstVertex_(path, first_vertex); + setLastVertex_(path, getPrevVertex(first_vertex)); + setRingAreaValid_(path, false); + + if (contains_checked_vertex != null) { + contains_checked_vertex[0] = contains; + } + + return path; + } + + + // Removes a path, gets rid of all its vertices, and returns the next one + int removePath(int path) { + int prev = getPrevPath(path); + int next = getNextPath(path); + int geometry = getGeometryFromPath(path); + if (prev != -1) + setNextPath_(prev, next); + else { + setFirstPath_(geometry, next); + } + if (next != -1) + setPrevPath_(next, prev); + else { + setLastPath_(geometry, prev); + } + + clearPath(path); + + setGeometryPathCount_(geometry, getPathCount(geometry) - 1); + freePath_(path); + return next; + } + + // Clears all vertices from the path + void clearPath(int path) { + int first_vertex = getFirstVertex(path); + if (first_vertex != -1) { + // TODO: can ve do this in one shot? + int vertex = first_vertex; + for (int i = 0, n = getPathSize(path); i < n; i++) { + int v = vertex; + vertex = getNextVertex(vertex); + freeVertex_(v); + } + int geometry = getGeometryFromPath(path); + setGeometryVertexCount_(geometry, getPointCount(geometry) + - getPathSize(path)); + } + setPathSize_(path, 0); + } + + // Returns the next path (-1 if there are no more paths in the geometry). + int getNextPath(int currentPath) { + return m_path_index_list.getField(currentPath, 2); + } + + // Returns the previous path (-1 if there are no more paths in the + // geometry). + int getPrevPath(int currentPath) { + return m_path_index_list.getField(currentPath, 1); + } + + // Returns the number of vertices in the path. + int getPathSize(int path) { + return m_path_index_list.getField(path, 3); + } + + // Returns True if the path is closed. + boolean isClosedPath(int path) { + return (getPathFlags_(path) & PathFlags_.closedPath) != 0; + } + + // Makes path closed. Closed paths are circular lists. get_next_vertex + // always succeeds + void setClosedPath(int path, boolean b_yes_no) { + if (isClosedPath(path) == b_yes_no) + return; + if (getPathSize(path) > 0) { + int first = getFirstVertex(path); + int last = getLastVertex(path); + if (b_yes_no) { + // make a circular list + setNextVertex_(last, first); + setPrevVertex_(first, last); + // set segment to NULL (just in case) + int vindex = getVertexIndex(last); + setSegmentToIndex_(vindex, null); + } else { + setNextVertex_(last, -1); + setPrevVertex_(first, -1); + int vindex = getVertexIndex(last); + setSegmentToIndex_(vindex, null); + } + } + + int oldflags = getPathFlags_(path); + int flags = (oldflags | (int) PathFlags_.closedPath) + - (int) PathFlags_.closedPath;// clear the bit; + setPathFlags_(path, flags + | (b_yes_no ? (int) PathFlags_.closedPath : 0)); + } + + // Closes all paths of the geometry (has to be a polyline or polygon). + void closeAllPaths(int geometry) { + if (getGeometryType(geometry) == Geometry.GeometryType.Polygon) + return; + if (!Geometry.isLinear(getGeometryType(geometry))) + throw GeometryException.GeometryInternalError(); + + for (int path = getFirstPath(geometry); path != -1; path = getNextPath(path)) { + setClosedPath(path, true); + } + } + + // Returns geometry from path + int getGeometryFromPath(int path) { + return m_path_index_list.getField(path, 7); + } + + // Returns True if the path is exterior. + boolean isExterior(int path) { + return (getPathFlags_(path) & PathFlags_.exteriorPath) != 0; + } + + // Sets exterior flag + void setExterior(int path, boolean b_yes_no) { + int oldflags = getPathFlags_(path); + int flags = (oldflags | (int) PathFlags_.exteriorPath) + - (int) PathFlags_.exteriorPath;// clear the bit; + setPathFlags_(path, flags + | (b_yes_no ? (int) PathFlags_.exteriorPath : 0)); + } + + // Returns the ring area + double getRingArea(int path) { + if (isRingAreaValid_(path)) + return m_path_areas.get(getPathIndex_(path)); + + Line line = new Line(); + int vertex = getFirstVertex(path); + if (vertex == -1) + return 0; + Point2D pt0 = new Point2D(); + getXY(vertex, pt0); + double area = 0; + for (int i = 0, n = getPathSize(path); i < n; i++, vertex = getNextVertex(vertex)) { + Segment seg = getSegment(vertex); + if (seg == null) { + if (!queryLineConnector(vertex, line)) + continue; + + seg = line; + } + + double a = seg._calculateArea2DHelper(pt0.x, pt0.y); + area += a; + } + + setRingAreaValid_(path, true); + m_path_areas.set(getPathIndex_(path), area); + + return area; + } + + // Sets value to the given user index on a path. + void setPathUserIndex(int path, int index, int value) { + AttributeStreamOfInt32 stream = m_pathindices.get(index); + int pindex = getPathIndex_(path); + if (stream.size() < m_path_areas.size()) + stream.resize(m_path_areas.size(), -1); + stream.write(pindex, value); + } + + // Returns the value of the given user index of a path + int getPathUserIndex(int path, int index) { + int pindex = getPathIndex_(path); + AttributeStreamOfInt32 stream = m_pathindices.get(index); + if (pindex < stream.size()) + return stream.read(pindex); + else + return -1; + } + + // Creates new user index on a path. The index have random values. The path + // index allows to store an integer user value on the path. + int createPathUserIndex() { + if (m_pathindices == null) + m_pathindices = new ArrayList(0); + // Try getting existing index. Use linear search. We do not expect many + // indices to be created. + for (int i = 0; i < m_pathindices.size(); i++) { + if (m_pathindices.get(i) == null) { + m_pathindices.set(i, + (AttributeStreamOfInt32) (AttributeStreamBase + .createIndexStream(0))); + return i; + } + } + + m_pathindices.add((AttributeStreamOfInt32) (AttributeStreamBase + .createIndexStream(0))); + return (int) (m_pathindices.size() - 1); + } + + // Removes the path user index. + void removePathUserIndex(int index) { + m_pathindices.set(index, null); + } + + // Moves a path from any geometry before a given path in the dst_geom + // geometry. The path_handle do not change after the operation. + // before_path can be -1, then the path is moved to the end of the dst_geom. + void movePath(int geom, int before_path, int path_to_move) { + if (path_to_move == -1) + throw new IllegalArgumentException(); + + if (before_path == path_to_move) + return; + + int next = getNextPath(path_to_move); + int prev = getPrevPath(path_to_move); + int geom_src = getGeometryFromPath(path_to_move); + if (prev == -1) { + setFirstPath_(geom_src, next); + } else { + setNextPath_(prev, next); + } + + if (next == -1) { + setLastPath_(geom_src, prev); + } else { + setPrevPath_(next, prev); + } + + setGeometryVertexCount_(geom_src, getPointCount(geom_src) + - getPathSize(path_to_move)); + setGeometryPathCount_(geom_src, getPathCount(geom_src) - 1); + + if (before_path == -1) + prev = getLastPath(geom); + else + prev = getPrevPath(before_path); + + setPrevPath_(path_to_move, prev); + setNextPath_(path_to_move, before_path); + if (before_path == -1) + setLastPath_(geom, path_to_move); + else + setPrevPath_(before_path, path_to_move); + if (prev == -1) + setFirstPath_(geom, path_to_move); + else + setNextPath_(prev, path_to_move); + setGeometryVertexCount_(geom, getPointCount(geom) + + getPathSize(path_to_move)); + setGeometryPathCount_(geom, getPathCount(geom) + 1); + setPathGeometry_(path_to_move, geom); + } + + // Adds a copy of a vertex to a path. Connects with a straight line. + // Returns new vertex handle. + int addVertex(int path, int vertex) { + m_vertices.getPointByVal(getVertexIndex(vertex), getHelperPoint_()); + return insertVertex_(path, -1, getHelperPoint_()); + } + + // Removes vertex from path. Uses either left or right segments to + // reconnect. Returns next vertex after erased one. + int removeVertex(int vertex, boolean b_left_segment) { + int path = getPathFromVertex(vertex); + int prev = getPrevVertex(vertex); + int next = getNextVertex(vertex); + if (prev != -1) + setNextVertex_(prev, next); + + int path_size = getPathSize(path); + + if (vertex == getFirstVertex(path)) { + setFirstVertex_(path, path_size > 1 ? next : -1); + } + + if (next != -1) + setPrevVertex_(next, prev); + + if (vertex == getLastVertex(path)) { + setLastVertex_(path, path_size > 1 ? prev : -1); + } + + if (prev != -1 && next != -1) { + int vindex_prev = getVertexIndex(prev); + int vindex_next = getVertexIndex(next); + if (b_left_segment) { + Segment seg = getSegmentFromIndex_(vindex_prev); + if (seg != null) { + Point2D pt = new Point2D(); + m_vertices.getXY(vindex_next, pt); + seg.setEndXY(pt); + } + } else { + int vindex_erased = getVertexIndex(vertex); + Segment seg = getSegmentFromIndex_(vindex_erased); + setSegmentToIndex_(vindex_prev, seg); + if (seg != null) { + Point2D pt = m_vertices.getXY(vindex_prev); + seg.setStartXY(pt); + } + } + } + + setPathSize_(path, path_size - 1); + int geometry = getGeometryFromPath(path); + setGeometryVertexCount_(geometry, getPointCount(geometry) - 1); + freeVertex_(vertex); + return next; + } + + // Returns first vertex of the given path. + int getFirstVertex(int path) { + return m_path_index_list.getField(path, 4); + } + + // Returns last vertex of the given path. For the closed paths + // get_next_vertex for the last vertex returns the first vertex. + int getLastVertex(int path) { + return m_path_index_list.getField(path, 5); + } + + // Returns next vertex. Closed paths are circular lists, so get_next_vertex + // always returns vertex. Open paths return -1 for last vertex. + int getNextVertex(int currentVertex) { + return m_vertex_index_list.getField(currentVertex, 2); + } + + // Returns previous vertex. Closed paths are circular lists, so + // get_prev_vertex always returns vertex. Open paths return -1 for first + // vertex. + int getPrevVertex(int currentVertex) { + return m_vertex_index_list.getField(currentVertex, 1); + } + + int getPrevVertex(int currentVertex, int dir) { + return dir > 0 ? m_vertex_index_list.getField(currentVertex, 1) : m_vertex_index_list.getField(currentVertex, 2); + } + + int getNextVertex(int currentVertex, int dir) { + return dir > 0 ? m_vertex_index_list.getField(currentVertex, 2) : m_vertex_index_list.getField(currentVertex, 1); + } + + // Returns a path the vertex belongs to. + int getPathFromVertex(int vertex) { + return m_vertex_index_list.getField(vertex, 3); + } + + // Adds a copy of the point to a path. Connects with a straight line. + // Returns new vertex handle. + int addPoint(int path, Point point) { + return insertVertex_(path, -1, point); + } + + // Vertex iterator allows to go through all vertices of the Edit_shape. + static class VertexIterator { + private EditShape m_parent; + private int m_geometry; + private int m_path; + private int m_vertex; + private int m_first_vertex; + private int m_index; + boolean m_b_first; + boolean m_b_skip_mulit_points; + + private VertexIterator(EditShape parent, int geometry, int path, + int vertex, int first_vertex, int index, + boolean b_skip_mulit_points) { + m_parent = parent; + m_geometry = geometry; + m_path = path; + m_vertex = vertex; + m_index = index; + m_b_skip_mulit_points = b_skip_mulit_points; + m_first_vertex = first_vertex; + m_b_first = true; + } + + int moveToNext_() { + if (m_b_first) { + m_b_first = false; + return m_vertex; + } + + if (m_vertex != -1) { + m_vertex = m_parent.getNextVertex(m_vertex); + m_index++; + if (m_vertex != -1 && m_vertex != m_first_vertex) + return m_vertex; + + return moveToNextHelper_();// separate into another function for + // inlining + } + + return -1; + } + + int moveToNextHelper_() { + m_path = m_parent.getNextPath(m_path); + m_index = 0; + while (m_geometry != -1) { + for (; m_path != -1; m_path = m_parent.getNextPath(m_path)) { + m_vertex = m_parent.getFirstVertex(m_path); + m_first_vertex = m_vertex; + if (m_vertex != -1) + return m_vertex; + } + + m_geometry = m_parent.getNextGeometry(m_geometry); + if (m_geometry == -1) + break; + + if (m_b_skip_mulit_points + && !Geometry.isMultiPath(m_parent + .getGeometryType(m_geometry))) { + continue; + } + + m_path = m_parent.getFirstPath(m_geometry); + } + + return -1; + } + + // moves to next vertex. Returns -1 when there are no more vertices. + VertexIterator(VertexIterator source) { + m_parent = source.m_parent; + m_geometry = source.m_geometry; + m_path = source.m_path; + m_vertex = source.m_vertex; + m_index = source.m_index; + m_b_skip_mulit_points = source.m_b_skip_mulit_points; + m_first_vertex = source.m_first_vertex; + m_b_first = true; + } + + public int next() { + return moveToNext_(); + } + + public int currentGeometry() { + assert (m_vertex != -1); + return m_geometry; + } + + public int currentPath() { + assert (m_vertex != -1); + return m_path; + } + + public static VertexIterator create_(EditShape parent, int geometry, + int path, int vertex, int first_vertex, int index, + boolean b_skip_mulit_points) { + return new VertexIterator(parent, geometry, path, vertex, + first_vertex, index, b_skip_mulit_points); + } + }; + + // Returns the vertex iterator that allows iteration through all vertices of + // all paths of all geometries. + VertexIterator queryVertexIterator() { + return queryVertexIterator(false); + } + + VertexIterator queryVertexIterator(VertexIterator source) { + return new VertexIterator(source); + } + + // Returns the vertex iterator that allows iteration through all vertices of + // all paths of all geometries. + // If bSkipMultiPoints is true, then the iterator will skip the Multi_point + // vertices + VertexIterator queryVertexIterator(boolean b_skip_multi_points) { + int geometry = -1; + int path = -1; + int vertex = -1; + int first_vertex = -1; + int index = 0; + boolean bFound = false; + + for (geometry = getFirstGeometry(); geometry != -1; geometry = getNextGeometry(geometry)) { + if (b_skip_multi_points + && !Geometry.isMultiPath(getGeometryType(geometry))) + continue; + + for (path = getFirstPath(geometry); path != -1; path = getNextPath(path)) { + vertex = getFirstVertex(path); + first_vertex = vertex; + index = 0; + if (vertex == -1) + continue; + + bFound = true; + break; + } + + if (bFound) + break; + } + + return VertexIterator.create_(this, geometry, path, vertex, + first_vertex, index, b_skip_multi_points); + } + + // Applies affine transformation + void applyTransformation(Transformation2D transform) { + m_vertices_mp.applyTransformation(transform); + if (m_segments != null) { + for (int i = 0, n = m_segments.size(); i < n; i++) { + if (m_segments.get(i) != null) { + m_segments.get(i).applyTransformation(transform); + } + } + } + } + + void interpolateAttributesForClosedPath_(int semantics, int path, + int from_vertex, int to_vertex, double sub_length, int ordinate) { + if (from_vertex == to_vertex) + return; + + double from_attribute = getAttributeAsDbl(semantics, from_vertex, + ordinate); + double to_attribute = getAttributeAsDbl(semantics, to_vertex, ordinate); + double cumulative_length = 0.0; + double prev_interpolated_attribute = from_attribute; + + for (int vertex = from_vertex; vertex != to_vertex; vertex = getNextVertex(vertex)) { + setAttribute(semantics, vertex, ordinate, + prev_interpolated_attribute); + + int vertex_index = getVertexIndex(vertex); + Segment segment = getSegmentFromIndex_(vertex_index); + double segment_length; + + if (segment != null) { + segment_length = segment.calculateLength2D(); + } else { + int next_vertex_index = getVertexIndex(getNextVertex(vertex)); + segment_length = m_vertices._getShortestDistance(vertex_index, + next_vertex_index); + } + cumulative_length += segment_length; + double t = cumulative_length / sub_length; + prev_interpolated_attribute = MathUtils.lerp(from_attribute, to_attribute, t); + } + + return; + } + + void SetGeometryType_(int geom, int gt) { + m_geometry_index_list.setField(geom, 2, gt); + } + + void splitSegment_(int origin_vertex, SegmentIntersector intersector, + int intersector_index, boolean b_forward) { + if (b_forward) { + splitSegmentForward_(origin_vertex, intersector, intersector_index); + } else { + splitSegmentBackward_(origin_vertex, intersector, intersector_index); + } + } + + void setPrevVertex_(int vertex, int prev) { + m_vertex_index_list.setField(vertex, 1, prev); + } + + void setNextVertex_(int vertex, int next) { + m_vertex_index_list.setField(vertex, 2, next); + } + + void setPathToVertex_(int vertex, int path) { + m_vertex_index_list.setField(vertex, 3, path); + } + + void setPathSize_(int path, int size) { + m_path_index_list.setField(path, 3, size); + } + + void setFirstVertex_(int path, int first_vertex) { + m_path_index_list.setField(path, 4, first_vertex); + } + + void setLastVertex_(int path, int last_vertex) { + m_path_index_list.setField(path, 5, last_vertex); + } + + void setGeometryPathCount_(int geom, int path_count) { + m_geometry_index_list.setField(geom, 6, path_count); + } + + void setGeometryVertexCount_(int geom, int vertex_count) { + m_geometry_index_list.setField(geom, 5, vertex_count); + } + + boolean ringParentageCheckInternal_(int vertex_1, int vertex_2) { + if (vertex_1 == vertex_2) + return true; + int vprev_1 = vertex_1; + int vprev_2 = vertex_2; + for (int v_1 = getNextVertex(vertex_1), v_2 = getNextVertex(vertex_2); v_1 != vertex_1 + && v_2 != vertex_2; v_1 = getNextVertex(v_1), v_2 = getNextVertex(v_2)) { + if (v_1 == vertex_2) + return true; + if (v_2 == vertex_1) + return true; + + assert (getPrevVertex(v_1) == vprev_1);// detect malformed list + assert (getPrevVertex(v_2) == vprev_2);// detect malformed list + vprev_1 = v_1; + vprev_2 = v_2; + } + + return false; + } + + void reverseRingInternal_(int vertex) { + int v = vertex; + do { + int prev = getPrevVertex(v); + int next = getNextVertex(v); + setNextVertex_(v, prev); + setPrevVertex_(v, next); + v = next; + } while (v != vertex); + // Path's last becomes invalid. Do not attempt to fix it here, because + // this is not the intent of the method + // Note: only last is invalid. other things sould not change. + } + + void setTotalPointCount_(int count) { + m_point_count = count; + } + + void removePathOnly_(int path) { + int prev = getPrevPath(path); + int next = getNextPath(path); + int geometry = getGeometryFromPath(path); + if (prev != -1) + setNextPath_(prev, next); + else { + setFirstPath_(geometry, next); + } + if (next != -1) + setPrevPath_(next, prev); + else { + setLastPath_(geometry, prev); + } + + setFirstVertex_(path, -1); + setLastVertex_(path, -1); + freePath_(path); + } + + // void DbgVerifyIntegrity(int vertex); + // void dbg_verify_vertex_counts(); + int removeVertexInternal_(int vertex, boolean b_left_segment) { + int prev = getPrevVertex(vertex); + int next = getNextVertex(vertex); + if (prev != -1) + setNextVertex_(prev, next); + + if (next != -1) + setPrevVertex_(next, prev); + + if (prev != -1 && next != -1) { + int vindex_prev = getVertexIndex(prev); + int vindex_next = getVertexIndex(next); + if (b_left_segment) { + Segment seg = getSegmentFromIndex_(vindex_prev); + if (seg != null) { + Point2D pt = new Point2D(); + m_vertices.getXY(vindex_next, pt); + seg.setEndXY(pt); + } + } else { + int vindex_erased = getVertexIndex(vertex); + Segment seg = getSegmentFromIndex_(vindex_erased); + setSegmentToIndex_(vindex_prev, seg); + if (seg != null) { + Point2D pt = new Point2D(); + m_vertices.getXY(vindex_prev, pt); + seg.setStartXY(pt); + } + } + } + freeVertex_(vertex); + return next; + } + + boolean isRingAreaValid_(int path) { + return (getPathFlags_(path) & PathFlags_.ringAreaValid) != 0; + } + + // Sets exterior flag + void setRingAreaValid_(int path, boolean b_yes_no) { + int oldflags = getPathFlags_(path); + int flags = (oldflags | (int) PathFlags_.ringAreaValid) + - (int) PathFlags_.ringAreaValid;// clear the bit; + setPathFlags_(path, flags + | (b_yes_no ? (int) PathFlags_.ringAreaValid : 0)); + } + + int compareVerticesSimpleY_(int v_1, int v_2) { + Point2D pt_1 = new Point2D(); + getXY(v_1, pt_1); + Point2D pt_2 = new Point2D(); + getXY(v_2, pt_2); + int res = pt_1.compare(pt_2); + return res; + } + + int compareVerticesSimpleX_(int v_1, int v_2) { + Point2D pt_1 = new Point2D(); + getXY(v_1, pt_1); + Point2D pt_2 = new Point2D(); + getXY(v_2, pt_2); + int res = pt_1.compare(pt_2); + return res; + } + + public static class SimplificatorVertexComparerY extends + AttributeStreamOfInt32.IntComparator { + EditShape parent; + + SimplificatorVertexComparerY(EditShape parent_) { + parent = parent_; + } + + @Override + public int compare(int i_1, int i_2) { + return parent.compareVerticesSimpleY_(i_1, i_2); + } + } + + public static class SimplificatorVertexComparerX extends + AttributeStreamOfInt32.IntComparator { + EditShape parent; + + SimplificatorVertexComparerX(EditShape parent_) { + parent = parent_; + } + + @Override + public int compare(int i_1, int i_2) { + return parent.compareVerticesSimpleX_(i_1, i_2); + } + } + + // void sort_vertices_simple_by_y_heap_merge(Dynamic_array& points, + // const Dynamic_array* geoms); + + void sortVerticesSimpleByY_(AttributeStreamOfInt32 points, int begin_, + int end_) { + if (m_bucket_sort == null) + m_bucket_sort = new BucketSort(); + m_bucket_sort.sort(points, begin_, end_, new EditShapeBucketSortHelper( + this)); + } + + void sortVerticesSimpleByYHelper_(AttributeStreamOfInt32 points, + int begin_, int end_) { + points.Sort(begin_, end_, new SimplificatorVertexComparerY(this)); + } + + void sortVerticesSimpleByX_(AttributeStreamOfInt32 points, int begin_, + int end_) { + points.Sort(begin_, end_, new SimplificatorVertexComparerX(this)); + } + + // Approximate size of the structure in memory. + // The estimated size can be very slightly less than the actual size. + // int estimate_memory_size() const; + + boolean hasPointFeatures() { + for (int geometry = getFirstGeometry(); geometry != -1; geometry = getNextGeometry(geometry)) { + if (!Geometry.isMultiPath(getGeometryType(geometry))) + return true; + } + return false; + } + + void swapGeometry(int geom1, int geom2) { + int first_path1 = getFirstPath(geom1); + int first_path2 = getFirstPath(geom2); + int last_path1 = getLastPath(geom1); + int last_path2 = getLastPath(geom2); + + for (int path = getFirstPath(geom1); path != -1; path = getNextPath(path)) { + setPathGeometry_(path, geom2); + } + + for (int path = getFirstPath(geom2); path != -1; path = getNextPath(path)) { + setPathGeometry_(path, geom1); + } + + setFirstPath_(geom1, first_path2); + setFirstPath_(geom2, first_path1); + setLastPath_(geom1, last_path2); + setLastPath_(geom2, last_path1); + + int vc1 = getPointCount(geom1); + int pc1 = getPathCount(geom1); + int vc2 = getPointCount(geom2); + int pc2 = getPathCount(geom2); + + setGeometryVertexCount_(geom1, vc2); + setGeometryVertexCount_(geom2, vc1); + setGeometryPathCount_(geom1, pc2); + setGeometryPathCount_(geom2, pc1); + + int gt1 = m_geometry_index_list.getField(geom1, 2); + int gt2 = m_geometry_index_list.getField(geom2, 2); + m_geometry_index_list.setField(geom1, 2, gt2); + m_geometry_index_list.setField(geom2, 2, gt1); + } } diff --git a/src/main/java/com/esri/core/geometry/EnclosingCircler.java b/src/main/java/com/esri/core/geometry/EnclosingCircler.java index 1c9dd069..0230e823 100644 --- a/src/main/java/com/esri/core/geometry/EnclosingCircler.java +++ b/src/main/java/com/esri/core/geometry/EnclosingCircler.java @@ -7,149 +7,152 @@ import java.util.stream.IntStream; public class EnclosingCircler { - class Circle { - final Point2D m_center; - final double m_radius; - Circle(Point2D center, double radius) { - m_center = center; - m_radius = radius; - } - - public boolean contains(Point2D point2D) { - return Point2D.distance(point2D, m_center) <= m_radius * (1 + m_tolerance / 2.0); - } - }; - - private Random m_random; - - // P is the set of all points to be processed. - private List m_indices; - - // S is the set of processed points. that will be kept track of using an index into the indices stream - private int m_processedIndex = 0; - - private Circle m_circle = null; - // Geometry to search - private MultiVertexGeometryImpl m_multiVertexGeometry; - - private int m_circleCount = 96; - SpatialReference m_bufferSpatialReference = null; - private ProjectionTransformation m_projectionTransformation; - private ProgressTracker m_progressTracker; - private double m_tolerance = 1e-10; - - EnclosingCircler(Geometry geometry, SpatialReference spatialReference, ProgressTracker progressTracker) { - if (spatialReference != null && !spatialReference.isLocal()) { - m_projectionTransformation = ProjectionTransformation.getEqualArea(geometry, spatialReference); - m_bufferSpatialReference = m_projectionTransformation.m_toSpatialReference; - m_tolerance = m_bufferSpatialReference.getTolerance(); - m_multiVertexGeometry = (MultiVertexGeometryImpl)Projecter.project(geometry, m_projectionTransformation, progressTracker)._getImpl(); - m_multiVertexGeometry._updateAllDirtyIntervals(true); - } else { - m_multiVertexGeometry = (MultiVertexGeometryImpl) geometry._getImpl(); - } - m_progressTracker = progressTracker; - m_random = new Random(1977); - } - - Geometry search() { - m_indices = IntStream.range(0, m_multiVertexGeometry.getPointCount()).boxed().collect(Collectors.toList()); - Collections.shuffle(m_indices, m_random); - - // Place first two points in boundary list - Point2D pt1 = __getShuffledPoint(m_processedIndex++); - Point2D pt2 = __getShuffledPoint(m_processedIndex++); - Point2D testCenter = new Point2D(); - testCenter.interpolate(pt1, pt2, .5); - double radius = Point2D.distance(pt1, pt2) / 2.0; - - m_circle = new Circle(testCenter, radius); - - __updateCircle(); - - if (m_projectionTransformation == null) - return __constructCircle(); - - return Projecter.project(__constructCircle(), m_projectionTransformation.getReverse(), m_progressTracker); - } - - private Geometry __constructCircle() { - Point point = new Point(m_circle.m_center); - - return OperatorBuffer.local().execute(point, m_bufferSpatialReference, m_circle.m_radius, m_progressTracker); - } - - private Point2D __getShuffledPoint(int index) { - return m_multiVertexGeometry.getXY(m_indices.get(index)); - } - - private void __updateCircle() { - // loop through all points in geometry - Circle circle = new Circle(m_circle.m_center, m_circle.m_radius); - while (m_processedIndex < m_multiVertexGeometry.getPointCount()) { - Point2D testPoint = __getShuffledPoint(m_processedIndex++); - if (!circle.contains(testPoint)) { - // if the point is outside the current circle - circle = __updateCircle(testPoint); - } - } - - m_circle = circle; - } - - private Circle __updateCircle(Point2D newBoundaryPoint) { - // two point option - Point2D testCenter = new Point2D(); - - // TODO geodesic - testCenter.interpolate(newBoundaryPoint, __getShuffledPoint(0), .5); - - Circle circle = new Circle(testCenter, Point2D.distance(testCenter, newBoundaryPoint)); - for (int i = 1; i < m_processedIndex; i++) { - Point2D testPoint = __getShuffledPoint(i); - if (!circle.contains(testPoint)) { - circle = __updateCircle(newBoundaryPoint, testPoint); - } - } - - return circle; - } - - private Circle __updateCircle(Point2D newBoundaryPoint, Point2D testPoint) { - Point2D testCenter = new Point2D(); - - // TODO geodesic - testCenter.interpolate(newBoundaryPoint, testPoint, .5); - - Circle circle = new Circle(testCenter, Point2D.distance(testCenter, newBoundaryPoint)); - for (int i = 0; i < m_processedIndex; i++) { - if (circle.contains(__getShuffledPoint(i))) { - continue; - } - - // test current index against testPoint - Point2D testCurrentCenter = new Point2D(); - testCurrentCenter.interpolate(testPoint, __getShuffledPoint(i), .5); - Circle testCurrentCircle = new Circle(testCurrentCenter, Point2D.distance(testCurrentCenter, __getShuffledPoint(i))); - if (testCurrentCircle.contains(newBoundaryPoint)) { - circle = testCurrentCircle; - continue; - } - - Point2D newCurrentCenter = new Point2D(); - newCurrentCenter.interpolate(newBoundaryPoint, __getShuffledPoint(i), .5); - Circle newCurrentCircle = new Circle(newCurrentCenter, Point2D.distance(newCurrentCenter, __getShuffledPoint(i))); - if (newCurrentCircle.contains(testPoint)) { - circle = newCurrentCircle; - continue; - } - - - // create circle from three points - testCenter = Point2D.calculateCircleCenterFromThreePoints(newBoundaryPoint, testPoint, __getShuffledPoint(i)); - circle = new Circle(testCenter, Point2D.distance(testCenter, newBoundaryPoint)); - } - - return circle; - } + class Circle { + final Point2D m_center; + final double m_radius; + + Circle(Point2D center, double radius) { + m_center = center; + m_radius = radius; + } + + public boolean contains(Point2D point2D) { + return Point2D.distance(point2D, m_center) <= m_radius * (1 + m_tolerance / 2.0); + } + } + + ; + + private Random m_random; + + // P is the set of all points to be processed. + private List m_indices; + + // S is the set of processed points. that will be kept track of using an index into the indices stream + private int m_processedIndex = 0; + + private Circle m_circle = null; + // Geometry to search + private MultiVertexGeometryImpl m_multiVertexGeometry; + + private int m_circleCount = 96; + SpatialReference m_bufferSpatialReference = null; + private ProjectionTransformation m_projectionTransformation; + private ProgressTracker m_progressTracker; + private double m_tolerance = 1e-10; + + EnclosingCircler(Geometry geometry, SpatialReference spatialReference, ProgressTracker progressTracker) { + if (spatialReference != null && !spatialReference.isLocal()) { + m_projectionTransformation = ProjectionTransformation.getEqualArea(geometry, spatialReference); + m_bufferSpatialReference = m_projectionTransformation.m_toSpatialReference; + m_tolerance = m_bufferSpatialReference.getTolerance(); + m_multiVertexGeometry = (MultiVertexGeometryImpl) Projecter.project(geometry, m_projectionTransformation, progressTracker)._getImpl(); + m_multiVertexGeometry._updateAllDirtyIntervals(true); + } else { + m_multiVertexGeometry = (MultiVertexGeometryImpl) geometry._getImpl(); + } + m_progressTracker = progressTracker; + m_random = new Random(1977); + } + + Geometry search() { + m_indices = IntStream.range(0, m_multiVertexGeometry.getPointCount()).boxed().collect(Collectors.toList()); + Collections.shuffle(m_indices, m_random); + + // Place first two points in boundary list + Point2D pt1 = __getShuffledPoint(m_processedIndex++); + Point2D pt2 = __getShuffledPoint(m_processedIndex++); + Point2D testCenter = new Point2D(); + testCenter.interpolate(pt1, pt2, .5); + double radius = Point2D.distance(pt1, pt2) / 2.0; + + m_circle = new Circle(testCenter, radius); + + __updateCircle(); + + if (m_projectionTransformation == null) + return __constructCircle(); + + return Projecter.project(__constructCircle(), m_projectionTransformation.getReverse(), m_progressTracker); + } + + private Geometry __constructCircle() { + Point point = new Point(m_circle.m_center); + + return OperatorBuffer.local().execute(point, m_bufferSpatialReference, m_circle.m_radius, m_progressTracker); + } + + private Point2D __getShuffledPoint(int index) { + return m_multiVertexGeometry.getXY(m_indices.get(index)); + } + + private void __updateCircle() { + // loop through all points in geometry + Circle circle = new Circle(m_circle.m_center, m_circle.m_radius); + while (m_processedIndex < m_multiVertexGeometry.getPointCount()) { + Point2D testPoint = __getShuffledPoint(m_processedIndex++); + if (!circle.contains(testPoint)) { + // if the point is outside the current circle + circle = __updateCircle(testPoint); + } + } + + m_circle = circle; + } + + private Circle __updateCircle(Point2D newBoundaryPoint) { + // two point option + Point2D testCenter = new Point2D(); + + // TODO geodesic + testCenter.interpolate(newBoundaryPoint, __getShuffledPoint(0), .5); + + Circle circle = new Circle(testCenter, Point2D.distance(testCenter, newBoundaryPoint)); + for (int i = 1; i < m_processedIndex; i++) { + Point2D testPoint = __getShuffledPoint(i); + if (!circle.contains(testPoint)) { + circle = __updateCircle(newBoundaryPoint, testPoint); + } + } + + return circle; + } + + private Circle __updateCircle(Point2D newBoundaryPoint, Point2D testPoint) { + Point2D testCenter = new Point2D(); + + // TODO geodesic + testCenter.interpolate(newBoundaryPoint, testPoint, .5); + + Circle circle = new Circle(testCenter, Point2D.distance(testCenter, newBoundaryPoint)); + for (int i = 0; i < m_processedIndex; i++) { + if (circle.contains(__getShuffledPoint(i))) { + continue; + } + + // test current index against testPoint + Point2D testCurrentCenter = new Point2D(); + testCurrentCenter.interpolate(testPoint, __getShuffledPoint(i), .5); + Circle testCurrentCircle = new Circle(testCurrentCenter, Point2D.distance(testCurrentCenter, __getShuffledPoint(i))); + if (testCurrentCircle.contains(newBoundaryPoint)) { + circle = testCurrentCircle; + continue; + } + + Point2D newCurrentCenter = new Point2D(); + newCurrentCenter.interpolate(newBoundaryPoint, __getShuffledPoint(i), .5); + Circle newCurrentCircle = new Circle(newCurrentCenter, Point2D.distance(newCurrentCenter, __getShuffledPoint(i))); + if (newCurrentCircle.contains(testPoint)) { + circle = newCurrentCircle; + continue; + } + + + // create circle from three points + testCenter = Point2D.calculateCircleCenterFromThreePoints(newBoundaryPoint, testPoint, __getShuffledPoint(i)); + circle = new Circle(testCenter, Point2D.distance(testCenter, newBoundaryPoint)); + } + + return circle; + } } diff --git a/src/main/java/com/esri/core/geometry/EnvSrlzr.java b/src/main/java/com/esri/core/geometry/EnvSrlzr.java index a7b6da7f..f884ef1f 100644 --- a/src/main/java/com/esri/core/geometry/EnvSrlzr.java +++ b/src/main/java/com/esri/core/geometry/EnvSrlzr.java @@ -29,67 +29,67 @@ //This is a writeReplace class for Envelope public class EnvSrlzr implements Serializable { - private static final long serialVersionUID = 1L; - double[] attribs; - int descriptionBitMask; + private static final long serialVersionUID = 1L; + double[] attribs; + int descriptionBitMask; - public Object readResolve() throws ObjectStreamException { - Envelope env = null; - if (descriptionBitMask == -1) - return null; + public Object readResolve() throws ObjectStreamException { + Envelope env = null; + if (descriptionBitMask == -1) + return null; - try { - VertexDescription vd = VertexDescriptionDesignerImpl - .getVertexDescription(descriptionBitMask); - env = new Envelope(vd); - if (attribs != null) { - env.setCoords(attribs[0], attribs[1], attribs[2], attribs[3]); - int index = 4; - for (int i = 1, n = vd.getAttributeCount(); i < n; i++) { - int semantics = vd.getSemantics(i); - int comps = VertexDescription.getComponentCount(semantics); - for (int ord = 0; ord < comps; ord++) { - env.setInterval(semantics, ord, attribs[index++], attribs[index++]); - } - } - } - } catch (Exception ex) { - throw new InvalidObjectException("Cannot read geometry from stream"); - } + try { + VertexDescription vd = VertexDescriptionDesignerImpl + .getVertexDescription(descriptionBitMask); + env = new Envelope(vd); + if (attribs != null) { + env.setCoords(attribs[0], attribs[1], attribs[2], attribs[3]); + int index = 4; + for (int i = 1, n = vd.getAttributeCount(); i < n; i++) { + int semantics = vd.getSemantics(i); + int comps = VertexDescription.getComponentCount(semantics); + for (int ord = 0; ord < comps; ord++) { + env.setInterval(semantics, ord, attribs[index++], attribs[index++]); + } + } + } + } catch (Exception ex) { + throw new InvalidObjectException("Cannot read geometry from stream"); + } - return env; - } + return env; + } - public void setGeometryByValue(Envelope env) throws ObjectStreamException { - try { - attribs = null; - if (env == null) { - descriptionBitMask = -1; - } + public void setGeometryByValue(Envelope env) throws ObjectStreamException { + try { + attribs = null; + if (env == null) { + descriptionBitMask = -1; + } - VertexDescription vd = env.getDescription(); - descriptionBitMask = vd.m_semanticsBitArray; - if (env.isEmpty()) { - return; - } + VertexDescription vd = env.getDescription(); + descriptionBitMask = vd.m_semanticsBitArray; + if (env.isEmpty()) { + return; + } - attribs = new double[vd.getTotalComponentCount() * 2]; - attribs[0] = env.getXMin(); - attribs[1] = env.getYMin(); - attribs[2] = env.getXMax(); - attribs[3] = env.getYMax(); - int index = 4; - for (int i = 1, n = vd.getAttributeCount(); i < n; i++) { - int semantics = vd.getSemantics(i); - int comps = VertexDescription.getComponentCount(semantics); - for (int ord = 0; ord < comps; ord++) { - Envelope1D e = env.queryInterval(semantics, ord); - attribs[index++] = e.vmin; - attribs[index++] = e.vmax; - } - } - } catch (Exception ex) { - throw new InvalidObjectException("Cannot serialize this geometry"); - } - } + attribs = new double[vd.getTotalComponentCount() * 2]; + attribs[0] = env.getXMin(); + attribs[1] = env.getYMin(); + attribs[2] = env.getXMax(); + attribs[3] = env.getYMax(); + int index = 4; + for (int i = 1, n = vd.getAttributeCount(); i < n; i++) { + int semantics = vd.getSemantics(i); + int comps = VertexDescription.getComponentCount(semantics); + for (int ord = 0; ord < comps; ord++) { + Envelope1D e = env.queryInterval(semantics, ord); + attribs[index++] = e.vmin; + attribs[index++] = e.vmax; + } + } + } catch (Exception ex) { + throw new InvalidObjectException("Cannot serialize this geometry"); + } + } } diff --git a/src/main/java/com/esri/core/geometry/Envelope.java b/src/main/java/com/esri/core/geometry/Envelope.java index 93dafd7e..c254df1c 100644 --- a/src/main/java/com/esri/core/geometry/Envelope.java +++ b/src/main/java/com/esri/core/geometry/Envelope.java @@ -35,398 +35,421 @@ * An envelope is an axis-aligned rectangle. */ public class Envelope extends Geometry implements Serializable { - //We are using writeReplace instead. - //private static final long serialVersionUID = 2L; - - Envelope2D m_envelope = new Envelope2D(); - - double[] m_attributes;// use doubles to store everything - - /** - * Creates an envelope by defining its center, width, and height. - * - * @param center The center point of the envelope. - * @param width The width of the envelope. - * @param height The height of the envelope. - */ - public Envelope(Point center, double width, double height) { - m_description = VertexDescriptionDesignerImpl.getDefaultDescriptor2D(); - m_envelope.setEmpty(); - if (center.isEmpty()) - return; - - _setFromPoint(center, width, height); - } - - public Envelope(Envelope2D env2D) { - m_description = VertexDescriptionDesignerImpl.getDefaultDescriptor2D(); - m_envelope.setCoords(env2D); - m_envelope.normalize(); - } - - public Envelope(VertexDescription vd) { - if (vd == null) - throw new IllegalArgumentException(); - m_description = vd; - m_envelope.setEmpty(); - } - - public Envelope(VertexDescription vd, Envelope2D env2D) { - if (vd == null) - throw new IllegalArgumentException(); - m_description = vd; - m_envelope.setCoords(env2D); - m_envelope.normalize(); - } - - /** - * Constructs an empty envelope. - */ - public Envelope() { - m_description = VertexDescriptionDesignerImpl.getDefaultDescriptor2D(); - m_envelope.setEmpty(); - } - - /** - * Constructs an envelope that covers the given point. The coordinates of - * the point are used to set the extent of the envelope. - * - * @param point The point that the envelope covers. - */ - public Envelope(Point point) { - m_description = VertexDescriptionDesignerImpl.getDefaultDescriptor2D(); - m_envelope.setEmpty(); - if (point.isEmpty()) - return; - - _setFromPoint(point); - } - - /** - * Constructs an envelope with the specified X and Y extents. - * - * @param xmin The minimum x-coordinate of the envelope. - * @param ymin The minimum y-coordinate of the envelope. - * @param xmax The maximum x-coordinate of the envelope. - * @param ymax The maximum y-coordinate of the envelope. - */ - public Envelope(double xmin, double ymin, double xmax, double ymax) { - m_description = VertexDescriptionDesignerImpl.getDefaultDescriptor2D(); - setCoords(xmin, ymin, xmax, ymax); - } - - /** - * Sets the 2-dimensional extents of the envelope. - * - * @param xmin The minimum x-coordinate of the envelope. - * @param ymin The minimum y-coordinate of the envelope. - * @param xmax The maximum x-coordinate of the envelope. - * @param ymax The maximum y-coordinate of the envelope. - */ - public void setCoords(double xmin, double ymin, double xmax, double ymax) { - _touch(); - m_envelope.setCoords(xmin, ymin, xmax, ymax); - } - - /** - * Sets the envelope from the array of points. The result envelope is a - * bounding box of all the points in the array. If the array has zero - * length, the envelope will be empty. - * - * @param points The point array. - */ - void setCoords(Point[] points) { - _touch(); - setEmpty(); - for (int i = 0, n = points.length; i < n; i++) - merge(points[i]); - } - - void setEnvelope2D(Envelope2D e2d) { - _touch(); - if (!e2d.isValid()) - throw new IllegalArgumentException(); - - m_envelope.setCoords(e2d); - } - - /** - * Removes all points from this geometry. - */ - @Override - public void setEmpty() { - _touch(); - m_envelope.setEmpty(); - } - - /** - * Indicates whether this envelope contains any points. - * - * @return boolean Returns true if the envelope is empty. - */ - @Override - public boolean isEmpty() { - return m_envelope.isEmpty(); - } - - /** - * The width of the envelope. - * - * @return The width of the envelope. - */ - - public double getWidth() { - return m_envelope.getWidth(); - } - - /** - * The height of the envelope. - * - * @return The height of the envelope. - */ - public double getHeight() { - return m_envelope.getHeight(); - } - - /** - * The x-coordinate of the center of the envelope. - * - * @return The x-coordinate of the center of the envelope. - */ - public double getCenterX() { - return m_envelope.getCenterX(); - } - - /** - * The y-coordinate of center of the envelope. - * - * @return The y-coordinate of center of the envelope. - */ - public double getCenterY() { - return m_envelope.getCenterY(); - } - - /** - * The x and y-coordinates of the center of the envelope. - * - * @return A point whose x and y-coordinates are that of the center of the envelope. - */ - public Point2D getCenterXY() { - return m_envelope.getCenter(); - } - - public void getCenter(Point point_out) { - point_out.assignVertexDescription(m_description); - if (isEmpty()) { - point_out.setEmpty(); - return; - } - - int nattrib = m_description.getAttributeCount(); - for (int i = 1; i < nattrib; i++) { - int semantics = m_description.getSemantics(i); - int ncomp = VertexDescription.getComponentCount(semantics); - for (int iord = 0; iord < ncomp; iord++) { - double v = 0.5 * (getAttributeAsDblImpl_(0, semantics, iord) + getAttributeAsDblImpl_( - 1, semantics, iord)); - point_out.setAttribute(semantics, iord, v); - } - } - point_out.setXY(m_envelope.getCenter()); - } - - public void merge(Point2D pt) { - _touch(); - m_envelope.merge(pt); - } - - /** - * Merges this envelope with the extent of the given envelope. If this - * envelope is empty, the coordinates of the given envelope - * are assigned. If the given envelope is empty, this envelope is unchanged. - * - * @param other The envelope to merge. - */ - public void merge(Envelope other) { - _touch(); - if (other.isEmpty()) - return; - - VertexDescription otherVD = other.m_description; - if (otherVD != m_description) - mergeVertexDescription(otherVD); - m_envelope.merge(other.m_envelope); - for (int iattrib = 1, nattrib = otherVD.getAttributeCount(); iattrib < nattrib; iattrib++) { - int semantics = otherVD.getSemantics(iattrib); - int ncomps = VertexDescription.getComponentCount(semantics); - for (int iord = 0; iord < ncomps; iord++) { - Envelope1D intervalOther = other.queryInterval(semantics, iord); - Envelope1D interval = queryInterval(semantics, iord); - interval.merge(intervalOther); - setInterval(semantics, iord, interval); - } - } - } - - /** - * Merges this envelope with the point. The boundary of the envelope is - * increased to include the point. If the envelope is empty, the coordinates - * of the point to merge are assigned. If the point is empty, the original - * envelope is unchanged. - * - * @param point The point to be merged. - */ - public void merge(Point point) { - _touch(); - if (point.isEmptyImpl()) - return; - - VertexDescription pointVD = point.m_description; - if (m_description != pointVD) - mergeVertexDescription(pointVD); - - if (isEmpty()) { - _setFromPoint(point); - return; - } - - m_envelope.merge(point.getXY()); - for (int iattrib = 1, nattrib = pointVD.getAttributeCount(); iattrib < nattrib; iattrib++) { - int semantics = pointVD._getSemanticsImpl(iattrib); - int ncomps = VertexDescription.getComponentCount(semantics); - for (int iord = 0; iord < ncomps; iord++) { - double v = point.getAttributeAsDbl(semantics, iord); - Envelope1D interval = queryInterval(semantics, iord); - interval.merge(v); - setInterval(semantics, iord, interval); - } - } - } - - void _setFromPoint(Point centerPoint, double width, double height) { - m_envelope.setCoords(centerPoint.getXY(), width, height); - VertexDescription pointVD = centerPoint.m_description; - for (int iattrib = 1, nattrib = pointVD.getAttributeCount(); iattrib < nattrib; iattrib++) { - int semantics = pointVD._getSemanticsImpl(iattrib); - int ncomps = VertexDescription.getComponentCount(semantics); - for (int iord = 0; iord < ncomps; iord++) { - double v = centerPoint.getAttributeAsDbl(semantics, iord); - setInterval(semantics, iord, v, v); - } - } - } - - void _setFromPoint(Point centerPoint) { - m_envelope.setCoords(centerPoint.m_attributes[0], - centerPoint.m_attributes[1]); - VertexDescription pointVD = centerPoint.m_description; - for (int iattrib = 1, nattrib = pointVD.getAttributeCount(); iattrib < nattrib; iattrib++) { - int semantics = pointVD._getSemanticsImpl(iattrib); - int ncomps = VertexDescription.getComponentCount(semantics); - for (int iord = 0; iord < ncomps; iord++) { - double v = centerPoint.getAttributeAsDbl(semantics, iord); - setInterval(semantics, iord, v, v); - } - } - } - - public void merge(Envelope2D other) { - _touch(); - m_envelope.merge(other); - } - - public void setInterval(int semantics, int ordinate, double vmin, - double vmax) { - setInterval(semantics, ordinate, new Envelope1D(vmin, vmax)); - } - - /** - * Re-aspects this envelope to fit within the specified width and height. - * - * @param arWidth The width within which to fit the envelope. - * @param arHeight The height within which to fit the envelope. - */ - public void reaspect(double arWidth, double arHeight) { - _touch(); - m_envelope.reaspect(arWidth, arHeight); - } - - /** - * Changes the dimensions of the envelope while preserving the center. New width - * is Width + 2 * dx, new height is Height + 2 * dy. If the result envelope - * width or height becomes negative, the envelope is set to be empty. - * - * @param dx The inflation along the x-axis. - * @param dy The inflation along the y-axis. - */ - public void inflate(double dx, double dy) { - _touch(); - m_envelope.inflate(dx, dy); - } - - @Override - public void applyTransformation(Transformation2D transform) { - _touch(); - transform.transform(m_envelope); - } - - @Override - void applyTransformation(Transformation3D transform) { - _touch(); - if (!m_envelope.isEmpty()) { - Envelope3D env = new Envelope3D(); - queryEnvelope3D(env); - if (env.isEmptyZ()) - env.setEmpty(); // Z components is empty, the - // AffineTransformation3D makes the whole - // envelope empty. Consider - // throwing an assert instead. - else - transform.transform(env); - } - } - - @Override - public void copyTo(Geometry dst) { - if (dst.getType() != getType()) - throw new IllegalArgumentException(); - - Envelope envDst = (Envelope) dst; - dst._touch(); - envDst.m_description = m_description; - envDst.m_envelope.setCoords(m_envelope); - envDst.m_attributes = null; - if (m_attributes != null) { - envDst._ensureAttributes(); - System.arraycopy(m_attributes, 0, envDst.m_attributes, 0, - (m_description.getTotalComponentCount() - 2) * 2); - } - } - - @Override - public Geometry createInstance() { - return new Envelope(m_description); - } - - @Override - public double calculateArea2D() { - return m_envelope.getArea(); - } - - @Override - public double calculateLength2D() { - return m_envelope.getLength(); - } - - @Override - public Geometry.Type getType() { - return Type.Envelope; - } - - @Override - public int getDimension() { - return 2; - } + //We are using writeReplace instead. + //private static final long serialVersionUID = 2L; + + Envelope2D m_envelope = new Envelope2D(); + + double[] m_attributes;// use doubles to store everything + + /** + * Creates an envelope by defining its center, width, and height. + * + * @param center + * The center point of the envelope. + * @param width + * The width of the envelope. + * @param height + * The height of the envelope. + */ + public Envelope(Point center, double width, double height) { + m_description = VertexDescriptionDesignerImpl.getDefaultDescriptor2D(); + m_envelope.setEmpty(); + if (center.isEmpty()) + return; + + _setFromPoint(center, width, height); + } + + public Envelope(Envelope2D env2D) { + m_description = VertexDescriptionDesignerImpl.getDefaultDescriptor2D(); + m_envelope.setCoords(env2D); + m_envelope.normalize(); + } + + public Envelope(VertexDescription vd) { + if (vd == null) + throw new IllegalArgumentException(); + + m_description = vd; + m_envelope.setEmpty(); + _ensureAttributes(); + } + + public Envelope(VertexDescription vd, Envelope2D env2D) { + if (vd == null) + throw new IllegalArgumentException(); + + m_description = vd; + m_envelope.setCoords(env2D); + m_envelope.normalize(); + _ensureAttributes(); + } + + /** + * Constructs an empty envelope. + */ + public Envelope() { + m_description = VertexDescriptionDesignerImpl.getDefaultDescriptor2D(); + m_envelope.setEmpty(); + } + + /** + * Constructs an envelope that covers the given point. The coordinates of + * the point are used to set the extent of the envelope. + * + * @param point The point that the envelope covers. + */ + public Envelope(Point point) { + m_description = VertexDescriptionDesignerImpl.getDefaultDescriptor2D(); + m_envelope.setEmpty(); + if (point.isEmpty()) + return; + + _setFromPoint(point); + } + + /** + * Constructs an envelope with the specified X and Y extents. + * + * @param xmin + * The minimum x-coordinate of the envelope. + * @param ymin + * The minimum y-coordinate of the envelope. + * @param xmax + * The maximum x-coordinate of the envelope. + * @param ymax + * The maximum y-coordinate of the envelope. + */ + public Envelope(double xmin, double ymin, double xmax, double ymax) { + m_description = VertexDescriptionDesignerImpl.getDefaultDescriptor2D(); + setCoords(xmin, ymin, xmax, ymax); + } + + /** + * Sets the 2-dimensional extents of the envelope. + * + * @param xmin + * The minimum x-coordinate of the envelope. + * @param ymin + * The minimum y-coordinate of the envelope. + * @param xmax + * The maximum x-coordinate of the envelope. + * @param ymax + * The maximum y-coordinate of the envelope. + */ + public void setCoords(double xmin, double ymin, double xmax, double ymax) { + _touch(); + m_envelope.setCoords(xmin, ymin, xmax, ymax); + } + + /** + * Sets the envelope from the array of points. The result envelope is a + * bounding box of all the points in the array. If the array has zero + * length, the envelope will be empty. + * + * @param points + * The point array. + */ + void setCoords(Point[] points) { + _touch(); + setEmpty(); + for (int i = 0, n = points.length; i < n; i++) + merge(points[i]); + } + + void setEnvelope2D(Envelope2D e2d) { + _touch(); + if (!e2d.isValid()) + throw new IllegalArgumentException(); + + m_envelope.setCoords(e2d); + } + + /** + * Removes all points from this geometry. + */ + @Override + public void setEmpty() { + _touch(); + m_envelope.setEmpty(); + } + + /** + * Indicates whether this envelope contains any points. + * + * @return boolean Returns true if the envelope is empty. + */ + @Override + public boolean isEmpty() { + return m_envelope.isEmpty(); + } + + /** + * The width of the envelope. + * + * @return The width of the envelope. + */ + + public double getWidth() { + return m_envelope.getWidth(); + } + + /** + * The height of the envelope. + * + * @return The height of the envelope. + */ + public double getHeight() { + return m_envelope.getHeight(); + } + + /** + * The x-coordinate of the center of the envelope. + * + * @return The x-coordinate of the center of the envelope. + */ + public double getCenterX() { + return m_envelope.getCenterX(); + } + + /** + * The y-coordinate of center of the envelope. + * + * @return The y-coordinate of center of the envelope. + */ + public double getCenterY() { + return m_envelope.getCenterY(); + } + + /** + * The x and y-coordinates of the center of the envelope. + * + * @return A point whose x and y-coordinates are that of the center of the envelope. + */ + public Point2D getCenterXY() { + return m_envelope.getCenter(); + } + + public void getCenter(Point point_out) { + point_out.assignVertexDescription(m_description); + if (isEmpty()) { + point_out.setEmpty(); + return; + } + + int nattrib = m_description.getAttributeCount(); + for (int i = 1; i < nattrib; i++) { + int semantics = m_description.getSemantics(i); + int ncomp = VertexDescription.getComponentCount(semantics); + for (int iord = 0; iord < ncomp; iord++) { + double v = 0.5 * (getAttributeAsDblImpl_(0, semantics, iord) + getAttributeAsDblImpl_( + 1, semantics, iord)); + point_out.setAttribute(semantics, iord, v); + } + } + point_out.setXY(m_envelope.getCenter()); + } + + public void merge(Point2D pt) { + _touch(); + m_envelope.merge(pt); + } + + /** + * Merges this envelope with the extent of the given envelope. If this + * envelope is empty, the coordinates of the given envelope + * are assigned. If the given envelope is empty, this envelope is unchanged. + * + * @param other + * The envelope to merge. + */ + public void merge(Envelope other) { + _touch(); + if (other.isEmpty()) + return; + + VertexDescription otherVD = other.m_description; + if (otherVD != m_description) + mergeVertexDescription(otherVD); + m_envelope.merge(other.m_envelope); + for (int iattrib = 1, nattrib = otherVD.getAttributeCount(); iattrib < nattrib; iattrib++) { + int semantics = otherVD.getSemantics(iattrib); + int ncomps = VertexDescription.getComponentCount(semantics); + for (int iord = 0; iord < ncomps; iord++) { + Envelope1D intervalOther = other.queryInterval(semantics, iord); + Envelope1D interval = queryInterval(semantics, iord); + interval.merge(intervalOther); + setInterval(semantics, iord, interval); + } + } + } + + /** + * Merges this envelope with the point. The boundary of the envelope is + * increased to include the point. If the envelope is empty, the coordinates + * of the point to merge are assigned. If the point is empty, the original + * envelope is unchanged. + * + * @param point + * The point to be merged. + */ + public void merge(Point point) { + _touch(); + if (point.isEmptyImpl()) + return; + + VertexDescription pointVD = point.m_description; + if (m_description != pointVD) + mergeVertexDescription(pointVD); + + if (isEmpty()) { + _setFromPoint(point); + return; + } + + m_envelope.merge(point.getXY()); + for (int iattrib = 1, nattrib = pointVD.getAttributeCount(); iattrib < nattrib; iattrib++) { + int semantics = pointVD._getSemanticsImpl(iattrib); + int ncomps = VertexDescription.getComponentCount(semantics); + for (int iord = 0; iord < ncomps; iord++) { + double v = point.getAttributeAsDbl(semantics, iord); + Envelope1D interval = queryInterval(semantics, iord); + interval.merge(v); + setInterval(semantics, iord, interval); + } + } + } + + void _setFromPoint(Point centerPoint, double width, double height) { + m_envelope.setCoords(centerPoint.getXY(), width, height); + VertexDescription pointVD = centerPoint.m_description; + for (int iattrib = 1, nattrib = pointVD.getAttributeCount(); iattrib < nattrib; iattrib++) { + int semantics = pointVD._getSemanticsImpl(iattrib); + int ncomps = VertexDescription.getComponentCount(semantics); + for (int iord = 0; iord < ncomps; iord++) { + double v = centerPoint.getAttributeAsDbl(semantics, iord); + setInterval(semantics, iord, v, v); + } + } + } + + void _setFromPoint(Point centerPoint) { + mergeVertexDescription(centerPoint.getDescription()); + m_envelope.setCoords(centerPoint.getX(), centerPoint.getY()); + VertexDescription pointVD = centerPoint.m_description; + for (int iattrib = 1, nattrib = pointVD.getAttributeCount(); iattrib < nattrib; iattrib++) { + int semantics = pointVD._getSemanticsImpl(iattrib); + int ncomps = VertexDescription.getComponentCount(semantics); + for (int iord = 0; iord < ncomps; iord++) { + double v = centerPoint.getAttributeAsDbl(semantics, iord); + setInterval(semantics, iord, v, v); + } + } + } + + public void merge(Envelope2D other) { + _touch(); + m_envelope.merge(other); + } + + public void setInterval(int semantics, int ordinate, double vmin, + double vmax) { + setInterval(semantics, ordinate, new Envelope1D(vmin, vmax)); + } + + /** + * Re-aspects this envelope to fit within the specified width and height. + * + * @param arWidth + * The width within which to fit the envelope. + * @param arHeight + * The height within which to fit the envelope. + */ + public void reaspect(double arWidth, double arHeight) { + _touch(); + m_envelope.reaspect(arWidth, arHeight); + } + + /** + * Changes the dimensions of the envelope while preserving the center. New width + * is Width + 2 * dx, new height is Height + 2 * dy. If the result envelope + * width or height becomes negative, the envelope is set to be empty. + * + * @param dx + * The inflation along the x-axis. + * @param dy + * The inflation along the y-axis. + */ + public void inflate(double dx, double dy) { + _touch(); + m_envelope.inflate(dx, dy); + } + + @Override + public void applyTransformation(Transformation2D transform) { + _touch(); + transform.transform(m_envelope); + } + + @Override + void applyTransformation(Transformation3D transform) { + _touch(); + if (!m_envelope.isEmpty()) { + Envelope3D env = new Envelope3D(); + queryEnvelope3D(env); + if (env.isEmptyZ()) + env.setEmpty(); // Z components is empty, the + // AffineTransformation3D makes the whole + // envelope empty. Consider + // throwing an assert instead. + else + transform.transform(env); + } + } + + @Override + public void copyTo(Geometry dst) { + if (dst.getType() != getType()) + throw new IllegalArgumentException(); + + Envelope envDst = (Envelope) dst; + dst._touch(); + envDst.m_description = m_description; + envDst.m_envelope.setCoords(m_envelope); + envDst.m_attributes = null; + if (m_attributes != null) + { + envDst._ensureAttributes(); + System.arraycopy(m_attributes, 0, envDst.m_attributes, 0, + (m_description.getTotalComponentCount() - 2) * 2); + } + } + + @Override + public Geometry createInstance() { + return new Envelope(m_description); + } + + @Override + public double calculateArea2D() { + return m_envelope.getArea(); + } + + @Override + public double calculateLength2D() { + return m_envelope.getLength(); + } + + @Override + public Geometry.Type getType() { + return Type.Envelope; + } + + @Override + public int getDimension() { + return 2; + } @Override public long estimateMemorySize() @@ -439,676 +462,674 @@ public void queryEnvelope(Envelope env) { copyTo(env); } - @Override - public void queryEnvelope2D(Envelope2D env) { - env.xmin = m_envelope.xmin; - env.ymin = m_envelope.ymin; - env.xmax = m_envelope.xmax; - env.ymax = m_envelope.ymax; - } - - @Override - void queryEnvelope3D(Envelope3D env) { - env.xmin = m_envelope.xmin; - env.ymin = m_envelope.ymin; - env.xmax = m_envelope.xmax; - env.ymax = m_envelope.ymax; - env.setCoords(m_envelope.xmin, m_envelope.ymin, - _getAttributeAsDbl(0, Semantics.Z, 0), m_envelope.xmax, - m_envelope.ymax, _getAttributeAsDbl(1, Semantics.Z, 0)); - } - - @Override - public Envelope1D queryInterval(int semantics, int ordinate) { - Envelope1D env = new Envelope1D(); - env.setCoords(_getAttributeAsDbl(0, semantics, ordinate), - _getAttributeAsDbl(1, semantics, ordinate)); - return env; - } - - public void setInterval(int semantics, int ordinate, Envelope1D env) { - _touch(); - if (semantics == Semantics.POSITION) { - if (ordinate == 0) { - m_envelope.xmin = env.vmin; - m_envelope.xmax = env.vmax; - } else if (ordinate == 1) { - m_envelope.ymin = env.vmin; - m_envelope.ymax = env.vmax; - } else - throw new IndexOutOfBoundsException(); - } else { - _setAttributeAsDbl(0, semantics, ordinate, env.vmin); - _setAttributeAsDbl(1, semantics, ordinate, env.vmax); - } - } - - public void queryCoordinates(Point2D[] dst) { - if (dst == null || dst.length < 4 || m_envelope.isEmpty()) - throw new IllegalArgumentException(); - - m_envelope.queryCorners(dst); - } - - /** - * Sets the point's coordinates to the coordinates of the envelope at the - * given corner. - * - * @param index The index of the envelope's corners from 0 to 3. - *

- * 0 = lower left corner - *

- * 1 = top-left corner - *

- * 2 = top right corner - *

- * 3 = bottom right corner - * @param ptDst The point whose coordinates are used to set the envelope's - * coordinate at a specified corner. - */ - public void queryCornerByVal(int index, Point ptDst) { - ptDst.assignVertexDescription(m_description); - int nattrib = getDescription().getAttributeCount() - 1; - switch (index) { - case 0: { - for (int i = 0; i < nattrib; i++) { - int semantics = m_description.getSemantics(i); - int ncomp = VertexDescription.getComponentCount(semantics); - for (int iord = 0; iord < ncomp; iord++) - ptDst.setAttribute(semantics, iord, - _getAttributeAsDbl(0, semantics, iord)); - } - ptDst.setXY(m_envelope.xmin, m_envelope.ymin); - return; - } - - case 1: { - for (int i = 0; i < nattrib; i++) { - int semantics = m_description.getSemantics(i); - int ncomp = VertexDescription.getComponentCount(semantics); - for (int iord = 0; iord < ncomp; iord++) - ptDst.setAttribute(semantics, iord, - _getAttributeAsDbl(1, semantics, iord)); - } - ptDst.setXY(m_envelope.xmin, m_envelope.ymax); - return; - } - case 2: { - for (int i = 0; i < nattrib; i++) { - int semantics = m_description.getSemantics(i); - int ncomp = VertexDescription.getComponentCount(semantics); - for (int iord = 0; iord < ncomp; iord++) - ptDst.setAttribute(semantics, iord, - _getAttributeAsDbl(0, semantics, iord)); - } - ptDst.setXY(m_envelope.xmax, m_envelope.ymax); - - return; - } - case 3: { - for (int i = 0; i < nattrib; i++) { - int semantics = m_description.getSemantics(i); - int ncomp = VertexDescription.getComponentCount(semantics); - for (int iord = 0; iord < ncomp; iord++) - ptDst.setAttribute(semantics, iord, - _getAttributeAsDbl(1, semantics, iord)); - } - ptDst.setXY(m_envelope.xmax, m_envelope.ymin); - return; - } - default: - throw new IndexOutOfBoundsException(); - } - } - - public void queryCorner(int index, Point2D ptDst) { - Point2D p = m_envelope.queryCorner(index); - ptDst.setCoords(p.x, p.y); - } - - int getEndPointOffset(VertexDescription descr, int end_point) { - return end_point * (descr.getTotalComponentCount() - 2); - } - - double getAttributeAsDblImpl_(int end_point, int semantics, int ordinate) { - if (m_envelope.isEmpty()) - throw new GeometryException("empty geometry"); - - assert (end_point == 0 || end_point == 1); - - if (semantics == VertexDescription.Semantics.POSITION) { - if (end_point != 0) { - return ordinate != 0 ? m_envelope.ymax : m_envelope.xmax; - } else { - return ordinate != 0 ? m_envelope.ymin : m_envelope.xmin; - } - } - - int ncomps = VertexDescription.getComponentCount(semantics); - if (ordinate >= ncomps) - throw new IllegalArgumentException(); - - int attribute_index = m_description.getAttributeIndex(semantics); - _ensureAttributes(); - if (attribute_index >= 0) { - return m_attributes[getEndPointOffset(m_description, end_point) - + m_description.getPointAttributeOffset_(attribute_index) - - 2 + ordinate]; - } - - return VertexDescription.getDefaultValue(semantics); - } - - void setAttributeAsDblImpl_(int end_point, int semantics, int ordinate, - double value) { - assert (end_point == 0 || end_point == 1); - - if (semantics == VertexDescription.Semantics.POSITION) { - if (end_point != 0) { - if (ordinate != 0) - m_envelope.ymax = value; - else - m_envelope.xmax = value; - } else { - if (ordinate != 0) - m_envelope.ymin = value; - else - m_envelope.xmin = value; - } - - return; - } - - int ncomps = VertexDescription.getComponentCount(semantics); - if (ordinate >= ncomps) - throw new IllegalArgumentException(); - - addAttribute(semantics); - _ensureAttributes(); - int attribute_index = m_description.getAttributeIndex(semantics); - m_attributes[getEndPointOffset(m_description, end_point) - + m_description.getPointAttributeOffset_(attribute_index) - 2 - + ordinate] = value; - } - - void _ensureAttributes() { - _touch(); - if (m_attributes == null && m_description.getTotalComponentCount() > 2) { - m_attributes = new double[(m_description.getTotalComponentCount() - 2) * 2]; - int offset0 = _getEndPointOffset(m_description, 0); - int offset1 = _getEndPointOffset(m_description, 1); - - int j = 0; - for (int i = 1, n = m_description.getAttributeCount(); i < n; i++) { - int semantics = m_description.getSemantics(i); - int nords = VertexDescription.getComponentCount(semantics); - double d = VertexDescription.getDefaultValue(semantics); - for (int ord = 0; ord < nords; ord++) { - m_attributes[offset0 + j] = d; - m_attributes[offset1 + j] = d; - j++; - } - } - } - } - - @Override - protected void _assignVertexDescriptionImpl(VertexDescription newDescription) { - if (m_attributes == null) { - m_description = newDescription; - return; - } - - if (newDescription.getTotalComponentCount() > 2) { - int[] mapping = VertexDescriptionDesignerImpl.mapAttributes(newDescription, m_description); - - double[] newAttributes = new double[(newDescription.getTotalComponentCount() - 2) * 2]; - - int old_offset0 = _getEndPointOffset(m_description, 0); - int old_offset1 = _getEndPointOffset(m_description, 1); - - int new_offset0 = _getEndPointOffset(newDescription, 0); - int new_offset1 = _getEndPointOffset(newDescription, 1); - - int j = 0; - for (int i = 1, n = newDescription.getAttributeCount(); i < n; i++) { - int semantics = newDescription.getSemantics(i); - int nords = VertexDescription.getComponentCount(semantics); - if (mapping[i] == -1) { - double d = VertexDescription.getDefaultValue(semantics); - for (int ord = 0; ord < nords; ord++) { - newAttributes[new_offset0 + j] = d; - newAttributes[new_offset1 + j] = d; - j++; - } - } else { - int m = mapping[i]; - int offset = m_description._getPointAttributeOffset(m) - 2; - for (int ord = 0; ord < nords; ord++) { - newAttributes[new_offset0 + j] = m_attributes[old_offset0 + offset]; - newAttributes[new_offset1 + j] = m_attributes[old_offset1 + offset]; - j++; - offset++; - } - } - - } - - m_attributes = newAttributes; - } else { - m_attributes = null; - } - - m_description = newDescription; - } - - double _getAttributeAsDbl(int endPoint, int semantics, int ordinate) { - if (m_envelope.isEmpty()) - throw new GeometryException( - "This operation was performed on an Empty Geometry."); - - // _ASSERT(endPoint == 0 || endPoint == 1); - - if (semantics == Semantics.POSITION) { - if (endPoint != 0) { - return ordinate != 0 ? m_envelope.ymax : m_envelope.xmax; - } else { - return ordinate != 0 ? m_envelope.ymin : m_envelope.xmin; - } - } - - int ncomps = VertexDescription.getComponentCount(semantics); - if (ordinate >= ncomps) - throw new IndexOutOfBoundsException(); - - int attributeIndex = m_description.getAttributeIndex(semantics); - if (attributeIndex >= 0) { - _ensureAttributes(); - return m_attributes[_getEndPointOffset(m_description, endPoint) - + m_description._getPointAttributeOffset(attributeIndex) - - 2 + ordinate]; - } else - return VertexDescription.getDefaultValue(semantics); - } - - void _setAttributeAsDbl(int endPoint, int semantics, int ordinate, - double value) { - _touch(); - // _ASSERT(endPoint == 0 || endPoint == 1); - - if (semantics == Semantics.POSITION) { - if (endPoint != 0) { - if (ordinate != 0) - m_envelope.ymax = value; - else - m_envelope.xmax = value; - } else { - if (ordinate != 0) - m_envelope.ymin = value; - else - m_envelope.xmin = value; - } - - return; - } - - int ncomps = VertexDescription.getComponentCount(semantics); - if (ordinate >= ncomps) - throw new IndexOutOfBoundsException(); - - if (!hasAttribute(semantics)) { - if (VertexDescription.isDefaultValue(semantics, value)) - return; - - addAttribute(semantics); - } - - int attributeIndex = m_description.getAttributeIndex(semantics); - _ensureAttributes(); - m_attributes[_getEndPointOffset(m_description, endPoint) - + m_description._getPointAttributeOffset(attributeIndex) - 2 - + ordinate] = value; - } - - int _getAttributeAsInt(int endPoint, int semantics, int ordinate) { - return (int) _getAttributeAsDbl(endPoint, semantics, ordinate); - } - - static int _getEndPointOffset(VertexDescription vd, int endPoint) { - return endPoint * (vd.getTotalComponentCount() - 2); - } - - public boolean isIntersecting(Envelope2D other) { - return m_envelope.isIntersecting(other); - } - - /** - * Changes this envelope to be the intersection of itself with the other - * envelope. - * - * @param other The envelope to intersect. - * @return Returns true if the result is not empty. - */ - public boolean intersect(Envelope other) { - _touch(); - Envelope2D e2d = new Envelope2D(); - other.queryEnvelope2D(e2d); - return m_envelope.intersect(e2d); - } - - /** - * Returns true if the envelope and the other given envelope intersect. - * - * @param other The envelope to with which to test intersection. - * @return Returns true if the two envelopes intersect. - */ - public boolean isIntersecting(Envelope other) {// TODO: attributes. - return m_envelope.isIntersecting(other.m_envelope); - } - - /** - * Sets the envelope's corners to be centered around the specified point, - * using its center, width, and height. - * - * @param c The point around which to center the envelope. - * @param w The width to be set for the envelope. - * @param h The height to be set for this envelope. - */ - public void centerAt(Point c, double w, double h) { - _touch(); - if (c.isEmpty()) { - setEmpty(); - return; - } - - _setFromPoint(c, w, h); - } - - /** - * Offsets the envelope by the specified distances along x and y-coordinates. - * - * @param dx The X offset to be applied. - * @param dy The Y offset to be applied. - */ - public void offset(double dx, double dy) { - _touch(); - m_envelope.offset(dx, dy); - } - - /** - * Normalizes envelopes if the minimum dimension is larger than the - * maximum dimension. - */ - public void normalize() {// TODO: attributes - _touch(); - m_envelope.normalize(); - } - - /** - * Gets the center point of the envelope. The center point occurs at: ((XMin - * + XMax) / 2, (YMin + YMax) / 2). - * - * @return The center point of the envelope. - */ - public Point2D getCenter2D() { - return m_envelope.getCenter(); - } - - /** - * Returns the center point of the envelope. - * - * @return The center point of the envelope. - */ - public Point getCenter() { - Point pointOut = new Point(m_description); - if (isEmpty()) { - return pointOut; - } - int nattrib = m_description.getAttributeCount(); - for (int i = 1; i < nattrib; i++) { - int semantics = m_description._getSemanticsImpl(i); - int ncomp = VertexDescription.getComponentCount(semantics); - for (int iord = 0; iord < ncomp; iord++) { - double v = 0.5 * (_getAttributeAsDbl(0, semantics, iord) + _getAttributeAsDbl( - 1, semantics, iord)); - pointOut.setAttribute(semantics, iord, v); - } - } - pointOut.setXY(m_envelope.getCenterX(), m_envelope.getCenterY()); - return pointOut; - } - - /** - * Centers the envelope around the specified point preserving the envelope's - * width and height. - * - * @param c The new center point. - */ - public void centerAt(Point c) { - _touch(); - if (c.isEmpty()) { - setEmpty(); - return; - } - m_envelope.centerAt(c.getX(), c.getY()); - } - - /** - * Returns the envelope's lower left corner point. - * - * @return Returns the lower left corner point. - */ - public Point getLowerLeft() { - return new Point(m_envelope.getLowerLeft()); - } - - /** - * Returns the envelope's upper right corner point. - * - * @return Returns the upper right corner point. - */ - public Point getUpperRight() { - return new Point(m_envelope.getUpperRight()); - } - - /** - * Returns the envelope's lower right corner point. - * - * @return Returns the lower right corner point. - */ - public Point getLowerRight() { - return new Point(m_envelope.getLowerRight()); - } - - /** - * Returns the envelope's upper left corner point. - * - * @return Returns the upper left corner point. - */ - public Point getUpperLeft() { - return new Point(m_envelope.getUpperLeft()); - } - - /** - * Checks if this envelope contains (covers) the specified point. - * - * @param p The Point to be tested for coverage. - * @return TRUE if this envelope contains (covers) the specified point. - */ - public boolean contains(Point p) { - if (p.isEmpty()) - return false; - return m_envelope.contains(p.getX(), p.getY()); - } - - /** - * Checks if this envelope contains (covers) other envelope. - * - * @param env The envelope to be tested for coverage. - * @return TRUE if this envelope contains (covers) the specified envelope. - */ - public boolean contains(Envelope env) { - return m_envelope.contains(env.m_envelope); - } - - /** - * Returns TRUE when this geometry has exactly same type, properties, and - * coordinates as the other geometry. - */ - @Override - public boolean equals(Object _other) { - if (_other == this) - return true; - - if (!(_other instanceof Envelope)) - return false; - - Envelope other = (Envelope) _other; - - if (m_description != other.m_description) - return false; - - if (isEmpty()) - if (other.isEmpty()) - return true; - else - return false; - - if (!this.m_envelope.equals(other.m_envelope)) - return false; - - for (int i = 0, n = (m_description.getTotalComponentCount() - 2) * 2; i < n; i++) - if (m_attributes[i] != other.m_attributes[i]) - return false; - - return true; - } - - /** - * Returns a hash code value for this envelope. - * - * @return A hash code value for this envelope. - */ - @Override - public int hashCode() { - int hashCode = m_description.hashCode(); - hashCode = NumberUtils.hash(hashCode, m_envelope.hashCode()); - if (!isEmpty() && m_attributes != null) { - for (int i = 0, n = (m_description.getTotalComponentCount() - 2) * 2; i < n; i++) { - hashCode = NumberUtils.hash(hashCode, m_attributes[i]); - } - } - return hashCode; - } - - /** - * Returns the X coordinate of the left corners of the envelope. - * - * @return The X coordinate of the left corners. - */ - public final double getXMin() { - return m_envelope.xmin; - } - - /** - * Returns the Y coordinate of the bottom corners of the envelope. - * - * @return The Y coordinate of the bottom corners. - */ - public final double getYMin() { - return m_envelope.ymin; - } - - /** - * Returns the X coordinate of the right corners of the envelope. - * - * @return The X coordinate of the right corners. - */ - public final double getXMax() { - return m_envelope.xmax; - } - - /** - * Returns the Y coordinate of the top corners of the envelope. - * - * @return The Y coordinate of the top corners. - */ - public final double getYMax() { - return m_envelope.ymax; - } - - /** - * Sets the left X coordinate. - * - * @param x The X coordinate of the left corner - */ - public void setXMin(double x) { - _touch(); - m_envelope.xmin = x; - } - - /** - * Sets the right X coordinate. - * - * @param x The X coordinate of the right corner. - */ - public void setXMax(double x) { - _touch(); - m_envelope.xmax = x; - } - - /** - * Sets the bottom Y coordinate. - * - * @param y the Y coordinate of the bottom corner. - */ - public void setYMin(double y) { - _touch(); - m_envelope.ymin = y; - } - - /** - * Sets the top Y coordinate. - * - * @param y The Y coordinate of the top corner. - */ - public void setYMax(double y) { - _touch(); - m_envelope.ymax = y; - } - - @Override - public Geometry getBoundary() { - return Boundary.calculate(this, null); - } - - @Override - public void replaceNaNs(int semantics, double value) { - addAttribute(semantics); - if (isEmpty()) - return; - - int ncomps = VertexDescription.getComponentCount(semantics); - for (int i = 0; i < ncomps; i++) { - Envelope1D interval = queryInterval(semantics, i); - if (interval.isEmpty()) { - interval.vmin = value; - interval.vmax = value; - setInterval(semantics, i, interval); - } - } - } - - /** - * The output of this method can be only used for debugging. It is subject to change without notice. - */ - @Override - public String toString() { - if (isEmpty()) - return "Envelope: []"; - - String s = "Envelope: [" + m_envelope.xmin + ", " + m_envelope.ymin + ", " + m_envelope.xmax + ", " + m_envelope.ymax + "]"; - return s; - } + @Override + public void queryEnvelope2D(Envelope2D env) { + env.xmin = m_envelope.xmin; + env.ymin = m_envelope.ymin; + env.xmax = m_envelope.xmax; + env.ymax = m_envelope.ymax; + } + @Override + void queryEnvelope3D(Envelope3D env) { + env.xmin = m_envelope.xmin; + env.ymin = m_envelope.ymin; + env.xmax = m_envelope.xmax; + env.ymax = m_envelope.ymax; + env.setCoords(m_envelope.xmin, m_envelope.ymin, + _getAttributeAsDbl(0, Semantics.Z, 0), m_envelope.xmax, + m_envelope.ymax, _getAttributeAsDbl(1, Semantics.Z, 0)); + } + + @Override + public Envelope1D queryInterval(int semantics, int ordinate) { + Envelope1D env = new Envelope1D(); + env.setCoords(_getAttributeAsDbl(0, semantics, ordinate), + _getAttributeAsDbl(1, semantics, ordinate)); + return env; + } + + public void setInterval(int semantics, int ordinate, Envelope1D env) { + _touch(); + if (semantics == Semantics.POSITION) { + if (ordinate == 0) { + m_envelope.xmin = env.vmin; + m_envelope.xmax = env.vmax; + } else if (ordinate == 1) { + m_envelope.ymin = env.vmin; + m_envelope.ymax = env.vmax; + } else + throw new IndexOutOfBoundsException(); + } else { + _setAttributeAsDbl(0, semantics, ordinate, env.vmin); + _setAttributeAsDbl(1, semantics, ordinate, env.vmax); + } + } + + public void queryCoordinates(Point2D[] dst) { + if (dst == null || dst.length < 4 || m_envelope.isEmpty()) + throw new IllegalArgumentException(); + + m_envelope.queryCorners(dst); + } + + /** + * Sets the point's coordinates to the coordinates of the envelope at the + * given corner. + * + * @param index + * The index of the envelope's corners from 0 to 3. + *

+ * 0 = lower left corner + *

+ * 1 = top-left corner + *

+ * 2 = top right corner + *

+ * 3 = bottom right corner + * @param ptDst + * The point whose coordinates are used to set the envelope's + * coordinate at a specified corner. + */ + public void queryCornerByVal(int index, Point ptDst) { + ptDst.assignVertexDescription(m_description); + int nattrib = getDescription().getAttributeCount() - 1; + switch (index) { + case 0: { + for (int i = 0; i < nattrib; i++) { + int semantics = m_description.getSemantics(i); + int ncomp = VertexDescription.getComponentCount(semantics); + for (int iord = 0; iord < ncomp; iord++) + ptDst.setAttribute(semantics, iord, + _getAttributeAsDbl(0, semantics, iord)); + } + ptDst.setXY(m_envelope.xmin, m_envelope.ymin); + return; + } + + case 1: { + for (int i = 0; i < nattrib; i++) { + int semantics = m_description.getSemantics(i); + int ncomp = VertexDescription.getComponentCount(semantics); + for (int iord = 0; iord < ncomp; iord++) + ptDst.setAttribute(semantics, iord, + _getAttributeAsDbl(1, semantics, iord)); + } + ptDst.setXY(m_envelope.xmin, m_envelope.ymax); + return; + } + case 2: { + for (int i = 0; i < nattrib; i++) { + int semantics = m_description.getSemantics(i); + int ncomp = VertexDescription.getComponentCount(semantics); + for (int iord = 0; iord < ncomp; iord++) + ptDst.setAttribute(semantics, iord, + _getAttributeAsDbl(0, semantics, iord)); + } + ptDst.setXY(m_envelope.xmax, m_envelope.ymax); + + return; + } + case 3: { + for (int i = 0; i < nattrib; i++) { + int semantics = m_description.getSemantics(i); + int ncomp = VertexDescription.getComponentCount(semantics); + for (int iord = 0; iord < ncomp; iord++) + ptDst.setAttribute(semantics, iord, + _getAttributeAsDbl(1, semantics, iord)); + } + ptDst.setXY(m_envelope.xmax, m_envelope.ymin); + return; + } + default: + throw new IndexOutOfBoundsException(); + } + } + + public void queryCorner(int index, Point2D ptDst) { + Point2D p = m_envelope.queryCorner(index); + ptDst.setCoords(p.x, p.y); + } + + int getEndPointOffset(VertexDescription descr, int end_point) { + return end_point * (descr.getTotalComponentCount() - 2); + } + + double getAttributeAsDblImpl_(int end_point, int semantics, int ordinate) { + if (m_envelope.isEmpty()) + throw new GeometryException("empty geometry"); + + assert (end_point == 0 || end_point == 1); + + if (semantics == VertexDescription.Semantics.POSITION) { + if (end_point != 0) { + return ordinate != 0 ? m_envelope.ymax : m_envelope.xmax; + } else { + return ordinate != 0 ? m_envelope.ymin : m_envelope.xmin; + } + } + + int ncomps = VertexDescription.getComponentCount(semantics); + if (ordinate >= ncomps) + throw new IllegalArgumentException(); + + int attribute_index = m_description.getAttributeIndex(semantics); + if (attribute_index >= 0) { + return m_attributes[getEndPointOffset(m_description, end_point) + + m_description.getPointAttributeOffset_(attribute_index) + - 2 + ordinate]; + } + + return VertexDescription.getDefaultValue(semantics); + } + + void setAttributeAsDblImpl_(int end_point, int semantics, int ordinate, + double value) { + assert (end_point == 0 || end_point == 1); + + if (semantics == VertexDescription.Semantics.POSITION) { + if (end_point != 0) { + if (ordinate != 0) + m_envelope.ymax = value; + else + m_envelope.xmax = value; + } else { + if (ordinate != 0) + m_envelope.ymin = value; + else + m_envelope.xmin = value; + } + + return; + } + + int ncomps = VertexDescription.getComponentCount(semantics); + if (ordinate >= ncomps) + throw new IllegalArgumentException(); + + addAttribute(semantics); + int attribute_index = m_description.getAttributeIndex(semantics); + m_attributes[getEndPointOffset(m_description, end_point) + + m_description.getPointAttributeOffset_(attribute_index) - 2 + + ordinate] = value; + } + + void _ensureAttributes() { + _touch(); + if (m_attributes == null && m_description.getTotalComponentCount() > 2) { + int halfLength = m_description.getTotalComponentCount() - 2; + m_attributes = new double[halfLength * 2]; + int offset0 = _getEndPointOffset(m_description, 0); + int offset1 = _getEndPointOffset(m_description, 1); + System.arraycopy(m_description._getDefaultPointAttributes(), 2, m_attributes, offset0, halfLength); + System.arraycopy(m_description._getDefaultPointAttributes(), 2, m_attributes, offset1, halfLength); + } + } + + @Override + protected void _assignVertexDescriptionImpl(VertexDescription newDescription) { + if (newDescription.getTotalComponentCount() > 2) { + int[] mapping = VertexDescriptionDesignerImpl.mapAttributes(newDescription, m_description); + + double[] newAttributes = new double[(newDescription.getTotalComponentCount() - 2) * 2]; + + int old_offset0 = _getEndPointOffset(m_description, 0); + int old_offset1 = _getEndPointOffset(m_description, 1); + + int new_offset0 = _getEndPointOffset(newDescription, 0); + int new_offset1 = _getEndPointOffset(newDescription, 1); + + int j = 0; + for (int i = 1, n = newDescription.getAttributeCount(); i < n; i++) { + int semantics = newDescription.getSemantics(i); + int nords = VertexDescription.getComponentCount(semantics); + if (mapping[i] == -1) + { + double d = VertexDescription.getDefaultValue(semantics); + for (int ord = 0; ord < nords; ord++) + { + newAttributes[new_offset0 + j] = d; + newAttributes[new_offset1 + j] = d; + j++; + } + } + else { + int m = mapping[i]; + int offset = m_description._getPointAttributeOffset(m) - 2; + for (int ord = 0; ord < nords; ord++) + { + newAttributes[new_offset0 + j] = m_attributes[old_offset0 + offset]; + newAttributes[new_offset1 + j] = m_attributes[old_offset1 + offset]; + j++; + offset++; + } + } + + } + + m_attributes = newAttributes; + } + else { + m_attributes = null; + } + + m_description = newDescription; + } + + double _getAttributeAsDbl(int endPoint, int semantics, int ordinate) { + if (m_envelope.isEmpty()) + throw new GeometryException( + "This operation was performed on an Empty Geometry."); + + if (semantics == Semantics.POSITION) { + if (endPoint != 0) { + return ordinate != 0 ? m_envelope.ymax : m_envelope.xmax; + } else { + return ordinate != 0 ? m_envelope.ymin : m_envelope.xmin; + } + } + + int ncomps = VertexDescription.getComponentCount(semantics); + if (ordinate >= ncomps) + throw new IndexOutOfBoundsException(); + + int attributeIndex = m_description.getAttributeIndex(semantics); + if (attributeIndex >= 0) { + return m_attributes[_getEndPointOffset(m_description, endPoint) + + m_description._getPointAttributeOffset(attributeIndex) + - 2 + ordinate]; + } else + return VertexDescription.getDefaultValue(semantics); + } + + void _setAttributeAsDbl(int endPoint, int semantics, int ordinate, + double value) { + _touch(); + // _ASSERT(endPoint == 0 || endPoint == 1); + + if (semantics == Semantics.POSITION) { + if (endPoint != 0) { + if (ordinate != 0) + m_envelope.ymax = value; + else + m_envelope.xmax = value; + } else { + if (ordinate != 0) + m_envelope.ymin = value; + else + m_envelope.xmin = value; + } + + return; + } + + int ncomps = VertexDescription.getComponentCount(semantics); + if (ordinate >= ncomps) + throw new IndexOutOfBoundsException(); + + if (!hasAttribute(semantics)) { + addAttribute(semantics); + } + + int attributeIndex = m_description.getAttributeIndex(semantics); + m_attributes[_getEndPointOffset(m_description, endPoint) + + m_description._getPointAttributeOffset(attributeIndex) - 2 + + ordinate] = value; + } + + int _getAttributeAsInt(int endPoint, int semantics, int ordinate) { + return (int) _getAttributeAsDbl(endPoint, semantics, ordinate); + } + + static int _getEndPointOffset(VertexDescription vd, int endPoint) { + return endPoint * (vd.getTotalComponentCount() - 2); + } + + public boolean isIntersecting(Envelope2D other) { + return m_envelope.isIntersecting(other); + } + + /** + * Changes this envelope to be the intersection of itself with the other + * envelope. + * + * @param other + * The envelope to intersect. + * @return Returns true if the result is not empty. + */ + public boolean intersect(Envelope other) { + _touch(); + Envelope2D e2d = new Envelope2D(); + other.queryEnvelope2D(e2d); + return m_envelope.intersect(e2d); + } + + /** + * Returns true if the envelope and the other given envelope intersect. + * + * @param other + * The envelope to with which to test intersection. + * @return Returns true if the two envelopes intersect. + */ + public boolean isIntersecting(Envelope other) {// TODO: attributes. + return m_envelope.isIntersecting(other.m_envelope); + } + + /** + * Sets the envelope's corners to be centered around the specified point, + * using its center, width, and height. + * + * @param c + * The point around which to center the envelope. + * @param w + * The width to be set for the envelope. + * @param h + * The height to be set for this envelope. + */ + public void centerAt(Point c, double w, double h) { + _touch(); + if (c.isEmpty()) { + setEmpty(); + return; + } + + _setFromPoint(c, w, h); + } + + /** + * Offsets the envelope by the specified distances along x and y-coordinates. + * + * @param dx + * The X offset to be applied. + * @param dy + * The Y offset to be applied. + */ + public void offset(double dx, double dy) { + _touch(); + m_envelope.offset(dx, dy); + } + + /** + * Normalizes envelopes if the minimum dimension is larger than the + * maximum dimension. + */ + public void normalize() {// TODO: attributes + _touch(); + m_envelope.normalize(); + } + + /** + * Gets the center point of the envelope. The center point occurs at: ((XMin + * + XMax) / 2, (YMin + YMax) / 2). + * + * @return The center point of the envelope. + */ + public Point2D getCenter2D() { + return m_envelope.getCenter(); + } + + /** + * Returns the center point of the envelope. + * + * @return The center point of the envelope. + */ + public Point getCenter() { + Point pointOut = new Point(m_description); + if (isEmpty()) { + return pointOut; + } + int nattrib = m_description.getAttributeCount(); + for (int i = 1; i < nattrib; i++) { + int semantics = m_description._getSemanticsImpl(i); + int ncomp = VertexDescription.getComponentCount(semantics); + for (int iord = 0; iord < ncomp; iord++) { + double v = 0.5 * (_getAttributeAsDbl(0, semantics, iord) + _getAttributeAsDbl( + 1, semantics, iord)); + pointOut.setAttribute(semantics, iord, v); + } + } + pointOut.setXY(m_envelope.getCenterX(), m_envelope.getCenterY()); + return pointOut; + } + + /** + * Centers the envelope around the specified point preserving the envelope's + * width and height. + * + * @param c + * The new center point. + */ + public void centerAt(Point c) { + _touch(); + if (c.isEmpty()) { + setEmpty(); + return; + } + m_envelope.centerAt(c.getX(), c.getY()); + } + + /** + * Returns the envelope's lower left corner point. + * + * @return Returns the lower left corner point. + */ + public Point getLowerLeft() { + return new Point(m_envelope.getLowerLeft()); + } + + /** + * Returns the envelope's upper right corner point. + * + * @return Returns the upper right corner point. + */ + public Point getUpperRight() { + return new Point(m_envelope.getUpperRight()); + } + + /** + * Returns the envelope's lower right corner point. + * + * @return Returns the lower right corner point. + */ + public Point getLowerRight() { + return new Point(m_envelope.getLowerRight()); + } + + /** + * Returns the envelope's upper left corner point. + * + * @return Returns the upper left corner point. + */ + public Point getUpperLeft() { + return new Point(m_envelope.getUpperLeft()); + } + + /** + * Checks if this envelope contains (covers) the specified point. + * + * @param p + * The Point to be tested for coverage. + * @return TRUE if this envelope contains (covers) the specified point. + */ + public boolean contains(Point p) { + if (p.isEmpty()) + return false; + return m_envelope.contains(p.getX(), p.getY()); + } + + /** + * Checks if this envelope contains (covers) other envelope. + * + * @param env + * The envelope to be tested for coverage. + * @return TRUE if this envelope contains (covers) the specified envelope. + */ + public boolean contains(Envelope env) { + return m_envelope.contains(env.m_envelope); + } + + /** + * Returns TRUE when this geometry has exactly same type, properties, and + * coordinates as the other geometry. + */ + @Override + public boolean equals(Object _other) { + if (_other == this) + return true; + + if (!(_other instanceof Envelope)) + return false; + + Envelope other = (Envelope) _other; + + if (m_description != other.m_description) + return false; + + if (isEmpty()) + if (other.isEmpty()) + return true; + else + return false; + + if (!this.m_envelope.equals(other.m_envelope)) + return false; + + for (int i = 0, n = (m_description.getTotalComponentCount() - 2) * 2; i < n; i++) + if (!NumberUtils.isEqualNonIEEE(m_attributes[i], other.m_attributes[i])) + return false; + + return true; + } + + /** + * Returns a hash code value for this envelope. + * + * @return A hash code value for this envelope. + */ + @Override + public int hashCode() { + int hashCode = m_description.hashCode(); + hashCode = NumberUtils.hash(hashCode, m_envelope.hashCode()); + if (!isEmpty()) { + for (int i = 0, n = (m_description.getTotalComponentCount() - 2) * 2; i < n; i++) { + hashCode = NumberUtils.hash(hashCode, m_attributes[i]); + } + } + return hashCode; + } + + /** + * Returns the X coordinate of the left corners of the envelope. + * + * @return The X coordinate of the left corners. + */ + public final double getXMin() { + return m_envelope.xmin; + } + + /** + * Returns the Y coordinate of the bottom corners of the envelope. + * + * @return The Y coordinate of the bottom corners. + */ + public final double getYMin() { + return m_envelope.ymin; + } + + /** + * Returns the X coordinate of the right corners of the envelope. + * + * @return The X coordinate of the right corners. + */ + public final double getXMax() { + return m_envelope.xmax; + } + + /** + * Returns the Y coordinate of the top corners of the envelope. + * + * @return The Y coordinate of the top corners. + */ + public final double getYMax() { + return m_envelope.ymax; + } + + /** + * Sets the left X coordinate. + * + * @param x + * The X coordinate of the left corner + */ + public void setXMin(double x) { + _touch(); + m_envelope.xmin = x; + } + + /** + * Sets the right X coordinate. + * + * @param x + * The X coordinate of the right corner. + */ + public void setXMax(double x) { + _touch(); + m_envelope.xmax = x; + } + + /** + * Sets the bottom Y coordinate. + * + * @param y + * the Y coordinate of the bottom corner. + */ + public void setYMin(double y) { + _touch(); + m_envelope.ymin = y; + } + + /** + * Sets the top Y coordinate. + * + * @param y + * The Y coordinate of the top corner. + */ + public void setYMax(double y) { + _touch(); + m_envelope.ymax = y; + } + + @Override + public Geometry getBoundary() { + return Boundary.calculate(this, null); + } + + @Override + public void replaceNaNs(int semantics, double value) { + addAttribute(semantics); + if (isEmpty()) + return; + + int ncomps = VertexDescription.getComponentCount(semantics); + for (int i = 0; i < ncomps; i++) { + Envelope1D interval = queryInterval(semantics, i); + if (interval.isEmpty()) { + interval.vmin = value; + interval.vmax = value; + setInterval(semantics, i, interval); + } + } + } + + /** + * The output of this method can be only used for debugging. It is subject to change without notice. + */ + @Override + public String toString() { + if (isEmpty()) + return "Envelope: []"; + + String s = "Envelope: [" + m_envelope.xmin + ", " + m_envelope.ymin + ", " + m_envelope.xmax + ", " + m_envelope.ymax +"]"; + return s; + } + } diff --git a/src/main/java/com/esri/core/geometry/Envelope1D.java b/src/main/java/com/esri/core/geometry/Envelope1D.java index f81bada7..e000ef0a 100644 --- a/src/main/java/com/esri/core/geometry/Envelope1D.java +++ b/src/main/java/com/esri/core/geometry/Envelope1D.java @@ -31,194 +31,207 @@ * A 1-dimensional interval. */ public final class Envelope1D implements Serializable { - private static final long serialVersionUID = 1L; - - public double vmin; - - public double vmax; - - public Envelope1D() { - - } - - public Envelope1D(double _vmin, double _vmax) { - setCoords(_vmin, _vmax); - } - - public Envelope1D(Envelope1D other) { - setCoords(other); - } - - public void setCoords(double _vmin, double _vmax) { - vmin = _vmin; - vmax = _vmax; - normalize(); - } - - public void setCoords(Envelope1D other) { - setCoords(other.vmin, other.vmax); - } - - public void normalize() { - if (NumberUtils.isNaN(vmin)) - return; - if (vmin > vmax) { - double v = vmin; - vmin = vmax; - vmax = v; - } - if (NumberUtils.isNaN(vmax))// vmax can be NAN - { - setEmpty(); - } - } - - public void setEmpty() { - vmin = NumberUtils.NaN(); - vmax = NumberUtils.NaN(); - } - - public boolean isEmpty() { - return NumberUtils.isNaN(vmin) || NumberUtils.isNaN(vmax); - } - - public void setInfinite() { - vmin = NumberUtils.negativeInf(); - vmax = NumberUtils.positiveInf(); - } - - public void merge(double v) { - if (isEmpty()) { - vmin = v; - vmax = v; - return; - } - - // no need to check for NaN, because all comparisons with NaN are false. - mergeNE(v); - } - - public void merge(Envelope1D other) { - if (other.isEmpty()) - return; - - if (isEmpty()) { - vmin = other.vmin; - vmax = other.vmax; - return; - } - - if (vmin > other.vmin) - vmin = other.vmin; - if (vmax < other.vmax) - vmax = other.vmax; - - if (vmin > vmax) - setEmpty(); - } - - public void mergeNE(double v) { - // Note, if v is NaN, vmin and vmax are unchanged - if (v < vmin) - vmin = v; - else if (v > vmax) - vmax = v; - } - - public boolean contains(double v) { - // If vmin is NaN, return false. No need to check for isEmpty. - return v >= vmin && v <= vmax; - } - - /** - * Returns True if the envelope contains the other envelope (boundary - * inclusive). Note: Will return false if either envelope is empty. - */ - public boolean contains(/* const */Envelope1D other) /* const */ { - return other.vmin >= vmin && other.vmax <= vmax; - } - - public void intersect(Envelope1D other) { - if (isEmpty() || other.isEmpty()) { - setEmpty(); - return; - } - - if (vmin < other.vmin) - vmin = other.vmin; - if (vmax > other.vmax) - vmax = other.vmax; - - if (vmin > vmax) - setEmpty(); - } - - public void inflate(double delta) { - if (isEmpty()) - return; - - vmin -= delta; - vmax += delta; - if (vmax < vmin) - setEmpty(); - } - - double _calculateToleranceFromEnvelope() { - if (isEmpty()) - return NumberUtils.doubleEps() * 100.0; // GEOMTERYX_EPSFACTOR - // 100.0; - double r = Math.abs(vmin) + Math.abs(vmax) + 1; - return r * NumberUtils.doubleEps() * 100.0; // GEOMTERYX_EPSFACTOR - // 100.0; - } - - void normalizeNoNaN_() { - if (vmin > vmax) { - double v = vmin; - vmin = vmax; - vmax = v; - } - } - - void setCoordsNoNaN_(double vmin_, double vmax_) { - vmin = vmin_; - vmax = vmax_; - normalizeNoNaN_(); - } - - public double snapClip(double v) /* const */ { - return NumberUtils.snap(v, vmin, vmax); - } - - public double getWidth() /* const */ { - return vmax - vmin; - } - - public double getCenter() /* const */ { - return 0.5 * (vmin + vmax); - } - - @Override - public boolean equals(Object _other) { - if (_other == this) - return true; - - if (!(_other instanceof Envelope1D)) - return false; - - Envelope1D other = (Envelope1D) _other; - if (isEmpty() && other.isEmpty()) - return true; - - if (vmin != other.vmin || vmax != other.vmax) - return false; - - return true; - } - - @Override - public int hashCode() { - return NumberUtils.hash(NumberUtils.hash(vmin), vmax); - } - + private static final long serialVersionUID = 1L; + + public double vmin; + + public double vmax; + + public Envelope1D() { + + } + + public Envelope1D(double _vmin, double _vmax) { + setCoords(_vmin, _vmax); + } + + public Envelope1D(Envelope1D other) { + setCoords(other); + } + + public void setCoords(double _vmin, double _vmax) { + vmin = _vmin; + vmax = _vmax; + normalize(); + } + + public void setCoords(Envelope1D other) { + setCoords(other.vmin, other.vmax); + } + + public void normalize() { + if (NumberUtils.isNaN(vmin)) + return; + if (vmin > vmax) { + double v = vmin; + vmin = vmax; + vmax = v; + } + if (NumberUtils.isNaN(vmax))// vmax can be NAN + { + setEmpty(); + } + } + + public void setEmpty() { + vmin = NumberUtils.NaN(); + vmax = NumberUtils.NaN(); + } + + public boolean isEmpty() { + return NumberUtils.isNaN(vmin) || NumberUtils.isNaN(vmax); + } + + public void setInfinite() { + vmin = NumberUtils.negativeInf(); + vmax = NumberUtils.positiveInf(); + } + + public void merge(double v) { + if (isEmpty()) { + vmin = v; + vmax = v; + return; + } + + // no need to check for NaN, because all comparisons with NaN are false. + mergeNE(v); + } + + public void merge(Envelope1D other) { + if (other.isEmpty()) + return; + + if (isEmpty()) { + vmin = other.vmin; + vmax = other.vmax; + return; + } + + if (vmin > other.vmin) + vmin = other.vmin; + if (vmax < other.vmax) + vmax = other.vmax; + + if (vmin > vmax) + setEmpty(); + } + + public void mergeNE(double v) { + // Note, if v is NaN, vmin and vmax are unchanged + if (v < vmin) + vmin = v; + else if (v > vmax) + vmax = v; + } + + public boolean contains(double v) { + // If vmin is NaN, return false. No need to check for isEmpty. + return v >= vmin && v <= vmax; + } + + /** + * Returns True if the envelope contains the other envelope (boundary + * inclusive). Note: Will return false if either envelope is empty. + * @param other The other envelope. + * @return Return true if this contains the other. + */ + public boolean contains(Envelope1D other) + { + return other.vmin >= vmin && other.vmax <= vmax; + } + + public void intersect(Envelope1D other) { + if (isEmpty() || other.isEmpty()) { + setEmpty(); + return; + } + + if (vmin < other.vmin) + vmin = other.vmin; + if (vmax > other.vmax) + vmax = other.vmax; + + if (vmin > vmax) + setEmpty(); + } + + public void inflate(double delta) { + if (isEmpty()) + return; + + vmin -= delta; + vmax += delta; + if (vmax < vmin) + setEmpty(); + } + + double _calculateToleranceFromEnvelope() { + if (isEmpty()) + return NumberUtils.doubleEps() * 100.0; // GEOMTERYX_EPSFACTOR + // 100.0; + double r = Math.abs(vmin) + Math.abs(vmax) + 1; + return r * NumberUtils.doubleEps() * 100.0; // GEOMTERYX_EPSFACTOR + // 100.0; + } + + void normalizeNoNaN_() { + if (vmin > vmax) { + double v = vmin; + vmin = vmax; + vmax = v; + } + } + + void setCoordsNoNaN_(double vmin_, double vmax_) { + vmin = vmin_; + vmax = vmax_; + normalizeNoNaN_(); + } + + public double snapClip(double v) /* const */ + { + return NumberUtils.snap(v, vmin, vmax); + } + + public double getWidth() /* const */ + { + return vmax - vmin; + } + + public double getCenter() /* const */ + { + return 0.5 * (vmin + vmax); + } + + @Override + public boolean equals(Object _other) + { + if (_other == this) + return true; + + if (!(_other instanceof Envelope1D)) + return false; + + Envelope1D other = (Envelope1D) _other; + if (isEmpty() && other.isEmpty()) + return true; + + if (vmin != other.vmin || vmax != other.vmax) + return false; + + return true; + } + + @Override + public int hashCode() { + if (isEmpty()) { + return NumberUtils.hash(NumberUtils.TheNaN); + } + + int hash = NumberUtils.hash(vmin); + hash = NumberUtils.hash(hash, vmax); + return hash; + } + } diff --git a/src/main/java/com/esri/core/geometry/Envelope2D.java b/src/main/java/com/esri/core/geometry/Envelope2D.java index 1d6172f5..5c8bebf5 100644 --- a/src/main/java/com/esri/core/geometry/Envelope2D.java +++ b/src/main/java/com/esri/core/geometry/Envelope2D.java @@ -34,49 +34,49 @@ * An axis parallel 2-dimensional rectangle. */ public final class Envelope2D implements Serializable { - private static final long serialVersionUID = 1L; - - private final static int XLESSXMIN = 1; - // private final int XGREATERXMAX = 2; - private final static int YLESSYMIN = 4; - // private final int YGREATERYMAX = 8; - private final static int XMASK = 3; - private final static int YMASK = 12; - - public double xmin; - - public double ymin; - - public double xmax; - - public double ymax; - - public static Envelope2D construct(double _xmin, double _ymin, - double _xmax, double _ymax) { - Envelope2D env = new Envelope2D(); - env.xmin = _xmin; - env.ymin = _ymin; - env.xmax = _xmax; - env.ymax = _ymax; - return env; - } - - public static Envelope2D construct(Envelope2D other) { - Envelope2D env = new Envelope2D(); - env.setCoords(other); - return env; - } - - public Envelope2D() { - setEmpty(); - } - - public Envelope2D(double _xmin, double _ymin, double _xmax, double _ymax) { - xmin = _xmin; - ymin = _ymin; - xmax = _xmax; - ymax = _ymax; - } + private static final long serialVersionUID = 1L; + + private final static int XLESSXMIN = 1; + // private final int XGREATERXMAX = 2; + private final static int YLESSYMIN = 4; + // private final int YGREATERYMAX = 8; + private final static int XMASK = 3; + private final static int YMASK = 12; + + public double xmin; + + public double ymin; + + public double xmax; + + public double ymax; + + public static Envelope2D construct(double _xmin, double _ymin, + double _xmax, double _ymax) { + Envelope2D env = new Envelope2D(); + env.xmin = _xmin; + env.ymin = _ymin; + env.xmax = _xmax; + env.ymax = _ymax; + return env; + } + + public static Envelope2D construct(Envelope2D other) { + Envelope2D env = new Envelope2D(); + env.setCoords(other); + return env; + } + + public Envelope2D() { + setEmpty(); + } + + public Envelope2D(double _xmin, double _ymin, double _xmax, double _ymax) { + xmin = _xmin; + ymin = _ymin; + xmax = _xmax; + ymax = _ymax; + } public Envelope2D(Envelope2D other) { setCoords(other); @@ -86,7 +86,7 @@ public int estimateMemorySize() { return SIZE_OF_ENVELOPE2D; } - + public void setCoords(double _x, double _y) { xmin = _x; ymin = _y; @@ -94,39 +94,39 @@ public void setCoords(double _x, double _y) { ymax = _y; } - public void setCoords(double _xmin, double _ymin, double _xmax, double _ymax) { - xmin = _xmin; - ymin = _ymin; - xmax = _xmax; - ymax = _ymax; - normalize(); - } - - public void setCoords(Point2D center, double width, double height) { - xmin = center.x - width * 0.5; - xmax = xmin + width; - ymin = center.y - height * 0.5; - ymax = ymin + height; - normalize(); - } - - public void setCoords(Point2D pt) { - xmin = pt.x; - ymin = pt.y; - xmax = pt.x; - ymax = pt.y; - } - - public void setCoords(Envelope2D envSrc) { - setCoords(envSrc.xmin, envSrc.ymin, envSrc.xmax, envSrc.ymax); - } - - public Envelope2D getInflated(double dx, double dy) { - Envelope2D env = new Envelope2D(); - env.setCoords(this.xmin, this.ymin, this.xmax, this.ymax); - env.inflate(dx, dy); - return env; - } + public void setCoords(double _xmin, double _ymin, double _xmax, double _ymax) { + xmin = _xmin; + ymin = _ymin; + xmax = _xmax; + ymax = _ymax; + normalize(); + } + + public void setCoords(Point2D center, double width, double height) { + xmin = center.x - width * 0.5; + xmax = xmin + width; + ymin = center.y - height * 0.5; + ymax = ymin + height; + normalize(); + } + + public void setCoords(Point2D pt) { + xmin = pt.x; + ymin = pt.y; + xmax = pt.x; + ymax = pt.y; + } + + public void setCoords(Envelope2D envSrc) { + setCoords(envSrc.xmin, envSrc.ymin, envSrc.xmax, envSrc.ymax); + } + + public Envelope2D getInflated(double dx, double dy) { + Envelope2D env = new Envelope2D(); + env.setCoords(this.xmin, this.ymin, this.xmax, this.ymax); + env.inflate(dx, dy); + return env; + } /** * Sets the envelope from the array of points. The envelope will be set to @@ -139,62 +139,62 @@ public void setFromPoints(Point2D[] points) { return; } - Point2D pt = points[0]; - setCoords(pt.x, pt.y); - for (int i = 1; i < points.length; i++) { - Point2D pt2d = points[i]; - mergeNE(pt2d.x, pt2d.y); - } - } - - public void setEmpty() { - xmin = NumberUtils.TheNaN; - ymin = NumberUtils.TheNaN; - xmax = NumberUtils.TheNaN; - ymax = NumberUtils.TheNaN; - } - - public void setInfinite() { - xmin = NumberUtils.negativeInf(); - xmax = NumberUtils.positiveInf(); - ymin = NumberUtils.negativeInf(); - ymax = NumberUtils.positiveInf(); - } - - public boolean isEmpty() { - return NumberUtils.isNaN(xmin) || NumberUtils.isNaN(ymin) || NumberUtils.isNaN(xmax) || NumberUtils.isNaN(ymax); - } - - public void setCoords(Envelope1D xinterval, Envelope1D yinterval) { - if (xinterval.isEmpty() || yinterval.isEmpty()) { - setEmpty(); - return; - } - - xmin = xinterval.vmin; - xmax = xinterval.vmax; - ymin = yinterval.vmin; - ymax = yinterval.vmax; - } - - public void merge(double x, double y) { - if (isEmpty()) { - xmin = x; - ymin = y; - xmax = x; - ymax = y; - } else { - if (xmin > x) - xmin = x; - else if (xmax < x) - xmax = x; - - if (ymin > y) - ymin = y; - else if (ymax < y) - ymax = y; - } - } + Point2D pt = points[0]; + setCoords(pt.x, pt.y); + for (int i = 1; i < points.length; i++) { + Point2D pt2d = points[i]; + mergeNE(pt2d.x, pt2d.y); + } + } + + public void setEmpty() { + xmin = NumberUtils.TheNaN; + ymin = NumberUtils.TheNaN; + xmax = NumberUtils.TheNaN; + ymax = NumberUtils.TheNaN; + } + + public void setInfinite() { + xmin = NumberUtils.negativeInf(); + xmax = NumberUtils.positiveInf(); + ymin = NumberUtils.negativeInf(); + ymax = NumberUtils.positiveInf(); + } + + public boolean isEmpty() { + return NumberUtils.isNaN(xmin) || NumberUtils.isNaN(ymin) || NumberUtils.isNaN(xmax) || NumberUtils.isNaN(ymax); + } + + public void setCoords(Envelope1D xinterval, Envelope1D yinterval) { + if (xinterval.isEmpty() || yinterval.isEmpty()) { + setEmpty(); + return; + } + + xmin = xinterval.vmin; + xmax = xinterval.vmax; + ymin = yinterval.vmin; + ymax = yinterval.vmax; + } + + public void merge(double x, double y) { + if (isEmpty()) { + xmin = x; + ymin = y; + xmax = x; + ymax = y; + } else { + if (xmin > x) + xmin = x; + else if (xmax < x) + xmax = x; + + if (ymin > y) + ymin = y; + else if (ymax < y) + ymax = y; + } + } /** * Merges a point with this envelope without checking if the envelope is @@ -208,56 +208,56 @@ public void mergeNE(double x, double y) { else if (xmax < x) xmax = x; - if (ymin > y) - ymin = y; - else if (ymax < y) - ymax = y; - } - - public void merge(Point2D pt) { - merge(pt.x, pt.y); - } - - public void merge(Point3D pt) { - merge(pt.x, pt.y); - } - - public void merge(Envelope2D other) { - if (other.isEmpty()) - return; - - merge(other.xmin, other.ymin); - merge(other.xmax, other.ymax); - } - - public void inflate(double dx, double dy) { - if (isEmpty()) - return; - xmin -= dx; - xmax += dx; - ymin -= dy; - ymax += dy; - if (xmin > xmax || ymin > ymax) - setEmpty(); - } - - public void scale(double f) { - if (f < 0.0) - setEmpty(); - - if (isEmpty()) - return; - - xmin *= f; - xmax *= f; - ymin *= f; - ymax *= f; - } - - public void zoom(double factorX, double factorY) { - if (!isEmpty()) - setCoords(getCenter(), factorX * getWidth(), factorY * getHeight()); - } + if (ymin > y) + ymin = y; + else if (ymax < y) + ymax = y; + } + + public void merge(Point2D pt) { + merge(pt.x, pt.y); + } + + public void merge(Point3D pt) { + merge(pt.x, pt.y); + } + + public void merge(Envelope2D other) { + if (other.isEmpty()) + return; + + merge(other.xmin, other.ymin); + merge(other.xmax, other.ymax); + } + + public void inflate(double dx, double dy) { + if (isEmpty()) + return; + xmin -= dx; + xmax += dx; + ymin -= dy; + ymax += dy; + if (xmin > xmax || ymin > ymax) + setEmpty(); + } + + public void scale(double f) { + if (f < 0.0) + setEmpty(); + + if (isEmpty()) + return; + + xmin *= f; + xmax *= f; + ymin *= f; + ymax *= f; + } + + public void zoom(double factorX, double factorY) { + if (!isEmpty()) + setCoords(getCenter(), factorX * getWidth(), factorY * getHeight()); + } /** * Checks if this envelope intersects the other. @@ -312,7 +312,7 @@ public boolean isIntersecting(double xmin_, double ymin_, double xmax_, double y // projections // overlap } - + /** * Intersects this envelope with the other and stores result in this * envelope. @@ -321,58 +321,62 @@ public boolean isIntersecting(double xmin_, double ymin_, double xmax_, double y * envelope to empty state and returns False. */ public boolean intersect(Envelope2D other) { - if (isEmpty() || other.isEmpty()) + if (isEmpty() || other.isEmpty()) { + setEmpty(); return false; + } + + if (other.xmin > xmin) + xmin = other.xmin; - if (other.xmin > xmin) - xmin = other.xmin; - - if (other.xmax < xmax) - xmax = other.xmax; - - if (other.ymin > ymin) - ymin = other.ymin; - - if (other.ymax < ymax) - ymax = other.ymax; - - boolean bIntersecting = xmin <= xmax && ymin <= ymax; - - if (!bIntersecting) - setEmpty(); - - return bIntersecting; - } - - /** - * Queries a corner of the envelope. - * - * @param index Indicates a corner of the envelope. - *

- * 0 means lower left or (xmin, ymin) - *

- * 1 means upper left or (xmin, ymax) - *

- * 2 means upper right or (xmax, ymax) - *

- * 3 means lower right or (xmax, ymin) - * @return Point at a corner of the envelope. - */ - public Point2D queryCorner(int index) { - switch (index) { - case 0: - return Point2D.construct(xmin, ymin); - case 1: - return Point2D.construct(xmin, ymax); - case 2: - return Point2D.construct(xmax, ymax); - case 3: - return Point2D.construct(xmax, ymin); - default: - throw new IndexOutOfBoundsException(); - - } - } + if (other.xmax < xmax) + xmax = other.xmax; + + if (other.ymin > ymin) + ymin = other.ymin; + + if (other.ymax < ymax) + ymax = other.ymax; + + boolean bIntersecting = xmin <= xmax && ymin <= ymax; + + if (!bIntersecting) + setEmpty(); + + return bIntersecting; + } + + /** + * Queries a corner of the envelope. + * + * @param index + * Indicates a corner of the envelope. + *

+ * 0 means lower left or (xmin, ymin) + *

+ * 1 means upper left or (xmin, ymax) + *

+ * 2 means upper right or (xmax, ymax) + *

+ * 3 means lower right or (xmax, ymin) + * @return Point at a corner of the envelope. + * + */ + public Point2D queryCorner(int index) { + switch (index) { + case 0: + return Point2D.construct(xmin, ymin); + case 1: + return Point2D.construct(xmin, ymax); + case 2: + return Point2D.construct(xmax, ymax); + case 3: + return Point2D.construct(xmax, ymin); + default: + throw new IndexOutOfBoundsException(); + + } + } /** * Queries corners into a given array. The array length must be at least @@ -387,21 +391,21 @@ public void queryCorners(Point2D[] corners) { else corners[0] = new Point2D(xmin, ymin); - if (corners[1] != null) - corners[1].setCoords(xmin, ymax); - else - corners[1] = new Point2D(xmin, ymax); + if (corners[1] != null) + corners[1].setCoords(xmin, ymax); + else + corners[1] = new Point2D(xmin, ymax); - if (corners[2] != null) - corners[2].setCoords(xmax, ymax); - else - corners[2] = new Point2D(xmax, ymax); + if (corners[2] != null) + corners[2].setCoords(xmax, ymax); + else + corners[2] = new Point2D(xmax, ymax); - if (corners[3] != null) - corners[3].setCoords(xmax, ymin); - else - corners[3] = new Point2D(xmax, ymin); - } + if (corners[3] != null) + corners[3].setCoords(xmax, ymin); + else + corners[3] = new Point2D(xmax, ymin); + } /** * Queries corners into a given array in reversed order. The array length @@ -417,95 +421,95 @@ public void queryCornersReversed(Point2D[] corners) { else corners[0] = new Point2D(xmin, ymin); - if (corners[1] != null) - corners[1].setCoords(xmax, ymin); - else - corners[1] = new Point2D(xmax, ymin); - - if (corners[2] != null) - corners[2].setCoords(xmax, ymax); - else - corners[2] = new Point2D(xmax, ymax); - - if (corners[3] != null) - corners[3].setCoords(xmin, ymax); - else - corners[3] = new Point2D(xmin, ymax); - } - - public double getArea() { - if (isEmpty()) - return 0; - return getWidth() * getHeight(); - } - - public double getLength() { - if (isEmpty()) - return 0; - return 2.0 * (getWidth() + getHeight()); - } - - public void setFromPoints(Point2D[] points, int count) { - if (count == 0) { - setEmpty(); - return; - } - xmin = points[0].x; - ymin = points[0].y; - xmax = xmin; - ymax = ymin; - for (int i = 1; i < count; i++) { - Point2D pt = points[i]; - if (pt.x < xmin) - xmin = pt.x; - else if (pt.x > xmax) - xmax = pt.x; - if (pt.y < ymin) - ymin = pt.y; - else if (pt.y > ymax) - ymax = pt.y; - } - } - - public void reaspect(double arWidth, double arHeight) { - if (isEmpty()) - return; - double newAspectRatio = arWidth / arHeight; - double widthHalf = getWidth() * 0.5; - double heightHalf = getHeight() * 0.5; - - double newWidthHalf = heightHalf * newAspectRatio; - if (widthHalf <= newWidthHalf) {// preserve height, increase width - double xc = getCenterX(); - xmin = xc - newWidthHalf; - xmax = xc + newWidthHalf; - } else {// preserve the width, increase height - double newHeightHalf = widthHalf / newAspectRatio; - double yc = getCenterY(); - ymin = yc - newHeightHalf; - ymax = yc + newHeightHalf; - } - - normalize(); - } - - public double getCenterX() { - double cx = (xmax + xmin) / 2d; - return cx; - } - - public double getCenterY() { - double cy = (ymax + ymin) / 2d; - return cy; - } - - public double getWidth() { - return xmax - xmin; - } - - public double getHeight() { - return ymax - ymin; - } + if (corners[1] != null) + corners[1].setCoords(xmax, ymin); + else + corners[1] = new Point2D(xmax, ymin); + + if (corners[2] != null) + corners[2].setCoords(xmax, ymax); + else + corners[2] = new Point2D(xmax, ymax); + + if (corners[3] != null) + corners[3].setCoords(xmin, ymax); + else + corners[3] = new Point2D(xmin, ymax); + } + + public double getArea() { + if (isEmpty()) + return 0; + return getWidth() * getHeight(); + } + + public double getLength() { + if (isEmpty()) + return 0; + return 2.0 * (getWidth() + getHeight()); + } + + public void setFromPoints(Point2D[] points, int count) { + if (count == 0) { + setEmpty(); + return; + } + xmin = points[0].x; + ymin = points[0].y; + xmax = xmin; + ymax = ymin; + for (int i = 1; i < count; i++) { + Point2D pt = points[i]; + if (pt.x < xmin) + xmin = pt.x; + else if (pt.x > xmax) + xmax = pt.x; + if (pt.y < ymin) + ymin = pt.y; + else if (pt.y > ymax) + ymax = pt.y; + } + } + + public void reaspect(double arWidth, double arHeight) { + if (isEmpty()) + return; + double newAspectRatio = arWidth / arHeight; + double widthHalf = getWidth() * 0.5; + double heightHalf = getHeight() * 0.5; + + double newWidthHalf = heightHalf * newAspectRatio; + if (widthHalf <= newWidthHalf) {// preserve height, increase width + double xc = getCenterX(); + xmin = xc - newWidthHalf; + xmax = xc + newWidthHalf; + } else {// preserve the width, increase height + double newHeightHalf = widthHalf / newAspectRatio; + double yc = getCenterY(); + ymin = yc - newHeightHalf; + ymax = yc + newHeightHalf; + } + + normalize(); + } + + public double getCenterX() { + double cx = (xmax + xmin) / 2d; + return cx; + } + + public double getCenterY() { + double cy = (ymax + ymin) / 2d; + return cy; + } + + public double getWidth() { + return xmax - xmin; + } + + public double getHeight() { + return ymax - ymin; + } /** * Moves the Envelope by given distance. @@ -521,50 +525,50 @@ public void move(double dx, double dy) { ymax += dy; } - public void centerAt(double x, double y) { - move(x - getCenterX(), y - getCenterY()); - } + public void centerAt(double x, double y) { + move(x - getCenterX(), y - getCenterY()); + } - void centerAt(Point2D pt) { - centerAt(pt.x, pt.y); - } + void centerAt(Point2D pt) { + centerAt(pt.x, pt.y); + } - public void offset(double dx, double dy) { - xmin += dx;// NaN remains NaN - xmax += dx; - ymin += dy; - ymax += dy; - } + public void offset(double dx, double dy) { + xmin += dx;// NaN remains NaN + xmax += dx; + ymin += dy; + ymax += dy; + } - public void normalize() { - if (isEmpty()) - return; + public void normalize() { + if (isEmpty()) + return; - double min = Math.min(xmin, xmax); - double max = Math.max(xmin, xmax); - xmin = min; - xmax = max; - min = Math.min(ymin, ymax); - max = Math.max(ymin, ymax); - ymin = min; - ymax = max; - } + double min = Math.min(xmin, xmax); + double max = Math.max(xmin, xmax); + xmin = min; + xmax = max; + min = Math.min(ymin, ymax); + max = Math.max(ymin, ymax); + ymin = min; + ymax = max; + } - public void queryLowerLeft(Point2D pt) { - pt.setCoords(xmin, ymin); - } + public void queryLowerLeft(Point2D pt) { + pt.setCoords(xmin, ymin); + } - public void queryLowerRight(Point2D pt) { - pt.setCoords(xmax, ymin); - } + public void queryLowerRight(Point2D pt) { + pt.setCoords(xmax, ymin); + } - public void queryUpperLeft(Point2D pt) { - pt.setCoords(xmin, ymax); - } + public void queryUpperLeft(Point2D pt) { + pt.setCoords(xmin, ymax); + } - public void queryUpperRight(Point2D pt) { - pt.setCoords(xmax, ymax); - } + public void queryUpperRight(Point2D pt) { + pt.setCoords(xmax, ymax); + } /** * Returns True if this envelope is valid (empty, or has xmin less or equal @@ -575,60 +579,60 @@ public boolean isValid() { return isEmpty() || (xmin <= xmax && ymin <= ymax); } - /** - * Gets the center point of the envelope. The Center Point occurs at: ((XMin - * + XMax) / 2, (YMin + YMax) / 2). - * - * @return the center point - */ - public Point2D getCenter() { - return new Point2D((xmax + xmin) / 2d, (ymax + ymin) / 2d); - } - - public void queryCenter(Point2D center) { - center.x = (xmax + xmin) / 2d; - center.y = (ymax + ymin) / 2d; - } - - public void centerAt(Point c) { - double cx = (xmax - xmin) / 2d; - double cy = (ymax - ymin) / 2d; - - xmin = c.getX() - cx; - xmax = c.getX() + cx; - ymin = c.getY() - cy; - ymax = c.getY() + cy; - } - - public Point2D getLowerLeft() { - return new Point2D(xmin, ymin); - } - - public Point2D getUpperLeft() { - return new Point2D(xmin, ymax); - } - - public Point2D getLowerRight() { - return new Point2D(xmax, ymin); - } - - public Point2D getUpperRight() { - return new Point2D(xmax, ymax); - } - - public boolean contains(Point p) { - return contains(p.getX(), p.getY()); - } - - public boolean contains(Point2D p) { - return contains(p.x, p.y); - } - - public boolean contains(double x, double y) { - // Note: This will return False, if envelope is empty, thus no need to - // call is_empty(). - return x >= xmin && x <= xmax && y >= ymin && y <= ymax; - } + /** + * Gets the center point of the envelope. The Center Point occurs at: ((XMin + * + XMax) / 2, (YMin + YMax) / 2). + * + * @return the center point + */ + public Point2D getCenter() { + return new Point2D((xmax + xmin) / 2d, (ymax + ymin) / 2d); + } + + public void queryCenter(Point2D center) { + center.x = (xmax + xmin) / 2d; + center.y = (ymax + ymin) / 2d; + } + + public void centerAt(Point c) { + double cx = (xmax - xmin) / 2d; + double cy = (ymax - ymin) / 2d; + + xmin = c.getX() - cx; + xmax = c.getX() + cx; + ymin = c.getY() - cy; + ymax = c.getY() + cy; + } + + public Point2D getLowerLeft() { + return new Point2D(xmin, ymin); + } + + public Point2D getUpperLeft() { + return new Point2D(xmin, ymax); + } + + public Point2D getLowerRight() { + return new Point2D(xmax, ymin); + } + + public Point2D getUpperRight() { + return new Point2D(xmax, ymax); + } + + public boolean contains(Point p) { + return contains(p.getX(), p.getY()); + } + + public boolean contains(Point2D p) { + return contains(p.x, p.y); + } + + public boolean contains(double x, double y) { + // Note: This will return False, if envelope is empty, thus no need to + // call is_empty(). + return x >= xmin && x <= xmax && y >= ymin && y <= ymax; + } /** * Returns True if the envelope contains the other envelope (boundary @@ -654,12 +658,12 @@ public boolean containsExclusive(double x, double y) { return x > xmin && x < xmax && y > ymin && y < ymax; } - /** - * Returns True if the envelope contains the point (boundary exclusive). - */ - public boolean containsExclusive(Point2D pt) { - return containsExclusive(pt.x, pt.y); - } + /** + * Returns True if the envelope contains the point (boundary exclusive). + */ + public boolean containsExclusive(Point2D pt) { + return containsExclusive(pt.x, pt.y); + } /** * Returns True if the envelope contains the other envelope (boundary @@ -674,271 +678,262 @@ boolean containsExclusive(Envelope2D other) { && other.ymax < ymax; } - @Override - public boolean equals(Object _other) { - if (_other == this) - return true; + @Override + public boolean equals(Object _other) { + if (_other == this) + return true; + + if (!(_other instanceof Envelope2D)) + return false; + + Envelope2D other = (Envelope2D) _other; + if (isEmpty() && other.isEmpty()) + return true; + + if (xmin != other.xmin || ymin != other.ymin || xmax != other.xmax + || ymax != other.ymax) + return false; + + return true; + } + + @Override + public int hashCode() { + if (isEmpty()) { + return NumberUtils.hash(NumberUtils.TheNaN); + } + + int hash = NumberUtils.hash(xmin); + hash = NumberUtils.hash(hash, xmax); + hash = NumberUtils.hash(hash, ymin); + hash = NumberUtils.hash(hash, ymax); + + return hash; + } + + Point2D _snapToBoundary(Point2D pt) { + Point2D p = new Point2D(); + p.setCoords(pt); + if (p._isNan()) + return p; + + if (isEmpty()) { + p._setNan(); + return p; + } + + if (p.x < xmin) + p.x = xmin; + else if (p.x > xmax) + p.x = xmax; + + if (p.y < ymin) + p.y = ymin; + else if (p.y > ymax) + p.y = ymax; + + if (!p.equals(pt)) + return p; + + // p is inside envelope + Point2D center = getCenter(); + double deltax = p.x < center.x ? p.x - xmin : xmax - p.x; + double deltay = p.y < center.y ? p.y - ymin : ymax - p.y; + + if (deltax < deltay) + p.x = p.x < center.x ? xmin : xmax; + else + p.y = p.y < center.y ? ymin : ymax; + + return p; + } - if (!(_other instanceof Envelope2D)) - return false; + // Calculates distance of point from lower left corner of envelope, + // moving clockwise along the envelope boundary. + // The input point is assumed to lie exactly on envelope boundary + // If this is not the case then a projection to the nearest position on the + // envelope boundary is performed. + // (If the user knows that the input point does most likely not lie on the + // boundary, + // it is more efficient to perform ProjectToBoundary before using this + // function). + double _boundaryDistance(Point2D pt) { + if (isEmpty()) + return NumberUtils.NaN(); - Envelope2D other = (Envelope2D) _other; - if (isEmpty() && other.isEmpty()) - return true; + if (pt.x == xmin) + return pt.y - ymin; - if (xmin != other.xmin || ymin != other.ymin || xmax != other.xmax - || ymax != other.ymax) - return false; + double height = ymax - ymin; + double width = xmax - xmin; - return true; - } + if (pt.y == ymax) + return height + pt.x - xmin; - @Override - public int hashCode() { + if (pt.x == xmax) + return height + width + ymax - pt.y; - long bits = Double.doubleToLongBits(xmin); - int hc = (int) (bits ^ (bits >>> 32)); + if (pt.y == ymin) + return height * 2.0 + width + xmax - pt.x; - int hash = NumberUtils.hash(hc); + return _boundaryDistance(_snapToBoundary(pt)); + } - bits = Double.doubleToLongBits(xmax); - hc = (int) (bits ^ (bits >>> 32)); - hash = NumberUtils.hash(hash, hc); + // returns 0,..3 depending on which side pt lies. + int _envelopeSide(Point2D pt) { - bits = Double.doubleToLongBits(ymin); - hc = (int) (bits ^ (bits >>> 32)); - hash = NumberUtils.hash(hash, hc); + if (isEmpty()) + return -1; - bits = Double.doubleToLongBits(ymax); - hc = (int) (bits ^ (bits >>> 32)); - hash = NumberUtils.hash(hash, hc); + double boundaryDist = _boundaryDistance(pt); + double height = ymax - ymin; + double width = xmax - xmin; - return hash; - } + if (boundaryDist < height) + return 0; - Point2D _snapToBoundary(Point2D pt) { - Point2D p = new Point2D(); - p.setCoords(pt); - if (p._isNan()) - return p; - - if (isEmpty()) { - p._setNan(); - return p; - } + if ((boundaryDist -= height) < width) + return 1; - if (p.x < xmin) - p.x = xmin; - else if (p.x > xmax) - p.x = xmax; - - if (p.y < ymin) - p.y = ymin; - else if (p.y > ymax) - p.y = ymax; + return boundaryDist - width < height ? 2 : 3; + } - if (!p.equals(pt)) - return p; + double _calculateToleranceFromEnvelope() { + if (isEmpty()) + return NumberUtils.doubleEps() * 100.0; // GEOMTERYX_EPSFACTOR + // 100.0; + double r = Math.abs(xmin) + Math.abs(xmax) + Math.abs(ymin) + + Math.abs(ymax) + 1; + return r * NumberUtils.doubleEps() * 100.0; // GEOMTERYX_EPSFACTOR + // 100.0; + } - // p is inside envelope - Point2D center = getCenter(); - double deltax = p.x < center.x ? p.x - xmin : xmax - p.x; - double deltay = p.y < center.y ? p.y - ymin : ymax - p.y; - - if (deltax < deltay) - p.x = p.x < center.x ? xmin : xmax; - else - p.y = p.y < center.y ? ymin : ymax; - - return p; - } - - // Calculates distance of point from lower left corner of envelope, - // moving clockwise along the envelope boundary. - // The input point is assumed to lie exactly on envelope boundary - // If this is not the case then a projection to the nearest position on the - // envelope boundary is performed. - // (If the user knows that the input point does most likely not lie on the - // boundary, - // it is more efficient to perform ProjectToBoundary before using this - // function). - double _boundaryDistance(Point2D pt) { - if (isEmpty()) - return NumberUtils.NaN(); - - if (pt.x == xmin) - return pt.y - ymin; - - double height = ymax - ymin; - double width = xmax - xmin; - - if (pt.y == ymax) - return height + pt.x - xmin; - - if (pt.x == xmax) - return height + width + ymax - pt.y; - - if (pt.y == ymin) - return height * 2.0 + width + xmax - pt.x; - - return _boundaryDistance(_snapToBoundary(pt)); - } - - // returns 0,..3 depending on which side pt lies. - int _envelopeSide(Point2D pt) { - - if (isEmpty()) - return -1; - - double boundaryDist = _boundaryDistance(pt); - double height = ymax - ymin; - double width = xmax - xmin; - - if (boundaryDist < height) - return 0; - - if ((boundaryDist -= height) < width) - return 1; - - return boundaryDist - width < height ? 2 : 3; - } - - double _calculateToleranceFromEnvelope() { - if (isEmpty()) - return NumberUtils.doubleEps() * 100.0; // GEOMTERYX_EPSFACTOR - // 100.0; - double r = Math.abs(xmin) + Math.abs(xmax) + Math.abs(ymin) - + Math.abs(ymax) + 1; - return r * NumberUtils.doubleEps() * 100.0; // GEOMTERYX_EPSFACTOR - // 100.0; - } - - public int clipLine(Point2D p1, Point2D p2) - // Modified Cohen-Sutherland Line-Clipping Algorithm - // returns: - // 0 - the segment is outside of the clipping window - // 1 - p1 was modified - // 2 - p2 was modified - // 3 - p1 and p2 were modified - // 4 - the segment is complitely inside of the clipping window - { - int c1 = _clipCode(p1), c2 = _clipCode(p2); - - if ((c1 & c2) != 0)// (c1 & c2) - return 0; - - if ((c1 | c2) == 0)// (!(c1 | c2)) - return 4; - - final int res = ((c1 != 0) ? 1 : 0) | ((c2 != 0) ? 2 : 0);// (c1 ? 1 : - // 0) | (c2 - // ? 2 : 0); - - do { - double dx = p2.x - p1.x, dy = p2.y - p1.y; - - boolean bDX = dx > dy; - - if (bDX) { - if ((c1 & XMASK) != 0)// (c1 & XMASK) - { - if ((c1 & XLESSXMIN) != 0)// (c1 & XLESSXMIN) - { - p1.y += dy * (xmin - p1.x) / dx; - p1.x = xmin; - } else { - p1.y += dy * (xmax - p1.x) / dx; - p1.x = xmax; - } - - c1 = _clipCode(p1); - } else if ((c2 & XMASK) != 0)// (c2 & XMASK) - { - if ((c2 & XLESSXMIN) != 0) { - p2.y += dy * (xmin - p2.x) / dx; - p2.x = xmin; - } else { - p2.y += dy * (xmax - p2.x) / dx; - p2.x = xmax; - } - - c2 = _clipCode(p2); - } else if (c1 != 0)// (c1) - { - if ((c1 & YLESSYMIN) != 0)// (c1 & YLESSYMIN) - { - p1.x += dx * (ymin - p1.y) / dy; - p1.y = ymin; - } else { - p1.x += dx * (ymax - p1.y) / dy; - p1.y = ymax; - } - - c1 = _clipCode(p1); - } else { - if ((c2 & YLESSYMIN) != 0)// (c2 & YLESSYMIN) - { - p2.x += dx * (ymin - p2.y) / dy; - p2.y = ymin; - } else { - p2.x += dx * (ymax - p2.y) / dy; - p2.y = ymax; - } - - c2 = _clipCode(p2); - } - } else { - if ((c1 & YMASK) != 0)// (c1 & YMASK) - { - if ((c1 & YLESSYMIN) != 0)// (c1 & YLESSYMIN) - { - p1.x += dx * (ymin - p1.y) / dy; - p1.y = ymin; - } else { - p1.x += dx * (ymax - p1.y) / dy; - p1.y = ymax; - } - - c1 = _clipCode(p1); - } else if ((c2 & YMASK) != 0)// (c2 & YMASK) - { - if ((c2 & YLESSYMIN) != 0) // (c2 & YLESSYMIN) - { - p2.x += dx * (ymin - p2.y) / dy; - p2.y = ymin; - } else { - p2.x += dx * (ymax - p2.y) / dy; - p2.y = ymax; - } - - c2 = _clipCode(p2); - } else if (c1 != 0)// (c1) - { - if ((c1 & XLESSXMIN) != 0)// (c1 & XLESSXMIN) - { - p1.y += dy * (xmin - p1.x) / dx; - p1.x = xmin; - } else { - p1.y += dy * (xmax - p1.x) / dx; - p1.x = xmax; - } - - c1 = _clipCode(p1); - } else { - if ((c2 & XLESSXMIN) != 0)// (c2 & XLESSXMIN) - { - p2.y += dy * (xmin - p2.x) / dx; - p2.x = xmin; - } else { - p2.y += dy * (xmax - p2.x) / dx; - p2.x = xmax; - } - - c2 = _clipCode(p2); - } + public int clipLine(Point2D p1, Point2D p2) + // Modified Cohen-Sutherland Line-Clipping Algorithm + // returns: + // 0 - the segment is outside of the clipping window + // 1 - p1 was modified + // 2 - p2 was modified + // 3 - p1 and p2 were modified + // 4 - the segment is complitely inside of the clipping window + { + int c1 = _clipCode(p1), c2 = _clipCode(p2); + + if ((c1 & c2) != 0)// (c1 & c2) + return 0; + + if ((c1 | c2) == 0)// (!(c1 | c2)) + return 4; + + final int res = ((c1 != 0) ? 1 : 0) | ((c2 != 0) ? 2 : 0);// (c1 ? 1 : + // 0) | (c2 + // ? 2 : 0); + + do { + double dx = p2.x - p1.x, dy = p2.y - p1.y; + + boolean bDX = dx > dy; + + if (bDX) { + if ((c1 & XMASK) != 0)// (c1 & XMASK) + { + if ((c1 & XLESSXMIN) != 0)// (c1 & XLESSXMIN) + { + p1.y += dy * (xmin - p1.x) / dx; + p1.x = xmin; + } else { + p1.y += dy * (xmax - p1.x) / dx; + p1.x = xmax; + } + + c1 = _clipCode(p1); + } else if ((c2 & XMASK) != 0)// (c2 & XMASK) + { + if ((c2 & XLESSXMIN) != 0) { + p2.y += dy * (xmin - p2.x) / dx; + p2.x = xmin; + } else { + p2.y += dy * (xmax - p2.x) / dx; + p2.x = xmax; + } + + c2 = _clipCode(p2); + } else if (c1 != 0)// (c1) + { + if ((c1 & YLESSYMIN) != 0)// (c1 & YLESSYMIN) + { + p1.x += dx * (ymin - p1.y) / dy; + p1.y = ymin; + } else { + p1.x += dx * (ymax - p1.y) / dy; + p1.y = ymax; + } + + c1 = _clipCode(p1); + } else { + if ((c2 & YLESSYMIN) != 0)// (c2 & YLESSYMIN) + { + p2.x += dx * (ymin - p2.y) / dy; + p2.y = ymin; + } else { + p2.x += dx * (ymax - p2.y) / dy; + p2.y = ymax; + } + + c2 = _clipCode(p2); + } + } else { + if ((c1 & YMASK) != 0)// (c1 & YMASK) + { + if ((c1 & YLESSYMIN) != 0)// (c1 & YLESSYMIN) + { + p1.x += dx * (ymin - p1.y) / dy; + p1.y = ymin; + } else { + p1.x += dx * (ymax - p1.y) / dy; + p1.y = ymax; + } + + c1 = _clipCode(p1); + } else if ((c2 & YMASK) != 0)// (c2 & YMASK) + { + if ((c2 & YLESSYMIN) != 0) // (c2 & YLESSYMIN) + { + p2.x += dx * (ymin - p2.y) / dy; + p2.y = ymin; + } else { + p2.x += dx * (ymax - p2.y) / dy; + p2.y = ymax; + } + + c2 = _clipCode(p2); + } else if (c1 != 0)// (c1) + { + if ((c1 & XLESSXMIN) != 0)// (c1 & XLESSXMIN) + { + p1.y += dy * (xmin - p1.x) / dx; + p1.x = xmin; + } else { + p1.y += dy * (xmax - p1.x) / dx; + p1.x = xmax; + } + + c1 = _clipCode(p1); + } else { + if ((c2 & XLESSXMIN) != 0)// (c2 & XLESSXMIN) + { + p2.y += dy * (xmin - p2.x) / dx; + p2.x = xmin; + } else { + p2.y += dy * (xmax - p2.x) / dx; + p2.x = xmax; + } + + c2 = _clipCode(p2); + } /* - * if (c1) //original code. Faster, but less robust numerically. + * if (c1) //original code. Faster, but less robust numerically. * ( //The Cohen-Sutherland Line-Clipping Algorithm) { if (c1 & * XLESSXMIN) { p1.y += dy * (xmin - p1.x) / dx; p1.x = xmin; } * else if (c1 & XGREATERXMAX) { p1.y += dy * (xmax - p1.x) / @@ -956,140 +951,140 @@ public int clipLine(Point2D p1, Point2D p2) * * c2 = _clipCode(p2, ClipRect); } */ - } - - if ((c1 & c2) != 0)// (c1 & c2) - return 0; - - } while ((c1 | c2) != 0);// (c1 | c2); - - return res; - } - - int _clipCode(Point2D p)// returns a code from the Cohen-Sutherland (0000 is - // boundary inclusive) - { - int left = (p.x < xmin) ? 1 : 0; - int right = (p.x > xmax) ? 1 : 0; - int bottom = (p.y < ymin) ? 1 : 0; - int top = (p.y > ymax) ? 1 : 0; - return left | right << 1 | bottom << 2 | top << 3; - } - - // Clips and optionally extends line within envelope; modifies point 'from', - // 'to'. - // Algorithm: Liang-Barsky parametric line-clipping (Foley, vanDam, Feiner, - // Hughes, second edition, 117-124) - // lineExtension: 0 no line eExtension, 1 extend line at from point, 2 - // extend line at endpoint, 3 extend line at both ends - // boundaryDistances can be NULLPTR. - // returns: - // 0 - the segment is outside of the clipping window - // 1 - p1 was modified - // 2 - p2 was modified - // 3 - p1 and p2 were modified - // 4 - the segment is complitely inside of the clipping window - int clipLine(Point2D p0, Point2D p1, int lineExtension, double[] segParams, - double[] boundaryDistances) { - if (boundaryDistances != null) { - boundaryDistances[0] = -1.0; - boundaryDistances[1] = -1.0; - } - - double[] tOld = new double[2];// LOCALREFCLASS1(ArrayOf(double), int, - // tOld, 2); - int modified = 0; - - Point2D delta = new Point2D(p1.x - p0.x, p1.y - p0.y); - - if (delta.x == 0.0 && delta.y == 0.0) // input line degenerates to a - // point - { - segParams[0] = 0.0; - segParams[1] = 0.0; - return contains(p0) ? 4 : 0; - } - - segParams[0] = ((lineExtension & 1) != 0) ? NumberUtils.negativeInf() - : 0.0; - segParams[1] = ((lineExtension & 2) != 0) ? NumberUtils.positiveInf() - : 1.0; - tOld[0] = segParams[0]; - tOld[1] = segParams[1]; - - if (clipLineAuxiliary(delta.x, xmin - p0.x, segParams) - && clipLineAuxiliary(-delta.x, p0.x - xmax, segParams) - && clipLineAuxiliary(delta.y, ymin - p0.y, segParams) - && clipLineAuxiliary(-delta.y, p0.y - ymax, segParams)) { - if (segParams[1] < tOld[1]) { - p1.scaleAdd(segParams[1], delta, p0); - _snapToBoundary(p1); // needed for accuracy - modified |= 2; - - if (boundaryDistances != null) - boundaryDistances[1] = _boundaryDistance(p1); - } - if (segParams[0] > tOld[0]) { - p0.scaleAdd(segParams[0], delta, p0); - _snapToBoundary(p0); // needed for accuracy - modified |= 1; - - if (boundaryDistances != null) - boundaryDistances[0] = _boundaryDistance(p0); - } - } - - return modified; - } - - boolean clipLineAuxiliary(double denominator, double numerator, - double[] segParams) { - double t = numerator / denominator; - if (denominator > 0.0) { - if (t > segParams[1]) - return false; - - if (t > segParams[0]) { - segParams[0] = t; - return true; - } - } else if (denominator < 0.0) { - if (t < segParams[0]) - return false; - - if (t < segParams[1]) { - segParams[1] = t; - return true; - } - } else - return numerator <= 0.0; - - return true; - } - - /** - * Returns True, envelope is degenerate (Width or Height are less than - * tolerance). Note: this returns False for Empty envelope. - */ - public boolean isDegenerate(double tolerance) { - return !isEmpty() - && (getWidth() <= tolerance || getHeight() <= tolerance); - } - - Point2D _snapClip(Point2D pt)// clips the point if it is outside, then snaps - // it to the boundary. - { - double x = NumberUtils.snap(pt.x, xmin, xmax); - double y = NumberUtils.snap(pt.y, ymin, ymax); - return new Point2D(x, y); - } - - public boolean isPointOnBoundary(Point2D pt, double tolerance) { - return Math.abs(pt.x - xmin) <= tolerance - || Math.abs(pt.x - xmax) <= tolerance - || Math.abs(pt.y - ymin) <= tolerance - || Math.abs(pt.y - ymax) <= tolerance; - } + } + + if ((c1 & c2) != 0)// (c1 & c2) + return 0; + + } while ((c1 | c2) != 0);// (c1 | c2); + + return res; + } + + int _clipCode(Point2D p)// returns a code from the Cohen-Sutherland (0000 is + // boundary inclusive) + { + int left = (p.x < xmin) ? 1 : 0; + int right = (p.x > xmax) ? 1 : 0; + int bottom = (p.y < ymin) ? 1 : 0; + int top = (p.y > ymax) ? 1 : 0; + return left | right << 1 | bottom << 2 | top << 3; + } + + // Clips and optionally extends line within envelope; modifies point 'from', + // 'to'. + // Algorithm: Liang-Barsky parametric line-clipping (Foley, vanDam, Feiner, + // Hughes, second edition, 117-124) + // lineExtension: 0 no line eExtension, 1 extend line at from point, 2 + // extend line at endpoint, 3 extend line at both ends + // boundaryDistances can be NULLPTR. + // returns: + // 0 - the segment is outside of the clipping window + // 1 - p1 was modified + // 2 - p2 was modified + // 3 - p1 and p2 were modified + // 4 - the segment is complitely inside of the clipping window + int clipLine(Point2D p0, Point2D p1, int lineExtension, double[] segParams, + double[] boundaryDistances) { + if (boundaryDistances != null) { + boundaryDistances[0] = -1.0; + boundaryDistances[1] = -1.0; + } + + double[] tOld = new double[2];// LOCALREFCLASS1(ArrayOf(double), int, + // tOld, 2); + int modified = 0; + + Point2D delta = new Point2D(p1.x - p0.x, p1.y - p0.y); + + if (delta.x == 0.0 && delta.y == 0.0) // input line degenerates to a + // point + { + segParams[0] = 0.0; + segParams[1] = 0.0; + return contains(p0) ? 4 : 0; + } + + segParams[0] = ((lineExtension & 1) != 0) ? NumberUtils.negativeInf() + : 0.0; + segParams[1] = ((lineExtension & 2) != 0) ? NumberUtils.positiveInf() + : 1.0; + tOld[0] = segParams[0]; + tOld[1] = segParams[1]; + + if (clipLineAuxiliary(delta.x, xmin - p0.x, segParams) + && clipLineAuxiliary(-delta.x, p0.x - xmax, segParams) + && clipLineAuxiliary(delta.y, ymin - p0.y, segParams) + && clipLineAuxiliary(-delta.y, p0.y - ymax, segParams)) { + if (segParams[1] < tOld[1]) { + p1.scaleAdd(segParams[1], delta, p0); + _snapToBoundary(p1); // needed for accuracy + modified |= 2; + + if (boundaryDistances != null) + boundaryDistances[1] = _boundaryDistance(p1); + } + if (segParams[0] > tOld[0]) { + p0.scaleAdd(segParams[0], delta, p0); + _snapToBoundary(p0); // needed for accuracy + modified |= 1; + + if (boundaryDistances != null) + boundaryDistances[0] = _boundaryDistance(p0); + } + } + + return modified; + } + + boolean clipLineAuxiliary(double denominator, double numerator, + double[] segParams) { + double t = numerator / denominator; + if (denominator > 0.0) { + if (t > segParams[1]) + return false; + + if (t > segParams[0]) { + segParams[0] = t; + return true; + } + } else if (denominator < 0.0) { + if (t < segParams[0]) + return false; + + if (t < segParams[1]) { + segParams[1] = t; + return true; + } + } else + return numerator <= 0.0; + + return true; + } + + /** + * Returns True, envelope is degenerate (Width or Height are less than + * tolerance). Note: this returns False for Empty envelope. + */ + public boolean isDegenerate(double tolerance) { + return !isEmpty() + && (getWidth() <= tolerance || getHeight() <= tolerance); + } + + Point2D _snapClip(Point2D pt)// clips the point if it is outside, then snaps + // it to the boundary. + { + double x = NumberUtils.snap(pt.x, xmin, xmax); + double y = NumberUtils.snap(pt.y, ymin, ymax); + return new Point2D(x, y); + } + + public boolean isPointOnBoundary(Point2D pt, double tolerance) { + return Math.abs(pt.x - xmin) <= tolerance + || Math.abs(pt.x - xmax) <= tolerance + || Math.abs(pt.y - ymin) <= tolerance + || Math.abs(pt.y - ymax) <= tolerance; + } /** * Calculates minimum distance from this envelope to the other. @@ -1125,24 +1120,24 @@ public double sqrDistance(Envelope2D other) double dy = 0; double nn; - nn = xmin - other.xmax; - if (nn > dx) - dx = nn; + nn = xmin - other.xmax; + if (nn > dx) + dx = nn; - nn = ymin - other.ymax; - if (nn > dy) - dy = nn; + nn = ymin - other.ymax; + if (nn > dy) + dy = nn; - nn = other.xmin - xmax; - if (nn > dx) - dx = nn; + nn = other.xmin - xmax; + if (nn > dx) + dx = nn; - nn = other.ymin - ymax; - if (nn > dy) - dy = nn; + nn = other.ymin - ymax; + if (nn > dy) + dy = nn; - return dx * dx + dy * dy; - } + return dx * dx + dy * dy; + } /** * Calculates minimum squared distance from this envelope to the other. @@ -1159,48 +1154,48 @@ public double sqrDistance(double xmin_, double ymin_, double xmax_, double ymax_ double dy = 0; double nn; - nn = xmin - xmax_; - if (nn > dx) - dx = nn; - - nn = ymin - ymax_; - if (nn > dy) - dy = nn; - - nn = xmin_ - xmax; - if (nn > dx) - dx = nn; - - nn = ymin_ - ymax; - if (nn > dy) - dy = nn; - - return dx * dx + dy * dy; - } - - /** - * Returns squared max distance between two bounding boxes. This is furthest distance between points on the two envelopes. - * - * @param other The bounding box to calculate the max distance two. - * @return Squared distance value. - */ - public double sqrMaxDistance(Envelope2D other) { - if (isEmpty() || other.isEmpty()) - return NumberUtils.TheNaN; - - double dist = 0; - Point2D[] points = new Point2D[4]; - queryCorners(points); - Point2D[] points_o = new Point2D[4]; - other.queryCorners(points_o); - for (int i = 0; i < 4; i++) { - for (int j = 0; j < 4; j++) { - double d = Point2D.sqrDistance(points[i], points_o[j]); - if (d > dist) { - dist = d; - } - } - } + nn = xmin - xmax_; + if (nn > dx) + dx = nn; + + nn = ymin - ymax_; + if (nn > dy) + dy = nn; + + nn = xmin_ - xmax; + if (nn > dx) + dx = nn; + + nn = ymin_ - ymax; + if (nn > dy) + dy = nn; + + return dx * dx + dy * dy; + } + + /** + *Returns squared max distance between two bounding boxes. This is furthest distance between points on the two envelopes. + * + *@param other The bounding box to calculate the max distance two. + *@return Squared distance value. + */ + public double sqrMaxDistance(Envelope2D other) { + if (isEmpty() || other.isEmpty()) + return NumberUtils.TheNaN; + + double dist = 0; + Point2D[] points = new Point2D[4]; + queryCorners(points); + Point2D[] points_o = new Point2D[4]; + other.queryCorners(points_o); + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) { + double d = Point2D.sqrDistance(points[i], points_o[j]); + if (d > dist) { + dist = d; + } + } + } return dist; } @@ -1217,51 +1212,51 @@ public double sqrDistance(Point2D pt2D) double dy = 0; double nn; - nn = xmin - pt2D.x; - if (nn > dx) - dx = nn; - - nn = ymin - pt2D.y; - if (nn > dy) - dy = nn; - - nn = pt2D.x - xmax; - if (nn > dx) - dx = nn; - - nn = pt2D.y - ymax; - if (nn > dy) - dy = nn; - - return dx * dx + dy * dy; - } - - public void queryIntervalX(Envelope1D env1D) { - if (isEmpty()) { - env1D.setEmpty(); - } else { - env1D.setCoords(xmin, xmax); - } - } - - public void queryIntervalY(Envelope1D env1D) { - if (isEmpty()) { - env1D.setEmpty(); - } else { - env1D.setCoords(ymin, ymax); - } - } - - private void writeObject(java.io.ObjectOutputStream out) throws IOException { - out.defaultWriteObject(); - } - - private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException { - in.defaultReadObject(); - } - - private void readObjectNoData() throws ObjectStreamException { - setEmpty(); - } + nn = xmin - pt2D.x; + if (nn > dx) + dx = nn; + + nn = ymin - pt2D.y; + if (nn > dy) + dy = nn; + + nn = pt2D.x - xmax; + if (nn > dx) + dx = nn; + + nn = pt2D.y - ymax; + if (nn > dy) + dy = nn; + + return dx * dx + dy * dy; + } + + public void queryIntervalX(Envelope1D env1D) + { + if (isEmpty()) { + env1D.setEmpty(); + } else { + env1D.setCoords(xmin, xmax); + } + } + + public void queryIntervalY(Envelope1D env1D) + { + if (isEmpty()) { + env1D.setEmpty(); + } else { + env1D.setCoords(ymin, ymax); + } + } + + private void writeObject(java.io.ObjectOutputStream out) throws IOException { + out.defaultWriteObject(); + } + private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException { + in.defaultReadObject(); + } + private void readObjectNoData() throws ObjectStreamException { + setEmpty(); + } } diff --git a/src/main/java/com/esri/core/geometry/Envelope2DIntersectorImpl.java b/src/main/java/com/esri/core/geometry/Envelope2DIntersectorImpl.java index 2974be49..2941fcb6 100644 --- a/src/main/java/com/esri/core/geometry/Envelope2DIntersectorImpl.java +++ b/src/main/java/com/esri/core/geometry/Envelope2DIntersectorImpl.java @@ -26,898 +26,898 @@ import java.util.ArrayList; class Envelope2DIntersectorImpl { - /* - * Constructor for Envelope_2D_intersector. - */ - Envelope2DIntersectorImpl() { - m_function = -1; - m_tolerance = 0.0; - reset_(); - } - - void startConstruction() { - reset_(); - m_b_add_red_red = true; - - if (m_envelopes_red == null) { - m_elements_red = new AttributeStreamOfInt32(0); - m_envelopes_red = new ArrayList(0); - } else { - m_elements_red.resizePreserveCapacity(0); - m_envelopes_red.clear(); - } - } - - void addEnvelope(int element, Envelope2D envelope) { - if (!m_b_add_red_red) - throw new GeometryException("invalid call"); - - Envelope2D e = new Envelope2D(); - e.setCoords(envelope); - m_elements_red.add(element); - m_envelopes_red.add(e); - } - - void endConstruction() { - if (!m_b_add_red_red) - throw new GeometryException("invalid call"); - - m_b_add_red_red = false; - - if (m_envelopes_red != null && m_envelopes_red.size() > 0) { - m_function = State.initialize; - m_b_done = false; - } - } - - void startRedConstruction() { - reset_(); - m_b_add_red = true; - - if (m_envelopes_red == null) { - m_elements_red = new AttributeStreamOfInt32(0); - m_envelopes_red = new ArrayList(0); - } else { - m_elements_red.resizePreserveCapacity(0); - m_envelopes_red.clear(); - } - } - - void addRedEnvelope(int element, Envelope2D red_envelope) { - if (!m_b_add_red) - throw new GeometryException("invalid call"); - - Envelope2D e = new Envelope2D(); - e.setCoords(red_envelope); - m_elements_red.add(element); - m_envelopes_red.add(e); - } - - void endRedConstruction() { - if (!m_b_add_red) - throw new GeometryException("invalid call"); - - m_b_add_red = false; - - if (m_envelopes_red != null && m_envelopes_red.size() > 0 && m_envelopes_blue != null && m_envelopes_blue.size() > 0) { - if (m_function == -1) - m_function = State.initializeRedBlue; - else if (m_function == State.initializeBlue) - m_function = State.initializeRedBlue; - else if (m_function != State.initializeRedBlue) - m_function = State.initializeRed; - - m_b_done = false; - } - } - - void startBlueConstruction() { - reset_(); - m_b_add_blue = true; - - if (m_envelopes_blue == null) { - m_elements_blue = new AttributeStreamOfInt32(0); - m_envelopes_blue = new ArrayList(0); - } else { - m_elements_blue.resizePreserveCapacity(0); - m_envelopes_blue.clear(); - } - } - - void addBlueEnvelope(int element, Envelope2D blue_envelope) { - if (!m_b_add_blue) - throw new GeometryException("invalid call"); - - Envelope2D e = new Envelope2D(); - e.setCoords(blue_envelope); - m_elements_blue.add(element); - m_envelopes_blue.add(e); - } - - void endBlueConstruction() { - if (!m_b_add_blue) - throw new GeometryException("invalid call"); - - m_b_add_blue = false; - - if (m_envelopes_red != null && m_envelopes_red.size() > 0 && m_envelopes_blue != null && m_envelopes_blue.size() > 0) { - if (m_function == -1) - m_function = State.initializeRedBlue; - else if (m_function == State.initializeRed) - m_function = State.initializeRedBlue; - else if (m_function != State.initializeRedBlue) - m_function = State.initializeBlue; - - m_b_done = false; - } - } - - /* - * Moves the iterator to the next intersecting pair of envelopes.Returns - * true if an intersecting pair is found. You can call get_handle_a() and - * get_handle_b() to get the index of each envelope in the current - * intersection. Otherwise if false is returned, then are no more - * intersections (if at all). - */ - boolean next() { - if (m_b_done) - return false; - - boolean b_searching = true; - while (b_searching) { - switch (m_function) { - case State.initialize: - b_searching = initialize_(); - break; - case State.initializeRed: - b_searching = initializeRed_(); - break; - case State.initializeBlue: - b_searching = initializeBlue_(); - break; - case State.initializeRedBlue: - b_searching = initializeRedBlue_(); - break; - case State.sweep: - b_searching = sweep_(); - break; - case State.sweepBruteForce: - b_searching = sweepBruteForce_(); - break; - case State.sweepRedBlueBruteForce: - b_searching = sweepRedBlueBruteForce_(); - break; - case State.sweepRedBlue: - b_searching = sweepRedBlue_(); - break; - case State.sweepRed: - b_searching = sweepRed_(); - break; - case State.sweepBlue: - b_searching = sweepBlue_(); - break; - case State.iterate: - b_searching = iterate_(); - break; - case State.iterateRed: - b_searching = iterateRed_(); - break; - case State.iterateBlue: - b_searching = iterateBlue_(); - break; - case State.iterateBruteForce: - b_searching = iterateBruteForce_(); - break; - case State.iterateRedBlueBruteForce: - b_searching = iterateRedBlueBruteForce_(); - break; - case State.resetRed: - b_searching = resetRed_(); - break; - case State.resetBlue: - b_searching = resetBlue_(); - break; - default: - throw GeometryException.GeometryInternalError(); - } - } - - if (m_b_done) - return false; - - return true; - } - - /* - * Returns the index of the first envelope in the intersection. In the - * red/blue case, this will be an index to the red envelopes. - */ - int getHandleA() { - return m_envelope_handle_a; - } - - /* - * Returns the index of the second envelope in the intersection. In the - * red/blue case, this will be an index to the blue envelopes. - */ - int getHandleB() { - return m_envelope_handle_b; - } - - /* - * Sets the tolerance used for the intersection tests.\param tolerance The - * tolerance used to determine intersection. - */ - void setTolerance(double tolerance) { - m_tolerance = tolerance; - } - - /* - * Returns a reference to the envelope at the given handle. Use this for the red/red intersection case. - */ - Envelope2D getEnvelope(int handle) { - return m_envelopes_red.get(handle); - } - - /* - * Returns the user element associated with handle. Use this for the red/red intersection case. - */ - int getElement(int handle) { - return m_elements_red.read(handle); - } - - /* - * Returns a reference to the red envelope at handle_a. - */ - Envelope2D getRedEnvelope(int handle_a) { - return m_envelopes_red.get(handle_a); - } - - /* - * Returns a reference to the blue envelope at handle_b. - */ - Envelope2D getBlueEnvelope(int handle_b) { - return m_envelopes_blue.get(handle_b); - } - - /* - * Returns the user element associated with handle_a. - */ - int getRedElement(int handle_a) { - return m_elements_red.read(handle_a); - } - - /* - * Returns the user element associated with handle_b. - */ - int getBlueElement(int handle_b) { - return m_elements_blue.read(handle_b); - } - - private double m_tolerance; - private int m_sweep_index_red; - private int m_sweep_index_blue; - private int m_envelope_handle_a; - private int m_envelope_handle_b; - private IntervalTreeImpl m_interval_tree_red; - private IntervalTreeImpl m_interval_tree_blue; - private IntervalTreeImpl.IntervalTreeIteratorImpl m_iterator_red; - private IntervalTreeImpl.IntervalTreeIteratorImpl m_iterator_blue; - private Envelope2D m_envelope_helper = new Envelope2D(); - - private ArrayList m_envelopes_red; - private ArrayList m_envelopes_blue; - private AttributeStreamOfInt32 m_elements_red; - private AttributeStreamOfInt32 m_elements_blue; - - private AttributeStreamOfInt32 m_sorted_end_indices_red; - private AttributeStreamOfInt32 m_sorted_end_indices_blue; - - private int m_queued_list_red; - private int m_queued_list_blue; - private IndexMultiDCList m_queued_envelopes; - private AttributeStreamOfInt32 m_queued_indices_red; - private AttributeStreamOfInt32 m_queued_indices_blue; - private boolean m_b_add_red; - private boolean m_b_add_blue; - private boolean m_b_add_red_red; - private boolean m_b_done; - - private static boolean isTop_(int y_end_point_handle) { - return (y_end_point_handle & 0x1) == 1; - } - - private static boolean isBottom_(int y_end_point_handle) { - return (y_end_point_handle & 0x1) == 0; - } - - private void reset_() { - m_b_add_red = false; - m_b_add_blue = false; - m_b_add_red_red = false; - m_sweep_index_red = -1; - m_sweep_index_blue = -1; - m_queued_list_red = -1; - m_queued_list_blue = -1; - m_b_done = true; - } - - private boolean initialize_() { - m_envelope_handle_a = -1; - m_envelope_handle_b = -1; - - if (m_envelopes_red.size() < 10) { - m_sweep_index_red = m_envelopes_red.size(); - m_function = State.sweepBruteForce; - return true; - } - - if (m_interval_tree_red == null) { - m_interval_tree_red = new IntervalTreeImpl(true); - m_sorted_end_indices_red = new AttributeStreamOfInt32(0); - } - - m_interval_tree_red.addEnvelopesRef(m_envelopes_red); - - if (m_iterator_red == null) { - m_iterator_red = m_interval_tree_red.getIterator(); - } - - m_sorted_end_indices_red.reserve(2 * m_envelopes_red.size()); - m_sorted_end_indices_red.resize(0); - - for (int i = 0; i < 2 * m_envelopes_red.size(); i++) - m_sorted_end_indices_red.add(i); - - sortYEndIndices_(m_sorted_end_indices_red, 0, 2 * m_envelopes_red.size(), true); - - m_sweep_index_red = 2 * m_envelopes_red.size(); - - m_function = State.sweep; // overwrite initialize_ - - return true; - } - - private boolean initializeRed_() { - m_envelope_handle_a = -1; - m_envelope_handle_b = -1; - - if (m_envelopes_red.size() < 10 || m_envelopes_blue.size() < 10) { - m_sweep_index_red = m_envelopes_red.size(); - m_function = State.sweepRedBlueBruteForce; - return true; - } - - if (m_interval_tree_red == null) { - m_interval_tree_red = new IntervalTreeImpl(true); - m_sorted_end_indices_red = new AttributeStreamOfInt32(0); - } - - m_interval_tree_red.addEnvelopesRef(m_envelopes_red); - - if (m_iterator_red == null) { - m_iterator_red = m_interval_tree_red.getIterator(); - } - - m_sorted_end_indices_red.reserve(2 * m_envelopes_red.size()); - m_sorted_end_indices_red.resize(0); + /* + * Constructor for Envelope_2D_intersector. + */ + Envelope2DIntersectorImpl() { + m_function = -1; + m_tolerance = 0.0; + reset_(); + } + + void startConstruction() { + reset_(); + m_b_add_red_red = true; + + if (m_envelopes_red == null) { + m_elements_red = new AttributeStreamOfInt32(0); + m_envelopes_red = new ArrayList(0); + } else { + m_elements_red.resizePreserveCapacity(0); + m_envelopes_red.clear(); + } + } + + void addEnvelope(int element, Envelope2D envelope) { + if (!m_b_add_red_red) + throw new GeometryException("invalid call"); + + Envelope2D e = new Envelope2D(); + e.setCoords(envelope); + m_elements_red.add(element); + m_envelopes_red.add(e); + } + + void endConstruction() { + if (!m_b_add_red_red) + throw new GeometryException("invalid call"); + + m_b_add_red_red = false; + + if (m_envelopes_red != null && m_envelopes_red.size() > 0) { + m_function = State.initialize; + m_b_done = false; + } + } + + void startRedConstruction() { + reset_(); + m_b_add_red = true; + + if (m_envelopes_red == null) { + m_elements_red = new AttributeStreamOfInt32(0); + m_envelopes_red = new ArrayList(0); + } else { + m_elements_red.resizePreserveCapacity(0); + m_envelopes_red.clear(); + } + } + + void addRedEnvelope(int element, Envelope2D red_envelope) { + if (!m_b_add_red) + throw new GeometryException("invalid call"); + + Envelope2D e = new Envelope2D(); + e.setCoords(red_envelope); + m_elements_red.add(element); + m_envelopes_red.add(e); + } + + void endRedConstruction() { + if (!m_b_add_red) + throw new GeometryException("invalid call"); + + m_b_add_red = false; + + if (m_envelopes_red != null && m_envelopes_red.size() > 0 && m_envelopes_blue != null && m_envelopes_blue.size() > 0) { + if (m_function == -1) + m_function = State.initializeRedBlue; + else if (m_function == State.initializeBlue) + m_function = State.initializeRedBlue; + else if (m_function != State.initializeRedBlue) + m_function = State.initializeRed; + + m_b_done = false; + } + } + + void startBlueConstruction() { + reset_(); + m_b_add_blue = true; + + if (m_envelopes_blue == null) { + m_elements_blue = new AttributeStreamOfInt32(0); + m_envelopes_blue = new ArrayList(0); + } else { + m_elements_blue.resizePreserveCapacity(0); + m_envelopes_blue.clear(); + } + } + + void addBlueEnvelope(int element, Envelope2D blue_envelope) { + if (!m_b_add_blue) + throw new GeometryException("invalid call"); + + Envelope2D e = new Envelope2D(); + e.setCoords(blue_envelope); + m_elements_blue.add(element); + m_envelopes_blue.add(e); + } + + void endBlueConstruction() { + if (!m_b_add_blue) + throw new GeometryException("invalid call"); + + m_b_add_blue = false; + + if (m_envelopes_red != null && m_envelopes_red.size() > 0 && m_envelopes_blue != null && m_envelopes_blue.size() > 0) { + if (m_function == -1) + m_function = State.initializeRedBlue; + else if (m_function == State.initializeRed) + m_function = State.initializeRedBlue; + else if (m_function != State.initializeRedBlue) + m_function = State.initializeBlue; + + m_b_done = false; + } + } + + /* + * Moves the iterator to the next intersecting pair of envelopes.Returns + * true if an intersecting pair is found. You can call get_handle_a() and + * get_handle_b() to get the index of each envelope in the current + * intersection. Otherwise if false is returned, then are no more + * intersections (if at all). + */ + boolean next() { + if (m_b_done) + return false; + + boolean b_searching = true; + while (b_searching) { + switch (m_function) { + case State.initialize: + b_searching = initialize_(); + break; + case State.initializeRed: + b_searching = initializeRed_(); + break; + case State.initializeBlue: + b_searching = initializeBlue_(); + break; + case State.initializeRedBlue: + b_searching = initializeRedBlue_(); + break; + case State.sweep: + b_searching = sweep_(); + break; + case State.sweepBruteForce: + b_searching = sweepBruteForce_(); + break; + case State.sweepRedBlueBruteForce: + b_searching = sweepRedBlueBruteForce_(); + break; + case State.sweepRedBlue: + b_searching = sweepRedBlue_(); + break; + case State.sweepRed: + b_searching = sweepRed_(); + break; + case State.sweepBlue: + b_searching = sweepBlue_(); + break; + case State.iterate: + b_searching = iterate_(); + break; + case State.iterateRed: + b_searching = iterateRed_(); + break; + case State.iterateBlue: + b_searching = iterateBlue_(); + break; + case State.iterateBruteForce: + b_searching = iterateBruteForce_(); + break; + case State.iterateRedBlueBruteForce: + b_searching = iterateRedBlueBruteForce_(); + break; + case State.resetRed: + b_searching = resetRed_(); + break; + case State.resetBlue: + b_searching = resetBlue_(); + break; + default: + throw GeometryException.GeometryInternalError(); + } + } + + if (m_b_done) + return false; + + return true; + } + + /* + * Returns the index of the first envelope in the intersection. In the + * red/blue case, this will be an index to the red envelopes. + */ + int getHandleA() { + return m_envelope_handle_a; + } + + /* + * Returns the index of the second envelope in the intersection. In the + * red/blue case, this will be an index to the blue envelopes. + */ + int getHandleB() { + return m_envelope_handle_b; + } + + /* + * Sets the tolerance used for the intersection tests.\param tolerance The + * tolerance used to determine intersection. + */ + void setTolerance(double tolerance) { + m_tolerance = tolerance; + } + + /* + * Returns a reference to the envelope at the given handle. Use this for the red/red intersection case. + */ + Envelope2D getEnvelope(int handle) { + return m_envelopes_red.get(handle); + } + + /* + * Returns the user element associated with handle. Use this for the red/red intersection case. + */ + int getElement(int handle) { + return m_elements_red.read(handle); + } + + /* + * Returns a reference to the red envelope at handle_a. + */ + Envelope2D getRedEnvelope(int handle_a) { + return m_envelopes_red.get(handle_a); + } + + /* + * Returns a reference to the blue envelope at handle_b. + */ + Envelope2D getBlueEnvelope(int handle_b) { + return m_envelopes_blue.get(handle_b); + } + + /* + * Returns the user element associated with handle_a. + */ + int getRedElement(int handle_a) { + return m_elements_red.read(handle_a); + } + + /* + * Returns the user element associated with handle_b. + */ + int getBlueElement(int handle_b) { + return m_elements_blue.read(handle_b); + } + + private double m_tolerance; + private int m_sweep_index_red; + private int m_sweep_index_blue; + private int m_envelope_handle_a; + private int m_envelope_handle_b; + private IntervalTreeImpl m_interval_tree_red; + private IntervalTreeImpl m_interval_tree_blue; + private IntervalTreeImpl.IntervalTreeIteratorImpl m_iterator_red; + private IntervalTreeImpl.IntervalTreeIteratorImpl m_iterator_blue; + private Envelope2D m_envelope_helper = new Envelope2D(); + + private ArrayList m_envelopes_red; + private ArrayList m_envelopes_blue; + private AttributeStreamOfInt32 m_elements_red; + private AttributeStreamOfInt32 m_elements_blue; + + private AttributeStreamOfInt32 m_sorted_end_indices_red; + private AttributeStreamOfInt32 m_sorted_end_indices_blue; + + private int m_queued_list_red; + private int m_queued_list_blue; + private IndexMultiDCList m_queued_envelopes; + private AttributeStreamOfInt32 m_queued_indices_red; + private AttributeStreamOfInt32 m_queued_indices_blue; + private boolean m_b_add_red; + private boolean m_b_add_blue; + private boolean m_b_add_red_red; + private boolean m_b_done; + + private static boolean isTop_(int y_end_point_handle) { + return (y_end_point_handle & 0x1) == 1; + } + + private static boolean isBottom_(int y_end_point_handle) { + return (y_end_point_handle & 0x1) == 0; + } + + private void reset_() { + m_b_add_red = false; + m_b_add_blue = false; + m_b_add_red_red = false; + m_sweep_index_red = -1; + m_sweep_index_blue = -1; + m_queued_list_red = -1; + m_queued_list_blue = -1; + m_b_done = true; + } + + private boolean initialize_() { + m_envelope_handle_a = -1; + m_envelope_handle_b = -1; + + if (m_envelopes_red.size() < 10) { + m_sweep_index_red = m_envelopes_red.size(); + m_function = State.sweepBruteForce; + return true; + } + + if (m_interval_tree_red == null) { + m_interval_tree_red = new IntervalTreeImpl(true); + m_sorted_end_indices_red = new AttributeStreamOfInt32(0); + } + + m_interval_tree_red.addEnvelopesRef(m_envelopes_red); + + if (m_iterator_red == null) { + m_iterator_red = m_interval_tree_red.getIterator(); + } + + m_sorted_end_indices_red.reserve(2 * m_envelopes_red.size()); + m_sorted_end_indices_red.resize(0); + + for (int i = 0; i < 2 * m_envelopes_red.size(); i++) + m_sorted_end_indices_red.add(i); + + sortYEndIndices_(m_sorted_end_indices_red, 0, 2 * m_envelopes_red.size(), true); + + m_sweep_index_red = 2 * m_envelopes_red.size(); + + m_function = State.sweep; // overwrite initialize_ + + return true; + } + + private boolean initializeRed_() { + m_envelope_handle_a = -1; + m_envelope_handle_b = -1; + + if (m_envelopes_red.size() < 10 || m_envelopes_blue.size() < 10) { + m_sweep_index_red = m_envelopes_red.size(); + m_function = State.sweepRedBlueBruteForce; + return true; + } + + if (m_interval_tree_red == null) { + m_interval_tree_red = new IntervalTreeImpl(true); + m_sorted_end_indices_red = new AttributeStreamOfInt32(0); + } + + m_interval_tree_red.addEnvelopesRef(m_envelopes_red); + + if (m_iterator_red == null) { + m_iterator_red = m_interval_tree_red.getIterator(); + } + + m_sorted_end_indices_red.reserve(2 * m_envelopes_red.size()); + m_sorted_end_indices_red.resize(0); - for (int i = 0; i < 2 * m_envelopes_red.size(); i++) - m_sorted_end_indices_red.add(i); + for (int i = 0; i < 2 * m_envelopes_red.size(); i++) + m_sorted_end_indices_red.add(i); - sortYEndIndices_(m_sorted_end_indices_red, 0, m_sorted_end_indices_red.size(), true); - m_sweep_index_red = m_sorted_end_indices_red.size(); + sortYEndIndices_(m_sorted_end_indices_red, 0, m_sorted_end_indices_red.size(), true); + m_sweep_index_red = m_sorted_end_indices_red.size(); - if (m_queued_list_red != -1) { - m_queued_envelopes.deleteList(m_queued_list_red); - m_queued_indices_red.resize(0); - m_queued_list_red = -1; - } + if (m_queued_list_red != -1) { + m_queued_envelopes.deleteList(m_queued_list_red); + m_queued_indices_red.resize(0); + m_queued_list_red = -1; + } - m_function = State.sweepRedBlue; // overwrite initialize_ + m_function = State.sweepRedBlue; // overwrite initialize_ - return resetBlue_(); - } + return resetBlue_(); + } - private boolean initializeBlue_() { - m_envelope_handle_a = -1; - m_envelope_handle_b = -1; + private boolean initializeBlue_() { + m_envelope_handle_a = -1; + m_envelope_handle_b = -1; - if (m_envelopes_red.size() < 10 || m_envelopes_blue.size() < 10) { - m_sweep_index_red = m_envelopes_red.size(); - m_function = State.sweepRedBlueBruteForce; - return true; - } + if (m_envelopes_red.size() < 10 || m_envelopes_blue.size() < 10) { + m_sweep_index_red = m_envelopes_red.size(); + m_function = State.sweepRedBlueBruteForce; + return true; + } - if (m_interval_tree_blue == null) { - m_interval_tree_blue = new IntervalTreeImpl(true); - m_sorted_end_indices_blue = new AttributeStreamOfInt32(0); - } + if (m_interval_tree_blue == null) { + m_interval_tree_blue = new IntervalTreeImpl(true); + m_sorted_end_indices_blue = new AttributeStreamOfInt32(0); + } - m_interval_tree_blue.addEnvelopesRef(m_envelopes_blue); + m_interval_tree_blue.addEnvelopesRef(m_envelopes_blue); - if (m_iterator_blue == null) { - m_iterator_blue = m_interval_tree_blue.getIterator(); - } + if (m_iterator_blue == null) { + m_iterator_blue = m_interval_tree_blue.getIterator(); + } - m_sorted_end_indices_blue.reserve(2 * m_envelopes_blue.size()); - m_sorted_end_indices_blue.resize(0); + m_sorted_end_indices_blue.reserve(2 * m_envelopes_blue.size()); + m_sorted_end_indices_blue.resize(0); - for (int i = 0; i < 2 * m_envelopes_blue.size(); i++) - m_sorted_end_indices_blue.add(i); + for (int i = 0; i < 2 * m_envelopes_blue.size(); i++) + m_sorted_end_indices_blue.add(i); - sortYEndIndices_(m_sorted_end_indices_blue, 0, m_sorted_end_indices_blue.size(), false); - m_sweep_index_blue = m_sorted_end_indices_blue.size(); + sortYEndIndices_(m_sorted_end_indices_blue, 0, m_sorted_end_indices_blue.size(), false); + m_sweep_index_blue = m_sorted_end_indices_blue.size(); - if (m_queued_list_blue != -1) { - m_queued_envelopes.deleteList(m_queued_list_blue); - m_queued_indices_blue.resize(0); - m_queued_list_blue = -1; - } + if (m_queued_list_blue != -1) { + m_queued_envelopes.deleteList(m_queued_list_blue); + m_queued_indices_blue.resize(0); + m_queued_list_blue = -1; + } - m_function = State.sweepRedBlue; // overwrite initialize_ + m_function = State.sweepRedBlue; // overwrite initialize_ - return resetRed_(); - } + return resetRed_(); + } - private boolean initializeRedBlue_() { - m_envelope_handle_a = -1; - m_envelope_handle_b = -1; + private boolean initializeRedBlue_() { + m_envelope_handle_a = -1; + m_envelope_handle_b = -1; - if (m_envelopes_red.size() < 10 || m_envelopes_blue.size() < 10) { - m_sweep_index_red = m_envelopes_red.size(); - m_function = State.sweepRedBlueBruteForce; - return true; - } + if (m_envelopes_red.size() < 10 || m_envelopes_blue.size() < 10) { + m_sweep_index_red = m_envelopes_red.size(); + m_function = State.sweepRedBlueBruteForce; + return true; + } - if (m_interval_tree_red == null) { - m_interval_tree_red = new IntervalTreeImpl(true); - m_sorted_end_indices_red = new AttributeStreamOfInt32(0); - } + if (m_interval_tree_red == null) { + m_interval_tree_red = new IntervalTreeImpl(true); + m_sorted_end_indices_red = new AttributeStreamOfInt32(0); + } - if (m_interval_tree_blue == null) { - m_interval_tree_blue = new IntervalTreeImpl(true); - m_sorted_end_indices_blue = new AttributeStreamOfInt32(0); - } + if (m_interval_tree_blue == null) { + m_interval_tree_blue = new IntervalTreeImpl(true); + m_sorted_end_indices_blue = new AttributeStreamOfInt32(0); + } - m_interval_tree_red.addEnvelopesRef(m_envelopes_red); - m_interval_tree_blue.addEnvelopesRef(m_envelopes_blue); + m_interval_tree_red.addEnvelopesRef(m_envelopes_red); + m_interval_tree_blue.addEnvelopesRef(m_envelopes_blue); - if (m_iterator_red == null) { - m_iterator_red = m_interval_tree_red.getIterator(); - } + if (m_iterator_red == null) { + m_iterator_red = m_interval_tree_red.getIterator(); + } - if (m_iterator_blue == null) { - m_iterator_blue = m_interval_tree_blue.getIterator(); - } + if (m_iterator_blue == null) { + m_iterator_blue = m_interval_tree_blue.getIterator(); + } - m_sorted_end_indices_red.reserve(2 * m_envelopes_red.size()); - m_sorted_end_indices_blue.reserve(2 * m_envelopes_blue.size()); - m_sorted_end_indices_red.resize(0); - m_sorted_end_indices_blue.resize(0); + m_sorted_end_indices_red.reserve(2 * m_envelopes_red.size()); + m_sorted_end_indices_blue.reserve(2 * m_envelopes_blue.size()); + m_sorted_end_indices_red.resize(0); + m_sorted_end_indices_blue.resize(0); - for (int i = 0; i < 2 * m_envelopes_red.size(); i++) - m_sorted_end_indices_red.add(i); + for (int i = 0; i < 2 * m_envelopes_red.size(); i++) + m_sorted_end_indices_red.add(i); - for (int i = 0; i < 2 * m_envelopes_blue.size(); i++) - m_sorted_end_indices_blue.add(i); + for (int i = 0; i < 2 * m_envelopes_blue.size(); i++) + m_sorted_end_indices_blue.add(i); - sortYEndIndices_(m_sorted_end_indices_red, 0, m_sorted_end_indices_red.size(), true); - sortYEndIndices_(m_sorted_end_indices_blue, 0, m_sorted_end_indices_blue.size(), false); + sortYEndIndices_(m_sorted_end_indices_red, 0, m_sorted_end_indices_red.size(), true); + sortYEndIndices_(m_sorted_end_indices_blue, 0, m_sorted_end_indices_blue.size(), false); - m_sweep_index_red = m_sorted_end_indices_red.size(); - m_sweep_index_blue = m_sorted_end_indices_blue.size(); - - if (m_queued_list_red != -1) { - m_queued_envelopes.deleteList(m_queued_list_red); - m_queued_indices_red.resize(0); - m_queued_list_red = -1; - } - - if (m_queued_list_blue != -1) { - m_queued_envelopes.deleteList(m_queued_list_blue); - m_queued_indices_blue.resize(0); - m_queued_list_blue = -1; - } - - m_function = State.sweepRedBlue; // overwrite initialize_ - - return true; - } - - private boolean sweep_() { - int y_end_point_handle = m_sorted_end_indices_red.get(--m_sweep_index_red); - int envelope_handle = y_end_point_handle >> 1; - - if (isBottom_(y_end_point_handle)) { - m_interval_tree_red.remove(envelope_handle); - - if (m_sweep_index_red == 0) { - m_envelope_handle_a = -1; - m_envelope_handle_b = -1; - m_b_done = true; - return false; - } - - return true; - } - - m_iterator_red.resetIterator(m_envelopes_red.get(envelope_handle).xmin, m_envelopes_red.get(envelope_handle).xmax, m_tolerance); - m_envelope_handle_a = envelope_handle; - m_function = State.iterate; - - return true; - } - - private boolean sweepBruteForce_() {// this isn't really a sweep, it just walks along the array of red envelopes backward. - if (--m_sweep_index_red == -1) { - m_envelope_handle_a = -1; - m_envelope_handle_b = -1; - m_b_done = true; - return false; - } - - m_envelope_handle_a = m_sweep_index_red; - m_sweep_index_blue = m_sweep_index_red; - m_function = State.iterateBruteForce; - - return true; - } - - private boolean sweepRedBlueBruteForce_() {// this isn't really a sweep, it just walks along the array of red envelopes backward. - if (--m_sweep_index_red == -1) { - m_envelope_handle_a = -1; - m_envelope_handle_b = -1; - m_b_done = true; - return false; - } - - m_envelope_handle_a = m_sweep_index_red; - m_sweep_index_blue = m_envelopes_blue.size(); - m_function = State.iterateRedBlueBruteForce; - - return true; - } - - private boolean sweepRedBlue_() {// controls whether we want to sweep the red envelopes or sweep the blue envelopes - int y_end_point_handle_red = m_sorted_end_indices_red.get(m_sweep_index_red - 1); - int y_end_point_handle_blue = m_sorted_end_indices_blue.get(m_sweep_index_blue - 1); - - double y_red = getAdjustedValue_(y_end_point_handle_red, true); - double y_blue = getAdjustedValue_(y_end_point_handle_blue, false); - - if (y_red > y_blue) - return sweepRed_(); - if (y_red < y_blue) - return sweepBlue_(); - - if (isTop_(y_end_point_handle_red)) - return sweepRed_(); - if (isTop_(y_end_point_handle_blue)) - return sweepBlue_(); - - return sweepRed_(); // arbitrary. can call sweep_blue_ instead and would also work correctly - } - - private boolean sweepRed_() { - int y_end_point_handle_red = m_sorted_end_indices_red.get(--m_sweep_index_red); - int envelope_handle_red = y_end_point_handle_red >> 1; - - if (isBottom_(y_end_point_handle_red)) { - if (m_queued_list_red != -1 && m_queued_indices_red.get(envelope_handle_red) != -1) { - m_queued_envelopes.deleteElement(m_queued_list_red, m_queued_indices_red.get(envelope_handle_red)); - m_queued_indices_red.set(envelope_handle_red, -1); - } else - m_interval_tree_red.remove(envelope_handle_red); - - if (m_sweep_index_red == 0) { - m_envelope_handle_a = -1; - m_envelope_handle_b = -1; - m_b_done = true; - return false; - } - - return true; - } - - if (m_queued_list_blue != -1 && m_queued_envelopes.getListSize(m_queued_list_blue) > 0) { - int node = m_queued_envelopes.getFirst(m_queued_list_blue); - while (node != -1) { - int e = m_queued_envelopes.getData(node); - m_interval_tree_blue.insert(e); - m_queued_indices_blue.set(e, -1); - int next_node = m_queued_envelopes.getNext(node); - m_queued_envelopes.deleteElement(m_queued_list_blue, node); - node = next_node; - } - } - - if (m_interval_tree_blue.size() > 0) { - m_iterator_blue.resetIterator(m_envelopes_red.get(envelope_handle_red).xmin, m_envelopes_red.get(envelope_handle_red).xmax, m_tolerance); - m_envelope_handle_a = envelope_handle_red; - m_function = State.iterateBlue; - } else { - if (m_queued_list_red == -1) { - if (m_queued_envelopes == null) - m_queued_envelopes = new IndexMultiDCList(); - - m_queued_indices_red = new AttributeStreamOfInt32(0); - m_queued_indices_red.resize(m_envelopes_red.size(), -1); - m_queued_indices_red.setRange(-1, 0, m_envelopes_red.size()); - m_queued_list_red = m_queued_envelopes.createList(1); - } - - m_queued_indices_red.set(envelope_handle_red, m_queued_envelopes.addElement(m_queued_list_red, envelope_handle_red)); - m_function = State.sweepRedBlue; - } - - return true; - } - - private boolean sweepBlue_() { - int y_end_point_handle_blue = m_sorted_end_indices_blue.get(--m_sweep_index_blue); - int envelope_handle_blue = y_end_point_handle_blue >> 1; - - if (isBottom_(y_end_point_handle_blue)) { - if (m_queued_list_blue != -1 && m_queued_indices_blue.get(envelope_handle_blue) != -1) { - m_queued_envelopes.deleteElement(m_queued_list_blue, m_queued_indices_blue.get(envelope_handle_blue)); - m_queued_indices_blue.set(envelope_handle_blue, -1); - } else - m_interval_tree_blue.remove(envelope_handle_blue); - - if (m_sweep_index_blue == 0) { - m_envelope_handle_a = -1; - m_envelope_handle_b = -1; - m_b_done = true; - return false; - } - - return true; - } - - if (m_queued_list_red != -1 && m_queued_envelopes.getListSize(m_queued_list_red) > 0) { - int node = m_queued_envelopes.getFirst(m_queued_list_red); - while (node != -1) { - int e = m_queued_envelopes.getData(node); - m_interval_tree_red.insert(e); - m_queued_indices_red.set(e, -1); - int next_node = m_queued_envelopes.getNext(node); - m_queued_envelopes.deleteElement(m_queued_list_red, node); - node = next_node; - } - } - - if (m_interval_tree_red.size() > 0) { - m_iterator_red.resetIterator(m_envelopes_blue.get(envelope_handle_blue).xmin, m_envelopes_blue.get(envelope_handle_blue).xmax, m_tolerance); - m_envelope_handle_b = envelope_handle_blue; - m_function = State.iterateRed; - } else { - if (m_queued_list_blue == -1) { - if (m_queued_envelopes == null) - m_queued_envelopes = new IndexMultiDCList(); - - m_queued_indices_blue = new AttributeStreamOfInt32(0); - m_queued_indices_blue.resize(m_envelopes_blue.size(), -1); - m_queued_indices_blue.setRange(-1, 0, m_envelopes_blue.size()); - m_queued_list_blue = m_queued_envelopes.createList(0); - } - - m_queued_indices_blue.set(envelope_handle_blue, m_queued_envelopes.addElement(m_queued_list_blue, envelope_handle_blue)); - m_function = State.sweepRedBlue; - } - - return true; - } - - private boolean iterate_() { - m_envelope_handle_b = m_iterator_red.next(); - if (m_envelope_handle_b != -1) - return false; - - int envelope_handle = m_sorted_end_indices_red.get(m_sweep_index_red) >> 1; - m_interval_tree_red.insert(envelope_handle); - m_function = State.sweep; - - return true; - } - - private boolean iterateRed_() { - m_envelope_handle_a = m_iterator_red.next(); - if (m_envelope_handle_a != -1) - return false; - - m_envelope_handle_a = -1; - m_envelope_handle_b = -1; - - int envelope_handle_blue = m_sorted_end_indices_blue.get(m_sweep_index_blue) >> 1; - m_interval_tree_blue.insert(envelope_handle_blue); - m_function = State.sweepRedBlue; - - return true; - } - - private boolean iterateBlue_() { - m_envelope_handle_b = m_iterator_blue.next(); - if (m_envelope_handle_b != -1) - return false; - - int envelope_handle_red = m_sorted_end_indices_red.get(m_sweep_index_red) >> 1; - m_interval_tree_red.insert(envelope_handle_red); - m_function = State.sweepRedBlue; - - return true; - } - - private boolean iterateBruteForce_() { - if (--m_sweep_index_blue == -1) { - m_function = State.sweepBruteForce; - return true; - } - - m_envelope_helper.setCoords(m_envelopes_red.get(m_sweep_index_red)); - Envelope2D envelope_b = m_envelopes_red.get(m_sweep_index_blue); - - m_envelope_helper.inflate(m_tolerance, m_tolerance); - if (m_envelope_helper.isIntersecting(envelope_b)) { - m_envelope_handle_b = m_sweep_index_blue; - return false; - } - - return true; - } - - private boolean iterateRedBlueBruteForce_() { - if (--m_sweep_index_blue == -1) { - m_function = State.sweepRedBlueBruteForce; - return true; - } - - m_envelope_helper.setCoords(m_envelopes_red.get(m_sweep_index_red)); - Envelope2D envelope_b = m_envelopes_blue.get(m_sweep_index_blue); - - m_envelope_helper.inflate(m_tolerance, m_tolerance); - if (m_envelope_helper.isIntersecting(envelope_b)) { - m_envelope_handle_b = m_sweep_index_blue; - return false; - } - - return true; - } - - private boolean resetRed_() { - if (m_interval_tree_red == null) { - m_b_done = true; - return false; - } - - m_sweep_index_red = m_sorted_end_indices_red.size(); - - if (m_interval_tree_red.size() > 0) - m_interval_tree_red.reset(); - - if (m_queued_list_red != -1) { - m_queued_envelopes.deleteList(m_queued_list_red); - m_queued_indices_red.resize(0); - m_queued_list_red = -1; - } - - m_b_done = false; - return true; - } - - private boolean resetBlue_() { - if (m_interval_tree_blue == null) { - m_b_done = true; - return false; - } - - m_sweep_index_blue = m_sorted_end_indices_blue.size(); - - if (m_interval_tree_blue.size() > 0) - m_interval_tree_blue.reset(); - - if (m_queued_list_blue != -1) { - m_queued_envelopes.deleteList(m_queued_list_blue); - m_queued_indices_blue.resize(0); - m_queued_list_blue = -1; - } - - m_b_done = false; - return true; - } - - private int m_function; - - private interface State { - static final int initialize = 0; - static final int initializeRed = 1; - static final int initializeBlue = 2; - static final int initializeRedBlue = 3; - static final int sweep = 4; - static final int sweepBruteForce = 5; - static final int sweepRedBlueBruteForce = 6; - static final int sweepRedBlue = 7; - static final int sweepRed = 8; - static final int sweepBlue = 9; - static final int iterate = 10; - static final int iterateRed = 11; - static final int iterateBlue = 12; - static final int iterateBruteForce = 13; - static final int iterateRedBlueBruteForce = 14; - static final int resetRed = 15; - static final int resetBlue = 16; - } - - // *********** Helpers for Bucket sort************** - private BucketSort m_bucket_sort; - - private void sortYEndIndices_(AttributeStreamOfInt32 end_indices, int begin_, int end_, boolean b_red) { - if (m_bucket_sort == null) - m_bucket_sort = new BucketSort(); - - Envelope2DBucketSortHelper sorter = new Envelope2DBucketSortHelper(this, b_red); - m_bucket_sort.sort(end_indices, begin_, end_, sorter); - } - - private void sortYEndIndicesHelper_(AttributeStreamOfInt32 end_indices, int begin_, int end_, boolean b_red) { - end_indices.Sort(begin_, end_, new EndPointsComparer(this, b_red)); - } - - private double getAdjustedValue_(int e, boolean b_red) { - double dy = 0.5 * m_tolerance; - if (b_red) { - Envelope2D envelope_red = m_envelopes_red.get(e >> 1); - double y = (isBottom_(e) ? envelope_red.ymin - dy : envelope_red.ymax + dy); - return y; - } - - Envelope2D envelope_blue = m_envelopes_blue.get(e >> 1); - double y = (isBottom_(e) ? envelope_blue.ymin - dy : envelope_blue.ymax + dy); - return y; - } - - private static final class EndPointsComparer extends AttributeStreamOfInt32.IntComparator {// For user sort - - EndPointsComparer(Envelope2DIntersectorImpl intersector, boolean b_red) { - m_intersector = intersector; - m_b_red = b_red; - } - - @Override - public int compare(int e_1, int e_2) { - double y1 = m_intersector.getAdjustedValue_(e_1, m_b_red); - double y2 = m_intersector.getAdjustedValue_(e_2, m_b_red); - - if (y1 < y2 || (y1 == y2 && isBottom_(e_1) && isTop_(e_2))) - return -1; - - return 1; - } - - private Envelope2DIntersectorImpl m_intersector; - private boolean m_b_red; - } - - private static final class Envelope2DBucketSortHelper extends ClassicSort {// For - - // bucket - // sort - Envelope2DBucketSortHelper(Envelope2DIntersectorImpl intersector, boolean b_red) { - m_intersector = intersector; - m_b_red = b_red; - } - - @Override - public void userSort(int begin, int end, AttributeStreamOfInt32 indices) { - m_intersector.sortYEndIndicesHelper_(indices, begin, end, m_b_red); - } - - @Override - public double getValue(int index) { - return m_intersector.getAdjustedValue_(index, m_b_red); - } - - private Envelope2DIntersectorImpl m_intersector; - private boolean m_b_red; - } + m_sweep_index_red = m_sorted_end_indices_red.size(); + m_sweep_index_blue = m_sorted_end_indices_blue.size(); + + if (m_queued_list_red != -1) { + m_queued_envelopes.deleteList(m_queued_list_red); + m_queued_indices_red.resize(0); + m_queued_list_red = -1; + } + + if (m_queued_list_blue != -1) { + m_queued_envelopes.deleteList(m_queued_list_blue); + m_queued_indices_blue.resize(0); + m_queued_list_blue = -1; + } + + m_function = State.sweepRedBlue; // overwrite initialize_ + + return true; + } + + private boolean sweep_() { + int y_end_point_handle = m_sorted_end_indices_red.get(--m_sweep_index_red); + int envelope_handle = y_end_point_handle >> 1; + + if (isBottom_(y_end_point_handle)) { + m_interval_tree_red.remove(envelope_handle); + + if (m_sweep_index_red == 0) { + m_envelope_handle_a = -1; + m_envelope_handle_b = -1; + m_b_done = true; + return false; + } + + return true; + } + + m_iterator_red.resetIterator(m_envelopes_red.get(envelope_handle).xmin, m_envelopes_red.get(envelope_handle).xmax, m_tolerance); + m_envelope_handle_a = envelope_handle; + m_function = State.iterate; + + return true; + } + + private boolean sweepBruteForce_() {// this isn't really a sweep, it just walks along the array of red envelopes backward. + if (--m_sweep_index_red == -1) { + m_envelope_handle_a = -1; + m_envelope_handle_b = -1; + m_b_done = true; + return false; + } + + m_envelope_handle_a = m_sweep_index_red; + m_sweep_index_blue = m_sweep_index_red; + m_function = State.iterateBruteForce; + + return true; + } + + private boolean sweepRedBlueBruteForce_() {// this isn't really a sweep, it just walks along the array of red envelopes backward. + if (--m_sweep_index_red == -1) { + m_envelope_handle_a = -1; + m_envelope_handle_b = -1; + m_b_done = true; + return false; + } + + m_envelope_handle_a = m_sweep_index_red; + m_sweep_index_blue = m_envelopes_blue.size(); + m_function = State.iterateRedBlueBruteForce; + + return true; + } + + private boolean sweepRedBlue_() {// controls whether we want to sweep the red envelopes or sweep the blue envelopes + int y_end_point_handle_red = m_sorted_end_indices_red.get(m_sweep_index_red - 1); + int y_end_point_handle_blue = m_sorted_end_indices_blue.get(m_sweep_index_blue - 1); + + double y_red = getAdjustedValue_(y_end_point_handle_red, true); + double y_blue = getAdjustedValue_(y_end_point_handle_blue, false); + + if (y_red > y_blue) + return sweepRed_(); + if (y_red < y_blue) + return sweepBlue_(); + + if (isTop_(y_end_point_handle_red)) + return sweepRed_(); + if (isTop_(y_end_point_handle_blue)) + return sweepBlue_(); + + return sweepRed_(); // arbitrary. can call sweep_blue_ instead and would also work correctly + } + + private boolean sweepRed_() { + int y_end_point_handle_red = m_sorted_end_indices_red.get(--m_sweep_index_red); + int envelope_handle_red = y_end_point_handle_red >> 1; + + if (isBottom_(y_end_point_handle_red)) { + if (m_queued_list_red != -1 && m_queued_indices_red.get(envelope_handle_red) != -1) { + m_queued_envelopes.deleteElement(m_queued_list_red, m_queued_indices_red.get(envelope_handle_red)); + m_queued_indices_red.set(envelope_handle_red, -1); + } else + m_interval_tree_red.remove(envelope_handle_red); + + if (m_sweep_index_red == 0) { + m_envelope_handle_a = -1; + m_envelope_handle_b = -1; + m_b_done = true; + return false; + } + + return true; + } + + if (m_queued_list_blue != -1 && m_queued_envelopes.getListSize(m_queued_list_blue) > 0) { + int node = m_queued_envelopes.getFirst(m_queued_list_blue); + while (node != -1) { + int e = m_queued_envelopes.getData(node); + m_interval_tree_blue.insert(e); + m_queued_indices_blue.set(e, -1); + int next_node = m_queued_envelopes.getNext(node); + m_queued_envelopes.deleteElement(m_queued_list_blue, node); + node = next_node; + } + } + + if (m_interval_tree_blue.size() > 0) { + m_iterator_blue.resetIterator(m_envelopes_red.get(envelope_handle_red).xmin, m_envelopes_red.get(envelope_handle_red).xmax, m_tolerance); + m_envelope_handle_a = envelope_handle_red; + m_function = State.iterateBlue; + } else { + if (m_queued_list_red == -1) { + if (m_queued_envelopes == null) + m_queued_envelopes = new IndexMultiDCList(); + + m_queued_indices_red = new AttributeStreamOfInt32(0); + m_queued_indices_red.resize(m_envelopes_red.size(), -1); + m_queued_indices_red.setRange(-1, 0, m_envelopes_red.size()); + m_queued_list_red = m_queued_envelopes.createList(1); + } + + m_queued_indices_red.set(envelope_handle_red, m_queued_envelopes.addElement(m_queued_list_red, envelope_handle_red)); + m_function = State.sweepRedBlue; + } + + return true; + } + + private boolean sweepBlue_() { + int y_end_point_handle_blue = m_sorted_end_indices_blue.get(--m_sweep_index_blue); + int envelope_handle_blue = y_end_point_handle_blue >> 1; + + if (isBottom_(y_end_point_handle_blue)) { + if (m_queued_list_blue != -1 && m_queued_indices_blue.get(envelope_handle_blue) != -1) { + m_queued_envelopes.deleteElement(m_queued_list_blue, m_queued_indices_blue.get(envelope_handle_blue)); + m_queued_indices_blue.set(envelope_handle_blue, -1); + } else + m_interval_tree_blue.remove(envelope_handle_blue); + + if (m_sweep_index_blue == 0) { + m_envelope_handle_a = -1; + m_envelope_handle_b = -1; + m_b_done = true; + return false; + } + + return true; + } + + if (m_queued_list_red != -1 && m_queued_envelopes.getListSize(m_queued_list_red) > 0) { + int node = m_queued_envelopes.getFirst(m_queued_list_red); + while (node != -1) { + int e = m_queued_envelopes.getData(node); + m_interval_tree_red.insert(e); + m_queued_indices_red.set(e, -1); + int next_node = m_queued_envelopes.getNext(node); + m_queued_envelopes.deleteElement(m_queued_list_red, node); + node = next_node; + } + } + + if (m_interval_tree_red.size() > 0) { + m_iterator_red.resetIterator(m_envelopes_blue.get(envelope_handle_blue).xmin, m_envelopes_blue.get(envelope_handle_blue).xmax, m_tolerance); + m_envelope_handle_b = envelope_handle_blue; + m_function = State.iterateRed; + } else { + if (m_queued_list_blue == -1) { + if (m_queued_envelopes == null) + m_queued_envelopes = new IndexMultiDCList(); + + m_queued_indices_blue = new AttributeStreamOfInt32(0); + m_queued_indices_blue.resize(m_envelopes_blue.size(), -1); + m_queued_indices_blue.setRange(-1, 0, m_envelopes_blue.size()); + m_queued_list_blue = m_queued_envelopes.createList(0); + } + + m_queued_indices_blue.set(envelope_handle_blue, m_queued_envelopes.addElement(m_queued_list_blue, envelope_handle_blue)); + m_function = State.sweepRedBlue; + } + + return true; + } + + private boolean iterate_() { + m_envelope_handle_b = m_iterator_red.next(); + if (m_envelope_handle_b != -1) + return false; + + int envelope_handle = m_sorted_end_indices_red.get(m_sweep_index_red) >> 1; + m_interval_tree_red.insert(envelope_handle); + m_function = State.sweep; + + return true; + } + + private boolean iterateRed_() { + m_envelope_handle_a = m_iterator_red.next(); + if (m_envelope_handle_a != -1) + return false; + + m_envelope_handle_a = -1; + m_envelope_handle_b = -1; + + int envelope_handle_blue = m_sorted_end_indices_blue.get(m_sweep_index_blue) >> 1; + m_interval_tree_blue.insert(envelope_handle_blue); + m_function = State.sweepRedBlue; + + return true; + } + + private boolean iterateBlue_() { + m_envelope_handle_b = m_iterator_blue.next(); + if (m_envelope_handle_b != -1) + return false; + + int envelope_handle_red = m_sorted_end_indices_red.get(m_sweep_index_red) >> 1; + m_interval_tree_red.insert(envelope_handle_red); + m_function = State.sweepRedBlue; + + return true; + } + + private boolean iterateBruteForce_() { + if (--m_sweep_index_blue == -1) { + m_function = State.sweepBruteForce; + return true; + } + + m_envelope_helper.setCoords(m_envelopes_red.get(m_sweep_index_red)); + Envelope2D envelope_b = m_envelopes_red.get(m_sweep_index_blue); + + m_envelope_helper.inflate(m_tolerance, m_tolerance); + if (m_envelope_helper.isIntersecting(envelope_b)) { + m_envelope_handle_b = m_sweep_index_blue; + return false; + } + + return true; + } + + private boolean iterateRedBlueBruteForce_() { + if (--m_sweep_index_blue == -1) { + m_function = State.sweepRedBlueBruteForce; + return true; + } + + m_envelope_helper.setCoords(m_envelopes_red.get(m_sweep_index_red)); + Envelope2D envelope_b = m_envelopes_blue.get(m_sweep_index_blue); + + m_envelope_helper.inflate(m_tolerance, m_tolerance); + if (m_envelope_helper.isIntersecting(envelope_b)) { + m_envelope_handle_b = m_sweep_index_blue; + return false; + } + + return true; + } + + private boolean resetRed_() { + if (m_interval_tree_red == null) { + m_b_done = true; + return false; + } + + m_sweep_index_red = m_sorted_end_indices_red.size(); + + if (m_interval_tree_red.size() > 0) + m_interval_tree_red.reset(); + + if (m_queued_list_red != -1) { + m_queued_envelopes.deleteList(m_queued_list_red); + m_queued_indices_red.resize(0); + m_queued_list_red = -1; + } + + m_b_done = false; + return true; + } + + private boolean resetBlue_() { + if (m_interval_tree_blue == null) { + m_b_done = true; + return false; + } + + m_sweep_index_blue = m_sorted_end_indices_blue.size(); + + if (m_interval_tree_blue.size() > 0) + m_interval_tree_blue.reset(); + + if (m_queued_list_blue != -1) { + m_queued_envelopes.deleteList(m_queued_list_blue); + m_queued_indices_blue.resize(0); + m_queued_list_blue = -1; + } + + m_b_done = false; + return true; + } + + private int m_function; + + private interface State { + static final int initialize = 0; + static final int initializeRed = 1; + static final int initializeBlue = 2; + static final int initializeRedBlue = 3; + static final int sweep = 4; + static final int sweepBruteForce = 5; + static final int sweepRedBlueBruteForce = 6; + static final int sweepRedBlue = 7; + static final int sweepRed = 8; + static final int sweepBlue = 9; + static final int iterate = 10; + static final int iterateRed = 11; + static final int iterateBlue = 12; + static final int iterateBruteForce = 13; + static final int iterateRedBlueBruteForce = 14; + static final int resetRed = 15; + static final int resetBlue = 16; + } + + // *********** Helpers for Bucket sort************** + private BucketSort m_bucket_sort; + + private void sortYEndIndices_(AttributeStreamOfInt32 end_indices, int begin_, int end_, boolean b_red) { + if (m_bucket_sort == null) + m_bucket_sort = new BucketSort(); + + Envelope2DBucketSortHelper sorter = new Envelope2DBucketSortHelper(this, b_red); + m_bucket_sort.sort(end_indices, begin_, end_, sorter); + } + + private void sortYEndIndicesHelper_(AttributeStreamOfInt32 end_indices, int begin_, int end_, boolean b_red) { + end_indices.Sort(begin_, end_, new EndPointsComparer(this, b_red)); + } + + private double getAdjustedValue_(int e, boolean b_red) { + double dy = 0.5 * m_tolerance; + if (b_red) { + Envelope2D envelope_red = m_envelopes_red.get(e >> 1); + double y = (isBottom_(e) ? envelope_red.ymin - dy : envelope_red.ymax + dy); + return y; + } + + Envelope2D envelope_blue = m_envelopes_blue.get(e >> 1); + double y = (isBottom_(e) ? envelope_blue.ymin - dy : envelope_blue.ymax + dy); + return y; + } + + private static final class EndPointsComparer extends AttributeStreamOfInt32.IntComparator {// For user sort + + EndPointsComparer(Envelope2DIntersectorImpl intersector, boolean b_red) { + m_intersector = intersector; + m_b_red = b_red; + } + + @Override + public int compare(int e_1, int e_2) { + double y1 = m_intersector.getAdjustedValue_(e_1, m_b_red); + double y2 = m_intersector.getAdjustedValue_(e_2, m_b_red); + + if (y1 < y2 || (y1 == y2 && isBottom_(e_1) && isTop_(e_2))) + return -1; + + return 1; + } + + private Envelope2DIntersectorImpl m_intersector; + private boolean m_b_red; + } + + private static final class Envelope2DBucketSortHelper extends ClassicSort {// For + + // bucket + // sort + Envelope2DBucketSortHelper(Envelope2DIntersectorImpl intersector, boolean b_red) { + m_intersector = intersector; + m_b_red = b_red; + } + + @Override + public void userSort(int begin, int end, AttributeStreamOfInt32 indices) { + m_intersector.sortYEndIndicesHelper_(indices, begin, end, m_b_red); + } + + @Override + public double getValue(int index) { + return m_intersector.getAdjustedValue_(index, m_b_red); + } + + private Envelope2DIntersectorImpl m_intersector; + private boolean m_b_red; + } } diff --git a/src/main/java/com/esri/core/geometry/Envelope3D.java b/src/main/java/com/esri/core/geometry/Envelope3D.java index 8df3989d..6fa8b522 100644 --- a/src/main/java/com/esri/core/geometry/Envelope3D.java +++ b/src/main/java/com/esri/core/geometry/Envelope3D.java @@ -30,337 +30,353 @@ /** * A class that represents axis parallel 3D rectangle. */ -public final class Envelope3D implements Serializable { - private static final long serialVersionUID = 1L; - - public double xmin; - - public double ymin; - - public double zmin; - - public double xmax; - - public double ymax; - - public double zmax; - - public static Envelope3D construct(double _xmin, double _ymin, - double _zmin, double _xmax, double _ymax, double _zmax) { - Envelope3D env = new Envelope3D(_xmin, _ymin, _zmin, _xmax, _ymax, _zmax); - return env; - } - - public Envelope3D(double _xmin, double _ymin, double _zmin, double _xmax, double _ymax, double _zmax) { - setCoords(_xmin, _ymin, _zmin, _xmax, _ymax, _zmax); - } - - public Envelope3D() { - - } - - public Envelope3D(Envelope3D other) { - setCoords(other); - } - - - public void setInfinite() { - xmin = NumberUtils.negativeInf(); - xmax = NumberUtils.positiveInf(); - ymin = NumberUtils.negativeInf(); - ymax = NumberUtils.positiveInf(); - zmin = NumberUtils.negativeInf(); - zmax = NumberUtils.positiveInf(); - } - - public void setEmpty() { - xmin = NumberUtils.NaN(); - ymin = NumberUtils.NaN(); - zmin = NumberUtils.NaN(); - xmax = 0; - ymax = 0; - zmax = 0; - } - - public boolean isEmpty() { - return NumberUtils.isNaN(xmin); - } - - public void setEmptyZ() { - zmin = NumberUtils.NaN(); - } - - public boolean isEmptyZ() { - return NumberUtils.isNaN(zmin); - } - - public boolean hasEmptyDimension() { - return isEmpty() || isEmptyZ(); - } - - public void setCoords(double _xmin, double _ymin, double _zmin, - double _xmax, double _ymax, double _zmax) { - xmin = _xmin; - ymin = _ymin; - zmin = _zmin; - xmax = _xmax; - ymax = _ymax; - zmax = _zmax; - normalize(); - } - - public void setCoords(double _x, double _y, double _z) { - xmin = _x; - ymin = _y; - zmin = _z; - xmax = _x; - ymax = _y; - zmax = _z; - } - - public void setCoords(Point3D center, double width, double height, - double depth) { - xmin = center.x - width * 0.5; - xmax = xmin + width; - ymin = center.y - height * 0.5; - ymax = ymin + height; - zmin = center.z - depth * 0.5; - zmax = zmin + depth; - normalize(); - } - - public void setCoords(Envelope3D envSrc) { - - setCoords(envSrc.xmin, envSrc.ymin, envSrc.zmin, envSrc.xmax, envSrc.ymax, envSrc.zmax); - } - - public double getWidth() { - return xmax - xmin; - } - - public double getHeight() { - return ymax - ymin; - } - - public double getDepth() { - return zmax - zmin; - } - - public void move(Point3D vector) { - xmin += vector.x; - ymin += vector.y; - zmin += vector.z; - xmax += vector.x; - ymax += vector.y; - zmax += vector.z; - } - - public void normalize() { - if (isEmpty()) - return; - - double min = Math.min(xmin, xmax); - double max = Math.max(xmin, xmax); - xmin = min; - xmax = max; - min = Math.min(ymin, ymax); - max = Math.max(ymin, ymax); - ymin = min; - ymax = max; - min = Math.min(zmin, zmax); - max = Math.max(zmin, zmax); - zmin = min; - zmax = max; - } - - public void copyTo(Envelope2D env) { - env.xmin = xmin; - env.ymin = ymin; - env.xmax = xmax; - env.ymax = ymax; - } - - public void mergeNE(double x, double y, double z) { - if (xmin > x) - xmin = x; - else if (xmax < x) - xmax = x; - - if (ymin > y) - ymin = y; - else if (ymax < y) - ymax = y; - - if (zmin != NumberUtils.NaN()) { - if (zmin > z) - zmin = z; - else if (zmax < z) - zmax = z; - } else { - zmin = z; - zmax = z; - } - } - - public void merge(double x, double y, double z) { - if (isEmpty()) { - xmin = x; - ymin = y; - zmin = z; - xmax = x; - ymax = y; - zmax = z; - } else { - mergeNE(x, y, z); - } - } - - public void merge(Point3D pt) { - merge(pt.x, pt.y, pt.z); - } - - public void merge(Envelope3D other) { - if (other.isEmpty()) - return; - - merge(other.xmin, other.ymin, other.zmin); - merge(other.xmax, other.ymax, other.zmax); - } - - public void merge(double x1, double y1, double z1, double x2, double y2, - double z2) { - merge(x1, y1, z1); - merge(x2, y2, z2); - } - - public void inflate(double dx, double dy, double dz) { - if (isEmpty()) - return; - xmin -= dx; - xmax += dx; - ymin -= dy; - ymax += dy; - zmin -= dz; - zmax += dz; - if (xmin > xmax || ymin > ymax || zmin > zmax) - setEmpty(); - } - - /** - * Checks if this envelope intersects the other. - * - * @return True if this envelope intersects the other. - */ - public boolean isIntersecting(Envelope3D other) { - return !isEmpty() && !other.isEmpty() && ((xmin <= other.xmin) ? xmax >= other.xmin : other.xmax >= xmin) && // check that x projections overlap - ((ymin <= other.ymin) ? ymax >= other.ymin : other.ymax >= ymin) && // check that y projections overlap - ((zmin <= other.zmin) ? zmax >= other.zmin : other.zmax >= zmin); // check that z projections overlap - } - - /** - * Intersects this envelope with the other and stores result in this - * envelope. - * - * @return True if this envelope intersects the other, otherwise sets this - * envelope to empty state and returns False. - */ - public boolean intersect(Envelope3D other) { - if (isEmpty() || other.isEmpty()) - return false; - - if (other.xmin > xmin) - xmin = other.xmin; - - if (other.xmax < xmax) - xmax = other.xmax; - - if (other.ymin > ymin) - ymin = other.ymin; - - if (other.ymax < ymax) - ymax = other.ymax; - - if (other.zmin > zmin) - zmin = other.zmin; - - if (other.zmax < zmax) - zmax = other.zmax; - - boolean bIntersecting = xmin <= xmax && ymin <= ymax && zmin <= zmax; - - if (!bIntersecting) - setEmpty(); - - return bIntersecting; - } - - /** - * Returns True if the envelope contains the other envelope (boundary - * inclusive). - */ - public boolean contains(Envelope3D other) {// Note: Will return False, if either envelope is empty. - return other.xmin >= xmin && other.xmax <= xmax && other.ymin >= ymin && other.ymax <= ymax && other.zmin >= zmin && other.zmax <= zmax; - } - - @Override - public boolean equals(Object _other) { - if (_other == this) - return true; - - if (!(_other instanceof Envelope3D)) - return false; - - Envelope3D other = (Envelope3D) _other; - if (isEmpty() && other.isEmpty()) - return true; - - if (xmin != other.xmin || ymin != other.ymin || zmin != other.zmin || xmax != other.xmax || ymax != other.ymax || zmax != other.zmax) - return false; - - return true; - } - - public void construct(Envelope1D xinterval, Envelope1D yinterval, - Envelope1D zinterval) { - if (xinterval.isEmpty() || yinterval.isEmpty()) { - setEmpty(); - return; - } - - xmin = xinterval.vmin; - xmax = xinterval.vmax; - ymin = yinterval.vmin; - ymax = yinterval.vmax; - zmin = zinterval.vmin; - zmax = zinterval.vmax; - } - - public void queryCorners(Point3D[] corners) { - if ((corners == null) || (corners.length < 8)) - throw new IllegalArgumentException(); - - corners[0] = new Point3D(xmin, ymin, zmin); - corners[1] = new Point3D(xmin, ymax, zmin); - corners[2] = new Point3D(xmax, ymax, zmin); - corners[3] = new Point3D(xmax, ymin, zmin); - corners[4] = new Point3D(xmin, ymin, zmax); - corners[5] = new Point3D(xmin, ymax, zmax); - corners[6] = new Point3D(xmax, ymax, zmax); - corners[7] = new Point3D(xmax, ymin, zmax); - - } - - public void setFromPoints(Point3D[] points) { - if (points == null || points.length == 0) { - setEmpty(); - return; - } - - Point3D p = points[0]; - setCoords(p.x, p.y, p.z); - for (int i = 1; i < points.length; i++) { - Point3D pt = points[i]; - mergeNE(pt.x, pt.y, pt.z); - } - } +public final class Envelope3D implements Serializable{ + private static final long serialVersionUID = 1L; + + public double xmin; + + public double ymin; + + public double zmin; + + public double xmax; + + public double ymax; + + public double zmax; + + public static Envelope3D construct(double _xmin, double _ymin, + double _zmin, double _xmax, double _ymax, double _zmax) { + Envelope3D env = new Envelope3D(_xmin, _ymin, _zmin, _xmax, _ymax, _zmax); + return env; + } + + public Envelope3D(double _xmin, double _ymin, double _zmin, double _xmax, double _ymax, double _zmax) { + setCoords(_xmin, _ymin, _zmin, _xmax, _ymax, _zmax); + } + + public Envelope3D() { + + } + + public Envelope3D(Envelope3D other) { + setCoords(other); + } + + + public void setInfinite() { + xmin = NumberUtils.negativeInf(); + xmax = NumberUtils.positiveInf(); + ymin = NumberUtils.negativeInf(); + ymax = NumberUtils.positiveInf(); + zmin = NumberUtils.negativeInf(); + zmax = NumberUtils.positiveInf(); + } + + public void setEmpty() { + xmin = NumberUtils.NaN(); + ymin = NumberUtils.NaN(); + zmin = NumberUtils.NaN(); + xmax = 0; + ymax = 0; + zmax = 0; + } + + public boolean isEmpty() { + return NumberUtils.isNaN(xmin); + } + + public void setEmptyZ() { + zmin = NumberUtils.NaN(); + } + + public boolean isEmptyZ() { + return NumberUtils.isNaN(zmin); + } + + public boolean hasEmptyDimension() { + return isEmpty() || isEmptyZ(); + } + + public void setCoords(double _xmin, double _ymin, double _zmin, + double _xmax, double _ymax, double _zmax) { + xmin = _xmin; + ymin = _ymin; + zmin = _zmin; + xmax = _xmax; + ymax = _ymax; + zmax = _zmax; + normalize(); + } + + public void setCoords(double _x, double _y, double _z) { + xmin = _x; + ymin = _y; + zmin = _z; + xmax = _x; + ymax = _y; + zmax = _z; + } + + public void setCoords(Point3D center, double width, double height, + double depth) { + xmin = center.x - width * 0.5; + xmax = xmin + width; + ymin = center.y - height * 0.5; + ymax = ymin + height; + zmin = center.z - depth * 0.5; + zmax = zmin + depth; + normalize(); + } + + public void setCoords(Envelope3D envSrc) { + + setCoords(envSrc.xmin, envSrc.ymin, envSrc.zmin, envSrc.xmax, envSrc.ymax, envSrc.zmax); + } + + public double getWidth() { + return xmax - xmin; + } + + public double getHeight() { + return ymax - ymin; + } + + public double getDepth() { + return zmax - zmin; + } + + public void move(Point3D vector) { + xmin += vector.x; + ymin += vector.y; + zmin += vector.z; + xmax += vector.x; + ymax += vector.y; + zmax += vector.z; + } + + public void normalize() { + if (isEmpty()) + return; + + double min = Math.min(xmin, xmax); + double max = Math.max(xmin, xmax); + xmin = min; + xmax = max; + min = Math.min(ymin, ymax); + max = Math.max(ymin, ymax); + ymin = min; + ymax = max; + min = Math.min(zmin, zmax); + max = Math.max(zmin, zmax); + zmin = min; + zmax = max; + } + + public void copyTo(Envelope2D env) { + env.xmin = xmin; + env.ymin = ymin; + env.xmax = xmax; + env.ymax = ymax; + } + + public void mergeNE(double x, double y, double z) { + if (xmin > x) + xmin = x; + else if (xmax < x) + xmax = x; + + if (ymin > y) + ymin = y; + else if (ymax < y) + ymax = y; + + if (zmin != NumberUtils.NaN()) { + if (zmin > z) + zmin = z; + else if (zmax < z) + zmax = z; + } else { + zmin = z; + zmax = z; + } + } + + public void merge(double x, double y, double z) { + if (isEmpty()) { + xmin = x; + ymin = y; + zmin = z; + xmax = x; + ymax = y; + zmax = z; + } else { + mergeNE(x, y, z); + } + } + + public void merge(Point3D pt) { + merge(pt.x, pt.y, pt.z); + } + + public void merge(Envelope3D other) { + if (other.isEmpty()) + return; + + merge(other.xmin, other.ymin, other.zmin); + merge(other.xmax, other.ymax, other.zmax); + } + + public void merge(double x1, double y1, double z1, double x2, double y2, + double z2) { + merge(x1, y1, z1); + merge(x2, y2, z2); + } + + public void inflate(double dx, double dy, double dz) { + if (isEmpty()) + return; + xmin -= dx; + xmax += dx; + ymin -= dy; + ymax += dy; + zmin -= dz; + zmax += dz; + if (xmin > xmax || ymin > ymax || zmin > zmax) + setEmpty(); + } + + /** + * Checks if this envelope intersects the other. + * + * @return True if this envelope intersects the other. + */ + public boolean isIntersecting(Envelope3D other) { + return !isEmpty() && !other.isEmpty() && ((xmin <= other.xmin) ? xmax >= other.xmin : other.xmax >= xmin) && // check that x projections overlap + ((ymin <= other.ymin) ? ymax >= other.ymin : other.ymax >= ymin) && // check that y projections overlap + ((zmin <= other.zmin) ? zmax >= other.zmin : other.zmax >= zmin); // check that z projections overlap + } + + /** + * Intersects this envelope with the other and stores result in this + * envelope. + * + * @return True if this envelope intersects the other, otherwise sets this + * envelope to empty state and returns False. + */ + public boolean intersect(Envelope3D other) { + if (isEmpty() || other.isEmpty()) + return false; + + if (other.xmin > xmin) + xmin = other.xmin; + + if (other.xmax < xmax) + xmax = other.xmax; + + if (other.ymin > ymin) + ymin = other.ymin; + + if (other.ymax < ymax) + ymax = other.ymax; + + if (other.zmin > zmin) + zmin = other.zmin; + + if (other.zmax < zmax) + zmax = other.zmax; + + boolean bIntersecting = xmin <= xmax && ymin <= ymax && zmin <= zmax; + + if (!bIntersecting) + setEmpty(); + + return bIntersecting; + } + + /** + * Returns True if the envelope contains the other envelope (boundary + * inclusive). + */ + public boolean contains(Envelope3D other) {// Note: Will return False, if either envelope is empty. + return other.xmin >= xmin && other.xmax <= xmax && other.ymin >= ymin && other.ymax <= ymax && other.zmin >= zmin && other.zmax <= zmax; + } + + @Override + public boolean equals(Object _other) { + if (_other == this) + return true; + + if (!(_other instanceof Envelope3D)) + return false; + + Envelope3D other = (Envelope3D) _other; + if (isEmpty() && other.isEmpty()) + return true; + + if (xmin != other.xmin || ymin != other.ymin || zmin != other.zmin || xmax != other.xmax || ymax != other.ymax || zmax != other.zmax) + return false; + + return true; + } + + + @Override + public int hashCode() { + if (isEmpty()) { + return NumberUtils.hash(NumberUtils.TheNaN); + } + + int hash = NumberUtils.hash(xmin); + hash = NumberUtils.hash(hash, xmax); + hash = NumberUtils.hash(hash, ymin); + hash = NumberUtils.hash(hash, ymax); + hash = NumberUtils.hash(hash, zmin); + hash = NumberUtils.hash(hash, zmax); + return hash; + } + + public void construct(Envelope1D xinterval, Envelope1D yinterval, + Envelope1D zinterval) { + if (xinterval.isEmpty() || yinterval.isEmpty()) { + setEmpty(); + return; + } + + xmin = xinterval.vmin; + xmax = xinterval.vmax; + ymin = yinterval.vmin; + ymax = yinterval.vmax; + zmin = zinterval.vmin; + zmax = zinterval.vmax; + } + + public void queryCorners(Point3D[] corners) { + if ((corners == null) || (corners.length < 8)) + throw new IllegalArgumentException(); + + corners[0] = new Point3D(xmin, ymin, zmin); + corners[1] = new Point3D(xmin, ymax, zmin); + corners[2] = new Point3D(xmax, ymax, zmin); + corners[3] = new Point3D(xmax, ymin, zmin); + corners[4] = new Point3D(xmin, ymin, zmax); + corners[5] = new Point3D(xmin, ymax, zmax); + corners[6] = new Point3D(xmax, ymax, zmax); + corners[7] = new Point3D(xmax, ymin, zmax); + + } + + public void setFromPoints(Point3D[] points) { + if (points == null || points.length == 0) { + setEmpty(); + return; + } + + Point3D p = points[0]; + setCoords(p.x, p.y, p.z); + for (int i = 1; i < points.length; i++) { + Point3D pt = points[i]; + mergeNE(pt.x, pt.y, pt.z); + } + } } diff --git a/src/main/java/com/esri/core/geometry/GeneralizeComparator.java b/src/main/java/com/esri/core/geometry/GeneralizeComparator.java index 6cf7e771..71b374d1 100644 --- a/src/main/java/com/esri/core/geometry/GeneralizeComparator.java +++ b/src/main/java/com/esri/core/geometry/GeneralizeComparator.java @@ -6,218 +6,218 @@ * Created by davidraleigh on 4/19/16. */ class GeneralizeComparator extends Treap.Comparator { - class EditShapeTriangle { - int m_prevVertexIndex; - int m_nextVertexIndex; - int m_vertexIndex; + class EditShapeTriangle { + int m_prevVertexIndex; + int m_nextVertexIndex; + int m_vertexIndex; - private Point2D m_point; - private Point2D m_prevPoint; - private Point2D m_nextPoint; - private double m_area; - private int m_orientation; + private Point2D m_point; + private Point2D m_prevPoint; + private Point2D m_nextPoint; + private double m_area; + private int m_orientation; - EditShapeTriangle() { + EditShapeTriangle() { - } + } - EditShapeTriangle(EditShape editShape, int iVertex) { - setTriangle(editShape, iVertex); - } + EditShapeTriangle(EditShape editShape, int iVertex) { + setTriangle(editShape, iVertex); + } - void setTriangle(EditShape editShape, int iVertex) { - int prevVertex = editShape.getPrevVertex(iVertex); - int nextVertex = editShape.getNextVertex(iVertex); - Point2D prevPoint = editShape.getXY(prevVertex); - Point2D currentPoint = editShape.getXY(iVertex); - Point2D nextPoint = editShape.getXY(nextVertex); + void setTriangle(EditShape editShape, int iVertex) { + int prevVertex = editShape.getPrevVertex(iVertex); + int nextVertex = editShape.getNextVertex(iVertex); + Point2D prevPoint = editShape.getXY(prevVertex); + Point2D currentPoint = editShape.getXY(iVertex); + Point2D nextPoint = editShape.getXY(nextVertex); - m_point = currentPoint; - m_prevPoint = prevPoint; - m_nextPoint = nextPoint; - m_vertexIndex = iVertex; - m_prevVertexIndex = prevVertex; - m_nextVertexIndex = nextVertex; - updateArea(); - updateOrientation(); - } - - - int getIndex() { - return m_vertexIndex; - } - - - double queryArea() { - return m_area; - } - - - int queryOrientation() { - return m_orientation; - } - - - void updateArea() { - m_area = m_prevPoint.calculateTriangleArea2D(m_point, m_nextPoint); - } - - - void updateOrientation() { - m_orientation = Point2D.orientationRobust(m_prevPoint, m_point, m_nextPoint); - } - } - - EditShape m_editShape; - int m_vertex_1 = -1; - int m_vertex_2 = -1; - int m_modulus_distribution = 0; - int m_subDivisions = 8; - GeneralizeType m_generalizeType; - - EditShapeTriangle m_temp_triangle_1 = null; - EditShapeTriangle m_temp_triangle_2 = null; - - ArrayList m_triangle_nodes_buffer; - ArrayList m_triangle_nodes_recycle; - ArrayList m_triangle_nodes_cache; - - GeneralizeComparator(EditShape editShape, GeneralizeType generalizeType) { - super(true); - m_editShape = editShape; - - m_generalizeType = generalizeType; - - m_triangle_nodes_buffer = new ArrayList(); - m_triangle_nodes_recycle = new ArrayList(); - m_triangle_nodes_cache = new ArrayList(); - - m_temp_triangle_1 = new EditShapeTriangle(); - m_temp_triangle_2 = new EditShapeTriangle(); - - m_modulus_distribution = 0; - - int s = Math.min(editShape.getTotalPointCount() * 3 / 2, (int) (67 /* SIMPLEDGE_CACHESIZE */)); - int cache_size = Math.min((int) 7, s); - - // TODO is this necessary or would a reserve call work? - for (int i = 0; i < cache_size; i++) { - m_triangle_nodes_cache.add(null); - } - } - - EditShapeTriangle createTriangle(int value) { - EditShapeTriangle triangle = new EditShapeTriangle(m_editShape, value); - return triangle; - } - - // Returns a cached edge for the given value. May return NULL. - EditShapeTriangle tryGetCachedTriangle_(int value) { - int ind = (value & NumberUtils.intMax()) % m_triangle_nodes_cache.size(); - EditShapeTriangle triangle = m_triangle_nodes_cache.get(ind); - if (triangle != null) { - if (triangle.m_vertexIndex == value) - return triangle; - else { - // int i = 0; - // cache collision - } - } - return null; - } - - // Removes cached edge from the cache for the given value. - void tryDeleteCachedTriangle_(int value) { - int ind = (value & NumberUtils.intMax()) % m_triangle_nodes_cache.size(); - EditShapeTriangle se = m_triangle_nodes_cache.get(ind); - if (se != null && se.m_vertexIndex == value) {// this value is cached - m_triangle_nodes_recycle.add(se); - m_triangle_nodes_cache.set(ind, null); - } else { - // The value has not been cached - } - } - - EditShapeTriangle tryCreateCachedTriangle_(int value) { - int ind = (value & NumberUtils.intMax()) % m_triangle_nodes_cache.size(); - EditShapeTriangle triangle = m_triangle_nodes_cache.get(ind); - if (triangle == null) { - if (m_triangle_nodes_recycle.isEmpty()) { - m_triangle_nodes_buffer.add(new EditShapeTriangle(m_editShape, value)); - triangle = m_triangle_nodes_buffer.get(m_triangle_nodes_buffer.size() - 1); - } else { - triangle = m_triangle_nodes_recycle.get(m_triangle_nodes_recycle.size() - 1); - m_triangle_nodes_recycle.remove(m_triangle_nodes_recycle.size() - 1); - triangle.setTriangle(m_editShape, value); - } - - m_triangle_nodes_cache.set(ind, triangle); - return triangle; - } else { - assert (triangle.getIndex() != value); - } - - return null; - } - - void setPathCount(int pathCount) { - if (pathCount < m_subDivisions * 2) - m_modulus_distribution = pathCount / 2; - else - m_modulus_distribution = pathCount / m_subDivisions; - if (m_modulus_distribution == 5) - m_modulus_distribution *= 2; - } - - @Override - public int compare(Treap treap, int left, int node) { - int right = treap.getElement(node); - - return compareTriangles(left, left, right, right); - } - - int compareTriangles(int leftElm, int left_vertex, int right_elm, int right_vertex) { - EditShapeTriangle triangleLeft = tryGetCachedTriangle_(leftElm); - if (triangleLeft == null) { - if (m_vertex_1 == left_vertex) { - triangleLeft = m_temp_triangle_1; - } else { - m_vertex_1 = left_vertex; - triangleLeft = tryCreateCachedTriangle_(leftElm); - if (triangleLeft == null) { - triangleLeft = m_temp_triangle_1; - m_temp_triangle_1.setTriangle(m_editShape, leftElm); - } - - } - } else { - m_vertex_1 = left_vertex; - } - - EditShapeTriangle triangleRight = tryGetCachedTriangle_(right_elm); - if (triangleRight == null) { - if (m_vertex_2 == right_vertex) { - triangleRight = m_temp_triangle_2; - } else { - m_vertex_2 = right_vertex; - triangleRight = tryCreateCachedTriangle_(right_elm); - if (triangleRight == null) { - triangleRight = m_temp_triangle_2; - m_temp_triangle_2.setTriangle(m_editShape, right_elm); - } - } - } else { - m_vertex_2 = right_vertex; - } - - return compare(triangleLeft, triangleRight); - } - - @Override - void onDelete(int elm) { + m_point = currentPoint; + m_prevPoint = prevPoint; + m_nextPoint = nextPoint; + m_vertexIndex = iVertex; + m_prevVertexIndex = prevVertex; + m_nextVertexIndex = nextVertex; + updateArea(); + updateOrientation(); + } + + + int getIndex() { + return m_vertexIndex; + } + + + double queryArea() { + return m_area; + } + + + int queryOrientation() { + return m_orientation; + } + + + void updateArea() { + m_area = m_prevPoint.calculateTriangleArea2D(m_point, m_nextPoint); + } + + + void updateOrientation() { + m_orientation = Point2D.orientationRobust(m_prevPoint, m_point, m_nextPoint); + } + } + + EditShape m_editShape; + int m_vertex_1 = -1; + int m_vertex_2 = -1; + int m_modulus_distribution = 0; + int m_subDivisions = 8; + GeneralizeType m_generalizeType; + + EditShapeTriangle m_temp_triangle_1 = null; + EditShapeTriangle m_temp_triangle_2 = null; + + ArrayList m_triangle_nodes_buffer; + ArrayList m_triangle_nodes_recycle; + ArrayList m_triangle_nodes_cache; + + GeneralizeComparator(EditShape editShape, GeneralizeType generalizeType) { + super(true); + m_editShape = editShape; + + m_generalizeType = generalizeType; + + m_triangle_nodes_buffer = new ArrayList(); + m_triangle_nodes_recycle = new ArrayList(); + m_triangle_nodes_cache = new ArrayList(); + + m_temp_triangle_1 = new EditShapeTriangle(); + m_temp_triangle_2 = new EditShapeTriangle(); + + m_modulus_distribution = 0; + + int s = Math.min(editShape.getTotalPointCount() * 3 / 2, (int) (67 /* SIMPLEDGE_CACHESIZE */)); + int cache_size = Math.min((int) 7, s); + + // TODO is this necessary or would a reserve call work? + for (int i = 0; i < cache_size; i++) { + m_triangle_nodes_cache.add(null); + } + } + + EditShapeTriangle createTriangle(int value) { + EditShapeTriangle triangle = new EditShapeTriangle(m_editShape, value); + return triangle; + } + + // Returns a cached edge for the given value. May return NULL. + EditShapeTriangle tryGetCachedTriangle_(int value) { + int ind = (value & NumberUtils.intMax()) % m_triangle_nodes_cache.size(); + EditShapeTriangle triangle = m_triangle_nodes_cache.get(ind); + if (triangle != null) { + if (triangle.m_vertexIndex == value) + return triangle; + else { + // int i = 0; + // cache collision + } + } + return null; + } + + // Removes cached edge from the cache for the given value. + void tryDeleteCachedTriangle_(int value) { + int ind = (value & NumberUtils.intMax()) % m_triangle_nodes_cache.size(); + EditShapeTriangle se = m_triangle_nodes_cache.get(ind); + if (se != null && se.m_vertexIndex == value) {// this value is cached + m_triangle_nodes_recycle.add(se); + m_triangle_nodes_cache.set(ind, null); + } else { + // The value has not been cached + } + } + + EditShapeTriangle tryCreateCachedTriangle_(int value) { + int ind = (value & NumberUtils.intMax()) % m_triangle_nodes_cache.size(); + EditShapeTriangle triangle = m_triangle_nodes_cache.get(ind); + if (triangle == null) { + if (m_triangle_nodes_recycle.isEmpty()) { + m_triangle_nodes_buffer.add(new EditShapeTriangle(m_editShape, value)); + triangle = m_triangle_nodes_buffer.get(m_triangle_nodes_buffer.size() - 1); + } else { + triangle = m_triangle_nodes_recycle.get(m_triangle_nodes_recycle.size() - 1); + m_triangle_nodes_recycle.remove(m_triangle_nodes_recycle.size() - 1); + triangle.setTriangle(m_editShape, value); + } + + m_triangle_nodes_cache.set(ind, triangle); + return triangle; + } else { + assert (triangle.getIndex() != value); + } + + return null; + } + + void setPathCount(int pathCount) { + if (pathCount < m_subDivisions * 2) + m_modulus_distribution = pathCount / 2; + else + m_modulus_distribution = pathCount / m_subDivisions; + if (m_modulus_distribution == 5) + m_modulus_distribution *= 2; + } + + @Override + public int compare(Treap treap, int left, int node) { + int right = treap.getElement(node); + + return compareTriangles(left, left, right, right); + } + + int compareTriangles(int leftElm, int left_vertex, int right_elm, int right_vertex) { + EditShapeTriangle triangleLeft = tryGetCachedTriangle_(leftElm); + if (triangleLeft == null) { + if (m_vertex_1 == left_vertex) { + triangleLeft = m_temp_triangle_1; + } else { + m_vertex_1 = left_vertex; + triangleLeft = tryCreateCachedTriangle_(leftElm); + if (triangleLeft == null) { + triangleLeft = m_temp_triangle_1; + m_temp_triangle_1.setTriangle(m_editShape, leftElm); + } + + } + } else { + m_vertex_1 = left_vertex; + } + + EditShapeTriangle triangleRight = tryGetCachedTriangle_(right_elm); + if (triangleRight == null) { + if (m_vertex_2 == right_vertex) { + triangleRight = m_temp_triangle_2; + } else { + m_vertex_2 = right_vertex; + triangleRight = tryCreateCachedTriangle_(right_elm); + if (triangleRight == null) { + triangleRight = m_temp_triangle_2; + m_temp_triangle_2.setTriangle(m_editShape, right_elm); + } + } + } else { + m_vertex_2 = right_vertex; + } + + return compare(triangleLeft, triangleRight); + } + + @Override + void onDelete(int elm) { //// EditShapeTriangle triangle = tryGetCachedTriangle_(elm); //// if (triangle == null) { //// triangle = tryCreateCachedTriangle_(elm); @@ -226,7 +226,7 @@ void onDelete(int elm) { //// int prevVertexIndex = triangle.m_prevVertexIndex; //// int nextVertexIndex = triangle.m_nextVertexIndex; - tryDeleteCachedTriangle_(elm); + tryDeleteCachedTriangle_(elm); //// EditShapeTriangle trianglePrev = tryGetCachedTriangle_(prevVertexIndex); //// if (trianglePrev == null) { @@ -236,7 +236,7 @@ void onDelete(int elm) { //// if (triangleNext == null) { //// triangleNext = tryCreateCachedTriangle_(nextVertexIndex); //// } - } + } // // @Override // void onSet(int oldelm) { @@ -253,74 +253,74 @@ void onDelete(int elm) { // tryDeleteCachedTriangle_(elm); // } - int compare(EditShapeTriangle tri1, EditShapeTriangle tri2) { - - if (m_generalizeType != GeneralizeType.Neither) { - // 1 for obtuse angle counter-clockwise, - // -1 for obtuse angle clockwise - // 0 for collinear - int orientation1 = tri1.queryOrientation(); - int orientation2 = tri2.queryOrientation(); - - if (m_generalizeType == GeneralizeType.ResultContainsOriginal) { - // if the result contains the original no vertices with a - // counter clockwise obtuse angle rotation (1) can be removed - if (orientation1 < 0 && orientation2 > 0) { - return 1; - } else if (orientation2 < 0 && orientation1 > 0) { - return -1; - } else if (orientation1 > 0 && orientation2 > 0) { - // Treap requires a unique definition of the positions in the case - // of deletions. no 0 returns allowed - - // for cases where there is a really even distribution of points this seperates the group - if (tri1.m_vertexIndex % m_modulus_distribution > tri1.m_vertexIndex % m_modulus_distribution) - return -1; - else if (tri1.m_vertexIndex % m_modulus_distribution < tri1.m_vertexIndex % m_modulus_distribution) - return 1; - else if (tri1.m_vertexIndex > tri2.m_vertexIndex) - return -1; - else if (tri1.m_vertexIndex < tri2.m_vertexIndex) - return 1; - return 0; - } - } else if (m_generalizeType == GeneralizeType.ResultWithinOriginal) { - if (orientation1 < 0 && orientation2 > 0) { - return -1; - } else if (orientation2 < 0 && orientation1 > 0) { - return 1; - } else if (orientation1 < 0 && orientation2 < 0) { - if (tri1.m_vertexIndex % m_modulus_distribution > tri1.m_vertexIndex % m_modulus_distribution) - return -1; - else if (tri1.m_vertexIndex % m_modulus_distribution < tri1.m_vertexIndex % m_modulus_distribution) - return 1; - else if (tri1.m_vertexIndex > tri2.m_vertexIndex) - return -1; - else if (tri1.m_vertexIndex < tri2.m_vertexIndex) - return 1; - return 0; - } - } - } - - // else if GeneralizeType.Neither - double area1 = tri1.queryArea(); - double area2 = tri2.queryArea(); - - if (area1 < area2) { - return -1; - } else if (area2 < area1) { - return 1; - } else if (tri1.m_vertexIndex % m_modulus_distribution > tri1.m_vertexIndex % m_modulus_distribution) - return -1; - else if (tri1.m_vertexIndex % m_modulus_distribution < tri1.m_vertexIndex % m_modulus_distribution) - return 1; - else if (tri1.m_vertexIndex > tri2.m_vertexIndex) { - return -1; - } else if (tri1.m_vertexIndex < tri2.m_vertexIndex) { - return 1; - } - - return 0; - } + int compare(EditShapeTriangle tri1, EditShapeTriangle tri2) { + + if (m_generalizeType != GeneralizeType.Neither) { + // 1 for obtuse angle counter-clockwise, + // -1 for obtuse angle clockwise + // 0 for collinear + int orientation1 = tri1.queryOrientation(); + int orientation2 = tri2.queryOrientation(); + + if (m_generalizeType == GeneralizeType.ResultContainsOriginal) { + // if the result contains the original no vertices with a + // counter clockwise obtuse angle rotation (1) can be removed + if (orientation1 < 0 && orientation2 > 0) { + return 1; + } else if (orientation2 < 0 && orientation1 > 0) { + return -1; + } else if (orientation1 > 0 && orientation2 > 0) { + // Treap requires a unique definition of the positions in the case + // of deletions. no 0 returns allowed + + // for cases where there is a really even distribution of points this seperates the group + if (tri1.m_vertexIndex % m_modulus_distribution > tri1.m_vertexIndex % m_modulus_distribution) + return -1; + else if (tri1.m_vertexIndex % m_modulus_distribution < tri1.m_vertexIndex % m_modulus_distribution) + return 1; + else if (tri1.m_vertexIndex > tri2.m_vertexIndex) + return -1; + else if (tri1.m_vertexIndex < tri2.m_vertexIndex) + return 1; + return 0; + } + } else if (m_generalizeType == GeneralizeType.ResultWithinOriginal) { + if (orientation1 < 0 && orientation2 > 0) { + return -1; + } else if (orientation2 < 0 && orientation1 > 0) { + return 1; + } else if (orientation1 < 0 && orientation2 < 0) { + if (tri1.m_vertexIndex % m_modulus_distribution > tri1.m_vertexIndex % m_modulus_distribution) + return -1; + else if (tri1.m_vertexIndex % m_modulus_distribution < tri1.m_vertexIndex % m_modulus_distribution) + return 1; + else if (tri1.m_vertexIndex > tri2.m_vertexIndex) + return -1; + else if (tri1.m_vertexIndex < tri2.m_vertexIndex) + return 1; + return 0; + } + } + } + + // else if GeneralizeType.Neither + double area1 = tri1.queryArea(); + double area2 = tri2.queryArea(); + + if (area1 < area2) { + return -1; + } else if (area2 < area1) { + return 1; + } else if (tri1.m_vertexIndex % m_modulus_distribution > tri1.m_vertexIndex % m_modulus_distribution) + return -1; + else if (tri1.m_vertexIndex % m_modulus_distribution < tri1.m_vertexIndex % m_modulus_distribution) + return 1; + else if (tri1.m_vertexIndex > tri2.m_vertexIndex) { + return -1; + } else if (tri1.m_vertexIndex < tri2.m_vertexIndex) { + return 1; + } + + return 0; + } } \ No newline at end of file diff --git a/src/main/java/com/esri/core/geometry/GeneralizeType.java b/src/main/java/com/esri/core/geometry/GeneralizeType.java index 92e5beb0..fab10743 100644 --- a/src/main/java/com/esri/core/geometry/GeneralizeType.java +++ b/src/main/java/com/esri/core/geometry/GeneralizeType.java @@ -4,7 +4,7 @@ * Created by davidraleigh on 4/17/16. */ public enum GeneralizeType { - ResultContainsOriginal, - ResultWithinOriginal, - Neither + ResultContainsOriginal, + ResultWithinOriginal, + Neither } diff --git a/src/main/java/com/esri/core/geometry/GenericGeometrySerializer.java b/src/main/java/com/esri/core/geometry/GenericGeometrySerializer.java index aa69e572..a276ccdd 100644 --- a/src/main/java/com/esri/core/geometry/GenericGeometrySerializer.java +++ b/src/main/java/com/esri/core/geometry/GenericGeometrySerializer.java @@ -29,66 +29,66 @@ //This is a writeReplace class for MultiPoint, Polyline, and Polygon public class GenericGeometrySerializer implements Serializable { - private static final long serialVersionUID = 1L; - int geometryType; - byte[] esriShape = null; - int simpleFlag = 0; - double tolerance = 0; - boolean[] ogcFlags = null; + private static final long serialVersionUID = 1L; + int geometryType; + byte[] esriShape = null; + int simpleFlag = 0; + double tolerance = 0; + boolean[] ogcFlags = null; - public Object readResolve() throws ObjectStreamException { - Geometry geometry = null; - try { - geometry = GeometryEngine.geometryFromEsriShape( - esriShape, Geometry.Type.intToType(geometryType)); + public Object readResolve() throws ObjectStreamException { + Geometry geometry = null; + try { + geometry = GeometryEngine.geometryFromEsriShape( + esriShape, Geometry.Type.intToType(geometryType)); - if (Geometry.isMultiVertex(geometryType)) { - MultiVertexGeometryImpl mvImpl = (MultiVertexGeometryImpl) geometry - ._getImpl(); - if (!geometry.isEmpty() - && Geometry.isMultiPath(geometryType)) { - MultiPathImpl mpImpl = (MultiPathImpl) geometry._getImpl(); - AttributeStreamOfInt8 pathFlags = mpImpl - .getPathFlagsStreamRef(); - for (int i = 0, n = mpImpl.getPathCount(); i < n; i++) { - if (ogcFlags[i]) - pathFlags.setBits(i, - (byte) PathFlags.enumOGCStartPolygon); - } - } - mvImpl.setIsSimple(simpleFlag, tolerance, false); - } - } catch (Exception ex) { - throw new InvalidObjectException("Cannot read geometry from stream"); - } - return geometry; - } + if (Geometry.isMultiVertex(geometryType)) { + MultiVertexGeometryImpl mvImpl = (MultiVertexGeometryImpl) geometry + ._getImpl(); + if (!geometry.isEmpty() + && Geometry.isMultiPath(geometryType)) { + MultiPathImpl mpImpl = (MultiPathImpl) geometry._getImpl(); + AttributeStreamOfInt8 pathFlags = mpImpl + .getPathFlagsStreamRef(); + for (int i = 0, n = mpImpl.getPathCount(); i < n; i++) { + if (ogcFlags[i]) + pathFlags.setBits(i, + (byte) PathFlags.enumOGCStartPolygon); + } + } + mvImpl.setIsSimple(simpleFlag, tolerance, false); + } + } catch (Exception ex) { + throw new InvalidObjectException("Cannot read geometry from stream"); + } + return geometry; + } - public void setGeometryByValue(Geometry geometry) - throws ObjectStreamException { - try { - esriShape = GeometryEngine - .geometryToEsriShape(geometry); - geometryType = geometry.getType().value(); - if (Geometry.isMultiVertex(geometryType)) { - MultiVertexGeometryImpl mvImpl = (MultiVertexGeometryImpl) geometry - ._getImpl(); - tolerance = mvImpl.m_simpleTolerance; - simpleFlag = mvImpl.getIsSimple(0); - if (!geometry.isEmpty() - && Geometry.isMultiPath(geometryType)) { - MultiPathImpl mpImpl = (MultiPathImpl) geometry._getImpl(); - ogcFlags = new boolean[mpImpl.getPathCount()]; - AttributeStreamOfInt8 pathFlags = mpImpl - .getPathFlagsStreamRef(); - for (int i = 0, n = mpImpl.getPathCount(); i < n; i++) { - ogcFlags[i] = (pathFlags.read(i) & (byte) PathFlags.enumOGCStartPolygon) != 0; - } - } + public void setGeometryByValue(Geometry geometry) + throws ObjectStreamException { + try { + esriShape = GeometryEngine + .geometryToEsriShape(geometry); + geometryType = geometry.getType().value(); + if (Geometry.isMultiVertex(geometryType)) { + MultiVertexGeometryImpl mvImpl = (MultiVertexGeometryImpl) geometry + ._getImpl(); + tolerance = mvImpl.m_simpleTolerance; + simpleFlag = mvImpl.getIsSimple(0); + if (!geometry.isEmpty() + && Geometry.isMultiPath(geometryType)) { + MultiPathImpl mpImpl = (MultiPathImpl) geometry._getImpl(); + ogcFlags = new boolean[mpImpl.getPathCount()]; + AttributeStreamOfInt8 pathFlags = mpImpl + .getPathFlagsStreamRef(); + for (int i = 0, n = mpImpl.getPathCount(); i < n; i++) { + ogcFlags[i] = (pathFlags.read(i) & (byte) PathFlags.enumOGCStartPolygon) != 0; + } + } - } - } catch (Exception ex) { - throw new InvalidObjectException("Cannot serialize this geometry"); - } - } + } + } catch (Exception ex) { + throw new InvalidObjectException("Cannot serialize this geometry"); + } + } } diff --git a/src/main/java/com/esri/core/geometry/GeoDist.java b/src/main/java/com/esri/core/geometry/GeoDist.java index 0d9b54c3..e75e12f5 100644 --- a/src/main/java/com/esri/core/geometry/GeoDist.java +++ b/src/main/java/com/esri/core/geometry/GeoDist.java @@ -25,60 +25,60 @@ package com.esri.core.geometry; final class GeoDist { - private static final double PE_PI = 3.14159265358979323846264; - private static final double PE_PI2 = 1.57079632679489661923132; - private static final double PE_2PI = 6.283185307179586476925287; - private static final double PE_EPS = 3.55271367880050092935562e-15; - private static final double RAD_TO_DEG = 180.0 / PE_PI; - private static final double DEG_TO_RAD = PE_PI / 180.0; - - /** - * Get the absolute value of a number - */ - static private double PE_ABS(double a) { - return (a < 0) ? -a : a; - } - - /** - * Assign the sign of the second number to the first - */ - static private double PE_SGN(double a, double b) { - return (b >= 0) ? PE_ABS(a) : -PE_ABS(a); - } - - /** - * Determine if two doubles are equal within a default tolerance - */ - static private boolean PE_EQ(double a, double b) { - return (a == b) - || PE_ABS(a - b) <= PE_EPS * (1 + (PE_ABS(a) + PE_ABS(b)) / 2); - } - - /** - * Determine if a double is within a given tolerance of zero - */ - static private boolean PE_ZERO(double a) { - return (a == 0.0) || (PE_ABS(a) <= PE_EPS); - } - - static private double lam_delta(double lam) { - double d = Math.IEEEremainder(lam, PE_2PI); - - return (PE_ABS(d) <= PE_PI) ? d : ((d < 0) ? d + PE_2PI : d - PE_2PI); - } - - static private void lam_phi_reduction(PeDouble p_lam, PeDouble p_phi) { - p_lam.val = lam_delta(p_lam.val); - p_phi.val = lam_delta(p_phi.val); - - if (PE_ABS(p_phi.val) > PE_PI2) { - p_lam.val = lam_delta(p_lam.val + PE_PI); - p_phi.val = PE_SGN(PE_PI, p_phi.val) - p_phi.val; - } - } - - static private double q90(double a, double e2) { - /* + private static final double PE_PI = 3.14159265358979323846264; + private static final double PE_PI2 = 1.57079632679489661923132; + private static final double PE_2PI = 6.283185307179586476925287; + private static final double PE_EPS = 3.55271367880050092935562e-15; + private static final double RAD_TO_DEG = 180.0 / PE_PI; + private static final double DEG_TO_RAD = PE_PI / 180.0; + + /** + * Get the absolute value of a number + */ + static private double PE_ABS(double a) { + return (a < 0) ? -a : a; + } + + /** + * Assign the sign of the second number to the first + */ + static private double PE_SGN(double a, double b) { + return (b >= 0) ? PE_ABS(a) : -PE_ABS(a); + } + + /** + * Determine if two doubles are equal within a default tolerance + */ + static private boolean PE_EQ(double a, double b) { + return (a == b) + || PE_ABS(a - b) <= PE_EPS * (1 + (PE_ABS(a) + PE_ABS(b)) / 2); + } + + /** + * Determine if a double is within a given tolerance of zero + */ + static private boolean PE_ZERO(double a) { + return (a == 0.0) || (PE_ABS(a) <= PE_EPS); + } + + static private double lam_delta(double lam) { + double d = Math.IEEEremainder(lam, PE_2PI); + + return (PE_ABS(d) <= PE_PI) ? d : ((d < 0) ? d + PE_2PI : d - PE_2PI); + } + + static private void lam_phi_reduction(PeDouble p_lam, PeDouble p_phi) { + p_lam.val = lam_delta(p_lam.val); + p_phi.val = lam_delta(p_phi.val); + + if (PE_ABS(p_phi.val) > PE_PI2) { + p_lam.val = lam_delta(p_lam.val + PE_PI); + p_phi.val = PE_SGN(PE_PI, p_phi.val) - p_phi.val; + } + } + + static private double q90(double a, double e2) { + /* * Rapp // Geometric Geodesy (Part I) // p. 39. Adams, O.S. // Latitude * Developments ... // pp. 122-127. Terms extended past n4 by David * Burrows, ESRI @@ -91,325 +91,325 @@ static private double q90(double a, double e2) { * 49/65536 n10 + ...)/(1.0 + n) */ - double t = Math.sqrt(1.0 - e2); - double n = (1.0 - t) / (1.0 + t); - double n2 = n * n; - - return a / (1.0 + n) - * (1.0 + n2 * (1.0 / 4.0 + n2 * (1.0 / 64.0 + n2 * (1.0 / 256.0)))) - * PE_PI2; - } - - // This should be a method within Envelop2D - public static void inflateEnv2D( - double a, - double e2, - Envelope2D env2D, - double dxMeters, - double dyMeters) { - if (env2D.isEmpty()) - return; - - double yMinAzimuth = dyMeters > 0 ? Math.PI : 0; - double yMaxAzimuth = dyMeters > 0 ? 0 : Math.PI; - - double xMinAzimuth = dxMeters > 0 ? 3 * Math.PI / 2 : Math.PI / 2; - double xMaxAzimuth = dxMeters > 0 ? Math.PI / 2 : 3 * Math.PI / 2; - - dxMeters = Math.abs(dxMeters); - dyMeters = Math.abs(dyMeters); - - PeDouble lamMin = new PeDouble(); - PeDouble phiMin = new PeDouble(); - PeDouble lamMax = new PeDouble(); - PeDouble phiMax = new PeDouble(); - PeDouble dummyVar = new PeDouble(); - - // TODO this probably needs improvement. Maybe a check to see which hemisphere and then whether to measure the - // x values at ymin or ymax and measure the y values at the xmin or xmax - // new ymin - geodesic_forward(a, e2, env2D.xmin * DEG_TO_RAD, env2D.ymin * DEG_TO_RAD, dyMeters, yMinAzimuth, dummyVar, phiMin); - // new xmin - geodesic_forward(a, e2, env2D.xmin * DEG_TO_RAD, env2D.ymax * DEG_TO_RAD, dxMeters, xMinAzimuth, lamMin, dummyVar); - // new yMAX - geodesic_forward(a, e2, env2D.xmax * DEG_TO_RAD, env2D.ymax * DEG_TO_RAD, dyMeters, yMaxAzimuth, dummyVar, phiMax); - // new xmax - geodesic_forward(a, e2, env2D.xmax * DEG_TO_RAD, env2D.ymin * DEG_TO_RAD, dxMeters, xMaxAzimuth, lamMax, dummyVar); - - env2D.ymax = phiMax.val * RAD_TO_DEG; - env2D.xmin = lamMin.val * RAD_TO_DEG; - env2D.ymin = phiMin.val * RAD_TO_DEG; - env2D.xmax = lamMax.val * RAD_TO_DEG; - - if (env2D.xmin > env2D.xmax || env2D.ymin > env2D.ymax) - env2D.setEmpty(); - } - - /** - * Gets the max geodetic width of an envelope - * - * @param a - * @param e2 - * @param env2D - * @return - */ - public static double getEnvWidth(double a, - double e2, - Envelope2D env2D) { - double rpu = Math.PI / 180.0; - PeDouble answer = new PeDouble(); - GeoDist.geodesic_distance_ngs( - a, - e2, - env2D.xmin * rpu, - env2D.ymin * rpu, - env2D.xmax * rpu, - env2D.ymin * rpu, - answer, null, null); - double lowerWidth = answer.val; - GeoDist.geodesic_distance_ngs( - a, - e2, - env2D.xmin * rpu, - env2D.ymax * rpu, - env2D.xmax * rpu, - env2D.ymax * rpu, - answer, null, null); - if (lowerWidth > answer.val) - return lowerWidth; - return answer.val; - } - - public static double getEnvHeight(double a, - double e2, - Envelope2D env2D) { - double rpu = Math.PI / 180.0; - PeDouble answer = new PeDouble(); - GeoDist.geodesic_distance_ngs( - a, - e2, - env2D.xmin * rpu, - env2D.ymin * rpu, - env2D.xmin * rpu, - env2D.ymax * rpu, - answer, null, null); - double leftHeight = answer.val; - GeoDist.geodesic_distance_ngs( - a, - e2, - env2D.xmax * rpu, - env2D.ymin * rpu, - env2D.xmax * rpu, - env2D.ymax * rpu, - answer, null, null); - if (leftHeight > answer.val) - return leftHeight; - return answer.val; - } - - public static Point2D getEnvCenter(Geometry geometry, SpatialReference spatialReference) { - Envelope2D inputEnvelope2D = new Envelope2D(); - - if (spatialReference == null) { - throw new GeometryException("Requires spatial reference"); - } - - if (spatialReference.getID() != 4326) { - OperatorProject operatorProject = (OperatorProject) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.Project); - // TODO this should be grabbing the GCS wkid from the input spatialreference instead of assuming 4326 - ProjectionTransformation projectionTransformation = new ProjectionTransformation(spatialReference, SpatialReference.create(4326)); - Geometry projectedGeom = operatorProject.execute(geometry, projectionTransformation, null); - projectedGeom.queryEnvelope2D(inputEnvelope2D); - } else { - geometry.queryEnvelope2D(inputEnvelope2D); - } - - // From GEOGRAPHIC Grab point - double a = spatialReference.getMajorAxis(); - double e2 = spatialReference.getEccentricitySquared(); - - Point2D ptCenter = new Point2D(); - GeoDist.getEnvCenter(a, e2, inputEnvelope2D, ptCenter); - - return ptCenter; - } - - public static void getEnvCenter(double a, - double e2, - Envelope2D env2D, - Point2D geodeticCenter) { - // Get minx miny, minx maxy midpoint - Point2D lowerRightUpperLeft = new Point2D(); - GeoDist.geodesicMidpoint(a, e2, env2D.getLowerRight(), env2D.getUpperLeft(), lowerRightUpperLeft); - - - // Get maxx miny, maxx maxy midpoint - Point2D upperRightLowerLeft = new Point2D(); - GeoDist.geodesicMidpoint(a, e2, env2D.getLowerLeft(), env2D.getUpperRight(), upperRightLowerLeft); - - // Get midpoint of midpoints - GeoDist.geodesicMidpoint(a, e2, lowerRightUpperLeft, upperRightLowerLeft, geodeticCenter); - } - - static public void geodesicMidpoint(double a, double e2, Point2D fromPoint, Point2D toPoint, Point2D outMidPoint) { - // TODO calculate distance - PeDouble azFromTo = new PeDouble(); - double distance = geodesicDistance(a, e2, fromPoint, toPoint, azFromTo, null); - - // TODO calculate midpoint - geodesicForward(a, e2, fromPoint, distance / 2f, azFromTo.val, outMidPoint); - } - - static public void geodesicForward(double a, - double e2, - Point2D fromPoint, - double distance, - double azimuth, - Point2D outToPoint) { - PeDouble lam2 = new PeDouble(); - PeDouble phi2 = new PeDouble(); - GeoDist.geodesic_forward( - a, - e2, - fromPoint.x * DEG_TO_RAD, - fromPoint.y * DEG_TO_RAD, - distance, - azimuth, - lam2, - phi2); - - outToPoint.x = lam2.val * RAD_TO_DEG; - outToPoint.y = phi2.val * RAD_TO_DEG; - } - - static public double geodesicDistance(double a, - double e2, - Point2D fromPoint, - Point2D toPoint, - PeDouble azFromTo, - PeDouble azToFrom) { + double t = Math.sqrt(1.0 - e2); + double n = (1.0 - t) / (1.0 + t); + double n2 = n * n; + + return a / (1.0 + n) + * (1.0 + n2 * (1.0 / 4.0 + n2 * (1.0 / 64.0 + n2 * (1.0 / 256.0)))) + * PE_PI2; + } + + // This should be a method within Envelop2D + public static void inflateEnv2D( + double a, + double e2, + Envelope2D env2D, + double dxMeters, + double dyMeters) { + if (env2D.isEmpty()) + return; + + double yMinAzimuth = dyMeters > 0 ? Math.PI : 0; + double yMaxAzimuth = dyMeters > 0 ? 0 : Math.PI; + + double xMinAzimuth = dxMeters > 0 ? 3 * Math.PI / 2 : Math.PI / 2; + double xMaxAzimuth = dxMeters > 0 ? Math.PI / 2 : 3 * Math.PI / 2; + + dxMeters = Math.abs(dxMeters); + dyMeters = Math.abs(dyMeters); + + PeDouble lamMin = new PeDouble(); + PeDouble phiMin = new PeDouble(); + PeDouble lamMax = new PeDouble(); + PeDouble phiMax = new PeDouble(); + PeDouble dummyVar = new PeDouble(); + + // TODO this probably needs improvement. Maybe a check to see which hemisphere and then whether to measure the + // x values at ymin or ymax and measure the y values at the xmin or xmax + // new ymin + geodesic_forward(a, e2, env2D.xmin * DEG_TO_RAD, env2D.ymin * DEG_TO_RAD, dyMeters, yMinAzimuth, dummyVar, phiMin); + // new xmin + geodesic_forward(a, e2, env2D.xmin * DEG_TO_RAD, env2D.ymax * DEG_TO_RAD, dxMeters, xMinAzimuth, lamMin, dummyVar); + // new yMAX + geodesic_forward(a, e2, env2D.xmax * DEG_TO_RAD, env2D.ymax * DEG_TO_RAD, dyMeters, yMaxAzimuth, dummyVar, phiMax); + // new xmax + geodesic_forward(a, e2, env2D.xmax * DEG_TO_RAD, env2D.ymin * DEG_TO_RAD, dxMeters, xMaxAzimuth, lamMax, dummyVar); + + env2D.ymax = phiMax.val * RAD_TO_DEG; + env2D.xmin = lamMin.val * RAD_TO_DEG; + env2D.ymin = phiMin.val * RAD_TO_DEG; + env2D.xmax = lamMax.val * RAD_TO_DEG; + + if (env2D.xmin > env2D.xmax || env2D.ymin > env2D.ymax) + env2D.setEmpty(); + } + + /** + * Gets the max geodetic width of an envelope + * + * @param a + * @param e2 + * @param env2D + * @return + */ + public static double getEnvWidth(double a, + double e2, + Envelope2D env2D) { + double rpu = Math.PI / 180.0; + PeDouble answer = new PeDouble(); + GeoDist.geodesic_distance_ngs( + a, + e2, + env2D.xmin * rpu, + env2D.ymin * rpu, + env2D.xmax * rpu, + env2D.ymin * rpu, + answer, null, null); + double lowerWidth = answer.val; + GeoDist.geodesic_distance_ngs( + a, + e2, + env2D.xmin * rpu, + env2D.ymax * rpu, + env2D.xmax * rpu, + env2D.ymax * rpu, + answer, null, null); + if (lowerWidth > answer.val) + return lowerWidth; + return answer.val; + } + + public static double getEnvHeight(double a, + double e2, + Envelope2D env2D) { + double rpu = Math.PI / 180.0; + PeDouble answer = new PeDouble(); + GeoDist.geodesic_distance_ngs( + a, + e2, + env2D.xmin * rpu, + env2D.ymin * rpu, + env2D.xmin * rpu, + env2D.ymax * rpu, + answer, null, null); + double leftHeight = answer.val; + GeoDist.geodesic_distance_ngs( + a, + e2, + env2D.xmax * rpu, + env2D.ymin * rpu, + env2D.xmax * rpu, + env2D.ymax * rpu, + answer, null, null); + if (leftHeight > answer.val) + return leftHeight; + return answer.val; + } + + public static Point2D getEnvCenter(Geometry geometry, SpatialReference spatialReference) { + Envelope2D inputEnvelope2D = new Envelope2D(); + + if (spatialReference == null) { + throw new GeometryException("Requires spatial reference"); + } + + if (spatialReference.getID() != 4326) { + OperatorProject operatorProject = (OperatorProject) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.Project); + // TODO this should be grabbing the GCS wkid from the input spatialreference instead of assuming 4326 + ProjectionTransformation projectionTransformation = new ProjectionTransformation(spatialReference, SpatialReference.create(4326)); + Geometry projectedGeom = operatorProject.execute(geometry, projectionTransformation, null); + projectedGeom.queryEnvelope2D(inputEnvelope2D); + } else { + geometry.queryEnvelope2D(inputEnvelope2D); + } + + // From GEOGRAPHIC Grab point + double a = spatialReference.getMajorAxis(); + double e2 = spatialReference.getEccentricitySquared(); + + Point2D ptCenter = new Point2D(); + GeoDist.getEnvCenter(a, e2, inputEnvelope2D, ptCenter); + + return ptCenter; + } + + public static void getEnvCenter(double a, + double e2, + Envelope2D env2D, + Point2D geodeticCenter) { + // Get minx miny, minx maxy midpoint + Point2D lowerRightUpperLeft = new Point2D(); + GeoDist.geodesicMidpoint(a, e2, env2D.getLowerRight(), env2D.getUpperLeft(), lowerRightUpperLeft); + + + // Get maxx miny, maxx maxy midpoint + Point2D upperRightLowerLeft = new Point2D(); + GeoDist.geodesicMidpoint(a, e2, env2D.getLowerLeft(), env2D.getUpperRight(), upperRightLowerLeft); + + // Get midpoint of midpoints + GeoDist.geodesicMidpoint(a, e2, lowerRightUpperLeft, upperRightLowerLeft, geodeticCenter); + } + + static public void geodesicMidpoint(double a, double e2, Point2D fromPoint, Point2D toPoint, Point2D outMidPoint) { + // TODO calculate distance + PeDouble azFromTo = new PeDouble(); + double distance = geodesicDistance(a, e2, fromPoint, toPoint, azFromTo, null); + + // TODO calculate midpoint + geodesicForward(a, e2, fromPoint, distance / 2f, azFromTo.val, outMidPoint); + } + + static public void geodesicForward(double a, + double e2, + Point2D fromPoint, + double distance, + double azimuth, + Point2D outToPoint) { + PeDouble lam2 = new PeDouble(); + PeDouble phi2 = new PeDouble(); + GeoDist.geodesic_forward( + a, + e2, + fromPoint.x * DEG_TO_RAD, + fromPoint.y * DEG_TO_RAD, + distance, + azimuth, + lam2, + phi2); + + outToPoint.x = lam2.val * RAD_TO_DEG; + outToPoint.y = phi2.val * RAD_TO_DEG; + } + + static public double geodesicDistance(double a, + double e2, + Point2D fromPoint, + Point2D toPoint, + PeDouble azFromTo, + PeDouble azToFrom) { // double a = 6378137.0; // radius of spheroid for WGS_1984 // double e2 = 0.0066943799901413165; // ellipticity for WGS_1984 - PeDouble answer = new PeDouble(); - GeoDist.geodesic_distance_ngs( - a, - e2, - fromPoint.x * DEG_TO_RAD, - fromPoint.y * DEG_TO_RAD, - toPoint.x * DEG_TO_RAD, - toPoint.y * DEG_TO_RAD, - answer, - azFromTo, - azToFrom); - return answer.val; - } - - // TODO replace geodesic_distance_ngs with this and get rid of PeDouble - static public InverseResult geodesicInverse(double a, - double e2, - Point2D fromPoint, - Point2D toPoint) { - PeDouble az12 = new PeDouble(); - PeDouble az21 = new PeDouble(); - PeDouble distance = new PeDouble(); - GeoDist.geodesic_distance_ngs( - a, - e2, - fromPoint.x * DEG_TO_RAD, - fromPoint.y * DEG_TO_RAD, - toPoint.x * DEG_TO_RAD, - toPoint.y * DEG_TO_RAD, - distance, - az12, - az21); - return new InverseResult(az12.val, az21.val, distance.val); - } - - static public void geodesic_forward(double a, - double e2, - double lam1, - double phi1, - double distance, - double az12, - PeDouble lam2, - PeDouble phi2) { - // http://www.fgg.uni-lj.si/~/mkuhar/Zalozba/Rapp_Geom_Geod_%20Vol_II.pdf - // it gets messy in here. This is the vicenty direct equations from Rapp, 1993 - // calculate A and B - // calc reduced latitude, beta1: (grabbed this from geodesic_distance_ngs) - double f = 1.0 - Math.sqrt(1.0 - e2); - double boa = 1.0 - f; - double beta1 = Math.atan(boa * Math.tan(phi1)); /* better reduced latitude */ - - //TODO might be buggy - double cosBeta1 = Math.cos(beta1); - // gets used in final results - double sinBeta1 = Math.sin(beta1); - - // Alpha1 in Rapp is az12, the azimuth of the direction traveled - double sinAlpha = cosBeta1 * Math.sin(az12); - double sinAlpha2 = sinAlpha * sinAlpha; - double cosAlpha2 = 1 - sinAlpha2; - double ePrime2 = e2 / (1 - e2); - double u2 = ePrime2 * cosAlpha2; - - double A = 1 + (u2 / 16384) * (4096 + u2 * (320 - 175 * u2)); - double B = (u2 / 1024) * (256 + u2 * (74 - 47 * u2)); - - // pre cooked for while loop - double B_4th = B / 4; - double B_6th = B / 6; - - double sigma1 = Math.atan(Math.tan(beta1) / Math.cos(az12)); - - double deltaSigma = 0; - double b = a * (1 - f); - double firstApprox = distance / (b * A); - double sigma = firstApprox; - double lastSigma = Double.MIN_VALUE; - - while (!PE_EQ(sigma, lastSigma)) { - lastSigma = sigma; - double cos2sigmaM = Math.cos(2 * sigma1 + sigma); - double cos2sigmaM2 = cos2sigmaM * cos2sigmaM; - double sinSigma2 = Math.sin(sigma) * Math.sin(sigma); - double cosSigmaGroup = Math.cos(sigma) * (-1 + 2 * cos2sigmaM2); - double cos2SigmaMGroup = cos2sigmaM * (-3 + 4 * sinSigma2) * (-3 + 4 * cos2sigmaM2); - deltaSigma = B * Math.sin(sigma) * (cos2sigmaM + B_4th * cosSigmaGroup - B_6th * cos2SigmaMGroup); - sigma = firstApprox + deltaSigma; - } - - // removing repetitive trig expressions - double cosSigma = Math.cos(sigma); - double sinSigma = Math.sin(sigma); - - double lambdaNumerator = sinSigma * Math.sin(az12); - double lambdaDenominator = cosBeta1 * cosSigma - sinBeta1 * sinSigma * Math.cos(az12); - double lambda = Math.atan2(lambdaNumerator, lambdaDenominator); - double C = (f / 16) * cosAlpha2 * (4 + f * (4 - 3 * cosAlpha2)); - - // from equation 184 in Rapp - double cos2sigmaM = Math.cos(2 * sigma1 + sigma); - double cos2sigmaM2 = cos2sigmaM * cos2sigmaM; - double squareBrackets_184 = cos2sigmaM + C * cosSigma * (-1 + 2 * cos2sigmaM2); - lam2.val = lam1 + lambda - (1 - C) * f * sinAlpha * (sigma + C * sinSigma * squareBrackets_184); - - double phiNumerator = sinBeta1 * cosSigma + cosBeta1 * sinSigma * Math.cos(az12); - double messyBlock = (sinBeta1 * sinSigma - cosBeta1 * cosSigma * Math.cos(az12)); - double messyBlock2 = messyBlock * messyBlock; - double phiDenominator = (1 - f) * Math.sqrt(sinAlpha2 + messyBlock2); - phi2.val = Math.atan2(phiNumerator, phiDenominator); - } - - static public void geodesic_distance_ngs(double a, - double e2, - double lam1, - double phi1, - double lam2, - double phi2, - PeDouble p_dist, - PeDouble p_az12, - PeDouble p_az21) { + PeDouble answer = new PeDouble(); + GeoDist.geodesic_distance_ngs( + a, + e2, + fromPoint.x * DEG_TO_RAD, + fromPoint.y * DEG_TO_RAD, + toPoint.x * DEG_TO_RAD, + toPoint.y * DEG_TO_RAD, + answer, + azFromTo, + azToFrom); + return answer.val; + } + + // TODO replace geodesic_distance_ngs with this and get rid of PeDouble + static public InverseResult geodesicInverse(double a, + double e2, + Point2D fromPoint, + Point2D toPoint) { + PeDouble az12 = new PeDouble(); + PeDouble az21 = new PeDouble(); + PeDouble distance = new PeDouble(); + GeoDist.geodesic_distance_ngs( + a, + e2, + fromPoint.x * DEG_TO_RAD, + fromPoint.y * DEG_TO_RAD, + toPoint.x * DEG_TO_RAD, + toPoint.y * DEG_TO_RAD, + distance, + az12, + az21); + return new InverseResult(az12.val, az21.val, distance.val); + } + + static public void geodesic_forward(double a, + double e2, + double lam1, + double phi1, + double distance, + double az12, + PeDouble lam2, + PeDouble phi2) { + // http://www.fgg.uni-lj.si/~/mkuhar/Zalozba/Rapp_Geom_Geod_%20Vol_II.pdf + // it gets messy in here. This is the vicenty direct equations from Rapp, 1993 + // calculate A and B + // calc reduced latitude, beta1: (grabbed this from geodesic_distance_ngs) + double f = 1.0 - Math.sqrt(1.0 - e2); + double boa = 1.0 - f; + double beta1 = Math.atan(boa * Math.tan(phi1)); /* better reduced latitude */ + + //TODO might be buggy + double cosBeta1 = Math.cos(beta1); + // gets used in final results + double sinBeta1 = Math.sin(beta1); + + // Alpha1 in Rapp is az12, the azimuth of the direction traveled + double sinAlpha = cosBeta1 * Math.sin(az12); + double sinAlpha2 = sinAlpha * sinAlpha; + double cosAlpha2 = 1 - sinAlpha2; + double ePrime2 = e2 / (1 - e2); + double u2 = ePrime2 * cosAlpha2; + + double A = 1 + (u2 / 16384) * (4096 + u2 * (320 - 175 * u2)); + double B = (u2 / 1024) * (256 + u2 * (74 - 47 * u2)); + + // pre cooked for while loop + double B_4th = B / 4; + double B_6th = B / 6; + + double sigma1 = Math.atan(Math.tan(beta1) / Math.cos(az12)); + + double deltaSigma = 0; + double b = a * (1 - f); + double firstApprox = distance / (b * A); + double sigma = firstApprox; + double lastSigma = Double.MIN_VALUE; + + while (!PE_EQ(sigma, lastSigma)) { + lastSigma = sigma; + double cos2sigmaM = Math.cos(2 * sigma1 + sigma); + double cos2sigmaM2 = cos2sigmaM * cos2sigmaM; + double sinSigma2 = Math.sin(sigma) * Math.sin(sigma); + double cosSigmaGroup = Math.cos(sigma) * (-1 + 2 * cos2sigmaM2); + double cos2SigmaMGroup = cos2sigmaM * (-3 + 4 * sinSigma2) * (-3 + 4 * cos2sigmaM2); + deltaSigma = B * Math.sin(sigma) * (cos2sigmaM + B_4th * cosSigmaGroup - B_6th * cos2SigmaMGroup); + sigma = firstApprox + deltaSigma; + } + + // removing repetitive trig expressions + double cosSigma = Math.cos(sigma); + double sinSigma = Math.sin(sigma); + + double lambdaNumerator = sinSigma * Math.sin(az12); + double lambdaDenominator = cosBeta1 * cosSigma - sinBeta1 * sinSigma * Math.cos(az12); + double lambda = Math.atan2(lambdaNumerator, lambdaDenominator); + double C = (f / 16) * cosAlpha2 * (4 + f * (4 - 3 * cosAlpha2)); + + // from equation 184 in Rapp + double cos2sigmaM = Math.cos(2 * sigma1 + sigma); + double cos2sigmaM2 = cos2sigmaM * cos2sigmaM; + double squareBrackets_184 = cos2sigmaM + C * cosSigma * (-1 + 2 * cos2sigmaM2); + lam2.val = lam1 + lambda - (1 - C) * f * sinAlpha * (sigma + C * sinSigma * squareBrackets_184); + + double phiNumerator = sinBeta1 * cosSigma + cosBeta1 * sinSigma * Math.cos(az12); + double messyBlock = (sinBeta1 * sinSigma - cosBeta1 * cosSigma * Math.cos(az12)); + double messyBlock2 = messyBlock * messyBlock; + double phiDenominator = (1 - f) * Math.sqrt(sinAlpha2 + messyBlock2); + phi2.val = Math.atan2(phiNumerator, phiDenominator); + } + + static public void geodesic_distance_ngs(double a, + double e2, + double lam1, + double phi1, + double lam2, + double phi2, + PeDouble p_dist, + PeDouble p_az12, + PeDouble p_az21) { /* Highly edited version (plus lots of additions) of NGS FORTRAN code */ /* @@ -419,354 +419,354 @@ static public void geodesic_distance_ngs(double a, * by thaddeus vincenty, 1975, 1976* removed back side solution option, * debugged, revised -- 2011may01 -- dgm* this version of code is * interim -- antipodal boundary needs work - * + * * * output (besides az12, az21, and dist):* These have been removed * from this esri version of the ngs code* it, iteration count* sigma, * spherical distance on auxiliary sphere* lam_sph, longitude difference * on auxiliary sphere* kind, solution flag: kind=1, long-line; kind=2, * antipodal - * - * + * + * * All references to Rapp are Part II */ - double tol = 1.0e-14; - double eps = 1.0e-15; + double tol = 1.0e-14; + double eps = 1.0e-15; - double boa = 0.0; - double dlam = 0.0; - double eta1 = 0.0, sin_eta1 = 0.0, cos_eta1 = 0.0; - double eta2 = 0.0, sin_eta2 = 0.0, cos_eta2 = 0.0; - double prev = 0.0, test = 0.0; - double sin_lam_sph = 0.0, cos_lam_sph = 0.0, temp = 0.0, sin_sigma = 0.0, cos_sigma = 0.0; - double sin_azeq = 0.0, cos2_azeq = 0.0, costm = 0.0, costm2 = 0.0, c = 0.0, d = 0.0; - double tem1 = 0.0, tem2 = 0.0, ep2 = 0.0, bige = 0.0, bigf = 0.0, biga = 0.0, bigb = 0.0, z = 0.0, dsigma = 0.0; - boolean q_continue_looping; + double boa = 0.0; + double dlam = 0.0; + double eta1 = 0.0, sin_eta1 = 0.0, cos_eta1 = 0.0; + double eta2 = 0.0, sin_eta2 = 0.0, cos_eta2 = 0.0; + double prev = 0.0, test = 0.0; + double sin_lam_sph = 0.0, cos_lam_sph = 0.0, temp = 0.0, sin_sigma = 0.0, cos_sigma = 0.0; + double sin_azeq = 0.0, cos2_azeq = 0.0, costm = 0.0, costm2 = 0.0, c = 0.0, d = 0.0; + double tem1 = 0.0, tem2 = 0.0, ep2 = 0.0, bige = 0.0, bigf = 0.0, biga = 0.0, bigb = 0.0, z = 0.0, dsigma = 0.0; + boolean q_continue_looping; - double f = 0.0; + double f = 0.0; - double az12 = 0.0, az21 = 0.0, dist = 0.0; - double sigma = 0.0, lam_sph = 0.0; - int it = 0, kind = 0; + double az12 = 0.0, az21 = 0.0, dist = 0.0; + double sigma = 0.0, lam_sph = 0.0; + int it = 0, kind = 0; - PeDouble lam = new PeDouble(); - PeDouble phi = new PeDouble(); + PeDouble lam = new PeDouble(); + PeDouble phi = new PeDouble(); /* Are there any values to calculate? */ - if (p_dist == null && p_az12 == null && p_az21 == null) { - return; - } + if (p_dist == null && p_az12 == null && p_az21 == null) { + return; + } /* Normalize point 1 and 2 */ - lam.val = lam1; - phi.val = phi1; - lam_phi_reduction(lam, phi); - lam1 = lam.val; - phi1 = phi.val; + lam.val = lam1; + phi.val = phi1; + lam_phi_reduction(lam, phi); + lam1 = lam.val; + phi1 = phi.val; - lam.val = lam2; - phi.val = phi2; - lam_phi_reduction(lam, phi); - lam2 = lam.val; - phi2 = phi.val; + lam.val = lam2; + phi.val = phi2; + lam_phi_reduction(lam, phi); + lam2 = lam.val; + phi2 = phi.val; - dlam = lam_delta(lam2 - lam1); /* longitude difference [-Pi, Pi] */ + dlam = lam_delta(lam2 - lam1); /* longitude difference [-Pi, Pi] */ - if (PE_EQ(phi1, phi2) && (PE_ZERO(dlam) || PE_EQ(PE_ABS(phi1), PE_PI2))) { + if (PE_EQ(phi1, phi2) && (PE_ZERO(dlam) || PE_EQ(PE_ABS(phi1), PE_PI2))) { /* Check that the points are not the same */ - if (p_dist != null) - p_dist.val = 0.0; - if (p_az12 != null) - p_az12.val = 0.0; - if (p_az21 != null) - p_az21.val = 0.0; - - return; - } else if (PE_EQ(phi1, -phi2)) { + if (p_dist != null) + p_dist.val = 0.0; + if (p_az12 != null) + p_az12.val = 0.0; + if (p_az21 != null) + p_az21.val = 0.0; + + return; + } else if (PE_EQ(phi1, -phi2)) { /* Check if they are perfectly antipodal */ - if (PE_EQ(PE_ABS(phi1), PE_PI2)) { + if (PE_EQ(PE_ABS(phi1), PE_PI2)) { /* Check if they are at opposite poles */ - if (p_dist != null) - p_dist.val = 2.0 * q90(a, e2); + if (p_dist != null) + p_dist.val = 2.0 * q90(a, e2); - if (p_az12 != null) - p_az12.val = phi1 > 0.0 ? lam_delta(PE_PI - lam_delta(lam2)) - : lam_delta(lam2); + if (p_az12 != null) + p_az12.val = phi1 > 0.0 ? lam_delta(PE_PI - lam_delta(lam2)) + : lam_delta(lam2); - if (p_az21 != null) - p_az21.val = phi1 > 0.0 ? lam_delta(lam2) : lam_delta(PE_PI - - lam_delta(lam2)); + if (p_az21 != null) + p_az21.val = phi1 > 0.0 ? lam_delta(lam2) : lam_delta(PE_PI + - lam_delta(lam2)); - return; - } else if (PE_EQ(PE_ABS(dlam), PE_PI)) { + return; + } else if (PE_EQ(PE_ABS(dlam), PE_PI)) { /* Other antipodal */ - if (p_dist != null) - p_dist.val = 2.0 * q90(a, e2); - if (p_az12 != null) - p_az12.val = 0.0; - if (p_az21 != null) - p_az21.val = 0.0; - return; - } - } - - if (PE_ZERO(e2)) /* Sphere */ { - double cos_phi1, cos_phi2; - double sin_phi1, sin_phi2; - - cos_phi1 = Math.cos(phi1); - cos_phi2 = Math.cos(phi2); - sin_phi1 = Math.sin(phi1); - sin_phi2 = Math.sin(phi2); - - if (p_dist != null) { - tem1 = Math.sin((phi2 - phi1) / 2.0); - tem2 = Math.sin(dlam / 2.0); - sigma = 2.0 * Math.asin(Math.sqrt(tem1 * tem1 + cos_phi1 - * cos_phi2 * tem2 * tem2)); - p_dist.val = sigma * a; - } - - if (p_az12 != null) { - if (PE_EQ(PE_ABS(phi1), PE_PI2)) /* Origin at N or S Pole */ { - p_az12.val = phi1 < 0.0 ? lam2 : lam_delta(PE_PI - lam2); - } else { - p_az12.val = Math.atan2(cos_phi2 * Math.sin(dlam), cos_phi1 - * sin_phi2 - sin_phi1 * cos_phi2 * Math.cos(dlam)); - } - } - - if (p_az21 != null) { - if (PE_EQ(PE_ABS(phi2), PE_PI2)) /* Destination at N or S Pole */ { - p_az21.val = phi2 < 0.0 ? lam1 : lam_delta(PE_PI - lam1); - } else { - p_az21.val = Math.atan2(cos_phi1 * Math.sin(dlam), sin_phi2 - * cos_phi1 * Math.cos(dlam) - cos_phi2 * sin_phi1); - p_az21.val = lam_delta(p_az21.val + PE_PI); - } - } - - return; - } - - f = 1.0 - Math.sqrt(1.0 - e2); - boa = 1.0 - f; - - eta1 = Math.atan(boa * Math.tan(phi1)); /* better reduced latitude */ - sin_eta1 = Math.sin(eta1); - cos_eta1 = Math.cos(eta1); - - eta2 = Math.atan(boa * Math.tan(phi2)); /* better reduced latitude */ - sin_eta2 = Math.sin(eta2); - cos_eta2 = Math.cos(eta2); - - prev = dlam; - test = dlam; - it = 0; - kind = 1; - lam_sph = dlam; /* v13 (Rapp ) */ + if (p_dist != null) + p_dist.val = 2.0 * q90(a, e2); + if (p_az12 != null) + p_az12.val = 0.0; + if (p_az21 != null) + p_az21.val = 0.0; + return; + } + } + + if (PE_ZERO(e2)) /* Sphere */ { + double cos_phi1, cos_phi2; + double sin_phi1, sin_phi2; + + cos_phi1 = Math.cos(phi1); + cos_phi2 = Math.cos(phi2); + sin_phi1 = Math.sin(phi1); + sin_phi2 = Math.sin(phi2); + + if (p_dist != null) { + tem1 = Math.sin((phi2 - phi1) / 2.0); + tem2 = Math.sin(dlam / 2.0); + sigma = 2.0 * Math.asin(Math.sqrt(tem1 * tem1 + cos_phi1 + * cos_phi2 * tem2 * tem2)); + p_dist.val = sigma * a; + } + + if (p_az12 != null) { + if (PE_EQ(PE_ABS(phi1), PE_PI2)) /* Origin at N or S Pole */ { + p_az12.val = phi1 < 0.0 ? lam2 : lam_delta(PE_PI - lam2); + } else { + p_az12.val = Math.atan2(cos_phi2 * Math.sin(dlam), cos_phi1 + * sin_phi2 - sin_phi1 * cos_phi2 * Math.cos(dlam)); + } + } + + if (p_az21 != null) { + if (PE_EQ(PE_ABS(phi2), PE_PI2)) /* Destination at N or S Pole */ { + p_az21.val = phi2 < 0.0 ? lam1 : lam_delta(PE_PI - lam1); + } else { + p_az21.val = Math.atan2(cos_phi1 * Math.sin(dlam), sin_phi2 + * cos_phi1 * Math.cos(dlam) - cos_phi2 * sin_phi1); + p_az21.val = lam_delta(p_az21.val + PE_PI); + } + } + + return; + } + + f = 1.0 - Math.sqrt(1.0 - e2); + boa = 1.0 - f; + + eta1 = Math.atan(boa * Math.tan(phi1)); /* better reduced latitude */ + sin_eta1 = Math.sin(eta1); + cos_eta1 = Math.cos(eta1); + + eta2 = Math.atan(boa * Math.tan(phi2)); /* better reduced latitude */ + sin_eta2 = Math.sin(eta2); + cos_eta2 = Math.cos(eta2); + + prev = dlam; + test = dlam; + it = 0; + kind = 1; + lam_sph = dlam; /* v13 (Rapp ) */ /* top of the long-line loop (kind = 1) */ - q_continue_looping = true; - while (q_continue_looping && it < 100) { - it = it + 1; + q_continue_looping = true; + while (q_continue_looping && it < 100) { + it = it + 1; - if (kind == 1) { - sin_lam_sph = Math.sin(lam_sph); + if (kind == 1) { + sin_lam_sph = Math.sin(lam_sph); /* * if ( PE_ABS(PE_PI - PE_ABS(dlam)) < 2.0e-11 ) sin_lam_sph = * 0.0 no--troublesome */ - cos_lam_sph = Math.cos(lam_sph); - tem1 = cos_eta2 * sin_lam_sph; - temp = cos_eta1 * sin_eta2 - sin_eta1 * cos_eta2 * cos_lam_sph; - sin_sigma = Math.sqrt(tem1 * tem1 + temp * temp); /* - * v14 (Rapp - * 1.87) - */ - cos_sigma = sin_eta1 * sin_eta2 + cos_eta1 * cos_eta2 - * cos_lam_sph; /* v15 (Rapp 1.88) */ - sigma = Math.atan2(sin_sigma, cos_sigma); /* (Rapp 1.89) */ - - if (PE_ABS(sin_sigma) < eps) /* avoid division by 0 */ { - sin_azeq = cos_eta1 * cos_eta2 * sin_lam_sph - / PE_SGN(eps, sin_sigma); - } else { - sin_azeq = cos_eta1 * cos_eta2 * sin_lam_sph / sin_sigma; + cos_lam_sph = Math.cos(lam_sph); + tem1 = cos_eta2 * sin_lam_sph; + temp = cos_eta1 * sin_eta2 - sin_eta1 * cos_eta2 * cos_lam_sph; + sin_sigma = Math.sqrt(tem1 * tem1 + temp * temp); /* + * v14 (Rapp + * 1.87) + */ + cos_sigma = sin_eta1 * sin_eta2 + cos_eta1 * cos_eta2 + * cos_lam_sph; /* v15 (Rapp 1.88) */ + sigma = Math.atan2(sin_sigma, cos_sigma); /* (Rapp 1.89) */ + + if (PE_ABS(sin_sigma) < eps) /* avoid division by 0 */ { + sin_azeq = cos_eta1 * cos_eta2 * sin_lam_sph + / PE_SGN(eps, sin_sigma); + } else { + sin_azeq = cos_eta1 * cos_eta2 * sin_lam_sph / sin_sigma; /* v17 (Rapp 1.90) */ - } + } - cos2_azeq = 1.0 - sin_azeq * sin_azeq; + cos2_azeq = 1.0 - sin_azeq * sin_azeq; - if (PE_ABS(cos2_azeq) < eps) /* avoid division by 0 */ { - costm = cos_sigma - 2.0 - * (sin_eta1 * sin_eta2 / PE_SGN(eps, cos2_azeq)); - } else { - costm = cos_sigma - 2.0 * (sin_eta1 * sin_eta2 / cos2_azeq); + if (PE_ABS(cos2_azeq) < eps) /* avoid division by 0 */ { + costm = cos_sigma - 2.0 + * (sin_eta1 * sin_eta2 / PE_SGN(eps, cos2_azeq)); + } else { + costm = cos_sigma - 2.0 * (sin_eta1 * sin_eta2 / cos2_azeq); /* v18 (Rapp 1.91) */ - } - costm2 = costm * costm; - c = ((-3.0 * cos2_azeq + 4.0) * f + 4.0) * cos2_azeq * f / 16.0; /* - * v10 - * ( - * Rapp - * 1.83 - * ) - */ - } + } + costm2 = costm * costm; + c = ((-3.0 * cos2_azeq + 4.0) * f + 4.0) * cos2_azeq * f / 16.0; /* + * v10 + * ( + * Rapp + * 1.83 + * ) + */ + } /* entry point of the antipodal loop (kind = 2) */ - d = (1.0 - c) - * f - * (sigma + c * sin_sigma - * (costm + cos_sigma * c * (2.0 * costm2 - 1.0))); + d = (1.0 - c) + * f + * (sigma + c * sin_sigma + * (costm + cos_sigma * c * (2.0 * costm2 - 1.0))); /* v11 (Rapp 1.84) */ - if (kind == 1) { - lam_sph = dlam + d * sin_azeq; - if (PE_ABS(lam_sph - test) < tol) { - q_continue_looping = false; - continue; - } - - if (PE_ABS(lam_sph) > PE_PI) { - kind = 2; - lam_sph = PE_PI; - if (dlam < 0.0) { - lam_sph = -lam_sph; - } - sin_azeq = 0.0; - cos2_azeq = 1.0; - test = 2.0; - prev = test; - - sigma = PE_PI - - PE_ABS(Math.atan(sin_eta1 / cos_eta1) - + Math.atan(sin_eta2 / cos_eta2)); - sin_sigma = Math.sin(sigma); - cos_sigma = Math.cos(sigma); - c = ((-3.0 * cos2_azeq + 4.0) * f + 4.0) * cos2_azeq * f - / 16.0; /* v10 (Rapp 1.83) */ - - if (PE_ABS(sin_azeq - prev) < tol) { - q_continue_looping = false; - continue; - } - if (PE_ABS(cos2_azeq) < eps) /* avoid division by 0 */ { - costm = cos_sigma - - 2.0 - * (sin_eta1 * sin_eta2 / PE_SGN(eps, cos2_azeq)); - } else { - costm = cos_sigma - 2.0 - * (sin_eta1 * sin_eta2 / cos2_azeq); + if (kind == 1) { + lam_sph = dlam + d * sin_azeq; + if (PE_ABS(lam_sph - test) < tol) { + q_continue_looping = false; + continue; + } + + if (PE_ABS(lam_sph) > PE_PI) { + kind = 2; + lam_sph = PE_PI; + if (dlam < 0.0) { + lam_sph = -lam_sph; + } + sin_azeq = 0.0; + cos2_azeq = 1.0; + test = 2.0; + prev = test; + + sigma = PE_PI + - PE_ABS(Math.atan(sin_eta1 / cos_eta1) + + Math.atan(sin_eta2 / cos_eta2)); + sin_sigma = Math.sin(sigma); + cos_sigma = Math.cos(sigma); + c = ((-3.0 * cos2_azeq + 4.0) * f + 4.0) * cos2_azeq * f + / 16.0; /* v10 (Rapp 1.83) */ + + if (PE_ABS(sin_azeq - prev) < tol) { + q_continue_looping = false; + continue; + } + if (PE_ABS(cos2_azeq) < eps) /* avoid division by 0 */ { + costm = cos_sigma + - 2.0 + * (sin_eta1 * sin_eta2 / PE_SGN(eps, cos2_azeq)); + } else { + costm = cos_sigma - 2.0 + * (sin_eta1 * sin_eta2 / cos2_azeq); /* v18 (Rapp 1.91) */ - } - costm2 = costm * costm; - continue; - } + } + costm2 = costm * costm; + continue; + } - if (((lam_sph - test) * (test - prev)) < 0.0 && it > 5) { + if (((lam_sph - test) * (test - prev)) < 0.0 && it > 5) { /* refined converge */ - lam_sph = (2.0 * lam_sph + 3.0 * test + prev) / 6.0; - } - prev = test; - test = lam_sph; - continue; - } else /* kind == 2 */ { - sin_azeq = (lam_sph - dlam) / d; - if (((sin_azeq - test) * (test - prev)) < 0.0 && it > 5) { + lam_sph = (2.0 * lam_sph + 3.0 * test + prev) / 6.0; + } + prev = test; + test = lam_sph; + continue; + } else /* kind == 2 */ { + sin_azeq = (lam_sph - dlam) / d; + if (((sin_azeq - test) * (test - prev)) < 0.0 && it > 5) { /* refined converge */ - sin_azeq = (2.0 * sin_azeq + 3.0 * test + prev) / 6.0; - } - prev = test; - test = sin_azeq; - cos2_azeq = 1.0 - sin_azeq * sin_azeq; - sin_lam_sph = sin_azeq * sin_sigma / (cos_eta1 * cos_eta2); - cos_lam_sph = -Math - .sqrt(PE_ABS(1.0 - sin_lam_sph * sin_lam_sph)); - lam_sph = Math.atan2(sin_lam_sph, cos_lam_sph); - tem1 = cos_eta2 * sin_lam_sph; - temp = cos_eta1 * sin_eta2 - sin_eta1 * cos_eta2 * cos_lam_sph; - sin_sigma = Math.sqrt(tem1 * tem1 + temp * temp); - cos_sigma = sin_eta1 * sin_eta2 + cos_eta1 * cos_eta2 - * cos_lam_sph; - sigma = Math.atan2(sin_sigma, cos_sigma); - c = ((-3.0 * cos2_azeq + 4.0) * f + 4.0) * cos2_azeq * f / 16.0; /* - * v10 - * ( - * Rapp - * 1.83 - * ) - */ - if (PE_ABS(sin_azeq - prev) < tol) { - q_continue_looping = false; - continue; - } - if (PE_ABS(cos2_azeq) < eps) /* avoid division by 0 */ { - costm = cos_sigma - 2.0 - * (sin_eta1 * sin_eta2 / PE_SGN(eps, cos2_azeq)); - } else { - costm = cos_sigma - 2.0 * (sin_eta1 * sin_eta2 / cos2_azeq); + sin_azeq = (2.0 * sin_azeq + 3.0 * test + prev) / 6.0; + } + prev = test; + test = sin_azeq; + cos2_azeq = 1.0 - sin_azeq * sin_azeq; + sin_lam_sph = sin_azeq * sin_sigma / (cos_eta1 * cos_eta2); + cos_lam_sph = -Math + .sqrt(PE_ABS(1.0 - sin_lam_sph * sin_lam_sph)); + lam_sph = Math.atan2(sin_lam_sph, cos_lam_sph); + tem1 = cos_eta2 * sin_lam_sph; + temp = cos_eta1 * sin_eta2 - sin_eta1 * cos_eta2 * cos_lam_sph; + sin_sigma = Math.sqrt(tem1 * tem1 + temp * temp); + cos_sigma = sin_eta1 * sin_eta2 + cos_eta1 * cos_eta2 + * cos_lam_sph; + sigma = Math.atan2(sin_sigma, cos_sigma); + c = ((-3.0 * cos2_azeq + 4.0) * f + 4.0) * cos2_azeq * f / 16.0; /* + * v10 + * ( + * Rapp + * 1.83 + * ) + */ + if (PE_ABS(sin_azeq - prev) < tol) { + q_continue_looping = false; + continue; + } + if (PE_ABS(cos2_azeq) < eps) /* avoid division by 0 */ { + costm = cos_sigma - 2.0 + * (sin_eta1 * sin_eta2 / PE_SGN(eps, cos2_azeq)); + } else { + costm = cos_sigma - 2.0 * (sin_eta1 * sin_eta2 / cos2_azeq); /* v18 (Rapp 1.91) */ - } - costm2 = costm * costm; - continue; - } - } /* End of while q_continue_looping */ + } + costm2 = costm * costm; + continue; + } + } /* End of while q_continue_looping */ /* Convergence */ - if (p_dist != null) { + if (p_dist != null) { /* * Helmert 1880 from Vincenty's * "Geodetic inverse solution between antipodal points" */ - ep2 = 1.0 / (boa * boa) - 1.0; - bige = Math.sqrt(1.0 + ep2 * cos2_azeq); /* 15 */ - bigf = (bige - 1.0) / (bige + 1.0); /* 16 */ - biga = (1.0 + bigf * bigf / 4.0) / (1.0 - bigf); /* 17 */ - bigb = bigf * (1.0 - 0.375 * bigf * bigf); /* 18 */ - z = bigb / 6.0 * costm * (-3.0 + 4.0 * sin_sigma * sin_sigma) - * (-3.0 + 4.0 * costm2); - dsigma = bigb - * sin_sigma - * (costm + bigb / 4.0 - * (cos_sigma * (-1.0 + 2.0 * costm2) - z)); /* 19 */ - dist = (boa * a) * biga * (sigma - dsigma); /* 20 */ - - p_dist.val = dist; - } - - if (p_az12 != null || p_az21 != null) { - if (kind == 2) /* antipodal */ { - az12 = sin_azeq / cos_eta1; - az21 = Math.sqrt(1.0 - az12 * az12); - if (temp < 0.0) { - az21 = -az21; - } - az12 = Math.atan2(az12, az21); - tem1 = -sin_azeq; - tem2 = sin_eta1 * sin_sigma - cos_eta1 * cos_sigma * az21; - az21 = Math.atan2(tem1, tem2); - } else /* long-line */ { - tem1 = cos_eta2 * sin_lam_sph; - tem2 = cos_eta1 * sin_eta2 - sin_eta1 * cos_eta2 * cos_lam_sph; - az12 = Math.atan2(tem1, tem2); - tem1 = -cos_eta1 * sin_lam_sph; - tem2 = sin_eta1 * cos_eta2 - cos_eta1 * sin_eta2 * cos_lam_sph; - az21 = Math.atan2(tem1, tem2); - } - - if (p_az12 != null) { - p_az12.val = lam_delta(az12); - } - if (p_az21 != null) { - p_az21.val = lam_delta(az21); - } - } - } + ep2 = 1.0 / (boa * boa) - 1.0; + bige = Math.sqrt(1.0 + ep2 * cos2_azeq); /* 15 */ + bigf = (bige - 1.0) / (bige + 1.0); /* 16 */ + biga = (1.0 + bigf * bigf / 4.0) / (1.0 - bigf); /* 17 */ + bigb = bigf * (1.0 - 0.375 * bigf * bigf); /* 18 */ + z = bigb / 6.0 * costm * (-3.0 + 4.0 * sin_sigma * sin_sigma) + * (-3.0 + 4.0 * costm2); + dsigma = bigb + * sin_sigma + * (costm + bigb / 4.0 + * (cos_sigma * (-1.0 + 2.0 * costm2) - z)); /* 19 */ + dist = (boa * a) * biga * (sigma - dsigma); /* 20 */ + + p_dist.val = dist; + } + + if (p_az12 != null || p_az21 != null) { + if (kind == 2) /* antipodal */ { + az12 = sin_azeq / cos_eta1; + az21 = Math.sqrt(1.0 - az12 * az12); + if (temp < 0.0) { + az21 = -az21; + } + az12 = Math.atan2(az12, az21); + tem1 = -sin_azeq; + tem2 = sin_eta1 * sin_sigma - cos_eta1 * cos_sigma * az21; + az21 = Math.atan2(tem1, tem2); + } else /* long-line */ { + tem1 = cos_eta2 * sin_lam_sph; + tem2 = cos_eta1 * sin_eta2 - sin_eta1 * cos_eta2 * cos_lam_sph; + az12 = Math.atan2(tem1, tem2); + tem1 = -cos_eta1 * sin_lam_sph; + tem2 = sin_eta1 * cos_eta2 - cos_eta1 * sin_eta2 * cos_lam_sph; + az21 = Math.atan2(tem1, tem2); + } + + if (p_az12 != null) { + p_az12.val = lam_delta(az12); + } + if (p_az21 != null) { + p_az21.val = lam_delta(az21); + } + } + } } diff --git a/src/main/java/com/esri/core/geometry/GeoJsonCrsTables.java b/src/main/java/com/esri/core/geometry/GeoJsonCrsTables.java index ee5fb963..b1633e2e 100644 --- a/src/main/java/com/esri/core/geometry/GeoJsonCrsTables.java +++ b/src/main/java/com/esri/core/geometry/GeoJsonCrsTables.java @@ -26,158 +26,158 @@ import java.util.Arrays; class GeoJsonCrsTables { - static int getWkidFromCrsShortForm(String crs_identifier) { - int last_colon = crs_identifier.lastIndexOf((int) ':'); // skip version + static int getWkidFromCrsShortForm(String crs_identifier) { + int last_colon = crs_identifier.lastIndexOf((int) ':'); // skip version - if (last_colon == -1) - return -1; + if (last_colon == -1) + return -1; - int code_start = last_colon + 1; - int wkid = getWkidFromCrsCode_(crs_identifier, code_start); - return wkid; - } + int code_start = last_colon + 1; + int wkid = getWkidFromCrsCode_(crs_identifier, code_start); + return wkid; + } - static int getWkidFromCrsName(String crs_identifier) { - int wkid = -1; + static int getWkidFromCrsName(String crs_identifier) { + int wkid = -1; - int last_colon = crs_identifier.lastIndexOf((int) ':'); // skip - // authority, - // version, and - // other things. - // Just try to - // get a wkid. - // This works - // for - // short/long - // form. + int last_colon = crs_identifier.lastIndexOf((int) ':'); // skip + // authority, + // version, and + // other things. + // Just try to + // get a wkid. + // This works + // for + // short/long + // form. - if (last_colon == -1) - return -1; + if (last_colon == -1) + return -1; - int code_start = last_colon + 1; - wkid = getWkidFromCrsCode_(crs_identifier, code_start); + int code_start = last_colon + 1; + wkid = getWkidFromCrsCode_(crs_identifier, code_start); - if (wkid != -1) - return wkid; + if (wkid != -1) + return wkid; - wkid = getWkidFromCrsOgcUrn(crs_identifier); // could be an OGC - // "preferred" urn - return wkid; - } + wkid = getWkidFromCrsOgcUrn(crs_identifier); // could be an OGC + // "preferred" urn + return wkid; + } - static int getWkidFromCrsOgcUrn(String crs_identifier) { - int wkid = -1; - if (crs_identifier.regionMatches(0, "urn:ogc:def:crs:OGC", 0, 19)) - wkid = getWkidFromCrsOgcUrn_(crs_identifier); + static int getWkidFromCrsOgcUrn(String crs_identifier) { + int wkid = -1; + if (crs_identifier.regionMatches(0, "urn:ogc:def:crs:OGC", 0, 19)) + wkid = getWkidFromCrsOgcUrn_(crs_identifier); - return wkid; - } + return wkid; + } - private static int getWkidFromCrsCode_(String crs_identifier, int code_start) { - assert (code_start > 0); + private static int getWkidFromCrsCode_(String crs_identifier, int code_start) { + assert (code_start > 0); - int wkid = -1; - int code_count = crs_identifier.length() - code_start; + int wkid = -1; + int code_count = crs_identifier.length() - code_start; - try { - wkid = Integer.parseInt(crs_identifier.substring(code_start, code_start + code_count)); - } catch (Exception e) { - } + try { + wkid = Integer.parseInt(crs_identifier.substring(code_start, code_start + code_count)); + } catch (Exception e) { + } - return (int) wkid; - } + return (int) wkid; + } - private static int getWkidFromCrsOgcUrn_(String crs_identifier) { - assert (crs_identifier.regionMatches(0, "urn:ogc:def:crs:OGC", 0, 19)); + private static int getWkidFromCrsOgcUrn_(String crs_identifier) { + assert (crs_identifier.regionMatches(0, "urn:ogc:def:crs:OGC", 0, 19)); - int last_colon = crs_identifier.lastIndexOf((int) ':'); // skip version + int last_colon = crs_identifier.lastIndexOf((int) ':'); // skip version - if (last_colon == -1) - return -1; + if (last_colon == -1) + return -1; - int ogc_code_start = last_colon + 1; - int ogc_code_count = crs_identifier.length() - ogc_code_start; + int ogc_code_start = last_colon + 1; + int ogc_code_count = crs_identifier.length() - ogc_code_start; - if (crs_identifier.regionMatches(ogc_code_start, "CRS84", 0, ogc_code_count)) - return 4326; + if (crs_identifier.regionMatches(ogc_code_start, "CRS84", 0, ogc_code_count)) + return 4326; - if (crs_identifier.regionMatches(ogc_code_start, "CRS83", 0, ogc_code_count)) - return 4269; + if (crs_identifier.regionMatches(ogc_code_start, "CRS83", 0, ogc_code_count)) + return 4269; - if (crs_identifier.regionMatches(ogc_code_start, "CRS27", 0, ogc_code_count)) - return 4267; + if (crs_identifier.regionMatches(ogc_code_start, "CRS27", 0, ogc_code_count)) + return 4267; - return -1; - } + return -1; + } - static int getWkidFromCrsHref(String crs_identifier) { - int sr_org_code_start = -1; + static int getWkidFromCrsHref(String crs_identifier) { + int sr_org_code_start = -1; - if (crs_identifier.regionMatches(0, "http://spatialreference.org/ref/epsg/", 0, 37)) - sr_org_code_start = 37; - else if (crs_identifier.regionMatches(0, "www.spatialreference.org/ref/epsg/", 0, 34)) - sr_org_code_start = 34; - else if (crs_identifier.regionMatches(0, "http://www.spatialreference.org/ref/epsg/", 0, 41)) - sr_org_code_start = 41; + if (crs_identifier.regionMatches(0, "http://spatialreference.org/ref/epsg/", 0, 37)) + sr_org_code_start = 37; + else if (crs_identifier.regionMatches(0, "www.spatialreference.org/ref/epsg/", 0, 34)) + sr_org_code_start = 34; + else if (crs_identifier.regionMatches(0, "http://www.spatialreference.org/ref/epsg/", 0, 41)) + sr_org_code_start = 41; - if (sr_org_code_start != -1) { - int sr_org_code_end = crs_identifier.indexOf('/', sr_org_code_start); + if (sr_org_code_start != -1) { + int sr_org_code_end = crs_identifier.indexOf('/', sr_org_code_start); - if (sr_org_code_end == -1) - return -1; + if (sr_org_code_end == -1) + return -1; - int count = sr_org_code_end - sr_org_code_start; - int wkid = -1; + int count = sr_org_code_end - sr_org_code_start; + int wkid = -1; - try { - wkid = Integer.parseInt(crs_identifier.substring(sr_org_code_start, sr_org_code_start + count)); - } catch (Exception e) { - } + try { + wkid = Integer.parseInt(crs_identifier.substring(sr_org_code_start, sr_org_code_start + count)); + } catch (Exception e) { + } - return wkid; - } + return wkid; + } - int open_gis_epsg_slash_end = -1; + int open_gis_epsg_slash_end = -1; - if (crs_identifier.regionMatches(0, "http://opengis.net/def/crs/EPSG/", 0, 32)) - open_gis_epsg_slash_end = 32; - else if (crs_identifier.regionMatches(0, "www.opengis.net/def/crs/EPSG/", 0, 29)) - open_gis_epsg_slash_end = 29; - else if (crs_identifier.regionMatches(0, "http://www.opengis.net/def/crs/EPSG/", 0, 36)) - open_gis_epsg_slash_end = 36; + if (crs_identifier.regionMatches(0, "http://opengis.net/def/crs/EPSG/", 0, 32)) + open_gis_epsg_slash_end = 32; + else if (crs_identifier.regionMatches(0, "www.opengis.net/def/crs/EPSG/", 0, 29)) + open_gis_epsg_slash_end = 29; + else if (crs_identifier.regionMatches(0, "http://www.opengis.net/def/crs/EPSG/", 0, 36)) + open_gis_epsg_slash_end = 36; - if (open_gis_epsg_slash_end != -1) { - int last_slash = crs_identifier.lastIndexOf('/'); // skip over the - // "0/" + if (open_gis_epsg_slash_end != -1) { + int last_slash = crs_identifier.lastIndexOf('/'); // skip over the + // "0/" - if (last_slash == -1) - return -1; + if (last_slash == -1) + return -1; - int open_gis_code_start = last_slash + 1; + int open_gis_code_start = last_slash + 1; - int count = crs_identifier.length() - open_gis_code_start; - int wkid = -1; + int count = crs_identifier.length() - open_gis_code_start; + int wkid = -1; - try { - wkid = Integer.parseInt(crs_identifier.substring(open_gis_code_start, open_gis_code_start + count)); - } catch (Exception e) { - } + try { + wkid = Integer.parseInt(crs_identifier.substring(open_gis_code_start, open_gis_code_start + count)); + } catch (Exception e) { + } - return wkid; - } + return wkid; + } - if (crs_identifier.compareToIgnoreCase("http://spatialreference.org/ref/sr-org/6928/ogcwkt/") == 0) - return 3857; + if (crs_identifier.compareToIgnoreCase("http://spatialreference.org/ref/sr-org/6928/ogcwkt/") == 0) + return 3857; - return -1; - } + return -1; + } - static String getWktFromCrsName(String crs_identifier) { - int last_colon = crs_identifier.lastIndexOf((int) ':'); // skip - // authority - int wkt_start = last_colon + 1; - int wkt_count = crs_identifier.length() - wkt_start; - String wkt = crs_identifier.substring(wkt_start, wkt_start + wkt_count); - return wkt; - } + static String getWktFromCrsName(String crs_identifier) { + int last_colon = crs_identifier.lastIndexOf((int) ':'); // skip + // authority + int wkt_start = last_colon + 1; + int wkt_count = crs_identifier.length() - wkt_start; + String wkt = crs_identifier.substring(wkt_start, wkt_start + wkt_count); + return wkt; + } } diff --git a/src/main/java/com/esri/core/geometry/GeoJsonExportFlags.java b/src/main/java/com/esri/core/geometry/GeoJsonExportFlags.java index 7866269e..fec55a03 100644 --- a/src/main/java/com/esri/core/geometry/GeoJsonExportFlags.java +++ b/src/main/java/com/esri/core/geometry/GeoJsonExportFlags.java @@ -24,31 +24,31 @@ package com.esri.core.geometry; public interface GeoJsonExportFlags { - public static final int geoJsonExportDefaults = 0; - /** - * Export MultiXXX geometries every time, by default it will export the minimum required type. - */ - public static final int geoJsonExportPreferMultiGeometry = 1; - public static final int geoJsonExportStripZs = 2; - public static final int geoJsonExportStripMs = 4; - public static final int geoJsonExportSkipCRS = 8; - public static final int geoJsonExportFailIfNotSimple = 16; - public static final int geoJsonExportPrecision16 = 0x02000; - public static final int geoJsonExportPrecision15 = 0x04000; - public static final int geoJsonExportPrecision14 = 0x06000; - public static final int geoJsonExportPrecision13 = 0x08000; - public static final int geoJsonExportPrecision12 = 0x0a000; - public static final int geoJsonExportPrecision11 = 0x0c000; - public static final int geoJsonExportPrecision10 = 0x0e000; - public static final int geoJsonExportPrecision9 = 0x10000; - public static final int geoJsonExportPrecision8 = 0x12000; - public static final int geoJsonExportPrecision7 = 0x14000; - public static final int geoJsonExportPrecision6 = 0x16000; - public static final int geoJsonExportPrecision5 = 0x18000; - public static final int geoJsonExportPrecision4 = 0x1a000; - public static final int geoJsonExportPrecision3 = 0x1c000; - public static final int geoJsonExportPrecision2 = 0x1e000; - public static final int geoJsonExportPrecision1 = 0x20000; - public static final int geoJsonExportPrecision0 = 0x22000; - public static final int geoJsonExportPrecisionFixedPoint = 0x40000; + public static final int geoJsonExportDefaults = 0; + /** + * Export MultiXXX geometries every time, by default it will export the minimum required type. + */ + public static final int geoJsonExportPreferMultiGeometry = 1; + public static final int geoJsonExportStripZs = 2; + public static final int geoJsonExportStripMs = 4; + public static final int geoJsonExportSkipCRS = 8; + public static final int geoJsonExportFailIfNotSimple = 16; + public static final int geoJsonExportPrecision16 = 0x02000; + public static final int geoJsonExportPrecision15 = 0x04000; + public static final int geoJsonExportPrecision14 = 0x06000; + public static final int geoJsonExportPrecision13 = 0x08000; + public static final int geoJsonExportPrecision12 = 0x0a000; + public static final int geoJsonExportPrecision11 = 0x0c000; + public static final int geoJsonExportPrecision10 = 0x0e000; + public static final int geoJsonExportPrecision9 = 0x10000; + public static final int geoJsonExportPrecision8 = 0x12000; + public static final int geoJsonExportPrecision7 = 0x14000; + public static final int geoJsonExportPrecision6 = 0x16000; + public static final int geoJsonExportPrecision5 = 0x18000; + public static final int geoJsonExportPrecision4 = 0x1a000; + public static final int geoJsonExportPrecision3 = 0x1c000; + public static final int geoJsonExportPrecision2 = 0x1e000; + public static final int geoJsonExportPrecision1 = 0x20000; + public static final int geoJsonExportPrecision0 = 0x22000; + public static final int geoJsonExportPrecisionFixedPoint = 0x40000; } diff --git a/src/main/java/com/esri/core/geometry/GeoJsonImportFlags.java b/src/main/java/com/esri/core/geometry/GeoJsonImportFlags.java index f59466f8..351b9045 100644 --- a/src/main/java/com/esri/core/geometry/GeoJsonImportFlags.java +++ b/src/main/java/com/esri/core/geometry/GeoJsonImportFlags.java @@ -24,16 +24,16 @@ package com.esri.core.geometry; public interface GeoJsonImportFlags { - public static final int geoJsonImportDefaults = 0; - @Deprecated - static final int geoJsonImportNonTrusted = 2; - /** - * If set, the import will skip CRS. - */ - public static final int geoJsonImportSkipCRS = 8; - /** - * If set, and the geojson does not have a spatial reference, the result geometry will not have one too, otherwise - * it'll assume WGS84. - */ - public static final int geoJsonImportNoWGS84Default = 16; + public static final int geoJsonImportDefaults = 0; + @Deprecated + static final int geoJsonImportNonTrusted = 2; + /** + * If set, the import will skip CRS. + */ + public static final int geoJsonImportSkipCRS = 8; + /** + * If set, and the geojson does not have a spatial reference, the result geometry will not have one too, otherwise + * it'll assume WGS84. + */ + public static final int geoJsonImportNoWGS84Default = 16; } diff --git a/src/main/java/com/esri/core/geometry/GeodesicBufferer.java b/src/main/java/com/esri/core/geometry/GeodesicBufferer.java index 41f22177..7132990f 100644 --- a/src/main/java/com/esri/core/geometry/GeodesicBufferer.java +++ b/src/main/java/com/esri/core/geometry/GeodesicBufferer.java @@ -6,289 +6,293 @@ * Created by davidraleigh on 2/20/16. */ class GeodesicBufferer { - /** - * Result is always a polygon. For non positive distance and non-areas - * returns an empty polygon. For points returns circles. - */ - static Geometry buffer(Geometry geometry, - double distance, - SpatialReference sr, - double densify_dist, - int max_vertex_in_complete_circle, - ProgressTracker progress_tracker) { - if (geometry == null) - throw new IllegalArgumentException(); - - if (densify_dist < 0) - throw new IllegalArgumentException(); - - if (geometry.isEmpty()) - return new Polygon(geometry.getDescription()); - - GeodesicBufferer geodesicBufferer = new GeodesicBufferer(progress_tracker); - - Envelope2D env2D = new Envelope2D(); - geometry.queryLooseEnvelope2D(env2D); - - geodesicBufferer.m_spatialReference = sr; - - if (distance > 0){ - // env2D.inflate(distance, distance); - GeoDist.inflateEnv2D( - geodesicBufferer.m_spatialReference.getMajorAxis(), - geodesicBufferer.m_spatialReference.getEccentricitySquared(), - env2D, - distance, - distance); - } - - geodesicBufferer.m_geometry = geometry; - geodesicBufferer.m_tolerance = InternalUtils.calculateToleranceFromGeometry(sr, env2D, true);// conservative to have same effect as simplify - geodesicBufferer.m_small_tolerance = InternalUtils.calculateToleranceFromGeometry(null, env2D, true);// conservative - // to have same effect as simplify - geodesicBufferer.m_distance = distance; - geodesicBufferer.m_original_geom_type = geometry.getType().value(); - if (max_vertex_in_complete_circle <= 0) { - max_vertex_in_complete_circle = 96;// 96 is the value used by SG. - // This is the number of - // vertices in the full circle. - } - - geodesicBufferer.m_abs_distance = Math.abs(geodesicBufferer.m_distance); - geodesicBufferer.m_abs_distance_reversed = geodesicBufferer.m_abs_distance != 0 ? 1.0 / geodesicBufferer.m_abs_distance : 0; - - if (NumberUtils.isNaN(densify_dist) || densify_dist == 0) { - densify_dist = geodesicBufferer.m_abs_distance * 1e-5; - } else if (densify_dist > geodesicBufferer.m_abs_distance * 0.5) { - //TODO put a break point here to see if this is ever a problem - // do not allow too large densify distance (the value will be adjusted anyway later) - densify_dist = geodesicBufferer.m_abs_distance * 0.5; - } - - if (max_vertex_in_complete_circle < 12) - max_vertex_in_complete_circle = 12; - - // TODO I don't know what max_dd is for. decimal degrees? - double max_dd = Math.abs(distance) * (1 - Math.cos(Math.PI / max_vertex_in_complete_circle)); - - if (max_dd > densify_dist) { - densify_dist = max_dd;// the densify distance has to agree with the - // max_vertex_in_complete_circle - } else { - double vertex_count = Math.PI / Math.acos(1.0 - densify_dist / Math.abs(distance)); - if (vertex_count < (double) max_vertex_in_complete_circle - 1.0) { - max_vertex_in_complete_circle = (int) vertex_count; - if (max_vertex_in_complete_circle < 12) { - max_vertex_in_complete_circle = 12; - densify_dist = Math.abs(distance) * (1 - Math.cos(Math.PI / max_vertex_in_complete_circle)); - } - } - } - - geodesicBufferer.m_densify_dist = densify_dist; - geodesicBufferer.m_max_vertex_in_complete_circle = max_vertex_in_complete_circle; - // when filtering close points we do not want the filter to distort - // generated buffer too much. - geodesicBufferer.m_filter_tolerance = Math.min(geodesicBufferer.m_small_tolerance, densify_dist * 0.25); - return geodesicBufferer.buffer_(); - } - - private Geometry m_geometry; - - protected static final class GeodesicBufferCommand { - protected interface Flags { - int enum_line = 1; - int enum_arc = 2; - int enum_dummy = 4; - int enum_concave_dip = 8; - int enum_connection = enum_arc | enum_line; - } - - protected Point2D m_from; - protected Point2D m_to; - protected Point2D m_center; - protected int m_next; - protected int m_prev; - protected int m_type; - - protected GeodesicBufferCommand(Point2D from, Point2D to, Point2D center, - int type, int next, int prev) { - m_from = new Point2D(); - m_to = new Point2D(); - m_center = new Point2D(); - m_from.setCoords(from); - m_to.setCoords(to); - m_center.setCoords(center); - m_type = type; - m_next = next; - m_prev = prev; - } - - protected GeodesicBufferCommand(Point2D from, Point2D to, int next, int prev, - String dummy) { - m_from = new Point2D(); - m_to = new Point2D(); - m_center = new Point2D(); - m_from.setCoords(from); - m_to.setCoords(to); - m_center.setNaN(); - m_type = 4; - m_next = next; - m_prev = prev; - } - } - - private ArrayList m_buffer_commands; - - private int m_original_geom_type; - private ProgressTracker m_progress_tracker; - private int m_max_vertex_in_complete_circle; - private SpatialReference m_spatialReference; - private double m_tolerance; - private double m_small_tolerance; - private double m_filter_tolerance; - private double m_densify_dist; - private double m_distance; - private double m_abs_distance; - private double m_abs_distance_reversed; - private double m_dA; - private boolean m_b_output_loops; - private boolean m_bfilter; -// private double m_a; + /** + * Result is always a polygon. For non positive distance and non-areas + * returns an empty polygon. For points returns circles. + */ + static Geometry buffer(Geometry geometry, + double distance, + SpatialReference sr, + double densify_dist, + int max_vertex_in_complete_circle, + ProgressTracker progress_tracker) { + if (geometry == null) + throw new IllegalArgumentException(); + + if (densify_dist < 0) + throw new IllegalArgumentException(); + + if (geometry.isEmpty()) + return new Polygon(geometry.getDescription()); + + GeodesicBufferer geodesicBufferer = new GeodesicBufferer(progress_tracker); + + Envelope2D env2D = new Envelope2D(); + geometry.queryLooseEnvelope2D(env2D); + + geodesicBufferer.m_spatialReference = sr; + + if (distance > 0) { + // env2D.inflate(distance, distance); + GeoDist.inflateEnv2D( + geodesicBufferer.m_spatialReference.getMajorAxis(), + geodesicBufferer.m_spatialReference.getEccentricitySquared(), + env2D, + distance, + distance); + } + + geodesicBufferer.m_geometry = geometry; + geodesicBufferer.m_tolerance = InternalUtils.calculateToleranceFromGeometry(sr, env2D, true);// conservative to have same effect as simplify + geodesicBufferer.m_small_tolerance = InternalUtils.calculateToleranceFromGeometry(null, env2D, true);// conservative + // to have same effect as simplify + geodesicBufferer.m_distance = distance; + geodesicBufferer.m_original_geom_type = geometry.getType().value(); + if (max_vertex_in_complete_circle <= 0) { + max_vertex_in_complete_circle = 96;// 96 is the value used by SG. + // This is the number of + // vertices in the full circle. + } + + geodesicBufferer.m_abs_distance = Math.abs(geodesicBufferer.m_distance); + geodesicBufferer.m_abs_distance_reversed = geodesicBufferer.m_abs_distance != 0 ? 1.0 / geodesicBufferer.m_abs_distance : 0; + + if (NumberUtils.isNaN(densify_dist) || densify_dist == 0) { + densify_dist = geodesicBufferer.m_abs_distance * 1e-5; + } else if (densify_dist > geodesicBufferer.m_abs_distance * 0.5) { + //TODO put a break point here to see if this is ever a problem + // do not allow too large densify distance (the value will be adjusted anyway later) + densify_dist = geodesicBufferer.m_abs_distance * 0.5; + } + + if (max_vertex_in_complete_circle < 12) + max_vertex_in_complete_circle = 12; + + // TODO I don't know what max_dd is for. decimal degrees? + double max_dd = Math.abs(distance) * (1 - Math.cos(Math.PI / max_vertex_in_complete_circle)); + + if (max_dd > densify_dist) { + densify_dist = max_dd;// the densify distance has to agree with the + // max_vertex_in_complete_circle + } else { + double vertex_count = Math.PI / Math.acos(1.0 - densify_dist / Math.abs(distance)); + if (vertex_count < (double) max_vertex_in_complete_circle - 1.0) { + max_vertex_in_complete_circle = (int) vertex_count; + if (max_vertex_in_complete_circle < 12) { + max_vertex_in_complete_circle = 12; + densify_dist = Math.abs(distance) * (1 - Math.cos(Math.PI / max_vertex_in_complete_circle)); + } + } + } + + geodesicBufferer.m_densify_dist = densify_dist; + geodesicBufferer.m_max_vertex_in_complete_circle = max_vertex_in_complete_circle; + // when filtering close points we do not want the filter to distort + // generated buffer too much. + geodesicBufferer.m_filter_tolerance = Math.min(geodesicBufferer.m_small_tolerance, densify_dist * 0.25); + return geodesicBufferer.buffer_(); + } + + private Geometry m_geometry; + + protected static final class GeodesicBufferCommand { + protected interface Flags { + int enum_line = 1; + int enum_arc = 2; + int enum_dummy = 4; + int enum_concave_dip = 8; + int enum_connection = enum_arc | enum_line; + } + + protected Point2D m_from; + protected Point2D m_to; + protected Point2D m_center; + protected int m_next; + protected int m_prev; + protected int m_type; + + protected GeodesicBufferCommand(Point2D from, Point2D to, Point2D center, + int type, int next, int prev) { + m_from = new Point2D(); + m_to = new Point2D(); + m_center = new Point2D(); + m_from.setCoords(from); + m_to.setCoords(to); + m_center.setCoords(center); + m_type = type; + m_next = next; + m_prev = prev; + } + + protected GeodesicBufferCommand(Point2D from, Point2D to, int next, int prev, + String dummy) { + m_from = new Point2D(); + m_to = new Point2D(); + m_center = new Point2D(); + m_from.setCoords(from); + m_to.setCoords(to); + m_center.setNaN(); + m_type = 4; + m_next = next; + m_prev = prev; + } + } + + private ArrayList m_buffer_commands; + + private int m_original_geom_type; + private ProgressTracker m_progress_tracker; + private int m_max_vertex_in_complete_circle; + private SpatialReference m_spatialReference; + private double m_tolerance; + private double m_small_tolerance; + private double m_filter_tolerance; + private double m_densify_dist; + private double m_distance; + private double m_abs_distance; + private double m_abs_distance_reversed; + private double m_dA; + private boolean m_b_output_loops; + private boolean m_bfilter; + // private double m_a; // private double m_e2; - private static final double RAD_TO_DEG = 180.0 / Math.PI; - private static final double DEG_TO_RAD = Math.PI / 180.0; - - // private ArrayList m_left_stack; - // private ArrayList m_middle_stack; - private Line m_helper_line_1; - private Line m_helper_line_2; - private Point2D[] m_helper_array; - private int m_progress_counter; - - private static final class GeometryCursorForMultiPoint extends GeometryCursor { - private int m_index; - private MultiPoint m_mp; - private SpatialReference m_spatialReference; - private double m_distance; - private double m_densify_dist; - private int m_max_vertex_in_complete_circle; - private ProgressTracker m_progress_tracker; - - GeometryCursorForMultiPoint(MultiPoint mp, - double distance, - SpatialReference sr, - double densify_dist, - int max_vertex_in_complete_circle, - ProgressTracker progress_tracker) { - m_index = 0; - m_mp = mp; - m_distance = distance; - m_spatialReference = sr; - m_densify_dist = densify_dist; - m_max_vertex_in_complete_circle = max_vertex_in_complete_circle; - m_progress_tracker = progress_tracker; - } - - @Override - public boolean hasNext() { return m_index < m_mp.getPointCount(); } - - @Override - public Geometry next() { - Point point = new Point(); - while (true) { - if (m_index == m_mp.getPointCount()) - return null; - - m_mp.getPointByVal(m_index, point); - m_index++; - if (point.isEmpty()) - continue; - break; - } - - return GeodesicBufferer.buffer( - point, - m_distance, - m_spatialReference, - m_densify_dist, - m_max_vertex_in_complete_circle, - m_progress_tracker); - } - - @Override - public long getGeometryID() { - return 0; - } - } - - private static final class GeometryCursorForPolyline extends GeometryCursor { - private GeodesicBufferer m_bufferer; - private int m_index; - private boolean m_bfilter; - - GeometryCursorForPolyline(GeodesicBufferer geodesicBufferer, boolean bfilter) { - m_bufferer = geodesicBufferer; - m_index = 0; - m_bfilter = bfilter; - } - - @Override - public boolean hasNext() { return m_index < ((MultiPath)m_bufferer.m_geometry).getPathCount(); } - - @Override - public Geometry next() { - MultiPathImpl mp = (MultiPathImpl) (m_bufferer.m_geometry._getImpl()); - // if there is a path left to retrieve - if (m_index < mp.getPathCount()) { - int ind = m_index; - m_index++; - - // TODO isClosedPathInXYPlane?! is the first point the same as the last? - if (!mp.isClosedPathInXYPlane(ind)) { - // TODO ??!! grab 2nd to last last point? - Point2D prev_end = mp.getXY(mp.getPathEnd(ind) - 1); - while (m_index < mp.getPathCount()) { - Point2D start = mp.getXY(mp.getPathStart(m_index)); - if (mp.isClosedPathInXYPlane(m_index)) - break; - if (start != prev_end) - break; - - prev_end = mp.getXY(mp.getPathEnd(m_index) - 1); - m_index++; - } - } - - - if (m_index - ind == 1) { - // if there is only one path - return m_bufferer.bufferPolylinePath_((Polyline) (m_bufferer.m_geometry), ind, m_bfilter); - } else { - Polyline tmp_polyline = new Polyline(m_bufferer.m_geometry.getDescription()); - tmp_polyline.addPath((Polyline) m_bufferer.m_geometry, ind, true); - for (int i = ind + 1; i < m_index; i++) { - ((MultiPathImpl) tmp_polyline._getImpl()).addSegmentsFromPath( - (MultiPathImpl) m_bufferer.m_geometry._getImpl(), - i, - 0, - mp.getSegmentCount(i), - false); - } - - Polygon res = m_bufferer.bufferPolylinePath_(tmp_polyline, 0, m_bfilter); - return res; - } - } - - return null; - } - - @Override - public long getGeometryID() { - return 0; - } - } + private static final double RAD_TO_DEG = 180.0 / Math.PI; + private static final double DEG_TO_RAD = Math.PI / 180.0; + + // private ArrayList m_left_stack; + // private ArrayList m_middle_stack; + private Line m_helper_line_1; + private Line m_helper_line_2; + private Point2D[] m_helper_array; + private int m_progress_counter; + + private static final class GeometryCursorForMultiPoint extends GeometryCursor { + private int m_index; + private MultiPoint m_mp; + private SpatialReference m_spatialReference; + private double m_distance; + private double m_densify_dist; + private int m_max_vertex_in_complete_circle; + private ProgressTracker m_progress_tracker; + + GeometryCursorForMultiPoint(MultiPoint mp, + double distance, + SpatialReference sr, + double densify_dist, + int max_vertex_in_complete_circle, + ProgressTracker progress_tracker) { + m_index = 0; + m_mp = mp; + m_distance = distance; + m_spatialReference = sr; + m_densify_dist = densify_dist; + m_max_vertex_in_complete_circle = max_vertex_in_complete_circle; + m_progress_tracker = progress_tracker; + } + + @Override + public boolean hasNext() { + return m_index < m_mp.getPointCount(); + } + + @Override + public Geometry next() { + Point point = new Point(); + while (true) { + if (m_index == m_mp.getPointCount()) + return null; + + m_mp.getPointByVal(m_index, point); + m_index++; + if (point.isEmpty()) + continue; + break; + } + + return GeodesicBufferer.buffer( + point, + m_distance, + m_spatialReference, + m_densify_dist, + m_max_vertex_in_complete_circle, + m_progress_tracker); + } + + @Override + public long getGeometryID() { + return 0; + } + } + + private static final class GeometryCursorForPolyline extends GeometryCursor { + private GeodesicBufferer m_bufferer; + private int m_index; + private boolean m_bfilter; + + GeometryCursorForPolyline(GeodesicBufferer geodesicBufferer, boolean bfilter) { + m_bufferer = geodesicBufferer; + m_index = 0; + m_bfilter = bfilter; + } + + @Override + public boolean hasNext() { + return m_index < ((MultiPath) m_bufferer.m_geometry).getPathCount(); + } + + @Override + public Geometry next() { + MultiPathImpl mp = (MultiPathImpl) (m_bufferer.m_geometry._getImpl()); + // if there is a path left to retrieve + if (m_index < mp.getPathCount()) { + int ind = m_index; + m_index++; + + // TODO isClosedPathInXYPlane?! is the first point the same as the last? + if (!mp.isClosedPathInXYPlane(ind)) { + // TODO ??!! grab 2nd to last last point? + Point2D prev_end = mp.getXY(mp.getPathEnd(ind) - 1); + while (m_index < mp.getPathCount()) { + Point2D start = mp.getXY(mp.getPathStart(m_index)); + if (mp.isClosedPathInXYPlane(m_index)) + break; + if (start != prev_end) + break; + + prev_end = mp.getXY(mp.getPathEnd(m_index) - 1); + m_index++; + } + } + + + if (m_index - ind == 1) { + // if there is only one path + return m_bufferer.bufferPolylinePath_((Polyline) (m_bufferer.m_geometry), ind, m_bfilter); + } else { + Polyline tmp_polyline = new Polyline(m_bufferer.m_geometry.getDescription()); + tmp_polyline.addPath((Polyline) m_bufferer.m_geometry, ind, true); + for (int i = ind + 1; i < m_index; i++) { + ((MultiPathImpl) tmp_polyline._getImpl()).addSegmentsFromPath( + (MultiPathImpl) m_bufferer.m_geometry._getImpl(), + i, + 0, + mp.getSegmentCount(i), + false); + } + + Polygon res = m_bufferer.bufferPolylinePath_(tmp_polyline, 0, m_bfilter); + return res; + } + } + + return null; + } + + @Override + public long getGeometryID() { + return 0; + } + } // private static final class GeometryCursorForPolygon extends GeometryCursor { // private GeodesicBufferer m_bufferer; @@ -334,135 +338,135 @@ public long getGeometryID() { // } // - private GeodesicBufferer(ProgressTracker progress_tracker) { - m_buffer_commands = new ArrayList(0); - m_progress_tracker = progress_tracker; - m_tolerance = 0; - m_small_tolerance = 0; - m_filter_tolerance = 0; - m_distance = 0; - m_original_geom_type = Geometry.GeometryType.Unknown; - m_abs_distance_reversed = 0; - m_abs_distance = 0; - m_densify_dist = -1; - m_dA = -1; - m_b_output_loops = true; - m_bfilter = true; + private GeodesicBufferer(ProgressTracker progress_tracker) { + m_buffer_commands = new ArrayList(0); + m_progress_tracker = progress_tracker; + m_tolerance = 0; + m_small_tolerance = 0; + m_filter_tolerance = 0; + m_distance = 0; + m_original_geom_type = Geometry.GeometryType.Unknown; + m_abs_distance_reversed = 0; + m_abs_distance = 0; + m_densify_dist = -1; + m_dA = -1; + m_b_output_loops = true; + m_bfilter = true; // m_a = 6378137.0; // radius of spheroid for WGS_1984 // m_e2 = 0.0066943799901413165; // ellipticity for WGS_1984 - } - - private Geometry buffer_() { - int gt = m_geometry.getType().value(); - if (Geometry.isSegment(gt)) {// convert segment to a polyline and repeat - // the call - Polyline polyline = new Polyline(m_geometry.getDescription()); - polyline.addSegment((Segment) (m_geometry), true); - m_geometry = polyline; - return buffer_(); - } - - if (m_distance <= m_tolerance) { - if (Geometry.isArea(gt)) { - //TODO add geodetic getWidth and getHeight for Envelope - if (m_distance <= 0) { - // if the geometry is area type, then the negative distance - // may produce a degenerate shape. Check for this and return - // empty geometry. - Envelope2D env = new Envelope2D(); - m_geometry.queryEnvelope2D(env); - - if (GeoDist.getEnvWidth(m_spatialReference.getMajorAxis(), m_spatialReference.getEccentricitySquared(), env) <= -m_distance * 2 || - GeoDist.getEnvHeight(m_spatialReference.getMajorAxis(), m_spatialReference.getEccentricitySquared(), env) <= m_distance * 2) { - return new Polygon(m_geometry.getDescription()); - } - } - } else { - return new Polygon(m_geometry.getDescription()); - // return an empty polygon for distance <= m_tolerance - // and any input other than polygon. - } - } - - // Complex cases: - switch (m_geometry.getType().value()) { - case Geometry.GeometryType.Point: - return bufferPoint_(); - case Geometry.GeometryType.MultiPoint: - return bufferMultiPoint_(); - case Geometry.GeometryType.Polyline: - return bufferPolyline_(); - case Geometry.GeometryType.Polygon: - return bufferPolygon_(); - case Geometry.GeometryType.Envelope: - return bufferEnvelope_(); - default: - throw GeometryException.GeometryInternalError(); - } - } - - private Geometry bufferPolyline_() { - if (isDegenerateGeometry_(m_geometry)) { - Point point = new Point(); - ((MultiVertexGeometry) m_geometry).getPointByVal(0, point); - Envelope2D env2D = new Envelope2D(); - m_geometry.queryEnvelope2D(env2D); - // TODO get center Geodesic - point.setXY(env2D.getCenter()); - return bufferPoint_(point); - } - - // TODO cannot use preparePolyline until there is a Geodetic Generalize - //m_geometry = preparePolyline_((Polyline) (m_geometry)); - - GeometryCursorForPolyline cursor = new GeometryCursorForPolyline(this, m_bfilter); - GeometryCursor union_cursor = ((OperatorUnion) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.Union)).execute( - cursor, - m_spatialReference, - m_progress_tracker); - Geometry result = union_cursor.next(); - return result; - } - - - private Geometry bufferPolygon_() { - if (m_distance == 0) - return m_geometry;// return input to the output. - - OperatorSimplify simplify = (OperatorSimplify) OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Simplify); - - m_geometry = simplify.execute(m_geometry, null, false, - m_progress_tracker); - - Polygon poly = (Polygon) (m_geometry); - OperatorBoundary boundaryOp = (OperatorBoundary) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.Boundary); - SimpleGeometryCursor inputPolygonCursor = new SimpleGeometryCursor(m_geometry); - GeometryCursor boundaryLocalCursor = boundaryOp.execute(inputPolygonCursor, null); - OperatorGeodesicBuffer geodesicOp = (OperatorGeodesicBuffer) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.GeodesicBuffer); - double[] distances = new double[1]; - distances[0] = m_abs_distance; - GeometryCursor bufferedBoundaryCursor = geodesicOp.execute(boundaryLocalCursor, m_spatialReference, 0, distances, m_densify_dist, false, true, m_progress_tracker); - if (m_distance < 0) { - OperatorDifference differenceOp = (OperatorDifference) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.Difference); - SimpleGeometryCursor subtractee = new SimpleGeometryCursor(m_geometry); - GeometryCursor negativeBufferedGeom = differenceOp.execute(subtractee, bufferedBoundaryCursor, m_spatialReference, m_progress_tracker); + } + + private Geometry buffer_() { + int gt = m_geometry.getType().value(); + if (Geometry.isSegment(gt)) {// convert segment to a polyline and repeat + // the call + Polyline polyline = new Polyline(m_geometry.getDescription()); + polyline.addSegment((Segment) (m_geometry), true); + m_geometry = polyline; + return buffer_(); + } + + if (m_distance <= m_tolerance) { + if (Geometry.isArea(gt)) { + //TODO add geodetic getWidth and getHeight for Envelope + if (m_distance <= 0) { + // if the geometry is area type, then the negative distance + // may produce a degenerate shape. Check for this and return + // empty geometry. + Envelope2D env = new Envelope2D(); + m_geometry.queryEnvelope2D(env); + + if (GeoDist.getEnvWidth(m_spatialReference.getMajorAxis(), m_spatialReference.getEccentricitySquared(), env) <= -m_distance * 2 || + GeoDist.getEnvHeight(m_spatialReference.getMajorAxis(), m_spatialReference.getEccentricitySquared(), env) <= m_distance * 2) { + return new Polygon(m_geometry.getDescription()); + } + } + } else { + return new Polygon(m_geometry.getDescription()); + // return an empty polygon for distance <= m_tolerance + // and any input other than polygon. + } + } + + // Complex cases: + switch (m_geometry.getType().value()) { + case Geometry.GeometryType.Point: + return bufferPoint_(); + case Geometry.GeometryType.MultiPoint: + return bufferMultiPoint_(); + case Geometry.GeometryType.Polyline: + return bufferPolyline_(); + case Geometry.GeometryType.Polygon: + return bufferPolygon_(); + case Geometry.GeometryType.Envelope: + return bufferEnvelope_(); + default: + throw GeometryException.GeometryInternalError(); + } + } + + private Geometry bufferPolyline_() { + if (isDegenerateGeometry_(m_geometry)) { + Point point = new Point(); + ((MultiVertexGeometry) m_geometry).getPointByVal(0, point); + Envelope2D env2D = new Envelope2D(); + m_geometry.queryEnvelope2D(env2D); + // TODO get center Geodesic + point.setXY(env2D.getCenter()); + return bufferPoint_(point); + } + + // TODO cannot use preparePolyline until there is a Geodetic Generalize + //m_geometry = preparePolyline_((Polyline) (m_geometry)); + + GeometryCursorForPolyline cursor = new GeometryCursorForPolyline(this, m_bfilter); + GeometryCursor union_cursor = ((OperatorUnion) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.Union)).execute( + cursor, + m_spatialReference, + m_progress_tracker); + Geometry result = union_cursor.next(); + return result; + } + + + private Geometry bufferPolygon_() { + if (m_distance == 0) + return m_geometry;// return input to the output. + + OperatorSimplify simplify = (OperatorSimplify) OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Simplify); + + m_geometry = simplify.execute(m_geometry, null, false, + m_progress_tracker); + + Polygon poly = (Polygon) (m_geometry); + OperatorBoundary boundaryOp = (OperatorBoundary) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.Boundary); + SimpleGeometryCursor inputPolygonCursor = new SimpleGeometryCursor(m_geometry); + GeometryCursor boundaryLocalCursor = boundaryOp.execute(inputPolygonCursor, null); + OperatorGeodesicBuffer geodesicOp = (OperatorGeodesicBuffer) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.GeodesicBuffer); + double[] distances = new double[1]; + distances[0] = m_abs_distance; + GeometryCursor bufferedBoundaryCursor = geodesicOp.execute(boundaryLocalCursor, m_spatialReference, 0, distances, m_densify_dist, false, true, m_progress_tracker); + if (m_distance < 0) { + OperatorDifference differenceOp = (OperatorDifference) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.Difference); + SimpleGeometryCursor subtractee = new SimpleGeometryCursor(m_geometry); + GeometryCursor negativeBufferedGeom = differenceOp.execute(subtractee, bufferedBoundaryCursor, m_spatialReference, m_progress_tracker); // Polygon buffered_result = bufferPolygonImpl_(poly, 0, // poly.getPathCount()); // return simplify.execute(buffered_result, m_spatialReference, false, // m_progress_tracker); - return negativeBufferedGeom.next(); - } else { - if (isDegenerateGeometry_(m_geometry)) { - Point point = new Point(); - ((MultiVertexGeometry) m_geometry).getPointByVal(0, point); - Envelope2D env2D = new Envelope2D(); - m_geometry.queryEnvelope2D(env2D); - // TODO get center Geodesic - point.setXY(env2D.getCenter()); - return bufferPoint_(point); - } - return ((OperatorUnion) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.Union)).execute(bufferedBoundaryCursor.next(), m_geometry, m_spatialReference, null); + return negativeBufferedGeom.next(); + } else { + if (isDegenerateGeometry_(m_geometry)) { + Point point = new Point(); + ((MultiVertexGeometry) m_geometry).getPointByVal(0, point); + Envelope2D env2D = new Envelope2D(); + m_geometry.queryEnvelope2D(env2D); + // TODO get center Geodesic + point.setXY(env2D.getCenter()); + return bufferPoint_(point); + } + return ((OperatorUnion) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.Union)).execute(bufferedBoundaryCursor.next(), m_geometry, m_spatialReference, null); // // For the positive distance we need to process polygon in the parts // // such that each exterior ring with holes is processed separatelly. // GeometryCursorForPolygon cursor = new GeometryCursorForPolygon(this); @@ -471,8 +475,8 @@ private Geometry bufferPolygon_() { // cursor, m_spatialReference, m_progress_tracker); // Geometry result = union_cursor.next(); // return result; - } - } + } + } // // private Polygon bufferPolygonImpl_(Polygon input_geom, int ipath_begin, // int ipath_end) { @@ -670,55 +674,55 @@ private Geometry bufferPolygon_() { // } // - private Geometry bufferPoint_() { - return bufferPoint_((Point) (m_geometry)); - } - - private Geometry bufferPoint_(Point point) { - assert (m_distance > 0); - Polygon resultPolygon = new Polygon(m_geometry.getDescription()); - addCircle_((MultiPathImpl) resultPolygon._getImpl(), point); - return setStrongSimple_(resultPolygon); - } - - private Geometry bufferMultiPoint_() { - assert (m_distance > 0); - GeometryCursorForMultiPoint mpCursor = new GeometryCursorForMultiPoint( - (MultiPoint) m_geometry, - m_distance, - m_spatialReference, - m_densify_dist, - m_max_vertex_in_complete_circle, - m_progress_tracker); - // TODO is this union necessary??!??!??! - GeometryCursor c = ((OperatorUnion) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.Union)).execute( - mpCursor, - m_spatialReference, - m_progress_tracker); - return c.next(); - } - - private Geometry bufferEnvelope_() { - Polygon polygon = new Polygon(m_geometry.getDescription()); - if (m_distance <= 0) { - if (m_distance == 0) - polygon.addEnvelope((Envelope) (m_geometry), false); - else { - Envelope2D env = new Envelope2D(); - m_geometry.queryEnvelope2D(env); - GeoDist.inflateEnv2D(m_spatialReference.getMajorAxis(), m_spatialReference.getEccentricitySquared(), env, m_distance, m_distance); + private Geometry bufferPoint_() { + return bufferPoint_((Point) (m_geometry)); + } + + private Geometry bufferPoint_(Point point) { + assert (m_distance > 0); + Polygon resultPolygon = new Polygon(m_geometry.getDescription()); + addCircle_((MultiPathImpl) resultPolygon._getImpl(), point); + return setStrongSimple_(resultPolygon); + } + + private Geometry bufferMultiPoint_() { + assert (m_distance > 0); + GeometryCursorForMultiPoint mpCursor = new GeometryCursorForMultiPoint( + (MultiPoint) m_geometry, + m_distance, + m_spatialReference, + m_densify_dist, + m_max_vertex_in_complete_circle, + m_progress_tracker); + // TODO is this union necessary??!??!??! + GeometryCursor c = ((OperatorUnion) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.Union)).execute( + mpCursor, + m_spatialReference, + m_progress_tracker); + return c.next(); + } + + private Geometry bufferEnvelope_() { + Polygon polygon = new Polygon(m_geometry.getDescription()); + if (m_distance <= 0) { + if (m_distance == 0) + polygon.addEnvelope((Envelope) (m_geometry), false); + else { + Envelope2D env = new Envelope2D(); + m_geometry.queryEnvelope2D(env); + GeoDist.inflateEnv2D(m_spatialReference.getMajorAxis(), m_spatialReference.getEccentricitySquared(), env, m_distance, m_distance); // env.inflate(m_distance, m_distance); - polygon.addEnvelope(env, false); - } + polygon.addEnvelope(env, false); + } - return polygon;// nothing is easier than negative buffer on the envelope. - } + return polygon;// nothing is easier than negative buffer on the envelope. + } - polygon.addEnvelope((Envelope) (m_geometry), false); - m_geometry = polygon; - return bufferPolygon_(); - //return bufferConvexPath_(polygon, 0); - } + polygon.addEnvelope((Envelope) (m_geometry), false); + m_geometry = polygon; + return bufferPolygon_(); + //return bufferConvexPath_(polygon, 0); + } // // private Polygon bufferConvexPath_(MultiPath src, int ipath) { // generateCircleTemplate_(); @@ -773,106 +777,106 @@ private Geometry bufferEnvelope_() { // return setWeakSimple_(resultPolygon); // } - private Polygon bufferPolylinePath_(Polyline polyline, int ipath, boolean bfilter) { - assert (m_distance != 0); - //TODO, circle template doesn't work with Geodesics (unless all circles are on the same line of latitude) + private Polygon bufferPolylinePath_(Polyline polyline, int ipath, boolean bfilter) { + assert (m_distance != 0); + //TODO, circle template doesn't work with Geodesics (unless all circles are on the same line of latitude) // generateCircleTemplate_(); - MultiPath input_multi_path = polyline; - MultiPathImpl mp_impl = (MultiPathImpl) (input_multi_path._getImpl()); - - if (mp_impl.getPathSize(ipath) < 1) - return null; - - if (isDegeneratePath_(mp_impl, ipath) && m_distance > 0) {// if a path - // is degenerate (almost a point), then we can draw a circle instead - // of it as a buffer and nobody would notice :) - - Point point = new Point(); - mp_impl.getPointByVal(mp_impl.getPathStart(ipath), point); - Envelope2D env2D = new Envelope2D(); - mp_impl.queryPathEnvelope2D(ipath, env2D); - point.setXY(env2D.getCenter()); - return (Polygon) (bufferPoint_(point)); - } - - Polyline result_polyline = new Polyline(polyline.getDescription()); - //TODO what is this commented out code? - // result_polyline.reserve((m_circle_template.size() / 10 + 4) * - // mp_impl.getPathSize(ipath)); - - MultiPathImpl result_mp = (MultiPathImpl) result_polyline._getImpl(); - boolean b_closed = mp_impl.isClosedPathInXYPlane(ipath); - - if (b_closed) { - bufferClosedPath_(input_multi_path, ipath, result_mp, bfilter, 1); - bufferClosedPath_(input_multi_path, ipath, result_mp, bfilter, -1); - } else { - Polyline tmpPoly = new Polyline(input_multi_path.getDescription()); - tmpPoly.addPath(input_multi_path, ipath, false); - ((MultiPathImpl) tmpPoly._getImpl()).addSegmentsFromPath( - (MultiPathImpl) input_multi_path._getImpl(), - ipath, - 0, - input_multi_path.getSegmentCount(ipath), - false); - bufferClosedPath_(tmpPoly, 0, result_mp, bfilter, 1); + MultiPath input_multi_path = polyline; + MultiPathImpl mp_impl = (MultiPathImpl) (input_multi_path._getImpl()); + + if (mp_impl.getPathSize(ipath) < 1) + return null; + + if (isDegeneratePath_(mp_impl, ipath) && m_distance > 0) {// if a path + // is degenerate (almost a point), then we can draw a circle instead + // of it as a buffer and nobody would notice :) + + Point point = new Point(); + mp_impl.getPointByVal(mp_impl.getPathStart(ipath), point); + Envelope2D env2D = new Envelope2D(); + mp_impl.queryPathEnvelope2D(ipath, env2D); + point.setXY(env2D.getCenter()); + return (Polygon) (bufferPoint_(point)); + } + + Polyline result_polyline = new Polyline(polyline.getDescription()); + //TODO what is this commented out code? + // result_polyline.reserve((m_circle_template.size() / 10 + 4) * + // mp_impl.getPathSize(ipath)); + + MultiPathImpl result_mp = (MultiPathImpl) result_polyline._getImpl(); + boolean b_closed = mp_impl.isClosedPathInXYPlane(ipath); + + if (b_closed) { + bufferClosedPath_(input_multi_path, ipath, result_mp, bfilter, 1); + bufferClosedPath_(input_multi_path, ipath, result_mp, bfilter, -1); + } else { + Polyline tmpPoly = new Polyline(input_multi_path.getDescription()); + tmpPoly.addPath(input_multi_path, ipath, false); + ((MultiPathImpl) tmpPoly._getImpl()).addSegmentsFromPath( + (MultiPathImpl) input_multi_path._getImpl(), + ipath, + 0, + input_multi_path.getSegmentCount(ipath), + false); + bufferClosedPath_(tmpPoly, 0, result_mp, bfilter, 1); // // Operator_factory_local::SaveJSONToTextFileDbg("c:/temp/buffer_prepare.txt", // // *result_polyline, nullptr); - } - - return bufferCleanup_(result_polyline, false); - } - - // Planar and Geodesic are equivalent - private void progress_() { - m_progress_counter++; - if (m_progress_counter % 1024 == 0) { - if ((m_progress_tracker != null) - && !(m_progress_tracker.progress(-1, -1))) - throw new RuntimeException("user_canceled"); - } - } - - - private Polygon bufferCleanup_(MultiPath multi_path, boolean simplify_result) { - double tol = simplify_result ? m_tolerance : m_small_tolerance; - String words = GeometryEngine.geometryToWkt((Polyline) multi_path, 0); - Polygon resultPolygon = (Polygon) (TopologicalOperations - .planarSimplify(multi_path, tol, true, !simplify_result, - m_progress_tracker)); - assert (InternalUtils.isWeakSimple(resultPolygon, 0.0)); - return resultPolygon; - } - - //TODO prepare this for Geodesic - private int calcN_(int minN) { - if (m_densify_dist == 0) - return m_max_vertex_in_complete_circle; - - double r = m_densify_dist * Math.abs(m_abs_distance_reversed); - double cos_a = 1 - r; - double N; - if (cos_a < -1) - N = minN; - else - N = 2.0 * Math.PI / Math.acos(cos_a) + 0.5; - - if (N < minN) - N = minN; - else if (N > m_max_vertex_in_complete_circle) - N = m_max_vertex_in_complete_circle; - - return (int) N; - } - - private void addJoin_(MultiPathImpl dst, - Point2D center, - Point2D arcStartPt, - Point2D arcEndPt, - boolean bStartPath, - boolean bFinishAtToPt) { - addArc_(dst, center, arcStartPt, arcEndPt, bStartPath, bFinishAtToPt); + } + + return bufferCleanup_(result_polyline, false); + } + + // Planar and Geodesic are equivalent + private void progress_() { + m_progress_counter++; + if (m_progress_counter % 1024 == 0) { + if ((m_progress_tracker != null) + && !(m_progress_tracker.progress(-1, -1))) + throw new RuntimeException("user_canceled"); + } + } + + + private Polygon bufferCleanup_(MultiPath multi_path, boolean simplify_result) { + double tol = simplify_result ? m_tolerance : m_small_tolerance; + String words = GeometryEngine.geometryToWkt((Polyline) multi_path, 0); + Polygon resultPolygon = (Polygon) (TopologicalOperations + .planarSimplify(multi_path, tol, true, !simplify_result, + m_progress_tracker)); + assert (InternalUtils.isWeakSimple(resultPolygon, 0.0)); + return resultPolygon; + } + + //TODO prepare this for Geodesic + private int calcN_(int minN) { + if (m_densify_dist == 0) + return m_max_vertex_in_complete_circle; + + double r = m_densify_dist * Math.abs(m_abs_distance_reversed); + double cos_a = 1 - r; + double N; + if (cos_a < -1) + N = minN; + else + N = 2.0 * Math.PI / Math.acos(cos_a) + 0.5; + + if (N < minN) + N = minN; + else if (N > m_max_vertex_in_complete_circle) + N = m_max_vertex_in_complete_circle; + + return (int) N; + } + + private void addJoin_(MultiPathImpl dst, + Point2D center, + Point2D arcStartPt, + Point2D arcEndPt, + boolean bStartPath, + boolean bFinishAtToPt) { + addArc_(dst, center, arcStartPt, arcEndPt, bStartPath, bFinishAtToPt); // v_1.sub(fromPt, center); // v_1.scale(m_abs_distance_reversed); @@ -935,682 +939,682 @@ private void addJoin_(MultiPathImpl dst, // if (bFinishAtToPt) { // dst.lineTo(toPt); // } - } - - private int bufferClosedPath_(Geometry input_geom, - int ipath, - MultiPathImpl result_mp, - boolean bfilter, - int dir) { - // Use temporary polyline for the path buffering. - EditShape edit_shape = new EditShape(); - int geom = edit_shape.addPathFromMultiPath((MultiPath) input_geom, ipath, true); - - //TODO not sure what filtering does - edit_shape.filterClosePoints(m_filter_tolerance, false, false); - - if (edit_shape.getPointCount(geom) < 2) { - // Got degenerate output. - // Wither bail out or - // produce a circle. - if (dir < 0) - return 1;// negative direction produces nothing. - - MultiPath mpIn = (MultiPath) input_geom; - // Add a circle - Point pt = new Point(); - mpIn.getPointByVal(mpIn.getPathStart(ipath), pt); - addCircle_(result_mp, pt); - return 1; - } - - assert (edit_shape.getFirstPath(geom) != -1); - assert (edit_shape.getFirstVertex(edit_shape.getFirstPath(geom)) != -1); - - //TODO this won't work with Geodesic operations!!! It will ruin the results + } + + private int bufferClosedPath_(Geometry input_geom, + int ipath, + MultiPathImpl result_mp, + boolean bfilter, + int dir) { + // Use temporary polyline for the path buffering. + EditShape edit_shape = new EditShape(); + int geom = edit_shape.addPathFromMultiPath((MultiPath) input_geom, ipath, true); + + //TODO not sure what filtering does + edit_shape.filterClosePoints(m_filter_tolerance, false, false); + + if (edit_shape.getPointCount(geom) < 2) { + // Got degenerate output. + // Wither bail out or + // produce a circle. + if (dir < 0) + return 1;// negative direction produces nothing. + + MultiPath mpIn = (MultiPath) input_geom; + // Add a circle + Point pt = new Point(); + mpIn.getPointByVal(mpIn.getPathStart(ipath), pt); + addCircle_(result_mp, pt); + return 1; + } + + assert (edit_shape.getFirstPath(geom) != -1); + assert (edit_shape.getFirstVertex(edit_shape.getFirstPath(geom)) != -1); + + //TODO this won't work with Geodesic operations!!! It will ruin the results // Point2D origin = edit_shape.getXY(edit_shape.getFirstVertex(edit_shape.getFirstPath(geom))); // Transformation2D tr = new Transformation2D(); // tr.setShift(-origin.x, -origin.y); // // move the path to origin for better accuracy in calculations. // edit_shape.applyTransformation(tr); - //TODO prepare filter for geodesics - //if (bfilter) { - if (false) { - // try removing the noise that does not contribute to the buffer. - int res_filter = filterPath_(edit_shape, geom, dir, true); - assert (res_filter == 1); - // Operator_factory_local::SaveJSONToTextFileDbg("c:/temp/buffer_filter.txt", - // *edit_shape.get_geometry(geom), nullptr); - if (edit_shape.getPointCount(geom) < 2) {// got degenerate output. - // Wither bail out or - // produce a circle. - if (dir < 0) - return 1;// negative direction produces nothing. - - MultiPath mpIn = (MultiPath) input_geom; - // Add a circle - Point pt = new Point(); - mpIn.getPointByVal(mpIn.getPathStart(ipath), pt); - addCircle_(result_mp, pt); - return 1; - } - } - - m_buffer_commands.clear(); - int path = edit_shape.getFirstPath(geom); - int ivert = edit_shape.getFirstVertex(path); - int iprev = dir == 1 ? edit_shape.getPrevVertex(ivert) : edit_shape.getNextVertex(ivert); - int inext = dir == 1 ? edit_shape.getNextVertex(ivert) : edit_shape.getPrevVertex(ivert); - boolean b_first = true; - - // current point - Point2D pt_current = new Point2D(); - // next point - Point2D pt_after = new Point2D(); - // previous point - Point2D pt_before = new Point2D(); - - - Point2D pt_left_prev = new Point2D(); - Point2D pt = new Point2D(); - Point2D pt1 = new Point2D(); - - Point2D v_after = new Point2D(); - Point2D v_before = new Point2D(); + //TODO prepare filter for geodesics + //if (bfilter) { + if (false) { + // try removing the noise that does not contribute to the buffer. + int res_filter = filterPath_(edit_shape, geom, dir, true); + assert (res_filter == 1); + // Operator_factory_local::SaveJSONToTextFileDbg("c:/temp/buffer_filter.txt", + // *edit_shape.get_geometry(geom), nullptr); + if (edit_shape.getPointCount(geom) < 2) {// got degenerate output. + // Wither bail out or + // produce a circle. + if (dir < 0) + return 1;// negative direction produces nothing. + + MultiPath mpIn = (MultiPath) input_geom; + // Add a circle + Point pt = new Point(); + mpIn.getPointByVal(mpIn.getPathStart(ipath), pt); + addCircle_(result_mp, pt); + return 1; + } + } + + m_buffer_commands.clear(); + int path = edit_shape.getFirstPath(geom); + int ivert = edit_shape.getFirstVertex(path); + int iprev = dir == 1 ? edit_shape.getPrevVertex(ivert) : edit_shape.getNextVertex(ivert); + int inext = dir == 1 ? edit_shape.getNextVertex(ivert) : edit_shape.getPrevVertex(ivert); + boolean b_first = true; + + // current point + Point2D pt_current = new Point2D(); + // next point + Point2D pt_after = new Point2D(); + // previous point + Point2D pt_before = new Point2D(); + + + Point2D pt_left_prev = new Point2D(); + Point2D pt = new Point2D(); + Point2D pt1 = new Point2D(); + + Point2D v_after = new Point2D(); + Point2D v_before = new Point2D(); // Point2D v_left = new Point2D(); // Point2D v_left_prev = new Point2D(); - PeDouble az12 = new PeDouble(); - PeDouble lam2 = new PeDouble(); - PeDouble phi2 = new PeDouble(); - - double abs_d = m_abs_distance; - int ncount = edit_shape.getPathSize(path); - - // write out buffer commands as a set of arcs and line segments. - // if we'd convert this directly to a polygon and draw using winding - // fill rule, we'd get the buffered result. - for (int index = 0; index < ncount; index++) { - edit_shape.getXY(inext, pt_after); - - if (b_first) { - // grab the first point - edit_shape.getXY(ivert, pt_current); - // get the previous point (TODO if polygon?!?) - edit_shape.getXY(iprev, pt_before); - - // not sure is this is the right direction. might want before to current - GeoDist.geodesic_distance_ngs(m_spatialReference.getMajorAxis(), m_spatialReference.getEccentricitySquared(), pt_before.x * DEG_TO_RAD, pt_before.y * DEG_TO_RAD, pt_current.x * DEG_TO_RAD, pt_current.y * DEG_TO_RAD, null, az12, null); - // not sure if this is the correct rotation (maybe should be -Math.PI/2.0) - GeoDist.geodesic_forward(m_spatialReference.getMajorAxis(), m_spatialReference.getEccentricitySquared(), pt_current.x * DEG_TO_RAD, pt_current.y * DEG_TO_RAD, abs_d, az12.val - Math.PI / 2.0, lam2, phi2); - pt_left_prev.x = lam2.val * RAD_TO_DEG; - pt_left_prev.y = phi2.val * RAD_TO_DEG; - - // move v_before position as if pt_current was origin - v_before.sub(pt_current, pt_before); - // change v_before into unit vector - v_before.normalize(); + PeDouble az12 = new PeDouble(); + PeDouble lam2 = new PeDouble(); + PeDouble phi2 = new PeDouble(); + + double abs_d = m_abs_distance; + int ncount = edit_shape.getPathSize(path); + + // write out buffer commands as a set of arcs and line segments. + // if we'd convert this directly to a polygon and draw using winding + // fill rule, we'd get the buffered result. + for (int index = 0; index < ncount; index++) { + edit_shape.getXY(inext, pt_after); + + if (b_first) { + // grab the first point + edit_shape.getXY(ivert, pt_current); + // get the previous point (TODO if polygon?!?) + edit_shape.getXY(iprev, pt_before); + + // not sure is this is the right direction. might want before to current + GeoDist.geodesic_distance_ngs(m_spatialReference.getMajorAxis(), m_spatialReference.getEccentricitySquared(), pt_before.x * DEG_TO_RAD, pt_before.y * DEG_TO_RAD, pt_current.x * DEG_TO_RAD, pt_current.y * DEG_TO_RAD, null, az12, null); + // not sure if this is the correct rotation (maybe should be -Math.PI/2.0) + GeoDist.geodesic_forward(m_spatialReference.getMajorAxis(), m_spatialReference.getEccentricitySquared(), pt_current.x * DEG_TO_RAD, pt_current.y * DEG_TO_RAD, abs_d, az12.val - Math.PI / 2.0, lam2, phi2); + pt_left_prev.x = lam2.val * RAD_TO_DEG; + pt_left_prev.y = phi2.val * RAD_TO_DEG; + + // move v_before position as if pt_current was origin + v_before.sub(pt_current, pt_before); + // change v_before into unit vector + v_before.normalize(); // // create unit vector that is 90 degree counter-clockwise of v_before // v_left_prev.leftPerpendicular(v_before); // // scale the left perpendicular vector by the distance // v_left_prev.scale(abs_d); // // create the pt left previous by shifting the left perpendicular vector by the current point // pt_left_prev.add(v_left_prev, pt_current); - } - - // not sure is this is the right direction. might want before to current - GeoDist.geodesic_distance_ngs(m_spatialReference.getMajorAxis(), m_spatialReference.getEccentricitySquared(), pt_current.x * DEG_TO_RAD, pt_current.y * DEG_TO_RAD, pt_after.x * DEG_TO_RAD, pt_after.y * DEG_TO_RAD, null, az12, null); - // not sure if this is the correct rotation (maybe should be -Math.PI/2.0) - GeoDist.geodesic_forward(m_spatialReference.getMajorAxis(), m_spatialReference.getEccentricitySquared(), pt_current.x * DEG_TO_RAD, pt_current.y * DEG_TO_RAD, abs_d, az12.val - Math.PI / 2.0, lam2, phi2); - pt.x = lam2.val * RAD_TO_DEG; - pt.y = phi2.val * RAD_TO_DEG; - - // v_after is the vector of pt_after with the pt_center at origin - v_after.sub(pt_after, pt_current); - // v_after is normalized to be a unit vector - v_after.normalize(); + } + + // not sure is this is the right direction. might want before to current + GeoDist.geodesic_distance_ngs(m_spatialReference.getMajorAxis(), m_spatialReference.getEccentricitySquared(), pt_current.x * DEG_TO_RAD, pt_current.y * DEG_TO_RAD, pt_after.x * DEG_TO_RAD, pt_after.y * DEG_TO_RAD, null, az12, null); + // not sure if this is the correct rotation (maybe should be -Math.PI/2.0) + GeoDist.geodesic_forward(m_spatialReference.getMajorAxis(), m_spatialReference.getEccentricitySquared(), pt_current.x * DEG_TO_RAD, pt_current.y * DEG_TO_RAD, abs_d, az12.val - Math.PI / 2.0, lam2, phi2); + pt.x = lam2.val * RAD_TO_DEG; + pt.y = phi2.val * RAD_TO_DEG; + + // v_after is the vector of pt_after with the pt_center at origin + v_after.sub(pt_after, pt_current); + // v_after is normalized to be a unit vector + v_after.normalize(); // // v_left is a perpendicular to the left of v_after vector, centered at pt_current // v_left.leftPerpendicular(v_after); // // scale v_left by the buffer distance // v_left.scale(abs_d); // // shift the vector back relative to pt_current // pt.add(pt_current, v_left); - // Use these two calculations to determine if the angle is concave or convex - double cross = v_before.crossProduct(v_after); - double dot = v_before.dotProduct(v_after); - boolean bDoJoin = cross < 0 || (dot < 0 && cross == 0); - - if (bDoJoin) { - // create an arc - m_buffer_commands.add( - new GeodesicBufferCommand( - pt_left_prev, - pt, - pt_current, - GeodesicBufferCommand.Flags.enum_arc, - m_buffer_commands.size() + 1, - m_buffer_commands.size() - 1)); - } else if (!pt_left_prev.isEqual(pt)) { - // create straight edge? - m_buffer_commands.add( - new GeodesicBufferCommand( - pt_left_prev, - pt_current, - m_buffer_commands.size() + 1, - m_buffer_commands.size() - 1, - "dummy")); - m_buffer_commands.add( - new GeodesicBufferCommand( - pt_current, - pt, - m_buffer_commands.size() + 1, - m_buffer_commands.size() - 1, - "dummy")); - } - - GeoDist.geodesic_forward(m_spatialReference.getMajorAxis(), m_spatialReference.getEccentricitySquared(), pt_after.x * DEG_TO_RAD, pt_after.y * DEG_TO_RAD, abs_d, az12.val - Math.PI / 2.0, lam2, phi2); - pt1.x = lam2.val * RAD_TO_DEG; - pt1.y = phi2.val * RAD_TO_DEG; + // Use these two calculations to determine if the angle is concave or convex + double cross = v_before.crossProduct(v_after); + double dot = v_before.dotProduct(v_after); + boolean bDoJoin = cross < 0 || (dot < 0 && cross == 0); + + if (bDoJoin) { + // create an arc + m_buffer_commands.add( + new GeodesicBufferCommand( + pt_left_prev, + pt, + pt_current, + GeodesicBufferCommand.Flags.enum_arc, + m_buffer_commands.size() + 1, + m_buffer_commands.size() - 1)); + } else if (!pt_left_prev.isEqual(pt)) { + // create straight edge? + m_buffer_commands.add( + new GeodesicBufferCommand( + pt_left_prev, + pt_current, + m_buffer_commands.size() + 1, + m_buffer_commands.size() - 1, + "dummy")); + m_buffer_commands.add( + new GeodesicBufferCommand( + pt_current, + pt, + m_buffer_commands.size() + 1, + m_buffer_commands.size() - 1, + "dummy")); + } + + GeoDist.geodesic_forward(m_spatialReference.getMajorAxis(), m_spatialReference.getEccentricitySquared(), pt_after.x * DEG_TO_RAD, pt_after.y * DEG_TO_RAD, abs_d, az12.val - Math.PI / 2.0, lam2, phi2); + pt1.x = lam2.val * RAD_TO_DEG; + pt1.y = phi2.val * RAD_TO_DEG; // pt1.add(pt_after, v_left); - m_buffer_commands.add( - new GeodesicBufferCommand( - pt, - pt1, - pt_current, - GeodesicBufferCommand.Flags.enum_line, - m_buffer_commands.size() + 1, - m_buffer_commands.size() - 1)); - - pt_left_prev.setCoords(pt1); + m_buffer_commands.add( + new GeodesicBufferCommand( + pt, + pt1, + pt_current, + GeodesicBufferCommand.Flags.enum_line, + m_buffer_commands.size() + 1, + m_buffer_commands.size() - 1)); + + pt_left_prev.setCoords(pt1); // v_left_prev.setCoords(v_left); - pt_before.setCoords(pt_current); - pt_current.setCoords(pt_after); - v_before.setCoords(v_after); - iprev = ivert; - ivert = inext; - b_first = false; - inext = dir == 1 ? edit_shape.getNextVertex(ivert) : edit_shape.getPrevVertex(ivert); - } - - m_buffer_commands.get(m_buffer_commands.size() - 1).m_next = 0; - m_buffer_commands.get(0).m_prev = m_buffer_commands.size() - 1; - processBufferCommands_(result_mp); + pt_before.setCoords(pt_current); + pt_current.setCoords(pt_after); + v_before.setCoords(v_after); + iprev = ivert; + ivert = inext; + b_first = false; + inext = dir == 1 ? edit_shape.getNextVertex(ivert) : edit_shape.getPrevVertex(ivert); + } + + m_buffer_commands.get(m_buffer_commands.size() - 1).m_next = 0; + m_buffer_commands.get(0).m_prev = m_buffer_commands.size() - 1; + processBufferCommands_(result_mp); // tr.setShift(origin.x, origin.y);// move the path to improve precision. // result_mp.applyTransformation(tr, result_mp.getPathCount() - 1); - return 1; - } - - private void processBufferCommands_(MultiPathImpl result_mp) { - int ifirst_seg = cleanupBufferCommands_(); - boolean first = true; - int iseg_next = ifirst_seg + 1; - for (int iseg = ifirst_seg; iseg_next != ifirst_seg; iseg = iseg_next) { - GeodesicBufferCommand command = m_buffer_commands.get(iseg); - iseg_next = command.m_next != -1 ? command.m_next : (iseg + 1) % m_buffer_commands.size(); - - if (command.m_type == 0) - continue;// deleted segment - - if (first) { - result_mp.startPath(command.m_from); - first = false; - } - - if (command.m_type == GeodesicBufferCommand.Flags.enum_arc) {// arc - addJoin_(result_mp, command.m_center, command.m_from, command.m_to, false, true); - } else { - result_mp.lineTo(command.m_to); - } - first = false; - } + return 1; + } + + private void processBufferCommands_(MultiPathImpl result_mp) { + int ifirst_seg = cleanupBufferCommands_(); + boolean first = true; + int iseg_next = ifirst_seg + 1; + for (int iseg = ifirst_seg; iseg_next != ifirst_seg; iseg = iseg_next) { + GeodesicBufferCommand command = m_buffer_commands.get(iseg); + iseg_next = command.m_next != -1 ? command.m_next : (iseg + 1) % m_buffer_commands.size(); + + if (command.m_type == 0) + continue;// deleted segment + + if (first) { + result_mp.startPath(command.m_from); + first = false; + } + + if (command.m_type == GeodesicBufferCommand.Flags.enum_arc) {// arc + addJoin_(result_mp, command.m_center, command.m_from, command.m_to, false, true); + } else { + result_mp.lineTo(command.m_to); + } + first = false; + } // if (result_mp.getPoint(0).getX() != result_mp.getPoint(result_mp.getPointCount() - 1).getX() && // result_mp.getPoint(0).getY() != result_mp.getPoint(result_mp.getPointCount() - 1).getY()) // result_mp.lineTo(result_mp.getPoint(0)); - } - - //TODO this seems to be fine for Geodesic vs Planar. The intersect test might be a little off, but this should work? - private int cleanupBufferCommands_() { - // The purpose of this function is to remove as many self intersections - // from the buffered shape as possible. - // The buffer works without cleanup also, but slower. - - if (m_helper_array == null) - m_helper_array = new Point2D[9]; - - int istart = 0; - for (int iseg = 0, nseg = m_buffer_commands.size(); iseg < nseg; ) { - GeodesicBufferCommand command = m_buffer_commands.get(iseg); - if ((command.m_type & GeodesicBufferCommand.Flags.enum_connection) != 0) { - //TODO put a breakpoint. needs test case - istart = iseg; - break; - } - - iseg = command.m_next; - } - - int iseg_next = istart + 1; - for (int iseg = istart; iseg_next != istart; iseg = iseg_next) { - GeodesicBufferCommand command = m_buffer_commands.get(iseg); - iseg_next = command.m_next; - int count = 1; - GeodesicBufferCommand command_next = null; - while (iseg_next != iseg) {// find next segement - command_next = m_buffer_commands.get(iseg_next); - if ((command_next.m_type & GeodesicBufferCommand.Flags.enum_connection) != 0) - break; - - iseg_next = command_next.m_next; - count++; - } - - if (count == 1) { - // Next segment starts where this one ends. Skip this case as it - // is simple. - assert (command.m_to.isEqual(command_next.m_from, 0.01)); + } + + //TODO this seems to be fine for Geodesic vs Planar. The intersect test might be a little off, but this should work? + private int cleanupBufferCommands_() { + // The purpose of this function is to remove as many self intersections + // from the buffered shape as possible. + // The buffer works without cleanup also, but slower. + + if (m_helper_array == null) + m_helper_array = new Point2D[9]; + + int istart = 0; + for (int iseg = 0, nseg = m_buffer_commands.size(); iseg < nseg; ) { + GeodesicBufferCommand command = m_buffer_commands.get(iseg); + if ((command.m_type & GeodesicBufferCommand.Flags.enum_connection) != 0) { + //TODO put a breakpoint. needs test case + istart = iseg; + break; + } + + iseg = command.m_next; + } + + int iseg_next = istart + 1; + for (int iseg = istart; iseg_next != istart; iseg = iseg_next) { + GeodesicBufferCommand command = m_buffer_commands.get(iseg); + iseg_next = command.m_next; + int count = 1; + GeodesicBufferCommand command_next = null; + while (iseg_next != iseg) {// find next segement + command_next = m_buffer_commands.get(iseg_next); + if ((command_next.m_type & GeodesicBufferCommand.Flags.enum_connection) != 0) + break; + + iseg_next = command_next.m_next; + count++; + } + + if (count == 1) { + // Next segment starts where this one ends. Skip this case as it + // is simple. + assert (command.m_to.isEqual(command_next.m_from, 0.01)); // assert (command.m_to.isEqual(command_next.m_from)); - continue; - } - - if ((command.m_type & command_next.m_type) == GeodesicBufferCommand.Flags.enum_line) {// simplest - // cleanup - // - - // intersect - // lines - if (m_helper_line_1 == null) { - m_helper_line_1 = new Line(); - m_helper_line_2 = new Line(); - } - m_helper_line_1.setStartXY(command.m_from); - m_helper_line_1.setEndXY(command.m_to); - m_helper_line_2.setStartXY(command_next.m_from); - m_helper_line_2.setEndXY(command_next.m_to); - - int count_ = m_helper_line_1.intersect(m_helper_line_2, - m_helper_array, null, null, m_small_tolerance); - if (count_ == 1) { - command.m_to.setCoords(m_helper_array[0]); - command_next.m_from.setCoords(m_helper_array[0]); - command.m_next = iseg_next;// skip until iseg_next - command_next.m_prev = iseg; - } else if (count_ == 2) {// TODO: this case needs improvement - } - } - } - - return istart; - } - - private boolean isGap_(Point2D pt_before, Point2D pt_current, - Point2D pt_after) { - Point2D v_gap = new Point2D(); - v_gap.sub(pt_after, pt_before); - double gap_length = v_gap.length(); - double sqr_delta = m_abs_distance * m_abs_distance - gap_length - * gap_length * 0.25; - if (sqr_delta > 0) { - double delta = Math.sqrt(sqr_delta); - v_gap.normalize(); - v_gap.rightPerpendicular(); - Point2D p = new Point2D(); - p.sub(pt_current, pt_before); - double d = p.dotProduct(v_gap); - if (d + delta >= m_abs_distance) { - return true; - } - } - - return false; - } - - private int filterPath_(EditShape edit_shape, - int geom, - int dir, - boolean closed) { - // **********************!!!!!!!!!!!!!!!!!!!!!!!!!!!! - // return 1; - - boolean bConvex = true; - for (int pass = 0; pass < 1; pass++) { - boolean b_filtered = false; - int ipath = edit_shape.getFirstPath(geom); - int isize = edit_shape.getPathSize(ipath); - if (isize == 0) - return 0; - - int ncount = isize; - if (isize < 3) - return 1; - - if (closed && !edit_shape.isClosedPath(ipath))// the path is closed - // only virtually - { - ncount = isize - 1; - } - - assert (dir == 1 || dir == -1); - int ivert = edit_shape.getFirstVertex(ipath); - if (!closed) - edit_shape.getNextVertex(ivert); - - int iprev = dir > 0 ? edit_shape.getPrevVertex(ivert) : edit_shape.getNextVertex(ivert); - int inext = dir > 0 ? edit_shape.getNextVertex(ivert) : edit_shape.getPrevVertex(ivert); - int ibefore = iprev; - boolean reload = true; - - Point2D pt_current = new Point2D(), pt_after = new Point2D(), pt_before = new Point2D(), pt_before_before = new Point2D(), pt_middle = new Point2D(), pt_gap_last = new Point2D( - 0, 0); - Point2D v_after = new Point2D(), v_before = new Point2D(), v_gap = new Point2D(); - Point2D temp = new Point2D(); - double abs_d = m_abs_distance; - - // When the path is open we cannot process the first and the last - // vertices, so we process size - 2. - // When the path is closed, we can process all vertices. - int iter_count = closed ? ncount : isize - 2; - int gap_counter = 0; - for (int iter = 0; iter < iter_count; ) { - edit_shape.getXY(inext, pt_after); - - if (reload) { - edit_shape.getXY(ivert, pt_current); - edit_shape.getXY(iprev, pt_before); - ibefore = iprev; - } - - v_before.sub(pt_current, pt_before); - v_before.normalize(); - - v_after.sub(pt_after, pt_current); - v_after.normalize(); - - if (ibefore == inext) { - break; - } - - double cross = v_before.crossProduct(v_after); - double dot = v_before.dotProduct(v_after); - boolean bDoJoin = cross < 0 || (dot < 0 && cross == 0); - boolean b_write = true; - if (!bDoJoin) { - if (isGap_(pt_before, pt_current, pt_after)) { - pt_gap_last.setCoords(pt_after); - b_write = false; - ++gap_counter; - b_filtered = true; - } - - bConvex = false; - } - - if (b_write) { - if (gap_counter > 0) { - for (; ; ) {// re-test back - int ibefore_before = dir > 0 ? edit_shape - .getPrevVertex(ibefore) : edit_shape - .getNextVertex(ibefore); - if (ibefore_before == ivert) - break; - - edit_shape.getXY(ibefore_before, pt_before_before); - if (isGap_(pt_before_before, pt_before, pt_gap_last)) { - pt_before.setCoords(pt_before_before); - ibefore = ibefore_before; - b_write = false; - ++gap_counter; - continue; - } else { - if (ibefore_before != inext - && isGap_(pt_before_before, pt_before, - pt_after) - && isGap_(pt_before_before, pt_current, - pt_after)) {// now the current - // point is a part - // of the gap also. - // We retest it. - pt_before.setCoords(pt_before_before); - ibefore = ibefore_before; - b_write = false; - ++gap_counter; - } - } - break; - } - } - - if (!b_write) - continue;// retest forward - - if (gap_counter > 0) { - // remove all but one gap vertices. - int p = dir > 0 ? edit_shape.getPrevVertex(iprev) - : edit_shape.getNextVertex(iprev); - for (int i = 1; i < gap_counter; i++) { - int pp = dir > 0 ? edit_shape.getPrevVertex(p) - : edit_shape.getNextVertex(p); - edit_shape.removeVertex(p, true); - p = pp; - } - - v_gap.sub(pt_current, pt_before); - double gap_length = v_gap.length(); - double sqr_delta = abs_d * abs_d - gap_length - * gap_length * 0.25; - double delta = Math.sqrt(sqr_delta); - if (abs_d - delta > m_densify_dist * 0.5) { - pt_middle.add(pt_before, pt_current); - pt_middle.scale(0.5); - v_gap.normalize(); - v_gap.rightPerpendicular(); - temp.setCoords(v_gap); - temp.scale(abs_d - delta); - pt_middle.add(temp); - edit_shape.setXY(iprev, pt_middle); - } else { - // the gap is too short to be considered. Can close - // it with the straight segment; - edit_shape.removeVertex(iprev, true); - } - - gap_counter = 0; - } - - pt_before.setCoords(pt_current); - ibefore = ivert; - } - - pt_current.setCoords(pt_after); - iprev = ivert; - ivert = inext; - // reload = false; - inext = dir > 0 ? edit_shape.getNextVertex(ivert) : edit_shape - .getPrevVertex(ivert); - iter++; - reload = false; - } - - if (gap_counter > 0) { - int p = dir > 0 ? edit_shape.getPrevVertex(iprev) : edit_shape - .getNextVertex(iprev); - for (int i = 1; i < gap_counter; i++) { - int pp = dir > 0 ? edit_shape.getPrevVertex(p) : edit_shape - .getNextVertex(p); - edit_shape.removeVertex(p, true); - p = pp; - } - - pt_middle.add(pt_before, pt_current); - pt_middle.scale(0.5); - - v_gap.sub(pt_current, pt_before); - double gap_length = v_gap.length(); - double sqr_delta = abs_d * abs_d - gap_length * gap_length - * 0.25; - assert (sqr_delta > 0); - double delta = Math.sqrt(sqr_delta); - v_gap.normalize(); - v_gap.rightPerpendicular(); - temp.setCoords(v_gap); - temp.scale(abs_d - delta); - pt_middle.add(temp); - edit_shape.setXY(iprev, pt_middle); - } - - edit_shape.filterClosePoints(m_filter_tolerance, false, false); - - if (!b_filtered) - break; - } - - return 1; - } - - private boolean isDegeneratePath_(MultiPathImpl mp_impl, int ipath) { - if (mp_impl.getPathSize(ipath) == 1) - return true; - Envelope2D env = new Envelope2D(); - mp_impl.queryPathEnvelope2D(ipath, env); - return isDegenerateEnv2D(env); - } - - private boolean isDegenerateEnv2D(Envelope2D env2D) { - double width = GeoDist.getEnvWidth(m_spatialReference.getMajorAxis(), m_spatialReference.getEccentricitySquared(), env2D); - double height = GeoDist.getEnvHeight(m_spatialReference.getMajorAxis(), m_spatialReference.getEccentricitySquared(), env2D); - - if (Math.max(width, height) < m_densify_dist * 0.5) - return true; - - return false; - } - - private boolean isDegenerateGeometry_(Geometry geom) { - Envelope2D env2D = new Envelope2D(); - geom.queryEnvelope2D(env2D); - return isDegenerateEnv2D(env2D); - } - - private Polyline preparePolyline_(Polyline input_geom) { - // Generalize it firstly using 25% of the densification deviation as a - // criterion. - //TODO create geodetic Geodetic Generalize - Polyline generalized_polyline = (Polyline) ((OperatorGeneralize) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.Generalize)).execute( - input_geom, - m_densify_dist * 0.25, - false, - m_progress_tracker); - - int path_point_count = 0; - for (int i = 0, npath = generalized_polyline.getPathCount(); i < npath; i++) { - path_point_count = Math.max(generalized_polyline.getPathSize(i), path_point_count); - } - - if (path_point_count < 32) { - m_bfilter = false; - return generalized_polyline; - } else { - m_bfilter = true; - // If we apply a filter to the polyline, then we have to resolve all - // self intersections. - Polyline simple_polyline = (Polyline) (TopologicalOperations.planarSimplify( - generalized_polyline, - m_small_tolerance, - false, - true, - m_progress_tracker)); - // Operator_factory_local::SaveJSONToTextFileDbg("c:/temp/buffer_simplify.txt", simple_polyline, nullptr); - return simple_polyline; - } - } - - - private void addArc_(MultiPathImpl dst, - Point2D center, - Point2D arcStartPt, - Point2D arcEndPt, - boolean bStartPath, - boolean bFinishArcEndPt) { - // TODO move this logic into the constructor, eh? - int N = calcN_(4); - int real_size = ((N + 3) / 4) * 4; - double dA = (2 * Math.PI) / real_size; - - //TODO this might be good for memory allocations? - // result_mp.reserve(real_size * 4); - - // center point - double lamCenter = center.x * DEG_TO_RAD; - double phiCenter = center.y * DEG_TO_RAD; - - double startAzimuth = 0.0; - - if (arcStartPt != null && arcEndPt != null) { - PeDouble az12 = new PeDouble(); - GeoDist.geodesic_distance_ngs( - m_spatialReference.getMajorAxis(), m_spatialReference.getEccentricitySquared(), lamCenter, phiCenter, - arcStartPt.x * DEG_TO_RAD, arcStartPt.y * DEG_TO_RAD, - null, az12, null); - startAzimuth = az12.val; - - GeoDist.geodesic_distance_ngs( - m_spatialReference.getMajorAxis(), m_spatialReference.getEccentricitySquared(), lamCenter, phiCenter, - arcEndPt.x * DEG_TO_RAD, arcEndPt.y * DEG_TO_RAD, - null, az12, null); - double endAzimuth = az12.val; - - if (startAzimuth < 0) - startAzimuth = Math.PI * 2 + startAzimuth; - if (endAzimuth < 0) - endAzimuth = Math.PI * 2 + endAzimuth; - double angleDifference = endAzimuth - startAzimuth; - if (endAzimuth < startAzimuth) - angleDifference = 2 * Math.PI - startAzimuth + endAzimuth; - - double ratio = angleDifference / (2 * Math.PI); - real_size = (int) Math.floor(real_size * ratio); - // change the angle to be distributed about the real_size interval - dA = angleDifference / ((double) real_size); - } - - - PeDouble lam2 = new PeDouble(); - PeDouble phi2 = new PeDouble(); - - if (bStartPath) { - GeoDist.geodesic_forward(m_spatialReference.getMajorAxis(), m_spatialReference.getEccentricitySquared(), lamCenter, phiCenter, m_abs_distance, startAzimuth, lam2, phi2); - dst.startPath(lam2.val * RAD_TO_DEG, phi2.val * RAD_TO_DEG); - if (arcEndPt == null) - arcEndPt = new Point2D(lam2.val * RAD_TO_DEG, phi2.val * RAD_TO_DEG); - } - startAzimuth += dA; - - for (int i = 1; i < real_size; i++) { - GeoDist.geodesic_forward(m_spatialReference.getMajorAxis(), m_spatialReference.getEccentricitySquared(), lamCenter, phiCenter, m_abs_distance, startAzimuth, lam2, phi2); - dst.lineTo(lam2.val * RAD_TO_DEG, phi2.val * RAD_TO_DEG); - startAzimuth += dA; - } - - if (bFinishArcEndPt) { - dst.lineTo(arcEndPt); - } - } - - - private void addCircle_(MultiPathImpl dst, Point point) { - addArc_(dst, point.getXY(), null, null, true, true); - } - - // Planar and Geodesic are equivalent - private static Polygon setWeakSimple_(Polygon poly) { - ((MultiPathImpl) poly._getImpl()).setIsSimple(MultiVertexGeometryImpl.GeometryXSimple.Weak, 0.0, false); - return poly; - } - - // Planar and Geodesic are equivalent - private Polygon setStrongSimple_(Polygon poly) { - ((MultiPathImpl) poly._getImpl()).setIsSimple(MultiVertexGeometryImpl.GeometryXSimple.Strong, m_tolerance, false); - ((MultiPathImpl) poly._getImpl())._updateOGCFlags(); - return poly; - } + continue; + } + + if ((command.m_type & command_next.m_type) == GeodesicBufferCommand.Flags.enum_line) {// simplest + // cleanup + // - + // intersect + // lines + if (m_helper_line_1 == null) { + m_helper_line_1 = new Line(); + m_helper_line_2 = new Line(); + } + m_helper_line_1.setStartXY(command.m_from); + m_helper_line_1.setEndXY(command.m_to); + m_helper_line_2.setStartXY(command_next.m_from); + m_helper_line_2.setEndXY(command_next.m_to); + + int count_ = m_helper_line_1.intersect(m_helper_line_2, + m_helper_array, null, null, m_small_tolerance); + if (count_ == 1) { + command.m_to.setCoords(m_helper_array[0]); + command_next.m_from.setCoords(m_helper_array[0]); + command.m_next = iseg_next;// skip until iseg_next + command_next.m_prev = iseg; + } else if (count_ == 2) {// TODO: this case needs improvement + } + } + } + + return istart; + } + + private boolean isGap_(Point2D pt_before, Point2D pt_current, + Point2D pt_after) { + Point2D v_gap = new Point2D(); + v_gap.sub(pt_after, pt_before); + double gap_length = v_gap.length(); + double sqr_delta = m_abs_distance * m_abs_distance - gap_length + * gap_length * 0.25; + if (sqr_delta > 0) { + double delta = Math.sqrt(sqr_delta); + v_gap.normalize(); + v_gap.rightPerpendicular(); + Point2D p = new Point2D(); + p.sub(pt_current, pt_before); + double d = p.dotProduct(v_gap); + if (d + delta >= m_abs_distance) { + return true; + } + } + + return false; + } + + private int filterPath_(EditShape edit_shape, + int geom, + int dir, + boolean closed) { + // **********************!!!!!!!!!!!!!!!!!!!!!!!!!!!! + // return 1; + + boolean bConvex = true; + for (int pass = 0; pass < 1; pass++) { + boolean b_filtered = false; + int ipath = edit_shape.getFirstPath(geom); + int isize = edit_shape.getPathSize(ipath); + if (isize == 0) + return 0; + + int ncount = isize; + if (isize < 3) + return 1; + + if (closed && !edit_shape.isClosedPath(ipath))// the path is closed + // only virtually + { + ncount = isize - 1; + } + + assert (dir == 1 || dir == -1); + int ivert = edit_shape.getFirstVertex(ipath); + if (!closed) + edit_shape.getNextVertex(ivert); + + int iprev = dir > 0 ? edit_shape.getPrevVertex(ivert) : edit_shape.getNextVertex(ivert); + int inext = dir > 0 ? edit_shape.getNextVertex(ivert) : edit_shape.getPrevVertex(ivert); + int ibefore = iprev; + boolean reload = true; + + Point2D pt_current = new Point2D(), pt_after = new Point2D(), pt_before = new Point2D(), pt_before_before = new Point2D(), pt_middle = new Point2D(), pt_gap_last = new Point2D( + 0, 0); + Point2D v_after = new Point2D(), v_before = new Point2D(), v_gap = new Point2D(); + Point2D temp = new Point2D(); + double abs_d = m_abs_distance; + + // When the path is open we cannot process the first and the last + // vertices, so we process size - 2. + // When the path is closed, we can process all vertices. + int iter_count = closed ? ncount : isize - 2; + int gap_counter = 0; + for (int iter = 0; iter < iter_count; ) { + edit_shape.getXY(inext, pt_after); + + if (reload) { + edit_shape.getXY(ivert, pt_current); + edit_shape.getXY(iprev, pt_before); + ibefore = iprev; + } + + v_before.sub(pt_current, pt_before); + v_before.normalize(); + + v_after.sub(pt_after, pt_current); + v_after.normalize(); + + if (ibefore == inext) { + break; + } + + double cross = v_before.crossProduct(v_after); + double dot = v_before.dotProduct(v_after); + boolean bDoJoin = cross < 0 || (dot < 0 && cross == 0); + boolean b_write = true; + if (!bDoJoin) { + if (isGap_(pt_before, pt_current, pt_after)) { + pt_gap_last.setCoords(pt_after); + b_write = false; + ++gap_counter; + b_filtered = true; + } + + bConvex = false; + } + + if (b_write) { + if (gap_counter > 0) { + for (; ; ) {// re-test back + int ibefore_before = dir > 0 ? edit_shape + .getPrevVertex(ibefore) : edit_shape + .getNextVertex(ibefore); + if (ibefore_before == ivert) + break; + + edit_shape.getXY(ibefore_before, pt_before_before); + if (isGap_(pt_before_before, pt_before, pt_gap_last)) { + pt_before.setCoords(pt_before_before); + ibefore = ibefore_before; + b_write = false; + ++gap_counter; + continue; + } else { + if (ibefore_before != inext + && isGap_(pt_before_before, pt_before, + pt_after) + && isGap_(pt_before_before, pt_current, + pt_after)) {// now the current + // point is a part + // of the gap also. + // We retest it. + pt_before.setCoords(pt_before_before); + ibefore = ibefore_before; + b_write = false; + ++gap_counter; + } + } + break; + } + } + + if (!b_write) + continue;// retest forward + + if (gap_counter > 0) { + // remove all but one gap vertices. + int p = dir > 0 ? edit_shape.getPrevVertex(iprev) + : edit_shape.getNextVertex(iprev); + for (int i = 1; i < gap_counter; i++) { + int pp = dir > 0 ? edit_shape.getPrevVertex(p) + : edit_shape.getNextVertex(p); + edit_shape.removeVertex(p, true); + p = pp; + } + + v_gap.sub(pt_current, pt_before); + double gap_length = v_gap.length(); + double sqr_delta = abs_d * abs_d - gap_length + * gap_length * 0.25; + double delta = Math.sqrt(sqr_delta); + if (abs_d - delta > m_densify_dist * 0.5) { + pt_middle.add(pt_before, pt_current); + pt_middle.scale(0.5); + v_gap.normalize(); + v_gap.rightPerpendicular(); + temp.setCoords(v_gap); + temp.scale(abs_d - delta); + pt_middle.add(temp); + edit_shape.setXY(iprev, pt_middle); + } else { + // the gap is too short to be considered. Can close + // it with the straight segment; + edit_shape.removeVertex(iprev, true); + } + + gap_counter = 0; + } + + pt_before.setCoords(pt_current); + ibefore = ivert; + } + + pt_current.setCoords(pt_after); + iprev = ivert; + ivert = inext; + // reload = false; + inext = dir > 0 ? edit_shape.getNextVertex(ivert) : edit_shape + .getPrevVertex(ivert); + iter++; + reload = false; + } + + if (gap_counter > 0) { + int p = dir > 0 ? edit_shape.getPrevVertex(iprev) : edit_shape + .getNextVertex(iprev); + for (int i = 1; i < gap_counter; i++) { + int pp = dir > 0 ? edit_shape.getPrevVertex(p) : edit_shape + .getNextVertex(p); + edit_shape.removeVertex(p, true); + p = pp; + } + + pt_middle.add(pt_before, pt_current); + pt_middle.scale(0.5); + + v_gap.sub(pt_current, pt_before); + double gap_length = v_gap.length(); + double sqr_delta = abs_d * abs_d - gap_length * gap_length + * 0.25; + assert (sqr_delta > 0); + double delta = Math.sqrt(sqr_delta); + v_gap.normalize(); + v_gap.rightPerpendicular(); + temp.setCoords(v_gap); + temp.scale(abs_d - delta); + pt_middle.add(temp); + edit_shape.setXY(iprev, pt_middle); + } + + edit_shape.filterClosePoints(m_filter_tolerance, false, false); + + if (!b_filtered) + break; + } + + return 1; + } + + private boolean isDegeneratePath_(MultiPathImpl mp_impl, int ipath) { + if (mp_impl.getPathSize(ipath) == 1) + return true; + Envelope2D env = new Envelope2D(); + mp_impl.queryPathEnvelope2D(ipath, env); + return isDegenerateEnv2D(env); + } + + private boolean isDegenerateEnv2D(Envelope2D env2D) { + double width = GeoDist.getEnvWidth(m_spatialReference.getMajorAxis(), m_spatialReference.getEccentricitySquared(), env2D); + double height = GeoDist.getEnvHeight(m_spatialReference.getMajorAxis(), m_spatialReference.getEccentricitySquared(), env2D); + + if (Math.max(width, height) < m_densify_dist * 0.5) + return true; + + return false; + } + + private boolean isDegenerateGeometry_(Geometry geom) { + Envelope2D env2D = new Envelope2D(); + geom.queryEnvelope2D(env2D); + return isDegenerateEnv2D(env2D); + } + + private Polyline preparePolyline_(Polyline input_geom) { + // Generalize it firstly using 25% of the densification deviation as a + // criterion. + //TODO create geodetic Geodetic Generalize + Polyline generalized_polyline = (Polyline) ((OperatorGeneralize) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.Generalize)).execute( + input_geom, + m_densify_dist * 0.25, + false, + m_progress_tracker); + + int path_point_count = 0; + for (int i = 0, npath = generalized_polyline.getPathCount(); i < npath; i++) { + path_point_count = Math.max(generalized_polyline.getPathSize(i), path_point_count); + } + + if (path_point_count < 32) { + m_bfilter = false; + return generalized_polyline; + } else { + m_bfilter = true; + // If we apply a filter to the polyline, then we have to resolve all + // self intersections. + Polyline simple_polyline = (Polyline) (TopologicalOperations.planarSimplify( + generalized_polyline, + m_small_tolerance, + false, + true, + m_progress_tracker)); + // Operator_factory_local::SaveJSONToTextFileDbg("c:/temp/buffer_simplify.txt", simple_polyline, nullptr); + return simple_polyline; + } + } + + + private void addArc_(MultiPathImpl dst, + Point2D center, + Point2D arcStartPt, + Point2D arcEndPt, + boolean bStartPath, + boolean bFinishArcEndPt) { + // TODO move this logic into the constructor, eh? + int N = calcN_(4); + int real_size = ((N + 3) / 4) * 4; + double dA = (2 * Math.PI) / real_size; + + //TODO this might be good for memory allocations? + // result_mp.reserve(real_size * 4); + + // center point + double lamCenter = center.x * DEG_TO_RAD; + double phiCenter = center.y * DEG_TO_RAD; + + double startAzimuth = 0.0; + + if (arcStartPt != null && arcEndPt != null) { + PeDouble az12 = new PeDouble(); + GeoDist.geodesic_distance_ngs( + m_spatialReference.getMajorAxis(), m_spatialReference.getEccentricitySquared(), lamCenter, phiCenter, + arcStartPt.x * DEG_TO_RAD, arcStartPt.y * DEG_TO_RAD, + null, az12, null); + startAzimuth = az12.val; + + GeoDist.geodesic_distance_ngs( + m_spatialReference.getMajorAxis(), m_spatialReference.getEccentricitySquared(), lamCenter, phiCenter, + arcEndPt.x * DEG_TO_RAD, arcEndPt.y * DEG_TO_RAD, + null, az12, null); + double endAzimuth = az12.val; + + if (startAzimuth < 0) + startAzimuth = Math.PI * 2 + startAzimuth; + if (endAzimuth < 0) + endAzimuth = Math.PI * 2 + endAzimuth; + double angleDifference = endAzimuth - startAzimuth; + if (endAzimuth < startAzimuth) + angleDifference = 2 * Math.PI - startAzimuth + endAzimuth; + + double ratio = angleDifference / (2 * Math.PI); + real_size = (int) Math.floor(real_size * ratio); + // change the angle to be distributed about the real_size interval + dA = angleDifference / ((double) real_size); + } + + + PeDouble lam2 = new PeDouble(); + PeDouble phi2 = new PeDouble(); + + if (bStartPath) { + GeoDist.geodesic_forward(m_spatialReference.getMajorAxis(), m_spatialReference.getEccentricitySquared(), lamCenter, phiCenter, m_abs_distance, startAzimuth, lam2, phi2); + dst.startPath(lam2.val * RAD_TO_DEG, phi2.val * RAD_TO_DEG); + if (arcEndPt == null) + arcEndPt = new Point2D(lam2.val * RAD_TO_DEG, phi2.val * RAD_TO_DEG); + } + startAzimuth += dA; + + for (int i = 1; i < real_size; i++) { + GeoDist.geodesic_forward(m_spatialReference.getMajorAxis(), m_spatialReference.getEccentricitySquared(), lamCenter, phiCenter, m_abs_distance, startAzimuth, lam2, phi2); + dst.lineTo(lam2.val * RAD_TO_DEG, phi2.val * RAD_TO_DEG); + startAzimuth += dA; + } + + if (bFinishArcEndPt) { + dst.lineTo(arcEndPt); + } + } + + + private void addCircle_(MultiPathImpl dst, Point point) { + addArc_(dst, point.getXY(), null, null, true, true); + } + + // Planar and Geodesic are equivalent + private static Polygon setWeakSimple_(Polygon poly) { + ((MultiPathImpl) poly._getImpl()).setIsSimple(MultiVertexGeometryImpl.GeometryXSimple.Weak, 0.0, false); + return poly; + } + + // Planar and Geodesic are equivalent + private Polygon setStrongSimple_(Polygon poly) { + ((MultiPathImpl) poly._getImpl()).setIsSimple(MultiVertexGeometryImpl.GeometryXSimple.Strong, m_tolerance, false); + ((MultiPathImpl) poly._getImpl())._updateOGCFlags(); + return poly; + } } diff --git a/src/main/java/com/esri/core/geometry/GeodesicDensifier.java b/src/main/java/com/esri/core/geometry/GeodesicDensifier.java index 3ef2cd25..83750d0d 100644 --- a/src/main/java/com/esri/core/geometry/GeodesicDensifier.java +++ b/src/main/java/com/esri/core/geometry/GeodesicDensifier.java @@ -4,169 +4,169 @@ * Created by davidraleigh on 2/24/16. */ class GeodesicDensifier { - static Geometry densifyByLength(Geometry geom, SpatialReference sr, double maxLength, ProgressTracker progressTracker) { - if (geom.isEmpty() || geom.getDimension() < 1) - return geom; - - int geometryType = geom.getType().value(); - - GeodesicDensifier geodesicDensifier = new GeodesicDensifier(maxLength, sr, progressTracker); - // TODO implement IsMultiPath and remove Polygon and Polyline call to - // match Native - // if (Geometry.IsMultiPath(geometryType)) - if (geometryType == Geometry.GeometryType.Polygon) - return geodesicDensifier.densifyMultiPath((MultiPath) geom); - else if (Geometry.GeometryType.Polyline == geometryType) - return geodesicDensifier.densifyMultiPath((MultiPath) geom); - else if (Geometry.isSegment(geometryType)) - return geodesicDensifier.densifySegment((Segment) geom); - else if (geometryType == Geometry.GeometryType.Envelope) - return geodesicDensifier.densifyEnvelope((Envelope) geom); - else - // TODO fix geometry exception to match native implementation - throw GeometryException.GeometryInternalError();// GEOMTHROW(internal_error); - } - - GeodesicDensifier(double maxLength, SpatialReference sr, ProgressTracker progressTracker) { - m_startPoint = new Point(); - m_endPoint = new Point(); - m_maxLength = maxLength; - - // sr is used to define these: - m_a = sr.getMajorAxis(); // radius of spheroid for WGS_1984 - m_e2 = sr.getEccentricitySquared(); // ellipticity for WGS_1984 - m_rpu = Math.PI / 180.0; - m_dpu = 180.0 / Math.PI; - } - - private Point m_startPoint; - private Point m_endPoint; - private double m_maxLength; - private double m_a; - private double m_e2; - private double m_rpu; - private double m_dpu; - - - private double geodesicDistanceOnWGS84(Point2D startPt2D, Point2D endPt2D) { - m_startPoint.setXY(startPt2D); - m_endPoint.setXY(endPt2D); - return SpatialReferenceImpl.geodesicDistanceOnWGS84Impl(m_startPoint, m_endPoint); - } - - private double geodesicDistanceOnWGS84(Segment segment) { - m_startPoint.setXY(segment.getStartXY()); - m_endPoint.setXY(segment.getEndXY()); - return SpatialReferenceImpl.geodesicDistanceOnWGS84Impl(m_startPoint, m_endPoint); - } - - private Geometry densifySegment(Segment geom) { - double length = geodesicDistanceOnWGS84(geom); - if (length <= m_maxLength) - return geom; - - Polyline polyline = new Polyline(geom.getDescription()); - polyline.addSegment(geom, true); - return densifyMultiPath(polyline); - } - - private Geometry densifyEnvelope(Envelope geom) { - Polygon polygon = new Polygon(geom.getDescription()); - polygon.addEnvelope(geom, false); - - Envelope2D env2D = new Envelope2D(); - geom.queryEnvelope2D(env2D); - double wTop = geodesicDistanceOnWGS84(env2D.getUpperLeft(), env2D.getUpperRight()); - double wBottom = geodesicDistanceOnWGS84(env2D.getLowerLeft(), env2D.getLowerRight()); - double height = geodesicDistanceOnWGS84(env2D.getUpperLeft(), env2D.getLowerLeft());// height on right is same as left. meridians are geodesics - - if (wTop <= m_maxLength && wBottom <= m_maxLength && height <= m_maxLength) - return polygon; - - return densifyMultiPath(polygon); - } - - private Geometry densifyMultiPath(MultiPath geom) { - PeDouble distanceMeters = new PeDouble(); - PeDouble az12 = new PeDouble(); - PeDouble lam2 = new PeDouble(); - PeDouble phi2 = new PeDouble(); - - - MultiPath densifiedPoly = (MultiPath) geom.createInstance(); - SegmentIterator iter = geom.querySegmentIterator(); - while (iter.nextPath()) { - boolean bStartNewPath = true; - while (iter.hasNextSegment()) { - Segment seg = iter.nextSegment(); - if (seg.getType().value() != Geometry.GeometryType.Line) - throw new GeometryException("curve densify not implemented"); - - boolean bIsClosing = iter.isClosingSegment(); - - // also get the segment's azimuth - GeoDist.geodesic_distance_ngs( - m_a, - m_e2, - seg.getStartX() * m_rpu, - seg.getStartY() * m_rpu, - seg.getEndX() * m_rpu, - seg.getEndY() * m_rpu, - distanceMeters, - az12, - null); - - if (distanceMeters.val > m_maxLength) {// need to split - double dcount = Math.ceil(distanceMeters.val / m_maxLength); - double distInterval = distanceMeters.val / dcount; - - Point point = new Point(geom.getDescription());// LOCALREFCLASS1(Point, - // VertexDescription, - // point, - // geom.getDescription()); - if (bStartNewPath) { - bStartNewPath = false; - seg.queryStart(point); - densifiedPoly.startPath(point); - } - - int n = (int) dcount - 1; - double distanceAlongGeodesic = 0.0; - - for (int i = 0; i < n; i++) { - distanceAlongGeodesic += distInterval; - GeoDist.geodesic_forward( - m_a, - m_e2, - seg.getStartX() * m_rpu, - seg.getStartY() * m_rpu, - distanceAlongGeodesic, - az12.val, - lam2, - phi2); - - densifiedPoly.lineTo(lam2.val * m_dpu, phi2.val * m_dpu); - } - - if (!bIsClosing) { - seg.queryEnd(point); - densifiedPoly.lineTo(point); - } else { - densifiedPoly.closePathWithLine(); - } - - bStartNewPath = false; - } else { - if (!bIsClosing) - densifiedPoly.addSegment(seg, bStartNewPath); - else - densifiedPoly.closePathWithLine(); - - bStartNewPath = false; - } - } - } - - return densifiedPoly; - } + static Geometry densifyByLength(Geometry geom, SpatialReference sr, double maxLength, ProgressTracker progressTracker) { + if (geom.isEmpty() || geom.getDimension() < 1) + return geom; + + int geometryType = geom.getType().value(); + + GeodesicDensifier geodesicDensifier = new GeodesicDensifier(maxLength, sr, progressTracker); + // TODO implement IsMultiPath and remove Polygon and Polyline call to + // match Native + // if (Geometry.IsMultiPath(geometryType)) + if (geometryType == Geometry.GeometryType.Polygon) + return geodesicDensifier.densifyMultiPath((MultiPath) geom); + else if (Geometry.GeometryType.Polyline == geometryType) + return geodesicDensifier.densifyMultiPath((MultiPath) geom); + else if (Geometry.isSegment(geometryType)) + return geodesicDensifier.densifySegment((Segment) geom); + else if (geometryType == Geometry.GeometryType.Envelope) + return geodesicDensifier.densifyEnvelope((Envelope) geom); + else + // TODO fix geometry exception to match native implementation + throw GeometryException.GeometryInternalError();// GEOMTHROW(internal_error); + } + + GeodesicDensifier(double maxLength, SpatialReference sr, ProgressTracker progressTracker) { + m_startPoint = new Point(); + m_endPoint = new Point(); + m_maxLength = maxLength; + + // sr is used to define these: + m_a = sr.getMajorAxis(); // radius of spheroid for WGS_1984 + m_e2 = sr.getEccentricitySquared(); // ellipticity for WGS_1984 + m_rpu = Math.PI / 180.0; + m_dpu = 180.0 / Math.PI; + } + + private Point m_startPoint; + private Point m_endPoint; + private double m_maxLength; + private double m_a; + private double m_e2; + private double m_rpu; + private double m_dpu; + + + private double geodesicDistanceOnWGS84(Point2D startPt2D, Point2D endPt2D) { + m_startPoint.setXY(startPt2D); + m_endPoint.setXY(endPt2D); + return SpatialReferenceImpl.geodesicDistanceOnWGS84Impl(m_startPoint, m_endPoint); + } + + private double geodesicDistanceOnWGS84(Segment segment) { + m_startPoint.setXY(segment.getStartXY()); + m_endPoint.setXY(segment.getEndXY()); + return SpatialReferenceImpl.geodesicDistanceOnWGS84Impl(m_startPoint, m_endPoint); + } + + private Geometry densifySegment(Segment geom) { + double length = geodesicDistanceOnWGS84(geom); + if (length <= m_maxLength) + return geom; + + Polyline polyline = new Polyline(geom.getDescription()); + polyline.addSegment(geom, true); + return densifyMultiPath(polyline); + } + + private Geometry densifyEnvelope(Envelope geom) { + Polygon polygon = new Polygon(geom.getDescription()); + polygon.addEnvelope(geom, false); + + Envelope2D env2D = new Envelope2D(); + geom.queryEnvelope2D(env2D); + double wTop = geodesicDistanceOnWGS84(env2D.getUpperLeft(), env2D.getUpperRight()); + double wBottom = geodesicDistanceOnWGS84(env2D.getLowerLeft(), env2D.getLowerRight()); + double height = geodesicDistanceOnWGS84(env2D.getUpperLeft(), env2D.getLowerLeft());// height on right is same as left. meridians are geodesics + + if (wTop <= m_maxLength && wBottom <= m_maxLength && height <= m_maxLength) + return polygon; + + return densifyMultiPath(polygon); + } + + private Geometry densifyMultiPath(MultiPath geom) { + PeDouble distanceMeters = new PeDouble(); + PeDouble az12 = new PeDouble(); + PeDouble lam2 = new PeDouble(); + PeDouble phi2 = new PeDouble(); + + + MultiPath densifiedPoly = (MultiPath) geom.createInstance(); + SegmentIterator iter = geom.querySegmentIterator(); + while (iter.nextPath()) { + boolean bStartNewPath = true; + while (iter.hasNextSegment()) { + Segment seg = iter.nextSegment(); + if (seg.getType().value() != Geometry.GeometryType.Line) + throw new GeometryException("curve densify not implemented"); + + boolean bIsClosing = iter.isClosingSegment(); + + // also get the segment's azimuth + GeoDist.geodesic_distance_ngs( + m_a, + m_e2, + seg.getStartX() * m_rpu, + seg.getStartY() * m_rpu, + seg.getEndX() * m_rpu, + seg.getEndY() * m_rpu, + distanceMeters, + az12, + null); + + if (distanceMeters.val > m_maxLength) {// need to split + double dcount = Math.ceil(distanceMeters.val / m_maxLength); + double distInterval = distanceMeters.val / dcount; + + Point point = new Point(geom.getDescription());// LOCALREFCLASS1(Point, + // VertexDescription, + // point, + // geom.getDescription()); + if (bStartNewPath) { + bStartNewPath = false; + seg.queryStart(point); + densifiedPoly.startPath(point); + } + + int n = (int) dcount - 1; + double distanceAlongGeodesic = 0.0; + + for (int i = 0; i < n; i++) { + distanceAlongGeodesic += distInterval; + GeoDist.geodesic_forward( + m_a, + m_e2, + seg.getStartX() * m_rpu, + seg.getStartY() * m_rpu, + distanceAlongGeodesic, + az12.val, + lam2, + phi2); + + densifiedPoly.lineTo(lam2.val * m_dpu, phi2.val * m_dpu); + } + + if (!bIsClosing) { + seg.queryEnd(point); + densifiedPoly.lineTo(point); + } else { + densifiedPoly.closePathWithLine(); + } + + bStartNewPath = false; + } else { + if (!bIsClosing) + densifiedPoly.addSegment(seg, bStartNewPath); + else + densifiedPoly.closePathWithLine(); + + bStartNewPath = false; + } + } + } + + return densifiedPoly; + } } diff --git a/src/main/java/com/esri/core/geometry/GeodeticCurveType.java b/src/main/java/com/esri/core/geometry/GeodeticCurveType.java index 125d680f..f534ca29 100644 --- a/src/main/java/com/esri/core/geometry/GeodeticCurveType.java +++ b/src/main/java/com/esri/core/geometry/GeodeticCurveType.java @@ -27,25 +27,25 @@ * Values for use in Geodetic length and area calculations */ public interface GeodeticCurveType { - /** - * Shortest distance between two points on an ellipsoide - */ - int Geodesic = 0; - /** - * A line of constant bearing or azimuth. Also known as a rhmub line - */ - public final static int Loxodrome = 1; - /** - * The line on a spheroid defined along the intersection at the surface by a - * plane that passes through the center of the spheroid. When the spheroid - * flattening is equal to zero (sphere) then a Great Elliptic is a Great - * Circle - */ - public final static int GreatElliptic = 2; - public final static int NormalSection = 3; - /*The ShapePreserving type means the segments shapes are preserved in the spatial reference where they are defined. - *The behavior of the ShapePreserving type can be emulated by densifying the geometry with a small step, and then calling a geodetic method - *using Geodesic or GreatElliptic curve types. - */ - public final static int ShapePreserving = 4; + /** + * Shortest distance between two points on an ellipsoide + */ + int Geodesic = 0; + /** + * A line of constant bearing or azimuth. Also known as a rhmub line + */ + public final static int Loxodrome = 1; + /** + * The line on a spheroid defined along the intersection at the surface by a + * plane that passes through the center of the spheroid. When the spheroid + * flattening is equal to zero (sphere) then a Great Elliptic is a Great + * Circle + */ + public final static int GreatElliptic = 2; + public final static int NormalSection = 3; + /*The ShapePreserving type means the segments shapes are preserved in the spatial reference where they are defined. + *The behavior of the ShapePreserving type can be emulated by densifying the geometry with a small step, and then calling a geodetic method + *using Geodesic or GreatElliptic curve types. + */ + public final static int ShapePreserving = 4; } diff --git a/src/main/java/com/esri/core/geometry/Geometry.java b/src/main/java/com/esri/core/geometry/Geometry.java index f293749b..285143b3 100644 --- a/src/main/java/com/esri/core/geometry/Geometry.java +++ b/src/main/java/com/esri/core/geometry/Geometry.java @@ -35,118 +35,120 @@ * objects that define a spatial location and and associated geometric shape. */ public abstract class Geometry implements Serializable { - VertexDescription m_description; - volatile int m_touchFlag; - - Geometry() { - m_description = null; - m_touchFlag = 0; - } - - /** - * Geometry types - */ - static public interface GeometryType { - public final static int Unknown = 0; - public final static int Point = 1 + 0x20; // points - public final static int Line = 2 + 0x40 + 0x100; // lines, segment - final static int Bezier = 3 + 0x40 + 0x100; // lines, segment - final static int EllipticArc = 4 + 0x40 + 0x100; // lines, segment - public final static int Envelope = 5 + 0x40 + 0x80; // lines, areas - public final static int MultiPoint = 6 + 0x20 + 0x200; // points, - // multivertex - public final static int Polyline = 7 + 0x40 + 0x200 + 0x400; // lines, - // multivertex, - // multipath - public final static int Polygon = 8 + 0x40 + 0x80 + 0x200 + 0x400; - } - - /** - * The type of this geometry. - */ - static public enum Type { - /** - * Used to indicate that the geometry type is not known before executing - * a method. - */ - Unknown(GeometryType.Unknown), - /** - * The value representing a point as geometry type. - */ - - Point(GeometryType.Point), - /** - * The value representing a line as geometry type. - */ - - Line(GeometryType.Line), - /** - * The value representing an envelope as geometry type. - */ - - Envelope(GeometryType.Envelope), - /** - * The value representing a multipoint as geometry type. - */ - - MultiPoint(GeometryType.MultiPoint), - /** - * The value representing a polyline as geometry type. - */ - - Polyline(GeometryType.Polyline), - /** - * The value representing a polygon as geometry type. - */ - - Polygon(GeometryType.Polygon); - - private int enumValue; - - /** - * Returns the integer representation of the enumeration value. - */ - public int value() { - return enumValue; - } + VertexDescription m_description; + volatile int m_touchFlag; - Type(int val) { - enumValue = val; - } + Geometry() { + m_description = null; + m_touchFlag = 0; + } + + /** + * Geometry types + */ + static public interface GeometryType { + public final static int Unknown = 0; + public final static int Point = 1 + 0x20; // points + public final static int Line = 2 + 0x40 + 0x100; // lines, segment + final static int Bezier = 3 + 0x40 + 0x100; // lines, segment + final static int EllipticArc = 4 + 0x40 + 0x100; // lines, segment + public final static int Envelope = 5 + 0x40 + 0x80; // lines, areas + public final static int MultiPoint = 6 + 0x20 + 0x200; // points, + // multivertex + public final static int Polyline = 7 + 0x40 + 0x200 + 0x400; // lines, + // multivertex, + // multipath + public final static int Polygon = 8 + 0x40 + 0x80 + 0x200 + 0x400; + } - static public Geometry.Type intToType(int geometryType) { - Geometry.Type[] v = Geometry.Type.values(); - for (int i = 0; i < v.length; i++) { - if (v[i].value() == geometryType) + /** + * The type of this geometry. + */ + static public enum Type { + /** + * Used to indicate that the geometry type is not known before executing + * a method. + */ + Unknown(GeometryType.Unknown), + /** + * The value representing a point as geometry type. + */ + + Point(GeometryType.Point), + /** + * The value representing a line as geometry type. + */ + + Line(GeometryType.Line), + /** + * The value representing an envelope as geometry type. + */ + + Envelope(GeometryType.Envelope), + /** + * The value representing a multipoint as geometry type. + */ + + MultiPoint(GeometryType.MultiPoint), + /** + * The value representing a polyline as geometry type. + */ + + Polyline(GeometryType.Polyline), + /** + * The value representing a polygon as geometry type. + */ + + Polygon(GeometryType.Polygon); + + private int enumValue; + + /** + * Returns the integer representation of the enumeration value. + */ + public int value() { + return enumValue; + } + + Type(int val) { + enumValue = val; + } + + static public Geometry.Type intToType(int geometryType) + { + Geometry.Type[] v = Geometry.Type.values(); + for(int i = 0; i < v.length; i++) + { + if(v[i].value() == geometryType) return v[i]; } throw new IllegalArgumentException(); } - } - - /** - * Returns the geometry type. - * - * @return Returns the geometry type. - */ - public abstract Geometry.Type getType(); - - /** - * Returns the topological dimension of the geometry object based on the - * geometry's type. - *

- * Returns 0 for point and multipoint. - *

- * Returns 1 for lines and polylines. - *

- * Returns 2 for polygons and envelopes - *

- * Returns 3 for objects with volume - * - * @return Returns the integer value of the dimension of geometry. - */ - public abstract int getDimension(); + } + + /** + * Returns the geometry type. + * + * @return Returns the geometry type. + */ + public abstract Geometry.Type getType(); + + /** + * Returns the topological dimension of the geometry object based on the + * geometry's type. + *

+ * Returns 0 for point and multipoint. + *

+ * Returns 1 for lines and polylines. + *

+ * Returns 2 for polygons and envelopes + *

+ * Returns 3 for objects with volume + * + * @return Returns the integer value of the dimension of geometry. + */ + public abstract int getDimension(); /** * Returns an estimate of this object size in bytes. @@ -182,10 +184,10 @@ public void assignVertexDescription(VertexDescription src) { if (src == m_description) return; - _assignVertexDescriptionImpl(src); - } + _assignVertexDescriptionImpl(src); + } - protected abstract void _assignVertexDescriptionImpl(VertexDescription src); + protected abstract void _assignVertexDescriptionImpl(VertexDescription src); /** * Merges the new VertexDescription by adding missing attributes from the @@ -198,13 +200,13 @@ public void mergeVertexDescription(VertexDescription src) { if (src == m_description) return; - // check if we need to do anything (if the src has same attributes) - VertexDescription newdescription = VertexDescriptionDesignerImpl.getMergedVertexDescription(m_description, src); - if (newdescription == m_description) - return; + // check if we need to do anything (if the src has same attributes) + VertexDescription newdescription = VertexDescriptionDesignerImpl.getMergedVertexDescription(m_description, src); + if (newdescription == m_description) + return; - _assignVertexDescriptionImpl(newdescription); - } + _assignVertexDescriptionImpl(newdescription); + } /** * A shortcut for getDescription().hasAttribute() @@ -217,14 +219,14 @@ public boolean hasAttribute(int semantics) { /** * Adds a new attribute to the Geometry. - * + * * @param semantics The VertexDescription.Semantics to add. */ public void addAttribute(int semantics) { _touch(); if (m_description.hasAttribute(semantics)) return; - + VertexDescription newvd = VertexDescriptionDesignerImpl.getMergedVertexDescription(m_description, semantics); _assignVertexDescriptionImpl(newvd); } @@ -241,17 +243,17 @@ public void dropAttribute(int semantics) { if (!m_description.hasAttribute(semantics)) return; - VertexDescription newvd = VertexDescriptionDesignerImpl.removeSemanticsFromVertexDescription(m_description, semantics); - _assignVertexDescriptionImpl(newvd); - } + VertexDescription newvd = VertexDescriptionDesignerImpl.removeSemanticsFromVertexDescription(m_description, semantics); + _assignVertexDescriptionImpl(newvd); + } - /** - * Drops all attributes from the Geometry with exception of POSITON. - */ - public void dropAllAttributes() { - assignVertexDescription(VertexDescriptionDesignerImpl - .getDefaultDescriptor2D()); - } + /** + * Drops all attributes from the Geometry with exception of POSITON. + */ + public void dropAllAttributes() { + assignVertexDescription(VertexDescriptionDesignerImpl + .getDefaultDescriptor2D()); + } /** * Returns the min and max attribute values at the ordinate of the Geometry. @@ -261,12 +263,13 @@ public void dropAllAttributes() { */ public abstract Envelope1D queryInterval(int semantics, int ordinate); - /** - * Returns the axis aligned bounding box of the geometry. - * - * @param env The envelope to return the result in. - */ - public abstract void queryEnvelope(Envelope env); + /** + * Returns the axis aligned bounding box of the geometry. + * + * @param env + * The envelope to return the result in. + */ + public abstract void queryEnvelope(Envelope env); /** * Returns tight bbox of the Geometry in X, Y plane. @@ -304,33 +307,35 @@ void queryLooseEnvelope3D(Envelope3D env) { queryEnvelope3D(env); } - /** - * IsEmpty returns TRUE when the Geometry object does not contain geometric - * information beyond its original initialization state. - * - * @return boolean Returns TRUE if this geometry is empty. - */ - public abstract boolean isEmpty(); + /** + * IsEmpty returns TRUE when the Geometry object does not contain geometric + * information beyond its original initialization state. + * + * @return boolean Returns TRUE if this geometry is empty. + */ + public abstract boolean isEmpty(); - /** - * Returns the geometry to its original initialization state by releasing - * all data referenced by the geometry. - */ - public abstract void setEmpty(); + /** + * Returns the geometry to its original initialization state by releasing + * all data referenced by the geometry. + */ + public abstract void setEmpty(); - /** - * Applies 2D affine transformation in XY plane. - * - * @param transform The affine transformation to be applied to this geometry. - */ - public abstract void applyTransformation(Transformation2D transform); + /** + * Applies 2D affine transformation in XY plane. + * + * @param transform + * The affine transformation to be applied to this geometry. + */ + public abstract void applyTransformation(Transformation2D transform); - /** - * Applies 3D affine transformation. Adds Z attribute if it is missing. - * - * @param transform The affine transformation to be applied to this geometry. - */ - abstract void applyTransformation(Transformation3D transform); + /** + * Applies 3D affine transformation. Adds Z attribute if it is missing. + * + * @param transform + * The affine transformation to be applied to this geometry. + */ + abstract void applyTransformation(Transformation3D transform); /** * Creates an instance of an empty geometry of the same type. @@ -347,183 +352,190 @@ void queryLooseEnvelope3D(Envelope3D env) { */ public abstract void copyTo(Geometry dst); - /** - * Calculates the area of the geometry. If the spatial reference is a - * Geographic Coordinate System (WGS84) then the 2D area calculation is - * defined in angular units. - * - * @return A double value representing the 2D area of the geometry. - */ - public double calculateArea2D() { - return 0; - } - - /** - * Calculates the length of the geometry. If the spatial reference is a - * Geographic Coordinate System (a system where coordinates are defined - * using angular units such as longitude and latitude) then the 2D distance - * calculation is returned in angular units. In cases where length must be - * calculated on a Geographic Coordinate System consider the using the - * geodeticLength method on the {@link GeometryEngine} - * - * @return A double value representing the 2D length of the geometry. - */ - public double calculateLength2D() { - return 0; - } - - protected Object _getImpl() { - throw new RuntimeException("invalid call"); - } - - /** - * Adds the Z attribute to this Geometry - */ - void addZ() { - addAttribute(VertexDescription.Semantics.Z); - } - - /** - * Returns true if this Geometry has the Z attribute - * - * @return true if this Geometry has the Z attribute - */ - public boolean hasZ() { - return hasAttribute(VertexDescription.Semantics.Z); - } - - /** - * Adds the M attribute to this Geometry - */ - public void addM() { - addAttribute(VertexDescription.Semantics.M); - } - - /** - * Returns true if this Geometry has an M attribute - * - * @return true if this Geometry has an M attribute - */ - public boolean hasM() { - return hasAttribute(VertexDescription.Semantics.M); - } - - /** - * Adds the ID attribute to this Geometry - */ - public void addID() { - addAttribute(VertexDescription.Semantics.ID); - } - - /** - * Returns true if this Geometry has an ID attribute - * - * @return true if this Geometry has an ID attribute - */ - public boolean hasID() { - return hasAttribute(VertexDescription.Semantics.ID); - } - - /** - * Returns this geometry's dimension. - *

- * Returns 0 for point and multipoint. - *

- * Returns 1 for lines and polylines. - *

- * Returns 2 for polygons and envelopes - *

- * Returns 3 for objects with volume - * - * @param type The integer value from geometry enumeration. You can use the - * method {@link Type#value()} to get at the integer value. - * @return The integer dimension of this geometry. - */ - public static int getDimensionFromType(int type) { - return (((type & (0x40 | 0x80)) >> 6) + 1) >> 1; - } - - /** - * Indicates if the integer value of the enumeration is a point type - * (dimension 0). - * - * @param type The integer value from geometry enumeration. You can use the - * method {@link Type#value()} to get at the integer value. - * @return TRUE if the geometry is a point. - */ - public static boolean isPoint(int type) { - return (type & 0x20) != 0; - } - - /** - * Indicates if the integer value of the enumeration is linear (dimension - * 1). - * - * @param type The integer value from geometry enumeration. You can use the - * method {@link Type#value()} to get at the integer value. - * @return TRUE if the geometry is a line. - */ - public static boolean isLinear(int type) { - return (type & 0x40) != 0; - } - - /** - * Indicates if the integer value of the enumeration is an area (dimension - * 2). - * - * @param type The integer value from geometry enumeration. You can use the - * method {@link Type#value()} to get at the integer value. - * @return TRUE if the geometry is a polygon. - */ - public static boolean isArea(int type) { - return (type & 0x80) != 0; - } - - /** - * Indicates if the integer value of the enumeration is a segment. - * - * @param type The integer value from geometry enumeration. You can use the - * method {@link Type#value()} to get at the integer value. - * @return TRUE if the geometry is a segment. - */ - public static boolean isSegment(int type) { - return (type & 0x100) != 0; - } - - /** - * Indicates if the integer value of the enumeration is a multivertex (ie, - * multipoint, line, or area). - * - * @param type The integer value from geometry enumeration. You can use the - * method {@link Type#value()} to get at the integer value. - * @return TRUE if the geometry has multiple vertices. - */ - public static boolean isMultiVertex(int type) { - return (type & 0x200) != 0; - } - - /** - * Indicates if the integer value of the enumeration is a multipath (ie, - * line or area). - * - * @param type The integer value from geometry enumeration. You can use the - * method {@link Type#value()} to get at the integer value. - * @return TRUE if the geometry is a multipath. - */ - public static boolean isMultiPath(int type) { - return (type & 0x400) != 0; - } - - /** - * Creates a copy of the geometry. - * - * @return Returns a copy of this geometry. - */ - public Geometry copy() { - Geometry geom = createInstance(); - this.copyTo(geom); - return geom; - } + /** + * Calculates the area of the geometry. If the spatial reference is a + * Geographic Coordinate System (WGS84) then the 2D area calculation is + * defined in angular units. + * + * @return A double value representing the 2D area of the geometry. + */ + public double calculateArea2D() { + return 0; + } + + /** + * Calculates the length of the geometry. If the spatial reference is a + * Geographic Coordinate System (a system where coordinates are defined + * using angular units such as longitude and latitude) then the 2D distance + * calculation is returned in angular units. In cases where length must be + * calculated on a Geographic Coordinate System consider the using the + * geodeticLength method on the {@link GeometryEngine} + * + * @return A double value representing the 2D length of the geometry. + */ + public double calculateLength2D() { + return 0; + } + + protected Object _getImpl() { + throw new RuntimeException("invalid call"); + } + + /** + * Adds the Z attribute to this Geometry + */ + void addZ() { + addAttribute(VertexDescription.Semantics.Z); + } + + /** + * Returns true if this Geometry has the Z attribute + * + * @return true if this Geometry has the Z attribute + */ + public boolean hasZ() { + return hasAttribute(VertexDescription.Semantics.Z); + } + + /** + * Adds the M attribute to this Geometry + */ + public void addM() { + addAttribute(VertexDescription.Semantics.M); + } + + /** + * Returns true if this Geometry has an M attribute + * + * @return true if this Geometry has an M attribute + */ + public boolean hasM() { + return hasAttribute(VertexDescription.Semantics.M); + } + + /** + * Adds the ID attribute to this Geometry + */ + public void addID() { + addAttribute(VertexDescription.Semantics.ID); + } + + /** + * Returns true if this Geometry has an ID attribute + * + * @return true if this Geometry has an ID attribute + */ + public boolean hasID() { + return hasAttribute(VertexDescription.Semantics.ID); + } + + /** + * Returns this geometry's dimension. + *

+ * Returns 0 for point and multipoint. + *

+ * Returns 1 for lines and polylines. + *

+ * Returns 2 for polygons and envelopes + *

+ * Returns 3 for objects with volume + * + * @param type + * The integer value from geometry enumeration. You can use the + * method {@link Type#value()} to get at the integer value. + * @return The integer dimension of this geometry. + */ + public static int getDimensionFromType(int type) { + return (((type & (0x40 | 0x80)) >> 6) + 1) >> 1; + } + + /** + * Indicates if the integer value of the enumeration is a point type + * (dimension 0). + * + * @param type + * The integer value from geometry enumeration. You can use the + * method {@link Type#value()} to get at the integer value. + * @return TRUE if the geometry is a point (a Point or a Multipoint). + */ + public static boolean isPoint(int type) { + return (type & 0x20) != 0; + } + + /** + * Indicates if the integer value of the enumeration is linear (dimension + * 1). + * + * @param type + * The integer value from geometry enumeration. You can use the + * method {@link Type#value()} to get at the integer value. + * @return TRUE if the geometry is a line. + */ + public static boolean isLinear(int type) { + return (type & 0x40) != 0; + } + + /** + * Indicates if the integer value of the enumeration is an area (dimension + * 2). + * + * @param type + * The integer value from geometry enumeration. You can use the + * method {@link Type#value()} to get at the integer value. + * @return TRUE if the geometry is a polygon. + */ + public static boolean isArea(int type) { + return (type & 0x80) != 0; + } + + /** + * Indicates if the integer value of the enumeration is a segment. + * + * @param type + * The integer value from geometry enumeration. You can use the + * method {@link Type#value()} to get at the integer value. + * @return TRUE if the geometry is a segment. + */ + public static boolean isSegment(int type) { + return (type & 0x100) != 0; + } + + /** + * Indicates if the integer value of the enumeration is a multivertex (ie, + * multipoint, line, or area). + * + * @param type + * The integer value from geometry enumeration. You can use the + * method {@link Type#value()} to get at the integer value. + * @return TRUE if the geometry has multiple vertices. + */ + public static boolean isMultiVertex(int type) { + return (type & 0x200) != 0; + } + + /** + * Indicates if the integer value of the enumeration is a multipath (ie, + * line or area). + * + * @param type + * The integer value from geometry enumeration. You can use the + * method {@link Type#value()} to get at the integer value. + * @return TRUE if the geometry is a multipath. + */ + public static boolean isMultiPath(int type) { + return (type & 0x400) != 0; + } + + /** + * Creates a copy of the geometry. + * + * @return Returns a copy of this geometry. + */ + public Geometry copy() { + Geometry geom = createInstance(); + this.copyTo(geom); + return geom; + } /** * Returns boundary of this geometry. @@ -544,86 +556,91 @@ public Geometry copy() { */ public abstract void replaceNaNs(int semantics, double value); - static Geometry _clone(Geometry src) { - Geometry geom = src.createInstance(); - src.copyTo(geom); - return geom; - } - - /** - * The stateFlag value changes with changes applied to this geometry. This - * allows the user to keep track of the geometry's state. - * - * @return The state of the geometry. - */ - public int getStateFlag() { - m_touchFlag &= 0x7FFFFFFF; - return m_touchFlag; - } - - // Called whenever geometry changes - synchronized void _touch() { - if (m_touchFlag >= 0) { - m_touchFlag += 0x80000001; - } - } - - /** - * Describes the degree of acceleration of the geometry. - * Acceleration usually builds a raster and a quadtree. - */ - static public enum GeometryAccelerationDegree { - /** - * mild acceleration, takes least amount of memory. (64x64x2 bit raster) - */ - enumMild, - /** - * medium acceleration, takes more memory and takes more time to accelerate, but may work faster. - * (256x256x2 bit raster and a quad tree for segments) - */ - enumMedium, - /** - * high acceleration, takes even more memory and may take - * longest time to accelerate, but may work faster than the - * other two. - * (1024x1024x2 bit raster and a quad tree for segments) - */ - enumHot - } - - Object writeReplace() throws ObjectStreamException { - Type gt = getType(); - if (gt == Geometry.Type.Point) { - PtSrlzr pt = new PtSrlzr(); - pt.setGeometryByValue((Point) this); - return pt; - } else if (gt == Geometry.Type.Envelope) { - EnvSrlzr e = new EnvSrlzr(); - e.setGeometryByValue((Envelope) this); - return e; - } else if (gt == Geometry.Type.Line) { - LnSrlzr ln = new LnSrlzr(); - ln.setGeometryByValue((Line) this); - return ln; - } + static Geometry _clone(Geometry src) { + Geometry geom = src.createInstance(); + src.copyTo(geom); + return geom; + } - GenericGeometrySerializer geomSerializer = new GenericGeometrySerializer(); - geomSerializer.setGeometryByValue(this); - return geomSerializer; - } - - /** - * The output of this method can be only used for debugging. It is subject to change without notice. - */ - @Override - public String toString() { - String snippet = OperatorExportToWkt.local().execute(0, this, null); - if (snippet.length() > 200) { - return snippet.substring(0, 197) + "... (" + snippet.length() + " characters)"; - } else { - return snippet; - } - } + /** + * The stateFlag value changes with changes applied to this geometry. This + * allows the user to keep track of the geometry's state. + * + * @return The state of the geometry. + */ + public int getStateFlag() { + m_touchFlag &= 0x7FFFFFFF; + return m_touchFlag; + } + + // Called whenever geometry changes + synchronized void _touch() { + if (m_touchFlag >= 0) { + m_touchFlag += 0x80000001; + } + } + + /** + * Describes the degree of acceleration of the geometry. + * Acceleration usually builds a raster and a quadtree. + */ + static public enum GeometryAccelerationDegree { + /** + * mild acceleration, takes least amount of memory. (64x64x2 bit raster) + */ + enumMild, + /** + * medium acceleration, takes more memory and takes more time to accelerate, but may work faster. + * (256x256x2 bit raster and a quad tree for segments) + */ + enumMedium, + /** + *high acceleration, takes even more memory and may take + *longest time to accelerate, but may work faster than the + *other two. + *(1024x1024x2 bit raster and a quad tree for segments) + */ + enumHot + } + + Object writeReplace() throws ObjectStreamException { + Type gt = getType(); + if (gt == Geometry.Type.Point) + { + PtSrlzr pt = new PtSrlzr(); + pt.setGeometryByValue((Point)this); + return pt; + } + else if (gt == Geometry.Type.Envelope) + { + EnvSrlzr e = new EnvSrlzr(); + e.setGeometryByValue((Envelope)this); + return e; + } + else if (gt == Geometry.Type.Line) + { + LnSrlzr ln = new LnSrlzr(); + ln.setGeometryByValue((Line)this); + return ln; + } + + GenericGeometrySerializer geomSerializer = new GenericGeometrySerializer(); + geomSerializer.setGeometryByValue(this); + return geomSerializer; + } + + /** + * The output of this method can be only used for debugging. It is subject to change without notice. + */ + @Override + public String toString() { + String snippet = OperatorExportToWkt.local().execute(0, this, null); + if (snippet.length() > 200) { + return snippet.substring(0, 197) + "... (" + snippet.length() + " characters)"; + } else { + return snippet; + } + } /** * Returns count of geometry vertices: 1 for Point, 4 for Envelope, @@ -637,32 +654,32 @@ public static int vertex_count(Geometry geom) { if (Geometry.isMultiVertex(gt.value())) return ((MultiVertexGeometry) geom).getPointCount(); - if (geom.isEmpty()) - return 0; + if (geom.isEmpty()) + return 0; - if (gt == Geometry.Type.Envelope) - return 4; + if (gt == Geometry.Type.Envelope) + return 4; - if (gt == Geometry.Type.Point) - return 1; + if (gt == Geometry.Type.Point) + return 1; - if (Geometry.isSegment(gt.value())) - return 2; + if (Geometry.isSegment(gt.value())) + return 2; - throw new GeometryException("missing type"); - } + throw new GeometryException("missing type"); + } - protected SimpleStateEnum getSimpleState() { - if (getType() != Type.Polygon && getType() != Type.Polyline && getType() != Type.MultiPoint) { - return SimpleStateEnum.STRONG_SIMPLE; - } else { - if (((MultiVertexGeometryImpl)this._getImpl())._hasDirtyFlag(MultiVertexGeometryImpl.DirtyFlags.IsStrongSimple)) { - return SimpleStateEnum.STRONG_SIMPLE; - } else if (((MultiVertexGeometryImpl)this._getImpl())._hasDirtyFlag(MultiVertexGeometryImpl.DirtyFlags.IsWeakSimple)) { - return SimpleStateEnum.WEAK_SIMPLE; - } - return SimpleStateEnum.SIMPLE_UNKNOWN; - } - } + protected SimpleStateEnum getSimpleState() { + if (getType() != Type.Polygon && getType() != Type.Polyline && getType() != Type.MultiPoint) { + return SimpleStateEnum.STRONG_SIMPLE; + } else { + if (((MultiVertexGeometryImpl) this._getImpl())._hasDirtyFlag(MultiVertexGeometryImpl.DirtyFlags.IsStrongSimple)) { + return SimpleStateEnum.STRONG_SIMPLE; + } else if (((MultiVertexGeometryImpl) this._getImpl())._hasDirtyFlag(MultiVertexGeometryImpl.DirtyFlags.IsWeakSimple)) { + return SimpleStateEnum.WEAK_SIMPLE; + } + return SimpleStateEnum.SIMPLE_UNKNOWN; + } + } } diff --git a/src/main/java/com/esri/core/geometry/GeometryAccelerators.java b/src/main/java/com/esri/core/geometry/GeometryAccelerators.java index 4aca3b1d..90d699d0 100644 --- a/src/main/java/com/esri/core/geometry/GeometryAccelerators.java +++ b/src/main/java/com/esri/core/geometry/GeometryAccelerators.java @@ -23,59 +23,55 @@ */ package com.esri.core.geometry; -import java.util.ArrayList; - class GeometryAccelerators { - private RasterizedGeometry2D m_rasterizedGeometry; - private QuadTreeImpl m_quad_tree; + private RasterizedGeometry2D m_rasterizedGeometry; + private QuadTreeImpl m_quad_tree; private QuadTreeImpl m_quad_tree_for_paths; - public RasterizedGeometry2D getRasterizedGeometry() { - return m_rasterizedGeometry; - } + public RasterizedGeometry2D getRasterizedGeometry() { + return m_rasterizedGeometry; + } - public QuadTreeImpl getQuadTree() { - return m_quad_tree; - } + public QuadTreeImpl getQuadTree() { + return m_quad_tree; + } - public QuadTreeImpl getQuadTreeForPaths() { - return m_quad_tree_for_paths; - } + public QuadTreeImpl getQuadTreeForPaths() { + return m_quad_tree_for_paths; + } - void _setRasterizedGeometry(RasterizedGeometry2D rg) { - m_rasterizedGeometry = rg; - } + void _setRasterizedGeometry(RasterizedGeometry2D rg) { + m_rasterizedGeometry = rg; + } - void _setQuadTree(QuadTreeImpl quad_tree) { - m_quad_tree = quad_tree; - } + void _setQuadTree(QuadTreeImpl quad_tree) { + m_quad_tree = quad_tree; + } - void _setQuadTreeForPaths(QuadTreeImpl quad_tree) { - m_quad_tree_for_paths = quad_tree; - } + void _setQuadTreeForPaths(QuadTreeImpl quad_tree) { m_quad_tree_for_paths = quad_tree; } - static boolean canUseRasterizedGeometry(Geometry geom) { - if (geom.isEmpty() - || !(geom.getType() == Geometry.Type.Polyline || geom.getType() == Geometry.Type.Polygon)) { - return false; - } + static boolean canUseRasterizedGeometry(Geometry geom) { + if (geom.isEmpty() + || !(geom.getType() == Geometry.Type.Polyline || geom.getType() == Geometry.Type.Polygon)) { + return false; + } - return true; - } + return true; + } - static boolean canUseQuadTree(Geometry geom) { - if (geom.isEmpty() - || !(geom.getType() == Geometry.Type.Polyline || geom.getType() == Geometry.Type.Polygon)) { - return false; - } + static boolean canUseQuadTree(Geometry geom) { + if (geom.isEmpty() + || !(geom.getType() == Geometry.Type.Polyline || geom.getType() == Geometry.Type.Polygon)) { + return false; + } - if (((MultiVertexGeometry) geom).getPointCount() < 20) { - return false; - } + if (((MultiVertexGeometry) geom).getPointCount() < 20) { + return false; + } - return true; - } + return true; + } static boolean canUseQuadTreeForPaths(Geometry geom) { if (geom.isEmpty() || !(geom.getType() == Geometry.Type.Polyline || geom.getType() == Geometry.Type.Polygon)) @@ -86,4 +82,11 @@ static boolean canUseQuadTreeForPaths(Geometry geom) { return true; } + + public long estimateMemorySize() + { + return (m_rasterizedGeometry != null ? m_rasterizedGeometry.estimateMemorySize() : 0) + + (m_quad_tree != null ? m_quad_tree.estimateMemorySize() : 0) + + (m_quad_tree_for_paths != null ? m_quad_tree_for_paths.estimateMemorySize() : 0); + } } diff --git a/src/main/java/com/esri/core/geometry/GeometryCursor.java b/src/main/java/com/esri/core/geometry/GeometryCursor.java index ab127471..725fc08b 100644 --- a/src/main/java/com/esri/core/geometry/GeometryCursor.java +++ b/src/main/java/com/esri/core/geometry/GeometryCursor.java @@ -29,45 +29,49 @@ * An abstract Geometry Cursor class. */ public abstract class GeometryCursor implements Iterator { - // TODO add count - // TODO add extent - // TODO add spatial reference - GeometryCursor m_inputGeoms = null; + // TODO add count + // TODO add extent + // TODO add spatial reference + GeometryCursor m_inputGeoms = null; - /** - * Moves the cursor to the next Geometry. Returns null when reached the end. - * The behavior of the cursor is undefined after the method returns null. - */ - public abstract Geometry next(); + /** + * Moves the cursor to the next Geometry. Returns null when reached the end. + * The behavior of the cursor is undefined after the method returns null. + */ + public abstract Geometry next(); - /** - * Returns the ID of the current geometry. The ID is propagated across the operations (when possible). - *

- * Returns an ID associated with the current Geometry. The ID is passed along and is returned by some operators to preserve relationship between the input and output geometry classes. - * It is not always possible to preserve an ID during an operation. - */ - public long getGeometryID() { - return m_inputGeoms.getGeometryID(); - } + /** + * Returns the ID of the current geometry. The ID is propagated across the operations (when possible). + *

+ * Returns an ID associated with the current Geometry. The ID is passed along and is returned by some operators to preserve relationship between the input and output geometry classes. + * It is not always possible to preserve an ID during an operation. + */ + public long getGeometryID() { + return m_inputGeoms.getGeometryID(); + } - public SimpleStateEnum getSimpleState() { return m_inputGeoms.getSimpleState(); } + public SimpleStateEnum getSimpleState() { + return m_inputGeoms.getSimpleState(); + } - public String getFeatureID() { return m_inputGeoms.getFeatureID(); } + public String getFeatureID() { + return m_inputGeoms.getFeatureID(); + } - /** - * Executes a unit of work on the cursor. - * - * @return Returns true, if there is a geometry ready to be pulled using next(). - *

- * This method is to be used together with the tick() method on the ListeningGeometryCursor. - * Call tock() for each tick() on the ListeningGeometryCursor. - */ - public boolean tock() { - return true; - } + /** + * Executes a unit of work on the cursor. + * + * @return Returns true, if there is a geometry ready to be pulled using next(). + *

+ * This method is to be used together with the tick() method on the ListeningGeometryCursor. + * Call tock() for each tick() on the ListeningGeometryCursor. + */ + public boolean tock() { + return true; + } - public boolean hasNext() { - return m_inputGeoms != null && m_inputGeoms.hasNext(); - } + public boolean hasNext() { + return m_inputGeoms != null && m_inputGeoms.hasNext(); + } } diff --git a/src/main/java/com/esri/core/geometry/GeometryCursorAppend.java b/src/main/java/com/esri/core/geometry/GeometryCursorAppend.java index 2228ddf4..37965ed6 100644 --- a/src/main/java/com/esri/core/geometry/GeometryCursorAppend.java +++ b/src/main/java/com/esri/core/geometry/GeometryCursorAppend.java @@ -25,31 +25,33 @@ public class GeometryCursorAppend extends GeometryCursor { - private GeometryCursor m_cur1; - private GeometryCursor m_cur2; - private GeometryCursor m_cur; - - public GeometryCursorAppend(GeometryCursor cur1, GeometryCursor cur2) { - m_cur1 = cur1; - m_cur2 = cur2; - m_cur = m_cur1; - } - - @Override - public boolean hasNext() { return m_cur != null && m_cur.hasNext(); } - - @Override - public Geometry next() { - Geometry g = m_cur.next(); - if (g == null && m_cur != m_cur2) { - m_cur = m_cur2; - return m_cur.next(); - } - return g; - } - - @Override - public long getGeometryID() { - return m_cur.getGeometryID(); - } + private GeometryCursor m_cur1; + private GeometryCursor m_cur2; + private GeometryCursor m_cur; + + public GeometryCursorAppend(GeometryCursor cur1, GeometryCursor cur2) { + m_cur1 = cur1; + m_cur2 = cur2; + m_cur = m_cur1; + } + + @Override + public boolean hasNext() { + return m_cur != null && m_cur.hasNext(); + } + + @Override + public Geometry next() { + Geometry g = m_cur.next(); + if (g == null && m_cur != m_cur2) { + m_cur = m_cur2; + return m_cur.next(); + } + return g; + } + + @Override + public long getGeometryID() { + return m_cur.getGeometryID(); + } } diff --git a/src/main/java/com/esri/core/geometry/GeometryEngine.java b/src/main/java/com/esri/core/geometry/GeometryEngine.java index 188ac0eb..fc9855a3 100644 --- a/src/main/java/com/esri/core/geometry/GeometryEngine.java +++ b/src/main/java/com/esri/core/geometry/GeometryEngine.java @@ -39,801 +39,796 @@ */ public class GeometryEngine { - private static OperatorFactoryLocal factory = OperatorFactoryLocal - .getInstance(); - - - /** - * Imports the MapGeometry from its JSON representation. M and Z values are - * not imported from JSON representation. - *

- * See OperatorImportFromJson. - * - * @param json The JSON representation of the geometry (with spatial - * reference). - * @return The MapGeometry instance containing the imported geometry and its - * spatial reference. - */ - public static MapGeometry jsonToGeometry(JsonParser json) { - MapGeometry geom = OperatorImportFromJson.local().execute(Geometry.Type.Unknown, new JsonParserReader(json)); - return geom; - } + private static OperatorFactoryLocal factory = OperatorFactoryLocal + .getInstance(); + + + /** + * Imports the MapGeometry from its JSON representation. M and Z values are + * not imported from JSON representation. + *

+ * See OperatorImportFromJson. + * + * @param json The JSON representation of the geometry (with spatial + * reference). + * @return The MapGeometry instance containing the imported geometry and its + * spatial reference. + */ + public static MapGeometry jsonToGeometry(JsonParser json) { + MapGeometry geom = OperatorImportFromJson.local().execute(Geometry.Type.Unknown, new JsonParserReader(json)); + return geom; + } /** * Imports the MapGeometry from its JSON representation. M and Z values are * not imported from JSON representation. - * + *

* See OperatorImportFromJson. - * - * @param json - * The JSON representation of the geometry (with spatial - * reference). + * + * @param json The JSON representation of the geometry (with spatial + * reference). * @return The MapGeometry instance containing the imported geometry and its - * spatial reference. + * spatial reference. */ public static MapGeometry jsonToGeometry(JsonReader json) { MapGeometry geom = OperatorImportFromJson.local().execute(Geometry.Type.Unknown, json); return geom; } - + /** * Imports the MapGeometry from its JSON representation. M and Z values are * not imported from JSON representation. - * + *

* See OperatorImportFromJson. - * - * @param json - * The JSON representation of the geometry (with spatial - * reference). + * + * @param json The JSON representation of the geometry (with spatial + * reference). * @return The MapGeometry instance containing the imported geometry and its - * spatial reference. + * spatial reference. */ public static MapGeometry jsonToGeometry(String json) { MapGeometry geom = OperatorImportFromJson.local().execute(Geometry.Type.Unknown, json); return geom; } - + /** * Exports the specified geometry instance to it's JSON representation. - * + *

* See OperatorExportToJson. - * - * @see GeometryEngine#geometryToJson(SpatialReference spatialiReference, - * Geometry geometry) - * @param wkid - * The spatial reference Well Known ID to be used for the JSON - * representation. - * @param geometry - * The geometry to be exported to JSON. + * + * @param wkid The spatial reference Well Known ID to be used for the JSON + * representation. + * @param geometry The geometry to be exported to JSON. * @return The JSON representation of the specified Geometry. + * @see GeometryEngine#geometryToJson(SpatialReference spatialiReference, + * Geometry geometry) */ public static String geometryToJson(int wkid, Geometry geometry) { return GeometryEngine.geometryToJson( wkid > 0 ? SpatialReference.create(wkid) : null, geometry); } - /** - * Exports the specified geometry instance to it's JSON representation. M - * and Z values are not imported from JSON representation. - *

- * See OperatorExportToJson. - * - * @param spatialReference The spatial reference of associated object. - * @param geometry The geometry. - * @return The JSON representation of the specified geometry. - */ - public static String geometryToJson(SpatialReference spatialReference, - Geometry geometry) { - OperatorExportToJson exporter = (OperatorExportToJson) factory - .getOperator(Operator.Type.ExportToJson); + /** + * Exports the specified geometry instance to it's JSON representation. M + * and Z values are not imported from JSON representation. + *

+ * See OperatorExportToJson. + * + * @param spatialReference The spatial reference of associated object. + * @param geometry The geometry. + * @return The JSON representation of the specified geometry. + */ + public static String geometryToJson(SpatialReference spatialReference, + Geometry geometry) { + OperatorExportToJson exporter = (OperatorExportToJson) factory + .getOperator(Operator.Type.ExportToJson); - return exporter.execute(spatialReference, geometry); - } + return exporter.execute(spatialReference, geometry); + } - public static String geometryToGeoJson(Geometry geometry) { - OperatorExportToGeoJson exporter = (OperatorExportToGeoJson) factory - .getOperator(Operator.Type.ExportToGeoJson); + public static String geometryToGeoJson(Geometry geometry) { + OperatorExportToGeoJson exporter = (OperatorExportToGeoJson) factory + .getOperator(Operator.Type.ExportToGeoJson); - return exporter.execute(geometry); - } + return exporter.execute(geometry); + } /** * Imports the MapGeometry from its JSON representation. M and Z values are * not imported from JSON representation. - * + *

* See OperatorImportFromJson. - * - * @param json - * The JSON representation of the geometry (with spatial - * reference). + * + * @param json The JSON representation of the geometry (with spatial + * reference). * @return The MapGeometry instance containing the imported geometry and its - * spatial reference. + * spatial reference. */ public static MapGeometry geoJsonToGeometry(String json, int importFlags, Geometry.Type type) { MapGeometry geom = OperatorImportFromGeoJson.local().execute(importFlags, type, json, null); return geom; } - /** - * Exports the specified geometry instance to its GeoJSON representation. - *

- * See OperatorExportToGeoJson. - * - * @param wkid The spatial reference Well Known ID to be used for the GeoJSON - * representation. - * @param geometry The geometry to be exported to GeoJSON. - * @return The GeoJSON representation of the specified geometry. - * @see GeometryEngine#geometryToGeoJson(SpatialReference spatialReference, - * Geometry geometry) - */ - public static String geometryToGeoJson(int wkid, Geometry geometry) { - return GeometryEngine.geometryToGeoJson(wkid > 0 ? SpatialReference.create(wkid) : null, geometry); - } - - /** - * Exports the specified geometry instance to it's JSON representation. - *

- * See OperatorImportFromGeoJson. - * - * @param spatialReference The spatial reference of associated object. - * @param geometry The geometry. - * @return The GeoJSON representation of the specified geometry. - */ - public static String geometryToGeoJson(SpatialReference spatialReference, Geometry geometry) { - OperatorExportToGeoJson exporter = (OperatorExportToGeoJson) factory.getOperator(Operator.Type.ExportToGeoJson); - - return exporter.execute(spatialReference, geometry); - } - - /** - * Imports geometry from the ESRI shape file format. - *

- * See OperatorImportFromESRIShape. - * - * @param esriShapeBuffer The buffer containing geometry in the ESRI shape file format. - * @param geometryType The required type of the Geometry to be imported. Use - * Geometry.Type.Unknown if the geometry type needs to be - * determined from the buffer content. - * @return The geometry or null if the buffer contains null shape. - * @throws GeometryException when the geometryType is not Geometry.Type.Unknown and the - * buffer contains geometry that cannot be converted to the - * given geometryType. or the buffer is corrupt. Another - * exception possible is IllegalArgumentsException. - */ - public static Geometry geometryFromEsriShape(byte[] esriShapeBuffer, Geometry.Type geometryType) { - OperatorImportFromESRIShape op = (OperatorImportFromESRIShape) factory.getOperator(Operator.Type.ImportFromESRIShape); - return op.execute(ShapeImportFlags.ShapeImportNonTrusted, - geometryType, - ByteBuffer.wrap(esriShapeBuffer).order(ByteOrder.LITTLE_ENDIAN)); - } - - /** - * Exports geometry to the ESRI shape file format. - *

- * See OperatorExportToESRIShape. - * - * @param geometry The geometry to export. (null value is not allowed) - * @return Array containing the exported ESRI shape file. - */ - public static byte[] geometryToEsriShape(Geometry geometry) { - if (geometry == null) - throw new IllegalArgumentException(); - OperatorExportToESRIShape op = (OperatorExportToESRIShape) factory - .getOperator(Operator.Type.ExportToESRIShape); - return op.execute(0, geometry).array(); - } + /** + * Exports the specified geometry instance to its GeoJSON representation. + *

+ * See OperatorExportToGeoJson. + * + * @param wkid The spatial reference Well Known ID to be used for the GeoJSON + * representation. + * @param geometry The geometry to be exported to GeoJSON. + * @return The GeoJSON representation of the specified geometry. + * @see GeometryEngine#geometryToGeoJson(SpatialReference spatialReference, + * Geometry geometry) + */ + public static String geometryToGeoJson(int wkid, Geometry geometry) { + return GeometryEngine.geometryToGeoJson(wkid > 0 ? SpatialReference.create(wkid) : null, geometry); + } + + /** + * Exports the specified geometry instance to it's JSON representation. + *

+ * See OperatorImportFromGeoJson. + * + * @param spatialReference The spatial reference of associated object. + * @param geometry The geometry. + * @return The GeoJSON representation of the specified geometry. + */ + public static String geometryToGeoJson(SpatialReference spatialReference, Geometry geometry) { + OperatorExportToGeoJson exporter = (OperatorExportToGeoJson) factory.getOperator(Operator.Type.ExportToGeoJson); + + return exporter.execute(spatialReference, geometry); + } + + /** + * Imports geometry from the ESRI shape file format. + *

+ * See OperatorImportFromESRIShape. + * + * @param esriShapeBuffer The buffer containing geometry in the ESRI shape file format. + * @param geometryType The required type of the Geometry to be imported. Use + * Geometry.Type.Unknown if the geometry type needs to be + * determined from the buffer content. + * @return The geometry or null if the buffer contains null shape. + * @throws GeometryException when the geometryType is not Geometry.Type.Unknown and the + * buffer contains geometry that cannot be converted to the + * given geometryType. or the buffer is corrupt. Another + * exception possible is IllegalArgumentsException. + */ + public static Geometry geometryFromEsriShape(byte[] esriShapeBuffer, Geometry.Type geometryType) { + OperatorImportFromESRIShape op = (OperatorImportFromESRIShape) factory.getOperator(Operator.Type.ImportFromESRIShape); + return op.execute(ShapeImportFlags.ShapeImportNonTrusted, + geometryType, + ByteBuffer.wrap(esriShapeBuffer).order(ByteOrder.LITTLE_ENDIAN)); + } + + /** + * Exports geometry to the ESRI shape file format. + *

+ * See OperatorExportToESRIShape. + * + * @param geometry The geometry to export. (null value is not allowed) + * @return Array containing the exported ESRI shape file. + */ + public static byte[] geometryToEsriShape(Geometry geometry) { + if (geometry == null) + throw new IllegalArgumentException(); + OperatorExportToESRIShape op = (OperatorExportToESRIShape) factory + .getOperator(Operator.Type.ExportToESRIShape); + return op.execute(0, geometry).array(); + } /** * Imports a geometry from a WKT string. - * + *

* See OperatorImportFromWkt. - * - * @param wkt The string containing the geometry in WKT format. - * @param importFlags Use the {@link WktImportFlags} interface. + * + * @param wkt The string containing the geometry in WKT format. + * @param importFlags Use the {@link WktImportFlags} interface. * @param geometryType The required type of the Geometry to be imported. Use Geometry.Type.Unknown if the geometry type needs to be determined from the WKT context. * @return The geometry. - * @throws GeometryException when the geometryType is not Geometry.Type.Unknown and the WKT contains a geometry that cannot be converted to the given geometryType. + * @throws GeometryException when the geometryType is not Geometry.Type.Unknown and the WKT contains a geometry that cannot be converted to the given geometryType. * @throws IllegalArgumentException if an error is found while parsing the WKT string. */ public static Geometry geometryFromWkt(String wkt, int importFlags, - Geometry.Type geometryType) { + Geometry.Type geometryType) { OperatorImportFromWkt op = (OperatorImportFromWkt) factory .getOperator(Operator.Type.ImportFromWkt); return op.execute(importFlags, geometryType, wkt, null); } - /** - * Exports a geometry to a string in WKT format. - *

- * See OperatorExportToWkt. - * - * @param geometry The geometry to export. (null value is not allowed) - * @param exportFlags Use the {@link WktExportFlags} interface. - * @return A String containing the exported geometry in WKT format. - */ - public static String geometryToWkt(Geometry geometry, int exportFlags) { - OperatorExportToWkt op = (OperatorExportToWkt) factory - .getOperator(Operator.Type.ExportToWkt); - return op.execute(exportFlags, geometry, null); - } - - /** - * Constructs a new geometry by union an array of geometries. All inputs - * must be of the same type of geometries and share one spatial reference. - *

- * See OperatorUnion. - * - * @param geometries The geometries to union. - * @param spatialReference The spatial reference of the geometries. - * @return The geometry object representing the resultant union. - */ - public static Geometry union(Geometry[] geometries, SpatialReference spatialReference) { - OperatorUnion op = (OperatorUnion) factory.getOperator(Operator.Type.Union); - - SimpleGeometryCursor inputGeometries = new SimpleGeometryCursor(geometries); - GeometryCursor result = op.execute(inputGeometries, spatialReference, null); - return result.next(); - } - - /** - * Creates the difference of two geometries. The dimension of geometry2 has - * to be equal to or greater than that of geometry1. - *

- * See OperatorDifference. - * - * @param geometry1 The geometry being subtracted. - * @param substractor The geometry object to subtract from. - * @param spatialReference The spatial reference of the geometries. - * @return The geometry of the differences. - */ - public static Geometry difference(Geometry geometry1, Geometry substractor, - SpatialReference spatialReference) { - OperatorDifference op = (OperatorDifference) factory.getOperator(Operator.Type.Difference); - Geometry result = op.execute(geometry1, substractor, spatialReference,null); - return result; - } - - /** - * Creates the symmetric difference of two geometries. - *

- * See OperatorSymmetricDifference. - * - * @param leftGeometry is one of the Geometry instances in the XOR operation. - * @param rightGeometry is one of the Geometry instances in the XOR operation. - * @param spatialReference The spatial reference of the geometries. - * @return Returns the result of the symmetric difference. - */ - public static Geometry symmetricDifference(Geometry leftGeometry, - Geometry rightGeometry, SpatialReference spatialReference) { - OperatorSymmetricDifference op = (OperatorSymmetricDifference) factory - .getOperator(Operator.Type.SymmetricDifference); - Geometry result = op.execute(leftGeometry, rightGeometry, - spatialReference, null); - return result; - } - - /** - * Indicates if two geometries are equal. - *

- * See OperatorEquals. - * - * @param geometry1 Geometry. - * @param geometry2 Geometry. - * @param spatialReference The spatial reference of the geometries. - * @return TRUE if both geometry objects are equal. - */ - public static boolean equals(Geometry geometry1, Geometry geometry2, - SpatialReference spatialReference) { - OperatorEquals op = (OperatorEquals) factory - .getOperator(Operator.Type.Equals); - boolean result = op.execute(geometry1, geometry2, spatialReference, - null); - return result; - } - - /** - * See OperatorDisjoint. - */ - public static boolean disjoint(Geometry geometry1, Geometry geometry2, - SpatialReference spatialReference) { - OperatorDisjoint op = (OperatorDisjoint) factory - .getOperator(Operator.Type.Disjoint); - boolean result = op.execute(geometry1, geometry2, spatialReference, - null); - return result; - } - - /** - * Constructs the set-theoretic intersection between an array of geometries - * and another geometry. - *

- * See OperatorIntersection (also for dimension specific intersection). - * - * @param inputGeometries An array of geometry objects. - * @param geometry The geometry object. - * @return Any array of geometry objects showing the intersection. - */ - static Geometry[] intersect(Geometry[] inputGeometries, Geometry geometry, - SpatialReference spatialReference) { - OperatorIntersection op = (OperatorIntersection) factory - .getOperator(Operator.Type.Intersection); - SimpleGeometryCursor inputGeometriesCursor = new SimpleGeometryCursor( - inputGeometries); - SimpleGeometryCursor intersectorCursor = new SimpleGeometryCursor( - geometry); - GeometryCursor result = op.execute(inputGeometriesCursor, - intersectorCursor, spatialReference, null); - - ArrayList resultGeoms = new ArrayList(); - Geometry g; - while ((g = result.next()) != null) { - resultGeoms.add(g); - } - - Geometry[] resultarr = resultGeoms.toArray(new Geometry[0]); - return resultarr; - } - - /** - * Creates a geometry through intersection between two geometries. - *

- * See OperatorIntersection. - * - * @param geometry1 The first geometry. - * @param intersector The geometry to intersect the first geometry. - * @param spatialReference The spatial reference of the geometries. - * @return The geometry created through intersection. - */ - public static Geometry intersect(Geometry geometry1, Geometry intersector, - SpatialReference spatialReference) { - OperatorIntersection op = (OperatorIntersection) factory.getOperator(Operator.Type.Intersection); - Geometry result = op.execute(geometry1, intersector, spatialReference,null); - return result; - } - - /** - * Indicates if one geometry is within another geometry. - *

- * See OperatorWithin. - * - * @param geometry1 The base geometry that is tested for within relationship to - * the other geometry. - * @param geometry2 The comparison geometry that is tested for the contains - * relationship to the other geometry. - * @param spatialReference The spatial reference of the geometries. - * @return TRUE if the first geometry is within the other geometry. - */ - public static boolean within(Geometry geometry1, Geometry geometry2, - SpatialReference spatialReference) { - OperatorWithin op = (OperatorWithin) factory - .getOperator(Operator.Type.Within); - boolean result = op.execute(geometry1, geometry2, spatialReference, - null); - return result; - } - - /** - * Indicates if one geometry contains another geometry. - *

- * See OperatorContains. - * - * @param geometry1 The geometry that is tested for the contains relationship to - * the other geometry.. - * @param geometry2 The geometry that is tested for within relationship to the - * other geometry. - * @param spatialReference The spatial reference of the geometries. - * @return TRUE if geometry1 contains geometry2. - */ - public static boolean contains(Geometry geometry1, Geometry geometry2, - SpatialReference spatialReference) { - OperatorContains op = (OperatorContains) factory - .getOperator(Operator.Type.Contains); - boolean result = op.execute(geometry1, geometry2, spatialReference, - null); - return result; - } - - /** - * Indicates if one geometry crosses another geometry. - *

- * See OperatorCrosses. - * - * @param geometry1 The geometry to cross. - * @param geometry2 The geometry being crossed. - * @param spatialReference The spatial reference of the geometries. - * @return TRUE if geometry1 crosses geometry2. - */ - public static boolean crosses(Geometry geometry1, Geometry geometry2, - SpatialReference spatialReference) { - OperatorCrosses op = (OperatorCrosses) factory - .getOperator(Operator.Type.Crosses); - boolean result = op.execute(geometry1, geometry2, spatialReference, - null); - return result; - } - - /** - * Indicates if one geometry touches another geometry. - *

- * See OperatorTouches. - * - * @param geometry1 The geometry to touch. - * @param geometry2 The geometry to be touched. - * @param spatialReference The spatial reference of the geometries. - * @return TRUE if geometry1 touches geometry2. - */ - public static boolean touches(Geometry geometry1, Geometry geometry2, - SpatialReference spatialReference) { - OperatorTouches op = (OperatorTouches) factory - .getOperator(Operator.Type.Touches); - boolean result = op.execute(geometry1, geometry2, spatialReference, - null); - return result; - } - - /** - * Indicates if one geometry overlaps another geometry. - *

- * See OperatorOverlaps. - * - * @param geometry1 The geometry to overlap. - * @param geometry2 The geometry to be overlapped. - * @param spatialReference The spatial reference of the geometries. - * @return TRUE if geometry1 overlaps geometry2. - */ - public static boolean overlaps(Geometry geometry1, Geometry geometry2, - SpatialReference spatialReference) { - OperatorOverlaps op = (OperatorOverlaps) factory - .getOperator(Operator.Type.Overlaps); - boolean result = op.execute(geometry1, geometry2, spatialReference, - null); - return result; - } - - /** - * Indicates if the given relation holds for the two geometries. - *

- * See OperatorRelate. - * - * @param geometry1 The first geometry for the relation. - * @param geometry2 The second geometry for the relation. - * @param spatialReference The spatial reference of the geometries. - * @param relation The DE-9IM relation. - * @return TRUE if the given relation holds between geometry1 and geometry2. - */ - public static boolean relate(Geometry geometry1, Geometry geometry2, - SpatialReference spatialReference, String relation) { - OperatorRelate op = (OperatorRelate) factory - .getOperator(Operator.Type.Relate); - boolean result = op.execute(geometry1, geometry2, spatialReference, - relation, null); - return result; - } - - /** - * Calculates the 2D planar distance between two geometries. - *

- * See OperatorDistance. - * - * @param geometry1 Geometry. - * @param geometry2 Geometry. - * @param spatialReference The spatial reference of the geometries. This parameter is not - * used and can be null. - * @return The distance between the two geometries. - */ - public static double distance(Geometry geometry1, Geometry geometry2, - SpatialReference spatialReference) { - OperatorDistance op = (OperatorDistance) factory - .getOperator(Operator.Type.Distance); - double result = op.execute(geometry1, geometry2, null); - return result; - } - - /** - * Calculates the clipped geometry from a target geometry using an envelope. - *

- * See OperatorClip. - * - * @param geometry The geometry to be clipped. - * @param envelope The envelope used to clip. - * @param spatialReference The spatial reference of the geometries. - * @return The geometry created by clipping. - */ - public static Geometry clip(Geometry geometry, Envelope envelope, - SpatialReference spatialReference) { - OperatorClip op = (OperatorClip) factory - .getOperator(Operator.Type.Clip); - Geometry result = op.execute(geometry, Envelope2D.construct( - envelope.getXMin(), envelope.getYMin(), envelope.getXMax(), - envelope.getYMax()), spatialReference, null); - return result; - } - - /** - * Calculates the cut geometry from a target geometry using a polyline. For - * Polylines, all left cuts will be grouped together in the first Geometry, - * Right cuts and coincident cuts are grouped in the second Geometry, and - * each undefined cut, along with any uncut parts, are output as separate - * Polylines. For Polygons, all left cuts are grouped in the first Polygon, - * all right cuts are in the second Polygon, and each undefined cut, along - * with any left-over parts after cutting, are output as a separate Polygon. - * If there were no cuts then the array will be empty. An undefined cut will - * only be produced if a left cut or right cut was produced, and there was a - * part left over after cutting or a cut is bounded to the left and right of - * the cutter. - *

- * See OperatorCut. - * - * @param cuttee The geometry to be cut. - * @param cutter The polyline to cut the geometry. - * @param spatialReference The spatial reference of the geometries. - * @return An array of geometries created from cutting. - */ - public static Geometry[] cut(Geometry cuttee, Polyline cutter, - SpatialReference spatialReference) { - if (cuttee == null || cutter == null) - return null; - - OperatorCut op = (OperatorCut) factory.getOperator(Operator.Type.Cut); - GeometryCursor cursor = op.execute(true, cuttee, cutter, - spatialReference, null); - ArrayList cutsList = new ArrayList(); - - Geometry geometry; - while ((geometry = cursor.next()) != null) { - if (!geometry.isEmpty()) { - cutsList.add(geometry); - } - } - - return cutsList.toArray(new Geometry[0]); - } - - /** - * Calculates a buffer polygon for each geometry at each of the - * corresponding specified distances. It is assumed that all geometries have - * the same spatial reference. There is an option to union the - * returned geometries. - *

- * See OperatorBuffer. - * - * @param geometries An array of geometries to be buffered. - * @param spatialReference The spatial reference of the geometries. - * @param distances The corresponding distances for the input geometries to be buffered. - * @param toUnionResults TRUE if all geometries buffered at a given distance are to be unioned into a single polygon. - * @return The buffer of the geometries. - */ - public static Polygon[] buffer(Geometry[] geometries, - SpatialReference spatialReference, double[] distances, - boolean toUnionResults) { - // initially assume distances are in unit of spatial reference - double[] bufferDistances = distances; - - OperatorBuffer op = (OperatorBuffer) factory - .getOperator(Operator.Type.Buffer); - - if (toUnionResults) { - SimpleGeometryCursor inputGeometriesCursor = new SimpleGeometryCursor( - geometries); - GeometryCursor result = op.execute(inputGeometriesCursor, - spatialReference, bufferDistances, toUnionResults, null); - - ArrayList resultGeoms = new ArrayList(); - Geometry g; - while ((g = result.next()) != null) { - resultGeoms.add((Polygon) g); - } - Polygon[] buffers = resultGeoms.toArray(new Polygon[0]); - return buffers; - } else { - Polygon[] buffers = new Polygon[geometries.length]; - for (int i = 0; i < geometries.length; i++) { - buffers[i] = (Polygon) op.execute(geometries[i], - spatialReference, bufferDistances[i], null); - } - return buffers; - } - } - - public static Polygon geodesicBuffer(Geometry geometry, SpatialReference spatialReference, double d) { - OperatorGeodesicBuffer operatorGeodesicBuffer = (OperatorGeodesicBuffer)factory.getOperator(Operator.Type.GeodesicBuffer); - return (Polygon) operatorGeodesicBuffer.execute(geometry, spatialReference, 0, d, Double.NaN, false, null); - } - - public static Geometry project(Geometry geometry, SpatialReference spatialReferenceInput, SpatialReference spatialReferenceOutput) { - OperatorProject operatorProject = (OperatorProject) factory.getOperator(Operator.Type.Project); - ProjectionTransformation projectionTransformation = new ProjectionTransformation(spatialReferenceInput, spatialReferenceOutput); - return operatorProject.execute(geometry, projectionTransformation, null); - } - - /** - * Calculates a buffer polygon of the geometry as specified by the - * distance input. The buffer is implemented in the xy-plane. - *

- * See OperatorBuffer - * - * @param geometry Geometry to be buffered. - * @param spatialReference The spatial reference of the geometry. - * @param distance The specified distance for buffer. Same units as the spatial reference. - * @return The buffer polygon at the specified distances. - */ - public static Polygon buffer(Geometry geometry, - SpatialReference spatialReference, double distance) { - double bufferDistance = distance; - - OperatorBuffer op = (OperatorBuffer) factory - .getOperator(Operator.Type.Buffer); - Geometry result = op.execute(geometry, spatialReference, - bufferDistance, null); - return (Polygon) result; - } - - /** - * Calculates the convex hull geometry. - *

- * See OperatorConvexHull. - * - * @param geometry The input geometry. - * @return Returns the convex hull. - *

- * For a Point - returns the same point. For an Envelope - - * returns the same envelope. For a MultiPoint - If the point - * count is one, returns the same multipoint. If the point count - * is two, returns a polyline of the points. Otherwise computes - * and returns the convex hull polygon. For a Segment - returns a - * polyline consisting of the segment. For a Polyline - If - * consists of only one segment, returns the same polyline. - * Otherwise computes and returns the convex hull polygon. For a - * Polygon - If more than one path, or if the path isn't already - * convex, computes and returns the convex hull polygon. - * Otherwise returns the same polygon. - */ - public static Geometry convexHull(Geometry geometry) { - OperatorConvexHull op = (OperatorConvexHull) factory - .getOperator(Operator.Type.ConvexHull); - return op.execute(geometry, null); - } - - /** - * Calculates the convex hull. - *

- * See OperatorConvexHull - * - * @param geometries The input geometry array. - * @param b_merge Put true if you want the convex hull of all the geometries in - * the array combined. Put false if you want the convex hull of - * each geometry in the array individually. - * @return Returns an array of convex hulls. If b_merge is true, the result - * will be a one element array consisting of the merged convex hull. - */ - public static Geometry[] convexHull(Geometry[] geometries, boolean b_merge) { - OperatorConvexHull op = (OperatorConvexHull) factory - .getOperator(Operator.Type.ConvexHull); - SimpleGeometryCursor simple_cursor = new SimpleGeometryCursor( - geometries); - GeometryCursor cursor = op.execute(simple_cursor, b_merge, null); - - ArrayList resultGeoms = new ArrayList(); - Geometry g; - while ((g = cursor.next()) != null) { - resultGeoms.add(g); - } - - Geometry[] output = new Geometry[resultGeoms.size()]; - - for (int i = 0; i < resultGeoms.size(); i++) - output[i] = resultGeoms.get(i); - - return output; - } - - /** - * Finds the coordinate of the geometry which is closest to the specified - * point. - *

- * See OperatorProximity2D. - * - * @param inputPoint The point to find the nearest coordinate in the geometry for. - * @param geometry The geometry to consider. - * @return Proximity2DResult containing the nearest coordinate. - */ - public static Proximity2DResult getNearestCoordinate(Geometry geometry, - Point inputPoint, boolean bTestPolygonInterior) { - - OperatorProximity2D proximity = (OperatorProximity2D) factory - .getOperator(com.esri.core.geometry.Operator.Type.Proximity2D); - Proximity2DResult result = proximity.getNearestCoordinate(geometry, - inputPoint, bTestPolygonInterior); - return result; - } - - /** - * Finds nearest vertex on the geometry which is closed to the specified - * point. - *

- * See OperatorProximity2D. - * - * @param inputPoint The point to find the nearest vertex of the geometry for. - * @param geometry The geometry to consider. - * @return Proximity2DResult containing the nearest vertex. - */ - public static Proximity2DResult getNearestVertex(Geometry geometry, - Point inputPoint) { - OperatorProximity2D proximity = (OperatorProximity2D) factory - .getOperator(com.esri.core.geometry.Operator.Type.Proximity2D); - Proximity2DResult result = proximity.getNearestVertex(geometry, - inputPoint); - return result; - } - - /** - * Finds all vertices in the given distance from the specified point, sorted - * from the closest to the furthest. - *

- * See OperatorProximity2D. - * - * @param inputPoint The point to start from. - * @param geometry The geometry to consider. - * @param searchRadius The search radius. - * @param maxVertexCountToReturn The maximum number number of vertices to return. - * @return Proximity2DResult containing the array of nearest vertices. - */ - public static Proximity2DResult[] getNearestVertices(Geometry geometry, - Point inputPoint, double searchRadius, int maxVertexCountToReturn) { - OperatorProximity2D proximity = (OperatorProximity2D) factory - .getOperator(com.esri.core.geometry.Operator.Type.Proximity2D); - - Proximity2DResult[] results = proximity.getNearestVertices(geometry, - inputPoint, searchRadius, maxVertexCountToReturn); - - return results; - } - - /** - * Performs the simplify operation on the geometry. - *

- * See OperatorSimplify and See OperatorSimplifyOGC. - * - * @param geometry The geometry to be simplified. - * @param spatialReference The spatial reference of the geometry to be simplified. - * @return The simplified geometry. - */ - public static Geometry simplify(Geometry geometry, - SpatialReference spatialReference) { - OperatorSimplify op = (OperatorSimplify) factory - .getOperator(Operator.Type.Simplify); - Geometry result = op.execute(geometry, spatialReference, false, null); - return result; - } - - /** - * Checks if the Geometry is simple. - *

- * See OperatorSimplify. - * - * @param geometry The geometry to be checked. - * @param spatialReference The spatial reference of the geometry. - * @return TRUE if the geometry is simple. - */ - static boolean isSimple(Geometry geometry, SpatialReference spatialReference) { - OperatorSimplify op = (OperatorSimplify) factory - .getOperator(Operator.Type.Simplify); - boolean result = op.isSimpleAsFeature(geometry, spatialReference, null); - return result; - } - - /** - * A geodesic distance is the shortest distance between any two points on the earth's surface when the earth's - * surface is approximated by a spheroid. The function returns the shortest distance between two points on the - * WGS84 spheroid. - * - * @param ptFrom The "from" point: long, lat in degrees. - * @param ptTo The "to" point: long, lat in degrees. - * @return The geodesic distance between two points in meters. - */ - public static double geodesicDistanceOnWGS84(Point ptFrom, Point ptTo) { - return SpatialReferenceImpl.geodesicDistanceOnWGS84Impl(ptFrom, ptTo); - } + /** + * Exports a geometry to a string in WKT format. + *

+ * See OperatorExportToWkt. + * + * @param geometry The geometry to export. (null value is not allowed) + * @param exportFlags Use the {@link WktExportFlags} interface. + * @return A String containing the exported geometry in WKT format. + */ + public static String geometryToWkt(Geometry geometry, int exportFlags) { + OperatorExportToWkt op = (OperatorExportToWkt) factory + .getOperator(Operator.Type.ExportToWkt); + return op.execute(exportFlags, geometry, null); + } + + /** + * Constructs a new geometry by union an array of geometries. All inputs + * must be of the same type of geometries and share one spatial reference. + *

+ * See OperatorUnion. + * + * @param geometries The geometries to union. + * @param spatialReference The spatial reference of the geometries. + * @return The geometry object representing the resultant union. + */ + public static Geometry union(Geometry[] geometries, SpatialReference spatialReference) { + OperatorUnion op = (OperatorUnion) factory.getOperator(Operator.Type.Union); + + SimpleGeometryCursor inputGeometries = new SimpleGeometryCursor(geometries); + GeometryCursor result = op.execute(inputGeometries, spatialReference, null); + return result.next(); + } + + /** + * Creates the difference of two geometries. The dimension of geometry2 has + * to be equal to or greater than that of geometry1. + *

+ * See OperatorDifference. + * + * @param geometry1 The geometry being subtracted. + * @param substractor The geometry object to subtract from. + * @param spatialReference The spatial reference of the geometries. + * @return The geometry of the differences. + */ + public static Geometry difference(Geometry geometry1, Geometry substractor, + SpatialReference spatialReference) { + OperatorDifference op = (OperatorDifference) factory.getOperator(Operator.Type.Difference); + Geometry result = op.execute(geometry1, substractor, spatialReference, null); + return result; + } + + /** + * Creates the symmetric difference of two geometries. + *

+ * See OperatorSymmetricDifference. + * + * @param leftGeometry is one of the Geometry instances in the XOR operation. + * @param rightGeometry is one of the Geometry instances in the XOR operation. + * @param spatialReference The spatial reference of the geometries. + * @return Returns the result of the symmetric difference. + */ + public static Geometry symmetricDifference(Geometry leftGeometry, + Geometry rightGeometry, SpatialReference spatialReference) { + OperatorSymmetricDifference op = (OperatorSymmetricDifference) factory + .getOperator(Operator.Type.SymmetricDifference); + Geometry result = op.execute(leftGeometry, rightGeometry, + spatialReference, null); + return result; + } + + /** + * Indicates if two geometries are equal. + *

+ * See OperatorEquals. + * + * @param geometry1 Geometry. + * @param geometry2 Geometry. + * @param spatialReference The spatial reference of the geometries. + * @return TRUE if both geometry objects are equal. + */ + public static boolean equals(Geometry geometry1, Geometry geometry2, + SpatialReference spatialReference) { + OperatorEquals op = (OperatorEquals) factory + .getOperator(Operator.Type.Equals); + boolean result = op.execute(geometry1, geometry2, spatialReference, + null); + return result; + } + + /** + * See OperatorDisjoint. + */ + public static boolean disjoint(Geometry geometry1, Geometry geometry2, + SpatialReference spatialReference) { + OperatorDisjoint op = (OperatorDisjoint) factory + .getOperator(Operator.Type.Disjoint); + boolean result = op.execute(geometry1, geometry2, spatialReference, + null); + return result; + } + + /** + * Constructs the set-theoretic intersection between an array of geometries + * and another geometry. + *

+ * See OperatorIntersection (also for dimension specific intersection). + * + * @param inputGeometries An array of geometry objects. + * @param geometry The geometry object. + * @return Any array of geometry objects showing the intersection. + */ + static Geometry[] intersect(Geometry[] inputGeometries, Geometry geometry, + SpatialReference spatialReference) { + OperatorIntersection op = (OperatorIntersection) factory + .getOperator(Operator.Type.Intersection); + SimpleGeometryCursor inputGeometriesCursor = new SimpleGeometryCursor( + inputGeometries); + SimpleGeometryCursor intersectorCursor = new SimpleGeometryCursor( + geometry); + GeometryCursor result = op.execute(inputGeometriesCursor, + intersectorCursor, spatialReference, null); + + ArrayList resultGeoms = new ArrayList(); + Geometry g; + while ((g = result.next()) != null) { + resultGeoms.add(g); + } + + Geometry[] resultarr = resultGeoms.toArray(new Geometry[0]); + return resultarr; + } + + /** + * Creates a geometry through intersection between two geometries. + *

+ * See OperatorIntersection. + * + * @param geometry1 The first geometry. + * @param intersector The geometry to intersect the first geometry. + * @param spatialReference The spatial reference of the geometries. + * @return The geometry created through intersection. + */ + public static Geometry intersect(Geometry geometry1, Geometry intersector, + SpatialReference spatialReference) { + OperatorIntersection op = (OperatorIntersection) factory.getOperator(Operator.Type.Intersection); + Geometry result = op.execute(geometry1, intersector, spatialReference, null); + return result; + } + + /** + * Indicates if one geometry is within another geometry. + *

+ * See OperatorWithin. + * + * @param geometry1 The base geometry that is tested for within relationship to + * the other geometry. + * @param geometry2 The comparison geometry that is tested for the contains + * relationship to the other geometry. + * @param spatialReference The spatial reference of the geometries. + * @return TRUE if the first geometry is within the other geometry. + */ + public static boolean within(Geometry geometry1, Geometry geometry2, + SpatialReference spatialReference) { + OperatorWithin op = (OperatorWithin) factory + .getOperator(Operator.Type.Within); + boolean result = op.execute(geometry1, geometry2, spatialReference, + null); + return result; + } + + /** + * Indicates if one geometry contains another geometry. + *

+ * See OperatorContains. + * + * @param geometry1 The geometry that is tested for the contains relationship to + * the other geometry.. + * @param geometry2 The geometry that is tested for within relationship to the + * other geometry. + * @param spatialReference The spatial reference of the geometries. + * @return TRUE if geometry1 contains geometry2. + */ + public static boolean contains(Geometry geometry1, Geometry geometry2, + SpatialReference spatialReference) { + OperatorContains op = (OperatorContains) factory + .getOperator(Operator.Type.Contains); + boolean result = op.execute(geometry1, geometry2, spatialReference, + null); + return result; + } + + /** + * Indicates if one geometry crosses another geometry. + *

+ * See OperatorCrosses. + * + * @param geometry1 The geometry to cross. + * @param geometry2 The geometry being crossed. + * @param spatialReference The spatial reference of the geometries. + * @return TRUE if geometry1 crosses geometry2. + */ + public static boolean crosses(Geometry geometry1, Geometry geometry2, + SpatialReference spatialReference) { + OperatorCrosses op = (OperatorCrosses) factory + .getOperator(Operator.Type.Crosses); + boolean result = op.execute(geometry1, geometry2, spatialReference, + null); + return result; + } + + /** + * Indicates if one geometry touches another geometry. + *

+ * See OperatorTouches. + * + * @param geometry1 The geometry to touch. + * @param geometry2 The geometry to be touched. + * @param spatialReference The spatial reference of the geometries. + * @return TRUE if geometry1 touches geometry2. + */ + public static boolean touches(Geometry geometry1, Geometry geometry2, + SpatialReference spatialReference) { + OperatorTouches op = (OperatorTouches) factory + .getOperator(Operator.Type.Touches); + boolean result = op.execute(geometry1, geometry2, spatialReference, + null); + return result; + } + + /** + * Indicates if one geometry overlaps another geometry. + *

+ * See OperatorOverlaps. + * + * @param geometry1 The geometry to overlap. + * @param geometry2 The geometry to be overlapped. + * @param spatialReference The spatial reference of the geometries. + * @return TRUE if geometry1 overlaps geometry2. + */ + public static boolean overlaps(Geometry geometry1, Geometry geometry2, + SpatialReference spatialReference) { + OperatorOverlaps op = (OperatorOverlaps) factory + .getOperator(Operator.Type.Overlaps); + boolean result = op.execute(geometry1, geometry2, spatialReference, + null); + return result; + } + + /** + * Indicates if the given relation holds for the two geometries. + *

+ * See OperatorRelate. + * + * @param geometry1 The first geometry for the relation. + * @param geometry2 The second geometry for the relation. + * @param spatialReference The spatial reference of the geometries. + * @param relation The DE-9IM relation. + * @return TRUE if the given relation holds between geometry1 and geometry2. + */ + public static boolean relate(Geometry geometry1, Geometry geometry2, + SpatialReference spatialReference, String relation) { + OperatorRelate op = (OperatorRelate) factory + .getOperator(Operator.Type.Relate); + boolean result = op.execute(geometry1, geometry2, spatialReference, + relation, null); + return result; + } + + /** + * Calculates the 2D planar distance between two geometries. + *

+ * See OperatorDistance. + * + * @param geometry1 Geometry. + * @param geometry2 Geometry. + * @param spatialReference The spatial reference of the geometries. This parameter is not + * used and can be null. + * @return The distance between the two geometries. + */ + public static double distance(Geometry geometry1, Geometry geometry2, + SpatialReference spatialReference) { + OperatorDistance op = (OperatorDistance) factory + .getOperator(Operator.Type.Distance); + double result = op.execute(geometry1, geometry2, null); + return result; + } + + /** + * Calculates the clipped geometry from a target geometry using an envelope. + *

+ * See OperatorClip. + * + * @param geometry The geometry to be clipped. + * @param envelope The envelope used to clip. + * @param spatialReference The spatial reference of the geometries. + * @return The geometry created by clipping. + */ + public static Geometry clip(Geometry geometry, Envelope envelope, + SpatialReference spatialReference) { + OperatorClip op = (OperatorClip) factory + .getOperator(Operator.Type.Clip); + Geometry result = op.execute(geometry, Envelope2D.construct( + envelope.getXMin(), envelope.getYMin(), envelope.getXMax(), + envelope.getYMax()), spatialReference, null); + return result; + } + + /** + * Calculates the cut geometry from a target geometry using a polyline. For + * Polylines, all left cuts will be grouped together in the first Geometry, + * Right cuts and coincident cuts are grouped in the second Geometry, and + * each undefined cut, along with any uncut parts, are output as separate + * Polylines. For Polygons, all left cuts are grouped in the first Polygon, + * all right cuts are in the second Polygon, and each undefined cut, along + * with any left-over parts after cutting, are output as a separate Polygon. + * If there were no cuts then the array will be empty. An undefined cut will + * only be produced if a left cut or right cut was produced, and there was a + * part left over after cutting or a cut is bounded to the left and right of + * the cutter. + *

+ * See OperatorCut. + * + * @param cuttee The geometry to be cut. + * @param cutter The polyline to cut the geometry. + * @param spatialReference The spatial reference of the geometries. + * @return An array of geometries created from cutting. + */ + public static Geometry[] cut(Geometry cuttee, Polyline cutter, + SpatialReference spatialReference) { + if (cuttee == null || cutter == null) + return null; + + OperatorCut op = (OperatorCut) factory.getOperator(Operator.Type.Cut); + GeometryCursor cursor = op.execute(true, cuttee, cutter, + spatialReference, null); + ArrayList cutsList = new ArrayList(); + + Geometry geometry; + while ((geometry = cursor.next()) != null) { + if (!geometry.isEmpty()) { + cutsList.add(geometry); + } + } + + return cutsList.toArray(new Geometry[0]); + } + + /** + * Calculates a buffer polygon for each geometry at each of the + * corresponding specified distances. It is assumed that all geometries have + * the same spatial reference. There is an option to union the + * returned geometries. + *

+ * See OperatorBuffer. + * + * @param geometries An array of geometries to be buffered. + * @param spatialReference The spatial reference of the geometries. + * @param distances The corresponding distances for the input geometries to be buffered. + * @param toUnionResults TRUE if all geometries buffered at a given distance are to be unioned into a single polygon. + * @return The buffer of the geometries. + */ + public static Polygon[] buffer(Geometry[] geometries, + SpatialReference spatialReference, double[] distances, + boolean toUnionResults) { + // initially assume distances are in unit of spatial reference + double[] bufferDistances = distances; + + OperatorBuffer op = (OperatorBuffer) factory + .getOperator(Operator.Type.Buffer); + + if (toUnionResults) { + SimpleGeometryCursor inputGeometriesCursor = new SimpleGeometryCursor( + geometries); + GeometryCursor result = op.execute(inputGeometriesCursor, + spatialReference, bufferDistances, toUnionResults, null); + + ArrayList resultGeoms = new ArrayList(); + Geometry g; + while ((g = result.next()) != null) { + resultGeoms.add((Polygon) g); + } + Polygon[] buffers = resultGeoms.toArray(new Polygon[0]); + return buffers; + } else { + Polygon[] buffers = new Polygon[geometries.length]; + for (int i = 0; i < geometries.length; i++) { + buffers[i] = (Polygon) op.execute(geometries[i], + spatialReference, bufferDistances[i], null); + } + return buffers; + } + } + + public static Polygon geodesicBuffer(Geometry geometry, SpatialReference spatialReference, double d) { + OperatorGeodesicBuffer operatorGeodesicBuffer = (OperatorGeodesicBuffer) factory.getOperator(Operator.Type.GeodesicBuffer); + return (Polygon) operatorGeodesicBuffer.execute(geometry, spatialReference, 0, d, Double.NaN, false, null); + } + + public static Geometry project(Geometry geometry, SpatialReference spatialReferenceInput, SpatialReference spatialReferenceOutput) { + OperatorProject operatorProject = (OperatorProject) factory.getOperator(Operator.Type.Project); + ProjectionTransformation projectionTransformation = new ProjectionTransformation(spatialReferenceInput, spatialReferenceOutput); + return operatorProject.execute(geometry, projectionTransformation, null); + } + + /** + * Calculates a buffer polygon of the geometry as specified by the + * distance input. The buffer is implemented in the xy-plane. + *

+ * See OperatorBuffer + * + * @param geometry Geometry to be buffered. + * @param spatialReference The spatial reference of the geometry. + * @param distance The specified distance for buffer. Same units as the spatial reference. + * @return The buffer polygon at the specified distances. + */ + public static Polygon buffer(Geometry geometry, + SpatialReference spatialReference, double distance) { + double bufferDistance = distance; + + OperatorBuffer op = (OperatorBuffer) factory + .getOperator(Operator.Type.Buffer); + Geometry result = op.execute(geometry, spatialReference, + bufferDistance, null); + return (Polygon) result; + } + + /** + * Calculates the convex hull geometry. + *

+ * See OperatorConvexHull. + * + * @param geometry The input geometry. + * @return Returns the convex hull. + *

+ * For a Point - returns the same point. For an Envelope - + * returns the same envelope. For a MultiPoint - If the point + * count is one, returns the same multipoint. If the point count + * is two, returns a polyline of the points. Otherwise computes + * and returns the convex hull polygon. For a Segment - returns a + * polyline consisting of the segment. For a Polyline - If + * consists of only one segment, returns the same polyline. + * Otherwise computes and returns the convex hull polygon. For a + * Polygon - If more than one path, or if the path isn't already + * convex, computes and returns the convex hull polygon. + * Otherwise returns the same polygon. + */ + public static Geometry convexHull(Geometry geometry) { + OperatorConvexHull op = (OperatorConvexHull) factory + .getOperator(Operator.Type.ConvexHull); + return op.execute(geometry, null); + } + + /** + * Calculates the convex hull. + *

+ * See OperatorConvexHull + * + * @param geometries The input geometry array. + * @param b_merge Put true if you want the convex hull of all the geometries in + * the array combined. Put false if you want the convex hull of + * each geometry in the array individually. + * @return Returns an array of convex hulls. If b_merge is true, the result + * will be a one element array consisting of the merged convex hull. + */ + public static Geometry[] convexHull(Geometry[] geometries, boolean b_merge) { + OperatorConvexHull op = (OperatorConvexHull) factory + .getOperator(Operator.Type.ConvexHull); + SimpleGeometryCursor simple_cursor = new SimpleGeometryCursor( + geometries); + GeometryCursor cursor = op.execute(simple_cursor, b_merge, null); + + ArrayList resultGeoms = new ArrayList(); + Geometry g; + while ((g = cursor.next()) != null) { + resultGeoms.add(g); + } + + Geometry[] output = new Geometry[resultGeoms.size()]; + + for (int i = 0; i < resultGeoms.size(); i++) + output[i] = resultGeoms.get(i); + + return output; + } + + /** + * Finds the coordinate of the geometry which is closest to the specified + * point. + *

+ * See OperatorProximity2D. + * + * @param inputPoint The point to find the nearest coordinate in the geometry for. + * @param geometry The geometry to consider. + * @return Proximity2DResult containing the nearest coordinate. + */ + public static Proximity2DResult getNearestCoordinate(Geometry geometry, + Point inputPoint, boolean bTestPolygonInterior) { + + OperatorProximity2D proximity = (OperatorProximity2D) factory + .getOperator(com.esri.core.geometry.Operator.Type.Proximity2D); + Proximity2DResult result = proximity.getNearestCoordinate(geometry, + inputPoint, bTestPolygonInterior); + return result; + } + + /** + * Finds nearest vertex on the geometry which is closed to the specified + * point. + *

+ * See OperatorProximity2D. + * + * @param inputPoint The point to find the nearest vertex of the geometry for. + * @param geometry The geometry to consider. + * @return Proximity2DResult containing the nearest vertex. + */ + public static Proximity2DResult getNearestVertex(Geometry geometry, + Point inputPoint) { + OperatorProximity2D proximity = (OperatorProximity2D) factory + .getOperator(com.esri.core.geometry.Operator.Type.Proximity2D); + Proximity2DResult result = proximity.getNearestVertex(geometry, + inputPoint); + return result; + } + + /** + * Finds all vertices in the given distance from the specified point, sorted + * from the closest to the furthest. + *

+ * See OperatorProximity2D. + * + * @param inputPoint The point to start from. + * @param geometry The geometry to consider. + * @param searchRadius The search radius. + * @param maxVertexCountToReturn The maximum number number of vertices to return. + * @return Proximity2DResult containing the array of nearest vertices. + */ + public static Proximity2DResult[] getNearestVertices(Geometry geometry, + Point inputPoint, double searchRadius, int maxVertexCountToReturn) { + OperatorProximity2D proximity = (OperatorProximity2D) factory + .getOperator(com.esri.core.geometry.Operator.Type.Proximity2D); + + Proximity2DResult[] results = proximity.getNearestVertices(geometry, + inputPoint, searchRadius, maxVertexCountToReturn); + + return results; + } + + /** + * Performs the simplify operation on the geometry. + *

+ * See OperatorSimplify and See OperatorSimplifyOGC. + * + * @param geometry The geometry to be simplified. + * @param spatialReference The spatial reference of the geometry to be simplified. + * @return The simplified geometry. + */ + public static Geometry simplify(Geometry geometry, + SpatialReference spatialReference) { + OperatorSimplify op = (OperatorSimplify) factory + .getOperator(Operator.Type.Simplify); + Geometry result = op.execute(geometry, spatialReference, false, null); + return result; + } + + /** + * Checks if the Geometry is simple. + *

+ * See OperatorSimplify. + * + * @param geometry The geometry to be checked. + * @param spatialReference The spatial reference of the geometry. + * @return TRUE if the geometry is simple. + */ + static boolean isSimple(Geometry geometry, SpatialReference spatialReference) { + OperatorSimplify op = (OperatorSimplify) factory + .getOperator(Operator.Type.Simplify); + boolean result = op.isSimpleAsFeature(geometry, spatialReference, null); + return result; + } + + /** + * A geodesic distance is the shortest distance between any two points on the earth's surface when the earth's + * surface is approximated by a spheroid. The function returns the shortest distance between two points on the + * WGS84 spheroid. + * + * @param ptFrom The "from" point: long, lat in degrees. + * @param ptTo The "to" point: long, lat in degrees. + * @return The geodesic distance between two points in meters. + */ + public static double geodesicDistanceOnWGS84(Point ptFrom, Point ptTo) { + return SpatialReferenceImpl.geodesicDistanceOnWGS84Impl(ptFrom, ptTo); + } } diff --git a/src/main/java/com/esri/core/geometry/GeometryException.java b/src/main/java/com/esri/core/geometry/GeometryException.java index 27c454fe..75498a73 100644 --- a/src/main/java/com/esri/core/geometry/GeometryException.java +++ b/src/main/java/com/esri/core/geometry/GeometryException.java @@ -30,18 +30,18 @@ */ public class GeometryException extends RuntimeException { - private static final long serialVersionUID = 1L; - - /** - * Constructs a Geometry Exception with the given error string/message. - * - * @param str - The error string. - */ - public GeometryException(String str) { - super(str); - } - - static GeometryException GeometryInternalError() { - return new GeometryException("internal error"); - } + private static final long serialVersionUID = 1L; + + /** + * Constructs a Geometry Exception with the given error string/message. + * + * @param str - The error string. + */ + public GeometryException(String str) { + super(str); + } + + static GeometryException GeometryInternalError() { + return new GeometryException("internal error"); + } } diff --git a/src/main/java/com/esri/core/geometry/GeometrySerializer.java b/src/main/java/com/esri/core/geometry/GeometrySerializer.java index 70f983f4..247a6746 100644 --- a/src/main/java/com/esri/core/geometry/GeometrySerializer.java +++ b/src/main/java/com/esri/core/geometry/GeometrySerializer.java @@ -30,89 +30,89 @@ //Left here for backward compatibility. Use GenericGeometrySerializer instead @Deprecated final class GeometrySerializer implements Serializable { - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 1L; - static class BaseGeometryData implements Serializable { - Geometry.Type geometryType; - byte[] esriShape = null; - } + static class BaseGeometryData implements Serializable { + Geometry.Type geometryType; + byte[] esriShape = null; + } - static class MultiVertexData extends BaseGeometryData { - int simpleFlag = 0; - double tolerance = 0; - } + static class MultiVertexData extends BaseGeometryData { + int simpleFlag = 0; + double tolerance = 0; + } - static class MultiPathData extends MultiVertexData { - boolean[] ogcFlags = null; - } + static class MultiPathData extends MultiVertexData { + boolean[] ogcFlags = null; + } - BaseGeometryData geometryData; + BaseGeometryData geometryData; - Object readResolve() throws ObjectStreamException { - Geometry geometry = null; - try { - geometry = GeometryEngine.geometryFromEsriShape( - geometryData.esriShape, geometryData.geometryType); - if (Geometry.isMultiVertex(geometry.getType().value())) { - MultiVertexData mvd = (MultiVertexData) geometryData; - MultiVertexGeometryImpl mvImpl = (MultiVertexGeometryImpl) geometry - ._getImpl(); - if (!geometry.isEmpty() - && Geometry.isMultiPath(geometry.getType().value())) { - MultiPathData mpd = (MultiPathData) geometryData; - MultiPathImpl mpImpl = (MultiPathImpl) geometry._getImpl(); - AttributeStreamOfInt8 pathFlags = mpImpl - .getPathFlagsStreamRef(); - for (int i = 0, n = mpImpl.getPathCount(); i < n; i++) { - if (mpd.ogcFlags[i]) - pathFlags.setBits(i, - (byte) PathFlags.enumOGCStartPolygon); - } - } - mvImpl.setIsSimple(mvd.simpleFlag, mvd.tolerance, false); - } + Object readResolve() throws ObjectStreamException { + Geometry geometry = null; + try { + geometry = GeometryEngine.geometryFromEsriShape( + geometryData.esriShape, geometryData.geometryType); + if (Geometry.isMultiVertex(geometry.getType().value())) { + MultiVertexData mvd = (MultiVertexData) geometryData; + MultiVertexGeometryImpl mvImpl = (MultiVertexGeometryImpl) geometry + ._getImpl(); + if (!geometry.isEmpty() + && Geometry.isMultiPath(geometry.getType().value())) { + MultiPathData mpd = (MultiPathData) geometryData; + MultiPathImpl mpImpl = (MultiPathImpl) geometry._getImpl(); + AttributeStreamOfInt8 pathFlags = mpImpl + .getPathFlagsStreamRef(); + for (int i = 0, n = mpImpl.getPathCount(); i < n; i++) { + if (mpd.ogcFlags[i]) + pathFlags.setBits(i, + (byte) PathFlags.enumOGCStartPolygon); + } + } + mvImpl.setIsSimple(mvd.simpleFlag, mvd.tolerance, false); + } - } catch (Exception ex) { - throw new InvalidObjectException("Cannot read geometry from stream"); - } - return geometry; - } + } catch (Exception ex) { + throw new InvalidObjectException("Cannot read geometry from stream"); + } + return geometry; + } - public void setGeometryByValue(Geometry geometry) - throws ObjectStreamException { - try { - if (Geometry.isMultiPath(geometry.getType().value())) { - geometryData = new MultiPathData(); - } else if (Geometry.isMultiVertex(geometry.getType().value())) { - geometryData = new MultiVertexData(); - } else { - geometryData = new BaseGeometryData(); - } - geometryData.esriShape = GeometryEngine - .geometryToEsriShape(geometry); - geometryData.geometryType = geometry.getType(); - if (Geometry.isMultiVertex(geometryData.geometryType.value())) { - MultiVertexData mvd = (MultiVertexData) geometryData; - MultiVertexGeometryImpl mvImpl = (MultiVertexGeometryImpl) geometry - ._getImpl(); - mvd.tolerance = mvImpl.m_simpleTolerance; - mvd.simpleFlag = mvImpl.getIsSimple(0); - if (!geometry.isEmpty() - && Geometry.isMultiPath(geometryData.geometryType - .value())) { - MultiPathData mpd = (MultiPathData) geometryData; - MultiPathImpl mpImpl = (MultiPathImpl) geometry._getImpl(); - mpd.ogcFlags = new boolean[mpImpl.getPathCount()]; - AttributeStreamOfInt8 pathFlags = mpImpl - .getPathFlagsStreamRef(); - for (int i = 0, n = mpImpl.getPathCount(); i < n; i++) { - mpd.ogcFlags[i] = (pathFlags.read(i) & (byte) PathFlags.enumOGCStartPolygon) != 0; - } - } + public void setGeometryByValue(Geometry geometry) + throws ObjectStreamException { + try { + if (Geometry.isMultiPath(geometry.getType().value())) { + geometryData = new MultiPathData(); + } else if (Geometry.isMultiVertex(geometry.getType().value())) { + geometryData = new MultiVertexData(); + } else { + geometryData = new BaseGeometryData(); + } + geometryData.esriShape = GeometryEngine + .geometryToEsriShape(geometry); + geometryData.geometryType = geometry.getType(); + if (Geometry.isMultiVertex(geometryData.geometryType.value())) { + MultiVertexData mvd = (MultiVertexData) geometryData; + MultiVertexGeometryImpl mvImpl = (MultiVertexGeometryImpl) geometry + ._getImpl(); + mvd.tolerance = mvImpl.m_simpleTolerance; + mvd.simpleFlag = mvImpl.getIsSimple(0); + if (!geometry.isEmpty() + && Geometry.isMultiPath(geometryData.geometryType + .value())) { + MultiPathData mpd = (MultiPathData) geometryData; + MultiPathImpl mpImpl = (MultiPathImpl) geometry._getImpl(); + mpd.ogcFlags = new boolean[mpImpl.getPathCount()]; + AttributeStreamOfInt8 pathFlags = mpImpl + .getPathFlagsStreamRef(); + for (int i = 0, n = mpImpl.getPathCount(); i < n; i++) { + mpd.ogcFlags[i] = (pathFlags.read(i) & (byte) PathFlags.enumOGCStartPolygon) != 0; + } + } - } - } catch (Exception ex) { - throw new InvalidObjectException("Cannot serialize this geometry"); - } - } + } + } catch (Exception ex) { + throw new InvalidObjectException("Cannot serialize this geometry"); + } + } } diff --git a/src/main/java/com/esri/core/geometry/IndexHashTable.java b/src/main/java/com/esri/core/geometry/IndexHashTable.java index 8ef6bfce..d95c9af4 100644 --- a/src/main/java/com/esri/core/geometry/IndexHashTable.java +++ b/src/main/java/com/esri/core/geometry/IndexHashTable.java @@ -26,252 +26,252 @@ import java.util.Arrays; final class IndexHashTable { - // The hash function abstract class that user need to define to use the - // IndexHashTable. - public static abstract class HashFunction { - public abstract int getHash(int element); - - public abstract boolean equal(int element1, int element2); - - public abstract int getHash(Object elementDescriptor); - - public abstract boolean equal(Object elementDescriptor, int element); - } - - int m_random; - AttributeStreamOfInt32 m_hashBuckets; - int[] m_bit_filter; //this is aimed to speedup the find - //operation and allows to have less buckets. - IndexMultiList m_lists; - HashFunction m_hash; - - // Create hash table. size is the bin count in the table. The hashFunction - // is the function to use. - public IndexHashTable(int size, HashFunction hashFunction) { - m_hashBuckets = new AttributeStreamOfInt32(size, nullNode()); - m_lists = new IndexMultiList(); - m_hash = hashFunction; - m_bit_filter = new int[(size * 10 + 31) >> 5]; //10 times more bits than buckets - } - - public void reserveElements(int capacity) { - m_lists.reserveLists(Math.min(m_hashBuckets.size(), capacity)); - m_lists.reserveNodes(capacity); - } - - // Adds new element to the hash table. - public int addElement(int element, int hash) { - int bit_bucket = hash % (m_bit_filter.length << 5); - m_bit_filter[(bit_bucket >> 5)] |= (1 << (bit_bucket & 0x1F)); - int bucket = hash % m_hashBuckets.size(); - int list = m_hashBuckets.get(bucket); - if (list == -1) { - list = m_lists.createList(); - m_hashBuckets.set(bucket, list); - } - int node = m_lists.addElement(list, element); - return node; - } - - public int addElement(int element) { - int hash = m_hash.getHash(element); - int bit_bucket = hash % (m_bit_filter.length << 5); - m_bit_filter[(bit_bucket >> 5)] |= (1 << (bit_bucket & 0x1F)); - int bucket = hash % m_hashBuckets.size(); - int list = m_hashBuckets.get(bucket); - if (list == -1) { - list = m_lists.createList(); - m_hashBuckets.set(bucket, list); - } - int node = m_lists.addElement(list, element); - return node; - } - - public void deleteElement(int element, int hash) { - int bucket = hash % m_hashBuckets.size(); - int list = m_hashBuckets.get(bucket); - if (list == -1) - throw new IllegalArgumentException(); - - int ptr = m_lists.getFirst(list); - int prev = -1; - while (ptr != -1) { - int e = m_lists.getElement(ptr); - int nextptr = m_lists.getNext(ptr); - if (e == element) { - m_lists.deleteElement(list, prev, ptr); - if (m_lists.getFirst(list) == -1) { - m_lists.deleteList(list);// do not keep empty lists - m_hashBuckets.set(bucket, -1); - } - } else { - prev = ptr; - } - ptr = nextptr; - } - - } - - // Removes element from the hash table. - public void deleteElement(int element) { - int hash = m_hash.getHash(element); - int bucket = hash % m_hashBuckets.size(); - int list = m_hashBuckets.get(bucket); - if (list == -1) - throw new IllegalArgumentException(); - - int ptr = m_lists.getFirst(list); - int prev = -1; - while (ptr != -1) { - int e = m_lists.getElement(ptr); - int nextptr = m_lists.getNext(ptr); - if (e == element) { - m_lists.deleteElement(list, prev, ptr); - if (m_lists.getFirst(list) == -1) { - m_lists.deleteList(list);// do not keep empty lists - m_hashBuckets.set(bucket, -1); - } - } else { - prev = ptr; - } - ptr = nextptr; - } - - } - - // Returns the first node in the hash table bucket defined by the given - // hashValue. - public int getFirstInBucket(int hashValue) { - int bit_bucket = hashValue % (m_bit_filter.length << 5); - if ((m_bit_filter[(bit_bucket >> 5)] & (1 << (bit_bucket & 0x1F))) == 0) - return -1; - - int bucket = hashValue % m_hashBuckets.size(); - int list = m_hashBuckets.get(bucket); - if (list == -1) - return -1; - - return m_lists.getFirst(list); - - } - - // Returns next node in a bucket. Can be used together with GetFirstInBucket - // only. - public int getNextInBucket(int elementHandle) { - return m_lists.getNext(elementHandle); - } - - // Returns a node of the first element in the hash table, that is equal to - // the given one. - public int findNode(int element) { - int hash = m_hash.getHash(element); - int ptr = getFirstInBucket(hash); - while (ptr != -1) { - int e = m_lists.getElement(ptr); - if (m_hash.equal(e, element)) { - return ptr; - } - ptr = m_lists.getNext(ptr); - } - - return -1; - - } - - // Returns a node to the first element in the hash table, that is equal to - // the given element descriptor. - public int findNode(Object elementDescriptor) { - int hash = m_hash.getHash(elementDescriptor); - int ptr = getFirstInBucket(hash); - ; - while (ptr != -1) { - int e = m_lists.getElement(ptr); - if (m_hash.equal(elementDescriptor, e)) { - return ptr; - } - ptr = m_lists.getNext(ptr); - } - - return -1; - - } - - // Gets next equal node. - public int getNextNode(int elementHandle) { - int element = m_lists.getElement(elementHandle); - int ptr = m_lists.getNext(elementHandle); - while (ptr != -1) { - int e = m_lists.getElement(ptr); - if (m_hash.equal(e, element)) { - return ptr; - } - ptr = m_lists.getNext(ptr); - } - - return -1; - - } - - // Removes a node. - public void deleteNode(int node) { - int element = getElement(node); - int hash = m_hash.getHash(element); - int bucket = hash % m_hashBuckets.size(); - int list = m_hashBuckets.get(bucket); - if (list == -1) - throw new IllegalArgumentException(); - - int ptr = m_lists.getFirst(list); - int prev = -1; - while (ptr != -1) { - if (ptr == node) { - m_lists.deleteElement(list, prev, ptr); - if (m_lists.getFirst(list) == -1) { - m_lists.deleteList(list);// do not keep empty lists - m_hashBuckets.set(bucket, -1); - } - return; - } - prev = ptr; - ptr = m_lists.getNext(ptr); - } - - throw new IllegalArgumentException(); - - } - - // Returns a value of the element stored in the given node. - public int getElement(int elementHandle) { - return m_lists.getElement(elementHandle); - } - - // Returns any existing element from the hash table. Throws if the table is - // empty. - public int getAnyElement() { - return m_lists.getFirstElement(m_lists.getFirstList()); - } - - // Returns a node for any existing element from the hash table or NullNode - // if the table is empty. - public int getAnyNode() { - return m_lists.getFirst(m_lists.getFirstList()); - } - - public static int nullNode() { - return -1; - } - - // Removes all elements from the hash table. - public void clear() { - Arrays.fill(m_bit_filter, 0); - m_hashBuckets = new AttributeStreamOfInt32(m_hashBuckets.size(), - nullNode()); - m_lists.clear(); - - } - - // Returns the number of elements in the hash table - public int size() { - return m_lists.getNodeCount(); - } + // The hash function abstract class that user need to define to use the + // IndexHashTable. + public static abstract class HashFunction { + public abstract int getHash(int element); + + public abstract boolean equal(int element1, int element2); + + public abstract int getHash(Object elementDescriptor); + + public abstract boolean equal(Object elementDescriptor, int element); + } + + int m_random; + AttributeStreamOfInt32 m_hashBuckets; + int[] m_bit_filter; //this is aimed to speedup the find + //operation and allows to have less buckets. + IndexMultiList m_lists; + HashFunction m_hash; + + // Create hash table. size is the bin count in the table. The hashFunction + // is the function to use. + public IndexHashTable(int size, HashFunction hashFunction) { + m_hashBuckets = new AttributeStreamOfInt32(size, nullNode()); + m_lists = new IndexMultiList(); + m_hash = hashFunction; + m_bit_filter = new int[(size * 10 + 31) >> 5]; //10 times more bits than buckets + } + + public void reserveElements(int capacity) { + m_lists.reserveLists(Math.min(m_hashBuckets.size(), capacity)); + m_lists.reserveNodes(capacity); + } + + // Adds new element to the hash table. + public int addElement(int element, int hash) { + int bit_bucket = hash % (m_bit_filter.length << 5); + m_bit_filter[(bit_bucket >> 5)] |= (1 << (bit_bucket & 0x1F)); + int bucket = hash % m_hashBuckets.size(); + int list = m_hashBuckets.get(bucket); + if (list == -1) { + list = m_lists.createList(); + m_hashBuckets.set(bucket, list); + } + int node = m_lists.addElement(list, element); + return node; + } + + public int addElement(int element) { + int hash = m_hash.getHash(element); + int bit_bucket = hash % (m_bit_filter.length << 5); + m_bit_filter[(bit_bucket >> 5)] |= (1 << (bit_bucket & 0x1F)); + int bucket = hash % m_hashBuckets.size(); + int list = m_hashBuckets.get(bucket); + if (list == -1) { + list = m_lists.createList(); + m_hashBuckets.set(bucket, list); + } + int node = m_lists.addElement(list, element); + return node; + } + + public void deleteElement(int element, int hash) { + int bucket = hash % m_hashBuckets.size(); + int list = m_hashBuckets.get(bucket); + if (list == -1) + throw new IllegalArgumentException(); + + int ptr = m_lists.getFirst(list); + int prev = -1; + while (ptr != -1) { + int e = m_lists.getElement(ptr); + int nextptr = m_lists.getNext(ptr); + if (e == element) { + m_lists.deleteElement(list, prev, ptr); + if (m_lists.getFirst(list) == -1) { + m_lists.deleteList(list);// do not keep empty lists + m_hashBuckets.set(bucket, -1); + } + } else { + prev = ptr; + } + ptr = nextptr; + } + + } + + // Removes element from the hash table. + public void deleteElement(int element) { + int hash = m_hash.getHash(element); + int bucket = hash % m_hashBuckets.size(); + int list = m_hashBuckets.get(bucket); + if (list == -1) + throw new IllegalArgumentException(); + + int ptr = m_lists.getFirst(list); + int prev = -1; + while (ptr != -1) { + int e = m_lists.getElement(ptr); + int nextptr = m_lists.getNext(ptr); + if (e == element) { + m_lists.deleteElement(list, prev, ptr); + if (m_lists.getFirst(list) == -1) { + m_lists.deleteList(list);// do not keep empty lists + m_hashBuckets.set(bucket, -1); + } + } else { + prev = ptr; + } + ptr = nextptr; + } + + } + + // Returns the first node in the hash table bucket defined by the given + // hashValue. + public int getFirstInBucket(int hashValue) { + int bit_bucket = hashValue % (m_bit_filter.length << 5); + if ((m_bit_filter[(bit_bucket >> 5)] & (1 << (bit_bucket & 0x1F))) == 0) + return -1; + + int bucket = hashValue % m_hashBuckets.size(); + int list = m_hashBuckets.get(bucket); + if (list == -1) + return -1; + + return m_lists.getFirst(list); + + } + + // Returns next node in a bucket. Can be used together with GetFirstInBucket + // only. + public int getNextInBucket(int elementHandle) { + return m_lists.getNext(elementHandle); + } + + // Returns a node of the first element in the hash table, that is equal to + // the given one. + public int findNode(int element) { + int hash = m_hash.getHash(element); + int ptr = getFirstInBucket(hash); + while (ptr != -1) { + int e = m_lists.getElement(ptr); + if (m_hash.equal(e, element)) { + return ptr; + } + ptr = m_lists.getNext(ptr); + } + + return -1; + + } + + // Returns a node to the first element in the hash table, that is equal to + // the given element descriptor. + public int findNode(Object elementDescriptor) { + int hash = m_hash.getHash(elementDescriptor); + int ptr = getFirstInBucket(hash); + ; + while (ptr != -1) { + int e = m_lists.getElement(ptr); + if (m_hash.equal(elementDescriptor, e)) { + return ptr; + } + ptr = m_lists.getNext(ptr); + } + + return -1; + + } + + // Gets next equal node. + public int getNextNode(int elementHandle) { + int element = m_lists.getElement(elementHandle); + int ptr = m_lists.getNext(elementHandle); + while (ptr != -1) { + int e = m_lists.getElement(ptr); + if (m_hash.equal(e, element)) { + return ptr; + } + ptr = m_lists.getNext(ptr); + } + + return -1; + + } + + // Removes a node. + public void deleteNode(int node) { + int element = getElement(node); + int hash = m_hash.getHash(element); + int bucket = hash % m_hashBuckets.size(); + int list = m_hashBuckets.get(bucket); + if (list == -1) + throw new IllegalArgumentException(); + + int ptr = m_lists.getFirst(list); + int prev = -1; + while (ptr != -1) { + if (ptr == node) { + m_lists.deleteElement(list, prev, ptr); + if (m_lists.getFirst(list) == -1) { + m_lists.deleteList(list);// do not keep empty lists + m_hashBuckets.set(bucket, -1); + } + return; + } + prev = ptr; + ptr = m_lists.getNext(ptr); + } + + throw new IllegalArgumentException(); + + } + + // Returns a value of the element stored in the given node. + public int getElement(int elementHandle) { + return m_lists.getElement(elementHandle); + } + + // Returns any existing element from the hash table. Throws if the table is + // empty. + public int getAnyElement() { + return m_lists.getFirstElement(m_lists.getFirstList()); + } + + // Returns a node for any existing element from the hash table or NullNode + // if the table is empty. + public int getAnyNode() { + return m_lists.getFirst(m_lists.getFirstList()); + } + + public static int nullNode() { + return -1; + } + + // Removes all elements from the hash table. + public void clear() { + Arrays.fill(m_bit_filter, 0); + m_hashBuckets = new AttributeStreamOfInt32(m_hashBuckets.size(), + nullNode()); + m_lists.clear(); + + } + + // Returns the number of elements in the hash table + public int size() { + return m_lists.getNodeCount(); + } } diff --git a/src/main/java/com/esri/core/geometry/IndexMultiDCList.java b/src/main/java/com/esri/core/geometry/IndexMultiDCList.java index 4b4afeae..0e75999a 100644 --- a/src/main/java/com/esri/core/geometry/IndexMultiDCList.java +++ b/src/main/java/com/esri/core/geometry/IndexMultiDCList.java @@ -25,286 +25,286 @@ class IndexMultiDCList { - StridedIndexTypeCollection m_list_nodes; // stores lists and list elements. - // Each list element is Index, - // Prev, next. - StridedIndexTypeCollection m_lists; // stores lists. Each list is Head, - // Tail, PrevList, NextList, NodeCount, - // ListData. - int m_list_of_lists; - boolean m_b_store_list_index_with_node; - - void freeNode_(int node) { - m_list_nodes.deleteElement(node); - } - - int newNode_() { - int node = m_list_nodes.newElement(); - return node; - } - - void freeList_(int list) { - m_lists.deleteElement(list); - } - - int newList_() { - int list = m_lists.newElement(); - return list; - } - - void setPrev_(int node, int prev) { - m_list_nodes.setField(node, 1, prev); - } - - void setNext_(int node, int next) { - m_list_nodes.setField(node, 2, next); - } - - void setData_(int node, int data) { - m_list_nodes.setField(node, 0, data); - } - - void setList_(int node, int list) { - m_list_nodes.setField(node, 3, list); - } - - void setListSize_(int list, int newsize) { - m_lists.setField(list, 4, newsize); - } - - void setNextList_(int list, int next) { - m_lists.setField(list, 3, next); - } - - void setPrevList_(int list, int prev) { - m_lists.setField(list, 2, prev); - } - - // Same as Index_multi_dc_list(true). - IndexMultiDCList() { - m_list_nodes = new StridedIndexTypeCollection(3); - m_lists = new StridedIndexTypeCollection(6); - m_b_store_list_index_with_node = false; - m_list_of_lists = nullNode(); - } - - // When bStoreListIndexWithNode is true, the each node stores a pointer to - // the list. Otherwise it does not. - // The get_list() method cannot be used if bStoreListIndexWithNode is false. - IndexMultiDCList(boolean b_store_list_index_with_node) { - m_list_nodes = new StridedIndexTypeCollection(3); - m_lists = new StridedIndexTypeCollection(6); - m_b_store_list_index_with_node = false; - m_list_of_lists = nullNode(); - } - - // Creates new list and returns it's handle. - // listData is user's info associated with the list - int createList(int listData) { - int list = newList_(); - // m_lists.set_field(list, 0, null_node());//head - // m_lists.set_field(list, 1, null_node());//tail - // m_lists.set_field(list, 2, null_node());//prev list - m_lists.setField(list, 3, m_list_of_lists); // next list - m_lists.setField(list, 4, 0);// node count in the list - m_lists.setField(list, 5, listData); - if (m_list_of_lists != nullNode()) - setPrevList_(m_list_of_lists, list); - - m_list_of_lists = list; - return list; - } - - // Deletes a list and returns the index of the next list. - int deleteList(int list) { - clear(list); - int prevList = m_lists.getField(list, 2); - int nextList = m_lists.getField(list, 3); - if (prevList != nullNode()) - setNextList_(prevList, nextList); - else - m_list_of_lists = nextList; - - if (nextList != nullNode()) - setPrevList_(nextList, prevList); - - freeList_(list); - return nextList; - } - - // Reserves memory for the given number of lists. - void reserveLists(int listCount) { - m_lists.setCapacity(listCount); - } - - // returns user's data associated with the list - int getListData(int list) { - return m_lists.getField(list, 5); - } - - // returns the list associated with the node_index. Do not use if list is - // created with bStoreListIndexWithNode == false. - int getList(int node_index) { - assert (m_b_store_list_index_with_node); - return m_list_nodes.getField(node_index, 3); - } - - // sets the user data to the list - void setListData(int list, int data) { - m_lists.setField(list, 5, data); - } - - // Adds element to a given list. The element is added to the end. Returns - // the new - int addElement(int list, int data) { - return insertElement(list, -1, data); - } - - // Inserts a new node before the given one . - int insertElement(int list, int beforeNode, int data) { - int node = newNode_(); - int prev = -1; - if (beforeNode != nullNode()) { - prev = getPrev(beforeNode); - setPrev_(beforeNode, node); - } - - setNext_(node, beforeNode); - if (prev != nullNode()) - setNext_(prev, node); - - int head = m_lists.getField(list, 0); - - if (beforeNode == head) - m_lists.setField(list, 0, node); - if (beforeNode == nullNode()) { - int tail = m_lists.getField(list, 1); - setPrev_(node, tail); - if (tail != -1) - setNext_(tail, node); - - m_lists.setField(list, 1, node); - } - - setData(node, data); - setListSize_(list, getListSize(list) + 1); - - if (m_b_store_list_index_with_node) - setList_(node, list); - - return node; - } - - // Deletes a node from a list. Returns the next node after the deleted one. - int deleteElement(int list, int node) { - int prev = getPrev(node); - int next = getNext(node); - if (prev != nullNode()) - setNext_(prev, next); - else - m_lists.setField(list, 0, next);// change head - if (next != nullNode()) - setPrev_(next, prev); - else - m_lists.setField(list, 1, prev);// change tail - - freeNode_(node); - setListSize_(list, getListSize(list) - 1); - return next; - } - - // Reserves memory for the given number of nodes. - void reserveNodes(int nodeCount) { - m_list_nodes.setCapacity(nodeCount); - } - - // Returns the data from the given list node. - int getData(int node_index) { - return m_list_nodes.getField(node_index, 0); - } - - // Sets the data to the given list node. - void setData(int node_index, int element) { - m_list_nodes.setField(node_index, 0, element); - } - - // Returns index of next node for the give node. - int getNext(int node_index) { - return m_list_nodes.getField(node_index, 2); - } - - // Returns index of previous node for the give node. - int getPrev(int node_index) { - return m_list_nodes.getField(node_index, 1); - } - - // Returns the first node in the list - int getFirst(int list) { - return m_lists.getField(list, 0); - } - - // Returns the last node in the list - int getLast(int list) { - return m_lists.getField(list, 1); - } - - // Check if the node is Null (does not exist) - static int nullNode() { - return -1; - } - - // Clears all nodes and removes all lists. - void clear() { - for (int list = getFirstList(); list != -1; ) { - list = deleteList(list); - } - } - - // Clears all nodes from the list. - void clear(int list) { - int last = getLast(list); - while (last != nullNode()) { - int n = last; - last = getPrev(n); - freeNode_(n); - } - m_lists.setField(list, 0, -1); - m_lists.setField(list, 1, -1); - setListSize_(list, 0); - } - - // Returns True if the given list is empty. - boolean isEmpty(int list) { - return m_lists.getField(list, 0) == -1; - } - - // Returns True if the multilist is empty - boolean isEmpty() { - return m_list_nodes.size() == 0; - } - - // Returns node count in all lists - int getNodeCount() { - return m_list_nodes.size(); - } - - // returns the number of lists - int getListCount() { - return m_lists.size(); - } - - // Returns the node count in the given list - int getListSize(int list) { - return m_lists.getField(list, 4); - } - - // returns the first list - int getFirstList() { - return m_list_of_lists; - } - - // returns the next list - int getNextList(int list) { - return m_lists.getField(list, 3); - } + StridedIndexTypeCollection m_list_nodes; // stores lists and list elements. + // Each list element is Index, + // Prev, next. + StridedIndexTypeCollection m_lists; // stores lists. Each list is Head, + // Tail, PrevList, NextList, NodeCount, + // ListData. + int m_list_of_lists; + boolean m_b_store_list_index_with_node; + + void freeNode_(int node) { + m_list_nodes.deleteElement(node); + } + + int newNode_() { + int node = m_list_nodes.newElement(); + return node; + } + + void freeList_(int list) { + m_lists.deleteElement(list); + } + + int newList_() { + int list = m_lists.newElement(); + return list; + } + + void setPrev_(int node, int prev) { + m_list_nodes.setField(node, 1, prev); + } + + void setNext_(int node, int next) { + m_list_nodes.setField(node, 2, next); + } + + void setData_(int node, int data) { + m_list_nodes.setField(node, 0, data); + } + + void setList_(int node, int list) { + m_list_nodes.setField(node, 3, list); + } + + void setListSize_(int list, int newsize) { + m_lists.setField(list, 4, newsize); + } + + void setNextList_(int list, int next) { + m_lists.setField(list, 3, next); + } + + void setPrevList_(int list, int prev) { + m_lists.setField(list, 2, prev); + } + + // Same as Index_multi_dc_list(true). + IndexMultiDCList() { + m_list_nodes = new StridedIndexTypeCollection(3); + m_lists = new StridedIndexTypeCollection(6); + m_b_store_list_index_with_node = false; + m_list_of_lists = nullNode(); + } + + // When bStoreListIndexWithNode is true, the each node stores a pointer to + // the list. Otherwise it does not. + // The get_list() method cannot be used if bStoreListIndexWithNode is false. + IndexMultiDCList(boolean b_store_list_index_with_node) { + m_list_nodes = new StridedIndexTypeCollection(3); + m_lists = new StridedIndexTypeCollection(6); + m_b_store_list_index_with_node = false; + m_list_of_lists = nullNode(); + } + + // Creates new list and returns it's handle. + // listData is user's info associated with the list + int createList(int listData) { + int list = newList_(); + // m_lists.set_field(list, 0, null_node());//head + // m_lists.set_field(list, 1, null_node());//tail + // m_lists.set_field(list, 2, null_node());//prev list + m_lists.setField(list, 3, m_list_of_lists); // next list + m_lists.setField(list, 4, 0);// node count in the list + m_lists.setField(list, 5, listData); + if (m_list_of_lists != nullNode()) + setPrevList_(m_list_of_lists, list); + + m_list_of_lists = list; + return list; + } + + // Deletes a list and returns the index of the next list. + int deleteList(int list) { + clear(list); + int prevList = m_lists.getField(list, 2); + int nextList = m_lists.getField(list, 3); + if (prevList != nullNode()) + setNextList_(prevList, nextList); + else + m_list_of_lists = nextList; + + if (nextList != nullNode()) + setPrevList_(nextList, prevList); + + freeList_(list); + return nextList; + } + + // Reserves memory for the given number of lists. + void reserveLists(int listCount) { + m_lists.setCapacity(listCount); + } + + // returns user's data associated with the list + int getListData(int list) { + return m_lists.getField(list, 5); + } + + // returns the list associated with the node_index. Do not use if list is + // created with bStoreListIndexWithNode == false. + int getList(int node_index) { + assert (m_b_store_list_index_with_node); + return m_list_nodes.getField(node_index, 3); + } + + // sets the user data to the list + void setListData(int list, int data) { + m_lists.setField(list, 5, data); + } + + // Adds element to a given list. The element is added to the end. Returns + // the new + int addElement(int list, int data) { + return insertElement(list, -1, data); + } + + // Inserts a new node before the given one . + int insertElement(int list, int beforeNode, int data) { + int node = newNode_(); + int prev = -1; + if (beforeNode != nullNode()) { + prev = getPrev(beforeNode); + setPrev_(beforeNode, node); + } + + setNext_(node, beforeNode); + if (prev != nullNode()) + setNext_(prev, node); + + int head = m_lists.getField(list, 0); + + if (beforeNode == head) + m_lists.setField(list, 0, node); + if (beforeNode == nullNode()) { + int tail = m_lists.getField(list, 1); + setPrev_(node, tail); + if (tail != -1) + setNext_(tail, node); + + m_lists.setField(list, 1, node); + } + + setData(node, data); + setListSize_(list, getListSize(list) + 1); + + if (m_b_store_list_index_with_node) + setList_(node, list); + + return node; + } + + // Deletes a node from a list. Returns the next node after the deleted one. + int deleteElement(int list, int node) { + int prev = getPrev(node); + int next = getNext(node); + if (prev != nullNode()) + setNext_(prev, next); + else + m_lists.setField(list, 0, next);// change head + if (next != nullNode()) + setPrev_(next, prev); + else + m_lists.setField(list, 1, prev);// change tail + + freeNode_(node); + setListSize_(list, getListSize(list) - 1); + return next; + } + + // Reserves memory for the given number of nodes. + void reserveNodes(int nodeCount) { + m_list_nodes.setCapacity(nodeCount); + } + + // Returns the data from the given list node. + int getData(int node_index) { + return m_list_nodes.getField(node_index, 0); + } + + // Sets the data to the given list node. + void setData(int node_index, int element) { + m_list_nodes.setField(node_index, 0, element); + } + + // Returns index of next node for the give node. + int getNext(int node_index) { + return m_list_nodes.getField(node_index, 2); + } + + // Returns index of previous node for the give node. + int getPrev(int node_index) { + return m_list_nodes.getField(node_index, 1); + } + + // Returns the first node in the list + int getFirst(int list) { + return m_lists.getField(list, 0); + } + + // Returns the last node in the list + int getLast(int list) { + return m_lists.getField(list, 1); + } + + // Check if the node is Null (does not exist) + static int nullNode() { + return -1; + } + + // Clears all nodes and removes all lists. + void clear() { + for (int list = getFirstList(); list != -1; ) { + list = deleteList(list); + } + } + + // Clears all nodes from the list. + void clear(int list) { + int last = getLast(list); + while (last != nullNode()) { + int n = last; + last = getPrev(n); + freeNode_(n); + } + m_lists.setField(list, 0, -1); + m_lists.setField(list, 1, -1); + setListSize_(list, 0); + } + + // Returns True if the given list is empty. + boolean isEmpty(int list) { + return m_lists.getField(list, 0) == -1; + } + + // Returns True if the multilist is empty + boolean isEmpty() { + return m_list_nodes.size() == 0; + } + + // Returns node count in all lists + int getNodeCount() { + return m_list_nodes.size(); + } + + // returns the number of lists + int getListCount() { + return m_lists.size(); + } + + // Returns the node count in the given list + int getListSize(int list) { + return m_lists.getField(list, 4); + } + + // returns the first list + int getFirstList() { + return m_list_of_lists; + } + + // returns the next list + int getNextList(int list) { + return m_lists.getField(list, 3); + } } diff --git a/src/main/java/com/esri/core/geometry/IndexMultiList.java b/src/main/java/com/esri/core/geometry/IndexMultiList.java index 88c19f1c..5a881481 100644 --- a/src/main/java/com/esri/core/geometry/IndexMultiList.java +++ b/src/main/java/com/esri/core/geometry/IndexMultiList.java @@ -25,242 +25,242 @@ class IndexMultiList { - StridedIndexTypeCollection m_listNodes; // stores lists and list elements. - // Each list element is Index, next. - StridedIndexTypeCollection m_lists; // stores lists. Each list is Head, - // Tail, [PrevList, NextList]. - int m_list_of_lists; - boolean m_b_allow_navigation_between_lists;// when False, get_first_list, - // get_next_list return -1. - - void freeNode_(int node) { - m_listNodes.deleteElement(node); - } - - int newNode_() { - int node = m_listNodes.newElement(); - return node; - } - - void freeList_(int list) { - m_lists.deleteElement(list); - } - - int newList_() { - int list = m_lists.newElement(); - return list; - } - - // Same as Index_multi_list(true); - IndexMultiList() { - m_listNodes = new StridedIndexTypeCollection(2); - m_lists = new StridedIndexTypeCollection(4); - m_list_of_lists = nullNode(); - m_b_allow_navigation_between_lists = true; - } - - // When b_allow_navigation_between_lists is False, the get_first_list and - // get_next_list do not work. - // There will be two Index_type elements per list and two Index_type - // elements per list element - // When b_allow_navigation_between_lists is True, the get_first_list and - // get_next_list will work. - // There will be four Index_type elements per list and two Index_type - // elements per list element - IndexMultiList(boolean b_allow_navigation_between_lists) { - m_listNodes = new StridedIndexTypeCollection(2); - m_lists = new StridedIndexTypeCollection( - b_allow_navigation_between_lists ? 4 : 2); - m_list_of_lists = nullNode(); - m_b_allow_navigation_between_lists = b_allow_navigation_between_lists; - } - - // Creates new list and returns it's handle. - int createList() { - int node = newList_(); - if (m_b_allow_navigation_between_lists) { - m_lists.setField(node, 3, m_list_of_lists); - if (m_list_of_lists != nullNode()) - m_lists.setField(m_list_of_lists, 2, node); - m_list_of_lists = node; - } - - return node; - } - - // Deletes a list. - void deleteList(int list) { - int ptr = getFirst(list); - while (ptr != nullNode()) { - int p = ptr; - ptr = getNext(ptr); - freeNode_(p); - } - - if (m_b_allow_navigation_between_lists) { - int prevList = m_lists.getField(list, 2); - int nextList = m_lists.getField(list, 3); - if (prevList != nullNode()) - m_lists.setField(prevList, 3, nextList); - else - m_list_of_lists = nextList; - - if (nextList != nullNode()) - m_lists.setField(nextList, 2, prevList); - } - - freeList_(list); - } - - // Reserves memory for the given number of lists. - void reserveLists(int listCount) { - m_lists.setCapacity(listCount); - } - - // Adds element to a given list. The element is added to the end. Returns - // the new - int addElement(int list, int element) { - int head = m_lists.getField(list, 0); - int tail = m_lists.getField(list, 1); - int node = newNode_(); - if (tail != nullNode()) { - assert (head != nullNode()); - m_listNodes.setField(tail, 1, node); - m_lists.setField(list, 1, node); - } else {// empty list - assert (head == nullNode()); - m_lists.setField(list, 0, node); - m_lists.setField(list, 1, node); - } - - m_listNodes.setField(node, 0, element); - return node; - } - - // Reserves memory for the given number of nodes. - void reserveNodes(int nodeCount) { - m_listNodes.setCapacity(nodeCount); - } - - // Deletes a node from a list, given the previous node (previous node is - // required, because the list is singly connected). - void deleteElement(int list, int prevNode, int node) { - if (prevNode != nullNode()) { - assert (m_listNodes.getField(prevNode, 1) == node); - m_listNodes.setField(prevNode, 1, m_listNodes.getField(node, 1)); - if (m_lists.getField(list, 1) == node)// deleting a tail - { - m_lists.setField(list, 1, prevNode); - } - } else { - assert (m_lists.getField(list, 0) == node); - m_lists.setField(list, 0, m_listNodes.getField(node, 1)); - if (m_lists.getField(list, 1) == node) {// removing last element - assert (m_listNodes.getField(node, 1) == nullNode()); - m_lists.setField(list, 1, nullNode()); - } - } - freeNode_(node); - } - - // Concatenates list1 and list2. The nodes of list2 are added to the end of - // list1. The list2 index becomes invalid. - // Returns list1. - int concatenateLists(int list1, int list2) { - int tailNode1 = m_lists.getField(list1, 1); - int headNode2 = m_lists.getField(list2, 0); - if (headNode2 != nullNode())// do not concatenate empty lists - { - if (tailNode1 != nullNode()) { - // connect head of list2 to the tail of list1. - m_listNodes.setField(tailNode1, 1, headNode2); - // set the tail of the list1 to be the tail of list2. - m_lists.setField(list1, 1, m_lists.getField(list2, 1)); - } else {// list1 is empty, while list2 is not. - m_lists.setField(list1, 0, headNode2); - m_lists.setField(list1, 1, m_lists.getField(list2, 1)); - } - } - - if (m_b_allow_navigation_between_lists) { - int prevList = m_lists.getField(list2, 2); - int nextList = m_lists.getField(list2, 3); - if (prevList != nullNode()) - m_lists.setField(prevList, 3, nextList); - else - m_list_of_lists = nextList; - - if (nextList != nullNode()) - m_lists.setField(nextList, 2, prevList); - } - - freeList_(list2); - return list1; - } - - // Returns the data from the given list node. - int getElement(int node_index) { - return m_listNodes.getField(node_index, 0); - } - - // Sets the data to the given list node. - void setElement(int node_index, int element) { - m_listNodes.setField(node_index, 0, element); - } - - // Returns index of next node for the give node. - int getNext(int node_index) { - return m_listNodes.getField(node_index, 1); - } - - // Returns the first node in the least - int getFirst(int list) { - return m_lists.getField(list, 0); - } - - // Returns the element from the first node in the least. Equivalent to - // get_element(get_first(list)); - int getFirstElement(int list) { - int f = getFirst(list); - return getElement(f); - } - - // Check if the node is Null (does not exist) - static int nullNode() { - return -1; - } - - // Clears all nodes and removes all lists. Frees the memory. - void clear() { - m_listNodes.deleteAll(true); - m_lists.deleteAll(true); - m_list_of_lists = nullNode(); - } - - // Returns True if the given list is empty. - boolean isEmpty(int list) { - return m_lists.getField(list, 0) == nullNode(); - } - - boolean isEmpty() { - return m_listNodes.size() == 0; - } - - int getNodeCount() { - return m_listNodes.size(); - } - - int getListCount() { - return m_lists.size(); - } - - int getFirstList() { - assert (m_b_allow_navigation_between_lists); - return m_list_of_lists; - } - - int getNextList(int list) { - assert (m_b_allow_navigation_between_lists); - return m_lists.getField(list, 3); - } + StridedIndexTypeCollection m_listNodes; // stores lists and list elements. + // Each list element is Index, next. + StridedIndexTypeCollection m_lists; // stores lists. Each list is Head, + // Tail, [PrevList, NextList]. + int m_list_of_lists; + boolean m_b_allow_navigation_between_lists;// when False, get_first_list, + // get_next_list return -1. + + void freeNode_(int node) { + m_listNodes.deleteElement(node); + } + + int newNode_() { + int node = m_listNodes.newElement(); + return node; + } + + void freeList_(int list) { + m_lists.deleteElement(list); + } + + int newList_() { + int list = m_lists.newElement(); + return list; + } + + // Same as Index_multi_list(true); + IndexMultiList() { + m_listNodes = new StridedIndexTypeCollection(2); + m_lists = new StridedIndexTypeCollection(4); + m_list_of_lists = nullNode(); + m_b_allow_navigation_between_lists = true; + } + + // When b_allow_navigation_between_lists is False, the get_first_list and + // get_next_list do not work. + // There will be two Index_type elements per list and two Index_type + // elements per list element + // When b_allow_navigation_between_lists is True, the get_first_list and + // get_next_list will work. + // There will be four Index_type elements per list and two Index_type + // elements per list element + IndexMultiList(boolean b_allow_navigation_between_lists) { + m_listNodes = new StridedIndexTypeCollection(2); + m_lists = new StridedIndexTypeCollection( + b_allow_navigation_between_lists ? 4 : 2); + m_list_of_lists = nullNode(); + m_b_allow_navigation_between_lists = b_allow_navigation_between_lists; + } + + // Creates new list and returns it's handle. + int createList() { + int node = newList_(); + if (m_b_allow_navigation_between_lists) { + m_lists.setField(node, 3, m_list_of_lists); + if (m_list_of_lists != nullNode()) + m_lists.setField(m_list_of_lists, 2, node); + m_list_of_lists = node; + } + + return node; + } + + // Deletes a list. + void deleteList(int list) { + int ptr = getFirst(list); + while (ptr != nullNode()) { + int p = ptr; + ptr = getNext(ptr); + freeNode_(p); + } + + if (m_b_allow_navigation_between_lists) { + int prevList = m_lists.getField(list, 2); + int nextList = m_lists.getField(list, 3); + if (prevList != nullNode()) + m_lists.setField(prevList, 3, nextList); + else + m_list_of_lists = nextList; + + if (nextList != nullNode()) + m_lists.setField(nextList, 2, prevList); + } + + freeList_(list); + } + + // Reserves memory for the given number of lists. + void reserveLists(int listCount) { + m_lists.setCapacity(listCount); + } + + // Adds element to a given list. The element is added to the end. Returns + // the new + int addElement(int list, int element) { + int head = m_lists.getField(list, 0); + int tail = m_lists.getField(list, 1); + int node = newNode_(); + if (tail != nullNode()) { + assert (head != nullNode()); + m_listNodes.setField(tail, 1, node); + m_lists.setField(list, 1, node); + } else {// empty list + assert (head == nullNode()); + m_lists.setField(list, 0, node); + m_lists.setField(list, 1, node); + } + + m_listNodes.setField(node, 0, element); + return node; + } + + // Reserves memory for the given number of nodes. + void reserveNodes(int nodeCount) { + m_listNodes.setCapacity(nodeCount); + } + + // Deletes a node from a list, given the previous node (previous node is + // required, because the list is singly connected). + void deleteElement(int list, int prevNode, int node) { + if (prevNode != nullNode()) { + assert (m_listNodes.getField(prevNode, 1) == node); + m_listNodes.setField(prevNode, 1, m_listNodes.getField(node, 1)); + if (m_lists.getField(list, 1) == node)// deleting a tail + { + m_lists.setField(list, 1, prevNode); + } + } else { + assert (m_lists.getField(list, 0) == node); + m_lists.setField(list, 0, m_listNodes.getField(node, 1)); + if (m_lists.getField(list, 1) == node) {// removing last element + assert (m_listNodes.getField(node, 1) == nullNode()); + m_lists.setField(list, 1, nullNode()); + } + } + freeNode_(node); + } + + // Concatenates list1 and list2. The nodes of list2 are added to the end of + // list1. The list2 index becomes invalid. + // Returns list1. + int concatenateLists(int list1, int list2) { + int tailNode1 = m_lists.getField(list1, 1); + int headNode2 = m_lists.getField(list2, 0); + if (headNode2 != nullNode())// do not concatenate empty lists + { + if (tailNode1 != nullNode()) { + // connect head of list2 to the tail of list1. + m_listNodes.setField(tailNode1, 1, headNode2); + // set the tail of the list1 to be the tail of list2. + m_lists.setField(list1, 1, m_lists.getField(list2, 1)); + } else {// list1 is empty, while list2 is not. + m_lists.setField(list1, 0, headNode2); + m_lists.setField(list1, 1, m_lists.getField(list2, 1)); + } + } + + if (m_b_allow_navigation_between_lists) { + int prevList = m_lists.getField(list2, 2); + int nextList = m_lists.getField(list2, 3); + if (prevList != nullNode()) + m_lists.setField(prevList, 3, nextList); + else + m_list_of_lists = nextList; + + if (nextList != nullNode()) + m_lists.setField(nextList, 2, prevList); + } + + freeList_(list2); + return list1; + } + + // Returns the data from the given list node. + int getElement(int node_index) { + return m_listNodes.getField(node_index, 0); + } + + // Sets the data to the given list node. + void setElement(int node_index, int element) { + m_listNodes.setField(node_index, 0, element); + } + + // Returns index of next node for the give node. + int getNext(int node_index) { + return m_listNodes.getField(node_index, 1); + } + + // Returns the first node in the least + int getFirst(int list) { + return m_lists.getField(list, 0); + } + + // Returns the element from the first node in the least. Equivalent to + // get_element(get_first(list)); + int getFirstElement(int list) { + int f = getFirst(list); + return getElement(f); + } + + // Check if the node is Null (does not exist) + static int nullNode() { + return -1; + } + + // Clears all nodes and removes all lists. Frees the memory. + void clear() { + m_listNodes.deleteAll(true); + m_lists.deleteAll(true); + m_list_of_lists = nullNode(); + } + + // Returns True if the given list is empty. + boolean isEmpty(int list) { + return m_lists.getField(list, 0) == nullNode(); + } + + boolean isEmpty() { + return m_listNodes.size() == 0; + } + + int getNodeCount() { + return m_listNodes.size(); + } + + int getListCount() { + return m_lists.size(); + } + + int getFirstList() { + assert (m_b_allow_navigation_between_lists); + return m_list_of_lists; + } + + int getNextList(int list) { + assert (m_b_allow_navigation_between_lists); + return m_lists.getField(list, 3); + } } diff --git a/src/main/java/com/esri/core/geometry/InternalUtils.java b/src/main/java/com/esri/core/geometry/InternalUtils.java index f7219126..1ce3082f 100644 --- a/src/main/java/com/esri/core/geometry/InternalUtils.java +++ b/src/main/java/com/esri/core/geometry/InternalUtils.java @@ -28,538 +28,538 @@ final class InternalUtils { - // p0 and p1 have to be on left/right boundary of fullRange2D (since this - // fuction can be called recursively, p0 or p1 can also be fullRange2D - // corners) - static int addPointsToArray(Point2D p0In, Point2D p1In, - Point2D[] pointsArray, int idx, Envelope2D fullRange2D, - boolean clockwise, double densifyDist)// PointerOfArrayOf(Point2D) - // pointsArray, int idx, - // Envelope2D fullRange2D, - // boolean clockwise, double - // densifyDist) - { - Point2D p0 = new Point2D(); - p0.setCoords(p0In); - Point2D p1 = new Point2D(); - p1.setCoords(p1In); - fullRange2D._snapToBoundary(p0); - fullRange2D._snapToBoundary(p1); - // //_ASSERT((p0.x == fullRange2D.xmin || p0.x == fullRange2D.xmax) && - // (p1.x == fullRange2D.xmin || p1.x == fullRange2D.xmax)); - double boundDist0 = fullRange2D._boundaryDistance(p0); - double boundDist1 = fullRange2D._boundaryDistance(p1); - if (boundDist1 == 0.0) - boundDist1 = fullRange2D.getLength(); - - if ((p0.x == p1.x || p0.y == p1.y - && (p0.y == fullRange2D.ymin || p0.y == fullRange2D.ymax)) - && (boundDist1 > boundDist0) == clockwise) { - Point2D delta = new Point2D(); - delta.setCoords(p1.x - p0.x, p1.y - p0.y); - if (densifyDist != 0)// if (densifyDist) - { - long cPoints = (long) (delta._norm(0) / densifyDist); - if (cPoints > 0) // if (cPoints) - { - delta.scale(1.0 / (cPoints + 1)); - for (long i = 0; i < cPoints; i++) { - p0.add(delta); - pointsArray[idx++].setCoords(p0.x, p0.y);// ARRAYELEMENT(pointsArray, - // idx++).setCoords(p0.x, - // p0.y); - } - } - } - } else { - int side0 = fullRange2D._envelopeSide(p0); - int side1 = fullRange2D._envelopeSide(p1); - // create up to four corner points; the order depends on boolean - // clockwise - Point2D corner; - int deltaSide = clockwise ? 1 : 3; // 3 is equivalent to -1 - do { - side0 = (side0 + deltaSide) & 3; - corner = fullRange2D.queryCorner(side0); - if (densifyDist != 0)// if (densifyDist) - { - idx = addPointsToArray(p0, corner, pointsArray, idx, - fullRange2D, clockwise, densifyDist); - } - pointsArray[idx++].setCoords(corner.x, corner.y);// ARRAYELEMENT(pointsArray, - // idx++).setCoords(corner.x, - // corner.y); - p0 = corner; - } while ((side0 & 3) != side1); - - if (densifyDist != 0)// if (densifyDist) - idx = addPointsToArray(p0, p1, pointsArray, idx, fullRange2D, - clockwise, densifyDist); - } - - return idx; - } - - void shiftPath(MultiPath inputGeom, int iPath, double shift) { - MultiVertexGeometryImpl vertexGeometryImpl = (MultiVertexGeometryImpl) inputGeom - ._getImpl(); - AttributeStreamOfDbl xyStream = (AttributeStreamOfDbl) vertexGeometryImpl - .getAttributeStreamRef(VertexDescription.Semantics.POSITION); - - int i1 = inputGeom.getPathStart(iPath); - int i2 = inputGeom.getPathEnd(iPath); - Point2D pt = new Point2D(); - - while (i1 < i2) { - xyStream.read(i1, pt); - pt.x += shift; - xyStream.write(i1, pt); - i1++; - } - } - - static double calculateToleranceFromGeometry(SpatialReference sr, - Envelope2D env2D, boolean bConservative) { - double gtolerance = env2D._calculateToleranceFromEnvelope(); - double stolerance = sr != null ? sr - .getTolerance(VertexDescription.Semantics.POSITION) : 0; - if (bConservative) { - gtolerance *= 4; - stolerance *= 1.1; - } - return Math.max(stolerance, gtolerance); - } - - static double adjust_tolerance_for_TE_clustering(double tol) { - return 2.0 * Math.sqrt(2.0) * tol; - } - - static double adjust_tolerance_for_TE_cracking(double tol) { - return Math.sqrt(2.0) * tol; - } - - static double calculateToleranceFromGeometry(SpatialReference sr, - Geometry geometry, boolean bConservative) { - Envelope2D env2D = new Envelope2D(); - geometry.queryEnvelope2D(env2D); - return calculateToleranceFromGeometry(sr, env2D, bConservative); - } - - static double calculateZToleranceFromGeometry(SpatialReference sr, - Geometry geometry, boolean bConservative) { - Envelope1D env1D = geometry.queryInterval( - VertexDescription.Semantics.Z, 0); - double gtolerance = env1D._calculateToleranceFromEnvelope(); - double stolerance = sr != null ? sr - .getTolerance(VertexDescription.Semantics.Z) : 0; - if (bConservative) { - gtolerance *= 4; - stolerance *= 1.1; - } - return Math.max(stolerance, gtolerance); - } - - double calculateZToleranceFromGeometry(SpatialReference sr, - Geometry geometry) { - Envelope1D env1D = geometry.queryInterval( - VertexDescription.Semantics.Z, 0); - double tolerance = env1D._calculateToleranceFromEnvelope(); - return Math - .max(sr != null ? sr - .getTolerance(VertexDescription.Semantics.Z) : 0, - tolerance); - } - - public static Envelope2D getMergedExtent(Geometry geom1, Envelope2D env2) { - Envelope2D env1 = new Envelope2D(); - geom1.queryLooseEnvelope2D(env1); - env1.merge(env2); - return env1; - } - - public static Envelope2D getMergedExtent(Geometry geom1, Geometry geom2) { - Envelope2D env1 = new Envelope2D(); - geom1.queryLooseEnvelope2D(env1); - Envelope2D env2 = new Envelope2D(); - geom2.queryLooseEnvelope2D(env2); - env1.merge(env2); - return env1; - } - - public static Geometry createGeometry(int gt, VertexDescription vdIn) { - VertexDescription vd = vdIn; - if (vd == null) - vd = VertexDescriptionDesignerImpl.getDefaultDescriptor2D(); - switch (gt) { - case Geometry.GeometryType.Point: - return new Point(vd); - case Geometry.GeometryType.Line: - return new Line(vd); - // case enum_value2(Geometry, GeometryType, enumBezier): - // break; - // case enum_value2(Geometry, GeometryType, enumEllipticArc): - // break; - case Geometry.GeometryType.Envelope: - return new Envelope(vd); - case Geometry.GeometryType.MultiPoint: - return new MultiPoint(vd); - case Geometry.GeometryType.Polyline: - return new Polyline(vd); - case Geometry.GeometryType.Polygon: - return new Polygon(vd); - default: - throw new GeometryException("invalid argument."); - } - } - - static boolean isClockwiseRing(MultiPathImpl polygon, int iring) { - int high_point_index = polygon.getHighestPointIndex(iring); - int path_start = polygon.getPathStart(iring); - int path_end = polygon.getPathEnd(iring); - - Point2D q = polygon.getXY(high_point_index); - Point2D p, r; - - if (high_point_index == path_start) { - p = polygon.getXY(path_end - 1); - r = polygon.getXY(path_start + 1); - } else if (high_point_index == path_end - 1) { - p = polygon.getXY(high_point_index - 1); - r = polygon.getXY(path_start); - } else { - p = polygon.getXY(high_point_index - 1); - r = polygon.getXY(high_point_index + 1); - } - - int orientation = Point2D.orientationRobust(p, q, r); - - if (orientation == 0) - return polygon.calculateRingArea2D(iring) > 0.0; - - return orientation == -1; - } - - static QuadTreeImpl buildQuadTree(MultiPathImpl multipathImpl) { - Envelope2D extent = new Envelope2D(); - multipathImpl.queryLooseEnvelope2D(extent); - QuadTreeImpl quad_tree_impl = new QuadTreeImpl(extent, 8); - int hint_index = -1; - SegmentIteratorImpl seg_iter = multipathImpl.querySegmentIterator(); - Envelope2D boundingbox = new Envelope2D(); - boolean resized_extent = false; - - while (seg_iter.nextPath()) { - while (seg_iter.hasNextSegment()) { - Segment segment = seg_iter.nextSegment(); - int index = seg_iter.getStartPointIndex(); - segment.queryEnvelope2D(boundingbox); - hint_index = quad_tree_impl.insert(index, boundingbox, - hint_index); - - if (hint_index == -1) { - if (resized_extent) - throw GeometryException.GeometryInternalError(); - - // resize extent - multipathImpl.calculateEnvelope2D(extent, false); - resized_extent = true; - quad_tree_impl.reset(extent, 8); - seg_iter.resetToFirstPath(); - break; - } - } - } - - return quad_tree_impl; - } - - static QuadTreeImpl buildQuadTree(MultiPathImpl multipathImpl, - Envelope2D extentOfInterest) { - Envelope2D extent = new Envelope2D(); - multipathImpl.queryLooseEnvelope2D(extent); - QuadTreeImpl quad_tree_impl = new QuadTreeImpl(extent, 8); - int hint_index = -1; - Envelope2D boundingbox = new Envelope2D(); - SegmentIteratorImpl seg_iter = multipathImpl.querySegmentIterator(); - - boolean resized_extent = false; - while (seg_iter.nextPath()) { - while (seg_iter.hasNextSegment()) { - Segment segment = seg_iter.nextSegment(); - int index = seg_iter.getStartPointIndex(); - segment.queryEnvelope2D(boundingbox); - - if (boundingbox.isIntersecting(extentOfInterest)) { - hint_index = quad_tree_impl.insert(index, boundingbox, - hint_index); - - if (hint_index == -1) { - if (resized_extent) - throw GeometryException.GeometryInternalError(); - - // resize extent - multipathImpl.calculateEnvelope2D(extent, false); - resized_extent = true; - quad_tree_impl.reset(extent, 8); - seg_iter.resetToFirstPath(); - break; - } - } - } - } - - return quad_tree_impl; - } - - static QuadTreeImpl buildQuadTreeForPaths(MultiPathImpl multipathImpl) { - Envelope2D extent = new Envelope2D(); - multipathImpl.queryLooseEnvelope2D(extent); - if (extent.isEmpty()) - return null; - - QuadTreeImpl quad_tree_impl = new QuadTreeImpl(extent, 8); - int hint_index = -1; - Envelope2D boundingbox = new Envelope2D(); - - boolean resized_extent = false; - do { - for (int ipath = 0, npaths = multipathImpl.getPathCount(); ipath < npaths; ipath++) { - multipathImpl.queryPathEnvelope2D(ipath, boundingbox); - hint_index = quad_tree_impl.insert(ipath, boundingbox, hint_index); - - if (hint_index == -1) { - if (resized_extent) - throw GeometryException.GeometryInternalError(); - - //This is usually happens because esri shape buffer contains geometry extent which is slightly different from the true extent. - //Recalculate extent - multipathImpl.calculateEnvelope2D(extent, false); - resized_extent = true; - quad_tree_impl.reset(extent, 8); - break; //break the for loop - } else { - resized_extent = false; - } - } - - } while (resized_extent); - - return quad_tree_impl; - } - - static QuadTreeImpl buildQuadTree(MultiPointImpl multipointImpl) { - Envelope2D extent = new Envelope2D(); - multipointImpl.queryLooseEnvelope2D(extent); - QuadTreeImpl quad_tree_impl = new QuadTreeImpl(extent, 8); - - Point2D pt = new Point2D(); - Envelope2D boundingbox = new Envelope2D(); - boolean resized_extent = false; - for (int i = 0; i < multipointImpl.getPointCount(); i++) { - multipointImpl.getXY(i, pt); - boundingbox.setCoords(pt); - int element_handle = quad_tree_impl.insert(i, boundingbox); - - if (element_handle == -1) { - if (resized_extent) - throw GeometryException.GeometryInternalError(); - - // resize extent - multipointImpl.calculateEnvelope2D(extent, false); - resized_extent = true; - quad_tree_impl.reset(extent, 8); - i = -1; // resets the for-loop - continue; - } - } - - return quad_tree_impl; - } - - static QuadTreeImpl buildQuadTree(MultiPointImpl multipointImpl, - Envelope2D extentOfInterest) { - QuadTreeImpl quad_tree_impl = new QuadTreeImpl(extentOfInterest, 8); - Point2D pt = new Point2D(); - boolean resized_extent = false; - Envelope2D boundingbox = new Envelope2D(); - for (int i = 0; i < multipointImpl.getPointCount(); i++) { - multipointImpl.getXY(i, pt); - - if (!extentOfInterest.contains(pt)) - continue; - - boundingbox.setCoords(pt); - int element_handle = quad_tree_impl.insert(i, boundingbox); - - if (element_handle == -1) { - if (resized_extent) - throw GeometryException.GeometryInternalError(); - - // resize extent - resized_extent = true; - Envelope2D extent = new Envelope2D(); - multipointImpl.calculateEnvelope2D(extent, false); - quad_tree_impl.reset(extent, 8); - i = -1; // resets the for-loop - continue; - } - } - - return quad_tree_impl; - } - - static Envelope2DIntersectorImpl getEnvelope2DIntersector( - MultiPathImpl multipathImplA, MultiPathImpl multipathImplB, - double tolerance) { - Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(); - multipathImplA.queryLooseEnvelope2D(env_a); - multipathImplB.queryLooseEnvelope2D(env_b); - env_a.inflate(tolerance, tolerance); - env_b.inflate(tolerance, tolerance); - - Envelope2D envInter = new Envelope2D(); - envInter.setCoords(env_a); - envInter.intersect(env_b); - - SegmentIteratorImpl segIterA = multipathImplA.querySegmentIterator(); - SegmentIteratorImpl segIterB = multipathImplB.querySegmentIterator(); - - Envelope2DIntersectorImpl intersector = new Envelope2DIntersectorImpl(); - intersector.setTolerance(tolerance); - - boolean b_found_red = false; - intersector.startRedConstruction(); - while (segIterA.nextPath()) { - while (segIterA.hasNextSegment()) { - Segment segmentA = segIterA.nextSegment(); - segmentA.queryEnvelope2D(env_a); - - if (!env_a.isIntersecting(envInter)) - continue; - - b_found_red = true; - Envelope2D env = new Envelope2D(); - env.setCoords(env_a); - intersector.addRedEnvelope(segIterA.getStartPointIndex(), env); - } - } - intersector.endRedConstruction(); - - if (!b_found_red) - return null; - - boolean b_found_blue = false; - intersector.startBlueConstruction(); - while (segIterB.nextPath()) { - while (segIterB.hasNextSegment()) { - Segment segmentB = segIterB.nextSegment(); - segmentB.queryEnvelope2D(env_b); - - if (!env_b.isIntersecting(envInter)) - continue; - - b_found_blue = true; - Envelope2D env = new Envelope2D(); - env.setCoords(env_b); - intersector.addBlueEnvelope(segIterB.getStartPointIndex(), env); - } - } - intersector.endBlueConstruction(); - - if (!b_found_blue) - return null; - - return intersector; - } - - static Envelope2DIntersectorImpl getEnvelope2DIntersectorForParts( - MultiPathImpl multipathImplA, MultiPathImpl multipathImplB, - double tolerance, boolean bExteriorOnlyA, boolean bExteriorOnlyB) { - int type_a = multipathImplA.getType().value(); - int type_b = multipathImplB.getType().value(); - - Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(); - multipathImplA.queryLooseEnvelope2D(env_a); - multipathImplB.queryLooseEnvelope2D(env_b); - env_a.inflate(tolerance, tolerance); - env_b.inflate(tolerance, tolerance); - - Envelope2D envInter = new Envelope2D(); - envInter.setCoords(env_a); - envInter.intersect(env_b); - - Envelope2DIntersectorImpl intersector = new Envelope2DIntersectorImpl(); - intersector.setTolerance(tolerance); - - boolean b_found_red = false; - intersector.startRedConstruction(); - for (int ipath_a = 0, npaths = multipathImplA.getPathCount(); ipath_a < npaths; ipath_a++) { - if (bExteriorOnlyA && type_a == Geometry.GeometryType.Polygon && !multipathImplA.isExteriorRing(ipath_a)) - continue; - - multipathImplA.queryPathEnvelope2D(ipath_a, env_a); - - if (!env_a.isIntersecting(envInter)) - continue; - - b_found_red = true; - intersector.addRedEnvelope(ipath_a, env_a); - } - intersector.endRedConstruction(); - - if (!b_found_red) - return null; - - boolean b_found_blue = false; - intersector.startBlueConstruction(); - for (int ipath_b = 0, npaths = multipathImplB.getPathCount(); ipath_b < npaths; ipath_b++) { - if (bExteriorOnlyB && type_b == Geometry.GeometryType.Polygon && !multipathImplB.isExteriorRing(ipath_b)) - continue; - - multipathImplB.queryPathEnvelope2D(ipath_b, env_b); - - if (!env_b.isIntersecting(envInter)) - continue; - - b_found_blue = true; - intersector.addBlueEnvelope(ipath_b, env_b); - } - intersector.endBlueConstruction(); - - if (!b_found_blue) - return null; - - return intersector; - } - - static boolean isWeakSimple(MultiVertexGeometry geom, double tol) { - return ((MultiVertexGeometryImpl) geom._getImpl()).getIsSimple(tol) > 0; - } - - static QuadTree buildQuadTreeForOnePath(MultiPathImpl multipathImpl, int path) { - Envelope2D extent = new Envelope2D(); - multipathImpl.queryLoosePathEnvelope2D(path, extent); - QuadTree quad_tree = new QuadTree(extent, 8); - int hint_index = -1; - Envelope2D boundingbox = new Envelope2D(); - SegmentIteratorImpl seg_iter = multipathImpl.querySegmentIterator(); - - seg_iter.resetToPath(path); - if (seg_iter.nextPath()) { - while (seg_iter.hasNextSegment()) { - Segment segment = seg_iter.nextSegment(); - int index = seg_iter.getStartPointIndex(); - segment.queryLooseEnvelope2D(boundingbox); - hint_index = quad_tree.insert(index, boundingbox, hint_index); - - if (hint_index == -1) { - throw new GeometryException("internal error"); - } - } - } - - return quad_tree; - } + // p0 and p1 have to be on left/right boundary of fullRange2D (since this + // fuction can be called recursively, p0 or p1 can also be fullRange2D + // corners) + static int addPointsToArray(Point2D p0In, Point2D p1In, + Point2D[] pointsArray, int idx, Envelope2D fullRange2D, + boolean clockwise, double densifyDist)// PointerOfArrayOf(Point2D) + // pointsArray, int idx, + // Envelope2D fullRange2D, + // boolean clockwise, double + // densifyDist) + { + Point2D p0 = new Point2D(); + p0.setCoords(p0In); + Point2D p1 = new Point2D(); + p1.setCoords(p1In); + fullRange2D._snapToBoundary(p0); + fullRange2D._snapToBoundary(p1); + // //_ASSERT((p0.x == fullRange2D.xmin || p0.x == fullRange2D.xmax) && + // (p1.x == fullRange2D.xmin || p1.x == fullRange2D.xmax)); + double boundDist0 = fullRange2D._boundaryDistance(p0); + double boundDist1 = fullRange2D._boundaryDistance(p1); + if (boundDist1 == 0.0) + boundDist1 = fullRange2D.getLength(); + + if ((p0.x == p1.x || p0.y == p1.y + && (p0.y == fullRange2D.ymin || p0.y == fullRange2D.ymax)) + && (boundDist1 > boundDist0) == clockwise) { + Point2D delta = new Point2D(); + delta.setCoords(p1.x - p0.x, p1.y - p0.y); + if (densifyDist != 0)// if (densifyDist) + { + long cPoints = (long) (delta._norm(0) / densifyDist); + if (cPoints > 0) // if (cPoints) + { + delta.scale(1.0 / (cPoints + 1)); + for (long i = 0; i < cPoints; i++) { + p0.add(delta); + pointsArray[idx++].setCoords(p0.x, p0.y);// ARRAYELEMENT(pointsArray, + // idx++).setCoords(p0.x, + // p0.y); + } + } + } + } else { + int side0 = fullRange2D._envelopeSide(p0); + int side1 = fullRange2D._envelopeSide(p1); + // create up to four corner points; the order depends on boolean + // clockwise + Point2D corner; + int deltaSide = clockwise ? 1 : 3; // 3 is equivalent to -1 + do { + side0 = (side0 + deltaSide) & 3; + corner = fullRange2D.queryCorner(side0); + if (densifyDist != 0)// if (densifyDist) + { + idx = addPointsToArray(p0, corner, pointsArray, idx, + fullRange2D, clockwise, densifyDist); + } + pointsArray[idx++].setCoords(corner.x, corner.y);// ARRAYELEMENT(pointsArray, + // idx++).setCoords(corner.x, + // corner.y); + p0 = corner; + } while ((side0 & 3) != side1); + + if (densifyDist != 0)// if (densifyDist) + idx = addPointsToArray(p0, p1, pointsArray, idx, fullRange2D, + clockwise, densifyDist); + } + + return idx; + } + + void shiftPath(MultiPath inputGeom, int iPath, double shift) { + MultiVertexGeometryImpl vertexGeometryImpl = (MultiVertexGeometryImpl) inputGeom + ._getImpl(); + AttributeStreamOfDbl xyStream = (AttributeStreamOfDbl) vertexGeometryImpl + .getAttributeStreamRef(VertexDescription.Semantics.POSITION); + + int i1 = inputGeom.getPathStart(iPath); + int i2 = inputGeom.getPathEnd(iPath); + Point2D pt = new Point2D(); + + while (i1 < i2) { + xyStream.read(i1, pt); + pt.x += shift; + xyStream.write(i1, pt); + i1++; + } + } + + static double calculateToleranceFromGeometry(SpatialReference sr, + Envelope2D env2D, boolean bConservative) { + double gtolerance = env2D._calculateToleranceFromEnvelope(); + double stolerance = sr != null ? sr + .getTolerance(VertexDescription.Semantics.POSITION) : 0; + if (bConservative) { + gtolerance *= 4; + stolerance *= 1.1; + } + return Math.max(stolerance, gtolerance); + } + + static double adjust_tolerance_for_TE_clustering(double tol) { + return 2.0 * Math.sqrt(2.0) * tol; + } + + static double adjust_tolerance_for_TE_cracking(double tol) { + return Math.sqrt(2.0) * tol; + } + + static double calculateToleranceFromGeometry(SpatialReference sr, + Geometry geometry, boolean bConservative) { + Envelope2D env2D = new Envelope2D(); + geometry.queryEnvelope2D(env2D); + return calculateToleranceFromGeometry(sr, env2D, bConservative); + } + + static double calculateZToleranceFromGeometry(SpatialReference sr, + Geometry geometry, boolean bConservative) { + Envelope1D env1D = geometry.queryInterval( + VertexDescription.Semantics.Z, 0); + double gtolerance = env1D._calculateToleranceFromEnvelope(); + double stolerance = sr != null ? sr + .getTolerance(VertexDescription.Semantics.Z) : 0; + if (bConservative) { + gtolerance *= 4; + stolerance *= 1.1; + } + return Math.max(stolerance, gtolerance); + } + + double calculateZToleranceFromGeometry(SpatialReference sr, + Geometry geometry) { + Envelope1D env1D = geometry.queryInterval( + VertexDescription.Semantics.Z, 0); + double tolerance = env1D._calculateToleranceFromEnvelope(); + return Math + .max(sr != null ? sr + .getTolerance(VertexDescription.Semantics.Z) : 0, + tolerance); + } + + public static Envelope2D getMergedExtent(Geometry geom1, Envelope2D env2) { + Envelope2D env1 = new Envelope2D(); + geom1.queryLooseEnvelope2D(env1); + env1.merge(env2); + return env1; + } + + public static Envelope2D getMergedExtent(Geometry geom1, Geometry geom2) { + Envelope2D env1 = new Envelope2D(); + geom1.queryLooseEnvelope2D(env1); + Envelope2D env2 = new Envelope2D(); + geom2.queryLooseEnvelope2D(env2); + env1.merge(env2); + return env1; + } + + public static Geometry createGeometry(int gt, VertexDescription vdIn) { + VertexDescription vd = vdIn; + if (vd == null) + vd = VertexDescriptionDesignerImpl.getDefaultDescriptor2D(); + switch (gt) { + case Geometry.GeometryType.Point: + return new Point(vd); + case Geometry.GeometryType.Line: + return new Line(vd); + // case enum_value2(Geometry, GeometryType, enumBezier): + // break; + // case enum_value2(Geometry, GeometryType, enumEllipticArc): + // break; + case Geometry.GeometryType.Envelope: + return new Envelope(vd); + case Geometry.GeometryType.MultiPoint: + return new MultiPoint(vd); + case Geometry.GeometryType.Polyline: + return new Polyline(vd); + case Geometry.GeometryType.Polygon: + return new Polygon(vd); + default: + throw new GeometryException("invalid argument."); + } + } + + static boolean isClockwiseRing(MultiPathImpl polygon, int iring) { + int high_point_index = polygon.getHighestPointIndex(iring); + int path_start = polygon.getPathStart(iring); + int path_end = polygon.getPathEnd(iring); + + Point2D q = polygon.getXY(high_point_index); + Point2D p, r; + + if (high_point_index == path_start) { + p = polygon.getXY(path_end - 1); + r = polygon.getXY(path_start + 1); + } else if (high_point_index == path_end - 1) { + p = polygon.getXY(high_point_index - 1); + r = polygon.getXY(path_start); + } else { + p = polygon.getXY(high_point_index - 1); + r = polygon.getXY(high_point_index + 1); + } + + int orientation = Point2D.orientationRobust(p, q, r); + + if (orientation == 0) + return polygon.calculateRingArea2D(iring) > 0.0; + + return orientation == -1; + } + + static QuadTreeImpl buildQuadTree(MultiPathImpl multipathImpl) { + Envelope2D extent = new Envelope2D(); + multipathImpl.queryLooseEnvelope2D(extent); + QuadTreeImpl quad_tree_impl = new QuadTreeImpl(extent, 8); + int hint_index = -1; + SegmentIteratorImpl seg_iter = multipathImpl.querySegmentIterator(); + Envelope2D boundingbox = new Envelope2D(); + boolean resized_extent = false; + + while (seg_iter.nextPath()) { + while (seg_iter.hasNextSegment()) { + Segment segment = seg_iter.nextSegment(); + int index = seg_iter.getStartPointIndex(); + segment.queryEnvelope2D(boundingbox); + hint_index = quad_tree_impl.insert(index, boundingbox, + hint_index); + + if (hint_index == -1) { + if (resized_extent) + throw GeometryException.GeometryInternalError(); + + // resize extent + multipathImpl.calculateEnvelope2D(extent, false); + resized_extent = true; + quad_tree_impl.reset(extent, 8); + seg_iter.resetToFirstPath(); + break; + } + } + } + + return quad_tree_impl; + } + + static QuadTreeImpl buildQuadTree(MultiPathImpl multipathImpl, + Envelope2D extentOfInterest) { + Envelope2D extent = new Envelope2D(); + multipathImpl.queryLooseEnvelope2D(extent); + QuadTreeImpl quad_tree_impl = new QuadTreeImpl(extent, 8); + int hint_index = -1; + Envelope2D boundingbox = new Envelope2D(); + SegmentIteratorImpl seg_iter = multipathImpl.querySegmentIterator(); + + boolean resized_extent = false; + while (seg_iter.nextPath()) { + while (seg_iter.hasNextSegment()) { + Segment segment = seg_iter.nextSegment(); + int index = seg_iter.getStartPointIndex(); + segment.queryEnvelope2D(boundingbox); + + if (boundingbox.isIntersecting(extentOfInterest)) { + hint_index = quad_tree_impl.insert(index, boundingbox, + hint_index); + + if (hint_index == -1) { + if (resized_extent) + throw GeometryException.GeometryInternalError(); + + // resize extent + multipathImpl.calculateEnvelope2D(extent, false); + resized_extent = true; + quad_tree_impl.reset(extent, 8); + seg_iter.resetToFirstPath(); + break; + } + } + } + } + + return quad_tree_impl; + } + + static QuadTreeImpl buildQuadTreeForPaths(MultiPathImpl multipathImpl) { + Envelope2D extent = new Envelope2D(); + multipathImpl.queryLooseEnvelope2D(extent); + if (extent.isEmpty()) + return null; + + QuadTreeImpl quad_tree_impl = new QuadTreeImpl(extent, 8); + int hint_index = -1; + Envelope2D boundingbox = new Envelope2D(); + + boolean resized_extent = false; + do { + for (int ipath = 0, npaths = multipathImpl.getPathCount(); ipath < npaths; ipath++) { + multipathImpl.queryPathEnvelope2D(ipath, boundingbox); + hint_index = quad_tree_impl.insert(ipath, boundingbox, hint_index); + + if (hint_index == -1) { + if (resized_extent) + throw GeometryException.GeometryInternalError(); + + //This is usually happens because esri shape buffer contains geometry extent which is slightly different from the true extent. + //Recalculate extent + multipathImpl.calculateEnvelope2D(extent, false); + resized_extent = true; + quad_tree_impl.reset(extent, 8); + break; //break the for loop + } else { + resized_extent = false; + } + } + + } while (resized_extent); + + return quad_tree_impl; + } + + static QuadTreeImpl buildQuadTree(MultiPointImpl multipointImpl) { + Envelope2D extent = new Envelope2D(); + multipointImpl.queryLooseEnvelope2D(extent); + QuadTreeImpl quad_tree_impl = new QuadTreeImpl(extent, 8); + + Point2D pt = new Point2D(); + Envelope2D boundingbox = new Envelope2D(); + boolean resized_extent = false; + for (int i = 0; i < multipointImpl.getPointCount(); i++) { + multipointImpl.getXY(i, pt); + boundingbox.setCoords(pt); + int element_handle = quad_tree_impl.insert(i, boundingbox); + + if (element_handle == -1) { + if (resized_extent) + throw GeometryException.GeometryInternalError(); + + // resize extent + multipointImpl.calculateEnvelope2D(extent, false); + resized_extent = true; + quad_tree_impl.reset(extent, 8); + i = -1; // resets the for-loop + continue; + } + } + + return quad_tree_impl; + } + + static QuadTreeImpl buildQuadTree(MultiPointImpl multipointImpl, + Envelope2D extentOfInterest) { + QuadTreeImpl quad_tree_impl = new QuadTreeImpl(extentOfInterest, 8); + Point2D pt = new Point2D(); + boolean resized_extent = false; + Envelope2D boundingbox = new Envelope2D(); + for (int i = 0; i < multipointImpl.getPointCount(); i++) { + multipointImpl.getXY(i, pt); + + if (!extentOfInterest.contains(pt)) + continue; + + boundingbox.setCoords(pt); + int element_handle = quad_tree_impl.insert(i, boundingbox); + + if (element_handle == -1) { + if (resized_extent) + throw GeometryException.GeometryInternalError(); + + // resize extent + resized_extent = true; + Envelope2D extent = new Envelope2D(); + multipointImpl.calculateEnvelope2D(extent, false); + quad_tree_impl.reset(extent, 8); + i = -1; // resets the for-loop + continue; + } + } + + return quad_tree_impl; + } + + static Envelope2DIntersectorImpl getEnvelope2DIntersector( + MultiPathImpl multipathImplA, MultiPathImpl multipathImplB, + double tolerance) { + Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(); + multipathImplA.queryLooseEnvelope2D(env_a); + multipathImplB.queryLooseEnvelope2D(env_b); + env_a.inflate(tolerance, tolerance); + env_b.inflate(tolerance, tolerance); + + Envelope2D envInter = new Envelope2D(); + envInter.setCoords(env_a); + envInter.intersect(env_b); + + SegmentIteratorImpl segIterA = multipathImplA.querySegmentIterator(); + SegmentIteratorImpl segIterB = multipathImplB.querySegmentIterator(); + + Envelope2DIntersectorImpl intersector = new Envelope2DIntersectorImpl(); + intersector.setTolerance(tolerance); + + boolean b_found_red = false; + intersector.startRedConstruction(); + while (segIterA.nextPath()) { + while (segIterA.hasNextSegment()) { + Segment segmentA = segIterA.nextSegment(); + segmentA.queryEnvelope2D(env_a); + + if (!env_a.isIntersecting(envInter)) + continue; + + b_found_red = true; + Envelope2D env = new Envelope2D(); + env.setCoords(env_a); + intersector.addRedEnvelope(segIterA.getStartPointIndex(), env); + } + } + intersector.endRedConstruction(); + + if (!b_found_red) + return null; + + boolean b_found_blue = false; + intersector.startBlueConstruction(); + while (segIterB.nextPath()) { + while (segIterB.hasNextSegment()) { + Segment segmentB = segIterB.nextSegment(); + segmentB.queryEnvelope2D(env_b); + + if (!env_b.isIntersecting(envInter)) + continue; + + b_found_blue = true; + Envelope2D env = new Envelope2D(); + env.setCoords(env_b); + intersector.addBlueEnvelope(segIterB.getStartPointIndex(), env); + } + } + intersector.endBlueConstruction(); + + if (!b_found_blue) + return null; + + return intersector; + } + + static Envelope2DIntersectorImpl getEnvelope2DIntersectorForParts( + MultiPathImpl multipathImplA, MultiPathImpl multipathImplB, + double tolerance, boolean bExteriorOnlyA, boolean bExteriorOnlyB) { + int type_a = multipathImplA.getType().value(); + int type_b = multipathImplB.getType().value(); + + Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(); + multipathImplA.queryLooseEnvelope2D(env_a); + multipathImplB.queryLooseEnvelope2D(env_b); + env_a.inflate(tolerance, tolerance); + env_b.inflate(tolerance, tolerance); + + Envelope2D envInter = new Envelope2D(); + envInter.setCoords(env_a); + envInter.intersect(env_b); + + Envelope2DIntersectorImpl intersector = new Envelope2DIntersectorImpl(); + intersector.setTolerance(tolerance); + + boolean b_found_red = false; + intersector.startRedConstruction(); + for (int ipath_a = 0, npaths = multipathImplA.getPathCount(); ipath_a < npaths; ipath_a++) { + if (bExteriorOnlyA && type_a == Geometry.GeometryType.Polygon && !multipathImplA.isExteriorRing(ipath_a)) + continue; + + multipathImplA.queryPathEnvelope2D(ipath_a, env_a); + + if (!env_a.isIntersecting(envInter)) + continue; + + b_found_red = true; + intersector.addRedEnvelope(ipath_a, env_a); + } + intersector.endRedConstruction(); + + if (!b_found_red) + return null; + + boolean b_found_blue = false; + intersector.startBlueConstruction(); + for (int ipath_b = 0, npaths = multipathImplB.getPathCount(); ipath_b < npaths; ipath_b++) { + if (bExteriorOnlyB && type_b == Geometry.GeometryType.Polygon && !multipathImplB.isExteriorRing(ipath_b)) + continue; + + multipathImplB.queryPathEnvelope2D(ipath_b, env_b); + + if (!env_b.isIntersecting(envInter)) + continue; + + b_found_blue = true; + intersector.addBlueEnvelope(ipath_b, env_b); + } + intersector.endBlueConstruction(); + + if (!b_found_blue) + return null; + + return intersector; + } + + static boolean isWeakSimple(MultiVertexGeometry geom, double tol) { + return ((MultiVertexGeometryImpl) geom._getImpl()).getIsSimple(tol) > 0; + } + + static QuadTree buildQuadTreeForOnePath(MultiPathImpl multipathImpl, int path) { + Envelope2D extent = new Envelope2D(); + multipathImpl.queryLoosePathEnvelope2D(path, extent); + QuadTree quad_tree = new QuadTree(extent, 8); + int hint_index = -1; + Envelope2D boundingbox = new Envelope2D(); + SegmentIteratorImpl seg_iter = multipathImpl.querySegmentIterator(); + + seg_iter.resetToPath(path); + if (seg_iter.nextPath()) { + while (seg_iter.hasNextSegment()) { + Segment segment = seg_iter.nextSegment(); + int index = seg_iter.getStartPointIndex(); + segment.queryLooseEnvelope2D(boundingbox); + hint_index = quad_tree.insert(index, boundingbox, hint_index); + + if (hint_index == -1) { + throw new GeometryException("internal error"); + } + } + } + + return quad_tree; + } } diff --git a/src/main/java/com/esri/core/geometry/Interop.java b/src/main/java/com/esri/core/geometry/Interop.java index b90726f0..b47801c7 100644 --- a/src/main/java/com/esri/core/geometry/Interop.java +++ b/src/main/java/com/esri/core/geometry/Interop.java @@ -25,11 +25,11 @@ package com.esri.core.geometry; class Interop { - public static double translateFromAVNaN(double n) { - return (n < -1.0e38) ? NumberUtils.NaN() : n; - } + public static double translateFromAVNaN(double n) { + return (n < -1.0e38) ? NumberUtils.NaN() : n; + } - public static double translateToAVNaN(double n) { - return (NumberUtils.isNaN(n)) ? -Double.MAX_VALUE : n; - } + public static double translateToAVNaN(double n) { + return (NumberUtils.isNaN(n)) ? -Double.MAX_VALUE : n; + } } diff --git a/src/main/java/com/esri/core/geometry/IntervalTreeImpl.java b/src/main/java/com/esri/core/geometry/IntervalTreeImpl.java index cd1d2553..f7248c47 100644 --- a/src/main/java/com/esri/core/geometry/IntervalTreeImpl.java +++ b/src/main/java/com/esri/core/geometry/IntervalTreeImpl.java @@ -26,183 +26,183 @@ import java.util.ArrayList; final class IntervalTreeImpl { - private void sortEndIndices_(AttributeStreamOfInt32 end_indices, int begin_, int end_) { - IntervalTreeBucketSortHelper sorter = new IntervalTreeBucketSortHelper(this); - BucketSort bucket_sort = new BucketSort(); - bucket_sort.sort(end_indices, begin_, end_, sorter); - } - - private void sortEndIndicesHelper_(AttributeStreamOfInt32 end_indices, int begin_, int end_) { - end_indices.Sort(begin_, end_, new EndPointsComparer(this)); - } - - private double getValue_(int e) { - if (!m_b_envelopes_ref) { - Envelope1D interval = m_intervals.get(e >> 1); - double v = (isLeft_(e) ? interval.vmin : interval.vmax); - return v; - } - - Envelope2D interval = m_envelopes_ref.get(e >> 1); - double v = (isLeft_(e) ? interval.xmin : interval.xmax); - return v; - } - - private static final class EndPointsComparer extends AttributeStreamOfInt32.IntComparator { // For user sort - - EndPointsComparer(IntervalTreeImpl interval_tree) { - m_interval_tree = interval_tree; - } - - @Override - public int compare(int e_1, int e_2) { - double v_1 = m_interval_tree.getValue_(e_1); - double v_2 = m_interval_tree.getValue_(e_2); - - if (v_1 < v_2 || (v_1 == v_2 && isLeft_(e_1) && isRight_(e_2))) - return -1; - - return 1; - } - - private IntervalTreeImpl m_interval_tree; - } - - private class IntervalTreeBucketSortHelper extends ClassicSort { // For bucket sort - - IntervalTreeBucketSortHelper(IntervalTreeImpl interval_tree) { - m_interval_tree = interval_tree; - } - - @Override - public void userSort(int begin, int end, AttributeStreamOfInt32 indices) { - m_interval_tree.sortEndIndicesHelper_(indices, begin, end); - } - - @Override - public double getValue(int e) { - return m_interval_tree.getValue_(e); - } - - private IntervalTreeImpl m_interval_tree; - } - - IntervalTreeImpl(boolean b_offline_dynamic) { - m_b_envelopes_ref = false; - m_b_offline_dynamic = b_offline_dynamic; - m_b_constructing = false; - m_b_construction_ended = false; - } - - void addEnvelopesRef(ArrayList envelopes) { - reset_(true, true); - m_b_envelopes_ref = true; - m_envelopes_ref = envelopes; - - m_b_constructing = false; - m_b_construction_ended = true; - - if (!m_b_offline_dynamic) { - insertIntervalsStatic_(); - m_c_count = m_envelopes_ref.size(); - } - } - - void startConstruction() { - reset_(true, false); - } - - void addInterval(Envelope1D interval) { - if (!m_b_constructing) - throw new GeometryException("invalid call"); - - m_intervals.add(interval); - } - - void addInterval(double min, double max) { - if (!m_b_constructing) - throw new GeometryException("invald call"); - - m_intervals.add(new Envelope1D(min, max)); - } - - void endConstruction() { - if (!m_b_constructing) - throw new GeometryException("invalid call"); - - m_b_constructing = false; - m_b_construction_ended = true; - - if (!m_b_offline_dynamic) { - insertIntervalsStatic_(); - m_c_count = m_intervals.size(); - } - } - - /* - * Resets the Interval_tree_impl to an empty state, but maintains a handle - * on the current intervals. - */ - void reset() { - if (!m_b_offline_dynamic || !m_b_construction_ended) - throw new IllegalArgumentException("invalid call"); - - reset_(false, m_b_envelopes_ref); - } - - /** - * Returns the number of intervals stored in the Interval_tree_impl - */ - int size() { - return m_c_count; - } - - /** - * Gets an iterator on the Interval_tree_impl using the input Envelope_1D - * interval as the query. To reuse the existing iterator on the same - * Interval_tree_impl but with a new query, use the reset_iterator function - * on the Interval_tree_iterator_impl. \param query The Envelope_1D interval - * used for the query. \param tolerance The tolerance used for the - * intersection tests. - */ - IntervalTreeIteratorImpl getIterator(Envelope1D query, double tolerance) { - return new IntervalTreeImpl.IntervalTreeIteratorImpl(this, query, tolerance); - } - - /** - * Gets an iterator on the Interval_tree_impl using the input double as the - * stabbing query. To reuse the existing iterator on the same - * Interval_tree_impl but with a new query, use the reset_iterator function - * on the Interval_tree_iterator_impl. \param query The double used for the - * stabbing query. \param tolerance The tolerance used for the intersection - * tests. - */ - IntervalTreeIteratorImpl getIterator(double query, double tolerance) { - return new IntervalTreeImpl.IntervalTreeIteratorImpl(this, query, tolerance); - } - - /** - * Gets an iterator on the Interval_tree_impl. - */ - IntervalTreeIteratorImpl getIterator() { - return new IntervalTreeImpl.IntervalTreeIteratorImpl(this); - } - - private boolean m_b_envelopes_ref; - private boolean m_b_offline_dynamic; - private ArrayList m_intervals; - private ArrayList m_envelopes_ref; - private StridedIndexTypeCollection m_tertiary_nodes; // 5 elements for offline dynamic case, 4 elements for static case - private StridedIndexTypeCollection m_interval_nodes; // 3 elements - private AttributeStreamOfInt32 m_interval_handles; // for offline dynamic// case - private IndexMultiDCList m_secondary_lists; // for static case - private Treap m_secondary_treaps; // for off-line dynamic case - private AttributeStreamOfInt32 m_end_indices_unique; // for both offline dynamic and static cases - private int m_c_count; - private int m_root; - private boolean m_b_sort_intervals; - private boolean m_b_constructing; - private boolean m_b_construction_ended; + private void sortEndIndices_(AttributeStreamOfInt32 end_indices, int begin_, int end_) { + IntervalTreeBucketSortHelper sorter = new IntervalTreeBucketSortHelper(this); + BucketSort bucket_sort = new BucketSort(); + bucket_sort.sort(end_indices, begin_, end_, sorter); + } + + private void sortEndIndicesHelper_(AttributeStreamOfInt32 end_indices, int begin_, int end_) { + end_indices.Sort(begin_, end_, new EndPointsComparer(this)); + } + + private double getValue_(int e) { + if (!m_b_envelopes_ref) { + Envelope1D interval = m_intervals.get(e >> 1); + double v = (isLeft_(e) ? interval.vmin : interval.vmax); + return v; + } + + Envelope2D interval = m_envelopes_ref.get(e >> 1); + double v = (isLeft_(e) ? interval.xmin : interval.xmax); + return v; + } + + private static final class EndPointsComparer extends AttributeStreamOfInt32.IntComparator { // For user sort + + EndPointsComparer(IntervalTreeImpl interval_tree) { + m_interval_tree = interval_tree; + } + + @Override + public int compare(int e_1, int e_2) { + double v_1 = m_interval_tree.getValue_(e_1); + double v_2 = m_interval_tree.getValue_(e_2); + + if (v_1 < v_2 || (v_1 == v_2 && isLeft_(e_1) && isRight_(e_2))) + return -1; + + return 1; + } + + private IntervalTreeImpl m_interval_tree; + } + + private class IntervalTreeBucketSortHelper extends ClassicSort { // For bucket sort + + IntervalTreeBucketSortHelper(IntervalTreeImpl interval_tree) { + m_interval_tree = interval_tree; + } + + @Override + public void userSort(int begin, int end, AttributeStreamOfInt32 indices) { + m_interval_tree.sortEndIndicesHelper_(indices, begin, end); + } + + @Override + public double getValue(int e) { + return m_interval_tree.getValue_(e); + } + + private IntervalTreeImpl m_interval_tree; + } + + IntervalTreeImpl(boolean b_offline_dynamic) { + m_b_envelopes_ref = false; + m_b_offline_dynamic = b_offline_dynamic; + m_b_constructing = false; + m_b_construction_ended = false; + } + + void addEnvelopesRef(ArrayList envelopes) { + reset_(true, true); + m_b_envelopes_ref = true; + m_envelopes_ref = envelopes; + + m_b_constructing = false; + m_b_construction_ended = true; + + if (!m_b_offline_dynamic) { + insertIntervalsStatic_(); + m_c_count = m_envelopes_ref.size(); + } + } + + void startConstruction() { + reset_(true, false); + } + + void addInterval(Envelope1D interval) { + if (!m_b_constructing) + throw new GeometryException("invalid call"); + + m_intervals.add(interval); + } + + void addInterval(double min, double max) { + if (!m_b_constructing) + throw new GeometryException("invald call"); + + m_intervals.add(new Envelope1D(min, max)); + } + + void endConstruction() { + if (!m_b_constructing) + throw new GeometryException("invalid call"); + + m_b_constructing = false; + m_b_construction_ended = true; + + if (!m_b_offline_dynamic) { + insertIntervalsStatic_(); + m_c_count = m_intervals.size(); + } + } + + /* + * Resets the Interval_tree_impl to an empty state, but maintains a handle + * on the current intervals. + */ + void reset() { + if (!m_b_offline_dynamic || !m_b_construction_ended) + throw new IllegalArgumentException("invalid call"); + + reset_(false, m_b_envelopes_ref); + } + + /** + * Returns the number of intervals stored in the Interval_tree_impl + */ + int size() { + return m_c_count; + } + + /** + * Gets an iterator on the Interval_tree_impl using the input Envelope_1D + * interval as the query. To reuse the existing iterator on the same + * Interval_tree_impl but with a new query, use the reset_iterator function + * on the Interval_tree_iterator_impl. \param query The Envelope_1D interval + * used for the query. \param tolerance The tolerance used for the + * intersection tests. + */ + IntervalTreeIteratorImpl getIterator(Envelope1D query, double tolerance) { + return new IntervalTreeImpl.IntervalTreeIteratorImpl(this, query, tolerance); + } + + /** + * Gets an iterator on the Interval_tree_impl using the input double as the + * stabbing query. To reuse the existing iterator on the same + * Interval_tree_impl but with a new query, use the reset_iterator function + * on the Interval_tree_iterator_impl. \param query The double used for the + * stabbing query. \param tolerance The tolerance used for the intersection + * tests. + */ + IntervalTreeIteratorImpl getIterator(double query, double tolerance) { + return new IntervalTreeImpl.IntervalTreeIteratorImpl(this, query, tolerance); + } + + /** + * Gets an iterator on the Interval_tree_impl. + */ + IntervalTreeIteratorImpl getIterator() { + return new IntervalTreeImpl.IntervalTreeIteratorImpl(this); + } + + private boolean m_b_envelopes_ref; + private boolean m_b_offline_dynamic; + private ArrayList m_intervals; + private ArrayList m_envelopes_ref; + private StridedIndexTypeCollection m_tertiary_nodes; // 5 elements for offline dynamic case, 4 elements for static case + private StridedIndexTypeCollection m_interval_nodes; // 3 elements + private AttributeStreamOfInt32 m_interval_handles; // for offline dynamic// case + private IndexMultiDCList m_secondary_lists; // for static case + private Treap m_secondary_treaps; // for off-line dynamic case + private AttributeStreamOfInt32 m_end_indices_unique; // for both offline dynamic and static cases + private int m_c_count; + private int m_root; + private boolean m_b_sort_intervals; + private boolean m_b_constructing; + private boolean m_b_construction_ended; /* m_tertiary_nodes * 0: m_discriminant_index_1 @@ -212,945 +212,945 @@ IntervalTreeIteratorImpl getIterator() { * 4: m_pptr */ - private void querySortedEndPointIndices_(AttributeStreamOfInt32 end_indices) { - int size = (!m_b_envelopes_ref ? m_intervals.size() : m_envelopes_ref.size()); - - for (int i = 0; i < 2 * size; i++) - end_indices.add(i); - - sortEndIndices_(end_indices, 0, 2 * size); - } - - private void querySortedDuplicatesRemoved_(AttributeStreamOfInt32 end_indices_sorted) { - // remove duplicates - - double prev = NumberUtils.TheNaN; - for (int i = 0; i < end_indices_sorted.size(); i++) { - int e = end_indices_sorted.get(i); - double v = getValue_(e); - - if (v != prev) { - m_end_indices_unique.add(e); - prev = v; - } - } - } - - void insert(int index) { - if (!m_b_offline_dynamic || !m_b_construction_ended) - throw new IllegalArgumentException("invalid call"); - - if (m_root == -1) { - - int size = (!m_b_envelopes_ref ? m_intervals.size() : m_envelopes_ref.size()); - - if (m_b_sort_intervals) { - // sort - AttributeStreamOfInt32 end_point_indices_sorted = new AttributeStreamOfInt32(0); - end_point_indices_sorted.reserve(2 * size); - querySortedEndPointIndices_(end_point_indices_sorted); - - // remove duplicates - m_end_indices_unique.resize(0); - querySortedDuplicatesRemoved_(end_point_indices_sorted); - m_interval_handles.resize(size, -1); - m_interval_handles.setRange(-1, 0, size); - m_b_sort_intervals = false; - } else { - m_interval_handles.setRange(-1, 0, size); - } - - m_root = createRoot_(); - } - - int interval_handle = insertIntervalEnd_(index << 1, m_root); - int secondary_handle = getSecondaryFromInterval_(interval_handle); - int right_end_handle = m_secondary_treaps.addElement((index << 1) + 1, secondary_handle); - setRightEnd_(interval_handle, right_end_handle); - m_interval_handles.set(index, interval_handle); - m_c_count++; - // assert(check_validation_()); - } - - private void insertIntervalsStatic_() { - int size = (!m_b_envelopes_ref ? m_intervals.size() : m_envelopes_ref.size()); - - assert (m_b_sort_intervals); - - // sort - AttributeStreamOfInt32 end_indices_sorted = new AttributeStreamOfInt32(0); - end_indices_sorted.reserve(2 * size); - querySortedEndPointIndices_(end_indices_sorted); - - // remove duplicates - m_end_indices_unique.resize(0); - querySortedDuplicatesRemoved_(end_indices_sorted); - - assert (m_tertiary_nodes.size() == 0); - m_interval_nodes.setCapacity(size); // one for each interval being inserted. each element contains a tertiary node, a left secondary node, and a right secondary node. - m_secondary_lists.reserveNodes(2 * size); // one for each end point of the original interval set (not the unique set) - - AttributeStreamOfInt32 interval_handles = (AttributeStreamOfInt32) AttributeStreamBase.createIndexStream(size); - interval_handles.setRange(-1, 0, size); - - m_root = createRoot_(); - - for (int i = 0; i < end_indices_sorted.size(); i++) { - int e = end_indices_sorted.get(i); - int interval_handle = interval_handles.get(e >> 1); - - if (interval_handle != -1) {// insert the right end point - assert (isRight_(e)); - int secondary_handle = getSecondaryFromInterval_(interval_handle); - setRightEnd_(interval_handle, m_secondary_lists.addElement(secondary_handle, e)); - } else {// insert the left end point - assert (isLeft_(e)); - interval_handle = insertIntervalEnd_(e, m_root); - interval_handles.set(e >> 1, interval_handle); - } - } - - assert (m_secondary_lists.getNodeCount() == 2 * size); - } - - private int createRoot_() { - int discriminant_index_1 = calculateDiscriminantIndex1_(0, m_end_indices_unique.size() - 1); - return createTertiaryNode_(discriminant_index_1); - } - - private int insertIntervalEnd_(int end_index, int root) { - assert (isLeft_(end_index)); - int pptr = -1; - int ptr = root; - int secondary_handle = -1; - int interval_handle = -1; - int il = 0, ir = m_end_indices_unique.size() - 1, im = 0; - int index = end_index >> 1; - double discriminant_pptr = NumberUtils.NaN(); - double discriminant_ptr = NumberUtils.NaN(); - boolean bSearching = true; - - double min = getMin_(index); - double max = getMax_(index); - - int discriminant_index_1 = -1; - - while (bSearching) { - im = il + (ir - il) / 2; - assert (il != ir || min == max); - discriminant_index_1 = calculateDiscriminantIndex1_(il, ir); - double discriminant = getDiscriminantFromIndex1_(discriminant_index_1); - assert (!NumberUtils.isNaN(discriminant)); - - if (max < discriminant) { - if (ptr != -1) { - if (discriminant_index_1 == getDiscriminantIndex1_(ptr)) { - assert (getDiscriminantFromIndex1_(discriminant_index_1) == getDiscriminant_(ptr)); - - pptr = ptr; - discriminant_pptr = discriminant; - ptr = getLPTR_(ptr); - - if (ptr != -1) - discriminant_ptr = getDiscriminant_(ptr); - else - discriminant_ptr = NumberUtils.NaN(); - } else if (discriminant_ptr > discriminant) { - int tertiary_handle = createTertiaryNode_(discriminant_index_1); - - if (discriminant < discriminant_pptr) - setLPTR_(pptr, tertiary_handle); - else - setRPTR_(pptr, tertiary_handle); - - setRPTR_(tertiary_handle, ptr); - - if (m_b_offline_dynamic) { - setPPTR_(tertiary_handle, pptr); - setPPTR_(ptr, tertiary_handle); - } - - pptr = tertiary_handle; - discriminant_pptr = discriminant; - ptr = -1; - discriminant_ptr = NumberUtils.NaN(); - } - } - - ir = im; - - continue; - } - - if (min > discriminant) { - if (ptr != -1) { - if (discriminant_index_1 == getDiscriminantIndex1_(ptr)) { - assert (getDiscriminantFromIndex1_(discriminant_index_1) == getDiscriminant_(ptr)); - - pptr = ptr; - discriminant_pptr = discriminant; - ptr = getRPTR_(ptr); - - if (ptr != -1) - discriminant_ptr = getDiscriminant_(ptr); - else - discriminant_ptr = NumberUtils.NaN(); - } else if (discriminant_ptr < discriminant) { - int tertiary_handle = createTertiaryNode_(discriminant_index_1); - - if (discriminant < discriminant_pptr) - setLPTR_(pptr, tertiary_handle); - else - setRPTR_(pptr, tertiary_handle); - - setLPTR_(tertiary_handle, ptr); - - if (m_b_offline_dynamic) { - setPPTR_(tertiary_handle, pptr); - setPPTR_(ptr, tertiary_handle); - } - - pptr = tertiary_handle; - discriminant_pptr = discriminant; - ptr = -1; - discriminant_ptr = NumberUtils.NaN(); - } - } - - il = im + 1; - - continue; - } - - int tertiary_handle = -1; - - if (ptr == -1 || discriminant_index_1 != getDiscriminantIndex1_(ptr)) { - tertiary_handle = createTertiaryNode_(discriminant_index_1); - } else { - tertiary_handle = ptr; - } - - secondary_handle = getSecondaryFromTertiary_(tertiary_handle); - - if (secondary_handle == -1) { - secondary_handle = createSecondary_(tertiary_handle); - setSecondaryToTertiary_(tertiary_handle, secondary_handle); - } - - int left_end_handle = addEndIndex_(secondary_handle, end_index); - interval_handle = createIntervalNode_(); - setSecondaryToInterval_(interval_handle, secondary_handle); - setLeftEnd_(interval_handle, left_end_handle); - - if (ptr == -1 || discriminant_index_1 != getDiscriminantIndex1_(ptr)) { - assert (tertiary_handle != -1); - assert (getLPTR_(tertiary_handle) == -1 && getRPTR_(tertiary_handle) == -1 && (!m_b_offline_dynamic || getPPTR_(tertiary_handle) == -1)); - - if (discriminant < discriminant_pptr) - setLPTR_(pptr, tertiary_handle); - else - setRPTR_(pptr, tertiary_handle); - - if (m_b_offline_dynamic) - setPPTR_(tertiary_handle, pptr); - - if (ptr != -1) { - if (discriminant_ptr < discriminant) - setLPTR_(tertiary_handle, ptr); - else - setRPTR_(tertiary_handle, ptr); - - if (m_b_offline_dynamic) - setPPTR_(ptr, tertiary_handle); - } - } - - bSearching = false; - break; - } - - return interval_handle; - } - - void remove(int index) { - if (!m_b_offline_dynamic || !m_b_construction_ended) - throw new GeometryException("invalid call"); - - int interval_handle = m_interval_handles.get(index); - - if (interval_handle == -1) - throw new GeometryException("the interval does not exist in the interval tree"); - - m_interval_handles.set(index, -1); - - assert (getSecondaryFromInterval_(interval_handle) != -1); - assert (getLeftEnd_(interval_handle) != -1); - assert (getRightEnd_(interval_handle) != -1); - - m_c_count--; - - int size; - int secondary_handle = getSecondaryFromInterval_(interval_handle); - int tertiary_handle = -1; - - tertiary_handle = m_secondary_treaps.getTreapData(secondary_handle); - m_secondary_treaps.deleteNode(getLeftEnd_(interval_handle), secondary_handle); - m_secondary_treaps.deleteNode(getRightEnd_(interval_handle), secondary_handle); - size = m_secondary_treaps.size(secondary_handle); - - if (size == 0) { - m_secondary_treaps.deleteTreap(secondary_handle); - setSecondaryToTertiary_(tertiary_handle, -1); - } - - m_interval_nodes.deleteElement(interval_handle); - int pptr = getPPTR_(tertiary_handle); - int lptr = getLPTR_(tertiary_handle); - int rptr = getRPTR_(tertiary_handle); - - int iterations = 0; - while (!(size > 0 || tertiary_handle == m_root || (lptr != -1 && rptr != -1))) { - assert (size == 0); - assert (lptr == -1 || rptr == -1); - assert (tertiary_handle != 0); - - if (tertiary_handle == getLPTR_(pptr)) { - if (lptr != -1) { - setLPTR_(pptr, lptr); - setPPTR_(lptr, pptr); - setLPTR_(tertiary_handle, -1); - setPPTR_(tertiary_handle, -1); - } else if (rptr != -1) { - setLPTR_(pptr, rptr); - setPPTR_(rptr, pptr); - setRPTR_(tertiary_handle, -1); - setPPTR_(tertiary_handle, -1); - } else { - setLPTR_(pptr, -1); - setPPTR_(tertiary_handle, -1); - } - } else { - if (lptr != -1) { - setRPTR_(pptr, lptr); - setPPTR_(lptr, pptr); - setLPTR_(tertiary_handle, -1); - setPPTR_(tertiary_handle, -1); - } else if (rptr != -1) { - setRPTR_(pptr, rptr); - setPPTR_(rptr, pptr); - setRPTR_(tertiary_handle, -1); - setPPTR_(tertiary_handle, -1); - } else { - setRPTR_(pptr, -1); - setPPTR_(tertiary_handle, -1); - } - } - - m_tertiary_nodes.deleteElement(tertiary_handle); - - iterations++; - tertiary_handle = pptr; - secondary_handle = getSecondaryFromTertiary_(tertiary_handle); - size = (secondary_handle != -1 ? m_secondary_treaps.size(secondary_handle) : 0); - lptr = getLPTR_(tertiary_handle); - rptr = getRPTR_(tertiary_handle); - pptr = getPPTR_(tertiary_handle); - } - - assert (iterations <= 2); - //assert(check_validation_()); - } - - private void reset_(boolean b_new_intervals, boolean b_envelopes_ref) { - if (b_new_intervals) { - m_b_envelopes_ref = false; - m_envelopes_ref = null; - - m_b_sort_intervals = true; - m_b_constructing = true; - m_b_construction_ended = false; - - if (m_end_indices_unique == null) - m_end_indices_unique = (AttributeStreamOfInt32) (AttributeStreamBase.createIndexStream(0)); - else - m_end_indices_unique.resize(0); - - if (!b_envelopes_ref) { - if (m_intervals == null) - m_intervals = new ArrayList(0); - else - m_intervals.clear(); - } else { - if (m_intervals != null) - m_intervals.clear(); - - m_b_envelopes_ref = true; - } - } else { - assert (m_b_offline_dynamic && m_b_construction_ended); - m_b_sort_intervals = false; - } - - if (m_b_offline_dynamic) { - if (m_interval_handles == null) { - m_interval_handles = (AttributeStreamOfInt32) (AttributeStreamBase.createIndexStream(0)); - m_secondary_treaps = new Treap(); - m_secondary_treaps.setComparator(new SecondaryComparator(this)); - } else { - m_secondary_treaps.clear(); - } - } else { - if (m_secondary_lists == null) - m_secondary_lists = new IndexMultiDCList(); - else - m_secondary_lists.clear(); - } - - if (m_tertiary_nodes == null) { - m_interval_nodes = new StridedIndexTypeCollection(3); - m_tertiary_nodes = new StridedIndexTypeCollection(m_b_offline_dynamic ? 5 : 4); - } else { - m_interval_nodes.deleteAll(false); - m_tertiary_nodes.deleteAll(false); - } - - m_root = -1; - m_c_count = 0; - } - - private double getDiscriminant_(int tertiary_handle) { - int discriminant_index_1 = getDiscriminantIndex1_(tertiary_handle); - return getDiscriminantFromIndex1_(discriminant_index_1); - } - - private double getDiscriminantFromIndex1_(int discriminant_index_1) { - if (discriminant_index_1 == -1) - return NumberUtils.NaN(); - - if (discriminant_index_1 > 0) { - int j = discriminant_index_1 - 2; - int e_1 = m_end_indices_unique.get(j); - int e_2 = m_end_indices_unique.get(j + 1); - - double v_1 = getValue_(e_1); - double v_2 = getValue_(e_2); - assert (v_1 < v_2); - - return 0.5 * (v_1 + v_2); - } - - int j = -discriminant_index_1 - 2; - assert (j >= 0); - int e = m_end_indices_unique.get(j); - double v = getValue_(e); - - return v; - } - - private int calculateDiscriminantIndex1_(int il, int ir) { - int discriminant_index_1; - - if (il < ir) { - int im = il + (ir - il) / 2; - discriminant_index_1 = im + 2; // positive discriminant means use average of im and im + 1 - } else { - discriminant_index_1 = -(il + 2); // negative discriminant just means use il (-(il + 2) will never be -1) - } - - return discriminant_index_1; - } - - static final class IntervalTreeIteratorImpl { - - private IntervalTreeImpl m_interval_tree; - private Envelope1D m_query = new Envelope1D(); - private int m_tertiary_handle; - private int m_next_tertiary_handle; - private int m_forked_handle; - private int m_current_end_handle; - private int m_next_end_handle; - private AttributeStreamOfInt32 m_tertiary_stack = new AttributeStreamOfInt32(0); - private int m_function_index; - private int[] m_function_stack = new int[2]; - - private interface State { - static final int initialize = 0; - static final int pIn = 1; - static final int pL = 2; - static final int pR = 3; - static final int pT = 4; - static final int right = 5; - static final int left = 6; - static final int all = 7; - } - - private int getNext_() { - if (!m_interval_tree.m_b_offline_dynamic) - return m_interval_tree.m_secondary_lists.getNext(m_current_end_handle); - - return m_interval_tree.m_secondary_treaps.getNext(m_current_end_handle); - } - - private int getPrev_() { - if (!m_interval_tree.m_b_offline_dynamic) - return m_interval_tree.m_secondary_lists.getPrev(m_current_end_handle); - - return m_interval_tree.m_secondary_treaps.getPrev(m_current_end_handle); - } - - private int getCurrentEndIndex_() { - if (!m_interval_tree.m_b_offline_dynamic) - return m_interval_tree.m_secondary_lists.getData(m_current_end_handle); - - return m_interval_tree.m_secondary_treaps.getElement(m_current_end_handle); - } - - int next() { - if (!m_interval_tree.m_b_construction_ended) - throw new GeometryException("invalid call"); - - if (m_function_index < 0) - return -1; - - boolean b_searching = true; - - while (b_searching) { - switch (m_function_stack[m_function_index]) { - case State.pIn: - b_searching = pIn_(); - break; - case State.pL: - b_searching = pL_(); - break; - case State.pR: - b_searching = pR_(); - break; - case State.pT: - b_searching = pT_(); - break; - case State.right: - b_searching = right_(); - break; - case State.left: - b_searching = left_(); - break; - case State.all: - b_searching = all_(); - break; - case State.initialize: - b_searching = initialize_(); - break; - default: - throw GeometryException.GeometryInternalError(); - } - } - - if (m_current_end_handle != -1) - return getCurrentEndIndex_() >> 1; - - return -1; - } - - private boolean initialize_() { - m_tertiary_handle = -1; - m_next_tertiary_handle = -1; - m_forked_handle = -1; - m_current_end_handle = -1; - - if (m_interval_tree.m_tertiary_nodes != null && m_interval_tree.m_tertiary_nodes.size() > 0) { - m_function_stack[0] = State.pIn; // overwrite initialize - m_next_tertiary_handle = m_interval_tree.m_root; - return true; - } - - m_function_index = -1; - return false; - } - - private boolean pIn_() { - m_tertiary_handle = m_next_tertiary_handle; - - if (m_tertiary_handle == -1) { - m_function_index = -1; - m_current_end_handle = -1; - return false; - } - - double discriminant = m_interval_tree.getDiscriminant_(m_tertiary_handle); - - if (m_query.vmax < discriminant) { - int secondary_handle = m_interval_tree.getSecondaryFromTertiary_(m_tertiary_handle); - m_next_tertiary_handle = m_interval_tree.getLPTR_(m_tertiary_handle); - - if (secondary_handle != -1) { - m_next_end_handle = m_interval_tree.getFirst_(secondary_handle); - m_function_stack[++m_function_index] = State.left; - } - - return true; - } - - if (discriminant < m_query.vmin) { - int secondary_handle = m_interval_tree.getSecondaryFromTertiary_(m_tertiary_handle); - m_next_tertiary_handle = m_interval_tree.getRPTR_(m_tertiary_handle); - - if (secondary_handle != -1) { - m_next_end_handle = m_interval_tree.getLast_(secondary_handle); - m_function_stack[++m_function_index] = State.right; - } - - return true; - } - - assert (m_query.contains(discriminant)); - - m_function_stack[m_function_index] = State.pL; // overwrite pIn - m_forked_handle = m_tertiary_handle; - int secondary_handle = m_interval_tree.getSecondaryFromTertiary_(m_tertiary_handle); - m_next_tertiary_handle = m_interval_tree.getLPTR_(m_tertiary_handle); - - if (secondary_handle != -1) { - m_next_end_handle = m_interval_tree.getFirst_(secondary_handle); - m_function_stack[++m_function_index] = State.all; - } - - return true; - } - - private boolean pL_() { - m_tertiary_handle = m_next_tertiary_handle; - - if (m_tertiary_handle == -1) { - m_function_stack[m_function_index] = State.pR; // overwrite pL - m_next_tertiary_handle = m_interval_tree.getRPTR_(m_forked_handle); - return true; - } + private void querySortedEndPointIndices_(AttributeStreamOfInt32 end_indices) { + int size = (!m_b_envelopes_ref ? m_intervals.size() : m_envelopes_ref.size()); + + for (int i = 0; i < 2 * size; i++) + end_indices.add(i); + + sortEndIndices_(end_indices, 0, 2 * size); + } + + private void querySortedDuplicatesRemoved_(AttributeStreamOfInt32 end_indices_sorted) { + // remove duplicates + + double prev = NumberUtils.TheNaN; + for (int i = 0; i < end_indices_sorted.size(); i++) { + int e = end_indices_sorted.get(i); + double v = getValue_(e); + + if (v != prev) { + m_end_indices_unique.add(e); + prev = v; + } + } + } + + void insert(int index) { + if (!m_b_offline_dynamic || !m_b_construction_ended) + throw new IllegalArgumentException("invalid call"); + + if (m_root == -1) { + + int size = (!m_b_envelopes_ref ? m_intervals.size() : m_envelopes_ref.size()); + + if (m_b_sort_intervals) { + // sort + AttributeStreamOfInt32 end_point_indices_sorted = new AttributeStreamOfInt32(0); + end_point_indices_sorted.reserve(2 * size); + querySortedEndPointIndices_(end_point_indices_sorted); + + // remove duplicates + m_end_indices_unique.resize(0); + querySortedDuplicatesRemoved_(end_point_indices_sorted); + m_interval_handles.resize(size, -1); + m_interval_handles.setRange(-1, 0, size); + m_b_sort_intervals = false; + } else { + m_interval_handles.setRange(-1, 0, size); + } + + m_root = createRoot_(); + } + + int interval_handle = insertIntervalEnd_(index << 1, m_root); + int secondary_handle = getSecondaryFromInterval_(interval_handle); + int right_end_handle = m_secondary_treaps.addElement((index << 1) + 1, secondary_handle); + setRightEnd_(interval_handle, right_end_handle); + m_interval_handles.set(index, interval_handle); + m_c_count++; + // assert(check_validation_()); + } + + private void insertIntervalsStatic_() { + int size = (!m_b_envelopes_ref ? m_intervals.size() : m_envelopes_ref.size()); + + assert (m_b_sort_intervals); + + // sort + AttributeStreamOfInt32 end_indices_sorted = new AttributeStreamOfInt32(0); + end_indices_sorted.reserve(2 * size); + querySortedEndPointIndices_(end_indices_sorted); + + // remove duplicates + m_end_indices_unique.resize(0); + querySortedDuplicatesRemoved_(end_indices_sorted); + + assert (m_tertiary_nodes.size() == 0); + m_interval_nodes.setCapacity(size); // one for each interval being inserted. each element contains a tertiary node, a left secondary node, and a right secondary node. + m_secondary_lists.reserveNodes(2 * size); // one for each end point of the original interval set (not the unique set) + + AttributeStreamOfInt32 interval_handles = (AttributeStreamOfInt32) AttributeStreamBase.createIndexStream(size); + interval_handles.setRange(-1, 0, size); + + m_root = createRoot_(); + + for (int i = 0; i < end_indices_sorted.size(); i++) { + int e = end_indices_sorted.get(i); + int interval_handle = interval_handles.get(e >> 1); + + if (interval_handle != -1) {// insert the right end point + assert (isRight_(e)); + int secondary_handle = getSecondaryFromInterval_(interval_handle); + setRightEnd_(interval_handle, m_secondary_lists.addElement(secondary_handle, e)); + } else {// insert the left end point + assert (isLeft_(e)); + interval_handle = insertIntervalEnd_(e, m_root); + interval_handles.set(e >> 1, interval_handle); + } + } + + assert (m_secondary_lists.getNodeCount() == 2 * size); + } + + private int createRoot_() { + int discriminant_index_1 = calculateDiscriminantIndex1_(0, m_end_indices_unique.size() - 1); + return createTertiaryNode_(discriminant_index_1); + } + + private int insertIntervalEnd_(int end_index, int root) { + assert (isLeft_(end_index)); + int pptr = -1; + int ptr = root; + int secondary_handle = -1; + int interval_handle = -1; + int il = 0, ir = m_end_indices_unique.size() - 1, im = 0; + int index = end_index >> 1; + double discriminant_pptr = NumberUtils.NaN(); + double discriminant_ptr = NumberUtils.NaN(); + boolean bSearching = true; + + double min = getMin_(index); + double max = getMax_(index); + + int discriminant_index_1 = -1; + + while (bSearching) { + im = il + (ir - il) / 2; + assert (il != ir || min == max); + discriminant_index_1 = calculateDiscriminantIndex1_(il, ir); + double discriminant = getDiscriminantFromIndex1_(discriminant_index_1); + assert (!NumberUtils.isNaN(discriminant)); + + if (max < discriminant) { + if (ptr != -1) { + if (discriminant_index_1 == getDiscriminantIndex1_(ptr)) { + assert (getDiscriminantFromIndex1_(discriminant_index_1) == getDiscriminant_(ptr)); + + pptr = ptr; + discriminant_pptr = discriminant; + ptr = getLPTR_(ptr); + + if (ptr != -1) + discriminant_ptr = getDiscriminant_(ptr); + else + discriminant_ptr = NumberUtils.NaN(); + } else if (discriminant_ptr > discriminant) { + int tertiary_handle = createTertiaryNode_(discriminant_index_1); + + if (discriminant < discriminant_pptr) + setLPTR_(pptr, tertiary_handle); + else + setRPTR_(pptr, tertiary_handle); + + setRPTR_(tertiary_handle, ptr); + + if (m_b_offline_dynamic) { + setPPTR_(tertiary_handle, pptr); + setPPTR_(ptr, tertiary_handle); + } + + pptr = tertiary_handle; + discriminant_pptr = discriminant; + ptr = -1; + discriminant_ptr = NumberUtils.NaN(); + } + } + + ir = im; + + continue; + } + + if (min > discriminant) { + if (ptr != -1) { + if (discriminant_index_1 == getDiscriminantIndex1_(ptr)) { + assert (getDiscriminantFromIndex1_(discriminant_index_1) == getDiscriminant_(ptr)); + + pptr = ptr; + discriminant_pptr = discriminant; + ptr = getRPTR_(ptr); + + if (ptr != -1) + discriminant_ptr = getDiscriminant_(ptr); + else + discriminant_ptr = NumberUtils.NaN(); + } else if (discriminant_ptr < discriminant) { + int tertiary_handle = createTertiaryNode_(discriminant_index_1); + + if (discriminant < discriminant_pptr) + setLPTR_(pptr, tertiary_handle); + else + setRPTR_(pptr, tertiary_handle); + + setLPTR_(tertiary_handle, ptr); + + if (m_b_offline_dynamic) { + setPPTR_(tertiary_handle, pptr); + setPPTR_(ptr, tertiary_handle); + } + + pptr = tertiary_handle; + discriminant_pptr = discriminant; + ptr = -1; + discriminant_ptr = NumberUtils.NaN(); + } + } + + il = im + 1; + + continue; + } + + int tertiary_handle = -1; + + if (ptr == -1 || discriminant_index_1 != getDiscriminantIndex1_(ptr)) { + tertiary_handle = createTertiaryNode_(discriminant_index_1); + } else { + tertiary_handle = ptr; + } + + secondary_handle = getSecondaryFromTertiary_(tertiary_handle); + + if (secondary_handle == -1) { + secondary_handle = createSecondary_(tertiary_handle); + setSecondaryToTertiary_(tertiary_handle, secondary_handle); + } + + int left_end_handle = addEndIndex_(secondary_handle, end_index); + interval_handle = createIntervalNode_(); + setSecondaryToInterval_(interval_handle, secondary_handle); + setLeftEnd_(interval_handle, left_end_handle); + + if (ptr == -1 || discriminant_index_1 != getDiscriminantIndex1_(ptr)) { + assert (tertiary_handle != -1); + assert (getLPTR_(tertiary_handle) == -1 && getRPTR_(tertiary_handle) == -1 && (!m_b_offline_dynamic || getPPTR_(tertiary_handle) == -1)); + + if (discriminant < discriminant_pptr) + setLPTR_(pptr, tertiary_handle); + else + setRPTR_(pptr, tertiary_handle); + + if (m_b_offline_dynamic) + setPPTR_(tertiary_handle, pptr); + + if (ptr != -1) { + if (discriminant_ptr < discriminant) + setLPTR_(tertiary_handle, ptr); + else + setRPTR_(tertiary_handle, ptr); + + if (m_b_offline_dynamic) + setPPTR_(ptr, tertiary_handle); + } + } + + bSearching = false; + break; + } + + return interval_handle; + } + + void remove(int index) { + if (!m_b_offline_dynamic || !m_b_construction_ended) + throw new GeometryException("invalid call"); + + int interval_handle = m_interval_handles.get(index); + + if (interval_handle == -1) + throw new GeometryException("the interval does not exist in the interval tree"); + + m_interval_handles.set(index, -1); + + assert (getSecondaryFromInterval_(interval_handle) != -1); + assert (getLeftEnd_(interval_handle) != -1); + assert (getRightEnd_(interval_handle) != -1); + + m_c_count--; + + int size; + int secondary_handle = getSecondaryFromInterval_(interval_handle); + int tertiary_handle = -1; + + tertiary_handle = m_secondary_treaps.getTreapData(secondary_handle); + m_secondary_treaps.deleteNode(getLeftEnd_(interval_handle), secondary_handle); + m_secondary_treaps.deleteNode(getRightEnd_(interval_handle), secondary_handle); + size = m_secondary_treaps.size(secondary_handle); + + if (size == 0) { + m_secondary_treaps.deleteTreap(secondary_handle); + setSecondaryToTertiary_(tertiary_handle, -1); + } + + m_interval_nodes.deleteElement(interval_handle); + int pptr = getPPTR_(tertiary_handle); + int lptr = getLPTR_(tertiary_handle); + int rptr = getRPTR_(tertiary_handle); + + int iterations = 0; + while (!(size > 0 || tertiary_handle == m_root || (lptr != -1 && rptr != -1))) { + assert (size == 0); + assert (lptr == -1 || rptr == -1); + assert (tertiary_handle != 0); + + if (tertiary_handle == getLPTR_(pptr)) { + if (lptr != -1) { + setLPTR_(pptr, lptr); + setPPTR_(lptr, pptr); + setLPTR_(tertiary_handle, -1); + setPPTR_(tertiary_handle, -1); + } else if (rptr != -1) { + setLPTR_(pptr, rptr); + setPPTR_(rptr, pptr); + setRPTR_(tertiary_handle, -1); + setPPTR_(tertiary_handle, -1); + } else { + setLPTR_(pptr, -1); + setPPTR_(tertiary_handle, -1); + } + } else { + if (lptr != -1) { + setRPTR_(pptr, lptr); + setPPTR_(lptr, pptr); + setLPTR_(tertiary_handle, -1); + setPPTR_(tertiary_handle, -1); + } else if (rptr != -1) { + setRPTR_(pptr, rptr); + setPPTR_(rptr, pptr); + setRPTR_(tertiary_handle, -1); + setPPTR_(tertiary_handle, -1); + } else { + setRPTR_(pptr, -1); + setPPTR_(tertiary_handle, -1); + } + } + + m_tertiary_nodes.deleteElement(tertiary_handle); + + iterations++; + tertiary_handle = pptr; + secondary_handle = getSecondaryFromTertiary_(tertiary_handle); + size = (secondary_handle != -1 ? m_secondary_treaps.size(secondary_handle) : 0); + lptr = getLPTR_(tertiary_handle); + rptr = getRPTR_(tertiary_handle); + pptr = getPPTR_(tertiary_handle); + } + + assert (iterations <= 2); + //assert(check_validation_()); + } + + private void reset_(boolean b_new_intervals, boolean b_envelopes_ref) { + if (b_new_intervals) { + m_b_envelopes_ref = false; + m_envelopes_ref = null; + + m_b_sort_intervals = true; + m_b_constructing = true; + m_b_construction_ended = false; + + if (m_end_indices_unique == null) + m_end_indices_unique = (AttributeStreamOfInt32) (AttributeStreamBase.createIndexStream(0)); + else + m_end_indices_unique.resize(0); + + if (!b_envelopes_ref) { + if (m_intervals == null) + m_intervals = new ArrayList(0); + else + m_intervals.clear(); + } else { + if (m_intervals != null) + m_intervals.clear(); + + m_b_envelopes_ref = true; + } + } else { + assert (m_b_offline_dynamic && m_b_construction_ended); + m_b_sort_intervals = false; + } + + if (m_b_offline_dynamic) { + if (m_interval_handles == null) { + m_interval_handles = (AttributeStreamOfInt32) (AttributeStreamBase.createIndexStream(0)); + m_secondary_treaps = new Treap(); + m_secondary_treaps.setComparator(new SecondaryComparator(this)); + } else { + m_secondary_treaps.clear(); + } + } else { + if (m_secondary_lists == null) + m_secondary_lists = new IndexMultiDCList(); + else + m_secondary_lists.clear(); + } + + if (m_tertiary_nodes == null) { + m_interval_nodes = new StridedIndexTypeCollection(3); + m_tertiary_nodes = new StridedIndexTypeCollection(m_b_offline_dynamic ? 5 : 4); + } else { + m_interval_nodes.deleteAll(false); + m_tertiary_nodes.deleteAll(false); + } + + m_root = -1; + m_c_count = 0; + } + + private double getDiscriminant_(int tertiary_handle) { + int discriminant_index_1 = getDiscriminantIndex1_(tertiary_handle); + return getDiscriminantFromIndex1_(discriminant_index_1); + } + + private double getDiscriminantFromIndex1_(int discriminant_index_1) { + if (discriminant_index_1 == -1) + return NumberUtils.NaN(); + + if (discriminant_index_1 > 0) { + int j = discriminant_index_1 - 2; + int e_1 = m_end_indices_unique.get(j); + int e_2 = m_end_indices_unique.get(j + 1); + + double v_1 = getValue_(e_1); + double v_2 = getValue_(e_2); + assert (v_1 < v_2); + + return 0.5 * (v_1 + v_2); + } + + int j = -discriminant_index_1 - 2; + assert (j >= 0); + int e = m_end_indices_unique.get(j); + double v = getValue_(e); + + return v; + } + + private int calculateDiscriminantIndex1_(int il, int ir) { + int discriminant_index_1; + + if (il < ir) { + int im = il + (ir - il) / 2; + discriminant_index_1 = im + 2; // positive discriminant means use average of im and im + 1 + } else { + discriminant_index_1 = -(il + 2); // negative discriminant just means use il (-(il + 2) will never be -1) + } + + return discriminant_index_1; + } + + static final class IntervalTreeIteratorImpl { + + private IntervalTreeImpl m_interval_tree; + private Envelope1D m_query = new Envelope1D(); + private int m_tertiary_handle; + private int m_next_tertiary_handle; + private int m_forked_handle; + private int m_current_end_handle; + private int m_next_end_handle; + private AttributeStreamOfInt32 m_tertiary_stack = new AttributeStreamOfInt32(0); + private int m_function_index; + private int[] m_function_stack = new int[2]; + + private interface State { + static final int initialize = 0; + static final int pIn = 1; + static final int pL = 2; + static final int pR = 3; + static final int pT = 4; + static final int right = 5; + static final int left = 6; + static final int all = 7; + } + + private int getNext_() { + if (!m_interval_tree.m_b_offline_dynamic) + return m_interval_tree.m_secondary_lists.getNext(m_current_end_handle); + + return m_interval_tree.m_secondary_treaps.getNext(m_current_end_handle); + } + + private int getPrev_() { + if (!m_interval_tree.m_b_offline_dynamic) + return m_interval_tree.m_secondary_lists.getPrev(m_current_end_handle); + + return m_interval_tree.m_secondary_treaps.getPrev(m_current_end_handle); + } + + private int getCurrentEndIndex_() { + if (!m_interval_tree.m_b_offline_dynamic) + return m_interval_tree.m_secondary_lists.getData(m_current_end_handle); + + return m_interval_tree.m_secondary_treaps.getElement(m_current_end_handle); + } + + int next() { + if (!m_interval_tree.m_b_construction_ended) + throw new GeometryException("invalid call"); + + if (m_function_index < 0) + return -1; + + boolean b_searching = true; + + while (b_searching) { + switch (m_function_stack[m_function_index]) { + case State.pIn: + b_searching = pIn_(); + break; + case State.pL: + b_searching = pL_(); + break; + case State.pR: + b_searching = pR_(); + break; + case State.pT: + b_searching = pT_(); + break; + case State.right: + b_searching = right_(); + break; + case State.left: + b_searching = left_(); + break; + case State.all: + b_searching = all_(); + break; + case State.initialize: + b_searching = initialize_(); + break; + default: + throw GeometryException.GeometryInternalError(); + } + } + + if (m_current_end_handle != -1) + return getCurrentEndIndex_() >> 1; + + return -1; + } + + private boolean initialize_() { + m_tertiary_handle = -1; + m_next_tertiary_handle = -1; + m_forked_handle = -1; + m_current_end_handle = -1; + + if (m_interval_tree.m_tertiary_nodes != null && m_interval_tree.m_tertiary_nodes.size() > 0) { + m_function_stack[0] = State.pIn; // overwrite initialize + m_next_tertiary_handle = m_interval_tree.m_root; + return true; + } + + m_function_index = -1; + return false; + } + + private boolean pIn_() { + m_tertiary_handle = m_next_tertiary_handle; + + if (m_tertiary_handle == -1) { + m_function_index = -1; + m_current_end_handle = -1; + return false; + } + + double discriminant = m_interval_tree.getDiscriminant_(m_tertiary_handle); + + if (m_query.vmax < discriminant) { + int secondary_handle = m_interval_tree.getSecondaryFromTertiary_(m_tertiary_handle); + m_next_tertiary_handle = m_interval_tree.getLPTR_(m_tertiary_handle); + + if (secondary_handle != -1) { + m_next_end_handle = m_interval_tree.getFirst_(secondary_handle); + m_function_stack[++m_function_index] = State.left; + } + + return true; + } + + if (discriminant < m_query.vmin) { + int secondary_handle = m_interval_tree.getSecondaryFromTertiary_(m_tertiary_handle); + m_next_tertiary_handle = m_interval_tree.getRPTR_(m_tertiary_handle); + + if (secondary_handle != -1) { + m_next_end_handle = m_interval_tree.getLast_(secondary_handle); + m_function_stack[++m_function_index] = State.right; + } + + return true; + } + + assert (m_query.contains(discriminant)); + + m_function_stack[m_function_index] = State.pL; // overwrite pIn + m_forked_handle = m_tertiary_handle; + int secondary_handle = m_interval_tree.getSecondaryFromTertiary_(m_tertiary_handle); + m_next_tertiary_handle = m_interval_tree.getLPTR_(m_tertiary_handle); + + if (secondary_handle != -1) { + m_next_end_handle = m_interval_tree.getFirst_(secondary_handle); + m_function_stack[++m_function_index] = State.all; + } + + return true; + } + + private boolean pL_() { + m_tertiary_handle = m_next_tertiary_handle; + + if (m_tertiary_handle == -1) { + m_function_stack[m_function_index] = State.pR; // overwrite pL + m_next_tertiary_handle = m_interval_tree.getRPTR_(m_forked_handle); + return true; + } - double discriminant = m_interval_tree.getDiscriminant_(m_tertiary_handle); + double discriminant = m_interval_tree.getDiscriminant_(m_tertiary_handle); - if (discriminant < m_query.vmin) { - int secondary_handle = m_interval_tree.getSecondaryFromTertiary_(m_tertiary_handle); - m_next_tertiary_handle = m_interval_tree.getRPTR_(m_tertiary_handle); + if (discriminant < m_query.vmin) { + int secondary_handle = m_interval_tree.getSecondaryFromTertiary_(m_tertiary_handle); + m_next_tertiary_handle = m_interval_tree.getRPTR_(m_tertiary_handle); - if (secondary_handle != -1) { - m_next_end_handle = m_interval_tree.getLast_(secondary_handle); - m_function_stack[++m_function_index] = State.right; - } + if (secondary_handle != -1) { + m_next_end_handle = m_interval_tree.getLast_(secondary_handle); + m_function_stack[++m_function_index] = State.right; + } - return true; - } + return true; + } - assert (m_query.contains(discriminant)); + assert (m_query.contains(discriminant)); - int secondary_handle = m_interval_tree.getSecondaryFromTertiary_(m_tertiary_handle); - m_next_tertiary_handle = m_interval_tree.getLPTR_(m_tertiary_handle); + int secondary_handle = m_interval_tree.getSecondaryFromTertiary_(m_tertiary_handle); + m_next_tertiary_handle = m_interval_tree.getLPTR_(m_tertiary_handle); - if (secondary_handle != -1) { - m_next_end_handle = m_interval_tree.getFirst_(secondary_handle); - m_function_stack[++m_function_index] = State.all; - } + if (secondary_handle != -1) { + m_next_end_handle = m_interval_tree.getFirst_(secondary_handle); + m_function_stack[++m_function_index] = State.all; + } - int rptr = m_interval_tree.getRPTR_(m_tertiary_handle); + int rptr = m_interval_tree.getRPTR_(m_tertiary_handle); - if (rptr != -1) { - m_tertiary_stack.add(rptr); // we'll search this in the pT state - } + if (rptr != -1) { + m_tertiary_stack.add(rptr); // we'll search this in the pT state + } - return true; - } + return true; + } - private boolean pR_() { - m_tertiary_handle = m_next_tertiary_handle; + private boolean pR_() { + m_tertiary_handle = m_next_tertiary_handle; - if (m_tertiary_handle == -1) { - m_function_stack[m_function_index] = State.pT; // overwrite pR - return true; - } + if (m_tertiary_handle == -1) { + m_function_stack[m_function_index] = State.pT; // overwrite pR + return true; + } - double discriminant = m_interval_tree.getDiscriminant_(m_tertiary_handle); + double discriminant = m_interval_tree.getDiscriminant_(m_tertiary_handle); - if (m_query.vmax < discriminant) { - int secondary_handle = m_interval_tree.getSecondaryFromTertiary_(m_tertiary_handle); - m_next_tertiary_handle = m_interval_tree.getLPTR_(m_tertiary_handle); + if (m_query.vmax < discriminant) { + int secondary_handle = m_interval_tree.getSecondaryFromTertiary_(m_tertiary_handle); + m_next_tertiary_handle = m_interval_tree.getLPTR_(m_tertiary_handle); - if (secondary_handle != -1) { - m_next_end_handle = m_interval_tree.getFirst_(secondary_handle); - m_function_stack[++m_function_index] = State.left; - } + if (secondary_handle != -1) { + m_next_end_handle = m_interval_tree.getFirst_(secondary_handle); + m_function_stack[++m_function_index] = State.left; + } - return true; - } + return true; + } - assert (m_query.contains(discriminant)); + assert (m_query.contains(discriminant)); - int secondary_handle = m_interval_tree.getSecondaryFromTertiary_(m_tertiary_handle); + int secondary_handle = m_interval_tree.getSecondaryFromTertiary_(m_tertiary_handle); - m_next_tertiary_handle = m_interval_tree.getRPTR_(m_tertiary_handle); + m_next_tertiary_handle = m_interval_tree.getRPTR_(m_tertiary_handle); - if (secondary_handle != -1) { - m_next_end_handle = m_interval_tree.getFirst_(secondary_handle); - m_function_stack[++m_function_index] = State.all; - } + if (secondary_handle != -1) { + m_next_end_handle = m_interval_tree.getFirst_(secondary_handle); + m_function_stack[++m_function_index] = State.all; + } - int lptr = m_interval_tree.getLPTR_(m_tertiary_handle); + int lptr = m_interval_tree.getLPTR_(m_tertiary_handle); - if (lptr != -1) { - m_tertiary_stack.add(lptr); // we'll search this in the pT state - } + if (lptr != -1) { + m_tertiary_stack.add(lptr); // we'll search this in the pT state + } - return true; - } + return true; + } - private boolean pT_() { - if (m_tertiary_stack.size() == 0) { - m_function_index = -1; - m_current_end_handle = -1; - return false; - } + private boolean pT_() { + if (m_tertiary_stack.size() == 0) { + m_function_index = -1; + m_current_end_handle = -1; + return false; + } - m_tertiary_handle = m_tertiary_stack.get(m_tertiary_stack.size() - 1); - m_tertiary_stack.resize(m_tertiary_stack.size() - 1); + m_tertiary_handle = m_tertiary_stack.get(m_tertiary_stack.size() - 1); + m_tertiary_stack.resize(m_tertiary_stack.size() - 1); - int secondary_handle = m_interval_tree.getSecondaryFromTertiary_(m_tertiary_handle); + int secondary_handle = m_interval_tree.getSecondaryFromTertiary_(m_tertiary_handle); - if (secondary_handle != -1) { - m_next_end_handle = m_interval_tree.getFirst_(secondary_handle); - m_function_stack[++m_function_index] = State.all; - } - - if (m_interval_tree.getLPTR_(m_tertiary_handle) != -1) - m_tertiary_stack.add(m_interval_tree.getLPTR_(m_tertiary_handle)); - - if (m_interval_tree.getRPTR_(m_tertiary_handle) != -1) - m_tertiary_stack.add(m_interval_tree.getRPTR_(m_tertiary_handle)); - - return true; - } - - private boolean left_() { - m_current_end_handle = m_next_end_handle; - - if (m_current_end_handle != -1 && IntervalTreeImpl.isLeft_(getCurrentEndIndex_()) && m_interval_tree.getValue_(getCurrentEndIndex_()) <= m_query.vmax) { - m_next_end_handle = getNext_(); - return false; - } - - m_function_index--; - return true; - } - - private boolean right_() { - m_current_end_handle = m_next_end_handle; - - if (m_current_end_handle != -1 && IntervalTreeImpl.isRight_(getCurrentEndIndex_()) && m_interval_tree.getValue_(getCurrentEndIndex_()) >= m_query.vmin) { - m_next_end_handle = getPrev_(); - return false; - } - - m_function_index--; - return true; - } - - private boolean all_() { - m_current_end_handle = m_next_end_handle; - - if (m_current_end_handle != -1 && IntervalTreeImpl.isLeft_(getCurrentEndIndex_())) { - m_next_end_handle = getNext_(); - return false; - } - - m_function_index--; - return true; - } - - IntervalTreeIteratorImpl(IntervalTreeImpl interval_tree, Envelope1D query, double tolerance) { - m_interval_tree = interval_tree; - m_tertiary_stack.reserve(20); - resetIterator(query, tolerance); - } - - IntervalTreeIteratorImpl(IntervalTreeImpl interval_tree, double query, double tolerance) { - m_interval_tree = interval_tree; - m_tertiary_stack.reserve(20); - resetIterator(query, tolerance); - } - - IntervalTreeIteratorImpl(IntervalTreeImpl interval_tree) { - m_interval_tree = interval_tree; - m_tertiary_stack.reserve(20); - m_function_index = -1; - } - - void resetIterator(Envelope1D query, double tolerance) { - m_query.vmin = query.vmin - tolerance; - m_query.vmax = query.vmax + tolerance; - m_tertiary_stack.resize(0); - m_function_index = 0; - m_function_stack[0] = State.initialize; - } - - void resetIterator(double query_min, double query_max, double tolerance) { - m_query.vmin = query_min - tolerance; - m_query.vmax = query_max + tolerance; - m_tertiary_stack.resize(0); - m_function_index = 0; - m_function_stack[0] = State.initialize; - } - - void resetIterator(double query, double tolerance) { - m_query.vmin = query - tolerance; - m_query.vmax = query + tolerance; - m_tertiary_stack.resize(0); - m_function_index = 0; - m_function_stack[0] = State.initialize; - } - } - - private static final class SecondaryComparator extends Treap.Comparator { - SecondaryComparator(IntervalTreeImpl interval_tree) { - m_interval_tree = interval_tree; - } - - @Override - public int compare(Treap treap, int e_1, int node) { - int e_2 = treap.getElement(node); - double v_1 = m_interval_tree.getValue_(e_1); - double v_2 = m_interval_tree.getValue_(e_2); - - if (v_1 < v_2) - return -1; - if (v_1 == v_2) { - if (isLeft_(e_1) && isRight_(e_2)) - return -1; - if (isLeft_(e_2) && isRight_(e_1)) - return 1; - return 0; - } - return 1; - } - - private IntervalTreeImpl m_interval_tree; - } - - private int createTertiaryNode_(int discriminant_index_1) { - int tertiary_handle = m_tertiary_nodes.newElement(); - setDiscriminantIndex1_(tertiary_handle, discriminant_index_1); - return tertiary_handle; - } - - private int createSecondary_(int tertiary_handle) { - if (!m_b_offline_dynamic) - return m_secondary_lists.createList(tertiary_handle); - - return m_secondary_treaps.createTreap(tertiary_handle); - } - - private int createIntervalNode_() { - return m_interval_nodes.newElement(); - } - - private void setDiscriminantIndex1_(int tertiary_handle, int end_index) { - m_tertiary_nodes.setField(tertiary_handle, 0, end_index); - } - - private void setSecondaryToTertiary_(int tertiary_handle, int secondary_handle) { - m_tertiary_nodes.setField(tertiary_handle, 1, secondary_handle); - } - - private void setLPTR_(int tertiary_handle, int lptr) { - m_tertiary_nodes.setField(tertiary_handle, 2, lptr); - } - - private void setRPTR_(int tertiary_handle, int rptr) { - m_tertiary_nodes.setField(tertiary_handle, 3, rptr); - } - - private void setPPTR_(int tertiary_handle, int pptr) { - m_tertiary_nodes.setField(tertiary_handle, 4, pptr); - } - - private void setSecondaryToInterval_(int interval_handle, int secondary_handle) { - m_interval_nodes.setField(interval_handle, 0, secondary_handle); - } - - private int addEndIndex_(int secondary_handle, int end_index) { - int end_index_handle; - - if (!m_b_offline_dynamic) - end_index_handle = m_secondary_lists.addElement(secondary_handle, end_index); - else - end_index_handle = m_secondary_treaps.addElement(end_index, secondary_handle); - - return end_index_handle; - } - - private void setLeftEnd_(int interval_handle, int left_end_handle) { - m_interval_nodes.setField(interval_handle, 1, left_end_handle); - } - - private void setRightEnd_(int interval_handle, int right_end_handle) { - m_interval_nodes.setField(interval_handle, 2, right_end_handle); - } - - private int getDiscriminantIndex1_(int tertiary_handle) { - return m_tertiary_nodes.getField(tertiary_handle, 0); - } - - private int getSecondaryFromTertiary_(int tertiary_handle) { - return m_tertiary_nodes.getField(tertiary_handle, 1); - } - - private int getLPTR_(int tertiary_handle) { - return m_tertiary_nodes.getField(tertiary_handle, 2); - } - - private int getRPTR_(int tertiary_handle) { - return m_tertiary_nodes.getField(tertiary_handle, 3); - } - - private int getPPTR_(int tertiary_handle) { - return m_tertiary_nodes.getField(tertiary_handle, 4); - } - - private int getSecondaryFromInterval_(int interval_handle) { - return m_interval_nodes.getField(interval_handle, 0); - } - - private int getLeftEnd_(int interval_handle) { - return m_interval_nodes.getField(interval_handle, 1); - } - - private int getRightEnd_(int interval_handle) { - return m_interval_nodes.getField(interval_handle, 2); - } + if (secondary_handle != -1) { + m_next_end_handle = m_interval_tree.getFirst_(secondary_handle); + m_function_stack[++m_function_index] = State.all; + } + + if (m_interval_tree.getLPTR_(m_tertiary_handle) != -1) + m_tertiary_stack.add(m_interval_tree.getLPTR_(m_tertiary_handle)); + + if (m_interval_tree.getRPTR_(m_tertiary_handle) != -1) + m_tertiary_stack.add(m_interval_tree.getRPTR_(m_tertiary_handle)); + + return true; + } + + private boolean left_() { + m_current_end_handle = m_next_end_handle; + + if (m_current_end_handle != -1 && IntervalTreeImpl.isLeft_(getCurrentEndIndex_()) && m_interval_tree.getValue_(getCurrentEndIndex_()) <= m_query.vmax) { + m_next_end_handle = getNext_(); + return false; + } + + m_function_index--; + return true; + } + + private boolean right_() { + m_current_end_handle = m_next_end_handle; + + if (m_current_end_handle != -1 && IntervalTreeImpl.isRight_(getCurrentEndIndex_()) && m_interval_tree.getValue_(getCurrentEndIndex_()) >= m_query.vmin) { + m_next_end_handle = getPrev_(); + return false; + } + + m_function_index--; + return true; + } + + private boolean all_() { + m_current_end_handle = m_next_end_handle; + + if (m_current_end_handle != -1 && IntervalTreeImpl.isLeft_(getCurrentEndIndex_())) { + m_next_end_handle = getNext_(); + return false; + } + + m_function_index--; + return true; + } + + IntervalTreeIteratorImpl(IntervalTreeImpl interval_tree, Envelope1D query, double tolerance) { + m_interval_tree = interval_tree; + m_tertiary_stack.reserve(20); + resetIterator(query, tolerance); + } + + IntervalTreeIteratorImpl(IntervalTreeImpl interval_tree, double query, double tolerance) { + m_interval_tree = interval_tree; + m_tertiary_stack.reserve(20); + resetIterator(query, tolerance); + } + + IntervalTreeIteratorImpl(IntervalTreeImpl interval_tree) { + m_interval_tree = interval_tree; + m_tertiary_stack.reserve(20); + m_function_index = -1; + } + + void resetIterator(Envelope1D query, double tolerance) { + m_query.vmin = query.vmin - tolerance; + m_query.vmax = query.vmax + tolerance; + m_tertiary_stack.resize(0); + m_function_index = 0; + m_function_stack[0] = State.initialize; + } + + void resetIterator(double query_min, double query_max, double tolerance) { + m_query.vmin = query_min - tolerance; + m_query.vmax = query_max + tolerance; + m_tertiary_stack.resize(0); + m_function_index = 0; + m_function_stack[0] = State.initialize; + } + + void resetIterator(double query, double tolerance) { + m_query.vmin = query - tolerance; + m_query.vmax = query + tolerance; + m_tertiary_stack.resize(0); + m_function_index = 0; + m_function_stack[0] = State.initialize; + } + } + + private static final class SecondaryComparator extends Treap.Comparator { + SecondaryComparator(IntervalTreeImpl interval_tree) { + m_interval_tree = interval_tree; + } + + @Override + public int compare(Treap treap, int e_1, int node) { + int e_2 = treap.getElement(node); + double v_1 = m_interval_tree.getValue_(e_1); + double v_2 = m_interval_tree.getValue_(e_2); + + if (v_1 < v_2) + return -1; + if (v_1 == v_2) { + if (isLeft_(e_1) && isRight_(e_2)) + return -1; + if (isLeft_(e_2) && isRight_(e_1)) + return 1; + return 0; + } + return 1; + } + + private IntervalTreeImpl m_interval_tree; + } + + private int createTertiaryNode_(int discriminant_index_1) { + int tertiary_handle = m_tertiary_nodes.newElement(); + setDiscriminantIndex1_(tertiary_handle, discriminant_index_1); + return tertiary_handle; + } + + private int createSecondary_(int tertiary_handle) { + if (!m_b_offline_dynamic) + return m_secondary_lists.createList(tertiary_handle); + + return m_secondary_treaps.createTreap(tertiary_handle); + } + + private int createIntervalNode_() { + return m_interval_nodes.newElement(); + } + + private void setDiscriminantIndex1_(int tertiary_handle, int end_index) { + m_tertiary_nodes.setField(tertiary_handle, 0, end_index); + } + + private void setSecondaryToTertiary_(int tertiary_handle, int secondary_handle) { + m_tertiary_nodes.setField(tertiary_handle, 1, secondary_handle); + } + + private void setLPTR_(int tertiary_handle, int lptr) { + m_tertiary_nodes.setField(tertiary_handle, 2, lptr); + } + + private void setRPTR_(int tertiary_handle, int rptr) { + m_tertiary_nodes.setField(tertiary_handle, 3, rptr); + } + + private void setPPTR_(int tertiary_handle, int pptr) { + m_tertiary_nodes.setField(tertiary_handle, 4, pptr); + } + + private void setSecondaryToInterval_(int interval_handle, int secondary_handle) { + m_interval_nodes.setField(interval_handle, 0, secondary_handle); + } + + private int addEndIndex_(int secondary_handle, int end_index) { + int end_index_handle; + + if (!m_b_offline_dynamic) + end_index_handle = m_secondary_lists.addElement(secondary_handle, end_index); + else + end_index_handle = m_secondary_treaps.addElement(end_index, secondary_handle); + + return end_index_handle; + } + + private void setLeftEnd_(int interval_handle, int left_end_handle) { + m_interval_nodes.setField(interval_handle, 1, left_end_handle); + } + + private void setRightEnd_(int interval_handle, int right_end_handle) { + m_interval_nodes.setField(interval_handle, 2, right_end_handle); + } + + private int getDiscriminantIndex1_(int tertiary_handle) { + return m_tertiary_nodes.getField(tertiary_handle, 0); + } + + private int getSecondaryFromTertiary_(int tertiary_handle) { + return m_tertiary_nodes.getField(tertiary_handle, 1); + } + + private int getLPTR_(int tertiary_handle) { + return m_tertiary_nodes.getField(tertiary_handle, 2); + } + + private int getRPTR_(int tertiary_handle) { + return m_tertiary_nodes.getField(tertiary_handle, 3); + } + + private int getPPTR_(int tertiary_handle) { + return m_tertiary_nodes.getField(tertiary_handle, 4); + } + + private int getSecondaryFromInterval_(int interval_handle) { + return m_interval_nodes.getField(interval_handle, 0); + } + + private int getLeftEnd_(int interval_handle) { + return m_interval_nodes.getField(interval_handle, 1); + } + + private int getRightEnd_(int interval_handle) { + return m_interval_nodes.getField(interval_handle, 2); + } - private double getMin_(int i) { - return (!m_b_envelopes_ref ? m_intervals.get(i).vmin : m_envelopes_ref.get(i).xmin); - } + private double getMin_(int i) { + return (!m_b_envelopes_ref ? m_intervals.get(i).vmin : m_envelopes_ref.get(i).xmin); + } - private double getMax_(int i) { - return (!m_b_envelopes_ref ? m_intervals.get(i).vmax : m_envelopes_ref.get(i).xmax); - } + private double getMax_(int i) { + return (!m_b_envelopes_ref ? m_intervals.get(i).vmax : m_envelopes_ref.get(i).xmax); + } - private int getFirst_(int secondary_handle) { - if (!m_b_offline_dynamic) - return m_secondary_lists.getFirst(secondary_handle); + private int getFirst_(int secondary_handle) { + if (!m_b_offline_dynamic) + return m_secondary_lists.getFirst(secondary_handle); - return m_secondary_treaps.getFirst(secondary_handle); - } + return m_secondary_treaps.getFirst(secondary_handle); + } - private int getLast_(int secondary_handle) { - if (!m_b_offline_dynamic) - return m_secondary_lists.getLast(secondary_handle); + private int getLast_(int secondary_handle) { + if (!m_b_offline_dynamic) + return m_secondary_lists.getLast(secondary_handle); - return m_secondary_treaps.getLast(secondary_handle); - } + return m_secondary_treaps.getLast(secondary_handle); + } - private static boolean isLeft_(int end_index) { - return (end_index & 0x1) == 0; - } + private static boolean isLeft_(int end_index) { + return (end_index & 0x1) == 0; + } - private static boolean isRight_(int end_index) { - return (end_index & 0x1) == 1; - } + private static boolean isRight_(int end_index) { + return (end_index & 0x1) == 1; + } } diff --git a/src/main/java/com/esri/core/geometry/InverseResult.java b/src/main/java/com/esri/core/geometry/InverseResult.java index 760d3b52..4102d9b3 100644 --- a/src/main/java/com/esri/core/geometry/InverseResult.java +++ b/src/main/java/com/esri/core/geometry/InverseResult.java @@ -1,39 +1,39 @@ package com.esri.core.geometry; public class InverseResult { - double az12_rad = 0; - double az21_rad = 0; - double distance_m = 0; + double az12_rad = 0; + double az21_rad = 0; + double distance_m = 0; - public InverseResult(double az12_rad, double az21_rad, double distance_m) { - this.az12_rad = az12_rad; - this.az21_rad = az21_rad; - this.distance_m = distance_m; - } + public InverseResult(double az12_rad, double az21_rad, double distance_m) { + this.az12_rad = az12_rad; + this.az21_rad = az21_rad; + this.distance_m = distance_m; + } - public double getAz12_rad() { - return az12_rad; - } + public double getAz12_rad() { + return az12_rad; + } - public void setAz12_rad(double az12_rad) { - this.az12_rad = az12_rad; - } + public void setAz12_rad(double az12_rad) { + this.az12_rad = az12_rad; + } - public double getAz21_rad() { - return az21_rad; - } + public double getAz21_rad() { + return az21_rad; + } - public void setAz21_rad(double az21_rad) { - this.az21_rad = az21_rad; - } + public void setAz21_rad(double az21_rad) { + this.az21_rad = az21_rad; + } - public double getDistance_m() { - return distance_m; - } + public double getDistance_m() { + return distance_m; + } - public void setDistance_m(double distance_m) { - this.distance_m = distance_m; - } + public void setDistance_m(double distance_m) { + this.distance_m = distance_m; + } } diff --git a/src/main/java/com/esri/core/geometry/JSONUtils.java b/src/main/java/com/esri/core/geometry/JSONUtils.java index 7bbc51fd..14bcf142 100644 --- a/src/main/java/com/esri/core/geometry/JSONUtils.java +++ b/src/main/java/com/esri/core/geometry/JSONUtils.java @@ -25,23 +25,23 @@ final class JSONUtils { - static boolean isObjectStart(JsonReader parser) throws Exception { - return parser.currentToken() == null ? parser.nextToken() == JsonReader.Token.START_OBJECT - : parser.currentToken() == JsonReader.Token.START_OBJECT; - } - - static double readDouble(JsonReader parser) { - if (parser.currentToken() == JsonReader.Token.VALUE_NUMBER_FLOAT) - return parser.currentDoubleValue(); - else if (parser.currentToken() == JsonReader.Token.VALUE_NUMBER_INT) - return parser.currentIntValue(); - else if (parser.currentToken() == JsonReader.Token.VALUE_NULL) - return NumberUtils.NaN(); - else if (parser.currentToken() == JsonReader.Token.VALUE_STRING) - if (parser.currentString().equals("NaN")) - return NumberUtils.NaN(); - - throw new GeometryException("invalid parameter"); - } + static boolean isObjectStart(JsonReader parser) throws Exception { + return parser.currentToken() == null ? parser.nextToken() == JsonReader.Token.START_OBJECT + : parser.currentToken() == JsonReader.Token.START_OBJECT; + } + + static double readDouble(JsonReader parser) { + if (parser.currentToken() == JsonReader.Token.VALUE_NUMBER_FLOAT) + return parser.currentDoubleValue(); + else if (parser.currentToken() == JsonReader.Token.VALUE_NUMBER_INT) + return parser.currentIntValue(); + else if (parser.currentToken() == JsonReader.Token.VALUE_NULL) + return NumberUtils.NaN(); + else if (parser.currentToken() == JsonReader.Token.VALUE_STRING) + if (parser.currentString().equals("NaN")) + return NumberUtils.NaN(); + + throw new GeometryException("invalid parameter"); + } } diff --git a/src/main/java/com/esri/core/geometry/JsonCursor.java b/src/main/java/com/esri/core/geometry/JsonCursor.java index 9d0f7e8e..f4eced5c 100644 --- a/src/main/java/com/esri/core/geometry/JsonCursor.java +++ b/src/main/java/com/esri/core/geometry/JsonCursor.java @@ -28,19 +28,19 @@ */ public abstract class JsonCursor { - /** - * Moves the cursor to the next string. Returns null when reached the end. - */ - public abstract String next(); - - /** - * Returns the ID of the current geometry. The ID is propagated across the - * operations (when possible). - *

- * Returns an ID associated with the current Geometry. The ID is passed - * along and is returned by some operators to preserve relationship between - * the input and output geometry classes. It is not always possible to - * preserve an ID during an operation. - */ - public abstract int getID(); + /** + * Moves the cursor to the next string. Returns null when reached the end. + */ + public abstract String next(); + + /** + * Returns the ID of the current geometry. The ID is propagated across the + * operations (when possible). + *

+ * Returns an ID associated with the current Geometry. The ID is passed + * along and is returned by some operators to preserve relationship between + * the input and output geometry classes. It is not always possible to + * preserve an ID during an operation. + */ + public abstract int getID(); } diff --git a/src/main/java/com/esri/core/geometry/JsonGeometryException.java b/src/main/java/com/esri/core/geometry/JsonGeometryException.java index 75f27a9b..7981a27a 100644 --- a/src/main/java/com/esri/core/geometry/JsonGeometryException.java +++ b/src/main/java/com/esri/core/geometry/JsonGeometryException.java @@ -28,25 +28,25 @@ * A runtime exception raised when a JSON related exception occurs. */ public class JsonGeometryException extends GeometryException { - private static final long serialVersionUID = 1L; - - /** - * Constructs a Json Geometry Exception with the given error string/message. - * - * @param str - The error string. - */ - public JsonGeometryException(String str) { - super(str); - } - - /** - * Constructs a Json Geometry Exception with the given another exception. - * - * @param ex - The exception to copy the message from. - */ - public JsonGeometryException(Exception ex) { - super(ex.getMessage()); - } + private static final long serialVersionUID = 1L; + + /** + * Constructs a Json Geometry Exception with the given error string/message. + * + * @param str - The error string. + */ + public JsonGeometryException(String str) { + super(str); + } + + /** + * Constructs a Json Geometry Exception with the given another exception. + * + * @param ex - The exception to copy the message from. + */ + public JsonGeometryException(Exception ex) { + super(ex.getMessage()); + } } diff --git a/src/main/java/com/esri/core/geometry/JsonParserReader.java b/src/main/java/com/esri/core/geometry/JsonParserReader.java index ce8db6b6..cccef914 100644 --- a/src/main/java/com/esri/core/geometry/JsonParserReader.java +++ b/src/main/java/com/esri/core/geometry/JsonParserReader.java @@ -31,138 +31,138 @@ */ public class JsonParserReader implements JsonReader { - private JsonParser m_jsonParser; - - public JsonParserReader(JsonParser jsonParser) { - m_jsonParser = jsonParser; - } - - /** - * Creates a JsonReader for the string. - * The nextToken is called by this method. - */ - public static JsonReader createFromString(String str) { - try { - JsonFactory factory = new JsonFactory(); - JsonParser jsonParser = factory.createParser(str); - - jsonParser.nextToken(); - return new JsonParserReader(jsonParser); - } catch (Exception ex) { - throw new JsonGeometryException(ex.getMessage()); - } - } - - /** - * Creates a JsonReader for the string. - * The nextToken is not called by this method. - */ - public static JsonReader createFromStringNNT(String str) { - try { - JsonFactory factory = new JsonFactory(); - JsonParser jsonParser = factory.createParser(str); - - return new JsonParserReader(jsonParser); - } catch (Exception ex) { - throw new JsonGeometryException(ex.getMessage()); - } - } - - private static Token mapToken(JsonToken token) { - if (token == JsonToken.END_ARRAY) - return Token.END_ARRAY; - if (token == JsonToken.END_OBJECT) - return Token.END_OBJECT; - if (token == JsonToken.FIELD_NAME) - return Token.FIELD_NAME; - if (token == JsonToken.START_ARRAY) - return Token.START_ARRAY; - if (token == JsonToken.START_OBJECT) - return Token.START_OBJECT; - if (token == JsonToken.VALUE_FALSE) - return Token.VALUE_FALSE; - if (token == JsonToken.VALUE_NULL) - return Token.VALUE_NULL; - if (token == JsonToken.VALUE_NUMBER_FLOAT) - return Token.VALUE_NUMBER_FLOAT; - if (token == JsonToken.VALUE_NUMBER_INT) - return Token.VALUE_NUMBER_INT; - if (token == JsonToken.VALUE_STRING) - return Token.VALUE_STRING; - if (token == JsonToken.VALUE_TRUE) - return Token.VALUE_TRUE; - if (token == null) - return null; - - throw new JsonGeometryException("unexpected token"); - } - - @Override - public Token nextToken() throws JsonGeometryException { - try { - JsonToken token = m_jsonParser.nextToken(); - return mapToken(token); - } catch (Exception ex) { - throw new JsonGeometryException(ex); - } - } - - @Override - public Token currentToken() throws JsonGeometryException { - try { - return mapToken(m_jsonParser.getCurrentToken()); - } catch (Exception ex) { - throw new JsonGeometryException(ex); - } - } - - @Override - public void skipChildren() throws JsonGeometryException { - try { - m_jsonParser.skipChildren(); - } catch (Exception ex) { - throw new JsonGeometryException(ex); - } - - } - - @Override - public String currentString() throws JsonGeometryException { - try { - return m_jsonParser.getText(); - } catch (Exception ex) { - throw new JsonGeometryException(ex); - } - - } - - @Override - public double currentDoubleValue() throws JsonGeometryException { - try { - return m_jsonParser.getValueAsDouble(); - } catch (Exception ex) { - throw new JsonGeometryException(ex); - } - - } - - @Override - public int currentIntValue() throws JsonGeometryException { - try { - return m_jsonParser.getValueAsInt(); - } catch (Exception ex) { - throw new JsonGeometryException(ex); - } - } - - @Override - public boolean currentBooleanValue() { - Token t = currentToken(); - if (t == Token.VALUE_TRUE) - return true; - else if (t == Token.VALUE_FALSE) - return false; - throw new JsonGeometryException("Not a boolean"); - } + private JsonParser m_jsonParser; + + public JsonParserReader(JsonParser jsonParser) { + m_jsonParser = jsonParser; + } + + /** + * Creates a JsonReader for the string. + * The nextToken is called by this method. + */ + public static JsonReader createFromString(String str) { + try { + JsonFactory factory = new JsonFactory(); + JsonParser jsonParser = factory.createParser(str); + + jsonParser.nextToken(); + return new JsonParserReader(jsonParser); + } catch (Exception ex) { + throw new JsonGeometryException(ex.getMessage()); + } + } + + /** + * Creates a JsonReader for the string. + * The nextToken is not called by this method. + */ + public static JsonReader createFromStringNNT(String str) { + try { + JsonFactory factory = new JsonFactory(); + JsonParser jsonParser = factory.createParser(str); + + return new JsonParserReader(jsonParser); + } catch (Exception ex) { + throw new JsonGeometryException(ex.getMessage()); + } + } + + private static Token mapToken(JsonToken token) { + if (token == JsonToken.END_ARRAY) + return Token.END_ARRAY; + if (token == JsonToken.END_OBJECT) + return Token.END_OBJECT; + if (token == JsonToken.FIELD_NAME) + return Token.FIELD_NAME; + if (token == JsonToken.START_ARRAY) + return Token.START_ARRAY; + if (token == JsonToken.START_OBJECT) + return Token.START_OBJECT; + if (token == JsonToken.VALUE_FALSE) + return Token.VALUE_FALSE; + if (token == JsonToken.VALUE_NULL) + return Token.VALUE_NULL; + if (token == JsonToken.VALUE_NUMBER_FLOAT) + return Token.VALUE_NUMBER_FLOAT; + if (token == JsonToken.VALUE_NUMBER_INT) + return Token.VALUE_NUMBER_INT; + if (token == JsonToken.VALUE_STRING) + return Token.VALUE_STRING; + if (token == JsonToken.VALUE_TRUE) + return Token.VALUE_TRUE; + if (token == null) + return null; + + throw new JsonGeometryException("unexpected token"); + } + + @Override + public Token nextToken() throws JsonGeometryException { + try { + JsonToken token = m_jsonParser.nextToken(); + return mapToken(token); + } catch (Exception ex) { + throw new JsonGeometryException(ex); + } + } + + @Override + public Token currentToken() throws JsonGeometryException { + try { + return mapToken(m_jsonParser.getCurrentToken()); + } catch (Exception ex) { + throw new JsonGeometryException(ex); + } + } + + @Override + public void skipChildren() throws JsonGeometryException { + try { + m_jsonParser.skipChildren(); + } catch (Exception ex) { + throw new JsonGeometryException(ex); + } + + } + + @Override + public String currentString() throws JsonGeometryException { + try { + return m_jsonParser.getText(); + } catch (Exception ex) { + throw new JsonGeometryException(ex); + } + + } + + @Override + public double currentDoubleValue() throws JsonGeometryException { + try { + return m_jsonParser.getValueAsDouble(); + } catch (Exception ex) { + throw new JsonGeometryException(ex); + } + + } + + @Override + public int currentIntValue() throws JsonGeometryException { + try { + return m_jsonParser.getValueAsInt(); + } catch (Exception ex) { + throw new JsonGeometryException(ex); + } + } + + @Override + public boolean currentBooleanValue() { + Token t = currentToken(); + if (t == Token.VALUE_TRUE) + return true; + else if (t == Token.VALUE_FALSE) + return false; + throw new JsonGeometryException("Not a boolean"); + } } diff --git a/src/main/java/com/esri/core/geometry/JsonReader.java b/src/main/java/com/esri/core/geometry/JsonReader.java index 00dd3f12..8c1126e9 100644 --- a/src/main/java/com/esri/core/geometry/JsonReader.java +++ b/src/main/java/com/esri/core/geometry/JsonReader.java @@ -29,32 +29,32 @@ * See JsonParserReader for a concrete implementation around JsonParser. */ abstract public interface JsonReader { - public static enum Token { - END_ARRAY, - END_OBJECT, - FIELD_NAME, - START_ARRAY, - START_OBJECT, - VALUE_FALSE, - VALUE_NULL, - VALUE_NUMBER_FLOAT, - VALUE_NUMBER_INT, - VALUE_STRING, - VALUE_TRUE - } + public static enum Token { + END_ARRAY, + END_OBJECT, + FIELD_NAME, + START_ARRAY, + START_OBJECT, + VALUE_FALSE, + VALUE_NULL, + VALUE_NUMBER_FLOAT, + VALUE_NUMBER_INT, + VALUE_STRING, + VALUE_TRUE + } - abstract public Token nextToken() throws JsonGeometryException; + abstract public Token nextToken() throws JsonGeometryException; - abstract public Token currentToken() throws JsonGeometryException; + abstract public Token currentToken() throws JsonGeometryException; - abstract public void skipChildren() throws JsonGeometryException; + abstract public void skipChildren() throws JsonGeometryException; - abstract public String currentString() throws JsonGeometryException; + abstract public String currentString() throws JsonGeometryException; - abstract public double currentDoubleValue() throws JsonGeometryException; + abstract public double currentDoubleValue() throws JsonGeometryException; - abstract public int currentIntValue() throws JsonGeometryException; + abstract public int currentIntValue() throws JsonGeometryException; - abstract public boolean currentBooleanValue() throws JsonGeometryException; + abstract public boolean currentBooleanValue() throws JsonGeometryException; } diff --git a/src/main/java/com/esri/core/geometry/JsonReaderCursor.java b/src/main/java/com/esri/core/geometry/JsonReaderCursor.java index 240e0ce1..c36ebe11 100644 --- a/src/main/java/com/esri/core/geometry/JsonReaderCursor.java +++ b/src/main/java/com/esri/core/geometry/JsonReaderCursor.java @@ -46,26 +46,26 @@ */ abstract class JsonReaderCursor implements Iterator { - /** - * Moves the cursor to the next JsonReader. Returns null when reached the - * end. - */ - public abstract JsonReader next(); - - /** - * Returns the ID of the current geometry. The ID is propagated across the - * operations (when possible). - *

- * Returns an ID associated with the current Geometry. The ID is passed - * along and is returned by some operators to preserve relationship between - * the input and output geometry classes. It is not always possible to - * preserve an ID during an operation. - */ - public abstract int getID(); - - public abstract SimpleStateEnum getSimpleState(); - - public abstract String getFeatureID(); - - public abstract boolean hasNext(); + /** + * Moves the cursor to the next JsonReader. Returns null when reached the + * end. + */ + public abstract JsonReader next(); + + /** + * Returns the ID of the current geometry. The ID is propagated across the + * operations (when possible). + *

+ * Returns an ID associated with the current Geometry. The ID is passed + * along and is returned by some operators to preserve relationship between + * the input and output geometry classes. It is not always possible to + * preserve an ID during an operation. + */ + public abstract int getID(); + + public abstract SimpleStateEnum getSimpleState(); + + public abstract String getFeatureID(); + + public abstract boolean hasNext(); } diff --git a/src/main/java/com/esri/core/geometry/JsonStringWriter.java b/src/main/java/com/esri/core/geometry/JsonStringWriter.java index 4c551d25..36be1445 100644 --- a/src/main/java/com/esri/core/geometry/JsonStringWriter.java +++ b/src/main/java/com/esri/core/geometry/JsonStringWriter.java @@ -25,402 +25,402 @@ final class JsonStringWriter extends JsonWriter { - @Override - Object getJson() { - next_(Action.accept); - return m_jsonString.toString(); - } - - @Override - void startObject() { - next_(Action.addObject); - m_jsonString.append('{'); - m_functionStack.add(State.objectStart); - } - - @Override - void startArray() { - next_(Action.addArray); - m_jsonString.append('['); - m_functionStack.add(State.arrayStart); - } - - @Override - void endObject() { - next_(Action.popObject); - m_jsonString.append('}'); - } - - @Override - void endArray() { - next_(Action.popArray); - m_jsonString.append(']'); - } - - @Override - void addFieldName(String fieldName) { - next_(Action.addKey); - appendQuote_(fieldName); - } - - @Override - void addPairObject(String fieldName) { - next_(Action.addPair); - appendQuote_(fieldName); - m_jsonString.append(":"); - addValueObject_(); - } - - @Override - void addPairArray(String fieldName) { - next_(Action.addPair); - appendQuote_(fieldName); - m_jsonString.append(":"); - addValueArray_(); - } - - @Override - void addPairString(String fieldName, String v) { - next_(Action.addPair); - appendQuote_(fieldName); - m_jsonString.append(":"); - addValueString_(v); - } - - @Override - void addPairDouble(String fieldName, double v) { - next_(Action.addPair); - appendQuote_(fieldName); - m_jsonString.append(":"); - addValueDouble_(v); - } - - @Override - void addPairDouble(String fieldName, double v, int precision, boolean bFixedPoint) { - next_(Action.addPair); - appendQuote_(fieldName); - m_jsonString.append(":"); - addValueDouble_(v, precision, bFixedPoint); - } - - @Override - void addPairInt(String fieldName, int v) { - next_(Action.addPair); - appendQuote_(fieldName); - m_jsonString.append(":"); - addValueInt_(v); - } - - @Override - void addPairBoolean(String fieldName, boolean v) { - next_(Action.addPair); - appendQuote_(fieldName); - m_jsonString.append(":"); - addValueBoolean_(v); - } - - @Override - void addPairNull(String fieldName) { - next_(Action.addPair); - appendQuote_(fieldName); - m_jsonString.append(":"); - addValueNull_(); - } - - @Override - void addValueObject() { - next_(Action.addObject); - addValueObject_(); - } - - @Override - void addValueArray() { - next_(Action.addArray); - addValueArray_(); - } - - @Override - void addValueString(String v) { - next_(Action.addTerminal); - addValueString_(v); - } - - @Override - void addValueDouble(double v) { - next_(Action.addTerminal); - addValueDouble_(v); - } - - @Override - void addValueDouble(double v, int precision, boolean bFixedPoint) { - next_(Action.addTerminal); - addValueDouble_(v, precision, bFixedPoint); - } - - @Override - void addValueInt(int v) { - next_(Action.addTerminal); - addValueInt_(v); - } - - @Override - void addValueBoolean(boolean v) { - next_(Action.addTerminal); - addValueBoolean_(v); - } - - @Override - void addValueNull() { - next_(Action.addTerminal); - addValueNull_(); - } - - JsonStringWriter() { - m_jsonString = new StringBuilder(); - m_functionStack = new AttributeStreamOfInt32(0); - m_functionStack.add(State.accept); - m_functionStack.add(State.start); - } - - private StringBuilder m_jsonString; - private AttributeStreamOfInt32 m_functionStack; - - private void addValueObject_() { - m_jsonString.append('{'); - m_functionStack.add(State.objectStart); - } - - private void addValueArray_() { - m_jsonString.append('['); - m_functionStack.add(State.arrayStart); - } - - private void addValueString_(String v) { - appendQuote_(v); - } - - private void addValueDouble_(double v) { - if (NumberUtils.isNaN(v)) { - addValueNull_(); - return; - } - - StringUtils.appendDouble(v, 17, m_jsonString); - } - - private void addValueDouble_(double v, int precision, boolean bFixedPoint) { - if (NumberUtils.isNaN(v)) { - addValueNull_(); - return; - } - - if (bFixedPoint) - StringUtils.appendDoubleF(v, precision, m_jsonString); - else - StringUtils.appendDouble(v, precision, m_jsonString); - } - - private void addValueInt_(int v) { - m_jsonString.append(v); - } - - private void addValueBoolean_(boolean v) { - if (v) { - m_jsonString.append("true"); - } else { - m_jsonString.append("false"); - } - } - - private void addValueNull_() { - m_jsonString.append("null"); - } - - private void next_(int action) { - switch (m_functionStack.getLast()) { - case State.accept: - accept_(action); - break; - case State.start: - start_(action); - break; - case State.objectStart: - objectStart_(action); - break; - case State.arrayStart: - arrayStart_(action); - break; - case State.pairEnd: - pairEnd_(action); - break; - case State.elementEnd: - elementEnd_(action); - break; - case State.fieldNameEnd: - fieldNameEnd_(action); - break; - default: - throw new GeometryException("internal error"); - } - } - - private void accept_(int action) { - if (action != Action.accept) { - throw new GeometryException("invalid call"); - } - } - - private void start_(int action) { - if ((action & Action.addContainer) != 0) { - m_functionStack.removeLast(); - } else { - throw new GeometryException("invalid call"); - } - } - - private void objectStart_(int action) { - if (action != Action.popObject && action != Action.addPair && action != Action.addKey) - throw new GeometryException("invalid call"); - - m_functionStack.removeLast(); - - if (action == Action.addPair) { - m_functionStack.add(State.pairEnd); - } else if (action == Action.addKey) { - m_functionStack.add(State.pairEnd); - m_functionStack.add(State.fieldNameEnd); - } - } - - private void pairEnd_(int action) { - if (action == Action.addPair) { - m_jsonString.append(','); - } else if (action == Action.addKey) { - m_jsonString.append(','); - m_functionStack.add(State.fieldNameEnd); - } else if (action == Action.popObject) { - m_functionStack.removeLast(); - } else { - throw new GeometryException("invalid call"); - } - } - - private void arrayStart_(int action) { - if ((action & Action.addValue) == 0 && action != Action.popArray) - throw new GeometryException("invalid call"); - - m_functionStack.removeLast(); - - if ((action & Action.addValue) != 0) { - m_functionStack.add(State.elementEnd); - } - } - - private void elementEnd_(int action) { - if ((action & Action.addValue) != 0) { - m_jsonString.append(','); - } else if (action == Action.popArray) { - m_functionStack.removeLast(); - } else { - throw new GeometryException("invalid call"); - } - } - - private void fieldNameEnd_(int action) { - if ((action & Action.addValue) == 0) - throw new GeometryException("invalid call"); - - m_functionStack.removeLast(); - m_jsonString.append(':'); - } - - private void appendQuote_(String string) { - int count = 0; - int start = 0; - int end = string.length(); - - m_jsonString.append('"'); - - for (int i = 0; i < end; i++) { - switch (string.charAt(i)) { - case '"': - if (count > 0) { - m_jsonString.append(string, start, start + count); - count = 0; - } - m_jsonString.append("\\\""); - start = i + 1; - break; - case '\\': - if (count > 0) { - m_jsonString.append(string, start, start + count); - count = 0; - } - m_jsonString.append("\\\\"); - start = i + 1; - break; - case '/': - if (i > 0 && string.charAt(i - 1) == '<') { - if (count > 0) { - m_jsonString.append(string, start, start + count); - count = 0; - } - m_jsonString.append("\\/"); - start = i + 1; - } else { - count++; - } - break; - case '\b': - if (count > 0) { - m_jsonString.append(string, start, start + count); - count = 0; - } - m_jsonString.append("\\b"); - start = i + 1; - break; - case '\f': - if (count > 0) { - m_jsonString.append(string, start, start + count); - count = 0; - } - m_jsonString.append("\\f"); - start = i + 1; - break; - case '\n': - if (count > 0) { - m_jsonString.append(string, start, start + count); - count = 0; - } - m_jsonString.append("\\n"); - start = i + 1; - break; - case '\r': - if (count > 0) { - m_jsonString.append(string, start, start + count); - count = 0; - } - m_jsonString.append("\\r"); - start = i + 1; - break; - case '\t': - if (count > 0) { - m_jsonString.append(string, start, start + count); - count = 0; - } - m_jsonString.append("\\t"); - start = i + 1; - break; - default: - count++; - break; - } - } - - if (count > 0) { - m_jsonString.append(string, start, start + count); - } - - m_jsonString.append('"'); - } + @Override + Object getJson() { + next_(Action.accept); + return m_jsonString.toString(); + } + + @Override + void startObject() { + next_(Action.addObject); + m_jsonString.append('{'); + m_functionStack.add(State.objectStart); + } + + @Override + void startArray() { + next_(Action.addArray); + m_jsonString.append('['); + m_functionStack.add(State.arrayStart); + } + + @Override + void endObject() { + next_(Action.popObject); + m_jsonString.append('}'); + } + + @Override + void endArray() { + next_(Action.popArray); + m_jsonString.append(']'); + } + + @Override + void addFieldName(String fieldName) { + next_(Action.addKey); + appendQuote_(fieldName); + } + + @Override + void addPairObject(String fieldName) { + next_(Action.addPair); + appendQuote_(fieldName); + m_jsonString.append(":"); + addValueObject_(); + } + + @Override + void addPairArray(String fieldName) { + next_(Action.addPair); + appendQuote_(fieldName); + m_jsonString.append(":"); + addValueArray_(); + } + + @Override + void addPairString(String fieldName, String v) { + next_(Action.addPair); + appendQuote_(fieldName); + m_jsonString.append(":"); + addValueString_(v); + } + + @Override + void addPairDouble(String fieldName, double v) { + next_(Action.addPair); + appendQuote_(fieldName); + m_jsonString.append(":"); + addValueDouble_(v); + } + + @Override + void addPairDouble(String fieldName, double v, int precision, boolean bFixedPoint) { + next_(Action.addPair); + appendQuote_(fieldName); + m_jsonString.append(":"); + addValueDouble_(v, precision, bFixedPoint); + } + + @Override + void addPairInt(String fieldName, int v) { + next_(Action.addPair); + appendQuote_(fieldName); + m_jsonString.append(":"); + addValueInt_(v); + } + + @Override + void addPairBoolean(String fieldName, boolean v) { + next_(Action.addPair); + appendQuote_(fieldName); + m_jsonString.append(":"); + addValueBoolean_(v); + } + + @Override + void addPairNull(String fieldName) { + next_(Action.addPair); + appendQuote_(fieldName); + m_jsonString.append(":"); + addValueNull_(); + } + + @Override + void addValueObject() { + next_(Action.addObject); + addValueObject_(); + } + + @Override + void addValueArray() { + next_(Action.addArray); + addValueArray_(); + } + + @Override + void addValueString(String v) { + next_(Action.addTerminal); + addValueString_(v); + } + + @Override + void addValueDouble(double v) { + next_(Action.addTerminal); + addValueDouble_(v); + } + + @Override + void addValueDouble(double v, int precision, boolean bFixedPoint) { + next_(Action.addTerminal); + addValueDouble_(v, precision, bFixedPoint); + } + + @Override + void addValueInt(int v) { + next_(Action.addTerminal); + addValueInt_(v); + } + + @Override + void addValueBoolean(boolean v) { + next_(Action.addTerminal); + addValueBoolean_(v); + } + + @Override + void addValueNull() { + next_(Action.addTerminal); + addValueNull_(); + } + + JsonStringWriter() { + m_jsonString = new StringBuilder(); + m_functionStack = new AttributeStreamOfInt32(0); + m_functionStack.add(State.accept); + m_functionStack.add(State.start); + } + + private StringBuilder m_jsonString; + private AttributeStreamOfInt32 m_functionStack; + + private void addValueObject_() { + m_jsonString.append('{'); + m_functionStack.add(State.objectStart); + } + + private void addValueArray_() { + m_jsonString.append('['); + m_functionStack.add(State.arrayStart); + } + + private void addValueString_(String v) { + appendQuote_(v); + } + + private void addValueDouble_(double v) { + if (NumberUtils.isNaN(v)) { + addValueNull_(); + return; + } + + StringUtils.appendDouble(v, 17, m_jsonString); + } + + private void addValueDouble_(double v, int precision, boolean bFixedPoint) { + if (NumberUtils.isNaN(v)) { + addValueNull_(); + return; + } + + if (bFixedPoint) + StringUtils.appendDoubleF(v, precision, m_jsonString); + else + StringUtils.appendDouble(v, precision, m_jsonString); + } + + private void addValueInt_(int v) { + m_jsonString.append(v); + } + + private void addValueBoolean_(boolean v) { + if (v) { + m_jsonString.append("true"); + } else { + m_jsonString.append("false"); + } + } + + private void addValueNull_() { + m_jsonString.append("null"); + } + + private void next_(int action) { + switch (m_functionStack.getLast()) { + case State.accept: + accept_(action); + break; + case State.start: + start_(action); + break; + case State.objectStart: + objectStart_(action); + break; + case State.arrayStart: + arrayStart_(action); + break; + case State.pairEnd: + pairEnd_(action); + break; + case State.elementEnd: + elementEnd_(action); + break; + case State.fieldNameEnd: + fieldNameEnd_(action); + break; + default: + throw new GeometryException("internal error"); + } + } + + private void accept_(int action) { + if (action != Action.accept) { + throw new GeometryException("invalid call"); + } + } + + private void start_(int action) { + if ((action & Action.addContainer) != 0) { + m_functionStack.removeLast(); + } else { + throw new GeometryException("invalid call"); + } + } + + private void objectStart_(int action) { + if (action != Action.popObject && action != Action.addPair && action != Action.addKey) + throw new GeometryException("invalid call"); + + m_functionStack.removeLast(); + + if (action == Action.addPair) { + m_functionStack.add(State.pairEnd); + } else if (action == Action.addKey) { + m_functionStack.add(State.pairEnd); + m_functionStack.add(State.fieldNameEnd); + } + } + + private void pairEnd_(int action) { + if (action == Action.addPair) { + m_jsonString.append(','); + } else if (action == Action.addKey) { + m_jsonString.append(','); + m_functionStack.add(State.fieldNameEnd); + } else if (action == Action.popObject) { + m_functionStack.removeLast(); + } else { + throw new GeometryException("invalid call"); + } + } + + private void arrayStart_(int action) { + if ((action & Action.addValue) == 0 && action != Action.popArray) + throw new GeometryException("invalid call"); + + m_functionStack.removeLast(); + + if ((action & Action.addValue) != 0) { + m_functionStack.add(State.elementEnd); + } + } + + private void elementEnd_(int action) { + if ((action & Action.addValue) != 0) { + m_jsonString.append(','); + } else if (action == Action.popArray) { + m_functionStack.removeLast(); + } else { + throw new GeometryException("invalid call"); + } + } + + private void fieldNameEnd_(int action) { + if ((action & Action.addValue) == 0) + throw new GeometryException("invalid call"); + + m_functionStack.removeLast(); + m_jsonString.append(':'); + } + + private void appendQuote_(String string) { + int count = 0; + int start = 0; + int end = string.length(); + + m_jsonString.append('"'); + + for (int i = 0; i < end; i++) { + switch (string.charAt(i)) { + case '"': + if (count > 0) { + m_jsonString.append(string, start, start + count); + count = 0; + } + m_jsonString.append("\\\""); + start = i + 1; + break; + case '\\': + if (count > 0) { + m_jsonString.append(string, start, start + count); + count = 0; + } + m_jsonString.append("\\\\"); + start = i + 1; + break; + case '/': + if (i > 0 && string.charAt(i - 1) == '<') { + if (count > 0) { + m_jsonString.append(string, start, start + count); + count = 0; + } + m_jsonString.append("\\/"); + start = i + 1; + } else { + count++; + } + break; + case '\b': + if (count > 0) { + m_jsonString.append(string, start, start + count); + count = 0; + } + m_jsonString.append("\\b"); + start = i + 1; + break; + case '\f': + if (count > 0) { + m_jsonString.append(string, start, start + count); + count = 0; + } + m_jsonString.append("\\f"); + start = i + 1; + break; + case '\n': + if (count > 0) { + m_jsonString.append(string, start, start + count); + count = 0; + } + m_jsonString.append("\\n"); + start = i + 1; + break; + case '\r': + if (count > 0) { + m_jsonString.append(string, start, start + count); + count = 0; + } + m_jsonString.append("\\r"); + start = i + 1; + break; + case '\t': + if (count > 0) { + m_jsonString.append(string, start, start + count); + count = 0; + } + m_jsonString.append("\\t"); + start = i + 1; + break; + default: + count++; + break; + } + } + + if (count > 0) { + m_jsonString.append(string, start, start + count); + } + + m_jsonString.append('"'); + } } diff --git a/src/main/java/com/esri/core/geometry/JsonWriter.java b/src/main/java/com/esri/core/geometry/JsonWriter.java index 0013cfcc..095f50e1 100644 --- a/src/main/java/com/esri/core/geometry/JsonWriter.java +++ b/src/main/java/com/esri/core/geometry/JsonWriter.java @@ -25,72 +25,72 @@ abstract class JsonWriter { - abstract Object getJson(); + abstract Object getJson(); - abstract void startObject(); + abstract void startObject(); - abstract void startArray(); + abstract void startArray(); - abstract void endObject(); + abstract void endObject(); - abstract void endArray(); + abstract void endArray(); - abstract void addFieldName(String fieldName); + abstract void addFieldName(String fieldName); - abstract void addPairObject(String fieldName); + abstract void addPairObject(String fieldName); - abstract void addPairArray(String fieldName); + abstract void addPairArray(String fieldName); - abstract void addPairString(String fieldName, String v); + abstract void addPairString(String fieldName, String v); - abstract void addPairDouble(String fieldName, double v); + abstract void addPairDouble(String fieldName, double v); - abstract void addPairDouble(String fieldName, double v, int precision, boolean bFixedPoint); + abstract void addPairDouble(String fieldName, double v, int precision, boolean bFixedPoint); - abstract void addPairInt(String fieldName, int v); + abstract void addPairInt(String fieldName, int v); - abstract void addPairBoolean(String fieldName, boolean v); + abstract void addPairBoolean(String fieldName, boolean v); - abstract void addPairNull(String fieldName); + abstract void addPairNull(String fieldName); - abstract void addValueObject(); + abstract void addValueObject(); - abstract void addValueArray(); + abstract void addValueArray(); - abstract void addValueString(String v); + abstract void addValueString(String v); - abstract void addValueDouble(double v); + abstract void addValueDouble(double v); - abstract void addValueDouble(double v, int precision, boolean bFixedPoint); + abstract void addValueDouble(double v, int precision, boolean bFixedPoint); - abstract void addValueInt(int v); + abstract void addValueInt(int v); - abstract void addValueBoolean(boolean v); + abstract void addValueBoolean(boolean v); - abstract void addValueNull(); + abstract void addValueNull(); - protected interface Action { + protected interface Action { - static final int accept = 0; - static final int addObject = 1; - static final int addArray = 2; - static final int popObject = 4; - static final int popArray = 8; - static final int addKey = 16; - static final int addTerminal = 32; - static final int addPair = 64; - static final int addContainer = addObject | addArray; - static final int addValue = addContainer | addTerminal; - } + static final int accept = 0; + static final int addObject = 1; + static final int addArray = 2; + static final int popObject = 4; + static final int popArray = 8; + static final int addKey = 16; + static final int addTerminal = 32; + static final int addPair = 64; + static final int addContainer = addObject | addArray; + static final int addValue = addContainer | addTerminal; + } - protected interface State { + protected interface State { - static final int accept = 0; - static final int start = 1; - static final int objectStart = 2; - static final int arrayStart = 3; - static final int pairEnd = 4; - static final int elementEnd = 5; - static final int fieldNameEnd = 6; - } + static final int accept = 0; + static final int start = 1; + static final int objectStart = 2; + static final int arrayStart = 3; + static final int pairEnd = 4; + static final int elementEnd = 5; + static final int fieldNameEnd = 6; + } } diff --git a/src/main/java/com/esri/core/geometry/Line.java b/src/main/java/com/esri/core/geometry/Line.java index 4c717691..ce7b7b23 100644 --- a/src/main/java/com/esri/core/geometry/Line.java +++ b/src/main/java/com/esri/core/geometry/Line.java @@ -33,13 +33,14 @@ /** * A straight line between a pair of points. + * */ public final class Line extends Segment implements Serializable { - @Override - public Geometry.Type getType() { - return Type.Line; - } + @Override + public Geometry.Type getType() { + return Type.Line; + } @Override public long estimateMemorySize() @@ -54,966 +55,970 @@ public double calculateLength2D() { return Math.sqrt(dx * dx + dy * dy); } - @Override - boolean isDegenerate(double tolerance) { - double dx = m_xStart - m_xEnd; - double dy = m_yStart - m_yEnd; - return Math.sqrt(dx * dx + dy * dy) <= tolerance; - } - - /** - * Indicates if the line segment is a curve. - */ - @Override - public boolean isCurve() { - return false; - } - - @Override - Point2D _getTangent(double t) { - Point2D pt = new Point2D(); - pt.sub(getEndXY(), getStartXY()); - return pt; - } + @Override + boolean isDegenerate(double tolerance) { + double dx = m_xStart - m_xEnd; + double dy = m_yStart - m_yEnd; + return Math.sqrt(dx * dx + dy * dy) <= tolerance; + } - @Override - boolean _isDegenerate(double tolerance) { - return calculateLength2D() <= tolerance; - } + /** + * Indicates if the line segment is a curve. + */ + @Override + public boolean isCurve() { + return false; + } - // HEADER DEF + @Override + Point2D _getTangent(double t) { + Point2D pt = new Point2D(); + pt.sub(getEndXY(), getStartXY()); + return pt; + } - // Cpp + @Override + boolean _isDegenerate(double tolerance) { + return calculateLength2D() <= tolerance; + } - /** - * Creates a line segment. - */ - public Line() { - m_description = VertexDescriptionDesignerImpl.getDefaultDescriptor2D(); - } + // HEADER DEF - Line(VertexDescription vd) { - m_description = vd; - } + // Cpp + /** + * Creates a line segment. + */ + public Line() { + m_description = VertexDescriptionDesignerImpl.getDefaultDescriptor2D(); + } - public Line(double x1, double y1, double x2, double y2) { - m_description = VertexDescriptionDesignerImpl.getDefaultDescriptor2D(); - setStartXY(x1, y1); - setEndXY(x2, y2); - } + Line(VertexDescription vd) { + m_description = vd; + } - @Override - public void queryEnvelope(Envelope env) { - env.setEmpty(); - env.assignVertexDescription(m_description); - Envelope2D env2D = new Envelope2D(); - queryEnvelope2D(env2D); - env.setEnvelope2D(env2D); - - for (int i = 1, n = m_description.getAttributeCount(); i < n; i++) { - int semantics = m_description.getSemantics(i); - for (int iord = 0, nord = VertexDescription - .getComponentCount(semantics); i < nord; i++) { - Envelope1D interval = queryInterval(semantics, iord); - env.setInterval(semantics, iord, interval); - } - } - } + public Line(double x1, double y1, double x2, double y2) { + m_description = VertexDescriptionDesignerImpl.getDefaultDescriptor2D(); + setStartXY(x1, y1); + setEndXY(x2, y2); + } - @Override - public void queryEnvelope2D(Envelope2D env) { - env.setCoords(m_xStart, m_yStart, m_xEnd, m_yEnd); - env.normalize(); - } + @Override + public void queryEnvelope(Envelope env) { + env.setEmpty(); + env.assignVertexDescription(m_description); + Envelope2D env2D = new Envelope2D(); + queryEnvelope2D(env2D); + env.setEnvelope2D(env2D); + + for (int i = 1, n = m_description.getAttributeCount(); i < n; i++) { + int semantics = m_description.getSemantics(i); + for (int iord = 0, nord = VertexDescription + .getComponentCount(semantics); i < nord; i++) { + Envelope1D interval = queryInterval(semantics, iord); + env.setInterval(semantics, iord, interval); + } + } + } - @Override - void queryEnvelope3D(Envelope3D env) { - env.setEmpty(); - env.merge(m_xStart, m_yStart, _getAttributeAsDbl(0, Semantics.Z, 0)); - env.merge(m_xEnd, m_yEnd, _getAttributeAsDbl(1, Semantics.Z, 0)); - } + @Override + public void queryEnvelope2D(Envelope2D env) { + env.setCoords(m_xStart, m_yStart, m_xEnd, m_yEnd); + env.normalize(); + } - @Override - public void applyTransformation(Transformation2D transform) { - _touch(); - Point2D pt = new Point2D(); - pt.x = m_xStart; - pt.y = m_yStart; - transform.transform(pt, pt); - m_xStart = pt.x; - m_yStart = pt.y; - pt.x = m_xEnd; - pt.y = m_yEnd; - transform.transform(pt, pt); - m_xEnd = pt.x; - m_yEnd = pt.y; - } + @Override + void queryEnvelope3D(Envelope3D env) { + env.setEmpty(); + env.merge(m_xStart, m_yStart, _getAttributeAsDbl(0, Semantics.Z, 0)); + env.merge(m_xEnd, m_yEnd, _getAttributeAsDbl(1, Semantics.Z, 0)); + } - @Override - void applyTransformation(Transformation3D transform) { - _touch(); - Point3D pt = new Point3D(); - pt.x = m_xStart; - pt.y = m_yStart; - pt.z = _getAttributeAsDbl(0, Semantics.Z, 0); - pt = transform.transform(pt); - m_xStart = pt.x; - m_yStart = pt.y; - _setAttribute(0, Semantics.Z, 0, pt.z); - pt.x = m_xEnd; - pt.y = m_yEnd; - pt.z = _getAttributeAsDbl(1, Semantics.Z, 0); - pt = transform.transform(pt); - m_xEnd = pt.x; - m_yEnd = pt.y; - _setAttribute(1, Semantics.Z, 0, pt.z); - } + @Override + public void applyTransformation(Transformation2D transform) { + _touch(); + Point2D pt = new Point2D(); + pt.x = m_xStart; + pt.y = m_yStart; + transform.transform(pt, pt); + m_xStart = pt.x; + m_yStart = pt.y; + pt.x = m_xEnd; + pt.y = m_yEnd; + transform.transform(pt, pt); + m_xEnd = pt.x; + m_yEnd = pt.y; + } - @Override - public Geometry createInstance() { - return new Line(m_description); - } + @Override + void applyTransformation(Transformation3D transform) { + _touch(); + Point3D pt = new Point3D(); + pt.x = m_xStart; + pt.y = m_yStart; + pt.z = _getAttributeAsDbl(0, Semantics.Z, 0); + pt = transform.transform(pt); + m_xStart = pt.x; + m_yStart = pt.y; + _setAttribute(0, Semantics.Z, 0, pt.z); + pt.x = m_xEnd; + pt.y = m_yEnd; + pt.z = _getAttributeAsDbl(1, Semantics.Z, 0); + pt = transform.transform(pt); + m_xEnd = pt.x; + m_yEnd = pt.y; + _setAttribute(1, Semantics.Z, 0, pt.z); + } - @Override - double _calculateArea2DHelper(double xorg, double yorg) { - return ((m_xEnd - xorg) - (m_xStart - xorg)) - * ((m_yEnd - yorg) + (m_yStart - yorg)) * 0.5; - } + @Override + public Geometry createInstance() { + return new Line(m_description); + } - @Override - double tToLength(double t) { - return t * calculateLength2D(); - } + @Override + double _calculateArea2DHelper(double xorg, double yorg) { + return ((m_xEnd - xorg) - (m_xStart - xorg)) + * ((m_yEnd - yorg) + (m_yStart - yorg)) * 0.5; + } - @Override - double lengthToT(double len) { - return len / calculateLength2D(); - } + @Override + double tToLength(double t) { + return t * calculateLength2D(); + } - double getCoordX_(double t) { - // Must match query_coord_2D and vice verse - // Also match get_attribute_as_dbl - return MathUtils.lerp(m_xStart, m_xEnd, t); - } + @Override + double lengthToT(double len) { + return len / calculateLength2D(); + } - double getCoordY_(double t) { - // Must match query_coord_2D and vice verse - // Also match get_attribute_as_dbl - return MathUtils.lerp(m_yStart, m_yEnd, t); - } + double getCoordX_(double t) { + // Must match query_coord_2D and vice verse + // Also match get_attribute_as_dbl + return MathUtils.lerp(m_xStart, m_xEnd, t); + } - @Override - public void getCoord2D(double t, Point2D pt) { - // We want: - // 1. When t == 0, get exactly Start - // 2. When t == 1, get exactly End - // 3. When m_x_end == m_x_start, we want m_x_start exactly - // 4. When m_y_end == m_y_start, we want m_y_start exactly - MathUtils.lerp(m_xStart, m_yStart, m_xEnd, m_yEnd, t, pt); - } + double getCoordY_(double t) { + // Must match query_coord_2D and vice verse + // Also match get_attribute_as_dbl + return MathUtils.lerp(m_yStart, m_yEnd, t); + } - @Override - public Segment cut(double t1, double t2) { - SegmentBuffer segmentBuffer = new SegmentBuffer(); - cut(t1, t2, segmentBuffer); - return segmentBuffer.get(); - } + @Override + public void getCoord2D(double t, Point2D pt) { + // We want: + // 1. When t == 0, get exactly Start + // 2. When t == 1, get exactly End + // 3. When m_x_end == m_x_start, we want m_x_start exactly + // 4. When m_y_end == m_y_start, we want m_y_start exactly + MathUtils.lerp(m_xStart, m_yStart, m_xEnd, m_yEnd, t, pt); + } - @Override - void cut(double t1, double t2, SegmentBuffer subSegmentBuffer) { - if (subSegmentBuffer == null) - throw new IllegalArgumentException(); - - subSegmentBuffer.createLine();// Make sure buffer contains Line class. - Segment subSegment = subSegmentBuffer.get(); - subSegment.assignVertexDescription(m_description); - - Point2D point = new Point2D(); - getCoord2D(t1, point); - subSegment.setStartXY(point.x, point.y); - getCoord2D(t2, point); - subSegment.setEndXY(point.x, point.y); - - for (int iattr = 1, nattr = m_description.getAttributeCount(); iattr < nattr; iattr++) { - int semantics = m_description._getSemanticsImpl(iattr); - int ncomps = VertexDescription.getComponentCount(semantics); - - for (int ordinate = 0; ordinate < ncomps; ordinate++) { - double value1 = getAttributeAsDbl(t1, semantics, ordinate); - subSegment.setStartAttribute(semantics, ordinate, value1); - - double value2 = getAttributeAsDbl(t2, semantics, ordinate); - subSegment.setEndAttribute(semantics, ordinate, value2); - } - } - } + @Override + public Segment cut(double t1, double t2) { + SegmentBuffer segmentBuffer = new SegmentBuffer(); + cut(t1, t2, segmentBuffer); + return segmentBuffer.get(); + } - @Override - public double getAttributeAsDbl(double t, int semantics, int ordinate) { - if (semantics == VertexDescription.Semantics.POSITION) - return ordinate == 0 ? getCoord2D(t).x : getCoord2D(t).y; - - int interpolation = VertexDescription.getInterpolation(semantics); - switch (interpolation) { - case VertexDescription.Interpolation.NONE: - if (t < 0.5) - return getStartAttributeAsDbl(semantics, ordinate); - else - return getEndAttributeAsDbl(semantics, ordinate); - case VertexDescription.Interpolation.LINEAR: { - double s = getStartAttributeAsDbl(semantics, ordinate); - double e = getEndAttributeAsDbl(semantics, ordinate); - return MathUtils.lerp(s, e, t); - } - case VertexDescription.Interpolation.ANGULAR: { - throw new GeometryException("not implemented"); - } - } - - throw GeometryException.GeometryInternalError(); - } + @Override + void cut(double t1, double t2, SegmentBuffer subSegmentBuffer) { + if (subSegmentBuffer == null) + throw new IllegalArgumentException(); + + subSegmentBuffer.createLine();// Make sure buffer contains Line class. + Segment subSegment = subSegmentBuffer.get(); + subSegment.assignVertexDescription(m_description); + + Point2D point = new Point2D(); + getCoord2D(t1, point); + subSegment.setStartXY(point.x, point.y); + getCoord2D(t2, point); + subSegment.setEndXY(point.x, point.y); + + for (int iattr = 1, nattr = m_description.getAttributeCount(); iattr < nattr; iattr++) { + int semantics = m_description._getSemanticsImpl(iattr); + int ncomps = VertexDescription.getComponentCount(semantics); + + for (int ordinate = 0; ordinate < ncomps; ordinate++) { + double value1 = getAttributeAsDbl(t1, semantics, ordinate); + subSegment.setStartAttribute(semantics, ordinate, value1); + + double value2 = getAttributeAsDbl(t2, semantics, ordinate); + subSegment.setEndAttribute(semantics, ordinate, value2); + } + } + } - @Override - public double getClosestCoordinate(Point2D inputPt, boolean bExtrapolate) { - double vx = m_xEnd - m_xStart; - double vy = m_yEnd - m_yStart; - double v2 = vx * vx + vy * vy; - if (v2 == 0) - return 0.5; - double rx = inputPt.x - m_xStart; - double ry = inputPt.y - m_yStart; - double t = (rx * vx + ry * vy) / v2; - if (!bExtrapolate) { - if (t < 0.0) - t = 0.0; - else if (t > 1.0) - t = 1.0; - } - - return t; - } + @Override + public double getAttributeAsDbl(double t, int semantics, int ordinate) { + if (semantics == VertexDescription.Semantics.POSITION) + return ordinate == 0 ? getCoord2D(t).x : getCoord2D(t).y; + + int interpolation = VertexDescription.getInterpolation(semantics); + switch (interpolation) { + case VertexDescription.Interpolation.NONE: + if (t < 0.5) + return getStartAttributeAsDbl(semantics, ordinate); + else + return getEndAttributeAsDbl(semantics, ordinate); + case VertexDescription.Interpolation.LINEAR: { + double s = getStartAttributeAsDbl(semantics, ordinate); + double e = getEndAttributeAsDbl(semantics, ordinate); + return MathUtils.lerp(s, e, t); + } + case VertexDescription.Interpolation.ANGULAR: { + throw new GeometryException("not implemented"); + } + } + + throw GeometryException.GeometryInternalError(); + } - @Override - public int intersectionWithAxis2D(boolean b_axis_x, double ordinate, - double[] result_ordinates, double[] parameters) { - if (b_axis_x) { - double a = (m_yEnd - m_yStart); + @Override + public double getClosestCoordinate(Point2D inputPt, boolean bExtrapolate) { + double vx = m_xEnd - m_xStart; + double vy = m_yEnd - m_yStart; + double v2 = vx * vx + vy * vy; + if (v2 == 0) + return 0.5; + double rx = inputPt.x - m_xStart; + double ry = inputPt.y - m_yStart; + double t = (rx * vx + ry * vy) / v2; + if (!bExtrapolate) { + if (t < 0.0) + t = 0.0; + else if (t > 1.0) + t = 1.0; + } + + return t; + } - if (a == 0) - return (ordinate == m_yEnd) ? -1 : 0; + @Override + public int intersectionWithAxis2D(boolean b_axis_x, double ordinate, + double[] result_ordinates, double[] parameters) { + if (b_axis_x) { + double a = (m_yEnd - m_yStart); - double t = (ordinate - m_yStart) / a; + if (a == 0) + return (ordinate == m_yEnd) ? -1 : 0; - if (t < 0.0 || t > 1.0) - return 0; + double t = (ordinate - m_yStart) / a; - if (result_ordinates != null) - (result_ordinates)[0] = getCoordX_(t); + if (t < 0.0 || t > 1.0) + return 0; - if (parameters != null) - (parameters)[0] = t; + if (result_ordinates != null) + (result_ordinates)[0] = getCoordX_(t); - return 1; - } else { - double a = (m_xEnd - m_xStart); + if (parameters != null) + (parameters)[0] = t; - if (a == 0) - return (ordinate == m_xEnd) ? -1 : 0; + return 1; + } else { + double a = (m_xEnd - m_xStart); - double t = (ordinate - m_xStart) / a; + if (a == 0) + return (ordinate == m_xEnd) ? -1 : 0; - if (t < 0.0 || t > 1.0) - return 0; + double t = (ordinate - m_xStart) / a; - if (result_ordinates != null) - (result_ordinates)[0] = getCoordY_(t); + if (t < 0.0 || t > 1.0) + return 0; - if (parameters != null) - (parameters)[0] = t; + if (result_ordinates != null) + (result_ordinates)[0] = getCoordY_(t); - return 1; - } - } + if (parameters != null) + (parameters)[0] = t; - // line segment can have 0 or 1 intersection interval with clipEnv2D. - // The function return 0 or 2 segParams (e.g. 0.0, 0.4; or 0.1, 0.9; or 0.6, - // 1.0; or 0.0, 1.0) - // segParams will be sorted in ascending order; the order of the - // envelopeDistances will correspond (i.e. the envelopeDistances may not be - // in ascending order); - // an envelopeDistance can be -1.0 if the corresponding endpoint is properly - // inside clipEnv2D. - int intersectionWithEnvelope2D(Envelope2D clipEnv2D, - boolean includeEnvBoundary, double[] segParams, - double[] envelopeDistances) { - Point2D p1 = getStartXY(); - Point2D p2 = getEndXY(); - - // includeEnvBoundary xxx ??? - - int modified = clipEnv2D.clipLine(p1, p2, 0, segParams, - envelopeDistances); - return modified != 0 ? 2 : 0; + return 1; + } + } - } + // line segment can have 0 or 1 intersection interval with clipEnv2D. + // The function return 0 or 2 segParams (e.g. 0.0, 0.4; or 0.1, 0.9; or 0.6, + // 1.0; or 0.0, 1.0) + // segParams will be sorted in ascending order; the order of the + // envelopeDistances will correspond (i.e. the envelopeDistances may not be + // in ascending order); + // an envelopeDistance can be -1.0 if the corresponding endpoint is properly + // inside clipEnv2D. + int intersectionWithEnvelope2D(Envelope2D clipEnv2D, + boolean includeEnvBoundary, double[] segParams, + double[] envelopeDistances) { + Point2D p1 = getStartXY(); + Point2D p2 = getEndXY(); + + // includeEnvBoundary xxx ??? + + int modified = clipEnv2D.clipLine(p1, p2, 0, segParams, + envelopeDistances); + return modified != 0 ? 2 : 0; - @Override - double intersectionOfYMonotonicWithAxisX(double y, double x_parallel) { - double a = (m_yEnd - m_yStart); - - if (a == 0) - return (y == m_yEnd) ? x_parallel : NumberUtils.NaN(); - - double t = (y - m_yStart) / a; - assert (t >= 0 && t <= 1.0); - // double t_1 = 1.0 - t; - // assert(t + t_1 == 1.0); - double resx = getCoordX_(t); - if (t == 1.0) - resx = m_xEnd; - assert ((resx >= m_xStart && resx <= m_xEnd) || (resx <= m_xStart && resx >= m_xEnd)); - return resx; - } + } - @Override - boolean _isIntersectingPoint(Point2D pt, double tolerance, - boolean bExcludeExactEndpoints) { - return _intersection(pt, tolerance, bExcludeExactEndpoints) >= 0;// must - // use - // same - // method - // that - // the - // intersection - // routine - // uses. - } + @Override + double intersectionOfYMonotonicWithAxisX(double y, double x_parallel) { + double a = (m_yEnd - m_yStart); + + if (a == 0) + return (y == m_yEnd) ? x_parallel : NumberUtils.NaN(); + + double t = (y - m_yStart) / a; + assert (t >= 0 && t <= 1.0); + // double t_1 = 1.0 - t; + // assert(t + t_1 == 1.0); + double resx = getCoordX_(t); + if (t == 1.0) + resx = m_xEnd; + assert ((resx >= m_xStart && resx <= m_xEnd) || (resx <= m_xStart && resx >= m_xEnd)); + return resx; + } - /** - * Returns True if point and the segment intersect (not disjoint) for the - * given tolerance. - */ - @Override - public boolean isIntersecting(Point2D pt, double tolerance) { - return _isIntersectingPoint(pt, tolerance, false); - } + @Override + boolean _isIntersectingPoint(Point2D pt, double tolerance, + boolean bExcludeExactEndpoints) { + return _intersection(pt, tolerance, bExcludeExactEndpoints) >= 0;// must + // use + // same + // method + // that + // the + // intersection + // routine + // uses. + } - void orientBottomUp_() { - if (m_yEnd < m_yStart || (m_yEnd == m_yStart && m_xEnd < m_xStart)) { - double x = m_xStart; - m_xStart = m_xEnd; - m_xEnd = x; - - double y = m_yStart; - m_yStart = m_yEnd; - m_yEnd = y; - for (int i = 0, n = m_description.getTotalComponentCount() - 2; i < n; i++) { - double a = m_attributes[i]; - m_attributes[i] = m_attributes[i + n]; - m_attributes[i + n] = a; - } - } - } + /** + * Returns True if point and the segment intersect (not disjoint) for the + * given tolerance. + */ + @Override + public boolean isIntersecting(Point2D pt, double tolerance) { + return _isIntersectingPoint(pt, tolerance, false); + } - // return -1 for the left side from the infinite line passing through thais - // Line, 1 for the right side of the line, 0 if on the line (in the bounds - // of the roundoff error) - int _side(Point2D pt) { - return _side(pt.x, pt.y); - } + void orientBottomUp_() { + if (m_yEnd < m_yStart || (m_yEnd == m_yStart && m_xEnd < m_xStart)) { + double x = m_xStart; + m_xStart = m_xEnd; + m_xEnd = x; + + double y = m_yStart; + m_yStart = m_yEnd; + m_yEnd = y; + for (int i = 0, n = m_description.getTotalComponentCount() - 2; i < n; i++) { + double a = m_attributes[i]; + m_attributes[i] = m_attributes[i + n]; + m_attributes[i + n] = a; + } + } + } - // return -1 for the left side from the infinite line passing through thais - // Line, 1 for the right side of the line, 0 if on the line (in the bounds - // of the roundoff error) - int _side(double ptX, double ptY) { - Point2D v1 = new Point2D(ptX, ptY); - v1.sub(getStartXY()); - Point2D v2 = new Point2D(); - v2.sub(getEndXY(), getStartXY()); - double cross = v2.crossProduct(v1); - double crossError = 4 * NumberUtils.doubleEps() - * (Math.abs(v2.x * v1.y) + Math.abs(v2.y * v1.x)); - return cross > crossError ? -1 : cross < -crossError ? 1 : 0; - } + // return -1 for the left side from the infinite line passing through thais + // Line, 1 for the right side of the line, 0 if on the line (in the bounds + // of the roundoff error) + int _side(Point2D pt) { + return _side(pt.x, pt.y); + } - double _intersection(Point2D pt, double tolerance, - boolean bExcludeExactEndPoints) { - Point2D v = new Point2D(); - Point2D start = new Point2D(); - - // Test start point distance to pt. - start.setCoords(m_xStart, m_yStart); - v.sub(pt, start); - double vlength = v.length(); - double vLengthError = vlength * 3 * NumberUtils.doubleEps(); - if (vlength <= Math.max(tolerance, vLengthError)) { - assert (vlength != 0 || pt.isEqual(start));// probably never asserts - if (bExcludeExactEndPoints && vlength == 0) - return NumberUtils.TheNaN; - else - return 0; - } - - Point2D end2D = getEndXY(); - // Test end point distance to pt. - v.sub(pt, end2D); - vlength = v.length(); - vLengthError = vlength * 3 * NumberUtils.doubleEps(); - if (vlength <= Math.max(tolerance, vLengthError)) { - assert (vlength != 0 || pt.isEqual(end2D));// probably never asserts - if (bExcludeExactEndPoints && vlength == 0) - return NumberUtils.TheNaN; - else - return 1.0; - } - - // Find a distance from the line to pt. - v.setCoords(m_xEnd - m_xStart, m_yEnd - m_yStart); - double len = v.length(); - if (len > 0) { - double invertedLength = 1.0 / len; - v.scale(invertedLength); - Point2D relativePoint = new Point2D(); - relativePoint.sub(pt, start); - double projection = relativePoint.dotProduct(v); - double projectionError = 8 * relativePoint._dotProductAbs(v) - * NumberUtils.doubleEps();// See Error Estimation Rules In - // Borg.docx - v.leftPerpendicular();// get left normal to v - double distance = relativePoint.dotProduct(v); - double distanceError = 8 * relativePoint._dotProductAbs(v) - * NumberUtils.doubleEps();// See Error Estimation Rules In - // Borg.docx - - double perror = Math.max(tolerance, projectionError); - if (projection < -perror || projection > len + perror) - return NumberUtils.TheNaN; - - double merror = Math.max(tolerance, distanceError); - if (Math.abs(distance) <= merror) { - double t = projection * invertedLength; - t = NumberUtils.snap(t, 0.0, 1.0); - Point2D ptOnLine = new Point2D(); - getCoord2D(t, ptOnLine); - if (Point2D.distance(ptOnLine, pt) <= tolerance) { - if (t < 0.5) { - if (Point2D.distance(ptOnLine, start) <= tolerance)// the - // projected - // point - // is - // close - // to - // the - // start - // point. - // Need - // to - // return - // 0. - return 0; - } else if (Point2D.distance(ptOnLine, end2D) <= tolerance)// the - // projected - // point - // is - // close - // to - // the - // end - // point. - // Need - // to - // return - // 1.0. - return 1.0; - - return t; - } - } - } - - return NumberUtils.TheNaN; - } + // return -1 for the left side from the infinite line passing through thais + // Line, 1 for the right side of the line, 0 if on the line (in the bounds + // of the roundoff error) + int _side(double ptX, double ptY) { + Point2D v1 = new Point2D(ptX, ptY); + v1.sub(getStartXY()); + Point2D v2 = new Point2D(); + v2.sub(getEndXY(), getStartXY()); + double cross = v2.crossProduct(v1); + double crossError = 4 * NumberUtils.doubleEps() + * (Math.abs(v2.x * v1.y) + Math.abs(v2.y * v1.x)); + return cross > crossError ? -1 : cross < -crossError ? 1 : 0; + } - @Override - public boolean equals(Object other) { - if (other == null) - return false; + double _intersection(Point2D pt, double tolerance, + boolean bExcludeExactEndPoints) { + Point2D v = new Point2D(); + Point2D start = new Point2D(); + + // Test start point distance to pt. + start.setCoords(m_xStart, m_yStart); + v.sub(pt, start); + double vlength = v.length(); + double vLengthError = vlength * 3 * NumberUtils.doubleEps(); + if (vlength <= Math.max(tolerance, vLengthError)) { + assert (vlength != 0 || pt.isEqual(start));// probably never asserts + if (bExcludeExactEndPoints && vlength == 0) + return NumberUtils.TheNaN; + else + return 0; + } + + Point2D end2D = getEndXY(); + // Test end point distance to pt. + v.sub(pt, end2D); + vlength = v.length(); + vLengthError = vlength * 3 * NumberUtils.doubleEps(); + if (vlength <= Math.max(tolerance, vLengthError)) { + assert (vlength != 0 || pt.isEqual(end2D));// probably never asserts + if (bExcludeExactEndPoints && vlength == 0) + return NumberUtils.TheNaN; + else + return 1.0; + } + + // Find a distance from the line to pt. + v.setCoords(m_xEnd - m_xStart, m_yEnd - m_yStart); + double len = v.length(); + if (len > 0) { + double invertedLength = 1.0 / len; + v.scale(invertedLength); + Point2D relativePoint = new Point2D(); + relativePoint.sub(pt, start); + double projection = relativePoint.dotProduct(v); + double projectionError = 8 * relativePoint._dotProductAbs(v) + * NumberUtils.doubleEps();// See Error Estimation Rules In + // Borg.docx + v.leftPerpendicular();// get left normal to v + double distance = relativePoint.dotProduct(v); + double distanceError = 8 * relativePoint._dotProductAbs(v) + * NumberUtils.doubleEps();// See Error Estimation Rules In + // Borg.docx + + double perror = Math.max(tolerance, projectionError); + if (projection < -perror || projection > len + perror) + return NumberUtils.TheNaN; + + double merror = Math.max(tolerance, distanceError); + if (Math.abs(distance) <= merror) { + double t = projection * invertedLength; + t = NumberUtils.snap(t, 0.0, 1.0); + Point2D ptOnLine = new Point2D(); + getCoord2D(t, ptOnLine); + if (Point2D.distance(ptOnLine, pt) <= tolerance) { + if (t < 0.5) { + if (Point2D.distance(ptOnLine, start) <= tolerance)// the + // projected + // point + // is + // close + // to + // the + // start + // point. + // Need + // to + // return + // 0. + return 0; + } else if (Point2D.distance(ptOnLine, end2D) <= tolerance)// the + // projected + // point + // is + // close + // to + // the + // end + // point. + // Need + // to + // return + // 1.0. + return 1.0; + + return t; + } + } + } + + return NumberUtils.TheNaN; + } - if (other == this) - return true; + @Override + public boolean equals(Object other) { + if (other == null) + return false; - if (other.getClass() != getClass()) - return false; + if (other == this) + return true; - return _equalsImpl((Segment) other); - } + if (other.getClass() != getClass()) + return false; - boolean equals(Line other) { - if (other == this) - return true; + return _equalsImpl((Segment)other); + } + + @Override + public int hashCode() { + return super.hashCode(); + } - if (!(other instanceof Line)) - return false; + boolean equals(Line other) { + if (other == this) + return true; - return _equalsImpl((Segment) other); - } + if (!(other instanceof Line)) + return false; - boolean _projectionIntersectHelper(Line other, Point2D v, boolean bStart) { - // v is the vector in the direction of this line == end - start. - double orgX = bStart ? m_xStart : m_xEnd; - double orgY = bStart ? m_yStart : m_yEnd; - Point2D m = new Point2D(); - m.x = other.getEndX() - orgX; - m.y = other.getEndY() - orgY; - double dot = v.dotProduct(m); - double dotError = 3 * NumberUtils.doubleEps() * v._dotProductAbs(m); - if (dot > dotError) { - m.x = other.getStartX() - orgX; - m.y = other.getStartY() - orgY; - double dot2 = v.dotProduct(m); - double dotError2 = 3 * NumberUtils.doubleEps() - * v._dotProductAbs(m); - return dot2 <= dotError2; - } - - return true; - } + return _equalsImpl((Segment) other); + } - boolean _projectionIntersect(Line other) { - // This function returns true, if the "other"'s projection on "this" - Point2D v = new Point2D(); - v.x = m_xEnd - m_xStart; - v.y = m_yEnd - m_yStart; - if (!_projectionIntersectHelper(other, v, false)) - return false; // Both other.Start and other.End projections on - // "this" lie to the right of the this.End - - v.negate(); - if (!_projectionIntersectHelper(other, v, true)) - return false; // Both other.Start and other.End projections on - // "this" lie to the left of the this.End - - return true; - } + boolean _projectionIntersectHelper(Line other, Point2D v, boolean bStart) { + // v is the vector in the direction of this line == end - start. + double orgX = bStart ? m_xStart : m_xEnd; + double orgY = bStart ? m_yStart : m_yEnd; + Point2D m = new Point2D(); + m.x = other.getEndX() - orgX; + m.y = other.getEndY() - orgY; + double dot = v.dotProduct(m); + double dotError = 3 * NumberUtils.doubleEps() * v._dotProductAbs(m); + if (dot > dotError) { + m.x = other.getStartX() - orgX; + m.y = other.getStartY() - orgY; + double dot2 = v.dotProduct(m); + double dotError2 = 3 * NumberUtils.doubleEps() + * v._dotProductAbs(m); + return dot2 <= dotError2; + } + + return true; + } - // Tests if two lines intersect using projection of one line to another. - static boolean _isIntersectingHelper(Line line1, Line line2) { - int s11 = line1._side(line2.m_xStart, line2.m_yStart); - int s12 = line1._side(line2.m_xEnd, line2.m_yEnd); - if (s11 < 0 && s12 < 0 || s11 > 0 && s12 > 0) - return false;// no intersection. The line2 lies to one side of an - // infinite line passing through line1 - - int s21 = line2._side(line1.m_xStart, line1.m_yStart); - int s22 = line2._side(line1.m_xEnd, line1.m_yEnd); - if (s21 < 0 && s22 < 0 || s21 > 0 && s22 > 0) - return false;// no intersection.The line1 lies to one side of an - // infinite line passing through line2 - - double len1 = line1.calculateLength2D(); - double len2 = line2.calculateLength2D(); - if (len1 > len2) { - return line1._projectionIntersect(line2); - } else { - return line2._projectionIntersect(line1); - } - } + boolean _projectionIntersect(Line other) { + // This function returns true, if the "other"'s projection on "this" + Point2D v = new Point2D(); + v.x = m_xEnd - m_xStart; + v.y = m_yEnd - m_yStart; + if (!_projectionIntersectHelper(other, v, false)) + return false; // Both other.Start and other.End projections on + // "this" lie to the right of the this.End + + v.negate(); + if (!_projectionIntersectHelper(other, v, true)) + return false; // Both other.Start and other.End projections on + // "this" lie to the left of the this.End + + return true; + } - static Point2D _intersectHelper1(Line line1, Line line2, double tolerance) { - Point2D result = new Point2D(NumberUtils.NaN(), NumberUtils.NaN()); - double k1x = line1.m_xEnd - line1.m_xStart; - double k1y = line1.m_yEnd - line1.m_yStart; - double k2x = line2.m_xEnd - line2.m_xStart; - double k2y = line2.m_yEnd - line2.m_yStart; - - double det = k2x * k1y - k1x * k2y; - if (det == 0) - return result; - - // estimate roundoff error for det: - double errdet = 4 * NumberUtils.doubleEps() - * (Math.abs(k2x * k1y) + Math.abs(k1x * k2y)); - - double bx = line2.m_xStart - line1.m_xStart; - double by = line2.m_yStart - line1.m_yStart; - - double a0 = (k2x * by - bx * k2y); - double a0error = 4 * NumberUtils.doubleEps() - * (Math.abs(k2x * by) + Math.abs(bx * k2y)); - double t0 = a0 / det; - double absdet = Math.abs(det); - double t0error = (a0error * absdet + errdet * Math.abs(a0)) - / (det * det) + NumberUtils.doubleEps() * Math.abs(t0); - if (t0 < -t0error || t0 > 1.0 + t0error) - return result; - - double a1 = (k1x * by - bx * k1y); - double a1error = 4 * NumberUtils.doubleEps() - * (Math.abs(k1x * by) + Math.abs(bx * k1y)); - double t1 = a1 / det; - double t1error = (a1error * absdet + errdet * Math.abs(a1)) - / (det * det) + NumberUtils.doubleEps() * Math.abs(t1); - - if (t1 < -t1error || t1 > 1.0 + t1error) - return result; - - double t0r = NumberUtils.snap(t0, 0.0, 1.0); - double t1r = NumberUtils.snap(t1, 0.0, 1.0); - Point2D pt0 = line1.getCoord2D(t0r); - Point2D pt1 = line2.getCoord2D(t1r); - Point2D pt = new Point2D(); - pt.sub(pt0, pt1); - if (pt.length() > tolerance) { - // Roundoff errors cause imprecise result. Try recalculate. - // 1. Use averaged point and recalculate the t values - // Point2D pt; - pt.add(pt0, pt1); - pt.scale(0.5); - t0r = line1.getClosestCoordinate(pt, false); - t1r = line2.getClosestCoordinate(pt, false); - Point2D pt01 = line1.getCoord2D(t0r); - Point2D pt11 = line2.getCoord2D(t1r); - pt01.sub(pt11); - if (pt01.length() > tolerance) { - // Seems to be no intersection here actually. Return NaNs - return result; - } - } - - result.setCoords(t0r, t1r); - return result; - } + // Tests if two lines intersect using projection of one line to another. + static boolean _isIntersectingHelper(Line line1, Line line2) { + int s11 = line1._side(line2.m_xStart, line2.m_yStart); + int s12 = line1._side(line2.m_xEnd, line2.m_yEnd); + if (s11 < 0 && s12 < 0 || s11 > 0 && s12 > 0) + return false;// no intersection. The line2 lies to one side of an + // infinite line passing through line1 + + int s21 = line2._side(line1.m_xStart, line1.m_yStart); + int s22 = line2._side(line1.m_xEnd, line1.m_yEnd); + if (s21 < 0 && s22 < 0 || s21 > 0 && s22 > 0) + return false;// no intersection.The line1 lies to one side of an + // infinite line passing through line2 + + double len1 = line1.calculateLength2D(); + double len2 = line2.calculateLength2D(); + if (len1 > len2) { + return line1._projectionIntersect(line2); + } else { + return line2._projectionIntersect(line1); + } + } - static int _isIntersectingLineLine(Line line1, Line line2, - double tolerance, boolean bExcludeExactEndpoints) { - // _ASSERT(line1 != line2); - // Check for the endpoints. - // The bExcludeExactEndpoints is True, means we care only about overlaps - // and real intersections, but do not care if the endpoints are exactly - // equal. - // bExcludeExactEndpoints is used in Cracking check test, because during - // cracking test all points are either coincident or further than the - // tolerance. - int counter = 0; - if (line1.m_xStart == line2.m_xStart - && line1.m_yStart == line2.m_yStart - || line1.m_xStart == line2.m_xEnd - && line1.m_yStart == line2.m_yEnd) { - counter++; - if (!bExcludeExactEndpoints) - return 1; - } - - if (line1.m_xEnd == line2.m_xStart && line1.m_yEnd == line2.m_yStart - || line1.m_xEnd == line2.m_xEnd && line1.m_yEnd == line2.m_yEnd) { - counter++; - if (counter == 2) - return 2; // counter == 2 means both endpoints coincide (Lines - // overlap). - if (!bExcludeExactEndpoints) - return 1; - } - - if (line2._isIntersectingPoint(line1.getStartXY(), tolerance, true)) - return 1;// return true; - if (line2._isIntersectingPoint(line1.getEndXY(), tolerance, true)) - return 1;// return true; - if (line1._isIntersectingPoint(line2.getStartXY(), tolerance, true)) - return 1;// return true; - if (line1._isIntersectingPoint(line2.getEndXY(), tolerance, true)) - return 1;// return true; - - if (bExcludeExactEndpoints && (counter != 0)) - return 0;// return false; - - return _isIntersectingHelper(line1, line2) == false ? 0 : 1; - } + static Point2D _intersectHelper1(Line line1, Line line2, double tolerance) { + Point2D result = new Point2D(NumberUtils.NaN(), NumberUtils.NaN()); + double k1x = line1.m_xEnd - line1.m_xStart; + double k1y = line1.m_yEnd - line1.m_yStart; + double k2x = line2.m_xEnd - line2.m_xStart; + double k2y = line2.m_yEnd - line2.m_yStart; + + double det = k2x * k1y - k1x * k2y; + if (det == 0) + return result; + + // estimate roundoff error for det: + double errdet = 4 * NumberUtils.doubleEps() + * (Math.abs(k2x * k1y) + Math.abs(k1x * k2y)); + + double bx = line2.m_xStart - line1.m_xStart; + double by = line2.m_yStart - line1.m_yStart; + + double a0 = (k2x * by - bx * k2y); + double a0error = 4 * NumberUtils.doubleEps() + * (Math.abs(k2x * by) + Math.abs(bx * k2y)); + double t0 = a0 / det; + double absdet = Math.abs(det); + double t0error = (a0error * absdet + errdet * Math.abs(a0)) + / (det * det) + NumberUtils.doubleEps() * Math.abs(t0); + if (t0 < -t0error || t0 > 1.0 + t0error) + return result; + + double a1 = (k1x * by - bx * k1y); + double a1error = 4 * NumberUtils.doubleEps() + * (Math.abs(k1x * by) + Math.abs(bx * k1y)); + double t1 = a1 / det; + double t1error = (a1error * absdet + errdet * Math.abs(a1)) + / (det * det) + NumberUtils.doubleEps() * Math.abs(t1); + + if (t1 < -t1error || t1 > 1.0 + t1error) + return result; + + double t0r = NumberUtils.snap(t0, 0.0, 1.0); + double t1r = NumberUtils.snap(t1, 0.0, 1.0); + Point2D pt0 = line1.getCoord2D(t0r); + Point2D pt1 = line2.getCoord2D(t1r); + Point2D pt = new Point2D(); + pt.sub(pt0, pt1); + if (pt.length() > tolerance) { + // Roundoff errors cause imprecise result. Try recalculate. + // 1. Use averaged point and recalculate the t values + // Point2D pt; + pt.add(pt0, pt1); + pt.scale(0.5); + t0r = line1.getClosestCoordinate(pt, false); + t1r = line2.getClosestCoordinate(pt, false); + Point2D pt01 = line1.getCoord2D(t0r); + Point2D pt11 = line2.getCoord2D(t1r); + pt01.sub(pt11); + if (pt01.length() > tolerance) { + // Seems to be no intersection here actually. Return NaNs + return result; + } + } + + result.setCoords(t0r, t1r); + return result; + } - int _intersectLineLineExact(Line line1, Line line2, - Point2D[] intersectionPoints, double[] param1, double[] param2) { - int counter = 0; - if (line1.m_xStart == line2.m_xStart - && line1.m_yStart == line2.m_yStart) { - if (param1 != null)// if (param1) - param1[counter] = 0.0; - if (param2 != null)// if (param2) - param2[counter] = 0.0; - - if (intersectionPoints != null)// if (intersectionPoints) - intersectionPoints[counter] = Point2D.construct(line1.m_xStart, - line1.m_yStart); - - counter++; - } - - if (line1.m_xStart == line2.m_xEnd && line1.m_yStart == line2.m_yEnd) { - if (param1 != null)// if (param1) - param1[counter] = 0.0; - if (param2 != null)// if (param2) - param2[counter] = 1.0; - - if (intersectionPoints != null)// if (intersectionPoints) - intersectionPoints[counter] = Point2D.construct(line1.m_xStart, - line1.m_yStart); - - counter++; - } - - if (line1.m_xEnd == line2.m_xStart && line1.m_yEnd == line2.m_yStart) { - if (counter == 2) {// both segments a degenerate - if (param1 != null)// if (param1) - { - param1[0] = 0.0; - param1[1] = 1.0; - } - if (param2 != null)// if (param2) - { - param2[0] = 1.0; - } - - if (intersectionPoints != null)// if (intersectionPoints) - { - intersectionPoints[0] = Point2D.construct(line1.m_xEnd, - line1.m_yEnd); - intersectionPoints[1] = Point2D.construct(line1.m_xEnd, - line1.m_yEnd); - } - - return counter; - } - - if (param1 != null)// if (param1) - param1[counter] = 1.0; - if (param2 != null)// if (param2) - param2[counter] = 0.0; - - if (intersectionPoints != null)// if (intersectionPoints) - intersectionPoints[counter] = Point2D.construct(line1.m_xEnd, - line1.m_yEnd); - - counter++; - } - - if (line1.m_xEnd == line2.m_xEnd && line1.m_yEnd == line2.m_yEnd) { - if (counter == 2) {// both segments are degenerate - if (param1 != null)// if (param1) - { - param1[0] = 0.0; - param1[1] = 1.0; - } - if (param2 != null)// if (param2) - { - param2[0] = 1.0; - } - - if (intersectionPoints != null)// if (intersectionPoints) - { - intersectionPoints[0] = Point2D.construct(line1.m_xEnd, - line1.m_yEnd); - intersectionPoints[1] = Point2D.construct(line1.m_xEnd, - line1.m_yEnd); - } - - return counter; - } - - if (param1 != null)// if (param1) - param1[counter] = 1.0; - if (param2 != null)// if (param2) - param2[counter] = 1.0; - - if (intersectionPoints != null)// if (intersectionPoints) - intersectionPoints[counter] = Point2D.construct(line1.m_xEnd, - line1.m_yEnd); - counter++; - } - - return counter; - } + static int _isIntersectingLineLine(Line line1, Line line2, + double tolerance, boolean bExcludeExactEndpoints) { + // _ASSERT(line1 != line2); + // Check for the endpoints. + // The bExcludeExactEndpoints is True, means we care only about overlaps + // and real intersections, but do not care if the endpoints are exactly + // equal. + // bExcludeExactEndpoints is used in Cracking check test, because during + // cracking test all points are either coincident or further than the + // tolerance. + int counter = 0; + if (line1.m_xStart == line2.m_xStart + && line1.m_yStart == line2.m_yStart + || line1.m_xStart == line2.m_xEnd + && line1.m_yStart == line2.m_yEnd) { + counter++; + if (!bExcludeExactEndpoints) + return 1; + } + + if (line1.m_xEnd == line2.m_xStart && line1.m_yEnd == line2.m_yStart + || line1.m_xEnd == line2.m_xEnd && line1.m_yEnd == line2.m_yEnd) { + counter++; + if (counter == 2) + return 2; // counter == 2 means both endpoints coincide (Lines + // overlap). + if (!bExcludeExactEndpoints) + return 1; + } + + if (line2._isIntersectingPoint(line1.getStartXY(), tolerance, true)) + return 1;// return true; + if (line2._isIntersectingPoint(line1.getEndXY(), tolerance, true)) + return 1;// return true; + if (line1._isIntersectingPoint(line2.getStartXY(), tolerance, true)) + return 1;// return true; + if (line1._isIntersectingPoint(line2.getEndXY(), tolerance, true)) + return 1;// return true; + + if (bExcludeExactEndpoints && (counter != 0)) + return 0;// return false; + + return _isIntersectingHelper(line1, line2) == false ? 0 : 1; + } - static int _intersectLineLine(Line line1, Line line2, - Point2D[] intersectionPoints, double[] param1, double[] param2, - double tolerance) { - // _ASSERT(!param1 && !param2 || param1); - int counter = 0; - // Test the end points for exact coincidence. - double t11 = line1._intersection(line2.getStartXY(), tolerance, false); - double t12 = line1._intersection(line2.getEndXY(), tolerance, false); - double t21 = line2._intersection(line1.getStartXY(), tolerance, false); - double t22 = line2._intersection(line1.getEndXY(), tolerance, false); - - if (!NumberUtils.isNaN(t11)) { - if (param1 != null)// if (param1) - param1[counter] = t11; - if (param2 != null)// if (param2) - param2[counter] = 0; - - if (intersectionPoints != null)// if (intersectionPoints) - intersectionPoints[counter] = Point2D.construct(line2.m_xStart, - line2.m_yStart); - counter++; - } - - if (!NumberUtils.isNaN(t12)) { - if (param1 != null)// if (param1) - param1[counter] = t12; - if (param2 != null)// if (param2) - param2[counter] = 1.0; - - if (intersectionPoints != null)// if (intersectionPoints) - intersectionPoints[counter] = Point2D.construct(line2.m_xEnd, - line2.m_yEnd); - counter++; - } - - if (counter != 2 && !NumberUtils.isNaN(t21)) { - if (!(t11 == 0 && t21 == 0) && !(t12 == 0 && t21 == 1.0))// the "if" - // makes - // sure - // this - // has - // not - // been - // already - // calculated - { - if (param1 != null)// if (param1) - param1[counter] = 0; - if (param2 != null)// if (param2) - param2[counter] = t21; - - if (intersectionPoints != null)// if (intersectionPoints) - intersectionPoints[counter] = Point2D.construct( - line1.m_xStart, line1.m_yStart); - counter++; - } - } - - if (counter != 2 && !NumberUtils.isNaN(t22)) { - if (!(t11 == 1.0 && t22 == 0) && !(t12 == 1.0 && t22 == 1.0))// the - // "if" - // makes - // sure - // this - // has - // not - // been - // already - // calculated - { - if (param1 != null)// if (param1) - param1[counter] = 1.0; - if (param2 != null)// if (param2) - param2[counter] = t22; - - if (intersectionPoints != null)// if (intersectionPoints) - intersectionPoints[counter] = Point2D.construct( - line2.m_xEnd, line2.m_yEnd); - counter++; - } - } - - if (counter > 0) { - if (counter == 2 && param1 != null && param1[0] > param1[1]) {// make - // sure - // the - // intersection - // events - // are - // sorted - // along - // the - // line1 - // can't - // swap - // doulbes - // in - // java - // NumberUtils::Swap(param1[0], - // param1[1]); - double zeroParam1 = param1[0]; - param1[0] = param1[1]; - param1[1] = zeroParam1; - - if (param2 != null)// if (param2) - { - double zeroParam2 = param2[0]; - param2[0] = param2[1]; - param2[1] = zeroParam2;// NumberUtils::Swap(ARRAYELEMENT(param2, - // 0), ARRAYELEMENT(param2, 1)); - } - - if (intersectionPoints != null)// if (intersectionPoints) - { - Point2D tmp = new Point2D(intersectionPoints[0].x, - intersectionPoints[0].y); - intersectionPoints[0] = intersectionPoints[1]; - intersectionPoints[1] = tmp; - } - } - - return counter; - } - - Point2D params = _intersectHelper1(line1, line2, tolerance); - if (NumberUtils.isNaN(params.x)) - return 0; - - if (intersectionPoints != null)// if (intersectionPoints) - { - intersectionPoints[0] = line1.getCoord2D(params.x); - } - - if (param1 != null)// if (param1) - { - param1[0] = params.x; - } - - if (param2 != null)// if (param2) - { - param2[0] = params.y; - } - - return 1; - } + int _intersectLineLineExact(Line line1, Line line2, + Point2D[] intersectionPoints, double[] param1, double[] param2) { + int counter = 0; + if (line1.m_xStart == line2.m_xStart + && line1.m_yStart == line2.m_yStart) { + if (param1 != null)// if (param1) + param1[counter] = 0.0; + if (param2 != null)// if (param2) + param2[counter] = 0.0; + + if (intersectionPoints != null)// if (intersectionPoints) + intersectionPoints[counter] = Point2D.construct(line1.m_xStart, + line1.m_yStart); + + counter++; + } + + if (line1.m_xStart == line2.m_xEnd && line1.m_yStart == line2.m_yEnd) { + if (param1 != null)// if (param1) + param1[counter] = 0.0; + if (param2 != null)// if (param2) + param2[counter] = 1.0; + + if (intersectionPoints != null)// if (intersectionPoints) + intersectionPoints[counter] = Point2D.construct(line1.m_xStart, + line1.m_yStart); + + counter++; + } + + if (line1.m_xEnd == line2.m_xStart && line1.m_yEnd == line2.m_yStart) { + if (counter == 2) {// both segments a degenerate + if (param1 != null)// if (param1) + { + param1[0] = 0.0; + param1[1] = 1.0; + } + if (param2 != null)// if (param2) + { + param2[0] = 1.0; + } + + if (intersectionPoints != null)// if (intersectionPoints) + { + intersectionPoints[0] = Point2D.construct(line1.m_xEnd, + line1.m_yEnd); + intersectionPoints[1] = Point2D.construct(line1.m_xEnd, + line1.m_yEnd); + } + + return counter; + } + + if (param1 != null)// if (param1) + param1[counter] = 1.0; + if (param2 != null)// if (param2) + param2[counter] = 0.0; + + if (intersectionPoints != null)// if (intersectionPoints) + intersectionPoints[counter] = Point2D.construct(line1.m_xEnd, + line1.m_yEnd); + + counter++; + } + + if (line1.m_xEnd == line2.m_xEnd && line1.m_yEnd == line2.m_yEnd) { + if (counter == 2) {// both segments are degenerate + if (param1 != null)// if (param1) + { + param1[0] = 0.0; + param1[1] = 1.0; + } + if (param2 != null)// if (param2) + { + param2[0] = 1.0; + } + + if (intersectionPoints != null)// if (intersectionPoints) + { + intersectionPoints[0] = Point2D.construct(line1.m_xEnd, + line1.m_yEnd); + intersectionPoints[1] = Point2D.construct(line1.m_xEnd, + line1.m_yEnd); + } + + return counter; + } + + if (param1 != null)// if (param1) + param1[counter] = 1.0; + if (param2 != null)// if (param2) + param2[counter] = 1.0; + + if (intersectionPoints != null)// if (intersectionPoints) + intersectionPoints[counter] = Point2D.construct(line1.m_xEnd, + line1.m_yEnd); + counter++; + } + + return counter; + } + static int _intersectLineLine(Line line1, Line line2, + Point2D[] intersectionPoints, double[] param1, double[] param2, + double tolerance) { + // _ASSERT(!param1 && !param2 || param1); + int counter = 0; + // Test the end points for exact coincidence. + double t11 = line1._intersection(line2.getStartXY(), tolerance, false); + double t12 = line1._intersection(line2.getEndXY(), tolerance, false); + double t21 = line2._intersection(line1.getStartXY(), tolerance, false); + double t22 = line2._intersection(line1.getEndXY(), tolerance, false); + + if (!NumberUtils.isNaN(t11)) { + if (param1 != null)// if (param1) + param1[counter] = t11; + if (param2 != null)// if (param2) + param2[counter] = 0; + + if (intersectionPoints != null)// if (intersectionPoints) + intersectionPoints[counter] = Point2D.construct(line2.m_xStart, + line2.m_yStart); + counter++; + } + + if (!NumberUtils.isNaN(t12)) { + if (param1 != null)// if (param1) + param1[counter] = t12; + if (param2 != null)// if (param2) + param2[counter] = 1.0; + + if (intersectionPoints != null)// if (intersectionPoints) + intersectionPoints[counter] = Point2D.construct(line2.m_xEnd, + line2.m_yEnd); + counter++; + } + + if (counter != 2 && !NumberUtils.isNaN(t21)) { + if (!(t11 == 0 && t21 == 0) && !(t12 == 0 && t21 == 1.0))// the "if" + // makes + // sure + // this + // has + // not + // been + // already + // calculated + { + if (param1 != null)// if (param1) + param1[counter] = 0; + if (param2 != null)// if (param2) + param2[counter] = t21; + + if (intersectionPoints != null)// if (intersectionPoints) + intersectionPoints[counter] = Point2D.construct( + line1.m_xStart, line1.m_yStart); + counter++; + } + } + + if (counter != 2 && !NumberUtils.isNaN(t22)) { + if (!(t11 == 1.0 && t22 == 0) && !(t12 == 1.0 && t22 == 1.0))// the + // "if" + // makes + // sure + // this + // has + // not + // been + // already + // calculated + { + if (param1 != null)// if (param1) + param1[counter] = 1.0; + if (param2 != null)// if (param2) + param2[counter] = t22; + + if (intersectionPoints != null)// if (intersectionPoints) + intersectionPoints[counter] = Point2D.construct( + line2.m_xEnd, line2.m_yEnd); + counter++; + } + } + + if (counter > 0) { + if (counter == 2 && param1 != null && param1[0] > param1[1]) {// make + // sure + // the + // intersection + // events + // are + // sorted + // along + // the + // line1 + // can't + // swap + // doulbes + // in + // java + // NumberUtils::Swap(param1[0], + // param1[1]); + double zeroParam1 = param1[0]; + param1[0] = param1[1]; + param1[1] = zeroParam1; + + if (param2 != null)// if (param2) + { + double zeroParam2 = param2[0]; + param2[0] = param2[1]; + param2[1] = zeroParam2;// NumberUtils::Swap(ARRAYELEMENT(param2, + // 0), ARRAYELEMENT(param2, 1)); + } + + if (intersectionPoints != null)// if (intersectionPoints) + { + Point2D tmp = new Point2D(intersectionPoints[0].x, + intersectionPoints[0].y); + intersectionPoints[0] = intersectionPoints[1]; + intersectionPoints[1] = tmp; + } + } + + return counter; + } + + Point2D params = _intersectHelper1(line1, line2, tolerance); + if (NumberUtils.isNaN(params.x)) + return 0; + + if (intersectionPoints != null)// if (intersectionPoints) + { + intersectionPoints[0] = line1.getCoord2D(params.x); + } + + if (param1 != null)// if (param1) + { + param1[0] = params.x; + } + + if (param2 != null)// if (param2) + { + param2[0] = params.y; + } + + return 1; + } + @Override public void replaceNaNs(int semantics, double value) { - addAttribute(semantics); - if (isEmpty()) - return; - - int ncomps = VertexDescription.getComponentCount(semantics); - for (int i = 0; i < ncomps; i++) { - double v = _getAttributeAsDbl(0, semantics, i); - if (Double.isNaN(v)) - _setAttribute(0, semantics, 0, value); - - v = _getAttributeAsDbl(1, semantics, i); - if (Double.isNaN(v)) - _setAttribute(1, semantics, 0, value); - } + addAttribute(semantics); + if (isEmpty()) + return; + + int ncomps = VertexDescription.getComponentCount(semantics); + for (int i = 0; i < ncomps; i++) { + double v = _getAttributeAsDbl(0, semantics, i); + if (Double.isNaN(v)) + _setAttribute(0, semantics, 0, value); + + v = _getAttributeAsDbl(1, semantics, i); + if (Double.isNaN(v)) + _setAttribute(1, semantics, 0, value); + } } + + @Override + int getYMonotonicParts(SegmentBuffer[] monotonicSegments) { + return 0; + } - @Override - int getYMonotonicParts(SegmentBuffer[] monotonicSegments) { - return 0; - } - - @Override - void _copyToImpl(Segment dst) { - // TODO Auto-generated method stub - - } + @Override + void _copyToImpl(Segment dst) { + // TODO Auto-generated method stub - /** - * The output of this method can be only used for debugging. It is subject to change without notice. - */ - @Override - public String toString() { - String s = "Line: [" + m_xStart + ", " + m_yStart + ", " + m_xEnd + ", " + m_yEnd + "]"; - return s; - } + } + /** + * The output of this method can be only used for debugging. It is subject to change without notice. + */ + @Override + public String toString() { + String s = "Line: [" + m_xStart + ", " + m_yStart + ", " + m_xEnd + ", " + m_yEnd +"]"; + return s; + } + } diff --git a/src/main/java/com/esri/core/geometry/ListeningGeometryCursor.java b/src/main/java/com/esri/core/geometry/ListeningGeometryCursor.java index d4867194..5ab1297a 100644 --- a/src/main/java/com/esri/core/geometry/ListeningGeometryCursor.java +++ b/src/main/java/com/esri/core/geometry/ListeningGeometryCursor.java @@ -34,47 +34,51 @@ * but are coming in a stream. */ public final class ListeningGeometryCursor extends GeometryCursor { - // required for use with grpc streaming - // https://github.com/grpc/grpc-java/blob/06e9b8814787b5cdec10a60e0d9a2228feb8554d/examples/src/main/java/io/grpc/examples/routeguide/RouteGuideServer.java#L246 - private Queue m_geomList = new ConcurrentLinkedQueue(); + // required for use with grpc streaming + // https://github.com/grpc/grpc-java/blob/06e9b8814787b5cdec10a60e0d9a2228feb8554d/examples/src/main/java/io/grpc/examples/routeguide/RouteGuideServer.java#L246 + private Queue m_geomList = new ConcurrentLinkedQueue(); - private long m_index = -1; + private long m_index = -1; - public ListeningGeometryCursor() { - } + public ListeningGeometryCursor() { + } - @Override - public boolean hasNext() { return m_geomList != null && !m_geomList.isEmpty(); } + @Override + public boolean hasNext() { + return m_geomList != null && !m_geomList.isEmpty(); + } - @Override - public long getGeometryID() { - return m_index; - } + @Override + public long getGeometryID() { + return m_index; + } - @Override - public String getFeatureID() { return ""; } + @Override + public String getFeatureID() { + return ""; + } - @Override - public Geometry next() { - if (m_geomList != null && !m_geomList.isEmpty()) { - m_index++; - return m_geomList.poll(); - } + @Override + public Geometry next() { + if (m_geomList != null && !m_geomList.isEmpty()) { + m_index++; + return m_geomList.poll(); + } - m_geomList = null;//prevent the class from being used again - return null; - } + m_geomList = null;//prevent the class from being used again + return null; + } - /** - * Call this method to add geometry to the cursor. After this method is - * called, call immediately the tock() method on the GeometryCursor returned - * by the OperatorUnion (or OperatorConvexHull with b_merge == true). Call - * next() on the GeometryCursor returned by the OperatorUnion when done - * listening to incoming geometries to finish the union operation. - * - * @param geom The geometry to be pushed into the cursor. - */ - public void tick(Geometry geom) { - m_geomList.add(geom); - } + /** + * Call this method to add geometry to the cursor. After this method is + * called, call immediately the tock() method on the GeometryCursor returned + * by the OperatorUnion (or OperatorConvexHull with b_merge == true). Call + * next() on the GeometryCursor returned by the OperatorUnion when done + * listening to incoming geometries to finish the union operation. + * + * @param geom The geometry to be pushed into the cursor. + */ + public void tick(Geometry geom) { + m_geomList.add(geom); + } } diff --git a/src/main/java/com/esri/core/geometry/LnSrlzr.java b/src/main/java/com/esri/core/geometry/LnSrlzr.java index 25e37fd9..8e7a6eaa 100644 --- a/src/main/java/com/esri/core/geometry/LnSrlzr.java +++ b/src/main/java/com/esri/core/geometry/LnSrlzr.java @@ -29,65 +29,65 @@ //This is a writeReplace class for Lin public class LnSrlzr implements Serializable { - private static final long serialVersionUID = 1L; - double[] attribs; - int descriptionBitMask; + private static final long serialVersionUID = 1L; + double[] attribs; + int descriptionBitMask; - public Object readResolve() throws ObjectStreamException { - Line ln = null; - if (descriptionBitMask == -1) - return null; + public Object readResolve() throws ObjectStreamException { + Line ln = null; + if (descriptionBitMask == -1) + return null; - try { - VertexDescription vd = VertexDescriptionDesignerImpl - .getVertexDescription(descriptionBitMask); - ln = new Line(vd); - if (attribs != null) { - ln.setStartXY(attribs[0], attribs[1]); - ln.setEndXY(attribs[2], attribs[3]); - int index = 4; - for (int i = 1, n = vd.getAttributeCount(); i < n; i++) { - int semantics = vd.getSemantics(i); - int comps = VertexDescription.getComponentCount(semantics); - for (int ord = 0; ord < comps; ord++) { - ln.setStartAttribute(semantics, ord, attribs[index++]); - ln.setEndAttribute(semantics, ord, attribs[index++]); - } - } - } - } catch (Exception ex) { - throw new InvalidObjectException("Cannot read geometry from stream"); - } + try { + VertexDescription vd = VertexDescriptionDesignerImpl + .getVertexDescription(descriptionBitMask); + ln = new Line(vd); + if (attribs != null) { + ln.setStartXY(attribs[0], attribs[1]); + ln.setEndXY(attribs[2], attribs[3]); + int index = 4; + for (int i = 1, n = vd.getAttributeCount(); i < n; i++) { + int semantics = vd.getSemantics(i); + int comps = VertexDescription.getComponentCount(semantics); + for (int ord = 0; ord < comps; ord++) { + ln.setStartAttribute(semantics, ord, attribs[index++]); + ln.setEndAttribute(semantics, ord, attribs[index++]); + } + } + } + } catch (Exception ex) { + throw new InvalidObjectException("Cannot read geometry from stream"); + } - return ln; - } + return ln; + } - public void setGeometryByValue(Line ln) throws ObjectStreamException { - try { - attribs = null; - if (ln == null) { - descriptionBitMask = -1; - } + public void setGeometryByValue(Line ln) throws ObjectStreamException { + try { + attribs = null; + if (ln == null) { + descriptionBitMask = -1; + } - VertexDescription vd = ln.getDescription(); - descriptionBitMask = vd.m_semanticsBitArray; + VertexDescription vd = ln.getDescription(); + descriptionBitMask = vd.m_semanticsBitArray; - attribs = new double[vd.getTotalComponentCount() * 2]; - attribs[0] = ln.getStartX(); - attribs[1] = ln.getStartY(); - attribs[2] = ln.getEndX(); - attribs[3] = ln.getEndY(); - int index = 4; - for (int i = 1, n = vd.getAttributeCount(); i < n; i++) { - int semantics = vd.getSemantics(i); - int comps = VertexDescription.getComponentCount(semantics); - for (int ord = 0; ord < comps; ord++) { - attribs[index++] = ln.getStartAttributeAsDbl(semantics, ord); - attribs[index++] = ln.getEndAttributeAsDbl(semantics, ord); - } - } - } catch (Exception ex) { - throw new InvalidObjectException("Cannot serialize this geometry"); - } - } + attribs = new double[vd.getTotalComponentCount() * 2]; + attribs[0] = ln.getStartX(); + attribs[1] = ln.getStartY(); + attribs[2] = ln.getEndX(); + attribs[3] = ln.getEndY(); + int index = 4; + for (int i = 1, n = vd.getAttributeCount(); i < n; i++) { + int semantics = vd.getSemantics(i); + int comps = VertexDescription.getComponentCount(semantics); + for (int ord = 0; ord < comps; ord++) { + attribs[index++] = ln.getStartAttributeAsDbl(semantics, ord); + attribs[index++] = ln.getEndAttributeAsDbl(semantics, ord); + } + } + } catch (Exception ex) { + throw new InvalidObjectException("Cannot serialize this geometry"); + } + } } diff --git a/src/main/java/com/esri/core/geometry/MapGeometry.java b/src/main/java/com/esri/core/geometry/MapGeometry.java index 37efc4fe..b9f6be1f 100644 --- a/src/main/java/com/esri/core/geometry/MapGeometry.java +++ b/src/main/java/com/esri/core/geometry/MapGeometry.java @@ -35,126 +35,126 @@ * spatial reference defined for this geometry. */ public class MapGeometry implements Serializable { - private static final long serialVersionUID = 1L; - - Geometry m_geometry = null; - SpatialReference sr = null; - - /** - * Construct a MapGeometry instance using the specified geometry instance - * and its corresponding spatial reference. - * - * @param g The geometry to construct the new MapGeometry object. - * @param _sr The spatial reference of the geometry. - */ - public MapGeometry(Geometry g, SpatialReference _sr) { - m_geometry = g; - sr = _sr; - } - - /** - * Gets the only geometry without the spatial reference from the - * MapGeometry. - */ - public Geometry getGeometry() { - return m_geometry; - } - - /** - * Sets the geometry for this MapGeometry. - * - * @param geometry The geometry. - */ - - public void setGeometry(Geometry geometry) { - this.m_geometry = geometry; - } - - /** - * Sets the spatial reference for this MapGeometry. - * - * @param sr The spatial reference. - */ - public void setSpatialReference(SpatialReference sr) { - this.sr = sr; - } - - /** - * Gets the spatial reference for this MapGeometry. - */ - public SpatialReference getSpatialReference() { - return sr; - } - - /** - * The output of this method can be only used for debugging. It is subject to change without notice. - */ - @Override - public String toString() { - String snippet = OperatorExportToJson.local().execute(getSpatialReference(), getGeometry()); - if (snippet.length() > 200) { - return snippet.substring(0, 197) + "... (" + snippet.length() + " characters)"; - } else { - return snippet; - } - } - - @Override - public boolean equals(Object other) { - if (other == null) - return false; - - if (other == this) - return true; - - if (other.getClass() != getClass()) - return false; - - MapGeometry omg = (MapGeometry) other; - SpatialReference sr = getSpatialReference(); - Geometry g = getGeometry(); - SpatialReference osr = omg.getSpatialReference(); - Geometry og = omg.getGeometry(); - - if (sr != osr) { - if (sr == null || !sr.equals(osr)) - return false; - } - - if (g != og) { - if (g == null || !g.equals(og)) - return false; - } - - return true; - } - - /** - * Returns an estimate of this object size in bytes. - *

- * This estimate doesn't include the size of the {@link SpatialReference} object - * because instances of {@link SpatialReference} are expected to be shared among - * geometry objects. - * - * @return Returns an estimate of this object size in bytes. - */ - public long estimateMemorySize() { - long sz = SIZE_OF_MAPGEOMETRY; - if (m_geometry != null) - sz += m_geometry.estimateMemorySize(); - return sz; - } - - @Override - public int hashCode() { - SpatialReference sr = getSpatialReference(); - Geometry g = getGeometry(); - int hc = 0x2937912; - if (sr != null) - hc ^= sr.hashCode(); - if (g != null) - hc ^= g.hashCode(); - - return hc; - } + private static final long serialVersionUID = 1L; + + Geometry m_geometry = null; + SpatialReference sr = null; + + /** + * Construct a MapGeometry instance using the specified geometry instance + * and its corresponding spatial reference. + * + * @param g The geometry to construct the new MapGeometry object. + * @param _sr The spatial reference of the geometry. + */ + public MapGeometry(Geometry g, SpatialReference _sr) { + m_geometry = g; + sr = _sr; + } + + /** + * Gets the only geometry without the spatial reference from the + * MapGeometry. + */ + public Geometry getGeometry() { + return m_geometry; + } + + /** + * Sets the geometry for this MapGeometry. + * + * @param geometry The geometry. + */ + + public void setGeometry(Geometry geometry) { + this.m_geometry = geometry; + } + + /** + * Sets the spatial reference for this MapGeometry. + * + * @param sr The spatial reference. + */ + public void setSpatialReference(SpatialReference sr) { + this.sr = sr; + } + + /** + * Gets the spatial reference for this MapGeometry. + */ + public SpatialReference getSpatialReference() { + return sr; + } + + /** + * The output of this method can be only used for debugging. It is subject to change without notice. + */ + @Override + public String toString() { + String snippet = OperatorExportToJson.local().execute(getSpatialReference(), getGeometry()); + if (snippet.length() > 200) { + return snippet.substring(0, 197) + "... (" + snippet.length() + " characters)"; + } else { + return snippet; + } + } + + @Override + public boolean equals(Object other) { + if (other == null) + return false; + + if (other == this) + return true; + + if (other.getClass() != getClass()) + return false; + + MapGeometry omg = (MapGeometry) other; + SpatialReference sr = getSpatialReference(); + Geometry g = getGeometry(); + SpatialReference osr = omg.getSpatialReference(); + Geometry og = omg.getGeometry(); + + if (sr != osr) { + if (sr == null || !sr.equals(osr)) + return false; + } + + if (g != og) { + if (g == null || !g.equals(og)) + return false; + } + + return true; + } + + /** + * Returns an estimate of this object size in bytes. + *

+ * This estimate doesn't include the size of the {@link SpatialReference} object + * because instances of {@link SpatialReference} are expected to be shared among + * geometry objects. + * + * @return Returns an estimate of this object size in bytes. + */ + public long estimateMemorySize() { + long sz = SIZE_OF_MAPGEOMETRY; + if (m_geometry != null) + sz += m_geometry.estimateMemorySize(); + return sz; + } + + @Override + public int hashCode() { + SpatialReference sr = getSpatialReference(); + Geometry g = getGeometry(); + int hc = 0x2937912; + if (sr != null) + hc ^= sr.hashCode(); + if (g != null) + hc ^= g.hashCode(); + + return hc; + } } diff --git a/src/main/java/com/esri/core/geometry/MapGeometryCursor.java b/src/main/java/com/esri/core/geometry/MapGeometryCursor.java index 20923fc6..925474f8 100644 --- a/src/main/java/com/esri/core/geometry/MapGeometryCursor.java +++ b/src/main/java/com/esri/core/geometry/MapGeometryCursor.java @@ -30,26 +30,26 @@ */ public abstract class MapGeometryCursor implements Iterator { - /** - * Moves the cursor to the next ProjectedGeometry. Returns null when reached - * the end. - */ - public abstract MapGeometry next(); - - /** - * Returns the ID of the current geometry. The ID is propagated across the - * operations (when possible). - *

- * Returns an ID associated with the current Geometry. The ID is passed - * along and is returned by some operators to preserve relationship between - * the input and output geometry classes. It is not always possible to - * preserve an ID during an operation. - */ - public abstract long getGeometryID(); - - public abstract SimpleStateEnum getSimpleState(); - - public abstract String getFeatureID(); - - public abstract boolean hasNext(); + /** + * Moves the cursor to the next ProjectedGeometry. Returns null when reached + * the end. + */ + public abstract MapGeometry next(); + + /** + * Returns the ID of the current geometry. The ID is propagated across the + * operations (when possible). + *

+ * Returns an ID associated with the current Geometry. The ID is passed + * along and is returned by some operators to preserve relationship between + * the input and output geometry classes. It is not always possible to + * preserve an ID during an operation. + */ + public abstract long getGeometryID(); + + public abstract SimpleStateEnum getSimpleState(); + + public abstract String getFeatureID(); + + public abstract boolean hasNext(); } diff --git a/src/main/java/com/esri/core/geometry/MapOGCStructure.java b/src/main/java/com/esri/core/geometry/MapOGCStructure.java index ea2e8d4c..c4eb5241 100644 --- a/src/main/java/com/esri/core/geometry/MapOGCStructure.java +++ b/src/main/java/com/esri/core/geometry/MapOGCStructure.java @@ -24,6 +24,6 @@ package com.esri.core.geometry; public class MapOGCStructure { - public OGCStructure m_ogcStructure; - public SpatialReference m_spatialReference; + public OGCStructure m_ogcStructure; + public SpatialReference m_spatialReference; } diff --git a/src/main/java/com/esri/core/geometry/MathUtils.java b/src/main/java/com/esri/core/geometry/MathUtils.java index fa37aed2..2b41d433 100644 --- a/src/main/java/com/esri/core/geometry/MathUtils.java +++ b/src/main/java/com/esri/core/geometry/MathUtils.java @@ -25,211 +25,211 @@ package com.esri.core.geometry; final class MathUtils { - /** - * The implementation of the Kahan summation algorithm. Use to get better - * precision when adding a lot of values. - */ - static final class KahanSummator { - private double sum; // the accumulated sum - private double compensation; - private double startValue; // the Base (the class returns sum + - // startValue) - - /** - * initialize to the given start value. \param startValue_ The value to - * be added to the accumulated sum. - */ - KahanSummator(double startValue_) { - startValue = startValue_; - reset(); - } - - /** - * Resets the accumulated sum to zero. The getResult() returns - * startValue_ after this call. - */ - void reset() { - sum = 0; - compensation = 0; - } - - /** - * add a value. - */ - void add(double v) { - double y = v - compensation; - double t = sum + y; - double h = t - sum; - compensation = h - y; - sum = t; - } - - /** - * Subtracts a value. - */ - void sub(double v) { - add(-v); - } - - /** - * add another summator. - */ - void add(/* const */KahanSummator v) { - double y = (v.getResult() + v.compensation) - compensation; - double t = sum + y; - double h = t - sum; - compensation = h - y; - sum = t; - } - - /** - * Subtracts another summator. - */ - void sub(/* const */KahanSummator v) { - double y = -(v.getResult() - v.compensation) - compensation; - double t = sum + y; - double h = t - sum; - compensation = h - y; - sum = t; - } - - /** - * Returns current value of the sum. - */ - double getResult() /* const */ { - return startValue + sum; - } - - KahanSummator plusEquals(double v) { - add(v); - return this; - } - - KahanSummator minusEquals(double v) { - add(-v); - return this; - } - - KahanSummator plusEquals(/* const */KahanSummator v) { - add(v); - return this; - } - - KahanSummator minusEquals(/* const */KahanSummator v) { - sub(v); - return this; - } - } - - /** - * Returns one value with the sign of another (like copysign). - */ - static double copySign(double x, double y) { - return y >= 0.0 ? Math.abs(x) : -Math.abs(x); - } - - /** - * Calculates sign of the given value. Returns 0 if the value is equal to 0. - */ - static int sign(double value) { - return value < 0 ? -1 : (value > 0) ? 1 : 0; - } - - /** - * Rounds towards zero. - */ - static double truncate(double v) { - if (v >= 0) - return Math.floor(v); - else - return -Math.floor(-v); - } - - /** - * C fmod function. - */ - static double FMod(double x, double y) { - return x - truncate(x / y) * y; - } - - - /** - * Rounds double to the closest integer value. - */ - static double round(double v) { - return Math.floor(v + 0.5); - } - - static double sqr(double v) { - return v * v; - } - - /** - * Computes interpolation between two values, using the interpolation factor t. - * The interpolation formula is (end - start) * t + start. - * However, the computation ensures that t = 0 produces exactly start, and t = 1, produces exactly end. - * It also guarantees that for 0 <= t <= 1, the interpolated value v is between start and end. - */ - static double lerp(double start_, double end_, double t) { - // When end == start, we want result to be equal to start, for all t - // values. At the same time, when end != start, we want the result to be - // equal to start for t==0 and end for t == 1.0 - // The regular formula end_ * t + (1.0 - t) * start_, when end_ == - // start_, and t at 1/3, produces value different from start - double v; - if (t <= 0.5) - v = start_ + (end_ - start_) * t; - else - v = end_ - (end_ - start_) * (1.0 - t); - - assert (t < 0 || t > 1.0 || (v >= start_ && v <= end_) || (v <= start_ && v >= end_) || NumberUtils.isNaN(start_) || NumberUtils.isNaN(end_)); - return v; - } - - /** - * Computes interpolation between two values, using the interpolation factor t. - * The interpolation formula is (end - start) * t + start. - * However, the computation ensures that t = 0 produces exactly start, and t = 1, produces exactly end. - * It also guarantees that for 0 <= t <= 1, the interpolated value v is between start and end. - */ - static void lerp(Point2D start_, Point2D end_, double t, Point2D result) { - assert (start_ != result); - // When end == start, we want result to be equal to start, for all t - // values. At the same time, when end != start, we want the result to be - // equal to start for t==0 and end for t == 1.0 - // The regular formula end_ * t + (1.0 - t) * start_, when end_ == - // start_, and t at 1/3, produces value different from start - double rx, ry; - if (t <= 0.5) { - rx = start_.x + (end_.x - start_.x) * t; - ry = start_.y + (end_.y - start_.y) * t; - } else { - rx = end_.x - (end_.x - start_.x) * (1.0 - t); - ry = end_.y - (end_.y - start_.y) * (1.0 - t); - } - - assert (t < 0 || t > 1.0 || (rx >= start_.x && rx <= end_.x) || (rx <= start_.x && rx >= end_.x)); - assert (t < 0 || t > 1.0 || (ry >= start_.y && ry <= end_.y) || (ry <= start_.y && ry >= end_.y)); - result.x = rx; - result.y = ry; - } - - static void lerp(double start_x, double start_y, double end_x, double end_y, double t, Point2D result) { - // When end == start, we want result to be equal to start, for all t - // values. At the same time, when end != start, we want the result to be - // equal to start for t==0 and end for t == 1.0 - // The regular formula end_ * t + (1.0 - t) * start_, when end_ == - // start_, and t at 1/3, produces value different from start - if (t <= 0.5) { - result.x = start_x + (end_x - start_x) * t; - result.y = start_y + (end_y - start_y) * t; - } else { - result.x = end_x - (end_x - start_x) * (1.0 - t); - result.y = end_y - (end_y - start_y) * (1.0 - t); - } - - assert (t < 0 || t > 1.0 || (result.x >= start_x && result.x <= end_x) || (result.x <= start_x && result.x >= end_x)); - assert (t < 0 || t > 1.0 || (result.y >= start_y && result.y <= end_y) || (result.y <= start_y && result.y >= end_y)); - } + /** + * The implementation of the Kahan summation algorithm. Use to get better + * precision when adding a lot of values. + */ + static final class KahanSummator { + private double sum; // the accumulated sum + private double compensation; + private double startValue; // the Base (the class returns sum + + // startValue) + + /** + * initialize to the given start value. \param startValue_ The value to + * be added to the accumulated sum. + */ + KahanSummator(double startValue_) { + startValue = startValue_; + reset(); + } + + /** + * Resets the accumulated sum to zero. The getResult() returns + * startValue_ after this call. + */ + void reset() { + sum = 0; + compensation = 0; + } + + /** + * add a value. + */ + void add(double v) { + double y = v - compensation; + double t = sum + y; + double h = t - sum; + compensation = h - y; + sum = t; + } + + /** + * Subtracts a value. + */ + void sub(double v) { + add(-v); + } + + /** + * add another summator. + */ + void add(/* const */KahanSummator v) { + double y = (v.getResult() + v.compensation) - compensation; + double t = sum + y; + double h = t - sum; + compensation = h - y; + sum = t; + } + + /** + * Subtracts another summator. + */ + void sub(/* const */KahanSummator v) { + double y = -(v.getResult() - v.compensation) - compensation; + double t = sum + y; + double h = t - sum; + compensation = h - y; + sum = t; + } + + /** + * Returns current value of the sum. + */ + double getResult() /* const */ { + return startValue + sum; + } + + KahanSummator plusEquals(double v) { + add(v); + return this; + } + + KahanSummator minusEquals(double v) { + add(-v); + return this; + } + + KahanSummator plusEquals(/* const */KahanSummator v) { + add(v); + return this; + } + + KahanSummator minusEquals(/* const */KahanSummator v) { + sub(v); + return this; + } + } + + /** + * Returns one value with the sign of another (like copysign). + */ + static double copySign(double x, double y) { + return y >= 0.0 ? Math.abs(x) : -Math.abs(x); + } + + /** + * Calculates sign of the given value. Returns 0 if the value is equal to 0. + */ + static int sign(double value) { + return value < 0 ? -1 : (value > 0) ? 1 : 0; + } + + /** + * Rounds towards zero. + */ + static double truncate(double v) { + if (v >= 0) + return Math.floor(v); + else + return -Math.floor(-v); + } + + /** + * C fmod function. + */ + static double FMod(double x, double y) { + return x - truncate(x / y) * y; + } + + + /** + * Rounds double to the closest integer value. + */ + static double round(double v) { + return Math.floor(v + 0.5); + } + + static double sqr(double v) { + return v * v; + } + + /** + * Computes interpolation between two values, using the interpolation factor t. + * The interpolation formula is (end - start) * t + start. + * However, the computation ensures that t = 0 produces exactly start, and t = 1, produces exactly end. + * It also guarantees that for 0 <= t <= 1, the interpolated value v is between start and end. + */ + static double lerp(double start_, double end_, double t) { + // When end == start, we want result to be equal to start, for all t + // values. At the same time, when end != start, we want the result to be + // equal to start for t==0 and end for t == 1.0 + // The regular formula end_ * t + (1.0 - t) * start_, when end_ == + // start_, and t at 1/3, produces value different from start + double v; + if (t <= 0.5) + v = start_ + (end_ - start_) * t; + else + v = end_ - (end_ - start_) * (1.0 - t); + + assert (t < 0 || t > 1.0 || (v >= start_ && v <= end_) || (v <= start_ && v >= end_) || NumberUtils.isNaN(start_) || NumberUtils.isNaN(end_)); + return v; + } + + /** + * Computes interpolation between two values, using the interpolation factor t. + * The interpolation formula is (end - start) * t + start. + * However, the computation ensures that t = 0 produces exactly start, and t = 1, produces exactly end. + * It also guarantees that for 0 <= t <= 1, the interpolated value v is between start and end. + */ + static void lerp(Point2D start_, Point2D end_, double t, Point2D result) { + assert (start_ != result); + // When end == start, we want result to be equal to start, for all t + // values. At the same time, when end != start, we want the result to be + // equal to start for t==0 and end for t == 1.0 + // The regular formula end_ * t + (1.0 - t) * start_, when end_ == + // start_, and t at 1/3, produces value different from start + double rx, ry; + if (t <= 0.5) { + rx = start_.x + (end_.x - start_.x) * t; + ry = start_.y + (end_.y - start_.y) * t; + } else { + rx = end_.x - (end_.x - start_.x) * (1.0 - t); + ry = end_.y - (end_.y - start_.y) * (1.0 - t); + } + + assert (t < 0 || t > 1.0 || (rx >= start_.x && rx <= end_.x) || (rx <= start_.x && rx >= end_.x)); + assert (t < 0 || t > 1.0 || (ry >= start_.y && ry <= end_.y) || (ry <= start_.y && ry >= end_.y)); + result.x = rx; + result.y = ry; + } + + static void lerp(double start_x, double start_y, double end_x, double end_y, double t, Point2D result) { + // When end == start, we want result to be equal to start, for all t + // values. At the same time, when end != start, we want the result to be + // equal to start for t==0 and end for t == 1.0 + // The regular formula end_ * t + (1.0 - t) * start_, when end_ == + // start_, and t at 1/3, produces value different from start + if (t <= 0.5) { + result.x = start_x + (end_x - start_x) * t; + result.y = start_y + (end_y - start_y) * t; + } else { + result.x = end_x - (end_x - start_x) * (1.0 - t); + result.y = end_y - (end_y - start_y) * (1.0 - t); + } + + assert (t < 0 || t > 1.0 || (result.x >= start_x && result.x <= end_x) || (result.x <= start_x && result.x >= end_x)); + assert (t < 0 || t > 1.0 || (result.y >= start_y && result.y <= end_y) || (result.y <= start_y && result.y >= end_y)); + } } diff --git a/src/main/java/com/esri/core/geometry/MgrsConversionMode.java b/src/main/java/com/esri/core/geometry/MgrsConversionMode.java index cc47215e..7542f078 100644 --- a/src/main/java/com/esri/core/geometry/MgrsConversionMode.java +++ b/src/main/java/com/esri/core/geometry/MgrsConversionMode.java @@ -29,32 +29,32 @@ * notation and coordinates. */ public interface MgrsConversionMode { - /** - * Uses the spheroid to determine the military grid string. - */ - public static final int mgrsAutomatic = 0;// PE_MGRS_STYLE_AUTO - /** - * Treats all spheroids as new, like WGS 1984, when creating or reading a - * military grid string. The 180 longitude falls into zone 60. - */ - public static final int mgrsNewStyle = 0x100; // PE_MGRS_STYLE_NEW - /** - * Treats all spheroids as old, like Bessel 1841, when creating or reading a - * military grid string. The 180 longitude falls into zone 60. - */ - public static final int mgrsOldStyle = 0x200; // PE_MGRS_STYLE_OLD - /** - * Treats all spheroids as new, like WGS 1984, when creating or reading a - * military grid string. The 180 longitude falls into zone 01. - */ - public static final int mgrsNewWith180InZone01 = 0x1000 + 0x100; // PE_MGRS_180_ZONE_1_PLUS - // | - // PE_MGRS_STYLE_NEW - /** - * Treats all spheroids as old, like Bessel 1841, when creating or reading a - * military grid string. The 180 longitude falls into zone 01. - */ - public static final int mgrsOldWith180InZone01 = 0x1000 + 0x200; // PE_MGRS_180_ZONE_1_PLUS - // | - // PE_MGRS_STYLE_OLD + /** + * Uses the spheroid to determine the military grid string. + */ + public static final int mgrsAutomatic = 0;// PE_MGRS_STYLE_AUTO + /** + * Treats all spheroids as new, like WGS 1984, when creating or reading a + * military grid string. The 180 longitude falls into zone 60. + */ + public static final int mgrsNewStyle = 0x100; // PE_MGRS_STYLE_NEW + /** + * Treats all spheroids as old, like Bessel 1841, when creating or reading a + * military grid string. The 180 longitude falls into zone 60. + */ + public static final int mgrsOldStyle = 0x200; // PE_MGRS_STYLE_OLD + /** + * Treats all spheroids as new, like WGS 1984, when creating or reading a + * military grid string. The 180 longitude falls into zone 01. + */ + public static final int mgrsNewWith180InZone01 = 0x1000 + 0x100; // PE_MGRS_180_ZONE_1_PLUS + // | + // PE_MGRS_STYLE_NEW + /** + * Treats all spheroids as old, like Bessel 1841, when creating or reading a + * military grid string. The 180 longitude falls into zone 01. + */ + public static final int mgrsOldWith180InZone01 = 0x1000 + 0x200; // PE_MGRS_180_ZONE_1_PLUS + // | + // PE_MGRS_STYLE_OLD } diff --git a/src/main/java/com/esri/core/geometry/MultiPath.java b/src/main/java/com/esri/core/geometry/MultiPath.java index 8d7be36b..3f320725 100644 --- a/src/main/java/com/esri/core/geometry/MultiPath.java +++ b/src/main/java/com/esri/core/geometry/MultiPath.java @@ -30,687 +30,687 @@ * The MulitPath class is a base class for polygons and polylines. */ public abstract class MultiPath extends MultiVertexGeometry implements - Serializable { - MultiPathImpl m_impl; - - @Override - public VertexDescription getDescription() { - return m_impl.getDescription(); - } - - @Override - public void assignVertexDescription(VertexDescription src) { - m_impl.assignVertexDescription(src); - } - - @Override - public void mergeVertexDescription(VertexDescription src) { - m_impl.mergeVertexDescription(src); - } - - @Override - public void addAttribute(int semantics) { - m_impl.addAttribute(semantics); - } - - @Override - public void dropAttribute(int semantics) { - m_impl.dropAttribute(semantics); - } - - @Override - public void dropAllAttributes() { - m_impl.dropAllAttributes(); - } - - @Override - public int getPointCount() { - return m_impl.getPointCount(); - } - - @Override - public Point getPoint(int index) { - return m_impl.getPoint(index); - } - - @Override - public void setPoint(int index, Point point) { - m_impl.setPoint(index, point); - } - - @Override - public boolean isEmpty() { - return m_impl.isEmptyImpl(); - } - - @Override - public double calculateArea2D() { - return m_impl.calculateArea2D(); - } - - @Override - public double calculateLength2D() { - return m_impl.calculateLength2D(); - } - - public double calculatePathLength2D(int pathIndex) { - return m_impl.calculatePathLength2D(pathIndex); - } - - @Override - public double getAttributeAsDbl(int semantics, int index, int ordinate) { - return m_impl.getAttributeAsDbl(semantics, index, ordinate); - } - - @Override - public int getAttributeAsInt(int semantics, int index, int ordinate) { - return m_impl.getAttributeAsInt(semantics, index, ordinate); - } - - @Override - public void setAttribute(int semantics, int index, int ordinate, - double value) { - m_impl.setAttribute(semantics, index, ordinate, value); - } - - @Override - public void setAttribute(int semantics, int index, int ordinate, int value) { - m_impl.setAttribute(semantics, index, ordinate, value); - } - - @Override - public Point2D getXY(int index) { - return m_impl.getXY(index); - } - - @Override - public void getXY(int index, Point2D pt) { - m_impl.getXY(index, pt); - } - - @Override - public void setXY(int index, Point2D pt) { - m_impl.setXY(index, pt); - } - - @Override - Point3D getXYZ(int index) { - return m_impl.getXYZ(index); - } - - @Override - void setXYZ(int index, Point3D pt) { - m_impl.setXYZ(index, pt); - } - - @Override - public void queryEnvelope(Envelope env) { - m_impl.queryEnvelope(env); - } - - @Override - public void queryEnvelope2D(Envelope2D env) { - m_impl.queryEnvelope2D(env); - } - - public void queryPathEnvelope2D(int pathIndex, Envelope2D env) { - m_impl.queryPathEnvelope2D(pathIndex, env); - } - - @Override - void queryEnvelope3D(Envelope3D env) { - m_impl.queryEnvelope3D(env); - } - - public void queryLooseEnvelope(Envelope2D env) { - m_impl.queryLooseEnvelope2D(env); - } - - void queryLooseEnvelope(Envelope3D env) { - m_impl.queryLooseEnvelope3D(env); - } - - @Override - public Envelope1D queryInterval(int semantics, int ordinate) { - return m_impl.queryInterval(semantics, ordinate); - } - - @Override - public void copyTo(Geometry dst) { - if (getType() != dst.getType()) - throw new IllegalArgumentException(); - - m_impl.copyTo((Geometry) dst._getImpl()); - } - - @Override - public Geometry getBoundary() { - return m_impl.getBoundary(); - } - - @Override - public void queryCoordinates(Point2D[] dst) { - m_impl.queryCoordinates(dst); - } - - public void queryCoordinates(Point2D[] dst, int dstSize, int beginIndex, int endIndex) { - m_impl.queryCoordinates(dst, dstSize, beginIndex, endIndex); - } - - @Override - void queryCoordinates(Point3D[] dst) { - m_impl.queryCoordinates(dst); - } - - @Override - public void queryCoordinates(Point[] dst) { - m_impl.queryCoordinates(dst); - - } - - /** - * Returns TRUE if the multipath contains non-linear segments. - */ - boolean hasNonLinearSegments() { - return m_impl.hasNonLinearSegments(); - } - - /** - * Returns total segment count in the MultiPath. - */ - public int getSegmentCount() { - return m_impl.getSegmentCount(); - } - - /** - * Returns the segment count in the given multipath path. - * - * @param pathIndex The path to determine the segment. - * @return The segment of the multipath. - */ - public int getSegmentCount(int pathIndex) { - int segCount = getPathSize(pathIndex); - if (!isClosedPath(pathIndex)) - segCount--; - return segCount; - } - - /** - * Appends all paths from another multipath. - * - * @param src The multipath to append to this multipath. - * @param bReversePaths TRUE if the multipath is added should be added with its paths - * reversed. - */ - public void add(MultiPath src, boolean bReversePaths) { - m_impl.add((MultiPathImpl) src._getImpl(), bReversePaths); - } - - /** - * Copies a path from another multipath. - * - * @param src The multipath to copy from. - * @param srcPathIndex The index of the path in the the source MultiPath. - * @param bForward When FALSE, the points are inserted in reverse order. - */ - public void addPath(MultiPath src, int srcPathIndex, boolean bForward) { - m_impl.addPath((MultiPathImpl) src._getImpl(), srcPathIndex, bForward); - } - - /** - * Adds a new path to this multipath. - * - * @param points The array of points to add to this multipath. - * @param count The number of points added to the mulitpath. - * @param bForward When FALSE, the points are inserted in reverse order. - */ - void addPath(Point2D[] points, int count, boolean bForward) { - m_impl.addPath(points, count, bForward); - } - - /** - * Adds segments from a source multipath to this MultiPath. - * - * @param src The source MultiPath to add segments from. - * @param srcPathIndex The index of the path in the the source MultiPath. - * @param srcSegmentFrom The index of first segment in the path to start adding from. - * The value has to be between 0 and - * src.getSegmentCount(srcPathIndex) - 1. - * @param srcSegmentCount The number of segments to add. If 0, the function does - * nothing. - * @param bStartNewPath When true, a new path is added and segments are added to it. - * Otherwise the segments are added to the last path of this - * MultiPath. - *

- * If bStartNewPath false, the first point of the first source - * segment is not added. This is done to ensure proper connection - * to existing segments. When the source path is closed, and the - * closing segment is among those to be added, it is added also - * as a closing segment, not as a real segment. Use add_segment - * instead if you do not like that behavior. - *

- * This MultiPath obtains all missing attributes from the src - * MultiPath. - */ - public void addSegmentsFromPath(MultiPath src, int srcPathIndex, - int srcSegmentFrom, int srcSegmentCount, boolean bStartNewPath) { - m_impl.addSegmentsFromPath((MultiPathImpl) src._getImpl(), - srcPathIndex, srcSegmentFrom, srcSegmentCount, bStartNewPath); - } - - /** - * Adds a new segment to this multipath. - * - * @param segment The segment to be added to this mulitpath. - * @param bStartNewPath TRUE if a new path will be added. - */ - public void addSegment(Segment segment, boolean bStartNewPath) { - m_impl.addSegment(segment, bStartNewPath); - } - - /** - * Reverses the order of the vertices in each path. - */ - public void reverseAllPaths() { - m_impl.reverseAllPaths(); - } - - /** - * Reverses the order of vertices in the path. - * - * @param pathIndex The start index of the path to reverse the order. - */ - public void reversePath(int pathIndex) { - m_impl.reversePath(pathIndex); - } - - /** - * Removes the path at the given index. - * - * @param pathIndex The start index to remove the path. - */ - public void removePath(int pathIndex) { - m_impl.removePath(pathIndex); - } - - /** - * Inserts a path from another multipath. - * - * @param pathIndex The start index of the multipath to insert. - * @param src The multipath to insert into this multipath. Can be the same - * as the multipath being modified. - * @param srcPathIndex The start index to insert the path into the multipath. - * @param bForward When FALSE, the points are inserted in reverse order. - */ - public void insertPath(int pathIndex, MultiPath src, int srcPathIndex, - boolean bForward) { - m_impl.insertPath(pathIndex, (MultiPathImpl) src._getImpl(), - srcPathIndex, bForward); - } - - /** - * Inserts a path from an array of 2D Points. - * - * @param pathIndex The path index of the multipath to place the new path. - * @param points The array of points defining the new path. - * @param pointsOffset The offset into the array to start reading. - * @param count The number of points to insert into the new path. - * @param bForward When FALSE, the points are inserted in reverse order. - */ - void insertPath(int pathIndex, Point2D[] points, int pointsOffset, - int count, boolean bForward) { - m_impl.insertPath(pathIndex, points, pointsOffset, count, bForward); - } - - /** - * Inserts vertices from the given multipath into this multipath. All added - * vertices are connected by linear segments with each other and with the - * existing vertices. - * - * @param pathIndex The path index in this multipath to insert points to. Must - * correspond to an existing path. - * @param beforePointIndex The point index before all other vertices to insert in the - * given path of this multipath. This value must be between 0 and - * GetPathSize(pathIndex), or -1 to insert points at the end of - * the given path. - * @param src The source multipath. - * @param srcPathIndex The source path index to copy points from. - * @param srcPointIndexFrom The start point in the source path to start copying from. - * @param srcPointCount The count of points to add. - * @param bForward When FALSE, the points are inserted in reverse order. - */ - public void insertPoints(int pathIndex, int beforePointIndex, - MultiPath src, int srcPathIndex, int srcPointIndexFrom, - int srcPointCount, boolean bForward) { - m_impl.insertPoints(pathIndex, beforePointIndex, - (MultiPathImpl) src._getImpl(), srcPathIndex, - srcPointIndexFrom, srcPointCount, bForward); - } - - /** - * Inserts a part of a path from the given array. - * - * @param pathIndex The path index in this class to insert points to. Must - * correspond to an existing path. - * @param beforePointIndex The point index in the given path of this MultiPath before - * which the vertices need to be inserted. This value must be - * between 0 and GetPathSize(pathIndex), or -1 to insert points - * at the end of the given path. - * @param src The source array - * @param srcPointIndexFrom The start point in the source array to start copying from. - * @param srcPointCount The count of points to add. - * @param bForward When FALSE, the points are inserted in reverse order. - */ - void insertPoints(int pathIndex, int beforePointIndex, Point2D[] src, - int srcPointIndexFrom, int srcPointCount, boolean bForward) { - m_impl.insertPoints(pathIndex, beforePointIndex, src, - srcPointIndexFrom, srcPointCount, bForward); - } - - /** - * Inserts a point. - * - * @param pathIndex The path index in this class to insert the point to. Must - * correspond to an existing path. - * @param beforePointIndex The point index in the given path of this multipath. This - * value must be between 0 and GetPathSize(pathIndex), or -1 to - * insert the point at the end of the given path. - * @param pt The point to be inserted. - */ - void insertPoint(int pathIndex, int beforePointIndex, Point2D pt) { - m_impl.insertPoint(pathIndex, beforePointIndex, pt); - } - - /** - * Inserts a point. - * - * @param pathIndex The path index in this class to insert the point to. Must - * correspond to an existing path. - * @param beforePointIndex The point index in the given path of this multipath. This - * value must be between 0 and GetPathSize(pathIndex), or -1 to - * insert the point at the end of the given path. - * @param pt The point to be inserted. - */ - public void insertPoint(int pathIndex, int beforePointIndex, Point pt) { - m_impl.insertPoint(pathIndex, beforePointIndex, pt); - } - - /** - * Removes a point at a given index. - * - * @param pathIndex The path from whom to remove the point. - * @param pointIndex The index of the point to be removed. - */ - public void removePoint(int pathIndex, int pointIndex) { - m_impl.removePoint(pathIndex, pointIndex); - } - - /** - * Returns the number of paths in this multipath. - * - * @return The number of paths in this multipath. - */ - public int getPathCount() { - return m_impl.getPathCount(); - } - - /** - * Returns the number of vertices in a path. - * - * @param pathIndex The index of the path to return the number of vertices from. - * @return The number of vertices in a path. - */ - public int getPathSize(int pathIndex) { - return m_impl.getPathSize(pathIndex); - } - - /** - * Returns the start index of the path. - * - * @param pathIndex The index of the path to return the start index from. - * @return The start index of the path. - */ - public int getPathStart(int pathIndex) { - return m_impl.getPathStart(pathIndex); - } - - /** - * Returns the index immediately following the last index of the path. - * - * @param pathIndex The index of the path to return the end index from. - * @return Integer index after last index of path - */ - public int getPathEnd(int pathIndex) { - return m_impl.getPathEnd(pathIndex); - } - - /** - * Returns the path index from the point index. This is O(log N) operation. - * - * @param pointIndex The index of the point. - * @return The index of the path. - */ - public int getPathIndexFromPointIndex(int pointIndex) { - return m_impl.getPathIndexFromPointIndex(pointIndex); - } - - /** - * Starts a new path at given coordinates. - * - * @param x The X coordinate of the start point. - * @param y The Y coordinate of the start point. - */ - public void startPath(double x, double y) { - m_impl.startPath(x, y); - } - - void startPath(Point2D point) { - m_impl.startPath(point); - } - - void startPath(Point3D point) { - m_impl.startPath(point); - } - - /** - * Starts a new path at a point. - * - * @param point The point to start the path from. - */ - public void startPath(Point point) { - m_impl.startPath(point); - } - - /** - * Adds a line segment from the last point to the given end coordinates. - * - * @param x The X coordinate to the end point. - * @param y The Y coordinate to the end point. - */ - public void lineTo(double x, double y) { - m_impl.lineTo(x, y); - } - - void lineTo(Point2D endPoint) { - m_impl.lineTo(endPoint); - } - - void lineTo(Point3D endPoint) { - m_impl.lineTo(endPoint); - } - - /** - * Adds a Line Segment to the given end point. - * - * @param endPoint The end point to which the newly added line segment should - * point. - */ - public void lineTo(Point endPoint) { - m_impl.lineTo(endPoint); - } - - /** - * Adds a Cubic Bezier Segment to the current Path. The Bezier Segment - * connects the current last Point and the given endPoint. - */ - void bezierTo(Point2D controlPoint1, Point2D controlPoint2, Point2D endPoint) { - m_impl.bezierTo(controlPoint1, controlPoint2, endPoint); - } - - /** - * Closes the last path of this multipath with a line segment. The closing - * segment is a segment that connects the last and the first points of the - * path. This is a virtual segment. The first point is not duplicated to - * close the path. - *

- * Call this method only for polylines. For polygons this method is - * implicitly called for the Polygon class. - */ - public void closePathWithLine() { - m_impl.closePathWithLine(); - } - - /** - * Closes last path of the MultiPath with the Bezier Segment. - *

- * The start point of the Bezier is the last point of the path and the last - * point of the bezier is the first point of the path. - */ - void closePathWithBezier(Point2D controlPoint1, Point2D controlPoint2) { - m_impl.closePathWithBezier(controlPoint1, controlPoint2); - } - - /** - * Closes last path of the MultiPath with the Arc Segment. - */ - void closePathWithArc() { - throw new RuntimeException("not implemented"); - } - - /** - * Closes all open paths by adding an implicit line segment from the end - * point to the start point. Call this method only for polylines.For - * polygons this method is implicitly called for the Polygon class. - */ - public void closeAllPaths() { - m_impl.closeAllPaths(); - } - - /** - * Indicates if the given path is closed (represents a ring). A closed path - * has a virtual segment that connects the last and the first points of the - * path. The first point is not duplicated to close the path. Polygons - * always have all paths closed. - * - * @param pathIndex The index of the path to check to be closed. - * @return TRUE if the given path is closed (represents a Ring). - */ - public boolean isClosedPath(int pathIndex) { - return m_impl.isClosedPath(pathIndex); - } - - public boolean isClosedPathInXYPlane(int pathIndex) { - return m_impl.isClosedPathInXYPlane(pathIndex); - } - - /** - * Returns TRUE if the given path might have non-linear segments. - */ - boolean hasNonLinearSegments(int pathIndex) { - return m_impl.hasNonLinearSegments(pathIndex); - } - - /** - * Adds a rectangular closed Path to the MultiPathImpl. - * - * @param envSrc is the source rectangle. - * @param bReverse Creates reversed path. - */ - public void addEnvelope(Envelope2D envSrc, boolean bReverse) { - m_impl.addEnvelope(envSrc, bReverse); - } - - /** - * Adds a rectangular closed path to this multipath. - * - * @param envSrc Is the envelope to add to this mulitpath. - * @param bReverse Adds the path reversed (counter-clockwise). - */ - public void addEnvelope(Envelope envSrc, boolean bReverse) { - m_impl.addEnvelope(envSrc, bReverse); - } - - /** - * Returns a SegmentIterator that is set right before the beginning of the - * multipath. Calling nextPath() will set the iterator to the first path of - * this multipath. - * - * @return The SegmentIterator for this mulitpath. - */ - public SegmentIterator querySegmentIterator() { - return new SegmentIterator(m_impl.querySegmentIterator()); - } - - /** - * Returns a SegmentIterator that is set to a specific vertex of the - * MultiPath. The call to nextSegment() will return the segment that starts - * at the vertex. Calling PreviousSegment () will return the segment that - * starts at the previous vertex. - * - * @param startVertexIndex The start index of the SegementIterator. - * @return The SegmentIterator for this mulitpath at the specified vertex. - */ - public SegmentIterator querySegmentIteratorAtVertex(int startVertexIndex) { - return new SegmentIterator( - m_impl.querySegmentIteratorAtVertex(startVertexIndex)); - } - - @Override - public void setEmpty() { - m_impl.setEmpty(); - } - - @Override - public void applyTransformation(Transformation2D transform) { - m_impl.applyTransformation(transform); - } - - @Override - void applyTransformation(Transformation3D transform) { - m_impl.applyTransformation(transform); - } - - @Override - protected Object _getImpl() { - return m_impl; - } - - /** - * Returns the hash code for the multipath. - */ - @Override - public int hashCode() { - return m_impl.hashCode(); - } - - @Override - public void getPointByVal(int index, Point outPoint) { - m_impl.getPointByVal(index, outPoint); - } - - @Override - public void setPointByVal(int index, Point point) { - m_impl.setPointByVal(index, point); - } - - @Override - public int getStateFlag() { - return m_impl.getStateFlag(); - } - - @Override - public void replaceNaNs(int semantics, double value) { - m_impl.replaceNaNs(semantics, value); - } + Serializable { + MultiPathImpl m_impl; + + @Override + public VertexDescription getDescription() { + return m_impl.getDescription(); + } + + @Override + public void assignVertexDescription(VertexDescription src) { + m_impl.assignVertexDescription(src); + } + + @Override + public void mergeVertexDescription(VertexDescription src) { + m_impl.mergeVertexDescription(src); + } + + @Override + public void addAttribute(int semantics) { + m_impl.addAttribute(semantics); + } + + @Override + public void dropAttribute(int semantics) { + m_impl.dropAttribute(semantics); + } + + @Override + public void dropAllAttributes() { + m_impl.dropAllAttributes(); + } + + @Override + public int getPointCount() { + return m_impl.getPointCount(); + } + + @Override + public Point getPoint(int index) { + return m_impl.getPoint(index); + } + + @Override + public void setPoint(int index, Point point) { + m_impl.setPoint(index, point); + } + + @Override + public boolean isEmpty() { + return m_impl.isEmptyImpl(); + } + + @Override + public double calculateArea2D() { + return m_impl.calculateArea2D(); + } + + @Override + public double calculateLength2D() { + return m_impl.calculateLength2D(); + } + + public double calculatePathLength2D(int pathIndex) { + return m_impl.calculatePathLength2D(pathIndex); + } + + @Override + public double getAttributeAsDbl(int semantics, int index, int ordinate) { + return m_impl.getAttributeAsDbl(semantics, index, ordinate); + } + + @Override + public int getAttributeAsInt(int semantics, int index, int ordinate) { + return m_impl.getAttributeAsInt(semantics, index, ordinate); + } + + @Override + public void setAttribute(int semantics, int index, int ordinate, + double value) { + m_impl.setAttribute(semantics, index, ordinate, value); + } + + @Override + public void setAttribute(int semantics, int index, int ordinate, int value) { + m_impl.setAttribute(semantics, index, ordinate, value); + } + + @Override + public Point2D getXY(int index) { + return m_impl.getXY(index); + } + + @Override + public void getXY(int index, Point2D pt) { + m_impl.getXY(index, pt); + } + + @Override + public void setXY(int index, Point2D pt) { + m_impl.setXY(index, pt); + } + + @Override + Point3D getXYZ(int index) { + return m_impl.getXYZ(index); + } + + @Override + void setXYZ(int index, Point3D pt) { + m_impl.setXYZ(index, pt); + } + + @Override + public void queryEnvelope(Envelope env) { + m_impl.queryEnvelope(env); + } + + @Override + public void queryEnvelope2D(Envelope2D env) { + m_impl.queryEnvelope2D(env); + } + + public void queryPathEnvelope2D(int pathIndex, Envelope2D env) { + m_impl.queryPathEnvelope2D(pathIndex, env); + } + + @Override + void queryEnvelope3D(Envelope3D env) { + m_impl.queryEnvelope3D(env); + } + + public void queryLooseEnvelope(Envelope2D env) { + m_impl.queryLooseEnvelope2D(env); + } + + void queryLooseEnvelope(Envelope3D env) { + m_impl.queryLooseEnvelope3D(env); + } + + @Override + public Envelope1D queryInterval(int semantics, int ordinate) { + return m_impl.queryInterval(semantics, ordinate); + } + + @Override + public void copyTo(Geometry dst) { + if (getType() != dst.getType()) + throw new IllegalArgumentException(); + + m_impl.copyTo((Geometry) dst._getImpl()); + } + + @Override + public Geometry getBoundary() { + return m_impl.getBoundary(); + } + + @Override + public void queryCoordinates(Point2D[] dst) { + m_impl.queryCoordinates(dst); + } + + public void queryCoordinates(Point2D[] dst, int dstSize, int beginIndex, int endIndex) { + m_impl.queryCoordinates(dst, dstSize, beginIndex, endIndex); + } + + @Override + void queryCoordinates(Point3D[] dst) { + m_impl.queryCoordinates(dst); + } + + @Override + public void queryCoordinates(Point[] dst) { + m_impl.queryCoordinates(dst); + + } + + /** + * Returns TRUE if the multipath contains non-linear segments. + */ + boolean hasNonLinearSegments() { + return m_impl.hasNonLinearSegments(); + } + + /** + * Returns total segment count in the MultiPath. + */ + public int getSegmentCount() { + return m_impl.getSegmentCount(); + } + + /** + * Returns the segment count in the given multipath path. + * + * @param pathIndex The path to determine the segment. + * @return The segment of the multipath. + */ + public int getSegmentCount(int pathIndex) { + int segCount = getPathSize(pathIndex); + if (!isClosedPath(pathIndex)) + segCount--; + return segCount; + } + + /** + * Appends all paths from another multipath. + * + * @param src The multipath to append to this multipath. + * @param bReversePaths TRUE if the multipath is added should be added with its paths + * reversed. + */ + public void add(MultiPath src, boolean bReversePaths) { + m_impl.add((MultiPathImpl) src._getImpl(), bReversePaths); + } + + /** + * Copies a path from another multipath. + * + * @param src The multipath to copy from. + * @param srcPathIndex The index of the path in the the source MultiPath. + * @param bForward When FALSE, the points are inserted in reverse order. + */ + public void addPath(MultiPath src, int srcPathIndex, boolean bForward) { + m_impl.addPath((MultiPathImpl) src._getImpl(), srcPathIndex, bForward); + } + + /** + * Adds a new path to this multipath. + * + * @param points The array of points to add to this multipath. + * @param count The number of points added to the mulitpath. + * @param bForward When FALSE, the points are inserted in reverse order. + */ + void addPath(Point2D[] points, int count, boolean bForward) { + m_impl.addPath(points, count, bForward); + } + + /** + * Adds segments from a source multipath to this MultiPath. + * + * @param src The source MultiPath to add segments from. + * @param srcPathIndex The index of the path in the the source MultiPath. + * @param srcSegmentFrom The index of first segment in the path to start adding from. + * The value has to be between 0 and + * src.getSegmentCount(srcPathIndex) - 1. + * @param srcSegmentCount The number of segments to add. If 0, the function does + * nothing. + * @param bStartNewPath When true, a new path is added and segments are added to it. + * Otherwise the segments are added to the last path of this + * MultiPath. + *

+ * If bStartNewPath false, the first point of the first source + * segment is not added. This is done to ensure proper connection + * to existing segments. When the source path is closed, and the + * closing segment is among those to be added, it is added also + * as a closing segment, not as a real segment. Use add_segment + * instead if you do not like that behavior. + *

+ * This MultiPath obtains all missing attributes from the src + * MultiPath. + */ + public void addSegmentsFromPath(MultiPath src, int srcPathIndex, + int srcSegmentFrom, int srcSegmentCount, boolean bStartNewPath) { + m_impl.addSegmentsFromPath((MultiPathImpl) src._getImpl(), + srcPathIndex, srcSegmentFrom, srcSegmentCount, bStartNewPath); + } + + /** + * Adds a new segment to this multipath. + * + * @param segment The segment to be added to this mulitpath. + * @param bStartNewPath TRUE if a new path will be added. + */ + public void addSegment(Segment segment, boolean bStartNewPath) { + m_impl.addSegment(segment, bStartNewPath); + } + + /** + * Reverses the order of the vertices in each path. + */ + public void reverseAllPaths() { + m_impl.reverseAllPaths(); + } + + /** + * Reverses the order of vertices in the path. + * + * @param pathIndex The start index of the path to reverse the order. + */ + public void reversePath(int pathIndex) { + m_impl.reversePath(pathIndex); + } + + /** + * Removes the path at the given index. + * + * @param pathIndex The start index to remove the path. + */ + public void removePath(int pathIndex) { + m_impl.removePath(pathIndex); + } + + /** + * Inserts a path from another multipath. + * + * @param pathIndex The start index of the multipath to insert. + * @param src The multipath to insert into this multipath. Can be the same + * as the multipath being modified. + * @param srcPathIndex The start index to insert the path into the multipath. + * @param bForward When FALSE, the points are inserted in reverse order. + */ + public void insertPath(int pathIndex, MultiPath src, int srcPathIndex, + boolean bForward) { + m_impl.insertPath(pathIndex, (MultiPathImpl) src._getImpl(), + srcPathIndex, bForward); + } + + /** + * Inserts a path from an array of 2D Points. + * + * @param pathIndex The path index of the multipath to place the new path. + * @param points The array of points defining the new path. + * @param pointsOffset The offset into the array to start reading. + * @param count The number of points to insert into the new path. + * @param bForward When FALSE, the points are inserted in reverse order. + */ + void insertPath(int pathIndex, Point2D[] points, int pointsOffset, + int count, boolean bForward) { + m_impl.insertPath(pathIndex, points, pointsOffset, count, bForward); + } + + /** + * Inserts vertices from the given multipath into this multipath. All added + * vertices are connected by linear segments with each other and with the + * existing vertices. + * + * @param pathIndex The path index in this multipath to insert points to. Must + * correspond to an existing path. + * @param beforePointIndex The point index before all other vertices to insert in the + * given path of this multipath. This value must be between 0 and + * GetPathSize(pathIndex), or -1 to insert points at the end of + * the given path. + * @param src The source multipath. + * @param srcPathIndex The source path index to copy points from. + * @param srcPointIndexFrom The start point in the source path to start copying from. + * @param srcPointCount The count of points to add. + * @param bForward When FALSE, the points are inserted in reverse order. + */ + public void insertPoints(int pathIndex, int beforePointIndex, + MultiPath src, int srcPathIndex, int srcPointIndexFrom, + int srcPointCount, boolean bForward) { + m_impl.insertPoints(pathIndex, beforePointIndex, + (MultiPathImpl) src._getImpl(), srcPathIndex, + srcPointIndexFrom, srcPointCount, bForward); + } + + /** + * Inserts a part of a path from the given array. + * + * @param pathIndex The path index in this class to insert points to. Must + * correspond to an existing path. + * @param beforePointIndex The point index in the given path of this MultiPath before + * which the vertices need to be inserted. This value must be + * between 0 and GetPathSize(pathIndex), or -1 to insert points + * at the end of the given path. + * @param src The source array + * @param srcPointIndexFrom The start point in the source array to start copying from. + * @param srcPointCount The count of points to add. + * @param bForward When FALSE, the points are inserted in reverse order. + */ + void insertPoints(int pathIndex, int beforePointIndex, Point2D[] src, + int srcPointIndexFrom, int srcPointCount, boolean bForward) { + m_impl.insertPoints(pathIndex, beforePointIndex, src, + srcPointIndexFrom, srcPointCount, bForward); + } + + /** + * Inserts a point. + * + * @param pathIndex The path index in this class to insert the point to. Must + * correspond to an existing path. + * @param beforePointIndex The point index in the given path of this multipath. This + * value must be between 0 and GetPathSize(pathIndex), or -1 to + * insert the point at the end of the given path. + * @param pt The point to be inserted. + */ + void insertPoint(int pathIndex, int beforePointIndex, Point2D pt) { + m_impl.insertPoint(pathIndex, beforePointIndex, pt); + } + + /** + * Inserts a point. + * + * @param pathIndex The path index in this class to insert the point to. Must + * correspond to an existing path. + * @param beforePointIndex The point index in the given path of this multipath. This + * value must be between 0 and GetPathSize(pathIndex), or -1 to + * insert the point at the end of the given path. + * @param pt The point to be inserted. + */ + public void insertPoint(int pathIndex, int beforePointIndex, Point pt) { + m_impl.insertPoint(pathIndex, beforePointIndex, pt); + } + + /** + * Removes a point at a given index. + * + * @param pathIndex The path from whom to remove the point. + * @param pointIndex The index of the point to be removed. + */ + public void removePoint(int pathIndex, int pointIndex) { + m_impl.removePoint(pathIndex, pointIndex); + } + + /** + * Returns the number of paths in this multipath. + * + * @return The number of paths in this multipath. + */ + public int getPathCount() { + return m_impl.getPathCount(); + } + + /** + * Returns the number of vertices in a path. + * + * @param pathIndex The index of the path to return the number of vertices from. + * @return The number of vertices in a path. + */ + public int getPathSize(int pathIndex) { + return m_impl.getPathSize(pathIndex); + } + + /** + * Returns the start index of the path. + * + * @param pathIndex The index of the path to return the start index from. + * @return The start index of the path. + */ + public int getPathStart(int pathIndex) { + return m_impl.getPathStart(pathIndex); + } + + /** + * Returns the index immediately following the last index of the path. + * + * @param pathIndex The index of the path to return the end index from. + * @return Integer index after last index of path + */ + public int getPathEnd(int pathIndex) { + return m_impl.getPathEnd(pathIndex); + } + + /** + * Returns the path index from the point index. This is O(log N) operation. + * + * @param pointIndex The index of the point. + * @return The index of the path. + */ + public int getPathIndexFromPointIndex(int pointIndex) { + return m_impl.getPathIndexFromPointIndex(pointIndex); + } + + /** + * Starts a new path at given coordinates. + * + * @param x The X coordinate of the start point. + * @param y The Y coordinate of the start point. + */ + public void startPath(double x, double y) { + m_impl.startPath(x, y); + } + + void startPath(Point2D point) { + m_impl.startPath(point); + } + + void startPath(Point3D point) { + m_impl.startPath(point); + } + + /** + * Starts a new path at a point. + * + * @param point The point to start the path from. + */ + public void startPath(Point point) { + m_impl.startPath(point); + } + + /** + * Adds a line segment from the last point to the given end coordinates. + * + * @param x The X coordinate to the end point. + * @param y The Y coordinate to the end point. + */ + public void lineTo(double x, double y) { + m_impl.lineTo(x, y); + } + + void lineTo(Point2D endPoint) { + m_impl.lineTo(endPoint); + } + + void lineTo(Point3D endPoint) { + m_impl.lineTo(endPoint); + } + + /** + * Adds a Line Segment to the given end point. + * + * @param endPoint The end point to which the newly added line segment should + * point. + */ + public void lineTo(Point endPoint) { + m_impl.lineTo(endPoint); + } + + /** + * Adds a Cubic Bezier Segment to the current Path. The Bezier Segment + * connects the current last Point and the given endPoint. + */ + void bezierTo(Point2D controlPoint1, Point2D controlPoint2, Point2D endPoint) { + m_impl.bezierTo(controlPoint1, controlPoint2, endPoint); + } + + /** + * Closes the last path of this multipath with a line segment. The closing + * segment is a segment that connects the last and the first points of the + * path. This is a virtual segment. The first point is not duplicated to + * close the path. + *

+ * Call this method only for polylines. For polygons this method is + * implicitly called for the Polygon class. + */ + public void closePathWithLine() { + m_impl.closePathWithLine(); + } + + /** + * Closes last path of the MultiPath with the Bezier Segment. + *

+ * The start point of the Bezier is the last point of the path and the last + * point of the bezier is the first point of the path. + */ + void closePathWithBezier(Point2D controlPoint1, Point2D controlPoint2) { + m_impl.closePathWithBezier(controlPoint1, controlPoint2); + } + + /** + * Closes last path of the MultiPath with the Arc Segment. + */ + void closePathWithArc() { + throw new RuntimeException("not implemented"); + } + + /** + * Closes all open paths by adding an implicit line segment from the end + * point to the start point. Call this method only for polylines.For + * polygons this method is implicitly called for the Polygon class. + */ + public void closeAllPaths() { + m_impl.closeAllPaths(); + } + + /** + * Indicates if the given path is closed (represents a ring). A closed path + * has a virtual segment that connects the last and the first points of the + * path. The first point is not duplicated to close the path. Polygons + * always have all paths closed. + * + * @param pathIndex The index of the path to check to be closed. + * @return TRUE if the given path is closed (represents a Ring). + */ + public boolean isClosedPath(int pathIndex) { + return m_impl.isClosedPath(pathIndex); + } + + public boolean isClosedPathInXYPlane(int pathIndex) { + return m_impl.isClosedPathInXYPlane(pathIndex); + } + + /** + * Returns TRUE if the given path might have non-linear segments. + */ + boolean hasNonLinearSegments(int pathIndex) { + return m_impl.hasNonLinearSegments(pathIndex); + } + + /** + * Adds a rectangular closed Path to the MultiPathImpl. + * + * @param envSrc is the source rectangle. + * @param bReverse Creates reversed path. + */ + public void addEnvelope(Envelope2D envSrc, boolean bReverse) { + m_impl.addEnvelope(envSrc, bReverse); + } + + /** + * Adds a rectangular closed path to this multipath. + * + * @param envSrc Is the envelope to add to this mulitpath. + * @param bReverse Adds the path reversed (counter-clockwise). + */ + public void addEnvelope(Envelope envSrc, boolean bReverse) { + m_impl.addEnvelope(envSrc, bReverse); + } + + /** + * Returns a SegmentIterator that is set right before the beginning of the + * multipath. Calling nextPath() will set the iterator to the first path of + * this multipath. + * + * @return The SegmentIterator for this mulitpath. + */ + public SegmentIterator querySegmentIterator() { + return new SegmentIterator(m_impl.querySegmentIterator()); + } + + /** + * Returns a SegmentIterator that is set to a specific vertex of the + * MultiPath. The call to nextSegment() will return the segment that starts + * at the vertex. Calling PreviousSegment () will return the segment that + * starts at the previous vertex. + * + * @param startVertexIndex The start index of the SegementIterator. + * @return The SegmentIterator for this mulitpath at the specified vertex. + */ + public SegmentIterator querySegmentIteratorAtVertex(int startVertexIndex) { + return new SegmentIterator( + m_impl.querySegmentIteratorAtVertex(startVertexIndex)); + } + + @Override + public void setEmpty() { + m_impl.setEmpty(); + } + + @Override + public void applyTransformation(Transformation2D transform) { + m_impl.applyTransformation(transform); + } + + @Override + void applyTransformation(Transformation3D transform) { + m_impl.applyTransformation(transform); + } + + @Override + protected Object _getImpl() { + return m_impl; + } + + /** + * Returns the hash code for the multipath. + */ + @Override + public int hashCode() { + return m_impl.hashCode(); + } + + @Override + public void getPointByVal(int index, Point outPoint) { + m_impl.getPointByVal(index, outPoint); + } + + @Override + public void setPointByVal(int index, Point point) { + m_impl.setPointByVal(index, point); + } + + @Override + public int getStateFlag() { + return m_impl.getStateFlag(); + } + + @Override + public void replaceNaNs(int semantics, double value) { + m_impl.replaceNaNs(semantics, value); + } } diff --git a/src/main/java/com/esri/core/geometry/MultiPathImpl.java b/src/main/java/com/esri/core/geometry/MultiPathImpl.java index a1963aff..c9400ee0 100644 --- a/src/main/java/com/esri/core/geometry/MultiPathImpl.java +++ b/src/main/java/com/esri/core/geometry/MultiPathImpl.java @@ -33,31 +33,31 @@ final class MultiPathImpl extends MultiVertexGeometryImpl { protected double m_cachedLength2D; protected double m_cachedArea2D; - protected AttributeStreamOfDbl m_cachedRingAreas2D; - protected boolean m_bPathStarted; - - // Contains starting points of the parts. The size is getPartCount() + 1. - // First element is 0, last element is equal to the getPointCount(). - protected AttributeStreamOfInt32 m_paths; - // same size as m_parts. Holds flags for each part (whether the part is - // closed, etc. See PathFlags) - protected AttributeStreamOfInt8 m_pathFlags; - // The segment flags. Size is getPointCount(). This is not a vertex - // attribute, because we may want to use indexed access later (via an index - // buffer). - // Can be NULL if the MultiPathImpl contains straight lines only. - protected AttributeStreamOfInt8 m_segmentFlags; - // An index into the m_segmentParams stream. Size is getPointCount(). Can be - // NULL if the MultiPathImpl contains straight lines only. - protected AttributeStreamOfInt32 m_segmentParamIndex; - protected AttributeStreamOfDbl m_segmentParams; - protected int m_curveParamwritePoint; - private int m_currentPathIndex; - private int m_fill_rule = Polygon.FillRule.enumFillRuleOddEven; - - static int[] _segmentParamSizes = {0, 0, 6, 0, 8, 0}; // None, Line, - // Bezier, XXX, Arc, - // XXX; + protected AttributeStreamOfDbl m_cachedRingAreas2D; + protected boolean m_bPathStarted; + + // Contains starting points of the parts. The size is getPartCount() + 1. + // First element is 0, last element is equal to the getPointCount(). + protected AttributeStreamOfInt32 m_paths; + // same size as m_parts. Holds flags for each part (whether the part is + // closed, etc. See PathFlags) + protected AttributeStreamOfInt8 m_pathFlags; + // The segment flags. Size is getPointCount(). This is not a vertex + // attribute, because we may want to use indexed access later (via an index + // buffer). + // Can be NULL if the MultiPathImpl contains straight lines only. + protected AttributeStreamOfInt8 m_segmentFlags; + // An index into the m_segmentParams stream. Size is getPointCount(). Can be + // NULL if the MultiPathImpl contains straight lines only. + protected AttributeStreamOfInt32 m_segmentParamIndex; + protected AttributeStreamOfDbl m_segmentParams; + protected int m_curveParamwritePoint; + private int m_currentPathIndex; + private int m_fill_rule = Polygon.FillRule.enumFillRuleOddEven; + + static int[] _segmentParamSizes = { 0, 0, 6, 0, 8, 0 }; // None, Line, + // Bezier, XXX, Arc, + // XXX; @Override public long estimateMemorySize() @@ -66,8 +66,8 @@ public long estimateMemorySize() + (m_envelope != null ? m_envelope.estimateMemorySize() : 0) + (m_moveToPoint != null ? m_moveToPoint.estimateMemorySize() : 0) + (m_cachedRingAreas2D != null ? m_cachedRingAreas2D.estimateMemorySize() : 0) - + m_paths.estimateMemorySize() - + m_pathFlags.estimateMemorySize() + + (m_paths != null ? m_paths.estimateMemorySize() : 0) + + (m_pathFlags != null ? m_pathFlags.estimateMemorySize() : 0) + (m_segmentFlags != null ? m_segmentFlags.estimateMemorySize() : 0) + (m_segmentParamIndex != null ? m_segmentParamIndex.estimateMemorySize() : 0) + (m_segmentParams != null ? m_segmentParams.estimateMemorySize() : 0); @@ -77,6 +77,11 @@ public long estimateMemorySize() size += m_vertexAttributes[i].estimateMemorySize(); } } + + if (m_accelerators != null) { + size += m_accelerators.estimateMemorySize(); + } + return size; } @@ -84,2535 +89,2531 @@ public boolean hasNonLinearSegments() { return m_curveParamwritePoint > 0; } - // / Cpp /// - // Reviewed vs. Native Jan 11, 2011 - public MultiPathImpl(boolean bPolygon) { - m_bPolygon = bPolygon; - - m_bPathStarted = false; - m_curveParamwritePoint = 0; - m_cachedLength2D = 0; - m_cachedArea2D = 0; - m_pointCount = 0; - m_description = VertexDescriptionDesignerImpl.getDefaultDescriptor2D(); - m_cachedRingAreas2D = null; - m_currentPathIndex = 0; - } - - // Reviewed vs. Native Jan 11, 2011 - public MultiPathImpl(boolean bPolygon, VertexDescription description) { - if (description == null) - throw new IllegalArgumentException(); - - m_bPolygon = bPolygon; - - m_bPathStarted = false; - m_curveParamwritePoint = 0; - m_cachedLength2D = 0; - m_cachedArea2D = 0; - m_pointCount = 0; - m_description = description; - m_cachedRingAreas2D = null; - m_currentPathIndex = 0; - } - - // Reviewed vs. Native Jan 11, 2011 - protected void _initPathStartPoint() { - _touch(); - if (m_moveToPoint == null) - m_moveToPoint = new Point(m_description); - else - m_moveToPoint.assignVertexDescription(m_description); - } - - // Reviewed vs. Native Jan 11, 2011 - - /** - * Starts a new Path at the Point. - */ - public void startPath(double x, double y) { - Point2D endPoint = new Point2D(); - endPoint.x = x; - endPoint.y = y; - startPath(endPoint); - } - - // Reviewed vs. Native Jan 11, 2011 - public void startPath(Point2D point) { - _initPathStartPoint(); - m_moveToPoint.setXY(point); - m_bPathStarted = true; - } - - // Reviewed vs. Native Jan 11, 2011 - public void startPath(Point3D point) { - _initPathStartPoint(); - m_moveToPoint.setXYZ(point); - assignVertexDescription(m_moveToPoint.getDescription()); - m_bPathStarted = true; - } - - // Reviewed vs. Native Jan 11, 2011 - public void startPath(Point point) { - if (point.isEmpty()) - throw new IllegalArgumentException();// throw new - // IllegalArgumentException(); - - mergeVertexDescription(point.getDescription()); - _initPathStartPoint(); - point.copyTo(m_moveToPoint); - - // TODO check MultiPathImpl.cpp comment - // "//the description will be merged later" - // assignVertexDescription(m_moveToPoint.getDescription()); - m_bPathStarted = true; - } - - // Reviewed vs. Native Jan 11, 2011 - protected void _beforeNewSegment(int resizeBy) { - // Called for each new segment being added. - if (m_bPathStarted) { - _initPathStartPoint();// make sure the m_movetoPoint exists and has - // right vertex description - - // The new path is started. Need to grow m_parts and m_pathFlags. - if (m_paths == null) { - m_paths = (AttributeStreamOfInt32) AttributeStreamBase - .createIndexStream(2); - m_paths.write(0, 0); - m_pathFlags = (AttributeStreamOfInt8) AttributeStreamBase - .createByteStream(2, (byte) 0); - } else { - // _ASSERT(m_parts.size() >= 2); - m_paths.resize(m_paths.size() + 1, 0); - m_pathFlags.resize(m_pathFlags.size() + 1, 0); - } - - if (m_bPolygon) { - // Mark the path as closed - m_pathFlags.write(m_pathFlags.size() - 2, - (byte) PathFlags.enumClosed); - } - - resizeBy++; // +1 for the StartPath point. - } - - int oldcount = m_pointCount; - m_paths.write(m_paths.size() - 1, m_pointCount + resizeBy); // The - // NotifyModified - // will - // update - // the - // m_pointCount - // with this - // value. - _resizeImpl(oldcount + resizeBy); - m_pathFlags.write(m_paths.size() - 1, (byte) 0); - - if (m_bPathStarted) { - setPointByVal(oldcount, m_moveToPoint);// setPoint(oldcount, - // m_moveToPoint); //finally - // set the start point to - // the geometry - m_bPathStarted = false; - } - } - - // Reviewed vs. Native Jan 11, 2011 - protected void _finishLineTo() { - } - - // Reviewed vs. Native Jan 11, 2011 - - /** - * adds a Line Segment from the last Point to the given endPoint. - */ - public void lineTo(double x, double y) { - _beforeNewSegment(1); - setXY(m_pointCount - 1, x, y); - _finishLineTo(); - // Point2D endPoint = new Point2D(); - // endPoint.x = x; endPoint.y = y; - // lineTo(endPoint); - } - - // Reviewed vs. Native Jan 11, 2011 - public void lineTo(Point2D endPoint) { - _beforeNewSegment(1); - setXY(m_pointCount - 1, endPoint); - _finishLineTo(); - } - - // Reviewed vs. Native Jan 11, 2011 - public void lineTo(Point3D endPoint) { - _beforeNewSegment(1); - setXYZ(m_pointCount - 1, endPoint); - _finishLineTo(); - } - - // Reviewed vs. Native Jan 11, 2011 - public void lineTo(Point endPoint) { - _beforeNewSegment(1); - setPointByVal(m_pointCount - 1, endPoint); - _finishLineTo(); - } - - // Reviewed vs. Native Jan 11, 2011 - protected void _initSegmentData(int sz) { - if (m_segmentParamIndex == null) { - m_segmentFlags = (AttributeStreamOfInt8) AttributeStreamBase - .createByteStream(m_pointCount, - (byte) SegmentFlags.enumLineSeg); - m_segmentParamIndex = (AttributeStreamOfInt32) AttributeStreamBase - .createIndexStream(m_pointCount, -1); - } - - int size = m_curveParamwritePoint + sz; - if (m_segmentParams == null) { - m_segmentParams = (AttributeStreamOfDbl) AttributeStreamBase - .createAttributeStreamWithPersistence( - VertexDescription.Persistence.enumDouble, size); - } else { - m_segmentParams.resize(size, 0); - } - } - - // Reviewed vs. Native Jan 11, 2011 - protected void _finishBezierTo() { - // _ASSERT(m_segmentFlags != null); - // _ASSERT(m_segmentParamIndex != null); - - m_segmentFlags.write(m_pointCount - 2, - (byte) SegmentFlags.enumBezierSeg); - } - - // Reviewed vs. Native Jan 11, 2011 - - /** - * adds a Cubic Bezier Segment to the current Path. The Bezier Segment - * connects the current last Point and the given endPoint. - */ - public void bezierTo(Point2D controlPoint1, Point2D controlPoint2, - Point2D endPoint) { - _beforeNewSegment(1); - setXY(m_pointCount - 1, endPoint); - double z; - _initSegmentData(6); - m_pathFlags.setBits(m_pathFlags.size() - 1, - (byte) PathFlags.enumHasNonlinearSegments); - m_segmentParamIndex.write(m_pointCount - 2, m_curveParamwritePoint); - m_curveParamwritePoint += 6; - int curveIndex = m_curveParamwritePoint; - m_segmentParams.write(curveIndex, controlPoint1.x); - m_segmentParams.write(curveIndex + 1, controlPoint1.y); - z = 0;// TODO: calculate me. - m_segmentParams.write(curveIndex + 2, z); - m_segmentParams.write(curveIndex + 3, controlPoint2.x); - m_segmentParams.write(curveIndex + 4, controlPoint2.y); - z = 0;// TODO: calculate me. - m_segmentParams.write(curveIndex + 5, z); - _finishBezierTo(); - } - - // Reviewed vs. Native Jan 11, 2011 - public void openPath(int pathIndex) { - _touch(); - if (m_bPolygon) - throw GeometryException.GeometryInternalError();// do not call this - // method on a - // polygon - - int pathCount = getPathCount(); - if (pathIndex > getPathCount()) - throw new IllegalArgumentException(); - - if (m_pathFlags == null) - throw GeometryException.GeometryInternalError(); - - m_pathFlags.clearBits(pathIndex, (byte) PathFlags.enumClosed); - } - - public void openPathAndDuplicateStartVertex(int pathIndex) { - _touch(); - if (m_bPolygon) - throw GeometryException.GeometryInternalError();// do not call this - // method on a - // polygon - - int pathCount = getPathCount(); - if (pathIndex > pathCount) - throw GeometryException.GeometryInternalError(); - - if (!isClosedPath(pathIndex)) - return;// do not open if open - - if (m_pathFlags == null)// if (!m_pathFlags) - throw GeometryException.GeometryInternalError(); - - int oldPointCount = m_pointCount; - int pathIndexStart = getPathStart(pathIndex); - int pathIndexEnd = getPathEnd(pathIndex); - _resizeImpl(m_pointCount + 1); // resize does not write into m_paths - // anymore! - _verifyAllStreams(); - for (int iattr = 0, nattr = m_description.getAttributeCount(); iattr < nattr; iattr++) { - if (m_vertexAttributes[iattr] != null)// if - // (m_vertexAttributes[iattr]) - { - int semantics = m_description._getSemanticsImpl(iattr); - int comp = VertexDescription.getComponentCount(semantics); - m_vertexAttributes[iattr].insertRange(comp * pathIndexEnd, - m_vertexAttributes[iattr], comp * pathIndexStart, comp, - true, 1, comp * oldPointCount); - } - } - - for (int ipath = pathCount; ipath > pathIndex; ipath--) { - int iend = m_paths.read(ipath); - m_paths.write(ipath, iend + 1); - } - - m_pathFlags.clearBits(pathIndex, (byte) PathFlags.enumClosed); - } - - // Reviewed vs. Native Jan 11, 2011 - // Major Changes on 16th of January - public void openAllPathsAndDuplicateStartVertex() { - _touch(); - if (m_bPolygon) - throw GeometryException.GeometryInternalError();// do not call this - // method on a - // polygon - - if (m_pathFlags == null)// if (!m_pathFlags) - throw GeometryException.GeometryInternalError(); - - _verifyAllStreams(); - - int closedPathCount = 0; - int pathCount = getPathCount(); - for (int i = 0; i < pathCount; i++) { - if (m_pathFlags.read(i) == (byte) PathFlags.enumClosed) { - closedPathCount++; - } - } - - for (int iattr = 0, nattr = m_description.getAttributeCount(); iattr < nattr; iattr++) { - if (m_vertexAttributes[iattr] != null) { - int semantics = m_description._getSemanticsImpl(iattr);// int - // semantics - // = - // m_description._getSemanticsImpl(iattr); - int comp = VertexDescription.getComponentCount(semantics); - int newSize = comp * (m_pointCount + closedPathCount); - m_vertexAttributes[iattr].resize(newSize); - - int offset = closedPathCount; - int ipath = pathCount; - for (int i = m_pointCount - 1; i >= 0; i--) { - if (i + 1 == m_paths.read(ipath)) { - ipath--; - if (m_pathFlags.read(ipath) == (byte) PathFlags.enumClosed) { - int istart = m_paths.read(ipath); - - for (int c = 0; c < comp; c++) { - double v = m_vertexAttributes[iattr] - .readAsDbl(comp * istart + c); - m_vertexAttributes[iattr].writeAsDbl(comp - * (offset + i) + c, v); - } - - if (--offset == 0) - break; - } - } - - for (int c = 0; c < comp; c++) { - double v = m_vertexAttributes[iattr].readAsDbl(comp * i - + c); - m_vertexAttributes[iattr].writeAsDbl(comp - * (offset + i) + c, v); - } - } - } - } - - int offset = closedPathCount; - for (int ipath = pathCount; ipath > 0; ipath--) { - int iend = m_paths.read(ipath); - m_paths.write(ipath, iend + offset); - - if (m_pathFlags.read(ipath - 1) == (byte) PathFlags.enumClosed) { - m_pathFlags.clearBits(ipath - 1, (byte) PathFlags.enumClosed); - - if (--offset == 0) { - break; - } - } - } - - m_pointCount += closedPathCount; - } - - void closePathWithLine(int path_index) { - // touch_(); - throwIfEmpty(); - - byte pf = m_pathFlags.read(path_index); - m_pathFlags.write(path_index, (byte) (pf | PathFlags.enumClosed)); - if (m_segmentFlags != null) { - int vindex = getPathEnd(path_index) - 1; - m_segmentFlags.write(vindex, (byte) SegmentFlags.enumLineSeg); - m_segmentParamIndex.write(vindex, -1); - } - } - - void closePathWithLine() { - throwIfEmpty(); - m_bPathStarted = false; - closePathWithLine(getPathCount() - 1); - } - - // Reviewed vs. Native Jan 11, 2011 - - /** - * Closes all open curves by adding an implicit line segment from the end - * point to the start point. - */ - public void closeAllPaths() { - _touch(); - if (m_bPolygon || isEmptyImpl()) - return; - - m_bPathStarted = false; - - for (int ipath = 0, npart = m_paths.size() - 1; ipath < npart; ipath++) { - if (isClosedPath(ipath)) - continue; - - byte pf = m_pathFlags.read(ipath); - m_pathFlags.write(ipath, (byte) (pf | PathFlags.enumClosed)); - // if (m_segmentFlags) - // { - // m_segmentFlags.write(m_pointCount - 1, - // (byte)SegmentFlags.LineSeg)); - // m_segmentParamIndex.write(m_pointCount - 1, -1); - // } - } - } - - // Reviewed vs. Native Jan 11, 2011 - - /** - * Returns the size of the segment data for the given segment type. - * - * @param flag is one of the segment flags from the SegmentFlags enum. - * @return the size of the segment params as the number of doubles. - */ - public static int getSegmentDataSize(byte flag) { - return _segmentParamSizes[flag]; - } - - // Reviewed vs. Native Jan 11, 2011 - - /** - * Closes last path of the MultiPathImpl with the Bezier Segment. - *

- * The start point of the Bezier is the last point of the path and the last - * point of the bezier is the first point of the path. - */ - public void closePathWithBezier(Point2D controlPoint1, Point2D controlPoint2) { - _touch(); - if (isEmptyImpl()) - throw new GeometryException( - "Invalid call. This operation cannot be performed on an empty geometry."); - - m_bPathStarted = false; - - int pathIndex = m_paths.size() - 2; - byte pf = m_pathFlags.read(pathIndex); - m_pathFlags - .write(pathIndex, - (byte) (pf | PathFlags.enumClosed | PathFlags.enumHasNonlinearSegments)); - _initSegmentData(6); - - byte oldType = m_segmentFlags - .read((byte) ((m_pointCount - 1) & SegmentFlags.enumSegmentMask)); - m_segmentFlags.write(m_pointCount - 1, - (byte) (SegmentFlags.enumBezierSeg)); - - int curveIndex = m_curveParamwritePoint; - if (getSegmentDataSize(oldType) < getSegmentDataSize((byte) SegmentFlags.enumBezierSeg)) { - m_segmentParamIndex.write(m_pointCount - 1, m_curveParamwritePoint); - m_curveParamwritePoint += 6; - } else { - // there was a closing bezier curve or an arc here. We can reuse the - // storage. - curveIndex = m_segmentParamIndex.read(m_pointCount - 1); - } - - double z; - m_segmentParams.write(curveIndex, controlPoint1.x); - m_segmentParams.write(curveIndex + 1, controlPoint1.y); - z = 0;// TODO: calculate me. - m_segmentParams.write(curveIndex + 2, z); - - m_segmentParams.write(curveIndex + 3, controlPoint2.x); - m_segmentParams.write(curveIndex + 4, controlPoint2.y); - z = 0;// TODO: calculate me. - m_segmentParams.write(curveIndex + 5, z); - } - - // Reviewed vs. Native Jan 11, 2011 - - /** - * Returns True if the given path is closed (represents a Ring). - */ - public boolean isClosedPath(int ipath) { - // Should we make a function called _UpdateClosedPathFlags and call it - // here? - return ((byte) (m_pathFlags.read(ipath) & PathFlags.enumClosed)) != 0; - } - - public boolean isClosedPathInXYPlane(int path_index) { - if (isClosedPath(path_index)) - return true; - int istart = getPathStart(path_index); - int iend = getPathEnd(path_index) - 1; - if (istart > iend) - return false; - Point2D ptS = getXY(istart); - Point2D ptE = getXY(iend); - return ptS.isEqual(ptE); - } - - // Reviewed vs. Native Jan 11, 2011 - - /** - * Returns True if the given path might have non-linear segments. - */ - public boolean hasNonLinearSegments(int ipath) { - // Should we make a function called _UpdateHasNonLinearSegmentsFlags and - // call it here? - return (m_pathFlags.read(ipath) & PathFlags.enumHasNonlinearSegments) != 0; - } - - // Reviewed vs. Native Jan 11, 2011 - public void addSegment(Segment segment, boolean bStartNewPath) { - mergeVertexDescription(segment.getDescription()); - if (segment.getType() == Type.Line) { - Point point = new Point(); - if (bStartNewPath || isEmpty()) { - segment.queryStart(point); - startPath(point); - } - - segment.queryEnd(point); - lineTo(point); - } else { - throw GeometryException.GeometryInternalError(); - } - } - - // Reviewed vs. Native Jan 11, 2011 - - /** - * adds a rectangular closed Path to the MultiPathImpl. - * - * @param envSrc is the source rectangle. - * @param bReverse Creates reversed path. - */ - public void addEnvelope(Envelope2D envSrc, boolean bReverse) { - boolean bWasEmpty = m_pointCount == 0; - - startPath(envSrc.xmin, envSrc.ymin); - if (bReverse) { - lineTo(envSrc.xmax, envSrc.ymin); - lineTo(envSrc.xmax, envSrc.ymax); - lineTo(envSrc.xmin, envSrc.ymax); - } else { - lineTo(envSrc.xmin, envSrc.ymax); - lineTo(envSrc.xmax, envSrc.ymax); - lineTo(envSrc.xmax, envSrc.ymin); - } - - closePathWithLine(); - m_bPathStarted = false; - - if (bWasEmpty && !bReverse) { - _setDirtyFlag(DirtyFlags.DirtyIsEnvelope, false);// now we no(sic?) - // the polypath - // is envelope - } - } - - // Reviewed vs. Native Jan 11, 2011 - - /** - * adds a rectangular closed Path to the MultiPathImpl. - * - * @param envSrc is the source rectangle. - * @param bReverse Creates reversed path. - */ - public void addEnvelope(Envelope envSrc, boolean bReverse) { - if (envSrc.isEmpty()) - return; - - boolean bWasEmpty = m_pointCount == 0; - Point pt = new Point(m_description);// getDescription()); - for (int i = 0, n = 4; i < n; i++) { - int j = bReverse ? n - i - 1 : i; - - envSrc.queryCornerByVal(j, pt); - if (i == 0) - startPath(pt); - else - lineTo(pt); - } - - closePathWithLine(); - m_bPathStarted = false; - - if (bWasEmpty && !bReverse) - _setDirtyFlag(DirtyFlags.DirtyIsEnvelope, false);// now we know the - // polypath is - // envelope - } - - // Reviewed vs. Native Jan 11, 2011 - public void add(MultiPathImpl src, boolean bReversePaths) { - for (int i = 0; i < src.getPathCount(); i++) - addPath(src, i, !bReversePaths); - } - - public void addPath(MultiPathImpl src, int srcPathIndex, boolean bForward) { - insertPath(-1, src, srcPathIndex, bForward); - } - - // Reviewed vs. Native Jan 11, 2011 Significant changes to last for loop - public void addPath(Point2D[] _points, int count, boolean bForward) { - insertPath(-1, _points, 0, count, bForward); - } - - public void addSegmentsFromPath(MultiPathImpl src, int src_path_index, - int src_segment_from, int src_segment_count, - boolean b_start_new_path) { - if (!b_start_new_path && getPathCount() == 0) - b_start_new_path = true; - - if (src_path_index < 0) - src_path_index = src.getPathCount() - 1; - - if (src_path_index >= src.getPathCount() || src_segment_from < 0 - || src_segment_count < 0 - || src_segment_count > src.getSegmentCount(src_path_index)) - throw new GeometryException("index out of bounds"); - - if (src_segment_count == 0) - return; - - boolean bIncludesClosingSegment = src.isClosedPath(src_path_index) - && src_segment_from + src_segment_count == src - .getSegmentCount(src_path_index); - - if (bIncludesClosingSegment && src_segment_count == 1) - return;// cannot add a closing segment alone. - - m_bPathStarted = false; - - mergeVertexDescription(src.getDescription()); - int src_point_count = src_segment_count; - int srcFromPoint = src.getPathStart(src_path_index) + src_segment_from - + 1; - if (b_start_new_path)// adding a new path. - { - src_point_count++;// add start point. - srcFromPoint--; - } - - if (bIncludesClosingSegment) { - src_point_count--; - } - - int oldPointCount = m_pointCount; - _resizeImpl(m_pointCount + src_point_count); - _verifyAllStreams(); - - if (b_start_new_path) { - if (src_point_count == 0) - return;// happens when adding a single closing segment to the - // new path - - m_paths.add(m_pointCount); - - byte flags = src.m_pathFlags.read(src_path_index); - flags &= ~(byte) PathFlags.enumCalcMask;// remove calculated flags - - if (m_bPolygon) - flags |= (byte) PathFlags.enumClosed; - - m_pathFlags.write(m_pathFlags.size() - 1, flags); - m_pathFlags.add((byte) 0); - } else { - m_paths.write(m_pathFlags.size() - 1, m_pointCount); - } - - // Index_type absoluteIndex = pathStart + before_point_index; - - for (int iattr = 0, nattr = m_description.getAttributeCount(); iattr < nattr; iattr++) { - int semantics = m_description.getSemantics(iattr); - int comp = VertexDescription.getComponentCount(semantics); - - int isrcAttr = src.m_description.getAttributeIndex(semantics); - if (isrcAttr < 0 || src.m_vertexAttributes[isrcAttr] == null) {// The - // source - // does - // not - // have - // the - // attribute. - // insert - // default - // value - double v = VertexDescription.getDefaultValue(semantics); - m_vertexAttributes[iattr].insertRange(comp * oldPointCount, v, - src_point_count * comp, comp * oldPointCount); - continue; - } - - // add vertices to the given stream - boolean b_forward = true; - m_vertexAttributes[iattr].insertRange(comp * oldPointCount, - src.m_vertexAttributes[isrcAttr], comp * srcFromPoint, - src_point_count * comp, b_forward, comp, comp - * oldPointCount); - } - - if (hasNonLinearSegments()) { - // TODO: implement me. For example as a while loop over all curves. - // Replace, calling ReplaceSegment - throw GeometryException.GeometryInternalError(); - // m_segment_flags->write_range((get_path_start(path_index) + - // before_point_index + src_point_count), (oldPointCount - - // get_path_start(path_index) - before_point_index), - // m_segment_flags, (get_path_start(path_index) + - // before_point_index), true, 1); - // m_segment_param_index->write_range((get_path_start(path_index) + - // before_point_index + src_point_count), (oldPointCount - - // get_path_start(path_index) - before_point_index), - // m_segment_param_index, (get_path_start(path_index) + - // before_point_index), true, 1); - // for (Index_type i = get_path_start(path_index) + - // before_point_index, n = get_path_start(path_index) + - // before_point_index + src_point_count; i < n; i++) - // { - // m_segment_flags->write(i, (int8_t)enum_value1(Segment_flags, - // enum_line_seg)); - // m_segment_param_index->write(i, -1); - // } - } - - if (src.hasNonLinearSegments(src_path_index)) { - // TODO: implement me. For example as a while loop over all curves. - // Replace, calling ReplaceSegment - throw GeometryException.GeometryInternalError(); - } - - notifyModified(DirtyFlags.DirtyCoordinates); - } - - // Reviewed vs. Native Jan 11, 2011 - public void reverseAllPaths() { - for (int i = 0, n = getPathCount(); i < n; i++) { - reversePath(i); - } - } - - // Reviewed vs. Native Jan 11, 2011 - public void reversePath(int pathIndex) { - _verifyAllStreams(); - int pathCount = getPathCount(); - if (pathIndex >= pathCount) - throw new IllegalArgumentException(); - - int reversedPathStart = getPathStart(pathIndex); - int reversedPathSize = getPathSize(pathIndex); - int offset = isClosedPath(pathIndex) ? 1 : 0; - - // TODO: a bug for the non linear segments here. - // There could be an issue here if someone explicity closes the path - // with the same start/end point. - for (int iattr = 0, nattr = m_description.getAttributeCount(); iattr < nattr; iattr++) { - if (m_vertexAttributes[iattr] != null) { - int semantics = m_description._getSemanticsImpl(iattr); - int comp = VertexDescription.getComponentCount(semantics); - m_vertexAttributes[iattr].reverseRange(comp - * (reversedPathStart + offset), comp - * (reversedPathSize - offset), comp); - } - } - - notifyModified(DirtyFlags.DirtyCoordinates); - } - - // Reviewed vs. Native Jan 11, 2011 - // TODO: Nonlinearsegments - public void removePath(int pathIndex) { - _verifyAllStreams(); - int pathCount = getPathCount(); - - if (pathIndex < 0) - pathIndex = pathCount - 1; - - if (pathIndex >= pathCount) - throw new IllegalArgumentException(); - - boolean bDirtyRingAreas2D = _hasDirtyFlag(DirtyFlags.DirtyRingAreas2D); - - int removedPathStart = getPathStart(pathIndex); - int removedPathSize = getPathSize(pathIndex); - - // Remove the attribute values for the path - for (int iattr = 0, nattr = m_description.getAttributeCount(); iattr < nattr; iattr++) { - if (m_vertexAttributes[iattr] != null) { - int semantics = m_description._getSemanticsImpl(iattr); - int comp = VertexDescription.getComponentCount(semantics); - m_vertexAttributes[iattr].eraseRange(comp * removedPathStart, - comp * removedPathSize, comp * m_pointCount); - } - } - - // Change the start of each path after the removed path - for (int i = pathIndex + 1; i <= pathCount; i++) { - int istart = m_paths.read(i); - m_paths.write(i - 1, istart - removedPathSize); - } - - if (m_pathFlags == null) { - for (int i = pathIndex + 1; i <= pathCount; i++) { - byte flags = m_pathFlags.read(i); - m_pathFlags.write(i - 1, flags); - } - } - - m_paths.resize(pathCount); - m_pathFlags.resize(pathCount); - m_pointCount -= removedPathSize; - m_reservedPointCount -= removedPathSize; - - notifyModified(DirtyFlags.DirtyCoordinates); - } - - // TODO: Nonlinearsegments - public void insertPath(int pathIndex, MultiPathImpl src, int srcPathIndex, - boolean bForward) { - if (src == this) - throw new IllegalArgumentException(); - - if (srcPathIndex >= src.getPathCount()) - throw new IllegalArgumentException(); - - int oldPathCount = getPathCount(); - if (pathIndex > oldPathCount) - throw new IllegalArgumentException(); - - if (pathIndex < 0) - pathIndex = oldPathCount; - - if (srcPathIndex < 0) - srcPathIndex = src.getPathCount() - 1; - - m_bPathStarted = false; - - mergeVertexDescription(src.m_description);// merge attributes from the - // source - - src._verifyAllStreams();// the source need to be correct. - - int srcPathIndexStart = src.getPathStart(srcPathIndex); - int srcPathSize = src.getPathSize(srcPathIndex); - int oldPointCount = m_pointCount; - int offset = src.isClosedPath(srcPathIndex) && !bForward ? 1 : 0; - - _resizeImpl(m_pointCount + srcPathSize); - _verifyAllStreams(); - int pathIndexStart = pathIndex < oldPathCount ? getPathStart(pathIndex) - : oldPointCount; - - // Copy all attribute values. - for (int iattr = 0, nattr = m_description.getAttributeCount(); iattr < nattr; iattr++) { - int semantics = m_description._getSemanticsImpl(iattr); - int isrcAttr = src.m_description.getAttributeIndex(semantics); - - int comp = VertexDescription.getComponentCount(semantics); - - if (isrcAttr >= 0 && src.m_vertexAttributes[isrcAttr] != null) { - if (offset != 0) - m_vertexAttributes[iattr].insertRange( - pathIndexStart * comp, - src.m_vertexAttributes[isrcAttr], comp - * srcPathIndexStart, comp, true, comp, comp - * oldPointCount); - m_vertexAttributes[iattr].insertRange((pathIndexStart + offset) - * comp, src.m_vertexAttributes[isrcAttr], comp - * (srcPathIndexStart + offset), comp - * (srcPathSize - offset), bForward, comp, comp - * (oldPointCount + offset)); - } else { - // Need to make room for the attributes, so we copy default - // values in - - double v = VertexDescription.getDefaultValue(semantics); - m_vertexAttributes[iattr].insertRange(pathIndexStart * comp, v, - comp * srcPathSize, comp * oldPointCount); - } - } - - int newPointCount = oldPointCount + srcPathSize; - m_paths.add(newPointCount); - - for (int ipath = oldPathCount; ipath >= pathIndex + 1; ipath--) { - int iend = m_paths.read(ipath - 1); - m_paths.write(ipath, iend + srcPathSize); - } - - // ========================== todo: NonLinearSegments ================= - if (src.hasNonLinearSegments(srcPathIndex)) { - - } - - m_pathFlags.add((byte) 0); - - // _ASSERT(m_pathFlags.size() == m_paths.size()); - - for (int ipath = oldPathCount - 1; ipath >= pathIndex + 1; ipath--) { - byte flags = m_pathFlags.read(ipath); - flags &= ~(byte) PathFlags.enumCalcMask;// remove calculated flags - m_pathFlags.write(ipath + 1, flags); - } - - AttributeStreamOfInt8 srcPathFlags = src.getPathFlagsStreamRef(); - byte flags = srcPathFlags.read(srcPathIndex); - flags &= ~(byte) PathFlags.enumCalcMask;// remove calculated flags - - if (m_bPolygon) - flags |= (byte) PathFlags.enumClosed; - - m_pathFlags.write(pathIndex, flags); - } - - public void insertPath(int pathIndex, Point2D[] points, int pointsOffset, - int count, boolean bForward) { - int oldPathCount = getPathCount(); - if (pathIndex > oldPathCount) - throw new IllegalArgumentException(); - - if (pathIndex < 0) - pathIndex = oldPathCount; - - m_bPathStarted = false; - - int oldPointCount = m_pointCount; - - // Copy all attribute values. - if (points != null) { - _resizeImpl(m_pointCount + count); - _verifyAllStreams(); - - int pathStart = pathIndex < oldPathCount ? getPathStart(pathIndex) - : oldPointCount; - - for (int iattr = 0, nattr = m_description.getAttributeCount(); iattr < nattr; iattr++) { - int semantics = m_description._getSemanticsImpl(iattr); - - if (semantics == VertexDescription.Semantics.POSITION) { - // copy range to make place for new vertices - m_vertexAttributes[iattr].writeRange( - 2 * (pathStart + count), - 2 * (oldPointCount - pathIndex), - m_vertexAttributes[iattr], 2 * pathStart, true, 2); - - AttributeStreamOfDbl position = (AttributeStreamOfDbl) (AttributeStreamBase) getAttributeStreamRef(semantics); - - int j = pathStart; - for (int i = 0; i < count; i++, j++) { - int index = (bForward ? pointsOffset + i : pointsOffset - + count - i - 1); - position.write(2 * j, points[index].x); - position.write(2 * j + 1, points[index].y); - } - } else { - // Need to make room for the attributes, so we copy default - // values in - - int comp = VertexDescription.getComponentCount(semantics); - double v = VertexDescription.getDefaultValue(semantics); - m_vertexAttributes[iattr].insertRange(pathStart * comp, v, - comp * count, comp * oldPointCount); - } - } - } else { - _verifyAllStreams(); - } - - m_paths.add(m_pointCount); - - for (int ipath = oldPathCount; ipath >= pathIndex + 1; ipath--) { - int iend = m_paths.read(ipath - 1); - m_paths.write(ipath, iend + count); - } - - m_pathFlags.add((byte) 0); - - // _ASSERT(m_pathFlags.size() == m_paths.size()); - - for (int ipath = oldPathCount - 1; ipath >= pathIndex + 1; ipath--) { - byte flags = m_pathFlags.read(ipath); - flags &= ~(byte) PathFlags.enumCalcMask;// remove calculated flags - m_pathFlags.write(ipath + 1, flags); - } - - if (m_bPolygon) - m_pathFlags.write(pathIndex, (byte) PathFlags.enumClosed); - } - - public void insertPoints(int pathIndex, int beforePointIndex, - MultiPathImpl src, int srcPathIndex, int srcPointIndexFrom, - int srcPointCount, boolean bForward) { - if (pathIndex < 0) - pathIndex = getPathCount(); - - if (srcPathIndex < 0) - srcPathIndex = src.getPathCount() - 1; - - if (pathIndex > getPathCount() || beforePointIndex >= 0 - && beforePointIndex > getPathSize(pathIndex) - || srcPathIndex >= src.getPathCount() - || srcPointCount > src.getPathSize(srcPathIndex)) - throw new GeometryException("index out of bounds"); - - if (srcPointCount == 0) - return; - - mergeVertexDescription(src.m_description); - - if (pathIndex == getPathCount())// adding a new path. - { - m_paths.add(m_pointCount); - - byte flags = src.m_pathFlags.read(srcPathIndex); - flags &= ~(byte) PathFlags.enumCalcMask;// remove calculated flags - - if (!m_bPolygon) - m_pathFlags.add(flags); - else - m_pathFlags.add((byte) (flags | PathFlags.enumClosed)); - } - - if (beforePointIndex < 0) - beforePointIndex = getPathSize(pathIndex); - - int oldPointCount = m_pointCount; - _resizeImpl(m_pointCount + srcPointCount); - _verifyAllStreams(); - src._verifyAllStreams(); - - int pathStart = getPathStart(pathIndex); - int absoluteIndex = pathStart + beforePointIndex; - - if (srcPointCount < 0) - srcPointCount = src.getPathSize(srcPathIndex); - - int srcPathStart = src.getPathStart(srcPathIndex); - int srcAbsoluteIndex = srcPathStart + srcPointCount; - - for (int iattr = 0, nattr = m_description.getAttributeCount(); iattr < nattr; iattr++) { - int semantics = m_description._getSemanticsImpl(iattr); - int comp = VertexDescription.getComponentCount(semantics); - - int isrcAttr = src.m_description.getAttributeIndex(semantics); - if (isrcAttr < 0 || src.m_vertexAttributes[isrcAttr] == null) // The - // source - // does - // not - // have - // the - // attribute. - { - double v = VertexDescription.getDefaultValue(semantics); - m_vertexAttributes[iattr].insertRange(comp * absoluteIndex, v, - srcAbsoluteIndex * comp, comp * oldPointCount); - continue; - } - - // add vertices to the given stream - m_vertexAttributes[iattr].insertRange(comp - * (pathStart + beforePointIndex), - src.m_vertexAttributes[isrcAttr], comp - * (srcPathStart + srcPointIndexFrom), srcPointCount - * comp, bForward, comp, comp * oldPointCount); - } - - if (hasNonLinearSegments()) {// TODO: probably a bug here when a new - // path is added. - m_segmentFlags.writeRange((getPathStart(pathIndex) - + beforePointIndex + srcPointCount), (oldPointCount - - getPathStart(pathIndex) - beforePointIndex), - m_segmentFlags, - (getPathStart(pathIndex) + beforePointIndex), true, 1); - m_segmentParamIndex.writeRange((getPathStart(pathIndex) - + beforePointIndex + srcPointCount), (oldPointCount - - getPathStart(pathIndex) - beforePointIndex), - m_segmentParamIndex, - (getPathStart(pathIndex) + beforePointIndex), true, 1); - for (int i = getPathStart(pathIndex) + beforePointIndex, n = getPathStart(pathIndex) - + beforePointIndex + srcPointCount; i < n; i++) { - m_segmentFlags.write(i, (byte) SegmentFlags.enumLineSeg); - m_segmentParamIndex.write(i, -1); - } - } - - if (src.hasNonLinearSegments(srcPathIndex)) { - // TODO: implement me. For example as a while loop over all curves. - // Replace, calling ReplaceSegment - throw GeometryException.GeometryInternalError(); - } - - for (int ipath = pathIndex + 1, npaths = getPathCount(); ipath <= npaths; ipath++) { - int num = m_paths.read(ipath); - m_paths.write(ipath, num + srcPointCount); - } - } - - public void insertPoints(int pathIndex, int beforePointIndex, - Point2D[] src, int srcPointIndexFrom, int srcPointCount, - boolean bForward) { - if (pathIndex < 0) - pathIndex = getPathCount(); - - if (pathIndex > getPathCount() - || beforePointIndex > getPathSize(pathIndex) - || srcPointIndexFrom < 0 || srcPointCount > src.length) - throw new GeometryException("index out of bounds"); - - if (srcPointCount == 0) - return; - - if (pathIndex == getPathCount())// adding a new path. - { - m_paths.add(m_pointCount); - - if (!m_bPolygon) - m_pathFlags.add((byte) 0); - else - m_pathFlags.add((byte) PathFlags.enumClosed); - } - - if (beforePointIndex < 0) - beforePointIndex = getPathSize(pathIndex); - - _verifyAllStreams(); - int oldPointCount = m_pointCount; - _resizeImpl(m_pointCount + srcPointCount); - _verifyAllStreams(); - for (int iattr = 0, nattr = m_description.getAttributeCount(); iattr < nattr; iattr++) { - int semantics = m_description._getSemanticsImpl(iattr); - int comp = VertexDescription.getComponentCount(semantics); - // copy range to make place for new vertices - m_vertexAttributes[iattr] - .writeRange( - comp - * (getPathStart(pathIndex) - + beforePointIndex + srcPointCount), - (oldPointCount - getPathStart(pathIndex) - beforePointIndex) - * comp, - m_vertexAttributes[iattr], - comp * (getPathStart(pathIndex) + beforePointIndex), - true, comp); - - if (iattr == 0) { - // add vertices to the given stream - ((AttributeStreamOfDbl) (AttributeStreamBase) m_vertexAttributes[iattr]) - .writeRange(comp - * (getPathStart(pathIndex) + beforePointIndex), - srcPointCount, src, srcPointIndexFrom, bForward); - } else { - double v = VertexDescription.getDefaultValue(semantics); - m_vertexAttributes[iattr].setRange(v, - (getPathStart(pathIndex) + beforePointIndex) * comp, - srcPointCount * comp); - } - } - - if (hasNonLinearSegments()) { - m_segmentFlags.writeRange((getPathStart(pathIndex) - + beforePointIndex + srcPointCount), (oldPointCount - - getPathStart(pathIndex) - beforePointIndex), - m_segmentFlags, - (getPathStart(pathIndex) + beforePointIndex), true, 1); - m_segmentParamIndex.writeRange((getPathStart(pathIndex) - + beforePointIndex + srcPointCount), (oldPointCount - - getPathStart(pathIndex) - beforePointIndex), - m_segmentParamIndex, - (getPathStart(pathIndex) + beforePointIndex), true, 1); - m_segmentFlags.setRange((byte) SegmentFlags.enumLineSeg, - getPathStart(pathIndex) + beforePointIndex, srcPointCount); - m_segmentParamIndex.setRange(-1, getPathStart(pathIndex) - + beforePointIndex, srcPointCount); - } - - for (int ipath = pathIndex + 1, npaths = getPathCount(); ipath <= npaths; ipath++) { - m_paths.write(ipath, m_paths.read(ipath) + srcPointCount); - } - } - - public void insertPoint(int pathIndex, int beforePointIndex, Point2D pt) { - int pathCount = getPathCount(); - - if (pathIndex < 0) - pathIndex = getPathCount(); - - if (pathIndex >= pathCount || beforePointIndex > getPathSize(pathIndex)) - throw new GeometryException("index out of bounds"); - - if (pathIndex == getPathCount())// adding a new path. - { - m_paths.add(m_pointCount); - - if (!m_bPolygon) - m_pathFlags.add((byte) 0); - else - m_pathFlags.add((byte) PathFlags.enumClosed); - } - - if (beforePointIndex < 0) - beforePointIndex = getPathSize(pathIndex); - - int oldPointCount = m_pointCount; - _resizeImpl(m_pointCount + 1); - _verifyAllStreams(); - - int pathStart = getPathStart(pathIndex); - - ((AttributeStreamOfDbl) (AttributeStreamBase) m_vertexAttributes[0]) - .insert(2 * (pathStart + beforePointIndex), pt, - 2 * oldPointCount); - - for (int iattr = 1, nattr = m_description.getAttributeCount(); iattr < nattr; iattr++) { - int semantics = m_description._getSemanticsImpl(iattr); - int comp = VertexDescription.getComponentCount(semantics); - - // Need to make room for the attribute, so we copy a default value - // in - double v = VertexDescription.getDefaultValue(semantics); - m_vertexAttributes[iattr].insertRange(comp - * (pathStart + beforePointIndex), v, comp, comp - * oldPointCount); - } - - for (int ipath = pathIndex + 1, npaths = pathCount; ipath <= npaths; ipath++) { - m_paths.write(ipath, m_paths.read(ipath) + 1); - } - } - - public void insertPoint(int pathIndex, int beforePointIndex, Point pt) { - int pathCount = getPathCount(); - - if (pathIndex < 0) - pathIndex = getPathCount(); - - if (pathIndex >= pathCount || beforePointIndex > getPathSize(pathIndex)) - throw new GeometryException("index out of bounds"); - - if (pathIndex == getPathCount())// adding a new path. - { - m_paths.add(m_pointCount); - - if (!m_bPolygon) - m_pathFlags.add((byte) 0); - else - m_pathFlags.add((byte) PathFlags.enumClosed); - } - - if (beforePointIndex < 0) - beforePointIndex = getPathSize(pathIndex); - - mergeVertexDescription(pt.getDescription()); - int oldPointCount = m_pointCount; - _resizeImpl(m_pointCount + 1); - _verifyAllStreams(); - - int pathStart = getPathStart(pathIndex); - - for (int iattr = 0, nattr = m_description.getAttributeCount(); iattr < nattr; iattr++) { - int semantics = m_description._getSemanticsImpl(iattr); - int comp = VertexDescription.getComponentCount(semantics); - - if (pt.hasAttribute(semantics)) { - m_vertexAttributes[iattr].insertAttributes(comp - * (pathStart + beforePointIndex), pt, semantics, comp - * oldPointCount); - } else { - // Need to make room for the attribute, so we copy a default - // value in - double v = VertexDescription.getDefaultValue(semantics); - m_vertexAttributes[iattr].insertRange(comp - * (pathStart + beforePointIndex), v, comp, comp - * oldPointCount); - } - } + // / Cpp /// + // Reviewed vs. Native Jan 11, 2011 + public MultiPathImpl(boolean bPolygon) { + m_bPolygon = bPolygon; + + m_bPathStarted = false; + m_curveParamwritePoint = 0; + m_cachedLength2D = 0; + m_cachedArea2D = 0; + m_pointCount = 0; + m_description = VertexDescriptionDesignerImpl.getDefaultDescriptor2D(); + m_cachedRingAreas2D = null; + m_currentPathIndex = 0; + } + + // Reviewed vs. Native Jan 11, 2011 + public MultiPathImpl(boolean bPolygon, VertexDescription description) { + if (description == null) + throw new IllegalArgumentException(); + + m_bPolygon = bPolygon; + + m_bPathStarted = false; + m_curveParamwritePoint = 0; + m_cachedLength2D = 0; + m_cachedArea2D = 0; + m_pointCount = 0; + m_description = description; + m_cachedRingAreas2D = null; + m_currentPathIndex = 0; + } + + // Reviewed vs. Native Jan 11, 2011 + protected void _initPathStartPoint() { + _touch(); + if (m_moveToPoint == null) + m_moveToPoint = new Point(m_description); + else + m_moveToPoint.assignVertexDescription(m_description); + } + + // Reviewed vs. Native Jan 11, 2011 + /** + * Starts a new Path at the Point. + */ + public void startPath(double x, double y) { + Point2D endPoint = new Point2D(); + endPoint.x = x; + endPoint.y = y; + startPath(endPoint); + } + + // Reviewed vs. Native Jan 11, 2011 + public void startPath(Point2D point) { + _initPathStartPoint(); + m_moveToPoint.setXY(point); + m_bPathStarted = true; + } + + // Reviewed vs. Native Jan 11, 2011 + public void startPath(Point3D point) { + _initPathStartPoint(); + m_moveToPoint.setXYZ(point); + assignVertexDescription(m_moveToPoint.getDescription()); + m_bPathStarted = true; + } + + // Reviewed vs. Native Jan 11, 2011 + public void startPath(Point point) { + if (point.isEmpty()) + throw new IllegalArgumentException();// throw new + // IllegalArgumentException(); + + mergeVertexDescription(point.getDescription()); + _initPathStartPoint(); + point.copyTo(m_moveToPoint); + + // TODO check MultiPathImpl.cpp comment + // "//the description will be merged later" + // assignVertexDescription(m_moveToPoint.getDescription()); + m_bPathStarted = true; + } + + // Reviewed vs. Native Jan 11, 2011 + protected void _beforeNewSegment(int resizeBy) { + // Called for each new segment being added. + if (m_bPathStarted) { + _initPathStartPoint();// make sure the m_movetoPoint exists and has + // right vertex description + + // The new path is started. Need to grow m_parts and m_pathFlags. + if (m_paths == null) { + m_paths = (AttributeStreamOfInt32) AttributeStreamBase + .createIndexStream(2); + m_paths.write(0, 0); + m_pathFlags = (AttributeStreamOfInt8) AttributeStreamBase + .createByteStream(2, (byte) 0); + } else { + // _ASSERT(m_parts.size() >= 2); + m_paths.resize(m_paths.size() + 1, 0); + m_pathFlags.resize(m_pathFlags.size() + 1, 0); + } + + if (m_bPolygon) { + // Mark the path as closed + m_pathFlags.write(m_pathFlags.size() - 2, + (byte) PathFlags.enumClosed); + } + + resizeBy++; // +1 for the StartPath point. + } + + int oldcount = m_pointCount; + m_paths.write(m_paths.size() - 1, m_pointCount + resizeBy); // The + // NotifyModified + // will + // update + // the + // m_pointCount + // with this + // value. + _resizeImpl(oldcount + resizeBy); + m_pathFlags.write(m_paths.size() - 1, (byte) 0); + + if (m_bPathStarted) { + setPointByVal(oldcount, m_moveToPoint);// setPoint(oldcount, + // m_moveToPoint); //finally + // set the start point to + // the geometry + m_bPathStarted = false; + } + } + + // Reviewed vs. Native Jan 11, 2011 + protected void _finishLineTo() { + } + + // Reviewed vs. Native Jan 11, 2011 + /** + * adds a Line Segment from the last Point to the given endPoint. + */ + public void lineTo(double x, double y) { + _beforeNewSegment(1); + setXY(m_pointCount - 1, x, y); + _finishLineTo(); + // Point2D endPoint = new Point2D(); + // endPoint.x = x; endPoint.y = y; + // lineTo(endPoint); + } + + // Reviewed vs. Native Jan 11, 2011 + public void lineTo(Point2D endPoint) { + _beforeNewSegment(1); + setXY(m_pointCount - 1, endPoint); + _finishLineTo(); + } + + // Reviewed vs. Native Jan 11, 2011 + public void lineTo(Point3D endPoint) { + _beforeNewSegment(1); + setXYZ(m_pointCount - 1, endPoint); + _finishLineTo(); + } + + // Reviewed vs. Native Jan 11, 2011 + public void lineTo(Point endPoint) { + _beforeNewSegment(1); + setPointByVal(m_pointCount - 1, endPoint); + _finishLineTo(); + } + + // Reviewed vs. Native Jan 11, 2011 + protected void _initSegmentData(int sz) { + if (m_segmentParamIndex == null) { + m_segmentFlags = (AttributeStreamOfInt8) AttributeStreamBase + .createByteStream(m_pointCount, + (byte) SegmentFlags.enumLineSeg); + m_segmentParamIndex = (AttributeStreamOfInt32) AttributeStreamBase + .createIndexStream(m_pointCount, -1); + } + + int size = m_curveParamwritePoint + sz; + if (m_segmentParams == null) { + m_segmentParams = (AttributeStreamOfDbl) AttributeStreamBase + .createAttributeStreamWithPersistence( + VertexDescription.Persistence.enumDouble, size); + } else { + m_segmentParams.resize(size, 0); + } + } + + // Reviewed vs. Native Jan 11, 2011 + protected void _finishBezierTo() { + // _ASSERT(m_segmentFlags != null); + // _ASSERT(m_segmentParamIndex != null); + + m_segmentFlags.write(m_pointCount - 2, + (byte) SegmentFlags.enumBezierSeg); + } + + // Reviewed vs. Native Jan 11, 2011 + /** + * adds a Cubic Bezier Segment to the current Path. The Bezier Segment + * connects the current last Point and the given endPoint. + */ + public void bezierTo(Point2D controlPoint1, Point2D controlPoint2, + Point2D endPoint) { + _beforeNewSegment(1); + setXY(m_pointCount - 1, endPoint); + double z; + _initSegmentData(6); + m_pathFlags.setBits(m_pathFlags.size() - 1, + (byte) PathFlags.enumHasNonlinearSegments); + m_segmentParamIndex.write(m_pointCount - 2, m_curveParamwritePoint); + m_curveParamwritePoint += 6; + int curveIndex = m_curveParamwritePoint; + m_segmentParams.write(curveIndex, controlPoint1.x); + m_segmentParams.write(curveIndex + 1, controlPoint1.y); + z = 0;// TODO: calculate me. + m_segmentParams.write(curveIndex + 2, z); + m_segmentParams.write(curveIndex + 3, controlPoint2.x); + m_segmentParams.write(curveIndex + 4, controlPoint2.y); + z = 0;// TODO: calculate me. + m_segmentParams.write(curveIndex + 5, z); + _finishBezierTo(); + } + + // Reviewed vs. Native Jan 11, 2011 + public void openPath(int pathIndex) { + _touch(); + if (m_bPolygon) + throw GeometryException.GeometryInternalError();// do not call this + // method on a + // polygon + + int pathCount = getPathCount(); + if (pathIndex > getPathCount()) + throw new IllegalArgumentException(); + + if (m_pathFlags == null) + throw GeometryException.GeometryInternalError(); + + m_pathFlags.clearBits(pathIndex, (byte) PathFlags.enumClosed); + } + + public void openPathAndDuplicateStartVertex(int pathIndex) { + _touch(); + if (m_bPolygon) + throw GeometryException.GeometryInternalError();// do not call this + // method on a + // polygon + + int pathCount = getPathCount(); + if (pathIndex > pathCount) + throw GeometryException.GeometryInternalError(); + + if (!isClosedPath(pathIndex)) + return;// do not open if open + + if (m_pathFlags == null)// if (!m_pathFlags) + throw GeometryException.GeometryInternalError(); + + int oldPointCount = m_pointCount; + int pathIndexStart = getPathStart(pathIndex); + int pathIndexEnd = getPathEnd(pathIndex); + _resizeImpl(m_pointCount + 1); // resize does not write into m_paths + // anymore! + _verifyAllStreams(); + for (int iattr = 0, nattr = m_description.getAttributeCount(); iattr < nattr; iattr++) { + if (m_vertexAttributes[iattr] != null)// if + // (m_vertexAttributes[iattr]) + { + int semantics = m_description._getSemanticsImpl(iattr); + int comp = VertexDescription.getComponentCount(semantics); + m_vertexAttributes[iattr].insertRange(comp * pathIndexEnd, + m_vertexAttributes[iattr], comp * pathIndexStart, comp, + true, 1, comp * oldPointCount); + } + } + + for (int ipath = pathCount; ipath > pathIndex; ipath--) { + int iend = m_paths.read(ipath); + m_paths.write(ipath, iend + 1); + } + + m_pathFlags.clearBits(pathIndex, (byte) PathFlags.enumClosed); + } + + // Reviewed vs. Native Jan 11, 2011 + // Major Changes on 16th of January + public void openAllPathsAndDuplicateStartVertex() { + _touch(); + if (m_bPolygon) + throw GeometryException.GeometryInternalError();// do not call this + // method on a + // polygon + + if (m_pathFlags == null)// if (!m_pathFlags) + throw GeometryException.GeometryInternalError(); + + _verifyAllStreams(); + + int closedPathCount = 0; + int pathCount = getPathCount(); + for (int i = 0; i < pathCount; i++) { + if (m_pathFlags.read(i) == (byte) PathFlags.enumClosed) { + closedPathCount++; + } + } + + for (int iattr = 0, nattr = m_description.getAttributeCount(); iattr < nattr; iattr++) { + if (m_vertexAttributes[iattr] != null) { + int semantics = m_description._getSemanticsImpl(iattr);// int + // semantics + // = + // m_description._getSemanticsImpl(iattr); + int comp = VertexDescription.getComponentCount(semantics); + int newSize = comp * (m_pointCount + closedPathCount); + m_vertexAttributes[iattr].resize(newSize); + + int offset = closedPathCount; + int ipath = pathCount; + for (int i = m_pointCount - 1; i >= 0; i--) { + if (i + 1 == m_paths.read(ipath)) { + ipath--; + if (m_pathFlags.read(ipath) == (byte) PathFlags.enumClosed) { + int istart = m_paths.read(ipath); + + for (int c = 0; c < comp; c++) { + double v = m_vertexAttributes[iattr] + .readAsDbl(comp * istart + c); + m_vertexAttributes[iattr].writeAsDbl(comp + * (offset + i) + c, v); + } + + if (--offset == 0) + break; + } + } + + for (int c = 0; c < comp; c++) { + double v = m_vertexAttributes[iattr].readAsDbl(comp * i + + c); + m_vertexAttributes[iattr].writeAsDbl(comp + * (offset + i) + c, v); + } + } + } + } + + int offset = closedPathCount; + for (int ipath = pathCount; ipath > 0; ipath--) { + int iend = m_paths.read(ipath); + m_paths.write(ipath, iend + offset); + + if (m_pathFlags.read(ipath - 1) == (byte) PathFlags.enumClosed) { + m_pathFlags.clearBits(ipath - 1, (byte) PathFlags.enumClosed); + + if (--offset == 0) { + break; + } + } + } + + m_pointCount += closedPathCount; + } + + void closePathWithLine(int path_index) { + // touch_(); + throwIfEmpty(); + + byte pf = m_pathFlags.read(path_index); + m_pathFlags.write(path_index, (byte) (pf | PathFlags.enumClosed)); + if (m_segmentFlags != null) { + int vindex = getPathEnd(path_index) - 1; + m_segmentFlags.write(vindex, (byte) SegmentFlags.enumLineSeg); + m_segmentParamIndex.write(vindex, -1); + } + } + + void closePathWithLine() { + throwIfEmpty(); + m_bPathStarted = false; + closePathWithLine(getPathCount() - 1); + } + + // Reviewed vs. Native Jan 11, 2011 + /** + * Closes all open curves by adding an implicit line segment from the end + * point to the start point. + */ + public void closeAllPaths() { + _touch(); + if (m_bPolygon || isEmptyImpl()) + return; + + m_bPathStarted = false; + + for (int ipath = 0, npart = m_paths.size() - 1; ipath < npart; ipath++) { + if (isClosedPath(ipath)) + continue; + + byte pf = m_pathFlags.read(ipath); + m_pathFlags.write(ipath, (byte) (pf | PathFlags.enumClosed)); + // if (m_segmentFlags) + // { + // m_segmentFlags.write(m_pointCount - 1, + // (byte)SegmentFlags.LineSeg)); + // m_segmentParamIndex.write(m_pointCount - 1, -1); + // } + } + } + + // Reviewed vs. Native Jan 11, 2011 + /** + * Returns the size of the segment data for the given segment type. + * + * @param flag + * is one of the segment flags from the SegmentFlags enum. + * @return the size of the segment params as the number of doubles. + */ + public static int getSegmentDataSize(byte flag) { + return _segmentParamSizes[flag]; + } + + // Reviewed vs. Native Jan 11, 2011 + /** + * Closes last path of the MultiPathImpl with the Bezier Segment. + * + * The start point of the Bezier is the last point of the path and the last + * point of the bezier is the first point of the path. + */ + public void closePathWithBezier(Point2D controlPoint1, Point2D controlPoint2) { + _touch(); + if (isEmptyImpl()) + throw new GeometryException( + "Invalid call. This operation cannot be performed on an empty geometry."); + + m_bPathStarted = false; + + int pathIndex = m_paths.size() - 2; + byte pf = m_pathFlags.read(pathIndex); + m_pathFlags + .write(pathIndex, + (byte) (pf | PathFlags.enumClosed | PathFlags.enumHasNonlinearSegments)); + _initSegmentData(6); + + byte oldType = m_segmentFlags + .read((byte) ((m_pointCount - 1) & SegmentFlags.enumSegmentMask)); + m_segmentFlags.write(m_pointCount - 1, + (byte) (SegmentFlags.enumBezierSeg)); + + int curveIndex = m_curveParamwritePoint; + if (getSegmentDataSize(oldType) < getSegmentDataSize((byte) SegmentFlags.enumBezierSeg)) { + m_segmentParamIndex.write(m_pointCount - 1, m_curveParamwritePoint); + m_curveParamwritePoint += 6; + } else { + // there was a closing bezier curve or an arc here. We can reuse the + // storage. + curveIndex = m_segmentParamIndex.read(m_pointCount - 1); + } + + double z; + m_segmentParams.write(curveIndex, controlPoint1.x); + m_segmentParams.write(curveIndex + 1, controlPoint1.y); + z = 0;// TODO: calculate me. + m_segmentParams.write(curveIndex + 2, z); + + m_segmentParams.write(curveIndex + 3, controlPoint2.x); + m_segmentParams.write(curveIndex + 4, controlPoint2.y); + z = 0;// TODO: calculate me. + m_segmentParams.write(curveIndex + 5, z); + } + + // Reviewed vs. Native Jan 11, 2011 + /** + * Returns True if the given path is closed (represents a Ring). + */ + public boolean isClosedPath(int ipath) { + // Should we make a function called _UpdateClosedPathFlags and call it + // here? + return ((byte) (m_pathFlags.read(ipath) & PathFlags.enumClosed)) != 0; + } + + public boolean isClosedPathInXYPlane(int path_index) { + if (isClosedPath(path_index)) + return true; + int istart = getPathStart(path_index); + int iend = getPathEnd(path_index) - 1; + if (istart > iend) + return false; + Point2D ptS = getXY(istart); + Point2D ptE = getXY(iend); + return ptS.isEqual(ptE); + } + + // Reviewed vs. Native Jan 11, 2011 + /** + * Returns True if the given path might have non-linear segments. + */ + public boolean hasNonLinearSegments(int ipath) { + // Should we make a function called _UpdateHasNonLinearSegmentsFlags and + // call it here? + return (m_pathFlags.read(ipath) & PathFlags.enumHasNonlinearSegments) != 0; + } + + // Reviewed vs. Native Jan 11, 2011 + public void addSegment(Segment segment, boolean bStartNewPath) { + mergeVertexDescription(segment.getDescription()); + if (segment.getType() == Type.Line) { + Point point = new Point(); + if (bStartNewPath || isEmpty()) { + segment.queryStart(point); + startPath(point); + } + + segment.queryEnd(point); + lineTo(point); + } else { + throw GeometryException.GeometryInternalError(); + } + } + + // Reviewed vs. Native Jan 11, 2011 + /** + * adds a rectangular closed Path to the MultiPathImpl. + * + * @param envSrc + * is the source rectangle. + * @param bReverse + * Creates reversed path. + */ + public void addEnvelope(Envelope2D envSrc, boolean bReverse) { + boolean bWasEmpty = m_pointCount == 0; + + startPath(envSrc.xmin, envSrc.ymin); + if (bReverse) { + lineTo(envSrc.xmax, envSrc.ymin); + lineTo(envSrc.xmax, envSrc.ymax); + lineTo(envSrc.xmin, envSrc.ymax); + } else { + lineTo(envSrc.xmin, envSrc.ymax); + lineTo(envSrc.xmax, envSrc.ymax); + lineTo(envSrc.xmax, envSrc.ymin); + } + + closePathWithLine(); + m_bPathStarted = false; + + if (bWasEmpty && !bReverse) { + _setDirtyFlag(DirtyFlags.DirtyIsEnvelope, false);// now we no(sic?) + // the polypath + // is envelope + } + } + + // Reviewed vs. Native Jan 11, 2011 + /** + * adds a rectangular closed Path to the MultiPathImpl. + * + * @param envSrc + * is the source rectangle. + * @param bReverse + * Creates reversed path. + */ + public void addEnvelope(Envelope envSrc, boolean bReverse) { + if (envSrc.isEmpty()) + return; + + boolean bWasEmpty = m_pointCount == 0; + Point pt = new Point(m_description);// getDescription()); + for (int i = 0, n = 4; i < n; i++) { + int j = bReverse ? n - i - 1 : i; + + envSrc.queryCornerByVal(j, pt); + if (i == 0) + startPath(pt); + else + lineTo(pt); + } + + closePathWithLine(); + m_bPathStarted = false; + + if (bWasEmpty && !bReverse) + _setDirtyFlag(DirtyFlags.DirtyIsEnvelope, false);// now we know the + // polypath is + // envelope + } + + // Reviewed vs. Native Jan 11, 2011 + public void add(MultiPathImpl src, boolean bReversePaths) { + for (int i = 0; i < src.getPathCount(); i++) + addPath(src, i, !bReversePaths); + } + + public void addPath(MultiPathImpl src, int srcPathIndex, boolean bForward) { + insertPath(-1, src, srcPathIndex, bForward); + } + + // Reviewed vs. Native Jan 11, 2011 Significant changes to last for loop + public void addPath(Point2D[] _points, int count, boolean bForward) { + insertPath(-1, _points, 0, count, bForward); + } + + public void addSegmentsFromPath(MultiPathImpl src, int src_path_index, + int src_segment_from, int src_segment_count, + boolean b_start_new_path) { + if (!b_start_new_path && getPathCount() == 0) + b_start_new_path = true; + + if (src_path_index < 0) + src_path_index = src.getPathCount() - 1; + + if (src_path_index >= src.getPathCount() || src_segment_from < 0 + || src_segment_count < 0 + || src_segment_count > src.getSegmentCount(src_path_index)) + throw new GeometryException("index out of bounds"); + + if (src_segment_count == 0) + return; + + boolean bIncludesClosingSegment = src.isClosedPath(src_path_index) + && src_segment_from + src_segment_count == src + .getSegmentCount(src_path_index); + + if (bIncludesClosingSegment && src_segment_count == 1) + return;// cannot add a closing segment alone. + + m_bPathStarted = false; + + mergeVertexDescription(src.getDescription()); + int src_point_count = src_segment_count; + int srcFromPoint = src.getPathStart(src_path_index) + src_segment_from + + 1; + if (b_start_new_path)// adding a new path. + { + src_point_count++;// add start point. + srcFromPoint--; + } + + if (bIncludesClosingSegment) { + src_point_count--; + } + + int oldPointCount = m_pointCount; + _resizeImpl(m_pointCount + src_point_count); + _verifyAllStreams(); + + if (b_start_new_path) { + if (src_point_count == 0) + return;// happens when adding a single closing segment to the + // new path + + m_paths.add(m_pointCount); + + byte flags = src.m_pathFlags.read(src_path_index); + flags &= ~(byte) PathFlags.enumCalcMask;// remove calculated flags + + if (m_bPolygon) + flags |= (byte) PathFlags.enumClosed; + + m_pathFlags.write(m_pathFlags.size() - 1, flags); + m_pathFlags.add((byte) 0); + } else { + m_paths.write(m_pathFlags.size() - 1, m_pointCount); + } + + // Index_type absoluteIndex = pathStart + before_point_index; + + for (int iattr = 0, nattr = m_description.getAttributeCount(); iattr < nattr; iattr++) { + int semantics = m_description.getSemantics(iattr); + int comp = VertexDescription.getComponentCount(semantics); + + int isrcAttr = src.m_description.getAttributeIndex(semantics); + if (isrcAttr < 0 || src.m_vertexAttributes[isrcAttr] == null) {// The + // source + // does + // not + // have + // the + // attribute. + // insert + // default + // value + double v = VertexDescription.getDefaultValue(semantics); + m_vertexAttributes[iattr].insertRange(comp * oldPointCount, v, + src_point_count * comp, comp * oldPointCount); + continue; + } + + // add vertices to the given stream + boolean b_forward = true; + m_vertexAttributes[iattr].insertRange(comp * oldPointCount, + src.m_vertexAttributes[isrcAttr], comp * srcFromPoint, + src_point_count * comp, b_forward, comp, comp + * oldPointCount); + } + + if (hasNonLinearSegments()) { + // TODO: implement me. For example as a while loop over all curves. + // Replace, calling ReplaceSegment + throw GeometryException.GeometryInternalError(); + // m_segment_flags->write_range((get_path_start(path_index) + + // before_point_index + src_point_count), (oldPointCount - + // get_path_start(path_index) - before_point_index), + // m_segment_flags, (get_path_start(path_index) + + // before_point_index), true, 1); + // m_segment_param_index->write_range((get_path_start(path_index) + + // before_point_index + src_point_count), (oldPointCount - + // get_path_start(path_index) - before_point_index), + // m_segment_param_index, (get_path_start(path_index) + + // before_point_index), true, 1); + // for (Index_type i = get_path_start(path_index) + + // before_point_index, n = get_path_start(path_index) + + // before_point_index + src_point_count; i < n; i++) + // { + // m_segment_flags->write(i, (int8_t)enum_value1(Segment_flags, + // enum_line_seg)); + // m_segment_param_index->write(i, -1); + // } + } + + if (src.hasNonLinearSegments(src_path_index)) { + // TODO: implement me. For example as a while loop over all curves. + // Replace, calling ReplaceSegment + throw GeometryException.GeometryInternalError(); + } + + notifyModified(DirtyFlags.DirtyCoordinates); + } + + // Reviewed vs. Native Jan 11, 2011 + public void reverseAllPaths() { + for (int i = 0, n = getPathCount(); i < n; i++) { + reversePath(i); + } + } + + // Reviewed vs. Native Jan 11, 2011 + public void reversePath(int pathIndex) { + _verifyAllStreams(); + int pathCount = getPathCount(); + if (pathIndex >= pathCount) + throw new IllegalArgumentException(); + + int reversedPathStart = getPathStart(pathIndex); + int reversedPathSize = getPathSize(pathIndex); + int offset = isClosedPath(pathIndex) ? 1 : 0; + + // TODO: a bug for the non linear segments here. + // There could be an issue here if someone explicity closes the path + // with the same start/end point. + for (int iattr = 0, nattr = m_description.getAttributeCount(); iattr < nattr; iattr++) { + if (m_vertexAttributes[iattr] != null) { + int semantics = m_description._getSemanticsImpl(iattr); + int comp = VertexDescription.getComponentCount(semantics); + m_vertexAttributes[iattr].reverseRange(comp + * (reversedPathStart + offset), comp + * (reversedPathSize - offset), comp); + } + } + + notifyModified(DirtyFlags.DirtyCoordinates); + } + + // Reviewed vs. Native Jan 11, 2011 + // TODO: Nonlinearsegments + public void removePath(int pathIndex) { + _verifyAllStreams(); + int pathCount = getPathCount(); + + if (pathIndex < 0) + pathIndex = pathCount - 1; + + if (pathIndex >= pathCount) + throw new IllegalArgumentException(); + + boolean bDirtyRingAreas2D = _hasDirtyFlag(DirtyFlags.DirtyRingAreas2D); + + int removedPathStart = getPathStart(pathIndex); + int removedPathSize = getPathSize(pathIndex); + + // Remove the attribute values for the path + for (int iattr = 0, nattr = m_description.getAttributeCount(); iattr < nattr; iattr++) { + if (m_vertexAttributes[iattr] != null) { + int semantics = m_description._getSemanticsImpl(iattr); + int comp = VertexDescription.getComponentCount(semantics); + m_vertexAttributes[iattr].eraseRange(comp * removedPathStart, + comp * removedPathSize, comp * m_pointCount); + } + } + + // Change the start of each path after the removed path + for (int i = pathIndex + 1; i <= pathCount; i++) { + int istart = m_paths.read(i); + m_paths.write(i - 1, istart - removedPathSize); + } + + if (m_pathFlags == null) { + for (int i = pathIndex + 1; i <= pathCount; i++) { + byte flags = m_pathFlags.read(i); + m_pathFlags.write(i - 1, flags); + } + } + + m_paths.resize(pathCount); + m_pathFlags.resize(pathCount); + m_pointCount -= removedPathSize; + m_reservedPointCount -= removedPathSize; + + notifyModified(DirtyFlags.DirtyCoordinates); + } + + // TODO: Nonlinearsegments + public void insertPath(int pathIndex, MultiPathImpl src, int srcPathIndex, + boolean bForward) { + if (src == this) + throw new IllegalArgumentException(); + + if (srcPathIndex >= src.getPathCount()) + throw new IllegalArgumentException(); + + int oldPathCount = getPathCount(); + if (pathIndex > oldPathCount) + throw new IllegalArgumentException(); + + if (pathIndex < 0) + pathIndex = oldPathCount; + + if (srcPathIndex < 0) + srcPathIndex = src.getPathCount() - 1; + + m_bPathStarted = false; + + mergeVertexDescription(src.m_description);// merge attributes from the + // source + + src._verifyAllStreams();// the source need to be correct. + + int srcPathIndexStart = src.getPathStart(srcPathIndex); + int srcPathSize = src.getPathSize(srcPathIndex); + int oldPointCount = m_pointCount; + int offset = src.isClosedPath(srcPathIndex) && !bForward ? 1 : 0; + + _resizeImpl(m_pointCount + srcPathSize); + _verifyAllStreams(); + int pathIndexStart = pathIndex < oldPathCount ? getPathStart(pathIndex) + : oldPointCount; + + // Copy all attribute values. + for (int iattr = 0, nattr = m_description.getAttributeCount(); iattr < nattr; iattr++) { + int semantics = m_description._getSemanticsImpl(iattr); + int isrcAttr = src.m_description.getAttributeIndex(semantics); + + int comp = VertexDescription.getComponentCount(semantics); + + if (isrcAttr >= 0 && src.m_vertexAttributes[isrcAttr] != null) { + if (offset != 0) + m_vertexAttributes[iattr].insertRange( + pathIndexStart * comp, + src.m_vertexAttributes[isrcAttr], comp + * srcPathIndexStart, comp, true, comp, comp + * oldPointCount); + m_vertexAttributes[iattr].insertRange((pathIndexStart + offset) + * comp, src.m_vertexAttributes[isrcAttr], comp + * (srcPathIndexStart + offset), comp + * (srcPathSize - offset), bForward, comp, comp + * (oldPointCount + offset)); + } else { + // Need to make room for the attributes, so we copy default + // values in + + double v = VertexDescription.getDefaultValue(semantics); + m_vertexAttributes[iattr].insertRange(pathIndexStart * comp, v, + comp * srcPathSize, comp * oldPointCount); + } + } + + int newPointCount = oldPointCount + srcPathSize; + m_paths.add(newPointCount); + + for (int ipath = oldPathCount; ipath >= pathIndex + 1; ipath--) { + int iend = m_paths.read(ipath - 1); + m_paths.write(ipath, iend + srcPathSize); + } + + // ========================== todo: NonLinearSegments ================= + if (src.hasNonLinearSegments(srcPathIndex)) { + + } + + m_pathFlags.add((byte) 0); + + // _ASSERT(m_pathFlags.size() == m_paths.size()); + + for (int ipath = oldPathCount - 1; ipath >= pathIndex + 1; ipath--) { + byte flags = m_pathFlags.read(ipath); + flags &= ~(byte) PathFlags.enumCalcMask;// remove calculated flags + m_pathFlags.write(ipath + 1, flags); + } + + AttributeStreamOfInt8 srcPathFlags = src.getPathFlagsStreamRef(); + byte flags = srcPathFlags.read(srcPathIndex); + flags &= ~(byte) PathFlags.enumCalcMask;// remove calculated flags + + if (m_bPolygon) + flags |= (byte) PathFlags.enumClosed; + + m_pathFlags.write(pathIndex, flags); + } + + public void insertPath(int pathIndex, Point2D[] points, int pointsOffset, + int count, boolean bForward) { + int oldPathCount = getPathCount(); + if (pathIndex > oldPathCount) + throw new IllegalArgumentException(); + + if (pathIndex < 0) + pathIndex = oldPathCount; + + m_bPathStarted = false; + + int oldPointCount = m_pointCount; + + // Copy all attribute values. + if (points != null) { + _resizeImpl(m_pointCount + count); + _verifyAllStreams(); + + int pathStart = pathIndex < oldPathCount ? getPathStart(pathIndex) + : oldPointCount; + + for (int iattr = 0, nattr = m_description.getAttributeCount(); iattr < nattr; iattr++) { + int semantics = m_description._getSemanticsImpl(iattr); + + if (semantics == VertexDescription.Semantics.POSITION) { + // copy range to make place for new vertices + m_vertexAttributes[iattr].writeRange( + 2 * (pathStart + count), + 2 * (oldPointCount - pathIndex), + m_vertexAttributes[iattr], 2 * pathStart, true, 2); + + AttributeStreamOfDbl position = (AttributeStreamOfDbl) (AttributeStreamBase) getAttributeStreamRef(semantics); + + int j = pathStart; + for (int i = 0; i < count; i++, j++) { + int index = (bForward ? pointsOffset + i : pointsOffset + + count - i - 1); + position.write(2 * j, points[index].x); + position.write(2 * j + 1, points[index].y); + } + } else { + // Need to make room for the attributes, so we copy default + // values in + + int comp = VertexDescription.getComponentCount(semantics); + double v = VertexDescription.getDefaultValue(semantics); + m_vertexAttributes[iattr].insertRange(pathStart * comp, v, + comp * count, comp * oldPointCount); + } + } + } else { + _verifyAllStreams(); + } + + m_paths.add(m_pointCount); + + for (int ipath = oldPathCount; ipath >= pathIndex + 1; ipath--) { + int iend = m_paths.read(ipath - 1); + m_paths.write(ipath, iend + count); + } + + m_pathFlags.add((byte) 0); + + // _ASSERT(m_pathFlags.size() == m_paths.size()); + + for (int ipath = oldPathCount - 1; ipath >= pathIndex + 1; ipath--) { + byte flags = m_pathFlags.read(ipath); + flags &= ~(byte) PathFlags.enumCalcMask;// remove calculated flags + m_pathFlags.write(ipath + 1, flags); + } + + if (m_bPolygon) + m_pathFlags.write(pathIndex, (byte) PathFlags.enumClosed); + } + + public void insertPoints(int pathIndex, int beforePointIndex, + MultiPathImpl src, int srcPathIndex, int srcPointIndexFrom, + int srcPointCount, boolean bForward) { + if (pathIndex < 0) + pathIndex = getPathCount(); + + if (srcPathIndex < 0) + srcPathIndex = src.getPathCount() - 1; + + if (pathIndex > getPathCount() || beforePointIndex >= 0 + && beforePointIndex > getPathSize(pathIndex) + || srcPathIndex >= src.getPathCount() + || srcPointCount > src.getPathSize(srcPathIndex)) + throw new GeometryException("index out of bounds"); + + if (srcPointCount == 0) + return; + + mergeVertexDescription(src.m_description); + + if (pathIndex == getPathCount())// adding a new path. + { + m_paths.add(m_pointCount); + + byte flags = src.m_pathFlags.read(srcPathIndex); + flags &= ~(byte) PathFlags.enumCalcMask;// remove calculated flags + + if (!m_bPolygon) + m_pathFlags.add(flags); + else + m_pathFlags.add((byte) (flags | PathFlags.enumClosed)); + } + + if (beforePointIndex < 0) + beforePointIndex = getPathSize(pathIndex); + + int oldPointCount = m_pointCount; + _resizeImpl(m_pointCount + srcPointCount); + _verifyAllStreams(); + src._verifyAllStreams(); + + int pathStart = getPathStart(pathIndex); + int absoluteIndex = pathStart + beforePointIndex; + + if (srcPointCount < 0) + srcPointCount = src.getPathSize(srcPathIndex); + + int srcPathStart = src.getPathStart(srcPathIndex); + int srcAbsoluteIndex = srcPathStart + srcPointCount; + + for (int iattr = 0, nattr = m_description.getAttributeCount(); iattr < nattr; iattr++) { + int semantics = m_description._getSemanticsImpl(iattr); + int comp = VertexDescription.getComponentCount(semantics); + + int isrcAttr = src.m_description.getAttributeIndex(semantics); + if (isrcAttr < 0 || src.m_vertexAttributes[isrcAttr] == null) // The + // source + // does + // not + // have + // the + // attribute. + { + double v = VertexDescription.getDefaultValue(semantics); + m_vertexAttributes[iattr].insertRange(comp * absoluteIndex, v, + srcAbsoluteIndex * comp, comp * oldPointCount); + continue; + } + + // add vertices to the given stream + m_vertexAttributes[iattr].insertRange(comp + * (pathStart + beforePointIndex), + src.m_vertexAttributes[isrcAttr], comp + * (srcPathStart + srcPointIndexFrom), srcPointCount + * comp, bForward, comp, comp * oldPointCount); + } + + if (hasNonLinearSegments()) {// TODO: probably a bug here when a new + // path is added. + m_segmentFlags.writeRange((getPathStart(pathIndex) + + beforePointIndex + srcPointCount), (oldPointCount + - getPathStart(pathIndex) - beforePointIndex), + m_segmentFlags, + (getPathStart(pathIndex) + beforePointIndex), true, 1); + m_segmentParamIndex.writeRange((getPathStart(pathIndex) + + beforePointIndex + srcPointCount), (oldPointCount + - getPathStart(pathIndex) - beforePointIndex), + m_segmentParamIndex, + (getPathStart(pathIndex) + beforePointIndex), true, 1); + for (int i = getPathStart(pathIndex) + beforePointIndex, n = getPathStart(pathIndex) + + beforePointIndex + srcPointCount; i < n; i++) { + m_segmentFlags.write(i, (byte) SegmentFlags.enumLineSeg); + m_segmentParamIndex.write(i, -1); + } + } + + if (src.hasNonLinearSegments(srcPathIndex)) { + // TODO: implement me. For example as a while loop over all curves. + // Replace, calling ReplaceSegment + throw GeometryException.GeometryInternalError(); + } + + for (int ipath = pathIndex + 1, npaths = getPathCount(); ipath <= npaths; ipath++) { + int num = m_paths.read(ipath); + m_paths.write(ipath, num + srcPointCount); + } + } + + public void insertPoints(int pathIndex, int beforePointIndex, + Point2D[] src, int srcPointIndexFrom, int srcPointCount, + boolean bForward) { + if (pathIndex < 0) + pathIndex = getPathCount(); + + if (pathIndex > getPathCount() + || beforePointIndex > getPathSize(pathIndex) + || srcPointIndexFrom < 0 || srcPointCount > src.length) + throw new GeometryException("index out of bounds"); + + if (srcPointCount == 0) + return; + + if (pathIndex == getPathCount())// adding a new path. + { + m_paths.add(m_pointCount); + + if (!m_bPolygon) + m_pathFlags.add((byte) 0); + else + m_pathFlags.add((byte) PathFlags.enumClosed); + } - for (int ipath = pathIndex + 1, npaths = pathCount; ipath <= npaths; ipath++) { - m_paths.write(ipath, m_paths.read(ipath) + 1); - } + if (beforePointIndex < 0) + beforePointIndex = getPathSize(pathIndex); + + _verifyAllStreams(); + int oldPointCount = m_pointCount; + _resizeImpl(m_pointCount + srcPointCount); + _verifyAllStreams(); + for (int iattr = 0, nattr = m_description.getAttributeCount(); iattr < nattr; iattr++) { + int semantics = m_description._getSemanticsImpl(iattr); + int comp = VertexDescription.getComponentCount(semantics); + // copy range to make place for new vertices + m_vertexAttributes[iattr] + .writeRange( + comp + * (getPathStart(pathIndex) + + beforePointIndex + srcPointCount), + (oldPointCount - getPathStart(pathIndex) - beforePointIndex) + * comp, + m_vertexAttributes[iattr], + comp * (getPathStart(pathIndex) + beforePointIndex), + true, comp); + + if (iattr == 0) { + // add vertices to the given stream + ((AttributeStreamOfDbl) (AttributeStreamBase) m_vertexAttributes[iattr]) + .writeRange(comp + * (getPathStart(pathIndex) + beforePointIndex), + srcPointCount, src, srcPointIndexFrom, bForward); + } else { + double v = VertexDescription.getDefaultValue(semantics); + m_vertexAttributes[iattr].setRange(v, + (getPathStart(pathIndex) + beforePointIndex) * comp, + srcPointCount * comp); + } + } - notifyModified(DirtyFlags.DirtyCoordinates); - } + if (hasNonLinearSegments()) { + m_segmentFlags.writeRange((getPathStart(pathIndex) + + beforePointIndex + srcPointCount), (oldPointCount + - getPathStart(pathIndex) - beforePointIndex), + m_segmentFlags, + (getPathStart(pathIndex) + beforePointIndex), true, 1); + m_segmentParamIndex.writeRange((getPathStart(pathIndex) + + beforePointIndex + srcPointCount), (oldPointCount + - getPathStart(pathIndex) - beforePointIndex), + m_segmentParamIndex, + (getPathStart(pathIndex) + beforePointIndex), true, 1); + m_segmentFlags.setRange((byte) SegmentFlags.enumLineSeg, + getPathStart(pathIndex) + beforePointIndex, srcPointCount); + m_segmentParamIndex.setRange(-1, getPathStart(pathIndex) + + beforePointIndex, srcPointCount); + } - public void removePoint(int pathIndex, int pointIndex) { - int pathCount = getPathCount(); + for (int ipath = pathIndex + 1, npaths = getPathCount(); ipath <= npaths; ipath++) { + m_paths.write(ipath, m_paths.read(ipath) + srcPointCount); + } + } - if (pathIndex < 0) - pathIndex = pathCount - 1; + public void insertPoint(int pathIndex, int beforePointIndex, Point2D pt) { + int pathCount = getPathCount(); - if (pathIndex >= pathCount || pointIndex >= getPathSize(pathIndex)) - throw new GeometryException("index out of bounds"); + if (pathIndex < 0) + pathIndex = getPathCount(); - _verifyAllStreams(); + if (pathIndex >= pathCount || beforePointIndex > getPathSize(pathIndex)) + throw new GeometryException("index out of bounds"); - int pathStart = getPathStart(pathIndex); + if (pathIndex == getPathCount())// adding a new path. + { + m_paths.add(m_pointCount); - if (pointIndex < 0) - pointIndex = getPathSize(pathIndex) - 1; + if (!m_bPolygon) + m_pathFlags.add((byte) 0); + else + m_pathFlags.add((byte) PathFlags.enumClosed); + } - int absoluteIndex = pathStart + pointIndex; + if (beforePointIndex < 0) + beforePointIndex = getPathSize(pathIndex); - // Remove the attribute values for the path - for (int iattr = 0, nattr = m_description.getAttributeCount(); iattr < nattr; iattr++) { - if (m_vertexAttributes[iattr] != null) { - int semantics = m_description._getSemanticsImpl(iattr); - int comp = VertexDescription.getComponentCount(semantics); - m_vertexAttributes[iattr].eraseRange(comp * absoluteIndex, - comp, comp * m_pointCount); - } - } + int oldPointCount = m_pointCount; + _resizeImpl(m_pointCount + 1); + _verifyAllStreams(); - for (int ipath = pathCount; ipath >= pathIndex + 1; ipath--) { - int iend = m_paths.read(ipath); - m_paths.write(ipath, iend - 1); - } + int pathStart = getPathStart(pathIndex); - m_pointCount--; - m_reservedPointCount--; - notifyModified(DirtyFlags.DirtyCoordinates); - } + ((AttributeStreamOfDbl) (AttributeStreamBase) m_vertexAttributes[0]) + .insert(2 * (pathStart + beforePointIndex), pt, + 2 * oldPointCount); - public double calculatePathLength2D(int pathIndex) /* const */ { - SegmentIteratorImpl segIter = querySegmentIteratorAtVertex(getPathStart(pathIndex)); + for (int iattr = 1, nattr = m_description.getAttributeCount(); iattr < nattr; iattr++) { + int semantics = m_description._getSemanticsImpl(iattr); + int comp = VertexDescription.getComponentCount(semantics); - MathUtils.KahanSummator len = new MathUtils.KahanSummator(0); - while (segIter.hasNextSegment()) { - len.add(segIter.nextSegment().calculateLength2D()); - } + // Need to make room for the attribute, so we copy a default value + // in + double v = VertexDescription.getDefaultValue(semantics); + m_vertexAttributes[iattr].insertRange(comp + * (pathStart + beforePointIndex), v, comp, comp + * oldPointCount); + } - return len.getResult(); - } + for (int ipath = pathIndex + 1, npaths = pathCount; ipath <= npaths; ipath++) { + m_paths.write(ipath, m_paths.read(ipath) + 1); + } + } - double calculateSubLength2D(int from_path_index, int from_point_index, - int to_path_index, int to_point_index) { - int absolute_from_index = getPathStart(from_path_index) - + from_point_index; - int absolute_to_index = getPathStart(to_path_index) + to_point_index; + public void insertPoint(int pathIndex, int beforePointIndex, Point pt) { + int pathCount = getPathCount(); - if (absolute_to_index < absolute_from_index || absolute_from_index < 0 - || absolute_to_index > getPointCount() - 1) - throw new IllegalArgumentException(); + if (pathIndex < 0) + pathIndex = getPathCount(); - SegmentIteratorImpl seg_iter = querySegmentIterator(); + if (pathIndex >= pathCount || beforePointIndex > getPathSize(pathIndex)) + throw new GeometryException("index out of bounds"); - double sub_length = 0.0; + if (pathIndex == getPathCount())// adding a new path. + { + m_paths.add(m_pointCount); - seg_iter.resetToVertex(absolute_from_index); + if (!m_bPolygon) + m_pathFlags.add((byte) 0); + else + m_pathFlags.add((byte) PathFlags.enumClosed); + } - do { - while (seg_iter.hasNextSegment()) { - Segment segment = seg_iter.nextSegment(); + if (beforePointIndex < 0) + beforePointIndex = getPathSize(pathIndex); + + mergeVertexDescription(pt.getDescription()); + int oldPointCount = m_pointCount; + _resizeImpl(m_pointCount + 1); + _verifyAllStreams(); + + int pathStart = getPathStart(pathIndex); + + for (int iattr = 0, nattr = m_description.getAttributeCount(); iattr < nattr; iattr++) { + int semantics = m_description._getSemanticsImpl(iattr); + int comp = VertexDescription.getComponentCount(semantics); + + if (pt.hasAttribute(semantics)) { + m_vertexAttributes[iattr].insertAttributes(comp + * (pathStart + beforePointIndex), pt, semantics, comp + * oldPointCount); + } else { + // Need to make room for the attribute, so we copy a default + // value in + double v = VertexDescription.getDefaultValue(semantics); + m_vertexAttributes[iattr].insertRange(comp + * (pathStart + beforePointIndex), v, comp, comp + * oldPointCount); + } + } - if (seg_iter.getStartPointIndex() == absolute_to_index) - break; + for (int ipath = pathIndex + 1, npaths = pathCount; ipath <= npaths; ipath++) { + m_paths.write(ipath, m_paths.read(ipath) + 1); + } - double segment_length = segment.calculateLength2D(); - sub_length += segment_length; - } + notifyModified(DirtyFlags.DirtyCoordinates); + } - if (seg_iter.getStartPointIndex() == absolute_to_index) - break; + public void removePoint(int pathIndex, int pointIndex) { + int pathCount = getPathCount(); - } while (seg_iter.nextPath()); + if (pathIndex < 0) + pathIndex = pathCount - 1; - return sub_length; - } + if (pathIndex >= pathCount || pointIndex >= getPathSize(pathIndex)) + throw new GeometryException("index out of bounds"); - double calculateSubLength2D(int path_index, int from_point_index, - int to_point_index) { - int absolute_from_index = getPathStart(path_index) + from_point_index; - int absolute_to_index = getPathStart(path_index) + to_point_index; + _verifyAllStreams(); - if (absolute_from_index < 0 || absolute_to_index > getPointCount() - 1) - throw new IllegalArgumentException(); + int pathStart = getPathStart(pathIndex); - SegmentIteratorImpl seg_iter = querySegmentIterator(); + if (pointIndex < 0) + pointIndex = getPathSize(pathIndex) - 1; - if (absolute_from_index > absolute_to_index) { - if (!isClosedPath(path_index)) - throw new IllegalArgumentException( - "cannot iterate across an open path"); + int absoluteIndex = pathStart + pointIndex; - seg_iter.setCirculator(true); - } + // Remove the attribute values for the path + for (int iattr = 0, nattr = m_description.getAttributeCount(); iattr < nattr; iattr++) { + if (m_vertexAttributes[iattr] != null) { + int semantics = m_description._getSemanticsImpl(iattr); + int comp = VertexDescription.getComponentCount(semantics); + m_vertexAttributes[iattr].eraseRange(comp * absoluteIndex, + comp, comp * m_pointCount); + } + } - double prev_length = 0.0; - double sub_length = 0.0; + for (int ipath = pathCount; ipath >= pathIndex + 1; ipath--) { + int iend = m_paths.read(ipath); + m_paths.write(ipath, iend - 1); + } - seg_iter.resetToVertex(absolute_from_index); + m_pointCount--; + m_reservedPointCount--; + notifyModified(DirtyFlags.DirtyCoordinates); + } - do { - assert (seg_iter.hasNextSegment()); - sub_length += prev_length; - Segment segment = seg_iter.nextSegment(); - prev_length = segment.calculateLength2D(); + public double calculatePathLength2D(int pathIndex) /* const */ + { + SegmentIteratorImpl segIter = querySegmentIteratorAtVertex(getPathStart(pathIndex)); - } while (seg_iter.getStartPointIndex() != absolute_to_index); + MathUtils.KahanSummator len = new MathUtils.KahanSummator(0); + while (segIter.hasNextSegment()) { + len.add(segIter.nextSegment().calculateLength2D()); + } - return sub_length; - } + return len.getResult(); + } - @Override - public Geometry getBoundary() { - return Boundary.calculate(this, null); - } + double calculateSubLength2D(int from_path_index, int from_point_index, + int to_path_index, int to_point_index) { + int absolute_from_index = getPathStart(from_path_index) + + from_point_index; + int absolute_to_index = getPathStart(to_path_index) + to_point_index; - // TODO: Add code fore interpolation type (none and angular) - void interpolateAttributes(int from_path_index, int from_point_index, - int to_path_index, int to_point_index) { - for (int ipath = from_path_index; ipath < to_path_index - 1; ipath++) { - if (isClosedPath(ipath)) - throw new IllegalArgumentException( - "cannot interpolate across closed paths"); - } + if (absolute_to_index < absolute_from_index || absolute_from_index < 0 + || absolute_to_index > getPointCount() - 1) + throw new IllegalArgumentException(); - int nattr = m_description.getAttributeCount(); + SegmentIteratorImpl seg_iter = querySegmentIterator(); - if (nattr == 1) - return; // only has position + double sub_length = 0.0; - double sub_length = calculateSubLength2D(from_path_index, - from_point_index, to_path_index, to_point_index); + seg_iter.resetToVertex(absolute_from_index); - if (sub_length == 0.0) - return; + do { + while (seg_iter.hasNextSegment()) { + Segment segment = seg_iter.nextSegment(); - for (int iattr = 1; iattr < nattr; iattr++) { - int semantics = m_description.getSemantics(iattr); + if (seg_iter.getStartPointIndex() == absolute_to_index) + break; - int interpolation = VertexDescription.getInterpolation(semantics); - if (interpolation == VertexDescription.Interpolation.ANGULAR) - continue; + double segment_length = segment.calculateLength2D(); + sub_length += segment_length; + } - int components = VertexDescription.getComponentCount(semantics); + if (seg_iter.getStartPointIndex() == absolute_to_index) + break; - for (int ordinate = 0; ordinate < components; ordinate++) - interpolateAttributes_(semantics, from_path_index, - from_point_index, to_path_index, to_point_index, - sub_length, ordinate); - } - } + } while (seg_iter.nextPath()); - // TODO: Add code for interpolation type (none and angular) - void interpolateAttributesForSemantics(int semantics, int from_path_index, - int from_point_index, int to_path_index, int to_point_index) { - if (semantics == VertexDescription.Semantics.POSITION) - return; + return sub_length; + } - if (!hasAttribute(semantics)) - throw new IllegalArgumentException( - "does not have the given attribute"); + double calculateSubLength2D(int path_index, int from_point_index, + int to_point_index) { + int absolute_from_index = getPathStart(path_index) + from_point_index; + int absolute_to_index = getPathStart(path_index) + to_point_index; - int interpolation = VertexDescription.getInterpolation(semantics); - if (interpolation == VertexDescription.Interpolation.ANGULAR) - throw new IllegalArgumentException( - "not implemented for the given semantics"); + if (absolute_from_index < 0 || absolute_to_index > getPointCount() - 1) + throw new IllegalArgumentException(); - for (int ipath = from_path_index; ipath < to_path_index - 1; ipath++) { - if (isClosedPath(ipath)) - throw new IllegalArgumentException( - "cannot interpolate across closed paths"); - } + SegmentIteratorImpl seg_iter = querySegmentIterator(); - double sub_length = calculateSubLength2D(from_path_index, - from_point_index, to_path_index, to_point_index); + if (absolute_from_index > absolute_to_index) { + if (!isClosedPath(path_index)) + throw new IllegalArgumentException( + "cannot iterate across an open path"); - if (sub_length == 0.0) - return; + seg_iter.setCirculator(true); + } - int components = VertexDescription.getComponentCount(semantics); + double prev_length = 0.0; + double sub_length = 0.0; - for (int ordinate = 0; ordinate < components; ordinate++) - interpolateAttributes_(semantics, from_path_index, - from_point_index, to_path_index, to_point_index, - sub_length, ordinate); - } + seg_iter.resetToVertex(absolute_from_index); - void interpolateAttributes(int path_index, int from_point_index, - int to_point_index) { - int nattr = m_description.getAttributeCount(); + do { + assert (seg_iter.hasNextSegment()); + sub_length += prev_length; + Segment segment = seg_iter.nextSegment(); + prev_length = segment.calculateLength2D(); - if (nattr == 1) - return; // only has position + } while (seg_iter.getStartPointIndex() != absolute_to_index); - double sub_length = calculateSubLength2D(path_index, from_point_index, - to_point_index); + return sub_length; + } - if (sub_length == 0.0) - return; + @Override + public Geometry getBoundary() { + return Boundary.calculate(this, null); + } - for (int iattr = 1; iattr < nattr; iattr++) { - int semantics = m_description.getSemantics(iattr); + // TODO: Add code fore interpolation type (none and angular) + void interpolateAttributes(int from_path_index, int from_point_index, + int to_path_index, int to_point_index) { + for (int ipath = from_path_index; ipath < to_path_index - 1; ipath++) { + if (isClosedPath(ipath)) + throw new IllegalArgumentException( + "cannot interpolate across closed paths"); + } - int interpolation = VertexDescription.getInterpolation(semantics); - if (interpolation == VertexDescription.Interpolation.ANGULAR) - continue; + int nattr = m_description.getAttributeCount(); - int components = VertexDescription.getComponentCount(semantics); + if (nattr == 1) + return; // only has position - for (int ordinate = 0; ordinate < components; ordinate++) - interpolateAttributes_(semantics, path_index, from_point_index, - to_point_index, sub_length, ordinate); - } - } + double sub_length = calculateSubLength2D(from_path_index, + from_point_index, to_path_index, to_point_index); - void interpolateAttributesForSemantics(int semantics, int path_index, - int from_point_index, int to_point_index) { - if (semantics == VertexDescription.Semantics.POSITION) - return; + if (sub_length == 0.0) + return; - if (!hasAttribute(semantics)) - throw new IllegalArgumentException( - "does not have the given attribute"); + for (int iattr = 1; iattr < nattr; iattr++) { + int semantics = m_description.getSemantics(iattr); - int interpolation = VertexDescription.getInterpolation(semantics); - if (interpolation == VertexDescription.Interpolation.ANGULAR) - throw new IllegalArgumentException( - "not implemented for the given semantics"); + int interpolation = VertexDescription.getInterpolation(semantics); + if (interpolation == VertexDescription.Interpolation.ANGULAR) + continue; - double sub_length = calculateSubLength2D(path_index, from_point_index, - to_point_index); + int components = VertexDescription.getComponentCount(semantics); - if (sub_length == 0.0) - return; + for (int ordinate = 0; ordinate < components; ordinate++) + interpolateAttributes_(semantics, from_path_index, + from_point_index, to_path_index, to_point_index, + sub_length, ordinate); + } + } - int components = VertexDescription.getComponentCount(semantics); + // TODO: Add code for interpolation type (none and angular) + void interpolateAttributesForSemantics(int semantics, int from_path_index, + int from_point_index, int to_path_index, int to_point_index) { + if (semantics == VertexDescription.Semantics.POSITION) + return; + + if (!hasAttribute(semantics)) + throw new IllegalArgumentException( + "does not have the given attribute"); + + int interpolation = VertexDescription.getInterpolation(semantics); + if (interpolation == VertexDescription.Interpolation.ANGULAR) + throw new IllegalArgumentException( + "not implemented for the given semantics"); + + for (int ipath = from_path_index; ipath < to_path_index - 1; ipath++) { + if (isClosedPath(ipath)) + throw new IllegalArgumentException( + "cannot interpolate across closed paths"); + } - for (int ordinate = 0; ordinate < components; ordinate++) - interpolateAttributes_(semantics, path_index, from_point_index, - to_point_index, sub_length, ordinate); - } + double sub_length = calculateSubLength2D(from_path_index, + from_point_index, to_path_index, to_point_index); - // TODO: Add code fore interpolation type (none and angular) - void interpolateAttributes_(int semantics, int from_path_index, - int from_point_index, int to_path_index, int to_point_index, - double sub_length, int ordinate) { - SegmentIteratorImpl seg_iter = querySegmentIterator(); - - int absolute_from_index = getPathStart(from_path_index) - + from_point_index; - int absolute_to_index = getPathStart(to_path_index) + to_point_index; + if (sub_length == 0.0) + return; - double from_attribute = getAttributeAsDbl(semantics, - absolute_from_index, ordinate); - double to_attribute = getAttributeAsDbl(semantics, absolute_to_index, - ordinate); - double interpolated_attribute = from_attribute; - double cumulative_length = 0.0; + int components = VertexDescription.getComponentCount(semantics); - seg_iter.resetToVertex(absolute_from_index); + for (int ordinate = 0; ordinate < components; ordinate++) + interpolateAttributes_(semantics, from_path_index, + from_point_index, to_path_index, to_point_index, + sub_length, ordinate); + } - do { - if (seg_iter.hasNextSegment()) { - seg_iter.nextSegment(); - - if (seg_iter.getStartPointIndex() == absolute_to_index) - return; - - setAttribute(semantics, seg_iter.getStartPointIndex(), - ordinate, interpolated_attribute); - - seg_iter.previousSegment(); - - do { - Segment segment = seg_iter.nextSegment(); - - if (seg_iter.getEndPointIndex() == absolute_to_index) - return; - - double segment_length = segment.calculateLength2D(); - cumulative_length += segment_length; - double t = cumulative_length / sub_length; - interpolated_attribute = MathUtils.lerp(from_attribute, to_attribute, t); - - if (!seg_iter.isClosingSegment()) - setAttribute(semantics, seg_iter.getEndPointIndex(), - ordinate, interpolated_attribute); - - } while (seg_iter.hasNextSegment()); - } - - } while (seg_iter.nextPath()); - } - - void interpolateAttributes_(int semantics, int path_index, - int from_point_index, int to_point_index, double sub_length, - int ordinate) { - assert (m_bPolygon); - SegmentIteratorImpl seg_iter = querySegmentIterator(); - - int absolute_from_index = getPathStart(path_index) + from_point_index; - int absolute_to_index = getPathStart(path_index) + to_point_index; - - if (absolute_to_index == absolute_from_index) - return; - - double from_attribute = getAttributeAsDbl(semantics, - absolute_from_index, ordinate); - double to_attribute = getAttributeAsDbl(semantics, absolute_to_index, - ordinate); - double cumulative_length = 0.0; - - seg_iter.resetToVertex(absolute_from_index); - seg_iter.setCirculator(true); - - double prev_interpolated_attribute = from_attribute; - - do { - Segment segment = seg_iter.nextSegment(); - setAttribute(semantics, seg_iter.getStartPointIndex(), ordinate, - prev_interpolated_attribute); - - double segment_length = segment.calculateLength2D(); - cumulative_length += segment_length; - double t = cumulative_length / sub_length; - prev_interpolated_attribute = MathUtils.lerp(from_attribute, to_attribute, t); - - } while (seg_iter.getEndPointIndex() != absolute_to_index); - } - - @Override - public void setEmpty() { - m_curveParamwritePoint = 0; - m_bPathStarted = false; - m_paths = null; - m_pathFlags = null; - m_segmentParamIndex = null; - m_segmentFlags = null; - m_segmentParams = null; - _setEmptyImpl(); - } - - @Override - public void applyTransformation(Transformation2D transform) { - applyTransformation(transform, -1); - } - - public void applyTransformation(Transformation2D transform, int pathIndex) { - if (isEmpty()) - return; - - if (transform.isIdentity()) - return; - - _verifyAllStreams(); - AttributeStreamOfDbl points = (AttributeStreamOfDbl) m_vertexAttributes[0]; - Point2D ptStart = new Point2D(); - Point2D ptControl = new Point2D(); - - boolean bHasNonLinear; - int fistIdx; - int lastIdx; - if (pathIndex < 0) { - bHasNonLinear = hasNonLinearSegments(); - fistIdx = 0; - lastIdx = m_pointCount; - } else { - bHasNonLinear = hasNonLinearSegments(pathIndex); - fistIdx = getPathStart(pathIndex); - lastIdx = getPathEnd(pathIndex); - } - - for (int ipoint = fistIdx; ipoint < lastIdx; ipoint++) { - ptStart.x = points.read(ipoint * 2); - ptStart.y = points.read(ipoint * 2 + 1); - - if (bHasNonLinear) { - int segIndex = m_segmentParamIndex.read(ipoint); - if (segIndex >= 0) { - int segmentType = (int) m_segmentFlags.read(ipoint); - int type = segmentType & SegmentFlags.enumSegmentMask; - switch (type) { - case SegmentFlags.enumBezierSeg: { - ptControl.x = m_segmentParams.read(segIndex); - ptControl.y = m_segmentParams.read(segIndex + 1); - transform.transform(ptControl, ptControl); - m_segmentParams.write(segIndex, ptControl.x); - m_segmentParams.write(segIndex + 1, ptControl.y); - - ptControl.x = m_segmentParams.read(segIndex + 3); - ptControl.y = m_segmentParams.read(segIndex + 4); - transform.transform(ptControl, ptControl); - m_segmentParams.write(segIndex + 3, ptControl.x); - m_segmentParams.write(segIndex + 4, ptControl.y); - } - break; - case SegmentFlags.enumArcSeg: - throw GeometryException.GeometryInternalError(); - - } - } - } - - transform.transform(ptStart, ptStart); - points.write(ipoint * 2, ptStart.x); - points.write(ipoint * 2 + 1, ptStart.y); - } - - notifyModified(DirtyFlags.DirtyCoordinates); - // REFACTOR: reset the exact envelope only and transform the loose - // envelope - } - - @Override - public void applyTransformation(Transformation3D transform) { - if (isEmpty()) - return; - - addAttribute(VertexDescription.Semantics.Z); - _verifyAllStreams(); - AttributeStreamOfDbl points = (AttributeStreamOfDbl) m_vertexAttributes[0]; - AttributeStreamOfDbl zs = (AttributeStreamOfDbl) m_vertexAttributes[1]; - Point3D ptStart = new Point3D(); - Point3D ptControl = new Point3D(); - boolean bHasNonLinear = hasNonLinearSegments(); - for (int ipoint = 0; ipoint < m_pointCount; ipoint++) { - ptStart.x = points.read(ipoint * 2); - ptStart.y = points.read(ipoint * 2 + 1); - ptStart.z = zs.read(ipoint); - - if (bHasNonLinear) { - int segIndex = m_segmentParamIndex.read(ipoint); - if (segIndex >= 0) { - int segmentType = (int) m_segmentFlags.read(ipoint); - int type = segmentType & (int) SegmentFlags.enumSegmentMask; - switch (type) { - case SegmentFlags.enumBezierSeg: { - ptControl.x = m_segmentParams.read(segIndex); - ptControl.y = m_segmentParams.read(segIndex + 1); - ptControl.z = m_segmentParams.read(segIndex + 2); - ptControl = transform.transform(ptControl); - m_segmentParams.write(segIndex, ptControl.x); - m_segmentParams.write(segIndex + 1, ptControl.y); - m_segmentParams.write(segIndex + 1, ptControl.z); - - ptControl.x = m_segmentParams.read(segIndex + 3); - ptControl.y = m_segmentParams.read(segIndex + 4); - ptControl.z = m_segmentParams.read(segIndex + 5); - ptControl = transform.transform(ptControl); - m_segmentParams.write(segIndex + 3, ptControl.x); - m_segmentParams.write(segIndex + 4, ptControl.y); - m_segmentParams.write(segIndex + 5, ptControl.z); - } - break; - case SegmentFlags.enumArcSeg: - throw GeometryException.GeometryInternalError(); - - } - } - } - - ptStart = transform.transform(ptStart); - points.write(ipoint * 2, ptStart.x); - points.write(ipoint * 2 + 1, ptStart.y); - zs.write(ipoint, ptStart.z); - } - - // REFACTOR: reset the exact envelope only and transform the loose - // envelope - - notifyModified(DirtyFlags.DirtyCoordinates); - } - - @Override - protected void _verifyStreamsImpl() { - if (m_paths == null) { - m_paths = (AttributeStreamOfInt32) AttributeStreamBase - .createIndexStream(1, 0); - m_pathFlags = (AttributeStreamOfInt8) AttributeStreamBase - .createByteStream(1, (byte) 0); - } - - if (m_segmentFlags != null) { - m_segmentFlags.resize(m_reservedPointCount, - (byte) SegmentFlags.enumLineSeg); - m_segmentParamIndex.resize(m_reservedPointCount, -1); - } - } - - @Override - void _copyToImpl(MultiVertexGeometryImpl dst) { - MultiPathImpl dstPoly = (MultiPathImpl) dst; - dstPoly.m_bPathStarted = false; - dstPoly.m_curveParamwritePoint = m_curveParamwritePoint; - dstPoly.m_fill_rule = m_fill_rule; - - if (m_paths != null) - dstPoly.m_paths = new AttributeStreamOfInt32(m_paths); - else - dstPoly.m_paths = null; - - if (m_pathFlags != null) - dstPoly.m_pathFlags = new AttributeStreamOfInt8(m_pathFlags); - else - dstPoly.m_pathFlags = null; - - if (m_segmentParamIndex != null) - dstPoly.m_segmentParamIndex = new AttributeStreamOfInt32( - m_segmentParamIndex); - else - dstPoly.m_segmentParamIndex = null; - - if (m_segmentFlags != null) - dstPoly.m_segmentFlags = new AttributeStreamOfInt8(m_segmentFlags); - else - dstPoly.m_segmentFlags = null; - - if (m_segmentParams != null) - dstPoly.m_segmentParams = new AttributeStreamOfDbl(m_segmentParams); - else - dstPoly.m_segmentParams = null; - - dstPoly.m_cachedLength2D = m_cachedLength2D; - dstPoly.m_cachedArea2D = m_cachedArea2D; - - if (!_hasDirtyFlag(DirtyFlags.DirtyRingAreas2D)) { - dstPoly.m_cachedRingAreas2D = (AttributeStreamOfDbl) m_cachedRingAreas2D; - } else - dstPoly.m_cachedRingAreas2D = null; - - } - - @Override - public double calculateLength2D() { - if (!_hasDirtyFlag(DirtyFlags.DirtyLength2D)) { - return m_cachedLength2D; - } - - SegmentIteratorImpl segIter = querySegmentIterator(); - MathUtils.KahanSummator len = new MathUtils.KahanSummator(0); - while (segIter.nextPath()) { - while (segIter.hasNextSegment()) { - len.add(segIter.nextSegment().calculateLength2D()); - } - } - - m_cachedLength2D = len.getResult(); - _setDirtyFlag(DirtyFlags.DirtyLength2D, false); - - return len.getResult(); - } - - @Override - public boolean equals(Object other) { - if (other == this) - return true; - - if (!(other instanceof MultiPathImpl)) - return false; - - if (!super.equals(other)) - return false; - - MultiPathImpl otherMultiPath = (MultiPathImpl) other; - - int pathCount = getPathCount(); - int pathCountOther = otherMultiPath.getPathCount(); - - if (pathCount != pathCountOther) - return false; - - if (pathCount > 0 && m_paths != null - && !m_paths.equals(otherMultiPath.m_paths, 0, pathCount + 1)) - return false; - - if (m_fill_rule != otherMultiPath.m_fill_rule) - return false; - - { - // Note: OGC flags do not participate in the equals operation by - // design. - // Because for the polygon pathFlags will have all enum_closed set, - // we do not need to compare this stream. Only for polyline. - // Polyline does not have OGC flags set. - if (!m_bPolygon) { - if (m_pathFlags != null - && !m_pathFlags.equals(otherMultiPath.m_pathFlags, 0, - pathCount)) - return false; - } - } - - return super.equals(other); - } - - /** - * Returns a SegmentIterator that set to a specific vertex of the - * MultiPathImpl. The call to NextSegment will return the segment that - * starts at the vertex. Call to PreviousSegment will return the segment - * that starts at the previous vertex. - */ - public SegmentIteratorImpl querySegmentIteratorAtVertex(int startVertexIndex) { - if (startVertexIndex < 0 || startVertexIndex >= getPointCount()) - throw new IndexOutOfBoundsException(); - - SegmentIteratorImpl iter = new SegmentIteratorImpl(this, - startVertexIndex); - return iter; - } - - // void QuerySegmentIterator(int fromVertex, SegmentIterator iterator); - public SegmentIteratorImpl querySegmentIterator() { - return new SegmentIteratorImpl(this); - } - - @Override - public void _updateXYImpl(boolean bExact) { - super._updateXYImpl(bExact); - boolean bHasCurves = hasNonLinearSegments(); - if (bHasCurves) { - SegmentIteratorImpl segIter = querySegmentIterator(); - while (segIter.nextPath()) { - while (segIter.hasNextSegment()) { - Segment curve = segIter.nextCurve(); - if (curve != null) { - Envelope2D env2D = new Envelope2D(); - curve.queryEnvelope2D(env2D); - m_envelope.merge(env2D); - } else - break; - } - } - } - } - - @Override - void calculateEnvelope2D(Envelope2D env, boolean bExact) { - super.calculateEnvelope2D(env, bExact); - boolean bHasCurves = hasNonLinearSegments(); - if (bHasCurves) { - SegmentIteratorImpl segIter = querySegmentIterator(); - while (segIter.nextPath()) { - while (segIter.hasNextSegment()) { - Segment curve = segIter.nextCurve(); - if (curve != null) { - Envelope2D env2D = new Envelope2D(); - curve.queryEnvelope2D(env2D); - env.merge(env2D); - } else - break; - } - } - } - } - - @Override - public void _notifyModifiedAllImpl() { - if (m_paths == null || m_paths.size() == 0)// if (m_paths == null || - // !m_paths.size()) - m_pointCount = 0; - else - m_pointCount = m_paths.read(m_paths.size() - 1); - } - - @Override - public double calculateArea2D() { - if (!m_bPolygon) - return 0.0; - - _updateRingAreas2D(); - - return m_cachedArea2D; - } - - /** - * Returns True if the ring is an exterior ring. Valid only for simple - * polygons. - */ - public boolean isExteriorRing(int ringIndex) { - if (!m_bPolygon) - return false; - - if (!_hasDirtyFlag(DirtyFlags.DirtyOGCFlags)) - return (m_pathFlags.read(ringIndex) & (byte) PathFlags.enumOGCStartPolygon) != 0; - - _updateRingAreas2D(); - return m_cachedRingAreas2D.read(ringIndex) > 0; - // Should we make a function called _UpdateHasNonLinearSegmentsFlags and - // call it here? - } - - public double calculateRingArea2D(int pathIndex) { - if (!m_bPolygon) - return 0.0; - - _updateRingAreas2D(); - - return m_cachedRingAreas2D.read(pathIndex); - } - - public void _updateRingAreas2D() { - if (_hasDirtyFlag(DirtyFlags.DirtyRingAreas2D)) { - int pathCount = getPathCount(); - - if (m_cachedRingAreas2D == null) - m_cachedRingAreas2D = new AttributeStreamOfDbl(pathCount); - else if (m_cachedRingAreas2D.size() != pathCount) - m_cachedRingAreas2D.resize(pathCount); - - MathUtils.KahanSummator totalArea = new MathUtils.KahanSummator(0); - MathUtils.KahanSummator pathArea = new MathUtils.KahanSummator(0); - Point2D pt = new Point2D(); - int ipath = 0; - SegmentIteratorImpl segIter = querySegmentIterator(); - while (segIter.nextPath()) { - pathArea.reset(); - getXY(getPathStart(segIter.getPathIndex()), pt);// get the area - // calculation - // origin to be - // the origin of - // the ring. - while (segIter.hasNextSegment()) { - pathArea.add(segIter.nextSegment()._calculateArea2DHelper( - pt.x, pt.y)); - } - - totalArea.add(pathArea.getResult()); - - int i = ipath++; - m_cachedRingAreas2D.write(i, pathArea.getResult()); - } - - m_cachedArea2D = totalArea.getResult(); - _setDirtyFlag(DirtyFlags.DirtyRingAreas2D, false); - } - } - - int getOGCPolygonCount() { - if (!m_bPolygon) - return 0; - - _updateOGCFlags(); - - int polygonCount = 0; - int partCount = getPathCount(); - for (int ipart = 0; ipart < partCount; ipart++) { - if (((int) m_pathFlags.read(ipart) & (int) PathFlags.enumOGCStartPolygon) != 0) - polygonCount++; - } - - return polygonCount; - } - - protected void _updateOGCFlags() { - if (_hasDirtyFlag(DirtyFlags.DirtyOGCFlags)) { - _updateRingAreas2D(); - - int pathCount = getPathCount(); - if (pathCount > 0 && (m_pathFlags == null || m_pathFlags.size() < pathCount)) - m_pathFlags = (AttributeStreamOfInt8) AttributeStreamBase - .createByteStream(pathCount + 1); - - int firstSign = 1; - for (int ipath = 0; ipath < pathCount; ipath++) { - double area = m_cachedRingAreas2D.read(ipath); - if (ipath == 0) - firstSign = area > 0 ? 1 : -1; - if (area * firstSign > 0.0) - m_pathFlags.setBits(ipath, - (byte) PathFlags.enumOGCStartPolygon); - else - m_pathFlags.clearBits(ipath, - (byte) PathFlags.enumOGCStartPolygon); - } - _setDirtyFlag(DirtyFlags.DirtyOGCFlags, false); - } - } - - public int getPathIndexFromPointIndex(int pointIndex) { - int positionHint = m_currentPathIndex;// in case of multithreading - // thiswould simply produce an - // invalid value - int pathCount = getPathCount(); - - // Try using the hint position first to get the path index. - if (positionHint >= 0 && positionHint < pathCount) { - if (pointIndex < getPathEnd(positionHint)) { - if (pointIndex >= getPathStart(positionHint)) - return positionHint; - positionHint--; - } else { - positionHint++; - } - - if (positionHint >= 0 && positionHint < pathCount) { - if (pointIndex >= getPathStart(positionHint) - && pointIndex < getPathEnd(positionHint)) { - m_currentPathIndex = positionHint; - return positionHint; - } - } - } - - if (pathCount < 5) {// TODO: time the performance to choose when to use - // linear search. - for (int i = 0; i < pathCount; i++) { - if (pointIndex < getPathEnd(i)) { - m_currentPathIndex = i; - return i; - } - } - throw new GeometryException("corrupted geometry"); - } - - // Do binary search: - int minPathIndex = 0; - int maxPathIndex = pathCount - 1; - while (maxPathIndex > minPathIndex) { - int mid = minPathIndex + ((maxPathIndex - minPathIndex) >> 1); - int pathStart = getPathStart(mid); - if (pointIndex < pathStart) - maxPathIndex = mid - 1; - else { - int pathEnd = getPathEnd(mid); - if (pointIndex >= pathEnd) - minPathIndex = mid + 1; - else { - m_currentPathIndex = mid; - return mid; - } - } - } - - m_currentPathIndex = minPathIndex; - return minPathIndex; - } - - int getHighestPointIndex(int path_index) { - assert (path_index >= 0 && path_index < getPathCount()); - - AttributeStreamOfDbl position = (AttributeStreamOfDbl) (getAttributeStreamRef(VertexDescription.Semantics.POSITION)); - AttributeStreamOfInt32 paths = (AttributeStreamOfInt32) (getPathStreamRef()); - - int path_end = getPathEnd(path_index); - int path_start = getPathStart(path_index); - int max_index = -1; - Point2D max_point = new Point2D(), pt = new Point2D(); - max_point.y = NumberUtils.negativeInf(); - max_point.x = NumberUtils.negativeInf(); - - for (int i = path_start + 0; i < path_end; i++) { - position.read(2 * i, pt); - if (max_point.compare(pt) == -1) { - max_index = i; - max_point.setCoords(pt); - } - } - - return max_index; - } - - /** - * Returns total segment count in the MultiPathImpl. - */ - public int getSegmentCount() { - int segCount = getPointCount(); - if (!m_bPolygon) { - segCount -= getPathCount(); - for (int i = 0, n = getPathCount(); i < n; i++) - if (isClosedPath(i)) - segCount++; - } - - return segCount; - } - - public int getSegmentCount(int path_index) { - int segCount = getPathSize(path_index); - if (!isClosedPath(path_index)) - segCount--; - return segCount; - } - - // HEADER defintions - @Override - public Geometry createInstance() { - return new MultiPathImpl(m_bPolygon, getDescription()); - } - - @Override - public int getDimension() { - return m_bPolygon ? 2 : 1; - } - - @Override - public Geometry.Type getType() { - return m_bPolygon ? Type.Polygon : Type.Polyline; - } - - /** - * Returns True if the class is envelope. THis is not an exact method. Only - * addEnvelope makes this true. - */ - public boolean isEnvelope() { - return !_hasDirtyFlag(DirtyFlags.DirtyIsEnvelope); - } - - /** - * Returns a reference to the AttributeStream of MultiPathImpl parts - * (Paths). - *

- * For the non empty MultiPathImpl, that stream contains start points of the - * MultiPathImpl curves. In addition, the last element is the total point - * count. The number of vertices in a given part is parts[i + 1] - parts[i]. - */ - public AttributeStreamOfInt32 getPathStreamRef() { - throwIfEmpty(); - return m_paths; - } - - /** - * sets a reference to an AttributeStream of MultiPathImpl paths (Paths). - */ - public void setPathStreamRef(AttributeStreamOfInt32 paths) { - m_paths = paths; - notifyModified(DirtyFlags.DirtyAll); - } - - /** - * Returns a reference to the AttributeStream of Segment flags (SegmentFlags - * flags). Can be NULL when no non-linear segments are present. - *

- * Segment flags indicate what kind of segment originates (starts) on the - * given point. The last vertices of open Path parts has enumNone flag. - */ - public AttributeStreamOfInt8 getSegmentFlagsStreamRef() { - throwIfEmpty(); - return m_segmentFlags; - } - - /** - * Returns a reference to the AttributeStream of Path flags (PathFlags - * flags). - *

- * Each start point of a path has a flag set to indicate if the Path is open - * or closed. - */ - public AttributeStreamOfInt8 getPathFlagsStreamRef() { - throwIfEmpty(); - return m_pathFlags; - } - - /** - * sets a reference to an AttributeStream of Path flags (PathFlags flags). - */ - public void setPathFlagsStreamRef(AttributeStreamOfInt8 pathFlags) { - m_pathFlags = pathFlags; - notifyModified(DirtyFlags.DirtyAll); - } - - public AttributeStreamOfInt32 getSegmentIndexStreamRef() { - throwIfEmpty(); - return m_segmentParamIndex; - } - - public AttributeStreamOfDbl getSegmentDataStreamRef() { - throwIfEmpty(); - return m_segmentParams; - } - - public int getPathCount() { - return (m_paths != null) ? m_paths.size() - 1 : 0; - } - - public int getPathEnd(int partIndex) { - return m_paths.read(partIndex + 1); - } - - public int getPathSize(int partIndex) { - return m_paths.read(partIndex + 1) - m_paths.read(partIndex); - } - - public int getPathStart(int partIndex) { - return m_paths.read(partIndex); - } - - @Override - public Object _getImpl() { - return this; - } - - public void setDirtyOGCFlags(boolean bYesNo) { - _setDirtyFlag(DirtyFlags.DirtyOGCFlags, bYesNo); - } - - public boolean hasDirtyOGCStartFlags() { - return _hasDirtyFlag(DirtyFlags.DirtyOGCFlags); - } - - public void setDirtyRingAreas2D(boolean bYesNo) { - _setDirtyFlag(DirtyFlags.DirtyRingAreas2D, bYesNo); - } - - public boolean hasDirtyRingAreas2D() { - return _hasDirtyFlag(DirtyFlags.DirtyRingAreas2D); - } - - public void setRingAreasStreamRef(AttributeStreamOfDbl ringAreas) { - m_cachedRingAreas2D = ringAreas; - _setDirtyFlag(DirtyFlags.DirtyRingAreas2D, false); - } - - // HEADER defintions - - // // TODO check this against current implementation in native - // public void notifyModified(int flags) - // { - // if(flags == DirtyFlags.DirtyAll) - // { - // m_reservedPointCount = -1; - // _notifyModifiedAllImpl(); - // } - // m_flagsMask |= flags; - // _clearAccelerators(); - // - // - // // ROHIT's implementation - // // if (m_paths == null || 0 == m_paths.size()) - // // m_pointCount = 0; - // // else - // // m_pointCount = m_paths.read(m_paths.size() - 1); - // // - // // super.notifyModified(flags); - // } - - @Override - public boolean _buildRasterizedGeometryAccelerator(double toleranceXY, - GeometryAccelerationDegree accelDegree) { - if (m_accelerators == null)// (!m_accelerators) - { - m_accelerators = new GeometryAccelerators(); - } - - int rasterSize = RasterizedGeometry2D - .rasterSizeFromAccelerationDegree(accelDegree); - RasterizedGeometry2D rgeom = m_accelerators.getRasterizedGeometry(); - if (rgeom != null) { - if (rgeom.getToleranceXY() < toleranceXY - || rasterSize > rgeom.getRasterSize()) { - m_accelerators._setRasterizedGeometry(null); - } else - return true; - } - - rgeom = RasterizedGeometry2D.create(this, toleranceXY, rasterSize); - m_accelerators._setRasterizedGeometry(rgeom); - //rgeom.dbgSaveToBitmap("c:/temp/ddd.bmp"); - return true; - } - - @Override - public int hashCode() { - int hashCode = super.hashCode(); - - if (!isEmptyImpl()) { - int pathCount = getPathCount(); - - if (m_paths != null) - m_paths.calculateHashImpl(hashCode, 0, pathCount + 1); - - if (m_pathFlags != null) - m_pathFlags.calculateHashImpl(hashCode, 0, pathCount); - } - - return hashCode; - } - - public byte getSegmentFlags(int ivertex) { - if (m_segmentFlags != null) - return m_segmentFlags.read(ivertex); - else - return (byte) SegmentFlags.enumLineSeg; - } - - public void getSegment(int startVertexIndex, SegmentBuffer segBuffer, - boolean bStripAttributes) { - int ipath = getPathIndexFromPointIndex(startVertexIndex); - if (startVertexIndex == getPathEnd(ipath) - 1 && !isClosedPath(ipath)) - throw new GeometryException("index out of bounds"); - - _verifyAllStreams(); - AttributeStreamOfInt8 segFlagStream = getSegmentFlagsStreamRef(); - int segFlag = SegmentFlags.enumLineSeg; - if (segFlagStream != null) - segFlag = segFlagStream.read(startVertexIndex) - & SegmentFlags.enumSegmentMask; - - switch (segFlag) { - case SegmentFlags.enumLineSeg: - segBuffer.createLine(); - break; - case SegmentFlags.enumBezierSeg: - throw GeometryException.GeometryInternalError(); - case SegmentFlags.enumArcSeg: - throw GeometryException.GeometryInternalError(); - default: - throw GeometryException.GeometryInternalError(); - } - - Segment currentSegment = segBuffer.get(); - if (!bStripAttributes) - currentSegment.assignVertexDescription(m_description); - else - currentSegment - .assignVertexDescription(VertexDescriptionDesignerImpl - .getDefaultDescriptor2D()); - - int endVertexIndex; - if (startVertexIndex == getPathEnd(ipath) - 1 && isClosedPath(ipath)) { - endVertexIndex = getPathStart(ipath); - } else - endVertexIndex = startVertexIndex + 1; - - Point2D pt = new Point2D(); - getXY(startVertexIndex, pt); - currentSegment.setStartXY(pt); - getXY(endVertexIndex, pt); - currentSegment.setEndXY(pt); - - if (!bStripAttributes) { - for (int i = 1, nattr = m_description.getAttributeCount(); i < nattr; i++) { - int semantics = m_description._getSemanticsImpl(i); - int ncomp = VertexDescription.getComponentCount(semantics); - for (int ord = 0; ord < ncomp; ord++) { - double vs = getAttributeAsDbl(semantics, startVertexIndex, - ord); - currentSegment.setStartAttribute(semantics, ord, vs); - double ve = getAttributeAsDbl(semantics, endVertexIndex, - ord); - currentSegment.setEndAttribute(semantics, ord, ve); - } - } - } - } - - void queryPathEnvelope2D(int path_index, Envelope2D envelope) { - if (path_index >= getPathCount()) - throw new IllegalArgumentException(); - - if (isEmpty()) { - envelope.setEmpty(); - return; - } - - if (hasNonLinearSegments(path_index)) { - throw new GeometryException("not implemented"); - } else { - AttributeStreamOfDbl stream = (AttributeStreamOfDbl) getAttributeStreamRef(VertexDescription.Semantics.POSITION); - Point2D pt = new Point2D(); - Envelope2D env = new Envelope2D(); - env.setEmpty(); - for (int i = getPathStart(path_index), iend = getPathEnd(path_index); i < iend; i++) { - stream.read(2 * i, pt); - env.merge(pt); - } - envelope.setCoords(env); - } - } - - public void queryLoosePathEnvelope2D(int path_index, Envelope2D envelope) { - if (path_index >= getPathCount()) - throw new IllegalArgumentException(); - - if (isEmpty()) { - envelope.setEmpty(); - return; - } - - if (hasNonLinearSegments(path_index)) { - throw new GeometryException("not implemented"); - } else { - AttributeStreamOfDbl stream = (AttributeStreamOfDbl) getAttributeStreamRef(VertexDescription.Semantics.POSITION); - Point2D pt = new Point2D(); - Envelope2D env = new Envelope2D(); - env.setEmpty(); - for (int i = getPathStart(path_index), iend = getPathEnd(path_index); i < iend; i++) { - stream.read(2 * i, pt); - env.merge(pt); - } - envelope.setCoords(env); - } - } - - @Override - public boolean _buildQuadTreeAccelerator(GeometryAccelerationDegree d) { - if (m_accelerators == null)// (!m_accelerators) - { - m_accelerators = new GeometryAccelerators(); - } - - if (d == GeometryAccelerationDegree.enumMild || getPointCount() < 16) - return false; - - QuadTreeImpl quad_tree_impl = InternalUtils.buildQuadTree(this); - m_accelerators._setQuadTree(quad_tree_impl); - - return true; - } - - boolean _buildQuadTreeForPathsAccelerator(GeometryAccelerationDegree degree) { - if (m_accelerators == null) { - m_accelerators = new GeometryAccelerators(); - } - - // TODO: when less than two envelopes - no need to this. - - if (m_accelerators.getQuadTreeForPaths() != null) - return true; - - m_accelerators._setQuadTreeForPaths(null); - QuadTreeImpl quad_tree_impl = InternalUtils.buildQuadTreeForPaths(this); - m_accelerators._setQuadTreeForPaths(quad_tree_impl); - - return true; - } - - void setFillRule(int rule) { - assert (m_bPolygon); - m_fill_rule = rule; - } - - int getFillRule() { - return m_fill_rule; - } - - void clearDirtyOGCFlags() { - _setDirtyFlag(DirtyFlags.DirtyOGCFlags, false); - } + void interpolateAttributes(int path_index, int from_point_index, + int to_point_index) { + int nattr = m_description.getAttributeCount(); + + if (nattr == 1) + return; // only has position + + double sub_length = calculateSubLength2D(path_index, from_point_index, + to_point_index); + + if (sub_length == 0.0) + return; + + for (int iattr = 1; iattr < nattr; iattr++) { + int semantics = m_description.getSemantics(iattr); + + int interpolation = VertexDescription.getInterpolation(semantics); + if (interpolation == VertexDescription.Interpolation.ANGULAR) + continue; + + int components = VertexDescription.getComponentCount(semantics); + + for (int ordinate = 0; ordinate < components; ordinate++) + interpolateAttributes_(semantics, path_index, from_point_index, + to_point_index, sub_length, ordinate); + } + } + + void interpolateAttributesForSemantics(int semantics, int path_index, + int from_point_index, int to_point_index) { + if (semantics == VertexDescription.Semantics.POSITION) + return; + + if (!hasAttribute(semantics)) + throw new IllegalArgumentException( + "does not have the given attribute"); + + int interpolation = VertexDescription.getInterpolation(semantics); + if (interpolation == VertexDescription.Interpolation.ANGULAR) + throw new IllegalArgumentException( + "not implemented for the given semantics"); + + double sub_length = calculateSubLength2D(path_index, from_point_index, + to_point_index); + + if (sub_length == 0.0) + return; + + int components = VertexDescription.getComponentCount(semantics); + + for (int ordinate = 0; ordinate < components; ordinate++) + interpolateAttributes_(semantics, path_index, from_point_index, + to_point_index, sub_length, ordinate); + } + + // TODO: Add code fore interpolation type (none and angular) + void interpolateAttributes_(int semantics, int from_path_index, + int from_point_index, int to_path_index, int to_point_index, + double sub_length, int ordinate) { + SegmentIteratorImpl seg_iter = querySegmentIterator(); + + int absolute_from_index = getPathStart(from_path_index) + + from_point_index; + int absolute_to_index = getPathStart(to_path_index) + to_point_index; + + double from_attribute = getAttributeAsDbl(semantics, + absolute_from_index, ordinate); + double to_attribute = getAttributeAsDbl(semantics, absolute_to_index, + ordinate); + double interpolated_attribute = from_attribute; + double cumulative_length = 0.0; + + seg_iter.resetToVertex(absolute_from_index); + + do { + if (seg_iter.hasNextSegment()) { + seg_iter.nextSegment(); + + if (seg_iter.getStartPointIndex() == absolute_to_index) + return; + + setAttribute(semantics, seg_iter.getStartPointIndex(), + ordinate, interpolated_attribute); + + seg_iter.previousSegment(); + + do { + Segment segment = seg_iter.nextSegment(); + + if (seg_iter.getEndPointIndex() == absolute_to_index) + return; + + double segment_length = segment.calculateLength2D(); + cumulative_length += segment_length; + double t = cumulative_length / sub_length; + interpolated_attribute = MathUtils.lerp(from_attribute, to_attribute, t); + + if (!seg_iter.isClosingSegment()) + setAttribute(semantics, seg_iter.getEndPointIndex(), + ordinate, interpolated_attribute); + + } while (seg_iter.hasNextSegment()); + } + + } while (seg_iter.nextPath()); + } + + void interpolateAttributes_(int semantics, int path_index, + int from_point_index, int to_point_index, double sub_length, + int ordinate) { + assert (m_bPolygon); + SegmentIteratorImpl seg_iter = querySegmentIterator(); + + int absolute_from_index = getPathStart(path_index) + from_point_index; + int absolute_to_index = getPathStart(path_index) + to_point_index; + + if (absolute_to_index == absolute_from_index) + return; + + double from_attribute = getAttributeAsDbl(semantics, + absolute_from_index, ordinate); + double to_attribute = getAttributeAsDbl(semantics, absolute_to_index, + ordinate); + double cumulative_length = 0.0; + + seg_iter.resetToVertex(absolute_from_index); + seg_iter.setCirculator(true); + + double prev_interpolated_attribute = from_attribute; + + do { + Segment segment = seg_iter.nextSegment(); + setAttribute(semantics, seg_iter.getStartPointIndex(), ordinate, + prev_interpolated_attribute); + + double segment_length = segment.calculateLength2D(); + cumulative_length += segment_length; + double t = cumulative_length / sub_length; + prev_interpolated_attribute = MathUtils.lerp(from_attribute, to_attribute, t); + + } while (seg_iter.getEndPointIndex() != absolute_to_index); + } + + @Override + public void setEmpty() { + m_curveParamwritePoint = 0; + m_bPathStarted = false; + m_paths = null; + m_pathFlags = null; + m_segmentParamIndex = null; + m_segmentFlags = null; + m_segmentParams = null; + _setEmptyImpl(); + } + + @Override + public void applyTransformation(Transformation2D transform) { + applyTransformation(transform, -1); + } + + public void applyTransformation(Transformation2D transform, int pathIndex) { + if (isEmpty()) + return; + + if (transform.isIdentity()) + return; + + _verifyAllStreams(); + AttributeStreamOfDbl points = (AttributeStreamOfDbl) m_vertexAttributes[0]; + Point2D ptStart = new Point2D(); + Point2D ptControl = new Point2D(); + + boolean bHasNonLinear; + int fistIdx; + int lastIdx; + if (pathIndex < 0) { + bHasNonLinear = hasNonLinearSegments(); + fistIdx = 0; + lastIdx = m_pointCount; + } else { + bHasNonLinear = hasNonLinearSegments(pathIndex); + fistIdx = getPathStart(pathIndex); + lastIdx = getPathEnd(pathIndex); + } + + for (int ipoint = fistIdx; ipoint < lastIdx; ipoint++) { + ptStart.x = points.read(ipoint * 2); + ptStart.y = points.read(ipoint * 2 + 1); + + if (bHasNonLinear) { + int segIndex = m_segmentParamIndex.read(ipoint); + if (segIndex >= 0) { + int segmentType = (int) m_segmentFlags.read(ipoint); + int type = segmentType & SegmentFlags.enumSegmentMask; + switch (type) { + case SegmentFlags.enumBezierSeg: { + ptControl.x = m_segmentParams.read(segIndex); + ptControl.y = m_segmentParams.read(segIndex + 1); + transform.transform(ptControl, ptControl); + m_segmentParams.write(segIndex, ptControl.x); + m_segmentParams.write(segIndex + 1, ptControl.y); + + ptControl.x = m_segmentParams.read(segIndex + 3); + ptControl.y = m_segmentParams.read(segIndex + 4); + transform.transform(ptControl, ptControl); + m_segmentParams.write(segIndex + 3, ptControl.x); + m_segmentParams.write(segIndex + 4, ptControl.y); + } + break; + case SegmentFlags.enumArcSeg: + throw GeometryException.GeometryInternalError(); + + } + } + } + + transform.transform(ptStart, ptStart); + points.write(ipoint * 2, ptStart.x); + points.write(ipoint * 2 + 1, ptStart.y); + } + + notifyModified(DirtyFlags.DirtyCoordinates); + // REFACTOR: reset the exact envelope only and transform the loose + // envelope + } + + @Override + public void applyTransformation(Transformation3D transform) { + if (isEmpty()) + return; + + addAttribute(VertexDescription.Semantics.Z); + _verifyAllStreams(); + AttributeStreamOfDbl points = (AttributeStreamOfDbl) m_vertexAttributes[0]; + AttributeStreamOfDbl zs = (AttributeStreamOfDbl) m_vertexAttributes[1]; + Point3D ptStart = new Point3D(); + Point3D ptControl = new Point3D(); + boolean bHasNonLinear = hasNonLinearSegments(); + for (int ipoint = 0; ipoint < m_pointCount; ipoint++) { + ptStart.x = points.read(ipoint * 2); + ptStart.y = points.read(ipoint * 2 + 1); + ptStart.z = zs.read(ipoint); + + if (bHasNonLinear) { + int segIndex = m_segmentParamIndex.read(ipoint); + if (segIndex >= 0) { + int segmentType = (int) m_segmentFlags.read(ipoint); + int type = segmentType & (int) SegmentFlags.enumSegmentMask; + switch (type) { + case SegmentFlags.enumBezierSeg: { + ptControl.x = m_segmentParams.read(segIndex); + ptControl.y = m_segmentParams.read(segIndex + 1); + ptControl.z = m_segmentParams.read(segIndex + 2); + ptControl = transform.transform(ptControl); + m_segmentParams.write(segIndex, ptControl.x); + m_segmentParams.write(segIndex + 1, ptControl.y); + m_segmentParams.write(segIndex + 1, ptControl.z); + + ptControl.x = m_segmentParams.read(segIndex + 3); + ptControl.y = m_segmentParams.read(segIndex + 4); + ptControl.z = m_segmentParams.read(segIndex + 5); + ptControl = transform.transform(ptControl); + m_segmentParams.write(segIndex + 3, ptControl.x); + m_segmentParams.write(segIndex + 4, ptControl.y); + m_segmentParams.write(segIndex + 5, ptControl.z); + } + break; + case SegmentFlags.enumArcSeg: + throw GeometryException.GeometryInternalError(); + + } + } + } + + ptStart = transform.transform(ptStart); + points.write(ipoint * 2, ptStart.x); + points.write(ipoint * 2 + 1, ptStart.y); + zs.write(ipoint, ptStart.z); + } + + // REFACTOR: reset the exact envelope only and transform the loose + // envelope + + notifyModified(DirtyFlags.DirtyCoordinates); + } + + @Override + protected void _verifyStreamsImpl() { + if (m_paths == null) { + m_paths = (AttributeStreamOfInt32) AttributeStreamBase + .createIndexStream(1, 0); + m_pathFlags = (AttributeStreamOfInt8) AttributeStreamBase + .createByteStream(1, (byte) 0); + } + + if (m_segmentFlags != null) { + m_segmentFlags.resize(m_reservedPointCount, + (byte) SegmentFlags.enumLineSeg); + m_segmentParamIndex.resize(m_reservedPointCount, -1); + } + } + + @Override + void _copyToImpl(MultiVertexGeometryImpl dst) { + MultiPathImpl dstPoly = (MultiPathImpl) dst; + dstPoly.m_bPathStarted = false; + dstPoly.m_curveParamwritePoint = m_curveParamwritePoint; + dstPoly.m_fill_rule = m_fill_rule; + + if (m_paths != null) + dstPoly.m_paths = new AttributeStreamOfInt32(m_paths); + else + dstPoly.m_paths = null; + + if (m_pathFlags != null) + dstPoly.m_pathFlags = new AttributeStreamOfInt8(m_pathFlags); + else + dstPoly.m_pathFlags = null; + + if (m_segmentParamIndex != null) + dstPoly.m_segmentParamIndex = new AttributeStreamOfInt32( + m_segmentParamIndex); + else + dstPoly.m_segmentParamIndex = null; + + if (m_segmentFlags != null) + dstPoly.m_segmentFlags = new AttributeStreamOfInt8(m_segmentFlags); + else + dstPoly.m_segmentFlags = null; + + if (m_segmentParams != null) + dstPoly.m_segmentParams = new AttributeStreamOfDbl(m_segmentParams); + else + dstPoly.m_segmentParams = null; + + dstPoly.m_cachedLength2D = m_cachedLength2D; + dstPoly.m_cachedArea2D = m_cachedArea2D; + + if (!_hasDirtyFlag(DirtyFlags.DirtyRingAreas2D)) { + dstPoly.m_cachedRingAreas2D = (AttributeStreamOfDbl) m_cachedRingAreas2D; + } else + dstPoly.m_cachedRingAreas2D = null; + + } + + @Override + public double calculateLength2D() { + if (!_hasDirtyFlag(DirtyFlags.DirtyLength2D)) { + return m_cachedLength2D; + } + + SegmentIteratorImpl segIter = querySegmentIterator(); + MathUtils.KahanSummator len = new MathUtils.KahanSummator(0); + while (segIter.nextPath()) { + while (segIter.hasNextSegment()) { + len.add(segIter.nextSegment().calculateLength2D()); + } + } + + m_cachedLength2D = len.getResult(); + _setDirtyFlag(DirtyFlags.DirtyLength2D, false); + + return len.getResult(); + } + + @Override + public boolean equals(Object other) { + if (other == this) + return true; + + if (!(other instanceof MultiPathImpl)) + return false; + + if (!super.equals(other)) + return false; + + MultiPathImpl otherMultiPath = (MultiPathImpl) other; + + int pathCount = getPathCount(); + int pathCountOther = otherMultiPath.getPathCount(); + + if (pathCount != pathCountOther) + return false; + + if (pathCount > 0 && m_paths != null + && !m_paths.equals(otherMultiPath.m_paths, 0, pathCount + 1)) + return false; + + if (m_fill_rule != otherMultiPath.m_fill_rule) + return false; + + { + // Note: OGC flags do not participate in the equals operation by + // design. + // Because for the polygon pathFlags will have all enum_closed set, + // we do not need to compare this stream. Only for polyline. + // Polyline does not have OGC flags set. + if (!m_bPolygon) { + if (m_pathFlags != null + && !m_pathFlags.equals(otherMultiPath.m_pathFlags, 0, + pathCount)) + return false; + } + } + + return super.equals(other); + } + + /** + * Returns a SegmentIterator that set to a specific vertex of the + * MultiPathImpl. The call to NextSegment will return the segment that + * starts at the vertex. Call to PreviousSegment will return the segment + * that starts at the previous vertex. + */ + public SegmentIteratorImpl querySegmentIteratorAtVertex(int startVertexIndex) { + if (startVertexIndex < 0 || startVertexIndex >= getPointCount()) + throw new IndexOutOfBoundsException(); + + SegmentIteratorImpl iter = new SegmentIteratorImpl(this, + startVertexIndex); + return iter; + } + + // void QuerySegmentIterator(int fromVertex, SegmentIterator iterator); + public SegmentIteratorImpl querySegmentIterator() { + return new SegmentIteratorImpl(this); + } + + @Override + public void _updateXYImpl(boolean bExact) { + super._updateXYImpl(bExact); + boolean bHasCurves = hasNonLinearSegments(); + if (bHasCurves) { + SegmentIteratorImpl segIter = querySegmentIterator(); + while (segIter.nextPath()) { + while (segIter.hasNextSegment()) { + Segment curve = segIter.nextCurve(); + if (curve != null) { + Envelope2D env2D = new Envelope2D(); + curve.queryEnvelope2D(env2D); + m_envelope.merge(env2D); + } else + break; + } + } + } + } + + @Override + void calculateEnvelope2D(Envelope2D env, boolean bExact) { + super.calculateEnvelope2D(env, bExact); + boolean bHasCurves = hasNonLinearSegments(); + if (bHasCurves) { + SegmentIteratorImpl segIter = querySegmentIterator(); + while (segIter.nextPath()) { + while (segIter.hasNextSegment()) { + Segment curve = segIter.nextCurve(); + if (curve != null) { + Envelope2D env2D = new Envelope2D(); + curve.queryEnvelope2D(env2D); + env.merge(env2D); + } else + break; + } + } + } + } + + @Override + public void _notifyModifiedAllImpl() { + if (m_paths == null || m_paths.size() == 0)// if (m_paths == null || + // !m_paths.size()) + m_pointCount = 0; + else + m_pointCount = m_paths.read(m_paths.size() - 1); + } + + @Override + public double calculateArea2D() { + if (!m_bPolygon) + return 0.0; + + _updateRingAreas2D(); + + return m_cachedArea2D; + } + + /** + * Returns True if the ring is an exterior ring. Valid only for simple + * polygons. + */ + public boolean isExteriorRing(int ringIndex) { + if (!m_bPolygon) + return false; + + if (!_hasDirtyFlag(DirtyFlags.DirtyOGCFlags)) + return (m_pathFlags.read(ringIndex) & (byte) PathFlags.enumOGCStartPolygon) != 0; + + _updateRingAreas2D(); + return m_cachedRingAreas2D.read(ringIndex) > 0; + // Should we make a function called _UpdateHasNonLinearSegmentsFlags and + // call it here? + } + + public double calculateRingArea2D(int pathIndex) { + if (!m_bPolygon) + return 0.0; + + _updateRingAreas2D(); + + return m_cachedRingAreas2D.read(pathIndex); + } + + public void _updateRingAreas2D() { + if (_hasDirtyFlag(DirtyFlags.DirtyRingAreas2D)) { + int pathCount = getPathCount(); + + if (m_cachedRingAreas2D == null) + m_cachedRingAreas2D = new AttributeStreamOfDbl(pathCount); + else if (m_cachedRingAreas2D.size() != pathCount) + m_cachedRingAreas2D.resize(pathCount); + + MathUtils.KahanSummator totalArea = new MathUtils.KahanSummator(0); + MathUtils.KahanSummator pathArea = new MathUtils.KahanSummator(0); + Point2D pt = new Point2D(); + int ipath = 0; + SegmentIteratorImpl segIter = querySegmentIterator(); + while (segIter.nextPath()) { + pathArea.reset(); + getXY(getPathStart(segIter.getPathIndex()), pt);// get the area + // calculation + // origin to be + // the origin of + // the ring. + while (segIter.hasNextSegment()) { + pathArea.add(segIter.nextSegment()._calculateArea2DHelper( + pt.x, pt.y)); + } + + totalArea.add(pathArea.getResult()); + + int i = ipath++; + m_cachedRingAreas2D.write(i, pathArea.getResult()); + } + + m_cachedArea2D = totalArea.getResult(); + _setDirtyFlag(DirtyFlags.DirtyRingAreas2D, false); + } + } + + int getOGCPolygonCount() { + if (!m_bPolygon) + return 0; + + _updateOGCFlags(); + + int polygonCount = 0; + int partCount = getPathCount(); + for (int ipart = 0; ipart < partCount; ipart++) { + if (((int) m_pathFlags.read(ipart) & (int) PathFlags.enumOGCStartPolygon) != 0) + polygonCount++; + } + + return polygonCount; + } + + protected void _updateOGCFlags() { + if (_hasDirtyFlag(DirtyFlags.DirtyOGCFlags)) { + _updateRingAreas2D(); + + int pathCount = getPathCount(); + if (pathCount > 0 && (m_pathFlags == null || m_pathFlags.size() < pathCount)) + m_pathFlags = (AttributeStreamOfInt8) AttributeStreamBase + .createByteStream(pathCount + 1); + + int firstSign = 1; + for (int ipath = 0; ipath < pathCount; ipath++) { + double area = m_cachedRingAreas2D.read(ipath); + if (ipath == 0) + firstSign = area > 0 ? 1 : -1; + if (area * firstSign > 0.0) + m_pathFlags.setBits(ipath, + (byte) PathFlags.enumOGCStartPolygon); + else + m_pathFlags.clearBits(ipath, + (byte) PathFlags.enumOGCStartPolygon); + } + _setDirtyFlag(DirtyFlags.DirtyOGCFlags, false); + } + } + + public int getPathIndexFromPointIndex(int pointIndex) { + int positionHint = m_currentPathIndex;// in case of multithreading + // thiswould simply produce an + // invalid value + int pathCount = getPathCount(); + + // Try using the hint position first to get the path index. + if (positionHint >= 0 && positionHint < pathCount) { + if (pointIndex < getPathEnd(positionHint)) { + if (pointIndex >= getPathStart(positionHint)) + return positionHint; + positionHint--; + } else { + positionHint++; + } + + if (positionHint >= 0 && positionHint < pathCount) { + if (pointIndex >= getPathStart(positionHint) + && pointIndex < getPathEnd(positionHint)) { + m_currentPathIndex = positionHint; + return positionHint; + } + } + } + + if (pathCount < 5) {// TODO: time the performance to choose when to use + // linear search. + for (int i = 0; i < pathCount; i++) { + if (pointIndex < getPathEnd(i)) { + m_currentPathIndex = i; + return i; + } + } + throw new GeometryException("corrupted geometry"); + } + + // Do binary search: + int minPathIndex = 0; + int maxPathIndex = pathCount - 1; + while (maxPathIndex > minPathIndex) { + int mid = minPathIndex + ((maxPathIndex - minPathIndex) >> 1); + int pathStart = getPathStart(mid); + if (pointIndex < pathStart) + maxPathIndex = mid - 1; + else { + int pathEnd = getPathEnd(mid); + if (pointIndex >= pathEnd) + minPathIndex = mid + 1; + else { + m_currentPathIndex = mid; + return mid; + } + } + } + + m_currentPathIndex = minPathIndex; + return minPathIndex; + } + + int getHighestPointIndex(int path_index) { + assert (path_index >= 0 && path_index < getPathCount()); + + AttributeStreamOfDbl position = (AttributeStreamOfDbl) (getAttributeStreamRef(VertexDescription.Semantics.POSITION)); + AttributeStreamOfInt32 paths = (AttributeStreamOfInt32) (getPathStreamRef()); + + int path_end = getPathEnd(path_index); + int path_start = getPathStart(path_index); + int max_index = -1; + Point2D max_point = new Point2D(), pt = new Point2D(); + max_point.y = NumberUtils.negativeInf(); + max_point.x = NumberUtils.negativeInf(); + + for (int i = path_start + 0; i < path_end; i++) { + position.read(2 * i, pt); + if (max_point.compare(pt) == -1) { + max_index = i; + max_point.setCoords(pt); + } + } + + return max_index; + } + + /** + * Returns total segment count in the MultiPathImpl. + */ + public int getSegmentCount() { + int segCount = getPointCount(); + if (!m_bPolygon) { + segCount -= getPathCount(); + for (int i = 0, n = getPathCount(); i < n; i++) + if (isClosedPath(i)) + segCount++; + } + + return segCount; + } + + public int getSegmentCount(int path_index) { + int segCount = getPathSize(path_index); + if (!isClosedPath(path_index)) + segCount--; + return segCount; + } + + // HEADER defintions + @Override + public Geometry createInstance() { + return new MultiPathImpl(m_bPolygon, getDescription()); + } + + @Override + public int getDimension() { + return m_bPolygon ? 2 : 1; + } + + @Override + public Geometry.Type getType() { + return m_bPolygon ? Type.Polygon : Type.Polyline; + } + + /** + * Returns True if the class is envelope. THis is not an exact method. Only + * addEnvelope makes this true. + */ + public boolean isEnvelope() { + return !_hasDirtyFlag(DirtyFlags.DirtyIsEnvelope); + } + + /** + * Returns a reference to the AttributeStream of MultiPathImpl parts + * (Paths). + * + * For the non empty MultiPathImpl, that stream contains start points of the + * MultiPathImpl curves. In addition, the last element is the total point + * count. The number of vertices in a given part is parts[i + 1] - parts[i]. + */ + public AttributeStreamOfInt32 getPathStreamRef() { + throwIfEmpty(); + return m_paths; + } + + /** + * sets a reference to an AttributeStream of MultiPathImpl paths (Paths). + */ + public void setPathStreamRef(AttributeStreamOfInt32 paths) { + m_paths = paths; + notifyModified(DirtyFlags.DirtyAll); + } + + /** + * Returns a reference to the AttributeStream of Segment flags (SegmentFlags + * flags). Can be NULL when no non-linear segments are present. + * + * Segment flags indicate what kind of segment originates (starts) on the + * given point. The last vertices of open Path parts has enumNone flag. + */ + public AttributeStreamOfInt8 getSegmentFlagsStreamRef() { + throwIfEmpty(); + return m_segmentFlags; + } + + /** + * Returns a reference to the AttributeStream of Path flags (PathFlags + * flags). + * + * Each start point of a path has a flag set to indicate if the Path is open + * or closed. + */ + public AttributeStreamOfInt8 getPathFlagsStreamRef() { + throwIfEmpty(); + return m_pathFlags; + } + + /** + * sets a reference to an AttributeStream of Path flags (PathFlags flags). + */ + public void setPathFlagsStreamRef(AttributeStreamOfInt8 pathFlags) { + m_pathFlags = pathFlags; + notifyModified(DirtyFlags.DirtyAll); + } + + public AttributeStreamOfInt32 getSegmentIndexStreamRef() { + throwIfEmpty(); + return m_segmentParamIndex; + } + + public AttributeStreamOfDbl getSegmentDataStreamRef() { + throwIfEmpty(); + return m_segmentParams; + } + + public int getPathCount() { + return (m_paths != null) ? m_paths.size() - 1 : 0; + } + + public int getPathEnd(int partIndex) { + return m_paths.read(partIndex + 1); + } + + public int getPathSize(int partIndex) { + return m_paths.read(partIndex + 1) - m_paths.read(partIndex); + } + + public int getPathStart(int partIndex) { + return m_paths.read(partIndex); + } + + @Override + public Object _getImpl() { + return this; + } + + public void setDirtyOGCFlags(boolean bYesNo) { + _setDirtyFlag(DirtyFlags.DirtyOGCFlags, bYesNo); + } + + public boolean hasDirtyOGCStartFlags() { + return _hasDirtyFlag(DirtyFlags.DirtyOGCFlags); + } + + public void setDirtyRingAreas2D(boolean bYesNo) { + _setDirtyFlag(DirtyFlags.DirtyRingAreas2D, bYesNo); + } + + public boolean hasDirtyRingAreas2D() { + return _hasDirtyFlag(DirtyFlags.DirtyRingAreas2D); + } + + public void setRingAreasStreamRef(AttributeStreamOfDbl ringAreas) { + m_cachedRingAreas2D = ringAreas; + _setDirtyFlag(DirtyFlags.DirtyRingAreas2D, false); + } + + // HEADER defintions + + // // TODO check this against current implementation in native + // public void notifyModified(int flags) + // { + // if(flags == DirtyFlags.DirtyAll) + // { + // m_reservedPointCount = -1; + // _notifyModifiedAllImpl(); + // } + // m_flagsMask |= flags; + // _clearAccelerators(); + // + // + // // ROHIT's implementation + // // if (m_paths == null || 0 == m_paths.size()) + // // m_pointCount = 0; + // // else + // // m_pointCount = m_paths.read(m_paths.size() - 1); + // // + // // super.notifyModified(flags); + // } + + @Override + public boolean _buildRasterizedGeometryAccelerator(double toleranceXY, + GeometryAccelerationDegree accelDegree) { + if (m_accelerators == null)// (!m_accelerators) + { + m_accelerators = new GeometryAccelerators(); + } + + int rasterSize = RasterizedGeometry2D + .rasterSizeFromAccelerationDegree(accelDegree); + RasterizedGeometry2D rgeom = m_accelerators.getRasterizedGeometry(); + if (rgeom != null) { + if (rgeom.getToleranceXY() < toleranceXY + || rasterSize > rgeom.getRasterSize()) { + m_accelerators._setRasterizedGeometry(null); + } else + return true; + } + + rgeom = RasterizedGeometry2D.create(this, toleranceXY, rasterSize); + m_accelerators._setRasterizedGeometry(rgeom); + //rgeom.dbgSaveToBitmap("c:/temp/ddd.bmp"); + return true; + } + + @Override + public int hashCode() { + int hashCode = super.hashCode(); + + if (!isEmptyImpl()) { + int pathCount = getPathCount(); + + if (m_paths != null) + m_paths.calculateHashImpl(hashCode, 0, pathCount + 1); + + if (m_pathFlags != null) + m_pathFlags.calculateHashImpl(hashCode, 0, pathCount); + } + + return hashCode; + } + + public byte getSegmentFlags(int ivertex) { + if (m_segmentFlags != null) + return m_segmentFlags.read(ivertex); + else + return (byte) SegmentFlags.enumLineSeg; + } + + public void getSegment(int startVertexIndex, SegmentBuffer segBuffer, + boolean bStripAttributes) { + int ipath = getPathIndexFromPointIndex(startVertexIndex); + if (startVertexIndex == getPathEnd(ipath) - 1 && !isClosedPath(ipath)) + throw new GeometryException("index out of bounds"); + + _verifyAllStreams(); + AttributeStreamOfInt8 segFlagStream = getSegmentFlagsStreamRef(); + int segFlag = SegmentFlags.enumLineSeg; + if (segFlagStream != null) + segFlag = segFlagStream.read(startVertexIndex) + & SegmentFlags.enumSegmentMask; + + switch (segFlag) { + case SegmentFlags.enumLineSeg: + segBuffer.createLine(); + break; + case SegmentFlags.enumBezierSeg: + throw GeometryException.GeometryInternalError(); + case SegmentFlags.enumArcSeg: + throw GeometryException.GeometryInternalError(); + default: + throw GeometryException.GeometryInternalError(); + } + + Segment currentSegment = segBuffer.get(); + if (!bStripAttributes) + currentSegment.assignVertexDescription(m_description); + else + currentSegment + .assignVertexDescription(VertexDescriptionDesignerImpl + .getDefaultDescriptor2D()); + + int endVertexIndex; + if (startVertexIndex == getPathEnd(ipath) - 1 && isClosedPath(ipath)) { + endVertexIndex = getPathStart(ipath); + } else + endVertexIndex = startVertexIndex + 1; + + Point2D pt = new Point2D(); + getXY(startVertexIndex, pt); + currentSegment.setStartXY(pt); + getXY(endVertexIndex, pt); + currentSegment.setEndXY(pt); + + if (!bStripAttributes) { + for (int i = 1, nattr = m_description.getAttributeCount(); i < nattr; i++) { + int semantics = m_description._getSemanticsImpl(i); + int ncomp = VertexDescription.getComponentCount(semantics); + for (int ord = 0; ord < ncomp; ord++) { + double vs = getAttributeAsDbl(semantics, startVertexIndex, + ord); + currentSegment.setStartAttribute(semantics, ord, vs); + double ve = getAttributeAsDbl(semantics, endVertexIndex, + ord); + currentSegment.setEndAttribute(semantics, ord, ve); + } + } + } + } + + void queryPathEnvelope2D(int path_index, Envelope2D envelope) { + if (path_index >= getPathCount()) + throw new IllegalArgumentException(); + + if (isEmpty()) { + envelope.setEmpty(); + return; + } + + if (hasNonLinearSegments(path_index)) { + throw new GeometryException("not implemented"); + } else { + AttributeStreamOfDbl stream = (AttributeStreamOfDbl) getAttributeStreamRef(VertexDescription.Semantics.POSITION); + Point2D pt = new Point2D(); + Envelope2D env = new Envelope2D(); + env.setEmpty(); + for (int i = getPathStart(path_index), iend = getPathEnd(path_index); i < iend; i++) { + stream.read(2 * i, pt); + env.merge(pt); + } + envelope.setCoords(env); + } + } + + public void queryLoosePathEnvelope2D(int path_index, Envelope2D envelope) { + if (path_index >= getPathCount()) + throw new IllegalArgumentException(); + + if (isEmpty()) { + envelope.setEmpty(); + return; + } + + if (hasNonLinearSegments(path_index)) { + throw new GeometryException("not implemented"); + } else { + AttributeStreamOfDbl stream = (AttributeStreamOfDbl) getAttributeStreamRef(VertexDescription.Semantics.POSITION); + Point2D pt = new Point2D(); + Envelope2D env = new Envelope2D(); + env.setEmpty(); + for (int i = getPathStart(path_index), iend = getPathEnd(path_index); i < iend; i++) { + stream.read(2 * i, pt); + env.merge(pt); + } + envelope.setCoords(env); + } + } + + @Override + public boolean _buildQuadTreeAccelerator(GeometryAccelerationDegree d) { + if (m_accelerators == null)// (!m_accelerators) + { + m_accelerators = new GeometryAccelerators(); + } + + if (d == GeometryAccelerationDegree.enumMild || getPointCount() < 16) + return false; + + QuadTreeImpl quad_tree_impl = InternalUtils.buildQuadTree(this); + m_accelerators._setQuadTree(quad_tree_impl); + + return true; + } + + boolean _buildQuadTreeForPathsAccelerator(GeometryAccelerationDegree degree) { + if (m_accelerators == null) { + m_accelerators = new GeometryAccelerators(); + } + + // TODO: when less than two envelopes - no need to this. + + if (m_accelerators.getQuadTreeForPaths() != null) + return true; + + m_accelerators._setQuadTreeForPaths(null); + QuadTreeImpl quad_tree_impl = InternalUtils.buildQuadTreeForPaths(this); + m_accelerators._setQuadTreeForPaths(quad_tree_impl); + + return true; + } + + void setFillRule(int rule) { + assert (m_bPolygon); + m_fill_rule = rule; + } + + int getFillRule() { + return m_fill_rule; + } + + void clearDirtyOGCFlags() { + _setDirtyFlag(DirtyFlags.DirtyOGCFlags, false); + } } diff --git a/src/main/java/com/esri/core/geometry/MultiPoint.java b/src/main/java/com/esri/core/geometry/MultiPoint.java index 43f40642..bcdae5ac 100644 --- a/src/main/java/com/esri/core/geometry/MultiPoint.java +++ b/src/main/java/com/esri/core/geometry/MultiPoint.java @@ -35,221 +35,220 @@ * essential characteristic of the point set. */ public class MultiPoint extends MultiVertexGeometry implements - Serializable { - - private static final long serialVersionUID = 2L; - - private MultiPointImpl m_impl; - - /** - * Creates a new empty multipoint. - */ - public MultiPoint() { - m_impl = new MultiPointImpl(); - } - - public MultiPoint(VertexDescription description) { - m_impl = new MultiPointImpl(description); - } - - @Override - public double getAttributeAsDbl(int semantics, int index, int ordinate) { - return m_impl.getAttributeAsDbl(semantics, index, ordinate); - } - - @Override - public int getAttributeAsInt(int semantics, int index, int ordinate) { - return m_impl.getAttributeAsInt(semantics, index, ordinate); - } - - @Override - public Point getPoint(int index) { - return m_impl.getPoint(index); - } - - @Override - public int getPointCount() { - return m_impl.getPointCount(); - } - - @Override - public Point2D getXY(int index) { - return m_impl.getXY(index); - } - - @Override - public void getXY(int index, Point2D pt) { - m_impl.getXY(index, pt); - } - - @Override - Point3D getXYZ(int index) { - return m_impl.getXYZ(index); - } - - @Override - public void queryCoordinates(Point2D[] dst) { - m_impl.queryCoordinates(dst); - } - - @Override - public void queryCoordinates(Point[] dst) { - m_impl.queryCoordinates(dst); - } - - @Override - protected Object _getImpl() { - return m_impl; - } - - /** - * Adds a point multipoint. - * - * @param point The Point to be added to this multipoint. - */ - public void add(Point point) { - m_impl.add(point); - } - - /** - * Adds a point with the specified X, Y coordinates to this multipoint. - * - * @param x The new Point's X coordinate. - * @param y The new Point's Y coordinate. - */ - public void add(double x, double y) { - m_impl.add(x, y); - } - - /** - * Adds a point with the specified X, Y coordinates to this multipoint. - * - * @param pt the point to add - */ - public void add(Point2D pt) { - m_impl.add(pt.x, pt.y); - } - - /** - * Adds a 3DPoint with the specified X, Y, Z coordinates to this multipoint. - * - * @param x The new Point's X coordinate. - * @param y The new Point's Y coordinate. - * @param z The new Point's Z coordinate. - */ - void add(double x, double y, double z) { - m_impl.add(x, y, z); - } - - /** - * Appends points from another multipoint at the end of this multipoint. - * - * @param src The mulitpoint to append to this multipoint. - * @param srcFrom The start index in the source multipoint from which to start - * appending points. - * @param srcTo The end index in the source multipoint right after the last - * point to be appended. Use -1 to indicate the rest of the - * source multipoint. - */ - public void add(MultiVertexGeometry src, int srcFrom, int srcTo) { - m_impl.add((MultiVertexGeometryImpl) src._getImpl(), srcFrom, srcTo); - } - - void addPoints(Point2D[] points) { - m_impl.addPoints(points); - } - - void addPoints(Point[] points) { - m_impl.addPoints(points); - } - - /** - * Inserts a point to this multipoint. - * - * @param beforePointIndex The index right before the new point to insert. - * @param pt The point to insert. - */ - public void insertPoint(int beforePointIndex, Point pt) { - m_impl.insertPoint(beforePointIndex, pt); - } // inserts a point. The point is connected with Lines - - /** - * Removes a point from this multipoint. - * - * @param pointIndex The index of the point to be removed. - */ - public void removePoint(int pointIndex) { - m_impl.removePoint(pointIndex); - } - - /** - * Resizes the multipoint to have the given size. - * - * @param pointCount - The number of points in this multipoint. - */ - public void resize(int pointCount) { - m_impl.resize(pointCount); - } - - @Override - void queryCoordinates(Point3D[] dst) { - m_impl.queryCoordinates(dst); - } - - @Override - public void setAttribute(int semantics, int index, int ordinate, - double value) { - m_impl.setAttribute(semantics, index, ordinate, value); - } - - @Override - public void setAttribute(int semantics, int index, int ordinate, int value) { - m_impl.setAttribute(semantics, index, ordinate, value); - } - - @Override - public void setPoint(int index, Point pointSrc) { - m_impl.setPoint(index, pointSrc); - } - - @Override - public void setXY(int index, Point2D pt) { - m_impl.setXY(index, pt); - } - - @Override - void setXYZ(int index, Point3D pt) { - m_impl.setXYZ(index, pt); - } - - @Override - public void applyTransformation(Transformation2D transform) { - m_impl.applyTransformation(transform); - } - - @Override - void applyTransformation(Transformation3D transform) { - m_impl.applyTransformation(transform); - } - - @Override - public void copyTo(Geometry dst) { - m_impl.copyTo((Geometry) dst._getImpl()); - } - - @Override - public Geometry createInstance() { - return new MultiPoint(getDescription()); - } - - @Override - public int getDimension() { - return 0; - } - - @Override - public long estimateMemorySize() - { + Serializable { + + private static final long serialVersionUID = 2L; + + private MultiPointImpl m_impl; + + /** + * Creates a new empty multipoint. + */ + public MultiPoint() { + m_impl = new MultiPointImpl(); + } + + public MultiPoint(VertexDescription description) { + m_impl = new MultiPointImpl(description); + } + + @Override + public double getAttributeAsDbl(int semantics, int index, int ordinate) { + return m_impl.getAttributeAsDbl(semantics, index, ordinate); + } + + @Override + public int getAttributeAsInt(int semantics, int index, int ordinate) { + return m_impl.getAttributeAsInt(semantics, index, ordinate); + } + + @Override + public Point getPoint(int index) { + return m_impl.getPoint(index); + } + + @Override + public int getPointCount() { + return m_impl.getPointCount(); + } + + @Override + public Point2D getXY(int index) { + return m_impl.getXY(index); + } + + @Override + public void getXY(int index, Point2D pt) { + m_impl.getXY(index, pt); + } + + @Override + Point3D getXYZ(int index) { + return m_impl.getXYZ(index); + } + + @Override + public void queryCoordinates(Point2D[] dst) { + m_impl.queryCoordinates(dst); + } + + @Override + public void queryCoordinates(Point[] dst) { + m_impl.queryCoordinates(dst); + } + + @Override + protected Object _getImpl() { + return m_impl; + } + + /** + * Adds a point multipoint. + * + * @param point The Point to be added to this multipoint. + */ + public void add(Point point) { + m_impl.add(point); + } + + /** + * Adds a point with the specified X, Y coordinates to this multipoint. + * + * @param x The new Point's X coordinate. + * @param y The new Point's Y coordinate. + */ + public void add(double x, double y) { + m_impl.add(x, y); + } + + /** + * Adds a point with the specified X, Y coordinates to this multipoint. + * + * @param pt the point to add + */ + public void add(Point2D pt) { + m_impl.add(pt.x, pt.y); + } + + /** + * Adds a 3DPoint with the specified X, Y, Z coordinates to this multipoint. + * + * @param x The new Point's X coordinate. + * @param y The new Point's Y coordinate. + * @param z The new Point's Z coordinate. + */ + void add(double x, double y, double z) { + m_impl.add(x, y, z); + } + + /** + * Appends points from another multipoint at the end of this multipoint. + * + * @param src The mulitpoint to append to this multipoint. + * @param srcFrom The start index in the source multipoint from which to start + * appending points. + * @param srcTo The end index in the source multipoint right after the last + * point to be appended. Use -1 to indicate the rest of the + * source multipoint. + */ + public void add(MultiVertexGeometry src, int srcFrom, int srcTo) { + m_impl.add((MultiVertexGeometryImpl) src._getImpl(), srcFrom, srcTo); + } + + void addPoints(Point2D[] points) { + m_impl.addPoints(points); + } + + void addPoints(Point[] points) { + m_impl.addPoints(points); + } + + /** + * Inserts a point to this multipoint. + * + * @param beforePointIndex The index right before the new point to insert. + * @param pt The point to insert. + */ + public void insertPoint(int beforePointIndex, Point pt) { + m_impl.insertPoint(beforePointIndex, pt); + } // inserts a point. The point is connected with Lines + + /** + * Removes a point from this multipoint. + * + * @param pointIndex The index of the point to be removed. + */ + public void removePoint(int pointIndex) { + m_impl.removePoint(pointIndex); + } + + /** + * Resizes the multipoint to have the given size. + * + * @param pointCount - The number of points in this multipoint. + */ + public void resize(int pointCount) { + m_impl.resize(pointCount); + } + + @Override + void queryCoordinates(Point3D[] dst) { + m_impl.queryCoordinates(dst); + } + + @Override + public void setAttribute(int semantics, int index, int ordinate, + double value) { + m_impl.setAttribute(semantics, index, ordinate, value); + } + + @Override + public void setAttribute(int semantics, int index, int ordinate, int value) { + m_impl.setAttribute(semantics, index, ordinate, value); + } + + @Override + public void setPoint(int index, Point pointSrc) { + m_impl.setPoint(index, pointSrc); + } + + @Override + public void setXY(int index, Point2D pt) { + m_impl.setXY(index, pt); + } + + @Override + void setXYZ(int index, Point3D pt) { + m_impl.setXYZ(index, pt); + } + + @Override + public void applyTransformation(Transformation2D transform) { + m_impl.applyTransformation(transform); + } + + @Override + void applyTransformation(Transformation3D transform) { + m_impl.applyTransformation(transform); + } + + @Override + public void copyTo(Geometry dst) { + m_impl.copyTo((Geometry) dst._getImpl()); + } + + @Override + public Geometry createInstance() { + return new MultiPoint(getDescription()); + } + + @Override + public int getDimension() { + return 0; + } + + @Override + public long estimateMemorySize() { return SIZE_OF_MULTI_POINT + m_impl.estimateMemorySize(); } @@ -258,119 +257,119 @@ public Geometry.Type getType() { return Type.MultiPoint; } - @Override - public VertexDescription getDescription() { - return m_impl.getDescription(); - } - - @Override - public void addAttribute(int semantics) { - m_impl.addAttribute(semantics); - } - - @Override - public void assignVertexDescription(VertexDescription src) { - m_impl.assignVertexDescription(src); - } - - @Override - public void dropAllAttributes() { - m_impl.dropAllAttributes(); - } - - @Override - public void dropAttribute(int semantics) { - m_impl.dropAttribute(semantics); - } - - @Override - public void mergeVertexDescription(VertexDescription src) { - m_impl.mergeVertexDescription(src); - } - - @Override - public boolean isEmpty() { - return m_impl.isEmpty(); - } - - @Override - public void queryEnvelope(Envelope env) { - m_impl.queryEnvelope(env); - } - - @Override - public void queryEnvelope2D(Envelope2D env) { - m_impl.queryEnvelope2D(env); - } - - @Override - void queryEnvelope3D(Envelope3D env) { - m_impl.queryEnvelope3D(env); - } - - @Override - public Envelope1D queryInterval(int semantics, int ordinate) { - return m_impl.queryInterval(semantics, ordinate); - } - - @Override - public void setEmpty() { - m_impl.setEmpty(); - } - - /** - * Returns TRUE when this geometry has exactly same type, properties, and - * coordinates as the other geometry. - */ - @Override - public boolean equals(Object other) { - if (other == null) - return false; - - if (other == this) - return true; - - if (other.getClass() != getClass()) - return false; - - return m_impl.equals(((MultiPoint) other)._getImpl()); - } - - /** - * Returns a hash code value for this multipoint. - */ - @Override - public int hashCode() { - return m_impl.hashCode(); - } - - int queryCoordinates(Point2D[] dst, int dstSize, int beginIndex, - int endIndex) { - return m_impl.queryCoordinates(dst, dstSize, beginIndex, endIndex); - } - - @Override - public void getPointByVal(int index, Point outPoint) { - m_impl.getPointByVal(index, outPoint); - } - - @Override - public void setPointByVal(int index, Point pointSrc) { - m_impl.setPointByVal(index, pointSrc); - } - - @Override - public int getStateFlag() { - return m_impl.getStateFlag(); - } - - @Override - public Geometry getBoundary() { - return m_impl.getBoundary(); - } - - @Override - public void replaceNaNs(int semantics, double value) { - m_impl.replaceNaNs(semantics, value); - } + @Override + public VertexDescription getDescription() { + return m_impl.getDescription(); + } + + @Override + public void addAttribute(int semantics) { + m_impl.addAttribute(semantics); + } + + @Override + public void assignVertexDescription(VertexDescription src) { + m_impl.assignVertexDescription(src); + } + + @Override + public void dropAllAttributes() { + m_impl.dropAllAttributes(); + } + + @Override + public void dropAttribute(int semantics) { + m_impl.dropAttribute(semantics); + } + + @Override + public void mergeVertexDescription(VertexDescription src) { + m_impl.mergeVertexDescription(src); + } + + @Override + public boolean isEmpty() { + return m_impl.isEmpty(); + } + + @Override + public void queryEnvelope(Envelope env) { + m_impl.queryEnvelope(env); + } + + @Override + public void queryEnvelope2D(Envelope2D env) { + m_impl.queryEnvelope2D(env); + } + + @Override + void queryEnvelope3D(Envelope3D env) { + m_impl.queryEnvelope3D(env); + } + + @Override + public Envelope1D queryInterval(int semantics, int ordinate) { + return m_impl.queryInterval(semantics, ordinate); + } + + @Override + public void setEmpty() { + m_impl.setEmpty(); + } + + /** + * Returns TRUE when this geometry has exactly same type, properties, and + * coordinates as the other geometry. + */ + @Override + public boolean equals(Object other) { + if (other == null) + return false; + + if (other == this) + return true; + + if (other.getClass() != getClass()) + return false; + + return m_impl.equals(((MultiPoint) other)._getImpl()); + } + + /** + * Returns a hash code value for this multipoint. + */ + @Override + public int hashCode() { + return m_impl.hashCode(); + } + + int queryCoordinates(Point2D[] dst, int dstSize, int beginIndex, + int endIndex) { + return m_impl.queryCoordinates(dst, dstSize, beginIndex, endIndex); + } + + @Override + public void getPointByVal(int index, Point outPoint) { + m_impl.getPointByVal(index, outPoint); + } + + @Override + public void setPointByVal(int index, Point pointSrc) { + m_impl.setPointByVal(index, pointSrc); + } + + @Override + public int getStateFlag() { + return m_impl.getStateFlag(); + } + + @Override + public Geometry getBoundary() { + return m_impl.getBoundary(); + } + + @Override + public void replaceNaNs(int semantics, double value) { + m_impl.replaceNaNs(semantics, value); + } } diff --git a/src/main/java/com/esri/core/geometry/MultiPointImpl.java b/src/main/java/com/esri/core/geometry/MultiPointImpl.java index 0825b86e..4e401a8f 100644 --- a/src/main/java/com/esri/core/geometry/MultiPointImpl.java +++ b/src/main/java/com/esri/core/geometry/MultiPointImpl.java @@ -33,224 +33,223 @@ */ final class MultiPointImpl extends MultiVertexGeometryImpl { - public MultiPointImpl() { - super(); - m_description = VertexDescriptionDesignerImpl.getDefaultDescriptor2D(); - m_pointCount = 0; - } - - public MultiPointImpl(VertexDescription description) { - super(); - if (description == null) - throw new IllegalArgumentException(); - - m_description = description; - m_pointCount = 0; - } - - @Override - public Geometry createInstance() { - return new MultiPoint(m_description); - } - - /** - * Adds a Point to this MultiPoint. - */ - public void add(Point point) { - resize(m_pointCount + 1); - setPoint(m_pointCount - 1, point); - } - - /** - * Adds a Point to this MultiPoint with given x, y coordinates. - */ - public void add(double x, double y) { - resize(m_pointCount + 1); - Point2D pt = new Point2D(); - pt.setCoords(x, y); - setXY(m_pointCount - 1, pt); - } - - /** - * Adds a Point to this MultiPoint with given x, y, z coordinates. - */ - public void add(double x, double y, double z) { - resize(m_pointCount + 1); - Point3D pt = new Point3D(); - pt.setCoords(x, y, z); - setXYZ(m_pointCount - 1, pt); - } - - /** - * Appends points from another MultiVertexGeometryImpl at the end of this - * one. - * - * @param src The source MultiVertexGeometryImpl - */ - public void add(MultiVertexGeometryImpl src, int beginIndex, int endIndex) { - int endIndexC = endIndex < 0 ? src.getPointCount() : endIndex; - if (beginIndex < 0 || beginIndex > src.getPointCount() - || endIndexC < beginIndex) - throw new IllegalArgumentException(); - - if (beginIndex == endIndexC) - return; - - mergeVertexDescription(src.getDescription()); - int count = endIndexC - beginIndex; - int oldPointCount = m_pointCount; - resize(m_pointCount + count); - _verifyAllStreams(); - for (int iattrib = 0, nattrib = src.getDescription() - .getAttributeCount(); iattrib < nattrib; iattrib++) { - int semantics = src.getDescription()._getSemanticsImpl(iattrib); - int ncomps = VertexDescription.getComponentCount(semantics); - AttributeStreamBase stream = getAttributeStreamRef(semantics); - AttributeStreamBase srcStream = src - .getAttributeStreamRef(semantics); - stream.insertRange(oldPointCount * ncomps, srcStream, beginIndex - * ncomps, count * ncomps, true, 1, oldPointCount * ncomps); - } - } - - public void addPoints(Point2D[] points) { - int count = points.length; - int oldPointCount = m_pointCount; - resize(m_pointCount + count); - for (int i = 0; i < count; i++) - setXY(oldPointCount + i, points[i]); - } - - public void insertPoint(int beforePointIndex, Point pt) { - if (beforePointIndex > getPointCount()) - throw new GeometryException("index out of bounds"); - - if (beforePointIndex < 0) - beforePointIndex = getPointCount(); - - mergeVertexDescription(pt.getDescription()); - int oldPointCount = m_pointCount; - _resizeImpl(m_pointCount + 1); - _verifyAllStreams(); - - for (int iattr = 0, nattr = m_description.getAttributeCount(); iattr < nattr; iattr++) { - int semantics = m_description._getSemanticsImpl(iattr); - int comp = VertexDescription.getComponentCount(semantics); - - AttributeStreamBase stream = AttributeStreamBase - .createAttributeStreamWithSemantics(semantics, 1); - if (pt.hasAttribute(semantics)) { - m_vertexAttributes[iattr] - .insertAttributes(comp * beforePointIndex, pt, - semantics, comp * oldPointCount); - } else { - // Need to make room for the attribute, so we copy a default - // value in - - double v = VertexDescription.getDefaultValue(semantics); - m_vertexAttributes[iattr].insertRange(comp * beforePointIndex, - v, comp, comp * oldPointCount); - } - } - - notifyModified(DirtyFlags.DirtyCoordinates); - } - - void removePoint(int pointIndex) { - if (pointIndex < 0 || pointIndex >= getPointCount()) - throw new GeometryException("index out of bounds"); - - _verifyAllStreams(); - - // Remove the attribute value for the path - for (int iattr = 0, nattr = m_description.getAttributeCount(); iattr < nattr; iattr++) { - if (m_vertexAttributes[iattr] != null) { - int semantics = m_description._getSemanticsImpl(iattr); - int comp = VertexDescription.getComponentCount(semantics); - m_vertexAttributes[iattr].eraseRange(comp * pointIndex, comp, - comp * m_pointCount); - } - } - - m_pointCount--; - m_reservedPointCount--; - notifyModified(DirtyFlags.DirtyCoordinates); - } - - /** - * Resizes the MultiPoint to have the given size. - */ - public void resize(int pointCount) { - _resizeImpl(pointCount); - } - - @Override - void _copyToImpl(MultiVertexGeometryImpl mvg) { - } - - @Override - public void setEmpty() { - super._setEmptyImpl(); - } - - @Override - public void applyTransformation(Transformation2D transform) { - if (isEmpty()) - return; - - _verifyAllStreams(); - AttributeStreamOfDbl points = (AttributeStreamOfDbl) m_vertexAttributes[0]; - Point2D pt2 = new Point2D(); - - for (int ipoint = 0; ipoint < m_pointCount; ipoint++) { - pt2.x = points.read(ipoint * 2); - pt2.y = points.read(ipoint * 2 + 1); - - transform.transform(pt2, pt2); - points.write(ipoint * 2, pt2.x); - points.write(ipoint * 2 + 1, pt2.y); - } - - // REFACTOR: reset the exact envelope only and transform the loose - // envelope - notifyModified(DirtyFlags.DirtyCoordinates); - } - - @Override - void applyTransformation(Transformation3D transform) { - if (isEmpty()) - return; - - _verifyAllStreams(); - addAttribute(Semantics.Z); - _verifyAllStreams(); - AttributeStreamOfDbl points = (AttributeStreamOfDbl) m_vertexAttributes[0]; - AttributeStreamOfDbl zs = (AttributeStreamOfDbl) m_vertexAttributes[1]; - Point3D pt3 = new Point3D(); - for (int ipoint = 0; ipoint < m_pointCount; ipoint++) { - pt3.x = points.read(ipoint * 2); - pt3.y = points.read(ipoint * 2 + 1); - pt3.z = zs.read(ipoint); - - Point3D res = transform.transform(pt3); - points.write(ipoint * 2, res.x); - points.write(ipoint * 2 + 1, res.y); - zs.write(ipoint, res.z); - } - - // REFACTOR: reset the exact envelope only and transform the loose - // envelope - notifyModified(DirtyFlags.DirtyCoordinates); - } - - @Override - public int getDimension() { - return 0; - } + public MultiPointImpl() { + super(); + m_description = VertexDescriptionDesignerImpl.getDefaultDescriptor2D(); + m_pointCount = 0; + } + + public MultiPointImpl(VertexDescription description) { + super(); + if (description == null) + throw new IllegalArgumentException(); + + m_description = description; + m_pointCount = 0; + } + + @Override + public Geometry createInstance() { + return new MultiPoint(m_description); + } + + /** + * Adds a Point to this MultiPoint. + */ + public void add(Point point) { + resize(m_pointCount + 1); + setPoint(m_pointCount - 1, point); + } + + /** + * Adds a Point to this MultiPoint with given x, y coordinates. + */ + public void add(double x, double y) { + resize(m_pointCount + 1); + Point2D pt = new Point2D(); + pt.setCoords(x, y); + setXY(m_pointCount - 1, pt); + } + + /** + * Adds a Point to this MultiPoint with given x, y, z coordinates. + */ + public void add(double x, double y, double z) { + resize(m_pointCount + 1); + Point3D pt = new Point3D(); + pt.setCoords(x, y, z); + setXYZ(m_pointCount - 1, pt); + } + + /** + * Appends points from another MultiVertexGeometryImpl at the end of this + * one. + * + * @param src The source MultiVertexGeometryImpl + */ + public void add(MultiVertexGeometryImpl src, int beginIndex, int endIndex) { + int endIndexC = endIndex < 0 ? src.getPointCount() : endIndex; + if (beginIndex < 0 || beginIndex > src.getPointCount() + || endIndexC < beginIndex) + throw new IllegalArgumentException(); + + if (beginIndex == endIndexC) + return; + + mergeVertexDescription(src.getDescription()); + int count = endIndexC - beginIndex; + int oldPointCount = m_pointCount; + resize(m_pointCount + count); + _verifyAllStreams(); + for (int iattrib = 0, nattrib = src.getDescription() + .getAttributeCount(); iattrib < nattrib; iattrib++) { + int semantics = src.getDescription()._getSemanticsImpl(iattrib); + int ncomps = VertexDescription.getComponentCount(semantics); + AttributeStreamBase stream = getAttributeStreamRef(semantics); + AttributeStreamBase srcStream = src + .getAttributeStreamRef(semantics); + stream.insertRange(oldPointCount * ncomps, srcStream, beginIndex + * ncomps, count * ncomps, true, 1, oldPointCount * ncomps); + } + } + + public void addPoints(Point2D[] points) { + int count = points.length; + int oldPointCount = m_pointCount; + resize(m_pointCount + count); + for (int i = 0; i < count; i++) + setXY(oldPointCount + i, points[i]); + } + + public void insertPoint(int beforePointIndex, Point pt) { + if (beforePointIndex > getPointCount()) + throw new GeometryException("index out of bounds"); + + if (beforePointIndex < 0) + beforePointIndex = getPointCount(); + + mergeVertexDescription(pt.getDescription()); + int oldPointCount = m_pointCount; + _resizeImpl(m_pointCount + 1); + _verifyAllStreams(); + + for (int iattr = 0, nattr = m_description.getAttributeCount(); iattr < nattr; iattr++) { + int semantics = m_description._getSemanticsImpl(iattr); + int comp = VertexDescription.getComponentCount(semantics); + + AttributeStreamBase stream = AttributeStreamBase + .createAttributeStreamWithSemantics(semantics, 1); + if (pt.hasAttribute(semantics)) { + m_vertexAttributes[iattr] + .insertAttributes(comp * beforePointIndex, pt, + semantics, comp * oldPointCount); + } else { + // Need to make room for the attribute, so we copy a default + // value in + + double v = VertexDescription.getDefaultValue(semantics); + m_vertexAttributes[iattr].insertRange(comp * beforePointIndex, + v, comp, comp * oldPointCount); + } + } + + notifyModified(DirtyFlags.DirtyCoordinates); + } + + void removePoint(int pointIndex) { + if (pointIndex < 0 || pointIndex >= getPointCount()) + throw new GeometryException("index out of bounds"); + + _verifyAllStreams(); + + // Remove the attribute value for the path + for (int iattr = 0, nattr = m_description.getAttributeCount(); iattr < nattr; iattr++) { + if (m_vertexAttributes[iattr] != null) { + int semantics = m_description._getSemanticsImpl(iattr); + int comp = VertexDescription.getComponentCount(semantics); + m_vertexAttributes[iattr].eraseRange(comp * pointIndex, comp, + comp * m_pointCount); + } + } + + m_pointCount--; + m_reservedPointCount--; + notifyModified(DirtyFlags.DirtyCoordinates); + } + + /** + * Resizes the MultiPoint to have the given size. + */ + public void resize(int pointCount) { + _resizeImpl(pointCount); + } + + @Override + void _copyToImpl(MultiVertexGeometryImpl mvg) { + } + + @Override + public void setEmpty() { + super._setEmptyImpl(); + } + + @Override + public void applyTransformation(Transformation2D transform) { + if (isEmpty()) + return; + + _verifyAllStreams(); + AttributeStreamOfDbl points = (AttributeStreamOfDbl) m_vertexAttributes[0]; + Point2D pt2 = new Point2D(); + + for (int ipoint = 0; ipoint < m_pointCount; ipoint++) { + pt2.x = points.read(ipoint * 2); + pt2.y = points.read(ipoint * 2 + 1); + + transform.transform(pt2, pt2); + points.write(ipoint * 2, pt2.x); + points.write(ipoint * 2 + 1, pt2.y); + } + + // REFACTOR: reset the exact envelope only and transform the loose + // envelope + notifyModified(DirtyFlags.DirtyCoordinates); + } @Override - public long estimateMemorySize() - { + void applyTransformation(Transformation3D transform) { + if (isEmpty()) + return; + + _verifyAllStreams(); + addAttribute(Semantics.Z); + _verifyAllStreams(); + AttributeStreamOfDbl points = (AttributeStreamOfDbl) m_vertexAttributes[0]; + AttributeStreamOfDbl zs = (AttributeStreamOfDbl) m_vertexAttributes[1]; + Point3D pt3 = new Point3D(); + for (int ipoint = 0; ipoint < m_pointCount; ipoint++) { + pt3.x = points.read(ipoint * 2); + pt3.y = points.read(ipoint * 2 + 1); + pt3.z = zs.read(ipoint); + + Point3D res = transform.transform(pt3); + points.write(ipoint * 2, res.x); + points.write(ipoint * 2 + 1, res.y); + zs.write(ipoint, res.z); + } + + // REFACTOR: reset the exact envelope only and transform the loose + // envelope + notifyModified(DirtyFlags.DirtyCoordinates); + } + + @Override + public int getDimension() { + return 0; + } + + @Override + public long estimateMemorySize() { long size = SIZE_OF_MULTI_POINT_IMPL + (m_envelope != null ? m_envelope.estimateMemorySize() : 0); if (m_vertexAttributes != null) { @@ -266,100 +265,100 @@ public Geometry.Type getType() { return Type.MultiPoint; } - @Override - public double calculateArea2D() { - return 0; - } - - @Override - public double calculateLength2D() { - return 0; - } - - @Override - public Object _getImpl() { - return this; - } - - @Override - public boolean equals(Object other) { - if (other == this) - return true; - - if (!(other instanceof MultiPointImpl)) - return false; - - return super.equals(other); - } - - public void addPoints(Point[] points) { - int count = points.length; - // int oldPointCount = m_pointCount; - resize(m_pointCount + count); - for (int i = 0; i < count; i++) - setPoint(i, points[i]); - } - - public int queryCoordinates(Point2D[] dst, int dstSize, int beginIndex, - int endIndex) { - int endIndexC = endIndex < 0 ? m_pointCount : endIndex; - endIndexC = Math.min(endIndexC, beginIndex + dstSize); - - if (beginIndex < 0 || beginIndex >= m_pointCount - || endIndexC < beginIndex || dst.length != dstSize) - throw new IllegalArgumentException();// GEOMTHROW(invalid_argument); - - AttributeStreamOfDbl xy = (AttributeStreamOfDbl) getAttributeStreamRef(VertexDescription.Semantics.POSITION); - int pointCountToRead = endIndexC - beginIndex; - double[] dstArray = new double[pointCountToRead * 2]; - xy.readRange(2 * beginIndex, pointCountToRead * 2, dstArray, 0, true); - - for (int i = 0; i < pointCountToRead; i++) { - dst[i] = new Point2D(dstArray[i * 2], dstArray[i * 2 + 1]); - } - - return endIndexC; - } - - @Override - protected void _notifyModifiedAllImpl() { - // TODO Auto-generated method stub - - } - - @Override - protected void _verifyStreamsImpl() { - // TODO Auto-generated method stub - - } - - @Override - public boolean _buildRasterizedGeometryAccelerator(double toleranceXY, - GeometryAccelerationDegree accelDegree) { - // TODO Auto-generated method stub - return false; - } - - @Override - public boolean _buildQuadTreeAccelerator(GeometryAccelerationDegree accelDegree) { - // TODO Auto-generated method stub - return false; - } - - // @Override - // void _notifyModifiedAllImpl() { - // // TODO Auto-generated method stub - // - // } - - // @Override - // protected void _verifyStreamsImpl() { - // // TODO Auto-generated method stub - // - // } - - @Override - public Geometry getBoundary() { - return null; - } + @Override + public double calculateArea2D() { + return 0; + } + + @Override + public double calculateLength2D() { + return 0; + } + + @Override + public Object _getImpl() { + return this; + } + + @Override + public boolean equals(Object other) { + if (other == this) + return true; + + if (!(other instanceof MultiPointImpl)) + return false; + + return super.equals(other); + } + + public void addPoints(Point[] points) { + int count = points.length; + // int oldPointCount = m_pointCount; + resize(m_pointCount + count); + for (int i = 0; i < count; i++) + setPoint(i, points[i]); + } + + public int queryCoordinates(Point2D[] dst, int dstSize, int beginIndex, + int endIndex) { + int endIndexC = endIndex < 0 ? m_pointCount : endIndex; + endIndexC = Math.min(endIndexC, beginIndex + dstSize); + + if (beginIndex < 0 || beginIndex >= m_pointCount + || endIndexC < beginIndex || dst.length != dstSize) + throw new IllegalArgumentException();// GEOMTHROW(invalid_argument); + + AttributeStreamOfDbl xy = (AttributeStreamOfDbl) getAttributeStreamRef(VertexDescription.Semantics.POSITION); + int pointCountToRead = endIndexC - beginIndex; + double[] dstArray = new double[pointCountToRead * 2]; + xy.readRange(2 * beginIndex, pointCountToRead * 2, dstArray, 0, true); + + for (int i = 0; i < pointCountToRead; i++) { + dst[i] = new Point2D(dstArray[i * 2], dstArray[i * 2 + 1]); + } + + return endIndexC; + } + + @Override + protected void _notifyModifiedAllImpl() { + // TODO Auto-generated method stub + + } + + @Override + protected void _verifyStreamsImpl() { + // TODO Auto-generated method stub + + } + + @Override + public boolean _buildRasterizedGeometryAccelerator(double toleranceXY, + GeometryAccelerationDegree accelDegree) { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean _buildQuadTreeAccelerator(GeometryAccelerationDegree accelDegree) { + // TODO Auto-generated method stub + return false; + } + + // @Override + // void _notifyModifiedAllImpl() { + // // TODO Auto-generated method stub + // + // } + + // @Override + // protected void _verifyStreamsImpl() { + // // TODO Auto-generated method stub + // + // } + + @Override + public Geometry getBoundary() { + return null; + } } diff --git a/src/main/java/com/esri/core/geometry/MultiVertexGeometry.java b/src/main/java/com/esri/core/geometry/MultiVertexGeometry.java index 56dca8ce..d3a7b921 100644 --- a/src/main/java/com/esri/core/geometry/MultiVertexGeometry.java +++ b/src/main/java/com/esri/core/geometry/MultiVertexGeometry.java @@ -33,173 +33,173 @@ * There are as many arrays as there are attributes in the vertex. */ public abstract class MultiVertexGeometry extends Geometry implements - Serializable { - - @Override - protected void _assignVertexDescriptionImpl(VertexDescription newDescription) { - throw new GeometryException("invalid call"); - } - - /** - * Returns the total vertex count in this Geometry. - */ - public abstract int getPointCount(); - - /** - * Returns given vertex of the Geometry. - */ - public abstract Point getPoint(int index);// Java only - - /** - * Returns given vertex of the Geometry by value. - */ - public void getPoint(int index, Point ptOut) { - getPointByVal(index, ptOut); - } - - /** - * Sets the vertex at given index of the Geometry. - * - * @param index The index of the vertex being changed. - * @param pointSrc The Point instance to set given vertex attributes from. The - * pointSrc can not be empty.
- * The method throws if the pointSrc is not of the Point type.
- * The attributes, that are present in the pointSrc and missing - * in this Geometry, will be added to the Geometry.
- * The vertex attributes missing in the pointSrc but present in - * the Geometry will be set to the default values (see - * VertexDescription::GetDefaultValue). - */ - public abstract void setPoint(int index, Point pointSrc);// Java only - - /** - * Returns XY coordinates of the given vertex of the Geometry. - */ - public abstract Point2D getXY(int index); - - public abstract void getXY(int index, Point2D pt); - - /** - * Sets XY coordinates of the given vertex of the Geometry. All other - * attributes are unchanged. - */ - public abstract void setXY(int index, Point2D pt); - - /** - * Returns XYZ coordinates of the given vertex of the Geometry. If the - * Geometry has no Z's, the default value for Z is returned (0). - */ - abstract Point3D getXYZ(int index); - - /** - * Sets XYZ coordinates of the given vertex of the Geometry. If Z attribute - * is not present in this Geometry, it is added. All other attributes are - * unchanged. - */ - abstract void setXYZ(int index, Point3D pt); - - /** - * Returns XY coordinates as an array. - */ - public Point2D[] getCoordinates2D() { - Point2D[] arr = new Point2D[getPointCount()]; - queryCoordinates(arr); - return arr; - } - - /** - * Returns XYZ coordinates as an array. - */ - Point3D[] getCoordinates3D() { - Point3D[] arr = new Point3D[getPointCount()]; - queryCoordinates(arr); - return arr; - } - - public abstract void queryCoordinates(Point[] dst); - - /** - * Queries XY coordinates as an array. The array must be larg enough (See - * GetPointCount()). - */ - public abstract void queryCoordinates(Point2D[] dst); - - /** - * Queries XYZ coordinates as an array. The array must be larg enough (See - * GetPointCount()). - */ - abstract void queryCoordinates(Point3D[] dst); - - /** - * Returns value of the given vertex attribute as double. - * - * @param semantics The atribute semantics. - * @param index is the vertex index in the Geometry. - * @param ordinate is the ordinate of a vertex attribute (for example, y has - * ordinate of 1, because it is second ordinate of POSITION) - *

- * If attribute is not present, the default value is returned. - * See VertexDescription::GetDefaultValue() method. - */ - abstract double getAttributeAsDbl(int semantics, int index, - int ordinate); - - /** - * Returns value of the given vertex attribute as int. - * - * @param semantics The atribute semantics. - * @param index is the vertex index in the Geometry. - * @param ordinate is the ordinate of a vertex attribute (for example, y has - * ordinate of 1, because it is second ordinate of POSITION) - *

- * If attribute is not present, the default value is returned. - * See VertexDescription::GetDefaultValue() method. Avoid using - * this method on non-integer atributes. - */ - abstract int getAttributeAsInt(int semantics, int index, int ordinate); - - /** - * Sets the value of given attribute at given posisiotnsis. - * - * @param semantics The atribute semantics. - * @param index is the vertex index in the Geometry. - * @param ordinate is the ordinate of a vertex attribute (for example, y has - * ordinate of 1, because it is seond ordinate of POSITION) - * @param value is the value to set. as well as the number of components of - * the attribute. - *

- * If the attribute is not present in this Geometry, it is added. - */ - abstract void setAttribute(int semantics, int index, int ordinate, - double value); - - /** - * Same as above, but works with ints. Avoid using this method on - * non-integer atributes because some double attributes may have NaN default - * values (e.g. Ms) - */ - abstract void setAttribute(int semantics, int index, int ordinate, - int value); - - /** - * Returns given vertex of the Geometry. The outPoint will have same - * VertexDescription as this Geometry. - */ - public abstract void getPointByVal(int index, Point outPoint); - - /** - * Sets the vertex at given index of the Geometry. - * - * @param index The index of the vertex being changed. - * @param pointSrc The Point instance to set given vertex attributes from. The - * pointSrc can not be empty.
- * The method throws if the pointSrc is not of the Point type.
- * The attributes, that are present in the pointSrc and missing - * in this Geometry, will be added to the Geometry.
- * The vertex attributes missing in the pointSrc but present in - * the Geometry will be set to the default values (see - * VertexDescription::GetDefaultValue). - */ - public abstract void setPointByVal(int index, Point pointSrc); + Serializable { + + @Override + protected void _assignVertexDescriptionImpl(VertexDescription newDescription) { + throw new GeometryException("invalid call"); + } + + /** + * Returns the total vertex count in this Geometry. + */ + public abstract int getPointCount(); + + /** + * Returns given vertex of the Geometry. + */ + public abstract Point getPoint(int index);// Java only + + /** + * Returns given vertex of the Geometry by value. + */ + public void getPoint(int index, Point ptOut) { + getPointByVal(index, ptOut); + } + + /** + * Sets the vertex at given index of the Geometry. + * + * @param index The index of the vertex being changed. + * @param pointSrc The Point instance to set given vertex attributes from. The + * pointSrc can not be empty.
+ * The method throws if the pointSrc is not of the Point type.
+ * The attributes, that are present in the pointSrc and missing + * in this Geometry, will be added to the Geometry.
+ * The vertex attributes missing in the pointSrc but present in + * the Geometry will be set to the default values (see + * VertexDescription::GetDefaultValue). + */ + public abstract void setPoint(int index, Point pointSrc);// Java only + + /** + * Returns XY coordinates of the given vertex of the Geometry. + */ + public abstract Point2D getXY(int index); + + public abstract void getXY(int index, Point2D pt); + + /** + * Sets XY coordinates of the given vertex of the Geometry. All other + * attributes are unchanged. + */ + public abstract void setXY(int index, Point2D pt); + + /** + * Returns XYZ coordinates of the given vertex of the Geometry. If the + * Geometry has no Z's, the default value for Z is returned (0). + */ + abstract Point3D getXYZ(int index); + + /** + * Sets XYZ coordinates of the given vertex of the Geometry. If Z attribute + * is not present in this Geometry, it is added. All other attributes are + * unchanged. + */ + abstract void setXYZ(int index, Point3D pt); + + /** + * Returns XY coordinates as an array. + */ + public Point2D[] getCoordinates2D() { + Point2D[] arr = new Point2D[getPointCount()]; + queryCoordinates(arr); + return arr; + } + + /** + * Returns XYZ coordinates as an array. + */ + Point3D[] getCoordinates3D() { + Point3D[] arr = new Point3D[getPointCount()]; + queryCoordinates(arr); + return arr; + } + + public abstract void queryCoordinates(Point[] dst); + + /** + * Queries XY coordinates as an array. The array must be larg enough (See + * GetPointCount()). + */ + public abstract void queryCoordinates(Point2D[] dst); + + /** + * Queries XYZ coordinates as an array. The array must be larg enough (See + * GetPointCount()). + */ + abstract void queryCoordinates(Point3D[] dst); + + /** + * Returns value of the given vertex attribute as double. + * + * @param semantics The atribute semantics. + * @param index is the vertex index in the Geometry. + * @param ordinate is the ordinate of a vertex attribute (for example, y has + * ordinate of 1, because it is second ordinate of POSITION) + *

+ * If attribute is not present, the default value is returned. + * See VertexDescription::GetDefaultValue() method. + */ + abstract double getAttributeAsDbl(int semantics, int index, + int ordinate); + + /** + * Returns value of the given vertex attribute as int. + * + * @param semantics The atribute semantics. + * @param index is the vertex index in the Geometry. + * @param ordinate is the ordinate of a vertex attribute (for example, y has + * ordinate of 1, because it is second ordinate of POSITION) + *

+ * If attribute is not present, the default value is returned. + * See VertexDescription::GetDefaultValue() method. Avoid using + * this method on non-integer atributes. + */ + abstract int getAttributeAsInt(int semantics, int index, int ordinate); + + /** + * Sets the value of given attribute at given posisiotnsis. + * + * @param semantics The atribute semantics. + * @param index is the vertex index in the Geometry. + * @param ordinate is the ordinate of a vertex attribute (for example, y has + * ordinate of 1, because it is seond ordinate of POSITION) + * @param value is the value to set. as well as the number of components of + * the attribute. + *

+ * If the attribute is not present in this Geometry, it is added. + */ + abstract void setAttribute(int semantics, int index, int ordinate, + double value); + + /** + * Same as above, but works with ints. Avoid using this method on + * non-integer atributes because some double attributes may have NaN default + * values (e.g. Ms) + */ + abstract void setAttribute(int semantics, int index, int ordinate, + int value); + + /** + * Returns given vertex of the Geometry. The outPoint will have same + * VertexDescription as this Geometry. + */ + public abstract void getPointByVal(int index, Point outPoint); + + /** + * Sets the vertex at given index of the Geometry. + * + * @param index The index of the vertex being changed. + * @param pointSrc The Point instance to set given vertex attributes from. The + * pointSrc can not be empty.
+ * The method throws if the pointSrc is not of the Point type.
+ * The attributes, that are present in the pointSrc and missing + * in this Geometry, will be added to the Geometry.
+ * The vertex attributes missing in the pointSrc but present in + * the Geometry will be set to the default values (see + * VertexDescription::GetDefaultValue). + */ + public abstract void setPointByVal(int index, Point pointSrc); } diff --git a/src/main/java/com/esri/core/geometry/MultiVertexGeometryImpl.java b/src/main/java/com/esri/core/geometry/MultiVertexGeometryImpl.java index 8907df37..e045aa2a 100644 --- a/src/main/java/com/esri/core/geometry/MultiVertexGeometryImpl.java +++ b/src/main/java/com/esri/core/geometry/MultiVertexGeometryImpl.java @@ -30,1087 +30,1055 @@ /** * This class is a base for geometries with many vertices. - *

+ * * The vertex attributes are stored in separate arrays of corresponding type. * There are as many arrays as there are attributes in the vertex. It uses lazy * allocation for the vertex attributes. This means, the actual AttributeStream * is allocated only when the users asks for it, or sets a non-default value. + * */ abstract class MultiVertexGeometryImpl extends MultiVertexGeometry { - // HEADER DEFINED - public interface GeometryXSimple { - final int Unknown = -1; // not know if simple or not - final int Not = 0; // not simple - final int Weak = 1; // weak simple (no self intersections, ring - // orientation is correct, but ring order is not) - final int Strong = 2; // same as weak simple + OGC ring order. - } - - // TODO Remove? - - /** - * \internal CHildren implement this method to copy additional information - */ - abstract void _copyToImpl(MultiVertexGeometryImpl mvg); - - protected abstract void _notifyModifiedAllImpl(); - - /** - * \internal Called inside of the VerifyAllStreams to get a child class a - * chance to do additional verify. - */ - protected abstract void _verifyStreamsImpl(); - - public interface DirtyFlags { - public static final int DirtyIsKnownSimple = 1; // !<0 when IsWeakSimple - // flag is valid - public static final int IsWeakSimple = 2; // != m_pointCount) - // TODO - throw new GeometryException("index out of bounds"); - - // _ASSERT(!IsEmpty()); - // _ASSERT(m_vertexAttributes != null); - - _verifyAllStreams(); - - Point outPoint = dst; - outPoint.assignVertexDescription(m_description); - if (outPoint.isEmpty()) - outPoint._setToDefault(); - - for (int attributeIndex = 0; attributeIndex < m_description - .getAttributeCount(); attributeIndex++) { - // fix semantics - int semantics = m_description._getSemanticsImpl(attributeIndex); - - // VertexDescription.getComponentCount(semantics); - for (int icomp = 0, ncomp = VertexDescription - .getComponentCount(semantics); icomp < ncomp; icomp++) { - double v = m_vertexAttributes[attributeIndex].readAsDbl(ncomp - * index + icomp); - outPoint.setAttribute(semantics, icomp, v); - } - } - } - - @Override - public void setPointByVal(int index, Point src) { - if (index < 0 || index >= m_pointCount) - throw new GeometryException("index out of bounds"); - - Point point = src; - - if (src.isEmpty())// can not assign an empty point to a multipoint - // vertex - throw new IllegalArgumentException(); - - _verifyAllStreams();// verify all allocated streams are of necessary - // size. - VertexDescription vdin = point.getDescription(); - for (int attributeIndex = 0; attributeIndex < vdin.getAttributeCount(); attributeIndex++) { - int semantics = vdin._getSemanticsImpl(attributeIndex); - int ncomp = VertexDescription.getComponentCount(semantics); - for (int icomp = 0; icomp < ncomp; icomp++) { - double v = point.getAttributeAsDbl(semantics, icomp); - setAttribute(semantics, index, icomp, v); - } - } - } - - // Checked vs. Jan 11, 2011 - @Override - public Point2D getXY(int index) { - Point2D pt = new Point2D(); - getXY(index, pt); - return pt; - } - - @Override - public void getXY(int index, Point2D pt) { - if (index < 0 || index >= getPointCount()) - throw new IndexOutOfBoundsException(); - - _verifyAllStreams(); - // AttributeStreamOfDbl v = (AttributeStreamOfDbl) - // m_vertexAttributes[0]; - AttributeStreamOfDbl v = (AttributeStreamOfDbl) m_vertexAttributes[0]; - v.read(index * 2, pt); - } - - // Checked vs. Jan 11, 2011 - @Override - public void setXY(int index, Point2D pt) { - if (index < 0 || index >= m_pointCount) - // TODO exception - throw new IndexOutOfBoundsException(); - - _verifyAllStreams(); - // AttributeStreamOfDbl v = (AttributeStreamOfDbl) - // m_vertexAttributes[0]; - AttributeStreamOfDbl v = (AttributeStreamOfDbl) m_vertexAttributes[0]; - v.write(index * 2, pt); - notifyModified(DirtyFlags.DirtyCoordinates); - } - - // Checked vs. Jan 11, 2011 - public void setXY(int index, double x, double y) { - if (index < 0 || index >= m_pointCount) - // TODO exc - throw new IndexOutOfBoundsException(); - - _verifyAllStreams(); - // AttributeStreamOfDbl v = (AttributeStreamOfDbl) - // m_vertexAttributes[0]; - // TODO ask sergey about casts - AttributeStreamOfDbl v = (AttributeStreamOfDbl) m_vertexAttributes[0]; - v.write(index * 2, x); - v.write(index * 2 + 1, y); - notifyModified(DirtyFlags.DirtyCoordinates); - } - - // Checked vs. Jan 11, 2011 - @Override - public Point3D getXYZ(int index) { - if (index < 0 || index >= getPointCount()) - throw new IndexOutOfBoundsException(); - - _verifyAllStreams(); - AttributeStreamOfDbl v = (AttributeStreamOfDbl) m_vertexAttributes[0]; - Point3D pt = new Point3D(); - pt.x = v.read(index * 2); - pt.y = v.read(index * 2 + 1); - - // TODO check excluded if statement componenet - if (hasAttribute(Semantics.Z))// && (m_vertexAttributes[1] != null)) - pt.z = m_vertexAttributes[1].readAsDbl(index); - else - pt.z = VertexDescription.getDefaultValue(Semantics.Z); - - return pt; - } - - // Checked vs. Jan 11, 2011 - @Override - public void setXYZ(int index, Point3D pt) { - if (index < 0 || index >= getPointCount()) - throw new IndexOutOfBoundsException(); - - addAttribute(Semantics.Z); - - _verifyAllStreams(); - notifyModified(DirtyFlags.DirtyCoordinates); - AttributeStreamOfDbl v = (AttributeStreamOfDbl) m_vertexAttributes[0]; - v.write(index * 2, pt.x); - v.write(index * 2 + 1, pt.y); - m_vertexAttributes[1].writeAsDbl(index, pt.z); - } - - // Checked vs. Jan 11, 2011 - @Override - public double getAttributeAsDbl(int semantics, int offset, int ordinate) { - if (offset < 0 || offset >= m_pointCount) - throw new IndexOutOfBoundsException(); - - int ncomps = VertexDescription.getComponentCount(semantics); - if (ordinate >= ncomps) - throw new IndexOutOfBoundsException(); - - _verifyAllStreams(); - int attributeIndex = m_description.getAttributeIndex(semantics); - // TODO check if statement - if (attributeIndex >= 0)// && m_vertexAttributes[attributeIndex] != - // null) { - { - return m_vertexAttributes[attributeIndex].readAsDbl(offset * ncomps - + ordinate); - } - return VertexDescription.getDefaultValue(semantics); - } - - // Checked vs. Jan 11, 2011 - @Override - public int getAttributeAsInt(int semantics, int offset, int ordinate) { - return (int) getAttributeAsDbl(semantics, offset, ordinate); - } - - // Checked vs. Jan 11, 2011 - @Override - public void setAttribute(int semantics, int offset, int ordinate, - double value) { - if (offset < 0 || offset >= m_pointCount) - throw new IndexOutOfBoundsException(); - - int ncomps = VertexDescription.getComponentCount(semantics); - if (ordinate >= ncomps) - throw new IndexOutOfBoundsException(); - - addAttribute(semantics); - _verifyAllStreams(); - int attributeIndex = m_description.getAttributeIndex(semantics); - notifyModified(DirtyFlags.DirtyCoordinates); - m_vertexAttributes[attributeIndex].writeAsDbl(offset * ncomps - + ordinate, value); - } - - // Checked vs. Jan 11, 2011 - @Override - public void setAttribute(int semantics, int offset, int ordinate, int value) { - setAttribute(semantics, offset, ordinate, (double) value); - } - - public AttributeStreamBase getAttributeStreamRef(int semantics) { - throwIfEmpty(); - - addAttribute(semantics); - _verifyAllStreams(); - - int attributeIndex = m_description.getAttributeIndex(semantics); - return m_vertexAttributes[attributeIndex]; - } - - /** - * Sets a reference to the given AttributeStream of the Geometry. Once the - * buffer has been obtained, the vertices of the Geometry can be manipulated - * directly. The AttributeStream parameters are not checked for the size.
- * If the attribute is missing, it will be added.
- * Note, that this method does not change the vertex count in the Geometry.
- * The stream can have more elements, than the Geometry point count, but - * only necessary part will be saved when exporting to a ESRI shape or other - * format. @param semantics Semantics of the attribute to assign the stream - * to. @param stream The input AttributeStream that will be assigned by - * reference. If one changes the stream later through the reference, one has - * to call NotifyStreamChanged. \exception Throws invalid_argument exception - * if the input stream type does not match that of the semantics - * persistence. - */ - public void setAttributeStreamRef(int semantics, AttributeStreamBase stream) { - // int test1 = VertexDescription.getPersistence(semantics); - // int test2 = stream.getPersistence(); - - if ((stream != null) - && VertexDescription.getPersistence(semantics) != stream - .getPersistence())// input stream has wrong persistence - throw new IllegalArgumentException(); - - // Do not check for the stream size here to allow several streams to be - // attached before the point count is changed. - addAttribute(semantics); - int attributeIndex = m_description.getAttributeIndex(semantics); - if (m_vertexAttributes == null) - m_vertexAttributes = new AttributeStreamBase[m_description - .getAttributeCount()]; - - m_vertexAttributes[attributeIndex] = stream; - notifyModified(DirtyFlags.DirtyAll); - } - - @Override - protected void _assignVertexDescriptionImpl(VertexDescription newDescription) { - AttributeStreamBase[] newAttributes = null; - - if (m_vertexAttributes != null) { - int[] mapping = VertexDescriptionDesignerImpl.mapAttributes( - newDescription, m_description); - - newAttributes = new AttributeStreamBase[newDescription - .getAttributeCount()]; - - for (int i = 0, n = newDescription.getAttributeCount(); i < n; i++) { - if (mapping[i] != -1) { - int m = mapping[i]; - newAttributes[i] = m_vertexAttributes[m]; - } - - } - } else { - //if there are no streams we do not create them - } - - m_description = newDescription; - m_vertexAttributes = newAttributes; // late assignment to try to stay - m_reservedPointCount = -1;// we need to recreate the new attribute then - notifyModified(DirtyFlags.DirtyAll); - } - - // Checked vs. Jan 11, 2011 - protected void _updateEnvelope(Envelope2D env) { - _updateAllDirtyIntervals(true); - m_envelope.queryEnvelope2D(env); - } // note: overload for polylines/polygons with curves - - // Checked vs. Jan 11, 2011 - protected void _updateEnvelope(Envelope3D env) { - _updateAllDirtyIntervals(true); - m_envelope.queryEnvelope3D(env); - } // note: overload for polylines/polygons with curves - - // Checked vs. Jan 11, 2011 - protected void _updateLooseEnvelope(Envelope2D env) { - // TODO ROHIT has this set to true? - _updateAllDirtyIntervals(false); - m_envelope.queryEnvelope2D(env); - } // note: overload for polylines/polygons with curves - - // Checked vs. Jan 11, 2011 - - /** - * \internal Calculates loose envelope. Returns True if the calculation - * renders exact envelope. - */ - protected void _updateLooseEnvelope(Envelope3D env) { - // TODO ROHIT has this set to true? - _updateAllDirtyIntervals(false); - m_envelope.queryEnvelope3D(env); - } // note: overload for polylines/polygons with curves - - // Checked vs. Jan 11, 2011 - @Override - public void queryEnvelope(Envelope env) { - _updateAllDirtyIntervals(true); - m_envelope.copyTo(env); - } - - // TODO rename to remove 2D - // Checked vs. Jan 11, 2011 - @Override - public void queryEnvelope2D(Envelope2D env) { - _updateEnvelope(env); - } - - // Checked vs. Jan 11, 2011 - // TODO rename to remove 3D - @Override - public void queryEnvelope3D(Envelope3D env) { - _updateEnvelope(env); - } - - // Checked vs. Jan 11, 2011 - // TODO rename to remove 2D - @Override - public void queryLooseEnvelope2D(Envelope2D env) { - _updateLooseEnvelope(env); - } - - // Checked vs. Jan 11, 2011 - // TODO rename to remove 3D - @Override - public void queryLooseEnvelope3D(Envelope3D env) { - _updateLooseEnvelope(env); - } - - // Checked vs. Jan 11, 2011 - @Override - public Envelope1D queryInterval(int semantics, int ordinate) { - Envelope1D env = new Envelope1D(); - if (isEmptyImpl()) { - env.setEmpty(); - return env; - } - - _updateAllDirtyIntervals(true); - return m_envelope.queryInterval(semantics, ordinate); - } - - // Checked vs. Jan 11, 2011 - // TODO Rename to getHashCode - @Override - public int hashCode() { - int hashCode = m_description.hashCode(); - - if (!isEmptyImpl()) { - int pointCount = getPointCount(); - for (int i = 0, n = m_description.getAttributeCount(); i < n; i++) { - int components = VertexDescription - .getComponentCount(m_description._getSemanticsImpl(i)); - AttributeStreamBase stream = m_vertexAttributes[i]; - hashCode = stream.calculateHashImpl(hashCode, 0, pointCount - * components); - } - } - - return hashCode; - } - - // Checked vs. Jan 11, 2011 - @Override - public boolean equals(Object other) { - // Java checks - if (other == this) - return true; - - if (!(other instanceof MultiVertexGeometryImpl)) - return false; - - MultiVertexGeometryImpl otherMulti = (MultiVertexGeometryImpl) other; - - if (!(m_description.equals(otherMulti.m_description))) - return false; - - if (isEmptyImpl() != otherMulti.isEmptyImpl()) - return false; - - if (isEmptyImpl()) - return true; // both geometries are empty - - int pointCount = getPointCount(); - int pointCountOther = otherMulti.getPointCount(); - - if (pointCount != pointCountOther) - return false; - - for (int i = 0; i < m_description.getAttributeCount(); i++) { - int semantics = m_description.getSemantics(i); - - AttributeStreamBase stream = getAttributeStreamRef(semantics); - AttributeStreamBase streamOther = otherMulti - .getAttributeStreamRef(semantics); - - int components = VertexDescription.getComponentCount(semantics); - - if (!stream.equals(streamOther, 0, pointCount * components)) - return false; - } - - return true; - } - - // Checked vs. Jan 11, 2011 - - /** - * Sets the envelope of the Geometry. The Envelope description must match - * that of the Geometry. - */ - public void setEnvelope(Envelope env) { - if (!m_description.equals(env.getDescription())) - throw new IllegalArgumentException(); - - // m_envelope = (Envelope) env.clone(); - m_envelope = (Envelope) env.createInstance(); - env.copyTo(m_envelope); - _setDirtyFlag(DirtyFlags.DirtyIntervals, false); - } - - @Override - public void copyTo(Geometry dstGeom) { - MultiVertexGeometryImpl dst = (MultiVertexGeometryImpl) dstGeom; - if (dst.getType() != getType()) - throw new IllegalArgumentException(); - - _copyToUnsafe(dst); - } - - //Does not check geometry type. Used to copy Polygon to Polyline - void _copyToUnsafe(MultiVertexGeometryImpl dst) { - _verifyAllStreams(); - dst.m_description = m_description; - dst.m_vertexAttributes = null; - int nattrib = m_description.getAttributeCount(); - AttributeStreamBase[] cloneAttributes = null; - if (m_vertexAttributes != null) { - cloneAttributes = new AttributeStreamBase[nattrib]; - for (int i = 0; i < nattrib; i++) { - if (m_vertexAttributes[i] != null) { - int ncomps = VertexDescription.getComponentCount(m_description._getSemanticsImpl(i)); - cloneAttributes[i] = m_vertexAttributes[i].restrictedClone(getPointCount() * ncomps); - } - } - } - - if (m_envelope != null) { - dst.m_envelope = (Envelope) m_envelope.createInstance(); - m_envelope.copyTo(dst.m_envelope); - // dst.m_envelope = (Envelope) m_envelope.clone(); - } else - dst.m_envelope = null; - - dst.m_pointCount = m_pointCount; - dst.m_flagsMask = m_flagsMask; - dst.m_vertexAttributes = cloneAttributes; - - try { - _copyToImpl(dst); // copy child props - } catch (Exception ex) { - dst.setEmpty(); - throw new RuntimeException(ex); - } - } - - // Checked vs. Jan 11, 2011 - public boolean _attributeStreamIsAllocated(int semantics) { - throwIfEmpty(); - - int attributeIndex = m_description.getAttributeIndex(semantics); - - if (attributeIndex >= 0 && m_vertexAttributes[attributeIndex] != null) - return true; - - return false; - } - - // Checked vs. Jan 11, 2011 - void _setEmptyImpl() { - m_pointCount = 0; - m_reservedPointCount = -1; - m_vertexAttributes = null;// release it all streams. - notifyModified(DirtyFlags.DirtyAll); - } - - // Checked vs. Jan 11, 2011 - - /** - * Notifies the Geometry of changes made to the vertices so that it could - * reset cached structures. - */ - public void notifyModified(int flags) { - if (flags == DirtyFlags.DirtyAll) { - m_reservedPointCount = -1;// forget the reserved point number - _notifyModifiedAllImpl(); - } - m_flagsMask |= flags; - - _clearAccelerators(); - _touch(); - } - - // Checked vs. Jan 11, 2011 - - /** - * @param bExact True, when the exact envelope need to be calculated and false - * for the loose one. - */ - protected void _updateAllDirtyIntervals(boolean bExact) { - _verifyAllStreams(); - if (_hasDirtyFlag(DirtyFlags.DirtyIntervals)) { - if (null == m_envelope) - m_envelope = new Envelope(m_description); - else - m_envelope.assignVertexDescription(m_description); - - if (isEmpty()) { - m_envelope.setEmpty(); - return; - } - - _updateXYImpl(bExact);// efficient method for xy's - // now go through other attribues. - for (int attributeIndex = 1; attributeIndex < m_description - .getAttributeCount(); attributeIndex++) { - int semantics = m_description._getSemanticsImpl(attributeIndex); - int ncomps = VertexDescription.getComponentCount(semantics); - AttributeStreamBase stream = m_vertexAttributes[attributeIndex]; - for (int iord = 0; iord < ncomps; iord++) { - Envelope1D interval = new Envelope1D(); - interval.setEmpty(); - for (int i = 0; i < m_pointCount; i++) { - double value = stream.readAsDbl(i * ncomps + iord);// some - // optimization - // is - // possible - // if - // non-virtual - // method - // is - // used - interval.merge(value); - } - m_envelope.setInterval(semantics, iord, interval); - } - } - if (bExact) - _setDirtyFlag(DirtyFlags.DirtyIntervals, false); - } - } - - // Checked vs. Jan 11, 2011 - - /** - * \internal Updates x, y intervals. - */ - public void _updateXYImpl(boolean bExact) { - m_envelope.setEmpty(); - AttributeStreamOfDbl stream = (AttributeStreamOfDbl) m_vertexAttributes[0]; - Point2D pt = new Point2D(); - for (int i = 0; i < m_pointCount; i++) { - stream.read(2 * i, pt); - m_envelope.merge(pt); - } - } - - void calculateEnvelope2D(Envelope2D env, boolean bExact) { - env.setEmpty(); - AttributeStreamOfDbl stream = (AttributeStreamOfDbl) m_vertexAttributes[0]; - Point2D pt = new Point2D(); - for (int i = 0; i < m_pointCount; i++) { - stream.read(2 * i, pt); - env.merge(pt); - } - } - - // Checked vs. Jan 11, 2011 lots of changes - - /** - * \internal Verifies all streams (calls _VerifyStream for every attribute). - */ - protected void _verifyAllStreamsImpl() { - // This method checks that the streams are of correct size. - // It resizes the streams to ensure they are not shorter than - // m_PointCount - // _ASSERT(_HasDirtyFlag(enum_value1(DirtyFlags, - // DirtyVerifiedStreams))); - if (m_reservedPointCount < m_pointCount) // an optimization to skip this - // expensive loop when - // adding point by point - { - if (m_vertexAttributes == null) - m_vertexAttributes = new AttributeStreamBase[m_description - .getAttributeCount()]; - - m_reservedPointCount = NumberUtils.intMax(); - for (int attributeIndex = 0; attributeIndex < m_description - .getAttributeCount(); attributeIndex++) { - int semantics = m_description._getSemanticsImpl(attributeIndex); - if (m_vertexAttributes[attributeIndex] != null) { - int ncomp = VertexDescription.getComponentCount(semantics); - int size = m_vertexAttributes[attributeIndex].virtualSize() - / ncomp; - if (size < m_pointCount) { - size = (m_reservedPointCount > m_pointCount + 5) ? (m_pointCount * 5 + 3) / 4 - : m_pointCount;// reserve 25% more than user - // asks - m_vertexAttributes[attributeIndex].resize(size * ncomp, - VertexDescription.getDefaultValue(semantics)); - } - - if (size < m_reservedPointCount) - m_reservedPointCount = size; - } else { - m_vertexAttributes[attributeIndex] = AttributeStreamBase - .createAttributeStreamWithSemantics(semantics, - m_pointCount); - m_reservedPointCount = m_pointCount; - } - } - } - _verifyStreamsImpl(); - - _setDirtyFlag(DirtyFlags.DirtyVerifiedStreams, false); - } - - // Checked vs. Jan 11, 2011 - void _resizeImpl(int pointCount) { - if (pointCount < 0) - throw new IllegalArgumentException(); - - if (pointCount == m_pointCount) - return; - - m_pointCount = pointCount; - notifyModified(DirtyFlags.DirtyAllInternal); - } - - // Checked vs. Jan 11, 2011 - int queryCoordinates(Point2D[] dst, int dstSize, int beginIndex, - int endIndex) { - int endIndexC = endIndex < 0 ? m_pointCount : endIndex; - endIndexC = Math.min(endIndexC, beginIndex + dstSize); - - if (beginIndex < 0 || beginIndex >= m_pointCount - || endIndexC < beginIndex) - throw new IllegalArgumentException(); - - AttributeStreamOfDbl xy = (AttributeStreamOfDbl) getAttributeStreamRef(VertexDescription.Semantics.POSITION); - int j = 0; - double[] dstArray = new double[dst.length * 2]; - xy.readRange(2 * beginIndex, (endIndexC - beginIndex) * 2, dstArray, j, true); - - for (int i = 0; i < dst.length; i++) { - dst[i] = new Point2D(dstArray[i * 2], dstArray[i * 2 + 1]); - } - - // for (int i = beginIndex; i < endIndexC; i++, j++) - // { - // xy.read(2 * i, dst[j]); - // } - - return endIndexC; - } - - // Checked vs. Jan 11, 2011 - int QueryCoordinates(Point3D[] dst, int dstSize, int beginIndex, - int endIndex) { - int endIndexC = endIndex < 0 ? m_pointCount : endIndex; - endIndexC = Math.min(endIndexC, beginIndex + dstSize); - - if (beginIndex < 0 || beginIndex >= m_pointCount - || endIndexC < beginIndex) - // TODO replace geometry exc - throw new IllegalArgumentException(); - - AttributeStreamOfDbl xy = (AttributeStreamOfDbl) getAttributeStreamRef(VertexDescription.Semantics.POSITION); - AttributeStreamOfDbl z = null; - double v = VertexDescription - .getDefaultValue(VertexDescription.Semantics.Z); - boolean bHasZ = hasAttribute(VertexDescription.Semantics.Z); - if (bHasZ) - z = (AttributeStreamOfDbl) getAttributeStreamRef(VertexDescription.Semantics.Z); - int j = 0; - for (int i = beginIndex; i < endIndexC; i++, j++) { - dst[j].x = xy.read(2 * i); - dst[j].y = xy.read(2 * i + 1); - dst[j].z = bHasZ ? z.read(i) : v; - - dst[j] = getXYZ(i); - } - - return endIndexC; - } - - // Checked vs. Jan 11, 2011 - // -1 : DirtySimple is true (whether or not the MultiPath is Simple is - // unknown) - // 0 : DirtySimple is false and the MultiPath is not Weak Simple - // 1 : DirtySimple is false and the MultiPath is Weak Simple but not ring - // ordering may be invalid - // 2 : DirtySimple is false and the MultiPath is Strong Simple (Weak Simple - // and valid ring ordering) - public int getIsSimple(double tolerance) { - if (!_hasDirtyFlag(DirtyFlags.DirtyIsKnownSimple)) { - if (!_hasDirtyFlag(DirtyFlags.IsWeakSimple)) { - return 0; - } - if (m_simpleTolerance >= tolerance) { - if (!_hasDirtyFlag(DirtyFlags.DirtyOGCFlags)) - return 2; - - return 1; - } - - return -1; - } - return -1; - } - - void setIsSimple(int isSimpleRes, double tolerance, boolean ogc_known) { - m_simpleTolerance = tolerance; - if (isSimpleRes == GeometryXSimple.Unknown) { - _setDirtyFlag(DirtyFlags.DirtyIsKnownSimple, true); - _setDirtyFlag(DirtyFlags.DirtyOGCFlags, true); - return; - } - _setDirtyFlag(DirtyFlags.DirtyIsKnownSimple, false); - - if (!ogc_known) - _setDirtyFlag(DirtyFlags.DirtyOGCFlags, true); - - if (isSimpleRes == GeometryXSimple.Not) { - _setDirtyFlag(DirtyFlags.IsWeakSimple, false); - _setDirtyFlag(DirtyFlags.IsStrongSimple, false); - } else if (isSimpleRes == GeometryXSimple.Weak) { - _setDirtyFlag(DirtyFlags.IsWeakSimple, true); - _setDirtyFlag(DirtyFlags.IsStrongSimple, false); - } else if (isSimpleRes == GeometryXSimple.Strong) { - _setDirtyFlag(DirtyFlags.IsWeakSimple, true); - _setDirtyFlag(DirtyFlags.IsStrongSimple, true); - } else - throw GeometryException.GeometryInternalError();// what? - } - - double _getSimpleTolerance() { - return m_simpleTolerance; - } - - public GeometryAccelerators _getAccelerators() { - return m_accelerators; - } - - void _clearAccelerators() { - if (m_accelerators != null) - m_accelerators = null; - } - - void _interpolateTwoVertices(int vertex1, int vertex2, double f, - Point outPoint) { - if (vertex1 < 0 || vertex1 >= m_pointCount) - throw new GeometryException("index out of bounds."); - if (vertex2 < 0 || vertex2 >= m_pointCount) - throw new GeometryException("index out of bounds."); - - // _ASSERT(!IsEmpty()); - // _ASSERT(m_vertexAttributes != NULLPTR); - - _verifyAllStreams(); - - outPoint.assignVertexDescription(m_description); - if (outPoint.isEmpty()) - outPoint._setToDefault(); - - for (int attributeIndex = 0; attributeIndex < m_description - .getAttributeCount(); attributeIndex++) { - int semantics = m_description._getSemanticsImpl(attributeIndex); - for (int icomp = 0, ncomp = VertexDescription - .getComponentCount(semantics); icomp < ncomp; icomp++) { - double v1 = m_vertexAttributes[attributeIndex].readAsDbl(ncomp - * vertex1 + icomp); - double v2 = m_vertexAttributes[attributeIndex].readAsDbl(ncomp - * vertex2 + icomp); - outPoint.setAttribute(semantics, icomp, MathUtils.lerp(v1, v2, f)); - } - } - } - - double _getShortestDistance(int vertex1, int vertex2) { - Point2D pt = getXY(vertex1); - pt.sub(getXY(vertex2)); - return pt.length(); - } - - // ////////////////// METHODS To REMOVE /////////////////////// - @Override - public Point getPoint(int index) { - if (index < 0 || index >= m_pointCount) - throw new IndexOutOfBoundsException(); - - _verifyAllStreams(); - - Point outPoint = new Point(); - outPoint.assignVertexDescription(m_description); - if (outPoint.isEmpty()) - outPoint._setToDefault(); - - for (int attributeIndex = 0; attributeIndex < m_description - .getAttributeCount(); attributeIndex++) { - int semantics = m_description.getSemantics(attributeIndex); - for (int icomp = 0, ncomp = VertexDescription - .getComponentCount(semantics); icomp < ncomp; icomp++) { - double v = m_vertexAttributes[attributeIndex].readAsDbl(ncomp - * index + icomp); - outPoint.setAttribute(semantics, icomp, v); - } - } - return outPoint; - } - - @Override - public void setPoint(int index, Point src) { - if (index < 0 || index >= m_pointCount) - throw new IndexOutOfBoundsException(); - - Point point = src; - - if (src.isEmpty())// can not assign an empty point to a multipoint - // vertex - throw new IllegalArgumentException(); - - _verifyAllStreams();// verify all allocated streams are of necessary - // size. - VertexDescription vdin = point.getDescription(); - for (int attributeIndex = 0; attributeIndex < vdin.getAttributeCount(); attributeIndex++) { - int semantics = vdin.getSemantics(attributeIndex); - int ncomp = VertexDescription.getComponentCount(semantics); - for (int icomp = 0; icomp < ncomp; icomp++) { - double v = point.getAttributeAsDbl(semantics, icomp); - setAttribute(semantics, index, icomp, v); - } - } - } - - @Override - public void queryCoordinates(Point[] dst) { - int sz = m_pointCount; - if (dst.length < sz) - throw new IllegalArgumentException(); - - // TODO: refactor to a better AttributeAray call (ReadRange?) - for (int i = 0; i < sz; i++) { - dst[i] = getPoint(i); - } - } - - @Override - public void queryCoordinates(Point2D[] dst) { - int sz = m_pointCount; - if (dst.length < sz) - throw new IllegalArgumentException(); - - // TODO: refactor to a better AttributeAray call (ReadRange?) - for (int i = 0; i < sz; i++) { - dst[i] = getXY(i); - } - } - - @Override - public void queryCoordinates(Point3D[] dst) { - int sz = m_pointCount; - if (dst.length < sz) - throw new IllegalArgumentException(); - - // TODO: refactor to a better AttributeAray call (ReadRange?) - for (int i = 0; i < sz; i++) { - dst[i] = getXYZ(i); - } - } - + // HEADER DEFINED + public interface GeometryXSimple { + final int Unknown = -1; // not know if simple or not + final int Not = 0; // not simple + final int Weak = 1; // weak simple (no self intersections, ring + // orientation is correct, but ring order is not) + final int Strong = 2; // same as weak simple + OGC ring order. + } + + // TODO Remove? + /** + * \internal CHildren implement this method to copy additional information + */ + abstract void _copyToImpl(MultiVertexGeometryImpl mvg); + + protected abstract void _notifyModifiedAllImpl(); + + /** + * \internal Called inside of the VerifyAllStreams to get a child class a + * chance to do additional verify. + */ + protected abstract void _verifyStreamsImpl(); + + public interface DirtyFlags { + /**0 when IsWeakSimple flag is valid*/ + int DirtyIsKnownSimple = 1; + /**when DirtyIsKnownSimple is 0, this flag indicates whether the geometry is weak simple or not*/ + int IsWeakSimple = 2; + int IsStrongSimple = 4; + /**OGCFlags are set by Simplify or WKB/WKT import.*/ + int DirtyOGCFlags = 8; + /** At least one stream is unverified*/ + int DirtyVerifiedStreams = 32; + /** exact envelope is dirty*/ + int DirtyExactIntervals = 64; + /** loose envelope is dirty*/ + int DirtyLooseIntervals = 128; + /** loose and dirty envelopes are dirty */ + int DirtyIntervals = DirtyExactIntervals + | DirtyLooseIntervals; + /**the geometry is not known to be an envelope*/ + int DirtyIsEnvelope = 256; + /** The geometry length needs update*/ + int DirtyLength2D = 512; + /** m_cachedRingAreas2D need update*/ + int DirtyRingAreas2D = 1024; + int DirtyCoordinates = DirtyIsKnownSimple + | DirtyIntervals | DirtyIsEnvelope | DirtyLength2D + | DirtyRingAreas2D | DirtyOGCFlags; + int DirtyAllInternal = 0xFFFF; + /** There has been a change to one of attribute streams from the outside.*/ + int DirtyAll = 0xFFFFFF; + } + + /** + * Returns the total vertex count in this Geometry. + * + * @return total vertex count in this Geometry. + */ + @Override + public int getPointCount() { + return m_pointCount; + } + + @Override + public boolean isEmpty() { + return isEmptyImpl(); + } + + public VertexDescription getDescriptionImpl() { + return m_description; + } + + boolean isEmptyImpl() { + return m_pointCount == 0; + } + + protected boolean _hasDirtyFlag(int flag) { + return (m_flagsMask & flag) != 0; + } + + protected void _setDirtyFlag(int flag, boolean bYesNo) { + if (bYesNo) + m_flagsMask |= flag; + else + m_flagsMask &= ~flag; + } + + protected void _verifyAllStreams() { + if (_hasDirtyFlag(DirtyFlags.DirtyVerifiedStreams)) + _verifyAllStreamsImpl(); + } + + protected void throwIfEmpty() { + if (isEmptyImpl()) + // TODO fix exceptions + throw new GeometryException( + "This operation was performed on an Empty Geometry."); + } + + private static final long serialVersionUID = 1L; + + AttributeStreamBase[] m_vertexAttributes; + // TODO implement accelerators + GeometryAccelerators m_accelerators; + Envelope m_envelope; // the BBOX for all attributes + protected int m_pointCount; + protected int m_reservedPointCount;// the number of vertices reserved and + // initialized to default value. + protected int m_flagsMask; + protected double m_simpleTolerance; + + public MultiVertexGeometryImpl() { + m_flagsMask = DirtyFlags.DirtyAllInternal; + m_pointCount = 0; + m_reservedPointCount = -1; + m_accelerators = null; + } + + @Override + public void getPointByVal(int index, Point dst) { + if (index < 0 || index >= m_pointCount) + // TODO + throw new GeometryException("index out of bounds"); + + _verifyAllStreams(); + + Point outPoint = dst; + outPoint.assignVertexDescription(m_description); + + for (int attributeIndex = 0; attributeIndex < m_description + .getAttributeCount(); attributeIndex++) { + // fix semantics + int semantics = m_description._getSemanticsImpl(attributeIndex); + + // VertexDescription.getComponentCount(semantics); + for (int icomp = 0, ncomp = VertexDescription + .getComponentCount(semantics); icomp < ncomp; icomp++) { + double v = m_vertexAttributes[attributeIndex].readAsDbl(ncomp + * index + icomp); + outPoint.setAttribute(semantics, icomp, v); + } + } + } + + @Override + public void setPointByVal(int index, Point src) { + if (index < 0 || index >= m_pointCount) + throw new GeometryException("index out of bounds"); + + Point point = src; + + if (src.isEmpty())// can not assign an empty point to a multipoint + // vertex + throw new IllegalArgumentException(); + + _verifyAllStreams();// verify all allocated streams are of necessary + // size. + VertexDescription vdin = point.getDescription(); + for (int attributeIndex = 0; attributeIndex < vdin.getAttributeCount(); attributeIndex++) { + int semantics = vdin._getSemanticsImpl(attributeIndex); + int ncomp = VertexDescription.getComponentCount(semantics); + for (int icomp = 0; icomp < ncomp; icomp++) { + double v = point.getAttributeAsDbl(semantics, icomp); + setAttribute(semantics, index, icomp, v); + } + } + } + + // Checked vs. Jan 11, 2011 + @Override + public Point2D getXY(int index) { + Point2D pt = new Point2D(); + getXY(index, pt); + return pt; + } + + @Override + public void getXY(int index, Point2D pt) { + if (index < 0 || index >= getPointCount()) + throw new IndexOutOfBoundsException(); + + _verifyAllStreams(); + // AttributeStreamOfDbl v = (AttributeStreamOfDbl) + // m_vertexAttributes[0]; + AttributeStreamOfDbl v = (AttributeStreamOfDbl) m_vertexAttributes[0]; + v.read(index * 2, pt); + } + + // Checked vs. Jan 11, 2011 + @Override + public void setXY(int index, Point2D pt) { + if (index < 0 || index >= m_pointCount) + // TODO exception + throw new IndexOutOfBoundsException(); + + _verifyAllStreams(); + // AttributeStreamOfDbl v = (AttributeStreamOfDbl) + // m_vertexAttributes[0]; + AttributeStreamOfDbl v = (AttributeStreamOfDbl) m_vertexAttributes[0]; + v.write(index * 2, pt); + notifyModified(DirtyFlags.DirtyCoordinates); + } + + // Checked vs. Jan 11, 2011 + public void setXY(int index, double x, double y) { + if (index < 0 || index >= m_pointCount) + // TODO exc + throw new IndexOutOfBoundsException(); + + _verifyAllStreams(); + // AttributeStreamOfDbl v = (AttributeStreamOfDbl) + // m_vertexAttributes[0]; + // TODO ask sergey about casts + AttributeStreamOfDbl v = (AttributeStreamOfDbl) m_vertexAttributes[0]; + v.write(index * 2, x); + v.write(index * 2 + 1, y); + notifyModified(DirtyFlags.DirtyCoordinates); + } + + // Checked vs. Jan 11, 2011 + @Override + public Point3D getXYZ(int index) { + if (index < 0 || index >= getPointCount()) + throw new IndexOutOfBoundsException(); + + _verifyAllStreams(); + AttributeStreamOfDbl v = (AttributeStreamOfDbl) m_vertexAttributes[0]; + Point3D pt = new Point3D(); + pt.x = v.read(index * 2); + pt.y = v.read(index * 2 + 1); + + // TODO check excluded if statement componenet + if (hasAttribute(Semantics.Z))// && (m_vertexAttributes[1] != null)) + pt.z = m_vertexAttributes[1].readAsDbl(index); + else + pt.z = VertexDescription.getDefaultValue(Semantics.Z); + + return pt; + } + + // Checked vs. Jan 11, 2011 + @Override + public void setXYZ(int index, Point3D pt) { + if (index < 0 || index >= getPointCount()) + throw new IndexOutOfBoundsException(); + + addAttribute(Semantics.Z); + + _verifyAllStreams(); + notifyModified(DirtyFlags.DirtyCoordinates); + AttributeStreamOfDbl v = (AttributeStreamOfDbl) m_vertexAttributes[0]; + v.write(index * 2, pt.x); + v.write(index * 2 + 1, pt.y); + m_vertexAttributes[1].writeAsDbl(index, pt.z); + } + + // Checked vs. Jan 11, 2011 + @Override + public double getAttributeAsDbl(int semantics, int offset, int ordinate) { + if (offset < 0 || offset >= m_pointCount) + throw new IndexOutOfBoundsException(); + + int ncomps = VertexDescription.getComponentCount(semantics); + if (ordinate >= ncomps) + throw new IndexOutOfBoundsException(); + + _verifyAllStreams(); + int attributeIndex = m_description.getAttributeIndex(semantics); + // TODO check if statement + if (attributeIndex >= 0)// && m_vertexAttributes[attributeIndex] != + // null) { + { + return m_vertexAttributes[attributeIndex].readAsDbl(offset * ncomps + + ordinate); + } + return VertexDescription.getDefaultValue(semantics); + } + + // Checked vs. Jan 11, 2011 + @Override + public int getAttributeAsInt(int semantics, int offset, int ordinate) { + return (int) getAttributeAsDbl(semantics, offset, ordinate); + } + + // Checked vs. Jan 11, 2011 + @Override + public void setAttribute(int semantics, int offset, int ordinate, + double value) { + if (offset < 0 || offset >= m_pointCount) + throw new IndexOutOfBoundsException(); + + int ncomps = VertexDescription.getComponentCount(semantics); + if (ordinate >= ncomps) + throw new IndexOutOfBoundsException(); + + addAttribute(semantics); + _verifyAllStreams(); + int attributeIndex = m_description.getAttributeIndex(semantics); + notifyModified(DirtyFlags.DirtyCoordinates); + m_vertexAttributes[attributeIndex].writeAsDbl(offset * ncomps + + ordinate, value); + } + + // Checked vs. Jan 11, 2011 + @Override + public void setAttribute(int semantics, int offset, int ordinate, int value) { + setAttribute(semantics, offset, ordinate, (double) value); + } + + public AttributeStreamBase getAttributeStreamRef(int semantics) { + throwIfEmpty(); + + addAttribute(semantics); + _verifyAllStreams(); + + int attributeIndex = m_description.getAttributeIndex(semantics); + return m_vertexAttributes[attributeIndex]; + } + + /** + * Sets a reference to the given AttributeStream of the Geometry. Once the + * buffer has been obtained, the vertices of the Geometry can be manipulated + * directly. The AttributeStream parameters are not checked for the size.
+ * If the attribute is missing, it will be added.
+ * Note, that this method does not change the vertex count in the Geometry.
+ * The stream can have more elements, than the Geometry point count, but + * only necessary part will be saved when exporting to a ESRI shape or other + * format. @param semantics Semantics of the attribute to assign the stream + * to. @param stream The input AttributeStream that will be assigned by + * reference. If one changes the stream later through the reference, one has + * to call NotifyStreamChanged. \exception Throws invalid_argument exception + * if the input stream type does not match that of the semantics + * persistence. + */ + public void setAttributeStreamRef(int semantics, AttributeStreamBase stream) { + // int test1 = VertexDescription.getPersistence(semantics); + // int test2 = stream.getPersistence(); + + if ((stream != null) + && VertexDescription.getPersistence(semantics) != stream + .getPersistence())// input stream has wrong persistence + throw new IllegalArgumentException(); + + // Do not check for the stream size here to allow several streams to be + // attached before the point count is changed. + addAttribute(semantics); + int attributeIndex = m_description.getAttributeIndex(semantics); + if (m_vertexAttributes == null) + m_vertexAttributes = new AttributeStreamBase[m_description + .getAttributeCount()]; + + m_vertexAttributes[attributeIndex] = stream; + notifyModified(DirtyFlags.DirtyAll); + } + + @Override + protected void _assignVertexDescriptionImpl(VertexDescription newDescription) { + AttributeStreamBase[] newAttributes = null; + + if (m_vertexAttributes != null) { + int[] mapping = VertexDescriptionDesignerImpl.mapAttributes( + newDescription, m_description); + + newAttributes = new AttributeStreamBase[newDescription + .getAttributeCount()]; + + for (int i = 0, n = newDescription.getAttributeCount(); i < n; i++) { + if (mapping[i] != -1) { + int m = mapping[i]; + newAttributes[i] = m_vertexAttributes[m]; + } + + } + } + else { + //if there are no streams we do not create them + } + + m_description = newDescription; + m_vertexAttributes = newAttributes; // late assignment to try to stay + m_reservedPointCount = -1;// we need to recreate the new attribute then + notifyModified(DirtyFlags.DirtyAll); + } + + // Checked vs. Jan 11, 2011 + protected void _updateEnvelope(Envelope2D env) { + _updateAllDirtyIntervals(true); + m_envelope.queryEnvelope2D(env); + } // note: overload for polylines/polygons with curves + + // Checked vs. Jan 11, 2011 + protected void _updateEnvelope(Envelope3D env) { + _updateAllDirtyIntervals(true); + m_envelope.queryEnvelope3D(env); + } // note: overload for polylines/polygons with curves + + // Checked vs. Jan 11, 2011 + protected void _updateLooseEnvelope(Envelope2D env) { + // TODO ROHIT has this set to true? + _updateAllDirtyIntervals(false); + m_envelope.queryEnvelope2D(env); + } // note: overload for polylines/polygons with curves + + // Checked vs. Jan 11, 2011 + /** + * \internal Calculates loose envelope. Returns True if the calculation + * renders exact envelope. + */ + protected void _updateLooseEnvelope(Envelope3D env) { + // TODO ROHIT has this set to true? + _updateAllDirtyIntervals(false); + m_envelope.queryEnvelope3D(env); + } // note: overload for polylines/polygons with curves + + // Checked vs. Jan 11, 2011 + @Override + public void queryEnvelope(Envelope env) { + _updateAllDirtyIntervals(true); + m_envelope.copyTo(env); + } + + // TODO rename to remove 2D + // Checked vs. Jan 11, 2011 + @Override + public void queryEnvelope2D(Envelope2D env) { + _updateEnvelope(env); + } + + // Checked vs. Jan 11, 2011 + // TODO rename to remove 3D + @Override + public void queryEnvelope3D(Envelope3D env) { + _updateEnvelope(env); + } + + // Checked vs. Jan 11, 2011 + // TODO rename to remove 2D + @Override + public void queryLooseEnvelope2D(Envelope2D env) { + _updateLooseEnvelope(env); + } + + // Checked vs. Jan 11, 2011 + // TODO rename to remove 3D + @Override + public void queryLooseEnvelope3D(Envelope3D env) { + _updateLooseEnvelope(env); + } + + // Checked vs. Jan 11, 2011 + @Override + public Envelope1D queryInterval(int semantics, int ordinate) { + Envelope1D env = new Envelope1D(); + if (isEmptyImpl()) { + env.setEmpty(); + return env; + } + + _updateAllDirtyIntervals(true); + return m_envelope.queryInterval(semantics, ordinate); + } + + // Checked vs. Jan 11, 2011 + // TODO Rename to getHashCode + @Override + public int hashCode() { + int hashCode = m_description.hashCode(); + + if (!isEmptyImpl()) { + int pointCount = getPointCount(); + for (int i = 0, n = m_description.getAttributeCount(); i < n; i++) { + int components = VertexDescription + .getComponentCount(m_description._getSemanticsImpl(i)); + AttributeStreamBase stream = m_vertexAttributes[i]; + hashCode = stream.calculateHashImpl(hashCode, 0, pointCount + * components); + } + } + + return hashCode; + } + + // Checked vs. Jan 11, 2011 + @Override + public boolean equals(Object other) { + // Java checks + if (other == this) + return true; + + if (!(other instanceof MultiVertexGeometryImpl)) + return false; + + MultiVertexGeometryImpl otherMulti = (MultiVertexGeometryImpl) other; + + if (!(m_description.equals(otherMulti.m_description))) + return false; + + if (isEmptyImpl() != otherMulti.isEmptyImpl()) + return false; + + if (isEmptyImpl()) + return true; // both geometries are empty + + int pointCount = getPointCount(); + int pointCountOther = otherMulti.getPointCount(); + + if (pointCount != pointCountOther) + return false; + + for (int i = 0; i < m_description.getAttributeCount(); i++) { + int semantics = m_description.getSemantics(i); + + AttributeStreamBase stream = getAttributeStreamRef(semantics); + AttributeStreamBase streamOther = otherMulti + .getAttributeStreamRef(semantics); + + int components = VertexDescription.getComponentCount(semantics); + + if (!stream.equals(streamOther, 0, pointCount * components)) + return false; + } + + return true; + } + + // Checked vs. Jan 11, 2011 + /** + * Sets the envelope of the Geometry. The Envelope description must match + * that of the Geometry. + */ + public void setEnvelope(Envelope env) { + if (!m_description.equals(env.getDescription())) + throw new IllegalArgumentException(); + + // m_envelope = (Envelope) env.clone(); + m_envelope = (Envelope) env.createInstance(); + env.copyTo(m_envelope); + _setDirtyFlag(DirtyFlags.DirtyIntervals, false); + } + + @Override + public void copyTo(Geometry dstGeom) { + MultiVertexGeometryImpl dst = (MultiVertexGeometryImpl) dstGeom; + if (dst.getType() != getType()) + throw new IllegalArgumentException(); + + _copyToUnsafe(dst); + } + + //Does not check geometry type. Used to copy Polygon to Polyline + void _copyToUnsafe(MultiVertexGeometryImpl dst) { + _verifyAllStreams(); + dst.m_description = m_description; + dst.m_vertexAttributes = null; + int nattrib = m_description.getAttributeCount(); + AttributeStreamBase[] cloneAttributes = null; + if (m_vertexAttributes != null) { + cloneAttributes = new AttributeStreamBase[nattrib]; + for (int i = 0; i < nattrib; i++) { + if (m_vertexAttributes[i] != null) { + int ncomps = VertexDescription + .getComponentCount(m_description + ._getSemanticsImpl(i)); + cloneAttributes[i] = m_vertexAttributes[i] + .restrictedClone(getPointCount() * ncomps); + } + } + } + + if (m_envelope != null) { + dst.m_envelope = (Envelope) m_envelope.createInstance(); + m_envelope.copyTo(dst.m_envelope); + // dst.m_envelope = (Envelope) m_envelope.clone(); + } else + dst.m_envelope = null; + + dst.m_pointCount = m_pointCount; + dst.m_flagsMask = m_flagsMask; + dst.m_vertexAttributes = cloneAttributes; + + try { + _copyToImpl(dst); // copy child props + } catch (Exception ex) { + dst.setEmpty(); + throw new RuntimeException(ex); + } + } + + // Checked vs. Jan 11, 2011 + public boolean _attributeStreamIsAllocated(int semantics) { + throwIfEmpty(); + + int attributeIndex = m_description.getAttributeIndex(semantics); + + if (attributeIndex >= 0 && m_vertexAttributes[attributeIndex] != null) + return true; + + return false; + } + + // Checked vs. Jan 11, 2011 + void _setEmptyImpl() { + m_pointCount = 0; + m_reservedPointCount = -1; + m_vertexAttributes = null;// release it all streams. + notifyModified(DirtyFlags.DirtyAll); + } + + // Checked vs. Jan 11, 2011 + /** + * Notifies the Geometry of changes made to the vertices so that it could + * reset cached structures. + */ + public void notifyModified(int flags) { + if (flags == DirtyFlags.DirtyAll) { + m_reservedPointCount = -1;// forget the reserved point number + _notifyModifiedAllImpl(); + } + m_flagsMask |= flags; + + _clearAccelerators(); + _touch(); + } + + // Checked vs. Jan 11, 2011 + /** + * @param bExact + * True, when the exact envelope need to be calculated and false + * for the loose one. + */ + protected void _updateAllDirtyIntervals(boolean bExact) { + _verifyAllStreams(); + if (_hasDirtyFlag(DirtyFlags.DirtyIntervals)) { + if (null == m_envelope) + m_envelope = new Envelope(m_description); + else + m_envelope.assignVertexDescription(m_description); + + if (isEmpty()) { + m_envelope.setEmpty(); + return; + } + + _updateXYImpl(bExact);// efficient method for xy's + // now go through other attribues. + for (int attributeIndex = 1; attributeIndex < m_description + .getAttributeCount(); attributeIndex++) { + int semantics = m_description._getSemanticsImpl(attributeIndex); + int ncomps = VertexDescription.getComponentCount(semantics); + AttributeStreamBase stream = m_vertexAttributes[attributeIndex]; + for (int iord = 0; iord < ncomps; iord++) { + Envelope1D interval = new Envelope1D(); + interval.setEmpty(); + for (int i = 0; i < m_pointCount; i++) { + double value = stream.readAsDbl(i * ncomps + iord);// some + // optimization + // is + // possible + // if + // non-virtual + // method + // is + // used + interval.merge(value); + } + m_envelope.setInterval(semantics, iord, interval); + } + } + if (bExact) + _setDirtyFlag(DirtyFlags.DirtyIntervals, false); + } + } + + // Checked vs. Jan 11, 2011 + /** + * \internal Updates x, y intervals. + */ + public void _updateXYImpl(boolean bExact) { + m_envelope.setEmpty(); + AttributeStreamOfDbl stream = (AttributeStreamOfDbl) m_vertexAttributes[0]; + Point2D pt = new Point2D(); + for (int i = 0; i < m_pointCount; i++) { + stream.read(2 * i, pt); + m_envelope.merge(pt); + } + } + + void calculateEnvelope2D(Envelope2D env, boolean bExact) { + env.setEmpty(); + AttributeStreamOfDbl stream = (AttributeStreamOfDbl) m_vertexAttributes[0]; + Point2D pt = new Point2D(); + for (int i = 0; i < m_pointCount; i++) { + stream.read(2 * i, pt); + env.merge(pt); + } + } + + // Checked vs. Jan 11, 2011 lots of changes + /** + * \internal Verifies all streams (calls _VerifyStream for every attribute). + */ + protected void _verifyAllStreamsImpl() { + // This method checks that the streams are of correct size. + // It resizes the streams to ensure they are not shorter than + // m_PointCount + // _ASSERT(_HasDirtyFlag(enum_value1(DirtyFlags, + // DirtyVerifiedStreams))); + if (m_reservedPointCount < m_pointCount) // an optimization to skip this + // expensive loop when + // adding point by point + { + if (m_vertexAttributes == null) + m_vertexAttributes = new AttributeStreamBase[m_description + .getAttributeCount()]; + + m_reservedPointCount = NumberUtils.intMax(); + for (int attributeIndex = 0; attributeIndex < m_description + .getAttributeCount(); attributeIndex++) { + int semantics = m_description._getSemanticsImpl(attributeIndex); + if (m_vertexAttributes[attributeIndex] != null) { + int ncomp = VertexDescription.getComponentCount(semantics); + int size = m_vertexAttributes[attributeIndex].virtualSize() + / ncomp; + if (size < m_pointCount) { + size = (m_reservedPointCount > m_pointCount + 5) ? (m_pointCount * 5 + 3) / 4 + : m_pointCount;// reserve 25% more than user + // asks + m_vertexAttributes[attributeIndex].resize(size * ncomp, + VertexDescription.getDefaultValue(semantics)); + } + + if (size < m_reservedPointCount) + m_reservedPointCount = size; + } else { + m_vertexAttributes[attributeIndex] = AttributeStreamBase + .createAttributeStreamWithSemantics(semantics, + m_pointCount); + m_reservedPointCount = m_pointCount; + } + } + } + _verifyStreamsImpl(); + + _setDirtyFlag(DirtyFlags.DirtyVerifiedStreams, false); + } + + // Checked vs. Jan 11, 2011 + void _resizeImpl(int pointCount) { + if (pointCount < 0) + throw new IllegalArgumentException(); + + if (pointCount == m_pointCount) + return; + + m_pointCount = pointCount; + notifyModified(DirtyFlags.DirtyAllInternal); + } + + // Checked vs. Jan 11, 2011 + int queryCoordinates(Point2D[] dst, int dstSize, int beginIndex, + int endIndex) { + int endIndexC = endIndex < 0 ? m_pointCount : endIndex; + endIndexC = Math.min(endIndexC, beginIndex + dstSize); + + if (beginIndex < 0 || beginIndex >= m_pointCount + || endIndexC < beginIndex) + throw new IllegalArgumentException(); + + AttributeStreamOfDbl xy = (AttributeStreamOfDbl) getAttributeStreamRef(VertexDescription.Semantics.POSITION); + int j = 0; + double[] dstArray = new double[dst.length * 2]; + xy.readRange(2 * beginIndex, (endIndexC - beginIndex) * 2, dstArray, j, true); + + for (int i = 0; i < dst.length; i++) { + dst[i] = new Point2D(dstArray[i * 2], dstArray[i * 2 + 1]); + } + + // for (int i = beginIndex; i < endIndexC; i++, j++) + // { + // xy.read(2 * i, dst[j]); + // } + + return endIndexC; + } + + // Checked vs. Jan 11, 2011 + int QueryCoordinates(Point3D[] dst, int dstSize, int beginIndex, + int endIndex) { + int endIndexC = endIndex < 0 ? m_pointCount : endIndex; + endIndexC = Math.min(endIndexC, beginIndex + dstSize); + + if (beginIndex < 0 || beginIndex >= m_pointCount + || endIndexC < beginIndex) + // TODO replace geometry exc + throw new IllegalArgumentException(); + + AttributeStreamOfDbl xy = (AttributeStreamOfDbl) getAttributeStreamRef(VertexDescription.Semantics.POSITION); + AttributeStreamOfDbl z = null; + double v = VertexDescription + .getDefaultValue(VertexDescription.Semantics.Z); + boolean bHasZ = hasAttribute(VertexDescription.Semantics.Z); + if (bHasZ) + z = (AttributeStreamOfDbl) getAttributeStreamRef(VertexDescription.Semantics.Z); + int j = 0; + for (int i = beginIndex; i < endIndexC; i++, j++) { + dst[j].x = xy.read(2 * i); + dst[j].y = xy.read(2 * i + 1); + dst[j].z = bHasZ ? z.read(i) : v; + + dst[j] = getXYZ(i); + } + + return endIndexC; + } + + // Checked vs. Jan 11, 2011 + // -1 : DirtySimple is true (whether or not the MultiPath is Simple is + // unknown) + // 0 : DirtySimple is false and the MultiPath is not Weak Simple + // 1 : DirtySimple is false and the MultiPath is Weak Simple but not ring + // ordering may be invalid + // 2 : DirtySimple is false and the MultiPath is Strong Simple (Weak Simple + // and valid ring ordering) + public int getIsSimple(double tolerance) { + if (!_hasDirtyFlag(DirtyFlags.DirtyIsKnownSimple)) { + if (!_hasDirtyFlag(DirtyFlags.IsWeakSimple)) { + return 0; + } + if (m_simpleTolerance >= tolerance) { + if (!_hasDirtyFlag(DirtyFlags.DirtyOGCFlags)) + return 2; + + return 1; + } + + return -1; + } + return -1; + } + + void setIsSimple(int isSimpleRes, double tolerance, boolean ogc_known) { + m_simpleTolerance = tolerance; + if (isSimpleRes == GeometryXSimple.Unknown) { + _setDirtyFlag(DirtyFlags.DirtyIsKnownSimple, true); + _setDirtyFlag(DirtyFlags.DirtyOGCFlags, true); + return; + } + _setDirtyFlag(DirtyFlags.DirtyIsKnownSimple, false); + + if (!ogc_known) + _setDirtyFlag(DirtyFlags.DirtyOGCFlags, true); + + if (isSimpleRes == GeometryXSimple.Not) { + _setDirtyFlag(DirtyFlags.IsWeakSimple, false); + _setDirtyFlag(DirtyFlags.IsStrongSimple, false); + } else if (isSimpleRes == GeometryXSimple.Weak) { + _setDirtyFlag(DirtyFlags.IsWeakSimple, true); + _setDirtyFlag(DirtyFlags.IsStrongSimple, false); + } else if (isSimpleRes == GeometryXSimple.Strong) { + _setDirtyFlag(DirtyFlags.IsWeakSimple, true); + _setDirtyFlag(DirtyFlags.IsStrongSimple, true); + } else + throw GeometryException.GeometryInternalError();// what? + } + + double _getSimpleTolerance() { + return m_simpleTolerance; + } + + public GeometryAccelerators _getAccelerators() { + return m_accelerators; + } + + void _clearAccelerators() { + if (m_accelerators != null) + m_accelerators = null; + } + + void _interpolateTwoVertices(int vertex1, int vertex2, double f, + Point outPoint) { + if (vertex1 < 0 || vertex1 >= m_pointCount) + throw new GeometryException("index out of bounds."); + if (vertex2 < 0 || vertex2 >= m_pointCount) + throw new GeometryException("index out of bounds."); + + // _ASSERT(!IsEmpty()); + // _ASSERT(m_vertexAttributes != NULLPTR); + + _verifyAllStreams(); + + outPoint.assignVertexDescription(m_description); + for (int attributeIndex = 0; attributeIndex < m_description + .getAttributeCount(); attributeIndex++) { + int semantics = m_description._getSemanticsImpl(attributeIndex); + for (int icomp = 0, ncomp = VertexDescription + .getComponentCount(semantics); icomp < ncomp; icomp++) { + double v1 = m_vertexAttributes[attributeIndex].readAsDbl(ncomp + * vertex1 + icomp); + double v2 = m_vertexAttributes[attributeIndex].readAsDbl(ncomp + * vertex2 + icomp); + outPoint.setAttribute(semantics, icomp, MathUtils.lerp(v1, v2, f)); + } + } + } + + double _getShortestDistance(int vertex1, int vertex2) { + Point2D pt = getXY(vertex1); + pt.sub(getXY(vertex2)); + return pt.length(); + } + + // ////////////////// METHODS To REMOVE /////////////////////// + @Override + public Point getPoint(int index) { + if (index < 0 || index >= m_pointCount) + throw new IndexOutOfBoundsException(); + + _verifyAllStreams(); + + Point outPoint = new Point(); + outPoint.assignVertexDescription(m_description); + + for (int attributeIndex = 0; attributeIndex < m_description + .getAttributeCount(); attributeIndex++) { + int semantics = m_description.getSemantics(attributeIndex); + for (int icomp = 0, ncomp = VertexDescription + .getComponentCount(semantics); icomp < ncomp; icomp++) { + double v = m_vertexAttributes[attributeIndex].readAsDbl(ncomp + * index + icomp); + outPoint.setAttribute(semantics, icomp, v); + } + } + return outPoint; + } + + @Override + public void setPoint(int index, Point src) { + if (index < 0 || index >= m_pointCount) + throw new IndexOutOfBoundsException(); + + Point point = src; + + if (src.isEmpty())// can not assign an empty point to a multipoint + // vertex + throw new IllegalArgumentException(); + + _verifyAllStreams();// verify all allocated streams are of necessary + // size. + VertexDescription vdin = point.getDescription(); + for (int attributeIndex = 0; attributeIndex < vdin.getAttributeCount(); attributeIndex++) { + int semantics = vdin.getSemantics(attributeIndex); + int ncomp = VertexDescription.getComponentCount(semantics); + for (int icomp = 0; icomp < ncomp; icomp++) { + double v = point.getAttributeAsDbl(semantics, icomp); + setAttribute(semantics, index, icomp, v); + } + } + } + + @Override + public void queryCoordinates(Point[] dst) { + int sz = m_pointCount; + if (dst.length < sz) + throw new IllegalArgumentException(); + + // TODO: refactor to a better AttributeAray call (ReadRange?) + for (int i = 0; i < sz; i++) { + dst[i] = getPoint(i); + } + } + + @Override + public void queryCoordinates(Point2D[] dst) { + int sz = m_pointCount; + if (dst.length < sz) + throw new IllegalArgumentException(); + + // TODO: refactor to a better AttributeAray call (ReadRange?) + for (int i = 0; i < sz; i++) { + dst[i] = getXY(i); + } + } + + @Override + public void queryCoordinates(Point3D[] dst) { + int sz = m_pointCount; + if (dst.length < sz) + throw new IllegalArgumentException(); + + // TODO: refactor to a better AttributeAray call (ReadRange?) + for (int i = 0; i < sz; i++) { + dst[i] = getXYZ(i); + } + } + @Override public void replaceNaNs(int semantics, double value) { - addAttribute(semantics); - if (isEmpty()) - return; - - boolean modified = false; - int ncomps = VertexDescription.getComponentCount(semantics); - for (int i = 0; i < ncomps; i++) { - AttributeStreamBase streamBase = getAttributeStreamRef(semantics); - if (streamBase instanceof AttributeStreamOfDbl) { - AttributeStreamOfDbl dblStream = (AttributeStreamOfDbl) streamBase; - for (int ivert = 0, n = m_pointCount * ncomps; ivert < n; ivert++) { - double v = dblStream.read(ivert); - if (Double.isNaN(v)) { - dblStream.write(ivert, value); - modified = true; - } - } - } else { - for (int ivert = 0, n = m_pointCount * ncomps; ivert < n; ivert++) { - double v = streamBase.readAsDbl(ivert); - if (Double.isNaN(v)) { - streamBase.writeAsDbl(ivert, value); - modified = true; - } - } - } - } - - if (modified) { - notifyModified(DirtyFlags.DirtyCoordinates); - } + addAttribute(semantics); + if (isEmpty()) + return; + + boolean modified = false; + int ncomps = VertexDescription.getComponentCount(semantics); + for (int i = 0; i < ncomps; i++) { + AttributeStreamBase streamBase = getAttributeStreamRef(semantics); + if (streamBase instanceof AttributeStreamOfDbl) { + AttributeStreamOfDbl dblStream = (AttributeStreamOfDbl)streamBase; + for (int ivert = 0, n = m_pointCount * ncomps; ivert < n; ivert++) { + double v = dblStream.read(ivert); + if (Double.isNaN(v)) { + dblStream.write(ivert, value); + modified = true; + } + } + } + else { + for (int ivert = 0, n = m_pointCount * ncomps; ivert < n; ivert++) { + double v = streamBase.readAsDbl(ivert); + if (Double.isNaN(v)) { + streamBase.writeAsDbl(ivert, value); + modified = true; + } + } + } + } + + if (modified) { + notifyModified(DirtyFlags.DirtyCoordinates); + } } - public abstract boolean _buildRasterizedGeometryAccelerator( - double toleranceXY, GeometryAccelerationDegree accelDegree); + public abstract boolean _buildRasterizedGeometryAccelerator( + double toleranceXY, GeometryAccelerationDegree accelDegree); - public abstract boolean _buildQuadTreeAccelerator( - GeometryAccelerationDegree d); + public abstract boolean _buildQuadTreeAccelerator( + GeometryAccelerationDegree d); - @Override - public String toString() { - return "MultiVertexGeometryImpl"; - } + @Override + public String toString() { + return "MultiVertexGeometryImpl"; + } } diff --git a/src/main/java/com/esri/core/geometry/NonSimpleResult.java b/src/main/java/com/esri/core/geometry/NonSimpleResult.java index 47fa6a59..517a19e7 100644 --- a/src/main/java/com/esri/core/geometry/NonSimpleResult.java +++ b/src/main/java/com/esri/core/geometry/NonSimpleResult.java @@ -27,80 +27,80 @@ * The result of the IsSimpleXXX. */ public class NonSimpleResult { - public enum Reason { - /** - * This value is returned if the geometry "knows" through an internal state that it is non-simple. - * To make it determine the reason, use - * bForceTest == True. - */ - NotDetermined, - /** - * non-simple, because the structure is bad (0 size path, for example). - */ - Structure, - /** - * Non-simple, because there are degenerate segments. - */ - DegenerateSegments, - /** - * Non-simple, because not clustered properly, that is there are non-coincident vertices closer than tolerance. - */ - Clustering, - /** - * Non-simple, because not cracked properly (intersecting segments, overlaping segments) - */ - Cracking, - /** - * Non-simple, because there are crossovers (self intersections that are not cracking case). - */ - CrossOver, - /** - * Non-simple, because holes or exteriors have wrong orientation. - */ - RingOrientation, - /** - * The geometry is simple, but not strong-simple, because exteriors - * and holes are not in the correct order, and separation into sub polygons is not possible. - * Geometry needs to be resimplified with the bForceTest = true to fix this. - */ - RingOrder, - /** - * There is a self tangency or cross-over situation (strong simple, but not OGC simple) - * Only OperatorSimplifyOGC returns this. - */ - OGCPolylineSelfTangency, - /** - * There is a self tangency situation (strong simple, but not OGC simple) - * Only OperatorSimplifyOGC returns this. - */ - OGCPolygonSelfTangency, - /** - * Touching interioir rings make a disconnected point set from polygon interior - * (strong simple, but not OGC simple). - * Only OperatorSimplifyOGC returns this. - */ - OGCDisconnectedInterior - } + public enum Reason { + /** + * This value is returned if the geometry "knows" through an internal state that it is non-simple. + * To make it determine the reason, use + * bForceTest == True. + */ + NotDetermined, + /** + * non-simple, because the structure is bad (0 size path, for example). + */ + Structure, + /** + * Non-simple, because there are degenerate segments. + */ + DegenerateSegments, + /** + * Non-simple, because not clustered properly, that is there are non-coincident vertices closer than tolerance. + */ + Clustering, + /** + * Non-simple, because not cracked properly (intersecting segments, overlaping segments) + */ + Cracking, + /** + * Non-simple, because there are crossovers (self intersections that are not cracking case). + */ + CrossOver, + /** + * Non-simple, because holes or exteriors have wrong orientation. + */ + RingOrientation, + /** + * The geometry is simple, but not strong-simple, because exteriors + * and holes are not in the correct order, and separation into sub polygons is not possible. + * Geometry needs to be resimplified with the bForceTest = true to fix this. + */ + RingOrder, + /** + * There is a self tangency or cross-over situation (strong simple, but not OGC simple) + * Only OperatorSimplifyOGC returns this. + */ + OGCPolylineSelfTangency, + /** + * There is a self tangency situation (strong simple, but not OGC simple) + * Only OperatorSimplifyOGC returns this. + */ + OGCPolygonSelfTangency, + /** + * Touching interioir rings make a disconnected point set from polygon interior + * (strong simple, but not OGC simple). + * Only OperatorSimplifyOGC returns this. + */ + OGCDisconnectedInterior + } - public Reason m_reason; - public int m_vertexIndex1; - public int m_vertexIndex2; + public Reason m_reason; + public int m_vertexIndex1; + public int m_vertexIndex2; - public NonSimpleResult() { - m_reason = Reason.NotDetermined; - m_vertexIndex1 = -1; - m_vertexIndex2 = -1; - } + public NonSimpleResult() { + m_reason = Reason.NotDetermined; + m_vertexIndex1 = -1; + m_vertexIndex2 = -1; + } - void Assign(NonSimpleResult src) { - m_reason = src.m_reason; - m_vertexIndex1 = src.m_vertexIndex1; - m_vertexIndex2 = src.m_vertexIndex2; - } + void Assign(NonSimpleResult src) { + m_reason = src.m_reason; + m_vertexIndex1 = src.m_vertexIndex1; + m_vertexIndex2 = src.m_vertexIndex2; + } - NonSimpleResult(Reason reason, int index1, int index2) { - m_reason = reason; - m_vertexIndex1 = index1; - m_vertexIndex2 = index2; - } + NonSimpleResult(Reason reason, int index1, int index2) { + m_reason = reason; + m_vertexIndex1 = index1; + m_vertexIndex2 = index2; + } } diff --git a/src/main/java/com/esri/core/geometry/NumberUtils.java b/src/main/java/com/esri/core/geometry/NumberUtils.java index 0fc74aa5..01b6fd92 100644 --- a/src/main/java/com/esri/core/geometry/NumberUtils.java +++ b/src/main/java/com/esri/core/geometry/NumberUtils.java @@ -26,115 +26,128 @@ public class NumberUtils { - public static int snap(int v, int minv, int maxv) { - return v < minv ? minv : v > maxv ? maxv : v; - } - - public static long snap(long v, long minv, long maxv) { - return v < minv ? minv : v > maxv ? maxv : v; - } - - public static double snap(double v, double minv, double maxv) { - return v < minv ? minv : v > maxv ? maxv : v; - } - - static int sizeOf(double v) { - return 8; - } - - static int sizeOfDouble() { - return 8; - } - - static int sizeOf(int v) { - return 4; - } - - static int sizeOf(long v) { - return 8; - } - - static int sizeOf(byte v) { - return 1; - } - - static boolean isNaN(double d) { - return Double.isNaN(d); - } - - final static double TheNaN = Double.NaN; - - static double NaN() { - return Double.NaN; - } - - //combines two hash values - public static int hashCombine(int hash1, int hash2) { - return (hash1 * 31 + hash2) & 0x7FFFFFFF; - } - - //makes a hash out of an int - static int hash(int n) { - int hash = 5381; - hash = ((hash << 5) + hash) + (n & 0xFF); /* hash * 33 + c */ - hash = ((hash << 5) + hash) + ((n >> 8) & 0xFF); - hash = ((hash << 5) + hash) + ((n >> 16) & 0xFF); - hash = ((hash << 5) + hash) + ((n >> 24) & 0xFF); - hash &= 0x7FFFFFFF; - return hash; - } - - // //makes a hash out of an double - static int hash(double d) { - long bits = Double.doubleToLongBits(d); - int hc = (int) (bits ^ (bits >>> 32)); - return hash(hc); - } - - //adds an int to a hash value - static int hash(int hashIn, int n) { - int hash = ((hashIn << 5) + hashIn) + (n & 0xFF); /* hash * 33 + c */ - hash = ((hash << 5) + hash) + ((n >> 8) & 0xFF); - hash = ((hash << 5) + hash) + ((n >> 16) & 0xFF); - hash = ((hash << 5) + hash) + ((n >> 24) & 0xFF); - hash &= 0x7FFFFFFF; - return hash; - } - - //adds a double to a hash value - static int hash(int hash, double d) { - long bits = Double.doubleToLongBits(d); - int hc = (int) (bits ^ (bits >>> 32)); - return hash(hash, hc); - } - - static long doubleToInt64Bits(double d) { - return Double.doubleToLongBits(d); - } - - static double negativeInf() { - return Double.NEGATIVE_INFINITY; - } - - static double positiveInf() { - return Double.POSITIVE_INFINITY; - } - - static int intMax() { - return Integer.MAX_VALUE; - } - - static double doubleEps() { - return 2.2204460492503131e-016; - } - - static double doubleMax() { - return Double.MAX_VALUE; - } - - static int nextRand(int prevRand) { - return (1103515245 * prevRand + 12345) & intMax(); // according to Wiki, - // this is gcc's - } - + public static int snap(int v, int minv, int maxv) { + return v < minv ? minv : v > maxv ? maxv : v; + } + + public static long snap(long v, long minv, long maxv) { + return v < minv ? minv : v > maxv ? maxv : v; + } + + public static double snap(double v, double minv, double maxv) { + return v < minv ? minv : v > maxv ? maxv : v; + } + + static int sizeOf(double v) { + return 8; + } + + static int sizeOfDouble() { + return 8; + } + + static int sizeOf(int v) { + return 4; + } + + static int sizeOf(long v) { + return 8; + } + + static int sizeOf(byte v) { + return 1; + } + + static boolean isNaN(double d) { + return Double.isNaN(d); + } + + final static double TheNaN = Double.NaN; + + static double NaN() { + return Double.NaN; + } + + //combines two hash values + public static int hashCombine(int hash1, int hash2) { + return (hash1 * 31 + hash2) & 0x7FFFFFFF; + } + + //makes a hash out of an int + static int hash(int n) { + int hash = 5381; + hash = ((hash << 5) + hash) + (n & 0xFF); /* hash * 33 + c */ + hash = ((hash << 5) + hash) + ((n >> 8) & 0xFF); + hash = ((hash << 5) + hash) + ((n >> 16) & 0xFF); + hash = ((hash << 5) + hash) + ((n >> 24) & 0xFF); + hash &= 0x7FFFFFFF; + return hash; + } + + // //makes a hash out of an double + static int hash(double d) { + long bits = Double.doubleToLongBits(d); + int hc = (int) (bits ^ (bits >>> 32)); + return hash(hc); + } + + //adds an int to a hash value + static int hash(int hashIn, int n) { + int hash = ((hashIn << 5) + hashIn) + (n & 0xFF); /* hash * 33 + c */ + hash = ((hash << 5) + hash) + ((n >> 8) & 0xFF); + hash = ((hash << 5) + hash) + ((n >> 16) & 0xFF); + hash = ((hash << 5) + hash) + ((n >> 24) & 0xFF); + hash &= 0x7FFFFFFF; + return hash; + } + + //adds a double to a hash value + static int hash(int hash, double d) { + long bits = Double.doubleToLongBits(d); + int hc = (int) (bits ^ (bits >>> 32)); + return hash(hash, hc); + } + + static long doubleToInt64Bits(double d) { + return Double.doubleToLongBits(d); + } + + static double negativeInf() { + return Double.NEGATIVE_INFINITY; + } + + static double positiveInf() { + return Double.POSITIVE_INFINITY; + } + + static int intMax() { + return Integer.MAX_VALUE; + } + + static double doubleEps() { + return 2.2204460492503131e-016; + } + + static double doubleMax() { + return Double.MAX_VALUE; + } + + static int nextRand(int prevRand) { + return (1103515245 * prevRand + 12345) & intMax(); // according to Wiki, + // this is gcc's + } + + /** + * Returns true if two values are equal (also can compare inf and nan). + */ + static boolean isEqualNonIEEE(double a, double b) { + return a == b || (Double.isNaN(a) && Double.isNaN(b)); + } + + /** + * Returns true if two values are equal (also can compare inf and nan). + */ + static boolean isEqualNonIEEE(double a, double b, double tolerance) { + return a == b || Math.abs(a - b) <= tolerance || (Double.isNaN(a) && Double.isNaN(b)); + } } diff --git a/src/main/java/com/esri/core/geometry/OGCStructure.java b/src/main/java/com/esri/core/geometry/OGCStructure.java index b5002dde..9f0875b9 100644 --- a/src/main/java/com/esri/core/geometry/OGCStructure.java +++ b/src/main/java/com/esri/core/geometry/OGCStructure.java @@ -26,7 +26,7 @@ import java.util.List; public class OGCStructure { - public int m_type; - public List m_structures; - public Geometry m_geometry; + public int m_type; + public List m_structures; + public Geometry m_geometry; } diff --git a/src/main/java/com/esri/core/geometry/OGCStructureInternal.java b/src/main/java/com/esri/core/geometry/OGCStructureInternal.java new file mode 100644 index 00000000..59cf1e61 --- /dev/null +++ b/src/main/java/com/esri/core/geometry/OGCStructureInternal.java @@ -0,0 +1,82 @@ +/* + Copyright 1995-2018 Esri + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + For additional information, contact: + Environmental Systems Research Institute, Inc. + Attn: Contracts Dept + 380 New York Street + Redlands, California, USA 92373 + + email: contracts@esri.com + */ +package com.esri.core.geometry; + +//An internal helper class. Do not use. +public class OGCStructureInternal { + private static class EditShapeCursor extends GeometryCursor { + EditShape m_shape; + int m_geom; + int m_index; + + EditShapeCursor(EditShape shape, int index) { + m_shape = shape; + m_geom = -1; + m_index = index; + } + @Override + public Geometry next() { + if (m_shape != null) { + if (m_geom == -1) + m_geom = m_shape.getFirstGeometry(); + else + m_geom = m_shape.getNextGeometry(m_geom); + + if (m_geom == -1) { + m_shape = null; + } + else { + return m_shape.getGeometry(m_geom); + } + + } + + return null; + } + + @Override + public int getGeometryID() { + return m_shape.getGeometryUserIndex(m_geom, m_index); + } + + }; + + public static GeometryCursor prepare_for_ops_(GeometryCursor geoms, SpatialReference sr) { + assert(geoms != null); + EditShape editShape = new EditShape(); + int geomIndex = editShape.createGeometryUserIndex(); + for (Geometry g = geoms.next(); g != null; g = geoms.next()) { + int egeom = editShape.addGeometry(g); + editShape.setGeometryUserIndex(egeom, geomIndex, geoms.getGeometryID()); + } + + Envelope2D env = editShape.getEnvelope2D(); + double tolerance = InternalUtils.calculateToleranceFromGeometry(sr, + env, true); + + CrackAndCluster.execute(editShape, tolerance, null, true); + return OperatorSimplifyOGC.local().execute(new EditShapeCursor(editShape, geomIndex), sr, false, null); + } +} + diff --git a/src/main/java/com/esri/core/geometry/ObjectCacheTable.java b/src/main/java/com/esri/core/geometry/ObjectCacheTable.java index bddb924b..54b18abd 100644 --- a/src/main/java/com/esri/core/geometry/ObjectCacheTable.java +++ b/src/main/java/com/esri/core/geometry/ObjectCacheTable.java @@ -28,38 +28,38 @@ import java.util.Map; class ObjectCacheTable { - private Map m_hashTable = Collections - .synchronizedMap(new HashMap()); - private Object[] m_lru; - private boolean[] m_places; - private int m_index; + private Map m_hashTable = Collections + .synchronizedMap(new HashMap()); + private Object[] m_lru; + private boolean[] m_places; + private int m_index; - public ObjectCacheTable(int maxSize) { - m_lru = new Object[maxSize]; - m_places = new boolean[maxSize]; - m_index = 0; - for (int i = 0; i < maxSize; i++) - m_places[i] = false; - } + public ObjectCacheTable(int maxSize) { + m_lru = new Object[maxSize]; + m_places = new boolean[maxSize]; + m_index = 0; + for (int i = 0; i < maxSize; i++) + m_places[i] = false; + } - boolean contains(K key) { - return m_hashTable.containsKey(key); - } + boolean contains(K key) { + return m_hashTable.containsKey(key); + } - T get(K key) { - return m_hashTable.get(key); - } + T get(K key) { + return m_hashTable.get(key); + } - void add(K key, T value) { - if (m_places[m_index]) {// remove existing element from the cache - m_places[m_index] = false; - m_hashTable.remove(m_lru[m_index]); - } + void add(K key, T value) { + if (m_places[m_index]) {// remove existing element from the cache + m_places[m_index] = false; + m_hashTable.remove(m_lru[m_index]); + } - m_hashTable.put(key, value); - m_lru[m_index] = key; - m_places[m_index] = true; - m_index = (m_index + 1) % m_lru.length; - } + m_hashTable.put(key, value); + m_lru[m_index] = key; + m_places[m_index] = true; + m_index = (m_index + 1) % m_lru.length; + } } diff --git a/src/main/java/com/esri/core/geometry/Operator.java b/src/main/java/com/esri/core/geometry/Operator.java index 82fd9632..490ceb79 100644 --- a/src/main/java/com/esri/core/geometry/Operator.java +++ b/src/main/java/com/esri/core/geometry/Operator.java @@ -29,108 +29,111 @@ * The base class for Geometry Operators. */ public abstract class Operator { - /** - * The operator type enum. - */ - public enum Type { -// TODO, if you change the order of this you will ruin the geometry service - Project, - ExportToJson, - ImportFromJson, - ExportToESRIShape, - ImportFromESRIShape, - Union, - Difference, - Proximity2D, - Relate, - Equals, - Disjoint, - Intersects, - Within, - Contains, - Crosses, - Touches, - Overlaps, - Buffer, - Distance, - Intersection, - Clip, - Cut, - DensifyByLength, - DensifyByAngle, - LabelPoint, - GeodesicBuffer, - GeodeticDensifyByLength, - ShapePreservingDensify, - GeodeticLength, - GeodeticArea, - Simplify, - SimplifyOGC, - Offset, - Generalize, - GeneralizeByArea, - ExportToWkb, - ImportFromWkb, - ExportToWkt, - ImportFromWkt, - ImportFromGeoJson, - ExportToGeoJson, - SymmetricDifference, - ConvexHull, - Boundary, - RandomPoints, - EnclosingCircle, - GeodeticInverse - } + /** + * The operator type enum. + */ + public enum Type { + // TODO, if you change the order of this you will ruin the geometry service + Project, + ExportToJson, + ImportFromJson, + ExportToESRIShape, + ImportFromESRIShape, + Union, + Difference, + Proximity2D, + Relate, + Equals, + Disjoint, + Intersects, + Within, + Contains, + Crosses, + Touches, + Overlaps, + Buffer, + Distance, + Intersection, + Clip, + Cut, + DensifyByLength, + DensifyByAngle, + LabelPoint, + GeodesicBuffer, + GeodeticDensifyByLength, + ShapePreservingDensify, + GeodeticLength, + GeodeticArea, + Simplify, + SimplifyOGC, + Offset, + Generalize, + GeneralizeByArea, + ExportToWkb, + ImportFromWkb, + ExportToWkt, + ImportFromWkt, + ImportFromGeoJson, + ExportToGeoJson, + SymmetricDifference, + ConvexHull, + Boundary, + RandomPoints, + EnclosingCircle, + GeodeticInverse, + Centroid2D + } - public abstract Type getType(); + public abstract Type getType(); - /** - * Processes Geometry to accelerate operations on it. The Geometry and it's - * copies remain accelerated until modified. The acceleration of Geometry - * can be a time consuming operation. The accelerated geometry also takes - * more memory. Some operators share the same accelerator, some require - * a different one. If the accelerator is built for the given parameters, - * the method returns immediately. - * - * @param geometry The geometry to be accelerated - * @param spatialReference The spatial reference of that geometry - * @param accelDegree The acceleration degree for geometry. - */ - public boolean accelerateGeometry(Geometry geometry, - SpatialReference spatialReference, - GeometryAccelerationDegree accelDegree) { - // Override at specific Operator level - return false; - } + /** + * Processes Geometry to accelerate operations on it. The Geometry and it's + * copies remain accelerated until modified. The acceleration of Geometry + * can be a time consuming operation. The accelerated geometry also takes + * more memory. Some operators share the same accelerator, some require + * a different one. If the accelerator is built for the given parameters, + * the method returns immediately. + * + * @param geometry + * The geometry to be accelerated + * @param spatialReference + * The spatial reference of that geometry + * @param accelDegree The acceleration degree for geometry. + */ + public boolean accelerateGeometry(Geometry geometry, + SpatialReference spatialReference, + GeometryAccelerationDegree accelDegree) { + // Override at specific Operator level + return false; + } - /** - * Returns true if the geometry can be accelerated. - * - * @param geometry - * @return true for geometries that can be accelerated, false for geometries - * that cannot - */ - public boolean canAccelerateGeometry(Geometry geometry) { - // Override at specific Operator level - return false; - } + /** + * Returns true if the geometry can be accelerated. + * + * @param geometry + * @return true for geometries that can be accelerated, false for geometries + * that cannot + */ + public boolean canAccelerateGeometry(Geometry geometry) { + // Override at specific Operator level + return false; + } - /** - * Removes accelerators from given geometry. - * - * @param geometry The geometry instance to remove accelerators from. - */ - public static void deaccelerateGeometry(Geometry geometry) { - Geometry.Type gt = geometry.getType(); - if (Geometry.isMultiVertex(gt.value())) { - GeometryAccelerators accel = ((MultiVertexGeometryImpl) geometry - ._getImpl())._getAccelerators(); - if (accel != null) { - accel._setRasterizedGeometry(null); - accel._setQuadTree(null); - } - } - } + /** + * Removes accelerators from given geometry. + * @param geometry The geometry instance to remove accelerators from. + */ + public static void deaccelerateGeometry(Geometry geometry) { + Geometry.Type gt = geometry.getType(); + if (Geometry.isMultiVertex(gt.value())) + { + GeometryAccelerators accel = ((MultiVertexGeometryImpl) geometry + ._getImpl())._getAccelerators(); + if (accel != null){ + accel._setRasterizedGeometry(null); + accel._setQuadTree(null); + } + } + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorBoundary.java b/src/main/java/com/esri/core/geometry/OperatorBoundary.java index 673949f8..ea0e8405 100644 --- a/src/main/java/com/esri/core/geometry/OperatorBoundary.java +++ b/src/main/java/com/esri/core/geometry/OperatorBoundary.java @@ -24,38 +24,38 @@ package com.esri.core.geometry; public abstract class OperatorBoundary extends Operator { - @Override - public Type getType() { - return Type.Boundary; - } - - /** - * Calculates the boundary geometry. - * - * @param geoms The input geometry cursor. - * @param progress_tracker The progress tracker, that allows to cancel the lengthy operation. - * @return Returns a cursor over boundaries for each geometry. - */ - abstract public GeometryCursor execute(GeometryCursor geoms, - ProgressTracker progress_tracker); - - /** - * Calculates the boundary. - * - * @param geom The input geometry. - * @param progress_tracker The progress tracker, that allows to cancel the lengthy operation. - * @return Returns the boundary. - *

- * For Point - returns an empty point. - * For Multi_point - returns an empty point. - * For Envelope - returns a polyline, that bounds the envelope. - * For Polyline - returns a multipoint, using OGC specification (includes path endpoints, using mod 2 rule). - * For Polygon - returns a polyline that bounds the polygon (adds all rings of the polygon to a polyline). - */ - abstract public Geometry execute(Geometry geom, - ProgressTracker progress_tracker); - - public static OperatorBoundary local() { - return (OperatorBoundary) OperatorFactoryLocal.getInstance().getOperator(Type.Boundary); - } + @Override + public Type getType() { + return Type.Boundary; + } + + /** + * Calculates the boundary geometry. + * + * @param geoms The input geometry cursor. + * @param progress_tracker The progress tracker, that allows to cancel the lengthy operation. + * @return Returns a cursor over boundaries for each geometry. + */ + abstract public GeometryCursor execute(GeometryCursor geoms, + ProgressTracker progress_tracker); + + /** + * Calculates the boundary. + * + * @param geom The input geometry. + * @param progress_tracker The progress tracker, that allows to cancel the lengthy operation. + * @return Returns the boundary. + *

+ * For Point - returns an empty point. + * For Multi_point - returns an empty point. + * For Envelope - returns a polyline, that bounds the envelope. + * For Polyline - returns a multipoint, using OGC specification (includes path endpoints, using mod 2 rule). + * For Polygon - returns a polyline that bounds the polygon (adds all rings of the polygon to a polyline). + */ + abstract public Geometry execute(Geometry geom, + ProgressTracker progress_tracker); + + public static OperatorBoundary local() { + return (OperatorBoundary) OperatorFactoryLocal.getInstance().getOperator(Type.Boundary); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorBoundaryLocal.java b/src/main/java/com/esri/core/geometry/OperatorBoundaryLocal.java index 56d31e11..97a62d8d 100644 --- a/src/main/java/com/esri/core/geometry/OperatorBoundaryLocal.java +++ b/src/main/java/com/esri/core/geometry/OperatorBoundaryLocal.java @@ -25,19 +25,19 @@ class OperatorBoundaryLocal extends OperatorBoundary { - @Override - public GeometryCursor execute(GeometryCursor geoms, - ProgressTracker progressTracker) { - // TODO Auto-generated method stub - return new OperatorBoundaryLocalCursor(geoms, progressTracker); - } - - @Override - public Geometry execute(Geometry geom, ProgressTracker progressTracker) { - // TODO Auto-generated method stub - GeometryCursor res = new OperatorBoundaryLocalCursor( - new SimpleGeometryCursor(geom), progressTracker); - return res.next(); - } + @Override + public GeometryCursor execute(GeometryCursor geoms, + ProgressTracker progressTracker) { + // TODO Auto-generated method stub + return new OperatorBoundaryLocalCursor(geoms, progressTracker); + } + + @Override + public Geometry execute(Geometry geom, ProgressTracker progressTracker) { + // TODO Auto-generated method stub + GeometryCursor res = new OperatorBoundaryLocalCursor( + new SimpleGeometryCursor(geom), progressTracker); + return res.next(); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorBoundaryLocalCursor.java b/src/main/java/com/esri/core/geometry/OperatorBoundaryLocalCursor.java index e2a8ff1c..7518058c 100644 --- a/src/main/java/com/esri/core/geometry/OperatorBoundaryLocalCursor.java +++ b/src/main/java/com/esri/core/geometry/OperatorBoundaryLocalCursor.java @@ -24,30 +24,30 @@ package com.esri.core.geometry; final class OperatorBoundaryLocalCursor extends GeometryCursor { - ProgressTracker m_progress_tracker; - - OperatorBoundaryLocalCursor(GeometryCursor inputGeoms, - ProgressTracker tracker) { - m_inputGeoms = inputGeoms; - m_progress_tracker = tracker; - } - - @Override - public Geometry next() { - if (hasNext()) { - return calculate_boundary(m_inputGeoms.next(), m_progress_tracker); - } - - return null; - } - - private static Geometry calculate_boundary(Geometry geom, - ProgressTracker progress_tracker) { - Geometry res = Boundary.calculate(geom, progress_tracker); - if (res == null) - return new Point(geom.getDescription());// cannot return null - else - return res; - } + ProgressTracker m_progress_tracker; + + OperatorBoundaryLocalCursor(GeometryCursor inputGeoms, + ProgressTracker tracker) { + m_inputGeoms = inputGeoms; + m_progress_tracker = tracker; + } + + @Override + public Geometry next() { + if (hasNext()) { + return calculate_boundary(m_inputGeoms.next(), m_progress_tracker); + } + + return null; + } + + private static Geometry calculate_boundary(Geometry geom, + ProgressTracker progress_tracker) { + Geometry res = Boundary.calculate(geom, progress_tracker); + if (res == null) + return new Point(geom.getDescription());// cannot return null + else + return res; + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorBuffer.java b/src/main/java/com/esri/core/geometry/OperatorBuffer.java index cac9742b..b940420d 100644 --- a/src/main/java/com/esri/core/geometry/OperatorBuffer.java +++ b/src/main/java/com/esri/core/geometry/OperatorBuffer.java @@ -30,69 +30,69 @@ * Creates buffer polygons around geometries. */ public abstract class OperatorBuffer extends Operator { - @Override - public Type getType() { - return Type.Buffer; - } + @Override + public Type getType() { + return Type.Buffer; + } - /** - * Creates a buffer around the input geometries - * - * @param inputGeometries The geometries to buffer. - * @param sr The SpatialReference of the Geometries. - * @param distances The buffer distances for the Geometries. If the size of the distances array is less than the number of geometries in the inputGeometries, the last distance value is used for the rest of geometries. - * @param bUnion If True, the buffered geometries will be unioned, otherwise they wont be unioned. - */ - public abstract GeometryCursor execute(GeometryCursor inputGeometries, - SpatialReference sr, - double[] distances, - boolean bUnion, - ProgressTracker progressTracker); + /** + * Creates a buffer around the input geometries + * + * @param inputGeometries The geometries to buffer. + * @param sr The SpatialReference of the Geometries. + * @param distances The buffer distances for the Geometries. If the size of the distances array is less than the number of geometries in the inputGeometries, the last distance value is used for the rest of geometries. + * @param bUnion If True, the buffered geometries will be unioned, otherwise they wont be unioned. + */ + public abstract GeometryCursor execute(GeometryCursor inputGeometries, + SpatialReference sr, + double[] distances, + boolean bUnion, + ProgressTracker progressTracker); - /** - * Creates a buffer around the input geometry - * - * @param inputGeometry The geometry to buffer. - * @param sr The SpatialReference of the Geometry. - * @param distance The buffer distance for the Geometry. - */ - public abstract Geometry execute(Geometry inputGeometry, - SpatialReference sr, - double distance, - ProgressTracker progressTracker); + /** + * Creates a buffer around the input geometry + * + * @param inputGeometry The geometry to buffer. + * @param sr The SpatialReference of the Geometry. + * @param distance The buffer distance for the Geometry. + */ + public abstract Geometry execute(Geometry inputGeometry, + SpatialReference sr, + double distance, + ProgressTracker progressTracker); - /** - * Creates a buffer around the input geometries - * - * @param input_geometries The geometries to buffer. - * @param sr The Spatial_reference of the Geometries. It is used to obtain the tolerance. Can be null. - * @param distances The buffer distances for the Geometries. If the size of the distances array is less than the number of geometries in the input_geometries, the last distance value is used for the rest of geometries. - * @param max_deviation The max deviation of the result buffer from the true buffer in the units of the sr. - * When max_deviation is NaN or 0, it is replaced with 1e-5 * abs(distance). - * When max_deviation is larger than MIN = 0.5 * abs(distance), it is replaced with MIN. See below for more information. - * @param max_vertices_in_full_circle The maximum number of vertices in polygon produced from a buffered point. A value of 96 is used in methods that do not accept max_vertices_in_full_circle. - * If the value is less than MIN=12, it is set to MIN. See below for more information. - * @param b_union If True, the buffered geometries will be unioned, otherwise they wont be unioned. - * @param progress_tracker The progress tracker that allows to cancel the operation. Pass null if not needed. - *

- * The max_deviation and max_vertices_in_full_circle control the quality of round joins in the buffer. That is, the precision of the buffer is max_deviation unless - * the number of required vertices is too large. - * The max_vertices_in_full_circle controls how many vertices can be in each round join in the buffer. It is approximately equal to the number of vertices in the polygon around a - * buffered point. It has a priority over max_deviation. The max deviation is the distance from the result polygon to a true buffer. - * The real deviation is calculated as the max(max_deviation, abs(distance) * (1 - cos(PI / max_vertex_in_complete_circle))). - *

- * Note that max_deviation can be exceeded because geometry is generalized with 0.25 * real_deviation, also input segments closer than 0.25 * real_deviation are - * snapped to a point. - */ - public abstract GeometryCursor execute(GeometryCursor input_geometries, - SpatialReference sr, - double[] distances, - double max_deviation, - int max_vertices_in_full_circle, - boolean b_union, - ProgressTracker progress_tracker); + /** + * Creates a buffer around the input geometries + * + * @param input_geometries The geometries to buffer. + * @param sr The Spatial_reference of the Geometries. It is used to obtain the tolerance. Can be null. + * @param distances The buffer distances for the Geometries. If the size of the distances array is less than the number of geometries in the input_geometries, the last distance value is used for the rest of geometries. + * @param max_deviation The max deviation of the result buffer from the true buffer in the units of the sr. + * When max_deviation is NaN or 0, it is replaced with 1e-5 * abs(distance). + * When max_deviation is larger than MIN = 0.5 * abs(distance), it is replaced with MIN. See below for more information. + * @param max_vertices_in_full_circle The maximum number of vertices in polygon produced from a buffered point. A value of 96 is used in methods that do not accept max_vertices_in_full_circle. + * If the value is less than MIN=12, it is set to MIN. See below for more information. + * @param b_union If True, the buffered geometries will be unioned, otherwise they wont be unioned. + * @param progress_tracker The progress tracker that allows to cancel the operation. Pass null if not needed. + *

+ * The max_deviation and max_vertices_in_full_circle control the quality of round joins in the buffer. That is, the precision of the buffer is max_deviation unless + * the number of required vertices is too large. + * The max_vertices_in_full_circle controls how many vertices can be in each round join in the buffer. It is approximately equal to the number of vertices in the polygon around a + * buffered point. It has a priority over max_deviation. The max deviation is the distance from the result polygon to a true buffer. + * The real deviation is calculated as the max(max_deviation, abs(distance) * (1 - cos(PI / max_vertex_in_complete_circle))). + *

+ * Note that max_deviation can be exceeded because geometry is generalized with 0.25 * real_deviation, also input segments closer than 0.25 * real_deviation are + * snapped to a point. + */ + public abstract GeometryCursor execute(GeometryCursor input_geometries, + SpatialReference sr, + double[] distances, + double max_deviation, + int max_vertices_in_full_circle, + boolean b_union, + ProgressTracker progress_tracker); - public static OperatorBuffer local() { - return (OperatorBuffer) OperatorFactoryLocal.getInstance().getOperator(Type.Buffer); - } + public static OperatorBuffer local() { + return (OperatorBuffer) OperatorFactoryLocal.getInstance().getOperator(Type.Buffer); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorBufferCursor.java b/src/main/java/com/esri/core/geometry/OperatorBufferCursor.java index bcd2d707..d77a1546 100644 --- a/src/main/java/com/esri/core/geometry/OperatorBufferCursor.java +++ b/src/main/java/com/esri/core/geometry/OperatorBufferCursor.java @@ -25,53 +25,53 @@ package com.esri.core.geometry; class OperatorBufferCursor extends GeometryCursor { - Bufferer m_bufferer = new Bufferer(); - private SpatialReferenceImpl m_Spatial_reference; - private ProgressTracker m_progress_tracker; - private double[] m_distances; - private Envelope2D m_currentUnionEnvelope2D; - private boolean m_bUnion; - double m_max_deviation; - int m_max_vertices_in_full_circle; - private int m_dindex; + Bufferer m_bufferer = new Bufferer(); + private SpatialReferenceImpl m_Spatial_reference; + private ProgressTracker m_progress_tracker; + private double[] m_distances; + private Envelope2D m_currentUnionEnvelope2D; + private boolean m_bUnion; + double m_max_deviation; + int m_max_vertices_in_full_circle; + private int m_dindex; - OperatorBufferCursor(GeometryCursor inputGeoms, - SpatialReference sr, - double[] distances, - double max_deviation, - int max_vertices, - boolean b_union, - ProgressTracker progress_tracker) { - m_inputGeoms = inputGeoms; - m_max_deviation = max_deviation; - m_max_vertices_in_full_circle = max_vertices; - m_Spatial_reference = (SpatialReferenceImpl) (sr); - m_distances = distances; - m_bUnion = b_union; - m_currentUnionEnvelope2D = new Envelope2D(); - m_currentUnionEnvelope2D.setEmpty(); - m_dindex = -1; - m_progress_tracker = progress_tracker; - } + OperatorBufferCursor(GeometryCursor inputGeoms, + SpatialReference sr, + double[] distances, + double max_deviation, + int max_vertices, + boolean b_union, + ProgressTracker progress_tracker) { + m_inputGeoms = inputGeoms; + m_max_deviation = max_deviation; + m_max_vertices_in_full_circle = max_vertices; + m_Spatial_reference = (SpatialReferenceImpl) (sr); + m_distances = distances; + m_bUnion = b_union; + m_currentUnionEnvelope2D = new Envelope2D(); + m_currentUnionEnvelope2D.setEmpty(); + m_dindex = -1; + m_progress_tracker = progress_tracker; + } - @Override - public Geometry next() { - if (m_bUnion) { - OperatorBufferCursor bufferCursor = new OperatorBufferCursor(m_inputGeoms, - m_Spatial_reference, m_distances, m_max_deviation, m_max_vertices_in_full_circle, false, m_progress_tracker); - return ((OperatorUnion) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.Union)).execute(bufferCursor, m_Spatial_reference, m_progress_tracker).next(); - } else { - if (hasNext()) { - if (m_dindex + 1 < m_distances.length) - m_dindex++; + @Override + public Geometry next() { + if (m_bUnion) { + OperatorBufferCursor bufferCursor = new OperatorBufferCursor(m_inputGeoms, + m_Spatial_reference, m_distances, m_max_deviation, m_max_vertices_in_full_circle, false, m_progress_tracker); + return ((OperatorUnion) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.Union)).execute(bufferCursor, m_Spatial_reference, m_progress_tracker).next(); + } else { + if (hasNext()) { + if (m_dindex + 1 < m_distances.length) + m_dindex++; - return buffer(m_inputGeoms.next(), m_distances[m_dindex]); - } - return null; - } - } + return buffer(m_inputGeoms.next(), m_distances[m_dindex]); + } + return null; + } + } - Geometry buffer(Geometry geom, double distance) { - return m_bufferer.buffer(geom, distance, m_Spatial_reference, m_max_deviation, m_max_vertices_in_full_circle, m_progress_tracker); - } + Geometry buffer(Geometry geom, double distance) { + return m_bufferer.buffer(geom, distance, m_Spatial_reference, m_max_deviation, m_max_vertices_in_full_circle, m_progress_tracker); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorBufferLocal.java b/src/main/java/com/esri/core/geometry/OperatorBufferLocal.java index 7dddbcf1..78e281cc 100644 --- a/src/main/java/com/esri/core/geometry/OperatorBufferLocal.java +++ b/src/main/java/com/esri/core/geometry/OperatorBufferLocal.java @@ -26,42 +26,42 @@ class OperatorBufferLocal extends OperatorBuffer { - @Override - public GeometryCursor execute(GeometryCursor inputGeometries, - SpatialReference sr, - double[] distances, - boolean bUnion, - ProgressTracker progressTracker) { - return execute(inputGeometries, - sr, - distances, - NumberUtils.NaN(), - 96, - bUnion, - progressTracker); - } + @Override + public GeometryCursor execute(GeometryCursor inputGeometries, + SpatialReference sr, + double[] distances, + boolean bUnion, + ProgressTracker progressTracker) { + return execute(inputGeometries, + sr, + distances, + NumberUtils.NaN(), + 96, + bUnion, + progressTracker); + } - @Override - public Geometry execute(Geometry inputGeometry, - SpatialReference sr, - double distance, - ProgressTracker progressTracker) { - SimpleGeometryCursor inputCursor = new SimpleGeometryCursor(inputGeometry); - double[] distances = new double[1]; - distances[0] = distance; - GeometryCursor outputCursor = execute(inputCursor, sr, distances, false, progressTracker); + @Override + public Geometry execute(Geometry inputGeometry, + SpatialReference sr, + double distance, + ProgressTracker progressTracker) { + SimpleGeometryCursor inputCursor = new SimpleGeometryCursor(inputGeometry); + double[] distances = new double[1]; + distances[0] = distance; + GeometryCursor outputCursor = execute(inputCursor, sr, distances, false, progressTracker); - return outputCursor.next(); - } + return outputCursor.next(); + } - @Override - public GeometryCursor execute(GeometryCursor inputGeometries, - SpatialReference sr, - double[] distances, - double max_deviation, - int max_vertices_in_full_circle, - boolean b_union, - ProgressTracker progressTracker) { - return new OperatorBufferCursor(inputGeometries, sr, distances, max_deviation, max_vertices_in_full_circle, b_union, progressTracker); - } + @Override + public GeometryCursor execute(GeometryCursor inputGeometries, + SpatialReference sr, + double[] distances, + double max_deviation, + int max_vertices_in_full_circle, + boolean b_union, + ProgressTracker progressTracker) { + return new OperatorBufferCursor(inputGeometries, sr, distances, max_deviation, max_vertices_in_full_circle, b_union, progressTracker); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorCentroid2D.java b/src/main/java/com/esri/core/geometry/OperatorCentroid2D.java new file mode 100644 index 00000000..9453053d --- /dev/null +++ b/src/main/java/com/esri/core/geometry/OperatorCentroid2D.java @@ -0,0 +1,37 @@ +/* + Copyright 1995-2017 Esri + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + For additional information, contact: + Environmental Systems Research Institute, Inc. + Attn: Contracts Dept + 380 New York Street + Redlands, California, USA 92373 + + email: contracts@esri.com + */ +package com.esri.core.geometry; + +public abstract class OperatorCentroid2D extends Operator { + @Override + public Type getType() { + return Type.Centroid2D; + } + + public abstract Point2D execute(Geometry geometry, ProgressTracker progressTracker); + + public static OperatorCentroid2D local() { + return (OperatorCentroid2D) OperatorFactoryLocal.getInstance().getOperator(Type.Centroid2D); + } +} diff --git a/src/main/java/com/esri/core/geometry/OperatorCentroid2DLocal.java b/src/main/java/com/esri/core/geometry/OperatorCentroid2DLocal.java new file mode 100644 index 00000000..ce7079b8 --- /dev/null +++ b/src/main/java/com/esri/core/geometry/OperatorCentroid2DLocal.java @@ -0,0 +1,143 @@ +/* + Copyright 1995-2019 Esri + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + For additional information, contact: + Environmental Systems Research Institute, Inc. + Attn: Contracts Dept + 380 New York Street + Redlands, California, USA 92373 + + email: contracts@esri.com + */ +package com.esri.core.geometry; + +public class OperatorCentroid2DLocal extends OperatorCentroid2D { + @Override + public Point2D execute(Geometry geometry, ProgressTracker progressTracker) { + if (geometry.isEmpty()) { + return null; + } + + Geometry.Type geometryType = geometry.getType(); + switch (geometryType) { + case Point: + return ((Point) geometry).getXY(); + case Line: + return computeLineCentroid((Line) geometry); + case Envelope: + return ((Envelope) geometry).getCenterXY(); + case MultiPoint: + return computePointsCentroid((MultiPoint) geometry); + case Polyline: + return computePolylineCentroid(((Polyline) geometry)); + case Polygon: + return computePolygonCentroid((Polygon) geometry); + default: + throw new UnsupportedOperationException("Unexpected geometry type: " + geometryType); + } + } + + private static Point2D computeLineCentroid(Line line) { + return new Point2D((line.getEndX() - line.getStartX()) / 2, (line.getEndY() - line.getStartY()) / 2); + } + + // Points centroid is arithmetic mean of the input points + private static Point2D computePointsCentroid(MultiVertexGeometry multiPoint) { + double xSum = 0; + double ySum = 0; + int pointCount = multiPoint.getPointCount(); + Point2D point2D = new Point2D(); + for (int i = 0; i < pointCount; i++) { + multiPoint.getXY(i, point2D); + xSum += point2D.x; + ySum += point2D.y; + } + return new Point2D(xSum / pointCount, ySum / pointCount); + } + + // Lines centroid is weighted mean of each line segment, weight in terms of line + // length + private static Point2D computePolylineCentroid(MultiPath polyline) { + double totalLength = polyline.calculateLength2D(); + if (totalLength == 0) { + return computePointsCentroid(polyline); + } + + MathUtils.KahanSummator xSum = new MathUtils.KahanSummator(0); + MathUtils.KahanSummator ySum = new MathUtils.KahanSummator(0); + Point2D point = new Point2D(); + SegmentIterator iter = polyline.querySegmentIterator(); + while (iter.nextPath()) { + while (iter.hasNextSegment()) { + Segment seg = iter.nextSegment(); + seg.getCoord2D(0.5, point); + double length = seg.calculateLength2D(); + point.scale(length); + xSum.add(point.x); + ySum.add(point.y); + } + } + + return new Point2D(xSum.getResult() / totalLength, ySum.getResult() / totalLength); + } + + // Polygon centroid: area weighted average of centroids + private static Point2D computePolygonCentroid(Polygon polygon) { + double totalArea = polygon.calculateArea2D(); + if (totalArea == 0) + { + return computePolylineCentroid(polygon); + } + + MathUtils.KahanSummator xSum = new MathUtils.KahanSummator(0); + MathUtils.KahanSummator ySum = new MathUtils.KahanSummator(0); + Point2D startPoint = new Point2D(); + Point2D current = new Point2D(); + Point2D next = new Point2D(); + Point2D origin = polygon.getXY(0); + + for (int ipath = 0, npaths = polygon.getPathCount(); ipath < npaths; ipath++) { + int startIndex = polygon.getPathStart(ipath); + int endIndex = polygon.getPathEnd(ipath); + int pointCount = endIndex - startIndex; + if (pointCount < 3) { + continue; + } + + polygon.getXY(startIndex, startPoint); + polygon.getXY(startIndex + 1, current); + current.sub(startPoint); + for (int i = startIndex + 2, n = endIndex; i < n; i++) { + polygon.getXY(i, next); + next.sub(startPoint); + double twiceTriangleArea = next.x * current.y - current.x * next.y; + xSum.add((current.x + next.x) * twiceTriangleArea); + ySum.add((current.y + next.y) * twiceTriangleArea); + current.setCoords(next); + } + + startPoint.sub(origin); + startPoint.scale(6.0 * polygon.calculateRingArea2D(ipath)); + //add weighted startPoint + xSum.add(startPoint.x); + ySum.add(startPoint.y); + } + + totalArea *= 6.0; + Point2D res = new Point2D(xSum.getResult() / totalArea, ySum.getResult() / totalArea); + res.add(origin); + return res; + } +} diff --git a/src/main/java/com/esri/core/geometry/OperatorClip.java b/src/main/java/com/esri/core/geometry/OperatorClip.java index adfc4018..a32312e3 100644 --- a/src/main/java/com/esri/core/geometry/OperatorClip.java +++ b/src/main/java/com/esri/core/geometry/OperatorClip.java @@ -30,25 +30,25 @@ * Clips geometries with Envelope2D. */ public abstract class OperatorClip extends Operator { - public Type getType() { - return Type.Clip; - } - - /** - * Performs the Clip operation on the geometry set. - */ - public abstract GeometryCursor execute(GeometryCursor geoms, - Envelope2D envelope, SpatialReference spatialRef, - ProgressTracker progressTracker); - - /** - * Performs the Clip operation on a single geometry. - */ - public abstract Geometry execute(Geometry geom, Envelope2D envelope, - SpatialReference spatialRef, ProgressTracker progressTracker); - - public static OperatorClip local() { - return (OperatorClip) OperatorFactoryLocal.getInstance().getOperator(Type.Clip); - } + public Type getType() { + return Type.Clip; + } + + /** + * Performs the Clip operation on the geometry set. + */ + public abstract GeometryCursor execute(GeometryCursor geoms, + Envelope2D envelope, SpatialReference spatialRef, + ProgressTracker progressTracker); + + /** + * Performs the Clip operation on a single geometry. + */ + public abstract Geometry execute(Geometry geom, Envelope2D envelope, + SpatialReference spatialRef, ProgressTracker progressTracker); + + public static OperatorClip local() { + return (OperatorClip) OperatorFactoryLocal.getInstance().getOperator(Type.Clip); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorClipCursor.java b/src/main/java/com/esri/core/geometry/OperatorClipCursor.java index 09f024a8..7904bd57 100644 --- a/src/main/java/com/esri/core/geometry/OperatorClipCursor.java +++ b/src/main/java/com/esri/core/geometry/OperatorClipCursor.java @@ -25,25 +25,25 @@ package com.esri.core.geometry; class OperatorClipCursor extends GeometryCursor { - private Envelope2D m_envelope; - double m_tolerance; - - OperatorClipCursor(GeometryCursor geoms, Envelope2D envelope, - SpatialReference spatial_ref, ProgressTracker progress_tracker) { - if (geoms == null) - throw new IllegalArgumentException(); - - m_envelope = envelope; - m_inputGeoms = geoms; - - m_tolerance = InternalUtils.calculateToleranceFromGeometry(spatial_ref, envelope, false); - } - - @Override - public Geometry next() { - if (hasNext()) { - return Clipper.clip(m_inputGeoms.next(), m_envelope, m_tolerance, 0.0); - } - return null; - } + private Envelope2D m_envelope; + double m_tolerance; + + OperatorClipCursor(GeometryCursor geoms, Envelope2D envelope, + SpatialReference spatial_ref, ProgressTracker progress_tracker) { + if (geoms == null) + throw new IllegalArgumentException(); + + m_envelope = envelope; + m_inputGeoms = geoms; + + m_tolerance = InternalUtils.calculateToleranceFromGeometry(spatial_ref, envelope, false); + } + + @Override + public Geometry next() { + if (hasNext()) { + return Clipper.clip(m_inputGeoms.next(), m_envelope, m_tolerance, 0.0); + } + return null; + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorClipLocal.java b/src/main/java/com/esri/core/geometry/OperatorClipLocal.java index e641a8c9..4905eba2 100644 --- a/src/main/java/com/esri/core/geometry/OperatorClipLocal.java +++ b/src/main/java/com/esri/core/geometry/OperatorClipLocal.java @@ -26,19 +26,19 @@ class OperatorClipLocal extends OperatorClip { - @Override - public GeometryCursor execute(GeometryCursor geoms, Envelope2D envelope, - SpatialReference spatialRef, ProgressTracker progressTracker) { - return new OperatorClipCursor(geoms, envelope, spatialRef, progressTracker); - } - - @Override - public Geometry execute(Geometry geom, Envelope2D envelope, - SpatialReference spatialRef, ProgressTracker progressTracker) { - SimpleGeometryCursor inputCursor = new SimpleGeometryCursor(geom); - - GeometryCursor outputCursor = execute(inputCursor, envelope, spatialRef, progressTracker); - return outputCursor.next(); - } + @Override + public GeometryCursor execute(GeometryCursor geoms, Envelope2D envelope, + SpatialReference spatialRef, ProgressTracker progressTracker) { + return new OperatorClipCursor(geoms, envelope, spatialRef, progressTracker); + } + + @Override + public Geometry execute(Geometry geom, Envelope2D envelope, + SpatialReference spatialRef, ProgressTracker progressTracker) { + SimpleGeometryCursor inputCursor = new SimpleGeometryCursor(geom); + + GeometryCursor outputCursor = execute(inputCursor, envelope, spatialRef, progressTracker); + return outputCursor.next(); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorContains.java b/src/main/java/com/esri/core/geometry/OperatorContains.java index 62745640..bbc4cf27 100644 --- a/src/main/java/com/esri/core/geometry/OperatorContains.java +++ b/src/main/java/com/esri/core/geometry/OperatorContains.java @@ -30,13 +30,13 @@ * Relational operation Contains. */ public abstract class OperatorContains extends OperatorSimpleRelation { - @Override - public Type getType() { - return Type.Contains; - } - - public static OperatorContains local() { - return (OperatorContains) OperatorFactoryLocal.getInstance() - .getOperator(Type.Contains); - } + @Override + public Type getType() { + return Type.Contains; + } + + public static OperatorContains local() { + return (OperatorContains) OperatorFactoryLocal.getInstance() + .getOperator(Type.Contains); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorContainsLocal.java b/src/main/java/com/esri/core/geometry/OperatorContainsLocal.java index 9a61ef0f..592822e4 100644 --- a/src/main/java/com/esri/core/geometry/OperatorContainsLocal.java +++ b/src/main/java/com/esri/core/geometry/OperatorContainsLocal.java @@ -25,11 +25,11 @@ package com.esri.core.geometry; class OperatorContainsLocal extends OperatorContains { - @Override - public boolean execute(Geometry inputGeom1, Geometry inputGeom2, - SpatialReference sr, ProgressTracker progressTracker) { - return RelationalOperations.relate(inputGeom1, inputGeom2, sr, - RelationalOperations.Relation.contains, progressTracker); - } + @Override + public boolean execute(Geometry inputGeom1, Geometry inputGeom2, + SpatialReference sr, ProgressTracker progressTracker) { + return RelationalOperations.relate(inputGeom1, inputGeom2, sr, + RelationalOperations.Relation.contains, progressTracker); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorConvexHull.java b/src/main/java/com/esri/core/geometry/OperatorConvexHull.java index 9c02f531..a010b62b 100644 --- a/src/main/java/com/esri/core/geometry/OperatorConvexHull.java +++ b/src/main/java/com/esri/core/geometry/OperatorConvexHull.java @@ -29,51 +29,51 @@ * Creates the convex hull of the input geometry. */ public abstract class OperatorConvexHull extends Operator { - @Override - public Operator.Type getType() { - return Operator.Type.ConvexHull; - } + @Override + public Operator.Type getType() { + return Operator.Type.ConvexHull; + } - /** - * Calculates the convex hull. - * - * @param geoms The input geometry cursor. - * @param progress_tracker The progress tracker. Allows cancellation of a lengthy operation. - * @param b_merge Put true if you want the convex hull of all the geometries in the cursor combined. - * Put false if you want the convex hull of each geometry in the cursor individually. - * @return Returns a cursor over result convex hulls. - */ - abstract public GeometryCursor execute(GeometryCursor geoms, boolean b_merge, - ProgressTracker progress_tracker); + /** + * Calculates the convex hull. + * + * @param geoms The input geometry cursor. + * @param progress_tracker The progress tracker. Allows cancellation of a lengthy operation. + * @param b_merge Put true if you want the convex hull of all the geometries in the cursor combined. + * Put false if you want the convex hull of each geometry in the cursor individually. + * @return Returns a cursor over result convex hulls. + */ + abstract public GeometryCursor execute(GeometryCursor geoms, boolean b_merge, + ProgressTracker progress_tracker); - /** - * Calculates the convex hull geometry. - * - * @param geom The input geometry. - * @param progress_tracker The progress tracker. Allows cancellation of a lengthy operation. - * @return Returns the convex hull. - *

- * Point - Returns the same point. - * Envelope - returns the same envelope. - * MultiPoint - If the point count is one, returns the same multipoint. If the point count is two, returns a polyline of the points. Otherwise, computes and returns the convex hull polygon. - * Segment - Returns a polyline consisting of the segment. - * Polyline - If consists of only one segment, returns the same polyline. Otherwise, computes and returns the convex hull polygon. - * Polygon - If more than one path or if the path isn't already convex, computes and returns the convex hull polygon. Otherwise, returns the same polygon. - */ - abstract public Geometry execute(Geometry geom, - ProgressTracker progress_tracker); + /** + * Calculates the convex hull geometry. + * + * @param geom The input geometry. + * @param progress_tracker The progress tracker. Allows cancellation of a lengthy operation. + * @return Returns the convex hull. + *

+ * Point - Returns the same point. + * Envelope - returns the same envelope. + * MultiPoint - If the point count is one, returns the same multipoint. If the point count is two, returns a polyline of the points. Otherwise, computes and returns the convex hull polygon. + * Segment - Returns a polyline consisting of the segment. + * Polyline - If consists of only one segment, returns the same polyline. Otherwise, computes and returns the convex hull polygon. + * Polygon - If more than one path or if the path isn't already convex, computes and returns the convex hull polygon. Otherwise, returns the same polygon. + */ + abstract public Geometry execute(Geometry geom, + ProgressTracker progress_tracker); - /** - * Checks whether a Geometry is convex. - * - * @param geom The input geometry to test for convex. - * @param progress_tracker The progress tracker. - * @return Returns true if the geometry is convex. - */ - abstract public boolean isConvex(Geometry geom, - ProgressTracker progress_tracker); + /** + * Checks whether a Geometry is convex. + * + * @param geom The input geometry to test for convex. + * @param progress_tracker The progress tracker. + * @return Returns true if the geometry is convex. + */ + abstract public boolean isConvex(Geometry geom, + ProgressTracker progress_tracker); - public static OperatorConvexHull local() { - return (OperatorConvexHull) OperatorFactoryLocal.getInstance().getOperator(Type.ConvexHull); - } + public static OperatorConvexHull local() { + return (OperatorConvexHull) OperatorFactoryLocal.getInstance().getOperator(Type.ConvexHull); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorConvexHullCursor.java b/src/main/java/com/esri/core/geometry/OperatorConvexHullCursor.java index a91aa327..5667b4c5 100644 --- a/src/main/java/com/esri/core/geometry/OperatorConvexHullCursor.java +++ b/src/main/java/com/esri/core/geometry/OperatorConvexHullCursor.java @@ -24,184 +24,184 @@ package com.esri.core.geometry; class OperatorConvexHullCursor extends GeometryCursor { - private ProgressTracker m_progress_tracker; - private boolean m_b_merge; - private boolean m_b_done; - ConvexHull m_hull = new ConvexHull(); - - OperatorConvexHullCursor(boolean b_merge, GeometryCursor geoms, ProgressTracker progress_tracker) { - if (geoms == null) - throw new IllegalArgumentException(); - - m_b_merge = b_merge; - m_b_done = false; - m_inputGeoms = geoms; - m_progress_tracker = progress_tracker; - } - - @Override - public Geometry next() { - if (m_b_merge) { - if (!m_b_done) { - Geometry result = calculateConvexHullMerging_(m_inputGeoms, m_progress_tracker); - m_b_done = true; - return result; - } - - return null; - } - - if (!m_b_done) { - if (hasNext()) { - return calculateConvexHull_(m_inputGeoms.next(), m_progress_tracker); - } - - m_b_done = true; - } - - return null; - } - - private Geometry calculateConvexHullMerging_(GeometryCursor geoms, ProgressTracker progress_tracker) { - while (geoms.hasNext()) { - m_hull.addGeometry(geoms.next()); - } - - return m_hull.getBoundingGeometry(); - } - - @Override - public boolean tock() { - if (m_b_done) - return true; - - if (!m_b_merge) { - //Do not use tick/tock with the non-merging convex hull. - //Call tick/next instead, - //because tick pushes geometry into the cursor, and next performs a single convex hull on it. - throw new GeometryException("Invalid call for non merging convex hull."); - } - - Geometry geometry = m_inputGeoms.next(); - if (geometry != null) { - m_hull.addGeometry(geometry); - return true; - } else { - throw new GeometryException("Expects a non-null geometry."); - } - } - - static Geometry calculateConvexHull_(Geometry geom, ProgressTracker progress_tracker) { - if (geom.isEmpty()) - return geom.createInstance(); - - Geometry.Type type = geom.getType(); - - if (Geometry.isSegment(type.value())) {// Segments are always returned either as a Point or Polyline - Segment segment = (Segment) geom; - if (segment.getStartXY().equals(segment.getEndXY())) { - Point point = new Point(); - segment.queryStart(point); - return point; - } else { - Point pt = new Point(); - Polyline polyline = new Polyline(geom.getDescription()); - segment.queryStart(pt); - polyline.startPath(pt); - segment.queryEnd(pt); - polyline.lineTo(pt); - return polyline; - } - } else if (type == Geometry.Type.Envelope) { - Envelope envelope = (Envelope) geom; - Envelope2D env = new Envelope2D(); - envelope.queryEnvelope2D(env); - if (env.xmin == env.xmax && env.ymin == env.ymax) { - Point point = new Point(); - envelope.queryCornerByVal(0, point); - return point; - } else if (env.xmin == env.xmax || env.ymin == env.ymax) { - Point pt = new Point(); - Polyline polyline = new Polyline(geom.getDescription()); - envelope.queryCornerByVal(0, pt); - polyline.startPath(pt); - envelope.queryCornerByVal(1, pt); - polyline.lineTo(pt); - return polyline; - } else { - Polygon polygon = new Polygon(geom.getDescription()); - polygon.addEnvelope(envelope, false); - return polygon; - } - } - - if (isConvex_(geom, progress_tracker)) { - if (type == Geometry.Type.MultiPoint) {// Downgrade to a Point for simplistic output - MultiPoint multi_point = (MultiPoint) geom; - Point point = new Point(); - multi_point.getPointByVal(0, point); - return point; - } - - return geom; - } - - assert (Geometry.isMultiVertex(type.value())); - - Geometry convex_hull = ConvexHull.construct((MultiVertexGeometry) geom); - return convex_hull; - } - - static boolean isConvex_(Geometry geom, ProgressTracker progress_tracker) { - if (geom.isEmpty()) - return true; // vacuously true - - Geometry.Type type = geom.getType(); - - if (type == Geometry.Type.Point) - return true; // vacuously true - - if (type == Geometry.Type.Envelope) { - Envelope envelope = (Envelope) geom; - if (envelope.getXMin() == envelope.getXMax() || envelope.getYMin() == envelope.getYMax()) - return false; - - return true; - } - - if (MultiPath.isSegment(type.value())) { - Segment segment = (Segment) geom; - if (segment.getStartXY().equals(segment.getEndXY())) - return false; - - return true; // true, but we will upgrade to a Polyline for the ConvexHull operation - } - - if (type == Geometry.Type.MultiPoint) { - MultiPoint multi_point = (MultiPoint) geom; - - if (multi_point.getPointCount() == 1) - return true; // vacuously true, but we will downgrade to a Point for the ConvexHull operation - - return false; - } - - if (type == Geometry.Type.Polyline) { - Polyline polyline = (Polyline) geom; - - if (polyline.getPathCount() == 1 && polyline.getPointCount() == 2) { - if (!polyline.getXY(0).equals(polyline.getXY(1))) - return true; // vacuously true - } - - return false; // create convex hull - } - - Polygon polygon = (Polygon) geom; - - if (polygon.getPathCount() != 1 || polygon.getPointCount() < 3) - return false; - - return ConvexHull.isPathConvex(polygon, 0, progress_tracker); - } + private ProgressTracker m_progress_tracker; + private boolean m_b_merge; + private boolean m_b_done; + ConvexHull m_hull = new ConvexHull(); + + OperatorConvexHullCursor(boolean b_merge, GeometryCursor geoms, ProgressTracker progress_tracker) { + if (geoms == null) + throw new IllegalArgumentException(); + + m_b_merge = b_merge; + m_b_done = false; + m_inputGeoms = geoms; + m_progress_tracker = progress_tracker; + } + + @Override + public Geometry next() { + if (m_b_merge) { + if (!m_b_done) { + Geometry result = calculateConvexHullMerging_(m_inputGeoms, m_progress_tracker); + m_b_done = true; + return result; + } + + return null; + } + + if (!m_b_done) { + if (hasNext()) { + return calculateConvexHull_(m_inputGeoms.next(), m_progress_tracker); + } + + m_b_done = true; + } + + return null; + } + + private Geometry calculateConvexHullMerging_(GeometryCursor geoms, ProgressTracker progress_tracker) { + while (geoms.hasNext()) { + m_hull.addGeometry(geoms.next()); + } + + return m_hull.getBoundingGeometry(); + } + + @Override + public boolean tock() { + if (m_b_done) + return true; + + if (!m_b_merge) { + //Do not use tick/tock with the non-merging convex hull. + //Call tick/next instead, + //because tick pushes geometry into the cursor, and next performs a single convex hull on it. + throw new GeometryException("Invalid call for non merging convex hull."); + } + + Geometry geometry = m_inputGeoms.next(); + if (geometry != null) { + m_hull.addGeometry(geometry); + return true; + } else { + throw new GeometryException("Expects a non-null geometry."); + } + } + + static Geometry calculateConvexHull_(Geometry geom, ProgressTracker progress_tracker) { + if (geom.isEmpty()) + return geom.createInstance(); + + Geometry.Type type = geom.getType(); + + if (Geometry.isSegment(type.value())) {// Segments are always returned either as a Point or Polyline + Segment segment = (Segment) geom; + if (segment.getStartXY().equals(segment.getEndXY())) { + Point point = new Point(); + segment.queryStart(point); + return point; + } else { + Point pt = new Point(); + Polyline polyline = new Polyline(geom.getDescription()); + segment.queryStart(pt); + polyline.startPath(pt); + segment.queryEnd(pt); + polyline.lineTo(pt); + return polyline; + } + } else if (type == Geometry.Type.Envelope) { + Envelope envelope = (Envelope) geom; + Envelope2D env = new Envelope2D(); + envelope.queryEnvelope2D(env); + if (env.xmin == env.xmax && env.ymin == env.ymax) { + Point point = new Point(); + envelope.queryCornerByVal(0, point); + return point; + } else if (env.xmin == env.xmax || env.ymin == env.ymax) { + Point pt = new Point(); + Polyline polyline = new Polyline(geom.getDescription()); + envelope.queryCornerByVal(0, pt); + polyline.startPath(pt); + envelope.queryCornerByVal(1, pt); + polyline.lineTo(pt); + return polyline; + } else { + Polygon polygon = new Polygon(geom.getDescription()); + polygon.addEnvelope(envelope, false); + return polygon; + } + } + + if (isConvex_(geom, progress_tracker)) { + if (type == Geometry.Type.MultiPoint) {// Downgrade to a Point for simplistic output + MultiPoint multi_point = (MultiPoint) geom; + Point point = new Point(); + multi_point.getPointByVal(0, point); + return point; + } + + return geom; + } + + assert (Geometry.isMultiVertex(type.value())); + + Geometry convex_hull = ConvexHull.construct((MultiVertexGeometry) geom); + return convex_hull; + } + + static boolean isConvex_(Geometry geom, ProgressTracker progress_tracker) { + if (geom.isEmpty()) + return true; // vacuously true + + Geometry.Type type = geom.getType(); + + if (type == Geometry.Type.Point) + return true; // vacuously true + + if (type == Geometry.Type.Envelope) { + Envelope envelope = (Envelope) geom; + if (envelope.getXMin() == envelope.getXMax() || envelope.getYMin() == envelope.getYMax()) + return false; + + return true; + } + + if (MultiPath.isSegment(type.value())) { + Segment segment = (Segment) geom; + if (segment.getStartXY().equals(segment.getEndXY())) + return false; + + return true; // true, but we will upgrade to a Polyline for the ConvexHull operation + } + + if (type == Geometry.Type.MultiPoint) { + MultiPoint multi_point = (MultiPoint) geom; + + if (multi_point.getPointCount() == 1) + return true; // vacuously true, but we will downgrade to a Point for the ConvexHull operation + + return false; + } + + if (type == Geometry.Type.Polyline) { + Polyline polyline = (Polyline) geom; + + if (polyline.getPathCount() == 1 && polyline.getPointCount() == 2) { + if (!polyline.getXY(0).equals(polyline.getXY(1))) + return true; // vacuously true + } + + return false; // create convex hull + } + + Polygon polygon = (Polygon) geom; + + if (polygon.getPathCount() != 1 || polygon.getPointCount() < 3) + return false; + + return ConvexHull.isPathConvex(polygon, 0, progress_tracker); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorConvexHullLocal.java b/src/main/java/com/esri/core/geometry/OperatorConvexHullLocal.java index 5f02bb62..d9537b79 100644 --- a/src/main/java/com/esri/core/geometry/OperatorConvexHullLocal.java +++ b/src/main/java/com/esri/core/geometry/OperatorConvexHullLocal.java @@ -24,20 +24,20 @@ package com.esri.core.geometry; class OperatorConvexHullLocal extends OperatorConvexHull { - @Override - public GeometryCursor execute(GeometryCursor geoms, boolean b_merge, - ProgressTracker progress_tracker) { - return new OperatorConvexHullCursor(b_merge, geoms, progress_tracker); - } - - @Override - public Geometry execute(Geometry geometry, ProgressTracker progress_tracker) { - return OperatorConvexHullCursor.calculateConvexHull_(geometry, - progress_tracker); - } - - @Override - public boolean isConvex(Geometry geom, ProgressTracker progress_tracker) { - return OperatorConvexHullCursor.isConvex_(geom, progress_tracker); - } + @Override + public GeometryCursor execute(GeometryCursor geoms, boolean b_merge, + ProgressTracker progress_tracker) { + return new OperatorConvexHullCursor(b_merge, geoms, progress_tracker); + } + + @Override + public Geometry execute(Geometry geometry, ProgressTracker progress_tracker) { + return OperatorConvexHullCursor.calculateConvexHull_(geometry, + progress_tracker); + } + + @Override + public boolean isConvex(Geometry geom, ProgressTracker progress_tracker) { + return OperatorConvexHullCursor.isConvex_(geom, progress_tracker); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorCrosses.java b/src/main/java/com/esri/core/geometry/OperatorCrosses.java index 40bbed50..0780879a 100644 --- a/src/main/java/com/esri/core/geometry/OperatorCrosses.java +++ b/src/main/java/com/esri/core/geometry/OperatorCrosses.java @@ -30,14 +30,14 @@ * Relational operation Crosses. */ public abstract class OperatorCrosses extends OperatorSimpleRelation { - @Override - public Type getType() { - return Type.Crosses; - } - - public static OperatorCrosses local() { - return (OperatorCrosses) OperatorFactoryLocal.getInstance() - .getOperator(Type.Crosses); - } + @Override + public Type getType() { + return Type.Crosses; + } + + public static OperatorCrosses local() { + return (OperatorCrosses) OperatorFactoryLocal.getInstance() + .getOperator(Type.Crosses); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorCrossesLocal.java b/src/main/java/com/esri/core/geometry/OperatorCrossesLocal.java index b4a7341e..752ab1be 100644 --- a/src/main/java/com/esri/core/geometry/OperatorCrossesLocal.java +++ b/src/main/java/com/esri/core/geometry/OperatorCrossesLocal.java @@ -26,11 +26,11 @@ class OperatorCrossesLocal extends OperatorCrosses { - @Override - public boolean execute(Geometry inputGeom1, Geometry inputGeom2, - SpatialReference sr, ProgressTracker progressTracker) { - return RelationalOperations.relate(inputGeom1, inputGeom2, sr, - RelationalOperations.Relation.crosses, progressTracker); - } + @Override + public boolean execute(Geometry inputGeom1, Geometry inputGeom2, + SpatialReference sr, ProgressTracker progressTracker) { + return RelationalOperations.relate(inputGeom1, inputGeom2, sr, + RelationalOperations.Relation.crosses, progressTracker); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorCut.java b/src/main/java/com/esri/core/geometry/OperatorCut.java index bf2d73e1..2bb553a5 100644 --- a/src/main/java/com/esri/core/geometry/OperatorCut.java +++ b/src/main/java/com/esri/core/geometry/OperatorCut.java @@ -28,42 +28,42 @@ * Splits the target polyline or polygon where it is crossed by the cutter polyline. */ public abstract class OperatorCut extends Operator { - @Override - public Type getType() { - return Type.Cut; - } + @Override + public Type getType() { + return Type.Cut; + } - /** - * Performs the Cut operation on a geometry. - * - * @param bConsiderTouch Indicates whether we consider a touch event a cut. - * This only applies to polylines, but it's recommended to set this variable to True. - * @param cuttee The input geometry to be cut. - * @param cutter The polyline that will be used to divide the cuttee into - * pieces where it crosses the cutter. - * @return Returns a GeometryCursor of cut geometries. - * All left cuts will be grouped together in the first geometry. Right cuts and - * coincident cuts are grouped in the second geometry, and each undefined cut along - * with any uncut parts are output as separate geometries. If there were no cuts - * the cursor will return no geometry. If the left or right cut does not - * exist, the returned geometry will be empty for this type of cut. An - * undefined cut will only be produced if a left cut or right cut was - * produced and there was a part left over after cutting or a cut is - * bounded to the left and right of the cutter. - */ - public abstract GeometryCursor execute(boolean bConsiderTouch, - Geometry cuttee, - Polyline cutter, - SpatialReference spatialReference, - ProgressTracker progressTracker); + /** + * Performs the Cut operation on a geometry. + * + * @param bConsiderTouch Indicates whether we consider a touch event a cut. + * This only applies to polylines, but it's recommended to set this variable to True. + * @param cuttee The input geometry to be cut. + * @param cutter The polyline that will be used to divide the cuttee into + * pieces where it crosses the cutter. + * @return Returns a GeometryCursor of cut geometries. + * All left cuts will be grouped together in the first geometry. Right cuts and + * coincident cuts are grouped in the second geometry, and each undefined cut along + * with any uncut parts are output as separate geometries. If there were no cuts + * the cursor will return no geometry. If the left or right cut does not + * exist, the returned geometry will be empty for this type of cut. An + * undefined cut will only be produced if a left cut or right cut was + * produced and there was a part left over after cutting or a cut is + * bounded to the left and right of the cutter. + */ + public abstract GeometryCursor execute(boolean bConsiderTouch, + Geometry cuttee, + Polyline cutter, + SpatialReference spatialReference, + ProgressTracker progressTracker); - public abstract GeometryCursor execute(boolean bConsiderTouch, - GeometryCursor cuttees, - Polyline cutter, - SpatialReference spatialReference, - ProgressTracker progressTracker); + public abstract GeometryCursor execute(boolean bConsiderTouch, + GeometryCursor cuttees, + Polyline cutter, + SpatialReference spatialReference, + ProgressTracker progressTracker); - public static OperatorCut local() { - return (OperatorCut) OperatorFactoryLocal.getInstance().getOperator(Type.Cut); - } + public static OperatorCut local() { + return (OperatorCut) OperatorFactoryLocal.getInstance().getOperator(Type.Cut); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorCutCursor.java b/src/main/java/com/esri/core/geometry/OperatorCutCursor.java index 10f97b02..c9bedffa 100644 --- a/src/main/java/com/esri/core/geometry/OperatorCutCursor.java +++ b/src/main/java/com/esri/core/geometry/OperatorCutCursor.java @@ -31,186 +31,186 @@ import java.util.ArrayList; class OperatorCutCursor extends GeometryCursor { - boolean m_bConsiderTouch; - Geometry m_cuttee; - Polyline m_cutter; - double m_tolerance; - ProgressTracker m_progressTracker; - SpatialReference m_spatialReference; - int m_cutIndex; - ArrayList m_cuts = null; - boolean m_bFirstCall = false; - - OperatorCutCursor(boolean bConsiderTouch, - GeometryCursor cutteeCursor, - Polyline cutter, - SpatialReference spatialReference, - ProgressTracker progressTracker) { - - m_bConsiderTouch = bConsiderTouch; - m_inputGeoms = cutteeCursor; - m_cutter = cutter; - m_spatialReference = spatialReference; - m_cutIndex = -1; - m_progressTracker = progressTracker; - m_bFirstCall = true; - } - - @Override - public boolean hasNext() { - return m_inputGeoms != null && (m_inputGeoms.hasNext() || (m_bFirstCall || m_cutIndex + 1 < m_cuts.size())); - } - - private boolean hasNextRes() { - return m_bFirstCall || m_cutIndex + 1 < m_cuts.size(); - } - - @Override - public Geometry next() { - if (m_bFirstCall || (m_inputGeoms != null && m_inputGeoms.hasNext() && !(m_cutIndex + 1 < m_cuts.size()))) { - m_cuttee = m_inputGeoms.next(); - Envelope2D e = InternalUtils.getMergedExtent(m_cuttee, m_cutter); - m_tolerance = InternalUtils.calculateToleranceFromGeometry(m_spatialReference, e, true); - m_bFirstCall = true; - m_cutIndex = -1; - } - - if (hasNextRes()) { - m_bFirstCall = false; - generateCuts_(); - if (++m_cutIndex < m_cuts.size()) { - return m_cuts.get(m_cutIndex); - } - } - - return null; - } - - private void generateCuts_() { - if (m_cuts != null) - return; - - m_cuts = new ArrayList<>(); - - Geometry.Type type = m_cuttee.getType(); - switch (type.value()) { - case Geometry.GeometryType.Polyline: - generate_polyline_cuts_(); - break; - - case Geometry.GeometryType.Polygon: - generate_polygon_cuts_(); - break; - - default: - break; // warning fix - } - } - - private void generate_polyline_cuts_() { - MultiPath left = new Polyline(); - MultiPath right = new Polyline(); - MultiPath uncut = new Polyline(); - - m_cuts.add(left); - m_cuts.add(right); - - ArrayList cutPairs = new ArrayList( - 0); - Cutter.CutPolyline(m_bConsiderTouch, (Polyline) m_cuttee, m_cutter, - m_tolerance, cutPairs, null, m_progressTracker); - - for (int icut = 0; icut < cutPairs.size(); icut++) { - OperatorCutLocal.CutPair cutPair = cutPairs.get(icut); - if (cutPair.m_side == Side.Left) { - left.add((MultiPath) cutPair.m_geometry, false); - } else if (cutPair.m_side == Side.Right - || cutPair.m_side == Side.Coincident) { - right.add((MultiPath) cutPair.m_geometry, false); - } else if (cutPair.m_side == Side.Undefined) { - m_cuts.add((MultiPath) cutPair.m_geometry); - } else { - uncut.add((MultiPath) cutPair.m_geometry, false); - } - } - - if (!uncut.isEmpty() - && (!left.isEmpty() || !right.isEmpty() || m_cuts.size() >= 3)) - m_cuts.add(uncut); - - if (left.isEmpty() && right.isEmpty() && m_cuts.size() < 3) - m_cuts.clear(); // no cuts - } - - private void generate_polygon_cuts_() { - AttributeStreamOfInt32 cutHandles = new AttributeStreamOfInt32(0); - EditShape shape = new EditShape(); - int sideIndex = shape.createGeometryUserIndex(); - int cutteeHandle = shape.addGeometry(m_cuttee); - int cutterHandle = shape.addGeometry(m_cutter); - TopologicalOperations topoOp = new TopologicalOperations(); - try { - topoOp.setEditShapeCrackAndCluster(shape, m_tolerance, - m_progressTracker); - topoOp.cut(sideIndex, cutteeHandle, cutterHandle, cutHandles); - Polygon cutteeRemainder = (Polygon) shape.getGeometry(cutteeHandle); - - MultiPath left = new Polygon(); - MultiPath right = new Polygon(); - - m_cuts.clear(); - m_cuts.add(left); - m_cuts.add(right); - - for (int icutIndex = 0; icutIndex < cutHandles.size(); icutIndex++) { - Geometry cutGeometry; - { - // intersection - EditShape shapeIntersect = new EditShape(); - int geometryA = shapeIntersect.addGeometry(cutteeRemainder); - int geometryB = shapeIntersect.addGeometry(shape - .getGeometry(cutHandles.get(icutIndex))); - topoOp.setEditShape(shapeIntersect, m_progressTracker); - int intersectHandle = topoOp.intersection(geometryA, - geometryB); - cutGeometry = shapeIntersect.getGeometry(intersectHandle); - - if (cutGeometry.isEmpty()) - continue; - - int side = shape.getGeometryUserIndex( - cutHandles.get(icutIndex), sideIndex); - if (side == 2) - left.add((MultiPath) cutGeometry, false); - else if (side == 1) - right.add((MultiPath) cutGeometry, false); - else - m_cuts.add((MultiPath) cutGeometry); // Undefined - } - - { - // difference - EditShape shapeDifference = new EditShape(); - int geometryA = shapeDifference - .addGeometry(cutteeRemainder); - int geometryB = shapeDifference.addGeometry(shape - .getGeometry(cutHandles.get(icutIndex))); - topoOp.setEditShape(shapeDifference, m_progressTracker); - cutteeRemainder = (Polygon) shapeDifference - .getGeometry(topoOp - .difference(geometryA, geometryB)); - } - } - - if (!cutteeRemainder.isEmpty() && cutHandles.size() > 0) - m_cuts.add((MultiPath) cutteeRemainder); - - if (left.isEmpty() && right.isEmpty()) - m_cuts.clear(); // no cuts - - } finally { - topoOp.removeShape(); - } - } + boolean m_bConsiderTouch; + Geometry m_cuttee; + Polyline m_cutter; + double m_tolerance; + ProgressTracker m_progressTracker; + SpatialReference m_spatialReference; + int m_cutIndex; + ArrayList m_cuts = null; + boolean m_bFirstCall = false; + + OperatorCutCursor(boolean bConsiderTouch, + GeometryCursor cutteeCursor, + Polyline cutter, + SpatialReference spatialReference, + ProgressTracker progressTracker) { + + m_bConsiderTouch = bConsiderTouch; + m_inputGeoms = cutteeCursor; + m_cutter = cutter; + m_spatialReference = spatialReference; + m_cutIndex = -1; + m_progressTracker = progressTracker; + m_bFirstCall = true; + } + + @Override + public boolean hasNext() { + return m_inputGeoms != null && (m_inputGeoms.hasNext() || (m_bFirstCall || m_cutIndex + 1 < m_cuts.size())); + } + + private boolean hasNextRes() { + return m_bFirstCall || m_cutIndex + 1 < m_cuts.size(); + } + + @Override + public Geometry next() { + if (m_bFirstCall || (m_inputGeoms != null && m_inputGeoms.hasNext() && !(m_cutIndex + 1 < m_cuts.size()))) { + m_cuttee = m_inputGeoms.next(); + Envelope2D e = InternalUtils.getMergedExtent(m_cuttee, m_cutter); + m_tolerance = InternalUtils.calculateToleranceFromGeometry(m_spatialReference, e, true); + m_bFirstCall = true; + m_cutIndex = -1; + } + + if (hasNextRes()) { + m_bFirstCall = false; + generateCuts_(); + if (++m_cutIndex < m_cuts.size()) { + return m_cuts.get(m_cutIndex); + } + } + + return null; + } + + private void generateCuts_() { + if (m_cuts != null) + return; + + m_cuts = new ArrayList<>(); + + Geometry.Type type = m_cuttee.getType(); + switch (type.value()) { + case Geometry.GeometryType.Polyline: + generate_polyline_cuts_(); + break; + + case Geometry.GeometryType.Polygon: + generate_polygon_cuts_(); + break; + + default: + break; // warning fix + } + } + + private void generate_polyline_cuts_() { + MultiPath left = new Polyline(); + MultiPath right = new Polyline(); + MultiPath uncut = new Polyline(); + + m_cuts.add(left); + m_cuts.add(right); + + ArrayList cutPairs = new ArrayList( + 0); + Cutter.CutPolyline(m_bConsiderTouch, (Polyline) m_cuttee, m_cutter, + m_tolerance, cutPairs, null, m_progressTracker); + + for (int icut = 0; icut < cutPairs.size(); icut++) { + OperatorCutLocal.CutPair cutPair = cutPairs.get(icut); + if (cutPair.m_side == Side.Left) { + left.add((MultiPath) cutPair.m_geometry, false); + } else if (cutPair.m_side == Side.Right + || cutPair.m_side == Side.Coincident) { + right.add((MultiPath) cutPair.m_geometry, false); + } else if (cutPair.m_side == Side.Undefined) { + m_cuts.add((MultiPath) cutPair.m_geometry); + } else { + uncut.add((MultiPath) cutPair.m_geometry, false); + } + } + + if (!uncut.isEmpty() + && (!left.isEmpty() || !right.isEmpty() || m_cuts.size() >= 3)) + m_cuts.add(uncut); + + if (left.isEmpty() && right.isEmpty() && m_cuts.size() < 3) + m_cuts.clear(); // no cuts + } + + private void generate_polygon_cuts_() { + AttributeStreamOfInt32 cutHandles = new AttributeStreamOfInt32(0); + EditShape shape = new EditShape(); + int sideIndex = shape.createGeometryUserIndex(); + int cutteeHandle = shape.addGeometry(m_cuttee); + int cutterHandle = shape.addGeometry(m_cutter); + TopologicalOperations topoOp = new TopologicalOperations(); + try { + topoOp.setEditShapeCrackAndCluster(shape, m_tolerance, + m_progressTracker); + topoOp.cut(sideIndex, cutteeHandle, cutterHandle, cutHandles); + Polygon cutteeRemainder = (Polygon) shape.getGeometry(cutteeHandle); + + MultiPath left = new Polygon(); + MultiPath right = new Polygon(); + + m_cuts.clear(); + m_cuts.add(left); + m_cuts.add(right); + + for (int icutIndex = 0; icutIndex < cutHandles.size(); icutIndex++) { + Geometry cutGeometry; + { + // intersection + EditShape shapeIntersect = new EditShape(); + int geometryA = shapeIntersect.addGeometry(cutteeRemainder); + int geometryB = shapeIntersect.addGeometry(shape + .getGeometry(cutHandles.get(icutIndex))); + topoOp.setEditShape(shapeIntersect, m_progressTracker); + int intersectHandle = topoOp.intersection(geometryA, + geometryB); + cutGeometry = shapeIntersect.getGeometry(intersectHandle); + + if (cutGeometry.isEmpty()) + continue; + + int side = shape.getGeometryUserIndex( + cutHandles.get(icutIndex), sideIndex); + if (side == 2) + left.add((MultiPath) cutGeometry, false); + else if (side == 1) + right.add((MultiPath) cutGeometry, false); + else + m_cuts.add((MultiPath) cutGeometry); // Undefined + } + + { + // difference + EditShape shapeDifference = new EditShape(); + int geometryA = shapeDifference + .addGeometry(cutteeRemainder); + int geometryB = shapeDifference.addGeometry(shape + .getGeometry(cutHandles.get(icutIndex))); + topoOp.setEditShape(shapeDifference, m_progressTracker); + cutteeRemainder = (Polygon) shapeDifference + .getGeometry(topoOp + .difference(geometryA, geometryB)); + } + } + + if (!cutteeRemainder.isEmpty() && cutHandles.size() > 0) + m_cuts.add((MultiPath) cutteeRemainder); + + if (left.isEmpty() && right.isEmpty()) + m_cuts.clear(); // no cuts + + } finally { + topoOp.removeShape(); + } + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorCutLocal.java b/src/main/java/com/esri/core/geometry/OperatorCutLocal.java index 374780cd..4ce3795a 100644 --- a/src/main/java/com/esri/core/geometry/OperatorCutLocal.java +++ b/src/main/java/com/esri/core/geometry/OperatorCutLocal.java @@ -25,69 +25,69 @@ package com.esri.core.geometry; class OperatorCutLocal extends OperatorCut { - public static interface Side { - public static final int Left = 0; - public static final int Right = 1; - public static final int Coincident = 2; - public static final int Undefined = 3; - public static final int Uncut = 4; - } + public static interface Side { + public static final int Left = 0; + public static final int Right = 1; + public static final int Coincident = 2; + public static final int Undefined = 3; + public static final int Uncut = 4; + } - public static class CutPair { - public CutPair(Geometry geometry, int side, int ipartCuttee, - int ivertexCuttee, double scalarCuttee, int sidePrev, - int ipartCutteePrev, int ivertexCutteePrev, - double scalarCutteePrev, int ipartCutter, int ivertexCutter, - double scalarCutter, int ipartCutterPrev, - int ivertexCutterPrev, double scalarCutterPrev) { - m_geometry = geometry; - m_side = side; - m_ipartCuttee = ipartCuttee; - m_ivertexCuttee = ivertexCuttee; - m_scalarCuttee = scalarCuttee; - m_sidePrev = sidePrev; - m_ipartCutteePrev = ipartCutteePrev; - m_ivertexCutteePrev = ivertexCutteePrev; - m_scalarCutteePrev = scalarCutteePrev; - m_ipartCutter = ipartCutter; - m_ivertexCutter = ivertexCutter; - m_scalarCutter = scalarCutter; - m_ipartCutterPrev = ipartCutterPrev; - m_ivertexCutterPrev = ivertexCutterPrev; - m_scalarCutterPrev = scalarCutterPrev; - } + public static class CutPair { + public CutPair(Geometry geometry, int side, int ipartCuttee, + int ivertexCuttee, double scalarCuttee, int sidePrev, + int ipartCutteePrev, int ivertexCutteePrev, + double scalarCutteePrev, int ipartCutter, int ivertexCutter, + double scalarCutter, int ipartCutterPrev, + int ivertexCutterPrev, double scalarCutterPrev) { + m_geometry = geometry; + m_side = side; + m_ipartCuttee = ipartCuttee; + m_ivertexCuttee = ivertexCuttee; + m_scalarCuttee = scalarCuttee; + m_sidePrev = sidePrev; + m_ipartCutteePrev = ipartCutteePrev; + m_ivertexCutteePrev = ivertexCutteePrev; + m_scalarCutteePrev = scalarCutteePrev; + m_ipartCutter = ipartCutter; + m_ivertexCutter = ivertexCutter; + m_scalarCutter = scalarCutter; + m_ipartCutterPrev = ipartCutterPrev; + m_ivertexCutterPrev = ivertexCutterPrev; + m_scalarCutterPrev = scalarCutterPrev; + } - Geometry m_geometry; - int m_side; - int m_ipartCuttee; - int m_ivertexCuttee; - double m_scalarCuttee; - int m_sidePrev; - int m_ipartCutteePrev; - int m_ivertexCutteePrev; - double m_scalarCutteePrev; - int m_ipartCutter; - int m_ivertexCutter; - double m_scalarCutter; - int m_ipartCutterPrev; - int m_ivertexCutterPrev; - double m_scalarCutterPrev; - } + Geometry m_geometry; + int m_side; + int m_ipartCuttee; + int m_ivertexCuttee; + double m_scalarCuttee; + int m_sidePrev; + int m_ipartCutteePrev; + int m_ivertexCutteePrev; + double m_scalarCutteePrev; + int m_ipartCutter; + int m_ivertexCutter; + double m_scalarCutter; + int m_ipartCutterPrev; + int m_ivertexCutterPrev; + double m_scalarCutterPrev; + } - ; + ; - @Override - public GeometryCursor execute(boolean bConsiderTouch, Geometry cuttee, - Polyline cutter, SpatialReference spatialReference, - ProgressTracker progressTracker) { - SimpleGeometryCursor simpleGeometryCursor = new SimpleGeometryCursor(cuttee); - return new OperatorCutCursor(bConsiderTouch, simpleGeometryCursor, cutter, - spatialReference, progressTracker); - } + @Override + public GeometryCursor execute(boolean bConsiderTouch, Geometry cuttee, + Polyline cutter, SpatialReference spatialReference, + ProgressTracker progressTracker) { + SimpleGeometryCursor simpleGeometryCursor = new SimpleGeometryCursor(cuttee); + return new OperatorCutCursor(bConsiderTouch, simpleGeometryCursor, cutter, + spatialReference, progressTracker); + } - @Override - public GeometryCursor execute(boolean bConsiderTouch, GeometryCursor cuttees, Polyline cutter, SpatialReference spatialReference, ProgressTracker progressTracker) { - return new OperatorCutCursor(bConsiderTouch, cuttees, cutter, - spatialReference, progressTracker); - } + @Override + public GeometryCursor execute(boolean bConsiderTouch, GeometryCursor cuttees, Polyline cutter, SpatialReference spatialReference, ProgressTracker progressTracker) { + return new OperatorCutCursor(bConsiderTouch, cuttees, cutter, + spatialReference, progressTracker); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorDensifyByLength.java b/src/main/java/com/esri/core/geometry/OperatorDensifyByLength.java index a64111f2..ff37e27c 100644 --- a/src/main/java/com/esri/core/geometry/OperatorDensifyByLength.java +++ b/src/main/java/com/esri/core/geometry/OperatorDensifyByLength.java @@ -31,50 +31,46 @@ * given threshold value. */ public abstract class OperatorDensifyByLength extends Operator { - @Override - public Type getType() { - return Type.DensifyByLength; - } + @Override + public Type getType() { + return Type.DensifyByLength; + } /** * Performs the Densify operation on the geometry set. - * - * @param inputGeometries - * The geometries to be densified. - * @param maxLength - * The maximum segment length allowed. Must be a positive value. - * Curves are densified to straight segments using the - * maxSegmentLength. Curves are split into shorter subcurves such - * that the length of subcurves is shorter than maxSegmentLength. - * After that the curves are replaced with straight segments. + * + * @param inputGeometries The geometries to be densified. + * @param maxLength The maximum segment length allowed. Must be a positive value. + * Curves are densified to straight segments using the + * maxSegmentLength. Curves are split into shorter subcurves such + * that the length of subcurves is shorter than maxSegmentLength. + * After that the curves are replaced with straight segments. * @param progressTracker * @return Returns the densified geometries (It does nothing to geometries - * with dim < 1, but simply passes them along). + * with dim < 1, but simply passes them along). */ public abstract GeometryCursor execute(GeometryCursor inputGeometries, - double maxLength, ProgressTracker progressTracker); + double maxLength, ProgressTracker progressTracker); - /** - * Performs the Densify operation on the geometry set. - * - * @param inputGeometry - * The geometry to be densified. - * @param maxLength - * The maximum segment length allowed. Must be a positive value. - * Curves are densified to straight segments using the - * maxSegmentLength. Curves are split into shorter subcurves such - * that the length of subcurves is shorter than maxSegmentLength. - * After that the curves are replaced with straight segments. - * @param progressTracker - * @return Returns the densified geometry. (It does nothing to geometries - * with dim < 1, but simply passes them along). - */ - public abstract Geometry execute(Geometry inputGeometry, double maxLength, - ProgressTracker progressTracker); + /** + * Performs the Densify operation on the geometry set. + * + * @param inputGeometry The geometry to be densified. + * @param maxLength The maximum segment length allowed. Must be a positive value. + * Curves are densified to straight segments using the + * maxSegmentLength. Curves are split into shorter subcurves such + * that the length of subcurves is shorter than maxSegmentLength. + * After that the curves are replaced with straight segments. + * @param progressTracker + * @return Returns the densified geometry. (It does nothing to geometries + * with dim < 1, but simply passes them along). + */ + public abstract Geometry execute(Geometry inputGeometry, double maxLength, + ProgressTracker progressTracker); - public static OperatorDensifyByLength local() { - return (OperatorDensifyByLength) OperatorFactoryLocal.getInstance() - .getOperator(Type.DensifyByLength); - } + public static OperatorDensifyByLength local() { + return (OperatorDensifyByLength) OperatorFactoryLocal.getInstance() + .getOperator(Type.DensifyByLength); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorDensifyByLengthCursor.java b/src/main/java/com/esri/core/geometry/OperatorDensifyByLengthCursor.java index e70439bd..22a1e151 100644 --- a/src/main/java/com/esri/core/geometry/OperatorDensifyByLengthCursor.java +++ b/src/main/java/com/esri/core/geometry/OperatorDensifyByLengthCursor.java @@ -25,124 +25,124 @@ package com.esri.core.geometry; class OperatorDensifyByLengthCursor extends GeometryCursor { - double m_maxLength; - - public OperatorDensifyByLengthCursor(GeometryCursor inputGeoms, - double maxLength, ProgressTracker progressTracker) { - m_inputGeoms = inputGeoms; - m_maxLength = maxLength; - } - - @Override - public Geometry next() { - if (hasNext()) { - return densifyByLength(m_inputGeoms.next()); - } - return null; - } - - private Geometry densifyByLength(Geometry geom) { - if (geom.isEmpty() || geom.getDimension() < 1) - return geom; - - int geometryType = geom.getType().value(); - - // TODO implement IsMultiPath and remove Polygon and Polyline call to - // match Native - // if (Geometry.IsMultiPath(geometryType)) - if (geometryType == Geometry.GeometryType.Polygon) - return densifyMultiPath((MultiPath) geom); - else if (Geometry.GeometryType.Polyline == geometryType) - return densifyMultiPath((MultiPath) geom); - else if (Geometry.isSegment(geometryType)) - return densifySegment((Segment) geom); - else if (geometryType == Geometry.GeometryType.Envelope) - return densifyEnvelope((Envelope) geom); - else - // TODO fix geometry exception to match native implementation - throw GeometryException.GeometryInternalError();// GEOMTHROW(internal_error); - - // unreachable in java - // return null; - } - - private Geometry densifySegment(Segment geom) { - double length = geom.calculateLength2D(); - if (length <= m_maxLength) - return (Geometry) geom; - - Polyline polyline = new Polyline(geom.getDescription()); - polyline.addSegment(geom, true); - return densifyMultiPath((MultiPath) polyline); - } - - private Geometry densifyEnvelope(Envelope geom) { - Polygon polygon = new Polygon(geom.getDescription()); - polygon.addEnvelope(geom, false); - - Envelope2D env2D = new Envelope2D(); - geom.queryEnvelope2D(env2D); - double w = env2D.getWidth(); - double h = env2D.getHeight(); - if (w <= m_maxLength && h <= m_maxLength) - return (Geometry) polygon; - - return densifyMultiPath((MultiPath) polygon); - } - - private Geometry densifyMultiPath(MultiPath geom) { - MultiPath densifiedPoly = (MultiPath) geom.createInstance(); - SegmentIterator iter = geom.querySegmentIterator(); - while (iter.nextPath()) { - boolean bStartNewPath = true; - while (iter.hasNextSegment()) { - Segment seg = iter.nextSegment(); - if (seg.getType().value() != Geometry.GeometryType.Line) - throw new GeometryException("not implemented"); - - boolean bIsClosing = iter.isClosingSegment(); - - double len = seg.calculateLength2D(); - if (len > m_maxLength) {// need to split - double dcount = Math.ceil(len / m_maxLength); - - Point point = new Point(geom.getDescription());// LOCALREFCLASS1(Point, - // VertexDescription, - // point, - // geom.getDescription()); - if (bStartNewPath) { - bStartNewPath = false; - seg.queryStart(point); - densifiedPoly.startPath(point); - } - double dt = 1.0 / dcount; - double t = dt; - for (int i = 0, n = (int) dcount - 1; i < n; i++) { - seg.queryCoord(t, point); - densifiedPoly.lineTo(point); - t += dt; - } - - if (!bIsClosing) { - seg.queryEnd(point); - densifiedPoly.lineTo(point); - } else { - densifiedPoly.closePathWithLine(); - } - - bStartNewPath = false; - } else { - if (!bIsClosing) - densifiedPoly.addSegment(seg, bStartNewPath); - else - densifiedPoly.closePathWithLine(); - - bStartNewPath = false; - } - } - } - - return densifiedPoly; - } + double m_maxLength; + + public OperatorDensifyByLengthCursor(GeometryCursor inputGeoms, + double maxLength, ProgressTracker progressTracker) { + m_inputGeoms = inputGeoms; + m_maxLength = maxLength; + } + + @Override + public Geometry next() { + if (hasNext()) { + return densifyByLength(m_inputGeoms.next()); + } + return null; + } + + private Geometry densifyByLength(Geometry geom) { + if (geom.isEmpty() || geom.getDimension() < 1) + return geom; + + int geometryType = geom.getType().value(); + + // TODO implement IsMultiPath and remove Polygon and Polyline call to + // match Native + // if (Geometry.IsMultiPath(geometryType)) + if (geometryType == Geometry.GeometryType.Polygon) + return densifyMultiPath((MultiPath) geom); + else if (Geometry.GeometryType.Polyline == geometryType) + return densifyMultiPath((MultiPath) geom); + else if (Geometry.isSegment(geometryType)) + return densifySegment((Segment) geom); + else if (geometryType == Geometry.GeometryType.Envelope) + return densifyEnvelope((Envelope) geom); + else + // TODO fix geometry exception to match native implementation + throw GeometryException.GeometryInternalError();// GEOMTHROW(internal_error); + + // unreachable in java + // return null; + } + + private Geometry densifySegment(Segment geom) { + double length = geom.calculateLength2D(); + if (length <= m_maxLength) + return (Geometry) geom; + + Polyline polyline = new Polyline(geom.getDescription()); + polyline.addSegment(geom, true); + return densifyMultiPath((MultiPath) polyline); + } + + private Geometry densifyEnvelope(Envelope geom) { + Polygon polygon = new Polygon(geom.getDescription()); + polygon.addEnvelope(geom, false); + + Envelope2D env2D = new Envelope2D(); + geom.queryEnvelope2D(env2D); + double w = env2D.getWidth(); + double h = env2D.getHeight(); + if (w <= m_maxLength && h <= m_maxLength) + return (Geometry) polygon; + + return densifyMultiPath((MultiPath) polygon); + } + + private Geometry densifyMultiPath(MultiPath geom) { + MultiPath densifiedPoly = (MultiPath) geom.createInstance(); + SegmentIterator iter = geom.querySegmentIterator(); + while (iter.nextPath()) { + boolean bStartNewPath = true; + while (iter.hasNextSegment()) { + Segment seg = iter.nextSegment(); + if (seg.getType().value() != Geometry.GeometryType.Line) + throw new GeometryException("not implemented"); + + boolean bIsClosing = iter.isClosingSegment(); + + double len = seg.calculateLength2D(); + if (len > m_maxLength) {// need to split + double dcount = Math.ceil(len / m_maxLength); + + Point point = new Point(geom.getDescription());// LOCALREFCLASS1(Point, + // VertexDescription, + // point, + // geom.getDescription()); + if (bStartNewPath) { + bStartNewPath = false; + seg.queryStart(point); + densifiedPoly.startPath(point); + } + double dt = 1.0 / dcount; + double t = dt; + for (int i = 0, n = (int) dcount - 1; i < n; i++) { + seg.queryCoord(t, point); + densifiedPoly.lineTo(point); + t += dt; + } + + if (!bIsClosing) { + seg.queryEnd(point); + densifiedPoly.lineTo(point); + } else { + densifiedPoly.closePathWithLine(); + } + + bStartNewPath = false; + } else { + if (!bIsClosing) + densifiedPoly.addSegment(seg, bStartNewPath); + else + densifiedPoly.closePathWithLine(); + + bStartNewPath = false; + } + } + } + + return densifiedPoly; + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorDensifyByLengthLocal.java b/src/main/java/com/esri/core/geometry/OperatorDensifyByLengthLocal.java index 083edfd0..22350f6b 100644 --- a/src/main/java/com/esri/core/geometry/OperatorDensifyByLengthLocal.java +++ b/src/main/java/com/esri/core/geometry/OperatorDensifyByLengthLocal.java @@ -25,26 +25,26 @@ class OperatorDensifyByLengthLocal extends OperatorDensifyByLength { - @Override - public GeometryCursor execute( - GeometryCursor inputGeometries, - double maxLength, - ProgressTracker progressTracker) { - if (maxLength <= 0) - // TODO fix geometry exception to match native implementation - throw new IllegalArgumentException();// GEOMTHROW(invalid_argument); - - return new OperatorDensifyByLengthCursor(inputGeometries, maxLength, - progressTracker); - } - - @Override - public Geometry execute(Geometry inputGeometry, double maxLength, - ProgressTracker progressTracker) { - SimpleGeometryCursor inputCursor = new SimpleGeometryCursor( - inputGeometry); - GeometryCursor outputCursor = execute(inputCursor, maxLength, - progressTracker); - return outputCursor.next(); - } + @Override + public GeometryCursor execute( + GeometryCursor inputGeometries, + double maxLength, + ProgressTracker progressTracker) { + if (maxLength <= 0) + // TODO fix geometry exception to match native implementation + throw new IllegalArgumentException();// GEOMTHROW(invalid_argument); + + return new OperatorDensifyByLengthCursor(inputGeometries, maxLength, + progressTracker); + } + + @Override + public Geometry execute(Geometry inputGeometry, double maxLength, + ProgressTracker progressTracker) { + SimpleGeometryCursor inputCursor = new SimpleGeometryCursor( + inputGeometry); + GeometryCursor outputCursor = execute(inputCursor, maxLength, + progressTracker); + return outputCursor.next(); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorDifference.java b/src/main/java/com/esri/core/geometry/OperatorDifference.java index ce71cb72..e22fb2a8 100644 --- a/src/main/java/com/esri/core/geometry/OperatorDifference.java +++ b/src/main/java/com/esri/core/geometry/OperatorDifference.java @@ -31,41 +31,41 @@ */ public abstract class OperatorDifference extends Operator implements CombineOperator { - @Override - public Type getType() { - return Type.Difference; - } + @Override + public Type getType() { + return Type.Difference; + } - /** - * Performs the Topological Difference operation on the geometry set. - * - * @param inputGeometries is the set of Geometry instances to be subtracted by the - * subtractor - * @param subtractor is the Geometry being subtracted. - * @return Returns the result of the subtraction. - *

- * The operator subtracts subtractor from every geometry in - * inputGeometries. - */ - public abstract GeometryCursor execute(GeometryCursor inputGeometries, - GeometryCursor subtractor, SpatialReference sr, - ProgressTracker progressTracker); + /** + * Performs the Topological Difference operation on the geometry set. + * + * @param inputGeometries is the set of Geometry instances to be subtracted by the + * subtractor + * @param subtractor is the Geometry being subtracted. + * @return Returns the result of the subtraction. + *

+ * The operator subtracts subtractor from every geometry in + * inputGeometries. + */ + public abstract GeometryCursor execute(GeometryCursor inputGeometries, + GeometryCursor subtractor, SpatialReference sr, + ProgressTracker progressTracker); - /** - * Performs the Topological Difference operation on the two geometries. - * - * @param inputGeometry is the Geometry instance on the left hand side of the - * subtraction. - * @param subtractor is the Geometry on the right hand side being subtracted. - * @return Returns the result of subtraction. - */ - public abstract Geometry execute(Geometry inputGeometry, - Geometry subtractor, SpatialReference sr, - ProgressTracker progressTracker); + /** + * Performs the Topological Difference operation on the two geometries. + * + * @param inputGeometry is the Geometry instance on the left hand side of the + * subtraction. + * @param subtractor is the Geometry on the right hand side being subtracted. + * @return Returns the result of subtraction. + */ + public abstract Geometry execute(Geometry inputGeometry, + Geometry subtractor, SpatialReference sr, + ProgressTracker progressTracker); - public static OperatorDifference local() { - return (OperatorDifference) OperatorFactoryLocal.getInstance() - .getOperator(Type.Difference); - } + public static OperatorDifference local() { + return (OperatorDifference) OperatorFactoryLocal.getInstance() + .getOperator(Type.Difference); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorDifferenceCursor.java b/src/main/java/com/esri/core/geometry/OperatorDifferenceCursor.java index a71dffbc..a75bb6dd 100644 --- a/src/main/java/com/esri/core/geometry/OperatorDifferenceCursor.java +++ b/src/main/java/com/esri/core/geometry/OperatorDifferenceCursor.java @@ -25,33 +25,33 @@ package com.esri.core.geometry; class OperatorDifferenceCursor extends GeometryCursor { - ProgressTracker m_progress_tracker; - SpatialReference m_Spatial_reference; - Geometry m_geomSubtractor; - boolean m_bEmpty; - - OperatorDifferenceCursor(GeometryCursor inputGeoms, - GeometryCursor geomSubtractor, SpatialReference sr, - ProgressTracker progress_tracker) { - m_bEmpty = (geomSubtractor == null); - m_inputGeoms = inputGeoms; - m_Spatial_reference = sr; - m_geomSubtractor = geomSubtractor.next(); - m_progress_tracker = progress_tracker; - } - - @Override - public Geometry next() { - if (m_bEmpty) - return null; - - if (hasNext()) { - return OperatorDifferenceLocal.difference( - m_inputGeoms.next(), - m_geomSubtractor, - m_Spatial_reference, - m_progress_tracker); - } - return null; - } + ProgressTracker m_progress_tracker; + SpatialReference m_Spatial_reference; + Geometry m_geomSubtractor; + boolean m_bEmpty; + + OperatorDifferenceCursor(GeometryCursor inputGeoms, + GeometryCursor geomSubtractor, SpatialReference sr, + ProgressTracker progress_tracker) { + m_bEmpty = (geomSubtractor == null); + m_inputGeoms = inputGeoms; + m_Spatial_reference = sr; + m_geomSubtractor = geomSubtractor.next(); + m_progress_tracker = progress_tracker; + } + + @Override + public Geometry next() { + if (m_bEmpty) + return null; + + if (hasNext()) { + return OperatorDifferenceLocal.difference( + m_inputGeoms.next(), + m_geomSubtractor, + m_Spatial_reference, + m_progress_tracker); + } + return null; + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorDifferenceLocal.java b/src/main/java/com/esri/core/geometry/OperatorDifferenceLocal.java index cd1b3b3f..31db5027 100644 --- a/src/main/java/com/esri/core/geometry/OperatorDifferenceLocal.java +++ b/src/main/java/com/esri/core/geometry/OperatorDifferenceLocal.java @@ -26,367 +26,332 @@ class OperatorDifferenceLocal extends OperatorDifference { - @Override - public GeometryCursor execute(GeometryCursor inputGeometries, - GeometryCursor subtractor, SpatialReference sr, - ProgressTracker progressTracker) { - return new OperatorDifferenceCursor(inputGeometries, subtractor, sr, - progressTracker); - } - - @Override - public Geometry execute(Geometry inputGeometry, Geometry subtractor, - SpatialReference sr, ProgressTracker progressTracker) { - SimpleGeometryCursor inputGeomCurs = new SimpleGeometryCursor( - inputGeometry); - SimpleGeometryCursor subractorCurs = new SimpleGeometryCursor( - subtractor); - GeometryCursor geometryCursor = execute(inputGeomCurs, subractorCurs, - sr, progressTracker); - - return geometryCursor.next(); - } - - static Geometry difference(Geometry geometry_a, Geometry geometry_b, - SpatialReference spatial_reference, ProgressTracker progress_tracker) { - if (geometry_a.isEmpty() || geometry_b.isEmpty()) - return geometry_a; - - int dimension_a = geometry_a.getDimension(); - int dimension_b = geometry_b.getDimension(); - - if (dimension_a > dimension_b) - return geometry_a; - - int type_a = geometry_a.getType().value(); - int type_b = geometry_b.getType().value(); - - Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(), env_merged = new Envelope2D(); - geometry_a.queryEnvelope2D(env_a); - geometry_b.queryEnvelope2D(env_b); - env_merged.setCoords(env_a); - env_merged.merge(env_b); - - double tolerance = InternalUtils.calculateToleranceFromGeometry( - spatial_reference, env_merged, false); - double tolerance_cluster = tolerance * Math.sqrt(2.0) * 1.00001; - - Envelope2D env_a_inflated = new Envelope2D(); - env_a_inflated.setCoords(env_a); - env_a_inflated.inflate(tolerance_cluster, tolerance_cluster); // inflate - // by - // cluster - // tolerance - - if (!env_a_inflated.isIntersecting(env_b)) - return geometry_a; - - if (dimension_a == 1 && dimension_b == 2) - return polylineMinusArea_(geometry_a, geometry_b, type_b, - spatial_reference, progress_tracker); - - if (type_a == Geometry.GeometryType.Point) { - Geometry geometry_b_; - if (MultiPath.isSegment(type_b)) { - geometry_b_ = new Polyline(geometry_b.getDescription()); - ((Polyline) (geometry_b_)).addSegment((Segment) (geometry_b), - true); - } else { - geometry_b_ = geometry_b; - } - switch (type_b) { - case Geometry.GeometryType.Polygon: - return pointMinusPolygon_((Point) (geometry_a), - (Polygon) (geometry_b_), tolerance, progress_tracker); - case Geometry.GeometryType.Polyline: - return pointMinusPolyline_((Point) (geometry_a), - (Polyline) (geometry_b_), tolerance, progress_tracker); - case Geometry.GeometryType.MultiPoint: - return pointMinusMultiPoint_((Point) (geometry_a), - (MultiPoint) (geometry_b_), tolerance, progress_tracker); - case Geometry.GeometryType.Envelope: - return pointMinusEnvelope_((Point) (geometry_a), - (Envelope) (geometry_b_), tolerance, progress_tracker); - case Geometry.GeometryType.Point: - return pointMinusPoint_((Point) (geometry_a), - (Point) (geometry_b_), tolerance, progress_tracker); - default: - throw new IllegalArgumentException(); - } - } else if (type_a == Geometry.GeometryType.MultiPoint) { - switch (type_b) { - case Geometry.GeometryType.Polygon: - return multiPointMinusPolygon_((MultiPoint) (geometry_a), - (Polygon) (geometry_b), tolerance, progress_tracker); - case Geometry.GeometryType.Envelope: - return multiPointMinusEnvelope_((MultiPoint) (geometry_a), - (Envelope) (geometry_b), tolerance, progress_tracker); - case Geometry.GeometryType.Point: - return multiPointMinusPoint_((MultiPoint) (geometry_a), - (Point) (geometry_b), tolerance, progress_tracker); - default: - break; - } - } - return TopologicalOperations.difference(geometry_a, geometry_b, - spatial_reference, progress_tracker); - } - - // these are special implementations, all others delegate to the topo-graph. - static Geometry pointMinusPolygon_(Point point, Polygon polygon, - double tolerance, ProgressTracker progress_tracker) { - PolygonUtils.PiPResult result = PolygonUtils.isPointInPolygon2D( - polygon, point, tolerance); - - if (result == PolygonUtils.PiPResult.PiPOutside) - return point; - - return point.createInstance(); - } - - static Geometry pointMinusPolyline_(Point point, Polyline polyline, - double tolerance, ProgressTracker progress_tracker) { - Point2D pt = point.getXY(); - SegmentIterator seg_iter = polyline.querySegmentIterator(); - - double tolerance_cluster = tolerance * Math.sqrt(2.0) * 1.00001; - double tolerance_cluster_sq = tolerance_cluster * tolerance_cluster; - Envelope2D env = new Envelope2D(); - - while (seg_iter.nextPath()) { - while (seg_iter.hasNextSegment()) { - Segment segment = seg_iter.nextSegment(); - - segment.queryEnvelope2D(env); - env.inflate(tolerance_cluster, tolerance_cluster); - - if (!env.contains(pt)) - continue; - - if (segment.isIntersecting(pt, tolerance)) - return point.createInstance(); - - // check segment end points to the cluster tolerance - Point2D end_point = segment.getStartXY(); - - if (Point2D.sqrDistance(pt, end_point) <= tolerance_cluster_sq) - return point.createInstance(); - - end_point = segment.getEndXY(); - - if (Point2D.sqrDistance(pt, end_point) <= tolerance_cluster_sq) - return point.createInstance(); - } - } - - return point; - } - - static Geometry pointMinusMultiPoint_(Point point, MultiPoint multi_point, - double tolerance, ProgressTracker progress_tracker) { - MultiPointImpl multipointImpl = (MultiPointImpl) (multi_point - ._getImpl()); - AttributeStreamOfDbl position = (AttributeStreamOfDbl) multipointImpl - .getAttributeStreamRef(VertexDescription.Semantics.POSITION); - int point_count = multi_point.getPointCount(); - Point2D point2D = point.getXY(); - Point2D pt = new Point2D(); - - double tolerance_cluster = tolerance * Math.sqrt(2.0) * 1.00001; - double tolerance_cluster_sq = tolerance_cluster * tolerance_cluster; - - for (int i = 0; i < point_count; i++) { - position.read(2 * i, pt); - double sqr_dist = Point2D.sqrDistance(pt, point2D); - if (sqr_dist <= tolerance_cluster_sq) - return point.createInstance();// return an empty point. - } - - return point;// return the input point - } - - static Geometry pointMinusEnvelope_(Point point, Envelope envelope, - double tolerance, ProgressTracker progress_tracker) { - Envelope2D env = new Envelope2D(); - envelope.queryEnvelope2D(env); - env.inflate(tolerance, tolerance); - - Point2D pt = point.getXY(); + @Override + public GeometryCursor execute(GeometryCursor inputGeometries, + GeometryCursor subtractor, SpatialReference sr, + ProgressTracker progressTracker) { + return new OperatorDifferenceCursor(inputGeometries, subtractor, sr, + progressTracker); + } + + @Override + public Geometry execute(Geometry inputGeometry, Geometry subtractor, + SpatialReference sr, ProgressTracker progressTracker) { + SimpleGeometryCursor inputGeomCurs = new SimpleGeometryCursor( + inputGeometry); + SimpleGeometryCursor subractorCurs = new SimpleGeometryCursor( + subtractor); + GeometryCursor geometryCursor = execute(inputGeomCurs, subractorCurs, + sr, progressTracker); + + return geometryCursor.next(); + } + + static Geometry difference(Geometry geometry_a, Geometry geometry_b, + SpatialReference spatial_reference, ProgressTracker progress_tracker) { + if (geometry_a.isEmpty() || geometry_b.isEmpty()) + return geometry_a; + + int dimension_a = geometry_a.getDimension(); + int dimension_b = geometry_b.getDimension(); + + if (dimension_a > dimension_b) + return geometry_a; + + int type_a = geometry_a.getType().value(); + int type_b = geometry_b.getType().value(); + + Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(), env_merged = new Envelope2D(); + geometry_a.queryEnvelope2D(env_a); + geometry_b.queryEnvelope2D(env_b); + env_merged.setCoords(env_a); + env_merged.merge(env_b); + + double tolerance = InternalUtils.calculateToleranceFromGeometry( + spatial_reference, env_merged, false); + double tolerance_cluster = tolerance * Math.sqrt(2.0) * 1.00001; + + Envelope2D env_a_inflated = new Envelope2D(); + env_a_inflated.setCoords(env_a); + env_a_inflated.inflate(tolerance_cluster, tolerance_cluster); // inflate + // by + // cluster + // tolerance + + if (!env_a_inflated.isIntersecting(env_b)) + return geometry_a; + + if (type_a == Geometry.GeometryType.Point) { + Geometry geometry_b_; + if (MultiPath.isSegment(type_b)) { + geometry_b_ = new Polyline(geometry_b.getDescription()); + ((Polyline) (geometry_b_)).addSegment((Segment) (geometry_b), + true); + } else { + geometry_b_ = geometry_b; + } + switch (type_b) { + case Geometry.GeometryType.Polygon: + return pointMinusPolygon_((Point) (geometry_a), + (Polygon) (geometry_b_), tolerance, progress_tracker); + case Geometry.GeometryType.Polyline: + return pointMinusPolyline_((Point) (geometry_a), + (Polyline) (geometry_b_), tolerance, progress_tracker); + case Geometry.GeometryType.MultiPoint: + return pointMinusMultiPoint_((Point) (geometry_a), + (MultiPoint) (geometry_b_), tolerance, progress_tracker); + case Geometry.GeometryType.Envelope: + return pointMinusEnvelope_((Point) (geometry_a), + (Envelope) (geometry_b_), tolerance, progress_tracker); + case Geometry.GeometryType.Point: + return pointMinusPoint_((Point) (geometry_a), + (Point) (geometry_b_), tolerance, progress_tracker); + default: + throw new IllegalArgumentException(); + } + } else if (type_a == Geometry.GeometryType.MultiPoint) { + switch (type_b) { + case Geometry.GeometryType.Polygon: + return multiPointMinusPolygon_((MultiPoint) (geometry_a), + (Polygon) (geometry_b), tolerance, progress_tracker); + case Geometry.GeometryType.Envelope: + return multiPointMinusEnvelope_((MultiPoint) (geometry_a), + (Envelope) (geometry_b), tolerance, progress_tracker); + case Geometry.GeometryType.Point: + return multiPointMinusPoint_((MultiPoint) (geometry_a), + (Point) (geometry_b), tolerance, progress_tracker); + default: + break; + } + } + return TopologicalOperations.difference(geometry_a, geometry_b, + spatial_reference, progress_tracker); + } + + // these are special implementations, all others delegate to the topo-graph. + static Geometry pointMinusPolygon_(Point point, Polygon polygon, + double tolerance, ProgressTracker progress_tracker) { + PolygonUtils.PiPResult result = PolygonUtils.isPointInPolygon2D( + polygon, point, tolerance); + + if (result == PolygonUtils.PiPResult.PiPOutside) + return point; + + return point.createInstance(); + } + + static Geometry pointMinusPolyline_(Point point, Polyline polyline, + double tolerance, ProgressTracker progress_tracker) { + Point2D pt = point.getXY(); + SegmentIterator seg_iter = polyline.querySegmentIterator(); + + double tolerance_cluster = tolerance * Math.sqrt(2.0) * 1.00001; + double tolerance_cluster_sq = tolerance_cluster * tolerance_cluster; + Envelope2D env = new Envelope2D(); + + while (seg_iter.nextPath()) { + while (seg_iter.hasNextSegment()) { + Segment segment = seg_iter.nextSegment(); + + segment.queryEnvelope2D(env); + env.inflate(tolerance_cluster, tolerance_cluster); + + if (!env.contains(pt)) + continue; + + if (segment.isIntersecting(pt, tolerance)) + return point.createInstance(); + + // check segment end points to the cluster tolerance + Point2D end_point = segment.getStartXY(); + + if (Point2D.sqrDistance(pt, end_point) <= tolerance_cluster_sq) + return point.createInstance(); + + end_point = segment.getEndXY(); + + if (Point2D.sqrDistance(pt, end_point) <= tolerance_cluster_sq) + return point.createInstance(); + } + } + + return point; + } + + static Geometry pointMinusMultiPoint_(Point point, MultiPoint multi_point, + double tolerance, ProgressTracker progress_tracker) { + MultiPointImpl multipointImpl = (MultiPointImpl) (multi_point + ._getImpl()); + AttributeStreamOfDbl position = (AttributeStreamOfDbl) multipointImpl + .getAttributeStreamRef(VertexDescription.Semantics.POSITION); + int point_count = multi_point.getPointCount(); + Point2D point2D = point.getXY(); + Point2D pt = new Point2D(); + + double tolerance_cluster = tolerance * Math.sqrt(2.0) * 1.00001; + double tolerance_cluster_sq = tolerance_cluster * tolerance_cluster; + + for (int i = 0; i < point_count; i++) { + position.read(2 * i, pt); + double sqr_dist = Point2D.sqrDistance(pt, point2D); + if (sqr_dist <= tolerance_cluster_sq) + return point.createInstance();// return an empty point. + } + + return point;// return the input point + } + + static Geometry pointMinusEnvelope_(Point point, Envelope envelope, + double tolerance, ProgressTracker progress_tracker) { + Envelope2D env = new Envelope2D(); + envelope.queryEnvelope2D(env); + env.inflate(tolerance, tolerance); + + Point2D pt = point.getXY(); - if (!env.contains(pt)) - return point; + if (!env.contains(pt)) + return point; - return point.createInstance(); - } + return point.createInstance(); + } - static Geometry pointMinusPoint_(Point point_a, Point point_b, - double tolerance, ProgressTracker progress_tracker) { - double tolerance_cluster = tolerance * Math.sqrt(2.0) * 1.00001; - double tolerance_cluster_sq = tolerance_cluster * tolerance_cluster; + static Geometry pointMinusPoint_(Point point_a, Point point_b, + double tolerance, ProgressTracker progress_tracker) { + double tolerance_cluster = tolerance * Math.sqrt(2.0) * 1.00001; + double tolerance_cluster_sq = tolerance_cluster * tolerance_cluster; - Point2D pt_a = point_a.getXY(); - Point2D pt_b = point_b.getXY(); + Point2D pt_a = point_a.getXY(); + Point2D pt_b = point_b.getXY(); - if (Point2D.sqrDistance(pt_a, pt_b) <= tolerance_cluster_sq) - return point_a.createInstance(); // return empty point + if (Point2D.sqrDistance(pt_a, pt_b) <= tolerance_cluster_sq) + return point_a.createInstance(); // return empty point - return point_a; - } + return point_a; + } - static Geometry multiPointMinusPolygon_(MultiPoint multi_point, - Polygon polygon, double tolerance, ProgressTracker progress_tracker) { - Envelope2D env = new Envelope2D(); - polygon.queryEnvelope2D(env); - env.inflate(tolerance, tolerance); + static Geometry multiPointMinusPolygon_(MultiPoint multi_point, + Polygon polygon, double tolerance, ProgressTracker progress_tracker) { + Envelope2D env = new Envelope2D(); + polygon.queryEnvelope2D(env); + env.inflate(tolerance, tolerance); - int point_count = multi_point.getPointCount(); + int point_count = multi_point.getPointCount(); - boolean b_found_covered = false; - boolean[] covered = new boolean[point_count]; - for (int i = 0; i < point_count; i++) - covered[i] = false; + boolean b_found_covered = false; + boolean[] covered = new boolean[point_count]; + for (int i = 0; i < point_count; i++) + covered[i] = false; - Point2D pt = new Point2D(); + Point2D pt = new Point2D(); - for (int i = 0; i < point_count; i++) { - multi_point.getXY(i, pt); + for (int i = 0; i < point_count; i++) { + multi_point.getXY(i, pt); - if (!env.contains(pt)) - continue; + if (!env.contains(pt)) + continue; - PolygonUtils.PiPResult result = PolygonUtils.isPointInPolygon2D( - polygon, pt, tolerance); + PolygonUtils.PiPResult result = PolygonUtils.isPointInPolygon2D( + polygon, pt, tolerance); - if (result == PolygonUtils.PiPResult.PiPOutside) - continue; + if (result == PolygonUtils.PiPResult.PiPOutside) + continue; - b_found_covered = true; - covered[i] = true; - } + b_found_covered = true; + covered[i] = true; + } - if (!b_found_covered) - return multi_point; + if (!b_found_covered) + return multi_point; - MultiPoint new_multipoint = (MultiPoint) multi_point.createInstance(); + MultiPoint new_multipoint = (MultiPoint) multi_point.createInstance(); - for (int i = 0; i < point_count; i++) { - if (!covered[i]) - new_multipoint.add(multi_point, i, i + 1); - } + for (int i = 0; i < point_count; i++) { + if (!covered[i]) + new_multipoint.add(multi_point, i, i + 1); + } - return new_multipoint; - } + return new_multipoint; + } - static Geometry multiPointMinusEnvelope_(MultiPoint multi_point, - Envelope envelope, double tolerance, - ProgressTracker progress_tracker) { - Envelope2D env = new Envelope2D(); - envelope.queryEnvelope2D(env); - env.inflate(tolerance, tolerance); + static Geometry multiPointMinusEnvelope_(MultiPoint multi_point, + Envelope envelope, double tolerance, + ProgressTracker progress_tracker) { + Envelope2D env = new Envelope2D(); + envelope.queryEnvelope2D(env); + env.inflate(tolerance, tolerance); - int point_count = multi_point.getPointCount(); + int point_count = multi_point.getPointCount(); - boolean b_found_covered = false; - boolean[] covered = new boolean[point_count]; - for (int i = 0; i < point_count; i++) - covered[i] = false; + boolean b_found_covered = false; + boolean[] covered = new boolean[point_count]; + for (int i = 0; i < point_count; i++) + covered[i] = false; - Point2D pt = new Point2D(); + Point2D pt = new Point2D(); - for (int i = 0; i < point_count; i++) { - multi_point.getXY(i, pt); + for (int i = 0; i < point_count; i++) { + multi_point.getXY(i, pt); - if (!env.contains(pt)) - continue; + if (!env.contains(pt)) + continue; - b_found_covered = true; - covered[i] = true; - } + b_found_covered = true; + covered[i] = true; + } - if (!b_found_covered) - return multi_point; + if (!b_found_covered) + return multi_point; - MultiPoint new_multipoint = (MultiPoint) multi_point.createInstance(); + MultiPoint new_multipoint = (MultiPoint) multi_point.createInstance(); - for (int i = 0; i < point_count; i++) { - if (!covered[i]) - new_multipoint.add(multi_point, i, i + 1); - } + for (int i = 0; i < point_count; i++) { + if (!covered[i]) + new_multipoint.add(multi_point, i, i + 1); + } - return new_multipoint; - } + return new_multipoint; + } - static Geometry multiPointMinusPoint_(MultiPoint multi_point, Point point, - double tolerance, ProgressTracker progress_tracker) { - MultiPointImpl multipointImpl = (MultiPointImpl) (multi_point - ._getImpl()); - AttributeStreamOfDbl position = (AttributeStreamOfDbl) (multipointImpl - .getAttributeStreamRef(VertexDescription.Semantics.POSITION)); - int point_count = multi_point.getPointCount(); - Point2D point2D = point.getXY(); - Point2D pt = new Point2D(); + static Geometry multiPointMinusPoint_(MultiPoint multi_point, Point point, + double tolerance, ProgressTracker progress_tracker) { + MultiPointImpl multipointImpl = (MultiPointImpl) (multi_point + ._getImpl()); + AttributeStreamOfDbl position = (AttributeStreamOfDbl) (multipointImpl + .getAttributeStreamRef(VertexDescription.Semantics.POSITION)); + int point_count = multi_point.getPointCount(); + Point2D point2D = point.getXY(); + Point2D pt = new Point2D(); - boolean b_found_covered = false; - boolean[] covered = new boolean[point_count]; - for (int i = 0; i < point_count; i++) - covered[i] = false; + boolean b_found_covered = false; + boolean[] covered = new boolean[point_count]; + for (int i = 0; i < point_count; i++) + covered[i] = false; - double tolerance_cluster = tolerance * Math.sqrt(2.0) * 1.00001; - double tolerance_cluster_sq = tolerance_cluster * tolerance_cluster; + double tolerance_cluster = tolerance * Math.sqrt(2.0) * 1.00001; + double tolerance_cluster_sq = tolerance_cluster * tolerance_cluster; - for (int i = 0; i < point_count; i++) { - position.read(2 * i, pt); + for (int i = 0; i < point_count; i++) { + position.read(2 * i, pt); - double sqr_dist = Point2D.sqrDistance(pt, point2D); + double sqr_dist = Point2D.sqrDistance(pt, point2D); - if (sqr_dist <= tolerance_cluster_sq) { - b_found_covered = true; - covered[i] = true; - } - } + if (sqr_dist <= tolerance_cluster_sq) { + b_found_covered = true; + covered[i] = true; + } + } - if (!b_found_covered) - return multi_point; + if (!b_found_covered) + return multi_point; - MultiPoint new_multipoint = (MultiPoint) (multi_point.createInstance()); + MultiPoint new_multipoint = (MultiPoint) (multi_point.createInstance()); - for (int i = 0; i < point_count; i++) { - if (!covered[i]) - new_multipoint.add(multi_point, i, i + 1); - } - - return new_multipoint; - } - - static Geometry polylineMinusArea_(Geometry geometry, Geometry area, - int area_type, SpatialReference sr, ProgressTracker progress_tracker) { - // construct the complement of the Polygon (or Envelope) - Envelope envelope = new Envelope(); - geometry.queryEnvelope(envelope); - Envelope2D env_2D = new Envelope2D(); - area.queryEnvelope2D(env_2D); - envelope.merge(env_2D); - double dw = 0.1 * envelope.getWidth(); - double dh = 0.1 * envelope.getHeight(); - envelope.inflate(dw, dh); - - Polygon complement = new Polygon(); - complement.addEnvelope(envelope, false); - - MultiPathImpl complementImpl = (MultiPathImpl) (complement._getImpl()); - - if (area_type == Geometry.GeometryType.Polygon) { - MultiPathImpl polygonImpl = (MultiPathImpl) (area._getImpl()); - complementImpl.add(polygonImpl, true); - } else - complementImpl.addEnvelope((Envelope) (area), true); - - OperatorFactoryLocal projEnv = OperatorFactoryLocal.getInstance(); - OperatorIntersection operatorIntersection = (OperatorIntersection) projEnv - .getOperator(Operator.Type.Intersection); - Geometry difference = operatorIntersection.execute(geometry, - complement, sr, progress_tracker); - return difference; - } + for (int i = 0; i < point_count; i++) { + if (!covered[i]) + new_multipoint.add(multi_point, i, i + 1); + } + return new_multipoint; + } } + diff --git a/src/main/java/com/esri/core/geometry/OperatorDisjoint.java b/src/main/java/com/esri/core/geometry/OperatorDisjoint.java index 6c703f5f..9404759f 100644 --- a/src/main/java/com/esri/core/geometry/OperatorDisjoint.java +++ b/src/main/java/com/esri/core/geometry/OperatorDisjoint.java @@ -31,14 +31,14 @@ */ public abstract class OperatorDisjoint extends OperatorSimpleRelation { - @Override - public Type getType() { - return Type.Disjoint; - } - - public static OperatorDisjoint local() { - return (OperatorDisjoint) OperatorFactoryLocal.getInstance() - .getOperator(Type.Disjoint); - } + @Override + public Type getType() { + return Type.Disjoint; + } + + public static OperatorDisjoint local() { + return (OperatorDisjoint) OperatorFactoryLocal.getInstance() + .getOperator(Type.Disjoint); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorDisjointLocal.java b/src/main/java/com/esri/core/geometry/OperatorDisjointLocal.java index 3229d70e..6b2ab840 100644 --- a/src/main/java/com/esri/core/geometry/OperatorDisjointLocal.java +++ b/src/main/java/com/esri/core/geometry/OperatorDisjointLocal.java @@ -25,11 +25,11 @@ package com.esri.core.geometry; class OperatorDisjointLocal extends OperatorDisjoint { - @Override - public boolean execute(Geometry inputGeom1, Geometry inputGeom2, - SpatialReference sr, ProgressTracker progressTracker) { - return RelationalOperations.relate(inputGeom1, inputGeom2, sr, - RelationalOperations.Relation.disjoint, progressTracker); - } + @Override + public boolean execute(Geometry inputGeom1, Geometry inputGeom2, + SpatialReference sr, ProgressTracker progressTracker) { + return RelationalOperations.relate(inputGeom1, inputGeom2, sr, + RelationalOperations.Relation.disjoint, progressTracker); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorDistance.java b/src/main/java/com/esri/core/geometry/OperatorDistance.java index 56b70976..6141f6f8 100644 --- a/src/main/java/com/esri/core/geometry/OperatorDistance.java +++ b/src/main/java/com/esri/core/geometry/OperatorDistance.java @@ -31,20 +31,20 @@ */ public abstract class OperatorDistance extends Operator { - @Override - public Type getType() { - return Type.Distance; - } - - /** - * Calculates distance between two geometries. - */ - public abstract double execute(Geometry geom1, Geometry geom2, - ProgressTracker progressTracker); - - public static OperatorDistance local() { - return (OperatorDistance) OperatorFactoryLocal.getInstance() - .getOperator(Type.Distance); - } + @Override + public Type getType() { + return Type.Distance; + } + + /** + * Calculates distance between two geometries. + */ + public abstract double execute(Geometry geom1, Geometry geom2, + ProgressTracker progressTracker); + + public static OperatorDistance local() { + return (OperatorDistance) OperatorFactoryLocal.getInstance() + .getOperator(Type.Distance); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorDistanceLocal.java b/src/main/java/com/esri/core/geometry/OperatorDistanceLocal.java index 2c2d5880..ca3b305c 100644 --- a/src/main/java/com/esri/core/geometry/OperatorDistanceLocal.java +++ b/src/main/java/com/esri/core/geometry/OperatorDistanceLocal.java @@ -26,417 +26,417 @@ class OperatorDistanceLocal extends OperatorDistance { - /** - * Performs the Distance operation on two geometries - * - * @return Returns a double. - */ - @Override - public double execute(Geometry geom1, Geometry geom2, - ProgressTracker progressTracker) { - if (null == geom1 || null == geom2) { - throw new IllegalArgumentException(); - } - - Geometry geometryA = geom1; - Geometry geometryB = geom2; - - if (geometryA.isEmpty() || geometryB.isEmpty()) - return NumberUtils.TheNaN; - - Polygon polygonA; - Polygon polygonB; - MultiPoint multiPointA; - MultiPoint multiPointB; - - // if geometryA is an envelope use a polygon instead (if geom1 was - // folded, then geometryA will already be a polygon) - // if geometryA is a point use a multipoint instead - Geometry.Type gtA = geometryA.getType(); - Geometry.Type gtB = geometryB.getType(); - if (gtA == Geometry.Type.Point) { - if (gtB == Geometry.Type.Point) { - return Point2D.distance(((Point) geometryA).getXY(), ((Point) geometryB).getXY()); - } else if (gtB == Geometry.Type.Envelope) { - Envelope2D envB = new Envelope2D(); - geometryB.queryEnvelope2D(envB); - return envB.distance(((Point) geometryA).getXY()); - } - - multiPointA = new MultiPoint(); - multiPointA.add((Point) geometryA); - geometryA = multiPointA; - } else if (gtA == Geometry.Type.Envelope) { - if (gtB == Geometry.Type.Envelope) { - Envelope2D envA = new Envelope2D(); - geometryA.queryEnvelope2D(envA); - Envelope2D envB = new Envelope2D(); - geometryB.queryEnvelope2D(envB); - return envB.distance(envA); - } - polygonA = new Polygon(); - polygonA.addEnvelope((Envelope) geometryA, false); - geometryA = polygonA; - } - - // if geom_2 is an envelope use a polygon instead - // if geom_2 is a point use a multipoint instead - if (gtB == Geometry.Type.Point) { - multiPointB = new MultiPoint(); - multiPointB.add((Point) geometryB); - geometryB = multiPointB; - } else if (gtB == Geometry.Type.Envelope) { - polygonB = new Polygon(); - polygonB.addEnvelope((Envelope) geometryB, false); - geometryB = polygonB; - } - - DistanceCalculator distanceCalculator = new DistanceCalculator( - progressTracker); - double distance = distanceCalculator.calculate(geometryA, geometryB); - return distance; - } - - // Implementation of distance algorithm. - class DistanceCalculator { - private ProgressTracker m_progressTracker; - private Envelope2D m_env2DgeometryA; - private Envelope2D m_env2DgeometryB; - - private void swapEnvelopes_() { - double temp; - // swap xmin - temp = m_env2DgeometryA.xmin; - m_env2DgeometryA.xmin = m_env2DgeometryB.xmin; - m_env2DgeometryB.xmin = temp; - // swap xmax - temp = m_env2DgeometryA.xmax; - m_env2DgeometryA.xmax = m_env2DgeometryB.xmax; - m_env2DgeometryB.xmax = temp; - // swap ymin - temp = m_env2DgeometryA.ymin; - m_env2DgeometryA.ymin = m_env2DgeometryB.ymin; - m_env2DgeometryB.ymin = temp; - // swap ymax - temp = m_env2DgeometryA.ymax; - m_env2DgeometryA.ymax = m_env2DgeometryB.ymax; - m_env2DgeometryB.ymax = temp; - } - - private double executeBruteForce_(/* const */Geometry geometryA, /* const */ - Geometry geometryB) { - if ((m_progressTracker != null) - && !(m_progressTracker.progress(-1, -1))) - throw new RuntimeException("user_canceled"); - - boolean geometriesAreDisjoint = !m_env2DgeometryA - .isIntersecting(m_env2DgeometryB); - if (Geometry.isMultiPath(geometryA.getType().value()) - && Geometry.isMultiPath(geometryB.getType().value())) { // MultiPath - // vs. - // MultiPath - // choose - // the - // multipath - // with - // more - // points - // to - // be - // geometryA, - // this - // way - // more - // of - // geometryA - // segments - // can - // be - // disqualified - // more - // quickly - // by - // testing - // segmentA - // envelope - // vs. - // geometryB - // envelope - if (((MultiPath) geometryA).getPointCount() > ((MultiPath) geometryB) - .getPointCount()) - return bruteForceMultiPathMultiPath_((MultiPath) geometryA, - (MultiPath) geometryB, geometriesAreDisjoint); - swapEnvelopes_(); - double answer = bruteForceMultiPathMultiPath_( - (MultiPath) geometryB, (MultiPath) geometryA, - geometriesAreDisjoint); - swapEnvelopes_(); - return answer; - } else if (geometryA.getType() == Geometry.Type.MultiPoint - && Geometry.isMultiPath(geometryB.getType().value())) { // MultiPoint - // vs. - // MultiPath - swapEnvelopes_(); - double answer = bruteForceMultiPathMultiPoint_( - (MultiPath) geometryB, (MultiPoint) geometryA, - geometriesAreDisjoint); - swapEnvelopes_(); - return answer; - } else if (geometryB.getType() == Geometry.Type.MultiPoint - && Geometry.isMultiPath(geometryA.getType().value())) { // MultiPath - // vs. - // MultiPoint - return bruteForceMultiPathMultiPoint_((MultiPath) geometryA, - (MultiPoint) geometryB, geometriesAreDisjoint); - } else if (geometryA.getType() == Geometry.Type.MultiPoint - && geometryB.getType() == Geometry.Type.MultiPoint) { // MultiPoint - // vs. - // MultiPoint - // choose - // the - // multipoint - // with - // more - // vertices - // to - // be - // the - // "geometryA", - // this - // way - // more - // points - // can - // be - // potentially - // excluded - // by - // envelope - // distance - // tests. - if (((MultiPoint) geometryA).getPointCount() > ((MultiPoint) geometryB) - .getPointCount()) - return bruteForceMultiPointMultiPoint_( - (MultiPoint) geometryA, (MultiPoint) geometryB, - geometriesAreDisjoint); - swapEnvelopes_(); - double answer = bruteForceMultiPointMultiPoint_( - (MultiPoint) geometryB, (MultiPoint) geometryA, - geometriesAreDisjoint); - swapEnvelopes_(); - return answer; - } - return 0.0; - } - - private double bruteForceMultiPathMultiPath_( - /* const */MultiPath geometryA, /* const */MultiPath geometryB, - boolean geometriesAreDisjoint) { - // It may be beneficial to have the geometry with less vertices - // always be geometryA. - SegmentIterator segIterA = geometryA.querySegmentIterator(); - SegmentIterator segIterB = geometryB.querySegmentIterator(); - Envelope2D env2DSegmentA = new Envelope2D(); - Envelope2D env2DSegmentB = new Envelope2D(); - - double minSqrDistance = NumberUtils.doubleMax(); - - if (!geometriesAreDisjoint) { - // Geometries might be non-disjoint. Check if they intersect - // using point-in-polygon tests - if (weakIntersectionTest_(geometryA, geometryB, segIterA, - segIterB)) - return 0.0; - } - - // if geometries are known disjoint, don't bother to do any tests - // for polygon containment - - // nested while-loop insanity - while (segIterA.nextPath()) { - while (segIterA.hasNextSegment()) { + /** + * Performs the Distance operation on two geometries + * + * @return Returns a double. + */ + @Override + public double execute(Geometry geom1, Geometry geom2, + ProgressTracker progressTracker) { + if (null == geom1 || null == geom2) { + throw new IllegalArgumentException(); + } + + Geometry geometryA = geom1; + Geometry geometryB = geom2; + + if (geometryA.isEmpty() || geometryB.isEmpty()) + return NumberUtils.TheNaN; + + Polygon polygonA; + Polygon polygonB; + MultiPoint multiPointA; + MultiPoint multiPointB; + + // if geometryA is an envelope use a polygon instead (if geom1 was + // folded, then geometryA will already be a polygon) + // if geometryA is a point use a multipoint instead + Geometry.Type gtA = geometryA.getType(); + Geometry.Type gtB = geometryB.getType(); + if (gtA == Geometry.Type.Point) { + if (gtB == Geometry.Type.Point) { + return Point2D.distance(((Point) geometryA).getXY(), ((Point) geometryB).getXY()); + } else if (gtB == Geometry.Type.Envelope) { + Envelope2D envB = new Envelope2D(); + geometryB.queryEnvelope2D(envB); + return envB.distance(((Point) geometryA).getXY()); + } + + multiPointA = new MultiPoint(); + multiPointA.add((Point) geometryA); + geometryA = multiPointA; + } else if (gtA == Geometry.Type.Envelope) { + if (gtB == Geometry.Type.Envelope) { + Envelope2D envA = new Envelope2D(); + geometryA.queryEnvelope2D(envA); + Envelope2D envB = new Envelope2D(); + geometryB.queryEnvelope2D(envB); + return envB.distance(envA); + } + polygonA = new Polygon(); + polygonA.addEnvelope((Envelope) geometryA, false); + geometryA = polygonA; + } + + // if geom_2 is an envelope use a polygon instead + // if geom_2 is a point use a multipoint instead + if (gtB == Geometry.Type.Point) { + multiPointB = new MultiPoint(); + multiPointB.add((Point) geometryB); + geometryB = multiPointB; + } else if (gtB == Geometry.Type.Envelope) { + polygonB = new Polygon(); + polygonB.addEnvelope((Envelope) geometryB, false); + geometryB = polygonB; + } + + DistanceCalculator distanceCalculator = new DistanceCalculator( + progressTracker); + double distance = distanceCalculator.calculate(geometryA, geometryB); + return distance; + } + + // Implementation of distance algorithm. + class DistanceCalculator { + private ProgressTracker m_progressTracker; + private Envelope2D m_env2DgeometryA; + private Envelope2D m_env2DgeometryB; + + private void swapEnvelopes_() { + double temp; + // swap xmin + temp = m_env2DgeometryA.xmin; + m_env2DgeometryA.xmin = m_env2DgeometryB.xmin; + m_env2DgeometryB.xmin = temp; + // swap xmax + temp = m_env2DgeometryA.xmax; + m_env2DgeometryA.xmax = m_env2DgeometryB.xmax; + m_env2DgeometryB.xmax = temp; + // swap ymin + temp = m_env2DgeometryA.ymin; + m_env2DgeometryA.ymin = m_env2DgeometryB.ymin; + m_env2DgeometryB.ymin = temp; + // swap ymax + temp = m_env2DgeometryA.ymax; + m_env2DgeometryA.ymax = m_env2DgeometryB.ymax; + m_env2DgeometryB.ymax = temp; + } + + private double executeBruteForce_(/* const */Geometry geometryA, /* const */ + Geometry geometryB) { + if ((m_progressTracker != null) + && !(m_progressTracker.progress(-1, -1))) + throw new RuntimeException("user_canceled"); + + boolean geometriesAreDisjoint = !m_env2DgeometryA + .isIntersecting(m_env2DgeometryB); + if (Geometry.isMultiPath(geometryA.getType().value()) + && Geometry.isMultiPath(geometryB.getType().value())) { // MultiPath + // vs. + // MultiPath + // choose + // the + // multipath + // with + // more + // points + // to + // be + // geometryA, + // this + // way + // more + // of + // geometryA + // segments + // can + // be + // disqualified + // more + // quickly + // by + // testing + // segmentA + // envelope + // vs. + // geometryB + // envelope + if (((MultiPath) geometryA).getPointCount() > ((MultiPath) geometryB) + .getPointCount()) + return bruteForceMultiPathMultiPath_((MultiPath) geometryA, + (MultiPath) geometryB, geometriesAreDisjoint); + swapEnvelopes_(); + double answer = bruteForceMultiPathMultiPath_( + (MultiPath) geometryB, (MultiPath) geometryA, + geometriesAreDisjoint); + swapEnvelopes_(); + return answer; + } else if (geometryA.getType() == Geometry.Type.MultiPoint + && Geometry.isMultiPath(geometryB.getType().value())) { // MultiPoint + // vs. + // MultiPath + swapEnvelopes_(); + double answer = bruteForceMultiPathMultiPoint_( + (MultiPath) geometryB, (MultiPoint) geometryA, + geometriesAreDisjoint); + swapEnvelopes_(); + return answer; + } else if (geometryB.getType() == Geometry.Type.MultiPoint + && Geometry.isMultiPath(geometryA.getType().value())) { // MultiPath + // vs. + // MultiPoint + return bruteForceMultiPathMultiPoint_((MultiPath) geometryA, + (MultiPoint) geometryB, geometriesAreDisjoint); + } else if (geometryA.getType() == Geometry.Type.MultiPoint + && geometryB.getType() == Geometry.Type.MultiPoint) { // MultiPoint + // vs. + // MultiPoint + // choose + // the + // multipoint + // with + // more + // vertices + // to + // be + // the + // "geometryA", + // this + // way + // more + // points + // can + // be + // potentially + // excluded + // by + // envelope + // distance + // tests. + if (((MultiPoint) geometryA).getPointCount() > ((MultiPoint) geometryB) + .getPointCount()) + return bruteForceMultiPointMultiPoint_( + (MultiPoint) geometryA, (MultiPoint) geometryB, + geometriesAreDisjoint); + swapEnvelopes_(); + double answer = bruteForceMultiPointMultiPoint_( + (MultiPoint) geometryB, (MultiPoint) geometryA, + geometriesAreDisjoint); + swapEnvelopes_(); + return answer; + } + return 0.0; + } + + private double bruteForceMultiPathMultiPath_( + /* const */MultiPath geometryA, /* const */MultiPath geometryB, + boolean geometriesAreDisjoint) { + // It may be beneficial to have the geometry with less vertices + // always be geometryA. + SegmentIterator segIterA = geometryA.querySegmentIterator(); + SegmentIterator segIterB = geometryB.querySegmentIterator(); + Envelope2D env2DSegmentA = new Envelope2D(); + Envelope2D env2DSegmentB = new Envelope2D(); + + double minSqrDistance = NumberUtils.doubleMax(); + + if (!geometriesAreDisjoint) { + // Geometries might be non-disjoint. Check if they intersect + // using point-in-polygon tests + if (weakIntersectionTest_(geometryA, geometryB, segIterA, + segIterB)) + return 0.0; + } + + // if geometries are known disjoint, don't bother to do any tests + // for polygon containment + + // nested while-loop insanity + while (segIterA.nextPath()) { + while (segIterA.hasNextSegment()) { /* const */ - Segment segmentA = segIterA.nextSegment(); - segmentA.queryEnvelope2D(env2DSegmentA); - if (env2DSegmentA.sqrDistance(m_env2DgeometryB) > minSqrDistance) - continue; + Segment segmentA = segIterA.nextSegment(); + segmentA.queryEnvelope2D(env2DSegmentA); + if (env2DSegmentA.sqrDistance(m_env2DgeometryB) > minSqrDistance) + continue; - while (segIterB.nextPath()) { - while (segIterB.hasNextSegment()) { + while (segIterB.nextPath()) { + while (segIterB.hasNextSegment()) { /* const */ - Segment segmentB = segIterB - .nextSegment(); - segmentB.queryEnvelope2D(env2DSegmentB); - if (env2DSegmentA.sqrDistance(env2DSegmentB) < minSqrDistance) { - // get distance between segments - double sqrDistance = segmentA.distance( - segmentB, geometriesAreDisjoint); - sqrDistance *= sqrDistance; - if (sqrDistance < minSqrDistance) { - if (sqrDistance == 0.0) - return 0.0; - - minSqrDistance = sqrDistance; - } - } - } - } - segIterB.resetToFirstPath(); - } - } - - return Math.sqrt(minSqrDistance); - } - - private double bruteForceMultiPathMultiPoint_( - /* const */MultiPath geometryA, /* const */ - MultiPoint geometryB, boolean geometriesAreDisjoint) { - SegmentIterator segIterA = geometryA.querySegmentIterator(); - - Envelope2D env2DSegmentA = new Envelope2D(); - - double minSqrDistance = NumberUtils.doubleMax(); - - Point2D inputPoint = new Point2D(); - double t = -1; - double sqrDistance = minSqrDistance; + Segment segmentB = segIterB + .nextSegment(); + segmentB.queryEnvelope2D(env2DSegmentB); + if (env2DSegmentA.sqrDistance(env2DSegmentB) < minSqrDistance) { + // get distance between segments + double sqrDistance = segmentA.distance( + segmentB, geometriesAreDisjoint); + sqrDistance *= sqrDistance; + if (sqrDistance < minSqrDistance) { + if (sqrDistance == 0.0) + return 0.0; + + minSqrDistance = sqrDistance; + } + } + } + } + segIterB.resetToFirstPath(); + } + } + + return Math.sqrt(minSqrDistance); + } + + private double bruteForceMultiPathMultiPoint_( + /* const */MultiPath geometryA, /* const */ + MultiPoint geometryB, boolean geometriesAreDisjoint) { + SegmentIterator segIterA = geometryA.querySegmentIterator(); + + Envelope2D env2DSegmentA = new Envelope2D(); + + double minSqrDistance = NumberUtils.doubleMax(); + + Point2D inputPoint = new Point2D(); + double t = -1; + double sqrDistance = minSqrDistance; /* const */ - MultiPointImpl multiPointImplB = (MultiPointImpl) geometryB - ._getImpl(); - int pointCountB = multiPointImplB.getPointCount(); - boolean bDoPiPTest = !geometriesAreDisjoint - && (geometryA.getType() == Geometry.Type.Polygon); - - while (segIterA.nextPath()) { - while (segIterA.hasNextSegment()) { + MultiPointImpl multiPointImplB = (MultiPointImpl) geometryB + ._getImpl(); + int pointCountB = multiPointImplB.getPointCount(); + boolean bDoPiPTest = !geometriesAreDisjoint + && (geometryA.getType() == Geometry.Type.Polygon); + + while (segIterA.nextPath()) { + while (segIterA.hasNextSegment()) { /* const */ - Segment segmentA = segIterA.nextSegment(); - segmentA.queryEnvelope2D(env2DSegmentA); - // if multipointB has only 1 vertex then it is faster to not - // test for - // env2DSegmentA.distance(env2DgeometryB) - if (pointCountB > 1 - && env2DSegmentA.sqrDistance(m_env2DgeometryB) > minSqrDistance) - continue; - - for (int i = 0; i < pointCountB; i++) { - multiPointImplB.getXY(i, inputPoint); - if (bDoPiPTest) { - // Test for polygon containment. This takes the - // place of a more general intersection test at the - // beginning of the operator - if (PolygonUtils.isPointInPolygon2D( - (Polygon) geometryA, inputPoint, 0) != PolygonUtils.PiPResult.PiPOutside) - return 0.0; - } - - t = segmentA.getClosestCoordinate(inputPoint, false); - inputPoint.sub(segmentA.getCoord2D(t)); - sqrDistance = inputPoint.sqrLength(); - if (sqrDistance < minSqrDistance) { - if (sqrDistance == 0.0) - return 0.0; - - minSqrDistance = sqrDistance; - } - } - - // No need to do point-in-polygon anymore (if it is a - // polygon vs polyline) - bDoPiPTest = false; - } - } - return Math.sqrt(minSqrDistance); - } - - private double bruteForceMultiPointMultiPoint_( - /* const */MultiPoint geometryA, /* const */ - MultiPoint geometryB, boolean geometriesAreDisjoint) { - double minSqrDistance = NumberUtils.doubleMax(); - - Point2D pointA = new Point2D(); - Point2D pointB = new Point2D(); - - double sqrDistance = minSqrDistance; + Segment segmentA = segIterA.nextSegment(); + segmentA.queryEnvelope2D(env2DSegmentA); + // if multipointB has only 1 vertex then it is faster to not + // test for + // env2DSegmentA.distance(env2DgeometryB) + if (pointCountB > 1 + && env2DSegmentA.sqrDistance(m_env2DgeometryB) > minSqrDistance) + continue; + + for (int i = 0; i < pointCountB; i++) { + multiPointImplB.getXY(i, inputPoint); + if (bDoPiPTest) { + // Test for polygon containment. This takes the + // place of a more general intersection test at the + // beginning of the operator + if (PolygonUtils.isPointInPolygon2D( + (Polygon) geometryA, inputPoint, 0) != PolygonUtils.PiPResult.PiPOutside) + return 0.0; + } + + t = segmentA.getClosestCoordinate(inputPoint, false); + inputPoint.sub(segmentA.getCoord2D(t)); + sqrDistance = inputPoint.sqrLength(); + if (sqrDistance < minSqrDistance) { + if (sqrDistance == 0.0) + return 0.0; + + minSqrDistance = sqrDistance; + } + } + + // No need to do point-in-polygon anymore (if it is a + // polygon vs polyline) + bDoPiPTest = false; + } + } + return Math.sqrt(minSqrDistance); + } + + private double bruteForceMultiPointMultiPoint_( + /* const */MultiPoint geometryA, /* const */ + MultiPoint geometryB, boolean geometriesAreDisjoint) { + double minSqrDistance = NumberUtils.doubleMax(); + + Point2D pointA = new Point2D(); + Point2D pointB = new Point2D(); + + double sqrDistance = minSqrDistance; /* const */ - MultiPointImpl multiPointImplA = (/* const */MultiPointImpl) geometryA - ._getImpl(); + MultiPointImpl multiPointImplA = (/* const */MultiPointImpl) geometryA + ._getImpl(); /* const */ - MultiPointImpl multiPointImplB = (/* const */MultiPointImpl) geometryB - ._getImpl(); - int pointCountA = multiPointImplA.getPointCount(); - int pointCountB = multiPointImplB.getPointCount(); - for (int i = 0; i < pointCountA; i++) { - multiPointImplA.getXY(i, pointA); - - if (pointCountB > 1 - && m_env2DgeometryB.sqrDistance(pointA) > minSqrDistance) - continue; - - for (int j = 0; j < pointCountB; j++) { - multiPointImplB.getXY(j, pointB); - sqrDistance = Point2D.sqrDistance(pointA, pointB); - if (sqrDistance < minSqrDistance) { - if (sqrDistance == 0.0) - return 0.0; - - minSqrDistance = sqrDistance; - } - } - } - - return Math.sqrt(minSqrDistance); - } - - // resets Iterators if they are used. - private boolean weakIntersectionTest_(/* const */Geometry geometryA, /* const */ - Geometry geometryB, SegmentIterator segIterA, SegmentIterator segIterB) { - if (geometryA.getType() == Geometry.Type.Polygon) { - // test PolygonA vs. first segment of each of geometryB's paths - while (segIterB.nextPath()) { - if (segIterB.hasNextSegment()) { + MultiPointImpl multiPointImplB = (/* const */MultiPointImpl) geometryB + ._getImpl(); + int pointCountA = multiPointImplA.getPointCount(); + int pointCountB = multiPointImplB.getPointCount(); + for (int i = 0; i < pointCountA; i++) { + multiPointImplA.getXY(i, pointA); + + if (pointCountB > 1 + && m_env2DgeometryB.sqrDistance(pointA) > minSqrDistance) + continue; + + for (int j = 0; j < pointCountB; j++) { + multiPointImplB.getXY(j, pointB); + sqrDistance = Point2D.sqrDistance(pointA, pointB); + if (sqrDistance < minSqrDistance) { + if (sqrDistance == 0.0) + return 0.0; + + minSqrDistance = sqrDistance; + } + } + } + + return Math.sqrt(minSqrDistance); + } + + // resets Iterators if they are used. + private boolean weakIntersectionTest_(/* const */Geometry geometryA, /* const */ + Geometry geometryB, SegmentIterator segIterA, SegmentIterator segIterB) { + if (geometryA.getType() == Geometry.Type.Polygon) { + // test PolygonA vs. first segment of each of geometryB's paths + while (segIterB.nextPath()) { + if (segIterB.hasNextSegment()) { /* const */ - Segment segmentB = segIterB.nextSegment(); - if (PolygonUtils.isPointInPolygon2D( - (Polygon) geometryA, segmentB.getEndXY(), 0) != PolygonUtils.PiPResult.PiPOutside) - return true; - } - } - segIterB.resetToFirstPath(); - } - - if (geometryB.getType() == Geometry.Type.Polygon) { - // test PolygonB vs. first segment of each of geometryA's paths - while (segIterA.nextPath()) { - if (segIterA.hasNextSegment()) { + Segment segmentB = segIterB.nextSegment(); + if (PolygonUtils.isPointInPolygon2D( + (Polygon) geometryA, segmentB.getEndXY(), 0) != PolygonUtils.PiPResult.PiPOutside) + return true; + } + } + segIterB.resetToFirstPath(); + } + + if (geometryB.getType() == Geometry.Type.Polygon) { + // test PolygonB vs. first segment of each of geometryA's paths + while (segIterA.nextPath()) { + if (segIterA.hasNextSegment()) { /* const */ - Segment segmentA = segIterA.nextSegment(); - if (PolygonUtils.isPointInPolygon2D( - (Polygon) geometryB, segmentA.getEndXY(), 0) != PolygonUtils.PiPResult.PiPOutside) - return true; - } - } - segIterA.resetToFirstPath(); - } - return false; - } - - DistanceCalculator(ProgressTracker progressTracker) { - m_progressTracker = progressTracker; - m_env2DgeometryA = new Envelope2D(); - m_env2DgeometryA.setEmpty(); - m_env2DgeometryB = new Envelope2D(); - m_env2DgeometryB.setEmpty(); - } - - double calculate(/* const */Geometry geometryA, /* const */ - Geometry geometryB) { - if (geometryA.isEmpty() || geometryB.isEmpty()) - return NumberUtils.TheNaN; - - geometryA.queryEnvelope2D(m_env2DgeometryA); - geometryB.queryEnvelope2D(m_env2DgeometryB); - return executeBruteForce_(geometryA, geometryB); - } - } + Segment segmentA = segIterA.nextSegment(); + if (PolygonUtils.isPointInPolygon2D( + (Polygon) geometryB, segmentA.getEndXY(), 0) != PolygonUtils.PiPResult.PiPOutside) + return true; + } + } + segIterA.resetToFirstPath(); + } + return false; + } + + DistanceCalculator(ProgressTracker progressTracker) { + m_progressTracker = progressTracker; + m_env2DgeometryA = new Envelope2D(); + m_env2DgeometryA.setEmpty(); + m_env2DgeometryB = new Envelope2D(); + m_env2DgeometryB.setEmpty(); + } + + double calculate(/* const */Geometry geometryA, /* const */ + Geometry geometryB) { + if (geometryA.isEmpty() || geometryB.isEmpty()) + return NumberUtils.TheNaN; + + geometryA.queryEnvelope2D(m_env2DgeometryA); + geometryB.queryEnvelope2D(m_env2DgeometryB); + return executeBruteForce_(geometryA, geometryB); + } + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorEnclosingCircle.java b/src/main/java/com/esri/core/geometry/OperatorEnclosingCircle.java index db4fe249..40276e8b 100644 --- a/src/main/java/com/esri/core/geometry/OperatorEnclosingCircle.java +++ b/src/main/java/com/esri/core/geometry/OperatorEnclosingCircle.java @@ -1,22 +1,22 @@ package com.esri.core.geometry; public abstract class OperatorEnclosingCircle extends Operator { - @Override - public Type getType() { - return Type.EnclosingCircle; - } + @Override + public Type getType() { + return Type.EnclosingCircle; + } - public abstract GeometryCursor execute(GeometryCursor geoms, SpatialReference spatialReference, ProgressTracker progressTracker); + public abstract GeometryCursor execute(GeometryCursor geoms, SpatialReference spatialReference, ProgressTracker progressTracker); - /** - * Performs the Generalize operation on a single geometry. Point and - * multipoint geometries are left unchanged. An envelope is converted to a - * polygon. - */ - public abstract Geometry execute(Geometry geom, SpatialReference spatialReference, ProgressTracker progressTracker); + /** + * Performs the Generalize operation on a single geometry. Point and + * multipoint geometries are left unchanged. An envelope is converted to a + * polygon. + */ + public abstract Geometry execute(Geometry geom, SpatialReference spatialReference, ProgressTracker progressTracker); - public static OperatorEnclosingCircle local() { - return (OperatorEnclosingCircle) OperatorFactoryLocal.getInstance().getOperator(Type.EnclosingCircle); - } + public static OperatorEnclosingCircle local() { + return (OperatorEnclosingCircle) OperatorFactoryLocal.getInstance().getOperator(Type.EnclosingCircle); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorEnclosingCircleCursor.java b/src/main/java/com/esri/core/geometry/OperatorEnclosingCircleCursor.java index 7368d38c..38611a42 100644 --- a/src/main/java/com/esri/core/geometry/OperatorEnclosingCircleCursor.java +++ b/src/main/java/com/esri/core/geometry/OperatorEnclosingCircleCursor.java @@ -6,30 +6,30 @@ import java.util.stream.IntStream; public class OperatorEnclosingCircleCursor extends GeometryCursor { - SpatialReference m_spatialReference; - ProgressTracker m_progressTracker; - - public OperatorEnclosingCircleCursor(GeometryCursor geoms, SpatialReference spatialReference, ProgressTracker progressTracker) { - m_inputGeoms = geoms; - m_spatialReference = spatialReference; - m_progressTracker = progressTracker; - } - - @Override - public Geometry next() { - if (hasNext()) - return getCircle(m_inputGeoms.next()); - - return null; - } - - protected Geometry getCircle(Geometry geometry) { - if (geometry.getType() == Geometry.Type.Point || ((MultiVertexGeometry)geometry).getPointCount() <= 1) - return geometry; - - EnclosingCircler enclosingCircler = new EnclosingCircler(geometry, m_spatialReference, m_progressTracker); - return enclosingCircler.search(); - } + SpatialReference m_spatialReference; + ProgressTracker m_progressTracker; + + public OperatorEnclosingCircleCursor(GeometryCursor geoms, SpatialReference spatialReference, ProgressTracker progressTracker) { + m_inputGeoms = geoms; + m_spatialReference = spatialReference; + m_progressTracker = progressTracker; + } + + @Override + public Geometry next() { + if (hasNext()) + return getCircle(m_inputGeoms.next()); + + return null; + } + + protected Geometry getCircle(Geometry geometry) { + if (geometry.getType() == Geometry.Type.Point || ((MultiVertexGeometry) geometry).getPointCount() <= 1) + return geometry; + + EnclosingCircler enclosingCircler = new EnclosingCircler(geometry, m_spatialReference, m_progressTracker); + return enclosingCircler.search(); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorEnclosingCircleLocal.java b/src/main/java/com/esri/core/geometry/OperatorEnclosingCircleLocal.java index b05d680b..4e63bfe0 100644 --- a/src/main/java/com/esri/core/geometry/OperatorEnclosingCircleLocal.java +++ b/src/main/java/com/esri/core/geometry/OperatorEnclosingCircleLocal.java @@ -1,14 +1,14 @@ package com.esri.core.geometry; public class OperatorEnclosingCircleLocal extends OperatorEnclosingCircle { - @Override - public GeometryCursor execute(GeometryCursor geoms, SpatialReference spatialReference, ProgressTracker progressTracker) { - return new OperatorEnclosingCircleCursor(geoms, spatialReference, progressTracker); - } + @Override + public GeometryCursor execute(GeometryCursor geoms, SpatialReference spatialReference, ProgressTracker progressTracker) { + return new OperatorEnclosingCircleCursor(geoms, spatialReference, progressTracker); + } - @Override - public Geometry execute(Geometry geom, SpatialReference spatialReference, ProgressTracker progressTracker) { - OperatorEnclosingCircleCursor operatorEnclosingCircleCursor = new OperatorEnclosingCircleCursor(new SimpleGeometryCursor(geom), spatialReference, progressTracker); - return operatorEnclosingCircleCursor.next(); - } + @Override + public Geometry execute(Geometry geom, SpatialReference spatialReference, ProgressTracker progressTracker) { + OperatorEnclosingCircleCursor operatorEnclosingCircleCursor = new OperatorEnclosingCircleCursor(new SimpleGeometryCursor(geom), spatialReference, progressTracker); + return operatorEnclosingCircleCursor.next(); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorEquals.java b/src/main/java/com/esri/core/geometry/OperatorEquals.java index 1286052f..2fb6d3ba 100644 --- a/src/main/java/com/esri/core/geometry/OperatorEquals.java +++ b/src/main/java/com/esri/core/geometry/OperatorEquals.java @@ -30,14 +30,14 @@ * Relational operation Equals. */ public abstract class OperatorEquals extends OperatorSimpleRelation { - @Override - public Type getType() { - return Type.Equals; - } - - public static OperatorEquals local() { - return (OperatorEquals) OperatorFactoryLocal.getInstance().getOperator( - Type.Equals); - } + @Override + public Type getType() { + return Type.Equals; + } + + public static OperatorEquals local() { + return (OperatorEquals) OperatorFactoryLocal.getInstance().getOperator( + Type.Equals); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorEqualsLocal.java b/src/main/java/com/esri/core/geometry/OperatorEqualsLocal.java index c0dbc7f8..945b0514 100644 --- a/src/main/java/com/esri/core/geometry/OperatorEqualsLocal.java +++ b/src/main/java/com/esri/core/geometry/OperatorEqualsLocal.java @@ -25,11 +25,11 @@ package com.esri.core.geometry; class OperatorEqualsLocal extends OperatorEquals { - @Override - public boolean execute(Geometry inputGeom1, Geometry inputGeom2, - SpatialReference sr, ProgressTracker progressTracker) { - return RelationalOperations.relate(inputGeom1, inputGeom2, sr, - RelationalOperations.Relation.equals, progressTracker); - } + @Override + public boolean execute(Geometry inputGeom1, Geometry inputGeom2, + SpatialReference sr, ProgressTracker progressTracker) { + return RelationalOperations.relate(inputGeom1, inputGeom2, sr, + RelationalOperations.Relation.equals, progressTracker); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorExportToESRIShape.java b/src/main/java/com/esri/core/geometry/OperatorExportToESRIShape.java index 5842a046..9eb4051e 100644 --- a/src/main/java/com/esri/core/geometry/OperatorExportToESRIShape.java +++ b/src/main/java/com/esri/core/geometry/OperatorExportToESRIShape.java @@ -32,38 +32,38 @@ * Export to ESRI shape format. */ public abstract class OperatorExportToESRIShape extends Operator { - @Override - public Type getType() { - return Type.ExportToESRIShape; - } + @Override + public Type getType() { + return Type.ExportToESRIShape; + } - /** - * Performs the ExportToESRIShape operation - * - * @return Returns a ByteBufferCursor. - */ - public abstract ByteBufferCursor execute(int exportFlags, GeometryCursor geometryCursor); + /** + * Performs the ExportToESRIShape operation + * + * @return Returns a ByteBufferCursor. + */ + public abstract ByteBufferCursor execute(int exportFlags, GeometryCursor geometryCursor); - /** - * Performs the ExportToESRIShape operation. - * - * @param exportFlags Use the {@link ShapeExportFlags} interface. - * @param geometry The Geometry being exported. - * @return Returns a ByteBuffer object containing the Geometry in ESRIShape format. - */ - public abstract ByteBuffer execute(int exportFlags, Geometry geometry); + /** + * Performs the ExportToESRIShape operation. + * + * @param exportFlags Use the {@link ShapeExportFlags} interface. + * @param geometry The Geometry being exported. + * @return Returns a ByteBuffer object containing the Geometry in ESRIShape format. + */ + public abstract ByteBuffer execute(int exportFlags, Geometry geometry); - /** - * Performs the ExportToESRIShape operation. - * - * @param exportFlags Use the {@link ShapeExportFlags} interface. - * @param geometry The Geometry being exported. - * @param shapeBuffer The ByteBuffer to contain the exported Geometry in ESRIShape format. - * @return If the input buffer is null, then the size needed for the buffer is returned. Otherwise the number of bytes written to the buffer is returned. - */ - public abstract int execute(int exportFlags, Geometry geometry, ByteBuffer shapeBuffer); + /** + * Performs the ExportToESRIShape operation. + * + * @param exportFlags Use the {@link ShapeExportFlags} interface. + * @param geometry The Geometry being exported. + * @param shapeBuffer The ByteBuffer to contain the exported Geometry in ESRIShape format. + * @return If the input buffer is null, then the size needed for the buffer is returned. Otherwise the number of bytes written to the buffer is returned. + */ + public abstract int execute(int exportFlags, Geometry geometry, ByteBuffer shapeBuffer); - public static OperatorExportToESRIShape local() { - return (OperatorExportToESRIShape) OperatorFactoryLocal.getInstance().getOperator(Type.ExportToESRIShape); - } + public static OperatorExportToESRIShape local() { + return (OperatorExportToESRIShape) OperatorFactoryLocal.getInstance().getOperator(Type.ExportToESRIShape); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorExportToESRIShapeCursor.java b/src/main/java/com/esri/core/geometry/OperatorExportToESRIShapeCursor.java index 360f3830..fa364be9 100644 --- a/src/main/java/com/esri/core/geometry/OperatorExportToESRIShapeCursor.java +++ b/src/main/java/com/esri/core/geometry/OperatorExportToESRIShapeCursor.java @@ -30,885 +30,887 @@ import java.nio.ByteOrder; public class OperatorExportToESRIShapeCursor extends ByteBufferCursor { - private GeometryCursor m_geometryCursor; - private int m_exportFlags; - private ByteBuffer m_shapeBuffer; - private SimpleStateEnum simpleStateEnum = SimpleStateEnum.SIMPLE_UNKNOWN; - - public OperatorExportToESRIShapeCursor(int exportFlags, GeometryCursor geometryCursor) { - if (geometryCursor == null) - throw new GeometryException("invalid argument"); - - m_exportFlags = exportFlags; - m_geometryCursor = geometryCursor; - m_shapeBuffer = null; - } - - @Override - public long getByteBufferID() { - return m_geometryCursor.getGeometryID(); - } - - @Override - public SimpleStateEnum getSimpleState() { - return simpleStateEnum; - } - - @Override - public String getFeatureID() { - return m_geometryCursor.getFeatureID(); - } - - @Override - public boolean hasNext() { return m_geometryCursor != null && m_geometryCursor.hasNext(); } - - @Override - public ByteBuffer next() { - Geometry geometry; - if (hasNext()) { - geometry = m_geometryCursor.next(); - simpleStateEnum = geometry.getSimpleState(); - int size = exportToESRIShape(m_exportFlags, geometry, null); - if (m_shapeBuffer == null || size > m_shapeBuffer.capacity()) - m_shapeBuffer = ByteBuffer.allocate(size).order( - ByteOrder.LITTLE_ENDIAN); - exportToESRIShape(m_exportFlags, geometry, m_shapeBuffer); - return m_shapeBuffer; - } - return null; - } - - static int exportToESRIShape(int exportFlags, Geometry geometry, - ByteBuffer shapeBuffer) { - if (geometry == null) { - if (shapeBuffer != null) - shapeBuffer.putInt(0, ShapeType.ShapeNull); - - return 4; - } - - int type = geometry.getType().value(); - switch (type) { - case Geometry.GeometryType.Polygon: - return exportMultiPathToESRIShape(true, exportFlags, - (MultiPath) geometry, shapeBuffer); - case Geometry.GeometryType.Polyline: - return exportMultiPathToESRIShape(false, exportFlags, - (MultiPath) geometry, shapeBuffer); - case Geometry.GeometryType.MultiPoint: - return exportMultiPointToESRIShape(exportFlags, - (MultiPoint) geometry, shapeBuffer); - case Geometry.GeometryType.Point: - return exportPointToESRIShape(exportFlags, (Point) geometry, - shapeBuffer); - case Geometry.GeometryType.Envelope: - return exportEnvelopeToESRIShape(exportFlags, (Envelope) geometry, - shapeBuffer); - default: { - throw GeometryException.GeometryInternalError(); - // return -1; - } - } - } - - private static int exportEnvelopeToESRIShape(int exportFlags, - Envelope envelope, ByteBuffer shapeBuffer) { - boolean bExportZs = envelope.hasAttribute(Semantics.Z) - && (exportFlags & ShapeExportFlags.ShapeExportStripZs) == 0; - boolean bExportMs = envelope.hasAttribute(Semantics.M) - && (exportFlags & ShapeExportFlags.ShapeExportStripMs) == 0; - boolean bExportIDs = envelope.hasAttribute(Semantics.ID) - && (exportFlags & ShapeExportFlags.ShapeExportStripIDs) == 0; - boolean bArcViewNaNs = (exportFlags & ShapeExportFlags.ShapeExportTrueNaNs) == 0; - - boolean bEmpty = envelope.isEmpty(); - int partCount = bEmpty ? 0 : 1; - int pointCount = bEmpty ? 0 : 5; - - int size = (4 /* type */) + (4 * 8 /* envelope */) + (4 /* part count */) - + (4 /* point count */) + (partCount * 4 /* start indices */) - + pointCount * 2 * 8 /* xy coordinates */; - - if (bExportZs) - size += (2 * 8 /* min max */) + (pointCount * 8 /* zs */); - if (bExportMs) - size += (2 * 8 /* min max */) + (pointCount * 8 /* ms */); - if (bExportIDs) - size += (pointCount * 4 /* ids */); - - if (shapeBuffer == null) - return size; - else if (shapeBuffer.capacity() < size) - throw new GeometryException("buffer is too small"); - - int type; - - // Determine the shape type - if (!bExportZs && !bExportMs) { - if (bExportIDs) - type = ShapeType.ShapeGeneralPolygon - | ShapeModifiers.ShapeHasIDs; - else - type = ShapeType.ShapePolygon; - } else if (bExportZs && !bExportMs) { - if (bExportIDs) - type = ShapeType.ShapeGeneralPolygon - | ShapeModifiers.ShapeHasZs - | ShapeModifiers.ShapeHasIDs; - else - type = ShapeType.ShapePolygonZ; - } else if (bExportMs && !bExportZs) { - if (bExportIDs) - type = ShapeType.ShapeGeneralPolygon - | ShapeModifiers.ShapeHasMs - | ShapeModifiers.ShapeHasIDs; - else - type = ShapeType.ShapePolygonM; - } else { - if (bExportIDs) - type = ShapeType.ShapeGeneralPolygon - | ShapeModifiers.ShapeHasZs | ShapeModifiers.ShapeHasMs - | ShapeModifiers.ShapeHasIDs; - else - type = ShapeType.ShapePolygonZM; - } - - int offset = 0; - - // write type - shapeBuffer.putInt(offset, type); - offset += 4; - - // write Envelope - Envelope2D env = new Envelope2D(); - envelope.queryEnvelope2D(env); // calls _VerifyAllStreams - shapeBuffer.putDouble(offset, env.xmin); - offset += 8; - shapeBuffer.putDouble(offset, env.ymin); - offset += 8; - shapeBuffer.putDouble(offset, env.xmax); - offset += 8; - shapeBuffer.putDouble(offset, env.ymax); - offset += 8; - - // write part count - shapeBuffer.putInt(offset, partCount); - offset += 4; - - // write pointCount - shapeBuffer.putInt(offset, pointCount); - offset += 4; - - if (!bEmpty) { - // write start index - shapeBuffer.putInt(offset, 0); - offset += 4; - - // write xy coordinates - shapeBuffer.putDouble(offset, env.xmin); - offset += 8; - shapeBuffer.putDouble(offset, env.ymin); - offset += 8; - - shapeBuffer.putDouble(offset, env.xmin); - offset += 8; - shapeBuffer.putDouble(offset, env.ymax); - offset += 8; - - shapeBuffer.putDouble(offset, env.xmax); - offset += 8; - shapeBuffer.putDouble(offset, env.ymax); - offset += 8; - - shapeBuffer.putDouble(offset, env.xmax); - offset += 8; - shapeBuffer.putDouble(offset, env.ymin); - offset += 8; - - shapeBuffer.putDouble(offset, env.xmin); - offset += 8; - shapeBuffer.putDouble(offset, env.ymin); - offset += 8; - } - // write Zs - if (bExportZs) { - Envelope1D zInterval; - zInterval = envelope.queryInterval(Semantics.Z, 0); - - double zmin = bArcViewNaNs ? Interop - .translateToAVNaN(zInterval.vmin) : zInterval.vmin; - double zmax = bArcViewNaNs ? Interop - .translateToAVNaN(zInterval.vmax) : zInterval.vmax; - - // write min max values - shapeBuffer.putDouble(offset, zmin); - offset += 8; - shapeBuffer.putDouble(offset, zmax); - offset += 8; - - if (!bEmpty) { - // write arbitrary z values - shapeBuffer.putDouble(offset, zmin); - offset += 8; - shapeBuffer.putDouble(offset, zmax); - offset += 8; - shapeBuffer.putDouble(offset, zmin); - offset += 8; - shapeBuffer.putDouble(offset, zmax); - offset += 8; - shapeBuffer.putDouble(offset, zmin); - offset += 8; - } - } - // write Ms - if (bExportMs) { - Envelope1D mInterval; - mInterval = envelope.queryInterval(Semantics.M, 0); - - double mmin = bArcViewNaNs ? Interop - .translateToAVNaN(mInterval.vmin) : mInterval.vmin; - double mmax = bArcViewNaNs ? Interop - .translateToAVNaN(mInterval.vmax) : mInterval.vmax; - - // write min max values - shapeBuffer.putDouble(offset, mmin); - offset += 8; - shapeBuffer.putDouble(offset, mmax); - offset += 8; - - if (!bEmpty) { - // write arbitrary m values - shapeBuffer.putDouble(offset, mmin); - offset += 8; - shapeBuffer.putDouble(offset, mmax); - offset += 8; - shapeBuffer.putDouble(offset, mmin); - offset += 8; - shapeBuffer.putDouble(offset, mmax); - offset += 8; - shapeBuffer.putDouble(offset, mmin); - offset += 8; - } - } - - // write IDs - if (bExportIDs && !bEmpty) { - Envelope1D idInterval; - idInterval = envelope.queryInterval(Semantics.ID, 0); - - int idmin = (int) idInterval.vmin; - int idmax = (int) idInterval.vmax; - - // write arbitrary id values - shapeBuffer.putInt(offset, idmin); - offset += 4; - shapeBuffer.putInt(offset, idmax); - offset += 4; - shapeBuffer.putInt(offset, idmin); - offset += 4; - shapeBuffer.putInt(offset, idmax); - offset += 4; - shapeBuffer.putInt(offset, idmin); - offset += 4; - } - - return offset; - } - - private static int exportPointToESRIShape(int exportFlags, Point point, - ByteBuffer shapeBuffer) { - boolean bExportZ = point.hasAttribute(Semantics.Z) - && (exportFlags & ShapeExportFlags.ShapeExportStripZs) == 0; - boolean bExportM = point.hasAttribute(Semantics.M) - && (exportFlags & ShapeExportFlags.ShapeExportStripMs) == 0; - boolean bExportID = point.hasAttribute(Semantics.ID) - && (exportFlags & ShapeExportFlags.ShapeExportStripIDs) == 0; - boolean bArcViewNaNs = (exportFlags & ShapeExportFlags.ShapeExportTrueNaNs) == 0; - - int size = (4 /* type */) + (2 * 8 /* xy coordinate */); - - if (bExportZ) - size += 8; - if (bExportM) - size += 8; - if (bExportID) - size += 4; - - if (shapeBuffer == null) - return size; - else if (shapeBuffer.capacity() < size) - throw new GeometryException("buffer is too small"); - - int type; - - // Determine the shape type - if (!bExportZ && !bExportM) { - if (bExportID) - type = ShapeType.ShapeGeneralPoint | ShapeModifiers.ShapeHasIDs; - else - type = ShapeType.ShapePoint; - } else if (bExportZ && !bExportM) { - if (bExportID) - type = ShapeType.ShapeGeneralPoint | ShapeModifiers.ShapeHasZs - | ShapeModifiers.ShapeHasIDs; - else - type = ShapeType.ShapePointZ; - } else if (bExportM && !bExportZ) { - if (bExportID) - type = ShapeType.ShapeGeneralPoint | ShapeModifiers.ShapeHasMs - | ShapeModifiers.ShapeHasIDs; - else - type = ShapeType.ShapePointM; - } else { - if (bExportID) - type = ShapeType.ShapeGeneralPoint | ShapeModifiers.ShapeHasZs - | ShapeModifiers.ShapeHasMs - | ShapeModifiers.ShapeHasIDs; - else - type = ShapeType.ShapePointZM; - } - - int offset = 0; - - // write type - - shapeBuffer.putInt(offset, type); - offset += 4; - - boolean bEmpty = point.isEmpty(); - - // write xy - double x = !bEmpty ? point.getX() : NumberUtils.NaN(); - double y = !bEmpty ? point.getY() : NumberUtils.NaN(); - shapeBuffer.putDouble(offset, - bArcViewNaNs ? Interop.translateToAVNaN(x) : x); - offset += 8; - shapeBuffer.putDouble(offset, - bArcViewNaNs ? Interop.translateToAVNaN(y) : y); - offset += 8; - - // write Z - if (bExportZ) { - double z = !bEmpty ? point.getZ() : NumberUtils.NaN(); - shapeBuffer.putDouble(offset, - bArcViewNaNs ? Interop.translateToAVNaN(z) : z); - offset += 8; - } - - // WriteM - if (bExportM) { - double m = !bEmpty ? point.getM() : NumberUtils.NaN(); - shapeBuffer.putDouble(offset, - bArcViewNaNs ? Interop.translateToAVNaN(m) : m); - offset += 8; - } - - // write ID - if (bExportID) { - int id = !bEmpty ? point.getID() : 0; - shapeBuffer.putInt(offset, id); - offset += 4; - } - - return offset; - } - - private static int exportMultiPointToESRIShape(int exportFlags, - MultiPoint multipoint, ByteBuffer shapeBuffer) { - MultiPointImpl multipointImpl = (MultiPointImpl) multipoint._getImpl(); - boolean bExportZs = multipointImpl.hasAttribute(Semantics.Z) - && (exportFlags & ShapeExportFlags.ShapeExportStripZs) == 0; - boolean bExportMs = multipointImpl.hasAttribute(Semantics.M) - && (exportFlags & ShapeExportFlags.ShapeExportStripMs) == 0; - boolean bExportIDs = multipointImpl.hasAttribute(Semantics.ID) - && (exportFlags & ShapeExportFlags.ShapeExportStripIDs) == 0; - boolean bArcViewNaNs = (exportFlags & ShapeExportFlags.ShapeExportTrueNaNs) == 0; - - int pointCount = multipointImpl.getPointCount(); - - int size = (4 /* type */) + (4 * 8 /* envelope */) + (4 /* point count */) - + (pointCount * 2 * 8 /* xy coordinates */); - - if (bExportZs) - size += (2 * 8 /* min max */) + (pointCount * 8 /* zs */); - if (bExportMs) - size += (2 * 8 /* min max */) + (pointCount * 8 /* ms */); - if (bExportIDs) - size += pointCount * 4 /* ids */; - - if (size >= NumberUtils.intMax()) - throw new GeometryException("invalid call"); - - if (shapeBuffer == null) - return size; - else if (shapeBuffer.capacity() < size) - throw new GeometryException("buffer is too small"); - - int type; - - // Determine the shape type - if (!bExportZs && !bExportMs) { - if (bExportIDs) - type = ShapeType.ShapeGeneralMultiPoint - | ShapeModifiers.ShapeHasIDs; - else - type = ShapeType.ShapeMultiPoint; - } else if (bExportZs && !bExportMs) { - if (bExportIDs) - type = ShapeType.ShapeGeneralMultiPoint - | ShapeModifiers.ShapeHasZs - | ShapeModifiers.ShapeHasIDs; - else - type = ShapeType.ShapeMultiPointZ; - } else if (bExportMs && !bExportZs) { - if (bExportIDs) - type = ShapeType.ShapeGeneralMultiPoint - | ShapeModifiers.ShapeHasMs - | ShapeModifiers.ShapeHasIDs; - else - type = ShapeType.ShapeMultiPointM; - } else { - if (bExportIDs) - type = ShapeType.ShapeGeneralMultiPoint - | ShapeModifiers.ShapeHasZs | ShapeModifiers.ShapeHasMs - | ShapeModifiers.ShapeHasIDs; - else - type = ShapeType.ShapeMultiPointZM; - } - - // write type - int offset = 0; - - shapeBuffer.putInt(offset, type); - offset += 4; - - // write Envelope - Envelope2D env = new Envelope2D(); - multipointImpl.queryEnvelope2D(env); // calls _VerifyAllStreams - shapeBuffer.putDouble(offset, env.xmin); - offset += 8; - shapeBuffer.putDouble(offset, env.ymin); - offset += 8; - shapeBuffer.putDouble(offset, env.xmax); - offset += 8; - shapeBuffer.putDouble(offset, env.ymax); - offset += 8; - - // write point count - shapeBuffer.putInt(offset, pointCount); - offset += 4; - - if (pointCount > 0) { - // write xy coordinates - AttributeStreamBase positionStream = multipointImpl - .getAttributeStreamRef(Semantics.POSITION); - AttributeStreamOfDbl position = (AttributeStreamOfDbl) positionStream; - for (int i = 0; i < pointCount; i++) { - double x = position.read(2 * i); - double y = position.read(2 * i + 1); - shapeBuffer.putDouble(offset, x); - offset += 8; - shapeBuffer.putDouble(offset, y); - offset += 8; - } - } - - // write Zs - if (bExportZs) { - Envelope1D zInterval = multipointImpl.queryInterval(Semantics.Z, 0); - shapeBuffer.putDouble(offset, - bArcViewNaNs ? Interop.translateToAVNaN(zInterval.vmin) - : zInterval.vmin); - offset += 8; - shapeBuffer.putDouble(offset, - bArcViewNaNs ? Interop.translateToAVNaN(zInterval.vmax) - : zInterval.vmax); - offset += 8; - - if (pointCount > 0) { - if (multipointImpl._attributeStreamIsAllocated(Semantics.Z)) { - AttributeStreamOfDbl zs = (AttributeStreamOfDbl) multipointImpl - .getAttributeStreamRef(Semantics.Z); - for (int i = 0; i < pointCount; i++) { - double z = zs.read(i); - shapeBuffer.putDouble(offset, - bArcViewNaNs ? Interop.translateToAVNaN(z) : z); - offset += 8; - } - } else { - double z = VertexDescription.getDefaultValue(Semantics.Z); - - if (bArcViewNaNs) - z = Interop.translateToAVNaN(z); - - // Can we write a function that writes all these values at - // once instead of doing a for loop? - for (int i = 0; i < pointCount; i++) - shapeBuffer.putDouble(offset, z); - offset += 8; - } - } - } - - // write Ms - if (bExportMs) { - Envelope1D mInterval = multipointImpl.queryInterval(Semantics.M, 0); - shapeBuffer.putDouble(offset, - bArcViewNaNs ? Interop.translateToAVNaN(mInterval.vmin) - : mInterval.vmin); - offset += 8; - shapeBuffer.putDouble(offset, - bArcViewNaNs ? Interop.translateToAVNaN(mInterval.vmax) - : mInterval.vmax); - offset += 8; - - if (pointCount > 0) { - if (multipointImpl._attributeStreamIsAllocated(Semantics.M)) { - AttributeStreamOfDbl ms = (AttributeStreamOfDbl) multipointImpl - .getAttributeStreamRef(Semantics.M); - for (int i = 0; i < pointCount; i++) { - double m = ms.read(i); - shapeBuffer.putDouble(offset, - bArcViewNaNs ? Interop.translateToAVNaN(m) : m); - offset += 8; - } - } else { - double m = VertexDescription.getDefaultValue(Semantics.M); - - if (bArcViewNaNs) - m = Interop.translateToAVNaN(m); - - for (int i = 0; i < pointCount; i++) - shapeBuffer.putDouble(offset, m); - offset += 8; - } - } - } - - // write IDs - if (bExportIDs) { - if (pointCount > 0) { - if (multipointImpl._attributeStreamIsAllocated(Semantics.ID)) { - AttributeStreamOfInt32 ids = (AttributeStreamOfInt32) multipointImpl - .getAttributeStreamRef(Semantics.ID); - for (int i = 0; i < pointCount; i++) { - int id = ids.read(i); - shapeBuffer.putInt(offset, id); - offset += 4; - } - } else { - int id = (int) VertexDescription - .getDefaultValue(Semantics.ID); - for (int i = 0; i < pointCount; i++) - shapeBuffer.putInt(offset, id); - offset += 4; - } - } - } - - return offset; - } - - private static int exportMultiPathToESRIShape(boolean bPolygon, - int exportFlags, MultiPath multipath, ByteBuffer shapeBuffer) { - MultiPathImpl multipathImpl = (MultiPathImpl) multipath._getImpl(); - - boolean bExportZs = multipathImpl.hasAttribute(Semantics.Z) - && (exportFlags & ShapeExportFlags.ShapeExportStripZs) == 0; - boolean bExportMs = multipathImpl.hasAttribute(Semantics.M) - && (exportFlags & ShapeExportFlags.ShapeExportStripMs) == 0; - boolean bExportIDs = multipathImpl.hasAttribute(Semantics.ID) - && (exportFlags & ShapeExportFlags.ShapeExportStripIDs) == 0; - boolean bHasCurves = multipathImpl.hasNonLinearSegments(); - boolean bArcViewNaNs = (exportFlags & ShapeExportFlags.ShapeExportTrueNaNs) == 0; - - int partCount = multipathImpl.getPathCount(); - int pointCount = multipathImpl.getPointCount(); - - if (!bPolygon) { - for (int ipart = 0; ipart < partCount; ipart++) - if (multipath.isClosedPath(ipart)) - pointCount++; - } else - pointCount += partCount; - - int size = (4 /* type */) + (4 * 8 /* envelope */) + (4 /* part count */) - + (4 /* point count */) + (partCount * 4 /* start indices */) - + pointCount * 2 * 8 /* xy coordinates */; - - if (bExportZs) - size += (2 * 8 /* min max */) + (pointCount * 8 /* zs */); - if (bExportMs) - size += (2 * 8 /* min max */) + (pointCount * 8 /* ms */); - if (bExportIDs) - size += pointCount * 4 /* ids */; - if (bHasCurves) { - // to-do: curves - } - - if (size >= NumberUtils.intMax()) - throw new GeometryException("invalid call"); - - if (shapeBuffer == null) - return size; - else if (shapeBuffer.capacity() < size) - throw new GeometryException("buffer is too small"); - - int offset = 0; - - // Determine the shape type - int type; - if (!bExportZs && !bExportMs) { - if (bExportIDs || bHasCurves) { - type = bPolygon ? ShapeType.ShapeGeneralPolygon - : ShapeType.ShapeGeneralPolyline; - if (bExportIDs) - type |= ShapeModifiers.ShapeHasIDs; - if (bHasCurves) - type |= ShapeModifiers.ShapeHasCurves; - } else - type = bPolygon ? ShapeType.ShapePolygon - : ShapeType.ShapePolyline; - } else if (bExportZs && !bExportMs) { - if (bExportIDs || bHasCurves) { - type = bPolygon ? ShapeType.ShapeGeneralPolygon - : ShapeType.ShapeGeneralPolyline; - type |= ShapeModifiers.ShapeHasZs; - if (bExportIDs) - type |= ShapeModifiers.ShapeHasIDs; - if (bHasCurves) - type |= ShapeModifiers.ShapeHasCurves; - } else - type = bPolygon ? ShapeType.ShapePolygonZ - : ShapeType.ShapePolylineZ; - } else if (bExportMs && !bExportZs) { - if (bExportIDs || bHasCurves) { - type = bPolygon ? ShapeType.ShapeGeneralPolygon - : ShapeType.ShapeGeneralPolyline; - type |= ShapeModifiers.ShapeHasMs; - if (bExportIDs) - type |= ShapeModifiers.ShapeHasIDs; - if (bHasCurves) - type |= ShapeModifiers.ShapeHasCurves; - } else - type = bPolygon ? ShapeType.ShapePolygonM - : ShapeType.ShapePolylineM; - } else { - if (bExportIDs || bHasCurves) { - type = bPolygon ? ShapeType.ShapeGeneralPolygon - : ShapeType.ShapeGeneralPolyline; - type |= ShapeModifiers.ShapeHasZs | ShapeModifiers.ShapeHasMs; - if (bExportIDs) - type |= ShapeModifiers.ShapeHasIDs; - if (bHasCurves) - type |= ShapeModifiers.ShapeHasCurves; - } else - type = bPolygon ? ShapeType.ShapePolygonZM - : ShapeType.ShapePolylineZM; - } - - // write type - shapeBuffer.putInt(offset, type); - offset += 4; - - // write Envelope - Envelope2D env = new Envelope2D(); - multipathImpl.queryEnvelope2D(env); // calls _VerifyAllStreams - shapeBuffer.putDouble(offset, env.xmin); - offset += 8; - shapeBuffer.putDouble(offset, env.ymin); - offset += 8; - shapeBuffer.putDouble(offset, env.xmax); - offset += 8; - shapeBuffer.putDouble(offset, env.ymax); - offset += 8; - - // write part count - shapeBuffer.putInt(offset, partCount); - offset += 4; // to-do: return error if larger than 2^32 - 1 - - // write pointCount - shapeBuffer.putInt(offset, pointCount); - offset += 4; - - // write start indices for each part - int pointIndexDelta = 0; - for (int ipart = 0; ipart < partCount; ipart++) { - int istart = multipathImpl.getPathStart(ipart) + pointIndexDelta; - shapeBuffer.putInt(offset, istart); - offset += 4; - if (bPolygon || multipathImpl.isClosedPath(ipart)) - pointIndexDelta++; - } - - if (pointCount > 0) { - // write xy coordinates - AttributeStreamBase positionStream = multipathImpl - .getAttributeStreamRef(Semantics.POSITION); - AttributeStreamOfDbl position = (AttributeStreamOfDbl) positionStream; - - for (int ipart = 0; ipart < partCount; ipart++) { - int partStart = multipathImpl.getPathStart(ipart); - int partEnd = multipathImpl.getPathEnd(ipart); - for (int i = partStart; i < partEnd; i++) { - double x = position.read(2 * i); - double y = position.read(2 * i + 1); - - shapeBuffer.putDouble(offset, x); - offset += 8; - shapeBuffer.putDouble(offset, y); - offset += 8; - } - - // If the part is closed, then we need to duplicate the start - // point - if (bPolygon || multipathImpl.isClosedPath(ipart)) { - double x = position.read(2 * partStart); - double y = position.read(2 * partStart + 1); - - shapeBuffer.putDouble(offset, x); - offset += 8; - shapeBuffer.putDouble(offset, y); - offset += 8; - } - } - } - - // write Zs - if (bExportZs) { - Envelope1D zInterval = multipathImpl.queryInterval(Semantics.Z, 0); - shapeBuffer.putDouble(offset, - bArcViewNaNs ? Interop.translateToAVNaN(zInterval.vmin) - : zInterval.vmin); - offset += 8; - shapeBuffer.putDouble(offset, - bArcViewNaNs ? Interop.translateToAVNaN(zInterval.vmax) - : zInterval.vmax); - offset += 8; - - if (pointCount > 0) { - if (multipathImpl._attributeStreamIsAllocated(Semantics.Z)) { - AttributeStreamOfDbl zs = (AttributeStreamOfDbl) multipathImpl - .getAttributeStreamRef(Semantics.Z); - for (int ipart = 0; ipart < partCount; ipart++) { - int partStart = multipathImpl.getPathStart(ipart); - int partEnd = multipathImpl.getPathEnd(ipart); - for (int i = partStart; i < partEnd; i++) { - double z = zs.read(i); - shapeBuffer.putDouble(offset, - bArcViewNaNs ? Interop.translateToAVNaN(z) - : z); - offset += 8; - } - - // If the part is closed, then we need to duplicate the - // start z - if (bPolygon || multipathImpl.isClosedPath(ipart)) { - double z = zs.read(partStart); - shapeBuffer.putDouble(offset, z); - offset += 8; - } - } - } else { - double z = VertexDescription.getDefaultValue(Semantics.Z); - - if (bArcViewNaNs) - z = Interop.translateToAVNaN(z); - - for (int i = 0; i < pointCount; i++) - shapeBuffer.putDouble(offset, z); - offset += 8; - } - } - } - - // write Ms - if (bExportMs) { - Envelope1D mInterval = multipathImpl.queryInterval(Semantics.M, 0); - shapeBuffer.putDouble(offset, - bArcViewNaNs ? Interop.translateToAVNaN(mInterval.vmin) - : mInterval.vmin); - offset += 8; - shapeBuffer.putDouble(offset, - bArcViewNaNs ? Interop.translateToAVNaN(mInterval.vmax) - : mInterval.vmax); - offset += 8; - - if (pointCount > 0) { - if (multipathImpl._attributeStreamIsAllocated(Semantics.M)) { - AttributeStreamOfDbl ms = (AttributeStreamOfDbl) multipathImpl - .getAttributeStreamRef(Semantics.M); - for (int ipart = 0; ipart < partCount; ipart++) { - int partStart = multipathImpl.getPathStart(ipart); - int partEnd = multipathImpl.getPathEnd(ipart); - for (int i = partStart; i < partEnd; i++) { - double m = ms.read(i); - shapeBuffer.putDouble(offset, - bArcViewNaNs ? Interop.translateToAVNaN(m) - : m); - offset += 8; - } - - // If the part is closed, then we need to duplicate the - // start m - if (bPolygon || multipathImpl.isClosedPath(ipart)) { - double m = ms.read(partStart); - shapeBuffer.putDouble(offset, m); - offset += 8; - } - } - } else { - double m = VertexDescription.getDefaultValue(Semantics.M); - - if (bArcViewNaNs) - m = Interop.translateToAVNaN(m); - - for (int i = 0; i < pointCount; i++) - shapeBuffer.putDouble(offset, m); - offset += 8; - } - } - } - - // write Curves - if (bHasCurves) { - // to-do: We'll finish this later - } - - // write IDs - if (bExportIDs) { - if (pointCount > 0) { - if (multipathImpl._attributeStreamIsAllocated(Semantics.ID)) { - AttributeStreamOfInt32 ids = (AttributeStreamOfInt32) multipathImpl - .getAttributeStreamRef(Semantics.ID); - for (int ipart = 0; ipart < partCount; ipart++) { - int partStart = multipathImpl.getPathStart(ipart); - int partEnd = multipathImpl.getPathEnd(ipart); - for (int i = partStart; i < partEnd; i++) { - int id = ids.read(i); - shapeBuffer.putInt(offset, id); - offset += 4; - } - - // If the part is closed, then we need to duplicate the - // start id - if (bPolygon || multipathImpl.isClosedPath(ipart)) { - int id = ids.read(partStart); - shapeBuffer.putInt(offset, id); - offset += 4; - } - } - } else { - int id = (int) VertexDescription - .getDefaultValue(Semantics.ID); - for (int i = 0; i < pointCount; i++) - shapeBuffer.putInt(offset, id); - offset += 4; - } - } - } - - return offset; - } + private GeometryCursor m_geometryCursor; + private int m_exportFlags; + private ByteBuffer m_shapeBuffer; + private SimpleStateEnum simpleStateEnum = SimpleStateEnum.SIMPLE_UNKNOWN; + + public OperatorExportToESRIShapeCursor(int exportFlags, GeometryCursor geometryCursor) { + if (geometryCursor == null) + throw new GeometryException("invalid argument"); + + m_exportFlags = exportFlags; + m_geometryCursor = geometryCursor; + m_shapeBuffer = null; + } + + @Override + public long getByteBufferID() { + return m_geometryCursor.getGeometryID(); + } + + @Override + public SimpleStateEnum getSimpleState() { + return simpleStateEnum; + } + + @Override + public String getFeatureID() { + return m_geometryCursor.getFeatureID(); + } + + @Override + public boolean hasNext() { + return m_geometryCursor != null && m_geometryCursor.hasNext(); + } + + @Override + public ByteBuffer next() { + Geometry geometry; + if (hasNext()) { + geometry = m_geometryCursor.next(); + simpleStateEnum = geometry.getSimpleState(); + int size = exportToESRIShape(m_exportFlags, geometry, null); + if (m_shapeBuffer == null || size > m_shapeBuffer.capacity()) + m_shapeBuffer = ByteBuffer.allocate(size).order( + ByteOrder.LITTLE_ENDIAN); + exportToESRIShape(m_exportFlags, geometry, m_shapeBuffer); + return m_shapeBuffer; + } + return null; + } + + static int exportToESRIShape(int exportFlags, Geometry geometry, + ByteBuffer shapeBuffer) { + if (geometry == null) { + if (shapeBuffer != null) + shapeBuffer.putInt(0, ShapeType.ShapeNull); + + return 4; + } + + int type = geometry.getType().value(); + switch (type) { + case Geometry.GeometryType.Polygon: + return exportMultiPathToESRIShape(true, exportFlags, + (MultiPath) geometry, shapeBuffer); + case Geometry.GeometryType.Polyline: + return exportMultiPathToESRIShape(false, exportFlags, + (MultiPath) geometry, shapeBuffer); + case Geometry.GeometryType.MultiPoint: + return exportMultiPointToESRIShape(exportFlags, + (MultiPoint) geometry, shapeBuffer); + case Geometry.GeometryType.Point: + return exportPointToESRIShape(exportFlags, (Point) geometry, + shapeBuffer); + case Geometry.GeometryType.Envelope: + return exportEnvelopeToESRIShape(exportFlags, (Envelope) geometry, + shapeBuffer); + default: { + throw GeometryException.GeometryInternalError(); + // return -1; + } + } + } + + private static int exportEnvelopeToESRIShape(int exportFlags, + Envelope envelope, ByteBuffer shapeBuffer) { + boolean bExportZs = envelope.hasAttribute(Semantics.Z) + && (exportFlags & ShapeExportFlags.ShapeExportStripZs) == 0; + boolean bExportMs = envelope.hasAttribute(Semantics.M) + && (exportFlags & ShapeExportFlags.ShapeExportStripMs) == 0; + boolean bExportIDs = envelope.hasAttribute(Semantics.ID) + && (exportFlags & ShapeExportFlags.ShapeExportStripIDs) == 0; + boolean bArcViewNaNs = (exportFlags & ShapeExportFlags.ShapeExportTrueNaNs) == 0; + + boolean bEmpty = envelope.isEmpty(); + int partCount = bEmpty ? 0 : 1; + int pointCount = bEmpty ? 0 : 5; + + int size = (4 /* type */) + (4 * 8 /* envelope */) + (4 /* part count */) + + (4 /* point count */) + (partCount * 4 /* start indices */) + + pointCount * 2 * 8 /* xy coordinates */; + + if (bExportZs) + size += (2 * 8 /* min max */) + (pointCount * 8 /* zs */); + if (bExportMs) + size += (2 * 8 /* min max */) + (pointCount * 8 /* ms */); + if (bExportIDs) + size += (pointCount * 4 /* ids */); + + if (shapeBuffer == null) + return size; + else if (shapeBuffer.capacity() < size) + throw new GeometryException("buffer is too small"); + + int type; + + // Determine the shape type + if (!bExportZs && !bExportMs) { + if (bExportIDs) + type = ShapeType.ShapeGeneralPolygon + | ShapeModifiers.ShapeHasIDs; + else + type = ShapeType.ShapePolygon; + } else if (bExportZs && !bExportMs) { + if (bExportIDs) + type = ShapeType.ShapeGeneralPolygon + | ShapeModifiers.ShapeHasZs + | ShapeModifiers.ShapeHasIDs; + else + type = ShapeType.ShapePolygonZ; + } else if (bExportMs && !bExportZs) { + if (bExportIDs) + type = ShapeType.ShapeGeneralPolygon + | ShapeModifiers.ShapeHasMs + | ShapeModifiers.ShapeHasIDs; + else + type = ShapeType.ShapePolygonM; + } else { + if (bExportIDs) + type = ShapeType.ShapeGeneralPolygon + | ShapeModifiers.ShapeHasZs | ShapeModifiers.ShapeHasMs + | ShapeModifiers.ShapeHasIDs; + else + type = ShapeType.ShapePolygonZM; + } + + int offset = 0; + + // write type + shapeBuffer.putInt(offset, type); + offset += 4; + + // write Envelope + Envelope2D env = new Envelope2D(); + envelope.queryEnvelope2D(env); // calls _VerifyAllStreams + shapeBuffer.putDouble(offset, env.xmin); + offset += 8; + shapeBuffer.putDouble(offset, env.ymin); + offset += 8; + shapeBuffer.putDouble(offset, env.xmax); + offset += 8; + shapeBuffer.putDouble(offset, env.ymax); + offset += 8; + + // write part count + shapeBuffer.putInt(offset, partCount); + offset += 4; + + // write pointCount + shapeBuffer.putInt(offset, pointCount); + offset += 4; + + if (!bEmpty) { + // write start index + shapeBuffer.putInt(offset, 0); + offset += 4; + + // write xy coordinates + shapeBuffer.putDouble(offset, env.xmin); + offset += 8; + shapeBuffer.putDouble(offset, env.ymin); + offset += 8; + + shapeBuffer.putDouble(offset, env.xmin); + offset += 8; + shapeBuffer.putDouble(offset, env.ymax); + offset += 8; + + shapeBuffer.putDouble(offset, env.xmax); + offset += 8; + shapeBuffer.putDouble(offset, env.ymax); + offset += 8; + + shapeBuffer.putDouble(offset, env.xmax); + offset += 8; + shapeBuffer.putDouble(offset, env.ymin); + offset += 8; + + shapeBuffer.putDouble(offset, env.xmin); + offset += 8; + shapeBuffer.putDouble(offset, env.ymin); + offset += 8; + } + // write Zs + if (bExportZs) { + Envelope1D zInterval; + zInterval = envelope.queryInterval(Semantics.Z, 0); + + double zmin = bArcViewNaNs ? Interop + .translateToAVNaN(zInterval.vmin) : zInterval.vmin; + double zmax = bArcViewNaNs ? Interop + .translateToAVNaN(zInterval.vmax) : zInterval.vmax; + + // write min max values + shapeBuffer.putDouble(offset, zmin); + offset += 8; + shapeBuffer.putDouble(offset, zmax); + offset += 8; + + if (!bEmpty) { + // write arbitrary z values + shapeBuffer.putDouble(offset, zmin); + offset += 8; + shapeBuffer.putDouble(offset, zmax); + offset += 8; + shapeBuffer.putDouble(offset, zmin); + offset += 8; + shapeBuffer.putDouble(offset, zmax); + offset += 8; + shapeBuffer.putDouble(offset, zmin); + offset += 8; + } + } + // write Ms + if (bExportMs) { + Envelope1D mInterval; + mInterval = envelope.queryInterval(Semantics.M, 0); + + double mmin = bArcViewNaNs ? Interop + .translateToAVNaN(mInterval.vmin) : mInterval.vmin; + double mmax = bArcViewNaNs ? Interop + .translateToAVNaN(mInterval.vmax) : mInterval.vmax; + + // write min max values + shapeBuffer.putDouble(offset, mmin); + offset += 8; + shapeBuffer.putDouble(offset, mmax); + offset += 8; + + if (!bEmpty) { + // write arbitrary m values + shapeBuffer.putDouble(offset, mmin); + offset += 8; + shapeBuffer.putDouble(offset, mmax); + offset += 8; + shapeBuffer.putDouble(offset, mmin); + offset += 8; + shapeBuffer.putDouble(offset, mmax); + offset += 8; + shapeBuffer.putDouble(offset, mmin); + offset += 8; + } + } + + // write IDs + if (bExportIDs && !bEmpty) { + Envelope1D idInterval; + idInterval = envelope.queryInterval(Semantics.ID, 0); + + int idmin = (int) idInterval.vmin; + int idmax = (int) idInterval.vmax; + + // write arbitrary id values + shapeBuffer.putInt(offset, idmin); + offset += 4; + shapeBuffer.putInt(offset, idmax); + offset += 4; + shapeBuffer.putInt(offset, idmin); + offset += 4; + shapeBuffer.putInt(offset, idmax); + offset += 4; + shapeBuffer.putInt(offset, idmin); + offset += 4; + } + + return offset; + } + + private static int exportPointToESRIShape(int exportFlags, Point point, + ByteBuffer shapeBuffer) { + boolean bExportZ = point.hasAttribute(Semantics.Z) + && (exportFlags & ShapeExportFlags.ShapeExportStripZs) == 0; + boolean bExportM = point.hasAttribute(Semantics.M) + && (exportFlags & ShapeExportFlags.ShapeExportStripMs) == 0; + boolean bExportID = point.hasAttribute(Semantics.ID) + && (exportFlags & ShapeExportFlags.ShapeExportStripIDs) == 0; + boolean bArcViewNaNs = (exportFlags & ShapeExportFlags.ShapeExportTrueNaNs) == 0; + + int size = (4 /* type */) + (2 * 8 /* xy coordinate */); + + if (bExportZ) + size += 8; + if (bExportM) + size += 8; + if (bExportID) + size += 4; + + if (shapeBuffer == null) + return size; + else if (shapeBuffer.capacity() < size) + throw new GeometryException("buffer is too small"); + + int type; + + // Determine the shape type + if (!bExportZ && !bExportM) { + if (bExportID) + type = ShapeType.ShapeGeneralPoint | ShapeModifiers.ShapeHasIDs; + else + type = ShapeType.ShapePoint; + } else if (bExportZ && !bExportM) { + if (bExportID) + type = ShapeType.ShapeGeneralPoint | ShapeModifiers.ShapeHasZs + | ShapeModifiers.ShapeHasIDs; + else + type = ShapeType.ShapePointZ; + } else if (bExportM && !bExportZ) { + if (bExportID) + type = ShapeType.ShapeGeneralPoint | ShapeModifiers.ShapeHasMs + | ShapeModifiers.ShapeHasIDs; + else + type = ShapeType.ShapePointM; + } else { + if (bExportID) + type = ShapeType.ShapeGeneralPoint | ShapeModifiers.ShapeHasZs + | ShapeModifiers.ShapeHasMs + | ShapeModifiers.ShapeHasIDs; + else + type = ShapeType.ShapePointZM; + } + + int offset = 0; + + // write type + + shapeBuffer.putInt(offset, type); + offset += 4; + + boolean bEmpty = point.isEmpty(); + + // write xy + double x = !bEmpty ? point.getX() : NumberUtils.NaN(); + double y = !bEmpty ? point.getY() : NumberUtils.NaN(); + shapeBuffer.putDouble(offset, + bArcViewNaNs ? Interop.translateToAVNaN(x) : x); + offset += 8; + shapeBuffer.putDouble(offset, + bArcViewNaNs ? Interop.translateToAVNaN(y) : y); + offset += 8; + + // write Z + if (bExportZ) { + double z = !bEmpty ? point.getZ() : NumberUtils.NaN(); + shapeBuffer.putDouble(offset, + bArcViewNaNs ? Interop.translateToAVNaN(z) : z); + offset += 8; + } + + // WriteM + if (bExportM) { + double m = !bEmpty ? point.getM() : NumberUtils.NaN(); + shapeBuffer.putDouble(offset, + bArcViewNaNs ? Interop.translateToAVNaN(m) : m); + offset += 8; + } + + // write ID + if (bExportID) { + int id = !bEmpty ? point.getID() : 0; + shapeBuffer.putInt(offset, id); + offset += 4; + } + + return offset; + } + + private static int exportMultiPointToESRIShape(int exportFlags, + MultiPoint multipoint, ByteBuffer shapeBuffer) { + MultiPointImpl multipointImpl = (MultiPointImpl) multipoint._getImpl(); + boolean bExportZs = multipointImpl.hasAttribute(Semantics.Z) + && (exportFlags & ShapeExportFlags.ShapeExportStripZs) == 0; + boolean bExportMs = multipointImpl.hasAttribute(Semantics.M) + && (exportFlags & ShapeExportFlags.ShapeExportStripMs) == 0; + boolean bExportIDs = multipointImpl.hasAttribute(Semantics.ID) + && (exportFlags & ShapeExportFlags.ShapeExportStripIDs) == 0; + boolean bArcViewNaNs = (exportFlags & ShapeExportFlags.ShapeExportTrueNaNs) == 0; + + int pointCount = multipointImpl.getPointCount(); + + int size = (4 /* type */) + (4 * 8 /* envelope */) + (4 /* point count */) + + (pointCount * 2 * 8 /* xy coordinates */); + + if (bExportZs) + size += (2 * 8 /* min max */) + (pointCount * 8 /* zs */); + if (bExportMs) + size += (2 * 8 /* min max */) + (pointCount * 8 /* ms */); + if (bExportIDs) + size += pointCount * 4 /* ids */; + + if (size >= NumberUtils.intMax()) + throw new GeometryException("invalid call"); + + if (shapeBuffer == null) + return size; + else if (shapeBuffer.capacity() < size) + throw new GeometryException("buffer is too small"); + + int type; + + // Determine the shape type + if (!bExportZs && !bExportMs) { + if (bExportIDs) + type = ShapeType.ShapeGeneralMultiPoint + | ShapeModifiers.ShapeHasIDs; + else + type = ShapeType.ShapeMultiPoint; + } else if (bExportZs && !bExportMs) { + if (bExportIDs) + type = ShapeType.ShapeGeneralMultiPoint + | ShapeModifiers.ShapeHasZs + | ShapeModifiers.ShapeHasIDs; + else + type = ShapeType.ShapeMultiPointZ; + } else if (bExportMs && !bExportZs) { + if (bExportIDs) + type = ShapeType.ShapeGeneralMultiPoint + | ShapeModifiers.ShapeHasMs + | ShapeModifiers.ShapeHasIDs; + else + type = ShapeType.ShapeMultiPointM; + } else { + if (bExportIDs) + type = ShapeType.ShapeGeneralMultiPoint + | ShapeModifiers.ShapeHasZs | ShapeModifiers.ShapeHasMs + | ShapeModifiers.ShapeHasIDs; + else + type = ShapeType.ShapeMultiPointZM; + } + + // write type + int offset = 0; + + shapeBuffer.putInt(offset, type); + offset += 4; + + // write Envelope + Envelope2D env = new Envelope2D(); + multipointImpl.queryEnvelope2D(env); // calls _VerifyAllStreams + shapeBuffer.putDouble(offset, env.xmin); + offset += 8; + shapeBuffer.putDouble(offset, env.ymin); + offset += 8; + shapeBuffer.putDouble(offset, env.xmax); + offset += 8; + shapeBuffer.putDouble(offset, env.ymax); + offset += 8; + + // write point count + shapeBuffer.putInt(offset, pointCount); + offset += 4; + + if (pointCount > 0) { + // write xy coordinates + AttributeStreamBase positionStream = multipointImpl + .getAttributeStreamRef(Semantics.POSITION); + AttributeStreamOfDbl position = (AttributeStreamOfDbl) positionStream; + for (int i = 0; i < pointCount; i++) { + double x = position.read(2 * i); + double y = position.read(2 * i + 1); + shapeBuffer.putDouble(offset, x); + offset += 8; + shapeBuffer.putDouble(offset, y); + offset += 8; + } + } + + // write Zs + if (bExportZs) { + Envelope1D zInterval = multipointImpl.queryInterval(Semantics.Z, 0); + shapeBuffer.putDouble(offset, + bArcViewNaNs ? Interop.translateToAVNaN(zInterval.vmin) + : zInterval.vmin); + offset += 8; + shapeBuffer.putDouble(offset, + bArcViewNaNs ? Interop.translateToAVNaN(zInterval.vmax) + : zInterval.vmax); + offset += 8; + + if (pointCount > 0) { + if (multipointImpl._attributeStreamIsAllocated(Semantics.Z)) { + AttributeStreamOfDbl zs = (AttributeStreamOfDbl) multipointImpl + .getAttributeStreamRef(Semantics.Z); + for (int i = 0; i < pointCount; i++) { + double z = zs.read(i); + shapeBuffer.putDouble(offset, + bArcViewNaNs ? Interop.translateToAVNaN(z) : z); + offset += 8; + } + } else { + double z = VertexDescription.getDefaultValue(Semantics.Z); + + if (bArcViewNaNs) + z = Interop.translateToAVNaN(z); + + // Can we write a function that writes all these values at + // once instead of doing a for loop? + for (int i = 0; i < pointCount; i++) + shapeBuffer.putDouble(offset, z); + offset += 8; + } + } + } + + // write Ms + if (bExportMs) { + Envelope1D mInterval = multipointImpl.queryInterval(Semantics.M, 0); + shapeBuffer.putDouble(offset, + bArcViewNaNs ? Interop.translateToAVNaN(mInterval.vmin) + : mInterval.vmin); + offset += 8; + shapeBuffer.putDouble(offset, + bArcViewNaNs ? Interop.translateToAVNaN(mInterval.vmax) + : mInterval.vmax); + offset += 8; + + if (pointCount > 0) { + if (multipointImpl._attributeStreamIsAllocated(Semantics.M)) { + AttributeStreamOfDbl ms = (AttributeStreamOfDbl) multipointImpl + .getAttributeStreamRef(Semantics.M); + for (int i = 0; i < pointCount; i++) { + double m = ms.read(i); + shapeBuffer.putDouble(offset, + bArcViewNaNs ? Interop.translateToAVNaN(m) : m); + offset += 8; + } + } else { + double m = VertexDescription.getDefaultValue(Semantics.M); + + if (bArcViewNaNs) + m = Interop.translateToAVNaN(m); + + for (int i = 0; i < pointCount; i++) + shapeBuffer.putDouble(offset, m); + offset += 8; + } + } + } + + // write IDs + if (bExportIDs) { + if (pointCount > 0) { + if (multipointImpl._attributeStreamIsAllocated(Semantics.ID)) { + AttributeStreamOfInt32 ids = (AttributeStreamOfInt32) multipointImpl + .getAttributeStreamRef(Semantics.ID); + for (int i = 0; i < pointCount; i++) { + int id = ids.read(i); + shapeBuffer.putInt(offset, id); + offset += 4; + } + } else { + int id = (int) VertexDescription + .getDefaultValue(Semantics.ID); + for (int i = 0; i < pointCount; i++) + shapeBuffer.putInt(offset, id); + offset += 4; + } + } + } + + return offset; + } + + private static int exportMultiPathToESRIShape(boolean bPolygon, + int exportFlags, MultiPath multipath, ByteBuffer shapeBuffer) { + MultiPathImpl multipathImpl = (MultiPathImpl) multipath._getImpl(); + + boolean bExportZs = multipathImpl.hasAttribute(Semantics.Z) + && (exportFlags & ShapeExportFlags.ShapeExportStripZs) == 0; + boolean bExportMs = multipathImpl.hasAttribute(Semantics.M) + && (exportFlags & ShapeExportFlags.ShapeExportStripMs) == 0; + boolean bExportIDs = multipathImpl.hasAttribute(Semantics.ID) + && (exportFlags & ShapeExportFlags.ShapeExportStripIDs) == 0; + boolean bHasCurves = multipathImpl.hasNonLinearSegments(); + boolean bArcViewNaNs = (exportFlags & ShapeExportFlags.ShapeExportTrueNaNs) == 0; + + int partCount = multipathImpl.getPathCount(); + int pointCount = multipathImpl.getPointCount(); + + if (!bPolygon) { + for (int ipart = 0; ipart < partCount; ipart++) + if (multipath.isClosedPath(ipart)) + pointCount++; + } else + pointCount += partCount; + + int size = (4 /* type */) + (4 * 8 /* envelope */) + (4 /* part count */) + + (4 /* point count */) + (partCount * 4 /* start indices */) + + pointCount * 2 * 8 /* xy coordinates */; + + if (bExportZs) + size += (2 * 8 /* min max */) + (pointCount * 8 /* zs */); + if (bExportMs) + size += (2 * 8 /* min max */) + (pointCount * 8 /* ms */); + if (bExportIDs) + size += pointCount * 4 /* ids */; + if (bHasCurves) { + // to-do: curves + } + + if (size >= NumberUtils.intMax()) + throw new GeometryException("invalid call"); + + if (shapeBuffer == null) + return size; + else if (shapeBuffer.capacity() < size) + throw new GeometryException("buffer is too small"); + + int offset = 0; + + // Determine the shape type + int type; + if (!bExportZs && !bExportMs) { + if (bExportIDs || bHasCurves) { + type = bPolygon ? ShapeType.ShapeGeneralPolygon + : ShapeType.ShapeGeneralPolyline; + if (bExportIDs) + type |= ShapeModifiers.ShapeHasIDs; + if (bHasCurves) + type |= ShapeModifiers.ShapeHasCurves; + } else + type = bPolygon ? ShapeType.ShapePolygon + : ShapeType.ShapePolyline; + } else if (bExportZs && !bExportMs) { + if (bExportIDs || bHasCurves) { + type = bPolygon ? ShapeType.ShapeGeneralPolygon + : ShapeType.ShapeGeneralPolyline; + type |= ShapeModifiers.ShapeHasZs; + if (bExportIDs) + type |= ShapeModifiers.ShapeHasIDs; + if (bHasCurves) + type |= ShapeModifiers.ShapeHasCurves; + } else + type = bPolygon ? ShapeType.ShapePolygonZ + : ShapeType.ShapePolylineZ; + } else if (bExportMs && !bExportZs) { + if (bExportIDs || bHasCurves) { + type = bPolygon ? ShapeType.ShapeGeneralPolygon + : ShapeType.ShapeGeneralPolyline; + type |= ShapeModifiers.ShapeHasMs; + if (bExportIDs) + type |= ShapeModifiers.ShapeHasIDs; + if (bHasCurves) + type |= ShapeModifiers.ShapeHasCurves; + } else + type = bPolygon ? ShapeType.ShapePolygonM + : ShapeType.ShapePolylineM; + } else { + if (bExportIDs || bHasCurves) { + type = bPolygon ? ShapeType.ShapeGeneralPolygon + : ShapeType.ShapeGeneralPolyline; + type |= ShapeModifiers.ShapeHasZs | ShapeModifiers.ShapeHasMs; + if (bExportIDs) + type |= ShapeModifiers.ShapeHasIDs; + if (bHasCurves) + type |= ShapeModifiers.ShapeHasCurves; + } else + type = bPolygon ? ShapeType.ShapePolygonZM + : ShapeType.ShapePolylineZM; + } + + // write type + shapeBuffer.putInt(offset, type); + offset += 4; + + // write Envelope + Envelope2D env = new Envelope2D(); + multipathImpl.queryEnvelope2D(env); // calls _VerifyAllStreams + shapeBuffer.putDouble(offset, env.xmin); + offset += 8; + shapeBuffer.putDouble(offset, env.ymin); + offset += 8; + shapeBuffer.putDouble(offset, env.xmax); + offset += 8; + shapeBuffer.putDouble(offset, env.ymax); + offset += 8; + + // write part count + shapeBuffer.putInt(offset, partCount); + offset += 4; // to-do: return error if larger than 2^32 - 1 + + // write pointCount + shapeBuffer.putInt(offset, pointCount); + offset += 4; + + // write start indices for each part + int pointIndexDelta = 0; + for (int ipart = 0; ipart < partCount; ipart++) { + int istart = multipathImpl.getPathStart(ipart) + pointIndexDelta; + shapeBuffer.putInt(offset, istart); + offset += 4; + if (bPolygon || multipathImpl.isClosedPath(ipart)) + pointIndexDelta++; + } + + if (pointCount > 0) { + // write xy coordinates + AttributeStreamBase positionStream = multipathImpl + .getAttributeStreamRef(Semantics.POSITION); + AttributeStreamOfDbl position = (AttributeStreamOfDbl) positionStream; + + for (int ipart = 0; ipart < partCount; ipart++) { + int partStart = multipathImpl.getPathStart(ipart); + int partEnd = multipathImpl.getPathEnd(ipart); + for (int i = partStart; i < partEnd; i++) { + double x = position.read(2 * i); + double y = position.read(2 * i + 1); + + shapeBuffer.putDouble(offset, x); + offset += 8; + shapeBuffer.putDouble(offset, y); + offset += 8; + } + + // If the part is closed, then we need to duplicate the start + // point + if (bPolygon || multipathImpl.isClosedPath(ipart)) { + double x = position.read(2 * partStart); + double y = position.read(2 * partStart + 1); + + shapeBuffer.putDouble(offset, x); + offset += 8; + shapeBuffer.putDouble(offset, y); + offset += 8; + } + } + } + + // write Zs + if (bExportZs) { + Envelope1D zInterval = multipathImpl.queryInterval(Semantics.Z, 0); + shapeBuffer.putDouble(offset, + bArcViewNaNs ? Interop.translateToAVNaN(zInterval.vmin) + : zInterval.vmin); + offset += 8; + shapeBuffer.putDouble(offset, + bArcViewNaNs ? Interop.translateToAVNaN(zInterval.vmax) + : zInterval.vmax); + offset += 8; + + if (pointCount > 0) { + if (multipathImpl._attributeStreamIsAllocated(Semantics.Z)) { + AttributeStreamOfDbl zs = (AttributeStreamOfDbl) multipathImpl + .getAttributeStreamRef(Semantics.Z); + for (int ipart = 0; ipart < partCount; ipart++) { + int partStart = multipathImpl.getPathStart(ipart); + int partEnd = multipathImpl.getPathEnd(ipart); + for (int i = partStart; i < partEnd; i++) { + double z = zs.read(i); + shapeBuffer.putDouble(offset, + bArcViewNaNs ? Interop.translateToAVNaN(z) + : z); + offset += 8; + } + + // If the part is closed, then we need to duplicate the + // start z + if (bPolygon || multipathImpl.isClosedPath(ipart)) { + double z = zs.read(partStart); + shapeBuffer.putDouble(offset, z); + offset += 8; + } + } + } else { + double z = VertexDescription.getDefaultValue(Semantics.Z); + + if (bArcViewNaNs) + z = Interop.translateToAVNaN(z); + + for (int i = 0; i < pointCount; i++) + shapeBuffer.putDouble(offset, z); + offset += 8; + } + } + } + + // write Ms + if (bExportMs) { + Envelope1D mInterval = multipathImpl.queryInterval(Semantics.M, 0); + shapeBuffer.putDouble(offset, + bArcViewNaNs ? Interop.translateToAVNaN(mInterval.vmin) + : mInterval.vmin); + offset += 8; + shapeBuffer.putDouble(offset, + bArcViewNaNs ? Interop.translateToAVNaN(mInterval.vmax) + : mInterval.vmax); + offset += 8; + + if (pointCount > 0) { + if (multipathImpl._attributeStreamIsAllocated(Semantics.M)) { + AttributeStreamOfDbl ms = (AttributeStreamOfDbl) multipathImpl + .getAttributeStreamRef(Semantics.M); + for (int ipart = 0; ipart < partCount; ipart++) { + int partStart = multipathImpl.getPathStart(ipart); + int partEnd = multipathImpl.getPathEnd(ipart); + for (int i = partStart; i < partEnd; i++) { + double m = ms.read(i); + shapeBuffer.putDouble(offset, + bArcViewNaNs ? Interop.translateToAVNaN(m) + : m); + offset += 8; + } + + // If the part is closed, then we need to duplicate the + // start m + if (bPolygon || multipathImpl.isClosedPath(ipart)) { + double m = ms.read(partStart); + shapeBuffer.putDouble(offset, m); + offset += 8; + } + } + } else { + double m = VertexDescription.getDefaultValue(Semantics.M); + + if (bArcViewNaNs) + m = Interop.translateToAVNaN(m); + + for (int i = 0; i < pointCount; i++) + shapeBuffer.putDouble(offset, m); + offset += 8; + } + } + } + + // write Curves + if (bHasCurves) { + // to-do: We'll finish this later + } + + // write IDs + if (bExportIDs) { + if (pointCount > 0) { + if (multipathImpl._attributeStreamIsAllocated(Semantics.ID)) { + AttributeStreamOfInt32 ids = (AttributeStreamOfInt32) multipathImpl + .getAttributeStreamRef(Semantics.ID); + for (int ipart = 0; ipart < partCount; ipart++) { + int partStart = multipathImpl.getPathStart(ipart); + int partEnd = multipathImpl.getPathEnd(ipart); + for (int i = partStart; i < partEnd; i++) { + int id = ids.read(i); + shapeBuffer.putInt(offset, id); + offset += 4; + } + + // If the part is closed, then we need to duplicate the + // start id + if (bPolygon || multipathImpl.isClosedPath(ipart)) { + int id = ids.read(partStart); + shapeBuffer.putInt(offset, id); + offset += 4; + } + } + } else { + int id = (int) VertexDescription + .getDefaultValue(Semantics.ID); + for (int i = 0; i < pointCount; i++) + shapeBuffer.putInt(offset, id); + offset += 4; + } + } + } + + return offset; + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorExportToESRIShapeLocal.java b/src/main/java/com/esri/core/geometry/OperatorExportToESRIShapeLocal.java index ce3c7b4c..071a9428 100644 --- a/src/main/java/com/esri/core/geometry/OperatorExportToESRIShapeLocal.java +++ b/src/main/java/com/esri/core/geometry/OperatorExportToESRIShapeLocal.java @@ -32,23 +32,23 @@ */ class OperatorExportToESRIShapeLocal extends OperatorExportToESRIShape { - @Override - public ByteBufferCursor execute(int exportFlags, GeometryCursor geometryCursor) { - return new OperatorExportToESRIShapeCursor(exportFlags, geometryCursor); - } - - @Override - public ByteBuffer execute(int exportFlags, Geometry geometry) { - ByteBuffer shapeBuffer = null; - int size = OperatorExportToESRIShapeCursor.exportToESRIShape(exportFlags, geometry, shapeBuffer); - shapeBuffer = ByteBuffer.allocate(size).order(ByteOrder.LITTLE_ENDIAN); - OperatorExportToESRIShapeCursor.exportToESRIShape(exportFlags, geometry, shapeBuffer); - return shapeBuffer; - } - - @Override - public int execute(int exportFlags, Geometry geometry, ByteBuffer shapeBuffer) { - shapeBuffer.order(ByteOrder.LITTLE_ENDIAN); - return OperatorExportToESRIShapeCursor.exportToESRIShape(exportFlags, geometry, shapeBuffer); - } + @Override + public ByteBufferCursor execute(int exportFlags, GeometryCursor geometryCursor) { + return new OperatorExportToESRIShapeCursor(exportFlags, geometryCursor); + } + + @Override + public ByteBuffer execute(int exportFlags, Geometry geometry) { + ByteBuffer shapeBuffer = null; + int size = OperatorExportToESRIShapeCursor.exportToESRIShape(exportFlags, geometry, shapeBuffer); + shapeBuffer = ByteBuffer.allocate(size).order(ByteOrder.LITTLE_ENDIAN); + OperatorExportToESRIShapeCursor.exportToESRIShape(exportFlags, geometry, shapeBuffer); + return shapeBuffer; + } + + @Override + public int execute(int exportFlags, Geometry geometry, ByteBuffer shapeBuffer) { + shapeBuffer.order(ByteOrder.LITTLE_ENDIAN); + return OperatorExportToESRIShapeCursor.exportToESRIShape(exportFlags, geometry, shapeBuffer); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorExportToGeoJson.java b/src/main/java/com/esri/core/geometry/OperatorExportToGeoJson.java index 656070de..52af8dfe 100644 --- a/src/main/java/com/esri/core/geometry/OperatorExportToGeoJson.java +++ b/src/main/java/com/esri/core/geometry/OperatorExportToGeoJson.java @@ -28,57 +28,57 @@ * Export to GeoJson format. */ public abstract class OperatorExportToGeoJson extends Operator { - @Override - public Type getType() { - return Type.ExportToGeoJson; - } + @Override + public Type getType() { + return Type.ExportToGeoJson; + } - /** - * Performs the ExportToGeoJson operation - * - * @param spatialReference The SpatialReference of the Geometry. Will be written as "crs":null if the spatialReference is null. - * @param geometryCursor The cursor of geometries to write as GeoJson. - * @return Returns a JsonCursor. - */ - public abstract StringCursor execute(SpatialReference spatialReference, GeometryCursor geometryCursor); + /** + * Performs the ExportToGeoJson operation + * + * @param spatialReference The SpatialReference of the Geometry. Will be written as "crs":null if the spatialReference is null. + * @param geometryCursor The cursor of geometries to write as GeoJson. + * @return Returns a JsonCursor. + */ + public abstract StringCursor execute(SpatialReference spatialReference, GeometryCursor geometryCursor); - /** - * Performs the ExportToGeoJson operation - * - * @param spatialReference The SpatialReference of the Geometry. Will be written as "crs":null if the spatialReference is null. - * @param geometry The Geometry to write as GeoJson. - * @return Returns a string in GeoJson format. - */ - public abstract String execute(SpatialReference spatialReference, Geometry geometry); + /** + * Performs the ExportToGeoJson operation + * + * @param spatialReference The SpatialReference of the Geometry. Will be written as "crs":null if the spatialReference is null. + * @param geometry The Geometry to write as GeoJson. + * @return Returns a string in GeoJson format. + */ + public abstract String execute(SpatialReference spatialReference, Geometry geometry); - /** - * Performs the ExportToGeoJson operation - * - * @param exportFlags Use the {@link GeoJsonExportFlags} interface. - * @param spatialReference The SpatialReference of the Geometry. Will be written as "crs":null if the spatialReference is null. - * @param geometry The Geometry to write as GeoJson. - * @return Returns a string in GeoJson format. - */ - public abstract String execute(int exportFlags, SpatialReference spatialReference, Geometry geometry); + /** + * Performs the ExportToGeoJson operation + * + * @param exportFlags Use the {@link GeoJsonExportFlags} interface. + * @param spatialReference The SpatialReference of the Geometry. Will be written as "crs":null if the spatialReference is null. + * @param geometry The Geometry to write as GeoJson. + * @return Returns a string in GeoJson format. + */ + public abstract String execute(int exportFlags, SpatialReference spatialReference, Geometry geometry); - /** - * Performs the ExportToGeoJson operation. Will not write out a spatial reference or crs tag. Assumes the geometry is in wgs84. - * - * @param geometry The Geometry to write as GeoJson. - * @return Returns a string in GeoJson format. - */ - public abstract String execute(Geometry geometry); + /** + * Performs the ExportToGeoJson operation. Will not write out a spatial reference or crs tag. Assumes the geometry is in wgs84. + * + * @param geometry The Geometry to write as GeoJson. + * @return Returns a string in GeoJson format. + */ + public abstract String execute(Geometry geometry); - /** - * Performs the ExportToGeoJson operation on a spatial reference. - * - * @param export_flags The flags used for the export. - * @param spatial_reference The spatial reference being exported. Cannot be null. - * @return Returns the crs value object. - */ - public abstract String exportSpatialReference(int export_flags, SpatialReference spatial_reference); + /** + * Performs the ExportToGeoJson operation on a spatial reference. + * + * @param export_flags The flags used for the export. + * @param spatial_reference The spatial reference being exported. Cannot be null. + * @return Returns the crs value object. + */ + public abstract String exportSpatialReference(int export_flags, SpatialReference spatial_reference); - public static OperatorExportToGeoJson local() { - return (OperatorExportToGeoJson) OperatorFactoryLocal.getInstance().getOperator(Type.ExportToGeoJson); - } + public static OperatorExportToGeoJson local() { + return (OperatorExportToGeoJson) OperatorFactoryLocal.getInstance().getOperator(Type.ExportToGeoJson); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorExportToGeoJsonCursor.java b/src/main/java/com/esri/core/geometry/OperatorExportToGeoJsonCursor.java index b5713159..33c1e926 100644 --- a/src/main/java/com/esri/core/geometry/OperatorExportToGeoJsonCursor.java +++ b/src/main/java/com/esri/core/geometry/OperatorExportToGeoJsonCursor.java @@ -48,768 +48,770 @@ import com.esri.core.geometry.VertexDescription.Semantics; public class OperatorExportToGeoJsonCursor extends StringCursor { - private GeometryCursor m_geometryCursor; - private SpatialReference m_spatialReference; - private int m_export_flags; - private SimpleStateEnum simpleStateEnum = SimpleStateEnum.SIMPLE_UNKNOWN; - - public OperatorExportToGeoJsonCursor(int export_flags, SpatialReference spatialReference, - GeometryCursor geometryCursor) { - if (geometryCursor == null) - throw new IllegalArgumentException(); - - m_export_flags = export_flags; - m_spatialReference = spatialReference; - m_geometryCursor = geometryCursor; - } + private GeometryCursor m_geometryCursor; + private SpatialReference m_spatialReference; + private int m_export_flags; + private SimpleStateEnum simpleStateEnum = SimpleStateEnum.SIMPLE_UNKNOWN; + + public OperatorExportToGeoJsonCursor(int export_flags, SpatialReference spatialReference, + GeometryCursor geometryCursor) { + if (geometryCursor == null) + throw new IllegalArgumentException(); + + m_export_flags = export_flags; + m_spatialReference = spatialReference; + m_geometryCursor = geometryCursor; + } + + @Override + public boolean hasNext() { + return m_geometryCursor != null && m_geometryCursor.hasNext(); + } + + @Override + public long getID() { + return m_geometryCursor.getGeometryID(); + } - @Override - public boolean hasNext() { return m_geometryCursor != null && m_geometryCursor.hasNext(); } + @Override + public SimpleStateEnum getSimpleState() { + return simpleStateEnum; + } - @Override - public long getID() { - return m_geometryCursor.getGeometryID(); - } + @Override + public String getFeatureID() { + return m_geometryCursor.getFeatureID(); + } - @Override - public SimpleStateEnum getSimpleState() { - return simpleStateEnum; - } + @Override + public String next() { + Geometry geometry; + if (hasNext()) { + geometry = m_geometryCursor.next(); + simpleStateEnum = geometry.getSimpleState(); + return exportToGeoJson(m_export_flags, geometry, m_spatialReference); + } + return null; + } - @Override - public String getFeatureID() { - return m_geometryCursor.getFeatureID(); - } + // Mirrors wkt + static String exportToGeoJson(int export_flags, Geometry geometry, SpatialReference spatial_reference) { - @Override - public String next() { - Geometry geometry; - if (hasNext()) { - geometry = m_geometryCursor.next(); - simpleStateEnum = geometry.getSimpleState(); - return exportToGeoJson(m_export_flags, geometry, m_spatialReference); - } - return null; - } + if (geometry == null) + throw new IllegalArgumentException(""); - // Mirrors wkt - static String exportToGeoJson(int export_flags, Geometry geometry, SpatialReference spatial_reference) { + JsonWriter json_writer = new JsonStringWriter(); - if (geometry == null) - throw new IllegalArgumentException(""); + json_writer.startObject(); - JsonWriter json_writer = new JsonStringWriter(); + exportGeometryToGeoJson_(export_flags, geometry, json_writer); - json_writer.startObject(); + if ((export_flags & GeoJsonExportFlags.geoJsonExportSkipCRS) == 0) { + json_writer.addFieldName("crs"); + exportSpatialReference(export_flags, spatial_reference, json_writer); + } - exportGeometryToGeoJson_(export_flags, geometry, json_writer); + json_writer.endObject(); - if ((export_flags & GeoJsonExportFlags.geoJsonExportSkipCRS) == 0) { - json_writer.addFieldName("crs"); - exportSpatialReference(export_flags, spatial_reference, json_writer); - } + return (String) json_writer.getJson(); + } - json_writer.endObject(); + static String exportSpatialReference(int export_flags, SpatialReference spatial_reference) { + if (spatial_reference == null || (export_flags & GeoJsonExportFlags.geoJsonExportSkipCRS) != 0) + throw new IllegalArgumentException(""); + + JsonWriter json_writer = new JsonStringWriter(); + exportSpatialReference(export_flags, spatial_reference, json_writer); - return (String) json_writer.getJson(); - } + return (String) json_writer.getJson(); + } + + private static void exportGeometryToGeoJson_(int export_flags, Geometry geometry, JsonWriter json_writer) { + int type = geometry.getType().value(); + switch (type) { + case Geometry.GeometryType.Polygon: + exportPolygonToGeoJson_(export_flags, (Polygon) geometry, json_writer); + return; + + case Geometry.GeometryType.Polyline: + exportPolylineToGeoJson_(export_flags, (Polyline) geometry, json_writer); + return; + + case Geometry.GeometryType.MultiPoint: + exportMultiPointToGeoJson_(export_flags, (MultiPoint) geometry, json_writer); + return; + + case Geometry.GeometryType.Point: + exportPointToGeoJson_(export_flags, (Point) geometry, json_writer); + return; + + case Geometry.GeometryType.Envelope: + exportEnvelopeToGeoJson_(export_flags, (Envelope) geometry, + json_writer); + return; + + default: + throw new RuntimeException("not implemented for this geometry type"); + } + } + + private static void exportSpatialReference(int export_flags, SpatialReference spatial_reference, + JsonWriter json_writer) { + if (spatial_reference != null) { + int wkid = spatial_reference.getLatestID(); + + if (wkid <= 0) + throw new GeometryException("invalid call"); + + json_writer.startObject(); + + json_writer.addFieldName("type"); + + json_writer.addValueString("name"); + + json_writer.addFieldName("properties"); + json_writer.startObject(); + + json_writer.addFieldName("name"); + + String authority = ((SpatialReferenceImpl) spatial_reference).getAuthority(); + authority = authority.toUpperCase(); + StringBuilder crs_identifier = new StringBuilder(authority); + crs_identifier.append(':'); + crs_identifier.append(wkid); + json_writer.addValueString(crs_identifier.toString()); + + json_writer.endObject(); + + json_writer.endObject(); + } else { + json_writer.addValueNull(); + } + } + + // Mirrors wkt + private static void exportPolygonToGeoJson_(int export_flags, Polygon polygon, JsonWriter json_writer) { + MultiPathImpl polygon_impl = (MultiPathImpl) (polygon._getImpl()); + + if ((export_flags & GeoJsonExportFlags.geoJsonExportFailIfNotSimple) != 0) { + int simple = polygon_impl.getIsSimple(0.0); + + if (simple != MultiPathImpl.GeometryXSimple.Strong) + throw new GeometryException("corrupted geometry"); + } + + int point_count = polygon.getPointCount(); + int polygon_count = polygon_impl.getOGCPolygonCount(); + + if (point_count > 0 && polygon_count == 0) + throw new GeometryException("corrupted geometry"); + + int precision = 17 - (31 & (export_flags >> 13)); + boolean bFixedPoint = (GeoJsonExportFlags.geoJsonExportPrecisionFixedPoint & export_flags) != 0; + boolean b_export_zs = polygon_impl.hasAttribute(VertexDescription.Semantics.Z) + && (export_flags & GeoJsonExportFlags.geoJsonExportStripZs) == 0; + boolean b_export_ms = polygon_impl.hasAttribute(VertexDescription.Semantics.M) + && (export_flags & GeoJsonExportFlags.geoJsonExportStripMs) == 0; + + if (!b_export_zs && b_export_ms) + throw new IllegalArgumentException("invalid argument"); + + int path_count = 0; + AttributeStreamOfDbl position = null; + AttributeStreamOfDbl zs = null; + AttributeStreamOfDbl ms = null; + AttributeStreamOfInt8 path_flags = null; + AttributeStreamOfInt32 paths = null; + + if (point_count > 0) { + position = (AttributeStreamOfDbl) polygon_impl.getAttributeStreamRef(Semantics.POSITION); + path_flags = polygon_impl.getPathFlagsStreamRef(); + paths = polygon_impl.getPathStreamRef(); + path_count = polygon_impl.getPathCount(); + + if (b_export_zs) { + if (polygon_impl._attributeStreamIsAllocated(Semantics.Z)) + zs = (AttributeStreamOfDbl) polygon_impl.getAttributeStreamRef(Semantics.Z); + } + + if (b_export_ms) { + if (polygon_impl._attributeStreamIsAllocated(Semantics.M)) + ms = (AttributeStreamOfDbl) polygon_impl.getAttributeStreamRef(Semantics.M); + } + } + + if ((export_flags & GeoJsonExportFlags.geoJsonExportPreferMultiGeometry) == 0 && polygon_count <= 1) + polygonTaggedText_(precision, bFixedPoint, b_export_zs, b_export_ms, zs, ms, position, paths, path_count, + json_writer); + else + multiPolygonTaggedText_(precision, bFixedPoint, b_export_zs, b_export_ms, zs, ms, position, path_flags, + paths, polygon_count, path_count, json_writer); + } + + // Mirrors wkt + private static void exportPolylineToGeoJson_(int export_flags, Polyline polyline, JsonWriter json_writer) { + MultiPathImpl polyline_impl = (MultiPathImpl) polyline._getImpl(); + + int point_count = polyline_impl.getPointCount(); + int path_count = polyline_impl.getPathCount(); + + if (point_count > 0 && path_count == 0) + throw new GeometryException("corrupted geometry"); + + int precision = 17 - (31 & (export_flags >> 13)); + boolean bFixedPoint = (GeoJsonExportFlags.geoJsonExportPrecisionFixedPoint & export_flags) != 0; + boolean b_export_zs = polyline_impl.hasAttribute(VertexDescription.Semantics.Z) + && (export_flags & GeoJsonExportFlags.geoJsonExportStripZs) == 0; + boolean b_export_ms = polyline_impl.hasAttribute(VertexDescription.Semantics.M) + && (export_flags & GeoJsonExportFlags.geoJsonExportStripMs) == 0; + + if (!b_export_zs && b_export_ms) + throw new IllegalArgumentException("invalid argument"); + + AttributeStreamOfDbl position = null; + AttributeStreamOfDbl zs = null; + AttributeStreamOfDbl ms = null; + AttributeStreamOfInt8 path_flags = null; + AttributeStreamOfInt32 paths = null; + + if (point_count > 0) { + position = (AttributeStreamOfDbl) polyline_impl.getAttributeStreamRef(Semantics.POSITION); + path_flags = polyline_impl.getPathFlagsStreamRef(); + paths = polyline_impl.getPathStreamRef(); + + if (b_export_zs) { + if (polyline_impl._attributeStreamIsAllocated(Semantics.Z)) + zs = (AttributeStreamOfDbl) polyline_impl.getAttributeStreamRef(Semantics.Z); + } + + if (b_export_ms) { + if (polyline_impl._attributeStreamIsAllocated(Semantics.M)) + ms = (AttributeStreamOfDbl) polyline_impl.getAttributeStreamRef(Semantics.M); + } + } + + if ((export_flags & GeoJsonExportFlags.geoJsonExportPreferMultiGeometry) == 0 && path_count <= 1) + lineStringTaggedText_(precision, bFixedPoint, b_export_zs, b_export_ms, zs, ms, position, path_flags, paths, + json_writer); + else + multiLineStringTaggedText_(precision, bFixedPoint, b_export_zs, b_export_ms, zs, ms, position, path_flags, + paths, path_count, json_writer); + } + + // Mirrors wkt + private static void exportMultiPointToGeoJson_(int export_flags, MultiPoint multipoint, JsonWriter json_writer) { + MultiPointImpl multipoint_impl = (MultiPointImpl) multipoint._getImpl(); + + int point_count = multipoint_impl.getPointCount(); + + int precision = 17 - (31 & (export_flags >> 13)); + boolean bFixedPoint = (GeoJsonExportFlags.geoJsonExportPrecisionFixedPoint & export_flags) != 0; + boolean b_export_zs = multipoint_impl.hasAttribute(VertexDescription.Semantics.Z) + && (export_flags & GeoJsonExportFlags.geoJsonExportStripZs) == 0; + boolean b_export_ms = multipoint_impl.hasAttribute(VertexDescription.Semantics.M) + && (export_flags & GeoJsonExportFlags.geoJsonExportStripMs) == 0; + + if (!b_export_zs && b_export_ms) + throw new IllegalArgumentException("invalid argument"); + + AttributeStreamOfDbl position = null; + AttributeStreamOfDbl zs = null; + AttributeStreamOfDbl ms = null; + + if (point_count > 0) { + position = (AttributeStreamOfDbl) multipoint_impl.getAttributeStreamRef(Semantics.POSITION); + + if (b_export_zs) { + if (multipoint_impl._attributeStreamIsAllocated(Semantics.Z)) + zs = (AttributeStreamOfDbl) multipoint_impl.getAttributeStreamRef(Semantics.Z); + } + + if (b_export_ms) { + if (multipoint_impl._attributeStreamIsAllocated(Semantics.M)) + ms = (AttributeStreamOfDbl) multipoint_impl.getAttributeStreamRef(Semantics.M); + } + } + + multiPointTaggedText_(precision, bFixedPoint, b_export_zs, b_export_ms, zs, ms, position, point_count, + json_writer); + } + + // Mirrors wkt + private static void exportPointToGeoJson_(int export_flags, Point point, JsonWriter json_writer) { + int precision = 17 - (31 & (export_flags >> 13)); + boolean bFixedPoint = (GeoJsonExportFlags.geoJsonExportPrecisionFixedPoint & export_flags) != 0; + boolean b_export_zs = point.hasAttribute(VertexDescription.Semantics.Z) + && (export_flags & GeoJsonExportFlags.geoJsonExportStripZs) == 0; + boolean b_export_ms = point.hasAttribute(VertexDescription.Semantics.M) + && (export_flags & GeoJsonExportFlags.geoJsonExportStripMs) == 0; + + if (!b_export_zs && b_export_ms) + throw new IllegalArgumentException("invalid argument"); + + double x = NumberUtils.NaN(); + double y = NumberUtils.NaN(); + double z = NumberUtils.NaN(); + double m = NumberUtils.NaN(); + + if (!point.isEmpty()) { + x = point.getX(); + y = point.getY(); + + if (b_export_zs) + z = point.getZ(); + + if (b_export_ms) + m = point.getM(); + } + + if ((export_flags & GeoJsonExportFlags.geoJsonExportPreferMultiGeometry) == 0) + pointTaggedText_(precision, bFixedPoint, b_export_zs, b_export_ms, x, y, z, m, json_writer); + else + multiPointTaggedTextFromPoint_(precision, bFixedPoint, b_export_zs, b_export_ms, x, y, z, m, json_writer); + } + + // Mirrors wkt + private static void exportEnvelopeToGeoJson_(int export_flags, Envelope envelope, JsonWriter json_writer) { + int precision = 17 - (31 & (export_flags >> 13)); + boolean bFixedPoint = (GeoJsonExportFlags.geoJsonExportPrecisionFixedPoint & export_flags) != 0; + boolean b_export_zs = envelope.hasAttribute(VertexDescription.Semantics.Z) + && (export_flags & GeoJsonExportFlags.geoJsonExportStripZs) == 0; + boolean b_export_ms = envelope.hasAttribute(VertexDescription.Semantics.M) + && (export_flags & GeoJsonExportFlags.geoJsonExportStripMs) == 0; + + if (!b_export_zs && b_export_ms) + throw new IllegalArgumentException("invalid argument"); + + double xmin = NumberUtils.NaN(); + double ymin = NumberUtils.NaN(); + double xmax = NumberUtils.NaN(); + double ymax = NumberUtils.NaN(); + double zmin = NumberUtils.NaN(); + double zmax = NumberUtils.NaN(); + double mmin = NumberUtils.NaN(); + double mmax = NumberUtils.NaN(); + + if (!envelope.isEmpty()) { + xmin = envelope.getXMin(); + ymin = envelope.getYMin(); + xmax = envelope.getXMax(); + ymax = envelope.getYMax(); + + Envelope1D interval; + + if (b_export_zs) { + interval = envelope.queryInterval(Semantics.Z, 0); + zmin = interval.vmin; + zmax = interval.vmax; + } + + if (b_export_ms) { + interval = envelope.queryInterval(Semantics.M, 0); + mmin = interval.vmin; + mmax = interval.vmax; + } + } + + if ((export_flags & GeoJsonExportFlags.geoJsonExportPreferMultiGeometry) == 0) + polygonTaggedTextFromEnvelope_(precision, bFixedPoint, b_export_zs, b_export_ms, xmin, ymin, xmax, ymax, + zmin, zmax, mmin, mmax, json_writer); + else + multiPolygonTaggedTextFromEnvelope_(precision, bFixedPoint, b_export_zs, b_export_ms, xmin, ymin, xmax, + ymax, zmin, zmax, mmin, mmax, json_writer); + } + + // Mirrors wkt + private static void multiPolygonTaggedText_(int precision, boolean bFixedPoint, boolean b_export_zs, + boolean b_export_ms, AttributeStreamOfDbl zs, AttributeStreamOfDbl ms, AttributeStreamOfDbl position, + AttributeStreamOfInt8 path_flags, AttributeStreamOfInt32 paths, int polygon_count, int path_count, + JsonWriter json_writer) { + json_writer.addFieldName("type"); + json_writer.addValueString("MultiPolygon"); + + json_writer.addFieldName("coordinates"); + + if (position == null) { + json_writer.startArray(); + json_writer.endArray(); + return; + } + + json_writer.startArray(); + + multiPolygonText_(precision, bFixedPoint, b_export_zs, b_export_ms, zs, ms, position, path_flags, paths, + polygon_count, path_count, json_writer); + + json_writer.endArray(); + } + + // Mirrors wkt + private static void multiPolygonTaggedTextFromEnvelope_(int precision, boolean bFixedPoint, boolean b_export_zs, + boolean b_export_ms, double xmin, double ymin, double xmax, double ymax, double zmin, double zmax, + double mmin, double mmax, JsonWriter json_writer) { + json_writer.addFieldName("type"); + json_writer.addValueString("MultiPolygon"); + + json_writer.addFieldName("coordinates"); + + if (NumberUtils.isNaN(xmin)) { + json_writer.startArray(); + json_writer.endArray(); + return; + } + + json_writer.startArray(); + + writeEnvelopeAsGeoJsonPolygon_(precision, bFixedPoint, b_export_zs, b_export_ms, xmin, ymin, xmax, ymax, zmin, + zmax, mmin, mmax, json_writer); + + json_writer.endArray(); + } + + // Mirrors wkt + private static void multiLineStringTaggedText_(int precision, boolean bFixedPoint, boolean b_export_zs, + boolean b_export_ms, AttributeStreamOfDbl zs, AttributeStreamOfDbl ms, AttributeStreamOfDbl position, + AttributeStreamOfInt8 path_flags, AttributeStreamOfInt32 paths, int path_count, JsonWriter json_writer) { + json_writer.addFieldName("type"); + json_writer.addValueString("MultiLineString"); + + json_writer.addFieldName("coordinates"); + + if (position == null) { + json_writer.startArray(); + json_writer.endArray(); + return; + } + + json_writer.startArray(); + + multiLineStringText_(precision, bFixedPoint, b_export_zs, b_export_ms, zs, ms, position, path_flags, paths, + path_count, json_writer); + + json_writer.endArray(); + } + + // Mirrors wkt + private static void multiPointTaggedText_(int precision, boolean bFixedPoint, boolean b_export_zs, + boolean b_export_ms, AttributeStreamOfDbl zs, AttributeStreamOfDbl ms, AttributeStreamOfDbl position, + int point_count, JsonWriter json_writer) { + json_writer.addFieldName("type"); + json_writer.addValueString("MultiPoint"); + + json_writer.addFieldName("coordinates"); + + if (position == null) { + json_writer.startArray(); + json_writer.endArray(); + return; + } + + lineStringText_(false, false, precision, bFixedPoint, b_export_zs, b_export_ms, zs, ms, position, 0, + point_count, json_writer); + } + + // Mirrors wkt + private static void multiPointTaggedTextFromPoint_(int precision, boolean bFixedPoint, boolean b_export_zs, + boolean b_export_ms, double x, double y, double z, double m, JsonWriter json_writer) { + json_writer.addFieldName("type"); + json_writer.addValueString("MultiPoint"); + + json_writer.addFieldName("coordinates"); + + if (NumberUtils.isNaN(x)) { + json_writer.startArray(); + json_writer.endArray(); + return; + } + + json_writer.startArray(); - static String exportSpatialReference(int export_flags, SpatialReference spatial_reference) { - if (spatial_reference == null || (export_flags & GeoJsonExportFlags.geoJsonExportSkipCRS) != 0) - throw new IllegalArgumentException(""); + pointText_(precision, bFixedPoint, b_export_zs, b_export_ms, x, y, z, m, json_writer); - JsonWriter json_writer = new JsonStringWriter(); - exportSpatialReference(export_flags, spatial_reference, json_writer); + json_writer.endArray(); + } - return (String) json_writer.getJson(); - } - - private static void exportGeometryToGeoJson_(int export_flags, Geometry geometry, JsonWriter json_writer) { - int type = geometry.getType().value(); - switch (type) { - case Geometry.GeometryType.Polygon: - exportPolygonToGeoJson_(export_flags, (Polygon) geometry, json_writer); - return; - - case Geometry.GeometryType.Polyline: - exportPolylineToGeoJson_(export_flags, (Polyline) geometry, json_writer); - return; - - case Geometry.GeometryType.MultiPoint: - exportMultiPointToGeoJson_(export_flags, (MultiPoint) geometry, json_writer); - return; - - case Geometry.GeometryType.Point: - exportPointToGeoJson_(export_flags, (Point) geometry, json_writer); - return; - - case Geometry.GeometryType.Envelope: - exportEnvelopeToGeoJson_(export_flags, (Envelope) geometry, - json_writer); - return; - - default: - throw new RuntimeException("not implemented for this geometry type"); - } - } - - private static void exportSpatialReference(int export_flags, SpatialReference spatial_reference, - JsonWriter json_writer) { - if (spatial_reference != null) { - int wkid = spatial_reference.getLatestID(); - - if (wkid <= 0) - throw new GeometryException("invalid call"); - - json_writer.startObject(); - - json_writer.addFieldName("type"); - - json_writer.addValueString("name"); - - json_writer.addFieldName("properties"); - json_writer.startObject(); - - json_writer.addFieldName("name"); - - String authority = ((SpatialReferenceImpl) spatial_reference).getAuthority(); - authority = authority.toUpperCase(); - StringBuilder crs_identifier = new StringBuilder(authority); - crs_identifier.append(':'); - crs_identifier.append(wkid); - json_writer.addValueString(crs_identifier.toString()); - - json_writer.endObject(); - - json_writer.endObject(); - } else { - json_writer.addValueNull(); - } - } - - // Mirrors wkt - private static void exportPolygonToGeoJson_(int export_flags, Polygon polygon, JsonWriter json_writer) { - MultiPathImpl polygon_impl = (MultiPathImpl) (polygon._getImpl()); - - if ((export_flags & GeoJsonExportFlags.geoJsonExportFailIfNotSimple) != 0) { - int simple = polygon_impl.getIsSimple(0.0); - - if (simple != MultiPathImpl.GeometryXSimple.Strong) - throw new GeometryException("corrupted geometry"); - } - - int point_count = polygon.getPointCount(); - int polygon_count = polygon_impl.getOGCPolygonCount(); - - if (point_count > 0 && polygon_count == 0) - throw new GeometryException("corrupted geometry"); - - int precision = 17 - (31 & (export_flags >> 13)); - boolean bFixedPoint = (GeoJsonExportFlags.geoJsonExportPrecisionFixedPoint & export_flags) != 0; - boolean b_export_zs = polygon_impl.hasAttribute(VertexDescription.Semantics.Z) - && (export_flags & GeoJsonExportFlags.geoJsonExportStripZs) == 0; - boolean b_export_ms = polygon_impl.hasAttribute(VertexDescription.Semantics.M) - && (export_flags & GeoJsonExportFlags.geoJsonExportStripMs) == 0; - - if (!b_export_zs && b_export_ms) - throw new IllegalArgumentException("invalid argument"); - - int path_count = 0; - AttributeStreamOfDbl position = null; - AttributeStreamOfDbl zs = null; - AttributeStreamOfDbl ms = null; - AttributeStreamOfInt8 path_flags = null; - AttributeStreamOfInt32 paths = null; - - if (point_count > 0) { - position = (AttributeStreamOfDbl) polygon_impl.getAttributeStreamRef(Semantics.POSITION); - path_flags = polygon_impl.getPathFlagsStreamRef(); - paths = polygon_impl.getPathStreamRef(); - path_count = polygon_impl.getPathCount(); - - if (b_export_zs) { - if (polygon_impl._attributeStreamIsAllocated(Semantics.Z)) - zs = (AttributeStreamOfDbl) polygon_impl.getAttributeStreamRef(Semantics.Z); - } - - if (b_export_ms) { - if (polygon_impl._attributeStreamIsAllocated(Semantics.M)) - ms = (AttributeStreamOfDbl) polygon_impl.getAttributeStreamRef(Semantics.M); - } - } - - if ((export_flags & GeoJsonExportFlags.geoJsonExportPreferMultiGeometry) == 0 && polygon_count <= 1) - polygonTaggedText_(precision, bFixedPoint, b_export_zs, b_export_ms, zs, ms, position, paths, path_count, - json_writer); - else - multiPolygonTaggedText_(precision, bFixedPoint, b_export_zs, b_export_ms, zs, ms, position, path_flags, - paths, polygon_count, path_count, json_writer); - } - - // Mirrors wkt - private static void exportPolylineToGeoJson_(int export_flags, Polyline polyline, JsonWriter json_writer) { - MultiPathImpl polyline_impl = (MultiPathImpl) polyline._getImpl(); - - int point_count = polyline_impl.getPointCount(); - int path_count = polyline_impl.getPathCount(); - - if (point_count > 0 && path_count == 0) - throw new GeometryException("corrupted geometry"); - - int precision = 17 - (31 & (export_flags >> 13)); - boolean bFixedPoint = (GeoJsonExportFlags.geoJsonExportPrecisionFixedPoint & export_flags) != 0; - boolean b_export_zs = polyline_impl.hasAttribute(VertexDescription.Semantics.Z) - && (export_flags & GeoJsonExportFlags.geoJsonExportStripZs) == 0; - boolean b_export_ms = polyline_impl.hasAttribute(VertexDescription.Semantics.M) - && (export_flags & GeoJsonExportFlags.geoJsonExportStripMs) == 0; - - if (!b_export_zs && b_export_ms) - throw new IllegalArgumentException("invalid argument"); - - AttributeStreamOfDbl position = null; - AttributeStreamOfDbl zs = null; - AttributeStreamOfDbl ms = null; - AttributeStreamOfInt8 path_flags = null; - AttributeStreamOfInt32 paths = null; - - if (point_count > 0) { - position = (AttributeStreamOfDbl) polyline_impl.getAttributeStreamRef(Semantics.POSITION); - path_flags = polyline_impl.getPathFlagsStreamRef(); - paths = polyline_impl.getPathStreamRef(); - - if (b_export_zs) { - if (polyline_impl._attributeStreamIsAllocated(Semantics.Z)) - zs = (AttributeStreamOfDbl) polyline_impl.getAttributeStreamRef(Semantics.Z); - } - - if (b_export_ms) { - if (polyline_impl._attributeStreamIsAllocated(Semantics.M)) - ms = (AttributeStreamOfDbl) polyline_impl.getAttributeStreamRef(Semantics.M); - } - } - - if ((export_flags & GeoJsonExportFlags.geoJsonExportPreferMultiGeometry) == 0 && path_count <= 1) - lineStringTaggedText_(precision, bFixedPoint, b_export_zs, b_export_ms, zs, ms, position, path_flags, paths, - json_writer); - else - multiLineStringTaggedText_(precision, bFixedPoint, b_export_zs, b_export_ms, zs, ms, position, path_flags, - paths, path_count, json_writer); - } - - // Mirrors wkt - private static void exportMultiPointToGeoJson_(int export_flags, MultiPoint multipoint, JsonWriter json_writer) { - MultiPointImpl multipoint_impl = (MultiPointImpl) multipoint._getImpl(); - - int point_count = multipoint_impl.getPointCount(); - - int precision = 17 - (31 & (export_flags >> 13)); - boolean bFixedPoint = (GeoJsonExportFlags.geoJsonExportPrecisionFixedPoint & export_flags) != 0; - boolean b_export_zs = multipoint_impl.hasAttribute(VertexDescription.Semantics.Z) - && (export_flags & GeoJsonExportFlags.geoJsonExportStripZs) == 0; - boolean b_export_ms = multipoint_impl.hasAttribute(VertexDescription.Semantics.M) - && (export_flags & GeoJsonExportFlags.geoJsonExportStripMs) == 0; - - if (!b_export_zs && b_export_ms) - throw new IllegalArgumentException("invalid argument"); - - AttributeStreamOfDbl position = null; - AttributeStreamOfDbl zs = null; - AttributeStreamOfDbl ms = null; - - if (point_count > 0) { - position = (AttributeStreamOfDbl) multipoint_impl.getAttributeStreamRef(Semantics.POSITION); - - if (b_export_zs) { - if (multipoint_impl._attributeStreamIsAllocated(Semantics.Z)) - zs = (AttributeStreamOfDbl) multipoint_impl.getAttributeStreamRef(Semantics.Z); - } - - if (b_export_ms) { - if (multipoint_impl._attributeStreamIsAllocated(Semantics.M)) - ms = (AttributeStreamOfDbl) multipoint_impl.getAttributeStreamRef(Semantics.M); - } - } - - multiPointTaggedText_(precision, bFixedPoint, b_export_zs, b_export_ms, zs, ms, position, point_count, - json_writer); - } - - // Mirrors wkt - private static void exportPointToGeoJson_(int export_flags, Point point, JsonWriter json_writer) { - int precision = 17 - (31 & (export_flags >> 13)); - boolean bFixedPoint = (GeoJsonExportFlags.geoJsonExportPrecisionFixedPoint & export_flags) != 0; - boolean b_export_zs = point.hasAttribute(VertexDescription.Semantics.Z) - && (export_flags & GeoJsonExportFlags.geoJsonExportStripZs) == 0; - boolean b_export_ms = point.hasAttribute(VertexDescription.Semantics.M) - && (export_flags & GeoJsonExportFlags.geoJsonExportStripMs) == 0; - - if (!b_export_zs && b_export_ms) - throw new IllegalArgumentException("invalid argument"); - - double x = NumberUtils.NaN(); - double y = NumberUtils.NaN(); - double z = NumberUtils.NaN(); - double m = NumberUtils.NaN(); - - if (!point.isEmpty()) { - x = point.getX(); - y = point.getY(); - - if (b_export_zs) - z = point.getZ(); - - if (b_export_ms) - m = point.getM(); - } - - if ((export_flags & GeoJsonExportFlags.geoJsonExportPreferMultiGeometry) == 0) - pointTaggedText_(precision, bFixedPoint, b_export_zs, b_export_ms, x, y, z, m, json_writer); - else - multiPointTaggedTextFromPoint_(precision, bFixedPoint, b_export_zs, b_export_ms, x, y, z, m, json_writer); - } - - // Mirrors wkt - private static void exportEnvelopeToGeoJson_(int export_flags, Envelope envelope, JsonWriter json_writer) { - int precision = 17 - (31 & (export_flags >> 13)); - boolean bFixedPoint = (GeoJsonExportFlags.geoJsonExportPrecisionFixedPoint & export_flags) != 0; - boolean b_export_zs = envelope.hasAttribute(VertexDescription.Semantics.Z) - && (export_flags & GeoJsonExportFlags.geoJsonExportStripZs) == 0; - boolean b_export_ms = envelope.hasAttribute(VertexDescription.Semantics.M) - && (export_flags & GeoJsonExportFlags.geoJsonExportStripMs) == 0; - - if (!b_export_zs && b_export_ms) - throw new IllegalArgumentException("invalid argument"); - - double xmin = NumberUtils.NaN(); - double ymin = NumberUtils.NaN(); - double xmax = NumberUtils.NaN(); - double ymax = NumberUtils.NaN(); - double zmin = NumberUtils.NaN(); - double zmax = NumberUtils.NaN(); - double mmin = NumberUtils.NaN(); - double mmax = NumberUtils.NaN(); - - if (!envelope.isEmpty()) { - xmin = envelope.getXMin(); - ymin = envelope.getYMin(); - xmax = envelope.getXMax(); - ymax = envelope.getYMax(); - - Envelope1D interval; - - if (b_export_zs) { - interval = envelope.queryInterval(Semantics.Z, 0); - zmin = interval.vmin; - zmax = interval.vmax; - } - - if (b_export_ms) { - interval = envelope.queryInterval(Semantics.M, 0); - mmin = interval.vmin; - mmax = interval.vmax; - } - } - - if ((export_flags & GeoJsonExportFlags.geoJsonExportPreferMultiGeometry) == 0) - polygonTaggedTextFromEnvelope_(precision, bFixedPoint, b_export_zs, b_export_ms, xmin, ymin, xmax, ymax, - zmin, zmax, mmin, mmax, json_writer); - else - multiPolygonTaggedTextFromEnvelope_(precision, bFixedPoint, b_export_zs, b_export_ms, xmin, ymin, xmax, - ymax, zmin, zmax, mmin, mmax, json_writer); - } - - // Mirrors wkt - private static void multiPolygonTaggedText_(int precision, boolean bFixedPoint, boolean b_export_zs, - boolean b_export_ms, AttributeStreamOfDbl zs, AttributeStreamOfDbl ms, AttributeStreamOfDbl position, - AttributeStreamOfInt8 path_flags, AttributeStreamOfInt32 paths, int polygon_count, int path_count, - JsonWriter json_writer) { - json_writer.addFieldName("type"); - json_writer.addValueString("MultiPolygon"); - - json_writer.addFieldName("coordinates"); - - if (position == null) { - json_writer.startArray(); - json_writer.endArray(); - return; - } - - json_writer.startArray(); - - multiPolygonText_(precision, bFixedPoint, b_export_zs, b_export_ms, zs, ms, position, path_flags, paths, - polygon_count, path_count, json_writer); - - json_writer.endArray(); - } - - // Mirrors wkt - private static void multiPolygonTaggedTextFromEnvelope_(int precision, boolean bFixedPoint, boolean b_export_zs, - boolean b_export_ms, double xmin, double ymin, double xmax, double ymax, double zmin, double zmax, - double mmin, double mmax, JsonWriter json_writer) { - json_writer.addFieldName("type"); - json_writer.addValueString("MultiPolygon"); - - json_writer.addFieldName("coordinates"); - - if (NumberUtils.isNaN(xmin)) { - json_writer.startArray(); - json_writer.endArray(); - return; - } - - json_writer.startArray(); - - writeEnvelopeAsGeoJsonPolygon_(precision, bFixedPoint, b_export_zs, b_export_ms, xmin, ymin, xmax, ymax, zmin, - zmax, mmin, mmax, json_writer); - - json_writer.endArray(); - } - - // Mirrors wkt - private static void multiLineStringTaggedText_(int precision, boolean bFixedPoint, boolean b_export_zs, - boolean b_export_ms, AttributeStreamOfDbl zs, AttributeStreamOfDbl ms, AttributeStreamOfDbl position, - AttributeStreamOfInt8 path_flags, AttributeStreamOfInt32 paths, int path_count, JsonWriter json_writer) { - json_writer.addFieldName("type"); - json_writer.addValueString("MultiLineString"); - - json_writer.addFieldName("coordinates"); - - if (position == null) { - json_writer.startArray(); - json_writer.endArray(); - return; - } - - json_writer.startArray(); - - multiLineStringText_(precision, bFixedPoint, b_export_zs, b_export_ms, zs, ms, position, path_flags, paths, - path_count, json_writer); - - json_writer.endArray(); - } - - // Mirrors wkt - private static void multiPointTaggedText_(int precision, boolean bFixedPoint, boolean b_export_zs, - boolean b_export_ms, AttributeStreamOfDbl zs, AttributeStreamOfDbl ms, AttributeStreamOfDbl position, - int point_count, JsonWriter json_writer) { - json_writer.addFieldName("type"); - json_writer.addValueString("MultiPoint"); - - json_writer.addFieldName("coordinates"); - - if (position == null) { - json_writer.startArray(); - json_writer.endArray(); - return; - } - - lineStringText_(false, false, precision, bFixedPoint, b_export_zs, b_export_ms, zs, ms, position, 0, - point_count, json_writer); - } - - // Mirrors wkt - private static void multiPointTaggedTextFromPoint_(int precision, boolean bFixedPoint, boolean b_export_zs, - boolean b_export_ms, double x, double y, double z, double m, JsonWriter json_writer) { - json_writer.addFieldName("type"); - json_writer.addValueString("MultiPoint"); - - json_writer.addFieldName("coordinates"); - - if (NumberUtils.isNaN(x)) { - json_writer.startArray(); - json_writer.endArray(); - return; - } - - json_writer.startArray(); + // Mirrors wkt + private static void polygonTaggedText_(int precision, boolean bFixedPoint, boolean b_export_zs, boolean b_export_ms, + AttributeStreamOfDbl zs, AttributeStreamOfDbl ms, AttributeStreamOfDbl position, + AttributeStreamOfInt32 paths, int path_count, JsonWriter json_writer) { + json_writer.addFieldName("type"); + json_writer.addValueString("Polygon"); + + json_writer.addFieldName("coordinates"); + + if (position == null) { + json_writer.startArray(); + json_writer.endArray(); + return; + } + + polygonText_(precision, bFixedPoint, b_export_zs, b_export_ms, zs, ms, position, paths, 0, path_count, + json_writer); + } + + // Mirrors wkt + private static void polygonTaggedTextFromEnvelope_(int precision, boolean bFixedPoint, boolean b_export_zs, + boolean b_export_ms, double xmin, double ymin, double xmax, double ymax, double zmin, double zmax, + double mmin, double mmax, JsonWriter json_writer) { + json_writer.addFieldName("type"); + json_writer.addValueString("Polygon"); + + json_writer.addFieldName("coordinates"); + + if (NumberUtils.isNaN(xmin)) { + json_writer.startArray(); + json_writer.endArray(); + return; + } + + writeEnvelopeAsGeoJsonPolygon_(precision, bFixedPoint, b_export_zs, b_export_ms, xmin, ymin, xmax, ymax, zmin, + zmax, mmin, mmax, json_writer); + } + + // Mirrors wkt + private static void lineStringTaggedText_(int precision, boolean bFixedPoint, boolean b_export_zs, + boolean b_export_ms, AttributeStreamOfDbl zs, AttributeStreamOfDbl ms, AttributeStreamOfDbl position, + AttributeStreamOfInt8 path_flags, AttributeStreamOfInt32 paths, JsonWriter json_writer) { + json_writer.addFieldName("type"); + json_writer.addValueString("LineString"); + + json_writer.addFieldName("coordinates"); + + if (position == null) { + json_writer.startArray(); + json_writer.endArray(); + return; + } + + boolean b_closed = ((path_flags.read(0) & PathFlags.enumClosed) != 0); + + lineStringText_(false, b_closed, precision, bFixedPoint, b_export_zs, b_export_ms, zs, ms, position, 0, + paths.read(1), json_writer); + } + + // Mirrors wkt + private static void pointTaggedText_(int precision, boolean bFixedPoint, boolean b_export_zs, boolean b_export_ms, + double x, double y, double z, double m, JsonWriter json_writer) { + json_writer.addFieldName("type"); + json_writer.addValueString("Point"); + + json_writer.addFieldName("coordinates"); + + if (NumberUtils.isNaN(x)) { + json_writer.startArray(); + json_writer.endArray(); + + return; + } + + pointText_(precision, bFixedPoint, b_export_zs, b_export_ms, x, y, z, m, json_writer); + } + + // Mirrors wkt + private static void multiPolygonText_(int precision, boolean bFixedPoint, boolean b_export_zs, boolean b_export_ms, + AttributeStreamOfDbl zs, AttributeStreamOfDbl ms, AttributeStreamOfDbl position, + AttributeStreamOfInt8 path_flags, AttributeStreamOfInt32 paths, int polygon_count, int path_count, + JsonWriter json_writer) { + int polygon_start = 0; + int polygon_end = 1; + + while (polygon_end < path_count && ((int) path_flags.read(polygon_end) & PathFlags.enumOGCStartPolygon) == 0) + polygon_end++; + + polygonText_(precision, bFixedPoint, b_export_zs, b_export_ms, zs, ms, position, paths, polygon_start, + polygon_end, json_writer); + + for (int ipolygon = 1; ipolygon < polygon_count; ipolygon++) { + polygon_start = polygon_end; + polygon_end++; + + while (polygon_end < path_count + && ((int) path_flags.read(polygon_end) & PathFlags.enumOGCStartPolygon) == 0) + polygon_end++; + + polygonText_(precision, bFixedPoint, b_export_zs, b_export_ms, zs, ms, position, paths, polygon_start, + polygon_end, json_writer); + } + } + + // Mirrors wkt + private static void multiLineStringText_(int precision, boolean bFixedPoint, boolean b_export_zs, + boolean b_export_ms, AttributeStreamOfDbl zs, AttributeStreamOfDbl ms, AttributeStreamOfDbl position, + AttributeStreamOfInt8 path_flags, AttributeStreamOfInt32 paths, int path_count, JsonWriter json_writer) { + boolean b_closed = ((path_flags.read(0) & PathFlags.enumClosed) != 0); + + lineStringText_(false, b_closed, precision, bFixedPoint, b_export_zs, b_export_ms, zs, ms, position, 0, + paths.read(1), json_writer); + + for (int path = 1; path < path_count; path++) { + b_closed = ((path_flags.read(path) & PathFlags.enumClosed) != 0); + + int istart = paths.read(path); + int iend = paths.read(path + 1); + lineStringText_(false, b_closed, precision, bFixedPoint, b_export_zs, b_export_ms, zs, ms, position, istart, + iend, json_writer); + } + } + + // Mirrors wkt + private static void polygonText_(int precision, boolean bFixedPoint, boolean b_export_zs, boolean b_export_ms, + AttributeStreamOfDbl zs, AttributeStreamOfDbl ms, AttributeStreamOfDbl position, + AttributeStreamOfInt32 paths, int polygon_start, int polygon_end, JsonWriter json_writer) { + json_writer.startArray(); + + int istart = paths.read(polygon_start); + int iend = paths.read(polygon_start + 1); + lineStringText_(true, true, precision, bFixedPoint, b_export_zs, b_export_ms, zs, ms, position, istart, iend, + json_writer); - pointText_(precision, bFixedPoint, b_export_zs, b_export_ms, x, y, z, m, json_writer); + for (int path = polygon_start + 1; path < polygon_end; path++) { + istart = paths.read(path); + iend = paths.read(path + 1); + lineStringText_(true, true, precision, bFixedPoint, b_export_zs, b_export_ms, zs, ms, position, istart, + iend, json_writer); + } - json_writer.endArray(); - } + json_writer.endArray(); + } - // Mirrors wkt - private static void polygonTaggedText_(int precision, boolean bFixedPoint, boolean b_export_zs, boolean b_export_ms, - AttributeStreamOfDbl zs, AttributeStreamOfDbl ms, AttributeStreamOfDbl position, - AttributeStreamOfInt32 paths, int path_count, JsonWriter json_writer) { - json_writer.addFieldName("type"); - json_writer.addValueString("Polygon"); - - json_writer.addFieldName("coordinates"); - - if (position == null) { - json_writer.startArray(); - json_writer.endArray(); - return; - } - - polygonText_(precision, bFixedPoint, b_export_zs, b_export_ms, zs, ms, position, paths, 0, path_count, - json_writer); - } - - // Mirrors wkt - private static void polygonTaggedTextFromEnvelope_(int precision, boolean bFixedPoint, boolean b_export_zs, - boolean b_export_ms, double xmin, double ymin, double xmax, double ymax, double zmin, double zmax, - double mmin, double mmax, JsonWriter json_writer) { - json_writer.addFieldName("type"); - json_writer.addValueString("Polygon"); - - json_writer.addFieldName("coordinates"); - - if (NumberUtils.isNaN(xmin)) { - json_writer.startArray(); - json_writer.endArray(); - return; - } - - writeEnvelopeAsGeoJsonPolygon_(precision, bFixedPoint, b_export_zs, b_export_ms, xmin, ymin, xmax, ymax, zmin, - zmax, mmin, mmax, json_writer); - } - - // Mirrors wkt - private static void lineStringTaggedText_(int precision, boolean bFixedPoint, boolean b_export_zs, - boolean b_export_ms, AttributeStreamOfDbl zs, AttributeStreamOfDbl ms, AttributeStreamOfDbl position, - AttributeStreamOfInt8 path_flags, AttributeStreamOfInt32 paths, JsonWriter json_writer) { - json_writer.addFieldName("type"); - json_writer.addValueString("LineString"); - - json_writer.addFieldName("coordinates"); - - if (position == null) { - json_writer.startArray(); - json_writer.endArray(); - return; - } - - boolean b_closed = ((path_flags.read(0) & PathFlags.enumClosed) != 0); - - lineStringText_(false, b_closed, precision, bFixedPoint, b_export_zs, b_export_ms, zs, ms, position, 0, - paths.read(1), json_writer); - } - - // Mirrors wkt - private static void pointTaggedText_(int precision, boolean bFixedPoint, boolean b_export_zs, boolean b_export_ms, - double x, double y, double z, double m, JsonWriter json_writer) { - json_writer.addFieldName("type"); - json_writer.addValueString("Point"); - - json_writer.addFieldName("coordinates"); - - if (NumberUtils.isNaN(x)) { - json_writer.startArray(); - json_writer.endArray(); - - return; - } - - pointText_(precision, bFixedPoint, b_export_zs, b_export_ms, x, y, z, m, json_writer); - } - - // Mirrors wkt - private static void multiPolygonText_(int precision, boolean bFixedPoint, boolean b_export_zs, boolean b_export_ms, - AttributeStreamOfDbl zs, AttributeStreamOfDbl ms, AttributeStreamOfDbl position, - AttributeStreamOfInt8 path_flags, AttributeStreamOfInt32 paths, int polygon_count, int path_count, - JsonWriter json_writer) { - int polygon_start = 0; - int polygon_end = 1; - - while (polygon_end < path_count && ((int) path_flags.read(polygon_end) & PathFlags.enumOGCStartPolygon) == 0) - polygon_end++; - - polygonText_(precision, bFixedPoint, b_export_zs, b_export_ms, zs, ms, position, paths, polygon_start, - polygon_end, json_writer); - - for (int ipolygon = 1; ipolygon < polygon_count; ipolygon++) { - polygon_start = polygon_end; - polygon_end++; - - while (polygon_end < path_count - && ((int) path_flags.read(polygon_end) & PathFlags.enumOGCStartPolygon) == 0) - polygon_end++; - - polygonText_(precision, bFixedPoint, b_export_zs, b_export_ms, zs, ms, position, paths, polygon_start, - polygon_end, json_writer); - } - } - - // Mirrors wkt - private static void multiLineStringText_(int precision, boolean bFixedPoint, boolean b_export_zs, - boolean b_export_ms, AttributeStreamOfDbl zs, AttributeStreamOfDbl ms, AttributeStreamOfDbl position, - AttributeStreamOfInt8 path_flags, AttributeStreamOfInt32 paths, int path_count, JsonWriter json_writer) { - boolean b_closed = ((path_flags.read(0) & PathFlags.enumClosed) != 0); - - lineStringText_(false, b_closed, precision, bFixedPoint, b_export_zs, b_export_ms, zs, ms, position, 0, - paths.read(1), json_writer); - - for (int path = 1; path < path_count; path++) { - b_closed = ((path_flags.read(path) & PathFlags.enumClosed) != 0); - - int istart = paths.read(path); - int iend = paths.read(path + 1); - lineStringText_(false, b_closed, precision, bFixedPoint, b_export_zs, b_export_ms, zs, ms, position, istart, - iend, json_writer); - } - } - - // Mirrors wkt - private static void polygonText_(int precision, boolean bFixedPoint, boolean b_export_zs, boolean b_export_ms, - AttributeStreamOfDbl zs, AttributeStreamOfDbl ms, AttributeStreamOfDbl position, - AttributeStreamOfInt32 paths, int polygon_start, int polygon_end, JsonWriter json_writer) { - json_writer.startArray(); - - int istart = paths.read(polygon_start); - int iend = paths.read(polygon_start + 1); - lineStringText_(true, true, precision, bFixedPoint, b_export_zs, b_export_ms, zs, ms, position, istart, iend, - json_writer); + // Mirrors wkt + private static void lineStringText_(boolean bRing, boolean b_closed, int precision, boolean bFixedPoint, + boolean b_export_zs, boolean b_export_ms, AttributeStreamOfDbl zs, AttributeStreamOfDbl ms, + AttributeStreamOfDbl position, int istart, int iend, JsonWriter json_writer) { + if (istart == iend) { + json_writer.startArray(); + json_writer.endArray(); + return; + } - for (int path = polygon_start + 1; path < polygon_end; path++) { - istart = paths.read(path); - iend = paths.read(path + 1); - lineStringText_(true, true, precision, bFixedPoint, b_export_zs, b_export_ms, zs, ms, position, istart, - iend, json_writer); - } + json_writer.startArray(); - json_writer.endArray(); - } + if (bRing) { + pointText_(precision, bFixedPoint, b_export_zs, b_export_ms, zs, ms, position, istart, json_writer); - // Mirrors wkt - private static void lineStringText_(boolean bRing, boolean b_closed, int precision, boolean bFixedPoint, - boolean b_export_zs, boolean b_export_ms, AttributeStreamOfDbl zs, AttributeStreamOfDbl ms, - AttributeStreamOfDbl position, int istart, int iend, JsonWriter json_writer) { - if (istart == iend) { - json_writer.startArray(); - json_writer.endArray(); - return; - } + for (int point = iend - 1; point >= istart + 1; point--) + pointText_(precision, bFixedPoint, b_export_zs, b_export_ms, zs, ms, position, point, json_writer); - json_writer.startArray(); + pointText_(precision, bFixedPoint, b_export_zs, b_export_ms, zs, ms, position, istart, json_writer); + } else { + for (int point = istart; point < iend - 1; point++) + pointText_(precision, bFixedPoint, b_export_zs, b_export_ms, zs, ms, position, point, json_writer); - if (bRing) { - pointText_(precision, bFixedPoint, b_export_zs, b_export_ms, zs, ms, position, istart, json_writer); + pointText_(precision, bFixedPoint, b_export_zs, b_export_ms, zs, ms, position, iend - 1, json_writer); - for (int point = iend - 1; point >= istart + 1; point--) - pointText_(precision, bFixedPoint, b_export_zs, b_export_ms, zs, ms, position, point, json_writer); + if (b_closed) + pointText_(precision, bFixedPoint, b_export_zs, b_export_ms, zs, ms, position, istart, json_writer); + } - pointText_(precision, bFixedPoint, b_export_zs, b_export_ms, zs, ms, position, istart, json_writer); - } else { - for (int point = istart; point < iend - 1; point++) - pointText_(precision, bFixedPoint, b_export_zs, b_export_ms, zs, ms, position, point, json_writer); + json_writer.endArray(); + } - pointText_(precision, bFixedPoint, b_export_zs, b_export_ms, zs, ms, position, iend - 1, json_writer); + // Mirrors wkt + private static int pointText_(int precision, boolean bFixedPoint, boolean b_export_zs, boolean b_export_ms, + double x, double y, double z, double m, JsonWriter json_writer) { - if (b_closed) - pointText_(precision, bFixedPoint, b_export_zs, b_export_ms, zs, ms, position, istart, json_writer); - } + json_writer.startArray(); - json_writer.endArray(); - } + json_writer.addValueDouble(x, precision, bFixedPoint); + json_writer.addValueDouble(y, precision, bFixedPoint); - // Mirrors wkt - private static int pointText_(int precision, boolean bFixedPoint, boolean b_export_zs, boolean b_export_ms, - double x, double y, double z, double m, JsonWriter json_writer) { + if (b_export_zs) + json_writer.addValueDouble(z, precision, bFixedPoint); - json_writer.startArray(); + if (b_export_ms) + json_writer.addValueDouble(m, precision, bFixedPoint); - json_writer.addValueDouble(x, precision, bFixedPoint); - json_writer.addValueDouble(y, precision, bFixedPoint); + json_writer.endArray(); - if (b_export_zs) - json_writer.addValueDouble(z, precision, bFixedPoint); + return 1; + } - if (b_export_ms) - json_writer.addValueDouble(m, precision, bFixedPoint); + // Mirrors wkt + private static void pointText_(int precision, boolean bFixedPoint, boolean b_export_zs, boolean b_export_ms, + AttributeStreamOfDbl zs, AttributeStreamOfDbl ms, AttributeStreamOfDbl position, int point, + JsonWriter json_writer) { + double x = position.readAsDbl(2 * point); + double y = position.readAsDbl(2 * point + 1); + double z = NumberUtils.NaN(); + double m = NumberUtils.NaN(); - json_writer.endArray(); + if (b_export_zs) + z = (zs != null ? zs.readAsDbl(point) : VertexDescription.getDefaultValue(Semantics.Z)); - return 1; - } + if (b_export_ms) + m = (ms != null ? ms.readAsDbl(point) : VertexDescription.getDefaultValue(Semantics.M)); - // Mirrors wkt - private static void pointText_(int precision, boolean bFixedPoint, boolean b_export_zs, boolean b_export_ms, - AttributeStreamOfDbl zs, AttributeStreamOfDbl ms, AttributeStreamOfDbl position, int point, - JsonWriter json_writer) { - double x = position.readAsDbl(2 * point); - double y = position.readAsDbl(2 * point + 1); - double z = NumberUtils.NaN(); - double m = NumberUtils.NaN(); + pointText_(precision, bFixedPoint, b_export_zs, b_export_ms, x, y, z, m, json_writer); + } - if (b_export_zs) - z = (zs != null ? zs.readAsDbl(point) : VertexDescription.getDefaultValue(Semantics.Z)); + // Mirrors wkt + private static void writeEnvelopeAsGeoJsonPolygon_(int precision, boolean bFixedPoint, boolean b_export_zs, + boolean b_export_ms, double xmin, double ymin, double xmax, double ymax, double zmin, double zmax, + double mmin, double mmax, JsonWriter json_writer) { + json_writer.startArray(); + json_writer.startArray(); - if (b_export_ms) - m = (ms != null ? ms.readAsDbl(point) : VertexDescription.getDefaultValue(Semantics.M)); + json_writer.startArray(); + json_writer.addValueDouble(xmin, precision, bFixedPoint); + json_writer.addValueDouble(ymin, precision, bFixedPoint); - pointText_(precision, bFixedPoint, b_export_zs, b_export_ms, x, y, z, m, json_writer); - } + if (b_export_zs) + json_writer.addValueDouble(zmin, precision, bFixedPoint); - // Mirrors wkt - private static void writeEnvelopeAsGeoJsonPolygon_(int precision, boolean bFixedPoint, boolean b_export_zs, - boolean b_export_ms, double xmin, double ymin, double xmax, double ymax, double zmin, double zmax, - double mmin, double mmax, JsonWriter json_writer) { - json_writer.startArray(); - json_writer.startArray(); + if (b_export_ms) + json_writer.addValueDouble(mmin, precision, bFixedPoint); - json_writer.startArray(); - json_writer.addValueDouble(xmin, precision, bFixedPoint); - json_writer.addValueDouble(ymin, precision, bFixedPoint); + json_writer.endArray(); - if (b_export_zs) - json_writer.addValueDouble(zmin, precision, bFixedPoint); + json_writer.startArray(); + json_writer.addValueDouble(xmax, precision, bFixedPoint); + json_writer.addValueDouble(ymin, precision, bFixedPoint); - if (b_export_ms) - json_writer.addValueDouble(mmin, precision, bFixedPoint); + if (b_export_zs) + json_writer.addValueDouble(zmax, precision, bFixedPoint); - json_writer.endArray(); + if (b_export_ms) + json_writer.addValueDouble(mmax, precision, bFixedPoint); - json_writer.startArray(); - json_writer.addValueDouble(xmax, precision, bFixedPoint); - json_writer.addValueDouble(ymin, precision, bFixedPoint); + json_writer.endArray(); - if (b_export_zs) - json_writer.addValueDouble(zmax, precision, bFixedPoint); + json_writer.startArray(); + json_writer.addValueDouble(xmax, precision, bFixedPoint); + json_writer.addValueDouble(ymax, precision, bFixedPoint); - if (b_export_ms) - json_writer.addValueDouble(mmax, precision, bFixedPoint); + if (b_export_zs) + json_writer.addValueDouble(zmin, precision, bFixedPoint); - json_writer.endArray(); + if (b_export_ms) + json_writer.addValueDouble(mmin, precision, bFixedPoint); - json_writer.startArray(); - json_writer.addValueDouble(xmax, precision, bFixedPoint); - json_writer.addValueDouble(ymax, precision, bFixedPoint); + json_writer.endArray(); - if (b_export_zs) - json_writer.addValueDouble(zmin, precision, bFixedPoint); + json_writer.startArray(); + json_writer.addValueDouble(xmin, precision, bFixedPoint); + json_writer.addValueDouble(ymax, precision, bFixedPoint); - if (b_export_ms) - json_writer.addValueDouble(mmin, precision, bFixedPoint); + if (b_export_zs) + json_writer.addValueDouble(zmax, precision, bFixedPoint); - json_writer.endArray(); + if (b_export_ms) + json_writer.addValueDouble(mmax, precision, bFixedPoint); - json_writer.startArray(); - json_writer.addValueDouble(xmin, precision, bFixedPoint); - json_writer.addValueDouble(ymax, precision, bFixedPoint); + json_writer.endArray(); - if (b_export_zs) - json_writer.addValueDouble(zmax, precision, bFixedPoint); + json_writer.startArray(); + json_writer.addValueDouble(xmin, precision, bFixedPoint); + json_writer.addValueDouble(ymin, precision, bFixedPoint); - if (b_export_ms) - json_writer.addValueDouble(mmax, precision, bFixedPoint); + if (b_export_zs) + json_writer.addValueDouble(zmin, precision, bFixedPoint); - json_writer.endArray(); + if (b_export_ms) + json_writer.addValueDouble(mmin, precision, bFixedPoint); - json_writer.startArray(); - json_writer.addValueDouble(xmin, precision, bFixedPoint); - json_writer.addValueDouble(ymin, precision, bFixedPoint); + json_writer.endArray(); - if (b_export_zs) - json_writer.addValueDouble(zmin, precision, bFixedPoint); - - if (b_export_ms) - json_writer.addValueDouble(mmin, precision, bFixedPoint); - - json_writer.endArray(); - - json_writer.endArray(); - json_writer.endArray(); - } + json_writer.endArray(); + json_writer.endArray(); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorExportToGeoJsonLocal.java b/src/main/java/com/esri/core/geometry/OperatorExportToGeoJsonLocal.java index 30bd7ad2..9412cd83 100644 --- a/src/main/java/com/esri/core/geometry/OperatorExportToGeoJsonLocal.java +++ b/src/main/java/com/esri/core/geometry/OperatorExportToGeoJsonLocal.java @@ -23,28 +23,28 @@ package com.esri.core.geometry; class OperatorExportToGeoJsonLocal extends OperatorExportToGeoJson { - @Override - public StringCursor execute(SpatialReference spatialReference, GeometryCursor geometryCursor) { - return new OperatorExportToGeoJsonCursor(GeoJsonExportFlags.geoJsonExportDefaults, spatialReference, geometryCursor); - } - - @Override - public String execute(SpatialReference spatialReference, Geometry geometry) { - return OperatorExportToGeoJsonCursor.exportToGeoJson(GeoJsonExportFlags.geoJsonExportDefaults, geometry, spatialReference); - } - - @Override - public String execute(int exportFlags, SpatialReference spatialReference, Geometry geometry) { - return OperatorExportToGeoJsonCursor.exportToGeoJson(exportFlags, geometry, spatialReference); - } - - @Override - public String execute(Geometry geometry) { - return OperatorExportToGeoJsonCursor.exportToGeoJson(GeoJsonExportFlags.geoJsonExportSkipCRS, geometry, null); - } - - @Override - public String exportSpatialReference(int export_flags, SpatialReference spatial_reference) { - return OperatorExportToGeoJsonCursor.exportSpatialReference(export_flags, spatial_reference); - } + @Override + public StringCursor execute(SpatialReference spatialReference, GeometryCursor geometryCursor) { + return new OperatorExportToGeoJsonCursor(GeoJsonExportFlags.geoJsonExportDefaults, spatialReference, geometryCursor); + } + + @Override + public String execute(SpatialReference spatialReference, Geometry geometry) { + return OperatorExportToGeoJsonCursor.exportToGeoJson(GeoJsonExportFlags.geoJsonExportDefaults, geometry, spatialReference); + } + + @Override + public String execute(int exportFlags, SpatialReference spatialReference, Geometry geometry) { + return OperatorExportToGeoJsonCursor.exportToGeoJson(exportFlags, geometry, spatialReference); + } + + @Override + public String execute(Geometry geometry) { + return OperatorExportToGeoJsonCursor.exportToGeoJson(GeoJsonExportFlags.geoJsonExportSkipCRS, geometry, null); + } + + @Override + public String exportSpatialReference(int export_flags, SpatialReference spatial_reference) { + return OperatorExportToGeoJsonCursor.exportSpatialReference(export_flags, spatial_reference); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorExportToJson.java b/src/main/java/com/esri/core/geometry/OperatorExportToJson.java index 63cf5958..2bb814c0 100644 --- a/src/main/java/com/esri/core/geometry/OperatorExportToJson.java +++ b/src/main/java/com/esri/core/geometry/OperatorExportToJson.java @@ -32,37 +32,37 @@ */ public abstract class OperatorExportToJson extends Operator { - @Override - public Type getType() { - return Type.ExportToJson; - } + @Override + public Type getType() { + return Type.ExportToJson; + } - /** - * Performs the ExportToJson operation - * - * @return Returns a StringCursor. - */ - public abstract StringCursor execute(SpatialReference spatialReference, - GeometryCursor geometryCursor); + /** + * Performs the ExportToJson operation + * + * @return Returns a StringCursor. + */ + public abstract StringCursor execute(SpatialReference spatialReference, + GeometryCursor geometryCursor); - /** - * Performs the ExportToJson operation - * - * @return Returns a String. - */ - public abstract String execute(SpatialReference spatialReference, - Geometry geometry); + /** + * Performs the ExportToJson operation + * + * @return Returns a String. + */ + public abstract String execute(SpatialReference spatialReference, + Geometry geometry); - /** - * Performs the ExportToJson operation - * - * @return Returns a String. - */ - public abstract String execute(SpatialReference spatialReference, - Geometry geometry, Map exportProperties); + /** + * Performs the ExportToJson operation + * + * @return Returns a String. + */ + public abstract String execute(SpatialReference spatialReference, + Geometry geometry, Map exportProperties); - public static OperatorExportToJson local() { - return (OperatorExportToJson) OperatorFactoryLocal.getInstance() - .getOperator(Type.ExportToJson); - } + public static OperatorExportToJson local() { + return (OperatorExportToJson) OperatorFactoryLocal.getInstance() + .getOperator(Type.ExportToJson); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorExportToJsonCursor.java b/src/main/java/com/esri/core/geometry/OperatorExportToJsonCursor.java index 04b98896..7d7ae145 100644 --- a/src/main/java/com/esri/core/geometry/OperatorExportToJsonCursor.java +++ b/src/main/java/com/esri/core/geometry/OperatorExportToJsonCursor.java @@ -29,442 +29,446 @@ public class OperatorExportToJsonCursor extends StringCursor { - private GeometryCursor m_geometryCursor; - private SpatialReference m_spatialReference; - private SimpleStateEnum simpleStateEnum = SimpleStateEnum.SIMPLE_UNKNOWN; - - - public OperatorExportToJsonCursor(SpatialReference spatialReference, GeometryCursor geometryCursor) { - if (geometryCursor == null) { - throw new IllegalArgumentException(); - } - - m_geometryCursor = geometryCursor; - m_spatialReference = spatialReference; - } - - @Override - public boolean hasNext() { return m_geometryCursor != null && m_geometryCursor.hasNext(); } - - @Override - public long getID() { - return m_geometryCursor.getGeometryID(); - } - - @Override - public SimpleStateEnum getSimpleState() { return simpleStateEnum; } - - @Override - public String getFeatureID() { - return m_geometryCursor.getFeatureID(); - } - - @Override - public String next() { - Geometry geometry; - if (hasNext()) { - geometry = m_geometryCursor.next(); - simpleStateEnum = geometry.getSimpleState(); - return exportToString(geometry, m_spatialReference, null); - } - return null; - } - - static String exportToString(Geometry geometry, SpatialReference spatialReference, Map exportProperties) { - JsonWriter jsonWriter = new JsonStringWriter(); - exportToJson_(geometry, spatialReference, jsonWriter, exportProperties); - return (String) jsonWriter.getJson(); - } - - private static void exportToJson_(Geometry geometry, SpatialReference spatialReference, JsonWriter jsonWriter, Map exportProperties) { - try { - int type = geometry.getType().value(); - switch (type) { - case Geometry.GeometryType.Point: - exportPointToJson((Point) geometry, spatialReference, jsonWriter, exportProperties); - break; - - case Geometry.GeometryType.MultiPoint: - exportMultiPointToJson((MultiPoint) geometry, spatialReference, jsonWriter, exportProperties); - break; - - case Geometry.GeometryType.Polyline: - exportPolylineToJson((Polyline) geometry, spatialReference, jsonWriter, exportProperties); - break; - - case Geometry.GeometryType.Polygon: - exportPolygonToJson((Polygon) geometry, spatialReference, jsonWriter, exportProperties); - break; - - case Geometry.GeometryType.Envelope: - exportEnvelopeToJson((Envelope) geometry, spatialReference, jsonWriter, exportProperties); - break; - - default: - throw new RuntimeException("not implemented for this geometry type"); - } - - } catch (Exception e) { - } - - } - - private static void exportPolygonToJson(Polygon pp, SpatialReference spatialReference, JsonWriter jsonWriter, Map exportProperties) { - exportPolypathToJson(pp, "rings", spatialReference, jsonWriter, exportProperties); - } - - private static void exportPolylineToJson(Polyline pp, SpatialReference spatialReference, JsonWriter jsonWriter, Map exportProperties) { - exportPolypathToJson(pp, "paths", spatialReference, jsonWriter, exportProperties); - } - - private static void exportPolypathToJson(MultiPath pp, String name, SpatialReference spatialReference, JsonWriter jsonWriter, Map exportProperties) { - boolean bExportZs = pp.hasAttribute(Semantics.Z); - boolean bExportMs = pp.hasAttribute(Semantics.M); - - boolean bPositionAsF = false; - int decimals = 17; - - if (exportProperties != null) { - Object numberOfDecimalsXY = exportProperties.get("numberOfDecimalsXY"); - if (numberOfDecimalsXY != null && numberOfDecimalsXY instanceof Number) { - bPositionAsF = true; - decimals = ((Number) numberOfDecimalsXY).intValue(); - } - } - - jsonWriter.startObject(); - - if (bExportZs) { - jsonWriter.addPairBoolean("hasZ", true); - } - - if (bExportMs) { - jsonWriter.addPairBoolean("hasM", true); - } - - jsonWriter.addPairArray(name); - - if (!pp.isEmpty()) { - int n = pp.getPathCount(); // rings or paths - - MultiPathImpl mpImpl = (MultiPathImpl) pp._getImpl();// get impl for - // faster - // access - AttributeStreamOfDbl zs = null; - AttributeStreamOfDbl ms = null; - - if (bExportZs) { - zs = (AttributeStreamOfDbl) mpImpl.getAttributeStreamRef(Semantics.Z); - } - - if (bExportMs) { - ms = (AttributeStreamOfDbl) mpImpl.getAttributeStreamRef(Semantics.M); - } - - boolean bPolygon = pp instanceof Polygon; - Point2D pt = new Point2D(); - - for (int i = 0; i < n; i++) { - jsonWriter.addValueArray(); - int startindex = pp.getPathStart(i); - int numVertices = pp.getPathSize(i); - double startx = 0.0, starty = 0.0, startz = NumberUtils.NaN(), startm = NumberUtils.NaN(); - double z = NumberUtils.NaN(), m = NumberUtils.NaN(); - boolean bClosed = pp.isClosedPath(i); - for (int j = startindex; j < startindex + numVertices; j++) { - pp.getXY(j, pt); - - jsonWriter.addValueArray(); - - if (bPositionAsF) { - jsonWriter.addValueDouble(pt.x, decimals, true); - jsonWriter.addValueDouble(pt.y, decimals, true); - } else { - jsonWriter.addValueDouble(pt.x); - jsonWriter.addValueDouble(pt.y); - } - - if (bExportZs) { - z = zs.get(j); - jsonWriter.addValueDouble(z); - } - - if (bExportMs) { - m = ms.get(j); - jsonWriter.addValueDouble(m); - } - - if (j == startindex && bClosed) { - startx = pt.x; - starty = pt.y; - startz = z; - startm = m; - } - - jsonWriter.endArray(); - } - - // Close the Path/Ring by writing the Point at the start index - if (bClosed && (startx != pt.x || starty != pt.y || (bExportZs && !(NumberUtils.isNaN(startz) && NumberUtils.isNaN(z)) && startz != z) || (bExportMs && !(NumberUtils.isNaN(startm) && NumberUtils.isNaN(m)) && startm != m))) { - pp.getXY(startindex, pt); - // getPoint(startindex); - jsonWriter.addValueArray(); - - if (bPositionAsF) { - jsonWriter.addValueDouble(pt.x, decimals, true); - jsonWriter.addValueDouble(pt.y, decimals, true); - } else { - jsonWriter.addValueDouble(pt.x); - jsonWriter.addValueDouble(pt.y); - } - - if (bExportZs) { - z = zs.get(startindex); - jsonWriter.addValueDouble(z); - } - - if (bExportMs) { - m = ms.get(startindex); - jsonWriter.addValueDouble(m); - } - - jsonWriter.endArray(); - } - - jsonWriter.endArray(); - } - } - - jsonWriter.endArray(); - - if (spatialReference != null) { - writeSR(spatialReference, jsonWriter); - } - - jsonWriter.endObject(); - } - - private static void exportMultiPointToJson(MultiPoint mpt, SpatialReference spatialReference, JsonWriter jsonWriter, Map exportProperties) { - boolean bExportZs = mpt.hasAttribute(Semantics.Z); - boolean bExportMs = mpt.hasAttribute(Semantics.M); - - boolean bPositionAsF = false; - int decimals = 17; - - if (exportProperties != null) { - Object numberOfDecimalsXY = exportProperties.get("numberOfDecimalsXY"); - if (numberOfDecimalsXY != null && numberOfDecimalsXY instanceof Number) { - bPositionAsF = true; - decimals = ((Number) numberOfDecimalsXY).intValue(); - } - } - - jsonWriter.startObject(); - - if (bExportZs) { - jsonWriter.addPairBoolean("hasZ", true); - } - - if (bExportMs) { - jsonWriter.addPairBoolean("hasM", true); - } - - jsonWriter.addPairArray("points"); - - if (!mpt.isEmpty()) { - MultiPointImpl mpImpl = (MultiPointImpl) mpt._getImpl();// get impl - // for - // faster - // access - AttributeStreamOfDbl zs = null; - AttributeStreamOfDbl ms = null; - - if (bExportZs) { - zs = (AttributeStreamOfDbl) mpImpl.getAttributeStreamRef(Semantics.Z); - } - - if (bExportMs) { - ms = (AttributeStreamOfDbl) mpImpl.getAttributeStreamRef(Semantics.M); - } - - Point2D pt = new Point2D(); - int n = mpt.getPointCount(); - for (int i = 0; i < n; i++) { - mpt.getXY(i, pt); - - jsonWriter.addValueArray(); - - if (bPositionAsF) { - jsonWriter.addValueDouble(pt.x, decimals, true); - jsonWriter.addValueDouble(pt.y, decimals, true); - } else { - jsonWriter.addValueDouble(pt.x); - jsonWriter.addValueDouble(pt.y); - } - - if (bExportZs) { - double z = zs.get(i); - jsonWriter.addValueDouble(z); - } - - if (bExportMs) { - double m = ms.get(i); - jsonWriter.addValueDouble(m); - } - - jsonWriter.endArray(); - } - } - - jsonWriter.endArray(); - - if (spatialReference != null) { - writeSR(spatialReference, jsonWriter); - } - - jsonWriter.endObject(); - } - - private static void exportPointToJson(Point pt, SpatialReference spatialReference, JsonWriter jsonWriter, Map exportProperties) { - boolean bExportZs = pt.hasAttribute(Semantics.Z); - boolean bExportMs = pt.hasAttribute(Semantics.M); - - boolean bPositionAsF = false; - int decimals = 17; - - if (exportProperties != null) { - Object numberOfDecimalsXY = exportProperties.get("numberOfDecimalsXY"); - if (numberOfDecimalsXY != null && numberOfDecimalsXY instanceof Number) { - bPositionAsF = true; - decimals = ((Number) numberOfDecimalsXY).intValue(); - } - } - - jsonWriter.startObject(); - - if (pt.isEmpty()) { - jsonWriter.addPairNull("x"); - jsonWriter.addPairNull("y"); - - if (bExportZs) { - jsonWriter.addPairNull("z"); - } - - if (bExportMs) { - jsonWriter.addPairNull("m"); - } - } else { - - if (bPositionAsF) { - jsonWriter.addPairDouble("x", pt.getX(), decimals, true); - jsonWriter.addPairDouble("y", pt.getY(), decimals, true); - } else { - jsonWriter.addPairDouble("x", pt.getX()); - jsonWriter.addPairDouble("y", pt.getY()); - } - - if (bExportZs) { - jsonWriter.addPairDouble("z", pt.getZ()); - } - - if (bExportMs) { - jsonWriter.addPairDouble("m", pt.getM()); - } - } - - if (spatialReference != null) { - writeSR(spatialReference, jsonWriter); - } - - jsonWriter.endObject(); - } - - private static void exportEnvelopeToJson(Envelope env, SpatialReference spatialReference, JsonWriter jsonWriter, Map exportProperties) { - boolean bExportZs = env.hasAttribute(Semantics.Z); - boolean bExportMs = env.hasAttribute(Semantics.M); - - boolean bPositionAsF = false; - int decimals = 17; - - if (exportProperties != null) { - Object numberOfDecimalsXY = exportProperties.get("numberOfDecimalsXY"); - if (numberOfDecimalsXY != null && numberOfDecimalsXY instanceof Number) { - bPositionAsF = true; - decimals = ((Number) numberOfDecimalsXY).intValue(); - } - } - - jsonWriter.startObject(); - - if (env.isEmpty()) { - jsonWriter.addPairNull("xmin"); - jsonWriter.addPairNull("ymin"); - jsonWriter.addPairNull("xmax"); - jsonWriter.addPairNull("ymax"); - - if (bExportZs) { - jsonWriter.addPairNull("zmin"); - jsonWriter.addPairNull("zmax"); - } - - if (bExportMs) { - jsonWriter.addPairNull("mmin"); - jsonWriter.addPairNull("mmax"); - } - } else { - - if (bPositionAsF) { - jsonWriter.addPairDouble("xmin", env.getXMin(), decimals, true); - jsonWriter.addPairDouble("ymin", env.getYMin(), decimals, true); - jsonWriter.addPairDouble("xmax", env.getXMax(), decimals, true); - jsonWriter.addPairDouble("ymax", env.getYMax(), decimals, true); - } else { - jsonWriter.addPairDouble("xmin", env.getXMin()); - jsonWriter.addPairDouble("ymin", env.getYMin()); - jsonWriter.addPairDouble("xmax", env.getXMax()); - jsonWriter.addPairDouble("ymax", env.getYMax()); - } - - if (bExportZs) { - Envelope1D z = env.queryInterval(Semantics.Z, 0); - jsonWriter.addPairDouble("zmin", z.vmin); - jsonWriter.addPairDouble("zmax", z.vmax); - } - - if (bExportMs) { - Envelope1D m = env.queryInterval(Semantics.M, 0); - jsonWriter.addPairDouble("mmin", m.vmin); - jsonWriter.addPairDouble("mmax", m.vmax); - } - } - - if (spatialReference != null) { - writeSR(spatialReference, jsonWriter); - } - - jsonWriter.endObject(); - } - - private static void writeSR(SpatialReference spatialReference, JsonWriter jsonWriter) { - int wkid = spatialReference.getOldID(); - if (wkid > 0) { - jsonWriter.addPairObject("spatialReference"); - - jsonWriter.addPairInt("wkid", wkid); - - int latest_wkid = spatialReference.getLatestID(); - if (latest_wkid > 0 && latest_wkid != wkid) { - jsonWriter.addPairInt("latestWkid", latest_wkid); - } - - jsonWriter.endObject(); - } else { - String wkt = spatialReference.getText(); - if (wkt != null) { - jsonWriter.addPairObject("spatialReference"); - jsonWriter.addPairString("wkt", wkt); - jsonWriter.endObject(); - } - } - } + private GeometryCursor m_geometryCursor; + private SpatialReference m_spatialReference; + private SimpleStateEnum simpleStateEnum = SimpleStateEnum.SIMPLE_UNKNOWN; + + + public OperatorExportToJsonCursor(SpatialReference spatialReference, GeometryCursor geometryCursor) { + if (geometryCursor == null) { + throw new IllegalArgumentException(); + } + + m_geometryCursor = geometryCursor; + m_spatialReference = spatialReference; + } + + @Override + public boolean hasNext() { + return m_geometryCursor != null && m_geometryCursor.hasNext(); + } + + @Override + public long getID() { + return m_geometryCursor.getGeometryID(); + } + + @Override + public SimpleStateEnum getSimpleState() { + return simpleStateEnum; + } + + @Override + public String getFeatureID() { + return m_geometryCursor.getFeatureID(); + } + + @Override + public String next() { + Geometry geometry; + if (hasNext()) { + geometry = m_geometryCursor.next(); + simpleStateEnum = geometry.getSimpleState(); + return exportToString(geometry, m_spatialReference, null); + } + return null; + } + + static String exportToString(Geometry geometry, SpatialReference spatialReference, Map exportProperties) { + JsonWriter jsonWriter = new JsonStringWriter(); + exportToJson_(geometry, spatialReference, jsonWriter, exportProperties); + return (String) jsonWriter.getJson(); + } + + private static void exportToJson_(Geometry geometry, SpatialReference spatialReference, JsonWriter jsonWriter, Map exportProperties) { + try { + int type = geometry.getType().value(); + switch (type) { + case Geometry.GeometryType.Point: + exportPointToJson((Point) geometry, spatialReference, jsonWriter, exportProperties); + break; + + case Geometry.GeometryType.MultiPoint: + exportMultiPointToJson((MultiPoint) geometry, spatialReference, jsonWriter, exportProperties); + break; + + case Geometry.GeometryType.Polyline: + exportPolylineToJson((Polyline) geometry, spatialReference, jsonWriter, exportProperties); + break; + + case Geometry.GeometryType.Polygon: + exportPolygonToJson((Polygon) geometry, spatialReference, jsonWriter, exportProperties); + break; + + case Geometry.GeometryType.Envelope: + exportEnvelopeToJson((Envelope) geometry, spatialReference, jsonWriter, exportProperties); + break; + + default: + throw new RuntimeException("not implemented for this geometry type"); + } + + } catch (Exception e) { + } + + } + + private static void exportPolygonToJson(Polygon pp, SpatialReference spatialReference, JsonWriter jsonWriter, Map exportProperties) { + exportPolypathToJson(pp, "rings", spatialReference, jsonWriter, exportProperties); + } + + private static void exportPolylineToJson(Polyline pp, SpatialReference spatialReference, JsonWriter jsonWriter, Map exportProperties) { + exportPolypathToJson(pp, "paths", spatialReference, jsonWriter, exportProperties); + } + + private static void exportPolypathToJson(MultiPath pp, String name, SpatialReference spatialReference, JsonWriter jsonWriter, Map exportProperties) { + boolean bExportZs = pp.hasAttribute(Semantics.Z); + boolean bExportMs = pp.hasAttribute(Semantics.M); + + boolean bPositionAsF = false; + int decimals = 17; + + if (exportProperties != null) { + Object numberOfDecimalsXY = exportProperties.get("numberOfDecimalsXY"); + if (numberOfDecimalsXY != null && numberOfDecimalsXY instanceof Number) { + bPositionAsF = true; + decimals = ((Number) numberOfDecimalsXY).intValue(); + } + } + + jsonWriter.startObject(); + + if (bExportZs) { + jsonWriter.addPairBoolean("hasZ", true); + } + + if (bExportMs) { + jsonWriter.addPairBoolean("hasM", true); + } + + jsonWriter.addPairArray(name); + + if (!pp.isEmpty()) { + int n = pp.getPathCount(); // rings or paths + + MultiPathImpl mpImpl = (MultiPathImpl) pp._getImpl();// get impl for + // faster + // access + AttributeStreamOfDbl zs = null; + AttributeStreamOfDbl ms = null; + + if (bExportZs) { + zs = (AttributeStreamOfDbl) mpImpl.getAttributeStreamRef(Semantics.Z); + } + + if (bExportMs) { + ms = (AttributeStreamOfDbl) mpImpl.getAttributeStreamRef(Semantics.M); + } + + boolean bPolygon = pp instanceof Polygon; + Point2D pt = new Point2D(); + + for (int i = 0; i < n; i++) { + jsonWriter.addValueArray(); + int startindex = pp.getPathStart(i); + int numVertices = pp.getPathSize(i); + double startx = 0.0, starty = 0.0, startz = NumberUtils.NaN(), startm = NumberUtils.NaN(); + double z = NumberUtils.NaN(), m = NumberUtils.NaN(); + boolean bClosed = pp.isClosedPath(i); + for (int j = startindex; j < startindex + numVertices; j++) { + pp.getXY(j, pt); + + jsonWriter.addValueArray(); + + if (bPositionAsF) { + jsonWriter.addValueDouble(pt.x, decimals, true); + jsonWriter.addValueDouble(pt.y, decimals, true); + } else { + jsonWriter.addValueDouble(pt.x); + jsonWriter.addValueDouble(pt.y); + } + + if (bExportZs) { + z = zs.get(j); + jsonWriter.addValueDouble(z); + } + + if (bExportMs) { + m = ms.get(j); + jsonWriter.addValueDouble(m); + } + + if (j == startindex && bClosed) { + startx = pt.x; + starty = pt.y; + startz = z; + startm = m; + } + + jsonWriter.endArray(); + } + + // Close the Path/Ring by writing the Point at the start index + if (bClosed && (startx != pt.x || starty != pt.y || (bExportZs && !(NumberUtils.isNaN(startz) && NumberUtils.isNaN(z)) && startz != z) || (bExportMs && !(NumberUtils.isNaN(startm) && NumberUtils.isNaN(m)) && startm != m))) { + pp.getXY(startindex, pt); + // getPoint(startindex); + jsonWriter.addValueArray(); + + if (bPositionAsF) { + jsonWriter.addValueDouble(pt.x, decimals, true); + jsonWriter.addValueDouble(pt.y, decimals, true); + } else { + jsonWriter.addValueDouble(pt.x); + jsonWriter.addValueDouble(pt.y); + } + + if (bExportZs) { + z = zs.get(startindex); + jsonWriter.addValueDouble(z); + } + + if (bExportMs) { + m = ms.get(startindex); + jsonWriter.addValueDouble(m); + } + + jsonWriter.endArray(); + } + + jsonWriter.endArray(); + } + } + + jsonWriter.endArray(); + + if (spatialReference != null) { + writeSR(spatialReference, jsonWriter); + } + + jsonWriter.endObject(); + } + + private static void exportMultiPointToJson(MultiPoint mpt, SpatialReference spatialReference, JsonWriter jsonWriter, Map exportProperties) { + boolean bExportZs = mpt.hasAttribute(Semantics.Z); + boolean bExportMs = mpt.hasAttribute(Semantics.M); + + boolean bPositionAsF = false; + int decimals = 17; + + if (exportProperties != null) { + Object numberOfDecimalsXY = exportProperties.get("numberOfDecimalsXY"); + if (numberOfDecimalsXY != null && numberOfDecimalsXY instanceof Number) { + bPositionAsF = true; + decimals = ((Number) numberOfDecimalsXY).intValue(); + } + } + + jsonWriter.startObject(); + + if (bExportZs) { + jsonWriter.addPairBoolean("hasZ", true); + } + + if (bExportMs) { + jsonWriter.addPairBoolean("hasM", true); + } + + jsonWriter.addPairArray("points"); + + if (!mpt.isEmpty()) { + MultiPointImpl mpImpl = (MultiPointImpl) mpt._getImpl();// get impl + // for + // faster + // access + AttributeStreamOfDbl zs = null; + AttributeStreamOfDbl ms = null; + + if (bExportZs) { + zs = (AttributeStreamOfDbl) mpImpl.getAttributeStreamRef(Semantics.Z); + } + + if (bExportMs) { + ms = (AttributeStreamOfDbl) mpImpl.getAttributeStreamRef(Semantics.M); + } + + Point2D pt = new Point2D(); + int n = mpt.getPointCount(); + for (int i = 0; i < n; i++) { + mpt.getXY(i, pt); + + jsonWriter.addValueArray(); + + if (bPositionAsF) { + jsonWriter.addValueDouble(pt.x, decimals, true); + jsonWriter.addValueDouble(pt.y, decimals, true); + } else { + jsonWriter.addValueDouble(pt.x); + jsonWriter.addValueDouble(pt.y); + } + + if (bExportZs) { + double z = zs.get(i); + jsonWriter.addValueDouble(z); + } + + if (bExportMs) { + double m = ms.get(i); + jsonWriter.addValueDouble(m); + } + + jsonWriter.endArray(); + } + } + + jsonWriter.endArray(); + + if (spatialReference != null) { + writeSR(spatialReference, jsonWriter); + } + + jsonWriter.endObject(); + } + + private static void exportPointToJson(Point pt, SpatialReference spatialReference, JsonWriter jsonWriter, Map exportProperties) { + boolean bExportZs = pt.hasAttribute(Semantics.Z); + boolean bExportMs = pt.hasAttribute(Semantics.M); + + boolean bPositionAsF = false; + int decimals = 17; + + if (exportProperties != null) { + Object numberOfDecimalsXY = exportProperties.get("numberOfDecimalsXY"); + if (numberOfDecimalsXY != null && numberOfDecimalsXY instanceof Number) { + bPositionAsF = true; + decimals = ((Number) numberOfDecimalsXY).intValue(); + } + } + + jsonWriter.startObject(); + + if (pt.isEmpty()) { + jsonWriter.addPairNull("x"); + jsonWriter.addPairNull("y"); + + if (bExportZs) { + jsonWriter.addPairNull("z"); + } + + if (bExportMs) { + jsonWriter.addPairNull("m"); + } + } else { + + if (bPositionAsF) { + jsonWriter.addPairDouble("x", pt.getX(), decimals, true); + jsonWriter.addPairDouble("y", pt.getY(), decimals, true); + } else { + jsonWriter.addPairDouble("x", pt.getX()); + jsonWriter.addPairDouble("y", pt.getY()); + } + + if (bExportZs) { + jsonWriter.addPairDouble("z", pt.getZ()); + } + + if (bExportMs) { + jsonWriter.addPairDouble("m", pt.getM()); + } + } + + if (spatialReference != null) { + writeSR(spatialReference, jsonWriter); + } + + jsonWriter.endObject(); + } + + private static void exportEnvelopeToJson(Envelope env, SpatialReference spatialReference, JsonWriter jsonWriter, Map exportProperties) { + boolean bExportZs = env.hasAttribute(Semantics.Z); + boolean bExportMs = env.hasAttribute(Semantics.M); + + boolean bPositionAsF = false; + int decimals = 17; + + if (exportProperties != null) { + Object numberOfDecimalsXY = exportProperties.get("numberOfDecimalsXY"); + if (numberOfDecimalsXY != null && numberOfDecimalsXY instanceof Number) { + bPositionAsF = true; + decimals = ((Number) numberOfDecimalsXY).intValue(); + } + } + + jsonWriter.startObject(); + + if (env.isEmpty()) { + jsonWriter.addPairNull("xmin"); + jsonWriter.addPairNull("ymin"); + jsonWriter.addPairNull("xmax"); + jsonWriter.addPairNull("ymax"); + + if (bExportZs) { + jsonWriter.addPairNull("zmin"); + jsonWriter.addPairNull("zmax"); + } + + if (bExportMs) { + jsonWriter.addPairNull("mmin"); + jsonWriter.addPairNull("mmax"); + } + } else { + + if (bPositionAsF) { + jsonWriter.addPairDouble("xmin", env.getXMin(), decimals, true); + jsonWriter.addPairDouble("ymin", env.getYMin(), decimals, true); + jsonWriter.addPairDouble("xmax", env.getXMax(), decimals, true); + jsonWriter.addPairDouble("ymax", env.getYMax(), decimals, true); + } else { + jsonWriter.addPairDouble("xmin", env.getXMin()); + jsonWriter.addPairDouble("ymin", env.getYMin()); + jsonWriter.addPairDouble("xmax", env.getXMax()); + jsonWriter.addPairDouble("ymax", env.getYMax()); + } + + if (bExportZs) { + Envelope1D z = env.queryInterval(Semantics.Z, 0); + jsonWriter.addPairDouble("zmin", z.vmin); + jsonWriter.addPairDouble("zmax", z.vmax); + } + + if (bExportMs) { + Envelope1D m = env.queryInterval(Semantics.M, 0); + jsonWriter.addPairDouble("mmin", m.vmin); + jsonWriter.addPairDouble("mmax", m.vmax); + } + } + + if (spatialReference != null) { + writeSR(spatialReference, jsonWriter); + } + + jsonWriter.endObject(); + } + + private static void writeSR(SpatialReference spatialReference, JsonWriter jsonWriter) { + int wkid = spatialReference.getOldID(); + if (wkid > 0) { + jsonWriter.addPairObject("spatialReference"); + + jsonWriter.addPairInt("wkid", wkid); + + int latest_wkid = spatialReference.getLatestID(); + if (latest_wkid > 0 && latest_wkid != wkid) { + jsonWriter.addPairInt("latestWkid", latest_wkid); + } + + jsonWriter.endObject(); + } else { + String wkt = spatialReference.getText(); + if (wkt != null) { + jsonWriter.addPairObject("spatialReference"); + jsonWriter.addPairString("wkt", wkt); + jsonWriter.endObject(); + } + } + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorExportToJsonLocal.java b/src/main/java/com/esri/core/geometry/OperatorExportToJsonLocal.java index 90c7880c..5446bf9b 100644 --- a/src/main/java/com/esri/core/geometry/OperatorExportToJsonLocal.java +++ b/src/main/java/com/esri/core/geometry/OperatorExportToJsonLocal.java @@ -27,22 +27,22 @@ class OperatorExportToJsonLocal extends OperatorExportToJson { - @Override - public StringCursor execute(SpatialReference spatialReference, - GeometryCursor geometryCursor) { - return new OperatorExportToJsonCursor(spatialReference, geometryCursor); - } - - @Override - public String execute(SpatialReference spatialReference, Geometry geometry) { - SimpleGeometryCursor gc = new SimpleGeometryCursor(geometry); - StringCursor cursor = new OperatorExportToJsonCursor(spatialReference, gc); - return cursor.next(); - } - - @Override - public String execute(SpatialReference spatialReference, - Geometry geometry, Map exportProperties) { - return OperatorExportToJsonCursor.exportToString(geometry, spatialReference, exportProperties); - } + @Override + public StringCursor execute(SpatialReference spatialReference, + GeometryCursor geometryCursor) { + return new OperatorExportToJsonCursor(spatialReference, geometryCursor); + } + + @Override + public String execute(SpatialReference spatialReference, Geometry geometry) { + SimpleGeometryCursor gc = new SimpleGeometryCursor(geometry); + StringCursor cursor = new OperatorExportToJsonCursor(spatialReference, gc); + return cursor.next(); + } + + @Override + public String execute(SpatialReference spatialReference, + Geometry geometry, Map exportProperties) { + return OperatorExportToJsonCursor.exportToString(geometry, spatialReference, exportProperties); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorExportToWkb.java b/src/main/java/com/esri/core/geometry/OperatorExportToWkb.java index 67b1d2a6..86b6d48d 100644 --- a/src/main/java/com/esri/core/geometry/OperatorExportToWkb.java +++ b/src/main/java/com/esri/core/geometry/OperatorExportToWkb.java @@ -32,41 +32,41 @@ * Export to WKB format. */ public abstract class OperatorExportToWkb extends Operator { - @Override - public Type getType() { - return Type.ExportToWkb; - } + @Override + public Type getType() { + return Type.ExportToWkb; + } - /** - * Performs the ExportToWKB operation on cursor of geometries - * - * @param exportFlags This should probably be removed - * @param geometryCursor - * @return - */ - public abstract ByteBufferCursor execute(int exportFlags, GeometryCursor geometryCursor); + /** + * Performs the ExportToWKB operation on cursor of geometries + * + * @param exportFlags This should probably be removed + * @param geometryCursor + * @return + */ + public abstract ByteBufferCursor execute(int exportFlags, GeometryCursor geometryCursor); - /** - * Performs the ExportToWKB operation. - * - * @param exportFlags Use the {@link WkbExportFlags} interface. - * @param geometry The Geometry being exported. - * @return Returns a ByteBuffer object containing the Geometry in WKB format - */ - public abstract ByteBuffer execute(int exportFlags, Geometry geometry, ProgressTracker progressTracker); + /** + * Performs the ExportToWKB operation. + * + * @param exportFlags Use the {@link WkbExportFlags} interface. + * @param geometry The Geometry being exported. + * @return Returns a ByteBuffer object containing the Geometry in WKB format + */ + public abstract ByteBuffer execute(int exportFlags, Geometry geometry, ProgressTracker progressTracker); - /** - * Performs the ExportToWKB operation. - * - * @param exportFlags Use the {@link WkbExportFlags} interface. - * @param geometry The Geometry being exported. - * @param wkbBuffer The ByteBuffer to contain the exported Geometry in WKB format. - * @return If the input buffer is null, then the size needed for the buffer is returned. Otherwise the number of bytes written to the buffer is returned. - */ - public abstract int execute(int exportFlags, Geometry geometry, ByteBuffer wkbBuffer, ProgressTracker progressTracker); + /** + * Performs the ExportToWKB operation. + * + * @param exportFlags Use the {@link WkbExportFlags} interface. + * @param geometry The Geometry being exported. + * @param wkbBuffer The ByteBuffer to contain the exported Geometry in WKB format. + * @return If the input buffer is null, then the size needed for the buffer is returned. Otherwise the number of bytes written to the buffer is returned. + */ + public abstract int execute(int exportFlags, Geometry geometry, ByteBuffer wkbBuffer, ProgressTracker progressTracker); - public static OperatorExportToWkb local() { - return (OperatorExportToWkb) OperatorFactoryLocal.getInstance().getOperator(Type.ExportToWkb); - } + public static OperatorExportToWkb local() { + return (OperatorExportToWkb) OperatorFactoryLocal.getInstance().getOperator(Type.ExportToWkb); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorExportToWkbCursor.java b/src/main/java/com/esri/core/geometry/OperatorExportToWkbCursor.java index 019f85b2..ca207237 100644 --- a/src/main/java/com/esri/core/geometry/OperatorExportToWkbCursor.java +++ b/src/main/java/com/esri/core/geometry/OperatorExportToWkbCursor.java @@ -4,49 +4,49 @@ import java.nio.ByteOrder; public class OperatorExportToWkbCursor extends ByteBufferCursor { - private GeometryCursor m_geometryCursor; - private int m_exportFlags; - private SimpleStateEnum simpleStateEnum = SimpleStateEnum.SIMPLE_UNKNOWN; - - public OperatorExportToWkbCursor(int exportFlags, GeometryCursor geometryCursor) { - if (geometryCursor == null) - throw new GeometryException("invalid argument"); - - m_exportFlags = exportFlags; - m_geometryCursor = geometryCursor; - } - - @Override - public boolean hasNext() { - return m_geometryCursor != null && m_geometryCursor.hasNext(); - } - - @Override - public ByteBuffer next() { - Geometry geometry; - if (hasNext()) { - geometry = m_geometryCursor.next(); - simpleStateEnum = geometry.getSimpleState(); - int size = OperatorExportToWkbLocal.exportToWKB(m_exportFlags, geometry, null); - ByteBuffer wkbBuffer = ByteBuffer.allocate(size).order(ByteOrder.nativeOrder()); - OperatorExportToWkbLocal.exportToWKB(m_exportFlags, geometry, wkbBuffer); - return wkbBuffer; - } - return null; - } - - @Override - public long getByteBufferID() { - return m_geometryCursor.getGeometryID(); - } - - @Override - public SimpleStateEnum getSimpleState() { - return simpleStateEnum; - } - - @Override - public String getFeatureID() { - return m_geometryCursor.getFeatureID(); - } + private GeometryCursor m_geometryCursor; + private int m_exportFlags; + private SimpleStateEnum simpleStateEnum = SimpleStateEnum.SIMPLE_UNKNOWN; + + public OperatorExportToWkbCursor(int exportFlags, GeometryCursor geometryCursor) { + if (geometryCursor == null) + throw new GeometryException("invalid argument"); + + m_exportFlags = exportFlags; + m_geometryCursor = geometryCursor; + } + + @Override + public boolean hasNext() { + return m_geometryCursor != null && m_geometryCursor.hasNext(); + } + + @Override + public ByteBuffer next() { + Geometry geometry; + if (hasNext()) { + geometry = m_geometryCursor.next(); + simpleStateEnum = geometry.getSimpleState(); + int size = OperatorExportToWkbLocal.exportToWKB(m_exportFlags, geometry, null); + ByteBuffer wkbBuffer = ByteBuffer.allocate(size).order(ByteOrder.nativeOrder()); + OperatorExportToWkbLocal.exportToWKB(m_exportFlags, geometry, wkbBuffer); + return wkbBuffer; + } + return null; + } + + @Override + public long getByteBufferID() { + return m_geometryCursor.getGeometryID(); + } + + @Override + public SimpleStateEnum getSimpleState() { + return simpleStateEnum; + } + + @Override + public String getFeatureID() { + return m_geometryCursor.getFeatureID(); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorExportToWkbLocal.java b/src/main/java/com/esri/core/geometry/OperatorExportToWkbLocal.java index 51c62f39..11a274ff 100644 --- a/src/main/java/com/esri/core/geometry/OperatorExportToWkbLocal.java +++ b/src/main/java/com/esri/core/geometry/OperatorExportToWkbLocal.java @@ -29,1224 +29,1224 @@ class OperatorExportToWkbLocal extends OperatorExportToWkb { - @Override - public ByteBufferCursor execute(int exportFlags, GeometryCursor geometryCursor) { - return new OperatorExportToWkbCursor(exportFlags, geometryCursor); - } - - @Override - public ByteBuffer execute(int exportFlags, Geometry geometry, ProgressTracker progressTracker) { - int size = exportToWKB(exportFlags, geometry, null); - ByteBuffer wkbBuffer = ByteBuffer.allocate(size).order(ByteOrder.nativeOrder()); - exportToWKB(exportFlags, geometry, wkbBuffer); - return wkbBuffer; - } - - @Override - public int execute(int exportFlags, Geometry geometry, - ByteBuffer wkbBuffer, ProgressTracker progressTracker) { - return exportToWKB(exportFlags, geometry, wkbBuffer); - } - - protected static int exportToWKB(int exportFlags, Geometry geometry, - ByteBuffer wkbBuffer) { - if (geometry == null) - return 0; - - int type = geometry.getType().value(); - switch (type) { - case Geometry.GeometryType.Polygon: - if ((exportFlags & WkbExportFlags.wkbExportLineString) != 0 - || (exportFlags & WkbExportFlags.wkbExportMultiLineString) != 0 - || (exportFlags & WkbExportFlags.wkbExportPoint) != 0 - || (exportFlags & WkbExportFlags.wkbExportMultiPoint) != 0) - throw new GeometryException("invalid argument"); - - return exportPolygonToWKB(exportFlags, (Polygon) geometry, - wkbBuffer); - case Geometry.GeometryType.Polyline: - if ((exportFlags & WkbExportFlags.wkbExportPolygon) != 0 - || (exportFlags & WkbExportFlags.wkbExportMultiPolygon) != 0 - || (exportFlags & WkbExportFlags.wkbExportPoint) != 0 - || (exportFlags & WkbExportFlags.wkbExportMultiPoint) != 0) - throw new GeometryException("invalid argument"); - return exportPolylineToWKB(exportFlags, (Polyline) geometry, - wkbBuffer); - - case Geometry.GeometryType.MultiPoint: - if ((exportFlags & WkbExportFlags.wkbExportLineString) != 0 - || (exportFlags & WkbExportFlags.wkbExportMultiLineString) != 0 - || (exportFlags & WkbExportFlags.wkbExportPolygon) != 0 - || (exportFlags & WkbExportFlags.wkbExportMultiPolygon) != 0) - throw new GeometryException("invalid argument"); - return exportMultiPointToWKB(exportFlags, (MultiPoint) geometry, - wkbBuffer); - - case Geometry.GeometryType.Point: - if ((exportFlags & WkbExportFlags.wkbExportLineString) != 0 - || (exportFlags & WkbExportFlags.wkbExportMultiLineString) != 0 - || (exportFlags & WkbExportFlags.wkbExportPolygon) != 0 - || (exportFlags & WkbExportFlags.wkbExportMultiPolygon) != 0) - throw new GeometryException("invalid argument"); - return exportPointToWKB(exportFlags, (Point) geometry, wkbBuffer); - - case Geometry.GeometryType.Envelope: - if ((exportFlags & WkbExportFlags.wkbExportLineString) != 0 - || (exportFlags & WkbExportFlags.wkbExportMultiLineString) != 0 - || (exportFlags & WkbExportFlags.wkbExportPoint) != 0 - || (exportFlags & WkbExportFlags.wkbExportMultiPoint) != 0) - throw new GeometryException("invalid argument"); - return exportEnvelopeToWKB(exportFlags, (Envelope) geometry, - wkbBuffer); - - default: { - throw GeometryException.GeometryInternalError(); - // return -1; - } - } - } - - private static int exportPolygonToWKB(int exportFlags, Polygon _polygon, - ByteBuffer wkbBuffer) { - MultiPathImpl polygon = (MultiPathImpl) _polygon._getImpl(); - - if ((exportFlags & (int) WkbExportFlags.wkbExportFailIfNotSimple) != 0) { - int simple = polygon.getIsSimple(0.0); - - if (simple != MultiVertexGeometryImpl.GeometryXSimple.Strong) - throw new GeometryException("non simple geometry"); - } - - boolean bExportZs = polygon.hasAttribute(VertexDescription.Semantics.Z) - && (exportFlags & (int) WkbExportFlags.wkbExportStripZs) == 0; - boolean bExportMs = polygon.hasAttribute(VertexDescription.Semantics.M) - && (exportFlags & (int) WkbExportFlags.wkbExportStripMs) == 0; - - int polygonCount = polygon.getOGCPolygonCount(); - if ((exportFlags & (int) WkbExportFlags.wkbExportPolygon) != 0 - && polygonCount > 1) - throw new IllegalArgumentException(); - - int partCount = polygon.getPathCount(); - int point_count = polygon.getPointCount(); - point_count += partCount; // add 1 point per part - - if (point_count > 0 && polygonCount == 0) - throw new GeometryException("corrupted geometry"); - - // In the WKB_export_defaults case, polygons gets exported as a - // WKB_multi_polygon. - - // get size for buffer - int size = 0; - if ((exportFlags & (int) WkbExportFlags.wkbExportPolygon) == 0 - || polygonCount == 0) - size += 1 /* byte order */ + 4 /* wkbType */ + 4 /* numPolygons */; - - size += polygonCount - * (1 /* byte order */ + 4 /* wkbType */ + 4/* numRings */) - + partCount * (4 /* num_points */) + point_count * (2 * 8 /* - * xy + @Override + public ByteBufferCursor execute(int exportFlags, GeometryCursor geometryCursor) { + return new OperatorExportToWkbCursor(exportFlags, geometryCursor); + } + + @Override + public ByteBuffer execute(int exportFlags, Geometry geometry, ProgressTracker progressTracker) { + int size = exportToWKB(exportFlags, geometry, null); + ByteBuffer wkbBuffer = ByteBuffer.allocate(size).order(ByteOrder.nativeOrder()); + exportToWKB(exportFlags, geometry, wkbBuffer); + return wkbBuffer; + } + + @Override + public int execute(int exportFlags, Geometry geometry, + ByteBuffer wkbBuffer, ProgressTracker progressTracker) { + return exportToWKB(exportFlags, geometry, wkbBuffer); + } + + private static int exportToWKB(int exportFlags, Geometry geometry, + ByteBuffer wkbBuffer) { + if (geometry == null) + return 0; + + int type = geometry.getType().value(); + switch (type) { + case Geometry.GeometryType.Polygon: + if ((exportFlags & WkbExportFlags.wkbExportLineString) != 0 + || (exportFlags & WkbExportFlags.wkbExportMultiLineString) != 0 + || (exportFlags & WkbExportFlags.wkbExportPoint) != 0 + || (exportFlags & WkbExportFlags.wkbExportMultiPoint) != 0) + throw new GeometryException("invalid argument"); + + return exportPolygonToWKB(exportFlags, (Polygon) geometry, + wkbBuffer); + case Geometry.GeometryType.Polyline: + if ((exportFlags & WkbExportFlags.wkbExportPolygon) != 0 + || (exportFlags & WkbExportFlags.wkbExportMultiPolygon) != 0 + || (exportFlags & WkbExportFlags.wkbExportPoint) != 0 + || (exportFlags & WkbExportFlags.wkbExportMultiPoint) != 0) + throw new GeometryException("invalid argument"); + return exportPolylineToWKB(exportFlags, (Polyline) geometry, + wkbBuffer); + + case Geometry.GeometryType.MultiPoint: + if ((exportFlags & WkbExportFlags.wkbExportLineString) != 0 + || (exportFlags & WkbExportFlags.wkbExportMultiLineString) != 0 + || (exportFlags & WkbExportFlags.wkbExportPolygon) != 0 + || (exportFlags & WkbExportFlags.wkbExportMultiPolygon) != 0) + throw new GeometryException("invalid argument"); + return exportMultiPointToWKB(exportFlags, (MultiPoint) geometry, + wkbBuffer); + + case Geometry.GeometryType.Point: + if ((exportFlags & WkbExportFlags.wkbExportLineString) != 0 + || (exportFlags & WkbExportFlags.wkbExportMultiLineString) != 0 + || (exportFlags & WkbExportFlags.wkbExportPolygon) != 0 + || (exportFlags & WkbExportFlags.wkbExportMultiPolygon) != 0) + throw new GeometryException("invalid argument"); + return exportPointToWKB(exportFlags, (Point) geometry, wkbBuffer); + + case Geometry.GeometryType.Envelope: + if ((exportFlags & WkbExportFlags.wkbExportLineString) != 0 + || (exportFlags & WkbExportFlags.wkbExportMultiLineString) != 0 + || (exportFlags & WkbExportFlags.wkbExportPoint) != 0 + || (exportFlags & WkbExportFlags.wkbExportMultiPoint) != 0) + throw new GeometryException("invalid argument"); + return exportEnvelopeToWKB(exportFlags, (Envelope) geometry, + wkbBuffer); + + default: { + throw GeometryException.GeometryInternalError(); + // return -1; + } + } + } + + private static int exportPolygonToWKB(int exportFlags, Polygon _polygon, + ByteBuffer wkbBuffer) { + MultiPathImpl polygon = (MultiPathImpl) _polygon._getImpl(); + + if ((exportFlags & (int) WkbExportFlags.wkbExportFailIfNotSimple) != 0) { + int simple = polygon.getIsSimple(0.0); + + if (simple != MultiVertexGeometryImpl.GeometryXSimple.Strong) + throw new GeometryException("non simple geometry"); + } + + boolean bExportZs = polygon.hasAttribute(VertexDescription.Semantics.Z) + && (exportFlags & (int) WkbExportFlags.wkbExportStripZs) == 0; + boolean bExportMs = polygon.hasAttribute(VertexDescription.Semantics.M) + && (exportFlags & (int) WkbExportFlags.wkbExportStripMs) == 0; + + int polygonCount = polygon.getOGCPolygonCount(); + if ((exportFlags & (int) WkbExportFlags.wkbExportPolygon) != 0 + && polygonCount > 1) + throw new IllegalArgumentException(); + + int partCount = polygon.getPathCount(); + int point_count = polygon.getPointCount(); + point_count += partCount; // add 1 point per part + + if (point_count > 0 && polygonCount == 0) + throw new GeometryException("corrupted geometry"); + + // In the WKB_export_defaults case, polygons gets exported as a + // WKB_multi_polygon. + + // get size for buffer + int size = 0; + if ((exportFlags & (int) WkbExportFlags.wkbExportPolygon) == 0 + || polygonCount == 0) + size += 1 /* byte order */+ 4 /* wkbType */+ 4 /* numPolygons */; + + size += polygonCount + * (1 /* byte order */+ 4 /* wkbType */+ 4/* numRings */) + + partCount * (4 /* num_points */) + point_count * (2 * 8 /* + * xy * coordinates */); - if (bExportZs) - size += (point_count * 8 /* zs */); - if (bExportMs) - size += (point_count * 8 /* ms */); - - if (size >= NumberUtils.intMax()) - throw new GeometryException("invalid call"); - - if (wkbBuffer == null) - return (int) size; - else if (wkbBuffer.capacity() < size) - throw new GeometryException("buffer is too small"); - - int offset = 0; - - byte byteOrder = (byte) (wkbBuffer.order() == ByteOrder.LITTLE_ENDIAN ? WkbByteOrder.wkbNDR - : WkbByteOrder.wkbXDR); - - // Determine the wkb type - int type; - if (!bExportZs && !bExportMs) { - type = WkbGeometryType.wkbPolygon; - - if ((exportFlags & WktExportFlags.wktExportPolygon) == 0) { - wkbBuffer.put(offset, byteOrder); - offset += 1; - wkbBuffer.putInt(offset, WkbGeometryType.wkbMultiPolygon); - offset += 4; - wkbBuffer.putInt(offset, polygonCount); - offset += 4; - } else if (polygonCount == 0) { - wkbBuffer.put(offset, byteOrder); - offset += 1; - wkbBuffer.putInt(offset, WkbGeometryType.wkbPolygon); - offset += 4; - wkbBuffer.putInt(offset, 0); - offset += 4; - } - } else if (bExportZs && !bExportMs) { - type = WkbGeometryType.wkbPolygonZ; - - if ((exportFlags & WkbExportFlags.wkbExportPolygon) == 0) { - wkbBuffer.put(offset, byteOrder); - offset += 1; - wkbBuffer.putInt(offset, WkbGeometryType.wkbMultiPolygonZ); - offset += 4; - wkbBuffer.putInt(offset, polygonCount); - offset += 4; - } else if (polygonCount == 0) { - wkbBuffer.put(offset, byteOrder); - offset += 1; - wkbBuffer.putInt(offset, WkbGeometryType.wkbPolygonZ); - offset += 4; - wkbBuffer.putInt(offset, 0); - offset += 4; - } - } else if (bExportMs && !bExportZs) { - type = WkbGeometryType.wkbPolygonM; - - if ((exportFlags & WkbExportFlags.wkbExportPolygon) == 0) { - wkbBuffer.put(offset, byteOrder); - offset += 1; - wkbBuffer.putInt(offset, WkbGeometryType.wkbMultiPolygonM); - offset += 4; - wkbBuffer.putInt(offset, (int) polygonCount); - offset += 4; - } else if (polygonCount == 0) { - wkbBuffer.put(offset, byteOrder); - offset += 1; - wkbBuffer.putInt(offset, WkbGeometryType.wkbPolygonM); - offset += 4; - wkbBuffer.putInt(offset, 0); - offset += 4; - } - } else { - type = WkbGeometryType.wkbPolygonZM; - - if ((exportFlags & WkbExportFlags.wkbExportPolygon) == 0) { - wkbBuffer.put(offset, byteOrder); - offset += 1; - wkbBuffer.putInt(offset, WkbGeometryType.wkbMultiPolygonZM); - offset += 4; - wkbBuffer.putInt(offset, polygonCount); - offset += 4; - } else if (polygonCount == 0) { - wkbBuffer.put(offset, byteOrder); - offset += 1; - wkbBuffer.putInt(offset, WkbGeometryType.wkbPolygonZM); - offset += 4; - wkbBuffer.putInt(offset, 0); - offset += 4; - } - } - - if (polygonCount == 0) - return offset; - - AttributeStreamOfDbl position = (AttributeStreamOfDbl) (polygon - .getAttributeStreamRef(VertexDescription.Semantics.POSITION)); - - AttributeStreamOfDbl zs = null; - if (bExportZs) { - if (polygon - ._attributeStreamIsAllocated(VertexDescription.Semantics.Z)) - zs = (AttributeStreamOfDbl) (polygon - .getAttributeStreamRef(VertexDescription.Semantics.Z)); - } - - AttributeStreamOfDbl ms = null; - if (bExportMs) { - if (polygon - ._attributeStreamIsAllocated(VertexDescription.Semantics.M)) - ms = (AttributeStreamOfDbl) (polygon - .getAttributeStreamRef(VertexDescription.Semantics.M)); - } - - int ipartend = 0; - int ipolygonend = 0; - - for (int ipolygon = 0; ipolygon < (int) polygonCount; ipolygon++) { - // write byte order - wkbBuffer.put(offset, byteOrder); - offset += 1; - - // write type - wkbBuffer.putInt(offset, type); - offset += 4; - - // get partcount for the ith polygon - AttributeStreamOfInt8 pathFlags = polygon.getPathFlagsStreamRef(); - - int ipolygonstart = ipolygonend; - ipolygonend++; - - while (ipolygonend < partCount - && (pathFlags.read(ipolygonend) & PathFlags.enumOGCStartPolygon) == 0) - ipolygonend++; - - // write numRings - wkbBuffer.putInt(offset, ipolygonend - ipolygonstart); - offset += 4; - - for (int ipart = ipolygonstart; ipart < ipolygonend; ipart++) { - // get num_points - int ipartstart = ipartend; - ipartend = (int) polygon.getPathEnd(ipart); - - // write num_points - wkbBuffer.putInt(offset, ipartend - ipartstart + 1); - offset += 4; - - // duplicate the start point - double x = position.read(2 * ipartstart); - double y = position.read(2 * ipartstart + 1); - - wkbBuffer.putDouble(offset, x); - offset += 8; - wkbBuffer.putDouble(offset, y); - offset += 8; - - if (bExportZs) { - double z; - if (zs != null) - z = zs.read(ipartstart); - else - z = VertexDescription - .getDefaultValue(VertexDescription.Semantics.Z); - - wkbBuffer.putDouble(offset, z); - offset += 8; - } - - if (bExportMs) { - double m; - if (ms != null) - m = ms.read(ipartstart); - else - m = VertexDescription - .getDefaultValue(VertexDescription.Semantics.M); - - wkbBuffer.putDouble(offset, m); - offset += 8; - } - - // We must write to the buffer backwards - ogc polygon format is - // opposite of shapefile format - for (int i = ipartend - 1; i >= ipartstart; i--) { - x = position.read(2 * i); - y = position.read(2 * i + 1); - - wkbBuffer.putDouble(offset, x); - offset += 8; - wkbBuffer.putDouble(offset, y); - offset += 8; - - if (bExportZs) { - double z; - if (zs != null) - z = zs.read(i); - else - z = VertexDescription - .getDefaultValue(VertexDescription.Semantics.Z); - - wkbBuffer.putDouble(offset, z); - offset += 8; - } - - if (bExportMs) { - double m; - if (ms != null) - m = ms.read(i); - else - m = VertexDescription - .getDefaultValue(VertexDescription.Semantics.M); - - wkbBuffer.putDouble(offset, m); - offset += 8; - } - } - } - } - - return offset; - } - - private static int exportPolylineToWKB(int exportFlags, Polyline _polyline, - ByteBuffer wkbBuffer) { - MultiPathImpl polyline = (MultiPathImpl) _polyline._getImpl(); - - if ((exportFlags & WkbExportFlags.wkbExportFailIfNotSimple) != 0) { - int simple = polyline.getIsSimple(0.0); - - if (simple < 1) - throw new GeometryException("corrupted geometry"); - } - - boolean bExportZs = polyline - .hasAttribute(VertexDescription.Semantics.Z) - && (exportFlags & WkbExportFlags.wkbExportStripZs) == 0; - boolean bExportMs = polyline - .hasAttribute(VertexDescription.Semantics.M) - && (exportFlags & WkbExportFlags.wkbExportStripMs) == 0; - - int partCount = polyline.getPathCount(); - if ((exportFlags & WkbExportFlags.wkbExportLineString) != 0 - && partCount > 1) - throw new IllegalArgumentException(); - - int point_count = polyline.getPointCount(); - - for (int ipart = 0; ipart < partCount; ipart++) - if (polyline.isClosedPath(ipart)) - point_count++; - - // In the WKB_export_defaults case, polylines gets exported as a - // WKB_multi_line_string - - // get size for buffer - int size = 0; - if ((exportFlags & WkbExportFlags.wkbExportLineString) == 0 - || partCount == 0) - size += 1 /* byte order */ + 4 /* wkbType */ + 4 /* numLineStrings */; - - size += partCount - * (1 /* byte order */ + 4 /* wkbType */ + 4/* num_points */) - + point_count * (2 * 8 /* xy coordinates */); - - if (bExportZs) - size += (point_count * 8 /* zs */); - if (bExportMs) - size += (point_count * 8 /* ms */); - - if (size >= NumberUtils.intMax()) - throw new GeometryException("invalid call"); - - if (wkbBuffer == null) - return (int) size; - else if (wkbBuffer.capacity() < (int) size) - throw new GeometryException("buffer is too small"); - - int offset = 0; - - byte byteOrder = (byte) (wkbBuffer.order() == ByteOrder.LITTLE_ENDIAN ? WkbByteOrder.wkbNDR - : WkbByteOrder.wkbXDR); - - // Determine the wkb type - int type; - if (!bExportZs && !bExportMs) { - type = WkbGeometryType.wkbLineString; - - if ((exportFlags & WkbExportFlags.wkbExportLineString) == 0) { - wkbBuffer.put(offset, byteOrder); - offset += 1; - wkbBuffer.putInt(offset, WkbGeometryType.wkbMultiLineString); - offset += 4; - wkbBuffer.putInt(offset, (int) partCount); - offset += 4; - } else if (partCount == 0) { - wkbBuffer.put(offset, byteOrder); - offset += 1; - wkbBuffer.putInt(offset, WkbGeometryType.wkbLineString); - offset += 4; - wkbBuffer.putInt(offset, 0); - offset += 4; - } - } else if (bExportZs && !bExportMs) { - type = WkbGeometryType.wkbLineStringZ; - - if ((exportFlags & WkbExportFlags.wkbExportLineString) == 0) { - wkbBuffer.put(offset, byteOrder); - offset += 1; - wkbBuffer.putInt(offset, WkbGeometryType.wkbMultiLineStringZ); - offset += 4; - wkbBuffer.putInt(offset, (int) partCount); - offset += 4; - } else if (partCount == 0) { - wkbBuffer.put(offset, byteOrder); - offset += 1; - wkbBuffer.putInt(offset, WkbGeometryType.wkbLineStringZ); - offset += 4; - wkbBuffer.putInt(offset, 0); - offset += 4; - } - } else if (bExportMs && !bExportZs) { - type = WkbGeometryType.wkbLineStringM; - - if ((exportFlags & WkbExportFlags.wkbExportLineString) == 0) { - wkbBuffer.put(offset, byteOrder); - offset += 1; - wkbBuffer.putInt(offset, WkbGeometryType.wkbMultiLineStringM); - offset += 4; - wkbBuffer.putInt(offset, (int) partCount); - offset += 4; - } else if (partCount == 0) { - wkbBuffer.put(offset, byteOrder); - offset += 1; - wkbBuffer.putInt(offset, WkbGeometryType.wkbLineStringM); - offset += 4; - wkbBuffer.putInt(offset, 0); - offset += 4; - } - } else { - type = WkbGeometryType.wkbLineStringZM; - - if ((exportFlags & WkbExportFlags.wkbExportLineString) == 0) { - wkbBuffer.put(offset, byteOrder); - offset += 1; - wkbBuffer.putInt(offset, WkbGeometryType.wkbMultiLineStringZM); - offset += 4; - wkbBuffer.putInt(offset, partCount); - offset += 4; - } else if (partCount == 0) { - wkbBuffer.put(offset, byteOrder); - offset += 1; - wkbBuffer.putInt(offset, WkbGeometryType.wkbLineStringZM); - offset += 4; - wkbBuffer.putInt(offset, 0); - offset += 4; - } - } - - if (partCount == 0) - return offset; - - AttributeStreamOfDbl position = (AttributeStreamOfDbl) (polyline - .getAttributeStreamRef(VertexDescription.Semantics.POSITION)); - - AttributeStreamOfDbl zs = null; - if (bExportZs) { - if (polyline - ._attributeStreamIsAllocated(VertexDescription.Semantics.Z)) - zs = (AttributeStreamOfDbl) (polyline - .getAttributeStreamRef(VertexDescription.Semantics.Z)); - } - - AttributeStreamOfDbl ms = null; - if (bExportMs) { - if (polyline - ._attributeStreamIsAllocated(VertexDescription.Semantics.M)) - ms = (AttributeStreamOfDbl) (polyline - .getAttributeStreamRef(VertexDescription.Semantics.M)); - } - - int ipartend = 0; - for (int ipart = 0; ipart < (int) partCount; ipart++) { - // write byte order - wkbBuffer.put(offset, byteOrder); - offset += 1; - - // write type - wkbBuffer.putInt(offset, type); - offset += 4; - - // get start and end indices - int ipartstart = ipartend; - ipartend = (int) polyline.getPathEnd(ipart); - - // write num_points - int num_points = ipartend - ipartstart; - if (polyline.isClosedPath(ipart)) - num_points++; - - wkbBuffer.putInt(offset, num_points); - offset += 4; - - // write points - for (int i = ipartstart; i < ipartend; i++) { - double x = position.read(2 * i); - double y = position.read(2 * i + 1); - - wkbBuffer.putDouble(offset, x); - offset += 8; - wkbBuffer.putDouble(offset, y); - offset += 8; - - if (bExportZs) { - double z; - if (zs != null) - z = zs.read(i); - else - z = VertexDescription - .getDefaultValue(VertexDescription.Semantics.Z); - - wkbBuffer.putDouble(offset, z); - offset += 8; - } - - if (bExportMs) { - double m; - if (ms != null) - m = ms.read(i); - else - m = VertexDescription - .getDefaultValue(VertexDescription.Semantics.M); - - wkbBuffer.putDouble(offset, m); - offset += 8; - } - } - - // duplicate the start point if the Polyline is closed - if (polyline.isClosedPath(ipart)) { - double x = position.read(2 * ipartstart); - double y = position.read(2 * ipartstart + 1); - - wkbBuffer.putDouble(offset, x); - offset += 8; - wkbBuffer.putDouble(offset, y); - offset += 8; - - if (bExportZs) { - double z; - if (zs != null) - z = zs.read(ipartstart); - else - z = VertexDescription - .getDefaultValue(VertexDescription.Semantics.Z); - - wkbBuffer.putDouble(offset, z); - offset += 8; - } - - if (bExportMs) { - double m; - if (ms != null) - m = ms.read(ipartstart); - else - m = VertexDescription - .getDefaultValue(VertexDescription.Semantics.M); - - wkbBuffer.putDouble(offset, m); - offset += 8; - } - } - } - - return offset; - } - - private static int exportMultiPointToWKB(int exportFlags, - MultiPoint _multipoint, ByteBuffer wkbBuffer) { - MultiPointImpl multipoint = (MultiPointImpl) _multipoint._getImpl(); - - boolean bExportZs = multipoint - .hasAttribute(VertexDescription.Semantics.Z) - && (exportFlags & WkbExportFlags.wkbExportStripZs) == 0; - boolean bExportMs = multipoint - .hasAttribute(VertexDescription.Semantics.M) - && (exportFlags & WkbExportFlags.wkbExportStripMs) == 0; - - int point_count = multipoint.getPointCount(); - if ((exportFlags & WkbExportFlags.wkbExportPoint) != 0 - && point_count > 1) - throw new IllegalArgumentException(); - - // get size for buffer - int size; - if ((exportFlags & WkbExportFlags.wkbExportPoint) == 0) { - size = 1 /* byte order */ + 4 /* wkbType */ + 4 /* num_points */ - + point_count - * (1 /* byte order */ + 4 /* wkbType */ + 2 * 8 /* + if (bExportZs) + size += (point_count * 8 /* zs */); + if (bExportMs) + size += (point_count * 8 /* ms */); + + if (size >= NumberUtils.intMax()) + throw new GeometryException("invalid call"); + + if (wkbBuffer == null) + return (int) size; + else if (wkbBuffer.capacity() < size) + throw new GeometryException("buffer is too small"); + + int offset = 0; + + byte byteOrder = (byte) (wkbBuffer.order() == ByteOrder.LITTLE_ENDIAN ? WkbByteOrder.wkbNDR + : WkbByteOrder.wkbXDR); + + // Determine the wkb type + int type; + if (!bExportZs && !bExportMs) { + type = WkbGeometryType.wkbPolygon; + + if ((exportFlags & WkbExportFlags.wkbExportPolygon) == 0) { + wkbBuffer.put(offset, byteOrder); + offset += 1; + wkbBuffer.putInt(offset, WkbGeometryType.wkbMultiPolygon); + offset += 4; + wkbBuffer.putInt(offset, polygonCount); + offset += 4; + } else if (polygonCount == 0) { + wkbBuffer.put(offset, byteOrder); + offset += 1; + wkbBuffer.putInt(offset, WkbGeometryType.wkbPolygon); + offset += 4; + wkbBuffer.putInt(offset, 0); + offset += 4; + } + } else if (bExportZs && !bExportMs) { + type = WkbGeometryType.wkbPolygonZ; + + if ((exportFlags & WkbExportFlags.wkbExportPolygon) == 0) { + wkbBuffer.put(offset, byteOrder); + offset += 1; + wkbBuffer.putInt(offset, WkbGeometryType.wkbMultiPolygonZ); + offset += 4; + wkbBuffer.putInt(offset, polygonCount); + offset += 4; + } else if (polygonCount == 0) { + wkbBuffer.put(offset, byteOrder); + offset += 1; + wkbBuffer.putInt(offset, WkbGeometryType.wkbPolygonZ); + offset += 4; + wkbBuffer.putInt(offset, 0); + offset += 4; + } + } else if (bExportMs && !bExportZs) { + type = WkbGeometryType.wkbPolygonM; + + if ((exportFlags & WkbExportFlags.wkbExportPolygon) == 0) { + wkbBuffer.put(offset, byteOrder); + offset += 1; + wkbBuffer.putInt(offset, WkbGeometryType.wkbMultiPolygonM); + offset += 4; + wkbBuffer.putInt(offset, (int) polygonCount); + offset += 4; + } else if (polygonCount == 0) { + wkbBuffer.put(offset, byteOrder); + offset += 1; + wkbBuffer.putInt(offset, WkbGeometryType.wkbPolygonM); + offset += 4; + wkbBuffer.putInt(offset, 0); + offset += 4; + } + } else { + type = WkbGeometryType.wkbPolygonZM; + + if ((exportFlags & WkbExportFlags.wkbExportPolygon) == 0) { + wkbBuffer.put(offset, byteOrder); + offset += 1; + wkbBuffer.putInt(offset, WkbGeometryType.wkbMultiPolygonZM); + offset += 4; + wkbBuffer.putInt(offset, polygonCount); + offset += 4; + } else if (polygonCount == 0) { + wkbBuffer.put(offset, byteOrder); + offset += 1; + wkbBuffer.putInt(offset, WkbGeometryType.wkbPolygonZM); + offset += 4; + wkbBuffer.putInt(offset, 0); + offset += 4; + } + } + + if (polygonCount == 0) + return offset; + + AttributeStreamOfDbl position = (AttributeStreamOfDbl) (polygon + .getAttributeStreamRef(VertexDescription.Semantics.POSITION)); + + AttributeStreamOfDbl zs = null; + if (bExportZs) { + if (polygon + ._attributeStreamIsAllocated(VertexDescription.Semantics.Z)) + zs = (AttributeStreamOfDbl) (polygon + .getAttributeStreamRef(VertexDescription.Semantics.Z)); + } + + AttributeStreamOfDbl ms = null; + if (bExportMs) { + if (polygon + ._attributeStreamIsAllocated(VertexDescription.Semantics.M)) + ms = (AttributeStreamOfDbl) (polygon + .getAttributeStreamRef(VertexDescription.Semantics.M)); + } + + int ipartend = 0; + int ipolygonend = 0; + + for (int ipolygon = 0; ipolygon < (int) polygonCount; ipolygon++) { + // write byte order + wkbBuffer.put(offset, byteOrder); + offset += 1; + + // write type + wkbBuffer.putInt(offset, type); + offset += 4; + + // get partcount for the ith polygon + AttributeStreamOfInt8 pathFlags = polygon.getPathFlagsStreamRef(); + + int ipolygonstart = ipolygonend; + ipolygonend++; + + while (ipolygonend < partCount + && (pathFlags.read(ipolygonend) & PathFlags.enumOGCStartPolygon) == 0) + ipolygonend++; + + // write numRings + wkbBuffer.putInt(offset, ipolygonend - ipolygonstart); + offset += 4; + + for (int ipart = ipolygonstart; ipart < ipolygonend; ipart++) { + // get num_points + int ipartstart = ipartend; + ipartend = (int) polygon.getPathEnd(ipart); + + // write num_points + wkbBuffer.putInt(offset, ipartend - ipartstart + 1); + offset += 4; + + // duplicate the start point + double x = position.read(2 * ipartstart); + double y = position.read(2 * ipartstart + 1); + + wkbBuffer.putDouble(offset, x); + offset += 8; + wkbBuffer.putDouble(offset, y); + offset += 8; + + if (bExportZs) { + double z; + if (zs != null) + z = zs.read(ipartstart); + else + z = VertexDescription + .getDefaultValue(VertexDescription.Semantics.Z); + + wkbBuffer.putDouble(offset, z); + offset += 8; + } + + if (bExportMs) { + double m; + if (ms != null) + m = ms.read(ipartstart); + else + m = VertexDescription + .getDefaultValue(VertexDescription.Semantics.M); + + wkbBuffer.putDouble(offset, m); + offset += 8; + } + + // We must write to the buffer backwards - ogc polygon format is + // opposite of shapefile format + for (int i = ipartend - 1; i >= ipartstart; i--) { + x = position.read(2 * i); + y = position.read(2 * i + 1); + + wkbBuffer.putDouble(offset, x); + offset += 8; + wkbBuffer.putDouble(offset, y); + offset += 8; + + if (bExportZs) { + double z; + if (zs != null) + z = zs.read(i); + else + z = VertexDescription + .getDefaultValue(VertexDescription.Semantics.Z); + + wkbBuffer.putDouble(offset, z); + offset += 8; + } + + if (bExportMs) { + double m; + if (ms != null) + m = ms.read(i); + else + m = VertexDescription + .getDefaultValue(VertexDescription.Semantics.M); + + wkbBuffer.putDouble(offset, m); + offset += 8; + } + } + } + } + + return offset; + } + + private static int exportPolylineToWKB(int exportFlags, Polyline _polyline, + ByteBuffer wkbBuffer) { + MultiPathImpl polyline = (MultiPathImpl) _polyline._getImpl(); + + if ((exportFlags & WkbExportFlags.wkbExportFailIfNotSimple) != 0) { + int simple = polyline.getIsSimple(0.0); + + if (simple < 1) + throw new GeometryException("corrupted geometry"); + } + + boolean bExportZs = polyline + .hasAttribute(VertexDescription.Semantics.Z) + && (exportFlags & WkbExportFlags.wkbExportStripZs) == 0; + boolean bExportMs = polyline + .hasAttribute(VertexDescription.Semantics.M) + && (exportFlags & WkbExportFlags.wkbExportStripMs) == 0; + + int partCount = polyline.getPathCount(); + if ((exportFlags & WkbExportFlags.wkbExportLineString) != 0 + && partCount > 1) + throw new IllegalArgumentException(); + + int point_count = polyline.getPointCount(); + + for (int ipart = 0; ipart < partCount; ipart++) + if (polyline.isClosedPath(ipart)) + point_count++; + + // In the WKB_export_defaults case, polylines gets exported as a + // WKB_multi_line_string + + // get size for buffer + int size = 0; + if ((exportFlags & WkbExportFlags.wkbExportLineString) == 0 + || partCount == 0) + size += 1 /* byte order */+ 4 /* wkbType */+ 4 /* numLineStrings */; + + size += partCount + * (1 /* byte order */+ 4 /* wkbType */+ 4/* num_points */) + + point_count * (2 * 8 /* xy coordinates */); + + if (bExportZs) + size += (point_count * 8 /* zs */); + if (bExportMs) + size += (point_count * 8 /* ms */); + + if (size >= NumberUtils.intMax()) + throw new GeometryException("invalid call"); + + if (wkbBuffer == null) + return (int) size; + else if (wkbBuffer.capacity() < (int) size) + throw new GeometryException("buffer is too small"); + + int offset = 0; + + byte byteOrder = (byte) (wkbBuffer.order() == ByteOrder.LITTLE_ENDIAN ? WkbByteOrder.wkbNDR + : WkbByteOrder.wkbXDR); + + // Determine the wkb type + int type; + if (!bExportZs && !bExportMs) { + type = WkbGeometryType.wkbLineString; + + if ((exportFlags & WkbExportFlags.wkbExportLineString) == 0) { + wkbBuffer.put(offset, byteOrder); + offset += 1; + wkbBuffer.putInt(offset, WkbGeometryType.wkbMultiLineString); + offset += 4; + wkbBuffer.putInt(offset, (int) partCount); + offset += 4; + } else if (partCount == 0) { + wkbBuffer.put(offset, byteOrder); + offset += 1; + wkbBuffer.putInt(offset, WkbGeometryType.wkbLineString); + offset += 4; + wkbBuffer.putInt(offset, 0); + offset += 4; + } + } else if (bExportZs && !bExportMs) { + type = WkbGeometryType.wkbLineStringZ; + + if ((exportFlags & WkbExportFlags.wkbExportLineString) == 0) { + wkbBuffer.put(offset, byteOrder); + offset += 1; + wkbBuffer.putInt(offset, WkbGeometryType.wkbMultiLineStringZ); + offset += 4; + wkbBuffer.putInt(offset, (int) partCount); + offset += 4; + } else if (partCount == 0) { + wkbBuffer.put(offset, byteOrder); + offset += 1; + wkbBuffer.putInt(offset, WkbGeometryType.wkbLineStringZ); + offset += 4; + wkbBuffer.putInt(offset, 0); + offset += 4; + } + } else if (bExportMs && !bExportZs) { + type = WkbGeometryType.wkbLineStringM; + + if ((exportFlags & WkbExportFlags.wkbExportLineString) == 0) { + wkbBuffer.put(offset, byteOrder); + offset += 1; + wkbBuffer.putInt(offset, WkbGeometryType.wkbMultiLineStringM); + offset += 4; + wkbBuffer.putInt(offset, (int) partCount); + offset += 4; + } else if (partCount == 0) { + wkbBuffer.put(offset, byteOrder); + offset += 1; + wkbBuffer.putInt(offset, WkbGeometryType.wkbLineStringM); + offset += 4; + wkbBuffer.putInt(offset, 0); + offset += 4; + } + } else { + type = WkbGeometryType.wkbLineStringZM; + + if ((exportFlags & WkbExportFlags.wkbExportLineString) == 0) { + wkbBuffer.put(offset, byteOrder); + offset += 1; + wkbBuffer.putInt(offset, WkbGeometryType.wkbMultiLineStringZM); + offset += 4; + wkbBuffer.putInt(offset, partCount); + offset += 4; + } else if (partCount == 0) { + wkbBuffer.put(offset, byteOrder); + offset += 1; + wkbBuffer.putInt(offset, WkbGeometryType.wkbLineStringZM); + offset += 4; + wkbBuffer.putInt(offset, 0); + offset += 4; + } + } + + if (partCount == 0) + return offset; + + AttributeStreamOfDbl position = (AttributeStreamOfDbl) (polyline + .getAttributeStreamRef(VertexDescription.Semantics.POSITION)); + + AttributeStreamOfDbl zs = null; + if (bExportZs) { + if (polyline + ._attributeStreamIsAllocated(VertexDescription.Semantics.Z)) + zs = (AttributeStreamOfDbl) (polyline + .getAttributeStreamRef(VertexDescription.Semantics.Z)); + } + + AttributeStreamOfDbl ms = null; + if (bExportMs) { + if (polyline + ._attributeStreamIsAllocated(VertexDescription.Semantics.M)) + ms = (AttributeStreamOfDbl) (polyline + .getAttributeStreamRef(VertexDescription.Semantics.M)); + } + + int ipartend = 0; + for (int ipart = 0; ipart < (int) partCount; ipart++) { + // write byte order + wkbBuffer.put(offset, byteOrder); + offset += 1; + + // write type + wkbBuffer.putInt(offset, type); + offset += 4; + + // get start and end indices + int ipartstart = ipartend; + ipartend = (int) polyline.getPathEnd(ipart); + + // write num_points + int num_points = ipartend - ipartstart; + if (polyline.isClosedPath(ipart)) + num_points++; + + wkbBuffer.putInt(offset, num_points); + offset += 4; + + // write points + for (int i = ipartstart; i < ipartend; i++) { + double x = position.read(2 * i); + double y = position.read(2 * i + 1); + + wkbBuffer.putDouble(offset, x); + offset += 8; + wkbBuffer.putDouble(offset, y); + offset += 8; + + if (bExportZs) { + double z; + if (zs != null) + z = zs.read(i); + else + z = VertexDescription + .getDefaultValue(VertexDescription.Semantics.Z); + + wkbBuffer.putDouble(offset, z); + offset += 8; + } + + if (bExportMs) { + double m; + if (ms != null) + m = ms.read(i); + else + m = VertexDescription + .getDefaultValue(VertexDescription.Semantics.M); + + wkbBuffer.putDouble(offset, m); + offset += 8; + } + } + + // duplicate the start point if the Polyline is closed + if (polyline.isClosedPath(ipart)) { + double x = position.read(2 * ipartstart); + double y = position.read(2 * ipartstart + 1); + + wkbBuffer.putDouble(offset, x); + offset += 8; + wkbBuffer.putDouble(offset, y); + offset += 8; + + if (bExportZs) { + double z; + if (zs != null) + z = zs.read(ipartstart); + else + z = VertexDescription + .getDefaultValue(VertexDescription.Semantics.Z); + + wkbBuffer.putDouble(offset, z); + offset += 8; + } + + if (bExportMs) { + double m; + if (ms != null) + m = ms.read(ipartstart); + else + m = VertexDescription + .getDefaultValue(VertexDescription.Semantics.M); + + wkbBuffer.putDouble(offset, m); + offset += 8; + } + } + } + + return offset; + } + + private static int exportMultiPointToWKB(int exportFlags, + MultiPoint _multipoint, ByteBuffer wkbBuffer) { + MultiPointImpl multipoint = (MultiPointImpl) _multipoint._getImpl(); + + boolean bExportZs = multipoint + .hasAttribute(VertexDescription.Semantics.Z) + && (exportFlags & WkbExportFlags.wkbExportStripZs) == 0; + boolean bExportMs = multipoint + .hasAttribute(VertexDescription.Semantics.M) + && (exportFlags & WkbExportFlags.wkbExportStripMs) == 0; + + int point_count = multipoint.getPointCount(); + if ((exportFlags & WkbExportFlags.wkbExportPoint) != 0 + && point_count > 1) + throw new IllegalArgumentException(); + + // get size for buffer + int size; + if ((exportFlags & WkbExportFlags.wkbExportPoint) == 0) { + size = 1 /* byte order */+ 4 /* wkbType */+ 4 /* num_points */ + + point_count + * (1 /* byte order */+ 4 /* wkbType */+ 2 * 8 /* * xy * coordinates */); - if (bExportZs) - size += (point_count * 8 /* zs */); - if (bExportMs) - size += (point_count * 8 /* ms */); - } else { - size = 1 /* byte order */ + 4 /* wkbType */ + 2 * 8 /* xy coordinates */; - - if (bExportZs) - size += 8 /* z */; - if (bExportMs) - size += 8 /* m */; - } - - if (size >= NumberUtils.intMax()) - throw new GeometryException("invalid call"); - - if (wkbBuffer == null) - return (int) size; - else if (wkbBuffer.capacity() < (int) size) - throw new GeometryException("buffer is too small"); - - int offset = 0; - - byte byteOrder = (byte) (wkbBuffer.order() == ByteOrder.LITTLE_ENDIAN ? WkbByteOrder.wkbNDR - : WkbByteOrder.wkbXDR); - - // Determine the wkb type - int type; - if (!bExportZs && !bExportMs) { - type = WkbGeometryType.wkbPoint; - - if ((exportFlags & WkbExportFlags.wkbExportPoint) == 0) { - wkbBuffer.put(offset, byteOrder); - offset += 1; - wkbBuffer.putInt(offset, WkbGeometryType.wkbMultiPoint); - offset += 4; - wkbBuffer.putInt(offset, (int) point_count); - offset += 4; - } else if (point_count == 0) { - wkbBuffer.put(offset, byteOrder); - offset += 1; - wkbBuffer.putInt(offset, type); - offset += 4; - wkbBuffer.putDouble(offset, NumberUtils.TheNaN); - offset += 8; - wkbBuffer.putDouble(offset, NumberUtils.TheNaN); - offset += 8; - } - } else if (bExportZs && !bExportMs) { - type = WkbGeometryType.wkbPointZ; - - if ((exportFlags & WkbExportFlags.wkbExportPoint) == 0) { - wkbBuffer.put(offset, byteOrder); - offset += 1; - wkbBuffer.putInt(offset, WkbGeometryType.wkbMultiPointZ); - offset += 4; - wkbBuffer.putInt(offset, (int) point_count); - offset += 4; - } else if (point_count == 0) { - wkbBuffer.put(offset, byteOrder); - offset += 1; - wkbBuffer.putInt(offset, type); - offset += 4; - wkbBuffer.putDouble(offset, NumberUtils.TheNaN); - offset += 8; - wkbBuffer.putDouble(offset, NumberUtils.TheNaN); - offset += 8; - wkbBuffer.putDouble(offset, NumberUtils.TheNaN); - offset += 8; - } - } else if (bExportMs && !bExportZs) { - type = WkbGeometryType.wkbPointM; - - if ((exportFlags & WkbExportFlags.wkbExportPoint) == 0) { - wkbBuffer.put(offset, byteOrder); - offset += 1; - wkbBuffer.putInt(offset, WkbGeometryType.wkbMultiPointM); - offset += 4; - wkbBuffer.putInt(offset, (int) point_count); - offset += 4; - } else if (point_count == 0) { - wkbBuffer.put(offset, byteOrder); - offset += 1; - wkbBuffer.putInt(offset, type); - offset += 4; - wkbBuffer.putDouble(offset, NumberUtils.TheNaN); - offset += 8; - wkbBuffer.putDouble(offset, NumberUtils.TheNaN); - offset += 8; - wkbBuffer.putDouble(offset, NumberUtils.TheNaN); - offset += 8; - } - } else { - type = WkbGeometryType.wkbPointZM; - - if ((exportFlags & WkbExportFlags.wkbExportPoint) == 0) { - wkbBuffer.put(offset, byteOrder); - offset += 1; - wkbBuffer.putInt(offset, WkbGeometryType.wkbMultiPolygonZM); - offset += 4; - wkbBuffer.putInt(offset, point_count); - offset += 4; - } else if (point_count == 0) { - wkbBuffer.put(offset, byteOrder); - offset += 1; - wkbBuffer.putInt(offset, type); - offset += 4; - wkbBuffer.putDouble(offset, NumberUtils.TheNaN); - offset += 8; - wkbBuffer.putDouble(offset, NumberUtils.TheNaN); - offset += 8; - wkbBuffer.putDouble(offset, NumberUtils.TheNaN); - offset += 8; - wkbBuffer.putDouble(offset, NumberUtils.TheNaN); - offset += 8; - } - } - - if (point_count == 0) - return offset; - - AttributeStreamOfDbl position = (AttributeStreamOfDbl) (multipoint - .getAttributeStreamRef(VertexDescription.Semantics.POSITION)); - - AttributeStreamOfDbl zs = null; - if (bExportZs) { - if (multipoint - ._attributeStreamIsAllocated(VertexDescription.Semantics.Z)) - zs = (AttributeStreamOfDbl) (multipoint - .getAttributeStreamRef(VertexDescription.Semantics.Z)); - } - - AttributeStreamOfDbl ms = null; - if (bExportMs) { - if (multipoint - ._attributeStreamIsAllocated(VertexDescription.Semantics.M)) - ms = (AttributeStreamOfDbl) (multipoint - .getAttributeStreamRef(VertexDescription.Semantics.M)); - } - - for (int i = 0; i < (int) point_count; i++) { - // write byte order - wkbBuffer.put(offset, byteOrder); - offset += 1; - - // write type - wkbBuffer.putInt(offset, type); - offset += 4; - - // write xy coordinates - double x = position.read(2 * i); - double y = position.read(2 * i + 1); - - wkbBuffer.putDouble(offset, x); - offset += 8; - wkbBuffer.putDouble(offset, y); - offset += 8; - - // write Z - if (bExportZs) { - double z; - if (zs != null) - z = zs.read(i); - else - z = VertexDescription - .getDefaultValue(VertexDescription.Semantics.Z); - - wkbBuffer.putDouble(offset, z); - offset += 8; - } - - // write M - if (bExportMs) { - double m; - if (ms != null) - m = ms.read(i); - else - m = VertexDescription - .getDefaultValue(VertexDescription.Semantics.M); - - wkbBuffer.putDouble(offset, m); - offset += 8; - } - } - - return offset; - } - - private static int exportPointToWKB(int exportFlags, Point point, - ByteBuffer wkbBuffer) { - boolean bExportZs = point.hasAttribute(VertexDescription.Semantics.Z) - && (exportFlags & WkbExportFlags.wkbExportStripZs) == 0; - boolean bExportMs = point.hasAttribute(VertexDescription.Semantics.M) - && (exportFlags & WkbExportFlags.wkbExportStripMs) == 0; - - boolean bEmpty = point.isEmpty(); - int point_count = bEmpty ? 0 : 1; - - // get size for buffer - int size; - if ((exportFlags & WkbExportFlags.wkbExportMultiPoint) != 0) { - size = 1 /* byte order */ + 4 /* wkbType */ + 4 /* num_points */ - + point_count - * (1 /* byte order */ + 4 /* wkbType */ + 2 * 8 /* + if (bExportZs) + size += (point_count * 8 /* zs */); + if (bExportMs) + size += (point_count * 8 /* ms */); + } else { + size = 1 /* byte order */+ 4 /* wkbType */+ 2 * 8 /* xy coordinates */; + + if (bExportZs) + size += 8 /* z */; + if (bExportMs) + size += 8 /* m */; + } + + if (size >= NumberUtils.intMax()) + throw new GeometryException("invalid call"); + + if (wkbBuffer == null) + return (int) size; + else if (wkbBuffer.capacity() < (int) size) + throw new GeometryException("buffer is too small"); + + int offset = 0; + + byte byteOrder = (byte) (wkbBuffer.order() == ByteOrder.LITTLE_ENDIAN ? WkbByteOrder.wkbNDR + : WkbByteOrder.wkbXDR); + + // Determine the wkb type + int type; + if (!bExportZs && !bExportMs) { + type = WkbGeometryType.wkbPoint; + + if ((exportFlags & WkbExportFlags.wkbExportPoint) == 0) { + wkbBuffer.put(offset, byteOrder); + offset += 1; + wkbBuffer.putInt(offset, WkbGeometryType.wkbMultiPoint); + offset += 4; + wkbBuffer.putInt(offset, (int) point_count); + offset += 4; + } else if (point_count == 0) { + wkbBuffer.put(offset, byteOrder); + offset += 1; + wkbBuffer.putInt(offset, type); + offset += 4; + wkbBuffer.putDouble(offset, NumberUtils.TheNaN); + offset += 8; + wkbBuffer.putDouble(offset, NumberUtils.TheNaN); + offset += 8; + } + } else if (bExportZs && !bExportMs) { + type = WkbGeometryType.wkbPointZ; + + if ((exportFlags & WkbExportFlags.wkbExportPoint) == 0) { + wkbBuffer.put(offset, byteOrder); + offset += 1; + wkbBuffer.putInt(offset, WkbGeometryType.wkbMultiPointZ); + offset += 4; + wkbBuffer.putInt(offset, (int) point_count); + offset += 4; + } else if (point_count == 0) { + wkbBuffer.put(offset, byteOrder); + offset += 1; + wkbBuffer.putInt(offset, type); + offset += 4; + wkbBuffer.putDouble(offset, NumberUtils.TheNaN); + offset += 8; + wkbBuffer.putDouble(offset, NumberUtils.TheNaN); + offset += 8; + wkbBuffer.putDouble(offset, NumberUtils.TheNaN); + offset += 8; + } + } else if (bExportMs && !bExportZs) { + type = WkbGeometryType.wkbPointM; + + if ((exportFlags & WkbExportFlags.wkbExportPoint) == 0) { + wkbBuffer.put(offset, byteOrder); + offset += 1; + wkbBuffer.putInt(offset, WkbGeometryType.wkbMultiPointM); + offset += 4; + wkbBuffer.putInt(offset, (int) point_count); + offset += 4; + } else if (point_count == 0) { + wkbBuffer.put(offset, byteOrder); + offset += 1; + wkbBuffer.putInt(offset, type); + offset += 4; + wkbBuffer.putDouble(offset, NumberUtils.TheNaN); + offset += 8; + wkbBuffer.putDouble(offset, NumberUtils.TheNaN); + offset += 8; + wkbBuffer.putDouble(offset, NumberUtils.TheNaN); + offset += 8; + } + } else { + type = WkbGeometryType.wkbPointZM; + + if ((exportFlags & WkbExportFlags.wkbExportPoint) == 0) { + wkbBuffer.put(offset, byteOrder); + offset += 1; + wkbBuffer.putInt(offset, WkbGeometryType.wkbMultiPolygonZM); + offset += 4; + wkbBuffer.putInt(offset, point_count); + offset += 4; + } else if (point_count == 0) { + wkbBuffer.put(offset, byteOrder); + offset += 1; + wkbBuffer.putInt(offset, type); + offset += 4; + wkbBuffer.putDouble(offset, NumberUtils.TheNaN); + offset += 8; + wkbBuffer.putDouble(offset, NumberUtils.TheNaN); + offset += 8; + wkbBuffer.putDouble(offset, NumberUtils.TheNaN); + offset += 8; + wkbBuffer.putDouble(offset, NumberUtils.TheNaN); + offset += 8; + } + } + + if (point_count == 0) + return offset; + + AttributeStreamOfDbl position = (AttributeStreamOfDbl) (multipoint + .getAttributeStreamRef(VertexDescription.Semantics.POSITION)); + + AttributeStreamOfDbl zs = null; + if (bExportZs) { + if (multipoint + ._attributeStreamIsAllocated(VertexDescription.Semantics.Z)) + zs = (AttributeStreamOfDbl) (multipoint + .getAttributeStreamRef(VertexDescription.Semantics.Z)); + } + + AttributeStreamOfDbl ms = null; + if (bExportMs) { + if (multipoint + ._attributeStreamIsAllocated(VertexDescription.Semantics.M)) + ms = (AttributeStreamOfDbl) (multipoint + .getAttributeStreamRef(VertexDescription.Semantics.M)); + } + + for (int i = 0; i < (int) point_count; i++) { + // write byte order + wkbBuffer.put(offset, byteOrder); + offset += 1; + + // write type + wkbBuffer.putInt(offset, type); + offset += 4; + + // write xy coordinates + double x = position.read(2 * i); + double y = position.read(2 * i + 1); + + wkbBuffer.putDouble(offset, x); + offset += 8; + wkbBuffer.putDouble(offset, y); + offset += 8; + + // write Z + if (bExportZs) { + double z; + if (zs != null) + z = zs.read(i); + else + z = VertexDescription + .getDefaultValue(VertexDescription.Semantics.Z); + + wkbBuffer.putDouble(offset, z); + offset += 8; + } + + // write M + if (bExportMs) { + double m; + if (ms != null) + m = ms.read(i); + else + m = VertexDescription + .getDefaultValue(VertexDescription.Semantics.M); + + wkbBuffer.putDouble(offset, m); + offset += 8; + } + } + + return offset; + } + + private static int exportPointToWKB(int exportFlags, Point point, + ByteBuffer wkbBuffer) { + boolean bExportZs = point.hasAttribute(VertexDescription.Semantics.Z) + && (exportFlags & WkbExportFlags.wkbExportStripZs) == 0; + boolean bExportMs = point.hasAttribute(VertexDescription.Semantics.M) + && (exportFlags & WkbExportFlags.wkbExportStripMs) == 0; + + boolean bEmpty = point.isEmpty(); + int point_count = bEmpty ? 0 : 1; + + // get size for buffer + int size; + if ((exportFlags & WkbExportFlags.wkbExportMultiPoint) != 0) { + size = 1 /* byte order */+ 4 /* wkbType */+ 4 /* num_points */ + + point_count + * (1 /* byte order */+ 4 /* wkbType */+ 2 * 8 /* * xy * coordinates */); - if (bExportZs) - size += (point_count * 8 /* zs */); - if (bExportMs) - size += (point_count * 8 /* ms */); - } else { - size = 1 /* byte order */ + 4 /* wkbType */ + 2 * 8 /* xy coordinates */; - - if (bExportZs) - size += 8 /* z */; - if (bExportMs) - size += 8 /* m */; - } - - if (size >= NumberUtils.intMax()) - throw new GeometryException("invalid call"); - - if (wkbBuffer == null) - return size; - else if (wkbBuffer.capacity() < size) - throw new GeometryException("buffer is too small"); - - int offset = 0; - - byte byteOrder = (byte) (wkbBuffer.order() == ByteOrder.LITTLE_ENDIAN ? WkbByteOrder.wkbNDR - : WkbByteOrder.wkbXDR); - - // Determine the wkb type - int type; - if (!bExportZs && !bExportMs) { - type = WkbGeometryType.wkbPoint; - - if ((exportFlags & WkbExportFlags.wkbExportMultiPoint) != 0) { - wkbBuffer.put(offset, byteOrder); - offset += 1; - wkbBuffer.putInt(offset, WkbGeometryType.wkbMultiPoint); - offset += 4; - wkbBuffer.putInt(offset, (int) point_count); - offset += 4; - } else if (point_count == 0) { - wkbBuffer.put(offset, byteOrder); - offset += 1; - wkbBuffer.putInt(offset, type); - offset += 4; - wkbBuffer.putDouble(offset, NumberUtils.TheNaN); - offset += 8; - wkbBuffer.putDouble(offset, NumberUtils.TheNaN); - offset += 8; - } - } else if (bExportZs && !bExportMs) { - type = WkbGeometryType.wkbPointZ; - - if ((exportFlags & WkbExportFlags.wkbExportMultiPoint) != 0) { - wkbBuffer.put(offset, byteOrder); - offset += 1; - wkbBuffer.putInt(offset, WkbGeometryType.wkbMultiPointZ); - offset += 4; - wkbBuffer.putInt(offset, (int) point_count); - offset += 4; - } else if (point_count == 0) { - wkbBuffer.put(offset, byteOrder); - offset += 1; - wkbBuffer.putInt(offset, type); - offset += 4; - wkbBuffer.putDouble(offset, NumberUtils.TheNaN); - offset += 8; - wkbBuffer.putDouble(offset, NumberUtils.TheNaN); - offset += 8; - wkbBuffer.putDouble(offset, NumberUtils.TheNaN); - offset += 8; - } - } else if (bExportMs && !bExportZs) { - type = WkbGeometryType.wkbPointM; - - if ((exportFlags & WkbExportFlags.wkbExportMultiPoint) != 0) { - wkbBuffer.put(offset, byteOrder); - offset += 1; - wkbBuffer.putInt(offset, WkbGeometryType.wkbMultiPointM); - offset += 4; - wkbBuffer.putInt(offset, (int) point_count); - offset += 4; - } else if (point_count == 0) { - wkbBuffer.put(offset, byteOrder); - offset += 1; - wkbBuffer.putInt(offset, type); - offset += 4; - wkbBuffer.putDouble(offset, NumberUtils.TheNaN); - offset += 8; - wkbBuffer.putDouble(offset, NumberUtils.TheNaN); - offset += 8; - wkbBuffer.putDouble(offset, NumberUtils.TheNaN); - offset += 8; - } - } else { - type = WkbGeometryType.wkbPointZM; - - if ((exportFlags & WkbExportFlags.wkbExportMultiPoint) != 0) { - wkbBuffer.put(offset, byteOrder); - offset += 1; - wkbBuffer.putInt(offset, WkbGeometryType.wkbMultiPointZM); - offset += 4; - wkbBuffer.putInt(offset, (int) point_count); - offset += 4; - } else if (point_count == 0) { - wkbBuffer.put(offset, byteOrder); - offset += 1; - wkbBuffer.putInt(offset, type); - offset += 4; - wkbBuffer.putDouble(offset, NumberUtils.TheNaN); - offset += 8; - wkbBuffer.putDouble(offset, NumberUtils.TheNaN); - offset += 8; - wkbBuffer.putDouble(offset, NumberUtils.TheNaN); - offset += 8; - wkbBuffer.putDouble(offset, NumberUtils.TheNaN); - offset += 8; - } - } - - if (point_count == 0) - return offset; - - // write byte order - wkbBuffer.put(offset, byteOrder); - offset += 1; - - // write type - wkbBuffer.putInt(offset, type); - offset += 4; - - // write xy coordinate - double x = point.getX(); - double y = point.getY(); - wkbBuffer.putDouble(offset, x); - offset += 8; - wkbBuffer.putDouble(offset, y); - offset += 8; - - // write Z - if (bExportZs) { - double z = point.getZ(); - wkbBuffer.putDouble(offset, z); - offset += 8; - } - - // write M - if (bExportMs) { - double m = point.getM(); - wkbBuffer.putDouble(offset, m); - offset += 8; - } - - return offset; - } - - private static int exportEnvelopeToWKB(int exportFlags, Envelope envelope, - ByteBuffer wkbBuffer) { - boolean bExportZs = envelope - .hasAttribute(VertexDescription.Semantics.Z) - && (exportFlags & WkbExportFlags.wkbExportStripZs) == 0; - boolean bExportMs = envelope - .hasAttribute(VertexDescription.Semantics.M) - && (exportFlags & WkbExportFlags.wkbExportStripMs) == 0; - boolean bEmpty = envelope.isEmpty(); - - int partCount = bEmpty ? 0 : 1; - int point_count = bEmpty ? 0 : 5; - - // Envelope by default is exported as a WKB_polygon - - // get size for buffer - int size = 0; - if ((exportFlags & WkbExportFlags.wkbExportMultiPolygon) != 0 - || partCount == 0) - size += 1 /* byte order */ + 4 /* wkbType */ + 4 /* numPolygons */; - - size += partCount - * (1 /* byte order */ + 4 /* wkbType */ + 4/* numRings */) - + partCount * (4 /* num_points */) + point_count * (2 * 8 /* + if (bExportZs) + size += (point_count * 8 /* zs */); + if (bExportMs) + size += (point_count * 8 /* ms */); + } else { + size = 1 /* byte order */+ 4 /* wkbType */+ 2 * 8 /* xy coordinates */; + + if (bExportZs) + size += 8 /* z */; + if (bExportMs) + size += 8 /* m */; + } + + if (size >= NumberUtils.intMax()) + throw new GeometryException("invalid call"); + + if (wkbBuffer == null) + return size; + else if (wkbBuffer.capacity() < size) + throw new GeometryException("buffer is too small"); + + int offset = 0; + + byte byteOrder = (byte) (wkbBuffer.order() == ByteOrder.LITTLE_ENDIAN ? WkbByteOrder.wkbNDR + : WkbByteOrder.wkbXDR); + + // Determine the wkb type + int type; + if (!bExportZs && !bExportMs) { + type = WkbGeometryType.wkbPoint; + + if ((exportFlags & WkbExportFlags.wkbExportMultiPoint) != 0) { + wkbBuffer.put(offset, byteOrder); + offset += 1; + wkbBuffer.putInt(offset, WkbGeometryType.wkbMultiPoint); + offset += 4; + wkbBuffer.putInt(offset, (int) point_count); + offset += 4; + } else if (point_count == 0) { + wkbBuffer.put(offset, byteOrder); + offset += 1; + wkbBuffer.putInt(offset, type); + offset += 4; + wkbBuffer.putDouble(offset, NumberUtils.TheNaN); + offset += 8; + wkbBuffer.putDouble(offset, NumberUtils.TheNaN); + offset += 8; + } + } else if (bExportZs && !bExportMs) { + type = WkbGeometryType.wkbPointZ; + + if ((exportFlags & WkbExportFlags.wkbExportMultiPoint) != 0) { + wkbBuffer.put(offset, byteOrder); + offset += 1; + wkbBuffer.putInt(offset, WkbGeometryType.wkbMultiPointZ); + offset += 4; + wkbBuffer.putInt(offset, (int) point_count); + offset += 4; + } else if (point_count == 0) { + wkbBuffer.put(offset, byteOrder); + offset += 1; + wkbBuffer.putInt(offset, type); + offset += 4; + wkbBuffer.putDouble(offset, NumberUtils.TheNaN); + offset += 8; + wkbBuffer.putDouble(offset, NumberUtils.TheNaN); + offset += 8; + wkbBuffer.putDouble(offset, NumberUtils.TheNaN); + offset += 8; + } + } else if (bExportMs && !bExportZs) { + type = WkbGeometryType.wkbPointM; + + if ((exportFlags & WkbExportFlags.wkbExportMultiPoint) != 0) { + wkbBuffer.put(offset, byteOrder); + offset += 1; + wkbBuffer.putInt(offset, WkbGeometryType.wkbMultiPointM); + offset += 4; + wkbBuffer.putInt(offset, (int) point_count); + offset += 4; + } else if (point_count == 0) { + wkbBuffer.put(offset, byteOrder); + offset += 1; + wkbBuffer.putInt(offset, type); + offset += 4; + wkbBuffer.putDouble(offset, NumberUtils.TheNaN); + offset += 8; + wkbBuffer.putDouble(offset, NumberUtils.TheNaN); + offset += 8; + wkbBuffer.putDouble(offset, NumberUtils.TheNaN); + offset += 8; + } + } else { + type = WkbGeometryType.wkbPointZM; + + if ((exportFlags & WkbExportFlags.wkbExportMultiPoint) != 0) { + wkbBuffer.put(offset, byteOrder); + offset += 1; + wkbBuffer.putInt(offset, WkbGeometryType.wkbMultiPointZM); + offset += 4; + wkbBuffer.putInt(offset, (int) point_count); + offset += 4; + } else if (point_count == 0) { + wkbBuffer.put(offset, byteOrder); + offset += 1; + wkbBuffer.putInt(offset, type); + offset += 4; + wkbBuffer.putDouble(offset, NumberUtils.TheNaN); + offset += 8; + wkbBuffer.putDouble(offset, NumberUtils.TheNaN); + offset += 8; + wkbBuffer.putDouble(offset, NumberUtils.TheNaN); + offset += 8; + wkbBuffer.putDouble(offset, NumberUtils.TheNaN); + offset += 8; + } + } + + if (point_count == 0) + return offset; + + // write byte order + wkbBuffer.put(offset, byteOrder); + offset += 1; + + // write type + wkbBuffer.putInt(offset, type); + offset += 4; + + // write xy coordinate + double x = point.getX(); + double y = point.getY(); + wkbBuffer.putDouble(offset, x); + offset += 8; + wkbBuffer.putDouble(offset, y); + offset += 8; + + // write Z + if (bExportZs) { + double z = point.getZ(); + wkbBuffer.putDouble(offset, z); + offset += 8; + } + + // write M + if (bExportMs) { + double m = point.getM(); + wkbBuffer.putDouble(offset, m); + offset += 8; + } + + return offset; + } + + private static int exportEnvelopeToWKB(int exportFlags, Envelope envelope, + ByteBuffer wkbBuffer) { + boolean bExportZs = envelope + .hasAttribute(VertexDescription.Semantics.Z) + && (exportFlags & WkbExportFlags.wkbExportStripZs) == 0; + boolean bExportMs = envelope + .hasAttribute(VertexDescription.Semantics.M) + && (exportFlags & WkbExportFlags.wkbExportStripMs) == 0; + boolean bEmpty = envelope.isEmpty(); + + int partCount = bEmpty ? 0 : 1; + int point_count = bEmpty ? 0 : 5; + + // Envelope by default is exported as a WKB_polygon + + // get size for buffer + int size = 0; + if ((exportFlags & WkbExportFlags.wkbExportMultiPolygon) != 0 + || partCount == 0) + size += 1 /* byte order */+ 4 /* wkbType */+ 4 /* numPolygons */; + + size += partCount + * (1 /* byte order */+ 4 /* wkbType */+ 4/* numRings */) + + partCount * (4 /* num_points */) + point_count * (2 * 8 /* * xy * coordinates */); - if (bExportZs) - size += (point_count * 8 /* zs */); - if (bExportMs) - size += (point_count * 8 /* ms */); - - if (size >= NumberUtils.intMax()) - throw new GeometryException("invalid call"); - - if (wkbBuffer == null) - return size; - else if (wkbBuffer.capacity() < size) - throw new GeometryException("buffer is too small"); - - int offset = 0; - - byte byteOrder = (byte) (wkbBuffer.order() == ByteOrder.LITTLE_ENDIAN ? WkbByteOrder.wkbNDR - : WkbByteOrder.wkbXDR); - - // Determine the wkb type - int type; - if (!bExportZs && !bExportMs) { - type = WkbGeometryType.wkbPolygon; - - if ((exportFlags & WkbExportFlags.wkbExportMultiPolygon) != 0) { - wkbBuffer.put(offset, byteOrder); - offset += 1; - wkbBuffer.putInt(offset, WkbGeometryType.wkbMultiPolygon); - offset += 4; - wkbBuffer.putInt(offset, (int) partCount); - offset += 4; - } else if (partCount == 0) { - wkbBuffer.put(offset, byteOrder); - offset += 1; - wkbBuffer.putInt(offset, WkbGeometryType.wkbPolygon); - offset += 4; - wkbBuffer.putInt(offset, 0); - offset += 4; - } - } else if (bExportZs && !bExportMs) { - type = WkbGeometryType.wkbPolygonZ; - - if ((exportFlags & WkbExportFlags.wkbExportPolygon) != 0) { - wkbBuffer.put(offset, byteOrder); - offset += 1; - wkbBuffer.putInt(offset, WkbGeometryType.wkbMultiPolygonZ); - offset += 4; - wkbBuffer.putInt(offset, partCount); - offset += 4; - } else if (partCount == 0) { - wkbBuffer.put(offset, byteOrder); - offset += 1; - wkbBuffer.putInt(offset, WkbGeometryType.wkbPolygonZ); - offset += 4; - wkbBuffer.putInt(offset, 0); - offset += 4; - } - } else if (bExportMs && !bExportZs) { - type = WkbGeometryType.wkbPolygonM; - - if ((exportFlags & WkbExportFlags.wkbExportMultiPolygon) != 0) { - wkbBuffer.put(offset, byteOrder); - offset += 1; - wkbBuffer.putInt(offset, WkbGeometryType.wkbMultiPolygonM); - offset += 4; - wkbBuffer.putInt(offset, partCount); - offset += 4; - } else if (partCount == 0) { - wkbBuffer.put(offset, byteOrder); - offset += 1; - wkbBuffer.putInt(offset, WkbGeometryType.wkbPolygonM); - offset += 4; - wkbBuffer.putInt(offset, 0); - offset += 4; - } - } else { - type = WkbGeometryType.wkbPolygonZM; - - if ((exportFlags & WkbExportFlags.wkbExportMultiPolygon) != 0) { - wkbBuffer.put(offset, byteOrder); - offset += 1; - wkbBuffer.putInt(offset, WkbGeometryType.wkbMultiPolygonZM); - offset += 4; - wkbBuffer.putInt(offset, partCount); - offset += 4; - } else if (partCount == 0) { - wkbBuffer.put(offset, byteOrder); - offset += 1; - wkbBuffer.putInt(offset, WkbGeometryType.wkbPolygonZM); - offset += 4; - wkbBuffer.putInt(offset, 0); - offset += 4; - } - } - - if (partCount == 0) - return offset; - - // write byte order - wkbBuffer.put(offset, byteOrder); - offset += 1; - - // write type - wkbBuffer.putInt(offset, type); - offset += 4; - - // write numRings - wkbBuffer.putInt(offset, 1); - offset += 4; - - // write num_points - wkbBuffer.putInt(offset, 5); - offset += 4; - - Envelope2D env = new Envelope2D(); - envelope.queryEnvelope2D(env); - - Envelope1D z_interval = null; - if (bExportZs) - z_interval = envelope.queryInterval(VertexDescription.Semantics.Z, - 0); - - Envelope1D mInterval = null; - if (bExportMs) - mInterval = envelope - .queryInterval(VertexDescription.Semantics.M, 0); - - wkbBuffer.putDouble(offset, env.xmin); - offset += 8; - wkbBuffer.putDouble(offset, env.ymin); - offset += 8; - - if (bExportZs) { - wkbBuffer.putDouble(offset, z_interval.vmin); - offset += 8; - } - - if (bExportMs) { - wkbBuffer.putDouble(offset, mInterval.vmin); - offset += 8; - } - - wkbBuffer.putDouble(offset, env.xmax); - offset += 8; - wkbBuffer.putDouble(offset, env.ymin); - offset += 8; - - if (bExportZs) { - wkbBuffer.putDouble(offset, z_interval.vmax); - offset += 8; - } - - if (bExportMs) { - wkbBuffer.putDouble(offset, mInterval.vmax); - offset += 8; - } - - wkbBuffer.putDouble(offset, env.xmax); - offset += 8; - wkbBuffer.putDouble(offset, env.ymax); - offset += 8; - - if (bExportZs) { - wkbBuffer.putDouble(offset, z_interval.vmin); - offset += 8; - } - - if (bExportMs) { - wkbBuffer.putDouble(offset, mInterval.vmin); - offset += 8; - } - - wkbBuffer.putDouble(offset, env.xmin); - offset += 8; - wkbBuffer.putDouble(offset, env.ymax); - offset += 8; - - if (bExportZs) { - wkbBuffer.putDouble(offset, z_interval.vmax); - offset += 8; - } - - if (bExportMs) { - wkbBuffer.putDouble(offset, mInterval.vmax); - offset += 8; - } - - wkbBuffer.putDouble(offset, env.xmin); - offset += 8; - wkbBuffer.putDouble(offset, env.ymin); - offset += 8; - - if (bExportZs) { - wkbBuffer.putDouble(offset, z_interval.vmin); - offset += 8; - } - - if (bExportMs) { - wkbBuffer.putDouble(offset, mInterval.vmin); - offset += 8; - } - - return offset; - } + if (bExportZs) + size += (point_count * 8 /* zs */); + if (bExportMs) + size += (point_count * 8 /* ms */); + + if (size >= NumberUtils.intMax()) + throw new GeometryException("invalid call"); + + if (wkbBuffer == null) + return size; + else if (wkbBuffer.capacity() < size) + throw new GeometryException("buffer is too small"); + + int offset = 0; + + byte byteOrder = (byte) (wkbBuffer.order() == ByteOrder.LITTLE_ENDIAN ? WkbByteOrder.wkbNDR + : WkbByteOrder.wkbXDR); + + // Determine the wkb type + int type; + if (!bExportZs && !bExportMs) { + type = WkbGeometryType.wkbPolygon; + + if ((exportFlags & WkbExportFlags.wkbExportMultiPolygon) != 0) { + wkbBuffer.put(offset, byteOrder); + offset += 1; + wkbBuffer.putInt(offset, WkbGeometryType.wkbMultiPolygon); + offset += 4; + wkbBuffer.putInt(offset, (int) partCount); + offset += 4; + } else if (partCount == 0) { + wkbBuffer.put(offset, byteOrder); + offset += 1; + wkbBuffer.putInt(offset, WkbGeometryType.wkbPolygon); + offset += 4; + wkbBuffer.putInt(offset, 0); + offset += 4; + } + } else if (bExportZs && !bExportMs) { + type = WkbGeometryType.wkbPolygonZ; + + if ((exportFlags & WkbExportFlags.wkbExportPolygon) != 0) { + wkbBuffer.put(offset, byteOrder); + offset += 1; + wkbBuffer.putInt(offset, WkbGeometryType.wkbMultiPolygonZ); + offset += 4; + wkbBuffer.putInt(offset, partCount); + offset += 4; + } else if (partCount == 0) { + wkbBuffer.put(offset, byteOrder); + offset += 1; + wkbBuffer.putInt(offset, WkbGeometryType.wkbPolygonZ); + offset += 4; + wkbBuffer.putInt(offset, 0); + offset += 4; + } + } else if (bExportMs && !bExportZs) { + type = WkbGeometryType.wkbPolygonM; + + if ((exportFlags & WkbExportFlags.wkbExportMultiPolygon) != 0) { + wkbBuffer.put(offset, byteOrder); + offset += 1; + wkbBuffer.putInt(offset, WkbGeometryType.wkbMultiPolygonM); + offset += 4; + wkbBuffer.putInt(offset, partCount); + offset += 4; + } else if (partCount == 0) { + wkbBuffer.put(offset, byteOrder); + offset += 1; + wkbBuffer.putInt(offset, WkbGeometryType.wkbPolygonM); + offset += 4; + wkbBuffer.putInt(offset, 0); + offset += 4; + } + } else { + type = WkbGeometryType.wkbPolygonZM; + + if ((exportFlags & WkbExportFlags.wkbExportMultiPolygon) != 0) { + wkbBuffer.put(offset, byteOrder); + offset += 1; + wkbBuffer.putInt(offset, WkbGeometryType.wkbMultiPolygonZM); + offset += 4; + wkbBuffer.putInt(offset, partCount); + offset += 4; + } else if (partCount == 0) { + wkbBuffer.put(offset, byteOrder); + offset += 1; + wkbBuffer.putInt(offset, WkbGeometryType.wkbPolygonZM); + offset += 4; + wkbBuffer.putInt(offset, 0); + offset += 4; + } + } + + if (partCount == 0) + return offset; + + // write byte order + wkbBuffer.put(offset, byteOrder); + offset += 1; + + // write type + wkbBuffer.putInt(offset, type); + offset += 4; + + // write numRings + wkbBuffer.putInt(offset, 1); + offset += 4; + + // write num_points + wkbBuffer.putInt(offset, 5); + offset += 4; + + Envelope2D env = new Envelope2D(); + envelope.queryEnvelope2D(env); + + Envelope1D z_interval = null; + if (bExportZs) + z_interval = envelope.queryInterval(VertexDescription.Semantics.Z, + 0); + + Envelope1D mInterval = null; + if (bExportMs) + mInterval = envelope + .queryInterval(VertexDescription.Semantics.M, 0); + + wkbBuffer.putDouble(offset, env.xmin); + offset += 8; + wkbBuffer.putDouble(offset, env.ymin); + offset += 8; + + if (bExportZs) { + wkbBuffer.putDouble(offset, z_interval.vmin); + offset += 8; + } + + if (bExportMs) { + wkbBuffer.putDouble(offset, mInterval.vmin); + offset += 8; + } + + wkbBuffer.putDouble(offset, env.xmax); + offset += 8; + wkbBuffer.putDouble(offset, env.ymin); + offset += 8; + + if (bExportZs) { + wkbBuffer.putDouble(offset, z_interval.vmax); + offset += 8; + } + + if (bExportMs) { + wkbBuffer.putDouble(offset, mInterval.vmax); + offset += 8; + } + + wkbBuffer.putDouble(offset, env.xmax); + offset += 8; + wkbBuffer.putDouble(offset, env.ymax); + offset += 8; + + if (bExportZs) { + wkbBuffer.putDouble(offset, z_interval.vmin); + offset += 8; + } + + if (bExportMs) { + wkbBuffer.putDouble(offset, mInterval.vmin); + offset += 8; + } + + wkbBuffer.putDouble(offset, env.xmin); + offset += 8; + wkbBuffer.putDouble(offset, env.ymax); + offset += 8; + + if (bExportZs) { + wkbBuffer.putDouble(offset, z_interval.vmax); + offset += 8; + } + + if (bExportMs) { + wkbBuffer.putDouble(offset, mInterval.vmax); + offset += 8; + } + + wkbBuffer.putDouble(offset, env.xmin); + offset += 8; + wkbBuffer.putDouble(offset, env.ymin); + offset += 8; + + if (bExportZs) { + wkbBuffer.putDouble(offset, z_interval.vmin); + offset += 8; + } + + if (bExportMs) { + wkbBuffer.putDouble(offset, mInterval.vmin); + offset += 8; + } + + return offset; + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorExportToWkt.java b/src/main/java/com/esri/core/geometry/OperatorExportToWkt.java index 41447a26..a773e48b 100644 --- a/src/main/java/com/esri/core/geometry/OperatorExportToWkt.java +++ b/src/main/java/com/esri/core/geometry/OperatorExportToWkt.java @@ -25,22 +25,22 @@ public abstract class OperatorExportToWkt extends Operator { - @Override - public Type getType() { - return Type.ExportToWkt; - } - - public abstract StringCursor execute(int exportFlags, - GeometryCursor geometryCursor, - ProgressTracker progressTracker); - - public abstract String execute(int exportFlags, - Geometry geometry, - ProgressTracker progress_tracker); - - public static OperatorExportToWkt local() { - return (OperatorExportToWkt) OperatorFactoryLocal.getInstance() - .getOperator(Type.ExportToWkt); - } + @Override + public Type getType() { + return Type.ExportToWkt; + } + + public abstract StringCursor execute(int exportFlags, + GeometryCursor geometryCursor, + ProgressTracker progressTracker); + + public abstract String execute(int exportFlags, + Geometry geometry, + ProgressTracker progress_tracker); + + public static OperatorExportToWkt local() { + return (OperatorExportToWkt) OperatorFactoryLocal.getInstance() + .getOperator(Type.ExportToWkt); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorExportToWktCursor.java b/src/main/java/com/esri/core/geometry/OperatorExportToWktCursor.java index 693dc87f..c434ea39 100644 --- a/src/main/java/com/esri/core/geometry/OperatorExportToWktCursor.java +++ b/src/main/java/com/esri/core/geometry/OperatorExportToWktCursor.java @@ -1,44 +1,48 @@ package com.esri.core.geometry; public class OperatorExportToWktCursor extends StringCursor { - private GeometryCursor m_geometryCursor; - private int m_export_flags; - private SimpleStateEnum simpleStateEnum = SimpleStateEnum.SIMPLE_UNKNOWN; - - public OperatorExportToWktCursor(int exportFlags, GeometryCursor geometryCursor, ProgressTracker progressTracker) { - if (geometryCursor == null) - throw new GeometryException("invalid argument"); - - m_export_flags = exportFlags; - m_geometryCursor = geometryCursor; - } - - @Override - public String next() { - Geometry geometry; - if (hasNext()) { - geometry = m_geometryCursor.next(); - simpleStateEnum = geometry.getSimpleState(); - StringBuilder stringBuilder = new StringBuilder(); - OperatorExportToWktLocal.exportToWkt(m_export_flags, geometry, stringBuilder); - return stringBuilder.toString(); - } - return null; - } - - @Override - public boolean hasNext() { return m_geometryCursor != null && m_geometryCursor.hasNext(); } - - @Override - public long getID() { - return m_geometryCursor.getGeometryID(); - } - - @Override - public SimpleStateEnum getSimpleState() { - return simpleStateEnum; - } - - @Override - public String getFeatureID() { return m_geometryCursor.getFeatureID(); } + private GeometryCursor m_geometryCursor; + private int m_export_flags; + private SimpleStateEnum simpleStateEnum = SimpleStateEnum.SIMPLE_UNKNOWN; + + public OperatorExportToWktCursor(int exportFlags, GeometryCursor geometryCursor, ProgressTracker progressTracker) { + if (geometryCursor == null) + throw new GeometryException("invalid argument"); + + m_export_flags = exportFlags; + m_geometryCursor = geometryCursor; + } + + @Override + public String next() { + Geometry geometry; + if (hasNext()) { + geometry = m_geometryCursor.next(); + simpleStateEnum = geometry.getSimpleState(); + StringBuilder stringBuilder = new StringBuilder(); + OperatorExportToWktLocal.exportToWkt(m_export_flags, geometry, stringBuilder); + return stringBuilder.toString(); + } + return null; + } + + @Override + public boolean hasNext() { + return m_geometryCursor != null && m_geometryCursor.hasNext(); + } + + @Override + public long getID() { + return m_geometryCursor.getGeometryID(); + } + + @Override + public SimpleStateEnum getSimpleState() { + return simpleStateEnum; + } + + @Override + public String getFeatureID() { + return m_geometryCursor.getFeatureID(); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorExportToWktLocal.java b/src/main/java/com/esri/core/geometry/OperatorExportToWktLocal.java index 4a86f938..725346ef 100644 --- a/src/main/java/com/esri/core/geometry/OperatorExportToWktLocal.java +++ b/src/main/java/com/esri/core/geometry/OperatorExportToWktLocal.java @@ -24,869 +24,869 @@ package com.esri.core.geometry; class OperatorExportToWktLocal extends OperatorExportToWkt { - @Override - public StringCursor execute(int exportFlags, GeometryCursor geometryCursor, ProgressTracker progressTracker) { - return new OperatorExportToWktCursor(exportFlags, geometryCursor, progressTracker); - } - - @Override - public String execute(int export_flags, Geometry geometry, - ProgressTracker progress_tracker) { - StringBuilder string = new StringBuilder(); - exportToWkt(export_flags, geometry, string); - - return string.toString(); - } - - static void exportToWkt(int export_flags, Geometry geometry, - StringBuilder string) { - int type = geometry.getType().value(); - switch (type) { - case Geometry.GeometryType.Polygon: - if ((export_flags & WktExportFlags.wktExportLineString) != 0 - || (export_flags & WktExportFlags.wktExportMultiLineString) != 0 - || (export_flags & WktExportFlags.wktExportPoint) != 0 - || (export_flags & WktExportFlags.wktExportMultiPoint) != 0) - throw new IllegalArgumentException("Cannot export a Polygon as (Multi)LineString/(Multi)Point : " + export_flags); - - exportPolygonToWkt(export_flags, (Polygon) geometry, string); - return; - - case Geometry.GeometryType.Polyline: - if ((export_flags & WktExportFlags.wktExportPolygon) != 0 - || (export_flags & WktExportFlags.wktExportMultiPolygon) != 0 - || (export_flags & WktExportFlags.wktExportPoint) != 0 - || (export_flags & WktExportFlags.wktExportMultiPoint) != 0) - throw new IllegalArgumentException("Cannot export a Polyline as (Multi)Polygon/(Multi)Point : " + export_flags); - - exportPolylineToWkt(export_flags, (Polyline) geometry, string); - return; - - case Geometry.GeometryType.MultiPoint: - if ((export_flags & WktExportFlags.wktExportLineString) != 0 - || (export_flags & WktExportFlags.wktExportMultiLineString) != 0 - || (export_flags & WktExportFlags.wktExportPolygon) != 0 - || (export_flags & WktExportFlags.wktExportMultiPolygon) != 0) - throw new IllegalArgumentException("Cannot export a MultiPoint as (Multi)LineString/(Multi)Polygon: " + export_flags); - - exportMultiPointToWkt(export_flags, (MultiPoint) geometry, string); - return; - - case Geometry.GeometryType.Point: - if ((export_flags & WktExportFlags.wktExportLineString) != 0 - || (export_flags & WktExportFlags.wktExportMultiLineString) != 0 - || (export_flags & WktExportFlags.wktExportPolygon) != 0 - || (export_flags & WktExportFlags.wktExportMultiPolygon) != 0) - throw new IllegalArgumentException("Cannot export a Point as (Multi)LineString/(Multi)Polygon: " + export_flags); - - exportPointToWkt(export_flags, (Point) geometry, string); - return; - - case Geometry.GeometryType.Envelope: - if ((export_flags & WktExportFlags.wktExportLineString) != 0 - || (export_flags & WktExportFlags.wktExportMultiLineString) != 0 - || (export_flags & WktExportFlags.wktExportPoint) != 0 - || (export_flags & WktExportFlags.wktExportMultiPoint) != 0) - throw new IllegalArgumentException("Cannot export an Envelope as (Multi)LineString/(Multi)Point: " + export_flags); - - exportEnvelopeToWkt(export_flags, (Envelope) geometry, string); - return; - - default: { - throw GeometryException.GeometryInternalError(); - } - } - } - - static void exportPolygonToWkt(int export_flags, Polygon polygon, - StringBuilder string) { - MultiPathImpl polygon_impl = (MultiPathImpl) polygon._getImpl(); - - if ((export_flags & WktExportFlags.wktExportFailIfNotSimple) != 0) { - int simple = polygon_impl.getIsSimple(0.0); - - if (simple != MultiPathImpl.GeometryXSimple.Strong) - throw new GeometryException("corrupted geometry"); - } - - int point_count = polygon.getPointCount(); - int polygon_count = polygon_impl.getOGCPolygonCount(); - - if (point_count > 0 && polygon_count == 0) - throw new GeometryException("corrupted geometry"); - - int precision = 17 - (7 & (export_flags >> 13)); - boolean b_export_zs = polygon_impl - .hasAttribute(VertexDescription.Semantics.Z) - && (export_flags & WktExportFlags.wktExportStripZs) == 0; - boolean b_export_ms = polygon_impl - .hasAttribute(VertexDescription.Semantics.M) - && (export_flags & WktExportFlags.wktExportStripMs) == 0; - - int path_count = 0; - AttributeStreamOfDbl position = null; - AttributeStreamOfDbl zs = null; - AttributeStreamOfDbl ms = null; - AttributeStreamOfInt8 path_flags = null; - AttributeStreamOfInt32 paths = null; - - if (point_count > 0) { - position = (AttributeStreamOfDbl) (polygon_impl - .getAttributeStreamRef(VertexDescription.Semantics.POSITION)); - path_flags = polygon_impl.getPathFlagsStreamRef(); - paths = polygon_impl.getPathStreamRef(); - path_count = polygon_impl.getPathCount(); - - if (b_export_zs) { - if (polygon_impl - ._attributeStreamIsAllocated(VertexDescription.Semantics.Z)) - zs = (AttributeStreamOfDbl) polygon_impl - .getAttributeStreamRef(VertexDescription.Semantics.Z); - } - - if (b_export_ms) { - if (polygon_impl - ._attributeStreamIsAllocated(VertexDescription.Semantics.M)) - ms = (AttributeStreamOfDbl) polygon_impl - .getAttributeStreamRef(VertexDescription.Semantics.M); - } - } - - if ((export_flags & WktExportFlags.wktExportPolygon) != 0) { - if (polygon_count > 1) - throw new IllegalArgumentException("Cannot export a Polygon with specified export flags: " + export_flags); - - polygonTaggedText_(precision, b_export_zs, b_export_ms, zs, ms, - position, path_flags, paths, path_count, string); - } else { - multiPolygonTaggedText_(precision, b_export_zs, b_export_ms, zs, - ms, position, path_flags, paths, polygon_count, path_count, - string); - } - } - - static void exportPolylineToWkt(int export_flags, Polyline polyline, - StringBuilder string) { - MultiPathImpl polyline_impl = (MultiPathImpl) polyline._getImpl(); - - int point_count = polyline_impl.getPointCount(); - int path_count = polyline_impl.getPathCount(); - - if (point_count > 0 && path_count == 0) - throw new GeometryException("corrupted geometry"); - - int precision = 17 - (7 & (export_flags >> 13)); - boolean b_export_zs = polyline_impl - .hasAttribute(VertexDescription.Semantics.Z) - && (export_flags & WktExportFlags.wktExportStripZs) == 0; - boolean b_export_ms = polyline_impl - .hasAttribute(VertexDescription.Semantics.M) - && (export_flags & WktExportFlags.wktExportStripMs) == 0; - - AttributeStreamOfDbl position = null; - AttributeStreamOfDbl zs = null; - AttributeStreamOfDbl ms = null; - AttributeStreamOfInt8 path_flags = null; - AttributeStreamOfInt32 paths = null; - - if (point_count > 0) { - position = (AttributeStreamOfDbl) polyline_impl - .getAttributeStreamRef(VertexDescription.Semantics.POSITION); - path_flags = polyline_impl.getPathFlagsStreamRef(); - paths = polyline_impl.getPathStreamRef(); - - if (b_export_zs) { - if (polyline_impl - ._attributeStreamIsAllocated(VertexDescription.Semantics.Z)) - zs = (AttributeStreamOfDbl) (polyline_impl - .getAttributeStreamRef(VertexDescription.Semantics.Z)); - } - - if (b_export_ms) { - if (polyline_impl - ._attributeStreamIsAllocated(VertexDescription.Semantics.M)) - ms = (AttributeStreamOfDbl) (polyline_impl - .getAttributeStreamRef(VertexDescription.Semantics.M)); - } - } - - if ((export_flags & WktExportFlags.wktExportLineString) != 0) { - if (path_count > 1) - throw new IllegalArgumentException("Cannot export a LineString with specified export flags: " + export_flags); - - lineStringTaggedText_(precision, b_export_zs, b_export_ms, zs, ms, - position, path_flags, paths, string); - } else { - multiLineStringTaggedText_(precision, b_export_zs, b_export_ms, zs, - ms, position, path_flags, paths, path_count, string); - } - } - - static void exportMultiPointToWkt(int export_flags, MultiPoint multipoint, - StringBuilder string) { - MultiPointImpl multipoint_impl = (MultiPointImpl) multipoint._getImpl(); - - int point_count = multipoint_impl.getPointCount(); - - int precision = 17 - (7 & (export_flags >> 13)); - boolean b_export_zs = multipoint_impl - .hasAttribute(VertexDescription.Semantics.Z) - && (export_flags & WktExportFlags.wktExportStripZs) == 0; - boolean b_export_ms = multipoint_impl - .hasAttribute(VertexDescription.Semantics.M) - && (export_flags & WktExportFlags.wktExportStripMs) == 0; - - AttributeStreamOfDbl position = null; - AttributeStreamOfDbl zs = null; - AttributeStreamOfDbl ms = null; - - if (point_count > 0) { - position = (AttributeStreamOfDbl) (multipoint_impl - .getAttributeStreamRef(VertexDescription.Semantics.POSITION)); - - if (b_export_zs) { - if (multipoint_impl - ._attributeStreamIsAllocated(VertexDescription.Semantics.Z)) - zs = (AttributeStreamOfDbl) (multipoint_impl - .getAttributeStreamRef(VertexDescription.Semantics.Z)); - } - - if (b_export_ms) { - if (multipoint_impl - ._attributeStreamIsAllocated(VertexDescription.Semantics.M)) - ms = (AttributeStreamOfDbl) (multipoint_impl - .getAttributeStreamRef(VertexDescription.Semantics.M)); - } - } - - if ((export_flags & WktExportFlags.wktExportPoint) != 0) { - if (point_count > 1) - throw new IllegalArgumentException("Cannot export a Point with specified export flags: " + export_flags); - - pointTaggedTextFromMultiPoint_(precision, b_export_zs, b_export_ms, - zs, ms, position, string); - } else { - multiPointTaggedText_(precision, b_export_zs, b_export_ms, zs, ms, - position, point_count, string); - } - } - - static void exportPointToWkt(int export_flags, Point point, - StringBuilder string) { - int precision = 17 - (7 & (export_flags >> 13)); - boolean b_export_zs = point.hasAttribute(VertexDescription.Semantics.Z) - && (export_flags & WktExportFlags.wktExportStripZs) == 0; - boolean b_export_ms = point.hasAttribute(VertexDescription.Semantics.M) - && (export_flags & WktExportFlags.wktExportStripMs) == 0; - - double x = NumberUtils.TheNaN; - double y = NumberUtils.TheNaN; - double z = NumberUtils.TheNaN; - double m = NumberUtils.TheNaN; - - if (!point.isEmpty()) { - x = point.getX(); - y = point.getY(); - - if (b_export_zs) - z = point.getZ(); - - if (b_export_ms) - m = point.getM(); - } - - if ((export_flags & WktExportFlags.wktExportMultiPoint) != 0) { - multiPointTaggedTextFromPoint_(precision, b_export_zs, b_export_ms, - x, y, z, m, string); - } else { - pointTaggedText_(precision, b_export_zs, b_export_ms, x, y, z, m, - string); - } - } - - static void exportEnvelopeToWkt(int export_flags, Envelope envelope, - StringBuilder string) { - int precision = 17 - (7 & (export_flags >> 13)); - boolean b_export_zs = envelope - .hasAttribute(VertexDescription.Semantics.Z) - && (export_flags & WktExportFlags.wktExportStripZs) == 0; - boolean b_export_ms = envelope - .hasAttribute(VertexDescription.Semantics.M) - && (export_flags & WktExportFlags.wktExportStripMs) == 0; - - double xmin = NumberUtils.TheNaN; - double ymin = NumberUtils.TheNaN; - double xmax = NumberUtils.TheNaN; - double ymax = NumberUtils.TheNaN; - double zmin = NumberUtils.TheNaN; - double zmax = NumberUtils.TheNaN; - double mmin = NumberUtils.TheNaN; - double mmax = NumberUtils.TheNaN; - Envelope1D interval; - - if (!envelope.isEmpty()) { - xmin = envelope.getXMin(); - ymin = envelope.getYMin(); - xmax = envelope.getXMax(); - ymax = envelope.getYMax(); - - if (b_export_zs) { - interval = envelope.queryInterval( - VertexDescription.Semantics.Z, 0); - zmin = interval.vmin; - zmax = interval.vmax; - } - - if (b_export_ms) { - interval = envelope.queryInterval( - VertexDescription.Semantics.M, 0); - mmin = interval.vmin; - mmax = interval.vmax; - } - } - - if ((export_flags & WktExportFlags.wktExportMultiPolygon) != 0) { - multiPolygonTaggedTextFromEnvelope_(precision, b_export_zs, - b_export_ms, xmin, ymin, xmax, ymax, zmin, zmax, mmin, - mmax, string); - } else { - polygonTaggedTextFromEnvelope_(precision, b_export_zs, b_export_ms, - xmin, ymin, xmax, ymax, zmin, zmax, mmin, mmax, string); - } - } - - static void multiPolygonTaggedText_(int precision, boolean b_export_zs, - boolean b_export_ms, AttributeStreamOfDbl zs, - AttributeStreamOfDbl ms, AttributeStreamOfDbl position, - AttributeStreamOfInt8 path_flags, AttributeStreamOfInt32 paths, - int polygon_count, int path_count, StringBuilder string) { - string.append("MULTIPOLYGON "); - - if (b_export_zs && b_export_ms) - string.append("ZM "); - else if (b_export_zs && !b_export_ms) - string.append("Z "); - else if (!b_export_zs && b_export_ms) - string.append("M "); - - if (position == null) { - string.append("EMPTY"); - return; - } - - string.append('('); - - multiPolygonText_(precision, b_export_zs, b_export_ms, zs, ms, - position, path_flags, paths, polygon_count, path_count, string); - - string.append(')'); - } - - static void multiPolygonTaggedTextFromEnvelope_(int precision, - boolean b_export_zs, boolean b_export_ms, double xmin, double ymin, - double xmax, double ymax, double zmin, double zmax, double mmin, - double mmax, StringBuilder string) { - string.append("MULTIPOLYGON "); - - if (b_export_zs && b_export_ms) - string.append("ZM "); - else if (b_export_zs && !b_export_ms) - string.append("Z "); - else if (!b_export_zs && b_export_ms) - string.append("M "); - - if (NumberUtils.isNaN(xmin)) { - string.append("EMPTY"); - return; - } - - string.append('('); - - writeEnvelopeAsWktPolygon_(precision, b_export_zs, b_export_ms, xmin, - ymin, xmax, ymax, zmin, zmax, mmin, mmax, string); - - string.append(')'); - } - - static void multiLineStringTaggedText_(int precision, boolean b_export_zs, - boolean b_export_ms, AttributeStreamOfDbl zs, - AttributeStreamOfDbl ms, AttributeStreamOfDbl position, - AttributeStreamOfInt8 path_flags, AttributeStreamOfInt32 paths, - int path_count, StringBuilder string) { - string.append("MULTILINESTRING "); - - if (b_export_zs && b_export_ms) - string.append("ZM "); - else if (b_export_zs && !b_export_ms) - string.append("Z "); - else if (!b_export_zs && b_export_ms) - string.append("M "); - - if (position == null) { - string.append("EMPTY"); - return; - } - - string.append('('); - - multiLineStringText_(precision, b_export_zs, b_export_ms, zs, ms, - position, path_flags, paths, path_count, string); - - string.append(')'); - } - - static void multiPointTaggedText_(int precision, boolean b_export_zs, - boolean b_export_ms, AttributeStreamOfDbl zs, - AttributeStreamOfDbl ms, AttributeStreamOfDbl position, - int point_count, StringBuilder string) { - string.append("MULTIPOINT "); - - if (b_export_zs && b_export_ms) - string.append("ZM "); - else if (b_export_zs && !b_export_ms) - string.append("Z "); - else if (!b_export_zs && b_export_ms) - string.append("M "); - - if (position == null) { - string.append("EMPTY"); - return; - } - - string.append('('); - - multiPointText_(precision, b_export_zs, b_export_ms, zs, ms, position, - point_count, string); - - string.append(')'); - } - - static void multiPointTaggedTextFromPoint_(int precision, - boolean b_export_zs, boolean b_export_ms, double x, double y, - double z, double m, StringBuilder string) { - string.append("MULTIPOINT "); - - if (b_export_zs && b_export_ms) - string.append("ZM "); - else if (b_export_zs && !b_export_ms) - string.append("Z "); - else if (!b_export_zs && b_export_ms) - string.append("M "); - - if (NumberUtils.isNaN(x)) { - string.append("EMPTY"); - return; - } - - string.append('('); - - pointText_(precision, b_export_zs, b_export_ms, x, y, z, m, string); - - string.append(')'); - } - - static void polygonTaggedText_(int precision, boolean b_export_zs, - boolean b_export_ms, AttributeStreamOfDbl zs, - AttributeStreamOfDbl ms, AttributeStreamOfDbl position, - AttributeStreamOfInt8 path_flags, AttributeStreamOfInt32 paths, - int path_count, StringBuilder string) { - string.append("POLYGON "); - - if (b_export_zs && b_export_ms) - string.append("ZM "); - else if (b_export_zs && !b_export_ms) - string.append("Z "); - else if (!b_export_zs && b_export_ms) - string.append("M "); - - if (position == null) { - string.append("EMPTY"); - return; - } - - polygonText_(precision, b_export_zs, b_export_ms, zs, ms, position, - path_flags, paths, 0, path_count, string); - } - - static void polygonTaggedTextFromEnvelope_(int precision, - boolean b_export_zs, boolean b_export_ms, double xmin, double ymin, - double xmax, double ymax, double zmin, double zmax, double mmin, - double mmax, StringBuilder string) { - string.append("POLYGON "); - - if (b_export_zs && b_export_ms) - string.append("ZM "); - else if (b_export_zs && !b_export_ms) - string.append("Z "); - else if (!b_export_zs && b_export_ms) - string.append("M "); - - if (NumberUtils.isNaN(xmin)) { - string.append("EMPTY"); - return; - } - - writeEnvelopeAsWktPolygon_(precision, b_export_zs, b_export_ms, xmin, - ymin, xmax, ymax, zmin, zmax, mmin, mmax, string); - } - - static void lineStringTaggedText_(int precision, boolean b_export_zs, - boolean b_export_ms, AttributeStreamOfDbl zs, - AttributeStreamOfDbl ms, AttributeStreamOfDbl position, - AttributeStreamOfInt8 path_flags, AttributeStreamOfInt32 paths, - StringBuilder string) { - string.append("LINESTRING "); - - if (b_export_zs && b_export_ms) - string.append("ZM "); - else if (b_export_zs && !b_export_ms) - string.append("Z "); - else if (!b_export_zs && b_export_ms) - string.append("M "); - - if (position == null) { - string.append("EMPTY"); - return; - } - - boolean b_closed = ((path_flags.read(0) & PathFlags.enumClosed) != 0); - - lineStringText_(false, b_closed, precision, b_export_zs, b_export_ms, - zs, ms, position, paths, 0, string); - } - - static void pointTaggedText_(int precision, boolean b_export_zs, - boolean b_export_ms, double x, double y, double z, double m, - StringBuilder string) { - string.append("POINT "); - - if (b_export_zs && b_export_ms) - string.append("ZM "); - else if (b_export_zs && !b_export_ms) - string.append("Z "); - else if (!b_export_zs && b_export_ms) - string.append("M "); - - if (NumberUtils.isNaN(x)) { - string.append("EMPTY"); - return; - } - - pointText_(precision, b_export_zs, b_export_ms, x, y, z, m, string); - } - - static void pointTaggedTextFromMultiPoint_(int precision, - boolean b_export_zs, boolean b_export_ms, AttributeStreamOfDbl zs, - AttributeStreamOfDbl ms, AttributeStreamOfDbl position, - StringBuilder string) { - string.append("POINT "); - - if (b_export_zs && b_export_ms) - string.append("ZM "); - else if (b_export_zs && !b_export_ms) - string.append("Z "); - else if (!b_export_zs && b_export_ms) - string.append("M "); - - if (position == null) { - string.append("EMPTY"); - return; - } - - pointText_(precision, b_export_zs, b_export_ms, zs, ms, position, 0, - string); - } - - static void multiPolygonText_(int precision, boolean b_export_zs, - boolean b_export_ms, AttributeStreamOfDbl zs, - AttributeStreamOfDbl ms, AttributeStreamOfDbl position, - AttributeStreamOfInt8 path_flags, AttributeStreamOfInt32 paths, - int polygon_count, int path_count, StringBuilder string) { - int polygon_start = 0; - int polygon_end = 1; - - while (polygon_end < path_count - && (path_flags.read(polygon_end) & PathFlags.enumOGCStartPolygon) == 0) - polygon_end++; - - polygonText_(precision, b_export_zs, b_export_ms, zs, ms, position, - path_flags, paths, polygon_start, polygon_end, string); - - for (int ipolygon = 1; ipolygon < polygon_count; ipolygon++) { - polygon_start = polygon_end; - polygon_end++; - - while (polygon_end < path_count - && (path_flags.read(polygon_end) & PathFlags.enumOGCStartPolygon) == 0) - polygon_end++; - - string.append(", "); - polygonText_(precision, b_export_zs, b_export_ms, zs, ms, position, - path_flags, paths, polygon_start, polygon_end, string); - } - } - - static void multiLineStringText_(int precision, boolean b_export_zs, - boolean b_export_ms, AttributeStreamOfDbl zs, - AttributeStreamOfDbl ms, AttributeStreamOfDbl position, - AttributeStreamOfInt8 path_flags, AttributeStreamOfInt32 paths, - int path_count, StringBuilder string) { - boolean b_closed = ((path_flags.read(0) & PathFlags.enumClosed) != 0); - - lineStringText_(false, b_closed, precision, b_export_zs, b_export_ms, - zs, ms, position, paths, 0, string); - - for (int path = 1; path < path_count; path++) { - string.append(", "); - - b_closed = ((path_flags.read(path) & PathFlags.enumClosed) != 0); - - lineStringText_(false, b_closed, precision, b_export_zs, - b_export_ms, zs, ms, position, paths, path, string); - } - } - - static void multiPointText_(int precision, boolean b_export_zs, - boolean b_export_ms, AttributeStreamOfDbl zs, - AttributeStreamOfDbl ms, AttributeStreamOfDbl position, - int point_count, StringBuilder string) { - pointText_(precision, b_export_zs, b_export_ms, zs, ms, position, 0, - string); - - for (int point = 1; point < point_count; point++) { - string.append(", "); - pointText_(precision, b_export_zs, b_export_ms, zs, ms, position, - point, string); - } - } - - static void polygonText_(int precision, boolean b_export_zs, - boolean b_export_ms, AttributeStreamOfDbl zs, - AttributeStreamOfDbl ms, AttributeStreamOfDbl position, - AttributeStreamOfInt8 path_flags, AttributeStreamOfInt32 paths, - int polygon_start, int polygon_end, StringBuilder string) { - string.append('('); - - lineStringText_(true, true, precision, b_export_zs, b_export_ms, zs, - ms, position, paths, polygon_start, string); - - for (int path = polygon_start + 1; path < polygon_end; path++) { - string.append(", "); - lineStringText_(true, true, precision, b_export_zs, b_export_ms, - zs, ms, position, paths, path, string); - } - - string.append(')'); - } - - static void lineStringText_(boolean bRing, boolean b_closed, int precision, - boolean b_export_zs, boolean b_export_ms, AttributeStreamOfDbl zs, - AttributeStreamOfDbl ms, AttributeStreamOfDbl position, - AttributeStreamOfInt32 paths, int path, StringBuilder string) { - int istart = paths.read(path); - int iend = paths.read(path + 1); - - if (istart == iend) { - string.append("EMPTY"); - return; - } - - string.append('('); - - if (bRing) { - point_(precision, b_export_zs, b_export_ms, zs, ms, position, - istart, string); - string.append(", "); - - for (int point = iend - 1; point >= istart + 1; point--) { - point_(precision, b_export_zs, b_export_ms, zs, ms, position, - point, string); - string.append(", "); - } - - point_(precision, b_export_zs, b_export_ms, zs, ms, position, - istart, string); - } else { - for (int point = istart; point < iend - 1; point++) { - point_(precision, b_export_zs, b_export_ms, zs, ms, position, - point, string); - string.append(", "); - } - - point_(precision, b_export_zs, b_export_ms, zs, ms, position, - iend - 1, string); - - if (b_closed) { - string.append(", "); - point_(precision, b_export_zs, b_export_ms, zs, ms, position, - istart, string); - } - } - - string.append(')'); - } - - static int pointText_(int precision, boolean b_export_zs, - boolean b_export_ms, double x, double y, double z, double m, - StringBuilder string) { - string.append('('); - point_(precision, b_export_zs, b_export_ms, x, y, z, m, string); - string.append(')'); - - return 1; - } - - static void pointText_(int precision, boolean b_export_zs, - boolean b_export_ms, AttributeStreamOfDbl zs, - AttributeStreamOfDbl ms, AttributeStreamOfDbl position, int point, - StringBuilder string) { - double x = position.read(2 * point); - double y = position.read(2 * point + 1); - double z = NumberUtils.TheNaN; - double m = NumberUtils.TheNaN; - - if (b_export_zs) - z = (zs != null ? zs.read(point) : VertexDescription - .getDefaultValue(VertexDescription.Semantics.Z)); - - if (b_export_ms) - m = (ms != null ? ms.read(point) : VertexDescription - .getDefaultValue(VertexDescription.Semantics.M)); - - pointText_(precision, b_export_zs, b_export_ms, x, y, z, m, string); - } - - static void point_(int precision, boolean b_export_zs, boolean b_export_ms, - double x, double y, double z, double m, StringBuilder string) { - writeSignedNumericLiteral_(x, precision, string); - string.append(' '); - writeSignedNumericLiteral_(y, precision, string); - - if (b_export_zs) { - string.append(' '); - writeSignedNumericLiteral_(z, precision, string); - } - - if (b_export_ms) { - string.append(' '); - writeSignedNumericLiteral_(m, precision, string); - } - } - - static void point_(int precision, boolean b_export_zs, boolean b_export_ms, - AttributeStreamOfDbl zs, AttributeStreamOfDbl ms, - AttributeStreamOfDbl position, int point, StringBuilder string) { - double x = position.read(2 * point); - double y = position.read(2 * point + 1); - double z = NumberUtils.TheNaN; - double m = NumberUtils.TheNaN; - - if (b_export_zs) - z = (zs != null ? zs.read(point) : VertexDescription - .getDefaultValue(VertexDescription.Semantics.Z)); - - if (b_export_ms) - m = (ms != null ? ms.read(point) : VertexDescription - .getDefaultValue(VertexDescription.Semantics.M)); - - point_(precision, b_export_zs, b_export_ms, x, y, z, m, string); - } - - static boolean writeSignedNumericLiteral_(double v, int precision, - StringBuilder string) { - if (NumberUtils.isNaN(v)) { - string.append("NAN"); - return false; - } - - StringUtils.appendDouble(v, precision, string); - return true; - } - - static void writeEnvelopeAsWktPolygon_(int precision, boolean b_export_zs, - boolean b_export_ms, double xmin, double ymin, double xmax, - double ymax, double zmin, double zmax, double mmin, double mmax, - StringBuilder string) { - string.append("(("); - - writeSignedNumericLiteral_(xmin, precision, string); - string.append(' '); - writeSignedNumericLiteral_(ymin, precision, string); - - if (b_export_zs) { - string.append(' '); - writeSignedNumericLiteral_(zmin, precision, string); - } - - if (b_export_ms) { - string.append(' '); - writeSignedNumericLiteral_(mmin, precision, string); - } - - string.append(", "); - - writeSignedNumericLiteral_(xmax, precision, string); - string.append(' '); - writeSignedNumericLiteral_(ymin, precision, string); - - if (b_export_zs) { - string.append(' '); - writeSignedNumericLiteral_(zmax, precision, string); - } - - if (b_export_ms) { - string.append(' '); - writeSignedNumericLiteral_(mmax, precision, string); - } - - string.append(", "); - - writeSignedNumericLiteral_(xmax, precision, string); - string.append(' '); - writeSignedNumericLiteral_(ymax, precision, string); - - if (b_export_zs) { - string.append(' '); - writeSignedNumericLiteral_(zmin, precision, string); - } - - if (b_export_ms) { - string.append(' '); - writeSignedNumericLiteral_(mmin, precision, string); - } - - string.append(", "); - - writeSignedNumericLiteral_(xmin, precision, string); - string.append(' '); - writeSignedNumericLiteral_(ymax, precision, string); - - if (b_export_zs) { - string.append(' '); - writeSignedNumericLiteral_(zmax, precision, string); - } - - if (b_export_ms) { - string.append(' '); - writeSignedNumericLiteral_(mmax, precision, string); - } - - string.append(", "); - - writeSignedNumericLiteral_(xmin, precision, string); - string.append(' '); - writeSignedNumericLiteral_(ymin, precision, string); - - if (b_export_zs) { - string.append(' '); - writeSignedNumericLiteral_(zmin, precision, string); - } - - if (b_export_ms) { - string.append(' '); - writeSignedNumericLiteral_(mmin, precision, string); - } - - string.append("))"); - } + @Override + public StringCursor execute(int exportFlags, GeometryCursor geometryCursor, ProgressTracker progressTracker) { + return new OperatorExportToWktCursor(exportFlags, geometryCursor, progressTracker); + } + + @Override + public String execute(int export_flags, Geometry geometry, + ProgressTracker progress_tracker) { + StringBuilder string = new StringBuilder(); + exportToWkt(export_flags, geometry, string); + + return string.toString(); + } + + static void exportToWkt(int export_flags, Geometry geometry, + StringBuilder string) { + int type = geometry.getType().value(); + switch (type) { + case Geometry.GeometryType.Polygon: + if ((export_flags & WktExportFlags.wktExportLineString) != 0 + || (export_flags & WktExportFlags.wktExportMultiLineString) != 0 + || (export_flags & WktExportFlags.wktExportPoint) != 0 + || (export_flags & WktExportFlags.wktExportMultiPoint) != 0) + throw new IllegalArgumentException("Cannot export a Polygon as (Multi)LineString/(Multi)Point : " + export_flags); + + exportPolygonToWkt(export_flags, (Polygon) geometry, string); + return; + + case Geometry.GeometryType.Polyline: + if ((export_flags & WktExportFlags.wktExportPolygon) != 0 + || (export_flags & WktExportFlags.wktExportMultiPolygon) != 0 + || (export_flags & WktExportFlags.wktExportPoint) != 0 + || (export_flags & WktExportFlags.wktExportMultiPoint) != 0) + throw new IllegalArgumentException("Cannot export a Polyline as (Multi)Polygon/(Multi)Point : " + export_flags); + + exportPolylineToWkt(export_flags, (Polyline) geometry, string); + return; + + case Geometry.GeometryType.MultiPoint: + if ((export_flags & WktExportFlags.wktExportLineString) != 0 + || (export_flags & WktExportFlags.wktExportMultiLineString) != 0 + || (export_flags & WktExportFlags.wktExportPolygon) != 0 + || (export_flags & WktExportFlags.wktExportMultiPolygon) != 0) + throw new IllegalArgumentException("Cannot export a MultiPoint as (Multi)LineString/(Multi)Polygon: " + export_flags); + + exportMultiPointToWkt(export_flags, (MultiPoint) geometry, string); + return; + + case Geometry.GeometryType.Point: + if ((export_flags & WktExportFlags.wktExportLineString) != 0 + || (export_flags & WktExportFlags.wktExportMultiLineString) != 0 + || (export_flags & WktExportFlags.wktExportPolygon) != 0 + || (export_flags & WktExportFlags.wktExportMultiPolygon) != 0) + throw new IllegalArgumentException("Cannot export a Point as (Multi)LineString/(Multi)Polygon: " + export_flags); + + exportPointToWkt(export_flags, (Point) geometry, string); + return; + + case Geometry.GeometryType.Envelope: + if ((export_flags & WktExportFlags.wktExportLineString) != 0 + || (export_flags & WktExportFlags.wktExportMultiLineString) != 0 + || (export_flags & WktExportFlags.wktExportPoint) != 0 + || (export_flags & WktExportFlags.wktExportMultiPoint) != 0) + throw new IllegalArgumentException("Cannot export an Envelope as (Multi)LineString/(Multi)Point: " + export_flags); + + exportEnvelopeToWkt(export_flags, (Envelope) geometry, string); + return; + + default: { + throw GeometryException.GeometryInternalError(); + } + } + } + + static void exportPolygonToWkt(int export_flags, Polygon polygon, + StringBuilder string) { + MultiPathImpl polygon_impl = (MultiPathImpl) polygon._getImpl(); + + if ((export_flags & WktExportFlags.wktExportFailIfNotSimple) != 0) { + int simple = polygon_impl.getIsSimple(0.0); + + if (simple != MultiPathImpl.GeometryXSimple.Strong) + throw new GeometryException("corrupted geometry"); + } + + int point_count = polygon.getPointCount(); + int polygon_count = polygon_impl.getOGCPolygonCount(); + + if (point_count > 0 && polygon_count == 0) + throw new GeometryException("corrupted geometry"); + + int precision = 17 - (7 & (export_flags >> 13)); + boolean b_export_zs = polygon_impl + .hasAttribute(VertexDescription.Semantics.Z) + && (export_flags & WktExportFlags.wktExportStripZs) == 0; + boolean b_export_ms = polygon_impl + .hasAttribute(VertexDescription.Semantics.M) + && (export_flags & WktExportFlags.wktExportStripMs) == 0; + + int path_count = 0; + AttributeStreamOfDbl position = null; + AttributeStreamOfDbl zs = null; + AttributeStreamOfDbl ms = null; + AttributeStreamOfInt8 path_flags = null; + AttributeStreamOfInt32 paths = null; + + if (point_count > 0) { + position = (AttributeStreamOfDbl) (polygon_impl + .getAttributeStreamRef(VertexDescription.Semantics.POSITION)); + path_flags = polygon_impl.getPathFlagsStreamRef(); + paths = polygon_impl.getPathStreamRef(); + path_count = polygon_impl.getPathCount(); + + if (b_export_zs) { + if (polygon_impl + ._attributeStreamIsAllocated(VertexDescription.Semantics.Z)) + zs = (AttributeStreamOfDbl) polygon_impl + .getAttributeStreamRef(VertexDescription.Semantics.Z); + } + + if (b_export_ms) { + if (polygon_impl + ._attributeStreamIsAllocated(VertexDescription.Semantics.M)) + ms = (AttributeStreamOfDbl) polygon_impl + .getAttributeStreamRef(VertexDescription.Semantics.M); + } + } + + if ((export_flags & WktExportFlags.wktExportPolygon) != 0) { + if (polygon_count > 1) + throw new IllegalArgumentException("Cannot export a Polygon with specified export flags: " + export_flags); + + polygonTaggedText_(precision, b_export_zs, b_export_ms, zs, ms, + position, path_flags, paths, path_count, string); + } else { + multiPolygonTaggedText_(precision, b_export_zs, b_export_ms, zs, + ms, position, path_flags, paths, polygon_count, path_count, + string); + } + } + + static void exportPolylineToWkt(int export_flags, Polyline polyline, + StringBuilder string) { + MultiPathImpl polyline_impl = (MultiPathImpl) polyline._getImpl(); + + int point_count = polyline_impl.getPointCount(); + int path_count = polyline_impl.getPathCount(); + + if (point_count > 0 && path_count == 0) + throw new GeometryException("corrupted geometry"); + + int precision = 17 - (7 & (export_flags >> 13)); + boolean b_export_zs = polyline_impl + .hasAttribute(VertexDescription.Semantics.Z) + && (export_flags & WktExportFlags.wktExportStripZs) == 0; + boolean b_export_ms = polyline_impl + .hasAttribute(VertexDescription.Semantics.M) + && (export_flags & WktExportFlags.wktExportStripMs) == 0; + + AttributeStreamOfDbl position = null; + AttributeStreamOfDbl zs = null; + AttributeStreamOfDbl ms = null; + AttributeStreamOfInt8 path_flags = null; + AttributeStreamOfInt32 paths = null; + + if (point_count > 0) { + position = (AttributeStreamOfDbl) polyline_impl + .getAttributeStreamRef(VertexDescription.Semantics.POSITION); + path_flags = polyline_impl.getPathFlagsStreamRef(); + paths = polyline_impl.getPathStreamRef(); + + if (b_export_zs) { + if (polyline_impl + ._attributeStreamIsAllocated(VertexDescription.Semantics.Z)) + zs = (AttributeStreamOfDbl) (polyline_impl + .getAttributeStreamRef(VertexDescription.Semantics.Z)); + } + + if (b_export_ms) { + if (polyline_impl + ._attributeStreamIsAllocated(VertexDescription.Semantics.M)) + ms = (AttributeStreamOfDbl) (polyline_impl + .getAttributeStreamRef(VertexDescription.Semantics.M)); + } + } + + if ((export_flags & WktExportFlags.wktExportLineString) != 0) { + if (path_count > 1) + throw new IllegalArgumentException("Cannot export a LineString with specified export flags: " + export_flags); + + lineStringTaggedText_(precision, b_export_zs, b_export_ms, zs, ms, + position, path_flags, paths, string); + } else { + multiLineStringTaggedText_(precision, b_export_zs, b_export_ms, zs, + ms, position, path_flags, paths, path_count, string); + } + } + + static void exportMultiPointToWkt(int export_flags, MultiPoint multipoint, + StringBuilder string) { + MultiPointImpl multipoint_impl = (MultiPointImpl) multipoint._getImpl(); + + int point_count = multipoint_impl.getPointCount(); + + int precision = 17 - (7 & (export_flags >> 13)); + boolean b_export_zs = multipoint_impl + .hasAttribute(VertexDescription.Semantics.Z) + && (export_flags & WktExportFlags.wktExportStripZs) == 0; + boolean b_export_ms = multipoint_impl + .hasAttribute(VertexDescription.Semantics.M) + && (export_flags & WktExportFlags.wktExportStripMs) == 0; + + AttributeStreamOfDbl position = null; + AttributeStreamOfDbl zs = null; + AttributeStreamOfDbl ms = null; + + if (point_count > 0) { + position = (AttributeStreamOfDbl) (multipoint_impl + .getAttributeStreamRef(VertexDescription.Semantics.POSITION)); + + if (b_export_zs) { + if (multipoint_impl + ._attributeStreamIsAllocated(VertexDescription.Semantics.Z)) + zs = (AttributeStreamOfDbl) (multipoint_impl + .getAttributeStreamRef(VertexDescription.Semantics.Z)); + } + + if (b_export_ms) { + if (multipoint_impl + ._attributeStreamIsAllocated(VertexDescription.Semantics.M)) + ms = (AttributeStreamOfDbl) (multipoint_impl + .getAttributeStreamRef(VertexDescription.Semantics.M)); + } + } + + if ((export_flags & WktExportFlags.wktExportPoint) != 0) { + if (point_count > 1) + throw new IllegalArgumentException("Cannot export a Point with specified export flags: " + export_flags); + + pointTaggedTextFromMultiPoint_(precision, b_export_zs, b_export_ms, + zs, ms, position, string); + } else { + multiPointTaggedText_(precision, b_export_zs, b_export_ms, zs, ms, + position, point_count, string); + } + } + + static void exportPointToWkt(int export_flags, Point point, + StringBuilder string) { + int precision = 17 - (7 & (export_flags >> 13)); + boolean b_export_zs = point.hasAttribute(VertexDescription.Semantics.Z) + && (export_flags & WktExportFlags.wktExportStripZs) == 0; + boolean b_export_ms = point.hasAttribute(VertexDescription.Semantics.M) + && (export_flags & WktExportFlags.wktExportStripMs) == 0; + + double x = NumberUtils.TheNaN; + double y = NumberUtils.TheNaN; + double z = NumberUtils.TheNaN; + double m = NumberUtils.TheNaN; + + if (!point.isEmpty()) { + x = point.getX(); + y = point.getY(); + + if (b_export_zs) + z = point.getZ(); + + if (b_export_ms) + m = point.getM(); + } + + if ((export_flags & WktExportFlags.wktExportMultiPoint) != 0) { + multiPointTaggedTextFromPoint_(precision, b_export_zs, b_export_ms, + x, y, z, m, string); + } else { + pointTaggedText_(precision, b_export_zs, b_export_ms, x, y, z, m, + string); + } + } + + static void exportEnvelopeToWkt(int export_flags, Envelope envelope, + StringBuilder string) { + int precision = 17 - (7 & (export_flags >> 13)); + boolean b_export_zs = envelope + .hasAttribute(VertexDescription.Semantics.Z) + && (export_flags & WktExportFlags.wktExportStripZs) == 0; + boolean b_export_ms = envelope + .hasAttribute(VertexDescription.Semantics.M) + && (export_flags & WktExportFlags.wktExportStripMs) == 0; + + double xmin = NumberUtils.TheNaN; + double ymin = NumberUtils.TheNaN; + double xmax = NumberUtils.TheNaN; + double ymax = NumberUtils.TheNaN; + double zmin = NumberUtils.TheNaN; + double zmax = NumberUtils.TheNaN; + double mmin = NumberUtils.TheNaN; + double mmax = NumberUtils.TheNaN; + Envelope1D interval; + + if (!envelope.isEmpty()) { + xmin = envelope.getXMin(); + ymin = envelope.getYMin(); + xmax = envelope.getXMax(); + ymax = envelope.getYMax(); + + if (b_export_zs) { + interval = envelope.queryInterval( + VertexDescription.Semantics.Z, 0); + zmin = interval.vmin; + zmax = interval.vmax; + } + + if (b_export_ms) { + interval = envelope.queryInterval( + VertexDescription.Semantics.M, 0); + mmin = interval.vmin; + mmax = interval.vmax; + } + } + + if ((export_flags & WktExportFlags.wktExportMultiPolygon) != 0) { + multiPolygonTaggedTextFromEnvelope_(precision, b_export_zs, + b_export_ms, xmin, ymin, xmax, ymax, zmin, zmax, mmin, + mmax, string); + } else { + polygonTaggedTextFromEnvelope_(precision, b_export_zs, b_export_ms, + xmin, ymin, xmax, ymax, zmin, zmax, mmin, mmax, string); + } + } + + static void multiPolygonTaggedText_(int precision, boolean b_export_zs, + boolean b_export_ms, AttributeStreamOfDbl zs, + AttributeStreamOfDbl ms, AttributeStreamOfDbl position, + AttributeStreamOfInt8 path_flags, AttributeStreamOfInt32 paths, + int polygon_count, int path_count, StringBuilder string) { + string.append("MULTIPOLYGON "); + + if (b_export_zs && b_export_ms) + string.append("ZM "); + else if (b_export_zs && !b_export_ms) + string.append("Z "); + else if (!b_export_zs && b_export_ms) + string.append("M "); + + if (position == null) { + string.append("EMPTY"); + return; + } + + string.append('('); + + multiPolygonText_(precision, b_export_zs, b_export_ms, zs, ms, + position, path_flags, paths, polygon_count, path_count, string); + + string.append(')'); + } + + static void multiPolygonTaggedTextFromEnvelope_(int precision, + boolean b_export_zs, boolean b_export_ms, double xmin, double ymin, + double xmax, double ymax, double zmin, double zmax, double mmin, + double mmax, StringBuilder string) { + string.append("MULTIPOLYGON "); + + if (b_export_zs && b_export_ms) + string.append("ZM "); + else if (b_export_zs && !b_export_ms) + string.append("Z "); + else if (!b_export_zs && b_export_ms) + string.append("M "); + + if (NumberUtils.isNaN(xmin)) { + string.append("EMPTY"); + return; + } + + string.append('('); + + writeEnvelopeAsWktPolygon_(precision, b_export_zs, b_export_ms, xmin, + ymin, xmax, ymax, zmin, zmax, mmin, mmax, string); + + string.append(')'); + } + + static void multiLineStringTaggedText_(int precision, boolean b_export_zs, + boolean b_export_ms, AttributeStreamOfDbl zs, + AttributeStreamOfDbl ms, AttributeStreamOfDbl position, + AttributeStreamOfInt8 path_flags, AttributeStreamOfInt32 paths, + int path_count, StringBuilder string) { + string.append("MULTILINESTRING "); + + if (b_export_zs && b_export_ms) + string.append("ZM "); + else if (b_export_zs && !b_export_ms) + string.append("Z "); + else if (!b_export_zs && b_export_ms) + string.append("M "); + + if (position == null) { + string.append("EMPTY"); + return; + } + + string.append('('); + + multiLineStringText_(precision, b_export_zs, b_export_ms, zs, ms, + position, path_flags, paths, path_count, string); + + string.append(')'); + } + + static void multiPointTaggedText_(int precision, boolean b_export_zs, + boolean b_export_ms, AttributeStreamOfDbl zs, + AttributeStreamOfDbl ms, AttributeStreamOfDbl position, + int point_count, StringBuilder string) { + string.append("MULTIPOINT "); + + if (b_export_zs && b_export_ms) + string.append("ZM "); + else if (b_export_zs && !b_export_ms) + string.append("Z "); + else if (!b_export_zs && b_export_ms) + string.append("M "); + + if (position == null) { + string.append("EMPTY"); + return; + } + + string.append('('); + + multiPointText_(precision, b_export_zs, b_export_ms, zs, ms, position, + point_count, string); + + string.append(')'); + } + + static void multiPointTaggedTextFromPoint_(int precision, + boolean b_export_zs, boolean b_export_ms, double x, double y, + double z, double m, StringBuilder string) { + string.append("MULTIPOINT "); + + if (b_export_zs && b_export_ms) + string.append("ZM "); + else if (b_export_zs && !b_export_ms) + string.append("Z "); + else if (!b_export_zs && b_export_ms) + string.append("M "); + + if (NumberUtils.isNaN(x)) { + string.append("EMPTY"); + return; + } + + string.append('('); + + pointText_(precision, b_export_zs, b_export_ms, x, y, z, m, string); + + string.append(')'); + } + + static void polygonTaggedText_(int precision, boolean b_export_zs, + boolean b_export_ms, AttributeStreamOfDbl zs, + AttributeStreamOfDbl ms, AttributeStreamOfDbl position, + AttributeStreamOfInt8 path_flags, AttributeStreamOfInt32 paths, + int path_count, StringBuilder string) { + string.append("POLYGON "); + + if (b_export_zs && b_export_ms) + string.append("ZM "); + else if (b_export_zs && !b_export_ms) + string.append("Z "); + else if (!b_export_zs && b_export_ms) + string.append("M "); + + if (position == null) { + string.append("EMPTY"); + return; + } + + polygonText_(precision, b_export_zs, b_export_ms, zs, ms, position, + path_flags, paths, 0, path_count, string); + } + + static void polygonTaggedTextFromEnvelope_(int precision, + boolean b_export_zs, boolean b_export_ms, double xmin, double ymin, + double xmax, double ymax, double zmin, double zmax, double mmin, + double mmax, StringBuilder string) { + string.append("POLYGON "); + + if (b_export_zs && b_export_ms) + string.append("ZM "); + else if (b_export_zs && !b_export_ms) + string.append("Z "); + else if (!b_export_zs && b_export_ms) + string.append("M "); + + if (NumberUtils.isNaN(xmin)) { + string.append("EMPTY"); + return; + } + + writeEnvelopeAsWktPolygon_(precision, b_export_zs, b_export_ms, xmin, + ymin, xmax, ymax, zmin, zmax, mmin, mmax, string); + } + + static void lineStringTaggedText_(int precision, boolean b_export_zs, + boolean b_export_ms, AttributeStreamOfDbl zs, + AttributeStreamOfDbl ms, AttributeStreamOfDbl position, + AttributeStreamOfInt8 path_flags, AttributeStreamOfInt32 paths, + StringBuilder string) { + string.append("LINESTRING "); + + if (b_export_zs && b_export_ms) + string.append("ZM "); + else if (b_export_zs && !b_export_ms) + string.append("Z "); + else if (!b_export_zs && b_export_ms) + string.append("M "); + + if (position == null) { + string.append("EMPTY"); + return; + } + + boolean b_closed = ((path_flags.read(0) & PathFlags.enumClosed) != 0); + + lineStringText_(false, b_closed, precision, b_export_zs, b_export_ms, + zs, ms, position, paths, 0, string); + } + + static void pointTaggedText_(int precision, boolean b_export_zs, + boolean b_export_ms, double x, double y, double z, double m, + StringBuilder string) { + string.append("POINT "); + + if (b_export_zs && b_export_ms) + string.append("ZM "); + else if (b_export_zs && !b_export_ms) + string.append("Z "); + else if (!b_export_zs && b_export_ms) + string.append("M "); + + if (NumberUtils.isNaN(x)) { + string.append("EMPTY"); + return; + } + + pointText_(precision, b_export_zs, b_export_ms, x, y, z, m, string); + } + + static void pointTaggedTextFromMultiPoint_(int precision, + boolean b_export_zs, boolean b_export_ms, AttributeStreamOfDbl zs, + AttributeStreamOfDbl ms, AttributeStreamOfDbl position, + StringBuilder string) { + string.append("POINT "); + + if (b_export_zs && b_export_ms) + string.append("ZM "); + else if (b_export_zs && !b_export_ms) + string.append("Z "); + else if (!b_export_zs && b_export_ms) + string.append("M "); + + if (position == null) { + string.append("EMPTY"); + return; + } + + pointText_(precision, b_export_zs, b_export_ms, zs, ms, position, 0, + string); + } + + static void multiPolygonText_(int precision, boolean b_export_zs, + boolean b_export_ms, AttributeStreamOfDbl zs, + AttributeStreamOfDbl ms, AttributeStreamOfDbl position, + AttributeStreamOfInt8 path_flags, AttributeStreamOfInt32 paths, + int polygon_count, int path_count, StringBuilder string) { + int polygon_start = 0; + int polygon_end = 1; + + while (polygon_end < path_count + && (path_flags.read(polygon_end) & PathFlags.enumOGCStartPolygon) == 0) + polygon_end++; + + polygonText_(precision, b_export_zs, b_export_ms, zs, ms, position, + path_flags, paths, polygon_start, polygon_end, string); + + for (int ipolygon = 1; ipolygon < polygon_count; ipolygon++) { + polygon_start = polygon_end; + polygon_end++; + + while (polygon_end < path_count + && (path_flags.read(polygon_end) & PathFlags.enumOGCStartPolygon) == 0) + polygon_end++; + + string.append(", "); + polygonText_(precision, b_export_zs, b_export_ms, zs, ms, position, + path_flags, paths, polygon_start, polygon_end, string); + } + } + + static void multiLineStringText_(int precision, boolean b_export_zs, + boolean b_export_ms, AttributeStreamOfDbl zs, + AttributeStreamOfDbl ms, AttributeStreamOfDbl position, + AttributeStreamOfInt8 path_flags, AttributeStreamOfInt32 paths, + int path_count, StringBuilder string) { + boolean b_closed = ((path_flags.read(0) & PathFlags.enumClosed) != 0); + + lineStringText_(false, b_closed, precision, b_export_zs, b_export_ms, + zs, ms, position, paths, 0, string); + + for (int path = 1; path < path_count; path++) { + string.append(", "); + + b_closed = ((path_flags.read(path) & PathFlags.enumClosed) != 0); + + lineStringText_(false, b_closed, precision, b_export_zs, + b_export_ms, zs, ms, position, paths, path, string); + } + } + + static void multiPointText_(int precision, boolean b_export_zs, + boolean b_export_ms, AttributeStreamOfDbl zs, + AttributeStreamOfDbl ms, AttributeStreamOfDbl position, + int point_count, StringBuilder string) { + pointText_(precision, b_export_zs, b_export_ms, zs, ms, position, 0, + string); + + for (int point = 1; point < point_count; point++) { + string.append(", "); + pointText_(precision, b_export_zs, b_export_ms, zs, ms, position, + point, string); + } + } + + static void polygonText_(int precision, boolean b_export_zs, + boolean b_export_ms, AttributeStreamOfDbl zs, + AttributeStreamOfDbl ms, AttributeStreamOfDbl position, + AttributeStreamOfInt8 path_flags, AttributeStreamOfInt32 paths, + int polygon_start, int polygon_end, StringBuilder string) { + string.append('('); + + lineStringText_(true, true, precision, b_export_zs, b_export_ms, zs, + ms, position, paths, polygon_start, string); + + for (int path = polygon_start + 1; path < polygon_end; path++) { + string.append(", "); + lineStringText_(true, true, precision, b_export_zs, b_export_ms, + zs, ms, position, paths, path, string); + } + + string.append(')'); + } + + static void lineStringText_(boolean bRing, boolean b_closed, int precision, + boolean b_export_zs, boolean b_export_ms, AttributeStreamOfDbl zs, + AttributeStreamOfDbl ms, AttributeStreamOfDbl position, + AttributeStreamOfInt32 paths, int path, StringBuilder string) { + int istart = paths.read(path); + int iend = paths.read(path + 1); + + if (istart == iend) { + string.append("EMPTY"); + return; + } + + string.append('('); + + if (bRing) { + point_(precision, b_export_zs, b_export_ms, zs, ms, position, + istart, string); + string.append(", "); + + for (int point = iend - 1; point >= istart + 1; point--) { + point_(precision, b_export_zs, b_export_ms, zs, ms, position, + point, string); + string.append(", "); + } + + point_(precision, b_export_zs, b_export_ms, zs, ms, position, + istart, string); + } else { + for (int point = istart; point < iend - 1; point++) { + point_(precision, b_export_zs, b_export_ms, zs, ms, position, + point, string); + string.append(", "); + } + + point_(precision, b_export_zs, b_export_ms, zs, ms, position, + iend - 1, string); + + if (b_closed) { + string.append(", "); + point_(precision, b_export_zs, b_export_ms, zs, ms, position, + istart, string); + } + } + + string.append(')'); + } + + static int pointText_(int precision, boolean b_export_zs, + boolean b_export_ms, double x, double y, double z, double m, + StringBuilder string) { + string.append('('); + point_(precision, b_export_zs, b_export_ms, x, y, z, m, string); + string.append(')'); + + return 1; + } + + static void pointText_(int precision, boolean b_export_zs, + boolean b_export_ms, AttributeStreamOfDbl zs, + AttributeStreamOfDbl ms, AttributeStreamOfDbl position, int point, + StringBuilder string) { + double x = position.read(2 * point); + double y = position.read(2 * point + 1); + double z = NumberUtils.TheNaN; + double m = NumberUtils.TheNaN; + + if (b_export_zs) + z = (zs != null ? zs.read(point) : VertexDescription + .getDefaultValue(VertexDescription.Semantics.Z)); + + if (b_export_ms) + m = (ms != null ? ms.read(point) : VertexDescription + .getDefaultValue(VertexDescription.Semantics.M)); + + pointText_(precision, b_export_zs, b_export_ms, x, y, z, m, string); + } + + static void point_(int precision, boolean b_export_zs, boolean b_export_ms, + double x, double y, double z, double m, StringBuilder string) { + writeSignedNumericLiteral_(x, precision, string); + string.append(' '); + writeSignedNumericLiteral_(y, precision, string); + + if (b_export_zs) { + string.append(' '); + writeSignedNumericLiteral_(z, precision, string); + } + + if (b_export_ms) { + string.append(' '); + writeSignedNumericLiteral_(m, precision, string); + } + } + + static void point_(int precision, boolean b_export_zs, boolean b_export_ms, + AttributeStreamOfDbl zs, AttributeStreamOfDbl ms, + AttributeStreamOfDbl position, int point, StringBuilder string) { + double x = position.read(2 * point); + double y = position.read(2 * point + 1); + double z = NumberUtils.TheNaN; + double m = NumberUtils.TheNaN; + + if (b_export_zs) + z = (zs != null ? zs.read(point) : VertexDescription + .getDefaultValue(VertexDescription.Semantics.Z)); + + if (b_export_ms) + m = (ms != null ? ms.read(point) : VertexDescription + .getDefaultValue(VertexDescription.Semantics.M)); + + point_(precision, b_export_zs, b_export_ms, x, y, z, m, string); + } + + static boolean writeSignedNumericLiteral_(double v, int precision, + StringBuilder string) { + if (NumberUtils.isNaN(v)) { + string.append("NAN"); + return false; + } + + StringUtils.appendDouble(v, precision, string); + return true; + } + + static void writeEnvelopeAsWktPolygon_(int precision, boolean b_export_zs, + boolean b_export_ms, double xmin, double ymin, double xmax, + double ymax, double zmin, double zmax, double mmin, double mmax, + StringBuilder string) { + string.append("(("); + + writeSignedNumericLiteral_(xmin, precision, string); + string.append(' '); + writeSignedNumericLiteral_(ymin, precision, string); + + if (b_export_zs) { + string.append(' '); + writeSignedNumericLiteral_(zmin, precision, string); + } + + if (b_export_ms) { + string.append(' '); + writeSignedNumericLiteral_(mmin, precision, string); + } + + string.append(", "); + + writeSignedNumericLiteral_(xmax, precision, string); + string.append(' '); + writeSignedNumericLiteral_(ymin, precision, string); + + if (b_export_zs) { + string.append(' '); + writeSignedNumericLiteral_(zmax, precision, string); + } + + if (b_export_ms) { + string.append(' '); + writeSignedNumericLiteral_(mmax, precision, string); + } + + string.append(", "); + + writeSignedNumericLiteral_(xmax, precision, string); + string.append(' '); + writeSignedNumericLiteral_(ymax, precision, string); + + if (b_export_zs) { + string.append(' '); + writeSignedNumericLiteral_(zmin, precision, string); + } + + if (b_export_ms) { + string.append(' '); + writeSignedNumericLiteral_(mmin, precision, string); + } + + string.append(", "); + + writeSignedNumericLiteral_(xmin, precision, string); + string.append(' '); + writeSignedNumericLiteral_(ymax, precision, string); + + if (b_export_zs) { + string.append(' '); + writeSignedNumericLiteral_(zmax, precision, string); + } + + if (b_export_ms) { + string.append(' '); + writeSignedNumericLiteral_(mmax, precision, string); + } + + string.append(", "); + + writeSignedNumericLiteral_(xmin, precision, string); + string.append(' '); + writeSignedNumericLiteral_(ymin, precision, string); + + if (b_export_zs) { + string.append(' '); + writeSignedNumericLiteral_(zmin, precision, string); + } + + if (b_export_ms) { + string.append(' '); + writeSignedNumericLiteral_(mmin, precision, string); + } + + string.append("))"); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorFactory.java b/src/main/java/com/esri/core/geometry/OperatorFactory.java index 673a9af0..745c5b97 100644 --- a/src/main/java/com/esri/core/geometry/OperatorFactory.java +++ b/src/main/java/com/esri/core/geometry/OperatorFactory.java @@ -31,13 +31,13 @@ * An abstract class that represent the basic OperatorFactory interface. */ public abstract class OperatorFactory { - /** - * Returns True if the given operator exists. The type is one of the Operator::Type values or a user defined value. - */ - public abstract boolean isOperatorSupported(Type type); - - /** - * Returns an operator of the given type. Throws an exception if the operator is not supported. - */ - public abstract Operator getOperator(Type type); + /** + * Returns True if the given operator exists. The type is one of the Operator::Type values or a user defined value. + */ + public abstract boolean isOperatorSupported(Type type); + + /** + * Returns an operator of the given type. Throws an exception if the operator is not supported. + */ + public abstract Operator getOperator(Type type); } diff --git a/src/main/java/com/esri/core/geometry/OperatorFactoryLocal.java b/src/main/java/com/esri/core/geometry/OperatorFactoryLocal.java index b7678ffb..923394fb 100644 --- a/src/main/java/com/esri/core/geometry/OperatorFactoryLocal.java +++ b/src/main/java/com/esri/core/geometry/OperatorFactoryLocal.java @@ -1,5 +1,5 @@ /* - Copyright 1995-2015 Esri + Copyright 1995-2017 Esri Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -39,241 +39,257 @@ import java.util.HashMap; /** - * An abstract class that represent the basic OperatorFactory interface. + *An abstract class that represent the basic OperatorFactory interface. */ public class OperatorFactoryLocal extends OperatorFactory { - private static final OperatorFactoryLocal INSTANCE = new OperatorFactoryLocal(); + private static final OperatorFactoryLocal INSTANCE = new OperatorFactoryLocal(); - private static final HashMap st_supportedOperators = new HashMap(); + private static final HashMap st_supportedOperators = new HashMap(); - static { - // Register all implemented operator allocators in the dictionary + static { + // Register all implemented operator allocators in the dictionary - st_supportedOperators.put(Type.Project, new OperatorProjectLocal()); - st_supportedOperators.put(Type.ExportToJson, new OperatorExportToJsonLocal()); - st_supportedOperators.put(Type.ImportFromJson, new OperatorImportFromJsonLocal()); + st_supportedOperators.put(Type.Project, new OperatorProjectLocal()); + st_supportedOperators.put(Type.ExportToJson, new OperatorExportToJsonLocal()); + st_supportedOperators.put(Type.ImportFromJson, new OperatorImportFromJsonLocal()); // st_supportedOperators.put(Type.ImportMapGeometryFromJson, new OperatorImportFromJsonLocal()); - st_supportedOperators.put(Type.ExportToESRIShape, new OperatorExportToESRIShapeLocal()); - st_supportedOperators.put(Type.ImportFromESRIShape, new OperatorImportFromESRIShapeLocal()); - - st_supportedOperators.put(Type.Proximity2D, new OperatorProximity2DLocal()); - st_supportedOperators.put(Type.DensifyByLength, new OperatorDensifyByLengthLocal()); - - st_supportedOperators.put(Type.Relate, new OperatorRelateLocal()); - st_supportedOperators.put(Type.Equals, new OperatorEqualsLocal()); - st_supportedOperators.put(Type.Disjoint, new OperatorDisjointLocal()); - - st_supportedOperators.put(Type.Intersects, new OperatorIntersectsLocal()); - st_supportedOperators.put(Type.Within, new OperatorWithinLocal()); - st_supportedOperators.put(Type.Contains, new OperatorContainsLocal()); - st_supportedOperators.put(Type.Crosses, new OperatorCrossesLocal()); - st_supportedOperators.put(Type.Touches, new OperatorTouchesLocal()); - st_supportedOperators.put(Type.Overlaps, new OperatorOverlapsLocal()); - - st_supportedOperators.put(Type.SimplifyOGC, new OperatorSimplifyLocalOGC()); - st_supportedOperators.put(Type.Simplify, new OperatorSimplifyLocal()); - st_supportedOperators.put(Type.Offset, new OperatorOffsetLocal()); - - st_supportedOperators.put(Type.GeodeticDensifyByLength, new OperatorGeodeticDensifyLocal()); - - st_supportedOperators.put(Type.ShapePreservingDensify, new OperatorShapePreservingDensifyLocal()); - - st_supportedOperators.put(Type.GeodesicBuffer, new OperatorGeodesicBufferLocal()); - - st_supportedOperators.put(Type.GeodeticLength, new OperatorGeodeticLengthLocal()); - st_supportedOperators.put(Type.GeodeticArea, new OperatorGeodeticAreaLocal()); - - st_supportedOperators.put(Type.Buffer, new OperatorBufferLocal()); - st_supportedOperators.put(Type.Distance, new OperatorDistanceLocal()); - st_supportedOperators.put(Type.Intersection, new OperatorIntersectionLocal()); - st_supportedOperators.put(Type.Difference, new OperatorDifferenceLocal()); - st_supportedOperators.put(Type.SymmetricDifference, new OperatorSymmetricDifferenceLocal()); - st_supportedOperators.put(Type.Clip, new OperatorClipLocal()); - st_supportedOperators.put(Type.Cut, new OperatorCutLocal()); - st_supportedOperators.put(Type.ExportToWkb, new OperatorExportToWkbLocal()); - st_supportedOperators.put(Type.ImportFromWkb, new OperatorImportFromWkbLocal()); - st_supportedOperators.put(Type.ExportToWkt, new OperatorExportToWktLocal()); - st_supportedOperators.put(Type.ImportFromWkt, new OperatorImportFromWktLocal()); - st_supportedOperators.put(Type.ImportFromGeoJson, new OperatorImportFromGeoJsonLocal()); - st_supportedOperators.put(Type.ExportToGeoJson, new OperatorExportToGeoJsonLocal()); - st_supportedOperators.put(Type.Union, new OperatorUnionLocal()); - st_supportedOperators.put(Type.GeneralizeByArea, new OperatorGeneralizeByAreaLocal()); - st_supportedOperators.put(Type.Generalize, new OperatorGeneralizeLocal()); - st_supportedOperators.put(Type.ConvexHull, new OperatorConvexHullLocal()); - st_supportedOperators.put(Type.Boundary, new OperatorBoundaryLocal()); - - st_supportedOperators.put(Type.RandomPoints, new OperatorRandomPointsLocal()); - st_supportedOperators.put(Type.EnclosingCircle, new OperatorEnclosingCircleLocal()); - st_supportedOperators.put(Type.GeodeticInverse, new OperatorGeodeticInverseLocal()); - - // LabelPoint, - not ported - - } - - private OperatorFactoryLocal() { - - } - - - /** - * Returns a reference to the singleton. - */ - public static OperatorFactoryLocal getInstance() { - return INSTANCE; - } - - @Override - public Operator getOperator(Type type) { - if (st_supportedOperators.containsKey(type)) { - return st_supportedOperators.get(type); - } else { - throw new IllegalArgumentException(); - } - } - - @Override - public boolean isOperatorSupported(Operator.Type type) { - return st_supportedOperators.containsKey(type); - } - - public static void saveJSONToTextFileDbg(String file_name, - Geometry geometry, - SpatialReference spatial_ref) { - if (file_name == null) { - throw new IllegalArgumentException(); - } - - OperatorFactoryLocal engine = OperatorFactoryLocal.getInstance(); - OperatorExportToJson exporterJSON = (OperatorExportToJson) engine - .getOperator(Operator.Type.ExportToJson); - String jsonString = exporterJSON.execute(spatial_ref, geometry); - - try { - FileOutputStream outfile = new FileOutputStream(file_name); - PrintStream p = new PrintStream(outfile); - p.print(jsonString); - p.close(); - } catch (Exception ex) { - } - } - - public static MapGeometry loadGeometryFromJSONFileDbg(String file_name) { - if (file_name == null) { - throw new IllegalArgumentException(); - } - - String jsonString = null; - try { - FileInputStream stream = new FileInputStream(file_name); - Reader reader = new BufferedReader(new InputStreamReader(stream)); - StringBuilder builder = new StringBuilder(); - char[] buffer = new char[8192]; - int read; - while ((read = reader.read(buffer, 0, buffer.length)) > 0) { - builder.append(buffer, 0, read); - } - stream.close(); - - jsonString = builder.toString(); - } catch (Exception ex) { - } - - MapGeometry mapGeom = OperatorImportFromJson.local().execute(Geometry.Type.Unknown, jsonString); - return mapGeom; - } - - public static MapGeometry loadGeometryFromJSONStringDbg(String json) { - if (json == null) { - throw new IllegalArgumentException(); - } - - MapGeometry mapGeom = null; - try { - mapGeom = OperatorImportFromJson.local().execute(Geometry.Type.Unknown, json); - } catch (Exception e) { - throw new IllegalArgumentException(e.toString()); - } - return mapGeom; - } - - public static Geometry loadGeometryFromEsriShapeDbg(String file_name) { - if (file_name == null) { - throw new IllegalArgumentException(); - } - - try { - FileInputStream stream = new FileInputStream(file_name); - FileChannel fchan = stream.getChannel(); - ByteBuffer bb = ByteBuffer.allocate((int) fchan.size()); - fchan.read(bb); - bb.order(ByteOrder.LITTLE_ENDIAN); - Geometry g = OperatorImportFromESRIShape.local().execute(0, - Geometry.Type.Unknown, bb); - fchan.close(); - stream.close(); - return g; - } catch (Exception ex) { - throw new IllegalArgumentException(); - } - } - - public static void saveGeometryToEsriShapeDbg(String file_name, Geometry geometry) { - if (file_name == null) { - throw new IllegalArgumentException(); - } - - try { - ByteBuffer bb = OperatorExportToESRIShape.local().execute(0, geometry); - FileOutputStream outfile = new FileOutputStream(file_name); - FileChannel fchan = outfile.getChannel(); - fchan.write(bb); - fchan.close(); - outfile.close(); - } catch (Exception ex) { - throw new IllegalArgumentException(); - } - } - - public static void saveToWKTFileDbg(String file_name, - Geometry geometry, SpatialReference spatial_ref) { - if (file_name == null) { - throw new IllegalArgumentException(); - } - - String jsonString = OperatorExportToWkt.local().execute(0, geometry, null); - - try { - FileOutputStream outfile = new FileOutputStream(file_name); - PrintStream p = new PrintStream(outfile); - p.print(jsonString); - p.close(); - } catch (Exception ex) { - } - } - - public static Geometry loadGeometryFromWKTFileDbg(String file_name) { - if (file_name == null) { - throw new IllegalArgumentException(); - } - - String s = null; - try { - FileInputStream stream = new FileInputStream(file_name); - Reader reader = new BufferedReader(new InputStreamReader(stream)); - StringBuilder builder = new StringBuilder(); - char[] buffer = new char[8192]; - int read; - while ((read = reader.read(buffer, 0, buffer.length)) > 0) { - builder.append(buffer, 0, read); - } - stream.close(); - - s = builder.toString(); - } catch (Exception ex) { - } - - return OperatorImportFromWkt.local().execute(0, Geometry.Type.Unknown, s, null); - } + st_supportedOperators.put(Type.ExportToESRIShape, new OperatorExportToESRIShapeLocal()); + st_supportedOperators.put(Type.ImportFromESRIShape, new OperatorImportFromESRIShapeLocal()); + + st_supportedOperators.put(Type.Proximity2D, new OperatorProximity2DLocal()); + st_supportedOperators.put(Type.Centroid2D, new OperatorCentroid2DLocal()); + st_supportedOperators.put(Type.DensifyByLength, new OperatorDensifyByLengthLocal()); + + st_supportedOperators.put(Type.Relate, new OperatorRelateLocal()); + st_supportedOperators.put(Type.Equals, new OperatorEqualsLocal()); + st_supportedOperators.put(Type.Disjoint, new OperatorDisjointLocal()); + + st_supportedOperators.put(Type.Intersects, new OperatorIntersectsLocal()); + st_supportedOperators.put(Type.Within, new OperatorWithinLocal()); + st_supportedOperators.put(Type.Contains, new OperatorContainsLocal()); + st_supportedOperators.put(Type.Crosses, new OperatorCrossesLocal()); + st_supportedOperators.put(Type.Touches, new OperatorTouchesLocal()); + st_supportedOperators.put(Type.Overlaps, new OperatorOverlapsLocal()); + + st_supportedOperators.put(Type.SimplifyOGC, new OperatorSimplifyLocalOGC()); + st_supportedOperators.put(Type.Simplify, new OperatorSimplifyLocal()); + st_supportedOperators.put(Type.Offset, new OperatorOffsetLocal()); + + st_supportedOperators.put(Type.GeodeticDensifyByLength, new OperatorGeodeticDensifyLocal()); + + st_supportedOperators.put(Type.ShapePreservingDensify, new OperatorShapePreservingDensifyLocal()); + + st_supportedOperators.put(Type.GeodesicBuffer, new OperatorGeodesicBufferLocal()); + + st_supportedOperators.put(Type.GeodeticLength, new OperatorGeodeticLengthLocal()); + st_supportedOperators.put(Type.GeodeticArea, new OperatorGeodeticAreaLocal()); + + st_supportedOperators.put(Type.Buffer, new OperatorBufferLocal()); + st_supportedOperators.put(Type.Distance, new OperatorDistanceLocal()); + st_supportedOperators.put(Type.Intersection, new OperatorIntersectionLocal()); + st_supportedOperators.put(Type.Difference, new OperatorDifferenceLocal()); + st_supportedOperators.put(Type.SymmetricDifference, new OperatorSymmetricDifferenceLocal()); + st_supportedOperators.put(Type.Clip, new OperatorClipLocal()); + st_supportedOperators.put(Type.Cut, new OperatorCutLocal()); + st_supportedOperators.put(Type.ExportToWkb, new OperatorExportToWkbLocal()); + st_supportedOperators.put(Type.ImportFromWkb, new OperatorImportFromWkbLocal()); + st_supportedOperators.put(Type.ExportToWkt, new OperatorExportToWktLocal()); + st_supportedOperators.put(Type.ImportFromWkt, new OperatorImportFromWktLocal()); + st_supportedOperators.put(Type.ImportFromGeoJson, new OperatorImportFromGeoJsonLocal()); + st_supportedOperators.put(Type.ExportToGeoJson, new OperatorExportToGeoJsonLocal()); + st_supportedOperators.put(Type.Union, new OperatorUnionLocal()); + st_supportedOperators.put(Type.GeneralizeByArea, new OperatorGeneralizeByAreaLocal()); + st_supportedOperators.put(Type.Generalize, new OperatorGeneralizeLocal()); + st_supportedOperators.put(Type.ConvexHull, new OperatorConvexHullLocal()); + st_supportedOperators.put(Type.Boundary, new OperatorBoundaryLocal()); + + st_supportedOperators.put(Type.RandomPoints, new OperatorRandomPointsLocal()); + st_supportedOperators.put(Type.EnclosingCircle, new OperatorEnclosingCircleLocal()); + st_supportedOperators.put(Type.GeodeticInverse, new OperatorGeodeticInverseLocal()); + + // LabelPoint, - not ported + + } + + private OperatorFactoryLocal() { + + } + + + /** + *Returns a reference to the singleton. + */ + public static OperatorFactoryLocal getInstance() { + return INSTANCE; + } + + @Override + public Operator getOperator(Type type) { + if (st_supportedOperators.containsKey(type)) { + return st_supportedOperators.get(type); + } else { + throw new IllegalArgumentException(); + } + } + + @Override + public boolean isOperatorSupported(Operator.Type type) { + return st_supportedOperators.containsKey(type); + } + + public static void saveJSONToTextFileDbg(String file_name, + Geometry geometry, SpatialReference spatial_ref) { + if (file_name == null) { + throw new IllegalArgumentException(); + } + + OperatorFactoryLocal engine = OperatorFactoryLocal.getInstance(); + OperatorExportToJson exporterJSON = (OperatorExportToJson) engine + .getOperator(Operator.Type.ExportToJson); + String jsonString = exporterJSON.execute(spatial_ref, geometry); + + try { + FileOutputStream outfile = new FileOutputStream(file_name); + PrintStream p = new PrintStream(outfile); + p.print(jsonString); + p.close(); + } catch (Exception ex) { + } + } + + public static MapGeometry loadGeometryFromJSONFileDbg(String file_name) { + if (file_name == null) { + throw new IllegalArgumentException(); + } + + String jsonString = null; + Reader reader = null; + try { + FileInputStream stream = new FileInputStream(file_name); + reader = new BufferedReader(new InputStreamReader(stream)); + StringBuilder builder = new StringBuilder(); + char[] buffer = new char[8192]; + int read; + while ((read = reader.read(buffer, 0, buffer.length)) > 0) { + builder.append(buffer, 0, read); + } + + jsonString = builder.toString(); + } catch (Exception ex) { + } + finally { + if (reader != null) { + try { + reader.close(); + } catch (IOException e) { + } + } + } + + MapGeometry mapGeom = OperatorImportFromJson.local().execute(Geometry.Type.Unknown, jsonString); + return mapGeom; + } + + public static MapGeometry loadGeometryFromJSONStringDbg(String json) { + if (json == null) { + throw new IllegalArgumentException(); + } + + MapGeometry mapGeom = null; + try { + mapGeom = OperatorImportFromJson.local().execute(Geometry.Type.Unknown, json); + } catch (Exception e) { + throw new IllegalArgumentException(e.toString()); + } + return mapGeom; + } + + public static Geometry loadGeometryFromEsriShapeDbg(String file_name) { + if (file_name == null) { + throw new IllegalArgumentException(); + } + + try { + FileInputStream stream = new FileInputStream(file_name); + FileChannel fchan = stream.getChannel(); + ByteBuffer bb = ByteBuffer.allocate((int) fchan.size()); + fchan.read(bb); + bb.order(ByteOrder.LITTLE_ENDIAN); + Geometry g = OperatorImportFromESRIShape.local().execute(0, + Geometry.Type.Unknown, bb); + fchan.close(); + stream.close(); + return g; + } catch (Exception ex) { + throw new IllegalArgumentException(); + } + } + + public static void saveGeometryToEsriShapeDbg(String file_name, Geometry geometry) { + if (file_name == null) { + throw new IllegalArgumentException(); + } + + try { + ByteBuffer bb = OperatorExportToESRIShape.local().execute(0, geometry); + FileOutputStream outfile = new FileOutputStream(file_name); + FileChannel fchan = outfile.getChannel(); + fchan.write(bb); + fchan.close(); + outfile.close(); + } catch (Exception ex) { + throw new IllegalArgumentException(); + } + } + + public static void saveToWKTFileDbg(String file_name, + Geometry geometry, SpatialReference spatial_ref) { + if (file_name == null) { + throw new IllegalArgumentException(); + } + + String jsonString = OperatorExportToWkt.local().execute(0, geometry, null); + + try { + FileOutputStream outfile = new FileOutputStream(file_name); + PrintStream p = new PrintStream(outfile); + p.print(jsonString); + p.close(); + } catch (Exception ex) { + } + } + + public static Geometry loadGeometryFromWKTFileDbg(String file_name) { + if (file_name == null) { + throw new IllegalArgumentException(); + } + + String s = null; + Reader reader = null; + try { + FileInputStream stream = new FileInputStream(file_name); + reader = new BufferedReader(new InputStreamReader(stream)); + StringBuilder builder = new StringBuilder(); + char[] buffer = new char[8192]; + int read; + while ((read = reader.read(buffer, 0, buffer.length)) > 0) { + builder.append(buffer, 0, read); + } + + s = builder.toString(); + } catch (Exception ex) { + } + finally { + if (reader != null) { + try { + reader.close(); + } catch (IOException e) { + } + } + } + + return OperatorImportFromWkt.local().execute(0, Geometry.Type.Unknown, s, null); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorGeneralize.java b/src/main/java/com/esri/core/geometry/OperatorGeneralize.java index d3a23fcb..15528321 100644 --- a/src/main/java/com/esri/core/geometry/OperatorGeneralize.java +++ b/src/main/java/com/esri/core/geometry/OperatorGeneralize.java @@ -27,30 +27,30 @@ * Generalizes geometries using Douglas-Peucker algorithm. */ public abstract class OperatorGeneralize extends Operator { - @Override - public Type getType() { - return Type.Generalize; - } - - /** - * Performs the Generalize operation on a geometry set. Point and - * multipoint geometries are left unchanged. An envelope is converted to a - * polygon. - */ - public abstract GeometryCursor execute(GeometryCursor geoms, - double maxDeviation, boolean bRemoveDegenerateParts, - ProgressTracker progressTracker); - - /** - * Performs the Generalize operation on a single geometry. Point and - * multipoint geometries are left unchanged. An envelope is converted to a - * polygon. - */ - public abstract Geometry execute(Geometry geom, double maxDeviation, - boolean bRemoveDegenerateParts, ProgressTracker progressTracker); - - public static OperatorGeneralize local() { - return (OperatorGeneralize) OperatorFactoryLocal.getInstance().getOperator(Type.Generalize); - } + @Override + public Type getType() { + return Type.Generalize; + } + + /** + * Performs the Generalize operation on a geometry set. Point and + * multipoint geometries are left unchanged. An envelope is converted to a + * polygon. + */ + public abstract GeometryCursor execute(GeometryCursor geoms, + double maxDeviation, boolean bRemoveDegenerateParts, + ProgressTracker progressTracker); + + /** + * Performs the Generalize operation on a single geometry. Point and + * multipoint geometries are left unchanged. An envelope is converted to a + * polygon. + */ + public abstract Geometry execute(Geometry geom, double maxDeviation, + boolean bRemoveDegenerateParts, ProgressTracker progressTracker); + + public static OperatorGeneralize local() { + return (OperatorGeneralize) OperatorFactoryLocal.getInstance().getOperator(Type.Generalize); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorGeneralizeByArea.java b/src/main/java/com/esri/core/geometry/OperatorGeneralizeByArea.java index e5a38acc..f34db8b4 100644 --- a/src/main/java/com/esri/core/geometry/OperatorGeneralizeByArea.java +++ b/src/main/java/com/esri/core/geometry/OperatorGeneralizeByArea.java @@ -5,60 +5,60 @@ * Generalizes geometries using Visvalingam algorithm */ public abstract class OperatorGeneralizeByArea extends Operator { - @Override - public Operator.Type getType() { - return Operator.Type.GeneralizeByArea; - } + @Override + public Operator.Type getType() { + return Operator.Type.GeneralizeByArea; + } - /** - * Performs the Generalize operation on a geometry set. Point and - * multipoint geometries are left unchanged. An envelope is converted to a - * polygon. - */ - public abstract GeometryCursor execute(GeometryCursor geoms, - double percentReduction, - boolean bRemoveDegenerateParts, - GeneralizeType generalizeType, - SpatialReference spatialReference, - ProgressTracker progressTracker); + /** + * Performs the Generalize operation on a geometry set. Point and + * multipoint geometries are left unchanged. An envelope is converted to a + * polygon. + */ + public abstract GeometryCursor execute(GeometryCursor geoms, + double percentReduction, + boolean bRemoveDegenerateParts, + GeneralizeType generalizeType, + SpatialReference spatialReference, + ProgressTracker progressTracker); - /** - * Performs the Generalize operation on a geometry set. Point and - * multipoint geometries are left unchanged. An envelope is converted to a - * polygon. - */ - public abstract GeometryCursor execute(GeometryCursor geoms, - boolean bRemoveDegenerateParts, - int maxPointCount, - GeneralizeType generalizeType, - SpatialReference spatialReference, - ProgressTracker progressTracker); + /** + * Performs the Generalize operation on a geometry set. Point and + * multipoint geometries are left unchanged. An envelope is converted to a + * polygon. + */ + public abstract GeometryCursor execute(GeometryCursor geoms, + boolean bRemoveDegenerateParts, + int maxPointCount, + GeneralizeType generalizeType, + SpatialReference spatialReference, + ProgressTracker progressTracker); - /** - * Performs the Generalize operation on a single geometry. Point and - * multipoint geometries are left unchanged. An envelope is converted to a - * polygon. - */ - public abstract Geometry execute(Geometry geom, - double percentReduction, - boolean bRemoveDegenerateParts, - GeneralizeType generalizeType, - SpatialReference spatialReference, - ProgressTracker progressTracker); + /** + * Performs the Generalize operation on a single geometry. Point and + * multipoint geometries are left unchanged. An envelope is converted to a + * polygon. + */ + public abstract Geometry execute(Geometry geom, + double percentReduction, + boolean bRemoveDegenerateParts, + GeneralizeType generalizeType, + SpatialReference spatialReference, + ProgressTracker progressTracker); - /** - * Performs the Generalize operation on a single geometry. Point and - * multipoint geometries are left unchanged. An envelope is converted to a - * polygon. - */ - public abstract Geometry execute(Geometry geom, - boolean bRemoveDegenerateParts, - int maxPointCount, - GeneralizeType generalizeType, - SpatialReference spatialReference, - ProgressTracker progressTracker); + /** + * Performs the Generalize operation on a single geometry. Point and + * multipoint geometries are left unchanged. An envelope is converted to a + * polygon. + */ + public abstract Geometry execute(Geometry geom, + boolean bRemoveDegenerateParts, + int maxPointCount, + GeneralizeType generalizeType, + SpatialReference spatialReference, + ProgressTracker progressTracker); - public static OperatorGeneralizeByArea local() { - return (OperatorGeneralizeByArea) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.GeneralizeByArea); - } + public static OperatorGeneralizeByArea local() { + return (OperatorGeneralizeByArea) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.GeneralizeByArea); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorGeneralizeByAreaCursor.java b/src/main/java/com/esri/core/geometry/OperatorGeneralizeByAreaCursor.java index 5411b2f6..94e56e53 100644 --- a/src/main/java/com/esri/core/geometry/OperatorGeneralizeByAreaCursor.java +++ b/src/main/java/com/esri/core/geometry/OperatorGeneralizeByAreaCursor.java @@ -8,151 +8,151 @@ * Created by davidraleigh on 4/17/16. */ public class OperatorGeneralizeByAreaCursor extends GeometryCursor { - ProgressTracker m_progressTracker; - boolean m_bRemoveDegenerateParts; - GeneralizeType m_generalizeType; - double m_percentReduction; - SpatialReference m_spatialReference; - int m_maxPointCount; - - public OperatorGeneralizeByAreaCursor(GeometryCursor geoms, - double percentReduction, - boolean bRemoveDegenerateParts, - GeneralizeType generalizeType, - SpatialReference spatialReference, - ProgressTracker progressTracker) { - m_inputGeoms = geoms; - m_progressTracker = progressTracker; - m_bRemoveDegenerateParts = bRemoveDegenerateParts; - m_generalizeType = generalizeType; - m_percentReduction = percentReduction; - m_spatialReference = spatialReference; - - m_maxPointCount = 0; - } - - public OperatorGeneralizeByAreaCursor(GeometryCursor geoms, - boolean bRemoveDegenerateParts, - int maxPointCount, - GeneralizeType generalizeType, - SpatialReference spatialReference, - ProgressTracker progressTracker) { - m_inputGeoms = geoms; - m_progressTracker = progressTracker; - m_bRemoveDegenerateParts = bRemoveDegenerateParts; - m_generalizeType = generalizeType; - m_spatialReference = spatialReference; - - m_maxPointCount = maxPointCount; - } - - @Override - public Geometry next() { - if (hasNext()) - return GeneralizeArea(m_inputGeoms.next()); - - return null; - } - - private Geometry GeneralizeArea(Geometry geom) { - Geometry.Type gt = geom.getType(); - - if (Geometry.isPoint(gt.value())) - return geom; - - if (gt == Geometry.Type.Envelope) { - Polygon poly = new Polygon(geom.getDescription()); - poly.addEnvelope((Envelope) geom, false); - return GeneralizeArea(poly); - } - - if (geom.isEmpty()) - return geom; - - if (m_maxPointCount > 0) { - int pointCount = ((MultiVertexGeometry)geom).getPointCount(); - m_percentReduction = 100 - 100.0 * ((double)m_maxPointCount) / ((double)pointCount); - } - - EditShape editShape = new EditShape(); - editShape.addGeometry(geom); - - GeneralizeAreaPath(editShape); - - // TODO this simplify is a cheat. maybe there's a better way for making sure our geometry isn't screwed up. - return GeometryEngine.simplify(editShape.getGeometry(editShape.getFirstGeometry()), m_spatialReference); - } - - - private void GeneralizeAreaPath(EditShape editShape) { - - Treap treap = new Treap(); - GeneralizeComparator areaComparator = new GeneralizeComparator(editShape, m_generalizeType); - treap.disableBalancing(); - treap.setComparator(areaComparator); - - // TODO fix this. path removal stuff. It's a messy solution to the whole treap cleanup problem - - - for (int iGeometry = editShape.getFirstGeometry(); iGeometry != -1; iGeometry = editShape.getNextGeometry(iGeometry)) { - for (int iPath = editShape.getFirstPath(iGeometry); iPath != -1; iPath = editShape.getNextPath(iPath)) { - int n = editShape.getPathSize(iPath); - treap.setCapacity(n); - int ptCountToRemove = (int)Math.ceil(n * m_percentReduction / 100.0); - - // if there are points that will remain after removals, then first create the treap - int iVertex = editShape.getFirstVertex(iPath); - areaComparator.setPathCount(n * 5); - for (int i = 0; i < n; iVertex = editShape.getNextVertex(iVertex), i++) { - treap.addElement(iVertex, -1); - } - - - while (0 < ptCountToRemove-- && treap.size(-1) > 0) { - - int vertexNode = treap.getFirst(-1); - int vertexElm = treap.getElement(vertexNode); - - GeneralizeComparator.EditShapeTriangle triangle = areaComparator.tryGetCachedTriangle_(vertexElm); - if (triangle == null) { - triangle = areaComparator.tryCreateCachedTriangle_(vertexElm); - if (triangle == null) { - triangle = areaComparator.createTriangle(vertexElm); - } - } - - if ((m_generalizeType == GeneralizeType.ResultContainsOriginal && triangle.queryOrientation() < 0) || - (m_generalizeType == GeneralizeType.ResultWithinOriginal && triangle.queryOrientation() > 0)) { - break; - } - - - if (treap.size(-1) == 1) { - treap.deleteNode(vertexNode, -1); - editShape.removeVertex(vertexElm, false); - } else { - int prevElement = triangle.m_prevVertexIndex; - int nextElement = triangle.m_nextVertexIndex; - - int prevNodeIndex = treap.search(prevElement, -1); - int nextNodeIndex = treap.search(nextElement, -1); + ProgressTracker m_progressTracker; + boolean m_bRemoveDegenerateParts; + GeneralizeType m_generalizeType; + double m_percentReduction; + SpatialReference m_spatialReference; + int m_maxPointCount; + + public OperatorGeneralizeByAreaCursor(GeometryCursor geoms, + double percentReduction, + boolean bRemoveDegenerateParts, + GeneralizeType generalizeType, + SpatialReference spatialReference, + ProgressTracker progressTracker) { + m_inputGeoms = geoms; + m_progressTracker = progressTracker; + m_bRemoveDegenerateParts = bRemoveDegenerateParts; + m_generalizeType = generalizeType; + m_percentReduction = percentReduction; + m_spatialReference = spatialReference; + + m_maxPointCount = 0; + } + + public OperatorGeneralizeByAreaCursor(GeometryCursor geoms, + boolean bRemoveDegenerateParts, + int maxPointCount, + GeneralizeType generalizeType, + SpatialReference spatialReference, + ProgressTracker progressTracker) { + m_inputGeoms = geoms; + m_progressTracker = progressTracker; + m_bRemoveDegenerateParts = bRemoveDegenerateParts; + m_generalizeType = generalizeType; + m_spatialReference = spatialReference; + + m_maxPointCount = maxPointCount; + } + + @Override + public Geometry next() { + if (hasNext()) + return GeneralizeArea(m_inputGeoms.next()); + + return null; + } + + private Geometry GeneralizeArea(Geometry geom) { + Geometry.Type gt = geom.getType(); + + if (Geometry.isPoint(gt.value())) + return geom; + + if (gt == Geometry.Type.Envelope) { + Polygon poly = new Polygon(geom.getDescription()); + poly.addEnvelope((Envelope) geom, false); + return GeneralizeArea(poly); + } + + if (geom.isEmpty()) + return geom; + + if (m_maxPointCount > 0) { + int pointCount = ((MultiVertexGeometry) geom).getPointCount(); + m_percentReduction = 100 - 100.0 * ((double) m_maxPointCount) / ((double) pointCount); + } + + EditShape editShape = new EditShape(); + editShape.addGeometry(geom); + + GeneralizeAreaPath(editShape); + + // TODO this simplify is a cheat. maybe there's a better way for making sure our geometry isn't screwed up. + return GeometryEngine.simplify(editShape.getGeometry(editShape.getFirstGeometry()), m_spatialReference); + } + + + private void GeneralizeAreaPath(EditShape editShape) { + + Treap treap = new Treap(); + GeneralizeComparator areaComparator = new GeneralizeComparator(editShape, m_generalizeType); + treap.disableBalancing(); + treap.setComparator(areaComparator); + + // TODO fix this. path removal stuff. It's a messy solution to the whole treap cleanup problem + + + for (int iGeometry = editShape.getFirstGeometry(); iGeometry != -1; iGeometry = editShape.getNextGeometry(iGeometry)) { + for (int iPath = editShape.getFirstPath(iGeometry); iPath != -1; iPath = editShape.getNextPath(iPath)) { + int n = editShape.getPathSize(iPath); + treap.setCapacity(n); + int ptCountToRemove = (int) Math.ceil(n * m_percentReduction / 100.0); + + // if there are points that will remain after removals, then first create the treap + int iVertex = editShape.getFirstVertex(iPath); + areaComparator.setPathCount(n * 5); + for (int i = 0; i < n; iVertex = editShape.getNextVertex(iVertex), i++) { + treap.addElement(iVertex, -1); + } + + + while (0 < ptCountToRemove-- && treap.size(-1) > 0) { + + int vertexNode = treap.getFirst(-1); + int vertexElm = treap.getElement(vertexNode); + + GeneralizeComparator.EditShapeTriangle triangle = areaComparator.tryGetCachedTriangle_(vertexElm); + if (triangle == null) { + triangle = areaComparator.tryCreateCachedTriangle_(vertexElm); + if (triangle == null) { + triangle = areaComparator.createTriangle(vertexElm); + } + } + + if ((m_generalizeType == GeneralizeType.ResultContainsOriginal && triangle.queryOrientation() < 0) || + (m_generalizeType == GeneralizeType.ResultWithinOriginal && triangle.queryOrientation() > 0)) { + break; + } + + + if (treap.size(-1) == 1) { + treap.deleteNode(vertexNode, -1); + editShape.removeVertex(vertexElm, false); + } else { + int prevElement = triangle.m_prevVertexIndex; + int nextElement = triangle.m_nextVertexIndex; + + int prevNodeIndex = treap.search(prevElement, -1); + int nextNodeIndex = treap.search(nextElement, -1); - if (prevNodeIndex > -1) - treap.deleteNode(prevNodeIndex, -1); - if (nextNodeIndex > -1) - treap.deleteNode(nextNodeIndex, -1); + if (prevNodeIndex > -1) + treap.deleteNode(prevNodeIndex, -1); + if (nextNodeIndex > -1) + treap.deleteNode(nextNodeIndex, -1); - treap.deleteNode(vertexNode, -1); - editShape.removeVertex(vertexElm, false); + treap.deleteNode(vertexNode, -1); + editShape.removeVertex(vertexElm, false); - if (prevNodeIndex > -1) - treap.addElement(prevElement, -1); - if (nextNodeIndex > -1) - treap.addElement(nextElement, -1); - } - } - treap.clear(); - } - } - } + if (prevNodeIndex > -1) + treap.addElement(prevElement, -1); + if (nextNodeIndex > -1) + treap.addElement(nextElement, -1); + } + } + treap.clear(); + } + } + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorGeneralizeByAreaLocal.java b/src/main/java/com/esri/core/geometry/OperatorGeneralizeByAreaLocal.java index ede6f969..7056ac85 100644 --- a/src/main/java/com/esri/core/geometry/OperatorGeneralizeByAreaLocal.java +++ b/src/main/java/com/esri/core/geometry/OperatorGeneralizeByAreaLocal.java @@ -5,75 +5,75 @@ */ final public class OperatorGeneralizeByAreaLocal extends OperatorGeneralizeByArea { - @Override - public GeometryCursor execute(GeometryCursor geoms, - double percentReduction, - boolean bRemoveDegenerateParts, - GeneralizeType generalizeType, - SpatialReference spatialReference, - ProgressTracker progressTracker) { + @Override + public GeometryCursor execute(GeometryCursor geoms, + double percentReduction, + boolean bRemoveDegenerateParts, + GeneralizeType generalizeType, + SpatialReference spatialReference, + ProgressTracker progressTracker) { - return new OperatorGeneralizeByAreaCursor(geoms, - percentReduction, - bRemoveDegenerateParts, - generalizeType, - spatialReference, - progressTracker); - } + return new OperatorGeneralizeByAreaCursor(geoms, + percentReduction, + bRemoveDegenerateParts, + generalizeType, + spatialReference, + progressTracker); + } - @Override - public GeometryCursor execute(GeometryCursor geoms, - boolean bRemoveDegenerateParts, - int maxPointCount, - GeneralizeType generalizeType, - SpatialReference spatialReference, - ProgressTracker progressTracker) { - return new OperatorGeneralizeByAreaCursor(geoms, - bRemoveDegenerateParts, - maxPointCount, - generalizeType, - spatialReference, - progressTracker); - } + @Override + public GeometryCursor execute(GeometryCursor geoms, + boolean bRemoveDegenerateParts, + int maxPointCount, + GeneralizeType generalizeType, + SpatialReference spatialReference, + ProgressTracker progressTracker) { + return new OperatorGeneralizeByAreaCursor(geoms, + bRemoveDegenerateParts, + maxPointCount, + generalizeType, + spatialReference, + progressTracker); + } - @Override - public Geometry execute(Geometry geom, - double percentReduction, - boolean bRemoveDegenerateParts, - GeneralizeType generalizeType, - SpatialReference spatialReference, - ProgressTracker progressTracker) { + @Override + public Geometry execute(Geometry geom, + double percentReduction, + boolean bRemoveDegenerateParts, + GeneralizeType generalizeType, + SpatialReference spatialReference, + ProgressTracker progressTracker) { - SimpleGeometryCursor inputGeomCurs = new SimpleGeometryCursor(geom); + SimpleGeometryCursor inputGeomCurs = new SimpleGeometryCursor(geom); - GeometryCursor geometryCursor = execute(inputGeomCurs, - percentReduction, - bRemoveDegenerateParts, - generalizeType, - spatialReference, - progressTracker); + GeometryCursor geometryCursor = execute(inputGeomCurs, + percentReduction, + bRemoveDegenerateParts, + generalizeType, + spatialReference, + progressTracker); - return geometryCursor.next(); - } + return geometryCursor.next(); + } - @Override - public Geometry execute(Geometry geom, - boolean bRemoveDegenerateParts, - int maxPointCount, - GeneralizeType generalizeType, - SpatialReference spatialReference, - ProgressTracker progressTracker) { + @Override + public Geometry execute(Geometry geom, + boolean bRemoveDegenerateParts, + int maxPointCount, + GeneralizeType generalizeType, + SpatialReference spatialReference, + ProgressTracker progressTracker) { - SimpleGeometryCursor inputGeomCurs = new SimpleGeometryCursor(geom); + SimpleGeometryCursor inputGeomCurs = new SimpleGeometryCursor(geom); - GeometryCursor geometryCursor = execute(inputGeomCurs, - bRemoveDegenerateParts, - maxPointCount, - generalizeType, - spatialReference, - progressTracker); + GeometryCursor geometryCursor = execute(inputGeomCurs, + bRemoveDegenerateParts, + maxPointCount, + generalizeType, + spatialReference, + progressTracker); - return geometryCursor.next(); + return geometryCursor.next(); - } + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorGeneralizeCursor.java b/src/main/java/com/esri/core/geometry/OperatorGeneralizeCursor.java index 5f03a87b..e08900ba 100644 --- a/src/main/java/com/esri/core/geometry/OperatorGeneralizeCursor.java +++ b/src/main/java/com/esri/core/geometry/OperatorGeneralizeCursor.java @@ -24,144 +24,144 @@ package com.esri.core.geometry; final class OperatorGeneralizeCursor extends GeometryCursor { - ProgressTracker m_progressTracker; - double m_maxDeviation; - boolean m_bRemoveDegenerateParts; - - public OperatorGeneralizeCursor(GeometryCursor geoms, double maxDeviation, - boolean bRemoveDegenerateParts, ProgressTracker progressTracker) { - m_inputGeoms = geoms; - m_maxDeviation = maxDeviation; - m_progressTracker = progressTracker; - m_bRemoveDegenerateParts = bRemoveDegenerateParts; - } - - @Override - public Geometry next() { - // TODO Auto-generated method stub - Geometry geom = m_inputGeoms.next(); - if (geom == null) - return null; - return Generalize(geom); - } - - private Geometry Generalize(Geometry geom) { - Geometry.Type gt = geom.getType(); - if (Geometry.isPoint(gt.value())) - return geom; - if (gt == Geometry.Type.Envelope) { - Polygon poly = new Polygon(geom.getDescription()); - poly.addEnvelope((Envelope) geom, false); - return Generalize(poly); - } - if (geom.isEmpty()) - return geom; - MultiPath mp = (MultiPath) geom; - MultiPath dstmp = (MultiPath) geom.createInstance(); - Line line = new Line(); - for (int ipath = 0, npath = mp.getPathCount(); ipath < npath; ipath++) { - GeneralizePath((MultiPathImpl) mp._getImpl(), ipath, - (MultiPathImpl) dstmp._getImpl(), line); - } - - return dstmp; - } - - private void GeneralizePath(MultiPathImpl mpsrc, int ipath, - MultiPathImpl mpdst, Line lineHelper) { - if (mpsrc.getPathSize(ipath) < 2) - return; - int start = mpsrc.getPathStart(ipath); - int end = mpsrc.getPathEnd(ipath) - 1; - AttributeStreamOfDbl xy = (AttributeStreamOfDbl) mpsrc - .getAttributeStreamRef(VertexDescription.Semantics.POSITION); - boolean bClosed = mpsrc.isClosedPath(ipath); - - AttributeStreamOfInt32 stack = new AttributeStreamOfInt32(0); - stack.reserve(mpsrc.getPathSize(ipath) + 1); - AttributeStreamOfInt32 resultStack = new AttributeStreamOfInt32(0); - resultStack.reserve(mpsrc.getPathSize(ipath) + 1); - stack.add(bClosed ? start : end); - stack.add(start); - Point2D pt = new Point2D(); - while (stack.size() > 1) { - int i1 = stack.getLast(); - stack.removeLast(); - int i2 = stack.getLast(); - mpsrc.getXY(i1, pt); - lineHelper.setStartXY(pt); - mpsrc.getXY(i2, pt); - lineHelper.setEndXY(pt); - int mid = FindGreatestDistance(lineHelper, pt, xy, i1, i2, end); - if (mid >= 0) { - stack.add(mid); - stack.add(i1); - } else { - resultStack.add(i1); - } - } - - if (!bClosed) - resultStack.add(stack.get(0)); - - int rs_size = resultStack.size(); - int path_size = mpsrc.getPathSize(ipath); - if (rs_size == path_size && rs_size == stack.size()) { - mpdst.addPath(mpsrc, ipath, true); - } else { - if (resultStack.size() > 0) { - if (m_bRemoveDegenerateParts && resultStack.size() <= 2) { - if (bClosed || resultStack.size() == 1) - return; - - double d = Point2D.distance( - mpsrc.getXY(resultStack.get(0)), - mpsrc.getXY(resultStack.get(1))); - if (d <= m_maxDeviation) - return; - } - - Point point = new Point(); - for (int i = 0, n = resultStack.size(); i < n; i++) { - mpsrc.getPointByVal(resultStack.get(i), point); - if (i == 0) - mpdst.startPath(point); - else - mpdst.lineTo(point); - } - - if (bClosed) { - for (int i = resultStack.size(); i < 3; i++) - mpdst.lineTo(point); - - mpdst.closePathWithLine(); - } - } - } - } - - private int FindGreatestDistance(Line line, Point2D ptHelper, - AttributeStreamOfDbl xy, int start, int end, int pathEnd) { - int to = end - 1; - if (end <= start) {// closed path case. end is equal to the path start. - to = pathEnd; - } - int mid = -1; - double maxd = -1.0; - for (int i = start + 1; i <= to; i++) { - xy.read(2 * i, ptHelper); - double x1 = ptHelper.x; - double y1 = ptHelper.y; - double t = line.getClosestCoordinate(ptHelper, false); - line.getCoord2D(t, ptHelper); - ptHelper.x -= x1; - ptHelper.y -= y1; - double dist = ptHelper.length(); - if (dist > m_maxDeviation && dist > maxd) { - mid = i; - maxd = dist; - } - } - return mid; - } + ProgressTracker m_progressTracker; + double m_maxDeviation; + boolean m_bRemoveDegenerateParts; + + public OperatorGeneralizeCursor(GeometryCursor geoms, double maxDeviation, + boolean bRemoveDegenerateParts, ProgressTracker progressTracker) { + m_inputGeoms = geoms; + m_maxDeviation = maxDeviation; + m_progressTracker = progressTracker; + m_bRemoveDegenerateParts = bRemoveDegenerateParts; + } + + @Override + public Geometry next() { + // TODO Auto-generated method stub + Geometry geom = m_inputGeoms.next(); + if (geom == null) + return null; + return Generalize(geom); + } + + private Geometry Generalize(Geometry geom) { + Geometry.Type gt = geom.getType(); + if (Geometry.isPoint(gt.value())) + return geom; + if (gt == Geometry.Type.Envelope) { + Polygon poly = new Polygon(geom.getDescription()); + poly.addEnvelope((Envelope) geom, false); + return Generalize(poly); + } + if (geom.isEmpty()) + return geom; + MultiPath mp = (MultiPath) geom; + MultiPath dstmp = (MultiPath) geom.createInstance(); + Line line = new Line(); + for (int ipath = 0, npath = mp.getPathCount(); ipath < npath; ipath++) { + GeneralizePath((MultiPathImpl) mp._getImpl(), ipath, + (MultiPathImpl) dstmp._getImpl(), line); + } + + return dstmp; + } + + private void GeneralizePath(MultiPathImpl mpsrc, int ipath, + MultiPathImpl mpdst, Line lineHelper) { + if (mpsrc.getPathSize(ipath) < 2) + return; + int start = mpsrc.getPathStart(ipath); + int end = mpsrc.getPathEnd(ipath) - 1; + AttributeStreamOfDbl xy = (AttributeStreamOfDbl) mpsrc + .getAttributeStreamRef(VertexDescription.Semantics.POSITION); + boolean bClosed = mpsrc.isClosedPath(ipath); + + AttributeStreamOfInt32 stack = new AttributeStreamOfInt32(0); + stack.reserve(mpsrc.getPathSize(ipath) + 1); + AttributeStreamOfInt32 resultStack = new AttributeStreamOfInt32(0); + resultStack.reserve(mpsrc.getPathSize(ipath) + 1); + stack.add(bClosed ? start : end); + stack.add(start); + Point2D pt = new Point2D(); + while (stack.size() > 1) { + int i1 = stack.getLast(); + stack.removeLast(); + int i2 = stack.getLast(); + mpsrc.getXY(i1, pt); + lineHelper.setStartXY(pt); + mpsrc.getXY(i2, pt); + lineHelper.setEndXY(pt); + int mid = FindGreatestDistance(lineHelper, pt, xy, i1, i2, end); + if (mid >= 0) { + stack.add(mid); + stack.add(i1); + } else { + resultStack.add(i1); + } + } + + if (!bClosed) + resultStack.add(stack.get(0)); + + int rs_size = resultStack.size(); + int path_size = mpsrc.getPathSize(ipath); + if (rs_size == path_size && rs_size == stack.size()) { + mpdst.addPath(mpsrc, ipath, true); + } else { + if (resultStack.size() > 0) { + if (m_bRemoveDegenerateParts && resultStack.size() <= 2) { + if (bClosed || resultStack.size() == 1) + return; + + double d = Point2D.distance( + mpsrc.getXY(resultStack.get(0)), + mpsrc.getXY(resultStack.get(1))); + if (d <= m_maxDeviation) + return; + } + + Point point = new Point(); + for (int i = 0, n = resultStack.size(); i < n; i++) { + mpsrc.getPointByVal(resultStack.get(i), point); + if (i == 0) + mpdst.startPath(point); + else + mpdst.lineTo(point); + } + + if (bClosed) { + for (int i = resultStack.size(); i < 3; i++) + mpdst.lineTo(point); + + mpdst.closePathWithLine(); + } + } + } + } + + private int FindGreatestDistance(Line line, Point2D ptHelper, + AttributeStreamOfDbl xy, int start, int end, int pathEnd) { + int to = end - 1; + if (end <= start) {// closed path case. end is equal to the path start. + to = pathEnd; + } + int mid = -1; + double maxd = -1.0; + for (int i = start + 1; i <= to; i++) { + xy.read(2 * i, ptHelper); + double x1 = ptHelper.x; + double y1 = ptHelper.y; + double t = line.getClosestCoordinate(ptHelper, false); + line.getCoord2D(t, ptHelper); + ptHelper.x -= x1; + ptHelper.y -= y1; + double dist = ptHelper.length(); + if (dist > m_maxDeviation && dist > maxd) { + mid = i; + maxd = dist; + } + } + return mid; + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorGeneralizeLocal.java b/src/main/java/com/esri/core/geometry/OperatorGeneralizeLocal.java index 912bb2da..e0392625 100644 --- a/src/main/java/com/esri/core/geometry/OperatorGeneralizeLocal.java +++ b/src/main/java/com/esri/core/geometry/OperatorGeneralizeLocal.java @@ -25,23 +25,23 @@ final class OperatorGeneralizeLocal extends OperatorGeneralize { - @Override - public GeometryCursor execute(GeometryCursor geoms, double maxDeviation, - boolean bRemoveDegenerateParts, ProgressTracker progressTracker) { - // TODO Auto-generated method stub - - return new OperatorGeneralizeCursor(geoms, maxDeviation, - bRemoveDegenerateParts, progressTracker); - } - - @Override - public Geometry execute(Geometry geom, double maxDeviation, - boolean bRemoveDegenerateParts, ProgressTracker progressTracker) { - SimpleGeometryCursor inputGeomCurs = new SimpleGeometryCursor(geom); - GeometryCursor geometryCursor = execute(inputGeomCurs, maxDeviation, - bRemoveDegenerateParts, progressTracker); - - return geometryCursor.next(); - } + @Override + public GeometryCursor execute(GeometryCursor geoms, double maxDeviation, + boolean bRemoveDegenerateParts, ProgressTracker progressTracker) { + // TODO Auto-generated method stub + + return new OperatorGeneralizeCursor(geoms, maxDeviation, + bRemoveDegenerateParts, progressTracker); + } + + @Override + public Geometry execute(Geometry geom, double maxDeviation, + boolean bRemoveDegenerateParts, ProgressTracker progressTracker) { + SimpleGeometryCursor inputGeomCurs = new SimpleGeometryCursor(geom); + GeometryCursor geometryCursor = execute(inputGeomCurs, maxDeviation, + bRemoveDegenerateParts, progressTracker); + + return geometryCursor.next(); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorGeodesicBuffer.java b/src/main/java/com/esri/core/geometry/OperatorGeodesicBuffer.java index 15fd7b38..2473d2c7 100644 --- a/src/main/java/com/esri/core/geometry/OperatorGeodesicBuffer.java +++ b/src/main/java/com/esri/core/geometry/OperatorGeodesicBuffer.java @@ -25,61 +25,61 @@ public abstract class OperatorGeodesicBuffer extends Operator { - @Override - public Operator.Type getType() { - return Operator.Type.GeodesicBuffer; - } + @Override + public Operator.Type getType() { + return Operator.Type.GeodesicBuffer; + } - /** - * Creates a geodesic buffer around the input geometries - * - * @param inputGeometries The geometries to buffer. - * @param sr The Spatial_reference of the Geometries. - * @param curveType The geodetic curve type of the segments. If the curve_type is Geodetic_curve::shape_preserving, then the segments are densified in the projection where they are defined before - * buffering. - * @param distancesMeters The buffer distances in meters for the Geometries. If the size of the distances array is less than the number of geometries in the input_geometries, the last distance value - * is used for the rest of geometries. - * @param maxDeviationMeters The deviation offset to use for convergence. The geodesic arcs of the resulting buffer will be closer than the max deviation of the true buffer. Pass in NaN to use the - * default deviation. - * @param bReserved Must be false. Reserved for future development. Will throw an exception if not false. - * @param bUnion If True, the buffered geometries will be unioned, otherwise they wont be unioned. - * @param progressTracker Can be null. Allows to cancel lengthy operation. - * @return Geometry cursor over result buffers. - */ - public abstract GeometryCursor execute( - GeometryCursor inputGeometries, - SpatialReference sr, - int curveType, - double[] distancesMeters, - double maxDeviationMeters, - boolean bReserved, - boolean bUnion, - ProgressTracker progressTracker); + /** + * Creates a geodesic buffer around the input geometries + * + * @param inputGeometries The geometries to buffer. + * @param sr The Spatial_reference of the Geometries. + * @param curveType The geodetic curve type of the segments. If the curve_type is Geodetic_curve::shape_preserving, then the segments are densified in the projection where they are defined before + * buffering. + * @param distancesMeters The buffer distances in meters for the Geometries. If the size of the distances array is less than the number of geometries in the input_geometries, the last distance value + * is used for the rest of geometries. + * @param maxDeviationMeters The deviation offset to use for convergence. The geodesic arcs of the resulting buffer will be closer than the max deviation of the true buffer. Pass in NaN to use the + * default deviation. + * @param bReserved Must be false. Reserved for future development. Will throw an exception if not false. + * @param bUnion If True, the buffered geometries will be unioned, otherwise they wont be unioned. + * @param progressTracker Can be null. Allows to cancel lengthy operation. + * @return Geometry cursor over result buffers. + */ + public abstract GeometryCursor execute( + GeometryCursor inputGeometries, + SpatialReference sr, + int curveType, + double[] distancesMeters, + double maxDeviationMeters, + boolean bReserved, + boolean bUnion, + ProgressTracker progressTracker); - /** - * Creates a geodesic buffer around the input geometry - * - * @param inputGeometry The geometry to buffer. - * @param sr The Spatial_reference of the Geometry. - * @param curveType The geodetic curve type of the segments. If the curve_type is Geodetic_curve::shape_preserving, then the segments are densified in the projection where they are defined before - * buffering. - * @param distanceMeters The buffer distance in meters for the Geometry. - * @param maxDeviationMeters The deviation offset to use for convergence. The geodesic arcs of the resulting buffer will be closer than the max deviation of the true buffer. Pass in NaN to use the - * default deviation. - * @param bReserved Must be false. Reserved for future development. Will throw an exception if not false. - * @param progressTracker Can be null. Allows to cancel lengthy operation. - * @return Returns result buffer. - */ - public abstract Geometry execute( - Geometry inputGeometry, - SpatialReference sr, - int curveType, - double distanceMeters, - double maxDeviationMeters, - boolean bReserved, - ProgressTracker progressTracker); + /** + * Creates a geodesic buffer around the input geometry + * + * @param inputGeometry The geometry to buffer. + * @param sr The Spatial_reference of the Geometry. + * @param curveType The geodetic curve type of the segments. If the curve_type is Geodetic_curve::shape_preserving, then the segments are densified in the projection where they are defined before + * buffering. + * @param distanceMeters The buffer distance in meters for the Geometry. + * @param maxDeviationMeters The deviation offset to use for convergence. The geodesic arcs of the resulting buffer will be closer than the max deviation of the true buffer. Pass in NaN to use the + * default deviation. + * @param bReserved Must be false. Reserved for future development. Will throw an exception if not false. + * @param progressTracker Can be null. Allows to cancel lengthy operation. + * @return Returns result buffer. + */ + public abstract Geometry execute( + Geometry inputGeometry, + SpatialReference sr, + int curveType, + double distanceMeters, + double maxDeviationMeters, + boolean bReserved, + ProgressTracker progressTracker); - public static OperatorGeodesicBuffer local() { - return (OperatorGeodesicBuffer) OperatorFactoryLocal.getInstance().getOperator(Type.GeodesicBuffer); - } + public static OperatorGeodesicBuffer local() { + return (OperatorGeodesicBuffer) OperatorFactoryLocal.getInstance().getOperator(Type.GeodesicBuffer); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorGeodesicBufferCursor.java b/src/main/java/com/esri/core/geometry/OperatorGeodesicBufferCursor.java index a6f6bce3..0a7650f7 100644 --- a/src/main/java/com/esri/core/geometry/OperatorGeodesicBufferCursor.java +++ b/src/main/java/com/esri/core/geometry/OperatorGeodesicBufferCursor.java @@ -4,54 +4,54 @@ * Created by davidraleigh on 2/20/16. */ public class OperatorGeodesicBufferCursor extends GeometryCursor { - private SpatialReferenceImpl m_spatialReference; - private ProgressTracker m_progressTracker; - private double[] m_distances; - private double m_maxDeviation; - private Envelope2D m_currentUnionEnvelope2D; - private boolean m_bUnion; - - private int m_dindex; - - // GeometryCursor inputGeometries, SpatialReference sr, int curveType, double[] distancesMeters, double maxDeviationMeters, boolean bReserved, boolean bUnion, ProgressTracker progressTracker - OperatorGeodesicBufferCursor(GeometryCursor inputGeoms, - SpatialReference sr, - double[] distances, - double maxDeviation, - boolean bReserved, - boolean b_union, - ProgressTracker progressTracker) { - m_inputGeoms = inputGeoms; - m_spatialReference = (SpatialReferenceImpl) sr; - m_distances = distances; - m_maxDeviation = maxDeviation; - m_bUnion = b_union; - m_currentUnionEnvelope2D = new Envelope2D(); - m_currentUnionEnvelope2D.setEmpty(); - m_dindex = -1; - m_progressTracker = progressTracker; - } - - - @Override - public Geometry next() { - if (m_bUnion) { - OperatorGeodesicBufferCursor cursor = new OperatorGeodesicBufferCursor(m_inputGeoms, m_spatialReference, m_distances, m_maxDeviation, false, false, m_progressTracker); - return ((OperatorUnion) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.Union)).execute(cursor, m_spatialReference, m_progressTracker).next(); - } - - if (hasNext()) { - if (m_dindex + 1 < m_distances.length) - m_dindex++; - - return geodesicBuffer(m_inputGeoms.next(), m_distances[m_dindex]); - } - - return null; - } - - // virtual bool IsRecycling() OVERRIDE { return false; } - Geometry geodesicBuffer(Geometry geom, double distance) { - return GeodesicBufferer.buffer(geom, distance, m_spatialReference, m_maxDeviation, 96, m_progressTracker); - } + private SpatialReferenceImpl m_spatialReference; + private ProgressTracker m_progressTracker; + private double[] m_distances; + private double m_maxDeviation; + private Envelope2D m_currentUnionEnvelope2D; + private boolean m_bUnion; + + private int m_dindex; + + // GeometryCursor inputGeometries, SpatialReference sr, int curveType, double[] distancesMeters, double maxDeviationMeters, boolean bReserved, boolean bUnion, ProgressTracker progressTracker + OperatorGeodesicBufferCursor(GeometryCursor inputGeoms, + SpatialReference sr, + double[] distances, + double maxDeviation, + boolean bReserved, + boolean b_union, + ProgressTracker progressTracker) { + m_inputGeoms = inputGeoms; + m_spatialReference = (SpatialReferenceImpl) sr; + m_distances = distances; + m_maxDeviation = maxDeviation; + m_bUnion = b_union; + m_currentUnionEnvelope2D = new Envelope2D(); + m_currentUnionEnvelope2D.setEmpty(); + m_dindex = -1; + m_progressTracker = progressTracker; + } + + + @Override + public Geometry next() { + if (m_bUnion) { + OperatorGeodesicBufferCursor cursor = new OperatorGeodesicBufferCursor(m_inputGeoms, m_spatialReference, m_distances, m_maxDeviation, false, false, m_progressTracker); + return ((OperatorUnion) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.Union)).execute(cursor, m_spatialReference, m_progressTracker).next(); + } + + if (hasNext()) { + if (m_dindex + 1 < m_distances.length) + m_dindex++; + + return geodesicBuffer(m_inputGeoms.next(), m_distances[m_dindex]); + } + + return null; + } + + // virtual bool IsRecycling() OVERRIDE { return false; } + Geometry geodesicBuffer(Geometry geom, double distance) { + return GeodesicBufferer.buffer(geom, distance, m_spatialReference, m_maxDeviation, 96, m_progressTracker); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorGeodesicBufferLocal.java b/src/main/java/com/esri/core/geometry/OperatorGeodesicBufferLocal.java index 8f2a0bf8..1d20ced4 100644 --- a/src/main/java/com/esri/core/geometry/OperatorGeodesicBufferLocal.java +++ b/src/main/java/com/esri/core/geometry/OperatorGeodesicBufferLocal.java @@ -27,50 +27,50 @@ //This is a stub class OperatorGeodesicBufferLocal extends OperatorGeodesicBuffer { - @Override - public GeometryCursor execute(GeometryCursor inputGeometries, - SpatialReference sr, - int curveType, - double[] distancesMeters, - double maxDeviationMeters, - boolean bReserved, - boolean bUnion, - ProgressTracker progressTracker) { - SpatialReference gcs = SpatialReference.create(4326); - if (sr.getCoordinateSystemType() != SpatialReference.CoordinateSystemType.GEOGRAPHIC) { - // TODO assigning to WGS 84, but should grab GCS from projection - ProjectionTransformation projectionTransformation = new ProjectionTransformation(sr, gcs); - inputGeometries = new OperatorProjectCursor(inputGeometries, projectionTransformation, progressTracker); - } else { - gcs = sr; - } - - inputGeometries = new OperatorGeodesicBufferCursor(inputGeometries, gcs, distancesMeters, maxDeviationMeters, bReserved, bUnion, progressTracker); - - if (sr.getCoordinateSystemType() != SpatialReference.CoordinateSystemType.GEOGRAPHIC) { - ProjectionTransformation projectionTransformation = new ProjectionTransformation(gcs, sr); - inputGeometries = new OperatorProjectCursor(inputGeometries, projectionTransformation, progressTracker); - } - - return inputGeometries; - } - - @Override - public Geometry execute(Geometry inputGeometry, - SpatialReference sr, - int curveType, - double distanceMeters, - double maxDeviationMeters, - boolean bReserved, - ProgressTracker progressTracker) { - - SimpleGeometryCursor inputCursor = new SimpleGeometryCursor(inputGeometry); - - double[] distances = new double[1]; - distances[0] = distanceMeters; - - GeometryCursor outputCursor = execute(inputCursor, sr, curveType, distances, maxDeviationMeters, false, false, progressTracker); - - return outputCursor.next(); - } + @Override + public GeometryCursor execute(GeometryCursor inputGeometries, + SpatialReference sr, + int curveType, + double[] distancesMeters, + double maxDeviationMeters, + boolean bReserved, + boolean bUnion, + ProgressTracker progressTracker) { + SpatialReference gcs = SpatialReference.create(4326); + if (sr.getCoordinateSystemType() != SpatialReference.CoordinateSystemType.GEOGRAPHIC) { + // TODO assigning to WGS 84, but should grab GCS from projection + ProjectionTransformation projectionTransformation = new ProjectionTransformation(sr, gcs); + inputGeometries = new OperatorProjectCursor(inputGeometries, projectionTransformation, progressTracker); + } else { + gcs = sr; + } + + inputGeometries = new OperatorGeodesicBufferCursor(inputGeometries, gcs, distancesMeters, maxDeviationMeters, bReserved, bUnion, progressTracker); + + if (sr.getCoordinateSystemType() != SpatialReference.CoordinateSystemType.GEOGRAPHIC) { + ProjectionTransformation projectionTransformation = new ProjectionTransformation(gcs, sr); + inputGeometries = new OperatorProjectCursor(inputGeometries, projectionTransformation, progressTracker); + } + + return inputGeometries; + } + + @Override + public Geometry execute(Geometry inputGeometry, + SpatialReference sr, + int curveType, + double distanceMeters, + double maxDeviationMeters, + boolean bReserved, + ProgressTracker progressTracker) { + + SimpleGeometryCursor inputCursor = new SimpleGeometryCursor(inputGeometry); + + double[] distances = new double[1]; + distances[0] = distanceMeters; + + GeometryCursor outputCursor = execute(inputCursor, sr, curveType, distances, maxDeviationMeters, false, false, progressTracker); + + return outputCursor.next(); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorGeodeticArea.java b/src/main/java/com/esri/core/geometry/OperatorGeodeticArea.java index d953ad69..bdf603e0 100644 --- a/src/main/java/com/esri/core/geometry/OperatorGeodeticArea.java +++ b/src/main/java/com/esri/core/geometry/OperatorGeodeticArea.java @@ -29,41 +29,41 @@ */ public abstract class OperatorGeodeticArea extends Operator { - @Override - public Type getType() { - return Type.GeodeticArea; - } + @Override + public Type getType() { + return Type.GeodeticArea; + } - /** - * Calculates the geodetic area of each geometry in the geometry cursor. - * - * @param geoms The geometry cursor to be iterated over to perform the - * Geodetic Area calculation. - * @param sr The SpatialReference of the geometries. - * @param geodeticCurveType Use the {@link GeodeticCurveType} interface to choose the - * interpretation of a line connecting two points. - * @param progressTracker - * @return Returns an array of the geodetic areas of the geometries. - */ - public abstract double[] execute(GeometryCursor geoms, SpatialReference sr, - int geodeticCurveType, ProgressTracker progressTracker); + /** + * Calculates the geodetic area of each geometry in the geometry cursor. + * + * @param geoms The geometry cursor to be iterated over to perform the + * Geodetic Area calculation. + * @param sr The SpatialReference of the geometries. + * @param geodeticCurveType Use the {@link GeodeticCurveType} interface to choose the + * interpretation of a line connecting two points. + * @param progressTracker + * @return Returns an array of the geodetic areas of the geometries. + */ + public abstract double[] execute(GeometryCursor geoms, SpatialReference sr, + int geodeticCurveType, ProgressTracker progressTracker); - /** - * Calculates the geodetic area of the input Geometry. - * - * @param geom The input Geometry for the geodetic area calculation. - * @param sr The SpatialReference of the Geometry. - * @param geodeticCurveType Use the {@link GeodeticCurveType} interface to choose the - * interpretation of a line connecting two points. - * @param progressTracker - * @return Returns the geodetic area of the Geometry. - */ - public abstract double execute(Geometry geom, SpatialReference sr, - int geodeticCurveType, ProgressTracker progressTracker); + /** + * Calculates the geodetic area of the input Geometry. + * + * @param geom The input Geometry for the geodetic area calculation. + * @param sr The SpatialReference of the Geometry. + * @param geodeticCurveType Use the {@link GeodeticCurveType} interface to choose the + * interpretation of a line connecting two points. + * @param progressTracker + * @return Returns the geodetic area of the Geometry. + */ + public abstract double execute(Geometry geom, SpatialReference sr, + int geodeticCurveType, ProgressTracker progressTracker); - public static OperatorGeodeticArea local() { - return (OperatorGeodeticArea) OperatorFactoryLocal.getInstance() - .getOperator(Type.GeodeticArea); - } + public static OperatorGeodeticArea local() { + return (OperatorGeodeticArea) OperatorFactoryLocal.getInstance() + .getOperator(Type.GeodeticArea); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorGeodeticAreaLocal.java b/src/main/java/com/esri/core/geometry/OperatorGeodeticAreaLocal.java index 4ee72ae7..556d43de 100644 --- a/src/main/java/com/esri/core/geometry/OperatorGeodeticAreaLocal.java +++ b/src/main/java/com/esri/core/geometry/OperatorGeodeticAreaLocal.java @@ -28,22 +28,22 @@ //This is a stub class OperatorGeodeticAreaLocal extends OperatorGeodeticArea { - @Override - public double[] execute(GeometryCursor geoms, SpatialReference sr, - int geodeticCurveType, ProgressTracker progressTracker) { - ArrayList areas = new ArrayList<>(); - while (geoms.hasNext()) { - areas.add(execute(geoms.next(), sr, geodeticCurveType, progressTracker)); - } - return areas.stream().mapToDouble(d -> d).toArray(); - } - - @Override - public double execute(Geometry geom, SpatialReference sr, - int geodeticCurveType, ProgressTracker progressTracker) { - if (geodeticCurveType != GeodeticCurveType.Geodesic) { - throw new GeometryException("Only implemented for Geodesic"); - } - return ((OperatorProject)OperatorFactoryLocal.getInstance().getOperator(Type.Project)).execute(geom, ProjectionTransformation.getEqualArea(geom, sr), null).calculateArea2D(); - } + @Override + public double[] execute(GeometryCursor geoms, SpatialReference sr, + int geodeticCurveType, ProgressTracker progressTracker) { + ArrayList areas = new ArrayList<>(); + while (geoms.hasNext()) { + areas.add(execute(geoms.next(), sr, geodeticCurveType, progressTracker)); + } + return areas.stream().mapToDouble(d -> d).toArray(); + } + + @Override + public double execute(Geometry geom, SpatialReference sr, + int geodeticCurveType, ProgressTracker progressTracker) { + if (geodeticCurveType != GeodeticCurveType.Geodesic) { + throw new GeometryException("Only implemented for Geodesic"); + } + return ((OperatorProject) OperatorFactoryLocal.getInstance().getOperator(Type.Project)).execute(geom, ProjectionTransformation.getEqualArea(geom, sr), null).calculateArea2D(); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorGeodeticDensifyByLength.java b/src/main/java/com/esri/core/geometry/OperatorGeodeticDensifyByLength.java index 9ed6a8d5..0b798975 100644 --- a/src/main/java/com/esri/core/geometry/OperatorGeodeticDensifyByLength.java +++ b/src/main/java/com/esri/core/geometry/OperatorGeodeticDensifyByLength.java @@ -30,40 +30,40 @@ */ public abstract class OperatorGeodeticDensifyByLength extends Operator { - @Override - public Type getType() { - return Type.GeodeticDensifyByLength; - } + @Override + public Type getType() { + return Type.GeodeticDensifyByLength; + } - /** - * Densifies input geometries. Attributes are interpolated along the scalar t-values of the input segments obtained from the length ratios along the densified segments. - * - * @param geoms The geometries to be densified. - * @param sr The SpatialReference of the Geometry. - * @param maxSegmentLengthMeters The maximum segment length (in meters) allowed. Must be a positive value. - * @param curveType The interpretation of a line connecting two points. - * @return Returns the densified geometries (It does nothing to geometries with dim less than 1, but simply passes them along). - *

- * Note the behavior is not determined for any geodetic curve segments that connect two poles, or for loxodrome segments that connect to any pole. - */ - public abstract GeometryCursor execute( - GeometryCursor geoms, - SpatialReference sr, - double maxSegmentLengthMeters, - int curveType, - ProgressTracker progressTracker); + /** + * Densifies input geometries. Attributes are interpolated along the scalar t-values of the input segments obtained from the length ratios along the densified segments. + * + * @param geoms The geometries to be densified. + * @param sr The SpatialReference of the Geometry. + * @param maxSegmentLengthMeters The maximum segment length (in meters) allowed. Must be a positive value. + * @param curveType The interpretation of a line connecting two points. + * @return Returns the densified geometries (It does nothing to geometries with dim less than 1, but simply passes them along). + *

+ * Note the behavior is not determined for any geodetic curve segments that connect two poles, or for loxodrome segments that connect to any pole. + */ + public abstract GeometryCursor execute( + GeometryCursor geoms, + SpatialReference sr, + double maxSegmentLengthMeters, + int curveType, + ProgressTracker progressTracker); - /** - * Same as above, but works with a single geometry. - */ - public abstract Geometry execute( - Geometry geom, - SpatialReference sr, - double maxSegmentLengthMeters, - int curveType, - ProgressTracker progressTracker); + /** + * Same as above, but works with a single geometry. + */ + public abstract Geometry execute( + Geometry geom, + SpatialReference sr, + double maxSegmentLengthMeters, + int curveType, + ProgressTracker progressTracker); - public static OperatorGeodeticDensifyByLength local() { - return (OperatorGeodeticDensifyByLength) OperatorFactoryLocal.getInstance().getOperator(Type.GeodeticDensifyByLength); - } + public static OperatorGeodeticDensifyByLength local() { + return (OperatorGeodeticDensifyByLength) OperatorFactoryLocal.getInstance().getOperator(Type.GeodeticDensifyByLength); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorGeodeticDensifyCursor.java b/src/main/java/com/esri/core/geometry/OperatorGeodeticDensifyCursor.java index b767a1fe..b2eb6a27 100644 --- a/src/main/java/com/esri/core/geometry/OperatorGeodeticDensifyCursor.java +++ b/src/main/java/com/esri/core/geometry/OperatorGeodeticDensifyCursor.java @@ -4,29 +4,29 @@ * Created by davidraleigh on 2/21/16. */ public class OperatorGeodeticDensifyCursor extends GeometryCursor { - SpatialReferenceImpl m_spatialReference; - double m_maxLength; - Point m_startPoint; - Point m_endPoint; - ProgressTracker m_progressTracker; + SpatialReferenceImpl m_spatialReference; + double m_maxLength; + Point m_startPoint; + Point m_endPoint; + ProgressTracker m_progressTracker; - public OperatorGeodeticDensifyCursor(GeometryCursor inputGeoms1, - SpatialReference spatialReference, - double maxLength, - ProgressTracker progressTracker) { - m_inputGeoms = inputGeoms1; - m_maxLength = maxLength; - m_spatialReference = (SpatialReferenceImpl) spatialReference; - m_startPoint = new Point(); - m_endPoint = new Point(); - m_progressTracker = progressTracker; - } + public OperatorGeodeticDensifyCursor(GeometryCursor inputGeoms1, + SpatialReference spatialReference, + double maxLength, + ProgressTracker progressTracker) { + m_inputGeoms = inputGeoms1; + m_maxLength = maxLength; + m_spatialReference = (SpatialReferenceImpl) spatialReference; + m_startPoint = new Point(); + m_endPoint = new Point(); + m_progressTracker = progressTracker; + } - @Override - public Geometry next() { - if (hasNext()) - return GeodesicDensifier.densifyByLength(m_inputGeoms.next(), m_spatialReference, m_maxLength, m_progressTracker); + @Override + public Geometry next() { + if (hasNext()) + return GeodesicDensifier.densifyByLength(m_inputGeoms.next(), m_spatialReference, m_maxLength, m_progressTracker); - return null; - } + return null; + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorGeodeticDensifyLocal.java b/src/main/java/com/esri/core/geometry/OperatorGeodeticDensifyLocal.java index da1ff5dd..1518885e 100644 --- a/src/main/java/com/esri/core/geometry/OperatorGeodeticDensifyLocal.java +++ b/src/main/java/com/esri/core/geometry/OperatorGeodeticDensifyLocal.java @@ -27,27 +27,27 @@ //This is a stub class OperatorGeodeticDensifyLocal extends OperatorGeodeticDensifyByLength { - @Override - public GeometryCursor execute(GeometryCursor geoms, - SpatialReference sr, - double maxSegmentLengthMeters, - int curveType, - ProgressTracker progressTracker) { - if (maxSegmentLengthMeters <= 0) - // TODO fix geometry exception to match native implementation - throw new GeometryException("max segment length must be positive and greater than 0");// GEOMTHROW(invalid_argument); - - return new OperatorGeodeticDensifyCursor(geoms, sr, maxSegmentLengthMeters, progressTracker); - } - - @Override - public Geometry execute(Geometry geom, - SpatialReference sr, - double maxSegmentLengthMeters, - int curveType, - ProgressTracker progressTracker) { - SimpleGeometryCursor inputCursor = new SimpleGeometryCursor(geom); - GeometryCursor outputCursor = execute(inputCursor, sr, maxSegmentLengthMeters, curveType, progressTracker); - return outputCursor.next(); - } + @Override + public GeometryCursor execute(GeometryCursor geoms, + SpatialReference sr, + double maxSegmentLengthMeters, + int curveType, + ProgressTracker progressTracker) { + if (maxSegmentLengthMeters <= 0) + // TODO fix geometry exception to match native implementation + throw new GeometryException("max segment length must be positive and greater than 0");// GEOMTHROW(invalid_argument); + + return new OperatorGeodeticDensifyCursor(geoms, sr, maxSegmentLengthMeters, progressTracker); + } + + @Override + public Geometry execute(Geometry geom, + SpatialReference sr, + double maxSegmentLengthMeters, + int curveType, + ProgressTracker progressTracker) { + SimpleGeometryCursor inputCursor = new SimpleGeometryCursor(geom); + GeometryCursor outputCursor = execute(inputCursor, sr, maxSegmentLengthMeters, curveType, progressTracker); + return outputCursor.next(); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorGeodeticInverse.java b/src/main/java/com/esri/core/geometry/OperatorGeodeticInverse.java index f5a03234..757a5e2e 100644 --- a/src/main/java/com/esri/core/geometry/OperatorGeodeticInverse.java +++ b/src/main/java/com/esri/core/geometry/OperatorGeodeticInverse.java @@ -29,31 +29,32 @@ */ public abstract class OperatorGeodeticInverse extends Operator { - @Override - public Type getType() { - return Type.GeodeticInverse; - } - - /** - * calculate the ngs forward equations for distance and azimuth calculations - * @param geom1 point1 (for now only supports point, could support centroids in future) - * @param geom2 point2 (for now only supports point, could support centroids in future) - * @param sr1 spatial reference of point one (this is the ellipsoid that the calculation will use) - * @param sr2 spatial reference of point two - * @param geodeticCurveType for now only ellipsoid geodesic - * @param progressTracker not used - * @return forward results of azimuth from 1 to 2, azimuth from 2 to 1, and the distance - */ - public abstract InverseResult execute(Geometry geom1, - Geometry geom2, - SpatialReference sr1, - SpatialReference sr2, - int geodeticCurveType, - ProgressTracker progressTracker); - - public static OperatorGeodeticInverse local() { - return (OperatorGeodeticInverse) OperatorFactoryLocal.getInstance() - .getOperator(Type.GeodeticInverse); - } + @Override + public Type getType() { + return Type.GeodeticInverse; + } + + /** + * calculate the ngs forward equations for distance and azimuth calculations + * + * @param geom1 point1 (for now only supports point, could support centroids in future) + * @param geom2 point2 (for now only supports point, could support centroids in future) + * @param sr1 spatial reference of point one (this is the ellipsoid that the calculation will use) + * @param sr2 spatial reference of point two + * @param geodeticCurveType for now only ellipsoid geodesic + * @param progressTracker not used + * @return forward results of azimuth from 1 to 2, azimuth from 2 to 1, and the distance + */ + public abstract InverseResult execute(Geometry geom1, + Geometry geom2, + SpatialReference sr1, + SpatialReference sr2, + int geodeticCurveType, + ProgressTracker progressTracker); + + public static OperatorGeodeticInverse local() { + return (OperatorGeodeticInverse) OperatorFactoryLocal.getInstance() + .getOperator(Type.GeodeticInverse); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorGeodeticInverseLocal.java b/src/main/java/com/esri/core/geometry/OperatorGeodeticInverseLocal.java index b8a4ea40..d52f81a8 100644 --- a/src/main/java/com/esri/core/geometry/OperatorGeodeticInverseLocal.java +++ b/src/main/java/com/esri/core/geometry/OperatorGeodeticInverseLocal.java @@ -26,35 +26,35 @@ //This is a stub class OperatorGeodeticInverseLocal extends OperatorGeodeticInverse { - @Override - public InverseResult execute(Geometry geom1, Geometry geom2, SpatialReference sr1, SpatialReference sr2, int geodeticCurveType, ProgressTracker progressTracker) { - if (geodeticCurveType != GeodeticCurveType.Geodesic) { - throw new GeometryException("only Geodesic implemented"); - } - if (geom1.getType() != Geometry.Type.Point || geom2.getType() != Geometry.Type.Point) { - throw new GeometryException("only implemented for points"); - } - - double a, e2; - Point projected1; - ProjectionTransformation projectionTransformation; - if (sr1.getCoordinateSystemType() != SpatialReference.CoordinateSystemType.GEOGRAPHIC) { - SpatialReference wgs84 = SpatialReference.create(4326); - projectionTransformation = new ProjectionTransformation(sr1, wgs84); - sr1 = wgs84; - projected1 = (Point)OperatorProject.local().execute(geom1, projectionTransformation, progressTracker); - a = wgs84.getMajorAxis(); - e2 = wgs84.getEccentricitySquared(); - } else { - projected1 = (Point)geom1; - a = sr1.getMajorAxis(); - e2 = sr1.getEccentricitySquared(); - } - - // TODO it'd be great if this was reusable so we didn't have this mem allocaiton - projectionTransformation = new ProjectionTransformation(sr2, sr1); - Point projected2 = (Point)OperatorProject.local().execute(geom2, projectionTransformation, progressTracker); - - return GeoDist.geodesicInverse(a, e2, projected1.getXY(), projected2.getXY()); - } + @Override + public InverseResult execute(Geometry geom1, Geometry geom2, SpatialReference sr1, SpatialReference sr2, int geodeticCurveType, ProgressTracker progressTracker) { + if (geodeticCurveType != GeodeticCurveType.Geodesic) { + throw new GeometryException("only Geodesic implemented"); + } + if (geom1.getType() != Geometry.Type.Point || geom2.getType() != Geometry.Type.Point) { + throw new GeometryException("only implemented for points"); + } + + double a, e2; + Point projected1; + ProjectionTransformation projectionTransformation; + if (sr1.getCoordinateSystemType() != SpatialReference.CoordinateSystemType.GEOGRAPHIC) { + SpatialReference wgs84 = SpatialReference.create(4326); + projectionTransformation = new ProjectionTransformation(sr1, wgs84); + sr1 = wgs84; + projected1 = (Point) OperatorProject.local().execute(geom1, projectionTransformation, progressTracker); + a = wgs84.getMajorAxis(); + e2 = wgs84.getEccentricitySquared(); + } else { + projected1 = (Point) geom1; + a = sr1.getMajorAxis(); + e2 = sr1.getEccentricitySquared(); + } + + // TODO it'd be great if this was reusable so we didn't have this mem allocaiton + projectionTransformation = new ProjectionTransformation(sr2, sr1); + Point projected2 = (Point) OperatorProject.local().execute(geom2, projectionTransformation, progressTracker); + + return GeoDist.geodesicInverse(a, e2, projected1.getXY(), projected2.getXY()); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorGeodeticLength.java b/src/main/java/com/esri/core/geometry/OperatorGeodeticLength.java index 665c7227..a58a4fb1 100644 --- a/src/main/java/com/esri/core/geometry/OperatorGeodeticLength.java +++ b/src/main/java/com/esri/core/geometry/OperatorGeodeticLength.java @@ -29,27 +29,27 @@ */ public abstract class OperatorGeodeticLength extends Operator { - @Override - public Type getType() { - return Operator.Type.GeodeticLength; - } - - /** - * Calculates the geodetic length of the input Geometry. - * - * @param geom The input Geometry for the geodetic length calculation. - * @param sr The SpatialReference of the Geometry. - * @param geodeticCurveType Use the {@link GeodeticCurveType} interface to choose the - * interpretation of a line connecting two points. - * @param progressTracker - * @return Returns the geoetic length of the Geometry. - */ - public abstract double execute(Geometry geom, SpatialReference sr, - int geodeticCurveType, ProgressTracker progressTracker); - - public static OperatorGeodeticLength local() { - return (OperatorGeodeticLength) OperatorFactoryLocal.getInstance() - .getOperator(Type.GeodeticLength); - } + @Override + public Type getType() { + return Operator.Type.GeodeticLength; + } + + /** + * Calculates the geodetic length of the input Geometry. + * + * @param geom The input Geometry for the geodetic length calculation. + * @param sr The SpatialReference of the Geometry. + * @param geodeticCurveType Use the {@link GeodeticCurveType} interface to choose the + * interpretation of a line connecting two points. + * @param progressTracker + * @return Returns the geoetic length of the Geometry. + */ + public abstract double execute(Geometry geom, SpatialReference sr, + int geodeticCurveType, ProgressTracker progressTracker); + + public static OperatorGeodeticLength local() { + return (OperatorGeodeticLength) OperatorFactoryLocal.getInstance() + .getOperator(Type.GeodeticLength); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorGeodeticLengthLocal.java b/src/main/java/com/esri/core/geometry/OperatorGeodeticLengthLocal.java index 822c311d..e1ba8048 100644 --- a/src/main/java/com/esri/core/geometry/OperatorGeodeticLengthLocal.java +++ b/src/main/java/com/esri/core/geometry/OperatorGeodeticLengthLocal.java @@ -26,43 +26,43 @@ //This is a stub class OperatorGeodeticLengthLocal extends OperatorGeodeticLength { - @Override - public double execute(Geometry geom, - SpatialReference sr, - int geodeticCurveType, - ProgressTracker progressTracker) { - if (geodeticCurveType != GeodeticCurveType.Geodesic) { - throw new GeometryException("only Geodesic implemented"); - } - if (geom.getType() == Geometry.Type.MultiPoint || geom.getType() == Geometry.Type.Point) { - return 0; - } + @Override + public double execute(Geometry geom, + SpatialReference sr, + int geodeticCurveType, + ProgressTracker progressTracker) { + if (geodeticCurveType != GeodeticCurveType.Geodesic) { + throw new GeometryException("only Geodesic implemented"); + } + if (geom.getType() == Geometry.Type.MultiPoint || geom.getType() == Geometry.Type.Point) { + return 0; + } - SegmentIteratorImpl segIter; - double a, e2; - if (sr.getCoordinateSystemType() != SpatialReference.CoordinateSystemType.GEOGRAPHIC) { - SpatialReference wgs84 = SpatialReference.create(4326); - ProjectionTransformation projectionTransformation = new ProjectionTransformation(sr, wgs84); - Geometry projected = OperatorProject.local().execute(geom, projectionTransformation, progressTracker); - segIter = ((MultiPathImpl)projected._getImpl()).querySegmentIterator(); - a = wgs84.getMajorAxis(); - e2 = wgs84.getEccentricitySquared(); - } else { - segIter = ((MultiPathImpl)geom._getImpl()).querySegmentIterator(); - a = sr.getMajorAxis(); - e2 = sr.getEccentricitySquared(); - } + SegmentIteratorImpl segIter; + double a, e2; + if (sr.getCoordinateSystemType() != SpatialReference.CoordinateSystemType.GEOGRAPHIC) { + SpatialReference wgs84 = SpatialReference.create(4326); + ProjectionTransformation projectionTransformation = new ProjectionTransformation(sr, wgs84); + Geometry projected = OperatorProject.local().execute(geom, projectionTransformation, progressTracker); + segIter = ((MultiPathImpl) projected._getImpl()).querySegmentIterator(); + a = wgs84.getMajorAxis(); + e2 = wgs84.getEccentricitySquared(); + } else { + segIter = ((MultiPathImpl) geom._getImpl()).querySegmentIterator(); + a = sr.getMajorAxis(); + e2 = sr.getEccentricitySquared(); + } - MathUtils.KahanSummator len = new MathUtils.KahanSummator(0); + MathUtils.KahanSummator len = new MathUtils.KahanSummator(0); - while (segIter.nextPath()) { - while (segIter.hasNextSegment()) { - Segment segment = segIter.nextSegment(); - double dist = GeoDist.geodesicDistance(a, e2, segment.getStartXY(), segment.getEndXY(), null, null); - len.add(dist); - } - } + while (segIter.nextPath()) { + while (segIter.hasNextSegment()) { + Segment segment = segIter.nextSegment(); + double dist = GeoDist.geodesicDistance(a, e2, segment.getStartXY(), segment.getEndXY(), null, null); + len.add(dist); + } + } - return len.getResult(); - } + return len.getResult(); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorImportFromESRIShape.java b/src/main/java/com/esri/core/geometry/OperatorImportFromESRIShape.java index 469359c4..f41e4554 100644 --- a/src/main/java/com/esri/core/geometry/OperatorImportFromESRIShape.java +++ b/src/main/java/com/esri/core/geometry/OperatorImportFromESRIShape.java @@ -32,41 +32,41 @@ * Import from ESRI shape format. */ public abstract class OperatorImportFromESRIShape extends Operator { - @Override - public Type getType() { - return Type.ImportFromESRIShape; - } + @Override + public Type getType() { + return Type.ImportFromESRIShape; + } - /** - * Performs the ImportFromESRIShape operation on a stream of shape buffers - * - * @param importFlags Use the {@link ShapeImportFlags} interface. The default is 0, which means geometry comes - * from a trusted source and is topologically simple. - * If the geometry comes from non-trusted source (that is it can be non-simple), pass ShapeImportNonTrusted. - * @param type The geometry type that you want to import. Use the {@link Geometry.Type} enum. It can be - * Geometry.Type.Unknown if the type of geometry has to be - * figured out from the shape buffer. - * @param shapeBuffers The cursor over shape buffers that hold the Geometries in ESRIShape format. - * @return Returns a GeometryCursor. - */ - public abstract GeometryCursor execute(int importFlags, Geometry.Type type, ByteBufferCursor shapeBuffers); + /** + * Performs the ImportFromESRIShape operation on a stream of shape buffers + * + * @param importFlags Use the {@link ShapeImportFlags} interface. The default is 0, which means geometry comes + * from a trusted source and is topologically simple. + * If the geometry comes from non-trusted source (that is it can be non-simple), pass ShapeImportNonTrusted. + * @param type The geometry type that you want to import. Use the {@link Geometry.Type} enum. It can be + * Geometry.Type.Unknown if the type of geometry has to be + * figured out from the shape buffer. + * @param shapeBuffers The cursor over shape buffers that hold the Geometries in ESRIShape format. + * @return Returns a GeometryCursor. + */ + public abstract GeometryCursor execute(int importFlags, Geometry.Type type, ByteBufferCursor shapeBuffers); - /** - * Performs the ImportFromESRIShape operation. - * - * @param importFlags Use the {@link ShapeImportFlags} interface. The default is 0, which means geometry - * comes from a trusted source and is topologically simple. - * If the geometry comes from non-trusted source (that is it can be non-simple), pass ShapeImportNonTrusted. - * @param type The geometry type that you want to import. Use the {@link Geometry.Type} enum. It can be - * Geometry.Type.Unknown if the type of geometry has to be - * figured out from the shape buffer. - * @param shapeBuffer The buffer holding the Geometry in ESRIShape format. - * @return Returns the imported Geometry. - */ - public abstract Geometry execute(int importFlags, Geometry.Type type, ByteBuffer shapeBuffer); + /** + * Performs the ImportFromESRIShape operation. + * + * @param importFlags Use the {@link ShapeImportFlags} interface. The default is 0, which means geometry + * comes from a trusted source and is topologically simple. + * If the geometry comes from non-trusted source (that is it can be non-simple), pass ShapeImportNonTrusted. + * @param type The geometry type that you want to import. Use the {@link Geometry.Type} enum. It can be + * Geometry.Type.Unknown if the type of geometry has to be + * figured out from the shape buffer. + * @param shapeBuffer The buffer holding the Geometry in ESRIShape format. + * @return Returns the imported Geometry. + */ + public abstract Geometry execute(int importFlags, Geometry.Type type, ByteBuffer shapeBuffer); - public static OperatorImportFromESRIShape local() { - return (OperatorImportFromESRIShape) OperatorFactoryLocal.getInstance().getOperator(Type.ImportFromESRIShape); - } + public static OperatorImportFromESRIShape local() { + return (OperatorImportFromESRIShape) OperatorFactoryLocal.getInstance().getOperator(Type.ImportFromESRIShape); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorImportFromESRIShapeCursor.java b/src/main/java/com/esri/core/geometry/OperatorImportFromESRIShapeCursor.java index 2176eeb9..ce7e0cd9 100644 --- a/src/main/java/com/esri/core/geometry/OperatorImportFromESRIShapeCursor.java +++ b/src/main/java/com/esri/core/geometry/OperatorImportFromESRIShapeCursor.java @@ -32,989 +32,993 @@ public class OperatorImportFromESRIShapeCursor extends GeometryCursor { - ByteBufferCursor m_inputShapeBuffers; - int m_importFlags; - int m_type; - - public OperatorImportFromESRIShapeCursor(int importFlags, int type, ByteBufferCursor shapeBuffers) { - if (shapeBuffers == null) - throw new GeometryException("invalid argument"); - - m_importFlags = importFlags; - m_type = type; - m_inputShapeBuffers = shapeBuffers; - } - - @Override - public boolean hasNext() { return m_inputShapeBuffers != null && m_inputShapeBuffers.hasNext(); } - - @Override - public Geometry next() { - ByteBuffer shapeBuffer = m_inputShapeBuffers.next(); - if (shapeBuffer != null) { - return importFromESRIShape(shapeBuffer); - } - return null; - } - - @Override - public SimpleStateEnum getSimpleState() { - return m_inputShapeBuffers.getSimpleState(); - } - - @Override - public String getFeatureID() { return m_inputShapeBuffers.getFeatureID(); } - - @Override - public long getGeometryID() { - return m_inputShapeBuffers.getByteBufferID(); - } - - private Geometry importFromESRIShape(ByteBuffer shapeBuffer) { - ByteOrder initialOrder = shapeBuffer.order(); - shapeBuffer.order(ByteOrder.LITTLE_ENDIAN); - - try { - // read type - int shapetype = shapeBuffer.getInt(0); - - // Extract general type and modifiers - int generaltype; - int modifiers; - switch (shapetype & ShapeModifiers.ShapeBasicTypeMask) { - // Polygon - case ShapeType.ShapePolygon: - generaltype = ShapeType.ShapeGeneralPolygon; - modifiers = 0; - break; - case ShapeType.ShapePolygonZM: - generaltype = ShapeType.ShapeGeneralPolygon; - modifiers = ShapeModifiers.ShapeHasZs | ShapeModifiers.ShapeHasMs; - break; - case ShapeType.ShapePolygonM: - generaltype = ShapeType.ShapeGeneralPolygon; - modifiers = ShapeModifiers.ShapeHasMs; - break; - case ShapeType.ShapePolygonZ: - generaltype = ShapeType.ShapeGeneralPolygon; - modifiers = ShapeModifiers.ShapeHasZs; - break; - case ShapeType.ShapeGeneralPolygon: - generaltype = ShapeType.ShapeGeneralPolygon; - modifiers = shapetype & ShapeModifiers.ShapeModifierMask; - break; - - // Polyline - case ShapeType.ShapePolyline: - generaltype = ShapeType.ShapeGeneralPolyline; - modifiers = 0; - break; - case ShapeType.ShapePolylineZM: - generaltype = ShapeType.ShapeGeneralPolyline; - modifiers = ShapeModifiers.ShapeHasZs - | (int) ShapeModifiers.ShapeHasMs; - break; - case ShapeType.ShapePolylineM: - generaltype = ShapeType.ShapeGeneralPolyline; - modifiers = ShapeModifiers.ShapeHasMs; - break; - case ShapeType.ShapePolylineZ: - generaltype = ShapeType.ShapeGeneralPolyline; - modifiers = ShapeModifiers.ShapeHasZs; - break; - case ShapeType.ShapeGeneralPolyline: - generaltype = ShapeType.ShapeGeneralPolyline; - modifiers = shapetype & ShapeModifiers.ShapeModifierMask; - break; - - // MultiPoint - case ShapeType.ShapeMultiPoint: - generaltype = ShapeType.ShapeGeneralMultiPoint; - modifiers = 0; - break; - case ShapeType.ShapeMultiPointZM: - generaltype = ShapeType.ShapeGeneralMultiPoint; - modifiers = (int) ShapeModifiers.ShapeHasZs - | (int) ShapeModifiers.ShapeHasMs; - break; - case ShapeType.ShapeMultiPointM: - generaltype = ShapeType.ShapeGeneralMultiPoint; - modifiers = ShapeModifiers.ShapeHasMs; - break; - case ShapeType.ShapeMultiPointZ: - generaltype = ShapeType.ShapeGeneralMultiPoint; - modifiers = ShapeModifiers.ShapeHasZs; - break; - case ShapeType.ShapeGeneralMultiPoint: - generaltype = ShapeType.ShapeGeneralMultiPoint; - modifiers = shapetype & ShapeModifiers.ShapeModifierMask; - break; - - // Point - case ShapeType.ShapePoint: - generaltype = ShapeType.ShapeGeneralPoint; - modifiers = 0; - break; - case ShapeType.ShapePointZM: - generaltype = ShapeType.ShapeGeneralPoint; - modifiers = ShapeModifiers.ShapeHasZs - | (int) ShapeModifiers.ShapeHasMs; - break; - case ShapeType.ShapePointM: - generaltype = ShapeType.ShapeGeneralPoint; - modifiers = ShapeModifiers.ShapeHasMs; - break; - case ShapeType.ShapePointZ: - generaltype = ShapeType.ShapeGeneralPoint; - modifiers = ShapeModifiers.ShapeHasZs; - break; - case ShapeType.ShapeGeneralPoint: - generaltype = ShapeType.ShapeGeneralPoint; - modifiers = shapetype & ShapeModifiers.ShapeModifierMask; - break; - - // Null Geometry - case ShapeType.ShapeNull: - return null; - - default: - throw new GeometryException("invalid shape type"); - } - - switch (generaltype) { - case ShapeType.ShapeGeneralPolygon: - if (m_type != Geometry.GeometryType.Polygon - && m_type != Geometry.GeometryType.Unknown - && m_type != Geometry.GeometryType.Envelope) - throw new GeometryException("invalid shape type"); - return importFromESRIShapeMultiPath(true, modifiers, - shapeBuffer); - - case ShapeType.ShapeGeneralPolyline: - if (m_type != Geometry.GeometryType.Polyline - && m_type != Geometry.GeometryType.Unknown - && m_type != Geometry.GeometryType.Envelope) - throw new GeometryException("invalid shape type"); - return importFromESRIShapeMultiPath(false, modifiers, - shapeBuffer); - - case ShapeType.ShapeGeneralMultiPoint: - if (m_type != Geometry.GeometryType.MultiPoint - && m_type != Geometry.GeometryType.Unknown - && m_type != Geometry.GeometryType.Envelope) - throw new GeometryException("invalid shape type"); - return importFromESRIShapeMultiPoint(modifiers, shapeBuffer); - - case ShapeType.ShapeGeneralPoint: - if (m_type != Geometry.GeometryType.Point - && m_type != Geometry.GeometryType.MultiPoint - && m_type != Geometry.GeometryType.Unknown - && m_type != Geometry.GeometryType.Envelope) - throw new GeometryException("invalid shape type"); - return importFromESRIShapePoint(modifiers, shapeBuffer); - } - - return null; - } finally { - shapeBuffer.order(initialOrder); - } - } - - private Geometry importFromESRIShapeMultiPath(boolean bPolygon, - int modifiers, ByteBuffer shapeBuffer) { - int offset = 4; - - boolean bZs = (modifiers & (int) ShapeModifiers.ShapeHasZs) != 0; - boolean bMs = (modifiers & (int) ShapeModifiers.ShapeHasMs) != 0; - boolean bIDs = (modifiers & (int) ShapeModifiers.ShapeHasIDs) != 0; - - boolean bHasAttributes = bZs || bMs || bIDs; - boolean bHasBadRings = false; - - // read Envelope - double xmin = shapeBuffer.getDouble(offset); - offset += 8; - double ymin = shapeBuffer.getDouble(offset); - offset += 8; - double xmax = shapeBuffer.getDouble(offset); - offset += 8; - double ymax = shapeBuffer.getDouble(offset); - offset += 8; - - // read part count - int originalPartCount = shapeBuffer.getInt(offset); - offset += 4; - int partCount = 0; - - // read point count - int pointCount = shapeBuffer.getInt(offset); - offset += 4; - - AttributeStreamOfDbl position = null; - AttributeStreamOfDbl zs = null; - AttributeStreamOfDbl ms = null; - AttributeStreamOfInt32 ids = null; - AttributeStreamOfInt32 parts = null; - AttributeStreamOfInt8 pathFlags = null; - - Envelope bbox = null; - MultiPath multipath = null; - MultiPathImpl multipathImpl = null; - if (m_type == Geometry.GeometryType.Polygon - || m_type == Geometry.GeometryType.Polyline - || m_type == Geometry.GeometryType.Unknown) { - if (bPolygon) - multipath = new Polygon(); - else - multipath = new Polyline(); - - multipathImpl = (MultiPathImpl) multipath._getImpl(); - - if (pointCount > 0) { - bbox = new Envelope(); - bbox.setCoords(xmin, ymin, xmax, ymax); - parts = (AttributeStreamOfInt32) AttributeStreamBase - .createIndexStream(originalPartCount + 1); - - int previstart = -1; - int lastCount = 0; - for (int i = 0; i < originalPartCount; i++) { - int istart = shapeBuffer.getInt(offset); - offset += 4; - lastCount = istart; - if (previstart > istart || istart < 0)// check that the part - // indices in the - // buffer are not - // corrupted - throw new GeometryException("corrupted geometry"); - - if (istart != previstart) { - parts.write(partCount, istart); - previstart = istart; - partCount++; - } - } - - parts.resize(partCount + 1); - if (pointCount < lastCount)// check that the point count in the - // buffer is not corrupted - throw new GeometryException("corrupted geometry"); - - parts.write(partCount, pointCount); - pathFlags = (AttributeStreamOfInt8) AttributeStreamBase - .createByteStream(parts.size(), (byte) 0); - - // Create empty position stream - position = (AttributeStreamOfDbl) AttributeStreamBase - .createAttributeStreamWithSemantics(Semantics.POSITION, - pointCount); - - int startpart = parts.read(0); - // read xy coordinates - int xyindex = 0; - for (int ipart = 0; ipart < partCount; ipart++) { - int endpartActual = parts.read(ipart + 1); - // for polygons we read one point less, then analyze if the - // polygon is closed. - int endpart = (bPolygon) ? endpartActual - 1 - : endpartActual; - - double startx = shapeBuffer.getDouble(offset); - offset += 8; - double starty = shapeBuffer.getDouble(offset); - offset += 8; - position.write(2 * xyindex, startx); - position.write(2 * xyindex + 1, starty); - xyindex++; - - for (int i = startpart + 1; i < endpart; i++) { - double x = shapeBuffer.getDouble(offset); - offset += 8; - double y = shapeBuffer.getDouble(offset); - offset += 8; - position.write(2 * xyindex, x); - position.write(2 * xyindex + 1, y); - xyindex++; - } - - if (endpart - startpart < 2) {// a part with only one point - multipathImpl.setIsSimple(GeometryXSimple.Unknown, 0.0, - false); - } - - if (bPolygon) {// read the last point of the part to decide - // if we need to close the polygon - if (startpart == endpart) {// a part with only one point - parts.write(ipart + 1, xyindex); - } else { - double x = shapeBuffer.getDouble(offset); - offset += 8; - double y = shapeBuffer.getDouble(offset); - offset += 8; - - if (x != startx || y != starty) {// bad polygon. The - // last point is - // not the same - // as the last - // one. We need - // to add it so - // that we do - // not loose it. - position.write(2 * xyindex, x); - position.write(2 * xyindex + 1, y); - xyindex++; - multipathImpl.setIsSimple( - GeometryXSimple.Unknown, 0.0, false); - bHasBadRings = true; - // write part count to indicate we need to - // account for one extra point - // The count will be fixed after the attributes - // are processed. So we write negative only when - // there are attributes. - parts.write(ipart + 1, - bHasAttributes ? -xyindex : xyindex); - } else - parts.write(ipart + 1, xyindex); - } - - pathFlags.setBits(ipart, (byte) PathFlags.enumClosed); - } - - startpart = endpartActual; - } - - if (bZs) - bbox.addAttribute(Semantics.Z); - - if (bMs) - bbox.addAttribute(Semantics.M); - - if (bIDs) - bbox.addAttribute(Semantics.ID); - } - } else { - bbox = new Envelope(); - - if (bZs) - bbox.addAttribute(Semantics.Z); - - if (bMs) - bbox.addAttribute(Semantics.M); - - if (bIDs) - bbox.addAttribute(Semantics.ID); - - if (pointCount > 0) { - bbox.setCoords(xmin, ymin, xmax, ymax); - offset += pointCount * 16 + originalPartCount * 4; - } else - return (Geometry) bbox; - } - - // read Zs - if (bZs) { - if (pointCount > 0) { - double zmin = Interop.translateFromAVNaN(shapeBuffer - .getDouble(offset)); - offset += 8; - double zmax = Interop.translateFromAVNaN(shapeBuffer - .getDouble(offset)); - offset += 8; - - Envelope1D env = new Envelope1D(); - env.setCoords(zmin, zmax); - bbox.setInterval(Semantics.Z, 0, env); - - if (m_type == Geometry.GeometryType.Polygon - || m_type == Geometry.GeometryType.Polyline - || m_type == Geometry.GeometryType.Unknown) { - zs = (AttributeStreamOfDbl) AttributeStreamBase - .createAttributeStreamWithSemantics(Semantics.Z, - pointCount); - - boolean bCreate = false; - int startpart = parts.read(0); - for (int ipart = 0; ipart < partCount; ipart++) { - int endpartActual = parts.read(ipart + 1); - int endpart = Math.abs(endpartActual); - - double startz = Interop.translateFromAVNaN(shapeBuffer - .getDouble(offset)); - offset += 8; - zs.write(startpart, startz); - if (!VertexDescription.isDefaultValue(Semantics.Z, - startz)) - bCreate = true; - - for (int i = startpart + 1; i < endpart; i++) { - double z = Interop.translateFromAVNaN(shapeBuffer - .getDouble(offset)); - offset += 8; - zs.write(i, z); - if (!VertexDescription.isDefaultValue(Semantics.Z, - z)) - bCreate = true; - } - - if (bPolygon && endpartActual > 0) { - offset += 8; - } - - startpart = endpart; - } - - if (!bCreate) - zs = null; - } else - offset += pointCount * 8; - } - - if (m_type == Geometry.GeometryType.Polygon - || m_type == Geometry.GeometryType.Polyline - || m_type == Geometry.GeometryType.Unknown) - multipathImpl.setAttributeStreamRef(Semantics.Z, zs); - } - - // read Ms - if (bMs) { - if (pointCount > 0) { - double mmin = Interop.translateFromAVNaN(shapeBuffer - .getDouble(offset)); - offset += 8; - double mmax = Interop.translateFromAVNaN(shapeBuffer - .getDouble(offset)); - offset += 8; - - Envelope1D env = new Envelope1D(); - env.setCoords(mmin, mmax); - bbox.setInterval(Semantics.M, 0, env); - - if (m_type == Geometry.GeometryType.Polygon - || m_type == Geometry.GeometryType.Polyline - || m_type == Geometry.GeometryType.Unknown) { - ms = (AttributeStreamOfDbl) AttributeStreamBase - .createAttributeStreamWithSemantics(Semantics.M, - pointCount); - - boolean bCreate = false; - int startpart = parts.read(0); - for (int ipart = 0; ipart < partCount; ipart++) { - int endpartActual = parts.read(ipart + 1); - int endpart = Math.abs(endpartActual); - - double startm = Interop.translateFromAVNaN(shapeBuffer - .getDouble(offset)); - offset += 8; - ms.write(startpart, startm); - if (!VertexDescription.isDefaultValue(Semantics.M, - startm)) - bCreate = true; - - for (int i = startpart + 1; i < endpart; i++) { - double m = Interop.translateFromAVNaN(shapeBuffer - .getDouble(offset)); - offset += 8; - ms.write(i, m); - if (!VertexDescription.isDefaultValue(Semantics.M, - m)) - bCreate = true; - } - - if (bPolygon && endpartActual > 0) { - offset += 8; - } - - startpart = endpart; - } - - if (!bCreate) - ms = null; - } else - offset += pointCount * 8; - } - - if (m_type == Geometry.GeometryType.Polygon - || m_type == Geometry.GeometryType.Polyline - || m_type == Geometry.GeometryType.Unknown) - multipathImpl.setAttributeStreamRef(Semantics.M, ms); - } - - // read IDs - if (bIDs) { - if (pointCount > 0) { - double idmin = NumberUtils.doubleMax(); - double idmax = -NumberUtils.doubleMax(); - - if (m_type == Geometry.GeometryType.Polygon - || m_type == Geometry.GeometryType.Polyline - || m_type == Geometry.GeometryType.Unknown) { - ids = (AttributeStreamOfInt32) AttributeStreamBase - .createAttributeStreamWithSemantics(Semantics.ID, - pointCount); - - boolean bCreate = false; - int startpart = parts.read(0); - for (int ipart = 0; ipart < partCount; ipart++) { - int endpartActual = parts.read(ipart + 1); - int endpart = Math.abs(endpartActual); - - int startid = shapeBuffer.getInt(offset); - offset += 4; - ids.write(startpart, startid); - if (!VertexDescription.isDefaultValue(Semantics.ID, - startid)) - bCreate = true; - - for (int i = startpart + 1; i < endpart; i++) { - int id = shapeBuffer.getInt(offset); - offset += 4; - ids.write(i, id); - if (!bCreate - && !VertexDescription.isDefaultValue( - Semantics.ID, id)) - bCreate = true; - - if (idmin > id) - idmin = id; - else if (idmax < id) - idmax = id; - } - - if (bPolygon && endpartActual > 0) { - offset += 4; - } - - startpart = endpart; - } - - if (!bCreate) - ids = null; - } else { - for (int i = 0; i < pointCount; i++) { - int id = shapeBuffer.getInt(offset); - offset += 4; - - if (idmin > id) - idmin = id; - else if (idmax < id) - idmax = id; - } - } - - Envelope1D env = new Envelope1D(); - env.setCoords(idmin, idmax); - bbox.setInterval(Semantics.ID, 0, env); - } - - if (m_type == Geometry.GeometryType.Polygon - || m_type == Geometry.GeometryType.Polyline - || m_type == Geometry.GeometryType.Unknown) - multipathImpl.setAttributeStreamRef(Semantics.ID, ids); - } - - if (bHasBadRings && bHasAttributes) {// revert our hack for bad polygons - for (int ipart = 1; ipart < partCount + 1; ipart++) { - int v = parts.read(ipart); - if (v < 0) - parts.write(ipart, -v); - } - } - - if (m_type == Geometry.GeometryType.Envelope) - return (Geometry) bbox; - - if (pointCount > 0) { - multipathImpl.setPathStreamRef(parts); - multipathImpl.setPathFlagsStreamRef(pathFlags); - multipathImpl.setAttributeStreamRef(Semantics.POSITION, position); - multipathImpl.setEnvelope(bbox); - } - - if ((m_importFlags & ShapeImportFlags.ShapeImportNonTrusted) == 0) - multipathImpl.setIsSimple(GeometryXSimple.Weak, 0.0, false);// We - // use - // tolerance - // of 0. - // What - // should - // we - // instead? - - return (Geometry) multipath; - } - - private Geometry importFromESRIShapeMultiPoint(int modifiers, - ByteBuffer shapeBuffer) { - int offset = 4; - - boolean bZs = (modifiers & (int) ShapeModifiers.ShapeHasZs) != 0; - boolean bMs = (modifiers & (int) ShapeModifiers.ShapeHasMs) != 0; - boolean bIDs = (modifiers & modifiers & (int) ShapeModifiers.ShapeHasIDs) != 0; - - double xmin = shapeBuffer.getDouble(offset); - offset += 8; - double ymin = shapeBuffer.getDouble(offset); - offset += 8; - double xmax = shapeBuffer.getDouble(offset); - offset += 8; - double ymax = shapeBuffer.getDouble(offset); - offset += 8; - - int cPoints = shapeBuffer.getInt(offset); - offset += 4; - - AttributeStreamOfDbl position = null; - AttributeStreamOfDbl zs = null; - AttributeStreamOfDbl ms = null; - AttributeStreamOfInt32 ids = null; - - Envelope bbox = null; - MultiPoint multipoint = null; - MultiPointImpl multipointImpl = null; - - if (m_type == Geometry.GeometryType.MultiPoint - || m_type == Geometry.GeometryType.Unknown) { - multipoint = new MultiPoint(); - multipointImpl = (MultiPointImpl) multipoint._getImpl(); - - if (cPoints > 0) { - bbox = new Envelope(); - multipointImpl.resize(cPoints); - position = (AttributeStreamOfDbl) AttributeStreamBase - .createAttributeStreamWithSemantics(Semantics.POSITION, - cPoints); - - for (int i = 0; i < cPoints; i++) { - double x = shapeBuffer.getDouble(offset); - offset += 8; - double y = shapeBuffer.getDouble(offset); - offset += 8; - position.write(2 * i, x); - position.write(2 * i + 1, y); - } - - multipointImpl.resize(cPoints); - bbox.setCoords(xmin, ymin, xmax, ymax); - - if (bZs) - bbox.addAttribute(Semantics.Z); - - if (bMs) - bbox.addAttribute(Semantics.M); - - if (bIDs) - bbox.addAttribute(Semantics.ID); - } - } else { - bbox = new Envelope(); - - if (bZs) - bbox.addAttribute(Semantics.Z); - - if (bMs) - bbox.addAttribute(Semantics.M); - - if (bIDs) - bbox.addAttribute(Semantics.ID); - - if (cPoints > 0) { - bbox.setCoords(xmin, ymin, xmax, ymax); - offset += cPoints * 16; - } else - return (Geometry) bbox; - } - - if (bZs) { - if (cPoints > 0) { - double zmin = Interop.translateFromAVNaN(shapeBuffer - .getDouble(offset)); - offset += 8; - double zmax = Interop.translateFromAVNaN(shapeBuffer - .getDouble(offset)); - offset += 8; - - Envelope1D env = new Envelope1D(); - env.setCoords(zmin, zmax); - bbox.setInterval(Semantics.Z, 0, env); - - if (m_type == Geometry.GeometryType.MultiPoint - || m_type == Geometry.GeometryType.Unknown) { - zs = (AttributeStreamOfDbl) AttributeStreamBase - .createAttributeStreamWithSemantics(Semantics.Z, - cPoints); - - boolean bCreate = false; - for (int i = 0; i < cPoints; i++) { - double value = Interop.translateFromAVNaN(shapeBuffer - .getDouble(offset)); - offset += 8; - zs.write(i, value); - if (!VertexDescription.isDefaultValue(Semantics.Z, - value)) - bCreate = true; - } - - if (!bCreate) - zs = null; - } else - offset += cPoints * 8; - } - - if (m_type == Geometry.GeometryType.MultiPoint - || m_type == Geometry.GeometryType.Unknown) - multipointImpl.setAttributeStreamRef(Semantics.Z, zs); - } - - if (bMs) { - if (cPoints > 0) { - double mmin = Interop.translateFromAVNaN(shapeBuffer - .getDouble(offset)); - offset += 8; - double mmax = Interop.translateFromAVNaN(shapeBuffer - .getDouble(offset)); - offset += 8; - - Envelope1D env = new Envelope1D(); - env.setCoords(mmin, mmax); - bbox.setInterval(Semantics.M, 0, env); - if (m_type == Geometry.GeometryType.MultiPoint - || m_type == Geometry.GeometryType.Unknown) { - ms = (AttributeStreamOfDbl) AttributeStreamBase - .createAttributeStreamWithSemantics(Semantics.M, - cPoints); - - boolean bCreate = false; - for (int i = 0; i < cPoints; i++) { - double value = Interop.translateFromAVNaN(shapeBuffer - .getDouble(offset)); - offset += 8; - ms.write(i, value); - if (!VertexDescription.isDefaultValue(Semantics.M, - value)) - bCreate = true; - } - - if (!bCreate) - ms = null; - } else - offset += cPoints * 8; - } - - if (m_type == Geometry.GeometryType.MultiPoint - || m_type == Geometry.GeometryType.Unknown) - multipointImpl.setAttributeStreamRef(Semantics.M, ms); - } - - if (bIDs) { - if (cPoints > 0) { - double idmin = NumberUtils.doubleMax(); - double idmax = -NumberUtils.doubleMax(); - - if (m_type == Geometry.GeometryType.MultiPoint - || m_type == Geometry.GeometryType.Unknown) { - ids = (AttributeStreamOfInt32) AttributeStreamBase - .createAttributeStreamWithSemantics(Semantics.ID, - cPoints); - - boolean bCreate = false; - for (int i = 0; i < cPoints; i++) { - int value = shapeBuffer.getInt(offset); - offset += 4; - ids.write(i, value); - if (!VertexDescription.isDefaultValue(Semantics.ID, - value)) - bCreate = true; - - if (idmin > value) - idmin = value; - else if (idmax < value) - idmax = value; - } - - if (!bCreate) - ids = null; - } else { - for (int i = 0; i < cPoints; i++) { - int id = shapeBuffer.getInt(offset); - offset += 4; - - if (idmin > id) - idmin = id; - else if (idmax < id) - idmax = id; - } - } - - Envelope1D env = new Envelope1D(); - env.setCoords(idmin, idmax); - bbox.setInterval(Semantics.ID, 0, env); - } - - if (m_type == Geometry.GeometryType.MultiPoint - || m_type == Geometry.GeometryType.Unknown) - multipointImpl.setAttributeStreamRef(Semantics.ID, ids); - } - - if (m_type == Geometry.GeometryType.Envelope) - return (Geometry) bbox; - - if (cPoints > 0) { - multipointImpl.setAttributeStreamRef(Semantics.POSITION, position); - multipointImpl.setEnvelope(bbox); - } - - return (Geometry) multipoint; - } - - private Geometry importFromESRIShapePoint(int modifiers, - ByteBuffer shapeBuffer) { - int offset = 4; - - boolean bZs = (modifiers & (int) ShapeModifiers.ShapeHasZs) != 0; - boolean bMs = (modifiers & (int) ShapeModifiers.ShapeHasMs) != 0; - boolean bIDs = (modifiers & modifiers & (int) ShapeModifiers.ShapeHasIDs) != 0; - - // read XY - double x = shapeBuffer.getDouble(offset); - offset += 8; - double y = shapeBuffer.getDouble(offset); - offset += 8; - - boolean bEmpty = NumberUtils.isNaN(x); - - double z = NumberUtils.NaN(); - if (bZs) { - z = Interop.translateFromAVNaN(shapeBuffer.getDouble(offset)); - offset += 8; - } - - double m = NumberUtils.NaN(); - if (bMs) { - m = Interop.translateFromAVNaN(shapeBuffer.getDouble(offset)); - offset += 8; - } - - int id = -1; - if (bIDs) { - id = shapeBuffer.getInt(offset); - offset += 4; - } - - if (m_type == Geometry.GeometryType.MultiPoint) { - MultiPoint newmultipoint = new MultiPoint(); - MultiPointImpl multipointImpl = (MultiPointImpl) newmultipoint - ._getImpl(); - - if (!bEmpty) { - AttributeStreamBase newPositionStream = AttributeStreamBase - .createAttributeStreamWithSemantics(Semantics.POSITION, - 1); - AttributeStreamOfDbl position = (AttributeStreamOfDbl) newPositionStream; - position.write(0, x); - position.write(1, y); - - multipointImpl.setAttributeStreamRef(Semantics.POSITION, - newPositionStream); - multipointImpl.resize(1); - } - - if (bZs) { - multipointImpl.addAttribute(Semantics.Z); - if (!bEmpty - && !VertexDescription.isDefaultValue(Semantics.Z, z)) { - AttributeStreamBase newZStream = AttributeStreamBase - .createAttributeStreamWithSemantics(Semantics.Z, 1); - newZStream.writeAsDbl(0, z); - multipointImpl.setAttributeStreamRef(Semantics.Z, - newZStream); - } - } - - if (bMs) { - multipointImpl.addAttribute(Semantics.M); - if (!bEmpty - && !VertexDescription.isDefaultValue(Semantics.M, m)) { - AttributeStreamBase newMStream = AttributeStreamBase - .createAttributeStreamWithSemantics(Semantics.M, 1); - newMStream.writeAsDbl(0, m); - multipointImpl.setAttributeStreamRef(Semantics.M, - newMStream); - } - } - - if (bIDs) { - multipointImpl.addAttribute(Semantics.ID); - if (!bEmpty - && !VertexDescription.isDefaultValue(Semantics.ID, id)) { - AttributeStreamBase newIDStream = AttributeStreamBase - .createAttributeStreamWithSemantics(Semantics.ID, 1); - newIDStream.writeAsInt(0, id); - multipointImpl.setAttributeStreamRef(Semantics.ID, - newIDStream); - } - } - - return (Geometry) newmultipoint; - } else if (m_type == Geometry.GeometryType.Envelope) { - Envelope envelope = new Envelope(); - envelope.setCoords(x, y, x, y); - - if (bZs) { - Envelope1D interval = new Envelope1D(); - interval.vmin = z; - interval.vmax = z; - envelope.addAttribute(Semantics.Z); - envelope.setInterval(Semantics.Z, 0, interval); - } - - if (bMs) { - Envelope1D interval = new Envelope1D(); - interval.vmin = m; - interval.vmax = m; - envelope.addAttribute(Semantics.M); - envelope.setInterval(Semantics.M, 0, interval); - } - - if (bIDs) { - Envelope1D interval = new Envelope1D(); - interval.vmin = id; - interval.vmax = id; - envelope.addAttribute(Semantics.ID); - envelope.setInterval(Semantics.ID, 0, interval); - } - - return (Geometry) envelope; - } - - Point point = new Point(); - - if (!bEmpty) { - point.setX(Interop.translateFromAVNaN(x)); - point.setY(Interop.translateFromAVNaN(y)); - } - - // read Z - if (bZs) { - point.addAttribute(Semantics.Z); - if (!bEmpty) - point.setZ(Interop.translateFromAVNaN(z)); - } - - // read M - if (bMs) { - point.addAttribute(Semantics.M); - if (!bEmpty) - point.setM(Interop.translateFromAVNaN(m)); - } - - // read ID - if (bIDs) { - point.addAttribute(Semantics.ID); - if (!bEmpty) - point.setID(id); - } - - return (Geometry) point; - } + ByteBufferCursor m_inputShapeBuffers; + int m_importFlags; + int m_type; + + public OperatorImportFromESRIShapeCursor(int importFlags, int type, ByteBufferCursor shapeBuffers) { + if (shapeBuffers == null) + throw new GeometryException("invalid argument"); + + m_importFlags = importFlags; + m_type = type; + m_inputShapeBuffers = shapeBuffers; + } + + @Override + public boolean hasNext() { + return m_inputShapeBuffers != null && m_inputShapeBuffers.hasNext(); + } + + @Override + public Geometry next() { + ByteBuffer shapeBuffer = m_inputShapeBuffers.next(); + if (shapeBuffer != null) { + return importFromESRIShape(shapeBuffer); + } + return null; + } + + @Override + public SimpleStateEnum getSimpleState() { + return m_inputShapeBuffers.getSimpleState(); + } + + @Override + public String getFeatureID() { + return m_inputShapeBuffers.getFeatureID(); + } + + @Override + public long getGeometryID() { + return m_inputShapeBuffers.getByteBufferID(); + } + + private Geometry importFromESRIShape(ByteBuffer shapeBuffer) { + ByteOrder initialOrder = shapeBuffer.order(); + shapeBuffer.order(ByteOrder.LITTLE_ENDIAN); + + try { + // read type + int shapetype = shapeBuffer.getInt(0); + + // Extract general type and modifiers + int generaltype; + int modifiers; + switch (shapetype & ShapeModifiers.ShapeBasicTypeMask) { + // Polygon + case ShapeType.ShapePolygon: + generaltype = ShapeType.ShapeGeneralPolygon; + modifiers = 0; + break; + case ShapeType.ShapePolygonZM: + generaltype = ShapeType.ShapeGeneralPolygon; + modifiers = ShapeModifiers.ShapeHasZs | ShapeModifiers.ShapeHasMs; + break; + case ShapeType.ShapePolygonM: + generaltype = ShapeType.ShapeGeneralPolygon; + modifiers = ShapeModifiers.ShapeHasMs; + break; + case ShapeType.ShapePolygonZ: + generaltype = ShapeType.ShapeGeneralPolygon; + modifiers = ShapeModifiers.ShapeHasZs; + break; + case ShapeType.ShapeGeneralPolygon: + generaltype = ShapeType.ShapeGeneralPolygon; + modifiers = shapetype & ShapeModifiers.ShapeModifierMask; + break; + + // Polyline + case ShapeType.ShapePolyline: + generaltype = ShapeType.ShapeGeneralPolyline; + modifiers = 0; + break; + case ShapeType.ShapePolylineZM: + generaltype = ShapeType.ShapeGeneralPolyline; + modifiers = ShapeModifiers.ShapeHasZs + | (int) ShapeModifiers.ShapeHasMs; + break; + case ShapeType.ShapePolylineM: + generaltype = ShapeType.ShapeGeneralPolyline; + modifiers = ShapeModifiers.ShapeHasMs; + break; + case ShapeType.ShapePolylineZ: + generaltype = ShapeType.ShapeGeneralPolyline; + modifiers = ShapeModifiers.ShapeHasZs; + break; + case ShapeType.ShapeGeneralPolyline: + generaltype = ShapeType.ShapeGeneralPolyline; + modifiers = shapetype & ShapeModifiers.ShapeModifierMask; + break; + + // MultiPoint + case ShapeType.ShapeMultiPoint: + generaltype = ShapeType.ShapeGeneralMultiPoint; + modifiers = 0; + break; + case ShapeType.ShapeMultiPointZM: + generaltype = ShapeType.ShapeGeneralMultiPoint; + modifiers = (int) ShapeModifiers.ShapeHasZs + | (int) ShapeModifiers.ShapeHasMs; + break; + case ShapeType.ShapeMultiPointM: + generaltype = ShapeType.ShapeGeneralMultiPoint; + modifiers = ShapeModifiers.ShapeHasMs; + break; + case ShapeType.ShapeMultiPointZ: + generaltype = ShapeType.ShapeGeneralMultiPoint; + modifiers = ShapeModifiers.ShapeHasZs; + break; + case ShapeType.ShapeGeneralMultiPoint: + generaltype = ShapeType.ShapeGeneralMultiPoint; + modifiers = shapetype & ShapeModifiers.ShapeModifierMask; + break; + + // Point + case ShapeType.ShapePoint: + generaltype = ShapeType.ShapeGeneralPoint; + modifiers = 0; + break; + case ShapeType.ShapePointZM: + generaltype = ShapeType.ShapeGeneralPoint; + modifiers = ShapeModifiers.ShapeHasZs + | (int) ShapeModifiers.ShapeHasMs; + break; + case ShapeType.ShapePointM: + generaltype = ShapeType.ShapeGeneralPoint; + modifiers = ShapeModifiers.ShapeHasMs; + break; + case ShapeType.ShapePointZ: + generaltype = ShapeType.ShapeGeneralPoint; + modifiers = ShapeModifiers.ShapeHasZs; + break; + case ShapeType.ShapeGeneralPoint: + generaltype = ShapeType.ShapeGeneralPoint; + modifiers = shapetype & ShapeModifiers.ShapeModifierMask; + break; + + // Null Geometry + case ShapeType.ShapeNull: + return null; + + default: + throw new GeometryException("invalid shape type"); + } + + switch (generaltype) { + case ShapeType.ShapeGeneralPolygon: + if (m_type != Geometry.GeometryType.Polygon + && m_type != Geometry.GeometryType.Unknown + && m_type != Geometry.GeometryType.Envelope) + throw new GeometryException("invalid shape type"); + return importFromESRIShapeMultiPath(true, modifiers, + shapeBuffer); + + case ShapeType.ShapeGeneralPolyline: + if (m_type != Geometry.GeometryType.Polyline + && m_type != Geometry.GeometryType.Unknown + && m_type != Geometry.GeometryType.Envelope) + throw new GeometryException("invalid shape type"); + return importFromESRIShapeMultiPath(false, modifiers, + shapeBuffer); + + case ShapeType.ShapeGeneralMultiPoint: + if (m_type != Geometry.GeometryType.MultiPoint + && m_type != Geometry.GeometryType.Unknown + && m_type != Geometry.GeometryType.Envelope) + throw new GeometryException("invalid shape type"); + return importFromESRIShapeMultiPoint(modifiers, shapeBuffer); + + case ShapeType.ShapeGeneralPoint: + if (m_type != Geometry.GeometryType.Point + && m_type != Geometry.GeometryType.MultiPoint + && m_type != Geometry.GeometryType.Unknown + && m_type != Geometry.GeometryType.Envelope) + throw new GeometryException("invalid shape type"); + return importFromESRIShapePoint(modifiers, shapeBuffer); + } + + return null; + } finally { + shapeBuffer.order(initialOrder); + } + } + + private Geometry importFromESRIShapeMultiPath(boolean bPolygon, + int modifiers, ByteBuffer shapeBuffer) { + int offset = 4; + + boolean bZs = (modifiers & (int) ShapeModifiers.ShapeHasZs) != 0; + boolean bMs = (modifiers & (int) ShapeModifiers.ShapeHasMs) != 0; + boolean bIDs = (modifiers & (int) ShapeModifiers.ShapeHasIDs) != 0; + + boolean bHasAttributes = bZs || bMs || bIDs; + boolean bHasBadRings = false; + + // read Envelope + double xmin = shapeBuffer.getDouble(offset); + offset += 8; + double ymin = shapeBuffer.getDouble(offset); + offset += 8; + double xmax = shapeBuffer.getDouble(offset); + offset += 8; + double ymax = shapeBuffer.getDouble(offset); + offset += 8; + + // read part count + int originalPartCount = shapeBuffer.getInt(offset); + offset += 4; + int partCount = 0; + + // read point count + int pointCount = shapeBuffer.getInt(offset); + offset += 4; + + AttributeStreamOfDbl position = null; + AttributeStreamOfDbl zs = null; + AttributeStreamOfDbl ms = null; + AttributeStreamOfInt32 ids = null; + AttributeStreamOfInt32 parts = null; + AttributeStreamOfInt8 pathFlags = null; + + Envelope bbox = null; + MultiPath multipath = null; + MultiPathImpl multipathImpl = null; + if (m_type == Geometry.GeometryType.Polygon + || m_type == Geometry.GeometryType.Polyline + || m_type == Geometry.GeometryType.Unknown) { + if (bPolygon) + multipath = new Polygon(); + else + multipath = new Polyline(); + + multipathImpl = (MultiPathImpl) multipath._getImpl(); + + if (pointCount > 0) { + bbox = new Envelope(); + bbox.setCoords(xmin, ymin, xmax, ymax); + parts = (AttributeStreamOfInt32) AttributeStreamBase + .createIndexStream(originalPartCount + 1); + + int previstart = -1; + int lastCount = 0; + for (int i = 0; i < originalPartCount; i++) { + int istart = shapeBuffer.getInt(offset); + offset += 4; + lastCount = istart; + if (previstart > istart || istart < 0)// check that the part + // indices in the + // buffer are not + // corrupted + throw new GeometryException("corrupted geometry"); + + if (istart != previstart) { + parts.write(partCount, istart); + previstart = istart; + partCount++; + } + } + + parts.resize(partCount + 1); + if (pointCount < lastCount)// check that the point count in the + // buffer is not corrupted + throw new GeometryException("corrupted geometry"); + + parts.write(partCount, pointCount); + pathFlags = (AttributeStreamOfInt8) AttributeStreamBase + .createByteStream(parts.size(), (byte) 0); + + // Create empty position stream + position = (AttributeStreamOfDbl) AttributeStreamBase + .createAttributeStreamWithSemantics(Semantics.POSITION, + pointCount); + + int startpart = parts.read(0); + // read xy coordinates + int xyindex = 0; + for (int ipart = 0; ipart < partCount; ipart++) { + int endpartActual = parts.read(ipart + 1); + // for polygons we read one point less, then analyze if the + // polygon is closed. + int endpart = (bPolygon) ? endpartActual - 1 + : endpartActual; + + double startx = shapeBuffer.getDouble(offset); + offset += 8; + double starty = shapeBuffer.getDouble(offset); + offset += 8; + position.write(2 * xyindex, startx); + position.write(2 * xyindex + 1, starty); + xyindex++; + + for (int i = startpart + 1; i < endpart; i++) { + double x = shapeBuffer.getDouble(offset); + offset += 8; + double y = shapeBuffer.getDouble(offset); + offset += 8; + position.write(2 * xyindex, x); + position.write(2 * xyindex + 1, y); + xyindex++; + } + + if (endpart - startpart < 2) {// a part with only one point + multipathImpl.setIsSimple(GeometryXSimple.Unknown, 0.0, + false); + } + + if (bPolygon) {// read the last point of the part to decide + // if we need to close the polygon + if (startpart == endpart) {// a part with only one point + parts.write(ipart + 1, xyindex); + } else { + double x = shapeBuffer.getDouble(offset); + offset += 8; + double y = shapeBuffer.getDouble(offset); + offset += 8; + + if (x != startx || y != starty) {// bad polygon. The + // last point is + // not the same + // as the last + // one. We need + // to add it so + // that we do + // not loose it. + position.write(2 * xyindex, x); + position.write(2 * xyindex + 1, y); + xyindex++; + multipathImpl.setIsSimple( + GeometryXSimple.Unknown, 0.0, false); + bHasBadRings = true; + // write part count to indicate we need to + // account for one extra point + // The count will be fixed after the attributes + // are processed. So we write negative only when + // there are attributes. + parts.write(ipart + 1, + bHasAttributes ? -xyindex : xyindex); + } else + parts.write(ipart + 1, xyindex); + } + + pathFlags.setBits(ipart, (byte) PathFlags.enumClosed); + } + + startpart = endpartActual; + } + + if (bZs) + bbox.addAttribute(Semantics.Z); + + if (bMs) + bbox.addAttribute(Semantics.M); + + if (bIDs) + bbox.addAttribute(Semantics.ID); + } + } else { + bbox = new Envelope(); + + if (bZs) + bbox.addAttribute(Semantics.Z); + + if (bMs) + bbox.addAttribute(Semantics.M); + + if (bIDs) + bbox.addAttribute(Semantics.ID); + + if (pointCount > 0) { + bbox.setCoords(xmin, ymin, xmax, ymax); + offset += pointCount * 16 + originalPartCount * 4; + } else + return (Geometry) bbox; + } + + // read Zs + if (bZs) { + if (pointCount > 0) { + double zmin = Interop.translateFromAVNaN(shapeBuffer + .getDouble(offset)); + offset += 8; + double zmax = Interop.translateFromAVNaN(shapeBuffer + .getDouble(offset)); + offset += 8; + + Envelope1D env = new Envelope1D(); + env.setCoords(zmin, zmax); + bbox.setInterval(Semantics.Z, 0, env); + + if (m_type == Geometry.GeometryType.Polygon + || m_type == Geometry.GeometryType.Polyline + || m_type == Geometry.GeometryType.Unknown) { + zs = (AttributeStreamOfDbl) AttributeStreamBase + .createAttributeStreamWithSemantics(Semantics.Z, + pointCount); + + boolean bCreate = false; + int startpart = parts.read(0); + for (int ipart = 0; ipart < partCount; ipart++) { + int endpartActual = parts.read(ipart + 1); + int endpart = Math.abs(endpartActual); + + double startz = Interop.translateFromAVNaN(shapeBuffer + .getDouble(offset)); + offset += 8; + zs.write(startpart, startz); + if (!VertexDescription.isDefaultValue(Semantics.Z, + startz)) + bCreate = true; + + for (int i = startpart + 1; i < endpart; i++) { + double z = Interop.translateFromAVNaN(shapeBuffer + .getDouble(offset)); + offset += 8; + zs.write(i, z); + if (!VertexDescription.isDefaultValue(Semantics.Z, + z)) + bCreate = true; + } + + if (bPolygon && endpartActual > 0) { + offset += 8; + } + + startpart = endpart; + } + + if (!bCreate) + zs = null; + } else + offset += pointCount * 8; + } + + if (m_type == Geometry.GeometryType.Polygon + || m_type == Geometry.GeometryType.Polyline + || m_type == Geometry.GeometryType.Unknown) + multipathImpl.setAttributeStreamRef(Semantics.Z, zs); + } + + // read Ms + if (bMs) { + if (pointCount > 0) { + double mmin = Interop.translateFromAVNaN(shapeBuffer + .getDouble(offset)); + offset += 8; + double mmax = Interop.translateFromAVNaN(shapeBuffer + .getDouble(offset)); + offset += 8; + + Envelope1D env = new Envelope1D(); + env.setCoords(mmin, mmax); + bbox.setInterval(Semantics.M, 0, env); + + if (m_type == Geometry.GeometryType.Polygon + || m_type == Geometry.GeometryType.Polyline + || m_type == Geometry.GeometryType.Unknown) { + ms = (AttributeStreamOfDbl) AttributeStreamBase + .createAttributeStreamWithSemantics(Semantics.M, + pointCount); + + boolean bCreate = false; + int startpart = parts.read(0); + for (int ipart = 0; ipart < partCount; ipart++) { + int endpartActual = parts.read(ipart + 1); + int endpart = Math.abs(endpartActual); + + double startm = Interop.translateFromAVNaN(shapeBuffer + .getDouble(offset)); + offset += 8; + ms.write(startpart, startm); + if (!VertexDescription.isDefaultValue(Semantics.M, + startm)) + bCreate = true; + + for (int i = startpart + 1; i < endpart; i++) { + double m = Interop.translateFromAVNaN(shapeBuffer + .getDouble(offset)); + offset += 8; + ms.write(i, m); + if (!VertexDescription.isDefaultValue(Semantics.M, + m)) + bCreate = true; + } + + if (bPolygon && endpartActual > 0) { + offset += 8; + } + + startpart = endpart; + } + + if (!bCreate) + ms = null; + } else + offset += pointCount * 8; + } + + if (m_type == Geometry.GeometryType.Polygon + || m_type == Geometry.GeometryType.Polyline + || m_type == Geometry.GeometryType.Unknown) + multipathImpl.setAttributeStreamRef(Semantics.M, ms); + } + + // read IDs + if (bIDs) { + if (pointCount > 0) { + double idmin = NumberUtils.doubleMax(); + double idmax = -NumberUtils.doubleMax(); + + if (m_type == Geometry.GeometryType.Polygon + || m_type == Geometry.GeometryType.Polyline + || m_type == Geometry.GeometryType.Unknown) { + ids = (AttributeStreamOfInt32) AttributeStreamBase + .createAttributeStreamWithSemantics(Semantics.ID, + pointCount); + + boolean bCreate = false; + int startpart = parts.read(0); + for (int ipart = 0; ipart < partCount; ipart++) { + int endpartActual = parts.read(ipart + 1); + int endpart = Math.abs(endpartActual); + + int startid = shapeBuffer.getInt(offset); + offset += 4; + ids.write(startpart, startid); + if (!VertexDescription.isDefaultValue(Semantics.ID, + startid)) + bCreate = true; + + for (int i = startpart + 1; i < endpart; i++) { + int id = shapeBuffer.getInt(offset); + offset += 4; + ids.write(i, id); + if (!bCreate + && !VertexDescription.isDefaultValue( + Semantics.ID, id)) + bCreate = true; + + if (idmin > id) + idmin = id; + else if (idmax < id) + idmax = id; + } + + if (bPolygon && endpartActual > 0) { + offset += 4; + } + + startpart = endpart; + } + + if (!bCreate) + ids = null; + } else { + for (int i = 0; i < pointCount; i++) { + int id = shapeBuffer.getInt(offset); + offset += 4; + + if (idmin > id) + idmin = id; + else if (idmax < id) + idmax = id; + } + } + + Envelope1D env = new Envelope1D(); + env.setCoords(idmin, idmax); + bbox.setInterval(Semantics.ID, 0, env); + } + + if (m_type == Geometry.GeometryType.Polygon + || m_type == Geometry.GeometryType.Polyline + || m_type == Geometry.GeometryType.Unknown) + multipathImpl.setAttributeStreamRef(Semantics.ID, ids); + } + + if (bHasBadRings && bHasAttributes) {// revert our hack for bad polygons + for (int ipart = 1; ipart < partCount + 1; ipart++) { + int v = parts.read(ipart); + if (v < 0) + parts.write(ipart, -v); + } + } + + if (m_type == Geometry.GeometryType.Envelope) + return (Geometry) bbox; + + if (pointCount > 0) { + multipathImpl.setPathStreamRef(parts); + multipathImpl.setPathFlagsStreamRef(pathFlags); + multipathImpl.setAttributeStreamRef(Semantics.POSITION, position); + multipathImpl.setEnvelope(bbox); + } + + if ((m_importFlags & ShapeImportFlags.ShapeImportNonTrusted) == 0) + multipathImpl.setIsSimple(GeometryXSimple.Weak, 0.0, false);// We + // use + // tolerance + // of 0. + // What + // should + // we + // instead? + + return (Geometry) multipath; + } + + private Geometry importFromESRIShapeMultiPoint(int modifiers, + ByteBuffer shapeBuffer) { + int offset = 4; + + boolean bZs = (modifiers & (int) ShapeModifiers.ShapeHasZs) != 0; + boolean bMs = (modifiers & (int) ShapeModifiers.ShapeHasMs) != 0; + boolean bIDs = (modifiers & modifiers & (int) ShapeModifiers.ShapeHasIDs) != 0; + + double xmin = shapeBuffer.getDouble(offset); + offset += 8; + double ymin = shapeBuffer.getDouble(offset); + offset += 8; + double xmax = shapeBuffer.getDouble(offset); + offset += 8; + double ymax = shapeBuffer.getDouble(offset); + offset += 8; + + int cPoints = shapeBuffer.getInt(offset); + offset += 4; + + AttributeStreamOfDbl position = null; + AttributeStreamOfDbl zs = null; + AttributeStreamOfDbl ms = null; + AttributeStreamOfInt32 ids = null; + + Envelope bbox = null; + MultiPoint multipoint = null; + MultiPointImpl multipointImpl = null; + + if (m_type == Geometry.GeometryType.MultiPoint + || m_type == Geometry.GeometryType.Unknown) { + multipoint = new MultiPoint(); + multipointImpl = (MultiPointImpl) multipoint._getImpl(); + + if (cPoints > 0) { + bbox = new Envelope(); + multipointImpl.resize(cPoints); + position = (AttributeStreamOfDbl) AttributeStreamBase + .createAttributeStreamWithSemantics(Semantics.POSITION, + cPoints); + + for (int i = 0; i < cPoints; i++) { + double x = shapeBuffer.getDouble(offset); + offset += 8; + double y = shapeBuffer.getDouble(offset); + offset += 8; + position.write(2 * i, x); + position.write(2 * i + 1, y); + } + + multipointImpl.resize(cPoints); + bbox.setCoords(xmin, ymin, xmax, ymax); + + if (bZs) + bbox.addAttribute(Semantics.Z); + + if (bMs) + bbox.addAttribute(Semantics.M); + + if (bIDs) + bbox.addAttribute(Semantics.ID); + } + } else { + bbox = new Envelope(); + + if (bZs) + bbox.addAttribute(Semantics.Z); + + if (bMs) + bbox.addAttribute(Semantics.M); + + if (bIDs) + bbox.addAttribute(Semantics.ID); + + if (cPoints > 0) { + bbox.setCoords(xmin, ymin, xmax, ymax); + offset += cPoints * 16; + } else + return (Geometry) bbox; + } + + if (bZs) { + if (cPoints > 0) { + double zmin = Interop.translateFromAVNaN(shapeBuffer + .getDouble(offset)); + offset += 8; + double zmax = Interop.translateFromAVNaN(shapeBuffer + .getDouble(offset)); + offset += 8; + + Envelope1D env = new Envelope1D(); + env.setCoords(zmin, zmax); + bbox.setInterval(Semantics.Z, 0, env); + + if (m_type == Geometry.GeometryType.MultiPoint + || m_type == Geometry.GeometryType.Unknown) { + zs = (AttributeStreamOfDbl) AttributeStreamBase + .createAttributeStreamWithSemantics(Semantics.Z, + cPoints); + + boolean bCreate = false; + for (int i = 0; i < cPoints; i++) { + double value = Interop.translateFromAVNaN(shapeBuffer + .getDouble(offset)); + offset += 8; + zs.write(i, value); + if (!VertexDescription.isDefaultValue(Semantics.Z, + value)) + bCreate = true; + } + + if (!bCreate) + zs = null; + } else + offset += cPoints * 8; + } + + if (m_type == Geometry.GeometryType.MultiPoint + || m_type == Geometry.GeometryType.Unknown) + multipointImpl.setAttributeStreamRef(Semantics.Z, zs); + } + + if (bMs) { + if (cPoints > 0) { + double mmin = Interop.translateFromAVNaN(shapeBuffer + .getDouble(offset)); + offset += 8; + double mmax = Interop.translateFromAVNaN(shapeBuffer + .getDouble(offset)); + offset += 8; + + Envelope1D env = new Envelope1D(); + env.setCoords(mmin, mmax); + bbox.setInterval(Semantics.M, 0, env); + if (m_type == Geometry.GeometryType.MultiPoint + || m_type == Geometry.GeometryType.Unknown) { + ms = (AttributeStreamOfDbl) AttributeStreamBase + .createAttributeStreamWithSemantics(Semantics.M, + cPoints); + + boolean bCreate = false; + for (int i = 0; i < cPoints; i++) { + double value = Interop.translateFromAVNaN(shapeBuffer + .getDouble(offset)); + offset += 8; + ms.write(i, value); + if (!VertexDescription.isDefaultValue(Semantics.M, + value)) + bCreate = true; + } + + if (!bCreate) + ms = null; + } else + offset += cPoints * 8; + } + + if (m_type == Geometry.GeometryType.MultiPoint + || m_type == Geometry.GeometryType.Unknown) + multipointImpl.setAttributeStreamRef(Semantics.M, ms); + } + + if (bIDs) { + if (cPoints > 0) { + double idmin = NumberUtils.doubleMax(); + double idmax = -NumberUtils.doubleMax(); + + if (m_type == Geometry.GeometryType.MultiPoint + || m_type == Geometry.GeometryType.Unknown) { + ids = (AttributeStreamOfInt32) AttributeStreamBase + .createAttributeStreamWithSemantics(Semantics.ID, + cPoints); + + boolean bCreate = false; + for (int i = 0; i < cPoints; i++) { + int value = shapeBuffer.getInt(offset); + offset += 4; + ids.write(i, value); + if (!VertexDescription.isDefaultValue(Semantics.ID, + value)) + bCreate = true; + + if (idmin > value) + idmin = value; + else if (idmax < value) + idmax = value; + } + + if (!bCreate) + ids = null; + } else { + for (int i = 0; i < cPoints; i++) { + int id = shapeBuffer.getInt(offset); + offset += 4; + + if (idmin > id) + idmin = id; + else if (idmax < id) + idmax = id; + } + } + + Envelope1D env = new Envelope1D(); + env.setCoords(idmin, idmax); + bbox.setInterval(Semantics.ID, 0, env); + } + + if (m_type == Geometry.GeometryType.MultiPoint + || m_type == Geometry.GeometryType.Unknown) + multipointImpl.setAttributeStreamRef(Semantics.ID, ids); + } + + if (m_type == Geometry.GeometryType.Envelope) + return (Geometry) bbox; + + if (cPoints > 0) { + multipointImpl.setAttributeStreamRef(Semantics.POSITION, position); + multipointImpl.setEnvelope(bbox); + } + + return (Geometry) multipoint; + } + + private Geometry importFromESRIShapePoint(int modifiers, + ByteBuffer shapeBuffer) { + int offset = 4; + + boolean bZs = (modifiers & (int) ShapeModifiers.ShapeHasZs) != 0; + boolean bMs = (modifiers & (int) ShapeModifiers.ShapeHasMs) != 0; + boolean bIDs = (modifiers & modifiers & (int) ShapeModifiers.ShapeHasIDs) != 0; + + // read XY + double x = shapeBuffer.getDouble(offset); + offset += 8; + double y = shapeBuffer.getDouble(offset); + offset += 8; + + boolean bEmpty = NumberUtils.isNaN(x); + + double z = NumberUtils.NaN(); + if (bZs) { + z = Interop.translateFromAVNaN(shapeBuffer.getDouble(offset)); + offset += 8; + } + + double m = NumberUtils.NaN(); + if (bMs) { + m = Interop.translateFromAVNaN(shapeBuffer.getDouble(offset)); + offset += 8; + } + + int id = -1; + if (bIDs) { + id = shapeBuffer.getInt(offset); + offset += 4; + } + + if (m_type == Geometry.GeometryType.MultiPoint) { + MultiPoint newmultipoint = new MultiPoint(); + MultiPointImpl multipointImpl = (MultiPointImpl) newmultipoint + ._getImpl(); + + if (!bEmpty) { + AttributeStreamBase newPositionStream = AttributeStreamBase + .createAttributeStreamWithSemantics(Semantics.POSITION, + 1); + AttributeStreamOfDbl position = (AttributeStreamOfDbl) newPositionStream; + position.write(0, x); + position.write(1, y); + + multipointImpl.setAttributeStreamRef(Semantics.POSITION, + newPositionStream); + multipointImpl.resize(1); + } + + if (bZs) { + multipointImpl.addAttribute(Semantics.Z); + if (!bEmpty + && !VertexDescription.isDefaultValue(Semantics.Z, z)) { + AttributeStreamBase newZStream = AttributeStreamBase + .createAttributeStreamWithSemantics(Semantics.Z, 1); + newZStream.writeAsDbl(0, z); + multipointImpl.setAttributeStreamRef(Semantics.Z, + newZStream); + } + } + + if (bMs) { + multipointImpl.addAttribute(Semantics.M); + if (!bEmpty + && !VertexDescription.isDefaultValue(Semantics.M, m)) { + AttributeStreamBase newMStream = AttributeStreamBase + .createAttributeStreamWithSemantics(Semantics.M, 1); + newMStream.writeAsDbl(0, m); + multipointImpl.setAttributeStreamRef(Semantics.M, + newMStream); + } + } + + if (bIDs) { + multipointImpl.addAttribute(Semantics.ID); + if (!bEmpty + && !VertexDescription.isDefaultValue(Semantics.ID, id)) { + AttributeStreamBase newIDStream = AttributeStreamBase + .createAttributeStreamWithSemantics(Semantics.ID, 1); + newIDStream.writeAsInt(0, id); + multipointImpl.setAttributeStreamRef(Semantics.ID, + newIDStream); + } + } + + return (Geometry) newmultipoint; + } else if (m_type == Geometry.GeometryType.Envelope) { + Envelope envelope = new Envelope(); + envelope.setCoords(x, y, x, y); + + if (bZs) { + Envelope1D interval = new Envelope1D(); + interval.vmin = z; + interval.vmax = z; + envelope.addAttribute(Semantics.Z); + envelope.setInterval(Semantics.Z, 0, interval); + } + + if (bMs) { + Envelope1D interval = new Envelope1D(); + interval.vmin = m; + interval.vmax = m; + envelope.addAttribute(Semantics.M); + envelope.setInterval(Semantics.M, 0, interval); + } + + if (bIDs) { + Envelope1D interval = new Envelope1D(); + interval.vmin = id; + interval.vmax = id; + envelope.addAttribute(Semantics.ID); + envelope.setInterval(Semantics.ID, 0, interval); + } + + return (Geometry) envelope; + } + + Point point = new Point(); + + if (!bEmpty) { + point.setX(Interop.translateFromAVNaN(x)); + point.setY(Interop.translateFromAVNaN(y)); + } + + // read Z + if (bZs) { + point.addAttribute(Semantics.Z); + if (!bEmpty) + point.setZ(Interop.translateFromAVNaN(z)); + } + + // read M + if (bMs) { + point.addAttribute(Semantics.M); + if (!bEmpty) + point.setM(Interop.translateFromAVNaN(m)); + } + + // read ID + if (bIDs) { + point.addAttribute(Semantics.ID); + if (!bEmpty) + point.setID(id); + } + + return (Geometry) point; + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorImportFromESRIShapeLocal.java b/src/main/java/com/esri/core/geometry/OperatorImportFromESRIShapeLocal.java index 496e0605..ed7f959c 100644 --- a/src/main/java/com/esri/core/geometry/OperatorImportFromESRIShapeLocal.java +++ b/src/main/java/com/esri/core/geometry/OperatorImportFromESRIShapeLocal.java @@ -31,16 +31,16 @@ */ class OperatorImportFromESRIShapeLocal extends OperatorImportFromESRIShape { - @Override - public GeometryCursor execute(int importFlags, Geometry.Type type, ByteBufferCursor shapeBuffers) { - return new OperatorImportFromESRIShapeCursor(importFlags, type.value(), shapeBuffers); - } - - @Override - public Geometry execute(int importFlags, Geometry.Type type, ByteBuffer shapeBuffer) { - SimpleByteBufferCursor byteBufferCursor = new SimpleByteBufferCursor(shapeBuffer); - GeometryCursor geometryCursor = execute(importFlags, type, byteBufferCursor); - - return geometryCursor.next(); - } + @Override + public GeometryCursor execute(int importFlags, Geometry.Type type, ByteBufferCursor shapeBuffers) { + return new OperatorImportFromESRIShapeCursor(importFlags, type.value(), shapeBuffers); + } + + @Override + public Geometry execute(int importFlags, Geometry.Type type, ByteBuffer shapeBuffer) { + SimpleByteBufferCursor byteBufferCursor = new SimpleByteBufferCursor(shapeBuffer); + GeometryCursor geometryCursor = execute(importFlags, type, byteBufferCursor); + + return geometryCursor.next(); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorImportFromGeoJson.java b/src/main/java/com/esri/core/geometry/OperatorImportFromGeoJson.java index 2eb37f61..d40a2373 100644 --- a/src/main/java/com/esri/core/geometry/OperatorImportFromGeoJson.java +++ b/src/main/java/com/esri/core/geometry/OperatorImportFromGeoJson.java @@ -25,48 +25,48 @@ public abstract class OperatorImportFromGeoJson extends Operator { - @Override - public Type getType() { - return Type.ImportFromGeoJson; - } + @Override + public Type getType() { + return Type.ImportFromGeoJson; + } - // TODO, this was never implemented. Maybe remove? + // TODO, this was never implemented. Maybe remove? // abstract MapGeometryCursor execute(int import_flags, String geoJsonString, ProgressTracker progressTracker); - abstract MapGeometryCursor execute(int import_flags, StringCursor stringCursor, ProgressTracker progressTracker); + abstract MapGeometryCursor execute(int import_flags, StringCursor stringCursor, ProgressTracker progressTracker); - /** - * Performs the ImportFromGeoJson operation. - * - * @param type Use the {@link Geometry.Type} enum. - * @param jsonObject The JSONObject holding the geometry and spatial reference. - * @return Returns the imported MapGeometry. - * @throws JsonGeometryException - */ - public abstract MapGeometry execute(int importFlags, Geometry.Type type, JsonReader jsonReader, ProgressTracker progressTracker); + /** + * Performs the ImportFromGeoJson operation. + * + * @param type Use the {@link Geometry.Type} enum. + * @param jsonObject The JSONObject holding the geometry and spatial reference. + * @return Returns the imported MapGeometry. + * @throws JsonGeometryException + */ + public abstract MapGeometry execute(int importFlags, Geometry.Type type, JsonReader jsonReader, ProgressTracker progressTracker); - /** - * Deprecated, use version without import_flags. - *

- * Performs the ImportFromGeoJson operation. - * - * @param import_flags Use the {@link GeoJsonImportFlags} interface. - * @param type Use the {@link Geometry.Type} enum. - * @param geoJsonString The string holding the Geometry in geoJson format. - * @return Returns the imported MapGeometry. - */ - public abstract MapGeometry execute(int import_flags, Geometry.Type type, String geoJsonString, ProgressTracker progress_tracker); + /** + * Deprecated, use version without import_flags. + *

+ * Performs the ImportFromGeoJson operation. + * + * @param import_flags Use the {@link GeoJsonImportFlags} interface. + * @param type Use the {@link Geometry.Type} enum. + * @param geoJsonString The string holding the Geometry in geoJson format. + * @return Returns the imported MapGeometry. + */ + public abstract MapGeometry execute(int import_flags, Geometry.Type type, String geoJsonString, ProgressTracker progress_tracker); - /** - * Performs the ImportFromGeoJson operation. - * - * @param import_flags Use the {@link GeoJsonImportFlags} interface. - * @param geoJsonString The string holding the Geometry in geoJson format. - * @return Returns the imported MapOGCStructure. - */ - public abstract MapOGCStructure executeOGC(int import_flags, String geoJsonString, ProgressTracker progress_tracker); + /** + * Performs the ImportFromGeoJson operation. + * + * @param import_flags Use the {@link GeoJsonImportFlags} interface. + * @param geoJsonString The string holding the Geometry in geoJson format. + * @return Returns the imported MapOGCStructure. + */ + public abstract MapOGCStructure executeOGC(int import_flags, String geoJsonString, ProgressTracker progress_tracker); - public static OperatorImportFromGeoJson local() { - return (OperatorImportFromGeoJson) OperatorFactoryLocal.getInstance().getOperator(Type.ImportFromGeoJson); - } + public static OperatorImportFromGeoJson local() { + return (OperatorImportFromGeoJson) OperatorFactoryLocal.getInstance().getOperator(Type.ImportFromGeoJson); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorImportFromGeoJsonCursor.java b/src/main/java/com/esri/core/geometry/OperatorImportFromGeoJsonCursor.java index 17b4de98..152c7b4d 100644 --- a/src/main/java/com/esri/core/geometry/OperatorImportFromGeoJsonCursor.java +++ b/src/main/java/com/esri/core/geometry/OperatorImportFromGeoJsonCursor.java @@ -1,11 +1,11 @@ package com.esri.core.geometry; public class OperatorImportFromGeoJsonCursor extends MapGeometryCursor { - StringCursor m_jsonStringCursor; - int m_import_flags; - int m_count; + StringCursor m_jsonStringCursor; + int m_import_flags; + int m_count; - // TODO, this was never implemented. Maybe remove? + // TODO, this was never implemented. Maybe remove? // public OperatorImportFromGeoJsonCursor(int import_flags, String geoJsonString, ProgressTracker progressTracker) { // m_geoJsonString = geoJsonString; // m_import_flags = import_flags; @@ -13,35 +13,39 @@ public class OperatorImportFromGeoJsonCursor extends MapGeometryCursor { // m_count = 1; // } - public OperatorImportFromGeoJsonCursor(int import_flags, StringCursor stringCursor, ProgressTracker progressTracker) { - m_jsonStringCursor = stringCursor; - m_import_flags = import_flags; - m_count = 1; - } - - @Override - public MapGeometry next() { - String nextString; - if ((nextString = m_jsonStringCursor.next()) != null) { - JsonReader jsonReader = JsonParserReader.createFromString(nextString); - return OperatorImportFromGeoJsonLocal.OperatorImportFromGeoJsonHelper.importFromGeoJson(m_import_flags, Geometry.Type.Unknown, jsonReader, null, false); - } - return null; - } - - @Override - public SimpleStateEnum getSimpleState() { return m_jsonStringCursor.getSimpleState(); } - - @Override - public String getFeatureID() { return m_jsonStringCursor.getFeatureID(); } - - @Override - public long getGeometryID() { - return m_jsonStringCursor.getID(); - } - - @Override - public boolean hasNext() { - return m_jsonStringCursor != null && m_jsonStringCursor.hasNext(); - } + public OperatorImportFromGeoJsonCursor(int import_flags, StringCursor stringCursor, ProgressTracker progressTracker) { + m_jsonStringCursor = stringCursor; + m_import_flags = import_flags; + m_count = 1; + } + + @Override + public MapGeometry next() { + String nextString; + if ((nextString = m_jsonStringCursor.next()) != null) { + JsonReader jsonReader = JsonParserReader.createFromString(nextString); + return OperatorImportFromGeoJsonLocal.OperatorImportFromGeoJsonHelper.importFromGeoJson(m_import_flags, Geometry.Type.Unknown, jsonReader, null, false); + } + return null; + } + + @Override + public SimpleStateEnum getSimpleState() { + return m_jsonStringCursor.getSimpleState(); + } + + @Override + public String getFeatureID() { + return m_jsonStringCursor.getFeatureID(); + } + + @Override + public long getGeometryID() { + return m_jsonStringCursor.getID(); + } + + @Override + public boolean hasNext() { + return m_jsonStringCursor != null && m_jsonStringCursor.hasNext(); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorImportFromGeoJsonLocal.java b/src/main/java/com/esri/core/geometry/OperatorImportFromGeoJsonLocal.java index 2e3c78aa..4df7676b 100644 --- a/src/main/java/com/esri/core/geometry/OperatorImportFromGeoJsonLocal.java +++ b/src/main/java/com/esri/core/geometry/OperatorImportFromGeoJsonLocal.java @@ -28,1305 +28,1305 @@ import java.util.ArrayList; class OperatorImportFromGeoJsonLocal extends OperatorImportFromGeoJson { - static enum GeoJsonType { - Point, LineString, Polygon, MultiPoint, MultiLineString, MultiPolygon, GeometryCollection; - - static GeoJsonType fromGeoJsonValue(int v) { - return GeoJsonType.values()[v - 1]; - } - - public int geogsjonvalue() { - return ordinal() + 1; - } - } - - static interface GeoJsonValues { - public final static int Point = GeoJsonType.Point.geogsjonvalue(); - public final static int LineString = GeoJsonType.LineString.geogsjonvalue(); - public final static int Polygon = GeoJsonType.Polygon.geogsjonvalue(); - public final static int MultiPoint = GeoJsonType.MultiPoint.geogsjonvalue(); - public final static int MultiLineString = GeoJsonType.MultiLineString.geogsjonvalue(); - public final static int MultiPolygon = GeoJsonType.MultiPolygon.geogsjonvalue(); - public final static int GeometryCollection = GeoJsonType.GeometryCollection.geogsjonvalue(); - } - - - // TODO, this was never implemented. Maybe remove? + static enum GeoJsonType { + Point, LineString, Polygon, MultiPoint, MultiLineString, MultiPolygon, GeometryCollection; + + static GeoJsonType fromGeoJsonValue(int v) { + return GeoJsonType.values()[v - 1]; + } + + public int geogsjonvalue() { + return ordinal() + 1; + } + } + + static interface GeoJsonValues { + public final static int Point = GeoJsonType.Point.geogsjonvalue(); + public final static int LineString = GeoJsonType.LineString.geogsjonvalue(); + public final static int Polygon = GeoJsonType.Polygon.geogsjonvalue(); + public final static int MultiPoint = GeoJsonType.MultiPoint.geogsjonvalue(); + public final static int MultiLineString = GeoJsonType.MultiLineString.geogsjonvalue(); + public final static int MultiPolygon = GeoJsonType.MultiPolygon.geogsjonvalue(); + public final static int GeometryCollection = GeoJsonType.GeometryCollection.geogsjonvalue(); + } + + + // TODO, this was never implemented. Maybe remove? // @Override // MapGeometryCursor execute(int import_flags, String geoJsonString, ProgressTracker progressTracker) { // return new OperatorImportFromGeoJsonCursor(import_flags, geoJsonString, progressTracker); // } - @Override - MapGeometryCursor execute(int import_flags, StringCursor stringCursor, ProgressTracker progressTracker) { - return new OperatorImportFromGeoJsonCursor(import_flags, stringCursor, progressTracker); - } - - @Override - public MapGeometry execute(int importFlags, Geometry.Type type, - String geoJsonString, ProgressTracker progressTracker) - throws JsonGeometryException { - MapGeometry map_geometry = OperatorImportFromGeoJsonHelper - .importFromGeoJson(importFlags, type, JsonParserReader.createFromString(geoJsonString), progressTracker, false); - return map_geometry; - } - - @Override - public MapGeometry execute(int importFlags, Geometry.Type type, - JsonReader jsonReader, ProgressTracker progressTracker) - throws JsonGeometryException { - if (jsonReader == null) - return null; - - return OperatorImportFromGeoJsonHelper.importFromGeoJson(importFlags, - type, jsonReader, progressTracker, false); - } - - static final class OperatorImportFromGeoJsonHelper { - - private AttributeStreamOfDbl m_position; - private AttributeStreamOfDbl m_zs; - private AttributeStreamOfDbl m_ms; - private AttributeStreamOfInt32 m_paths; - private AttributeStreamOfInt8 m_path_flags; - private Point m_point; // special case for Points - private boolean m_b_has_zs; - private boolean m_b_has_ms; - private boolean m_b_has_zs_known; - private boolean m_b_has_ms_known; - private int m_num_embeddings; - - int m_ogcType; - - OperatorImportFromGeoJsonHelper() { - m_position = null; - m_zs = null; - m_ms = null; - m_paths = null; - m_path_flags = null; - m_point = null; - m_b_has_zs = false; - m_b_has_ms = false; - m_b_has_zs_known = false; - m_b_has_ms_known = false; - m_num_embeddings = 0; - m_ogcType = 0; - } - - static MapGeometry importFromGeoJson(int importFlags, - Geometry.Type type, JsonReader json_iterator, - ProgressTracker progress_tracker, boolean skip_coordinates) - throws JsonGeometryException { - OperatorImportFromGeoJsonHelper geo_json_helper = new OperatorImportFromGeoJsonHelper(); - MapOGCStructure ms = geo_json_helper.importFromGeoJsonImpl( - importFlags, type, json_iterator, progress_tracker, - skip_coordinates, 0); - - if (geo_json_helper.m_ogcType == GeoJsonValues.GeometryCollection && !skip_coordinates) - throw new JsonGeometryException("parsing error"); - - return new MapGeometry(ms.m_ogcStructure.m_geometry, - ms.m_spatialReference); - } - - static MapOGCStructure importFromGeoJson(int importFlags, - Geometry.Type type, JsonReader json_iterator, - ProgressTracker progress_tracker, boolean skip_coordinates, - int recursion) throws JsonGeometryException { - OperatorImportFromGeoJsonHelper geo_json_helper = new OperatorImportFromGeoJsonHelper(); - MapOGCStructure ms = geo_json_helper.importFromGeoJsonImpl( - importFlags, type, json_iterator, progress_tracker, - skip_coordinates, recursion); - - if (geo_json_helper.m_ogcType == GeoJsonValues.GeometryCollection && !skip_coordinates) - throw new JsonGeometryException("parsing error"); - - return ms; - } - - MapOGCStructure importFromGeoJsonImpl(int importFlags, - Geometry.Type type, JsonReader json_iterator, - ProgressTracker progress_tracker, boolean skip_coordinates, - int recursion) throws JsonGeometryException { - OperatorImportFromGeoJsonHelper geo_json_helper = this; - boolean b_type_found = false; - boolean b_coordinates_found = false; - boolean b_crs_found = false; - boolean b_crsURN_found = false; - boolean b_geometry_collection = false; - boolean b_geometries_found = false; - GeoJsonType geo_json_type = null; - - Geometry geometry = null; - SpatialReference spatial_reference = null; - - JsonReader.Token current_token; - String field_name = null; - MapOGCStructure ms = new MapOGCStructure(); - - while ((current_token = json_iterator.nextToken()) != JsonReader.Token.END_OBJECT) { - field_name = json_iterator.currentString(); - - if (field_name.equals("type")) { - if (b_type_found) { - throw new JsonGeometryException("parsing error"); - } - - b_type_found = true; - current_token = json_iterator.nextToken(); - - if (current_token != JsonReader.Token.VALUE_STRING) { - throw new JsonGeometryException("parsing error"); - } - - String s = json_iterator.currentString(); - try { - geo_json_type = GeoJsonType.valueOf(s); - } catch (Exception ex) { - throw new JsonGeometryException(s); - } - - if (geo_json_type == GeoJsonType.GeometryCollection) { - if (type != Geometry.Type.Unknown) - throw new JsonGeometryException("parsing error"); - - b_geometry_collection = true; - } - } else if (field_name.equals("geometries")) { - b_geometries_found = true; - if (type != Geometry.Type.Unknown) - throw new JsonGeometryException("parsing error"); - - if (recursion > 10) { - throw new JsonGeometryException("deep geojson"); - } - - if (skip_coordinates) { - json_iterator.skipChildren(); - } else { - current_token = json_iterator.nextToken(); - - ms.m_ogcStructure = new OGCStructure(); - ms.m_ogcStructure.m_type = GeoJsonValues.GeometryCollection; - ms.m_ogcStructure.m_structures = new ArrayList( - 0); - - if (current_token == JsonReader.Token.START_ARRAY) { - current_token = json_iterator.nextToken(); - while (current_token != JsonReader.Token.END_ARRAY) { - MapOGCStructure child = importFromGeoJson( - importFlags - | GeoJsonImportFlags.geoJsonImportSkipCRS, - type, json_iterator, - progress_tracker, false, - recursion + 1); - ms.m_ogcStructure.m_structures - .add(child.m_ogcStructure); - - current_token = json_iterator.nextToken(); - } - } else if (current_token != JsonReader.Token.VALUE_NULL) { - throw new JsonGeometryException("parsing error"); - } - } - } else if (field_name.equals("coordinates")) { - - if (b_coordinates_found) { - throw new JsonGeometryException("parsing error"); - } - - b_coordinates_found = true; - current_token = json_iterator.nextToken(); - - if (skip_coordinates) { - json_iterator.skipChildren(); - } else {// According to the spec, the value of the - // coordinates must be an array. However, I do an - // extra check for null too. - if (current_token != JsonReader.Token.VALUE_NULL) { - if (current_token != JsonReader.Token.START_ARRAY) { - throw new JsonGeometryException("parsing error"); - } - - geo_json_helper.import_coordinates_(json_iterator, - progress_tracker); - } - } - } else if (field_name.equals("crs")) { - if (b_crs_found || b_crsURN_found) { - throw new JsonGeometryException("parsing error"); - } - - b_crs_found = true; - current_token = json_iterator.nextToken(); - - if ((importFlags & GeoJsonImportFlags.geoJsonImportSkipCRS) == 0) - spatial_reference = importSpatialReferenceFromCrs( - json_iterator, progress_tracker); - else - json_iterator.skipChildren(); - } else if (field_name.equals("crsURN")) { - if (b_crs_found || b_crsURN_found) { - throw new JsonGeometryException("parsing error"); - } - - b_crsURN_found = true; - current_token = json_iterator.nextToken(); - - spatial_reference = importSpatialReferenceFromCrsUrn_( - json_iterator, progress_tracker); - } else { - json_iterator.nextToken(); - json_iterator.skipChildren(); - } - } - - // According to the spec, a GeoJSON object must have both a type and - // a coordinates array - if (!b_type_found || (!b_geometry_collection && !b_coordinates_found && !skip_coordinates)) { - throw new JsonGeometryException("parsing error"); - } - - if ((!b_geometry_collection && b_geometries_found) || (b_geometry_collection && !b_geometries_found)) { - throw new JsonGeometryException("parsing error");//found "geometries" but did not see "GeometryCollection" - } - - - if (!skip_coordinates && !b_geometry_collection) { - geometry = geo_json_helper.createGeometry_(geo_json_type, - type.value()); - - ms.m_ogcStructure = new OGCStructure(); - ms.m_ogcStructure.m_type = m_ogcType; - ms.m_ogcStructure.m_geometry = geometry; - } - - if (!b_crs_found - && !b_crsURN_found - && ((importFlags & GeoJsonImportFlags.geoJsonImportSkipCRS) == 0) - && ((importFlags & GeoJsonImportFlags.geoJsonImportNoWGS84Default) == 0)) { - spatial_reference = SpatialReference.create(4326); // the spec - // gives a - // default - // of 4326 - // if no crs - // is given - } - - ms.m_spatialReference = spatial_reference; - return ms; - } - - // We have to import the coordinates in the most general way possible to - // not assume the type of geometry we're parsing. - // JSON allows for unordered objects, so it's possible that the - // coordinates array can come before the type tag when parsing - // sequentially, otherwise - // we would have to parse using a JSON_object, which would be easier, - // but not as space/time efficient. So this function blindly imports the - // coordinates - // into the attribute stream(s), and will later assign them to a - // geometry after the type tag is found. - private void import_coordinates_(JsonReader json_iterator, - ProgressTracker progress_tracker) throws JsonGeometryException { - assert (json_iterator.currentToken() == JsonReader.Token.START_ARRAY); - - int coordinates_level_lower = 1; - int coordinates_level_upper = 4; - - json_iterator.nextToken(); - - while (json_iterator.currentToken() != JsonReader.Token.END_ARRAY) { - if (isDouble_(json_iterator)) { - if (coordinates_level_upper > 1) { - coordinates_level_upper = 1; - } - } else if (json_iterator.currentToken() == JsonReader.Token.START_ARRAY) { - if (coordinates_level_lower < 2) { - coordinates_level_lower = 2; - } - } else { - throw new JsonGeometryException("parsing error"); - } - - if (coordinates_level_lower > coordinates_level_upper) { - throw new IllegalArgumentException("invalid argument"); - } - - if (coordinates_level_lower == coordinates_level_upper - && coordinates_level_lower == 1) {// special - // code - // for - // Points - readCoordinateAsPoint_(json_iterator); - } else { - boolean b_add_path_level_3 = true; - boolean b_polygon_start_level_4 = true; - - assert (json_iterator.currentToken() == JsonReader.Token.START_ARRAY); - json_iterator.nextToken(); - - while (json_iterator.currentToken() != JsonReader.Token.END_ARRAY) { - if (isDouble_(json_iterator)) { - if (coordinates_level_upper > 2) { - coordinates_level_upper = 2; - } - } else if (json_iterator.currentToken() == JsonReader.Token.START_ARRAY) { - if (coordinates_level_lower < 3) { - coordinates_level_lower = 3; - } - } else { - throw new JsonGeometryException("parsing error"); - } - - if (coordinates_level_lower > coordinates_level_upper) { - throw new JsonGeometryException("parsing error"); - } - - if (coordinates_level_lower == coordinates_level_upper - && coordinates_level_lower == 2) {// LineString - // or - // MultiPoint - addCoordinate_(json_iterator); - } else { - boolean b_add_path_level_4 = true; - - assert (json_iterator.currentToken() == JsonReader.Token.START_ARRAY); - json_iterator.nextToken(); - - while (json_iterator.currentToken() != JsonReader.Token.END_ARRAY) { - if (isDouble_(json_iterator)) { - if (coordinates_level_upper > 3) { - coordinates_level_upper = 3; - } - } else if (json_iterator.currentToken() == JsonReader.Token.START_ARRAY) { - if (coordinates_level_lower < 4) { - coordinates_level_lower = 4; - } - } else { - throw new JsonGeometryException("parsing error"); - } - - if (coordinates_level_lower > coordinates_level_upper) { - throw new JsonGeometryException("parsing error"); - } - - if (coordinates_level_lower == coordinates_level_upper - && coordinates_level_lower == 3) {// Polygon - // or - // MultiLineString - if (b_add_path_level_3) { - addPath_(); - b_add_path_level_3 = false; - } - - addCoordinate_(json_iterator); - } else { - assert (json_iterator.currentToken() == JsonReader.Token.START_ARRAY); - json_iterator.nextToken(); - - if (json_iterator.currentToken() != JsonReader.Token.END_ARRAY) { - if (!isDouble_(json_iterator)) { - throw new JsonGeometryException("parsing error"); - } - - assert (coordinates_level_lower == coordinates_level_upper && coordinates_level_lower == 4); - // MultiPolygon - - if (b_add_path_level_4) { - addPath_(); - addPathFlag_(b_polygon_start_level_4); - b_add_path_level_4 = false; - b_polygon_start_level_4 = false; - } - - addCoordinate_(json_iterator); - } - - json_iterator.nextToken(); - } - } - - json_iterator.nextToken(); - } - } - - json_iterator.nextToken(); - } - } - - if (m_paths != null) { - m_paths.add(m_position.size() / 2); // add final path size - } - if (m_path_flags != null) { - m_path_flags.add((byte) 0); // to match the paths size - } - - m_num_embeddings = coordinates_level_lower; - } - - private void readCoordinateAsPoint_(JsonReader json_iterator) - throws JsonGeometryException { - assert (isDouble_(json_iterator)); - - m_point = new Point(); - - double x = readDouble_(json_iterator); - json_iterator.nextToken(); - double y = readDouble_(json_iterator); - json_iterator.nextToken(); - - if (NumberUtils.isNaN(y)) { - x = NumberUtils.NaN(); - } - - m_point.setXY(x, y); - - if (isDouble_(json_iterator)) { - double z = readDouble_(json_iterator); - json_iterator.nextToken(); - m_point.setZ(z); - } - - if (isDouble_(json_iterator)) { - double m = readDouble_(json_iterator); - json_iterator.nextToken(); - m_point.setM(m); - } - - if (json_iterator.currentToken() != JsonReader.Token.END_ARRAY) { - throw new JsonGeometryException("parsing error"); - } - } - - private void addCoordinate_(JsonReader json_iterator) - throws JsonGeometryException { - assert (isDouble_(json_iterator)); - - if (m_position == null) { - m_position = (AttributeStreamOfDbl) AttributeStreamBase - .createDoubleStream(0); - } - - double x = readDouble_(json_iterator); - json_iterator.nextToken(); - double y = readDouble_(json_iterator); - json_iterator.nextToken(); - - int size = m_position.size(); - - m_position.add(x); - m_position.add(y); - - if (isDouble_(json_iterator)) { - if (!m_b_has_zs_known) { - m_b_has_zs_known = true; - m_b_has_zs = true; - m_zs = (AttributeStreamOfDbl) AttributeStreamBase - .createDoubleStream(0); - } else { - if (!m_b_has_zs) { - m_zs = (AttributeStreamOfDbl) AttributeStreamBase - .createDoubleStream(size >> 1, - VertexDescription - .getDefaultValue(Semantics.Z)); - m_b_has_zs = true; - } - } - - double z = readDouble_(json_iterator); - json_iterator.nextToken(); - m_zs.add(z); - } else { - if (!m_b_has_zs_known) { - m_b_has_zs_known = true; - m_b_has_zs = false; - } else { - if (m_b_has_zs) { - m_zs.add(VertexDescription.getDefaultValue(Semantics.Z)); - } - } - } - - if (isDouble_(json_iterator)) { - if (!m_b_has_ms_known) { - m_b_has_ms_known = true; - m_b_has_ms = true; - m_ms = (AttributeStreamOfDbl) AttributeStreamBase - .createDoubleStream(0); - } else { - if (!m_b_has_ms) { - m_ms = (AttributeStreamOfDbl) AttributeStreamBase - .createDoubleStream(size >> 1, - VertexDescription - .getDefaultValue(Semantics.M)); - m_b_has_ms = true; - } - } - - double m = readDouble_(json_iterator); - json_iterator.nextToken(); - m_ms.add(m); - } else { - if (!m_b_has_ms_known) { - m_b_has_ms_known = true; - m_b_has_ms = false; - } else { - if (m_b_has_ms) { - m_zs.add(VertexDescription.getDefaultValue(Semantics.M)); - } - } - } - - if (json_iterator.currentToken() != JsonReader.Token.END_ARRAY) { - throw new JsonGeometryException("parsing error"); - } - } - - private void addPath_() { - if (m_paths == null) { - m_paths = (AttributeStreamOfInt32) AttributeStreamBase - .createIndexStream(0); - } - - if (m_position == null) { - m_paths.add(0); - } else { - m_paths.add(m_position.size() / 2); - } - } - - private void addPathFlag_(boolean b_polygon_start) { - if (m_path_flags == null) { - m_path_flags = (AttributeStreamOfInt8) AttributeStreamBase - .createByteStream(0); - } - - if (b_polygon_start) { - m_path_flags - .add((byte) (PathFlags.enumClosed | PathFlags.enumOGCStartPolygon)); - } else { - m_path_flags.add((byte) PathFlags.enumClosed); - } - } - - private double readDouble_(JsonReader json_iterator) - throws JsonGeometryException { - JsonReader.Token current_token = json_iterator.currentToken(); - if (current_token == JsonReader.Token.VALUE_NULL - || (current_token == JsonReader.Token.VALUE_STRING && json_iterator - .currentString().equals("NaN"))) { - return NumberUtils.NaN(); - } else { - return json_iterator.currentDoubleValue(); - } - } - - private boolean isDouble_(JsonReader json_iterator) - throws JsonGeometryException { - JsonReader.Token current_token = json_iterator.currentToken(); - - if (current_token == JsonReader.Token.VALUE_NUMBER_FLOAT) { - return true; - } - - if (current_token == JsonReader.Token.VALUE_NUMBER_INT) { - return true; - } - - if (current_token == JsonReader.Token.VALUE_NULL - || (current_token == JsonReader.Token.VALUE_STRING && json_iterator - .currentString().equals("NaN"))) { - return true; - } - - return false; - } - - //does not accept GeometryCollection - private Geometry createGeometry_(GeoJsonType geo_json_type, int type) - throws JsonGeometryException { - Geometry geometry; - - if (type != Geometry.GeometryType.Unknown) { - switch (type) { - case Geometry.GeometryType.Polygon: - if (geo_json_type != GeoJsonType.MultiPolygon - && geo_json_type != GeoJsonType.Polygon) { - throw new GeometryException("invalid shape type"); - } - break; - case Geometry.GeometryType.Polyline: - if (geo_json_type != GeoJsonType.MultiLineString - && geo_json_type != GeoJsonType.LineString) { - throw new GeometryException("invalid shape type"); - } - break; - case Geometry.GeometryType.MultiPoint: - if (geo_json_type != GeoJsonType.MultiPoint) { - throw new GeometryException("invalid shape type"); - } - break; - case Geometry.GeometryType.Point: - if (geo_json_type != GeoJsonType.Point) { - throw new GeometryException("invalid shape type"); - } - break; - default: - throw new GeometryException("invalid shape type"); - } - } - - m_ogcType = geo_json_type.geogsjonvalue(); - if (geo_json_type == GeoJsonType.GeometryCollection) - throw new IllegalArgumentException("invalid argument"); - - if (m_position == null && m_point == null) { - switch (geo_json_type) { - case Point: { - if (m_num_embeddings > 1) { - throw new JsonGeometryException("parsing error"); - } - - geometry = new Point(); - break; - } - case MultiPoint: { - if (m_num_embeddings > 2) { - throw new JsonGeometryException("parsing error"); - } - - geometry = new MultiPoint(); - break; - } - case LineString: { - if (m_num_embeddings > 2) { - throw new JsonGeometryException("parsing error"); - } - - geometry = new Polyline(); - break; - } - case MultiLineString: { - if (m_num_embeddings > 3) { - throw new JsonGeometryException("parsing error"); - } - - geometry = new Polyline(); - break; - } - case Polygon: { - if (m_num_embeddings > 3) { - throw new JsonGeometryException("parsing error"); - } - - geometry = new Polygon(); - break; - } - case MultiPolygon: { - assert (m_num_embeddings <= 4); - geometry = new Polygon(); - break; - } - default: - throw new JsonGeometryException("parsing error"); - } - } else if (m_num_embeddings == 1) { - if (geo_json_type != GeoJsonType.Point) { - throw new JsonGeometryException("parsing error"); - } - - assert (m_point != null); - geometry = m_point; - } else if (m_num_embeddings == 2) { - if (geo_json_type == GeoJsonType.MultiPoint) { - geometry = createMultiPointFromStreams_(); - } else if (geo_json_type == GeoJsonType.LineString) { - geometry = createPolylineFromStreams_(); - } else { - throw new JsonGeometryException("parsing error"); - } - } else if (m_num_embeddings == 3) { - if (geo_json_type == GeoJsonType.Polygon) { - geometry = createPolygonFromStreams_(); - } else if (geo_json_type == GeoJsonType.MultiLineString) { - geometry = createPolylineFromStreams_(); - } else { - throw new JsonGeometryException("parsing error"); - } - } else { - if (geo_json_type != GeoJsonType.MultiPolygon) { - throw new JsonGeometryException("parsing error"); - } - - geometry = createPolygonFromStreams_(); - } - - return geometry; - } - - private Geometry createPolygonFromStreams_() { - assert (m_position != null); - assert (m_paths != null); - assert ((m_num_embeddings == 3 && m_path_flags == null) || (m_num_embeddings == 4 && m_path_flags != null)); - - Polygon polygon = new Polygon(); - MultiPathImpl multi_path_impl = (MultiPathImpl) polygon._getImpl(); - - checkPathPointCountsForMultiPath_(true); - multi_path_impl.setAttributeStreamRef(Semantics.POSITION, - m_position); - - if (m_b_has_zs) { - assert (m_zs != null); - multi_path_impl.setAttributeStreamRef(Semantics.Z, m_zs); - } - - if (m_b_has_ms) { - assert (m_ms != null); - multi_path_impl.setAttributeStreamRef(Semantics.M, m_ms); - } - - if (m_path_flags == null) { - m_path_flags = (AttributeStreamOfInt8) AttributeStreamBase - .createByteStream(m_paths.size(), (byte) 0); - m_path_flags - .setBits( - 0, - (byte) (PathFlags.enumClosed | PathFlags.enumOGCStartPolygon)); - - for (int i = 1; i < m_path_flags.size() - 1; i++) { - m_path_flags.setBits(i, (byte) PathFlags.enumClosed); - } - } - - multi_path_impl.setPathStreamRef(m_paths); - multi_path_impl.setPathFlagsStreamRef(m_path_flags); - multi_path_impl - .notifyModified(MultiVertexGeometryImpl.DirtyFlags.DirtyAll); - - AttributeStreamOfInt8 path_flags_clone = new AttributeStreamOfInt8( - m_path_flags); - - for (int i = 0; i < path_flags_clone.size() - 1; i++) { - assert ((path_flags_clone.read(i) & PathFlags.enumClosed) != 0); - assert ((m_path_flags.read(i) & PathFlags.enumClosed) != 0); - - if ((path_flags_clone.read(i) & PathFlags.enumOGCStartPolygon) != 0) {// Should - // be - // clockwise - if (!InternalUtils.isClockwiseRing(multi_path_impl, i)) { - multi_path_impl.reversePath(i); // make clockwise - } - } else {// Should be counter-clockwise - if (InternalUtils.isClockwiseRing(multi_path_impl, i)) { - multi_path_impl.reversePath(i); // make - // counter-clockwise - } - } - } - - multi_path_impl.setPathFlagsStreamRef(path_flags_clone); - multi_path_impl.clearDirtyOGCFlags(); - - return polygon; - } - - private Geometry createPolylineFromStreams_() { - assert (m_position != null); - assert ((m_num_embeddings == 2 && m_paths == null) || (m_num_embeddings == 3 && m_paths != null)); - assert (m_path_flags == null); - - Polyline polyline = new Polyline(); - MultiPathImpl multi_path_impl = (MultiPathImpl) polyline._getImpl(); - - if (m_paths == null) { - m_paths = (AttributeStreamOfInt32) AttributeStreamBase - .createIndexStream(0); - m_paths.add(0); - m_paths.add(m_position.size() / 2); - } - - checkPathPointCountsForMultiPath_(false); - multi_path_impl.setAttributeStreamRef(Semantics.POSITION, - m_position); - - if (m_b_has_zs) { - assert (m_zs != null); - multi_path_impl.setAttributeStreamRef(Semantics.Z, m_zs); - } - - if (m_b_has_ms) { - assert (m_ms != null); - multi_path_impl.setAttributeStreamRef(Semantics.M, m_ms); - } - - m_path_flags = (AttributeStreamOfInt8) AttributeStreamBase - .createByteStream(m_paths.size(), (byte) 0); - - multi_path_impl.setPathStreamRef(m_paths); - multi_path_impl.setPathFlagsStreamRef(m_path_flags); - multi_path_impl - .notifyModified(MultiVertexGeometryImpl.DirtyFlags.DirtyAll); - - return polyline; - } - - private Geometry createMultiPointFromStreams_() { - assert (m_position != null); - assert (m_paths == null); - assert (m_path_flags == null); - - MultiPoint multi_point = new MultiPoint(); - MultiPointImpl multi_point_impl = (MultiPointImpl) multi_point - ._getImpl(); - multi_point_impl.setAttributeStreamRef(Semantics.POSITION, - m_position); - - if (m_b_has_zs) { - assert (m_zs != null); - multi_point_impl.setAttributeStreamRef(Semantics.Z, m_zs); - } - - if (m_b_has_ms) { - assert (m_ms != null); - multi_point_impl.setAttributeStreamRef(Semantics.M, m_ms); - } - - multi_point_impl.resize(m_position.size() / 2); - multi_point_impl.notifyModified(MultiVertexGeometryImpl.DirtyFlags.DirtyAll); - return multi_point; - } - - private void checkPathPointCountsForMultiPath_(boolean b_is_polygon) { - Point2D pt1 = new Point2D(), pt2 = new Point2D(); - double z1 = 0.0, z2 = 0.0, m1 = 0.0, m2 = 0.0; - int path_count = m_paths.size() - 1; - int guess_adjustment = 0; - - if (b_is_polygon) {// Polygon - guess_adjustment = path_count; // may remove up to path_count - // number of points - } else {// Polyline - for (int path = 0; path < path_count; path++) { - int path_size = m_paths.read(path + 1) - m_paths.read(path); - - if (path_size == 1) { - guess_adjustment--; // will add a point for each path - // containing only 1 point - } - } - - if (guess_adjustment == 0) { - return; // all paths are okay - } - } - - AttributeStreamOfDbl adjusted_position = (AttributeStreamOfDbl) AttributeStreamBase - .createDoubleStream(m_position.size() - guess_adjustment); - AttributeStreamOfInt32 adjusted_paths = (AttributeStreamOfInt32) AttributeStreamBase - .createIndexStream(m_paths.size()); - AttributeStreamOfDbl adjusted_zs = null; - AttributeStreamOfDbl adjusted_ms = null; - - if (m_b_has_zs) { - adjusted_zs = (AttributeStreamOfDbl) AttributeStreamBase - .createDoubleStream(m_zs.size() - guess_adjustment); - } - - if (m_b_has_ms) { - adjusted_ms = (AttributeStreamOfDbl) AttributeStreamBase - .createDoubleStream(m_ms.size() - guess_adjustment); - } - - int adjusted_start = 0; - adjusted_paths.write(0, 0); - - for (int path = 0; path < path_count; path++) { - int path_start = m_paths.read(path); - int path_end = m_paths.read(path + 1); - int path_size = path_end - path_start; - assert (path_size != 0); // we should not have added empty parts - // on import - - if (path_size == 1) { - insertIntoAdjustedStreams_(adjusted_position, adjusted_zs, - adjusted_ms, adjusted_start, path_start, path_size); - insertIntoAdjustedStreams_(adjusted_position, adjusted_zs, - adjusted_ms, adjusted_start + 1, path_start, - path_size); - adjusted_start += 2; - } else if (path_size >= 3 && b_is_polygon) { - m_position.read(path_start * 2, pt1); - m_position.read((path_end - 1) * 2, pt2); - - if (m_b_has_zs) { - z1 = m_zs.readAsDbl(path_start); - z2 = m_zs.readAsDbl(path_end - 1); - } - - if (m_b_has_ms) { - m1 = m_ms.readAsDbl(path_start); - m2 = m_ms.readAsDbl(path_end - 1); - } - - if (pt1.equals(pt2) - && (NumberUtils.isNaN(z1) && NumberUtils.isNaN(z2) || z1 == z2) - && (NumberUtils.isNaN(m1) && NumberUtils.isNaN(m2) || m1 == m2)) { - insertIntoAdjustedStreams_(adjusted_position, - adjusted_zs, adjusted_ms, adjusted_start, - path_start, path_size - 1); - adjusted_start += path_size - 1; - } else { - insertIntoAdjustedStreams_(adjusted_position, - adjusted_zs, adjusted_ms, adjusted_start, - path_start, path_size); - adjusted_start += path_size; - } - } else { - insertIntoAdjustedStreams_(adjusted_position, adjusted_zs, - adjusted_ms, adjusted_start, path_start, path_size); - adjusted_start += path_size; - } - adjusted_paths.write(path + 1, adjusted_start); - } - - m_position = adjusted_position; - m_paths = adjusted_paths; - m_zs = adjusted_zs; - m_ms = adjusted_ms; - } - - private void insertIntoAdjustedStreams_( - AttributeStreamOfDbl adjusted_position, - AttributeStreamOfDbl adjusted_zs, - AttributeStreamOfDbl adjusted_ms, int adjusted_start, - int path_start, int count) { - adjusted_position.insertRange(adjusted_start * 2, m_position, - path_start * 2, count * 2, true, 2, adjusted_start * 2); - - if (m_b_has_zs) { - adjusted_zs.insertRange(adjusted_start, m_zs, path_start, - count, true, 1, adjusted_start); - } - - if (m_b_has_ms) { - adjusted_ms.insertRange(adjusted_start, m_ms, path_start, - count, true, 1, adjusted_start); - } - } - - static SpatialReference importSpatialReferenceFromCrs( - JsonReader json_iterator, ProgressTracker progress_tracker) - throws JsonGeometryException { - // According to the spec, a null crs corresponds to no spatial - // reference - if (json_iterator.currentToken() == JsonReader.Token.VALUE_NULL) { - return null; - } - - if (json_iterator.currentToken() == JsonReader.Token.VALUE_STRING) {// see - // http://wiki.geojson.org/RFC-001 - // (this - // is - // deprecated, - // but - // there - // may - // be - // data - // with - // this - // format) - - String crs_short_form = json_iterator.currentString(); - int wkid = GeoJsonCrsTables - .getWkidFromCrsShortForm(crs_short_form); - - if (wkid == -1) { - throw new GeometryException("not implemented"); - } - - SpatialReference spatial_reference = null; - - try { - spatial_reference = SpatialReference.create(wkid); - } catch (Exception e) { - } - - return spatial_reference; - } - - if (json_iterator.currentToken() != JsonReader.Token.START_OBJECT) { - throw new JsonGeometryException("parsing error"); - } - - // This is to support all cases of crs identifiers I've seen. Some - // may be rare or are legacy formats, but all are simple to - // accomodate. - boolean b_found_type = false; - boolean b_found_properties = false; - boolean b_found_properties_name = false; - boolean b_found_properties_href = false; - boolean b_found_properties_urn = false; - boolean b_found_properties_url = false; - boolean b_found_properties_code = false; - boolean b_found_esriwkt = false; - String crs_field = null; - String properties_field = null; - String crs_identifier_name = null; - String crs_identifier_urn = null; - String crs_identifier_href = null; - String crs_identifier_url = null; - String esriwkt = null; - int crs_identifier_code = -1; - JsonReader.Token current_token; - - while (json_iterator.nextToken() != JsonReader.Token.END_OBJECT) { - crs_field = json_iterator.currentString(); - - if (crs_field.equals("type")) { - if (b_found_type) { - throw new JsonGeometryException("parsing error"); - } - - b_found_type = true; - - current_token = json_iterator.nextToken(); - - if (current_token != JsonReader.Token.VALUE_STRING) { - throw new JsonGeometryException("parsing error"); - } - - //type = json_iterator.currentString(); - } else if (crs_field.equals("properties")) { - if (b_found_properties) { - throw new JsonGeometryException("parsing error"); - } - - b_found_properties = true; - - current_token = json_iterator.nextToken(); - - if (current_token != JsonReader.Token.START_OBJECT) { - throw new JsonGeometryException("parsing error"); - } - - while (json_iterator.nextToken() != JsonReader.Token.END_OBJECT) { - properties_field = json_iterator.currentString(); - - if (properties_field.equals("name")) { - if (b_found_properties_name) { - throw new JsonGeometryException("parsing error"); - } - - b_found_properties_name = true; - crs_identifier_name = getCrsIdentifier_(json_iterator); - } else if (properties_field.equals("href")) { - if (b_found_properties_href) { - throw new JsonGeometryException("parsing error"); - } - - b_found_properties_href = true; - crs_identifier_href = getCrsIdentifier_(json_iterator); - } else if (properties_field.equals("urn")) { - if (b_found_properties_urn) { - throw new JsonGeometryException("parsing error"); - } - - b_found_properties_urn = true; - crs_identifier_urn = getCrsIdentifier_(json_iterator); - } else if (properties_field.equals("url")) { - if (b_found_properties_url) { - throw new JsonGeometryException("parsing error"); - } - - b_found_properties_url = true; - crs_identifier_url = getCrsIdentifier_(json_iterator); - } else if (properties_field.equals("code")) { - if (b_found_properties_code) { - throw new JsonGeometryException("parsing error"); - } - - b_found_properties_code = true; - - current_token = json_iterator.nextToken(); - - if (current_token != JsonReader.Token.VALUE_NUMBER_INT) { - throw new JsonGeometryException("parsing error"); - } - - crs_identifier_code = json_iterator - .currentIntValue(); - } else { - json_iterator.nextToken(); - json_iterator.skipChildren(); - } - } - } else if (crs_field.equals("esriwkt")) { - if (b_found_esriwkt) { - throw new JsonGeometryException("parsing error"); - } - - b_found_esriwkt = true; - - current_token = json_iterator.nextToken(); - - if (current_token != JsonReader.Token.VALUE_STRING) { - throw new JsonGeometryException("parsing error"); - } - - esriwkt = json_iterator.currentString(); - } else { - json_iterator.nextToken(); - json_iterator.skipChildren(); - } - } - - if ((!b_found_type || !b_found_properties) && !b_found_esriwkt) { - throw new JsonGeometryException("parsing error"); - } - - int wkid = -1; - - if (b_found_properties_name) { - wkid = GeoJsonCrsTables.getWkidFromCrsName(crs_identifier_name); // see - // http://wiki.geojson.org/GeoJSON_draft_version_6 - // (most - // common) - } else if (b_found_properties_href) { - wkid = GeoJsonCrsTables.getWkidFromCrsHref(crs_identifier_href); // see - // http://wiki.geojson.org/GeoJSON_draft_version_6 - // (somewhat - // common) - } else if (b_found_properties_urn) { - wkid = GeoJsonCrsTables - .getWkidFromCrsOgcUrn(crs_identifier_urn); // see - // http://wiki.geojson.org/GeoJSON_draft_version_5 - // (rare) - } else if (b_found_properties_url) { - wkid = GeoJsonCrsTables.getWkidFromCrsHref(crs_identifier_url); // see - // http://wiki.geojson.org/GeoJSON_draft_version_5 - // (rare) - } else if (b_found_properties_code) { - wkid = crs_identifier_code; // see - // http://wiki.geojson.org/GeoJSON_draft_version_5 - // (rare) - } else if (!b_found_esriwkt) { - throw new JsonGeometryException("parsing error"); - } - - if (wkid < 0 && !b_found_esriwkt && !b_found_properties_name) { - throw new JsonGeometryException("parsing error"); - } - - SpatialReference spatial_reference = null; - - if (wkid > 0) { - try { - spatial_reference = SpatialReference.create(wkid); - } catch (Exception e) { - } - } - - if (spatial_reference == null) { - try { - if (b_found_esriwkt) {// I exported crs wkt strings like - // this - spatial_reference = SpatialReference.create(esriwkt); - } else if (b_found_properties_name) {// AGOL exported crs - // wkt strings like - // this where the - // crs identifier of - // the properties - // name is like - // "ESRI:" - String potential_wkt = GeoJsonCrsTables - .getWktFromCrsName(crs_identifier_name); - spatial_reference = SpatialReference - .create(potential_wkt); - } - } catch (Exception e) { - } - } - - return spatial_reference; - } - - // see http://geojsonwg.github.io/draft-geojson/draft.html - static SpatialReference importSpatialReferenceFromCrsUrn_( - JsonReader json_iterator, ProgressTracker progress_tracker) - throws JsonGeometryException { - // According to the spec, a null crs corresponds to no spatial - // reference - if (json_iterator.currentToken() == JsonReader.Token.VALUE_NULL) { - return null; - } - - if (json_iterator.currentToken() != JsonReader.Token.VALUE_STRING) { - throw new JsonGeometryException("parsing error"); - } - - String crs_identifier_urn = json_iterator.currentString(); - - int wkid = GeoJsonCrsTables.getWkidFromCrsName(crs_identifier_urn); // This - // will - // check - // for - // short - // form - // name, - // as - // well - // as - // long - // form - // URNs - - if (wkid == -1) { - throw new GeometryException("not implemented"); - } - - SpatialReference spatial_reference = SpatialReference.create(wkid); - - return spatial_reference; - } - - private static String getCrsIdentifier_(JsonReader json_iterator) - throws JsonGeometryException { - JsonReader.Token current_token = json_iterator.nextToken(); - - if (current_token != JsonReader.Token.VALUE_STRING) { - throw new JsonGeometryException("parsing error"); - } - - return json_iterator.currentString(); - } - - } - - @Override - public MapOGCStructure executeOGC(int import_flags, String geoJsonString, - ProgressTracker progress_tracker) throws JsonGeometryException { - return executeOGC(import_flags, JsonParserReader.createFromString(geoJsonString), - progress_tracker); - } - - public MapOGCStructure executeOGC(int import_flags, - JsonReader json_iterator, ProgressTracker progress_tracker) - throws JsonGeometryException { - MapOGCStructure mapOGCStructure = OperatorImportFromGeoJsonHelper.importFromGeoJson( - import_flags, Geometry.Type.Unknown, json_iterator, - progress_tracker, false, 0); - - //This is to restore legacy behavior when we always return a geometry collection of one element. - MapOGCStructure res = new MapOGCStructure(); - res.m_ogcStructure = new OGCStructure(); - res.m_ogcStructure.m_type = 0; - res.m_ogcStructure.m_structures = new ArrayList(); - res.m_ogcStructure.m_structures.add(mapOGCStructure.m_ogcStructure); - res.m_spatialReference = mapOGCStructure.m_spatialReference; - return res; - } + @Override + MapGeometryCursor execute(int import_flags, StringCursor stringCursor, ProgressTracker progressTracker) { + return new OperatorImportFromGeoJsonCursor(import_flags, stringCursor, progressTracker); + } + + @Override + public MapGeometry execute(int importFlags, Geometry.Type type, + String geoJsonString, ProgressTracker progressTracker) + throws JsonGeometryException { + MapGeometry map_geometry = OperatorImportFromGeoJsonHelper + .importFromGeoJson(importFlags, type, JsonParserReader.createFromString(geoJsonString), progressTracker, false); + return map_geometry; + } + + @Override + public MapGeometry execute(int importFlags, Geometry.Type type, + JsonReader jsonReader, ProgressTracker progressTracker) + throws JsonGeometryException { + if (jsonReader == null) + return null; + + return OperatorImportFromGeoJsonHelper.importFromGeoJson(importFlags, + type, jsonReader, progressTracker, false); + } + + static final class OperatorImportFromGeoJsonHelper { + + private AttributeStreamOfDbl m_position; + private AttributeStreamOfDbl m_zs; + private AttributeStreamOfDbl m_ms; + private AttributeStreamOfInt32 m_paths; + private AttributeStreamOfInt8 m_path_flags; + private Point m_point; // special case for Points + private boolean m_b_has_zs; + private boolean m_b_has_ms; + private boolean m_b_has_zs_known; + private boolean m_b_has_ms_known; + private int m_num_embeddings; + + int m_ogcType; + + OperatorImportFromGeoJsonHelper() { + m_position = null; + m_zs = null; + m_ms = null; + m_paths = null; + m_path_flags = null; + m_point = null; + m_b_has_zs = false; + m_b_has_ms = false; + m_b_has_zs_known = false; + m_b_has_ms_known = false; + m_num_embeddings = 0; + m_ogcType = 0; + } + + static MapGeometry importFromGeoJson(int importFlags, + Geometry.Type type, JsonReader json_iterator, + ProgressTracker progress_tracker, boolean skip_coordinates) + throws JsonGeometryException { + OperatorImportFromGeoJsonHelper geo_json_helper = new OperatorImportFromGeoJsonHelper(); + MapOGCStructure ms = geo_json_helper.importFromGeoJsonImpl( + importFlags, type, json_iterator, progress_tracker, + skip_coordinates, 0); + + if (geo_json_helper.m_ogcType == GeoJsonValues.GeometryCollection && !skip_coordinates) + throw new JsonGeometryException("parsing error"); + + return new MapGeometry(ms.m_ogcStructure.m_geometry, + ms.m_spatialReference); + } + + static MapOGCStructure importFromGeoJson(int importFlags, + Geometry.Type type, JsonReader json_iterator, + ProgressTracker progress_tracker, boolean skip_coordinates, + int recursion) throws JsonGeometryException { + OperatorImportFromGeoJsonHelper geo_json_helper = new OperatorImportFromGeoJsonHelper(); + MapOGCStructure ms = geo_json_helper.importFromGeoJsonImpl( + importFlags, type, json_iterator, progress_tracker, + skip_coordinates, recursion); + + if (geo_json_helper.m_ogcType == GeoJsonValues.GeometryCollection && !skip_coordinates) + throw new JsonGeometryException("parsing error"); + + return ms; + } + + MapOGCStructure importFromGeoJsonImpl(int importFlags, + Geometry.Type type, JsonReader json_iterator, + ProgressTracker progress_tracker, boolean skip_coordinates, + int recursion) throws JsonGeometryException { + OperatorImportFromGeoJsonHelper geo_json_helper = this; + boolean b_type_found = false; + boolean b_coordinates_found = false; + boolean b_crs_found = false; + boolean b_crsURN_found = false; + boolean b_geometry_collection = false; + boolean b_geometries_found = false; + GeoJsonType geo_json_type = null; + + Geometry geometry = null; + SpatialReference spatial_reference = null; + + JsonReader.Token current_token; + String field_name = null; + MapOGCStructure ms = new MapOGCStructure(); + + while ((current_token = json_iterator.nextToken()) != JsonReader.Token.END_OBJECT) { + field_name = json_iterator.currentString(); + + if (field_name.equals("type")) { + if (b_type_found) { + throw new JsonGeometryException("parsing error"); + } + + b_type_found = true; + current_token = json_iterator.nextToken(); + + if (current_token != JsonReader.Token.VALUE_STRING) { + throw new JsonGeometryException("parsing error"); + } + + String s = json_iterator.currentString(); + try { + geo_json_type = GeoJsonType.valueOf(s); + } catch (Exception ex) { + throw new JsonGeometryException(s); + } + + if (geo_json_type == GeoJsonType.GeometryCollection) { + if (type != Geometry.Type.Unknown) + throw new JsonGeometryException("parsing error"); + + b_geometry_collection = true; + } + } else if (field_name.equals("geometries")) { + b_geometries_found = true; + if (type != Geometry.Type.Unknown) + throw new JsonGeometryException("parsing error"); + + if (recursion > 10) { + throw new JsonGeometryException("deep geojson"); + } + + if (skip_coordinates) { + json_iterator.skipChildren(); + } else { + current_token = json_iterator.nextToken(); + + ms.m_ogcStructure = new OGCStructure(); + ms.m_ogcStructure.m_type = GeoJsonValues.GeometryCollection; + ms.m_ogcStructure.m_structures = new ArrayList( + 0); + + if (current_token == JsonReader.Token.START_ARRAY) { + current_token = json_iterator.nextToken(); + while (current_token != JsonReader.Token.END_ARRAY) { + MapOGCStructure child = importFromGeoJson( + importFlags + | GeoJsonImportFlags.geoJsonImportSkipCRS, + type, json_iterator, + progress_tracker, false, + recursion + 1); + ms.m_ogcStructure.m_structures + .add(child.m_ogcStructure); + + current_token = json_iterator.nextToken(); + } + } else if (current_token != JsonReader.Token.VALUE_NULL) { + throw new JsonGeometryException("parsing error"); + } + } + } else if (field_name.equals("coordinates")) { + + if (b_coordinates_found) { + throw new JsonGeometryException("parsing error"); + } + + b_coordinates_found = true; + current_token = json_iterator.nextToken(); + + if (skip_coordinates) { + json_iterator.skipChildren(); + } else {// According to the spec, the value of the + // coordinates must be an array. However, I do an + // extra check for null too. + if (current_token != JsonReader.Token.VALUE_NULL) { + if (current_token != JsonReader.Token.START_ARRAY) { + throw new JsonGeometryException("parsing error"); + } + + geo_json_helper.import_coordinates_(json_iterator, + progress_tracker); + } + } + } else if (field_name.equals("crs")) { + if (b_crs_found || b_crsURN_found) { + throw new JsonGeometryException("parsing error"); + } + + b_crs_found = true; + current_token = json_iterator.nextToken(); + + if ((importFlags & GeoJsonImportFlags.geoJsonImportSkipCRS) == 0) + spatial_reference = importSpatialReferenceFromCrs( + json_iterator, progress_tracker); + else + json_iterator.skipChildren(); + } else if (field_name.equals("crsURN")) { + if (b_crs_found || b_crsURN_found) { + throw new JsonGeometryException("parsing error"); + } + + b_crsURN_found = true; + current_token = json_iterator.nextToken(); + + spatial_reference = importSpatialReferenceFromCrsUrn_( + json_iterator, progress_tracker); + } else { + json_iterator.nextToken(); + json_iterator.skipChildren(); + } + } + + // According to the spec, a GeoJSON object must have both a type and + // a coordinates array + if (!b_type_found || (!b_geometry_collection && !b_coordinates_found && !skip_coordinates)) { + throw new JsonGeometryException("parsing error"); + } + + if ((!b_geometry_collection && b_geometries_found) || (b_geometry_collection && !b_geometries_found)) { + throw new JsonGeometryException("parsing error");//found "geometries" but did not see "GeometryCollection" + } + + + if (!skip_coordinates && !b_geometry_collection) { + geometry = geo_json_helper.createGeometry_(geo_json_type, + type.value()); + + ms.m_ogcStructure = new OGCStructure(); + ms.m_ogcStructure.m_type = m_ogcType; + ms.m_ogcStructure.m_geometry = geometry; + } + + if (!b_crs_found + && !b_crsURN_found + && ((importFlags & GeoJsonImportFlags.geoJsonImportSkipCRS) == 0) + && ((importFlags & GeoJsonImportFlags.geoJsonImportNoWGS84Default) == 0)) { + spatial_reference = SpatialReference.create(4326); // the spec + // gives a + // default + // of 4326 + // if no crs + // is given + } + + ms.m_spatialReference = spatial_reference; + return ms; + } + + // We have to import the coordinates in the most general way possible to + // not assume the type of geometry we're parsing. + // JSON allows for unordered objects, so it's possible that the + // coordinates array can come before the type tag when parsing + // sequentially, otherwise + // we would have to parse using a JSON_object, which would be easier, + // but not as space/time efficient. So this function blindly imports the + // coordinates + // into the attribute stream(s), and will later assign them to a + // geometry after the type tag is found. + private void import_coordinates_(JsonReader json_iterator, + ProgressTracker progress_tracker) throws JsonGeometryException { + assert (json_iterator.currentToken() == JsonReader.Token.START_ARRAY); + + int coordinates_level_lower = 1; + int coordinates_level_upper = 4; + + json_iterator.nextToken(); + + while (json_iterator.currentToken() != JsonReader.Token.END_ARRAY) { + if (isDouble_(json_iterator)) { + if (coordinates_level_upper > 1) { + coordinates_level_upper = 1; + } + } else if (json_iterator.currentToken() == JsonReader.Token.START_ARRAY) { + if (coordinates_level_lower < 2) { + coordinates_level_lower = 2; + } + } else { + throw new JsonGeometryException("parsing error"); + } + + if (coordinates_level_lower > coordinates_level_upper) { + throw new IllegalArgumentException("invalid argument"); + } + + if (coordinates_level_lower == coordinates_level_upper + && coordinates_level_lower == 1) {// special + // code + // for + // Points + readCoordinateAsPoint_(json_iterator); + } else { + boolean b_add_path_level_3 = true; + boolean b_polygon_start_level_4 = true; + + assert (json_iterator.currentToken() == JsonReader.Token.START_ARRAY); + json_iterator.nextToken(); + + while (json_iterator.currentToken() != JsonReader.Token.END_ARRAY) { + if (isDouble_(json_iterator)) { + if (coordinates_level_upper > 2) { + coordinates_level_upper = 2; + } + } else if (json_iterator.currentToken() == JsonReader.Token.START_ARRAY) { + if (coordinates_level_lower < 3) { + coordinates_level_lower = 3; + } + } else { + throw new JsonGeometryException("parsing error"); + } + + if (coordinates_level_lower > coordinates_level_upper) { + throw new JsonGeometryException("parsing error"); + } + + if (coordinates_level_lower == coordinates_level_upper + && coordinates_level_lower == 2) {// LineString + // or + // MultiPoint + addCoordinate_(json_iterator); + } else { + boolean b_add_path_level_4 = true; + + assert (json_iterator.currentToken() == JsonReader.Token.START_ARRAY); + json_iterator.nextToken(); + + while (json_iterator.currentToken() != JsonReader.Token.END_ARRAY) { + if (isDouble_(json_iterator)) { + if (coordinates_level_upper > 3) { + coordinates_level_upper = 3; + } + } else if (json_iterator.currentToken() == JsonReader.Token.START_ARRAY) { + if (coordinates_level_lower < 4) { + coordinates_level_lower = 4; + } + } else { + throw new JsonGeometryException("parsing error"); + } + + if (coordinates_level_lower > coordinates_level_upper) { + throw new JsonGeometryException("parsing error"); + } + + if (coordinates_level_lower == coordinates_level_upper + && coordinates_level_lower == 3) {// Polygon + // or + // MultiLineString + if (b_add_path_level_3) { + addPath_(); + b_add_path_level_3 = false; + } + + addCoordinate_(json_iterator); + } else { + assert (json_iterator.currentToken() == JsonReader.Token.START_ARRAY); + json_iterator.nextToken(); + + if (json_iterator.currentToken() != JsonReader.Token.END_ARRAY) { + if (!isDouble_(json_iterator)) { + throw new JsonGeometryException("parsing error"); + } + + assert (coordinates_level_lower == coordinates_level_upper && coordinates_level_lower == 4); + // MultiPolygon + + if (b_add_path_level_4) { + addPath_(); + addPathFlag_(b_polygon_start_level_4); + b_add_path_level_4 = false; + b_polygon_start_level_4 = false; + } + + addCoordinate_(json_iterator); + } + + json_iterator.nextToken(); + } + } + + json_iterator.nextToken(); + } + } + + json_iterator.nextToken(); + } + } + + if (m_paths != null) { + m_paths.add(m_position.size() / 2); // add final path size + } + if (m_path_flags != null) { + m_path_flags.add((byte) 0); // to match the paths size + } + + m_num_embeddings = coordinates_level_lower; + } + + private void readCoordinateAsPoint_(JsonReader json_iterator) + throws JsonGeometryException { + assert (isDouble_(json_iterator)); + + m_point = new Point(); + + double x = readDouble_(json_iterator); + json_iterator.nextToken(); + double y = readDouble_(json_iterator); + json_iterator.nextToken(); + + if (NumberUtils.isNaN(y)) { + x = NumberUtils.NaN(); + } + + m_point.setXY(x, y); + + if (isDouble_(json_iterator)) { + double z = readDouble_(json_iterator); + json_iterator.nextToken(); + m_point.setZ(z); + } + + if (isDouble_(json_iterator)) { + double m = readDouble_(json_iterator); + json_iterator.nextToken(); + m_point.setM(m); + } + + if (json_iterator.currentToken() != JsonReader.Token.END_ARRAY) { + throw new JsonGeometryException("parsing error"); + } + } + + private void addCoordinate_(JsonReader json_iterator) + throws JsonGeometryException { + assert (isDouble_(json_iterator)); + + if (m_position == null) { + m_position = (AttributeStreamOfDbl) AttributeStreamBase + .createDoubleStream(0); + } + + double x = readDouble_(json_iterator); + json_iterator.nextToken(); + double y = readDouble_(json_iterator); + json_iterator.nextToken(); + + int size = m_position.size(); + + m_position.add(x); + m_position.add(y); + + if (isDouble_(json_iterator)) { + if (!m_b_has_zs_known) { + m_b_has_zs_known = true; + m_b_has_zs = true; + m_zs = (AttributeStreamOfDbl) AttributeStreamBase + .createDoubleStream(0); + } else { + if (!m_b_has_zs) { + m_zs = (AttributeStreamOfDbl) AttributeStreamBase + .createDoubleStream(size >> 1, + VertexDescription + .getDefaultValue(Semantics.Z)); + m_b_has_zs = true; + } + } + + double z = readDouble_(json_iterator); + json_iterator.nextToken(); + m_zs.add(z); + } else { + if (!m_b_has_zs_known) { + m_b_has_zs_known = true; + m_b_has_zs = false; + } else { + if (m_b_has_zs) { + m_zs.add(VertexDescription.getDefaultValue(Semantics.Z)); + } + } + } + + if (isDouble_(json_iterator)) { + if (!m_b_has_ms_known) { + m_b_has_ms_known = true; + m_b_has_ms = true; + m_ms = (AttributeStreamOfDbl) AttributeStreamBase + .createDoubleStream(0); + } else { + if (!m_b_has_ms) { + m_ms = (AttributeStreamOfDbl) AttributeStreamBase + .createDoubleStream(size >> 1, + VertexDescription + .getDefaultValue(Semantics.M)); + m_b_has_ms = true; + } + } + + double m = readDouble_(json_iterator); + json_iterator.nextToken(); + m_ms.add(m); + } else { + if (!m_b_has_ms_known) { + m_b_has_ms_known = true; + m_b_has_ms = false; + } else { + if (m_b_has_ms) { + m_zs.add(VertexDescription.getDefaultValue(Semantics.M)); + } + } + } + + if (json_iterator.currentToken() != JsonReader.Token.END_ARRAY) { + throw new JsonGeometryException("parsing error"); + } + } + + private void addPath_() { + if (m_paths == null) { + m_paths = (AttributeStreamOfInt32) AttributeStreamBase + .createIndexStream(0); + } + + if (m_position == null) { + m_paths.add(0); + } else { + m_paths.add(m_position.size() / 2); + } + } + + private void addPathFlag_(boolean b_polygon_start) { + if (m_path_flags == null) { + m_path_flags = (AttributeStreamOfInt8) AttributeStreamBase + .createByteStream(0); + } + + if (b_polygon_start) { + m_path_flags + .add((byte) (PathFlags.enumClosed | PathFlags.enumOGCStartPolygon)); + } else { + m_path_flags.add((byte) PathFlags.enumClosed); + } + } + + private double readDouble_(JsonReader json_iterator) + throws JsonGeometryException { + JsonReader.Token current_token = json_iterator.currentToken(); + if (current_token == JsonReader.Token.VALUE_NULL + || (current_token == JsonReader.Token.VALUE_STRING && json_iterator + .currentString().equals("NaN"))) { + return NumberUtils.NaN(); + } else { + return json_iterator.currentDoubleValue(); + } + } + + private boolean isDouble_(JsonReader json_iterator) + throws JsonGeometryException { + JsonReader.Token current_token = json_iterator.currentToken(); + + if (current_token == JsonReader.Token.VALUE_NUMBER_FLOAT) { + return true; + } + + if (current_token == JsonReader.Token.VALUE_NUMBER_INT) { + return true; + } + + if (current_token == JsonReader.Token.VALUE_NULL + || (current_token == JsonReader.Token.VALUE_STRING && json_iterator + .currentString().equals("NaN"))) { + return true; + } + + return false; + } + + //does not accept GeometryCollection + private Geometry createGeometry_(GeoJsonType geo_json_type, int type) + throws JsonGeometryException { + Geometry geometry; + + if (type != Geometry.GeometryType.Unknown) { + switch (type) { + case Geometry.GeometryType.Polygon: + if (geo_json_type != GeoJsonType.MultiPolygon + && geo_json_type != GeoJsonType.Polygon) { + throw new GeometryException("invalid shape type"); + } + break; + case Geometry.GeometryType.Polyline: + if (geo_json_type != GeoJsonType.MultiLineString + && geo_json_type != GeoJsonType.LineString) { + throw new GeometryException("invalid shape type"); + } + break; + case Geometry.GeometryType.MultiPoint: + if (geo_json_type != GeoJsonType.MultiPoint) { + throw new GeometryException("invalid shape type"); + } + break; + case Geometry.GeometryType.Point: + if (geo_json_type != GeoJsonType.Point) { + throw new GeometryException("invalid shape type"); + } + break; + default: + throw new GeometryException("invalid shape type"); + } + } + + m_ogcType = geo_json_type.geogsjonvalue(); + if (geo_json_type == GeoJsonType.GeometryCollection) + throw new IllegalArgumentException("invalid argument"); + + if (m_position == null && m_point == null) { + switch (geo_json_type) { + case Point: { + if (m_num_embeddings > 1) { + throw new JsonGeometryException("parsing error"); + } + + geometry = new Point(); + break; + } + case MultiPoint: { + if (m_num_embeddings > 2) { + throw new JsonGeometryException("parsing error"); + } + + geometry = new MultiPoint(); + break; + } + case LineString: { + if (m_num_embeddings > 2) { + throw new JsonGeometryException("parsing error"); + } + + geometry = new Polyline(); + break; + } + case MultiLineString: { + if (m_num_embeddings > 3) { + throw new JsonGeometryException("parsing error"); + } + + geometry = new Polyline(); + break; + } + case Polygon: { + if (m_num_embeddings > 3) { + throw new JsonGeometryException("parsing error"); + } + + geometry = new Polygon(); + break; + } + case MultiPolygon: { + assert (m_num_embeddings <= 4); + geometry = new Polygon(); + break; + } + default: + throw new JsonGeometryException("parsing error"); + } + } else if (m_num_embeddings == 1) { + if (geo_json_type != GeoJsonType.Point) { + throw new JsonGeometryException("parsing error"); + } + + assert (m_point != null); + geometry = m_point; + } else if (m_num_embeddings == 2) { + if (geo_json_type == GeoJsonType.MultiPoint) { + geometry = createMultiPointFromStreams_(); + } else if (geo_json_type == GeoJsonType.LineString) { + geometry = createPolylineFromStreams_(); + } else { + throw new JsonGeometryException("parsing error"); + } + } else if (m_num_embeddings == 3) { + if (geo_json_type == GeoJsonType.Polygon) { + geometry = createPolygonFromStreams_(); + } else if (geo_json_type == GeoJsonType.MultiLineString) { + geometry = createPolylineFromStreams_(); + } else { + throw new JsonGeometryException("parsing error"); + } + } else { + if (geo_json_type != GeoJsonType.MultiPolygon) { + throw new JsonGeometryException("parsing error"); + } + + geometry = createPolygonFromStreams_(); + } + + return geometry; + } + + private Geometry createPolygonFromStreams_() { + assert (m_position != null); + assert (m_paths != null); + assert ((m_num_embeddings == 3 && m_path_flags == null) || (m_num_embeddings == 4 && m_path_flags != null)); + + Polygon polygon = new Polygon(); + MultiPathImpl multi_path_impl = (MultiPathImpl) polygon._getImpl(); + + checkPathPointCountsForMultiPath_(true); + multi_path_impl.setAttributeStreamRef(Semantics.POSITION, + m_position); + + if (m_b_has_zs) { + assert (m_zs != null); + multi_path_impl.setAttributeStreamRef(Semantics.Z, m_zs); + } + + if (m_b_has_ms) { + assert (m_ms != null); + multi_path_impl.setAttributeStreamRef(Semantics.M, m_ms); + } + + if (m_path_flags == null) { + m_path_flags = (AttributeStreamOfInt8) AttributeStreamBase + .createByteStream(m_paths.size(), (byte) 0); + m_path_flags + .setBits( + 0, + (byte) (PathFlags.enumClosed | PathFlags.enumOGCStartPolygon)); + + for (int i = 1; i < m_path_flags.size() - 1; i++) { + m_path_flags.setBits(i, (byte) PathFlags.enumClosed); + } + } + + multi_path_impl.setPathStreamRef(m_paths); + multi_path_impl.setPathFlagsStreamRef(m_path_flags); + multi_path_impl + .notifyModified(MultiVertexGeometryImpl.DirtyFlags.DirtyAll); + + AttributeStreamOfInt8 path_flags_clone = new AttributeStreamOfInt8( + m_path_flags); + + for (int i = 0; i < path_flags_clone.size() - 1; i++) { + assert ((path_flags_clone.read(i) & PathFlags.enumClosed) != 0); + assert ((m_path_flags.read(i) & PathFlags.enumClosed) != 0); + + if ((path_flags_clone.read(i) & PathFlags.enumOGCStartPolygon) != 0) {// Should + // be + // clockwise + if (!InternalUtils.isClockwiseRing(multi_path_impl, i)) { + multi_path_impl.reversePath(i); // make clockwise + } + } else {// Should be counter-clockwise + if (InternalUtils.isClockwiseRing(multi_path_impl, i)) { + multi_path_impl.reversePath(i); // make + // counter-clockwise + } + } + } + + multi_path_impl.setPathFlagsStreamRef(path_flags_clone); + multi_path_impl.clearDirtyOGCFlags(); + + return polygon; + } + + private Geometry createPolylineFromStreams_() { + assert (m_position != null); + assert ((m_num_embeddings == 2 && m_paths == null) || (m_num_embeddings == 3 && m_paths != null)); + assert (m_path_flags == null); + + Polyline polyline = new Polyline(); + MultiPathImpl multi_path_impl = (MultiPathImpl) polyline._getImpl(); + + if (m_paths == null) { + m_paths = (AttributeStreamOfInt32) AttributeStreamBase + .createIndexStream(0); + m_paths.add(0); + m_paths.add(m_position.size() / 2); + } + + checkPathPointCountsForMultiPath_(false); + multi_path_impl.setAttributeStreamRef(Semantics.POSITION, + m_position); + + if (m_b_has_zs) { + assert (m_zs != null); + multi_path_impl.setAttributeStreamRef(Semantics.Z, m_zs); + } + + if (m_b_has_ms) { + assert (m_ms != null); + multi_path_impl.setAttributeStreamRef(Semantics.M, m_ms); + } + + m_path_flags = (AttributeStreamOfInt8) AttributeStreamBase + .createByteStream(m_paths.size(), (byte) 0); + + multi_path_impl.setPathStreamRef(m_paths); + multi_path_impl.setPathFlagsStreamRef(m_path_flags); + multi_path_impl + .notifyModified(MultiVertexGeometryImpl.DirtyFlags.DirtyAll); + + return polyline; + } + + private Geometry createMultiPointFromStreams_() { + assert (m_position != null); + assert (m_paths == null); + assert (m_path_flags == null); + + MultiPoint multi_point = new MultiPoint(); + MultiPointImpl multi_point_impl = (MultiPointImpl) multi_point + ._getImpl(); + multi_point_impl.setAttributeStreamRef(Semantics.POSITION, + m_position); + + if (m_b_has_zs) { + assert (m_zs != null); + multi_point_impl.setAttributeStreamRef(Semantics.Z, m_zs); + } + + if (m_b_has_ms) { + assert (m_ms != null); + multi_point_impl.setAttributeStreamRef(Semantics.M, m_ms); + } + + multi_point_impl.resize(m_position.size() / 2); + multi_point_impl.notifyModified(MultiVertexGeometryImpl.DirtyFlags.DirtyAll); + return multi_point; + } + + private void checkPathPointCountsForMultiPath_(boolean b_is_polygon) { + Point2D pt1 = new Point2D(), pt2 = new Point2D(); + double z1 = 0.0, z2 = 0.0, m1 = 0.0, m2 = 0.0; + int path_count = m_paths.size() - 1; + int guess_adjustment = 0; + + if (b_is_polygon) {// Polygon + guess_adjustment = path_count; // may remove up to path_count + // number of points + } else {// Polyline + for (int path = 0; path < path_count; path++) { + int path_size = m_paths.read(path + 1) - m_paths.read(path); + + if (path_size == 1) { + guess_adjustment--; // will add a point for each path + // containing only 1 point + } + } + + if (guess_adjustment == 0) { + return; // all paths are okay + } + } + + AttributeStreamOfDbl adjusted_position = (AttributeStreamOfDbl) AttributeStreamBase + .createDoubleStream(m_position.size() - guess_adjustment); + AttributeStreamOfInt32 adjusted_paths = (AttributeStreamOfInt32) AttributeStreamBase + .createIndexStream(m_paths.size()); + AttributeStreamOfDbl adjusted_zs = null; + AttributeStreamOfDbl adjusted_ms = null; + + if (m_b_has_zs) { + adjusted_zs = (AttributeStreamOfDbl) AttributeStreamBase + .createDoubleStream(m_zs.size() - guess_adjustment); + } + + if (m_b_has_ms) { + adjusted_ms = (AttributeStreamOfDbl) AttributeStreamBase + .createDoubleStream(m_ms.size() - guess_adjustment); + } + + int adjusted_start = 0; + adjusted_paths.write(0, 0); + + for (int path = 0; path < path_count; path++) { + int path_start = m_paths.read(path); + int path_end = m_paths.read(path + 1); + int path_size = path_end - path_start; + assert (path_size != 0); // we should not have added empty parts + // on import + + if (path_size == 1) { + insertIntoAdjustedStreams_(adjusted_position, adjusted_zs, + adjusted_ms, adjusted_start, path_start, path_size); + insertIntoAdjustedStreams_(adjusted_position, adjusted_zs, + adjusted_ms, adjusted_start + 1, path_start, + path_size); + adjusted_start += 2; + } else if (path_size >= 3 && b_is_polygon) { + m_position.read(path_start * 2, pt1); + m_position.read((path_end - 1) * 2, pt2); + + if (m_b_has_zs) { + z1 = m_zs.readAsDbl(path_start); + z2 = m_zs.readAsDbl(path_end - 1); + } + + if (m_b_has_ms) { + m1 = m_ms.readAsDbl(path_start); + m2 = m_ms.readAsDbl(path_end - 1); + } + + if (pt1.equals(pt2) + && (NumberUtils.isNaN(z1) && NumberUtils.isNaN(z2) || z1 == z2) + && (NumberUtils.isNaN(m1) && NumberUtils.isNaN(m2) || m1 == m2)) { + insertIntoAdjustedStreams_(adjusted_position, + adjusted_zs, adjusted_ms, adjusted_start, + path_start, path_size - 1); + adjusted_start += path_size - 1; + } else { + insertIntoAdjustedStreams_(adjusted_position, + adjusted_zs, adjusted_ms, adjusted_start, + path_start, path_size); + adjusted_start += path_size; + } + } else { + insertIntoAdjustedStreams_(adjusted_position, adjusted_zs, + adjusted_ms, adjusted_start, path_start, path_size); + adjusted_start += path_size; + } + adjusted_paths.write(path + 1, adjusted_start); + } + + m_position = adjusted_position; + m_paths = adjusted_paths; + m_zs = adjusted_zs; + m_ms = adjusted_ms; + } + + private void insertIntoAdjustedStreams_( + AttributeStreamOfDbl adjusted_position, + AttributeStreamOfDbl adjusted_zs, + AttributeStreamOfDbl adjusted_ms, int adjusted_start, + int path_start, int count) { + adjusted_position.insertRange(adjusted_start * 2, m_position, + path_start * 2, count * 2, true, 2, adjusted_start * 2); + + if (m_b_has_zs) { + adjusted_zs.insertRange(adjusted_start, m_zs, path_start, + count, true, 1, adjusted_start); + } + + if (m_b_has_ms) { + adjusted_ms.insertRange(adjusted_start, m_ms, path_start, + count, true, 1, adjusted_start); + } + } + + static SpatialReference importSpatialReferenceFromCrs( + JsonReader json_iterator, ProgressTracker progress_tracker) + throws JsonGeometryException { + // According to the spec, a null crs corresponds to no spatial + // reference + if (json_iterator.currentToken() == JsonReader.Token.VALUE_NULL) { + return null; + } + + if (json_iterator.currentToken() == JsonReader.Token.VALUE_STRING) {// see + // http://wiki.geojson.org/RFC-001 + // (this + // is + // deprecated, + // but + // there + // may + // be + // data + // with + // this + // format) + + String crs_short_form = json_iterator.currentString(); + int wkid = GeoJsonCrsTables + .getWkidFromCrsShortForm(crs_short_form); + + if (wkid == -1) { + throw new GeometryException("not implemented"); + } + + SpatialReference spatial_reference = null; + + try { + spatial_reference = SpatialReference.create(wkid); + } catch (Exception e) { + } + + return spatial_reference; + } + + if (json_iterator.currentToken() != JsonReader.Token.START_OBJECT) { + throw new JsonGeometryException("parsing error"); + } + + // This is to support all cases of crs identifiers I've seen. Some + // may be rare or are legacy formats, but all are simple to + // accomodate. + boolean b_found_type = false; + boolean b_found_properties = false; + boolean b_found_properties_name = false; + boolean b_found_properties_href = false; + boolean b_found_properties_urn = false; + boolean b_found_properties_url = false; + boolean b_found_properties_code = false; + boolean b_found_esriwkt = false; + String crs_field = null; + String properties_field = null; + String crs_identifier_name = null; + String crs_identifier_urn = null; + String crs_identifier_href = null; + String crs_identifier_url = null; + String esriwkt = null; + int crs_identifier_code = -1; + JsonReader.Token current_token; + + while (json_iterator.nextToken() != JsonReader.Token.END_OBJECT) { + crs_field = json_iterator.currentString(); + + if (crs_field.equals("type")) { + if (b_found_type) { + throw new JsonGeometryException("parsing error"); + } + + b_found_type = true; + + current_token = json_iterator.nextToken(); + + if (current_token != JsonReader.Token.VALUE_STRING) { + throw new JsonGeometryException("parsing error"); + } + + //type = json_iterator.currentString(); + } else if (crs_field.equals("properties")) { + if (b_found_properties) { + throw new JsonGeometryException("parsing error"); + } + + b_found_properties = true; + + current_token = json_iterator.nextToken(); + + if (current_token != JsonReader.Token.START_OBJECT) { + throw new JsonGeometryException("parsing error"); + } + + while (json_iterator.nextToken() != JsonReader.Token.END_OBJECT) { + properties_field = json_iterator.currentString(); + + if (properties_field.equals("name")) { + if (b_found_properties_name) { + throw new JsonGeometryException("parsing error"); + } + + b_found_properties_name = true; + crs_identifier_name = getCrsIdentifier_(json_iterator); + } else if (properties_field.equals("href")) { + if (b_found_properties_href) { + throw new JsonGeometryException("parsing error"); + } + + b_found_properties_href = true; + crs_identifier_href = getCrsIdentifier_(json_iterator); + } else if (properties_field.equals("urn")) { + if (b_found_properties_urn) { + throw new JsonGeometryException("parsing error"); + } + + b_found_properties_urn = true; + crs_identifier_urn = getCrsIdentifier_(json_iterator); + } else if (properties_field.equals("url")) { + if (b_found_properties_url) { + throw new JsonGeometryException("parsing error"); + } + + b_found_properties_url = true; + crs_identifier_url = getCrsIdentifier_(json_iterator); + } else if (properties_field.equals("code")) { + if (b_found_properties_code) { + throw new JsonGeometryException("parsing error"); + } + + b_found_properties_code = true; + + current_token = json_iterator.nextToken(); + + if (current_token != JsonReader.Token.VALUE_NUMBER_INT) { + throw new JsonGeometryException("parsing error"); + } + + crs_identifier_code = json_iterator + .currentIntValue(); + } else { + json_iterator.nextToken(); + json_iterator.skipChildren(); + } + } + } else if (crs_field.equals("esriwkt")) { + if (b_found_esriwkt) { + throw new JsonGeometryException("parsing error"); + } + + b_found_esriwkt = true; + + current_token = json_iterator.nextToken(); + + if (current_token != JsonReader.Token.VALUE_STRING) { + throw new JsonGeometryException("parsing error"); + } + + esriwkt = json_iterator.currentString(); + } else { + json_iterator.nextToken(); + json_iterator.skipChildren(); + } + } + + if ((!b_found_type || !b_found_properties) && !b_found_esriwkt) { + throw new JsonGeometryException("parsing error"); + } + + int wkid = -1; + + if (b_found_properties_name) { + wkid = GeoJsonCrsTables.getWkidFromCrsName(crs_identifier_name); // see + // http://wiki.geojson.org/GeoJSON_draft_version_6 + // (most + // common) + } else if (b_found_properties_href) { + wkid = GeoJsonCrsTables.getWkidFromCrsHref(crs_identifier_href); // see + // http://wiki.geojson.org/GeoJSON_draft_version_6 + // (somewhat + // common) + } else if (b_found_properties_urn) { + wkid = GeoJsonCrsTables + .getWkidFromCrsOgcUrn(crs_identifier_urn); // see + // http://wiki.geojson.org/GeoJSON_draft_version_5 + // (rare) + } else if (b_found_properties_url) { + wkid = GeoJsonCrsTables.getWkidFromCrsHref(crs_identifier_url); // see + // http://wiki.geojson.org/GeoJSON_draft_version_5 + // (rare) + } else if (b_found_properties_code) { + wkid = crs_identifier_code; // see + // http://wiki.geojson.org/GeoJSON_draft_version_5 + // (rare) + } else if (!b_found_esriwkt) { + throw new JsonGeometryException("parsing error"); + } + + if (wkid < 0 && !b_found_esriwkt && !b_found_properties_name) { + throw new JsonGeometryException("parsing error"); + } + + SpatialReference spatial_reference = null; + + if (wkid > 0) { + try { + spatial_reference = SpatialReference.create(wkid); + } catch (Exception e) { + } + } + + if (spatial_reference == null) { + try { + if (b_found_esriwkt) {// I exported crs wkt strings like + // this + spatial_reference = SpatialReference.create(esriwkt); + } else if (b_found_properties_name) {// AGOL exported crs + // wkt strings like + // this where the + // crs identifier of + // the properties + // name is like + // "ESRI:" + String potential_wkt = GeoJsonCrsTables + .getWktFromCrsName(crs_identifier_name); + spatial_reference = SpatialReference + .create(potential_wkt); + } + } catch (Exception e) { + } + } + + return spatial_reference; + } + + // see http://geojsonwg.github.io/draft-geojson/draft.html + static SpatialReference importSpatialReferenceFromCrsUrn_( + JsonReader json_iterator, ProgressTracker progress_tracker) + throws JsonGeometryException { + // According to the spec, a null crs corresponds to no spatial + // reference + if (json_iterator.currentToken() == JsonReader.Token.VALUE_NULL) { + return null; + } + + if (json_iterator.currentToken() != JsonReader.Token.VALUE_STRING) { + throw new JsonGeometryException("parsing error"); + } + + String crs_identifier_urn = json_iterator.currentString(); + + int wkid = GeoJsonCrsTables.getWkidFromCrsName(crs_identifier_urn); // This + // will + // check + // for + // short + // form + // name, + // as + // well + // as + // long + // form + // URNs + + if (wkid == -1) { + throw new GeometryException("not implemented"); + } + + SpatialReference spatial_reference = SpatialReference.create(wkid); + + return spatial_reference; + } + + private static String getCrsIdentifier_(JsonReader json_iterator) + throws JsonGeometryException { + JsonReader.Token current_token = json_iterator.nextToken(); + + if (current_token != JsonReader.Token.VALUE_STRING) { + throw new JsonGeometryException("parsing error"); + } + + return json_iterator.currentString(); + } + + } + + @Override + public MapOGCStructure executeOGC(int import_flags, String geoJsonString, + ProgressTracker progress_tracker) throws JsonGeometryException { + return executeOGC(import_flags, JsonParserReader.createFromString(geoJsonString), + progress_tracker); + } + + public MapOGCStructure executeOGC(int import_flags, + JsonReader json_iterator, ProgressTracker progress_tracker) + throws JsonGeometryException { + MapOGCStructure mapOGCStructure = OperatorImportFromGeoJsonHelper.importFromGeoJson( + import_flags, Geometry.Type.Unknown, json_iterator, + progress_tracker, false, 0); + + //This is to restore legacy behavior when we always return a geometry collection of one element. + MapOGCStructure res = new MapOGCStructure(); + res.m_ogcStructure = new OGCStructure(); + res.m_ogcStructure.m_type = 0; + res.m_ogcStructure.m_structures = new ArrayList(); + res.m_ogcStructure.m_structures.add(mapOGCStructure.m_ogcStructure); + res.m_spatialReference = mapOGCStructure.m_spatialReference; + return res; + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorImportFromJson.java b/src/main/java/com/esri/core/geometry/OperatorImportFromJson.java index 7d5e0c25..dd5565fb 100644 --- a/src/main/java/com/esri/core/geometry/OperatorImportFromJson.java +++ b/src/main/java/com/esri/core/geometry/OperatorImportFromJson.java @@ -28,36 +28,36 @@ * Import from JSON format. */ public abstract class OperatorImportFromJson extends Operator { - @Override - public Type getType() { - return Type.ImportFromJson; - } - - /** - * Performs the ImportFromJson operation on a number of Json Strings - * - * @return Returns a MapGeometryCursor. - */ - abstract MapGeometryCursor execute(Geometry.Type type, - JsonReaderCursor jsonReaderCursor); - - /** - * Performs the ImportFromJson operation on a single Json string - * - * @return Returns a MapGeometry. - */ - public abstract MapGeometry execute(Geometry.Type type, - JsonReader jsonReader); - - /** - * Performs the ImportFromJson operation on a single Json string - * - * @return Returns a MapGeometry. - */ - public abstract MapGeometry execute(Geometry.Type type, String string); - - public static OperatorImportFromJson local() { - return (OperatorImportFromJson) OperatorFactoryLocal.getInstance().getOperator(Type.ImportFromJson); - } + @Override + public Type getType() { + return Type.ImportFromJson; + } + + /** + * Performs the ImportFromJson operation on a number of Json Strings + * + * @return Returns a MapGeometryCursor. + */ + abstract MapGeometryCursor execute(Geometry.Type type, + JsonReaderCursor jsonReaderCursor); + + /** + * Performs the ImportFromJson operation on a single Json string + * + * @return Returns a MapGeometry. + */ + public abstract MapGeometry execute(Geometry.Type type, + JsonReader jsonReader); + + /** + * Performs the ImportFromJson operation on a single Json string + * + * @return Returns a MapGeometry. + */ + public abstract MapGeometry execute(Geometry.Type type, String string); + + public static OperatorImportFromJson local() { + return (OperatorImportFromJson) OperatorFactoryLocal.getInstance().getOperator(Type.ImportFromJson); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorImportFromJsonCursor.java b/src/main/java/com/esri/core/geometry/OperatorImportFromJsonCursor.java index c51fd6ef..22801a36 100644 --- a/src/main/java/com/esri/core/geometry/OperatorImportFromJsonCursor.java +++ b/src/main/java/com/esri/core/geometry/OperatorImportFromJsonCursor.java @@ -28,538 +28,540 @@ import com.esri.core.geometry.VertexDescription.Semantics; public class OperatorImportFromJsonCursor extends MapGeometryCursor { - JsonReaderCursor m_inputJsonParsers; - - int m_type; - - long m_index; - - public OperatorImportFromJsonCursor(int type, JsonReaderCursor jsonParsers) { - m_index = -1; - if (jsonParsers == null) - throw new IllegalArgumentException(); - - m_type = type; - m_inputJsonParsers = jsonParsers; - } - - @Override - public long getGeometryID() { - return m_index; - } - - @Override - public SimpleStateEnum getSimpleState() { - return m_inputJsonParsers.getSimpleState(); - } - - @Override - public String getFeatureID() { return m_inputJsonParsers.getFeatureID(); } - - @Override - public boolean hasNext() { - return m_inputJsonParsers.hasNext(); - } - - @Override - public MapGeometry next() { - JsonReader jsonParser; - if ((jsonParser = m_inputJsonParsers.next()) != null) { - m_index = m_inputJsonParsers.getID(); - return importFromJsonParser(m_type, jsonParser); - } - return null; - } - - static MapGeometry importFromJsonParser(int gt, JsonReader parser) { - MapGeometry mp; - - try { - if (!JSONUtils.isObjectStart(parser)) - return null; - - boolean bFoundSpatial_reference = false; - boolean bFoundHasZ = false; - boolean bFoundHasM = false; - boolean bFoundPolygon = false; - boolean bFoundPolyline = false; - boolean bFoundMultiPoint = false; - boolean bFoundX = false; - boolean bFoundY = false; - boolean bFoundZ = false; - boolean bFoundM = false; - boolean bFoundXMin = false; - boolean bFoundYMin = false; - boolean bFoundXMax = false; - boolean bFoundYMax = false; - boolean bFoundZMin = false; - boolean bFoundZMax = false; - boolean bFoundMMin = false; - boolean bFoundMMax = false; - double x = NumberUtils.NaN(); - double y = NumberUtils.NaN(); - double z = NumberUtils.NaN(); - double m = NumberUtils.NaN(); - double xmin = NumberUtils.NaN(); - double ymin = NumberUtils.NaN(); - double xmax = NumberUtils.NaN(); - double ymax = NumberUtils.NaN(); - double zmin = NumberUtils.NaN(); - double zmax = NumberUtils.NaN(); - double mmin = NumberUtils.NaN(); - double mmax = NumberUtils.NaN(); - boolean bHasZ = false; - boolean bHasM = false; - AttributeStreamOfDbl as = (AttributeStreamOfDbl) AttributeStreamBase - .createDoubleStream(0); - AttributeStreamOfDbl bs = (AttributeStreamOfDbl) AttributeStreamBase - .createDoubleStream(0); - - Geometry geometry = null; - SpatialReference spatial_reference = null; - - while (parser.nextToken() != JsonReader.Token.END_OBJECT) { - String name = parser.currentString(); - parser.nextToken(); - - if (!bFoundSpatial_reference && name.equals("spatialReference")) { - bFoundSpatial_reference = true; - - if (parser.currentToken() == JsonReader.Token.START_OBJECT) { - spatial_reference = SpatialReference.fromJson(parser); - } else { - if (parser.currentToken() != JsonReader.Token.VALUE_NULL) - throw new GeometryException( - "failed to parse spatial reference: object or null is expected"); - } - } else if (!bFoundHasZ && name.equals("hasZ")) { - bFoundHasZ = true; - bHasZ = (parser.currentToken() == JsonReader.Token.VALUE_TRUE); - } else if (!bFoundHasM && name.equals("hasM")) { - bFoundHasM = true; - bHasM = (parser.currentToken() == JsonReader.Token.VALUE_TRUE); - } else if (!bFoundPolygon - && name.equals("rings") - && (gt == Geometry.GeometryType.Unknown || gt == Geometry.GeometryType.Polygon)) { - bFoundPolygon = true; - geometry = importFromJsonMultiPath(true, parser, as, bs); - continue; - } else if (!bFoundPolyline - && name.equals("paths") - && (gt == Geometry.GeometryType.Unknown || gt == Geometry.GeometryType.Polyline)) { - bFoundPolyline = true; - geometry = importFromJsonMultiPath(false, parser, as, bs); - continue; - } else if (!bFoundMultiPoint - && name.equals("points") - && (gt == Geometry.GeometryType.Unknown || gt == Geometry.GeometryType.MultiPoint)) { - bFoundMultiPoint = true; - geometry = importFromJsonMultiPoint(parser, as, bs); - continue; - } else if (!bFoundX - && name.equals("x") - && (gt == Geometry.GeometryType.Unknown || gt == Geometry.GeometryType.Point)) { - bFoundX = true; - x = readDouble(parser); - } else if (!bFoundY - && name.equals("y") - && (gt == Geometry.GeometryType.Unknown || gt == Geometry.GeometryType.Point)) { - bFoundY = true; - y = readDouble(parser); - } else if (!bFoundZ - && name.equals("z") - && (gt == Geometry.GeometryType.Unknown || gt == Geometry.GeometryType.Point)) { - bFoundZ = true; - z = readDouble(parser); - } else if (!bFoundM - && name.equals("m") - && (gt == Geometry.GeometryType.Unknown || gt == Geometry.GeometryType.Point)) { - bFoundM = true; - m = readDouble(parser); - } - if (!bFoundXMin - && name.equals("xmin") - && (gt == Geometry.GeometryType.Unknown || gt == Geometry.GeometryType.Envelope)) { - bFoundXMin = true; - xmin = readDouble(parser); - } else if (!bFoundYMin - && name.equals("ymin") - && (gt == Geometry.GeometryType.Unknown || gt == Geometry.GeometryType.Envelope)) { - bFoundYMin = true; - ymin = readDouble(parser); - } else if (!bFoundMMin - && name.equals("mmin") - && (gt == Geometry.GeometryType.Unknown || gt == Geometry.GeometryType.Envelope)) { - bFoundMMin = true; - mmin = readDouble(parser); - } else if (!bFoundZMin - && name.equals("zmin") - && (gt == Geometry.GeometryType.Unknown || gt == Geometry.GeometryType.Envelope)) { - bFoundZMin = true; - zmin = readDouble(parser); - } else if (!bFoundXMax - && name.equals("xmax") - && (gt == Geometry.GeometryType.Unknown || gt == Geometry.GeometryType.Envelope)) { - bFoundXMax = true; - xmax = readDouble(parser); - } else if (!bFoundYMax - && name.equals("ymax") - && (gt == Geometry.GeometryType.Unknown || gt == Geometry.GeometryType.Envelope)) { - bFoundYMax = true; - ymax = readDouble(parser); - } else if (!bFoundMMax - && name.equals("mmax") - && (gt == Geometry.GeometryType.Unknown || gt == Geometry.GeometryType.Envelope)) { - bFoundMMax = true; - mmax = readDouble(parser); - } else if (!bFoundZMax - && name.equals("zmax") - && (gt == Geometry.GeometryType.Unknown || gt == Geometry.GeometryType.Envelope)) { - bFoundZMax = true; - zmax = readDouble(parser); - } else { - windup(parser); - } - } - - if (bFoundPolygon || bFoundPolyline || bFoundMultiPoint) { - assert (geometry != null); - MultiVertexGeometryImpl mvImpl = (MultiVertexGeometryImpl) geometry - ._getImpl(); - - AttributeStreamBase zs = null; - AttributeStreamBase ms = null; - - if (bHasZ) { - geometry.addAttribute(Semantics.Z); - zs = as; - } - if (bHasM) { - geometry.addAttribute(Semantics.M); - ms = !bHasZ ? as : bs; - } - - if (bHasZ && zs != null) { - mvImpl.setAttributeStreamRef(Semantics.Z, zs); - } - - if (bHasM && ms != null) { - mvImpl.setAttributeStreamRef(Semantics.M, ms); - } - - mvImpl.notifyModified(DirtyFlags.DirtyAll); - } else if (bFoundX || bFoundY || bFoundY || bFoundZ) { - if (NumberUtils.isNaN(y)) - x = NumberUtils.NaN(); - - Point p = new Point(x, y); - - if (bFoundZ) - p.setZ(z); - - if (bFoundM) - p.setM(m); - - geometry = p; - } else if (bFoundXMin || bFoundYMin || bFoundXMax || bFoundYMax - || bFoundZMin || bFoundZMax || bFoundMMin || bFoundMMax) { - if (NumberUtils.isNaN(ymin) || NumberUtils.isNaN(xmax) - || NumberUtils.isNaN(ymax)) - xmin = NumberUtils.NaN(); - - Envelope e = new Envelope(xmin, ymin, xmax, ymax); - - if (bFoundZMin && bFoundZMax) - e.setInterval(Semantics.Z, 0, zmin, zmax); - - if (bFoundMMin && bFoundMMax) - e.setInterval(Semantics.M, 0, mmin, mmax); - - geometry = e; - } - - mp = new MapGeometry(geometry, spatial_reference); - - } catch (Exception e) { - return null; - } - - return mp; - } - - public static MapGeometry fromJsonToUnknown(JsonReader parser) - throws Exception { - - return importFromJsonParser(Geometry.GeometryType.Unknown, parser); - } - - public static MapGeometry fromJsonToEnvelope(JsonReader parser) - throws Exception { - return importFromJsonParser(Geometry.GeometryType.Envelope, parser); - } - - public static MapGeometry fromJsonToPoint(JsonReader parser) - throws Exception { - return importFromJsonParser(Geometry.GeometryType.Point, parser); - } - - public static MapGeometry fromJsonToPolygon(JsonReader parser) - throws Exception { - return importFromJsonParser(Geometry.GeometryType.Polygon, parser); - } - - public static MapGeometry fromJsonToPolyline(JsonReader parser) - throws Exception { - return importFromJsonParser(Geometry.GeometryType.Polyline, parser); - } - - public static MapGeometry fromJsonToMultiPoint(JsonReader parser) - throws Exception { - return importFromJsonParser(Geometry.GeometryType.MultiPoint, parser); - } - - private static void windup(JsonReader parser) { - parser.skipChildren(); - } - - private static double readDouble(JsonReader parser) { - if (parser.currentToken() == JsonReader.Token.VALUE_NULL - || parser.currentToken() == JsonReader.Token.VALUE_STRING - && parser.currentString().equals("NaN")) - return NumberUtils.NaN(); - else - return parser.currentDoubleValue(); - } - - private static Geometry importFromJsonMultiPoint(JsonReader parser, - AttributeStreamOfDbl as, AttributeStreamOfDbl bs) throws Exception { - if (parser.currentToken() != JsonReader.Token.START_ARRAY) - throw new GeometryException( - "failed to parse multipoint: array of vertices is expected"); - - int point_count = 0; - MultiPoint multipoint; - - multipoint = new MultiPoint(); - - AttributeStreamOfDbl position = (AttributeStreamOfDbl) (AttributeStreamBase - .createDoubleStream(2, 0)); - - // At start of rings - int sz; - double[] buf = new double[4]; - while (parser.nextToken() != JsonReader.Token.END_ARRAY) { - if (parser.currentToken() != JsonReader.Token.START_ARRAY) - throw new GeometryException( - "failed to parse multipoint: array is expected, multipoint vertices consist of arrays of cooridinates"); - - sz = 0; - while (parser.nextToken() != JsonReader.Token.END_ARRAY) { - buf[sz++] = readDouble(parser); - } - - if (sz < 2) - throw new GeometryException( - "failed to parse multipoint: each vertex array has to have at least 2 elements"); - - if (position.size() == 2 * point_count) { - int c = point_count * 3; - if (c % 2 != 0) - c++;// have to be even - position.resize(c); - } - - position.write(2 * point_count, buf[0]); - position.write(2 * point_count + 1, buf[1]); - - if (as.size() == point_count) { - int c = (point_count * 3) / 2; - if (c < 4) - c = 4; - else if (c < 16) - c = 16; - - as.resize(c); - } - - if (sz > 2) { - as.write(point_count, buf[2]); - } else - as.write(point_count, NumberUtils.NaN()); - - if (bs.size() == point_count) { - int c = (point_count * 3) / 2; - if (c < 4) - c = 4; - else if (c < 16) - c = 16; - - bs.resize(c); - } - - if (sz > 3) { - bs.write(point_count, buf[3]); - } else - bs.write(point_count, NumberUtils.NaN()); - - point_count++; - } - - if (point_count != 0) { - MultiPointImpl mp_impl = (MultiPointImpl) multipoint._getImpl(); - mp_impl.resize(point_count); - mp_impl.setAttributeStreamRef(Semantics.POSITION, position); - } - return multipoint; - } - - private static Geometry importFromJsonMultiPath(boolean b_polygon, - JsonReader parser, AttributeStreamOfDbl as, AttributeStreamOfDbl bs) - throws Exception { - if (parser.currentToken() != JsonReader.Token.START_ARRAY) - throw new GeometryException( - "failed to parse multipath: array of array of vertices is expected"); - - MultiPath multipath; - - if (b_polygon) - multipath = new Polygon(); - else - multipath = new Polyline(); - - AttributeStreamOfInt32 parts = (AttributeStreamOfInt32) AttributeStreamBase - .createIndexStream(0); - AttributeStreamOfDbl position = (AttributeStreamOfDbl) AttributeStreamBase - .createDoubleStream(2, 0); - AttributeStreamOfInt8 pathFlags = (AttributeStreamOfInt8) AttributeStreamBase - .createByteStream(0); - - // set up min max variables - double[] buf = new double[4]; - double[] start = new double[4]; - - int point_count = 0; - int path_count = 0; - byte pathFlag = b_polygon ? (byte) PathFlags.enumClosed : 0; - int requiredSize = b_polygon ? 3 : 2; - - // At start of rings - while (parser.nextToken() != JsonReader.Token.END_ARRAY) { - if (parser.currentToken() != JsonReader.Token.START_ARRAY) - throw new GeometryException( - "failed to parse multipath: ring/path array is expected"); - - int pathPointCount = 0; - boolean b_first = true; - int sz = 0; - int szstart = 0; - - parser.nextToken(); - while (parser.currentToken() != JsonReader.Token.END_ARRAY) { - if (parser.currentToken() != JsonReader.Token.START_ARRAY) - throw new GeometryException( - "failed to parse multipath: array is expected, rings/paths vertices consist of arrays of cooridinates"); - - sz = 0; - while (parser.nextToken() != JsonReader.Token.END_ARRAY) { - buf[sz++] = readDouble(parser); - } - - if (sz < 2) - throw new GeometryException( - "failed to parse multipath: each vertex array has to have at least 2 elements"); - - parser.nextToken(); - - do { - if (position.size() == point_count * 2) { - int c = point_count * 3; - - if (c % 2 != 0) - c++;// have to be even - if (c < 8) - c = 8; - else if (c < 32) - c = 32; - - position.resize(c); - } - - position.write(2 * point_count, buf[0]); - position.write(2 * point_count + 1, buf[1]); - - if (as.size() == point_count) { - int c = (point_count * 3) / 2;// have to be even - if (c < 4) - c = 4; - else if (c < 16) - c = 16; - as.resize(c); - } - - if (sz > 2) { - as.write(point_count, buf[2]); - } else - as.write(point_count, NumberUtils.NaN()); - - if (bs.size() == point_count) { - int c = (point_count * 3) / 2;// have to be even - if (c < 4) - c = 4; - else if (c < 16) - c = 16; - bs.resize(c); - } - - if (sz > 3) { - bs.write(point_count, buf[3]); - } else - bs.write(point_count, NumberUtils.NaN()); - - if (b_first) { - path_count++; - parts.add(point_count); - pathFlags.add(pathFlag); - b_first = false; - szstart = sz; - start[0] = buf[0]; - start[1] = buf[1]; - start[2] = buf[2]; - start[3] = buf[3]; - } - point_count++; - pathPointCount++; - } while (pathPointCount < requiredSize - && parser.currentToken() == JsonReader.Token.END_ARRAY); - } - - if (b_polygon && pathPointCount > requiredSize && sz == szstart - && start[0] == buf[0] && start[1] == buf[1] - && start[2] == buf[2] && start[3] == buf[3]) { - // remove the end point that is equal to the start point. - point_count--; - pathPointCount--; - } - - if (pathPointCount == 0) - continue;// skip empty paths - } - - if (point_count != 0) { - parts.resize(path_count); - pathFlags.resize(path_count); - - if (point_count > 0) { - parts.add(point_count); - pathFlags.add((byte) 0); - } - - MultiPathImpl mp_impl = (MultiPathImpl) multipath._getImpl(); - mp_impl.setAttributeStreamRef(Semantics.POSITION, position); - mp_impl.setPathFlagsStreamRef(pathFlags); - mp_impl.setPathStreamRef(parts); - } - return multipath; - } + JsonReaderCursor m_inputJsonParsers; + + int m_type; + + long m_index; + + public OperatorImportFromJsonCursor(int type, JsonReaderCursor jsonParsers) { + m_index = -1; + if (jsonParsers == null) + throw new IllegalArgumentException(); + + m_type = type; + m_inputJsonParsers = jsonParsers; + } + + @Override + public long getGeometryID() { + return m_index; + } + + @Override + public SimpleStateEnum getSimpleState() { + return m_inputJsonParsers.getSimpleState(); + } + + @Override + public String getFeatureID() { + return m_inputJsonParsers.getFeatureID(); + } + + @Override + public boolean hasNext() { + return m_inputJsonParsers.hasNext(); + } + + @Override + public MapGeometry next() { + JsonReader jsonParser; + if ((jsonParser = m_inputJsonParsers.next()) != null) { + m_index = m_inputJsonParsers.getID(); + return importFromJsonParser(m_type, jsonParser); + } + return null; + } + + static MapGeometry importFromJsonParser(int gt, JsonReader parser) { + MapGeometry mp; + + try { + if (!JSONUtils.isObjectStart(parser)) + return null; + + boolean bFoundSpatial_reference = false; + boolean bFoundHasZ = false; + boolean bFoundHasM = false; + boolean bFoundPolygon = false; + boolean bFoundPolyline = false; + boolean bFoundMultiPoint = false; + boolean bFoundX = false; + boolean bFoundY = false; + boolean bFoundZ = false; + boolean bFoundM = false; + boolean bFoundXMin = false; + boolean bFoundYMin = false; + boolean bFoundXMax = false; + boolean bFoundYMax = false; + boolean bFoundZMin = false; + boolean bFoundZMax = false; + boolean bFoundMMin = false; + boolean bFoundMMax = false; + double x = NumberUtils.NaN(); + double y = NumberUtils.NaN(); + double z = NumberUtils.NaN(); + double m = NumberUtils.NaN(); + double xmin = NumberUtils.NaN(); + double ymin = NumberUtils.NaN(); + double xmax = NumberUtils.NaN(); + double ymax = NumberUtils.NaN(); + double zmin = NumberUtils.NaN(); + double zmax = NumberUtils.NaN(); + double mmin = NumberUtils.NaN(); + double mmax = NumberUtils.NaN(); + boolean bHasZ = false; + boolean bHasM = false; + AttributeStreamOfDbl as = (AttributeStreamOfDbl) AttributeStreamBase + .createDoubleStream(0); + AttributeStreamOfDbl bs = (AttributeStreamOfDbl) AttributeStreamBase + .createDoubleStream(0); + + Geometry geometry = null; + SpatialReference spatial_reference = null; + + while (parser.nextToken() != JsonReader.Token.END_OBJECT) { + String name = parser.currentString(); + parser.nextToken(); + + if (!bFoundSpatial_reference && name.equals("spatialReference")) { + bFoundSpatial_reference = true; + + if (parser.currentToken() == JsonReader.Token.START_OBJECT) { + spatial_reference = SpatialReference.fromJson(parser); + } else { + if (parser.currentToken() != JsonReader.Token.VALUE_NULL) + throw new GeometryException( + "failed to parse spatial reference: object or null is expected"); + } + } else if (!bFoundHasZ && name.equals("hasZ")) { + bFoundHasZ = true; + bHasZ = (parser.currentToken() == JsonReader.Token.VALUE_TRUE); + } else if (!bFoundHasM && name.equals("hasM")) { + bFoundHasM = true; + bHasM = (parser.currentToken() == JsonReader.Token.VALUE_TRUE); + } else if (!bFoundPolygon + && name.equals("rings") + && (gt == Geometry.GeometryType.Unknown || gt == Geometry.GeometryType.Polygon)) { + bFoundPolygon = true; + geometry = importFromJsonMultiPath(true, parser, as, bs); + continue; + } else if (!bFoundPolyline + && name.equals("paths") + && (gt == Geometry.GeometryType.Unknown || gt == Geometry.GeometryType.Polyline)) { + bFoundPolyline = true; + geometry = importFromJsonMultiPath(false, parser, as, bs); + continue; + } else if (!bFoundMultiPoint + && name.equals("points") + && (gt == Geometry.GeometryType.Unknown || gt == Geometry.GeometryType.MultiPoint)) { + bFoundMultiPoint = true; + geometry = importFromJsonMultiPoint(parser, as, bs); + continue; + } else if (!bFoundX + && name.equals("x") + && (gt == Geometry.GeometryType.Unknown || gt == Geometry.GeometryType.Point)) { + bFoundX = true; + x = readDouble(parser); + } else if (!bFoundY + && name.equals("y") + && (gt == Geometry.GeometryType.Unknown || gt == Geometry.GeometryType.Point)) { + bFoundY = true; + y = readDouble(parser); + } else if (!bFoundZ + && name.equals("z") + && (gt == Geometry.GeometryType.Unknown || gt == Geometry.GeometryType.Point)) { + bFoundZ = true; + z = readDouble(parser); + } else if (!bFoundM + && name.equals("m") + && (gt == Geometry.GeometryType.Unknown || gt == Geometry.GeometryType.Point)) { + bFoundM = true; + m = readDouble(parser); + } + if (!bFoundXMin + && name.equals("xmin") + && (gt == Geometry.GeometryType.Unknown || gt == Geometry.GeometryType.Envelope)) { + bFoundXMin = true; + xmin = readDouble(parser); + } else if (!bFoundYMin + && name.equals("ymin") + && (gt == Geometry.GeometryType.Unknown || gt == Geometry.GeometryType.Envelope)) { + bFoundYMin = true; + ymin = readDouble(parser); + } else if (!bFoundMMin + && name.equals("mmin") + && (gt == Geometry.GeometryType.Unknown || gt == Geometry.GeometryType.Envelope)) { + bFoundMMin = true; + mmin = readDouble(parser); + } else if (!bFoundZMin + && name.equals("zmin") + && (gt == Geometry.GeometryType.Unknown || gt == Geometry.GeometryType.Envelope)) { + bFoundZMin = true; + zmin = readDouble(parser); + } else if (!bFoundXMax + && name.equals("xmax") + && (gt == Geometry.GeometryType.Unknown || gt == Geometry.GeometryType.Envelope)) { + bFoundXMax = true; + xmax = readDouble(parser); + } else if (!bFoundYMax + && name.equals("ymax") + && (gt == Geometry.GeometryType.Unknown || gt == Geometry.GeometryType.Envelope)) { + bFoundYMax = true; + ymax = readDouble(parser); + } else if (!bFoundMMax + && name.equals("mmax") + && (gt == Geometry.GeometryType.Unknown || gt == Geometry.GeometryType.Envelope)) { + bFoundMMax = true; + mmax = readDouble(parser); + } else if (!bFoundZMax + && name.equals("zmax") + && (gt == Geometry.GeometryType.Unknown || gt == Geometry.GeometryType.Envelope)) { + bFoundZMax = true; + zmax = readDouble(parser); + } else { + windup(parser); + } + } + + if (bFoundPolygon || bFoundPolyline || bFoundMultiPoint) { + assert (geometry != null); + MultiVertexGeometryImpl mvImpl = (MultiVertexGeometryImpl) geometry + ._getImpl(); + + AttributeStreamBase zs = null; + AttributeStreamBase ms = null; + + if (bHasZ) { + geometry.addAttribute(Semantics.Z); + zs = as; + } + if (bHasM) { + geometry.addAttribute(Semantics.M); + ms = !bHasZ ? as : bs; + } + + if (bHasZ && zs != null) { + mvImpl.setAttributeStreamRef(Semantics.Z, zs); + } + + if (bHasM && ms != null) { + mvImpl.setAttributeStreamRef(Semantics.M, ms); + } + + mvImpl.notifyModified(DirtyFlags.DirtyAll); + } else if (bFoundX || bFoundY || bFoundY || bFoundZ) { + if (NumberUtils.isNaN(y)) + x = NumberUtils.NaN(); + + Point p = new Point(x, y); + + if (bFoundZ) + p.setZ(z); + + if (bFoundM) + p.setM(m); + + geometry = p; + } else if (bFoundXMin || bFoundYMin || bFoundXMax || bFoundYMax + || bFoundZMin || bFoundZMax || bFoundMMin || bFoundMMax) { + if (NumberUtils.isNaN(ymin) || NumberUtils.isNaN(xmax) + || NumberUtils.isNaN(ymax)) + xmin = NumberUtils.NaN(); + + Envelope e = new Envelope(xmin, ymin, xmax, ymax); + + if (bFoundZMin && bFoundZMax) + e.setInterval(Semantics.Z, 0, zmin, zmax); + + if (bFoundMMin && bFoundMMax) + e.setInterval(Semantics.M, 0, mmin, mmax); + + geometry = e; + } + + mp = new MapGeometry(geometry, spatial_reference); + + } catch (Exception e) { + return null; + } + + return mp; + } + + public static MapGeometry fromJsonToUnknown(JsonReader parser) + throws Exception { + + return importFromJsonParser(Geometry.GeometryType.Unknown, parser); + } + + public static MapGeometry fromJsonToEnvelope(JsonReader parser) + throws Exception { + return importFromJsonParser(Geometry.GeometryType.Envelope, parser); + } + + public static MapGeometry fromJsonToPoint(JsonReader parser) + throws Exception { + return importFromJsonParser(Geometry.GeometryType.Point, parser); + } + + public static MapGeometry fromJsonToPolygon(JsonReader parser) + throws Exception { + return importFromJsonParser(Geometry.GeometryType.Polygon, parser); + } + + public static MapGeometry fromJsonToPolyline(JsonReader parser) + throws Exception { + return importFromJsonParser(Geometry.GeometryType.Polyline, parser); + } + + public static MapGeometry fromJsonToMultiPoint(JsonReader parser) + throws Exception { + return importFromJsonParser(Geometry.GeometryType.MultiPoint, parser); + } + + private static void windup(JsonReader parser) { + parser.skipChildren(); + } + + private static double readDouble(JsonReader parser) { + if (parser.currentToken() == JsonReader.Token.VALUE_NULL + || parser.currentToken() == JsonReader.Token.VALUE_STRING + && parser.currentString().equals("NaN")) + return NumberUtils.NaN(); + else + return parser.currentDoubleValue(); + } + + private static Geometry importFromJsonMultiPoint(JsonReader parser, + AttributeStreamOfDbl as, AttributeStreamOfDbl bs) throws Exception { + if (parser.currentToken() != JsonReader.Token.START_ARRAY) + throw new GeometryException( + "failed to parse multipoint: array of vertices is expected"); + + int point_count = 0; + MultiPoint multipoint; + + multipoint = new MultiPoint(); + + AttributeStreamOfDbl position = (AttributeStreamOfDbl) (AttributeStreamBase + .createDoubleStream(2, 0)); + + // At start of rings + int sz; + double[] buf = new double[4]; + while (parser.nextToken() != JsonReader.Token.END_ARRAY) { + if (parser.currentToken() != JsonReader.Token.START_ARRAY) + throw new GeometryException( + "failed to parse multipoint: array is expected, multipoint vertices consist of arrays of cooridinates"); + + sz = 0; + while (parser.nextToken() != JsonReader.Token.END_ARRAY) { + buf[sz++] = readDouble(parser); + } + + if (sz < 2) + throw new GeometryException( + "failed to parse multipoint: each vertex array has to have at least 2 elements"); + + if (position.size() == 2 * point_count) { + int c = point_count * 3; + if (c % 2 != 0) + c++;// have to be even + position.resize(c); + } + + position.write(2 * point_count, buf[0]); + position.write(2 * point_count + 1, buf[1]); + + if (as.size() == point_count) { + int c = (point_count * 3) / 2; + if (c < 4) + c = 4; + else if (c < 16) + c = 16; + + as.resize(c); + } + + if (sz > 2) { + as.write(point_count, buf[2]); + } else + as.write(point_count, NumberUtils.NaN()); + + if (bs.size() == point_count) { + int c = (point_count * 3) / 2; + if (c < 4) + c = 4; + else if (c < 16) + c = 16; + + bs.resize(c); + } + + if (sz > 3) { + bs.write(point_count, buf[3]); + } else + bs.write(point_count, NumberUtils.NaN()); + + point_count++; + } + + if (point_count != 0) { + MultiPointImpl mp_impl = (MultiPointImpl) multipoint._getImpl(); + mp_impl.resize(point_count); + mp_impl.setAttributeStreamRef(Semantics.POSITION, position); + } + return multipoint; + } + + private static Geometry importFromJsonMultiPath(boolean b_polygon, + JsonReader parser, AttributeStreamOfDbl as, AttributeStreamOfDbl bs) + throws Exception { + if (parser.currentToken() != JsonReader.Token.START_ARRAY) + throw new GeometryException( + "failed to parse multipath: array of array of vertices is expected"); + + MultiPath multipath; + + if (b_polygon) + multipath = new Polygon(); + else + multipath = new Polyline(); + + AttributeStreamOfInt32 parts = (AttributeStreamOfInt32) AttributeStreamBase + .createIndexStream(0); + AttributeStreamOfDbl position = (AttributeStreamOfDbl) AttributeStreamBase + .createDoubleStream(2, 0); + AttributeStreamOfInt8 pathFlags = (AttributeStreamOfInt8) AttributeStreamBase + .createByteStream(0); + + // set up min max variables + double[] buf = new double[4]; + double[] start = new double[4]; + + int point_count = 0; + int path_count = 0; + byte pathFlag = b_polygon ? (byte) PathFlags.enumClosed : 0; + int requiredSize = b_polygon ? 3 : 2; + + // At start of rings + while (parser.nextToken() != JsonReader.Token.END_ARRAY) { + if (parser.currentToken() != JsonReader.Token.START_ARRAY) + throw new GeometryException( + "failed to parse multipath: ring/path array is expected"); + + int pathPointCount = 0; + boolean b_first = true; + int sz = 0; + int szstart = 0; + + parser.nextToken(); + while (parser.currentToken() != JsonReader.Token.END_ARRAY) { + if (parser.currentToken() != JsonReader.Token.START_ARRAY) + throw new GeometryException( + "failed to parse multipath: array is expected, rings/paths vertices consist of arrays of cooridinates"); + + sz = 0; + while (parser.nextToken() != JsonReader.Token.END_ARRAY) { + buf[sz++] = readDouble(parser); + } + + if (sz < 2) + throw new GeometryException( + "failed to parse multipath: each vertex array has to have at least 2 elements"); + + parser.nextToken(); + + do { + if (position.size() == point_count * 2) { + int c = point_count * 3; + + if (c % 2 != 0) + c++;// have to be even + if (c < 8) + c = 8; + else if (c < 32) + c = 32; + + position.resize(c); + } + + position.write(2 * point_count, buf[0]); + position.write(2 * point_count + 1, buf[1]); + + if (as.size() == point_count) { + int c = (point_count * 3) / 2;// have to be even + if (c < 4) + c = 4; + else if (c < 16) + c = 16; + as.resize(c); + } + + if (sz > 2) { + as.write(point_count, buf[2]); + } else + as.write(point_count, NumberUtils.NaN()); + + if (bs.size() == point_count) { + int c = (point_count * 3) / 2;// have to be even + if (c < 4) + c = 4; + else if (c < 16) + c = 16; + bs.resize(c); + } + + if (sz > 3) { + bs.write(point_count, buf[3]); + } else + bs.write(point_count, NumberUtils.NaN()); + + if (b_first) { + path_count++; + parts.add(point_count); + pathFlags.add(pathFlag); + b_first = false; + szstart = sz; + start[0] = buf[0]; + start[1] = buf[1]; + start[2] = buf[2]; + start[3] = buf[3]; + } + point_count++; + pathPointCount++; + } while (pathPointCount < requiredSize + && parser.currentToken() == JsonReader.Token.END_ARRAY); + } + + if (b_polygon && pathPointCount > requiredSize && sz == szstart + && start[0] == buf[0] && start[1] == buf[1] + && start[2] == buf[2] && start[3] == buf[3]) { + // remove the end point that is equal to the start point. + point_count--; + pathPointCount--; + } + + if (pathPointCount == 0) + continue;// skip empty paths + } + + if (point_count != 0) { + parts.resize(path_count); + pathFlags.resize(path_count); + + if (point_count > 0) { + parts.add(point_count); + pathFlags.add((byte) 0); + } + + MultiPathImpl mp_impl = (MultiPathImpl) multipath._getImpl(); + mp_impl.setAttributeStreamRef(Semantics.POSITION, position); + mp_impl.setPathFlagsStreamRef(pathFlags); + mp_impl.setPathStreamRef(parts); + } + return multipath; + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorImportFromJsonLocal.java b/src/main/java/com/esri/core/geometry/OperatorImportFromJsonLocal.java index bb7cb107..5c515e0f 100644 --- a/src/main/java/com/esri/core/geometry/OperatorImportFromJsonLocal.java +++ b/src/main/java/com/esri/core/geometry/OperatorImportFromJsonLocal.java @@ -25,19 +25,19 @@ class OperatorImportFromJsonLocal extends OperatorImportFromJson { - @Override - public MapGeometryCursor execute(Geometry.Type type, - JsonReaderCursor jsonParserCursor) { - return new OperatorImportFromJsonCursor(type.value(), jsonParserCursor); - } - - @Override - public MapGeometry execute(Geometry.Type type, JsonReader jsonParser) { - return OperatorImportFromJsonCursor.importFromJsonParser(type.value(), jsonParser); - } - - @Override - public MapGeometry execute(Geometry.Type type, String string) { - return execute(type, JsonParserReader.createFromString(string)); - } + @Override + public MapGeometryCursor execute(Geometry.Type type, + JsonReaderCursor jsonParserCursor) { + return new OperatorImportFromJsonCursor(type.value(), jsonParserCursor); + } + + @Override + public MapGeometry execute(Geometry.Type type, JsonReader jsonParser) { + return OperatorImportFromJsonCursor.importFromJsonParser(type.value(), jsonParser); + } + + @Override + public MapGeometry execute(Geometry.Type type, String string) { + return execute(type, JsonParserReader.createFromString(string)); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorImportFromWkb.java b/src/main/java/com/esri/core/geometry/OperatorImportFromWkb.java index 40d4ab99..6d20a2d5 100644 --- a/src/main/java/com/esri/core/geometry/OperatorImportFromWkb.java +++ b/src/main/java/com/esri/core/geometry/OperatorImportFromWkb.java @@ -33,48 +33,48 @@ */ public abstract class OperatorImportFromWkb extends Operator { - @Override - public Type getType() { - return Type.ImportFromWkb; - } - - - /** - * @param importFlags Use the {@link ShapeImportFlags} interface. The default is 0, which means geometry comes - * from a trusted source and is topologically simple. - * @param wkbBuffers The cursor over wkb buffers that hold the Geometries in wkb format. - * @param progressTracker - * @return Returns a GeometryCursor. - */ - public abstract GeometryCursor execute(int importFlags, ByteBufferCursor wkbBuffers, ProgressTracker progressTracker); - - /** - * Performs the ImportFromWKB operation. - * - * @param importFlags Use the {@link WkbImportFlags} interface. - * @param type Use the {@link Geometry.Type} enum. - * @param wkbBuffer The buffer holding the Geometry in wkb format. - * @return Returns the imported Geometry. - */ - public abstract Geometry execute(int importFlags, - Geometry.Type type, - ByteBuffer wkbBuffer, - ProgressTracker progress_tracker); - - - /** - * Performs the ImportFromWkb operation. - * - * @param importFlags Use the {@link WkbImportFlags} interface. - * @param wkbBuffer The buffer holding the Geometry in wkb format. - * @return Returns the imported OGCStructure. - */ - public abstract OGCStructure executeOGC(int importFlags, - ByteBuffer wkbBuffer, - ProgressTracker progress_tracker); - - public static OperatorImportFromWkb local() { - return (OperatorImportFromWkb) OperatorFactoryLocal.getInstance().getOperator(Type.ImportFromWkb); - } + @Override + public Type getType() { + return Type.ImportFromWkb; + } + + + /** + * @param importFlags Use the {@link ShapeImportFlags} interface. The default is 0, which means geometry comes + * from a trusted source and is topologically simple. + * @param wkbBuffers The cursor over wkb buffers that hold the Geometries in wkb format. + * @param progressTracker + * @return Returns a GeometryCursor. + */ + public abstract GeometryCursor execute(int importFlags, ByteBufferCursor wkbBuffers, ProgressTracker progressTracker); + + /** + * Performs the ImportFromWKB operation. + * + * @param importFlags Use the {@link WkbImportFlags} interface. + * @param type Use the {@link Geometry.Type} enum. + * @param wkbBuffer The buffer holding the Geometry in wkb format. + * @return Returns the imported Geometry. + */ + public abstract Geometry execute(int importFlags, + Geometry.Type type, + ByteBuffer wkbBuffer, + ProgressTracker progress_tracker); + + + /** + * Performs the ImportFromWkb operation. + * + * @param importFlags Use the {@link WkbImportFlags} interface. + * @param wkbBuffer The buffer holding the Geometry in wkb format. + * @return Returns the imported OGCStructure. + */ + public abstract OGCStructure executeOGC(int importFlags, + ByteBuffer wkbBuffer, + ProgressTracker progress_tracker); + + public static OperatorImportFromWkb local() { + return (OperatorImportFromWkb) OperatorFactoryLocal.getInstance().getOperator(Type.ImportFromWkb); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorImportFromWkbCursor.java b/src/main/java/com/esri/core/geometry/OperatorImportFromWkbCursor.java index 65b0c726..48debc90 100644 --- a/src/main/java/com/esri/core/geometry/OperatorImportFromWkbCursor.java +++ b/src/main/java/com/esri/core/geometry/OperatorImportFromWkbCursor.java @@ -1,40 +1,46 @@ package com.esri.core.geometry; public class OperatorImportFromWkbCursor extends GeometryCursor { - private ByteBufferCursor m_inputWkbBuffers; - private int m_importFlags; - - public OperatorImportFromWkbCursor(int importFlags, ByteBufferCursor wkbBuffers) { - if (wkbBuffers == null) - throw new GeometryException("invalid argument"); - - m_importFlags = importFlags; - m_inputWkbBuffers = wkbBuffers; - } - - @Override - public boolean hasNext() { return m_inputWkbBuffers != null && m_inputWkbBuffers.hasNext(); } - - @Override - public Geometry next() { - if (hasNext()) { - return OperatorImportFromWkbLocal.local().execute( - m_importFlags, - Geometry.Type.Unknown, - m_inputWkbBuffers.next(), - null); - } - return null; - } - - @Override - public long getGeometryID() { - return m_inputWkbBuffers.getByteBufferID(); - } - - @Override - public SimpleStateEnum getSimpleState() { return m_inputWkbBuffers.getSimpleState(); } - - @Override - public String getFeatureID() { return m_inputWkbBuffers.getFeatureID(); } + private ByteBufferCursor m_inputWkbBuffers; + private int m_importFlags; + + public OperatorImportFromWkbCursor(int importFlags, ByteBufferCursor wkbBuffers) { + if (wkbBuffers == null) + throw new GeometryException("invalid argument"); + + m_importFlags = importFlags; + m_inputWkbBuffers = wkbBuffers; + } + + @Override + public boolean hasNext() { + return m_inputWkbBuffers != null && m_inputWkbBuffers.hasNext(); + } + + @Override + public Geometry next() { + if (hasNext()) { + return OperatorImportFromWkbLocal.local().execute( + m_importFlags, + Geometry.Type.Unknown, + m_inputWkbBuffers.next(), + null); + } + return null; + } + + @Override + public long getGeometryID() { + return m_inputWkbBuffers.getByteBufferID(); + } + + @Override + public SimpleStateEnum getSimpleState() { + return m_inputWkbBuffers.getSimpleState(); + } + + @Override + public String getFeatureID() { + return m_inputWkbBuffers.getFeatureID(); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorImportFromWkbLocal.java b/src/main/java/com/esri/core/geometry/OperatorImportFromWkbLocal.java index 226ffe1b..181c73fe 100644 --- a/src/main/java/com/esri/core/geometry/OperatorImportFromWkbLocal.java +++ b/src/main/java/com/esri/core/geometry/OperatorImportFromWkbLocal.java @@ -33,1031 +33,1031 @@ */ class OperatorImportFromWkbLocal extends OperatorImportFromWkb { - static final class WkbHelper { - WkbHelper(ByteBuffer buffer) { - wkbBuffer = buffer; - adjustment = 0; - } + static final class WkbHelper { + WkbHelper(ByteBuffer buffer) { + wkbBuffer = buffer; + adjustment = 0; + } - int getInt(int offset) { - return wkbBuffer.getInt(adjustment + offset); - } + int getInt(int offset) { + return wkbBuffer.getInt(adjustment + offset); + } - double getDouble(int offset) { - return wkbBuffer.getDouble(adjustment + offset); - } - - ByteBuffer wkbBuffer; - int adjustment; - } - - - @Override - public GeometryCursor execute(int importFlags, ByteBufferCursor wkbBuffers, ProgressTracker progressTracker) { - return new OperatorImportFromWkbCursor(importFlags, wkbBuffers); - } - - @Override - public Geometry execute(int importFlags, Geometry.Type type, ByteBuffer wkbBuffer, ProgressTracker progress_tracker) { - - ByteOrder initialOrder = wkbBuffer.order(); - - // read byte ordering - int byteOrder = wkbBuffer.get(0); - - if (byteOrder == WkbByteOrder.wkbNDR) - wkbBuffer.order(ByteOrder.LITTLE_ENDIAN); - else - wkbBuffer.order(ByteOrder.BIG_ENDIAN); - - WkbHelper wkbHelper = new WkbHelper(wkbBuffer); - - try { - return importFromWkb(importFlags, type, wkbHelper); - } finally { - wkbBuffer.order(initialOrder); - } - } - - @Override - public OGCStructure executeOGC(int importFlags, ByteBuffer wkbBuffer, ProgressTracker progress_tracker) { - - ByteOrder initialOrder = wkbBuffer.order(); - - // read byte ordering - int byteOrder = wkbBuffer.get(0); - - if (byteOrder == WkbByteOrder.wkbNDR) - wkbBuffer.order(ByteOrder.LITTLE_ENDIAN); - else - wkbBuffer.order(ByteOrder.BIG_ENDIAN); - - ArrayList stack = new ArrayList(0); - AttributeStreamOfInt32 numGeometries = new AttributeStreamOfInt32(0); - AttributeStreamOfInt32 indices = new AttributeStreamOfInt32(0); - WkbHelper wkbHelper = new WkbHelper(wkbBuffer); - - OGCStructure root = new OGCStructure(); - root.m_structures = new ArrayList(0); - stack.add(root); // add dummy root - numGeometries.add(1); - indices.add(0); - - boolean bCheckConsistentAttributes = false; - boolean bHasZs = false; - boolean bHasMs = false; - - try { - - while (!stack.isEmpty()) { - - if (indices.getLast() == numGeometries.getLast()) { - stack.remove(stack.size() - 1); - indices.removeLast(); - numGeometries.removeLast(); - continue; - } - - OGCStructure last = stack.get(stack.size() - 1); - indices.write(indices.size() - 1, indices.getLast() + 1); - Geometry geometry; - - int wkbType = wkbHelper.getInt(1); - int ogcType; - - // strip away attributes from type identifier - - if (wkbType > 3000) { - ogcType = wkbType - 3000; - - if (bCheckConsistentAttributes) { - if (!bHasZs || !bHasMs) - throw new IllegalArgumentException(); - } else { - bHasZs = true; - bHasMs = true; - bCheckConsistentAttributes = true; - } - } else if (wkbType > 2000) { - ogcType = wkbType - 2000; - - if (bCheckConsistentAttributes) { - if (bHasZs || !bHasMs) - throw new IllegalArgumentException(); - } else { - bHasZs = false; - bHasMs = true; - bCheckConsistentAttributes = true; - } - } else if (wkbType > 1000) { - ogcType = wkbType - 1000; - - if (bCheckConsistentAttributes) { - if (!bHasZs || bHasMs) - throw new IllegalArgumentException(); - } else { - bHasZs = true; - bHasMs = false; - bCheckConsistentAttributes = true; - } - } else { - ogcType = wkbType; - - if (bCheckConsistentAttributes) { - if (bHasZs || bHasMs) - throw new IllegalArgumentException(); - } else { - bHasZs = false; - bHasMs = false; - bCheckConsistentAttributes = true; - } - } - if (ogcType == 7) { - int count = wkbHelper.getInt(5); - wkbHelper.adjustment += 9; - - OGCStructure next = new OGCStructure(); - next.m_type = ogcType; - next.m_structures = new ArrayList(0); - last.m_structures.add(next); - stack.add(next); - indices.add(0); - numGeometries.add(count); - } else { - geometry = importFromWkb(importFlags, - Geometry.Type.Unknown, wkbHelper); - OGCStructure leaf = new OGCStructure(); - leaf.m_type = ogcType; - leaf.m_geometry = geometry; - last.m_structures.add(leaf); - } - } - } finally { - wkbBuffer.order(initialOrder); - } - - return root; - } - - private static Geometry importFromWkb(int importFlags, Geometry.Type type, - WkbHelper wkbHelper) { - - // read type - int wkbType = wkbHelper.getInt(1); - - switch (wkbType) { - case WkbGeometryType.wkbPolygon: - if (type.value() != Geometry.GeometryType.Polygon - && type.value() != Geometry.GeometryType.Unknown) - throw new GeometryException("invalid shape type"); - return importFromWkbPolygon(false, importFlags, false, false, - wkbHelper); - - case WkbGeometryType.wkbPolygonM: - if (type.value() != Geometry.GeometryType.Polygon - && type.value() != Geometry.GeometryType.Unknown) - throw new GeometryException("invalid shape type"); - return importFromWkbPolygon(false, importFlags, false, true, - wkbHelper); - - case WkbGeometryType.wkbPolygonZ: - if (type.value() != Geometry.GeometryType.Polygon - && type.value() != Geometry.GeometryType.Unknown) - throw new GeometryException("invalid shape type"); - return importFromWkbPolygon(false, importFlags, true, false, - wkbHelper); - - case WkbGeometryType.wkbPolygonZM: - if (type.value() != Geometry.GeometryType.Polygon - && type.value() != Geometry.GeometryType.Unknown) - throw new GeometryException("invalid shape type"); - return importFromWkbPolygon(false, importFlags, true, true, - wkbHelper); - - case WkbGeometryType.wkbMultiPolygon: - if (type.value() != Geometry.GeometryType.Polygon - && type.value() != Geometry.GeometryType.Unknown) - throw new GeometryException("invalid shape type"); - return importFromWkbPolygon(true, importFlags, false, false, - wkbHelper); - - case WkbGeometryType.wkbMultiPolygonM: - if (type.value() != Geometry.GeometryType.Polygon - && type.value() != Geometry.GeometryType.Unknown) - throw new GeometryException("invalid shape type"); - return importFromWkbPolygon(true, importFlags, false, true, - wkbHelper); - - case WkbGeometryType.wkbMultiPolygonZ: - if (type.value() != Geometry.GeometryType.Polygon - && type.value() != Geometry.GeometryType.Unknown) - throw new GeometryException("invalid shape type"); - return importFromWkbPolygon(true, importFlags, true, false, - wkbHelper); - - case WkbGeometryType.wkbMultiPolygonZM: - if (type.value() != Geometry.GeometryType.Polygon - && type.value() != Geometry.GeometryType.Unknown) - throw new GeometryException("invalid shape type"); - return importFromWkbPolygon(true, importFlags, true, true, - wkbHelper); - - case WkbGeometryType.wkbLineString: - if (type.value() != Geometry.GeometryType.Polyline - && type.value() != Geometry.GeometryType.Unknown) - throw new GeometryException("invalid shape type"); - return importFromWkbPolyline(false, importFlags, false, false, - wkbHelper); - - case WkbGeometryType.wkbLineStringM: - if (type.value() != Geometry.GeometryType.Polyline - && type.value() != Geometry.GeometryType.Unknown) - throw new GeometryException("invalid shape type"); - return importFromWkbPolyline(false, importFlags, false, true, - wkbHelper); - - case WkbGeometryType.wkbLineStringZ: - if (type.value() != Geometry.GeometryType.Polyline - && type.value() != Geometry.GeometryType.Unknown) - throw new GeometryException("invalid shape type"); - return importFromWkbPolyline(false, importFlags, true, false, - wkbHelper); - - case WkbGeometryType.wkbLineStringZM: - if (type.value() != Geometry.GeometryType.Polyline - && type.value() != Geometry.GeometryType.Unknown) - throw new GeometryException("invalid shape type"); - return importFromWkbPolyline(false, importFlags, true, true, - wkbHelper); - - case WkbGeometryType.wkbMultiLineString: - if (type.value() != Geometry.GeometryType.Polyline - && type.value() != Geometry.GeometryType.Unknown) - throw new GeometryException("invalid shape type"); - return importFromWkbPolyline(true, importFlags, false, false, - wkbHelper); - - case WkbGeometryType.wkbMultiLineStringM: - if (type.value() != Geometry.GeometryType.Polyline - && type.value() != Geometry.GeometryType.Unknown) - throw new GeometryException("invalid shape type"); - return importFromWkbPolyline(true, importFlags, false, true, - wkbHelper); - - case WkbGeometryType.wkbMultiLineStringZ: - if (type.value() != Geometry.GeometryType.Polyline - && type.value() != Geometry.GeometryType.Unknown) - throw new GeometryException("invalid shape type"); - return importFromWkbPolyline(true, importFlags, true, false, - wkbHelper); - - case WkbGeometryType.wkbMultiLineStringZM: - if (type.value() != Geometry.GeometryType.Polyline - && type.value() != Geometry.GeometryType.Unknown) - throw new GeometryException("invalid shape type"); - return importFromWkbPolyline(true, importFlags, true, true, - wkbHelper); - - case WkbGeometryType.wkbMultiPoint: - if (type.value() != Geometry.GeometryType.MultiPoint - && type.value() != Geometry.GeometryType.Unknown) - throw new GeometryException("invalid shape type"); - return importFromWkbMultiPoint(importFlags, false, false, wkbHelper); - - case WkbGeometryType.wkbMultiPointM: - if (type.value() != Geometry.GeometryType.MultiPoint - && type.value() != Geometry.GeometryType.Unknown) - throw new GeometryException("invalid shape type"); - return importFromWkbMultiPoint(importFlags, false, true, wkbHelper); - - case WkbGeometryType.wkbMultiPointZ: - if (type.value() != Geometry.GeometryType.MultiPoint - && type.value() != Geometry.GeometryType.Unknown) - throw new GeometryException("invalid shape type"); - return importFromWkbMultiPoint(importFlags, true, false, wkbHelper); - - case WkbGeometryType.wkbMultiPointZM: - if (type.value() != Geometry.GeometryType.MultiPoint - && type.value() != Geometry.GeometryType.Unknown) - throw new GeometryException("invalid shape type"); - return importFromWkbMultiPoint(importFlags, true, true, wkbHelper); - - case WkbGeometryType.wkbPoint: - if (type.value() != Geometry.GeometryType.Point - && type.value() != Geometry.GeometryType.Unknown) - throw new GeometryException("invalid shape type"); - return importFromWkbPoint(importFlags, false, false, wkbHelper); - - case WkbGeometryType.wkbPointM: - if (type.value() != Geometry.GeometryType.Point - && type.value() != Geometry.GeometryType.Unknown) - throw new GeometryException("invalid shape type"); - return importFromWkbPoint(importFlags, false, true, wkbHelper); - - case WkbGeometryType.wkbPointZ: - if (type.value() != Geometry.GeometryType.Point - && type.value() != Geometry.GeometryType.Unknown) - throw new GeometryException("invalid shape type"); - return importFromWkbPoint(importFlags, true, false, wkbHelper); - - case WkbGeometryType.wkbPointZM: - if (type.value() != Geometry.GeometryType.Point - && type.value() != Geometry.GeometryType.Unknown) - throw new GeometryException("invalid shape type"); - return importFromWkbPoint(importFlags, true, true, wkbHelper); - - default: - throw new GeometryException("invalid shape type"); - } - } - - private static Geometry importFromWkbPolygon(boolean bMultiPolygon, - int importFlags, boolean bZs, boolean bMs, WkbHelper wkbHelper) { - int offset; - int polygonCount; - - if (bMultiPolygon) { - polygonCount = wkbHelper.getInt(5); - offset = 9; - } else { - polygonCount = 1; - offset = 0; - } - - // Find total point count and part count - int point_count = 0; - int partCount = 0; - int tempOffset = offset; - for (int ipolygon = 0; ipolygon < polygonCount; ipolygon++) { - tempOffset += 5; // skip redundant byte order and type fields - int ipartcount = wkbHelper.getInt(tempOffset); - tempOffset += 4; - - for (int ipart = 0; ipart < ipartcount; ipart++) { - int ipointcount = wkbHelper.getInt(tempOffset); - tempOffset += 4; - - // If ipointcount == 0, then we have an empty part - if (ipointcount == 0) - continue; - - if (ipointcount <= 2) { - tempOffset += ipointcount * 2 * 8; - - if (bZs) - tempOffset += ipointcount * 8; - - if (bMs) - tempOffset += ipointcount * 8; - - if (ipointcount == 1) - point_count += ipointcount + 1; - else - point_count += ipointcount; - - partCount++; - - continue; - } - - double startx = wkbHelper.getDouble(tempOffset); - tempOffset += 8; - double starty = wkbHelper.getDouble(tempOffset); - tempOffset += 8; - double startz = NumberUtils.TheNaN; - double startm = NumberUtils.TheNaN; - - if (bZs) { - startz = wkbHelper.getDouble(tempOffset); - tempOffset += 8; - } - - if (bMs) { - startm = wkbHelper.getDouble(tempOffset); - tempOffset += 8; - } - - tempOffset += (ipointcount - 2) * 2 * 8; - - if (bZs) - tempOffset += (ipointcount - 2) * 8; - - if (bMs) - tempOffset += (ipointcount - 2) * 8; - - double endx = wkbHelper.getDouble(tempOffset); - tempOffset += 8; - double endy = wkbHelper.getDouble(tempOffset); - tempOffset += 8; - double endz = NumberUtils.TheNaN; - double endm = NumberUtils.TheNaN; - - if (bZs) { - endz = wkbHelper.getDouble(tempOffset); - tempOffset += 8; - } - - if (bMs) { - endm = wkbHelper.getDouble(tempOffset); - tempOffset += 8; - } - - if ((startx == endx || (NumberUtils.isNaN(startx) && NumberUtils - .isNaN(endx))) - && (starty == endy || (NumberUtils.isNaN(starty) && NumberUtils - .isNaN(endy))) - && (!bZs || startz == endz || (NumberUtils - .isNaN(startz) && NumberUtils.isNaN(endz))) - && (!bMs || startm == endm || (NumberUtils - .isNaN(startm) && NumberUtils.isNaN(endm)))) { - point_count += ipointcount - 1; - } else { - point_count += ipointcount; - } - - partCount++; - } - } - - AttributeStreamOfDbl position = null; - AttributeStreamOfDbl zs = null; - AttributeStreamOfDbl ms = null; - AttributeStreamOfInt32 parts = null; - AttributeStreamOfInt8 pathFlags = null; - - Geometry newPolygon; - MultiPathImpl polygon; - - newPolygon = new Polygon(); - polygon = (MultiPathImpl) newPolygon._getImpl(); - - if (bZs) - polygon.addAttribute(VertexDescription.Semantics.Z); - - if (bMs) - polygon.addAttribute(VertexDescription.Semantics.M); - - if (point_count > 0) { - parts = (AttributeStreamOfInt32) (AttributeStreamBase - .createIndexStream(partCount + 1, 0)); - pathFlags = (AttributeStreamOfInt8) (AttributeStreamBase - .createByteStream(parts.size(), (byte) PathFlags.enumClosed)); - position = (AttributeStreamOfDbl) (AttributeStreamBase - .createAttributeStreamWithSemantics( - VertexDescription.Semantics.POSITION, point_count)); - - if (bZs) - zs = (AttributeStreamOfDbl) (AttributeStreamBase - .createAttributeStreamWithSemantics( - VertexDescription.Semantics.Z, point_count)); - - if (bMs) - ms = (AttributeStreamOfDbl) (AttributeStreamBase - .createAttributeStreamWithSemantics( - VertexDescription.Semantics.M, point_count)); - } - - boolean bCreateMs = false, bCreateZs = false; - int ipartend = 0; - int ipolygonend = 0; - int part_index = 0; - - // read Coordinates - for (int ipolygon = 0; ipolygon < polygonCount; ipolygon++) { - offset += 5; // skip redundant byte order and type fields - int ipartcount = wkbHelper.getInt(offset); - offset += 4; - int ipolygonstart = ipolygonend; - ipolygonend = ipolygonstart + ipartcount; - - for (int ipart = ipolygonstart; ipart < ipolygonend; ipart++) { - int ipointcount = wkbHelper.getInt(offset); - offset += 4; - - if (ipointcount == 0) - continue; - - int ipartstart = ipartend; - ipartend += ipointcount; - boolean bSkipLastPoint = true; - - if (ipointcount == 1) { - ipartstart++; - ipartend++; - bSkipLastPoint = false; - } else if (ipointcount == 2) { - bSkipLastPoint = false; - } else { - // Check if start point is equal to end point - - tempOffset = offset; - - double startx = wkbHelper.getDouble(tempOffset); - tempOffset += 8; - double starty = wkbHelper.getDouble(tempOffset); - tempOffset += 8; - double startz = NumberUtils.TheNaN; - double startm = NumberUtils.TheNaN; - - if (bZs) { - startz = wkbHelper.getDouble(tempOffset); - tempOffset += 8; - } - - if (bMs) { - startm = wkbHelper.getDouble(tempOffset); - tempOffset += 8; - } - - tempOffset += (ipointcount - 2) * 2 * 8; - - if (bZs) - tempOffset += (ipointcount - 2) * 8; - - if (bMs) - tempOffset += (ipointcount - 2) * 8; - - double endx = wkbHelper.getDouble(tempOffset); - tempOffset += 8; - double endy = wkbHelper.getDouble(tempOffset); - tempOffset += 8; - double endz = NumberUtils.TheNaN; - double endm = NumberUtils.TheNaN; - - if (bZs) { - endz = wkbHelper.getDouble(tempOffset); - tempOffset += 8; - } - - if (bMs) { - endm = wkbHelper.getDouble(tempOffset); - tempOffset += 8; - } - - if ((startx == endx || (NumberUtils.isNaN(startx) && NumberUtils - .isNaN(endx))) - && (starty == endy || (NumberUtils.isNaN(starty) && NumberUtils - .isNaN(endy))) - && (!bZs || startz == endz || (NumberUtils - .isNaN(startz) && NumberUtils.isNaN(endz))) - && (!bMs || startm == endm || (NumberUtils - .isNaN(startm) && NumberUtils.isNaN(endm)))) - ipartend--; - else - bSkipLastPoint = false; - } - - if (ipart == ipolygonstart) - pathFlags.setBits(ipart, - (byte) PathFlags.enumOGCStartPolygon); - - parts.write(++part_index, ipartend); - - // We must write from the buffer backwards - ogc polygon - // format is opposite of shapefile format - for (int i = ipartstart; i < ipartend; i++) { - double x = wkbHelper.getDouble(offset); - offset += 8; - double y = wkbHelper.getDouble(offset); - offset += 8; - - position.write(2 * i, x); - position.write(2 * i + 1, y); - - if (bZs) { - double z = wkbHelper.getDouble(offset); - offset += 8; - - zs.write(i, z); - if (!VertexDescription.isDefaultValue( - VertexDescription.Semantics.Z, z)) - bCreateZs = true; - } - - if (bMs) { - double m = wkbHelper.getDouble(offset); - offset += 8; - - ms.write(i, m); - if (!VertexDescription.isDefaultValue( - VertexDescription.Semantics.M, m)) - bCreateMs = true; - } - } - - if (bSkipLastPoint) { - offset += 2 * 8; - - if (bZs) - offset += 8; - - if (bMs) - offset += 8; - } else if (ipointcount == 1) { - double x = position.read(2 * ipartstart); - double y = position.read(2 * ipartstart + 1); - position.write(2 * (ipartstart - 1), x); - position.write(2 * (ipartstart - 1) + 1, y); - - if (bZs) { - double z = zs.read(ipartstart); - zs.write(ipartstart - 1, z); - } - - if (bMs) { - double m = ms.read(ipartstart); - ms.write(ipartstart - 1, m); - } - } - } - } - - // set envelopes and assign AttributeStreams - - if (point_count > 0) { - polygon.setPathStreamRef(parts); // sets m_parts - polygon.setPathFlagsStreamRef(pathFlags); - polygon.setAttributeStreamRef(VertexDescription.Semantics.POSITION, - position); - - if (bZs) { - if (!bCreateZs) - zs = null; - - polygon.setAttributeStreamRef(VertexDescription.Semantics.Z, zs); - } - - if (bMs) { - if (!bCreateMs) - ms = null; - - polygon.setAttributeStreamRef(VertexDescription.Semantics.M, ms); - } - - polygon.notifyModified(MultiPathImpl.DirtyFlags.DirtyAll); - - AttributeStreamOfInt8 path_flags_clone = new AttributeStreamOfInt8( - pathFlags); - - for (int i = 0; i < path_flags_clone.size() - 1; i++) { - if (((int) path_flags_clone.read(i) & (int) PathFlags.enumOGCStartPolygon) != 0) {// Should - // be - // clockwise - if (!InternalUtils.isClockwiseRing(polygon, i)) - polygon.reversePath(i); // make clockwise - } else {// Should be counter-clockwise - if (InternalUtils.isClockwiseRing(polygon, i)) - polygon.reversePath(i); // make counter-clockwise - } - } - - polygon.setPathFlagsStreamRef(path_flags_clone); - } - - if ((importFlags & (int) WkbImportFlags.wkbImportNonTrusted) == 0) - polygon.setIsSimple(MultiVertexGeometryImpl.GeometryXSimple.Weak, - 0.0, false); - - polygon.setDirtyOGCFlags(false); - wkbHelper.adjustment += offset; - - return newPolygon; - } - - private static Geometry importFromWkbPolyline(boolean bMultiPolyline, - int importFlags, boolean bZs, boolean bMs, WkbHelper wkbHelper) { - int offset; - int originalPartCount; - - if (bMultiPolyline) { - originalPartCount = wkbHelper.getInt(5); - offset = 9; - } else { - originalPartCount = 1; - offset = 0; - } - - // Find total point count and part count - int point_count = 0; - int partCount = 0; - int tempOffset = offset; - for (int ipart = 0; ipart < originalPartCount; ipart++) { - tempOffset += 5; // skip redundant byte order and type fields - int ipointcount = wkbHelper.getInt(tempOffset); - tempOffset += 4; - - // If ipointcount == 0, then we have an empty part - if (ipointcount == 0) - continue; - - point_count += ipointcount; - partCount++; - - if (ipointcount == 1) - point_count++; - - tempOffset += ipointcount * 2 * 8; - - if (bZs) - tempOffset += ipointcount * 8; - - if (bMs) - tempOffset += ipointcount * 8; - } - - AttributeStreamOfDbl position = null; - AttributeStreamOfDbl zs = null; - AttributeStreamOfDbl ms = null; - AttributeStreamOfInt32 parts = null; - AttributeStreamOfInt8 pathFlags = null; - - Polyline newpolyline; - MultiPathImpl polyline; - - newpolyline = new Polyline(); - polyline = (MultiPathImpl) newpolyline._getImpl(); - - if (bZs) - polyline.addAttribute(VertexDescription.Semantics.Z); - - if (bMs) - polyline.addAttribute(VertexDescription.Semantics.M); - - if (point_count > 0) { - parts = (AttributeStreamOfInt32) (AttributeStreamBase - .createIndexStream(partCount + 1, 0)); - pathFlags = (AttributeStreamOfInt8) (AttributeStreamBase - .createByteStream(parts.size(), (byte) 0)); - position = (AttributeStreamOfDbl) (AttributeStreamBase - .createAttributeStreamWithSemantics( - VertexDescription.Semantics.POSITION, point_count)); - - if (bZs) - zs = (AttributeStreamOfDbl) (AttributeStreamBase - .createAttributeStreamWithSemantics( - VertexDescription.Semantics.Z, point_count)); - - if (bMs) - ms = (AttributeStreamOfDbl) (AttributeStreamBase - .createAttributeStreamWithSemantics( - VertexDescription.Semantics.M, point_count)); - } - - boolean bCreateMs = false, bCreateZs = false; - int ipartend = 0; - int part_index = 0; - - // read Coordinates - for (int ipart = 0; ipart < originalPartCount; ipart++) { - offset += 5; // skip redundant byte order and type fields - - int ipointcount = wkbHelper.getInt(offset); - offset += 4; - - if (ipointcount == 0) - continue; - - int ipartstart = ipartend; - ipartend = ipartstart + ipointcount; - - if (ipointcount == 1) { - ipartstart++; - ipartend++; - } - - parts.write(++part_index, ipartend); - - for (int i = ipartstart; i < ipartend; i++) { - double x = wkbHelper.getDouble(offset); - offset += 8; - double y = wkbHelper.getDouble(offset); - offset += 8; - - position.write(2 * i, x); - position.write(2 * i + 1, y); - - if (bZs) { - double z = wkbHelper.getDouble(offset); - offset += 8; - - zs.write(i, z); - if (!VertexDescription.isDefaultValue( - VertexDescription.Semantics.Z, z)) - bCreateZs = true; - } - - if (bMs) { - double m = wkbHelper.getDouble(offset); - offset += 8; - - ms.write(i, m); - if (!VertexDescription.isDefaultValue( - VertexDescription.Semantics.M, m)) - bCreateMs = true; - } - } - - if (ipointcount == 1) { - double x = position.read(2 * ipartstart); - double y = position.read(2 * ipartstart + 1); - position.write(2 * (ipartstart - 1), x); - position.write(2 * (ipartstart - 1) + 1, y); - - if (bZs) { - double z = zs.read(ipartstart); - zs.write(ipartstart - 1, z); - } - - if (bMs) { - double m = ms.read(ipartstart); - ms.write(ipartstart - 1, m); - } - } - } - - // set envelopes and assign AttributeStreams - - if (point_count > 0) { - polyline.setPathStreamRef(parts); // sets m_parts - polyline.setPathFlagsStreamRef(pathFlags); - polyline.setAttributeStreamRef( - VertexDescription.Semantics.POSITION, position); - - if (bZs) { - if (!bCreateZs) - zs = null; - - polyline.setAttributeStreamRef(VertexDescription.Semantics.Z, - zs); - } - - if (bMs) { - if (!bCreateMs) - ms = null; - - polyline.setAttributeStreamRef(VertexDescription.Semantics.M, - ms); - } - - polyline.notifyModified(MultiPathImpl.DirtyFlags.DirtyAll); - } - - wkbHelper.adjustment += offset; - - return newpolyline; - } - - private static Geometry importFromWkbMultiPoint(int importFlags, - boolean bZs, boolean bMs, WkbHelper wkbHelper) { - int offset = 5; // skip byte order and type - - // set point count - int point_count = wkbHelper.getInt(offset); - offset += 4; - - AttributeStreamOfDbl position = null; - AttributeStreamOfDbl zs = null; - AttributeStreamOfDbl ms = null; - - MultiPoint newmultipoint; - MultiPointImpl multipoint; - - newmultipoint = new MultiPoint(); - multipoint = (MultiPointImpl) newmultipoint._getImpl(); - - if (bZs) - multipoint.addAttribute(VertexDescription.Semantics.Z); - - if (bMs) - multipoint.addAttribute(VertexDescription.Semantics.M); - - if (point_count > 0) { - position = (AttributeStreamOfDbl) (AttributeStreamBase - .createAttributeStreamWithSemantics( - VertexDescription.Semantics.POSITION, point_count)); - - if (bZs) - zs = (AttributeStreamOfDbl) (AttributeStreamBase - .createAttributeStreamWithSemantics( - VertexDescription.Semantics.Z, point_count)); - - if (bMs) - ms = (AttributeStreamOfDbl) (AttributeStreamBase - .createAttributeStreamWithSemantics( - VertexDescription.Semantics.M, point_count)); - } - - boolean bCreateMs = false, bCreateZs = false; - for (int i = 0; i < point_count; i++) { - offset += 5; // skip redundant byte order and type fields - - // read xy coordinates - double x = wkbHelper.getDouble(offset); - offset += 8; - double y = wkbHelper.getDouble(offset); - offset += 8; - - position.write(2 * i, x); - position.write(2 * i + 1, y); - - if (bZs) { - double z = wkbHelper.getDouble(offset); - offset += 8; - - zs.write(i, z); - if (!VertexDescription.isDefaultValue( - VertexDescription.Semantics.Z, z)) - bCreateZs = true; - } - - if (bMs) { - double m = wkbHelper.getDouble(offset); - offset += 8; - - ms.write(i, m); - if (!VertexDescription.isDefaultValue( - VertexDescription.Semantics.M, m)) - bCreateMs = true; - } - } - - // set envelopes and assign AttributeStreams - - if (point_count > 0) { - multipoint.resize(point_count); - multipoint.setAttributeStreamRef( - VertexDescription.Semantics.POSITION, position); - - if (bZs) { - if (!bCreateZs) - zs = null; - - multipoint.setAttributeStreamRef(VertexDescription.Semantics.Z, - zs); - } - - if (bMs) { - if (!bCreateMs) - ms = null; - - multipoint.setAttributeStreamRef(VertexDescription.Semantics.M, - ms); - } - - multipoint.notifyModified(MultiPointImpl.DirtyFlags.DirtyAll); - } - - wkbHelper.adjustment += offset; - - return newmultipoint; - } - - private static Geometry importFromWkbPoint(int importFlags, boolean bZs, - boolean bMs, WkbHelper wkbHelper) { - int offset = 5; // skip byte order and type - - // set xy coordinate - double x = wkbHelper.getDouble(offset); - offset += 8; - double y = wkbHelper.getDouble(offset); - offset += 8; - - double z = NumberUtils.TheNaN; - if (bZs) { - z = wkbHelper.getDouble(offset); - offset += 8; - } - - double m = NumberUtils.TheNaN; - if (bMs) { - m = wkbHelper.getDouble(offset); - offset += 8; - } - - boolean bEmpty = NumberUtils.isNaN(x); - Point point = new Point(); - - if (!bEmpty) { - point.setX(x); - point.setY(y); - } - - // set Z - if (bZs) { - point.addAttribute(VertexDescription.Semantics.Z); - if (!bEmpty) - point.setZ(z); - } - - // set M - if (bMs) { - point.addAttribute(VertexDescription.Semantics.M); - if (!bEmpty) - point.setM(m); - } - - wkbHelper.adjustment += offset; - - return point; - } + double getDouble(int offset) { + return wkbBuffer.getDouble(adjustment + offset); + } + + ByteBuffer wkbBuffer; + int adjustment; + } + + + @Override + public GeometryCursor execute(int importFlags, ByteBufferCursor wkbBuffers, ProgressTracker progressTracker) { + return new OperatorImportFromWkbCursor(importFlags, wkbBuffers); + } + + @Override + public Geometry execute(int importFlags, Geometry.Type type, ByteBuffer wkbBuffer, ProgressTracker progress_tracker) { + + ByteOrder initialOrder = wkbBuffer.order(); + + // read byte ordering + int byteOrder = wkbBuffer.get(0); + + if (byteOrder == WkbByteOrder.wkbNDR) + wkbBuffer.order(ByteOrder.LITTLE_ENDIAN); + else + wkbBuffer.order(ByteOrder.BIG_ENDIAN); + + WkbHelper wkbHelper = new WkbHelper(wkbBuffer); + + try { + return importFromWkb(importFlags, type, wkbHelper); + } finally { + wkbBuffer.order(initialOrder); + } + } + + @Override + public OGCStructure executeOGC(int importFlags, ByteBuffer wkbBuffer, ProgressTracker progress_tracker) { + + ByteOrder initialOrder = wkbBuffer.order(); + + // read byte ordering + int byteOrder = wkbBuffer.get(0); + + if (byteOrder == WkbByteOrder.wkbNDR) + wkbBuffer.order(ByteOrder.LITTLE_ENDIAN); + else + wkbBuffer.order(ByteOrder.BIG_ENDIAN); + + ArrayList stack = new ArrayList(0); + AttributeStreamOfInt32 numGeometries = new AttributeStreamOfInt32(0); + AttributeStreamOfInt32 indices = new AttributeStreamOfInt32(0); + WkbHelper wkbHelper = new WkbHelper(wkbBuffer); + + OGCStructure root = new OGCStructure(); + root.m_structures = new ArrayList(0); + stack.add(root); // add dummy root + numGeometries.add(1); + indices.add(0); + + boolean bCheckConsistentAttributes = false; + boolean bHasZs = false; + boolean bHasMs = false; + + try { + + while (!stack.isEmpty()) { + + if (indices.getLast() == numGeometries.getLast()) { + stack.remove(stack.size() - 1); + indices.removeLast(); + numGeometries.removeLast(); + continue; + } + + OGCStructure last = stack.get(stack.size() - 1); + indices.write(indices.size() - 1, indices.getLast() + 1); + Geometry geometry; + + int wkbType = wkbHelper.getInt(1); + int ogcType; + + // strip away attributes from type identifier + + if (wkbType > 3000) { + ogcType = wkbType - 3000; + + if (bCheckConsistentAttributes) { + if (!bHasZs || !bHasMs) + throw new IllegalArgumentException(); + } else { + bHasZs = true; + bHasMs = true; + bCheckConsistentAttributes = true; + } + } else if (wkbType > 2000) { + ogcType = wkbType - 2000; + + if (bCheckConsistentAttributes) { + if (bHasZs || !bHasMs) + throw new IllegalArgumentException(); + } else { + bHasZs = false; + bHasMs = true; + bCheckConsistentAttributes = true; + } + } else if (wkbType > 1000) { + ogcType = wkbType - 1000; + + if (bCheckConsistentAttributes) { + if (!bHasZs || bHasMs) + throw new IllegalArgumentException(); + } else { + bHasZs = true; + bHasMs = false; + bCheckConsistentAttributes = true; + } + } else { + ogcType = wkbType; + + if (bCheckConsistentAttributes) { + if (bHasZs || bHasMs) + throw new IllegalArgumentException(); + } else { + bHasZs = false; + bHasMs = false; + bCheckConsistentAttributes = true; + } + } + if (ogcType == 7) { + int count = wkbHelper.getInt(5); + wkbHelper.adjustment += 9; + + OGCStructure next = new OGCStructure(); + next.m_type = ogcType; + next.m_structures = new ArrayList(0); + last.m_structures.add(next); + stack.add(next); + indices.add(0); + numGeometries.add(count); + } else { + geometry = importFromWkb(importFlags, + Geometry.Type.Unknown, wkbHelper); + OGCStructure leaf = new OGCStructure(); + leaf.m_type = ogcType; + leaf.m_geometry = geometry; + last.m_structures.add(leaf); + } + } + } finally { + wkbBuffer.order(initialOrder); + } + + return root; + } + + private static Geometry importFromWkb(int importFlags, Geometry.Type type, + WkbHelper wkbHelper) { + + // read type + int wkbType = wkbHelper.getInt(1); + + switch (wkbType) { + case WkbGeometryType.wkbPolygon: + if (type.value() != Geometry.GeometryType.Polygon + && type.value() != Geometry.GeometryType.Unknown) + throw new GeometryException("invalid shape type"); + return importFromWkbPolygon(false, importFlags, false, false, + wkbHelper); + + case WkbGeometryType.wkbPolygonM: + if (type.value() != Geometry.GeometryType.Polygon + && type.value() != Geometry.GeometryType.Unknown) + throw new GeometryException("invalid shape type"); + return importFromWkbPolygon(false, importFlags, false, true, + wkbHelper); + + case WkbGeometryType.wkbPolygonZ: + if (type.value() != Geometry.GeometryType.Polygon + && type.value() != Geometry.GeometryType.Unknown) + throw new GeometryException("invalid shape type"); + return importFromWkbPolygon(false, importFlags, true, false, + wkbHelper); + + case WkbGeometryType.wkbPolygonZM: + if (type.value() != Geometry.GeometryType.Polygon + && type.value() != Geometry.GeometryType.Unknown) + throw new GeometryException("invalid shape type"); + return importFromWkbPolygon(false, importFlags, true, true, + wkbHelper); + + case WkbGeometryType.wkbMultiPolygon: + if (type.value() != Geometry.GeometryType.Polygon + && type.value() != Geometry.GeometryType.Unknown) + throw new GeometryException("invalid shape type"); + return importFromWkbPolygon(true, importFlags, false, false, + wkbHelper); + + case WkbGeometryType.wkbMultiPolygonM: + if (type.value() != Geometry.GeometryType.Polygon + && type.value() != Geometry.GeometryType.Unknown) + throw new GeometryException("invalid shape type"); + return importFromWkbPolygon(true, importFlags, false, true, + wkbHelper); + + case WkbGeometryType.wkbMultiPolygonZ: + if (type.value() != Geometry.GeometryType.Polygon + && type.value() != Geometry.GeometryType.Unknown) + throw new GeometryException("invalid shape type"); + return importFromWkbPolygon(true, importFlags, true, false, + wkbHelper); + + case WkbGeometryType.wkbMultiPolygonZM: + if (type.value() != Geometry.GeometryType.Polygon + && type.value() != Geometry.GeometryType.Unknown) + throw new GeometryException("invalid shape type"); + return importFromWkbPolygon(true, importFlags, true, true, + wkbHelper); + + case WkbGeometryType.wkbLineString: + if (type.value() != Geometry.GeometryType.Polyline + && type.value() != Geometry.GeometryType.Unknown) + throw new GeometryException("invalid shape type"); + return importFromWkbPolyline(false, importFlags, false, false, + wkbHelper); + + case WkbGeometryType.wkbLineStringM: + if (type.value() != Geometry.GeometryType.Polyline + && type.value() != Geometry.GeometryType.Unknown) + throw new GeometryException("invalid shape type"); + return importFromWkbPolyline(false, importFlags, false, true, + wkbHelper); + + case WkbGeometryType.wkbLineStringZ: + if (type.value() != Geometry.GeometryType.Polyline + && type.value() != Geometry.GeometryType.Unknown) + throw new GeometryException("invalid shape type"); + return importFromWkbPolyline(false, importFlags, true, false, + wkbHelper); + + case WkbGeometryType.wkbLineStringZM: + if (type.value() != Geometry.GeometryType.Polyline + && type.value() != Geometry.GeometryType.Unknown) + throw new GeometryException("invalid shape type"); + return importFromWkbPolyline(false, importFlags, true, true, + wkbHelper); + + case WkbGeometryType.wkbMultiLineString: + if (type.value() != Geometry.GeometryType.Polyline + && type.value() != Geometry.GeometryType.Unknown) + throw new GeometryException("invalid shape type"); + return importFromWkbPolyline(true, importFlags, false, false, + wkbHelper); + + case WkbGeometryType.wkbMultiLineStringM: + if (type.value() != Geometry.GeometryType.Polyline + && type.value() != Geometry.GeometryType.Unknown) + throw new GeometryException("invalid shape type"); + return importFromWkbPolyline(true, importFlags, false, true, + wkbHelper); + + case WkbGeometryType.wkbMultiLineStringZ: + if (type.value() != Geometry.GeometryType.Polyline + && type.value() != Geometry.GeometryType.Unknown) + throw new GeometryException("invalid shape type"); + return importFromWkbPolyline(true, importFlags, true, false, + wkbHelper); + + case WkbGeometryType.wkbMultiLineStringZM: + if (type.value() != Geometry.GeometryType.Polyline + && type.value() != Geometry.GeometryType.Unknown) + throw new GeometryException("invalid shape type"); + return importFromWkbPolyline(true, importFlags, true, true, + wkbHelper); + + case WkbGeometryType.wkbMultiPoint: + if (type.value() != Geometry.GeometryType.MultiPoint + && type.value() != Geometry.GeometryType.Unknown) + throw new GeometryException("invalid shape type"); + return importFromWkbMultiPoint(importFlags, false, false, wkbHelper); + + case WkbGeometryType.wkbMultiPointM: + if (type.value() != Geometry.GeometryType.MultiPoint + && type.value() != Geometry.GeometryType.Unknown) + throw new GeometryException("invalid shape type"); + return importFromWkbMultiPoint(importFlags, false, true, wkbHelper); + + case WkbGeometryType.wkbMultiPointZ: + if (type.value() != Geometry.GeometryType.MultiPoint + && type.value() != Geometry.GeometryType.Unknown) + throw new GeometryException("invalid shape type"); + return importFromWkbMultiPoint(importFlags, true, false, wkbHelper); + + case WkbGeometryType.wkbMultiPointZM: + if (type.value() != Geometry.GeometryType.MultiPoint + && type.value() != Geometry.GeometryType.Unknown) + throw new GeometryException("invalid shape type"); + return importFromWkbMultiPoint(importFlags, true, true, wkbHelper); + + case WkbGeometryType.wkbPoint: + if (type.value() != Geometry.GeometryType.Point + && type.value() != Geometry.GeometryType.Unknown) + throw new GeometryException("invalid shape type"); + return importFromWkbPoint(importFlags, false, false, wkbHelper); + + case WkbGeometryType.wkbPointM: + if (type.value() != Geometry.GeometryType.Point + && type.value() != Geometry.GeometryType.Unknown) + throw new GeometryException("invalid shape type"); + return importFromWkbPoint(importFlags, false, true, wkbHelper); + + case WkbGeometryType.wkbPointZ: + if (type.value() != Geometry.GeometryType.Point + && type.value() != Geometry.GeometryType.Unknown) + throw new GeometryException("invalid shape type"); + return importFromWkbPoint(importFlags, true, false, wkbHelper); + + case WkbGeometryType.wkbPointZM: + if (type.value() != Geometry.GeometryType.Point + && type.value() != Geometry.GeometryType.Unknown) + throw new GeometryException("invalid shape type"); + return importFromWkbPoint(importFlags, true, true, wkbHelper); + + default: + throw new GeometryException("invalid shape type"); + } + } + + private static Geometry importFromWkbPolygon(boolean bMultiPolygon, + int importFlags, boolean bZs, boolean bMs, WkbHelper wkbHelper) { + int offset; + int polygonCount; + + if (bMultiPolygon) { + polygonCount = wkbHelper.getInt(5); + offset = 9; + } else { + polygonCount = 1; + offset = 0; + } + + // Find total point count and part count + int point_count = 0; + int partCount = 0; + int tempOffset = offset; + for (int ipolygon = 0; ipolygon < polygonCount; ipolygon++) { + tempOffset += 5; // skip redundant byte order and type fields + int ipartcount = wkbHelper.getInt(tempOffset); + tempOffset += 4; + + for (int ipart = 0; ipart < ipartcount; ipart++) { + int ipointcount = wkbHelper.getInt(tempOffset); + tempOffset += 4; + + // If ipointcount == 0, then we have an empty part + if (ipointcount == 0) + continue; + + if (ipointcount <= 2) { + tempOffset += ipointcount * 2 * 8; + + if (bZs) + tempOffset += ipointcount * 8; + + if (bMs) + tempOffset += ipointcount * 8; + + if (ipointcount == 1) + point_count += ipointcount + 1; + else + point_count += ipointcount; + + partCount++; + + continue; + } + + double startx = wkbHelper.getDouble(tempOffset); + tempOffset += 8; + double starty = wkbHelper.getDouble(tempOffset); + tempOffset += 8; + double startz = NumberUtils.TheNaN; + double startm = NumberUtils.TheNaN; + + if (bZs) { + startz = wkbHelper.getDouble(tempOffset); + tempOffset += 8; + } + + if (bMs) { + startm = wkbHelper.getDouble(tempOffset); + tempOffset += 8; + } + + tempOffset += (ipointcount - 2) * 2 * 8; + + if (bZs) + tempOffset += (ipointcount - 2) * 8; + + if (bMs) + tempOffset += (ipointcount - 2) * 8; + + double endx = wkbHelper.getDouble(tempOffset); + tempOffset += 8; + double endy = wkbHelper.getDouble(tempOffset); + tempOffset += 8; + double endz = NumberUtils.TheNaN; + double endm = NumberUtils.TheNaN; + + if (bZs) { + endz = wkbHelper.getDouble(tempOffset); + tempOffset += 8; + } + + if (bMs) { + endm = wkbHelper.getDouble(tempOffset); + tempOffset += 8; + } + + if ((startx == endx || (NumberUtils.isNaN(startx) && NumberUtils + .isNaN(endx))) + && (starty == endy || (NumberUtils.isNaN(starty) && NumberUtils + .isNaN(endy))) + && (!bZs || startz == endz || (NumberUtils + .isNaN(startz) && NumberUtils.isNaN(endz))) + && (!bMs || startm == endm || (NumberUtils + .isNaN(startm) && NumberUtils.isNaN(endm)))) { + point_count += ipointcount - 1; + } else { + point_count += ipointcount; + } + + partCount++; + } + } + + AttributeStreamOfDbl position = null; + AttributeStreamOfDbl zs = null; + AttributeStreamOfDbl ms = null; + AttributeStreamOfInt32 parts = null; + AttributeStreamOfInt8 pathFlags = null; + + Geometry newPolygon; + MultiPathImpl polygon; + + newPolygon = new Polygon(); + polygon = (MultiPathImpl) newPolygon._getImpl(); + + if (bZs) + polygon.addAttribute(VertexDescription.Semantics.Z); + + if (bMs) + polygon.addAttribute(VertexDescription.Semantics.M); + + if (point_count > 0) { + parts = (AttributeStreamOfInt32) (AttributeStreamBase + .createIndexStream(partCount + 1, 0)); + pathFlags = (AttributeStreamOfInt8) (AttributeStreamBase + .createByteStream(parts.size(), (byte) PathFlags.enumClosed)); + position = (AttributeStreamOfDbl) (AttributeStreamBase + .createAttributeStreamWithSemantics( + VertexDescription.Semantics.POSITION, point_count)); + + if (bZs) + zs = (AttributeStreamOfDbl) (AttributeStreamBase + .createAttributeStreamWithSemantics( + VertexDescription.Semantics.Z, point_count)); + + if (bMs) + ms = (AttributeStreamOfDbl) (AttributeStreamBase + .createAttributeStreamWithSemantics( + VertexDescription.Semantics.M, point_count)); + } + + boolean bCreateMs = false, bCreateZs = false; + int ipartend = 0; + int ipolygonend = 0; + int part_index = 0; + + // read Coordinates + for (int ipolygon = 0; ipolygon < polygonCount; ipolygon++) { + offset += 5; // skip redundant byte order and type fields + int ipartcount = wkbHelper.getInt(offset); + offset += 4; + int ipolygonstart = ipolygonend; + ipolygonend = ipolygonstart + ipartcount; + + for (int ipart = ipolygonstart; ipart < ipolygonend; ipart++) { + int ipointcount = wkbHelper.getInt(offset); + offset += 4; + + if (ipointcount == 0) + continue; + + int ipartstart = ipartend; + ipartend += ipointcount; + boolean bSkipLastPoint = true; + + if (ipointcount == 1) { + ipartstart++; + ipartend++; + bSkipLastPoint = false; + } else if (ipointcount == 2) { + bSkipLastPoint = false; + } else { + // Check if start point is equal to end point + + tempOffset = offset; + + double startx = wkbHelper.getDouble(tempOffset); + tempOffset += 8; + double starty = wkbHelper.getDouble(tempOffset); + tempOffset += 8; + double startz = NumberUtils.TheNaN; + double startm = NumberUtils.TheNaN; + + if (bZs) { + startz = wkbHelper.getDouble(tempOffset); + tempOffset += 8; + } + + if (bMs) { + startm = wkbHelper.getDouble(tempOffset); + tempOffset += 8; + } + + tempOffset += (ipointcount - 2) * 2 * 8; + + if (bZs) + tempOffset += (ipointcount - 2) * 8; + + if (bMs) + tempOffset += (ipointcount - 2) * 8; + + double endx = wkbHelper.getDouble(tempOffset); + tempOffset += 8; + double endy = wkbHelper.getDouble(tempOffset); + tempOffset += 8; + double endz = NumberUtils.TheNaN; + double endm = NumberUtils.TheNaN; + + if (bZs) { + endz = wkbHelper.getDouble(tempOffset); + tempOffset += 8; + } + + if (bMs) { + endm = wkbHelper.getDouble(tempOffset); + tempOffset += 8; + } + + if ((startx == endx || (NumberUtils.isNaN(startx) && NumberUtils + .isNaN(endx))) + && (starty == endy || (NumberUtils.isNaN(starty) && NumberUtils + .isNaN(endy))) + && (!bZs || startz == endz || (NumberUtils + .isNaN(startz) && NumberUtils.isNaN(endz))) + && (!bMs || startm == endm || (NumberUtils + .isNaN(startm) && NumberUtils.isNaN(endm)))) + ipartend--; + else + bSkipLastPoint = false; + } + + if (ipart == ipolygonstart) + pathFlags.setBits(ipart, + (byte) PathFlags.enumOGCStartPolygon); + + parts.write(++part_index, ipartend); + + // We must write from the buffer backwards - ogc polygon + // format is opposite of shapefile format + for (int i = ipartstart; i < ipartend; i++) { + double x = wkbHelper.getDouble(offset); + offset += 8; + double y = wkbHelper.getDouble(offset); + offset += 8; + + position.write(2 * i, x); + position.write(2 * i + 1, y); + + if (bZs) { + double z = wkbHelper.getDouble(offset); + offset += 8; + + zs.write(i, z); + if (!VertexDescription.isDefaultValue( + VertexDescription.Semantics.Z, z)) + bCreateZs = true; + } + + if (bMs) { + double m = wkbHelper.getDouble(offset); + offset += 8; + + ms.write(i, m); + if (!VertexDescription.isDefaultValue( + VertexDescription.Semantics.M, m)) + bCreateMs = true; + } + } + + if (bSkipLastPoint) { + offset += 2 * 8; + + if (bZs) + offset += 8; + + if (bMs) + offset += 8; + } else if (ipointcount == 1) { + double x = position.read(2 * ipartstart); + double y = position.read(2 * ipartstart + 1); + position.write(2 * (ipartstart - 1), x); + position.write(2 * (ipartstart - 1) + 1, y); + + if (bZs) { + double z = zs.read(ipartstart); + zs.write(ipartstart - 1, z); + } + + if (bMs) { + double m = ms.read(ipartstart); + ms.write(ipartstart - 1, m); + } + } + } + } + + // set envelopes and assign AttributeStreams + + if (point_count > 0) { + polygon.setPathStreamRef(parts); // sets m_parts + polygon.setPathFlagsStreamRef(pathFlags); + polygon.setAttributeStreamRef(VertexDescription.Semantics.POSITION, + position); + + if (bZs) { + if (!bCreateZs) + zs = null; + + polygon.setAttributeStreamRef(VertexDescription.Semantics.Z, zs); + } + + if (bMs) { + if (!bCreateMs) + ms = null; + + polygon.setAttributeStreamRef(VertexDescription.Semantics.M, ms); + } + + polygon.notifyModified(MultiPathImpl.DirtyFlags.DirtyAll); + + AttributeStreamOfInt8 path_flags_clone = new AttributeStreamOfInt8( + pathFlags); + + for (int i = 0; i < path_flags_clone.size() - 1; i++) { + if (((int) path_flags_clone.read(i) & (int) PathFlags.enumOGCStartPolygon) != 0) {// Should + // be + // clockwise + if (!InternalUtils.isClockwiseRing(polygon, i)) + polygon.reversePath(i); // make clockwise + } else {// Should be counter-clockwise + if (InternalUtils.isClockwiseRing(polygon, i)) + polygon.reversePath(i); // make counter-clockwise + } + } + + polygon.setPathFlagsStreamRef(path_flags_clone); + } + + if ((importFlags & (int) WkbImportFlags.wkbImportNonTrusted) == 0) + polygon.setIsSimple(MultiVertexGeometryImpl.GeometryXSimple.Weak, + 0.0, false); + + polygon.setDirtyOGCFlags(false); + wkbHelper.adjustment += offset; + + return newPolygon; + } + + private static Geometry importFromWkbPolyline(boolean bMultiPolyline, + int importFlags, boolean bZs, boolean bMs, WkbHelper wkbHelper) { + int offset; + int originalPartCount; + + if (bMultiPolyline) { + originalPartCount = wkbHelper.getInt(5); + offset = 9; + } else { + originalPartCount = 1; + offset = 0; + } + + // Find total point count and part count + int point_count = 0; + int partCount = 0; + int tempOffset = offset; + for (int ipart = 0; ipart < originalPartCount; ipart++) { + tempOffset += 5; // skip redundant byte order and type fields + int ipointcount = wkbHelper.getInt(tempOffset); + tempOffset += 4; + + // If ipointcount == 0, then we have an empty part + if (ipointcount == 0) + continue; + + point_count += ipointcount; + partCount++; + + if (ipointcount == 1) + point_count++; + + tempOffset += ipointcount * 2 * 8; + + if (bZs) + tempOffset += ipointcount * 8; + + if (bMs) + tempOffset += ipointcount * 8; + } + + AttributeStreamOfDbl position = null; + AttributeStreamOfDbl zs = null; + AttributeStreamOfDbl ms = null; + AttributeStreamOfInt32 parts = null; + AttributeStreamOfInt8 pathFlags = null; + + Polyline newpolyline; + MultiPathImpl polyline; + + newpolyline = new Polyline(); + polyline = (MultiPathImpl) newpolyline._getImpl(); + + if (bZs) + polyline.addAttribute(VertexDescription.Semantics.Z); + + if (bMs) + polyline.addAttribute(VertexDescription.Semantics.M); + + if (point_count > 0) { + parts = (AttributeStreamOfInt32) (AttributeStreamBase + .createIndexStream(partCount + 1, 0)); + pathFlags = (AttributeStreamOfInt8) (AttributeStreamBase + .createByteStream(parts.size(), (byte) 0)); + position = (AttributeStreamOfDbl) (AttributeStreamBase + .createAttributeStreamWithSemantics( + VertexDescription.Semantics.POSITION, point_count)); + + if (bZs) + zs = (AttributeStreamOfDbl) (AttributeStreamBase + .createAttributeStreamWithSemantics( + VertexDescription.Semantics.Z, point_count)); + + if (bMs) + ms = (AttributeStreamOfDbl) (AttributeStreamBase + .createAttributeStreamWithSemantics( + VertexDescription.Semantics.M, point_count)); + } + + boolean bCreateMs = false, bCreateZs = false; + int ipartend = 0; + int part_index = 0; + + // read Coordinates + for (int ipart = 0; ipart < originalPartCount; ipart++) { + offset += 5; // skip redundant byte order and type fields + + int ipointcount = wkbHelper.getInt(offset); + offset += 4; + + if (ipointcount == 0) + continue; + + int ipartstart = ipartend; + ipartend = ipartstart + ipointcount; + + if (ipointcount == 1) { + ipartstart++; + ipartend++; + } + + parts.write(++part_index, ipartend); + + for (int i = ipartstart; i < ipartend; i++) { + double x = wkbHelper.getDouble(offset); + offset += 8; + double y = wkbHelper.getDouble(offset); + offset += 8; + + position.write(2 * i, x); + position.write(2 * i + 1, y); + + if (bZs) { + double z = wkbHelper.getDouble(offset); + offset += 8; + + zs.write(i, z); + if (!VertexDescription.isDefaultValue( + VertexDescription.Semantics.Z, z)) + bCreateZs = true; + } + + if (bMs) { + double m = wkbHelper.getDouble(offset); + offset += 8; + + ms.write(i, m); + if (!VertexDescription.isDefaultValue( + VertexDescription.Semantics.M, m)) + bCreateMs = true; + } + } + + if (ipointcount == 1) { + double x = position.read(2 * ipartstart); + double y = position.read(2 * ipartstart + 1); + position.write(2 * (ipartstart - 1), x); + position.write(2 * (ipartstart - 1) + 1, y); + + if (bZs) { + double z = zs.read(ipartstart); + zs.write(ipartstart - 1, z); + } + + if (bMs) { + double m = ms.read(ipartstart); + ms.write(ipartstart - 1, m); + } + } + } + + // set envelopes and assign AttributeStreams + + if (point_count > 0) { + polyline.setPathStreamRef(parts); // sets m_parts + polyline.setPathFlagsStreamRef(pathFlags); + polyline.setAttributeStreamRef( + VertexDescription.Semantics.POSITION, position); + + if (bZs) { + if (!bCreateZs) + zs = null; + + polyline.setAttributeStreamRef(VertexDescription.Semantics.Z, + zs); + } + + if (bMs) { + if (!bCreateMs) + ms = null; + + polyline.setAttributeStreamRef(VertexDescription.Semantics.M, + ms); + } + + polyline.notifyModified(MultiPathImpl.DirtyFlags.DirtyAll); + } + + wkbHelper.adjustment += offset; + + return newpolyline; + } + + private static Geometry importFromWkbMultiPoint(int importFlags, + boolean bZs, boolean bMs, WkbHelper wkbHelper) { + int offset = 5; // skip byte order and type + + // set point count + int point_count = wkbHelper.getInt(offset); + offset += 4; + + AttributeStreamOfDbl position = null; + AttributeStreamOfDbl zs = null; + AttributeStreamOfDbl ms = null; + + MultiPoint newmultipoint; + MultiPointImpl multipoint; + + newmultipoint = new MultiPoint(); + multipoint = (MultiPointImpl) newmultipoint._getImpl(); + + if (bZs) + multipoint.addAttribute(VertexDescription.Semantics.Z); + + if (bMs) + multipoint.addAttribute(VertexDescription.Semantics.M); + + if (point_count > 0) { + position = (AttributeStreamOfDbl) (AttributeStreamBase + .createAttributeStreamWithSemantics( + VertexDescription.Semantics.POSITION, point_count)); + + if (bZs) + zs = (AttributeStreamOfDbl) (AttributeStreamBase + .createAttributeStreamWithSemantics( + VertexDescription.Semantics.Z, point_count)); + + if (bMs) + ms = (AttributeStreamOfDbl) (AttributeStreamBase + .createAttributeStreamWithSemantics( + VertexDescription.Semantics.M, point_count)); + } + + boolean bCreateMs = false, bCreateZs = false; + for (int i = 0; i < point_count; i++) { + offset += 5; // skip redundant byte order and type fields + + // read xy coordinates + double x = wkbHelper.getDouble(offset); + offset += 8; + double y = wkbHelper.getDouble(offset); + offset += 8; + + position.write(2 * i, x); + position.write(2 * i + 1, y); + + if (bZs) { + double z = wkbHelper.getDouble(offset); + offset += 8; + + zs.write(i, z); + if (!VertexDescription.isDefaultValue( + VertexDescription.Semantics.Z, z)) + bCreateZs = true; + } + + if (bMs) { + double m = wkbHelper.getDouble(offset); + offset += 8; + + ms.write(i, m); + if (!VertexDescription.isDefaultValue( + VertexDescription.Semantics.M, m)) + bCreateMs = true; + } + } + + // set envelopes and assign AttributeStreams + + if (point_count > 0) { + multipoint.resize(point_count); + multipoint.setAttributeStreamRef( + VertexDescription.Semantics.POSITION, position); + + if (bZs) { + if (!bCreateZs) + zs = null; + + multipoint.setAttributeStreamRef(VertexDescription.Semantics.Z, + zs); + } + + if (bMs) { + if (!bCreateMs) + ms = null; + + multipoint.setAttributeStreamRef(VertexDescription.Semantics.M, + ms); + } + + multipoint.notifyModified(MultiPointImpl.DirtyFlags.DirtyAll); + } + + wkbHelper.adjustment += offset; + + return newmultipoint; + } + + private static Geometry importFromWkbPoint(int importFlags, boolean bZs, + boolean bMs, WkbHelper wkbHelper) { + int offset = 5; // skip byte order and type + + // set xy coordinate + double x = wkbHelper.getDouble(offset); + offset += 8; + double y = wkbHelper.getDouble(offset); + offset += 8; + + double z = NumberUtils.TheNaN; + if (bZs) { + z = wkbHelper.getDouble(offset); + offset += 8; + } + + double m = NumberUtils.TheNaN; + if (bMs) { + m = wkbHelper.getDouble(offset); + offset += 8; + } + + boolean bEmpty = NumberUtils.isNaN(x); + Point point = new Point(); + + if (!bEmpty) { + point.setX(x); + point.setY(y); + } + + // set Z + if (bZs) { + point.addAttribute(VertexDescription.Semantics.Z); + if (!bEmpty) + point.setZ(z); + } + + // set M + if (bMs) { + point.addAttribute(VertexDescription.Semantics.M); + if (!bEmpty) + point.setM(m); + } + + wkbHelper.adjustment += offset; + + return point; + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorImportFromWkt.java b/src/main/java/com/esri/core/geometry/OperatorImportFromWkt.java index 62e68255..fa4c3705 100644 --- a/src/main/java/com/esri/core/geometry/OperatorImportFromWkt.java +++ b/src/main/java/com/esri/core/geometry/OperatorImportFromWkt.java @@ -24,41 +24,41 @@ package com.esri.core.geometry; public abstract class OperatorImportFromWkt extends Operator { - @Override - public Type getType() { - return Type.ImportFromWkb; - } + @Override + public Type getType() { + return Type.ImportFromWkb; + } - public abstract GeometryCursor execute(int import_flags, - SimpleStringCursor wkt_stringCursor, - ProgressTracker progress_tracker); + public abstract GeometryCursor execute(int import_flags, + SimpleStringCursor wkt_stringCursor, + ProgressTracker progress_tracker); - /** - * Performs the ImportFromWkt operation. - * - * @param import_flags Use the {@link WktImportFlags} interface. - * @param type Use the {@link Geometry.Type} enum. - * @param wkt_string The string holding the Geometry in wkt format. - * @return Returns the imported Geometry. - */ - public abstract Geometry execute(int import_flags, - Geometry.Type type, - String wkt_string, - ProgressTracker progress_tracker); + /** + * Performs the ImportFromWkt operation. + * + * @param import_flags Use the {@link WktImportFlags} interface. + * @param type Use the {@link Geometry.Type} enum. + * @param wkt_string The string holding the Geometry in wkt format. + * @return Returns the imported Geometry. + */ + public abstract Geometry execute(int import_flags, + Geometry.Type type, + String wkt_string, + ProgressTracker progress_tracker); - /** - * Performs the ImportFromWkt operation. - * - * @param import_flags Use the {@link WktImportFlags} interface. - * @param wkt_string The string holding the Geometry in wkt format. - * @return Returns the imported OGCStructure. - */ - public abstract OGCStructure executeOGC(int import_flags, - String wkt_string, ProgressTracker progress_tracker); + /** + * Performs the ImportFromWkt operation. + * + * @param import_flags Use the {@link WktImportFlags} interface. + * @param wkt_string The string holding the Geometry in wkt format. + * @return Returns the imported OGCStructure. + */ + public abstract OGCStructure executeOGC(int import_flags, + String wkt_string, ProgressTracker progress_tracker); - public static OperatorImportFromWkt local() { - return (OperatorImportFromWkt) OperatorFactoryLocal.getInstance() - .getOperator(Type.ImportFromWkt); - } + public static OperatorImportFromWkt local() { + return (OperatorImportFromWkt) OperatorFactoryLocal.getInstance() + .getOperator(Type.ImportFromWkt); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorImportFromWktCursor.java b/src/main/java/com/esri/core/geometry/OperatorImportFromWktCursor.java index 0c3b3f53..9866db0a 100644 --- a/src/main/java/com/esri/core/geometry/OperatorImportFromWktCursor.java +++ b/src/main/java/com/esri/core/geometry/OperatorImportFromWktCursor.java @@ -1,40 +1,46 @@ package com.esri.core.geometry; public class OperatorImportFromWktCursor extends GeometryCursor { - private StringCursor m_wktStringCursor; - private int m_importFlags; - - public OperatorImportFromWktCursor(int import_flags, StringCursor stringCursor) { - if (stringCursor == null) - throw new GeometryException("invalid argument"); - - m_importFlags = import_flags; - m_wktStringCursor = stringCursor; - } - - @Override - public boolean hasNext() { return m_wktStringCursor != null && m_wktStringCursor.hasNext(); } - - @Override - public Geometry next() { - if (hasNext()) { - return OperatorImportFromWkt.local().execute( - m_importFlags, - Geometry.Type.Unknown, - m_wktStringCursor.next(), - null); - } - return null; - } - - @Override - public long getGeometryID() { - return m_wktStringCursor.getID(); - } - - @Override - public SimpleStateEnum getSimpleState() { return m_wktStringCursor.getSimpleState(); } - - @Override - public String getFeatureID() { return m_wktStringCursor.getFeatureID(); } + private StringCursor m_wktStringCursor; + private int m_importFlags; + + public OperatorImportFromWktCursor(int import_flags, StringCursor stringCursor) { + if (stringCursor == null) + throw new GeometryException("invalid argument"); + + m_importFlags = import_flags; + m_wktStringCursor = stringCursor; + } + + @Override + public boolean hasNext() { + return m_wktStringCursor != null && m_wktStringCursor.hasNext(); + } + + @Override + public Geometry next() { + if (hasNext()) { + return OperatorImportFromWkt.local().execute( + m_importFlags, + Geometry.Type.Unknown, + m_wktStringCursor.next(), + null); + } + return null; + } + + @Override + public long getGeometryID() { + return m_wktStringCursor.getID(); + } + + @Override + public SimpleStateEnum getSimpleState() { + return m_wktStringCursor.getSimpleState(); + } + + @Override + public String getFeatureID() { + return m_wktStringCursor.getFeatureID(); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorImportFromWktLocal.java b/src/main/java/com/esri/core/geometry/OperatorImportFromWktLocal.java index 65b30c63..d2d67bd7 100644 --- a/src/main/java/com/esri/core/geometry/OperatorImportFromWktLocal.java +++ b/src/main/java/com/esri/core/geometry/OperatorImportFromWktLocal.java @@ -28,643 +28,643 @@ class OperatorImportFromWktLocal extends OperatorImportFromWkt { - @Override - public GeometryCursor execute(int import_flags, SimpleStringCursor wkt_stringCursor, ProgressTracker progress_tracker) { - return new OperatorImportFromWktCursor(import_flags, wkt_stringCursor); - } - - - @Override - public Geometry execute(int import_flags, Geometry.Type type, - String wkt_string, ProgressTracker progress_tracker) { - WktParser wkt_parser = new WktParser(wkt_string); - int current_token = wkt_parser.nextToken(); - return importFromWkt(import_flags, type, wkt_parser); - } - - @Override - public OGCStructure executeOGC(int import_flags, String wkt_string, - ProgressTracker progress_tracker) { - ArrayList stack = new ArrayList(0); - WktParser wkt_parser = new WktParser(wkt_string); - - OGCStructure root = new OGCStructure(); - root.m_structures = new ArrayList(0); - stack.add(root); // add dummy root - - while (wkt_parser.nextToken() != WktParser.WktToken.not_available) { - int current_token = wkt_parser.currentToken(); - - if (current_token == WktParser.WktToken.right_paren) { - stack.remove(stack.size() - 1); - continue; - } - - int ogc_type = current_token; - OGCStructure last = stack.get(stack.size() - 1); - - if (current_token == WktParser.WktToken.geometrycollection) { - current_token = wkt_parser.nextToken(); - - if (current_token == WktParser.WktToken.attribute_z - || current_token == WktParser.WktToken.attribute_m - || current_token == WktParser.WktToken.attribute_zm) - wkt_parser.nextToken(); - - OGCStructure next = new OGCStructure(); - next.m_type = ogc_type; - next.m_structures = new ArrayList(0); - last.m_structures.add(next); - - if (current_token != WktParser.WktToken.empty) - stack.add(next); - continue; - } - - Geometry geometry = importFromWkt(import_flags, - Geometry.Type.Unknown, wkt_parser); - - OGCStructure leaf = new OGCStructure(); - leaf.m_type = ogc_type; - leaf.m_geometry = geometry; - last.m_structures.add(leaf); - } - - return root; - } - - static Geometry importFromWkt(int import_flags, Geometry.Type type, - WktParser wkt_parser) { - int current_token = wkt_parser.currentToken(); - - switch (current_token) { - case WktParser.WktToken.multipolygon: - if (type != Geometry.Type.Polygon && type != Geometry.Type.Unknown) - throw new IllegalArgumentException("invalid shapetype"); - return polygonTaggedText(true, import_flags, wkt_parser); - - case WktParser.WktToken.multilinestring: - if (type != Geometry.Type.Polyline && type != Geometry.Type.Unknown) - throw new IllegalArgumentException("invalid shapetype"); - return lineStringTaggedText(true, import_flags, wkt_parser); - - case WktParser.WktToken.multipoint: - if (type != Geometry.Type.MultiPoint - && type != Geometry.Type.Unknown) - throw new IllegalArgumentException("invalid shapetype"); - return multiPointTaggedText(import_flags, wkt_parser); - - case WktParser.WktToken.polygon: - if (type != Geometry.Type.Polygon && type != Geometry.Type.Unknown) - throw new IllegalArgumentException("invalid shapetype"); - return polygonTaggedText(false, import_flags, wkt_parser); - - case WktParser.WktToken.linestring: - if (type != Geometry.Type.Polyline && type != Geometry.Type.Unknown) - throw new IllegalArgumentException("invalid shapetype"); - return lineStringTaggedText(false, import_flags, wkt_parser); - - case WktParser.WktToken.point: - if (type != Geometry.Type.Point && type != Geometry.Type.Unknown) - throw new IllegalArgumentException("invalid shapetype"); - return pointTaggedText(import_flags, wkt_parser); - - default: - break; // warning fix - } - - return null; - } - - static Geometry polygonTaggedText(boolean b_multi_polygon, - int import_flags, WktParser wkt_parser) { - MultiPath multi_path; - MultiPathImpl multi_path_impl; - AttributeStreamOfDbl zs = null; - AttributeStreamOfDbl ms = null; - AttributeStreamOfDbl position; - AttributeStreamOfInt32 paths; - AttributeStreamOfInt8 path_flags; - - position = (AttributeStreamOfDbl) AttributeStreamBase - .createDoubleStream(0); - paths = (AttributeStreamOfInt32) AttributeStreamBase.createIndexStream( - 1, 0); - path_flags = (AttributeStreamOfInt8) AttributeStreamBase - .createByteStream(1, (byte) 0); - - multi_path = new Polygon(); - multi_path_impl = (MultiPathImpl) multi_path._getImpl(); - - int current_token = wkt_parser.nextToken(); - - if (current_token == WktParser.WktToken.attribute_z) { - zs = (AttributeStreamOfDbl) AttributeStreamBase.createDoubleStream( - 0, NumberUtils.TheNaN); - multi_path_impl.addAttribute(VertexDescription.Semantics.Z); - wkt_parser.nextToken(); - } else if (current_token == WktParser.WktToken.attribute_m) { - ms = (AttributeStreamOfDbl) AttributeStreamBase.createDoubleStream( - 0, NumberUtils.TheNaN); - multi_path_impl.addAttribute(VertexDescription.Semantics.M); - wkt_parser.nextToken(); - } else if (current_token == WktParser.WktToken.attribute_zm) { - zs = (AttributeStreamOfDbl) AttributeStreamBase.createDoubleStream( - 0, NumberUtils.TheNaN); - ms = (AttributeStreamOfDbl) AttributeStreamBase.createDoubleStream( - 0, NumberUtils.TheNaN); - multi_path_impl.addAttribute(VertexDescription.Semantics.Z); - multi_path_impl.addAttribute(VertexDescription.Semantics.M); - wkt_parser.nextToken(); - } - - int point_count; - - if (b_multi_polygon) - point_count = multiPolygonText(zs, ms, position, paths, path_flags, - wkt_parser); - else - point_count = polygonText(zs, ms, position, paths, path_flags, 0, - wkt_parser); - - if (point_count != 0) { - assert (2 * point_count == position.size()); - multi_path_impl.setAttributeStreamRef( - VertexDescription.Semantics.POSITION, position); - multi_path_impl.setPathStreamRef(paths); - multi_path_impl.setPathFlagsStreamRef(path_flags); - - if (zs != null) - multi_path_impl.setAttributeStreamRef( - VertexDescription.Semantics.Z, zs); - - if (ms != null) - multi_path_impl.setAttributeStreamRef( - VertexDescription.Semantics.M, ms); - - multi_path_impl.notifyModified(MultiPathImpl.DirtyFlags.DirtyAll); - - AttributeStreamOfInt8 path_flags_clone = new AttributeStreamOfInt8( - path_flags); - - for (int i = 0; i < path_flags_clone.size() - 1; i++) { - if (((int) path_flags_clone.read(i) & (int) PathFlags.enumOGCStartPolygon) != 0) {// Should - // be - // clockwise - if (!InternalUtils.isClockwiseRing(multi_path_impl, i)) - multi_path_impl.reversePath(i); // make clockwise - } else {// Should be counter-clockwise - if (InternalUtils.isClockwiseRing(multi_path_impl, i)) - multi_path_impl.reversePath(i); // make - // counter-clockwise - } - } - - multi_path_impl.setPathFlagsStreamRef(path_flags_clone); - } - - if ((import_flags & (int) WktImportFlags.wktImportNonTrusted) == 0) - multi_path_impl.setIsSimple(MultiPathImpl.GeometryXSimple.Weak, - 0.0, false); - - multi_path_impl.setDirtyOGCFlags(false); - - return multi_path; - } - - static Geometry lineStringTaggedText(boolean b_multi_linestring, - int import_flags, WktParser wkt_parser) { - MultiPath multi_path; - MultiPathImpl multi_path_impl; - AttributeStreamOfDbl zs = null; - AttributeStreamOfDbl ms = null; - AttributeStreamOfDbl position; - AttributeStreamOfInt32 paths; - AttributeStreamOfInt8 path_flags; - - position = (AttributeStreamOfDbl) AttributeStreamBase - .createDoubleStream(0); - paths = (AttributeStreamOfInt32) AttributeStreamBase.createIndexStream( - 1, 0); - path_flags = (AttributeStreamOfInt8) AttributeStreamBase - .createByteStream(1, (byte) 0); - - multi_path = new Polyline(); - multi_path_impl = (MultiPathImpl) multi_path._getImpl(); - - int current_token = wkt_parser.nextToken(); - - if (current_token == WktParser.WktToken.attribute_z) { - zs = (AttributeStreamOfDbl) AttributeStreamBase.createDoubleStream( - 0, NumberUtils.TheNaN); - multi_path_impl.addAttribute(VertexDescription.Semantics.Z); - wkt_parser.nextToken(); - } else if (current_token == WktParser.WktToken.attribute_m) { - ms = (AttributeStreamOfDbl) AttributeStreamBase.createDoubleStream( - 0, NumberUtils.TheNaN); - multi_path_impl.addAttribute(VertexDescription.Semantics.M); - wkt_parser.nextToken(); - } else if (current_token == WktParser.WktToken.attribute_zm) { - zs = (AttributeStreamOfDbl) AttributeStreamBase.createDoubleStream( - 0, NumberUtils.TheNaN); - ms = (AttributeStreamOfDbl) AttributeStreamBase.createDoubleStream( - 0, NumberUtils.TheNaN); - multi_path_impl.addAttribute(VertexDescription.Semantics.Z); - multi_path_impl.addAttribute(VertexDescription.Semantics.M); - wkt_parser.nextToken(); - } - - int point_count; - - if (b_multi_linestring) - point_count = multiLineStringText(zs, ms, position, paths, - path_flags, wkt_parser); - else - point_count = lineStringText(false, zs, ms, position, paths, - path_flags, wkt_parser); - - if (point_count != 0) { - assert (2 * point_count == position.size()); - multi_path_impl.setAttributeStreamRef( - VertexDescription.Semantics.POSITION, position); - multi_path_impl.setPathStreamRef(paths); - multi_path_impl.setPathFlagsStreamRef(path_flags); - - if (zs != null) - multi_path_impl.setAttributeStreamRef( - VertexDescription.Semantics.Z, zs); - - if (ms != null) - multi_path_impl.setAttributeStreamRef( - VertexDescription.Semantics.M, ms); - - multi_path_impl.notifyModified(MultiPathImpl.DirtyFlags.DirtyAll); - } - - return multi_path; - } - - static Geometry multiPointTaggedText(int import_flags, WktParser wkt_parser) { - MultiPoint multi_point; - MultiPointImpl multi_point_impl; - AttributeStreamOfDbl zs = null; - AttributeStreamOfDbl ms = null; - AttributeStreamOfDbl position; - - position = (AttributeStreamOfDbl) AttributeStreamBase - .createDoubleStream(0); - - multi_point = new MultiPoint(); - multi_point_impl = (MultiPointImpl) multi_point._getImpl(); - - int current_token = wkt_parser.nextToken(); - - if (current_token == WktParser.WktToken.attribute_z) { - zs = (AttributeStreamOfDbl) AttributeStreamBase.createDoubleStream( - 0, NumberUtils.TheNaN); - multi_point_impl.addAttribute(VertexDescription.Semantics.Z); - wkt_parser.nextToken(); - } else if (current_token == WktParser.WktToken.attribute_m) { - ms = (AttributeStreamOfDbl) AttributeStreamBase.createDoubleStream( - 0, NumberUtils.TheNaN); - multi_point_impl.addAttribute(VertexDescription.Semantics.M); - wkt_parser.nextToken(); - } else if (current_token == WktParser.WktToken.attribute_zm) { - zs = (AttributeStreamOfDbl) AttributeStreamBase.createDoubleStream( - 0, NumberUtils.TheNaN); - ms = (AttributeStreamOfDbl) AttributeStreamBase.createDoubleStream( - 0, NumberUtils.TheNaN); - multi_point_impl.addAttribute(VertexDescription.Semantics.Z); - multi_point_impl.addAttribute(VertexDescription.Semantics.M); - wkt_parser.nextToken(); - } - - int point_count = multiPointText(zs, ms, position, wkt_parser); - - if (point_count != 0) { - assert (2 * point_count == position.size()); - multi_point_impl.resize(point_count); - multi_point_impl.setAttributeStreamRef( - VertexDescription.Semantics.POSITION, position); - - if (zs != null) - multi_point_impl.setAttributeStreamRef( - VertexDescription.Semantics.Z, zs); - - if (ms != null) - multi_point_impl.setAttributeStreamRef( - VertexDescription.Semantics.M, ms); - - multi_point_impl.notifyModified(MultiPointImpl.DirtyFlags.DirtyAll); - } - - return multi_point; - } - - static Geometry pointTaggedText(int import_flags, WktParser wkt_parser) { - Point point = new Point(); - - int current_token = wkt_parser.nextToken(); - - if (current_token == WktParser.WktToken.attribute_z) { - point.addAttribute(VertexDescription.Semantics.Z); - wkt_parser.nextToken(); - } else if (current_token == WktParser.WktToken.attribute_m) { - point.addAttribute(VertexDescription.Semantics.M); - wkt_parser.nextToken(); - } else if (current_token == WktParser.WktToken.attribute_zm) { - point.addAttribute(VertexDescription.Semantics.Z); - point.addAttribute(VertexDescription.Semantics.M); - wkt_parser.nextToken(); - } - // At start of PointText + @Override + public GeometryCursor execute(int import_flags, SimpleStringCursor wkt_stringCursor, ProgressTracker progress_tracker) { + return new OperatorImportFromWktCursor(import_flags, wkt_stringCursor); + } + + + @Override + public Geometry execute(int import_flags, Geometry.Type type, + String wkt_string, ProgressTracker progress_tracker) { + WktParser wkt_parser = new WktParser(wkt_string); + int current_token = wkt_parser.nextToken(); + return importFromWkt(import_flags, type, wkt_parser); + } + + @Override + public OGCStructure executeOGC(int import_flags, String wkt_string, + ProgressTracker progress_tracker) { + ArrayList stack = new ArrayList(0); + WktParser wkt_parser = new WktParser(wkt_string); + + OGCStructure root = new OGCStructure(); + root.m_structures = new ArrayList(0); + stack.add(root); // add dummy root + + while (wkt_parser.nextToken() != WktParser.WktToken.not_available) { + int current_token = wkt_parser.currentToken(); + + if (current_token == WktParser.WktToken.right_paren) { + stack.remove(stack.size() - 1); + continue; + } + + int ogc_type = current_token; + OGCStructure last = stack.get(stack.size() - 1); + + if (current_token == WktParser.WktToken.geometrycollection) { + current_token = wkt_parser.nextToken(); + + if (current_token == WktParser.WktToken.attribute_z + || current_token == WktParser.WktToken.attribute_m + || current_token == WktParser.WktToken.attribute_zm) + wkt_parser.nextToken(); + + OGCStructure next = new OGCStructure(); + next.m_type = ogc_type; + next.m_structures = new ArrayList(0); + last.m_structures.add(next); + + if (current_token != WktParser.WktToken.empty) + stack.add(next); + continue; + } + + Geometry geometry = importFromWkt(import_flags, + Geometry.Type.Unknown, wkt_parser); + + OGCStructure leaf = new OGCStructure(); + leaf.m_type = ogc_type; + leaf.m_geometry = geometry; + last.m_structures.add(leaf); + } + + return root; + } + + static Geometry importFromWkt(int import_flags, Geometry.Type type, + WktParser wkt_parser) { + int current_token = wkt_parser.currentToken(); + + switch (current_token) { + case WktParser.WktToken.multipolygon: + if (type != Geometry.Type.Polygon && type != Geometry.Type.Unknown) + throw new IllegalArgumentException("invalid shapetype"); + return polygonTaggedText(true, import_flags, wkt_parser); + + case WktParser.WktToken.multilinestring: + if (type != Geometry.Type.Polyline && type != Geometry.Type.Unknown) + throw new IllegalArgumentException("invalid shapetype"); + return lineStringTaggedText(true, import_flags, wkt_parser); + + case WktParser.WktToken.multipoint: + if (type != Geometry.Type.MultiPoint + && type != Geometry.Type.Unknown) + throw new IllegalArgumentException("invalid shapetype"); + return multiPointTaggedText(import_flags, wkt_parser); + + case WktParser.WktToken.polygon: + if (type != Geometry.Type.Polygon && type != Geometry.Type.Unknown) + throw new IllegalArgumentException("invalid shapetype"); + return polygonTaggedText(false, import_flags, wkt_parser); + + case WktParser.WktToken.linestring: + if (type != Geometry.Type.Polyline && type != Geometry.Type.Unknown) + throw new IllegalArgumentException("invalid shapetype"); + return lineStringTaggedText(false, import_flags, wkt_parser); + + case WktParser.WktToken.point: + if (type != Geometry.Type.Point && type != Geometry.Type.Unknown) + throw new IllegalArgumentException("invalid shapetype"); + return pointTaggedText(import_flags, wkt_parser); + + default: + break; // warning fix + } + + return null; + } + + static Geometry polygonTaggedText(boolean b_multi_polygon, + int import_flags, WktParser wkt_parser) { + MultiPath multi_path; + MultiPathImpl multi_path_impl; + AttributeStreamOfDbl zs = null; + AttributeStreamOfDbl ms = null; + AttributeStreamOfDbl position; + AttributeStreamOfInt32 paths; + AttributeStreamOfInt8 path_flags; + + position = (AttributeStreamOfDbl) AttributeStreamBase + .createDoubleStream(0); + paths = (AttributeStreamOfInt32) AttributeStreamBase.createIndexStream( + 1, 0); + path_flags = (AttributeStreamOfInt8) AttributeStreamBase + .createByteStream(1, (byte) 0); + + multi_path = new Polygon(); + multi_path_impl = (MultiPathImpl) multi_path._getImpl(); + + int current_token = wkt_parser.nextToken(); + + if (current_token == WktParser.WktToken.attribute_z) { + zs = (AttributeStreamOfDbl) AttributeStreamBase.createDoubleStream( + 0, NumberUtils.TheNaN); + multi_path_impl.addAttribute(VertexDescription.Semantics.Z); + wkt_parser.nextToken(); + } else if (current_token == WktParser.WktToken.attribute_m) { + ms = (AttributeStreamOfDbl) AttributeStreamBase.createDoubleStream( + 0, NumberUtils.TheNaN); + multi_path_impl.addAttribute(VertexDescription.Semantics.M); + wkt_parser.nextToken(); + } else if (current_token == WktParser.WktToken.attribute_zm) { + zs = (AttributeStreamOfDbl) AttributeStreamBase.createDoubleStream( + 0, NumberUtils.TheNaN); + ms = (AttributeStreamOfDbl) AttributeStreamBase.createDoubleStream( + 0, NumberUtils.TheNaN); + multi_path_impl.addAttribute(VertexDescription.Semantics.Z); + multi_path_impl.addAttribute(VertexDescription.Semantics.M); + wkt_parser.nextToken(); + } + + int point_count; + + if (b_multi_polygon) + point_count = multiPolygonText(zs, ms, position, paths, path_flags, + wkt_parser); + else + point_count = polygonText(zs, ms, position, paths, path_flags, 0, + wkt_parser); + + if (point_count != 0) { + assert (2 * point_count == position.size()); + multi_path_impl.setAttributeStreamRef( + VertexDescription.Semantics.POSITION, position); + multi_path_impl.setPathStreamRef(paths); + multi_path_impl.setPathFlagsStreamRef(path_flags); + + if (zs != null) + multi_path_impl.setAttributeStreamRef( + VertexDescription.Semantics.Z, zs); + + if (ms != null) + multi_path_impl.setAttributeStreamRef( + VertexDescription.Semantics.M, ms); + + multi_path_impl.notifyModified(MultiPathImpl.DirtyFlags.DirtyAll); + + AttributeStreamOfInt8 path_flags_clone = new AttributeStreamOfInt8( + path_flags); + + for (int i = 0; i < path_flags_clone.size() - 1; i++) { + if (((int) path_flags_clone.read(i) & (int) PathFlags.enumOGCStartPolygon) != 0) {// Should + // be + // clockwise + if (!InternalUtils.isClockwiseRing(multi_path_impl, i)) + multi_path_impl.reversePath(i); // make clockwise + } else {// Should be counter-clockwise + if (InternalUtils.isClockwiseRing(multi_path_impl, i)) + multi_path_impl.reversePath(i); // make + // counter-clockwise + } + } + + multi_path_impl.setPathFlagsStreamRef(path_flags_clone); + } + + if ((import_flags & (int) WktImportFlags.wktImportNonTrusted) == 0) + multi_path_impl.setIsSimple(MultiPathImpl.GeometryXSimple.Weak, + 0.0, false); + + multi_path_impl.setDirtyOGCFlags(false); + + return multi_path; + } + + static Geometry lineStringTaggedText(boolean b_multi_linestring, + int import_flags, WktParser wkt_parser) { + MultiPath multi_path; + MultiPathImpl multi_path_impl; + AttributeStreamOfDbl zs = null; + AttributeStreamOfDbl ms = null; + AttributeStreamOfDbl position; + AttributeStreamOfInt32 paths; + AttributeStreamOfInt8 path_flags; + + position = (AttributeStreamOfDbl) AttributeStreamBase + .createDoubleStream(0); + paths = (AttributeStreamOfInt32) AttributeStreamBase.createIndexStream( + 1, 0); + path_flags = (AttributeStreamOfInt8) AttributeStreamBase + .createByteStream(1, (byte) 0); + + multi_path = new Polyline(); + multi_path_impl = (MultiPathImpl) multi_path._getImpl(); + + int current_token = wkt_parser.nextToken(); + + if (current_token == WktParser.WktToken.attribute_z) { + zs = (AttributeStreamOfDbl) AttributeStreamBase.createDoubleStream( + 0, NumberUtils.TheNaN); + multi_path_impl.addAttribute(VertexDescription.Semantics.Z); + wkt_parser.nextToken(); + } else if (current_token == WktParser.WktToken.attribute_m) { + ms = (AttributeStreamOfDbl) AttributeStreamBase.createDoubleStream( + 0, NumberUtils.TheNaN); + multi_path_impl.addAttribute(VertexDescription.Semantics.M); + wkt_parser.nextToken(); + } else if (current_token == WktParser.WktToken.attribute_zm) { + zs = (AttributeStreamOfDbl) AttributeStreamBase.createDoubleStream( + 0, NumberUtils.TheNaN); + ms = (AttributeStreamOfDbl) AttributeStreamBase.createDoubleStream( + 0, NumberUtils.TheNaN); + multi_path_impl.addAttribute(VertexDescription.Semantics.Z); + multi_path_impl.addAttribute(VertexDescription.Semantics.M); + wkt_parser.nextToken(); + } + + int point_count; + + if (b_multi_linestring) + point_count = multiLineStringText(zs, ms, position, paths, + path_flags, wkt_parser); + else + point_count = lineStringText(false, zs, ms, position, paths, + path_flags, wkt_parser); + + if (point_count != 0) { + assert (2 * point_count == position.size()); + multi_path_impl.setAttributeStreamRef( + VertexDescription.Semantics.POSITION, position); + multi_path_impl.setPathStreamRef(paths); + multi_path_impl.setPathFlagsStreamRef(path_flags); + + if (zs != null) + multi_path_impl.setAttributeStreamRef( + VertexDescription.Semantics.Z, zs); + + if (ms != null) + multi_path_impl.setAttributeStreamRef( + VertexDescription.Semantics.M, ms); + + multi_path_impl.notifyModified(MultiPathImpl.DirtyFlags.DirtyAll); + } + + return multi_path; + } + + static Geometry multiPointTaggedText(int import_flags, WktParser wkt_parser) { + MultiPoint multi_point; + MultiPointImpl multi_point_impl; + AttributeStreamOfDbl zs = null; + AttributeStreamOfDbl ms = null; + AttributeStreamOfDbl position; + + position = (AttributeStreamOfDbl) AttributeStreamBase + .createDoubleStream(0); + + multi_point = new MultiPoint(); + multi_point_impl = (MultiPointImpl) multi_point._getImpl(); + + int current_token = wkt_parser.nextToken(); + + if (current_token == WktParser.WktToken.attribute_z) { + zs = (AttributeStreamOfDbl) AttributeStreamBase.createDoubleStream( + 0, NumberUtils.TheNaN); + multi_point_impl.addAttribute(VertexDescription.Semantics.Z); + wkt_parser.nextToken(); + } else if (current_token == WktParser.WktToken.attribute_m) { + ms = (AttributeStreamOfDbl) AttributeStreamBase.createDoubleStream( + 0, NumberUtils.TheNaN); + multi_point_impl.addAttribute(VertexDescription.Semantics.M); + wkt_parser.nextToken(); + } else if (current_token == WktParser.WktToken.attribute_zm) { + zs = (AttributeStreamOfDbl) AttributeStreamBase.createDoubleStream( + 0, NumberUtils.TheNaN); + ms = (AttributeStreamOfDbl) AttributeStreamBase.createDoubleStream( + 0, NumberUtils.TheNaN); + multi_point_impl.addAttribute(VertexDescription.Semantics.Z); + multi_point_impl.addAttribute(VertexDescription.Semantics.M); + wkt_parser.nextToken(); + } + + int point_count = multiPointText(zs, ms, position, wkt_parser); + + if (point_count != 0) { + assert (2 * point_count == position.size()); + multi_point_impl.resize(point_count); + multi_point_impl.setAttributeStreamRef( + VertexDescription.Semantics.POSITION, position); + + if (zs != null) + multi_point_impl.setAttributeStreamRef( + VertexDescription.Semantics.Z, zs); + + if (ms != null) + multi_point_impl.setAttributeStreamRef( + VertexDescription.Semantics.M, ms); + + multi_point_impl.notifyModified(MultiPointImpl.DirtyFlags.DirtyAll); + } + + return multi_point; + } + + static Geometry pointTaggedText(int import_flags, WktParser wkt_parser) { + Point point = new Point(); + + int current_token = wkt_parser.nextToken(); + + if (current_token == WktParser.WktToken.attribute_z) { + point.addAttribute(VertexDescription.Semantics.Z); + wkt_parser.nextToken(); + } else if (current_token == WktParser.WktToken.attribute_m) { + point.addAttribute(VertexDescription.Semantics.M); + wkt_parser.nextToken(); + } else if (current_token == WktParser.WktToken.attribute_zm) { + point.addAttribute(VertexDescription.Semantics.Z); + point.addAttribute(VertexDescription.Semantics.M); + wkt_parser.nextToken(); + } + // At start of PointText - current_token = wkt_parser.currentToken(); + current_token = wkt_parser.currentToken(); - if (current_token != WktParser.WktToken.empty) { - wkt_parser.nextToken(); + if (current_token != WktParser.WktToken.empty) { + wkt_parser.nextToken(); - double x = wkt_parser.currentNumericLiteral(); - wkt_parser.nextToken(); + double x = wkt_parser.currentNumericLiteral(); + wkt_parser.nextToken(); - double y = wkt_parser.currentNumericLiteral(); - wkt_parser.nextToken(); + double y = wkt_parser.currentNumericLiteral(); + wkt_parser.nextToken(); - point.setXY(x, y); + point.setXY(x, y); - if (wkt_parser.hasZs()) { - double z = wkt_parser.currentNumericLiteral(); - wkt_parser.nextToken(); - point.setZ(z); - } + if (wkt_parser.hasZs()) { + double z = wkt_parser.currentNumericLiteral(); + wkt_parser.nextToken(); + point.setZ(z); + } - if (wkt_parser.hasMs()) { - double m = wkt_parser.currentNumericLiteral(); - wkt_parser.nextToken(); - point.setM(m); - } - } + if (wkt_parser.hasMs()) { + double m = wkt_parser.currentNumericLiteral(); + wkt_parser.nextToken(); + point.setM(m); + } + } - return point; - } + return point; + } - static int multiPolygonText(AttributeStreamOfDbl zs, - AttributeStreamOfDbl ms, AttributeStreamOfDbl position, - AttributeStreamOfInt32 paths, AttributeStreamOfInt8 path_flags, - WktParser wkt_parser) { - // At start of MultiPolygonText + static int multiPolygonText(AttributeStreamOfDbl zs, + AttributeStreamOfDbl ms, AttributeStreamOfDbl position, + AttributeStreamOfInt32 paths, AttributeStreamOfInt8 path_flags, + WktParser wkt_parser) { + // At start of MultiPolygonText - int current_token = wkt_parser.currentToken(); + int current_token = wkt_parser.currentToken(); - int total_point_count = 0; + int total_point_count = 0; - if (current_token == WktParser.WktToken.empty) - return total_point_count; + if (current_token == WktParser.WktToken.empty) + return total_point_count; - current_token = wkt_parser.nextToken(); + current_token = wkt_parser.nextToken(); - while (current_token != WktParser.WktToken.right_paren) { - // At start of PolygonText + while (current_token != WktParser.WktToken.right_paren) { + // At start of PolygonText - total_point_count = polygonText(zs, ms, position, paths, - path_flags, total_point_count, wkt_parser); - current_token = wkt_parser.nextToken(); - } + total_point_count = polygonText(zs, ms, position, paths, + path_flags, total_point_count, wkt_parser); + current_token = wkt_parser.nextToken(); + } - return total_point_count; - } + return total_point_count; + } - static int multiLineStringText(AttributeStreamOfDbl zs, - AttributeStreamOfDbl ms, AttributeStreamOfDbl position, - AttributeStreamOfInt32 paths, AttributeStreamOfInt8 path_flags, - WktParser wkt_parser) { - // At start of MultiLineStringText + static int multiLineStringText(AttributeStreamOfDbl zs, + AttributeStreamOfDbl ms, AttributeStreamOfDbl position, + AttributeStreamOfInt32 paths, AttributeStreamOfInt8 path_flags, + WktParser wkt_parser) { + // At start of MultiLineStringText - int current_token = wkt_parser.currentToken(); + int current_token = wkt_parser.currentToken(); - int total_point_count = 0; + int total_point_count = 0; - if (current_token == WktParser.WktToken.empty) - return total_point_count; + if (current_token == WktParser.WktToken.empty) + return total_point_count; - current_token = wkt_parser.nextToken(); + current_token = wkt_parser.nextToken(); - while (current_token != WktParser.WktToken.right_paren) { - // At start of LineStringText + while (current_token != WktParser.WktToken.right_paren) { + // At start of LineStringText - int point_count = lineStringText(false, zs, ms, position, paths, - path_flags, wkt_parser); - total_point_count += point_count; + int point_count = lineStringText(false, zs, ms, position, paths, + path_flags, wkt_parser); + total_point_count += point_count; - current_token = wkt_parser.nextToken(); - } + current_token = wkt_parser.nextToken(); + } - return total_point_count; - } + return total_point_count; + } - static int multiPointText(AttributeStreamOfDbl zs, AttributeStreamOfDbl ms, - AttributeStreamOfDbl position, WktParser wkt_parser) { - // At start of MultiPointText + static int multiPointText(AttributeStreamOfDbl zs, AttributeStreamOfDbl ms, + AttributeStreamOfDbl position, WktParser wkt_parser) { + // At start of MultiPointText - int current_token = wkt_parser.currentToken(); + int current_token = wkt_parser.currentToken(); - int point_count = 0; + int point_count = 0; - if (current_token == WktParser.WktToken.empty) - return point_count; + if (current_token == WktParser.WktToken.empty) + return point_count; - current_token = wkt_parser.nextToken(); + current_token = wkt_parser.nextToken(); - while (current_token != WktParser.WktToken.right_paren) { - // At start of PointText + while (current_token != WktParser.WktToken.right_paren) { + // At start of PointText - point_count += pointText(zs, ms, position, wkt_parser); + point_count += pointText(zs, ms, position, wkt_parser); - if (current_token == WktParser.WktToken.left_paren - || current_token == WktParser.WktToken.empty) - current_token = wkt_parser.nextToken(); // ogc standard - else - current_token = wkt_parser.currentToken(); // not ogc standard. - // treat as - // linestring - } + if (current_token == WktParser.WktToken.left_paren + || current_token == WktParser.WktToken.empty) + current_token = wkt_parser.nextToken(); // ogc standard + else + current_token = wkt_parser.currentToken(); // not ogc standard. + // treat as + // linestring + } - return point_count; - } + return point_count; + } - static int polygonText(AttributeStreamOfDbl zs, AttributeStreamOfDbl ms, - AttributeStreamOfDbl position, AttributeStreamOfInt32 paths, - AttributeStreamOfInt8 path_flags, int total_point_count, - WktParser wkt_parser) { - // At start of PolygonText + static int polygonText(AttributeStreamOfDbl zs, AttributeStreamOfDbl ms, + AttributeStreamOfDbl position, AttributeStreamOfInt32 paths, + AttributeStreamOfInt8 path_flags, int total_point_count, + WktParser wkt_parser) { + // At start of PolygonText - int current_token = wkt_parser.currentToken(); + int current_token = wkt_parser.currentToken(); - if (current_token == WktParser.WktToken.empty) - return total_point_count; + if (current_token == WktParser.WktToken.empty) + return total_point_count; - boolean b_first_line_string = true; + boolean b_first_line_string = true; - current_token = wkt_parser.nextToken(); + current_token = wkt_parser.nextToken(); - while (current_token != WktParser.WktToken.right_paren) { - // At start of LineStringText + while (current_token != WktParser.WktToken.right_paren) { + // At start of LineStringText - int point_count = lineStringText(true, zs, ms, position, paths, - path_flags, wkt_parser); + int point_count = lineStringText(true, zs, ms, position, paths, + path_flags, wkt_parser); - if (point_count != 0) { - if (b_first_line_string) { - b_first_line_string = false; - path_flags.setBits(path_flags.size() - 2, - (byte) PathFlags.enumOGCStartPolygon); - } + if (point_count != 0) { + if (b_first_line_string) { + b_first_line_string = false; + path_flags.setBits(path_flags.size() - 2, + (byte) PathFlags.enumOGCStartPolygon); + } - path_flags.setBits(path_flags.size() - 2, - (byte) PathFlags.enumClosed); - total_point_count += point_count; - } + path_flags.setBits(path_flags.size() - 2, + (byte) PathFlags.enumClosed); + total_point_count += point_count; + } - current_token = wkt_parser.nextToken(); - } + current_token = wkt_parser.nextToken(); + } - return total_point_count; - } + return total_point_count; + } - static int lineStringText(boolean b_ring, AttributeStreamOfDbl zs, - AttributeStreamOfDbl ms, AttributeStreamOfDbl position, - AttributeStreamOfInt32 paths, AttributeStreamOfInt8 path_flags, - WktParser wkt_parser) { - // At start of LineStringText + static int lineStringText(boolean b_ring, AttributeStreamOfDbl zs, + AttributeStreamOfDbl ms, AttributeStreamOfDbl position, + AttributeStreamOfInt32 paths, AttributeStreamOfInt8 path_flags, + WktParser wkt_parser) { + // At start of LineStringText - int current_token = wkt_parser.currentToken(); + int current_token = wkt_parser.currentToken(); - int point_count = 0; + int point_count = 0; - if (current_token == WktParser.WktToken.empty) - return point_count; + if (current_token == WktParser.WktToken.empty) + return point_count; - boolean b_start_path = true; - double startx = NumberUtils.TheNaN; - double starty = NumberUtils.TheNaN; - double startz = NumberUtils.TheNaN; - double startm = NumberUtils.TheNaN; + boolean b_start_path = true; + double startx = NumberUtils.TheNaN; + double starty = NumberUtils.TheNaN; + double startz = NumberUtils.TheNaN; + double startm = NumberUtils.TheNaN; - current_token = wkt_parser.nextToken(); + current_token = wkt_parser.nextToken(); - while (current_token != WktParser.WktToken.right_paren) { - // At start of x + while (current_token != WktParser.WktToken.right_paren) { + // At start of x - double x = wkt_parser.currentNumericLiteral(); - wkt_parser.nextToken(); + double x = wkt_parser.currentNumericLiteral(); + wkt_parser.nextToken(); - double y = wkt_parser.currentNumericLiteral(); - wkt_parser.nextToken(); + double y = wkt_parser.currentNumericLiteral(); + wkt_parser.nextToken(); - double z = NumberUtils.TheNaN, m = NumberUtils.TheNaN; + double z = NumberUtils.TheNaN, m = NumberUtils.TheNaN; - if (wkt_parser.hasZs()) { - z = wkt_parser.currentNumericLiteral(); - wkt_parser.nextToken(); - } + if (wkt_parser.hasZs()) { + z = wkt_parser.currentNumericLiteral(); + wkt_parser.nextToken(); + } - if (wkt_parser.hasMs()) { - m = wkt_parser.currentNumericLiteral(); - wkt_parser.nextToken(); - } + if (wkt_parser.hasMs()) { + m = wkt_parser.currentNumericLiteral(); + wkt_parser.nextToken(); + } - current_token = wkt_parser.currentToken(); - boolean b_add_point = true; + current_token = wkt_parser.currentToken(); + boolean b_add_point = true; - if (b_ring && point_count >= 2 - && current_token == WktParser.WktToken.right_paren) { - // If the last point in the ring is not equal to the start - // point, then let's add it. + if (b_ring && point_count >= 2 + && current_token == WktParser.WktToken.right_paren) { + // If the last point in the ring is not equal to the start + // point, then let's add it. - if ((startx == x || (NumberUtils.isNaN(startx) && NumberUtils - .isNaN(x))) - && (starty == y || (NumberUtils.isNaN(starty) && NumberUtils - .isNaN(y))) - && (!wkt_parser.hasZs() || startz == z || (NumberUtils - .isNaN(startz) && NumberUtils.isNaN(z))) - && (!wkt_parser.hasMs() || startm == m || (NumberUtils - .isNaN(startm) && NumberUtils.isNaN(m)))) - b_add_point = false; - } + if ((startx == x || (NumberUtils.isNaN(startx) && NumberUtils + .isNaN(x))) + && (starty == y || (NumberUtils.isNaN(starty) && NumberUtils + .isNaN(y))) + && (!wkt_parser.hasZs() || startz == z || (NumberUtils + .isNaN(startz) && NumberUtils.isNaN(z))) + && (!wkt_parser.hasMs() || startm == m || (NumberUtils + .isNaN(startm) && NumberUtils.isNaN(m)))) + b_add_point = false; + } - if (b_add_point) { - if (b_start_path) { - b_start_path = false; - startx = x; - starty = y; - startz = z; - startm = m; - } + if (b_add_point) { + if (b_start_path) { + b_start_path = false; + startx = x; + starty = y; + startz = z; + startm = m; + } - point_count++; - addToStreams(zs, ms, position, x, y, z, m); - } - } + point_count++; + addToStreams(zs, ms, position, x, y, z, m); + } + } - if (point_count == 1) { - point_count++; - addToStreams(zs, ms, position, startx, starty, startz, startm); - } + if (point_count == 1) { + point_count++; + addToStreams(zs, ms, position, startx, starty, startz, startm); + } - paths.add(position.size() / 2); - path_flags.add((byte) 0); + paths.add(position.size() / 2); + path_flags.add((byte) 0); - return point_count; - } + return point_count; + } - static int pointText(AttributeStreamOfDbl zs, AttributeStreamOfDbl ms, - AttributeStreamOfDbl position, WktParser wkt_parser) { - // At start of PointText + static int pointText(AttributeStreamOfDbl zs, AttributeStreamOfDbl ms, + AttributeStreamOfDbl position, WktParser wkt_parser) { + // At start of PointText - int current_token = wkt_parser.currentToken(); + int current_token = wkt_parser.currentToken(); - if (current_token == WktParser.WktToken.empty) - return 0; + if (current_token == WktParser.WktToken.empty) + return 0; - if (current_token == WktParser.WktToken.left_paren) - wkt_parser.nextToken(); // ogc standard + if (current_token == WktParser.WktToken.left_paren) + wkt_parser.nextToken(); // ogc standard - // At start of x + // At start of x - double x = wkt_parser.currentNumericLiteral(); - wkt_parser.nextToken(); + double x = wkt_parser.currentNumericLiteral(); + wkt_parser.nextToken(); - double y = wkt_parser.currentNumericLiteral(); - wkt_parser.nextToken(); + double y = wkt_parser.currentNumericLiteral(); + wkt_parser.nextToken(); - double z = NumberUtils.TheNaN; - double m = NumberUtils.TheNaN; + double z = NumberUtils.TheNaN; + double m = NumberUtils.TheNaN; - if (zs != null) { - z = wkt_parser.currentNumericLiteral(); - wkt_parser.nextToken(); - } + if (zs != null) { + z = wkt_parser.currentNumericLiteral(); + wkt_parser.nextToken(); + } - if (ms != null) { - m = wkt_parser.currentNumericLiteral(); - wkt_parser.nextToken(); - } + if (ms != null) { + m = wkt_parser.currentNumericLiteral(); + wkt_parser.nextToken(); + } - addToStreams(zs, ms, position, x, y, z, m); + addToStreams(zs, ms, position, x, y, z, m); - return 1; - } + return 1; + } - static void addToStreams(AttributeStreamOfDbl zs, AttributeStreamOfDbl ms, - AttributeStreamOfDbl position, double x, double y, double z, - double m) { - position.add(x); - position.add(y); + static void addToStreams(AttributeStreamOfDbl zs, AttributeStreamOfDbl ms, + AttributeStreamOfDbl position, double x, double y, double z, + double m) { + position.add(x); + position.add(y); - if (zs != null) - zs.add(z); - - if (ms != null) - ms.add(m); - } + if (zs != null) + zs.add(z); + + if (ms != null) + ms.add(m); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorInternalRelationUtils.java b/src/main/java/com/esri/core/geometry/OperatorInternalRelationUtils.java index ea3c475a..899f7745 100644 --- a/src/main/java/com/esri/core/geometry/OperatorInternalRelationUtils.java +++ b/src/main/java/com/esri/core/geometry/OperatorInternalRelationUtils.java @@ -27,707 +27,707 @@ class OperatorInternalRelationUtils { - interface Relation { - public final int Unknown = 0; - public final int Contains = 1; - public final int Within = 2; - public final int Equals = 3; // == Within | Contains tests both within - // and contains - public final int Disjoint = 4; - public final int Touches = 8; - public final int Crosses = 16; - public final int Overlaps = 32; - - public final int NoThisRelation = 64; // returned when the relation is - // not satisified - public final int Intersects = 0x40000000;// this means not_disjoint. - // Used for early bailout - public final int IntersectsOrDisjoint = Intersects | Disjoint; - } - - public static int quickTest2D(Geometry geomA, Geometry geomB, - double tolerance, int testType) { - if (geomB.isEmpty() || geomA.isEmpty()) - return (int) Relation.Disjoint; - - int geomAtype = geomA.getType().value(); - int geomBtype = geomB.getType().value(); - - // We do not support segments directly for now. Convert to Polyline - Polyline autoPolyA; - if (Geometry.isSegment(geomAtype)) { - autoPolyA = new Polyline(geomA.getDescription()); - geomA = (Geometry) autoPolyA; - autoPolyA.addSegment((Segment) geomA, true); - } - - Polyline autoPolyB; - if (Geometry.isSegment(geomBtype)) { - autoPolyB = new Polyline(geomB.getDescription()); - geomB = (Geometry) autoPolyB; - autoPolyB.addSegment((Segment) geomB, true); - } - - // Now process GeometryxGeometry case by case - switch (geomAtype) { - case Geometry.GeometryType.Point: { - switch (geomBtype) { - case Geometry.GeometryType.Point: - return quickTest2DPointPoint((Point) geomA, (Point) geomB, - tolerance); - case Geometry.GeometryType.Envelope: - return reverseResult(quickTest2DEnvelopePoint((Envelope) geomB, - (Point) geomA, tolerance)); - case Geometry.GeometryType.MultiPoint: - return reverseResult(quickTest2DMultiPointPoint( - (MultiPoint) geomB, (Point) geomA, tolerance)); - case Geometry.GeometryType.Polyline: - return reverseResult(quickTest2DPolylinePoint((Polyline) geomB, - (Point) geomA, tolerance, testType)); - case Geometry.GeometryType.Polygon: - return reverseResult(quickTest2DPolygonPoint((Polygon) geomB, - (Point) geomA, tolerance)); - } - throw GeometryException.GeometryInternalError();// GEOMTHROW(internal_error);//what - // else? - } - case Geometry.GeometryType.Envelope: { - switch (geomBtype) { - case Geometry.GeometryType.Point: - return quickTest2DEnvelopePoint((Envelope) geomA, - (Point) geomB, tolerance); - case Geometry.GeometryType.Envelope: - return quickTest2DEnvelopeEnvelope((Envelope) geomA, - (Envelope) geomB, tolerance); - case Geometry.GeometryType.MultiPoint: - return reverseResult(quickTest2DMultiPointEnvelope( - (MultiPoint) geomB, (Envelope) geomA, tolerance, - testType)); - case Geometry.GeometryType.Polyline: - return reverseResult(quickTest2DPolylineEnvelope( - (Polyline) geomB, (Envelope) geomA, tolerance)); - case Geometry.GeometryType.Polygon: - return reverseResult(quickTest2DPolygonEnvelope( - (Polygon) geomB, (Envelope) geomA, tolerance)); - } - throw GeometryException.GeometryInternalError();// GEOMTHROW(internal_error);//what - // else? - } - case Geometry.GeometryType.MultiPoint: { - switch (geomBtype) { - case Geometry.GeometryType.Point: - return quickTest2DMultiPointPoint((MultiPoint) geomA, - (Point) geomB, tolerance); - case Geometry.GeometryType.Envelope: - return quickTest2DMultiPointEnvelope((MultiPoint) geomA, - (Envelope) geomB, tolerance, testType); - case Geometry.GeometryType.MultiPoint: - return quickTest2DMultiPointMultiPoint((MultiPoint) geomA, - (MultiPoint) geomB, tolerance, testType); - case Geometry.GeometryType.Polyline: - return reverseResult(quickTest2DPolylineMultiPoint( - (Polyline) geomB, (MultiPoint) geomA, tolerance)); - case Geometry.GeometryType.Polygon: - return reverseResult(quickTest2DPolygonMultiPoint( - (Polygon) geomB, (MultiPoint) geomA, tolerance)); - } - throw GeometryException.GeometryInternalError();// GEOMTHROW(internal_error);//what - // else? - } - case Geometry.GeometryType.Polyline: { - switch (geomBtype) { - case Geometry.GeometryType.Point: - return quickTest2DPolylinePoint((Polyline) geomA, - (Point) geomB, tolerance, testType); - case Geometry.GeometryType.Envelope: - return quickTest2DPolylineEnvelope((Polyline) geomA, - (Envelope) geomB, tolerance); - case Geometry.GeometryType.MultiPoint: - return quickTest2DPolylineMultiPoint((Polyline) geomA, - (MultiPoint) geomB, tolerance); - case Geometry.GeometryType.Polyline: - return quickTest2DPolylinePolyline((Polyline) geomA, - (Polyline) geomB, tolerance); - case Geometry.GeometryType.Polygon: - return reverseResult(quickTest2DPolygonPolyline( - (Polygon) geomB, (Polyline) geomA, tolerance)); - } - throw GeometryException.GeometryInternalError();// GEOMTHROW(internal_error);//what - // else? - } - case Geometry.GeometryType.Polygon: { - switch (geomBtype) { - case Geometry.GeometryType.Point: - return quickTest2DPolygonPoint((Polygon) geomA, (Point) geomB, - tolerance); - case Geometry.GeometryType.Envelope: - return quickTest2DPolygonEnvelope((Polygon) geomA, - (Envelope) geomB, tolerance); - case Geometry.GeometryType.MultiPoint: - return quickTest2DPolygonMultiPoint((Polygon) geomA, - (MultiPoint) geomB, tolerance); - case Geometry.GeometryType.Polyline: - return quickTest2DPolygonPolyline((Polygon) geomA, - (Polyline) geomB, tolerance); - case Geometry.GeometryType.Polygon: - return quickTest2DPolygonPolygon((Polygon) geomA, - (Polygon) geomB, tolerance); - } - throw GeometryException.GeometryInternalError();// GEOMTHROW(internal_error);//what - // else? - } - - default: - throw GeometryException.GeometryInternalError();// GEOMTHROW(internal_error);//what - // else? - // return 0; - } - } - - private static int quickTest2DPointPoint(Point geomA, Point geomB, - double tolerance) { - Point2D ptA = geomA.getXY(); - Point2D ptB = geomB.getXY(); - return quickTest2DPointPoint(ptA, ptB, tolerance); - } - - private static int quickTest2DPointPoint(Point2D ptA, Point2D ptB, - double tolerance) { - ptA.sub(ptB); - double len = ptA.sqrLength();// Should we test against 2*tol or tol? - if (len <= tolerance * tolerance)// Two points are equal if they are not - // Disjoint. We consider a point to - // be a disk of radius tolerance. - // Any intersection of two disks - // produces same disk. - return (int) Relation.Within | (int) Relation.Contains;// ==Equals - - return (int) Relation.Disjoint; - } - - private static int quickTest2DEnvelopePoint(Envelope geomA, Point geomB, - double tolerance) { - Envelope2D geomAEnv = new Envelope2D(); - geomA.queryEnvelope2D(geomAEnv); - Point2D ptB; - ptB = geomB.getXY(); - return quickTest2DEnvelopePoint(geomAEnv, ptB, tolerance); - } - - private static int quickTest2DEnvelopePoint(Envelope2D geomAEnv, - Point2D ptB, double tolerance) { - Envelope2D envAMinus = geomAEnv; - envAMinus.inflate(-tolerance, -tolerance); - if (envAMinus.contains(ptB)) - return (int) Relation.Contains;// clementini's contains - Envelope2D envAPlus = geomAEnv; - envAPlus.inflate(tolerance, tolerance); - if (envAPlus.contains(ptB)) - return (int) Relation.Touches;// clementini's touches - - return (int) Relation.Disjoint;// clementini's disjoint - } - - private static int quickTest2DEnvelopePoint(Envelope2D envAPlus, - Envelope2D envAMinus, Point2D ptB, double tolerance) { - if (envAMinus.contains(ptB)) - return (int) Relation.Contains;// clementini's contains - if (envAPlus.contains(ptB)) - return (int) Relation.Touches;// clementini's touches - - return (int) Relation.Disjoint;// clementini's disjoint - } - - private static int quickTest2DEnvelopeEnvelope(Envelope geomA, - Envelope geomB, double tolerance) { - Envelope2D geomAEnv = new Envelope2D(); - geomA.queryEnvelope2D(geomAEnv); - Envelope2D geomBEnv = new Envelope2D(); - geomB.queryEnvelope2D(geomBEnv); - return quickTest2DEnvelopeEnvelope(geomAEnv, geomBEnv, tolerance); - } - - private static int quickTest2DEnvelopeEnvelope(Envelope2D geomAEnv, - Envelope2D geomBEnv, double tolerance) { - // firstly check for contains and within to give a chance degenerate - // envelopes to work. - // otherwise, if there are two degenerate envelopes that are equal, - // Touch relation may occur. - int res = 0; - if (geomAEnv.contains(geomBEnv)) - res |= (int) Relation.Contains; - - if (geomBEnv.contains(geomAEnv)) - res |= (int) Relation.Within; - - if (res != 0) - return res; - - Envelope2D envAMinus = geomAEnv; - envAMinus.inflate(-tolerance, -tolerance);// Envelope A interior - Envelope2D envBMinus = geomBEnv; - envBMinus.inflate(-tolerance, -tolerance);// Envelope B interior - if (envAMinus.isIntersecting(envBMinus)) { - Envelope2D envAPlus = geomAEnv; - envAPlus.inflate(tolerance, tolerance);// Envelope A interior plus - // boundary - res = envAPlus.contains(geomBEnv) ? (int) Relation.Contains : 0; - Envelope2D envBPlus = geomBEnv; - envBPlus.inflate(tolerance, tolerance);// Envelope A interior plus - // boundary - res |= envBPlus.contains(geomAEnv) ? (int) Relation.Within : 0; - if (res != 0) - return res; - - return (int) Relation.Overlaps; // Clementini's Overlap - } else { - Envelope2D envAPlus = geomAEnv; - envAPlus.inflate(tolerance, tolerance);// Envelope A interior plus - // boundary - Envelope2D envBPlus = geomBEnv; - envBPlus.inflate(tolerance, tolerance);// Envelope A interior plus - // boundary - if (envAPlus.isIntersecting(envBPlus)) { - return (int) Relation.Touches; // Clementini Touch - } else { - return (int) Relation.Disjoint; // Clementini Disjoint - } - } - } - - private static int quickTest2DMultiPointPoint(MultiPoint geomA, - Point geomB, double tolerance) { - Point2D ptB; - ptB = geomB.getXY(); - return quickTest2DMultiPointPoint(geomA, ptB, tolerance); - } - - private static int quickTest2DMultiPointPoint(MultiPoint geomA, - Point2D ptB, double tolerance) { - // TODO: Add Geometry accelerator. (RasterizedGeometry + kd-tree or - // alike) - for (int i = 0, n = geomA.getPointCount(); i < n; i++) { - Point2D ptA; - ptA = geomA.getXY(i); - int res = quickTest2DPointPoint(ptA, ptB, tolerance); - if (res != (int) Relation.Disjoint) { - if ((res & (int) Relation.Within) != 0 && n != 1) { - // _ASSERT(res & (int)Relation.Contains); - return (int) Relation.Contains; - } - - return res; - } - } - - return (int) Relation.Disjoint; - } - - private static int quickTest2DMultiPointEnvelope(MultiPoint geomA, - Envelope geomB, double tolerance, int testType) { - Envelope2D geomBEnv = new Envelope2D(); - geomB.queryEnvelope2D(geomBEnv); - return quickTest2DMultiPointEnvelope(geomA, geomBEnv, tolerance, - testType); - } - - private static int quickTest2DMultiPointEnvelope(MultiPoint geomA, - Envelope2D geomBEnv, double tolerance, int testType) { - // Add early bailout for disjoint test. - Envelope2D envBMinus = geomBEnv; - envBMinus.inflate(-tolerance, -tolerance); - Envelope2D envBPlus = geomBEnv; - envBPlus.inflate(tolerance, tolerance); - int dres = 0; - for (int i = 0, n = geomA.getPointCount(); i < n; i++) { - Point2D ptA; - ptA = geomA.getXY(i); - int res = reverseResult(quickTest2DEnvelopePoint(envBPlus, - envBMinus, ptA, tolerance)); - if (res != (int) Relation.Disjoint) { - dres |= res; - if (testType == (int) Relation.Disjoint) - return (int) Relation.Intersects; - } - } - - if (dres == 0) - return (int) Relation.Disjoint; - - if (dres == (int) Relation.Within) - return dres; - - return (int) Relation.Overlaps; - } - - private static int quickTest2DMultiPointMultiPoint(MultiPoint geomA, - MultiPoint geomB, double tolerance, int testType) { - int counter = 0; - for (int ib = 0, nb = geomB.getPointCount(); ib < nb; ib++) { - Point2D ptB; - ptB = geomB.getXY(ib); - int res = quickTest2DMultiPointPoint(geomA, ptB, tolerance); - if (res != (int) Relation.Disjoint) { - counter++; - if (testType == (int) Relation.Disjoint) - return (int) Relation.Intersects; - } - } - - if (counter > 0) { - if (counter == geomB.getPointCount())// every point from B is within - // A. Means the A contains B - { - if (testType == (int) Relation.Equals) {// This is slow. - // Refactor. - int res = quickTest2DMultiPointMultiPoint(geomB, geomA, - tolerance, (int) Relation.Contains); - return res == (int) Relation.Contains ? (int) Relation.Equals - : (int) Relation.Unknown; - } - return (int) Relation.Contains; - } else { - return (int) Relation.Overlaps; - } - } - - return 0; - } - - private static int quickTest2DPolylinePoint(Polyline geomA, Point geomB, - double tolerance, int testType) { - Point2D ptB; - ptB = geomB.getXY(); - return quickTest2DPolylinePoint(geomA, ptB, tolerance, testType); - } - - private static int quickTest2DMVPointRasterOnly(MultiVertexGeometry geomA, - Point2D ptB, double tolerance) { - // Use rasterized Geometry: - RasterizedGeometry2D rgeomA = null; - MultiVertexGeometryImpl mpImpl = (MultiVertexGeometryImpl) geomA - ._getImpl(); - GeometryAccelerators gaccel = mpImpl._getAccelerators(); - if (gaccel != null) { - rgeomA = gaccel.getRasterizedGeometry(); - } - - if (rgeomA != null) { - RasterizedGeometry2D.HitType hitres = rgeomA.queryPointInGeometry( - ptB.x, ptB.y); - if (hitres == RasterizedGeometry2D.HitType.Outside) - return (int) Relation.Disjoint; - - if (hitres == RasterizedGeometry2D.HitType.Inside) - return (int) Relation.Contains; - } else - return -1; - - return 0; - } - - private static int quickTest2DPolylinePoint(Polyline geomA, Point2D ptB, - double tolerance, int testType) { - int mask = Relation.Touches | Relation.Contains | Relation.Within - | Relation.Disjoint | Relation.Intersects; - - if ((testType & mask) == 0) - return Relation.NoThisRelation; - - int res = quickTest2DMVPointRasterOnly(geomA, ptB, tolerance); - if (res > 0) - return res; - - // Go through the segments: - double toleranceSqr = tolerance * tolerance; - MultiPathImpl mpImpl = (MultiPathImpl) geomA._getImpl(); - SegmentIteratorImpl iter = mpImpl.querySegmentIterator(); - while (iter.nextPath()) { - int pathIndex = iter.getPathIndex(); - if (!geomA.isClosedPath(pathIndex)) { - int pathSize = geomA.getPathSize(pathIndex); - int pathStart = geomA.getPathStart(pathIndex); - if (pathSize == 0) - continue; - - if (Point2D.sqrDistance(geomA.getXY(pathStart), ptB) <= toleranceSqr - || (pathSize > 1 && Point2D.sqrDistance( - geomA.getXY(pathStart + pathSize - 1), ptB) <= toleranceSqr)) { - return (int) Relation.Touches; - } - } - - if (testType != Relation.Touches) { - while (iter.hasNextSegment()) { - Segment segment = iter.nextSegment(); - double t = segment.getClosestCoordinate(ptB, false); - Point2D pt = segment.getCoord2D(t); - if (Point2D.sqrDistance(pt, ptB) <= toleranceSqr) { - if ((testType & Relation.IntersectsOrDisjoint) != 0) { - return Relation.Intersects; - } - - return (int) Relation.Contains; - } - } - } - } - - return (testType & Relation.IntersectsOrDisjoint) != 0 ? Relation.Disjoint - : Relation.NoThisRelation; - } - - private static int quickTest2DPolylineEnvelope(Polyline geomA, - Envelope geomB, double tolerance) { - Envelope2D geomBEnv = new Envelope2D(); - geomB.queryEnvelope2D(geomBEnv); - return quickTest2DPolylineEnvelope(geomA, geomBEnv, tolerance); - } - - private static int quickTest2DPolylineEnvelope(Polyline geomA, - Envelope2D geomBEnv, double tolerance) { - int res = quickTest2DMVEnvelopeRasterOnly(geomA, geomBEnv, tolerance); - if (res > 0) - return res; - - // TODO: implement me - return 0; - } - - private static int quickTest2DMVEnvelopeRasterOnly( - MultiVertexGeometry geomA, Envelope2D geomBEnv, double tolerance) { - // Use rasterized Geometry only: - RasterizedGeometry2D rgeomA; - MultiVertexGeometryImpl mpImpl = (MultiVertexGeometryImpl) geomA - ._getImpl(); - GeometryAccelerators gaccel = mpImpl._getAccelerators(); - if (gaccel != null) { - rgeomA = gaccel.getRasterizedGeometry(); - } else - return -1; - - if (rgeomA != null) { - HitType hitres = rgeomA.queryEnvelopeInGeometry(geomBEnv); - if (hitres == RasterizedGeometry2D.HitType.Outside) - return (int) Relation.Disjoint; - - if (hitres == RasterizedGeometry2D.HitType.Inside) - return (int) Relation.Contains; - } else - return -1; - - return 0; - } - - private static int quickTest2DPolylineMultiPoint(Polyline geomA, - MultiPoint geomB, double tolerance) { - Envelope2D geomBEnv = new Envelope2D(); - geomB.queryEnvelope2D(geomBEnv); - int res = quickTest2DMVEnvelopeRasterOnly(geomA, geomBEnv, tolerance); - if (res > 0) - return res; - - // TODO: implement me - return 0; - } - - private static int quickTest2DMVMVRasterOnly(MultiVertexGeometry geomA, - MultiVertexGeometry geomB, double tolerance) { - Envelope2D geomBEnv = new Envelope2D(); - geomB.queryEnvelope2D(geomBEnv); - int res = quickTest2DMVEnvelopeRasterOnly(geomA, geomBEnv, tolerance); - if (res > 0) - return res; - - if (res == -1) { - Envelope2D geomAEnv = new Envelope2D(); - geomA.queryEnvelope2D(geomAEnv); - res = quickTest2DMVEnvelopeRasterOnly(geomB, geomAEnv, tolerance); - if (res > 0) - return reverseResult(res); - } - - // TODO: implement me - return 0; - } - - private static int quickTest2DPolylinePolyline(Polyline geomA, - Polyline geomB, double tolerance) { - int res = quickTest2DMVMVRasterOnly(geomA, geomB, tolerance); - if (res > 0) - return res; - - // TODO: implement me - return 0; - } - - private static int quickTest2DPolygonPoint(Polygon geomA, Point geomB, - double tolerance) { - Point2D ptB; - ptB = geomB.getXY(); - return quickTest2DPolygonPoint(geomA, ptB, tolerance); - } - - private static int quickTest2DPolygonPoint(Polygon geomA, Point2D ptB, - double tolerance) { - PolygonUtils.PiPResult pipres = PolygonUtils.isPointInPolygon2D(geomA, - ptB, tolerance);// this method uses the accelerator if available - if (pipres == PolygonUtils.PiPResult.PiPOutside) - return (int) Relation.Disjoint;// clementini's disjoint - - if (pipres == PolygonUtils.PiPResult.PiPInside) - return (int) Relation.Contains;// clementini's contains - - if (pipres == PolygonUtils.PiPResult.PiPBoundary) - return (int) Relation.Touches;// clementini's touches - - throw GeometryException.GeometryInternalError();// GEOMTHROW(internal_error); - // //what else - // return 0; - } - - private static int quickTest2DPolygonEnvelope(Polygon geomA, - Envelope geomB, double tolerance) { - Envelope2D geomBEnv = new Envelope2D(); - geomB.queryEnvelope2D(geomBEnv); - return quickTest2DPolygonEnvelope(geomA, geomBEnv, tolerance); - } - - private static int quickTest2DPolygonEnvelope(Polygon geomA, - Envelope2D geomBEnv, double tolerance) { - int res = quickTest2DMVEnvelopeRasterOnly(geomA, geomBEnv, tolerance); - if (res > 0) - return res; - - // TODO: implement me - return 0; - } - - private static int quickTest2DPolygonMultiPoint(Polygon geomA, - MultiPoint geomB, double tolerance) { - int res = quickTest2DMVMVRasterOnly(geomA, geomB, tolerance); - if (res > 0) - return res; - - // TODO: implement me - return 0; - } - - private static int quickTest2DPolygonPolyline(Polygon geomA, - Polyline geomB, double tolerance) { - int res = quickTest2DMVMVRasterOnly(geomA, geomB, tolerance); - if (res > 0) - return res; - - // TODO: implement me - return 0; - } - - private static int quickTest2DPolygonPolygon(Polygon geomA, Polygon geomB, - double tolerance) { - int res = quickTest2DMVMVRasterOnly(geomA, geomB, tolerance); - if (res > 0) - return res; - - // TODO: implement me - return 0; - } - - public static int quickTest2D_Accelerated_DisjointOrContains( - Geometry geomA, Geometry geomB, double tolerance) { - int gtA = geomA.getType().value(); - int gtB = geomB.getType().value(); - GeometryAccelerators accel; - boolean endWhileStatement = false; - do { - if (Geometry.isMultiVertex(gtA)) { - MultiVertexGeometryImpl impl = (MultiVertexGeometryImpl) geomA - ._getImpl(); - accel = impl._getAccelerators(); - if (accel != null) { - RasterizedGeometry2D rgeom = accel.getRasterizedGeometry(); - if (rgeom != null) { - if (gtB == Geometry.GeometryType.Point) { - Point2D ptB = ((Point) geomB).getXY(); - HitType hit = rgeom.queryPointInGeometry(ptB.x, - ptB.y); - if (hit == RasterizedGeometry2D.HitType.Inside) { - return (int) Relation.Contains; - } else if (hit == RasterizedGeometry2D.HitType.Outside) { - return (int) Relation.Disjoint; - } - - break; - } - Envelope2D envB = new Envelope2D(); - geomB.queryEnvelope2D(envB); - RasterizedGeometry2D.HitType hit = rgeom - .queryEnvelopeInGeometry(envB); - if (hit == RasterizedGeometry2D.HitType.Inside) { - return (int) Relation.Contains; - } else if (hit == RasterizedGeometry2D.HitType.Outside) { - return (int) Relation.Disjoint; - } - - break; - } - } - } - } while (endWhileStatement); - - accel = null; - do { - if (Geometry.isMultiVertex(gtB)) { - MultiVertexGeometryImpl impl = (MultiVertexGeometryImpl) geomB - ._getImpl(); - accel = impl._getAccelerators(); - if (accel != null) { - RasterizedGeometry2D rgeom = accel.getRasterizedGeometry(); - if (rgeom != null) { - if (gtA == Geometry.GeometryType.Point) { - Point2D ptA = ((Point) geomA).getXY(); - RasterizedGeometry2D.HitType hit = rgeom - .queryPointInGeometry(ptA.x, ptA.y); - if (hit == RasterizedGeometry2D.HitType.Inside) { - return (int) Relation.Within; - } else if (hit == RasterizedGeometry2D.HitType.Outside) { - return (int) Relation.Disjoint; - } - - break; - } - - Envelope2D envA = new Envelope2D(); - geomA.queryEnvelope2D(envA); - RasterizedGeometry2D.HitType hit = rgeom - .queryEnvelopeInGeometry(envA); - if (hit == RasterizedGeometry2D.HitType.Inside) { - return (int) Relation.Within; - } else if (hit == RasterizedGeometry2D.HitType.Outside) { - return (int) Relation.Disjoint; - } - - break; - } - } - } - } while (endWhileStatement); - - return 0; - } - - private static int reverseResult(int resIn) { - int res = resIn; - if ((res & (int) Relation.Contains) != 0) { - res &= ~(int) Relation.Contains; - res |= (int) Relation.Within; - } - if ((res & (int) Relation.Within) != 0) { - res &= ~(int) Relation.Within; - res |= (int) Relation.Contains; - } - - return res; - } + interface Relation { + public final int Unknown = 0; + public final int Contains = 1; + public final int Within = 2; + public final int Equals = 3; // == Within | Contains tests both within + // and contains + public final int Disjoint = 4; + public final int Touches = 8; + public final int Crosses = 16; + public final int Overlaps = 32; + + public final int NoThisRelation = 64; // returned when the relation is + // not satisified + public final int Intersects = 0x40000000;// this means not_disjoint. + // Used for early bailout + public final int IntersectsOrDisjoint = Intersects | Disjoint; + } + + public static int quickTest2D(Geometry geomA, Geometry geomB, + double tolerance, int testType) { + if (geomB.isEmpty() || geomA.isEmpty()) + return (int) Relation.Disjoint; + + int geomAtype = geomA.getType().value(); + int geomBtype = geomB.getType().value(); + + // We do not support segments directly for now. Convert to Polyline + Polyline autoPolyA; + if (Geometry.isSegment(geomAtype)) { + autoPolyA = new Polyline(geomA.getDescription()); + geomA = (Geometry) autoPolyA; + autoPolyA.addSegment((Segment) geomA, true); + } + + Polyline autoPolyB; + if (Geometry.isSegment(geomBtype)) { + autoPolyB = new Polyline(geomB.getDescription()); + geomB = (Geometry) autoPolyB; + autoPolyB.addSegment((Segment) geomB, true); + } + + // Now process GeometryxGeometry case by case + switch (geomAtype) { + case Geometry.GeometryType.Point: { + switch (geomBtype) { + case Geometry.GeometryType.Point: + return quickTest2DPointPoint((Point) geomA, (Point) geomB, + tolerance); + case Geometry.GeometryType.Envelope: + return reverseResult(quickTest2DEnvelopePoint((Envelope) geomB, + (Point) geomA, tolerance)); + case Geometry.GeometryType.MultiPoint: + return reverseResult(quickTest2DMultiPointPoint( + (MultiPoint) geomB, (Point) geomA, tolerance)); + case Geometry.GeometryType.Polyline: + return reverseResult(quickTest2DPolylinePoint((Polyline) geomB, + (Point) geomA, tolerance, testType)); + case Geometry.GeometryType.Polygon: + return reverseResult(quickTest2DPolygonPoint((Polygon) geomB, + (Point) geomA, tolerance)); + } + throw GeometryException.GeometryInternalError();// GEOMTHROW(internal_error);//what + // else? + } + case Geometry.GeometryType.Envelope: { + switch (geomBtype) { + case Geometry.GeometryType.Point: + return quickTest2DEnvelopePoint((Envelope) geomA, + (Point) geomB, tolerance); + case Geometry.GeometryType.Envelope: + return quickTest2DEnvelopeEnvelope((Envelope) geomA, + (Envelope) geomB, tolerance); + case Geometry.GeometryType.MultiPoint: + return reverseResult(quickTest2DMultiPointEnvelope( + (MultiPoint) geomB, (Envelope) geomA, tolerance, + testType)); + case Geometry.GeometryType.Polyline: + return reverseResult(quickTest2DPolylineEnvelope( + (Polyline) geomB, (Envelope) geomA, tolerance)); + case Geometry.GeometryType.Polygon: + return reverseResult(quickTest2DPolygonEnvelope( + (Polygon) geomB, (Envelope) geomA, tolerance)); + } + throw GeometryException.GeometryInternalError();// GEOMTHROW(internal_error);//what + // else? + } + case Geometry.GeometryType.MultiPoint: { + switch (geomBtype) { + case Geometry.GeometryType.Point: + return quickTest2DMultiPointPoint((MultiPoint) geomA, + (Point) geomB, tolerance); + case Geometry.GeometryType.Envelope: + return quickTest2DMultiPointEnvelope((MultiPoint) geomA, + (Envelope) geomB, tolerance, testType); + case Geometry.GeometryType.MultiPoint: + return quickTest2DMultiPointMultiPoint((MultiPoint) geomA, + (MultiPoint) geomB, tolerance, testType); + case Geometry.GeometryType.Polyline: + return reverseResult(quickTest2DPolylineMultiPoint( + (Polyline) geomB, (MultiPoint) geomA, tolerance)); + case Geometry.GeometryType.Polygon: + return reverseResult(quickTest2DPolygonMultiPoint( + (Polygon) geomB, (MultiPoint) geomA, tolerance)); + } + throw GeometryException.GeometryInternalError();// GEOMTHROW(internal_error);//what + // else? + } + case Geometry.GeometryType.Polyline: { + switch (geomBtype) { + case Geometry.GeometryType.Point: + return quickTest2DPolylinePoint((Polyline) geomA, + (Point) geomB, tolerance, testType); + case Geometry.GeometryType.Envelope: + return quickTest2DPolylineEnvelope((Polyline) geomA, + (Envelope) geomB, tolerance); + case Geometry.GeometryType.MultiPoint: + return quickTest2DPolylineMultiPoint((Polyline) geomA, + (MultiPoint) geomB, tolerance); + case Geometry.GeometryType.Polyline: + return quickTest2DPolylinePolyline((Polyline) geomA, + (Polyline) geomB, tolerance); + case Geometry.GeometryType.Polygon: + return reverseResult(quickTest2DPolygonPolyline( + (Polygon) geomB, (Polyline) geomA, tolerance)); + } + throw GeometryException.GeometryInternalError();// GEOMTHROW(internal_error);//what + // else? + } + case Geometry.GeometryType.Polygon: { + switch (geomBtype) { + case Geometry.GeometryType.Point: + return quickTest2DPolygonPoint((Polygon) geomA, (Point) geomB, + tolerance); + case Geometry.GeometryType.Envelope: + return quickTest2DPolygonEnvelope((Polygon) geomA, + (Envelope) geomB, tolerance); + case Geometry.GeometryType.MultiPoint: + return quickTest2DPolygonMultiPoint((Polygon) geomA, + (MultiPoint) geomB, tolerance); + case Geometry.GeometryType.Polyline: + return quickTest2DPolygonPolyline((Polygon) geomA, + (Polyline) geomB, tolerance); + case Geometry.GeometryType.Polygon: + return quickTest2DPolygonPolygon((Polygon) geomA, + (Polygon) geomB, tolerance); + } + throw GeometryException.GeometryInternalError();// GEOMTHROW(internal_error);//what + // else? + } + + default: + throw GeometryException.GeometryInternalError();// GEOMTHROW(internal_error);//what + // else? + // return 0; + } + } + + private static int quickTest2DPointPoint(Point geomA, Point geomB, + double tolerance) { + Point2D ptA = geomA.getXY(); + Point2D ptB = geomB.getXY(); + return quickTest2DPointPoint(ptA, ptB, tolerance); + } + + private static int quickTest2DPointPoint(Point2D ptA, Point2D ptB, + double tolerance) { + ptA.sub(ptB); + double len = ptA.sqrLength();// Should we test against 2*tol or tol? + if (len <= tolerance * tolerance)// Two points are equal if they are not + // Disjoint. We consider a point to + // be a disk of radius tolerance. + // Any intersection of two disks + // produces same disk. + return (int) Relation.Within | (int) Relation.Contains;// ==Equals + + return (int) Relation.Disjoint; + } + + private static int quickTest2DEnvelopePoint(Envelope geomA, Point geomB, + double tolerance) { + Envelope2D geomAEnv = new Envelope2D(); + geomA.queryEnvelope2D(geomAEnv); + Point2D ptB; + ptB = geomB.getXY(); + return quickTest2DEnvelopePoint(geomAEnv, ptB, tolerance); + } + + private static int quickTest2DEnvelopePoint(Envelope2D geomAEnv, + Point2D ptB, double tolerance) { + Envelope2D envAMinus = geomAEnv; + envAMinus.inflate(-tolerance, -tolerance); + if (envAMinus.contains(ptB)) + return (int) Relation.Contains;// clementini's contains + Envelope2D envAPlus = geomAEnv; + envAPlus.inflate(tolerance, tolerance); + if (envAPlus.contains(ptB)) + return (int) Relation.Touches;// clementini's touches + + return (int) Relation.Disjoint;// clementini's disjoint + } + + private static int quickTest2DEnvelopePoint(Envelope2D envAPlus, + Envelope2D envAMinus, Point2D ptB, double tolerance) { + if (envAMinus.contains(ptB)) + return (int) Relation.Contains;// clementini's contains + if (envAPlus.contains(ptB)) + return (int) Relation.Touches;// clementini's touches + + return (int) Relation.Disjoint;// clementini's disjoint + } + + private static int quickTest2DEnvelopeEnvelope(Envelope geomA, + Envelope geomB, double tolerance) { + Envelope2D geomAEnv = new Envelope2D(); + geomA.queryEnvelope2D(geomAEnv); + Envelope2D geomBEnv = new Envelope2D(); + geomB.queryEnvelope2D(geomBEnv); + return quickTest2DEnvelopeEnvelope(geomAEnv, geomBEnv, tolerance); + } + + private static int quickTest2DEnvelopeEnvelope(Envelope2D geomAEnv, + Envelope2D geomBEnv, double tolerance) { + // firstly check for contains and within to give a chance degenerate + // envelopes to work. + // otherwise, if there are two degenerate envelopes that are equal, + // Touch relation may occur. + int res = 0; + if (geomAEnv.contains(geomBEnv)) + res |= (int) Relation.Contains; + + if (geomBEnv.contains(geomAEnv)) + res |= (int) Relation.Within; + + if (res != 0) + return res; + + Envelope2D envAMinus = geomAEnv; + envAMinus.inflate(-tolerance, -tolerance);// Envelope A interior + Envelope2D envBMinus = geomBEnv; + envBMinus.inflate(-tolerance, -tolerance);// Envelope B interior + if (envAMinus.isIntersecting(envBMinus)) { + Envelope2D envAPlus = geomAEnv; + envAPlus.inflate(tolerance, tolerance);// Envelope A interior plus + // boundary + res = envAPlus.contains(geomBEnv) ? (int) Relation.Contains : 0; + Envelope2D envBPlus = geomBEnv; + envBPlus.inflate(tolerance, tolerance);// Envelope A interior plus + // boundary + res |= envBPlus.contains(geomAEnv) ? (int) Relation.Within : 0; + if (res != 0) + return res; + + return (int) Relation.Overlaps; // Clementini's Overlap + } else { + Envelope2D envAPlus = geomAEnv; + envAPlus.inflate(tolerance, tolerance);// Envelope A interior plus + // boundary + Envelope2D envBPlus = geomBEnv; + envBPlus.inflate(tolerance, tolerance);// Envelope A interior plus + // boundary + if (envAPlus.isIntersecting(envBPlus)) { + return (int) Relation.Touches; // Clementini Touch + } else { + return (int) Relation.Disjoint; // Clementini Disjoint + } + } + } + + private static int quickTest2DMultiPointPoint(MultiPoint geomA, + Point geomB, double tolerance) { + Point2D ptB; + ptB = geomB.getXY(); + return quickTest2DMultiPointPoint(geomA, ptB, tolerance); + } + + private static int quickTest2DMultiPointPoint(MultiPoint geomA, + Point2D ptB, double tolerance) { + // TODO: Add Geometry accelerator. (RasterizedGeometry + kd-tree or + // alike) + for (int i = 0, n = geomA.getPointCount(); i < n; i++) { + Point2D ptA; + ptA = geomA.getXY(i); + int res = quickTest2DPointPoint(ptA, ptB, tolerance); + if (res != (int) Relation.Disjoint) { + if ((res & (int) Relation.Within) != 0 && n != 1) { + // _ASSERT(res & (int)Relation.Contains); + return (int) Relation.Contains; + } + + return res; + } + } + + return (int) Relation.Disjoint; + } + + private static int quickTest2DMultiPointEnvelope(MultiPoint geomA, + Envelope geomB, double tolerance, int testType) { + Envelope2D geomBEnv = new Envelope2D(); + geomB.queryEnvelope2D(geomBEnv); + return quickTest2DMultiPointEnvelope(geomA, geomBEnv, tolerance, + testType); + } + + private static int quickTest2DMultiPointEnvelope(MultiPoint geomA, + Envelope2D geomBEnv, double tolerance, int testType) { + // Add early bailout for disjoint test. + Envelope2D envBMinus = geomBEnv; + envBMinus.inflate(-tolerance, -tolerance); + Envelope2D envBPlus = geomBEnv; + envBPlus.inflate(tolerance, tolerance); + int dres = 0; + for (int i = 0, n = geomA.getPointCount(); i < n; i++) { + Point2D ptA; + ptA = geomA.getXY(i); + int res = reverseResult(quickTest2DEnvelopePoint(envBPlus, + envBMinus, ptA, tolerance)); + if (res != (int) Relation.Disjoint) { + dres |= res; + if (testType == (int) Relation.Disjoint) + return (int) Relation.Intersects; + } + } + + if (dres == 0) + return (int) Relation.Disjoint; + + if (dres == (int) Relation.Within) + return dres; + + return (int) Relation.Overlaps; + } + + private static int quickTest2DMultiPointMultiPoint(MultiPoint geomA, + MultiPoint geomB, double tolerance, int testType) { + int counter = 0; + for (int ib = 0, nb = geomB.getPointCount(); ib < nb; ib++) { + Point2D ptB; + ptB = geomB.getXY(ib); + int res = quickTest2DMultiPointPoint(geomA, ptB, tolerance); + if (res != (int) Relation.Disjoint) { + counter++; + if (testType == (int) Relation.Disjoint) + return (int) Relation.Intersects; + } + } + + if (counter > 0) { + if (counter == geomB.getPointCount())// every point from B is within + // A. Means the A contains B + { + if (testType == (int) Relation.Equals) {// This is slow. + // Refactor. + int res = quickTest2DMultiPointMultiPoint(geomB, geomA, + tolerance, (int) Relation.Contains); + return res == (int) Relation.Contains ? (int) Relation.Equals + : (int) Relation.Unknown; + } + return (int) Relation.Contains; + } else { + return (int) Relation.Overlaps; + } + } + + return 0; + } + + private static int quickTest2DPolylinePoint(Polyline geomA, Point geomB, + double tolerance, int testType) { + Point2D ptB; + ptB = geomB.getXY(); + return quickTest2DPolylinePoint(geomA, ptB, tolerance, testType); + } + + private static int quickTest2DMVPointRasterOnly(MultiVertexGeometry geomA, + Point2D ptB, double tolerance) { + // Use rasterized Geometry: + RasterizedGeometry2D rgeomA = null; + MultiVertexGeometryImpl mpImpl = (MultiVertexGeometryImpl) geomA + ._getImpl(); + GeometryAccelerators gaccel = mpImpl._getAccelerators(); + if (gaccel != null) { + rgeomA = gaccel.getRasterizedGeometry(); + } + + if (rgeomA != null) { + RasterizedGeometry2D.HitType hitres = rgeomA.queryPointInGeometry( + ptB.x, ptB.y); + if (hitres == RasterizedGeometry2D.HitType.Outside) + return (int) Relation.Disjoint; + + if (hitres == RasterizedGeometry2D.HitType.Inside) + return (int) Relation.Contains; + } else + return -1; + + return 0; + } + + private static int quickTest2DPolylinePoint(Polyline geomA, Point2D ptB, + double tolerance, int testType) { + int mask = Relation.Touches | Relation.Contains | Relation.Within + | Relation.Disjoint | Relation.Intersects; + + if ((testType & mask) == 0) + return Relation.NoThisRelation; + + int res = quickTest2DMVPointRasterOnly(geomA, ptB, tolerance); + if (res > 0) + return res; + + // Go through the segments: + double toleranceSqr = tolerance * tolerance; + MultiPathImpl mpImpl = (MultiPathImpl) geomA._getImpl(); + SegmentIteratorImpl iter = mpImpl.querySegmentIterator(); + while (iter.nextPath()) { + int pathIndex = iter.getPathIndex(); + if (!geomA.isClosedPath(pathIndex)) { + int pathSize = geomA.getPathSize(pathIndex); + int pathStart = geomA.getPathStart(pathIndex); + if (pathSize == 0) + continue; + + if (Point2D.sqrDistance(geomA.getXY(pathStart), ptB) <= toleranceSqr + || (pathSize > 1 && Point2D.sqrDistance( + geomA.getXY(pathStart + pathSize - 1), ptB) <= toleranceSqr)) { + return (int) Relation.Touches; + } + } + + if (testType != Relation.Touches) { + while (iter.hasNextSegment()) { + Segment segment = iter.nextSegment(); + double t = segment.getClosestCoordinate(ptB, false); + Point2D pt = segment.getCoord2D(t); + if (Point2D.sqrDistance(pt, ptB) <= toleranceSqr) { + if ((testType & Relation.IntersectsOrDisjoint) != 0) { + return Relation.Intersects; + } + + return (int) Relation.Contains; + } + } + } + } + + return (testType & Relation.IntersectsOrDisjoint) != 0 ? Relation.Disjoint + : Relation.NoThisRelation; + } + + private static int quickTest2DPolylineEnvelope(Polyline geomA, + Envelope geomB, double tolerance) { + Envelope2D geomBEnv = new Envelope2D(); + geomB.queryEnvelope2D(geomBEnv); + return quickTest2DPolylineEnvelope(geomA, geomBEnv, tolerance); + } + + private static int quickTest2DPolylineEnvelope(Polyline geomA, + Envelope2D geomBEnv, double tolerance) { + int res = quickTest2DMVEnvelopeRasterOnly(geomA, geomBEnv, tolerance); + if (res > 0) + return res; + + // TODO: implement me + return 0; + } + + private static int quickTest2DMVEnvelopeRasterOnly( + MultiVertexGeometry geomA, Envelope2D geomBEnv, double tolerance) { + // Use rasterized Geometry only: + RasterizedGeometry2D rgeomA; + MultiVertexGeometryImpl mpImpl = (MultiVertexGeometryImpl) geomA + ._getImpl(); + GeometryAccelerators gaccel = mpImpl._getAccelerators(); + if (gaccel != null) { + rgeomA = gaccel.getRasterizedGeometry(); + } else + return -1; + + if (rgeomA != null) { + HitType hitres = rgeomA.queryEnvelopeInGeometry(geomBEnv); + if (hitres == RasterizedGeometry2D.HitType.Outside) + return (int) Relation.Disjoint; + + if (hitres == RasterizedGeometry2D.HitType.Inside) + return (int) Relation.Contains; + } else + return -1; + + return 0; + } + + private static int quickTest2DPolylineMultiPoint(Polyline geomA, + MultiPoint geomB, double tolerance) { + Envelope2D geomBEnv = new Envelope2D(); + geomB.queryEnvelope2D(geomBEnv); + int res = quickTest2DMVEnvelopeRasterOnly(geomA, geomBEnv, tolerance); + if (res > 0) + return res; + + // TODO: implement me + return 0; + } + + private static int quickTest2DMVMVRasterOnly(MultiVertexGeometry geomA, + MultiVertexGeometry geomB, double tolerance) { + Envelope2D geomBEnv = new Envelope2D(); + geomB.queryEnvelope2D(geomBEnv); + int res = quickTest2DMVEnvelopeRasterOnly(geomA, geomBEnv, tolerance); + if (res > 0) + return res; + + if (res == -1) { + Envelope2D geomAEnv = new Envelope2D(); + geomA.queryEnvelope2D(geomAEnv); + res = quickTest2DMVEnvelopeRasterOnly(geomB, geomAEnv, tolerance); + if (res > 0) + return reverseResult(res); + } + + // TODO: implement me + return 0; + } + + private static int quickTest2DPolylinePolyline(Polyline geomA, + Polyline geomB, double tolerance) { + int res = quickTest2DMVMVRasterOnly(geomA, geomB, tolerance); + if (res > 0) + return res; + + // TODO: implement me + return 0; + } + + private static int quickTest2DPolygonPoint(Polygon geomA, Point geomB, + double tolerance) { + Point2D ptB; + ptB = geomB.getXY(); + return quickTest2DPolygonPoint(geomA, ptB, tolerance); + } + + private static int quickTest2DPolygonPoint(Polygon geomA, Point2D ptB, + double tolerance) { + PolygonUtils.PiPResult pipres = PolygonUtils.isPointInPolygon2D(geomA, + ptB, tolerance);// this method uses the accelerator if available + if (pipres == PolygonUtils.PiPResult.PiPOutside) + return (int) Relation.Disjoint;// clementini's disjoint + + if (pipres == PolygonUtils.PiPResult.PiPInside) + return (int) Relation.Contains;// clementini's contains + + if (pipres == PolygonUtils.PiPResult.PiPBoundary) + return (int) Relation.Touches;// clementini's touches + + throw GeometryException.GeometryInternalError();// GEOMTHROW(internal_error); + // //what else + // return 0; + } + + private static int quickTest2DPolygonEnvelope(Polygon geomA, + Envelope geomB, double tolerance) { + Envelope2D geomBEnv = new Envelope2D(); + geomB.queryEnvelope2D(geomBEnv); + return quickTest2DPolygonEnvelope(geomA, geomBEnv, tolerance); + } + + private static int quickTest2DPolygonEnvelope(Polygon geomA, + Envelope2D geomBEnv, double tolerance) { + int res = quickTest2DMVEnvelopeRasterOnly(geomA, geomBEnv, tolerance); + if (res > 0) + return res; + + // TODO: implement me + return 0; + } + + private static int quickTest2DPolygonMultiPoint(Polygon geomA, + MultiPoint geomB, double tolerance) { + int res = quickTest2DMVMVRasterOnly(geomA, geomB, tolerance); + if (res > 0) + return res; + + // TODO: implement me + return 0; + } + + private static int quickTest2DPolygonPolyline(Polygon geomA, + Polyline geomB, double tolerance) { + int res = quickTest2DMVMVRasterOnly(geomA, geomB, tolerance); + if (res > 0) + return res; + + // TODO: implement me + return 0; + } + + private static int quickTest2DPolygonPolygon(Polygon geomA, Polygon geomB, + double tolerance) { + int res = quickTest2DMVMVRasterOnly(geomA, geomB, tolerance); + if (res > 0) + return res; + + // TODO: implement me + return 0; + } + + public static int quickTest2D_Accelerated_DisjointOrContains( + Geometry geomA, Geometry geomB, double tolerance) { + int gtA = geomA.getType().value(); + int gtB = geomB.getType().value(); + GeometryAccelerators accel; + boolean endWhileStatement = false; + do { + if (Geometry.isMultiVertex(gtA)) { + MultiVertexGeometryImpl impl = (MultiVertexGeometryImpl) geomA + ._getImpl(); + accel = impl._getAccelerators(); + if (accel != null) { + RasterizedGeometry2D rgeom = accel.getRasterizedGeometry(); + if (rgeom != null) { + if (gtB == Geometry.GeometryType.Point) { + Point2D ptB = ((Point) geomB).getXY(); + HitType hit = rgeom.queryPointInGeometry(ptB.x, + ptB.y); + if (hit == RasterizedGeometry2D.HitType.Inside) { + return (int) Relation.Contains; + } else if (hit == RasterizedGeometry2D.HitType.Outside) { + return (int) Relation.Disjoint; + } + + break; + } + Envelope2D envB = new Envelope2D(); + geomB.queryEnvelope2D(envB); + RasterizedGeometry2D.HitType hit = rgeom + .queryEnvelopeInGeometry(envB); + if (hit == RasterizedGeometry2D.HitType.Inside) { + return (int) Relation.Contains; + } else if (hit == RasterizedGeometry2D.HitType.Outside) { + return (int) Relation.Disjoint; + } + + break; + } + } + } + } while (endWhileStatement); + + accel = null; + do { + if (Geometry.isMultiVertex(gtB)) { + MultiVertexGeometryImpl impl = (MultiVertexGeometryImpl) geomB + ._getImpl(); + accel = impl._getAccelerators(); + if (accel != null) { + RasterizedGeometry2D rgeom = accel.getRasterizedGeometry(); + if (rgeom != null) { + if (gtA == Geometry.GeometryType.Point) { + Point2D ptA = ((Point) geomA).getXY(); + RasterizedGeometry2D.HitType hit = rgeom + .queryPointInGeometry(ptA.x, ptA.y); + if (hit == RasterizedGeometry2D.HitType.Inside) { + return (int) Relation.Within; + } else if (hit == RasterizedGeometry2D.HitType.Outside) { + return (int) Relation.Disjoint; + } + + break; + } + + Envelope2D envA = new Envelope2D(); + geomA.queryEnvelope2D(envA); + RasterizedGeometry2D.HitType hit = rgeom + .queryEnvelopeInGeometry(envA); + if (hit == RasterizedGeometry2D.HitType.Inside) { + return (int) Relation.Within; + } else if (hit == RasterizedGeometry2D.HitType.Outside) { + return (int) Relation.Disjoint; + } + + break; + } + } + } + } while (endWhileStatement); + + return 0; + } + + private static int reverseResult(int resIn) { + int res = resIn; + if ((res & (int) Relation.Contains) != 0) { + res &= ~(int) Relation.Contains; + res |= (int) Relation.Within; + } + if ((res & (int) Relation.Within) != 0) { + res &= ~(int) Relation.Within; + res |= (int) Relation.Contains; + } + + return res; + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorIntersection.java b/src/main/java/com/esri/core/geometry/OperatorIntersection.java index 7e151db5..e820025e 100644 --- a/src/main/java/com/esri/core/geometry/OperatorIntersection.java +++ b/src/main/java/com/esri/core/geometry/OperatorIntersection.java @@ -28,71 +28,73 @@ * Intersection of geometries by a given geometry. */ public abstract class OperatorIntersection extends Operator implements CombineOperator { - @Override - public Type getType() { - return Type.Intersection; - } + @Override + public Type getType() { + return Type.Intersection; + } - /** - * Performs the Topological Intersection operation on the geometry set. - * - * @param inputGeometries is the set of Geometry instances to be intersected by the intersector. - * @param intersector is the intersector Geometry. - *

- * The operator intersects every geometry in the inputGeometries with the first geometry of the intersector and returns the result. - */ - public abstract GeometryCursor execute(GeometryCursor inputGeometries, - GeometryCursor intersector, SpatialReference sr, - ProgressTracker progressTracker); + /** + * Performs the Topological Intersection operation on the geometry set. + * + * @param inputGeometries is the set of Geometry instances to be intersected by the intersector. + * @param intersector is the intersector Geometry. + *

+ * The operator intersects every geometry in the inputGeometries with the first geometry of the intersector and returns the result. + */ + public abstract GeometryCursor execute(GeometryCursor inputGeometries, + GeometryCursor intersector, SpatialReference sr, + ProgressTracker progressTracker); - /** - *Performs the Topological intersection operation on the geometry set. - *@param input_geometries is the set of Geometry instances to be intersected by the intersector. - *@param intersector is the intersector Geometry. Only single intersector is used, therefore, the intersector.next() is called only once. - *@param sr The spatial reference is used to get tolerance value. Can be null, then the tolerance is not used and the operation is performed with - *a small tolerance value just enough to make the operation robust. - *@param progress_tracker Allows to cancel the operation. Can be null. - *@param dimensionMask The dimension of the intersection. The value is either -1, or a bitmask mask of values (1 << dim). - *The value of -1 means the lower dimension in the intersecting pair. - *This is a fastest option when intersecting polygons with polygons or polylines. - *The bitmask of values (1 << dim), where dim is the desired dimension value, is used to indicate - *what dimensions of geometry one wants to be returned. For example, to return - *multipoints and lines only, pass (1 << 0) | (1 << 1), which is equivalen to 1 | 2, or 3. - *@return Returns the cursor of the intersection result. The cursors' getGeometryID method returns the current ID of the input geometry - *being processed. When dimensionMask is a bitmask, there will be n result geometries per one input geometry returned, where n is the number - *of bits set in the bitmask. For example, if the dimensionMask is 5, there will be two geometries per one input geometry. - * - *The operator intersects every geometry in the input_geometries with the first geometry of the intersector and returns the result. - * - *Note, when the dimensionMask is -1, then for each intersected pair of geometries, - *the result has the lower of dimentions of the two geometries. That is, the dimension of the Polyline/Polyline intersection - *is always 1 (that is, for polylines it never returns crossing points, but the overlaps only). - *If dimensionMask is 7, the operation will return any possible intersections. - */ - public abstract GeometryCursor execute(GeometryCursor input_geometries, - GeometryCursor intersector, SpatialReference sr, - ProgressTracker progress_tracker, int dimensionMask); + /** + * Performs the Topological intersection operation on the geometry set. + * + * @param input_geometries is the set of Geometry instances to be intersected by the intersector. + * @param intersector is the intersector Geometry. Only single intersector is used, therefore, the intersector.next() is called only once. + * @param sr The spatial reference is used to get tolerance value. Can be null, then the tolerance is not used and the operation is performed with + * a small tolerance value just enough to make the operation robust. + * @param progress_tracker Allows to cancel the operation. Can be null. + * @param dimensionMask The dimension of the intersection. The value is either -1, or a bitmask mask of values (1 << dim). + * The value of -1 means the lower dimension in the intersecting pair. + * This is a fastest option when intersecting polygons with polygons or polylines. + * The bitmask of values (1 << dim), where dim is the desired dimension value, is used to indicate + * what dimensions of geometry one wants to be returned. For example, to return + * multipoints and lines only, pass (1 << 0) | (1 << 1), which is equivalen to 1 | 2, or 3. + * @return Returns the cursor of the intersection result. The cursors' getGeometryID method returns the current ID of the input geometry + * being processed. When dimensionMask is a bitmask, there will be n result geometries per one input geometry returned, where n is the number + * of bits set in the bitmask. For example, if the dimensionMask is 5, there will be two geometries per one input geometry. + *

+ * The operator intersects every geometry in the input_geometries with the first geometry of the intersector and returns the result. + *

+ * Note, when the dimensionMask is -1, then for each intersected pair of geometries, + * the result has the lower of dimentions of the two geometries. That is, the dimension of the Polyline/Polyline intersection + * is always 1 (that is, for polylines it never returns crossing points, but the overlaps only). + * If dimensionMask is 7, the operation will return any possible intersections. + */ + public abstract GeometryCursor execute(GeometryCursor input_geometries, + GeometryCursor intersector, SpatialReference sr, + ProgressTracker progress_tracker, int dimensionMask); - /** - *Performs the Topological Intersection operation on the geometry. - *The result has the lower of dimentions of the two geometries. That is, the dimension of the - *Polyline/Polyline intersection is always 1 (that is, for polylines it never returns crossing - *points, but the overlaps only). - *The call is equivalent to calling the overloaded method using cursors: - *execute(new SimpleGeometryCursor(input_geometry), new SimpleGeometryCursor(intersector), sr, progress_tracker, mask).next(); - *where mask can be either -1 or min(1 << input_geometry.getDimension(), 1 << intersector.getDimension()); - *@param inputGeometry is the Geometry instance to be intersected by the intersector. - *@param intersector is the intersector Geometry. - *@param sr The spatial reference to get the tolerance value from. Can be null, then the tolerance is calculated from the input geometries. - *@return Returns the intersected Geometry. - */ - public abstract Geometry execute(Geometry inputGeometry, - Geometry intersector, SpatialReference sr, - ProgressTracker progressTracker); + /** + * Performs the Topological Intersection operation on the geometry. + * The result has the lower of dimentions of the two geometries. That is, the dimension of the + * Polyline/Polyline intersection is always 1 (that is, for polylines it never returns crossing + * points, but the overlaps only). + * The call is equivalent to calling the overloaded method using cursors: + * execute(new SimpleGeometryCursor(input_geometry), new SimpleGeometryCursor(intersector), sr, progress_tracker, mask).next(); + * where mask can be either -1 or min(1 << input_geometry.getDimension(), 1 << intersector.getDimension()); + * + * @param inputGeometry is the Geometry instance to be intersected by the intersector. + * @param intersector is the intersector Geometry. + * @param sr The spatial reference to get the tolerance value from. Can be null, then the tolerance is calculated from the input geometries. + * @return Returns the intersected Geometry. + */ + public abstract Geometry execute(Geometry inputGeometry, + Geometry intersector, SpatialReference sr, + ProgressTracker progressTracker); - public static OperatorIntersection local() { - return (OperatorIntersection) OperatorFactoryLocal.getInstance() - .getOperator(Type.Intersection); - } + public static OperatorIntersection local() { + return (OperatorIntersection) OperatorFactoryLocal.getInstance() + .getOperator(Type.Intersection); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorIntersectionCursor.java b/src/main/java/com/esri/core/geometry/OperatorIntersectionCursor.java index 223f36f9..5e23bc82 100644 --- a/src/main/java/com/esri/core/geometry/OperatorIntersectionCursor.java +++ b/src/main/java/com/esri/core/geometry/OperatorIntersectionCursor.java @@ -26,775 +26,775 @@ // TODO test this public class OperatorIntersectionCursor extends GeometryCursor { - GeometryCursor m_smallCursor; - ProgressTracker m_progress_tracker; - SpatialReference m_spatial_reference; - Geometry m_geomIntersector; - Geometry m_geomIntersectorEmptyGeom;// holds empty geometry of intersector - // type. - int m_geomIntersectorType; - int m_currentGeomType; - int m_dimensionMask; - boolean m_bEmpty; - - OperatorIntersectionCursor(GeometryCursor inputGeoms, - GeometryCursor geomIntersector, - SpatialReference sr, - ProgressTracker progress_tracker, - int dimensionMask) { - m_bEmpty = geomIntersector == null; - m_inputGeoms = inputGeoms; - m_spatial_reference = sr; - m_geomIntersector = geomIntersector.next(); - m_geomIntersectorType = m_geomIntersector.getType().value(); - m_currentGeomType = Geometry.Type.Unknown.value(); - m_progress_tracker = progress_tracker; - m_dimensionMask = dimensionMask; - if (m_dimensionMask != -1 - && (m_dimensionMask <= 0 || m_dimensionMask > 7)) - throw new IllegalArgumentException("bad dimension mask");// dimension - // mask - // can - // be - // -1, - // for - // the - // default - // behavior, - // or a - // value - // between - // 1 and - // 7. - } - - @Override - public Geometry next() { - if (m_bEmpty) - return null; - - Geometry geom; - if (m_smallCursor != null && m_smallCursor.hasNext()) {// when dimension mask is used, we produce a - geom = m_smallCursor.next(); - if (geom != null) - return geom; - else - m_smallCursor = null;// done with the small cursor - } - - if (m_inputGeoms.hasNext()) { - geom = m_inputGeoms.next(); - if (m_dimensionMask == -1) { - Geometry resGeom = intersect(geom); - assert (resGeom != null); - return resGeom; - } else { - m_smallCursor = intersectEx(geom); - Geometry resGeom = m_smallCursor.next(); - assert (resGeom != null); - return resGeom; - } - } - return null; - } - - Geometry intersect(Geometry input_geom) { - Geometry dst_geom = tryNativeImplementation_(input_geom); - if (dst_geom != null) - return dst_geom; - - Envelope2D commonExtent = InternalUtils.getMergedExtent( - m_geomIntersector, input_geom); - - // return Topological_operations::intersection(input_geom, - // m_geomIntersector, m_spatial_reference, m_progress_tracker); - // Preprocess geometries to be clipped to the extent of intersection to - // get rid of extra segments. - double t = InternalUtils.calculateToleranceFromGeometry(m_spatial_reference, commonExtent, true); - Envelope2D env = new Envelope2D(); - m_geomIntersector.queryEnvelope2D(env); - Envelope2D env1 = new Envelope2D(); - input_geom.queryEnvelope2D(env1); - env.inflate(2.0 * t, 2.0 * t); - env.intersect(env1); - assert (!env.isEmpty()); - env.inflate(100 * t, 100 * t); - double tol = 0; - Geometry clippedIntersector = Clipper.clip(m_geomIntersector, env, tol, - 0.0); - Geometry clippedInputGeom = Clipper.clip(input_geom, env, tol, 0.0); - // perform the clip - return TopologicalOperations.intersection(clippedInputGeom, - clippedIntersector, m_spatial_reference, m_progress_tracker); - } - - // Parses the input vector to ensure the out result contains only geometries - // as indicated with the dimensionMask - GeometryCursor prepareVector_(VertexDescription descr, int dimensionMask, - Geometry[] res_vec) { - int inext = 0; - if ((dimensionMask & 1) != 0) { - if (res_vec[0] == null) - res_vec[0] = new MultiPoint(descr); - inext++; - } else { - for (int i = 0; i < res_vec.length - 1; i++) - res_vec[i] = res_vec[i + 1]; - } - - if ((dimensionMask & 2) != 0) { - if (res_vec[inext] == null) - res_vec[inext] = new Polyline(descr); - inext++; - } else { - for (int i = inext; i < res_vec.length - 1; i++) - res_vec[i] = res_vec[i + 1]; - } - - if ((dimensionMask & 4) != 0) { - if (res_vec[inext] == null) - res_vec[inext] = new Polygon(descr); - inext++; - } else { - for (int i = inext; i < res_vec.length - 1; i++) - res_vec[i] = res_vec[i + 1]; - } - - if (inext != 3) { - Geometry[] r = new Geometry[inext]; - for (int i = 0; i < inext; i++) - r[i] = res_vec[i]; - - return new SimpleGeometryCursor(r); - } else { - return new SimpleGeometryCursor(res_vec); - } - } - - GeometryCursor intersectEx(Geometry input_geom) { - assert (m_dimensionMask != -1); - Geometry dst_geom = tryNativeImplementation_(input_geom); - if (dst_geom != null) { - Geometry[] res_vec = new Geometry[3]; - res_vec[dst_geom.getDimension()] = dst_geom; - return prepareVector_(input_geom.getDescription(), m_dimensionMask, - res_vec); - } - - Envelope2D commonExtent = InternalUtils.getMergedExtent( - m_geomIntersector, input_geom); - double t = InternalUtils.calculateToleranceFromGeometry( - m_spatial_reference, commonExtent, true); - - // Preprocess geometries to be clipped to the extent of intersection to - // get rid of extra segments. - - Envelope2D env = new Envelope2D(); - m_geomIntersector.queryEnvelope2D(env); - env.inflate(2 * t, 2 * t); - Envelope2D env1 = new Envelope2D(); - input_geom.queryEnvelope2D(env1); - env.intersect(env1); - assert (!env.isEmpty()); - env.inflate(100 * t, 100 * t); - double tol = 0; - Geometry clippedIntersector = Clipper.clip(m_geomIntersector, env, tol, - 0.0); - Geometry clippedInputGeom = Clipper.clip(input_geom, env, tol, 0.0); - // perform the clip - Geometry[] res_vec; - res_vec = TopologicalOperations.intersectionEx(clippedInputGeom, - clippedIntersector, m_spatial_reference, m_progress_tracker); - return prepareVector_(input_geom.getDescription(), m_dimensionMask, - res_vec); - } - - Geometry tryNativeImplementation_(Geometry input_geom) { - // A note on attributes: - // 1. The geometry with lower dimension wins in regard to the - // attributes. - // 2. If the dimensions are the same, the input_geometry attributes win. - // 3. The exception to the 2. is when the input is an Envelope, and the - // intersector is a polygon, then the intersector wins. - - // A note on the tolerance: - // This operator performs a simple intersection operation. Should it use - // the tolerance? - // Example: Point is intersected by the envelope. - // If it is slightly outside of the envelope, should we still return it - // if it is closer than the tolerance? - // Should we do crack and cluster and snap the point coordinates to the - // envelope boundary? - // - // Consider floating point arithmetics approach. When you compare - // doubles, you should use an epsilon (equals means ::fabs(a - b) < - // eps), however when you add/subtract, etc them, you do not use - // epsilon. - // Shouldn't we do same here? Relational operators use tolerance, but - // the action operators don't. - - Envelope2D mergedExtent = InternalUtils.getMergedExtent(input_geom, - m_geomIntersector); - double tolerance = InternalUtils.calculateToleranceFromGeometry( - m_spatial_reference, mergedExtent, false); - - int gtInput = input_geom.getType().value(); - boolean bInputEmpty = input_geom.isEmpty(); - boolean bGeomIntersectorEmpty = m_geomIntersector.isEmpty(); - boolean bResultIsEmpty = bInputEmpty || bGeomIntersectorEmpty; - if (!bResultIsEmpty) {// test envelopes - Envelope2D env2D1 = new Envelope2D(); - input_geom.queryEnvelope2D(env2D1); - Envelope2D env2D2 = new Envelope2D(); - m_geomIntersector.queryEnvelope2D(env2D2); - env2D2.inflate(2.0 * tolerance, 2.0 * tolerance); - bResultIsEmpty = !env2D1.isIntersecting(env2D2); - } - - if (!bResultIsEmpty) {// try accelerated test - int res = OperatorInternalRelationUtils - .quickTest2D_Accelerated_DisjointOrContains( - m_geomIntersector, input_geom, tolerance); - if (res == OperatorInternalRelationUtils.Relation.Disjoint) {// disjoint - bResultIsEmpty = true; - } else if ((res & OperatorInternalRelationUtils.Relation.Within) != 0) {// intersector - // is - // within - // the - // input_geom - // TODO: - // assign - // input_geom - // attributes - // first - return m_geomIntersector; - } else if ((res & OperatorInternalRelationUtils.Relation.Contains) != 0) {// intersector - // contains - // input_geom - return input_geom; - } - } - - if (bResultIsEmpty) {// When one geometry or both are empty, we need to - // return an empty geometry. - // Here we do that end also ensure the type is - // correct. - // That is the lower dimension need to be - // returned. Also, for Point vs Multi_point, an - // empty Point need to be returned. - int dim1 = Geometry.getDimensionFromType(gtInput); - int dim2 = Geometry.getDimensionFromType(m_geomIntersectorType); - if (dim1 < dim2) - return returnEmpty_(input_geom, bInputEmpty); - else if (dim1 > dim2) - return returnEmptyIntersector_(); - else if (dim1 == 0) { - if (gtInput == Geometry.GeometryType.MultiPoint - && m_geomIntersectorType == Geometry.GeometryType.Point) {// point - // vs - // Multi_point - // need - // special - // treatment - // to - // ensure - // Point - // is - // returned - // always. - return returnEmptyIntersector_(); - } else - // Both input and intersector have same gtype, or input is - // Point. - return returnEmpty_(input_geom, bInputEmpty); - } else - return returnEmpty_(input_geom, bInputEmpty); - } - - // Note: No empty geometries after this point! - - // Warning: Do not try clip for polylines and polygons. - - // Try clip of Envelope with Envelope. - if ((m_dimensionMask == -1 || m_dimensionMask == (1 << 2)) - && gtInput == Geometry.GeometryType.Envelope - && m_geomIntersectorType == Geometry.GeometryType.Envelope) { - Envelope env1 = (Envelope) input_geom; - Envelope env2 = (Envelope) m_geomIntersector; - Envelope2D env2D_1 = new Envelope2D(); - env1.queryEnvelope2D(env2D_1); - Envelope2D env2D_2 = new Envelope2D(); - env2.queryEnvelope2D(env2D_2); - env2D_1.intersect(env2D_2); - Envelope result_env = new Envelope(); - env1.copyTo(result_env); - result_env.setEnvelope2D(env2D_1); - return result_env; - } - - // Use clip for Point and Multi_point with Envelope - if ((gtInput == Geometry.GeometryType.Envelope && Geometry - .getDimensionFromType(m_geomIntersectorType) == 0) - || (m_geomIntersectorType == Geometry.GeometryType.Envelope && Geometry - .getDimensionFromType(gtInput) == 0)) { - Envelope env = gtInput == Geometry.GeometryType.Envelope ? (Envelope) input_geom - : (Envelope) m_geomIntersector; - Geometry other = gtInput == Geometry.GeometryType.Envelope ? m_geomIntersector - : input_geom; - Envelope2D env_2D = new Envelope2D(); - env.queryEnvelope2D(env_2D); - return Clipper.clip(other, env_2D, tolerance, 0); - } - - if ((Geometry.getDimensionFromType(gtInput) == 0 && Geometry - .getDimensionFromType(m_geomIntersectorType) > 0) - || (Geometry.getDimensionFromType(gtInput) > 0 && Geometry - .getDimensionFromType(m_geomIntersectorType) == 0)) {// multipoint - // intersection - double tolerance1 = InternalUtils.calculateToleranceFromGeometry( - m_spatial_reference, input_geom, false); - if (gtInput == Geometry.GeometryType.MultiPoint) - return TopologicalOperations.intersection( - (MultiPoint) input_geom, m_geomIntersector, tolerance1); - if (gtInput == Geometry.GeometryType.Point) - return TopologicalOperations.intersection((Point) input_geom, - m_geomIntersector, tolerance1); - if (m_geomIntersectorType == Geometry.GeometryType.MultiPoint) - return TopologicalOperations.intersection( - (MultiPoint) m_geomIntersector, input_geom, tolerance1); - if (m_geomIntersectorType == Geometry.GeometryType.Point) - return TopologicalOperations.intersection( - (Point) m_geomIntersector, input_geom, tolerance1); - throw GeometryException.GeometryInternalError(); - } - - // Try Polyline vs Polygon - if ((m_dimensionMask == -1 || m_dimensionMask == (1 << 1)) - && (gtInput == Geometry.GeometryType.Polyline) - && (m_geomIntersectorType == Geometry.GeometryType.Polygon)) { - return tryFastIntersectPolylinePolygon_((Polyline) (input_geom), - (Polygon) (m_geomIntersector)); - } - - // Try Polygon vs Polyline - if ((m_dimensionMask == -1 || m_dimensionMask == (1 << 1)) - && (gtInput == Geometry.GeometryType.Polygon) - && (m_geomIntersectorType == Geometry.GeometryType.Polyline)) { - return tryFastIntersectPolylinePolygon_( - (Polyline) (m_geomIntersector), (Polygon) (input_geom)); - } - - return null; - } - - Geometry tryFastIntersectPolylinePolygon_(Polyline polyline, Polygon polygon) { - MultiPathImpl polylineImpl = (MultiPathImpl) polyline._getImpl(); - MultiPathImpl polygonImpl = (MultiPathImpl) polygon._getImpl(); - - double tolerance = InternalUtils.calculateToleranceFromGeometry( - m_spatial_reference, polygon, false); - Envelope2D clipEnvelope = new Envelope2D(); - { - polygonImpl.queryEnvelope2D(clipEnvelope); - Envelope2D env1 = new Envelope2D(); - polylineImpl.queryEnvelope2D(env1); - env1.inflate(2.0 * tolerance, 2.0 * tolerance); - clipEnvelope.intersect(env1); - assert (!clipEnvelope.isEmpty()); - } - - clipEnvelope.inflate(10 * tolerance, 10 * tolerance); - - if (true) { - double tol = 0; - Geometry clippedPolyline = Clipper.clip(polyline, clipEnvelope, - tol, 0.0); - polyline = (Polyline) clippedPolyline; - polylineImpl = (MultiPathImpl) polyline._getImpl(); - } - - AttributeStreamOfInt32 clipResult = new AttributeStreamOfInt32(0); - int unresolvedSegments = -1; - GeometryAccelerators accel = polygonImpl._getAccelerators(); - if (accel != null) { - RasterizedGeometry2D rgeom = accel.getRasterizedGeometry(); - if (rgeom != null) { - unresolvedSegments = 0; - clipResult.reserve(polylineImpl.getPointCount() - + polylineImpl.getPathCount()); - Envelope2D seg_env = new Envelope2D(); - SegmentIteratorImpl iter = polylineImpl.querySegmentIterator(); - while (iter.nextPath()) { - while (iter.hasNextSegment()) { - Segment seg = iter.nextSegment(); - seg.queryEnvelope2D(seg_env); - RasterizedGeometry2D.HitType hit = rgeom - .queryEnvelopeInGeometry(seg_env); - if (hit == RasterizedGeometry2D.HitType.Inside) { - clipResult.add(1); - } else if (hit == RasterizedGeometry2D.HitType.Outside) { - clipResult.add(0); - } else { - clipResult.add(-1); - unresolvedSegments++; - } - } - } - } - } - - if (polygon.getPointCount() > 5) { - double tol = 0; - Geometry clippedPolygon = Clipper.clip(polygon, clipEnvelope, tol, - 0.0); - - polygon = (Polygon) clippedPolygon; - polygonImpl = (MultiPathImpl) polygon._getImpl(); - accel = polygonImpl._getAccelerators();//update accelerators - } - - if (unresolvedSegments < 0) { - unresolvedSegments = polylineImpl.getSegmentCount(); - } - - // Some heuristics to decide if it makes sense to go with fast intersect - // vs going with the regular planesweep. - double totalPoints = (double) (polylineImpl.getPointCount() + polygonImpl - .getPointCount()); - double thisAlgorithmComplexity = ((double) unresolvedSegments * polygonImpl - .getPointCount());// assume the worst case. - double planesweepComplexity = Math.log(totalPoints) * totalPoints; - double empiricConstantFactorPlaneSweep = 4; - if (thisAlgorithmComplexity > planesweepComplexity - * empiricConstantFactorPlaneSweep) { - // Based on the number of input points, we deduced that the - // plansweep performance should be better than the brute force - // performance. - return null; // resort to planesweep if quadtree does not help - } - - QuadTreeImpl polygonQuadTree = null; - SegmentIteratorImpl polygonIter = polygonImpl.querySegmentIterator(); - // Some logic to decide if it makes sense to build a quadtree on the - // polygon segments - if (accel != null && accel.getQuadTree() != null) - polygonQuadTree = accel.getQuadTree(); - - if (polygonQuadTree == null && polygonImpl.getPointCount() > 20) { - polygonQuadTree = InternalUtils.buildQuadTree(polygonImpl); - } - - Polyline result_polyline = (Polyline) polyline.createInstance(); - MultiPathImpl resultPolylineImpl = (MultiPathImpl) result_polyline - ._getImpl(); - QuadTreeImpl.QuadTreeIteratorImpl qIter = null; - SegmentIteratorImpl polylineIter = polylineImpl.querySegmentIterator(); - double[] params = new double[9]; - AttributeStreamOfDbl intersections = new AttributeStreamOfDbl(0); - SegmentBuffer segmentBuffer = new SegmentBuffer(); - int start_index = -1; - int inCount = 0; - int segIndex = 0; - boolean bOptimized = clipResult.size() > 0; - - // The algorithm is like that: - // Loop through all the segments of the polyline. - // For each polyline segment, intersect it with each of the polygon - // segments. - // If no intersections found then, - // If the polyline segment is completely inside, it is added to the - // result polyline. - // If it is outside, it is thrown out. - // If it intersects, then cut the polyline segment to pieces and test - // each part of the intersected result. - // The cut pieces will either have one point inside, or one point - // outside, or the middle point inside/outside. - // - int polylinePathIndex = -1; - - while (polylineIter.nextPath()) { - polylinePathIndex = polylineIter.getPathIndex(); - int stateNewPath = 0; - int stateAddSegment = 1; - int stateManySegments = 2; - int stateManySegmentsContinuePath = 2; - int stateManySegmentsNewPath = 3; - int state = stateNewPath; - start_index = -1; - inCount = 0; - - while (polylineIter.hasNextSegment()) { - int clipStatus = bOptimized ? (int) clipResult.get(segIndex) - : -1; - segIndex++; - Segment polylineSeg = polylineIter.nextSegment(); - if (clipStatus < 0) { - assert (clipStatus == -1); - // Analyse polyline segment for intersection with the - // polygon. - if (polygonQuadTree != null) { - if (qIter == null) { - qIter = polygonQuadTree.getIterator(polylineSeg, - tolerance); - } else { - qIter.resetIterator(polylineSeg, tolerance); - } - - int path_index = -1; - for (int ind = qIter.next(); ind != -1; ind = qIter - .next()) { - polygonIter.resetToVertex(polygonQuadTree - .getElement(ind)); // path_index - path_index = polygonIter.getPathIndex(); - Segment polygonSeg = polygonIter.nextSegment(); - // intersect polylineSeg and polygonSeg. - int count = polylineSeg.intersect(polygonSeg, null, - params, null, tolerance); - for (int i = 0; i < count; i++) - intersections.add(params[i]); - } - } else {// no quadtree built - polygonIter.resetToFirstPath(); - while (polygonIter.nextPath()) { - while (polygonIter.hasNextSegment()) { - Segment polygonSeg = polygonIter.nextSegment(); - // intersect polylineSeg and polygonSeg. - int count = polylineSeg.intersect(polygonSeg, - null, params, null, tolerance); - for (int i = 0; i < count; i++) - intersections.add(params[i]); - } - } - } - - if (intersections.size() > 0) {// intersections detected. - intersections.sort(0, intersections.size()); // std::sort(intersections.begin(), - // intersections.end()); - - double t0 = 0; - intersections.add(1.0); - int status = -1; - for (int i = 0, n = intersections.size(); i < n; i++) { - double t = intersections.get(i); - if (t == t0) { - continue; - } - boolean bWholeSegment = false; - Segment resSeg; - if (t0 != 0 || t != 1.0) { - polylineSeg.cut(t0, t, segmentBuffer); - resSeg = segmentBuffer.get(); - } else { - resSeg = polylineSeg; - bWholeSegment = true; - } - - if (state >= stateManySegments) { - resultPolylineImpl.addSegmentsFromPath( - polylineImpl, polylinePathIndex, - start_index, inCount, - state == stateManySegmentsNewPath); - if (analyseClipSegment_(polygon, - resSeg.getStartXY(), tolerance) != 1) { - if (analyseClipSegment_(polygon, resSeg, - tolerance) != 1) { - return null; //someting went wrong we'll falback to slower but robust planesweep code. - } - } - - resultPolylineImpl.addSegment(resSeg, false); - state = stateAddSegment; - inCount = 0; - } else { - status = analyseClipSegment_(polygon, resSeg, - tolerance); - switch (status) { - case 1: - if (!bWholeSegment) { - resultPolylineImpl.addSegment(resSeg, - state == stateNewPath); - state = stateAddSegment; - } else { - if (state < stateManySegments) { - start_index = polylineIter - .getStartPointIndex() - - polylineImpl - .getPathStart(polylinePathIndex); - inCount = 1; - - if (state == stateNewPath) - state = stateManySegmentsNewPath; - else { - assert (state == stateAddSegment); - state = stateManySegmentsContinuePath; - } - } else - inCount++; - } - - break; - case 0: - state = stateNewPath; - start_index = -1; - inCount = 0; - break; - default: - return null;// may happen if a segment - // coincides with the border. - } - } - - t0 = t; - } - } else { - clipStatus = analyseClipSegment_(polygon, - polylineSeg.getStartXY(), tolerance);// simple - // case - // no - // intersection. - // Both - // points - // must - // be - // inside. - if (clipStatus < 0) { - assert (clipStatus >= 0); - return null;// something goes wrong, resort to - // planesweep - } - - assert (analyseClipSegment_(polygon, - polylineSeg.getEndXY(), tolerance) == clipStatus); - if (clipStatus == 1) {// the whole segment inside - if (state < stateManySegments) { - assert (inCount == 0); - start_index = polylineIter.getStartPointIndex() - - polylineImpl - .getPathStart(polylinePathIndex); - if (state == stateNewPath) - state = stateManySegmentsNewPath; - else { - assert (state == stateAddSegment); - state = stateManySegmentsContinuePath; - } - } - - inCount++; - } else { - assert (state < stateManySegments); - start_index = -1; - inCount = 0; - } - } - - intersections.clear(false); - } else {// clip status is determined by other means - if (clipStatus == 0) {// outside - assert (analyseClipSegment_(polygon, polylineSeg, - tolerance) == 0); - assert (start_index < 0); - assert (inCount == 0); - continue; - } - - if (clipStatus == 1) { - assert (analyseClipSegment_(polygon, polylineSeg, - tolerance) == 1); - if (state == stateNewPath) { - state = stateManySegmentsNewPath; - start_index = polylineIter.getStartPointIndex() - - polylineImpl - .getPathStart(polylinePathIndex); - } else if (state == stateAddSegment) { - state = stateManySegmentsContinuePath; - start_index = polylineIter.getStartPointIndex() - - polylineImpl - .getPathStart(polylinePathIndex); - } else - assert (state >= stateManySegments); - - inCount++; - continue; - } - } - } - - if (state >= stateManySegments) { - resultPolylineImpl.addSegmentsFromPath(polylineImpl, - polylinePathIndex, start_index, inCount, - state == stateManySegmentsNewPath); - start_index = -1; - } - } - - return result_polyline; - } - - int analyseClipSegment_(Polygon polygon, Point2D pt, double tol) { - int v = PointInPolygonHelper.isPointInPolygon(polygon, pt, tol); - return v; - } - - int analyseClipSegment_(Polygon polygon, Segment seg, double tol) { - Point2D pt_1 = seg.getStartXY(); - Point2D pt_2 = seg.getEndXY(); - int v_1 = PointInPolygonHelper.isPointInPolygon(polygon, pt_1, tol); - int v_2 = PointInPolygonHelper.isPointInPolygon(polygon, pt_2, tol); - if ((v_1 == 1 && v_2 == 0) || (v_1 == 0 && v_2 == 1)) { - // Operator_factory_local::SaveJSONToTextFileDbg("c:/temp/badPointInPolygon.json", - // polygon, m_spatial_reference); - assert (false);// if happens - return -1;// something went wrong. One point is inside, the other is - // outside. Should not happen. We'll resort to - // planesweep. - } - if (v_1 == 0 || v_2 == 0) - return 0; - if (v_1 == 1 || v_2 == 1) - return 1; - - Point2D midPt = new Point2D(); - midPt.add(pt_1, pt_2); - midPt.scale(0.5);// calculate midpoint - int v = PointInPolygonHelper.isPointInPolygon(polygon, midPt, tol); - if (v == 0) { - return 0; - } - - if (v == 1) { - return 1; - } - - return -1; - } - - Geometry normalizeIntersectionOutput(Geometry geom, int GT_1, int GT_2) { - if (GT_1 == Geometry.GeometryType.Point - || GT_2 == Geometry.GeometryType.Point) { - assert (geom.getType().value() == Geometry.GeometryType.Point); - } - if (GT_1 == Geometry.GeometryType.MultiPoint) { - if (geom.getType().value() == Geometry.GeometryType.Point) { - MultiPoint mp = new MultiPoint(geom.getDescription()); - if (!geom.isEmpty()) - mp.add((Point) geom); - return mp; - } - } - - return geom; - } - - static Geometry returnEmpty_(Geometry geom, boolean bEmpty) { - return bEmpty ? geom : geom.createInstance(); - } - - Geometry returnEmptyIntersector_() { - if (m_geomIntersectorEmptyGeom == null) - m_geomIntersectorEmptyGeom = m_geomIntersector.createInstance(); - - return m_geomIntersectorEmptyGeom; - } - - // virtual boolean IsRecycling() OVERRIDE { return false; } + GeometryCursor m_smallCursor; + ProgressTracker m_progress_tracker; + SpatialReference m_spatial_reference; + Geometry m_geomIntersector; + Geometry m_geomIntersectorEmptyGeom;// holds empty geometry of intersector + // type. + int m_geomIntersectorType; + int m_currentGeomType; + int m_dimensionMask; + boolean m_bEmpty; + + OperatorIntersectionCursor(GeometryCursor inputGeoms, + GeometryCursor geomIntersector, + SpatialReference sr, + ProgressTracker progress_tracker, + int dimensionMask) { + m_bEmpty = geomIntersector == null; + m_inputGeoms = inputGeoms; + m_spatial_reference = sr; + m_geomIntersector = geomIntersector.next(); + m_geomIntersectorType = m_geomIntersector.getType().value(); + m_currentGeomType = Geometry.Type.Unknown.value(); + m_progress_tracker = progress_tracker; + m_dimensionMask = dimensionMask; + if (m_dimensionMask != -1 + && (m_dimensionMask <= 0 || m_dimensionMask > 7)) + throw new IllegalArgumentException("bad dimension mask");// dimension + // mask + // can + // be + // -1, + // for + // the + // default + // behavior, + // or a + // value + // between + // 1 and + // 7. + } + + @Override + public Geometry next() { + if (m_bEmpty) + return null; + + Geometry geom; + if (m_smallCursor != null && m_smallCursor.hasNext()) {// when dimension mask is used, we produce a + geom = m_smallCursor.next(); + if (geom != null) + return geom; + else + m_smallCursor = null;// done with the small cursor + } + + if (m_inputGeoms.hasNext()) { + geom = m_inputGeoms.next(); + if (m_dimensionMask == -1) { + Geometry resGeom = intersect(geom); + assert (resGeom != null); + return resGeom; + } else { + m_smallCursor = intersectEx(geom); + Geometry resGeom = m_smallCursor.next(); + assert (resGeom != null); + return resGeom; + } + } + return null; + } + + Geometry intersect(Geometry input_geom) { + Geometry dst_geom = tryNativeImplementation_(input_geom); + if (dst_geom != null) + return dst_geom; + + Envelope2D commonExtent = InternalUtils.getMergedExtent( + m_geomIntersector, input_geom); + + // return Topological_operations::intersection(input_geom, + // m_geomIntersector, m_spatial_reference, m_progress_tracker); + // Preprocess geometries to be clipped to the extent of intersection to + // get rid of extra segments. + double t = InternalUtils.calculateToleranceFromGeometry(m_spatial_reference, commonExtent, true); + Envelope2D env = new Envelope2D(); + m_geomIntersector.queryEnvelope2D(env); + Envelope2D env1 = new Envelope2D(); + input_geom.queryEnvelope2D(env1); + env.inflate(2.0 * t, 2.0 * t); + env.intersect(env1); + assert (!env.isEmpty()); + env.inflate(100 * t, 100 * t); + double tol = 0; + Geometry clippedIntersector = Clipper.clip(m_geomIntersector, env, tol, + 0.0); + Geometry clippedInputGeom = Clipper.clip(input_geom, env, tol, 0.0); + // perform the clip + return TopologicalOperations.intersection(clippedInputGeom, + clippedIntersector, m_spatial_reference, m_progress_tracker); + } + + // Parses the input vector to ensure the out result contains only geometries + // as indicated with the dimensionMask + GeometryCursor prepareVector_(VertexDescription descr, int dimensionMask, + Geometry[] res_vec) { + int inext = 0; + if ((dimensionMask & 1) != 0) { + if (res_vec[0] == null) + res_vec[0] = new MultiPoint(descr); + inext++; + } else { + for (int i = 0; i < res_vec.length - 1; i++) + res_vec[i] = res_vec[i + 1]; + } + + if ((dimensionMask & 2) != 0) { + if (res_vec[inext] == null) + res_vec[inext] = new Polyline(descr); + inext++; + } else { + for (int i = inext; i < res_vec.length - 1; i++) + res_vec[i] = res_vec[i + 1]; + } + + if ((dimensionMask & 4) != 0) { + if (res_vec[inext] == null) + res_vec[inext] = new Polygon(descr); + inext++; + } else { + for (int i = inext; i < res_vec.length - 1; i++) + res_vec[i] = res_vec[i + 1]; + } + + if (inext != 3) { + Geometry[] r = new Geometry[inext]; + for (int i = 0; i < inext; i++) + r[i] = res_vec[i]; + + return new SimpleGeometryCursor(r); + } else { + return new SimpleGeometryCursor(res_vec); + } + } + + GeometryCursor intersectEx(Geometry input_geom) { + assert (m_dimensionMask != -1); + Geometry dst_geom = tryNativeImplementation_(input_geom); + if (dst_geom != null) { + Geometry[] res_vec = new Geometry[3]; + res_vec[dst_geom.getDimension()] = dst_geom; + return prepareVector_(input_geom.getDescription(), m_dimensionMask, + res_vec); + } + + Envelope2D commonExtent = InternalUtils.getMergedExtent( + m_geomIntersector, input_geom); + double t = InternalUtils.calculateToleranceFromGeometry( + m_spatial_reference, commonExtent, true); + + // Preprocess geometries to be clipped to the extent of intersection to + // get rid of extra segments. + + Envelope2D env = new Envelope2D(); + m_geomIntersector.queryEnvelope2D(env); + env.inflate(2 * t, 2 * t); + Envelope2D env1 = new Envelope2D(); + input_geom.queryEnvelope2D(env1); + env.intersect(env1); + assert (!env.isEmpty()); + env.inflate(100 * t, 100 * t); + double tol = 0; + Geometry clippedIntersector = Clipper.clip(m_geomIntersector, env, tol, + 0.0); + Geometry clippedInputGeom = Clipper.clip(input_geom, env, tol, 0.0); + // perform the clip + Geometry[] res_vec; + res_vec = TopologicalOperations.intersectionEx(clippedInputGeom, + clippedIntersector, m_spatial_reference, m_progress_tracker); + return prepareVector_(input_geom.getDescription(), m_dimensionMask, + res_vec); + } + + Geometry tryNativeImplementation_(Geometry input_geom) { + // A note on attributes: + // 1. The geometry with lower dimension wins in regard to the + // attributes. + // 2. If the dimensions are the same, the input_geometry attributes win. + // 3. The exception to the 2. is when the input is an Envelope, and the + // intersector is a polygon, then the intersector wins. + + // A note on the tolerance: + // This operator performs a simple intersection operation. Should it use + // the tolerance? + // Example: Point is intersected by the envelope. + // If it is slightly outside of the envelope, should we still return it + // if it is closer than the tolerance? + // Should we do crack and cluster and snap the point coordinates to the + // envelope boundary? + // + // Consider floating point arithmetics approach. When you compare + // doubles, you should use an epsilon (equals means ::fabs(a - b) < + // eps), however when you add/subtract, etc them, you do not use + // epsilon. + // Shouldn't we do same here? Relational operators use tolerance, but + // the action operators don't. + + Envelope2D mergedExtent = InternalUtils.getMergedExtent(input_geom, + m_geomIntersector); + double tolerance = InternalUtils.calculateToleranceFromGeometry( + m_spatial_reference, mergedExtent, false); + + int gtInput = input_geom.getType().value(); + boolean bInputEmpty = input_geom.isEmpty(); + boolean bGeomIntersectorEmpty = m_geomIntersector.isEmpty(); + boolean bResultIsEmpty = bInputEmpty || bGeomIntersectorEmpty; + if (!bResultIsEmpty) {// test envelopes + Envelope2D env2D1 = new Envelope2D(); + input_geom.queryEnvelope2D(env2D1); + Envelope2D env2D2 = new Envelope2D(); + m_geomIntersector.queryEnvelope2D(env2D2); + env2D2.inflate(2.0 * tolerance, 2.0 * tolerance); + bResultIsEmpty = !env2D1.isIntersecting(env2D2); + } + + if (!bResultIsEmpty) {// try accelerated test + int res = OperatorInternalRelationUtils + .quickTest2D_Accelerated_DisjointOrContains( + m_geomIntersector, input_geom, tolerance); + if (res == OperatorInternalRelationUtils.Relation.Disjoint) {// disjoint + bResultIsEmpty = true; + } else if ((res & OperatorInternalRelationUtils.Relation.Within) != 0) {// intersector + // is + // within + // the + // input_geom + // TODO: + // assign + // input_geom + // attributes + // first + return m_geomIntersector; + } else if ((res & OperatorInternalRelationUtils.Relation.Contains) != 0) {// intersector + // contains + // input_geom + return input_geom; + } + } + + if (bResultIsEmpty) {// When one geometry or both are empty, we need to + // return an empty geometry. + // Here we do that end also ensure the type is + // correct. + // That is the lower dimension need to be + // returned. Also, for Point vs Multi_point, an + // empty Point need to be returned. + int dim1 = Geometry.getDimensionFromType(gtInput); + int dim2 = Geometry.getDimensionFromType(m_geomIntersectorType); + if (dim1 < dim2) + return returnEmpty_(input_geom, bInputEmpty); + else if (dim1 > dim2) + return returnEmptyIntersector_(); + else if (dim1 == 0) { + if (gtInput == Geometry.GeometryType.MultiPoint + && m_geomIntersectorType == Geometry.GeometryType.Point) {// point + // vs + // Multi_point + // need + // special + // treatment + // to + // ensure + // Point + // is + // returned + // always. + return returnEmptyIntersector_(); + } else + // Both input and intersector have same gtype, or input is + // Point. + return returnEmpty_(input_geom, bInputEmpty); + } else + return returnEmpty_(input_geom, bInputEmpty); + } + + // Note: No empty geometries after this point! + + // Warning: Do not try clip for polylines and polygons. + + // Try clip of Envelope with Envelope. + if ((m_dimensionMask == -1 || m_dimensionMask == (1 << 2)) + && gtInput == Geometry.GeometryType.Envelope + && m_geomIntersectorType == Geometry.GeometryType.Envelope) { + Envelope env1 = (Envelope) input_geom; + Envelope env2 = (Envelope) m_geomIntersector; + Envelope2D env2D_1 = new Envelope2D(); + env1.queryEnvelope2D(env2D_1); + Envelope2D env2D_2 = new Envelope2D(); + env2.queryEnvelope2D(env2D_2); + env2D_1.intersect(env2D_2); + Envelope result_env = new Envelope(); + env1.copyTo(result_env); + result_env.setEnvelope2D(env2D_1); + return result_env; + } + + // Use clip for Point and Multi_point with Envelope + if ((gtInput == Geometry.GeometryType.Envelope && Geometry + .getDimensionFromType(m_geomIntersectorType) == 0) + || (m_geomIntersectorType == Geometry.GeometryType.Envelope && Geometry + .getDimensionFromType(gtInput) == 0)) { + Envelope env = gtInput == Geometry.GeometryType.Envelope ? (Envelope) input_geom + : (Envelope) m_geomIntersector; + Geometry other = gtInput == Geometry.GeometryType.Envelope ? m_geomIntersector + : input_geom; + Envelope2D env_2D = new Envelope2D(); + env.queryEnvelope2D(env_2D); + return Clipper.clip(other, env_2D, tolerance, 0); + } + + if ((Geometry.getDimensionFromType(gtInput) == 0 && Geometry + .getDimensionFromType(m_geomIntersectorType) > 0) + || (Geometry.getDimensionFromType(gtInput) > 0 && Geometry + .getDimensionFromType(m_geomIntersectorType) == 0)) {// multipoint + // intersection + double tolerance1 = InternalUtils.calculateToleranceFromGeometry( + m_spatial_reference, input_geom, false); + if (gtInput == Geometry.GeometryType.MultiPoint) + return TopologicalOperations.intersection( + (MultiPoint) input_geom, m_geomIntersector, tolerance1); + if (gtInput == Geometry.GeometryType.Point) + return TopologicalOperations.intersection((Point) input_geom, + m_geomIntersector, tolerance1); + if (m_geomIntersectorType == Geometry.GeometryType.MultiPoint) + return TopologicalOperations.intersection( + (MultiPoint) m_geomIntersector, input_geom, tolerance1); + if (m_geomIntersectorType == Geometry.GeometryType.Point) + return TopologicalOperations.intersection( + (Point) m_geomIntersector, input_geom, tolerance1); + throw GeometryException.GeometryInternalError(); + } + + // Try Polyline vs Polygon + if ((m_dimensionMask == -1 || m_dimensionMask == (1 << 1)) + && (gtInput == Geometry.GeometryType.Polyline) + && (m_geomIntersectorType == Geometry.GeometryType.Polygon)) { + return tryFastIntersectPolylinePolygon_((Polyline) (input_geom), + (Polygon) (m_geomIntersector)); + } + + // Try Polygon vs Polyline + if ((m_dimensionMask == -1 || m_dimensionMask == (1 << 1)) + && (gtInput == Geometry.GeometryType.Polygon) + && (m_geomIntersectorType == Geometry.GeometryType.Polyline)) { + return tryFastIntersectPolylinePolygon_( + (Polyline) (m_geomIntersector), (Polygon) (input_geom)); + } + + return null; + } + + Geometry tryFastIntersectPolylinePolygon_(Polyline polyline, Polygon polygon) { + MultiPathImpl polylineImpl = (MultiPathImpl) polyline._getImpl(); + MultiPathImpl polygonImpl = (MultiPathImpl) polygon._getImpl(); + + double tolerance = InternalUtils.calculateToleranceFromGeometry( + m_spatial_reference, polygon, false); + Envelope2D clipEnvelope = new Envelope2D(); + { + polygonImpl.queryEnvelope2D(clipEnvelope); + Envelope2D env1 = new Envelope2D(); + polylineImpl.queryEnvelope2D(env1); + env1.inflate(2.0 * tolerance, 2.0 * tolerance); + clipEnvelope.intersect(env1); + assert (!clipEnvelope.isEmpty()); + } + + clipEnvelope.inflate(10 * tolerance, 10 * tolerance); + + if (true) { + double tol = 0; + Geometry clippedPolyline = Clipper.clip(polyline, clipEnvelope, + tol, 0.0); + polyline = (Polyline) clippedPolyline; + polylineImpl = (MultiPathImpl) polyline._getImpl(); + } + + AttributeStreamOfInt32 clipResult = new AttributeStreamOfInt32(0); + int unresolvedSegments = -1; + GeometryAccelerators accel = polygonImpl._getAccelerators(); + if (accel != null) { + RasterizedGeometry2D rgeom = accel.getRasterizedGeometry(); + if (rgeom != null) { + unresolvedSegments = 0; + clipResult.reserve(polylineImpl.getPointCount() + + polylineImpl.getPathCount()); + Envelope2D seg_env = new Envelope2D(); + SegmentIteratorImpl iter = polylineImpl.querySegmentIterator(); + while (iter.nextPath()) { + while (iter.hasNextSegment()) { + Segment seg = iter.nextSegment(); + seg.queryEnvelope2D(seg_env); + RasterizedGeometry2D.HitType hit = rgeom + .queryEnvelopeInGeometry(seg_env); + if (hit == RasterizedGeometry2D.HitType.Inside) { + clipResult.add(1); + } else if (hit == RasterizedGeometry2D.HitType.Outside) { + clipResult.add(0); + } else { + clipResult.add(-1); + unresolvedSegments++; + } + } + } + } + } + + if (polygon.getPointCount() > 5) { + double tol = 0; + Geometry clippedPolygon = Clipper.clip(polygon, clipEnvelope, tol, + 0.0); + + polygon = (Polygon) clippedPolygon; + polygonImpl = (MultiPathImpl) polygon._getImpl(); + accel = polygonImpl._getAccelerators();//update accelerators + } + + if (unresolvedSegments < 0) { + unresolvedSegments = polylineImpl.getSegmentCount(); + } + + // Some heuristics to decide if it makes sense to go with fast intersect + // vs going with the regular planesweep. + double totalPoints = (double) (polylineImpl.getPointCount() + polygonImpl + .getPointCount()); + double thisAlgorithmComplexity = ((double) unresolvedSegments * polygonImpl + .getPointCount());// assume the worst case. + double planesweepComplexity = Math.log(totalPoints) * totalPoints; + double empiricConstantFactorPlaneSweep = 4; + if (thisAlgorithmComplexity > planesweepComplexity + * empiricConstantFactorPlaneSweep) { + // Based on the number of input points, we deduced that the + // plansweep performance should be better than the brute force + // performance. + return null; // resort to planesweep if quadtree does not help + } + + QuadTreeImpl polygonQuadTree = null; + SegmentIteratorImpl polygonIter = polygonImpl.querySegmentIterator(); + // Some logic to decide if it makes sense to build a quadtree on the + // polygon segments + if (accel != null && accel.getQuadTree() != null) + polygonQuadTree = accel.getQuadTree(); + + if (polygonQuadTree == null && polygonImpl.getPointCount() > 20) { + polygonQuadTree = InternalUtils.buildQuadTree(polygonImpl); + } + + Polyline result_polyline = (Polyline) polyline.createInstance(); + MultiPathImpl resultPolylineImpl = (MultiPathImpl) result_polyline + ._getImpl(); + QuadTreeImpl.QuadTreeIteratorImpl qIter = null; + SegmentIteratorImpl polylineIter = polylineImpl.querySegmentIterator(); + double[] params = new double[9]; + AttributeStreamOfDbl intersections = new AttributeStreamOfDbl(0); + SegmentBuffer segmentBuffer = new SegmentBuffer(); + int start_index = -1; + int inCount = 0; + int segIndex = 0; + boolean bOptimized = clipResult.size() > 0; + + // The algorithm is like that: + // Loop through all the segments of the polyline. + // For each polyline segment, intersect it with each of the polygon + // segments. + // If no intersections found then, + // If the polyline segment is completely inside, it is added to the + // result polyline. + // If it is outside, it is thrown out. + // If it intersects, then cut the polyline segment to pieces and test + // each part of the intersected result. + // The cut pieces will either have one point inside, or one point + // outside, or the middle point inside/outside. + // + int polylinePathIndex = -1; + + while (polylineIter.nextPath()) { + polylinePathIndex = polylineIter.getPathIndex(); + int stateNewPath = 0; + int stateAddSegment = 1; + int stateManySegments = 2; + int stateManySegmentsContinuePath = 2; + int stateManySegmentsNewPath = 3; + int state = stateNewPath; + start_index = -1; + inCount = 0; + + while (polylineIter.hasNextSegment()) { + int clipStatus = bOptimized ? (int) clipResult.get(segIndex) + : -1; + segIndex++; + Segment polylineSeg = polylineIter.nextSegment(); + if (clipStatus < 0) { + assert (clipStatus == -1); + // Analyse polyline segment for intersection with the + // polygon. + if (polygonQuadTree != null) { + if (qIter == null) { + qIter = polygonQuadTree.getIterator(polylineSeg, + tolerance); + } else { + qIter.resetIterator(polylineSeg, tolerance); + } + + int path_index = -1; + for (int ind = qIter.next(); ind != -1; ind = qIter + .next()) { + polygonIter.resetToVertex(polygonQuadTree + .getElement(ind)); // path_index + path_index = polygonIter.getPathIndex(); + Segment polygonSeg = polygonIter.nextSegment(); + // intersect polylineSeg and polygonSeg. + int count = polylineSeg.intersect(polygonSeg, null, + params, null, tolerance); + for (int i = 0; i < count; i++) + intersections.add(params[i]); + } + } else {// no quadtree built + polygonIter.resetToFirstPath(); + while (polygonIter.nextPath()) { + while (polygonIter.hasNextSegment()) { + Segment polygonSeg = polygonIter.nextSegment(); + // intersect polylineSeg and polygonSeg. + int count = polylineSeg.intersect(polygonSeg, + null, params, null, tolerance); + for (int i = 0; i < count; i++) + intersections.add(params[i]); + } + } + } + + if (intersections.size() > 0) {// intersections detected. + intersections.sort(0, intersections.size()); // std::sort(intersections.begin(), + // intersections.end()); + + double t0 = 0; + intersections.add(1.0); + int status = -1; + for (int i = 0, n = intersections.size(); i < n; i++) { + double t = intersections.get(i); + if (t == t0) { + continue; + } + boolean bWholeSegment = false; + Segment resSeg; + if (t0 != 0 || t != 1.0) { + polylineSeg.cut(t0, t, segmentBuffer); + resSeg = segmentBuffer.get(); + } else { + resSeg = polylineSeg; + bWholeSegment = true; + } + + if (state >= stateManySegments) { + resultPolylineImpl.addSegmentsFromPath( + polylineImpl, polylinePathIndex, + start_index, inCount, + state == stateManySegmentsNewPath); + if (analyseClipSegment_(polygon, + resSeg.getStartXY(), tolerance) != 1) { + if (analyseClipSegment_(polygon, resSeg, + tolerance) != 1) { + return null; //someting went wrong we'll falback to slower but robust planesweep code. + } + } + + resultPolylineImpl.addSegment(resSeg, false); + state = stateAddSegment; + inCount = 0; + } else { + status = analyseClipSegment_(polygon, resSeg, + tolerance); + switch (status) { + case 1: + if (!bWholeSegment) { + resultPolylineImpl.addSegment(resSeg, + state == stateNewPath); + state = stateAddSegment; + } else { + if (state < stateManySegments) { + start_index = polylineIter + .getStartPointIndex() + - polylineImpl + .getPathStart(polylinePathIndex); + inCount = 1; + + if (state == stateNewPath) + state = stateManySegmentsNewPath; + else { + assert (state == stateAddSegment); + state = stateManySegmentsContinuePath; + } + } else + inCount++; + } + + break; + case 0: + state = stateNewPath; + start_index = -1; + inCount = 0; + break; + default: + return null;// may happen if a segment + // coincides with the border. + } + } + + t0 = t; + } + } else { + clipStatus = analyseClipSegment_(polygon, + polylineSeg.getStartXY(), tolerance);// simple + // case + // no + // intersection. + // Both + // points + // must + // be + // inside. + if (clipStatus < 0) { + assert (clipStatus >= 0); + return null;// something goes wrong, resort to + // planesweep + } + + assert (analyseClipSegment_(polygon, + polylineSeg.getEndXY(), tolerance) == clipStatus); + if (clipStatus == 1) {// the whole segment inside + if (state < stateManySegments) { + assert (inCount == 0); + start_index = polylineIter.getStartPointIndex() + - polylineImpl + .getPathStart(polylinePathIndex); + if (state == stateNewPath) + state = stateManySegmentsNewPath; + else { + assert (state == stateAddSegment); + state = stateManySegmentsContinuePath; + } + } + + inCount++; + } else { + assert (state < stateManySegments); + start_index = -1; + inCount = 0; + } + } + + intersections.clear(false); + } else {// clip status is determined by other means + if (clipStatus == 0) {// outside + assert (analyseClipSegment_(polygon, polylineSeg, + tolerance) == 0); + assert (start_index < 0); + assert (inCount == 0); + continue; + } + + if (clipStatus == 1) { + assert (analyseClipSegment_(polygon, polylineSeg, + tolerance) == 1); + if (state == stateNewPath) { + state = stateManySegmentsNewPath; + start_index = polylineIter.getStartPointIndex() + - polylineImpl + .getPathStart(polylinePathIndex); + } else if (state == stateAddSegment) { + state = stateManySegmentsContinuePath; + start_index = polylineIter.getStartPointIndex() + - polylineImpl + .getPathStart(polylinePathIndex); + } else + assert (state >= stateManySegments); + + inCount++; + continue; + } + } + } + + if (state >= stateManySegments) { + resultPolylineImpl.addSegmentsFromPath(polylineImpl, + polylinePathIndex, start_index, inCount, + state == stateManySegmentsNewPath); + start_index = -1; + } + } + + return result_polyline; + } + + int analyseClipSegment_(Polygon polygon, Point2D pt, double tol) { + int v = PointInPolygonHelper.isPointInPolygon(polygon, pt, tol); + return v; + } + + int analyseClipSegment_(Polygon polygon, Segment seg, double tol) { + Point2D pt_1 = seg.getStartXY(); + Point2D pt_2 = seg.getEndXY(); + int v_1 = PointInPolygonHelper.isPointInPolygon(polygon, pt_1, tol); + int v_2 = PointInPolygonHelper.isPointInPolygon(polygon, pt_2, tol); + if ((v_1 == 1 && v_2 == 0) || (v_1 == 0 && v_2 == 1)) { + // Operator_factory_local::SaveJSONToTextFileDbg("c:/temp/badPointInPolygon.json", + // polygon, m_spatial_reference); + assert (false);// if happens + return -1;// something went wrong. One point is inside, the other is + // outside. Should not happen. We'll resort to + // planesweep. + } + if (v_1 == 0 || v_2 == 0) + return 0; + if (v_1 == 1 || v_2 == 1) + return 1; + + Point2D midPt = new Point2D(); + midPt.add(pt_1, pt_2); + midPt.scale(0.5);// calculate midpoint + int v = PointInPolygonHelper.isPointInPolygon(polygon, midPt, tol); + if (v == 0) { + return 0; + } + + if (v == 1) { + return 1; + } + + return -1; + } + + Geometry normalizeIntersectionOutput(Geometry geom, int GT_1, int GT_2) { + if (GT_1 == Geometry.GeometryType.Point + || GT_2 == Geometry.GeometryType.Point) { + assert (geom.getType().value() == Geometry.GeometryType.Point); + } + if (GT_1 == Geometry.GeometryType.MultiPoint) { + if (geom.getType().value() == Geometry.GeometryType.Point) { + MultiPoint mp = new MultiPoint(geom.getDescription()); + if (!geom.isEmpty()) + mp.add((Point) geom); + return mp; + } + } + + return geom; + } + + static Geometry returnEmpty_(Geometry geom, boolean bEmpty) { + return bEmpty ? geom : geom.createInstance(); + } + + Geometry returnEmptyIntersector_() { + if (m_geomIntersectorEmptyGeom == null) + m_geomIntersectorEmptyGeom = m_geomIntersector.createInstance(); + + return m_geomIntersectorEmptyGeom; + } + + // virtual boolean IsRecycling() OVERRIDE { return false; } } diff --git a/src/main/java/com/esri/core/geometry/OperatorIntersectionLocal.java b/src/main/java/com/esri/core/geometry/OperatorIntersectionLocal.java index 03d50c31..f2ce196b 100644 --- a/src/main/java/com/esri/core/geometry/OperatorIntersectionLocal.java +++ b/src/main/java/com/esri/core/geometry/OperatorIntersectionLocal.java @@ -28,54 +28,54 @@ class OperatorIntersectionLocal extends OperatorIntersection { - @Override - public GeometryCursor execute(GeometryCursor inputGeometries, - GeometryCursor intersector, SpatialReference sr, - ProgressTracker progressTracker) { - - return new OperatorIntersectionCursor(inputGeometries, intersector, sr, - progressTracker, -1); - } - - @Override - public GeometryCursor execute(GeometryCursor input_geometries, - GeometryCursor intersector, SpatialReference sr, - ProgressTracker progress_tracker, int dimensionMask) { - return new OperatorIntersectionCursor(input_geometries, intersector, - sr, progress_tracker, dimensionMask); - } - - @Override - public Geometry execute(Geometry inputGeometry, Geometry intersector, - SpatialReference sr, ProgressTracker progressTracker) { - SimpleGeometryCursor inputGeomCurs = new SimpleGeometryCursor( - inputGeometry); - SimpleGeometryCursor intersectorCurs = new SimpleGeometryCursor( - intersector); - GeometryCursor geometryCursor = execute(inputGeomCurs, intersectorCurs, - sr, progressTracker); - - return geometryCursor.next(); - } - - @Override - public boolean accelerateGeometry(Geometry geometry, - SpatialReference spatialReference, - GeometryAccelerationDegree accelDegree) { - if (!canAccelerateGeometry(geometry)) - return false; - - double tol = InternalUtils.calculateToleranceFromGeometry(spatialReference, geometry, false); - boolean accelerated = ((MultiVertexGeometryImpl) geometry._getImpl()) - ._buildQuadTreeAccelerator(accelDegree); - accelerated |= ((MultiVertexGeometryImpl) geometry._getImpl()) - ._buildRasterizedGeometryAccelerator(tol, accelDegree); - return accelerated; - } - - @Override - public boolean canAccelerateGeometry(Geometry geometry) { - return RasterizedGeometry2D.canUseAccelerator(geometry); - } + @Override + public GeometryCursor execute(GeometryCursor inputGeometries, + GeometryCursor intersector, SpatialReference sr, + ProgressTracker progressTracker) { + + return new OperatorIntersectionCursor(inputGeometries, intersector, sr, + progressTracker, -1); + } + + @Override + public GeometryCursor execute(GeometryCursor input_geometries, + GeometryCursor intersector, SpatialReference sr, + ProgressTracker progress_tracker, int dimensionMask) { + return new OperatorIntersectionCursor(input_geometries, intersector, + sr, progress_tracker, dimensionMask); + } + + @Override + public Geometry execute(Geometry inputGeometry, Geometry intersector, + SpatialReference sr, ProgressTracker progressTracker) { + SimpleGeometryCursor inputGeomCurs = new SimpleGeometryCursor( + inputGeometry); + SimpleGeometryCursor intersectorCurs = new SimpleGeometryCursor( + intersector); + GeometryCursor geometryCursor = execute(inputGeomCurs, intersectorCurs, + sr, progressTracker); + + return geometryCursor.next(); + } + + @Override + public boolean accelerateGeometry(Geometry geometry, + SpatialReference spatialReference, + GeometryAccelerationDegree accelDegree) { + if (!canAccelerateGeometry(geometry)) + return false; + + double tol = InternalUtils.calculateToleranceFromGeometry(spatialReference, geometry, false); + boolean accelerated = ((MultiVertexGeometryImpl) geometry._getImpl()) + ._buildQuadTreeAccelerator(accelDegree); + accelerated |= ((MultiVertexGeometryImpl) geometry._getImpl()) + ._buildRasterizedGeometryAccelerator(tol, accelDegree); + return accelerated; + } + + @Override + public boolean canAccelerateGeometry(Geometry geometry) { + return RasterizedGeometry2D.canUseAccelerator(geometry); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorIntersects.java b/src/main/java/com/esri/core/geometry/OperatorIntersects.java index e42ce750..ace6c277 100644 --- a/src/main/java/com/esri/core/geometry/OperatorIntersects.java +++ b/src/main/java/com/esri/core/geometry/OperatorIntersects.java @@ -25,14 +25,14 @@ package com.esri.core.geometry; public abstract class OperatorIntersects extends OperatorSimpleRelation { - @Override - public Type getType() { - return Type.Intersects; - } - - public static OperatorIntersects local() { - return (OperatorIntersects) OperatorFactoryLocal.getInstance() - .getOperator(Type.Intersects); - } + @Override + public Type getType() { + return Type.Intersects; + } + + public static OperatorIntersects local() { + return (OperatorIntersects) OperatorFactoryLocal.getInstance() + .getOperator(Type.Intersects); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorIntersectsLocal.java b/src/main/java/com/esri/core/geometry/OperatorIntersectsLocal.java index cf9c358b..d4b47d76 100644 --- a/src/main/java/com/esri/core/geometry/OperatorIntersectsLocal.java +++ b/src/main/java/com/esri/core/geometry/OperatorIntersectsLocal.java @@ -26,13 +26,13 @@ class OperatorIntersectsLocal extends OperatorIntersects { - OperatorDisjoint m_disjoint = (OperatorDisjoint) OperatorFactoryLocal - .getInstance().getOperator(Type.Disjoint); - - @Override - public boolean execute(Geometry inputGeom1, Geometry inputGeom2, - SpatialReference sr, ProgressTracker progressTracker) { - return !m_disjoint.execute(inputGeom1, inputGeom2, sr, progressTracker); - } + OperatorDisjoint m_disjoint = (OperatorDisjoint) OperatorFactoryLocal + .getInstance().getOperator(Type.Disjoint); + + @Override + public boolean execute(Geometry inputGeom1, Geometry inputGeom2, + SpatialReference sr, ProgressTracker progressTracker) { + return !m_disjoint.execute(inputGeom1, inputGeom2, sr, progressTracker); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorOffset.java b/src/main/java/com/esri/core/geometry/OperatorOffset.java index 68b1c1b8..214ee811 100644 --- a/src/main/java/com/esri/core/geometry/OperatorOffset.java +++ b/src/main/java/com/esri/core/geometry/OperatorOffset.java @@ -26,31 +26,32 @@ import com.esri.core.geometry.Operator.Type; public abstract class OperatorOffset extends Operator { - @Override - public Operator.Type getType() { - return Operator.Type.Offset; - } + @Override + public Operator.Type getType() { + return Operator.Type.Offset; + } - /** - * Join types for the offset operation. Updated to match grpc int values - */ - public enum JoinType { - Round(0), Bevel(1), Miter(2), Square(3); - private final int value; - JoinType(int value) { - this.value = value; - } + /** + * Join types for the offset operation. Updated to match grpc int values + */ + public enum JoinType { + Round(0), Bevel(1), Miter(2), Square(3); + private final int value; + + JoinType(int value) { + this.value = value; + } - public int getValue() { - return this.value; - } - } + public int getValue() { + return this.value; + } + } - ; + ; /** * Creates offset version of the input geometries. - * + *

* The offset operation creates a geometry that is a constant distance from * an input polyline or polygon. It is similar to buffering, but produces a * one sided result. If offsetDistance greater than 0, then the offset geometry is @@ -61,35 +62,29 @@ public int getValue() { * multiplied by the offset distance and the result determines how far a * mitered offset intersection can be from the input curve before it is * beveled. - * - * @param inputGeometries - * The geometries to calculate offset for. Point and MultiPoint - * are not supported. - * @param sr - * The SpatialReference of the Geometries. - * @param distance - * The offset distance for the Geometries. - * @param joins - * The join type of the offset geometry. - * @param bevelRatio - * The ratio used to produce a bevel join instead of a miter join - * (used only when joins is Miter) - * @param flattenError - * The maximum distance of the resulting segments compared to the - * true circular arc (used only when joins is Round). If - * flattenError is 0, tolerance value is used. Also, the - * algorithm never produces more than around 180 vertices for - * each round join. + * + * @param inputGeometries The geometries to calculate offset for. Point and MultiPoint + * are not supported. + * @param sr The SpatialReference of the Geometries. + * @param distance The offset distance for the Geometries. + * @param joins The join type of the offset geometry. + * @param bevelRatio The ratio used to produce a bevel join instead of a miter join + * (used only when joins is Miter) + * @param flattenError The maximum distance of the resulting segments compared to the + * true circular arc (used only when joins is Round). If + * flattenError is 0, tolerance value is used. Also, the + * algorithm never produces more than around 180 vertices for + * each round join. * @return Returns the result of the offset operation. */ public abstract GeometryCursor execute(GeometryCursor inputGeometries, - SpatialReference sr, double distance, JoinType joins, - double bevelRatio, double flattenError, - ProgressTracker progressTracker); + SpatialReference sr, double distance, JoinType joins, + double bevelRatio, double flattenError, + ProgressTracker progressTracker); /** * Creates offset version of the input geometry. - * + *

* The offset operation creates a geometry that is a constant distance from * an input polyline or polygon. It is similar to buffering, but produces a * one sided result. If offsetDistance greater than 0, then the offset geometry is @@ -100,35 +95,29 @@ public abstract GeometryCursor execute(GeometryCursor inputGeometries, * multiplied by the offset distance and the result determines how far a * mitered offset intersection can be from the input curve before it is * beveled. - * - * @param inputGeometry - * The geometry to calculate offset for. Point and MultiPoint are - * not supported. - * @param sr - * The SpatialReference of the Geometries. - * @param distance - * The offset distance for the Geometries. - * @param joins - * The join type of the offset geometry. - * @param bevelRatio - * The ratio used to produce a bevel join instead of a miter join - * (used only when joins is Miter) - * @param flattenError - * The maximum distance of the resulting segments compared to the - * true circular arc (used only when joins is Round). If - * flattenError is 0, tolerance value is used. Also, the - * algorithm never produces more than around 180 vetices for each - * round join. + * + * @param inputGeometry The geometry to calculate offset for. Point and MultiPoint are + * not supported. + * @param sr The SpatialReference of the Geometries. + * @param distance The offset distance for the Geometries. + * @param joins The join type of the offset geometry. + * @param bevelRatio The ratio used to produce a bevel join instead of a miter join + * (used only when joins is Miter) + * @param flattenError The maximum distance of the resulting segments compared to the + * true circular arc (used only when joins is Round). If + * flattenError is 0, tolerance value is used. Also, the + * algorithm never produces more than around 180 vetices for each + * round join. * @return Returns the result of the offset operation. */ public abstract Geometry execute(Geometry inputGeometry, - SpatialReference sr, double distance, JoinType joins, - double bevelRatio, double flattenError, - ProgressTracker progressTracker); + SpatialReference sr, double distance, JoinType joins, + double bevelRatio, double flattenError, + ProgressTracker progressTracker); - public static OperatorOffset local() { - return (OperatorOffset) OperatorFactoryLocal.getInstance().getOperator( - Type.Offset); - } + public static OperatorOffset local() { + return (OperatorOffset) OperatorFactoryLocal.getInstance().getOperator( + Type.Offset); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorOffsetCursor.java b/src/main/java/com/esri/core/geometry/OperatorOffsetCursor.java index e6ece9f0..303af8f2 100644 --- a/src/main/java/com/esri/core/geometry/OperatorOffsetCursor.java +++ b/src/main/java/com/esri/core/geometry/OperatorOffsetCursor.java @@ -25,45 +25,45 @@ // TODO test this, never been public before public class OperatorOffsetCursor extends GeometryCursor { - SpatialReferenceImpl m_spatialReference; - ProgressTracker m_progressTracker; - double m_distance; - double m_miterLimit; - OperatorOffset.JoinType m_joins; - double m_flattenError; + SpatialReferenceImpl m_spatialReference; + ProgressTracker m_progressTracker; + double m_distance; + double m_miterLimit; + OperatorOffset.JoinType m_joins; + double m_flattenError; - OperatorOffsetCursor(GeometryCursor inputGeometries, - SpatialReference sr, - double distance, OperatorOffset.JoinType joins, - double bevelRatio, - double flattenError, - ProgressTracker progressTracker) { - m_inputGeoms = inputGeometries; - m_spatialReference = (SpatialReferenceImpl) sr; - m_distance = distance; - m_joins = joins; - m_miterLimit = bevelRatio; - m_flattenError = flattenError; - m_progressTracker = progressTracker; - } + OperatorOffsetCursor(GeometryCursor inputGeometries, + SpatialReference sr, + double distance, OperatorOffset.JoinType joins, + double bevelRatio, + double flattenError, + ProgressTracker progressTracker) { + m_inputGeoms = inputGeometries; + m_spatialReference = (SpatialReferenceImpl) sr; + m_distance = distance; + m_joins = joins; + m_miterLimit = bevelRatio; + m_flattenError = flattenError; + m_progressTracker = progressTracker; + } - @Override - public Geometry next() { - if (hasNext()) - return Offset(m_inputGeoms.next()); + @Override + public Geometry next() { + if (hasNext()) + return Offset(m_inputGeoms.next()); - return null; - } + return null; + } - Geometry Offset(Geometry geom) { - double tolerance; - if (m_flattenError <= 0) - tolerance = InternalUtils.calculateToleranceFromGeometry( - m_spatialReference, geom, false); - else - tolerance = m_flattenError; - return ConstructOffset.execute(geom, m_distance, m_joins, m_miterLimit, - tolerance, m_progressTracker); - } + Geometry Offset(Geometry geom) { + double tolerance; + if (m_flattenError <= 0) + tolerance = InternalUtils.calculateToleranceFromGeometry( + m_spatialReference, geom, false); + else + tolerance = m_flattenError; + return ConstructOffset.execute(geom, m_distance, m_joins, m_miterLimit, + tolerance, m_progressTracker); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorOffsetLocal.java b/src/main/java/com/esri/core/geometry/OperatorOffsetLocal.java index 5381b120..894f2849 100644 --- a/src/main/java/com/esri/core/geometry/OperatorOffsetLocal.java +++ b/src/main/java/com/esri/core/geometry/OperatorOffsetLocal.java @@ -25,24 +25,24 @@ class OperatorOffsetLocal extends OperatorOffset { - @Override - public GeometryCursor execute(GeometryCursor inputGeometries, - SpatialReference sr, double distance, JoinType joins, - double bevelRatio, double flattenError, - ProgressTracker progressTracker) { - return new OperatorOffsetCursor(inputGeometries, sr, distance, joins, - bevelRatio, flattenError, progressTracker); - } - - @Override - public Geometry execute(Geometry inputGeometry, SpatialReference sr, - double distance, JoinType joins, double bevelRatio, - double flattenError, ProgressTracker progressTracker) { - SimpleGeometryCursor inputCursor = new SimpleGeometryCursor( - inputGeometry); - GeometryCursor outCursor = execute(inputCursor, sr, distance, joins, - bevelRatio, flattenError, progressTracker); - return outCursor.next(); - } + @Override + public GeometryCursor execute(GeometryCursor inputGeometries, + SpatialReference sr, double distance, JoinType joins, + double bevelRatio, double flattenError, + ProgressTracker progressTracker) { + return new OperatorOffsetCursor(inputGeometries, sr, distance, joins, + bevelRatio, flattenError, progressTracker); + } + + @Override + public Geometry execute(Geometry inputGeometry, SpatialReference sr, + double distance, JoinType joins, double bevelRatio, + double flattenError, ProgressTracker progressTracker) { + SimpleGeometryCursor inputCursor = new SimpleGeometryCursor( + inputGeometry); + GeometryCursor outCursor = execute(inputCursor, sr, distance, joins, + bevelRatio, flattenError, progressTracker); + return outCursor.next(); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorOverlaps.java b/src/main/java/com/esri/core/geometry/OperatorOverlaps.java index ca2b4905..c7b3b207 100644 --- a/src/main/java/com/esri/core/geometry/OperatorOverlaps.java +++ b/src/main/java/com/esri/core/geometry/OperatorOverlaps.java @@ -26,14 +26,14 @@ import com.esri.core.geometry.Operator.Type; public abstract class OperatorOverlaps extends OperatorSimpleRelation { - @Override - public Type getType() { - return Type.Equals; - } - - public static OperatorOverlaps local() { - return (OperatorOverlaps) OperatorFactoryLocal.getInstance() - .getOperator(Type.Overlaps); - } + @Override + public Type getType() { + return Type.Equals; + } + + public static OperatorOverlaps local() { + return (OperatorOverlaps) OperatorFactoryLocal.getInstance() + .getOperator(Type.Overlaps); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorOverlapsLocal.java b/src/main/java/com/esri/core/geometry/OperatorOverlapsLocal.java index 1196e6a7..33a81c5e 100644 --- a/src/main/java/com/esri/core/geometry/OperatorOverlapsLocal.java +++ b/src/main/java/com/esri/core/geometry/OperatorOverlapsLocal.java @@ -24,10 +24,10 @@ package com.esri.core.geometry; class OperatorOverlapsLocal extends OperatorOverlaps { - @Override - public boolean execute(Geometry inputGeom1, Geometry inputGeom2, - SpatialReference sr, ProgressTracker progressTracker) { - return RelationalOperations.relate(inputGeom1, inputGeom2, sr, - RelationalOperations.Relation.overlaps, progressTracker); - } + @Override + public boolean execute(Geometry inputGeom1, Geometry inputGeom2, + SpatialReference sr, ProgressTracker progressTracker) { + return RelationalOperations.relate(inputGeom1, inputGeom2, sr, + RelationalOperations.Relation.overlaps, progressTracker); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorProject.java b/src/main/java/com/esri/core/geometry/OperatorProject.java index 3b9cc296..9f5fe8b2 100644 --- a/src/main/java/com/esri/core/geometry/OperatorProject.java +++ b/src/main/java/com/esri/core/geometry/OperatorProject.java @@ -28,135 +28,135 @@ */ public abstract class OperatorProject extends Operator { - @Override - public Type getType() { - return Type.Project; - } - - /** - * Performs the Project operation on a geometry cursor - * - * @return Returns a GeometryCursor. - */ - public abstract GeometryCursor execute(GeometryCursor inputGeoms, - ProjectionTransformation projection, - ProgressTracker progressTracker); - - /** - * Performs the Project operation on a single geometry instance - * - * @return Returns the Geometry after projection - */ - public abstract Geometry execute(Geometry geometry, - ProjectionTransformation projection, - ProgressTracker progressTracker); - - /** - * Transforms an array of points. Returns the number of points transformed. - */ - public abstract int transform(ProjectionTransformation transform, - Point[] coordsSrc, - int length, - Point[] coordsDst) throws org.proj4.PJException; - - /** - * Transforms an array of 2D points and returns it. The points are stored in - * an interleaved array (x0, y0, x1, y1, x2, y2, ...). - * - * @param transform ProjectionTransformation - * @param coordsSrc source coordinates to project. - * @param pointCount the point count in the coordSrc. THere has to be at least - * pointCount * 2 elements in the coordsSrc array. - * @param bHasZ does the coordSrc array include z values - * @return projected coordinates in the interleaved form. - */ - public abstract double[] transform(ProjectionTransformation transform, - double[] coordsSrc, - int pointCount, - boolean bHasZ) throws org.proj4.PJException; - - /** - * Folds a geometry into the 360 degree range of the associated spatial reference. If the spatial reference be a 'pannable' PROJECTED or GEOGRAPHIC. For other spatial types, the function throws an invalid - * argument exception. A pannable PROJECTED it a Rectangular PROJECTED where the x coordinate range is equivalent to a 360 degree range on the defining geographic Coordinate System(GEOGRAPHIC). If the spatial - * reference is a GEOGRAPHIC then it is always pannable(default 360 range for spatial reference in GEOGRAPHIC coordinates is -180 to 180) - *

- * If the geometry is an Envelope fold_into_360_range returns a polygon, unless the Envelope is empty, in which case the empty envelope is returned. The result geometry will be completely inside of - * the coordinate system extent. The folding happens where geometry intersects the min or max meridian of the spatial reference and when geometry is completely outside of the min-max meridian range. - * Folding does not preserve geodetic area or length. Folding does not preserve perimeter of a polygon. - * - * @param geom The geometry to be folded. - * @param pannableSR The pannable Spatial Reference. - * @return Folded geometry. - */ - public static Geometry foldInto360Range(Geometry geom, SpatialReference pannableSR) { - Envelope2D envelope2D = new Envelope2D(); - geom.queryEnvelope2D(envelope2D); - if (envelope2D.xmax <= 180.0 && envelope2D.xmin >= -180.0) { - return geom; - } - - // clip by -180 and 180 - MultiPath foldedGeometry = null; - - if (geom.getType() != Geometry.Type.Polyline && geom.getType() != Geometry.Type.Polygon) - return geom; - - MultiPathImpl multiPath = (MultiPathImpl)geom._getImpl(); - if (geom.getType() == Geometry.Type.Polygon) { - foldedGeometry = new Polygon(multiPath.m_description); - } else if (geom.getType() == Geometry.Type.Polyline) { - foldedGeometry = new Polyline(multiPath.m_description); - } - - // TODO this should be a static class member - Polyline cuttee1 = new Polyline(); - cuttee1.startPath(-180, 90); - cuttee1.lineTo(-180, -90); - cuttee1.startPath(180, 90); - cuttee1.lineTo(180, -90); - Geometry[] parts = GeometryEngine.cut(geom, cuttee1, pannableSR); - - if (parts.length == 0) { - parts = new Geometry[] {geom}; - } - - for (Geometry geometryPart : parts) { - geometryPart.queryEnvelope2D(envelope2D); - // TODO this only accounts for geometries with lat lon rang of -540 to 540 - if (envelope2D.xmin < -180) { - // add 180 to all vertices in geometry - // TODO this should be a static class member - Transformation2D transformation2D = new Transformation2D(); - transformation2D.xd = 360; - geometryPart.applyTransformation(transformation2D); - } - if (envelope2D.xmax > 180) { - // TODO this should be a static class member - Transformation2D transformation2D = new Transformation2D(); - transformation2D.xd = -360; - geometryPart.applyTransformation(transformation2D); - } - foldedGeometry.add((MultiPath) geometryPart, false); - } - - return foldedGeometry; - } - - /** - * Same as fold_into_360_range. The difference is that this function preserves geodetic area of polygons and geodetic length of polylines. It does not preserve regular area and length or perimeter - * of polygons. Also, this function might change tangent of the lines at the points of folding. - *

- * If the geometry is an Envelope fold_into_360_range returns a polygon, unless the Envelope is empty, in which case the empty envelope is returned. The result geometry will be completely inside of - * the coordinate system extent. The folding happens where geometry intersects the min or max meridian of the spatial reference and when geometry is completely outside of the min-max meridian range. - * - * @param geom The geometry to be folded. - * @param pannableSR The pannable Spatial Reference. - * @param curveType The type of geodetic curve to use to produce vertices at the points of folding. \return Folded geometry. - */ - public abstract Geometry foldInto360RangeGeodetic(Geometry geom, SpatialReference pannableSR, int curveType); - - public static OperatorProject local() { - return (OperatorProject) OperatorFactoryLocal.getInstance().getOperator(Type.Project); - } + @Override + public Type getType() { + return Type.Project; + } + + /** + * Performs the Project operation on a geometry cursor + * + * @return Returns a GeometryCursor. + */ + public abstract GeometryCursor execute(GeometryCursor inputGeoms, + ProjectionTransformation projection, + ProgressTracker progressTracker); + + /** + * Performs the Project operation on a single geometry instance + * + * @return Returns the Geometry after projection + */ + public abstract Geometry execute(Geometry geometry, + ProjectionTransformation projection, + ProgressTracker progressTracker); + + /** + * Transforms an array of points. Returns the number of points transformed. + */ + public abstract int transform(ProjectionTransformation transform, + Point[] coordsSrc, + int length, + Point[] coordsDst) throws org.proj4.PJException; + + /** + * Transforms an array of 2D points and returns it. The points are stored in + * an interleaved array (x0, y0, x1, y1, x2, y2, ...). + * + * @param transform ProjectionTransformation + * @param coordsSrc source coordinates to project. + * @param pointCount the point count in the coordSrc. THere has to be at least + * pointCount * 2 elements in the coordsSrc array. + * @param bHasZ does the coordSrc array include z values + * @return projected coordinates in the interleaved form. + */ + public abstract double[] transform(ProjectionTransformation transform, + double[] coordsSrc, + int pointCount, + boolean bHasZ) throws org.proj4.PJException; + + /** + * Folds a geometry into the 360 degree range of the associated spatial reference. If the spatial reference be a 'pannable' PROJECTED or GEOGRAPHIC. For other spatial types, the function throws an invalid + * argument exception. A pannable PROJECTED it a Rectangular PROJECTED where the x coordinate range is equivalent to a 360 degree range on the defining geographic Coordinate System(GEOGRAPHIC). If the spatial + * reference is a GEOGRAPHIC then it is always pannable(default 360 range for spatial reference in GEOGRAPHIC coordinates is -180 to 180) + *

+ * If the geometry is an Envelope fold_into_360_range returns a polygon, unless the Envelope is empty, in which case the empty envelope is returned. The result geometry will be completely inside of + * the coordinate system extent. The folding happens where geometry intersects the min or max meridian of the spatial reference and when geometry is completely outside of the min-max meridian range. + * Folding does not preserve geodetic area or length. Folding does not preserve perimeter of a polygon. + * + * @param geom The geometry to be folded. + * @param pannableSR The pannable Spatial Reference. + * @return Folded geometry. + */ + public static Geometry foldInto360Range(Geometry geom, SpatialReference pannableSR) { + Envelope2D envelope2D = new Envelope2D(); + geom.queryEnvelope2D(envelope2D); + if (envelope2D.xmax <= 180.0 && envelope2D.xmin >= -180.0) { + return geom; + } + + // clip by -180 and 180 + MultiPath foldedGeometry = null; + + if (geom.getType() != Geometry.Type.Polyline && geom.getType() != Geometry.Type.Polygon) + return geom; + + MultiPathImpl multiPath = (MultiPathImpl) geom._getImpl(); + if (geom.getType() == Geometry.Type.Polygon) { + foldedGeometry = new Polygon(multiPath.m_description); + } else if (geom.getType() == Geometry.Type.Polyline) { + foldedGeometry = new Polyline(multiPath.m_description); + } + + // TODO this should be a static class member + Polyline cuttee1 = new Polyline(); + cuttee1.startPath(-180, 90); + cuttee1.lineTo(-180, -90); + cuttee1.startPath(180, 90); + cuttee1.lineTo(180, -90); + Geometry[] parts = GeometryEngine.cut(geom, cuttee1, pannableSR); + + if (parts.length == 0) { + parts = new Geometry[]{geom}; + } + + for (Geometry geometryPart : parts) { + geometryPart.queryEnvelope2D(envelope2D); + // TODO this only accounts for geometries with lat lon rang of -540 to 540 + if (envelope2D.xmin < -180) { + // add 180 to all vertices in geometry + // TODO this should be a static class member + Transformation2D transformation2D = new Transformation2D(); + transformation2D.xd = 360; + geometryPart.applyTransformation(transformation2D); + } + if (envelope2D.xmax > 180) { + // TODO this should be a static class member + Transformation2D transformation2D = new Transformation2D(); + transformation2D.xd = -360; + geometryPart.applyTransformation(transformation2D); + } + foldedGeometry.add((MultiPath) geometryPart, false); + } + + return foldedGeometry; + } + + /** + * Same as fold_into_360_range. The difference is that this function preserves geodetic area of polygons and geodetic length of polylines. It does not preserve regular area and length or perimeter + * of polygons. Also, this function might change tangent of the lines at the points of folding. + *

+ * If the geometry is an Envelope fold_into_360_range returns a polygon, unless the Envelope is empty, in which case the empty envelope is returned. The result geometry will be completely inside of + * the coordinate system extent. The folding happens where geometry intersects the min or max meridian of the spatial reference and when geometry is completely outside of the min-max meridian range. + * + * @param geom The geometry to be folded. + * @param pannableSR The pannable Spatial Reference. + * @param curveType The type of geodetic curve to use to produce vertices at the points of folding. \return Folded geometry. + */ + public abstract Geometry foldInto360RangeGeodetic(Geometry geom, SpatialReference pannableSR, int curveType); + + public static OperatorProject local() { + return (OperatorProject) OperatorFactoryLocal.getInstance().getOperator(Type.Project); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorProjectCursor.java b/src/main/java/com/esri/core/geometry/OperatorProjectCursor.java index 995c8a28..0a4724d3 100644 --- a/src/main/java/com/esri/core/geometry/OperatorProjectCursor.java +++ b/src/main/java/com/esri/core/geometry/OperatorProjectCursor.java @@ -4,24 +4,24 @@ * Created by davidraleigh on 5/12/17. */ public class OperatorProjectCursor extends GeometryCursor { - ProjectionTransformation m_projectionTransformation; - ProgressTracker m_progressTracker; + ProjectionTransformation m_projectionTransformation; + ProgressTracker m_progressTracker; - OperatorProjectCursor( - GeometryCursor inputGeoms, - ProjectionTransformation projectionTransformation, - ProgressTracker progressTracker) { - m_inputGeoms = inputGeoms; - m_projectionTransformation = projectionTransformation; - m_progressTracker = progressTracker; - } + OperatorProjectCursor( + GeometryCursor inputGeoms, + ProjectionTransformation projectionTransformation, + ProgressTracker progressTracker) { + m_inputGeoms = inputGeoms; + m_projectionTransformation = projectionTransformation; + m_progressTracker = progressTracker; + } - @Override - public Geometry next() { - if (m_inputGeoms.hasNext()) { - Geometry geometry = m_inputGeoms.next(); - return Projecter.project(geometry, m_projectionTransformation, m_progressTracker); - } - return null; - } + @Override + public Geometry next() { + if (m_inputGeoms.hasNext()) { + Geometry geometry = m_inputGeoms.next(); + return Projecter.project(geometry, m_projectionTransformation, m_progressTracker); + } + return null; + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorProjectLocal.java b/src/main/java/com/esri/core/geometry/OperatorProjectLocal.java index 49386c12..62b442aa 100644 --- a/src/main/java/com/esri/core/geometry/OperatorProjectLocal.java +++ b/src/main/java/com/esri/core/geometry/OperatorProjectLocal.java @@ -31,37 +31,37 @@ //This is a stub class OperatorProjectLocal extends OperatorProject { - @Override - public GeometryCursor execute(GeometryCursor inputGeoms, - ProjectionTransformation transform, - ProgressTracker progressTracker) { - return new OperatorProjectCursor(inputGeoms, transform, progressTracker); - } + @Override + public GeometryCursor execute(GeometryCursor inputGeoms, + ProjectionTransformation transform, + ProgressTracker progressTracker) { + return new OperatorProjectCursor(inputGeoms, transform, progressTracker); + } - public Geometry execute(Geometry inputGeom, - ProjectionTransformation transform, - ProgressTracker progressTracker) { - return execute(new SimpleGeometryCursor(inputGeom), transform, progressTracker).next(); - } + public Geometry execute(Geometry inputGeom, + ProjectionTransformation transform, + ProgressTracker progressTracker) { + return execute(new SimpleGeometryCursor(inputGeom), transform, progressTracker).next(); + } - @Override - public int transform(ProjectionTransformation transform, - Point[] pointsIn, - int count, - Point[] pointsOut) throws org.proj4.PJException { - return Projecter.transform(transform, pointsIn, count, pointsOut); - } + @Override + public int transform(ProjectionTransformation transform, + Point[] pointsIn, + int count, + Point[] pointsOut) throws org.proj4.PJException { + return Projecter.transform(transform, pointsIn, count, pointsOut); + } - public double[] transform(ProjectionTransformation transform, - double[] coordsSrc, - int pointCount, - boolean bHasZ) throws org.proj4.PJException { - return Projecter.transform(transform, coordsSrc, bHasZ); - } + public double[] transform(ProjectionTransformation transform, + double[] coordsSrc, + int pointCount, + boolean bHasZ) throws org.proj4.PJException { + return Projecter.transform(transform, coordsSrc, bHasZ); + } - @Override - public Geometry foldInto360RangeGeodetic(Geometry _geom, SpatialReference pannableSR, int curveType) { - return _geom; - } + @Override + public Geometry foldInto360RangeGeodetic(Geometry _geom, SpatialReference pannableSR, int curveType) { + return _geom; + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorProximity2D.java b/src/main/java/com/esri/core/geometry/OperatorProximity2D.java index 6b40d72f..bb7e19e1 100644 --- a/src/main/java/com/esri/core/geometry/OperatorProximity2D.java +++ b/src/main/java/com/esri/core/geometry/OperatorProximity2D.java @@ -30,70 +30,70 @@ * Finds closest vertices of the Geometry. */ public abstract class OperatorProximity2D extends Operator { - @Override - public Type getType() { - return Type.Proximity2D; - } + @Override + public Type getType() { + return Type.Proximity2D; + } - /** - * Returns the nearest coordinate on the Geometry to the given input point. - * - * @param geom The input Geometry. - * @param inputPoint The query point. - * @param bTestPolygonInterior When true and geom is a polygon, the function will test if the input_point is inside of the polygon. Points that are - * inside of the polygon have zero distance to the polygon. When false, the function will not check if the point is inside of the polygon, - * but only determine proximity to the boundary. - * @param bCalculateLeftRightSide The function will calculate left/right side of polylines or polygons when the parameter is True. - * \return Returns the result of proximity calculation. See Proximity_2D_result. - */ - public abstract Proximity2DResult getNearestCoordinate(Geometry geom, - Point inputPoint, boolean bTestPolygonInterior, - boolean bCalculateLeftRightSide); + /** + * Returns the nearest coordinate on the Geometry to the given input point. + * + * @param geom The input Geometry. + * @param inputPoint The query point. + * @param bTestPolygonInterior When true and geom is a polygon, the function will test if the input_point is inside of the polygon. Points that are + * inside of the polygon have zero distance to the polygon. When false, the function will not check if the point is inside of the polygon, + * but only determine proximity to the boundary. + * @param bCalculateLeftRightSide The function will calculate left/right side of polylines or polygons when the parameter is True. + * \return Returns the result of proximity calculation. See Proximity_2D_result. + */ + public abstract Proximity2DResult getNearestCoordinate(Geometry geom, + Point inputPoint, boolean bTestPolygonInterior, + boolean bCalculateLeftRightSide); - /** - * Returns the nearest coordinate on the Geometry to the given input point. - * - * @param geom The input Geometry. - * @param inputPoint The query point. - * @param bTestPolygonInterior When true and geom is a polygon, the function will test if the input_point is inside of the polygon. Points that are - * inside of the polygon have zero distance to the polygon. When false, the function will not check if the point is inside of the polygon, - * but only determine proximity to the boundary. - * \return Returns the result of proximity calculation. See Proximity_2D_result. - */ - public abstract Proximity2DResult getNearestCoordinate(Geometry geom, - Point inputPoint, boolean bTestPolygonInterior); + /** + * Returns the nearest coordinate on the Geometry to the given input point. + * + * @param geom The input Geometry. + * @param inputPoint The query point. + * @param bTestPolygonInterior When true and geom is a polygon, the function will test if the input_point is inside of the polygon. Points that are + * inside of the polygon have zero distance to the polygon. When false, the function will not check if the point is inside of the polygon, + * but only determine proximity to the boundary. + * \return Returns the result of proximity calculation. See Proximity_2D_result. + */ + public abstract Proximity2DResult getNearestCoordinate(Geometry geom, + Point inputPoint, boolean bTestPolygonInterior); - /** - * Returns the nearest vertex of the Geometry to the given input point. - */ - public abstract Proximity2DResult getNearestVertex(Geometry geom, - Point inputPoint); + /** + * Returns the nearest vertex of the Geometry to the given input point. + */ + public abstract Proximity2DResult getNearestVertex(Geometry geom, + Point inputPoint); - /** - * Returns vertices of the Geometry that are closer to the given point than - * the given radius. - * - * @param geom The input Geometry. - * @param inputPoint The query point. - * @param searchRadius The maximum distance to the query point of the vertices. - * @param maxVertexCountToReturn The maximum vertex count to return. The function returns no - * more than this number of vertices. - * @return The array of vertices that are in the given search radius to the - * point. The array is sorted by distance to the queryPoint with the - * closest point first. When there are more than the - * maxVertexCountToReturn vertices to return, it returns the closest - * vertices. The array will be empty when geom is empty. - */ - public abstract Proximity2DResult[] getNearestVertices(Geometry geom, - Point inputPoint, double searchRadius, int maxVertexCountToReturn); + /** + * Returns vertices of the Geometry that are closer to the given point than + * the given radius. + * + * @param geom The input Geometry. + * @param inputPoint The query point. + * @param searchRadius The maximum distance to the query point of the vertices. + * @param maxVertexCountToReturn The maximum vertex count to return. The function returns no + * more than this number of vertices. + * @return The array of vertices that are in the given search radius to the + * point. The array is sorted by distance to the queryPoint with the + * closest point first. When there are more than the + * maxVertexCountToReturn vertices to return, it returns the closest + * vertices. The array will be empty when geom is empty. + */ + public abstract Proximity2DResult[] getNearestVertices(Geometry geom, + Point inputPoint, double searchRadius, int maxVertexCountToReturn); - public static OperatorProximity2D local() { - return (OperatorProximity2D) OperatorFactoryLocal.getInstance() - .getOperator(Type.Proximity2D); - } + public static OperatorProximity2D local() { + return (OperatorProximity2D) OperatorFactoryLocal.getInstance() + .getOperator(Type.Proximity2D); + } - interface ProxResultInfo { - static final int rightSide = 0x1; - } + interface ProxResultInfo { + static final int rightSide = 0x1; + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorProximity2DLocal.java b/src/main/java/com/esri/core/geometry/OperatorProximity2DLocal.java index 7b6969d7..832ad712 100644 --- a/src/main/java/com/esri/core/geometry/OperatorProximity2DLocal.java +++ b/src/main/java/com/esri/core/geometry/OperatorProximity2DLocal.java @@ -31,511 +31,511 @@ class OperatorProximity2DLocal extends OperatorProximity2D { - class Side_helper { - int m_i1; - int m_i2; - boolean m_bRight1; - boolean m_bRight2; - - void reset() { - m_i1 = -1; - m_i2 = -1; - m_bRight1 = false; - m_bRight2 = false; - } - - int find_non_degenerate(SegmentIterator segIter, int vertexIndex, - int pathIndex) { - segIter.resetToVertex(vertexIndex, pathIndex); - - while (segIter.hasNextSegment()) { - Segment segment = segIter.nextSegment(); - double length = segment.calculateLength2D(); - - if (length != 0.0) - return segIter.getStartPointIndex(); - } - - segIter.resetToVertex(vertexIndex, pathIndex); - - while (segIter.hasPreviousSegment()) { - Segment segment = segIter.previousSegment(); - double length = segment.calculateLength2D(); - - if (length != 0) - return segIter.getStartPointIndex(); - } - - return -1; - } - - int find_prev_non_degenerate(SegmentIterator segIter, int index) { - segIter.resetToVertex(index, -1); - - while (segIter.hasPreviousSegment()) { - Segment segment = segIter.previousSegment(); - double length = segment.calculateLength2D(); - - if (length != 0) - return segIter.getStartPointIndex(); - } - - return -1; - } - - int find_next_non_degenerate(SegmentIterator segIter, int index) { - segIter.resetToVertex(index, -1); - segIter.nextSegment(); - - while (segIter.hasNextSegment()) { - Segment segment = segIter.nextSegment(); - double length = segment.calculateLength2D(); - - if (length != 0) - return segIter.getStartPointIndex(); - } - - return -1; - } - - void find_analysis_pair_from_index(Point2D inputPoint, - SegmentIterator segIter, int vertexIndex, int pathIndex) { - m_i1 = find_non_degenerate(segIter, vertexIndex, pathIndex); - - if (m_i1 != -1) { - segIter.resetToVertex(m_i1, -1); - Segment segment1 = segIter.nextSegment(); - double t1 = segment1.getClosestCoordinate(inputPoint, false); - Point2D p1 = segment1.getCoord2D(t1); - double d1 = Point2D.sqrDistance(p1, inputPoint); - Point2D pq = new Point2D(); - pq.setCoords(p1); - pq.sub(segment1.getStartXY()); - Point2D pr = new Point2D(); - pr.setCoords(inputPoint); - pr.sub(segment1.getStartXY()); - m_bRight1 = (pq.crossProduct(pr) < 0); - - m_i2 = find_next_non_degenerate(segIter, m_i1); - if (m_i2 != -1) { - segIter.resetToVertex(m_i2, -1); - Segment segment2 = segIter.nextSegment(); - double t2 = segment2 - .getClosestCoordinate(inputPoint, false); - Point2D p2 = segment2.getCoord2D(t2); - double d2 = Point2D.sqrDistance(p2, inputPoint); - - if (d2 > d1) { - m_i2 = -1; - } else { - pq.setCoords(p2); - pq.sub(segment2.getStartXY()); - pr.setCoords(inputPoint); - pr.sub(segment2.getStartXY()); - m_bRight2 = (pq.crossProduct(pr) < 0); - } - } - - if (m_i2 == -1) { - m_i2 = find_prev_non_degenerate(segIter, m_i1); - if (m_i2 != -1) { - segIter.resetToVertex(m_i2, -1); - Segment segment2 = segIter.nextSegment(); - double t2 = segment2.getClosestCoordinate(inputPoint, - false); - Point2D p2 = segment2.getCoord2D(t2); - double d2 = Point2D.sqrDistance(p2, inputPoint); - - if (d2 > d1) - m_i2 = -1; - else { - pq.setCoords(p2); - pq.sub(segment2.getStartXY()); - pr.setCoords(inputPoint); - pr.sub(segment2.getStartXY()); - m_bRight2 = (pq.crossProduct(pr) < 0); - - int itemp = m_i1; - m_i1 = m_i2; - m_i2 = itemp; - - boolean btemp = m_bRight1; - m_bRight1 = m_bRight2; - m_bRight2 = btemp; - } - } - } - } - } - - // Try to find two segements that are not degenerate - boolean calc_side(Point2D inputPoint, boolean bRight, - MultiPath multipath, int vertexIndex, int pathIndex) { - SegmentIterator segIter = multipath.querySegmentIterator(); - - find_analysis_pair_from_index(inputPoint, segIter, vertexIndex, - pathIndex); - - if (m_i1 != -1 && m_i2 == -1) {// could not find a pair of segments - return m_bRight1; - } - - if (m_i1 != -1 && m_i2 != -1) { - if (m_bRight1 == m_bRight2) - return m_bRight1;// no conflicting result for the side - else { - // the conflicting result, that we are trying to resolve, - // happens in the obtuse (outer) side of the turn only. - segIter.resetToVertex(m_i1, -1); - Segment segment1 = segIter.nextSegment(); - Point2D tang1 = segment1._getTangent(1.0); - - segIter.resetToVertex(m_i2, -1); - Segment segment2 = segIter.nextSegment(); - Point2D tang2 = segment2._getTangent(0.0); - - double cross = tang1.crossProduct(tang2); - - if (cross >= 0) // the obtuse angle is on the right side - { - return true; - } else // the obtuse angle is on the right side - { - return false; - } - } - } else { - assert (m_i1 == -1 && m_i2 == -1); - return bRight;// could not resolve the side. So just return the - // old value. - } - } - } - - @Override - public Proximity2DResult getNearestCoordinate(Geometry geom, - Point inputPoint, boolean bTestPolygonInterior) { - - return getNearestCoordinate(geom, inputPoint, bTestPolygonInterior, - false); - } - - @Override - public Proximity2DResult getNearestCoordinate(Geometry geom, - Point inputPoint, boolean bTestPolygonInterior, - boolean bCalculateLeftRightSide) { - if (geom.isEmpty()) - return new Proximity2DResult(); - - Point2D inputPoint2D = inputPoint.getXY(); - - Geometry proxmityTestGeom = geom; - int gt = geom.getType().value(); - - if (gt == Geometry.GeometryType.Envelope) { - Polygon polygon = new Polygon(); - polygon.addEnvelope((Envelope) geom, false); - proxmityTestGeom = polygon; - gt = Geometry.GeometryType.Polygon; - } - switch (gt) { - case Geometry.GeometryType.Point: - return pointGetNearestVertex((Point) proxmityTestGeom, inputPoint2D); - case Geometry.GeometryType.MultiPoint: - return multiVertexGetNearestVertex( - (MultiVertexGeometry) proxmityTestGeom, inputPoint2D); - case Geometry.GeometryType.Polyline: - case Geometry.GeometryType.Polygon: - return multiPathGetNearestCoordinate((MultiPath) proxmityTestGeom, - inputPoint2D, bTestPolygonInterior, bCalculateLeftRightSide); - default: { - throw new GeometryException("not implemented"); - } - } - } - - @Override - public Proximity2DResult getNearestVertex(Geometry geom, Point inputPoint) { - if (geom.isEmpty()) - return new Proximity2DResult(); - - Point2D inputPoint2D = inputPoint.getXY(); - - Geometry proxmityTestGeom = geom; - int gt = geom.getType().value(); - - if (gt == Geometry.GeometryType.Envelope) { - Polygon polygon = new Polygon(); - polygon.addEnvelope((Envelope) geom, false); - proxmityTestGeom = polygon; - gt = Geometry.GeometryType.Polygon; - } - switch (gt) { - case Geometry.GeometryType.Point: - return pointGetNearestVertex((Point) proxmityTestGeom, inputPoint2D); - case Geometry.GeometryType.MultiPoint: - case Geometry.GeometryType.Polyline: - case Geometry.GeometryType.Polygon: - return multiVertexGetNearestVertex( - (MultiVertexGeometry) proxmityTestGeom, inputPoint2D); - default: { - throw new GeometryException("not implemented"); - } - } - } - - @Override - public Proximity2DResult[] getNearestVertices(Geometry geom, - Point inputPoint, double searchRadius, int maxVertexCountToReturn) { - if (maxVertexCountToReturn < 0) - throw new IllegalArgumentException(); - - if (geom.isEmpty()) - return new Proximity2DResult[]{}; - - Point2D inputPoint2D = inputPoint.getXY(); - - Geometry proxmityTestGeom = geom; - int gt = geom.getType().value(); - - if (gt == Geometry.GeometryType.Envelope) { - Polygon polygon = new Polygon(); - polygon.addEnvelope((Envelope) geom, false); - proxmityTestGeom = polygon; - gt = Geometry.GeometryType.Polygon; - } - switch (gt) { - case Geometry.GeometryType.Point: - return pointGetNearestVertices((Point) proxmityTestGeom, - inputPoint2D, searchRadius, maxVertexCountToReturn); - case Geometry.GeometryType.MultiPoint: - case Geometry.GeometryType.Polyline: - case Geometry.GeometryType.Polygon: - return multiVertexGetNearestVertices( - (MultiVertexGeometry) proxmityTestGeom, inputPoint2D, - searchRadius, maxVertexCountToReturn); - default: { - throw new GeometryException("not implemented"); - } - } - } - - Proximity2DResult multiPathGetNearestCoordinate(MultiPath geom, - Point2D inputPoint, boolean bTestPolygonInterior, - boolean bCalculateLeftRightSide) { - if (geom.getType() == Geometry.Type.Polygon && bTestPolygonInterior) { - Envelope2D env = new Envelope2D(); - geom.queryEnvelope2D(env); - double tolerance = InternalUtils.calculateToleranceFromGeometry( - null, env, false); - - PolygonUtils.PiPResult pipResult; - - if (bCalculateLeftRightSide) - pipResult = PolygonUtils.isPointInPolygon2D((Polygon) geom, - inputPoint, 0.0); - else - pipResult = PolygonUtils.isPointInPolygon2D((Polygon) geom, - inputPoint, tolerance); - - if (pipResult != PolygonUtils.PiPResult.PiPOutside) { - Proximity2DResult result = new Proximity2DResult(inputPoint, 0, - 0.0); - - if (bCalculateLeftRightSide) - result.setRightSide(true); - - return result; - } - } - - SegmentIterator segIter = geom.querySegmentIterator(); - - Point2D closest = new Point2D(); - int closestVertexIndex = -1; - int closestPathIndex = -1; - double closestDistanceSq = NumberUtils.doubleMax(); - boolean bRight = false; - int num_candidates = 0; - - while (segIter.nextPath()) { - while (segIter.hasNextSegment()) { - Segment segment = segIter.nextSegment(); - double t = segment.getClosestCoordinate(inputPoint, false); - - Point2D point = segment.getCoord2D(t); - - double distanceSq = Point2D.sqrDistance(point, inputPoint); - if (distanceSq < closestDistanceSq) { - num_candidates = 1; - closest = point; - closestVertexIndex = segIter.getStartPointIndex(); - closestPathIndex = segIter.getPathIndex(); - closestDistanceSq = distanceSq; - } else if (distanceSq == closestDistanceSq) { - num_candidates++; - } - } - } - - Proximity2DResult result = new Proximity2DResult(closest, - closestVertexIndex, Math.sqrt(closestDistanceSq)); - - if (bCalculateLeftRightSide) { - segIter.resetToVertex(closestVertexIndex, closestPathIndex); - Segment segment = segIter.nextSegment(); - bRight = (Point2D.orientationRobust(inputPoint, - segment.getStartXY(), segment.getEndXY()) < 0); - - if (num_candidates > 1) { - Side_helper sideHelper = new Side_helper(); - sideHelper.reset(); - bRight = sideHelper.calc_side(inputPoint, bRight, geom, - closestVertexIndex, closestPathIndex); - } - - result.setRightSide(bRight); - } - - return result; - } - - Proximity2DResult pointGetNearestVertex(Point geom, Point2D input_point) { - Point2D pt = geom.getXY(); - double distance = Point2D.distance(pt, input_point); - return new Proximity2DResult(pt, 0, distance); - } - - Proximity2DResult multiVertexGetNearestVertex(MultiVertexGeometry geom, - Point2D inputPoint) { - MultiVertexGeometryImpl mpImpl = (MultiVertexGeometryImpl) geom - ._getImpl(); - AttributeStreamOfDbl position = (AttributeStreamOfDbl) mpImpl - .getAttributeStreamRef((Semantics.POSITION)); - int pointCount = geom.getPointCount(); - - int closestIndex = 0; - double closestx = 0.0; - double closesty = 0.0; - double closestDistanceSq = NumberUtils.doubleMax(); - for (int i = 0; i < pointCount; i++) { - Point2D pt = new Point2D(); - position.read(2 * i, pt); - - double distanceSq = Point2D.sqrDistance(pt, inputPoint); - if (distanceSq < closestDistanceSq) { - closestx = pt.x; - closesty = pt.y; - closestIndex = i; - closestDistanceSq = distanceSq; - } - } - - Proximity2DResult result = new Proximity2DResult(); - result._setParams(closestx, closesty, closestIndex, - Math.sqrt(closestDistanceSq)); - - return result; - } - - Proximity2DResult[] pointGetNearestVertices(Point geom, Point2D inputPoint, - double searchRadius, int maxVertexCountToReturn) { - Proximity2DResult[] resultArray; - - if (maxVertexCountToReturn == 0) { - resultArray = new Proximity2DResult[]{}; - return resultArray; - } - - double searchRadiusSq = searchRadius * searchRadius; - Point2D pt = geom.getXY(); - - double distanceSq = Point2D.sqrDistance(pt, inputPoint); - if (distanceSq <= searchRadiusSq) { - resultArray = new Proximity2DResult[1]; - - Proximity2DResult result = new Proximity2DResult(); - result._setParams(pt.x, pt.y, 0, Math.sqrt(distanceSq)); - resultArray[0] = result; - } else { - resultArray = new Proximity2DResult[0]; - } - - return resultArray; - } - - Proximity2DResult[] multiVertexGetNearestVertices(MultiVertexGeometry geom, - Point2D inputPoint, double searchRadius, int maxVertexCountToReturn) { - Proximity2DResult[] resultArray; - - if (maxVertexCountToReturn == 0) { - resultArray = new Proximity2DResult[0]; - return resultArray; - } - - MultiVertexGeometryImpl mpImpl = (MultiVertexGeometryImpl) geom - ._getImpl(); - AttributeStreamOfDbl position = (AttributeStreamOfDbl) mpImpl - .getAttributeStreamRef((Semantics.POSITION)); - int pointCount = geom.getPointCount(); - - ArrayList v = new ArrayList( - maxVertexCountToReturn); - - int count = 0; - double searchRadiusSq = searchRadius * searchRadius; - for (int i = 0; i < pointCount; i++) { - double x = position.read(2 * i); - double y = position.read(2 * i + 1); - - double xDiff = inputPoint.x - x; - double yDiff = inputPoint.y - y; - - double distanceSq = xDiff * xDiff + yDiff * yDiff; - if (distanceSq <= searchRadiusSq) { - Proximity2DResult result = new Proximity2DResult(); - result._setParams(x, y, i, Math.sqrt(distanceSq)); - - count++; - v.add(result); - - } - } - - int vsize = v.size(); - Collections.sort(v, new Proximity2DResultComparator()); - - if (maxVertexCountToReturn >= vsize) - return v.toArray(new Proximity2DResult[0]); - return v.subList(0, maxVertexCountToReturn).toArray( - new Proximity2DResult[0]); - - } + class Side_helper { + int m_i1; + int m_i2; + boolean m_bRight1; + boolean m_bRight2; + + void reset() { + m_i1 = -1; + m_i2 = -1; + m_bRight1 = false; + m_bRight2 = false; + } + + int find_non_degenerate(SegmentIterator segIter, int vertexIndex, + int pathIndex) { + segIter.resetToVertex(vertexIndex, pathIndex); + + while (segIter.hasNextSegment()) { + Segment segment = segIter.nextSegment(); + double length = segment.calculateLength2D(); + + if (length != 0.0) + return segIter.getStartPointIndex(); + } + + segIter.resetToVertex(vertexIndex, pathIndex); + + while (segIter.hasPreviousSegment()) { + Segment segment = segIter.previousSegment(); + double length = segment.calculateLength2D(); + + if (length != 0) + return segIter.getStartPointIndex(); + } + + return -1; + } + + int find_prev_non_degenerate(SegmentIterator segIter, int index) { + segIter.resetToVertex(index, -1); + + while (segIter.hasPreviousSegment()) { + Segment segment = segIter.previousSegment(); + double length = segment.calculateLength2D(); + + if (length != 0) + return segIter.getStartPointIndex(); + } + + return -1; + } + + int find_next_non_degenerate(SegmentIterator segIter, int index) { + segIter.resetToVertex(index, -1); + segIter.nextSegment(); + + while (segIter.hasNextSegment()) { + Segment segment = segIter.nextSegment(); + double length = segment.calculateLength2D(); + + if (length != 0) + return segIter.getStartPointIndex(); + } + + return -1; + } + + void find_analysis_pair_from_index(Point2D inputPoint, + SegmentIterator segIter, int vertexIndex, int pathIndex) { + m_i1 = find_non_degenerate(segIter, vertexIndex, pathIndex); + + if (m_i1 != -1) { + segIter.resetToVertex(m_i1, -1); + Segment segment1 = segIter.nextSegment(); + double t1 = segment1.getClosestCoordinate(inputPoint, false); + Point2D p1 = segment1.getCoord2D(t1); + double d1 = Point2D.sqrDistance(p1, inputPoint); + Point2D pq = new Point2D(); + pq.setCoords(p1); + pq.sub(segment1.getStartXY()); + Point2D pr = new Point2D(); + pr.setCoords(inputPoint); + pr.sub(segment1.getStartXY()); + m_bRight1 = (pq.crossProduct(pr) < 0); + + m_i2 = find_next_non_degenerate(segIter, m_i1); + if (m_i2 != -1) { + segIter.resetToVertex(m_i2, -1); + Segment segment2 = segIter.nextSegment(); + double t2 = segment2 + .getClosestCoordinate(inputPoint, false); + Point2D p2 = segment2.getCoord2D(t2); + double d2 = Point2D.sqrDistance(p2, inputPoint); + + if (d2 > d1) { + m_i2 = -1; + } else { + pq.setCoords(p2); + pq.sub(segment2.getStartXY()); + pr.setCoords(inputPoint); + pr.sub(segment2.getStartXY()); + m_bRight2 = (pq.crossProduct(pr) < 0); + } + } + + if (m_i2 == -1) { + m_i2 = find_prev_non_degenerate(segIter, m_i1); + if (m_i2 != -1) { + segIter.resetToVertex(m_i2, -1); + Segment segment2 = segIter.nextSegment(); + double t2 = segment2.getClosestCoordinate(inputPoint, + false); + Point2D p2 = segment2.getCoord2D(t2); + double d2 = Point2D.sqrDistance(p2, inputPoint); + + if (d2 > d1) + m_i2 = -1; + else { + pq.setCoords(p2); + pq.sub(segment2.getStartXY()); + pr.setCoords(inputPoint); + pr.sub(segment2.getStartXY()); + m_bRight2 = (pq.crossProduct(pr) < 0); + + int itemp = m_i1; + m_i1 = m_i2; + m_i2 = itemp; + + boolean btemp = m_bRight1; + m_bRight1 = m_bRight2; + m_bRight2 = btemp; + } + } + } + } + } + + // Try to find two segements that are not degenerate + boolean calc_side(Point2D inputPoint, boolean bRight, + MultiPath multipath, int vertexIndex, int pathIndex) { + SegmentIterator segIter = multipath.querySegmentIterator(); + + find_analysis_pair_from_index(inputPoint, segIter, vertexIndex, + pathIndex); + + if (m_i1 != -1 && m_i2 == -1) {// could not find a pair of segments + return m_bRight1; + } + + if (m_i1 != -1 && m_i2 != -1) { + if (m_bRight1 == m_bRight2) + return m_bRight1;// no conflicting result for the side + else { + // the conflicting result, that we are trying to resolve, + // happens in the obtuse (outer) side of the turn only. + segIter.resetToVertex(m_i1, -1); + Segment segment1 = segIter.nextSegment(); + Point2D tang1 = segment1._getTangent(1.0); + + segIter.resetToVertex(m_i2, -1); + Segment segment2 = segIter.nextSegment(); + Point2D tang2 = segment2._getTangent(0.0); + + double cross = tang1.crossProduct(tang2); + + if (cross >= 0) // the obtuse angle is on the right side + { + return true; + } else // the obtuse angle is on the right side + { + return false; + } + } + } else { + assert (m_i1 == -1 && m_i2 == -1); + return bRight;// could not resolve the side. So just return the + // old value. + } + } + } + + @Override + public Proximity2DResult getNearestCoordinate(Geometry geom, + Point inputPoint, boolean bTestPolygonInterior) { + + return getNearestCoordinate(geom, inputPoint, bTestPolygonInterior, + false); + } + + @Override + public Proximity2DResult getNearestCoordinate(Geometry geom, + Point inputPoint, boolean bTestPolygonInterior, + boolean bCalculateLeftRightSide) { + if (geom.isEmpty()) + return new Proximity2DResult(); + + Point2D inputPoint2D = inputPoint.getXY(); + + Geometry proxmityTestGeom = geom; + int gt = geom.getType().value(); + + if (gt == Geometry.GeometryType.Envelope) { + Polygon polygon = new Polygon(); + polygon.addEnvelope((Envelope) geom, false); + proxmityTestGeom = polygon; + gt = Geometry.GeometryType.Polygon; + } + switch (gt) { + case Geometry.GeometryType.Point: + return pointGetNearestVertex((Point) proxmityTestGeom, inputPoint2D); + case Geometry.GeometryType.MultiPoint: + return multiVertexGetNearestVertex( + (MultiVertexGeometry) proxmityTestGeom, inputPoint2D); + case Geometry.GeometryType.Polyline: + case Geometry.GeometryType.Polygon: + return multiPathGetNearestCoordinate((MultiPath) proxmityTestGeom, + inputPoint2D, bTestPolygonInterior, bCalculateLeftRightSide); + default: { + throw new GeometryException("not implemented"); + } + } + } + + @Override + public Proximity2DResult getNearestVertex(Geometry geom, Point inputPoint) { + if (geom.isEmpty()) + return new Proximity2DResult(); + + Point2D inputPoint2D = inputPoint.getXY(); + + Geometry proxmityTestGeom = geom; + int gt = geom.getType().value(); + + if (gt == Geometry.GeometryType.Envelope) { + Polygon polygon = new Polygon(); + polygon.addEnvelope((Envelope) geom, false); + proxmityTestGeom = polygon; + gt = Geometry.GeometryType.Polygon; + } + switch (gt) { + case Geometry.GeometryType.Point: + return pointGetNearestVertex((Point) proxmityTestGeom, inputPoint2D); + case Geometry.GeometryType.MultiPoint: + case Geometry.GeometryType.Polyline: + case Geometry.GeometryType.Polygon: + return multiVertexGetNearestVertex( + (MultiVertexGeometry) proxmityTestGeom, inputPoint2D); + default: { + throw new GeometryException("not implemented"); + } + } + } + + @Override + public Proximity2DResult[] getNearestVertices(Geometry geom, + Point inputPoint, double searchRadius, int maxVertexCountToReturn) { + if (maxVertexCountToReturn < 0) + throw new IllegalArgumentException(); + + if (geom.isEmpty()) + return new Proximity2DResult[]{}; + + Point2D inputPoint2D = inputPoint.getXY(); + + Geometry proxmityTestGeom = geom; + int gt = geom.getType().value(); + + if (gt == Geometry.GeometryType.Envelope) { + Polygon polygon = new Polygon(); + polygon.addEnvelope((Envelope) geom, false); + proxmityTestGeom = polygon; + gt = Geometry.GeometryType.Polygon; + } + switch (gt) { + case Geometry.GeometryType.Point: + return pointGetNearestVertices((Point) proxmityTestGeom, + inputPoint2D, searchRadius, maxVertexCountToReturn); + case Geometry.GeometryType.MultiPoint: + case Geometry.GeometryType.Polyline: + case Geometry.GeometryType.Polygon: + return multiVertexGetNearestVertices( + (MultiVertexGeometry) proxmityTestGeom, inputPoint2D, + searchRadius, maxVertexCountToReturn); + default: { + throw new GeometryException("not implemented"); + } + } + } + + Proximity2DResult multiPathGetNearestCoordinate(MultiPath geom, + Point2D inputPoint, boolean bTestPolygonInterior, + boolean bCalculateLeftRightSide) { + if (geom.getType() == Geometry.Type.Polygon && bTestPolygonInterior) { + Envelope2D env = new Envelope2D(); + geom.queryEnvelope2D(env); + double tolerance = InternalUtils.calculateToleranceFromGeometry( + null, env, false); + + PolygonUtils.PiPResult pipResult; + + if (bCalculateLeftRightSide) + pipResult = PolygonUtils.isPointInPolygon2D((Polygon) geom, + inputPoint, 0.0); + else + pipResult = PolygonUtils.isPointInPolygon2D((Polygon) geom, + inputPoint, tolerance); + + if (pipResult != PolygonUtils.PiPResult.PiPOutside) { + Proximity2DResult result = new Proximity2DResult(inputPoint, 0, + 0.0); + + if (bCalculateLeftRightSide) + result.setRightSide(true); + + return result; + } + } + + SegmentIterator segIter = geom.querySegmentIterator(); + + Point2D closest = new Point2D(); + int closestVertexIndex = -1; + int closestPathIndex = -1; + double closestDistanceSq = NumberUtils.doubleMax(); + boolean bRight = false; + int num_candidates = 0; + + while (segIter.nextPath()) { + while (segIter.hasNextSegment()) { + Segment segment = segIter.nextSegment(); + double t = segment.getClosestCoordinate(inputPoint, false); + + Point2D point = segment.getCoord2D(t); + + double distanceSq = Point2D.sqrDistance(point, inputPoint); + if (distanceSq < closestDistanceSq) { + num_candidates = 1; + closest = point; + closestVertexIndex = segIter.getStartPointIndex(); + closestPathIndex = segIter.getPathIndex(); + closestDistanceSq = distanceSq; + } else if (distanceSq == closestDistanceSq) { + num_candidates++; + } + } + } + + Proximity2DResult result = new Proximity2DResult(closest, + closestVertexIndex, Math.sqrt(closestDistanceSq)); + + if (bCalculateLeftRightSide) { + segIter.resetToVertex(closestVertexIndex, closestPathIndex); + Segment segment = segIter.nextSegment(); + bRight = (Point2D.orientationRobust(inputPoint, + segment.getStartXY(), segment.getEndXY()) < 0); + + if (num_candidates > 1) { + Side_helper sideHelper = new Side_helper(); + sideHelper.reset(); + bRight = sideHelper.calc_side(inputPoint, bRight, geom, + closestVertexIndex, closestPathIndex); + } + + result.setRightSide(bRight); + } + + return result; + } + + Proximity2DResult pointGetNearestVertex(Point geom, Point2D input_point) { + Point2D pt = geom.getXY(); + double distance = Point2D.distance(pt, input_point); + return new Proximity2DResult(pt, 0, distance); + } + + Proximity2DResult multiVertexGetNearestVertex(MultiVertexGeometry geom, + Point2D inputPoint) { + MultiVertexGeometryImpl mpImpl = (MultiVertexGeometryImpl) geom + ._getImpl(); + AttributeStreamOfDbl position = (AttributeStreamOfDbl) mpImpl + .getAttributeStreamRef((Semantics.POSITION)); + int pointCount = geom.getPointCount(); + + int closestIndex = 0; + double closestx = 0.0; + double closesty = 0.0; + double closestDistanceSq = NumberUtils.doubleMax(); + for (int i = 0; i < pointCount; i++) { + Point2D pt = new Point2D(); + position.read(2 * i, pt); + + double distanceSq = Point2D.sqrDistance(pt, inputPoint); + if (distanceSq < closestDistanceSq) { + closestx = pt.x; + closesty = pt.y; + closestIndex = i; + closestDistanceSq = distanceSq; + } + } + + Proximity2DResult result = new Proximity2DResult(); + result._setParams(closestx, closesty, closestIndex, + Math.sqrt(closestDistanceSq)); + + return result; + } + + Proximity2DResult[] pointGetNearestVertices(Point geom, Point2D inputPoint, + double searchRadius, int maxVertexCountToReturn) { + Proximity2DResult[] resultArray; + + if (maxVertexCountToReturn == 0) { + resultArray = new Proximity2DResult[]{}; + return resultArray; + } + + double searchRadiusSq = searchRadius * searchRadius; + Point2D pt = geom.getXY(); + + double distanceSq = Point2D.sqrDistance(pt, inputPoint); + if (distanceSq <= searchRadiusSq) { + resultArray = new Proximity2DResult[1]; + + Proximity2DResult result = new Proximity2DResult(); + result._setParams(pt.x, pt.y, 0, Math.sqrt(distanceSq)); + resultArray[0] = result; + } else { + resultArray = new Proximity2DResult[0]; + } + + return resultArray; + } + + Proximity2DResult[] multiVertexGetNearestVertices(MultiVertexGeometry geom, + Point2D inputPoint, double searchRadius, int maxVertexCountToReturn) { + Proximity2DResult[] resultArray; + + if (maxVertexCountToReturn == 0) { + resultArray = new Proximity2DResult[0]; + return resultArray; + } + + MultiVertexGeometryImpl mpImpl = (MultiVertexGeometryImpl) geom + ._getImpl(); + AttributeStreamOfDbl position = (AttributeStreamOfDbl) mpImpl + .getAttributeStreamRef((Semantics.POSITION)); + int pointCount = geom.getPointCount(); + + ArrayList v = new ArrayList( + maxVertexCountToReturn); + + int count = 0; + double searchRadiusSq = searchRadius * searchRadius; + for (int i = 0; i < pointCount; i++) { + double x = position.read(2 * i); + double y = position.read(2 * i + 1); + + double xDiff = inputPoint.x - x; + double yDiff = inputPoint.y - y; + + double distanceSq = xDiff * xDiff + yDiff * yDiff; + if (distanceSq <= searchRadiusSq) { + Proximity2DResult result = new Proximity2DResult(); + result._setParams(x, y, i, Math.sqrt(distanceSq)); + + count++; + v.add(result); + + } + } + + int vsize = v.size(); + Collections.sort(v, new Proximity2DResultComparator()); + + if (maxVertexCountToReturn >= vsize) + return v.toArray(new Proximity2DResult[0]); + return v.subList(0, maxVertexCountToReturn).toArray( + new Proximity2DResult[0]); + + } /* - * if (distanceSq <= searchRadiusSq) { if (count >= maxVertexCountToReturn + + * if (distanceSq <= searchRadiusSq) { if (count >= maxVertexCountToReturn + * 1) { count++; double frontDistance = v.get(0).getDistance(); if * (frontDistance * frontDistance <= distanceSq) continue; } - * + * * Proximity2DResult result = new Proximity2DResult(); result._setParams(x, * y, i, Math.sqrt(distanceSq)); - * + * * count++; - * + * * if (count <= maxVertexCountToReturn) { v.add(result); } // else // { // * if (count == maxVertexCountToReturn + 1) // MAKEHEAP(v, * Proximity2DResult, Proximity2DResult::_Compare); // // PUSHHEAP(v, * result, Proximity2DResult, Proximity2DResult::_Compare); // POPHEAP(v, * Proximity2DResult, Proximity2DResult::_Compare); // } } } - * + * * int vsize = v.size(); Collections.sort(v, new * Proximity2DResultComparator()); - * + * * // SORTDYNAMICARRAY(v, Proximity2DResult, 0, vsize, * Proximity2DResult::_Compare); resultArray = new Proximity2DResult[vsize]; * for (int i = 0; i < vsize; i++) { resultArray[i] = * (Proximity2DResult)v.get(i); } - * + * * return resultArray; } */ } diff --git a/src/main/java/com/esri/core/geometry/OperatorRandomPoints.java b/src/main/java/com/esri/core/geometry/OperatorRandomPoints.java index 5dc0841e..5e72aac2 100644 --- a/src/main/java/com/esri/core/geometry/OperatorRandomPoints.java +++ b/src/main/java/com/esri/core/geometry/OperatorRandomPoints.java @@ -5,27 +5,27 @@ package com.esri.core.geometry; public abstract class OperatorRandomPoints extends Operator { - @Override - public Operator.Type getType() { - return Type.RandomPoints; - } + @Override + public Operator.Type getType() { + return Type.RandomPoints; + } - public abstract GeometryCursor execute( - GeometryCursor inputPolygons, - double[] pointsPerSquareKm, - long seed, - SpatialReference sr, - ProgressTracker progressTracker); + public abstract GeometryCursor execute( + GeometryCursor inputPolygons, + double[] pointsPerSquareKm, + long seed, + SpatialReference sr, + ProgressTracker progressTracker); - public abstract Geometry execute( - Geometry inputPolygon, - double pointsPerSquareKm, - long seed, - SpatialReference sr, - ProgressTracker progressTracker); + public abstract Geometry execute( + Geometry inputPolygon, + double pointsPerSquareKm, + long seed, + SpatialReference sr, + ProgressTracker progressTracker); - public static OperatorRandomPoints local() { - return (OperatorRandomPoints) OperatorFactoryLocal.getInstance().getOperator(Type.RandomPoints); - } + public static OperatorRandomPoints local() { + return (OperatorRandomPoints) OperatorFactoryLocal.getInstance().getOperator(Type.RandomPoints); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorRandomPointsCursor.java b/src/main/java/com/esri/core/geometry/OperatorRandomPointsCursor.java index 8f73dea2..65a8cf22 100644 --- a/src/main/java/com/esri/core/geometry/OperatorRandomPointsCursor.java +++ b/src/main/java/com/esri/core/geometry/OperatorRandomPointsCursor.java @@ -8,47 +8,47 @@ * Created by davidraleigh on 5/10/17. */ public class OperatorRandomPointsCursor extends GeometryCursor { - private double[] m_pointsPerSquareKm; - private SpatialReferenceImpl m_spatialReference; - private ProgressTracker m_progressTracker; - private Random m_numberGenerator; - private long m_seed; + private double[] m_pointsPerSquareKm; + private SpatialReferenceImpl m_spatialReference; + private ProgressTracker m_progressTracker; + private Random m_numberGenerator; + private long m_seed; - private int m_PPSKmindex; + private int m_PPSKmindex; - public OperatorRandomPointsCursor(GeometryCursor inputGeoms, - double[] pointsPerSquareKm, - long seed, - SpatialReference sr, - ProgressTracker pr) { - m_inputGeoms = inputGeoms; - m_spatialReference = (SpatialReferenceImpl) sr; - m_pointsPerSquareKm = pointsPerSquareKm; - // TODO, for distributed case geometries will be done in different order each time, - // that is why the random number generator is started over with the same seed - // for each object in the cursor - m_seed = seed; - m_numberGenerator = new Random(seed); - } + public OperatorRandomPointsCursor(GeometryCursor inputGeoms, + double[] pointsPerSquareKm, + long seed, + SpatialReference sr, + ProgressTracker pr) { + m_inputGeoms = inputGeoms; + m_spatialReference = (SpatialReferenceImpl) sr; + m_pointsPerSquareKm = pointsPerSquareKm; + // TODO, for distributed case geometries will be done in different order each time, + // that is why the random number generator is started over with the same seed + // for each object in the cursor + m_seed = seed; + m_numberGenerator = new Random(seed); + } - @Override - public Geometry next() { - if (hasNext()) { - if (m_PPSKmindex + 1 < m_pointsPerSquareKm.length) - m_PPSKmindex++; + @Override + public Geometry next() { + if (hasNext()) { + if (m_PPSKmindex + 1 < m_pointsPerSquareKm.length) + m_PPSKmindex++; - m_numberGenerator.setSeed(m_seed); - try { - return RandomPointMaker.generate( - m_inputGeoms.next(), - m_pointsPerSquareKm[m_PPSKmindex], - m_numberGenerator, - m_spatialReference, - m_progressTracker); - } catch (PJException e) { - throw new GeometryException(e.getMessage()); - } - } - return null; - } + m_numberGenerator.setSeed(m_seed); + try { + return RandomPointMaker.generate( + m_inputGeoms.next(), + m_pointsPerSquareKm[m_PPSKmindex], + m_numberGenerator, + m_spatialReference, + m_progressTracker); + } catch (PJException e) { + throw new GeometryException(e.getMessage()); + } + } + return null; + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorRandomPointsLocal.java b/src/main/java/com/esri/core/geometry/OperatorRandomPointsLocal.java index c3ae8cef..42da2350 100644 --- a/src/main/java/com/esri/core/geometry/OperatorRandomPointsLocal.java +++ b/src/main/java/com/esri/core/geometry/OperatorRandomPointsLocal.java @@ -4,26 +4,26 @@ * Created by davidraleigh on 5/10/17. */ public class OperatorRandomPointsLocal extends OperatorRandomPoints { - @Override - public GeometryCursor execute( - GeometryCursor inputPolygons, - double[] pointsPerSquareKm, - long seed, - SpatialReference sr, - ProgressTracker progressTracker) { - GeometryCursor randomPointsCursor = new OperatorRandomPointsCursor(inputPolygons, pointsPerSquareKm, seed, sr, progressTracker); - return randomPointsCursor; - } + @Override + public GeometryCursor execute( + GeometryCursor inputPolygons, + double[] pointsPerSquareKm, + long seed, + SpatialReference sr, + ProgressTracker progressTracker) { + GeometryCursor randomPointsCursor = new OperatorRandomPointsCursor(inputPolygons, pointsPerSquareKm, seed, sr, progressTracker); + return randomPointsCursor; + } - @Override - public Geometry execute( - Geometry inputPolygon, - double pointsPerSquareKm, - long seed, - SpatialReference sr, - ProgressTracker progressTracker) { - double[] perSqrKM = {pointsPerSquareKm}; - GeometryCursor res = execute(new SimpleGeometryCursor(inputPolygon), perSqrKM, seed, sr, progressTracker); - return res.next(); - } + @Override + public Geometry execute( + Geometry inputPolygon, + double pointsPerSquareKm, + long seed, + SpatialReference sr, + ProgressTracker progressTracker) { + double[] perSqrKM = {pointsPerSquareKm}; + GeometryCursor res = execute(new SimpleGeometryCursor(inputPolygon), perSqrKM, seed, sr, progressTracker); + return res.next(); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorRelate.java b/src/main/java/com/esri/core/geometry/OperatorRelate.java index 3cd3399d..f06d516b 100644 --- a/src/main/java/com/esri/core/geometry/OperatorRelate.java +++ b/src/main/java/com/esri/core/geometry/OperatorRelate.java @@ -31,40 +31,40 @@ * Performs the Relation operation between two geometries using the DE-9IM matrix encoded as a string. */ public abstract class OperatorRelate extends Operator { - @Override - public Type getType() { - return Type.Relate; - } + @Override + public Type getType() { + return Type.Relate; + } - /** - * Performs the Relation operation between two geometries using the DE-9IM matrix encoded as a string. - * - * @param inputGeom1 The first geometry in the relation. - * @param inputGeom2 The second geometry in the relation. - * @param sr The spatial reference of the geometries. - * @param de_9im_string The DE-9IM matrix relation encoded as a string. - * @return Returns True if the relation holds, False otherwise. - */ - public abstract boolean execute(Geometry inputGeom1, Geometry inputGeom2, - SpatialReference sr, String de_9im_string, ProgressTracker progressTracker); + /** + * Performs the Relation operation between two geometries using the DE-9IM matrix encoded as a string. + * + * @param inputGeom1 The first geometry in the relation. + * @param inputGeom2 The second geometry in the relation. + * @param sr The spatial reference of the geometries. + * @param de_9im_string The DE-9IM matrix relation encoded as a string. + * @return Returns True if the relation holds, False otherwise. + */ + public abstract boolean execute(Geometry inputGeom1, Geometry inputGeom2, + SpatialReference sr, String de_9im_string, ProgressTracker progressTracker); - public static OperatorRelate local() { - return (OperatorRelate) OperatorFactoryLocal.getInstance().getOperator( - Type.Relate); - } + public static OperatorRelate local() { + return (OperatorRelate) OperatorFactoryLocal.getInstance().getOperator( + Type.Relate); + } - @Override - public boolean canAccelerateGeometry(Geometry geometry) { - return RelationalOperations.Accelerate_helper - .can_accelerate_geometry(geometry); - } + @Override + public boolean canAccelerateGeometry(Geometry geometry) { + return RelationalOperations.Accelerate_helper + .can_accelerate_geometry(geometry); + } - @Override - public boolean accelerateGeometry(Geometry geometry, - SpatialReference spatialReference, - GeometryAccelerationDegree accelDegree) { - return RelationalOperations.Accelerate_helper.accelerate_geometry( - geometry, spatialReference, accelDegree); - } + @Override + public boolean accelerateGeometry(Geometry geometry, + SpatialReference spatialReference, + GeometryAccelerationDegree accelDegree) { + return RelationalOperations.Accelerate_helper.accelerate_geometry( + geometry, spatialReference, accelDegree); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorRelateLocal.java b/src/main/java/com/esri/core/geometry/OperatorRelateLocal.java index 59227b73..f40b915d 100644 --- a/src/main/java/com/esri/core/geometry/OperatorRelateLocal.java +++ b/src/main/java/com/esri/core/geometry/OperatorRelateLocal.java @@ -26,11 +26,11 @@ class OperatorRelateLocal extends OperatorRelate { - @Override - public boolean execute(Geometry inputGeom1, Geometry inputGeom2, - SpatialReference sr, String scl, ProgressTracker progress_tracker) { - return RelationalOperationsMatrix.relate(inputGeom1, inputGeom2, sr, - scl, progress_tracker); - } + @Override + public boolean execute(Geometry inputGeom1, Geometry inputGeom2, + SpatialReference sr, String scl, ProgressTracker progress_tracker) { + return RelationalOperationsMatrix.relate(inputGeom1, inputGeom2, sr, + scl, progress_tracker); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorShapePreservingDensify.java b/src/main/java/com/esri/core/geometry/OperatorShapePreservingDensify.java index 685ab7d9..c9de6126 100644 --- a/src/main/java/com/esri/core/geometry/OperatorShapePreservingDensify.java +++ b/src/main/java/com/esri/core/geometry/OperatorShapePreservingDensify.java @@ -29,43 +29,43 @@ */ abstract class OperatorShapePreservingDensify extends Operator { - @Override - public Type getType() { - return Type.ShapePreservingDensify; - } + @Override + public Type getType() { + return Type.ShapePreservingDensify; + } - /** - * Performs the Shape Preserving Densify operation on the geometry set. Attributes are interpolated along the scalar t-values of the input segments obtained from the length ratios along the - * densified segments. - * - * @param geoms The geometries to be densified. - * @param sr The spatial reference of the geometries. - * @param maxLengthMeters The maximum segment length allowed. Must be a positive value to be used. Pass zero or NaN to disable densification by length. - * @param maxDeviationMeters The maximum deviation. Must be a positive value to be used. Pass zero or NaN to disable densification by deviation. - * @param reserved Must be 0 or NaN. Reserved for future use. Throws and exception if not NaN or 0. - * @return Returns the densified geometries (It does nothing to geometries with dim less than 1, but simply passes them along). - *

- * The operation always starts from the lowest point on the segment, thus guaranteeing that topologically equal segments are always densified exactly the same. - */ - public abstract GeometryCursor execute(GeometryCursor geoms, SpatialReference sr, double maxLengthMeters, double maxDeviationMeters, double reserved, ProgressTracker progressTracker); + /** + * Performs the Shape Preserving Densify operation on the geometry set. Attributes are interpolated along the scalar t-values of the input segments obtained from the length ratios along the + * densified segments. + * + * @param geoms The geometries to be densified. + * @param sr The spatial reference of the geometries. + * @param maxLengthMeters The maximum segment length allowed. Must be a positive value to be used. Pass zero or NaN to disable densification by length. + * @param maxDeviationMeters The maximum deviation. Must be a positive value to be used. Pass zero or NaN to disable densification by deviation. + * @param reserved Must be 0 or NaN. Reserved for future use. Throws and exception if not NaN or 0. + * @return Returns the densified geometries (It does nothing to geometries with dim less than 1, but simply passes them along). + *

+ * The operation always starts from the lowest point on the segment, thus guaranteeing that topologically equal segments are always densified exactly the same. + */ + public abstract GeometryCursor execute(GeometryCursor geoms, SpatialReference sr, double maxLengthMeters, double maxDeviationMeters, double reserved, ProgressTracker progressTracker); - /** - * Performs the Shape Preserving Densify operation on the geometry. Attributes are interpolated along the scalar t-values of the input segments obtained from the length ratios along the densified - * segments. - * - * @param geom The geometry to be densified. - * @param sr The spatial reference of the geometry. - * @param maxLengthMeters The maximum segment length allowed. Must be a positive value to be used. Pass zero or NaN to disable densification by length. - * @param maxDeviationMeters The maximum deviation. Must be a positive value to be used. Pass zero or NaN to disable densification by deviation. - * @param reserved Must be 0 or NaN. Reserved for future use. Throws and exception if not NaN or 0. - * @return Returns the densified geometries (It does nothing to geometries with dim less than 1, but simply passes them along). - *

- * The operation always starts from the lowest point on the segment, thus guaranteeing that topologically equal segments are always densified exactly the same. - */ - public abstract Geometry execute(Geometry geom, SpatialReference sr, double maxLengthMeters, double maxDeviationMeters, double reserved, ProgressTracker progressTracker); + /** + * Performs the Shape Preserving Densify operation on the geometry. Attributes are interpolated along the scalar t-values of the input segments obtained from the length ratios along the densified + * segments. + * + * @param geom The geometry to be densified. + * @param sr The spatial reference of the geometry. + * @param maxLengthMeters The maximum segment length allowed. Must be a positive value to be used. Pass zero or NaN to disable densification by length. + * @param maxDeviationMeters The maximum deviation. Must be a positive value to be used. Pass zero or NaN to disable densification by deviation. + * @param reserved Must be 0 or NaN. Reserved for future use. Throws and exception if not NaN or 0. + * @return Returns the densified geometries (It does nothing to geometries with dim less than 1, but simply passes them along). + *

+ * The operation always starts from the lowest point on the segment, thus guaranteeing that topologically equal segments are always densified exactly the same. + */ + public abstract Geometry execute(Geometry geom, SpatialReference sr, double maxLengthMeters, double maxDeviationMeters, double reserved, ProgressTracker progressTracker); - public static OperatorShapePreservingDensify local() { - return (OperatorShapePreservingDensify) OperatorFactoryLocal.getInstance() - .getOperator(Type.ShapePreservingDensify); - } + public static OperatorShapePreservingDensify local() { + return (OperatorShapePreservingDensify) OperatorFactoryLocal.getInstance() + .getOperator(Type.ShapePreservingDensify); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorShapePreservingDensifyLocal.java b/src/main/java/com/esri/core/geometry/OperatorShapePreservingDensifyLocal.java index 2a7d4128..50a9874b 100644 --- a/src/main/java/com/esri/core/geometry/OperatorShapePreservingDensifyLocal.java +++ b/src/main/java/com/esri/core/geometry/OperatorShapePreservingDensifyLocal.java @@ -26,19 +26,19 @@ //This is a stub class OperatorShapePreservingDensifyLocal extends - OperatorShapePreservingDensify { - - @Override - public GeometryCursor execute(GeometryCursor geoms, SpatialReference sr, - double maxLengthMeters, double maxDeviationMeters, double reserved, - ProgressTracker progressTracker) { - throw new GeometryException("not implemented"); - } - - @Override - public Geometry execute(Geometry geom, SpatialReference sr, - double maxLengthMeters, double maxDeviationMeters, double reserved, - ProgressTracker progressTracker) { - throw new GeometryException("not implemented"); - } + OperatorShapePreservingDensify { + + @Override + public GeometryCursor execute(GeometryCursor geoms, SpatialReference sr, + double maxLengthMeters, double maxDeviationMeters, double reserved, + ProgressTracker progressTracker) { + throw new GeometryException("not implemented"); + } + + @Override + public Geometry execute(Geometry geom, SpatialReference sr, + double maxLengthMeters, double maxDeviationMeters, double reserved, + ProgressTracker progressTracker) { + throw new GeometryException("not implemented"); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorSimpleRelation.java b/src/main/java/com/esri/core/geometry/OperatorSimpleRelation.java index feb6a6b1..ff24f76d 100644 --- a/src/main/java/com/esri/core/geometry/OperatorSimpleRelation.java +++ b/src/main/java/com/esri/core/geometry/OperatorSimpleRelation.java @@ -33,42 +33,42 @@ */ public abstract class OperatorSimpleRelation extends Operator { - /** - * Performs the given relation operation between two geometries. - * - * @return Returns True if the relation holds, False otherwise. - */ - public abstract boolean execute(Geometry inputGeom1, - Geometry inputGeom2, - SpatialReference sr, - ProgressTracker progressTracker); + /** + * Performs the given relation operation between two geometries. + * + * @return Returns True if the relation holds, False otherwise. + */ + public abstract boolean execute(Geometry inputGeom1, + Geometry inputGeom2, + SpatialReference sr, + ProgressTracker progressTracker); - public HashMap execute(Geometry inputGeom1, - GeometryCursor geometryCursor2, - SpatialReference sr, - ProgressTracker progressTracker) { - HashMap hashMap = new HashMap<>(); - Geometry inputGeom2; - while ((inputGeom2 = geometryCursor2.next()) != null) { - Long index = geometryCursor2.getGeometryID(); - if ((progressTracker != null) && !(progressTracker.progress(-1, -1))) - throw new RuntimeException("user_canceled"); - hashMap.put(index, execute(inputGeom1, inputGeom2, sr, progressTracker)); - } - return hashMap; - } + public HashMap execute(Geometry inputGeom1, + GeometryCursor geometryCursor2, + SpatialReference sr, + ProgressTracker progressTracker) { + HashMap hashMap = new HashMap<>(); + Geometry inputGeom2; + while ((inputGeom2 = geometryCursor2.next()) != null) { + Long index = geometryCursor2.getGeometryID(); + if ((progressTracker != null) && !(progressTracker.progress(-1, -1))) + throw new RuntimeException("user_canceled"); + hashMap.put(index, execute(inputGeom1, inputGeom2, sr, progressTracker)); + } + return hashMap; + } - @Override - public boolean canAccelerateGeometry(Geometry geometry) { - return RelationalOperations.Accelerate_helper - .can_accelerate_geometry(geometry); - } + @Override + public boolean canAccelerateGeometry(Geometry geometry) { + return RelationalOperations.Accelerate_helper + .can_accelerate_geometry(geometry); + } - @Override - public boolean accelerateGeometry(Geometry geometry, - SpatialReference spatialReference, - GeometryAccelerationDegree accelDegree) { - return RelationalOperations.Accelerate_helper.accelerate_geometry( - geometry, spatialReference, accelDegree); - } + @Override + public boolean accelerateGeometry(Geometry geometry, + SpatialReference spatialReference, + GeometryAccelerationDegree accelDegree) { + return RelationalOperations.Accelerate_helper.accelerate_geometry( + geometry, spatialReference, accelDegree); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorSimplify.java b/src/main/java/com/esri/core/geometry/OperatorSimplify.java index 400f1e9b..dbba5391 100644 --- a/src/main/java/com/esri/core/geometry/OperatorSimplify.java +++ b/src/main/java/com/esri/core/geometry/OperatorSimplify.java @@ -39,72 +39,72 @@ * See also OperatorSimplifyOGC. */ public abstract class OperatorSimplify extends Operator { - @Override - public Operator.Type getType() { - return Operator.Type.Simplify; - } + @Override + public Operator.Type getType() { + return Operator.Type.Simplify; + } - /** - * Tests if the Geometry is simple. - * - * @param geom The Geometry to be tested. - * @param spatialRef Spatial reference from which the tolerance is obtained. Can be null, then a - * very small tolerance value is derived from the geometry bounds. - * @param bForceTest When True, the Geometry will be tested regardless of the internal IsKnownSimple flag. - * @param result if not null, will contain the results of the check. - * @param progressTracker Allows cancellation of a long operation. Can be null. - **/ - public abstract boolean isSimpleAsFeature(Geometry geom, - SpatialReference spatialRef, - boolean bForceTest, - NonSimpleResult result, - ProgressTracker progressTracker); + /** + * Tests if the Geometry is simple. + * + * @param geom The Geometry to be tested. + * @param spatialRef Spatial reference from which the tolerance is obtained. Can be null, then a + * very small tolerance value is derived from the geometry bounds. + * @param bForceTest When True, the Geometry will be tested regardless of the internal IsKnownSimple flag. + * @param result if not null, will contain the results of the check. + * @param progressTracker Allows cancellation of a long operation. Can be null. + **/ + public abstract boolean isSimpleAsFeature(Geometry geom, + SpatialReference spatialRef, + boolean bForceTest, + NonSimpleResult result, + ProgressTracker progressTracker); - /** - * Tests if the Geometry is simple (second call will use a cached IsKnownSimple flag and immediately return). - * - * @param geom The Geometry to be tested. - * @param spatialRef Spatial reference from which the tolerance is obtained. Can be null, then a - * very small tolerance value is derived from the geometry bounds. - * @param progressTracker Allows cancellation of a long operation. Can be null. - */ - public boolean isSimpleAsFeature(Geometry geom, SpatialReference spatialRef, ProgressTracker progressTracker) { - return isSimpleAsFeature(geom, spatialRef, false, null, progressTracker); - } + /** + * Tests if the Geometry is simple (second call will use a cached IsKnownSimple flag and immediately return). + * + * @param geom The Geometry to be tested. + * @param spatialRef Spatial reference from which the tolerance is obtained. Can be null, then a + * very small tolerance value is derived from the geometry bounds. + * @param progressTracker Allows cancellation of a long operation. Can be null. + */ + public boolean isSimpleAsFeature(Geometry geom, SpatialReference spatialRef, ProgressTracker progressTracker) { + return isSimpleAsFeature(geom, spatialRef, false, null, progressTracker); + } - /** - * Performs the Simplify operation on the geometry cursor. - * - * @param geoms Geometries to simplify. - * @param sr Spatial reference from which the tolerance is obtained. When null, the tolerance - * will be derived individually for each geometry from its bounds. - * @param bForceSimplify When True, the Geometry will be simplified regardless of the internal IsKnownSimple flag. - * @param progressTracker Allows cancellation of a long operation. Can be null. - * @return Returns a GeometryCursor of simplified geometries. - *

- * The isSimpleAsFeature returns true after this method. - */ - public abstract GeometryCursor execute(GeometryCursor geoms, - SpatialReference sr, boolean bForceSimplify, - ProgressTracker progressTracker); + /** + * Performs the Simplify operation on the geometry cursor. + * + * @param geoms Geometries to simplify. + * @param sr Spatial reference from which the tolerance is obtained. When null, the tolerance + * will be derived individually for each geometry from its bounds. + * @param bForceSimplify When True, the Geometry will be simplified regardless of the internal IsKnownSimple flag. + * @param progressTracker Allows cancellation of a long operation. Can be null. + * @return Returns a GeometryCursor of simplified geometries. + *

+ * The isSimpleAsFeature returns true after this method. + */ + public abstract GeometryCursor execute(GeometryCursor geoms, + SpatialReference sr, boolean bForceSimplify, + ProgressTracker progressTracker); - /** - * Performs the Simplify operation on the geometry. - * - * @param geom Geometry to simplify. - * @param sr Spatial reference from which the tolerance is obtained. When null, the tolerance - * will be derived individually for each geometry from its bounds. - * @param bForceSimplify When True, the Geometry will be simplified regardless of the internal IsKnownSimple flag. - * @param progressTracker Allows cancellation of a long operation. Can be null. - * @return Returns a simple geometry. - *

- * The isSimpleAsFeature returns true after this method. - */ - public abstract Geometry execute(Geometry geom, SpatialReference sr, - boolean bForceSimplify, ProgressTracker progressTracker); + /** + * Performs the Simplify operation on the geometry. + * + * @param geom Geometry to simplify. + * @param sr Spatial reference from which the tolerance is obtained. When null, the tolerance + * will be derived individually for each geometry from its bounds. + * @param bForceSimplify When True, the Geometry will be simplified regardless of the internal IsKnownSimple flag. + * @param progressTracker Allows cancellation of a long operation. Can be null. + * @return Returns a simple geometry. + *

+ * The isSimpleAsFeature returns true after this method. + */ + public abstract Geometry execute(Geometry geom, SpatialReference sr, + boolean bForceSimplify, ProgressTracker progressTracker); - public static OperatorSimplify local() { - return (OperatorSimplify) OperatorFactoryLocal.getInstance() - .getOperator(Type.Simplify); - } + public static OperatorSimplify local() { + return (OperatorSimplify) OperatorFactoryLocal.getInstance() + .getOperator(Type.Simplify); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorSimplifyCursor.java b/src/main/java/com/esri/core/geometry/OperatorSimplifyCursor.java index 362154a5..a2cb146d 100644 --- a/src/main/java/com/esri/core/geometry/OperatorSimplifyCursor.java +++ b/src/main/java/com/esri/core/geometry/OperatorSimplifyCursor.java @@ -24,42 +24,42 @@ package com.esri.core.geometry; class OperatorSimplifyCursor extends GeometryCursor { - SpatialReference m_spatialReference; - ProgressTracker m_progressTracker; - boolean m_bForceSimplify; + SpatialReference m_spatialReference; + ProgressTracker m_progressTracker; + boolean m_bForceSimplify; - // Reviewed vs. Feb 8 2011 - OperatorSimplifyCursor(GeometryCursor geoms, SpatialReference spatialRef, - boolean bForceSimplify, ProgressTracker progressTracker) { - if (geoms == null) - throw new IllegalArgumentException(); + // Reviewed vs. Feb 8 2011 + OperatorSimplifyCursor(GeometryCursor geoms, SpatialReference spatialRef, + boolean bForceSimplify, ProgressTracker progressTracker) { + if (geoms == null) + throw new IllegalArgumentException(); - m_progressTracker = progressTracker; - m_bForceSimplify = bForceSimplify; - m_inputGeoms = geoms; + m_progressTracker = progressTracker; + m_bForceSimplify = bForceSimplify; + m_inputGeoms = geoms; - m_spatialReference = spatialRef; - } + m_spatialReference = spatialRef; + } - // Reviewed vs. Feb 8 2011 - @Override - public Geometry next() { - if (hasNext()) { - if ((m_progressTracker != null) && !(m_progressTracker.progress(-1, -1))) - throw new RuntimeException("user_canceled"); - return simplify(m_inputGeoms.next()); - } - return null; - } + // Reviewed vs. Feb 8 2011 + @Override + public Geometry next() { + if (hasNext()) { + if ((m_progressTracker != null) && !(m_progressTracker.progress(-1, -1))) + throw new RuntimeException("user_canceled"); + return simplify(m_inputGeoms.next()); + } + return null; + } - // Reviewed vs. Feb 8 2011 - Geometry simplify(Geometry geometry) { - if (geometry == null) - throw new IllegalArgumentException(); + // Reviewed vs. Feb 8 2011 + Geometry simplify(Geometry geometry) { + if (geometry == null) + throw new IllegalArgumentException(); - // Geometry.Type type = geometry.getType(); + // Geometry.Type type = geometry.getType(); - return OperatorSimplifyLocalHelper.simplifyAsFeature(geometry, - m_spatialReference, m_bForceSimplify, m_progressTracker); - } + return OperatorSimplifyLocalHelper.simplifyAsFeature(geometry, + m_spatialReference, m_bForceSimplify, m_progressTracker); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorSimplifyCursorOGC.java b/src/main/java/com/esri/core/geometry/OperatorSimplifyCursorOGC.java index e1d5e0af..55690dc6 100644 --- a/src/main/java/com/esri/core/geometry/OperatorSimplifyCursorOGC.java +++ b/src/main/java/com/esri/core/geometry/OperatorSimplifyCursorOGC.java @@ -24,39 +24,39 @@ package com.esri.core.geometry; class OperatorSimplifyCursorOGC extends GeometryCursor { - SpatialReference m_spatialReference; - ProgressTracker m_progressTracker; - boolean m_bForceSimplify; - - OperatorSimplifyCursorOGC(GeometryCursor geoms, - SpatialReference spatialRef, boolean bForceSimplify, - ProgressTracker progressTracker) { - if (geoms == null) - throw new IllegalArgumentException(); - - m_progressTracker = progressTracker; - m_bForceSimplify = bForceSimplify; - - m_inputGeoms = geoms; - - m_spatialReference = spatialRef; - } - - @Override - public Geometry next() { - if (hasNext()) { - if ((m_progressTracker != null) && !(m_progressTracker.progress(-1, -1))) - throw new RuntimeException("user_canceled"); - return simplify(m_inputGeoms.next()); - } - return null; - } - - Geometry simplify(Geometry geometry) { - if (geometry == null) - throw new IllegalArgumentException(); - - return OperatorSimplifyLocalHelper.simplifyOGC(geometry, - m_spatialReference, m_bForceSimplify, m_progressTracker); - } + SpatialReference m_spatialReference; + ProgressTracker m_progressTracker; + boolean m_bForceSimplify; + + OperatorSimplifyCursorOGC(GeometryCursor geoms, + SpatialReference spatialRef, boolean bForceSimplify, + ProgressTracker progressTracker) { + if (geoms == null) + throw new IllegalArgumentException(); + + m_progressTracker = progressTracker; + m_bForceSimplify = bForceSimplify; + + m_inputGeoms = geoms; + + m_spatialReference = spatialRef; + } + + @Override + public Geometry next() { + if (hasNext()) { + if ((m_progressTracker != null) && !(m_progressTracker.progress(-1, -1))) + throw new RuntimeException("user_canceled"); + return simplify(m_inputGeoms.next()); + } + return null; + } + + Geometry simplify(Geometry geometry) { + if (geometry == null) + throw new IllegalArgumentException(); + + return OperatorSimplifyLocalHelper.simplifyOGC(geometry, + m_spatialReference, m_bForceSimplify, m_progressTracker); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorSimplifyLocal.java b/src/main/java/com/esri/core/geometry/OperatorSimplifyLocal.java index a1eea89c..c18690ad 100644 --- a/src/main/java/com/esri/core/geometry/OperatorSimplifyLocal.java +++ b/src/main/java/com/esri/core/geometry/OperatorSimplifyLocal.java @@ -25,35 +25,35 @@ class OperatorSimplifyLocal extends OperatorSimplify { - // Reviewed vs. Feb 8 2011 - @Override - public GeometryCursor execute(GeometryCursor geoms, - SpatialReference spatialRef, - boolean bForceSimplify, - ProgressTracker progressTracker) { - return new OperatorSimplifyCursor(geoms, spatialRef, bForceSimplify,progressTracker); - } - - // Reviewed vs. Feb 8 2011 - @Override - public boolean isSimpleAsFeature(Geometry geom, - SpatialReference spatialRef, - boolean bForceTest, - NonSimpleResult result, - ProgressTracker progressTracker) { - int res = OperatorSimplifyLocalHelper.isSimpleAsFeature(geom, spatialRef, bForceTest, result, progressTracker); - return res > 0; - } - - // Reviewed vs. Feb 8 2011 - @Override - public Geometry execute(Geometry geom, - SpatialReference spatialRef, - boolean bForceSimplify, - ProgressTracker progressTracker) { - SimpleGeometryCursor inputCursor = new SimpleGeometryCursor(geom); - GeometryCursor outputCursor = execute(inputCursor, spatialRef,bForceSimplify, progressTracker); - - return outputCursor.next(); - } + // Reviewed vs. Feb 8 2011 + @Override + public GeometryCursor execute(GeometryCursor geoms, + SpatialReference spatialRef, + boolean bForceSimplify, + ProgressTracker progressTracker) { + return new OperatorSimplifyCursor(geoms, spatialRef, bForceSimplify, progressTracker); + } + + // Reviewed vs. Feb 8 2011 + @Override + public boolean isSimpleAsFeature(Geometry geom, + SpatialReference spatialRef, + boolean bForceTest, + NonSimpleResult result, + ProgressTracker progressTracker) { + int res = OperatorSimplifyLocalHelper.isSimpleAsFeature(geom, spatialRef, bForceTest, result, progressTracker); + return res > 0; + } + + // Reviewed vs. Feb 8 2011 + @Override + public Geometry execute(Geometry geom, + SpatialReference spatialRef, + boolean bForceSimplify, + ProgressTracker progressTracker) { + SimpleGeometryCursor inputCursor = new SimpleGeometryCursor(geom); + GeometryCursor outputCursor = execute(inputCursor, spatialRef, bForceSimplify, progressTracker); + + return outputCursor.next(); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorSimplifyLocalHelper.java b/src/main/java/com/esri/core/geometry/OperatorSimplifyLocalHelper.java index b6707af3..2513693e 100644 --- a/src/main/java/com/esri/core/geometry/OperatorSimplifyLocalHelper.java +++ b/src/main/java/com/esri/core/geometry/OperatorSimplifyLocalHelper.java @@ -31,2204 +31,2180 @@ import com.esri.core.geometry.MultiVertexGeometryImpl.GeometryXSimple; class OperatorSimplifyLocalHelper { - private static final class Edge { - Edge() { - m_flags = 0; - // m_segment.createInstance(); - } - - Segment m_segment; - int m_vertexIndex; - int m_pathIndex; - int m_flags; - - void setReversed(boolean bYesNo) { - m_flags &= (~1); - m_flags = m_flags | (bYesNo ? 1 : 0); - } - - // The value returned by GetReversed is interpreted differently in - // checkSelfIntersections_ and checkValidRingOrientation_ - boolean getReversed() /* const */ { - return (m_flags & 1) != 0; - } - - int getRightSide() /* const */ { - return getReversed() ? 0 : 1; // 0 means there should be an - // emptiness on the right side of - // the edge, 1 means there is - // interior - } - } - - private final VertexDescription m_description; - private Geometry m_geometry; - private SpatialReferenceImpl m_sr; - private int m_dbgCounter; // debugging counter(for breakpoints) - private double m_toleranceIsSimple; - private double m_toleranceSimplify; - // private double m_toleranceCluster; //cluster tolerance needs to be - // sqrt(2) times larger than the tolerance of the other simplify processes. - private int m_knownSimpleResult; - private int m_attributeCount; - - private ArrayList m_edges; - private AttributeStreamOfInt32 m_FreeEdges; - private ArrayList m_lineEdgesRecycle; - private AttributeStreamOfInt32 m_newEdges; - private SegmentIteratorImpl m_recycledSegIter; - private IndexMultiDCList m_crossOverHelperList; - private AttributeStreamOfInt32 m_paths_for_OGC_tests; - - private ProgressTracker m_progressTracker; - - private Treap m_AET; - private AttributeStreamOfInt32 m_xyToNode1; // for each vertex, contains -1, - // or the edge node. - private AttributeStreamOfInt32 m_xyToNode2; // for each vertex, contains -1, - // or the edge node. - private AttributeStreamOfInt32 m_pathOrientations; // 0 if undefined, -1 for - // counterclockwise, 1 - // for clockwise. - private AttributeStreamOfInt32 m_pathParentage; - private int m_unknownOrientationPathCount; - private double m_yScanline; - - private AttributeStreamOfDbl m_xy; - private AttributeStreamOfInt32 m_pairs; - private AttributeStreamOfInt32 m_pairIndices; - - private EditShape m_editShape; - private boolean m_bOGCRestrictions; - private boolean m_bPlanarSimplify; - - private int isSimplePlanarImpl_() { - m_bPlanarSimplify = true; - if (Geometry.isMultiPath(m_geometry.getType().value())) { - if (!checkStructure_()) // check structure of geometry(no zero - // length paths, etc) - return 0; - - if (!checkDegenerateSegments_(false)) // check for degenerate - // segments(only 2D,no zs or - // other attributes) - return 0; - } - - if (!checkClustering_()) // check clustering(points are either - // coincident,or further than tolerance) - return 0; - - if (!Geometry.isMultiPath(m_geometry.getType().value())) - return 2; // multipoint is simple - - if (!checkCracking_()) // check that there are no self intersections and - // overlaps among segments. - return 0; - - if (m_geometry.getType() == Geometry.Type.Polyline) { - if (!checkSelfIntersectionsPolylinePlanar_()) - return 0; - - return 2; // polyline is simple - } - - if (!checkSelfIntersections_()) // check that there are no other self - // intersections (for the cases of - // several segments connect in a point) - return 0; - - // check that every hole is counterclockwise, and every exterior is - // clockwise. - // for the strong simple also check that exterior rings are followed by - // the interior rings. - return checkValidRingOrientation_(); - } - - private boolean testToleranceDistance_(int xyindex1, int xyindex2) { - double x1 = m_xy.read(2 * xyindex1); - double y1 = m_xy.read(2 * xyindex1 + 1); - double x2 = m_xy.read(2 * xyindex2); - double y2 = m_xy.read(2 * xyindex2 + 1); - boolean b = !Clusterer.isClusterCandidate_(x1, y1, x2, y2, - m_toleranceIsSimple * m_toleranceIsSimple); - if (!b) { - if (m_geometry.getDimension() == 0) - return false; - - return (x1 == x2 && y1 == y2); // points either coincide or - // further,than the tolerance - } - - return b; - } - - private boolean checkStructure_() { - MultiPathImpl multiPathImpl = (MultiPathImpl) m_geometry._getImpl(); - int minsize = multiPathImpl.m_bPolygon ? 3 : 2; - for (int ipath = 0, npath = multiPathImpl.getPathCount(); ipath < npath; ipath++) { - if (multiPathImpl.getPathSize(ipath) < minsize) { - m_nonSimpleResult = new NonSimpleResult(NonSimpleResult.Reason.Structure, ipath, 0); - return false; - } - } - - return true; - } - - private boolean checkDegenerateSegments_(boolean bTestZs) { - MultiPathImpl multiPathImpl = (MultiPathImpl) m_geometry._getImpl(); - SegmentIteratorImpl segIter = multiPathImpl.querySegmentIterator(); - // Envelope2D env2D; - boolean bHasZ = multiPathImpl - .hasAttribute(VertexDescription.Semantics.Z); - double ztolerance = !bHasZ ? 0 : InternalUtils - .calculateZToleranceFromGeometry(m_sr, multiPathImpl, false); - while (segIter.nextPath()) { - while (segIter.hasNextSegment()) { - /* const */ - Segment seg = segIter.nextSegment(); - double length = seg.calculateLength2D(); - if (length > m_toleranceIsSimple) - continue; - - if (bTestZs && bHasZ) { - double z0 = seg.getStartAttributeAsDbl( - VertexDescription.Semantics.Z, 0); - double z1 = seg.getStartAttributeAsDbl( - VertexDescription.Semantics.Z, 0); - if (Math.abs(z1 - z0) > ztolerance) - continue; - } - - m_nonSimpleResult = new NonSimpleResult( - NonSimpleResult.Reason.DegenerateSegments, - segIter.getStartPointIndex(), -1); - return false; - } - } - - return true; - } - - private boolean checkClustering_() { - MultiVertexGeometryImpl multiVertexImpl = (MultiVertexGeometryImpl) m_geometry - ._getImpl(); - - MultiPathImpl multiPathImpl = null; - if (Geometry.isMultiPath(m_geometry.getType().value())) - multiPathImpl = (MultiPathImpl) m_geometry._getImpl(); - - boolean get_paths = (m_bPlanarSimplify || m_bOGCRestrictions) - && multiPathImpl != null; - - int pointCount = multiVertexImpl.getPointCount(); - m_xy = (AttributeStreamOfDbl) multiVertexImpl - .getAttributeStreamRef(VertexDescription.Semantics.POSITION); - m_pairs = new AttributeStreamOfInt32(0); - m_pairs.reserve(pointCount * 2); - m_pairIndices = new AttributeStreamOfInt32(0); - m_pairIndices.reserve(pointCount * 2); - if (get_paths) { - if (m_paths_for_OGC_tests == null) - m_paths_for_OGC_tests = new AttributeStreamOfInt32(0); - m_paths_for_OGC_tests.reserve(pointCount); - } - int ipath = 0; - for (int i = 0; i < pointCount; i++) { - m_pairs.add(2 * i); // y - tol(BOTTOM) - m_pairs.add(2 * i + 1); // y + tol(TOP) - m_pairIndices.add(2 * i); - m_pairIndices.add(2 * i + 1); - if (get_paths) { - while (i >= multiPathImpl.getPathEnd(ipath)) - ipath++; - - m_paths_for_OGC_tests.add(ipath); - } - - } - - BucketSort sorter = new BucketSort(); - sorter.sort(m_pairIndices, 0, 2 * pointCount, new IndexSorter(this, - get_paths)); - - m_AET.clear(); - m_AET.setComparator(new ClusterTestComparator(this)); - m_AET.setCapacity(pointCount); - for (int index = 0, n = pointCount * 2; index < n; index++) { - int pairIndex = m_pairIndices.get(index); - int pair = m_pairs.get(pairIndex); - int xyindex = pair >> 1; // k = 2n or 2n + 1 represent a vertical - // segment for the same vertex. - // Therefore, k / 2 represents a vertex - // index - // Points need to be either exactly equal or further than 2 * - // tolerance apart. - if ((pair & 1) == 0) {// bottom element - int aetNode = m_AET.addElement(xyindex, -1); - // add it to the AET,end test it against its left and right - // neighbours. - int leftneighbour = m_AET.getPrev(aetNode); - if (leftneighbour != Treap.nullNode() - && !testToleranceDistance_( - m_AET.getElement(leftneighbour), xyindex)) { - m_nonSimpleResult = new NonSimpleResult( - NonSimpleResult.Reason.Clustering, xyindex, - m_AET.getElement(leftneighbour)); - return false; - } - int rightneighbour = m_AET.getNext(aetNode); - if (rightneighbour != Treap.nullNode() - && !testToleranceDistance_( - m_AET.getElement(rightneighbour), xyindex)) { - m_nonSimpleResult = new NonSimpleResult( - NonSimpleResult.Reason.Clustering, xyindex, - m_AET.getElement(rightneighbour)); - return false; - } - } else { // top - // get left and right neighbours, and remove the element - // from AET. Then test the neighbours with the - // tolerance. - int aetNode = m_AET.search(xyindex, -1); - int leftneighbour = m_AET.getPrev(aetNode); - int rightneighbour = m_AET.getNext(aetNode); - m_AET.deleteNode(aetNode, -1); - if (leftneighbour != Treap.nullNode() - && rightneighbour != Treap.nullNode() - && !testToleranceDistance_( - m_AET.getElement(leftneighbour), - m_AET.getElement(rightneighbour))) { - m_nonSimpleResult = new NonSimpleResult( - NonSimpleResult.Reason.Clustering, - m_AET.getElement(leftneighbour), - m_AET.getElement(rightneighbour)); - return false; - } - } - } - - return true; - } - - private boolean checkCracking_() { - MultiVertexGeometryImpl multiVertexImpl = (MultiVertexGeometryImpl) m_geometry - ._getImpl(); - int pointCount = multiVertexImpl.getPointCount(); - if (pointCount < 10)// use brute force for smaller polygons - { - return checkCrackingBrute_(); - } else { - return checkCrackingPlanesweep_(); - } - } - - private boolean checkCrackingPlanesweep_() // cracker,that uses planesweep - // algorithm. - { - EditShape editShape = new EditShape(); - editShape.addGeometry(m_geometry); - NonSimpleResult result = new NonSimpleResult(); - boolean bNonSimple = Cracker.needsCracking(false, editShape, - m_toleranceIsSimple, result, m_progressTracker); - if (bNonSimple) { - result.m_vertexIndex1 = editShape - .getVertexIndex(result.m_vertexIndex1); - result.m_vertexIndex2 = editShape - .getVertexIndex(result.m_vertexIndex2); - m_nonSimpleResult.Assign(result); - return false; - } else - return true; - } - - private boolean checkCrackingBrute_() // cracker, that uses brute force (a - // double loop) to find segment - // intersections. - { - MultiPathImpl multiPathImpl = (MultiPathImpl) m_geometry._getImpl(); - // Implementation without a QuadTreeImpl accelerator - SegmentIteratorImpl segIter1 = multiPathImpl.querySegmentIterator(); - SegmentIteratorImpl segIter2 = multiPathImpl.querySegmentIterator(); - // Envelope2D env2D; - while (segIter1.nextPath()) { - while (segIter1.hasNextSegment()) { - /* const */ - Segment seg1 = segIter1.nextSegment(); - if (!segIter1.isLastSegmentInPath() || !segIter1.isLastPath()) { - segIter2.resetTo(segIter1); - do { - while (segIter2.hasNextSegment()) { - /* const */ - Segment seg2 = segIter2.nextSegment(); - int res = seg1._isIntersecting(seg2, - m_toleranceIsSimple, true); - if (res != 0) { - NonSimpleResult.Reason reason = res == 2 ? NonSimpleResult.Reason.CrossOver - : NonSimpleResult.Reason.Cracking; - m_nonSimpleResult = new NonSimpleResult(reason, - segIter1.getStartPointIndex(), - segIter2.getStartPointIndex()); - return false; - } - } - } while (segIter2.nextPath()); - } - } - } - return true; - } - - private boolean checkSelfIntersections_() { - MultiPathImpl multiPathImpl = (MultiPathImpl) m_geometry._getImpl(); - m_edges.clear(); - m_edges.ensureCapacity(20);// we reuse the edges while going through a - // polygon. - m_lineEdgesRecycle.clear(); - m_lineEdgesRecycle.ensureCapacity(20);// we reuse the edges while going - // through a polygon. - - m_recycledSegIter = multiPathImpl.querySegmentIterator(); - m_recycledSegIter.setCirculator(true); - - AttributeStreamOfInt32 bunch = new AttributeStreamOfInt32(0);// stores - // coincident - // vertices - bunch.reserve(10); - int pointCount = multiPathImpl.getPointCount(); - double xprev = NumberUtils.TheNaN; - double yprev = 0; - // We already have a sorted list of vertices from clustering check. - for (int index = 0, n = pointCount * 2; index < n; index++) { - int pairIndex = m_pairIndices.get(index); - int pair = m_pairs.get(pairIndex); - if ((pair & 1) != 0) - continue; // m_pairs array is redundant. See checkClustering_. - - int xyindex = pair >> 1; - - double x = m_xy.read(2 * xyindex); - double y = m_xy.read(2 * xyindex + 1); - if (bunch.size() != 0) { - if (x != xprev || y != yprev) { - if (!processBunchForSelfIntersectionTest_(bunch)) - return false; - if (bunch != null) - bunch.clear(false); - } - } - - bunch.add(xyindex); - xprev = x; - yprev = y; - } - - assert (bunch.size() > 0);// cannot be empty - - if (!processBunchForSelfIntersectionTest_(bunch)) - return false; - - return true; - } - - static final class Vertex_info { - double x, y; - int ipath; - int ivertex; - boolean boundary; - } - - ; - - static final class Vertex_info_pl { - double x; - double y; - int ipath; - int ivertex; - boolean boundary; - boolean end_point; - } - - ; - - boolean checkSelfIntersectionsPolylinePlanar_() { - MultiPathImpl multiPathImpl = (MultiPathImpl) m_geometry._getImpl(); - - boolean closedPaths[] = new boolean[multiPathImpl.getPathCount()]; - for (int ipath = 0, npaths = multiPathImpl.getPathCount(); ipath < npaths; ipath++) { - closedPaths[ipath] = multiPathImpl.isClosedPathInXYPlane(ipath); - } - - Vertex_info_pl vi_prev = new Vertex_info_pl(); - boolean is_closed_path; - int path_start; - int path_last; - - Point2D pt = new Point2D(); - - {// scope - int pairIndex = m_pairIndices.get(0); - int pair = m_pairs.get(pairIndex); - int xyindex = pair >> 1; - m_xy.read(2 * xyindex, pt); - int ipath = m_paths_for_OGC_tests.get(xyindex); - is_closed_path = closedPaths[ipath]; - path_start = multiPathImpl.getPathStart(ipath); - path_last = multiPathImpl.getPathEnd(ipath) - 1; - vi_prev.end_point = (xyindex == path_start) - || (xyindex == path_last); - if (m_bOGCRestrictions) - vi_prev.boundary = !is_closed_path && vi_prev.end_point; - else - // for regular planar simplify, only the end points are allowed - // to coincide - vi_prev.boundary = vi_prev.end_point; - vi_prev.ipath = ipath; - vi_prev.x = pt.x; - vi_prev.y = pt.y; - vi_prev.ivertex = xyindex; - } - - Vertex_info_pl vi = new Vertex_info_pl(); - - for (int index = 1, n = m_pairIndices.size(); index < n; index++) { - int pairIndex = m_pairIndices.get(index); - int pair = m_pairs.get(pairIndex); - if ((pair & 1) != 0) - continue; - - int xyindex = pair >> 1; - m_xy.read(2 * xyindex, pt); - int ipath = m_paths_for_OGC_tests.get(xyindex); - if (ipath != vi_prev.ipath) { - is_closed_path = closedPaths[ipath]; - path_start = multiPathImpl.getPathStart(ipath); - path_last = multiPathImpl.getPathEnd(ipath) - 1; - } - boolean boundary; - boolean end_point = (xyindex == path_start) - || (xyindex == path_last); - if (m_bOGCRestrictions) - boundary = !is_closed_path && vi_prev.end_point; - else - // for regular planar simplify, only the end points are allowed - // to coincide - boundary = vi_prev.end_point; - - vi.x = pt.x; - vi.y = pt.y; - vi.ipath = ipath; - vi.ivertex = xyindex; - vi.boundary = boundary; - vi.end_point = end_point; - - if (vi.x == vi_prev.x && vi.y == vi_prev.y) { - if (m_bOGCRestrictions) { - if (!vi.boundary || !vi_prev.boundary) { - if ((vi.ipath != vi_prev.ipath) - || (!vi.end_point && !vi_prev.end_point))// check - // that - // this - // is - // not - // the - // endpoints - // of - // a - // closed - // path - { - // one of coincident vertices is not on the boundary - // this is either Non_simple_result::cross_over or - // Non_simple_result::ogc_self_tangency. - // too expensive to distinguish between the two. - m_nonSimpleResult = new NonSimpleResult( - NonSimpleResult.Reason.OGCPolylineSelfTangency, - vi.ivertex, vi_prev.ivertex); - return false;// common point not on the boundary - } - } - } else { - if (!vi.end_point || !vi_prev.end_point) {// one of - // coincident - // vertices is - // not an - // endpoint - m_nonSimpleResult = new NonSimpleResult( - NonSimpleResult.Reason.CrossOver, vi.ivertex, - vi_prev.ivertex); - return false;// common point not on the boundary - } - } - } - - Vertex_info_pl tmp = vi_prev; - vi_prev = vi; - vi = tmp; - } - - return true; - } - - final static class Vertex_info_pg { - double x; - double y; - int ipath; - int ivertex; - int ipolygon; - - Vertex_info_pg(double x_, double y_, int ipath_, int xyindex_, - int polygon_) { - x = x_; - y = y_; - ipath = ipath_; - ivertex = xyindex_; - ipolygon = polygon_; - } - - boolean is_equal(Vertex_info_pg other) { - return x == other.x && y == other.y && ipath == other.ipath - && ivertex == other.ivertex && ipolygon == other.ipolygon; - } - } - - ; - - boolean check_self_intersections_polygons_OGC_() { - MultiPathImpl multiPathImpl = (MultiPathImpl) (m_geometry._getImpl()); - // OGC MultiPolygon is simple when each Polygon is simple and Polygons a - // allowed only touch at finite number of vertices. - // OGC Polygon is simple if it consist of simple LinearRings. - // LinearRings cannot cross. - // Any two LinearRings of a OGC Polygon are allowed to touch at single - // vertex only. - // The OGC Polygon interior has to be a connected set. - - // At this point we assume that the ring order has to be correct (holes - // follow corresponding exterior ring). - // No Rings cross. Exterior rings can only touch at finite number of - // vertices. - - // Fill a mapping of ring to - int[] ring_to_polygon = new int[multiPathImpl.getPathCount()]; - int exteriors = -1; - boolean has_holes = false; - for (int ipath = 0, n = multiPathImpl.getPathCount(); ipath < n; ipath++) { - if (multiPathImpl.isExteriorRing(ipath)) { - has_holes = false; - exteriors++; - if (ipath < n - 1) { - if (!multiPathImpl.isExteriorRing(ipath + 1)) - has_holes = true; - } - } - - // For OGC polygons with no holes, store -1. - // For polygons with holes, store polygon index for each ring. - ring_to_polygon[ipath] = has_holes ? exteriors : -1; - } - - // Use already sorted m_pairIndices - Vertex_info_pg vi_prev = null; - Point2D pt = new Point2D(); - {// scope - int pairIndex = m_pairIndices.get(0); - int pair = m_pairs.get(pairIndex); - int xyindex = pair >> 1; - m_xy.read(2 * xyindex, pt); - int ipath = m_paths_for_OGC_tests.get(xyindex); - vi_prev = new Vertex_info_pg(pt.x, pt.y, ipath, xyindex, - ring_to_polygon[ipath]); - } - - ArrayList intersections = new ArrayList( - multiPathImpl.getPathCount() * 2); - for (int index = 1, n = m_pairIndices.size(); index < n; index++) { - int pairIndex = m_pairIndices.get(index); - int pair = m_pairs.get(pairIndex); - if ((pair & 1) != 0) - continue; - int xyindex = pair >> 1; - m_xy.read(2 * xyindex, pt); - int ipath = m_paths_for_OGC_tests.get(xyindex); - Vertex_info_pg vi = new Vertex_info_pg(pt.x, pt.y, ipath, xyindex, - ring_to_polygon[ipath]); - - if (vi.x == vi_prev.x && vi.y == vi_prev.y) { - if (vi.ipath == vi_prev.ipath) {// the ring has self tangency - m_nonSimpleResult = new NonSimpleResult( - NonSimpleResult.Reason.OGCPolygonSelfTangency, - vi.ivertex, vi_prev.ivertex); - return false; - } else if (ring_to_polygon[vi.ipath] >= 0 - && ring_to_polygon[vi.ipath] == ring_to_polygon[vi_prev.ipath]) {// only - // add - // rings - // from - // polygons - // with - // holes. - // Only - // interested - // in - // touching - // rings - // that - // belong - // to - // the - // same - // polygon - if (intersections.size() == 0 - || intersections.get(intersections.size() - 1) != vi_prev) - intersections.add(vi_prev); - intersections.add(vi); - } - } - - vi_prev = vi; - } - - if (intersections.size() == 0) - return true; - - // Find disconnected interior cases (OGC spec: Interior of polygon has - // to be a closed set) - - // Note: Now we'll reuse ring_to_polygon for different purpose - to - // store mapping from the rings to the graph nodes. - - IndexMultiDCList graph = new IndexMultiDCList(true); - Arrays.fill(ring_to_polygon, -1); - int vnode_index = -1; - Point2D prev = new Point2D(); - prev.setNaN(); - for (int i = 0, n = intersections.size(); i < n; i++) { - Vertex_info_pg cur = intersections.get(i); - if (cur.x != prev.x || cur.y != prev.y) { - vnode_index = graph.createList(0); - prev.x = cur.x; - prev.y = cur.y; - } - - int rnode_index = ring_to_polygon[cur.ipath]; - if (rnode_index == -1) { - rnode_index = graph.createList(2); - ring_to_polygon[cur.ipath] = rnode_index; - } - graph.addElement(rnode_index, vnode_index); // add to rnode - // adjacency list the - // current vnode - graph.addElement(vnode_index, rnode_index); // add to vnode - // adjacency list the - // rnode - } - - AttributeStreamOfInt32 depth_first_stack = new AttributeStreamOfInt32(0); - depth_first_stack.reserve(10); - - for (int node = graph.getFirstList(); node != -1; node = graph - .getNextList(node)) { - int ncolor = graph.getListData(node); - if ((ncolor & 1) != 0 || (ncolor & 2) == 0) - continue;// already visited or this is a vnode (we do not want - // to start from vnode). - - int bad_rnode = -1; - depth_first_stack.add(node); - depth_first_stack.add(-1);// parent - while (depth_first_stack.size() > 0) { - int cur_node_parent = depth_first_stack.getLast(); - depth_first_stack.removeLast(); - int cur_node = depth_first_stack.getLast(); - depth_first_stack.removeLast(); - int color = graph.getListData(cur_node); - if ((color & 1) != 0) { - // already visited this node. This means we found a loop. - if ((color & 2) == 0) {// closing on vnode - bad_rnode = cur_node_parent; - } else - bad_rnode = cur_node; - - // assert(bad_rnode != -1); - break; - } - - graph.setListData(cur_node, color | 1); - for (int adjacent_node = graph.getFirst(cur_node); adjacent_node != -1; adjacent_node = graph - .getNext(adjacent_node)) { - int adjacent_node_data = graph.getData(adjacent_node); - if (adjacent_node_data == cur_node_parent) - continue;// avoid going back to where we just came from - depth_first_stack.add(adjacent_node_data); - depth_first_stack.add(cur_node);// push cur_node as parent - // of adjacent_node - } - } - - if (bad_rnode != -1) { - int bad_ring_index = -1; - for (int i = 0, n = ring_to_polygon.length; i < n; i++) - if (ring_to_polygon[i] == bad_rnode) { - bad_ring_index = i; - break; - } - - // bad_ring_index is any ring in a problematic chain of touching - // rings. - // When chain of touching rings form a loop, the result is a - // disconnected interior, - // which is non-simple for OGC spec. - m_nonSimpleResult = new NonSimpleResult( - NonSimpleResult.Reason.OGCDisconnectedInterior, - bad_ring_index, -1); - return false; - } - } - - return true; - } - - private int checkValidRingOrientation_() { - MultiPathImpl multiPathImpl = (MultiPathImpl) m_geometry._getImpl(); - double totalArea = multiPathImpl.calculateArea2D(); - if (totalArea <= 0) { - m_nonSimpleResult = new NonSimpleResult( - NonSimpleResult.Reason.RingOrientation, - multiPathImpl.getPathCount() == 1 ? 1 : -1, -1); - return 0; - } - - if (multiPathImpl.getPathCount() == 1) {// optimization for a single - // polygon - if (m_bOGCRestrictions) { - if (!check_self_intersections_polygons_OGC_()) - return 0; - } - - return 2; - } - - // 1.Go through all vertices in the sorted order. - // 2.For each vertex,insert any non-horizontal segment that has the - // vertex as low point(there can be max two segments) - m_pathOrientations = new AttributeStreamOfInt32( - multiPathImpl.getPathCount(), 0); - - m_pathParentage = new AttributeStreamOfInt32( - multiPathImpl.getPathCount(), -1); - - int parent_ring = -1; - double exteriorArea = 0; - for (int ipath = 0, n = multiPathImpl.getPathCount(); ipath < n; ipath++) { - double area = multiPathImpl.calculateRingArea2D(ipath); - m_pathOrientations.write(ipath, area < 0 ? 0 : 256); // 8th bit - // is - // existing - // orientation - if (area > 0) { - parent_ring = ipath; - exteriorArea = area; - } else if (area == 0) { - m_nonSimpleResult = new NonSimpleResult( - NonSimpleResult.Reason.RingOrientation, ipath, -1); - return 0; - } else { - // area < 0: this is a hole. - // We write the parent exterior - // ring for it (assumed to be first previous exterior ring) - if (parent_ring < 0 || exteriorArea < Math.abs(area)) { - // The first ring is a hole - this is a wrong ring ordering. - // Or the hole's area is bigger than the previous exterior - // area - this means ring order is broken, - // because holes are always smaller. This is not the only - // condition when ring order is broken though. - m_nonSimpleResult = new NonSimpleResult( - NonSimpleResult.Reason.RingOrder, ipath, -1); - if (m_bOGCRestrictions) - return 0; - } - m_pathParentage.write(ipath, parent_ring); - } - } - - m_unknownOrientationPathCount = multiPathImpl.getPathCount(); - m_newEdges = new AttributeStreamOfInt32(0); - m_newEdges.reserve(10); - - int pointCount = multiPathImpl.getPointCount(); - m_yScanline = NumberUtils.TheNaN; - AttributeStreamOfInt32 bunch = new AttributeStreamOfInt32(0); // stores - // coincident - // vertices - bunch.reserve(10); - // Each vertex has two edges attached.These two arrays map vertices to - // edges as nodes in the m_AET - m_xyToNode1 = new AttributeStreamOfInt32(pointCount, Treap.nullNode()); - m_xyToNode2 = new AttributeStreamOfInt32(pointCount, Treap.nullNode()); - if (m_FreeEdges != null) - m_FreeEdges.clear(false); - else - m_FreeEdges = new AttributeStreamOfInt32(0); - m_FreeEdges.reserve(10); - - m_AET.clear(); - m_AET.setComparator(new RingOrientationTestComparator(this)); - for (int index = 0, n = pointCount * 2; m_unknownOrientationPathCount > 0 - && index < n; index++) { - int pairIndex = m_pairIndices.get(index); - int pair = m_pairs.get(pairIndex); - if ((pair & 1) != 0) - continue;// m_pairs array is redundant.See checkClustering_. - - int xyindex = pair >> 1; - double y = m_xy.read(2 * xyindex + 1); - - if (y != m_yScanline && bunch.size() != 0) { - if (!processBunchForRingOrientationTest_(bunch)) { - // m_nonSimpleResult is set in the - // processBunchForRingOrientationTest_ - return 0; - } - if (bunch != null) - bunch.clear(false); - } - - bunch.add(xyindex);// all vertices that have same y are added to the - // bunch - m_yScanline = y; - } - - if (m_unknownOrientationPathCount > 0 - && !processBunchForRingOrientationTest_(bunch)) { - // m_nonSimpleResult is set in the - // processBunchForRingOrientationTest_ - return 0; - } - - if (m_bOGCRestrictions) { - if (m_nonSimpleResult.m_reason != NonSimpleResult.Reason.NotDetermined) - return 0;// cannot proceed with OGC verification if the ring - // order is broken (cannot decide polygons then). - - if (!check_self_intersections_polygons_OGC_()) - return 0; - - return 2;// everything is good - } else { - if (m_nonSimpleResult.m_reason == NonSimpleResult.Reason.NotDetermined) - return 2;// everything is good - - // weak simple - return 1; - } - } - - private boolean processBunchForSelfIntersectionTest_( - AttributeStreamOfInt32 bunch) { - assert (bunch.size() > 0); - if (bunch.size() == 1) - return true; - - assert (m_edges.size() == 0); - - // Bunch contains vertices that have exactly same x and y. - // We populate m_edges array with the edges that originate in the - // vertices of the bunch. - for (int i = 0, n = bunch.size(); i < n; i++) { - int xyindex = bunch.get(i); - m_recycledSegIter.resetToVertex(xyindex);// the iterator is - // circular. - /* const */ - Segment seg1 = m_recycledSegIter.previousSegment(); - m_edges.add(createEdge_(seg1, xyindex, - m_recycledSegIter.getPathIndex(), true)); - m_recycledSegIter.nextSegment();// Need to skip one,because of the - // previousSegment call - // before (otherwise will get same segment again) - /* const */ - Segment seg2 = m_recycledSegIter.nextSegment(); - m_edges.add(createEdge_(seg2, xyindex, - m_recycledSegIter.getPathIndex(), false)); - } - - assert ((m_edges.size() & 1) == 0); // even size - - // Analyze the bunch edges for self intersections(the edges touch at the - // end points only at this stage of IsSimple) - // 1.sort the edges by angle between edge and the unit vector along axis - // x,using the cross product sign.Precondition:no overlaps occur at this - // stage. - - Collections.sort(m_edges, new EdgeComparerForSelfIntersection(this)); - - // 2.Analyze the bunch.There can be no edges between edges that share - // same vertex coordinates. - // We populate a doubly linked list with the edge indices and iterate - // over this list getting rid of the neighbouring pairs of vertices. - // The process is similar to peeling an onion. - // If the list becomes empty,there are no crossovers,otherwise,the - // geometry has cross-over. - int list = m_crossOverHelperList.getFirstList(); - - if (list == -1) - list = m_crossOverHelperList.createList(0); - - m_crossOverHelperList.reserveNodes(m_edges.size()); - - for (int i = 0, n = m_edges.size(); i < n; i++) { - m_crossOverHelperList.addElement(list, i); - } - - // Peel the onion - boolean bContinue = true; - int i1 = -1; - int i2 = -1; - while (bContinue) { - bContinue = false; - int listnode = m_crossOverHelperList.getFirst(list); - if (listnode == -1) - break; - - int nextnode = m_crossOverHelperList.getNext(listnode); - while (nextnode != -1) { - int edgeindex1 = m_crossOverHelperList.getData(listnode); - int edgeindex2 = m_crossOverHelperList.getData(nextnode); - i1 = m_edges.get(edgeindex1).m_vertexIndex; - i2 = m_edges.get(edgeindex2).m_vertexIndex; - if (i1 == i2) { - bContinue = true; - m_crossOverHelperList.deleteElement(list, listnode); - listnode = m_crossOverHelperList.getPrev(nextnode); - nextnode = m_crossOverHelperList.deleteElement(list, - nextnode); - if (nextnode == -1 || listnode == -1) - break; - else - continue; - } - listnode = nextnode; - nextnode = m_crossOverHelperList.getNext(listnode); - } - } - - int listSize = m_crossOverHelperList.getListSize(list); - m_crossOverHelperList.clear(list); - if (listSize > 0) { - // There is self-intersection here. - m_nonSimpleResult = new NonSimpleResult( - NonSimpleResult.Reason.CrossOver, i1, i2); - return false; - } - - // Recycle the bunch to save on object creation - for (int i = 0, n = bunch.size(); i < n; i++) { - recycleEdge_(m_edges.get(i)); - } - - m_edges.clear(); - return true; - } - - private boolean processBunchForRingOrientationTest_( - AttributeStreamOfInt32 bunch) { - m_dbgCounter++; - assert (bunch.size() > 0); - - // remove nodes that go out of scope - for (int i = 0, n = bunch.size(); i < n; i++) { - int xyindex = bunch.get(i); - int aetNode = m_xyToNode1.read(xyindex); - if (aetNode != Treap.nullNode()) {// We found that there is an edge - // in AET, attached to the - // xyindex vertex. This edge - // goes out of scope. Delete it - // from AET. - int edgeIndex = m_AET.getElement(aetNode); - m_FreeEdges.add(edgeIndex); - m_AET.deleteNode(aetNode, -1); - recycleEdge_(m_edges.get(edgeIndex)); - m_edges.set(edgeIndex, null); - m_xyToNode1.write(xyindex, Treap.nullNode()); - } - - aetNode = m_xyToNode2.read(xyindex); - if (aetNode != Treap.nullNode()) {// We found that there is an edge - // in AET, attached to the - // xyindex vertex. This edge - // goes out of scope. Delete it - // from AET. - int edgeIndex = m_AET.getElement(aetNode); - m_FreeEdges.add(edgeIndex); - m_AET.deleteNode(aetNode, -1); - recycleEdge_(m_edges.get(edgeIndex)); - m_edges.set(edgeIndex, null); - m_xyToNode2.write(xyindex, Treap.nullNode()); - } - } - - // add new edges to AET - for (int i = 0, n = bunch.size(); i < n; i++) { - int xyindex = bunch.get(i); - m_recycledSegIter.resetToVertex(xyindex);// the iterator is - // circular. - Segment seg1 = m_recycledSegIter.previousSegment();// this - // segment - // has - // end - // point - // at - // xyindex - if (seg1.getStartY() > seg1.getEndY())// do not allow horizontal - // segments in here - { - // get the top vertex index.We use it to determine what segments - // to get rid of. - int edgeTopIndex = m_recycledSegIter.getStartPointIndex(); - Edge edge = createEdge_(seg1, xyindex, - m_recycledSegIter.getPathIndex(), true); - int edgeIndex; - if (m_FreeEdges.size() > 0) { - edgeIndex = m_FreeEdges.getLast(); - m_FreeEdges.removeLast(); - m_edges.set(edgeIndex, edge); - } else { - edgeIndex = m_edges.size(); - m_edges.add(edge); - } - - int aetNode = m_AET.addElement(edgeIndex, -1); - // Remember AET nodes in the vertex to AET node maps. - if (m_xyToNode1.read(edgeTopIndex) == Treap.nullNode()) - m_xyToNode1.write(edgeTopIndex, aetNode); - else { - assert (m_xyToNode2.read(edgeTopIndex) == Treap.nullNode()); - m_xyToNode2.write(edgeTopIndex, aetNode); - } - - // If this edge belongs to a path that has not have direction - // figured out yet, - // add it to m_newEdges for post processing - if ((m_pathOrientations.read(m_recycledSegIter.getPathIndex()) & 3) == 0) - m_newEdges.add(aetNode); - } - - m_recycledSegIter.nextSegment();// Need to skip one,because of the - // previousSegment call - // before(otherwise will get same - // segment again) - // seg1 is invalid now - Segment seg2 = m_recycledSegIter.nextSegment(); - // start has to be lower than end for this one - if (seg2.getStartY() < seg2.getEndY())// do not allow horizontal - // segments in here - { - // get the top vertex index.We use it to determine what segments - // to get rid of. - int edgeTopIndex = m_recycledSegIter.getEndPointIndex(); - Edge edge = createEdge_(seg2, xyindex, - m_recycledSegIter.getPathIndex(), false); - int edgeIndex; - if (m_FreeEdges.size() > 0) { - edgeIndex = m_FreeEdges.getLast(); - m_FreeEdges.removeLast(); - m_edges.set(edgeIndex, edge); - } else { - edgeIndex = m_edges.size(); - m_edges.add(edge); - } - - int aetNode = m_AET.addElement(edgeIndex, -1); - if (m_xyToNode1.read(edgeTopIndex) == Treap.nullNode()) - m_xyToNode1.write(edgeTopIndex, aetNode); - else { - assert (m_xyToNode2.read(edgeTopIndex) == Treap.nullNode()); - m_xyToNode2.write(edgeTopIndex, aetNode); - } - - // If this edge belongs to a path that has not have direction - // figured out yet, - // add it to m_newEdges for post processing - if ((m_pathOrientations.read(m_recycledSegIter.getPathIndex()) & 3) == 0) - m_newEdges.add(aetNode); - } - } - - for (int i = 0, n = m_newEdges.size(); i < n - && m_unknownOrientationPathCount > 0; i++) { - int aetNode = m_newEdges.get(i); - int edgeIndexInitial = m_AET.getElement(aetNode); - Edge edgeInitial = m_edges.get(edgeIndexInitial); - int pathIndexInitial = edgeInitial.m_pathIndex; - int directionInitial = m_pathOrientations.read(pathIndexInitial); - if ((directionInitial & 3) == 0) { - int prevExteriorPath = -1; - int node = m_AET.getPrev(aetNode); - int prevNode = aetNode; - int oddEven = 0; - {// scope - int edgeIndex = -1; - Edge edge = null; - int pathIndex = -1; - int dir = 0; - // find the leftmost edge for which the ring orientation is - // known - while (node != Treap.nullNode()) { - edgeIndex = m_AET.getElement(node); - edge = m_edges.get(edgeIndex); - pathIndex = edge.m_pathIndex; - dir = m_pathOrientations.read(pathIndex); - if ((dir & 3) != 0) - break; - - prevNode = node; - node = m_AET.getPrev(node); - } - - if (node == Treap.nullNode()) {// if no edges have ring - // orientation known, then - // start - // from the left most and it - // has - // to be exterior ring. - oddEven = 1; - node = prevNode; - } else { - if ((dir & 3) == 1) { - prevExteriorPath = pathIndex; - } else { - prevExteriorPath = m_pathParentage.read(pathIndex); - } - - oddEven = (edge.getRightSide() != 0) ? 0 : 1; - node = m_AET.getNext(node); - } - } - - do { - int edgeIndex = m_AET.getElement(node); - Edge edge = m_edges.get(edgeIndex); - int pathIndex = edge.m_pathIndex; - int direction = m_pathOrientations.read(pathIndex); - if ((direction & 3) == 0) { - if (oddEven != edge.getRightSide()) { - m_nonSimpleResult = new NonSimpleResult( - NonSimpleResult.Reason.RingOrientation, - pathIndex, -1); - return false;// wrong ring orientation - } - - int dir = (oddEven != 0 && !edge.getReversed()) ? 1 : 2; - direction = (direction & 0xfc) | dir; - m_pathOrientations.write(pathIndex, dir); - if (dir == 2 - && m_nonSimpleResult.m_reason == NonSimpleResult.Reason.NotDetermined) { - // check that this hole has a correct parent - // exterior ring. - int parent = m_pathParentage.read(pathIndex); - if (parent != prevExteriorPath) { - m_nonSimpleResult = new NonSimpleResult( - NonSimpleResult.Reason.RingOrder, - pathIndex, -1); - if (m_bOGCRestrictions) - return false; - } - } - - m_unknownOrientationPathCount--; - if (m_unknownOrientationPathCount == 0)// if(!m_unknownOrientationPathCount) - return true; - } - - if ((direction & 3) == 1) { - prevExteriorPath = pathIndex; - } - - prevNode = node; - node = m_AET.getNext(node); - oddEven = oddEven != 0 ? 0 : 1; - } while (prevNode != aetNode); - } - } - - if (m_newEdges != null) - m_newEdges.clear(false); - else - m_newEdges = new AttributeStreamOfInt32(0); - return true; - } - - private Edge createEdge_(/* const */Segment seg, int xyindex, int pathIndex, - boolean bReversed) { - Edge edge; - Geometry.Type gt = seg.getType(); - if (gt == Geometry.Type.Line) { - edge = createEdgeLine_(seg); - } else { - throw GeometryException.GeometryInternalError(); // implement - // recycling for - // curves - } - edge.m_vertexIndex = xyindex; - edge.m_pathIndex = pathIndex; - edge.m_flags = 0; - edge.setReversed(bReversed); - - return edge; - } - - private Edge createEdgeLine_(/* const */Segment seg) { - Edge edge = null; - if (m_lineEdgesRecycle.size() > 0) { - int indexLast = m_lineEdgesRecycle.size() - 1; - edge = m_lineEdgesRecycle.get(indexLast); - m_lineEdgesRecycle.remove(indexLast); - seg.copyTo(edge.m_segment); - } else { - edge = new Edge(); - edge.m_segment = (Segment) Segment._clone(seg); - } - - return edge; - } - - private void recycleEdge_(/* const */Edge edge) { - Geometry.Type gt = edge.m_segment.getType(); - if (gt == Geometry.Type.Line) { - m_lineEdgesRecycle.add(edge); - } - } - - private static final class ClusterTestComparator extends Treap.Comparator { - OperatorSimplifyLocalHelper m_helper; - - ClusterTestComparator(OperatorSimplifyLocalHelper helper) { - m_helper = helper; - } - - @Override - int compare(/* const */Treap treap, int xy1, int node) { - int xy2 = treap.getElement(node); - double x1 = m_helper.m_xy.read(2 * xy1); - double x2 = m_helper.m_xy.read(2 * xy2); - double dx = x1 - x2; - return dx < 0 ? -1 : (dx > 0 ? 1 : 0); - } - } - - private static final class RingOrientationTestComparator extends - Treap.Comparator { - private OperatorSimplifyLocalHelper m_helper; - - RingOrientationTestComparator(OperatorSimplifyLocalHelper helper) { - m_helper = helper; - } - - @Override - int compare(/* const */Treap treap, int left, int node) { - int right = treap.getElement(node); - Edge edge1 = m_helper.m_edges.get(left); - Edge edge2 = m_helper.m_edges.get(right); - boolean bEdge1Reversed = edge1.getReversed(); - boolean bEdge2Reversed = edge2.getReversed(); - - double x1 = edge1.m_segment.intersectionOfYMonotonicWithAxisX( - m_helper.m_yScanline, 0); - double x2 = edge2.m_segment.intersectionOfYMonotonicWithAxisX( - m_helper.m_yScanline, 0); - - if (x1 == x2) { - // apparently these edges originate from same vertex and the - // scanline is on the vertex.move scanline a little. - double y1 = bEdge1Reversed ? edge1.m_segment.getStartY() - : edge1.m_segment.getEndY(); - double y2 = bEdge2Reversed ? edge2.m_segment.getStartY() - : edge2.m_segment.getEndY(); - double miny = Math.min(y1, y2); - double y = (miny - m_helper.m_yScanline) * 0.5 - + m_helper.m_yScanline; - if (y == m_helper.m_yScanline) { - // assert(0); //ST: not a bug. just curious to see this - // happens. - y = miny; // apparently, one of the segments is almost - // horizontal line. - } - x1 = edge1.m_segment.intersectionOfYMonotonicWithAxisX(y, 0); - x2 = edge2.m_segment.intersectionOfYMonotonicWithAxisX(y, 0); - assert (x1 != x2); - } - - return x1 < x2 ? -1 : (x1 > x2 ? 1 : 0); - } - } - - int multiPointIsSimpleAsFeature_() { - MultiVertexGeometryImpl multiVertexImpl = (MultiVertexGeometryImpl) m_geometry - ._getImpl(); - // sort lexicographically: by y,then by x, then by other attributes in - // the order. - // Go through the sorted list and make sure no points coincide exactly - // (no tolerance is taken into account). - int pointCount = multiVertexImpl.getPointCount(); - - AttributeStreamOfInt32 indices = new AttributeStreamOfInt32(0); - - for (int i = 0; i < pointCount; i++) { - indices.add(i); - } - - indices.Sort(0, pointCount, new MultiPointVertexComparer(this)); - - for (int i = 1; i < pointCount; i++) { - if (compareVerticesMultiPoint_(indices.get(i - 1), indices.get(i)) == 0) { - m_nonSimpleResult = new NonSimpleResult( - NonSimpleResult.Reason.Clustering, indices.get(i - 1), - indices.get(i)); - return 0;// points are coincident-simplify. - } - } - - return 2; - } - - int polylineIsSimpleAsFeature_() { - if (!checkStructure_()) - return 0; - // Non planar IsSimple. - // Go through all line segments and make sure no line segments are - // degenerate. - // Degenerate segment is the one which has its length shorter than - // tolerance or Z projection shorter than z tolerance. - return checkDegenerateSegments_(true) ? 2 : 0; - } - - int polygonIsSimpleAsFeature_() { - return isSimplePlanarImpl_(); - } - - MultiPoint multiPointSimplifyAsFeature_() { - MultiVertexGeometryImpl multiVertexImpl = (MultiVertexGeometryImpl) m_geometry - ._getImpl(); - // sort lexicographically:by y,then by x,then by other attributes in the - // order. - int pointCount = multiVertexImpl.getPointCount(); - assert (pointCount > 0); - - AttributeStreamOfInt32 indices = new AttributeStreamOfInt32(0); - - for (int i = 0; i < pointCount; i++) { - indices.add(i); - } - - indices.Sort(0, pointCount, new MultiPointVertexComparer2(this)); - - // Mark vertices that are unique - boolean[] indicesOut = new boolean[pointCount]; - - indicesOut[indices.get(0)] = true; - - for (int i = 1; i < pointCount; i++) { - int ind1 = indices.get(i - 1); - int ind2 = indices.get(i); - if (compareVerticesMultiPoint_(ind1, ind2) == 0) { - indicesOut[ind2] = false; - continue; - } - - indicesOut[ind2] = true; - } - - // get rid of non-unique vertices. - // We preserve the order of MultiPoint vertices.Among duplicate - // vertices,those that have - // higher index are deleted. - MultiPoint dst = (MultiPoint) m_geometry.createInstance(); - MultiPoint src = (MultiPoint) m_geometry; - int istart = 0; - int iend = 1; - for (int i = 0; i < pointCount; i++) { - if (indicesOut[i]) - iend = i + 1; - else { - if (istart < iend) { - dst.add(src, istart, iend); - } - - istart = i + 1; - } - } - - if (istart < iend) { - dst.add(src, istart, iend); - } - - ((MultiVertexGeometryImpl) dst._getImpl()).setIsSimple( - GeometryXSimple.Strong, m_toleranceSimplify, false); - return dst; - } - - Polyline polylineSimplifyAsFeature_() { - // Non planar simplify. - // Go through all line segments and make sure no line segments are - // degenerate. - // Degenerate segment is the one which has its length shorter than - // tolerance or Z projection shorter than z tolerance. - // The algorithm processes each path symmetrically from each end to - // ensure the result of simplify does not depend on the direction of the - // path. - - MultiPathImpl multiPathImpl = (MultiPathImpl) m_geometry._getImpl(); - SegmentIteratorImpl segIterFwd = multiPathImpl.querySegmentIterator(); - SegmentIteratorImpl segIterBwd = multiPathImpl.querySegmentIterator(); - Polyline dst = (Polyline) m_geometry.createInstance(); - Polyline src = (Polyline) m_geometry; - // Envelope2D env2D; - boolean bHasZ = multiPathImpl - .hasAttribute(VertexDescription.Semantics.Z); - double ztolerance = !bHasZ ? 0.0 : InternalUtils - .calculateZToleranceFromGeometry(m_sr, multiPathImpl, true); - AttributeStreamOfInt32 fwdStack = new AttributeStreamOfInt32(0); - AttributeStreamOfInt32 bwdStack = new AttributeStreamOfInt32(0); - fwdStack.reserve(multiPathImpl.getPointCount() / 2 + 1); - bwdStack.reserve(multiPathImpl.getPointCount() / 2 + 1); - while (segIterFwd.nextPath()) { - segIterBwd.nextPath(); - if (multiPathImpl.getPathSize(segIterFwd.getPathIndex()) < 2) - continue; - - segIterBwd.resetToLastSegment(); - double lengthFwd = 0; - double lengthBwd = 0; - boolean bFirst = true; - while (segIterFwd.hasNextSegment()) { - assert (segIterBwd.hasPreviousSegment()); - - /* const */ - Segment segFwd = segIterFwd.nextSegment(); - /* const */ - Segment segBwd = segIterBwd.previousSegment(); - - int idx1 = segIterFwd.getStartPointIndex(); - int idx2 = segIterBwd.getStartPointIndex(); - if (idx1 > idx2) - break; - - if (bFirst) { - // add the very first and the very last point indices - fwdStack.add(segIterFwd.getStartPointIndex());// first goes - // to - // fwdStack - bwdStack.add(segIterBwd.getEndPointIndex());// last goes to - // bwdStack - bFirst = false; - } - - { - int index0 = fwdStack.getLast(); - int index1 = segIterFwd.getEndPointIndex(); - if (index1 - index0 > 1) { - Point2D pt = new Point2D(); - pt.sub(multiPathImpl.getXY(index0), - multiPathImpl.getXY(index1)); - lengthFwd = pt.length(); - } else { - lengthFwd = segFwd.calculateLength2D(); - } - } - - { - int index0 = bwdStack.getLast(); - int index1 = segIterBwd.getStartPointIndex(); - if (index1 - index0 > 1) { - Point2D pt = new Point2D(); - pt.sub(multiPathImpl.getXY(index0), - multiPathImpl.getXY(index1)); - lengthBwd = pt.length(); - } else { - lengthBwd = segBwd.calculateLength2D(); - } - } - - if (lengthFwd > m_toleranceSimplify) { - fwdStack.add(segIterFwd.getEndPointIndex()); - lengthFwd = 0; - } else { - if (bHasZ) { - double z0 = multiPathImpl.getAttributeAsDbl( - VertexDescription.Semantics.Z, - fwdStack.getLast(), 0); - double z1 = segFwd.getEndAttributeAsDbl( - VertexDescription.Semantics.Z, 0); - if (Math.abs(z1 - z0) > ztolerance) { - fwdStack.add(segIterFwd.getEndPointIndex()); - lengthFwd = 0; - } - } - } - - if (lengthBwd > m_toleranceSimplify) { - bwdStack.add(segIterBwd.getStartPointIndex()); - lengthBwd = 0; - } else { - if (bHasZ) { - double z0 = multiPathImpl.getAttributeAsDbl( - VertexDescription.Semantics.Z, - bwdStack.getLast(), 0); - double z1 = segBwd.getEndAttributeAsDbl( - VertexDescription.Semantics.Z, 0); - if (Math.abs(z1 - z0) > ztolerance) { - bwdStack.add(segIterBwd.getStartPointIndex()); - lengthBwd = 0; - } - } - } - } - - // assert(fwdStack.getLast() <= bwdStack.getLast()); - if (fwdStack.getLast() < bwdStack.getLast()) { - // There is degenerate segment in the middle. Remove. - // If the path degenerate, this will make fwdStack.size() + - // bwdStack.size() < 2. - if (fwdStack.size() > bwdStack.size()) - fwdStack.removeLast(); - else - bwdStack.removeLast(); - } else if (fwdStack.getLast() == bwdStack.getLast()) { - bwdStack.removeLast(); - } else { - assert (fwdStack.getLast() - bwdStack.getLast() == 1); - bwdStack.removeLast(); - bwdStack.removeLast(); - } - - if (bwdStack.size() + fwdStack.size() >= 2) { - // Completely ignore the curves for now. - Point point = new Point(); - for (int i = 0, n = fwdStack.size(); i < n; i++) { - src.getPointByVal(fwdStack.get(i), point); - if (i == 0) - dst.startPath(point); - else - dst.lineTo(point); - } - - // int prevIdx = fwdStack.getLast(); - for (int i = bwdStack.size() - 1; i > 0; i--) { - src.getPointByVal(bwdStack.get(i), point); - dst.lineTo(point); - } - - if (src.isClosedPath(segIterFwd.getPathIndex())) { - dst.closePathWithLine(); - } else { - if (bwdStack.size() > 0) { - src.getPointByVal(bwdStack.get(0), point); - dst.lineTo(point); - } - } - } else { - // degenerate path won't be added - } - - if (fwdStack != null) - fwdStack.clear(false); - if (bwdStack != null) - bwdStack.clear(false); - } - - ((MultiVertexGeometryImpl) dst._getImpl()).setIsSimple( - GeometryXSimple.Strong, m_toleranceSimplify, false); - return dst; - } - - Polygon polygonSimplifyAsFeature_() { - return (Polygon) simplifyPlanar_(); - } - - MultiVertexGeometry simplifyPlanar_() { - // do clustering/cracking loop - // if (false) - // { - // ((MultiPathImpl)m_geometry._getImpl()).saveToTextFileDbg("c:/temp/_simplifyDbg0.txt"); - // } - - if (m_geometry.getType() == Geometry.Type.Polygon) { - if (((Polygon) m_geometry).getFillRule() == Polygon.FillRule.enumFillRuleWinding) { - // when the fill rule is winding, we need to call a special - // method. - return TopologicalOperations.planarSimplify( - (MultiVertexGeometry) m_geometry, m_toleranceSimplify, - true, false, m_progressTracker); - } - } - - m_editShape = new EditShape(); - m_editShape.addGeometry(m_geometry); - - if (m_editShape.getTotalPointCount() != 0) { - assert (m_knownSimpleResult != GeometryXSimple.Strong); - if (m_knownSimpleResult != GeometryXSimple.Weak) { - CrackAndCluster.execute(m_editShape, m_toleranceSimplify, - m_progressTracker, true); - } - - if (m_geometry.getType().equals(Geometry.Type.Polygon)) { - Simplificator.execute(m_editShape, m_editShape.getFirstGeometry(), - m_knownSimpleResult, false, m_progressTracker); - } - } - - m_geometry = m_editShape.getGeometry(m_editShape.getFirstGeometry()); // extract - // the - // result - // of - // simplify - - if (m_geometry.getType().equals(Geometry.Type.Polygon)) { - ((MultiPathImpl) m_geometry._getImpl())._updateOGCFlags(); - ((Polygon) m_geometry).setFillRule(Polygon.FillRule.enumFillRuleOddEven); - } - - // We have simplified the geometry using the given tolerance. Now mark - // the geometry as strong simple, - // So that the next call will not have to repeat these steps. - - ((MultiVertexGeometryImpl) m_geometry._getImpl()).setIsSimple( - GeometryXSimple.Strong, m_toleranceSimplify, false); - - return (MultiVertexGeometry) (m_geometry); - } - - NonSimpleResult m_nonSimpleResult; - - OperatorSimplifyLocalHelper(Geometry geometry, - SpatialReference spatialReference, int knownSimpleResult, - ProgressTracker progressTracker, boolean bOGCRestrictions) { - - m_description = geometry.getDescription(); - m_geometry = geometry; - m_sr = (SpatialReferenceImpl) spatialReference; - m_dbgCounter = 0; - m_toleranceIsSimple = InternalUtils.calculateToleranceFromGeometry( - m_sr, geometry, false); - m_toleranceSimplify = InternalUtils.calculateToleranceFromGeometry( - m_sr, geometry, true); - // m_toleranceCluster = m_toleranceSimplify * Math.sqrt(2.0) * 1.00001; - m_knownSimpleResult = knownSimpleResult; - m_attributeCount = m_description.getAttributeCount(); - m_edges = new ArrayList(); - m_lineEdgesRecycle = new ArrayList(); - m_crossOverHelperList = new IndexMultiDCList(); - m_AET = new Treap(); - m_nonSimpleResult = new NonSimpleResult(); - m_bOGCRestrictions = bOGCRestrictions; - m_bPlanarSimplify = m_bOGCRestrictions; - } - - // Returns 0 non-simple, 1 weak simple, 2 strong simple - - /** - * The code is executed in the 2D plane only.Attributes are ignored. - * MultiPoint-check for clustering. Polyline -check for clustering and - * cracking. Polygon -check for clustering,cracking,absence of - * self-intersections,and correct ring ordering. - */ - static protected int isSimplePlanar(/* const */Geometry geometry, /* const */ - SpatialReference spatialReference, boolean bForce, - ProgressTracker progressTracker) { - assert (false); // this code is not called yet. - if (geometry.isEmpty()) - return 1; - Geometry.Type gt = geometry.getType(); - if (gt == Geometry.Type.Point) - return 1; - else if (gt == Geometry.Type.Envelope) { - Envelope2D env2D = new Envelope2D(); - geometry.queryEnvelope2D(env2D); - boolean bReturnValue = !env2D.isDegenerate(InternalUtils - .calculateToleranceFromGeometry(spatialReference, geometry, - false)); - return bReturnValue ? 1 : 0; - } else if (Geometry.isSegment(gt.value())) { - throw GeometryException.GeometryInternalError(); - // return seg.IsSimple(m_tolerance); - } else if (!Geometry.isMultiVertex(gt.value())) { - throw GeometryException.GeometryInternalError();// What else? - } - - double tolerance = InternalUtils.calculateToleranceFromGeometry( - spatialReference, geometry, false); - - double geomTolerance = 0; - int isSimple = ((MultiVertexGeometryImpl) geometry._getImpl()) - .getIsSimple(tolerance); - int knownSimpleResult = bForce ? -1 : isSimple; - // TODO: need to distinguish KnownSimple between SimpleAsFeature and - // SimplePlanar. The SimplePlanar implies SimpleAsFeature. - if (knownSimpleResult != -1) - return knownSimpleResult; - - if (knownSimpleResult == GeometryXSimple.Weak) { - assert (tolerance <= geomTolerance); - tolerance = geomTolerance;// OVERRIDE the tolerance. - } - - OperatorSimplifyLocalHelper helper = new OperatorSimplifyLocalHelper( - geometry, spatialReference, knownSimpleResult, progressTracker, - false); - knownSimpleResult = helper.isSimplePlanarImpl_(); - ((MultiVertexGeometryImpl) geometry._getImpl()).setIsSimple( - knownSimpleResult, tolerance, false); - return knownSimpleResult; - } - - /** - * Checks if Geometry is simple for storing in DB: - *

- * MultiPoint:check that no points coincide.tolerance is ignored. - * Polyline:ensure there no segments degenerate segments. Polygon:Same as - * IsSimplePlanar. - */ - static protected int isSimpleAsFeature(/* const */Geometry geometry, /* const */ - SpatialReference spatialReference, boolean bForce, NonSimpleResult result, - ProgressTracker progressTracker) { - if (result != null) { - result.m_reason = NonSimpleResult.Reason.NotDetermined; - result.m_vertexIndex1 = -1; - result.m_vertexIndex2 = -1; - } - if (geometry.isEmpty()) - return 1; - Geometry.Type gt = geometry.getType(); - if (gt == Geometry.Type.Point) - return 1; - - double tolerance = InternalUtils.calculateToleranceFromGeometry( - spatialReference, geometry, false); - if (gt == Geometry.Type.Envelope) { - /* const */ - Envelope env = (Envelope) geometry; - Envelope2D env2D = new Envelope2D(); - env.queryEnvelope2D(env2D); - if (env2D.isDegenerate(tolerance)) { - if (result != null) { - result.m_reason = NonSimpleResult.Reason.DegenerateSegments; - result.m_vertexIndex1 = -1; - result.m_vertexIndex2 = -1; - } - return 0; - } - return 1; - } else if (Geometry.isSegment(gt.value())) { - /* const */ - Segment seg = (Segment) geometry; - Polyline polyline = new Polyline(seg.getDescription()); - polyline.addSegment(seg, true); - return isSimpleAsFeature(polyline, spatialReference, bForce, - result, progressTracker); - } - - // double geomTolerance = 0; - int isSimple = ((MultiVertexGeometryImpl) geometry._getImpl()) - .getIsSimple(tolerance); - int knownSimpleResult = bForce ? -1 : isSimple; - // TODO: need to distinguish KnownSimple between SimpleAsFeature and - // SimplePlanar. - // From the first sight it seems the SimplePlanar implies - // SimpleAsFeature. - if (knownSimpleResult != -1) - return knownSimpleResult; - - OperatorSimplifyLocalHelper helper = new OperatorSimplifyLocalHelper( - geometry, spatialReference, knownSimpleResult, progressTracker, - false); - - if (gt == Geometry.Type.MultiPoint) { - knownSimpleResult = helper.multiPointIsSimpleAsFeature_(); - } else if (gt == Geometry.Type.Polyline) { - knownSimpleResult = helper.polylineIsSimpleAsFeature_(); - } else if (gt == Geometry.Type.Polygon) { - knownSimpleResult = helper.polygonIsSimpleAsFeature_(); - } else { - throw GeometryException.GeometryInternalError();// what else? - } - - ((MultiVertexGeometryImpl) (geometry._getImpl())).setIsSimple( - knownSimpleResult, tolerance, false); - if (result != null && knownSimpleResult == 0) - result.Assign(helper.m_nonSimpleResult); - return knownSimpleResult; - } - - static int isSimpleOGC(/* const */Geometry geometry, /* const */ - SpatialReference spatialReference, boolean bForce, NonSimpleResult result, - ProgressTracker progressTracker) { - if (result != null) { - result.m_reason = NonSimpleResult.Reason.NotDetermined; - result.m_vertexIndex1 = -1; - result.m_vertexIndex2 = -1; - } - if (geometry.isEmpty()) - return 1; - Geometry.Type gt = geometry.getType(); - if (gt == Geometry.Type.Point) - return 1; - - double tolerance = InternalUtils.calculateToleranceFromGeometry( - spatialReference, geometry, false); - if (gt == Geometry.Type.Envelope) { - /* const */ - Envelope env = (Envelope) geometry; - Envelope2D env2D = new Envelope2D(); - env.queryEnvelope2D(env2D); - if (env2D.isDegenerate(tolerance)) { - if (result != null) { - result.m_reason = NonSimpleResult.Reason.DegenerateSegments; - result.m_vertexIndex1 = -1; - result.m_vertexIndex2 = -1; - } - return 0; - } - return 1; - } else if (Geometry.isSegment(gt.value())) { - /* const */ - Segment seg = (Segment) geometry; - Polyline polyline = new Polyline(seg.getDescription()); - polyline.addSegment(seg, true); - return isSimpleAsFeature(polyline, spatialReference, bForce, - result, progressTracker); - } - - int knownSimpleResult = -1; - - OperatorSimplifyLocalHelper helper = new OperatorSimplifyLocalHelper( - geometry, spatialReference, knownSimpleResult, progressTracker, - true); - - if (gt == Geometry.Type.MultiPoint || gt == Geometry.Type.Polyline - || gt == Geometry.Type.Polygon) { - knownSimpleResult = helper.isSimplePlanarImpl_(); - } else { - throw GeometryException.GeometryInternalError();// what else? - } - - if (result != null) - result.Assign(helper.m_nonSimpleResult); - - return knownSimpleResult; - } - - /** - * Simplifies geometries for storing in DB: - *

- * MultiPoint:check that no points coincide.tolerance is ignored. - * Polyline:ensure there no segments degenerate segments. Polygon:cracks and - * clusters using cluster tolerance and resolves all self intersections, - * orients rings properly and arranges the rings in the OGC order. - *

- * Returns simplified geometry. - */ - static protected Geometry simplifyAsFeature(/* const */Geometry geometry, /* const */ - SpatialReference spatialReference, boolean bForce, - ProgressTracker progressTracker) { - if (geometry.isEmpty()) - return geometry; - Geometry.Type gt = geometry.getType(); - if (gt == Geometry.Type.Point) - return geometry; - - double tolerance = InternalUtils.calculateToleranceFromGeometry( - spatialReference, geometry, false); - if (gt == Geometry.Type.Envelope) { - Envelope env = (Envelope) geometry; - Envelope2D env2D = new Envelope2D(); - env.queryEnvelope2D(env2D); - if (env2D.isDegenerate(tolerance)) { - return (Geometry) (env.createInstance()); // return empty - // geometry - } - return geometry; - } else if (Geometry.isSegment(gt.value())) { - Segment seg = (Segment) geometry; - Polyline polyline = new Polyline(seg.getDescription()); - polyline.addSegment(seg, true); - return simplifyAsFeature(polyline, spatialReference, bForce, - progressTracker); - } - - double geomTolerance = 0; - int isSimple = ((MultiVertexGeometryImpl) geometry._getImpl()) - .getIsSimple(tolerance); - int knownSimpleResult = bForce ? GeometryXSimple.Unknown : isSimple; - - // TODO: need to distinguish KnownSimple between SimpleAsFeature and - // SimplePlanar. - // From the first sight it seems the SimplePlanar implies - // SimpleAsFeature. - if (knownSimpleResult == GeometryXSimple.Strong) { - if (gt == Geometry.Type.Polygon && ((Polygon) geometry).getFillRule() != Polygon.FillRule.enumFillRuleOddEven) { - Geometry res = geometry.copy(); - ((Polygon) res).setFillRule(Polygon.FillRule.enumFillRuleOddEven);//standardize on odd_even fill rule - return res; - } - - return geometry; - } - - OperatorSimplifyLocalHelper helper = new OperatorSimplifyLocalHelper( - geometry, spatialReference, knownSimpleResult, progressTracker, - false); - - Geometry result; - - if (gt == Geometry.Type.MultiPoint) { - result = (Geometry) (helper.multiPointSimplifyAsFeature_()); - } else if (gt == Geometry.Type.Polyline) { - result = (Geometry) (helper.polylineSimplifyAsFeature_()); - } else if (gt == Geometry.Type.Polygon) { - result = (Geometry) (helper.polygonSimplifyAsFeature_()); - } else { - throw GeometryException.GeometryInternalError(); // what else? - } - - return result; - } - - /** - * Simplifies geometries for storing in OGC format: - *

- * MultiPoint:check that no points coincide.tolerance is ignored. - * Polyline:ensure there no segments degenerate segments. Polygon:cracks and - * clusters using cluster tolerance and resolves all self intersections, - * orients rings properly and arranges the rings in the OGC order. - *

- * Returns simplified geometry. - */ - static Geometry simplifyOGC(/* const */Geometry geometry, /* const */ - SpatialReference spatialReference, boolean bForce, - ProgressTracker progressTracker) { - if (geometry.isEmpty()) - return geometry; - Geometry.Type gt = geometry.getType(); - if (gt == Geometry.Type.Point) - return geometry; - - double tolerance = InternalUtils.calculateToleranceFromGeometry( - spatialReference, geometry, false); - if (gt == Geometry.Type.Envelope) { - Envelope env = (Envelope) geometry; - Envelope2D env2D = new Envelope2D(); - env.queryEnvelope2D(env2D); - if (env2D.isDegenerate(tolerance)) { - return (Geometry) (env.createInstance()); // return empty - // geometry - } - return geometry; - } else if (Geometry.isSegment(gt.value())) { - Segment seg = (Segment) geometry; - Polyline polyline = new Polyline(seg.getDescription()); - polyline.addSegment(seg, true); - return simplifyOGC(polyline, spatialReference, bForce, - progressTracker); - } - - if (!Geometry.isMultiVertex(gt.value())) { - throw new GeometryException("OGC simplify is not implemented for this geometry type" + gt); - } - - MultiVertexGeometry result = TopologicalOperations.simplifyOGC( - (MultiVertexGeometry) geometry, tolerance, false, progressTracker); - - return result; - } - - private int compareVertices_(int i1, int i2, boolean get_paths) { - if (i1 == i2) - return 0; - - int pair1 = m_pairs.get(i1); - int pair2 = m_pairs.get(i2); - int xy1 = pair1 >> 1; - int xy2 = pair2 >> 1; - Point2D pt1 = new Point2D(); - Point2D pt2 = new Point2D(); - m_xy.read(2 * xy1, pt1); - pt1.y += (((pair1 & 1) != 0) ? m_toleranceIsSimple - : -m_toleranceIsSimple); - m_xy.read(2 * xy2, pt2); - pt2.y += (((pair2 & 1) != 0) ? m_toleranceIsSimple - : -m_toleranceIsSimple); - int res = pt1.compare(pt2); - if (res == 0 && get_paths) { - int di = m_paths_for_OGC_tests.get(xy1) - - m_paths_for_OGC_tests.get(xy2); - return di < 0 ? -1 : di > 0 ? 1 : 0; - } - return res; - } - - private static final class VertexComparer extends - AttributeStreamOfInt32.IntComparator { - OperatorSimplifyLocalHelper parent; - boolean get_paths; - - VertexComparer(OperatorSimplifyLocalHelper parent_, boolean get_paths_) { - parent = parent_; - get_paths = get_paths_; - } - - @Override - public int compare(int i1, int i2) { - return parent.compareVertices_(i1, i2, get_paths); - } - } - - private static final class IndexSorter extends ClassicSort { - OperatorSimplifyLocalHelper parent; - private boolean get_paths; - private Point2D pt1_dummy = new Point2D(); - - IndexSorter(OperatorSimplifyLocalHelper parent_, boolean get_paths_) { - parent = parent_; - get_paths = get_paths_; - } - - @Override - public void userSort(int begin, int end, AttributeStreamOfInt32 indices) { - indices.Sort(begin, end, new VertexComparer(parent, get_paths)); - } - - @Override - public double getValue(int index) /* const */ { - int pair = parent.m_pairs.get(index); - int xy1 = pair >> 1; - parent.m_xy.read(2 * xy1, pt1_dummy); - double y = pt1_dummy.y - + (((pair & 1) != 0) ? parent.m_toleranceIsSimple - : -parent.m_toleranceIsSimple); - return y; - } - } - - private int compareVerticesMultiPoint_(int i1, int i2) { - if (i1 == i2) - return 0; - MultiVertexGeometryImpl multiVertexImpl = (MultiVertexGeometryImpl) m_geometry - ._getImpl(); - Point2D pt1 = multiVertexImpl.getXY(i1); - Point2D pt2 = multiVertexImpl.getXY(i2); - - if (pt1.x < pt2.x) - return -1; - if (pt1.x > pt2.x) - return 1; - if (pt1.y < pt2.y) - return -1; - if (pt1.y > pt2.y) - return 1; - - for (int attrib = 1; attrib < m_attributeCount; attrib++) { - int semantics = m_description.getSemantics(attrib); - int nords = VertexDescription.getComponentCount(semantics); - for (int ord = 0; ord < nords; ord++) { - double v1 = multiVertexImpl.getAttributeAsDbl(semantics, i1, - ord); - double v2 = multiVertexImpl.getAttributeAsDbl(semantics, i2, - ord); - if (v1 < v2) - return -1; - if (v1 > v2) - return 1; - } - } - - return 0; - } - - private int compareVerticesMultiPoint2_(int i1, int i2) { - int res = compareVerticesMultiPoint_(i1, i2); - if (res == 0) - return i1 < i2 ? -1 : 1; - else - return res; - } - - private static final class EdgeComparerForSelfIntersection implements - Comparator { - OperatorSimplifyLocalHelper parent; - - EdgeComparerForSelfIntersection(OperatorSimplifyLocalHelper parent_) { - parent = parent_; - } - - // Recall that the total ordering [<] induced by compare satisfies e1 - // [<] e2 if and only if compare(e1, e2) < 0. - - @Override - public int compare(Edge e1, Edge e2) { - return parent.edgeAngleCompare_(e1, e2); - } - } - - private static final class MultiPointVertexComparer extends - AttributeStreamOfInt32.IntComparator { - OperatorSimplifyLocalHelper parent; - - MultiPointVertexComparer(OperatorSimplifyLocalHelper parent_) { - parent = parent_; - } - - @Override - public int compare(int i1, int i2) { - return parent.compareVerticesMultiPoint_(i1, i2); - } - } - - private static final class MultiPointVertexComparer2 extends - AttributeStreamOfInt32.IntComparator { - OperatorSimplifyLocalHelper parent; - - MultiPointVertexComparer2(OperatorSimplifyLocalHelper parent_) { - parent = parent_; - } - - @Override - public int compare(int i1, int i2) { - return parent.compareVerticesMultiPoint2_(i1, i2); - } - } - - // compares angles between two edges - private int edgeAngleCompare_(/* const */Edge edge1, /* const */Edge edge2) { - if (edge1.equals(edge2)) - return 0; - - Point2D v1 = edge1.m_segment._getTangent(edge1.getReversed() ? 1.0 - : 0.0); - if (edge1.getReversed()) - v1.negate(); - Point2D v2 = edge2.m_segment._getTangent(edge2.getReversed() ? 1.0 - : 0.0); - if (edge2.getReversed()) - v2.negate(); - - int q1 = v1._getQuarter(); - int q2 = v2._getQuarter(); - - if (q2 == q1) { - double cross = v1.crossProduct(v2); - double crossError = 4 * NumberUtils.doubleEps() - * (Math.abs(v2.x * v1.y) + Math.abs(v2.y * v1.x)); - if (Math.abs(cross) <= crossError) { - cross--; // To avoid warning of "this line has no effect" from - // cross = cross. - cross++; - } - assert (Math.abs(cross) > crossError); - return cross < 0 ? 1 : (cross > 0 ? -1 : 0); - } else { - return q1 < q2 ? -1 : 1; - } - } + private static final class Edge { + Edge() { + m_flags = 0; + // m_segment.createInstance(); + } + + Segment m_segment; + int m_vertexIndex; + int m_pathIndex; + int m_flags; + + void setReversed(boolean bYesNo) { + m_flags &= (~1); + m_flags = m_flags | (bYesNo ? 1 : 0); + } + + // The value returned by GetReversed is interpreted differently in + // checkSelfIntersections_ and checkValidRingOrientation_ + boolean getReversed() /* const */ + { + return (m_flags & 1) != 0; + } + + int getRightSide() /* const */ + { + return getReversed() ? 0 : 1; // 0 means there should be an + // emptiness on the right side of + // the edge, 1 means there is + // interior + } + } + + private final VertexDescription m_description; + private Geometry m_geometry; + private SpatialReferenceImpl m_sr; + private int m_dbgCounter; // debugging counter(for breakpoints) + private double m_toleranceIsSimple; + private double m_toleranceSimplify; + // private double m_toleranceCluster; //cluster tolerance needs to be + // sqrt(2) times larger than the tolerance of the other simplify processes. + private int m_knownSimpleResult; + private int m_attributeCount; + + private ArrayList m_edges; + private AttributeStreamOfInt32 m_FreeEdges; + private ArrayList m_lineEdgesRecycle; + private AttributeStreamOfInt32 m_newEdges; + private SegmentIteratorImpl m_recycledSegIter; + private IndexMultiDCList m_crossOverHelperList; + private AttributeStreamOfInt32 m_paths_for_OGC_tests; + + private ProgressTracker m_progressTracker; + + private Treap m_AET; + private AttributeStreamOfInt32 m_xyToNode1; // for each vertex, contains -1, + // or the edge node. + private AttributeStreamOfInt32 m_xyToNode2; // for each vertex, contains -1, + // or the edge node. + private AttributeStreamOfInt32 m_pathOrientations; // 0 if undefined, -1 for + // counterclockwise, 1 + // for clockwise. + private AttributeStreamOfInt32 m_pathParentage; + private int m_unknownOrientationPathCount; + private double m_yScanline; + + private AttributeStreamOfDbl m_xy; + private AttributeStreamOfInt32 m_pairs; + private AttributeStreamOfInt32 m_pairIndices; + + private EditShape m_editShape; + private boolean m_bOGCRestrictions; + private boolean m_bPlanarSimplify; + + private int isSimplePlanarImpl_() { + m_bPlanarSimplify = true; + if (Geometry.isMultiPath(m_geometry.getType().value())) { + if (!checkStructure_()) // check structure of geometry(no zero + // length paths, etc) + return 0; + + if (!checkDegenerateSegments_(false)) // check for degenerate + // segments(only 2D,no zs or + // other attributes) + return 0; + } + + if (!checkClustering_()) // check clustering(points are either + // coincident,or further than tolerance) + return 0; + + if (!Geometry.isMultiPath(m_geometry.getType().value())) + return 2; // multipoint is simple + + if (!checkCracking_()) // check that there are no self intersections and + // overlaps among segments. + return 0; + + if (m_geometry.getType() == Geometry.Type.Polyline) { + if (!checkSelfIntersectionsPolylinePlanar_()) + return 0; + + return 2; // polyline is simple + } + + if (!checkSelfIntersections_()) // check that there are no other self + // intersections (for the cases of + // several segments connect in a point) + return 0; + + // check that every hole is counterclockwise, and every exterior is + // clockwise. + // for the strong simple also check that exterior rings are followed by + // the interior rings. + return checkValidRingOrientation_(); + } + + private boolean testToleranceDistance_(int xyindex1, int xyindex2) { + double x1 = m_xy.read(2 * xyindex1); + double y1 = m_xy.read(2 * xyindex1 + 1); + double x2 = m_xy.read(2 * xyindex2); + double y2 = m_xy.read(2 * xyindex2 + 1); + boolean b = !Clusterer.isClusterCandidate_(x1, y1, x2, y2, + m_toleranceIsSimple * m_toleranceIsSimple); + if (!b) { + if (m_geometry.getDimension() == 0) + return false; + + return (x1 == x2 && y1 == y2); // points either coincide or + // further,than the tolerance + } + + return b; + } + + private boolean checkStructure_() { + MultiPathImpl multiPathImpl = (MultiPathImpl) m_geometry._getImpl(); + int minsize = multiPathImpl.m_bPolygon ? 3 : 2; + for (int ipath = 0, npath = multiPathImpl.getPathCount(); ipath < npath; ipath++) { + if (multiPathImpl.getPathSize(ipath) < minsize) { + m_nonSimpleResult = new NonSimpleResult( + NonSimpleResult.Reason.Structure, ipath, 0); + return false; + } + } + + return true; + } + + private boolean checkDegenerateSegments_(boolean bTestZs) { + MultiPathImpl multiPathImpl = (MultiPathImpl) m_geometry._getImpl(); + SegmentIteratorImpl segIter = multiPathImpl.querySegmentIterator(); + // Envelope2D env2D; + boolean bHasZ = multiPathImpl + .hasAttribute(VertexDescription.Semantics.Z); + double ztolerance = !bHasZ ? 0 : InternalUtils + .calculateZToleranceFromGeometry(m_sr, multiPathImpl, false); + while (segIter.nextPath()) { + while (segIter.hasNextSegment()) { + /* const */Segment seg = segIter.nextSegment(); + double length = seg.calculateLength2D(); + if (length > m_toleranceIsSimple) + continue; + + if (bTestZs && bHasZ) { + double z0 = seg.getStartAttributeAsDbl( + VertexDescription.Semantics.Z, 0); + double z1 = seg.getStartAttributeAsDbl( + VertexDescription.Semantics.Z, 0); + if (Math.abs(z1 - z0) > ztolerance) + continue; + } + + m_nonSimpleResult = new NonSimpleResult( + NonSimpleResult.Reason.DegenerateSegments, + segIter.getStartPointIndex(), -1); + return false; + } + } + + return true; + } + + private boolean checkClustering_() { + MultiVertexGeometryImpl multiVertexImpl = (MultiVertexGeometryImpl) m_geometry + ._getImpl(); + + MultiPathImpl multiPathImpl = null; + if (Geometry.isMultiPath(m_geometry.getType().value())) + multiPathImpl = (MultiPathImpl) m_geometry._getImpl(); + + boolean get_paths = (m_bPlanarSimplify || m_bOGCRestrictions) + && multiPathImpl != null; + + int pointCount = multiVertexImpl.getPointCount(); + m_xy = (AttributeStreamOfDbl) multiVertexImpl + .getAttributeStreamRef(VertexDescription.Semantics.POSITION); + m_pairs = new AttributeStreamOfInt32(0); + m_pairs.reserve(pointCount * 2); + m_pairIndices = new AttributeStreamOfInt32(0); + m_pairIndices.reserve(pointCount * 2); + if (get_paths) { + if (m_paths_for_OGC_tests == null) + m_paths_for_OGC_tests = new AttributeStreamOfInt32(0); + m_paths_for_OGC_tests.reserve(pointCount); + } + int ipath = 0; + for (int i = 0; i < pointCount; i++) { + m_pairs.add(2 * i); // y - tol(BOTTOM) + m_pairs.add(2 * i + 1); // y + tol(TOP) + m_pairIndices.add(2 * i); + m_pairIndices.add(2 * i + 1); + if (get_paths) { + while (i >= multiPathImpl.getPathEnd(ipath)) + ipath++; + + m_paths_for_OGC_tests.add(ipath); + } + + } + + BucketSort sorter = new BucketSort(); + sorter.sort(m_pairIndices, 0, 2 * pointCount, new IndexSorter(this, + get_paths)); + + m_AET.clear(); + m_AET.setComparator(new ClusterTestComparator(this)); + m_AET.setCapacity(pointCount); + for (int index = 0, n = pointCount * 2; index < n; index++) { + int pairIndex = m_pairIndices.get(index); + int pair = m_pairs.get(pairIndex); + int xyindex = pair >> 1; // k = 2n or 2n + 1 represent a vertical + // segment for the same vertex. + // Therefore, k / 2 represents a vertex + // index + // Points need to be either exactly equal or further than 2 * + // tolerance apart. + if ((pair & 1) == 0) {// bottom element + int aetNode = m_AET.addElement(xyindex, -1); + // add it to the AET,end test it against its left and right + // neighbours. + int leftneighbour = m_AET.getPrev(aetNode); + if (leftneighbour != Treap.nullNode() + && !testToleranceDistance_( + m_AET.getElement(leftneighbour), xyindex)) { + m_nonSimpleResult = new NonSimpleResult( + NonSimpleResult.Reason.Clustering, xyindex, + m_AET.getElement(leftneighbour)); + return false; + } + int rightneighbour = m_AET.getNext(aetNode); + if (rightneighbour != Treap.nullNode() + && !testToleranceDistance_( + m_AET.getElement(rightneighbour), xyindex)) { + m_nonSimpleResult = new NonSimpleResult( + NonSimpleResult.Reason.Clustering, xyindex, + m_AET.getElement(rightneighbour)); + return false; + } + } else { // top + // get left and right neighbours, and remove the element + // from AET. Then test the neighbours with the + // tolerance. + int aetNode = m_AET.search(xyindex, -1); + int leftneighbour = m_AET.getPrev(aetNode); + int rightneighbour = m_AET.getNext(aetNode); + m_AET.deleteNode(aetNode, -1); + if (leftneighbour != Treap.nullNode() + && rightneighbour != Treap.nullNode() + && !testToleranceDistance_( + m_AET.getElement(leftneighbour), + m_AET.getElement(rightneighbour))) { + m_nonSimpleResult = new NonSimpleResult( + NonSimpleResult.Reason.Clustering, + m_AET.getElement(leftneighbour), + m_AET.getElement(rightneighbour)); + return false; + } + } + } + + return true; + } + + private boolean checkCracking_() { + MultiVertexGeometryImpl multiVertexImpl = (MultiVertexGeometryImpl) m_geometry + ._getImpl(); + int pointCount = multiVertexImpl.getPointCount(); + if (pointCount < 10)// use brute force for smaller polygons + { + return checkCrackingBrute_(); + } else { + return checkCrackingPlanesweep_(); + } + } + + private boolean checkCrackingPlanesweep_() // cracker,that uses planesweep + // algorithm. + { + EditShape editShape = new EditShape(); + editShape.addGeometry(m_geometry); + NonSimpleResult result = new NonSimpleResult(); + boolean bNonSimple = Cracker.needsCracking(false, editShape, + m_toleranceIsSimple, result, m_progressTracker); + if (bNonSimple) { + result.m_vertexIndex1 = editShape + .getVertexIndex(result.m_vertexIndex1); + result.m_vertexIndex2 = editShape + .getVertexIndex(result.m_vertexIndex2); + m_nonSimpleResult.Assign(result); + return false; + } else + return true; + } + + private boolean checkCrackingBrute_() // cracker, that uses brute force (a + // double loop) to find segment + // intersections. + { + MultiPathImpl multiPathImpl = (MultiPathImpl) m_geometry._getImpl(); + // Implementation without a QuadTreeImpl accelerator + SegmentIteratorImpl segIter1 = multiPathImpl.querySegmentIterator(); + SegmentIteratorImpl segIter2 = multiPathImpl.querySegmentIterator(); + // Envelope2D env2D; + while (segIter1.nextPath()) { + while (segIter1.hasNextSegment()) { + /* const */Segment seg1 = segIter1.nextSegment(); + if (!segIter1.isLastSegmentInPath() || !segIter1.isLastPath()) { + segIter2.resetTo(segIter1); + do { + while (segIter2.hasNextSegment()) { + /* const */Segment seg2 = segIter2.nextSegment(); + int res = seg1._isIntersecting(seg2, + m_toleranceIsSimple, true); + if (res != 0) { + NonSimpleResult.Reason reason = res == 2 ? NonSimpleResult.Reason.CrossOver + : NonSimpleResult.Reason.Cracking; + m_nonSimpleResult = new NonSimpleResult(reason, + segIter1.getStartPointIndex(), + segIter2.getStartPointIndex()); + return false; + } + } + } while (segIter2.nextPath()); + } + } + } + return true; + } + + private boolean checkSelfIntersections_() { + MultiPathImpl multiPathImpl = (MultiPathImpl) m_geometry._getImpl(); + m_edges.clear(); + m_edges.ensureCapacity(20);// we reuse the edges while going through a + // polygon. + m_lineEdgesRecycle.clear(); + m_lineEdgesRecycle.ensureCapacity(20);// we reuse the edges while going + // through a polygon. + + m_recycledSegIter = multiPathImpl.querySegmentIterator(); + m_recycledSegIter.setCirculator(true); + + AttributeStreamOfInt32 bunch = new AttributeStreamOfInt32(0);// stores + // coincident + // vertices + bunch.reserve(10); + int pointCount = multiPathImpl.getPointCount(); + double xprev = NumberUtils.TheNaN; + double yprev = 0; + // We already have a sorted list of vertices from clustering check. + for (int index = 0, n = pointCount * 2; index < n; index++) { + int pairIndex = m_pairIndices.get(index); + int pair = m_pairs.get(pairIndex); + if ((pair & 1) != 0) + continue; // m_pairs array is redundant. See checkClustering_. + + int xyindex = pair >> 1; + + double x = m_xy.read(2 * xyindex); + double y = m_xy.read(2 * xyindex + 1); + if (bunch.size() != 0) { + if (x != xprev || y != yprev) { + if (!processBunchForSelfIntersectionTest_(bunch)) + return false; + if (bunch != null) + bunch.clear(false); + } + } + + bunch.add(xyindex); + xprev = x; + yprev = y; + } + + assert (bunch.size() > 0);// cannot be empty + + if (!processBunchForSelfIntersectionTest_(bunch)) + return false; + + return true; + } + + static final class Vertex_info { + double x, y; + int ipath; + int ivertex; + boolean boundary; + }; + + static final class Vertex_info_pl { + double x; + double y; + int ipath; + int ivertex; + boolean boundary; + boolean end_point; + }; + + boolean checkSelfIntersectionsPolylinePlanar_() { + MultiPathImpl multiPathImpl = (MultiPathImpl) m_geometry._getImpl(); + + boolean closedPaths[] = new boolean[multiPathImpl.getPathCount()]; + for (int ipath = 0, npaths = multiPathImpl.getPathCount(); ipath < npaths; ipath++) { + closedPaths[ipath] = multiPathImpl.isClosedPathInXYPlane(ipath); + } + + Vertex_info_pl vi_prev = new Vertex_info_pl(); + boolean is_closed_path; + int path_start; + int path_last; + + Point2D pt = new Point2D(); + + {// scope + int pairIndex = m_pairIndices.get(0); + int pair = m_pairs.get(pairIndex); + int xyindex = pair >> 1; + m_xy.read(2 * xyindex, pt); + int ipath = m_paths_for_OGC_tests.get(xyindex); + is_closed_path = closedPaths[ipath]; + path_start = multiPathImpl.getPathStart(ipath); + path_last = multiPathImpl.getPathEnd(ipath) - 1; + vi_prev.end_point = (xyindex == path_start) + || (xyindex == path_last); + if (m_bOGCRestrictions) + vi_prev.boundary = !is_closed_path && vi_prev.end_point; + else { + // for regular planar simplify, only the end points are allowed + // to coincide + vi_prev.boundary = vi_prev.end_point; + } + + vi_prev.ipath = ipath; + vi_prev.x = pt.x; + vi_prev.y = pt.y; + vi_prev.ivertex = xyindex; + } + + Vertex_info_pl vi = new Vertex_info_pl(); + + for (int index = 1, n = m_pairIndices.size(); index < n; index++) { + int pairIndex = m_pairIndices.get(index); + int pair = m_pairs.get(pairIndex); + if ((pair & 1) != 0) + continue; + + int xyindex = pair >> 1; + m_xy.read(2 * xyindex, pt); + int ipath = m_paths_for_OGC_tests.get(xyindex); + if (ipath != vi_prev.ipath) { + is_closed_path = closedPaths[ipath]; + path_start = multiPathImpl.getPathStart(ipath); + path_last = multiPathImpl.getPathEnd(ipath) - 1; + } + boolean boundary; + boolean end_point = (xyindex == path_start) + || (xyindex == path_last); + if (m_bOGCRestrictions) + boundary = !is_closed_path && end_point; + else + // for regular planar simplify, only the end points are allowed + // to coincide + boundary = end_point; + + vi.x = pt.x; + vi.y = pt.y; + vi.ipath = ipath; + vi.ivertex = xyindex; + vi.boundary = boundary; + vi.end_point = end_point; + + if (vi.x == vi_prev.x && vi.y == vi_prev.y) { + if (m_bOGCRestrictions) { + if (!vi.boundary || !vi_prev.boundary) { + // check that this is not the endpoints of a closed path + if ((vi.ipath != vi_prev.ipath) + || (!vi.end_point && !vi_prev.end_point)) { + // one of coincident vertices is not on the boundary + // this is either NonSimpleResult.CrossOver or + // NonSimpleResult.OGCPolylineSelfTangency. + // too expensive to distinguish between the two. + m_nonSimpleResult = new NonSimpleResult( + NonSimpleResult.Reason.OGCPolylineSelfTangency, + vi.ivertex, vi_prev.ivertex); + return false;// common point not on the boundary + } + } + } else { + if (!vi.end_point || !vi_prev.end_point) { + //one of coincident vertices is not an endpoint + m_nonSimpleResult = new NonSimpleResult( + NonSimpleResult.Reason.CrossOver, vi.ivertex, + vi_prev.ivertex); + return false;// common point not on the boundary + } + } + } + + Vertex_info_pl tmp = vi_prev; + vi_prev = vi; + vi = tmp; + } + + return true; + } + + final static class Vertex_info_pg { + double x; + double y; + int ipath; + int ivertex; + int ipolygon; + + Vertex_info_pg(double x_, double y_, int ipath_, int xyindex_, + int polygon_) { + x = x_; + y = y_; + ipath = ipath_; + ivertex = xyindex_; + ipolygon = polygon_; + } + + boolean is_equal(Vertex_info_pg other) { + return x == other.x && y == other.y && ipath == other.ipath + && ivertex == other.ivertex && ipolygon == other.ipolygon; + } + }; + + boolean check_self_intersections_polygons_OGC_() { + MultiPathImpl multiPathImpl = (MultiPathImpl) (m_geometry._getImpl()); + // OGC MultiPolygon is simple when each Polygon is simple and Polygons a + // allowed only touch at finite number of vertices. + // OGC Polygon is simple if it consist of simple LinearRings. + // LinearRings cannot cross. + // Any two LinearRings of a OGC Polygon are allowed to touch at single + // vertex only. + // The OGC Polygon interior has to be a connected set. + + // At this point we assume that the ring order has to be correct (holes + // follow corresponding exterior ring). + // No Rings cross. Exterior rings can only touch at finite number of + // vertices. + + // Fill a mapping of ring to + int[] ring_to_polygon = new int[multiPathImpl.getPathCount()]; + int exteriors = -1; + boolean has_holes = false; + for (int ipath = 0, n = multiPathImpl.getPathCount(); ipath < n; ipath++) { + if (multiPathImpl.isExteriorRing(ipath)) { + has_holes = false; + exteriors++; + if (ipath < n - 1) { + if (!multiPathImpl.isExteriorRing(ipath + 1)) + has_holes = true; + } + } + + // For OGC polygons with no holes, store -1. + // For polygons with holes, store polygon index for each ring. + ring_to_polygon[ipath] = has_holes ? exteriors : -1; + } + + // Use already sorted m_pairIndices + Vertex_info_pg vi_prev = null; + Point2D pt = new Point2D(); + {// scope + int pairIndex = m_pairIndices.get(0); + int pair = m_pairs.get(pairIndex); + int xyindex = pair >> 1; + m_xy.read(2 * xyindex, pt); + int ipath = m_paths_for_OGC_tests.get(xyindex); + vi_prev = new Vertex_info_pg(pt.x, pt.y, ipath, xyindex, + ring_to_polygon[ipath]); + } + + ArrayList intersections = new ArrayList( + multiPathImpl.getPathCount() * 2); + for (int index = 1, n = m_pairIndices.size(); index < n; index++) { + int pairIndex = m_pairIndices.get(index); + int pair = m_pairs.get(pairIndex); + if ((pair & 1) != 0) + continue; + int xyindex = pair >> 1; + m_xy.read(2 * xyindex, pt); + int ipath = m_paths_for_OGC_tests.get(xyindex); + Vertex_info_pg vi = new Vertex_info_pg(pt.x, pt.y, ipath, xyindex, + ring_to_polygon[ipath]); + + if (vi.x == vi_prev.x && vi.y == vi_prev.y) { + if (vi.ipath == vi_prev.ipath) {// the ring has self tangency + m_nonSimpleResult = new NonSimpleResult( + NonSimpleResult.Reason.OGCPolygonSelfTangency, + vi.ivertex, vi_prev.ivertex); + return false; + } else if (ring_to_polygon[vi.ipath] >= 0 + && ring_to_polygon[vi.ipath] == ring_to_polygon[vi_prev.ipath]) {// only + // add + // rings + // from + // polygons + // with + // holes. + // Only + // interested + // in + // touching + // rings + // that + // belong + // to + // the + // same + // polygon + if (intersections.size() == 0 + || intersections.get(intersections.size() - 1) != vi_prev) + intersections.add(vi_prev); + intersections.add(vi); + } + } + + vi_prev = vi; + } + + if (intersections.size() == 0) + return true; + + // Find disconnected interior cases (OGC spec: Interior of polygon has + // to be a closed set) + + // Note: Now we'll reuse ring_to_polygon for different purpose - to + // store mapping from the rings to the graph nodes. + + IndexMultiDCList graph = new IndexMultiDCList(true); + Arrays.fill(ring_to_polygon, -1); + int vnode_index = -1; + Point2D prev = new Point2D(); + prev.setNaN(); + for (int i = 0, n = intersections.size(); i < n; i++) { + Vertex_info_pg cur = intersections.get(i); + if (cur.x != prev.x || cur.y != prev.y) { + vnode_index = graph.createList(0); + prev.x = cur.x; + prev.y = cur.y; + } + + int rnode_index = ring_to_polygon[cur.ipath]; + if (rnode_index == -1) { + rnode_index = graph.createList(2); + ring_to_polygon[cur.ipath] = rnode_index; + } + graph.addElement(rnode_index, vnode_index); // add to rnode + // adjacency list the + // current vnode + graph.addElement(vnode_index, rnode_index); // add to vnode + // adjacency list the + // rnode + } + + AttributeStreamOfInt32 depth_first_stack = new AttributeStreamOfInt32(0); + depth_first_stack.reserve(10); + + for (int node = graph.getFirstList(); node != -1; node = graph + .getNextList(node)) { + int ncolor = graph.getListData(node); + if ((ncolor & 1) != 0 || (ncolor & 2) == 0) + continue;// already visited or this is a vnode (we do not want + // to start from vnode). + + int bad_rnode = -1; + depth_first_stack.add(node); + depth_first_stack.add(-1);// parent + while (depth_first_stack.size() > 0) { + int cur_node_parent = depth_first_stack.getLast(); + depth_first_stack.removeLast(); + int cur_node = depth_first_stack.getLast(); + depth_first_stack.removeLast(); + int color = graph.getListData(cur_node); + if ((color & 1) != 0) { + // already visited this node. This means we found a loop. + if ((color & 2) == 0) {// closing on vnode + bad_rnode = cur_node_parent; + } else + bad_rnode = cur_node; + + // assert(bad_rnode != -1); + break; + } + + graph.setListData(cur_node, color | 1); + for (int adjacent_node = graph.getFirst(cur_node); adjacent_node != -1; adjacent_node = graph + .getNext(adjacent_node)) { + int adjacent_node_data = graph.getData(adjacent_node); + if (adjacent_node_data == cur_node_parent) + continue;// avoid going back to where we just came from + depth_first_stack.add(adjacent_node_data); + depth_first_stack.add(cur_node);// push cur_node as parent + // of adjacent_node + } + } + + if (bad_rnode != -1) { + int bad_ring_index = -1; + for (int i = 0, n = ring_to_polygon.length; i < n; i++) + if (ring_to_polygon[i] == bad_rnode) { + bad_ring_index = i; + break; + } + + // bad_ring_index is any ring in a problematic chain of touching + // rings. + // When chain of touching rings form a loop, the result is a + // disconnected interior, + // which is non-simple for OGC spec. + m_nonSimpleResult = new NonSimpleResult( + NonSimpleResult.Reason.OGCDisconnectedInterior, + bad_ring_index, -1); + return false; + } + } + + return true; + } + + private int checkValidRingOrientation_() { + MultiPathImpl multiPathImpl = (MultiPathImpl) m_geometry._getImpl(); + double totalArea = multiPathImpl.calculateArea2D(); + if (totalArea <= 0) { + m_nonSimpleResult = new NonSimpleResult( + NonSimpleResult.Reason.RingOrientation, + multiPathImpl.getPathCount() == 1 ? 1 : -1, -1); + return 0; + } + + if (multiPathImpl.getPathCount() == 1) {// optimization for a single + // polygon + if (m_bOGCRestrictions) { + if (!check_self_intersections_polygons_OGC_()) + return 0; + } + + return 2; + } + + // 1.Go through all vertices in the sorted order. + // 2.For each vertex,insert any non-horizontal segment that has the + // vertex as low point(there can be max two segments) + m_pathOrientations = new AttributeStreamOfInt32( + multiPathImpl.getPathCount(), 0); + + m_pathParentage = new AttributeStreamOfInt32( + multiPathImpl.getPathCount(), -1); + + int parent_ring = -1; + double exteriorArea = 0; + for (int ipath = 0, n = multiPathImpl.getPathCount(); ipath < n; ipath++) { + double area = multiPathImpl.calculateRingArea2D(ipath); + m_pathOrientations.write(ipath, area < 0 ? 0 : 256); // 8th bit + // is + // existing + // orientation + if (area > 0) { + parent_ring = ipath; + exteriorArea = area; + } else if (area == 0) { + m_nonSimpleResult = new NonSimpleResult( + NonSimpleResult.Reason.RingOrientation, ipath, -1); + return 0; + } else { + // area < 0: this is a hole. + // We write the parent exterior + // ring for it (assumed to be first previous exterior ring) + if (parent_ring < 0 || exteriorArea < Math.abs(area)) { + // The first ring is a hole - this is a wrong ring ordering. + // Or the hole's area is bigger than the previous exterior + // area - this means ring order is broken, + // because holes are always smaller. This is not the only + // condition when ring order is broken though. + m_nonSimpleResult = new NonSimpleResult( + NonSimpleResult.Reason.RingOrder, ipath, -1); + if (m_bOGCRestrictions) + return 0; + } + m_pathParentage.write(ipath, parent_ring); + } + } + + m_unknownOrientationPathCount = multiPathImpl.getPathCount(); + m_newEdges = new AttributeStreamOfInt32(0); + m_newEdges.reserve(10); + + int pointCount = multiPathImpl.getPointCount(); + m_yScanline = NumberUtils.TheNaN; + AttributeStreamOfInt32 bunch = new AttributeStreamOfInt32(0); // stores + // coincident + // vertices + bunch.reserve(10); + // Each vertex has two edges attached.These two arrays map vertices to + // edges as nodes in the m_AET + m_xyToNode1 = new AttributeStreamOfInt32(pointCount, Treap.nullNode()); + m_xyToNode2 = new AttributeStreamOfInt32(pointCount, Treap.nullNode()); + if (m_FreeEdges != null) + m_FreeEdges.clear(false); + else + m_FreeEdges = new AttributeStreamOfInt32(0); + m_FreeEdges.reserve(10); + + m_AET.clear(); + m_AET.setComparator(new RingOrientationTestComparator(this)); + for (int index = 0, n = pointCount * 2; m_unknownOrientationPathCount > 0 + && index < n; index++) { + int pairIndex = m_pairIndices.get(index); + int pair = m_pairs.get(pairIndex); + if ((pair & 1) != 0) + continue;// m_pairs array is redundant.See checkClustering_. + + int xyindex = pair >> 1; + double y = m_xy.read(2 * xyindex + 1); + + if (y != m_yScanline && bunch.size() != 0) { + if (!processBunchForRingOrientationTest_(bunch)) { + // m_nonSimpleResult is set in the + // processBunchForRingOrientationTest_ + return 0; + } + if (bunch != null) + bunch.clear(false); + } + + bunch.add(xyindex);// all vertices that have same y are added to the + // bunch + m_yScanline = y; + } + + if (m_unknownOrientationPathCount > 0 + && !processBunchForRingOrientationTest_(bunch)) { + // m_nonSimpleResult is set in the + // processBunchForRingOrientationTest_ + return 0; + } + + if (m_bOGCRestrictions) { + if (m_nonSimpleResult.m_reason != NonSimpleResult.Reason.NotDetermined) + return 0;// cannot proceed with OGC verification if the ring + // order is broken (cannot decide polygons then). + + if (!check_self_intersections_polygons_OGC_()) + return 0; + + return 2;// everything is good + } else { + if (m_nonSimpleResult.m_reason == NonSimpleResult.Reason.NotDetermined) + return 2;// everything is good + + // weak simple + return 1; + } + } + + private boolean processBunchForSelfIntersectionTest_( + AttributeStreamOfInt32 bunch) { + assert (bunch.size() > 0); + if (bunch.size() == 1) + return true; + + assert (m_edges.size() == 0); + + // Bunch contains vertices that have exactly same x and y. + // We populate m_edges array with the edges that originate in the + // vertices of the bunch. + for (int i = 0, n = bunch.size(); i < n; i++) { + int xyindex = bunch.get(i); + m_recycledSegIter.resetToVertex(xyindex);// the iterator is + // circular. + /* const */Segment seg1 = m_recycledSegIter.previousSegment(); + m_edges.add(createEdge_(seg1, xyindex, + m_recycledSegIter.getPathIndex(), true)); + m_recycledSegIter.nextSegment();// Need to skip one,because of the + // previousSegment call + // before (otherwise will get same segment again) + /* const */Segment seg2 = m_recycledSegIter.nextSegment(); + m_edges.add(createEdge_(seg2, xyindex, + m_recycledSegIter.getPathIndex(), false)); + } + + assert ((m_edges.size() & 1) == 0); // even size + + // Analyze the bunch edges for self intersections(the edges touch at the + // end points only at this stage of IsSimple) + // 1.sort the edges by angle between edge and the unit vector along axis + // x,using the cross product sign.Precondition:no overlaps occur at this + // stage. + + Collections.sort(m_edges, new EdgeComparerForSelfIntersection(this)); + + // 2.Analyze the bunch.There can be no edges between edges that share + // same vertex coordinates. + // We populate a doubly linked list with the edge indices and iterate + // over this list getting rid of the neighbouring pairs of vertices. + // The process is similar to peeling an onion. + // If the list becomes empty,there are no crossovers,otherwise,the + // geometry has cross-over. + int list = m_crossOverHelperList.getFirstList(); + + if (list == -1) + list = m_crossOverHelperList.createList(0); + + m_crossOverHelperList.reserveNodes(m_edges.size()); + + for (int i = 0, n = m_edges.size(); i < n; i++) { + m_crossOverHelperList.addElement(list, i); + } + + // Peel the onion + boolean bContinue = true; + int i1 = -1; + int i2 = -1; + while (bContinue) { + bContinue = false; + int listnode = m_crossOverHelperList.getFirst(list); + if (listnode == -1) + break; + + int nextnode = m_crossOverHelperList.getNext(listnode); + while (nextnode != -1) { + int edgeindex1 = m_crossOverHelperList.getData(listnode); + int edgeindex2 = m_crossOverHelperList.getData(nextnode); + i1 = m_edges.get(edgeindex1).m_vertexIndex; + i2 = m_edges.get(edgeindex2).m_vertexIndex; + if (i1 == i2) { + bContinue = true; + m_crossOverHelperList.deleteElement(list, listnode); + listnode = m_crossOverHelperList.getPrev(nextnode); + nextnode = m_crossOverHelperList.deleteElement(list, + nextnode); + if (nextnode == -1 || listnode == -1) + break; + else + continue; + } + listnode = nextnode; + nextnode = m_crossOverHelperList.getNext(listnode); + } + } + + int listSize = m_crossOverHelperList.getListSize(list); + m_crossOverHelperList.clear(list); + if (listSize > 0) { + // There is self-intersection here. + m_nonSimpleResult = new NonSimpleResult( + NonSimpleResult.Reason.CrossOver, i1, i2); + return false; + } + + // Recycle the bunch to save on object creation + for (int i = 0, n = bunch.size(); i < n; i++) { + recycleEdge_(m_edges.get(i)); + } + + m_edges.clear(); + return true; + } + + private boolean processBunchForRingOrientationTest_( + AttributeStreamOfInt32 bunch) { + m_dbgCounter++; + assert (bunch.size() > 0); + + // remove nodes that go out of scope + for (int i = 0, n = bunch.size(); i < n; i++) { + int xyindex = bunch.get(i); + int aetNode = m_xyToNode1.read(xyindex); + if (aetNode != Treap.nullNode()) {// We found that there is an edge + // in AET, attached to the + // xyindex vertex. This edge + // goes out of scope. Delete it + // from AET. + int edgeIndex = m_AET.getElement(aetNode); + m_FreeEdges.add(edgeIndex); + m_AET.deleteNode(aetNode, -1); + recycleEdge_(m_edges.get(edgeIndex)); + m_edges.set(edgeIndex, null); + m_xyToNode1.write(xyindex, Treap.nullNode()); + } + + aetNode = m_xyToNode2.read(xyindex); + if (aetNode != Treap.nullNode()) {// We found that there is an edge + // in AET, attached to the + // xyindex vertex. This edge + // goes out of scope. Delete it + // from AET. + int edgeIndex = m_AET.getElement(aetNode); + m_FreeEdges.add(edgeIndex); + m_AET.deleteNode(aetNode, -1); + recycleEdge_(m_edges.get(edgeIndex)); + m_edges.set(edgeIndex, null); + m_xyToNode2.write(xyindex, Treap.nullNode()); + } + } + + // add new edges to AET + for (int i = 0, n = bunch.size(); i < n; i++) { + int xyindex = bunch.get(i); + m_recycledSegIter.resetToVertex(xyindex);// the iterator is + // circular. + Segment seg1 = m_recycledSegIter.previousSegment();// this + // segment + // has + // end + // point + // at + // xyindex + if (seg1.getStartY() > seg1.getEndY())// do not allow horizontal + // segments in here + { + // get the top vertex index.We use it to determine what segments + // to get rid of. + int edgeTopIndex = m_recycledSegIter.getStartPointIndex(); + Edge edge = createEdge_(seg1, xyindex, + m_recycledSegIter.getPathIndex(), true); + int edgeIndex; + if (m_FreeEdges.size() > 0) { + edgeIndex = m_FreeEdges.getLast(); + m_FreeEdges.removeLast(); + m_edges.set(edgeIndex, edge); + } else { + edgeIndex = m_edges.size(); + m_edges.add(edge); + } + + int aetNode = m_AET.addElement(edgeIndex, -1); + // Remember AET nodes in the vertex to AET node maps. + if (m_xyToNode1.read(edgeTopIndex) == Treap.nullNode()) + m_xyToNode1.write(edgeTopIndex, aetNode); + else { + assert (m_xyToNode2.read(edgeTopIndex) == Treap.nullNode()); + m_xyToNode2.write(edgeTopIndex, aetNode); + } + + // If this edge belongs to a path that has not have direction + // figured out yet, + // add it to m_newEdges for post processing + if ((m_pathOrientations.read(m_recycledSegIter.getPathIndex()) & 3) == 0) + m_newEdges.add(aetNode); + } + + m_recycledSegIter.nextSegment();// Need to skip one,because of the + // previousSegment call + // before(otherwise will get same + // segment again) + // seg1 is invalid now + Segment seg2 = m_recycledSegIter.nextSegment(); + // start has to be lower than end for this one + if (seg2.getStartY() < seg2.getEndY())// do not allow horizontal + // segments in here + { + // get the top vertex index.We use it to determine what segments + // to get rid of. + int edgeTopIndex = m_recycledSegIter.getEndPointIndex(); + Edge edge = createEdge_(seg2, xyindex, + m_recycledSegIter.getPathIndex(), false); + int edgeIndex; + if (m_FreeEdges.size() > 0) { + edgeIndex = m_FreeEdges.getLast(); + m_FreeEdges.removeLast(); + m_edges.set(edgeIndex, edge); + } else { + edgeIndex = m_edges.size(); + m_edges.add(edge); + } + + int aetNode = m_AET.addElement(edgeIndex, -1); + if (m_xyToNode1.read(edgeTopIndex) == Treap.nullNode()) + m_xyToNode1.write(edgeTopIndex, aetNode); + else { + assert (m_xyToNode2.read(edgeTopIndex) == Treap.nullNode()); + m_xyToNode2.write(edgeTopIndex, aetNode); + } + + // If this edge belongs to a path that has not have direction + // figured out yet, + // add it to m_newEdges for post processing + if ((m_pathOrientations.read(m_recycledSegIter.getPathIndex()) & 3) == 0) + m_newEdges.add(aetNode); + } + } + + for (int i = 0, n = m_newEdges.size(); i < n + && m_unknownOrientationPathCount > 0; i++) { + int aetNode = m_newEdges.get(i); + int edgeIndexInitial = m_AET.getElement(aetNode); + Edge edgeInitial = m_edges.get(edgeIndexInitial); + int pathIndexInitial = edgeInitial.m_pathIndex; + int directionInitial = m_pathOrientations.read(pathIndexInitial); + if ((directionInitial & 3) == 0) { + int prevExteriorPath = -1; + int node = m_AET.getPrev(aetNode); + int prevNode = aetNode; + int oddEven = 0; + {// scope + int edgeIndex = -1; + Edge edge = null; + int pathIndex = -1; + int dir = 0; + // find the leftmost edge for which the ring orientation is + // known + while (node != Treap.nullNode()) { + edgeIndex = m_AET.getElement(node); + edge = m_edges.get(edgeIndex); + pathIndex = edge.m_pathIndex; + dir = m_pathOrientations.read(pathIndex); + if ((dir & 3) != 0) + break; + + prevNode = node; + node = m_AET.getPrev(node); + } + + if (node == Treap.nullNode()) {// if no edges have ring + // orientation known, then + // start + // from the left most and it + // has + // to be exterior ring. + oddEven = 1; + node = prevNode; + } else { + if ((dir & 3) == 1) { + prevExteriorPath = pathIndex; + } else { + prevExteriorPath = m_pathParentage.read(pathIndex); + } + + oddEven = (edge.getRightSide() != 0) ? 0 : 1; + node = m_AET.getNext(node); + } + } + + do { + int edgeIndex = m_AET.getElement(node); + Edge edge = m_edges.get(edgeIndex); + int pathIndex = edge.m_pathIndex; + int direction = m_pathOrientations.read(pathIndex); + if ((direction & 3) == 0) { + if (oddEven != edge.getRightSide()) { + m_nonSimpleResult = new NonSimpleResult( + NonSimpleResult.Reason.RingOrientation, + pathIndex, -1); + return false;// wrong ring orientation + } + + int dir = (oddEven != 0 && !edge.getReversed()) ? 1 : 2; + direction = (direction & 0xfc) | dir; + m_pathOrientations.write(pathIndex, dir); + if (dir == 2 + && m_nonSimpleResult.m_reason == NonSimpleResult.Reason.NotDetermined) { + // check that this hole has a correct parent + // exterior ring. + int parent = m_pathParentage.read(pathIndex); + if (parent != prevExteriorPath) { + m_nonSimpleResult = new NonSimpleResult( + NonSimpleResult.Reason.RingOrder, + pathIndex, -1); + if (m_bOGCRestrictions) + return false; + } + } + + m_unknownOrientationPathCount--; + if (m_unknownOrientationPathCount == 0)// if(!m_unknownOrientationPathCount) + return true; + } + + if ((direction & 3) == 1) { + prevExteriorPath = pathIndex; + } + + prevNode = node; + node = m_AET.getNext(node); + oddEven = oddEven != 0 ? 0 : 1; + } while (prevNode != aetNode); + } + } + + if (m_newEdges != null) + m_newEdges.clear(false); + else + m_newEdges = new AttributeStreamOfInt32(0); + return true; + } + + private Edge createEdge_(/* const */Segment seg, int xyindex, int pathIndex, + boolean bReversed) { + Edge edge; + Geometry.Type gt = seg.getType(); + if (gt == Geometry.Type.Line) { + edge = createEdgeLine_(seg); + } else { + throw GeometryException.GeometryInternalError(); // implement + // recycling for + // curves + } + edge.m_vertexIndex = xyindex; + edge.m_pathIndex = pathIndex; + edge.m_flags = 0; + edge.setReversed(bReversed); + + return edge; + } + + private Edge createEdgeLine_(/* const */Segment seg) { + Edge edge = null; + if (m_lineEdgesRecycle.size() > 0) { + int indexLast = m_lineEdgesRecycle.size() - 1; + edge = m_lineEdgesRecycle.get(indexLast); + m_lineEdgesRecycle.remove(indexLast); + seg.copyTo(edge.m_segment); + } else { + edge = new Edge(); + edge.m_segment = (Segment) Segment._clone(seg); + } + + return edge; + } + + private void recycleEdge_(/* const */Edge edge) { + Geometry.Type gt = edge.m_segment.getType(); + if (gt == Geometry.Type.Line) { + m_lineEdgesRecycle.add(edge); + } + } + + private static final class ClusterTestComparator extends Treap.Comparator { + OperatorSimplifyLocalHelper m_helper; + + ClusterTestComparator(OperatorSimplifyLocalHelper helper) { + m_helper = helper; + } + + @Override + int compare(/* const */Treap treap, int xy1, int node) { + int xy2 = treap.getElement(node); + double x1 = m_helper.m_xy.read(2 * xy1); + double x2 = m_helper.m_xy.read(2 * xy2); + double dx = x1 - x2; + return dx < 0 ? -1 : (dx > 0 ? 1 : 0); + } + } + + private static final class RingOrientationTestComparator extends + Treap.Comparator { + private OperatorSimplifyLocalHelper m_helper; + + RingOrientationTestComparator(OperatorSimplifyLocalHelper helper) { + m_helper = helper; + } + + @Override + int compare(/* const */Treap treap, int left, int node) { + int right = treap.getElement(node); + Edge edge1 = m_helper.m_edges.get(left); + Edge edge2 = m_helper.m_edges.get(right); + boolean bEdge1Reversed = edge1.getReversed(); + boolean bEdge2Reversed = edge2.getReversed(); + + double x1 = edge1.m_segment.intersectionOfYMonotonicWithAxisX( + m_helper.m_yScanline, 0); + double x2 = edge2.m_segment.intersectionOfYMonotonicWithAxisX( + m_helper.m_yScanline, 0); + + if (x1 == x2) { + // apparently these edges originate from same vertex and the + // scanline is on the vertex.move scanline a little. + double y1 = bEdge1Reversed ? edge1.m_segment.getStartY() + : edge1.m_segment.getEndY(); + double y2 = bEdge2Reversed ? edge2.m_segment.getStartY() + : edge2.m_segment.getEndY(); + double miny = Math.min(y1, y2); + double y = (miny - m_helper.m_yScanline) * 0.5 + + m_helper.m_yScanline; + if (y == m_helper.m_yScanline) { + // assert(0); //ST: not a bug. just curious to see this + // happens. + y = miny; // apparently, one of the segments is almost + // horizontal line. + } + x1 = edge1.m_segment.intersectionOfYMonotonicWithAxisX(y, 0); + x2 = edge2.m_segment.intersectionOfYMonotonicWithAxisX(y, 0); + assert (x1 != x2); + } + + return x1 < x2 ? -1 : (x1 > x2 ? 1 : 0); + } + } + + int multiPointIsSimpleAsFeature_() { + MultiVertexGeometryImpl multiVertexImpl = (MultiVertexGeometryImpl) m_geometry + ._getImpl(); + // sort lexicographically: by y,then by x, then by other attributes in + // the order. + // Go through the sorted list and make sure no points coincide exactly + // (no tolerance is taken into account). + int pointCount = multiVertexImpl.getPointCount(); + + AttributeStreamOfInt32 indices = new AttributeStreamOfInt32(0); + + for (int i = 0; i < pointCount; i++) { + indices.add(i); + } + + indices.Sort(0, pointCount, new MultiPointVertexComparer(this)); + + for (int i = 1; i < pointCount; i++) { + if (compareVerticesMultiPoint_(indices.get(i - 1), indices.get(i)) == 0) { + m_nonSimpleResult = new NonSimpleResult( + NonSimpleResult.Reason.Clustering, indices.get(i - 1), + indices.get(i)); + return 0;// points are coincident-simplify. + } + } + + return 2; + } + + int polylineIsSimpleAsFeature_() { + if (!checkStructure_()) + return 0; + // Non planar IsSimple. + // Go through all line segments and make sure no line segments are + // degenerate. + // Degenerate segment is the one which has its length shorter than + // tolerance or Z projection shorter than z tolerance. + return checkDegenerateSegments_(true) ? 2 : 0; + } + + int polygonIsSimpleAsFeature_() { + return isSimplePlanarImpl_(); + } + + MultiPoint multiPointSimplifyAsFeature_() { + MultiVertexGeometryImpl multiVertexImpl = (MultiVertexGeometryImpl) m_geometry + ._getImpl(); + // sort lexicographically:by y,then by x,then by other attributes in the + // order. + int pointCount = multiVertexImpl.getPointCount(); + assert (pointCount > 0); + + AttributeStreamOfInt32 indices = new AttributeStreamOfInt32(0); + + for (int i = 0; i < pointCount; i++) { + indices.add(i); + } + + indices.Sort(0, pointCount, new MultiPointVertexComparer2(this)); + + // Mark vertices that are unique + boolean[] indicesOut = new boolean[pointCount]; + + indicesOut[indices.get(0)] = true; + + for (int i = 1; i < pointCount; i++) { + int ind1 = indices.get(i - 1); + int ind2 = indices.get(i); + if (compareVerticesMultiPoint_(ind1, ind2) == 0) { + indicesOut[ind2] = false; + continue; + } + + indicesOut[ind2] = true; + } + + // get rid of non-unique vertices. + // We preserve the order of MultiPoint vertices.Among duplicate + // vertices,those that have + // higher index are deleted. + MultiPoint dst = (MultiPoint) m_geometry.createInstance(); + MultiPoint src = (MultiPoint) m_geometry; + int istart = 0; + int iend = 1; + for (int i = 0; i < pointCount; i++) { + if (indicesOut[i]) + iend = i + 1; + else { + if (istart < iend) { + dst.add(src, istart, iend); + } + + istart = i + 1; + } + } + + if (istart < iend) { + dst.add(src, istart, iend); + } + + ((MultiVertexGeometryImpl) dst._getImpl()).setIsSimple( + GeometryXSimple.Strong, m_toleranceSimplify, false); + return dst; + } + + Polyline polylineSimplifyAsFeature_() { + // Non planar simplify. + // Go through all line segments and make sure no line segments are + // degenerate. + // Degenerate segment is the one which has its length shorter than + // tolerance or Z projection shorter than z tolerance. + // The algorithm processes each path symmetrically from each end to + // ensure the result of simplify does not depend on the direction of the + // path. + + MultiPathImpl multiPathImpl = (MultiPathImpl) m_geometry._getImpl(); + SegmentIteratorImpl segIterFwd = multiPathImpl.querySegmentIterator(); + SegmentIteratorImpl segIterBwd = multiPathImpl.querySegmentIterator(); + Polyline dst = (Polyline) m_geometry.createInstance(); + Polyline src = (Polyline) m_geometry; + // Envelope2D env2D; + boolean bHasZ = multiPathImpl + .hasAttribute(VertexDescription.Semantics.Z); + double ztolerance = !bHasZ ? 0.0 : InternalUtils + .calculateZToleranceFromGeometry(m_sr, multiPathImpl, true); + AttributeStreamOfInt32 fwdStack = new AttributeStreamOfInt32(0); + AttributeStreamOfInt32 bwdStack = new AttributeStreamOfInt32(0); + fwdStack.reserve(multiPathImpl.getPointCount() / 2 + 1); + bwdStack.reserve(multiPathImpl.getPointCount() / 2 + 1); + while (segIterFwd.nextPath()) { + segIterBwd.nextPath(); + if (multiPathImpl.getPathSize(segIterFwd.getPathIndex()) < 2) + continue; + + segIterBwd.resetToLastSegment(); + double lengthFwd = 0; + double lengthBwd = 0; + boolean bFirst = true; + while (segIterFwd.hasNextSegment()) { + assert (segIterBwd.hasPreviousSegment()); + + /* const */Segment segFwd = segIterFwd.nextSegment(); + /* const */Segment segBwd = segIterBwd.previousSegment(); + + int idx1 = segIterFwd.getStartPointIndex(); + int idx2 = segIterBwd.getStartPointIndex(); + if (idx1 > idx2) + break; + + if (bFirst) { + // add the very first and the very last point indices + fwdStack.add(segIterFwd.getStartPointIndex());// first goes + // to + // fwdStack + bwdStack.add(segIterBwd.getEndPointIndex());// last goes to + // bwdStack + bFirst = false; + } + + { + int index0 = fwdStack.getLast(); + int index1 = segIterFwd.getEndPointIndex(); + if (index1 - index0 > 1) { + Point2D pt = new Point2D(); + pt.sub(multiPathImpl.getXY(index0), + multiPathImpl.getXY(index1)); + lengthFwd = pt.length(); + } else { + lengthFwd = segFwd.calculateLength2D(); + } + } + + { + int index0 = bwdStack.getLast(); + int index1 = segIterBwd.getStartPointIndex(); + if (index1 - index0 > 1) { + Point2D pt = new Point2D(); + pt.sub(multiPathImpl.getXY(index0), + multiPathImpl.getXY(index1)); + lengthBwd = pt.length(); + } else { + lengthBwd = segBwd.calculateLength2D(); + } + } + + if (lengthFwd > m_toleranceSimplify) { + fwdStack.add(segIterFwd.getEndPointIndex()); + lengthFwd = 0; + } else { + if (bHasZ) { + double z0 = multiPathImpl.getAttributeAsDbl( + VertexDescription.Semantics.Z, + fwdStack.getLast(), 0); + double z1 = segFwd.getEndAttributeAsDbl( + VertexDescription.Semantics.Z, 0); + if (Math.abs(z1 - z0) > ztolerance) { + fwdStack.add(segIterFwd.getEndPointIndex()); + lengthFwd = 0; + } + } + } + + if (lengthBwd > m_toleranceSimplify) { + bwdStack.add(segIterBwd.getStartPointIndex()); + lengthBwd = 0; + } else { + if (bHasZ) { + double z0 = multiPathImpl.getAttributeAsDbl( + VertexDescription.Semantics.Z, + bwdStack.getLast(), 0); + double z1 = segBwd.getEndAttributeAsDbl( + VertexDescription.Semantics.Z, 0); + if (Math.abs(z1 - z0) > ztolerance) { + bwdStack.add(segIterBwd.getStartPointIndex()); + lengthBwd = 0; + } + } + } + } + + // assert(fwdStack.getLast() <= bwdStack.getLast()); + if (fwdStack.getLast() < bwdStack.getLast()) { + // There is degenerate segment in the middle. Remove. + // If the path degenerate, this will make fwdStack.size() + + // bwdStack.size() < 2. + if (fwdStack.size() > bwdStack.size()) + fwdStack.removeLast(); + else + bwdStack.removeLast(); + } else if (fwdStack.getLast() == bwdStack.getLast()) { + bwdStack.removeLast(); + } else { + assert (fwdStack.getLast() - bwdStack.getLast() == 1); + bwdStack.removeLast(); + bwdStack.removeLast(); + } + + if (bwdStack.size() + fwdStack.size() >= 2) { + // Completely ignore the curves for now. + Point point = new Point(); + for (int i = 0, n = fwdStack.size(); i < n; i++) { + src.getPointByVal(fwdStack.get(i), point); + if (i == 0) + dst.startPath(point); + else + dst.lineTo(point); + } + + // int prevIdx = fwdStack.getLast(); + for (int i = bwdStack.size() - 1; i > 0; i--) { + src.getPointByVal(bwdStack.get(i), point); + dst.lineTo(point); + } + + if (src.isClosedPath(segIterFwd.getPathIndex())) { + dst.closePathWithLine(); + } else { + if (bwdStack.size() > 0) { + src.getPointByVal(bwdStack.get(0), point); + dst.lineTo(point); + } + } + } else { + // degenerate path won't be added + } + + if (fwdStack != null) + fwdStack.clear(false); + if (bwdStack != null) + bwdStack.clear(false); + } + + ((MultiVertexGeometryImpl) dst._getImpl()).setIsSimple( + GeometryXSimple.Strong, m_toleranceSimplify, false); + return dst; + } + + Polygon polygonSimplifyAsFeature_() { + return (Polygon) simplifyPlanar_(); + } + + MultiVertexGeometry simplifyPlanar_() { + // do clustering/cracking loop + // if (false) + // { + // ((MultiPathImpl)m_geometry._getImpl()).saveToTextFileDbg("c:/temp/_simplifyDbg0.txt"); + // } + + if (m_geometry.getType() == Geometry.Type.Polygon) { + if (((Polygon) m_geometry).getFillRule() == Polygon.FillRule.enumFillRuleWinding) { + // when the fill rule is winding, we need to call a special + // method. + return TopologicalOperations.planarSimplify( + (MultiVertexGeometry) m_geometry, m_toleranceSimplify, + true, false, m_progressTracker); + } + } + + m_editShape = new EditShape(); + m_editShape.addGeometry(m_geometry); + + if (m_editShape.getTotalPointCount() != 0) { + assert (m_knownSimpleResult != GeometryXSimple.Strong); + if (m_knownSimpleResult != GeometryXSimple.Weak) { + CrackAndCluster.execute(m_editShape, m_toleranceSimplify, + m_progressTracker, true); + } + + if (m_geometry.getType().equals(Geometry.Type.Polygon)) { + Simplificator.execute(m_editShape, m_editShape.getFirstGeometry(), + m_knownSimpleResult, false, m_progressTracker); + } + } + + m_geometry = m_editShape.getGeometry(m_editShape.getFirstGeometry()); // extract + // the + // result + // of + // simplify + + if (m_geometry.getType().equals(Geometry.Type.Polygon)) { + ((MultiPathImpl)m_geometry._getImpl())._updateOGCFlags(); + ((Polygon)m_geometry).setFillRule(Polygon.FillRule.enumFillRuleOddEven); + } + + // We have simplified the geometry using the given tolerance. Now mark + // the geometry as strong simple, + // So that the next call will not have to repeat these steps. + + ((MultiVertexGeometryImpl) m_geometry._getImpl()).setIsSimple( + GeometryXSimple.Strong, m_toleranceSimplify, false); + + return (MultiVertexGeometry) (m_geometry); + } + + NonSimpleResult m_nonSimpleResult; + + OperatorSimplifyLocalHelper(Geometry geometry, + SpatialReference spatialReference, int knownSimpleResult, + ProgressTracker progressTracker, boolean bOGCRestrictions) { + + m_description = geometry.getDescription(); + m_geometry = geometry; + m_sr = (SpatialReferenceImpl) spatialReference; + m_dbgCounter = 0; + m_toleranceIsSimple = InternalUtils.calculateToleranceFromGeometry( + m_sr, geometry, false); + m_toleranceSimplify = InternalUtils.calculateToleranceFromGeometry( + m_sr, geometry, true); + // m_toleranceCluster = m_toleranceSimplify * Math.sqrt(2.0) * 1.00001; + m_knownSimpleResult = knownSimpleResult; + m_attributeCount = m_description.getAttributeCount(); + m_edges = new ArrayList(); + m_lineEdgesRecycle = new ArrayList(); + m_crossOverHelperList = new IndexMultiDCList(); + m_AET = new Treap(); + m_nonSimpleResult = new NonSimpleResult(); + m_bOGCRestrictions = bOGCRestrictions; + m_bPlanarSimplify = m_bOGCRestrictions; + } + + // Returns 0 non-simple, 1 weak simple, 2 strong simple + /** + * The code is executed in the 2D plane only.Attributes are ignored. + * MultiPoint-check for clustering. Polyline -check for clustering and + * cracking. Polygon -check for clustering,cracking,absence of + * self-intersections,and correct ring ordering. + */ + static protected int isSimplePlanar(/* const */Geometry geometry, /* const */ + SpatialReference spatialReference, boolean bForce, + ProgressTracker progressTracker) { + assert (false); // this code is not called yet. + if (geometry.isEmpty()) + return 1; + Geometry.Type gt = geometry.getType(); + if (gt == Geometry.Type.Point) + return 1; + else if (gt == Geometry.Type.Envelope) { + Envelope2D env2D = new Envelope2D(); + geometry.queryEnvelope2D(env2D); + boolean bReturnValue = !env2D.isDegenerate(InternalUtils + .calculateToleranceFromGeometry(spatialReference, geometry, + false)); + return bReturnValue ? 1 : 0; + } else if (Geometry.isSegment(gt.value())) { + throw GeometryException.GeometryInternalError(); + // return seg.IsSimple(m_tolerance); + } else if (!Geometry.isMultiVertex(gt.value())) { + throw GeometryException.GeometryInternalError();// What else? + } + + double tolerance = InternalUtils.calculateToleranceFromGeometry( + spatialReference, geometry, false); + + double geomTolerance = 0; + int isSimple = ((MultiVertexGeometryImpl) geometry._getImpl()) + .getIsSimple(tolerance); + int knownSimpleResult = bForce ? -1 : isSimple; + // TODO: need to distinguish KnownSimple between SimpleAsFeature and + // SimplePlanar. The SimplePlanar implies SimpleAsFeature. + if (knownSimpleResult != -1) + return knownSimpleResult; + + if (knownSimpleResult == GeometryXSimple.Weak) { + assert (tolerance <= geomTolerance); + tolerance = geomTolerance;// OVERRIDE the tolerance. + } + + OperatorSimplifyLocalHelper helper = new OperatorSimplifyLocalHelper( + geometry, spatialReference, knownSimpleResult, progressTracker, + false); + knownSimpleResult = helper.isSimplePlanarImpl_(); + ((MultiVertexGeometryImpl) geometry._getImpl()).setIsSimple( + knownSimpleResult, tolerance, false); + return knownSimpleResult; + } + + /** + * Checks if Geometry is simple for storing in DB: + * + * MultiPoint:check that no points coincide.tolerance is ignored. + * Polyline:ensure there no segments degenerate segments. Polygon:Same as + * IsSimplePlanar. + */ + static protected int isSimpleAsFeature(/* const */Geometry geometry, /* const */ + SpatialReference spatialReference, boolean bForce, NonSimpleResult result, + ProgressTracker progressTracker) { + if (result != null) { + result.m_reason = NonSimpleResult.Reason.NotDetermined; + result.m_vertexIndex1 = -1; + result.m_vertexIndex2 = -1; + } + if (geometry.isEmpty()) + return 1; + Geometry.Type gt = geometry.getType(); + if (gt == Geometry.Type.Point) + return 1; + + double tolerance = InternalUtils.calculateToleranceFromGeometry( + spatialReference, geometry, false); + if (gt == Geometry.Type.Envelope) { + /* const */Envelope env = (Envelope) geometry; + Envelope2D env2D = new Envelope2D(); + env.queryEnvelope2D(env2D); + if (env2D.isDegenerate(tolerance)) { + if (result != null) { + result.m_reason = NonSimpleResult.Reason.DegenerateSegments; + result.m_vertexIndex1 = -1; + result.m_vertexIndex2 = -1; + } + return 0; + } + return 1; + } else if (Geometry.isSegment(gt.value())) { + /* const */Segment seg = (Segment) geometry; + Polyline polyline = new Polyline(seg.getDescription()); + polyline.addSegment(seg, true); + return isSimpleAsFeature(polyline, spatialReference, bForce, + result, progressTracker); + } + + // double geomTolerance = 0; + int isSimple = ((MultiVertexGeometryImpl) geometry._getImpl()) + .getIsSimple(tolerance); + int knownSimpleResult = bForce ? -1 : isSimple; + // TODO: need to distinguish KnownSimple between SimpleAsFeature and + // SimplePlanar. + // From the first sight it seems the SimplePlanar implies + // SimpleAsFeature. + if (knownSimpleResult != -1) + return knownSimpleResult; + + OperatorSimplifyLocalHelper helper = new OperatorSimplifyLocalHelper( + geometry, spatialReference, knownSimpleResult, progressTracker, + false); + + if (gt == Geometry.Type.MultiPoint) { + knownSimpleResult = helper.multiPointIsSimpleAsFeature_(); + } else if (gt == Geometry.Type.Polyline) { + knownSimpleResult = helper.polylineIsSimpleAsFeature_(); + } else if (gt == Geometry.Type.Polygon) { + knownSimpleResult = helper.polygonIsSimpleAsFeature_(); + } else { + throw GeometryException.GeometryInternalError();// what else? + } + + ((MultiVertexGeometryImpl) (geometry._getImpl())).setIsSimple( + knownSimpleResult, tolerance, false); + if (result != null && knownSimpleResult == 0) + result.Assign(helper.m_nonSimpleResult); + return knownSimpleResult; + } + + static int isSimpleOGC(/* const */Geometry geometry, /* const */ + SpatialReference spatialReference, boolean bForce, NonSimpleResult result, + ProgressTracker progressTracker) { + if (result != null) { + result.m_reason = NonSimpleResult.Reason.NotDetermined; + result.m_vertexIndex1 = -1; + result.m_vertexIndex2 = -1; + } + if (geometry.isEmpty()) + return 1; + Geometry.Type gt = geometry.getType(); + if (gt == Geometry.Type.Point) + return 1; + + double tolerance = InternalUtils.calculateToleranceFromGeometry( + spatialReference, geometry, false); + if (gt == Geometry.Type.Envelope) { + /* const */Envelope env = (Envelope) geometry; + Envelope2D env2D = new Envelope2D(); + env.queryEnvelope2D(env2D); + if (env2D.isDegenerate(tolerance)) { + if (result != null) { + result.m_reason = NonSimpleResult.Reason.DegenerateSegments; + result.m_vertexIndex1 = -1; + result.m_vertexIndex2 = -1; + } + return 0; + } + return 1; + } else if (Geometry.isSegment(gt.value())) { + /* const */Segment seg = (Segment) geometry; + Polyline polyline = new Polyline(seg.getDescription()); + polyline.addSegment(seg, true); + return isSimpleAsFeature(polyline, spatialReference, bForce, + result, progressTracker); + } + + int knownSimpleResult = -1; + + OperatorSimplifyLocalHelper helper = new OperatorSimplifyLocalHelper( + geometry, spatialReference, knownSimpleResult, progressTracker, + true); + + if (gt == Geometry.Type.MultiPoint || gt == Geometry.Type.Polyline + || gt == Geometry.Type.Polygon) { + knownSimpleResult = helper.isSimplePlanarImpl_(); + } else { + throw GeometryException.GeometryInternalError();// what else? + } + + if (result != null) + result.Assign(helper.m_nonSimpleResult); + + return knownSimpleResult; + } + + /** + * Simplifies geometries for storing in DB: + * + * MultiPoint:check that no points coincide.tolerance is ignored. + * Polyline:ensure there no segments degenerate segments. Polygon:cracks and + * clusters using cluster tolerance and resolves all self intersections, + * orients rings properly and arranges the rings in the OGC order. + * + * Returns simplified geometry. + */ + static protected Geometry simplifyAsFeature(/* const */Geometry geometry, /* const */ + SpatialReference spatialReference, boolean bForce, + ProgressTracker progressTracker) { + if (geometry.isEmpty()) + return geometry; + Geometry.Type gt = geometry.getType(); + if (gt == Geometry.Type.Point) + return geometry; + + double tolerance = InternalUtils.calculateToleranceFromGeometry( + spatialReference, geometry, false); + if (gt == Geometry.Type.Envelope) { + Envelope env = (Envelope) geometry; + Envelope2D env2D = new Envelope2D(); + env.queryEnvelope2D(env2D); + if (env2D.isDegenerate(tolerance)) { + return (Geometry) (env.createInstance()); // return empty + // geometry + } + return geometry; + } else if (Geometry.isSegment(gt.value())) { + Segment seg = (Segment) geometry; + Polyline polyline = new Polyline(seg.getDescription()); + polyline.addSegment(seg, true); + return simplifyAsFeature(polyline, spatialReference, bForce, + progressTracker); + } + + double geomTolerance = 0; + int isSimple = ((MultiVertexGeometryImpl) geometry._getImpl()) + .getIsSimple(tolerance); + int knownSimpleResult = bForce ? GeometryXSimple.Unknown : isSimple; + + // TODO: need to distinguish KnownSimple between SimpleAsFeature and + // SimplePlanar. + // From the first sight it seems the SimplePlanar implies + // SimpleAsFeature. + if (knownSimpleResult == GeometryXSimple.Strong) { + if (gt == Geometry.Type.Polygon && ((Polygon)geometry).getFillRule() != Polygon.FillRule.enumFillRuleOddEven) + { + Geometry res = geometry.copy(); + ((Polygon)res).setFillRule(Polygon.FillRule.enumFillRuleOddEven);//standardize on odd_even fill rule + return res; + } + + return geometry; + } + + OperatorSimplifyLocalHelper helper = new OperatorSimplifyLocalHelper( + geometry, spatialReference, knownSimpleResult, progressTracker, + false); + + Geometry result; + + if (gt == Geometry.Type.MultiPoint) { + result = (Geometry) (helper.multiPointSimplifyAsFeature_()); + } else if (gt == Geometry.Type.Polyline) { + result = (Geometry) (helper.polylineSimplifyAsFeature_()); + } else if (gt == Geometry.Type.Polygon) { + result = (Geometry) (helper.polygonSimplifyAsFeature_()); + } else { + throw GeometryException.GeometryInternalError(); // what else? + } + + return result; + } + + /** + * Simplifies geometries for storing in OGC format: + * + * MultiPoint:check that no points coincide.tolerance is ignored. + * Polyline:ensure there no segments degenerate segments. Polygon:cracks and + * clusters using cluster tolerance and resolves all self intersections, + * orients rings properly and arranges the rings in the OGC order. + * + * Returns simplified geometry. + */ + static Geometry simplifyOGC(/* const */Geometry geometry, /* const */ + SpatialReference spatialReference, boolean bForce, + ProgressTracker progressTracker) { + if (geometry.isEmpty()) + return geometry; + Geometry.Type gt = geometry.getType(); + if (gt == Geometry.Type.Point) + return geometry; + + double tolerance = InternalUtils.calculateToleranceFromGeometry( + spatialReference, geometry, false); + if (gt == Geometry.Type.Envelope) { + Envelope env = (Envelope) geometry; + Envelope2D env2D = new Envelope2D(); + env.queryEnvelope2D(env2D); + if (env2D.isDegenerate(tolerance)) { + return (Geometry) (env.createInstance()); // return empty + // geometry + } + return geometry; + } else if (Geometry.isSegment(gt.value())) { + Segment seg = (Segment) geometry; + Polyline polyline = new Polyline(seg.getDescription()); + polyline.addSegment(seg, true); + return simplifyOGC(polyline, spatialReference, bForce, + progressTracker); + } + + if (!Geometry.isMultiVertex(gt.value())) { + throw new GeometryException("OGC simplify is not implemented for this geometry type" + gt); + } + + MultiVertexGeometry result = TopologicalOperations.simplifyOGC( + (MultiVertexGeometry) geometry, tolerance, false, progressTracker); + + return result; + } + + private int compareVertices_(int i1, int i2, boolean get_paths) { + if (i1 == i2) + return 0; + + int pair1 = m_pairs.get(i1); + int pair2 = m_pairs.get(i2); + int xy1 = pair1 >> 1; + int xy2 = pair2 >> 1; + Point2D pt1 = new Point2D(); + Point2D pt2 = new Point2D(); + m_xy.read(2 * xy1, pt1); + pt1.y += (((pair1 & 1) != 0) ? m_toleranceIsSimple + : -m_toleranceIsSimple); + m_xy.read(2 * xy2, pt2); + pt2.y += (((pair2 & 1) != 0) ? m_toleranceIsSimple + : -m_toleranceIsSimple); + int res = pt1.compare(pt2); + if (res == 0 && get_paths) { + int di = m_paths_for_OGC_tests.get(xy1) + - m_paths_for_OGC_tests.get(xy2); + return di < 0 ? -1 : di > 0 ? 1 : 0; + } + return res; + } + + private static final class VertexComparer extends + AttributeStreamOfInt32.IntComparator { + OperatorSimplifyLocalHelper parent; + boolean get_paths; + + VertexComparer(OperatorSimplifyLocalHelper parent_, boolean get_paths_) { + parent = parent_; + get_paths = get_paths_; + } + + @Override + public int compare(int i1, int i2) { + return parent.compareVertices_(i1, i2, get_paths); + } + } + + private static final class IndexSorter extends ClassicSort { + OperatorSimplifyLocalHelper parent; + private boolean get_paths; + private Point2D pt1_dummy = new Point2D(); + + IndexSorter(OperatorSimplifyLocalHelper parent_, boolean get_paths_) { + parent = parent_; + get_paths = get_paths_; + } + + @Override + public void userSort(int begin, int end, AttributeStreamOfInt32 indices) { + indices.Sort(begin, end, new VertexComparer(parent, get_paths)); + } + + @Override + public double getValue(int index) /* const */ + { + int pair = parent.m_pairs.get(index); + int xy1 = pair >> 1; + parent.m_xy.read(2 * xy1, pt1_dummy); + double y = pt1_dummy.y + + (((pair & 1) != 0) ? parent.m_toleranceIsSimple + : -parent.m_toleranceIsSimple); + return y; + } + } + + private int compareVerticesMultiPoint_(int i1, int i2) { + if (i1 == i2) + return 0; + MultiVertexGeometryImpl multiVertexImpl = (MultiVertexGeometryImpl) m_geometry + ._getImpl(); + Point2D pt1 = multiVertexImpl.getXY(i1); + Point2D pt2 = multiVertexImpl.getXY(i2); + + if (pt1.x < pt2.x) + return -1; + if (pt1.x > pt2.x) + return 1; + if (pt1.y < pt2.y) + return -1; + if (pt1.y > pt2.y) + return 1; + + for (int attrib = 1; attrib < m_attributeCount; attrib++) { + int semantics = m_description.getSemantics(attrib); + int nords = VertexDescription.getComponentCount(semantics); + for (int ord = 0; ord < nords; ord++) { + double v1 = multiVertexImpl.getAttributeAsDbl(semantics, i1, + ord); + double v2 = multiVertexImpl.getAttributeAsDbl(semantics, i2, + ord); + if (v1 < v2) + return -1; + if (v1 > v2) + return 1; + } + } + + return 0; + } + + private int compareVerticesMultiPoint2_(int i1, int i2) { + int res = compareVerticesMultiPoint_(i1, i2); + if (res == 0) + return i1 < i2 ? -1 : 1; + else + return res; + } + + private static final class EdgeComparerForSelfIntersection implements + Comparator { + OperatorSimplifyLocalHelper parent; + + EdgeComparerForSelfIntersection(OperatorSimplifyLocalHelper parent_) { + parent = parent_; + } + + // Recall that the total ordering [<] induced by compare satisfies e1 + // [<] e2 if and only if compare(e1, e2) < 0. + + @Override + public int compare(Edge e1, Edge e2) { + return parent.edgeAngleCompare_(e1, e2); + } + } + + private static final class MultiPointVertexComparer extends + AttributeStreamOfInt32.IntComparator { + OperatorSimplifyLocalHelper parent; + + MultiPointVertexComparer(OperatorSimplifyLocalHelper parent_) { + parent = parent_; + } + + @Override + public int compare(int i1, int i2) { + return parent.compareVerticesMultiPoint_(i1, i2); + } + } + + private static final class MultiPointVertexComparer2 extends + AttributeStreamOfInt32.IntComparator { + OperatorSimplifyLocalHelper parent; + + MultiPointVertexComparer2(OperatorSimplifyLocalHelper parent_) { + parent = parent_; + } + + @Override + public int compare(int i1, int i2) { + return parent.compareVerticesMultiPoint2_(i1, i2); + } + } + + // compares angles between two edges + private int edgeAngleCompare_(/* const */Edge edge1, /* const */Edge edge2) { + if (edge1.equals(edge2)) + return 0; + + Point2D v1 = edge1.m_segment._getTangent(edge1.getReversed() ? 1.0 + : 0.0); + if (edge1.getReversed()) + v1.negate(); + Point2D v2 = edge2.m_segment._getTangent(edge2.getReversed() ? 1.0 + : 0.0); + if (edge2.getReversed()) + v2.negate(); + + int q1 = v1._getQuarter(); + int q2 = v2._getQuarter(); + + if (q2 == q1) { + double cross = v1.crossProduct(v2); + double crossError = 4 * NumberUtils.doubleEps() + * (Math.abs(v2.x * v1.y) + Math.abs(v2.y * v1.x)); + if (Math.abs(cross) <= crossError) { + cross--; // To avoid warning of "this line has no effect" from + // cross = cross. + cross++; + } + assert (Math.abs(cross) > crossError); + return cross < 0 ? 1 : (cross > 0 ? -1 : 0); + } else { + return q1 < q2 ? -1 : 1; + } + } }; diff --git a/src/main/java/com/esri/core/geometry/OperatorSimplifyLocalOGC.java b/src/main/java/com/esri/core/geometry/OperatorSimplifyLocalOGC.java index 1cdf3acf..f1f367fb 100644 --- a/src/main/java/com/esri/core/geometry/OperatorSimplifyLocalOGC.java +++ b/src/main/java/com/esri/core/geometry/OperatorSimplifyLocalOGC.java @@ -25,30 +25,30 @@ class OperatorSimplifyLocalOGC extends OperatorSimplifyOGC { - @Override - public GeometryCursor execute(GeometryCursor geoms, - SpatialReference spatialRef, boolean bForceSimplify, - ProgressTracker progressTracker) { - return new OperatorSimplifyCursorOGC(geoms, spatialRef, bForceSimplify, - progressTracker); - } - - @Override - public boolean isSimpleOGC(Geometry geom, SpatialReference spatialRef, - boolean bForceTest, NonSimpleResult result, - ProgressTracker progressTracker) { - int res = OperatorSimplifyLocalHelper.isSimpleOGC(geom, spatialRef, - bForceTest, result, progressTracker); - return res > 0; - } - - @Override - public Geometry execute(Geometry geom, SpatialReference spatialRef, - boolean bForceSimplify, ProgressTracker progressTracker) { - SimpleGeometryCursor inputCursor = new SimpleGeometryCursor(geom); - GeometryCursor outputCursor = execute(inputCursor, spatialRef, - bForceSimplify, progressTracker); - - return outputCursor.next(); - } + @Override + public GeometryCursor execute(GeometryCursor geoms, + SpatialReference spatialRef, boolean bForceSimplify, + ProgressTracker progressTracker) { + return new OperatorSimplifyCursorOGC(geoms, spatialRef, bForceSimplify, + progressTracker); + } + + @Override + public boolean isSimpleOGC(Geometry geom, SpatialReference spatialRef, + boolean bForceTest, NonSimpleResult result, + ProgressTracker progressTracker) { + int res = OperatorSimplifyLocalHelper.isSimpleOGC(geom, spatialRef, + bForceTest, result, progressTracker); + return res > 0; + } + + @Override + public Geometry execute(Geometry geom, SpatialReference spatialRef, + boolean bForceSimplify, ProgressTracker progressTracker) { + SimpleGeometryCursor inputCursor = new SimpleGeometryCursor(geom); + GeometryCursor outputCursor = execute(inputCursor, spatialRef, + bForceSimplify, progressTracker); + + return outputCursor.next(); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorSimplifyOGC.java b/src/main/java/com/esri/core/geometry/OperatorSimplifyOGC.java index 140a9259..478ef745 100644 --- a/src/main/java/com/esri/core/geometry/OperatorSimplifyOGC.java +++ b/src/main/java/com/esri/core/geometry/OperatorSimplifyOGC.java @@ -29,63 +29,63 @@ * Uses tolerance to determine equal vertices or points of intersection. */ public abstract class OperatorSimplifyOGC extends Operator { - @Override - public Operator.Type getType() { - return Operator.Type.SimplifyOGC; - } + @Override + public Operator.Type getType() { + return Operator.Type.SimplifyOGC; + } - /** - * Tests if the Geometry is simple for OGC specification. - * - * @param geom The Geometry to be tested. - * @param spatialRef Spatial reference to obtain the tolerance from. When null, the tolerance - * will be derived individually from geometry bounds. - * @param bForceTest When True, the Geometry will be tested regardless of the IsKnownSimple flag. - * @param progressTracker Allows cancellation of a long operation. Can be null. - *

- * Note: As other methods in the OperatorSimplifyOGC, this method uses tolerance from the spatial reference. - * Points that are within the tolerance are considered equal. - *

- * When this method returns true, the OperatorSimplify.isSimpleAsFeature will return true also (this does not necessary happen the other way around). - */ - public abstract boolean isSimpleOGC(Geometry geom, - SpatialReference spatialRef, boolean bForceTest, - NonSimpleResult result, ProgressTracker progressTracker); + /** + * Tests if the Geometry is simple for OGC specification. + * + * @param geom The Geometry to be tested. + * @param spatialRef Spatial reference to obtain the tolerance from. When null, the tolerance + * will be derived individually from geometry bounds. + * @param bForceTest When True, the Geometry will be tested regardless of the IsKnownSimple flag. + * @param progressTracker Allows cancellation of a long operation. Can be null. + *

+ * Note: As other methods in the OperatorSimplifyOGC, this method uses tolerance from the spatial reference. + * Points that are within the tolerance are considered equal. + *

+ * When this method returns true, the OperatorSimplify.isSimpleAsFeature will return true also (this does not necessary happen the other way around). + */ + public abstract boolean isSimpleOGC(Geometry geom, + SpatialReference spatialRef, boolean bForceTest, + NonSimpleResult result, ProgressTracker progressTracker); - /** - * Processes geometry cursor to ensure its geometries are simple for OGC specification. - * - * @param geoms Geometries to be simplified. - * @param sr Spatial reference to obtain the tolerance from. When null, the tolerance - * will be derived individually for each geometry from its bounds. - * @param bForceSimplify When True, the Geometry will be simplified regardless of the internal IsKnownSimple flag. - * @param progressTracker Allows cancellation of a long operation. Can be null. - * @return Returns a GeometryCursor of simplified geometries. - *

- * The isSimpleOGC returns true after this call. - */ - public abstract GeometryCursor execute(GeometryCursor geoms, - SpatialReference sr, boolean bForceSimplify, - ProgressTracker progressTracker); + /** + * Processes geometry cursor to ensure its geometries are simple for OGC specification. + * + * @param geoms Geometries to be simplified. + * @param sr Spatial reference to obtain the tolerance from. When null, the tolerance + * will be derived individually for each geometry from its bounds. + * @param bForceSimplify When True, the Geometry will be simplified regardless of the internal IsKnownSimple flag. + * @param progressTracker Allows cancellation of a long operation. Can be null. + * @return Returns a GeometryCursor of simplified geometries. + *

+ * The isSimpleOGC returns true after this call. + */ + public abstract GeometryCursor execute(GeometryCursor geoms, + SpatialReference sr, boolean bForceSimplify, + ProgressTracker progressTracker); - /** - * Processes geometry to ensure it is simple for OGC specification. - * - * @param geom The geometry to be simplified. - * @param sr Spatial reference to obtain the tolerance from. When null, the tolerance - * will be derived individually from geometry bounds. - * @param bForceSimplify When True, the Geometry will be simplified regardless of the internal IsKnownSimple flag. - * @param progressTracker Allows cancellation of a long operation. Can be null. - * @return Returns a simple Geometry that should be visually equivalent to the input geometry. - *

- * The isSimpleOGC returns true after this call. - */ - public abstract Geometry execute(Geometry geom, SpatialReference sr, - boolean bForceSimplify, ProgressTracker progressTracker); + /** + * Processes geometry to ensure it is simple for OGC specification. + * + * @param geom The geometry to be simplified. + * @param sr Spatial reference to obtain the tolerance from. When null, the tolerance + * will be derived individually from geometry bounds. + * @param bForceSimplify When True, the Geometry will be simplified regardless of the internal IsKnownSimple flag. + * @param progressTracker Allows cancellation of a long operation. Can be null. + * @return Returns a simple Geometry that should be visually equivalent to the input geometry. + *

+ * The isSimpleOGC returns true after this call. + */ + public abstract Geometry execute(Geometry geom, SpatialReference sr, + boolean bForceSimplify, ProgressTracker progressTracker); - public static OperatorSimplifyOGC local() { - return (OperatorSimplifyOGC) OperatorFactoryLocal.getInstance() - .getOperator(Type.SimplifyOGC); - } + public static OperatorSimplifyOGC local() { + return (OperatorSimplifyOGC) OperatorFactoryLocal.getInstance() + .getOperator(Type.SimplifyOGC); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorSymmetricDifference.java b/src/main/java/com/esri/core/geometry/OperatorSymmetricDifference.java index f31b7178..f8a17117 100644 --- a/src/main/java/com/esri/core/geometry/OperatorSymmetricDifference.java +++ b/src/main/java/com/esri/core/geometry/OperatorSymmetricDifference.java @@ -29,38 +29,38 @@ * Symmetric difference (XOR) operation between geometries. */ public abstract class OperatorSymmetricDifference extends Operator implements CombineOperator { - @Override - public Type getType() { - return Type.Difference; - } + @Override + public Type getType() { + return Type.Difference; + } - /** - * Performs the Symmetric Difference operation on the geometry set. - * - * @param inputGeometries is the set of Geometry instances to be XOR'd by rightGeometry. - * @param rightGeometry is the Geometry being XOR'd with the inputGeometies. - * @return Returns the result of the symmetric difference. - *

- * The operator XOR's every geometry in inputGeometries with rightGeometry. - */ - public abstract GeometryCursor execute(GeometryCursor inputGeometries, - GeometryCursor rightGeometry, SpatialReference sr, - ProgressTracker progressTracker); + /** + * Performs the Symmetric Difference operation on the geometry set. + * + * @param inputGeometries is the set of Geometry instances to be XOR'd by rightGeometry. + * @param rightGeometry is the Geometry being XOR'd with the inputGeometies. + * @return Returns the result of the symmetric difference. + *

+ * The operator XOR's every geometry in inputGeometries with rightGeometry. + */ + public abstract GeometryCursor execute(GeometryCursor inputGeometries, + GeometryCursor rightGeometry, SpatialReference sr, + ProgressTracker progressTracker); - /** - * Performs the Symmetric Difference operation on the two geometries. - * - * @param leftGeometry is one of the Geometry instances in the XOR operation. - * @param rightGeometry is one of the Geometry instances in the XOR operation. - * @return Returns the result of the symmetric difference. - */ - public abstract Geometry execute(Geometry leftGeometry, - Geometry rightGeometry, SpatialReference sr, - ProgressTracker progressTracker); + /** + * Performs the Symmetric Difference operation on the two geometries. + * + * @param leftGeometry is one of the Geometry instances in the XOR operation. + * @param rightGeometry is one of the Geometry instances in the XOR operation. + * @return Returns the result of the symmetric difference. + */ + public abstract Geometry execute(Geometry leftGeometry, + Geometry rightGeometry, SpatialReference sr, + ProgressTracker progressTracker); - public static OperatorSymmetricDifference local() { - return (OperatorSymmetricDifference) OperatorFactoryLocal.getInstance() - .getOperator(Type.SymmetricDifference); - } + public static OperatorSymmetricDifference local() { + return (OperatorSymmetricDifference) OperatorFactoryLocal.getInstance() + .getOperator(Type.SymmetricDifference); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorSymmetricDifferenceCursor.java b/src/main/java/com/esri/core/geometry/OperatorSymmetricDifferenceCursor.java index 647ca21f..302648db 100644 --- a/src/main/java/com/esri/core/geometry/OperatorSymmetricDifferenceCursor.java +++ b/src/main/java/com/esri/core/geometry/OperatorSymmetricDifferenceCursor.java @@ -24,34 +24,34 @@ package com.esri.core.geometry; public class OperatorSymmetricDifferenceCursor extends GeometryCursor { - ProgressTracker m_progress_tracker; - SpatialReference m_spatial_reference; - Geometry m_rightGeom; - boolean m_bEmpty; - - OperatorSymmetricDifferenceCursor(GeometryCursor inputGeoms, - GeometryCursor rightGeom, SpatialReference sr, - ProgressTracker progress_tracker) { - m_bEmpty = rightGeom == null; - m_inputGeoms = inputGeoms; - m_spatial_reference = sr; - m_rightGeom = rightGeom.next(); - m_progress_tracker = progress_tracker; - } - - @Override - public Geometry next() { - if (m_bEmpty) - return null; - - if (hasNext()) { - return OperatorSymmetricDifferenceLocal.symmetricDifference( - m_inputGeoms.next(), - m_rightGeom, - m_spatial_reference, - m_progress_tracker); - } - - return null; - } + ProgressTracker m_progress_tracker; + SpatialReference m_spatial_reference; + Geometry m_rightGeom; + boolean m_bEmpty; + + OperatorSymmetricDifferenceCursor(GeometryCursor inputGeoms, + GeometryCursor rightGeom, SpatialReference sr, + ProgressTracker progress_tracker) { + m_bEmpty = rightGeom == null; + m_inputGeoms = inputGeoms; + m_spatial_reference = sr; + m_rightGeom = rightGeom.next(); + m_progress_tracker = progress_tracker; + } + + @Override + public Geometry next() { + if (m_bEmpty) + return null; + + if (hasNext()) { + return OperatorSymmetricDifferenceLocal.symmetricDifference( + m_inputGeoms.next(), + m_rightGeom, + m_spatial_reference, + m_progress_tracker); + } + + return null; + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorSymmetricDifferenceLocal.java b/src/main/java/com/esri/core/geometry/OperatorSymmetricDifferenceLocal.java index 0fb12613..0a6a0374 100644 --- a/src/main/java/com/esri/core/geometry/OperatorSymmetricDifferenceLocal.java +++ b/src/main/java/com/esri/core/geometry/OperatorSymmetricDifferenceLocal.java @@ -25,144 +25,144 @@ class OperatorSymmetricDifferenceLocal extends OperatorSymmetricDifference { - @Override - public GeometryCursor execute(GeometryCursor inputGeometries, - GeometryCursor rightGeometry, SpatialReference sr, - ProgressTracker progressTracker) { - return new OperatorSymmetricDifferenceCursor(inputGeometries, - rightGeometry, sr, progressTracker); - } - - @Override - public Geometry execute(Geometry leftGeometry, Geometry rightGeometry, - SpatialReference sr, ProgressTracker progressTracker) { - SimpleGeometryCursor leftGeomCurs = new SimpleGeometryCursor( - leftGeometry); - SimpleGeometryCursor rightGeomCurs = new SimpleGeometryCursor( - rightGeometry); - GeometryCursor geometryCursor = execute(leftGeomCurs, rightGeomCurs, - sr, progressTracker); - return geometryCursor.next(); - } - - static Geometry symmetricDifference(Geometry geometry_a, - Geometry geometry_b, SpatialReference spatial_reference, - ProgressTracker progress_tracker) { - int dim_a = geometry_a.getDimension(); - int dim_b = geometry_b.getDimension(); - - if (geometry_a.isEmpty() && geometry_b.isEmpty()) - return dim_a > dim_b ? geometry_a : geometry_b; - - if (geometry_a.isEmpty()) - return geometry_b; - if (geometry_b.isEmpty()) - return geometry_a; - - Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(), env_merged = new Envelope2D(); - geometry_a.queryEnvelope2D(env_a); - geometry_b.queryEnvelope2D(env_b); - env_merged.setCoords(env_a); - env_merged.merge(env_b); - - double tolerance = InternalUtils.calculateToleranceFromGeometry( - spatial_reference, env_merged, false); - - int type_a = geometry_a.getType().value(); - int type_b = geometry_b.getType().value(); - - if (type_a == Geometry.GeometryType.Point - && type_b == Geometry.GeometryType.Point) - return pointSymDiffPoint_((Point) (geometry_a), - (Point) (geometry_b), tolerance, progress_tracker); - - if (type_a != type_b) { - if (dim_a > 0 || dim_b > 0) - return dim_a > dim_b ? geometry_a : geometry_b; - - // Multi_point/Point case - - if (type_a == Geometry.GeometryType.MultiPoint) - return multiPointSymDiffPoint_((MultiPoint) (geometry_a), - (Point) (geometry_b), tolerance, progress_tracker); - - return multiPointSymDiffPoint_((MultiPoint) (geometry_b), - (Point) (geometry_a), tolerance, progress_tracker); - } - - return TopologicalOperations.symmetricDifference(geometry_a, - geometry_b, spatial_reference, progress_tracker); - } - - static Geometry pointSymDiffPoint_(Point point_a, Point point_b, - double tolerance, ProgressTracker progress_tracker) { - double tolerance_cluster = tolerance * Math.sqrt(2.0) * 1.00001; - double tolerance_cluster_sq = tolerance_cluster * tolerance_cluster; - - Point2D pt_a = point_a.getXY(); - Point2D pt_b = point_b.getXY(); - - MultiPoint multi_point = new MultiPoint(point_a.getDescription()); - - if (Point2D.sqrDistance(pt_a, pt_b) > tolerance_cluster_sq) { - multi_point.add(point_a); - multi_point.add(point_b); - } - - return multi_point; - } - - static Geometry multiPointSymDiffPoint_(MultiPoint multi_point, - Point point, double tolerance, ProgressTracker progress_tracker) { - MultiPointImpl multipointImpl = (MultiPointImpl) (multi_point - ._getImpl()); - AttributeStreamOfDbl position = (AttributeStreamOfDbl) (multipointImpl - .getAttributeStreamRef(VertexDescription.Semantics.POSITION)); - int point_count = multi_point.getPointCount(); - Point2D point2D = point.getXY(); - - MultiPoint new_multipoint = (MultiPoint) (multi_point.createInstance()); - double tolerance_cluster = tolerance * Math.sqrt(2.0) * 1.00001; - - Envelope2D env = new Envelope2D(); - multi_point.queryEnvelope2D(env); - env.inflate(tolerance_cluster, tolerance_cluster); - - if (env.contains(point2D)) { - double tolerance_cluster_sq = tolerance_cluster * tolerance_cluster; - - boolean b_found_covered = false; - boolean[] covered = new boolean[point_count]; - for (int i = 0; i < point_count; i++) - covered[i] = false; - - for (int i = 0; i < point_count; i++) { - double x = position.read(2 * i); - double y = position.read(2 * i + 1); - - double dx = x - point2D.x; - double dy = y - point2D.y; - - if (dx * dx + dy * dy <= tolerance_cluster_sq) { - b_found_covered = true; - covered[i] = true; - } - } - - if (!b_found_covered) { - new_multipoint.add(multi_point, 0, point_count); - new_multipoint.add(point); - } else { - for (int i = 0; i < point_count; i++) { - if (!covered[i]) - new_multipoint.add(multi_point, i, i + 1); - } - } - } else { - new_multipoint.add(multi_point, 0, point_count); - new_multipoint.add(point); - } - - return new_multipoint; - } + @Override + public GeometryCursor execute(GeometryCursor inputGeometries, + GeometryCursor rightGeometry, SpatialReference sr, + ProgressTracker progressTracker) { + return new OperatorSymmetricDifferenceCursor(inputGeometries, + rightGeometry, sr, progressTracker); + } + + @Override + public Geometry execute(Geometry leftGeometry, Geometry rightGeometry, + SpatialReference sr, ProgressTracker progressTracker) { + SimpleGeometryCursor leftGeomCurs = new SimpleGeometryCursor( + leftGeometry); + SimpleGeometryCursor rightGeomCurs = new SimpleGeometryCursor( + rightGeometry); + GeometryCursor geometryCursor = execute(leftGeomCurs, rightGeomCurs, + sr, progressTracker); + return geometryCursor.next(); + } + + static Geometry symmetricDifference(Geometry geometry_a, + Geometry geometry_b, SpatialReference spatial_reference, + ProgressTracker progress_tracker) { + int dim_a = geometry_a.getDimension(); + int dim_b = geometry_b.getDimension(); + + if (geometry_a.isEmpty() && geometry_b.isEmpty()) + return dim_a > dim_b ? geometry_a : geometry_b; + + if (geometry_a.isEmpty()) + return geometry_b; + if (geometry_b.isEmpty()) + return geometry_a; + + Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(), env_merged = new Envelope2D(); + geometry_a.queryEnvelope2D(env_a); + geometry_b.queryEnvelope2D(env_b); + env_merged.setCoords(env_a); + env_merged.merge(env_b); + + double tolerance = InternalUtils.calculateToleranceFromGeometry( + spatial_reference, env_merged, false); + + int type_a = geometry_a.getType().value(); + int type_b = geometry_b.getType().value(); + + if (type_a == Geometry.GeometryType.Point + && type_b == Geometry.GeometryType.Point) + return pointSymDiffPoint_((Point) (geometry_a), + (Point) (geometry_b), tolerance, progress_tracker); + + if (type_a != type_b) { + if (dim_a > 0 || dim_b > 0) + return dim_a > dim_b ? geometry_a : geometry_b; + + // Multi_point/Point case + + if (type_a == Geometry.GeometryType.MultiPoint) + return multiPointSymDiffPoint_((MultiPoint) (geometry_a), + (Point) (geometry_b), tolerance, progress_tracker); + + return multiPointSymDiffPoint_((MultiPoint) (geometry_b), + (Point) (geometry_a), tolerance, progress_tracker); + } + + return TopologicalOperations.symmetricDifference(geometry_a, + geometry_b, spatial_reference, progress_tracker); + } + + static Geometry pointSymDiffPoint_(Point point_a, Point point_b, + double tolerance, ProgressTracker progress_tracker) { + double tolerance_cluster = tolerance * Math.sqrt(2.0) * 1.00001; + double tolerance_cluster_sq = tolerance_cluster * tolerance_cluster; + + Point2D pt_a = point_a.getXY(); + Point2D pt_b = point_b.getXY(); + + MultiPoint multi_point = new MultiPoint(point_a.getDescription()); + + if (Point2D.sqrDistance(pt_a, pt_b) > tolerance_cluster_sq) { + multi_point.add(point_a); + multi_point.add(point_b); + } + + return multi_point; + } + + static Geometry multiPointSymDiffPoint_(MultiPoint multi_point, + Point point, double tolerance, ProgressTracker progress_tracker) { + MultiPointImpl multipointImpl = (MultiPointImpl) (multi_point + ._getImpl()); + AttributeStreamOfDbl position = (AttributeStreamOfDbl) (multipointImpl + .getAttributeStreamRef(VertexDescription.Semantics.POSITION)); + int point_count = multi_point.getPointCount(); + Point2D point2D = point.getXY(); + + MultiPoint new_multipoint = (MultiPoint) (multi_point.createInstance()); + double tolerance_cluster = tolerance * Math.sqrt(2.0) * 1.00001; + + Envelope2D env = new Envelope2D(); + multi_point.queryEnvelope2D(env); + env.inflate(tolerance_cluster, tolerance_cluster); + + if (env.contains(point2D)) { + double tolerance_cluster_sq = tolerance_cluster * tolerance_cluster; + + boolean b_found_covered = false; + boolean[] covered = new boolean[point_count]; + for (int i = 0; i < point_count; i++) + covered[i] = false; + + for (int i = 0; i < point_count; i++) { + double x = position.read(2 * i); + double y = position.read(2 * i + 1); + + double dx = x - point2D.x; + double dy = y - point2D.y; + + if (dx * dx + dy * dy <= tolerance_cluster_sq) { + b_found_covered = true; + covered[i] = true; + } + } + + if (!b_found_covered) { + new_multipoint.add(multi_point, 0, point_count); + new_multipoint.add(point); + } else { + for (int i = 0; i < point_count; i++) { + if (!covered[i]) + new_multipoint.add(multi_point, i, i + 1); + } + } + } else { + new_multipoint.add(multi_point, 0, point_count); + new_multipoint.add(point); + } + + return new_multipoint; + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorTouches.java b/src/main/java/com/esri/core/geometry/OperatorTouches.java index a4c07d81..172f4f28 100644 --- a/src/main/java/com/esri/core/geometry/OperatorTouches.java +++ b/src/main/java/com/esri/core/geometry/OperatorTouches.java @@ -30,14 +30,14 @@ * Relational operation Touches. */ public abstract class OperatorTouches extends OperatorSimpleRelation { - @Override - public Type getType() { - return Type.Touches; - } - - public static OperatorTouches local() { - return (OperatorTouches) OperatorFactoryLocal.getInstance() - .getOperator(Type.Touches); - } + @Override + public Type getType() { + return Type.Touches; + } + + public static OperatorTouches local() { + return (OperatorTouches) OperatorFactoryLocal.getInstance() + .getOperator(Type.Touches); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorTouchesLocal.java b/src/main/java/com/esri/core/geometry/OperatorTouchesLocal.java index ac5b852d..2e2227f0 100644 --- a/src/main/java/com/esri/core/geometry/OperatorTouchesLocal.java +++ b/src/main/java/com/esri/core/geometry/OperatorTouchesLocal.java @@ -25,11 +25,11 @@ package com.esri.core.geometry; class OperatorTouchesLocal extends OperatorTouches { - @Override - public boolean execute(Geometry inputGeom1, Geometry inputGeom2, - SpatialReference sr, ProgressTracker progressTracker) { - return RelationalOperations.relate(inputGeom1, inputGeom2, sr, - RelationalOperations.Relation.touches, progressTracker); - } + @Override + public boolean execute(Geometry inputGeom1, Geometry inputGeom2, + SpatialReference sr, ProgressTracker progressTracker) { + return RelationalOperations.relate(inputGeom1, inputGeom2, sr, + RelationalOperations.Relation.touches, progressTracker); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorUnion.java b/src/main/java/com/esri/core/geometry/OperatorUnion.java index d83c6887..4de6a2cf 100644 --- a/src/main/java/com/esri/core/geometry/OperatorUnion.java +++ b/src/main/java/com/esri/core/geometry/OperatorUnion.java @@ -30,30 +30,30 @@ * Union of geometries. */ public abstract class OperatorUnion extends Operator implements CombineOperator { - @Override - public Type getType() { - return Type.Union; - } - - /** - * Performs the Topological Union operation on the geometry set. - * - * @param inputGeometries is the set of Geometry instances to be unioned. - */ - public abstract GeometryCursor execute(GeometryCursor inputGeometries, - SpatialReference sr, ProgressTracker progressTracker); - - /** - * Performs the Topological Union operation on two geometries. - * - * @param geom1 and geom2 are the geometry instances to be unioned. - */ - public abstract Geometry execute(Geometry geom1, Geometry geom2, - SpatialReference sr, ProgressTracker progressTracker); - - public static OperatorUnion local() { - return (OperatorUnion) OperatorFactoryLocal.getInstance().getOperator( - Type.Union); - } + @Override + public Type getType() { + return Type.Union; + } + + /** + * Performs the Topological Union operation on the geometry set. + * + * @param inputGeometries is the set of Geometry instances to be unioned. + */ + public abstract GeometryCursor execute(GeometryCursor inputGeometries, + SpatialReference sr, ProgressTracker progressTracker); + + /** + * Performs the Topological Union operation on two geometries. + * + * @param geom1 and geom2 are the geometry instances to be unioned. + */ + public abstract Geometry execute(Geometry geom1, Geometry geom2, + SpatialReference sr, ProgressTracker progressTracker); + + public static OperatorUnion local() { + return (OperatorUnion) OperatorFactoryLocal.getInstance().getOperator( + Type.Union); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorUnionCursor.java b/src/main/java/com/esri/core/geometry/OperatorUnionCursor.java index f18fa633..dfc66bcc 100644 --- a/src/main/java/com/esri/core/geometry/OperatorUnionCursor.java +++ b/src/main/java/com/esri/core/geometry/OperatorUnionCursor.java @@ -30,264 +30,264 @@ import java.util.TreeMap; public final class OperatorUnionCursor extends GeometryCursor { - private ProgressTracker m_progress_tracker; - private SpatialReferenceImpl m_spatial_reference; - private boolean m_b_done = false; - private boolean[] m_had_geometry = new boolean[4]; - private int[] m_dim_geom_counts = new int[4]; - private boolean m_b_union_all_dimensions = false; - private int m_max_dimension = -1; - private int m_added_geoms = 0; - private int m_current_dim = -1; - - private final static class Geom_pair { - void init() { - geom = null; - vertex_count = -1; - unioned = false; - } - - Geometry geom; - int vertex_count; - boolean unioned;//true if geometry is a result of union operation - } - - final static class Bin_type //bin array and the total vertex count in the bin - { - int bin_vertex_count = 0; - ArrayList geometries = new ArrayList(); - - void add_pair(Geom_pair geom) { - bin_vertex_count += geom.vertex_count; - geometries.add(geom); - } - - void pop_pair() { - bin_vertex_count -= geometries.get(geometries.size() - 1).vertex_count; - geometries.remove(geometries.size() - 1); - } - - Geom_pair back_pair() { - return geometries.get(geometries.size() - 1); - } - - int geom_count() { - return geometries.size(); - } - } - - ArrayList> m_union_bins = new ArrayList>();//for each dimension there is a list of bins sorted by level - - OperatorUnionCursor(GeometryCursor inputGeoms, SpatialReference sr, - ProgressTracker progress_tracker) { - m_inputGeoms = inputGeoms; - m_spatial_reference = (SpatialReferenceImpl) (sr); - m_progress_tracker = progress_tracker; - } - - private Geometry get_result_geometry(int dim) { - assert (m_dim_geom_counts[dim] > 0); - java.util.TreeMap map = m_union_bins.get(dim); - Map.Entry e = map.firstEntry(); - Bin_type bin = e.getValue(); - - Geometry resG; - resG = bin.back_pair().geom; - boolean unioned = bin.back_pair().unioned; - map.remove(e.getKey()); - - if (unioned) { - resG = OperatorSimplify.local().execute(resG, m_spatial_reference, - false, m_progress_tracker); - if (dim == 0 && resG.getType() == Geometry.Type.Point) {// must - // return - // multipoint - // for - // points - MultiPoint mp = new MultiPoint(resG.getDescription()); - if (!resG.isEmpty()) - mp.add((Point) resG); - - resG = mp; - } - } - - return resG; - } - - @Override - public Geometry next() { - if (m_b_done && m_current_dim == m_max_dimension) - return null; - - while (!step_()) { - } - - if (m_max_dimension == -1) - return null;// empty input cursor - - if (m_b_union_all_dimensions) { - m_current_dim++; - while (true) { - if (m_current_dim > m_max_dimension || m_current_dim < 0) - throw GeometryException.GeometryInternalError(); - - if (m_had_geometry[m_current_dim]) - break; - } - - return get_result_geometry(m_current_dim); - } else { - assert (m_max_dimension >= 0); - m_current_dim = m_max_dimension; - return get_result_geometry(m_max_dimension); - } - } - - private boolean step_() { - if (m_b_done) - return true; - - Geometry geom = null; - if (m_inputGeoms != null) { - geom = m_inputGeoms.next(); - if (geom == null) { - m_b_done = true; - } - } - - ProgressTracker.checkAndThrow(m_progress_tracker); - - if (geom != null) { - int dim = geom.getDimension(); - m_had_geometry[dim] = true; - if (dim >= m_max_dimension && !m_b_union_all_dimensions) { - add_geom(dim, false, geom); - if (dim > m_max_dimension && !m_b_union_all_dimensions) { - //this geometry has higher dimension than the previously processed one - //Therefore we delete all lower dimensions (unless m_b_union_all_dimensions is true). - remove_all_bins_with_lower_dimension(dim); - } - } else { - //this geometry is skipped - } - } else { - //geom is null. do nothing - } - - if (m_added_geoms > 0) { - for (int dim = 0; dim <= m_max_dimension; dim++) { - while (m_dim_geom_counts[dim] > 1) { - ArrayList batch_to_union = collect_geometries_to_union(dim); - boolean serial_execution = true; - if (serial_execution) { - if (batch_to_union.size() != 0) { - Geometry geomRes = TopologicalOperations - .dissolveDirty(batch_to_union, - m_spatial_reference, - m_progress_tracker); - add_geom(dim, true, geomRes); - } else { - break; - } - } - } - } - } - - return m_b_done; - } - - ArrayList collect_geometries_to_union(int dim) { - ArrayList batch_to_union = new ArrayList(); - ArrayList> entriesToRemove = new ArrayList>(); - Set> set = m_union_bins.get(dim) - .entrySet(); - for (Map.Entry e : set) { - //int level = e.getKey(); - Bin_type bin = e.getValue(); - - final int binVertexThreshold = 10000; - - if (m_b_done - || (bin.bin_vertex_count > binVertexThreshold && bin - .geom_count() > 1)) { - m_dim_geom_counts[dim] -= bin.geom_count(); - m_added_geoms -= bin.geom_count(); - while (bin.geometries.size() > 0) { - // empty geometries will be unioned too. - batch_to_union.add(bin.back_pair().geom); - bin.pop_pair(); - } - - entriesToRemove.add(e); - } - } - - set.removeAll(entriesToRemove); - return batch_to_union; - } - - private void remove_all_bins_with_lower_dimension(int dim) { - // this geometry has higher dimension than the previously processed one - for (int i = 0; i < dim; i++) { - m_union_bins.get(i).clear(); - m_added_geoms -= m_dim_geom_counts[i]; - m_dim_geom_counts[i] = 0; - } - } - - private void add_geom(int dimension, boolean unioned, Geometry geom) { - Geom_pair pair = new Geom_pair(); - pair.init(); - pair.geom = geom; - int sz = get_vertex_count_(geom); - pair.vertex_count = sz; - int level = get_level_(sz); - if (dimension + 1 > (int) m_union_bins.size()) { - for (int i = 0, n = Math.max(2, dimension + 1); i < n; i++) { - m_union_bins.add(new TreeMap()); - } - } - - Bin_type bin = m_union_bins.get(dimension).get(level);//return null if level is abscent - if (bin == null) { - bin = new Bin_type(); - m_union_bins.get(dimension).put(level, bin); - } - - pair.unioned = unioned; - bin.add_pair(pair); - - // Update global cursor state - m_dim_geom_counts[dimension]++; - m_added_geoms++; - m_max_dimension = Math.max(m_max_dimension, dimension); - } - - private static int get_level_(int sz) {// calculates logarithm of sz to base - // 4. - return sz > 0 ? (int) (Math.log((double) sz) / Math.log(4.0) + 0.5) - : (int) 0; - } - - private static int get_vertex_count_(Geometry geom) { - int gt = geom.getType().value(); - if (Geometry.isMultiVertex(gt)) { - return ((MultiVertexGeometry) geom).getPointCount(); - } else if (gt == Geometry.GeometryType.Point) { - return 1; - } else if (gt == Geometry.GeometryType.Envelope) { - return 4; - } else if (Geometry.isSegment(gt)) { - return 2; - } else { - throw GeometryException.GeometryInternalError(); - } - } - - @Override - public boolean tock() { - return step_(); - } + private ProgressTracker m_progress_tracker; + private SpatialReferenceImpl m_spatial_reference; + private boolean m_b_done = false; + private boolean[] m_had_geometry = new boolean[4]; + private int[] m_dim_geom_counts = new int[4]; + private boolean m_b_union_all_dimensions = false; + private int m_max_dimension = -1; + private int m_added_geoms = 0; + private int m_current_dim = -1; + + private final static class Geom_pair { + void init() { + geom = null; + vertex_count = -1; + unioned = false; + } + + Geometry geom; + int vertex_count; + boolean unioned;//true if geometry is a result of union operation + } + + final static class Bin_type //bin array and the total vertex count in the bin + { + int bin_vertex_count = 0; + ArrayList geometries = new ArrayList(); + + void add_pair(Geom_pair geom) { + bin_vertex_count += geom.vertex_count; + geometries.add(geom); + } + + void pop_pair() { + bin_vertex_count -= geometries.get(geometries.size() - 1).vertex_count; + geometries.remove(geometries.size() - 1); + } + + Geom_pair back_pair() { + return geometries.get(geometries.size() - 1); + } + + int geom_count() { + return geometries.size(); + } + } + + ArrayList> m_union_bins = new ArrayList>();//for each dimension there is a list of bins sorted by level + + OperatorUnionCursor(GeometryCursor inputGeoms, SpatialReference sr, + ProgressTracker progress_tracker) { + m_inputGeoms = inputGeoms; + m_spatial_reference = (SpatialReferenceImpl) (sr); + m_progress_tracker = progress_tracker; + } + + private Geometry get_result_geometry(int dim) { + assert (m_dim_geom_counts[dim] > 0); + java.util.TreeMap map = m_union_bins.get(dim); + Map.Entry e = map.firstEntry(); + Bin_type bin = e.getValue(); + + Geometry resG; + resG = bin.back_pair().geom; + boolean unioned = bin.back_pair().unioned; + map.remove(e.getKey()); + + if (unioned) { + resG = OperatorSimplify.local().execute(resG, m_spatial_reference, + false, m_progress_tracker); + if (dim == 0 && resG.getType() == Geometry.Type.Point) {// must + // return + // multipoint + // for + // points + MultiPoint mp = new MultiPoint(resG.getDescription()); + if (!resG.isEmpty()) + mp.add((Point) resG); + + resG = mp; + } + } + + return resG; + } + + @Override + public Geometry next() { + if (m_b_done && m_current_dim == m_max_dimension) + return null; + + while (!step_()) { + } + + if (m_max_dimension == -1) + return null;// empty input cursor + + if (m_b_union_all_dimensions) { + m_current_dim++; + while (true) { + if (m_current_dim > m_max_dimension || m_current_dim < 0) + throw GeometryException.GeometryInternalError(); + + if (m_had_geometry[m_current_dim]) + break; + } + + return get_result_geometry(m_current_dim); + } else { + assert (m_max_dimension >= 0); + m_current_dim = m_max_dimension; + return get_result_geometry(m_max_dimension); + } + } + + private boolean step_() { + if (m_b_done) + return true; + + Geometry geom = null; + if (m_inputGeoms != null) { + geom = m_inputGeoms.next(); + if (geom == null) { + m_b_done = true; + } + } + + ProgressTracker.checkAndThrow(m_progress_tracker); + + if (geom != null) { + int dim = geom.getDimension(); + m_had_geometry[dim] = true; + if (dim >= m_max_dimension && !m_b_union_all_dimensions) { + add_geom(dim, false, geom); + if (dim > m_max_dimension && !m_b_union_all_dimensions) { + //this geometry has higher dimension than the previously processed one + //Therefore we delete all lower dimensions (unless m_b_union_all_dimensions is true). + remove_all_bins_with_lower_dimension(dim); + } + } else { + //this geometry is skipped + } + } else { + //geom is null. do nothing + } + + if (m_added_geoms > 0) { + for (int dim = 0; dim <= m_max_dimension; dim++) { + while (m_dim_geom_counts[dim] > 1) { + ArrayList batch_to_union = collect_geometries_to_union(dim); + boolean serial_execution = true; + if (serial_execution) { + if (batch_to_union.size() != 0) { + Geometry geomRes = TopologicalOperations + .dissolveDirty(batch_to_union, + m_spatial_reference, + m_progress_tracker); + add_geom(dim, true, geomRes); + } else { + break; + } + } + } + } + } + + return m_b_done; + } + + ArrayList collect_geometries_to_union(int dim) { + ArrayList batch_to_union = new ArrayList(); + ArrayList> entriesToRemove = new ArrayList>(); + Set> set = m_union_bins.get(dim) + .entrySet(); + for (Map.Entry e : set) { + //int level = e.getKey(); + Bin_type bin = e.getValue(); + + final int binVertexThreshold = 10000; + + if (m_b_done + || (bin.bin_vertex_count > binVertexThreshold && bin + .geom_count() > 1)) { + m_dim_geom_counts[dim] -= bin.geom_count(); + m_added_geoms -= bin.geom_count(); + while (bin.geometries.size() > 0) { + // empty geometries will be unioned too. + batch_to_union.add(bin.back_pair().geom); + bin.pop_pair(); + } + + entriesToRemove.add(e); + } + } + + set.removeAll(entriesToRemove); + return batch_to_union; + } + + private void remove_all_bins_with_lower_dimension(int dim) { + // this geometry has higher dimension than the previously processed one + for (int i = 0; i < dim; i++) { + m_union_bins.get(i).clear(); + m_added_geoms -= m_dim_geom_counts[i]; + m_dim_geom_counts[i] = 0; + } + } + + private void add_geom(int dimension, boolean unioned, Geometry geom) { + Geom_pair pair = new Geom_pair(); + pair.init(); + pair.geom = geom; + int sz = get_vertex_count_(geom); + pair.vertex_count = sz; + int level = get_level_(sz); + if (dimension + 1 > (int) m_union_bins.size()) { + for (int i = 0, n = Math.max(2, dimension + 1); i < n; i++) { + m_union_bins.add(new TreeMap()); + } + } + + Bin_type bin = m_union_bins.get(dimension).get(level);//return null if level is abscent + if (bin == null) { + bin = new Bin_type(); + m_union_bins.get(dimension).put(level, bin); + } + + pair.unioned = unioned; + bin.add_pair(pair); + + // Update global cursor state + m_dim_geom_counts[dimension]++; + m_added_geoms++; + m_max_dimension = Math.max(m_max_dimension, dimension); + } + + private static int get_level_(int sz) {// calculates logarithm of sz to base + // 4. + return sz > 0 ? (int) (Math.log((double) sz) / Math.log(4.0) + 0.5) + : (int) 0; + } + + private static int get_vertex_count_(Geometry geom) { + int gt = geom.getType().value(); + if (Geometry.isMultiVertex(gt)) { + return ((MultiVertexGeometry) geom).getPointCount(); + } else if (gt == Geometry.GeometryType.Point) { + return 1; + } else if (gt == Geometry.GeometryType.Envelope) { + return 4; + } else if (Geometry.isSegment(gt)) { + return 2; + } else { + throw GeometryException.GeometryInternalError(); + } + } + + @Override + public boolean tock() { + return step_(); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorUnionLocal.java b/src/main/java/com/esri/core/geometry/OperatorUnionLocal.java index c8805f28..516875aa 100644 --- a/src/main/java/com/esri/core/geometry/OperatorUnionLocal.java +++ b/src/main/java/com/esri/core/geometry/OperatorUnionLocal.java @@ -28,21 +28,22 @@ class OperatorUnionLocal extends OperatorUnion { - @Override - public GeometryCursor execute(GeometryCursor inputGeometries, - SpatialReference sr, ProgressTracker progressTracker) { - return new OperatorUnionCursor(inputGeometries, sr, progressTracker); - } - - @Override - public Geometry execute(Geometry geom1, Geometry geom2, - SpatialReference sr, ProgressTracker progressTracker) { - ArrayDeque geometryArrayDeque = new ArrayDeque<>(); - geometryArrayDeque.add(geom1);geometryArrayDeque.add(geom2); - SimpleGeometryCursor inputGeometries = new SimpleGeometryCursor(geometryArrayDeque); - GeometryCursor outputCursor = execute(inputGeometries, sr, progressTracker); - - return outputCursor.next(); - } + @Override + public GeometryCursor execute(GeometryCursor inputGeometries, + SpatialReference sr, ProgressTracker progressTracker) { + return new OperatorUnionCursor(inputGeometries, sr, progressTracker); + } + + @Override + public Geometry execute(Geometry geom1, Geometry geom2, + SpatialReference sr, ProgressTracker progressTracker) { + ArrayDeque geometryArrayDeque = new ArrayDeque<>(); + geometryArrayDeque.add(geom1); + geometryArrayDeque.add(geom2); + SimpleGeometryCursor inputGeometries = new SimpleGeometryCursor(geometryArrayDeque); + GeometryCursor outputCursor = execute(inputGeometries, sr, progressTracker); + + return outputCursor.next(); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorWithin.java b/src/main/java/com/esri/core/geometry/OperatorWithin.java index 8817c533..e1780359 100644 --- a/src/main/java/com/esri/core/geometry/OperatorWithin.java +++ b/src/main/java/com/esri/core/geometry/OperatorWithin.java @@ -30,14 +30,14 @@ * Relational operation Within. */ public abstract class OperatorWithin extends OperatorSimpleRelation { - @Override - public Type getType() { - return Type.Within; - } - - public static OperatorWithin local() { - return (OperatorWithin) OperatorFactoryLocal.getInstance().getOperator( - Type.Within); - } + @Override + public Type getType() { + return Type.Within; + } + + public static OperatorWithin local() { + return (OperatorWithin) OperatorFactoryLocal.getInstance().getOperator( + Type.Within); + } } diff --git a/src/main/java/com/esri/core/geometry/OperatorWithinLocal.java b/src/main/java/com/esri/core/geometry/OperatorWithinLocal.java index 635910b3..b1b8ace3 100644 --- a/src/main/java/com/esri/core/geometry/OperatorWithinLocal.java +++ b/src/main/java/com/esri/core/geometry/OperatorWithinLocal.java @@ -26,11 +26,11 @@ class OperatorWithinLocal extends OperatorWithin { - @Override - public boolean execute(Geometry inputGeom1, Geometry inputGeom2, - SpatialReference sr, ProgressTracker progressTracker) { - return RelationalOperations.relate(inputGeom1, inputGeom2, sr, - RelationalOperations.Relation.within, progressTracker); - } + @Override + public boolean execute(Geometry inputGeom1, Geometry inputGeom2, + SpatialReference sr, ProgressTracker progressTracker) { + return RelationalOperations.relate(inputGeom1, inputGeom2, sr, + RelationalOperations.Relation.within, progressTracker); + } } diff --git a/src/main/java/com/esri/core/geometry/PairwiseIntersectorImpl.java b/src/main/java/com/esri/core/geometry/PairwiseIntersectorImpl.java index d02cc4fa..857f16c4 100644 --- a/src/main/java/com/esri/core/geometry/PairwiseIntersectorImpl.java +++ b/src/main/java/com/esri/core/geometry/PairwiseIntersectorImpl.java @@ -24,226 +24,226 @@ package com.esri.core.geometry; class PairwiseIntersectorImpl { - // Quad_tree - private MultiPathImpl m_multi_path_impl_a; - private MultiPathImpl m_multi_path_impl_b; - private boolean m_b_paths; - private boolean m_b_quad_tree; - private boolean m_b_done; - private boolean m_b_swap_elements; - private double m_tolerance; - private int m_path_index; - private int m_element_handle; - private Envelope2D m_paths_query = new Envelope2D(); // only used for m_b_paths == true case - private QuadTreeImpl m_quad_tree; - private QuadTreeImpl.QuadTreeIteratorImpl m_qt_iter; - private SegmentIteratorImpl m_seg_iter; - - // Envelope_2D_intersector - private Envelope2DIntersectorImpl m_intersector; - - private int m_function; - - private interface State { - static final int nextPath = 0; - static final int nextSegment = 1; - static final int iterate = 2; - } - - PairwiseIntersectorImpl(MultiPathImpl multi_path_impl_a, MultiPathImpl multi_path_impl_b, double tolerance, boolean b_paths) { - m_multi_path_impl_a = multi_path_impl_a; - m_multi_path_impl_b = multi_path_impl_b; - - m_b_paths = b_paths; - m_path_index = -1; - - m_b_quad_tree = false; - - GeometryAccelerators geometry_accelerators_a = multi_path_impl_a._getAccelerators(); - - if (geometry_accelerators_a != null) { - QuadTreeImpl qtree_a = (!b_paths ? geometry_accelerators_a.getQuadTree() : geometry_accelerators_a.getQuadTreeForPaths()); - - if (qtree_a != null) { - m_b_done = false; - m_tolerance = tolerance; - m_quad_tree = qtree_a; - m_qt_iter = m_quad_tree.getIterator(); - m_b_quad_tree = true; - m_b_swap_elements = true; - m_function = State.nextPath; - - if (!b_paths) - m_seg_iter = multi_path_impl_b.querySegmentIterator(); - else - m_path_index = multi_path_impl_b.getPathCount(); // we will iterate backwards until we hit -1 - } - } - - if (!m_b_quad_tree) { - GeometryAccelerators geometry_accelerators_b = multi_path_impl_b._getAccelerators(); - - if (geometry_accelerators_b != null) { - QuadTreeImpl qtree_b = (!b_paths ? geometry_accelerators_b.getQuadTree() : geometry_accelerators_b.getQuadTreeForPaths()); - - if (qtree_b != null) { - m_b_done = false; - m_tolerance = tolerance; - m_quad_tree = qtree_b; - m_qt_iter = m_quad_tree.getIterator(); - m_b_quad_tree = true; - m_b_swap_elements = false; - m_function = State.nextPath; - - if (!b_paths) - m_seg_iter = multi_path_impl_a.querySegmentIterator(); - else - m_path_index = multi_path_impl_a.getPathCount(); // we will iterate backwards until we hit -1 - } - } - } - - if (!m_b_quad_tree) { - if (!b_paths) { - m_intersector = InternalUtils.getEnvelope2DIntersector(multi_path_impl_a, multi_path_impl_b, tolerance); - } else { - boolean b_simple_a = multi_path_impl_a.getIsSimple(0.0) >= 1; - boolean b_simple_b = multi_path_impl_b.getIsSimple(0.0) >= 1; - m_intersector = InternalUtils.getEnvelope2DIntersectorForParts(multi_path_impl_a, multi_path_impl_b, tolerance, b_simple_a, b_simple_b); - } - } - } - - boolean next() { - if (m_b_quad_tree) { - if (m_b_done) - return false; - - boolean b_searching = true; - while (b_searching) { - switch (m_function) { - case State.nextPath: - b_searching = nextPath_(); - break; - case State.nextSegment: - b_searching = nextSegment_(); - break; - case State.iterate: - b_searching = iterate_(); - break; - default: - throw GeometryException.GeometryInternalError(); - } - } - - if (m_b_done) - return false; - - return true; - } - - if (m_intersector == null) - return false; - - return m_intersector.next(); - } - - int getRedElement() { - if (m_b_quad_tree) { - if (!m_b_swap_elements) - return (!m_b_paths ? m_seg_iter.getStartPointIndex() : m_path_index); - - return m_quad_tree.getElement(m_element_handle); - } - - return m_intersector.getRedElement(m_intersector.getHandleA()); - } - - int getBlueElement() { - if (m_b_quad_tree) { - if (m_b_swap_elements) - return (!m_b_paths ? m_seg_iter.getStartPointIndex() : m_path_index); - - return m_quad_tree.getElement(m_element_handle); - } - - return m_intersector.getBlueElement(m_intersector.getHandleB()); - } - - Envelope2D getRedEnvelope() { - if (!m_b_paths) - throw GeometryException.GeometryInternalError(); - - if (m_b_quad_tree) { - if (!m_b_swap_elements) - return m_paths_query; - - return m_quad_tree.getElementExtent(m_element_handle); - } - - return m_intersector.getRedEnvelope(m_intersector.getHandleA()); - } - - Envelope2D getBlueEnvelope() { - if (!m_b_paths) - throw GeometryException.GeometryInternalError(); - - if (m_b_quad_tree) { - if (m_b_swap_elements) - return m_paths_query; - - return m_quad_tree.getElementExtent(m_element_handle); - } - - return m_intersector.getBlueEnvelope(m_intersector.getHandleB()); - } - - boolean nextPath_() { - if (!m_b_paths) { - if (!m_seg_iter.nextPath()) { - m_b_done = true; - return false; - } - - m_function = State.nextSegment; - return true; - } - - if (--m_path_index == -1) { - m_b_done = true; - return false; - } - - if (m_b_swap_elements) - m_multi_path_impl_b.queryPathEnvelope2D(m_path_index, m_paths_query); - else - m_multi_path_impl_a.queryPathEnvelope2D(m_path_index, m_paths_query); - - m_qt_iter.resetIterator(m_paths_query, m_tolerance); - m_function = State.iterate; - return true; - } - - boolean nextSegment_() { - if (!m_seg_iter.hasNextSegment()) { - m_function = State.nextPath; - return true; - } - - Segment segment = m_seg_iter.nextSegment(); - m_qt_iter.resetIterator(segment, m_tolerance); - m_function = State.iterate; - return true; - } + // Quad_tree + private MultiPathImpl m_multi_path_impl_a; + private MultiPathImpl m_multi_path_impl_b; + private boolean m_b_paths; + private boolean m_b_quad_tree; + private boolean m_b_done; + private boolean m_b_swap_elements; + private double m_tolerance; + private int m_path_index; + private int m_element_handle; + private Envelope2D m_paths_query = new Envelope2D(); // only used for m_b_paths == true case + private QuadTreeImpl m_quad_tree; + private QuadTreeImpl.QuadTreeIteratorImpl m_qt_iter; + private SegmentIteratorImpl m_seg_iter; + + // Envelope_2D_intersector + private Envelope2DIntersectorImpl m_intersector; + + private int m_function; + + private interface State { + static final int nextPath = 0; + static final int nextSegment = 1; + static final int iterate = 2; + } + + PairwiseIntersectorImpl(MultiPathImpl multi_path_impl_a, MultiPathImpl multi_path_impl_b, double tolerance, boolean b_paths) { + m_multi_path_impl_a = multi_path_impl_a; + m_multi_path_impl_b = multi_path_impl_b; + + m_b_paths = b_paths; + m_path_index = -1; + + m_b_quad_tree = false; + + GeometryAccelerators geometry_accelerators_a = multi_path_impl_a._getAccelerators(); + + if (geometry_accelerators_a != null) { + QuadTreeImpl qtree_a = (!b_paths ? geometry_accelerators_a.getQuadTree() : geometry_accelerators_a.getQuadTreeForPaths()); + + if (qtree_a != null) { + m_b_done = false; + m_tolerance = tolerance; + m_quad_tree = qtree_a; + m_qt_iter = m_quad_tree.getIterator(); + m_b_quad_tree = true; + m_b_swap_elements = true; + m_function = State.nextPath; + + if (!b_paths) + m_seg_iter = multi_path_impl_b.querySegmentIterator(); + else + m_path_index = multi_path_impl_b.getPathCount(); // we will iterate backwards until we hit -1 + } + } + + if (!m_b_quad_tree) { + GeometryAccelerators geometry_accelerators_b = multi_path_impl_b._getAccelerators(); + + if (geometry_accelerators_b != null) { + QuadTreeImpl qtree_b = (!b_paths ? geometry_accelerators_b.getQuadTree() : geometry_accelerators_b.getQuadTreeForPaths()); + + if (qtree_b != null) { + m_b_done = false; + m_tolerance = tolerance; + m_quad_tree = qtree_b; + m_qt_iter = m_quad_tree.getIterator(); + m_b_quad_tree = true; + m_b_swap_elements = false; + m_function = State.nextPath; + + if (!b_paths) + m_seg_iter = multi_path_impl_a.querySegmentIterator(); + else + m_path_index = multi_path_impl_a.getPathCount(); // we will iterate backwards until we hit -1 + } + } + } + + if (!m_b_quad_tree) { + if (!b_paths) { + m_intersector = InternalUtils.getEnvelope2DIntersector(multi_path_impl_a, multi_path_impl_b, tolerance); + } else { + boolean b_simple_a = multi_path_impl_a.getIsSimple(0.0) >= 1; + boolean b_simple_b = multi_path_impl_b.getIsSimple(0.0) >= 1; + m_intersector = InternalUtils.getEnvelope2DIntersectorForParts(multi_path_impl_a, multi_path_impl_b, tolerance, b_simple_a, b_simple_b); + } + } + } + + boolean next() { + if (m_b_quad_tree) { + if (m_b_done) + return false; + + boolean b_searching = true; + while (b_searching) { + switch (m_function) { + case State.nextPath: + b_searching = nextPath_(); + break; + case State.nextSegment: + b_searching = nextSegment_(); + break; + case State.iterate: + b_searching = iterate_(); + break; + default: + throw GeometryException.GeometryInternalError(); + } + } + + if (m_b_done) + return false; + + return true; + } + + if (m_intersector == null) + return false; + + return m_intersector.next(); + } + + int getRedElement() { + if (m_b_quad_tree) { + if (!m_b_swap_elements) + return (!m_b_paths ? m_seg_iter.getStartPointIndex() : m_path_index); + + return m_quad_tree.getElement(m_element_handle); + } + + return m_intersector.getRedElement(m_intersector.getHandleA()); + } + + int getBlueElement() { + if (m_b_quad_tree) { + if (m_b_swap_elements) + return (!m_b_paths ? m_seg_iter.getStartPointIndex() : m_path_index); + + return m_quad_tree.getElement(m_element_handle); + } + + return m_intersector.getBlueElement(m_intersector.getHandleB()); + } + + Envelope2D getRedEnvelope() { + if (!m_b_paths) + throw GeometryException.GeometryInternalError(); + + if (m_b_quad_tree) { + if (!m_b_swap_elements) + return m_paths_query; + + return m_quad_tree.getElementExtent(m_element_handle); + } + + return m_intersector.getRedEnvelope(m_intersector.getHandleA()); + } + + Envelope2D getBlueEnvelope() { + if (!m_b_paths) + throw GeometryException.GeometryInternalError(); + + if (m_b_quad_tree) { + if (m_b_swap_elements) + return m_paths_query; + + return m_quad_tree.getElementExtent(m_element_handle); + } + + return m_intersector.getBlueEnvelope(m_intersector.getHandleB()); + } + + boolean nextPath_() { + if (!m_b_paths) { + if (!m_seg_iter.nextPath()) { + m_b_done = true; + return false; + } + + m_function = State.nextSegment; + return true; + } + + if (--m_path_index == -1) { + m_b_done = true; + return false; + } + + if (m_b_swap_elements) + m_multi_path_impl_b.queryPathEnvelope2D(m_path_index, m_paths_query); + else + m_multi_path_impl_a.queryPathEnvelope2D(m_path_index, m_paths_query); + + m_qt_iter.resetIterator(m_paths_query, m_tolerance); + m_function = State.iterate; + return true; + } + + boolean nextSegment_() { + if (!m_seg_iter.hasNextSegment()) { + m_function = State.nextPath; + return true; + } + + Segment segment = m_seg_iter.nextSegment(); + m_qt_iter.resetIterator(segment, m_tolerance); + m_function = State.iterate; + return true; + } - boolean iterate_() { - m_element_handle = m_qt_iter.next(); + boolean iterate_() { + m_element_handle = m_qt_iter.next(); - if (m_element_handle == -1) { - m_function = (!m_b_paths ? State.nextSegment : State.nextPath); - return true; - } + if (m_element_handle == -1) { + m_function = (!m_b_paths ? State.nextSegment : State.nextPath); + return true; + } - return false; - } + return false; + } } diff --git a/src/main/java/com/esri/core/geometry/PathFlags.java b/src/main/java/com/esri/core/geometry/PathFlags.java index 296db3ea..4e899128 100644 --- a/src/main/java/com/esri/core/geometry/PathFlags.java +++ b/src/main/java/com/esri/core/geometry/PathFlags.java @@ -25,16 +25,16 @@ package com.esri.core.geometry; interface PathFlags { - public static final int enumClosed = 1; - public static final int enumHasNonlinearSegments = 2;// set when the given - // part has - // non-linear - // segments - public static final int enumOGCStartPolygon = 4;// set at the start of a - // Polygon when viewed as an - // OGC MultiPolygon - public static final int enumCalcMask = 4;// mask of flags that are obtained - // by calculation and depend on - // the order of MultiPath parts. + public static final int enumClosed = 1; + public static final int enumHasNonlinearSegments = 2;// set when the given + // part has + // non-linear + // segments + public static final int enumOGCStartPolygon = 4;// set at the start of a + // Polygon when viewed as an + // OGC MultiPolygon + public static final int enumCalcMask = 4;// mask of flags that are obtained + // by calculation and depend on + // the order of MultiPath parts. } diff --git a/src/main/java/com/esri/core/geometry/PeDouble.java b/src/main/java/com/esri/core/geometry/PeDouble.java index 9595af29..fd33af49 100644 --- a/src/main/java/com/esri/core/geometry/PeDouble.java +++ b/src/main/java/com/esri/core/geometry/PeDouble.java @@ -25,13 +25,13 @@ package com.esri.core.geometry; final class PeDouble { - double val; + double val; - PeDouble() { - val = 0.0; - } + PeDouble() { + val = 0.0; + } - PeDouble(double v) { - val = v; - } + PeDouble(double v) { + val = v; + } } diff --git a/src/main/java/com/esri/core/geometry/PlaneSweepCrackerHelper.java b/src/main/java/com/esri/core/geometry/PlaneSweepCrackerHelper.java index f295ea77..d286aac4 100644 --- a/src/main/java/com/esri/core/geometry/PlaneSweepCrackerHelper.java +++ b/src/main/java/com/esri/core/geometry/PlaneSweepCrackerHelper.java @@ -28,1506 +28,1506 @@ package com.esri.core.geometry; final class PlaneSweepCrackerHelper { - PlaneSweepCrackerHelper() { - m_edges = new StridedIndexTypeCollection(8); - m_clusters = new StridedIndexTypeCollection(5); - m_cluster_vertices = new IndexMultiList(); - m_edge_vertices = new IndexMultiList(); - m_complications = false; - m_sweep_point = new Point2D(); - m_sweep_point.setCoords(0, 0); - m_tolerance = 0; - m_vertex_cluster_index = -1; - m_b_cracked = false; - m_shape = null; - - m_event_q = new Treap(); - m_sweep_structure = new Treap(); - m_edges_to_insert_in_sweep_structure = new AttributeStreamOfInt32(0); - m_segment_intersector = new SegmentIntersector(); - m_temp_edge_buffer = new AttributeStreamOfInt32(0); - m_modified_clusters = new AttributeStreamOfInt32(0); - m_helper_point = new Point(); - } - - // For use in Cluster/Cracker loop - boolean sweep(EditShape shape, double tolerance) { - Transformation2D transform = new Transformation2D(); - transform.setSwapCoordinates(); - shape.applyTransformation(transform);// swap coordinates for the sweep - // along x - setEditShape_(shape); - m_b_cracked = false; - m_tolerance = tolerance; - m_tolerance_sqr = tolerance * tolerance; - - boolean b_cracked = sweepImpl_(); - shape.applyTransformation(transform); - if (!b_cracked) { - fillEventQueuePass2(); - b_cracked |= sweepImpl_(); - } - - if (m_vertex_cluster_index != -1) { - m_shape.removeUserIndex(m_vertex_cluster_index); - m_vertex_cluster_index = -1; - } - - m_shape = null; - return m_b_cracked; - } - - // Does one pass sweep vertically - boolean sweepVertical(EditShape shape, double tolerance) { - setEditShape_(shape); - m_b_cracked = false; - m_tolerance = tolerance; - m_tolerance_sqr = tolerance * tolerance; - m_complications = false; - boolean bresult = sweepImpl_(); - if (!m_complications) { - int filtered = shape.filterClosePoints(tolerance, true, false); - m_complications = filtered == 1; - bresult |= filtered == 1; - } - - if (m_vertex_cluster_index != -1) { - m_shape.removeUserIndex(m_vertex_cluster_index); - m_vertex_cluster_index = -1; - } - - m_shape = null; - return bresult; - } - - boolean hadCompications() { - return m_complications; - } - - private EditShape m_shape; - private StridedIndexTypeCollection m_edges; - private StridedIndexTypeCollection m_clusters; - private IndexMultiList m_cluster_vertices; - private IndexMultiList m_edge_vertices; - private Point m_helper_point; - - private Treap m_event_q; - private Treap m_sweep_structure; - - boolean m_complications; - - static final class SimplifySweepComparator extends SweepComparator { - PlaneSweepCrackerHelper m_parent; - - SimplifySweepComparator(PlaneSweepCrackerHelper parent) { - super(parent.m_shape, parent.m_tolerance, false); - m_parent = parent; - } - - @Override - int compare(Treap treap, int elm, int node) { - // Compares two segments on a sweep line passing through m_sweep_y, - // m_sweep_x. - if (m_b_intersection_detected) - return -1; - - int vertex_list_left = m_parent.getEdgeOriginVertices(elm); - int left = m_parent.m_edge_vertices - .getFirstElement(vertex_list_left); - - int right_elm = treap.getElement(node); - assert (m_parent.getEdgeSweepNode(right_elm) == node); - int vertex_list_right = m_parent.getEdgeOriginVertices(right_elm); - int right = m_parent.m_edge_vertices - .getFirstElement(vertex_list_right); - - m_current_node = node; - return compareSegments(elm, left, right_elm, right); - } - } - - ; - - static final class SimplifySweepMonikerComparator extends - SweepMonkierComparator { - PlaneSweepCrackerHelper m_parent; - - SimplifySweepMonikerComparator(PlaneSweepCrackerHelper parent) { - super(parent.m_shape, parent.m_tolerance); - m_parent = parent; - } - - @Override - int compare(Treap treap, int node) { - // Compares two segments on a sweep line passing through m_sweep_y, - // m_sweep_x. - if (m_b_intersection_detected) - return -1; - - int elm = treap.getElement(node); - int vertexList = m_parent.getEdgeOriginVertices(elm); - int vertex = m_parent.m_edge_vertices.getFirstElement(vertexList); - - m_current_node = node; - return compareVertex_(treap, node, vertex); - } - } - - ; - - SimplifySweepComparator m_sweep_comparator; - - AttributeStreamOfInt32 m_temp_edge_buffer; - AttributeStreamOfInt32 m_modified_clusters; - AttributeStreamOfInt32 m_edges_to_insert_in_sweep_structure; - - int m_prev_neighbour; - int m_next_neighbour; - boolean m_b_continuing_segment_chain_optimization;// set to true, when the - // cluster has two edges - // attached, one is - // below and another - // above the sweep line - - SegmentIntersector m_segment_intersector; - - Line m_line_1; - Line m_line_2; - - Point2D m_sweep_point; - double m_tolerance; - double m_tolerance_sqr; - - int m_sweep_point_cluster; - int m_vertex_cluster_index; - - boolean m_b_cracked; - boolean m_b_sweep_point_cluster_was_modified;// set to true if the - // coordinates of the - // cluster, where the sweep - // line was, has been - // changed. - - int getEdgeCluster(int edge, int end) { - assert (end == 0 || end == 1); - return m_edges.getField(edge, 0 + end); - } - - void setEdgeCluster_(int edge, int end, int cluster) { - assert (end == 0 || end == 1); - m_edges.setField(edge, 0 + end, cluster); - } - - // Edge may have several origin vertices, when there are two or more equal - // segements in that edge - // We have to store edge origin separately from the cluster vertices, - // because cluster can have several different edges started on it. - int getEdgeOriginVertices(int edge) { - return m_edges.getField(edge, 2); - } - - void setEdgeOriginVertices_(int edge, int vertices) { - m_edges.setField(edge, 2, vertices); - } - - int getNextEdgeEx(int edge, int end) { - assert (end == 0 || end == 1); - return m_edges.getField(edge, 3 + end); - } - - void setNextEdgeEx_(int edge, int end, int next_edge) { - assert (end == 0 || end == 1); - m_edges.setField(edge, 3 + end, next_edge); - } - - // int get_prev_edge_ex(int edge, int end) - // { - // assert(end == 0 || end == 1); - // return m_edges.get_field(edge, 5 + end); - // } - // void set_prev_edge_ex_(int edge, int end, int prevEdge) - // { - // assert(end == 0 || end == 1); - // m_edges.set_field(edge, 5 + end, prevEdge); - // } - - int getEdgeSweepNode(int edge) { - return m_edges.getField(edge, 7); - } - - void setEdgeSweepNode_(int edge, int sweepNode) { - m_edges.setField(edge, 7, sweepNode); - } - - int getNextEdge(int edge, int cluster) { - int end = getEdgeEnd(edge, cluster); - assert (end == 0 || end == 1); - return m_edges.getField(edge, 3 + end); - } - - void setNextEdge_(int edge, int cluster, int next_edge) { - int end = getEdgeEnd(edge, cluster); - assert (end == 0 || end == 1); - m_edges.setField(edge, 3 + end, next_edge); - } - - int getPrevEdge(int edge, int cluster) { - int end = getEdgeEnd(edge, cluster); - assert (end == 0 || end == 1); - return m_edges.getField(edge, 5 + end); - } - - void setPrevEdge_(int edge, int cluster, int prevEdge) { - int end = getEdgeEnd(edge, cluster); - assert (end == 0 || end == 1); - m_edges.setField(edge, 5 + end, prevEdge); - } - - int getClusterVertices(int cluster) { - return m_clusters.getField(cluster, 0); - } - - void setClusterVertices_(int cluster, int vertices) { - m_clusters.setField(cluster, 0, vertices); - } - - int getClusterVertexIndex(int cluster) { - return m_clusters.getField(cluster, 4); - } - - void setClusterVertexIndex_(int cluster, int vindex) { - m_clusters.setField(cluster, 4, vindex); - } - - int getClusterSweepEdgeList(int cluster) { - return m_clusters.getField(cluster, 2); - } - - void setClusterSweepEdgeList_(int cluster, int sweep_edges) { - m_clusters.setField(cluster, 2, sweep_edges); - } - - int getClusterFirstEdge(int cluster) { - return m_clusters.getField(cluster, 1); - } - - void setClusterFirstEdge_(int cluster, int first_edge) { - m_clusters.setField(cluster, 1, first_edge); - } - - int getClusterEventQNode(int cluster) { - return m_clusters.getField(cluster, 3); - } - - void setClusterEventQNode_(int cluster, int node) { - m_clusters.setField(cluster, 3, node); - } - - int newCluster_(int vertex) { - int cluster = m_clusters.newElement(); - int vertexList = m_cluster_vertices.createList(); - setClusterVertices_(cluster, vertexList); - if (vertex != -1) { - m_cluster_vertices.addElement(vertexList, vertex); - assert (m_shape.getUserIndex(vertex, m_vertex_cluster_index) == -1); - m_shape.setUserIndex(vertex, m_vertex_cluster_index, cluster); - setClusterVertexIndex_(cluster, m_shape.getVertexIndex(vertex)); - } else { - setClusterVertexIndex_(cluster, -1); - } - - return cluster; - } - - void deleteCluster_(int cluster) { - m_clusters.deleteElement(cluster); - } - - void addVertexToCluster_(int cluster, int vertex) { - assert (m_shape.getUserIndex(vertex, m_vertex_cluster_index) == -1); - int vertexList = getClusterVertices(cluster); - m_cluster_vertices.addElement(vertexList, vertex); - m_shape.setUserIndex(vertex, m_vertex_cluster_index, cluster); - } - - // Creates a new unattached edge with the given origin. - int newEdge_(int origin_vertex) { - int edge = m_edges.newElement(); - int edgeVertices = m_edge_vertices.createList(); - setEdgeOriginVertices_(edge, edgeVertices); - if (origin_vertex != -1) - m_edge_vertices.addElement(edgeVertices, origin_vertex); - - return edge; - } - - void addVertexToEdge_(int edge, int vertex) { - int vertexList = getEdgeOriginVertices(edge); - m_edge_vertices.addElement(vertexList, vertex); - } - - void deleteEdge_(int edge) { - m_edges.deleteElement(edge); - int ind = m_edges_to_insert_in_sweep_structure.findElement(edge); - if (ind >= 0) - m_edges_to_insert_in_sweep_structure.popElement(ind); - } - - void addEdgeToCluster(int edge, int cluster) { - if (getEdgeCluster(edge, 0) == -1) { - assert (getEdgeCluster(edge, 1) != cluster); - setEdgeCluster_(edge, 0, cluster); - } else if (getEdgeCluster(edge, 1) == -1) { - assert (getEdgeCluster(edge, 0) != cluster); - setEdgeCluster_(edge, 1, cluster); - } else - throw GeometryException.GeometryInternalError(); - - addEdgeToClusterImpl_(edge, cluster);// simply adds the edge to the list - // of cluster edges. - } - - void addEdgeToClusterImpl_(int edge, int cluster) { - int first_edge = getClusterFirstEdge(cluster); - if (first_edge != -1) { - int next = getNextEdge(first_edge, cluster); - setPrevEdge_(next, cluster, edge); - setNextEdge_(edge, cluster, next); - setNextEdge_(first_edge, cluster, edge); - setPrevEdge_(edge, cluster, first_edge); - } else { - setPrevEdge_(edge, cluster, edge);// point to itself - setNextEdge_(edge, cluster, edge); - setClusterFirstEdge_(cluster, edge); - } - } - - int getEdgeEnd(int edge, int cluster) { - if (getEdgeCluster(edge, 0) == cluster) { - assert (getEdgeCluster(edge, 1) != cluster); - return 0; - } else { - assert (getEdgeCluster(edge, 1) == cluster); - return 1; - } - } - - // Merges two coincident clusters into one. The cluster2 becomes invalid. - void mergeClusters_(int cluster_1, int cluster2) { - // dbg_check_cluster_(cluster_1); - // dbg_check_cluster_(cluster2); - int eventQnode = getClusterEventQNode(cluster2); - if (eventQnode != -1) { - m_event_q.deleteNode(eventQnode, -1); - setClusterEventQNode_(cluster2, -1); - } - - int firstEdge1 = getClusterFirstEdge(cluster_1); - int firstEdge2 = getClusterFirstEdge(cluster2); - - if (firstEdge2 != -1) {// scope - int edge2 = firstEdge2; - int lastEdge = firstEdge2; - boolean bForceContinue = false; - // Delete edges that connect cluster_1 and cluster2. - do { - // dbg_check_edge_(edge2); - bForceContinue = false; - // assert(!StridedIndexTypeCollection.isValidElement(getEdgeSweepNode(edge2))); - int end = getEdgeEnd(edge2, cluster2); - int nextEdge2 = getNextEdgeEx(edge2, end); - if (getEdgeCluster(edge2, (end + 1) & 1) == cluster_1) { // Snapping - // clusters - // that - // are - // connected - // with - // an - // edge - // Delete - // the - // edge. - disconnectEdge_(edge2); - int edgeOrigins2 = getEdgeOriginVertices(edge2); - m_edge_vertices.deleteList(edgeOrigins2); - deleteEdge_(edge2); - if (edge2 == nextEdge2) {// deleted last edge connecting to - // the cluster2 (all connections - // are degenerate) - firstEdge2 = -1; - break; - } - if (firstEdge2 == edge2) { - firstEdge2 = getClusterFirstEdge(cluster2); - lastEdge = nextEdge2; - bForceContinue = true; - } - } else { - assert (edge2 != getClusterFirstEdge(cluster_1)); - } - edge2 = nextEdge2; - } while (edge2 != lastEdge || bForceContinue); - - if (firstEdge2 != -1) { - // set the cluster to the edge ends - do { - int end = getEdgeEnd(edge2, cluster2); - int nextEdge2 = getNextEdgeEx(edge2, end); - assert (edge2 != getClusterFirstEdge(cluster_1)); - setEdgeCluster_(edge2, end, cluster_1); - edge2 = nextEdge2; - } while (edge2 != lastEdge); - - firstEdge1 = getClusterFirstEdge(cluster_1); - if (firstEdge1 != -1) { - int next1 = getNextEdge(firstEdge1, cluster_1); - int next2 = getNextEdge(firstEdge2, cluster_1); - if (next1 == firstEdge1) { - setClusterFirstEdge_(cluster_1, firstEdge2); - addEdgeToClusterImpl_(firstEdge1, cluster_1); - setClusterFirstEdge_(cluster_1, firstEdge1); - } else if (next2 == firstEdge2) { - addEdgeToClusterImpl_(firstEdge2, cluster_1); - } - - setNextEdge_(firstEdge2, cluster_1, next1); - setPrevEdge_(next1, cluster_1, firstEdge2); - setNextEdge_(firstEdge1, cluster_1, next2); - setPrevEdge_(next2, cluster_1, firstEdge1); - } else { - setClusterFirstEdge_(cluster_1, firstEdge2); - } - } - } - - int vertices1 = getClusterVertices(cluster_1); - int vertices2 = getClusterVertices(cluster2); - // Update cluster info on vertices. - for (int vh = m_cluster_vertices.getFirst(vertices2); vh != -1; vh = m_cluster_vertices - .getNext(vh)) { - int v = m_cluster_vertices.getElement(vh); - m_shape.setUserIndex(v, m_vertex_cluster_index, cluster_1); - } - m_cluster_vertices.concatenateLists(vertices1, vertices2); - deleteCluster_(cluster2); - // dbg_check_cluster_(cluster_1); - } - - // Merges two coincident edges into one. The edge2 becomes invalid. - void mergeEdges_(int edge1, int edge2) { - // dbg_check_edge_(edge1); - int cluster_1 = getEdgeCluster(edge1, 0); - int cluster2 = getEdgeCluster(edge1, 1); - int cluster21 = getEdgeCluster(edge2, 0); - int cluster22 = getEdgeCluster(edge2, 1); - - int originVertices1 = getEdgeOriginVertices(edge1); - int originVertices2 = getEdgeOriginVertices(edge2); - m_edge_vertices.concatenateLists(originVertices1, originVertices2); - if (edge2 == getClusterFirstEdge(cluster_1)) - setClusterFirstEdge_(cluster_1, edge1); - if (edge2 == getClusterFirstEdge(cluster2)) - setClusterFirstEdge_(cluster2, edge1); - - disconnectEdge_(edge2);// disconnects the edge2 from the clusters. - deleteEdge_(edge2); - - if (!((cluster_1 == cluster21 && cluster2 == cluster22) || (cluster2 == cluster21 && cluster_1 == cluster22))) { - // Merged edges have different clusters (clusters have not yet been - // merged) - // merge clusters before merging the edges - getClusterXY(cluster_1, pt_1); - getClusterXY(cluster21, pt_2); - if (pt_1.isEqual(pt_2)) { - if (cluster_1 != cluster21) { - mergeClusters_(cluster_1, cluster21); - assert (!m_modified_clusters.hasElement(cluster21)); - } - if (cluster2 != cluster22) { - mergeClusters_(cluster2, cluster22); - assert (!m_modified_clusters.hasElement(cluster22)); - } - } else { - if (cluster2 != cluster21) { - mergeClusters_(cluster2, cluster21); - assert (!m_modified_clusters.hasElement(cluster21)); - } - if (cluster_1 != cluster22) { - mergeClusters_(cluster_1, cluster22); - assert (!m_modified_clusters.hasElement(cluster22)); - } - } - } else { - // Merged edges have equal clusters. - } - // dbg_check_edge_(edge1); - } - - // Disconnects the edge from its clusters. - void disconnectEdge_(int edge) { - int cluster_1 = getEdgeCluster(edge, 0); - int cluster2 = getEdgeCluster(edge, 1); - disconnectEdgeFromCluster_(edge, cluster_1); - disconnectEdgeFromCluster_(edge, cluster2); - } - - // Disconnects the edge from a cluster it is connected to. - void disconnectEdgeFromCluster_(int edge, int cluster) { - int next = getNextEdge(edge, cluster); - assert (getPrevEdge(next, cluster) == edge); - int prev = getPrevEdge(edge, cluster); - assert (getNextEdge(prev, cluster) == edge); - int first_edge = getClusterFirstEdge(cluster); - if (next != edge) { - setNextEdge_(prev, cluster, next); - setPrevEdge_(next, cluster, prev); - if (first_edge == edge) - setClusterFirstEdge_(cluster, next); - } else - setClusterFirstEdge_(cluster, -1); - } - - void applyIntersectorToEditShape_(int edgeOrigins, - SegmentIntersector intersector, int intersector_index) { - // Split Edit_shape segments and produce new vertices. Modify - // coordinates as necessary. No vertices are deleted. - int vertexHandle = m_edge_vertices.getFirst(edgeOrigins); - int first_vertex = m_edge_vertices.getElement(vertexHandle); - - int cluster_1 = getClusterFromVertex(first_vertex); - int cluster2 = getClusterFromVertex(m_shape.getNextVertex(first_vertex)); - boolean bComplexCase = cluster_1 == cluster2; - assert (!bComplexCase);// if it ever asserts there will be a bug. Should - // be a case of a curve that forms a loop. - - m_shape.splitSegment_(first_vertex, intersector, intersector_index, - true); - for (vertexHandle = m_edge_vertices.getNext(vertexHandle); vertexHandle != -1; vertexHandle = m_edge_vertices - .getNext(vertexHandle)) { - int vertex = m_edge_vertices.getElement(vertexHandle); - boolean b_forward = getClusterFromVertex(vertex) == cluster_1; - assert ((b_forward && getClusterFromVertex(m_shape - .getNextVertex(vertex)) == cluster2) || (getClusterFromVertex(vertex) == cluster2 && getClusterFromVertex(m_shape - .getNextVertex(vertex)) == cluster_1)); - m_shape.splitSegment_(vertex, intersector, intersector_index, - b_forward); - } - - // Now apply the updated coordinates to all vertices in the cluster_1 - // and cluster2. - Point2D pt_0; - Point2D pt_1; - pt_0 = intersector.getResultSegment(intersector_index, 0).getStartXY(); - pt_1 = intersector.getResultSegment(intersector_index, - intersector.getResultSegmentCount(intersector_index) - 1) - .getEndXY(); - updateClusterXY(cluster_1, pt_0); - updateClusterXY(cluster2, pt_1); - } - - void createEdgesAndClustersFromSplitEdge_(int edge1, - SegmentIntersector intersector, int intersector_index) { - // dbg_check_new_edges_array_(); - // The method uses m_temp_edge_buffer for temporary storage and clears - // it at the end. - int edgeOrigins1 = getEdgeOriginVertices(edge1); - - // create new edges and clusters - // Note that edge1 is disconnected from its clusters already (the - // cluster's edge list does not contain it). - int cluster_1 = getEdgeCluster(edge1, 0); - int cluster2 = getEdgeCluster(edge1, 1); - int prevEdge = newEdge_(-1); - m_edges_to_insert_in_sweep_structure.add(prevEdge); - int c_3 = StridedIndexTypeCollection.impossibleIndex3(); - setEdgeSweepNode_(prevEdge, c_3);// mark that its in - // m_edges_to_insert_in_sweep_structure - m_temp_edge_buffer.add(prevEdge); - addEdgeToCluster(prevEdge, cluster_1); - for (int i = 1, n = intersector - .getResultSegmentCount(intersector_index); i < n; i++) {// each - // iteration - // adds - // new - // Cluster - // and - // Edge. - int newCluster = newCluster_(-1); - m_modified_clusters.add(newCluster); - m_temp_edge_buffer.add(newCluster); - addEdgeToCluster(prevEdge, newCluster); - int newEdge = newEdge_(-1); - m_edges_to_insert_in_sweep_structure.add(newEdge); - setEdgeSweepNode_(newEdge, c_3);// mark that its in - // m_edges_to_insert_in_sweep_structure - m_temp_edge_buffer.add(newEdge); - addEdgeToCluster(newEdge, newCluster); - prevEdge = newEdge; - } - addEdgeToCluster(prevEdge, cluster2); - // set the Edit_shape vertices to the new clusters and edges. - for (int vertexHandle = m_edge_vertices.getFirst(edgeOrigins1); vertexHandle != -1; vertexHandle = m_edge_vertices - .getNext(vertexHandle)) { - int vertex = m_edge_vertices.getElement(vertexHandle); - int cluster = getClusterFromVertex(vertex); - if (cluster == cluster_1) {// connecting from cluster_1 to cluster2 - int i = 0; - do { - if (i > 0) { - int c = m_temp_edge_buffer.get(i - 1); - addVertexToCluster_(c, vertex); - if (getClusterVertexIndex(c) == -1) - setClusterVertexIndex_(c, - m_shape.getVertexIndex(vertex)); - } - - int edge = m_temp_edge_buffer.get(i); - i += 2; - addVertexToEdge_(edge, vertex); - vertex = m_shape.getNextVertex(vertex); - } while (i < m_temp_edge_buffer.size()); - assert (getClusterFromVertex(vertex) == cluster2); - } else {// connecting from cluster2 to cluster_1 - assert (cluster == cluster2); - int i = m_temp_edge_buffer.size() - 1; - do { - if (i < m_temp_edge_buffer.size() - 2) { - int c = m_temp_edge_buffer.get(i + 1); - addVertexToCluster_(c, vertex); - if (getClusterVertexIndex(c) < 0) - setClusterVertexIndex_(c, - m_shape.getVertexIndex(vertex)); - } - - assert (i % 2 == 0); - int edge = m_temp_edge_buffer.get(i); - i -= 2; - addVertexToEdge_(edge, vertex); - vertex = m_shape.getNextVertex(vertex); - } while (i >= 0); - assert (getClusterFromVertex(vertex) == cluster_1); - } - } - - // #ifdef _DEBUG_TOPO - // for (int i = 0, j = 0, n = - // intersector->get_result_segment_count(intersector_index); i < n; i++, - // j+=2) - // { - // int edge = m_temp_edge_buffer.get(j); - // dbg_check_edge_(edge); - // } - // #endif - - m_temp_edge_buffer.clear(false); - // dbg_check_new_edges_array_(); - } - - int getVertexFromClusterIndex(int cluster) { - int vertexList = getClusterVertices(cluster); - int vertex = m_cluster_vertices.getFirstElement(vertexList); - return vertex; - } - - int getClusterFromVertex(int vertex) { - return m_shape.getUserIndex(vertex, m_vertex_cluster_index); - } - - static final class QComparator extends Treap.Comparator { - EditShape m_shape; - Point2D pt_1 = new Point2D(); - Point2D pt_2 = new Point2D(); - - QComparator(EditShape shape) { - m_shape = shape; - } - - @Override - int compare(Treap treap, int vertex, int node) { - m_shape.getXY(vertex, pt_1); - int v_2 = treap.getElement(node); - m_shape.getXY(v_2, pt_2); - return pt_1.compare(pt_2); - } - } - - static final class QMonikerComparator extends Treap.MonikerComparator { - EditShape m_shape; - Point2D m_point = new Point2D(); - Point2D m_pt = new Point2D(); - - QMonikerComparator(EditShape shape) { - m_shape = shape; - } - - void setPoint(Point2D pt) { - m_point.setCoords(pt); - } - - @Override - int compare(Treap treap, int node) { - int v = treap.getElement(node); - m_shape.getXY(v, m_pt); - return m_point.compare(m_pt); - } - } - - ; - - void processSplitHelper1_(int index, int edge, - SegmentIntersector intersector) { - int clusterStart = getEdgeCluster(edge, 0); - Point2D ptClusterStart = new Point2D(); - getClusterXY(clusterStart, ptClusterStart); - Point2D ptClusterEnd = new Point2D(); - int clusterEnd = getEdgeCluster(edge, 1); - getClusterXY(clusterEnd, ptClusterEnd); - - // Collect all edges that are affected by the split and that are in the - // sweep structure. - int count = intersector.getResultSegmentCount(index); - Segment seg = intersector.getResultSegment(index, 0); - Point2D newStart = new Point2D(); - seg.getStartXY(newStart); - - if (!ptClusterStart.isEqual(newStart)) { - if (!m_complications) { - int res1 = ptClusterStart.compare(m_sweep_point); - int res2 = newStart.compare(m_sweep_point); - if (res1 * res2 < 0) { - m_complications = true;// point is not yet have been processed - // but moved before the sweep point, - // this will require - // repeating the cracking step and the sweep_vertical cannot - // help here - } - } - - // This cluster's position needs to be changed - getAffectedEdges(clusterStart, m_temp_edge_buffer); - m_modified_clusters.add(clusterStart); - } - - if (!m_complications && count > 1) { - int dir = ptClusterStart.compare(ptClusterEnd); - Point2D midPoint = seg.getEndXY(); - if (ptClusterStart.compare(midPoint) != dir - || midPoint.compare(ptClusterEnd) != dir) {// split segment - // midpoint is - // above the - // sweep line. - // Therefore the - // part of the - // segment - m_complications = true; - } else { - if (midPoint.compare(m_sweep_point) < 0) { - // midpoint moved below sweepline. - m_complications = true; - } - } - } - - seg = intersector.getResultSegment(index, count - 1); - Point2D newEnd = seg.getEndXY(); - if (!ptClusterEnd.isEqual(newEnd)) { - if (!m_complications) { - int res1 = ptClusterEnd.compare(m_sweep_point); - int res2 = newEnd.compare(m_sweep_point); - if (res1 * res2 < 0) { - m_complications = true;// point is not yet have been processed - // but moved before the sweep point. - } - } - // This cluster's position needs to be changed - getAffectedEdges(clusterEnd, m_temp_edge_buffer); - m_modified_clusters.add(clusterEnd); - } - - m_temp_edge_buffer.add(edge); - // Delete all nodes from the sweep structure that are affected by the - // change. - for (int i = 0, n = m_temp_edge_buffer.size(); i < n; i++) { - int e = m_temp_edge_buffer.get(i); - int sweepNode = getEdgeSweepNode(e); - if (StridedIndexTypeCollection.isValidElement(sweepNode)) { - m_sweep_structure.deleteNode(sweepNode, -1); - setEdgeSweepNode_(e, -1); - } - - int c_3 = StridedIndexTypeCollection.impossibleIndex3(); - if (e != edge && getEdgeSweepNode(e) != c_3)// c_3 means the edge is - // already in the - // m_edges_to_insert_in_sweep_structure - { - m_edges_to_insert_in_sweep_structure.add(e); - setEdgeSweepNode_(e, c_3); - } - } - m_temp_edge_buffer.clear(false); - } - - boolean checkAndFixIntersection_(int leftSweepNode, int rightSweepNode) { - int leftEdge = m_sweep_structure.getElement(leftSweepNode); - m_sweep_comparator.compare(m_sweep_structure, leftEdge, rightSweepNode); - if (m_sweep_comparator.intersectionDetected()) { - m_sweep_comparator.clearIntersectionDetectedFlag(); - fixIntersection_(leftSweepNode, rightSweepNode); - return true; - } - - return false; - } - - void fixIntersection_(int left, int right) { - m_b_cracked = true; - int edge1 = m_sweep_structure.getElement(left); - int edge2 = m_sweep_structure.getElement(right); - assert (edge1 != edge2); - Segment seg_1; - Segment seg_2; - int vertexList1 = getEdgeOriginVertices(edge1); - int origin1 = m_edge_vertices.getFirstElement(vertexList1); - int vertexList2 = getEdgeOriginVertices(edge2); - int origin2 = m_edge_vertices.getFirstElement(vertexList2); - seg_1 = m_shape.getSegment(origin1); - if (seg_1 == null) { - if (m_line_1 == null) - m_line_1 = new Line(); - m_shape.queryLineConnector(origin1, m_line_1); - seg_1 = m_line_1; - } - - seg_2 = m_shape.getSegment(origin2); - if (seg_2 == null) { - if (m_line_2 == null) - m_line_2 = new Line(); - m_shape.queryLineConnector(origin2, m_line_2); - seg_2 = m_line_2; - } - - // #ifdef _DEBUG_CRACKING_REPORT - // { - // Point_2D pt11, pt12, pt21, pt22; - // pt11 = seg_1->get_start_xy(); - // pt12 = seg_1->get_end_xy(); - // pt21 = seg_2->get_start_xy(); - // pt22 = seg_2->get_end_xy(); - // DEBUGPRINTF(L"Intersecting %d (%0.4f, %0.4f - %0.4f, %0.4f) and %d (%0.4f, %0.4f - %0.4f, %0.4f)\n", - // edge1, pt11.x, pt11.y, pt12.x, pt12.y, edge2, pt21.x, pt21.y, pt22.x, - // pt22.y); - // } - // #endif - - m_segment_intersector.pushSegment(seg_1); - m_segment_intersector.pushSegment(seg_2); - if (m_segment_intersector.intersect(m_tolerance, true)) - m_complications = true; - - - splitEdge_(edge1, edge2, -1, m_segment_intersector); - m_segment_intersector.clear(); - } - - void fixIntersectionPointSegment_(int cluster, int node) { - m_b_cracked = true; - int edge1 = m_sweep_structure.getElement(node); - Segment seg_1; - int vertexList1 = getEdgeOriginVertices(edge1); - int origin1 = m_edge_vertices.getFirstElement(vertexList1); - seg_1 = m_shape.getSegment(origin1); - if (seg_1 == null) { - if (m_line_1 == null) - m_line_1 = new Line(); - m_shape.queryLineConnector(origin1, m_line_1); - seg_1 = m_line_1; - } - - int clusterVertex = getClusterFirstVertex(cluster); - m_segment_intersector.pushSegment(seg_1); - - m_shape.queryPoint(clusterVertex, m_helper_point); - m_segment_intersector.intersect(m_tolerance, m_helper_point, 0, 1.0, - true); - - splitEdge_(edge1, -1, cluster, m_segment_intersector); - - m_segment_intersector.clear(); - } - - void insertNewEdges_() { - if (m_edges_to_insert_in_sweep_structure.size() == 0) - return; - - while (m_edges_to_insert_in_sweep_structure.size() != 0) { - if (m_edges_to_insert_in_sweep_structure.size() > Math.max( - (int) 100, m_shape.getTotalPointCount())) { - assert (false); - m_edges_to_insert_in_sweep_structure.clear(false); - m_complications = true; - break;// something strange going on here. bail out, forget about - // these edges and continue with sweep line. We'll - // iterate on the data one more time. - } - - int edge = m_edges_to_insert_in_sweep_structure.getLast(); - m_edges_to_insert_in_sweep_structure.removeLast(); - - assert (getEdgeSweepNode(edge) == StridedIndexTypeCollection - .impossibleIndex3()); - setEdgeSweepNode_(edge, -1); - int terminatingCluster = isEdgeOnSweepLine_(edge); - if (terminatingCluster != -1) { - insertNewEdgeToSweepStructure_(edge, terminatingCluster); - } - m_b_continuing_segment_chain_optimization = false; - } - } - - boolean insertNewEdgeToSweepStructure_(int edge, int terminatingCluster) { - assert (getEdgeSweepNode(edge) == -1); - int newEdgeNode; - if (m_b_continuing_segment_chain_optimization) { - newEdgeNode = m_sweep_structure.addElementAtPosition( - m_prev_neighbour, m_next_neighbour, edge, true, true, -1); - m_b_continuing_segment_chain_optimization = false; - } else { - newEdgeNode = m_sweep_structure.addUniqueElement(edge, -1); - } - - if (newEdgeNode == -1) {// a coinciding edge. - int existingNode = m_sweep_structure.getDuplicateElement(-1); - int existingEdge = m_sweep_structure.getElement(existingNode); - mergeEdges_(existingEdge, edge); - return false; - } - - // Remember the sweep structure node in the edge. - setEdgeSweepNode_(edge, newEdgeNode); - - if (m_sweep_comparator.intersectionDetected()) { - // The edge has been inserted into the sweep structure and an - // intersection has beebn found. The edge will be split and removed. - m_sweep_comparator.clearIntersectionDetectedFlag(); - int intersectionNode = m_sweep_comparator.getLastComparedNode(); - fixIntersection_(intersectionNode, newEdgeNode); - return true; - } else { - // The edge has been inserted into the sweep structure without - // problems (it does not intersect its neighbours) - } - - return false; - } - - Point2D pt_1 = new Point2D(); - Point2D pt_2 = new Point2D(); - - int isEdgeOnSweepLine_(int edge) { - int cluster_1 = getEdgeCluster(edge, 0); - int cluster2 = getEdgeCluster(edge, 1); - getClusterXY(cluster_1, pt_1); - getClusterXY(cluster2, pt_2); - if (Point2D.sqrDistance(pt_1, pt_2) <= m_tolerance_sqr) {// avoid - // degenerate - // segments - m_complications = true; - return -1; - } - int cmp1 = pt_1.compare(m_sweep_point); - int cmp2 = pt_2.compare(m_sweep_point); - if (cmp1 <= 0 && cmp2 > 0) { - return cluster2; - } - - if (cmp2 <= 0 && cmp1 > 0) { - return cluster_1; - } - - return -1; - } - - // void set_edit_shape(Edit_shape* shape); - // Fills the event queue and merges coincident clusters. - void fillEventQueue() { - AttributeStreamOfInt32 event_q = new AttributeStreamOfInt32(0); - event_q.reserve(m_shape.getTotalPointCount());// temporary structure to - // sort and find - // clusters - EditShape.VertexIterator iter = m_shape.queryVertexIterator(); - for (int vert = iter.next(); vert != -1; vert = iter.next()) { - if (m_shape.getUserIndex(vert, m_vertex_cluster_index) != -1) - event_q.add(vert); - } - - // Now we can merge coincident clusters and form the envent structure. - - // sort vertices lexicographically. - m_shape.sortVerticesSimpleByY_(event_q, 0, event_q.size()); - - // The m_event_q is the event structure for the planesweep algorithm. - // We could use any data structure that allows log(n) insertion and - // deletion in the sorted order and - // allow to iterate through in the sorted order. - - m_event_q.clear(); - // Populate the event structure - m_event_q.setCapacity(event_q.size()); - { - // The comparator is used to sort vertices by the m_event_q - m_event_q.setComparator(new QComparator(m_shape)); - } - - // create the vertex clusters and fill the event structure m_event_q. - // Because most vertices are expected to be non clustered, we create - // clusters only for actual clusters to save some memory. - Point2D cluster_pt = new Point2D(); - cluster_pt.setNaN(); - int cluster = -1; - Point2D pt = new Point2D(); - for (int index = 0, nvertex = event_q.size(); index < nvertex; index++) { - int vertex = event_q.get(index); - m_shape.getXY(vertex, pt); - if (pt.isEqual(cluster_pt)) { - int vertexCluster = m_shape.getUserIndex(vertex, - m_vertex_cluster_index); - mergeClusters_(cluster, vertexCluster); - continue; - } - - cluster = getClusterFromVertex(vertex); - // add a vertex to the event queue - m_shape.getXY(vertex, cluster_pt); - int eventQnode = m_event_q.addBiggestElement(vertex, -1); // this - // method - // does - // not - // call - // comparator's - // compare, - // assuming - // sorted - // order. - setClusterEventQNode_(cluster, eventQnode); - } - } - - void fillEventQueuePass2() { - AttributeStreamOfInt32 event_q = new AttributeStreamOfInt32(0); - event_q.reserve(m_shape.getTotalPointCount());// temporary structure to - // sort and find - // clusters - for (int node = m_event_q.getFirst(-1); node != -1; node = m_event_q - .getNext(node)) { - int v = m_event_q.getElement(node); - event_q.add(v); - } - - assert (event_q.size() == m_event_q.size(-1)); - - m_event_q.clear(); - - // sort vertices lexicographically. - m_shape.sortVerticesSimpleByY_(event_q, 0, event_q.size()); - - for (int index = 0, nvertex = event_q.size(); index < nvertex; index++) { - int vertex = event_q.get(index); - int cluster = getClusterFromVertex(vertex); - int eventQnode = m_event_q.addBiggestElement(vertex, -1); // this - // method - // does - // not - // call - // comparator's - // compare, - // assuming - // sorted - // order. - setClusterEventQNode_(cluster, eventQnode); - } - } - - // Returns edges already in the sweep structure that are affected by the - // change of cluster coordinate. - void getAffectedEdges(int cluster, AttributeStreamOfInt32 edges) { - int first_edge = getClusterFirstEdge(cluster); - if (first_edge == -1) - return; - - int edge = first_edge; - do { - int sweepNode = getEdgeSweepNode(edge); - if (StridedIndexTypeCollection.isValidElement(sweepNode)) { - edges.add(edge); - } - edge = getNextEdge(edge, cluster); - } while (edge != first_edge); - } - - // Updates all vertices of the cluster to new coordinate - void updateClusterXY(int cluster, Point2D pt) { - int vertexList = getClusterVertices(cluster); - for (int vh = m_cluster_vertices.getFirst(vertexList); vh != -1; vh = m_cluster_vertices - .getNext(vh)) { - int vertex = m_cluster_vertices.getElement(vh); - m_shape.setXY(vertex, pt); - } - } - - // Modifies the given edges given the intersector class and the result - // index. - // The function updates the the event structure and puts new edges into the - // m_edges_to_insert_in_sweep_structure. - void splitEdge_(int edge1, int edge2, int intersectionCluster, - SegmentIntersector intersector) { - - disconnectEdge_(edge1);// disconnects the edge from the clusters. The - // edge still remembers the clusters. - if (edge2 != -1) - disconnectEdge_(edge2);// disconnects the edge from the clusters. - // The edge still remembers the clusters. - - // Collect all edges that are affected when the clusters change position - // due to snapping - // The edges are collected in m_edges_to_insert_in_sweep_structure. - // Collect the modified clusters in m_modified_clusters. - processSplitHelper1_(0, edge1, intersector); - if (edge2 != -1) - processSplitHelper1_(1, edge2, intersector); - - if (intersectionCluster != -1) { - intersector.getResultPoint().getXY(pt_1); - getClusterXY(intersectionCluster, pt_2); - if (!pt_2.isEqual(pt_1)) - m_modified_clusters.add(intersectionCluster); - } - - // remove modified clusters from the event queue. We'll reincert them - // later - for (int i = 0, n = m_modified_clusters.size(); i < n; i++) { - int cluster = m_modified_clusters.get(i); - int eventQnode = getClusterEventQNode(cluster); - if (eventQnode != -1) { - m_event_q.deleteNode(eventQnode, -1); - setClusterEventQNode_(cluster, -1); - } - } - - int edgeOrigins1 = getEdgeOriginVertices(edge1); - int edgeOrigins2 = (edge2 != -1) ? getEdgeOriginVertices(edge2) : -1; - - // Adjust the vertex coordinates and split the segments in the the edit - // shape. - applyIntersectorToEditShape_(edgeOrigins1, intersector, 0); - if (edge2 != -1) - applyIntersectorToEditShape_(edgeOrigins2, intersector, 1); - - // Produce clusters, and new edges. The new edges are added to - // m_edges_to_insert_in_sweep_structure. - createEdgesAndClustersFromSplitEdge_(edge1, intersector, 0); - if (edge2 != -1) - createEdgesAndClustersFromSplitEdge_(edge2, intersector, 1); - - m_edge_vertices.deleteList(edgeOrigins1); - deleteEdge_(edge1); - - if (edge2 != -1) { - m_edge_vertices.deleteList(edgeOrigins2); - deleteEdge_(edge2); - } - - // insert clusters into the event queue and the edges into the sweep - // structure. - for (int i = 0, n = m_modified_clusters.size(); i < n; i++) { - int cluster = m_modified_clusters.get(i); - if (cluster == m_sweep_point_cluster) - m_b_sweep_point_cluster_was_modified = true; - - int eventQnode = getClusterEventQNode(cluster); - if (eventQnode == -1) { - int vertex = getClusterFirstVertex(cluster); - assert (getClusterFromVertex(vertex) == cluster); - - eventQnode = m_event_q.addUniqueElement(vertex, -1);// O(logN) - // operation - if (eventQnode == -1) {// the cluster is coinciding with another - // one. merge. - int existingNode = m_event_q.getDuplicateElement(-1); - int v = m_event_q.getElement(existingNode); - assert (m_shape.isEqualXY(vertex, v)); - int existingCluster = getClusterFromVertex(v); - mergeClusters_(existingCluster, cluster); - } else { - setClusterEventQNode_(cluster, eventQnode); - } - } else { - // if already inserted (probably impossible) case - } - } - - m_modified_clusters.clear(false); - } - - // Returns a cluster's xy. - void getClusterXY(int cluster, Point2D ptOut) { - int vindex = getClusterVertexIndex(cluster); - m_shape.getXYWithIndex(vindex, ptOut); - } - - int getClusterFirstVertex(int cluster) { - int vertexList = getClusterVertices(cluster); - int vertex = m_cluster_vertices.getFirstElement(vertexList); - return vertex; - } - - boolean sweepImpl_() { - m_b_sweep_point_cluster_was_modified = false; - m_sweep_point_cluster = -1; - if (m_sweep_comparator == null) { - m_sweep_structure.disableBalancing(); - m_sweep_comparator = new SimplifySweepComparator(this); - m_sweep_structure.setComparator(m_sweep_comparator); - } - - AttributeStreamOfInt32 edgesToDelete = new AttributeStreamOfInt32(0); - SimplifySweepMonikerComparator sweepMoniker = null; - QMonikerComparator moniker = null; - - int iterationCounter = 0; - m_prev_neighbour = -1; - m_next_neighbour = -1; - m_b_continuing_segment_chain_optimization = false; - - int c_2 = StridedIndexTypeCollection.impossibleIndex2(); - int c_3 = StridedIndexTypeCollection.impossibleIndex3(); - assert (c_2 != c_3); - - for (int eventQnode = m_event_q.getFirst(-1); eventQnode != -1; ) { - iterationCounter++; - m_b_continuing_segment_chain_optimization = false; - - int vertex = m_event_q.getElement(eventQnode); - m_sweep_point_cluster = getClusterFromVertex(vertex); - m_shape.getXY(vertex, m_sweep_point); - - m_sweep_comparator.setSweepY(m_sweep_point.y, m_sweep_point.x);// move - // the - // sweep - // line - - boolean bDisconnectedCluster = false; - {// scope - int first_edge = getClusterFirstEdge(m_sweep_point_cluster); - bDisconnectedCluster = first_edge == -1; - if (!bDisconnectedCluster) { - int edge = first_edge; - do { - int sweepNode = getEdgeSweepNode(edge); - if (sweepNode == -1) { - m_edges_to_insert_in_sweep_structure.add(edge); - setEdgeSweepNode_(edge, c_3);// mark that its in - // m_edges_to_insert_in_sweep_structure - } else if (sweepNode != c_3) { - assert (StridedIndexTypeCollection.isValidElement(sweepNode)); - edgesToDelete.add(sweepNode); - } - edge = getNextEdge(edge, m_sweep_point_cluster); - } while (edge != first_edge); - } - } - - // st_counter_insertions_peaks += edgesToDelete.size() == 0 && - // m_edges_to_insert_in_sweep_structure.size() > 0; - // First step is to delete the edges that terminate in the - // cluster. - // During that step we also determine the left and right neighbors - // of the deleted bunch and then check if those left and right - // intersect or not. - if (edgesToDelete.size() > 0) { - m_b_continuing_segment_chain_optimization = (edgesToDelete - .size() == 1 && m_edges_to_insert_in_sweep_structure - .size() == 1); - - // Mark nodes that need to be deleted by setting c_2 to the - // edge's sweep node member. - for (int i = 0, n = edgesToDelete.size(); i < n; i++) { - int edge = m_sweep_structure.getElement(edgesToDelete - .get(i)); - setEdgeSweepNode_(edge, c_2); - } - - int left = c_2; - int right = c_2; - // Determine left and right nodes for the bunch of nodes we are - // deleting. - for (int i = 0, n = edgesToDelete.size(); i < n; i++) { - int sweepNode = edgesToDelete.get(i); - if (left == c_2) { - int localleft = m_sweep_structure.getPrev(sweepNode); - if (localleft != -1) { - int edge = m_sweep_structure.getElement(localleft); - int node = getEdgeSweepNode(edge); - if (node != c_2) - left = localleft; - } else - left = -1; - } - - if (right == c_2) { - int localright = m_sweep_structure.getNext(sweepNode); - if (localright != -1) { - int edge = m_sweep_structure.getElement(localright); - int node = getEdgeSweepNode(edge); - if (node != c_2) - right = localright; - } else - right = -1; - } - - if (left != c_2 && right != c_2) - break; - } - - assert (left != c_2 && right != c_2); - // Now delete the bunch. - for (int i = 0, n = edgesToDelete.size(); i < n; i++) { - int sweepNode = edgesToDelete.get(i); - int edge = m_sweep_structure.getElement(sweepNode); - m_sweep_structure.deleteNode(sweepNode, -1); - setEdgeSweepNode_(edge, -1); - } - - edgesToDelete.clear(false); - - m_prev_neighbour = left != -1 ? left : -1; - m_next_neighbour = right != -1 ? right : -1; - - // Now check if the left and right we found intersect or not. - if (left != -1 && right != -1) { - if (!m_b_continuing_segment_chain_optimization) { - boolean bIntersected = checkAndFixIntersection_(left, - right); - } - } else { - if ((left == -1) && (right == -1)) - m_b_continuing_segment_chain_optimization = false; - } - } else { - // edgesToDelete.size() == 0 - nothing to delete here. This is a - // cluster which has all edges directed up or a disconnected - // cluster. - - if (bDisconnectedCluster) {// check standalone cluster (point or - // multipoint) if it cracks an edge. - if (sweepMoniker == null) - sweepMoniker = new SimplifySweepMonikerComparator(this); - - sweepMoniker.setPoint(m_sweep_point); - m_sweep_structure.searchUpperBound(sweepMoniker, -1); - if (sweepMoniker.intersectionDetected()) { - sweepMoniker.clearIntersectionDetectedFlag(); - fixIntersectionPointSegment_(m_sweep_point_cluster, - sweepMoniker.getCurrentNode()); - } - } - } - - // Now insert edges that start at the cluster and go up - insertNewEdges_(); - - if (m_b_sweep_point_cluster_was_modified) { - m_b_sweep_point_cluster_was_modified = false; - if (moniker == null) - moniker = new QMonikerComparator(m_shape); - moniker.setPoint(m_sweep_point); - eventQnode = m_event_q.searchUpperBound(moniker, -1); - } else - eventQnode = m_event_q.getNext(eventQnode); - } - - return m_b_cracked; - } - - void setEditShape_(EditShape shape) { - // Populate the cluster and edge structures. - m_shape = shape; - m_vertex_cluster_index = m_shape.createUserIndex(); - - m_edges.setCapacity(shape.getTotalPointCount() + 32); - - m_clusters.setCapacity(shape.getTotalPointCount()); - - m_cluster_vertices.reserveLists(shape.getTotalPointCount()); - m_cluster_vertices.reserveNodes(shape.getTotalPointCount()); - - m_edge_vertices.reserveLists(shape.getTotalPointCount() + 32); - m_edge_vertices.reserveNodes(shape.getTotalPointCount() + 32); - - for (int geometry = m_shape.getFirstGeometry(); geometry != -1; geometry = m_shape - .getNextGeometry(geometry)) { - boolean bMultiPath = Geometry.isMultiPath(m_shape - .getGeometryType(geometry)); - - if (!bMultiPath) {// for multipoints do not add edges. - assert (m_shape.getGeometryType(geometry) == Geometry.GeometryType.MultiPoint); - - for (int path = m_shape.getFirstPath(geometry); path != -1; path = m_shape - .getNextPath(path)) { - int vertex = m_shape.getFirstVertex(path); - for (int i = 0, n = m_shape.getPathSize(path); i < n; i++) { - // int cluster - newCluster_(vertex); - vertex = m_shape.getNextVertex(vertex); - } - } - continue; - } - - for (int path = m_shape.getFirstPath(geometry); path != -1; path = m_shape - .getNextPath(path)) { - int path_size = m_shape.getPathSize(path); - assert (path_size > 1); - int first_vertex = m_shape.getFirstVertex(path); - - // first------------------ - int firstCluster = newCluster_(first_vertex); - int first_edge = newEdge_(first_vertex); - addEdgeToCluster(first_edge, firstCluster); - int prevEdge = first_edge; - int vertex = m_shape.getNextVertex(first_vertex); - for (int index = 0, n = path_size - 2; index < n; index++) { - int nextvertex = m_shape.getNextVertex(vertex); - // ------------x------------ - int cluster = newCluster_(vertex); - addEdgeToCluster(prevEdge, cluster); - int newEdge = newEdge_(vertex); - addEdgeToCluster(newEdge, cluster); - prevEdge = newEdge; - vertex = nextvertex; - } - - // ------------------lastx - if (m_shape.isClosedPath(path)) { - int cluster = newCluster_(vertex); - addEdgeToCluster(prevEdge, cluster); - // close the path - // lastx------------------firstx - int newEdge = newEdge_(vertex); - addEdgeToCluster(newEdge, cluster); - addEdgeToCluster(newEdge, firstCluster); - } else { - // ------------------lastx - int cluster = newCluster_(vertex); - addEdgeToCluster(prevEdge, cluster); - } - - } - } - - fillEventQueue(); - - // int perPoint = estimate_memory_size() / - // m_shape.get_total_point_count(); - // perPoint = 0; - } + PlaneSweepCrackerHelper() { + m_edges = new StridedIndexTypeCollection(8); + m_clusters = new StridedIndexTypeCollection(5); + m_cluster_vertices = new IndexMultiList(); + m_edge_vertices = new IndexMultiList(); + m_complications = false; + m_sweep_point = new Point2D(); + m_sweep_point.setCoords(0, 0); + m_tolerance = 0; + m_vertex_cluster_index = -1; + m_b_cracked = false; + m_shape = null; + + m_event_q = new Treap(); + m_sweep_structure = new Treap(); + m_edges_to_insert_in_sweep_structure = new AttributeStreamOfInt32(0); + m_segment_intersector = new SegmentIntersector(); + m_temp_edge_buffer = new AttributeStreamOfInt32(0); + m_modified_clusters = new AttributeStreamOfInt32(0); + m_helper_point = new Point(); + } + + // For use in Cluster/Cracker loop + boolean sweep(EditShape shape, double tolerance) { + Transformation2D transform = new Transformation2D(); + transform.setSwapCoordinates(); + shape.applyTransformation(transform);// swap coordinates for the sweep + // along x + setEditShape_(shape); + m_b_cracked = false; + m_tolerance = tolerance; + m_tolerance_sqr = tolerance * tolerance; + + boolean b_cracked = sweepImpl_(); + shape.applyTransformation(transform); + if (!b_cracked) { + fillEventQueuePass2(); + b_cracked |= sweepImpl_(); + } + + if (m_vertex_cluster_index != -1) { + m_shape.removeUserIndex(m_vertex_cluster_index); + m_vertex_cluster_index = -1; + } + + m_shape = null; + return m_b_cracked; + } + + // Does one pass sweep vertically + boolean sweepVertical(EditShape shape, double tolerance) { + setEditShape_(shape); + m_b_cracked = false; + m_tolerance = tolerance; + m_tolerance_sqr = tolerance * tolerance; + m_complications = false; + boolean bresult = sweepImpl_(); + if (!m_complications) { + int filtered = shape.filterClosePoints(tolerance, true, false); + m_complications = filtered == 1; + bresult |= filtered == 1; + } + + if (m_vertex_cluster_index != -1) { + m_shape.removeUserIndex(m_vertex_cluster_index); + m_vertex_cluster_index = -1; + } + + m_shape = null; + return bresult; + } + + boolean hadCompications() { + return m_complications; + } + + private EditShape m_shape; + private StridedIndexTypeCollection m_edges; + private StridedIndexTypeCollection m_clusters; + private IndexMultiList m_cluster_vertices; + private IndexMultiList m_edge_vertices; + private Point m_helper_point; + + private Treap m_event_q; + private Treap m_sweep_structure; + + boolean m_complications; + + static final class SimplifySweepComparator extends SweepComparator { + PlaneSweepCrackerHelper m_parent; + + SimplifySweepComparator(PlaneSweepCrackerHelper parent) { + super(parent.m_shape, parent.m_tolerance, false); + m_parent = parent; + } + + @Override + int compare(Treap treap, int elm, int node) { + // Compares two segments on a sweep line passing through m_sweep_y, + // m_sweep_x. + if (m_b_intersection_detected) + return -1; + + int vertex_list_left = m_parent.getEdgeOriginVertices(elm); + int left = m_parent.m_edge_vertices + .getFirstElement(vertex_list_left); + + int right_elm = treap.getElement(node); + assert (m_parent.getEdgeSweepNode(right_elm) == node); + int vertex_list_right = m_parent.getEdgeOriginVertices(right_elm); + int right = m_parent.m_edge_vertices + .getFirstElement(vertex_list_right); + + m_current_node = node; + return compareSegments(elm, left, right_elm, right); + } + } + + ; + + static final class SimplifySweepMonikerComparator extends + SweepMonkierComparator { + PlaneSweepCrackerHelper m_parent; + + SimplifySweepMonikerComparator(PlaneSweepCrackerHelper parent) { + super(parent.m_shape, parent.m_tolerance); + m_parent = parent; + } + + @Override + int compare(Treap treap, int node) { + // Compares two segments on a sweep line passing through m_sweep_y, + // m_sweep_x. + if (m_b_intersection_detected) + return -1; + + int elm = treap.getElement(node); + int vertexList = m_parent.getEdgeOriginVertices(elm); + int vertex = m_parent.m_edge_vertices.getFirstElement(vertexList); + + m_current_node = node; + return compareVertex_(treap, node, vertex); + } + } + + ; + + SimplifySweepComparator m_sweep_comparator; + + AttributeStreamOfInt32 m_temp_edge_buffer; + AttributeStreamOfInt32 m_modified_clusters; + AttributeStreamOfInt32 m_edges_to_insert_in_sweep_structure; + + int m_prev_neighbour; + int m_next_neighbour; + boolean m_b_continuing_segment_chain_optimization;// set to true, when the + // cluster has two edges + // attached, one is + // below and another + // above the sweep line + + SegmentIntersector m_segment_intersector; + + Line m_line_1; + Line m_line_2; + + Point2D m_sweep_point; + double m_tolerance; + double m_tolerance_sqr; + + int m_sweep_point_cluster; + int m_vertex_cluster_index; + + boolean m_b_cracked; + boolean m_b_sweep_point_cluster_was_modified;// set to true if the + // coordinates of the + // cluster, where the sweep + // line was, has been + // changed. + + int getEdgeCluster(int edge, int end) { + assert (end == 0 || end == 1); + return m_edges.getField(edge, 0 + end); + } + + void setEdgeCluster_(int edge, int end, int cluster) { + assert (end == 0 || end == 1); + m_edges.setField(edge, 0 + end, cluster); + } + + // Edge may have several origin vertices, when there are two or more equal + // segements in that edge + // We have to store edge origin separately from the cluster vertices, + // because cluster can have several different edges started on it. + int getEdgeOriginVertices(int edge) { + return m_edges.getField(edge, 2); + } + + void setEdgeOriginVertices_(int edge, int vertices) { + m_edges.setField(edge, 2, vertices); + } + + int getNextEdgeEx(int edge, int end) { + assert (end == 0 || end == 1); + return m_edges.getField(edge, 3 + end); + } + + void setNextEdgeEx_(int edge, int end, int next_edge) { + assert (end == 0 || end == 1); + m_edges.setField(edge, 3 + end, next_edge); + } + + // int get_prev_edge_ex(int edge, int end) + // { + // assert(end == 0 || end == 1); + // return m_edges.get_field(edge, 5 + end); + // } + // void set_prev_edge_ex_(int edge, int end, int prevEdge) + // { + // assert(end == 0 || end == 1); + // m_edges.set_field(edge, 5 + end, prevEdge); + // } + + int getEdgeSweepNode(int edge) { + return m_edges.getField(edge, 7); + } + + void setEdgeSweepNode_(int edge, int sweepNode) { + m_edges.setField(edge, 7, sweepNode); + } + + int getNextEdge(int edge, int cluster) { + int end = getEdgeEnd(edge, cluster); + assert (end == 0 || end == 1); + return m_edges.getField(edge, 3 + end); + } + + void setNextEdge_(int edge, int cluster, int next_edge) { + int end = getEdgeEnd(edge, cluster); + assert (end == 0 || end == 1); + m_edges.setField(edge, 3 + end, next_edge); + } + + int getPrevEdge(int edge, int cluster) { + int end = getEdgeEnd(edge, cluster); + assert (end == 0 || end == 1); + return m_edges.getField(edge, 5 + end); + } + + void setPrevEdge_(int edge, int cluster, int prevEdge) { + int end = getEdgeEnd(edge, cluster); + assert (end == 0 || end == 1); + m_edges.setField(edge, 5 + end, prevEdge); + } + + int getClusterVertices(int cluster) { + return m_clusters.getField(cluster, 0); + } + + void setClusterVertices_(int cluster, int vertices) { + m_clusters.setField(cluster, 0, vertices); + } + + int getClusterVertexIndex(int cluster) { + return m_clusters.getField(cluster, 4); + } + + void setClusterVertexIndex_(int cluster, int vindex) { + m_clusters.setField(cluster, 4, vindex); + } + + int getClusterSweepEdgeList(int cluster) { + return m_clusters.getField(cluster, 2); + } + + void setClusterSweepEdgeList_(int cluster, int sweep_edges) { + m_clusters.setField(cluster, 2, sweep_edges); + } + + int getClusterFirstEdge(int cluster) { + return m_clusters.getField(cluster, 1); + } + + void setClusterFirstEdge_(int cluster, int first_edge) { + m_clusters.setField(cluster, 1, first_edge); + } + + int getClusterEventQNode(int cluster) { + return m_clusters.getField(cluster, 3); + } + + void setClusterEventQNode_(int cluster, int node) { + m_clusters.setField(cluster, 3, node); + } + + int newCluster_(int vertex) { + int cluster = m_clusters.newElement(); + int vertexList = m_cluster_vertices.createList(); + setClusterVertices_(cluster, vertexList); + if (vertex != -1) { + m_cluster_vertices.addElement(vertexList, vertex); + assert (m_shape.getUserIndex(vertex, m_vertex_cluster_index) == -1); + m_shape.setUserIndex(vertex, m_vertex_cluster_index, cluster); + setClusterVertexIndex_(cluster, m_shape.getVertexIndex(vertex)); + } else { + setClusterVertexIndex_(cluster, -1); + } + + return cluster; + } + + void deleteCluster_(int cluster) { + m_clusters.deleteElement(cluster); + } + + void addVertexToCluster_(int cluster, int vertex) { + assert (m_shape.getUserIndex(vertex, m_vertex_cluster_index) == -1); + int vertexList = getClusterVertices(cluster); + m_cluster_vertices.addElement(vertexList, vertex); + m_shape.setUserIndex(vertex, m_vertex_cluster_index, cluster); + } + + // Creates a new unattached edge with the given origin. + int newEdge_(int origin_vertex) { + int edge = m_edges.newElement(); + int edgeVertices = m_edge_vertices.createList(); + setEdgeOriginVertices_(edge, edgeVertices); + if (origin_vertex != -1) + m_edge_vertices.addElement(edgeVertices, origin_vertex); + + return edge; + } + + void addVertexToEdge_(int edge, int vertex) { + int vertexList = getEdgeOriginVertices(edge); + m_edge_vertices.addElement(vertexList, vertex); + } + + void deleteEdge_(int edge) { + m_edges.deleteElement(edge); + int ind = m_edges_to_insert_in_sweep_structure.findElement(edge); + if (ind >= 0) + m_edges_to_insert_in_sweep_structure.popElement(ind); + } + + void addEdgeToCluster(int edge, int cluster) { + if (getEdgeCluster(edge, 0) == -1) { + assert (getEdgeCluster(edge, 1) != cluster); + setEdgeCluster_(edge, 0, cluster); + } else if (getEdgeCluster(edge, 1) == -1) { + assert (getEdgeCluster(edge, 0) != cluster); + setEdgeCluster_(edge, 1, cluster); + } else + throw GeometryException.GeometryInternalError(); + + addEdgeToClusterImpl_(edge, cluster);// simply adds the edge to the list + // of cluster edges. + } + + void addEdgeToClusterImpl_(int edge, int cluster) { + int first_edge = getClusterFirstEdge(cluster); + if (first_edge != -1) { + int next = getNextEdge(first_edge, cluster); + setPrevEdge_(next, cluster, edge); + setNextEdge_(edge, cluster, next); + setNextEdge_(first_edge, cluster, edge); + setPrevEdge_(edge, cluster, first_edge); + } else { + setPrevEdge_(edge, cluster, edge);// point to itself + setNextEdge_(edge, cluster, edge); + setClusterFirstEdge_(cluster, edge); + } + } + + int getEdgeEnd(int edge, int cluster) { + if (getEdgeCluster(edge, 0) == cluster) { + assert (getEdgeCluster(edge, 1) != cluster); + return 0; + } else { + assert (getEdgeCluster(edge, 1) == cluster); + return 1; + } + } + + // Merges two coincident clusters into one. The cluster2 becomes invalid. + void mergeClusters_(int cluster_1, int cluster2) { + // dbg_check_cluster_(cluster_1); + // dbg_check_cluster_(cluster2); + int eventQnode = getClusterEventQNode(cluster2); + if (eventQnode != -1) { + m_event_q.deleteNode(eventQnode, -1); + setClusterEventQNode_(cluster2, -1); + } + + int firstEdge1 = getClusterFirstEdge(cluster_1); + int firstEdge2 = getClusterFirstEdge(cluster2); + + if (firstEdge2 != -1) {// scope + int edge2 = firstEdge2; + int lastEdge = firstEdge2; + boolean bForceContinue = false; + // Delete edges that connect cluster_1 and cluster2. + do { + // dbg_check_edge_(edge2); + bForceContinue = false; + // assert(!StridedIndexTypeCollection.isValidElement(getEdgeSweepNode(edge2))); + int end = getEdgeEnd(edge2, cluster2); + int nextEdge2 = getNextEdgeEx(edge2, end); + if (getEdgeCluster(edge2, (end + 1) & 1) == cluster_1) { // Snapping + // clusters + // that + // are + // connected + // with + // an + // edge + // Delete + // the + // edge. + disconnectEdge_(edge2); + int edgeOrigins2 = getEdgeOriginVertices(edge2); + m_edge_vertices.deleteList(edgeOrigins2); + deleteEdge_(edge2); + if (edge2 == nextEdge2) {// deleted last edge connecting to + // the cluster2 (all connections + // are degenerate) + firstEdge2 = -1; + break; + } + if (firstEdge2 == edge2) { + firstEdge2 = getClusterFirstEdge(cluster2); + lastEdge = nextEdge2; + bForceContinue = true; + } + } else { + assert (edge2 != getClusterFirstEdge(cluster_1)); + } + edge2 = nextEdge2; + } while (edge2 != lastEdge || bForceContinue); + + if (firstEdge2 != -1) { + // set the cluster to the edge ends + do { + int end = getEdgeEnd(edge2, cluster2); + int nextEdge2 = getNextEdgeEx(edge2, end); + assert (edge2 != getClusterFirstEdge(cluster_1)); + setEdgeCluster_(edge2, end, cluster_1); + edge2 = nextEdge2; + } while (edge2 != lastEdge); + + firstEdge1 = getClusterFirstEdge(cluster_1); + if (firstEdge1 != -1) { + int next1 = getNextEdge(firstEdge1, cluster_1); + int next2 = getNextEdge(firstEdge2, cluster_1); + if (next1 == firstEdge1) { + setClusterFirstEdge_(cluster_1, firstEdge2); + addEdgeToClusterImpl_(firstEdge1, cluster_1); + setClusterFirstEdge_(cluster_1, firstEdge1); + } else if (next2 == firstEdge2) { + addEdgeToClusterImpl_(firstEdge2, cluster_1); + } + + setNextEdge_(firstEdge2, cluster_1, next1); + setPrevEdge_(next1, cluster_1, firstEdge2); + setNextEdge_(firstEdge1, cluster_1, next2); + setPrevEdge_(next2, cluster_1, firstEdge1); + } else { + setClusterFirstEdge_(cluster_1, firstEdge2); + } + } + } + + int vertices1 = getClusterVertices(cluster_1); + int vertices2 = getClusterVertices(cluster2); + // Update cluster info on vertices. + for (int vh = m_cluster_vertices.getFirst(vertices2); vh != -1; vh = m_cluster_vertices + .getNext(vh)) { + int v = m_cluster_vertices.getElement(vh); + m_shape.setUserIndex(v, m_vertex_cluster_index, cluster_1); + } + m_cluster_vertices.concatenateLists(vertices1, vertices2); + deleteCluster_(cluster2); + // dbg_check_cluster_(cluster_1); + } + + // Merges two coincident edges into one. The edge2 becomes invalid. + void mergeEdges_(int edge1, int edge2) { + // dbg_check_edge_(edge1); + int cluster_1 = getEdgeCluster(edge1, 0); + int cluster2 = getEdgeCluster(edge1, 1); + int cluster21 = getEdgeCluster(edge2, 0); + int cluster22 = getEdgeCluster(edge2, 1); + + int originVertices1 = getEdgeOriginVertices(edge1); + int originVertices2 = getEdgeOriginVertices(edge2); + m_edge_vertices.concatenateLists(originVertices1, originVertices2); + if (edge2 == getClusterFirstEdge(cluster_1)) + setClusterFirstEdge_(cluster_1, edge1); + if (edge2 == getClusterFirstEdge(cluster2)) + setClusterFirstEdge_(cluster2, edge1); + + disconnectEdge_(edge2);// disconnects the edge2 from the clusters. + deleteEdge_(edge2); + + if (!((cluster_1 == cluster21 && cluster2 == cluster22) || (cluster2 == cluster21 && cluster_1 == cluster22))) { + // Merged edges have different clusters (clusters have not yet been + // merged) + // merge clusters before merging the edges + getClusterXY(cluster_1, pt_1); + getClusterXY(cluster21, pt_2); + if (pt_1.isEqual(pt_2)) { + if (cluster_1 != cluster21) { + mergeClusters_(cluster_1, cluster21); + assert (!m_modified_clusters.hasElement(cluster21)); + } + if (cluster2 != cluster22) { + mergeClusters_(cluster2, cluster22); + assert (!m_modified_clusters.hasElement(cluster22)); + } + } else { + if (cluster2 != cluster21) { + mergeClusters_(cluster2, cluster21); + assert (!m_modified_clusters.hasElement(cluster21)); + } + if (cluster_1 != cluster22) { + mergeClusters_(cluster_1, cluster22); + assert (!m_modified_clusters.hasElement(cluster22)); + } + } + } else { + // Merged edges have equal clusters. + } + // dbg_check_edge_(edge1); + } + + // Disconnects the edge from its clusters. + void disconnectEdge_(int edge) { + int cluster_1 = getEdgeCluster(edge, 0); + int cluster2 = getEdgeCluster(edge, 1); + disconnectEdgeFromCluster_(edge, cluster_1); + disconnectEdgeFromCluster_(edge, cluster2); + } + + // Disconnects the edge from a cluster it is connected to. + void disconnectEdgeFromCluster_(int edge, int cluster) { + int next = getNextEdge(edge, cluster); + assert (getPrevEdge(next, cluster) == edge); + int prev = getPrevEdge(edge, cluster); + assert (getNextEdge(prev, cluster) == edge); + int first_edge = getClusterFirstEdge(cluster); + if (next != edge) { + setNextEdge_(prev, cluster, next); + setPrevEdge_(next, cluster, prev); + if (first_edge == edge) + setClusterFirstEdge_(cluster, next); + } else + setClusterFirstEdge_(cluster, -1); + } + + void applyIntersectorToEditShape_(int edgeOrigins, + SegmentIntersector intersector, int intersector_index) { + // Split Edit_shape segments and produce new vertices. Modify + // coordinates as necessary. No vertices are deleted. + int vertexHandle = m_edge_vertices.getFirst(edgeOrigins); + int first_vertex = m_edge_vertices.getElement(vertexHandle); + + int cluster_1 = getClusterFromVertex(first_vertex); + int cluster2 = getClusterFromVertex(m_shape.getNextVertex(first_vertex)); + boolean bComplexCase = cluster_1 == cluster2; + assert (!bComplexCase);// if it ever asserts there will be a bug. Should + // be a case of a curve that forms a loop. + + m_shape.splitSegment_(first_vertex, intersector, intersector_index, + true); + for (vertexHandle = m_edge_vertices.getNext(vertexHandle); vertexHandle != -1; vertexHandle = m_edge_vertices + .getNext(vertexHandle)) { + int vertex = m_edge_vertices.getElement(vertexHandle); + boolean b_forward = getClusterFromVertex(vertex) == cluster_1; + assert ((b_forward && getClusterFromVertex(m_shape + .getNextVertex(vertex)) == cluster2) || (getClusterFromVertex(vertex) == cluster2 && getClusterFromVertex(m_shape + .getNextVertex(vertex)) == cluster_1)); + m_shape.splitSegment_(vertex, intersector, intersector_index, + b_forward); + } + + // Now apply the updated coordinates to all vertices in the cluster_1 + // and cluster2. + Point2D pt_0; + Point2D pt_1; + pt_0 = intersector.getResultSegment(intersector_index, 0).getStartXY(); + pt_1 = intersector.getResultSegment(intersector_index, + intersector.getResultSegmentCount(intersector_index) - 1) + .getEndXY(); + updateClusterXY(cluster_1, pt_0); + updateClusterXY(cluster2, pt_1); + } + + void createEdgesAndClustersFromSplitEdge_(int edge1, + SegmentIntersector intersector, int intersector_index) { + // dbg_check_new_edges_array_(); + // The method uses m_temp_edge_buffer for temporary storage and clears + // it at the end. + int edgeOrigins1 = getEdgeOriginVertices(edge1); + + // create new edges and clusters + // Note that edge1 is disconnected from its clusters already (the + // cluster's edge list does not contain it). + int cluster_1 = getEdgeCluster(edge1, 0); + int cluster2 = getEdgeCluster(edge1, 1); + int prevEdge = newEdge_(-1); + m_edges_to_insert_in_sweep_structure.add(prevEdge); + int c_3 = StridedIndexTypeCollection.impossibleIndex3(); + setEdgeSweepNode_(prevEdge, c_3);// mark that its in + // m_edges_to_insert_in_sweep_structure + m_temp_edge_buffer.add(prevEdge); + addEdgeToCluster(prevEdge, cluster_1); + for (int i = 1, n = intersector + .getResultSegmentCount(intersector_index); i < n; i++) {// each + // iteration + // adds + // new + // Cluster + // and + // Edge. + int newCluster = newCluster_(-1); + m_modified_clusters.add(newCluster); + m_temp_edge_buffer.add(newCluster); + addEdgeToCluster(prevEdge, newCluster); + int newEdge = newEdge_(-1); + m_edges_to_insert_in_sweep_structure.add(newEdge); + setEdgeSweepNode_(newEdge, c_3);// mark that its in + // m_edges_to_insert_in_sweep_structure + m_temp_edge_buffer.add(newEdge); + addEdgeToCluster(newEdge, newCluster); + prevEdge = newEdge; + } + addEdgeToCluster(prevEdge, cluster2); + // set the Edit_shape vertices to the new clusters and edges. + for (int vertexHandle = m_edge_vertices.getFirst(edgeOrigins1); vertexHandle != -1; vertexHandle = m_edge_vertices + .getNext(vertexHandle)) { + int vertex = m_edge_vertices.getElement(vertexHandle); + int cluster = getClusterFromVertex(vertex); + if (cluster == cluster_1) {// connecting from cluster_1 to cluster2 + int i = 0; + do { + if (i > 0) { + int c = m_temp_edge_buffer.get(i - 1); + addVertexToCluster_(c, vertex); + if (getClusterVertexIndex(c) == -1) + setClusterVertexIndex_(c, + m_shape.getVertexIndex(vertex)); + } + + int edge = m_temp_edge_buffer.get(i); + i += 2; + addVertexToEdge_(edge, vertex); + vertex = m_shape.getNextVertex(vertex); + } while (i < m_temp_edge_buffer.size()); + assert (getClusterFromVertex(vertex) == cluster2); + } else {// connecting from cluster2 to cluster_1 + assert (cluster == cluster2); + int i = m_temp_edge_buffer.size() - 1; + do { + if (i < m_temp_edge_buffer.size() - 2) { + int c = m_temp_edge_buffer.get(i + 1); + addVertexToCluster_(c, vertex); + if (getClusterVertexIndex(c) < 0) + setClusterVertexIndex_(c, + m_shape.getVertexIndex(vertex)); + } + + assert (i % 2 == 0); + int edge = m_temp_edge_buffer.get(i); + i -= 2; + addVertexToEdge_(edge, vertex); + vertex = m_shape.getNextVertex(vertex); + } while (i >= 0); + assert (getClusterFromVertex(vertex) == cluster_1); + } + } + + // #ifdef _DEBUG_TOPO + // for (int i = 0, j = 0, n = + // intersector->get_result_segment_count(intersector_index); i < n; i++, + // j+=2) + // { + // int edge = m_temp_edge_buffer.get(j); + // dbg_check_edge_(edge); + // } + // #endif + + m_temp_edge_buffer.clear(false); + // dbg_check_new_edges_array_(); + } + + int getVertexFromClusterIndex(int cluster) { + int vertexList = getClusterVertices(cluster); + int vertex = m_cluster_vertices.getFirstElement(vertexList); + return vertex; + } + + int getClusterFromVertex(int vertex) { + return m_shape.getUserIndex(vertex, m_vertex_cluster_index); + } + + static final class QComparator extends Treap.Comparator { + EditShape m_shape; + Point2D pt_1 = new Point2D(); + Point2D pt_2 = new Point2D(); + + QComparator(EditShape shape) { + m_shape = shape; + } + + @Override + int compare(Treap treap, int vertex, int node) { + m_shape.getXY(vertex, pt_1); + int v_2 = treap.getElement(node); + m_shape.getXY(v_2, pt_2); + return pt_1.compare(pt_2); + } + } + + static final class QMonikerComparator extends Treap.MonikerComparator { + EditShape m_shape; + Point2D m_point = new Point2D(); + Point2D m_pt = new Point2D(); + + QMonikerComparator(EditShape shape) { + m_shape = shape; + } + + void setPoint(Point2D pt) { + m_point.setCoords(pt); + } + + @Override + int compare(Treap treap, int node) { + int v = treap.getElement(node); + m_shape.getXY(v, m_pt); + return m_point.compare(m_pt); + } + } + + ; + + void processSplitHelper1_(int index, int edge, + SegmentIntersector intersector) { + int clusterStart = getEdgeCluster(edge, 0); + Point2D ptClusterStart = new Point2D(); + getClusterXY(clusterStart, ptClusterStart); + Point2D ptClusterEnd = new Point2D(); + int clusterEnd = getEdgeCluster(edge, 1); + getClusterXY(clusterEnd, ptClusterEnd); + + // Collect all edges that are affected by the split and that are in the + // sweep structure. + int count = intersector.getResultSegmentCount(index); + Segment seg = intersector.getResultSegment(index, 0); + Point2D newStart = new Point2D(); + seg.getStartXY(newStart); + + if (!ptClusterStart.isEqual(newStart)) { + if (!m_complications) { + int res1 = ptClusterStart.compare(m_sweep_point); + int res2 = newStart.compare(m_sweep_point); + if (res1 * res2 < 0) { + m_complications = true;// point is not yet have been processed + // but moved before the sweep point, + // this will require + // repeating the cracking step and the sweep_vertical cannot + // help here + } + } + + // This cluster's position needs to be changed + getAffectedEdges(clusterStart, m_temp_edge_buffer); + m_modified_clusters.add(clusterStart); + } + + if (!m_complications && count > 1) { + int dir = ptClusterStart.compare(ptClusterEnd); + Point2D midPoint = seg.getEndXY(); + if (ptClusterStart.compare(midPoint) != dir + || midPoint.compare(ptClusterEnd) != dir) {// split segment + // midpoint is + // above the + // sweep line. + // Therefore the + // part of the + // segment + m_complications = true; + } else { + if (midPoint.compare(m_sweep_point) < 0) { + // midpoint moved below sweepline. + m_complications = true; + } + } + } + + seg = intersector.getResultSegment(index, count - 1); + Point2D newEnd = seg.getEndXY(); + if (!ptClusterEnd.isEqual(newEnd)) { + if (!m_complications) { + int res1 = ptClusterEnd.compare(m_sweep_point); + int res2 = newEnd.compare(m_sweep_point); + if (res1 * res2 < 0) { + m_complications = true;// point is not yet have been processed + // but moved before the sweep point. + } + } + // This cluster's position needs to be changed + getAffectedEdges(clusterEnd, m_temp_edge_buffer); + m_modified_clusters.add(clusterEnd); + } + + m_temp_edge_buffer.add(edge); + // Delete all nodes from the sweep structure that are affected by the + // change. + for (int i = 0, n = m_temp_edge_buffer.size(); i < n; i++) { + int e = m_temp_edge_buffer.get(i); + int sweepNode = getEdgeSweepNode(e); + if (StridedIndexTypeCollection.isValidElement(sweepNode)) { + m_sweep_structure.deleteNode(sweepNode, -1); + setEdgeSweepNode_(e, -1); + } + + int c_3 = StridedIndexTypeCollection.impossibleIndex3(); + if (e != edge && getEdgeSweepNode(e) != c_3)// c_3 means the edge is + // already in the + // m_edges_to_insert_in_sweep_structure + { + m_edges_to_insert_in_sweep_structure.add(e); + setEdgeSweepNode_(e, c_3); + } + } + m_temp_edge_buffer.clear(false); + } + + boolean checkAndFixIntersection_(int leftSweepNode, int rightSweepNode) { + int leftEdge = m_sweep_structure.getElement(leftSweepNode); + m_sweep_comparator.compare(m_sweep_structure, leftEdge, rightSweepNode); + if (m_sweep_comparator.intersectionDetected()) { + m_sweep_comparator.clearIntersectionDetectedFlag(); + fixIntersection_(leftSweepNode, rightSweepNode); + return true; + } + + return false; + } + + void fixIntersection_(int left, int right) { + m_b_cracked = true; + int edge1 = m_sweep_structure.getElement(left); + int edge2 = m_sweep_structure.getElement(right); + assert (edge1 != edge2); + Segment seg_1; + Segment seg_2; + int vertexList1 = getEdgeOriginVertices(edge1); + int origin1 = m_edge_vertices.getFirstElement(vertexList1); + int vertexList2 = getEdgeOriginVertices(edge2); + int origin2 = m_edge_vertices.getFirstElement(vertexList2); + seg_1 = m_shape.getSegment(origin1); + if (seg_1 == null) { + if (m_line_1 == null) + m_line_1 = new Line(); + m_shape.queryLineConnector(origin1, m_line_1); + seg_1 = m_line_1; + } + + seg_2 = m_shape.getSegment(origin2); + if (seg_2 == null) { + if (m_line_2 == null) + m_line_2 = new Line(); + m_shape.queryLineConnector(origin2, m_line_2); + seg_2 = m_line_2; + } + + // #ifdef _DEBUG_CRACKING_REPORT + // { + // Point_2D pt11, pt12, pt21, pt22; + // pt11 = seg_1->get_start_xy(); + // pt12 = seg_1->get_end_xy(); + // pt21 = seg_2->get_start_xy(); + // pt22 = seg_2->get_end_xy(); + // DEBUGPRINTF(L"Intersecting %d (%0.4f, %0.4f - %0.4f, %0.4f) and %d (%0.4f, %0.4f - %0.4f, %0.4f)\n", + // edge1, pt11.x, pt11.y, pt12.x, pt12.y, edge2, pt21.x, pt21.y, pt22.x, + // pt22.y); + // } + // #endif + + m_segment_intersector.pushSegment(seg_1); + m_segment_intersector.pushSegment(seg_2); + if (m_segment_intersector.intersect(m_tolerance, true)) + m_complications = true; + + + splitEdge_(edge1, edge2, -1, m_segment_intersector); + m_segment_intersector.clear(); + } + + void fixIntersectionPointSegment_(int cluster, int node) { + m_b_cracked = true; + int edge1 = m_sweep_structure.getElement(node); + Segment seg_1; + int vertexList1 = getEdgeOriginVertices(edge1); + int origin1 = m_edge_vertices.getFirstElement(vertexList1); + seg_1 = m_shape.getSegment(origin1); + if (seg_1 == null) { + if (m_line_1 == null) + m_line_1 = new Line(); + m_shape.queryLineConnector(origin1, m_line_1); + seg_1 = m_line_1; + } + + int clusterVertex = getClusterFirstVertex(cluster); + m_segment_intersector.pushSegment(seg_1); + + m_shape.queryPoint(clusterVertex, m_helper_point); + m_segment_intersector.intersect(m_tolerance, m_helper_point, 0, 1.0, + true); + + splitEdge_(edge1, -1, cluster, m_segment_intersector); + + m_segment_intersector.clear(); + } + + void insertNewEdges_() { + if (m_edges_to_insert_in_sweep_structure.size() == 0) + return; + + while (m_edges_to_insert_in_sweep_structure.size() != 0) { + if (m_edges_to_insert_in_sweep_structure.size() > Math.max( + (int) 100, m_shape.getTotalPointCount())) { + assert (false); + m_edges_to_insert_in_sweep_structure.clear(false); + m_complications = true; + break;// something strange going on here. bail out, forget about + // these edges and continue with sweep line. We'll + // iterate on the data one more time. + } + + int edge = m_edges_to_insert_in_sweep_structure.getLast(); + m_edges_to_insert_in_sweep_structure.removeLast(); + + assert (getEdgeSweepNode(edge) == StridedIndexTypeCollection + .impossibleIndex3()); + setEdgeSweepNode_(edge, -1); + int terminatingCluster = isEdgeOnSweepLine_(edge); + if (terminatingCluster != -1) { + insertNewEdgeToSweepStructure_(edge, terminatingCluster); + } + m_b_continuing_segment_chain_optimization = false; + } + } + + boolean insertNewEdgeToSweepStructure_(int edge, int terminatingCluster) { + assert (getEdgeSweepNode(edge) == -1); + int newEdgeNode; + if (m_b_continuing_segment_chain_optimization) { + newEdgeNode = m_sweep_structure.addElementAtPosition( + m_prev_neighbour, m_next_neighbour, edge, true, true, -1); + m_b_continuing_segment_chain_optimization = false; + } else { + newEdgeNode = m_sweep_structure.addUniqueElement(edge, -1); + } + + if (newEdgeNode == -1) {// a coinciding edge. + int existingNode = m_sweep_structure.getDuplicateElement(-1); + int existingEdge = m_sweep_structure.getElement(existingNode); + mergeEdges_(existingEdge, edge); + return false; + } + + // Remember the sweep structure node in the edge. + setEdgeSweepNode_(edge, newEdgeNode); + + if (m_sweep_comparator.intersectionDetected()) { + // The edge has been inserted into the sweep structure and an + // intersection has beebn found. The edge will be split and removed. + m_sweep_comparator.clearIntersectionDetectedFlag(); + int intersectionNode = m_sweep_comparator.getLastComparedNode(); + fixIntersection_(intersectionNode, newEdgeNode); + return true; + } else { + // The edge has been inserted into the sweep structure without + // problems (it does not intersect its neighbours) + } + + return false; + } + + Point2D pt_1 = new Point2D(); + Point2D pt_2 = new Point2D(); + + int isEdgeOnSweepLine_(int edge) { + int cluster_1 = getEdgeCluster(edge, 0); + int cluster2 = getEdgeCluster(edge, 1); + getClusterXY(cluster_1, pt_1); + getClusterXY(cluster2, pt_2); + if (Point2D.sqrDistance(pt_1, pt_2) <= m_tolerance_sqr) {// avoid + // degenerate + // segments + m_complications = true; + return -1; + } + int cmp1 = pt_1.compare(m_sweep_point); + int cmp2 = pt_2.compare(m_sweep_point); + if (cmp1 <= 0 && cmp2 > 0) { + return cluster2; + } + + if (cmp2 <= 0 && cmp1 > 0) { + return cluster_1; + } + + return -1; + } + + // void set_edit_shape(Edit_shape* shape); + // Fills the event queue and merges coincident clusters. + void fillEventQueue() { + AttributeStreamOfInt32 event_q = new AttributeStreamOfInt32(0); + event_q.reserve(m_shape.getTotalPointCount());// temporary structure to + // sort and find + // clusters + EditShape.VertexIterator iter = m_shape.queryVertexIterator(); + for (int vert = iter.next(); vert != -1; vert = iter.next()) { + if (m_shape.getUserIndex(vert, m_vertex_cluster_index) != -1) + event_q.add(vert); + } + + // Now we can merge coincident clusters and form the envent structure. + + // sort vertices lexicographically. + m_shape.sortVerticesSimpleByY_(event_q, 0, event_q.size()); + + // The m_event_q is the event structure for the planesweep algorithm. + // We could use any data structure that allows log(n) insertion and + // deletion in the sorted order and + // allow to iterate through in the sorted order. + + m_event_q.clear(); + // Populate the event structure + m_event_q.setCapacity(event_q.size()); + { + // The comparator is used to sort vertices by the m_event_q + m_event_q.setComparator(new QComparator(m_shape)); + } + + // create the vertex clusters and fill the event structure m_event_q. + // Because most vertices are expected to be non clustered, we create + // clusters only for actual clusters to save some memory. + Point2D cluster_pt = new Point2D(); + cluster_pt.setNaN(); + int cluster = -1; + Point2D pt = new Point2D(); + for (int index = 0, nvertex = event_q.size(); index < nvertex; index++) { + int vertex = event_q.get(index); + m_shape.getXY(vertex, pt); + if (pt.isEqual(cluster_pt)) { + int vertexCluster = m_shape.getUserIndex(vertex, + m_vertex_cluster_index); + mergeClusters_(cluster, vertexCluster); + continue; + } + + cluster = getClusterFromVertex(vertex); + // add a vertex to the event queue + m_shape.getXY(vertex, cluster_pt); + int eventQnode = m_event_q.addBiggestElement(vertex, -1); // this + // method + // does + // not + // call + // comparator's + // compare, + // assuming + // sorted + // order. + setClusterEventQNode_(cluster, eventQnode); + } + } + + void fillEventQueuePass2() { + AttributeStreamOfInt32 event_q = new AttributeStreamOfInt32(0); + event_q.reserve(m_shape.getTotalPointCount());// temporary structure to + // sort and find + // clusters + for (int node = m_event_q.getFirst(-1); node != -1; node = m_event_q + .getNext(node)) { + int v = m_event_q.getElement(node); + event_q.add(v); + } + + assert (event_q.size() == m_event_q.size(-1)); + + m_event_q.clear(); + + // sort vertices lexicographically. + m_shape.sortVerticesSimpleByY_(event_q, 0, event_q.size()); + + for (int index = 0, nvertex = event_q.size(); index < nvertex; index++) { + int vertex = event_q.get(index); + int cluster = getClusterFromVertex(vertex); + int eventQnode = m_event_q.addBiggestElement(vertex, -1); // this + // method + // does + // not + // call + // comparator's + // compare, + // assuming + // sorted + // order. + setClusterEventQNode_(cluster, eventQnode); + } + } + + // Returns edges already in the sweep structure that are affected by the + // change of cluster coordinate. + void getAffectedEdges(int cluster, AttributeStreamOfInt32 edges) { + int first_edge = getClusterFirstEdge(cluster); + if (first_edge == -1) + return; + + int edge = first_edge; + do { + int sweepNode = getEdgeSweepNode(edge); + if (StridedIndexTypeCollection.isValidElement(sweepNode)) { + edges.add(edge); + } + edge = getNextEdge(edge, cluster); + } while (edge != first_edge); + } + + // Updates all vertices of the cluster to new coordinate + void updateClusterXY(int cluster, Point2D pt) { + int vertexList = getClusterVertices(cluster); + for (int vh = m_cluster_vertices.getFirst(vertexList); vh != -1; vh = m_cluster_vertices + .getNext(vh)) { + int vertex = m_cluster_vertices.getElement(vh); + m_shape.setXY(vertex, pt); + } + } + + // Modifies the given edges given the intersector class and the result + // index. + // The function updates the the event structure and puts new edges into the + // m_edges_to_insert_in_sweep_structure. + void splitEdge_(int edge1, int edge2, int intersectionCluster, + SegmentIntersector intersector) { + + disconnectEdge_(edge1);// disconnects the edge from the clusters. The + // edge still remembers the clusters. + if (edge2 != -1) + disconnectEdge_(edge2);// disconnects the edge from the clusters. + // The edge still remembers the clusters. + + // Collect all edges that are affected when the clusters change position + // due to snapping + // The edges are collected in m_edges_to_insert_in_sweep_structure. + // Collect the modified clusters in m_modified_clusters. + processSplitHelper1_(0, edge1, intersector); + if (edge2 != -1) + processSplitHelper1_(1, edge2, intersector); + + if (intersectionCluster != -1) { + intersector.getResultPoint().getXY(pt_1); + getClusterXY(intersectionCluster, pt_2); + if (!pt_2.isEqual(pt_1)) + m_modified_clusters.add(intersectionCluster); + } + + // remove modified clusters from the event queue. We'll reincert them + // later + for (int i = 0, n = m_modified_clusters.size(); i < n; i++) { + int cluster = m_modified_clusters.get(i); + int eventQnode = getClusterEventQNode(cluster); + if (eventQnode != -1) { + m_event_q.deleteNode(eventQnode, -1); + setClusterEventQNode_(cluster, -1); + } + } + + int edgeOrigins1 = getEdgeOriginVertices(edge1); + int edgeOrigins2 = (edge2 != -1) ? getEdgeOriginVertices(edge2) : -1; + + // Adjust the vertex coordinates and split the segments in the the edit + // shape. + applyIntersectorToEditShape_(edgeOrigins1, intersector, 0); + if (edge2 != -1) + applyIntersectorToEditShape_(edgeOrigins2, intersector, 1); + + // Produce clusters, and new edges. The new edges are added to + // m_edges_to_insert_in_sweep_structure. + createEdgesAndClustersFromSplitEdge_(edge1, intersector, 0); + if (edge2 != -1) + createEdgesAndClustersFromSplitEdge_(edge2, intersector, 1); + + m_edge_vertices.deleteList(edgeOrigins1); + deleteEdge_(edge1); + + if (edge2 != -1) { + m_edge_vertices.deleteList(edgeOrigins2); + deleteEdge_(edge2); + } + + // insert clusters into the event queue and the edges into the sweep + // structure. + for (int i = 0, n = m_modified_clusters.size(); i < n; i++) { + int cluster = m_modified_clusters.get(i); + if (cluster == m_sweep_point_cluster) + m_b_sweep_point_cluster_was_modified = true; + + int eventQnode = getClusterEventQNode(cluster); + if (eventQnode == -1) { + int vertex = getClusterFirstVertex(cluster); + assert (getClusterFromVertex(vertex) == cluster); + + eventQnode = m_event_q.addUniqueElement(vertex, -1);// O(logN) + // operation + if (eventQnode == -1) {// the cluster is coinciding with another + // one. merge. + int existingNode = m_event_q.getDuplicateElement(-1); + int v = m_event_q.getElement(existingNode); + assert (m_shape.isEqualXY(vertex, v)); + int existingCluster = getClusterFromVertex(v); + mergeClusters_(existingCluster, cluster); + } else { + setClusterEventQNode_(cluster, eventQnode); + } + } else { + // if already inserted (probably impossible) case + } + } + + m_modified_clusters.clear(false); + } + + // Returns a cluster's xy. + void getClusterXY(int cluster, Point2D ptOut) { + int vindex = getClusterVertexIndex(cluster); + m_shape.getXYWithIndex(vindex, ptOut); + } + + int getClusterFirstVertex(int cluster) { + int vertexList = getClusterVertices(cluster); + int vertex = m_cluster_vertices.getFirstElement(vertexList); + return vertex; + } + + boolean sweepImpl_() { + m_b_sweep_point_cluster_was_modified = false; + m_sweep_point_cluster = -1; + if (m_sweep_comparator == null) { + m_sweep_structure.disableBalancing(); + m_sweep_comparator = new SimplifySweepComparator(this); + m_sweep_structure.setComparator(m_sweep_comparator); + } + + AttributeStreamOfInt32 edgesToDelete = new AttributeStreamOfInt32(0); + SimplifySweepMonikerComparator sweepMoniker = null; + QMonikerComparator moniker = null; + + int iterationCounter = 0; + m_prev_neighbour = -1; + m_next_neighbour = -1; + m_b_continuing_segment_chain_optimization = false; + + int c_2 = StridedIndexTypeCollection.impossibleIndex2(); + int c_3 = StridedIndexTypeCollection.impossibleIndex3(); + assert (c_2 != c_3); + + for (int eventQnode = m_event_q.getFirst(-1); eventQnode != -1; ) { + iterationCounter++; + m_b_continuing_segment_chain_optimization = false; + + int vertex = m_event_q.getElement(eventQnode); + m_sweep_point_cluster = getClusterFromVertex(vertex); + m_shape.getXY(vertex, m_sweep_point); + + m_sweep_comparator.setSweepY(m_sweep_point.y, m_sweep_point.x);// move + // the + // sweep + // line + + boolean bDisconnectedCluster = false; + {// scope + int first_edge = getClusterFirstEdge(m_sweep_point_cluster); + bDisconnectedCluster = first_edge == -1; + if (!bDisconnectedCluster) { + int edge = first_edge; + do { + int sweepNode = getEdgeSweepNode(edge); + if (sweepNode == -1) { + m_edges_to_insert_in_sweep_structure.add(edge); + setEdgeSweepNode_(edge, c_3);// mark that its in + // m_edges_to_insert_in_sweep_structure + } else if (sweepNode != c_3) { + assert (StridedIndexTypeCollection.isValidElement(sweepNode)); + edgesToDelete.add(sweepNode); + } + edge = getNextEdge(edge, m_sweep_point_cluster); + } while (edge != first_edge); + } + } + + // st_counter_insertions_peaks += edgesToDelete.size() == 0 && + // m_edges_to_insert_in_sweep_structure.size() > 0; + // First step is to delete the edges that terminate in the + // cluster. + // During that step we also determine the left and right neighbors + // of the deleted bunch and then check if those left and right + // intersect or not. + if (edgesToDelete.size() > 0) { + m_b_continuing_segment_chain_optimization = (edgesToDelete + .size() == 1 && m_edges_to_insert_in_sweep_structure + .size() == 1); + + // Mark nodes that need to be deleted by setting c_2 to the + // edge's sweep node member. + for (int i = 0, n = edgesToDelete.size(); i < n; i++) { + int edge = m_sweep_structure.getElement(edgesToDelete + .get(i)); + setEdgeSweepNode_(edge, c_2); + } + + int left = c_2; + int right = c_2; + // Determine left and right nodes for the bunch of nodes we are + // deleting. + for (int i = 0, n = edgesToDelete.size(); i < n; i++) { + int sweepNode = edgesToDelete.get(i); + if (left == c_2) { + int localleft = m_sweep_structure.getPrev(sweepNode); + if (localleft != -1) { + int edge = m_sweep_structure.getElement(localleft); + int node = getEdgeSweepNode(edge); + if (node != c_2) + left = localleft; + } else + left = -1; + } + + if (right == c_2) { + int localright = m_sweep_structure.getNext(sweepNode); + if (localright != -1) { + int edge = m_sweep_structure.getElement(localright); + int node = getEdgeSweepNode(edge); + if (node != c_2) + right = localright; + } else + right = -1; + } + + if (left != c_2 && right != c_2) + break; + } + + assert (left != c_2 && right != c_2); + // Now delete the bunch. + for (int i = 0, n = edgesToDelete.size(); i < n; i++) { + int sweepNode = edgesToDelete.get(i); + int edge = m_sweep_structure.getElement(sweepNode); + m_sweep_structure.deleteNode(sweepNode, -1); + setEdgeSweepNode_(edge, -1); + } + + edgesToDelete.clear(false); + + m_prev_neighbour = left != -1 ? left : -1; + m_next_neighbour = right != -1 ? right : -1; + + // Now check if the left and right we found intersect or not. + if (left != -1 && right != -1) { + if (!m_b_continuing_segment_chain_optimization) { + boolean bIntersected = checkAndFixIntersection_(left, + right); + } + } else { + if ((left == -1) && (right == -1)) + m_b_continuing_segment_chain_optimization = false; + } + } else { + // edgesToDelete.size() == 0 - nothing to delete here. This is a + // cluster which has all edges directed up or a disconnected + // cluster. + + if (bDisconnectedCluster) {// check standalone cluster (point or + // multipoint) if it cracks an edge. + if (sweepMoniker == null) + sweepMoniker = new SimplifySweepMonikerComparator(this); + + sweepMoniker.setPoint(m_sweep_point); + m_sweep_structure.searchUpperBound(sweepMoniker, -1); + if (sweepMoniker.intersectionDetected()) { + sweepMoniker.clearIntersectionDetectedFlag(); + fixIntersectionPointSegment_(m_sweep_point_cluster, + sweepMoniker.getCurrentNode()); + } + } + } + + // Now insert edges that start at the cluster and go up + insertNewEdges_(); + + if (m_b_sweep_point_cluster_was_modified) { + m_b_sweep_point_cluster_was_modified = false; + if (moniker == null) + moniker = new QMonikerComparator(m_shape); + moniker.setPoint(m_sweep_point); + eventQnode = m_event_q.searchUpperBound(moniker, -1); + } else + eventQnode = m_event_q.getNext(eventQnode); + } + + return m_b_cracked; + } + + void setEditShape_(EditShape shape) { + // Populate the cluster and edge structures. + m_shape = shape; + m_vertex_cluster_index = m_shape.createUserIndex(); + + m_edges.setCapacity(shape.getTotalPointCount() + 32); + + m_clusters.setCapacity(shape.getTotalPointCount()); + + m_cluster_vertices.reserveLists(shape.getTotalPointCount()); + m_cluster_vertices.reserveNodes(shape.getTotalPointCount()); + + m_edge_vertices.reserveLists(shape.getTotalPointCount() + 32); + m_edge_vertices.reserveNodes(shape.getTotalPointCount() + 32); + + for (int geometry = m_shape.getFirstGeometry(); geometry != -1; geometry = m_shape + .getNextGeometry(geometry)) { + boolean bMultiPath = Geometry.isMultiPath(m_shape + .getGeometryType(geometry)); + + if (!bMultiPath) {// for multipoints do not add edges. + assert (m_shape.getGeometryType(geometry) == Geometry.GeometryType.MultiPoint); + + for (int path = m_shape.getFirstPath(geometry); path != -1; path = m_shape + .getNextPath(path)) { + int vertex = m_shape.getFirstVertex(path); + for (int i = 0, n = m_shape.getPathSize(path); i < n; i++) { + // int cluster + newCluster_(vertex); + vertex = m_shape.getNextVertex(vertex); + } + } + continue; + } + + for (int path = m_shape.getFirstPath(geometry); path != -1; path = m_shape + .getNextPath(path)) { + int path_size = m_shape.getPathSize(path); + assert (path_size > 1); + int first_vertex = m_shape.getFirstVertex(path); + + // first------------------ + int firstCluster = newCluster_(first_vertex); + int first_edge = newEdge_(first_vertex); + addEdgeToCluster(first_edge, firstCluster); + int prevEdge = first_edge; + int vertex = m_shape.getNextVertex(first_vertex); + for (int index = 0, n = path_size - 2; index < n; index++) { + int nextvertex = m_shape.getNextVertex(vertex); + // ------------x------------ + int cluster = newCluster_(vertex); + addEdgeToCluster(prevEdge, cluster); + int newEdge = newEdge_(vertex); + addEdgeToCluster(newEdge, cluster); + prevEdge = newEdge; + vertex = nextvertex; + } + + // ------------------lastx + if (m_shape.isClosedPath(path)) { + int cluster = newCluster_(vertex); + addEdgeToCluster(prevEdge, cluster); + // close the path + // lastx------------------firstx + int newEdge = newEdge_(vertex); + addEdgeToCluster(newEdge, cluster); + addEdgeToCluster(newEdge, firstCluster); + } else { + // ------------------lastx + int cluster = newCluster_(vertex); + addEdgeToCluster(prevEdge, cluster); + } + + } + } + + fillEventQueue(); + + // int perPoint = estimate_memory_size() / + // m_shape.get_total_point_count(); + // perPoint = 0; + } } diff --git a/src/main/java/com/esri/core/geometry/Point.java b/src/main/java/com/esri/core/geometry/Point.java index 83d7d074..cc5b7042 100644 --- a/src/main/java/com/esri/core/geometry/Point.java +++ b/src/main/java/com/esri/core/geometry/Point.java @@ -36,322 +36,309 @@ * Systems, the X coordinate is the longitude and the Y is the latitude. */ public class Point extends Geometry implements Serializable { - //We are using writeReplace instead. - //private static final long serialVersionUID = 2L; - - double[] m_attributes; // use doubles to store everything (long are bitcast) - - /** - * Creates an empty 2D point. - */ - public Point() { - m_description = VertexDescriptionDesignerImpl.getDefaultDescriptor2D(); - } - - public Point(VertexDescription vd) { - if (vd == null) - throw new IllegalArgumentException(); - m_description = vd; - } - - /** - * Creates a 2D Point with specified X and Y coordinates. In case of - * Geographic Coordinate Systems, the X coordinate is the longitude and the - * Y is the latitude. - * - * @param x The X coordinate of the new 2D point. - * @param y The Y coordinate of the new 2D point. - */ - public Point(double x, double y) { - m_description = VertexDescriptionDesignerImpl.getDefaultDescriptor2D(); - setXY(x, y); - } - - public Point(Point2D pt) { - m_description = VertexDescriptionDesignerImpl.getDefaultDescriptor2D(); - setXY(pt); - } - - /** - * Creates a 3D point with specified X, Y and Z coordinates. In case of - * Geographic Coordinate Systems, the X coordinate is the longitude and the - * Y is the latitude. - * - * @param x The X coordinate of the new 3D point. - * @param y The Y coordinate of the new 3D point. - * @param z The Z coordinate of the new 3D point. - */ - public Point(double x, double y, double z) { - m_description = VertexDescriptionDesignerImpl.getDefaultDescriptor2D(); - Point3D pt = new Point3D(); - pt.setCoords(x, y, z); - setXYZ(pt); - - } - - /** - * Returns XY coordinates of this point. - */ - public final Point2D getXY() { - if (isEmptyImpl()) - throw new GeometryException( - "This operation should not be performed on an empty geometry."); - - Point2D pt = new Point2D(); - pt.setCoords(m_attributes[0], m_attributes[1]); - return pt; - } - - /** - * Returns XY coordinates of this point. - */ - public final void getXY(Point2D pt) { - if (isEmptyImpl()) - throw new GeometryException( - "This operation should not be performed on an empty geometry."); - - pt.setCoords(m_attributes[0], m_attributes[1]); - } - - /** - * Sets the XY coordinates of this point. param pt The point to create the X - * and Y coordinate from. - */ - public final void setXY(Point2D pt) { - _touch(); - setXY(pt.x, pt.y); - } - - /** - * Returns XYZ coordinates of the point. Z will be set to 0 if Z is missing. - */ - public Point3D getXYZ() { - if (isEmptyImpl()) - throw new GeometryException( - "This operation should not be performed on an empty geometry."); - - Point3D pt = new Point3D(); - pt.x = m_attributes[0]; - pt.y = m_attributes[1]; - if (m_description.hasZ()) - pt.z = m_attributes[2]; - else - pt.z = VertexDescription.getDefaultValue(Semantics.Z); - - return pt; - } - - /** - * Sets the XYZ coordinates of this point. - * - * @param pt The point to create the XYZ coordinate from. - */ - public void setXYZ(Point3D pt) { - _touch(); - boolean bHasZ = hasAttribute(Semantics.Z); - if (!bHasZ && !VertexDescription.isDefaultValue(Semantics.Z, pt.z)) {// add - // Z - // only - // if - // pt.z - // is - // not - // a - // default - // value. - addAttribute(Semantics.Z); - bHasZ = true; - } - - if (m_attributes == null) - _setToDefault(); - - m_attributes[0] = pt.x; - m_attributes[1] = pt.y; - if (bHasZ) - m_attributes[2] = pt.z; - } - - /** - * Returns the X coordinate of the point. - */ - public final double getX() { - if (isEmptyImpl()) - throw new GeometryException( - "This operation should not be performed on an empty geometry."); - - return m_attributes[0]; - } - - /** - * Sets the X coordinate of the point. - * - * @param x The X coordinate to be set for this point. - */ - public void setX(double x) { - setAttribute(Semantics.POSITION, 0, x); - } - - /** - * Returns the Y coordinate of this point. - */ - public final double getY() { - if (isEmptyImpl()) - throw new GeometryException( - "This operation should not be performed on an empty geometry."); - - return m_attributes[1]; - } - - /** - * Sets the Y coordinate of this point. - * - * @param y The Y coordinate to be set for this point. - */ - public void setY(double y) { - setAttribute(Semantics.POSITION, 1, y); - } - - /** - * Returns the Z coordinate of this point. - */ - public double getZ() { - return getAttributeAsDbl(Semantics.Z, 0); - } - - /** - * Sets the Z coordinate of this point. - * - * @param z The Z coordinate to be set for this point. - */ - public void setZ(double z) { - setAttribute(Semantics.Z, 0, z); - } - - /** - * Returns the attribute M of this point. - */ - public double getM() { - return getAttributeAsDbl(Semantics.M, 0); - } - - /** - * Sets the M coordinate of this point. - * - * @param m The M coordinate to be set for this point. - */ - public void setM(double m) { - setAttribute(Semantics.M, 0, m); - } - - /** - * Returns the ID of this point. - */ - public int getID() { - return getAttributeAsInt(Semantics.ID, 0); - } - - /** - * Sets the ID of this point. - * - * @param id The ID of this point. - */ - public void setID(int id) { - setAttribute(Semantics.ID, 0, id); - } - - /** - * Returns value of the given vertex attribute's ordinate. - * - * @param semantics The attribute semantics. - * @param ordinate The attribute's ordinate. For example, the Y coordinate of the - * NORMAL has ordinate of 1. - * @return The ordinate as double value. - */ - public double getAttributeAsDbl(int semantics, int ordinate) { - if (isEmptyImpl()) - throw new GeometryException( - "This operation was performed on an Empty Geometry."); - - int ncomps = VertexDescription.getComponentCount(semantics); - if (ordinate >= ncomps) - throw new IndexOutOfBoundsException(); - - int attributeIndex = m_description.getAttributeIndex(semantics); - if (attributeIndex >= 0) - return m_attributes[m_description - ._getPointAttributeOffset(attributeIndex) + ordinate]; - else - return VertexDescription.getDefaultValue(semantics); - } - - /** - * Returns value of the given vertex attribute's ordinate. The ordinate is - * always 0 because integer attributes always have one component. - * - * @param semantics The attribute semantics. - * @param ordinate The attribute's ordinate. For example, the y coordinate of the - * NORMAL has ordinate of 1. - * @return The ordinate value truncated to a 32 bit integer value. - */ - public int getAttributeAsInt(int semantics, int ordinate) { - if (isEmptyImpl()) - throw new GeometryException( - "This operation was performed on an Empty Geometry."); - - int ncomps = VertexDescription.getComponentCount(semantics); - if (ordinate >= ncomps) - throw new IndexOutOfBoundsException(); - - int attributeIndex = m_description.getAttributeIndex(semantics); - if (attributeIndex >= 0) - return (int) m_attributes[m_description - ._getPointAttributeOffset(attributeIndex) + ordinate]; - else - return (int) VertexDescription.getDefaultValue(semantics); - } - - /** - * Sets the value of the attribute. - * - * @param semantics The attribute semantics. - * @param ordinate The ordinate of the attribute. - * @param value Is the array to write values to. The attribute type and the - * number of elements must match the persistence type, as well as - * the number of components of the attribute. - */ - public void setAttribute(int semantics, int ordinate, double value) { - _touch(); - int ncomps = VertexDescription.getComponentCount(semantics); - if (ncomps < ordinate) - throw new IndexOutOfBoundsException(); - - int attributeIndex = m_description.getAttributeIndex(semantics); - if (attributeIndex < 0) { - addAttribute(semantics); - attributeIndex = m_description.getAttributeIndex(semantics); - } - - if (m_attributes == null) - _setToDefault(); - - m_attributes[m_description._getPointAttributeOffset(attributeIndex) - + ordinate] = value; - } - - public void setAttribute(int semantics, int ordinate, int value) { - setAttribute(semantics, ordinate, (double) value); - } - - @Override - public Geometry.Type getType() { - return Type.Point; - } - - @Override - public int getDimension() { - return 0; - } + //We are using writeReplace instead. + //private static final long serialVersionUID = 2L; + + private double m_x; + private double m_y; + private double[] m_attributes; // use doubles to store everything (long are bitcast) + + /** + * Creates an empty 2D point. + */ + public Point() { + m_description = VertexDescriptionDesignerImpl.getDefaultDescriptor2D(); + m_x = NumberUtils.TheNaN; + m_y = NumberUtils.TheNaN; + } + + public Point(VertexDescription vd) { + if (vd == null) + throw new IllegalArgumentException(); + m_description = vd; + _setToDefault(); + } + + /** + * Creates a 2D Point with specified X and Y coordinates. In case of + * Geographic Coordinate Systems, the X coordinate is the longitude and the + * Y is the latitude. + * + * @param x + * The X coordinate of the new 2D point. + * @param y + * The Y coordinate of the new 2D point. + */ + public Point(double x, double y) { + m_description = VertexDescriptionDesignerImpl.getDefaultDescriptor2D(); + setXY(x, y); + } + + public Point(Point2D pt) { + m_description = VertexDescriptionDesignerImpl.getDefaultDescriptor2D(); + setXY(pt); + } + + /** + * Creates a 3D point with specified X, Y and Z coordinates. In case of + * Geographic Coordinate Systems, the X coordinate is the longitude and the + * Y is the latitude. + * + * @param x + * The X coordinate of the new 3D point. + * @param y + * The Y coordinate of the new 3D point. + * @param z + * The Z coordinate of the new 3D point. + * + */ + public Point(double x, double y, double z) { + m_description = VertexDescriptionDesignerImpl.getDefaultDescriptor2D(); + Point3D pt = new Point3D(); + pt.setCoords(x, y, z); + setXYZ(pt); + } + + /** + * Returns XY coordinates of this point. + */ + public final Point2D getXY() { + Point2D pt = new Point2D(); + pt.setCoords(m_x, m_y); + return pt; + } + + /** + * Returns XY coordinates of this point. + */ + public final void getXY(Point2D pt) { + pt.setCoords(m_x, m_y); + } + + /** + * Sets the XY coordinates of this point. param pt The point to create the X + * and Y coordinate from. + */ + public final void setXY(Point2D pt) { + _touch(); + setXY(pt.x, pt.y); + } + + /** + * Returns XYZ coordinates of the point. Z will be set to 0 if Z is missing. + */ + public Point3D getXYZ() { + Point3D pt = new Point3D(); + pt.x = m_x; + pt.y = m_y; + pt.z = hasZ() ? m_attributes[0] : VertexDescription.getDefaultValue(VertexDescription.Semantics.Z); + + return pt; + } + + /** + * Sets the XYZ coordinates of this point. + * + * @param pt + * The point to create the XYZ coordinate from. + */ + public void setXYZ(Point3D pt) { + _touch(); + addAttribute(Semantics.Z); + m_x = pt.x; + m_y = pt.y; + m_attributes[0] = pt.z; + } + + /** + * Returns the X coordinate of the point. + */ + public final double getX() { + return m_x; + } + + /** + * Sets the X coordinate of the point. + * + * @param x + * The X coordinate to be set for this point. + */ + public void setX(double x) { + m_x = x; + } + + /** + * Returns the Y coordinate of this point. + */ + public final double getY() { + return m_y; + } + + /** + * Sets the Y coordinate of this point. + * + * @param y + * The Y coordinate to be set for this point. + */ + public void setY(double y) { + m_y = y; + } + + /** + * Returns the Z coordinate of this point. + */ + public double getZ() { + return hasZ() ? m_attributes[0] : VertexDescription.getDefaultValue(VertexDescription.Semantics.Z); + } + + /** + * Sets the Z coordinate of this point. + * + * @param z + * The Z coordinate to be set for this point. + */ + public void setZ(double z) { + setAttribute(Semantics.Z, 0, z); + } + + /** + * Returns the attribute M of this point. + */ + public double getM() { + return getAttributeAsDbl(Semantics.M, 0); + } + + /** + * Sets the M coordinate of this point. + * + * @param m + * The M coordinate to be set for this point. + */ + public void setM(double m) { + setAttribute(Semantics.M, 0, m); + } + + /** + * Returns the ID of this point. + */ + public int getID() { + return getAttributeAsInt(Semantics.ID, 0); + } + + /** + * Sets the ID of this point. + * + * @param id + * The ID of this point. + */ + public void setID(int id) { + setAttribute(Semantics.ID, 0, id); + } + + /** + * Returns value of the given vertex attribute's ordinate. + * + * @param semantics + * The attribute semantics. + * @param ordinate + * The attribute's ordinate. For example, the Y coordinate of the + * NORMAL has ordinate of 1. + * @return The ordinate as double value. + */ + public double getAttributeAsDbl(int semantics, int ordinate) { + if (semantics == VertexDescription.Semantics.POSITION) { + if (ordinate == 0) { + return m_x; + } + else if (ordinate == 1) { + return m_y; + } + else { + throw new IndexOutOfBoundsException(); + } + } + + int ncomps = VertexDescription.getComponentCount(semantics); + if (ordinate >= ncomps) + throw new IndexOutOfBoundsException(); + + int attributeIndex = m_description.getAttributeIndex(semantics); + if (attributeIndex >= 0) + return m_attributes[m_description + ._getPointAttributeOffset(attributeIndex) - 2 + ordinate]; + else + return VertexDescription.getDefaultValue(semantics); + } + + /** + * Returns value of the given vertex attribute's ordinate. The ordinate is + * always 0 because integer attributes always have one component. + * + * @param semantics + * The attribute semantics. + * @param ordinate + * The attribute's ordinate. For example, the y coordinate of the + * NORMAL has ordinate of 1. + * @return The ordinate value truncated to a 32 bit integer value. + */ + public int getAttributeAsInt(int semantics, int ordinate) { + return (int)getAttributeAsDbl(semantics, ordinate); + } + + /** + * Sets the value of the attribute. + * + * @param semantics + * The attribute semantics. + * @param ordinate + * The ordinate of the attribute. + * @param value + * Is the array to write values to. The attribute type and the + * number of elements must match the persistence type, as well as + * the number of components of the attribute. + */ + public void setAttribute(int semantics, int ordinate, double value) { + _touch(); + if (semantics == VertexDescription.Semantics.POSITION) { + if (ordinate == 0) { + m_x = value; + } + else if (ordinate == 1) { + m_y = value; + } + else { + throw new IndexOutOfBoundsException(); + } + return; + } + + int ncomps = VertexDescription.getComponentCount(semantics); + if (ncomps < ordinate) + throw new IndexOutOfBoundsException(); + + int attributeIndex = m_description.getAttributeIndex(semantics); + if (attributeIndex < 0) { + addAttribute(semantics); + attributeIndex = m_description.getAttributeIndex(semantics); + } + + m_attributes[m_description._getPointAttributeOffset(attributeIndex) - 2 + + ordinate] = value; + } + + public void setAttribute(int semantics, int ordinate, int value) { + setAttribute(semantics, ordinate, (double) value); + } + + @Override + public Geometry.Type getType() { + return Type.Point; + } + + @Override + public int getDimension() { + return 0; + } @Override public long estimateMemorySize() @@ -362,245 +349,256 @@ public long estimateMemorySize() @Override public void setEmpty() { _touch(); - if (m_attributes != null) { - m_attributes[0] = NumberUtils.NaN(); - m_attributes[1] = NumberUtils.NaN(); + _setToDefault(); + } + + @Override + protected void _assignVertexDescriptionImpl(VertexDescription newDescription) { + int[] mapping = VertexDescriptionDesignerImpl.mapAttributes(newDescription, m_description); + + int newLen = newDescription.getTotalComponentCount() - 2; + if (newLen > 0) { + double[] newAttributes = new double[newLen]; + + int j = 0; + for (int i = 1, n = newDescription.getAttributeCount(); i < n; i++) { + int semantics = newDescription.getSemantics(i); + int nords = VertexDescription.getComponentCount(semantics); + if (mapping[i] == -1) + { + double d = VertexDescription.getDefaultValue(semantics); + for (int ord = 0; ord < nords; ord++) + { + newAttributes[j] = d; + j++; + } + } + else { + int m = mapping[i]; + int offset = m_description._getPointAttributeOffset(m) - 2; + for (int ord = 0; ord < nords; ord++) + { + newAttributes[j] = m_attributes[offset]; + j++; + offset++; + } + } + + } + + m_attributes = newAttributes; + } + else { + m_attributes = null; } + + m_description = newDescription; } - @Override - protected void _assignVertexDescriptionImpl(VertexDescription newDescription) { - if (m_attributes == null) { - m_description = newDescription; - return; - } - - int[] mapping = VertexDescriptionDesignerImpl.mapAttributes(newDescription, m_description); - - double[] newAttributes = new double[newDescription.getTotalComponentCount()]; - - int j = 0; - for (int i = 0, n = newDescription.getAttributeCount(); i < n; i++) { - int semantics = newDescription.getSemantics(i); - int nords = VertexDescription.getComponentCount(semantics); - if (mapping[i] == -1) { - double d = VertexDescription.getDefaultValue(semantics); - for (int ord = 0; ord < nords; ord++) { - newAttributes[j] = d; - j++; - } - } else { - int m = mapping[i]; - int offset = m_description._getPointAttributeOffset(m); - for (int ord = 0; ord < nords; ord++) { - newAttributes[j] = m_attributes[offset]; - j++; - offset++; - } - } - - } - - m_attributes = newAttributes; - m_description = newDescription; - } - - /** - * Sets the Point to a default, non-empty state. - */ - void _setToDefault() { - resizeAttributes(m_description.getTotalComponentCount()); - Point.attributeCopy(m_description._getDefaultPointAttributes(), - m_attributes, m_description.getTotalComponentCount()); - m_attributes[0] = NumberUtils.NaN(); - m_attributes[1] = NumberUtils.NaN(); - } - - @Override - public void applyTransformation(Transformation2D transform) { - if (isEmptyImpl()) - return; - - Point2D pt = getXY(); - transform.transform(pt, pt); - setXY(pt); - } - - @Override - void applyTransformation(Transformation3D transform) { - if (isEmptyImpl()) - return; - - addAttribute(Semantics.Z); - Point3D pt = getXYZ(); - setXYZ(transform.transform(pt)); - } - - @Override - public void copyTo(Geometry dst) { - if (dst.getType() != Type.Point) - throw new IllegalArgumentException(); - - Point pointDst = (Point) dst; - dst._touch(); - - if (m_attributes == null) { - pointDst.setEmpty(); - pointDst.m_attributes = null; - pointDst.assignVertexDescription(m_description); - } else { - pointDst.assignVertexDescription(m_description); - pointDst.resizeAttributes(m_description.getTotalComponentCount()); - attributeCopy(m_attributes, pointDst.m_attributes, - m_description.getTotalComponentCount()); - } - } - - @Override - public Geometry createInstance() { - Point point = new Point(m_description); - return point; - } - - @Override - public boolean isEmpty() { - return isEmptyImpl(); - } - - final boolean isEmptyImpl() { - return ((m_attributes == null) || NumberUtils.isNaN(m_attributes[0]) || NumberUtils - .isNaN(m_attributes[1])); - } - - @Override - public void queryEnvelope(Envelope env) { - env.setEmpty(); - if (m_description != env.m_description) - env.assignVertexDescription(m_description); - env.merge(this); - } - - @Override - public void queryEnvelope2D(Envelope2D env) { - - if (isEmptyImpl()) { - env.setEmpty(); - return; - } - - env.xmin = m_attributes[0]; - env.ymin = m_attributes[1]; - env.xmax = m_attributes[0]; - env.ymax = m_attributes[1]; - } - - @Override - void queryEnvelope3D(Envelope3D env) { - if (isEmptyImpl()) { - env.setEmpty(); - return; - } - - Point3D pt = getXYZ(); - env.xmin = pt.x; - env.ymin = pt.y; - env.zmin = pt.z; - env.xmax = pt.x; - env.ymax = pt.y; - env.zmax = pt.z; - } - - @Override - public Envelope1D queryInterval(int semantics, int ordinate) { - Envelope1D env = new Envelope1D(); - if (isEmptyImpl()) { - env.setEmpty(); - return env; - } - - double s = getAttributeAsDbl(semantics, ordinate); - env.vmin = s; - env.vmax = s; - return env; - } - - private void resizeAttributes(int newSize) { - if (m_attributes == null) { - m_attributes = new double[newSize]; - } else if (m_attributes.length < newSize) { - double[] newbuffer = new double[newSize]; - System.arraycopy(m_attributes, 0, newbuffer, 0, m_attributes.length); - m_attributes = newbuffer; - } - } - - static void attributeCopy(double[] src, double[] dst, int count) { - if (count > 0) - System.arraycopy(src, 0, dst, 0, count); - } - - /** - * Set the X and Y coordinate of the point. - * - * @param x X coordinate of the point. - * @param y Y coordinate of the point. - */ - public void setXY(double x, double y) { - _touch(); - - if (m_attributes == null) - _setToDefault(); - - m_attributes[0] = x; - m_attributes[1] = y; - } - - /** - * Returns TRUE when this geometry has exactly same type, properties, and - * coordinates as the other geometry. - */ - @Override - public boolean equals(Object _other) { - if (_other == this) - return true; - - if (!(_other instanceof Point)) - return false; - - Point otherPt = (Point) _other; - - if (m_description != otherPt.m_description) - return false; - - if (isEmptyImpl()) - if (otherPt.isEmptyImpl()) - return true; - else - return false; - - for (int i = 0, n = m_description.getTotalComponentCount(); i < n; i++) - if (m_attributes[i] != otherPt.m_attributes[i]) - return false; - - return true; - } - - /** - * Returns the hash code for the point. - */ - - @Override - public int hashCode() { - int hashCode = m_description.hashCode(); - if (!isEmptyImpl()) { - for (int i = 0, n = m_description.getTotalComponentCount(); i < n; i++) { - long bits = Double.doubleToLongBits(m_attributes[i]); - int hc = (int) (bits ^ (bits >>> 32)); - hashCode = NumberUtils.hash(hashCode, hc); - } - } - return hashCode; - } + /** + * Sets to a default empty state. + */ + private void _setToDefault() { + int len = m_description.getTotalComponentCount() - 2; + if (len != 0) { + if (m_attributes == null || m_attributes.length != len) { + m_attributes = new double[len]; + } + + System.arraycopy(m_description._getDefaultPointAttributes(), 2, m_attributes, 0, len); + } + else { + m_attributes = null; + } + + m_x = NumberUtils.TheNaN; + m_y = NumberUtils.TheNaN; + } + + @Override + public void applyTransformation(Transformation2D transform) { + if (isEmptyImpl()) + return; + + Point2D pt = getXY(); + transform.transform(pt, pt); + setXY(pt); + } + + @Override + public void applyTransformation(Transformation3D transform) { + if (isEmptyImpl()) + return; + + addAttribute(Semantics.Z); + Point3D pt = getXYZ(); + setXYZ(transform.transform(pt)); + } + + @Override + public void copyTo(Geometry dst) { + if (dst.getType() != Type.Point) + throw new IllegalArgumentException(); + + if (this == dst) + return; + + dst._touch(); + + Point pointDst = (Point) dst; + dst.m_description = m_description; + pointDst.m_x = m_x; + pointDst.m_y = m_y; + int attrLen = m_description.getTotalComponentCount() - 2; + if (attrLen == 0) { + pointDst.m_attributes = null; + return; + } + + if (pointDst.m_attributes == null || pointDst.m_attributes.length != attrLen) { + pointDst.m_attributes = new double[attrLen]; + } + + System.arraycopy(m_attributes, 0, pointDst.m_attributes, 0, attrLen); + } + + @Override + public Geometry createInstance() { + Point point = new Point(m_description); + return point; + } + + @Override + public boolean isEmpty() { + return isEmptyImpl(); + } + + final boolean isEmptyImpl() { + return NumberUtils.isNaN(m_x) || NumberUtils.isNaN(m_y); + } + + @Override + public void queryEnvelope(Envelope env) { + if (m_description != env.m_description) + env.assignVertexDescription(m_description); + + env.setEmpty(); + env.merge(this); + } + + @Override + public void queryEnvelope2D(Envelope2D env) { + if (isEmptyImpl()) { + env.setEmpty(); + return; + } + + env.xmin = m_x; + env.ymin = m_y; + env.xmax = m_x; + env.ymax = m_y; + } + + @Override + void queryEnvelope3D(Envelope3D env) { + if (isEmptyImpl()) { + env.setEmpty(); + return; + } + + env.xmin = m_x; + env.ymin = m_y; + env.xmax = m_x; + env.ymax = m_y; + double z = getZ(); + env.zmin = z; + env.zmax = z; + } + + @Override + public Envelope1D queryInterval(int semantics, int ordinate) { + Envelope1D env = new Envelope1D(); + if (isEmptyImpl()) { + env.setEmpty(); + return env; + } + + double s = getAttributeAsDbl(semantics, ordinate); + env.vmin = s; + env.vmax = s; + return env; + } + + /** + * Set the X and Y coordinate of the point. + * + * @param x + * X coordinate of the point. + * @param y + * Y coordinate of the point. + */ + public void setXY(double x, double y) { + _touch(); + + m_x = x; + m_y = y; + } + + /** + * Returns TRUE when this geometry has exactly same type, properties, and + * coordinates as the other geometry. + */ + @Override + public boolean equals(Object _other) { + if (_other == this) + return true; + + if (!(_other instanceof Point)) + return false; + + Point otherPt = (Point) _other; + + if (m_description != otherPt.m_description) + return false; + + if (isEmptyImpl()) { + if (otherPt.isEmptyImpl()) + return true; + else + return false; + } + + if (m_x != otherPt.m_x || m_y != otherPt.m_y) { + return false; + } + + for (int i = 0, n = m_description.getTotalComponentCount() - 2; i < n; i++) { + if (!NumberUtils.isEqualNonIEEE(m_attributes[i], otherPt.m_attributes[i])) + return false; + } + + return true; + } + + /** + * Returns the hash code for the point. + */ + + @Override + public int hashCode() { + int hashCode = m_description.hashCode(); + if (!isEmptyImpl()) { + hashCode = NumberUtils.hash(hashCode, m_x); + hashCode = NumberUtils.hash(hashCode, m_y); + for (int i = 0, n = m_description.getTotalComponentCount() - 2; i < n; i++) { + long bits = Double.doubleToLongBits(m_attributes[i]); + int hc = (int) (bits ^ (bits >>> 32)); + hashCode = NumberUtils.hash(hashCode, hc); + } + } + + return hashCode; + } @Override public Geometry getBoundary() { diff --git a/src/main/java/com/esri/core/geometry/Point2D.java b/src/main/java/com/esri/core/geometry/Point2D.java index b20e81d0..95a46c66 100644 --- a/src/main/java/com/esri/core/geometry/Point2D.java +++ b/src/main/java/com/esri/core/geometry/Point2D.java @@ -30,783 +30,735 @@ import java.util.Comparator; /** + * * Basic 2D point class. Contains only two double fields. + * */ -public final class Point2D implements Serializable { - private static final long serialVersionUID = 1L; - - public double x; - public double y; - - public Point2D() { - } - - public Point2D(double x, double y) { - this.x = x; - this.y = y; - } - - public Point2D(Point2D other) { - setCoords(other); - } - - public static Point2D construct(double x, double y) { - return new Point2D(x, y); - } - - public void setCoords(double x, double y) { - this.x = x; - this.y = y; - } - - public void setCoords(Point2D other) { - x = other.x; - y = other.y; - } - - public boolean isEqual(Point2D other) { - return x == other.x && y == other.y; - } - - public boolean isEqual(double x_, double y_) { - return x == x_ && y == y_; - } - - public boolean isEqual(Point2D other, double tol) { - return (Math.abs(x - other.x) <= tol) && (Math.abs(y - other.y) <= tol); - } - - public boolean equals(Point2D other) { - return x == other.x && y == other.y; - } - - @Override - public boolean equals(Object other) { - if (other == this) - return true; - - if (!(other instanceof Point2D)) - return false; - - Point2D v = (Point2D) other; - - return x == v.x && y == v.y; - } - - public void sub(Point2D other) { - x -= other.x; - y -= other.y; - } - - public void sub(Point2D p1, Point2D p2) { - x = p1.x - p2.x; - y = p1.y - p2.y; - } - - public void add(Point2D other) { - x += other.x; - y += other.y; - } - - public void add(Point2D p1, Point2D p2) { - x = p1.x + p2.x; - y = p1.y + p2.y; - } - - public void negate() { - x = -x; - y = -y; - } - - public void negate(Point2D other) { - x = -other.x; - y = -other.y; - } - - public void interpolate(Point2D other, double alpha) { - MathUtils.lerp(this, other, alpha, this); - } - - public void interpolate(Point2D p1, Point2D p2, double alpha) { - MathUtils.lerp(p1, p2, alpha, this); - } - - /** - * Calculates this = this * f + shift - * - * @param f - * @param shift - */ - public void scaleAdd(double f, Point2D shift) { - x = x * f + shift.x; - y = y * f + shift.y; - } - - /** - * Calculates this = other * f + shift - * - * @param f - * @param other - * @param shift - */ - public void scaleAdd(double f, Point2D other, Point2D shift) { - x = other.x * f + shift.x; - y = other.y * f + shift.y; - } - - public void scale(double f, Point2D other) { - x = f * other.x; - y = f * other.y; - } - - public void scale(double f) { - x *= f; - y *= f; - } - - /** - * Compares two vertices lexicographically by y. - */ - public int compare(Point2D other) { - return y < other.y ? -1 : (y > other.y ? 1 : (x < other.x ? -1 - : (x > other.x ? 1 : 0))); - } - - /** - * Compares two vertices lexicographically by x. - */ - int compareX(Point2D other) { - return x < other.x ? -1 : (x > other.x ? 1 : (y < other.y ? -1 - : (y > other.y ? 1 : 0))); - } - - public void normalize(Point2D other) { - double len = other.length(); - if (len == 0) { - x = 1.0; - y = 0.0; - } else { - x = other.x / len; - y = other.y / len; - } - } - - public void normalize() { - double len = length(); - if (len == 0)// (!len) - { - x = 1.0; - y = 0.0; - } - x /= len; - y /= len; - } - - public double length() { - return Math.sqrt(x * x + y * y); - } - - public double sqrLength() { - return x * x + y * y; - } - - public static double distance(Point2D pt1, Point2D pt2) { - return Math.sqrt(sqrDistance(pt1, pt2)); - } - - public double dotProduct(Point2D other) { - return x * other.x + y * other.y; - } - - double _dotProductAbs(Point2D other) { - return Math.abs(x * other.x) + Math.abs(y * other.y); - } - - public double crossProduct(Point2D other) { - return x * other.y - y * other.x; - } - - public void rotateDirect(double Cos, double Sin) // corresponds to the - // Transformation2D.SetRotate(cos, - // sin).Transform(pt) - { - double xx = x * Cos - y * Sin; - double yy = x * Sin + y * Cos; - x = xx; - y = yy; - } - - public void rotateReverse(double Cos, double Sin) { - double xx = x * Cos + y * Sin; - double yy = -x * Sin + y * Cos; - x = xx; - y = yy; - } - - /** - * 90 degree rotation, anticlockwise. Equivalent to RotateDirect(cos(pi/2), - * sin(pi/2)). - */ - public void leftPerpendicular() { - double xx = x; - x = -y; - y = xx; - } - - /** - * 90 degree rotation, anticlockwise. Equivalent to RotateDirect(cos(pi/2), - * sin(pi/2)). - */ - public void leftPerpendicular(Point2D pt) { - x = -pt.y; - y = pt.x; - } - - /** - * 270 degree rotation, anticlockwise. Equivalent to - * RotateDirect(-cos(pi/2), sin(-pi/2)). - */ - public void rightPerpendicular() { - double xx = x; - x = y; - y = -xx; - } - - /** - * 270 degree rotation, anticlockwise. Equivalent to - * RotateDirect(-cos(pi/2), sin(-pi/2)). - */ - public void rightPerpendicular(Point2D pt) { - x = pt.y; - y = -pt.x; - } - - void _setNan() { - x = NumberUtils.NaN(); - y = NumberUtils.NaN(); - } - - boolean _isNan() { - return NumberUtils.isNaN(x) || NumberUtils.isNaN(y); - } - - // calculates which quarter of xy plane the vector lies in. First quater is - // between vectors (1,0) and (0, 1), second between (0, 1) and (-1, 0), etc. - // Angle intervals corresponding to quarters: 1 : [0 : 90); 2 : [90 : 180); - // 3 : [180 : 270); 4 : [270 : 360) - final int _getQuarter() { - if (x > 0) { - if (y >= 0) - return 1; // x > 0 && y <= 0 - else - return 4; // y < 0 && x > 0. Should be x >= 0 && y < 0. The x == - // 0 case is processed later. - } else { - if (y > 0) - return 2; // x <= 0 && y > 0 - else - return x == 0 ? 4 : 3; // 3: x < 0 && y <= 0. The case x == 0 && - // y <= 0 is attribute to the case 4. - // The point x==0 and y==0 is a bug, but - // will be assigned to 4. - } - } - - /** - * Calculates which quarter of XY plane the vector lies in. First quarter is - * between vectors (1,0) and (0, 1), second between (0, 1) and (-1, 0), etc. - * The quarters are numbered counterclockwise. - * Angle intervals corresponding to quarters: 1 : [0 : 90); 2 : [90 : 180); - * 3 : [180 : 270); 4 : [270 : 360) - */ - public int getQuarter() { - return _getQuarter(); - } - - // Assume vector v1 and v2 have same origin. The function compares the - // vectors by angle from the x axis to the vector in the counter clockwise - // direction. - // > > - // \ / - // V3 \ / V1 - // \ - // \ - // >V2 - // _compareVectors(V1, V2) == -1. - // _compareVectors(V1, V3) == -1 - // _compareVectors(V2, V3) == 1 - // - final static int _compareVectors(Point2D v1, Point2D v2) { - int q1 = v1._getQuarter(); - int q2 = v2._getQuarter(); - - if (q2 == q1) { - double cross = v1.crossProduct(v2); - return cross < 0 ? 1 : (cross > 0 ? -1 : 0); - } else - return q1 < q2 ? -1 : 1; - } - - /** - * Assume vector v1 and v2 have same origin. The function compares the - * vectors by angle in the counter clockwise direction from the axis X. - *

- * For example, V1 makes 30 degree angle counterclockwise from horizontal x axis - * V2, makes 270, V3 makes 90, then - * compareVectors(V1, V2) == -1. - * compareVectors(V1, V3) == -1. - * compareVectors(V2, V3) == 1. - * - * @return Returns 1 if v1 is less than v2, 0 if equal, and 1 if greater. - */ - public static int compareVectors(Point2D v1, Point2D v2) { - return _compareVectors(v1, v2); - } - - static class CompareVectors implements Comparator { - @Override - public int compare(Point2D v1, Point2D v2) { - return _compareVectors((Point2D) v1, (Point2D) v2); - } - } - - public static double sqrDistance(Point2D pt1, Point2D pt2) { - double dx = pt1.x - pt2.x; - double dy = pt1.y - pt2.y; - return dx * dx + dy * dy; - } - - @Override - public String toString() { - return "(" + x + " , " + y + ")"; - } - - public void setNaN() { - x = NumberUtils.NaN(); - y = NumberUtils.NaN(); - } - - public boolean isNaN() { - return NumberUtils.isNaN(x) || NumberUtils.isNaN(y); - } - - // metric = 1: Manhattan metric - // 2: Euclidian metric (default) - // 0: used for L-infinite (max(fabs(x), fabs(y)) - // for predefined metrics, use the DistanceMetricEnum defined in WKSPoint.h - double _norm(int metric) { - if (metric < 0 || _isNan()) - return NumberUtils.NaN(); - - switch (metric) { - case 0: // L-infinite - return Math.abs(x) >= Math.abs(y) ? Math.abs(x) : Math.abs(y); - - case 1: // L1 or Manhattan metric - return Math.abs(x) + Math.abs(y); - - case 2: // L2 or Euclidean metric - return Math.sqrt(x * x + y * y); - - default: - return Math - .pow(Math.pow(x, (double) metric) - + Math.pow(y, (double) metric), - 1.0 / (double) metric); - } - } - - /** - * returns signed distance of point from infinite line represented by - * pt_1...pt_2. The returned distance is positive if this point lies on the - * right-hand side of the line, negative otherwise. If the two input points - * are equal, the (positive) distance of this point to p_1 is returned. - */ - double offset(/* const */Point2D pt1, /* const */Point2D pt2) { - double newDistance = distance(pt1, pt2); - Point2D p = construct(x, y); - if (newDistance == 0.0) - return distance(p, pt1); - - // get vectors relative to pt_1 - Point2D p2 = new Point2D(); - p2.setCoords(pt2); - p2.sub(pt1); - p.sub(pt1); - - double cross = p.crossProduct(p2); - return cross / newDistance; - } - - /** - * Calculates the orientation of the triangle formed by p->q->r. Returns 1 - * for counter-clockwise, -1 for clockwise, and 0 for collinear. May use - * high precision arithmetics for some special degenerate cases. - */ - public static int orientationRobust(Point2D p, Point2D q, Point2D r) { - ECoordinate det_ec = new ECoordinate(); - det_ec.set(q.x); - det_ec.sub(p.x); - - ECoordinate rp_y_ec = new ECoordinate(); - rp_y_ec.set(r.y); - rp_y_ec.sub(p.y); - - ECoordinate qp_y_ec = new ECoordinate(); - qp_y_ec.set(q.y); - qp_y_ec.sub(p.y); - - ECoordinate rp_x_ec = new ECoordinate(); - rp_x_ec.set(r.x); - rp_x_ec.sub(p.x); - - det_ec.mul(rp_y_ec); - qp_y_ec.mul(rp_x_ec); - det_ec.sub(qp_y_ec); - - if (!det_ec.isFuzzyZero()) { - double det_ec_value = det_ec.value(); - - if (det_ec_value < 0.0) - return -1; - - if (det_ec_value > 0.0) - return 1; - - return 0; - } - - // Need extended precision - - BigDecimal det_mp = new BigDecimal(q.x); - BigDecimal px_mp = new BigDecimal(p.x); - BigDecimal py_mp = new BigDecimal(p.y); - det_mp = det_mp.subtract(px_mp); - - BigDecimal rp_y_mp = new BigDecimal(r.y); - rp_y_mp = rp_y_mp.subtract(py_mp); - - BigDecimal qp_y_mp = new BigDecimal(q.y); - qp_y_mp = qp_y_mp.subtract(py_mp); - - BigDecimal rp_x_mp = new BigDecimal(r.x); - rp_x_mp = rp_x_mp.subtract(px_mp); - - det_mp = det_mp.multiply(rp_y_mp); - qp_y_mp = qp_y_mp.multiply(rp_x_mp); - det_mp = det_mp.subtract(qp_y_mp); - - return det_mp.signum(); - } - - private static int inCircleRobustMP_(Point2D p, Point2D q, Point2D r, Point2D s) { - BigDecimal sx_mp = new BigDecimal(s.x), sy_mp = new BigDecimal(s.y); - - BigDecimal psx_mp = new BigDecimal(p.x), psy_mp = new BigDecimal(p.y); - psx_mp = psx_mp.subtract(sx_mp); - psy_mp = psy_mp.subtract(sy_mp); - - BigDecimal qsx_mp = new BigDecimal(q.x), qsy_mp = new BigDecimal(q.y); - qsx_mp = qsx_mp.subtract(sx_mp); - qsy_mp = qsy_mp.subtract(sy_mp); - - BigDecimal rsx_mp = new BigDecimal(r.x), rsy_mp = new BigDecimal(r.y); - rsx_mp = rsx_mp.subtract(sx_mp); - rsy_mp = rsy_mp.subtract(sy_mp); - - BigDecimal pq_det_mp = psx_mp.multiply(qsy_mp).subtract(psy_mp.multiply(qsx_mp)); - BigDecimal qr_det_mp = qsx_mp.multiply(rsy_mp).subtract(qsy_mp.multiply(rsx_mp)); - BigDecimal pr_det_mp = psx_mp.multiply(rsy_mp).subtract(psy_mp.multiply(rsx_mp)); - - BigDecimal p_parab_mp = psx_mp.multiply(psx_mp).add(psy_mp.multiply(psy_mp)); - BigDecimal q_parab_mp = qsx_mp.multiply(qsx_mp).add(qsy_mp.multiply(qsy_mp)); - BigDecimal r_parab_mp = rsx_mp.multiply(rsx_mp).add(rsy_mp.multiply(rsy_mp)); - - BigDecimal det_mp = (p_parab_mp.multiply(qr_det_mp).subtract(q_parab_mp.multiply(pr_det_mp))) - .add(r_parab_mp.multiply(pq_det_mp)); - - return det_mp.signum(); - } - - /** - * Calculates if the point s is inside of the circumcircle inscribed by the clockwise oriented triangle p-q-r. - * Returns 1 for outside, -1 for inside, and 0 for cocircular. - * Note that the convention used here differs from what is commonly found in literature, which can define the relation - * in terms of a counter-clockwise oriented circle, and this flips the sign (think of the signed volume of the tetrahedron). - * May use high precision arithmetics for some special cases. - */ - static int inCircleRobust(Point2D p, Point2D q, Point2D r, Point2D s) { - ECoordinate psx_ec = new ECoordinate(), psy_ec = new ECoordinate(); - psx_ec.set(p.x); - psx_ec.sub(s.x); - psy_ec.set(p.y); - psy_ec.sub(s.y); - - ECoordinate qsx_ec = new ECoordinate(), qsy_ec = new ECoordinate(); - qsx_ec.set(q.x); - qsx_ec.sub(s.x); - qsy_ec.set(q.y); - qsy_ec.sub(s.y); - - ECoordinate rsx_ec = new ECoordinate(), rsy_ec = new ECoordinate(); - rsx_ec.set(r.x); - rsx_ec.sub(s.x); - rsy_ec.set(r.y); - rsy_ec.sub(s.y); - - ECoordinate psx_ec_qsy_ec = new ECoordinate(); - psx_ec_qsy_ec.set(psx_ec); - psx_ec_qsy_ec.mul(qsy_ec); - ECoordinate psy_ec_qsx_ec = new ECoordinate(); - psy_ec_qsx_ec.set(psy_ec); - psy_ec_qsx_ec.mul(qsx_ec); - ECoordinate qsx_ec_rsy_ec = new ECoordinate(); - qsx_ec_rsy_ec.set(qsx_ec); - qsx_ec_rsy_ec.mul(rsy_ec); - ECoordinate qsy_ec_rsx_ec = new ECoordinate(); - qsy_ec_rsx_ec.set(qsy_ec); - qsy_ec_rsx_ec.mul(rsx_ec); - ECoordinate psx_ec_rsy_ec = new ECoordinate(); - psx_ec_rsy_ec.set(psx_ec); - psx_ec_rsy_ec.mul(rsy_ec); - ECoordinate psy_ec_rsx_ec = new ECoordinate(); - psy_ec_rsx_ec.set(psy_ec); - psy_ec_rsx_ec.mul(rsx_ec); - - ECoordinate pq_det_ec = new ECoordinate(); - pq_det_ec.set(psx_ec_qsy_ec); - pq_det_ec.sub(psy_ec_qsx_ec); - ECoordinate qr_det_ec = new ECoordinate(); - qr_det_ec.set(qsx_ec_rsy_ec); - qr_det_ec.sub(qsy_ec_rsx_ec); - ECoordinate pr_det_ec = new ECoordinate(); - pr_det_ec.set(psx_ec_rsy_ec); - pr_det_ec.sub(psy_ec_rsx_ec); - - ECoordinate psx_ec_psx_ec = new ECoordinate(); - psx_ec_psx_ec.set(psx_ec); - psx_ec_psx_ec.mul(psx_ec); - ECoordinate psy_ec_psy_ec = new ECoordinate(); - psy_ec_psy_ec.set(psy_ec); - psy_ec_psy_ec.mul(psy_ec); - ECoordinate qsx_ec_qsx_ec = new ECoordinate(); - qsx_ec_qsx_ec.set(qsx_ec); - qsx_ec_qsx_ec.mul(qsx_ec); - ECoordinate qsy_ec_qsy_ec = new ECoordinate(); - qsy_ec_qsy_ec.set(qsy_ec); - qsy_ec_qsy_ec.mul(qsy_ec); - ECoordinate rsx_ec_rsx_ec = new ECoordinate(); - rsx_ec_rsx_ec.set(rsx_ec); - rsx_ec_rsx_ec.mul(rsx_ec); - ECoordinate rsy_ec_rsy_ec = new ECoordinate(); - rsy_ec_rsy_ec.set(rsy_ec); - rsy_ec_rsy_ec.mul(rsy_ec); - - ECoordinate p_parab_ec = new ECoordinate(); - p_parab_ec.set(psx_ec_psx_ec); - p_parab_ec.add(psy_ec_psy_ec); - ECoordinate q_parab_ec = new ECoordinate(); - q_parab_ec.set(qsx_ec_qsx_ec); - q_parab_ec.add(qsy_ec_qsy_ec); - ECoordinate r_parab_ec = new ECoordinate(); - r_parab_ec.set(rsx_ec_rsx_ec); - r_parab_ec.add(rsy_ec_rsy_ec); - - p_parab_ec.mul(qr_det_ec); - q_parab_ec.mul(pr_det_ec); - r_parab_ec.mul(pq_det_ec); - - ECoordinate det_ec = new ECoordinate(); - det_ec.set(p_parab_ec); - det_ec.sub(q_parab_ec); - det_ec.add(r_parab_ec); - - if (!det_ec.isFuzzyZero()) { - double det_ec_value = det_ec.value(); - - if (det_ec_value < 0.0) - return -1; - - if (det_ec_value > 0.0) - return 1; - - return 0; - } - - return inCircleRobustMP_(p, q, r, s); - } - - private static Point2D calculateCenterFromThreePointsHelperMP_(Point2D from, Point2D mid_point, Point2D to) { - assert (!mid_point.isEqual(to) && !mid_point.isEqual(from) && !from.isEqual(to)); - BigDecimal mx = new BigDecimal(mid_point.x); - mx = mx.subtract(new BigDecimal(from.x)); - BigDecimal my = new BigDecimal(mid_point.y); - my = my.subtract(new BigDecimal(from.y)); - BigDecimal tx = new BigDecimal(to.x); - tx = tx.subtract(new BigDecimal(from.x)); - BigDecimal ty = new BigDecimal(to.y); - ty = ty.subtract(new BigDecimal(from.y)); - - BigDecimal d = mx.multiply(ty); - BigDecimal tmp = my.multiply(tx); - d = d.subtract(tmp); - - if (d.signum() == 0) { - return Point2D.construct(NumberUtils.NaN(), NumberUtils.NaN()); - } - - d = d.multiply(new BigDecimal(2.0)); - - BigDecimal mx2 = mx.multiply(mx); - BigDecimal my2 = my.multiply(my); - BigDecimal m_norm2 = mx2.add(my2); - BigDecimal tx2 = tx.multiply(tx); - BigDecimal ty2 = ty.multiply(ty); - BigDecimal t_norm2 = tx2.add(ty2); - - BigDecimal xo = my.multiply(t_norm2); - tmp = ty.multiply(m_norm2); - xo = xo.subtract(tmp); - xo = xo.divide(d, BigDecimal.ROUND_HALF_EVEN); - - BigDecimal yo = mx.multiply(t_norm2); - tmp = tx.multiply(m_norm2); - yo = yo.subtract(tmp); - yo = yo.divide(d, BigDecimal.ROUND_HALF_EVEN); - - Point2D center = Point2D.construct(from.x - xo.doubleValue(), from.y + yo.doubleValue()); - return center; - } - - private static Point2D calculateCenterFromThreePointsHelper_(Point2D from, Point2D mid_point, Point2D to) { - assert (!mid_point.isEqual(to) && !mid_point.isEqual(from) && !from.isEqual(to)); - ECoordinate mx = new ECoordinate(mid_point.x); - mx.sub(from.x); - ECoordinate my = new ECoordinate(mid_point.y); - my.sub(from.y); - ECoordinate tx = new ECoordinate(to.x); - tx.sub(from.x); - ECoordinate ty = new ECoordinate(to.y); - ty.sub(from.y); - - ECoordinate d = new ECoordinate(mx); - d.mul(ty); - ECoordinate tmp = new ECoordinate(my); - tmp.mul(tx); - d.sub(tmp); - - if (d.value() == 0.0) { - return Point2D.construct(NumberUtils.NaN(), NumberUtils.NaN()); - } - - d.mul(2.0); - - ECoordinate mx2 = new ECoordinate(mx); - mx2.mul(mx); - ECoordinate my2 = new ECoordinate(my); - my2.mul(my); - ECoordinate m_norm2 = new ECoordinate(mx2); - m_norm2.add(my2); - ECoordinate tx2 = new ECoordinate(tx); - tx2.mul(tx); - ECoordinate ty2 = new ECoordinate(ty); - ty2.mul(ty); - ECoordinate t_norm2 = new ECoordinate(tx2); - t_norm2.add(ty2); - - ECoordinate xo = new ECoordinate(my); - xo.mul(t_norm2); - tmp = new ECoordinate(ty); - tmp.mul(m_norm2); - xo.sub(tmp); - xo.div(d); - - ECoordinate yo = new ECoordinate(mx); - yo.mul(t_norm2); - tmp = new ECoordinate(tx); - tmp.mul(m_norm2); - yo.sub(tmp); - yo.div(d); - - Point2D center = Point2D.construct(from.x - xo.value(), from.y + yo.value()); - double r1 = Point2D.construct(from.x - center.x, from.y - center.y).length(); - double r2 = Point2D.construct(mid_point.x - center.x, mid_point.y - center.y).length(); - double r3 = Point2D.construct(to.x - center.x, to.y - center.y).length(); - double base = r1 + Math.abs(from.x) + Math.abs(mid_point.x) + Math.abs(to.x) + Math.abs(from.y) - + Math.abs(mid_point.y) + Math.abs(to.y); - - double tol = 1e-15; - if ((Math.abs(r1 - r2) <= base * tol && Math.abs(r1 - r3) <= base * tol)) - return center;//returns center value for MP_value type or when calculated radius value for from - center, mid - center, and to - center are very close. - - return Point2D.construct(NumberUtils.NaN(), NumberUtils.NaN()); - } - - /** - * Calculate the center of a circle, whose perimeter contains the points from, mid_point and to - * @param from - * @param mid_point - * @param to - * @return - */ - static Point2D calculateCircleCenterFromThreePoints(Point2D from, Point2D mid_point, Point2D to) { - if (from.isEqual(to) || from.isEqual(mid_point) || to.isEqual(mid_point)) { - return new Point2D(NumberUtils.NaN(), NumberUtils.NaN()); - } - - Point2D pt = calculateCenterFromThreePointsHelper_(from, mid_point, to); //use error tracking calculations - if (pt.isNaN()) - return calculateCenterFromThreePointsHelperMP_(from, mid_point, to); //use precise calculations - else { - return pt; - } - } - - @Override - public int hashCode() { - return NumberUtils.hash(NumberUtils.hash(x), y); - } - - public double calculateTriangleArea2D(Point2D pt1, Point2D pt2) { - double a = Point2D.distance(pt1, pt2); - double b = Point2D.distance(pt1, this); - double c = Point2D.distance(pt2, this); - double temp; - - - if (a < b) { - // set a >= b - temp = b; - b = a; - a = temp; - } - - if (c > a) { - // set a >= c - temp = c; - c = a; - a = temp; - } - - if (c > b) { - temp = c; - c = b; - b = temp; - } - - // First sort a, b, c so that a ≥ b ≥ c ; this can be done at the cost of at most three comparisons. - // If c-(a-b) < 0 then the data are not side-lengths of a real triangle - if (c - (a - b) < 0) - return 0.0; - - //double result = 0.5 * Math.abs((x - pt2.x)*(pt1.y - y) - (x - pt1.x)*(pt2.y - y)); - double result = Math.sqrt((a + (b + c)) * (c - (a - b)) * (c + (a - b)) * (a + (b - c))) / 4.0; - return result; - - } - - double getAxis(int ordinate) { - assert (ordinate == 0 || ordinate == 1); - return (ordinate == 0 ? x : y); - } +public final class Point2D implements Serializable{ + private static final long serialVersionUID = 1L; + + public double x; + public double y; + + public Point2D() { + } + + public Point2D(double x, double y) { + this.x = x; + this.y = y; + } + + public Point2D(Point2D other) { + setCoords(other); + } + + public static Point2D construct(double x, double y) { + return new Point2D(x, y); + } + + public void setCoords(double x, double y) { + this.x = x; + this.y = y; + } + + public void setCoords(Point2D other) { + x = other.x; + y = other.y; + } + + public boolean isEqual(Point2D other) { + return x == other.x && y == other.y; + } + + public boolean isEqual(double x_, double y_) { + return x == x_ && y == y_; + } + + public boolean isEqual(Point2D other, double tol) { + return (Math.abs(x - other.x) <= tol) && (Math.abs(y - other.y) <= tol); + } + + public boolean equals(Point2D other) { + return x == other.x && y == other.y; + } + + @Override + public boolean equals(Object other) { + if (other == this) + return true; + + if (!(other instanceof Point2D)) + return false; + + Point2D v = (Point2D)other; + + return x == v.x && y == v.y; + } + + @Override + public int hashCode() { + return NumberUtils.hash(NumberUtils.hash(x), y); + } + + + public void sub(Point2D other) { + x -= other.x; + y -= other.y; + } + + public void sub(Point2D p1, Point2D p2) { + x = p1.x - p2.x; + y = p1.y - p2.y; + } + + public void add(Point2D other) { + x += other.x; + y += other.y; + } + + public void add(Point2D p1, Point2D p2) { + x = p1.x + p2.x; + y = p1.y + p2.y; + } + + public void negate() { + x = -x; + y = -y; + } + + public void negate(Point2D other) { + x = -other.x; + y = -other.y; + } + + public void interpolate(Point2D other, double alpha) { + MathUtils.lerp(this, other, alpha, this); + } + + public void interpolate(Point2D p1, Point2D p2, double alpha) { + MathUtils.lerp(p1, p2, alpha, this); + } + + /** + * Calculates this = this * f + shift + * @param f + * @param shift + */ + public void scaleAdd(double f, Point2D shift) { + x = x * f + shift.x; + y = y * f + shift.y; + } + + /** + * Calculates this = other * f + shift + * @param f + * @param other + * @param shift + */ + public void scaleAdd(double f, Point2D other, Point2D shift) { + x = other.x * f + shift.x; + y = other.y * f + shift.y; + } + + public void scale(double f, Point2D other) { + x = f * other.x; + y = f * other.y; + } + + public void scale(double f) { + x *= f; + y *= f; + } + + /** + * Compares two vertices lexicographically by y. + */ + public int compare(Point2D other) { + return y < other.y ? -1 : (y > other.y ? 1 : (x < other.x ? -1 + : (x > other.x ? 1 : 0))); + } + /** + * Compares two vertices lexicographically by x. + */ + int compareX(Point2D other) { + return x < other.x ? -1 : (x > other.x ? 1 : (y < other.y ? -1 + : (y > other.y ? 1 : 0))); + } + + public void normalize(Point2D other) { + double len = other.length(); + if (len == 0) { + x = 1.0; + y = 0.0; + } else { + x = other.x / len; + y = other.y / len; + } + } + + public void normalize() { + double len = length(); + if (len == 0)// (!len) + { + x = 1.0; + y = 0.0; + } + x /= len; + y /= len; + } + + public double length() { + return Math.sqrt(x * x + y * y); + } + + public double sqrLength() { + return x * x + y * y; + } + + public static double distance(Point2D pt1, Point2D pt2) { + return Math.sqrt(sqrDistance(pt1, pt2)); + } + + public double dotProduct(Point2D other) { + return x * other.x + y * other.y; + } + + double _dotProductAbs(Point2D other) { + return Math.abs(x * other.x) + Math.abs(y * other.y); + } + + public double crossProduct(Point2D other) { + return x * other.y - y * other.x; + } + + public void rotateDirect(double Cos, double Sin) // corresponds to the + // Transformation2D.SetRotate(cos, + // sin).Transform(pt) + { + double xx = x * Cos - y * Sin; + double yy = x * Sin + y * Cos; + x = xx; + y = yy; + } + + public void rotateReverse(double Cos, double Sin) { + double xx = x * Cos + y * Sin; + double yy = -x * Sin + y * Cos; + x = xx; + y = yy; + } + + /** + * 90 degree rotation, anticlockwise. Equivalent to RotateDirect(cos(pi/2), + * sin(pi/2)). + */ + public void leftPerpendicular() { + double xx = x; + x = -y; + y = xx; + } + + /** + * 90 degree rotation, anticlockwise. Equivalent to RotateDirect(cos(pi/2), + * sin(pi/2)). + */ + public void leftPerpendicular(Point2D pt) { + x = -pt.y; + y = pt.x; + } + + /** + * 270 degree rotation, anticlockwise. Equivalent to + * RotateDirect(-cos(pi/2), sin(-pi/2)). + */ + public void rightPerpendicular() { + double xx = x; + x = y; + y = -xx; + } + + /** + * 270 degree rotation, anticlockwise. Equivalent to + * RotateDirect(-cos(pi/2), sin(-pi/2)). + */ + public void rightPerpendicular(Point2D pt) { + x = pt.y; + y = -pt.x; + } + + void _setNan() { + x = NumberUtils.NaN(); + y = NumberUtils.NaN(); + } + + boolean _isNan() { + return NumberUtils.isNaN(x) || NumberUtils.isNaN(y); + } + + // calculates which quarter of xy plane the vector lies in. First quater is + // between vectors (1,0) and (0, 1), second between (0, 1) and (-1, 0), etc. + // Angle intervals corresponding to quarters: 1 : [0 : 90); 2 : [90 : 180); + // 3 : [180 : 270); 4 : [270 : 360) + final int _getQuarter() { + if (x > 0) { + if (y >= 0) + return 1; // x > 0 && y <= 0 + else + return 4; // y < 0 && x > 0. Should be x >= 0 && y < 0. The x == + // 0 case is processed later. + } else { + if (y > 0) + return 2; // x <= 0 && y > 0 + else + return x == 0 ? 4 : 3; // 3: x < 0 && y <= 0. The case x == 0 && + // y <= 0 is attribute to the case 4. + // The point x==0 and y==0 is a bug, but + // will be assigned to 4. + } + } + + /** + * Calculates which quarter of XY plane the vector lies in. First quarter is + * between vectors (1,0) and (0, 1), second between (0, 1) and (-1, 0), etc. + * The quarters are numbered counterclockwise. + * Angle intervals corresponding to quarters: 1 : [0 : 90); 2 : [90 : 180); + * 3 : [180 : 270); 4 : [270 : 360) + */ + public int getQuarter() { return _getQuarter(); } + + // Assume vector v1 and v2 have same origin. The function compares the + // vectors by angle from the x axis to the vector in the counter clockwise + // direction. + // > > + // \ / + // V3 \ / V1 + // \ + // \ + // >V2 + // _compareVectors(V1, V2) == -1. + // _compareVectors(V1, V3) == -1 + // _compareVectors(V2, V3) == 1 + // + final static int _compareVectors(Point2D v1, Point2D v2) { + int q1 = v1._getQuarter(); + int q2 = v2._getQuarter(); + + if (q2 == q1) { + double cross = v1.crossProduct(v2); + return cross < 0 ? 1 : (cross > 0 ? -1 : 0); + } else + return q1 < q2 ? -1 : 1; + } + + /** + * Assume vector v1 and v2 have same origin. The function compares the + * vectors by angle in the counter clockwise direction from the axis X. + * + * For example, V1 makes 30 degree angle counterclockwise from horizontal x axis + * V2, makes 270, V3 makes 90, then + * compareVectors(V1, V2) == -1. + * compareVectors(V1, V3) == -1. + * compareVectors(V2, V3) == 1. + * @return Returns 1 if v1 is less than v2, 0 if equal, and 1 if greater. + */ + public static int compareVectors(Point2D v1, Point2D v2) { + return _compareVectors(v1, v2); + } + + static class CompareVectors implements Comparator { + @Override + public int compare(Point2D v1, Point2D v2) { + return _compareVectors((Point2D) v1, (Point2D) v2); + } + } + + public static double sqrDistance(Point2D pt1, Point2D pt2) { + double dx = pt1.x - pt2.x; + double dy = pt1.y - pt2.y; + return dx * dx + dy * dy; + } + + @Override + public String toString() { + return "(" + x + " , " + y + ")"; + } + + public void setNaN() { + x = NumberUtils.NaN(); + y = NumberUtils.NaN(); + } + + public boolean isNaN() { + return NumberUtils.isNaN(x) || NumberUtils.isNaN(y); + } + + // metric = 1: Manhattan metric + // 2: Euclidian metric (default) + // 0: used for L-infinite (max(fabs(x), fabs(y)) + // for predefined metrics, use the DistanceMetricEnum defined in WKSPoint.h + double _norm(int metric) { + if (metric < 0 || _isNan()) + return NumberUtils.NaN(); + + switch (metric) { + case 0: // L-infinite + return Math.abs(x) >= Math.abs(y) ? Math.abs(x) : Math.abs(y); + + case 1: // L1 or Manhattan metric + return Math.abs(x) + Math.abs(y); + + case 2: // L2 or Euclidean metric + return Math.sqrt(x * x + y * y); + + default: + return Math + .pow(Math.pow(x, (double) metric) + + Math.pow(y, (double) metric), + 1.0 / (double) metric); + } + } + + /** + * returns signed distance of point from infinite line represented by + * pt_1...pt_2. The returned distance is positive if this point lies on the + * right-hand side of the line, negative otherwise. If the two input points + * are equal, the (positive) distance of this point to p_1 is returned. + */ + double offset(/* const */Point2D pt1, /* const */Point2D pt2) { + double newDistance = distance(pt1, pt2); + Point2D p = construct(x, y); + if (newDistance == 0.0) + return distance(p, pt1); + + // get vectors relative to pt_1 + Point2D p2 = new Point2D(); + p2.setCoords(pt2); + p2.sub(pt1); + p.sub(pt1); + + double cross = p.crossProduct(p2); + return cross / newDistance; + } + + /** + * Calculates the orientation of the triangle formed by p, q, r. Returns 1 + * for counter-clockwise, -1 for clockwise, and 0 for collinear. May use + * high precision arithmetics for some special degenerate cases. + */ + public static int orientationRobust(Point2D p, Point2D q, Point2D r) { + ECoordinate det_ec = new ECoordinate(); + det_ec.set(q.x); + det_ec.sub(p.x); + + ECoordinate rp_y_ec = new ECoordinate(); + rp_y_ec.set(r.y); + rp_y_ec.sub(p.y); + + ECoordinate qp_y_ec = new ECoordinate(); + qp_y_ec.set(q.y); + qp_y_ec.sub(p.y); + + ECoordinate rp_x_ec = new ECoordinate(); + rp_x_ec.set(r.x); + rp_x_ec.sub(p.x); + + det_ec.mul(rp_y_ec); + qp_y_ec.mul(rp_x_ec); + det_ec.sub(qp_y_ec); + + if (!det_ec.isFuzzyZero()) { + double det_ec_value = det_ec.value(); + + if (det_ec_value < 0.0) + return -1; + + if (det_ec_value > 0.0) + return 1; + + return 0; + } + + // Need extended precision + + BigDecimal det_mp = new BigDecimal(q.x); + BigDecimal px_mp = new BigDecimal(p.x); + BigDecimal py_mp = new BigDecimal(p.y); + det_mp = det_mp.subtract(px_mp); + + BigDecimal rp_y_mp = new BigDecimal(r.y); + rp_y_mp = rp_y_mp.subtract(py_mp); + + BigDecimal qp_y_mp = new BigDecimal(q.y); + qp_y_mp = qp_y_mp.subtract(py_mp); + + BigDecimal rp_x_mp = new BigDecimal(r.x); + rp_x_mp = rp_x_mp.subtract(px_mp); + + det_mp = det_mp.multiply(rp_y_mp); + qp_y_mp = qp_y_mp.multiply(rp_x_mp); + det_mp = det_mp.subtract(qp_y_mp); + + return det_mp.signum(); + } + + private static int inCircleRobustMP_(Point2D p, Point2D q, Point2D r, Point2D s) { + BigDecimal sx_mp = new BigDecimal(s.x), sy_mp = new BigDecimal(s.y); + + BigDecimal psx_mp = new BigDecimal(p.x), psy_mp = new BigDecimal(p.y); + psx_mp = psx_mp.subtract(sx_mp); + psy_mp = psy_mp.subtract(sy_mp); + + BigDecimal qsx_mp = new BigDecimal(q.x), qsy_mp = new BigDecimal(q.y); + qsx_mp = qsx_mp.subtract(sx_mp); + qsy_mp = qsy_mp.subtract(sy_mp); + + BigDecimal rsx_mp = new BigDecimal(r.x), rsy_mp = new BigDecimal(r.y); + rsx_mp = rsx_mp.subtract(sx_mp); + rsy_mp = rsy_mp.subtract(sy_mp); + + BigDecimal pq_det_mp = psx_mp.multiply(qsy_mp).subtract(psy_mp.multiply(qsx_mp)); + BigDecimal qr_det_mp = qsx_mp.multiply(rsy_mp).subtract(qsy_mp.multiply(rsx_mp)); + BigDecimal pr_det_mp = psx_mp.multiply(rsy_mp).subtract(psy_mp.multiply(rsx_mp)); + + BigDecimal p_parab_mp = psx_mp.multiply(psx_mp).add(psy_mp.multiply(psy_mp)); + BigDecimal q_parab_mp = qsx_mp.multiply(qsx_mp).add(qsy_mp.multiply(qsy_mp)); + BigDecimal r_parab_mp = rsx_mp.multiply(rsx_mp).add(rsy_mp.multiply(rsy_mp)); + + BigDecimal det_mp = (p_parab_mp.multiply(qr_det_mp).subtract(q_parab_mp.multiply(pr_det_mp))) + .add(r_parab_mp.multiply(pq_det_mp)); + + return det_mp.signum(); + } + + /** + * Calculates if the point s is inside of the circumcircle inscribed by the clockwise oriented triangle p-q-r. + * Returns 1 for outside, -1 for inside, and 0 for cocircular. + * Note that the convention used here differs from what is commonly found in literature, which can define the relation + * in terms of a counter-clockwise oriented circle, and this flips the sign (think of the signed volume of the tetrahedron). + * May use high precision arithmetics for some special cases. + */ + static int inCircleRobust(Point2D p, Point2D q, Point2D r, Point2D s) { + ECoordinate psx_ec = new ECoordinate(), psy_ec = new ECoordinate(); + psx_ec.set(p.x); + psx_ec.sub(s.x); + psy_ec.set(p.y); + psy_ec.sub(s.y); + + ECoordinate qsx_ec = new ECoordinate(), qsy_ec = new ECoordinate(); + qsx_ec.set(q.x); + qsx_ec.sub(s.x); + qsy_ec.set(q.y); + qsy_ec.sub(s.y); + + ECoordinate rsx_ec = new ECoordinate(), rsy_ec = new ECoordinate(); + rsx_ec.set(r.x); + rsx_ec.sub(s.x); + rsy_ec.set(r.y); + rsy_ec.sub(s.y); + + ECoordinate psx_ec_qsy_ec = new ECoordinate(); + psx_ec_qsy_ec.set(psx_ec); + psx_ec_qsy_ec.mul(qsy_ec); + ECoordinate psy_ec_qsx_ec = new ECoordinate(); + psy_ec_qsx_ec.set(psy_ec); + psy_ec_qsx_ec.mul(qsx_ec); + ECoordinate qsx_ec_rsy_ec = new ECoordinate(); + qsx_ec_rsy_ec.set(qsx_ec); + qsx_ec_rsy_ec.mul(rsy_ec); + ECoordinate qsy_ec_rsx_ec = new ECoordinate(); + qsy_ec_rsx_ec.set(qsy_ec); + qsy_ec_rsx_ec.mul(rsx_ec); + ECoordinate psx_ec_rsy_ec = new ECoordinate(); + psx_ec_rsy_ec.set(psx_ec); + psx_ec_rsy_ec.mul(rsy_ec); + ECoordinate psy_ec_rsx_ec = new ECoordinate(); + psy_ec_rsx_ec.set(psy_ec); + psy_ec_rsx_ec.mul(rsx_ec); + + ECoordinate pq_det_ec = new ECoordinate(); + pq_det_ec.set(psx_ec_qsy_ec); + pq_det_ec.sub(psy_ec_qsx_ec); + ECoordinate qr_det_ec = new ECoordinate(); + qr_det_ec.set(qsx_ec_rsy_ec); + qr_det_ec.sub(qsy_ec_rsx_ec); + ECoordinate pr_det_ec = new ECoordinate(); + pr_det_ec.set(psx_ec_rsy_ec); + pr_det_ec.sub(psy_ec_rsx_ec); + + ECoordinate psx_ec_psx_ec = new ECoordinate(); + psx_ec_psx_ec.set(psx_ec); + psx_ec_psx_ec.mul(psx_ec); + ECoordinate psy_ec_psy_ec = new ECoordinate(); + psy_ec_psy_ec.set(psy_ec); + psy_ec_psy_ec.mul(psy_ec); + ECoordinate qsx_ec_qsx_ec = new ECoordinate(); + qsx_ec_qsx_ec.set(qsx_ec); + qsx_ec_qsx_ec.mul(qsx_ec); + ECoordinate qsy_ec_qsy_ec = new ECoordinate(); + qsy_ec_qsy_ec.set(qsy_ec); + qsy_ec_qsy_ec.mul(qsy_ec); + ECoordinate rsx_ec_rsx_ec = new ECoordinate(); + rsx_ec_rsx_ec.set(rsx_ec); + rsx_ec_rsx_ec.mul(rsx_ec); + ECoordinate rsy_ec_rsy_ec = new ECoordinate(); + rsy_ec_rsy_ec.set(rsy_ec); + rsy_ec_rsy_ec.mul(rsy_ec); + + ECoordinate p_parab_ec = new ECoordinate(); + p_parab_ec.set(psx_ec_psx_ec); + p_parab_ec.add(psy_ec_psy_ec); + ECoordinate q_parab_ec = new ECoordinate(); + q_parab_ec.set(qsx_ec_qsx_ec); + q_parab_ec.add(qsy_ec_qsy_ec); + ECoordinate r_parab_ec = new ECoordinate(); + r_parab_ec.set(rsx_ec_rsx_ec); + r_parab_ec.add(rsy_ec_rsy_ec); + + p_parab_ec.mul(qr_det_ec); + q_parab_ec.mul(pr_det_ec); + r_parab_ec.mul(pq_det_ec); + + ECoordinate det_ec = new ECoordinate(); + det_ec.set(p_parab_ec); + det_ec.sub(q_parab_ec); + det_ec.add(r_parab_ec); + + if (!det_ec.isFuzzyZero()) { + double det_ec_value = det_ec.value(); + + if (det_ec_value < 0.0) + return -1; + + if (det_ec_value > 0.0) + return 1; + + return 0; + } + + return inCircleRobustMP_(p, q, r, s); + } + + private static Point2D calculateCenterFromThreePointsHelperMP_(Point2D from, Point2D mid_point, Point2D to) { + assert(!mid_point.isEqual(to) && !mid_point.isEqual(from) && !from.isEqual(to)); + BigDecimal mx = new BigDecimal(mid_point.x); + mx = mx.subtract(new BigDecimal(from.x)); + BigDecimal my = new BigDecimal(mid_point.y); + my = my.subtract(new BigDecimal(from.y)); + BigDecimal tx = new BigDecimal(to.x); + tx = tx.subtract(new BigDecimal(from.x)); + BigDecimal ty = new BigDecimal(to.y); + ty = ty.subtract(new BigDecimal(from.y)); + + BigDecimal d = mx.multiply(ty); + BigDecimal tmp = my.multiply(tx); + d = d.subtract(tmp); + + if (d.signum() == 0) { + return Point2D.construct(NumberUtils.NaN(), NumberUtils.NaN()); + } + + d = d.multiply(new BigDecimal(2.0)); + + BigDecimal mx2 = mx.multiply(mx); + BigDecimal my2 = my.multiply(my); + BigDecimal m_norm2 = mx2.add(my2); + BigDecimal tx2 = tx.multiply(tx); + BigDecimal ty2 = ty.multiply(ty); + BigDecimal t_norm2 = tx2.add(ty2); + + BigDecimal xo = my.multiply(t_norm2); + tmp = ty.multiply(m_norm2); + xo = xo.subtract(tmp); + xo = xo.divide(d, BigDecimal.ROUND_HALF_EVEN); + + BigDecimal yo = mx.multiply(t_norm2); + tmp = tx.multiply(m_norm2); + yo = yo.subtract(tmp); + yo = yo.divide(d, BigDecimal.ROUND_HALF_EVEN); + + Point2D center = Point2D.construct(from.x - xo.doubleValue(), from.y + yo.doubleValue()); + return center; + } + + private static Point2D calculateCenterFromThreePointsHelper_(Point2D from, Point2D mid_point, Point2D to) { + assert(!mid_point.isEqual(to) && !mid_point.isEqual(from) && !from.isEqual(to)); + ECoordinate mx = new ECoordinate(mid_point.x); + mx.sub(from.x); + ECoordinate my = new ECoordinate(mid_point.y); + my.sub(from.y); + ECoordinate tx = new ECoordinate(to.x); + tx.sub(from.x); + ECoordinate ty = new ECoordinate(to.y); + ty.sub(from.y); + + ECoordinate d = new ECoordinate(mx); + d.mul(ty); + ECoordinate tmp = new ECoordinate(my); + tmp.mul(tx); + d.sub(tmp); + + if (d.value() == 0.0) { + return Point2D.construct(NumberUtils.NaN(), NumberUtils.NaN()); + } + + d.mul(2.0); + + ECoordinate mx2 = new ECoordinate(mx); + mx2.mul(mx); + ECoordinate my2 = new ECoordinate(my); + my2.mul(my); + ECoordinate m_norm2 = new ECoordinate(mx2); + m_norm2.add(my2); + ECoordinate tx2 = new ECoordinate(tx); + tx2.mul(tx); + ECoordinate ty2 = new ECoordinate(ty); + ty2.mul(ty); + ECoordinate t_norm2 = new ECoordinate(tx2); + t_norm2.add(ty2); + + ECoordinate xo = new ECoordinate(my); + xo.mul(t_norm2); + tmp = new ECoordinate(ty); + tmp.mul(m_norm2); + xo.sub(tmp); + xo.div(d); + + ECoordinate yo = new ECoordinate(mx); + yo.mul(t_norm2); + tmp = new ECoordinate(tx); + tmp.mul(m_norm2); + yo.sub(tmp); + yo.div(d); + + Point2D center = Point2D.construct(from.x - xo.value(), from.y + yo.value()); + double r1 = Point2D.construct(from.x - center.x, from.y - center.y).length(); + double r2 = Point2D.construct(mid_point.x - center.x, mid_point.y - center.y).length(); + double r3 = Point2D.construct(to.x - center.x, to.y - center.y).length(); + double base = r1 + Math.abs(from.x) + Math.abs(mid_point.x) + Math.abs(to.x) + Math.abs(from.y) + + Math.abs(mid_point.y) + Math.abs(to.y); + + double tol = 1e-15; + if ((Math.abs(r1 - r2) <= base * tol && Math.abs(r1 - r3) <= base * tol)) + return center;//returns center value for MP_value type or when calculated radius value for from - center, mid - center, and to - center are very close. + + return Point2D.construct(NumberUtils.NaN(), NumberUtils.NaN()); + } + + static Point2D calculateCircleCenterFromThreePoints(Point2D from, Point2D mid_point, Point2D to) { + if (from.isEqual(to) || from.isEqual(mid_point) || to.isEqual(mid_point)) { + return new Point2D(NumberUtils.NaN(), NumberUtils.NaN()); + } + + Point2D pt = calculateCenterFromThreePointsHelper_(from, mid_point, to); //use error tracking calculations + if (pt.isNaN()) + return calculateCenterFromThreePointsHelperMP_(from, mid_point, to); //use precise calculations + else { + return pt; + } + } + + double getAxis(int ordinate) { + assert(ordinate == 0 || ordinate == 1); + return (ordinate == 0 ? x : y); + } } diff --git a/src/main/java/com/esri/core/geometry/Point3D.java b/src/main/java/com/esri/core/geometry/Point3D.java index 123a51ac..71cbfdba 100644 --- a/src/main/java/com/esri/core/geometry/Point3D.java +++ b/src/main/java/com/esri/core/geometry/Point3D.java @@ -28,105 +28,135 @@ import java.io.Serializable; /** + * * Basic 3D point class. + * */ public final class Point3D implements Serializable { - private static final long serialVersionUID = 1L; - - public double x; - public double y; - public double z; - - public Point3D() { - } - - public Point3D(Point3D other) { - setCoords(other); - } - - public Point3D(double x, double y, double z) { - setCoords(x, y, z); - } - - public static Point3D construct(double x, double y, double z) { - Point3D pt = new Point3D(); - pt.setCoords(x, y, z); - return pt; - } - - public void setCoords(double x, double y, double z) { - this.x = x; - this.y = y; - this.z = z; - } - - public void setCoords(Point3D other) { - setCoords(other.x, other.y, other.z); - } - - public void setZero() { - x = 0.0; - y = 0.0; - z = 0.0; - } - - public void normalize() { - double len = length(); - if (len == 0) { - x = 1.0; - y = 0.0; - z = 0.0; - } else { - x /= len; - y /= len; - z /= len; - } - } - - public double dotProduct(Point3D other) { - return x * other.x + y * other.y + z * other.z; - } - - public double sqrLength() { - return x * x + y * y + z * z; - } - - public double length() { - return Math.sqrt(x * x + y * y + z * z); - } - - public void sub(Point3D other) { - x -= other.x; - y -= other.y; - z -= other.z; - } - - public void sub(Point3D p1, Point3D p2) { - x = p1.x - p2.x; - y = p1.y - p2.y; - z = p1.z - p2.z; - } - - public void scale(double f, Point3D other) { - x = f * other.x; - y = f * other.y; - z = f * other.z; - } - - public void mul(double factor) { - x *= factor; - y *= factor; - z *= factor; - } - - void _setNan() { - x = NumberUtils.NaN(); - y = NumberUtils.NaN(); - z = NumberUtils.NaN(); - } - - boolean _isNan() { - return NumberUtils.isNaN(x) || NumberUtils.isNaN(y) || NumberUtils.isNaN(z); - } - + private static final long serialVersionUID = 1L; + + public double x; + public double y; + public double z; + + public Point3D() { + } + + public Point3D(Point3D other) { + setCoords(other); + } + + public Point3D(double x, double y, double z) { + setCoords(x, y, z); + } + + public static Point3D construct(double x, double y, double z) { + Point3D pt = new Point3D(); + pt.setCoords(x, y, z); + return pt; + } + + public void setCoords(double x, double y, double z) { + this.x = x; + this.y = y; + this.z = z; + } + + public void setCoords(Point3D other) { + setCoords(other.x, other.y, other.z); + } + + public void setZero() { + x = 0.0; + y = 0.0; + z = 0.0; + } + + public void normalize() { + double len = length(); + if (len == 0) { + x = 1.0; + y = 0.0; + z = 0.0; + } else { + x /= len; + y /= len; + z /= len; + } + } + + public double dotProduct(Point3D other) { + return x * other.x + y * other.y + z * other.z; + } + + public double sqrLength() { + return x * x + y * y + z * z; + } + + public double length() { + return Math.sqrt(x * x + y * y + z * z); + } + + public void sub(Point3D other) + { + x -= other.x; + y -= other.y; + z -= other.z; + } + + public void sub(Point3D p1, Point3D p2) { + x = p1.x - p2.x; + y = p1.y - p2.y; + z = p1.z - p2.z; + } + + public void scale(double f, Point3D other) { + x = f * other.x; + y = f * other.y; + z = f * other.z; + } + + public void mul(double factor) { + x *= factor; + y *= factor; + z *= factor; + } + + void _setNan() { + x = NumberUtils.NaN(); + y = NumberUtils.NaN(); + z = NumberUtils.NaN(); + } + + boolean _isNan() { + return NumberUtils.isNaN(x) || NumberUtils.isNaN(y) || NumberUtils.isNaN(z); + } + + public boolean equals(Point3D other) { + //note that for nan value this returns false. + //this is by design for this class. + return x == other.x && y == other.y && z == other.z; + } + + @Override + public boolean equals(Object other_) { + if (other_ == this) + return true; + + if (!(other_ instanceof Point3D)) + return false; + + Point3D other = (Point3D)other_; + //note that for nan value this returns false. + //this is by design for this class. + return x == other.x && y == other.y && z == other.z; + } + + @Override + public int hashCode() { + int hash = NumberUtils.hash(x); + hash = NumberUtils.hash(hash, y); + hash = NumberUtils.hash(hash, z); + return hash; + } } diff --git a/src/main/java/com/esri/core/geometry/PointInPolygonHelper.java b/src/main/java/com/esri/core/geometry/PointInPolygonHelper.java index 0f3dd9da..863ba992 100644 --- a/src/main/java/com/esri/core/geometry/PointInPolygonHelper.java +++ b/src/main/java/com/esri/core/geometry/PointInPolygonHelper.java @@ -26,410 +26,410 @@ final class PointInPolygonHelper { - private Point2D m_inputPoint; - private int m_windnum; - private SegmentBuffer[] m_monotoneParts = null; - private double[] m_xOrds = null; - private double m_tolerance; - private double m_toleranceSqr; - private double m_miny; - private double m_maxy; - private boolean m_bAlternate; - private boolean m_bTestBorder; - private boolean m_bBreak; - private boolean m_bPointInAnyOuterRingTest; - - private int result() { - return m_windnum != 0 ? 1 : 0; - } - - private boolean _testBorder(Segment seg) { - double t = seg.getClosestCoordinate(m_inputPoint, false); - Point2D pt = seg.getCoord2D(t); - if (Point2D.sqrDistance(pt, m_inputPoint) <= m_toleranceSqr) { - return true; - } - return false; - } - - private void doOne(Segment seg) { - if (!m_bTestBorder) { - // test if point is on the boundary - if (m_bAlternate && m_inputPoint.isEqual(seg.getStartXY()) - || m_inputPoint.isEqual(seg.getEndXY())) {// test if the - // point - // coincides - // with a vertex - m_bBreak = true; - return; - } - } - - if (seg.getStartY() == m_inputPoint.y - && seg.getStartY() == seg.getEndY()) {// skip horizontal - // segments. test if the - // point lies on a - // horizontal segment - if (m_bAlternate && !m_bTestBorder) { - double minx = Math.min(seg.getStartX(), seg.getEndX()); - double maxx = Math.max(seg.getStartX(), seg.getEndX()); - if (m_inputPoint.x > minx && m_inputPoint.x < maxx) - m_bBreak = true; - } - - return;// skip horizontal segments - } - - boolean bToTheRight = false; - double maxx = Math.max(seg.getStartX(), seg.getEndX()); - if (m_inputPoint.x > maxx) { - bToTheRight = true; - } else { - if (m_inputPoint.x >= Math.min(seg.getStartX(), seg.getEndX())) { - int n = seg.intersectionWithAxis2D(true, m_inputPoint.y, - m_xOrds, null); - bToTheRight = n > 0 && m_xOrds[0] <= m_inputPoint.x; - } - } - - if (bToTheRight) { - // to prevent double counting, when the ray crosses a vertex, count - // only the segments that are below the ray. - if (m_inputPoint.y == seg.getStartXY().y) { - if (m_inputPoint.y < seg.getEndXY().y) - return; - } else if (m_inputPoint.y == seg.getEndXY().y) { - if (m_inputPoint.y < seg.getStartXY().y) - return; - } - - if (m_bAlternate) - m_windnum ^= 1; - else - m_windnum += (seg.getStartXY().y > seg.getEndXY().y) ? 1 : -1; - } - } - - public PointInPolygonHelper(boolean bFillRule_Alternate, - Point2D inputPoint, double tolerance) { - // //_ASSERT(tolerance >= 0); - m_inputPoint = inputPoint; - m_miny = inputPoint.y - tolerance; - m_maxy = inputPoint.y + tolerance; - m_windnum = 0; - m_bAlternate = bFillRule_Alternate; - m_tolerance = tolerance; - m_toleranceSqr = tolerance * tolerance; - m_bTestBorder = tolerance != 0;// - m_bBreak = false; - } - - private boolean processSegment(Segment segment) { - Envelope1D yrange = segment.queryInterval( - (int) VertexDescription.Semantics.POSITION, 1); - if (yrange.vmin > m_maxy || yrange.vmax < m_miny) { - return false; - } - - if (m_bTestBorder && _testBorder(segment)) - return true; - - if (yrange.vmin > m_inputPoint.y || yrange.vmax < m_inputPoint.y) { - return false; - } - - if (m_monotoneParts == null) - m_monotoneParts = new SegmentBuffer[5]; - if (m_xOrds == null) - m_xOrds = new double[3]; - - int nparts = segment.getYMonotonicParts(m_monotoneParts); - if (nparts > 0) {// the segment is a curve and has been broken in - // ymonotone parts - for (int i = 0; i < nparts; i++) { - Segment part = m_monotoneParts[i].get(); - doOne(part); - if (m_bBreak) - return true; - } - } else {// the segment is a line or it is y monotone curve - doOne(segment); - if (m_bBreak) - return true; - } - - return false; - } - - private static int _isPointInPolygonInternal(Polygon inputPolygon, - Point2D inputPoint, double tolerance) { - - boolean bAltenate = inputPolygon.getFillRule() == Polygon.FillRule.enumFillRuleOddEven; - PointInPolygonHelper helper = new PointInPolygonHelper(bAltenate, - inputPoint, tolerance); - MultiPathImpl mpImpl = (MultiPathImpl) inputPolygon._getImpl(); - SegmentIteratorImpl iter = mpImpl.querySegmentIterator(); - while (iter.nextPath()) { - while (iter.hasNextSegment()) { - Segment segment = iter.nextSegment(); - if (helper.processSegment(segment)) - return -1; // point on boundary - } - } - - return helper.result(); - } - - private static int _isPointInPolygonInternalWithQuadTree( - Polygon inputPolygon, QuadTreeImpl quadTree, Point2D inputPoint, - double tolerance) { - Envelope2D envPoly = new Envelope2D(); - inputPolygon.queryLooseEnvelope(envPoly); - envPoly.inflate(tolerance, tolerance); - - boolean bAltenate = inputPolygon.getFillRule() == Polygon.FillRule.enumFillRuleOddEven; - PointInPolygonHelper helper = new PointInPolygonHelper(bAltenate, - inputPoint, tolerance); - - MultiPathImpl mpImpl = (MultiPathImpl) inputPolygon._getImpl(); - SegmentIteratorImpl iter = mpImpl.querySegmentIterator(); - Envelope2D queryEnv = new Envelope2D(); - queryEnv.setCoords(envPoly); - queryEnv.xmax = inputPoint.x + tolerance;// no need to query segments to - // the right of the point. - // Only segments to the left - // matter. - queryEnv.ymin = inputPoint.y - tolerance; - queryEnv.ymax = inputPoint.y + tolerance; - QuadTreeImpl.QuadTreeIteratorImpl qiter = quadTree.getIterator( - queryEnv, tolerance); - for (int qhandle = qiter.next(); qhandle != -1; qhandle = qiter.next()) { - iter.resetToVertex(quadTree.getElement(qhandle)); - if (iter.hasNextSegment()) { - Segment segment = iter.nextSegment(); - if (helper.processSegment(segment)) - return -1; // point on boundary - } - } - - return helper.result(); - } - - public static int isPointInPolygon(Polygon inputPolygon, - Point2D inputPoint, double tolerance) { - if (inputPolygon.isEmpty()) - return 0; - - Envelope2D env = new Envelope2D(); - inputPolygon.queryLooseEnvelope(env); - env.inflate(tolerance, tolerance); - if (!env.contains(inputPoint)) - return 0; - - MultiPathImpl mpImpl = (MultiPathImpl) inputPolygon._getImpl(); - GeometryAccelerators accel = mpImpl._getAccelerators(); - if (accel != null) { - // geometry has spatial indices built. Try using them. - RasterizedGeometry2D rgeom = accel.getRasterizedGeometry(); - if (rgeom != null) { - RasterizedGeometry2D.HitType hit = rgeom.queryPointInGeometry( - inputPoint.x, inputPoint.y); - if (hit == RasterizedGeometry2D.HitType.Inside) - return 1; - else if (hit == RasterizedGeometry2D.HitType.Outside) - return 0; - } - - QuadTreeImpl qtree = accel.getQuadTree(); - if (qtree != null) { - return _isPointInPolygonInternalWithQuadTree(inputPolygon, - qtree, inputPoint, tolerance); - } - } - - return _isPointInPolygonInternal(inputPolygon, inputPoint, tolerance); - } - - static int isPointInPolygon(Polygon inputPolygon, double inputPointXVal, - double inputPointYVal, double tolerance) { - if (inputPolygon.isEmpty()) - return 0; - - Envelope2D env = new Envelope2D(); - inputPolygon.queryLooseEnvelope(env); - env.inflate(tolerance, tolerance); - if (!env.contains(inputPointXVal, inputPointYVal)) - return 0; - - MultiPathImpl mpImpl = (MultiPathImpl) inputPolygon._getImpl(); - GeometryAccelerators accel = mpImpl._getAccelerators(); - if (accel != null) { - RasterizedGeometry2D rgeom = accel.getRasterizedGeometry(); - if (rgeom != null) { - RasterizedGeometry2D.HitType hit = rgeom.queryPointInGeometry( - inputPointXVal, inputPointYVal); - if (hit == RasterizedGeometry2D.HitType.Inside) - return 1; - else if (hit == RasterizedGeometry2D.HitType.Outside) - return 0; - } - } - - return _isPointInPolygonInternal(inputPolygon, new Point2D( - inputPointXVal, inputPointYVal), tolerance); - } - - public static int isPointInRing(MultiPathImpl inputPolygonImpl, int iRing, - Point2D inputPoint, double tolerance, QuadTree quadTree) { - Envelope2D env = new Envelope2D(); - inputPolygonImpl.queryLooseEnvelope2D(env); - env.inflate(tolerance, tolerance); - if (!env.contains(inputPoint)) - return 0; - - boolean bAltenate = true; - PointInPolygonHelper helper = new PointInPolygonHelper(bAltenate, - inputPoint, tolerance); - - if (quadTree != null) { - Envelope2D queryEnv = new Envelope2D(); - queryEnv.setCoords(env); - queryEnv.xmax = inputPoint.x + tolerance;// no need to query - // segments to - // the right of the - // point. - // Only segments to the - // left - // matter. - queryEnv.ymin = inputPoint.y - tolerance; - queryEnv.ymax = inputPoint.y + tolerance; - SegmentIteratorImpl iter = inputPolygonImpl.querySegmentIterator(); - QuadTree.QuadTreeIterator qiter = quadTree.getIterator(queryEnv, - tolerance); - - for (int qhandle = qiter.next(); qhandle != -1; qhandle = qiter - .next()) { - iter.resetToVertex(quadTree.getElement(qhandle), iRing); - if (iter.hasNextSegment()) { - if (iter.getPathIndex() != iRing) - continue; - - Segment segment = iter.nextSegment(); - if (helper.processSegment(segment)) - return -1; // point on boundary - } - } - - return helper.result(); - } else { - SegmentIteratorImpl iter = inputPolygonImpl.querySegmentIterator(); - iter.resetToPath(iRing); - - if (iter.nextPath()) { - while (iter.hasNextSegment()) { - Segment segment = iter.nextSegment(); - if (helper.processSegment(segment)) - return -1; // point on boundary - } - } - - return helper.result(); - } - } - - public static int isPointInPolygon(Polygon inputPolygon, Point inputPoint, - double tolerance) { - if (inputPoint.isEmpty()) - return 0; - - return isPointInPolygon(inputPolygon, inputPoint.getXY(), tolerance); - } - - public static int isPointInAnyOuterRing(Polygon inputPolygon, - Point2D inputPoint, double tolerance) { - Envelope2D env = new Envelope2D(); - inputPolygon.queryLooseEnvelope(env); - env.inflate(tolerance, tolerance); - if (!env.contains(inputPoint)) - return 0; - - // Note: - // Wolfgang had noted that this could be optimized if the exterior rings - // have positive area: - // Only test the positive rings and bail out immediately when in a - // positive ring. - // The worst case complexity is still O(n), but on average for polygons - // with holes, that would be faster. - // However, that method would not work if polygon is reversed, while the - // one here works fine same as PointInPolygon. - - boolean bAltenate = false;// use winding in this test - PointInPolygonHelper helper = new PointInPolygonHelper(bAltenate, - inputPoint, tolerance); - MultiPathImpl mpImpl = (MultiPathImpl) inputPolygon._getImpl(); - SegmentIteratorImpl iter = mpImpl.querySegmentIterator(); - while (iter.nextPath()) { - double ringArea = mpImpl.calculateRingArea2D(iter.getPathIndex()); - boolean bIsHole = ringArea < 0; - if (!bIsHole) { - helper.m_windnum = 0; - while (iter.hasNextSegment()) { - Segment segment = iter.nextSegment(); - if (helper.processSegment(segment)) - return -1; // point on boundary - } - - if (helper.m_windnum != 0) - return 1; - } - } - - return helper.result(); - } - - // Tests if Ring1 is inside Ring2. - // We assume here that the Polygon is Weak Simple. That is if one point of - // Ring1 is found to be inside of Ring2, then - // we assume that all of Ring1 is inside Ring2. - static boolean _isRingInRing2D(MultiPath polygon, int iRing1, int iRing2, - double tolerance, QuadTree quadTree) { - MultiPathImpl polygonImpl = (MultiPathImpl) polygon._getImpl(); - SegmentIteratorImpl segIter = polygonImpl.querySegmentIterator(); - segIter.resetToPath(iRing1); - if (!segIter.nextPath() || !segIter.hasNextSegment()) - throw new GeometryException("corrupted geometry"); - - int res = 2; - - while (res == 2 && segIter.hasNextSegment()) { - Segment segment = segIter.nextSegment(); - Point2D point = segment.getCoord2D(0.5); - res = PointInPolygonHelper.isPointInRing(polygonImpl, iRing2, - point, tolerance, quadTree); - } - - if (res == 2) - throw GeometryException.GeometryInternalError(); - if (res == 1) - return true; - - return false; - } - - static boolean quadTreeWillHelp(Polygon polygon, int c_queries) { - int n = polygon.getPointCount(); - - if (n < 16) - return false; - - double c_build_quad_tree = 2.0; // what's a good constant? - double c_query_quad_tree = 1.0; // what's a good constant? - double c_point_in_polygon_brute_force = 1.0; // what's a good constant? - - double c_quad_tree = c_build_quad_tree * n + c_query_quad_tree * (Math.log((double) n) / Math.log(2.0)) * c_queries; - double c_brute_force = c_point_in_polygon_brute_force * n * c_queries; - - return c_quad_tree < c_brute_force; - } + private Point2D m_inputPoint; + private int m_windnum; + private SegmentBuffer[] m_monotoneParts = null; + private double[] m_xOrds = null; + private double m_tolerance; + private double m_toleranceSqr; + private double m_miny; + private double m_maxy; + private boolean m_bAlternate; + private boolean m_bTestBorder; + private boolean m_bBreak; + private boolean m_bPointInAnyOuterRingTest; + + private int result() { + return m_windnum != 0 ? 1 : 0; + } + + private boolean _testBorder(Segment seg) { + double t = seg.getClosestCoordinate(m_inputPoint, false); + Point2D pt = seg.getCoord2D(t); + if (Point2D.sqrDistance(pt, m_inputPoint) <= m_toleranceSqr) { + return true; + } + return false; + } + + private void doOne(Segment seg) { + if (!m_bTestBorder) { + // test if point is on the boundary + if (m_bAlternate && m_inputPoint.isEqual(seg.getStartXY()) + || m_inputPoint.isEqual(seg.getEndXY())) {// test if the + // point + // coincides + // with a vertex + m_bBreak = true; + return; + } + } + + if (seg.getStartY() == m_inputPoint.y + && seg.getStartY() == seg.getEndY()) {// skip horizontal + // segments. test if the + // point lies on a + // horizontal segment + if (m_bAlternate && !m_bTestBorder) { + double minx = Math.min(seg.getStartX(), seg.getEndX()); + double maxx = Math.max(seg.getStartX(), seg.getEndX()); + if (m_inputPoint.x > minx && m_inputPoint.x < maxx) + m_bBreak = true; + } + + return;// skip horizontal segments + } + + boolean bToTheRight = false; + double maxx = Math.max(seg.getStartX(), seg.getEndX()); + if (m_inputPoint.x > maxx) { + bToTheRight = true; + } else { + if (m_inputPoint.x >= Math.min(seg.getStartX(), seg.getEndX())) { + int n = seg.intersectionWithAxis2D(true, m_inputPoint.y, + m_xOrds, null); + bToTheRight = n > 0 && m_xOrds[0] <= m_inputPoint.x; + } + } + + if (bToTheRight) { + // to prevent double counting, when the ray crosses a vertex, count + // only the segments that are below the ray. + if (m_inputPoint.y == seg.getStartXY().y) { + if (m_inputPoint.y < seg.getEndXY().y) + return; + } else if (m_inputPoint.y == seg.getEndXY().y) { + if (m_inputPoint.y < seg.getStartXY().y) + return; + } + + if (m_bAlternate) + m_windnum ^= 1; + else + m_windnum += (seg.getStartXY().y > seg.getEndXY().y) ? 1 : -1; + } + } + + public PointInPolygonHelper(boolean bFillRule_Alternate, + Point2D inputPoint, double tolerance) { + // //_ASSERT(tolerance >= 0); + m_inputPoint = inputPoint; + m_miny = inputPoint.y - tolerance; + m_maxy = inputPoint.y + tolerance; + m_windnum = 0; + m_bAlternate = bFillRule_Alternate; + m_tolerance = tolerance; + m_toleranceSqr = tolerance * tolerance; + m_bTestBorder = tolerance != 0;// + m_bBreak = false; + } + + private boolean processSegment(Segment segment) { + Envelope1D yrange = segment.queryInterval( + (int) VertexDescription.Semantics.POSITION, 1); + if (yrange.vmin > m_maxy || yrange.vmax < m_miny) { + return false; + } + + if (m_bTestBorder && _testBorder(segment)) + return true; + + if (yrange.vmin > m_inputPoint.y || yrange.vmax < m_inputPoint.y) { + return false; + } + + if (m_monotoneParts == null) + m_monotoneParts = new SegmentBuffer[5]; + if (m_xOrds == null) + m_xOrds = new double[3]; + + int nparts = segment.getYMonotonicParts(m_monotoneParts); + if (nparts > 0) {// the segment is a curve and has been broken in + // ymonotone parts + for (int i = 0; i < nparts; i++) { + Segment part = m_monotoneParts[i].get(); + doOne(part); + if (m_bBreak) + return true; + } + } else {// the segment is a line or it is y monotone curve + doOne(segment); + if (m_bBreak) + return true; + } + + return false; + } + + private static int _isPointInPolygonInternal(Polygon inputPolygon, + Point2D inputPoint, double tolerance) { + + boolean bAltenate = inputPolygon.getFillRule() == Polygon.FillRule.enumFillRuleOddEven; + PointInPolygonHelper helper = new PointInPolygonHelper(bAltenate, + inputPoint, tolerance); + MultiPathImpl mpImpl = (MultiPathImpl) inputPolygon._getImpl(); + SegmentIteratorImpl iter = mpImpl.querySegmentIterator(); + while (iter.nextPath()) { + while (iter.hasNextSegment()) { + Segment segment = iter.nextSegment(); + if (helper.processSegment(segment)) + return -1; // point on boundary + } + } + + return helper.result(); + } + + private static int _isPointInPolygonInternalWithQuadTree( + Polygon inputPolygon, QuadTreeImpl quadTree, Point2D inputPoint, + double tolerance) { + Envelope2D envPoly = new Envelope2D(); + inputPolygon.queryLooseEnvelope(envPoly); + envPoly.inflate(tolerance, tolerance); + + boolean bAltenate = inputPolygon.getFillRule() == Polygon.FillRule.enumFillRuleOddEven; + PointInPolygonHelper helper = new PointInPolygonHelper(bAltenate, + inputPoint, tolerance); + + MultiPathImpl mpImpl = (MultiPathImpl) inputPolygon._getImpl(); + SegmentIteratorImpl iter = mpImpl.querySegmentIterator(); + Envelope2D queryEnv = new Envelope2D(); + queryEnv.setCoords(envPoly); + queryEnv.xmax = inputPoint.x + tolerance;// no need to query segments to + // the right of the point. + // Only segments to the left + // matter. + queryEnv.ymin = inputPoint.y - tolerance; + queryEnv.ymax = inputPoint.y + tolerance; + QuadTreeImpl.QuadTreeIteratorImpl qiter = quadTree.getIterator( + queryEnv, tolerance); + for (int qhandle = qiter.next(); qhandle != -1; qhandle = qiter.next()) { + iter.resetToVertex(quadTree.getElement(qhandle)); + if (iter.hasNextSegment()) { + Segment segment = iter.nextSegment(); + if (helper.processSegment(segment)) + return -1; // point on boundary + } + } + + return helper.result(); + } + + public static int isPointInPolygon(Polygon inputPolygon, + Point2D inputPoint, double tolerance) { + if (inputPolygon.isEmpty()) + return 0; + + Envelope2D env = new Envelope2D(); + inputPolygon.queryLooseEnvelope(env); + env.inflate(tolerance, tolerance); + if (!env.contains(inputPoint)) + return 0; + + MultiPathImpl mpImpl = (MultiPathImpl) inputPolygon._getImpl(); + GeometryAccelerators accel = mpImpl._getAccelerators(); + if (accel != null) { + // geometry has spatial indices built. Try using them. + RasterizedGeometry2D rgeom = accel.getRasterizedGeometry(); + if (rgeom != null) { + RasterizedGeometry2D.HitType hit = rgeom.queryPointInGeometry( + inputPoint.x, inputPoint.y); + if (hit == RasterizedGeometry2D.HitType.Inside) + return 1; + else if (hit == RasterizedGeometry2D.HitType.Outside) + return 0; + } + + QuadTreeImpl qtree = accel.getQuadTree(); + if (qtree != null) { + return _isPointInPolygonInternalWithQuadTree(inputPolygon, + qtree, inputPoint, tolerance); + } + } + + return _isPointInPolygonInternal(inputPolygon, inputPoint, tolerance); + } + + static int isPointInPolygon(Polygon inputPolygon, double inputPointXVal, + double inputPointYVal, double tolerance) { + if (inputPolygon.isEmpty()) + return 0; + + Envelope2D env = new Envelope2D(); + inputPolygon.queryLooseEnvelope(env); + env.inflate(tolerance, tolerance); + if (!env.contains(inputPointXVal, inputPointYVal)) + return 0; + + MultiPathImpl mpImpl = (MultiPathImpl) inputPolygon._getImpl(); + GeometryAccelerators accel = mpImpl._getAccelerators(); + if (accel != null) { + RasterizedGeometry2D rgeom = accel.getRasterizedGeometry(); + if (rgeom != null) { + RasterizedGeometry2D.HitType hit = rgeom.queryPointInGeometry( + inputPointXVal, inputPointYVal); + if (hit == RasterizedGeometry2D.HitType.Inside) + return 1; + else if (hit == RasterizedGeometry2D.HitType.Outside) + return 0; + } + } + + return _isPointInPolygonInternal(inputPolygon, new Point2D( + inputPointXVal, inputPointYVal), tolerance); + } + + public static int isPointInRing(MultiPathImpl inputPolygonImpl, int iRing, + Point2D inputPoint, double tolerance, QuadTree quadTree) { + Envelope2D env = new Envelope2D(); + inputPolygonImpl.queryLooseEnvelope2D(env); + env.inflate(tolerance, tolerance); + if (!env.contains(inputPoint)) + return 0; + + boolean bAltenate = true; + PointInPolygonHelper helper = new PointInPolygonHelper(bAltenate, + inputPoint, tolerance); + + if (quadTree != null) { + Envelope2D queryEnv = new Envelope2D(); + queryEnv.setCoords(env); + queryEnv.xmax = inputPoint.x + tolerance;// no need to query + // segments to + // the right of the + // point. + // Only segments to the + // left + // matter. + queryEnv.ymin = inputPoint.y - tolerance; + queryEnv.ymax = inputPoint.y + tolerance; + SegmentIteratorImpl iter = inputPolygonImpl.querySegmentIterator(); + QuadTree.QuadTreeIterator qiter = quadTree.getIterator(queryEnv, + tolerance); + + for (int qhandle = qiter.next(); qhandle != -1; qhandle = qiter + .next()) { + iter.resetToVertex(quadTree.getElement(qhandle), iRing); + if (iter.hasNextSegment()) { + if (iter.getPathIndex() != iRing) + continue; + + Segment segment = iter.nextSegment(); + if (helper.processSegment(segment)) + return -1; // point on boundary + } + } + + return helper.result(); + } else { + SegmentIteratorImpl iter = inputPolygonImpl.querySegmentIterator(); + iter.resetToPath(iRing); + + if (iter.nextPath()) { + while (iter.hasNextSegment()) { + Segment segment = iter.nextSegment(); + if (helper.processSegment(segment)) + return -1; // point on boundary + } + } + + return helper.result(); + } + } + + public static int isPointInPolygon(Polygon inputPolygon, Point inputPoint, + double tolerance) { + if (inputPoint.isEmpty()) + return 0; + + return isPointInPolygon(inputPolygon, inputPoint.getXY(), tolerance); + } + + public static int isPointInAnyOuterRing(Polygon inputPolygon, + Point2D inputPoint, double tolerance) { + Envelope2D env = new Envelope2D(); + inputPolygon.queryLooseEnvelope(env); + env.inflate(tolerance, tolerance); + if (!env.contains(inputPoint)) + return 0; + + // Note: + // Wolfgang had noted that this could be optimized if the exterior rings + // have positive area: + // Only test the positive rings and bail out immediately when in a + // positive ring. + // The worst case complexity is still O(n), but on average for polygons + // with holes, that would be faster. + // However, that method would not work if polygon is reversed, while the + // one here works fine same as PointInPolygon. + + boolean bAltenate = false;// use winding in this test + PointInPolygonHelper helper = new PointInPolygonHelper(bAltenate, + inputPoint, tolerance); + MultiPathImpl mpImpl = (MultiPathImpl) inputPolygon._getImpl(); + SegmentIteratorImpl iter = mpImpl.querySegmentIterator(); + while (iter.nextPath()) { + double ringArea = mpImpl.calculateRingArea2D(iter.getPathIndex()); + boolean bIsHole = ringArea < 0; + if (!bIsHole) { + helper.m_windnum = 0; + while (iter.hasNextSegment()) { + Segment segment = iter.nextSegment(); + if (helper.processSegment(segment)) + return -1; // point on boundary + } + + if (helper.m_windnum != 0) + return 1; + } + } + + return helper.result(); + } + + // Tests if Ring1 is inside Ring2. + // We assume here that the Polygon is Weak Simple. That is if one point of + // Ring1 is found to be inside of Ring2, then + // we assume that all of Ring1 is inside Ring2. + static boolean _isRingInRing2D(MultiPath polygon, int iRing1, int iRing2, + double tolerance, QuadTree quadTree) { + MultiPathImpl polygonImpl = (MultiPathImpl) polygon._getImpl(); + SegmentIteratorImpl segIter = polygonImpl.querySegmentIterator(); + segIter.resetToPath(iRing1); + if (!segIter.nextPath() || !segIter.hasNextSegment()) + throw new GeometryException("corrupted geometry"); + + int res = 2; + + while (res == 2 && segIter.hasNextSegment()) { + Segment segment = segIter.nextSegment(); + Point2D point = segment.getCoord2D(0.5); + res = PointInPolygonHelper.isPointInRing(polygonImpl, iRing2, + point, tolerance, quadTree); + } + + if (res == 2) + throw GeometryException.GeometryInternalError(); + if (res == 1) + return true; + + return false; + } + + static boolean quadTreeWillHelp(Polygon polygon, int c_queries) { + int n = polygon.getPointCount(); + + if (n < 16) + return false; + + double c_build_quad_tree = 2.0; // what's a good constant? + double c_query_quad_tree = 1.0; // what's a good constant? + double c_point_in_polygon_brute_force = 1.0; // what's a good constant? + + double c_quad_tree = c_build_quad_tree * n + c_query_quad_tree * (Math.log((double) n) / Math.log(2.0)) * c_queries; + double c_brute_force = c_point_in_polygon_brute_force * n * c_queries; + + return c_quad_tree < c_brute_force; + } } diff --git a/src/main/java/com/esri/core/geometry/Polygon.java b/src/main/java/com/esri/core/geometry/Polygon.java index 44b920df..d37e92dd 100644 --- a/src/main/java/com/esri/core/geometry/Polygon.java +++ b/src/main/java/com/esri/core/geometry/Polygon.java @@ -34,34 +34,34 @@ */ public class Polygon extends MultiPath implements Serializable { private static final long serialVersionUID = 2L;// TODO:remove as we use - // writeReplace and - // GeometrySerializer - - /** - * Creates a polygon. - */ - public Polygon() { - m_impl = new MultiPathImpl(true); - } - - public Polygon(VertexDescription vd) { - m_impl = new MultiPathImpl(true, vd); - } - - @Override - public Geometry createInstance() { - return new Polygon(getDescription()); - } - - @Override - public int getDimension() { - return 2; - } - - @Override - public Geometry.Type getType() { - return Type.Polygon; - } + // writeReplace and + // GeometrySerializer + + /** + * Creates a polygon. + */ + public Polygon() { + m_impl = new MultiPathImpl(true); + } + + public Polygon(VertexDescription vd) { + m_impl = new MultiPathImpl(true, vd); + } + + @Override + public Geometry createInstance() { + return new Polygon(getDescription()); + } + + @Override + public int getDimension() { + return 2; + } + + @Override + public Geometry.Type getType() { + return Type.Polygon; + } @Override public long estimateMemorySize() { @@ -70,78 +70,77 @@ public long estimateMemorySize() { /** * Calculates the ring area for this ring. - * - * @param ringIndex - * The index of this ring. + * + * @param ringIndex The index of this ring. * @return The ring area for this ring. */ public double calculateRingArea2D(int ringIndex) { return m_impl.calculateRingArea2D(ringIndex); } - /** - * Returns TRUE if the ring is an exterior ring. Valid only for simple - * polygons. - */ - public boolean isExteriorRing(int partIndex) { - return m_impl.isExteriorRing(partIndex); - } - - /** - * Returns TRUE when this geometry has exactly same type, properties, and - * coordinates as the other geometry. - */ - @Override - public boolean equals(Object other) { - if (other == null) - return false; - - if (other == this) - return true; - - if (other.getClass() != getClass()) - return false; - - return m_impl.equals(((Polygon) other)._getImpl()); - } - - /** - * Returns a hash code value for this polygon. - */ - - @Override - public int hashCode() { - return m_impl.hashCode(); - } - - /** - * Sets a new vertex for the polygon. - * - * @param i The index of the new vertex. - * @param x The X coordinate for the new vertex. - * @param y The Y coordinate for the new vertex. - */ - public void setXY(int i, double x, double y) { - m_impl.setXY(i, x, y); - - } - - public void interpolateAttributes(int path_index, int from_point_index, - int to_point_index) { - m_impl.interpolateAttributes(path_index, from_point_index, - to_point_index); - } - - public void interpolateAttributes(int semantics, int path_index, - int from_point_index, int to_point_index) { - m_impl.interpolateAttributesForSemantics(semantics, path_index, - from_point_index, to_point_index); - } + /** + * Returns TRUE if the ring is an exterior ring. Valid only for simple + * polygons. + */ + public boolean isExteriorRing(int partIndex) { + return m_impl.isExteriorRing(partIndex); + } + + /** + * Returns TRUE when this geometry has exactly same type, properties, and + * coordinates as the other geometry. + */ + @Override + public boolean equals(Object other) { + if (other == null) + return false; + + if (other == this) + return true; + + if (other.getClass() != getClass()) + return false; + + return m_impl.equals(((Polygon) other)._getImpl()); + } + + /** + * Returns a hash code value for this polygon. + */ + + @Override + public int hashCode() { + return m_impl.hashCode(); + } + + /** + * Sets a new vertex for the polygon. + * + * @param i The index of the new vertex. + * @param x The X coordinate for the new vertex. + * @param y The Y coordinate for the new vertex. + */ + public void setXY(int i, double x, double y) { + m_impl.setXY(i, x, y); + + } + + public void interpolateAttributes(int path_index, int from_point_index, + int to_point_index) { + m_impl.interpolateAttributes(path_index, from_point_index, + to_point_index); + } + + public void interpolateAttributes(int semantics, int path_index, + int from_point_index, int to_point_index) { + m_impl.interpolateAttributesForSemantics(semantics, path_index, + from_point_index, to_point_index); + } public int getExteriorRingCount() { return m_impl.getOGCPolygonCount(); } - + public interface FillRule { /** * odd-even fill rule. This is the default value. A point is in the polygon @@ -157,7 +156,9 @@ public interface FillRule { * crosses segments directed down, then the winding number is equal to N-M. */ public final static int enumFillRuleWinding = 1; - }; + } + + ; /** * Fill rule for the polygon that defines the interior of the self intersecting diff --git a/src/main/java/com/esri/core/geometry/PolygonUtils.java b/src/main/java/com/esri/core/geometry/PolygonUtils.java index f858e7f2..5d581564 100644 --- a/src/main/java/com/esri/core/geometry/PolygonUtils.java +++ b/src/main/java/com/esri/core/geometry/PolygonUtils.java @@ -26,306 +26,306 @@ final class PolygonUtils { - public enum PiPResult { - PiPOutside, PiPInside, PiPBoundary - } - - ; - - // enum_class PiPResult { PiPOutside = 0, PiPInside = 1, PiPBoundary = 2}; - - /** - * Tests if Point is inside the Polygon. Returns PiPOutside if not in - * polygon, PiPInside if in the polygon, PiPBoundary is if on the border. It - * tests border only if the tolerance is greater than 0, otherwise PiPBoundary cannot - * be returned. Note: If the tolerance is not 0, the test is more expensive - * because it calculates closest distance from a point to each segment. - *

- * O(n) complexity, where n is the number of polygon segments. - */ - public static PiPResult isPointInPolygon2D(Polygon polygon, - Point inputPoint, double tolerance) { - int res = PointInPolygonHelper.isPointInPolygon(polygon, inputPoint, - tolerance); - if (res == 0) - return PiPResult.PiPOutside; - if (res == 1) - return PiPResult.PiPInside; - - return PiPResult.PiPBoundary; - } - - public static PiPResult isPointInPolygon2D(Polygon polygon, - Point2D inputPoint, double tolerance) { - int res = PointInPolygonHelper.isPointInPolygon(polygon, inputPoint, - tolerance); - if (res == 0) - return PiPResult.PiPOutside; - if (res == 1) - return PiPResult.PiPInside; - - return PiPResult.PiPBoundary; - } - - static PiPResult isPointInPolygon2D(Polygon polygon, double inputPointXVal, - double inputPointYVal, double tolerance) { - int res = PointInPolygonHelper.isPointInPolygon(polygon, - inputPointXVal, inputPointYVal, tolerance); - if (res == 0) - return PiPResult.PiPOutside; - if (res == 1) - return PiPResult.PiPInside; - - return PiPResult.PiPBoundary; - } - - /** - * Tests if Point is inside the Polygon's ring. Returns PiPOutside if not in - * ring, PiPInside if in the ring, PiPBoundary is if on the border. It tests - * border only if the tolerance is greater than 0, otherwise PiPBoundary cannot be - * returned. Note: If the tolerance is not 0, the test is more expensive - * because it calculates closest distance from a point to each segment. - *

- * O(n) complexity, where n is the number of ring segments. - */ - public static PiPResult isPointInRing2D(Polygon polygon, int iRing, - Point2D inputPoint, double tolerance) { - MultiPathImpl polygonImpl = (MultiPathImpl) polygon._getImpl(); - int res = PointInPolygonHelper.isPointInRing(polygonImpl, iRing, - inputPoint, tolerance, null); - if (res == 0) - return PiPResult.PiPOutside; - if (res == 1) - return PiPResult.PiPInside; - - // return PiPResult.PiPBoundary; - return PiPResult.PiPInside; // we do not return PiPBoundary. Overwise, - // we would have to do more complex - // calculations to differentiat between - // internal and external boundaries. - } - - /** - * Tests if Point is inside of the any outer ring of a Polygon. Returns - * PiPOutside if not in any outer ring, PiPInside if in the any outer ring, - * or on the boundary. PiPBoundary is never returned. Note: If the tolerance - * is not 0, the test is more expensive because it calculates closest - * distance from a point to each segment. - *

- * O(n) complexity, where n is the number of polygon segments. - */ - public static PiPResult isPointInAnyOuterRing(Polygon polygon, - Point2D inputPoint, double tolerance) { - int res = PointInPolygonHelper.isPointInAnyOuterRing(polygon, - inputPoint, tolerance); - if (res == 0) - return PiPResult.PiPOutside; - if (res == 1) - return PiPResult.PiPInside; - - // return PiPResult.PiPBoundary; - return PiPResult.PiPInside; // we do not return PiPBoundary. Overwise, - // we would have to do more complex - // calculations to differentiat between - // internal and external boundaries. - } - - /** - * Tests point is inside the Polygon for an array of points. Returns - * PiPOutside if not in polygon, PiPInside if in the polygon, PiPBoundary is - * if on the border. It tests border only if the tolerance is greater than 0, otherwise - * PiPBoundary cannot be returned. Note: If the tolerance is not 0, the test - * is more expensive. - *

- * O(n*m) complexity, where n is the number of polygon segments, m is the - * number of input points. - */ - public static void testPointsInPolygon2D(Polygon polygon, - Point2D[] inputPoints, int count, double tolerance, - PiPResult[] testResults) { - if (inputPoints.length < count || testResults.length < count) - throw new IllegalArgumentException();// GEOMTHROW(invalid_argument); - - for (int i = 0; i < count; i++) - testResults[i] = isPointInPolygon2D(polygon, inputPoints[i], - tolerance); - } - - static void testPointsInPolygon2D(Polygon polygon, double[] xyStreamBuffer, - int pointCount, double tolerance, PiPResult[] testResults) { - if (xyStreamBuffer.length / 2 < pointCount - || testResults.length < pointCount) - throw new IllegalArgumentException();// GEOMTHROW(invalid_argument); - - for (int i = 0; i < pointCount; i++) - testResults[i] = isPointInPolygon2D(polygon, xyStreamBuffer[i * 2], - xyStreamBuffer[i * 2 + 1], tolerance); - } - - /** - * Tests point is inside an Area Geometry (Envelope, Polygon) for an array - * of points. Returns PiPOutside if not in area, PiPInside if in the area, - * PiPBoundary is if on the border. It tests border only if the tolerance is - * greater than 0, otherwise PiPBoundary cannot be returned. Note: If the tolerance is - * not 0, the test is more expensive. - *

- * O(n*m) complexity, where n is the number of polygon segments, m is the - * number of input points. - */ - public static void testPointsInArea2D(Geometry polygon, - Point2D[] inputPoints, int count, double tolerance, - PiPResult[] testResults) { - if (polygon.getType() == Geometry.Type.Polygon) - testPointsInPolygon2D((Polygon) polygon, inputPoints, count, - tolerance, testResults); - else if (polygon.getType() == Geometry.Type.Envelope) { - Envelope2D env2D = new Envelope2D(); - ((Envelope) polygon).queryEnvelope2D(env2D); - _testPointsInEnvelope2D(env2D, inputPoints, count, tolerance, - testResults); - } else - throw new GeometryException("invalid_call");// GEOMTHROW(invalid_call); - } - - public static void testPointsInArea2D(Geometry polygon, - double[] xyStreamBuffer, int count, double tolerance, - PiPResult[] testResults) { - if (polygon.getType() == Geometry.Type.Polygon) - testPointsInPolygon2D((Polygon) polygon, xyStreamBuffer, count, - tolerance, testResults); - else if (polygon.getType() == Geometry.Type.Envelope) { - Envelope2D env2D = new Envelope2D(); - ((Envelope) polygon).queryEnvelope2D(env2D); - _testPointsInEnvelope2D(env2D, xyStreamBuffer, count, tolerance, - testResults); - } else - throw new GeometryException("invalid_call");// GEOMTHROW(invalid_call); - } - - private static void _testPointsInEnvelope2D(Envelope2D env2D, - Point2D[] inputPoints, int count, double tolerance, - PiPResult[] testResults) { - if (inputPoints.length < count || testResults.length < count) - throw new IllegalArgumentException(); - - if (env2D.isEmpty()) { - for (int i = 0; i < count; i++) - testResults[i] = PiPResult.PiPOutside; - return; - } - - Envelope2D envIn = env2D; // note for java port - assignement by value - envIn.inflate(-tolerance * 0.5, -tolerance * 0.5); - Envelope2D envOut = env2D;// note for java port - assignement by value - envOut.inflate(tolerance * 0.5, tolerance * 0.5); - for (int i = 0; i < count; i++) { - if (envIn.contains(inputPoints[i])) - testResults[i] = PiPResult.PiPInside; - else if (!envOut.contains(inputPoints[i])) - testResults[i] = PiPResult.PiPOutside; - else - testResults[i] = PiPResult.PiPBoundary; - } - } - - private static void _testPointsInEnvelope2D(Envelope2D env2D, - double[] xyStreamBuffer, int pointCount, double tolerance, - PiPResult[] testResults) { - if (xyStreamBuffer.length / 2 < pointCount - || testResults.length < pointCount) - throw new IllegalArgumentException(); - - if (env2D.isEmpty()) { - for (int i = 0; i < pointCount; i++) - testResults[i] = PiPResult.PiPOutside; - return; - } - - Envelope2D envIn = env2D; // note for java port - assignement by value - envIn.inflate(-tolerance * 0.5, -tolerance * 0.5); - Envelope2D envOut = env2D;// note for java port - assignement by value - envOut.inflate(tolerance * 0.5, tolerance * 0.5); - for (int i = 0; i < pointCount; i++) { - if (envIn - .contains(xyStreamBuffer[i * 2], xyStreamBuffer[i * 2 + 1])) - testResults[i] = PiPResult.PiPInside; - else if (!envIn.contains(xyStreamBuffer[i * 2], - xyStreamBuffer[i * 2 + 1])) - testResults[i] = PiPResult.PiPOutside; - else - testResults[i] = PiPResult.PiPBoundary; - } - } - - static void testPointsOnSegment_(Segment seg, Point2D[] input_points, - int count, double tolerance, PolygonUtils.PiPResult[] test_results) { - for (int i = 0; i < count; i++) { - if (seg.isIntersecting(input_points[i], tolerance)) - test_results[i] = PiPResult.PiPBoundary; - else - test_results[i] = PiPResult.PiPOutside; - } - } - - static void testPointsOnPolyline2D_(Polyline poly, Point2D[] input_points, - int count, double tolerance, PolygonUtils.PiPResult[] test_results) { - MultiPathImpl mp_impl = (MultiPathImpl) poly._getImpl(); - GeometryAccelerators accel = mp_impl._getAccelerators(); - RasterizedGeometry2D rgeom = null; - if (accel != null) { - rgeom = accel.getRasterizedGeometry(); - } - - int pointsLeft = count; - for (int i = 0; i < count; i++) { - test_results[i] = PiPResult.PiPInside;// set to impossible value - - if (rgeom != null) { - Point2D input_point = input_points[i]; - RasterizedGeometry2D.HitType hit = rgeom.queryPointInGeometry( - input_point.x, input_point.y); - if (hit == RasterizedGeometry2D.HitType.Outside) { - test_results[i] = PiPResult.PiPOutside; - pointsLeft--; - } - } - } - - if (pointsLeft != 0) { - SegmentIteratorImpl iter = mp_impl.querySegmentIterator(); - while (iter.nextPath() && pointsLeft != 0) { - while (iter.hasNextSegment() && pointsLeft != 0) { - Segment segment = iter.nextSegment(); - for (int i = 0; i < count && pointsLeft != 0; i++) { - if (test_results[i] == PiPResult.PiPInside) { - if (segment.isIntersecting(input_points[i], - tolerance)) { - test_results[i] = PiPResult.PiPBoundary; - pointsLeft--; - } - } - } - } - } - } - - for (int i = 0; i < count; i++) { - if (test_results[i] == PiPResult.PiPInside) - test_results[i] = PiPResult.PiPOutside; - } - } - - static void testPointsOnLine2D(Geometry line, Point2D[] input_points, - int count, double tolerance, PolygonUtils.PiPResult[] test_results) { - Geometry.Type gt = line.getType(); - if (gt == Geometry.Type.Polyline) - testPointsOnPolyline2D_((Polyline) line, input_points, count, - tolerance, test_results); - else if (Geometry.isSegment(gt.value())) { - testPointsOnSegment_((Segment) line, input_points, count, - tolerance, test_results); - } else - throw new GeometryException("Invalid call."); - } + public enum PiPResult { + PiPOutside, PiPInside, PiPBoundary + } + + ; + + // enum_class PiPResult { PiPOutside = 0, PiPInside = 1, PiPBoundary = 2}; + + /** + * Tests if Point is inside the Polygon. Returns PiPOutside if not in + * polygon, PiPInside if in the polygon, PiPBoundary is if on the border. It + * tests border only if the tolerance is greater than 0, otherwise PiPBoundary cannot + * be returned. Note: If the tolerance is not 0, the test is more expensive + * because it calculates closest distance from a point to each segment. + *

+ * O(n) complexity, where n is the number of polygon segments. + */ + public static PiPResult isPointInPolygon2D(Polygon polygon, + Point inputPoint, double tolerance) { + int res = PointInPolygonHelper.isPointInPolygon(polygon, inputPoint, + tolerance); + if (res == 0) + return PiPResult.PiPOutside; + if (res == 1) + return PiPResult.PiPInside; + + return PiPResult.PiPBoundary; + } + + public static PiPResult isPointInPolygon2D(Polygon polygon, + Point2D inputPoint, double tolerance) { + int res = PointInPolygonHelper.isPointInPolygon(polygon, inputPoint, + tolerance); + if (res == 0) + return PiPResult.PiPOutside; + if (res == 1) + return PiPResult.PiPInside; + + return PiPResult.PiPBoundary; + } + + static PiPResult isPointInPolygon2D(Polygon polygon, double inputPointXVal, + double inputPointYVal, double tolerance) { + int res = PointInPolygonHelper.isPointInPolygon(polygon, + inputPointXVal, inputPointYVal, tolerance); + if (res == 0) + return PiPResult.PiPOutside; + if (res == 1) + return PiPResult.PiPInside; + + return PiPResult.PiPBoundary; + } + + /** + * Tests if Point is inside the Polygon's ring. Returns PiPOutside if not in + * ring, PiPInside if in the ring, PiPBoundary is if on the border. It tests + * border only if the tolerance is greater than 0, otherwise PiPBoundary cannot be + * returned. Note: If the tolerance is not 0, the test is more expensive + * because it calculates closest distance from a point to each segment. + *

+ * O(n) complexity, where n is the number of ring segments. + */ + public static PiPResult isPointInRing2D(Polygon polygon, int iRing, + Point2D inputPoint, double tolerance) { + MultiPathImpl polygonImpl = (MultiPathImpl) polygon._getImpl(); + int res = PointInPolygonHelper.isPointInRing(polygonImpl, iRing, + inputPoint, tolerance, null); + if (res == 0) + return PiPResult.PiPOutside; + if (res == 1) + return PiPResult.PiPInside; + + // return PiPResult.PiPBoundary; + return PiPResult.PiPInside; // we do not return PiPBoundary. Overwise, + // we would have to do more complex + // calculations to differentiat between + // internal and external boundaries. + } + + /** + * Tests if Point is inside of the any outer ring of a Polygon. Returns + * PiPOutside if not in any outer ring, PiPInside if in the any outer ring, + * or on the boundary. PiPBoundary is never returned. Note: If the tolerance + * is not 0, the test is more expensive because it calculates closest + * distance from a point to each segment. + *

+ * O(n) complexity, where n is the number of polygon segments. + */ + public static PiPResult isPointInAnyOuterRing(Polygon polygon, + Point2D inputPoint, double tolerance) { + int res = PointInPolygonHelper.isPointInAnyOuterRing(polygon, + inputPoint, tolerance); + if (res == 0) + return PiPResult.PiPOutside; + if (res == 1) + return PiPResult.PiPInside; + + // return PiPResult.PiPBoundary; + return PiPResult.PiPInside; // we do not return PiPBoundary. Overwise, + // we would have to do more complex + // calculations to differentiat between + // internal and external boundaries. + } + + /** + * Tests point is inside the Polygon for an array of points. Returns + * PiPOutside if not in polygon, PiPInside if in the polygon, PiPBoundary is + * if on the border. It tests border only if the tolerance is greater than 0, otherwise + * PiPBoundary cannot be returned. Note: If the tolerance is not 0, the test + * is more expensive. + *

+ * O(n*m) complexity, where n is the number of polygon segments, m is the + * number of input points. + */ + public static void testPointsInPolygon2D(Polygon polygon, + Point2D[] inputPoints, int count, double tolerance, + PiPResult[] testResults) { + if (inputPoints.length < count || testResults.length < count) + throw new IllegalArgumentException();// GEOMTHROW(invalid_argument); + + for (int i = 0; i < count; i++) + testResults[i] = isPointInPolygon2D(polygon, inputPoints[i], + tolerance); + } + + static void testPointsInPolygon2D(Polygon polygon, double[] xyStreamBuffer, + int pointCount, double tolerance, PiPResult[] testResults) { + if (xyStreamBuffer.length / 2 < pointCount + || testResults.length < pointCount) + throw new IllegalArgumentException();// GEOMTHROW(invalid_argument); + + for (int i = 0; i < pointCount; i++) + testResults[i] = isPointInPolygon2D(polygon, xyStreamBuffer[i * 2], + xyStreamBuffer[i * 2 + 1], tolerance); + } + + /** + * Tests point is inside an Area Geometry (Envelope, Polygon) for an array + * of points. Returns PiPOutside if not in area, PiPInside if in the area, + * PiPBoundary is if on the border. It tests border only if the tolerance is + * greater than 0, otherwise PiPBoundary cannot be returned. Note: If the tolerance is + * not 0, the test is more expensive. + *

+ * O(n*m) complexity, where n is the number of polygon segments, m is the + * number of input points. + */ + public static void testPointsInArea2D(Geometry polygon, + Point2D[] inputPoints, int count, double tolerance, + PiPResult[] testResults) { + if (polygon.getType() == Geometry.Type.Polygon) + testPointsInPolygon2D((Polygon) polygon, inputPoints, count, + tolerance, testResults); + else if (polygon.getType() == Geometry.Type.Envelope) { + Envelope2D env2D = new Envelope2D(); + ((Envelope) polygon).queryEnvelope2D(env2D); + _testPointsInEnvelope2D(env2D, inputPoints, count, tolerance, + testResults); + } else + throw new GeometryException("invalid_call");// GEOMTHROW(invalid_call); + } + + public static void testPointsInArea2D(Geometry polygon, + double[] xyStreamBuffer, int count, double tolerance, + PiPResult[] testResults) { + if (polygon.getType() == Geometry.Type.Polygon) + testPointsInPolygon2D((Polygon) polygon, xyStreamBuffer, count, + tolerance, testResults); + else if (polygon.getType() == Geometry.Type.Envelope) { + Envelope2D env2D = new Envelope2D(); + ((Envelope) polygon).queryEnvelope2D(env2D); + _testPointsInEnvelope2D(env2D, xyStreamBuffer, count, tolerance, + testResults); + } else + throw new GeometryException("invalid_call");// GEOMTHROW(invalid_call); + } + + private static void _testPointsInEnvelope2D(Envelope2D env2D, + Point2D[] inputPoints, int count, double tolerance, + PiPResult[] testResults) { + if (inputPoints.length < count || testResults.length < count) + throw new IllegalArgumentException(); + + if (env2D.isEmpty()) { + for (int i = 0; i < count; i++) + testResults[i] = PiPResult.PiPOutside; + return; + } + + Envelope2D envIn = env2D; // note for java port - assignement by value + envIn.inflate(-tolerance * 0.5, -tolerance * 0.5); + Envelope2D envOut = env2D;// note for java port - assignement by value + envOut.inflate(tolerance * 0.5, tolerance * 0.5); + for (int i = 0; i < count; i++) { + if (envIn.contains(inputPoints[i])) + testResults[i] = PiPResult.PiPInside; + else if (!envOut.contains(inputPoints[i])) + testResults[i] = PiPResult.PiPOutside; + else + testResults[i] = PiPResult.PiPBoundary; + } + } + + private static void _testPointsInEnvelope2D(Envelope2D env2D, + double[] xyStreamBuffer, int pointCount, double tolerance, + PiPResult[] testResults) { + if (xyStreamBuffer.length / 2 < pointCount + || testResults.length < pointCount) + throw new IllegalArgumentException(); + + if (env2D.isEmpty()) { + for (int i = 0; i < pointCount; i++) + testResults[i] = PiPResult.PiPOutside; + return; + } + + Envelope2D envIn = env2D; // note for java port - assignement by value + envIn.inflate(-tolerance * 0.5, -tolerance * 0.5); + Envelope2D envOut = env2D;// note for java port - assignement by value + envOut.inflate(tolerance * 0.5, tolerance * 0.5); + for (int i = 0; i < pointCount; i++) { + if (envIn + .contains(xyStreamBuffer[i * 2], xyStreamBuffer[i * 2 + 1])) + testResults[i] = PiPResult.PiPInside; + else if (!envIn.contains(xyStreamBuffer[i * 2], + xyStreamBuffer[i * 2 + 1])) + testResults[i] = PiPResult.PiPOutside; + else + testResults[i] = PiPResult.PiPBoundary; + } + } + + static void testPointsOnSegment_(Segment seg, Point2D[] input_points, + int count, double tolerance, PolygonUtils.PiPResult[] test_results) { + for (int i = 0; i < count; i++) { + if (seg.isIntersecting(input_points[i], tolerance)) + test_results[i] = PiPResult.PiPBoundary; + else + test_results[i] = PiPResult.PiPOutside; + } + } + + static void testPointsOnPolyline2D_(Polyline poly, Point2D[] input_points, + int count, double tolerance, PolygonUtils.PiPResult[] test_results) { + MultiPathImpl mp_impl = (MultiPathImpl) poly._getImpl(); + GeometryAccelerators accel = mp_impl._getAccelerators(); + RasterizedGeometry2D rgeom = null; + if (accel != null) { + rgeom = accel.getRasterizedGeometry(); + } + + int pointsLeft = count; + for (int i = 0; i < count; i++) { + test_results[i] = PiPResult.PiPInside;// set to impossible value + + if (rgeom != null) { + Point2D input_point = input_points[i]; + RasterizedGeometry2D.HitType hit = rgeom.queryPointInGeometry( + input_point.x, input_point.y); + if (hit == RasterizedGeometry2D.HitType.Outside) { + test_results[i] = PiPResult.PiPOutside; + pointsLeft--; + } + } + } + + if (pointsLeft != 0) { + SegmentIteratorImpl iter = mp_impl.querySegmentIterator(); + while (iter.nextPath() && pointsLeft != 0) { + while (iter.hasNextSegment() && pointsLeft != 0) { + Segment segment = iter.nextSegment(); + for (int i = 0; i < count && pointsLeft != 0; i++) { + if (test_results[i] == PiPResult.PiPInside) { + if (segment.isIntersecting(input_points[i], + tolerance)) { + test_results[i] = PiPResult.PiPBoundary; + pointsLeft--; + } + } + } + } + } + } + + for (int i = 0; i < count; i++) { + if (test_results[i] == PiPResult.PiPInside) + test_results[i] = PiPResult.PiPOutside; + } + } + + static void testPointsOnLine2D(Geometry line, Point2D[] input_points, + int count, double tolerance, PolygonUtils.PiPResult[] test_results) { + Geometry.Type gt = line.getType(); + if (gt == Geometry.Type.Polyline) + testPointsOnPolyline2D_((Polyline) line, input_points, count, + tolerance, test_results); + else if (Geometry.isSegment(gt.value())) { + testPointsOnSegment_((Segment) line, input_points, count, + tolerance, test_results); + } else + throw new GeometryException("Invalid call."); + } } diff --git a/src/main/java/com/esri/core/geometry/Polyline.java b/src/main/java/com/esri/core/geometry/Polyline.java index d6bfe51d..faa3fc6f 100644 --- a/src/main/java/com/esri/core/geometry/Polyline.java +++ b/src/main/java/com/esri/core/geometry/Polyline.java @@ -34,44 +34,44 @@ */ public class Polyline extends MultiPath implements Serializable { - private static final long serialVersionUID = 2L;// TODO:remove as we use - // writeReplace and - // GeometrySerializer - - /** - * Creates an empty polyline. - */ - public Polyline() { - m_impl = new MultiPathImpl(false); - } - - public Polyline(VertexDescription vd) { - m_impl = new MultiPathImpl(false, vd); - } - - /** - * Creates a polyline with one line segment. - */ - public Polyline(Point start, Point end) { - m_impl = new MultiPathImpl(false, start.getDescription()); - startPath(start); - lineTo(end); - } - - @Override - public Geometry createInstance() { - return new Polyline(getDescription()); - } - - @Override - public int getDimension() { - return 1; - } - - @Override - public Geometry.Type getType() { - return Type.Polyline; - } + private static final long serialVersionUID = 2L;// TODO:remove as we use + // writeReplace and + // GeometrySerializer + + /** + * Creates an empty polyline. + */ + public Polyline() { + m_impl = new MultiPathImpl(false); + } + + public Polyline(VertexDescription vd) { + m_impl = new MultiPathImpl(false, vd); + } + + /** + * Creates a polyline with one line segment. + */ + public Polyline(Point start, Point end) { + m_impl = new MultiPathImpl(false, start.getDescription()); + startPath(start); + lineTo(end); + } + + @Override + public Geometry createInstance() { + return new Polyline(getDescription()); + } + + @Override + public int getDimension() { + return 1; + } + + @Override + public Geometry.Type getType() { + return Type.Polyline; + } @Override public long estimateMemorySize() { @@ -87,38 +87,38 @@ public boolean equals(Object other) { if (other == null) return false; - if (other == this) - return true; + if (other == this) + return true; - if (other.getClass() != getClass()) - return false; + if (other.getClass() != getClass()) + return false; - return m_impl.equals(((Polyline) other)._getImpl()); - } + return m_impl.equals(((Polyline) other)._getImpl()); + } - /** - * Returns the hash code for the polyline. - */ + /** + * Returns the hash code for the polyline. + */ - @Override - public int hashCode() { - return m_impl.hashCode(); - } + @Override + public int hashCode() { + return m_impl.hashCode(); + } - @Override - public void addSegment(Segment segment, boolean bStartNewPath) { - m_impl.addSegment(segment, bStartNewPath); - } + @Override + public void addSegment(Segment segment, boolean bStartNewPath) { + m_impl.addSegment(segment, bStartNewPath); + } - public void interpolateAttributes(int from_path_index, - int from_point_index, int to_path_index, int to_point_index) { - m_impl.interpolateAttributes(from_path_index, from_point_index, - to_path_index, to_point_index); - } + public void interpolateAttributes(int from_path_index, + int from_point_index, int to_path_index, int to_point_index) { + m_impl.interpolateAttributes(from_path_index, from_point_index, + to_path_index, to_point_index); + } - public void interpolateAttributes(int semantics, int from_path_index, - int from_point_index, int to_path_index, int to_point_index) { - m_impl.interpolateAttributesForSemantics(semantics, from_path_index, - from_point_index, to_path_index, to_point_index); - } + public void interpolateAttributes(int semantics, int from_path_index, + int from_point_index, int to_path_index, int to_point_index) { + m_impl.interpolateAttributesForSemantics(semantics, from_path_index, + from_point_index, to_path_index, to_point_index); + } } diff --git a/src/main/java/com/esri/core/geometry/ProgressTracker.java b/src/main/java/com/esri/core/geometry/ProgressTracker.java index 9f1b9f1f..94c77578 100644 --- a/src/main/java/com/esri/core/geometry/ProgressTracker.java +++ b/src/main/java/com/esri/core/geometry/ProgressTracker.java @@ -27,22 +27,22 @@ * A callback to provide progress and cancel tracking mechanism for lengthy operation. */ public abstract class ProgressTracker { - /** - * Periodically called by a lengthy operation to check if the caller requested to cancel. - * - * @param step The current step of the operation. - * @param totalExpectedSteps is the number of steps the operation is expects to complete its task. - * @return true, if the operation can continue. Returns False, when the operation has to terminate due to a user cancelation. - */ - public abstract boolean progress(int step, int totalExpectedSteps); + /** + * Periodically called by a lengthy operation to check if the caller requested to cancel. + * + * @param step The current step of the operation. + * @param totalExpectedSteps is the number of steps the operation is expects to complete its task. + * @return true, if the operation can continue. Returns False, when the operation has to terminate due to a user cancelation. + */ + public abstract boolean progress(int step, int totalExpectedSteps); - /** - * Checks the tracker and throws UserCancelException if tracker is not null and progress returns false - * - * @param tracker can be null, then the method does nothing. - */ - public static void checkAndThrow(ProgressTracker tracker) { - if (tracker != null && !tracker.progress(-1, -1)) - throw new UserCancelException(); - } + /** + * Checks the tracker and throws UserCancelException if tracker is not null and progress returns false + * + * @param tracker can be null, then the method does nothing. + */ + public static void checkAndThrow(ProgressTracker tracker) { + if (tracker != null && !tracker.progress(-1, -1)) + throw new UserCancelException(); + } } diff --git a/src/main/java/com/esri/core/geometry/Projecter.java b/src/main/java/com/esri/core/geometry/Projecter.java index 06f42657..bcb80b30 100644 --- a/src/main/java/com/esri/core/geometry/Projecter.java +++ b/src/main/java/com/esri/core/geometry/Projecter.java @@ -6,151 +6,151 @@ * Created by davidraleigh on 5/12/17. */ class Projecter { - static { - System.loadLibrary("proj"); - } - - public static int transform(ProjectionTransformation projectionTransformation, Point[] pointsIn, - int count, Point[] pointsOut) throws org.proj4.PJException { - if (pointsIn[0].hasZ()) - return __transform3D(projectionTransformation, pointsIn, count, pointsOut); - return __transform2D(projectionTransformation, pointsIn, count, pointsOut); - } - - private static int __transform2D(ProjectionTransformation projectionTransformation, - Point[] pointsIn, - int count, - Point[] pointsOut) throws org.proj4.PJException { - double[] coordsIn = new double[pointsIn.length * 2]; - for (int i = 0; i < pointsIn.length; i++) { - coordsIn[i * 2] = pointsIn[i].getX(); - coordsIn[i * 2 + 1] = pointsIn[i].getY(); - } - - Projecter.transform(projectionTransformation, coordsIn, false); - for (int i = 0; i < pointsOut.length; i++) { - pointsOut[i].setX(coordsIn[i * 2]); - pointsOut[i].setY(coordsIn[i * 2 + 1]); - } - - return 0; - } - - private static int __transform3D(ProjectionTransformation projectionTransformation, - Point[] pointsIn, - int count, - Point[] pointsOut) throws org.proj4.PJException { - double[] coordsIn = new double[pointsIn.length * 3]; - for (int i = 0; i < pointsIn.length; i++) { - coordsIn[i * 2] = pointsIn[i].getX(); - coordsIn[i * 2 + 1] = pointsIn[i].getY(); - coordsIn[i * 2 + 2] = pointsIn[i].getZ(); - } - - Projecter.transform(projectionTransformation, coordsIn, true); - for (int i = 0; i < pointsOut.length; i++) { - pointsOut[i].setX(coordsIn[i * 2]); - pointsOut[i].setY(coordsIn[i * 2 + 1]); - pointsOut[i].setZ(coordsIn[i * 2 + 2]); - } - - return 0; - } - - public static double[] transform(ProjectionTransformation projectionTransformation, - double[] coordsSrc, - boolean hasZ) throws org.proj4.PJException { - int n = 2; - if (hasZ) - n = 3; - - projectionTransformation.getFromProj().transform(projectionTransformation.getToProj(), n, coordsSrc, 0, coordsSrc.length / n); - return coordsSrc; - } - - static Geometry project(Geometry geometry, - ProjectionTransformation projectionTransformation, - ProgressTracker progressTracker) { - if (geometry.isEmpty()) { - return geometry; - } - - if (projectionTransformation.m_fromSpatialReference == null || projectionTransformation.m_toSpatialReference == null) { - throw new GeometryException("From and To Spatial references required to Project Geometry"); - } - // TODO check that all project methods no longer use 'new Geometry' - // TODO maybe push copy down to each geometry type? Envelope shouldn't create copy, right? - // TODO is clipping creating a new cloned geometry? Should there should be a check so that there aren't too many unnecessary clones - Geometry result = geometry.copy(); - try { - switch (geometry.getType()) { - case Unknown: - break; - case Point: - result = projectPoint(result, projectionTransformation, progressTracker); - break; - case Line: - break; - case Envelope: - result = projectEnvelope(result, projectionTransformation, progressTracker); - break; - case MultiPoint: - result = projectMultiPoint(result, projectionTransformation, progressTracker); - break; - case Polyline: - result = projectPolyline(result, projectionTransformation, progressTracker); - break; - case Polygon: - result = projectPolygon(result, projectionTransformation, progressTracker); - break; - } - } catch (PJException e) { - throw new GeometryException(String.format("Proj4 projection exception:\n{}\n{}", e.getLocalizedMessage(), e.getStackTrace())); - } - - return result; - } - - static Geometry clipGeometry(Geometry geometry, ProjectionTransformation projectionTransformation, ProgressTracker progressTracker) { - // TODO implement a real horizon - if (projectionTransformation.m_fromSpatialReference.getCoordinateSystemType() == SpatialReference.CoordinateSystemType.GEOGRAPHIC) { - // Fold Geometries into a space that ranges from -180 - 180 - Geometry folded = OperatorProjectLocal.foldInto360Range(geometry, projectionTransformation.m_fromSpatialReference); - - // Cut geometries at horizon - - // union rings - return folded; - } - - return geometry; - } - - static Geometry projectPoint(Geometry geometry, - ProjectionTransformation projectionTransformation, - ProgressTracker progressTracker) throws org.proj4.PJException { - geometry = clipGeometry(geometry, projectionTransformation, progressTracker); - Point outpoint = new Point(); - // TODO clean this idea up - Point[] outputs = {outpoint}; - Point[] inputs = {(Point) geometry}; - transform(projectionTransformation, inputs, 1, outputs); - // TODO setDirtyFlag? - return outputs[0]; - } - - static Geometry projectMultiPoint(Geometry geometry, - ProjectionTransformation projectionTransformation, - ProgressTracker progressTracker) throws org.proj4.PJException { - MultiPoint multiPoint = (MultiPoint) clipGeometry(geometry, projectionTransformation, progressTracker); - - int pointCount = multiPoint.getPointCount(); - MultiVertexGeometryImpl multiVertexGeometry = (MultiVertexGeometryImpl) multiPoint._getImpl(); - - AttributeStreamOfDbl xyPositions = (AttributeStreamOfDbl) multiVertexGeometry.getAttributeStreamRef(0); - // TODO check that there isn't a way for grabbing xyzPositions - transform(projectionTransformation, xyPositions.m_buffer, false); - multiVertexGeometry._setDirtyFlag(DirtyFlags.dirtyAll, true); + static { + System.loadLibrary("proj"); + } + + public static int transform(ProjectionTransformation projectionTransformation, Point[] pointsIn, + int count, Point[] pointsOut) throws org.proj4.PJException { + if (pointsIn[0].hasZ()) + return __transform3D(projectionTransformation, pointsIn, count, pointsOut); + return __transform2D(projectionTransformation, pointsIn, count, pointsOut); + } + + private static int __transform2D(ProjectionTransformation projectionTransformation, + Point[] pointsIn, + int count, + Point[] pointsOut) throws org.proj4.PJException { + double[] coordsIn = new double[pointsIn.length * 2]; + for (int i = 0; i < pointsIn.length; i++) { + coordsIn[i * 2] = pointsIn[i].getX(); + coordsIn[i * 2 + 1] = pointsIn[i].getY(); + } + + Projecter.transform(projectionTransformation, coordsIn, false); + for (int i = 0; i < pointsOut.length; i++) { + pointsOut[i].setX(coordsIn[i * 2]); + pointsOut[i].setY(coordsIn[i * 2 + 1]); + } + + return 0; + } + + private static int __transform3D(ProjectionTransformation projectionTransformation, + Point[] pointsIn, + int count, + Point[] pointsOut) throws org.proj4.PJException { + double[] coordsIn = new double[pointsIn.length * 3]; + for (int i = 0; i < pointsIn.length; i++) { + coordsIn[i * 2] = pointsIn[i].getX(); + coordsIn[i * 2 + 1] = pointsIn[i].getY(); + coordsIn[i * 2 + 2] = pointsIn[i].getZ(); + } + + Projecter.transform(projectionTransformation, coordsIn, true); + for (int i = 0; i < pointsOut.length; i++) { + pointsOut[i].setX(coordsIn[i * 2]); + pointsOut[i].setY(coordsIn[i * 2 + 1]); + pointsOut[i].setZ(coordsIn[i * 2 + 2]); + } + + return 0; + } + + public static double[] transform(ProjectionTransformation projectionTransformation, + double[] coordsSrc, + boolean hasZ) throws org.proj4.PJException { + int n = 2; + if (hasZ) + n = 3; + + projectionTransformation.getFromProj().transform(projectionTransformation.getToProj(), n, coordsSrc, 0, coordsSrc.length / n); + return coordsSrc; + } + + static Geometry project(Geometry geometry, + ProjectionTransformation projectionTransformation, + ProgressTracker progressTracker) { + if (geometry.isEmpty()) { + return geometry; + } + + if (projectionTransformation.m_fromSpatialReference == null || projectionTransformation.m_toSpatialReference == null) { + throw new GeometryException("From and To Spatial references required to Project Geometry"); + } + // TODO check that all project methods no longer use 'new Geometry' + // TODO maybe push copy down to each geometry type? Envelope shouldn't create copy, right? + // TODO is clipping creating a new cloned geometry? Should there should be a check so that there aren't too many unnecessary clones + Geometry result = geometry.copy(); + try { + switch (geometry.getType()) { + case Unknown: + break; + case Point: + result = projectPoint(result, projectionTransformation, progressTracker); + break; + case Line: + break; + case Envelope: + result = projectEnvelope(result, projectionTransformation, progressTracker); + break; + case MultiPoint: + result = projectMultiPoint(result, projectionTransformation, progressTracker); + break; + case Polyline: + result = projectPolyline(result, projectionTransformation, progressTracker); + break; + case Polygon: + result = projectPolygon(result, projectionTransformation, progressTracker); + break; + } + } catch (PJException e) { + throw new GeometryException(String.format("Proj4 projection exception:\n{}\n{}", e.getLocalizedMessage(), e.getStackTrace())); + } + + return result; + } + + static Geometry clipGeometry(Geometry geometry, ProjectionTransformation projectionTransformation, ProgressTracker progressTracker) { + // TODO implement a real horizon + if (projectionTransformation.m_fromSpatialReference.getCoordinateSystemType() == SpatialReference.CoordinateSystemType.GEOGRAPHIC) { + // Fold Geometries into a space that ranges from -180 - 180 + Geometry folded = OperatorProjectLocal.foldInto360Range(geometry, projectionTransformation.m_fromSpatialReference); + + // Cut geometries at horizon + + // union rings + return folded; + } + + return geometry; + } + + static Geometry projectPoint(Geometry geometry, + ProjectionTransformation projectionTransformation, + ProgressTracker progressTracker) throws org.proj4.PJException { + geometry = clipGeometry(geometry, projectionTransformation, progressTracker); + Point outpoint = new Point(); + // TODO clean this idea up + Point[] outputs = {outpoint}; + Point[] inputs = {(Point) geometry}; + transform(projectionTransformation, inputs, 1, outputs); + // TODO setDirtyFlag? + return outputs[0]; + } + + static Geometry projectMultiPoint(Geometry geometry, + ProjectionTransformation projectionTransformation, + ProgressTracker progressTracker) throws org.proj4.PJException { + MultiPoint multiPoint = (MultiPoint) clipGeometry(geometry, projectionTransformation, progressTracker); + + int pointCount = multiPoint.getPointCount(); + MultiVertexGeometryImpl multiVertexGeometry = (MultiVertexGeometryImpl) multiPoint._getImpl(); + + AttributeStreamOfDbl xyPositions = (AttributeStreamOfDbl) multiVertexGeometry.getAttributeStreamRef(0); + // TODO check that there isn't a way for grabbing xyzPositions + transform(projectionTransformation, xyPositions.m_buffer, false); + multiVertexGeometry._setDirtyFlag(DirtyFlags.dirtyAll, true); // AttributeStreamOfDbl attributeStreamOfDbl = new AttributeStreamOfDbl(pointCount * 2); // attributeStreamOfDbl.writeRange(0, pointCount * 2, output, 0, true); // @@ -160,23 +160,23 @@ static Geometry projectMultiPoint(Geometry geometry, // multiVertexGeometryOut.setAttributeStreamRef(0, attributeStreamOfDbl); // multiVertexGeometryOut._resizeImpl(pointCount); // multiPointOut.resize(pointCount); - multiVertexGeometry._updateAllDirtyIntervals(true); + multiVertexGeometry._updateAllDirtyIntervals(true); - return multiPoint; - } + return multiPoint; + } - static Geometry projectPolyline(Geometry geometry, - ProjectionTransformation projectionTransformation, - ProgressTracker progressTracker) throws org.proj4.PJException { - Polyline polyline = (Polyline) clipGeometry(geometry, projectionTransformation, progressTracker); + static Geometry projectPolyline(Geometry geometry, + ProjectionTransformation projectionTransformation, + ProgressTracker progressTracker) throws org.proj4.PJException { + Polyline polyline = (Polyline) clipGeometry(geometry, projectionTransformation, progressTracker); - int pointCount = polyline.getPointCount(); - MultiVertexGeometryImpl multiVertexGeometry = (MultiVertexGeometryImpl) polyline._getImpl(); + int pointCount = polyline.getPointCount(); + MultiVertexGeometryImpl multiVertexGeometry = (MultiVertexGeometryImpl) polyline._getImpl(); - AttributeStreamOfDbl xyPositions = (AttributeStreamOfDbl) multiVertexGeometry.getAttributeStreamRef(0); - // TODO check that there isn't a way for grabbing xyzPositions - transform(projectionTransformation, xyPositions.m_buffer, false); - multiVertexGeometry._setDirtyFlag(DirtyFlags.dirtyAll, true); + AttributeStreamOfDbl xyPositions = (AttributeStreamOfDbl) multiVertexGeometry.getAttributeStreamRef(0); + // TODO check that there isn't a way for grabbing xyzPositions + transform(projectionTransformation, xyPositions.m_buffer, false); + multiVertexGeometry._setDirtyFlag(DirtyFlags.dirtyAll, true); // AttributeStreamOfDbl attributeStreamOfDbl = new AttributeStreamOfDbl(pointCount * 2); // attributeStreamOfDbl.writeRange(0, pointCount * 2, output, 0, true); @@ -185,22 +185,22 @@ static Geometry projectPolyline(Geometry geometry, // // multiVertexGeometryOut.setAttributeStreamRef(0, attributeStreamOfDbl); // multiVertexGeometryOut._resizeImpl(pointCount); - multiVertexGeometry._updateAllDirtyIntervals(true); + multiVertexGeometry._updateAllDirtyIntervals(true); - return polyline; - } + return polyline; + } - static Geometry projectPolygon(Geometry geometry, - ProjectionTransformation projectionTransformation, - ProgressTracker progressTracker) throws org.proj4.PJException { - Polygon polygon = (Polygon) clipGeometry(geometry, projectionTransformation, progressTracker); + static Geometry projectPolygon(Geometry geometry, + ProjectionTransformation projectionTransformation, + ProgressTracker progressTracker) throws org.proj4.PJException { + Polygon polygon = (Polygon) clipGeometry(geometry, projectionTransformation, progressTracker); - MultiVertexGeometryImpl multiVertexGeometry = (MultiVertexGeometryImpl) polygon._getImpl(); + MultiVertexGeometryImpl multiVertexGeometry = (MultiVertexGeometryImpl) polygon._getImpl(); - AttributeStreamOfDbl xyPositions = (AttributeStreamOfDbl) multiVertexGeometry.getAttributeStreamRef(0); - // TODO check that there isn't a way for grabbing xyzPositions - transform(projectionTransformation, xyPositions.m_buffer, false); - multiVertexGeometry._setDirtyFlag(DirtyFlags.dirtyAll, true); + AttributeStreamOfDbl xyPositions = (AttributeStreamOfDbl) multiVertexGeometry.getAttributeStreamRef(0); + // TODO check that there isn't a way for grabbing xyzPositions + transform(projectionTransformation, xyPositions.m_buffer, false); + multiVertexGeometry._setDirtyFlag(DirtyFlags.dirtyAll, true); // AttributeStreamOfDbl attributeStreamOfDbl = new AttributeStreamOfDbl(pointCount * 2); // attributeStreamOfDbl.writeRange(0, pointCount * 2, output, 0, true); // @@ -209,18 +209,18 @@ static Geometry projectPolygon(Geometry geometry, // // multiVertexGeometryOut.setAttributeStreamRef(0, attributeStreamOfDbl); // multiVertexGeometryOut._resizeImpl(pointCount); - multiVertexGeometry._updateAllDirtyIntervals(true); - return polygon; - } - - static Geometry projectEnvelope(Geometry geometry, - ProjectionTransformation projectionTransformation, - ProgressTracker progressTracker) throws org.proj4.PJException { - Envelope envelope = (Envelope) geometry; - // TODO how to properly copy envelope into polygon - Polygon polygon = new Polygon(); - polygon.addEnvelope(envelope, false); - - return projectPolygon(polygon, projectionTransformation, progressTracker); - } + multiVertexGeometry._updateAllDirtyIntervals(true); + return polygon; + } + + static Geometry projectEnvelope(Geometry geometry, + ProjectionTransformation projectionTransformation, + ProgressTracker progressTracker) throws org.proj4.PJException { + Envelope envelope = (Envelope) geometry; + // TODO how to properly copy envelope into polygon + Polygon polygon = new Polygon(); + polygon.addEnvelope(envelope, false); + + return projectPolygon(polygon, projectionTransformation, progressTracker); + } } diff --git a/src/main/java/com/esri/core/geometry/ProjectionTransformation.java b/src/main/java/com/esri/core/geometry/ProjectionTransformation.java index 625723eb..7c946b44 100644 --- a/src/main/java/com/esri/core/geometry/ProjectionTransformation.java +++ b/src/main/java/com/esri/core/geometry/ProjectionTransformation.java @@ -28,31 +28,36 @@ //This is a stub public class ProjectionTransformation { - SpatialReference m_fromSpatialReference; - SpatialReference m_toSpatialReference; - // TODO maybe cache the PJ objects? - - public ProjectionTransformation(SpatialReference fromSpatialReference, SpatialReference toSpatialReference) { - m_fromSpatialReference = fromSpatialReference; - m_toSpatialReference = toSpatialReference; - } - - public ProjectionTransformation getReverse() { - return new ProjectionTransformation(m_toSpatialReference, m_fromSpatialReference); - } - - PJ getFromProj() { - return ((SpatialReferenceImpl)m_fromSpatialReference).getPJ(); - } - - public SpatialReference getFrom() { return m_fromSpatialReference; } - public SpatialReference getTo() { return m_toSpatialReference; } - - PJ getToProj() { - return ((SpatialReferenceImpl)m_toSpatialReference).getPJ(); - } - - public static ProjectionTransformation getEqualArea(Geometry geometry, SpatialReference spatialReference) { - return new ProjectionTransformation(spatialReference, SpatialReference.createEqualArea(geometry, spatialReference)); - } + SpatialReference m_fromSpatialReference; + SpatialReference m_toSpatialReference; + // TODO maybe cache the PJ objects? + + public ProjectionTransformation(SpatialReference fromSpatialReference, SpatialReference toSpatialReference) { + m_fromSpatialReference = fromSpatialReference; + m_toSpatialReference = toSpatialReference; + } + + public ProjectionTransformation getReverse() { + return new ProjectionTransformation(m_toSpatialReference, m_fromSpatialReference); + } + + PJ getFromProj() { + return ((SpatialReferenceImpl) m_fromSpatialReference).getPJ(); + } + + public SpatialReference getFrom() { + return m_fromSpatialReference; + } + + public SpatialReference getTo() { + return m_toSpatialReference; + } + + PJ getToProj() { + return ((SpatialReferenceImpl) m_toSpatialReference).getPJ(); + } + + public static ProjectionTransformation getEqualArea(Geometry geometry, SpatialReference spatialReference) { + return new ProjectionTransformation(spatialReference, SpatialReference.createEqualArea(geometry, spatialReference)); + } } diff --git a/src/main/java/com/esri/core/geometry/Proximity2DResult.java b/src/main/java/com/esri/core/geometry/Proximity2DResult.java index 92c348cd..27a84a92 100644 --- a/src/main/java/com/esri/core/geometry/Proximity2DResult.java +++ b/src/main/java/com/esri/core/geometry/Proximity2DResult.java @@ -29,104 +29,104 @@ * the distance from a given point to the nearest point on another geometry. */ public class Proximity2DResult { - Point2D m_coordinate = new Point2D(); - int m_vertexIndex; - double m_distance; - int m_info; - - /** - * Sets the right_side info to true or false. - * - * @param bRight Whether the nearest coordinate is to the right or left of the - * geometry. - */ - public void setRightSide(boolean bRight) { - if (bRight) - m_info |= (int) OperatorProximity2D.ProxResultInfo.rightSide; - else - m_info &= ~(int) OperatorProximity2D.ProxResultInfo.rightSide; - } - - /** - * Returns TRUE if the Proximity2DResult is empty. This only happens if the - * Geometry passed to the Proximity operator is empty. - */ - public boolean isEmpty() { - return m_vertexIndex < 0; - } - - /** - * Returns the closest coordinate for - * OperatorProximity2D.getNearestCoordinate or the vertex coordinates for - * the OperatorProximity2D.getNearestVertex and - * OperatorProximity2D.getNearestVertices. - */ - public Point getCoordinate() { - if (isEmpty()) - throw new GeometryException("invalid call"); - - return new Point(m_coordinate.x, m_coordinate.y); - } - - /** - * Returns the vertex index. For OperatorProximity2D.getNearestCoordinate - * the behavior is: When the input is a polygon or an envelope and the - * bTestPolygonInterior is true, the value is zero. When the input is a - * polygon or an Envelope and the bTestPolygonInterior is false, the value - * is the start vertex index of a segment with the closest coordinate. When - * the input is a polyline, the value is the start vertex index of a segment - * with the closest coordinate. When the input is a point, the value is 0. - * When the input is a multipoint, the value is the closest vertex. - */ - public int getVertexIndex() { - if (isEmpty()) - throw new GeometryException("invalid call"); - - return m_vertexIndex; - } - - /** - * Returns the distance to the closest vertex or coordinate. - */ - public double getDistance() { - if (isEmpty()) - throw new GeometryException("invalid call"); - - return m_distance; - } - - /** - * Returns true if the closest coordinate is to the right of the MultiPath. - */ - public boolean isRightSide() { - return (m_info & (int) OperatorProximity2D.ProxResultInfo.rightSide) != 0; - } - - void _setParams(double x, double y, int vertexIndex, double distance) { - m_coordinate.x = x; - m_coordinate.y = y; - m_vertexIndex = vertexIndex; - m_distance = distance; - } - - // static int _compare(Proximity2DResult v1, Proximity2DResult v2) - // { - // if (v1.m_distance < v2.m_distance) - // return -1; - // if (v1.m_distance == v2.m_distance) - // return 0; - // - // return 1; - // } - - Proximity2DResult() { - m_vertexIndex = -1; - } - - Proximity2DResult(Point2D coordinate, int vertexIndex, double distance) { - m_coordinate.setCoords(coordinate); - m_vertexIndex = vertexIndex; - m_distance = distance; - m_info = 0; - } + Point2D m_coordinate = new Point2D(); + int m_vertexIndex; + double m_distance; + int m_info; + + /** + * Sets the right_side info to true or false. + * + * @param bRight Whether the nearest coordinate is to the right or left of the + * geometry. + */ + public void setRightSide(boolean bRight) { + if (bRight) + m_info |= (int) OperatorProximity2D.ProxResultInfo.rightSide; + else + m_info &= ~(int) OperatorProximity2D.ProxResultInfo.rightSide; + } + + /** + * Returns TRUE if the Proximity2DResult is empty. This only happens if the + * Geometry passed to the Proximity operator is empty. + */ + public boolean isEmpty() { + return m_vertexIndex < 0; + } + + /** + * Returns the closest coordinate for + * OperatorProximity2D.getNearestCoordinate or the vertex coordinates for + * the OperatorProximity2D.getNearestVertex and + * OperatorProximity2D.getNearestVertices. + */ + public Point getCoordinate() { + if (isEmpty()) + throw new GeometryException("invalid call"); + + return new Point(m_coordinate.x, m_coordinate.y); + } + + /** + * Returns the vertex index. For OperatorProximity2D.getNearestCoordinate + * the behavior is: When the input is a polygon or an envelope and the + * bTestPolygonInterior is true, the value is zero. When the input is a + * polygon or an Envelope and the bTestPolygonInterior is false, the value + * is the start vertex index of a segment with the closest coordinate. When + * the input is a polyline, the value is the start vertex index of a segment + * with the closest coordinate. When the input is a point, the value is 0. + * When the input is a multipoint, the value is the closest vertex. + */ + public int getVertexIndex() { + if (isEmpty()) + throw new GeometryException("invalid call"); + + return m_vertexIndex; + } + + /** + * Returns the distance to the closest vertex or coordinate. + */ + public double getDistance() { + if (isEmpty()) + throw new GeometryException("invalid call"); + + return m_distance; + } + + /** + * Returns true if the closest coordinate is to the right of the MultiPath. + */ + public boolean isRightSide() { + return (m_info & (int) OperatorProximity2D.ProxResultInfo.rightSide) != 0; + } + + void _setParams(double x, double y, int vertexIndex, double distance) { + m_coordinate.x = x; + m_coordinate.y = y; + m_vertexIndex = vertexIndex; + m_distance = distance; + } + + // static int _compare(Proximity2DResult v1, Proximity2DResult v2) + // { + // if (v1.m_distance < v2.m_distance) + // return -1; + // if (v1.m_distance == v2.m_distance) + // return 0; + // + // return 1; + // } + + Proximity2DResult() { + m_vertexIndex = -1; + } + + Proximity2DResult(Point2D coordinate, int vertexIndex, double distance) { + m_coordinate.setCoords(coordinate); + m_vertexIndex = vertexIndex; + m_distance = distance; + m_info = 0; + } } diff --git a/src/main/java/com/esri/core/geometry/Proximity2DResultComparator.java b/src/main/java/com/esri/core/geometry/Proximity2DResultComparator.java index c8c35828..0404aa80 100644 --- a/src/main/java/com/esri/core/geometry/Proximity2DResultComparator.java +++ b/src/main/java/com/esri/core/geometry/Proximity2DResultComparator.java @@ -28,13 +28,13 @@ class Proximity2DResultComparator implements Comparator { - public int compare(Proximity2DResult v1, Proximity2DResult v2) { - if (v1.m_distance < v2.m_distance) - return -1; - if (v1.m_distance == v2.m_distance) - return 0; - - return 1; - } + public int compare(Proximity2DResult v1, Proximity2DResult v2) { + if (v1.m_distance < v2.m_distance) + return -1; + if (v1.m_distance == v2.m_distance) + return 0; + + return 1; + } } diff --git a/src/main/java/com/esri/core/geometry/PtSrlzr.java b/src/main/java/com/esri/core/geometry/PtSrlzr.java index 5d9435f4..68dd1aae 100644 --- a/src/main/java/com/esri/core/geometry/PtSrlzr.java +++ b/src/main/java/com/esri/core/geometry/PtSrlzr.java @@ -29,60 +29,60 @@ //This is a writeReplace class for Point public class PtSrlzr implements Serializable { - private static final long serialVersionUID = 1L; - double[] attribs; - int descriptionBitMask; + private static final long serialVersionUID = 1L; + double[] attribs; + int descriptionBitMask; - public Object readResolve() throws ObjectStreamException { - Point point = null; - try { - VertexDescription vd = VertexDescriptionDesignerImpl - .getVertexDescription(descriptionBitMask); - point = new Point(vd); - if (attribs != null) { - point.setXY(attribs[0], attribs[1]); - int index = 2; - for (int i = 1, n = vd.getAttributeCount(); i < n; i++) { - int semantics = vd.getSemantics(i); - int comps = VertexDescription.getComponentCount(semantics); - for (int ord = 0; ord < comps; ord++) { - point.setAttribute(semantics, ord, attribs[index++]); - } - } - } - } catch (Exception ex) { - throw new InvalidObjectException("Cannot read geometry from stream"); - } + public Object readResolve() throws ObjectStreamException { + Point point = null; + try { + VertexDescription vd = VertexDescriptionDesignerImpl + .getVertexDescription(descriptionBitMask); + point = new Point(vd); + if (attribs != null) { + point.setXY(attribs[0], attribs[1]); + int index = 2; + for (int i = 1, n = vd.getAttributeCount(); i < n; i++) { + int semantics = vd.getSemantics(i); + int comps = VertexDescription.getComponentCount(semantics); + for (int ord = 0; ord < comps; ord++) { + point.setAttribute(semantics, ord, attribs[index++]); + } + } + } + } catch (Exception ex) { + throw new InvalidObjectException("Cannot read geometry from stream"); + } - return point; - } + return point; + } - public void setGeometryByValue(Point point) throws ObjectStreamException { - try { - attribs = null; - if (point == null) { - descriptionBitMask = 1; - } + public void setGeometryByValue(Point point) throws ObjectStreamException { + try { + attribs = null; + if (point == null) { + descriptionBitMask = 1; + } - VertexDescription vd = point.getDescription(); - descriptionBitMask = vd.m_semanticsBitArray; - if (point.isEmpty()) { - return; - } + VertexDescription vd = point.getDescription(); + descriptionBitMask = vd.m_semanticsBitArray; + if (point.isEmpty()) { + return; + } - attribs = new double[vd.getTotalComponentCount()]; - attribs[0] = point.getX(); - attribs[1] = point.getY(); - int index = 2; - for (int i = 1, n = vd.getAttributeCount(); i < n; i++) { - int semantics = vd.getSemantics(i); - int comps = VertexDescription.getComponentCount(semantics); - for (int ord = 0; ord < comps; ord++) { - attribs[index++] = point.getAttributeAsDbl(semantics, ord); - } - } - } catch (Exception ex) { - throw new InvalidObjectException("Cannot serialize this geometry"); - } - } + attribs = new double[vd.getTotalComponentCount()]; + attribs[0] = point.getX(); + attribs[1] = point.getY(); + int index = 2; + for (int i = 1, n = vd.getAttributeCount(); i < n; i++) { + int semantics = vd.getSemantics(i); + int comps = VertexDescription.getComponentCount(semantics); + for (int ord = 0; ord < comps; ord++) { + attribs[index++] = point.getAttributeAsDbl(semantics, ord); + } + } + } catch (Exception ex) { + throw new InvalidObjectException("Cannot serialize this geometry"); + } + } } diff --git a/src/main/java/com/esri/core/geometry/QuadTree.java b/src/main/java/com/esri/core/geometry/QuadTree.java index e236826b..0b4a4945 100644 --- a/src/main/java/com/esri/core/geometry/QuadTree.java +++ b/src/main/java/com/esri/core/geometry/QuadTree.java @@ -1,5 +1,5 @@ /* - Copyright 1995-2015 Esri + Copyright 1995-2018 Esri Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -25,316 +25,320 @@ package com.esri.core.geometry; -public class QuadTree { - public static final class QuadTreeIterator { - /** - * Resets the iterator to an starting state on the QuadTree. If the - * input Geometry is a Line segment, then the query will be the segment. - * Otherwise the query will be the Envelope2D bounding the Geometry. - * \param query The Geometry used for the query. - * \param tolerance The tolerance used for the intersection tests. - */ - public void resetIterator(Geometry query, double tolerance) { - if (!m_b_sorted) - ((QuadTreeImpl.QuadTreeIteratorImpl) m_impl).resetIterator(query, tolerance); - else - ((QuadTreeImpl.QuadTreeSortedIteratorImpl) m_impl).resetIterator(query, tolerance); - } - - /** - * Resets the iterator to a starting state on the QuadTree using the - * input Envelope2D as the query. - * \param query The Envelope2D used for the query. - * \param tolerance The tolerance used for the intersection - * tests. - */ - public void resetIterator(Envelope2D query, double tolerance) { - if (!m_b_sorted) - ((QuadTreeImpl.QuadTreeIteratorImpl) m_impl).resetIterator(query, tolerance); - else - ((QuadTreeImpl.QuadTreeSortedIteratorImpl) m_impl).resetIterator(query, tolerance); - } - - /** - * Moves the iterator to the next Element_handle and returns the - * Element_handle. - */ - public int next() { - if (!m_b_sorted) - return ((QuadTreeImpl.QuadTreeIteratorImpl) m_impl).next(); - else - return ((QuadTreeImpl.QuadTreeSortedIteratorImpl) m_impl).next(); - } - - /** - * Returns a void* to the impl class. - */ - Object getImpl_() { - return m_impl; - } - - // Creates an iterator on the input QuadTreeImpl. The query will be - // the Envelope2D bounding the input Geometry. - private QuadTreeIterator(Object obj, boolean bSorted) { - - m_impl = obj; - m_b_sorted = bSorted; - } - - private Object m_impl; - private boolean m_b_sorted; - } - - /** - * Creates a QuadTree with the root having the extent of the input - * Envelope2D, and height of the input height, where the root starts at height 0. - * \param extent The extent of the QuadTree. - * \param height The max height of the QuadTree. - */ - public QuadTree(Envelope2D extent, int height) { - m_impl = new QuadTreeImpl(extent, height); - } - - /** - * Creates a QuadTree with the root having the extent of the input Envelope2D, and height of the input height, where the root starts at height 0. - * \param extent The extent of the QuadTreeImpl. - * \param height The max height of the QuadTreeImpl. - * \param bStoreDuplicates Put true to place elements deeper into the quad tree at intesecting quads, duplicates will be stored. Put false to only place elements into quads that can contain it.. - */ - public QuadTree(Envelope2D extent, int height, boolean bStoreDuplicates) { - m_impl = new QuadTreeImpl(extent, height, bStoreDuplicates); - } - - /** - * Inserts the element and bounding_box into the QuadTree. Note that a copy - * will me made of the input bounding_box. Note that this will invalidate - * any active iterator on the QuadTree. Returns an Element_handle - * corresponding to the element and bounding_box. - * \param element The element of the Geometry to be inserted. - * \param bounding_box The bounding_box of - * the Geometry to be inserted. - */ - public int insert(int element, Envelope2D boundingBox) { - return m_impl.insert(element, boundingBox); - } - - /** - * Inserts the element and bounding_box into the QuadTree at the given - * quad_handle. Note that a copy will me made of the input bounding_box. - * Note that this will invalidate any active iterator on the QuadTree. - * Returns an Element_handle corresponding to the element and bounding_box. - * \param element The element of the Geometry to be inserted. - * \param bounding_box The bounding_box of the Geometry to be inserted. - * \param hint_index A handle used as a hint where to place the element. This can - * be a handle obtained from a previous insertion and is useful on data - * having strong locality such as segments of a Polygon. - */ - public int insert(int element, Envelope2D boundingBox, int hintIndex) { - return m_impl.insert(element, boundingBox, hintIndex); - } - - /** - * Removes the element and bounding_box at the given element_handle. Note - * that this will invalidate any active iterator on the QuadTree. - * \param element_handle The handle corresponding to the element and bounding_box - * to be removed. - */ - public void removeElement(int elementHandle) { - m_impl.removeElement(elementHandle); - } - - /** - * Returns the element at the given element_handle. - * \param element_handle The handle corresponding to the element to be retrieved. - */ - public int getElement(int elementHandle) { - return m_impl.getElement(elementHandle); - } - - /** - * Returns the element extent at the given element_handle. - * \param element_handle The handle corresponding to the element extent to be retrieved. - */ - public Envelope2D getElementExtent(int elementHandle) { - return m_impl.getElementExtent(elementHandle); - } - - /** - * Returns the extent of all elements in the quad tree. - */ - public Envelope2D getDataExtent() { - return m_impl.getDataExtent(); - } - - /** - * Returns the extent of the quad tree. - */ - public Envelope2D getQuadTreeExtent() { - return m_impl.getQuadTreeExtent(); - } - - /** - * Returns the number of elements in the subtree rooted at the given quad_handle. - * \param quad_handle The handle corresponding to the quad. - */ - public int getSubTreeElementCount(int quadHandle) { - return m_impl.getSubTreeElementCount(quadHandle); - } - - /** - * Returns the number of elements contained in the subtree rooted at the given quad_handle. - * \param quad_handle The handle corresponding to the quad. - */ - public int getContainedSubTreeElementCount(int quadHandle) { - return m_impl.getContainedSubTreeElementCount(quadHandle); - } - - /** - * Returns the number of elements in the quad tree that intersect the qiven query. Some elements may be duplicated if the quad tree stores duplicates. - * \param query The Envelope2D used for the query. - * \param tolerance The tolerance used for the intersection tests. - * \param max_count If the intersection count becomes greater than or equal to the max_count, then max_count is returned. - */ - public int getIntersectionCount(Envelope2D query, double tolerance, int maxCount) { - return m_impl.getIntersectionCount(query, tolerance, maxCount); - } - - /** - * Returns true if the quad tree has data intersecting the given query. - * \param query The Envelope2D used for the query. - * \param tolerance The tolerance used for the intersection tests. - */ - public boolean hasData(Envelope2D query, double tolerance) { - return m_impl.hasData(query, tolerance); - } - - /** - * Returns the height of the quad at the given quad_handle. \param - * quad_handle The handle corresponding to the quad. - */ - public int getHeight(int quadHandle) { - return m_impl.getHeight(quadHandle); - } - - /** - * Returns the max height the quad tree can grow to. - */ - public int getMaxHeight() { - return m_impl.getMaxHeight(); - } - - /** - * Returns the extent of the quad at the given quad_handle. - * \param quad_handle The handle corresponding to the quad. - */ - public Envelope2D getExtent(int quadHandle) { - return m_impl.getExtent(quadHandle); - } - - /** - * Returns the Quad_handle of the quad containing the given element_handle. - * \param element_handle The handle corresponding to the element. - */ - public int getQuad(int elementHandle) { - return m_impl.getQuad(elementHandle); - } - - /** - * Returns the number of elements in the QuadTree. - */ - public int getElementCount() { - return m_impl.getElementCount(); - } - - /** - * Gets an iterator on the QuadTree. The query will be the Envelope2D that - * bounds the input Geometry. To reuse the existing iterator on the same - * QuadTree but with a new query, use the reset_iterator function on the - * QuadTree_iterator. - * \param query The Geometry used for the query. If the - * Geometry is a Line segment, then the query will be the segment. Otherwise - * the query will be the Envelope2D bounding the Geometry. - * \param tolerance The tolerance used for the intersection tests. - */ - public QuadTreeIterator getIterator(Geometry query, double tolerance) { - QuadTreeImpl.QuadTreeIteratorImpl iterator = m_impl.getIterator(query, tolerance); - return new QuadTreeIterator(iterator, false); - } - - /** - * Gets an iterator on the QuadTree using the input Envelope2D as the - * query. To reuse the existing iterator on the same QuadTree but with a - * new query, use the reset_iterator function on the QuadTree_iterator. - * \param query The Envelope2D used for the query. - * \param tolerance The tolerance used for the intersection tests. - */ - public QuadTreeIterator getIterator(Envelope2D query, double tolerance) { - QuadTreeImpl.QuadTreeIteratorImpl iterator = m_impl.getIterator(query, tolerance); - return new QuadTreeIterator(iterator, false); - } - - /** - * Gets an iterator on the QuadTree. - */ - public QuadTreeIterator getIterator() { - QuadTreeImpl.QuadTreeIteratorImpl iterator = m_impl.getIterator(); - return new QuadTreeIterator(iterator, false); - } - - /** - * Gets an iterator on the QuadTree. The query will be the Envelope2D that bounds the input Geometry. - * To reuse the existing iterator on the same QuadTree but with a new query, use the reset_iterator function on the QuadTree_iterator. - * \param query The Geometry used for the query. If the Geometry is a Line segment, then the query will be the segment. Otherwise the query will be the Envelope2D bounding the Geometry. - * \param tolerance The tolerance used for the intersection tests. - * \param bSorted Put true to iterate the quad tree in the order of the Element_types. - */ - public QuadTreeIterator getIterator(Geometry query, double tolerance, boolean bSorted) { - if (!bSorted) { - QuadTreeImpl.QuadTreeIteratorImpl iterator = m_impl.getIterator(query, tolerance); - return new QuadTreeIterator(iterator, false); - } else { - QuadTreeImpl.QuadTreeSortedIteratorImpl iterator = m_impl.getSortedIterator(query, tolerance); - return new QuadTreeIterator(iterator, true); - } - } - - /** - * Gets an iterator on the QuadTree using the input Envelope2D as the query. - * To reuse the existing iterator on the same QuadTree but with a new query, use the reset_iterator function on the QuadTree_iterator. - * \param query The Envelope2D used for the query. - * \param tolerance The tolerance used for the intersection tests. - * \param bSorted Put true to iterate the quad tree in the order of the Element_types. - */ - public QuadTreeIterator getIterator(Envelope2D query, double tolerance, boolean bSorted) { - if (!bSorted) { - QuadTreeImpl.QuadTreeIteratorImpl iterator = m_impl.getIterator(query, tolerance); - return new QuadTreeIterator(iterator, false); - } else { - QuadTreeImpl.QuadTreeSortedIteratorImpl iterator = m_impl.getSortedIterator(query, tolerance); - return new QuadTreeIterator(iterator, true); - } - } - - /** - * Gets an iterator on the QuadTree. - * \param bSorted Put true to iterate the quad tree in the order of the Element_types. - */ - public QuadTreeIterator getIterator(boolean bSorted) { - if (!bSorted) { - QuadTreeImpl.QuadTreeIteratorImpl iterator = m_impl.getIterator(); - return new QuadTreeIterator(iterator, false); - } else { - QuadTreeImpl.QuadTreeSortedIteratorImpl iterator = m_impl.getSortedIterator(); - return new QuadTreeIterator(iterator, true); - } - } - - /** - * Returns a void* to the impl class. - */ - Object getImpl_() { - return m_impl; - } - - private QuadTreeImpl m_impl; +import java.io.Serializable; + +public class QuadTree implements Serializable { + private static final long serialVersionUID = 1L; + + public static final class QuadTreeIterator { + /** + * Resets the iterator to an starting state on the QuadTree. If the + * input Geometry is a Line segment, then the query will be the segment. + * Otherwise the query will be the Envelope2D bounding the Geometry. + * \param query The Geometry used for the query. + * \param tolerance The tolerance used for the intersection tests. + */ + public void resetIterator(Geometry query, double tolerance) { + if (!m_b_sorted) + ((QuadTreeImpl.QuadTreeIteratorImpl) m_impl).resetIterator(query, tolerance); + else + ((QuadTreeImpl.QuadTreeSortedIteratorImpl) m_impl).resetIterator(query, tolerance); + } + + /** + * Resets the iterator to a starting state on the QuadTree using the + * input Envelope2D as the query. + * \param query The Envelope2D used for the query. + * \param tolerance The tolerance used for the intersection + * tests. + */ + public void resetIterator(Envelope2D query, double tolerance) { + if (!m_b_sorted) + ((QuadTreeImpl.QuadTreeIteratorImpl) m_impl).resetIterator(query, tolerance); + else + ((QuadTreeImpl.QuadTreeSortedIteratorImpl) m_impl).resetIterator(query, tolerance); + } + + /** + * Moves the iterator to the next Element_handle and returns the + * Element_handle. + */ + public int next() { + if (!m_b_sorted) + return ((QuadTreeImpl.QuadTreeIteratorImpl) m_impl).next(); + else + return ((QuadTreeImpl.QuadTreeSortedIteratorImpl) m_impl).next(); + } + + /** + * Returns a void* to the impl class. + */ + Object getImpl_() { + return m_impl; + } + + // Creates an iterator on the input QuadTreeImpl. The query will be + // the Envelope2D bounding the input Geometry. + private QuadTreeIterator(Object obj, boolean bSorted) { + + m_impl = obj; + m_b_sorted = bSorted; + } + + private Object m_impl; + private boolean m_b_sorted; + } + + /** + * Creates a QuadTree with the root having the extent of the input + * Envelope2D, and height of the input height, where the root starts at height 0. + * \param extent The extent of the QuadTree. + * \param height The max height of the QuadTree. + */ + public QuadTree(Envelope2D extent, int height) { + m_impl = new QuadTreeImpl(extent, height); + } + + /** + * Creates a QuadTree with the root having the extent of the input Envelope2D, and height of the input height, where the root starts at height 0. + * \param extent The extent of the QuadTreeImpl. + * \param height The max height of the QuadTreeImpl. + * \param bStoreDuplicates Put true to place elements deeper into the quad tree at intesecting quads, duplicates will be stored. Put false to only place elements into quads that can contain it.. + */ + public QuadTree(Envelope2D extent, int height, boolean bStoreDuplicates) { + m_impl = new QuadTreeImpl(extent, height, bStoreDuplicates); + } + + /** + * Inserts the element and bounding_box into the QuadTree. Note that a copy + * will me made of the input bounding_box. Note that this will invalidate + * any active iterator on the QuadTree. Returns an Element_handle + * corresponding to the element and bounding_box. + * \param element The element of the Geometry to be inserted. + * \param bounding_box The bounding_box of + * the Geometry to be inserted. + */ + public int insert(int element, Envelope2D boundingBox) { + return m_impl.insert(element, boundingBox); + } + + /** + * Inserts the element and bounding_box into the QuadTree at the given + * quad_handle. Note that a copy will me made of the input bounding_box. + * Note that this will invalidate any active iterator on the QuadTree. + * Returns an Element_handle corresponding to the element and bounding_box. + * \param element The element of the Geometry to be inserted. + * \param bounding_box The bounding_box of the Geometry to be inserted. + * \param hint_index A handle used as a hint where to place the element. This can + * be a handle obtained from a previous insertion and is useful on data + * having strong locality such as segments of a Polygon. + */ + public int insert(int element, Envelope2D boundingBox, int hintIndex) { + return m_impl.insert(element, boundingBox, hintIndex); + } + + /** + * Removes the element and bounding_box at the given element_handle. Note + * that this will invalidate any active iterator on the QuadTree. + * \param element_handle The handle corresponding to the element and bounding_box + * to be removed. + */ + public void removeElement(int elementHandle) { + m_impl.removeElement(elementHandle); + } + + /** + * Returns the element at the given element_handle. + * \param element_handle The handle corresponding to the element to be retrieved. + */ + public int getElement(int elementHandle) { + return m_impl.getElement(elementHandle); + } + + /** + * Returns the element extent at the given element_handle. + * \param element_handle The handle corresponding to the element extent to be retrieved. + */ + public Envelope2D getElementExtent(int elementHandle) { + return m_impl.getElementExtent(elementHandle); + } + + /** + * Returns the extent of all elements in the quad tree. + */ + public Envelope2D getDataExtent() { + return m_impl.getDataExtent(); + } + + /** + * Returns the extent of the quad tree. + */ + public Envelope2D getQuadTreeExtent() { + return m_impl.getQuadTreeExtent(); + } + + /** + * Returns the number of elements in the subtree rooted at the given quad_handle. + * \param quad_handle The handle corresponding to the quad. + */ + public int getSubTreeElementCount(int quadHandle) { + return m_impl.getSubTreeElementCount(quadHandle); + } + + /** + * Returns the number of elements contained in the subtree rooted at the given quad_handle. + * \param quad_handle The handle corresponding to the quad. + */ + public int getContainedSubTreeElementCount(int quadHandle) { + return m_impl.getContainedSubTreeElementCount(quadHandle); + } + + /** + * Returns the number of elements in the quad tree that intersect the qiven query. Some elements may be duplicated if the quad tree stores duplicates. + * \param query The Envelope2D used for the query. + * \param tolerance The tolerance used for the intersection tests. + * \param max_count If the intersection count becomes greater than or equal to the max_count, then max_count is returned. + */ + public int getIntersectionCount(Envelope2D query, double tolerance, int maxCount) { + return m_impl.getIntersectionCount(query, tolerance, maxCount); + } + + /** + * Returns true if the quad tree has data intersecting the given query. + * \param query The Envelope2D used for the query. + * \param tolerance The tolerance used for the intersection tests. + */ + public boolean hasData(Envelope2D query, double tolerance) { + return m_impl.hasData(query, tolerance); + } + + /** + * Returns the height of the quad at the given quad_handle. \param + * quad_handle The handle corresponding to the quad. + */ + public int getHeight(int quadHandle) { + return m_impl.getHeight(quadHandle); + } + + /** + * Returns the max height the quad tree can grow to. + */ + public int getMaxHeight() { + return m_impl.getMaxHeight(); + } + + /** + * Returns the extent of the quad at the given quad_handle. + * \param quad_handle The handle corresponding to the quad. + */ + public Envelope2D getExtent(int quadHandle) { + return m_impl.getExtent(quadHandle); + } + + /** + * Returns the Quad_handle of the quad containing the given element_handle. + * \param element_handle The handle corresponding to the element. + */ + public int getQuad(int elementHandle) { + return m_impl.getQuad(elementHandle); + } + + /** + * Returns the number of elements in the QuadTree. + */ + public int getElementCount() { + return m_impl.getElementCount(); + } + + /** + * Gets an iterator on the QuadTree. The query will be the Envelope2D that + * bounds the input Geometry. To reuse the existing iterator on the same + * QuadTree but with a new query, use the reset_iterator function on the + * QuadTree_iterator. + * \param query The Geometry used for the query. If the + * Geometry is a Line segment, then the query will be the segment. Otherwise + * the query will be the Envelope2D bounding the Geometry. + * \param tolerance The tolerance used for the intersection tests. + */ + public QuadTreeIterator getIterator(Geometry query, double tolerance) { + QuadTreeImpl.QuadTreeIteratorImpl iterator = m_impl.getIterator(query, tolerance); + return new QuadTreeIterator(iterator, false); + } + + /** + * Gets an iterator on the QuadTree using the input Envelope2D as the + * query. To reuse the existing iterator on the same QuadTree but with a + * new query, use the reset_iterator function on the QuadTree_iterator. + * \param query The Envelope2D used for the query. + * \param tolerance The tolerance used for the intersection tests. + */ + public QuadTreeIterator getIterator(Envelope2D query, double tolerance) { + QuadTreeImpl.QuadTreeIteratorImpl iterator = m_impl.getIterator(query, tolerance); + return new QuadTreeIterator(iterator, false); + } + + /** + * Gets an iterator on the QuadTree. + */ + public QuadTreeIterator getIterator() { + QuadTreeImpl.QuadTreeIteratorImpl iterator = m_impl.getIterator(); + return new QuadTreeIterator(iterator, false); + } + + /** + * Gets an iterator on the QuadTree. The query will be the Envelope2D that bounds the input Geometry. + * To reuse the existing iterator on the same QuadTree but with a new query, use the reset_iterator function on the QuadTree_iterator. + * \param query The Geometry used for the query. If the Geometry is a Line segment, then the query will be the segment. Otherwise the query will be the Envelope2D bounding the Geometry. + * \param tolerance The tolerance used for the intersection tests. + * \param bSorted Put true to iterate the quad tree in the order of the Element_types. + */ + public QuadTreeIterator getIterator(Geometry query, double tolerance, boolean bSorted) { + if (!bSorted) { + QuadTreeImpl.QuadTreeIteratorImpl iterator = m_impl.getIterator(query, tolerance); + return new QuadTreeIterator(iterator, false); + } else { + QuadTreeImpl.QuadTreeSortedIteratorImpl iterator = m_impl.getSortedIterator(query, tolerance); + return new QuadTreeIterator(iterator, true); + } + } + + /** + * Gets an iterator on the QuadTree using the input Envelope2D as the query. + * To reuse the existing iterator on the same QuadTree but with a new query, use the reset_iterator function on the QuadTree_iterator. + * \param query The Envelope2D used for the query. + * \param tolerance The tolerance used for the intersection tests. + * \param bSorted Put true to iterate the quad tree in the order of the Element_types. + */ + public QuadTreeIterator getIterator(Envelope2D query, double tolerance, boolean bSorted) { + if (!bSorted) { + QuadTreeImpl.QuadTreeIteratorImpl iterator = m_impl.getIterator(query, tolerance); + return new QuadTreeIterator(iterator, false); + } else { + QuadTreeImpl.QuadTreeSortedIteratorImpl iterator = m_impl.getSortedIterator(query, tolerance); + return new QuadTreeIterator(iterator, true); + } + } + + /** + * Gets an iterator on the QuadTree. + * \param bSorted Put true to iterate the quad tree in the order of the Element_types. + */ + public QuadTreeIterator getIterator(boolean bSorted) { + if (!bSorted) { + QuadTreeImpl.QuadTreeIteratorImpl iterator = m_impl.getIterator(); + return new QuadTreeIterator(iterator, false); + } else { + QuadTreeImpl.QuadTreeSortedIteratorImpl iterator = m_impl.getSortedIterator(); + return new QuadTreeIterator(iterator, true); + } + } + + /** + * Returns a void* to the impl class. + */ + Object getImpl_() { + return m_impl; + } + + private QuadTreeImpl m_impl; } diff --git a/src/main/java/com/esri/core/geometry/QuadTreeImpl.java b/src/main/java/com/esri/core/geometry/QuadTreeImpl.java index 092f6bbe..e9234bb5 100644 --- a/src/main/java/com/esri/core/geometry/QuadTreeImpl.java +++ b/src/main/java/com/esri/core/geometry/QuadTreeImpl.java @@ -1,5 +1,5 @@ /* - Copyright 1995-2015 Esri + Copyright 1995-2018 Esri Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -23,1251 +23,1334 @@ */ package com.esri.core.geometry; +import java.io.IOException; +import java.io.InvalidObjectException; +import java.io.ObjectStreamException; +import java.io.Serializable; import java.util.ArrayList; -class QuadTreeImpl { - static final class QuadTreeIteratorImpl { - /** - * Resets the iterator to an starting state on the Quad_tree_impl. If - * the input Geometry is a Line segment, then the query will be the - * segment. Otherwise the query will be the Envelope_2D bounding the - * Geometry. \param query The Geometry used for the query. \param - * tolerance The tolerance used for the intersection tests. \param - * tolerance The tolerance used for the intersection tests. - */ - void resetIterator(Geometry query, double tolerance) { - m_quads_stack.resize(0); - m_extents_stack.clear(); - m_current_element_handle = -1; - query.queryLooseEnvelope2D(m_query_box); - m_query_box.inflate(tolerance, tolerance); - - if (m_quad_tree.m_root != -1 && m_query_box.isIntersecting(m_quad_tree.m_extent)) { - int type = query.getType().value(); - m_b_linear = Geometry.isSegment(type); - - if (m_b_linear) { - Segment segment = (Segment) query; - m_query_start = segment.getStartXY(); - m_query_end = segment.getEndXY(); - m_tolerance = tolerance; - } else { - m_tolerance = NumberUtils.NaN(); // we don't need it - } - - m_quads_stack.add(m_quad_tree.m_root); - m_extents_stack.add(m_quad_tree.m_extent); - m_next_element_handle = m_quad_tree.get_first_element_(m_quad_tree.m_root); - } else - m_next_element_handle = -1; - } - - /** - * Resets the iterator to a starting state on the Quad_tree_impl using - * the input Envelope_2D as the query. \param query The Envelope_2D used - * for the query. \param tolerance The tolerance used for the - * intersection tests. - */ - void resetIterator(Envelope2D query, double tolerance) { - m_quads_stack.resize(0); - m_extents_stack.clear(); - m_current_element_handle = -1; - m_query_box.setCoords(query); - m_query_box.inflate(tolerance, tolerance); - m_tolerance = NumberUtils.NaN(); // we don't need it - - if (m_quad_tree.m_root != -1 && m_query_box.isIntersecting(m_quad_tree.m_extent)) { - m_quads_stack.add(m_quad_tree.m_root); - m_extents_stack.add(m_quad_tree.m_extent); - m_next_element_handle = m_quad_tree.get_first_element_(m_quad_tree.m_root); - m_b_linear = false; - } else - m_next_element_handle = -1; - } - - /** - * Moves the iterator to the next int and returns the int. - */ - int next() { - // If the node stack is empty, then we've exhausted our search - - if (m_quads_stack.size() == 0) - return -1; - - m_current_element_handle = m_next_element_handle; - - Point2D start = null; - Point2D end = null; - Envelope2D bounding_box; - Envelope2D extent_inf = null; - Envelope2D[] child_extents = null; - - if (m_b_linear) { - start = new Point2D(); - end = new Point2D(); - extent_inf = new Envelope2D(); - } - - boolean b_found_hit = false; - while (!b_found_hit) { - while (m_current_element_handle != -1) { - int current_data_handle = m_quad_tree.get_data_(m_current_element_handle); - bounding_box = m_quad_tree.get_bounding_box_value_(current_data_handle); - - if (bounding_box.isIntersecting(m_query_box)) { - if (m_b_linear) { - start.setCoords(m_query_start); - end.setCoords(m_query_end); - extent_inf.setCoords(bounding_box); - - extent_inf.inflate(m_tolerance, m_tolerance); - if (extent_inf.clipLine(start, end) > 0) { - b_found_hit = true; - break; - } - } else { - b_found_hit = true; - break; - } - } - - // get next element_handle - m_current_element_handle = m_quad_tree.get_next_element_(m_current_element_handle); - } - - // If m_current_element_handle equals -1, then we've exhausted our search in the current quadtree node - if (m_current_element_handle == -1) { - // get the last node from the stack and add the children whose extent intersects m_query_box - int current_quad = m_quads_stack.getLast(); - Envelope2D current_extent = m_extents_stack.get(m_extents_stack.size() - 1); - - if (child_extents == null) { - child_extents = new Envelope2D[4]; - child_extents[0] = new Envelope2D(); - child_extents[1] = new Envelope2D(); - child_extents[2] = new Envelope2D(); - child_extents[3] = new Envelope2D(); - } - - set_child_extents_(current_extent, child_extents); - m_quads_stack.removeLast(); - m_extents_stack.remove(m_extents_stack.size() - 1); - - for (int quadrant = 0; quadrant < 4; quadrant++) { - int child_handle = m_quad_tree.get_child_(current_quad, quadrant); - - if (child_handle != -1 && m_quad_tree.getSubTreeElementCount(child_handle) > 0) { - if (child_extents[quadrant].isIntersecting(m_query_box)) { - if (m_b_linear) { - start.setCoords(m_query_start); - end.setCoords(m_query_end); - - extent_inf.setCoords(child_extents[quadrant]); - extent_inf.inflate(m_tolerance, m_tolerance); - if (extent_inf.clipLine(start, end) > 0) { - Envelope2D child_extent = new Envelope2D(); - child_extent.setCoords(child_extents[quadrant]); - m_quads_stack.add(child_handle); - m_extents_stack.add(child_extent); - } - } else { - Envelope2D child_extent = new Envelope2D(); - child_extent.setCoords(child_extents[quadrant]); - m_quads_stack.add(child_handle); - m_extents_stack.add(child_extent); - } - } - } - } - - assert (m_quads_stack.size() <= 4 * (m_quad_tree.m_height - 1)); - - if (m_quads_stack.size() == 0) - return -1; - - m_current_element_handle = m_quad_tree.get_first_element_(m_quads_stack.get(m_quads_stack.size() - 1)); - } - } - - // We did not exhaust our search in the current node, so we return - // the element at m_current_element_handle in m_element_nodes - - m_next_element_handle = m_quad_tree.get_next_element_(m_current_element_handle); - return m_current_element_handle; - } - - // Creates an iterator on the input Quad_tree_impl. The query will be - // the Envelope_2D bounding the input Geometry. - QuadTreeIteratorImpl(QuadTreeImpl quad_tree_impl, Geometry query, double tolerance) { - m_quad_tree = quad_tree_impl; - m_query_box = new Envelope2D(); - m_quads_stack = new AttributeStreamOfInt32(0); - m_extents_stack = new ArrayList(0); - resetIterator(query, tolerance); - } - - // Creates an iterator on the input Quad_tree_impl using the input - // Envelope_2D as the query. - QuadTreeIteratorImpl(QuadTreeImpl quad_tree_impl, Envelope2D query, double tolerance) { - m_quad_tree = quad_tree_impl; - m_query_box = new Envelope2D(); - m_quads_stack = new AttributeStreamOfInt32(0); - m_extents_stack = new ArrayList(0); - resetIterator(query, tolerance); - } - - // Creates an iterator on the input Quad_tree_impl. - QuadTreeIteratorImpl(QuadTreeImpl quad_tree_impl) { - m_quad_tree = quad_tree_impl; - m_query_box = new Envelope2D(); - m_quads_stack = new AttributeStreamOfInt32(0); - m_extents_stack = new ArrayList(0); - } - - private boolean m_b_linear; - private Point2D m_query_start; - private Point2D m_query_end; - private Envelope2D m_query_box; - private double m_tolerance; - private int m_current_element_handle; - private int m_next_element_handle; - private QuadTreeImpl m_quad_tree; - private AttributeStreamOfInt32 m_quads_stack; - private ArrayList m_extents_stack; // this won't grow bigger than 4 * (m_quad_tree->m_height - 1) - } - - static final class QuadTreeSortedIteratorImpl { - /** - * Resets the iterator to a starting state on the Quad_tree_impl. If the input Geometry is a Line segment, then the query will be the segment. Otherwise the query will be the Envelope_2D bounding the Geometry. - * \param query The Geometry used for the query. - * \param tolerance The tolerance used for the intersection tests. - * \param tolerance The tolerance used for the intersection tests. - */ - void resetIterator(Geometry query, double tolerance) { - m_quad_tree_iterator_impl.resetIterator(query, tolerance); - m_sorted_handles.resize(0); - m_index = -1; - } - - /** - * Resets the iterator to a starting state on the Quad_tree_impl using the input Envelope_2D as the query. - * \param query The Envelope_2D used for the query. - * \param tolerance The tolerance used for the intersection tests. - */ - void resetIterator(Envelope2D query, double tolerance) { - m_quad_tree_iterator_impl.resetIterator(query, tolerance); - m_sorted_handles.resize(0); - m_index = -1; - } - - /** - * Moves the iterator to the next Element_handle and returns the Element_handle. - */ - int next() { - if (m_index == -1) { - int element_handle = -1; - while ((element_handle = m_quad_tree_iterator_impl.next()) != -1) - m_sorted_handles.add(element_handle); - - m_bucket_sort.sort(m_sorted_handles, 0, m_sorted_handles.size(), new Sorter(m_quad_tree_iterator_impl.m_quad_tree)); - } - - if (m_index == m_sorted_handles.size() - 1) - return -1; - - m_index++; - return m_sorted_handles.get(m_index); - } - - //Creates a sorted iterator on the input Quad_tree_iterator_impl - QuadTreeSortedIteratorImpl(QuadTreeIteratorImpl quad_tree_iterator_impl) { - m_bucket_sort = new BucketSort(); - m_sorted_handles = new AttributeStreamOfInt32(0); - m_quad_tree_iterator_impl = quad_tree_iterator_impl; - m_index = -1; - } - - private class Sorter extends ClassicSort { - public Sorter(QuadTreeImpl quad_tree) { - m_quad_tree = quad_tree; - } - - @Override - public void userSort(int begin, int end, AttributeStreamOfInt32 indices) { - indices.sort(begin, end); - } - - @Override - public double getValue(int e) { - return m_quad_tree.getElement(e); - } - - private QuadTreeImpl m_quad_tree; - } - - private BucketSort m_bucket_sort; - private AttributeStreamOfInt32 m_sorted_handles; - private QuadTreeIteratorImpl m_quad_tree_iterator_impl; - int m_index; - } - - /** - * Creates a Quad_tree_impl with the root having the extent of the input Envelope_2D, and height of the input height, where the root starts at height 0. - * \param extent The extent of the Quad_tree_impl. - * \param height The max height of the Quad_tree_impl. - */ - QuadTreeImpl(Envelope2D extent, int height) { - m_quad_tree_nodes = new StridedIndexTypeCollection(10); - m_element_nodes = new StridedIndexTypeCollection(4); - m_data = new ArrayList(0); - m_free_data = new AttributeStreamOfInt32(0); - m_b_store_duplicates = false; - - m_extent = new Envelope2D(); - m_data_extent = new Envelope2D(); - - reset_(extent, height); - } - - /** - * Creates a Quad_tree_impl with the root having the extent of the input Envelope_2D, and height of the input height, where the root starts at height 0. - * \param extent The extent of the Quad_tree_impl. - * \param height The max height of the Quad_tree_impl. - * \param b_store_duplicates Put true to place elements deeper into the quad tree at intesecting quads, duplicates will be stored. Put false to only place elements into quads that can contain it. - */ - QuadTreeImpl(Envelope2D extent, int height, boolean b_store_duplicates) { - m_quad_tree_nodes = (b_store_duplicates ? new StridedIndexTypeCollection(11) : new StridedIndexTypeCollection(10)); - m_element_nodes = new StridedIndexTypeCollection(4); - m_data = new ArrayList(0); - m_free_data = new AttributeStreamOfInt32(0); - m_b_store_duplicates = b_store_duplicates; - - m_extent = new Envelope2D(); - m_data_extent = new Envelope2D(); - - reset_(extent, height); - } - - /** - * Resets the Quad_tree_impl to the given extent and height. - * \param extent The extent of the Quad_tree_impl. - * \param height The max height of the Quad_tree_impl. - */ - void reset(Envelope2D extent, int height) { - m_quad_tree_nodes.deleteAll(false); - m_element_nodes.deleteAll(false); - m_data.clear(); - m_free_data.clear(false); - reset_(extent, height); - } - - /** - * Inserts the element and bounding_box into the Quad_tree_impl. - * Note that this will invalidate any active iterator on the Quad_tree_impl. - * Returns an Element_handle corresponding to the element and bounding_box. - * \param element The element of the Geometry to be inserted. - * \param bounding_box The bounding_box of the Geometry to be inserted. - */ - int insert(int element, Envelope2D bounding_box) { - if (m_root == -1) - create_root_(); - - if (m_b_store_duplicates) { - int success = insert_duplicates_(element, bounding_box, 0, m_extent, m_root, false, -1); - - if (success != -1) { - if (m_data_extent.isEmpty()) - m_data_extent.setCoords(bounding_box); - else - m_data_extent.merge(bounding_box); - } - - return success; - } - - int element_handle = insert_(element, bounding_box, 0, m_extent, m_root, false, -1); - - if (element_handle != -1) { - if (m_data_extent.isEmpty()) - m_data_extent.setCoords(bounding_box); - else - m_data_extent.merge(bounding_box); - } - - return element_handle; - } - - /** - * Inserts the element and bounding_box into the Quad_tree_impl at the given quad_handle. - * Note that this will invalidate any active iterator on the Quad_tree_impl. - * Returns an Element_handle corresponding to the element and bounding_box. - * \param element The element of the Geometry to be inserted. - * \param bounding_box The bounding_box of the Geometry to be inserted. - * \param hint_index A handle used as a hint where to place the element. This can be a handle obtained from a previous insertion and is useful on data having strong locality such as segments of a Polygon. - */ - int insert(int element, Envelope2D bounding_box, int hint_index) { - if (m_root == -1) - create_root_(); - - if (m_b_store_duplicates) { - int success = insert_duplicates_(element, bounding_box, 0, m_extent, m_root, false, -1); - - if (success != -1) { - if (m_data_extent.isEmpty()) - m_data_extent.setCoords(bounding_box); - else - m_data_extent.merge(bounding_box); - } - return success; - } - - int quad_handle; - - if (hint_index == -1) - quad_handle = m_root; - else - quad_handle = get_quad_(hint_index); - - int quad_height = getHeight(quad_handle); - Envelope2D quad_extent = getExtent(quad_handle); - - int element_handle = insert_(element, bounding_box, quad_height, quad_extent, quad_handle, false, -1); - - if (element_handle != -1) { - if (m_data_extent.isEmpty()) - m_data_extent.setCoords(bounding_box); - else - m_data_extent.merge(bounding_box); - } - - return element_handle; - } - - /** - * Removes the element and bounding_box at the given element_handle. - * Note that this will invalidate any active iterator on the Quad_tree_impl. - * \param element_handle The handle corresponding to the element and bounding_box to be removed. - */ - void removeElement(int element_handle) { - if (m_b_store_duplicates) - throw new GeometryException("invalid call"); - - int quad_handle = get_quad_(element_handle); - disconnect_element_handle_(element_handle); - free_element_and_box_node_(element_handle); - - int q = quad_handle; - - while (q != -1) { - set_sub_tree_element_count_(q, get_sub_tree_element_count_(q) - 1); - int parent = get_parent_(q); - - if (get_sub_tree_element_count_(q) == 0) { - assert (get_local_element_count_(q) == 0); - - if (q != m_root) { - int quadrant = get_quadrant_(q); - m_quad_tree_nodes.deleteElement(q); - set_child_(parent, quadrant, -1); - } - } - - q = parent; - } - } - - /** - * Returns the element at the given element_handle. - * \param element_handle The handle corresponding to the element to be retrieved. - */ - int getElement(int element_handle) { - return get_element_value_(get_data_(element_handle)); - } - - /** - * Returns the ith unique element. - * \param i The index corresponding to the ith unique element. - */ - int getElementAtIndex(int i) { - return m_data.get(i).element; - } - - /** - * Returns the element extent at the given element_handle. - * \param element_handle The handle corresponding to the element extent to be retrieved. - */ - Envelope2D getElementExtent(int element_handle) { - int data_handle = get_data_(element_handle); - return get_bounding_box_value_(data_handle); - } - - /** - * Returns the extent of the ith unique element. - * \param i The index corresponding to the ith unique element. - */ - Envelope2D getElementExtentAtIndex(int i) { - return m_data.get(i).box; - } - - /** - * Returns the extent of all elements in the quad tree. - */ - Envelope2D getDataExtent() { - return m_data_extent; - } - - /** - * Returns the extent of the quad tree. - */ - Envelope2D getQuadTreeExtent() { - return m_extent; - } - - /** - * Returns the height of the quad at the given quad_handle. - * \param quad_handle The handle corresponding to the quad. - */ - int getHeight(int quad_handle) { - return get_height_(quad_handle); - } - - int getMaxHeight() { - return m_height; - } - - /** - * Returns the extent of the quad at the given quad_handle. - * \param quad_handle The handle corresponding to the quad. - */ - Envelope2D getExtent(int quad_handle) { - Envelope2D quad_extent = new Envelope2D(); - quad_extent.setCoords(m_extent); - - if (quad_handle == m_root) - return quad_extent; - - AttributeStreamOfInt32 quadrants = new AttributeStreamOfInt32(0); - - int q = quad_handle; - - do { - quadrants.add(get_quadrant_(q)); - q = get_parent_(q); - - } while (q != m_root); - - int sz = quadrants.size(); - assert (sz == getHeight(quad_handle)); - - for (int i = 0; i < sz; i++) { - int child = quadrants.getLast(); - quadrants.removeLast(); - - if (child == 0) {//northeast - quad_extent.xmin = 0.5 * (quad_extent.xmin + quad_extent.xmax); - quad_extent.ymin = 0.5 * (quad_extent.ymin + quad_extent.ymax); - } else if (child == 1) {//northwest - quad_extent.xmax = 0.5 * (quad_extent.xmin + quad_extent.xmax); - quad_extent.ymin = 0.5 * (quad_extent.ymin + quad_extent.ymax); - } else if (child == 2) {//southwest - quad_extent.xmax = 0.5 * (quad_extent.xmin + quad_extent.xmax); - quad_extent.ymax = 0.5 * (quad_extent.ymin + quad_extent.ymax); - } else {//southeast - quad_extent.xmin = 0.5 * (quad_extent.xmin + quad_extent.xmax); - quad_extent.ymax = 0.5 * (quad_extent.ymin + quad_extent.ymax); - } - } - - return quad_extent; - } - - /** - * Returns the Quad_handle of the quad containing the given element_handle. - * \param element_handle The handle corresponding to the element. - */ - int getQuad(int element_handle) { - return get_quad_(element_handle); - } - - /** - * Returns the number of elements in the Quad_tree_impl. - */ - int getElementCount() { - if (m_root == -1) - return 0; - - assert (get_sub_tree_element_count_(m_root) == m_data.size()); - return get_sub_tree_element_count_(m_root); - } - - /** - * Returns the number of elements in the subtree rooted at the given quad_handle. - * \param quad_handle The handle corresponding to the quad. - */ - int getSubTreeElementCount(int quad_handle) { - return get_sub_tree_element_count_(quad_handle); - } - - /** - * Returns the number of elements contained in the subtree rooted at the given quad_handle. - * \param quad_handle The handle corresponding to the quad. - */ - int getContainedSubTreeElementCount(int quad_handle) { - if (!m_b_store_duplicates) - return get_sub_tree_element_count_(quad_handle); - - return get_contained_sub_tree_element_count_(quad_handle); - } - - /** - * Returns the number of elements in the quad tree that intersect the qiven query. Some elements may be duplicated if the quad tree stores duplicates. - * \param query The Envelope_2D used for the query. - * \param tolerance The tolerance used for the intersection tests. - * \param max_count If the intersection count becomes greater than or equal to the max_count, then max_count is returned. - */ - int getIntersectionCount(Envelope2D query, double tolerance, int max_count) { - if (m_root == -1) - return 0; - - Envelope2D query_inflated = new Envelope2D(); - query_inflated.setCoords(query); - query_inflated.inflate(tolerance, tolerance); - - AttributeStreamOfInt32 quads_stack = new AttributeStreamOfInt32(0); - ArrayList extents_stack = new ArrayList(0); - quads_stack.add(m_root); - extents_stack.add(new Envelope2D(m_extent.xmin, m_extent.ymin, m_extent.xmax, m_extent.ymax)); - - Envelope2D[] child_extents = new Envelope2D[4]; - child_extents[0] = new Envelope2D(); - child_extents[1] = new Envelope2D(); - child_extents[2] = new Envelope2D(); - child_extents[3] = new Envelope2D(); - - Envelope2D current_extent = new Envelope2D(); - - int intersection_count = 0; - - while (quads_stack.size() > 0) { - boolean b_subdivide = false; - - int current_quad_handle = quads_stack.getLast(); - current_extent.setCoords(extents_stack.get(extents_stack.size() - 1)); - - quads_stack.removeLast(); - extents_stack.remove(extents_stack.size() - 1); - - - if (query_inflated.contains(current_extent)) { - intersection_count += getSubTreeElementCount(current_quad_handle); - - if (max_count > 0 && intersection_count >= max_count) - return max_count; - } else { - if (query_inflated.isIntersecting(current_extent)) { - for (int element_handle = get_first_element_(current_quad_handle); element_handle != -1; element_handle = get_next_element_(element_handle)) { - int data_handle = get_data_(element_handle); - Envelope2D env = get_bounding_box_value_(data_handle); - - if (env.isIntersecting(query_inflated)) { - intersection_count++; - - if (max_count > 0 && intersection_count >= max_count) - return max_count; - } - } - - b_subdivide = getHeight(current_quad_handle) + 1 <= m_height; - } - } - - if (b_subdivide) { - set_child_extents_(current_extent, child_extents); - - for (int i = 0; i < 4; i++) { - int child_handle = get_child_(current_quad_handle, i); - - if (child_handle != -1 && getSubTreeElementCount(child_handle) > 0) { - boolean b_is_intersecting = query_inflated.isIntersecting(child_extents[i]); - - if (b_is_intersecting) { - quads_stack.add(child_handle); - extents_stack.add(new Envelope2D(child_extents[i].xmin, child_extents[i].ymin, child_extents[i].xmax, child_extents[i].ymax)); - } - } - } - } - } - - return intersection_count; - } - - /** - * Returns true if the quad tree has data intersecting the given query. - * \param query The Envelope_2D used for the query. - * \param tolerance The tolerance used for the intersection tests. - */ - boolean hasData(Envelope2D query, double tolerance) { - int count = getIntersectionCount(query, tolerance, 1); - return count >= 1; - } - - /** - * Gets an iterator on the Quad_tree_impl. The query will be the Envelope_2D - * that bounds the input Geometry. To reuse the existing iterator on the - * same Quad_tree_impl but with a new query, use the reset_iterator function - * on the Quad_tree_iterator_impl. \param query The Geometry used for the - * query. If the Geometry is a Line segment, then the query will be the - * segment. Otherwise the query will be the Envelope_2D bounding the - * Geometry. \param tolerance The tolerance used for the intersection tests. - */ - QuadTreeIteratorImpl getIterator(Geometry query, double tolerance) { - return new QuadTreeIteratorImpl(this, query, tolerance); - } - - /** - * Gets an iterator on the Quad_tree_impl using the input Envelope_2D as the - * query. To reuse the existing iterator on the same Quad_tree_impl but with - * a new query, use the reset_iterator function on the - * Quad_tree_iterator_impl. \param query The Envelope_2D used for the query. - * \param tolerance The tolerance used for the intersection tests. - */ - QuadTreeIteratorImpl getIterator(Envelope2D query, double tolerance) { - return new QuadTreeIteratorImpl(this, query, tolerance); - } - - /** - * Gets an iterator on the Quad_tree. - */ - QuadTreeIteratorImpl getIterator() { - return new QuadTreeIteratorImpl(this); - } - - /** - * Gets a sorted iterator on the Quad_tree_impl. The Element_handles will be returned in increasing order of their corresponding Element_types. - * The query will be the Envelope_2D that bounds the input Geometry. - * To reuse the existing iterator on the same Quad_tree_impl but with a new query, use the reset_iterator function on the Quad_tree_sorted_iterator_impl. - * \param query The Geometry used for the query. If the Geometry is a Line segment, then the query will be the segment. Otherwise the query will be the Envelope_2D bounding the Geometry. - * \param tolerance The tolerance used for the intersection tests. - */ - QuadTreeSortedIteratorImpl getSortedIterator(Geometry query, double tolerance) { - return new QuadTreeSortedIteratorImpl(getIterator(query, tolerance)); - } - - /** - * Gets a sorted iterator on the Quad_tree_impl using the input Envelope_2D as the query. The Element_handles will be returned in increasing order of their corresponding Element_types. - * To reuse the existing iterator on the same Quad_tree_impl but with a new query, use the reset_iterator function on the Quad_tree_iterator_impl. - * \param query The Envelope_2D used for the query. - * \param tolerance The tolerance used for the intersection tests. - */ - QuadTreeSortedIteratorImpl getSortedIterator(Envelope2D query, double tolerance) { - return new QuadTreeSortedIteratorImpl(getIterator(query, tolerance)); - } - - /** - * Gets a sorted iterator on the Quad_tree. The Element_handles will be returned in increasing order of their corresponding Element_types - */ - QuadTreeSortedIteratorImpl getSortedIterator() { - return new QuadTreeSortedIteratorImpl(getIterator()); - } - - private void reset_(Envelope2D extent, int height) { - if (height < 0 || height > 127) - throw new IllegalArgumentException("invalid height"); - - m_height = height; - m_extent.setCoords(extent); - m_root = m_quad_tree_nodes.newElement(); - m_data_extent.setEmpty(); - m_root = -1; - } - - private int insert_(int element, Envelope2D bounding_box, int height, Envelope2D quad_extent, int quad_handle, boolean b_flushing, int flushed_element_handle) { - if (!quad_extent.contains(bounding_box)) { - assert (!b_flushing); - - if (height == 0) - return -1; - - return insert_(element, bounding_box, 0, m_extent, m_root, b_flushing, flushed_element_handle); - } - - if (!b_flushing) { - for (int q = quad_handle; q != -1; q = get_parent_(q)) - set_sub_tree_element_count_(q, get_sub_tree_element_count_(q) + 1); - } - - Envelope2D current_extent = new Envelope2D(); - current_extent.setCoords(quad_extent); - - int current_quad_handle = quad_handle; - - Envelope2D[] child_extents = new Envelope2D[4]; - child_extents[0] = new Envelope2D(); - child_extents[1] = new Envelope2D(); - child_extents[2] = new Envelope2D(); - child_extents[3] = new Envelope2D(); - - int current_height; - for (current_height = height; current_height < m_height && can_push_down_(current_quad_handle); current_height++) { - set_child_extents_(current_extent, child_extents); - - boolean b_contains = false; - - for (int i = 0; i < 4; i++) { - if (child_extents[i].contains(bounding_box)) { - b_contains = true; - - int child_handle = get_child_(current_quad_handle, i); - if (child_handle == -1) - child_handle = create_child_(current_quad_handle, i); - - set_sub_tree_element_count_(child_handle, get_sub_tree_element_count_(child_handle) + 1); - - current_quad_handle = child_handle; - current_extent.setCoords(child_extents[i]); - break; - } - } - - if (!b_contains) - break; - } - - return insert_at_quad_(element, bounding_box, current_height, current_extent, current_quad_handle, b_flushing, quad_handle, flushed_element_handle, -1); - } - - private int insert_duplicates_(int element, Envelope2D bounding_box, int height, Envelope2D quad_extent, int quad_handle, boolean b_flushing, int flushed_element_handle) { - assert (b_flushing || m_root == quad_handle); - - if (!b_flushing) // If b_flushing is true, then the sub tree element counts are already accounted for since the element already lies in the current incoming quad - { - if (!quad_extent.contains(bounding_box)) - return -1; - - set_sub_tree_element_count_(quad_handle, get_sub_tree_element_count_(quad_handle) + 1); - set_contained_sub_tree_element_count_(quad_handle, get_contained_sub_tree_element_count_(quad_handle) + 1); - } - - double bounding_box_max_dim = Math.max(bounding_box.getWidth(), bounding_box.getHeight()); - - int element_handle = -1; - AttributeStreamOfInt32 quads_stack = new AttributeStreamOfInt32(0); - ArrayList extents_stack = new ArrayList(0); - AttributeStreamOfInt32 heights_stack = new AttributeStreamOfInt32(0); - quads_stack.add(quad_handle); - extents_stack.add(new Envelope2D(quad_extent.xmin, quad_extent.ymin, quad_extent.xmax, quad_extent.ymax)); - heights_stack.add(height); - - Envelope2D[] child_extents = new Envelope2D[4]; - child_extents[0] = new Envelope2D(); - child_extents[1] = new Envelope2D(); - child_extents[2] = new Envelope2D(); - child_extents[3] = new Envelope2D(); - - Envelope2D current_extent = new Envelope2D(); - - while (quads_stack.size() > 0) { - boolean b_subdivide = false; - - int current_quad_handle = quads_stack.getLast(); - current_extent.setCoords(extents_stack.get(extents_stack.size() - 1)); - int current_height = heights_stack.getLast(); - - quads_stack.removeLast(); - extents_stack.remove(extents_stack.size() - 1); - heights_stack.removeLast(); - - if (current_height + 1 < m_height && can_push_down_(current_quad_handle)) { - double current_extent_max_dim = Math.max(current_extent.getWidth(), current_extent.getHeight()); - - if (bounding_box_max_dim <= current_extent_max_dim / 2.0) - b_subdivide = true; - } +import static com.esri.core.geometry.SizeOf.SIZE_OF_DATA; +import static com.esri.core.geometry.SizeOf.SIZE_OF_QUAD_TREE_IMPL; +import static com.esri.core.geometry.SizeOf.sizeOfObjectArray; + +class QuadTreeImpl implements Serializable { + private static final long serialVersionUID = 1L; + + static final class QuadTreeIteratorImpl { + /** + * Resets the iterator to an starting state on the Quad_tree_impl. If + * the input Geometry is a Line segment, then the query will be the + * segment. Otherwise the query will be the Envelope_2D bounding the + * Geometry. \param query The Geometry used for the query. \param + * tolerance The tolerance used for the intersection tests. \param + * tolerance The tolerance used for the intersection tests. + */ + void resetIterator(Geometry query, double tolerance) { + m_quads_stack.resize(0); + m_extents_stack.clear(); + m_current_element_handle = -1; + query.queryLooseEnvelope2D(m_query_box); + m_query_box.inflate(tolerance, tolerance); + + if (m_quad_tree.m_root != -1 && m_query_box.isIntersecting(m_quad_tree.m_extent)) { + int type = query.getType().value(); + m_b_linear = Geometry.isSegment(type); + + if (m_b_linear) { + Segment segment = (Segment) query; + m_query_start = segment.getStartXY(); + m_query_end = segment.getEndXY(); + m_tolerance = tolerance; + } else { + m_tolerance = NumberUtils.NaN(); // we don't need it + } + + m_quads_stack.add(m_quad_tree.m_root); + m_extents_stack.add(m_quad_tree.m_extent); + m_next_element_handle = m_quad_tree.get_first_element_(m_quad_tree.m_root); + } else + m_next_element_handle = -1; + } + + /** + * Resets the iterator to a starting state on the Quad_tree_impl using + * the input Envelope_2D as the query. \param query The Envelope_2D used + * for the query. \param tolerance The tolerance used for the + * intersection tests. + */ + void resetIterator(Envelope2D query, double tolerance) { + m_quads_stack.resize(0); + m_extents_stack.clear(); + m_current_element_handle = -1; + m_query_box.setCoords(query); + m_query_box.inflate(tolerance, tolerance); + m_tolerance = NumberUtils.NaN(); // we don't need it + + if (m_quad_tree.m_root != -1 && m_query_box.isIntersecting(m_quad_tree.m_extent)) { + m_quads_stack.add(m_quad_tree.m_root); + m_extents_stack.add(m_quad_tree.m_extent); + m_next_element_handle = m_quad_tree.get_first_element_(m_quad_tree.m_root); + m_b_linear = false; + } else + m_next_element_handle = -1; + } + + /** + * Moves the iterator to the next int and returns the int. + */ + int next() { + // If the node stack is empty, then we've exhausted our search + + if (m_quads_stack.size() == 0) + return -1; + + m_current_element_handle = m_next_element_handle; + + Point2D start = null; + Point2D end = null; + Envelope2D bounding_box; + Envelope2D extent_inf = null; + Envelope2D[] child_extents = null; + + if (m_b_linear) { + start = new Point2D(); + end = new Point2D(); + extent_inf = new Envelope2D(); + } + + boolean b_found_hit = false; + while (!b_found_hit) { + while (m_current_element_handle != -1) { + int current_data_handle = m_quad_tree.get_data_(m_current_element_handle); + bounding_box = m_quad_tree.get_bounding_box_value_(current_data_handle); + + if (bounding_box.isIntersecting(m_query_box)) { + if (m_b_linear) { + start.setCoords(m_query_start); + end.setCoords(m_query_end); + extent_inf.setCoords(bounding_box); + + extent_inf.inflate(m_tolerance, m_tolerance); + if (extent_inf.clipLine(start, end) > 0) { + b_found_hit = true; + break; + } + } else { + b_found_hit = true; + break; + } + } + + // get next element_handle + m_current_element_handle = m_quad_tree.get_next_element_(m_current_element_handle); + } + + // If m_current_element_handle equals -1, then we've exhausted our search in the current quadtree node + if (m_current_element_handle == -1) { + // get the last node from the stack and add the children whose extent intersects m_query_box + int current_quad = m_quads_stack.getLast(); + Envelope2D current_extent = m_extents_stack.get(m_extents_stack.size() - 1); + + if (child_extents == null) { + child_extents = new Envelope2D[4]; + child_extents[0] = new Envelope2D(); + child_extents[1] = new Envelope2D(); + child_extents[2] = new Envelope2D(); + child_extents[3] = new Envelope2D(); + } + + set_child_extents_(current_extent, child_extents); + m_quads_stack.removeLast(); + m_extents_stack.remove(m_extents_stack.size() - 1); + + for (int quadrant = 0; quadrant < 4; quadrant++) { + int child_handle = m_quad_tree.get_child_(current_quad, quadrant); + + if (child_handle != -1 && m_quad_tree.getSubTreeElementCount(child_handle) > 0) { + if (child_extents[quadrant].isIntersecting(m_query_box)) { + if (m_b_linear) { + start.setCoords(m_query_start); + end.setCoords(m_query_end); + + extent_inf.setCoords(child_extents[quadrant]); + extent_inf.inflate(m_tolerance, m_tolerance); + if (extent_inf.clipLine(start, end) > 0) { + Envelope2D child_extent = new Envelope2D(); + child_extent.setCoords(child_extents[quadrant]); + m_quads_stack.add(child_handle); + m_extents_stack.add(child_extent); + } + } else { + Envelope2D child_extent = new Envelope2D(); + child_extent.setCoords(child_extents[quadrant]); + m_quads_stack.add(child_handle); + m_extents_stack.add(child_extent); + } + } + } + } + + assert (m_quads_stack.size() <= 4 * (m_quad_tree.m_height - 1)); + + if (m_quads_stack.size() == 0) + return -1; + + m_current_element_handle = m_quad_tree.get_first_element_(m_quads_stack.get(m_quads_stack.size() - 1)); + } + } + + // We did not exhaust our search in the current node, so we return + // the element at m_current_element_handle in m_element_nodes + + m_next_element_handle = m_quad_tree.get_next_element_(m_current_element_handle); + return m_current_element_handle; + } + + // Creates an iterator on the input Quad_tree_impl. The query will be + // the Envelope_2D bounding the input Geometry. + QuadTreeIteratorImpl(QuadTreeImpl quad_tree_impl, Geometry query, double tolerance) { + m_quad_tree = quad_tree_impl; + m_query_box = new Envelope2D(); + m_quads_stack = new AttributeStreamOfInt32(0); + m_extents_stack = new ArrayList(0); + resetIterator(query, tolerance); + } + + // Creates an iterator on the input Quad_tree_impl using the input + // Envelope_2D as the query. + QuadTreeIteratorImpl(QuadTreeImpl quad_tree_impl, Envelope2D query, double tolerance) { + m_quad_tree = quad_tree_impl; + m_query_box = new Envelope2D(); + m_quads_stack = new AttributeStreamOfInt32(0); + m_extents_stack = new ArrayList(0); + resetIterator(query, tolerance); + } + + // Creates an iterator on the input Quad_tree_impl. + QuadTreeIteratorImpl(QuadTreeImpl quad_tree_impl) { + m_quad_tree = quad_tree_impl; + m_query_box = new Envelope2D(); + m_quads_stack = new AttributeStreamOfInt32(0); + m_extents_stack = new ArrayList(0); + } + + private boolean m_b_linear; + private Point2D m_query_start; + private Point2D m_query_end; + private Envelope2D m_query_box; + private double m_tolerance; + private int m_current_element_handle; + private int m_next_element_handle; + private QuadTreeImpl m_quad_tree; + private AttributeStreamOfInt32 m_quads_stack; + private ArrayList m_extents_stack; // this won't grow bigger than 4 * (m_quad_tree->m_height - 1) + } + + static final class QuadTreeSortedIteratorImpl { + /** + * Resets the iterator to a starting state on the Quad_tree_impl. If the input Geometry is a Line segment, then the query will be the segment. Otherwise the query will be the Envelope_2D bounding the Geometry. + * \param query The Geometry used for the query. + * \param tolerance The tolerance used for the intersection tests. + * \param tolerance The tolerance used for the intersection tests. + */ + void resetIterator(Geometry query, double tolerance) { + m_quad_tree_iterator_impl.resetIterator(query, tolerance); + m_sorted_handles.resize(0); + m_index = -1; + } + + /** + * Resets the iterator to a starting state on the Quad_tree_impl using the input Envelope_2D as the query. + * \param query The Envelope_2D used for the query. + * \param tolerance The tolerance used for the intersection tests. + */ + void resetIterator(Envelope2D query, double tolerance) { + m_quad_tree_iterator_impl.resetIterator(query, tolerance); + m_sorted_handles.resize(0); + m_index = -1; + } + + /** + * Moves the iterator to the next Element_handle and returns the Element_handle. + */ + int next() { + if (m_index == -1) { + int element_handle = -1; + while ((element_handle = m_quad_tree_iterator_impl.next()) != -1) + m_sorted_handles.add(element_handle); + + m_bucket_sort.sort(m_sorted_handles, 0, m_sorted_handles.size(), new Sorter(m_quad_tree_iterator_impl.m_quad_tree)); + } + + if (m_index == m_sorted_handles.size() - 1) + return -1; + + m_index++; + return m_sorted_handles.get(m_index); + } + + //Creates a sorted iterator on the input Quad_tree_iterator_impl + QuadTreeSortedIteratorImpl(QuadTreeIteratorImpl quad_tree_iterator_impl) { + m_bucket_sort = new BucketSort(); + m_sorted_handles = new AttributeStreamOfInt32(0); + m_quad_tree_iterator_impl = quad_tree_iterator_impl; + m_index = -1; + } + + private class Sorter extends ClassicSort { + public Sorter(QuadTreeImpl quad_tree) { + m_quad_tree = quad_tree; + } + + @Override + public void userSort(int begin, int end, AttributeStreamOfInt32 indices) { + indices.sort(begin, end); + } + + @Override + public double getValue(int e) { + return m_quad_tree.getElement(e); + } + + private QuadTreeImpl m_quad_tree; + } + + private BucketSort m_bucket_sort; + private AttributeStreamOfInt32 m_sorted_handles; + private QuadTreeIteratorImpl m_quad_tree_iterator_impl; + int m_index; + } + + /** + * Creates a Quad_tree_impl with the root having the extent of the input Envelope_2D, and height of the input height, where the root starts at height 0. + * \param extent The extent of the Quad_tree_impl. + * \param height The max height of the Quad_tree_impl. + */ + QuadTreeImpl(Envelope2D extent, int height) { + m_quad_tree_nodes = new StridedIndexTypeCollection(10); + m_element_nodes = new StridedIndexTypeCollection(4); + m_data = new ArrayList(0); + m_free_data = new AttributeStreamOfInt32(0); + m_b_store_duplicates = false; + + m_extent = new Envelope2D(); + m_data_extent = new Envelope2D(); + + reset_(extent, height); + } + + /** + * Creates a Quad_tree_impl with the root having the extent of the input Envelope_2D, and height of the input height, where the root starts at height 0. + * \param extent The extent of the Quad_tree_impl. + * \param height The max height of the Quad_tree_impl. + * \param b_store_duplicates Put true to place elements deeper into the quad tree at intesecting quads, duplicates will be stored. Put false to only place elements into quads that can contain it. + */ + QuadTreeImpl(Envelope2D extent, int height, boolean b_store_duplicates) { + m_quad_tree_nodes = (b_store_duplicates ? new StridedIndexTypeCollection(11) : new StridedIndexTypeCollection(10)); + m_element_nodes = new StridedIndexTypeCollection(4); + m_data = new ArrayList(0); + m_free_data = new AttributeStreamOfInt32(0); + m_b_store_duplicates = b_store_duplicates; + + m_extent = new Envelope2D(); + m_data_extent = new Envelope2D(); + + reset_(extent, height); + } + + /** + * Resets the Quad_tree_impl to the given extent and height. + * \param extent The extent of the Quad_tree_impl. + * \param height The max height of the Quad_tree_impl. + */ + void reset(Envelope2D extent, int height) { + m_quad_tree_nodes.deleteAll(false); + m_element_nodes.deleteAll(false); + m_data.clear(); + m_free_data.clear(false); + reset_(extent, height); + } + + /** + * Inserts the element and bounding_box into the Quad_tree_impl. + * Note that this will invalidate any active iterator on the Quad_tree_impl. + * Returns an Element_handle corresponding to the element and bounding_box. + * \param element The element of the Geometry to be inserted. + * \param bounding_box The bounding_box of the Geometry to be inserted. + */ + int insert(int element, Envelope2D bounding_box) { + if (m_root == -1) + create_root_(); + + if (m_b_store_duplicates) { + int success = insert_duplicates_(element, bounding_box, 0, m_extent, m_root, false, -1); + + if (success != -1) { + if (m_data_extent.isEmpty()) + m_data_extent.setCoords(bounding_box); + else + m_data_extent.merge(bounding_box); + } + + return success; + } + + int element_handle = insert_(element, bounding_box, 0, m_extent, m_root, false, -1); + + if (element_handle != -1) { + if (m_data_extent.isEmpty()) + m_data_extent.setCoords(bounding_box); + else + m_data_extent.merge(bounding_box); + } + + return element_handle; + } + + /** + * Inserts the element and bounding_box into the Quad_tree_impl at the given quad_handle. + * Note that this will invalidate any active iterator on the Quad_tree_impl. + * Returns an Element_handle corresponding to the element and bounding_box. + * \param element The element of the Geometry to be inserted. + * \param bounding_box The bounding_box of the Geometry to be inserted. + * \param hint_index A handle used as a hint where to place the element. This can be a handle obtained from a previous insertion and is useful on data having strong locality such as segments of a Polygon. + */ + int insert(int element, Envelope2D bounding_box, int hint_index) { + if (m_root == -1) + create_root_(); + + if (m_b_store_duplicates) { + int success = insert_duplicates_(element, bounding_box, 0, m_extent, m_root, false, -1); + + if (success != -1) { + if (m_data_extent.isEmpty()) + m_data_extent.setCoords(bounding_box); + else + m_data_extent.merge(bounding_box); + } + return success; + } + + int quad_handle; + + if (hint_index == -1) + quad_handle = m_root; + else + quad_handle = get_quad_(hint_index); + + int quad_height = getHeight(quad_handle); + Envelope2D quad_extent = getExtent(quad_handle); + + int element_handle = insert_(element, bounding_box, quad_height, quad_extent, quad_handle, false, -1); + + if (element_handle != -1) { + if (m_data_extent.isEmpty()) + m_data_extent.setCoords(bounding_box); + else + m_data_extent.merge(bounding_box); + } + + return element_handle; + } + + /** + * Removes the element and bounding_box at the given element_handle. + * Note that this will invalidate any active iterator on the Quad_tree_impl. + * \param element_handle The handle corresponding to the element and bounding_box to be removed. + */ + void removeElement(int element_handle) { + if (m_b_store_duplicates) + throw new GeometryException("invalid call"); + + int quad_handle = get_quad_(element_handle); + disconnect_element_handle_(element_handle); + free_element_and_box_node_(element_handle); + + int q = quad_handle; + + while (q != -1) { + set_sub_tree_element_count_(q, get_sub_tree_element_count_(q) - 1); + int parent = get_parent_(q); + + if (get_sub_tree_element_count_(q) == 0) { + assert (get_local_element_count_(q) == 0); + + if (q != m_root) { + int quadrant = get_quadrant_(q); + m_quad_tree_nodes.deleteElement(q); + set_child_(parent, quadrant, -1); + } + } + + q = parent; + } + } + + /** + * Returns the element at the given element_handle. + * \param element_handle The handle corresponding to the element to be retrieved. + */ + int getElement(int element_handle) { + return get_element_value_(get_data_(element_handle)); + } + + /** + * Returns the ith unique element. + * \param i The index corresponding to the ith unique element. + */ + int getElementAtIndex(int i) { + return m_data.get(i).element; + } + + /** + * Returns the element extent at the given element_handle. + * \param element_handle The handle corresponding to the element extent to be retrieved. + */ + Envelope2D getElementExtent(int element_handle) { + int data_handle = get_data_(element_handle); + return get_bounding_box_value_(data_handle); + } + + /** + * Returns the extent of the ith unique element. + * \param i The index corresponding to the ith unique element. + */ + Envelope2D getElementExtentAtIndex(int i) { + return m_data.get(i).box; + } + + /** + * Returns the extent of all elements in the quad tree. + */ + Envelope2D getDataExtent() { + return m_data_extent; + } + + /** + * Returns the extent of the quad tree. + */ + Envelope2D getQuadTreeExtent() { + return m_extent; + } + + /** + * Returns the height of the quad at the given quad_handle. + * \param quad_handle The handle corresponding to the quad. + */ + int getHeight(int quad_handle) { + return get_height_(quad_handle); + } + + int getMaxHeight() { + return m_height; + } + + /** + * Returns the extent of the quad at the given quad_handle. + * \param quad_handle The handle corresponding to the quad. + */ + Envelope2D getExtent(int quad_handle) { + Envelope2D quad_extent = new Envelope2D(); + quad_extent.setCoords(m_extent); + + if (quad_handle == m_root) + return quad_extent; + + AttributeStreamOfInt32 quadrants = new AttributeStreamOfInt32(0); + + int q = quad_handle; + + do { + quadrants.add(get_quadrant_(q)); + q = get_parent_(q); + + } while (q != m_root); + + int sz = quadrants.size(); + assert (sz == getHeight(quad_handle)); + + for (int i = 0; i < sz; i++) { + int child = quadrants.getLast(); + quadrants.removeLast(); + + if (child == 0) {//northeast + quad_extent.xmin = 0.5 * (quad_extent.xmin + quad_extent.xmax); + quad_extent.ymin = 0.5 * (quad_extent.ymin + quad_extent.ymax); + } else if (child == 1) {//northwest + quad_extent.xmax = 0.5 * (quad_extent.xmin + quad_extent.xmax); + quad_extent.ymin = 0.5 * (quad_extent.ymin + quad_extent.ymax); + } else if (child == 2) {//southwest + quad_extent.xmax = 0.5 * (quad_extent.xmin + quad_extent.xmax); + quad_extent.ymax = 0.5 * (quad_extent.ymin + quad_extent.ymax); + } else {//southeast + quad_extent.xmin = 0.5 * (quad_extent.xmin + quad_extent.xmax); + quad_extent.ymax = 0.5 * (quad_extent.ymin + quad_extent.ymax); + } + } + + return quad_extent; + } + + /** + * Returns the Quad_handle of the quad containing the given element_handle. + * \param element_handle The handle corresponding to the element. + */ + int getQuad(int element_handle) { + return get_quad_(element_handle); + } + + /** + * Returns the number of elements in the Quad_tree_impl. + */ + int getElementCount() { + if (m_root == -1) + return 0; + + assert (get_sub_tree_element_count_(m_root) == m_data.size()); + return get_sub_tree_element_count_(m_root); + } + + /** + * Returns the number of elements in the subtree rooted at the given quad_handle. + * \param quad_handle The handle corresponding to the quad. + */ + int getSubTreeElementCount(int quad_handle) { + return get_sub_tree_element_count_(quad_handle); + } + + /** + * Returns the number of elements contained in the subtree rooted at the given quad_handle. + * \param quad_handle The handle corresponding to the quad. + */ + int getContainedSubTreeElementCount(int quad_handle) { + if (!m_b_store_duplicates) + return get_sub_tree_element_count_(quad_handle); + + return get_contained_sub_tree_element_count_(quad_handle); + } + + /** + * Returns the number of elements in the quad tree that intersect the qiven query. Some elements may be duplicated if the quad tree stores duplicates. + * \param query The Envelope_2D used for the query. + * \param tolerance The tolerance used for the intersection tests. + * \param max_count If the intersection count becomes greater than or equal to the max_count, then max_count is returned. + */ + int getIntersectionCount(Envelope2D query, double tolerance, int max_count) { + if (m_root == -1) + return 0; + + Envelope2D query_inflated = new Envelope2D(); + query_inflated.setCoords(query); + query_inflated.inflate(tolerance, tolerance); + + AttributeStreamOfInt32 quads_stack = new AttributeStreamOfInt32(0); + ArrayList extents_stack = new ArrayList(0); + quads_stack.add(m_root); + extents_stack.add(new Envelope2D(m_extent.xmin, m_extent.ymin, m_extent.xmax, m_extent.ymax)); + + Envelope2D[] child_extents = new Envelope2D[4]; + child_extents[0] = new Envelope2D(); + child_extents[1] = new Envelope2D(); + child_extents[2] = new Envelope2D(); + child_extents[3] = new Envelope2D(); + + Envelope2D current_extent = new Envelope2D(); + + int intersection_count = 0; + + while (quads_stack.size() > 0) { + boolean b_subdivide = false; + + int current_quad_handle = quads_stack.getLast(); + current_extent.setCoords(extents_stack.get(extents_stack.size() - 1)); + + quads_stack.removeLast(); + extents_stack.remove(extents_stack.size() - 1); + + + if (query_inflated.contains(current_extent)) { + intersection_count += getSubTreeElementCount(current_quad_handle); + + if (max_count > 0 && intersection_count >= max_count) + return max_count; + } else { + if (query_inflated.isIntersecting(current_extent)) { + for (int element_handle = get_first_element_(current_quad_handle); element_handle != -1; element_handle = get_next_element_(element_handle)) { + int data_handle = get_data_(element_handle); + Envelope2D env = get_bounding_box_value_(data_handle); + + if (env.isIntersecting(query_inflated)) { + intersection_count++; + + if (max_count > 0 && intersection_count >= max_count) + return max_count; + } + } + + b_subdivide = getHeight(current_quad_handle) + 1 <= m_height; + } + } + + if (b_subdivide) { + set_child_extents_(current_extent, child_extents); + + for (int i = 0; i < 4; i++) { + int child_handle = get_child_(current_quad_handle, i); + + if (child_handle != -1 && getSubTreeElementCount(child_handle) > 0) { + boolean b_is_intersecting = query_inflated.isIntersecting(child_extents[i]); + + if (b_is_intersecting) { + quads_stack.add(child_handle); + extents_stack.add(new Envelope2D(child_extents[i].xmin, child_extents[i].ymin, child_extents[i].xmax, child_extents[i].ymax)); + } + } + } + } + } + + return intersection_count; + } + + /** + * Returns true if the quad tree has data intersecting the given query. + * \param query The Envelope_2D used for the query. + * \param tolerance The tolerance used for the intersection tests. + */ + boolean hasData(Envelope2D query, double tolerance) { + int count = getIntersectionCount(query, tolerance, 1); + return count >= 1; + } + + /** + * Gets an iterator on the Quad_tree_impl. The query will be the Envelope_2D + * that bounds the input Geometry. To reuse the existing iterator on the + * same Quad_tree_impl but with a new query, use the reset_iterator function + * on the Quad_tree_iterator_impl. \param query The Geometry used for the + * query. If the Geometry is a Line segment, then the query will be the + * segment. Otherwise the query will be the Envelope_2D bounding the + * Geometry. \param tolerance The tolerance used for the intersection tests. + */ + QuadTreeIteratorImpl getIterator(Geometry query, double tolerance) { + return new QuadTreeIteratorImpl(this, query, tolerance); + } + + /** + * Gets an iterator on the Quad_tree_impl using the input Envelope_2D as the + * query. To reuse the existing iterator on the same Quad_tree_impl but with + * a new query, use the reset_iterator function on the + * Quad_tree_iterator_impl. \param query The Envelope_2D used for the query. + * \param tolerance The tolerance used for the intersection tests. + */ + QuadTreeIteratorImpl getIterator(Envelope2D query, double tolerance) { + return new QuadTreeIteratorImpl(this, query, tolerance); + } + + /** + * Gets an iterator on the Quad_tree. + */ + QuadTreeIteratorImpl getIterator() { + return new QuadTreeIteratorImpl(this); + } + + /** + * Gets a sorted iterator on the Quad_tree_impl. The Element_handles will be returned in increasing order of their corresponding Element_types. + * The query will be the Envelope_2D that bounds the input Geometry. + * To reuse the existing iterator on the same Quad_tree_impl but with a new query, use the reset_iterator function on the Quad_tree_sorted_iterator_impl. + * \param query The Geometry used for the query. If the Geometry is a Line segment, then the query will be the segment. Otherwise the query will be the Envelope_2D bounding the Geometry. + * \param tolerance The tolerance used for the intersection tests. + */ + QuadTreeSortedIteratorImpl getSortedIterator(Geometry query, double tolerance) { + return new QuadTreeSortedIteratorImpl(getIterator(query, tolerance)); + } + + /** + * Gets a sorted iterator on the Quad_tree_impl using the input Envelope_2D as the query. The Element_handles will be returned in increasing order of their corresponding Element_types. + * To reuse the existing iterator on the same Quad_tree_impl but with a new query, use the reset_iterator function on the Quad_tree_iterator_impl. + * \param query The Envelope_2D used for the query. + * \param tolerance The tolerance used for the intersection tests. + */ + QuadTreeSortedIteratorImpl getSortedIterator(Envelope2D query, double tolerance) { + return new QuadTreeSortedIteratorImpl(getIterator(query, tolerance)); + } + + /** + * Gets a sorted iterator on the Quad_tree. The Element_handles will be returned in increasing order of their corresponding Element_types + */ + QuadTreeSortedIteratorImpl getSortedIterator() { + return new QuadTreeSortedIteratorImpl(getIterator()); + } + + public long estimateMemorySize() + { + long size = SIZE_OF_QUAD_TREE_IMPL + + (m_extent != null ? m_extent.estimateMemorySize() : 0) + + (m_data_extent != null ? m_data_extent.estimateMemorySize() : 0) + + (m_quad_tree_nodes != null ? m_quad_tree_nodes.estimateMemorySize() : 0) + + (m_element_nodes != null ? m_element_nodes.estimateMemorySize() : 0) + + (m_free_data != null ? m_free_data.estimateMemorySize() : 0); + + if (m_data != null) { + size += sizeOfObjectArray(m_data.size()) + m_data.size() * SIZE_OF_DATA; + } + + return size; + } + + private void reset_(Envelope2D extent, int height) { + if (height < 0 || height > 127) + throw new IllegalArgumentException("invalid height"); + + m_height = height; + m_extent.setCoords(extent); + m_root = m_quad_tree_nodes.newElement(); + m_data_extent.setEmpty(); + m_root = -1; + } + + private int insert_(int element, Envelope2D bounding_box, int height, Envelope2D quad_extent, int quad_handle, boolean b_flushing, int flushed_element_handle) { + if (!quad_extent.contains(bounding_box)) { + assert (!b_flushing); + + if (height == 0) + return -1; + + return insert_(element, bounding_box, 0, m_extent, m_root, b_flushing, flushed_element_handle); + } + + if (!b_flushing) { + for (int q = quad_handle; q != -1; q = get_parent_(q)) + set_sub_tree_element_count_(q, get_sub_tree_element_count_(q) + 1); + } + + Envelope2D current_extent = new Envelope2D(); + current_extent.setCoords(quad_extent); + + int current_quad_handle = quad_handle; + + Envelope2D[] child_extents = new Envelope2D[4]; + child_extents[0] = new Envelope2D(); + child_extents[1] = new Envelope2D(); + child_extents[2] = new Envelope2D(); + child_extents[3] = new Envelope2D(); + + int current_height; + for (current_height = height; current_height < m_height && can_push_down_(current_quad_handle); current_height++) { + set_child_extents_(current_extent, child_extents); + + boolean b_contains = false; + + for (int i = 0; i < 4; i++) { + if (child_extents[i].contains(bounding_box)) { + b_contains = true; + + int child_handle = get_child_(current_quad_handle, i); + if (child_handle == -1) + child_handle = create_child_(current_quad_handle, i); + + set_sub_tree_element_count_(child_handle, get_sub_tree_element_count_(child_handle) + 1); + + current_quad_handle = child_handle; + current_extent.setCoords(child_extents[i]); + break; + } + } + + if (!b_contains) + break; + } + + return insert_at_quad_(element, bounding_box, current_height, current_extent, current_quad_handle, b_flushing, quad_handle, flushed_element_handle, -1); + } + + private int insert_duplicates_(int element, Envelope2D bounding_box, int height, Envelope2D quad_extent, int quad_handle, boolean b_flushing, int flushed_element_handle) { + assert (b_flushing || m_root == quad_handle); + + if (!b_flushing) // If b_flushing is true, then the sub tree element counts are already accounted for since the element already lies in the current incoming quad + { + if (!quad_extent.contains(bounding_box)) + return -1; + + set_sub_tree_element_count_(quad_handle, get_sub_tree_element_count_(quad_handle) + 1); + set_contained_sub_tree_element_count_(quad_handle, get_contained_sub_tree_element_count_(quad_handle) + 1); + } + + double bounding_box_max_dim = Math.max(bounding_box.getWidth(), bounding_box.getHeight()); + + int element_handle = -1; + AttributeStreamOfInt32 quads_stack = new AttributeStreamOfInt32(0); + ArrayList extents_stack = new ArrayList(0); + AttributeStreamOfInt32 heights_stack = new AttributeStreamOfInt32(0); + quads_stack.add(quad_handle); + extents_stack.add(new Envelope2D(quad_extent.xmin, quad_extent.ymin, quad_extent.xmax, quad_extent.ymax)); + heights_stack.add(height); + + Envelope2D[] child_extents = new Envelope2D[4]; + child_extents[0] = new Envelope2D(); + child_extents[1] = new Envelope2D(); + child_extents[2] = new Envelope2D(); + child_extents[3] = new Envelope2D(); + + Envelope2D current_extent = new Envelope2D(); + + while (quads_stack.size() > 0) { + boolean b_subdivide = false; + + int current_quad_handle = quads_stack.getLast(); + current_extent.setCoords(extents_stack.get(extents_stack.size() - 1)); + int current_height = heights_stack.getLast(); + + quads_stack.removeLast(); + extents_stack.remove(extents_stack.size() - 1); + heights_stack.removeLast(); + + if (current_height + 1 < m_height && can_push_down_(current_quad_handle)) { + double current_extent_max_dim = Math.max(current_extent.getWidth(), current_extent.getHeight()); + + if (bounding_box_max_dim <= current_extent_max_dim / 2.0) + b_subdivide = true; + } - if (b_subdivide) { - set_child_extents_(current_extent, child_extents); - - boolean b_contains = false; - - for (int i = 0; i < 4; i++) { - b_contains = child_extents[i].contains(bounding_box); - - if (b_contains) { - int child_handle = get_child_(current_quad_handle, i); - if (child_handle == -1) - child_handle = create_child_(current_quad_handle, i); - - quads_stack.add(child_handle); - extents_stack.add(new Envelope2D(child_extents[i].xmin, child_extents[i].ymin, child_extents[i].xmax, child_extents[i].ymax)); - heights_stack.add(current_height + 1); - - set_sub_tree_element_count_(child_handle, get_sub_tree_element_count_(child_handle) + 1); - set_contained_sub_tree_element_count_(child_handle, get_contained_sub_tree_element_count_(child_handle) + 1); - break; - } - } - - if (!b_contains) { - for (int i = 0; i < 4; i++) { - boolean b_intersects = child_extents[i].isIntersecting(bounding_box); - - if (b_intersects) { - int child_handle = get_child_(current_quad_handle, i); - if (child_handle == -1) - child_handle = create_child_(current_quad_handle, i); - - quads_stack.add(child_handle); - extents_stack.add(new Envelope2D(child_extents[i].xmin, child_extents[i].ymin, child_extents[i].xmax, child_extents[i].ymax)); - heights_stack.add(current_height + 1); - - set_sub_tree_element_count_(child_handle, get_sub_tree_element_count_(child_handle) + 1); - } - } - } - } else { - element_handle = insert_at_quad_(element, bounding_box, current_height, current_extent, current_quad_handle, b_flushing, quad_handle, flushed_element_handle, element_handle); - b_flushing = false; // flushing is false after the first inserted element has been flushed down, all subsequent inserts will be new - } - } - - return 0; - } - - private int insert_at_quad_(int element, Envelope2D bounding_box, int current_height, Envelope2D current_extent, int current_quad_handle, boolean b_flushing, int quad_handle, int flushed_element_handle, int duplicate_element_handle) { - // If the bounding box is not contained in any of the current_node's children, or if the current_height is m_height, then insert the element and - // bounding box into the current_node - - int head_element_handle = get_first_element_(current_quad_handle); - int tail_element_handle = get_last_element_(current_quad_handle); - int element_handle = -1; - - if (b_flushing) { - assert (flushed_element_handle != -1); - - if (current_quad_handle == quad_handle) - return flushed_element_handle; - - disconnect_element_handle_(flushed_element_handle); // Take it out of the incoming quad_handle, and place in current_quad_handle - element_handle = flushed_element_handle; - } else { - if (duplicate_element_handle == -1) { - element_handle = create_element_(); - set_data_values_(get_data_(element_handle), element, bounding_box); - } else { - assert (m_b_store_duplicates); - element_handle = create_element_from_duplicate_(duplicate_element_handle); - } - } - - assert (!b_flushing || element_handle == flushed_element_handle); - - set_quad_(element_handle, current_quad_handle); // set parent quad (needed for removal of element) - - // assign the prev pointer of the new tail to point at the old tail (tail_element_handle) - // assign the next pointer of the old tail to point at the new tail (next_element_handle) - if (tail_element_handle != -1) { - set_prev_element_(element_handle, tail_element_handle); - set_next_element_(tail_element_handle, element_handle); - } else { - assert (head_element_handle == -1); - set_first_element_(current_quad_handle, element_handle); - } - - // assign the new tail - set_last_element_(current_quad_handle, element_handle); - - set_local_element_count_(current_quad_handle, get_local_element_count_(current_quad_handle) + 1); - - if (can_flush_(current_quad_handle)) - flush_(current_height, current_extent, current_quad_handle); - - return element_handle; - } - - private static void set_child_extents_(Envelope2D current_extent, Envelope2D[] child_extents) { - double x_mid = 0.5 * (current_extent.xmin + current_extent.xmax); - double y_mid = 0.5 * (current_extent.ymin + current_extent.ymax); - - child_extents[0].setCoords(x_mid, y_mid, current_extent.xmax, current_extent.ymax); // northeast - child_extents[1].setCoords(current_extent.xmin, y_mid, x_mid, current_extent.ymax); // northwest - child_extents[2].setCoords(current_extent.xmin, current_extent.ymin, x_mid, y_mid); // southwest - child_extents[3].setCoords(x_mid, current_extent.ymin, current_extent.xmax, y_mid); // southeast - } - - private void disconnect_element_handle_(int element_handle) { - assert (element_handle != -1); - int quad_handle = get_quad_(element_handle); - int head_element_handle = get_first_element_(quad_handle); - int tail_element_handle = get_last_element_(quad_handle); - int prev_element_handle = get_prev_element_(element_handle); - int next_element_handle = get_next_element_(element_handle); - assert (head_element_handle != -1 && tail_element_handle != -1); - - if (head_element_handle == element_handle) { - if (next_element_handle != -1) - set_prev_element_(next_element_handle, -1); - else { - assert (head_element_handle == tail_element_handle); - assert (get_local_element_count_(quad_handle) == 1); - set_last_element_(quad_handle, -1); - } - - set_first_element_(quad_handle, next_element_handle); - } else if (tail_element_handle == element_handle) { - assert (prev_element_handle != -1); - assert (get_local_element_count_(quad_handle) >= 2); - set_next_element_(prev_element_handle, -1); - set_last_element_(quad_handle, prev_element_handle); - } else { - assert (next_element_handle != -1 && prev_element_handle != -1); - assert (get_local_element_count_(quad_handle) >= 3); - set_prev_element_(next_element_handle, prev_element_handle); - set_next_element_(prev_element_handle, next_element_handle); - } - - set_prev_element_(element_handle, -1); - set_next_element_(element_handle, -1); - - set_local_element_count_(quad_handle, get_local_element_count_(quad_handle) - 1); - assert (get_local_element_count_(quad_handle) >= 0); - } - - private boolean can_flush_(int quad_handle) { - return get_local_element_count_(quad_handle) == m_flushing_count && !has_children_(quad_handle); - } - - private void flush_(int height, Envelope2D extent, int quad_handle) { - int element; - Envelope2D bounding_box = new Envelope2D(); - - assert (quad_handle != -1); - - int element_handle = get_first_element_(quad_handle), next_handle = -1; - int data_handle = -1; - assert (element_handle != -1); - - do { - data_handle = get_data_(element_handle); - element = get_element_value_(data_handle); - bounding_box.setCoords(get_bounding_box_value_(data_handle)); - - next_handle = get_next_element_(element_handle); - - if (!m_b_store_duplicates) - insert_(element, bounding_box, height, extent, quad_handle, true, element_handle); - else - insert_duplicates_(element, bounding_box, height, extent, quad_handle, true, element_handle); - - element_handle = next_handle; - - } while (element_handle != -1); - } - - private boolean can_push_down_(int quad_handle) { - return get_local_element_count_(quad_handle) >= m_flushing_count || has_children_(quad_handle); - } - - private boolean has_children_(int parent) { - return get_child_(parent, 0) != -1 || get_child_(parent, 1) != -1 || get_child_(parent, 2) != -1 || get_child_(parent, 3) != -1; - } - - private int create_child_(int parent, int quadrant) { - int child = m_quad_tree_nodes.newElement(); - set_child_(parent, quadrant, child); - set_sub_tree_element_count_(child, 0); - set_local_element_count_(child, 0); - set_parent_(child, parent); - set_height_and_quadrant_(child, get_height_(parent) + 1, quadrant); - - if (m_b_store_duplicates) - set_contained_sub_tree_element_count_(child, 0); - - return child; - } - - private void create_root_() { - m_root = m_quad_tree_nodes.newElement(); - set_sub_tree_element_count_(m_root, 0); - set_local_element_count_(m_root, 0); - set_height_and_quadrant_(m_root, 0, 0); - - if (m_b_store_duplicates) - set_contained_sub_tree_element_count_(m_root, 0); - } - - private int create_element_() { - int element_handle = m_element_nodes.newElement(); - int data_handle; - - if (m_free_data.size() > 0) { - data_handle = m_free_data.get(m_free_data.size() - 1); - m_free_data.removeLast(); - } else { - data_handle = m_data.size(); - m_data.add(null); - } - - set_data_(element_handle, data_handle); - return element_handle; - } - - private int create_element_from_duplicate_(int duplicate_element_handle) { - int element_handle = m_element_nodes.newElement(); - int data_handle = get_data_(duplicate_element_handle); - set_data_(element_handle, data_handle); - return element_handle; - } - - private void free_element_and_box_node_(int element_handle) { - int data_handle = get_data_(element_handle); - m_free_data.add(data_handle); - m_element_nodes.deleteElement(element_handle); - } - - private int get_child_(int quad_handle, int quadrant) { - return m_quad_tree_nodes.getField(quad_handle, quadrant); - } - - private void set_child_(int parent, int quadrant, int child) { - m_quad_tree_nodes.setField(parent, quadrant, child); - } - - private int get_first_element_(int quad_handle) { - return m_quad_tree_nodes.getField(quad_handle, 4); - } - - private void set_first_element_(int quad_handle, int head) { - m_quad_tree_nodes.setField(quad_handle, 4, head); - } - - private int get_last_element_(int quad_handle) { - return m_quad_tree_nodes.getField(quad_handle, 5); - } - - private void set_last_element_(int quad_handle, int tail) { - m_quad_tree_nodes.setField(quad_handle, 5, tail); - } - - - private int get_quadrant_(int quad_handle) { - int height_quadrant_hybrid = m_quad_tree_nodes.getField(quad_handle, 6); - int quadrant = height_quadrant_hybrid & m_quadrant_mask; - return quadrant; - } - - private int get_height_(int quad_handle) { - int height_quadrant_hybrid = m_quad_tree_nodes.getField(quad_handle, 6); - int height = height_quadrant_hybrid >> m_height_bit_shift; - return height; - } - - private void set_height_and_quadrant_(int quad_handle, int height, int quadrant) { - assert (quadrant >= 0 && quadrant <= 3); - int height_quadrant_hybrid = (int) ((height << m_height_bit_shift) | quadrant); - m_quad_tree_nodes.setField(quad_handle, 6, height_quadrant_hybrid); - } - - private int get_local_element_count_(int quad_handle) { - return m_quad_tree_nodes.getField(quad_handle, 7); - } - - private void set_local_element_count_(int quad_handle, int count) { - m_quad_tree_nodes.setField(quad_handle, 7, count); - } - - private int get_sub_tree_element_count_(int quad_handle) { - return m_quad_tree_nodes.getField(quad_handle, 8); - } - - private void set_sub_tree_element_count_(int quad_handle, int count) { - m_quad_tree_nodes.setField(quad_handle, 8, count); - } - - private int get_parent_(int child) { - return m_quad_tree_nodes.getField(child, 9); - } - - private void set_parent_(int child, int parent) { - m_quad_tree_nodes.setField(child, 9, parent); - } - - private int get_contained_sub_tree_element_count_(int quad_handle) { - return m_quad_tree_nodes.getField(quad_handle, 10); - } - - private void set_contained_sub_tree_element_count_(int quad_handle, int count) { - m_quad_tree_nodes.setField(quad_handle, 10, count); - } - - private int get_data_(int element_handle) { - return m_element_nodes.getField(element_handle, 0); - } - - private void set_data_(int element_handle, int data_handle) { - m_element_nodes.setField(element_handle, 0, data_handle); - } - - private int get_prev_element_(int element_handle) { - return m_element_nodes.getField(element_handle, 1); - } - - private int get_next_element_(int element_handle) { - return m_element_nodes.getField(element_handle, 2); - } - - private void set_prev_element_(int element_handle, int prev_handle) { - m_element_nodes.setField(element_handle, 1, prev_handle); - } - - private void set_next_element_(int element_handle, int next_handle) { - m_element_nodes.setField(element_handle, 2, next_handle); - } - - private int get_quad_(int element_handle) { - return m_element_nodes.getField(element_handle, 3); - } - - private void set_quad_(int element_handle, int parent) { - m_element_nodes.setField(element_handle, 3, parent); - } - - private int get_element_value_(int data_handle) { - return m_data.get(data_handle).element; - } - - private Envelope2D get_bounding_box_value_(int data_handle) { - return m_data.get(data_handle).box; - } - - private void set_data_values_(int data_handle, int element, Envelope2D bounding_box) { - m_data.set(data_handle, new Data(element, bounding_box)); - } - - private Envelope2D m_extent; - private Envelope2D m_data_extent; - private StridedIndexTypeCollection m_quad_tree_nodes; - private StridedIndexTypeCollection m_element_nodes; - private ArrayList m_data; - private AttributeStreamOfInt32 m_free_data; - private int m_root; - private int m_height; - private boolean m_b_store_duplicates; - - private int m_quadrant_mask = 3; - private int m_height_bit_shift = 2; - private int m_flushing_count = 5; - - static final class Data { - int element; - Envelope2D box; - - Data(int element_, Envelope2D box_) { - element = element_; - box = new Envelope2D(); - box.setCoords(box_); - } - } + if (b_subdivide) { + set_child_extents_(current_extent, child_extents); + + boolean b_contains = false; + + for (int i = 0; i < 4; i++) { + b_contains = child_extents[i].contains(bounding_box); + + if (b_contains) { + int child_handle = get_child_(current_quad_handle, i); + if (child_handle == -1) + child_handle = create_child_(current_quad_handle, i); + + quads_stack.add(child_handle); + extents_stack.add(new Envelope2D(child_extents[i].xmin, child_extents[i].ymin, child_extents[i].xmax, child_extents[i].ymax)); + heights_stack.add(current_height + 1); + + set_sub_tree_element_count_(child_handle, get_sub_tree_element_count_(child_handle) + 1); + set_contained_sub_tree_element_count_(child_handle, get_contained_sub_tree_element_count_(child_handle) + 1); + break; + } + } + + if (!b_contains) { + for (int i = 0; i < 4; i++) { + boolean b_intersects = child_extents[i].isIntersecting(bounding_box); + + if (b_intersects) { + int child_handle = get_child_(current_quad_handle, i); + if (child_handle == -1) + child_handle = create_child_(current_quad_handle, i); + + quads_stack.add(child_handle); + extents_stack.add(new Envelope2D(child_extents[i].xmin, child_extents[i].ymin, child_extents[i].xmax, child_extents[i].ymax)); + heights_stack.add(current_height + 1); + + set_sub_tree_element_count_(child_handle, get_sub_tree_element_count_(child_handle) + 1); + } + } + } + } else { + element_handle = insert_at_quad_(element, bounding_box, current_height, current_extent, current_quad_handle, b_flushing, quad_handle, flushed_element_handle, element_handle); + b_flushing = false; // flushing is false after the first inserted element has been flushed down, all subsequent inserts will be new + } + } + + return 0; + } + + private int insert_at_quad_(int element, Envelope2D bounding_box, int current_height, Envelope2D current_extent, int current_quad_handle, boolean b_flushing, int quad_handle, int flushed_element_handle, int duplicate_element_handle) { + // If the bounding box is not contained in any of the current_node's children, or if the current_height is m_height, then insert the element and + // bounding box into the current_node + + int head_element_handle = get_first_element_(current_quad_handle); + int tail_element_handle = get_last_element_(current_quad_handle); + int element_handle = -1; + + if (b_flushing) { + assert (flushed_element_handle != -1); + + if (current_quad_handle == quad_handle) + return flushed_element_handle; + + disconnect_element_handle_(flushed_element_handle); // Take it out of the incoming quad_handle, and place in current_quad_handle + element_handle = flushed_element_handle; + } else { + if (duplicate_element_handle == -1) { + element_handle = create_element_(); + set_data_values_(get_data_(element_handle), element, bounding_box); + } else { + assert (m_b_store_duplicates); + element_handle = create_element_from_duplicate_(duplicate_element_handle); + } + } + + assert (!b_flushing || element_handle == flushed_element_handle); + + set_quad_(element_handle, current_quad_handle); // set parent quad (needed for removal of element) + + // assign the prev pointer of the new tail to point at the old tail (tail_element_handle) + // assign the next pointer of the old tail to point at the new tail (next_element_handle) + if (tail_element_handle != -1) { + set_prev_element_(element_handle, tail_element_handle); + set_next_element_(tail_element_handle, element_handle); + } else { + assert (head_element_handle == -1); + set_first_element_(current_quad_handle, element_handle); + } + + // assign the new tail + set_last_element_(current_quad_handle, element_handle); + + set_local_element_count_(current_quad_handle, get_local_element_count_(current_quad_handle) + 1); + + if (can_flush_(current_quad_handle)) + flush_(current_height, current_extent, current_quad_handle); + + return element_handle; + } + + private static void set_child_extents_(Envelope2D current_extent, Envelope2D[] child_extents) { + double x_mid = 0.5 * (current_extent.xmin + current_extent.xmax); + double y_mid = 0.5 * (current_extent.ymin + current_extent.ymax); + + child_extents[0].setCoords(x_mid, y_mid, current_extent.xmax, current_extent.ymax); // northeast + child_extents[1].setCoords(current_extent.xmin, y_mid, x_mid, current_extent.ymax); // northwest + child_extents[2].setCoords(current_extent.xmin, current_extent.ymin, x_mid, y_mid); // southwest + child_extents[3].setCoords(x_mid, current_extent.ymin, current_extent.xmax, y_mid); // southeast + } + + private void disconnect_element_handle_(int element_handle) { + assert (element_handle != -1); + int quad_handle = get_quad_(element_handle); + int head_element_handle = get_first_element_(quad_handle); + int tail_element_handle = get_last_element_(quad_handle); + int prev_element_handle = get_prev_element_(element_handle); + int next_element_handle = get_next_element_(element_handle); + assert (head_element_handle != -1 && tail_element_handle != -1); + + if (head_element_handle == element_handle) { + if (next_element_handle != -1) + set_prev_element_(next_element_handle, -1); + else { + assert (head_element_handle == tail_element_handle); + assert (get_local_element_count_(quad_handle) == 1); + set_last_element_(quad_handle, -1); + } + + set_first_element_(quad_handle, next_element_handle); + } else if (tail_element_handle == element_handle) { + assert (prev_element_handle != -1); + assert (get_local_element_count_(quad_handle) >= 2); + set_next_element_(prev_element_handle, -1); + set_last_element_(quad_handle, prev_element_handle); + } else { + assert (next_element_handle != -1 && prev_element_handle != -1); + assert (get_local_element_count_(quad_handle) >= 3); + set_prev_element_(next_element_handle, prev_element_handle); + set_next_element_(prev_element_handle, next_element_handle); + } + + set_prev_element_(element_handle, -1); + set_next_element_(element_handle, -1); + + set_local_element_count_(quad_handle, get_local_element_count_(quad_handle) - 1); + assert (get_local_element_count_(quad_handle) >= 0); + } + + private boolean can_flush_(int quad_handle) { + return get_local_element_count_(quad_handle) == m_flushing_count && !has_children_(quad_handle); + } + + private void flush_(int height, Envelope2D extent, int quad_handle) { + int element; + Envelope2D bounding_box = new Envelope2D(); + + assert (quad_handle != -1); + + int element_handle = get_first_element_(quad_handle), next_handle = -1; + int data_handle = -1; + assert (element_handle != -1); + + do { + data_handle = get_data_(element_handle); + element = get_element_value_(data_handle); + bounding_box.setCoords(get_bounding_box_value_(data_handle)); + + next_handle = get_next_element_(element_handle); + + if (!m_b_store_duplicates) + insert_(element, bounding_box, height, extent, quad_handle, true, element_handle); + else + insert_duplicates_(element, bounding_box, height, extent, quad_handle, true, element_handle); + + element_handle = next_handle; + + } while (element_handle != -1); + } + + private boolean can_push_down_(int quad_handle) { + return get_local_element_count_(quad_handle) >= m_flushing_count || has_children_(quad_handle); + } + + private boolean has_children_(int parent) { + return get_child_(parent, 0) != -1 || get_child_(parent, 1) != -1 || get_child_(parent, 2) != -1 || get_child_(parent, 3) != -1; + } + + private int create_child_(int parent, int quadrant) { + int child = m_quad_tree_nodes.newElement(); + set_child_(parent, quadrant, child); + set_sub_tree_element_count_(child, 0); + set_local_element_count_(child, 0); + set_parent_(child, parent); + set_height_and_quadrant_(child, get_height_(parent) + 1, quadrant); + + if (m_b_store_duplicates) + set_contained_sub_tree_element_count_(child, 0); + + return child; + } + + private void create_root_() { + m_root = m_quad_tree_nodes.newElement(); + set_sub_tree_element_count_(m_root, 0); + set_local_element_count_(m_root, 0); + set_height_and_quadrant_(m_root, 0, 0); + + if (m_b_store_duplicates) + set_contained_sub_tree_element_count_(m_root, 0); + } + + private int create_element_() { + int element_handle = m_element_nodes.newElement(); + int data_handle; + + if (m_free_data.size() > 0) { + data_handle = m_free_data.get(m_free_data.size() - 1); + m_free_data.removeLast(); + } else { + data_handle = m_data.size(); + m_data.add(null); + } + + set_data_(element_handle, data_handle); + return element_handle; + } + + private int create_element_from_duplicate_(int duplicate_element_handle) { + int element_handle = m_element_nodes.newElement(); + int data_handle = get_data_(duplicate_element_handle); + set_data_(element_handle, data_handle); + return element_handle; + } + + private void free_element_and_box_node_(int element_handle) { + int data_handle = get_data_(element_handle); + m_free_data.add(data_handle); + m_element_nodes.deleteElement(element_handle); + } + + private int get_child_(int quad_handle, int quadrant) { + return m_quad_tree_nodes.getField(quad_handle, quadrant); + } + + private void set_child_(int parent, int quadrant, int child) { + m_quad_tree_nodes.setField(parent, quadrant, child); + } + + private int get_first_element_(int quad_handle) { + return m_quad_tree_nodes.getField(quad_handle, 4); + } + + private void set_first_element_(int quad_handle, int head) { + m_quad_tree_nodes.setField(quad_handle, 4, head); + } + + private int get_last_element_(int quad_handle) { + return m_quad_tree_nodes.getField(quad_handle, 5); + } + + private void set_last_element_(int quad_handle, int tail) { + m_quad_tree_nodes.setField(quad_handle, 5, tail); + } + + + private int get_quadrant_(int quad_handle) { + int height_quadrant_hybrid = m_quad_tree_nodes.getField(quad_handle, 6); + int quadrant = height_quadrant_hybrid & m_quadrant_mask; + return quadrant; + } + + private int get_height_(int quad_handle) { + int height_quadrant_hybrid = m_quad_tree_nodes.getField(quad_handle, 6); + int height = height_quadrant_hybrid >> m_height_bit_shift; + return height; + } + + private void set_height_and_quadrant_(int quad_handle, int height, int quadrant) { + assert (quadrant >= 0 && quadrant <= 3); + int height_quadrant_hybrid = (int) ((height << m_height_bit_shift) | quadrant); + m_quad_tree_nodes.setField(quad_handle, 6, height_quadrant_hybrid); + } + + private int get_local_element_count_(int quad_handle) { + return m_quad_tree_nodes.getField(quad_handle, 7); + } + + private void set_local_element_count_(int quad_handle, int count) { + m_quad_tree_nodes.setField(quad_handle, 7, count); + } + + private int get_sub_tree_element_count_(int quad_handle) { + return m_quad_tree_nodes.getField(quad_handle, 8); + } + + private void set_sub_tree_element_count_(int quad_handle, int count) { + m_quad_tree_nodes.setField(quad_handle, 8, count); + } + + private int get_parent_(int child) { + return m_quad_tree_nodes.getField(child, 9); + } + + private void set_parent_(int child, int parent) { + m_quad_tree_nodes.setField(child, 9, parent); + } + + private int get_contained_sub_tree_element_count_(int quad_handle) { + return m_quad_tree_nodes.getField(quad_handle, 10); + } + + private void set_contained_sub_tree_element_count_(int quad_handle, int count) { + m_quad_tree_nodes.setField(quad_handle, 10, count); + } + + private int get_data_(int element_handle) { + return m_element_nodes.getField(element_handle, 0); + } + + private void set_data_(int element_handle, int data_handle) { + m_element_nodes.setField(element_handle, 0, data_handle); + } + + private int get_prev_element_(int element_handle) { + return m_element_nodes.getField(element_handle, 1); + } + + private int get_next_element_(int element_handle) { + return m_element_nodes.getField(element_handle, 2); + } + + private void set_prev_element_(int element_handle, int prev_handle) { + m_element_nodes.setField(element_handle, 1, prev_handle); + } + + private void set_next_element_(int element_handle, int next_handle) { + m_element_nodes.setField(element_handle, 2, next_handle); + } + + private int get_quad_(int element_handle) { + return m_element_nodes.getField(element_handle, 3); + } + + private void set_quad_(int element_handle, int parent) { + m_element_nodes.setField(element_handle, 3, parent); + } + + private int get_element_value_(int data_handle) { + return m_data.get(data_handle).element; + } + + private Envelope2D get_bounding_box_value_(int data_handle) { + return m_data.get(data_handle).box; + } + + private void set_data_values_(int data_handle, int element, Envelope2D bounding_box) { + m_data.set(data_handle, new Data(element, bounding_box)); + } + + private Envelope2D m_extent; + private Envelope2D m_data_extent; + private StridedIndexTypeCollection m_quad_tree_nodes; + private StridedIndexTypeCollection m_element_nodes; + transient private ArrayList m_data; + private AttributeStreamOfInt32 m_free_data; + private int m_root; + private int m_height; + private boolean m_b_store_duplicates; + + final static private int m_quadrant_mask = 3; + final static private int m_height_bit_shift = 2; + final static private int m_flushing_count = 5; + + static final class Data { + int element; + Envelope2D box; + + Data(int element_, double x1, double y1, double x2, double y2) { + element = element_; + box = new Envelope2D(); + box.setCoords(x1, y1, x2, y2); + } + + Data(int element_, Envelope2D box_) { + element = element_; + box = new Envelope2D(); + box.setCoords(box_); + } + } + + private void writeObject(java.io.ObjectOutputStream stream) + throws IOException { + stream.defaultWriteObject(); + stream.writeInt(m_data.size()); + for (int i = 0, n = m_data.size(); i < n; ++i) { + Data d = m_data.get(i); + if (d != null) { + stream.writeByte(1); + stream.writeInt(d.element); + stream.writeDouble(d.box.xmin); + stream.writeDouble(d.box.ymin); + stream.writeDouble(d.box.xmax); + stream.writeDouble(d.box.ymax); + } + else { + stream.writeByte(0); + } + + } + } + + private void readObject(java.io.ObjectInputStream stream) + throws IOException, ClassNotFoundException { + stream.defaultReadObject(); + int dataSize = stream.readInt(); + m_data = new ArrayList(dataSize); + for (int i = 0, n = dataSize; i < n; ++i) { + int b = stream.readByte(); + if (b == 1) { + int elm = stream.readInt(); + double x1 = stream.readDouble(); + double y1 = stream.readDouble(); + double x2 = stream.readDouble(); + double y2 = stream.readDouble(); + Data d = new Data(elm, x1, y1, x2, y2); + m_data.add(d); + } + else if (b == 0) { + m_data.add(null); + } + else { + throw new IOException(); + } + } + } + + @SuppressWarnings("unused") + private void readObjectNoData() throws ObjectStreamException { + throw new InvalidObjectException("Stream data required"); + } /* m_quad_tree_nodes * 0: m_north_east_child diff --git a/src/main/java/com/esri/core/geometry/RandomPointMaker.java b/src/main/java/com/esri/core/geometry/RandomPointMaker.java index 1e6aec76..da4ec1a5 100644 --- a/src/main/java/com/esri/core/geometry/RandomPointMaker.java +++ b/src/main/java/com/esri/core/geometry/RandomPointMaker.java @@ -10,109 +10,109 @@ class RandomPointMaker { - /** - * This assumes an equal area projection - * - * @param geometry - * @param pointsPerSquareKm - * @param sr - * @param progressTracker - * @return - */ - static Geometry generate(Geometry geometry, - double pointsPerSquareKm, - Random numberGenerator, - SpatialReference sr, - ProgressTracker progressTracker) throws PJException { - if (geometry.getType() != Geometry.Type.Polygon && geometry.getType() != Geometry.Type.Envelope) - throw new GeometryException("Geometry input must be of type Polygon or Envelope"); - - if (sr == null || sr.isLocal()) - throw new GeometryException("Spatial reference must be defined and must have unit definition"); - - Polygon polygon = null; - if (geometry.getType() == Geometry.Type.Envelope) { - polygon = new Polygon(); - polygon.addEnvelope((Envelope) geometry, false); - } else { - polygon = (Polygon) geometry; - } - - // TODO should iterate over paths - // TODO iterator should check for containment. If a path is contained within another, random points shouldn't - // be generated for that contained path - // Ask Aaron if paths are written to attribute stream such that paths contained come after container paths - return __makeRandomPoints(polygon, pointsPerSquareKm, numberGenerator, sr, progressTracker); - } - - // TODO input should be multiplath - static Geometry __makeRandomPoints(Polygon polygon, - double pointsPerSquareKm, - Random numberGenerator, - SpatialReference sr, - ProgressTracker progressTracker) throws PJException { - // TODO for each ring project, in order to prevent from creating an excess of points if two parts of a polygon are on opposite sides of the globe. - - ProjectionTransformation forwardProjectionTransformation = ProjectionTransformation.getEqualArea(polygon, sr); - - Envelope env = new Envelope(); - polygon.queryEnvelope(env); - // Project bounding coordinates to equal area - // equalAreaEnvelopeGeom must be a geometry/polygon because projection of envelope will almost certainly - // or skew geometry - // TODO, maybe it would be computationally cheaper or more accurate to project input polygon instead of it's envelope - Geometry equalAreaEnvelopeGeom = OperatorProject.local().execute(env, forwardProjectionTransformation, progressTracker); - - Envelope2D equalAreaEnvelope = new Envelope2D(); - // envelope of projected envelope - equalAreaEnvelopeGeom.queryEnvelope2D(equalAreaEnvelope); - - double areaKm = equalAreaEnvelope.getArea() / (1000.0 * 1000.0); - double pointCountNotCast = Math.ceil(areaKm * pointsPerSquareKm); - //http://stackoverflow.com/questions/3038392/do-java-arrays-have-a-maximum-size - if (pointCountNotCast * 2 > Integer.MAX_VALUE - 8) { - throw new GeometryException("Random Point count outside of available"); - } - int pointCount = (int) pointCountNotCast; - - // TODO if the area of the envelope is more than twice that of the initial polygon, maybe a raster creation - // of random multipoints would be required...? - - double[] xy = new double[pointCount * 2]; - - double xdiff = equalAreaEnvelope.xmax - equalAreaEnvelope.xmin; - double ydiff = equalAreaEnvelope.ymax - equalAreaEnvelope.ymin; - for (int i = 0; i < pointCount * 2; i++) { - if (i % 2 == 0) // x val - xy[i] = numberGenerator.nextDouble() * xdiff + equalAreaEnvelope.xmin; - else // y val - xy[i] = numberGenerator.nextDouble() * ydiff + equalAreaEnvelope.ymin; - } - - // Create Multipoint from vertices - MultiPoint multiPoint = new MultiPoint(); - MultiVertexGeometryImpl multiVertexGeometry = (MultiVertexGeometryImpl) multiPoint._getImpl(); - AttributeStreamOfDbl attributeStreamOfDbl = new AttributeStreamOfDbl(pointCount * 2); - - // TODO it would be better if we could just std::move the array. - attributeStreamOfDbl.writeRangeMove(xy); - multiVertexGeometry.setAttributeStreamRef(0, attributeStreamOfDbl); - //multiVertexGeometry._resizeImpl(pointCount); - multiPoint.resize(pointCount); - multiVertexGeometry._setDirtyFlag(DirtyFlags.dirtyAll, true); - - ProjectionTransformation backProjectionTransformation = forwardProjectionTransformation.getReverse(); - // project inplace instead of projecting a copy using OperatorProject::execute - Projecter.projectMultiPoint(multiPoint, backProjectionTransformation, progressTracker); - - - // TODO project multipoint back to input spatial reference (it is necessary to do it here, - // because if we projected the above array, then we wouldn't benefit from clipping - - // Intersect by input geometry - // TODO reduce densify distance? - Geometry intersector = OperatorGeodeticDensifyByLength.local().execute(polygon, sr, areaKm, GeodeticCurveType.Geodesic, null); + /** + * This assumes an equal area projection + * + * @param geometry + * @param pointsPerSquareKm + * @param sr + * @param progressTracker + * @return + */ + static Geometry generate(Geometry geometry, + double pointsPerSquareKm, + Random numberGenerator, + SpatialReference sr, + ProgressTracker progressTracker) throws PJException { + if (geometry.getType() != Geometry.Type.Polygon && geometry.getType() != Geometry.Type.Envelope) + throw new GeometryException("Geometry input must be of type Polygon or Envelope"); + + if (sr == null || sr.isLocal()) + throw new GeometryException("Spatial reference must be defined and must have unit definition"); + + Polygon polygon = null; + if (geometry.getType() == Geometry.Type.Envelope) { + polygon = new Polygon(); + polygon.addEnvelope((Envelope) geometry, false); + } else { + polygon = (Polygon) geometry; + } + + // TODO should iterate over paths + // TODO iterator should check for containment. If a path is contained within another, random points shouldn't + // be generated for that contained path + // Ask Aaron if paths are written to attribute stream such that paths contained come after container paths + return __makeRandomPoints(polygon, pointsPerSquareKm, numberGenerator, sr, progressTracker); + } + + // TODO input should be multiplath + static Geometry __makeRandomPoints(Polygon polygon, + double pointsPerSquareKm, + Random numberGenerator, + SpatialReference sr, + ProgressTracker progressTracker) throws PJException { + // TODO for each ring project, in order to prevent from creating an excess of points if two parts of a polygon are on opposite sides of the globe. + + ProjectionTransformation forwardProjectionTransformation = ProjectionTransformation.getEqualArea(polygon, sr); + + Envelope env = new Envelope(); + polygon.queryEnvelope(env); + // Project bounding coordinates to equal area + // equalAreaEnvelopeGeom must be a geometry/polygon because projection of envelope will almost certainly + // or skew geometry + // TODO, maybe it would be computationally cheaper or more accurate to project input polygon instead of it's envelope + Geometry equalAreaEnvelopeGeom = OperatorProject.local().execute(env, forwardProjectionTransformation, progressTracker); + + Envelope2D equalAreaEnvelope = new Envelope2D(); + // envelope of projected envelope + equalAreaEnvelopeGeom.queryEnvelope2D(equalAreaEnvelope); + + double areaKm = equalAreaEnvelope.getArea() / (1000.0 * 1000.0); + double pointCountNotCast = Math.ceil(areaKm * pointsPerSquareKm); + //http://stackoverflow.com/questions/3038392/do-java-arrays-have-a-maximum-size + if (pointCountNotCast * 2 > Integer.MAX_VALUE - 8) { + throw new GeometryException("Random Point count outside of available"); + } + int pointCount = (int) pointCountNotCast; + + // TODO if the area of the envelope is more than twice that of the initial polygon, maybe a raster creation + // of random multipoints would be required...? + + double[] xy = new double[pointCount * 2]; + + double xdiff = equalAreaEnvelope.xmax - equalAreaEnvelope.xmin; + double ydiff = equalAreaEnvelope.ymax - equalAreaEnvelope.ymin; + for (int i = 0; i < pointCount * 2; i++) { + if (i % 2 == 0) // x val + xy[i] = numberGenerator.nextDouble() * xdiff + equalAreaEnvelope.xmin; + else // y val + xy[i] = numberGenerator.nextDouble() * ydiff + equalAreaEnvelope.ymin; + } + + // Create Multipoint from vertices + MultiPoint multiPoint = new MultiPoint(); + MultiVertexGeometryImpl multiVertexGeometry = (MultiVertexGeometryImpl) multiPoint._getImpl(); + AttributeStreamOfDbl attributeStreamOfDbl = new AttributeStreamOfDbl(pointCount * 2); + + // TODO it would be better if we could just std::move the array. + attributeStreamOfDbl.writeRangeMove(xy); + multiVertexGeometry.setAttributeStreamRef(0, attributeStreamOfDbl); + //multiVertexGeometry._resizeImpl(pointCount); + multiPoint.resize(pointCount); + multiVertexGeometry._setDirtyFlag(DirtyFlags.dirtyAll, true); + + ProjectionTransformation backProjectionTransformation = forwardProjectionTransformation.getReverse(); + // project inplace instead of projecting a copy using OperatorProject::execute + Projecter.projectMultiPoint(multiPoint, backProjectionTransformation, progressTracker); + + + // TODO project multipoint back to input spatial reference (it is necessary to do it here, + // because if we projected the above array, then we wouldn't benefit from clipping + + // Intersect by input geometry + // TODO reduce densify distance? + Geometry intersector = OperatorGeodeticDensifyByLength.local().execute(polygon, sr, areaKm, GeodeticCurveType.Geodesic, null); // double geodeticDensify = 1 - return GeometryEngine.intersect(multiPoint, intersector, sr); - } + return GeometryEngine.intersect(multiPoint, intersector, sr); + } } diff --git a/src/main/java/com/esri/core/geometry/RasterizedGeometry2D.java b/src/main/java/com/esri/core/geometry/RasterizedGeometry2D.java index 86e1a5b4..ff1b8257 100644 --- a/src/main/java/com/esri/core/geometry/RasterizedGeometry2D.java +++ b/src/main/java/com/esri/core/geometry/RasterizedGeometry2D.java @@ -27,112 +27,119 @@ public abstract class RasterizedGeometry2D { - public enum HitType { - Outside(0), // the test geometry is well outside the geometry bounds - Inside(1), // the test geometry is well inside the geomety bounds - Border(2); // the test geometry is close to the bounds or intersects the - // bounds - - int enumVal; - - private HitType(int val) { - enumVal = val; - } - - ; - } - - /** - * Test a point against the RasterizedGeometry - */ - public abstract HitType queryPointInGeometry(double x, double y); - - /** - * Test an envelope against the RasterizedGeometry. - */ - public abstract HitType queryEnvelopeInGeometry(Envelope2D env); - - /** - * Creates a rasterized geometry from a given Geometry. - * - * @param geom The input geometry to rasterize. It has to be a MultiVertexGeometry instance. - * @param toleranceXY The tolerance of the rasterization. Raster pixels that are - * closer than given tolerance to the Geometry will be set. - * @param rasterSizeBytes The max size of the raster in bytes. The raster has size of - * rasterSize x rasterSize. Polygons are rasterized into 2 bpp - * (bits per pixel) rasters while other geometries are rasterized - * into 1 bpp rasters. 32x32 pixel raster for a polygon would - * take 256 bytes of memory - */ - public static RasterizedGeometry2D create(Geometry geom, - double toleranceXY, int rasterSizeBytes) { - if (!canUseAccelerator(geom)) - throw new IllegalArgumentException(); - - RasterizedGeometry2DImpl gc = RasterizedGeometry2DImpl.createImpl(geom, - toleranceXY, rasterSizeBytes); - return (RasterizedGeometry2D) gc; - } - - static RasterizedGeometry2D create(MultiVertexGeometryImpl geom, - double toleranceXY, int rasterSizeBytes) { - if (!canUseAccelerator(geom)) - throw new IllegalArgumentException(); - - RasterizedGeometry2DImpl gc = RasterizedGeometry2DImpl.createImpl(geom, - toleranceXY, rasterSizeBytes); - return (RasterizedGeometry2D) gc; - - } - - public static int rasterSizeFromAccelerationDegree( - GeometryAccelerationDegree accelDegree) { - int value = 0; - switch (accelDegree) { - case enumMild: - value = 64 * 64 * 2 / 8;// 1k - break; - case enumMedium: - value = 256 * 256 * 2 / 8;// 16k - break; - case enumHot: - value = 1024 * 1024 * 2 / 8;// 256k - break; - default: - throw GeometryException.GeometryInternalError(); - } - - return value; - } - - /** - * Checks whether the RasterizedGeometry2D accelerator can be used with the - * given geometry. - */ - static boolean canUseAccelerator(Geometry geom) { - if (geom.isEmpty() - || !(geom.getType() == Geometry.Type.Polyline || geom.getType() == Geometry.Type.Polygon)) - return false; - - return true; - } - - /** - * Returns the tolerance for which the rasterized Geometry has been built. - */ - public abstract double getToleranceXY(); - - /** - * Returns raster size in bytes - */ - public abstract int getRasterSize(); - - /** - * Dumps the raster to a bmp file for debug purposes. - * - * @param fileName - * @return true if success, false otherwise. - */ - public abstract boolean dbgSaveToBitmap(String fileName); - + public enum HitType { + Outside(0), // the test geometry is well outside the geometry bounds + Inside(1), // the test geometry is well inside the geomety bounds + Border(2); // the test geometry is close to the bounds or intersects the + // bounds + + int enumVal; + + private HitType(int val) { + enumVal = val; + }; + } + + /** + * Test a point against the RasterizedGeometry + */ + public abstract HitType queryPointInGeometry(double x, double y); + + /** + * Test an envelope against the RasterizedGeometry. + */ + public abstract HitType queryEnvelopeInGeometry(Envelope2D env); + + /** + * Creates a rasterized geometry from a given Geometry. + * + * @param geom + * The input geometry to rasterize. It has to be a MultiVertexGeometry instance. + * @param toleranceXY + * The tolerance of the rasterization. Raster pixels that are + * closer than given tolerance to the Geometry will be set. + * @param rasterSizeBytes + * The max size of the raster in bytes. The raster has size of + * rasterSize x rasterSize. Polygons are rasterized into 2 bpp + * (bits per pixel) rasters while other geometries are rasterized + * into 1 bpp rasters. 32x32 pixel raster for a polygon would + * take 256 bytes of memory + */ + public static RasterizedGeometry2D create(Geometry geom, + double toleranceXY, int rasterSizeBytes) { + if (!canUseAccelerator(geom)) + throw new IllegalArgumentException(); + + RasterizedGeometry2DImpl gc = RasterizedGeometry2DImpl.createImpl(geom, + toleranceXY, rasterSizeBytes); + return (RasterizedGeometry2D) gc; + } + + static RasterizedGeometry2D create(MultiVertexGeometryImpl geom, + double toleranceXY, int rasterSizeBytes) { + if (!canUseAccelerator(geom)) + throw new IllegalArgumentException(); + + RasterizedGeometry2DImpl gc = RasterizedGeometry2DImpl.createImpl(geom, + toleranceXY, rasterSizeBytes); + return (RasterizedGeometry2D) gc; + + } + + public static int rasterSizeFromAccelerationDegree( + GeometryAccelerationDegree accelDegree) { + int value = 0; + switch (accelDegree) { + case enumMild: + value = 64 * 64 * 2 / 8;// 1k + break; + case enumMedium: + value = 256 * 256 * 2 / 8;// 16k + break; + case enumHot: + value = 1024 * 1024 * 2 / 8;// 256k + break; + default: + throw GeometryException.GeometryInternalError(); + } + + return value; + } + + /** + * Checks whether the RasterizedGeometry2D accelerator can be used with the + * given geometry. + */ + static boolean canUseAccelerator(Geometry geom) { + if (geom.isEmpty() + || !(geom.getType() == Geometry.Type.Polyline || geom.getType() == Geometry.Type.Polygon)) + return false; + + return true; + } + + /** + * Returns the tolerance for which the rasterized Geometry has been built. + */ + public abstract double getToleranceXY(); + + /** + * Returns raster size in bytes + */ + public abstract int getRasterSize(); + + /** + * Dumps the raster to a bmp file for debug purposes. + * + * @param fileName + * @return true if success, false otherwise. + */ + public abstract boolean dbgSaveToBitmap(String fileName); + + /** + * Returns an estimate of this object size in bytes. + * + * @return Returns an estimate of this object size in bytes. + */ + public abstract long estimateMemorySize(); } diff --git a/src/main/java/com/esri/core/geometry/RasterizedGeometry2DImpl.java b/src/main/java/com/esri/core/geometry/RasterizedGeometry2DImpl.java index fb8179e8..c7def2d4 100644 --- a/src/main/java/com/esri/core/geometry/RasterizedGeometry2DImpl.java +++ b/src/main/java/com/esri/core/geometry/RasterizedGeometry2DImpl.java @@ -24,539 +24,558 @@ package com.esri.core.geometry; -import java.io.*; +import java.io.FileOutputStream; +import java.io.IOException; import java.nio.ByteBuffer; import java.nio.ByteOrder; -import com.esri.core.geometry.Envelope2D; -import com.esri.core.geometry.Geometry; -import com.esri.core.geometry.GeometryException; -import com.esri.core.geometry.NumberUtils; -import com.esri.core.geometry.Point2D; -import com.esri.core.geometry.Segment; -import com.esri.core.geometry.SegmentIteratorImpl; -import com.esri.core.geometry.SimpleRasterizer; +import static com.esri.core.geometry.SizeOf.SIZE_OF_RASTERIZED_GEOMETRY_2D_IMPL; +import static com.esri.core.geometry.SizeOf.SIZE_OF_SCAN_CALLBACK_IMPL; +import static com.esri.core.geometry.SizeOf.sizeOfIntArray; final class RasterizedGeometry2DImpl extends RasterizedGeometry2D { - int[] m_bitmap; - int m_scanLineSize; - int m_width; - double m_dx; - double m_dy; - double m_x0; - double m_y0; - double m_toleranceXY; - double m_stroke_half_widthX_pix; - double m_stroke_half_widthY_pix; - double m_stroke_half_width; - - Envelope2D m_geomEnv;// envelope of the raster in world coordinates - Transformation2D m_transform; - int m_dbgTestCount; - SimpleRasterizer m_rasterizer; - ScanCallbackImpl m_callback; - - class ScanCallbackImpl implements SimpleRasterizer.ScanCallback { - int[] m_bitmap; - int m_scanlineWidth; - int m_color; - - public ScanCallbackImpl(int[] bitmap, int scanlineWidth) { - m_scanlineWidth = scanlineWidth; - m_bitmap = bitmap; - } - - public void setColor(SimpleRasterizer rasterizer, int color) { - if (m_color != color) - rasterizer.flush(); - - m_color = color;// set new color - } - - @Override - public void drawScan(int[] scans, int scanCount3) { - for (int i = 0; i < scanCount3; ) { - int x0 = scans[i++]; - int x1 = scans[i++]; - int y = scans[i++]; - - int scanlineStart = y * m_scanlineWidth; - for (int xx = x0; xx < x1; xx++) { - m_bitmap[scanlineStart + (xx >> 4)] |= m_color << ((xx & 15) * 2);// 2 - // bit - // per - // color - } - } - } - } - - void fillMultiPath(SimpleRasterizer rasterizer, Transformation2D trans, MultiPathImpl polygon, boolean isWinding) { - SegmentIteratorImpl segIter = polygon.querySegmentIterator(); - Point2D p1 = new Point2D(); - Point2D p2 = new Point2D(); - while (segIter.nextPath()) { - while (segIter.hasNextSegment()) { - Segment seg = segIter.nextSegment(); - if (seg.getType() != Geometry.Type.Line) - throw GeometryException.GeometryInternalError(); // TODO: - // densify - // the - // segment - // here - trans.transform(seg.getStartXY(), p1); - trans.transform(seg.getEndXY(), p2); - m_rasterizer.addEdge(p1.x, p1.y, p2.x, p2.y); - } - } - - m_rasterizer.renderEdges(isWinding ? SimpleRasterizer.WINDING : SimpleRasterizer.EVEN_ODD); - } - - void fillPoints(SimpleRasterizer rasterizer, MultiPointImpl geom, double stroke_half_width) { - throw GeometryException.GeometryInternalError(); - } - - void fillConvexPolygon(SimpleRasterizer rasterizer, Point2D[] fan, int len) { - for (int i = 1, n = len; i < n; i++) { - rasterizer.addEdge(fan[i - 1].x, fan[i - 1].y, fan[i].x, fan[i].y); - } - rasterizer.addEdge(fan[len - 1].x, fan[len - 1].y, fan[0].x, fan[0].y); - m_rasterizer.renderEdges(SimpleRasterizer.EVEN_ODD); - } - - void fillEnvelope(SimpleRasterizer rasterizer, Envelope2D envIn) { - rasterizer.fillEnvelope(envIn); - } - - void strokeDrawPolyPath(SimpleRasterizer rasterizer, - MultiPathImpl polyPath, double tol) { - - Point2D[] fan = new Point2D[4]; - for (int i = 0; i < fan.length; i++) - fan[i] = new Point2D(); - - SegmentIteratorImpl segIter = polyPath.querySegmentIterator(); - double strokeHalfWidth = m_transform.transform(tol) + 1.5; - double shortSegment = 0.25; - Point2D vec = new Point2D(); - Point2D vecA = new Point2D(); - Point2D vecB = new Point2D(); - - Point2D ptStart = new Point2D(); - Point2D ptEnd = new Point2D(); - Point2D prev_start = new Point2D(); - Point2D prev_end = new Point2D(); - double[] helper_xy_10_elm = new double[10]; - Envelope2D segEnv = new Envelope2D(); - Point2D ptOld = new Point2D(); - while (segIter.nextPath()) { - boolean hasFan = false; - boolean first = true; - ptOld.setCoords(0, 0); - while (segIter.hasNextSegment()) { - Segment seg = segIter.nextSegment(); - ptStart.x = seg.getStartX(); - ptStart.y = seg.getStartY(); - ptEnd.x = seg.getEndX(); - ptEnd.y = seg.getEndY(); - segEnv.setEmpty(); - segEnv.merge(ptStart.x, ptStart.y); - segEnv.mergeNE(ptEnd.x, ptEnd.y); - if (!m_geomEnv.isIntersectingNE(segEnv)) { - if (hasFan) { - rasterizer.startAddingEdges(); - rasterizer.addSegmentStroke(prev_start.x, prev_start.y, - prev_end.x, prev_end.y, strokeHalfWidth, false, - helper_xy_10_elm); - rasterizer.renderEdges(SimpleRasterizer.EVEN_ODD); - hasFan = false; - } - - first = true; - continue; - } - - m_transform.transform(ptEnd, ptEnd); - - if (first) { - m_transform.transform(ptStart, ptStart); - ptOld.setCoords(ptStart); - first = false; - } else { - ptStart.setCoords(ptOld); - } - - prev_start.setCoords(ptStart); - prev_end.setCoords(ptEnd); - - rasterizer.startAddingEdges(); - hasFan = !rasterizer.addSegmentStroke(prev_start.x, - prev_start.y, prev_end.x, prev_end.y, strokeHalfWidth, - true, helper_xy_10_elm); - rasterizer.renderEdges(SimpleRasterizer.EVEN_ODD); - if (!hasFan) - ptOld.setCoords(prev_end); - } - - if (hasFan) { - rasterizer.startAddingEdges(); - hasFan = !rasterizer.addSegmentStroke(prev_start.x, - prev_start.y, prev_end.x, prev_end.y, strokeHalfWidth, - false, helper_xy_10_elm); - rasterizer.renderEdges(SimpleRasterizer.EVEN_ODD); - } - } - } - - int worldToPixX(double x) { - return (int) (x * m_dx + m_x0); - } - - int worldToPixY(double y) { - return (int) (y * m_dy + m_y0); - } - - RasterizedGeometry2DImpl(Geometry geom, double toleranceXY, - int rasterSizeBytes) { - // //_ASSERT(CanUseAccelerator(geom)); - init((MultiVertexGeometryImpl) geom._getImpl(), toleranceXY, - rasterSizeBytes); - } - - static RasterizedGeometry2DImpl createImpl(Geometry geom, - double toleranceXY, int rasterSizeBytes) { - RasterizedGeometry2DImpl rgImpl = new RasterizedGeometry2DImpl(geom, - toleranceXY, rasterSizeBytes); - - return rgImpl; - } - - private RasterizedGeometry2DImpl(MultiVertexGeometryImpl geom, - double toleranceXY, int rasterSizeBytes) { - init(geom, toleranceXY, rasterSizeBytes); - } - - static RasterizedGeometry2DImpl createImpl(MultiVertexGeometryImpl geom, - double toleranceXY, int rasterSizeBytes) { - RasterizedGeometry2DImpl rgImpl = new RasterizedGeometry2DImpl(geom, - toleranceXY, rasterSizeBytes); - return rgImpl; - } - - void init(MultiVertexGeometryImpl geom, double toleranceXY, - int rasterSizeBytes) { - // _ASSERT(CanUseAccelerator(geom)); - m_width = Math.max((int) (Math.sqrt(rasterSizeBytes) * 2 + 0.5), 64); - m_scanLineSize = (m_width * 2 + 31) / 32; // 2 bits per pixel - m_geomEnv = new Envelope2D(); - - m_toleranceXY = toleranceXY; - - // calculate bitmap size - int size = 0; - int width = m_width; - int scanLineSize = m_scanLineSize; - while (width >= 8) { - size += width * scanLineSize; - width /= 2; - scanLineSize = (width * 2 + 31) / 32; - } - - // allocate the bitmap, that contains the base and the mip-levels - m_bitmap = new int[size]; - for (int i = 0; i < size; i++) - m_bitmap[i] = 0; - - m_rasterizer = new SimpleRasterizer(); - ScanCallbackImpl callback = new ScanCallbackImpl(m_bitmap, - m_scanLineSize); - m_callback = callback; - m_rasterizer.setup(m_width, m_width, callback); - geom.queryEnvelope2D(m_geomEnv); - if (m_geomEnv.getWidth() > m_width * m_geomEnv.getHeight() - || m_geomEnv.getHeight() > m_geomEnv.getWidth() * m_width) { - // the geometry is thin and the rasterizer is not needed. - } - m_geomEnv.inflate(toleranceXY, toleranceXY); - Envelope2D worldEnv = new Envelope2D(); - - Envelope2D pixEnv = Envelope2D - .construct(1, 1, m_width - 2, m_width - 2); - - double minWidth = toleranceXY * pixEnv.getWidth(); // min width is such - // that the size of - // one pixel is - // equal to the - // tolerance - double minHeight = toleranceXY * pixEnv.getHeight(); - - worldEnv.setCoords(m_geomEnv.getCenter(), - Math.max(minWidth, m_geomEnv.getWidth()), - Math.max(minHeight, m_geomEnv.getHeight())); - - m_stroke_half_widthX_pix = worldEnv.getWidth() / pixEnv.getWidth(); - m_stroke_half_widthY_pix = worldEnv.getHeight() / pixEnv.getHeight(); - - // The stroke half width. Later it will be inflated to account for - // pixels size. - m_stroke_half_width = m_toleranceXY; - - m_transform = new Transformation2D(); - m_transform.initializeFromRect(worldEnv, pixEnv);// geom to pixels - - Transformation2D identityTransform = new Transformation2D(); - - switch (geom.getType().value()) { - case Geometry.GeometryType.MultiPoint: - callback.setColor(m_rasterizer, 2); - fillPoints(m_rasterizer, (MultiPointImpl) geom, m_stroke_half_width); - break; - case Geometry.GeometryType.Polyline: - callback.setColor(m_rasterizer, 2); - strokeDrawPolyPath(m_rasterizer, (MultiPathImpl) geom._getImpl(), - m_stroke_half_width); - break; - case Geometry.GeometryType.Polygon: { - boolean isWinding = false;// NOTE: change when winding is supported - callback.setColor(m_rasterizer, 1); - fillMultiPath(m_rasterizer, m_transform, (MultiPathImpl) geom, isWinding); - callback.setColor(m_rasterizer, 2); - strokeDrawPolyPath(m_rasterizer, (MultiPathImpl) geom._getImpl(), - m_stroke_half_width); - } - break; - } - - m_dx = m_transform.xx; - m_dy = m_transform.yy; - m_x0 = m_transform.xd; - m_y0 = m_transform.yd; - buildLevels(); - //dbgSaveToBitmap("c:/temp/_dbg.bmp"); - } - - boolean tryRenderAsSmallEnvelope_(Envelope2D env) { - if (!env.isIntersecting(m_geomEnv)) - return true; - - Envelope2D envPix = new Envelope2D(); - envPix.setCoords(env); - m_transform.transform(env); - double strokeHalfWidthPixX = m_stroke_half_widthX_pix; - double strokeHalfWidthPixY = m_stroke_half_widthY_pix; - if (envPix.getWidth() > 2 * strokeHalfWidthPixX + 1 - || envPix.getHeight() > 2 * strokeHalfWidthPixY + 1) - return false; - - // This envelope is too narrow/small, so that it can be just drawn as a - // rectangle using only boundary color. - - envPix.inflate(strokeHalfWidthPixX, strokeHalfWidthPixY); - envPix.xmax += 1.0; - envPix.ymax += 1.0;// take into account that it does not draw right and - // bottom edges. - - m_callback.setColor(m_rasterizer, 2); - fillEnvelope(m_rasterizer, envPix); - return true; - } - - void buildLevels() { - m_rasterizer.flush(); - int iStart = 0; - int iStartNext = m_width * m_scanLineSize; - int width = m_width; - int widthNext = m_width / 2; - int scanLineSize = m_scanLineSize; - int scanLineSizeNext = (widthNext * 2 + 31) / 32; - while (width > 8) { - for (int iy = 0; iy < widthNext; iy++) { - int iysrc1 = iy * 2; - int iysrc2 = iy * 2 + 1; - for (int ix = 0; ix < widthNext; ix++) { - int ixsrc1 = ix * 2; - int ixsrc2 = ix * 2 + 1; - int divix1 = ixsrc1 >> 4; - int modix1 = (ixsrc1 & 15) * 2; - int divix2 = ixsrc2 >> 4; - int modix2 = (ixsrc2 & 15) * 2; - int res = (m_bitmap[iStart + scanLineSize * iysrc1 + divix1] >> modix1) & 3; - res |= (m_bitmap[iStart + scanLineSize * iysrc1 + divix2] >> modix2) & 3; - res |= (m_bitmap[iStart + scanLineSize * iysrc2 + divix1] >> modix1) & 3; - res |= (m_bitmap[iStart + scanLineSize * iysrc2 + divix2] >> modix2) & 3; - int divixDst = ix >> 4; - int modixDst = (ix & 15) * 2; - m_bitmap[iStartNext + scanLineSizeNext * iy + divixDst] |= res << modixDst; - } - } - - width = widthNext; - scanLineSize = scanLineSizeNext; - iStart = iStartNext; - widthNext = width / 2; - scanLineSizeNext = (widthNext * 2 + 31) / 32; - iStartNext = iStart + scanLineSize * width; - } - } - - @Override - public HitType queryPointInGeometry(double x, double y) { - if (!m_geomEnv.contains(x, y)) - return HitType.Outside; - - int ix = worldToPixX(x); - int iy = worldToPixY(y); - if (ix < 0 || ix >= m_width || iy < 0 || iy >= m_width) - return HitType.Outside; - int divix = ix >> 4; - int modix = (ix & 15) * 2; - int res = (m_bitmap[m_scanLineSize * iy + divix] >> modix) & 3; - if (res == 0) - return HitType.Outside; - else if (res == 1) - return HitType.Inside; - else - return HitType.Border; - } - - @Override - public HitType queryEnvelopeInGeometry(Envelope2D env) { - if (!env.intersect(m_geomEnv)) - return HitType.Outside; - - int ixmin = worldToPixX(env.xmin); - int ixmax = worldToPixX(env.xmax); - int iymin = worldToPixY(env.ymin); - int iymax = worldToPixY(env.ymax); - if (ixmin < 0) - ixmin = 0; - if (iymin < 0) - iymin = 0; - if (ixmax >= m_width) - ixmax = m_width - 1; - if (iymax >= m_width) - iymax = m_width - 1; - - if (ixmin > ixmax || iymin > iymax) - return HitType.Outside; - - int area = Math.max(ixmax - ixmin, 1) * Math.max(iymax - iymin, 1); - int iStart = 0; - int scanLineSize = m_scanLineSize; - int width = m_width; - int res = 0; - while (true) { - if (area < 32 || width < 16) { - for (int iy = iymin; iy <= iymax; iy++) { - for (int ix = ixmin; ix <= ixmax; ix++) { - int divix = ix >> 4; - int modix = (ix & 15) * 2; - res = (m_bitmap[iStart + scanLineSize * iy + divix] >> modix) & 3; // read - // two - // bit - // color. - if (res > 1) - return HitType.Border; - } - } - - if (res == 0) - return HitType.Outside; - else if (res == 1) - return HitType.Inside; - } - - iStart += scanLineSize * width; - width /= 2; - scanLineSize = (width * 2 + 31) / 32; - ixmin /= 2; - iymin /= 2; - ixmax /= 2; - iymax /= 2; - area = Math.max(ixmax - ixmin, 1) * Math.max(iymax - iymin, 1); - } - } - - @Override - public double getToleranceXY() { - return m_toleranceXY; - } - - @Override - public int getRasterSize() { - return m_width * m_scanLineSize; - } - - @Override - public boolean dbgSaveToBitmap(String fileName) { - try { - FileOutputStream outfile = new FileOutputStream(fileName); - - int height = m_width; - int width = m_width; - int sz = 14 + 40 + 4 * m_width * height; - // Write the BITMAPFILEHEADER - ByteBuffer byteBuffer = ByteBuffer.allocate(sz); - byteBuffer.order(ByteOrder.LITTLE_ENDIAN); - // byteBuffer.put((byte) 'M'); - byteBuffer.put((byte) 66); - byteBuffer.put((byte) 77); - // fwrite("BM", 1, 2, f); //bfType - byteBuffer.putInt(sz); - // fwrite(&sz, 1, 4, f);//bfSize - short zero16 = 0; - byteBuffer.putShort(zero16); - // fwrite(&zero16, 1, 2, f);//bfReserved1 - byteBuffer.putShort(zero16); - // fwrite(&zero16, 1, 2, f);//bfReserved2 - int offset = 14 + 40; - byteBuffer.putInt(offset); - // fwrite(&offset, 1, 4, f);//bfOffBits - - // Write the BITMAPINFOHEADER - int biSize = 40; - int biWidth = width; - int biHeight = -height; - short biPlanes = 1; - short biBitCount = 32; - int biCompression = 0; - int biSizeImage = 4 * width * height; - int biXPelsPerMeter = 0; - int biYPelsPerMeter = 0; - int biClrUsed = 0; - int biClrImportant = 0; - byteBuffer.putInt(biSize); - byteBuffer.putInt(biWidth); - byteBuffer.putInt(biHeight); - byteBuffer.putShort(biPlanes); - byteBuffer.putShort(biBitCount); - byteBuffer.putInt(biCompression); - byteBuffer.putInt(biSizeImage); - byteBuffer.putInt(biXPelsPerMeter); - byteBuffer.putInt(biYPelsPerMeter); - byteBuffer.putInt(biClrUsed); - byteBuffer.putInt(biClrImportant); - - int colors[] = {0xFFFFFFFF, 0xFF000000, 0xFFFF0000, 0xFF00FF00}; - // int32_t* rgb4 = (int32_t*)malloc(biSizeImage); - for (int y = 0; y < height; y++) { - int scanlineIn = y * ((width * 2 + 31) / 32); - int scanlineOut = offset + width * y; - - for (int x = 0; x < width; x++) { - int res = (m_bitmap[scanlineIn + (x >> 4)] >> ((x & 15) * 2)) & 3; - byteBuffer.putInt(colors[res]); - } - } - - byte[] b = byteBuffer.array(); - outfile.write(b); - outfile.close(); - return true; - } catch (IOException ex) { - return false; - - } - } + int[] m_bitmap; + int m_scanLineSize; + int m_width; + double m_dx; + double m_dy; + double m_x0; + double m_y0; + double m_toleranceXY; + double m_stroke_half_widthX_pix; + double m_stroke_half_widthY_pix; + double m_stroke_half_width; + + Envelope2D m_geomEnv;// envelope of the raster in world coordinates + Transformation2D m_transform; + int m_dbgTestCount; + SimpleRasterizer m_rasterizer; + ScanCallbackImpl m_callback; + + class ScanCallbackImpl implements SimpleRasterizer.ScanCallback { + int[] m_bitmap; + int m_scanlineWidth; + int m_color; + + public ScanCallbackImpl(int[] bitmap, int scanlineWidth) { + m_scanlineWidth = scanlineWidth; + m_bitmap = bitmap; + } + + public void setColor(SimpleRasterizer rasterizer, int color) { + if (m_color != color) + rasterizer.flush(); + + m_color = color;// set new color + } + + @Override + public void drawScan(int[] scans, int scanCount3) { + for (int i = 0; i < scanCount3; ) { + int x0 = scans[i++]; + int x1 = scans[i++]; + int y = scans[i++]; + + int scanlineStart = y * m_scanlineWidth; + for (int xx = x0; xx < x1; xx++) { + m_bitmap[scanlineStart + (xx >> 4)] |= m_color << ((xx & 15) * 2);// 2 + // bit + // per + // color + } + } + } + + /** + * Returns an estimate of this object size in bytes. + * + * @return Returns an estimate of this object size in bytes. + */ + public long estimateMemorySize() + { + return SIZE_OF_SCAN_CALLBACK_IMPL + + (m_bitmap != null ? sizeOfIntArray(m_bitmap.length) : 0); + } + } + + void fillMultiPath(SimpleRasterizer rasterizer, Transformation2D trans, MultiPathImpl polygon, boolean isWinding) { + SegmentIteratorImpl segIter = polygon.querySegmentIterator(); + Point2D p1 = new Point2D(); + Point2D p2 = new Point2D(); + while (segIter.nextPath()) { + while (segIter.hasNextSegment()) { + Segment seg = segIter.nextSegment(); + if (seg.getType() != Geometry.Type.Line) + throw GeometryException.GeometryInternalError(); // TODO: + // densify + // the + // segment + // here + trans.transform(seg.getStartXY(), p1); + trans.transform(seg.getEndXY(), p2); + m_rasterizer.addEdge(p1.x, p1.y, p2.x, p2.y); + } + } + + m_rasterizer.renderEdges(isWinding ? SimpleRasterizer.WINDING : SimpleRasterizer.EVEN_ODD); + } + + void fillPoints(SimpleRasterizer rasterizer, MultiPointImpl geom, double stroke_half_width) { + throw GeometryException.GeometryInternalError(); + } + + void fillConvexPolygon(SimpleRasterizer rasterizer, Point2D[] fan, int len) { + for (int i = 1, n = len; i < n; i++) { + rasterizer.addEdge(fan[i-1].x, fan[i-1].y, fan[i].x, fan[i].y); + } + rasterizer.addEdge(fan[len-1].x, fan[len-1].y, fan[0].x, fan[0].y); + m_rasterizer.renderEdges(SimpleRasterizer.EVEN_ODD); + } + + void fillEnvelope(SimpleRasterizer rasterizer, Envelope2D envIn) { + rasterizer.fillEnvelope(envIn); + } + + void strokeDrawPolyPath(SimpleRasterizer rasterizer, + MultiPathImpl polyPath, double tol) { + + Point2D[] fan = new Point2D[4]; + for (int i = 0; i < fan.length; i++) + fan[i] = new Point2D(); + + SegmentIteratorImpl segIter = polyPath.querySegmentIterator(); + double strokeHalfWidth = m_transform.transform(tol) + 1.5; + + Point2D ptStart = new Point2D(); + Point2D ptEnd = new Point2D(); + Point2D prev_start = new Point2D(); + Point2D prev_end = new Point2D(); + double[] helper_xy_10_elm = new double[10]; + Envelope2D segEnv = new Envelope2D(); + Point2D ptOld = new Point2D(); + double extraWidth = 0; + while (segIter.nextPath()) { + boolean hasFan = false; + boolean first = true; + ptOld.setCoords(0, 0); + while (segIter.hasNextSegment()) { + Segment seg = segIter.nextSegment(); + ptStart.x = seg.getStartX(); + ptStart.y = seg.getStartY(); + ptEnd.x = seg.getEndX(); + ptEnd.y = seg.getEndY(); + segEnv.setEmpty(); + segEnv.merge(ptStart.x, ptStart.y); + segEnv.mergeNE(ptEnd.x, ptEnd.y); + if (!m_geomEnv.isIntersectingNE(segEnv)) { + if (hasFan) { + rasterizer.startAddingEdges(); + rasterizer.addSegmentStroke(prev_start.x, prev_start.y, + prev_end.x, prev_end.y, strokeHalfWidth + extraWidth, false, + helper_xy_10_elm); + rasterizer.renderEdges(SimpleRasterizer.EVEN_ODD); + hasFan = false; + extraWidth = 0.0; + } + + first = true; + continue; + } + + m_transform.transform(ptEnd, ptEnd); + + if (first) { + m_transform.transform(ptStart, ptStart); + ptOld.setCoords(ptStart); + first = false; + } else { + ptStart.setCoords(ptOld); + } + + prev_start.setCoords(ptStart); + prev_end.setCoords(ptEnd); + + rasterizer.startAddingEdges(); + hasFan = !rasterizer.addSegmentStroke(prev_start.x, + prev_start.y, prev_end.x, prev_end.y, strokeHalfWidth + extraWidth, + true, helper_xy_10_elm); + rasterizer.renderEdges(SimpleRasterizer.EVEN_ODD); + if (!hasFan) { + ptOld.setCoords(prev_end); + extraWidth = 0.0; + } + else { + //track length of skipped segment to add it to the stroke width for the next edge. + extraWidth = Math.max(extraWidth, Point2D.distance(prev_start, prev_end)); + } + } + + if (hasFan) { + rasterizer.startAddingEdges(); + hasFan = !rasterizer.addSegmentStroke(prev_start.x, + prev_start.y, prev_end.x, prev_end.y, strokeHalfWidth + extraWidth, + false, helper_xy_10_elm); + rasterizer.renderEdges(SimpleRasterizer.EVEN_ODD); + extraWidth = 0.0; + } + } + } + + int worldToPixX(double x) { + return (int) (x * m_dx + m_x0); + } + + int worldToPixY(double y) { + return (int) (y * m_dy + m_y0); + } + + RasterizedGeometry2DImpl(Geometry geom, double toleranceXY, + int rasterSizeBytes) { + // //_ASSERT(CanUseAccelerator(geom)); + init((MultiVertexGeometryImpl) geom._getImpl(), toleranceXY, + rasterSizeBytes); + } + + static RasterizedGeometry2DImpl createImpl(Geometry geom, + double toleranceXY, int rasterSizeBytes) { + RasterizedGeometry2DImpl rgImpl = new RasterizedGeometry2DImpl(geom, + toleranceXY, rasterSizeBytes); + + return rgImpl; + } + + private RasterizedGeometry2DImpl(MultiVertexGeometryImpl geom, + double toleranceXY, int rasterSizeBytes) { + init(geom, toleranceXY, rasterSizeBytes); + } + + static RasterizedGeometry2DImpl createImpl(MultiVertexGeometryImpl geom, + double toleranceXY, int rasterSizeBytes) { + RasterizedGeometry2DImpl rgImpl = new RasterizedGeometry2DImpl(geom, + toleranceXY, rasterSizeBytes); + return rgImpl; + } + + void init(MultiVertexGeometryImpl geom, double toleranceXY, + int rasterSizeBytes) { + // _ASSERT(CanUseAccelerator(geom)); + m_width = Math.max((int) (Math.sqrt(rasterSizeBytes) * 2 + 0.5), 64); + m_scanLineSize = (m_width * 2 + 31) / 32; // 2 bits per pixel + m_geomEnv = new Envelope2D(); + + m_toleranceXY = toleranceXY; + + // calculate bitmap size + int size = 0; + int width = m_width; + int scanLineSize = m_scanLineSize; + while (width >= 8) { + size += width * scanLineSize; + width /= 2; + scanLineSize = (width * 2 + 31) / 32; + } + + // allocate the bitmap, that contains the base and the mip-levels + m_bitmap = new int[size]; + for (int i = 0; i < size; i++) + m_bitmap[i] = 0; + + m_rasterizer = new SimpleRasterizer(); + ScanCallbackImpl callback = new ScanCallbackImpl(m_bitmap, + m_scanLineSize); + m_callback = callback; + m_rasterizer.setup(m_width, m_width, callback); + geom.queryEnvelope2D(m_geomEnv); + if (m_geomEnv.getWidth() > m_width * m_geomEnv.getHeight() + || m_geomEnv.getHeight() > m_geomEnv.getWidth() * m_width) { + // the geometry is thin and the rasterizer is not needed. + } + m_geomEnv.inflate(toleranceXY, toleranceXY); + Envelope2D worldEnv = new Envelope2D(); + + Envelope2D pixEnv = Envelope2D + .construct(1, 1, m_width - 2, m_width - 2); + + double minWidth = toleranceXY * pixEnv.getWidth(); // min width is such + // that the size of + // one pixel is + // equal to the + // tolerance + double minHeight = toleranceXY * pixEnv.getHeight(); + + worldEnv.setCoords(m_geomEnv.getCenter(), + Math.max(minWidth, m_geomEnv.getWidth()), + Math.max(minHeight, m_geomEnv.getHeight())); + + m_stroke_half_widthX_pix = worldEnv.getWidth() / pixEnv.getWidth(); + m_stroke_half_widthY_pix = worldEnv.getHeight() / pixEnv.getHeight(); + + // The stroke half width. Later it will be inflated to account for + // pixels size. + m_stroke_half_width = m_toleranceXY; + + m_transform = new Transformation2D(); + m_transform.initializeFromRect(worldEnv, pixEnv);// geom to pixels + + switch (geom.getType().value()) { + case Geometry.GeometryType.MultiPoint: + callback.setColor(m_rasterizer, 2); + fillPoints(m_rasterizer, (MultiPointImpl) geom, m_stroke_half_width); + break; + case Geometry.GeometryType.Polyline: + callback.setColor(m_rasterizer, 2); + strokeDrawPolyPath(m_rasterizer, (MultiPathImpl) geom._getImpl(), + m_stroke_half_width); + break; + case Geometry.GeometryType.Polygon: { + boolean isWinding = false;// NOTE: change when winding is supported + callback.setColor(m_rasterizer, 1); + fillMultiPath(m_rasterizer, m_transform, (MultiPathImpl) geom, isWinding); + callback.setColor(m_rasterizer, 2); + strokeDrawPolyPath(m_rasterizer, (MultiPathImpl) geom._getImpl(), + m_stroke_half_width); + } + break; + } + + m_dx = m_transform.xx; + m_dy = m_transform.yy; + m_x0 = m_transform.xd; + m_y0 = m_transform.yd; + buildLevels(); + //dbgSaveToBitmap("c:/temp/_dbg.bmp"); + } + + boolean tryRenderAsSmallEnvelope_(Envelope2D env) { + if (!env.isIntersecting(m_geomEnv)) + return true; + + Envelope2D envPix = new Envelope2D(); + envPix.setCoords(env); + m_transform.transform(env); + double strokeHalfWidthPixX = m_stroke_half_widthX_pix; + double strokeHalfWidthPixY = m_stroke_half_widthY_pix; + if (envPix.getWidth() > 2 * strokeHalfWidthPixX + 1 + || envPix.getHeight() > 2 * strokeHalfWidthPixY + 1) + return false; + + // This envelope is too narrow/small, so that it can be just drawn as a + // rectangle using only boundary color. + + envPix.inflate(strokeHalfWidthPixX, strokeHalfWidthPixY); + envPix.xmax += 1.0; + envPix.ymax += 1.0;// take into account that it does not draw right and + // bottom edges. + + m_callback.setColor(m_rasterizer, 2); + fillEnvelope(m_rasterizer, envPix); + return true; + } + + void buildLevels() { + m_rasterizer.flush(); + int iStart = 0; + int iStartNext = m_width * m_scanLineSize; + int width = m_width; + int widthNext = m_width / 2; + int scanLineSize = m_scanLineSize; + int scanLineSizeNext = (widthNext * 2 + 31) / 32; + while (width > 8) { + for (int iy = 0; iy < widthNext; iy++) { + int iysrc1 = iy * 2; + int iysrc2 = iy * 2 + 1; + for (int ix = 0; ix < widthNext; ix++) { + int ixsrc1 = ix * 2; + int ixsrc2 = ix * 2 + 1; + int divix1 = ixsrc1 >> 4; + int modix1 = (ixsrc1 & 15) * 2; + int divix2 = ixsrc2 >> 4; + int modix2 = (ixsrc2 & 15) * 2; + int res = (m_bitmap[iStart + scanLineSize * iysrc1 + divix1] >> modix1) & 3; + res |= (m_bitmap[iStart + scanLineSize * iysrc1 + divix2] >> modix2) & 3; + res |= (m_bitmap[iStart + scanLineSize * iysrc2 + divix1] >> modix1) & 3; + res |= (m_bitmap[iStart + scanLineSize * iysrc2 + divix2] >> modix2) & 3; + int divixDst = ix >> 4; + int modixDst = (ix & 15) * 2; + m_bitmap[iStartNext + scanLineSizeNext * iy + divixDst] |= res << modixDst; + } + } + + width = widthNext; + scanLineSize = scanLineSizeNext; + iStart = iStartNext; + widthNext = width / 2; + scanLineSizeNext = (widthNext * 2 + 31) / 32; + iStartNext = iStart + scanLineSize * width; + } + } + + @Override + public HitType queryPointInGeometry(double x, double y) { + if (!m_geomEnv.contains(x, y)) + return HitType.Outside; + + int ix = worldToPixX(x); + int iy = worldToPixY(y); + if (ix < 0 || ix >= m_width || iy < 0 || iy >= m_width) + return HitType.Outside; + int divix = ix >> 4; + int modix = (ix & 15) * 2; + int res = (m_bitmap[m_scanLineSize * iy + divix] >> modix) & 3; + if (res == 0) + return HitType.Outside; + else if (res == 1) + return HitType.Inside; + else + return HitType.Border; + } + + @Override + public HitType queryEnvelopeInGeometry(Envelope2D env) { + if (!env.intersect(m_geomEnv)) + return HitType.Outside; + + int ixmin = worldToPixX(env.xmin); + int ixmax = worldToPixX(env.xmax); + int iymin = worldToPixY(env.ymin); + int iymax = worldToPixY(env.ymax); + if (ixmin < 0) + ixmin = 0; + if (iymin < 0) + iymin = 0; + if (ixmax >= m_width) + ixmax = m_width - 1; + if (iymax >= m_width) + iymax = m_width - 1; + + if (ixmin > ixmax || iymin > iymax) + return HitType.Outside; + + int area = Math.max(ixmax - ixmin, 1) * Math.max(iymax - iymin, 1); + int iStart = 0; + int scanLineSize = m_scanLineSize; + int width = m_width; + int res = 0; + while (true) { + if (area < 32 || width < 16) { + for (int iy = iymin; iy <= iymax; iy++) { + for (int ix = ixmin; ix <= ixmax; ix++) { + int divix = ix >> 4; + int modix = (ix & 15) * 2; + res = (m_bitmap[iStart + scanLineSize * iy + divix] >> modix) & 3; // read + // two + // bit + // color. + if (res > 1) + return HitType.Border; + } + } + + if (res == 0) + return HitType.Outside; + else if (res == 1) + return HitType.Inside; + } + + iStart += scanLineSize * width; + width /= 2; + scanLineSize = (width * 2 + 31) / 32; + ixmin /= 2; + iymin /= 2; + ixmax /= 2; + iymax /= 2; + area = Math.max(ixmax - ixmin, 1) * Math.max(iymax - iymin, 1); + } + } + + @Override + public double getToleranceXY() { + return m_toleranceXY; + } + + @Override + public int getRasterSize() { + return m_width * m_scanLineSize; + } + + @Override + public boolean dbgSaveToBitmap(String fileName) { + try { + FileOutputStream outfile = new FileOutputStream(fileName); + + int height = m_width; + int width = m_width; + int sz = 14 + 40 + 4 * m_width * height; + // Write the BITMAPFILEHEADER + ByteBuffer byteBuffer = ByteBuffer.allocate(sz); + byteBuffer.order(ByteOrder.LITTLE_ENDIAN); + // byteBuffer.put((byte) 'M'); + byteBuffer.put((byte) 66); + byteBuffer.put((byte) 77); + // fwrite("BM", 1, 2, f); //bfType + byteBuffer.putInt(sz); + // fwrite(&sz, 1, 4, f);//bfSize + short zero16 = 0; + byteBuffer.putShort(zero16); + // fwrite(&zero16, 1, 2, f);//bfReserved1 + byteBuffer.putShort(zero16); + // fwrite(&zero16, 1, 2, f);//bfReserved2 + int offset = 14 + 40; + byteBuffer.putInt(offset); + // fwrite(&offset, 1, 4, f);//bfOffBits + + // Write the BITMAPINFOHEADER + int biSize = 40; + int biWidth = width; + int biHeight = -height; + short biPlanes = 1; + short biBitCount = 32; + int biCompression = 0; + int biSizeImage = 4 * width * height; + int biXPelsPerMeter = 0; + int biYPelsPerMeter = 0; + int biClrUsed = 0; + int biClrImportant = 0; + byteBuffer.putInt(biSize); + byteBuffer.putInt(biWidth); + byteBuffer.putInt(biHeight); + byteBuffer.putShort(biPlanes); + byteBuffer.putShort(biBitCount); + byteBuffer.putInt(biCompression); + byteBuffer.putInt(biSizeImage); + byteBuffer.putInt(biXPelsPerMeter); + byteBuffer.putInt(biYPelsPerMeter); + byteBuffer.putInt(biClrUsed); + byteBuffer.putInt(biClrImportant); + + int colors[] = { 0xFFFFFFFF, 0xFF000000, 0xFFFF0000, 0xFF00FF00 }; + // int32_t* rgb4 = (int32_t*)malloc(biSizeImage); + for (int y = 0; y < height; y++) { + int scanlineIn = y * ((width * 2 + 31) / 32); + + for (int x = 0; x < width; x++) { + int res = (m_bitmap[scanlineIn + (x >> 4)] >> ((x & 15) * 2)) & 3; + byteBuffer.putInt(colors[res]); + } + } + + byte[] b = byteBuffer.array(); + outfile.write(b); + outfile.close(); + return true; + } catch (IOException ex) { + return false; + + } + } + + @Override + public long estimateMemorySize() + { + return SIZE_OF_RASTERIZED_GEOMETRY_2D_IMPL + + (m_geomEnv != null ? m_geomEnv.estimateMemorySize() : 0) + + (m_transform != null ? m_transform.estimateMemorySize(): 0) + + (m_rasterizer != null ? m_rasterizer.estimateMemorySize(): 0) + + (m_callback != null ? m_callback.estimateMemorySize(): 0); + } } diff --git a/src/main/java/com/esri/core/geometry/RelationalOperations.java b/src/main/java/com/esri/core/geometry/RelationalOperations.java index c36e78dc..abf03372 100644 --- a/src/main/java/com/esri/core/geometry/RelationalOperations.java +++ b/src/main/java/com/esri/core/geometry/RelationalOperations.java @@ -26,4167 +26,1812 @@ import java.util.ArrayList; class RelationalOperations { - interface Relation { - static final int contains = 1; - static final int within = 2; - static final int equals = 3; - static final int disjoint = 4; - static final int touches = 8; - static final int crosses = 16; - static final int overlaps = 32; - - static final int unknown = 0; - static final int intersects = 0x40000000; - } - - static boolean relate(Geometry geometry_a, Geometry geometry_b, - SpatialReference sr, int relation, ProgressTracker progress_tracker) { - int type_a = geometry_a.getType().value(); - int type_b = geometry_b.getType().value(); - - // Give preference to the Point vs Envelope, Envelope vs Envelope and - // Point vs Point realtions: - if (type_a == Geometry.GeometryType.Envelope) { - if (type_b == Geometry.GeometryType.Envelope) { - return relate((Envelope) geometry_a, (Envelope) geometry_b, sr, - relation, progress_tracker); - } else if (type_b == Geometry.GeometryType.Point) { - if (relation == Relation.within) - relation = Relation.contains; - else if (relation == Relation.contains) - relation = Relation.within; - - return relate((Point) geometry_b, (Envelope) geometry_a, sr, - relation, progress_tracker); - } else { - // proceed below - } - } else if (type_a == Geometry.GeometryType.Point) { - if (type_b == Geometry.GeometryType.Envelope) { - return relate((Point) geometry_a, (Envelope) geometry_b, sr, - relation, progress_tracker); - } else if (type_b == Geometry.GeometryType.Point) { - return relate((Point) geometry_a, (Point) geometry_b, sr, - relation, progress_tracker); - } else { - // proceed below - } - } else { - // proceed below - } - - if (geometry_a.isEmpty() || geometry_b.isEmpty()) { - if (relation == Relation.disjoint) - return true; // Always true - - return false; // Always false - } - - Envelope2D env1 = new Envelope2D(); - geometry_a.queryEnvelope2D(env1); - Envelope2D env2 = new Envelope2D(); - geometry_b.queryEnvelope2D(env2); - - Envelope2D envMerged = new Envelope2D(); - envMerged.setCoords(env1); - envMerged.merge(env2); - double tolerance = InternalUtils.calculateToleranceFromGeometry(sr, - envMerged, false); - - if (envelopeDisjointEnvelope_(env1, env2, tolerance, progress_tracker)) { - if (relation == Relation.disjoint) - return true; - - return false; - } - - boolean bRelation = false; - - Geometry _geometry_a; - Geometry _geometry_b; - Polyline polyline_a, polyline_b; - - if (MultiPath.isSegment(type_a)) { - polyline_a = new Polyline(geometry_a.getDescription()); - polyline_a.addSegment((Segment) geometry_a, true); - _geometry_a = polyline_a; - type_a = Geometry.GeometryType.Polyline; - } else { - _geometry_a = geometry_a; - } - - if (MultiPath.isSegment(type_b)) { - polyline_b = new Polyline(geometry_b.getDescription()); - polyline_b.addSegment((Segment) geometry_b, true); - _geometry_b = polyline_b; - type_b = Geometry.GeometryType.Polyline; - } else { - _geometry_b = geometry_b; - } - - if (type_a != Geometry.GeometryType.Envelope - && type_b != Geometry.GeometryType.Envelope) { - if (_geometry_a.getDimension() < _geometry_b.getDimension() - || (type_a == Geometry.GeometryType.Point && type_b == Geometry.GeometryType.MultiPoint)) {// we - // will - // switch - // the - // order - // of - // the - // geometries - // below. - if (relation == Relation.within) - relation = Relation.contains; - else if (relation == Relation.contains) - relation = Relation.within; - } - } else { - if (type_a != Geometry.GeometryType.Polygon - && type_b != Geometry.GeometryType.Envelope) { // we will - // switch - // the order - // of the - // geometries - // below. - if (relation == Relation.within) - relation = Relation.contains; - else if (relation == Relation.contains) - relation = Relation.within; - } - } - - switch (type_a) { - case Geometry.GeometryType.Polygon: - switch (type_b) { - case Geometry.GeometryType.Polygon: - bRelation = polygonRelatePolygon_((Polygon) (_geometry_a), - (Polygon) (_geometry_b), tolerance, relation, - progress_tracker); - break; - - case Geometry.GeometryType.Polyline: - bRelation = polygonRelatePolyline_((Polygon) (_geometry_a), - (Polyline) (_geometry_b), tolerance, relation, - progress_tracker); - break; - - case Geometry.GeometryType.Point: - bRelation = polygonRelatePoint_((Polygon) (_geometry_a), - (Point) (_geometry_b), tolerance, relation, - progress_tracker); - break; - - case Geometry.GeometryType.MultiPoint: - bRelation = polygonRelateMultiPoint_((Polygon) (_geometry_a), - (MultiPoint) (_geometry_b), tolerance, relation, - progress_tracker); - break; - - case Geometry.GeometryType.Envelope: - bRelation = polygonRelateEnvelope_((Polygon) (_geometry_a), - (Envelope) (_geometry_b), tolerance, relation, - progress_tracker); - break; - - default: - break; // warning fix - } - break; - - case Geometry.GeometryType.Polyline: - switch (type_b) { - case Geometry.GeometryType.Polygon: - bRelation = polygonRelatePolyline_((Polygon) (_geometry_b), - (Polyline) (_geometry_a), tolerance, relation, - progress_tracker); - break; - - case Geometry.GeometryType.Polyline: - bRelation = polylineRelatePolyline_((Polyline) (_geometry_a), - (Polyline) (_geometry_b), tolerance, relation, - progress_tracker); - break; - - case Geometry.GeometryType.Point: - bRelation = polylineRelatePoint_((Polyline) (_geometry_a), - (Point) (_geometry_b), tolerance, relation, - progress_tracker); - break; - - case Geometry.GeometryType.MultiPoint: - bRelation = polylineRelateMultiPoint_((Polyline) (_geometry_a), - (MultiPoint) (_geometry_b), tolerance, relation, - progress_tracker); - break; - - case Geometry.GeometryType.Envelope: - bRelation = polylineRelateEnvelope_((Polyline) (_geometry_a), - (Envelope) (_geometry_b), tolerance, relation, - progress_tracker); - break; - - default: - break; // warning fix - } - break; - - case Geometry.GeometryType.Point: - switch (type_b) { - case Geometry.GeometryType.Polygon: - bRelation = polygonRelatePoint_((Polygon) (_geometry_b), - (Point) (_geometry_a), tolerance, relation, - progress_tracker); - break; - - case Geometry.GeometryType.Polyline: - bRelation = polylineRelatePoint_((Polyline) (_geometry_b), - (Point) (_geometry_a), tolerance, relation, - progress_tracker); - break; - - case Geometry.GeometryType.MultiPoint: - bRelation = multiPointRelatePoint_((MultiPoint) (_geometry_b), - (Point) (_geometry_a), tolerance, relation, - progress_tracker); - break; - - default: - break; // warning fix - } - break; - - case Geometry.GeometryType.MultiPoint: - switch (type_b) { - case Geometry.GeometryType.Polygon: - bRelation = polygonRelateMultiPoint_((Polygon) (_geometry_b), - (MultiPoint) (_geometry_a), tolerance, relation, - progress_tracker); - break; - - case Geometry.GeometryType.Polyline: - bRelation = polylineRelateMultiPoint_((Polyline) (_geometry_b), - (MultiPoint) (_geometry_a), tolerance, relation, - progress_tracker); - break; - - case Geometry.GeometryType.MultiPoint: - bRelation = multiPointRelateMultiPoint_( - (MultiPoint) (_geometry_a), (MultiPoint) (_geometry_b), - tolerance, relation, progress_tracker); - break; - - case Geometry.GeometryType.Point: - bRelation = multiPointRelatePoint_((MultiPoint) (_geometry_a), - (Point) (_geometry_b), tolerance, relation, - progress_tracker); - break; - - case Geometry.GeometryType.Envelope: - bRelation = multiPointRelateEnvelope_( - (MultiPoint) (_geometry_a), (Envelope) (_geometry_b), - tolerance, relation, progress_tracker); - break; - - default: - break; // warning fix - } - break; - - case Geometry.GeometryType.Envelope: - switch (type_b) { - case Geometry.GeometryType.Polygon: - bRelation = polygonRelateEnvelope_((Polygon) (_geometry_b), - (Envelope) (_geometry_a), tolerance, relation, - progress_tracker); - break; - - case Geometry.GeometryType.Polyline: - bRelation = polylineRelateEnvelope_((Polyline) (_geometry_b), - (Envelope) (_geometry_a), tolerance, relation, - progress_tracker); - break; - - case Geometry.GeometryType.MultiPoint: - bRelation = multiPointRelateEnvelope_( - (MultiPoint) (_geometry_b), (Envelope) (_geometry_a), - tolerance, relation, progress_tracker); - break; - - default: - break; // warning fix - } - break; - - default: - break; // warning fix - } - - return bRelation; - } - - // Computes the necessary 9 intersection relationships of boundary, - // interior, and exterior of envelope_a vs envelope_b for the given - // relation. - private static boolean relate(Envelope envelope_a, Envelope envelope_b, - SpatialReference sr, int relation, ProgressTracker progress_tracker) { - if (envelope_a.isEmpty() || envelope_b.isEmpty()) { - if (relation == Relation.disjoint) - return true; // Always true - - return false; // Always false - } - - Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(), env_merged = new Envelope2D(); - envelope_a.queryEnvelope2D(env_a); - envelope_b.queryEnvelope2D(env_b); - env_merged.setCoords(env_a); - env_merged.merge(env_b); - - double tolerance = InternalUtils.calculateToleranceFromGeometry(sr, - env_merged, false); - - switch (relation) { - case Relation.disjoint: - return envelopeDisjointEnvelope_(env_a, env_b, tolerance, - progress_tracker); - - case Relation.within: - return envelopeContainsEnvelope_(env_b, env_a, tolerance, - progress_tracker); - - case Relation.contains: - return envelopeContainsEnvelope_(env_a, env_b, tolerance, - progress_tracker); - - case Relation.equals: - return envelopeEqualsEnvelope_(env_a, env_b, tolerance, - progress_tracker); - - case Relation.touches: - return envelopeTouchesEnvelope_(env_a, env_b, tolerance, - progress_tracker); - - case Relation.overlaps: - return envelopeOverlapsEnvelope_(env_a, env_b, tolerance, - progress_tracker); - - case Relation.crosses: - return envelopeCrossesEnvelope_(env_a, env_b, tolerance, - progress_tracker); - - default: - break; // warning fix - } - - return false; - } - - // Computes the necessary 9 intersection relationships of boundary, - // interior, and exterior of point_a vs envelope_b for the given relation. - private static boolean relate(Point point_a, Envelope envelope_b, - SpatialReference sr, int relation, ProgressTracker progress_tracker) { - if (point_a.isEmpty() || envelope_b.isEmpty()) { - if (relation == Relation.disjoint) - return true; // Always true - - return false; // Always false - } - - Point2D pt_a = point_a.getXY(); - Envelope2D env_b = new Envelope2D(), env_merged = new Envelope2D(); - envelope_b.queryEnvelope2D(env_b); - env_merged.setCoords(pt_a); - env_merged.merge(env_b); - - double tolerance = InternalUtils.calculateToleranceFromGeometry(sr, - env_merged, false); - - switch (relation) { - case Relation.disjoint: - return pointDisjointEnvelope_(pt_a, env_b, tolerance, - progress_tracker); - - case Relation.within: - return pointWithinEnvelope_(pt_a, env_b, tolerance, - progress_tracker); - - case Relation.contains: - return pointContainsEnvelope_(pt_a, env_b, tolerance, - progress_tracker); - - case Relation.equals: - return pointEqualsEnvelope_(pt_a, env_b, tolerance, - progress_tracker); - - case Relation.touches: - return pointTouchesEnvelope_(pt_a, env_b, tolerance, - progress_tracker); - - default: - break; // warning fix - } - - return false; - } - - // Computes the necessary 9 intersection relationships of boundary, - // interior, and exterior of point_a vs point_b for the given relation. - private static boolean relate(Point point_a, Point point_b, - SpatialReference sr, int relation, ProgressTracker progress_tracker) { - if (point_a.isEmpty() || point_b.isEmpty()) { - if (relation == Relation.disjoint) - return true; // Always true - - return false; // Always false - } - - Point2D pt_a = point_a.getXY(); - Point2D pt_b = point_b.getXY(); - Envelope2D env_merged = new Envelope2D(); - env_merged.setCoords(pt_a); - env_merged.merge(pt_b); - - double tolerance = InternalUtils.calculateToleranceFromGeometry(sr, - env_merged, false); - - switch (relation) { - case Relation.disjoint: - return pointDisjointPoint_(pt_a, pt_b, tolerance, progress_tracker); - - case Relation.within: - return pointContainsPoint_(pt_b, pt_a, tolerance, progress_tracker); - - case Relation.contains: - return pointContainsPoint_(pt_a, pt_b, tolerance, progress_tracker); - - case Relation.equals: - return pointEqualsPoint_(pt_a, pt_b, tolerance, progress_tracker); - - default: - break; // warning fix - } - - return false; - } - - // Returns true if the relation holds. - private static boolean polygonRelatePolygon_(Polygon polygon_a, - Polygon polygon_b, double tolerance, int relation, - ProgressTracker progress_tracker) { - switch (relation) { - case Relation.disjoint: - return polygonDisjointPolygon_(polygon_a, polygon_b, tolerance, - progress_tracker); - - case Relation.within: - return polygonContainsPolygon_(polygon_b, polygon_a, tolerance, - progress_tracker); - - case Relation.contains: - return polygonContainsPolygon_(polygon_a, polygon_b, tolerance, - progress_tracker); - - case Relation.equals: - return polygonEqualsPolygon_(polygon_a, polygon_b, tolerance, - progress_tracker); - - case Relation.touches: - return polygonTouchesPolygon_(polygon_a, polygon_b, tolerance, - progress_tracker); - - case Relation.overlaps: - return polygonOverlapsPolygon_(polygon_a, polygon_b, tolerance, - progress_tracker); - - default: - break; // warning fix - } - - return false; - } - - // Returns true if the relation holds. - private static boolean polygonRelatePolyline_(Polygon polygon_a, - Polyline polyline_b, double tolerance, int relation, - ProgressTracker progress_tracker) { - switch (relation) { - case Relation.disjoint: - return polygonDisjointPolyline_(polygon_a, polyline_b, tolerance, - progress_tracker); - - case Relation.contains: - return polygonContainsPolyline_(polygon_a, polyline_b, tolerance, - progress_tracker); - - case Relation.touches: - return polygonTouchesPolyline_(polygon_a, polyline_b, tolerance, - progress_tracker); - - case Relation.crosses: - return polygonCrossesPolyline_(polygon_a, polyline_b, tolerance, - progress_tracker); - - default: - break; // warning fix - } - - return false; - } - - // Returns true if the relation holds. - private static boolean polygonRelatePoint_(Polygon polygon_a, - Point point_b, double tolerance, int relation, - ProgressTracker progress_tracker) { - switch (relation) { - case Relation.disjoint: - return polygonDisjointPoint_(polygon_a, point_b, tolerance, - progress_tracker); - - case Relation.contains: - return polygonContainsPoint_(polygon_a, point_b, tolerance, - progress_tracker); - - case Relation.touches: - return polygonTouchesPoint_(polygon_a, point_b, tolerance, - progress_tracker); - - default: - break; // warning fix - } - - return false; - } - - // Returns true if the relation holds - private static boolean polygonRelateMultiPoint_(Polygon polygon_a, - MultiPoint multipoint_b, double tolerance, int relation, - ProgressTracker progress_tracker) { - switch (relation) { - case Relation.disjoint: - return polygonDisjointMultiPoint_(polygon_a, multipoint_b, - tolerance, true, progress_tracker); - - case Relation.contains: - return polygonContainsMultiPoint_(polygon_a, multipoint_b, - tolerance, progress_tracker); - - case Relation.touches: - return polygonTouchesMultiPoint_(polygon_a, multipoint_b, - tolerance, progress_tracker); - - case Relation.crosses: - return polygonCrossesMultiPoint_(polygon_a, multipoint_b, - tolerance, progress_tracker); - - default: - break; // warning fix - } - - return false; - } - - // Returns true if the relation holds - private static boolean polygonRelateEnvelope_(Polygon polygon_a, - Envelope envelope_b, double tolerance, int relation, - ProgressTracker progress_tracker) { - if (polygonDisjointEnvelope_(polygon_a, envelope_b, tolerance, - progress_tracker)) { - if (relation == Relation.disjoint) - return true; - - return false; - } else if (relation == Relation.disjoint) { - return false; - } - - switch (relation) { - case Relation.within: - return polygonWithinEnvelope_(polygon_a, envelope_b, tolerance, - progress_tracker); - - case Relation.contains: - return polygonContainsEnvelope_(polygon_a, envelope_b, tolerance, - progress_tracker); - - case Relation.equals: - return polygonEqualsEnvelope_(polygon_a, envelope_b, tolerance, - progress_tracker); - - case Relation.touches: - return polygonTouchesEnvelope_(polygon_a, envelope_b, tolerance, - progress_tracker); - - case Relation.overlaps: - return polygonOverlapsEnvelope_(polygon_a, envelope_b, tolerance, - progress_tracker); - - case Relation.crosses: - return polygonCrossesEnvelope_(polygon_a, envelope_b, tolerance, - progress_tracker); - - default: - break; // warning fix - } - - return false; - } - - // Returns true if the relation holds. - private static boolean polylineRelatePolyline_(Polyline polyline_a, - Polyline polyline_b, double tolerance, int relation, - ProgressTracker progress_tracker) { - switch (relation) { - case Relation.disjoint: - return polylineDisjointPolyline_(polyline_a, polyline_b, tolerance, - progress_tracker); - - case Relation.within: - return polylineContainsPolyline_(polyline_b, polyline_a, tolerance, - progress_tracker); - - case Relation.contains: - return polylineContainsPolyline_(polyline_a, polyline_b, tolerance, - progress_tracker); - - case Relation.equals: - return polylineEqualsPolyline_(polyline_a, polyline_b, tolerance, - progress_tracker); - - case Relation.touches: - return polylineTouchesPolyline_(polyline_a, polyline_b, tolerance, - progress_tracker); - - case Relation.overlaps: - return polylineOverlapsPolyline_(polyline_a, polyline_b, tolerance, - progress_tracker); - - case Relation.crosses: - return polylineCrossesPolyline_(polyline_a, polyline_b, tolerance, - progress_tracker); - - default: - break; // warning fix - } - - return false; - } - - // Returns true if the relation holds. - private static boolean polylineRelatePoint_(Polyline polyline_a, - Point point_b, double tolerance, int relation, - ProgressTracker progress_tracker) { - switch (relation) { - case Relation.disjoint: - return polylineDisjointPoint_(polyline_a, point_b, tolerance, - progress_tracker); - - case Relation.contains: - return polylineContainsPoint_(polyline_a, point_b, tolerance, - progress_tracker); - - case Relation.touches: - return polylineTouchesPoint_(polyline_a, point_b, tolerance, - progress_tracker); - - default: - break; // warning fix - } - - return false; - } - - // Returns true if the relation holds. - private static boolean polylineRelateMultiPoint_(Polyline polyline_a, - MultiPoint multipoint_b, double tolerance, int relation, - ProgressTracker progress_tracker) { - switch (relation) { - case Relation.disjoint: - return polylineDisjointMultiPoint_(polyline_a, multipoint_b, - tolerance, progress_tracker); - - case Relation.contains: - return polylineContainsMultiPoint_(polyline_a, multipoint_b, - tolerance, progress_tracker); - - case Relation.touches: - return polylineTouchesMultiPoint_(polyline_a, multipoint_b, - tolerance, progress_tracker); - - case Relation.crosses: - return polylineCrossesMultiPoint_(polyline_a, multipoint_b, - tolerance, progress_tracker); - - default: - break; // warning fix - } - - return false; - } - - // Returns true if the relation holds. - private static boolean polylineRelateEnvelope_(Polyline polyline_a, - Envelope envelope_b, double tolerance, int relation, - ProgressTracker progress_tracker) { - if (polylineDisjointEnvelope_(polyline_a, envelope_b, tolerance, - progress_tracker)) { - if (relation == Relation.disjoint) - return true; - - return false; - } else if (relation == Relation.disjoint) { - return false; - } - - switch (relation) { - case Relation.within: - return polylineWithinEnvelope_(polyline_a, envelope_b, tolerance, - progress_tracker); - - case Relation.contains: - return polylineContainsEnvelope_(polyline_a, envelope_b, tolerance, - progress_tracker); - - case Relation.equals: - return polylineEqualsEnvelope_(polyline_a, envelope_b, tolerance, - progress_tracker); - - case Relation.touches: - return polylineTouchesEnvelope_(polyline_a, envelope_b, tolerance, - progress_tracker); - - case Relation.overlaps: - return polylineOverlapsEnvelope_(polyline_a, envelope_b, tolerance, - progress_tracker); - - case Relation.crosses: - return polylineCrossesEnvelope_(polyline_a, envelope_b, tolerance, - progress_tracker); - - default: - break; // warning fix - } - - return false; - } - - // Returns true if the relation holds. - private static boolean multiPointRelateMultiPoint_(MultiPoint multipoint_a, - MultiPoint multipoint_b, double tolerance, int relation, - ProgressTracker progress_tracker) { - switch (relation) { - case Relation.disjoint: - return multiPointDisjointMultiPoint_(multipoint_a, multipoint_b, - tolerance, progress_tracker); - - case Relation.within: - return multiPointContainsMultiPoint_(multipoint_b, multipoint_a, - tolerance, progress_tracker); - - case Relation.contains: - return multiPointContainsMultiPoint_(multipoint_a, multipoint_b, - tolerance, progress_tracker); - - case Relation.equals: - return multiPointEqualsMultiPoint_(multipoint_a, multipoint_b, - tolerance, progress_tracker); - - case Relation.overlaps: - return multiPointOverlapsMultiPoint_(multipoint_a, multipoint_b, - tolerance, progress_tracker); - - default: - break; // warning fix - } - - return false; - } - - // Returns true if the relation holds. - private static boolean multiPointRelatePoint_(MultiPoint multipoint_a, - Point point_b, double tolerance, int relation, - ProgressTracker progress_tracker) { - switch (relation) { - case Relation.disjoint: - return multiPointDisjointPoint_(multipoint_a, point_b, tolerance, - progress_tracker); - - case Relation.within: - return multiPointWithinPoint_(multipoint_a, point_b, tolerance, - progress_tracker); - - case Relation.contains: - return multiPointContainsPoint_(multipoint_a, point_b, tolerance, - progress_tracker); - - case Relation.equals: - return multiPointEqualsPoint_(multipoint_a, point_b, tolerance, - progress_tracker); - - default: - break; // warning fix - } - - return false; - } - - // Returns true if the relation holds. - private static boolean multiPointRelateEnvelope_(MultiPoint multipoint_a, - Envelope envelope_b, double tolerance, int relation, - ProgressTracker progress_tracker) { - switch (relation) { - case Relation.disjoint: - return multiPointDisjointEnvelope_(multipoint_a, envelope_b, - tolerance, progress_tracker); - - case Relation.within: - return multiPointWithinEnvelope_(multipoint_a, envelope_b, - tolerance, progress_tracker); - - case Relation.contains: - return multiPointContainsEnvelope_(multipoint_a, envelope_b, - tolerance, progress_tracker); - - case Relation.equals: - return multiPointEqualsEnvelope_(multipoint_a, envelope_b, - tolerance, progress_tracker); - - case Relation.touches: - return multiPointTouchesEnvelope_(multipoint_a, envelope_b, - tolerance, progress_tracker); - - case Relation.crosses: - return multiPointCrossesEnvelope_(multipoint_a, envelope_b, - tolerance, progress_tracker); - - default: - break; // warning fix - } - - return false; - } - - // Returns true if polygon_a equals polygon_b. - private static boolean polygonEqualsPolygon_(Polygon polygon_a, - Polygon polygon_b, double tolerance, - ProgressTracker progress_tracker) { - Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(); - polygon_a.queryEnvelope2D(env_a); - polygon_b.queryEnvelope2D(env_b); - - // Quick envelope rejection test for false equality. - if (!envelopeEqualsEnvelope_(env_a, env_b, tolerance, progress_tracker)) - return false; - - // Quick rasterize test to see whether the the geometries are disjoint, - // or if one is contained in the other. - int relation = tryRasterizedContainsOrDisjoint_(polygon_a, polygon_b, - tolerance, false); - - if (relation == Relation.disjoint || relation == Relation.contains - || relation == Relation.within) - return false; - - // Quick point equality check for true equality. This just checks if all - // the points in each ring are the same (within a tolerance) and in the - // same order - if (multiPathExactlyEqualsMultiPath_(polygon_a, polygon_b, tolerance, - progress_tracker)) - return true; - - double length_a = polygon_a.calculateLength2D(); - double length_b = polygon_b.calculateLength2D(); - int max_vertices = Math.max(polygon_a.getPointCount(), - polygon_b.getPointCount()); - - if (Math.abs(length_a - length_b) > max_vertices * 4.0 * tolerance) - return false; - - return linearPathEqualsLinearPath_(polygon_a, polygon_b, tolerance, true); - } - - // Returns true if polygon_a is disjoint from polygon_b. - private static boolean polygonDisjointPolygon_(Polygon polygon_a, - Polygon polygon_b, double tolerance, - ProgressTracker progress_tracker) { - // Quick rasterize test to see whether the the geometries are disjoint, - // or if one is contained in the other. - int relation = tryRasterizedContainsOrDisjoint_(polygon_a, polygon_b, - tolerance, true); - - if (relation == Relation.disjoint) - return true; - - if (relation == Relation.contains || relation == Relation.within - || relation == Relation.intersects) - return false; - - return polygonDisjointMultiPath_(polygon_a, polygon_b, tolerance, - progress_tracker); - } - - // Returns true if polygon_a touches polygon_b. - private static boolean polygonTouchesPolygon_(Polygon polygon_a, - Polygon polygon_b, double tolerance, - ProgressTracker progress_tracker) { - // Quick rasterize test to see whether the the geometries are disjoint, - // or if one is contained in the other. - int relation = tryRasterizedContainsOrDisjoint_(polygon_a, polygon_b, - tolerance, false); - - if (relation == Relation.disjoint || relation == Relation.contains - || relation == Relation.within) - return false; - - return polygonTouchesPolygonImpl_(polygon_a, polygon_b, tolerance, null); - } - - // Returns true if polygon_a overlaps polygon_b. - private static boolean polygonOverlapsPolygon_(Polygon polygon_a, - Polygon polygon_b, double tolerance, - ProgressTracker progress_tracker) { - // Quick rasterize test to see whether the the geometries are disjoint, - // or if one is contained in the other. - int relation = tryRasterizedContainsOrDisjoint_(polygon_a, polygon_b, - tolerance, false); - - if (relation == Relation.disjoint || relation == Relation.contains - || relation == Relation.within) - return false; - - return polygonOverlapsPolygonImpl_(polygon_a, polygon_b, tolerance, - progress_tracker); - } - - // Returns true if polygon_a contains polygon_b. - private static boolean polygonContainsPolygon_(Polygon polygon_a, - Polygon polygon_b, double tolerance, - ProgressTracker progress_tracker) { - Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(); - polygon_a.queryEnvelope2D(env_a); - polygon_b.queryEnvelope2D(env_b); - - // Quick envelope rejection test for false equality. - if (!envelopeInfContainsEnvelope_(env_a, env_b, tolerance)) - return false; - - // Quick rasterize test to see whether the the geometries are disjoint, - // or if one is contained in the other. - int relation = tryRasterizedContainsOrDisjoint_(polygon_a, polygon_b, - tolerance, false); - - if (relation == Relation.disjoint || relation == Relation.within) - return false; - - if (relation == Relation.contains) - return true; - - return polygonContainsPolygonImpl_(polygon_a, polygon_b, tolerance, - progress_tracker); - } - - // Returns true if polygon_a is disjoint from polyline_b. - private static boolean polygonDisjointPolyline_(Polygon polygon_a, - Polyline polyline_b, double tolerance, - ProgressTracker progress_tracker) { - // Quick rasterize test to see whether the the geometries are disjoint, - // or if one is contained in the other. - int relation = tryRasterizedContainsOrDisjoint_(polygon_a, polyline_b, - tolerance, true); - - if (relation == Relation.disjoint) - return true; - - if (relation == Relation.contains || relation == Relation.intersects) - return false; - - return polygonDisjointMultiPath_(polygon_a, polyline_b, tolerance, - progress_tracker); - } - - // Returns true if polygon_a touches polyline_b. - private static boolean polygonTouchesPolyline_(Polygon polygon_a, - Polyline polyline_b, double tolerance, - ProgressTracker progress_tracker) { - // Quick rasterize test to see whether the the geometries are disjoint, - // or if one is contained in the other. - int relation = tryRasterizedContainsOrDisjoint_(polygon_a, polyline_b, - tolerance, false); - - if (relation == Relation.disjoint || relation == Relation.contains) - return false; - - return polygonTouchesPolylineImpl_(polygon_a, polyline_b, tolerance, - progress_tracker); - } - - // Returns true if polygon_a crosses polyline_b. - private static boolean polygonCrossesPolyline_(Polygon polygon_a, - Polyline polyline_b, double tolerance, - ProgressTracker progress_tracker) { - // Quick rasterize test to see whether the the geometries are disjoint, - // or if one is contained in the other. - int relation = tryRasterizedContainsOrDisjoint_(polygon_a, polyline_b, - tolerance, false); - - if (relation == Relation.disjoint || relation == Relation.contains) - return false; - - return polygonCrossesPolylineImpl_(polygon_a, polyline_b, tolerance, - null); - } - - // Returns true if polygon_a contains polyline_b. - private static boolean polygonContainsPolyline_(Polygon polygon_a, - Polyline polyline_b, double tolerance, - ProgressTracker progress_tracker) { - Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(); - polygon_a.queryEnvelope2D(env_a); - polyline_b.queryEnvelope2D(env_b); - - // Quick envelope rejection test for false equality. - if (!envelopeInfContainsEnvelope_(env_a, env_b, tolerance)) - return false; - - // Quick rasterize test to see whether the the geometries are disjoint, - // or if one is contained in the other. - int relation = tryRasterizedContainsOrDisjoint_(polygon_a, polyline_b, - tolerance, false); - - if (relation == Relation.disjoint) - return false; - - if (relation == Relation.contains) - return true; - - return polygonContainsPolylineImpl_(polygon_a, polyline_b, tolerance, - progress_tracker); - } - - // Returns true if polygon_a is disjoint from point_b. - private static boolean polygonDisjointPoint_(Polygon polygon_a, - Point point_b, double tolerance, ProgressTracker progress_tracker) { - PolygonUtils.PiPResult result = PolygonUtils.isPointInPolygon2D( - polygon_a, point_b, tolerance); - - if (result == PolygonUtils.PiPResult.PiPOutside) - return true; - - return false; - } - - // Returns true of polygon_a touches point_b. - private static boolean polygonTouchesPoint_(Polygon polygon_a, - Point point_b, double tolerance, ProgressTracker progress_tracker) { - Point2D pt_b = point_b.getXY(); - return polygonTouchesPointImpl_(polygon_a, pt_b, tolerance, null); - } - - // Returns true if polygon_a contains point_b. - private static boolean polygonContainsPoint_(Polygon polygon_a, - Point point_b, double tolerance, ProgressTracker progress_tracker) { - Point2D pt_b = point_b.getXY(); - return polygonContainsPointImpl_(polygon_a, pt_b, tolerance, - progress_tracker); - } - - // Returns true if polygon_a is disjoint from multipoint_b. - private static boolean polygonDisjointMultiPoint_(Polygon polygon_a, - MultiPoint multipoint_b, double tolerance, - boolean bIncludeBoundaryA, ProgressTracker progress_tracker) { - // Quick rasterize test to see whether the the geometries are disjoint, - // or if one is contained in the other. - int relation = tryRasterizedContainsOrDisjoint_(polygon_a, - multipoint_b, tolerance, false); - - if (relation == Relation.disjoint) - return true; - - if (relation == Relation.contains) - return false; - - Envelope2D env_a_inflated = new Envelope2D(); - polygon_a.queryEnvelope2D(env_a_inflated); - env_a_inflated.inflate(tolerance, tolerance); - Point2D ptB = new Point2D(); - - for (int i = 0; i < multipoint_b.getPointCount(); i++) { - multipoint_b.getXY(i, ptB); - - if (!env_a_inflated.contains(ptB)) - continue; - - PolygonUtils.PiPResult result = PolygonUtils.isPointInPolygon2D( - polygon_a, ptB, tolerance); - - if (result == PolygonUtils.PiPResult.PiPInside - || (bIncludeBoundaryA && result == PolygonUtils.PiPResult.PiPBoundary)) - return false; - } - - return true; - } - - // Returns true if polygon_a touches multipoint_b. - private static boolean polygonTouchesMultiPoint_(Polygon polygon_a, - MultiPoint multipoint_b, double tolerance, - ProgressTracker progress_tracker) { - // Quick rasterize test to see whether the the geometries are disjoint, - // or if one is contained in the other. - int relation = tryRasterizedContainsOrDisjoint_(polygon_a, - multipoint_b, tolerance, false); - - if (relation == Relation.disjoint || relation == Relation.contains) - return false; - - Envelope2D env_a_inflated = new Envelope2D(); - polygon_a.queryEnvelope2D(env_a_inflated); - env_a_inflated.inflate(tolerance, tolerance); - - Point2D ptB; - boolean b_boundary = false; - - MultiPathImpl polygon_a_impl = (MultiPathImpl) polygon_a._getImpl(); - - Polygon pa = null; - Polygon p_polygon_a = polygon_a; - - boolean b_checked_polygon_a_quad_tree = false; - - for (int i = 0; i < multipoint_b.getPointCount(); i++) { - ptB = multipoint_b.getXY(i); - - if (env_a_inflated.contains(ptB)) { - - PolygonUtils.PiPResult result = PolygonUtils.isPointInPolygon2D(p_polygon_a, ptB, tolerance); - - if (result == PolygonUtils.PiPResult.PiPBoundary) - b_boundary = true; - else if (result == PolygonUtils.PiPResult.PiPInside) - return false; - } - - if (!b_checked_polygon_a_quad_tree) { - if (PointInPolygonHelper.quadTreeWillHelp(polygon_a, multipoint_b.getPointCount() - 1) && (polygon_a_impl._getAccelerators() == null || polygon_a_impl._getAccelerators().getQuadTree() == null)) { - pa = new Polygon(); - polygon_a.copyTo(pa); - ((MultiPathImpl) pa._getImpl())._buildQuadTreeAccelerator(Geometry.GeometryAccelerationDegree.enumMedium); - p_polygon_a = pa; - } else { - p_polygon_a = polygon_a; - } - - b_checked_polygon_a_quad_tree = true; - } - } - - if (b_boundary) - return true; - - return false; - } - - // Returns true if polygon_a crosses multipoint_b. - private static boolean polygonCrossesMultiPoint_(Polygon polygon_a, - MultiPoint multipoint_b, double tolerance, - ProgressTracker progress_tracker) { - // Quick rasterize test to see whether the the geometries are disjoint, - // or if one is contained in the other. - int relation = tryRasterizedContainsOrDisjoint_(polygon_a, - multipoint_b, tolerance, false); - - if (relation == Relation.disjoint || relation == Relation.contains) - return false; - - Envelope2D env_a = new Envelope2D(), env_a_inflated = new Envelope2D(), env_b = new Envelope2D(); - polygon_a.queryEnvelope2D(env_a); - multipoint_b.queryEnvelope2D(env_b); - env_a_inflated.setCoords(env_a); - env_a_inflated.inflate(tolerance, tolerance); - - boolean b_interior = false, b_exterior = false; - - Point2D pt_b; - - MultiPathImpl polygon_a_impl = (MultiPathImpl) polygon_a._getImpl(); - - Polygon pa = null; - Polygon p_polygon_a = polygon_a; - - boolean b_checked_polygon_a_quad_tree = false; - - for (int i = 0; i < multipoint_b.getPointCount(); i++) { - pt_b = multipoint_b.getXY(i); - - if (!env_a_inflated.contains(pt_b)) { - b_exterior = true; - } else { - PolygonUtils.PiPResult result = PolygonUtils.isPointInPolygon2D(p_polygon_a, pt_b, tolerance); - - if (result == PolygonUtils.PiPResult.PiPOutside) - b_exterior = true; - else if (result == PolygonUtils.PiPResult.PiPInside) - b_interior = true; - } - - if (b_interior && b_exterior) - return true; - - if (!b_checked_polygon_a_quad_tree) { - if (PointInPolygonHelper.quadTreeWillHelp(polygon_a, multipoint_b.getPointCount() - 1) && (polygon_a_impl._getAccelerators() == null || polygon_a_impl._getAccelerators().getQuadTree() == null)) { - pa = new Polygon(); - polygon_a.copyTo(pa); - ((MultiPathImpl) pa._getImpl())._buildQuadTreeAccelerator(Geometry.GeometryAccelerationDegree.enumMedium); - p_polygon_a = pa; - } else { - p_polygon_a = polygon_a; - } - - b_checked_polygon_a_quad_tree = true; - } - } - - return false; - } - - // Returns true if polygon_a contains multipoint_b. - private static boolean polygonContainsMultiPoint_(Polygon polygon_a, - MultiPoint multipoint_b, double tolerance, - ProgressTracker progress_tracker) { - Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(); - polygon_a.queryEnvelope2D(env_a); - multipoint_b.queryEnvelope2D(env_b); - - // Quick envelope rejection test for false equality. - if (!envelopeInfContainsEnvelope_(env_a, env_b, tolerance)) - return false; - - // Quick rasterize test to see whether the the geometries are disjoint, - // or if one is contained in the other. - int relation = tryRasterizedContainsOrDisjoint_(polygon_a, - multipoint_b, tolerance, false); - - if (relation == Relation.disjoint) - return false; - - if (relation == Relation.contains) - return true; - - boolean b_interior = false; - Point2D ptB; - - MultiPathImpl polygon_a_impl = (MultiPathImpl) polygon_a._getImpl(); - - Polygon pa = null; - Polygon p_polygon_a = polygon_a; - - boolean b_checked_polygon_a_quad_tree = false; - - for (int i = 0; i < multipoint_b.getPointCount(); i++) { - ptB = multipoint_b.getXY(i); - - if (!env_a.contains(ptB)) - return false; - - PolygonUtils.PiPResult result = PolygonUtils.isPointInPolygon2D(p_polygon_a, ptB, tolerance); - - if (result == PolygonUtils.PiPResult.PiPInside) - b_interior = true; - else if (result == PolygonUtils.PiPResult.PiPOutside) - return false; - - if (!b_checked_polygon_a_quad_tree) { - if (PointInPolygonHelper.quadTreeWillHelp(polygon_a, multipoint_b.getPointCount() - 1) && (polygon_a_impl._getAccelerators() == null || polygon_a_impl._getAccelerators().getQuadTree() == null)) { - pa = new Polygon(); - polygon_a.copyTo(pa); - ((MultiPathImpl) pa._getImpl())._buildQuadTreeAccelerator(Geometry.GeometryAccelerationDegree.enumMedium); - p_polygon_a = pa; - } else { - p_polygon_a = polygon_a; - } - - b_checked_polygon_a_quad_tree = true; - } - } - - return b_interior; - } - - // Returns true if polygon_a equals envelope_b. - private static boolean polygonEqualsEnvelope_(Polygon polygon_a, - Envelope envelope_b, double tolerance, - ProgressTracker progress_tracker) { - Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(); - polygon_a.queryEnvelope2D(env_a); - envelope_b.queryEnvelope2D(env_b); - - // Quick envelope rejection test for false equality. - // This check will correctly handle degenerate envelope cases (i.e. - // degenerate to point or line) - if (!envelopeEqualsEnvelope_(env_a, env_b, tolerance, progress_tracker)) - return false; - - Polygon polygon_b = new Polygon(); - polygon_b.addEnvelope(envelope_b, false); - - return linearPathEqualsLinearPath_(polygon_a, polygon_b, tolerance, true); - } - - // Returns true if polygon_a is disjoint from envelope_b. - private static boolean polygonDisjointEnvelope_(Polygon polygon_a, - Envelope envelope_b, double tolerance, - ProgressTracker progress_tracker) { - // Quick rasterize test to see whether the the geometries are disjoint, - // or if one is contained in the other. - int relation = tryRasterizedContainsOrDisjoint_(polygon_a, envelope_b, - tolerance, false); - - if (relation == Relation.disjoint) - return true; - - if (relation == Relation.contains || relation == Relation.within) - return false; - - Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(); - polygon_a.queryEnvelope2D(env_a); - envelope_b.queryEnvelope2D(env_b); - - if (envelopeInfContainsEnvelope_(env_b, env_a, tolerance)) - return false; - - PolygonUtils.PiPResult pipres; - Point2D pt_b = new Point2D(); - env_b.queryLowerLeft(pt_b); - pipres = PolygonUtils.isPointInPolygon2D(polygon_a, pt_b, tolerance); - if (pipres != PolygonUtils.PiPResult.PiPOutside) - return false; - - env_b.queryLowerRight(pt_b); - pipres = PolygonUtils.isPointInPolygon2D(polygon_a, pt_b, tolerance); - if (pipres != PolygonUtils.PiPResult.PiPOutside) - return false; - - env_b.queryUpperRight(pt_b); - pipres = PolygonUtils.isPointInPolygon2D(polygon_a, pt_b, tolerance); - if (pipres != PolygonUtils.PiPResult.PiPOutside) - return false; - - env_b.queryUpperLeft(pt_b); - pipres = PolygonUtils.isPointInPolygon2D(polygon_a, pt_b, tolerance); - if (pipres != PolygonUtils.PiPResult.PiPOutside) - return false; - - MultiPathImpl mimpl_a = (MultiPathImpl) polygon_a._getImpl(); - AttributeStreamOfDbl pos = (AttributeStreamOfDbl) (mimpl_a - .getAttributeStreamRef(VertexDescription.Semantics.POSITION)); - - Envelope2D env_b_inflated = new Envelope2D(); - env_b_inflated.setCoords(env_b); - env_b_inflated.inflate(tolerance, tolerance); - for (int ptIndex = 0, n = mimpl_a.getPointCount(); ptIndex < n; ptIndex++) { - double x = pos.read(2 * ptIndex); - double y = pos.read(2 * ptIndex + 1); - if (env_b_inflated.contains(x, y)) - return false; - } - - return !linearPathIntersectsEnvelope_(polygon_a, env_b, tolerance, - progress_tracker); - } - - // Returns true if polygon_a touches envelope_b. - private static boolean polygonTouchesEnvelope_(Polygon polygon_a, - Envelope envelope_b, double tolerance, - ProgressTracker progress_tracker) { - // Quick rasterize test to see whether the the geometries are disjoint, - // or if one is contained in the other. - int relation = tryRasterizedContainsOrDisjoint_(polygon_a, envelope_b, - tolerance, false); - - if (relation == Relation.disjoint || relation == Relation.contains - || relation == Relation.within) - return false; - - Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(); - polygon_a.queryEnvelope2D(env_a); - envelope_b.queryEnvelope2D(env_b); - - if (envelopeInfContainsEnvelope_(env_b, env_a, tolerance)) - return false; - - if (env_b.getWidth() <= tolerance && env_b.getHeight() <= tolerance) {// treat - // as - // point - Point2D pt_b = envelope_b.getCenterXY(); - return polygonTouchesPointImpl_(polygon_a, pt_b, tolerance, - progress_tracker); - } - - if (env_b.getWidth() <= tolerance || env_b.getHeight() <= tolerance) {// treat - // as - // polyline - Polyline polyline_b = new Polyline(); - Point p = new Point(); - envelope_b.queryCornerByVal(0, p); - polyline_b.startPath(p); - envelope_b.queryCornerByVal(2, p); - polyline_b.lineTo(p); - return polygonTouchesPolylineImpl_(polygon_a, polyline_b, - tolerance, progress_tracker); - } - - // treat as polygon - Polygon polygon_b = new Polygon(); - polygon_b.addEnvelope(envelope_b, false); - return polygonTouchesPolygonImpl_(polygon_a, polygon_b, tolerance, - progress_tracker); - } - - // Returns true if polygon_a overlaps envelope_b. - private static boolean polygonOverlapsEnvelope_(Polygon polygon_a, - Envelope envelope_b, double tolerance, - ProgressTracker progress_tracker) { - // Quick rasterize test to see whether the the geometries are disjoint, - // or if one is contained in the other. - int relation = tryRasterizedContainsOrDisjoint_(polygon_a, envelope_b, - tolerance, false); - - if (relation == Relation.disjoint || relation == Relation.contains - || relation == Relation.within) - return false; - - Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(); - polygon_a.queryEnvelope2D(env_a); - envelope_b.queryEnvelope2D(env_b); - - if (envelopeInfContainsEnvelope_(env_b, env_a, tolerance)) - return false; - - if (env_b.getWidth() <= tolerance || env_b.getHeight() <= tolerance) - return false; // has no interior - - Polygon polygon_b = new Polygon(); - polygon_b.addEnvelope(envelope_b, false); - return polygonOverlapsPolygonImpl_(polygon_a, polygon_b, tolerance, - progress_tracker); - } - - // Returns true if polygon_a is within envelope_b - private static boolean polygonWithinEnvelope_(Polygon polygon_a, - Envelope envelope_b, double tolerance, - ProgressTracker progress_tracker) { - Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(); - polygon_a.queryEnvelope2D(env_a); - envelope_b.queryEnvelope2D(env_b); - return envelopeInfContainsEnvelope_(env_b, env_a, tolerance); - } - - // Returns true if polygon_a contains envelope_b. - private static boolean polygonContainsEnvelope_(Polygon polygon_a, - Envelope envelope_b, double tolerance, - ProgressTracker progress_tracker) { - // Quick envelope rejection test - - Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(); - polygon_a.queryEnvelope2D(env_a); - envelope_b.queryEnvelope2D(env_b); - - if (!envelopeInfContainsEnvelope_(env_a, env_b, tolerance)) - return false; - - // Quick rasterize test to see whether the the geometries are disjoint, - // or if one is contained in the other. - int relation = tryRasterizedContainsOrDisjoint_(polygon_a, envelope_b, - tolerance, false); - - if (relation == Relation.disjoint || relation == Relation.within) - return false; - - if (relation == Relation.contains) - return true; - - if (env_b.getWidth() <= tolerance && env_b.getHeight() <= tolerance) {// treat - // as - // point - Point2D pt_b = envelope_b.getCenterXY(); - return polygonContainsPointImpl_(polygon_a, pt_b, tolerance, - progress_tracker); - } - - if (env_b.getWidth() <= tolerance || env_b.getHeight() <= tolerance) {// treat - // as - // polyline - Polyline polyline_b = new Polyline(); - Point p = new Point(); - envelope_b.queryCornerByVal(0, p); - polyline_b.startPath(p); - envelope_b.queryCornerByVal(2, p); - polyline_b.lineTo(p); - return polygonContainsPolylineImpl_(polygon_a, polyline_b, - tolerance, null); - } - - // treat as polygon - Polygon polygon_b = new Polygon(); - polygon_b.addEnvelope(envelope_b, false); - return polygonContainsPolygonImpl_(polygon_a, polygon_b, tolerance, - null); - } - - // Returns true if polygon_a crosses envelope_b. - private static boolean polygonCrossesEnvelope_(Polygon polygon_a, - Envelope envelope_b, double tolerance, - ProgressTracker progress_tracker) { - Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(); - polygon_a.queryEnvelope2D(env_a); - envelope_b.queryEnvelope2D(env_b); - - if (envelopeInfContainsEnvelope_(env_b, env_a, tolerance)) - return false; - - if (env_b.getHeight() > tolerance && env_b.getWidth() > tolerance) - return false; // when treated as an area, areas cannot cross areas. - - if (env_b.getHeight() <= tolerance && env_b.getWidth() <= tolerance) - return false; // when treated as a point, areas cannot cross points. - - // Treat as polyline - Polyline polyline_b = new Polyline(); - Point p = new Point(); - envelope_b.queryCornerByVal(0, p); - polyline_b.startPath(p); - envelope_b.queryCornerByVal(2, p); - polyline_b.lineTo(p); - return polygonCrossesPolylineImpl_(polygon_a, polyline_b, tolerance, - progress_tracker); - } - - // Returns true if polyline_a equals polyline_b. - private static boolean polylineEqualsPolyline_(Polyline polyline_a, - Polyline polyline_b, double tolerance, - ProgressTracker progress_tracker) { - Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(); - polyline_a.queryEnvelope2D(env_a); - polyline_b.queryEnvelope2D(env_b); - - // Quick envelope rejection test for false equality. - if (!envelopeEqualsEnvelope_(env_a, env_b, tolerance, progress_tracker)) - return false; - - // Quick rasterize test to see whether the the geometries are disjoint. - if (tryRasterizedContainsOrDisjoint_(polyline_a, polyline_b, tolerance, - false) == Relation.disjoint) - return false; - - // Quick point equality check for true equality. This just checks if all - // the points in each ring are the same (within a tolerance) and in the - // same order - if (multiPathExactlyEqualsMultiPath_(polyline_a, polyline_b, tolerance, - progress_tracker)) - return true; - - return linearPathEqualsLinearPath_(polyline_a, polyline_b, tolerance, false); - } - - // Returns true if polyline_a is disjoint from polyline_b. - private static boolean polylineDisjointPolyline_(Polyline polyline_a, - Polyline polyline_b, double tolerance, - ProgressTracker progress_tracker) { - // Quick rasterize test to see whether the the geometries are disjoint. - if (tryRasterizedContainsOrDisjoint_(polyline_a, polyline_b, tolerance, - false) == Relation.disjoint) - return true; - - MultiPathImpl multi_path_impl_a = (MultiPathImpl) polyline_a._getImpl(); - MultiPathImpl multi_path_impl_b = (MultiPathImpl) polyline_b._getImpl(); - - PairwiseIntersectorImpl intersector_paths = new PairwiseIntersectorImpl(multi_path_impl_a, multi_path_impl_b, tolerance, true); - - if (!intersector_paths.next()) - return false; - - return !linearPathIntersectsLinearPath_(polyline_a, polyline_b, - tolerance); - } - - // Returns true if polyline_a touches polyline_b. - private static boolean polylineTouchesPolyline_(Polyline polyline_a, - Polyline polyline_b, double tolerance, - ProgressTracker progress_tracker) { - // Quick rasterize test to see whether the the geometries are disjoint. - if (tryRasterizedContainsOrDisjoint_(polyline_a, polyline_b, tolerance, - false) == Relation.disjoint) - return false; - - AttributeStreamOfDbl intersections = new AttributeStreamOfDbl(0); - - int dim = linearPathIntersectsLinearPathMaxDim_(polyline_a, polyline_b, - tolerance, intersections); - - if (dim != 0) - return false; - - MultiPoint intersection = new MultiPoint(); - - for (int i = 0; i < intersections.size(); i += 2) { - double x = intersections.read(i); - double y = intersections.read(i + 1); - intersection.add(x, y); - } - - MultiPoint boundary_a_b = (MultiPoint) (polyline_a.getBoundary()); - MultiPoint boundary_b = (MultiPoint) (polyline_b.getBoundary()); - - boundary_a_b.add(boundary_b, 0, boundary_b.getPointCount()); - - return multiPointContainsMultiPointBrute_(boundary_a_b, intersection, - tolerance); - } - - // Returns true if polyline_a crosses polyline_b. - private static boolean polylineCrossesPolyline_(Polyline polyline_a, - Polyline polyline_b, double tolerance, - ProgressTracker progress_tracker) { - // Quick rasterize test to see whether the the geometries are disjoint. - if (tryRasterizedContainsOrDisjoint_(polyline_a, polyline_b, tolerance, - false) == Relation.disjoint) - return false; - - AttributeStreamOfDbl intersections = new AttributeStreamOfDbl(0); - - int dim = linearPathIntersectsLinearPathMaxDim_(polyline_a, polyline_b, - tolerance, intersections); - - if (dim != 0) - return false; - - MultiPoint intersection = new MultiPoint(); - - for (int i = 0; i < intersections.size(); i += 2) { - double x = intersections.read(i); - double y = intersections.read(i + 1); - intersection.add(x, y); - } - - MultiPoint boundary_a_b = (MultiPoint) (polyline_a.getBoundary()); - MultiPoint boundary_b = (MultiPoint) (polyline_b.getBoundary()); - - boundary_a_b.add(boundary_b, 0, boundary_b.getPointCount()); - - return !multiPointContainsMultiPointBrute_(boundary_a_b, intersection, - tolerance); - } - - // Returns true if polyline_a overlaps polyline_b. - private static boolean polylineOverlapsPolyline_(Polyline polyline_a, - Polyline polyline_b, double tolerance, - ProgressTracker progress_tracker) { - // Quick rasterize test to see whether the the geometries are disjoint. - if (tryRasterizedContainsOrDisjoint_(polyline_a, polyline_b, tolerance, - false) == Relation.disjoint) - return false; - - return linearPathOverlapsLinearPath_(polyline_a, polyline_b, tolerance); - } - - // Returns true if polyline_a contains polyline_b. - private static boolean polylineContainsPolyline_(Polyline polyline_a, - Polyline polyline_b, double tolerance, - ProgressTracker progress_tracker) { - Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(); - polyline_a.queryEnvelope2D(env_a); - polyline_b.queryEnvelope2D(env_b); - - // Quick envelope rejection test for false equality. - if (!envelopeInfContainsEnvelope_(env_a, env_b, tolerance)) - return false; - - // Quick rasterize test to see whether the the geometries are disjoint. - if (tryRasterizedContainsOrDisjoint_(polyline_a, polyline_b, tolerance, - false) == Relation.disjoint) - return false; - - return linearPathWithinLinearPath_(polyline_b, polyline_a, tolerance, false); - } - - // Returns true if polyline_a is disjoint from point_b. - private static boolean polylineDisjointPoint_(Polyline polyline_a, - Point point_b, double tolerance, ProgressTracker progress_tracker) { - // Quick rasterize test to see whether the the geometries are disjoint. - if (tryRasterizedContainsOrDisjoint_(polyline_a, point_b, tolerance, - false) == Relation.disjoint) - return true; - - Point2D pt_b = point_b.getXY(); - return !linearPathIntersectsPoint_(polyline_a, pt_b, tolerance); - } - - // Returns true if polyline_a touches point_b. - private static boolean polylineTouchesPoint_(Polyline polyline_a, - Point point_b, double tolerance, ProgressTracker progress_tracker) { - // Quick rasterize test to see whether the the geometries are disjoint. - if (tryRasterizedContainsOrDisjoint_(polyline_a, point_b, tolerance, - false) == Relation.disjoint) - return false; - - Point2D pt_b = point_b.getXY(); - return linearPathTouchesPointImpl_(polyline_a, pt_b, tolerance); - } - - // Returns true of polyline_a contains point_b. - private static boolean polylineContainsPoint_(Polyline polyline_a, - Point point_b, double tolerance, ProgressTracker progress_tracker) { - // Quick rasterize test to see whether the the geometries are disjoint. - if (tryRasterizedContainsOrDisjoint_(polyline_a, point_b, tolerance, - false) == Relation.disjoint) - return false; - - Point2D pt_b = point_b.getXY(); - return linearPathContainsPoint_(polyline_a, pt_b, tolerance); - } - - // Returns true if polyline_a is disjoint from multipoint_b. - private static boolean polylineDisjointMultiPoint_(Polyline polyline_a, - MultiPoint multipoint_b, double tolerance, - ProgressTracker progress_tracker) { - // Quick rasterize test to see whether the the geometries are disjoint. - if (tryRasterizedContainsOrDisjoint_(polyline_a, multipoint_b, - tolerance, false) == Relation.disjoint) - return true; - - return !linearPathIntersectsMultiPoint_(polyline_a, multipoint_b, - tolerance, false); - } - - // Returns true if polyline_a touches multipoint_b. - private static boolean polylineTouchesMultiPoint_(Polyline polyline_a, - MultiPoint multipoint_b, double tolerance, - ProgressTracker progress_tracker) { - // Quick rasterize test to see whether the the geometries are disjoint. - if (tryRasterizedContainsOrDisjoint_(polyline_a, multipoint_b, - tolerance, false) == Relation.disjoint) { - return false; - } - - SegmentIteratorImpl segIterA = ((MultiPathImpl) polyline_a._getImpl()) - .querySegmentIterator(); - - Envelope2D env_a = new Envelope2D(); - Envelope2D env_b = new Envelope2D(); - Envelope2D envInter = new Envelope2D(); - polyline_a.queryEnvelope2D(env_a); - multipoint_b.queryEnvelope2D(env_b); - env_a.inflate(tolerance, tolerance); - env_b.inflate(tolerance, tolerance); - envInter.setCoords(env_a); - envInter.intersect(env_b); - - QuadTreeImpl qtA = null; - QuadTreeImpl quadTreeA = null; - QuadTreeImpl quadTreePathsA = null; - - GeometryAccelerators accel = ((MultiPathImpl) (polyline_a._getImpl())) - ._getAccelerators(); - - if (accel != null) { - quadTreeA = accel.getQuadTree(); - quadTreePathsA = accel.getQuadTreeForPaths(); - if (quadTreeA == null) { - qtA = InternalUtils.buildQuadTree( - (MultiPathImpl) polyline_a._getImpl(), envInter); - quadTreeA = qtA; - } - } else { - qtA = InternalUtils.buildQuadTree( - (MultiPathImpl) polyline_a._getImpl(), envInter); - quadTreeA = qtA; - } - - QuadTreeImpl.QuadTreeIteratorImpl qtIterA = quadTreeA.getIterator(); - - QuadTreeImpl.QuadTreeIteratorImpl qtIterPathsA = null; - if (quadTreePathsA != null) - qtIterPathsA = quadTreePathsA.getIterator(); - - Point2D ptB = new Point2D(), closest = new Point2D(); - boolean b_intersects = false; - double toleranceSq = tolerance * tolerance; - - AttributeStreamOfInt8 intersects = new AttributeStreamOfInt8( - multipoint_b.getPointCount()); - for (int i = 0; i < multipoint_b.getPointCount(); i++) { - intersects.write(i, (byte) 0); - } - - for (int i = 0; i < multipoint_b.getPointCount(); i++) { - multipoint_b.getXY(i, ptB); - - if (!envInter.contains(ptB)) { - continue; - } - - env_b.setCoords(ptB.x, ptB.y, ptB.x, ptB.y); - - if (qtIterPathsA != null) { - qtIterPathsA.resetIterator(env_b, tolerance); - - if (qtIterPathsA.next() == -1) - continue; - } - - qtIterA.resetIterator(env_b, tolerance); - - for (int elementHandleA = qtIterA.next(); elementHandleA != -1; elementHandleA = qtIterA - .next()) { - int vertex_a = quadTreeA.getElement(elementHandleA); - segIterA.resetToVertex(vertex_a); - - Segment segmentA = segIterA.nextSegment(); - double t = segmentA.getClosestCoordinate(ptB, false); - segmentA.getCoord2D(t, closest); - - if (Point2D.sqrDistance(ptB, closest) <= toleranceSq) { - intersects.write(i, (byte) 1); - b_intersects = true; - break; - } - } - } - - if (!b_intersects) { - return false; - } - - MultiPoint boundary_a = (MultiPoint) (polyline_a.getBoundary()); - MultiPoint multipoint_b_inter = new MultiPoint(); - Point2D pt = new Point2D(); - - for (int i = 0; i < multipoint_b.getPointCount(); i++) { - if (intersects.read(i) == 0) { - continue; - } - - multipoint_b.getXY(i, pt); - multipoint_b_inter.add(pt.x, pt.y); - } - - return multiPointContainsMultiPointBrute_(boundary_a, - multipoint_b_inter, tolerance); - } - - // Returns true if polyline_a crosses multipoint_b. - private static boolean polylineCrossesMultiPoint_(Polyline polyline_a, - MultiPoint multipoint_b, double tolerance, - ProgressTracker progress_tracker) { - // Quick rasterize test to see whether the the geometries are disjoint. - if (tryRasterizedContainsOrDisjoint_(polyline_a, multipoint_b, - tolerance, false) == Relation.disjoint) { - return false; - } - - SegmentIteratorImpl segIterA = ((MultiPathImpl) polyline_a._getImpl()) - .querySegmentIterator(); - - Envelope2D env_a = new Envelope2D(); - Envelope2D env_b = new Envelope2D(); - Envelope2D envInter = new Envelope2D(); - polyline_a.queryEnvelope2D(env_a); - multipoint_b.queryEnvelope2D(env_b); - env_a.inflate(tolerance, tolerance); - env_b.inflate(tolerance, tolerance); - envInter.setCoords(env_a); - envInter.intersect(env_b); - - QuadTreeImpl qtA = null; - QuadTreeImpl quadTreeA = null; - QuadTreeImpl quadTreePathsA = null; - - GeometryAccelerators accel = ((MultiPathImpl) (polyline_a._getImpl())) - ._getAccelerators(); - - if (accel != null) { - quadTreeA = accel.getQuadTree(); - quadTreePathsA = accel.getQuadTreeForPaths(); - if (quadTreeA == null) { - qtA = InternalUtils.buildQuadTree( - (MultiPathImpl) polyline_a._getImpl(), envInter); - quadTreeA = qtA; - } - } else { - qtA = InternalUtils.buildQuadTree( - (MultiPathImpl) polyline_a._getImpl(), envInter); - quadTreeA = qtA; - } - - QuadTreeImpl.QuadTreeIteratorImpl qtIterA = quadTreeA.getIterator(); - - QuadTreeImpl.QuadTreeIteratorImpl qtIterPathsA = null; - if (quadTreePathsA != null) - qtIterPathsA = quadTreePathsA.getIterator(); - - Point2D ptB = new Point2D(), closest = new Point2D(); - boolean b_intersects = false; - boolean b_exterior_found = false; - double toleranceSq = tolerance * tolerance; - - AttributeStreamOfInt8 intersects = new AttributeStreamOfInt8( - multipoint_b.getPointCount()); - for (int i = 0; i < multipoint_b.getPointCount(); i++) { - intersects.write(i, (byte) 0); - } - - for (int i = 0; i < multipoint_b.getPointCount(); i++) { - multipoint_b.getXY(i, ptB); - - if (!envInter.contains(ptB)) { - b_exterior_found = true; - continue; - } - - env_b.setCoords(ptB.x, ptB.y, ptB.x, ptB.y); - - if (qtIterPathsA != null) { - qtIterPathsA.resetIterator(env_b, tolerance); - - if (qtIterPathsA.next() == -1) { - b_exterior_found = true; - continue; - } - } - - qtIterA.resetIterator(env_b, tolerance); - - boolean b_covered = false; - - for (int elementHandleA = qtIterA.next(); elementHandleA != -1; elementHandleA = qtIterA - .next()) { - int vertex_a = quadTreeA.getElement(elementHandleA); - segIterA.resetToVertex(vertex_a); - - Segment segmentA = segIterA.nextSegment(); - double t = segmentA.getClosestCoordinate(ptB, false); - segmentA.getCoord2D(t, closest); - - if (Point2D.sqrDistance(ptB, closest) <= toleranceSq) { - intersects.write(i, (byte) 1); - b_intersects = true; - b_covered = true; - break; - } - } - - if (!b_covered) { - b_exterior_found = true; - } - } - - if (!b_intersects || !b_exterior_found) { - return false; - } - - MultiPoint boundary_a = (MultiPoint) (polyline_a.getBoundary()); - MultiPoint multipoint_b_inter = new MultiPoint(); - Point2D pt = new Point2D(); - - for (int i = 0; i < multipoint_b.getPointCount(); i++) { - if (intersects.read(i) == 0) { - continue; - } - - multipoint_b.getXY(i, pt); - multipoint_b_inter.add(pt.x, pt.y); - } - - return !multiPointContainsMultiPointBrute_(boundary_a, - multipoint_b_inter, tolerance); - } - - // Returns true if polyline_a contains multipoint_b. - private static boolean polylineContainsMultiPoint_(Polyline polyline_a, - MultiPoint multipoint_b, double tolerance, - ProgressTracker progress_tracker) { - Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(); - polyline_a.queryEnvelope2D(env_a); - multipoint_b.queryEnvelope2D(env_b); - - if (!envelopeInfContainsEnvelope_(env_a, env_b, tolerance)) - return false; - - // Quick rasterize test to see whether the the geometries are disjoint. - if (tryRasterizedContainsOrDisjoint_(polyline_a, multipoint_b, - tolerance, false) == Relation.disjoint) - return false; - - if (!linearPathIntersectsMultiPoint_(polyline_a, multipoint_b, - tolerance, true)) - return false; - - MultiPoint boundary_a = (MultiPoint) (polyline_a.getBoundary()); - return !multiPointIntersectsMultiPoint_(boundary_a, multipoint_b, - tolerance, progress_tracker); - } - - // Returns true if polyline_a equals envelope_b. - private static boolean polylineEqualsEnvelope_(Polyline polyline_a, - Envelope envelope_b, double tolerance, - ProgressTracker progress_tracker) { - Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(); - polyline_a.queryEnvelope2D(env_a); - envelope_b.queryEnvelope2D(env_b); - - if (env_b.getHeight() > tolerance && env_b.getWidth() > tolerance) - return false; // area cannot equal a line - - return envelopeEqualsEnvelope_(env_a, env_b, tolerance, - progress_tracker); - } - - // Returns true if polyline_a is disjoint from envelope_b. - private static boolean polylineDisjointEnvelope_(Polyline polyline_a, - Envelope envelope_b, double tolerance, - ProgressTracker progress_tracker) { - Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(); - polyline_a.queryEnvelope2D(env_a); - envelope_b.queryEnvelope2D(env_b); - - if (envelopeInfContainsEnvelope_(env_b, env_a, tolerance)) - return false; - - return !linearPathIntersectsEnvelope_(polyline_a, env_b, tolerance, - progress_tracker); - } - - // Returns true if polyline_a touches envelope_b. - private static boolean polylineTouchesEnvelope_(Polyline polyline_a, - Envelope envelope_b, double tolerance, - ProgressTracker progress_tracker) { - Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(); - polyline_a.queryEnvelope2D(env_a); - envelope_b.queryEnvelope2D(env_b); - - if (env_b.getHeight() <= tolerance && env_b.getWidth() <= tolerance) {// Treat - // as - // point - Point2D pt_b = envelope_b.getCenterXY(); - return linearPathTouchesPointImpl_(polyline_a, pt_b, tolerance); - } - - if (env_b.getHeight() <= tolerance || env_b.getWidth() <= tolerance) {// Treat - // as - // polyline - Polyline polyline_b = new Polyline(); - Point p = new Point(); - envelope_b.queryCornerByVal(0, p); - polyline_b.startPath(p); - envelope_b.queryCornerByVal(2, p); - polyline_b.lineTo(p); - return polylineTouchesPolyline_(polyline_a, polyline_b, tolerance, - progress_tracker); - } - - // Treat env_b as area - - SegmentIterator seg_iter_a = polyline_a.querySegmentIterator(); - Envelope2D env_b_deflated = new Envelope2D(), env_b_inflated = new Envelope2D(); - env_b_deflated.setCoords(env_b); - env_b_inflated.setCoords(env_b); - env_b_deflated.inflate(-tolerance, -tolerance); - env_b_inflated.inflate(tolerance, tolerance); - - boolean b_boundary = false; - Envelope2D env_segment_a = new Envelope2D(); - Envelope2D env_inter = new Envelope2D(); - - while (seg_iter_a.nextPath()) { - while (seg_iter_a.hasNextSegment()) { - Segment segment_a = seg_iter_a.nextSegment(); - segment_a.queryEnvelope2D(env_segment_a); - - env_inter.setCoords(env_b_deflated); - env_inter.intersect(env_segment_a); - - if (!env_inter.isEmpty() - && (env_inter.getHeight() > tolerance || env_inter - .getWidth() > tolerance)) - return false; // consider segment within - - env_inter.setCoords(env_b_inflated); - env_inter.intersect(env_segment_a); - - if (!env_inter.isEmpty()) - b_boundary = true; - } - } - - return b_boundary; - } - - // Returns true if polyline_a overlaps envelope_b. - private static boolean polylineOverlapsEnvelope_(Polyline polyline_a, - Envelope envelope_b, double tolerance, - ProgressTracker progress_tracker) { - Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(); - polyline_a.queryEnvelope2D(env_a); - envelope_b.queryEnvelope2D(env_b); - - if (envelopeInfContainsEnvelope_(env_a, env_b, tolerance) - || envelopeInfContainsEnvelope_(env_b, env_a, tolerance)) - return false; - - if (envelopeInfContainsEnvelope_(env_b, env_a, tolerance)) - return false; - - if (env_b.getHeight() > tolerance && env_b.getWidth() > tolerance) - return false; // lines cannot overlap areas - - if (env_b.getHeight() <= tolerance && env_b.getWidth() <= tolerance) - return false; // lines cannot overlap points - - // Treat as polyline - Polyline polyline_b = new Polyline(); - Point p = new Point(); - envelope_b.queryCornerByVal(0, p); - polyline_b.startPath(p); - envelope_b.queryCornerByVal(2, p); - polyline_b.lineTo(p); - return linearPathOverlapsLinearPath_(polyline_a, polyline_b, tolerance); - } - - // Returns true if polyline_a is within envelope_b. - private static boolean polylineWithinEnvelope_(Polyline polyline_a, - Envelope envelope_b, double tolerance, - ProgressTracker progress_tracker) { - Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(); - polyline_a.queryEnvelope2D(env_a); - envelope_b.queryEnvelope2D(env_b); - - if (!envelopeInfContainsEnvelope_(env_b, env_a, tolerance)) - return false; - - if (env_b.getHeight() <= tolerance && env_b.getWidth() <= tolerance) - return false; - - if (env_b.getHeight() <= tolerance || env_b.getWidth() <= tolerance) - return envelopeInfContainsEnvelope_(env_b, env_a, tolerance); - - SegmentIterator seg_iter_a = polyline_a.querySegmentIterator(); - Envelope2D env_b_deflated = new Envelope2D(); - env_b_deflated.setCoords(env_b); - env_b_deflated.inflate(-tolerance, -tolerance); - - boolean b_interior = false; - Envelope2D env_segment_a = new Envelope2D(); - Envelope2D env_inter = new Envelope2D(); - - while (seg_iter_a.nextPath()) { - while (seg_iter_a.hasNextSegment()) { - Segment segment_a = seg_iter_a.nextSegment(); - segment_a.queryEnvelope2D(env_segment_a); - - if (env_b_deflated.containsExclusive(env_segment_a)) { - b_interior = true; - continue; - } - - env_inter.setCoords(env_b_deflated); - env_inter.intersect(env_segment_a); - - if (!env_inter.isEmpty() - && (env_inter.getHeight() > tolerance || env_inter - .getWidth() > tolerance)) - b_interior = true; - } - } - - return b_interior; - } - - // Returns true if polyline_a contains envelope_b. - private static boolean polylineContainsEnvelope_(Polyline polyline_a, - Envelope envelope_b, double tolerance, - ProgressTracker progress_tracker) { - Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(); - envelope_b.queryEnvelope2D(env_b); - polyline_a.queryEnvelope2D(env_a); - - if (!envelopeInfContainsEnvelope_(env_a, env_b, tolerance)) - return false; - - if (env_b.getHeight() > tolerance && env_b.getWidth() > tolerance) - return false; // when treated as an area, lines cannot contain - // areas. - - if (env_b.getHeight() <= tolerance && env_b.getWidth() <= tolerance) {// Treat - // as - // point - Point2D pt_b = envelope_b.getCenterXY(); - return linearPathContainsPoint_(polyline_a, pt_b, tolerance); - } - - // Treat as polyline - Polyline polyline_b = new Polyline(); - Point p = new Point(); - envelope_b.queryCornerByVal(0, p); - polyline_b.startPath(p); - envelope_b.queryCornerByVal(2, p); - polyline_b.lineTo(p); - return linearPathWithinLinearPath_(polyline_b, polyline_a, tolerance, false); - } - - // Returns true if polyline_a crosses envelope_b. - private static boolean polylineCrossesEnvelope_(Polyline polyline_a, - Envelope envelope_b, double tolerance, - ProgressTracker progress_tracker) { - Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(); - polyline_a.queryEnvelope2D(env_a); - envelope_b.queryEnvelope2D(env_b); - - if (envelopeInfContainsEnvelope_(env_b, env_a, tolerance)) - return false; - - if (env_b.getHeight() <= tolerance && env_b.getWidth() <= tolerance) - return false; // when treated as a point, lines cannot cross points. - - if (env_b.getHeight() <= tolerance || env_b.getWidth() <= tolerance) {// Treat - // as - // polyline - Polyline polyline_b = new Polyline(); - Point p = new Point(); - envelope_b.queryCornerByVal(0, p); - polyline_b.startPath(p); - envelope_b.queryCornerByVal(2, p); - polyline_b.lineTo(p); - return polylineCrossesPolyline_(polyline_a, polyline_b, tolerance, - progress_tracker); - } - - // Treat env_b as area - - SegmentIterator seg_iter_a = polyline_a.querySegmentIterator(); - Envelope2D env_b_inflated = new Envelope2D(), env_b_deflated = new Envelope2D(); - env_b_deflated.setCoords(env_b); - env_b_inflated.setCoords(env_b); - env_b_deflated.inflate(-tolerance, -tolerance); - env_b_inflated.inflate(tolerance, tolerance); - - boolean b_interior = false, b_exterior = false; - Envelope2D env_segment_a = new Envelope2D(); - Envelope2D env_inter = new Envelope2D(); - - while (seg_iter_a.nextPath()) { - while (seg_iter_a.hasNextSegment()) { - Segment segment_a = seg_iter_a.nextSegment(); - segment_a.queryEnvelope2D(env_segment_a); - - if (!b_exterior) { - if (!env_b_inflated.contains(env_segment_a)) - b_exterior = true; - } - - if (!b_interior) { - env_inter.setCoords(env_b_deflated); - env_inter.intersect(env_segment_a); - - if (!env_inter.isEmpty() - && (env_inter.getHeight() > tolerance || env_inter - .getWidth() > tolerance)) - b_interior = true; - } - - if (b_interior && b_exterior) - return true; - } - } - - return false; - } - - // Returns true if multipoint_a equals multipoint_b. - private static boolean multiPointEqualsMultiPoint_(MultiPoint multipoint_a, - MultiPoint multipoint_b, double tolerance, - ProgressTracker progress_tracker) { - Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(); - multipoint_a.queryEnvelope2D(env_a); - multipoint_b.queryEnvelope2D(env_b); - - if (!envelopeEqualsEnvelope_(env_a, env_b, tolerance, progress_tracker)) - return false; - - if (multiPointExactlyEqualsMultiPoint_(multipoint_a, multipoint_b, - tolerance, progress_tracker)) - return true; - - return multiPointCoverageMultiPoint_(multipoint_a, multipoint_b, - tolerance, false, true, false, progress_tracker); - } - - // Returns true if multipoint_a is disjoint from multipoint_b. - private static boolean multiPointDisjointMultiPoint_( - MultiPoint multipoint_a, MultiPoint multipoint_b, double tolerance, - ProgressTracker progress_tracker) { - return !multiPointIntersectsMultiPoint_(multipoint_a, multipoint_b, - tolerance, progress_tracker); - } - - // Returns true if multipoint_a overlaps multipoint_b. - private static boolean multiPointOverlapsMultiPoint_( - MultiPoint multipoint_a, MultiPoint multipoint_b, double tolerance, - ProgressTracker progress_tracker) { - return multiPointCoverageMultiPoint_(multipoint_a, multipoint_b, - tolerance, false, false, true, progress_tracker); - } - - // Returns true if multipoint_a contains multipoint_b. - private static boolean multiPointContainsMultiPoint_( - MultiPoint multipoint_a, MultiPoint multipoint_b, double tolerance, - ProgressTracker progress_tracker) { - Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(); - multipoint_a.queryEnvelope2D(env_a); - multipoint_b.queryEnvelope2D(env_b); - - if (!envelopeInfContainsEnvelope_(env_a, env_b, tolerance)) - return false; - - return multiPointCoverageMultiPoint_(multipoint_b, multipoint_a, - tolerance, true, false, false, progress_tracker); - } - - private static boolean multiPointContainsMultiPointBrute_( - MultiPoint multipoint_a, MultiPoint multipoint_b, double tolerance) { - double tolerance_sq = tolerance * tolerance; - Point2D pt_a = new Point2D(); - Point2D pt_b = new Point2D(); - - for (int i = 0; i < multipoint_b.getPointCount(); i++) { - multipoint_b.getXY(i, pt_b); - boolean b_contained = false; - - for (int j = 0; j < multipoint_a.getPointCount(); j++) { - multipoint_a.getXY(j, pt_a); - - if (Point2D.sqrDistance(pt_a, pt_b) <= tolerance_sq) { - b_contained = true; - break; - } - } - - if (!b_contained) - return false; - } - - return true; - } - - // Returns true if multipoint_a equals point_b. - static boolean multiPointEqualsPoint_(MultiPoint multipoint_a, - Point point_b, double tolerance, ProgressTracker progress_tracker) { - Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(); - multipoint_a.queryEnvelope2D(env_a); - point_b.queryEnvelope2D(env_b); - return envelopeEqualsEnvelope_(env_a, env_b, tolerance, - progress_tracker); - } - - // Returns true if multipoint_a is disjoint from point_b. - private static boolean multiPointDisjointPoint_(MultiPoint multipoint_a, - Point point_b, double tolerance, ProgressTracker progress_tracker) { - Point2D pt_b = point_b.getXY(); - return multiPointDisjointPointImpl_(multipoint_a, pt_b, tolerance, - progress_tracker); - } - - // Returns true if multipoint_a is within point_b. - private static boolean multiPointWithinPoint_(MultiPoint multipoint_a, - Point point_b, double tolerance, ProgressTracker progress_tracker) { - return multiPointEqualsPoint_(multipoint_a, point_b, tolerance, - progress_tracker); - } - - // Returns true if multipoint_a contains point_b. - private static boolean multiPointContainsPoint_(MultiPoint multipoint_a, - Point point_b, double tolerance, ProgressTracker progress_tracker) { - return !multiPointDisjointPoint_(multipoint_a, point_b, tolerance, - progress_tracker); - } - - // Returns true if multipoint_a equals envelope_b. - private static boolean multiPointEqualsEnvelope_(MultiPoint multipoint_a, - Envelope envelope_b, double tolerance, - ProgressTracker progress_tracker) { - Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(); - multipoint_a.queryEnvelope2D(env_a); - envelope_b.queryEnvelope2D(env_b); - - if (env_b.getHeight() > tolerance || env_b.getWidth() > tolerance) - return false; - - // only true if all the points of the multi_point degenerate to a point - // equal to the envelope - return envelopeEqualsEnvelope_(env_a, env_b, tolerance, - progress_tracker); - } - - // Returns true if multipoint_a is disjoint from envelope_b. - private static boolean multiPointDisjointEnvelope_(MultiPoint multipoint_a, - Envelope envelope_b, double tolerance, - ProgressTracker progress_tracker) { - Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(); - multipoint_a.queryEnvelope2D(env_a); - envelope_b.queryEnvelope2D(env_b); - - if (envelopeInfContainsEnvelope_(env_b, env_a, tolerance)) - return false; - - Envelope2D env_b_inflated = new Envelope2D(); - env_b_inflated.setCoords(env_b); - env_b_inflated.inflate(tolerance, tolerance); - Point2D pt_a = new Point2D(); - - for (int i = 0; i < multipoint_a.getPointCount(); i++) { - multipoint_a.getXY(i, pt_a); - - if (!env_b_inflated.contains(pt_a)) - continue; - - return false; - } - - return true; - } - - // Returns true if multipoint_a touches envelope_b. - private static boolean multiPointTouchesEnvelope_(MultiPoint multipoint_a, - Envelope envelope_b, double tolerance, - ProgressTracker progress_tracker) { - Envelope2D env_b = new Envelope2D(), env_b_inflated = new Envelope2D(), env_b_deflated = new Envelope2D(); - envelope_b.queryEnvelope2D(env_b); - - if (env_b.getHeight() <= tolerance && env_b.getWidth() <= tolerance) - return false; // there are no boundaries to intersect - - if (env_b.getHeight() <= tolerance || env_b.getWidth() <= tolerance) {// treat - // as - // line - - Point2D pt_a = new Point2D(); - boolean b_boundary = false; - - env_b_inflated.setCoords(env_b); - env_b_deflated.setCoords(env_b); - env_b_inflated.inflate(tolerance, tolerance); - if (env_b.getHeight() > tolerance) - env_b_deflated.inflate(0, -tolerance); - else - env_b_deflated.inflate(-tolerance, 0); - - for (int i = 0; i < multipoint_a.getPointCount(); i++) { - multipoint_a.getXY(i, pt_a); - - if (!env_b_inflated.contains(pt_a)) - continue; - - if (env_b.getHeight() > tolerance) { - if (pt_a.y > env_b_deflated.ymin - && pt_a.y < env_b_deflated.ymax) - return false; - - b_boundary = true; - } else { - if (pt_a.x > env_b_deflated.xmin - && pt_a.x < env_b_deflated.xmax) - return false; - - b_boundary = true; - } - } - - return b_boundary; - } - - // treat as area - env_b_inflated.setCoords(env_b); - env_b_deflated.setCoords(env_b); - env_b_inflated.inflate(tolerance, tolerance); - env_b_deflated.inflate(-tolerance, -tolerance); - - Point2D pt_a = new Point2D(); - boolean b_boundary = false; - - for (int i = 0; i < multipoint_a.getPointCount(); i++) { - multipoint_a.getXY(i, pt_a); - - if (!env_b_inflated.contains(pt_a)) - continue; - - if (env_b_deflated.containsExclusive(pt_a)) - return false; - - b_boundary = true; - } - - return b_boundary; - } - - // Returns true if multipoint_a is within envelope_b. - private static boolean multiPointWithinEnvelope_(MultiPoint multipoint_a, - Envelope envelope_b, double tolerance, - ProgressTracker progress_tracker) { - Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(); - multipoint_a.queryEnvelope2D(env_a); - envelope_b.queryEnvelope2D(env_b); - - if (!envelopeInfContainsEnvelope_(env_b, env_a, tolerance)) - return false; - - if (env_b.getHeight() <= tolerance && env_b.getWidth() <= tolerance) - return envelopeEqualsEnvelope_(env_a, env_b, tolerance, - progress_tracker); // treat as point - - if (env_b.getHeight() <= tolerance || env_b.getWidth() <= tolerance) {// treat - // as - // line - - boolean b_interior = false; - - Envelope2D env_b_deflated = new Envelope2D(), env_b_inflated = new Envelope2D(); - env_b_deflated.setCoords(env_b); - env_b_inflated.setCoords(env_b); - - if (env_b.getHeight() > tolerance) - env_b_deflated.inflate(0, -tolerance); - else - env_b_deflated.inflate(-tolerance, 0); - - env_b_inflated.inflate(tolerance, tolerance); - - Point2D pt_a = new Point2D(); - - for (int i = 0; i < multipoint_a.getPointCount(); i++) { - multipoint_a.getXY(i, pt_a); - - if (!env_b_inflated.contains(pt_a)) - return false; - - if (env_b.getHeight() > tolerance) { - if (pt_a.y > env_b_deflated.ymin - && pt_a.y < env_b_deflated.ymax) - b_interior = true; - } else { - if (pt_a.x > env_b_deflated.xmin - && pt_a.x < env_b_deflated.xmax) - b_interior = true; - } - } - - return b_interior; - } - - // treat as area - - boolean b_interior = false; - - Envelope2D env_b_deflated = new Envelope2D(), env_b_inflated = new Envelope2D(); - env_b_deflated.setCoords(env_b); - env_b_inflated.setCoords(env_b); - env_b_deflated.inflate(-tolerance, -tolerance); - env_b_inflated.inflate(tolerance, tolerance); - - Point2D pt_a = new Point2D(); - - // we loop to find a proper interior intersection (i.e. something inside - // instead of just on the boundary) - for (int i = 0; i < multipoint_a.getPointCount(); i++) { - multipoint_a.getXY(i, pt_a); - - if (!env_b_inflated.contains(pt_a)) - return false; - - if (env_b_deflated.containsExclusive(pt_a)) - b_interior = true; - } - - return b_interior; - } - - // Returns true if multipoint_a contains envelope_b. - private static boolean multiPointContainsEnvelope_(MultiPoint multipoint_a, - Envelope envelope_b, double tolerance, - ProgressTracker progress_tracker) { - Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(); - multipoint_a.queryEnvelope2D(env_a); - envelope_b.queryEnvelope2D(env_b); - - if (!envelopeInfContainsEnvelope_(env_a, env_b, tolerance)) - return false; - - if (env_b.getHeight() > tolerance || env_b.getWidth() > tolerance) - return false; - - Point2D pt_b = envelope_b.getCenterXY(); - return !multiPointDisjointPointImpl_(multipoint_a, pt_b, tolerance, - progress_tracker); - } - - // Returns true if multipoint_a crosses envelope_b. - static boolean multiPointCrossesEnvelope_(MultiPoint multipoint_a, - Envelope envelope_b, double tolerance, - ProgressTracker progress_tracker) { - Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(); - multipoint_a.queryEnvelope2D(env_a); - envelope_b.queryEnvelope2D(env_b); - - if (envelopeInfContainsEnvelope_(env_b, env_a, tolerance)) - return false; - - if (env_b.getHeight() <= tolerance && env_b.getWidth() <= tolerance) - return false; - - if (env_b.getHeight() <= tolerance || env_b.getWidth() <= tolerance) {// treat - // as - // line - Envelope2D env_b_deflated = new Envelope2D(); - Envelope2D env_b_inflated = new Envelope2D(); - env_b_deflated.setCoords(env_b); - - if (env_b.getHeight() > tolerance) - env_b_deflated.inflate(0, -tolerance); - else - env_b_deflated.inflate(-tolerance, 0); - - env_b_inflated.setCoords(env_b); - env_b_inflated.inflate(tolerance, tolerance); - - Point2D pt_a = new Point2D(); - boolean b_interior = false, b_exterior = false; - - for (int i = 0; i < multipoint_a.getPointCount(); i++) { - multipoint_a.getXY(i, pt_a); - - if (!b_interior) { - if (env_b.getHeight() > tolerance) { - if (pt_a.y > env_b_deflated.ymin - && pt_a.y < env_b_deflated.ymax) - b_interior = true; - } else { - if (pt_a.x > env_b_deflated.xmin - && pt_a.x < env_b_deflated.xmax) - b_interior = true; - } - } - - if (!b_exterior && !env_b_inflated.contains(pt_a)) - b_exterior = true; - - if (b_interior && b_exterior) - return true; - } - - return false; - } - - Envelope2D env_b_deflated = new Envelope2D(), env_b_inflated = new Envelope2D(); - env_b_deflated.setCoords(env_b); - env_b_deflated.inflate(-tolerance, -tolerance); - assert (!env_b_deflated.isEmpty()); - - env_b_inflated.setCoords(env_b); - env_b_inflated.inflate(tolerance, tolerance); - - Point2D pt_a = new Point2D(); - boolean b_interior = false, b_exterior = false; - - for (int i = 0; i < multipoint_a.getPointCount(); i++) { - multipoint_a.getXY(i, pt_a); - - if (!b_interior && env_b_deflated.containsExclusive(pt_a)) - b_interior = true; - - if (!b_exterior && !env_b_inflated.contains(pt_a)) - b_exterior = true; - - if (b_interior && b_exterior) - return true; - } - - return false; - } - - // Returns true if pt_a equals pt_b. - private static boolean pointEqualsPoint_(Point2D pt_a, Point2D pt_b, - double tolerance, ProgressTracker progress_tracker) { - if (Point2D.sqrDistance(pt_a, pt_b) <= tolerance * tolerance) - return true; - - return false; - } - - // Returns true if pt_a is disjoint from pt_b. - private static boolean pointDisjointPoint_(Point2D pt_a, Point2D pt_b, - double tolerance, ProgressTracker progress_tracker) { - if (Point2D.sqrDistance(pt_a, pt_b) > tolerance * tolerance) - return true; - - return false; - } - - // Returns true if pt_a contains pt_b. - private static boolean pointContainsPoint_(Point2D pt_a, Point2D pt_b, - double tolerance, ProgressTracker progress_tracker) { - return pointEqualsPoint_(pt_a, pt_b, tolerance, progress_tracker); - } - - // Returns true if pt_a equals enve_b. - private static boolean pointEqualsEnvelope_(Point2D pt_a, Envelope2D env_b, - double tolerance, ProgressTracker progress_tracker) { - Envelope2D env_a = new Envelope2D(); - env_a.setCoords(pt_a); - return envelopeEqualsEnvelope_(env_a, env_b, tolerance, - progress_tracker); - } - - // Returns true if pt_a is disjoint from env_b. - static boolean pointDisjointEnvelope_(Point2D pt_a, Envelope2D env_b, - double tolerance, ProgressTracker progress_tracker) { - Envelope2D env_b_inflated = new Envelope2D(); - env_b_inflated.setCoords(env_b); - env_b_inflated.inflate(tolerance, tolerance); - return !env_b_inflated.contains(pt_a); - } - - // Returns true if pt_a touches env_b. - private static boolean pointTouchesEnvelope_(Point2D pt_a, - Envelope2D env_b, double tolerance, ProgressTracker progress_tracker) { - if (env_b.getHeight() <= tolerance && env_b.getWidth() <= tolerance) - return false; // when treates as a point, points cannot touch points - - Envelope2D env_b_inflated = new Envelope2D(), env_b_deflated = new Envelope2D(); - - env_b_inflated.setCoords(env_b); - env_b_inflated.inflate(tolerance, tolerance); - - if (!env_b_inflated.contains(pt_a)) - return false; - - if (env_b.getHeight() <= tolerance || env_b.getWidth() <= tolerance) { - env_b_deflated.setCoords(env_b); - - if (env_b.getHeight() > tolerance) - env_b_deflated.inflate(0, -tolerance); - else - env_b_deflated.inflate(-tolerance, 0); - - if (env_b.getHeight() > tolerance) { - if (pt_a.y > env_b_deflated.ymin - && pt_a.y < env_b_deflated.ymax) - return false; - } else { - if (pt_a.x > env_b_deflated.xmin - && pt_a.x < env_b_deflated.xmax) - return false; - } - - return true; - } - - env_b_deflated.setCoords(env_b); - env_b_deflated.inflate(-tolerance, -tolerance); - - if (env_b_deflated.containsExclusive(pt_a)) - return false; - - return true; - } - - // Returns true if pt_a is within env_b. - private static boolean pointWithinEnvelope_(Point2D pt_a, Envelope2D env_b, - double tolerance, ProgressTracker progress_tracker) { - if (env_b.getHeight() <= tolerance && env_b.getWidth() <= tolerance) { - // assert(env_b_inflated.contains(pt_a)); // should contain if we - // got to here (i.e. not disjoint) - return true; - } - - if (env_b.getHeight() <= tolerance || env_b.getWidth() <= tolerance) {// treat - // as - // line - Envelope2D env_b_deflated = new Envelope2D(); - env_b_deflated.setCoords(env_b); - - if (env_b.getHeight() > tolerance) - env_b_deflated.inflate(0, -tolerance); - else - env_b_deflated.inflate(-tolerance, 0); - - boolean b_interior = false; - - if (env_b.getHeight() > tolerance) { - if (pt_a.y > env_b_deflated.ymin - && pt_a.y < env_b_deflated.ymax) - b_interior = true; - } else { - if (pt_a.x > env_b_deflated.xmin - && pt_a.x < env_b_deflated.xmax) - b_interior = true; - } - - return b_interior; - } - - // treat as area - - Envelope2D env_b_deflated = new Envelope2D(); - env_b_deflated.setCoords(env_b); - env_b_deflated.inflate(-tolerance, -tolerance); - return env_b_deflated.containsExclusive(pt_a); - } - - // Returns true if pt_a contains env_b. - private static boolean pointContainsEnvelope_(Point2D pt_a, - Envelope2D env_b, double tolerance, ProgressTracker progress_tracker) { - return pointEqualsEnvelope_(pt_a, env_b, tolerance, progress_tracker); - } - - // Returns true if env_a equals env_b. - private static boolean envelopeEqualsEnvelope_(Envelope2D env_a, - Envelope2D env_b, double tolerance, ProgressTracker progress_tracker) { - return envelopeInfContainsEnvelope_(env_a, env_b, tolerance) - && envelopeInfContainsEnvelope_(env_b, env_a, tolerance); - } - - // Returns true if env_a is disjoint from env_b. - static boolean envelopeDisjointEnvelope_(Envelope2D env_a, - Envelope2D env_b, double tolerance, ProgressTracker progress_tracker) { - Envelope2D env_b_inflated = new Envelope2D(); - env_b_inflated.setCoords(env_b); - env_b_inflated.inflate(tolerance, tolerance); - return !env_a.isIntersecting(env_b_inflated); - } - - // Returns true if env_a touches env_b. - private static boolean envelopeTouchesEnvelope_(Envelope2D env_a, - Envelope2D env_b, double tolerance, ProgressTracker progress_tracker) { - if (env_a.getHeight() <= tolerance && env_a.getWidth() <= tolerance) {// treat - // env_a - // as - // point - Point2D pt_a = env_a.getCenter(); - return pointTouchesEnvelope_(pt_a, env_b, tolerance, - progress_tracker); - } - - if (env_b.getHeight() <= tolerance && env_b.getWidth() <= tolerance) {// treat - // env_b - // as - // point - Point2D pt_b = env_b.getCenter(); - return pointTouchesEnvelope_(pt_b, env_a, tolerance, - progress_tracker); - } - - Envelope2D _env_a; - Envelope2D _env_b; - - if (env_a.getHeight() > tolerance - && env_a.getWidth() > tolerance - && (env_b.getHeight() <= tolerance || env_b.getWidth() <= tolerance)) { - // swap a and b - _env_a = env_b; - _env_b = env_a; - } else { - _env_a = env_a; - _env_b = env_b; - } - - if (_env_a.getHeight() <= tolerance || _env_a.getWidth() <= tolerance) {// treat - // env_a - // as - // line - - if (_env_b.getHeight() <= tolerance - || _env_b.getWidth() <= tolerance) {// treat env_b as line - - Line line_a = new Line(), line_b = new Line(); - double[] scalars_a = new double[2]; - double[] scalars_b = new double[2]; - Point2D pt = new Point2D(); - _env_a.queryLowerLeft(pt); - line_a.setStartXY(pt); - _env_a.queryUpperRight(pt); - line_a.setEndXY(pt); - _env_b.queryLowerLeft(pt); - line_b.setStartXY(pt); - _env_b.queryUpperRight(pt); - line_b.setEndXY(pt); - - line_a.intersect(line_b, null, scalars_a, scalars_b, tolerance); - int count = line_a.intersect(line_b, null, null, null, - tolerance); - - if (count != 1) - return false; - - return scalars_a[0] == 0.0 || scalars_a[1] == 1.0 - || scalars_b[0] == 0.0 || scalars_b[1] == 1.0; - } - - // treat env_b as area - - Envelope2D env_b_deflated = new Envelope2D(), env_inter = new Envelope2D(); - env_b_deflated.setCoords(_env_b); - env_b_deflated.inflate(-tolerance, -tolerance); - env_inter.setCoords(env_b_deflated); - env_inter.intersect(_env_a); - - if (!env_inter.isEmpty() - && (env_inter.getHeight() > tolerance || env_inter - .getWidth() > tolerance)) - return false; - - assert (!envelopeDisjointEnvelope_(_env_a, _env_b, tolerance, - progress_tracker)); - return true; // we already know they intersect within a tolerance - } - - Envelope2D env_inter = new Envelope2D(); - env_inter.setCoords(_env_a); - env_inter.intersect(_env_b); - - if (!env_inter.isEmpty() && env_inter.getHeight() > tolerance - && env_inter.getWidth() > tolerance) - return false; - - return true; // we already know they intersect within a tolerance - } - - // Returns true if env_a overlaps env_b. - private static boolean envelopeOverlapsEnvelope_(Envelope2D env_a, - Envelope2D env_b, double tolerance, ProgressTracker progress_tracker) { - if (envelopeInfContainsEnvelope_(env_a, env_b, tolerance) - || envelopeInfContainsEnvelope_(env_b, env_a, tolerance)) - return false; - - if (env_a.getHeight() <= tolerance && env_a.getWidth() <= tolerance) - return false; // points cannot overlap - - if (env_b.getHeight() <= tolerance && env_b.getWidth() <= tolerance) - return false; // points cannot overlap - - if (env_a.getHeight() <= tolerance || env_a.getWidth() <= tolerance) {// treat - // env_a - // as - // a - // line - - if (env_b.getHeight() > tolerance && env_b.getWidth() > tolerance) - return false; // lines cannot overlap areas - - // treat both as lines - - Line line_a = new Line(), line_b = new Line(); - double[] scalars_a = new double[2]; - double[] scalars_b = new double[2]; - Point2D pt = new Point2D(); - env_a.queryLowerLeft(pt); - line_a.setStartXY(pt); - env_a.queryUpperRight(pt); - line_a.setEndXY(pt); - env_b.queryLowerLeft(pt); - line_b.setStartXY(pt); - env_b.queryUpperRight(pt); - line_b.setEndXY(pt); - - line_a.intersect(line_b, null, scalars_a, scalars_b, tolerance); - int count = line_a.intersect(line_b, null, null, null, tolerance); - - if (count != 2) - return false; - - return (scalars_a[0] > 0.0 || scalars_a[1] < 1.0) - && (scalars_b[0] > 0.0 || scalars_b[1] < 1.0); - } - - if (env_b.getHeight() <= tolerance || env_b.getWidth() <= tolerance) - return false; // lines cannot overlap areas - - // treat both as areas - - Envelope2D env_inter = new Envelope2D(); - env_inter.setCoords(env_a); - env_inter.intersect(env_b); - - if (env_inter.isEmpty()) - return false; - - if (env_inter.getHeight() <= tolerance - || env_inter.getWidth() <= tolerance) - return false; // not an area - - assert (!envelopeInfContainsEnvelope_(env_inter, env_a, tolerance) && !envelopeInfContainsEnvelope_( - env_inter, env_b, tolerance)); - - return true; - } - - // Returns true if env_a contains env_b. - private static boolean envelopeContainsEnvelope_(Envelope2D env_a, - Envelope2D env_b, double tolerance, ProgressTracker progress_tracker) { - if (!envelopeInfContainsEnvelope_(env_a, env_b, tolerance)) - return false; - - if (env_a.getHeight() <= tolerance && env_a.getWidth() <= tolerance) { - Point2D pt_a = env_a.getCenter(); - return pointWithinEnvelope_(pt_a, env_b, tolerance, - progress_tracker); - } - - if (env_b.getHeight() <= tolerance && env_b.getWidth() <= tolerance) { - Point2D pt_b = env_b.getCenter(); - return pointWithinEnvelope_(pt_b, env_a, tolerance, - progress_tracker); - } - - if (env_a.getHeight() <= tolerance || env_a.getWidth() <= tolerance) - return envelopeInfContainsEnvelope_(env_a, env_b, tolerance); // treat - // env_b - // as - // line - - // treat env_a as area - - if (env_b.getHeight() <= tolerance || env_b.getWidth() <= tolerance) {// treat - // env_b - // as - // line - - Envelope2D env_a_deflated = new Envelope2D(); - env_a_deflated.setCoords(env_a); - env_a_deflated.inflate(-tolerance, -tolerance); - - if (env_a_deflated.containsExclusive(env_b)) - return true; - - Envelope2D env_inter = new Envelope2D(); - env_inter.setCoords(env_a_deflated); - env_inter.intersect(env_b); - - if (env_inter.isEmpty() - || (env_inter.getHeight() <= tolerance && env_inter - .getWidth() <= tolerance)) - return false; - - return true; - } - - return envelopeInfContainsEnvelope_(env_a, env_b, tolerance); - } - - // Returns true if env_a crosses env_b. - private static boolean envelopeCrossesEnvelope_(Envelope2D env_a, - Envelope2D env_b, double tolerance, ProgressTracker progress_tracker) { - if (envelopeInfContainsEnvelope_(env_a, env_b, tolerance) - || envelopeInfContainsEnvelope_(env_b, env_a, tolerance)) - return false; - - if (env_a.getHeight() <= tolerance && env_a.getWidth() <= tolerance) - return false; // points cannot cross - - if (env_b.getHeight() <= tolerance && env_b.getWidth() <= tolerance) - return false; // points cannot cross - - if (env_b.getHeight() > tolerance && env_b.getWidth() > tolerance) { - if (env_a.getHeight() > tolerance && env_a.getWidth() > tolerance) - return false; // areas cannot cross - } - - Envelope2D _env_a; - Envelope2D _env_b; - - if (env_a.getHeight() > tolerance && env_a.getWidth() > tolerance) { - // swap b and a - _env_a = env_b; - _env_b = env_a; - } else { - _env_a = env_a; - _env_b = env_b; - } - - if (_env_b.getHeight() > tolerance && _env_b.getWidth() > tolerance) {// treat - // env_b - // as - // an - // area - // (env_a - // as - // a - // line); - - Envelope2D env_inter = new Envelope2D(), env_b_deflated = new Envelope2D(); - env_b_deflated.setCoords(_env_b); - env_b_deflated.inflate(-tolerance, -tolerance); - env_inter.setCoords(env_b_deflated); - env_inter.intersect(_env_a); - - if (env_inter.isEmpty()) - return false; - - if (env_inter.getHeight() <= tolerance - && env_inter.getWidth() <= tolerance) - return false; // not a line - - assert (!envelopeInfContainsEnvelope_(env_inter, _env_a, tolerance)); - return true; - } - - // treat both as lines - - Line line_a = new Line(), line_b = new Line(); - double[] scalars_a = new double[2]; - double[] scalars_b = new double[2]; - Point2D pt = new Point2D(); - _env_a.queryLowerLeft(pt); - line_a.setStartXY(pt); - _env_a.queryUpperRight(pt); - line_a.setEndXY(pt); - _env_b.queryLowerLeft(pt); - line_b.setStartXY(pt); - _env_b.queryUpperRight(pt); - line_b.setEndXY(pt); - - line_a.intersect(line_b, null, scalars_a, scalars_b, tolerance); - int count = line_a.intersect(line_b, null, null, null, tolerance); - - if (count != 1) - return false; - - return scalars_a[0] > 0.0 && scalars_a[1] < 1.0 && scalars_b[0] > 0.0 - && scalars_b[1] < 1.0; - } - - // Returns true if polygon_a is disjoint from multipath_b. - private static boolean polygonDisjointMultiPath_(Polygon polygon_a, - MultiPath multipath_b, double tolerance, - ProgressTracker progress_tracker) { - Point2D pt_a, pt_b; - Envelope2D env_a_inf = new Envelope2D(), env_b_inf = new Envelope2D(); - - MultiPathImpl multi_path_impl_a = (MultiPathImpl) polygon_a._getImpl(); - MultiPathImpl multi_path_impl_b = (MultiPathImpl) multipath_b._getImpl(); - - PairwiseIntersectorImpl intersector = new PairwiseIntersectorImpl(multi_path_impl_a, multi_path_impl_b, tolerance, true); - - if (!intersector.next()) - return true; // no rings intersect - - boolean b_intersects = linearPathIntersectsLinearPath_(polygon_a, multipath_b, tolerance); - - if (b_intersects) - return false; - - Polygon pa = null; - Polygon p_polygon_a = polygon_a; - - Polygon pb = null; - Polygon p_polygon_b = null; - - if (multipath_b.getType().value() == Geometry.GeometryType.Polygon) - p_polygon_b = (Polygon) multipath_b; - - boolean b_checked_polygon_a_quad_tree = false; - boolean b_checked_polygon_b_quad_tree = false; - - do { - int path_a = intersector.getRedElement(); - int path_b = intersector.getBlueElement(); - - pt_b = multipath_b.getXY(multipath_b.getPathStart(path_b)); - env_a_inf.setCoords(intersector.getRedEnvelope()); - env_a_inf.inflate(tolerance, tolerance); - - if (env_a_inf.contains(pt_b)) { - PolygonUtils.PiPResult result = PolygonUtils.isPointInPolygon2D(p_polygon_a, pt_b, 0.0); - - if (result != PolygonUtils.PiPResult.PiPOutside) - return false; - } - - if (multipath_b.getType().value() == Geometry.GeometryType.Polygon) { - pt_a = polygon_a.getXY(polygon_a.getPathStart(path_a)); - env_b_inf.setCoords(intersector.getBlueEnvelope()); - env_b_inf.inflate(tolerance, tolerance); - - if (env_b_inf.contains(pt_a)) { - PolygonUtils.PiPResult result = PolygonUtils.isPointInPolygon2D(p_polygon_b, pt_a, 0.0); - - if (result != PolygonUtils.PiPResult.PiPOutside) - return false; - } - } - - if (!b_checked_polygon_a_quad_tree) { - if (PointInPolygonHelper.quadTreeWillHelp(polygon_a, multipath_b.getPathCount() - 1) && (multi_path_impl_a._getAccelerators() == null || multi_path_impl_a._getAccelerators().getQuadTree() == null)) { - pa = new Polygon(); - polygon_a.copyTo(pa); - ((MultiPathImpl) pa._getImpl())._buildQuadTreeAccelerator(Geometry.GeometryAccelerationDegree.enumMedium); - p_polygon_a = pa; - } else { - p_polygon_a = polygon_a; - } - - b_checked_polygon_a_quad_tree = true; - } - - if (multipath_b.getType().value() == Geometry.GeometryType.Polygon) { - if (!b_checked_polygon_b_quad_tree) { - Polygon polygon_b = (Polygon) multipath_b; - if (PointInPolygonHelper.quadTreeWillHelp(polygon_b, polygon_a.getPathCount() - 1) && (multi_path_impl_b._getAccelerators() == null || multi_path_impl_b._getAccelerators().getQuadTree() == null)) { - pb = new Polygon(); - polygon_b.copyTo(pb); - ((MultiPathImpl) pb._getImpl())._buildQuadTreeAccelerator(Geometry.GeometryAccelerationDegree.enumMedium); - p_polygon_b = pb; - } else { - p_polygon_b = (Polygon) multipath_b; - } - - b_checked_polygon_b_quad_tree = true; - } - } - - } while (intersector.next()); - - return true; - } - - // Returns true if env_a inflated contains env_b. - private static boolean envelopeInfContainsEnvelope_(Envelope2D env_a, - Envelope2D env_b, double tolerance) { - Envelope2D env_a_inflated = new Envelope2D(); - env_a_inflated.setCoords(env_a); - env_a_inflated.inflate(tolerance, tolerance); - return env_a_inflated.contains(env_b); - } - - // Returns true if a coordinate of envelope A is outside of envelope B. - private static boolean interiorEnvExteriorEnv_(Envelope2D env_a, - Envelope2D env_b, double tolerance) { - Envelope2D envBInflated = new Envelope2D(); - envBInflated.setCoords(env_b); - envBInflated.inflate(tolerance, tolerance); - Point2D pt = new Point2D(); - - env_a.queryLowerLeft(pt); - if (!envBInflated.contains(pt)) - return true; - - env_a.queryLowerRight(pt); - if (!envBInflated.contains(pt)) - return true; - - env_a.queryUpperLeft(pt); - if (!envBInflated.contains(pt)) - return true; - - env_a.queryUpperRight(pt); - if (!envBInflated.contains(pt)) - return true; - - assert (envBInflated.contains(env_a)); - return false; - } - - // Returns true if the points in each path of multipathA are the same as - // those in multipathB, within a tolerance, and in the same order. - private static boolean multiPathExactlyEqualsMultiPath_( - MultiPath multipathA, MultiPath multipathB, double tolerance, - ProgressTracker progress_tracker) { - if (multipathA.getPathCount() != multipathB.getPathCount() - || multipathA.getPointCount() != multipathB.getPointCount()) - return false; - - Point2D ptA = new Point2D(), ptB = new Point2D(); - boolean bAllPointsEqual = true; - double tolerance_sq = tolerance * tolerance; - - for (int ipath = 0; ipath < multipathA.getPathCount(); ipath++) { - if (multipathA.getPathEnd(ipath) != multipathB.getPathEnd(ipath)) { - bAllPointsEqual = false; - break; - } - - for (int i = multipathA.getPathStart(ipath); i < multipathB - .getPathEnd(ipath); i++) { - multipathA.getXY(i, ptA); - multipathB.getXY(i, ptB); - - if (Point2D.sqrDistance(ptA, ptB) > tolerance_sq) { - bAllPointsEqual = false; - break; - } - } - - if (!bAllPointsEqual) - break; - } - - if (!bAllPointsEqual) - return false; - - return true; - } - - // Returns true if the points of multipoint_a are the same as those in - // multipoint_b, within a tolerance, and in the same order. - private static boolean multiPointExactlyEqualsMultiPoint_( - MultiPoint multipoint_a, MultiPoint multipoint_b, double tolerance, - ProgressTracker progress_tracker) { - if (multipoint_a.getPointCount() != multipoint_b.getPointCount()) - return false; - - Point2D ptA = new Point2D(), ptB = new Point2D(); - boolean bAllPointsEqual = true; - double tolerance_sq = tolerance * tolerance; - - for (int i = 0; i < multipoint_a.getPointCount(); i++) { - multipoint_a.getXY(i, ptA); - multipoint_b.getXY(i, ptB); - - if (Point2D.sqrDistance(ptA, ptB) > tolerance_sq) { - bAllPointsEqual = false; - break; - } - } - - if (!bAllPointsEqual) - return false; - - return true; - } - - // By default this will perform the within operation if bEquals is false. - // Otherwise it will do equals. - private static boolean multiPointCoverageMultiPoint_( - MultiPoint _multipointA, MultiPoint _multipointB, double tolerance, - boolean bPerformWithin, boolean bPerformEquals, - boolean bPerformOverlaps, ProgressTracker progress_tracker) { - boolean bPerformContains = false; - MultiPoint multipoint_a; - MultiPoint multipoint_b; - - if (_multipointA.getPointCount() > _multipointB.getPointCount()) { - if (bPerformWithin) { - bPerformWithin = false; - bPerformContains = true; - } - - multipoint_a = _multipointB; - multipoint_b = _multipointA; - } else { - multipoint_a = _multipointA; - multipoint_b = _multipointB; - } - - AttributeStreamOfInt8 contained = null; - - if (bPerformEquals || bPerformOverlaps || bPerformContains) { - contained = new AttributeStreamOfInt8(multipoint_b.getPointCount()); - - for (int i = 0; i < multipoint_b.getPointCount(); i++) - contained.write(i, (byte) 0); - } - - Envelope2D env_a = new Envelope2D(); - Envelope2D env_b = new Envelope2D(); - Envelope2D envInter = new Envelope2D(); - multipoint_a.queryEnvelope2D(env_a); - multipoint_b.queryEnvelope2D(env_b); - env_a.inflate(tolerance, tolerance); - env_b.inflate(tolerance, tolerance); - envInter.setCoords(env_a); - envInter.intersect(env_b); - - Point2D ptA = new Point2D(); - Point2D ptB = new Point2D(); - - boolean bWithin = true; // starts off true by default - - QuadTreeImpl quadTreeB = InternalUtils.buildQuadTree( - (MultiPointImpl) (multipoint_b._getImpl()), envInter); - QuadTreeImpl.QuadTreeIteratorImpl qtIterB = quadTreeB.getIterator(); - double tolerance_sq = tolerance * tolerance; - - for (int vertex_a = 0; vertex_a < multipoint_a.getPointCount(); vertex_a++) { - multipoint_a.getXY(vertex_a, ptA); - - if (!envInter.contains(ptA)) { - if (bPerformEquals || bPerformWithin) - return false; - else { - bWithin = false; - continue; - } - } - - boolean bPtACovered = false; - env_a.setCoords(ptA.x, ptA.y, ptA.x, ptA.y); - qtIterB.resetIterator(env_a, tolerance); - for (int elementHandleB = qtIterB.next(); elementHandleB != -1; elementHandleB = qtIterB - .next()) { - int vertex_b = quadTreeB.getElement(elementHandleB); - multipoint_b.getXY(vertex_b, ptB); - - if (Point2D.sqrDistance(ptA, ptB) <= tolerance_sq) { - if (bPerformEquals || bPerformOverlaps || bPerformContains) - contained.write(vertex_b, (byte) 1); - - bPtACovered = true; - - if (bPerformWithin) - break; - } - } - - if (!bPtACovered) { - bWithin = false; - - if (bPerformEquals || bPerformWithin) - return false; - } - } - - if (bPerformOverlaps && bWithin) - return false; - - if (bPerformWithin) - return true; - - for (int i = 0; i < multipoint_b.getPointCount(); i++) { - if (contained.read(i) == 1) { - if (bPerformOverlaps) - return true; - } else { - if (bPerformEquals || bPerformContains) - return false; - } - } - - if (bPerformOverlaps) - return false; - - return true; - } - - // Returns true if multipoint_a intersects multipoint_b. - private static boolean multiPointIntersectsMultiPoint_( - MultiPoint _multipointA, MultiPoint _multipointB, double tolerance, - ProgressTracker progress_tracker) { - MultiPoint multipoint_a; - MultiPoint multipoint_b; - - if (_multipointA.getPointCount() > _multipointB.getPointCount()) { - multipoint_a = _multipointB; - multipoint_b = _multipointA; - } else { - multipoint_a = _multipointA; - multipoint_b = _multipointB; - } - - Envelope2D env_a = new Envelope2D(); - Envelope2D env_b = new Envelope2D(); - Envelope2D envInter = new Envelope2D(); - multipoint_a.queryEnvelope2D(env_a); - multipoint_b.queryEnvelope2D(env_b); - env_a.inflate(tolerance, tolerance); - env_b.inflate(tolerance, tolerance); - envInter.setCoords(env_a); - envInter.intersect(env_b); - - Point2D ptA = new Point2D(); - Point2D ptB = new Point2D(); - double tolerance_sq = tolerance * tolerance; - - QuadTreeImpl quadTreeB = InternalUtils.buildQuadTree( - (MultiPointImpl) (multipoint_b._getImpl()), envInter); - QuadTreeImpl.QuadTreeIteratorImpl qtIterB = quadTreeB.getIterator(); - - for (int vertex_a = 0; vertex_a < multipoint_a.getPointCount(); vertex_a++) { - multipoint_a.getXY(vertex_a, ptA); - - if (!envInter.contains(ptA)) - continue; - - env_a.setCoords(ptA.x, ptA.y, ptA.x, ptA.y); - qtIterB.resetIterator(env_a, tolerance); - - for (int elementHandleB = qtIterB.next(); elementHandleB != -1; elementHandleB = qtIterB - .next()) { - int vertex_b = quadTreeB.getElement(elementHandleB); - multipoint_b.getXY(vertex_b, ptB); - - if (Point2D.sqrDistance(ptA, ptB) <= tolerance_sq) - return true; - } - } - - return false; - } - - // Returns true if multipathA equals multipathB. - private static boolean linearPathEqualsLinearPath_(MultiPath multipathA, - MultiPath multipathB, double tolerance, boolean bEnforceOrientation) { - return linearPathWithinLinearPath_(multipathA, multipathB, tolerance, bEnforceOrientation) - && linearPathWithinLinearPath_(multipathB, multipathA, - tolerance, bEnforceOrientation); - } - - // Returns true if the segments of multipathA are within the segments of - // multipathB. - private static boolean linearPathWithinLinearPath_(MultiPath multipathA, - MultiPath multipathB, double tolerance, boolean bEnforceOrientation) { - boolean bWithin = true; - double[] scalarsA = new double[2]; - double[] scalarsB = new double[2]; - - int ievent = 0; - AttributeStreamOfInt32 eventIndices = new AttributeStreamOfInt32(0); - RelationalOperations relOps = new RelationalOperations(); - OverlapComparer overlapComparer = new OverlapComparer(relOps); - OverlapEvent overlapEvent; - - Envelope2D env_a = new Envelope2D(); - Envelope2D env_b = new Envelope2D(); - Envelope2D envInter = new Envelope2D(); - multipathA.queryEnvelope2D(env_a); - multipathB.queryEnvelope2D(env_b); - env_a.inflate(tolerance, tolerance); - env_b.inflate(tolerance, tolerance); - envInter.setCoords(env_a); - envInter.intersect(env_b); - - SegmentIteratorImpl segIterA = ((MultiPathImpl) multipathA._getImpl()) - .querySegmentIterator(); - SegmentIteratorImpl segIterB = ((MultiPathImpl) multipathB._getImpl()) - .querySegmentIterator(); - - QuadTreeImpl qtB = null; - QuadTreeImpl quadTreeB = null; - QuadTreeImpl quadTreePathsB = null; - - GeometryAccelerators accel = ((MultiPathImpl) multipathB._getImpl()) - ._getAccelerators(); - - if (accel != null) { - quadTreeB = accel.getQuadTree(); - quadTreePathsB = accel.getQuadTreeForPaths(); - if (quadTreeB == null) { - qtB = InternalUtils.buildQuadTree( - (MultiPathImpl) multipathB._getImpl(), envInter); - quadTreeB = qtB; - } - } else { - qtB = InternalUtils.buildQuadTree( - (MultiPathImpl) multipathB._getImpl(), envInter); - quadTreeB = qtB; - } - - QuadTreeImpl.QuadTreeIteratorImpl qtIterB = quadTreeB.getIterator(); - - QuadTreeImpl.QuadTreeIteratorImpl qtIterPathsB = null; - if (quadTreePathsB != null) - qtIterPathsB = quadTreePathsB.getIterator(); + interface Relation { + static final int contains = 1; + static final int within = 2; + static final int equals = 3; + static final int disjoint = 4; + static final int touches = 8; + static final int crosses = 16; + static final int overlaps = 32; + + static final int unknown = 0; + static final int intersects = 0x40000000; + } + + static boolean relate(Geometry geometry_a, Geometry geometry_b, + SpatialReference sr, int relation, ProgressTracker progress_tracker) { + int type_a = geometry_a.getType().value(); + int type_b = geometry_b.getType().value(); + + // Give preference to the Point vs Envelope, Envelope vs Envelope and + // Point vs Point realtions: + if (type_a == Geometry.GeometryType.Envelope) { + if (type_b == Geometry.GeometryType.Envelope) { + return relate((Envelope) geometry_a, (Envelope) geometry_b, sr, + relation, progress_tracker); + } else if (type_b == Geometry.GeometryType.Point) { + if (relation == Relation.within) + relation = Relation.contains; + else if (relation == Relation.contains) + relation = Relation.within; + + return relate((Point) geometry_b, (Envelope) geometry_a, sr, + relation, progress_tracker); + } else { + // proceed below + } + } else if (type_a == Geometry.GeometryType.Point) { + if (type_b == Geometry.GeometryType.Envelope) { + return relate((Point) geometry_a, (Envelope) geometry_b, sr, + relation, progress_tracker); + } else if (type_b == Geometry.GeometryType.Point) { + return relate((Point) geometry_a, (Point) geometry_b, sr, + relation, progress_tracker); + } else { + // proceed below + } + } else { + // proceed below + } + + if (geometry_a.isEmpty() || geometry_b.isEmpty()) { + if (relation == Relation.disjoint) + return true; // Always true + + return false; // Always false + } + + Envelope2D env1 = new Envelope2D(); + geometry_a.queryEnvelope2D(env1); + Envelope2D env2 = new Envelope2D(); + geometry_b.queryEnvelope2D(env2); + + Envelope2D envMerged = new Envelope2D(); + envMerged.setCoords(env1); + envMerged.merge(env2); + double tolerance = InternalUtils.calculateToleranceFromGeometry(sr, + envMerged, false); + + if (envelopeDisjointEnvelope_(env1, env2, tolerance, progress_tracker)) { + if (relation == Relation.disjoint) + return true; + + return false; + } + + boolean bRelation = false; + + Geometry _geometry_a; + Geometry _geometry_b; + Polyline polyline_a, polyline_b; + + if (MultiPath.isSegment(type_a)) { + polyline_a = new Polyline(geometry_a.getDescription()); + polyline_a.addSegment((Segment) geometry_a, true); + _geometry_a = polyline_a; + type_a = Geometry.GeometryType.Polyline; + } else { + _geometry_a = geometry_a; + } + + if (MultiPath.isSegment(type_b)) { + polyline_b = new Polyline(geometry_b.getDescription()); + polyline_b.addSegment((Segment) geometry_b, true); + _geometry_b = polyline_b; + type_b = Geometry.GeometryType.Polyline; + } else { + _geometry_b = geometry_b; + } + + if (type_a != Geometry.GeometryType.Envelope + && type_b != Geometry.GeometryType.Envelope) { + if (_geometry_a.getDimension() < _geometry_b.getDimension() + || (type_a == Geometry.GeometryType.Point && type_b == Geometry.GeometryType.MultiPoint)) {// we + // will + // switch + // the + // order + // of + // the + // geometries + // below. + if (relation == Relation.within) + relation = Relation.contains; + else if (relation == Relation.contains) + relation = Relation.within; + } + } else { + if (type_a != Geometry.GeometryType.Polygon + && type_b != Geometry.GeometryType.Envelope) { // we will + // switch + // the order + // of the + // geometries + // below. + if (relation == Relation.within) + relation = Relation.contains; + else if (relation == Relation.contains) + relation = Relation.within; + } + } + + switch (type_a) { + case Geometry.GeometryType.Polygon: + switch (type_b) { + case Geometry.GeometryType.Polygon: + bRelation = polygonRelatePolygon_((Polygon) (_geometry_a), + (Polygon) (_geometry_b), tolerance, relation, + progress_tracker); + break; + + case Geometry.GeometryType.Polyline: + bRelation = polygonRelatePolyline_((Polygon) (_geometry_a), + (Polyline) (_geometry_b), tolerance, relation, + progress_tracker); + break; + + case Geometry.GeometryType.Point: + bRelation = polygonRelatePoint_((Polygon) (_geometry_a), + (Point) (_geometry_b), tolerance, relation, + progress_tracker); + break; + + case Geometry.GeometryType.MultiPoint: + bRelation = polygonRelateMultiPoint_((Polygon) (_geometry_a), + (MultiPoint) (_geometry_b), tolerance, relation, + progress_tracker); + break; + + case Geometry.GeometryType.Envelope: + bRelation = polygonRelateEnvelope_((Polygon) (_geometry_a), + (Envelope) (_geometry_b), tolerance, relation, + progress_tracker); + break; + + default: + break; // warning fix + } + break; + + case Geometry.GeometryType.Polyline: + switch (type_b) { + case Geometry.GeometryType.Polygon: + bRelation = polygonRelatePolyline_((Polygon) (_geometry_b), + (Polyline) (_geometry_a), tolerance, relation, + progress_tracker); + break; + + case Geometry.GeometryType.Polyline: + bRelation = polylineRelatePolyline_((Polyline) (_geometry_a), + (Polyline) (_geometry_b), tolerance, relation, + progress_tracker); + break; + + case Geometry.GeometryType.Point: + bRelation = polylineRelatePoint_((Polyline) (_geometry_a), + (Point) (_geometry_b), tolerance, relation, + progress_tracker); + break; + + case Geometry.GeometryType.MultiPoint: + bRelation = polylineRelateMultiPoint_((Polyline) (_geometry_a), + (MultiPoint) (_geometry_b), tolerance, relation, + progress_tracker); + break; + + case Geometry.GeometryType.Envelope: + bRelation = polylineRelateEnvelope_((Polyline) (_geometry_a), + (Envelope) (_geometry_b), tolerance, relation, + progress_tracker); + break; + + default: + break; // warning fix + } + break; + + case Geometry.GeometryType.Point: + switch (type_b) { + case Geometry.GeometryType.Polygon: + bRelation = polygonRelatePoint_((Polygon) (_geometry_b), + (Point) (_geometry_a), tolerance, relation, + progress_tracker); + break; + + case Geometry.GeometryType.Polyline: + bRelation = polylineRelatePoint_((Polyline) (_geometry_b), + (Point) (_geometry_a), tolerance, relation, + progress_tracker); + break; + + case Geometry.GeometryType.MultiPoint: + bRelation = multiPointRelatePoint_((MultiPoint) (_geometry_b), + (Point) (_geometry_a), tolerance, relation, + progress_tracker); + break; + + default: + break; // warning fix + } + break; + + case Geometry.GeometryType.MultiPoint: + switch (type_b) { + case Geometry.GeometryType.Polygon: + bRelation = polygonRelateMultiPoint_((Polygon) (_geometry_b), + (MultiPoint) (_geometry_a), tolerance, relation, + progress_tracker); + break; + + case Geometry.GeometryType.Polyline: + bRelation = polylineRelateMultiPoint_((Polyline) (_geometry_b), + (MultiPoint) (_geometry_a), tolerance, relation, + progress_tracker); + break; + + case Geometry.GeometryType.MultiPoint: + bRelation = multiPointRelateMultiPoint_( + (MultiPoint) (_geometry_a), (MultiPoint) (_geometry_b), + tolerance, relation, progress_tracker); + break; + + case Geometry.GeometryType.Point: + bRelation = multiPointRelatePoint_((MultiPoint) (_geometry_a), + (Point) (_geometry_b), tolerance, relation, + progress_tracker); + break; + + case Geometry.GeometryType.Envelope: + bRelation = multiPointRelateEnvelope_( + (MultiPoint) (_geometry_a), (Envelope) (_geometry_b), + tolerance, relation, progress_tracker); + break; + + default: + break; // warning fix + } + break; + + case Geometry.GeometryType.Envelope: + switch (type_b) { + case Geometry.GeometryType.Polygon: + bRelation = polygonRelateEnvelope_((Polygon) (_geometry_b), + (Envelope) (_geometry_a), tolerance, relation, + progress_tracker); + break; + + case Geometry.GeometryType.Polyline: + bRelation = polylineRelateEnvelope_((Polyline) (_geometry_b), + (Envelope) (_geometry_a), tolerance, relation, + progress_tracker); + break; + + case Geometry.GeometryType.MultiPoint: + bRelation = multiPointRelateEnvelope_( + (MultiPoint) (_geometry_b), (Envelope) (_geometry_a), + tolerance, relation, progress_tracker); + break; + + default: + break; // warning fix + } + break; + + default: + break; // warning fix + } + + return bRelation; + } + + // Computes the necessary 9 intersection relationships of boundary, + // interior, and exterior of envelope_a vs envelope_b for the given + // relation. + private static boolean relate(Envelope envelope_a, Envelope envelope_b, + SpatialReference sr, int relation, ProgressTracker progress_tracker) { + if (envelope_a.isEmpty() || envelope_b.isEmpty()) { + if (relation == Relation.disjoint) + return true; // Always true + + return false; // Always false + } + + Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(), env_merged = new Envelope2D(); + envelope_a.queryEnvelope2D(env_a); + envelope_b.queryEnvelope2D(env_b); + env_merged.setCoords(env_a); + env_merged.merge(env_b); + + double tolerance = InternalUtils.calculateToleranceFromGeometry(sr, + env_merged, false); + + switch (relation) { + case Relation.disjoint: + return envelopeDisjointEnvelope_(env_a, env_b, tolerance, + progress_tracker); + + case Relation.within: + return envelopeContainsEnvelope_(env_b, env_a, tolerance, + progress_tracker); + + case Relation.contains: + return envelopeContainsEnvelope_(env_a, env_b, tolerance, + progress_tracker); + + case Relation.equals: + return envelopeEqualsEnvelope_(env_a, env_b, tolerance, + progress_tracker); + + case Relation.touches: + return envelopeTouchesEnvelope_(env_a, env_b, tolerance, + progress_tracker); + + case Relation.overlaps: + return envelopeOverlapsEnvelope_(env_a, env_b, tolerance, + progress_tracker); + + case Relation.crosses: + return envelopeCrossesEnvelope_(env_a, env_b, tolerance, + progress_tracker); + + default: + break; // warning fix + } + + return false; + } + + // Computes the necessary 9 intersection relationships of boundary, + // interior, and exterior of point_a vs envelope_b for the given relation. + private static boolean relate(Point point_a, Envelope envelope_b, + SpatialReference sr, int relation, ProgressTracker progress_tracker) { + if (point_a.isEmpty() || envelope_b.isEmpty()) { + if (relation == Relation.disjoint) + return true; // Always true + + return false; // Always false + } + + Point2D pt_a = point_a.getXY(); + Envelope2D env_b = new Envelope2D(), env_merged = new Envelope2D(); + envelope_b.queryEnvelope2D(env_b); + env_merged.setCoords(pt_a); + env_merged.merge(env_b); + + double tolerance = InternalUtils.calculateToleranceFromGeometry(sr, + env_merged, false); + + switch (relation) { + case Relation.disjoint: + return pointDisjointEnvelope_(pt_a, env_b, tolerance, + progress_tracker); + + case Relation.within: + return pointWithinEnvelope_(pt_a, env_b, tolerance, + progress_tracker); + + case Relation.contains: + return pointContainsEnvelope_(pt_a, env_b, tolerance, + progress_tracker); + + case Relation.equals: + return pointEqualsEnvelope_(pt_a, env_b, tolerance, + progress_tracker); + + case Relation.touches: + return pointTouchesEnvelope_(pt_a, env_b, tolerance, + progress_tracker); + + default: + break; // warning fix + } + + return false; + } + + // Computes the necessary 9 intersection relationships of boundary, + // interior, and exterior of point_a vs point_b for the given relation. + private static boolean relate(Point point_a, Point point_b, + SpatialReference sr, int relation, ProgressTracker progress_tracker) { + if (point_a.isEmpty() || point_b.isEmpty()) { + if (relation == Relation.disjoint) + return true; // Always true + + return false; // Always false + } + + Point2D pt_a = point_a.getXY(); + Point2D pt_b = point_b.getXY(); + Envelope2D env_merged = new Envelope2D(); + env_merged.setCoords(pt_a); + env_merged.merge(pt_b); + + double tolerance = InternalUtils.calculateToleranceFromGeometry(sr, + env_merged, false); + + switch (relation) { + case Relation.disjoint: + return pointDisjointPoint_(pt_a, pt_b, tolerance, progress_tracker); + + case Relation.within: + return pointContainsPoint_(pt_b, pt_a, tolerance, progress_tracker); + + case Relation.contains: + return pointContainsPoint_(pt_a, pt_b, tolerance, progress_tracker); + + case Relation.equals: + return pointEqualsPoint_(pt_a, pt_b, tolerance, progress_tracker); + + default: + break; // warning fix + } + + return false; + } + + // Returns true if the relation holds. + private static boolean polygonRelatePolygon_(Polygon polygon_a, + Polygon polygon_b, double tolerance, int relation, + ProgressTracker progress_tracker) { + switch (relation) { + case Relation.disjoint: + return polygonDisjointPolygon_(polygon_a, polygon_b, tolerance, + progress_tracker); + + case Relation.within: + return polygonContainsPolygon_(polygon_b, polygon_a, tolerance, + progress_tracker); + + case Relation.contains: + return polygonContainsPolygon_(polygon_a, polygon_b, tolerance, + progress_tracker); + + case Relation.equals: + return polygonEqualsPolygon_(polygon_a, polygon_b, tolerance, + progress_tracker); + + case Relation.touches: + return polygonTouchesPolygon_(polygon_a, polygon_b, tolerance, + progress_tracker); + + case Relation.overlaps: + return polygonOverlapsPolygon_(polygon_a, polygon_b, tolerance, + progress_tracker); + + default: + break; // warning fix + } + + return false; + } + + // Returns true if the relation holds. + private static boolean polygonRelatePolyline_(Polygon polygon_a, + Polyline polyline_b, double tolerance, int relation, + ProgressTracker progress_tracker) { + switch (relation) { + case Relation.disjoint: + return polygonDisjointPolyline_(polygon_a, polyline_b, tolerance, + progress_tracker); + + case Relation.contains: + return polygonContainsPolyline_(polygon_a, polyline_b, tolerance, + progress_tracker); + + case Relation.touches: + return polygonTouchesPolyline_(polygon_a, polyline_b, tolerance, + progress_tracker); + + case Relation.crosses: + return polygonCrossesPolyline_(polygon_a, polyline_b, tolerance, + progress_tracker); + + default: + break; // warning fix + } + + return false; + } + + // Returns true if the relation holds. + private static boolean polygonRelatePoint_(Polygon polygon_a, + Point point_b, double tolerance, int relation, + ProgressTracker progress_tracker) { + switch (relation) { + case Relation.disjoint: + return polygonDisjointPoint_(polygon_a, point_b, tolerance, + progress_tracker); + + case Relation.contains: + return polygonContainsPoint_(polygon_a, point_b, tolerance, + progress_tracker); + + case Relation.touches: + return polygonTouchesPoint_(polygon_a, point_b, tolerance, + progress_tracker); + + default: + break; // warning fix + } + + return false; + } + + // Returns true if the relation holds + private static boolean polygonRelateMultiPoint_(Polygon polygon_a, + MultiPoint multipoint_b, double tolerance, int relation, + ProgressTracker progress_tracker) { + switch (relation) { + case Relation.disjoint: + return polygonDisjointMultiPoint_(polygon_a, multipoint_b, + tolerance, true, progress_tracker); + + case Relation.contains: + return polygonContainsMultiPoint_(polygon_a, multipoint_b, + tolerance, progress_tracker); + + case Relation.touches: + return polygonTouchesMultiPoint_(polygon_a, multipoint_b, + tolerance, progress_tracker); + + case Relation.crosses: + return polygonCrossesMultiPoint_(polygon_a, multipoint_b, + tolerance, progress_tracker); + + default: + break; // warning fix + } + + return false; + } + + // Returns true if the relation holds + private static boolean polygonRelateEnvelope_(Polygon polygon_a, + Envelope envelope_b, double tolerance, int relation, + ProgressTracker progress_tracker) { + if (polygonDisjointEnvelope_(polygon_a, envelope_b, tolerance, + progress_tracker)) { + if (relation == Relation.disjoint) + return true; + + return false; + } else if (relation == Relation.disjoint) { + return false; + } + + switch (relation) { + case Relation.within: + return polygonWithinEnvelope_(polygon_a, envelope_b, tolerance, + progress_tracker); + + case Relation.contains: + return polygonContainsEnvelope_(polygon_a, envelope_b, tolerance, + progress_tracker); + + case Relation.equals: + return polygonEqualsEnvelope_(polygon_a, envelope_b, tolerance, + progress_tracker); + + case Relation.touches: + return polygonTouchesEnvelope_(polygon_a, envelope_b, tolerance, + progress_tracker); + + case Relation.overlaps: + return polygonOverlapsEnvelope_(polygon_a, envelope_b, tolerance, + progress_tracker); + + case Relation.crosses: + return polygonCrossesEnvelope_(polygon_a, envelope_b, tolerance, + progress_tracker); + + default: + break; // warning fix + } + + return false; + } + + // Returns true if the relation holds. + private static boolean polylineRelatePolyline_(Polyline polyline_a, + Polyline polyline_b, double tolerance, int relation, + ProgressTracker progress_tracker) { + switch (relation) { + case Relation.disjoint: + return polylineDisjointPolyline_(polyline_a, polyline_b, tolerance, + progress_tracker); + + case Relation.within: + return polylineContainsPolyline_(polyline_b, polyline_a, tolerance, + progress_tracker); + + case Relation.contains: + return polylineContainsPolyline_(polyline_a, polyline_b, tolerance, + progress_tracker); + + case Relation.equals: + return polylineEqualsPolyline_(polyline_a, polyline_b, tolerance, + progress_tracker); + + case Relation.touches: + return polylineTouchesPolyline_(polyline_a, polyline_b, tolerance, + progress_tracker); + + case Relation.overlaps: + return polylineOverlapsPolyline_(polyline_a, polyline_b, tolerance, + progress_tracker); + + case Relation.crosses: + return polylineCrossesPolyline_(polyline_a, polyline_b, tolerance, + progress_tracker); + + default: + break; // warning fix + } + + return false; + } + + // Returns true if the relation holds. + private static boolean polylineRelatePoint_(Polyline polyline_a, + Point point_b, double tolerance, int relation, + ProgressTracker progress_tracker) { + switch (relation) { + case Relation.disjoint: + return polylineDisjointPoint_(polyline_a, point_b, tolerance, + progress_tracker); + + case Relation.contains: + return polylineContainsPoint_(polyline_a, point_b, tolerance, + progress_tracker); + + case Relation.touches: + return polylineTouchesPoint_(polyline_a, point_b, tolerance, + progress_tracker); + + default: + break; // warning fix + } + + return false; + } + + // Returns true if the relation holds. + private static boolean polylineRelateMultiPoint_(Polyline polyline_a, + MultiPoint multipoint_b, double tolerance, int relation, + ProgressTracker progress_tracker) { + switch (relation) { + case Relation.disjoint: + return polylineDisjointMultiPoint_(polyline_a, multipoint_b, + tolerance, progress_tracker); + + case Relation.contains: + return polylineContainsMultiPoint_(polyline_a, multipoint_b, + tolerance, progress_tracker); + + case Relation.touches: + return polylineTouchesMultiPoint_(polyline_a, multipoint_b, + tolerance, progress_tracker); + + case Relation.crosses: + return polylineCrossesMultiPoint_(polyline_a, multipoint_b, + tolerance, progress_tracker); + + default: + break; // warning fix + } + + return false; + } + + // Returns true if the relation holds. + private static boolean polylineRelateEnvelope_(Polyline polyline_a, + Envelope envelope_b, double tolerance, int relation, + ProgressTracker progress_tracker) { + if (polylineDisjointEnvelope_(polyline_a, envelope_b, tolerance, + progress_tracker)) { + if (relation == Relation.disjoint) + return true; + + return false; + } else if (relation == Relation.disjoint) { + return false; + } + + switch (relation) { + case Relation.within: + return polylineWithinEnvelope_(polyline_a, envelope_b, tolerance, + progress_tracker); + + case Relation.contains: + return polylineContainsEnvelope_(polyline_a, envelope_b, tolerance, + progress_tracker); + + case Relation.equals: + return polylineEqualsEnvelope_(polyline_a, envelope_b, tolerance, + progress_tracker); + + case Relation.touches: + return polylineTouchesEnvelope_(polyline_a, envelope_b, tolerance, + progress_tracker); + + case Relation.overlaps: + return polylineOverlapsEnvelope_(polyline_a, envelope_b, tolerance, + progress_tracker); + + case Relation.crosses: + return polylineCrossesEnvelope_(polyline_a, envelope_b, tolerance, + progress_tracker); + + default: + break; // warning fix + } + + return false; + } + + // Returns true if the relation holds. + private static boolean multiPointRelateMultiPoint_(MultiPoint multipoint_a, + MultiPoint multipoint_b, double tolerance, int relation, + ProgressTracker progress_tracker) { + switch (relation) { + case Relation.disjoint: + return multiPointDisjointMultiPoint_(multipoint_a, multipoint_b, + tolerance, progress_tracker); + + case Relation.within: + return multiPointContainsMultiPoint_(multipoint_b, multipoint_a, + tolerance, progress_tracker); + + case Relation.contains: + return multiPointContainsMultiPoint_(multipoint_a, multipoint_b, + tolerance, progress_tracker); + + case Relation.equals: + return multiPointEqualsMultiPoint_(multipoint_a, multipoint_b, + tolerance, progress_tracker); + + case Relation.overlaps: + return multiPointOverlapsMultiPoint_(multipoint_a, multipoint_b, + tolerance, progress_tracker); + + default: + break; // warning fix + } + + return false; + } + + // Returns true if the relation holds. + private static boolean multiPointRelatePoint_(MultiPoint multipoint_a, + Point point_b, double tolerance, int relation, + ProgressTracker progress_tracker) { + switch (relation) { + case Relation.disjoint: + return multiPointDisjointPoint_(multipoint_a, point_b, tolerance, + progress_tracker); + + case Relation.within: + return multiPointWithinPoint_(multipoint_a, point_b, tolerance, + progress_tracker); + + case Relation.contains: + return multiPointContainsPoint_(multipoint_a, point_b, tolerance, + progress_tracker); + + case Relation.equals: + return multiPointEqualsPoint_(multipoint_a, point_b, tolerance, + progress_tracker); + + default: + break; // warning fix + } + + return false; + } + + // Returns true if the relation holds. + private static boolean multiPointRelateEnvelope_(MultiPoint multipoint_a, + Envelope envelope_b, double tolerance, int relation, + ProgressTracker progress_tracker) { + switch (relation) { + case Relation.disjoint: + return multiPointDisjointEnvelope_(multipoint_a, envelope_b, + tolerance, progress_tracker); + + case Relation.within: + return multiPointWithinEnvelope_(multipoint_a, envelope_b, + tolerance, progress_tracker); + + case Relation.contains: + return multiPointContainsEnvelope_(multipoint_a, envelope_b, + tolerance, progress_tracker); + + case Relation.equals: + return multiPointEqualsEnvelope_(multipoint_a, envelope_b, + tolerance, progress_tracker); + + case Relation.touches: + return multiPointTouchesEnvelope_(multipoint_a, envelope_b, + tolerance, progress_tracker); + + case Relation.crosses: + return multiPointCrossesEnvelope_(multipoint_a, envelope_b, + tolerance, progress_tracker); + + default: + break; // warning fix + } + + return false; + } + + // Returns true if polygon_a equals polygon_b. + private static boolean polygonEqualsPolygon_(Polygon polygon_a, + Polygon polygon_b, double tolerance, + ProgressTracker progress_tracker) { + Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(); + polygon_a.queryEnvelope2D(env_a); + polygon_b.queryEnvelope2D(env_b); + + // Quick envelope rejection test for false equality. + if (!envelopeEqualsEnvelope_(env_a, env_b, tolerance, progress_tracker)) + return false; + + // Quick rasterize test to see whether the the geometries are disjoint, + // or if one is contained in the other. + int relation = tryRasterizedContainsOrDisjoint_(polygon_a, polygon_b, + tolerance, false); + + if (relation == Relation.disjoint || relation == Relation.contains + || relation == Relation.within) + return false; + + // Quick point equality check for true equality. This just checks if all + // the points in each ring are the same (within a tolerance) and in the + // same order + if (multiPathExactlyEqualsMultiPath_(polygon_a, polygon_b, tolerance, + progress_tracker)) + return true; + + double length_a = polygon_a.calculateLength2D(); + double length_b = polygon_b.calculateLength2D(); + int max_vertices = Math.max(polygon_a.getPointCount(), + polygon_b.getPointCount()); + + if (Math.abs(length_a - length_b) > max_vertices * 4.0 * tolerance) + return false; + + return linearPathEqualsLinearPath_(polygon_a, polygon_b, tolerance, true); + } + + // Returns true if polygon_a is disjoint from polygon_b. + private static boolean polygonDisjointPolygon_(Polygon polygon_a, + Polygon polygon_b, double tolerance, + ProgressTracker progress_tracker) { + // Quick rasterize test to see whether the the geometries are disjoint, + // or if one is contained in the other. + int relation = tryRasterizedContainsOrDisjoint_(polygon_a, polygon_b, + tolerance, true); + + if (relation == Relation.disjoint) + return true; + + if (relation == Relation.contains || relation == Relation.within + || relation == Relation.intersects) + return false; + + return polygonDisjointMultiPath_(polygon_a, polygon_b, tolerance, + progress_tracker); + } + + // Returns true if polygon_a touches polygon_b. + private static boolean polygonTouchesPolygon_(Polygon polygon_a, + Polygon polygon_b, double tolerance, + ProgressTracker progress_tracker) { + // Quick rasterize test to see whether the the geometries are disjoint, + // or if one is contained in the other. + int relation = tryRasterizedContainsOrDisjoint_(polygon_a, polygon_b, + tolerance, false); + + if (relation == Relation.disjoint || relation == Relation.contains + || relation == Relation.within) + return false; + + return polygonTouchesPolygonImpl_(polygon_a, polygon_b, tolerance, null); + } + + // Returns true if polygon_a overlaps polygon_b. + private static boolean polygonOverlapsPolygon_(Polygon polygon_a, + Polygon polygon_b, double tolerance, + ProgressTracker progress_tracker) { + // Quick rasterize test to see whether the the geometries are disjoint, + // or if one is contained in the other. + int relation = tryRasterizedContainsOrDisjoint_(polygon_a, polygon_b, + tolerance, false); + + if (relation == Relation.disjoint || relation == Relation.contains + || relation == Relation.within) + return false; + + return polygonOverlapsPolygonImpl_(polygon_a, polygon_b, tolerance, + progress_tracker); + } + + // Returns true if polygon_a contains polygon_b. + private static boolean polygonContainsPolygon_(Polygon polygon_a, + Polygon polygon_b, double tolerance, + ProgressTracker progress_tracker) { + Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(); + polygon_a.queryEnvelope2D(env_a); + polygon_b.queryEnvelope2D(env_b); + + // Quick envelope rejection test for false equality. + if (!envelopeInfContainsEnvelope_(env_a, env_b, tolerance)) + return false; + + // Quick rasterize test to see whether the the geometries are disjoint, + // or if one is contained in the other. + int relation = tryRasterizedContainsOrDisjoint_(polygon_a, polygon_b, + tolerance, false); + + if (relation == Relation.disjoint || relation == Relation.within) + return false; + + if (relation == Relation.contains) + return true; + + return polygonContainsPolygonImpl_(polygon_a, polygon_b, tolerance, + progress_tracker); + } + + // Returns true if polygon_a is disjoint from polyline_b. + private static boolean polygonDisjointPolyline_(Polygon polygon_a, + Polyline polyline_b, double tolerance, + ProgressTracker progress_tracker) { + // Quick rasterize test to see whether the the geometries are disjoint, + // or if one is contained in the other. + int relation = tryRasterizedContainsOrDisjoint_(polygon_a, polyline_b, + tolerance, true); + + if (relation == Relation.disjoint) + return true; + + if (relation == Relation.contains || relation == Relation.intersects) + return false; + + return polygonDisjointMultiPath_(polygon_a, polyline_b, tolerance, + progress_tracker); + } + + // Returns true if polygon_a touches polyline_b. + private static boolean polygonTouchesPolyline_(Polygon polygon_a, + Polyline polyline_b, double tolerance, + ProgressTracker progress_tracker) { + // Quick rasterize test to see whether the the geometries are disjoint, + // or if one is contained in the other. + int relation = tryRasterizedContainsOrDisjoint_(polygon_a, polyline_b, + tolerance, false); + + if (relation == Relation.disjoint || relation == Relation.contains) + return false; + + return polygonTouchesPolylineImpl_(polygon_a, polyline_b, tolerance, + progress_tracker); + } + + // Returns true if polygon_a crosses polyline_b. + private static boolean polygonCrossesPolyline_(Polygon polygon_a, + Polyline polyline_b, double tolerance, + ProgressTracker progress_tracker) { + // Quick rasterize test to see whether the the geometries are disjoint, + // or if one is contained in the other. + int relation = tryRasterizedContainsOrDisjoint_(polygon_a, polyline_b, + tolerance, false); + + if (relation == Relation.disjoint || relation == Relation.contains) + return false; + + return polygonCrossesPolylineImpl_(polygon_a, polyline_b, tolerance, + null); + } + + // Returns true if polygon_a contains polyline_b. + private static boolean polygonContainsPolyline_(Polygon polygon_a, + Polyline polyline_b, double tolerance, + ProgressTracker progress_tracker) { + Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(); + polygon_a.queryEnvelope2D(env_a); + polyline_b.queryEnvelope2D(env_b); + + // Quick envelope rejection test for false equality. + if (!envelopeInfContainsEnvelope_(env_a, env_b, tolerance)) + return false; + + // Quick rasterize test to see whether the the geometries are disjoint, + // or if one is contained in the other. + int relation = tryRasterizedContainsOrDisjoint_(polygon_a, polyline_b, + tolerance, false); + + if (relation == Relation.disjoint) + return false; + + if (relation == Relation.contains) + return true; + + return polygonContainsPolylineImpl_(polygon_a, polyline_b, tolerance, + progress_tracker); + } + + // Returns true if polygon_a is disjoint from point_b. + private static boolean polygonDisjointPoint_(Polygon polygon_a, + Point point_b, double tolerance, ProgressTracker progress_tracker) { + PolygonUtils.PiPResult result = PolygonUtils.isPointInPolygon2D( + polygon_a, point_b, tolerance); + + if (result == PolygonUtils.PiPResult.PiPOutside) + return true; + + return false; + } + + // Returns true of polygon_a touches point_b. + private static boolean polygonTouchesPoint_(Polygon polygon_a, + Point point_b, double tolerance, ProgressTracker progress_tracker) { + Point2D pt_b = point_b.getXY(); + return polygonTouchesPointImpl_(polygon_a, pt_b, tolerance, null); + } + + // Returns true if polygon_a contains point_b. + private static boolean polygonContainsPoint_(Polygon polygon_a, + Point point_b, double tolerance, ProgressTracker progress_tracker) { + Point2D pt_b = point_b.getXY(); + return polygonContainsPointImpl_(polygon_a, pt_b, tolerance, + progress_tracker); + } + + // Returns true if polygon_a is disjoint from multipoint_b. + private static boolean polygonDisjointMultiPoint_(Polygon polygon_a, + MultiPoint multipoint_b, double tolerance, + boolean bIncludeBoundaryA, ProgressTracker progress_tracker) { + // Quick rasterize test to see whether the the geometries are disjoint, + // or if one is contained in the other. + int relation = tryRasterizedContainsOrDisjoint_(polygon_a, + multipoint_b, tolerance, false); + + if (relation == Relation.disjoint) + return true; + + if (relation == Relation.contains) + return false; + + Envelope2D env_a_inflated = new Envelope2D(); + polygon_a.queryEnvelope2D(env_a_inflated); + env_a_inflated.inflate(tolerance, tolerance); + Point2D ptB = new Point2D(); + + for (int i = 0; i < multipoint_b.getPointCount(); i++) { + multipoint_b.getXY(i, ptB); + + if (!env_a_inflated.contains(ptB)) + continue; + + PolygonUtils.PiPResult result = PolygonUtils.isPointInPolygon2D( + polygon_a, ptB, tolerance); + + if (result == PolygonUtils.PiPResult.PiPInside + || (bIncludeBoundaryA && result == PolygonUtils.PiPResult.PiPBoundary)) + return false; + } + + return true; + } + + // Returns true if polygon_a touches multipoint_b. + private static boolean polygonTouchesMultiPoint_(Polygon polygon_a, + MultiPoint multipoint_b, double tolerance, + ProgressTracker progress_tracker) { + // Quick rasterize test to see whether the the geometries are disjoint, + // or if one is contained in the other. + int relation = tryRasterizedContainsOrDisjoint_(polygon_a, + multipoint_b, tolerance, false); + + if (relation == Relation.disjoint || relation == Relation.contains) + return false; - while (segIterA.nextPath()) { - while (segIterA.hasNextSegment()) { - boolean bStringOfSegmentAsCovered = false; - - Segment segmentA = segIterA.nextSegment(); - segmentA.queryEnvelope2D(env_a); - - if (!env_a.isIntersecting(envInter)) { - return false; // bWithin = false - } - - if (qtIterPathsB != null) { - qtIterPathsB.resetIterator(env_a, tolerance); - - if (qtIterPathsB.next() == -1) { - bWithin = false; - return false; - } - } + Envelope2D env_a_inflated = new Envelope2D(); + polygon_a.queryEnvelope2D(env_a_inflated); + env_a_inflated.inflate(tolerance, tolerance); - double lengthA = segmentA.calculateLength2D(); - - qtIterB.resetIterator(segmentA, tolerance); - - for (int elementHandleB = qtIterB.next(); elementHandleB != -1; elementHandleB = qtIterB - .next()) { - int vertex_b = quadTreeB.getElement(elementHandleB); - segIterB.resetToVertex(vertex_b); - Segment segmentB = segIterB.nextSegment(); - - int result = segmentA.intersect(segmentB, null, scalarsA, - scalarsB, tolerance); - - if (result == 2 && (!bEnforceOrientation || scalarsB[0] <= scalarsB[1])) { - double scalar_a_0 = scalarsA[0]; - double scalar_a_1 = scalarsA[1]; - double scalar_b_0 = scalarsB[0]; - double scalar_b_1 = scalarsB[1]; - - // Performance enhancement for nice cases where - // localization occurs. Increment segIterA as far as we - // can while the current segmentA is covered. - if (scalar_a_0 * lengthA <= tolerance - && (1.0 - scalar_a_1) * lengthA <= tolerance) { - bStringOfSegmentAsCovered = true; - - ievent = 0; - eventIndices.resize(0); - relOps.m_overlap_events.clear(); - - int ivertex_a = segIterA.getStartPointIndex(); - boolean bSegmentACovered = true; - - while (bSegmentACovered) {// keep going while the - // current segmentA is - // covered. - if (segIterA.hasNextSegment()) { - segmentA = segIterA.nextSegment(); - lengthA = segmentA.calculateLength2D(); - - result = segmentA.intersect(segmentB, null, - scalarsA, scalarsB, tolerance); - - if (result == 2 && (!bEnforceOrientation || scalarsB[0] <= scalarsB[1])) { - scalar_a_0 = scalarsA[0]; - scalar_a_1 = scalarsA[1]; - - if (scalar_a_0 * lengthA <= tolerance - && (1.0 - scalar_a_1) * lengthA <= tolerance) { - ivertex_a = segIterA - .getStartPointIndex(); - continue; - } - } - - if (segIterB.hasNextSegment()) { - segmentB = segIterB.nextSegment(); - result = segmentA.intersect(segmentB, - null, scalarsA, scalarsB, - tolerance); - - if (result == 2 && (!bEnforceOrientation || scalarsB[0] <= scalarsB[1])) { - scalar_a_0 = scalarsA[0]; - scalar_a_1 = scalarsA[1]; - - if (scalar_a_0 * lengthA <= tolerance - && (1.0 - scalar_a_1) - * lengthA <= tolerance) { - ivertex_a = segIterA - .getStartPointIndex(); - continue; - } - } - } - } - - bSegmentACovered = false; - } - - if (ivertex_a != segIterA.getStartPointIndex()) { - segIterA.resetToVertex(ivertex_a); - segIterA.nextSegment(); - } - - break; - } else { - int ivertex_a = segIterA.getStartPointIndex(); - int ipath_a = segIterA.getPathIndex(); - int ivertex_b = segIterB.getStartPointIndex(); - int ipath_b = segIterB.getPathIndex(); - - overlapEvent = OverlapEvent.construct(ivertex_a, - ipath_a, scalar_a_0, scalar_a_1, ivertex_b, - ipath_b, scalar_b_0, scalar_b_1); - relOps.m_overlap_events.add(overlapEvent); - eventIndices.add(eventIndices.size()); - } - } - } + Point2D ptB; + boolean b_boundary = false; - if (bStringOfSegmentAsCovered) { - continue; // no need to check that segmentA is covered - } - if (ievent == relOps.m_overlap_events.size()) { - return false; // bWithin = false - } + MultiPathImpl polygon_a_impl = (MultiPathImpl)polygon_a._getImpl(); - if (eventIndices.size() - ievent > 1) { - eventIndices.Sort(ievent, eventIndices.size(), - overlapComparer); - } + Polygon pa = null; + Polygon p_polygon_a = polygon_a; - double lastScalar = 0.0; + boolean b_checked_polygon_a_quad_tree = false; - for (int i = ievent; i < relOps.m_overlap_events.size(); i++) { - overlapEvent = relOps.m_overlap_events.get(eventIndices - .get(i)); + for (int i = 0; i < multipoint_b.getPointCount(); i++) + { + ptB = multipoint_b.getXY(i); - if (overlapEvent.m_scalar_a_0 < lastScalar - && overlapEvent.m_scalar_a_1 < lastScalar) { - continue; - } + if (env_a_inflated.contains(ptB)) { - if (lengthA * (overlapEvent.m_scalar_a_0 - lastScalar) > tolerance) { - return false; // bWithin = false - } else { - lastScalar = overlapEvent.m_scalar_a_1; + PolygonUtils.PiPResult result = PolygonUtils.isPointInPolygon2D(p_polygon_a, ptB, tolerance); - if (lengthA * (1.0 - lastScalar) <= tolerance - || lastScalar == 1.0) { - break; - } - } - } + if (result == PolygonUtils.PiPResult.PiPBoundary) + b_boundary = true; + else if (result == PolygonUtils.PiPResult.PiPInside) + return false; + } - if (lengthA * (1.0 - lastScalar) > tolerance) { - return false; // bWithin = false + if (!b_checked_polygon_a_quad_tree) { + if (PointInPolygonHelper.quadTreeWillHelp(polygon_a, multipoint_b.getPointCount() - 1) && (polygon_a_impl._getAccelerators() == null || polygon_a_impl._getAccelerators().getQuadTree() == null)) { + pa = new Polygon(); + polygon_a.copyTo(pa); + ((MultiPathImpl) pa._getImpl())._buildQuadTreeAccelerator(Geometry.GeometryAccelerationDegree.enumMedium); + p_polygon_a = pa; + } else { + p_polygon_a = polygon_a; } - ievent = 0; - eventIndices.resize(0); - relOps.m_overlap_events.clear(); + b_checked_polygon_a_quad_tree = true; } } - return bWithin; - } - - // Returns true if the segments of multipathA overlap the segments of - // multipathB. - private static boolean linearPathOverlapsLinearPath_(MultiPath multipathA, - MultiPath multipathB, double tolerance) { - int dim = linearPathIntersectsLinearPathMaxDim_(multipathA, multipathB, - tolerance, null); - - if (dim < 1) - return false; - - Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(); - multipathA.queryEnvelope2D(env_a); - multipathB.queryEnvelope2D(env_b); - - boolean bIntAExtB = interiorEnvExteriorEnv_(env_a, env_b, tolerance); - boolean bIntBExtA = interiorEnvExteriorEnv_(env_b, env_a, tolerance); - - if (bIntAExtB && bIntBExtA) + if (b_boundary) return true; - if (bIntAExtB && !bIntBExtA) - return !linearPathWithinLinearPath_(multipathB, multipathA, - tolerance, false); - - if (bIntBExtA && !bIntAExtB) - return !linearPathWithinLinearPath_(multipathA, multipathB, - tolerance, false); - - return !linearPathWithinLinearPath_(multipathA, multipathB, tolerance, false) - && !linearPathWithinLinearPath_(multipathB, multipathA, - tolerance, false); - } + return false; + } - // Returns true the dimension of intersection of _multipathA and - // _multipathB. - static int linearPathIntersectsLinearPathMaxDim_(MultiPath _multipathA, - MultiPath _multipathB, double tolerance, - AttributeStreamOfDbl intersections) { - MultiPath multipathA; - MultiPath multipathB; - - if (_multipathA.getSegmentCount() > _multipathB.getSegmentCount()) { - multipathA = _multipathB; - multipathB = _multipathA; - } else { - multipathA = _multipathA; - multipathB = _multipathB; - } + // Returns true if polygon_a crosses multipoint_b. + private static boolean polygonCrossesMultiPoint_(Polygon polygon_a, + MultiPoint multipoint_b, double tolerance, + ProgressTracker progress_tracker) { + // Quick rasterize test to see whether the the geometries are disjoint, + // or if one is contained in the other. + int relation = tryRasterizedContainsOrDisjoint_(polygon_a, + multipoint_b, tolerance, false); - SegmentIteratorImpl segIterA = ((MultiPathImpl) multipathA._getImpl()) - .querySegmentIterator(); - SegmentIteratorImpl segIterB = ((MultiPathImpl) multipathB._getImpl()) - .querySegmentIterator(); - double[] scalarsA = new double[2]; - double[] scalarsB = new double[2]; + if (relation == Relation.disjoint || relation == Relation.contains) + return false; - int dim = -1; - - int ievent = 0; - double overlapLength; - AttributeStreamOfInt32 eventIndices = new AttributeStreamOfInt32(0); - RelationalOperations relOps = new RelationalOperations(); - OverlapComparer overlapComparer = new OverlapComparer(relOps); - OverlapEvent overlapEvent; - - Envelope2D env_a = new Envelope2D(); - Envelope2D env_b = new Envelope2D(); - Envelope2D envInter = new Envelope2D(); - multipathA.queryEnvelope2D(env_a); - multipathB.queryEnvelope2D(env_b); - env_a.inflate(tolerance, tolerance); - env_b.inflate(tolerance, tolerance); - envInter.setCoords(env_a); - envInter.intersect(env_b); - - Point2D int_point = null; - - if (intersections != null) { - int_point = new Point2D(); - } + Envelope2D env_a = new Envelope2D(), env_a_inflated = new Envelope2D(), env_b = new Envelope2D(); + polygon_a.queryEnvelope2D(env_a); + multipoint_b.queryEnvelope2D(env_b); + env_a_inflated.setCoords(env_a); + env_a_inflated.inflate(tolerance, tolerance); - QuadTreeImpl qtB = null; - QuadTreeImpl quadTreeB = null; - QuadTreeImpl quadTreePathsB = null; + boolean b_interior = false, b_exterior = false; - GeometryAccelerators accel = ((MultiPathImpl) multipathB._getImpl()) - ._getAccelerators(); + Point2D pt_b; - if (accel != null) { - quadTreeB = accel.getQuadTree(); - quadTreePathsB = accel.getQuadTreeForPaths(); - if (quadTreeB == null) { - qtB = InternalUtils.buildQuadTree( - (MultiPathImpl) multipathB._getImpl(), envInter); - quadTreeB = qtB; - } - } else { - qtB = InternalUtils.buildQuadTree( - (MultiPathImpl) multipathB._getImpl(), envInter); - quadTreeB = qtB; - } + MultiPathImpl polygon_a_impl = (MultiPathImpl)polygon_a._getImpl(); - QuadTreeImpl.QuadTreeIteratorImpl qtIterB = quadTreeB.getIterator(); + Polygon pa = null; + Polygon p_polygon_a = polygon_a; - QuadTreeImpl.QuadTreeIteratorImpl qtIterPathsB = null; - if (quadTreePathsB != null) - qtIterPathsB = quadTreePathsB.getIterator(); + boolean b_checked_polygon_a_quad_tree = false; - while (segIterA.nextPath()) { - overlapLength = 0.0; + for (int i = 0; i < multipoint_b.getPointCount(); i++) + { + pt_b = multipoint_b.getXY(i); - while (segIterA.hasNextSegment()) { - Segment segmentA = segIterA.nextSegment(); - segmentA.queryEnvelope2D(env_a); + if (!env_a_inflated.contains(pt_b)) + { + b_exterior = true; + } + else + { + PolygonUtils.PiPResult result = PolygonUtils.isPointInPolygon2D(p_polygon_a, pt_b, tolerance); - if (!env_a.isIntersecting(envInter)) { - continue; - } + if (result == PolygonUtils.PiPResult.PiPOutside) + b_exterior = true; + else if (result == PolygonUtils.PiPResult.PiPInside) + b_interior = true; + } - if (qtIterPathsB != null) { - qtIterPathsB.resetIterator(env_a, tolerance); + if (b_interior && b_exterior) + return true; - if (qtIterPathsB.next() == -1) - continue; + if (!b_checked_polygon_a_quad_tree) { + if (PointInPolygonHelper.quadTreeWillHelp(polygon_a, multipoint_b.getPointCount() - 1) && (polygon_a_impl._getAccelerators() == null || polygon_a_impl._getAccelerators().getQuadTree() == null)) { + pa = new Polygon(); + polygon_a.copyTo(pa); + ((MultiPathImpl) pa._getImpl())._buildQuadTreeAccelerator(Geometry.GeometryAccelerationDegree.enumMedium); + p_polygon_a = pa; + } else { + p_polygon_a = polygon_a; } - double lengthA = segmentA.calculateLength2D(); - - qtIterB.resetIterator(segmentA, tolerance); - - for (int elementHandleB = qtIterB.next(); elementHandleB != -1; elementHandleB = qtIterB - .next()) { - int vertex_b = quadTreeB.getElement(elementHandleB); - segIterB.resetToVertex(vertex_b); - - Segment segmentB = segIterB.nextSegment(); - double lengthB = segmentB.calculateLength2D(); - - int result = segmentA.intersect(segmentB, null, scalarsA, - scalarsB, tolerance); - - if (result > 0) { - double scalar_a_0 = scalarsA[0]; - double scalar_b_0 = scalarsB[0]; - double scalar_a_1 = (result == 2 ? scalarsA[1] - : NumberUtils.TheNaN); - double scalar_b_1 = (result == 2 ? scalarsB[1] - : NumberUtils.TheNaN); - - if (result == 2) { - if (lengthA * (scalar_a_1 - scalar_a_0) > tolerance) { - dim = 1; - return dim; - } - - // Quick neighbor check - double length = lengthA * (scalar_a_1 - scalar_a_0); - - if (segIterB.hasNextSegment()) { - segmentB = segIterB.nextSegment(); - result = segmentA.intersect(segmentB, null, - scalarsA, null, tolerance); - - if (result == 2) { - double nextScalarA0 = scalarsA[0]; - double nextScalarA1 = scalarsA[1]; - - double lengthNext = lengthA - * (nextScalarA1 - nextScalarA0); - - if (length + lengthNext > tolerance) { - dim = 1; - return dim; - } - } - - segIterB.resetToVertex(vertex_b); - segIterB.nextSegment(); - } - - if (!segIterB.isFirstSegmentInPath()) { - segIterB.previousSegment(); - segmentB = segIterB.previousSegment(); - result = segmentA.intersect(segmentB, null, - scalarsA, null, tolerance); - - if (result == 2) { - double nextScalarA0 = scalarsA[0]; - double nextScalarA1 = scalarsA[1]; - - double lengthPrevious = lengthA - * (nextScalarA1 - nextScalarA0); - - if (length + lengthPrevious > tolerance) { - dim = 1; - return dim; - } - } - - segIterB.resetToVertex(vertex_b); - segIterB.nextSegment(); - } - - if (segIterA.hasNextSegment()) { - int vertex_a = segIterA.getStartPointIndex(); - segmentA = segIterA.nextSegment(); - result = segmentA.intersect(segmentB, null, - scalarsA, null, tolerance); - - if (result == 2) { - double nextScalarA0 = scalarsA[0]; - double nextScalarA1 = scalarsA[1]; - - double lengthNext = lengthA - * (nextScalarA1 - nextScalarA0); - - if (length + lengthNext > tolerance) { - dim = 1; - return dim; - } - } - - segIterA.resetToVertex(vertex_a); - segIterA.nextSegment(); - } - - if (!segIterA.isFirstSegmentInPath()) { - int vertex_a = segIterA.getStartPointIndex(); - segIterA.previousSegment(); - segmentA = segIterA.previousSegment(); - result = segmentA.intersect(segmentB, null, - scalarsA, null, tolerance); - - if (result == 2) { - double nextScalarA0 = scalarsA[0]; - double nextScalarA1 = scalarsA[1]; - - double lengthPrevious = lengthB - * (nextScalarA1 - nextScalarA0); - - if (length + lengthPrevious > tolerance) { - dim = 1; - return dim; - } - } - - segIterA.resetToVertex(vertex_a); - segIterA.nextSegment(); - } - - int ivertex_a = segIterA.getStartPointIndex(); - int ipath_a = segIterA.getPathIndex(); - int ivertex_b = segIterB.getStartPointIndex(); - int ipath_b = segIterB.getPathIndex(); - - overlapEvent = OverlapEvent.construct(ivertex_a, - ipath_a, scalar_a_0, scalar_a_1, ivertex_b, - ipath_b, scalar_b_0, scalar_b_1); - relOps.m_overlap_events.add(overlapEvent); - eventIndices.add(eventIndices.size()); - } + b_checked_polygon_a_quad_tree = true; + } + } - dim = 0; + return false; + } - if (intersections != null) { - segmentA.getCoord2D(scalar_a_0, int_point); - intersections.add(int_point.x); - intersections.add(int_point.y); - } - } - } + // Returns true if polygon_a contains multipoint_b. + private static boolean polygonContainsMultiPoint_(Polygon polygon_a, + MultiPoint multipoint_b, double tolerance, + ProgressTracker progress_tracker) { + Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(); + polygon_a.queryEnvelope2D(env_a); + multipoint_b.queryEnvelope2D(env_b); - if (ievent < relOps.m_overlap_events.size()) { - eventIndices.Sort(ievent, eventIndices.size(), - overlapComparer); + // Quick envelope rejection test for false equality. + if (!envelopeInfContainsEnvelope_(env_a, env_b, tolerance)) + return false; - double lastScalar = 0.0; - int lastPath = relOps.m_overlap_events.get(eventIndices - .get(ievent)).m_ipath_a; + // Quick rasterize test to see whether the the geometries are disjoint, + // or if one is contained in the other. + int relation = tryRasterizedContainsOrDisjoint_(polygon_a, + multipoint_b, tolerance, false); - for (int i = ievent; i < relOps.m_overlap_events.size(); i++) { - overlapEvent = relOps.m_overlap_events.get(eventIndices - .get(i)); + if (relation == Relation.disjoint) + return false; - if (overlapEvent.m_scalar_a_0 < lastScalar - && overlapEvent.m_scalar_a_1 < lastScalar) { - continue; - } + if (relation == Relation.contains) + return true; - if (lengthA * (overlapEvent.m_scalar_a_0 - lastScalar) > tolerance) { - overlapLength = lengthA - * (overlapEvent.m_scalar_a_1 - overlapEvent.m_scalar_a_0); // reset - lastScalar = overlapEvent.m_scalar_a_1; - lastPath = overlapEvent.m_ipath_a; - } else { - if (overlapEvent.m_ipath_a != lastPath) { - overlapLength = lengthA - * (overlapEvent.m_scalar_a_1 - overlapEvent.m_scalar_a_0); // reset - lastPath = overlapEvent.m_ipath_a; - } else { - overlapLength += lengthA - * (overlapEvent.m_scalar_a_1 - overlapEvent.m_scalar_a_0); // accumulate - } - if (overlapLength > tolerance) { - dim = 1; - return dim; - } - - lastScalar = overlapEvent.m_scalar_a_1; - - if (lastScalar == 1.0) { - break; - } - } - } + boolean b_interior = false; + Point2D ptB; - if (lengthA * (1.0 - lastScalar) > tolerance) { - overlapLength = 0.0; // reset - } - ievent = 0; - eventIndices.resize(0); - relOps.m_overlap_events.clear(); - } - } - } + MultiPathImpl polygon_a_impl = (MultiPathImpl)polygon_a._getImpl(); - return dim; - } + Polygon pa = null; + Polygon p_polygon_a = polygon_a; - // Returns true if the line segments of _multipathA intersect the line - // segments of _multipathB. - private static boolean linearPathIntersectsLinearPath_( - MultiPath multipathA, MultiPath multipathB, double tolerance) { - MultiPathImpl multi_path_impl_a = (MultiPathImpl) multipathA._getImpl(); - MultiPathImpl multi_path_impl_b = (MultiPathImpl) multipathB._getImpl(); + boolean b_checked_polygon_a_quad_tree = false; - SegmentIteratorImpl segIterA = multi_path_impl_a.querySegmentIterator(); - SegmentIteratorImpl segIterB = multi_path_impl_b.querySegmentIterator(); + for (int i = 0; i < multipoint_b.getPointCount(); i++) + { + ptB = multipoint_b.getXY(i); - PairwiseIntersectorImpl intersector = new PairwiseIntersectorImpl(multi_path_impl_a, multi_path_impl_b, tolerance, false); + if (!env_a.contains(ptB)) + return false; - while (intersector.next()) { - int vertex_a = intersector.getRedElement(); - int vertex_b = intersector.getBlueElement(); + PolygonUtils.PiPResult result = PolygonUtils.isPointInPolygon2D(p_polygon_a, ptB, tolerance); - segIterA.resetToVertex(vertex_a); - segIterB.resetToVertex(vertex_b); - Segment segmentA = segIterA.nextSegment(); - Segment segmentB = segIterB.nextSegment(); + if (result == PolygonUtils.PiPResult.PiPInside) + b_interior = true; + else if (result == PolygonUtils.PiPResult.PiPOutside) + return false; - int result = segmentB.intersect(segmentA, null, null, null, - tolerance); + if (!b_checked_polygon_a_quad_tree) { + if (PointInPolygonHelper.quadTreeWillHelp(polygon_a, multipoint_b.getPointCount() - 1) && (polygon_a_impl._getAccelerators() == null || polygon_a_impl._getAccelerators().getQuadTree() == null)) { + pa = new Polygon(); + polygon_a.copyTo(pa); + ((MultiPathImpl) pa._getImpl())._buildQuadTreeAccelerator(Geometry.GeometryAccelerationDegree.enumMedium); + p_polygon_a = pa; + } else { + p_polygon_a = polygon_a; + } - if (result > 0) { - return true; + b_checked_polygon_a_quad_tree = true; } } - return false; - } + return b_interior; + } + + // Returns true if polygon_a equals envelope_b. + private static boolean polygonEqualsEnvelope_(Polygon polygon_a, + Envelope envelope_b, double tolerance, + ProgressTracker progress_tracker) { + Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(); + polygon_a.queryEnvelope2D(env_a); + envelope_b.queryEnvelope2D(env_b); + + // Quick envelope rejection test for false equality. + // This check will correctly handle degenerate envelope cases (i.e. + // degenerate to point or line) + if (!envelopeEqualsEnvelope_(env_a, env_b, tolerance, progress_tracker)) + return false; + + Polygon polygon_b = new Polygon(); + polygon_b.addEnvelope(envelope_b, false); + + return linearPathEqualsLinearPath_(polygon_a, polygon_b, tolerance, true); + } + + // Returns true if polygon_a is disjoint from envelope_b. + private static boolean polygonDisjointEnvelope_(Polygon polygon_a, + Envelope envelope_b, double tolerance, + ProgressTracker progress_tracker) { + // Quick rasterize test to see whether the the geometries are disjoint, + // or if one is contained in the other. + int relation = tryRasterizedContainsOrDisjoint_(polygon_a, envelope_b, + tolerance, false); + + if (relation == Relation.disjoint) + return true; + + if (relation == Relation.contains || relation == Relation.within) + return false; + + Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(); + polygon_a.queryEnvelope2D(env_a); + envelope_b.queryEnvelope2D(env_b); + + if (envelopeInfContainsEnvelope_(env_b, env_a, tolerance)) + return false; + + PolygonUtils.PiPResult pipres; + Point2D pt_b = new Point2D(); + env_b.queryLowerLeft(pt_b); + pipres = PolygonUtils.isPointInPolygon2D(polygon_a, pt_b, tolerance); + if (pipres != PolygonUtils.PiPResult.PiPOutside) + return false; + + env_b.queryLowerRight(pt_b); + pipres = PolygonUtils.isPointInPolygon2D(polygon_a, pt_b, tolerance); + if (pipres != PolygonUtils.PiPResult.PiPOutside) + return false; + + env_b.queryUpperRight(pt_b); + pipres = PolygonUtils.isPointInPolygon2D(polygon_a, pt_b, tolerance); + if (pipres != PolygonUtils.PiPResult.PiPOutside) + return false; + + env_b.queryUpperLeft(pt_b); + pipres = PolygonUtils.isPointInPolygon2D(polygon_a, pt_b, tolerance); + if (pipres != PolygonUtils.PiPResult.PiPOutside) + return false; + + MultiPathImpl mimpl_a = (MultiPathImpl) polygon_a._getImpl(); + AttributeStreamOfDbl pos = (AttributeStreamOfDbl) (mimpl_a + .getAttributeStreamRef(VertexDescription.Semantics.POSITION)); + + Envelope2D env_b_inflated = new Envelope2D(); + env_b_inflated.setCoords(env_b); + env_b_inflated.inflate(tolerance, tolerance); + for (int ptIndex = 0, n = mimpl_a.getPointCount(); ptIndex < n; ptIndex++) { + double x = pos.read(2 * ptIndex); + double y = pos.read(2 * ptIndex + 1); + if (env_b_inflated.contains(x, y)) + return false; + } + + return !linearPathIntersectsEnvelope_(polygon_a, env_b, tolerance, + progress_tracker); + } + + // Returns true if polygon_a touches envelope_b. + private static boolean polygonTouchesEnvelope_(Polygon polygon_a, + Envelope envelope_b, double tolerance, + ProgressTracker progress_tracker) { + // Quick rasterize test to see whether the the geometries are disjoint, + // or if one is contained in the other. + int relation = tryRasterizedContainsOrDisjoint_(polygon_a, envelope_b, + tolerance, false); + + if (relation == Relation.disjoint || relation == Relation.contains + || relation == Relation.within) + return false; + + Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(); + polygon_a.queryEnvelope2D(env_a); + envelope_b.queryEnvelope2D(env_b); + + if (envelopeInfContainsEnvelope_(env_b, env_a, tolerance)) + return false; + + if (env_b.getWidth() <= tolerance && env_b.getHeight() <= tolerance) {// treat + // as + // point + Point2D pt_b = envelope_b.getCenterXY(); + return polygonTouchesPointImpl_(polygon_a, pt_b, tolerance, + progress_tracker); + } + + if (env_b.getWidth() <= tolerance || env_b.getHeight() <= tolerance) {// treat + // as + // polyline + Polyline polyline_b = new Polyline(); + Point p = new Point(); + envelope_b.queryCornerByVal(0, p); + polyline_b.startPath(p); + envelope_b.queryCornerByVal(2, p); + polyline_b.lineTo(p); + return polygonTouchesPolylineImpl_(polygon_a, polyline_b, + tolerance, progress_tracker); + } + + // treat as polygon + Polygon polygon_b = new Polygon(); + polygon_b.addEnvelope(envelope_b, false); + return polygonTouchesPolygonImpl_(polygon_a, polygon_b, tolerance, + progress_tracker); + } + + // Returns true if polygon_a overlaps envelope_b. + private static boolean polygonOverlapsEnvelope_(Polygon polygon_a, + Envelope envelope_b, double tolerance, + ProgressTracker progress_tracker) { + // Quick rasterize test to see whether the the geometries are disjoint, + // or if one is contained in the other. + int relation = tryRasterizedContainsOrDisjoint_(polygon_a, envelope_b, + tolerance, false); + + if (relation == Relation.disjoint || relation == Relation.contains + || relation == Relation.within) + return false; + + Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(); + polygon_a.queryEnvelope2D(env_a); + envelope_b.queryEnvelope2D(env_b); + + if (envelopeInfContainsEnvelope_(env_b, env_a, tolerance)) + return false; + + if (env_b.getWidth() <= tolerance || env_b.getHeight() <= tolerance) + return false; // has no interior + + Polygon polygon_b = new Polygon(); + polygon_b.addEnvelope(envelope_b, false); + return polygonOverlapsPolygonImpl_(polygon_a, polygon_b, tolerance, + progress_tracker); + } + + // Returns true if polygon_a is within envelope_b + private static boolean polygonWithinEnvelope_(Polygon polygon_a, + Envelope envelope_b, double tolerance, + ProgressTracker progress_tracker) { + Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(); + polygon_a.queryEnvelope2D(env_a); + envelope_b.queryEnvelope2D(env_b); + return envelopeInfContainsEnvelope_(env_b, env_a, tolerance); + } + + // Returns true if polygon_a contains envelope_b. + private static boolean polygonContainsEnvelope_(Polygon polygon_a, + Envelope envelope_b, double tolerance, + ProgressTracker progress_tracker) { + // Quick envelope rejection test + + Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(); + polygon_a.queryEnvelope2D(env_a); + envelope_b.queryEnvelope2D(env_b); + + if (!envelopeInfContainsEnvelope_(env_a, env_b, tolerance)) + return false; + + // Quick rasterize test to see whether the the geometries are disjoint, + // or if one is contained in the other. + int relation = tryRasterizedContainsOrDisjoint_(polygon_a, envelope_b, + tolerance, false); + + if (relation == Relation.disjoint || relation == Relation.within) + return false; + + if (relation == Relation.contains) + return true; + + if (env_b.getWidth() <= tolerance && env_b.getHeight() <= tolerance) {// treat + // as + // point + Point2D pt_b = envelope_b.getCenterXY(); + return polygonContainsPointImpl_(polygon_a, pt_b, tolerance, + progress_tracker); + } + + if (env_b.getWidth() <= tolerance || env_b.getHeight() <= tolerance) {// treat + // as + // polyline + Polyline polyline_b = new Polyline(); + Point p = new Point(); + envelope_b.queryCornerByVal(0, p); + polyline_b.startPath(p); + envelope_b.queryCornerByVal(2, p); + polyline_b.lineTo(p); + return polygonContainsPolylineImpl_(polygon_a, polyline_b, + tolerance, null); + } + + // treat as polygon + Polygon polygon_b = new Polygon(); + polygon_b.addEnvelope(envelope_b, false); + return polygonContainsPolygonImpl_(polygon_a, polygon_b, tolerance, + null); + } + + // Returns true if polygon_a crosses envelope_b. + private static boolean polygonCrossesEnvelope_(Polygon polygon_a, + Envelope envelope_b, double tolerance, + ProgressTracker progress_tracker) { + Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(); + polygon_a.queryEnvelope2D(env_a); + envelope_b.queryEnvelope2D(env_b); + + if (envelopeInfContainsEnvelope_(env_b, env_a, tolerance)) + return false; + + if (env_b.getHeight() > tolerance && env_b.getWidth() > tolerance) + return false; // when treated as an area, areas cannot cross areas. + + if (env_b.getHeight() <= tolerance && env_b.getWidth() <= tolerance) + return false; // when treated as a point, areas cannot cross points. + + // Treat as polyline + Polyline polyline_b = new Polyline(); + Point p = new Point(); + envelope_b.queryCornerByVal(0, p); + polyline_b.startPath(p); + envelope_b.queryCornerByVal(2, p); + polyline_b.lineTo(p); + return polygonCrossesPolylineImpl_(polygon_a, polyline_b, tolerance, + progress_tracker); + } + + // Returns true if polyline_a equals polyline_b. + private static boolean polylineEqualsPolyline_(Polyline polyline_a, + Polyline polyline_b, double tolerance, + ProgressTracker progress_tracker) { + Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(); + polyline_a.queryEnvelope2D(env_a); + polyline_b.queryEnvelope2D(env_b); + + // Quick envelope rejection test for false equality. + if (!envelopeEqualsEnvelope_(env_a, env_b, tolerance, progress_tracker)) + return false; + + // Quick rasterize test to see whether the the geometries are disjoint. + if (tryRasterizedContainsOrDisjoint_(polyline_a, polyline_b, tolerance, + false) == Relation.disjoint) + return false; + + // Quick point equality check for true equality. This just checks if all + // the points in each ring are the same (within a tolerance) and in the + // same order + if (multiPathExactlyEqualsMultiPath_(polyline_a, polyline_b, tolerance, + progress_tracker)) + return true; + + return linearPathEqualsLinearPath_(polyline_a, polyline_b, tolerance, false); + } + + // Returns true if polyline_a is disjoint from polyline_b. + private static boolean polylineDisjointPolyline_(Polyline polyline_a, + Polyline polyline_b, double tolerance, + ProgressTracker progress_tracker) { + // Quick rasterize test to see whether the the geometries are disjoint. + if (tryRasterizedContainsOrDisjoint_(polyline_a, polyline_b, tolerance, + false) == Relation.disjoint) + return true; + + MultiPathImpl multi_path_impl_a = (MultiPathImpl)polyline_a._getImpl(); + MultiPathImpl multi_path_impl_b = (MultiPathImpl)polyline_b._getImpl(); - // Returns true if the relation intersects, crosses, or contains holds - // between multipathA and multipoint_b. multipathA is put in the - // Quad_tree_impl. - private static boolean linearPathIntersectsMultiPoint_( - MultiPath multipathA, MultiPoint multipoint_b, double tolerance, - boolean b_intersects_all) { - SegmentIteratorImpl segIterA = ((MultiPathImpl) multipathA._getImpl()) - .querySegmentIterator(); - - boolean bContained = true; - boolean bInteriorHitFound = false; - - Envelope2D env_a = new Envelope2D(); - Envelope2D env_b = new Envelope2D(); - Envelope2D envInter = new Envelope2D(); - multipathA.queryEnvelope2D(env_a); - multipoint_b.queryEnvelope2D(env_b); - env_a.inflate(tolerance, tolerance); + PairwiseIntersectorImpl intersector_paths = new PairwiseIntersectorImpl(multi_path_impl_a, multi_path_impl_b, tolerance, true); - if (!env_a.contains(env_b)) { - bContained = false; - } + if (!intersector_paths.next()) + return false; - env_b.inflate(tolerance, tolerance); - envInter.setCoords(env_a); - envInter.intersect(env_b); + return !linearPathIntersectsLinearPath_(polyline_a, polyline_b, + tolerance); + } - QuadTreeImpl qtA = null; - QuadTreeImpl quadTreeA = null; + // Returns true if polyline_a touches polyline_b. + private static boolean polylineTouchesPolyline_(Polyline polyline_a, + Polyline polyline_b, double tolerance, + ProgressTracker progress_tracker) { + // Quick rasterize test to see whether the the geometries are disjoint. + if (tryRasterizedContainsOrDisjoint_(polyline_a, polyline_b, tolerance, + false) == Relation.disjoint) + return false; + + AttributeStreamOfDbl intersections = new AttributeStreamOfDbl(0); + + int dim = linearPathIntersectsLinearPathMaxDim_(polyline_a, polyline_b, + tolerance, intersections); + + if (dim != 0) + return false; + + MultiPoint intersection = new MultiPoint(); + + for (int i = 0; i < intersections.size(); i += 2) { + double x = intersections.read(i); + double y = intersections.read(i + 1); + intersection.add(x, y); + } + + MultiPoint boundary_a_b = (MultiPoint) (polyline_a.getBoundary()); + MultiPoint boundary_b = (MultiPoint) (polyline_b.getBoundary()); + + boundary_a_b.add(boundary_b, 0, boundary_b.getPointCount()); + + return multiPointContainsMultiPointBrute_(boundary_a_b, intersection, + tolerance); + } + + // Returns true if polyline_a crosses polyline_b. + private static boolean polylineCrossesPolyline_(Polyline polyline_a, + Polyline polyline_b, double tolerance, + ProgressTracker progress_tracker) { + // Quick rasterize test to see whether the the geometries are disjoint. + if (tryRasterizedContainsOrDisjoint_(polyline_a, polyline_b, tolerance, + false) == Relation.disjoint) + return false; + + AttributeStreamOfDbl intersections = new AttributeStreamOfDbl(0); + + int dim = linearPathIntersectsLinearPathMaxDim_(polyline_a, polyline_b, + tolerance, intersections); + + if (dim != 0) + return false; + + MultiPoint intersection = new MultiPoint(); + + for (int i = 0; i < intersections.size(); i += 2) { + double x = intersections.read(i); + double y = intersections.read(i + 1); + intersection.add(x, y); + } + + MultiPoint boundary_a_b = (MultiPoint) (polyline_a.getBoundary()); + MultiPoint boundary_b = (MultiPoint) (polyline_b.getBoundary()); + + boundary_a_b.add(boundary_b, 0, boundary_b.getPointCount()); + + return !multiPointContainsMultiPointBrute_(boundary_a_b, intersection, + tolerance); + } + + // Returns true if polyline_a overlaps polyline_b. + private static boolean polylineOverlapsPolyline_(Polyline polyline_a, + Polyline polyline_b, double tolerance, + ProgressTracker progress_tracker) { + // Quick rasterize test to see whether the the geometries are disjoint. + if (tryRasterizedContainsOrDisjoint_(polyline_a, polyline_b, tolerance, + false) == Relation.disjoint) + return false; + + return linearPathOverlapsLinearPath_(polyline_a, polyline_b, tolerance); + } + + // Returns true if polyline_a contains polyline_b. + private static boolean polylineContainsPolyline_(Polyline polyline_a, + Polyline polyline_b, double tolerance, + ProgressTracker progress_tracker) { + Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(); + polyline_a.queryEnvelope2D(env_a); + polyline_b.queryEnvelope2D(env_b); + + // Quick envelope rejection test for false equality. + if (!envelopeInfContainsEnvelope_(env_a, env_b, tolerance)) + return false; + + // Quick rasterize test to see whether the the geometries are disjoint. + if (tryRasterizedContainsOrDisjoint_(polyline_a, polyline_b, tolerance, + false) == Relation.disjoint) + return false; + + return linearPathWithinLinearPath_(polyline_b, polyline_a, tolerance, false); + } + + // Returns true if polyline_a is disjoint from point_b. + private static boolean polylineDisjointPoint_(Polyline polyline_a, + Point point_b, double tolerance, ProgressTracker progress_tracker) { + // Quick rasterize test to see whether the the geometries are disjoint. + if (tryRasterizedContainsOrDisjoint_(polyline_a, point_b, tolerance, + false) == Relation.disjoint) + return true; + + Point2D pt_b = point_b.getXY(); + return !linearPathIntersectsPoint_(polyline_a, pt_b, tolerance); + } + + // Returns true if polyline_a touches point_b. + private static boolean polylineTouchesPoint_(Polyline polyline_a, + Point point_b, double tolerance, ProgressTracker progress_tracker) { + // Quick rasterize test to see whether the the geometries are disjoint. + if (tryRasterizedContainsOrDisjoint_(polyline_a, point_b, tolerance, + false) == Relation.disjoint) + return false; + + Point2D pt_b = point_b.getXY(); + return linearPathTouchesPointImpl_(polyline_a, pt_b, tolerance); + } + + // Returns true of polyline_a contains point_b. + private static boolean polylineContainsPoint_(Polyline polyline_a, + Point point_b, double tolerance, ProgressTracker progress_tracker) { + // Quick rasterize test to see whether the the geometries are disjoint. + if (tryRasterizedContainsOrDisjoint_(polyline_a, point_b, tolerance, + false) == Relation.disjoint) + return false; + + Point2D pt_b = point_b.getXY(); + return linearPathContainsPoint_(polyline_a, pt_b, tolerance); + } + + // Returns true if polyline_a is disjoint from multipoint_b. + private static boolean polylineDisjointMultiPoint_(Polyline polyline_a, + MultiPoint multipoint_b, double tolerance, + ProgressTracker progress_tracker) { + // Quick rasterize test to see whether the the geometries are disjoint. + if (tryRasterizedContainsOrDisjoint_(polyline_a, multipoint_b, + tolerance, false) == Relation.disjoint) + return true; + + return !linearPathIntersectsMultiPoint_(polyline_a, multipoint_b, + tolerance, false); + } + + // Returns true if polyline_a touches multipoint_b. + private static boolean polylineTouchesMultiPoint_(Polyline polyline_a, + MultiPoint multipoint_b, double tolerance, + ProgressTracker progress_tracker) { + // Quick rasterize test to see whether the the geometries are disjoint. + if (tryRasterizedContainsOrDisjoint_(polyline_a, multipoint_b, + tolerance, false) == Relation.disjoint) { + return false; + } + + SegmentIteratorImpl segIterA = ((MultiPathImpl) polyline_a._getImpl()) + .querySegmentIterator(); + + Envelope2D env_a = new Envelope2D(); + Envelope2D env_b = new Envelope2D(); + Envelope2D envInter = new Envelope2D(); + polyline_a.queryEnvelope2D(env_a); + multipoint_b.queryEnvelope2D(env_b); + env_a.inflate(tolerance, tolerance); + env_b.inflate(tolerance, tolerance); + envInter.setCoords(env_a); + envInter.intersect(env_b); + + QuadTreeImpl qtA = null; + QuadTreeImpl quadTreeA = null; QuadTreeImpl quadTreePathsA = null; - GeometryAccelerators accel = ((MultiPathImpl) multipathA._getImpl()) - ._getAccelerators(); + GeometryAccelerators accel = ((MultiPathImpl) (polyline_a._getImpl())) + ._getAccelerators(); - if (accel != null) { - quadTreeA = accel.getQuadTree(); - if (quadTreeA == null) { - qtA = InternalUtils.buildQuadTree( - (MultiPathImpl) multipathA._getImpl(), envInter); - quadTreeA = qtA; - } - } else { - qtA = InternalUtils.buildQuadTree( - (MultiPathImpl) multipathA._getImpl(), envInter); - quadTreeA = qtA; - } - - QuadTreeImpl.QuadTreeIteratorImpl qtIterA = quadTreeA.getIterator(); + if (accel != null) { + quadTreeA = accel.getQuadTree(); + quadTreePathsA = accel.getQuadTreeForPaths(); + if (quadTreeA == null) { + qtA = InternalUtils.buildQuadTree( + (MultiPathImpl) polyline_a._getImpl(), envInter); + quadTreeA = qtA; + } + } else { + qtA = InternalUtils.buildQuadTree( + (MultiPathImpl) polyline_a._getImpl(), envInter); + quadTreeA = qtA; + } + + QuadTreeImpl.QuadTreeIteratorImpl qtIterA = quadTreeA.getIterator(); QuadTreeImpl.QuadTreeIteratorImpl qtIterPathsA = null; if (quadTreePathsA != null) qtIterPathsA = quadTreePathsA.getIterator(); - Point2D ptB = new Point2D(), closest = new Point2D(); - boolean b_intersects = false; - double toleranceSq = tolerance * tolerance; + Point2D ptB = new Point2D(), closest = new Point2D(); + boolean b_intersects = false; + double toleranceSq = tolerance * tolerance; - for (int i = 0; i < multipoint_b.getPointCount(); i++) { - multipoint_b.getXY(i, ptB); + AttributeStreamOfInt8 intersects = new AttributeStreamOfInt8( + multipoint_b.getPointCount()); + for (int i = 0; i < multipoint_b.getPointCount(); i++) { + intersects.write(i, (byte) 0); + } - if (!envInter.contains(ptB)) { - continue; - } + for (int i = 0; i < multipoint_b.getPointCount(); i++) { + multipoint_b.getXY(i, ptB); - env_b.setCoords(ptB.x, ptB.y, ptB.x, ptB.y); + if (!envInter.contains(ptB)) { + continue; + } + + env_b.setCoords(ptB.x, ptB.y, ptB.x, ptB.y); if (qtIterPathsA != null) { qtIterPathsA.resetIterator(env_b, tolerance); @@ -4195,521 +1840,2880 @@ private static boolean linearPathIntersectsMultiPoint_( continue; } - qtIterA.resetIterator(env_b, tolerance); - - boolean b_covered = false; - - for (int elementHandleA = qtIterA.next(); elementHandleA != -1; elementHandleA = qtIterA - .next()) { - int vertex_a = quadTreeA.getElement(elementHandleA); - segIterA.resetToVertex(vertex_a); - Segment segmentA = segIterA.nextSegment(); - - double t = segmentA.getClosestCoordinate(ptB, false); - segmentA.getCoord2D(t, closest); + qtIterA.resetIterator(env_b, tolerance); + + for (int elementHandleA = qtIterA.next(); elementHandleA != -1; elementHandleA = qtIterA + .next()) { + int vertex_a = quadTreeA.getElement(elementHandleA); + segIterA.resetToVertex(vertex_a); + + Segment segmentA = segIterA.nextSegment(); + double t = segmentA.getClosestCoordinate(ptB, false); + segmentA.getCoord2D(t, closest); + + if (Point2D.sqrDistance(ptB, closest) <= toleranceSq) { + intersects.write(i, (byte) 1); + b_intersects = true; + break; + } + } + } + + if (!b_intersects) { + return false; + } + + MultiPoint boundary_a = (MultiPoint) (polyline_a.getBoundary()); + MultiPoint multipoint_b_inter = new MultiPoint(); + Point2D pt = new Point2D(); + + for (int i = 0; i < multipoint_b.getPointCount(); i++) { + if (intersects.read(i) == 0) { + continue; + } + + multipoint_b.getXY(i, pt); + multipoint_b_inter.add(pt.x, pt.y); + } + + return multiPointContainsMultiPointBrute_(boundary_a, + multipoint_b_inter, tolerance); + } + + // Returns true if polyline_a crosses multipoint_b. + private static boolean polylineCrossesMultiPoint_(Polyline polyline_a, + MultiPoint multipoint_b, double tolerance, + ProgressTracker progress_tracker) { + // Quick rasterize test to see whether the the geometries are disjoint. + if (tryRasterizedContainsOrDisjoint_(polyline_a, multipoint_b, + tolerance, false) == Relation.disjoint) { + return false; + } + + SegmentIteratorImpl segIterA = ((MultiPathImpl) polyline_a._getImpl()) + .querySegmentIterator(); + + Envelope2D env_a = new Envelope2D(); + Envelope2D env_b = new Envelope2D(); + Envelope2D envInter = new Envelope2D(); + polyline_a.queryEnvelope2D(env_a); + multipoint_b.queryEnvelope2D(env_b); + env_a.inflate(tolerance, tolerance); + env_b.inflate(tolerance, tolerance); + envInter.setCoords(env_a); + envInter.intersect(env_b); + + QuadTreeImpl qtA = null; + QuadTreeImpl quadTreeA = null; + QuadTreeImpl quadTreePathsA = null; - if (Point2D.sqrDistance(closest, ptB) <= toleranceSq) { - b_covered = true; - break; - } - } + GeometryAccelerators accel = ((MultiPathImpl) (polyline_a._getImpl())) + ._getAccelerators(); - if (b_intersects_all) { - if (!b_covered) { - return false; - } - } else { - if (b_covered) { - return true; - } - } - } + if (accel != null) { + quadTreeA = accel.getQuadTree(); + quadTreePathsA = accel.getQuadTreeForPaths(); + if (quadTreeA == null) { + qtA = InternalUtils.buildQuadTree( + (MultiPathImpl) polyline_a._getImpl(), envInter); + quadTreeA = qtA; + } + } else { + qtA = InternalUtils.buildQuadTree( + (MultiPathImpl) polyline_a._getImpl(), envInter); + quadTreeA = qtA; + } + + QuadTreeImpl.QuadTreeIteratorImpl qtIterA = quadTreeA.getIterator(); - if (b_intersects_all) { - return true; - } + QuadTreeImpl.QuadTreeIteratorImpl qtIterPathsA = null; + if (quadTreePathsA != null) + qtIterPathsA = quadTreePathsA.getIterator(); - return false; - } + Point2D ptB = new Point2D(), closest = new Point2D(); + boolean b_intersects = false; + boolean b_exterior_found = false; + double toleranceSq = tolerance * tolerance; - // Returns true if a segment of multipathA intersects point_b. - static boolean linearPathIntersectsPoint_(MultiPath multipathA, - Point2D ptB, double tolerance) { - Point2D closest = new Point2D(); - double toleranceSq = tolerance * tolerance; - SegmentIteratorImpl segIterA = ((MultiPathImpl) multipathA._getImpl()) - .querySegmentIterator(); + AttributeStreamOfInt8 intersects = new AttributeStreamOfInt8( + multipoint_b.getPointCount()); + for (int i = 0; i < multipoint_b.getPointCount(); i++) { + intersects.write(i, (byte) 0); + } - GeometryAccelerators accel = ((MultiPathImpl) multipathA._getImpl()) - ._getAccelerators(); + for (int i = 0; i < multipoint_b.getPointCount(); i++) { + multipoint_b.getXY(i, ptB); - if (accel != null) { - QuadTreeImpl quadTreeA = accel.getQuadTree(); - if (quadTreeA != null) { - Envelope2D env_b = new Envelope2D(); - env_b.setCoords(ptB); + if (!envInter.contains(ptB)) { + b_exterior_found = true; + continue; + } - QuadTreeImpl.QuadTreeIteratorImpl qt_iter = quadTreeA - .getIterator(env_b, tolerance); + env_b.setCoords(ptB.x, ptB.y, ptB.x, ptB.y); - for (int e = qt_iter.next(); e != -1; e = qt_iter.next()) { - segIterA.resetToVertex(quadTreeA.getElement(e)); + if (qtIterPathsA != null) { + qtIterPathsA.resetIterator(env_b, tolerance); - if (segIterA.hasNextSegment()) { - Segment segmentA = segIterA.nextSegment(); + if (qtIterPathsA.next() == -1) { + b_exterior_found = true; + continue; + } + } - double t = segmentA.getClosestCoordinate(ptB, false); - segmentA.getCoord2D(t, closest); + qtIterA.resetIterator(env_b, tolerance); + + boolean b_covered = false; + + for (int elementHandleA = qtIterA.next(); elementHandleA != -1; elementHandleA = qtIterA + .next()) { + int vertex_a = quadTreeA.getElement(elementHandleA); + segIterA.resetToVertex(vertex_a); + + Segment segmentA = segIterA.nextSegment(); + double t = segmentA.getClosestCoordinate(ptB, false); + segmentA.getCoord2D(t, closest); + + if (Point2D.sqrDistance(ptB, closest) <= toleranceSq) { + intersects.write(i, (byte) 1); + b_intersects = true; + b_covered = true; + break; + } + } + + if (!b_covered) { + b_exterior_found = true; + } + } + + if (!b_intersects || !b_exterior_found) { + return false; + } + + MultiPoint boundary_a = (MultiPoint) (polyline_a.getBoundary()); + MultiPoint multipoint_b_inter = new MultiPoint(); + Point2D pt = new Point2D(); + + for (int i = 0; i < multipoint_b.getPointCount(); i++) { + if (intersects.read(i) == 0) { + continue; + } + + multipoint_b.getXY(i, pt); + multipoint_b_inter.add(pt.x, pt.y); + } + + return !multiPointContainsMultiPointBrute_(boundary_a, + multipoint_b_inter, tolerance); + } + + // Returns true if polyline_a contains multipoint_b. + private static boolean polylineContainsMultiPoint_(Polyline polyline_a, + MultiPoint multipoint_b, double tolerance, + ProgressTracker progress_tracker) { + Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(); + polyline_a.queryEnvelope2D(env_a); + multipoint_b.queryEnvelope2D(env_b); + + if (!envelopeInfContainsEnvelope_(env_a, env_b, tolerance)) + return false; + + // Quick rasterize test to see whether the the geometries are disjoint. + if (tryRasterizedContainsOrDisjoint_(polyline_a, multipoint_b, + tolerance, false) == Relation.disjoint) + return false; + + if (!linearPathIntersectsMultiPoint_(polyline_a, multipoint_b, + tolerance, true)) + return false; + + MultiPoint boundary_a = (MultiPoint) (polyline_a.getBoundary()); + return !multiPointIntersectsMultiPoint_(boundary_a, multipoint_b, + tolerance, progress_tracker); + } + + // Returns true if polyline_a equals envelope_b. + private static boolean polylineEqualsEnvelope_(Polyline polyline_a, + Envelope envelope_b, double tolerance, + ProgressTracker progress_tracker) { + Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(); + polyline_a.queryEnvelope2D(env_a); + envelope_b.queryEnvelope2D(env_b); + + if (env_b.getHeight() > tolerance && env_b.getWidth() > tolerance) + return false; // area cannot equal a line + + return envelopeEqualsEnvelope_(env_a, env_b, tolerance, + progress_tracker); + } + + // Returns true if polyline_a is disjoint from envelope_b. + private static boolean polylineDisjointEnvelope_(Polyline polyline_a, + Envelope envelope_b, double tolerance, + ProgressTracker progress_tracker) { + Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(); + polyline_a.queryEnvelope2D(env_a); + envelope_b.queryEnvelope2D(env_b); + + if (envelopeInfContainsEnvelope_(env_b, env_a, tolerance)) + return false; + + return !linearPathIntersectsEnvelope_(polyline_a, env_b, tolerance, + progress_tracker); + } + + // Returns true if polyline_a touches envelope_b. + private static boolean polylineTouchesEnvelope_(Polyline polyline_a, + Envelope envelope_b, double tolerance, + ProgressTracker progress_tracker) { + Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(); + polyline_a.queryEnvelope2D(env_a); + envelope_b.queryEnvelope2D(env_b); + + if (env_b.getHeight() <= tolerance && env_b.getWidth() <= tolerance) {// Treat + // as + // point + Point2D pt_b = envelope_b.getCenterXY(); + return linearPathTouchesPointImpl_(polyline_a, pt_b, tolerance); + } + + if (env_b.getHeight() <= tolerance || env_b.getWidth() <= tolerance) {// Treat + // as + // polyline + Polyline polyline_b = new Polyline(); + Point p = new Point(); + envelope_b.queryCornerByVal(0, p); + polyline_b.startPath(p); + envelope_b.queryCornerByVal(2, p); + polyline_b.lineTo(p); + return polylineTouchesPolyline_(polyline_a, polyline_b, tolerance, + progress_tracker); + } + + // Treat env_b as area + + SegmentIterator seg_iter_a = polyline_a.querySegmentIterator(); + Envelope2D env_b_deflated = new Envelope2D(), env_b_inflated = new Envelope2D(); + env_b_deflated.setCoords(env_b); + env_b_inflated.setCoords(env_b); + env_b_deflated.inflate(-tolerance, -tolerance); + env_b_inflated.inflate(tolerance, tolerance); + + boolean b_boundary = false; + Envelope2D env_segment_a = new Envelope2D(); + Envelope2D env_inter = new Envelope2D(); + + while (seg_iter_a.nextPath()) { + while (seg_iter_a.hasNextSegment()) { + Segment segment_a = seg_iter_a.nextSegment(); + segment_a.queryEnvelope2D(env_segment_a); + + env_inter.setCoords(env_b_deflated); + env_inter.intersect(env_segment_a); + + if (!env_inter.isEmpty() + && (env_inter.getHeight() > tolerance || env_inter + .getWidth() > tolerance)) + return false; // consider segment within + + env_inter.setCoords(env_b_inflated); + env_inter.intersect(env_segment_a); + + if (!env_inter.isEmpty()) + b_boundary = true; + } + } + + return b_boundary; + } + + // Returns true if polyline_a overlaps envelope_b. + private static boolean polylineOverlapsEnvelope_(Polyline polyline_a, + Envelope envelope_b, double tolerance, + ProgressTracker progress_tracker) { + Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(); + polyline_a.queryEnvelope2D(env_a); + envelope_b.queryEnvelope2D(env_b); + + if (envelopeInfContainsEnvelope_(env_a, env_b, tolerance) + || envelopeInfContainsEnvelope_(env_b, env_a, tolerance)) + return false; + + if (envelopeInfContainsEnvelope_(env_b, env_a, tolerance)) + return false; + + if (env_b.getHeight() > tolerance && env_b.getWidth() > tolerance) + return false; // lines cannot overlap areas + + if (env_b.getHeight() <= tolerance && env_b.getWidth() <= tolerance) + return false; // lines cannot overlap points + + // Treat as polyline + Polyline polyline_b = new Polyline(); + Point p = new Point(); + envelope_b.queryCornerByVal(0, p); + polyline_b.startPath(p); + envelope_b.queryCornerByVal(2, p); + polyline_b.lineTo(p); + return linearPathOverlapsLinearPath_(polyline_a, polyline_b, tolerance); + } + + // Returns true if polyline_a is within envelope_b. + private static boolean polylineWithinEnvelope_(Polyline polyline_a, + Envelope envelope_b, double tolerance, + ProgressTracker progress_tracker) { + Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(); + polyline_a.queryEnvelope2D(env_a); + envelope_b.queryEnvelope2D(env_b); + + if (!envelopeInfContainsEnvelope_(env_b, env_a, tolerance)) + return false; + + if (env_b.getHeight() <= tolerance && env_b.getWidth() <= tolerance) + return false; + + if (env_b.getHeight() <= tolerance || env_b.getWidth() <= tolerance) + return envelopeInfContainsEnvelope_(env_b, env_a, tolerance); + + SegmentIterator seg_iter_a = polyline_a.querySegmentIterator(); + Envelope2D env_b_deflated = new Envelope2D(); + env_b_deflated.setCoords(env_b); + env_b_deflated.inflate(-tolerance, -tolerance); + + boolean b_interior = false; + Envelope2D env_segment_a = new Envelope2D(); + Envelope2D env_inter = new Envelope2D(); + + while (seg_iter_a.nextPath()) { + while (seg_iter_a.hasNextSegment()) { + Segment segment_a = seg_iter_a.nextSegment(); + segment_a.queryEnvelope2D(env_segment_a); + + if (env_b_deflated.containsExclusive(env_segment_a)) { + b_interior = true; + continue; + } + + env_inter.setCoords(env_b_deflated); + env_inter.intersect(env_segment_a); + + if (!env_inter.isEmpty() + && (env_inter.getHeight() > tolerance || env_inter + .getWidth() > tolerance)) + b_interior = true; + } + } + + return b_interior; + } + + // Returns true if polyline_a contains envelope_b. + private static boolean polylineContainsEnvelope_(Polyline polyline_a, + Envelope envelope_b, double tolerance, + ProgressTracker progress_tracker) { + Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(); + envelope_b.queryEnvelope2D(env_b); + polyline_a.queryEnvelope2D(env_a); + + if (!envelopeInfContainsEnvelope_(env_a, env_b, tolerance)) + return false; + + if (env_b.getHeight() > tolerance && env_b.getWidth() > tolerance) + return false; // when treated as an area, lines cannot contain + // areas. + + if (env_b.getHeight() <= tolerance && env_b.getWidth() <= tolerance) {// Treat + // as + // point + Point2D pt_b = envelope_b.getCenterXY(); + return linearPathContainsPoint_(polyline_a, pt_b, tolerance); + } + + // Treat as polyline + Polyline polyline_b = new Polyline(); + Point p = new Point(); + envelope_b.queryCornerByVal(0, p); + polyline_b.startPath(p); + envelope_b.queryCornerByVal(2, p); + polyline_b.lineTo(p); + return linearPathWithinLinearPath_(polyline_b, polyline_a, tolerance, false); + } + + // Returns true if polyline_a crosses envelope_b. + private static boolean polylineCrossesEnvelope_(Polyline polyline_a, + Envelope envelope_b, double tolerance, + ProgressTracker progress_tracker) { + Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(); + polyline_a.queryEnvelope2D(env_a); + envelope_b.queryEnvelope2D(env_b); + + if (envelopeInfContainsEnvelope_(env_b, env_a, tolerance)) + return false; + + if (env_b.getHeight() <= tolerance && env_b.getWidth() <= tolerance) + return false; // when treated as a point, lines cannot cross points. + + if (env_b.getHeight() <= tolerance || env_b.getWidth() <= tolerance) {// Treat + // as + // polyline + Polyline polyline_b = new Polyline(); + Point p = new Point(); + envelope_b.queryCornerByVal(0, p); + polyline_b.startPath(p); + envelope_b.queryCornerByVal(2, p); + polyline_b.lineTo(p); + return polylineCrossesPolyline_(polyline_a, polyline_b, tolerance, + progress_tracker); + } + + // Treat env_b as area + + SegmentIterator seg_iter_a = polyline_a.querySegmentIterator(); + Envelope2D env_b_inflated = new Envelope2D(), env_b_deflated = new Envelope2D(); + env_b_deflated.setCoords(env_b); + env_b_inflated.setCoords(env_b); + env_b_deflated.inflate(-tolerance, -tolerance); + env_b_inflated.inflate(tolerance, tolerance); + + boolean b_interior = false, b_exterior = false; + Envelope2D env_segment_a = new Envelope2D(); + Envelope2D env_inter = new Envelope2D(); + + while (seg_iter_a.nextPath()) { + while (seg_iter_a.hasNextSegment()) { + Segment segment_a = seg_iter_a.nextSegment(); + segment_a.queryEnvelope2D(env_segment_a); + + if (!b_exterior) { + if (!env_b_inflated.contains(env_segment_a)) + b_exterior = true; + } + + if (!b_interior) { + env_inter.setCoords(env_b_deflated); + env_inter.intersect(env_segment_a); + + if (!env_inter.isEmpty() + && (env_inter.getHeight() > tolerance || env_inter + .getWidth() > tolerance)) + b_interior = true; + } + + if (b_interior && b_exterior) + return true; + } + } + + return false; + } + + // Returns true if multipoint_a equals multipoint_b. + private static boolean multiPointEqualsMultiPoint_(MultiPoint multipoint_a, + MultiPoint multipoint_b, double tolerance, + ProgressTracker progress_tracker) { + Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(); + multipoint_a.queryEnvelope2D(env_a); + multipoint_b.queryEnvelope2D(env_b); + + if (!envelopeEqualsEnvelope_(env_a, env_b, tolerance, progress_tracker)) + return false; + + if (multiPointExactlyEqualsMultiPoint_(multipoint_a, multipoint_b, + tolerance, progress_tracker)) + return true; + + return multiPointCoverageMultiPoint_(multipoint_a, multipoint_b, + tolerance, false, true, false, progress_tracker); + } + + // Returns true if multipoint_a is disjoint from multipoint_b. + private static boolean multiPointDisjointMultiPoint_( + MultiPoint multipoint_a, MultiPoint multipoint_b, double tolerance, + ProgressTracker progress_tracker) { + return !multiPointIntersectsMultiPoint_(multipoint_a, multipoint_b, + tolerance, progress_tracker); + } + + // Returns true if multipoint_a overlaps multipoint_b. + private static boolean multiPointOverlapsMultiPoint_( + MultiPoint multipoint_a, MultiPoint multipoint_b, double tolerance, + ProgressTracker progress_tracker) { + return multiPointCoverageMultiPoint_(multipoint_a, multipoint_b, + tolerance, false, false, true, progress_tracker); + } + + // Returns true if multipoint_a contains multipoint_b. + private static boolean multiPointContainsMultiPoint_( + MultiPoint multipoint_a, MultiPoint multipoint_b, double tolerance, + ProgressTracker progress_tracker) { + Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(); + multipoint_a.queryEnvelope2D(env_a); + multipoint_b.queryEnvelope2D(env_b); + + if (!envelopeInfContainsEnvelope_(env_a, env_b, tolerance)) + return false; + + return multiPointCoverageMultiPoint_(multipoint_b, multipoint_a, + tolerance, true, false, false, progress_tracker); + } + + private static boolean multiPointContainsMultiPointBrute_( + MultiPoint multipoint_a, MultiPoint multipoint_b, double tolerance) { + double tolerance_sq = tolerance * tolerance; + Point2D pt_a = new Point2D(); + Point2D pt_b = new Point2D(); + + for (int i = 0; i < multipoint_b.getPointCount(); i++) { + multipoint_b.getXY(i, pt_b); + boolean b_contained = false; + + for (int j = 0; j < multipoint_a.getPointCount(); j++) { + multipoint_a.getXY(j, pt_a); + + if (Point2D.sqrDistance(pt_a, pt_b) <= tolerance_sq) { + b_contained = true; + break; + } + } + + if (!b_contained) + return false; + } + + return true; + } + + // Returns true if multipoint_a equals point_b. + static boolean multiPointEqualsPoint_(MultiPoint multipoint_a, + Point point_b, double tolerance, ProgressTracker progress_tracker) { + Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(); + multipoint_a.queryEnvelope2D(env_a); + point_b.queryEnvelope2D(env_b); + return envelopeEqualsEnvelope_(env_a, env_b, tolerance, + progress_tracker); + } + + // Returns true if multipoint_a is disjoint from point_b. + private static boolean multiPointDisjointPoint_(MultiPoint multipoint_a, + Point point_b, double tolerance, ProgressTracker progress_tracker) { + Point2D pt_b = point_b.getXY(); + return multiPointDisjointPointImpl_(multipoint_a, pt_b, tolerance, + progress_tracker); + } + + // Returns true if multipoint_a is within point_b. + private static boolean multiPointWithinPoint_(MultiPoint multipoint_a, + Point point_b, double tolerance, ProgressTracker progress_tracker) { + return multiPointEqualsPoint_(multipoint_a, point_b, tolerance, + progress_tracker); + } + + // Returns true if multipoint_a contains point_b. + private static boolean multiPointContainsPoint_(MultiPoint multipoint_a, + Point point_b, double tolerance, ProgressTracker progress_tracker) { + return !multiPointDisjointPoint_(multipoint_a, point_b, tolerance, + progress_tracker); + } + + // Returns true if multipoint_a equals envelope_b. + private static boolean multiPointEqualsEnvelope_(MultiPoint multipoint_a, + Envelope envelope_b, double tolerance, + ProgressTracker progress_tracker) { + Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(); + multipoint_a.queryEnvelope2D(env_a); + envelope_b.queryEnvelope2D(env_b); + + if (env_b.getHeight() > tolerance || env_b.getWidth() > tolerance) + return false; + + // only true if all the points of the multi_point degenerate to a point + // equal to the envelope + return envelopeEqualsEnvelope_(env_a, env_b, tolerance, + progress_tracker); + } + + // Returns true if multipoint_a is disjoint from envelope_b. + private static boolean multiPointDisjointEnvelope_(MultiPoint multipoint_a, + Envelope envelope_b, double tolerance, + ProgressTracker progress_tracker) { + Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(); + multipoint_a.queryEnvelope2D(env_a); + envelope_b.queryEnvelope2D(env_b); + + if (envelopeInfContainsEnvelope_(env_b, env_a, tolerance)) + return false; + + Envelope2D env_b_inflated = new Envelope2D(); + env_b_inflated.setCoords(env_b); + env_b_inflated.inflate(tolerance, tolerance); + Point2D pt_a = new Point2D(); + + for (int i = 0; i < multipoint_a.getPointCount(); i++) { + multipoint_a.getXY(i, pt_a); + + if (!env_b_inflated.contains(pt_a)) + continue; + + return false; + } + + return true; + } + + // Returns true if multipoint_a touches envelope_b. + private static boolean multiPointTouchesEnvelope_(MultiPoint multipoint_a, + Envelope envelope_b, double tolerance, + ProgressTracker progress_tracker) { + Envelope2D env_b = new Envelope2D(), env_b_inflated = new Envelope2D(), env_b_deflated = new Envelope2D(); + envelope_b.queryEnvelope2D(env_b); + + if (env_b.getHeight() <= tolerance && env_b.getWidth() <= tolerance) + return false; // there are no boundaries to intersect + + if (env_b.getHeight() <= tolerance || env_b.getWidth() <= tolerance) {// treat + // as + // line + + Point2D pt_a = new Point2D(); + boolean b_boundary = false; + + env_b_inflated.setCoords(env_b); + env_b_deflated.setCoords(env_b); + env_b_inflated.inflate(tolerance, tolerance); + if (env_b.getHeight() > tolerance) + env_b_deflated.inflate(0, -tolerance); + else + env_b_deflated.inflate(-tolerance, 0); + + for (int i = 0; i < multipoint_a.getPointCount(); i++) { + multipoint_a.getXY(i, pt_a); + + if (!env_b_inflated.contains(pt_a)) + continue; + + if (env_b.getHeight() > tolerance) { + if (pt_a.y > env_b_deflated.ymin + && pt_a.y < env_b_deflated.ymax) + return false; + + b_boundary = true; + } else { + if (pt_a.x > env_b_deflated.xmin + && pt_a.x < env_b_deflated.xmax) + return false; + + b_boundary = true; + } + } + + return b_boundary; + } + + // treat as area + env_b_inflated.setCoords(env_b); + env_b_deflated.setCoords(env_b); + env_b_inflated.inflate(tolerance, tolerance); + env_b_deflated.inflate(-tolerance, -tolerance); - if (Point2D.sqrDistance(ptB, closest) <= toleranceSq) { - return true; - } - } - } + Point2D pt_a = new Point2D(); + boolean b_boundary = false; + + for (int i = 0; i < multipoint_a.getPointCount(); i++) { + multipoint_a.getXY(i, pt_a); + + if (!env_b_inflated.contains(pt_a)) + continue; + + if (env_b_deflated.containsExclusive(pt_a)) + return false; + + b_boundary = true; + } - return false; - } - } - Envelope2D env_a = new Envelope2D(); + return b_boundary; + } - while (segIterA.nextPath()) { - while (segIterA.hasNextSegment()) { - Segment segmentA = segIterA.nextSegment(); - segmentA.queryEnvelope2D(env_a); - env_a.inflate(tolerance, tolerance); + // Returns true if multipoint_a is within envelope_b. + private static boolean multiPointWithinEnvelope_(MultiPoint multipoint_a, + Envelope envelope_b, double tolerance, + ProgressTracker progress_tracker) { + Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(); + multipoint_a.queryEnvelope2D(env_a); + envelope_b.queryEnvelope2D(env_b); - if (!env_a.contains(ptB)) { - continue; - } + if (!envelopeInfContainsEnvelope_(env_b, env_a, tolerance)) + return false; - double t = segmentA.getClosestCoordinate(ptB, false); - segmentA.getCoord2D(t, closest); + if (env_b.getHeight() <= tolerance && env_b.getWidth() <= tolerance) + return envelopeEqualsEnvelope_(env_a, env_b, tolerance, + progress_tracker); // treat as point - if (Point2D.sqrDistance(ptB, closest) <= toleranceSq) { - return true; - } - } - } + if (env_b.getHeight() <= tolerance || env_b.getWidth() <= tolerance) {// treat + // as + // line + + boolean b_interior = false; - return false; - } + Envelope2D env_b_deflated = new Envelope2D(), env_b_inflated = new Envelope2D(); + env_b_deflated.setCoords(env_b); + env_b_inflated.setCoords(env_b); + + if (env_b.getHeight() > tolerance) + env_b_deflated.inflate(0, -tolerance); + else + env_b_deflated.inflate(-tolerance, 0); + + env_b_inflated.inflate(tolerance, tolerance); - private static boolean linearPathContainsPoint_(MultiPath multipathA, - Point2D pt_b, double tolerance) { - return linearPathIntersectsPoint_(multipathA, pt_b, tolerance) - && !linearPathTouchesPointImpl_(multipathA, pt_b, tolerance); - } + Point2D pt_a = new Point2D(); - private static boolean linearPathTouchesPointImpl_(MultiPath multipathA, - Point2D ptB, double tolerance) { - MultiPoint boundary = (MultiPoint) (multipathA.getBoundary()); - return !multiPointDisjointPointImpl_(boundary, ptB, tolerance, null); - } + for (int i = 0; i < multipoint_a.getPointCount(); i++) { + multipoint_a.getXY(i, pt_a); - // Returns true if the segments of multipathA intersects env_b - private static boolean linearPathIntersectsEnvelope_(MultiPath multipath_a, - Envelope2D env_b, double tolerance, ProgressTracker progress_tracker) { - if (!multipath_a.hasNonLinearSegments()) { - Envelope2D env_b_inflated = new Envelope2D(); - env_b_inflated.setCoords(env_b); - env_b_inflated.inflate(tolerance, tolerance); - MultiPathImpl mimpl_a = (MultiPathImpl) multipath_a._getImpl(); - AttributeStreamOfDbl xy = (AttributeStreamOfDbl) (mimpl_a - .getAttributeStreamRef(VertexDescription.Semantics.POSITION)); - Point2D pt = new Point2D(); - Point2D pt_prev = new Point2D(); - Point2D pt_1 = new Point2D(); - Point2D pt_2 = new Point2D(); - for (int ipath = 0, npath = mimpl_a.getPathCount(); ipath < npath; ipath++) { - boolean b_first = true; - for (int i = mimpl_a.getPathStart(ipath), n = mimpl_a - .getPathEnd(ipath); i < n; i++) { - if (b_first) { - xy.read(2 * i, pt_prev); - b_first = false; - continue; - } + if (!env_b_inflated.contains(pt_a)) + return false; + + if (env_b.getHeight() > tolerance) { + if (pt_a.y > env_b_deflated.ymin + && pt_a.y < env_b_deflated.ymax) + b_interior = true; + } else { + if (pt_a.x > env_b_deflated.xmin + && pt_a.x < env_b_deflated.xmax) + b_interior = true; + } + } + + return b_interior; + } + + // treat as area + + boolean b_interior = false; + + Envelope2D env_b_deflated = new Envelope2D(), env_b_inflated = new Envelope2D(); + env_b_deflated.setCoords(env_b); + env_b_inflated.setCoords(env_b); + env_b_deflated.inflate(-tolerance, -tolerance); + env_b_inflated.inflate(tolerance, tolerance); + + Point2D pt_a = new Point2D(); + + // we loop to find a proper interior intersection (i.e. something inside + // instead of just on the boundary) + for (int i = 0; i < multipoint_a.getPointCount(); i++) { + multipoint_a.getXY(i, pt_a); - xy.read(2 * i, pt); - pt_1.setCoords(pt_prev); - pt_2.setCoords(pt); - if (env_b_inflated.clipLine(pt_1, pt_2) != 0) - return true; + if (!env_b_inflated.contains(pt_a)) + return false; - pt_prev.setCoords(pt); - } - } - } else { - Line line_1 = new Line(env_b.xmin, env_b.ymin, env_b.xmin, - env_b.ymax); - Line line_2 = new Line(env_b.xmin, env_b.ymax, env_b.xmax, - env_b.ymax); - Line line3 = new Line(env_b.xmax, env_b.ymax, env_b.xmax, - env_b.ymin); - Line line4 = new Line(env_b.xmax, env_b.ymin, env_b.xmin, - env_b.ymin); - SegmentIterator iter = multipath_a.querySegmentIterator(); - while (iter.nextPath()) { - while (iter.hasNextSegment()) { - Segment polySeg = iter.nextSegment(); - if (polySeg.isIntersecting(line_1, tolerance)) - return true; - - if (polySeg.isIntersecting(line_2, tolerance)) - return true; - - if (polySeg.isIntersecting(line3, tolerance)) - return true; - - if (polySeg.isIntersecting(line4, tolerance)) - return true; - } - } - } + if (env_b_deflated.containsExclusive(pt_a)) + b_interior = true; + } - return false; - } + return b_interior; + } - // Returns contains, disjoint, or within if the relationship can be - // determined from the rasterized tests. - // When bExtraTestForIntersects is true performs extra tests and can return - // "intersects". - static int tryRasterizedContainsOrDisjoint_(Geometry geom_a, - Geometry geom_b, double tolerance, boolean bExtraTestForIntersects) { - int gtA = geom_a.getType().value(); - int gtB = geom_b.getType().value(); - do { - if (Geometry.isMultiVertex(gtA)) { - MultiVertexGeometryImpl impl = (MultiVertexGeometryImpl) geom_a - ._getImpl(); - GeometryAccelerators accel = impl._getAccelerators(); - if (accel != null) { - RasterizedGeometry2D rgeom = accel.getRasterizedGeometry(); - if (rgeom != null) { - if (gtB == Geometry.GeometryType.Point) { - Point2D ptB = ((Point) geom_b).getXY(); - RasterizedGeometry2D.HitType hit = rgeom - .queryPointInGeometry(ptB.x, ptB.y); - if (hit == RasterizedGeometry2D.HitType.Inside) { - return Relation.contains; - } else if (hit == RasterizedGeometry2D.HitType.Outside) { - return Relation.disjoint; - } - break; - } - Envelope2D env_b = new Envelope2D(); - geom_b.queryEnvelope2D(env_b); - RasterizedGeometry2D.HitType hit = rgeom - .queryEnvelopeInGeometry(env_b); - if (hit == RasterizedGeometry2D.HitType.Inside) { - return Relation.contains; - } else if (hit == RasterizedGeometry2D.HitType.Outside) { - return Relation.disjoint; - } else if (bExtraTestForIntersects - && Geometry.isMultiVertex(gtB)) { - if (checkVerticesForIntersection_( - (MultiVertexGeometryImpl) geom_b._getImpl(), - rgeom)) { - return Relation.intersects; - } - } + // Returns true if multipoint_a contains envelope_b. + private static boolean multiPointContainsEnvelope_(MultiPoint multipoint_a, + Envelope envelope_b, double tolerance, + ProgressTracker progress_tracker) { + Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(); + multipoint_a.queryEnvelope2D(env_a); + envelope_b.queryEnvelope2D(env_b); + + if (!envelopeInfContainsEnvelope_(env_a, env_b, tolerance)) + return false; + + if (env_b.getHeight() > tolerance || env_b.getWidth() > tolerance) + return false; + + Point2D pt_b = envelope_b.getCenterXY(); + return !multiPointDisjointPointImpl_(multipoint_a, pt_b, tolerance, + progress_tracker); + } + + // Returns true if multipoint_a crosses envelope_b. + static boolean multiPointCrossesEnvelope_(MultiPoint multipoint_a, + Envelope envelope_b, double tolerance, + ProgressTracker progress_tracker) { + Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(); + multipoint_a.queryEnvelope2D(env_a); + envelope_b.queryEnvelope2D(env_b); - break; - } - } - } - } while (false); - - do { - if (Geometry.isMultiVertex(gtB)) { - MultiVertexGeometryImpl impl = (MultiVertexGeometryImpl) geom_b - ._getImpl(); - GeometryAccelerators accel = impl._getAccelerators(); - if (accel != null) { - RasterizedGeometry2D rgeom = accel.getRasterizedGeometry(); - if (rgeom != null) { - if (gtA == Geometry.GeometryType.Point) { - Point2D ptA = ((Point) geom_a).getXY(); - RasterizedGeometry2D.HitType hit = rgeom - .queryPointInGeometry(ptA.x, ptA.y); - if (hit == RasterizedGeometry2D.HitType.Inside) { - return Relation.within; - } else if (hit == RasterizedGeometry2D.HitType.Outside) { - return Relation.disjoint; - } - break; - } + if (envelopeInfContainsEnvelope_(env_b, env_a, tolerance)) + return false; + + if (env_b.getHeight() <= tolerance && env_b.getWidth() <= tolerance) + return false; + + if (env_b.getHeight() <= tolerance || env_b.getWidth() <= tolerance) {// treat + // as + // line + Envelope2D env_b_deflated = new Envelope2D(); + Envelope2D env_b_inflated = new Envelope2D(); + env_b_deflated.setCoords(env_b); + + if (env_b.getHeight() > tolerance) + env_b_deflated.inflate(0, -tolerance); + else + env_b_deflated.inflate(-tolerance, 0); + + env_b_inflated.setCoords(env_b); + env_b_inflated.inflate(tolerance, tolerance); + + Point2D pt_a = new Point2D(); + boolean b_interior = false, b_exterior = false; + + for (int i = 0; i < multipoint_a.getPointCount(); i++) { + multipoint_a.getXY(i, pt_a); + + if (!b_interior) { + if (env_b.getHeight() > tolerance) { + if (pt_a.y > env_b_deflated.ymin + && pt_a.y < env_b_deflated.ymax) + b_interior = true; + } else { + if (pt_a.x > env_b_deflated.xmin + && pt_a.x < env_b_deflated.xmax) + b_interior = true; + } + } + + if (!b_exterior && !env_b_inflated.contains(pt_a)) + b_exterior = true; + + if (b_interior && b_exterior) + return true; + } + + return false; + } + + Envelope2D env_b_deflated = new Envelope2D(), env_b_inflated = new Envelope2D(); + env_b_deflated.setCoords(env_b); + env_b_deflated.inflate(-tolerance, -tolerance); + assert (!env_b_deflated.isEmpty()); + + env_b_inflated.setCoords(env_b); + env_b_inflated.inflate(tolerance, tolerance); + + Point2D pt_a = new Point2D(); + boolean b_interior = false, b_exterior = false; + + for (int i = 0; i < multipoint_a.getPointCount(); i++) { + multipoint_a.getXY(i, pt_a); + + if (!b_interior && env_b_deflated.containsExclusive(pt_a)) + b_interior = true; + + if (!b_exterior && !env_b_inflated.contains(pt_a)) + b_exterior = true; + + if (b_interior && b_exterior) + return true; + } + + return false; + } + + // Returns true if pt_a equals pt_b. + private static boolean pointEqualsPoint_(Point2D pt_a, Point2D pt_b, + double tolerance, ProgressTracker progress_tracker) { + if (Point2D.sqrDistance(pt_a, pt_b) <= tolerance * tolerance) + return true; + + return false; + } + + // Returns true if pt_a is disjoint from pt_b. + private static boolean pointDisjointPoint_(Point2D pt_a, Point2D pt_b, + double tolerance, ProgressTracker progress_tracker) { + if (Point2D.sqrDistance(pt_a, pt_b) > tolerance * tolerance) + return true; + + return false; + } + + // Returns true if pt_a contains pt_b. + private static boolean pointContainsPoint_(Point2D pt_a, Point2D pt_b, + double tolerance, ProgressTracker progress_tracker) { + return pointEqualsPoint_(pt_a, pt_b, tolerance, progress_tracker); + } + + // Returns true if pt_a equals enve_b. + private static boolean pointEqualsEnvelope_(Point2D pt_a, Envelope2D env_b, + double tolerance, ProgressTracker progress_tracker) { + Envelope2D env_a = new Envelope2D(); + env_a.setCoords(pt_a); + return envelopeEqualsEnvelope_(env_a, env_b, tolerance, + progress_tracker); + } + + // Returns true if pt_a is disjoint from env_b. + static boolean pointDisjointEnvelope_(Point2D pt_a, Envelope2D env_b, + double tolerance, ProgressTracker progress_tracker) { + Envelope2D env_b_inflated = new Envelope2D(); + env_b_inflated.setCoords(env_b); + env_b_inflated.inflate(tolerance, tolerance); + return !env_b_inflated.contains(pt_a); + } + + // Returns true if pt_a touches env_b. + private static boolean pointTouchesEnvelope_(Point2D pt_a, + Envelope2D env_b, double tolerance, ProgressTracker progress_tracker) { + if (env_b.getHeight() <= tolerance && env_b.getWidth() <= tolerance) + return false; // when treates as a point, points cannot touch points + + Envelope2D env_b_inflated = new Envelope2D(), env_b_deflated = new Envelope2D(); + + env_b_inflated.setCoords(env_b); + env_b_inflated.inflate(tolerance, tolerance); + + if (!env_b_inflated.contains(pt_a)) + return false; + + if (env_b.getHeight() <= tolerance || env_b.getWidth() <= tolerance) { + env_b_deflated.setCoords(env_b); + + if (env_b.getHeight() > tolerance) + env_b_deflated.inflate(0, -tolerance); + else + env_b_deflated.inflate(-tolerance, 0); + + if (env_b.getHeight() > tolerance) { + if (pt_a.y > env_b_deflated.ymin + && pt_a.y < env_b_deflated.ymax) + return false; + } else { + if (pt_a.x > env_b_deflated.xmin + && pt_a.x < env_b_deflated.xmax) + return false; + } + + return true; + } + + env_b_deflated.setCoords(env_b); + env_b_deflated.inflate(-tolerance, -tolerance); + + if (env_b_deflated.containsExclusive(pt_a)) + return false; + + return true; + } + + // Returns true if pt_a is within env_b. + private static boolean pointWithinEnvelope_(Point2D pt_a, Envelope2D env_b, + double tolerance, ProgressTracker progress_tracker) { + if (env_b.getHeight() <= tolerance && env_b.getWidth() <= tolerance) { + // assert(env_b_inflated.contains(pt_a)); // should contain if we + // got to here (i.e. not disjoint) + return true; + } + + if (env_b.getHeight() <= tolerance || env_b.getWidth() <= tolerance) {// treat + // as + // line + Envelope2D env_b_deflated = new Envelope2D(); + env_b_deflated.setCoords(env_b); + + if (env_b.getHeight() > tolerance) + env_b_deflated.inflate(0, -tolerance); + else + env_b_deflated.inflate(-tolerance, 0); + + boolean b_interior = false; + + if (env_b.getHeight() > tolerance) { + if (pt_a.y > env_b_deflated.ymin + && pt_a.y < env_b_deflated.ymax) + b_interior = true; + } else { + if (pt_a.x > env_b_deflated.xmin + && pt_a.x < env_b_deflated.xmax) + b_interior = true; + } + + return b_interior; + } + + // treat as area + + Envelope2D env_b_deflated = new Envelope2D(); + env_b_deflated.setCoords(env_b); + env_b_deflated.inflate(-tolerance, -tolerance); + return env_b_deflated.containsExclusive(pt_a); + } + + // Returns true if pt_a contains env_b. + private static boolean pointContainsEnvelope_(Point2D pt_a, + Envelope2D env_b, double tolerance, ProgressTracker progress_tracker) { + return pointEqualsEnvelope_(pt_a, env_b, tolerance, progress_tracker); + } + + // Returns true if env_a equals env_b. + private static boolean envelopeEqualsEnvelope_(Envelope2D env_a, + Envelope2D env_b, double tolerance, ProgressTracker progress_tracker) { + return envelopeInfContainsEnvelope_(env_a, env_b, tolerance) + && envelopeInfContainsEnvelope_(env_b, env_a, tolerance); + } + + // Returns true if env_a is disjoint from env_b. + static boolean envelopeDisjointEnvelope_(Envelope2D env_a, + Envelope2D env_b, double tolerance, ProgressTracker progress_tracker) { + Envelope2D env_b_inflated = new Envelope2D(); + env_b_inflated.setCoords(env_b); + env_b_inflated.inflate(tolerance, tolerance); + return !env_a.isIntersecting(env_b_inflated); + } + + // Returns true if env_a touches env_b. + private static boolean envelopeTouchesEnvelope_(Envelope2D env_a, + Envelope2D env_b, double tolerance, ProgressTracker progress_tracker) { + if (env_a.getHeight() <= tolerance && env_a.getWidth() <= tolerance) {// treat + // env_a + // as + // point + Point2D pt_a = env_a.getCenter(); + return pointTouchesEnvelope_(pt_a, env_b, tolerance, + progress_tracker); + } + + if (env_b.getHeight() <= tolerance && env_b.getWidth() <= tolerance) {// treat + // env_b + // as + // point + Point2D pt_b = env_b.getCenter(); + return pointTouchesEnvelope_(pt_b, env_a, tolerance, + progress_tracker); + } + + Envelope2D _env_a; + Envelope2D _env_b; + + if (env_a.getHeight() > tolerance + && env_a.getWidth() > tolerance + && (env_b.getHeight() <= tolerance || env_b.getWidth() <= tolerance)) { + // swap a and b + _env_a = env_b; + _env_b = env_a; + } else { + _env_a = env_a; + _env_b = env_b; + } + + if (_env_a.getHeight() <= tolerance || _env_a.getWidth() <= tolerance) {// treat + // env_a + // as + // line + + if (_env_b.getHeight() <= tolerance + || _env_b.getWidth() <= tolerance) {// treat env_b as line + + Line line_a = new Line(), line_b = new Line(); + double[] scalars_a = new double[2]; + double[] scalars_b = new double[2]; + Point2D pt = new Point2D(); + _env_a.queryLowerLeft(pt); + line_a.setStartXY(pt); + _env_a.queryUpperRight(pt); + line_a.setEndXY(pt); + _env_b.queryLowerLeft(pt); + line_b.setStartXY(pt); + _env_b.queryUpperRight(pt); + line_b.setEndXY(pt); + + line_a.intersect(line_b, null, scalars_a, scalars_b, tolerance); + int count = line_a.intersect(line_b, null, null, null, + tolerance); + + if (count != 1) + return false; + + return scalars_a[0] == 0.0 || scalars_a[1] == 1.0 + || scalars_b[0] == 0.0 || scalars_b[1] == 1.0; + } + + // treat env_b as area + + Envelope2D env_b_deflated = new Envelope2D(), env_inter = new Envelope2D(); + env_b_deflated.setCoords(_env_b); + env_b_deflated.inflate(-tolerance, -tolerance); + env_inter.setCoords(env_b_deflated); + env_inter.intersect(_env_a); + + if (!env_inter.isEmpty() + && (env_inter.getHeight() > tolerance || env_inter + .getWidth() > tolerance)) + return false; + + assert (!envelopeDisjointEnvelope_(_env_a, _env_b, tolerance, + progress_tracker)); + return true; // we already know they intersect within a tolerance + } + + Envelope2D env_inter = new Envelope2D(); + env_inter.setCoords(_env_a); + env_inter.intersect(_env_b); + + if (!env_inter.isEmpty() && env_inter.getHeight() > tolerance + && env_inter.getWidth() > tolerance) + return false; + + return true; // we already know they intersect within a tolerance + } + + // Returns true if env_a overlaps env_b. + private static boolean envelopeOverlapsEnvelope_(Envelope2D env_a, + Envelope2D env_b, double tolerance, ProgressTracker progress_tracker) { + if (envelopeInfContainsEnvelope_(env_a, env_b, tolerance) + || envelopeInfContainsEnvelope_(env_b, env_a, tolerance)) + return false; + + if (env_a.getHeight() <= tolerance && env_a.getWidth() <= tolerance) + return false; // points cannot overlap + + if (env_b.getHeight() <= tolerance && env_b.getWidth() <= tolerance) + return false; // points cannot overlap + + if (env_a.getHeight() <= tolerance || env_a.getWidth() <= tolerance) {// treat + // env_a + // as + // a + // line + + if (env_b.getHeight() > tolerance && env_b.getWidth() > tolerance) + return false; // lines cannot overlap areas + + // treat both as lines + + Line line_a = new Line(), line_b = new Line(); + double[] scalars_a = new double[2]; + double[] scalars_b = new double[2]; + Point2D pt = new Point2D(); + env_a.queryLowerLeft(pt); + line_a.setStartXY(pt); + env_a.queryUpperRight(pt); + line_a.setEndXY(pt); + env_b.queryLowerLeft(pt); + line_b.setStartXY(pt); + env_b.queryUpperRight(pt); + line_b.setEndXY(pt); + + line_a.intersect(line_b, null, scalars_a, scalars_b, tolerance); + int count = line_a.intersect(line_b, null, null, null, tolerance); + + if (count != 2) + return false; + + return (scalars_a[0] > 0.0 || scalars_a[1] < 1.0) + && (scalars_b[0] > 0.0 || scalars_b[1] < 1.0); + } + + if (env_b.getHeight() <= tolerance || env_b.getWidth() <= tolerance) + return false; // lines cannot overlap areas + + // treat both as areas + + Envelope2D env_inter = new Envelope2D(); + env_inter.setCoords(env_a); + env_inter.intersect(env_b); + + if (env_inter.isEmpty()) + return false; + + if (env_inter.getHeight() <= tolerance + || env_inter.getWidth() <= tolerance) + return false; // not an area + + assert (!envelopeInfContainsEnvelope_(env_inter, env_a, tolerance) && !envelopeInfContainsEnvelope_( + env_inter, env_b, tolerance)); + + return true; + } + + // Returns true if env_a contains env_b. + private static boolean envelopeContainsEnvelope_(Envelope2D env_a, + Envelope2D env_b, double tolerance, ProgressTracker progress_tracker) { + if (!envelopeInfContainsEnvelope_(env_a, env_b, tolerance)) + return false; + + if (env_a.getHeight() <= tolerance && env_a.getWidth() <= tolerance) { + Point2D pt_a = env_a.getCenter(); + return pointWithinEnvelope_(pt_a, env_b, tolerance, + progress_tracker); + } + + if (env_b.getHeight() <= tolerance && env_b.getWidth() <= tolerance) { + Point2D pt_b = env_b.getCenter(); + return pointWithinEnvelope_(pt_b, env_a, tolerance, + progress_tracker); + } + + if (env_a.getHeight() <= tolerance || env_a.getWidth() <= tolerance) + return envelopeInfContainsEnvelope_(env_a, env_b, tolerance); // treat + // env_b + // as + // line + + // treat env_a as area + + if (env_b.getHeight() <= tolerance || env_b.getWidth() <= tolerance) {// treat + // env_b + // as + // line + + Envelope2D env_a_deflated = new Envelope2D(); + env_a_deflated.setCoords(env_a); + env_a_deflated.inflate(-tolerance, -tolerance); + + if (env_a_deflated.containsExclusive(env_b)) + return true; + + Envelope2D env_inter = new Envelope2D(); + env_inter.setCoords(env_a_deflated); + env_inter.intersect(env_b); + + if (env_inter.isEmpty() + || (env_inter.getHeight() <= tolerance && env_inter + .getWidth() <= tolerance)) + return false; + + return true; + } + + return envelopeInfContainsEnvelope_(env_a, env_b, tolerance); + } + + // Returns true if env_a crosses env_b. + private static boolean envelopeCrossesEnvelope_(Envelope2D env_a, + Envelope2D env_b, double tolerance, ProgressTracker progress_tracker) { + if (envelopeInfContainsEnvelope_(env_a, env_b, tolerance) + || envelopeInfContainsEnvelope_(env_b, env_a, tolerance)) + return false; + + if (env_a.getHeight() <= tolerance && env_a.getWidth() <= tolerance) + return false; // points cannot cross + + if (env_b.getHeight() <= tolerance && env_b.getWidth() <= tolerance) + return false; // points cannot cross + + if (env_b.getHeight() > tolerance && env_b.getWidth() > tolerance) { + if (env_a.getHeight() > tolerance && env_a.getWidth() > tolerance) + return false; // areas cannot cross + } + + Envelope2D _env_a; + Envelope2D _env_b; + + if (env_a.getHeight() > tolerance && env_a.getWidth() > tolerance) { + // swap b and a + _env_a = env_b; + _env_b = env_a; + } else { + _env_a = env_a; + _env_b = env_b; + } + + if (_env_b.getHeight() > tolerance && _env_b.getWidth() > tolerance) {// treat + // env_b + // as + // an + // area + // (env_a + // as + // a + // line); + + Envelope2D env_inter = new Envelope2D(), env_b_deflated = new Envelope2D(); + env_b_deflated.setCoords(_env_b); + env_b_deflated.inflate(-tolerance, -tolerance); + env_inter.setCoords(env_b_deflated); + env_inter.intersect(_env_a); + + if (env_inter.isEmpty()) + return false; + + if (env_inter.getHeight() <= tolerance + && env_inter.getWidth() <= tolerance) + return false; // not a line + + assert (!envelopeInfContainsEnvelope_(env_inter, _env_a, tolerance)); + return true; + } + + // treat both as lines + + Line line_a = new Line(), line_b = new Line(); + double[] scalars_a = new double[2]; + double[] scalars_b = new double[2]; + Point2D pt = new Point2D(); + _env_a.queryLowerLeft(pt); + line_a.setStartXY(pt); + _env_a.queryUpperRight(pt); + line_a.setEndXY(pt); + _env_b.queryLowerLeft(pt); + line_b.setStartXY(pt); + _env_b.queryUpperRight(pt); + line_b.setEndXY(pt); + + line_a.intersect(line_b, null, scalars_a, scalars_b, tolerance); + int count = line_a.intersect(line_b, null, null, null, tolerance); + + if (count != 1) + return false; + + return scalars_a[0] > 0.0 && scalars_a[1] < 1.0 && scalars_b[0] > 0.0 + && scalars_b[1] < 1.0; + } + + // Returns true if polygon_a is disjoint from multipath_b. + private static boolean polygonDisjointMultiPath_(Polygon polygon_a, + MultiPath multipath_b, double tolerance, + ProgressTracker progress_tracker) { + Point2D pt_a, pt_b; + Envelope2D env_a_inf = new Envelope2D(), env_b_inf = new Envelope2D(); - Envelope2D env_a = new Envelope2D(); - geom_a.queryEnvelope2D(env_a); - RasterizedGeometry2D.HitType hit = rgeom - .queryEnvelopeInGeometry(env_a); - if (hit == RasterizedGeometry2D.HitType.Inside) { - return Relation.within; - } else if (hit == RasterizedGeometry2D.HitType.Outside) { - return Relation.disjoint; - } else if (bExtraTestForIntersects - && Geometry.isMultiVertex(gtA)) { - if (checkVerticesForIntersection_( - (MultiVertexGeometryImpl) geom_a._getImpl(), - rgeom)) { - return Relation.intersects; - } - } + MultiPathImpl multi_path_impl_a = (MultiPathImpl)polygon_a._getImpl(); + MultiPathImpl multi_path_impl_b = (MultiPathImpl)multipath_b._getImpl(); - break; - } - } - } - } while (false); + PairwiseIntersectorImpl intersector = new PairwiseIntersectorImpl(multi_path_impl_a, multi_path_impl_b, tolerance, true); - return Relation.unknown; - } + if (!intersector.next()) + return true; // no rings intersect - // Returns true if intersects and false if nothing can be determined. - private static boolean checkVerticesForIntersection_( - MultiVertexGeometryImpl geom, RasterizedGeometry2D rgeom) { - // Do a quick raster test for each point. If any point is inside, then - // there is an intersection. - int pointCount = geom.getPointCount(); - Point2D pt = new Point2D(); - for (int ipoint = 0; ipoint < pointCount; ipoint++) { - geom.getXY(ipoint, pt); - RasterizedGeometry2D.HitType hit = rgeom.queryPointInGeometry(pt.x, - pt.y); - if (hit == RasterizedGeometry2D.HitType.Inside) { - return true; - } - } + boolean b_intersects = linearPathIntersectsLinearPath_(polygon_a, multipath_b, tolerance); - return false; - } + if (b_intersects) + return false; - private static boolean polygonTouchesPolygonImpl_(Polygon polygon_a, - Polygon polygon_b, double tolerance, ProgressTracker progressTracker) { - MultiPathImpl polygon_impl_a = (MultiPathImpl) polygon_a._getImpl(); - MultiPathImpl polygon_impl_b = (MultiPathImpl) polygon_b._getImpl(); + Polygon pa = null; + Polygon p_polygon_a = polygon_a; - // double geom_tolerance; - boolean b_geometries_simple = polygon_impl_a.getIsSimple(0.0) >= 1 - && polygon_impl_b.getIsSimple(0.0) >= 1; + Polygon pb = null; + Polygon p_polygon_b = null; - SegmentIteratorImpl segIterA = polygon_impl_a.querySegmentIterator(); - SegmentIteratorImpl segIterB = polygon_impl_b.querySegmentIterator(); - double[] scalarsA = new double[2]; - double[] scalarsB = new double[2]; + if (multipath_b.getType().value() == Geometry.GeometryType.Polygon) + p_polygon_b = (Polygon)multipath_b; - PairwiseIntersectorImpl intersector = new PairwiseIntersectorImpl( - polygon_impl_a, polygon_impl_b, tolerance, false); + boolean b_checked_polygon_a_quad_tree = false; + boolean b_checked_polygon_b_quad_tree = false; - boolean b_boundaries_intersect = false; + do + { + int path_a = intersector.getRedElement(); + int path_b = intersector.getBlueElement(); - while (intersector.next()) { - int vertex_a = intersector.getRedElement(); - int vertex_b = intersector.getBlueElement(); + pt_b = multipath_b.getXY(multipath_b.getPathStart(path_b)); + env_a_inf.setCoords(intersector.getRedEnvelope()); + env_a_inf.inflate(tolerance, tolerance); - segIterA.resetToVertex(vertex_a); - segIterB.resetToVertex(vertex_b); - Segment segmentA = segIterA.nextSegment(); - Segment segmentB = segIterB.nextSegment(); + if (env_a_inf.contains(pt_b)) + { + PolygonUtils.PiPResult result = PolygonUtils.isPointInPolygon2D(p_polygon_a, pt_b, 0.0); + + if (result != PolygonUtils.PiPResult.PiPOutside) + return false; + } - int result = segmentB.intersect(segmentA, null, scalarsB, scalarsA, - tolerance); + if (multipath_b.getType().value() == Geometry.GeometryType.Polygon) + { + pt_a = polygon_a.getXY(polygon_a.getPathStart(path_a)); + env_b_inf.setCoords(intersector.getBlueEnvelope()); + env_b_inf.inflate(tolerance, tolerance); - if (result == 2) { - double scalar_a_0 = scalarsA[0]; - double scalar_a_1 = scalarsA[1]; - double length_a = segmentA.calculateLength2D(); + if (env_b_inf.contains(pt_a)) + { + PolygonUtils.PiPResult result = PolygonUtils.isPointInPolygon2D(p_polygon_b, pt_a, 0.0); - if (b_geometries_simple - && (scalar_a_1 - scalar_a_0) * length_a > tolerance) { - // If the line segments overlap along the same direction, - // then we have an Interior-Interior intersection - return false; + if (result != PolygonUtils.PiPResult.PiPOutside) + return false; } + } - b_boundaries_intersect = true; - } else if (result != 0) { - double scalar_a_0 = scalarsA[0]; - double scalar_b_0 = scalarsB[0]; - - if (scalar_a_0 > 0.0 && scalar_a_0 < 1.0 && scalar_b_0 > 0.0 - && scalar_b_0 < 1.0) { - return false; + if (!b_checked_polygon_a_quad_tree) { + if (PointInPolygonHelper.quadTreeWillHelp(polygon_a, multipath_b.getPathCount() - 1) && (multi_path_impl_a._getAccelerators() == null || multi_path_impl_a._getAccelerators().getQuadTree() == null)) { + pa = new Polygon(); + polygon_a.copyTo(pa); + ((MultiPathImpl) pa._getImpl())._buildQuadTreeAccelerator(Geometry.GeometryAccelerationDegree.enumMedium); + p_polygon_a = pa; + } else { + p_polygon_a = polygon_a; } - b_boundaries_intersect = true; + b_checked_polygon_a_quad_tree = true; } - } - if (!b_boundaries_intersect) { - return false; - } + if (multipath_b.getType().value() == Geometry.GeometryType.Polygon) + { + if (!b_checked_polygon_b_quad_tree) { + Polygon polygon_b = (Polygon) multipath_b; + if (PointInPolygonHelper.quadTreeWillHelp(polygon_b, polygon_a.getPathCount() - 1) && (multi_path_impl_b._getAccelerators() == null || multi_path_impl_b._getAccelerators().getQuadTree() == null)) { + pb = new Polygon(); + polygon_b.copyTo(pb); + ((MultiPathImpl) pb._getImpl())._buildQuadTreeAccelerator(Geometry.GeometryAccelerationDegree.enumMedium); + p_polygon_b = pb; + } else { + p_polygon_b = (Polygon) multipath_b; + } - Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(), envInter = new Envelope2D(); - polygon_a.queryEnvelope2D(env_a); - polygon_b.queryEnvelope2D(env_b); - env_a.inflate(1000.0 * tolerance, 1000.0 * tolerance); - env_b.inflate(1000.0 * tolerance, 1000.0 * tolerance); - envInter.setCoords(env_a); - envInter.intersect(env_b); - - Polygon _polygonA; - Polygon _polygonB; - - if (polygon_a.getPointCount() > 10) { - _polygonA = (Polygon) (Clipper.clip(polygon_a, envInter, tolerance, - 0.0)); - if (_polygonA.isEmpty()) { - return false; + b_checked_polygon_b_quad_tree = true; + } } - } else { - _polygonA = polygon_a; - } - if (polygon_b.getPointCount() > 10) { - _polygonB = (Polygon) (Clipper.clip(polygon_b, envInter, tolerance, - 0.0)); - if (_polygonB.isEmpty()) { - return false; - } - } else { - _polygonB = polygon_b; - } + } while (intersector.next()); - // We just need to determine whether interior_interior is false - String scl = "F********"; - boolean bRelation = RelationalOperationsMatrix.polygonRelatePolygon_( - _polygonA, _polygonB, tolerance, scl, progressTracker); + return true; + } + + // Returns true if env_a inflated contains env_b. + private static boolean envelopeInfContainsEnvelope_(Envelope2D env_a, + Envelope2D env_b, double tolerance) { + Envelope2D env_a_inflated = new Envelope2D(); + env_a_inflated.setCoords(env_a); + env_a_inflated.inflate(tolerance, tolerance); + return env_a_inflated.contains(env_b); + } + + // Returns true if a coordinate of envelope A is outside of envelope B. + private static boolean interiorEnvExteriorEnv_(Envelope2D env_a, + Envelope2D env_b, double tolerance) { + Envelope2D envBInflated = new Envelope2D(); + envBInflated.setCoords(env_b); + envBInflated.inflate(tolerance, tolerance); + Point2D pt = new Point2D(); + + env_a.queryLowerLeft(pt); + if (!envBInflated.contains(pt)) + return true; + + env_a.queryLowerRight(pt); + if (!envBInflated.contains(pt)) + return true; + + env_a.queryUpperLeft(pt); + if (!envBInflated.contains(pt)) + return true; + + env_a.queryUpperRight(pt); + if (!envBInflated.contains(pt)) + return true; + + assert (envBInflated.contains(env_a)); + return false; + } + + // Returns true if the points in each path of multipathA are the same as + // those in multipathB, within a tolerance, and in the same order. + private static boolean multiPathExactlyEqualsMultiPath_( + MultiPath multipathA, MultiPath multipathB, double tolerance, + ProgressTracker progress_tracker) { + if (multipathA.getPathCount() != multipathB.getPathCount() + || multipathA.getPointCount() != multipathB.getPointCount()) + return false; + + Point2D ptA = new Point2D(), ptB = new Point2D(); + boolean bAllPointsEqual = true; + double tolerance_sq = tolerance * tolerance; + + for (int ipath = 0; ipath < multipathA.getPathCount(); ipath++) { + if (multipathA.getPathEnd(ipath) != multipathB.getPathEnd(ipath)) { + bAllPointsEqual = false; + break; + } + + for (int i = multipathA.getPathStart(ipath); i < multipathB + .getPathEnd(ipath); i++) { + multipathA.getXY(i, ptA); + multipathB.getXY(i, ptB); + + if (Point2D.sqrDistance(ptA, ptB) > tolerance_sq) { + bAllPointsEqual = false; + break; + } + } + + if (!bAllPointsEqual) + break; + } + + if (!bAllPointsEqual) + return false; + + return true; + } + + // Returns true if the points of multipoint_a are the same as those in + // multipoint_b, within a tolerance, and in the same order. + private static boolean multiPointExactlyEqualsMultiPoint_( + MultiPoint multipoint_a, MultiPoint multipoint_b, double tolerance, + ProgressTracker progress_tracker) { + if (multipoint_a.getPointCount() != multipoint_b.getPointCount()) + return false; + + Point2D ptA = new Point2D(), ptB = new Point2D(); + boolean bAllPointsEqual = true; + double tolerance_sq = tolerance * tolerance; + + for (int i = 0; i < multipoint_a.getPointCount(); i++) { + multipoint_a.getXY(i, ptA); + multipoint_b.getXY(i, ptB); + + if (Point2D.sqrDistance(ptA, ptB) > tolerance_sq) { + bAllPointsEqual = false; + break; + } + } + + if (!bAllPointsEqual) + return false; + + return true; + } + + // By default this will perform the within operation if bEquals is false. + // Otherwise it will do equals. + private static boolean multiPointCoverageMultiPoint_( + MultiPoint _multipointA, MultiPoint _multipointB, double tolerance, + boolean bPerformWithin, boolean bPerformEquals, + boolean bPerformOverlaps, ProgressTracker progress_tracker) { + boolean bPerformContains = false; + MultiPoint multipoint_a; + MultiPoint multipoint_b; + + if (_multipointA.getPointCount() > _multipointB.getPointCount()) { + if (bPerformWithin) { + bPerformWithin = false; + bPerformContains = true; + } + + multipoint_a = _multipointB; + multipoint_b = _multipointA; + } else { + multipoint_a = _multipointA; + multipoint_b = _multipointB; + } + + AttributeStreamOfInt8 contained = null; + + if (bPerformEquals || bPerformOverlaps || bPerformContains) { + contained = new AttributeStreamOfInt8(multipoint_b.getPointCount()); + + for (int i = 0; i < multipoint_b.getPointCount(); i++) + contained.write(i, (byte) 0); + } + + Envelope2D env_a = new Envelope2D(); + Envelope2D env_b = new Envelope2D(); + Envelope2D envInter = new Envelope2D(); + multipoint_a.queryEnvelope2D(env_a); + multipoint_b.queryEnvelope2D(env_b); + env_a.inflate(tolerance, tolerance); + env_b.inflate(tolerance, tolerance); + envInter.setCoords(env_a); + envInter.intersect(env_b); + + Point2D ptA = new Point2D(); + Point2D ptB = new Point2D(); + + boolean bWithin = true; // starts off true by default + + QuadTreeImpl quadTreeB = InternalUtils.buildQuadTree( + (MultiPointImpl) (multipoint_b._getImpl()), envInter); + QuadTreeImpl.QuadTreeIteratorImpl qtIterB = quadTreeB.getIterator(); + double tolerance_sq = tolerance * tolerance; + + for (int vertex_a = 0; vertex_a < multipoint_a.getPointCount(); vertex_a++) { + multipoint_a.getXY(vertex_a, ptA); + + if (!envInter.contains(ptA)) { + if (bPerformEquals || bPerformWithin) + return false; + else { + bWithin = false; + continue; + } + } + + boolean bPtACovered = false; + env_a.setCoords(ptA.x, ptA.y, ptA.x, ptA.y); + qtIterB.resetIterator(env_a, tolerance); + for (int elementHandleB = qtIterB.next(); elementHandleB != -1; elementHandleB = qtIterB + .next()) { + int vertex_b = quadTreeB.getElement(elementHandleB); + multipoint_b.getXY(vertex_b, ptB); + + if (Point2D.sqrDistance(ptA, ptB) <= tolerance_sq) { + if (bPerformEquals || bPerformOverlaps || bPerformContains) + contained.write(vertex_b, (byte) 1); + + bPtACovered = true; + + if (bPerformWithin) + break; + } + } + + if (!bPtACovered) { + bWithin = false; + + if (bPerformEquals || bPerformWithin) + return false; + } + } + + if (bPerformOverlaps && bWithin) + return false; + + if (bPerformWithin) + return true; + + for (int i = 0; i < multipoint_b.getPointCount(); i++) { + if (contained.read(i) == 1) { + if (bPerformOverlaps) + return true; + } else { + if (bPerformEquals || bPerformContains) + return false; + } + } + + if (bPerformOverlaps) + return false; + + return true; + } + + // Returns true if multipoint_a intersects multipoint_b. + private static boolean multiPointIntersectsMultiPoint_( + MultiPoint _multipointA, MultiPoint _multipointB, double tolerance, + ProgressTracker progress_tracker) { + MultiPoint multipoint_a; + MultiPoint multipoint_b; + + if (_multipointA.getPointCount() > _multipointB.getPointCount()) { + multipoint_a = _multipointB; + multipoint_b = _multipointA; + } else { + multipoint_a = _multipointA; + multipoint_b = _multipointB; + } + + Envelope2D env_a = new Envelope2D(); + Envelope2D env_b = new Envelope2D(); + Envelope2D envInter = new Envelope2D(); + multipoint_a.queryEnvelope2D(env_a); + multipoint_b.queryEnvelope2D(env_b); + env_a.inflate(tolerance, tolerance); + env_b.inflate(tolerance, tolerance); + envInter.setCoords(env_a); + envInter.intersect(env_b); + + Point2D ptA = new Point2D(); + Point2D ptB = new Point2D(); + double tolerance_sq = tolerance * tolerance; + + QuadTreeImpl quadTreeB = InternalUtils.buildQuadTree( + (MultiPointImpl) (multipoint_b._getImpl()), envInter); + QuadTreeImpl.QuadTreeIteratorImpl qtIterB = quadTreeB.getIterator(); + + for (int vertex_a = 0; vertex_a < multipoint_a.getPointCount(); vertex_a++) { + multipoint_a.getXY(vertex_a, ptA); + + if (!envInter.contains(ptA)) + continue; + + env_a.setCoords(ptA.x, ptA.y, ptA.x, ptA.y); + qtIterB.resetIterator(env_a, tolerance); + + for (int elementHandleB = qtIterB.next(); elementHandleB != -1; elementHandleB = qtIterB + .next()) { + int vertex_b = quadTreeB.getElement(elementHandleB); + multipoint_b.getXY(vertex_b, ptB); + + if (Point2D.sqrDistance(ptA, ptB) <= tolerance_sq) + return true; + } + } + + return false; + } + + // Returns true if multipathA equals multipathB. + private static boolean linearPathEqualsLinearPath_(MultiPath multipathA, + MultiPath multipathB, double tolerance, boolean bEnforceOrientation) { + return linearPathWithinLinearPath_(multipathA, multipathB, tolerance, bEnforceOrientation) + && linearPathWithinLinearPath_(multipathB, multipathA, + tolerance, bEnforceOrientation); + } + + // Returns true if the segments of multipathA are within the segments of + // multipathB. + private static boolean linearPathWithinLinearPath_(MultiPath multipathA, + MultiPath multipathB, double tolerance, boolean bEnforceOrientation) { + boolean bWithin = true; + double[] scalarsA = new double[2]; + double[] scalarsB = new double[2]; + + int ievent = 0; + AttributeStreamOfInt32 eventIndices = new AttributeStreamOfInt32(0); + RelationalOperations relOps = new RelationalOperations(); + OverlapComparer overlapComparer = new OverlapComparer(relOps); + OverlapEvent overlapEvent; + + Envelope2D env_a = new Envelope2D(); + Envelope2D env_b = new Envelope2D(); + Envelope2D envInter = new Envelope2D(); + multipathA.queryEnvelope2D(env_a); + multipathB.queryEnvelope2D(env_b); + env_a.inflate(tolerance, tolerance); + env_b.inflate(tolerance, tolerance); + envInter.setCoords(env_a); + envInter.intersect(env_b); + + SegmentIteratorImpl segIterA = ((MultiPathImpl) multipathA._getImpl()) + .querySegmentIterator(); + SegmentIteratorImpl segIterB = ((MultiPathImpl) multipathB._getImpl()) + .querySegmentIterator(); + + QuadTreeImpl qtB = null; + QuadTreeImpl quadTreeB = null; + QuadTreeImpl quadTreePathsB = null; - return bRelation; - } + GeometryAccelerators accel = ((MultiPathImpl) multipathB._getImpl()) + ._getAccelerators(); - private static boolean polygonOverlapsPolygonImpl_(Polygon polygon_a, - Polygon polygon_b, double tolerance, ProgressTracker progressTracker) { - MultiPathImpl polygon_impl_a = (MultiPathImpl) polygon_a._getImpl(); - MultiPathImpl polygon_impl_b = (MultiPathImpl) polygon_b._getImpl(); + if (accel != null) { + quadTreeB = accel.getQuadTree(); + quadTreePathsB = accel.getQuadTreeForPaths(); + if (quadTreeB == null) { + qtB = InternalUtils.buildQuadTree( + (MultiPathImpl) multipathB._getImpl(), envInter); + quadTreeB = qtB; + } + } else { + qtB = InternalUtils.buildQuadTree( + (MultiPathImpl) multipathB._getImpl(), envInter); + quadTreeB = qtB; + } + + QuadTreeImpl.QuadTreeIteratorImpl qtIterB = quadTreeB.getIterator(); - // double geom_tolerance; - boolean b_geometries_simple = polygon_impl_a.getIsSimple(0.0) >= 1 - && polygon_impl_b.getIsSimple(0.0) >= 1; + QuadTreeImpl.QuadTreeIteratorImpl qtIterPathsB = null; + if (quadTreePathsB != null) + qtIterPathsB = quadTreePathsB.getIterator(); - Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(), envInter = new Envelope2D(); - polygon_a.queryEnvelope2D(env_a); - polygon_b.queryEnvelope2D(env_b); + while (segIterA.nextPath()) { + while (segIterA.hasNextSegment()) { + boolean bStringOfSegmentAsCovered = false; - boolean bInteriorIntersectionKnown = false; + Segment segmentA = segIterA.nextSegment(); + segmentA.queryEnvelope2D(env_a); - boolean bIntAExtB = interiorEnvExteriorEnv_(env_a, env_b, tolerance); - boolean bExtAIntB = interiorEnvExteriorEnv_(env_b, env_a, tolerance); + if (!env_a.isIntersecting(envInter)) { + return false; // bWithin = false + } - SegmentIteratorImpl segIterA = polygon_impl_a.querySegmentIterator(); - SegmentIteratorImpl segIterB = polygon_impl_b.querySegmentIterator(); - double[] scalarsA = new double[2]; - double[] scalarsB = new double[2]; + if (qtIterPathsB != null) { + qtIterPathsB.resetIterator(env_a, tolerance); - PairwiseIntersectorImpl intersector = new PairwiseIntersectorImpl( - polygon_impl_a, polygon_impl_b, tolerance, false); + if (qtIterPathsB.next() == -1) { + bWithin = false; + return false; + } + } - while (intersector.next()) { - int vertex_a = intersector.getRedElement(); - int vertex_b = intersector.getBlueElement(); + double lengthA = segmentA.calculateLength2D(); + + qtIterB.resetIterator(segmentA, tolerance); + + for (int elementHandleB = qtIterB.next(); elementHandleB != -1; elementHandleB = qtIterB + .next()) { + int vertex_b = quadTreeB.getElement(elementHandleB); + segIterB.resetToVertex(vertex_b); + Segment segmentB = segIterB.nextSegment(); + + int result = segmentA.intersect(segmentB, null, scalarsA, + scalarsB, tolerance); + + if (result == 2 && (!bEnforceOrientation || scalarsB[0] <= scalarsB[1])) { + double scalar_a_0 = scalarsA[0]; + double scalar_a_1 = scalarsA[1]; + double scalar_b_0 = scalarsB[0]; + double scalar_b_1 = scalarsB[1]; + + // Performance enhancement for nice cases where + // localization occurs. Increment segIterA as far as we + // can while the current segmentA is covered. + if (scalar_a_0 * lengthA <= tolerance + && (1.0 - scalar_a_1) * lengthA <= tolerance) { + bStringOfSegmentAsCovered = true; + + ievent = 0; + eventIndices.resize(0); + relOps.m_overlap_events.clear(); + + int ivertex_a = segIterA.getStartPointIndex(); + boolean bSegmentACovered = true; + + while (bSegmentACovered) {// keep going while the + // current segmentA is + // covered. + if (segIterA.hasNextSegment()) { + segmentA = segIterA.nextSegment(); + lengthA = segmentA.calculateLength2D(); + + result = segmentA.intersect(segmentB, null, + scalarsA, scalarsB, tolerance); + + if (result == 2 && (!bEnforceOrientation || scalarsB[0] <= scalarsB[1])) { + scalar_a_0 = scalarsA[0]; + scalar_a_1 = scalarsA[1]; + + if (scalar_a_0 * lengthA <= tolerance + && (1.0 - scalar_a_1) * lengthA <= tolerance) { + ivertex_a = segIterA + .getStartPointIndex(); + continue; + } + } + + if (segIterB.hasNextSegment()) { + segmentB = segIterB.nextSegment(); + result = segmentA.intersect(segmentB, + null, scalarsA, scalarsB, + tolerance); + + if (result == 2 && (!bEnforceOrientation || scalarsB[0] <= scalarsB[1])) { + scalar_a_0 = scalarsA[0]; + scalar_a_1 = scalarsA[1]; + + if (scalar_a_0 * lengthA <= tolerance + && (1.0 - scalar_a_1) + * lengthA <= tolerance) { + ivertex_a = segIterA + .getStartPointIndex(); + continue; + } + } + } + } + + bSegmentACovered = false; + } + + if (ivertex_a != segIterA.getStartPointIndex()) { + segIterA.resetToVertex(ivertex_a); + segIterA.nextSegment(); + } + + break; + } else { + int ivertex_a = segIterA.getStartPointIndex(); + int ipath_a = segIterA.getPathIndex(); + int ivertex_b = segIterB.getStartPointIndex(); + int ipath_b = segIterB.getPathIndex(); + + overlapEvent = OverlapEvent.construct(ivertex_a, + ipath_a, scalar_a_0, scalar_a_1, ivertex_b, + ipath_b, scalar_b_0, scalar_b_1); + relOps.m_overlap_events.add(overlapEvent); + eventIndices.add(eventIndices.size()); + } + } + } + + if (bStringOfSegmentAsCovered) { + continue; // no need to check that segmentA is covered + } + if (ievent == relOps.m_overlap_events.size()) { + return false; // bWithin = false + } + + if (eventIndices.size() - ievent > 1) { + eventIndices.Sort(ievent, eventIndices.size(), + overlapComparer); + } + + double lastScalar = 0.0; + + for (int i = ievent; i < relOps.m_overlap_events.size(); i++) { + overlapEvent = relOps.m_overlap_events.get(eventIndices + .get(i)); + + if (overlapEvent.m_scalar_a_0 < lastScalar + && overlapEvent.m_scalar_a_1 < lastScalar) { + continue; + } + + if (lengthA * (overlapEvent.m_scalar_a_0 - lastScalar) > tolerance) { + return false; // bWithin = false + } else { + lastScalar = overlapEvent.m_scalar_a_1; + + if (lengthA * (1.0 - lastScalar) <= tolerance + || lastScalar == 1.0) { + break; + } + } + } + + if (lengthA * (1.0 - lastScalar) > tolerance) { + return false; // bWithin = false + } + + ievent = 0; + eventIndices.resize(0); + relOps.m_overlap_events.clear(); + } + } + + return bWithin; + } + + // Returns true if the segments of multipathA overlap the segments of + // multipathB. + private static boolean linearPathOverlapsLinearPath_(MultiPath multipathA, + MultiPath multipathB, double tolerance) { + int dim = linearPathIntersectsLinearPathMaxDim_(multipathA, multipathB, + tolerance, null); + + if (dim < 1) + return false; + + Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(); + multipathA.queryEnvelope2D(env_a); + multipathB.queryEnvelope2D(env_b); + + boolean bIntAExtB = interiorEnvExteriorEnv_(env_a, env_b, tolerance); + boolean bIntBExtA = interiorEnvExteriorEnv_(env_b, env_a, tolerance); + + if (bIntAExtB && bIntBExtA) + return true; + + if (bIntAExtB && !bIntBExtA) + return !linearPathWithinLinearPath_(multipathB, multipathA, + tolerance, false); + + if (bIntBExtA && !bIntAExtB) + return !linearPathWithinLinearPath_(multipathA, multipathB, + tolerance, false); + + return !linearPathWithinLinearPath_(multipathA, multipathB, tolerance, false) + && !linearPathWithinLinearPath_(multipathB, multipathA, + tolerance, false); + } + + // Returns true the dimension of intersection of _multipathA and + // _multipathB. + static int linearPathIntersectsLinearPathMaxDim_(MultiPath _multipathA, + MultiPath _multipathB, double tolerance, + AttributeStreamOfDbl intersections) { + MultiPath multipathA; + MultiPath multipathB; + + if (_multipathA.getSegmentCount() > _multipathB.getSegmentCount()) { + multipathA = _multipathB; + multipathB = _multipathA; + } else { + multipathA = _multipathA; + multipathB = _multipathB; + } + + SegmentIteratorImpl segIterA = ((MultiPathImpl) multipathA._getImpl()) + .querySegmentIterator(); + SegmentIteratorImpl segIterB = ((MultiPathImpl) multipathB._getImpl()) + .querySegmentIterator(); + double[] scalarsA = new double[2]; + double[] scalarsB = new double[2]; + + int dim = -1; + + int ievent = 0; + double overlapLength; + AttributeStreamOfInt32 eventIndices = new AttributeStreamOfInt32(0); + RelationalOperations relOps = new RelationalOperations(); + OverlapComparer overlapComparer = new OverlapComparer(relOps); + OverlapEvent overlapEvent; + + Envelope2D env_a = new Envelope2D(); + Envelope2D env_b = new Envelope2D(); + Envelope2D envInter = new Envelope2D(); + multipathA.queryEnvelope2D(env_a); + multipathB.queryEnvelope2D(env_b); + env_a.inflate(tolerance, tolerance); + env_b.inflate(tolerance, tolerance); + envInter.setCoords(env_a); + envInter.intersect(env_b); + + Point2D int_point = null; + + if (intersections != null) { + int_point = new Point2D(); + } + + QuadTreeImpl qtB = null; + QuadTreeImpl quadTreeB = null; + QuadTreeImpl quadTreePathsB = null; - segIterA.resetToVertex(vertex_a); - segIterB.resetToVertex(vertex_b); - Segment segmentA = segIterA.nextSegment(); - Segment segmentB = segIterB.nextSegment(); + GeometryAccelerators accel = ((MultiPathImpl) multipathB._getImpl()) + ._getAccelerators(); + + if (accel != null) { + quadTreeB = accel.getQuadTree(); + quadTreePathsB = accel.getQuadTreeForPaths(); + if (quadTreeB == null) { + qtB = InternalUtils.buildQuadTree( + (MultiPathImpl) multipathB._getImpl(), envInter); + quadTreeB = qtB; + } + } else { + qtB = InternalUtils.buildQuadTree( + (MultiPathImpl) multipathB._getImpl(), envInter); + quadTreeB = qtB; + } + + QuadTreeImpl.QuadTreeIteratorImpl qtIterB = quadTreeB.getIterator(); + + QuadTreeImpl.QuadTreeIteratorImpl qtIterPathsB = null; + if (quadTreePathsB != null) + qtIterPathsB = quadTreePathsB.getIterator(); - int result = segmentB.intersect(segmentA, null, scalarsB, scalarsA, - tolerance); + while (segIterA.nextPath()) { + overlapLength = 0.0; - if (result == 2) { - double scalar_a_0 = scalarsA[0]; - double scalar_a_1 = scalarsA[1]; - double length_a = segmentA.calculateLength2D(); + while (segIterA.hasNextSegment()) { + Segment segmentA = segIterA.nextSegment(); + segmentA.queryEnvelope2D(env_a); - if (b_geometries_simple - && (scalar_a_1 - scalar_a_0) * length_a > tolerance) { - // When the line segments intersect along the same - // direction, then we have an interior-interior intersection - bInteriorIntersectionKnown = true; + if (!env_a.isIntersecting(envInter)) { + continue; + } - if (bIntAExtB && bExtAIntB) { - return true; - } - } - } else if (result != 0) { - double scalar_a_0 = scalarsA[0]; - double scalar_b_0 = scalarsB[0]; + if (qtIterPathsB != null) { + qtIterPathsB.resetIterator(env_a, tolerance); - if (scalar_a_0 > 0.0 && scalar_a_0 < 1.0 && scalar_b_0 > 0.0 - && scalar_b_0 < 1.0) { - return true; + if (qtIterPathsB.next() == -1) + continue; } - } - } - Envelope2D envAInflated = new Envelope2D(), envBInflated = new Envelope2D(); - envAInflated.setCoords(env_a); - envAInflated.inflate(1000.0 * tolerance, 1000.0 * tolerance); - envBInflated.setCoords(env_b); - envBInflated.inflate(1000.0 * tolerance, 1000.0 * tolerance); + double lengthA = segmentA.calculateLength2D(); + + qtIterB.resetIterator(segmentA, tolerance); + + for (int elementHandleB = qtIterB.next(); elementHandleB != -1; elementHandleB = qtIterB + .next()) { + int vertex_b = quadTreeB.getElement(elementHandleB); + segIterB.resetToVertex(vertex_b); + + Segment segmentB = segIterB.nextSegment(); + double lengthB = segmentB.calculateLength2D(); + + int result = segmentA.intersect(segmentB, null, scalarsA, + scalarsB, tolerance); + + if (result > 0) { + double scalar_a_0 = scalarsA[0]; + double scalar_b_0 = scalarsB[0]; + double scalar_a_1 = (result == 2 ? scalarsA[1] + : NumberUtils.TheNaN); + double scalar_b_1 = (result == 2 ? scalarsB[1] + : NumberUtils.TheNaN); + + if (result == 2) { + if (lengthA * (scalar_a_1 - scalar_a_0) > tolerance) { + dim = 1; + return dim; + } + + // Quick neighbor check + double length = lengthA * (scalar_a_1 - scalar_a_0); + + if (segIterB.hasNextSegment()) { + segmentB = segIterB.nextSegment(); + result = segmentA.intersect(segmentB, null, + scalarsA, null, tolerance); + + if (result == 2) { + double nextScalarA0 = scalarsA[0]; + double nextScalarA1 = scalarsA[1]; + + double lengthNext = lengthA + * (nextScalarA1 - nextScalarA0); + + if (length + lengthNext > tolerance) { + dim = 1; + return dim; + } + } + + segIterB.resetToVertex(vertex_b); + segIterB.nextSegment(); + } + + if (!segIterB.isFirstSegmentInPath()) { + segIterB.previousSegment(); + segmentB = segIterB.previousSegment(); + result = segmentA.intersect(segmentB, null, + scalarsA, null, tolerance); + + if (result == 2) { + double nextScalarA0 = scalarsA[0]; + double nextScalarA1 = scalarsA[1]; + + double lengthPrevious = lengthA + * (nextScalarA1 - nextScalarA0); + + if (length + lengthPrevious > tolerance) { + dim = 1; + return dim; + } + } + + segIterB.resetToVertex(vertex_b); + segIterB.nextSegment(); + } + + if (segIterA.hasNextSegment()) { + int vertex_a = segIterA.getStartPointIndex(); + segmentA = segIterA.nextSegment(); + result = segmentA.intersect(segmentB, null, + scalarsA, null, tolerance); + + if (result == 2) { + double nextScalarA0 = scalarsA[0]; + double nextScalarA1 = scalarsA[1]; + + double lengthNext = lengthA + * (nextScalarA1 - nextScalarA0); + + if (length + lengthNext > tolerance) { + dim = 1; + return dim; + } + } + + segIterA.resetToVertex(vertex_a); + segIterA.nextSegment(); + } + + if (!segIterA.isFirstSegmentInPath()) { + int vertex_a = segIterA.getStartPointIndex(); + segIterA.previousSegment(); + segmentA = segIterA.previousSegment(); + result = segmentA.intersect(segmentB, null, + scalarsA, null, tolerance); + + if (result == 2) { + double nextScalarA0 = scalarsA[0]; + double nextScalarA1 = scalarsA[1]; + + double lengthPrevious = lengthB + * (nextScalarA1 - nextScalarA0); + + if (length + lengthPrevious > tolerance) { + dim = 1; + return dim; + } + } + + segIterA.resetToVertex(vertex_a); + segIterA.nextSegment(); + } + + int ivertex_a = segIterA.getStartPointIndex(); + int ipath_a = segIterA.getPathIndex(); + int ivertex_b = segIterB.getStartPointIndex(); + int ipath_b = segIterB.getPathIndex(); + + overlapEvent = OverlapEvent.construct(ivertex_a, + ipath_a, scalar_a_0, scalar_a_1, ivertex_b, + ipath_b, scalar_b_0, scalar_b_1); + relOps.m_overlap_events.add(overlapEvent); + eventIndices.add(eventIndices.size()); + } + + dim = 0; + + if (intersections != null) { + segmentA.getCoord2D(scalar_a_0, int_point); + intersections.add(int_point.x); + intersections.add(int_point.y); + } + } + } + + if (ievent < relOps.m_overlap_events.size()) { + eventIndices.Sort(ievent, eventIndices.size(), + overlapComparer); + + double lastScalar = 0.0; + int lastPath = relOps.m_overlap_events.get(eventIndices + .get(ievent)).m_ipath_a; + + for (int i = ievent; i < relOps.m_overlap_events.size(); i++) { + overlapEvent = relOps.m_overlap_events.get(eventIndices + .get(i)); + + if (overlapEvent.m_scalar_a_0 < lastScalar + && overlapEvent.m_scalar_a_1 < lastScalar) { + continue; + } + + if (lengthA * (overlapEvent.m_scalar_a_0 - lastScalar) > tolerance) { + overlapLength = lengthA + * (overlapEvent.m_scalar_a_1 - overlapEvent.m_scalar_a_0); // reset + lastScalar = overlapEvent.m_scalar_a_1; + lastPath = overlapEvent.m_ipath_a; + } else { + if (overlapEvent.m_ipath_a != lastPath) { + overlapLength = lengthA + * (overlapEvent.m_scalar_a_1 - overlapEvent.m_scalar_a_0); // reset + lastPath = overlapEvent.m_ipath_a; + } else { + overlapLength += lengthA + * (overlapEvent.m_scalar_a_1 - overlapEvent.m_scalar_a_0); // accumulate + } + if (overlapLength > tolerance) { + dim = 1; + return dim; + } + + lastScalar = overlapEvent.m_scalar_a_1; + + if (lastScalar == 1.0) { + break; + } + } + } + + if (lengthA * (1.0 - lastScalar) > tolerance) { + overlapLength = 0.0; // reset + } + ievent = 0; + eventIndices.resize(0); + relOps.m_overlap_events.clear(); + } + } + } + + return dim; + } + + // Returns true if the line segments of _multipathA intersect the line + // segments of _multipathB. + private static boolean linearPathIntersectsLinearPath_( + MultiPath multipathA, MultiPath multipathB, double tolerance) { + MultiPathImpl multi_path_impl_a = (MultiPathImpl) multipathA._getImpl(); + MultiPathImpl multi_path_impl_b = (MultiPathImpl) multipathB._getImpl(); + + SegmentIteratorImpl segIterA = multi_path_impl_a.querySegmentIterator(); + SegmentIteratorImpl segIterB = multi_path_impl_b.querySegmentIterator(); - envInter.setCoords(envAInflated); - envInter.intersect(envBInflated); + PairwiseIntersectorImpl intersector = new PairwiseIntersectorImpl(multi_path_impl_a, multi_path_impl_b, tolerance, false); - Polygon _polygonA; - Polygon _polygonB; - StringBuilder scl = new StringBuilder(); + while (intersector.next()) { + int vertex_a = intersector.getRedElement(); + int vertex_b = intersector.getBlueElement(); + + segIterA.resetToVertex(vertex_a); + segIterB.resetToVertex(vertex_b); + Segment segmentA = segIterA.nextSegment(); + Segment segmentB = segIterB.nextSegment(); + + int result = segmentB.intersect(segmentA, null, null, null, + tolerance); + + if (result > 0) { + return true; + } + } + + return false; + } + + // Returns true if the relation intersects, crosses, or contains holds + // between multipathA and multipoint_b. multipathA is put in the + // Quad_tree_impl. + private static boolean linearPathIntersectsMultiPoint_( + MultiPath multipathA, MultiPoint multipoint_b, double tolerance, + boolean b_intersects_all) { + SegmentIteratorImpl segIterA = ((MultiPathImpl) multipathA._getImpl()) + .querySegmentIterator(); + + Envelope2D env_a = new Envelope2D(); + Envelope2D env_b = new Envelope2D(); + Envelope2D envInter = new Envelope2D(); + multipathA.queryEnvelope2D(env_a); + multipoint_b.queryEnvelope2D(env_b); + env_a.inflate(tolerance, tolerance); + + env_b.inflate(tolerance, tolerance); + envInter.setCoords(env_a); + envInter.intersect(env_b); + + QuadTreeImpl qtA = null; + QuadTreeImpl quadTreeA = null; + QuadTreeImpl quadTreePathsA = null; - if (!bInteriorIntersectionKnown) { - scl.append("T*"); - } else { - scl.append("**"); - } + GeometryAccelerators accel = ((MultiPathImpl) multipathA._getImpl()) + ._getAccelerators(); + + if (accel != null) { + quadTreeA = accel.getQuadTree(); + quadTreePathsA = accel.getQuadTreeForPaths(); + if (quadTreeA == null) { + qtA = InternalUtils.buildQuadTree( + (MultiPathImpl) multipathA._getImpl(), envInter); + quadTreeA = qtA; + } + } else { + qtA = InternalUtils.buildQuadTree( + (MultiPathImpl) multipathA._getImpl(), envInter); + quadTreeA = qtA; + } + + QuadTreeImpl.QuadTreeIteratorImpl qtIterA = quadTreeA.getIterator(); - if (bIntAExtB) { - if (polygon_b.getPointCount() > 10) { - _polygonB = (Polygon) (Clipper.clip(polygon_b, envInter, - tolerance, 0.0)); - if (_polygonB.isEmpty()) { - return false; - } - } else { - _polygonB = polygon_b; - } + QuadTreeImpl.QuadTreeIteratorImpl qtIterPathsA = null; + if (quadTreePathsA != null) + qtIterPathsA = quadTreePathsA.getIterator(); - scl.append("****"); - } else { - _polygonB = polygon_b; - scl.append("T***"); - } + Point2D ptB = new Point2D(), closest = new Point2D(); + double toleranceSq = tolerance * tolerance; - if (bExtAIntB) { - if (polygon_a.getPointCount() > 10) { - _polygonA = (Polygon) (Clipper.clip(polygon_a, envInter, - tolerance, 0.0)); - if (_polygonA.isEmpty()) { - return false; - } - } else { - _polygonA = polygon_a; - } + for (int i = 0; i < multipoint_b.getPointCount(); i++) { + multipoint_b.getXY(i, ptB); - scl.append("***"); - } else { - _polygonA = polygon_a; - scl.append("T**"); - } + if (!envInter.contains(ptB)) { + continue; + } - boolean bRelation = RelationalOperationsMatrix.polygonRelatePolygon_( - _polygonA, _polygonB, tolerance, scl.toString(), - progressTracker); - return bRelation; - } + env_b.setCoords(ptB.x, ptB.y, ptB.x, ptB.y); + + if (qtIterPathsA != null) { + qtIterPathsA.resetIterator(env_b, tolerance); + + if (qtIterPathsA.next() == -1) + continue; + } - private static boolean polygonContainsPolygonImpl_(Polygon polygon_a, - Polygon polygon_b, double tolerance, ProgressTracker progressTracker) { + qtIterA.resetIterator(env_b, tolerance); + + boolean b_covered = false; + + for (int elementHandleA = qtIterA.next(); elementHandleA != -1; elementHandleA = qtIterA + .next()) { + int vertex_a = quadTreeA.getElement(elementHandleA); + segIterA.resetToVertex(vertex_a); + Segment segmentA = segIterA.nextSegment(); + + double t = segmentA.getClosestCoordinate(ptB, false); + segmentA.getCoord2D(t, closest); + + if (Point2D.sqrDistance(closest, ptB) <= toleranceSq) { + b_covered = true; + break; + } + } + + if (b_intersects_all) { + if (!b_covered) { + return false; + } + } else { + if (b_covered) { + return true; + } + } + } + + if (b_intersects_all) { + return true; + } + + return false; + } + + // Returns true if a segment of multipathA intersects point_b. + static boolean linearPathIntersectsPoint_(MultiPath multipathA, + Point2D ptB, double tolerance) { + Point2D closest = new Point2D(); + double toleranceSq = tolerance * tolerance; + SegmentIteratorImpl segIterA = ((MultiPathImpl) multipathA._getImpl()) + .querySegmentIterator(); + + GeometryAccelerators accel = ((MultiPathImpl) multipathA._getImpl()) + ._getAccelerators(); + + if (accel != null) { + QuadTreeImpl quadTreeA = accel.getQuadTree(); + if (quadTreeA != null) { + Envelope2D env_b = new Envelope2D(); + env_b.setCoords(ptB); + + QuadTreeImpl.QuadTreeIteratorImpl qt_iter = quadTreeA + .getIterator(env_b, tolerance); + + for (int e = qt_iter.next(); e != -1; e = qt_iter.next()) { + segIterA.resetToVertex(quadTreeA.getElement(e)); + + if (segIterA.hasNextSegment()) { + Segment segmentA = segIterA.nextSegment(); + + double t = segmentA.getClosestCoordinate(ptB, false); + segmentA.getCoord2D(t, closest); + + if (Point2D.sqrDistance(ptB, closest) <= toleranceSq) { + return true; + } + } + } + + return false; + } + } + Envelope2D env_a = new Envelope2D(); + + while (segIterA.nextPath()) { + while (segIterA.hasNextSegment()) { + Segment segmentA = segIterA.nextSegment(); + segmentA.queryEnvelope2D(env_a); + env_a.inflate(tolerance, tolerance); + + if (!env_a.contains(ptB)) { + continue; + } + + double t = segmentA.getClosestCoordinate(ptB, false); + segmentA.getCoord2D(t, closest); + + if (Point2D.sqrDistance(ptB, closest) <= toleranceSq) { + return true; + } + } + } + + return false; + } + + private static boolean linearPathContainsPoint_(MultiPath multipathA, + Point2D pt_b, double tolerance) { + return linearPathIntersectsPoint_(multipathA, pt_b, tolerance) + && !linearPathTouchesPointImpl_(multipathA, pt_b, tolerance); + } + + private static boolean linearPathTouchesPointImpl_(MultiPath multipathA, + Point2D ptB, double tolerance) { + MultiPoint boundary = (MultiPoint) (multipathA.getBoundary()); + return !multiPointDisjointPointImpl_(boundary, ptB, tolerance, null); + } + + // Returns true if the segments of multipathA intersects env_b + private static boolean linearPathIntersectsEnvelope_(MultiPath multipath_a, + Envelope2D env_b, double tolerance, ProgressTracker progress_tracker) { + if (!multipath_a.hasNonLinearSegments()) { + Envelope2D env_b_inflated = new Envelope2D(); + env_b_inflated.setCoords(env_b); + env_b_inflated.inflate(tolerance, tolerance); + MultiPathImpl mimpl_a = (MultiPathImpl) multipath_a._getImpl(); + AttributeStreamOfDbl xy = (AttributeStreamOfDbl) (mimpl_a + .getAttributeStreamRef(VertexDescription.Semantics.POSITION)); + Point2D pt = new Point2D(); + Point2D pt_prev = new Point2D(); + Point2D pt_1 = new Point2D(); + Point2D pt_2 = new Point2D(); + for (int ipath = 0, npath = mimpl_a.getPathCount(); ipath < npath; ipath++) { + boolean b_first = true; + for (int i = mimpl_a.getPathStart(ipath), n = mimpl_a + .getPathEnd(ipath); i < n; i++) { + if (b_first) { + xy.read(2 * i, pt_prev); + b_first = false; + continue; + } + + xy.read(2 * i, pt); + pt_1.setCoords(pt_prev); + pt_2.setCoords(pt); + if (env_b_inflated.clipLine(pt_1, pt_2) != 0) + return true; + + pt_prev.setCoords(pt); + } + } + } else { + Line line_1 = new Line(env_b.xmin, env_b.ymin, env_b.xmin, + env_b.ymax); + Line line_2 = new Line(env_b.xmin, env_b.ymax, env_b.xmax, + env_b.ymax); + Line line3 = new Line(env_b.xmax, env_b.ymax, env_b.xmax, + env_b.ymin); + Line line4 = new Line(env_b.xmax, env_b.ymin, env_b.xmin, + env_b.ymin); + SegmentIterator iter = multipath_a.querySegmentIterator(); + while (iter.nextPath()) { + while (iter.hasNextSegment()) { + Segment polySeg = iter.nextSegment(); + if (polySeg.isIntersecting(line_1, tolerance)) + return true; + + if (polySeg.isIntersecting(line_2, tolerance)) + return true; + + if (polySeg.isIntersecting(line3, tolerance)) + return true; + + if (polySeg.isIntersecting(line4, tolerance)) + return true; + } + } + } + + return false; + } + + // Returns contains, disjoint, or within if the relationship can be + // determined from the rasterized tests. + // When bExtraTestForIntersects is true performs extra tests and can return + // "intersects". + static int tryRasterizedContainsOrDisjoint_(Geometry geom_a, + Geometry geom_b, double tolerance, boolean bExtraTestForIntersects) { + int gtA = geom_a.getType().value(); + int gtB = geom_b.getType().value(); + do { + if (Geometry.isMultiVertex(gtA)) { + MultiVertexGeometryImpl impl = (MultiVertexGeometryImpl) geom_a + ._getImpl(); + GeometryAccelerators accel = impl._getAccelerators(); + if (accel != null) { + RasterizedGeometry2D rgeom = accel.getRasterizedGeometry(); + if (rgeom != null) { + if (gtB == Geometry.GeometryType.Point) { + Point2D ptB = ((Point) geom_b).getXY(); + RasterizedGeometry2D.HitType hit = rgeom + .queryPointInGeometry(ptB.x, ptB.y); + if (hit == RasterizedGeometry2D.HitType.Inside) { + return Relation.contains; + } else if (hit == RasterizedGeometry2D.HitType.Outside) { + return Relation.disjoint; + } + break; + } + Envelope2D env_b = new Envelope2D(); + geom_b.queryEnvelope2D(env_b); + RasterizedGeometry2D.HitType hit = rgeom + .queryEnvelopeInGeometry(env_b); + if (hit == RasterizedGeometry2D.HitType.Inside) { + return Relation.contains; + } else if (hit == RasterizedGeometry2D.HitType.Outside) { + return Relation.disjoint; + } else if (bExtraTestForIntersects + && Geometry.isMultiVertex(gtB)) { + if (checkVerticesForIntersection_( + (MultiVertexGeometryImpl) geom_b._getImpl(), + rgeom)) { + return Relation.intersects; + } + } + + break; + } + } + } + } while (false); + + do { + if (Geometry.isMultiVertex(gtB)) { + MultiVertexGeometryImpl impl = (MultiVertexGeometryImpl) geom_b + ._getImpl(); + GeometryAccelerators accel = impl._getAccelerators(); + if (accel != null) { + RasterizedGeometry2D rgeom = accel.getRasterizedGeometry(); + if (rgeom != null) { + if (gtA == Geometry.GeometryType.Point) { + Point2D ptA = ((Point) geom_a).getXY(); + RasterizedGeometry2D.HitType hit = rgeom + .queryPointInGeometry(ptA.x, ptA.y); + if (hit == RasterizedGeometry2D.HitType.Inside) { + return Relation.within; + } else if (hit == RasterizedGeometry2D.HitType.Outside) { + return Relation.disjoint; + } + break; + } + + Envelope2D env_a = new Envelope2D(); + geom_a.queryEnvelope2D(env_a); + RasterizedGeometry2D.HitType hit = rgeom + .queryEnvelopeInGeometry(env_a); + if (hit == RasterizedGeometry2D.HitType.Inside) { + return Relation.within; + } else if (hit == RasterizedGeometry2D.HitType.Outside) { + return Relation.disjoint; + } else if (bExtraTestForIntersects + && Geometry.isMultiVertex(gtA)) { + if (checkVerticesForIntersection_( + (MultiVertexGeometryImpl) geom_a._getImpl(), + rgeom)) { + return Relation.intersects; + } + } + + break; + } + } + } + } while (false); + + return Relation.unknown; + } + + // Returns true if intersects and false if nothing can be determined. + private static boolean checkVerticesForIntersection_( + MultiVertexGeometryImpl geom, RasterizedGeometry2D rgeom) { + // Do a quick raster test for each point. If any point is inside, then + // there is an intersection. + int pointCount = geom.getPointCount(); + Point2D pt = new Point2D(); + for (int ipoint = 0; ipoint < pointCount; ipoint++) { + geom.getXY(ipoint, pt); + RasterizedGeometry2D.HitType hit = rgeom.queryPointInGeometry(pt.x, + pt.y); + if (hit == RasterizedGeometry2D.HitType.Inside) { + return true; + } + } + + return false; + } + + private static boolean polygonTouchesPolygonImpl_(Polygon polygon_a, + Polygon polygon_b, double tolerance, ProgressTracker progressTracker) { + MultiPathImpl polygon_impl_a = (MultiPathImpl) polygon_a._getImpl(); + MultiPathImpl polygon_impl_b = (MultiPathImpl) polygon_b._getImpl(); + + // double geom_tolerance; + boolean b_geometries_simple = polygon_impl_a.getIsSimple(0.0) >= 1 + && polygon_impl_b.getIsSimple(0.0) >= 1; + + SegmentIteratorImpl segIterA = polygon_impl_a.querySegmentIterator(); + SegmentIteratorImpl segIterB = polygon_impl_b.querySegmentIterator(); + double[] scalarsA = new double[2]; + double[] scalarsB = new double[2]; + + PairwiseIntersectorImpl intersector = new PairwiseIntersectorImpl( + polygon_impl_a, polygon_impl_b, tolerance, false); + + boolean b_boundaries_intersect = false; + + while (intersector.next()) { + int vertex_a = intersector.getRedElement(); + int vertex_b = intersector.getBlueElement(); + + segIterA.resetToVertex(vertex_a); + segIterB.resetToVertex(vertex_b); + Segment segmentA = segIterA.nextSegment(); + Segment segmentB = segIterB.nextSegment(); + + int result = segmentB.intersect(segmentA, null, scalarsB, scalarsA, + tolerance); + + if (result == 2) { + double scalar_a_0 = scalarsA[0]; + double scalar_a_1 = scalarsA[1]; + double length_a = segmentA.calculateLength2D(); + + if (b_geometries_simple + && (scalar_a_1 - scalar_a_0) * length_a > tolerance) { + // If the line segments overlap along the same direction, + // then we have an Interior-Interior intersection + return false; + } + + b_boundaries_intersect = true; + } else if (result != 0) { + double scalar_a_0 = scalarsA[0]; + double scalar_b_0 = scalarsB[0]; + + if (scalar_a_0 > 0.0 && scalar_a_0 < 1.0 && scalar_b_0 > 0.0 + && scalar_b_0 < 1.0) { + return false; + } + + b_boundaries_intersect = true; + } + } + + if (!b_boundaries_intersect) { + return false; + } + + Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(), envInter = new Envelope2D(); + polygon_a.queryEnvelope2D(env_a); + polygon_b.queryEnvelope2D(env_b); + env_a.inflate(1000.0 * tolerance, 1000.0 * tolerance); + env_b.inflate(1000.0 * tolerance, 1000.0 * tolerance); + envInter.setCoords(env_a); + envInter.intersect(env_b); + + Polygon _polygonA; + Polygon _polygonB; + + if (polygon_a.getPointCount() > 10) { + _polygonA = (Polygon) (Clipper.clip(polygon_a, envInter, tolerance, + 0.0)); + if (_polygonA.isEmpty()) { + return false; + } + } else { + _polygonA = polygon_a; + } + + if (polygon_b.getPointCount() > 10) { + _polygonB = (Polygon) (Clipper.clip(polygon_b, envInter, tolerance, + 0.0)); + if (_polygonB.isEmpty()) { + return false; + } + } else { + _polygonB = polygon_b; + } + + // We just need to determine whether interior_interior is false + String scl = "F********"; + boolean bRelation = RelationalOperationsMatrix.polygonRelatePolygon_( + _polygonA, _polygonB, tolerance, scl, progressTracker); + + return bRelation; + } + + private static boolean polygonOverlapsPolygonImpl_(Polygon polygon_a, + Polygon polygon_b, double tolerance, ProgressTracker progressTracker) { + MultiPathImpl polygon_impl_a = (MultiPathImpl) polygon_a._getImpl(); + MultiPathImpl polygon_impl_b = (MultiPathImpl) polygon_b._getImpl(); + + // double geom_tolerance; + boolean b_geometries_simple = polygon_impl_a.getIsSimple(0.0) >= 1 + && polygon_impl_b.getIsSimple(0.0) >= 1; + + Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(), envInter = new Envelope2D(); + polygon_a.queryEnvelope2D(env_a); + polygon_b.queryEnvelope2D(env_b); + + boolean bInteriorIntersectionKnown = false; + + boolean bIntAExtB = interiorEnvExteriorEnv_(env_a, env_b, tolerance); + boolean bExtAIntB = interiorEnvExteriorEnv_(env_b, env_a, tolerance); + + SegmentIteratorImpl segIterA = polygon_impl_a.querySegmentIterator(); + SegmentIteratorImpl segIterB = polygon_impl_b.querySegmentIterator(); + double[] scalarsA = new double[2]; + double[] scalarsB = new double[2]; + + PairwiseIntersectorImpl intersector = new PairwiseIntersectorImpl( + polygon_impl_a, polygon_impl_b, tolerance, false); + + while (intersector.next()) { + int vertex_a = intersector.getRedElement(); + int vertex_b = intersector.getBlueElement(); + + segIterA.resetToVertex(vertex_a); + segIterB.resetToVertex(vertex_b); + Segment segmentA = segIterA.nextSegment(); + Segment segmentB = segIterB.nextSegment(); + + int result = segmentB.intersect(segmentA, null, scalarsB, scalarsA, + tolerance); + + if (result == 2) { + double scalar_a_0 = scalarsA[0]; + double scalar_a_1 = scalarsA[1]; + double length_a = segmentA.calculateLength2D(); + + if (b_geometries_simple + && (scalar_a_1 - scalar_a_0) * length_a > tolerance) { + // When the line segments intersect along the same + // direction, then we have an interior-interior intersection + bInteriorIntersectionKnown = true; + + if (bIntAExtB && bExtAIntB) { + return true; + } + } + } else if (result != 0) { + double scalar_a_0 = scalarsA[0]; + double scalar_b_0 = scalarsB[0]; + + if (scalar_a_0 > 0.0 && scalar_a_0 < 1.0 && scalar_b_0 > 0.0 + && scalar_b_0 < 1.0) { + return true; + } + } + } + + Envelope2D envAInflated = new Envelope2D(), envBInflated = new Envelope2D(); + envAInflated.setCoords(env_a); + envAInflated.inflate(1000.0 * tolerance, 1000.0 * tolerance); + envBInflated.setCoords(env_b); + envBInflated.inflate(1000.0 * tolerance, 1000.0 * tolerance); + + envInter.setCoords(envAInflated); + envInter.intersect(envBInflated); + + Polygon _polygonA; + Polygon _polygonB; + StringBuilder scl = new StringBuilder(); + + if (!bInteriorIntersectionKnown) { + scl.append("T*"); + } else { + scl.append("**"); + } + + if (bIntAExtB) { + if (polygon_b.getPointCount() > 10) { + _polygonB = (Polygon) (Clipper.clip(polygon_b, envInter, + tolerance, 0.0)); + if (_polygonB.isEmpty()) { + return false; + } + } else { + _polygonB = polygon_b; + } + + scl.append("****"); + } else { + _polygonB = polygon_b; + scl.append("T***"); + } + + if (bExtAIntB) { + if (polygon_a.getPointCount() > 10) { + _polygonA = (Polygon) (Clipper.clip(polygon_a, envInter, + tolerance, 0.0)); + if (_polygonA.isEmpty()) { + return false; + } + } else { + _polygonA = polygon_a; + } + + scl.append("***"); + } else { + _polygonA = polygon_a; + scl.append("T**"); + } + + boolean bRelation = RelationalOperationsMatrix.polygonRelatePolygon_( + _polygonA, _polygonB, tolerance, scl.toString(), + progressTracker); + return bRelation; + } + + private static boolean polygonContainsPolygonImpl_(Polygon polygon_a, + Polygon polygon_b, double tolerance, ProgressTracker progressTracker) { boolean[] b_result_known = new boolean[1]; b_result_known[0] = false; boolean res = polygonContainsMultiPath_(polygon_a, polygon_b, tolerance, b_result_known, progressTracker); @@ -4725,23 +4729,27 @@ private static boolean polygonContainsPolygonImpl_(Polygon polygon_a, Polygon _polygonA = null; - if (polygon_a.getPointCount() > 10) { - _polygonA = (Polygon) Clipper.clip(polygon_a, envBInflated, tolerance, 0.0); + if (polygon_a.getPointCount() > 10) + { + _polygonA = (Polygon)Clipper.clip(polygon_a, envBInflated, tolerance, 0.0); if (_polygonA.isEmpty()) return false; - } else { + } + else + { _polygonA = polygon_a; } boolean bContains = RelationalOperationsMatrix.polygonContainsPolygon_(_polygonA, polygon_b, tolerance, progressTracker); return bContains; - } + } - private static boolean polygonContainsMultiPath_(Polygon polygon_a, MultiPath multi_path_b, double tolerance, boolean[] b_result_known, ProgressTracker progress_tracker) { + private static boolean polygonContainsMultiPath_(Polygon polygon_a, MultiPath multi_path_b, double tolerance, boolean[] b_result_known, ProgressTracker progress_tracker) + { b_result_known[0] = false; - MultiPathImpl polygon_impl_a = (MultiPathImpl) polygon_a._getImpl(); - MultiPathImpl multi_path_impl_b = (MultiPathImpl) multi_path_b._getImpl(); + MultiPathImpl polygon_impl_a = (MultiPathImpl)polygon_a._getImpl(); + MultiPathImpl multi_path_impl_b = (MultiPathImpl)multi_path_b._getImpl(); SegmentIteratorImpl segIterA = polygon_impl_a.querySegmentIterator(); SegmentIteratorImpl segIterB = multi_path_impl_b.querySegmentIterator(); @@ -4751,7 +4759,8 @@ private static boolean polygonContainsMultiPath_(Polygon polygon_a, MultiPath mu PairwiseIntersectorImpl intersector = new PairwiseIntersectorImpl(polygon_impl_a, multi_path_impl_b, tolerance, false); boolean b_boundaries_intersect = false; - while (intersector.next()) { + while (intersector.next()) + { int vertex_a = intersector.getRedElement(); int vertex_b = intersector.getBlueElement(); @@ -4776,7 +4785,8 @@ private static boolean polygonContainsMultiPath_(Polygon polygon_a, MultiPath mu } } - if (!b_boundaries_intersect) { + if (!b_boundaries_intersect) + { b_result_known[0] = true; //boundaries do not intersect @@ -4792,16 +4802,21 @@ private static boolean polygonContainsMultiPath_(Polygon polygon_a, MultiPath mu Envelope2D path_env_b = new Envelope2D(); - for (int ipath = 0, npath = multi_path_b.getPathCount(); ipath < npath; ipath++) { - if (multi_path_b.getPathSize(ipath) > 0) { + for (int ipath = 0, npath = multi_path_b.getPathCount(); ipath < npath; ipath++) + { + if (multi_path_b.getPathSize(ipath) > 0) + { multi_path_b.queryPathEnvelope2D(ipath, path_env_b); - if (env_a_inflated.isIntersecting(path_env_b)) { + if (env_a_inflated.isIntersecting(path_env_b)) + { Point2D anyPoint = multi_path_b.getXY(multi_path_b.getPathStart(ipath)); int res = PointInPolygonHelper.isPointInPolygon(p_polygon_a, anyPoint, 0); if (res == 0) return false; - } else { + } + else + { return false; } @@ -4825,7 +4840,7 @@ private static boolean polygonContainsMultiPath_(Polygon polygon_a, MultiPath mu // Polygon A has multiple rings, and Multi_path B is a polygon. - Polygon polygon_b = (Polygon) multi_path_b; + Polygon polygon_b = (Polygon)multi_path_b; Envelope2D env_b_inflated = new Envelope2D(); polygon_b.queryEnvelope2D(env_b_inflated); @@ -4838,11 +4853,14 @@ private static boolean polygonContainsMultiPath_(Polygon polygon_a, MultiPath mu Envelope2D path_env_a = new Envelope2D(); - for (int ipath = 0, npath = polygon_a.getPathCount(); ipath < npath; ipath++) { - if (polygon_a.getPathSize(ipath) > 0) { + for (int ipath = 0, npath = polygon_a.getPathCount(); ipath < npath; ipath++) + { + if (polygon_a.getPathSize(ipath) > 0) + { polygon_a.queryPathEnvelope2D(ipath, path_env_a); - if (env_b_inflated.isIntersecting(path_env_a)) { + if (env_b_inflated.isIntersecting(path_env_a)) + { Point2D anyPoint = polygon_a.getXY(polygon_a.getPathStart(ipath)); int res = PointInPolygonHelper.isPointInPolygon(p_polygon_b, anyPoint, 0); if (res == 1) @@ -4870,191 +4888,191 @@ private static boolean polygonContainsMultiPath_(Polygon polygon_a, MultiPath mu return false; } - private static boolean polygonTouchesPolylineImpl_(Polygon polygon_a, - Polyline polyline_b, double tolerance, - ProgressTracker progressTracker) { - MultiPathImpl polygon_impl_a = (MultiPathImpl) polygon_a._getImpl(); - MultiPathImpl polyline_impl_b = (MultiPathImpl) polyline_b._getImpl(); - - SegmentIteratorImpl segIterA = polygon_impl_a.querySegmentIterator(); - SegmentIteratorImpl segIterB = polyline_impl_b.querySegmentIterator(); - double[] scalarsA = new double[2]; - double[] scalarsB = new double[2]; - - PairwiseIntersectorImpl intersector = new PairwiseIntersectorImpl( - polygon_impl_a, polyline_impl_b, tolerance, false); - - boolean b_boundaries_intersect = false; - - while (intersector.next()) { - int vertex_a = intersector.getRedElement(); - int vertex_b = intersector.getBlueElement(); - - segIterA.resetToVertex(vertex_a); - segIterB.resetToVertex(vertex_b); - Segment segmentA = segIterA.nextSegment(); - Segment segmentB = segIterB.nextSegment(); - - int result = segmentB.intersect(segmentA, null, scalarsB, scalarsA, - tolerance); - - if (result == 2) { - b_boundaries_intersect = true; - } else if (result != 0) { - double scalar_a_0 = scalarsA[0]; - double scalar_b_0 = scalarsB[0]; - - if (scalar_a_0 > 0.0 && scalar_a_0 < 1.0 && scalar_b_0 > 0.0 - && scalar_b_0 < 1.0) { - return false; - } - - b_boundaries_intersect = true; - } - } - - if (!b_boundaries_intersect) { - return false; - } - - Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(), envInter = new Envelope2D(); - polygon_a.queryEnvelope2D(env_a); - polyline_b.queryEnvelope2D(env_b); - env_a.inflate(1000.0 * tolerance, 1000.0 * tolerance); - env_b.inflate(1000.0 * tolerance, 1000.0 * tolerance); - envInter.setCoords(env_a); - envInter.intersect(env_b); - - Polygon _polygonA; - Polyline _polylineB; - - if (polygon_a.getPointCount() > 10) { - _polygonA = (Polygon) (Clipper.clip(polygon_a, envInter, tolerance, - 0.0)); - if (_polygonA.isEmpty()) { - return false; - } - } else { - _polygonA = polygon_a; - } - - if (polyline_b.getPointCount() > 10) { - _polylineB = (Polyline) Clipper.clip(polyline_b, envInter, - tolerance, 0.0); - if (_polylineB.isEmpty()) { - return false; - } - } else { - _polylineB = polyline_b; - } - - // We just need to determine that interior_interior is false - String scl = "F********"; - boolean bRelation = RelationalOperationsMatrix.polygonRelatePolyline_( - _polygonA, _polylineB, tolerance, scl, progressTracker); - - return bRelation; - } - - private static boolean polygonCrossesPolylineImpl_(Polygon polygon_a, - Polyline polyline_b, double tolerance, - ProgressTracker progressTracker) { - MultiPathImpl polygon_impl_a = (MultiPathImpl) polygon_a._getImpl(); - MultiPathImpl polyline_impl_b = (MultiPathImpl) polyline_b._getImpl(); - - SegmentIteratorImpl segIterA = polygon_impl_a.querySegmentIterator(); - SegmentIteratorImpl segIterB = polyline_impl_b.querySegmentIterator(); - double[] scalarsA = new double[2]; - double[] scalarsB = new double[2]; - - PairwiseIntersectorImpl intersector = new PairwiseIntersectorImpl( - polygon_impl_a, polyline_impl_b, tolerance, false); - - boolean b_boundaries_intersect = false; - - while (intersector.next()) { - int vertex_a = intersector.getRedElement(); - int vertex_b = intersector.getBlueElement(); - - segIterA.resetToVertex(vertex_a); - segIterB.resetToVertex(vertex_b); - Segment segmentA = segIterA.nextSegment(); - Segment segmentB = segIterB.nextSegment(); - - int result = segmentB.intersect(segmentA, null, scalarsB, scalarsA, - tolerance); - - if (result == 2) { - b_boundaries_intersect = true; - } else if (result != 0) { - double scalar_a_0 = scalarsA[0]; - double scalar_b_0 = scalarsB[0]; - - if (scalar_a_0 > 0.0 && scalar_a_0 < 1.0 && scalar_b_0 > 0.0 - && scalar_b_0 < 1.0) { - return true; - } - - b_boundaries_intersect = true; - } - } - - if (!b_boundaries_intersect) { - return false; - } - - Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(), envAInflated = new Envelope2D(), envBInflated = new Envelope2D(), envInter = new Envelope2D(); - polygon_a.queryEnvelope2D(env_a); - polyline_b.queryEnvelope2D(env_b); - - if (interiorEnvExteriorEnv_(env_b, env_a, tolerance)) { - envAInflated.setCoords(env_a); - envAInflated.inflate(1000.0 * tolerance, 1000.0 * tolerance); - envBInflated.setCoords(env_b); - envBInflated.inflate(1000.0 * tolerance, 1000.0 * tolerance); - envInter.setCoords(envAInflated); - envInter.intersect(envBInflated); - - Polygon _polygonA; - Polyline _polylineB; - - if (polygon_a.getPointCount() > 10) { - _polygonA = (Polygon) (Clipper.clip(polygon_a, envInter, - tolerance, 0.0)); - if (_polygonA.isEmpty()) { - return false; - } - } else { - _polygonA = polygon_a; - } - - if (polyline_b.getPointCount() > 10) { - _polylineB = (Polyline) (Clipper.clip(polyline_b, envInter, - tolerance, 0.0)); - if (_polylineB.isEmpty()) { - return false; - } - } else { - _polylineB = polyline_b; - } - - String scl = "T********"; - boolean bRelation = RelationalOperationsMatrix - .polygonRelatePolyline_(_polygonA, _polylineB, tolerance, - scl, progressTracker); - return bRelation; - } - - String scl = "T*****T**"; - boolean bRelation = RelationalOperationsMatrix.polygonRelatePolyline_( - polygon_a, polyline_b, tolerance, scl, progressTracker); - - return bRelation; - } - - private static boolean polygonContainsPolylineImpl_(Polygon polygon_a, - Polyline polyline_b, double tolerance, - ProgressTracker progress_tracker) { + private static boolean polygonTouchesPolylineImpl_(Polygon polygon_a, + Polyline polyline_b, double tolerance, + ProgressTracker progressTracker) { + MultiPathImpl polygon_impl_a = (MultiPathImpl) polygon_a._getImpl(); + MultiPathImpl polyline_impl_b = (MultiPathImpl) polyline_b._getImpl(); + + SegmentIteratorImpl segIterA = polygon_impl_a.querySegmentIterator(); + SegmentIteratorImpl segIterB = polyline_impl_b.querySegmentIterator(); + double[] scalarsA = new double[2]; + double[] scalarsB = new double[2]; + + PairwiseIntersectorImpl intersector = new PairwiseIntersectorImpl( + polygon_impl_a, polyline_impl_b, tolerance, false); + + boolean b_boundaries_intersect = false; + + while (intersector.next()) { + int vertex_a = intersector.getRedElement(); + int vertex_b = intersector.getBlueElement(); + + segIterA.resetToVertex(vertex_a); + segIterB.resetToVertex(vertex_b); + Segment segmentA = segIterA.nextSegment(); + Segment segmentB = segIterB.nextSegment(); + + int result = segmentB.intersect(segmentA, null, scalarsB, scalarsA, + tolerance); + + if (result == 2) { + b_boundaries_intersect = true; + } else if (result != 0) { + double scalar_a_0 = scalarsA[0]; + double scalar_b_0 = scalarsB[0]; + + if (scalar_a_0 > 0.0 && scalar_a_0 < 1.0 && scalar_b_0 > 0.0 + && scalar_b_0 < 1.0) { + return false; + } + + b_boundaries_intersect = true; + } + } + + if (!b_boundaries_intersect) { + return false; + } + + Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(), envInter = new Envelope2D(); + polygon_a.queryEnvelope2D(env_a); + polyline_b.queryEnvelope2D(env_b); + env_a.inflate(1000.0 * tolerance, 1000.0 * tolerance); + env_b.inflate(1000.0 * tolerance, 1000.0 * tolerance); + envInter.setCoords(env_a); + envInter.intersect(env_b); + + Polygon _polygonA; + Polyline _polylineB; + + if (polygon_a.getPointCount() > 10) { + _polygonA = (Polygon) (Clipper.clip(polygon_a, envInter, tolerance, + 0.0)); + if (_polygonA.isEmpty()) { + return false; + } + } else { + _polygonA = polygon_a; + } + + if (polyline_b.getPointCount() > 10) { + _polylineB = (Polyline) Clipper.clip(polyline_b, envInter, + tolerance, 0.0); + if (_polylineB.isEmpty()) { + return false; + } + } else { + _polylineB = polyline_b; + } + + // We just need to determine that interior_interior is false + String scl = "F********"; + boolean bRelation = RelationalOperationsMatrix.polygonRelatePolyline_( + _polygonA, _polylineB, tolerance, scl, progressTracker); + + return bRelation; + } + + private static boolean polygonCrossesPolylineImpl_(Polygon polygon_a, + Polyline polyline_b, double tolerance, + ProgressTracker progressTracker) { + MultiPathImpl polygon_impl_a = (MultiPathImpl) polygon_a._getImpl(); + MultiPathImpl polyline_impl_b = (MultiPathImpl) polyline_b._getImpl(); + + SegmentIteratorImpl segIterA = polygon_impl_a.querySegmentIterator(); + SegmentIteratorImpl segIterB = polyline_impl_b.querySegmentIterator(); + double[] scalarsA = new double[2]; + double[] scalarsB = new double[2]; + + PairwiseIntersectorImpl intersector = new PairwiseIntersectorImpl( + polygon_impl_a, polyline_impl_b, tolerance, false); + + boolean b_boundaries_intersect = false; + + while (intersector.next()) { + int vertex_a = intersector.getRedElement(); + int vertex_b = intersector.getBlueElement(); + + segIterA.resetToVertex(vertex_a); + segIterB.resetToVertex(vertex_b); + Segment segmentA = segIterA.nextSegment(); + Segment segmentB = segIterB.nextSegment(); + + int result = segmentB.intersect(segmentA, null, scalarsB, scalarsA, + tolerance); + + if (result == 2) { + b_boundaries_intersect = true; + } else if (result != 0) { + double scalar_a_0 = scalarsA[0]; + double scalar_b_0 = scalarsB[0]; + + if (scalar_a_0 > 0.0 && scalar_a_0 < 1.0 && scalar_b_0 > 0.0 + && scalar_b_0 < 1.0) { + return true; + } + + b_boundaries_intersect = true; + } + } + + if (!b_boundaries_intersect) { + return false; + } + + Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(), envAInflated = new Envelope2D(), envBInflated = new Envelope2D(), envInter = new Envelope2D(); + polygon_a.queryEnvelope2D(env_a); + polyline_b.queryEnvelope2D(env_b); + + if (interiorEnvExteriorEnv_(env_b, env_a, tolerance)) { + envAInflated.setCoords(env_a); + envAInflated.inflate(1000.0 * tolerance, 1000.0 * tolerance); + envBInflated.setCoords(env_b); + envBInflated.inflate(1000.0 * tolerance, 1000.0 * tolerance); + envInter.setCoords(envAInflated); + envInter.intersect(envBInflated); + + Polygon _polygonA; + Polyline _polylineB; + + if (polygon_a.getPointCount() > 10) { + _polygonA = (Polygon) (Clipper.clip(polygon_a, envInter, + tolerance, 0.0)); + if (_polygonA.isEmpty()) { + return false; + } + } else { + _polygonA = polygon_a; + } + + if (polyline_b.getPointCount() > 10) { + _polylineB = (Polyline) (Clipper.clip(polyline_b, envInter, + tolerance, 0.0)); + if (_polylineB.isEmpty()) { + return false; + } + } else { + _polylineB = polyline_b; + } + + String scl = "T********"; + boolean bRelation = RelationalOperationsMatrix + .polygonRelatePolyline_(_polygonA, _polylineB, tolerance, + scl, progressTracker); + return bRelation; + } + + String scl = "T*****T**"; + boolean bRelation = RelationalOperationsMatrix.polygonRelatePolyline_( + polygon_a, polyline_b, tolerance, scl, progressTracker); + + return bRelation; + } + + private static boolean polygonContainsPolylineImpl_(Polygon polygon_a, + Polyline polyline_b, double tolerance, + ProgressTracker progress_tracker) { boolean[] b_result_known = new boolean[1]; b_result_known[0] = false; boolean res = polygonContainsMultiPath_(polygon_a, polyline_b, tolerance, b_result_known, progress_tracker); @@ -5070,160 +5088,163 @@ private static boolean polygonContainsPolylineImpl_(Polygon polygon_a, Polygon _polygonA = null; - if (polygon_a.getPointCount() > 10) { - _polygonA = (Polygon) Clipper.clip(polygon_a, envBInflated, tolerance, 0.0); + if (polygon_a.getPointCount() > 10) + { + _polygonA = (Polygon)Clipper.clip(polygon_a, envBInflated, tolerance, 0.0); if (_polygonA.isEmpty()) return false; - } else { + } + else + { _polygonA = polygon_a; } boolean bContains = RelationalOperationsMatrix.polygonContainsPolyline_(_polygonA, polyline_b, tolerance, progress_tracker); return bContains; - } - - private static boolean polygonContainsPointImpl_(Polygon polygon_a, - Point2D pt_b, double tolerance, ProgressTracker progressTracker) { - PolygonUtils.PiPResult result = PolygonUtils.isPointInPolygon2D( - polygon_a, pt_b, tolerance); - - if (result == PolygonUtils.PiPResult.PiPInside) - return true; - - return false; - } - - private static boolean polygonTouchesPointImpl_(Polygon polygon_a, - Point2D pt_b, double tolerance, ProgressTracker progressTracker) { - PolygonUtils.PiPResult result = PolygonUtils.isPointInPolygon2D( - polygon_a, pt_b, tolerance); - - if (result == PolygonUtils.PiPResult.PiPBoundary) - return true; - - return false; - } - - static boolean multiPointDisjointPointImpl_(MultiPoint multipoint_a, - Point2D pt_b, double tolerance, ProgressTracker progressTracker) { - Point2D pt_a = new Point2D(); - double tolerance_sq = tolerance * tolerance; - - for (int i = 0; i < multipoint_a.getPointCount(); i++) { - multipoint_a.getXY(i, pt_a); - - if (Point2D.sqrDistance(pt_a, pt_b) <= tolerance_sq) - return false; - } - - return true; - } - - private static final class OverlapEvent { - int m_ivertex_a; - int m_ipath_a; - double m_scalar_a_0; - double m_scalar_a_1; - int m_ivertex_b; - int m_ipath_b; - double m_scalar_b_0; - double m_scalar_b_1; - - static OverlapEvent construct(int ivertex_a, int ipath_a, - double scalar_a_0, double scalar_a_1, int ivertex_b, - int ipath_b, double scalar_b_0, double scalar_b_1) { - OverlapEvent overlapEvent = new OverlapEvent(); - overlapEvent.m_ivertex_a = ivertex_a; - overlapEvent.m_ipath_a = ipath_a; - overlapEvent.m_scalar_a_0 = scalar_a_0; - overlapEvent.m_scalar_a_1 = scalar_a_1; - overlapEvent.m_ivertex_b = ivertex_b; - overlapEvent.m_ipath_b = ipath_b; - overlapEvent.m_scalar_b_0 = scalar_b_0; - overlapEvent.m_scalar_b_1 = scalar_b_1; - return overlapEvent; - } - } - - ArrayList m_overlap_events; - - private RelationalOperations() { - m_overlap_events = new ArrayList(); - } - - private static class OverlapComparer extends - AttributeStreamOfInt32.IntComparator { - OverlapComparer(RelationalOperations rel_ops) { - m_rel_ops = rel_ops; - } - - @Override - public int compare(int o_1, int o_2) { - return m_rel_ops.compareOverlapEvents_(o_1, o_2); - } - - private RelationalOperations m_rel_ops; - } - - int compareOverlapEvents_(int o_1, int o_2) { - OverlapEvent overlapEvent1 = m_overlap_events.get(o_1); - OverlapEvent overlapEvent2 = m_overlap_events.get(o_2); - - if (overlapEvent1.m_ipath_a < overlapEvent2.m_ipath_a) - return -1; - - if (overlapEvent1.m_ipath_a == overlapEvent2.m_ipath_a) { - if (overlapEvent1.m_ivertex_a < overlapEvent2.m_ivertex_a) - return -1; - - if (overlapEvent1.m_ivertex_a == overlapEvent2.m_ivertex_a) { - if (overlapEvent1.m_scalar_a_0 < overlapEvent2.m_scalar_a_0) - return -1; - - if (overlapEvent1.m_scalar_a_0 == overlapEvent2.m_scalar_a_0) { - if (overlapEvent1.m_scalar_a_1 < overlapEvent2.m_scalar_a_1) - return -1; - - if (overlapEvent1.m_scalar_a_1 == overlapEvent2.m_scalar_a_1) { - if (overlapEvent1.m_ivertex_b < overlapEvent2.m_ivertex_b) - return -1; - } - } - } - } - - return 1; - } - - static final class Accelerate_helper { - static boolean accelerate_geometry(Geometry geometry, - SpatialReference sr, - Geometry.GeometryAccelerationDegree accel_degree) { - if (!can_accelerate_geometry(geometry)) - return false; - - double tol = InternalUtils.calculateToleranceFromGeometry(sr, - geometry, false); - boolean bAccelerated = false; - if (GeometryAccelerators.canUseRasterizedGeometry(geometry)) - bAccelerated |= ((MultiVertexGeometryImpl) geometry._getImpl()) - ._buildRasterizedGeometryAccelerator(tol, accel_degree); - - Geometry.Type type = geometry.getType(); - if ((type == Geometry.Type.Polygon || type == Geometry.Type.Polyline) - && GeometryAccelerators.canUseQuadTree(geometry) - && accel_degree != Geometry.GeometryAccelerationDegree.enumMild) - bAccelerated |= ((MultiVertexGeometryImpl) geometry._getImpl()) - ._buildQuadTreeAccelerator(accel_degree); - - if ((type == Geometry.Type.Polygon || type == Geometry.Type.Polyline) - && GeometryAccelerators.canUseQuadTreeForPaths(geometry) - && accel_degree != Geometry.GeometryAccelerationDegree.enumMild) - bAccelerated |= ((MultiPathImpl) geometry._getImpl()) - ._buildQuadTreeForPathsAccelerator(accel_degree); - - return bAccelerated; - } + } + + private static boolean polygonContainsPointImpl_(Polygon polygon_a, + Point2D pt_b, double tolerance, ProgressTracker progressTracker) { + PolygonUtils.PiPResult result = PolygonUtils.isPointInPolygon2D( + polygon_a, pt_b, tolerance); + + if (result == PolygonUtils.PiPResult.PiPInside) + return true; + + return false; + } + + private static boolean polygonTouchesPointImpl_(Polygon polygon_a, + Point2D pt_b, double tolerance, ProgressTracker progressTracker) { + PolygonUtils.PiPResult result = PolygonUtils.isPointInPolygon2D( + polygon_a, pt_b, tolerance); + + if (result == PolygonUtils.PiPResult.PiPBoundary) + return true; + + return false; + } + + static boolean multiPointDisjointPointImpl_(MultiPoint multipoint_a, + Point2D pt_b, double tolerance, ProgressTracker progressTracker) { + Point2D pt_a = new Point2D(); + double tolerance_sq = tolerance * tolerance; + + for (int i = 0; i < multipoint_a.getPointCount(); i++) { + multipoint_a.getXY(i, pt_a); + + if (Point2D.sqrDistance(pt_a, pt_b) <= tolerance_sq) + return false; + } + + return true; + } + + private static final class OverlapEvent { + int m_ivertex_a; + int m_ipath_a; + double m_scalar_a_0; + double m_scalar_a_1; + int m_ivertex_b; +// int m_ipath_b; +// double m_scalar_b_0; +// double m_scalar_b_1; + + static OverlapEvent construct(int ivertex_a, int ipath_a, + double scalar_a_0, double scalar_a_1, int ivertex_b, + int ipath_b, double scalar_b_0, double scalar_b_1) { + OverlapEvent overlapEvent = new OverlapEvent(); + overlapEvent.m_ivertex_a = ivertex_a; + overlapEvent.m_ipath_a = ipath_a; + overlapEvent.m_scalar_a_0 = scalar_a_0; + overlapEvent.m_scalar_a_1 = scalar_a_1; + overlapEvent.m_ivertex_b = ivertex_b; +// overlapEvent.m_ipath_b = ipath_b; +// overlapEvent.m_scalar_b_0 = scalar_b_0; +// overlapEvent.m_scalar_b_1 = scalar_b_1; + return overlapEvent; + } + } + + ArrayList m_overlap_events; + + private RelationalOperations() { + m_overlap_events = new ArrayList(); + } + + private static class OverlapComparer extends + AttributeStreamOfInt32.IntComparator { + OverlapComparer(RelationalOperations rel_ops) { + m_rel_ops = rel_ops; + } + + @Override + public int compare(int o_1, int o_2) { + return m_rel_ops.compareOverlapEvents_(o_1, o_2); + } + + private RelationalOperations m_rel_ops; + } + + int compareOverlapEvents_(int o_1, int o_2) { + OverlapEvent overlapEvent1 = m_overlap_events.get(o_1); + OverlapEvent overlapEvent2 = m_overlap_events.get(o_2); + + if (overlapEvent1.m_ipath_a < overlapEvent2.m_ipath_a) + return -1; + + if (overlapEvent1.m_ipath_a == overlapEvent2.m_ipath_a) { + if (overlapEvent1.m_ivertex_a < overlapEvent2.m_ivertex_a) + return -1; + + if (overlapEvent1.m_ivertex_a == overlapEvent2.m_ivertex_a) { + if (overlapEvent1.m_scalar_a_0 < overlapEvent2.m_scalar_a_0) + return -1; + + if (overlapEvent1.m_scalar_a_0 == overlapEvent2.m_scalar_a_0) { + if (overlapEvent1.m_scalar_a_1 < overlapEvent2.m_scalar_a_1) + return -1; + + if (overlapEvent1.m_scalar_a_1 == overlapEvent2.m_scalar_a_1) { + if (overlapEvent1.m_ivertex_b < overlapEvent2.m_ivertex_b) + return -1; + } + } + } + } + + return 1; + } + + static final class Accelerate_helper { + static boolean accelerate_geometry(Geometry geometry, + SpatialReference sr, + Geometry.GeometryAccelerationDegree accel_degree) { + if (!can_accelerate_geometry(geometry)) + return false; + + double tol = InternalUtils.calculateToleranceFromGeometry(sr, + geometry, false); + boolean bAccelerated = false; + if (GeometryAccelerators.canUseRasterizedGeometry(geometry)) + bAccelerated |= ((MultiVertexGeometryImpl) geometry._getImpl()) + ._buildRasterizedGeometryAccelerator(tol, accel_degree); + + Geometry.Type type = geometry.getType(); + if ((type == Geometry.Type.Polygon || type == Geometry.Type.Polyline) + && GeometryAccelerators.canUseQuadTree(geometry) + && accel_degree != Geometry.GeometryAccelerationDegree.enumMild) + bAccelerated |= ((MultiVertexGeometryImpl) geometry._getImpl()) + ._buildQuadTreeAccelerator(accel_degree); + + if ((type == Geometry.Type.Polygon || type == Geometry.Type.Polyline) + && GeometryAccelerators.canUseQuadTreeForPaths(geometry) + && accel_degree != Geometry.GeometryAccelerationDegree.enumMild) + bAccelerated |= ((MultiPathImpl) geometry._getImpl()) + ._buildQuadTreeForPathsAccelerator(accel_degree); + + return bAccelerated; + } static boolean can_accelerate_geometry(Geometry geometry) { return GeometryAccelerators.canUseRasterizedGeometry(geometry) diff --git a/src/main/java/com/esri/core/geometry/RelationalOperationsMatrix.java b/src/main/java/com/esri/core/geometry/RelationalOperationsMatrix.java index 7b01ff75..1d93f5c8 100644 --- a/src/main/java/com/esri/core/geometry/RelationalOperationsMatrix.java +++ b/src/main/java/com/esri/core/geometry/RelationalOperationsMatrix.java @@ -24,49 +24,50 @@ package com.esri.core.geometry; class RelationalOperationsMatrix { - private TopoGraph m_topo_graph; - private int[] m_matrix; + private TopoGraph m_topo_graph; + private int[] m_matrix; private int[] m_max_dim; - private boolean[] m_perform_predicates; - private String m_scl; - private int m_predicates_half_edge; + private boolean[] m_perform_predicates; + private String m_scl; + private int m_predicates_half_edge; private int m_predicates_cluster; - private int m_predicate_count; - private int m_cluster_index_a; - private int m_cluster_index_b; - private int m_visited_index; - - private interface MatrixPredicate { - static final int InteriorInterior = 0; - static final int InteriorBoundary = 1; - static final int InteriorExterior = 2; - static final int BoundaryInterior = 3; - static final int BoundaryBoundary = 4; - static final int BoundaryExterior = 5; - static final int ExteriorInterior = 6; - static final int ExteriorBoundary = 7; - static final int ExteriorExterior = 8; - } - - private interface Predicates { - static final int AreaAreaPredicates = 0; - static final int AreaLinePredicates = 1; - static final int LineLinePredicates = 2; - static final int AreaPointPredicates = 3; - static final int LinePointPredicates = 4; - static final int PointPointPredicates = 5; - } - - // Computes the necessary 9 intersection relationships of boundary, - // interior, and exterior of geometry_a vs geometry_b for the given scl - // string. - static boolean relate(Geometry geometry_a, Geometry geometry_b, - SpatialReference sr, String scl, ProgressTracker progress_tracker) { + private int m_predicate_count; + private int m_cluster_index_a; + private int m_cluster_index_b; + private int m_visited_index; + + private interface MatrixPredicate { + static final int InteriorInterior = 0; + static final int InteriorBoundary = 1; + static final int InteriorExterior = 2; + static final int BoundaryInterior = 3; + static final int BoundaryBoundary = 4; + static final int BoundaryExterior = 5; + static final int ExteriorInterior = 6; + static final int ExteriorBoundary = 7; + static final int ExteriorExterior = 8; + } + + private interface Predicates { + static final int AreaAreaPredicates = 0; + static final int AreaLinePredicates = 1; + static final int LineLinePredicates = 2; + static final int AreaPointPredicates = 3; + static final int LinePointPredicates = 4; + static final int PointPointPredicates = 5; + } + + // Computes the necessary 9 intersection relationships of boundary, + // interior, and exterior of geometry_a vs geometry_b for the given scl + // string. + static boolean relate(Geometry geometry_a, Geometry geometry_b, + SpatialReference sr, String scl, ProgressTracker progress_tracker) { if (scl.length() != 9) throw new GeometryException("relation string length has to be 9 characters"); - for (int i = 0; i < 9; i++) { + for (int i = 0; i < 9; i++) + { char c = scl.charAt(i); if (c != '*' && c != 'T' && c != 'F' && c != '0' && c != '1' && c != '2') @@ -74,230 +75,231 @@ static boolean relate(Geometry geometry_a, Geometry geometry_b, } int relation = getPredefinedRelation_(scl, geometry_a.getDimension(), - geometry_b.getDimension()); + geometry_b.getDimension()); - if (relation != RelationalOperations.Relation.unknown) - return RelationalOperations.relate(geometry_a, geometry_b, sr, - relation, progress_tracker); + if (relation != RelationalOperations.Relation.unknown) + return RelationalOperations.relate(geometry_a, geometry_b, sr, + relation, progress_tracker); - Envelope2D env1 = new Envelope2D(); - geometry_a.queryEnvelope2D(env1); - Envelope2D env2 = new Envelope2D(); - geometry_b.queryEnvelope2D(env2); + Envelope2D env1 = new Envelope2D(); + geometry_a.queryEnvelope2D(env1); + Envelope2D env2 = new Envelope2D(); + geometry_b.queryEnvelope2D(env2); - Envelope2D envMerged = new Envelope2D(); - envMerged.setCoords(env1); - envMerged.merge(env2); - double tolerance = InternalUtils.calculateToleranceFromGeometry(sr, - envMerged, false); + Envelope2D envMerged = new Envelope2D(); + envMerged.setCoords(env1); + envMerged.merge(env2); + double tolerance = InternalUtils.calculateToleranceFromGeometry(sr, + envMerged, false); - Geometry _geometryA = convertGeometry_(geometry_a, tolerance); - Geometry _geometryB = convertGeometry_(geometry_b, tolerance); + Geometry _geometryA = convertGeometry_(geometry_a, tolerance); + Geometry _geometryB = convertGeometry_(geometry_b, tolerance); if (_geometryA.isEmpty() || _geometryB.isEmpty()) return relateEmptyGeometries_(_geometryA, _geometryB, scl); - int typeA = _geometryA.getType().value(); - int typeB = _geometryB.getType().value(); - - boolean bRelation = false; - - switch (typeA) { - case Geometry.GeometryType.Polygon: - switch (typeB) { - case Geometry.GeometryType.Polygon: - bRelation = polygonRelatePolygon_((Polygon) (_geometryA), - (Polygon) (_geometryB), tolerance, scl, - progress_tracker); - break; - - case Geometry.GeometryType.Polyline: - bRelation = polygonRelatePolyline_((Polygon) (_geometryA), - (Polyline) (_geometryB), tolerance, scl, - progress_tracker); - break; - - case Geometry.GeometryType.Point: - bRelation = polygonRelatePoint_((Polygon) (_geometryA), - (Point) (_geometryB), tolerance, scl, progress_tracker); - break; - - case Geometry.GeometryType.MultiPoint: - bRelation = polygonRelateMultiPoint_((Polygon) (_geometryA), - (MultiPoint) (_geometryB), tolerance, scl, - progress_tracker); - break; - - default: - break; // warning fix - } - break; - - case Geometry.GeometryType.Polyline: - switch (typeB) { - case Geometry.GeometryType.Polygon: - bRelation = polygonRelatePolyline_((Polygon) (_geometryB), - (Polyline) (_geometryA), tolerance, - getTransposeMatrix_(scl), progress_tracker); - break; - - case Geometry.GeometryType.Polyline: - bRelation = polylineRelatePolyline_((Polyline) (_geometryA), - (Polyline) (_geometryB), tolerance, scl, - progress_tracker); - break; - - case Geometry.GeometryType.Point: - bRelation = polylineRelatePoint_((Polyline) (_geometryA), - (Point) (_geometryB), tolerance, scl, progress_tracker); - break; - - case Geometry.GeometryType.MultiPoint: - bRelation = polylineRelateMultiPoint_((Polyline) (_geometryA), - (MultiPoint) (_geometryB), tolerance, scl, - progress_tracker); - break; - - default: - break; // warning fix - } - break; - - case Geometry.GeometryType.Point: - switch (typeB) { - case Geometry.GeometryType.Polygon: - bRelation = polygonRelatePoint_((Polygon) (_geometryB), - (Point) (_geometryA), tolerance, - getTransposeMatrix_(scl), progress_tracker); - break; - - case Geometry.GeometryType.Polyline: - bRelation = polylineRelatePoint_((Polyline) (_geometryB), - (Point) (_geometryA), tolerance, - getTransposeMatrix_(scl), progress_tracker); - break; - - case Geometry.GeometryType.Point: - bRelation = pointRelatePoint_((Point) (_geometryA), - (Point) (_geometryB), tolerance, scl, progress_tracker); - break; - - case Geometry.GeometryType.MultiPoint: - bRelation = multiPointRelatePoint_((MultiPoint) (_geometryB), - (Point) (_geometryA), tolerance, - getTransposeMatrix_(scl), progress_tracker); - break; - - default: - break; // warning fix - } - break; - - case Geometry.GeometryType.MultiPoint: - switch (typeB) { - case Geometry.GeometryType.Polygon: - bRelation = polygonRelateMultiPoint_((Polygon) (_geometryB), - (MultiPoint) (_geometryA), tolerance, - getTransposeMatrix_(scl), progress_tracker); - break; - - case Geometry.GeometryType.Polyline: - bRelation = polylineRelateMultiPoint_((Polyline) (_geometryB), - (MultiPoint) (_geometryA), tolerance, - getTransposeMatrix_(scl), progress_tracker); - break; - - case Geometry.GeometryType.MultiPoint: - bRelation = multiPointRelateMultiPoint_( - (MultiPoint) (_geometryA), (MultiPoint) (_geometryB), - tolerance, scl, progress_tracker); - break; - - case Geometry.GeometryType.Point: - bRelation = multiPointRelatePoint_((MultiPoint) (_geometryA), - (Point) (_geometryB), tolerance, scl, progress_tracker); - break; - - default: - break; // warning fix - } - break; - default: - bRelation = false; - break; - } - - return bRelation; - } - - private RelationalOperationsMatrix() { - m_predicate_count = 0; - m_topo_graph = new TopoGraph(); - m_matrix = new int[9]; + int typeA = _geometryA.getType().value(); + int typeB = _geometryB.getType().value(); + + boolean bRelation = false; + + switch (typeA) { + case Geometry.GeometryType.Polygon: + switch (typeB) { + case Geometry.GeometryType.Polygon: + bRelation = polygonRelatePolygon_((Polygon) (_geometryA), + (Polygon) (_geometryB), tolerance, scl, + progress_tracker); + break; + + case Geometry.GeometryType.Polyline: + bRelation = polygonRelatePolyline_((Polygon) (_geometryA), + (Polyline) (_geometryB), tolerance, scl, + progress_tracker); + break; + + case Geometry.GeometryType.Point: + bRelation = polygonRelatePoint_((Polygon) (_geometryA), + (Point) (_geometryB), tolerance, scl, progress_tracker); + break; + + case Geometry.GeometryType.MultiPoint: + bRelation = polygonRelateMultiPoint_((Polygon) (_geometryA), + (MultiPoint) (_geometryB), tolerance, scl, + progress_tracker); + break; + + default: + break; // warning fix + } + break; + + case Geometry.GeometryType.Polyline: + switch (typeB) { + case Geometry.GeometryType.Polygon: + bRelation = polygonRelatePolyline_((Polygon) (_geometryB), + (Polyline) (_geometryA), tolerance, + getTransposeMatrix_(scl), progress_tracker); + break; + + case Geometry.GeometryType.Polyline: + bRelation = polylineRelatePolyline_((Polyline) (_geometryA), + (Polyline) (_geometryB), tolerance, scl, + progress_tracker); + break; + + case Geometry.GeometryType.Point: + bRelation = polylineRelatePoint_((Polyline) (_geometryA), + (Point) (_geometryB), tolerance, scl, progress_tracker); + break; + + case Geometry.GeometryType.MultiPoint: + bRelation = polylineRelateMultiPoint_((Polyline) (_geometryA), + (MultiPoint) (_geometryB), tolerance, scl, + progress_tracker); + break; + + default: + break; // warning fix + } + break; + + case Geometry.GeometryType.Point: + switch (typeB) { + case Geometry.GeometryType.Polygon: + bRelation = polygonRelatePoint_((Polygon) (_geometryB), + (Point) (_geometryA), tolerance, + getTransposeMatrix_(scl), progress_tracker); + break; + + case Geometry.GeometryType.Polyline: + bRelation = polylineRelatePoint_((Polyline) (_geometryB), + (Point) (_geometryA), tolerance, + getTransposeMatrix_(scl), progress_tracker); + break; + + case Geometry.GeometryType.Point: + bRelation = pointRelatePoint_((Point) (_geometryA), + (Point) (_geometryB), tolerance, scl, progress_tracker); + break; + + case Geometry.GeometryType.MultiPoint: + bRelation = multiPointRelatePoint_((MultiPoint) (_geometryB), + (Point) (_geometryA), tolerance, + getTransposeMatrix_(scl), progress_tracker); + break; + + default: + break; // warning fix + } + break; + + case Geometry.GeometryType.MultiPoint: + switch (typeB) { + case Geometry.GeometryType.Polygon: + bRelation = polygonRelateMultiPoint_((Polygon) (_geometryB), + (MultiPoint) (_geometryA), tolerance, + getTransposeMatrix_(scl), progress_tracker); + break; + + case Geometry.GeometryType.Polyline: + bRelation = polylineRelateMultiPoint_((Polyline) (_geometryB), + (MultiPoint) (_geometryA), tolerance, + getTransposeMatrix_(scl), progress_tracker); + break; + + case Geometry.GeometryType.MultiPoint: + bRelation = multiPointRelateMultiPoint_( + (MultiPoint) (_geometryA), (MultiPoint) (_geometryB), + tolerance, scl, progress_tracker); + break; + + case Geometry.GeometryType.Point: + bRelation = multiPointRelatePoint_((MultiPoint) (_geometryA), + (Point) (_geometryB), tolerance, scl, progress_tracker); + break; + + default: + break; // warning fix + } + break; + default: + bRelation = false; + break; + } + + return bRelation; + } + + private RelationalOperationsMatrix() { + m_predicate_count = 0; + m_topo_graph = new TopoGraph(); + m_matrix = new int[9]; m_max_dim = new int[9]; - m_perform_predicates = new boolean[9]; + m_perform_predicates = new boolean[9]; m_predicates_half_edge = -1; - m_predicates_cluster = -1; - } - - // Returns true if the relation holds. - static boolean polygonRelatePolygon_(Polygon polygon_a, Polygon polygon_b, - double tolerance, String scl, ProgressTracker progress_tracker) { - RelationalOperationsMatrix relOps = new RelationalOperationsMatrix(); - relOps.resetMatrix_(); - relOps.setPredicates_(scl); - relOps.setAreaAreaPredicates_(); - - Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(); - polygon_a.queryEnvelope2D(env_a); - polygon_b.queryEnvelope2D(env_b); - - boolean bRelationKnown = false; - boolean b_disjoint = RelationalOperations.envelopeDisjointEnvelope_( - env_a, env_b, tolerance, progress_tracker); - - if (b_disjoint) { - relOps.areaAreaDisjointPredicates_(polygon_a, polygon_b); - bRelationKnown = true; - } - - if (!bRelationKnown) { - // Quick rasterize test to see whether the the geometries are - // disjoint, or if one is contained in the other. - int relation = RelationalOperations - .tryRasterizedContainsOrDisjoint_(polygon_a, polygon_b, - tolerance, false); - - if (relation == RelationalOperations.Relation.disjoint) { - relOps.areaAreaDisjointPredicates_(polygon_a, polygon_b); - bRelationKnown = true; - } else if (relation == RelationalOperations.Relation.contains) { - relOps.areaAreaContainsPredicates_(polygon_b); - bRelationKnown = true; - } else if (relation == RelationalOperations.Relation.within) { - relOps.areaAreaWithinPredicates_(polygon_a); - bRelationKnown = true; - } - } - - if (!bRelationKnown) { - EditShape edit_shape = new EditShape(); - int geom_a = edit_shape.addGeometry(polygon_a); - int geom_b = edit_shape.addGeometry(polygon_b); - relOps.setEditShapeCrackAndCluster_(edit_shape, tolerance, - progress_tracker); - relOps.computeMatrixTopoGraphHalfEdges_(geom_a, geom_b); - relOps.m_topo_graph.removeShape(); - } - - boolean bRelation = relationCompare_(relOps.m_matrix, relOps.m_scl); - return bRelation; - } + m_predicates_cluster = -1; + } + + // Returns true if the relation holds. + static boolean polygonRelatePolygon_(Polygon polygon_a, Polygon polygon_b, + double tolerance, String scl, ProgressTracker progress_tracker) { + RelationalOperationsMatrix relOps = new RelationalOperationsMatrix(); + relOps.resetMatrix_(); + relOps.setPredicates_(scl); + relOps.setAreaAreaPredicates_(); + + Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(); + polygon_a.queryEnvelope2D(env_a); + polygon_b.queryEnvelope2D(env_b); + + boolean bRelationKnown = false; + boolean b_disjoint = RelationalOperations.envelopeDisjointEnvelope_( + env_a, env_b, tolerance, progress_tracker); + + if (b_disjoint) { + relOps.areaAreaDisjointPredicates_(polygon_a, polygon_b); + bRelationKnown = true; + } + + if (!bRelationKnown) { + // Quick rasterize test to see whether the the geometries are + // disjoint, or if one is contained in the other. + int relation = RelationalOperations + .tryRasterizedContainsOrDisjoint_(polygon_a, polygon_b, + tolerance, false); + + if (relation == RelationalOperations.Relation.disjoint) { + relOps.areaAreaDisjointPredicates_(polygon_a, polygon_b); + bRelationKnown = true; + } else if (relation == RelationalOperations.Relation.contains) { + relOps.areaAreaContainsPredicates_(polygon_b); + bRelationKnown = true; + } else if (relation == RelationalOperations.Relation.within) { + relOps.areaAreaWithinPredicates_(polygon_a); + bRelationKnown = true; + } + } + + if (!bRelationKnown) { + EditShape edit_shape = new EditShape(); + int geom_a = edit_shape.addGeometry(polygon_a); + int geom_b = edit_shape.addGeometry(polygon_b); + relOps.setEditShapeCrackAndCluster_(edit_shape, tolerance, + progress_tracker); + relOps.computeMatrixTopoGraphHalfEdges_(geom_a, geom_b); + relOps.m_topo_graph.removeShape(); + } + + boolean bRelation = relationCompare_(relOps.m_matrix, relOps.m_scl); + return bRelation; + } // The relation is based on the simplified-Polygon A containing Polygon B, which may be non-simple. - static boolean polygonContainsPolygon_(Polygon polygon_a, Polygon polygon_b, double tolerance, ProgressTracker progress_tracker) { - assert (!polygon_a.isEmpty()); - assert (!polygon_b.isEmpty()); + static boolean polygonContainsPolygon_(Polygon polygon_a, Polygon polygon_b, double tolerance, ProgressTracker progress_tracker) + { + assert(!polygon_a.isEmpty()); + assert(!polygon_b.isEmpty()); RelationalOperationsMatrix relOps = new RelationalOperationsMatrix(); relOps.resetMatrix_(); @@ -311,28 +313,36 @@ static boolean polygonContainsPolygon_(Polygon polygon_a, Polygon polygon_b, dou boolean bRelationKnown = false; boolean b_disjoint = RelationalOperations.envelopeDisjointEnvelope_(env_a, env_b, tolerance, progress_tracker); - if (b_disjoint) { + if (b_disjoint) + { relOps.areaAreaDisjointPredicates_(polygon_a, polygon_b); bRelationKnown = true; } - if (!bRelationKnown) { + if (!bRelationKnown) + { // Quick rasterize test to see whether the the geometries are disjoint, or if one is contained in the other. int relation = RelationalOperations.tryRasterizedContainsOrDisjoint_(polygon_a, polygon_b, tolerance, false); - if (relation == RelationalOperations.Relation.disjoint) { + if (relation == RelationalOperations.Relation.disjoint) + { relOps.areaAreaDisjointPredicates_(polygon_a, polygon_b); bRelationKnown = true; - } else if (relation == RelationalOperations.Relation.contains) { + } + else if (relation == RelationalOperations.Relation.contains) + { relOps.areaAreaContainsPredicates_(polygon_b); bRelationKnown = true; - } else if (relation == RelationalOperations.Relation.within) { + } + else if (relation == RelationalOperations.Relation.within) + { relOps.areaAreaWithinPredicates_(polygon_a); bRelationKnown = true; } } - if (bRelationKnown) { + if (bRelationKnown) + { boolean bContains = relationCompare_(relOps.m_matrix, relOps.m_scl); return bContains; } @@ -342,7 +352,7 @@ static boolean polygonContainsPolygon_(Polygon polygon_a, Polygon polygon_b, dou int geom_b = edit_shape.addGeometry(polygon_b); CrackAndCluster.execute(edit_shape, tolerance, progress_tracker, false); - Polyline boundary_b = (Polyline) edit_shape.getGeometry(geom_b).getBoundary(); + Polyline boundary_b = (Polyline)edit_shape.getGeometry(geom_b).getBoundary(); edit_shape.filterClosePoints(0, true, true); Simplificator.execute(edit_shape, geom_a, -1, false, progress_tracker); @@ -359,7 +369,8 @@ static boolean polygonContainsPolygon_(Polygon polygon_a, Polygon polygon_b, dou boolean b_empty = edit_shape.getPointCount(geom_b) == 0; - if (!b_empty) {//geom_b has interior + if (!b_empty) + {//geom_b has interior relOps.computeMatrixTopoGraphHalfEdges_(geom_a, geom_b); relOps.m_topo_graph.removeShape(); boolean bContains = relationCompare_(relOps.m_matrix, relOps.m_scl); @@ -368,7 +379,7 @@ static boolean polygonContainsPolygon_(Polygon polygon_a, Polygon polygon_b, dou return bContains; } - Polygon polygon_simple_a = (Polygon) edit_shape.getGeometry(geom_a); + Polygon polygon_simple_a = (Polygon)edit_shape.getGeometry(geom_a); edit_shape = new EditShape(); geom_a = edit_shape.addGeometry(polygon_simple_a); geom_b = edit_shape.addGeometry(boundary_b); @@ -386,73 +397,74 @@ static boolean polygonContainsPolygon_(Polygon polygon_a, Polygon polygon_b, dou return bContains; } - // Returns true if the relation holds. - static boolean polygonRelatePolyline_(Polygon polygon_a, - Polyline polyline_b, double tolerance, String scl, - ProgressTracker progress_tracker) { - RelationalOperationsMatrix relOps = new RelationalOperationsMatrix(); - relOps.resetMatrix_(); - relOps.setPredicates_(scl); - relOps.setAreaLinePredicates_(); - - Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(); - polygon_a.queryEnvelope2D(env_a); - polyline_b.queryEnvelope2D(env_b); - - boolean bRelationKnown = false; - boolean b_disjoint = RelationalOperations.envelopeDisjointEnvelope_( - env_a, env_b, tolerance, progress_tracker); - - if (b_disjoint) { - relOps.areaLineDisjointPredicates_(polygon_a, polyline_b); // passing polyline - // to get boundary - // information - bRelationKnown = true; - } - - if (!bRelationKnown) { - // Quick rasterize test to see whether the the geometries are - // disjoint, or if one is contained in the other. - int relation = RelationalOperations - .tryRasterizedContainsOrDisjoint_(polygon_a, polyline_b, - tolerance, false); - - if (relation == RelationalOperations.Relation.disjoint) { - relOps.areaLineDisjointPredicates_(polygon_a, polyline_b); // passing - // polyline to - // get boundary - // information - bRelationKnown = true; - } else if (relation == RelationalOperations.Relation.contains) { - relOps.areaLineContainsPredicates_(polygon_a, polyline_b); // passing - // polyline to - // get boundary - // information - bRelationKnown = true; - } - } - - if (!bRelationKnown) { - EditShape edit_shape = new EditShape(); - int geom_a = edit_shape.addGeometry(polygon_a); - int geom_b = edit_shape.addGeometry(polyline_b); - relOps.setEditShapeCrackAndCluster_(edit_shape, tolerance, - progress_tracker); - relOps.m_cluster_index_b = relOps.m_topo_graph - .createUserIndexForClusters(); - markClusterEndPoints_(geom_b, relOps.m_topo_graph, - relOps.m_cluster_index_b); - relOps.computeMatrixTopoGraphHalfEdges_(geom_a, geom_b); - relOps.m_topo_graph - .deleteUserIndexForClusters(relOps.m_cluster_index_b); - relOps.m_topo_graph.removeShape(); - } - - boolean bRelation = relationCompare_(relOps.m_matrix, relOps.m_scl); - return bRelation; - } - - static boolean polygonContainsPolyline_(Polygon polygon_a, Polyline polyline_b, double tolerance, ProgressTracker progress_tracker) { + // Returns true if the relation holds. + static boolean polygonRelatePolyline_(Polygon polygon_a, + Polyline polyline_b, double tolerance, String scl, + ProgressTracker progress_tracker) { + RelationalOperationsMatrix relOps = new RelationalOperationsMatrix(); + relOps.resetMatrix_(); + relOps.setPredicates_(scl); + relOps.setAreaLinePredicates_(); + + Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(); + polygon_a.queryEnvelope2D(env_a); + polyline_b.queryEnvelope2D(env_b); + + boolean bRelationKnown = false; + boolean b_disjoint = RelationalOperations.envelopeDisjointEnvelope_( + env_a, env_b, tolerance, progress_tracker); + + if (b_disjoint) { + relOps.areaLineDisjointPredicates_(polygon_a, polyline_b); // passing polyline + // to get boundary + // information + bRelationKnown = true; + } + + if (!bRelationKnown) { + // Quick rasterize test to see whether the the geometries are + // disjoint, or if one is contained in the other. + int relation = RelationalOperations + .tryRasterizedContainsOrDisjoint_(polygon_a, polyline_b, + tolerance, false); + + if (relation == RelationalOperations.Relation.disjoint) { + relOps.areaLineDisjointPredicates_(polygon_a, polyline_b); // passing + // polyline to + // get boundary + // information + bRelationKnown = true; + } else if (relation == RelationalOperations.Relation.contains) { + relOps.areaLineContainsPredicates_(polygon_a, polyline_b); // passing + // polyline to + // get boundary + // information + bRelationKnown = true; + } + } + + if (!bRelationKnown) { + EditShape edit_shape = new EditShape(); + int geom_a = edit_shape.addGeometry(polygon_a); + int geom_b = edit_shape.addGeometry(polyline_b); + relOps.setEditShapeCrackAndCluster_(edit_shape, tolerance, + progress_tracker); + relOps.m_cluster_index_b = relOps.m_topo_graph + .createUserIndexForClusters(); + markClusterEndPoints_(geom_b, relOps.m_topo_graph, + relOps.m_cluster_index_b); + relOps.computeMatrixTopoGraphHalfEdges_(geom_a, geom_b); + relOps.m_topo_graph + .deleteUserIndexForClusters(relOps.m_cluster_index_b); + relOps.m_topo_graph.removeShape(); + } + + boolean bRelation = relationCompare_(relOps.m_matrix, relOps.m_scl); + return bRelation; + } + + static boolean polygonContainsPolyline_(Polygon polygon_a, Polyline polyline_b, double tolerance, ProgressTracker progress_tracker) + { RelationalOperationsMatrix relOps = new RelationalOperationsMatrix(); relOps.resetMatrix_(); relOps.setPredicates_("T*****F**"); @@ -465,25 +477,31 @@ static boolean polygonContainsPolyline_(Polygon polygon_a, Polyline polyline_b, boolean bRelationKnown = false; boolean b_disjoint = RelationalOperations.envelopeDisjointEnvelope_(env_a, env_b, tolerance, progress_tracker); - if (b_disjoint) { + if (b_disjoint) + { relOps.areaLineDisjointPredicates_(polygon_a, polyline_b); // passing polyline to get boundary information bRelationKnown = true; } - if (!bRelationKnown) { + if (!bRelationKnown) + { // Quick rasterize test to see whether the the geometries are disjoint, or if one is contained in the other. int relation = RelationalOperations.tryRasterizedContainsOrDisjoint_(polygon_a, polyline_b, tolerance, false); - if (relation == RelationalOperations.Relation.disjoint) { + if (relation == RelationalOperations.Relation.disjoint) + { relOps.areaLineDisjointPredicates_(polygon_a, polyline_b); // passing polyline to get boundary information bRelationKnown = true; - } else if (relation == RelationalOperations.Relation.contains) { + } + else if (relation == RelationalOperations.Relation.contains) + { relOps.areaLineContainsPredicates_(polygon_a, polyline_b); // passing polyline to get boundary information bRelationKnown = true; } } - if (bRelationKnown) { + if (bRelationKnown) + { boolean bContains = relationCompare_(relOps.m_matrix, relOps.m_scl); return bContains; } @@ -505,213 +523,213 @@ static boolean polygonContainsPolyline_(Polygon polygon_a, Polyline polyline_b, return bContains; } - // Returns true if the relation holds - static boolean polygonRelateMultiPoint_(Polygon polygon_a, - MultiPoint multipoint_b, double tolerance, String scl, - ProgressTracker progress_tracker) { - RelationalOperationsMatrix relOps = new RelationalOperationsMatrix(); - relOps.resetMatrix_(); - relOps.setPredicates_(scl); - relOps.setAreaPointPredicates_(); - - Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(); - polygon_a.queryEnvelope2D(env_a); - multipoint_b.queryEnvelope2D(env_b); - - boolean bRelationKnown = false; - boolean b_disjoint = RelationalOperations.envelopeDisjointEnvelope_( - env_a, env_b, tolerance, progress_tracker); - - if (b_disjoint) { - relOps.areaPointDisjointPredicates_(polygon_a); - bRelationKnown = true; - } - - if (!bRelationKnown) { - // Quick rasterize test to see whether the the geometries are - // disjoint, or if one is contained in the other. - int relation = RelationalOperations - .tryRasterizedContainsOrDisjoint_(polygon_a, multipoint_b, - tolerance, false); - - if (relation == RelationalOperations.Relation.disjoint) { - relOps.areaPointDisjointPredicates_(polygon_a); - bRelationKnown = true; - } else if (relation == RelationalOperations.Relation.contains) { - relOps.areaPointContainsPredicates_(polygon_a); - bRelationKnown = true; - } - } - - if (!bRelationKnown) { - EditShape edit_shape = new EditShape(); - int geom_a = edit_shape.addGeometry(polygon_a); - int geom_b = edit_shape.addGeometry(multipoint_b); - relOps.setEditShapeCrackAndCluster_(edit_shape, tolerance, - progress_tracker); - relOps.computeMatrixTopoGraphClusters_(geom_a, geom_b); - relOps.m_topo_graph.removeShape(); - } - - boolean bRelation = relationCompare_(relOps.m_matrix, relOps.m_scl); - return bRelation; - } - - // Returns true if the relation holds. - static boolean polylineRelatePolyline_(Polyline polyline_a, - Polyline polyline_b, double tolerance, String scl, - ProgressTracker progress_tracker) { - RelationalOperationsMatrix relOps = new RelationalOperationsMatrix(); - relOps.resetMatrix_(); - relOps.setPredicates_(scl); - relOps.setLineLinePredicates_(); - - Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(); - polyline_a.queryEnvelope2D(env_a); - polyline_b.queryEnvelope2D(env_b); - - boolean bRelationKnown = false; - boolean b_disjoint = RelationalOperations.envelopeDisjointEnvelope_( - env_a, env_b, tolerance, progress_tracker); - - if (b_disjoint) { - relOps.lineLineDisjointPredicates_(polyline_a, polyline_b); - bRelationKnown = true; - } - - if (!bRelationKnown) { - // Quick rasterize test to see whether the the geometries are - // disjoint, or if one is contained in the other. - int relation = RelationalOperations - .tryRasterizedContainsOrDisjoint_(polyline_a, polyline_b, - tolerance, false); - - if (relation == RelationalOperations.Relation.disjoint) { - relOps.lineLineDisjointPredicates_(polyline_a, polyline_b); - bRelationKnown = true; - } - } - - if (!bRelationKnown) { - EditShape edit_shape = new EditShape(); - int geom_a = edit_shape.addGeometry(polyline_a); - int geom_b = edit_shape.addGeometry(polyline_b); - relOps.setEditShapeCrackAndCluster_(edit_shape, tolerance, - progress_tracker); - relOps.m_cluster_index_a = relOps.m_topo_graph - .createUserIndexForClusters(); - relOps.m_cluster_index_b = relOps.m_topo_graph - .createUserIndexForClusters(); - markClusterEndPoints_(geom_a, relOps.m_topo_graph, - relOps.m_cluster_index_a); - markClusterEndPoints_(geom_b, relOps.m_topo_graph, - relOps.m_cluster_index_b); - relOps.computeMatrixTopoGraphHalfEdges_(geom_a, geom_b); - relOps.m_topo_graph - .deleteUserIndexForClusters(relOps.m_cluster_index_a); - relOps.m_topo_graph - .deleteUserIndexForClusters(relOps.m_cluster_index_b); - relOps.m_topo_graph.removeShape(); - } - - boolean bRelation = relationCompare_(relOps.m_matrix, relOps.m_scl); - return bRelation; - } - - // Returns true if the relation holds. - static boolean polylineRelateMultiPoint_(Polyline polyline_a, - MultiPoint multipoint_b, double tolerance, String scl, - ProgressTracker progress_tracker) { - RelationalOperationsMatrix relOps = new RelationalOperationsMatrix(); - relOps.resetMatrix_(); - relOps.setPredicates_(scl); - relOps.setLinePointPredicates_(); - - Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(); - polyline_a.queryEnvelope2D(env_a); - multipoint_b.queryEnvelope2D(env_b); - - boolean bRelationKnown = false; - boolean b_disjoint = RelationalOperations.envelopeDisjointEnvelope_( - env_a, env_b, tolerance, progress_tracker); - - if (b_disjoint) { - relOps.linePointDisjointPredicates_(polyline_a); - bRelationKnown = true; - } - - if (!bRelationKnown) { - // Quick rasterize test to see whether the the geometries are - // disjoint, or if one is contained in the other. - int relation = RelationalOperations - .tryRasterizedContainsOrDisjoint_(polyline_a, multipoint_b, - tolerance, false); - - if (relation == RelationalOperations.Relation.disjoint) { - relOps.linePointDisjointPredicates_(polyline_a); - bRelationKnown = true; - } - } - - if (!bRelationKnown) { - EditShape edit_shape = new EditShape(); - int geom_a = edit_shape.addGeometry(polyline_a); - int geom_b = edit_shape.addGeometry(multipoint_b); - relOps.setEditShapeCrackAndCluster_(edit_shape, tolerance, - progress_tracker); - relOps.m_cluster_index_a = relOps.m_topo_graph - .createUserIndexForClusters(); - markClusterEndPoints_(geom_a, relOps.m_topo_graph, - relOps.m_cluster_index_a); - relOps.computeMatrixTopoGraphClusters_(geom_a, geom_b); - relOps.m_topo_graph - .deleteUserIndexForClusters(relOps.m_cluster_index_a); - relOps.m_topo_graph.removeShape(); - } - - boolean bRelation = relationCompare_(relOps.m_matrix, relOps.m_scl); - return bRelation; - } - - // Returns true if the relation holds. - static boolean multiPointRelateMultiPoint_(MultiPoint multipoint_a, - MultiPoint multipoint_b, double tolerance, String scl, - ProgressTracker progress_tracker) { - RelationalOperationsMatrix relOps = new RelationalOperationsMatrix(); - relOps.resetMatrix_(); - relOps.setPredicates_(scl); - relOps.setPointPointPredicates_(); - - Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(); - multipoint_a.queryEnvelope2D(env_a); - multipoint_b.queryEnvelope2D(env_b); - - boolean bRelationKnown = false; - boolean b_disjoint = RelationalOperations.envelopeDisjointEnvelope_( - env_a, env_b, tolerance, progress_tracker); - - if (b_disjoint) { - relOps.pointPointDisjointPredicates_(); - bRelationKnown = true; - } - - if (!bRelationKnown) { - EditShape edit_shape = new EditShape(); - int geom_a = edit_shape.addGeometry(multipoint_a); - int geom_b = edit_shape.addGeometry(multipoint_b); - relOps.setEditShapeCrackAndCluster_(edit_shape, tolerance, - progress_tracker); - relOps.computeMatrixTopoGraphClusters_(geom_a, geom_b); - relOps.m_topo_graph.removeShape(); - } - - boolean bRelation = relationCompare_(relOps.m_matrix, relOps.m_scl); - return bRelation; - } - - // Returns true if the relation holds. - static boolean polygonRelatePoint_(Polygon polygon_a, Point point_b, - double tolerance, String scl, ProgressTracker progress_tracker) { + // Returns true if the relation holds + static boolean polygonRelateMultiPoint_(Polygon polygon_a, + MultiPoint multipoint_b, double tolerance, String scl, + ProgressTracker progress_tracker) { + RelationalOperationsMatrix relOps = new RelationalOperationsMatrix(); + relOps.resetMatrix_(); + relOps.setPredicates_(scl); + relOps.setAreaPointPredicates_(); + + Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(); + polygon_a.queryEnvelope2D(env_a); + multipoint_b.queryEnvelope2D(env_b); + + boolean bRelationKnown = false; + boolean b_disjoint = RelationalOperations.envelopeDisjointEnvelope_( + env_a, env_b, tolerance, progress_tracker); + + if (b_disjoint) { + relOps.areaPointDisjointPredicates_(polygon_a); + bRelationKnown = true; + } + + if (!bRelationKnown) { + // Quick rasterize test to see whether the the geometries are + // disjoint, or if one is contained in the other. + int relation = RelationalOperations + .tryRasterizedContainsOrDisjoint_(polygon_a, multipoint_b, + tolerance, false); + + if (relation == RelationalOperations.Relation.disjoint) { + relOps.areaPointDisjointPredicates_(polygon_a); + bRelationKnown = true; + } else if (relation == RelationalOperations.Relation.contains) { + relOps.areaPointContainsPredicates_(polygon_a); + bRelationKnown = true; + } + } + + if (!bRelationKnown) { + EditShape edit_shape = new EditShape(); + int geom_a = edit_shape.addGeometry(polygon_a); + int geom_b = edit_shape.addGeometry(multipoint_b); + relOps.setEditShapeCrackAndCluster_(edit_shape, tolerance, + progress_tracker); + relOps.computeMatrixTopoGraphClusters_(geom_a, geom_b); + relOps.m_topo_graph.removeShape(); + } + + boolean bRelation = relationCompare_(relOps.m_matrix, relOps.m_scl); + return bRelation; + } + + // Returns true if the relation holds. + static boolean polylineRelatePolyline_(Polyline polyline_a, + Polyline polyline_b, double tolerance, String scl, + ProgressTracker progress_tracker) { + RelationalOperationsMatrix relOps = new RelationalOperationsMatrix(); + relOps.resetMatrix_(); + relOps.setPredicates_(scl); + relOps.setLineLinePredicates_(); + + Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(); + polyline_a.queryEnvelope2D(env_a); + polyline_b.queryEnvelope2D(env_b); + + boolean bRelationKnown = false; + boolean b_disjoint = RelationalOperations.envelopeDisjointEnvelope_( + env_a, env_b, tolerance, progress_tracker); + + if (b_disjoint) { + relOps.lineLineDisjointPredicates_(polyline_a, polyline_b); + bRelationKnown = true; + } + + if (!bRelationKnown) { + // Quick rasterize test to see whether the the geometries are + // disjoint, or if one is contained in the other. + int relation = RelationalOperations + .tryRasterizedContainsOrDisjoint_(polyline_a, polyline_b, + tolerance, false); + + if (relation == RelationalOperations.Relation.disjoint) { + relOps.lineLineDisjointPredicates_(polyline_a, polyline_b); + bRelationKnown = true; + } + } + + if (!bRelationKnown) { + EditShape edit_shape = new EditShape(); + int geom_a = edit_shape.addGeometry(polyline_a); + int geom_b = edit_shape.addGeometry(polyline_b); + relOps.setEditShapeCrackAndCluster_(edit_shape, tolerance, + progress_tracker); + relOps.m_cluster_index_a = relOps.m_topo_graph + .createUserIndexForClusters(); + relOps.m_cluster_index_b = relOps.m_topo_graph + .createUserIndexForClusters(); + markClusterEndPoints_(geom_a, relOps.m_topo_graph, + relOps.m_cluster_index_a); + markClusterEndPoints_(geom_b, relOps.m_topo_graph, + relOps.m_cluster_index_b); + relOps.computeMatrixTopoGraphHalfEdges_(geom_a, geom_b); + relOps.m_topo_graph + .deleteUserIndexForClusters(relOps.m_cluster_index_a); + relOps.m_topo_graph + .deleteUserIndexForClusters(relOps.m_cluster_index_b); + relOps.m_topo_graph.removeShape(); + } + + boolean bRelation = relationCompare_(relOps.m_matrix, relOps.m_scl); + return bRelation; + } + + // Returns true if the relation holds. + static boolean polylineRelateMultiPoint_(Polyline polyline_a, + MultiPoint multipoint_b, double tolerance, String scl, + ProgressTracker progress_tracker) { + RelationalOperationsMatrix relOps = new RelationalOperationsMatrix(); + relOps.resetMatrix_(); + relOps.setPredicates_(scl); + relOps.setLinePointPredicates_(); + + Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(); + polyline_a.queryEnvelope2D(env_a); + multipoint_b.queryEnvelope2D(env_b); + + boolean bRelationKnown = false; + boolean b_disjoint = RelationalOperations.envelopeDisjointEnvelope_( + env_a, env_b, tolerance, progress_tracker); + + if (b_disjoint) { + relOps.linePointDisjointPredicates_(polyline_a); + bRelationKnown = true; + } + + if (!bRelationKnown) { + // Quick rasterize test to see whether the the geometries are + // disjoint, or if one is contained in the other. + int relation = RelationalOperations + .tryRasterizedContainsOrDisjoint_(polyline_a, multipoint_b, + tolerance, false); + + if (relation == RelationalOperations.Relation.disjoint) { + relOps.linePointDisjointPredicates_(polyline_a); + bRelationKnown = true; + } + } + + if (!bRelationKnown) { + EditShape edit_shape = new EditShape(); + int geom_a = edit_shape.addGeometry(polyline_a); + int geom_b = edit_shape.addGeometry(multipoint_b); + relOps.setEditShapeCrackAndCluster_(edit_shape, tolerance, + progress_tracker); + relOps.m_cluster_index_a = relOps.m_topo_graph + .createUserIndexForClusters(); + markClusterEndPoints_(geom_a, relOps.m_topo_graph, + relOps.m_cluster_index_a); + relOps.computeMatrixTopoGraphClusters_(geom_a, geom_b); + relOps.m_topo_graph + .deleteUserIndexForClusters(relOps.m_cluster_index_a); + relOps.m_topo_graph.removeShape(); + } + + boolean bRelation = relationCompare_(relOps.m_matrix, relOps.m_scl); + return bRelation; + } + + // Returns true if the relation holds. + static boolean multiPointRelateMultiPoint_(MultiPoint multipoint_a, + MultiPoint multipoint_b, double tolerance, String scl, + ProgressTracker progress_tracker) { + RelationalOperationsMatrix relOps = new RelationalOperationsMatrix(); + relOps.resetMatrix_(); + relOps.setPredicates_(scl); + relOps.setPointPointPredicates_(); + + Envelope2D env_a = new Envelope2D(), env_b = new Envelope2D(); + multipoint_a.queryEnvelope2D(env_a); + multipoint_b.queryEnvelope2D(env_b); + + boolean bRelationKnown = false; + boolean b_disjoint = RelationalOperations.envelopeDisjointEnvelope_( + env_a, env_b, tolerance, progress_tracker); + + if (b_disjoint) { + relOps.pointPointDisjointPredicates_(); + bRelationKnown = true; + } + + if (!bRelationKnown) { + EditShape edit_shape = new EditShape(); + int geom_a = edit_shape.addGeometry(multipoint_a); + int geom_b = edit_shape.addGeometry(multipoint_b); + relOps.setEditShapeCrackAndCluster_(edit_shape, tolerance, + progress_tracker); + relOps.computeMatrixTopoGraphClusters_(geom_a, geom_b); + relOps.m_topo_graph.removeShape(); + } + + boolean bRelation = relationCompare_(relOps.m_matrix, relOps.m_scl); + return bRelation; + } + + // Returns true if the relation holds. + static boolean polygonRelatePoint_(Polygon polygon_a, Point point_b, + double tolerance, String scl, ProgressTracker progress_tracker) { RelationalOperationsMatrix relOps = new RelationalOperationsMatrix(); relOps.resetMatrix_(); relOps.setPredicates_(scl); @@ -724,31 +742,39 @@ static boolean polygonRelatePoint_(Polygon polygon_a, Point point_b, boolean bRelationKnown = false; boolean b_disjoint = RelationalOperations.pointDisjointEnvelope_(pt_b, env_a, tolerance, progress_tracker); - if (b_disjoint) { + if (b_disjoint) + { relOps.areaPointDisjointPredicates_(polygon_a); bRelationKnown = true; } - if (!bRelationKnown) { + if (!bRelationKnown) + { PolygonUtils.PiPResult res = PolygonUtils.isPointInPolygon2D(polygon_a, pt_b, tolerance); // uses accelerator - if (res == PolygonUtils.PiPResult.PiPInside) {// polygon must have area + if (res == PolygonUtils.PiPResult.PiPInside) + {// polygon must have area relOps.m_matrix[MatrixPredicate.InteriorInterior] = 0; relOps.m_matrix[MatrixPredicate.InteriorExterior] = 2; relOps.m_matrix[MatrixPredicate.BoundaryInterior] = -1; relOps.m_matrix[MatrixPredicate.BoundaryExterior] = 1; relOps.m_matrix[MatrixPredicate.ExteriorInterior] = -1; - } else if (res == PolygonUtils.PiPResult.PiPBoundary) { + } + else if (res == PolygonUtils.PiPResult.PiPBoundary) + { relOps.m_matrix[MatrixPredicate.ExteriorInterior] = -1; double area = polygon_a.calculateArea2D(); - if (area != 0) { + if (area != 0) + { relOps.m_matrix[MatrixPredicate.InteriorInterior] = -1; relOps.m_matrix[MatrixPredicate.BoundaryInterior] = 0; relOps.m_matrix[MatrixPredicate.InteriorExterior] = 2; relOps.m_matrix[MatrixPredicate.BoundaryExterior] = 1; - } else { + } + else + { relOps.m_matrix[MatrixPredicate.InteriorInterior] = 0; relOps.m_matrix[MatrixPredicate.BoundaryInterior] = -1; relOps.m_matrix[MatrixPredicate.BoundaryExterior] = -1; @@ -757,18 +783,20 @@ static boolean polygonRelatePoint_(Polygon polygon_a, Point point_b, polygon_a.queryEnvelope2D(env); relOps.m_matrix[MatrixPredicate.InteriorExterior] = (env.getHeight() == 0.0 && env.getWidth() == 0.0 ? -1 : 1); } - } else { + } + else + { relOps.areaPointDisjointPredicates_(polygon_a); } } boolean bRelation = relationCompare_(relOps.m_matrix, scl); return bRelation; - } + } - // Returns true if the relation holds. - static boolean polylineRelatePoint_(Polyline polyline_a, Point point_b, - double tolerance, String scl, ProgressTracker progress_tracker) { + // Returns true if the relation holds. + static boolean polylineRelatePoint_(Polyline polyline_a, Point point_b, + double tolerance, String scl, ProgressTracker progress_tracker) { RelationalOperationsMatrix relOps = new RelationalOperationsMatrix(); relOps.resetMatrix_(); relOps.setPredicates_(scl); @@ -781,22 +809,27 @@ static boolean polylineRelatePoint_(Polyline polyline_a, Point point_b, boolean bRelationKnown = false; boolean b_disjoint = RelationalOperations.pointDisjointEnvelope_(pt_b, env_a, tolerance, progress_tracker); - if (b_disjoint) { + if (b_disjoint) + { relOps.linePointDisjointPredicates_(polyline_a); bRelationKnown = true; } - if (!bRelationKnown) { + if (!bRelationKnown) + { MultiPoint boundary_a = null; boolean b_boundary_contains_point_known = false; boolean b_boundary_contains_point = false; - if (relOps.m_perform_predicates[MatrixPredicate.InteriorInterior] || relOps.m_perform_predicates[MatrixPredicate.ExteriorInterior]) { + if (relOps.m_perform_predicates[MatrixPredicate.InteriorInterior] || relOps.m_perform_predicates[MatrixPredicate.ExteriorInterior]) + { boolean b_intersects = RelationalOperations.linearPathIntersectsPoint_(polyline_a, pt_b, tolerance); - if (b_intersects) { - if (relOps.m_perform_predicates[MatrixPredicate.InteriorInterior]) { - boundary_a = (MultiPoint) Boundary.calculate(polyline_a, progress_tracker); + if (b_intersects) + { + if (relOps.m_perform_predicates[MatrixPredicate.InteriorInterior]) + { + boundary_a = (MultiPoint)Boundary.calculate(polyline_a, progress_tracker); b_boundary_contains_point = !RelationalOperations.multiPointDisjointPointImpl_(boundary_a, pt_b, tolerance, progress_tracker); b_boundary_contains_point_known = true; @@ -807,19 +840,26 @@ static boolean polylineRelatePoint_(Polyline polyline_a, Point point_b, } relOps.m_matrix[MatrixPredicate.ExteriorInterior] = -1; - } else { + } + else + { relOps.m_matrix[MatrixPredicate.InteriorInterior] = -1; relOps.m_matrix[MatrixPredicate.ExteriorInterior] = 0; } } - if (relOps.m_perform_predicates[MatrixPredicate.BoundaryInterior]) { - if (boundary_a != null && boundary_a.isEmpty()) { + if (relOps.m_perform_predicates[MatrixPredicate.BoundaryInterior]) + { + if (boundary_a != null && boundary_a.isEmpty()) + { relOps.m_matrix[MatrixPredicate.BoundaryInterior] = -1; - } else { - if (!b_boundary_contains_point_known) { + } + else + { + if (!b_boundary_contains_point_known) + { if (boundary_a == null) - boundary_a = (MultiPoint) Boundary.calculate(polyline_a, progress_tracker); + boundary_a = (MultiPoint)Boundary.calculate(polyline_a, progress_tracker); b_boundary_contains_point = !RelationalOperations.multiPointDisjointPointImpl_(boundary_a, pt_b, tolerance, progress_tracker); b_boundary_contains_point_known = true; @@ -829,15 +869,22 @@ static boolean polylineRelatePoint_(Polyline polyline_a, Point point_b, } } - if (relOps.m_perform_predicates[MatrixPredicate.BoundaryExterior]) { - if (boundary_a != null && boundary_a.isEmpty()) { + if (relOps.m_perform_predicates[MatrixPredicate.BoundaryExterior]) + { + if (boundary_a != null && boundary_a.isEmpty()) + { relOps.m_matrix[MatrixPredicate.BoundaryExterior] = -1; - } else { - if (b_boundary_contains_point_known && !b_boundary_contains_point) { + } + else + { + if (b_boundary_contains_point_known && !b_boundary_contains_point) + { relOps.m_matrix[MatrixPredicate.BoundaryExterior] = 0; - } else { + } + else + { if (boundary_a == null) - boundary_a = (MultiPoint) Boundary.calculate(polyline_a, progress_tracker); + boundary_a = (MultiPoint)Boundary.calculate(polyline_a, progress_tracker); boolean b_boundary_equals_point = RelationalOperations.multiPointEqualsPoint_(boundary_a, point_b, tolerance, progress_tracker); relOps.m_matrix[MatrixPredicate.BoundaryExterior] = (b_boundary_equals_point ? -1 : 0); @@ -845,12 +892,16 @@ static boolean polylineRelatePoint_(Polyline polyline_a, Point point_b, } } - if (relOps.m_perform_predicates[MatrixPredicate.InteriorExterior]) { + if (relOps.m_perform_predicates[MatrixPredicate.InteriorExterior]) + { boolean b_has_length = polyline_a.calculateLength2D() != 0; - if (b_has_length) { + if (b_has_length) + { relOps.m_matrix[MatrixPredicate.InteriorExterior] = 1; - } else { + } + else + { // all points are interior MultiPoint interior_a = new MultiPoint(polyline_a.getDescription()); interior_a.add(polyline_a, 0, polyline_a.getPointCount()); @@ -862,136 +913,138 @@ static boolean polylineRelatePoint_(Polyline polyline_a, Point point_b, boolean bRelation = relationCompare_(relOps.m_matrix, relOps.m_scl); return bRelation; - } - - // Returns true if the relation holds. - static boolean multiPointRelatePoint_(MultiPoint multipoint_a, - Point point_b, double tolerance, String scl, - ProgressTracker progress_tracker) { - RelationalOperationsMatrix relOps = new RelationalOperationsMatrix(); - relOps.resetMatrix_(); - relOps.setPredicates_(scl); - relOps.setPointPointPredicates_(); - - Envelope2D env_a = new Envelope2D(); - multipoint_a.queryEnvelope2D(env_a); - Point2D pt_b = point_b.getXY(); - - boolean bRelationKnown = false; - boolean b_disjoint = RelationalOperations.pointDisjointEnvelope_(pt_b, - env_a, tolerance, progress_tracker); - - if (b_disjoint) { - relOps.pointPointDisjointPredicates_(); - bRelationKnown = true; - } - - if (!bRelationKnown) { - boolean b_intersects = false; - boolean b_multipoint_contained = true; - double tolerance_sq = tolerance * tolerance; - - for (int i = 0; i < multipoint_a.getPointCount(); i++) { - Point2D pt_a = multipoint_a.getXY(i); - - if (Point2D.sqrDistance(pt_a, pt_b) <= tolerance_sq) - b_intersects = true; - else - b_multipoint_contained = false; - - if (b_intersects && !b_multipoint_contained) - break; - } - - if (b_intersects) { - relOps.m_matrix[MatrixPredicate.InteriorInterior] = 0; - - if (!b_multipoint_contained) - relOps.m_matrix[MatrixPredicate.InteriorExterior] = 0; - else - relOps.m_matrix[MatrixPredicate.InteriorExterior] = -1; - - relOps.m_matrix[MatrixPredicate.ExteriorInterior] = -1; - } else { - relOps.m_matrix[MatrixPredicate.InteriorInterior] = -1; - relOps.m_matrix[MatrixPredicate.InteriorExterior] = 0; - relOps.m_matrix[MatrixPredicate.ExteriorInterior] = 0; - } - } - - boolean bRelation = relationCompare_(relOps.m_matrix, scl); - return bRelation; - } - - // Returns true if the relation holds. - static boolean pointRelatePoint_(Point point_a, Point point_b, - double tolerance, String scl, ProgressTracker progress_tracker) { - Point2D pt_a = point_a.getXY(); - Point2D pt_b = point_b.getXY(); - int[] matrix = new int[9]; - - for (int i = 0; i < 9; i++) - matrix[i] = -1; - - if (Point2D.sqrDistance(pt_a, pt_b) <= tolerance * tolerance) { - matrix[MatrixPredicate.InteriorInterior] = 0; - } else { - matrix[MatrixPredicate.InteriorExterior] = 0; - matrix[MatrixPredicate.ExteriorInterior] = 0; - } - - matrix[MatrixPredicate.ExteriorExterior] = 2; - - boolean bRelation = relationCompare_(matrix, scl); - return bRelation; - } - - // Compares the DE-9I matrix against the scl string. - private static boolean relationCompare_(int[] matrix, String scl) { - for (int i = 0; i < 9; i++) { - switch (scl.charAt(i)) { - case 'T': - assert (matrix[i] != -2); - if (matrix[i] == -1) - return false; - break; - - case 'F': - assert (matrix[i] != -2); - if (matrix[i] != -1) - return false; - break; - - case '0': - assert (matrix[i] != -2); - if (matrix[i] != 0) - return false; - break; - - case '1': - assert (matrix[i] != -2); - if (matrix[i] != 1) - return false; - break; - - case '2': - assert (matrix[i] != -2); - if (matrix[i] != 2) - return false; - break; - - default: - break; - } - } - - return true; - } - - static boolean relateEmptyGeometries_(Geometry geometry_a, Geometry geometry_b, String scl) { + } + + // Returns true if the relation holds. + static boolean multiPointRelatePoint_(MultiPoint multipoint_a, + Point point_b, double tolerance, String scl, + ProgressTracker progress_tracker) { + RelationalOperationsMatrix relOps = new RelationalOperationsMatrix(); + relOps.resetMatrix_(); + relOps.setPredicates_(scl); + relOps.setPointPointPredicates_(); + + Envelope2D env_a = new Envelope2D(); + multipoint_a.queryEnvelope2D(env_a); + Point2D pt_b = point_b.getXY(); + + boolean bRelationKnown = false; + boolean b_disjoint = RelationalOperations.pointDisjointEnvelope_(pt_b, + env_a, tolerance, progress_tracker); + + if (b_disjoint) { + relOps.pointPointDisjointPredicates_(); + bRelationKnown = true; + } + + if (!bRelationKnown) { + boolean b_intersects = false; + boolean b_multipoint_contained = true; + double tolerance_sq = tolerance * tolerance; + + for (int i = 0; i < multipoint_a.getPointCount(); i++) { + Point2D pt_a = multipoint_a.getXY(i); + + if (Point2D.sqrDistance(pt_a, pt_b) <= tolerance_sq) + b_intersects = true; + else + b_multipoint_contained = false; + + if (b_intersects && !b_multipoint_contained) + break; + } + + if (b_intersects) { + relOps.m_matrix[MatrixPredicate.InteriorInterior] = 0; + + if (!b_multipoint_contained) + relOps.m_matrix[MatrixPredicate.InteriorExterior] = 0; + else + relOps.m_matrix[MatrixPredicate.InteriorExterior] = -1; + + relOps.m_matrix[MatrixPredicate.ExteriorInterior] = -1; + } else { + relOps.m_matrix[MatrixPredicate.InteriorInterior] = -1; + relOps.m_matrix[MatrixPredicate.InteriorExterior] = 0; + relOps.m_matrix[MatrixPredicate.ExteriorInterior] = 0; + } + } + + boolean bRelation = relationCompare_(relOps.m_matrix, scl); + return bRelation; + } + + // Returns true if the relation holds. + static boolean pointRelatePoint_(Point point_a, Point point_b, + double tolerance, String scl, ProgressTracker progress_tracker) { + Point2D pt_a = point_a.getXY(); + Point2D pt_b = point_b.getXY(); + int[] matrix = new int[9]; + + for (int i = 0; i < 9; i++) + matrix[i] = -1; + + if (Point2D.sqrDistance(pt_a, pt_b) <= tolerance * tolerance) { + matrix[MatrixPredicate.InteriorInterior] = 0; + } else { + matrix[MatrixPredicate.InteriorExterior] = 0; + matrix[MatrixPredicate.ExteriorInterior] = 0; + } + + matrix[MatrixPredicate.ExteriorExterior] = 2; + + boolean bRelation = relationCompare_(matrix, scl); + return bRelation; + } + + // Compares the DE-9I matrix against the scl string. + private static boolean relationCompare_(int[] matrix, String scl) { + for (int i = 0; i < 9; i++) { + switch (scl.charAt(i)) { + case 'T': + assert (matrix[i] != -2); + if (matrix[i] == -1) + return false; + break; + + case 'F': + assert (matrix[i] != -2); + if (matrix[i] != -1) + return false; + break; + + case '0': + assert (matrix[i] != -2); + if (matrix[i] != 0) + return false; + break; + + case '1': + assert (matrix[i] != -2); + if (matrix[i] != 1) + return false; + break; + + case '2': + assert (matrix[i] != -2); + if (matrix[i] != 2) + return false; + break; + + default: + break; + } + } + + return true; + } + + static boolean relateEmptyGeometries_(Geometry geometry_a, Geometry geometry_b, String scl) + { int[] matrix = new int[9]; - if (geometry_a.isEmpty() && geometry_b.isEmpty()) { + if (geometry_a.isEmpty() && geometry_b.isEmpty()) + { for (int i = 0; i < 9; i++) matrix[i] = -1; @@ -1003,10 +1056,13 @@ static boolean relateEmptyGeometries_(Geometry geometry_a, Geometry geometry_b, Geometry g_a; Geometry g_b; - if (!geometry_a.isEmpty()) { + if (!geometry_a.isEmpty()) + { g_a = geometry_a; g_b = geometry_b; - } else { + } + else + { g_a = geometry_b; g_b = geometry_a; b_transpose = true; @@ -1023,26 +1079,35 @@ static boolean relateEmptyGeometries_(Geometry geometry_a, Geometry geometry_b, int type = g_a.getType().value(); - if (Geometry.isMultiPath(type)) { - if (type == Geometry.GeometryType.Polygon) { - double area = ((Polygon) g_a).calculateArea2D(); + if (Geometry.isMultiPath(type)) + { + if (type == Geometry.GeometryType.Polygon) + { + double area = ((Polygon)g_a).calculateArea2D(); - if (area != 0) { + if (area != 0) + { matrix[MatrixPredicate.InteriorExterior] = 2; matrix[MatrixPredicate.BoundaryExterior] = 1; - } else { + } + else + { matrix[MatrixPredicate.BoundaryExterior] = -1; Envelope2D env = new Envelope2D(); g_a.queryEnvelope2D(env); matrix[MatrixPredicate.InteriorExterior] = (env.getHeight() == 0.0 && env.getWidth() == 0.0 ? 0 : 1); } - } else { - boolean b_has_length = ((Polyline) g_a).calculateLength2D() != 0; + } + else + { + boolean b_has_length = ((Polyline)g_a).calculateLength2D() != 0; matrix[MatrixPredicate.InteriorExterior] = (b_has_length ? 1 : 0); - matrix[MatrixPredicate.BoundaryExterior] = (Boundary.hasNonEmptyBoundary((Polyline) g_a, null) ? 0 : -1); + matrix[MatrixPredicate.BoundaryExterior] = (Boundary.hasNonEmptyBoundary((Polyline)g_a, null) ? 0 : -1); } - } else { + } + else + { matrix[MatrixPredicate.InteriorExterior] = 0; matrix[MatrixPredicate.BoundaryExterior] = -1; } @@ -1053,175 +1118,177 @@ static boolean relateEmptyGeometries_(Geometry geometry_a, Geometry geometry_b, return relationCompare_(matrix, scl); } - // Checks whether scl string is a predefined relation. - private static int getPredefinedRelation_(String scl, int dim_a, int dim_b) { - if (equals_(scl)) - return RelationalOperations.Relation.equals; - - if (disjoint_(scl)) - return RelationalOperations.Relation.disjoint; - - if (touches_(scl, dim_a, dim_b)) - return RelationalOperations.Relation.touches; + // Checks whether scl string is a predefined relation. + private static int getPredefinedRelation_(String scl, int dim_a, int dim_b) { + if (equals_(scl)) + return RelationalOperations.Relation.equals; + + if (disjoint_(scl)) + return RelationalOperations.Relation.disjoint; + + if (touches_(scl, dim_a, dim_b)) + return RelationalOperations.Relation.touches; + + if (crosses_(scl, dim_a, dim_b)) + return RelationalOperations.Relation.crosses; + + if (contains_(scl)) + return RelationalOperations.Relation.contains; + + if (overlaps_(scl, dim_a, dim_b)) + return RelationalOperations.Relation.overlaps; + + return RelationalOperations.Relation.unknown; + } + + // Checks whether the scl string is the equals relation. + private static boolean equals_(String scl) { + // Valid for all + if (scl.charAt(0) == 'T' && scl.charAt(1) == '*' + && scl.charAt(2) == 'F' && scl.charAt(3) == '*' + && scl.charAt(4) == '*' && scl.charAt(5) == 'F' + && scl.charAt(6) == 'F' && scl.charAt(7) == 'F' + && scl.charAt(8) == '*') + return true; + + return false; + } + + // Checks whether the scl string is the disjoint relation. + private static boolean disjoint_(String scl) { + if (scl.charAt(0) == 'F' && scl.charAt(1) == 'F' + && scl.charAt(2) == '*' && scl.charAt(3) == 'F' + && scl.charAt(4) == 'F' && scl.charAt(5) == '*' + && scl.charAt(6) == '*' && scl.charAt(7) == '*' + && scl.charAt(8) == '*') + return true; + + return false; + } + + // Checks whether the scl string is the touches relation. + private static boolean touches_(String scl, int dim_a, int dim_b) { + // Points cant touch + if (dim_a == 0 && dim_b == 0) + return false; + + if (!(dim_a == 2 && dim_b == 2)) { + // Valid for area-Line, Line-Line, area-Point, and Line-Point + if (scl.charAt(0) == 'F' && scl.charAt(1) == '*' + && scl.charAt(2) == '*' && scl.charAt(3) == 'T' + && scl.charAt(4) == '*' && scl.charAt(5) == '*' + && scl.charAt(6) == '*' && scl.charAt(7) == '*' + && scl.charAt(8) == '*') + return true; + + if (dim_a == 1 && dim_b == 1) { + // Valid for Line-Line + if (scl.charAt(0) == 'F' && scl.charAt(1) == 'T' + && scl.charAt(2) == '*' && scl.charAt(3) == '*' + && scl.charAt(4) == '*' && scl.charAt(5) == '*' + && scl.charAt(6) == '*' && scl.charAt(7) == '*' + && scl.charAt(8) == '*') + return true; + } + } + + // Valid for area-area, area-Line, Line-Line + + if (dim_b != 0) { + if (scl.charAt(0) == 'F' && scl.charAt(1) == '*' + && scl.charAt(2) == '*' && scl.charAt(3) == '*' + && scl.charAt(4) == 'T' && scl.charAt(5) == '*' + && scl.charAt(6) == '*' && scl.charAt(7) == '*' + && scl.charAt(8) == '*') + return true; + } + + return false; + } + + // Checks whether the scl string is the crosses relation. + private static boolean crosses_(String scl, int dim_a, int dim_b) { + if (dim_a > dim_b) { + // Valid for area-Line, area-Point, Line-Point + if (scl.charAt(0) == 'T' && scl.charAt(1) == '*' + && scl.charAt(2) == '*' && scl.charAt(3) == '*' + && scl.charAt(4) == '*' && scl.charAt(5) == '*' + && scl.charAt(6) == 'T' && scl.charAt(7) == '*' + && scl.charAt(8) == '*') + return true; + + return false; + } + + if (dim_a == 1 && dim_b == 1) { + // Valid for Line-Line + if (scl.charAt(0) == '0' && scl.charAt(1) == '*' + && scl.charAt(2) == '*' && scl.charAt(3) == '*' + && scl.charAt(4) == '*' && scl.charAt(5) == '*' + && scl.charAt(6) == '*' && scl.charAt(7) == '*' + && scl.charAt(8) == '*') + return true; + } + + return false; + } + + // Checks whether the scl string is the contains relation. + private static boolean contains_(String scl) { + // Valid for all + if (scl.charAt(0) == 'T' && scl.charAt(1) == '*' + && scl.charAt(2) == '*' && scl.charAt(3) == '*' + && scl.charAt(4) == '*' && scl.charAt(5) == '*' + && scl.charAt(6) == 'F' && scl.charAt(7) == 'F' + && scl.charAt(8) == '*') + return true; + + return false; + } + + // Checks whether the scl string is the overlaps relation. + private static boolean overlaps_(String scl, int dim_a, int dim_b) { + if (dim_a == dim_b) { + if (dim_a != 1) { + // Valid for area-area, Point-Point + if (scl.charAt(0) == 'T' && scl.charAt(1) == '*' + && scl.charAt(2) == 'T' && scl.charAt(3) == '*' + && scl.charAt(4) == '*' && scl.charAt(5) == '*' + && scl.charAt(6) == 'T' && scl.charAt(7) == '*' + && scl.charAt(8) == '*') + return true; + + return false; + } + + // Valid for Line-Line + if (scl.charAt(0) == '1' && scl.charAt(1) == '*' + && scl.charAt(2) == 'T' && scl.charAt(3) == '*' + && scl.charAt(4) == '*' && scl.charAt(5) == '*' + && scl.charAt(6) == 'T' && scl.charAt(7) == '*' + && scl.charAt(8) == '*') + return true; + } + + return false; + } + + // Marks each cluster of the topoGraph as belonging to an interior vertex of + // the geometry and/or a boundary index of the geometry. + private static void markClusterEndPoints_(int geometry, + TopoGraph topoGraph, int clusterIndex) { + int id = topoGraph.getGeometryID(geometry); - if (crosses_(scl, dim_a, dim_b)) - return RelationalOperations.Relation.crosses; + for (int cluster = topoGraph.getFirstCluster(); cluster != -1; cluster = topoGraph.getNextCluster(cluster)) + { + int cluster_parentage = topoGraph.getClusterParentage(cluster); - if (contains_(scl)) - return RelationalOperations.Relation.contains; - - if (overlaps_(scl, dim_a, dim_b)) - return RelationalOperations.Relation.overlaps; - - return RelationalOperations.Relation.unknown; - } - - // Checks whether the scl string is the equals relation. - private static boolean equals_(String scl) { - // Valid for all - if (scl.charAt(0) == 'T' && scl.charAt(1) == '*' - && scl.charAt(2) == 'F' && scl.charAt(3) == '*' - && scl.charAt(4) == '*' && scl.charAt(5) == 'F' - && scl.charAt(6) == 'F' && scl.charAt(7) == 'F' - && scl.charAt(8) == '*') - return true; - - return false; - } - - // Checks whether the scl string is the disjoint relation. - private static boolean disjoint_(String scl) { - if (scl.charAt(0) == 'F' && scl.charAt(1) == 'F' - && scl.charAt(2) == '*' && scl.charAt(3) == 'F' - && scl.charAt(4) == 'F' && scl.charAt(5) == '*' - && scl.charAt(6) == '*' && scl.charAt(7) == '*' - && scl.charAt(8) == '*') - return true; - - return false; - } - - // Checks whether the scl string is the touches relation. - private static boolean touches_(String scl, int dim_a, int dim_b) { - // Points cant touch - if (dim_a == 0 && dim_b == 0) - return false; - - if (!(dim_a == 2 && dim_b == 2)) { - // Valid for area-Line, Line-Line, area-Point, and Line-Point - if (scl.charAt(0) == 'F' && scl.charAt(1) == '*' - && scl.charAt(2) == '*' && scl.charAt(3) == 'T' - && scl.charAt(4) == '*' && scl.charAt(5) == '*' - && scl.charAt(6) == '*' && scl.charAt(7) == '*' - && scl.charAt(8) == '*') - return true; - - if (dim_a == 1 && dim_b == 1) { - // Valid for Line-Line - if (scl.charAt(0) == 'F' && scl.charAt(1) == 'T' - && scl.charAt(2) == '*' && scl.charAt(3) == '*' - && scl.charAt(4) == '*' && scl.charAt(5) == '*' - && scl.charAt(6) == '*' && scl.charAt(7) == '*' - && scl.charAt(8) == '*') - return true; - } - } - - // Valid for area-area, area-Line, Line-Line - - if (dim_b != 0) { - if (scl.charAt(0) == 'F' && scl.charAt(1) == '*' - && scl.charAt(2) == '*' && scl.charAt(3) == '*' - && scl.charAt(4) == 'T' && scl.charAt(5) == '*' - && scl.charAt(6) == '*' && scl.charAt(7) == '*' - && scl.charAt(8) == '*') - return true; - } - - return false; - } - - // Checks whether the scl string is the crosses relation. - private static boolean crosses_(String scl, int dim_a, int dim_b) { - if (dim_a > dim_b) { - // Valid for area-Line, area-Point, Line-Point - if (scl.charAt(0) == 'T' && scl.charAt(1) == '*' - && scl.charAt(2) == '*' && scl.charAt(3) == '*' - && scl.charAt(4) == '*' && scl.charAt(5) == '*' - && scl.charAt(6) == 'T' && scl.charAt(7) == '*' - && scl.charAt(8) == '*') - return true; - - return false; - } - - if (dim_a == 1 && dim_b == 1) { - // Valid for Line-Line - if (scl.charAt(0) == '0' && scl.charAt(1) == '*' - && scl.charAt(2) == '*' && scl.charAt(3) == '*' - && scl.charAt(4) == '*' && scl.charAt(5) == '*' - && scl.charAt(6) == '*' && scl.charAt(7) == '*' - && scl.charAt(8) == '*') - return true; - } - - return false; - } - - // Checks whether the scl string is the contains relation. - private static boolean contains_(String scl) { - // Valid for all - if (scl.charAt(0) == 'T' && scl.charAt(1) == '*' - && scl.charAt(2) == '*' && scl.charAt(3) == '*' - && scl.charAt(4) == '*' && scl.charAt(5) == '*' - && scl.charAt(6) == 'F' && scl.charAt(7) == 'F' - && scl.charAt(8) == '*') - return true; - - return false; - } - - // Checks whether the scl string is the overlaps relation. - private static boolean overlaps_(String scl, int dim_a, int dim_b) { - if (dim_a == dim_b) { - if (dim_a != 1) { - // Valid for area-area, Point-Point - if (scl.charAt(0) == 'T' && scl.charAt(1) == '*' - && scl.charAt(2) == 'T' && scl.charAt(3) == '*' - && scl.charAt(4) == '*' && scl.charAt(5) == '*' - && scl.charAt(6) == 'T' && scl.charAt(7) == '*' - && scl.charAt(8) == '*') - return true; - - return false; - } - - // Valid for Line-Line - if (scl.charAt(0) == '1' && scl.charAt(1) == '*' - && scl.charAt(2) == 'T' && scl.charAt(3) == '*' - && scl.charAt(4) == '*' && scl.charAt(5) == '*' - && scl.charAt(6) == 'T' && scl.charAt(7) == '*' - && scl.charAt(8) == '*') - return true; - } - - return false; - } - - // Marks each cluster of the topoGraph as belonging to an interior vertex of - // the geometry and/or a boundary index of the geometry. - private static void markClusterEndPoints_(int geometry, - TopoGraph topoGraph, int clusterIndex) { - int id = topoGraph.getGeometryID(geometry); - - for (int cluster = topoGraph.getFirstCluster(); cluster != -1; cluster = topoGraph.getNextCluster(cluster)) { - int cluster_parentage = topoGraph.getClusterParentage(cluster); - - if ((cluster_parentage & id) == 0) - continue; + if ((cluster_parentage & id) == 0) + continue; int first_half_edge = topoGraph.getClusterHalfEdge(cluster); - if (first_half_edge == -1) { + if (first_half_edge == -1) + { topoGraph.setClusterUserIndex(cluster, clusterIndex, 0); continue; } @@ -1229,7 +1296,8 @@ private static void markClusterEndPoints_(int geometry, int next_half_edge = first_half_edge; int index = 0; - do { + do + { int half_edge = next_half_edge; int half_edge_parentage = topoGraph.getHalfEdgeParentage(half_edge); @@ -1244,102 +1312,110 @@ private static void markClusterEndPoints_(int geometry, } return; - } - - private static String getTransposeMatrix_(String scl) { - String transpose = new String(); - transpose += scl.charAt(0); - transpose += scl.charAt(3); - transpose += scl.charAt(6); - transpose += scl.charAt(1); - transpose += scl.charAt(4); - transpose += scl.charAt(7); - transpose += scl.charAt(2); - transpose += scl.charAt(5); - transpose += scl.charAt(8); - return transpose; - } - - // Allocates the matrix array if need be, and sets all entries to -2. - // -2: Not Computed - // -1: No intersection - // 0: 0-dimension intersection - // 1: 1-dimension intersection - // 2: 2-dimension intersection - private void resetMatrix_() { - for (int i = 0; i < 9; i++) { + } + + private static String getTransposeMatrix_(String scl) { + String transpose = new String(); + transpose += scl.charAt(0); + transpose += scl.charAt(3); + transpose += scl.charAt(6); + transpose += scl.charAt(1); + transpose += scl.charAt(4); + transpose += scl.charAt(7); + transpose += scl.charAt(2); + transpose += scl.charAt(5); + transpose += scl.charAt(8); + return transpose; + } + + // Allocates the matrix array if need be, and sets all entries to -2. + // -2: Not Computed + // -1: No intersection + // 0: 0-dimension intersection + // 1: 1-dimension intersection + // 2: 2-dimension intersection + private void resetMatrix_() { + for (int i = 0; i < 9; i++) + { m_matrix[i] = -2; m_max_dim[i] = -2; } - } - - private static void transposeMatrix_(int[] matrix) { - int temp1 = matrix[1]; - int temp2 = matrix[2]; - int temp5 = matrix[5]; - - matrix[1] = matrix[3]; - matrix[2] = matrix[6]; - matrix[5] = matrix[7]; - - matrix[3] = temp1; - matrix[6] = temp2; - matrix[7] = temp5; - } - - // Sets the relation predicates from the scl string. - private void setPredicates_(String scl) { - m_scl = scl; - - for (int i = 0; i < 9; i++) { - if (m_scl.charAt(i) != '*') { - m_perform_predicates[i] = true; - m_predicate_count++; - } else - m_perform_predicates[i] = false; - } - } - - // Sets the remaining predicates to false - private void setRemainingPredicatesToFalse_() { - for (int i = 0; i < 9; i++) { - if (m_perform_predicates[i] && m_matrix[i] == -2) { - m_matrix[i] = -1; - m_perform_predicates[i] = false; - } - } - } - - // Checks whether the predicate is known. - private boolean isPredicateKnown_(int predicate) { - assert (m_scl.charAt(predicate) != '*'); + } + + private static void transposeMatrix_(int[] matrix) { + int temp1 = matrix[1]; + int temp2 = matrix[2]; + int temp5 = matrix[5]; + + matrix[1] = matrix[3]; + matrix[2] = matrix[6]; + matrix[5] = matrix[7]; + + matrix[3] = temp1; + matrix[6] = temp2; + matrix[7] = temp5; + } + + // Sets the relation predicates from the scl string. + private void setPredicates_(String scl) { + m_scl = scl; + + for (int i = 0; i < 9; i++) { + if (m_scl.charAt(i) != '*') { + m_perform_predicates[i] = true; + m_predicate_count++; + } else + m_perform_predicates[i] = false; + } + } + + // Sets the remaining predicates to false + private void setRemainingPredicatesToFalse_() { + for (int i = 0; i < 9; i++) { + if (m_perform_predicates[i] && m_matrix[i] == -2) { + m_matrix[i] = -1; + m_perform_predicates[i] = false; + } + } + } + + // Checks whether the predicate is known. + private boolean isPredicateKnown_(int predicate) { + assert(m_scl.charAt(predicate) != '*'); if (m_matrix[predicate] == -2) return false; - if (m_matrix[predicate] == -1) { + if (m_matrix[predicate] == -1) + { m_perform_predicates[predicate] = false; m_predicate_count--; return true; } - if (m_scl.charAt(predicate) != 'T' && m_scl.charAt(predicate) != 'F') { - if (m_matrix[predicate] < m_max_dim[predicate]) { + if (m_scl.charAt(predicate) != 'T' && m_scl.charAt(predicate) != 'F') + { + if (m_matrix[predicate] < m_max_dim[predicate]) + { return false; - } else { + } + else + { m_perform_predicates[predicate] = false; m_predicate_count--; return true; } - } else { + } + else + { m_perform_predicates[predicate] = false; m_predicate_count--; return true; } - } + } - // Sets the area-area predicates function. - private void setAreaAreaPredicates_() { + // Sets the area-area predicates function. + private void setAreaAreaPredicates_() { m_predicates_half_edge = Predicates.AreaAreaPredicates; m_max_dim[MatrixPredicate.InteriorInterior] = 2; @@ -1353,15 +1429,16 @@ private void setAreaAreaPredicates_() { m_max_dim[MatrixPredicate.ExteriorExterior] = 2; // set predicates that are always true/false - if (m_perform_predicates[MatrixPredicate.ExteriorExterior]) { + if (m_perform_predicates[MatrixPredicate.ExteriorExterior]) + { m_matrix[MatrixPredicate.ExteriorExterior] = 2; // Always true m_perform_predicates[MatrixPredicate.ExteriorExterior] = false; m_predicate_count--; } - } + } - // Sets the area-line predicate function. - private void setAreaLinePredicates_() { + // Sets the area-line predicate function. + private void setAreaLinePredicates_() { m_predicates_half_edge = Predicates.AreaLinePredicates; m_predicates_cluster = Predicates.AreaPointPredicates; @@ -1375,15 +1452,16 @@ private void setAreaLinePredicates_() { m_max_dim[MatrixPredicate.ExteriorBoundary] = 0; m_max_dim[MatrixPredicate.ExteriorExterior] = 2; - if (m_perform_predicates[MatrixPredicate.ExteriorExterior]) { + if (m_perform_predicates[MatrixPredicate.ExteriorExterior]) + { m_matrix[MatrixPredicate.ExteriorExterior] = 2; // Always true m_perform_predicates[MatrixPredicate.ExteriorExterior] = false; m_predicate_count--; } - } + } - // Sets the line-line predicates function. - private void setLineLinePredicates_() { + // Sets the line-line predicates function. + private void setLineLinePredicates_() { m_predicates_half_edge = Predicates.LineLinePredicates; m_predicates_cluster = Predicates.LinePointPredicates; @@ -1398,15 +1476,16 @@ private void setLineLinePredicates_() { m_max_dim[MatrixPredicate.ExteriorExterior] = 2; // set predicates that are always true/false - if (m_perform_predicates[MatrixPredicate.ExteriorExterior]) { + if (m_perform_predicates[MatrixPredicate.ExteriorExterior]) + { m_matrix[MatrixPredicate.ExteriorExterior] = 2; // Always true m_perform_predicates[MatrixPredicate.ExteriorExterior] = false; m_predicate_count--; } - } + } - // Sets the area-point predicate function. - private void setAreaPointPredicates_() { + // Sets the area-point predicate function. + private void setAreaPointPredicates_() { m_predicates_cluster = Predicates.AreaPointPredicates; m_max_dim[MatrixPredicate.InteriorInterior] = 0; @@ -1420,33 +1499,37 @@ private void setAreaPointPredicates_() { m_max_dim[MatrixPredicate.ExteriorExterior] = 2; // set predicates that are always true/false - if (m_perform_predicates[MatrixPredicate.InteriorBoundary]) { + if (m_perform_predicates[MatrixPredicate.InteriorBoundary]) + { m_matrix[MatrixPredicate.InteriorBoundary] = -1; // Always false m_perform_predicates[MatrixPredicate.InteriorBoundary] = false; m_predicate_count--; } - if (m_perform_predicates[MatrixPredicate.BoundaryBoundary]) { + if (m_perform_predicates[MatrixPredicate.BoundaryBoundary]) + { m_matrix[MatrixPredicate.BoundaryBoundary] = -1; // Always false m_perform_predicates[MatrixPredicate.BoundaryBoundary] = false; m_predicate_count--; } - if (m_perform_predicates[MatrixPredicate.ExteriorBoundary]) { + if (m_perform_predicates[MatrixPredicate.ExteriorBoundary]) + { m_matrix[MatrixPredicate.ExteriorBoundary] = -1; // Always false m_perform_predicates[MatrixPredicate.ExteriorBoundary] = false; m_predicate_count--; } - if (m_perform_predicates[MatrixPredicate.ExteriorExterior]) { + if (m_perform_predicates[MatrixPredicate.ExteriorExterior]) + { m_matrix[MatrixPredicate.ExteriorExterior] = 2; // Always true m_perform_predicates[MatrixPredicate.ExteriorExterior] = false; m_predicate_count--; } - } + } - // Sets the line-point predicates function. - private void setLinePointPredicates_() { + // Sets the line-point predicates function. + private void setLinePointPredicates_() { m_predicates_cluster = Predicates.LinePointPredicates; m_max_dim[MatrixPredicate.InteriorInterior] = 0; @@ -1460,33 +1543,37 @@ private void setLinePointPredicates_() { m_max_dim[MatrixPredicate.ExteriorExterior] = 2; // set predicates that are always true/false - if (m_perform_predicates[MatrixPredicate.InteriorBoundary]) { + if (m_perform_predicates[MatrixPredicate.InteriorBoundary]) + { m_matrix[MatrixPredicate.InteriorBoundary] = -1; // Always false m_perform_predicates[MatrixPredicate.InteriorBoundary] = false; m_predicate_count--; } - if (m_perform_predicates[MatrixPredicate.BoundaryBoundary]) { + if (m_perform_predicates[MatrixPredicate.BoundaryBoundary]) + { m_matrix[MatrixPredicate.BoundaryBoundary] = -1; // Always false m_perform_predicates[MatrixPredicate.BoundaryBoundary] = false; m_predicate_count--; } - if (m_perform_predicates[MatrixPredicate.ExteriorBoundary]) { + if (m_perform_predicates[MatrixPredicate.ExteriorBoundary]) + { m_matrix[MatrixPredicate.ExteriorBoundary] = -1; // Always false m_perform_predicates[MatrixPredicate.ExteriorBoundary] = false; m_predicate_count--; } - if (m_perform_predicates[MatrixPredicate.ExteriorExterior]) { + if (m_perform_predicates[MatrixPredicate.ExteriorExterior]) + { m_matrix[MatrixPredicate.ExteriorExterior] = 2; // Always true m_perform_predicates[MatrixPredicate.ExteriorExterior] = false; m_predicate_count--; } - } + } - // Sets the point-point predicates function. - private void setPointPointPredicates_() { + // Sets the point-point predicates function. + private void setPointPointPredicates_() { m_predicates_cluster = Predicates.PointPointPredicates; m_max_dim[MatrixPredicate.InteriorInterior] = 0; @@ -1500,105 +1587,111 @@ private void setPointPointPredicates_() { m_max_dim[MatrixPredicate.ExteriorExterior] = 2; // set predicates that are always true/false - if (m_perform_predicates[MatrixPredicate.InteriorBoundary]) { + if (m_perform_predicates[MatrixPredicate.InteriorBoundary]) + { m_matrix[MatrixPredicate.InteriorBoundary] = -1; // Always false m_perform_predicates[MatrixPredicate.InteriorBoundary] = false; m_predicate_count--; } - if (m_perform_predicates[MatrixPredicate.BoundaryInterior]) { + if (m_perform_predicates[MatrixPredicate.BoundaryInterior]) + { m_matrix[MatrixPredicate.BoundaryInterior] = -1; // Always false m_perform_predicates[MatrixPredicate.BoundaryInterior] = false; m_predicate_count--; } - if (m_perform_predicates[MatrixPredicate.BoundaryBoundary]) { + if (m_perform_predicates[MatrixPredicate.BoundaryBoundary]) + { m_matrix[MatrixPredicate.BoundaryBoundary] = -1; // Always false m_perform_predicates[MatrixPredicate.BoundaryBoundary] = false; m_predicate_count--; } - if (m_perform_predicates[MatrixPredicate.BoundaryExterior]) { + if (m_perform_predicates[MatrixPredicate.BoundaryExterior]) + { m_matrix[MatrixPredicate.BoundaryExterior] = -1; // Always false m_perform_predicates[MatrixPredicate.BoundaryExterior] = false; m_predicate_count--; } - if (m_perform_predicates[MatrixPredicate.ExteriorBoundary]) { + if (m_perform_predicates[MatrixPredicate.ExteriorBoundary]) + { m_matrix[MatrixPredicate.ExteriorBoundary] = -1; // Always false m_perform_predicates[MatrixPredicate.ExteriorBoundary] = false; m_predicate_count--; } - if (m_perform_predicates[MatrixPredicate.ExteriorExterior]) { + if (m_perform_predicates[MatrixPredicate.ExteriorExterior]) + { m_matrix[MatrixPredicate.ExteriorExterior] = 2; // Always true m_perform_predicates[MatrixPredicate.ExteriorExterior] = false; m_predicate_count--; } - } - - // Invokes the 9 relational predicates of area vs area. - private boolean areaAreaPredicates_(int half_edge, int id_a, int id_b) { - boolean bRelationKnown = true; - - if (m_perform_predicates[MatrixPredicate.InteriorInterior]) { - interiorAreaInteriorArea_(half_edge, id_a, id_b); - bRelationKnown &= isPredicateKnown_( - MatrixPredicate.InteriorInterior); - } - - if (m_perform_predicates[MatrixPredicate.InteriorBoundary]) { - interiorAreaBoundaryArea_(half_edge, id_a, - MatrixPredicate.InteriorBoundary); - bRelationKnown &= isPredicateKnown_( - MatrixPredicate.InteriorBoundary); - } - - if (m_perform_predicates[MatrixPredicate.InteriorExterior]) { - interiorAreaExteriorArea_(half_edge, id_a, id_b, - MatrixPredicate.InteriorExterior); - bRelationKnown &= isPredicateKnown_( - MatrixPredicate.InteriorExterior); - } - - if (m_perform_predicates[MatrixPredicate.BoundaryInterior]) { - interiorAreaBoundaryArea_(half_edge, id_b, - MatrixPredicate.BoundaryInterior); - bRelationKnown &= isPredicateKnown_( - MatrixPredicate.BoundaryInterior); - } - - if (m_perform_predicates[MatrixPredicate.BoundaryBoundary]) { - boundaryAreaBoundaryArea_(half_edge, id_a, id_b); - bRelationKnown &= isPredicateKnown_( - MatrixPredicate.BoundaryBoundary); - } - - if (m_perform_predicates[MatrixPredicate.BoundaryExterior]) { - boundaryAreaExteriorArea_(half_edge, id_a, id_b, - MatrixPredicate.BoundaryExterior); - bRelationKnown &= isPredicateKnown_( - MatrixPredicate.BoundaryExterior); - } - - if (m_perform_predicates[MatrixPredicate.ExteriorInterior]) { - interiorAreaExteriorArea_(half_edge, id_b, id_a, - MatrixPredicate.ExteriorInterior); - bRelationKnown &= isPredicateKnown_( - MatrixPredicate.ExteriorInterior); - } - - if (m_perform_predicates[MatrixPredicate.ExteriorBoundary]) { - boundaryAreaExteriorArea_(half_edge, id_b, id_a, - MatrixPredicate.ExteriorBoundary); - bRelationKnown &= isPredicateKnown_( - MatrixPredicate.ExteriorBoundary); - } - - return bRelationKnown; - } - - private void areaAreaDisjointPredicates_(Polygon polygon_a, Polygon polygon_b) { + } + + // Invokes the 9 relational predicates of area vs area. + private boolean areaAreaPredicates_(int half_edge, int id_a, int id_b) { + boolean bRelationKnown = true; + + if (m_perform_predicates[MatrixPredicate.InteriorInterior]) { + interiorAreaInteriorArea_(half_edge, id_a, id_b); + bRelationKnown &= isPredicateKnown_( + MatrixPredicate.InteriorInterior); + } + + if (m_perform_predicates[MatrixPredicate.InteriorBoundary]) { + interiorAreaBoundaryArea_(half_edge, id_a, + MatrixPredicate.InteriorBoundary); + bRelationKnown &= isPredicateKnown_( + MatrixPredicate.InteriorBoundary); + } + + if (m_perform_predicates[MatrixPredicate.InteriorExterior]) { + interiorAreaExteriorArea_(half_edge, id_a, id_b, + MatrixPredicate.InteriorExterior); + bRelationKnown &= isPredicateKnown_( + MatrixPredicate.InteriorExterior); + } + + if (m_perform_predicates[MatrixPredicate.BoundaryInterior]) { + interiorAreaBoundaryArea_(half_edge, id_b, + MatrixPredicate.BoundaryInterior); + bRelationKnown &= isPredicateKnown_( + MatrixPredicate.BoundaryInterior); + } + + if (m_perform_predicates[MatrixPredicate.BoundaryBoundary]) { + boundaryAreaBoundaryArea_(half_edge, id_a, id_b); + bRelationKnown &= isPredicateKnown_( + MatrixPredicate.BoundaryBoundary); + } + + if (m_perform_predicates[MatrixPredicate.BoundaryExterior]) { + boundaryAreaExteriorArea_(half_edge, id_a, id_b, + MatrixPredicate.BoundaryExterior); + bRelationKnown &= isPredicateKnown_( + MatrixPredicate.BoundaryExterior); + } + + if (m_perform_predicates[MatrixPredicate.ExteriorInterior]) { + interiorAreaExteriorArea_(half_edge, id_b, id_a, + MatrixPredicate.ExteriorInterior); + bRelationKnown &= isPredicateKnown_( + MatrixPredicate.ExteriorInterior); + } + + if (m_perform_predicates[MatrixPredicate.ExteriorBoundary]) { + boundaryAreaExteriorArea_(half_edge, id_b, id_a, + MatrixPredicate.ExteriorBoundary); + bRelationKnown &= isPredicateKnown_( + MatrixPredicate.ExteriorBoundary); + } + + return bRelationKnown; + } + + private void areaAreaDisjointPredicates_(Polygon polygon_a, Polygon polygon_b) { m_matrix[MatrixPredicate.InteriorInterior] = -1; m_matrix[MatrixPredicate.InteriorBoundary] = -1; m_matrix[MatrixPredicate.BoundaryInterior] = -1; @@ -1606,22 +1699,28 @@ private void areaAreaDisjointPredicates_(Polygon polygon_a, Polygon polygon_b) { areaGeomContainsOrDisjointPredicates_(polygon_a, m_perform_predicates[MatrixPredicate.InteriorExterior] ? MatrixPredicate.InteriorExterior : -1, m_scl.charAt(MatrixPredicate.InteriorExterior), m_perform_predicates[MatrixPredicate.BoundaryExterior] ? MatrixPredicate.BoundaryExterior : -1, m_scl.charAt(MatrixPredicate.BoundaryExterior)); areaGeomContainsOrDisjointPredicates_(polygon_b, m_perform_predicates[MatrixPredicate.ExteriorInterior] ? MatrixPredicate.ExteriorInterior : -1, m_scl.charAt(MatrixPredicate.ExteriorInterior), m_perform_predicates[MatrixPredicate.ExteriorBoundary] ? MatrixPredicate.ExteriorBoundary : -1, m_scl.charAt(MatrixPredicate.ExteriorBoundary)); - } + } - private void areaGeomContainsOrDisjointPredicates_(Polygon polygon, int matrix_interior, char c1, int matrix_boundary, char c2) { - if (matrix_interior != -1 || matrix_boundary != -1) { + private void areaGeomContainsOrDisjointPredicates_(Polygon polygon, int matrix_interior, char c1, int matrix_boundary, char c2) + { + if (matrix_interior != -1 || matrix_boundary != -1) + { boolean has_area = ((c1 != 'T' && c1 != 'F' && matrix_interior != -1) || (c2 != 'T' && c2 != 'F' && matrix_boundary != -1) ? polygon.calculateArea2D() != 0 : true); - if (has_area) { + if (has_area) + { if (matrix_interior != -1) - m_matrix[matrix_interior] = 2; + m_matrix[matrix_interior] = 2; if (matrix_boundary != -1) - m_matrix[matrix_boundary] = 1; - } else { + m_matrix[matrix_boundary] = 1; + } + else + { if (matrix_boundary != -1) - m_matrix[matrix_boundary] = -1; + m_matrix[matrix_boundary] = -1; - if (matrix_interior != -1) { + if (matrix_interior != -1) + { Envelope2D env = new Envelope2D(); polygon.queryEnvelope2D(env); m_matrix[matrix_interior] = (env.getHeight() == 0.0 && env.getWidth() == 0.0 ? 0 : 1); @@ -1630,7 +1729,7 @@ private void areaGeomContainsOrDisjointPredicates_(Polygon polygon, int matrix_i } } - private void areaAreaContainsPredicates_(Polygon polygon_b) { + private void areaAreaContainsPredicates_(Polygon polygon_b) { m_matrix[MatrixPredicate.InteriorExterior] = 2; // im assuming its a proper contains. m_matrix[MatrixPredicate.BoundaryInterior] = -1; m_matrix[MatrixPredicate.BoundaryBoundary] = -1; @@ -1643,39 +1742,43 @@ private void areaAreaContainsPredicates_(Polygon polygon_b) { // all other predicates should already be set by set_area_area_predicates } - private void areaAreaWithinPredicates_(Polygon polygon_a) { - areaAreaContainsPredicates_(polygon_a); - transposeMatrix_(m_matrix); - } + private void areaAreaWithinPredicates_(Polygon polygon_a) { + areaAreaContainsPredicates_(polygon_a); + transposeMatrix_(m_matrix); + } - private void areaLineDisjointPredicates_(Polygon polygon, Polyline polyline) { + private void areaLineDisjointPredicates_(Polygon polygon, Polyline polyline) { m_matrix[MatrixPredicate.InteriorInterior] = -1; m_matrix[MatrixPredicate.InteriorBoundary] = -1; m_matrix[MatrixPredicate.BoundaryInterior] = -1; m_matrix[MatrixPredicate.BoundaryBoundary] = -1; - if (m_perform_predicates[MatrixPredicate.ExteriorInterior]) { + if (m_perform_predicates[MatrixPredicate.ExteriorInterior]) + { char c = m_scl.charAt(MatrixPredicate.ExteriorInterior); boolean b_has_length = (c != 'T' && c != 'F' ? polyline.calculateLength2D() != 0 : true); m_matrix[MatrixPredicate.ExteriorInterior] = (b_has_length ? 1 : 0); } - if (m_perform_predicates[MatrixPredicate.ExteriorBoundary]) { + if (m_perform_predicates[MatrixPredicate.ExteriorBoundary]) + { boolean has_non_empty_boundary = Boundary.hasNonEmptyBoundary(polyline, null); m_matrix[MatrixPredicate.ExteriorBoundary] = has_non_empty_boundary ? 0 : -1; } areaGeomContainsOrDisjointPredicates_(polygon, m_perform_predicates[MatrixPredicate.InteriorExterior] ? MatrixPredicate.InteriorExterior : -1, m_scl.charAt(MatrixPredicate.InteriorExterior), m_perform_predicates[MatrixPredicate.BoundaryExterior] ? MatrixPredicate.BoundaryExterior : -1, m_scl.charAt(MatrixPredicate.BoundaryExterior)); - } + } - private void areaLineContainsPredicates_(Polygon polygon, Polyline polyline) { - if (m_perform_predicates[MatrixPredicate.InteriorInterior]) { + private void areaLineContainsPredicates_(Polygon polygon, Polyline polyline) { + if (m_perform_predicates[MatrixPredicate.InteriorInterior]) + { char c = m_scl.charAt(MatrixPredicate.InteriorInterior); boolean b_has_length = (c != 'T' && c != 'F' ? polyline.calculateLength2D() != 0 : true); m_matrix[MatrixPredicate.InteriorInterior] = (b_has_length ? 1 : 0); } - if (m_perform_predicates[MatrixPredicate.InteriorBoundary]) { + if (m_perform_predicates[MatrixPredicate.InteriorBoundary]) + { boolean has_non_empty_boundary = Boundary.hasNonEmptyBoundary(polyline, null); m_matrix[MatrixPredicate.InteriorBoundary] = has_non_empty_boundary ? 0 : -1; } @@ -1686,17 +1789,17 @@ private void areaLineContainsPredicates_(Polygon polygon, Polyline polyline) { m_matrix[MatrixPredicate.BoundaryExterior] = 1; //assume polygon has area m_matrix[MatrixPredicate.ExteriorInterior] = -1; m_matrix[MatrixPredicate.ExteriorBoundary] = -1; - } + } - private void areaPointDisjointPredicates_(Polygon polygon) { + private void areaPointDisjointPredicates_(Polygon polygon) { m_matrix[MatrixPredicate.InteriorInterior] = -1; m_matrix[MatrixPredicate.BoundaryInterior] = -1; m_matrix[MatrixPredicate.ExteriorInterior] = 0; areaGeomContainsOrDisjointPredicates_(polygon, m_perform_predicates[MatrixPredicate.InteriorExterior] ? MatrixPredicate.InteriorExterior : -1, m_scl.charAt(MatrixPredicate.InteriorExterior), m_perform_predicates[MatrixPredicate.BoundaryExterior] ? MatrixPredicate.BoundaryExterior : -1, m_scl.charAt(MatrixPredicate.BoundaryExterior)); - } + } - private void areaPointContainsPredicates_(Polygon polygon) { + private void areaPointContainsPredicates_(Polygon polygon) { m_matrix[MatrixPredicate.InteriorInterior] = 0; m_matrix[MatrixPredicate.InteriorExterior] = 2; //assume polygon has area m_matrix[MatrixPredicate.BoundaryInterior] = -1; @@ -1704,752 +1807,797 @@ private void areaPointContainsPredicates_(Polygon polygon) { m_matrix[MatrixPredicate.ExteriorInterior] = -1; } - private void lineLineDisjointPredicates_(Polyline polyline_a, - Polyline polyline_b) { + private void lineLineDisjointPredicates_(Polyline polyline_a, + Polyline polyline_b) { m_matrix[MatrixPredicate.InteriorInterior] = -1; m_matrix[MatrixPredicate.InteriorBoundary] = -1; m_matrix[MatrixPredicate.BoundaryInterior] = -1; m_matrix[MatrixPredicate.BoundaryBoundary] = -1; - if (m_perform_predicates[MatrixPredicate.InteriorExterior]) { + if (m_perform_predicates[MatrixPredicate.InteriorExterior]) + { char c = m_scl.charAt(MatrixPredicate.InteriorExterior); boolean b_has_length = (c != 'T' && c != 'F' ? polyline_a.calculateLength2D() != 0 : true); m_matrix[MatrixPredicate.InteriorExterior] = (b_has_length ? 1 : 0); } - if (m_perform_predicates[MatrixPredicate.BoundaryExterior]) { + if (m_perform_predicates[MatrixPredicate.BoundaryExterior]) + { boolean has_non_empty_boundary_a = Boundary.hasNonEmptyBoundary(polyline_a, null); m_matrix[MatrixPredicate.BoundaryExterior] = has_non_empty_boundary_a ? 0 : -1; } - if (m_perform_predicates[MatrixPredicate.ExteriorInterior]) { + if (m_perform_predicates[MatrixPredicate.ExteriorInterior]) + { char c = m_scl.charAt(MatrixPredicate.ExteriorInterior); boolean b_has_length = (c != 'T' && c != 'F' ? polyline_b.calculateLength2D() != 0 : true); m_matrix[MatrixPredicate.ExteriorInterior] = (b_has_length ? 1 : 0); } - if (m_perform_predicates[MatrixPredicate.ExteriorBoundary]) { + if (m_perform_predicates[MatrixPredicate.ExteriorBoundary]) + { boolean has_non_empty_boundary_b = Boundary.hasNonEmptyBoundary(polyline_b, null); m_matrix[MatrixPredicate.ExteriorBoundary] = has_non_empty_boundary_b ? 0 : -1; } - } + } - private void linePointDisjointPredicates_(Polyline polyline) { + private void linePointDisjointPredicates_(Polyline polyline) { m_matrix[MatrixPredicate.InteriorInterior] = -1; m_matrix[MatrixPredicate.BoundaryInterior] = -1; - if (m_perform_predicates[MatrixPredicate.InteriorExterior]) { + if (m_perform_predicates[MatrixPredicate.InteriorExterior]) + { char c = m_scl.charAt(MatrixPredicate.InteriorExterior); boolean b_has_length = (c != 'T' && c != 'F' ? polyline.calculateLength2D() != 0 : true); m_matrix[MatrixPredicate.InteriorExterior] = (b_has_length ? 1 : 0); } - if (m_perform_predicates[MatrixPredicate.BoundaryExterior]) { + if (m_perform_predicates[MatrixPredicate.BoundaryExterior]) + { boolean has_non_empty_boundary = Boundary.hasNonEmptyBoundary(polyline, null); m_matrix[MatrixPredicate.BoundaryExterior] = (has_non_empty_boundary ? 0 : -1); } m_matrix[MatrixPredicate.ExteriorInterior] = 0; - } + } - private void pointPointDisjointPredicates_() { - m_matrix[MatrixPredicate.InteriorInterior] = -1; - m_matrix[MatrixPredicate.InteriorExterior] = 0; - m_matrix[MatrixPredicate.ExteriorInterior] = 0; - } + private void pointPointDisjointPredicates_() { + m_matrix[MatrixPredicate.InteriorInterior] = -1; + m_matrix[MatrixPredicate.InteriorExterior] = 0; + m_matrix[MatrixPredicate.ExteriorInterior] = 0; + } - // Invokes the 9 relational predicates of area vs Line. - private boolean areaLinePredicates_(int half_edge, int id_a, int id_b) { + // Invokes the 9 relational predicates of area vs Line. + private boolean areaLinePredicates_(int half_edge, int id_a, int id_b) { boolean bRelationKnown = true; - if (m_perform_predicates[MatrixPredicate.InteriorInterior]) { + if (m_perform_predicates[MatrixPredicate.InteriorInterior]) + { interiorAreaInteriorLine_(half_edge, id_a, id_b); bRelationKnown &= isPredicateKnown_(MatrixPredicate.InteriorInterior); } - if (m_perform_predicates[MatrixPredicate.InteriorBoundary]) { + if (m_perform_predicates[MatrixPredicate.InteriorBoundary]) + { interiorAreaBoundaryLine_(half_edge, id_a, id_b, m_cluster_index_b); bRelationKnown &= isPredicateKnown_(MatrixPredicate.InteriorBoundary); } - if (m_perform_predicates[MatrixPredicate.InteriorExterior]) { + if (m_perform_predicates[MatrixPredicate.InteriorExterior]) + { interiorAreaExteriorLine_(half_edge, id_a, id_b); bRelationKnown &= isPredicateKnown_(MatrixPredicate.InteriorExterior); } - if (m_perform_predicates[MatrixPredicate.BoundaryInterior]) { + if (m_perform_predicates[MatrixPredicate.BoundaryInterior]) + { boundaryAreaInteriorLine_(half_edge, id_a, id_b, m_cluster_index_b); bRelationKnown &= isPredicateKnown_(MatrixPredicate.BoundaryInterior); } - if (m_perform_predicates[MatrixPredicate.BoundaryBoundary]) { + if (m_perform_predicates[MatrixPredicate.BoundaryBoundary]) + { boundaryAreaBoundaryLine_(half_edge, id_a, id_b, m_cluster_index_b); bRelationKnown &= isPredicateKnown_(MatrixPredicate.BoundaryBoundary); } - if (m_perform_predicates[MatrixPredicate.BoundaryExterior]) { + if (m_perform_predicates[MatrixPredicate.BoundaryExterior]) + { boundaryAreaExteriorLine_(half_edge, id_a, id_b); bRelationKnown &= isPredicateKnown_(MatrixPredicate.BoundaryExterior); } - if (m_perform_predicates[MatrixPredicate.ExteriorInterior]) { + if (m_perform_predicates[MatrixPredicate.ExteriorInterior]) + { exteriorAreaInteriorLine_(half_edge, id_a); bRelationKnown &= isPredicateKnown_(MatrixPredicate.ExteriorInterior); } - if (m_perform_predicates[MatrixPredicate.ExteriorBoundary]) { + if (m_perform_predicates[MatrixPredicate.ExteriorBoundary]) + { exteriorAreaBoundaryLine_(half_edge, id_a, id_b, m_cluster_index_b); bRelationKnown &= isPredicateKnown_(MatrixPredicate.ExteriorBoundary); } return bRelationKnown; - } + } - // Invokes the 9 relational predicates of Line vs Line. - private boolean lineLinePredicates_(int half_edge, int id_a, int id_b) { + // Invokes the 9 relational predicates of Line vs Line. + private boolean lineLinePredicates_(int half_edge, int id_a, int id_b) { boolean bRelationKnown = true; - if (m_perform_predicates[MatrixPredicate.InteriorInterior]) { + if (m_perform_predicates[MatrixPredicate.InteriorInterior]) + { interiorLineInteriorLine_(half_edge, id_a, id_b, m_cluster_index_a, m_cluster_index_b); bRelationKnown &= isPredicateKnown_(MatrixPredicate.InteriorInterior); } - if (m_perform_predicates[MatrixPredicate.InteriorBoundary]) { + if (m_perform_predicates[MatrixPredicate.InteriorBoundary]) + { interiorLineBoundaryLine_(half_edge, id_a, id_b, m_cluster_index_a, m_cluster_index_b, MatrixPredicate.InteriorBoundary); bRelationKnown &= isPredicateKnown_(MatrixPredicate.InteriorBoundary); } - if (m_perform_predicates[MatrixPredicate.InteriorExterior]) { + if (m_perform_predicates[MatrixPredicate.InteriorExterior]) + { interiorLineExteriorLine_(half_edge, id_a, id_b, MatrixPredicate.InteriorExterior); bRelationKnown &= isPredicateKnown_(MatrixPredicate.InteriorExterior); } - if (m_perform_predicates[MatrixPredicate.BoundaryInterior]) { + if (m_perform_predicates[MatrixPredicate.BoundaryInterior]) + { interiorLineBoundaryLine_(half_edge, id_b, id_a, m_cluster_index_b, m_cluster_index_a, MatrixPredicate.BoundaryInterior); bRelationKnown &= isPredicateKnown_(MatrixPredicate.BoundaryInterior); } - if (m_perform_predicates[MatrixPredicate.BoundaryBoundary]) { + if (m_perform_predicates[MatrixPredicate.BoundaryBoundary]) + { boundaryLineBoundaryLine_(half_edge, id_a, id_b, m_cluster_index_a, m_cluster_index_b); bRelationKnown &= isPredicateKnown_(MatrixPredicate.BoundaryBoundary); } - if (m_perform_predicates[MatrixPredicate.BoundaryExterior]) { + if (m_perform_predicates[MatrixPredicate.BoundaryExterior]) + { boundaryLineExteriorLine_(half_edge, id_a, id_b, m_cluster_index_a, MatrixPredicate.BoundaryExterior); bRelationKnown &= isPredicateKnown_(MatrixPredicate.BoundaryExterior); } - if (m_perform_predicates[MatrixPredicate.ExteriorInterior]) { + if (m_perform_predicates[MatrixPredicate.ExteriorInterior]) + { interiorLineExteriorLine_(half_edge, id_b, id_a, MatrixPredicate.ExteriorInterior); bRelationKnown &= isPredicateKnown_(MatrixPredicate.ExteriorInterior); } - if (m_perform_predicates[MatrixPredicate.ExteriorBoundary]) { + if (m_perform_predicates[MatrixPredicate.ExteriorBoundary]) + { boundaryLineExteriorLine_(half_edge, id_b, id_a, m_cluster_index_b, MatrixPredicate.ExteriorBoundary); bRelationKnown &= isPredicateKnown_(MatrixPredicate.ExteriorBoundary); } return bRelationKnown; - } + } - // Invokes the 9 relational predicates of area vs Point. - private boolean areaPointPredicates_(int cluster, int id_a, int id_b) { + // Invokes the 9 relational predicates of area vs Point. + private boolean areaPointPredicates_(int cluster, int id_a, int id_b) { boolean bRelationKnown = true; - if (m_perform_predicates[MatrixPredicate.InteriorInterior]) { + if (m_perform_predicates[MatrixPredicate.InteriorInterior]) + { interiorAreaInteriorPoint_(cluster, id_a); bRelationKnown &= isPredicateKnown_(MatrixPredicate.InteriorInterior); } - if (m_perform_predicates[MatrixPredicate.InteriorExterior]) { + if (m_perform_predicates[MatrixPredicate.InteriorExterior]) + { interiorAreaExteriorPoint_(cluster, id_a); bRelationKnown &= isPredicateKnown_(MatrixPredicate.InteriorExterior); } - if (m_perform_predicates[MatrixPredicate.BoundaryInterior]) { + if (m_perform_predicates[MatrixPredicate.BoundaryInterior]) + { boundaryAreaInteriorPoint_(cluster, id_a, id_b); bRelationKnown &= isPredicateKnown_(MatrixPredicate.BoundaryInterior); } - if (m_perform_predicates[MatrixPredicate.BoundaryExterior]) { + if (m_perform_predicates[MatrixPredicate.BoundaryExterior]) + { boundaryAreaExteriorPoint_(cluster, id_a); bRelationKnown &= isPredicateKnown_(MatrixPredicate.BoundaryExterior); } - if (m_perform_predicates[MatrixPredicate.ExteriorInterior]) { + if (m_perform_predicates[MatrixPredicate.ExteriorInterior]) + { exteriorAreaInteriorPoint_(cluster, id_a); bRelationKnown &= isPredicateKnown_(MatrixPredicate.ExteriorInterior); } return bRelationKnown; - } + } - // Invokes the 9 relational predicates of Line vs Point. - private boolean linePointPredicates_(int cluster, int id_a, int id_b) { + // Invokes the 9 relational predicates of Line vs Point. + private boolean linePointPredicates_(int cluster, int id_a, int id_b) { boolean bRelationKnown = true; - if (m_perform_predicates[MatrixPredicate.InteriorInterior]) { + if (m_perform_predicates[MatrixPredicate.InteriorInterior]) + { interiorLineInteriorPoint_(cluster, id_a, id_b, m_cluster_index_a); bRelationKnown &= isPredicateKnown_(MatrixPredicate.InteriorInterior); } - if (m_perform_predicates[MatrixPredicate.InteriorExterior]) { + if (m_perform_predicates[MatrixPredicate.InteriorExterior]) + { interiorLineExteriorPoint_(cluster, id_a, id_b, m_cluster_index_a); bRelationKnown &= isPredicateKnown_(MatrixPredicate.InteriorExterior); } - if (m_perform_predicates[MatrixPredicate.BoundaryInterior]) { + if (m_perform_predicates[MatrixPredicate.BoundaryInterior]) + { boundaryLineInteriorPoint_(cluster, id_a, id_b, m_cluster_index_a); bRelationKnown &= isPredicateKnown_(MatrixPredicate.BoundaryInterior); } - if (m_perform_predicates[MatrixPredicate.BoundaryExterior]) { + if (m_perform_predicates[MatrixPredicate.BoundaryExterior]) + { boundaryLineExteriorPoint_(cluster, id_a, id_b, m_cluster_index_a); bRelationKnown &= isPredicateKnown_(MatrixPredicate.BoundaryExterior); } - if (m_perform_predicates[MatrixPredicate.ExteriorInterior]) { + if (m_perform_predicates[MatrixPredicate.ExteriorInterior]) + { exteriorLineInteriorPoint_(cluster, id_a, id_b); bRelationKnown &= isPredicateKnown_(MatrixPredicate.ExteriorInterior); } return bRelationKnown; - } + } - // Invokes the 9 relational predicates of Point vs Point. - private boolean pointPointPredicates_(int cluster, int id_a, int id_b) { + // Invokes the 9 relational predicates of Point vs Point. + private boolean pointPointPredicates_(int cluster, int id_a, int id_b) { boolean bRelationKnown = true; - if (m_perform_predicates[MatrixPredicate.InteriorInterior]) { + if (m_perform_predicates[MatrixPredicate.InteriorInterior]) + { interiorPointInteriorPoint_(cluster, id_a, id_b); bRelationKnown &= isPredicateKnown_(MatrixPredicate.InteriorInterior); } - if (m_perform_predicates[MatrixPredicate.InteriorExterior]) { + if (m_perform_predicates[MatrixPredicate.InteriorExterior]) + { interiorPointExteriorPoint_(cluster, id_a, id_b, MatrixPredicate.InteriorExterior); bRelationKnown &= isPredicateKnown_(MatrixPredicate.InteriorExterior); } - if (m_perform_predicates[MatrixPredicate.ExteriorInterior]) { + if (m_perform_predicates[MatrixPredicate.ExteriorInterior]) + { interiorPointExteriorPoint_(cluster, id_b, id_a, MatrixPredicate.ExteriorInterior); bRelationKnown &= isPredicateKnown_(MatrixPredicate.ExteriorInterior); } return bRelationKnown; - } - - // Relational predicate to determine if the interior of area A intersects - // with the interior of area B. - private void interiorAreaInteriorArea_(int half_edge, int id_a, int id_b) { - if (m_matrix[MatrixPredicate.InteriorInterior] == 2) - return; - - int faceParentage = m_topo_graph.getHalfEdgeFaceParentage(half_edge); - - if ((faceParentage & id_a) != 0 && (faceParentage & id_b) != 0) - m_matrix[MatrixPredicate.InteriorInterior] = 2; - } - - // Relational predicate to determine if the interior of area A intersects - // with the boundary of area B. - private void interiorAreaBoundaryArea_(int half_edge, int id_a, - int predicate) { - if (m_matrix[predicate] == 1) - return; - - int faceParentage = m_topo_graph.getHalfEdgeFaceParentage(half_edge); - int twinFaceParentage = m_topo_graph - .getHalfEdgeFaceParentage(m_topo_graph - .getHalfEdgeTwin(half_edge)); - - if ((faceParentage & id_a) != 0 && (twinFaceParentage & id_a) != 0) - m_matrix[predicate] = 1; - } - - // Relational predicate to determine if the interior of area A intersects - // with the exterior of area B. - private void interiorAreaExteriorArea_(int half_edge, int id_a, int id_b, - int predicate) { - if (m_matrix[predicate] == 2) - return; - - int faceParentage = m_topo_graph.getHalfEdgeFaceParentage(half_edge); - - if ((faceParentage & id_a) != 0 && (faceParentage & id_b) == 0) - m_matrix[predicate] = 2; - - } - - // Relational predicate to determine if the boundary of area A intersects - // with the boundary of area B. - private void boundaryAreaBoundaryArea_(int half_edge, int id_a, int id_b) { - if (m_matrix[MatrixPredicate.BoundaryBoundary] == 1) - return; - - int parentage = m_topo_graph.getHalfEdgeParentage(half_edge); - - if ((parentage & id_a) != 0 && (parentage & id_b) != 0) { - m_matrix[MatrixPredicate.BoundaryBoundary] = 1; - return; - } - - if (m_matrix[MatrixPredicate.BoundaryBoundary] != 0) { - if (m_topo_graph.getHalfEdgeUserIndex(m_topo_graph - .getHalfEdgePrev(m_topo_graph.getHalfEdgeTwin(half_edge)), - m_visited_index) != 1) { - int cluster = m_topo_graph.getHalfEdgeTo(half_edge); - int clusterParentage = m_topo_graph - .getClusterParentage(cluster); - - if ((clusterParentage & id_a) != 0 - && (clusterParentage & id_b) != 0) { - m_matrix[MatrixPredicate.BoundaryBoundary] = 0; - } - } - } - } - - // Relational predicate to determine if the boundary of area A intersects - // with the exterior of area B. - private void boundaryAreaExteriorArea_(int half_edge, int id_a, int id_b, - int predicate) { - if (m_matrix[predicate] == 1) - return; - - int faceParentage = m_topo_graph.getHalfEdgeFaceParentage(half_edge); - int twinFaceParentage = m_topo_graph - .getHalfEdgeFaceParentage(m_topo_graph - .getHalfEdgeTwin(half_edge)); - - if ((faceParentage & id_b) == 0 && (twinFaceParentage & id_b) == 0) - m_matrix[predicate] = 1; - } - - // Relational predicate to determine if the interior of area A intersects - // with the interior of Line B. - private void interiorAreaInteriorLine_(int half_edge, int id_a, int id_b) { - if (m_matrix[MatrixPredicate.InteriorInterior] == 1) - return; - - int faceParentage = m_topo_graph.getHalfEdgeFaceParentage(half_edge); - int twinFaceParentage = m_topo_graph - .getHalfEdgeFaceParentage(m_topo_graph - .getHalfEdgeTwin(half_edge)); - - if ((faceParentage & id_a) != 0 && (twinFaceParentage & id_a) != 0) - m_matrix[MatrixPredicate.InteriorInterior] = 1; - } - - // Relational predicate to determine if the interior of area A intersects - // with the boundary of Line B. - private void interiorAreaBoundaryLine_(int half_edge, int id_a, int id_b, - int cluster_index_b) { - if (m_matrix[MatrixPredicate.InteriorBoundary] == 0) - return; - - if (m_topo_graph.getHalfEdgeUserIndex(m_topo_graph - .getHalfEdgePrev(m_topo_graph.getHalfEdgeTwin(half_edge)), - m_visited_index) != 1) { - int cluster = m_topo_graph.getHalfEdgeTo(half_edge); - int clusterParentage = m_topo_graph.getClusterParentage(cluster); - - if ((clusterParentage & id_a) == 0) { - int faceParentage = m_topo_graph - .getHalfEdgeFaceParentage(half_edge); - - if ((faceParentage & id_a) != 0) { - int index = m_topo_graph.getClusterUserIndex(cluster, - cluster_index_b); - - if ((clusterParentage & id_b) != 0 && (index % 2 != 0)) { - assert (index != -1); - m_matrix[MatrixPredicate.InteriorBoundary] = 0; - } - } - } - } - } - - private void interiorAreaExteriorLine_(int half_edge, int id_a, int id_b) { + } + + // Relational predicate to determine if the interior of area A intersects + // with the interior of area B. + private void interiorAreaInteriorArea_(int half_edge, int id_a, int id_b) { + if (m_matrix[MatrixPredicate.InteriorInterior] == 2) + return; + + int faceParentage = m_topo_graph.getHalfEdgeFaceParentage(half_edge); + + if ((faceParentage & id_a) != 0 && (faceParentage & id_b) != 0) + m_matrix[MatrixPredicate.InteriorInterior] = 2; + } + + // Relational predicate to determine if the interior of area A intersects + // with the boundary of area B. + private void interiorAreaBoundaryArea_(int half_edge, int id_a, + int predicate) { + if (m_matrix[predicate] == 1) + return; + + int faceParentage = m_topo_graph.getHalfEdgeFaceParentage(half_edge); + int twinFaceParentage = m_topo_graph + .getHalfEdgeFaceParentage(m_topo_graph + .getHalfEdgeTwin(half_edge)); + + if ((faceParentage & id_a) != 0 && (twinFaceParentage & id_a) != 0) + m_matrix[predicate] = 1; + } + + // Relational predicate to determine if the interior of area A intersects + // with the exterior of area B. + private void interiorAreaExteriorArea_(int half_edge, int id_a, int id_b, + int predicate) { + if (m_matrix[predicate] == 2) + return; + + int faceParentage = m_topo_graph.getHalfEdgeFaceParentage(half_edge); + + if ((faceParentage & id_a) != 0 && (faceParentage & id_b) == 0) + m_matrix[predicate] = 2; + + } + + // Relational predicate to determine if the boundary of area A intersects + // with the boundary of area B. + private void boundaryAreaBoundaryArea_(int half_edge, int id_a, int id_b) { + if (m_matrix[MatrixPredicate.BoundaryBoundary] == 1) + return; + + int parentage = m_topo_graph.getHalfEdgeParentage(half_edge); + + if ((parentage & id_a) != 0 && (parentage & id_b) != 0) { + m_matrix[MatrixPredicate.BoundaryBoundary] = 1; + return; + } + + if (m_matrix[MatrixPredicate.BoundaryBoundary] != 0) { + if (m_topo_graph.getHalfEdgeUserIndex(m_topo_graph + .getHalfEdgePrev(m_topo_graph.getHalfEdgeTwin(half_edge)), + m_visited_index) != 1) { + int cluster = m_topo_graph.getHalfEdgeTo(half_edge); + int clusterParentage = m_topo_graph + .getClusterParentage(cluster); + + if ((clusterParentage & id_a) != 0 + && (clusterParentage & id_b) != 0) { + m_matrix[MatrixPredicate.BoundaryBoundary] = 0; + } + } + } + } + + // Relational predicate to determine if the boundary of area A intersects + // with the exterior of area B. + private void boundaryAreaExteriorArea_(int half_edge, int id_a, int id_b, + int predicate) { + if (m_matrix[predicate] == 1) + return; + + int faceParentage = m_topo_graph.getHalfEdgeFaceParentage(half_edge); + int twinFaceParentage = m_topo_graph + .getHalfEdgeFaceParentage(m_topo_graph + .getHalfEdgeTwin(half_edge)); + + if ((faceParentage & id_b) == 0 && (twinFaceParentage & id_b) == 0) + m_matrix[predicate] = 1; + } + + // Relational predicate to determine if the interior of area A intersects + // with the interior of Line B. + private void interiorAreaInteriorLine_(int half_edge, int id_a, int id_b) { + if (m_matrix[MatrixPredicate.InteriorInterior] == 1) + return; + + int faceParentage = m_topo_graph.getHalfEdgeFaceParentage(half_edge); + int twinFaceParentage = m_topo_graph + .getHalfEdgeFaceParentage(m_topo_graph + .getHalfEdgeTwin(half_edge)); + + if ((faceParentage & id_a) != 0 && (twinFaceParentage & id_a) != 0) + m_matrix[MatrixPredicate.InteriorInterior] = 1; + } + + // Relational predicate to determine if the interior of area A intersects + // with the boundary of Line B. + private void interiorAreaBoundaryLine_(int half_edge, int id_a, int id_b, + int cluster_index_b) { + if (m_matrix[MatrixPredicate.InteriorBoundary] == 0) + return; + + if (m_topo_graph.getHalfEdgeUserIndex(m_topo_graph + .getHalfEdgePrev(m_topo_graph.getHalfEdgeTwin(half_edge)), + m_visited_index) != 1) { + int cluster = m_topo_graph.getHalfEdgeTo(half_edge); + int clusterParentage = m_topo_graph.getClusterParentage(cluster); + + if ((clusterParentage & id_a) == 0) { + int faceParentage = m_topo_graph + .getHalfEdgeFaceParentage(half_edge); + + if ((faceParentage & id_a) != 0) { + int index = m_topo_graph.getClusterUserIndex(cluster, + cluster_index_b); + + if ((clusterParentage & id_b) != 0 && (index % 2 != 0)) { + assert (index != -1); + m_matrix[MatrixPredicate.InteriorBoundary] = 0; + } + } + } + } + } + + private void interiorAreaExteriorLine_(int half_edge, int id_a, int id_b) + { if (m_matrix[MatrixPredicate.InteriorExterior] == 2) return; int half_edge_parentage = m_topo_graph.getHalfEdgeParentage(half_edge); - if ((half_edge_parentage & id_a) != 0) {//half edge of polygon + if ((half_edge_parentage & id_a) != 0) + {//half edge of polygon m_matrix[MatrixPredicate.InteriorExterior] = 2; } } - // Relational predicate to determine if the boundary of area A intersects - // with the interior of Line B. - private void boundaryAreaInteriorLine_(int half_edge, int id_a, int id_b, - int cluster_index_b) { - if (m_matrix[MatrixPredicate.BoundaryInterior] == 1) - return; - - int parentage = m_topo_graph.getHalfEdgeParentage(half_edge); - - if ((parentage & id_a) != 0 && (parentage & id_b) != 0) { - m_matrix[MatrixPredicate.BoundaryInterior] = 1; - return; - } - - if (m_matrix[MatrixPredicate.BoundaryInterior] != 0) { - if (m_topo_graph.getHalfEdgeUserIndex(m_topo_graph - .getHalfEdgePrev(m_topo_graph.getHalfEdgeTwin(half_edge)), - m_visited_index) != 1) { - int cluster = m_topo_graph.getHalfEdgeTo(half_edge); - int clusterParentage = m_topo_graph - .getClusterParentage(cluster); - - if ((clusterParentage & id_a) != 0) { - int index = m_topo_graph.getClusterUserIndex(cluster, - cluster_index_b); - - if ((clusterParentage & id_b) != 0 && (index % 2 == 0)) { - assert (index != -1); - m_matrix[MatrixPredicate.BoundaryInterior] = 0; - } - } - } - } - } - - // Relational predicate to determine if the boundary of area A intersects - // with the boundary of Line B. - private void boundaryAreaBoundaryLine_(int half_edge, int id_a, int id_b, - int cluster_index_b) { - if (m_matrix[MatrixPredicate.BoundaryBoundary] == 0) - return; - - if (m_topo_graph.getHalfEdgeUserIndex(m_topo_graph - .getHalfEdgePrev(m_topo_graph.getHalfEdgeTwin(half_edge)), - m_visited_index) != 1) { - int cluster = m_topo_graph.getHalfEdgeTo(half_edge); - int clusterParentage = m_topo_graph.getClusterParentage(cluster); - - if ((clusterParentage & id_a) != 0) { - int index = m_topo_graph.getClusterUserIndex(cluster, - cluster_index_b); - - if ((clusterParentage & id_b) != 0 && (index % 2 != 0)) { - assert (index != -1); - m_matrix[MatrixPredicate.BoundaryBoundary] = 0; - } - } - } - } - - // Relational predicate to determine if the boundary of area A intersects - // with the exterior of Line B. - private void boundaryAreaExteriorLine_(int half_edge, int id_a, int id_b) { - if (m_matrix[MatrixPredicate.BoundaryExterior] == 1) - return; - - int parentage = m_topo_graph.getHalfEdgeParentage(half_edge); - - if ((parentage & id_a) != 0 && (parentage & id_b) == 0) - m_matrix[MatrixPredicate.BoundaryExterior] = 1; - - } - - // Relational predicate to determine if the exterior of area A intersects - // with the interior of Line B. - private void exteriorAreaInteriorLine_(int half_edge, int id_a) { - if (m_matrix[MatrixPredicate.ExteriorInterior] == 1) - return; - - int faceParentage = m_topo_graph.getHalfEdgeFaceParentage(half_edge); - int twinFaceParentage = m_topo_graph - .getHalfEdgeFaceParentage(m_topo_graph - .getHalfEdgeTwin(half_edge)); - - if ((faceParentage & id_a) == 0 && (twinFaceParentage & id_a) == 0) - m_matrix[MatrixPredicate.ExteriorInterior] = 1; - } - - // Relational predicate to determine if the exterior of area A intersects - // with the boundary of Line B. - private void exteriorAreaBoundaryLine_(int half_edge, int id_a, int id_b, - int cluster_index_b) { - if (m_matrix[MatrixPredicate.ExteriorBoundary] == 0) - return; - - if (m_topo_graph.getHalfEdgeUserIndex(m_topo_graph - .getHalfEdgePrev(m_topo_graph.getHalfEdgeTwin(half_edge)), - m_visited_index) != 1) { - int cluster = m_topo_graph.getHalfEdgeTo(half_edge); - int clusterParentage = m_topo_graph.getClusterParentage(cluster); - - if ((clusterParentage & id_a) == 0) { - int faceParentage = m_topo_graph - .getHalfEdgeFaceParentage(half_edge); - - if ((faceParentage & id_a) == 0) { - assert ((m_topo_graph.getHalfEdgeParentage(m_topo_graph - .getHalfEdgeTwin(half_edge)) & id_a) == 0); - - int index = m_topo_graph.getClusterUserIndex(cluster, - cluster_index_b); - - if ((clusterParentage & id_b) != 0 && (index % 2 != 0)) { - assert (index != -1); - m_matrix[MatrixPredicate.ExteriorBoundary] = 0; - } - } - } - } - } - - // Relational predicate to determine if the interior of Line A intersects - // with the interior of Line B. - private void interiorLineInteriorLine_(int half_edge, int id_a, int id_b, - int cluster_index_a, int cluster_index_b) { - if (m_matrix[MatrixPredicate.InteriorInterior] == 1) - return; - - int parentage = m_topo_graph.getHalfEdgeParentage(half_edge); - - if ((parentage & id_a) != 0 && (parentage & id_b) != 0) { - m_matrix[MatrixPredicate.InteriorInterior] = 1; - return; - } - - if (m_matrix[MatrixPredicate.InteriorInterior] != 0) { - if (m_topo_graph.getHalfEdgeUserIndex(m_topo_graph - .getHalfEdgePrev(m_topo_graph.getHalfEdgeTwin(half_edge)), - m_visited_index) != 1) { - int cluster = m_topo_graph.getHalfEdgeTo(half_edge); - int clusterParentage = m_topo_graph - .getClusterParentage(cluster); - - if ((clusterParentage & id_a) != 0 - && (clusterParentage & id_b) != 0) { - int index_a = m_topo_graph.getClusterUserIndex(cluster, - cluster_index_a); - int index_b = m_topo_graph.getClusterUserIndex(cluster, - cluster_index_b); - assert (index_a != -1); - assert (index_b != -1); - - if ((index_a % 2 == 0) && (index_b % 2 == 0)) { - assert ((m_topo_graph.getClusterParentage(cluster) & id_a) != 0 && (m_topo_graph - .getClusterParentage(cluster) & id_b) != 0); - m_matrix[MatrixPredicate.InteriorInterior] = 0; - } - } - } - } - } - - // Relational predicate to determine of the interior of LineA intersects - // with the boundary of Line B. - private void interiorLineBoundaryLine_(int half_edge, int id_a, int id_b, - int cluster_index_a, int cluster_index_b, int predicate) { - if (m_matrix[predicate] == 0) - return; - - if (m_topo_graph.getHalfEdgeUserIndex(m_topo_graph - .getHalfEdgePrev(m_topo_graph.getHalfEdgeTwin(half_edge)), - m_visited_index) != 1) { - int cluster = m_topo_graph.getHalfEdgeTo(half_edge); - int clusterParentage = m_topo_graph.getClusterParentage(cluster); - - if ((clusterParentage & id_a) != 0 - && (clusterParentage & id_b) != 0) { - int index_a = m_topo_graph.getClusterUserIndex(cluster, - cluster_index_a); - int index_b = m_topo_graph.getClusterUserIndex(cluster, - cluster_index_b); - assert (index_a != -1); - assert (index_b != -1); - - if ((index_a % 2 == 0) && (index_b % 2 != 0)) { - assert ((m_topo_graph.getClusterParentage(cluster) & id_a) != 0 && (m_topo_graph - .getClusterParentage(cluster) & id_b) != 0); - m_matrix[predicate] = 0; - } - } - } - } - - // Relational predicate to determine if the interior of Line A intersects - // with the exterior of Line B. - private void interiorLineExteriorLine_(int half_edge, int id_a, int id_b, - int predicate) { - if (m_matrix[predicate] == 1) - return; - - int parentage = m_topo_graph.getHalfEdgeParentage(half_edge); - - if ((parentage & id_a) != 0 && (parentage & id_b) == 0) - m_matrix[predicate] = 1; - } - - // Relational predicate to determine if the boundary of Line A intersects - // with the boundary of Line B. - private void boundaryLineBoundaryLine_(int half_edge, int id_a, int id_b, - int cluster_index_a, int cluster_index_b) { - if (m_matrix[MatrixPredicate.BoundaryBoundary] == 0) - return; - - if (m_topo_graph.getHalfEdgeUserIndex(m_topo_graph - .getHalfEdgePrev(m_topo_graph.getHalfEdgeTwin(half_edge)), - m_visited_index) != 1) { - int cluster = m_topo_graph.getHalfEdgeTo(half_edge); - int clusterParentage = m_topo_graph.getClusterParentage(cluster); - - if ((clusterParentage & id_a) != 0 - && (clusterParentage & id_b) != 0) { - int index_a = m_topo_graph.getClusterUserIndex(cluster, - cluster_index_a); - int index_b = m_topo_graph.getClusterUserIndex(cluster, - cluster_index_b); - assert (index_a != -1); - assert (index_b != -1); - - if ((index_a % 2 != 0) && (index_b % 2 != 0)) { - assert ((m_topo_graph.getClusterParentage(cluster) & id_a) != 0 && (m_topo_graph - .getClusterParentage(cluster) & id_b) != 0); - m_matrix[MatrixPredicate.BoundaryBoundary] = 0; - } - } - } - } - - // Relational predicate to determine if the boundary of Line A intersects - // with the exterior of Line B. - private void boundaryLineExteriorLine_(int half_edge, int id_a, int id_b, - int cluster_index_a, int predicate) { - if (m_matrix[predicate] == 0) - return; - - if (m_topo_graph.getHalfEdgeUserIndex(m_topo_graph - .getHalfEdgePrev(m_topo_graph.getHalfEdgeTwin(half_edge)), - m_visited_index) != 1) { - int cluster = m_topo_graph.getHalfEdgeTo(half_edge); - int clusterParentage = m_topo_graph.getClusterParentage(cluster); - - if ((clusterParentage & id_b) == 0) { - int index = m_topo_graph.getClusterUserIndex(cluster, - cluster_index_a); - assert (index != -1); - - if (index % 2 != 0) { - assert ((m_topo_graph.getClusterParentage(cluster) & id_a) != 0); - m_matrix[predicate] = 0; - } - } - } - } - - // Relational predicate to determine if the interior of area A intersects - // with the interior of Point B. - private void interiorAreaInteriorPoint_(int cluster, int id_a) { - if (m_matrix[MatrixPredicate.InteriorInterior] == 0) - return; - - int clusterParentage = m_topo_graph.getClusterParentage(cluster); - - if ((clusterParentage & id_a) == 0) { - int chain = m_topo_graph.getClusterChain(cluster); - int chainParentage = m_topo_graph.getChainParentage(chain); - - if ((chainParentage & id_a) != 0) { - m_matrix[MatrixPredicate.InteriorInterior] = 0; - } - } - } - - private void interiorAreaExteriorPoint_(int cluster, int id_a) { + // Relational predicate to determine if the boundary of area A intersects + // with the interior of Line B. + private void boundaryAreaInteriorLine_(int half_edge, int id_a, int id_b, + int cluster_index_b) { + if (m_matrix[MatrixPredicate.BoundaryInterior] == 1) + return; + + int parentage = m_topo_graph.getHalfEdgeParentage(half_edge); + + if ((parentage & id_a) != 0 && (parentage & id_b) != 0) { + m_matrix[MatrixPredicate.BoundaryInterior] = 1; + return; + } + + if (m_matrix[MatrixPredicate.BoundaryInterior] != 0) { + if (m_topo_graph.getHalfEdgeUserIndex(m_topo_graph + .getHalfEdgePrev(m_topo_graph.getHalfEdgeTwin(half_edge)), + m_visited_index) != 1) { + int cluster = m_topo_graph.getHalfEdgeTo(half_edge); + int clusterParentage = m_topo_graph + .getClusterParentage(cluster); + + if ((clusterParentage & id_a) != 0) { + int index = m_topo_graph.getClusterUserIndex(cluster, + cluster_index_b); + + if ((clusterParentage & id_b) != 0 && (index % 2 == 0)) { + assert (index != -1); + m_matrix[MatrixPredicate.BoundaryInterior] = 0; + } + } + } + } + } + + // Relational predicate to determine if the boundary of area A intersects + // with the boundary of Line B. + private void boundaryAreaBoundaryLine_(int half_edge, int id_a, int id_b, + int cluster_index_b) { + if (m_matrix[MatrixPredicate.BoundaryBoundary] == 0) + return; + + if (m_topo_graph.getHalfEdgeUserIndex(m_topo_graph + .getHalfEdgePrev(m_topo_graph.getHalfEdgeTwin(half_edge)), + m_visited_index) != 1) { + int cluster = m_topo_graph.getHalfEdgeTo(half_edge); + int clusterParentage = m_topo_graph.getClusterParentage(cluster); + + if ((clusterParentage & id_a) != 0) { + int index = m_topo_graph.getClusterUserIndex(cluster, + cluster_index_b); + + if ((clusterParentage & id_b) != 0 && (index % 2 != 0)) { + assert (index != -1); + m_matrix[MatrixPredicate.BoundaryBoundary] = 0; + } + } + } + } + + // Relational predicate to determine if the boundary of area A intersects + // with the exterior of Line B. + private void boundaryAreaExteriorLine_(int half_edge, int id_a, int id_b) { + if (m_matrix[MatrixPredicate.BoundaryExterior] == 1) + return; + + int parentage = m_topo_graph.getHalfEdgeParentage(half_edge); + + if ((parentage & id_a) != 0 && (parentage & id_b) == 0) + m_matrix[MatrixPredicate.BoundaryExterior] = 1; + + } + + // Relational predicate to determine if the exterior of area A intersects + // with the interior of Line B. + private void exteriorAreaInteriorLine_(int half_edge, int id_a) { + if (m_matrix[MatrixPredicate.ExteriorInterior] == 1) + return; + + int faceParentage = m_topo_graph.getHalfEdgeFaceParentage(half_edge); + int twinFaceParentage = m_topo_graph + .getHalfEdgeFaceParentage(m_topo_graph + .getHalfEdgeTwin(half_edge)); + + if ((faceParentage & id_a) == 0 && (twinFaceParentage & id_a) == 0) + m_matrix[MatrixPredicate.ExteriorInterior] = 1; + } + + // Relational predicate to determine if the exterior of area A intersects + // with the boundary of Line B. + private void exteriorAreaBoundaryLine_(int half_edge, int id_a, int id_b, + int cluster_index_b) { + if (m_matrix[MatrixPredicate.ExteriorBoundary] == 0) + return; + + if (m_topo_graph.getHalfEdgeUserIndex(m_topo_graph + .getHalfEdgePrev(m_topo_graph.getHalfEdgeTwin(half_edge)), + m_visited_index) != 1) { + int cluster = m_topo_graph.getHalfEdgeTo(half_edge); + int clusterParentage = m_topo_graph.getClusterParentage(cluster); + + if ((clusterParentage & id_a) == 0) { + int faceParentage = m_topo_graph + .getHalfEdgeFaceParentage(half_edge); + + if ((faceParentage & id_a) == 0) { + assert ((m_topo_graph.getHalfEdgeParentage(m_topo_graph + .getHalfEdgeTwin(half_edge)) & id_a) == 0); + + int index = m_topo_graph.getClusterUserIndex(cluster, + cluster_index_b); + + if ((clusterParentage & id_b) != 0 && (index % 2 != 0)) { + assert (index != -1); + m_matrix[MatrixPredicate.ExteriorBoundary] = 0; + } + } + } + } + } + + // Relational predicate to determine if the interior of Line A intersects + // with the interior of Line B. + private void interiorLineInteriorLine_(int half_edge, int id_a, int id_b, + int cluster_index_a, int cluster_index_b) { + if (m_matrix[MatrixPredicate.InteriorInterior] == 1) + return; + + int parentage = m_topo_graph.getHalfEdgeParentage(half_edge); + + if ((parentage & id_a) != 0 && (parentage & id_b) != 0) { + m_matrix[MatrixPredicate.InteriorInterior] = 1; + return; + } + + if (m_matrix[MatrixPredicate.InteriorInterior] != 0) { + if (m_topo_graph.getHalfEdgeUserIndex(m_topo_graph + .getHalfEdgePrev(m_topo_graph.getHalfEdgeTwin(half_edge)), + m_visited_index) != 1) { + int cluster = m_topo_graph.getHalfEdgeTo(half_edge); + int clusterParentage = m_topo_graph + .getClusterParentage(cluster); + + if ((clusterParentage & id_a) != 0 + && (clusterParentage & id_b) != 0) { + int index_a = m_topo_graph.getClusterUserIndex(cluster, + cluster_index_a); + int index_b = m_topo_graph.getClusterUserIndex(cluster, + cluster_index_b); + assert (index_a != -1); + assert (index_b != -1); + + if ((index_a % 2 == 0) && (index_b % 2 == 0)) { + assert ((m_topo_graph.getClusterParentage(cluster) & id_a) != 0 && (m_topo_graph + .getClusterParentage(cluster) & id_b) != 0); + m_matrix[MatrixPredicate.InteriorInterior] = 0; + } + } + } + } + } + + // Relational predicate to determine of the interior of LineA intersects + // with the boundary of Line B. + private void interiorLineBoundaryLine_(int half_edge, int id_a, int id_b, + int cluster_index_a, int cluster_index_b, int predicate) { + if (m_matrix[predicate] == 0) + return; + + if (m_topo_graph.getHalfEdgeUserIndex(m_topo_graph + .getHalfEdgePrev(m_topo_graph.getHalfEdgeTwin(half_edge)), + m_visited_index) != 1) { + int cluster = m_topo_graph.getHalfEdgeTo(half_edge); + int clusterParentage = m_topo_graph.getClusterParentage(cluster); + + if ((clusterParentage & id_a) != 0 + && (clusterParentage & id_b) != 0) { + int index_a = m_topo_graph.getClusterUserIndex(cluster, + cluster_index_a); + int index_b = m_topo_graph.getClusterUserIndex(cluster, + cluster_index_b); + assert (index_a != -1); + assert (index_b != -1); + + if ((index_a % 2 == 0) && (index_b % 2 != 0)) { + assert ((m_topo_graph.getClusterParentage(cluster) & id_a) != 0 && (m_topo_graph + .getClusterParentage(cluster) & id_b) != 0); + m_matrix[predicate] = 0; + } + } + } + } + + // Relational predicate to determine if the interior of Line A intersects + // with the exterior of Line B. + private void interiorLineExteriorLine_(int half_edge, int id_a, int id_b, + int predicate) { + if (m_matrix[predicate] == 1) + return; + + int parentage = m_topo_graph.getHalfEdgeParentage(half_edge); + + if ((parentage & id_a) != 0 && (parentage & id_b) == 0) + m_matrix[predicate] = 1; + } + + // Relational predicate to determine if the boundary of Line A intersects + // with the boundary of Line B. + private void boundaryLineBoundaryLine_(int half_edge, int id_a, int id_b, + int cluster_index_a, int cluster_index_b) { + if (m_matrix[MatrixPredicate.BoundaryBoundary] == 0) + return; + + if (m_topo_graph.getHalfEdgeUserIndex(m_topo_graph + .getHalfEdgePrev(m_topo_graph.getHalfEdgeTwin(half_edge)), + m_visited_index) != 1) { + int cluster = m_topo_graph.getHalfEdgeTo(half_edge); + int clusterParentage = m_topo_graph.getClusterParentage(cluster); + + if ((clusterParentage & id_a) != 0 + && (clusterParentage & id_b) != 0) { + int index_a = m_topo_graph.getClusterUserIndex(cluster, + cluster_index_a); + int index_b = m_topo_graph.getClusterUserIndex(cluster, + cluster_index_b); + assert (index_a != -1); + assert (index_b != -1); + + if ((index_a % 2 != 0) && (index_b % 2 != 0)) { + assert ((m_topo_graph.getClusterParentage(cluster) & id_a) != 0 && (m_topo_graph + .getClusterParentage(cluster) & id_b) != 0); + m_matrix[MatrixPredicate.BoundaryBoundary] = 0; + } + } + } + } + + // Relational predicate to determine if the boundary of Line A intersects + // with the exterior of Line B. + private void boundaryLineExteriorLine_(int half_edge, int id_a, int id_b, + int cluster_index_a, int predicate) { + if (m_matrix[predicate] == 0) + return; + + if (m_topo_graph.getHalfEdgeUserIndex(m_topo_graph + .getHalfEdgePrev(m_topo_graph.getHalfEdgeTwin(half_edge)), + m_visited_index) != 1) { + int cluster = m_topo_graph.getHalfEdgeTo(half_edge); + int clusterParentage = m_topo_graph.getClusterParentage(cluster); + + if ((clusterParentage & id_b) == 0) { + int index = m_topo_graph.getClusterUserIndex(cluster, + cluster_index_a); + assert (index != -1); + + if (index % 2 != 0) { + assert ((m_topo_graph.getClusterParentage(cluster) & id_a) != 0); + m_matrix[predicate] = 0; + } + } + } + } + + // Relational predicate to determine if the interior of area A intersects + // with the interior of Point B. + private void interiorAreaInteriorPoint_(int cluster, int id_a) { + if (m_matrix[MatrixPredicate.InteriorInterior] == 0) + return; + + int clusterParentage = m_topo_graph.getClusterParentage(cluster); + + if ((clusterParentage & id_a) == 0) { + int chain = m_topo_graph.getClusterChain(cluster); + int chainParentage = m_topo_graph.getChainParentage(chain); + + if ((chainParentage & id_a) != 0) { + m_matrix[MatrixPredicate.InteriorInterior] = 0; + } + } + } + + private void interiorAreaExteriorPoint_(int cluster, int id_a) + { if (m_matrix[MatrixPredicate.InteriorExterior] == 2) return; int cluster_parentage = m_topo_graph.getClusterParentage(cluster); - if ((cluster_parentage & id_a) != 0) { + if ((cluster_parentage & id_a) != 0) + { m_matrix[MatrixPredicate.InteriorExterior] = 2; } } - // Relational predicate to determine if the boundary of area A intersects - // with the interior of Point B. - private void boundaryAreaInteriorPoint_(int cluster, int id_a, int id_b) { - if (m_matrix[MatrixPredicate.BoundaryInterior] == 0) - return; + // Relational predicate to determine if the boundary of area A intersects + // with the interior of Point B. + private void boundaryAreaInteriorPoint_(int cluster, int id_a, int id_b) { + if (m_matrix[MatrixPredicate.BoundaryInterior] == 0) + return; - int clusterParentage = m_topo_graph.getClusterParentage(cluster); + int clusterParentage = m_topo_graph.getClusterParentage(cluster); - if ((clusterParentage & id_a) != 0 && (clusterParentage & id_b) != 0) { - m_matrix[MatrixPredicate.BoundaryInterior] = 0; - } - } + if ((clusterParentage & id_a) != 0 && (clusterParentage & id_b) != 0) { + m_matrix[MatrixPredicate.BoundaryInterior] = 0; + } + } - private void boundaryAreaExteriorPoint_(int cluster, int id_a) { + private void boundaryAreaExteriorPoint_(int cluster, int id_a) + { if (m_matrix[MatrixPredicate.BoundaryExterior] == 1) return; int cluster_parentage = m_topo_graph.getClusterParentage(cluster); - if ((cluster_parentage & id_a) != 0) { + if ((cluster_parentage & id_a) != 0) + { m_matrix[MatrixPredicate.BoundaryExterior] = 1; } } - // Relational predicate to determine if the exterior of area A intersects - // with the interior of Point B. - private void exteriorAreaInteriorPoint_(int cluster, int id_a) { - if (m_matrix[MatrixPredicate.ExteriorInterior] == 0) - return; + // Relational predicate to determine if the exterior of area A intersects + // with the interior of Point B. + private void exteriorAreaInteriorPoint_(int cluster, int id_a) { + if (m_matrix[MatrixPredicate.ExteriorInterior] == 0) + return; - int clusterParentage = m_topo_graph.getClusterParentage(cluster); + int clusterParentage = m_topo_graph.getClusterParentage(cluster); - if ((clusterParentage & id_a) == 0) { - int chain = m_topo_graph.getClusterChain(cluster); - int chainParentage = m_topo_graph.getChainParentage(chain); + if ((clusterParentage & id_a) == 0) { + int chain = m_topo_graph.getClusterChain(cluster); + int chainParentage = m_topo_graph.getChainParentage(chain); - if ((chainParentage & id_a) == 0) { - m_matrix[MatrixPredicate.ExteriorInterior] = 0; - } - } - } + if ((chainParentage & id_a) == 0) { + m_matrix[MatrixPredicate.ExteriorInterior] = 0; + } + } + } - // Relational predicate to determine if the interior of Line A intersects - // with the interior of Point B. - private void interiorLineInteriorPoint_(int cluster, int id_a, int id_b, - int cluster_index_a) { - if (m_matrix[MatrixPredicate.InteriorInterior] == 0) - return; + // Relational predicate to determine if the interior of Line A intersects + // with the interior of Point B. + private void interiorLineInteriorPoint_(int cluster, int id_a, int id_b, + int cluster_index_a) { + if (m_matrix[MatrixPredicate.InteriorInterior] == 0) + return; - int clusterParentage = m_topo_graph.getClusterParentage(cluster); + int clusterParentage = m_topo_graph.getClusterParentage(cluster); - if ((clusterParentage & id_a) != 0 && (clusterParentage & id_b) != 0) { - int index = m_topo_graph.getClusterUserIndex(cluster, - cluster_index_a); + if ((clusterParentage & id_a) != 0 && (clusterParentage & id_b) != 0) { + int index = m_topo_graph.getClusterUserIndex(cluster, + cluster_index_a); - if (index % 2 == 0) { - m_matrix[MatrixPredicate.InteriorInterior] = 0; - } - } - } + if (index % 2 == 0) { + m_matrix[MatrixPredicate.InteriorInterior] = 0; + } + } + } - private void interiorLineExteriorPoint_(int cluster, int id_a, int id_b, int cluster_index_a) { + private void interiorLineExteriorPoint_(int cluster, int id_a, int id_b, int cluster_index_a) + { if (m_matrix[MatrixPredicate.InteriorExterior] == 1) return; int half_edge_a = m_topo_graph.getClusterHalfEdge(cluster); - if (half_edge_a != -1) { + if (half_edge_a != -1) + { m_matrix[MatrixPredicate.InteriorExterior] = 1; return; } - if (m_matrix[MatrixPredicate.InteriorExterior] != 0) { + if (m_matrix[MatrixPredicate.InteriorExterior] != 0) + { int clusterParentage = m_topo_graph.getClusterParentage(cluster); - if ((clusterParentage & id_b) == 0) { - assert (m_topo_graph.getClusterUserIndex(cluster, cluster_index_a) % 2 == 0); + if ((clusterParentage & id_b) == 0) + { + assert(m_topo_graph.getClusterUserIndex(cluster, cluster_index_a) % 2 == 0); m_matrix[MatrixPredicate.InteriorExterior] = 0; return; } @@ -2458,102 +2606,105 @@ private void interiorLineExteriorPoint_(int cluster, int id_a, int id_b, int clu return; } - // Relational predicate to determine if the boundary of Line A intersects - // with the interior of Point B. - private void boundaryLineInteriorPoint_(int cluster, int id_a, int id_b, - int cluster_index_a) { - if (m_matrix[MatrixPredicate.BoundaryInterior] == 0) - return; - - int clusterParentage = m_topo_graph.getClusterParentage(cluster); - - if ((clusterParentage & id_a) != 0 && (clusterParentage & id_b) != 0) { - int index = m_topo_graph.getClusterUserIndex(cluster, - cluster_index_a); - - if (index % 2 != 0) { - m_matrix[MatrixPredicate.BoundaryInterior] = 0; - } - } - } - - // Relational predicate to determine if the boundary of Line A intersects - // with the exterior of Point B. - private void boundaryLineExteriorPoint_(int cluster, int id_a, int id_b, - int cluster_index_a) { - if (m_matrix[MatrixPredicate.BoundaryExterior] == 0) - return; - - int clusterParentage = m_topo_graph.getClusterParentage(cluster); - - if ((clusterParentage & id_a) != 0 && (clusterParentage & id_b) == 0) { - int index = m_topo_graph.getClusterUserIndex(cluster, - cluster_index_a); - - if (index % 2 != 0) { - m_matrix[MatrixPredicate.BoundaryExterior] = 0; - } - } - } - - // Relational predicate to determine if the exterior of Line A intersects - // with the interior of Point B. - private void exteriorLineInteriorPoint_(int cluster, int id_a, int id_b) { - if (m_matrix[MatrixPredicate.ExteriorInterior] == 0) - return; - - int clusterParentage = m_topo_graph.getClusterParentage(cluster); - - if ((clusterParentage & id_a) == 0 && (clusterParentage & id_b) != 0) { - m_matrix[MatrixPredicate.ExteriorInterior] = 0; - } - } - - // Relational predicate to determine if the interior of Point A intersects - // with the interior of Point B. - private void interiorPointInteriorPoint_(int cluster, int id_a, int id_b) { - if (m_matrix[MatrixPredicate.InteriorInterior] == 0) - return; - - int clusterParentage = m_topo_graph.getClusterParentage(cluster); - - if ((clusterParentage & id_a) != 0 && (clusterParentage & id_b) != 0) { - m_matrix[MatrixPredicate.InteriorInterior] = 0; - } - } - - // Relational predicate to determine if the interior of Point A intersects - // with the exterior of Point B. - private void interiorPointExteriorPoint_(int cluster, int id_a, int id_b, - int predicate) { - if (m_matrix[predicate] == 0) - return; - - int clusterParentage = m_topo_graph.getClusterParentage(cluster); - - if ((clusterParentage & id_a) != 0 && (clusterParentage & id_b) == 0) { - m_matrix[predicate] = 0; - } - } - - // Computes the 9 intersection relationships of boundary, interior, and - // exterior of geometry_a vs geometry_b using the Topo_graph for area/area, - // area/Line, and Line/Line relations - private void computeMatrixTopoGraphHalfEdges_(int geometry_a, int geometry_b) { - boolean bRelationKnown = false; - - int id_a = m_topo_graph.getGeometryID(geometry_a); - int id_b = m_topo_graph.getGeometryID(geometry_b); - - m_visited_index = m_topo_graph.createUserIndexForHalfEdges(); - - for (int cluster = m_topo_graph.getFirstCluster(); cluster != -1; cluster = m_topo_graph - .getNextCluster(cluster)) { - int first_half_edge = m_topo_graph.getClusterHalfEdge(cluster); - if (first_half_edge == -1) { - if (m_predicates_cluster != -1) { + // Relational predicate to determine if the boundary of Line A intersects + // with the interior of Point B. + private void boundaryLineInteriorPoint_(int cluster, int id_a, int id_b, + int cluster_index_a) { + if (m_matrix[MatrixPredicate.BoundaryInterior] == 0) + return; + + int clusterParentage = m_topo_graph.getClusterParentage(cluster); + + if ((clusterParentage & id_a) != 0 && (clusterParentage & id_b) != 0) { + int index = m_topo_graph.getClusterUserIndex(cluster, + cluster_index_a); + + if (index % 2 != 0) { + m_matrix[MatrixPredicate.BoundaryInterior] = 0; + } + } + } + + // Relational predicate to determine if the boundary of Line A intersects + // with the exterior of Point B. + private void boundaryLineExteriorPoint_(int cluster, int id_a, int id_b, + int cluster_index_a) { + if (m_matrix[MatrixPredicate.BoundaryExterior] == 0) + return; + + int clusterParentage = m_topo_graph.getClusterParentage(cluster); + + if ((clusterParentage & id_a) != 0 && (clusterParentage & id_b) == 0) { + int index = m_topo_graph.getClusterUserIndex(cluster, + cluster_index_a); + + if (index % 2 != 0) { + m_matrix[MatrixPredicate.BoundaryExterior] = 0; + } + } + } + + // Relational predicate to determine if the exterior of Line A intersects + // with the interior of Point B. + private void exteriorLineInteriorPoint_(int cluster, int id_a, int id_b) { + if (m_matrix[MatrixPredicate.ExteriorInterior] == 0) + return; + + int clusterParentage = m_topo_graph.getClusterParentage(cluster); + + if ((clusterParentage & id_a) == 0 && (clusterParentage & id_b) != 0) { + m_matrix[MatrixPredicate.ExteriorInterior] = 0; + } + } + + // Relational predicate to determine if the interior of Point A intersects + // with the interior of Point B. + private void interiorPointInteriorPoint_(int cluster, int id_a, int id_b) { + if (m_matrix[MatrixPredicate.InteriorInterior] == 0) + return; + + int clusterParentage = m_topo_graph.getClusterParentage(cluster); + + if ((clusterParentage & id_a) != 0 && (clusterParentage & id_b) != 0) { + m_matrix[MatrixPredicate.InteriorInterior] = 0; + } + } + + // Relational predicate to determine if the interior of Point A intersects + // with the exterior of Point B. + private void interiorPointExteriorPoint_(int cluster, int id_a, int id_b, + int predicate) { + if (m_matrix[predicate] == 0) + return; + + int clusterParentage = m_topo_graph.getClusterParentage(cluster); + + if ((clusterParentage & id_a) != 0 && (clusterParentage & id_b) == 0) { + m_matrix[predicate] = 0; + } + } + + // Computes the 9 intersection relationships of boundary, interior, and + // exterior of geometry_a vs geometry_b using the Topo_graph for area/area, + // area/Line, and Line/Line relations + private void computeMatrixTopoGraphHalfEdges_(int geometry_a, int geometry_b) { + boolean bRelationKnown = false; + + int id_a = m_topo_graph.getGeometryID(geometry_a); + int id_b = m_topo_graph.getGeometryID(geometry_b); + + m_visited_index = m_topo_graph.createUserIndexForHalfEdges(); + + for (int cluster = m_topo_graph.getFirstCluster(); cluster != -1; cluster = m_topo_graph + .getNextCluster(cluster)) { + int first_half_edge = m_topo_graph.getClusterHalfEdge(cluster); + if (first_half_edge == -1) + { + if (m_predicates_cluster != -1) + { // Treat cluster as an interior point - switch (m_predicates_cluster) { + switch (m_predicates_cluster) + { case Predicates.AreaPointPredicates: bRelationKnown = areaPointPredicates_(cluster, id_a, id_b); break; @@ -2568,158 +2719,158 @@ private void computeMatrixTopoGraphHalfEdges_(int geometry_a, int geometry_b) { continue; } - int next_half_edge = first_half_edge; - - do { - int half_edge = next_half_edge; - int visited = m_topo_graph.getHalfEdgeUserIndex(half_edge, - m_visited_index); - - if (visited != 1) { - do { - // Invoke relational predicates - switch (m_predicates_half_edge) { - case Predicates.AreaAreaPredicates: - bRelationKnown = areaAreaPredicates_(half_edge, - id_a, id_b); - break; - case Predicates.AreaLinePredicates: - bRelationKnown = areaLinePredicates_(half_edge, - id_a, id_b); - break; - case Predicates.LineLinePredicates: - bRelationKnown = lineLinePredicates_(half_edge, - id_a, id_b); - break; - default: - throw GeometryException.GeometryInternalError(); - } - - if (bRelationKnown) - break; - - m_topo_graph.setHalfEdgeUserIndex(half_edge, - m_visited_index, 1); - half_edge = m_topo_graph.getHalfEdgeNext(half_edge); - } while (half_edge != next_half_edge && !bRelationKnown); - } - - if (bRelationKnown) - break; - - next_half_edge = m_topo_graph.getHalfEdgeNext(m_topo_graph - .getHalfEdgeTwin(half_edge)); - } while (next_half_edge != first_half_edge); - - if (bRelationKnown) - break; - } - - if (!bRelationKnown) - setRemainingPredicatesToFalse_(); - - m_topo_graph.deleteUserIndexForHalfEdges(m_visited_index); - } - - // Computes the 9 intersection relationships of boundary, interior, and - // exterior of geometry_a vs geometry_b using the Topo_graph for area/Point, - // Line/Point, and Point/Point relations - private void computeMatrixTopoGraphClusters_(int geometry_a, int geometry_b) { - boolean bRelationKnown = false; - - int id_a = m_topo_graph.getGeometryID(geometry_a); - int id_b = m_topo_graph.getGeometryID(geometry_b); - - for (int cluster = m_topo_graph.getFirstCluster(); cluster != -1; cluster = m_topo_graph - .getNextCluster(cluster)) { - // Invoke relational predicates - switch (m_predicates_cluster) { - case Predicates.AreaPointPredicates: - bRelationKnown = areaPointPredicates_(cluster, id_a, id_b); - break; - case Predicates.LinePointPredicates: - bRelationKnown = linePointPredicates_(cluster, id_a, id_b); - break; - case Predicates.PointPointPredicates: - bRelationKnown = pointPointPredicates_(cluster, id_a, id_b); - break; - default: - throw GeometryException.GeometryInternalError(); - } - - if (bRelationKnown) - break; - } - - if (!bRelationKnown) - setRemainingPredicatesToFalse_(); - } - - // Call this method to set the edit shape, if the edit shape has been - // cracked and clustered already. - private void setEditShape_(EditShape shape, ProgressTracker progressTracker) { - m_topo_graph.setEditShape(shape, progressTracker); - } - - private void setEditShapeCrackAndCluster_(EditShape shape, - double tolerance, ProgressTracker progress_tracker) { - editShapeCrackAndCluster_(shape, tolerance, progress_tracker); - setEditShape_(shape, progress_tracker); - } - - private void editShapeCrackAndCluster_(EditShape shape, double tolerance, - ProgressTracker progress_tracker) { - CrackAndCluster.execute(shape, tolerance, progress_tracker, false); //do not filter degenerate segments. + int next_half_edge = first_half_edge; + + do { + int half_edge = next_half_edge; + int visited = m_topo_graph.getHalfEdgeUserIndex(half_edge, + m_visited_index); + + if (visited != 1) { + do { + // Invoke relational predicates + switch (m_predicates_half_edge) { + case Predicates.AreaAreaPredicates: + bRelationKnown = areaAreaPredicates_(half_edge, + id_a, id_b); + break; + case Predicates.AreaLinePredicates: + bRelationKnown = areaLinePredicates_(half_edge, + id_a, id_b); + break; + case Predicates.LineLinePredicates: + bRelationKnown = lineLinePredicates_(half_edge, + id_a, id_b); + break; + default: + throw GeometryException.GeometryInternalError(); + } + + if (bRelationKnown) + break; + + m_topo_graph.setHalfEdgeUserIndex(half_edge, + m_visited_index, 1); + half_edge = m_topo_graph.getHalfEdgeNext(half_edge); + } while (half_edge != next_half_edge && !bRelationKnown); + } + + if (bRelationKnown) + break; + + next_half_edge = m_topo_graph.getHalfEdgeNext(m_topo_graph + .getHalfEdgeTwin(half_edge)); + } while (next_half_edge != first_half_edge); + + if (bRelationKnown) + break; + } + + if (!bRelationKnown) + setRemainingPredicatesToFalse_(); + + m_topo_graph.deleteUserIndexForHalfEdges(m_visited_index); + } + + // Computes the 9 intersection relationships of boundary, interior, and + // exterior of geometry_a vs geometry_b using the Topo_graph for area/Point, + // Line/Point, and Point/Point relations + private void computeMatrixTopoGraphClusters_(int geometry_a, int geometry_b) { + boolean bRelationKnown = false; + + int id_a = m_topo_graph.getGeometryID(geometry_a); + int id_b = m_topo_graph.getGeometryID(geometry_b); + + for (int cluster = m_topo_graph.getFirstCluster(); cluster != -1; cluster = m_topo_graph + .getNextCluster(cluster)) { + // Invoke relational predicates + switch (m_predicates_cluster) { + case Predicates.AreaPointPredicates: + bRelationKnown = areaPointPredicates_(cluster, id_a, id_b); + break; + case Predicates.LinePointPredicates: + bRelationKnown = linePointPredicates_(cluster, id_a, id_b); + break; + case Predicates.PointPointPredicates: + bRelationKnown = pointPointPredicates_(cluster, id_a, id_b); + break; + default: + throw GeometryException.GeometryInternalError(); + } + + if (bRelationKnown) + break; + } + + if (!bRelationKnown) + setRemainingPredicatesToFalse_(); + } + + // Call this method to set the edit shape, if the edit shape has been + // cracked and clustered already. + private void setEditShape_(EditShape shape, ProgressTracker progressTracker) { + m_topo_graph.setEditShape(shape, progressTracker); + } + + private void setEditShapeCrackAndCluster_(EditShape shape, + double tolerance, ProgressTracker progress_tracker) { + editShapeCrackAndCluster_(shape, tolerance, progress_tracker); + setEditShape_(shape, progress_tracker); + } + + private void editShapeCrackAndCluster_(EditShape shape, double tolerance, + ProgressTracker progress_tracker) { + CrackAndCluster.execute(shape, tolerance, progress_tracker, false); //do not filter degenerate segments. shape.filterClosePoints(0, true, true);//remove degeneracies from polygon geometries. - for (int geometry = shape.getFirstGeometry(); geometry != -1; geometry = shape - .getNextGeometry(geometry)) { - if (shape.getGeometryType(geometry) == Geometry.Type.Polygon - .value()) - Simplificator.execute(shape, geometry, -1, false, progress_tracker); - } - } - - // Upgrades the geometry to a feature geometry. - private static Geometry convertGeometry_(Geometry geometry, double tolerance) { - int gt = geometry.getType().value(); - - if (Geometry.isSegment(gt)) { - Polyline polyline = new Polyline(geometry.getDescription()); - polyline.addSegment((Segment) geometry, true); - return polyline; - } - - if (gt == Geometry.GeometryType.Envelope) { - Envelope envelope = (Envelope) (geometry); - Envelope2D env = new Envelope2D(); - geometry.queryEnvelope2D(env); - - if (env.getHeight() <= tolerance && env.getWidth() <= tolerance) {// treat - // as - // point - Point point = new Point(geometry.getDescription()); - envelope.getCenter(point); - return point; - } - - if (env.getHeight() <= tolerance || env.getWidth() <= tolerance) {// treat - // as - // line - Polyline polyline = new Polyline(geometry.getDescription()); - Point p = new Point(); - envelope.queryCornerByVal(0, p); - polyline.startPath(p); - envelope.queryCornerByVal(2, p); - polyline.lineTo(p); - return polyline; - } - - // treat as polygon - Polygon polygon = new Polygon(geometry.getDescription()); - polygon.addEnvelope(envelope, false); - return polygon; - } - - return geometry; - } + for (int geometry = shape.getFirstGeometry(); geometry != -1; geometry = shape + .getNextGeometry(geometry)) { + if (shape.getGeometryType(geometry) == Geometry.Type.Polygon + .value()) + Simplificator.execute(shape, geometry, -1, false, progress_tracker); + } + } + + // Upgrades the geometry to a feature geometry. + private static Geometry convertGeometry_(Geometry geometry, double tolerance) { + int gt = geometry.getType().value(); + + if (Geometry.isSegment(gt)) { + Polyline polyline = new Polyline(geometry.getDescription()); + polyline.addSegment((Segment) geometry, true); + return polyline; + } + + if (gt == Geometry.GeometryType.Envelope) { + Envelope envelope = (Envelope) (geometry); + Envelope2D env = new Envelope2D(); + geometry.queryEnvelope2D(env); + + if (env.getHeight() <= tolerance && env.getWidth() <= tolerance) {// treat + // as + // point + Point point = new Point(geometry.getDescription()); + envelope.getCenter(point); + return point; + } + + if (env.getHeight() <= tolerance || env.getWidth() <= tolerance) {// treat + // as + // line + Polyline polyline = new Polyline(geometry.getDescription()); + Point p = new Point(); + envelope.queryCornerByVal(0, p); + polyline.startPath(p); + envelope.queryCornerByVal(2, p); + polyline.lineTo(p); + return polyline; + } + + // treat as polygon + Polygon polygon = new Polygon(geometry.getDescription()); + polygon.addEnvelope(envelope, false); + return polygon; + } + + return geometry; + } } diff --git a/src/main/java/com/esri/core/geometry/RingOrientationFixer.java b/src/main/java/com/esri/core/geometry/RingOrientationFixer.java index c84703aa..af601b83 100644 --- a/src/main/java/com/esri/core/geometry/RingOrientationFixer.java +++ b/src/main/java/com/esri/core/geometry/RingOrientationFixer.java @@ -24,662 +24,662 @@ package com.esri.core.geometry; class RingOrientationFixer { - EditShape m_shape; - Treap m_AET; - double m_y_scanline; - int m_geometry; - int m_unknown_ring_orientation_count; - IndexMultiDCList m_sorted_vertices; - AttributeStreamOfInt32 m_unknown_nodes; - int m_node_1_user_index; - int m_node_2_user_index; - int m_path_orientation_index; - int m_path_parentage_index; - boolean m_fixSelfTangency; - - static final class Edges { - EditShape m_shape; - AttributeStreamOfInt32 m_end_1_nodes; - AttributeStreamOfInt32 m_end_2_nodes; - AttributeStreamOfInt8 m_directions; - Point2D pt_1 = new Point2D(); - Point2D pt_2 = new Point2D(); - int m_first_free; - - boolean getDirection_(int index) { - return m_shape.getNextVertex(getEnd1(index)) == getEnd2(index); - } - - int getEnd_(int index) { - int v_1 = getEnd1(index); - int v_2 = getEnd2(index); - if (m_shape.getNextVertex(v_1) == v_2) - return v_2; - else - return v_1; - } - - Edges(EditShape shape) { - m_shape = shape; - m_first_free = -1; - } - - Segment getSegment(int index) { - return m_shape.getSegment(getStart(index)); - } - - // True if the start vertex is the lower point of the edge. - boolean isBottomUp(int index) { - int v_1 = getEnd1(index); - int v_2 = getEnd2(index); - if (m_shape.getPrevVertex(v_1) == v_2) { - int temp = v_1; - v_1 = v_2; - v_2 = temp; - } - m_shape.getXY(v_1, pt_1); - m_shape.getXY(v_2, pt_2); - return pt_1.y < pt_2.y; - } - - int getStart(int index) { - int v_1 = getEnd1(index); - int v_2 = getEnd2(index); - return (m_shape.getNextVertex(v_1) == v_2) ? v_1 : v_2; - } - - int getEnd1(int index) { - return m_end_1_nodes.get(index); - } - - int getEnd2(int index) { - return m_end_2_nodes.get(index); - } - - void freeEdge(int edge) { - m_end_1_nodes.set(edge, m_first_free); - m_first_free = edge; - } - - int newEdge(int vertex) { - if (m_first_free != -1) { - int index = m_first_free; - m_first_free = m_end_1_nodes.get(index); - m_end_1_nodes.set(index, vertex); - m_end_2_nodes.set(index, m_shape.getNextVertex(vertex)); - return index; - } else if (m_end_1_nodes == null) { - m_end_1_nodes = new AttributeStreamOfInt32(0); - m_end_2_nodes = new AttributeStreamOfInt32(0); - } - - int index = m_end_1_nodes.size(); - m_end_1_nodes.add(vertex); - m_end_2_nodes.add(m_shape.getNextVertex(vertex)); - return index; - } - - EditShape getShape() { - return m_shape; - } - - int getPath(int index) { - return m_shape.getPathFromVertex(getEnd1(index)); - } - } - - Edges m_edges; - - class RingOrientationTestComparator extends Treap.Comparator { - RingOrientationFixer m_helper; - Line m_line_1; - Line m_line_2; - int m_left_elm; - double m_leftx; - Segment m_seg_1; - - RingOrientationTestComparator(RingOrientationFixer helper) { - m_helper = helper; - m_line_1 = new Line(); - m_line_2 = new Line(); - m_leftx = 0; - m_seg_1 = null; - m_left_elm = -1; - } - - @Override - int compare(Treap treap, int left, int node) { - int right = treap.getElement(node); - RingOrientationFixer.Edges edges = m_helper.m_edges; - double x_1; - if (m_left_elm == left) - x_1 = m_leftx; - else { - m_seg_1 = edges.getSegment(left); - if (m_seg_1 == null) { - EditShape shape = edges.getShape(); - shape.queryLineConnector(edges.getStart(left), m_line_1); - m_seg_1 = m_line_1; - x_1 = m_line_1.intersectionOfYMonotonicWithAxisX( - m_helper.m_y_scanline, 0); - } else - x_1 = m_seg_1.intersectionOfYMonotonicWithAxisX( - m_helper.m_y_scanline, 0); - - m_leftx = x_1; - m_left_elm = left; - } - - Segment seg_2 = edges.getSegment(right); - double x2; - if (seg_2 == null) { - EditShape shape = edges.getShape(); - shape.queryLineConnector(edges.getStart(right), m_line_2); - seg_2 = m_line_2; - x2 = m_line_2.intersectionOfYMonotonicWithAxisX( - m_helper.m_y_scanline, 0); - } else - x2 = seg_2.intersectionOfYMonotonicWithAxisX( - m_helper.m_y_scanline, 0); - - if (x_1 == x2) { - boolean bStartLower1 = edges.isBottomUp(left); - boolean bStartLower2 = edges.isBottomUp(right); - - // apparently these edges originate from same vertex and the - // scanline is on the vertex. move scanline a little. - double y1 = !bStartLower1 ? m_seg_1.getStartY() : m_seg_1 - .getEndY(); - double y2 = !bStartLower2 ? seg_2.getStartY() : seg_2.getEndY(); - double miny = Math.min(y1, y2); - double y = (miny + m_helper.m_y_scanline) * 0.5; - if (y == m_helper.m_y_scanline) { - // assert(0);//ST: not a bug. just curious to see this - // happens. - y = miny; // apparently, one of the segments is almost - // horizontal line. - } - x_1 = m_seg_1.intersectionOfYMonotonicWithAxisX(y, 0); - x2 = seg_2.intersectionOfYMonotonicWithAxisX(y, 0); - assert (x_1 != x2); - } - - return x_1 < x2 ? -1 : (x_1 > x2 ? 1 : 0); - } - - void reset() { - m_left_elm = -1; - } - } - - RingOrientationTestComparator m_sweep_comparator; - - RingOrientationFixer() { - m_AET = new Treap(); - m_AET.disableBalancing(); - m_sweep_comparator = new RingOrientationTestComparator(this); - m_AET.setComparator(m_sweep_comparator); - } - - boolean fixRingOrientation_() { - boolean bFound = false; - - if (m_fixSelfTangency) - bFound = fixRingSelfTangency_(); - - if (m_shape.getPathCount(m_geometry) == 1) { - int path = m_shape.getFirstPath(m_geometry); - double area = m_shape.getRingArea(path); - m_shape.setExterior(path, true); - if (area < 0) { - int first = m_shape.getFirstVertex(path); - m_shape.reverseRingInternal_(first); - m_shape.setLastVertex_(path, m_shape.getPrevVertex(first));// fix - // last - // after - // the - // reverse - return true; - } - - return false; - } - - m_path_orientation_index = m_shape.createPathUserIndex();// used to - // store - // discovered - // orientation - // (3 - - // extrior, - // 2 - - // interior) - m_path_parentage_index = m_shape.createPathUserIndex();// used to - // resolve OGC - // order - for (int path = m_shape.getFirstPath(m_geometry); path != -1; path = m_shape - .getNextPath(path)) { - m_shape.setPathUserIndex(path, m_path_orientation_index, 0); - m_shape.setPathUserIndex(path, m_path_parentage_index, -1); - } - - AttributeStreamOfInt32 bunch = new AttributeStreamOfInt32(0); - m_y_scanline = NumberUtils.TheNaN; - Point2D pt = new Point2D(); - m_unknown_ring_orientation_count = m_shape.getPathCount(m_geometry); - m_node_1_user_index = m_shape.createUserIndex(); - m_node_2_user_index = m_shape.createUserIndex(); - for (int ivertex = m_sorted_vertices.getFirst(m_sorted_vertices - .getFirstList()); ivertex != -1; ivertex = m_sorted_vertices - .getNext(ivertex)) { - int vertex = m_sorted_vertices.getData(ivertex); - m_shape.getXY(vertex, pt); - if (pt.y != m_y_scanline && bunch.size() != 0) { - bFound |= processBunchForRingOrientationTest_(bunch); - m_sweep_comparator.reset(); - bunch.clear(false); - } - - bunch.add(vertex);// all vertices that have same y are added to the - // bunch - m_y_scanline = pt.y; - if (m_unknown_ring_orientation_count == 0) - break; - } - - if (m_unknown_ring_orientation_count > 0) { - bFound |= processBunchForRingOrientationTest_(bunch); - bunch.clear(false); - } - - m_shape.removeUserIndex(m_node_1_user_index); - m_shape.removeUserIndex(m_node_2_user_index); - - // dbg_verify_ring_orientation_();//debug - - for (int path = m_shape.getFirstPath(m_geometry); path != -1; ) { - if (m_shape.getPathUserIndex(path, m_path_orientation_index) == 3) {// exterior - m_shape.setExterior(path, true); - int afterPath = path; - for (int nextHole = m_shape.getPathUserIndex(path, - m_path_parentage_index); nextHole != -1; ) { - int p = m_shape.getPathUserIndex(nextHole, - m_path_parentage_index); - m_shape.movePath(m_geometry, - m_shape.getNextPath(afterPath), nextHole); - afterPath = nextHole; - nextHole = p; - } - path = m_shape.getNextPath(afterPath); - } else { - m_shape.setExterior(path, false); - path = m_shape.getNextPath(path); - } - } - - m_shape.removePathUserIndex(m_path_orientation_index); - m_shape.removePathUserIndex(m_path_parentage_index); - - return bFound; - } - - boolean processBunchForRingOrientationTest_(AttributeStreamOfInt32 bunch) { - return processBunchForRingOrientationTestOddEven_(bunch); - } - - boolean processBunchForRingOrientationTestOddEven_( - AttributeStreamOfInt32 bunch) { - boolean bModified = false; - if (m_edges == null) - m_edges = new Edges(m_shape); - - if (m_unknown_nodes == null) { - m_unknown_nodes = new AttributeStreamOfInt32(0); - m_unknown_nodes.reserve(16); - } else { - m_unknown_nodes.clear(false); - } - - processBunchForRingOrientationRemoveEdges_(bunch); - - // add edges that come into scope - for (int i = 0, n = bunch.size(); i < n; i++) { - int vertex = bunch.get(i); - if (vertex == -1) - continue; - insertEdge_(vertex, -1); - } - - for (int i = 0; i < m_unknown_nodes.size() - && m_unknown_ring_orientation_count > 0; i++) { - int aetNode = m_unknown_nodes.get(i); - int edge = m_AET.getElement(aetNode); - int path = m_edges.getPath(edge); - int orientation = m_shape.getPathUserIndex(path, - m_path_orientation_index); - int prevPath = -1; - if (orientation == 0) { - int node = m_AET.getPrev(aetNode); - int prevNode = aetNode; - boolean odd_even = false; - // find the leftmost edge for which the ring orientation is - // known - while (node != Treap.nullNode()) { - int edge1 = m_AET.getElement(node); - int path1 = m_edges.getPath(edge1); - int orientation1 = m_shape.getPathUserIndex(path1, - m_path_orientation_index); - if (orientation1 != 0) { - prevPath = path1; - break; - } - prevNode = node; - node = m_AET.getPrev(node); - } - if (node == Treap.nullNode()) {// if no edges have ring - // orientation known, then start - // from the left most and it has - // to be exterior ring. - odd_even = true; - node = prevNode; - } else { - int edge1 = m_AET.getElement(node); - odd_even = m_edges.isBottomUp(edge1); - node = m_AET.getNext(node); - odd_even = !odd_even; - } - - do { - int edge1 = m_AET.getElement(node); - int path1 = m_edges.getPath(edge1); - int orientation1 = m_shape.getPathUserIndex(path1, - m_path_orientation_index); - if (orientation1 == 0) { - if (odd_even != m_edges.isBottomUp(edge1)) { - int first = m_shape.getFirstVertex(path1); - m_shape.reverseRingInternal_(first); - m_shape.setLastVertex_(path1, - m_shape.getPrevVertex(first)); - bModified = true; - } - - m_shape.setPathUserIndex(path1, - m_path_orientation_index, odd_even ? 3 : 2); - if (!odd_even) {// link the holes into the linked list - // to mantain the OGC order. - int lastHole = m_shape.getPathUserIndex(prevPath, - m_path_parentage_index); - m_shape.setPathUserIndex(prevPath, - m_path_parentage_index, path1); - m_shape.setPathUserIndex(path1, - m_path_parentage_index, lastHole); - } - - m_unknown_ring_orientation_count--; - if (m_unknown_ring_orientation_count == 0) - return bModified; - } - - prevPath = path1; - prevNode = node; - node = m_AET.getNext(node); - odd_even = !odd_even; - } while (prevNode != aetNode); - } - } - - return bModified; - } - - void processBunchForRingOrientationRemoveEdges_(AttributeStreamOfInt32 bunch) { - // remove all nodes that go out of scope - for (int i = 0, n = bunch.size(); i < n; i++) { - int vertex = bunch.get(i); - int node1 = m_shape.getUserIndex(vertex, m_node_1_user_index); - int node2 = m_shape.getUserIndex(vertex, m_node_2_user_index); - if (node1 != -1) { - int edge = m_AET.getElement(node1); - m_edges.freeEdge(edge); - m_shape.setUserIndex(vertex, m_node_1_user_index, -1); - } - if (node2 != -1) { - int edge = m_AET.getElement(node2); - m_edges.freeEdge(edge); - m_shape.setUserIndex(vertex, m_node_2_user_index, -1); - } - - int reused_node = -1; - if (node1 != -1 && node2 != -1) {// terminating vertex - m_AET.deleteNode(node1, -1); - m_AET.deleteNode(node2, -1); - bunch.set(i, -1); - } else - reused_node = node1 != -1 ? node1 : node2; - - if (reused_node != -1) {// this vertex is a part of vertical chain. - // Sorted order in AET did not change, so - // reuse the AET node. - if (!insertEdge_(vertex, reused_node)) - m_AET.deleteNode(reused_node, -1);// horizontal edge was not - // inserted - bunch.set(i, -1); - } - } - } - - boolean insertEdge_(int vertex, int reused_node) { - Point2D pt_1 = new Point2D(); - Point2D pt_2 = new Point2D(); - m_shape.getXY(vertex, pt_1); - int next = m_shape.getNextVertex(vertex); - m_shape.getXY(next, pt_2); - boolean b_res = false; - if (pt_1.y < pt_2.y) { - b_res = true; - int edge = m_edges.newEdge(vertex); - int aetNode; - if (reused_node == -1) - aetNode = m_AET.addElement(edge, -1); - else { - aetNode = reused_node; - m_AET.setElement(aetNode, edge); - } - int node = m_shape.getUserIndex(next, m_node_1_user_index); - if (node == -1) - m_shape.setUserIndex(next, m_node_1_user_index, aetNode); - else - m_shape.setUserIndex(next, m_node_2_user_index, aetNode); - - int path = m_shape.getPathFromVertex(vertex); - if (m_shape.getPathUserIndex(path, m_path_orientation_index) == 0) { - m_unknown_nodes.add(aetNode); - } - } - - int prev = m_shape.getPrevVertex(vertex); - m_shape.getXY(prev, pt_2); - if (pt_1.y < pt_2.y) { - b_res = true; - int edge = m_edges.newEdge(prev); - int aetNode; - if (reused_node == -1) - aetNode = m_AET.addElement(edge, -1); - else { - aetNode = reused_node; - m_AET.setElement(aetNode, edge); - } - int node = m_shape.getUserIndex(prev, m_node_1_user_index); - if (node == -1) - m_shape.setUserIndex(prev, m_node_1_user_index, aetNode); - else - m_shape.setUserIndex(prev, m_node_2_user_index, aetNode); - - int path = m_shape.getPathFromVertex(vertex); - if (m_shape.getPathUserIndex(path, m_path_orientation_index) == 0) { - m_unknown_nodes.add(aetNode); - } - } - - return b_res; - } - - static boolean execute(EditShape shape, int geometry, - IndexMultiDCList sorted_vertices, boolean fixSelfTangency) { - RingOrientationFixer fixer = new RingOrientationFixer(); - fixer.m_shape = shape; - fixer.m_geometry = geometry; - fixer.m_sorted_vertices = sorted_vertices; - fixer.m_fixSelfTangency = fixSelfTangency; - return fixer.fixRingOrientation_(); - } - - boolean fixRingSelfTangency_() { - AttributeStreamOfInt32 self_tangent_paths = new AttributeStreamOfInt32( - 0); - AttributeStreamOfInt32 self_tangency_clusters = new AttributeStreamOfInt32( - 0); - int tangent_path_first_vertex_index = -1; - int tangent_vertex_cluster_index = -1; - Point2D pt_prev = new Point2D(); - pt_prev.setNaN(); - int prev_vertex = -1; - int old_path = -1; - int current_cluster = -1; - Point2D pt = new Point2D(); - for (int ivertex = m_sorted_vertices.getFirst(m_sorted_vertices - .getFirstList()); ivertex != -1; ivertex = m_sorted_vertices - .getNext(ivertex)) { - int vertex = m_sorted_vertices.getData(ivertex); - m_shape.getXY(vertex, pt); - int path = m_shape.getPathFromVertex(vertex); - if (pt_prev.isEqual(pt) && old_path == path) { - if (tangent_vertex_cluster_index == -1) { - tangent_path_first_vertex_index = m_shape - .createPathUserIndex(); - tangent_vertex_cluster_index = m_shape.createUserIndex(); - } - - if (current_cluster == -1) { - current_cluster = self_tangency_clusters.size(); - m_shape.setUserIndex(prev_vertex, - tangent_vertex_cluster_index, current_cluster); - self_tangency_clusters.add(1); - int p = m_shape.getPathUserIndex(path, - tangent_path_first_vertex_index); - if (p == -1) { - m_shape.setPathUserIndex(path, - tangent_path_first_vertex_index, prev_vertex); - self_tangent_paths.add(path); - } - } - - m_shape.setUserIndex(vertex, tangent_vertex_cluster_index, - current_cluster); - self_tangency_clusters - .setLast(self_tangency_clusters.getLast() + 1); - } else { - current_cluster = -1; - pt_prev.setCoords(pt); - } - - prev_vertex = vertex; - old_path = path; - } - - if (self_tangent_paths.size() == 0) - return false; - - // Now self_tangent_paths contains list of clusters of tangency for each - // path. - // The clusters contains list of clusters and for each cluster it - // contains a list of vertices. - AttributeStreamOfInt32 vertex_stack = new AttributeStreamOfInt32(0); - AttributeStreamOfInt32 cluster_stack = new AttributeStreamOfInt32(0); - - for (int ipath = 0, npath = self_tangent_paths.size(); ipath < npath; ipath++) { - int path = self_tangent_paths.get(ipath); - int first_vertex = m_shape.getPathUserIndex(path, - tangent_path_first_vertex_index); - int cluster = m_shape.getUserIndex(first_vertex, - tangent_vertex_cluster_index); - vertex_stack.clear(false); - cluster_stack.clear(false); - vertex_stack.add(first_vertex); - cluster_stack.add(cluster); - - for (int vertex = m_shape.getNextVertex(first_vertex); vertex != first_vertex; vertex = m_shape - .getNextVertex(vertex)) { - int vertex_to = vertex; - int cluster_to = m_shape.getUserIndex(vertex_to, - tangent_vertex_cluster_index); - if (cluster_to != -1) { - if (cluster_stack.size() == 0) { - cluster_stack.add(cluster_to); - vertex_stack.add(vertex_to); - continue; - } - - if (cluster_stack.getLast() == cluster_to) { - int vertex_from = vertex_stack.getLast(); - - // peel the loop from path - int from_next = m_shape.getNextVertex(vertex_from); - int from_prev = m_shape.getPrevVertex(vertex_from); - int to_next = m_shape.getNextVertex(vertex_to); - int to_prev = m_shape.getPrevVertex(vertex_to); - - m_shape.setNextVertex_(vertex_from, to_next); - m_shape.setPrevVertex_(to_next, vertex_from); - - m_shape.setNextVertex_(vertex_to, from_next); - m_shape.setPrevVertex_(from_next, vertex_to); - - // vertex_from is left in the path we are processing, - // while the vertex_to is in the loop being teared off. - boolean[] first_vertex_correction_requied = new boolean[]{false}; - int new_path = m_shape.insertClosedPath_(m_geometry, - -1, from_next, m_shape.getFirstVertex(path), - first_vertex_correction_requied); - - m_shape.setUserIndex(vertex, - tangent_vertex_cluster_index, -1); - - // Fix the path after peeling if the peeled loop had the - // first path vertex in it - - if (first_vertex_correction_requied[0]) { - m_shape.setFirstVertex_(path, to_next); - } - - int path_size = m_shape.getPathSize(path); - int new_path_size = m_shape.getPathSize(new_path); - path_size -= new_path_size; - assert (path_size >= 3); - m_shape.setPathSize_(path, path_size); - - self_tangency_clusters.set(cluster_to, - self_tangency_clusters.get(cluster_to) - 1); - if (self_tangency_clusters.get(cluster_to) == 1) { - self_tangency_clusters.set(cluster_to, 0); - cluster_stack.removeLast(); - vertex_stack.removeLast(); - } else { - // this cluster has more than two vertices in it. - } - - first_vertex = vertex_from;// reset the counter to - // ensure we find all loops. - vertex = vertex_from; - } else { - vertex_stack.add(vertex); - cluster_stack.add(cluster_to); - } - } - } - } - - m_shape.removePathUserIndex(tangent_path_first_vertex_index); - m_shape.removeUserIndex(tangent_vertex_cluster_index); - return true; - } + EditShape m_shape; + Treap m_AET; + double m_y_scanline; + int m_geometry; + int m_unknown_ring_orientation_count; + IndexMultiDCList m_sorted_vertices; + AttributeStreamOfInt32 m_unknown_nodes; + int m_node_1_user_index; + int m_node_2_user_index; + int m_path_orientation_index; + int m_path_parentage_index; + boolean m_fixSelfTangency; + + static final class Edges { + EditShape m_shape; + AttributeStreamOfInt32 m_end_1_nodes; + AttributeStreamOfInt32 m_end_2_nodes; + AttributeStreamOfInt8 m_directions; + Point2D pt_1 = new Point2D(); + Point2D pt_2 = new Point2D(); + int m_first_free; + + boolean getDirection_(int index) { + return m_shape.getNextVertex(getEnd1(index)) == getEnd2(index); + } + + int getEnd_(int index) { + int v_1 = getEnd1(index); + int v_2 = getEnd2(index); + if (m_shape.getNextVertex(v_1) == v_2) + return v_2; + else + return v_1; + } + + Edges(EditShape shape) { + m_shape = shape; + m_first_free = -1; + } + + Segment getSegment(int index) { + return m_shape.getSegment(getStart(index)); + } + + // True if the start vertex is the lower point of the edge. + boolean isBottomUp(int index) { + int v_1 = getEnd1(index); + int v_2 = getEnd2(index); + if (m_shape.getPrevVertex(v_1) == v_2) { + int temp = v_1; + v_1 = v_2; + v_2 = temp; + } + m_shape.getXY(v_1, pt_1); + m_shape.getXY(v_2, pt_2); + return pt_1.y < pt_2.y; + } + + int getStart(int index) { + int v_1 = getEnd1(index); + int v_2 = getEnd2(index); + return (m_shape.getNextVertex(v_1) == v_2) ? v_1 : v_2; + } + + int getEnd1(int index) { + return m_end_1_nodes.get(index); + } + + int getEnd2(int index) { + return m_end_2_nodes.get(index); + } + + void freeEdge(int edge) { + m_end_1_nodes.set(edge, m_first_free); + m_first_free = edge; + } + + int newEdge(int vertex) { + if (m_first_free != -1) { + int index = m_first_free; + m_first_free = m_end_1_nodes.get(index); + m_end_1_nodes.set(index, vertex); + m_end_2_nodes.set(index, m_shape.getNextVertex(vertex)); + return index; + } else if (m_end_1_nodes == null) { + m_end_1_nodes = new AttributeStreamOfInt32(0); + m_end_2_nodes = new AttributeStreamOfInt32(0); + } + + int index = m_end_1_nodes.size(); + m_end_1_nodes.add(vertex); + m_end_2_nodes.add(m_shape.getNextVertex(vertex)); + return index; + } + + EditShape getShape() { + return m_shape; + } + + int getPath(int index) { + return m_shape.getPathFromVertex(getEnd1(index)); + } + } + + Edges m_edges; + + class RingOrientationTestComparator extends Treap.Comparator { + RingOrientationFixer m_helper; + Line m_line_1; + Line m_line_2; + int m_left_elm; + double m_leftx; + Segment m_seg_1; + + RingOrientationTestComparator(RingOrientationFixer helper) { + m_helper = helper; + m_line_1 = new Line(); + m_line_2 = new Line(); + m_leftx = 0; + m_seg_1 = null; + m_left_elm = -1; + } + + @Override + int compare(Treap treap, int left, int node) { + int right = treap.getElement(node); + RingOrientationFixer.Edges edges = m_helper.m_edges; + double x_1; + if (m_left_elm == left) + x_1 = m_leftx; + else { + m_seg_1 = edges.getSegment(left); + if (m_seg_1 == null) { + EditShape shape = edges.getShape(); + shape.queryLineConnector(edges.getStart(left), m_line_1); + m_seg_1 = m_line_1; + x_1 = m_line_1.intersectionOfYMonotonicWithAxisX( + m_helper.m_y_scanline, 0); + } else + x_1 = m_seg_1.intersectionOfYMonotonicWithAxisX( + m_helper.m_y_scanline, 0); + + m_leftx = x_1; + m_left_elm = left; + } + + Segment seg_2 = edges.getSegment(right); + double x2; + if (seg_2 == null) { + EditShape shape = edges.getShape(); + shape.queryLineConnector(edges.getStart(right), m_line_2); + seg_2 = m_line_2; + x2 = m_line_2.intersectionOfYMonotonicWithAxisX( + m_helper.m_y_scanline, 0); + } else + x2 = seg_2.intersectionOfYMonotonicWithAxisX( + m_helper.m_y_scanline, 0); + + if (x_1 == x2) { + boolean bStartLower1 = edges.isBottomUp(left); + boolean bStartLower2 = edges.isBottomUp(right); + + // apparently these edges originate from same vertex and the + // scanline is on the vertex. move scanline a little. + double y1 = !bStartLower1 ? m_seg_1.getStartY() : m_seg_1 + .getEndY(); + double y2 = !bStartLower2 ? seg_2.getStartY() : seg_2.getEndY(); + double miny = Math.min(y1, y2); + double y = (miny + m_helper.m_y_scanline) * 0.5; + if (y == m_helper.m_y_scanline) { + // assert(0);//ST: not a bug. just curious to see this + // happens. + y = miny; // apparently, one of the segments is almost + // horizontal line. + } + x_1 = m_seg_1.intersectionOfYMonotonicWithAxisX(y, 0); + x2 = seg_2.intersectionOfYMonotonicWithAxisX(y, 0); + assert (x_1 != x2); + } + + return x_1 < x2 ? -1 : (x_1 > x2 ? 1 : 0); + } + + void reset() { + m_left_elm = -1; + } + } + + RingOrientationTestComparator m_sweep_comparator; + + RingOrientationFixer() { + m_AET = new Treap(); + m_AET.disableBalancing(); + m_sweep_comparator = new RingOrientationTestComparator(this); + m_AET.setComparator(m_sweep_comparator); + } + + boolean fixRingOrientation_() { + boolean bFound = false; + + if (m_fixSelfTangency) + bFound = fixRingSelfTangency_(); + + if (m_shape.getPathCount(m_geometry) == 1) { + int path = m_shape.getFirstPath(m_geometry); + double area = m_shape.getRingArea(path); + m_shape.setExterior(path, true); + if (area < 0) { + int first = m_shape.getFirstVertex(path); + m_shape.reverseRingInternal_(first); + m_shape.setLastVertex_(path, m_shape.getPrevVertex(first));// fix + // last + // after + // the + // reverse + return true; + } + + return false; + } + + m_path_orientation_index = m_shape.createPathUserIndex();// used to + // store + // discovered + // orientation + // (3 - + // extrior, + // 2 - + // interior) + m_path_parentage_index = m_shape.createPathUserIndex();// used to + // resolve OGC + // order + for (int path = m_shape.getFirstPath(m_geometry); path != -1; path = m_shape + .getNextPath(path)) { + m_shape.setPathUserIndex(path, m_path_orientation_index, 0); + m_shape.setPathUserIndex(path, m_path_parentage_index, -1); + } + + AttributeStreamOfInt32 bunch = new AttributeStreamOfInt32(0); + m_y_scanline = NumberUtils.TheNaN; + Point2D pt = new Point2D(); + m_unknown_ring_orientation_count = m_shape.getPathCount(m_geometry); + m_node_1_user_index = m_shape.createUserIndex(); + m_node_2_user_index = m_shape.createUserIndex(); + for (int ivertex = m_sorted_vertices.getFirst(m_sorted_vertices + .getFirstList()); ivertex != -1; ivertex = m_sorted_vertices + .getNext(ivertex)) { + int vertex = m_sorted_vertices.getData(ivertex); + m_shape.getXY(vertex, pt); + if (pt.y != m_y_scanline && bunch.size() != 0) { + bFound |= processBunchForRingOrientationTest_(bunch); + m_sweep_comparator.reset(); + bunch.clear(false); + } + + bunch.add(vertex);// all vertices that have same y are added to the + // bunch + m_y_scanline = pt.y; + if (m_unknown_ring_orientation_count == 0) + break; + } + + if (m_unknown_ring_orientation_count > 0) { + bFound |= processBunchForRingOrientationTest_(bunch); + bunch.clear(false); + } + + m_shape.removeUserIndex(m_node_1_user_index); + m_shape.removeUserIndex(m_node_2_user_index); + + // dbg_verify_ring_orientation_();//debug + + for (int path = m_shape.getFirstPath(m_geometry); path != -1; ) { + if (m_shape.getPathUserIndex(path, m_path_orientation_index) == 3) {// exterior + m_shape.setExterior(path, true); + int afterPath = path; + for (int nextHole = m_shape.getPathUserIndex(path, + m_path_parentage_index); nextHole != -1; ) { + int p = m_shape.getPathUserIndex(nextHole, + m_path_parentage_index); + m_shape.movePath(m_geometry, + m_shape.getNextPath(afterPath), nextHole); + afterPath = nextHole; + nextHole = p; + } + path = m_shape.getNextPath(afterPath); + } else { + m_shape.setExterior(path, false); + path = m_shape.getNextPath(path); + } + } + + m_shape.removePathUserIndex(m_path_orientation_index); + m_shape.removePathUserIndex(m_path_parentage_index); + + return bFound; + } + + boolean processBunchForRingOrientationTest_(AttributeStreamOfInt32 bunch) { + return processBunchForRingOrientationTestOddEven_(bunch); + } + + boolean processBunchForRingOrientationTestOddEven_( + AttributeStreamOfInt32 bunch) { + boolean bModified = false; + if (m_edges == null) + m_edges = new Edges(m_shape); + + if (m_unknown_nodes == null) { + m_unknown_nodes = new AttributeStreamOfInt32(0); + m_unknown_nodes.reserve(16); + } else { + m_unknown_nodes.clear(false); + } + + processBunchForRingOrientationRemoveEdges_(bunch); + + // add edges that come into scope + for (int i = 0, n = bunch.size(); i < n; i++) { + int vertex = bunch.get(i); + if (vertex == -1) + continue; + insertEdge_(vertex, -1); + } + + for (int i = 0; i < m_unknown_nodes.size() + && m_unknown_ring_orientation_count > 0; i++) { + int aetNode = m_unknown_nodes.get(i); + int edge = m_AET.getElement(aetNode); + int path = m_edges.getPath(edge); + int orientation = m_shape.getPathUserIndex(path, + m_path_orientation_index); + int prevPath = -1; + if (orientation == 0) { + int node = m_AET.getPrev(aetNode); + int prevNode = aetNode; + boolean odd_even = false; + // find the leftmost edge for which the ring orientation is + // known + while (node != Treap.nullNode()) { + int edge1 = m_AET.getElement(node); + int path1 = m_edges.getPath(edge1); + int orientation1 = m_shape.getPathUserIndex(path1, + m_path_orientation_index); + if (orientation1 != 0) { + prevPath = path1; + break; + } + prevNode = node; + node = m_AET.getPrev(node); + } + if (node == Treap.nullNode()) {// if no edges have ring + // orientation known, then start + // from the left most and it has + // to be exterior ring. + odd_even = true; + node = prevNode; + } else { + int edge1 = m_AET.getElement(node); + odd_even = m_edges.isBottomUp(edge1); + node = m_AET.getNext(node); + odd_even = !odd_even; + } + + do { + int edge1 = m_AET.getElement(node); + int path1 = m_edges.getPath(edge1); + int orientation1 = m_shape.getPathUserIndex(path1, + m_path_orientation_index); + if (orientation1 == 0) { + if (odd_even != m_edges.isBottomUp(edge1)) { + int first = m_shape.getFirstVertex(path1); + m_shape.reverseRingInternal_(first); + m_shape.setLastVertex_(path1, + m_shape.getPrevVertex(first)); + bModified = true; + } + + m_shape.setPathUserIndex(path1, + m_path_orientation_index, odd_even ? 3 : 2); + if (!odd_even) {// link the holes into the linked list + // to mantain the OGC order. + int lastHole = m_shape.getPathUserIndex(prevPath, + m_path_parentage_index); + m_shape.setPathUserIndex(prevPath, + m_path_parentage_index, path1); + m_shape.setPathUserIndex(path1, + m_path_parentage_index, lastHole); + } + + m_unknown_ring_orientation_count--; + if (m_unknown_ring_orientation_count == 0) + return bModified; + } + + prevPath = path1; + prevNode = node; + node = m_AET.getNext(node); + odd_even = !odd_even; + } while (prevNode != aetNode); + } + } + + return bModified; + } + + void processBunchForRingOrientationRemoveEdges_(AttributeStreamOfInt32 bunch) { + // remove all nodes that go out of scope + for (int i = 0, n = bunch.size(); i < n; i++) { + int vertex = bunch.get(i); + int node1 = m_shape.getUserIndex(vertex, m_node_1_user_index); + int node2 = m_shape.getUserIndex(vertex, m_node_2_user_index); + if (node1 != -1) { + int edge = m_AET.getElement(node1); + m_edges.freeEdge(edge); + m_shape.setUserIndex(vertex, m_node_1_user_index, -1); + } + if (node2 != -1) { + int edge = m_AET.getElement(node2); + m_edges.freeEdge(edge); + m_shape.setUserIndex(vertex, m_node_2_user_index, -1); + } + + int reused_node = -1; + if (node1 != -1 && node2 != -1) {// terminating vertex + m_AET.deleteNode(node1, -1); + m_AET.deleteNode(node2, -1); + bunch.set(i, -1); + } else + reused_node = node1 != -1 ? node1 : node2; + + if (reused_node != -1) {// this vertex is a part of vertical chain. + // Sorted order in AET did not change, so + // reuse the AET node. + if (!insertEdge_(vertex, reused_node)) + m_AET.deleteNode(reused_node, -1);// horizontal edge was not + // inserted + bunch.set(i, -1); + } + } + } + + boolean insertEdge_(int vertex, int reused_node) { + Point2D pt_1 = new Point2D(); + Point2D pt_2 = new Point2D(); + m_shape.getXY(vertex, pt_1); + int next = m_shape.getNextVertex(vertex); + m_shape.getXY(next, pt_2); + boolean b_res = false; + if (pt_1.y < pt_2.y) { + b_res = true; + int edge = m_edges.newEdge(vertex); + int aetNode; + if (reused_node == -1) + aetNode = m_AET.addElement(edge, -1); + else { + aetNode = reused_node; + m_AET.setElement(aetNode, edge); + } + int node = m_shape.getUserIndex(next, m_node_1_user_index); + if (node == -1) + m_shape.setUserIndex(next, m_node_1_user_index, aetNode); + else + m_shape.setUserIndex(next, m_node_2_user_index, aetNode); + + int path = m_shape.getPathFromVertex(vertex); + if (m_shape.getPathUserIndex(path, m_path_orientation_index) == 0) { + m_unknown_nodes.add(aetNode); + } + } + + int prev = m_shape.getPrevVertex(vertex); + m_shape.getXY(prev, pt_2); + if (pt_1.y < pt_2.y) { + b_res = true; + int edge = m_edges.newEdge(prev); + int aetNode; + if (reused_node == -1) + aetNode = m_AET.addElement(edge, -1); + else { + aetNode = reused_node; + m_AET.setElement(aetNode, edge); + } + int node = m_shape.getUserIndex(prev, m_node_1_user_index); + if (node == -1) + m_shape.setUserIndex(prev, m_node_1_user_index, aetNode); + else + m_shape.setUserIndex(prev, m_node_2_user_index, aetNode); + + int path = m_shape.getPathFromVertex(vertex); + if (m_shape.getPathUserIndex(path, m_path_orientation_index) == 0) { + m_unknown_nodes.add(aetNode); + } + } + + return b_res; + } + + static boolean execute(EditShape shape, int geometry, + IndexMultiDCList sorted_vertices, boolean fixSelfTangency) { + RingOrientationFixer fixer = new RingOrientationFixer(); + fixer.m_shape = shape; + fixer.m_geometry = geometry; + fixer.m_sorted_vertices = sorted_vertices; + fixer.m_fixSelfTangency = fixSelfTangency; + return fixer.fixRingOrientation_(); + } + + boolean fixRingSelfTangency_() { + AttributeStreamOfInt32 self_tangent_paths = new AttributeStreamOfInt32( + 0); + AttributeStreamOfInt32 self_tangency_clusters = new AttributeStreamOfInt32( + 0); + int tangent_path_first_vertex_index = -1; + int tangent_vertex_cluster_index = -1; + Point2D pt_prev = new Point2D(); + pt_prev.setNaN(); + int prev_vertex = -1; + int old_path = -1; + int current_cluster = -1; + Point2D pt = new Point2D(); + for (int ivertex = m_sorted_vertices.getFirst(m_sorted_vertices + .getFirstList()); ivertex != -1; ivertex = m_sorted_vertices + .getNext(ivertex)) { + int vertex = m_sorted_vertices.getData(ivertex); + m_shape.getXY(vertex, pt); + int path = m_shape.getPathFromVertex(vertex); + if (pt_prev.isEqual(pt) && old_path == path) { + if (tangent_vertex_cluster_index == -1) { + tangent_path_first_vertex_index = m_shape + .createPathUserIndex(); + tangent_vertex_cluster_index = m_shape.createUserIndex(); + } + + if (current_cluster == -1) { + current_cluster = self_tangency_clusters.size(); + m_shape.setUserIndex(prev_vertex, + tangent_vertex_cluster_index, current_cluster); + self_tangency_clusters.add(1); + int p = m_shape.getPathUserIndex(path, + tangent_path_first_vertex_index); + if (p == -1) { + m_shape.setPathUserIndex(path, + tangent_path_first_vertex_index, prev_vertex); + self_tangent_paths.add(path); + } + } + + m_shape.setUserIndex(vertex, tangent_vertex_cluster_index, + current_cluster); + self_tangency_clusters + .setLast(self_tangency_clusters.getLast() + 1); + } else { + current_cluster = -1; + pt_prev.setCoords(pt); + } + + prev_vertex = vertex; + old_path = path; + } + + if (self_tangent_paths.size() == 0) + return false; + + // Now self_tangent_paths contains list of clusters of tangency for each + // path. + // The clusters contains list of clusters and for each cluster it + // contains a list of vertices. + AttributeStreamOfInt32 vertex_stack = new AttributeStreamOfInt32(0); + AttributeStreamOfInt32 cluster_stack = new AttributeStreamOfInt32(0); + + for (int ipath = 0, npath = self_tangent_paths.size(); ipath < npath; ipath++) { + int path = self_tangent_paths.get(ipath); + int first_vertex = m_shape.getPathUserIndex(path, + tangent_path_first_vertex_index); + int cluster = m_shape.getUserIndex(first_vertex, + tangent_vertex_cluster_index); + vertex_stack.clear(false); + cluster_stack.clear(false); + vertex_stack.add(first_vertex); + cluster_stack.add(cluster); + + for (int vertex = m_shape.getNextVertex(first_vertex); vertex != first_vertex; vertex = m_shape + .getNextVertex(vertex)) { + int vertex_to = vertex; + int cluster_to = m_shape.getUserIndex(vertex_to, + tangent_vertex_cluster_index); + if (cluster_to != -1) { + if (cluster_stack.size() == 0) { + cluster_stack.add(cluster_to); + vertex_stack.add(vertex_to); + continue; + } + + if (cluster_stack.getLast() == cluster_to) { + int vertex_from = vertex_stack.getLast(); + + // peel the loop from path + int from_next = m_shape.getNextVertex(vertex_from); + int from_prev = m_shape.getPrevVertex(vertex_from); + int to_next = m_shape.getNextVertex(vertex_to); + int to_prev = m_shape.getPrevVertex(vertex_to); + + m_shape.setNextVertex_(vertex_from, to_next); + m_shape.setPrevVertex_(to_next, vertex_from); + + m_shape.setNextVertex_(vertex_to, from_next); + m_shape.setPrevVertex_(from_next, vertex_to); + + // vertex_from is left in the path we are processing, + // while the vertex_to is in the loop being teared off. + boolean[] first_vertex_correction_requied = new boolean[]{false}; + int new_path = m_shape.insertClosedPath_(m_geometry, + -1, from_next, m_shape.getFirstVertex(path), + first_vertex_correction_requied); + + m_shape.setUserIndex(vertex, + tangent_vertex_cluster_index, -1); + + // Fix the path after peeling if the peeled loop had the + // first path vertex in it + + if (first_vertex_correction_requied[0]) { + m_shape.setFirstVertex_(path, to_next); + } + + int path_size = m_shape.getPathSize(path); + int new_path_size = m_shape.getPathSize(new_path); + path_size -= new_path_size; + assert (path_size >= 3); + m_shape.setPathSize_(path, path_size); + + self_tangency_clusters.set(cluster_to, + self_tangency_clusters.get(cluster_to) - 1); + if (self_tangency_clusters.get(cluster_to) == 1) { + self_tangency_clusters.set(cluster_to, 0); + cluster_stack.removeLast(); + vertex_stack.removeLast(); + } else { + // this cluster has more than two vertices in it. + } + + first_vertex = vertex_from;// reset the counter to + // ensure we find all loops. + vertex = vertex_from; + } else { + vertex_stack.add(vertex); + cluster_stack.add(cluster_to); + } + } + } + } + + m_shape.removePathUserIndex(tangent_path_first_vertex_index); + m_shape.removeUserIndex(tangent_vertex_cluster_index); + return true; + } } diff --git a/src/main/java/com/esri/core/geometry/Segment.java b/src/main/java/com/esri/core/geometry/Segment.java index 9d21eb65..b15364a2 100644 --- a/src/main/java/com/esri/core/geometry/Segment.java +++ b/src/main/java/com/esri/core/geometry/Segment.java @@ -32,907 +32,951 @@ * A base class for segments. Presently only Line segments are supported. */ public abstract class Segment extends Geometry implements Serializable { - double m_xStart; - - double m_yStart; - - double m_xEnd; - - double m_yEnd; - - double[] m_attributes; - - // Header Definitions - - /** - * Returns XY coordinates of the start point. - */ - public Point2D getStartXY() { - return Point2D.construct(m_xStart, m_yStart); - } - - public void getStartXY(Point2D pt) { - pt.x = m_xStart; - pt.y = m_yStart; - } - - /** - * Sets the XY coordinates of the start point. - */ - public void setStartXY(Point2D pt) { - _setXY(0, pt); - } - - public void setStartXY(double x, double y) { - _setXY(0, Point2D.construct(x, y)); - } - - /** - * Returns XYZ coordinates of the start point. Z if 0 if Z is missing. - */ - public Point3D getStartXYZ() { - return _getXYZ(0); - } - - /** - * Sets the XYZ coordinates of the start point. - */ - public void setStartXYZ(Point3D pt) { - _setXYZ(0, pt); - } - - public void setStartXYZ(double x, double y, double z) { - _setXYZ(0, Point3D.construct(x, y, z)); - } - - /** - * Returns coordinates of the start point in a Point class. - */ - public void queryStart(Point dstPoint) { - _get(0, dstPoint); - } - - /** - * Sets the coordinates of the start point in this segment. - * - * @param srcPoint The new start point of this segment. - */ - public void setStart(Point srcPoint) { - _set(0, srcPoint); - } - - /** - * Returns value of the start vertex attribute's ordinate. Throws if the - * Point is empty. - * - * @param semantics The attribute semantics. - * @param ordinate The attribute's ordinate. For example, the y coordinate of the - * NORMAL has ordinate of 1. - * @return Ordinate value as double. - */ - public double getStartAttributeAsDbl(int semantics, int ordinate) { - return _getAttributeAsDbl(0, semantics, ordinate); - } - - /** - * Returns the value of the start vertex attribute's ordinate. The ordinate - * is always 0 because integer attributes always have one component. - * - * @param semantics The attribute semantics. - * @param ordinate The attribute's ordinate. For example, the y coordinate of the - * NORMAL has ordinate of 1. - * @return Ordinate value truncated to 32 bit integer. - */ - public int getStartAttributeAsInt(int semantics, int ordinate) { - return _getAttributeAsInt(0, semantics, ordinate); - } - - /** - * Sets the value of the start vertex attribute. - * - * @param semantics The attribute semantics. - * @param value is the array to write values to. The attribute type and the - * number of elements must match the persistence type, as well as - * the number of components of the attribute. - */ - public void setStartAttribute(int semantics, int ordinate, double value) { - _setAttribute(0, semantics, ordinate, value); - } - - public void setStartAttribute(int semantics, int ordinate, int value) { - _setAttribute(0, semantics, ordinate, value); - } - - /** - * Returns the X coordinate of starting point. - * - * @return The X coordinate of starting point. - */ - public double getStartX() { - return m_xStart; - } - - /** - * Returns the Y coordinate of starting point. - * - * @return The Y coordinate of starting point. - */ - public double getStartY() { - return m_yStart; - } - - /** - * Returns the X coordinate of ending point. - * - * @return The X coordinate of ending point. - */ - public double getEndX() { - return m_xEnd; - } - - /** - * Returns the Y coordinate of ending point. - * - * @return The Y coordinate of ending point. - */ - public double getEndY() { - return m_yEnd; - } - - /** - * Returns XY coordinates of the end point. - * - * @return The XY coordinates of the end point. - */ - public Point2D getEndXY() { - return Point2D.construct(m_xEnd, m_yEnd); - } - - public void getEndXY(Point2D pt) { - pt.x = m_xEnd; - pt.y = m_yEnd; - } - - /** - * Sets the XY coordinates of the end point. - * - * @param pt The end point of the segment. - */ - public void setEndXY(Point2D pt) { - _setXY(1, pt); - } - - public void setEndXY(double x, double y) { - _setXY(1, Point2D.construct(x, y)); - } - - /** - * Returns XYZ coordinates of the end point. Z if 0 if Z is missing. - * - * @return The XYZ coordinates of the end point. - */ - public Point3D getEndXYZ() { - return _getXYZ(1); - } - - /** - * Sets the XYZ coordinates of the end point. - */ - public void setEndXYZ(Point3D pt) { - _setXYZ(1, pt); - } - - public void setEndXYZ(double x, double y, double z) { - _setXYZ(1, Point3D.construct(x, y, z)); - } - - /** - * Returns coordinates of the end point in this segment. - * - * @param dstPoint The end point of this segment. - */ - public void queryEnd(Point dstPoint) { - _get(1, dstPoint); - } - - /** - * Sets the coordinates of the end point in a Point class. - * - * @param srcPoint The new end point of this segment. - */ - public void setEnd(Point srcPoint) { - _set(1, srcPoint); - } - - /** - * Returns value of the end vertex attribute's ordinate. Throws if the Point - * is empty. - * - * @param semantics The attribute semantics. - * @param ordinate The attribute's ordinate. For example, the y coordinate of the - * NORMAL has ordinate of 1. - * @return Ordinate value as double. - */ - public double getEndAttributeAsDbl(int semantics, int ordinate) { - return _getAttributeAsDbl(1, semantics, ordinate); - } - - /** - * Returns the value of the end vertex attribute's ordinate. The ordinate is - * always 0 because integer attributes always have one component. - * - * @param semantics The attribute semantics. - * @param ordinate The attribute's ordinate. For example, the y coordinate of the - * NORMAL has ordinate of 1. - * @return The ordinate value truncated to 32 bit integer. - */ - public int getEndAttributeAsInt(int semantics, int ordinate) { - return _getAttributeAsInt(1, semantics, ordinate); - } - - /** - * Sets the value of end vertex attribute. - * - * @param semantics The attribute semantics. - * @param ordinate The attribute's ordinate. - * @param value Is the array to write values to. The attribute type and the - * number of elements must match the persistence type, as well as - * the number of components of the attribute. - */ - public void setEndAttribute(int semantics, int ordinate, double value) { - _setAttribute(1, semantics, ordinate, value); - } - - public void setEndAttribute(int semantics, int ordinate, int value) { - _setAttribute(1, semantics, ordinate, value); - } - - @Override - public final int getDimension() { - return 1; - } - - @Override - public final boolean isEmpty() { - return isEmptyImpl(); - } - - @Override - public final void setEmpty() { - - } - - @Override - public double calculateArea2D() { - return 0; - } - - /** - * Calculates intersections of this segment with another segment. - *

- * Note: This is not a topological operation. It needs to be paired with the - * Segment.Overlap call. - * - * @param other The segment to calculate intersection with. - * @param intersectionPoints The intersection points. Can be NULL. - * @param paramThis The value of the parameter in the intersection points for this - * Segment (between 0 and 1). Can be NULL. - * @param paramOther The value of the parameter in the intersection points for the - * other Segment (between 0 and 1). Can be NULL. - * @param tolerance The tolerance value for the intersection calculation. Can be - * 0. - * @return The number of intersection points, 0 when no intersection points - * exist. - */ - int intersect(Segment other, Point2D[] intersectionPoints, - double[] paramThis, double[] paramOther, double tolerance) { - return _intersect(other, intersectionPoints, paramThis, paramOther, - tolerance); - } - - /** - * Returns TRUE if this segment intersects with the other segment with the - * given tolerance. - */ - public boolean isIntersecting(Segment other, double tolerance) { - return _isIntersecting(other, tolerance, false) != 0; - } - - /** - * Returns TRUE if the point and segment intersect (not disjoint) for the - * given tolerance. - */ - public boolean isIntersecting(Point2D pt, double tolerance) { - return _isIntersectingPoint(pt, tolerance, false); - } - - /** - * Non public abstract version of the function. - */ - public boolean isEmptyImpl() { - return false; - } - - // Header Definitions - - // Cpp definitions - - /** - * Creates a segment with start and end points (0,0). - */ - public Segment() { - m_xStart = 0; - m_yStart = 0; - m_xEnd = 0; - m_yEnd = 0; - m_attributes = null; - } - - void _resizeAttributes(int newSize) { - _touch(); - if (m_attributes == null && newSize > 0) { - m_attributes = new double[newSize * 2]; - } else if (m_attributes != null && m_attributes.length < newSize * 2) { - double[] newbuffer = new double[newSize * 2]; - System.arraycopy(m_attributes, 0, newbuffer, 0, m_attributes.length); - m_attributes = newbuffer; - } - } - - static void _attributeCopy(double[] src, int srcStart, double[] dst, - int dstStart, int count) { - if (count > 0) - System.arraycopy(src, srcStart, dst, dstStart, count); - } - - private Point2D _getXY(int endPoint) { - Point2D pt = new Point2D(); - if (endPoint != 0) { - pt.setCoords(m_xEnd, m_yEnd); - } else { - pt.setCoords(m_xStart, m_yStart); - } - return pt; - } - - private void _setXY(int endPoint, Point2D pt) { - if (endPoint != 0) { - m_xEnd = pt.x; - m_yEnd = pt.y; - } else { - m_xStart = pt.x; - m_yStart = pt.y; - } - } - - private Point3D _getXYZ(int endPoint) { - Point3D pt = new Point3D(); - if (endPoint != 0) { - pt.x = m_xEnd; - pt.y = m_yEnd; - } else { - pt.x = m_xStart; - pt.y = m_yStart; - } - - if (m_description.hasZ()) - pt.z = m_attributes[_getEndPointOffset(m_description, endPoint)]; - else - pt.z = VertexDescription.getDefaultValue(Semantics.Z); - - return pt; - } - - private void _setXYZ(int endPoint, Point3D pt) { - _touch(); - boolean bHasZ = hasAttribute(Semantics.Z); - if (!bHasZ && !VertexDescription.isDefaultValue(Semantics.Z, pt.z)) {// add - // Z - // only - // if - // pt.z - // is - // not - // a - // default - // value. - addAttribute(Semantics.Z); - bHasZ = true; - } - - if (endPoint != 0) { - m_xEnd = pt.x; - m_yEnd = pt.y; - } else { - m_xStart = pt.x; - m_yStart = pt.y; - } - - if (bHasZ) - m_attributes[_getEndPointOffset(m_description, endPoint)] = pt.z; - - } - - @Override - protected void _assignVertexDescriptionImpl(VertexDescription newDescription) { - if (m_attributes == null) { - m_description = newDescription; - return; - } - - int[] mapping = VertexDescriptionDesignerImpl.mapAttributes(newDescription, m_description); - - double[] newAttributes = new double[(newDescription.getTotalComponentCount() - 2) * 2]; - - int old_offset0 = _getEndPointOffset(m_description, 0); - int old_offset1 = _getEndPointOffset(m_description, 1); - - int new_offset0 = _getEndPointOffset(newDescription, 0); - int new_offset1 = _getEndPointOffset(newDescription, 1); - - int j = 0; - for (int i = 1, n = newDescription.getAttributeCount(); i < n; i++) { - int semantics = newDescription.getSemantics(i); - int nords = VertexDescription.getComponentCount(semantics); - if (mapping[i] == -1) { - double d = VertexDescription.getDefaultValue(semantics); - for (int ord = 0; ord < nords; ord++) { - newAttributes[new_offset0 + j] = d; - newAttributes[new_offset1 + j] = d; - j++; - } - } else { - int m = mapping[i]; - int offset = m_description._getPointAttributeOffset(m) - 2; - for (int ord = 0; ord < nords; ord++) { - newAttributes[new_offset0 + j] = m_attributes[old_offset0 + offset]; - newAttributes[new_offset1 + j] = m_attributes[old_offset1 + offset]; - j++; - offset++; - } - } - - } - - m_attributes = newAttributes; - m_description = newDescription; - } - - private void _get(int endPoint, Point outPoint) { - if (isEmptyImpl()) - throw new GeometryException("empty geometry");// ._setToDefault(); - - outPoint.assignVertexDescription(m_description); - - if (outPoint.isEmptyImpl()) - outPoint._setToDefault(); - - for (int attributeIndex = 0; attributeIndex < m_description - .getAttributeCount(); attributeIndex++) { - int semantics = m_description._getSemanticsImpl(attributeIndex); - for (int icomp = 0, ncomp = VertexDescription - .getComponentCount(semantics); icomp < ncomp; icomp++) { - double v = _getAttributeAsDbl(endPoint, semantics, icomp); - outPoint.setAttribute(semantics, icomp, v); - } - } - } - - private void _set(int endPoint, Point src) { - _touch(); - Point point = src; - - if (src.isEmptyImpl())// can not assign an empty point - throw new GeometryException("empty_Geometry"); - - VertexDescription vdin = point.getDescription(); - for (int attributeIndex = 0, nattrib = vdin.getAttributeCount(); attributeIndex < nattrib; attributeIndex++) { - int semantics = vdin._getSemanticsImpl(attributeIndex); - int ncomp = VertexDescription.getComponentCount(semantics); - for (int icomp = 0; icomp < ncomp; icomp++) { - double v = point.getAttributeAsDbl(semantics, icomp); - _setAttribute(endPoint, semantics, icomp, v); - } - } - } - - double _getAttributeAsDbl(int endPoint, int semantics, int ordinate) { - if (isEmptyImpl()) - throw new GeometryException( - "This operation was performed on an Empty Geometry."); - - if (semantics == Semantics.POSITION) { - if (endPoint != 0) { - return (ordinate != 0) ? m_yEnd : m_xEnd; - } else { - return (ordinate != 0) ? m_yStart : m_xStart; - } - } - - int ncomps = VertexDescription.getComponentCount(semantics); - if (ordinate >= ncomps) - throw new IndexOutOfBoundsException(); - - int attributeIndex = m_description.getAttributeIndex(semantics); - if (attributeIndex >= 0) { - if (m_attributes != null) - _resizeAttributes(m_description.getTotalComponentCount() - 2); - - return m_attributes[_getEndPointOffset(m_description, endPoint) - + m_description._getPointAttributeOffset(attributeIndex) - - 2 + ordinate]; - } else - return VertexDescription.getDefaultValue(semantics); - } - - private int _getAttributeAsInt(int endPoint, int semantics, int ordinate) { - if (isEmptyImpl()) - throw new GeometryException("Empty_Geometry."); - - return (int) _getAttributeAsDbl(endPoint, semantics, ordinate); - } - - void _setAttribute(int endPoint, int semantics, int ordinate, double value) { - _touch(); - int ncomps = VertexDescription.getComponentCount(semantics); - if (ordinate >= ncomps) - throw new IndexOutOfBoundsException(); - - int attributeIndex = m_description.getAttributeIndex(semantics); - if (attributeIndex < 0) { - addAttribute(semantics); - attributeIndex = m_description.getAttributeIndex(semantics); - } - - if (semantics == Semantics.POSITION) { - if (endPoint != 0) { - if (ordinate != 0) - m_yEnd = value; - else - m_xEnd = value; - } else if (ordinate != 0) - m_yStart = value; - else - m_xStart = value; - return; - } - - if (m_attributes == null) - _resizeAttributes(m_description.getTotalComponentCount() - 2); - - m_attributes[_getEndPointOffset(m_description, endPoint) - + m_description._getPointAttributeOffset(attributeIndex) - 2 - + ordinate] = value; - - } - - void _setAttribute(int endPoint, int semantics, int ordinate, int value) { - _setAttribute(endPoint, semantics, ordinate, (double) value); - } - - @Override - public void copyTo(Geometry dst) { - if (dst.getType() != getType()) - throw new IllegalArgumentException(); - - Segment segDst = (Segment) dst; - segDst.m_description = m_description; - segDst._resizeAttributes(m_description.getTotalComponentCount() - 2); - _attributeCopy(m_attributes, 0, segDst.m_attributes, 0, - (m_description.getTotalComponentCount() - 2) * 2); - segDst.m_xStart = m_xStart; - segDst.m_yStart = m_yStart; - segDst.m_xEnd = m_xEnd; - segDst.m_yEnd = m_yEnd; - dst._touch(); - - _copyToImpl(segDst); - } - - @Override - public Envelope1D queryInterval(int semantics, int ordinate) { - Envelope1D env = new Envelope1D(); - if (isEmptyImpl()) { - env.setEmpty(); - return env; - } - - env.vmin = _getAttributeAsDbl(0, semantics, ordinate); - env.vmax = env.vmin; - env.mergeNE(_getAttributeAsDbl(1, semantics, ordinate)); - return env; - } - - void queryCoord(double t, Point point) { - point.assignVertexDescription(m_description); - point.setXY(getCoord2D(t)); - for (int iattrib = 1, nattrib = m_description.getAttributeCount(); iattrib < nattrib; iattrib++) { - int semantics = m_description._getSemanticsImpl(iattrib); - int ncomp = VertexDescription.getComponentCount(semantics); - for (int iord = 0; iord < ncomp; iord++) { - double value = getAttributeAsDbl(t, semantics, iord); - point.setAttribute(semantics, iord, value); - } - } - } - - boolean _equalsImpl(Segment other) { - if (m_description != other.m_description) - return false; - - if (m_xStart != other.m_xStart || m_xEnd != other.m_xEnd - || m_yStart != other.m_yStart || m_yEnd != other.m_yEnd) - return false; - for (int i = 0; i < (m_description.getTotalComponentCount() - 2) * 2; i++) - if (m_attributes[i] != other.m_attributes[i]) - return false; - - return true; - } - - /** - * Returns true, when this segment is a closed curve (start point is equal - * to end point exactly). - *

- * Note, this will return true for lines, that are degenerate to a point - * too. - */ - boolean isClosed() { - return m_xStart == m_xEnd && m_yStart == m_yEnd; - } - - void reverse() { - _reverseImpl(); - double origxStart = m_xStart; - double origxEnd = m_xEnd; - m_xStart = origxEnd; - m_xEnd = origxStart; - double origyStart = m_yStart; - double origyEnd = m_yEnd; - m_yStart = origyEnd; - m_yEnd = origyStart; - - for (int i = 1, n = m_description.getAttributeCount(); i < n; i++) { - int semantics = m_description.getSemantics(i);// VertexDescription.Semantics - // semantics = - // m_description.getSemantics(i); - for (int iord = 0, nord = VertexDescription - .getComponentCount(semantics); iord < nord; iord++) { - double v1 = _getAttributeAsDbl(0, semantics, iord); - double v2 = _getAttributeAsDbl(1, semantics, iord); - _setAttribute(0, semantics, iord, v2); - _setAttribute(1, semantics, iord, v1); - } - } - } - - int _isIntersecting(Segment other, double tolerance, - boolean bExcludeExactEndpoints) { - int gtThis = getType().value(); - int gtOther = other.getType().value(); - switch (gtThis) { - case Geometry.GeometryType.Line: - if (gtOther == Geometry.GeometryType.Line) - return Line._isIntersectingLineLine((Line) this, (Line) other, - tolerance, bExcludeExactEndpoints); - else - throw GeometryException.GeometryInternalError(); - default: - throw GeometryException.GeometryInternalError(); - } - } - - int _intersect(Segment other, Point2D[] intersectionPoints, - double[] paramThis, double[] paramOther, double tolerance) { - int gtThis = getType().value(); - int gtOther = other.getType().value(); - switch (gtThis) { - case Geometry.GeometryType.Line: - if (gtOther == Geometry.GeometryType.Line) - return Line._intersectLineLine((Line) this, (Line) other, - intersectionPoints, paramThis, paramOther, tolerance); - else - throw GeometryException.GeometryInternalError(); - default: - throw GeometryException.GeometryInternalError(); - } - } - - /** - * A helper function for area calculation. Calculates the Integral(y(t) * - * x'(t) * dt) for t = [0, 1]. The area of a ring is caluclated as a sum of - * the results of CalculateArea2DHelper. - */ - abstract double _calculateArea2DHelper(double xorg, double yorg); - - static int _getEndPointOffset(VertexDescription vd, int endPoint) { - return endPoint * (vd.getTotalComponentCount() - 2); - } - - /** - * Returns the coordinate of the point on this segment for the given - * parameter value. - */ - public Point2D getCoord2D(double t) { - Point2D pt = new Point2D(); - getCoord2D(t, pt); - return pt; - } - - /** - * Returns the coordinate of the point on this segment for the given - * parameter value (segments are parametric curves). - * - * @param t the parameter coordinate along the segment from 0.0 to 1.0. - * Value of 0 returns the start point, 1 returns end point. - * @param dst the coordinate where result will be placed. - */ - public abstract void getCoord2D(double t, Point2D dst); - - /** - * Finds a closest coordinate on this segment. - * - * @param inputPoint The 2D point to find the closest coordinate on this segment. - * @param bExtrapolate TRUE if the segment is extrapolated at the end points along - * the end point tangents. Otherwise the result is limited to - * values between 0 and 1. - * @return The parametric coordinate t on the segment (0 corresponds to the - * start point, 1 corresponds to the end point). Use getCoord2D to - * obtain the 2D coordinate on the segment from t. To find the - * distance, call (inputPoint.sub(seg.getCoord2D(t))).length(); - */ - public abstract double getClosestCoordinate(Point2D inputPoint, - boolean bExtrapolate); - - /** - * Splits this segment into Y monotonic parts and places them into the input - * array. - * - * @param monotonicSegments The in/out array of SegmentBuffer structures that will be - * filled with the monotonic parts. The monotonicSegments array - * must contain at least 3 elements. - * @return The number of monotonic parts if the split had happened. Returns - * 0 if the segment is already monotonic. - */ - abstract int getYMonotonicParts(SegmentBuffer[] monotonicSegments); - - /** - * Calculates intersection points of this segment with an infinite line, - * parallel to one of the axes. - * - * @param bAxisX TRUE if the function works with the line parallel to the axis - * X. - * @param ordinate The ordinate value of the line (x for axis Y, y for axis X). - * @param resultOrdinates The value of ordinate in the intersection points One ordinate - * is equal to the ordinate parameter. This parameter can be - * NULL. - * @param parameters The value of the parameter in the intersection points (between - * 0 and 1). This parameter can be NULL. - * @return The number of intersection points, 0 when no intersection points - * exist, -1 when the segment coincides with the line (infinite - * number of intersection points). - */ - public abstract int intersectionWithAxis2D(boolean bAxisX, double ordinate, - double[] resultOrdinates, double[] parameters); - - void _reverseImpl() { - } - - /** - * Returns True if the segment is degenerate to a point with relation to the - * given tolerance. For Lines this means the line length is not longer than - * the tolerance. For the curves, the distance between the segment endpoints - * should not be longer than the tolerance and the distance from the line, - * connecting the endpoints to the furtherst point on the segment is not - * larger than the tolerance. - */ - abstract boolean isDegenerate(double tolerance); - - // Cpp definitions - - abstract boolean isCurve(); - - abstract Point2D _getTangent(double t); - - abstract boolean _isDegenerate(double tolerance); - - double _calculateSubLength(double t) { - return tToLength(t); - } - - double _calculateSubLength(double t1, double t2) { - return tToLength(t2) - tToLength(t1); - } - - abstract void _copyToImpl(Segment dst); - - /** - * Returns subsegment between parameters t1 and t2. The attributes are - * interpolated along the length of the curve. - */ - public abstract Segment cut(double t1, double t2); - - /** - * Calculates the subsegment between parameters t1 and t2, and stores the - * result in subSegmentBuffer. The attributes are interpolated along the - * length of the curve. - */ - abstract void cut(double t1, double t2, SegmentBuffer subSegmentBuffer); - - /** - * Returns the attribute on the segment for the given parameter value. The - * interpolation of attribute is given by the attribute interpolation type. - */ - public abstract double getAttributeAsDbl(double t, int semantics, - int ordinate); - - abstract boolean _isIntersectingPoint(Point2D pt, double tolerance, - boolean bExcludeExactEndpoints); - - /** - * Calculates intersection point of this segment with an infinite line, - * parallel to axis X. This segment must be to be y-monotonic (or - * horizontal). - * - * @param y The y coordinate of the line. - * @param xParallel For segments, that are horizontal, and have y coordinate, this - * value is returned. - * @return X coordinate of the intersection, or NaN, if no intersection. - */ - abstract double intersectionOfYMonotonicWithAxisX(double y, double xParallel); - - /** - * Converts curves parameter t to the curve length. Can be expensive for curves. - */ - abstract double tToLength(double t); - - abstract double lengthToT(double len); - - public double distance(/* const */Segment otherSegment, - boolean bSegmentsKnownDisjoint) { - // if the segments are not known to be disjoint, and - // the segments are found to touch in any way, then return 0.0 - if (!bSegmentsKnownDisjoint - && _isIntersecting(otherSegment, 0, false) != 0) { - return 0.0; - } - - double minDistance = NumberUtils.doubleMax(); - - Point2D input_point; - double t; - double distance; - - input_point = getStartXY(); - t = otherSegment.getClosestCoordinate(input_point, false); - input_point.sub(otherSegment.getCoord2D(t)); - distance = input_point.length(); - if (distance < minDistance) - minDistance = distance; - - input_point = getEndXY(); - t = otherSegment.getClosestCoordinate(input_point, false); - input_point.sub(otherSegment.getCoord2D(t)); - distance = input_point.length(); - if (distance < minDistance) - minDistance = distance; - - input_point = otherSegment.getStartXY(); - t = getClosestCoordinate(input_point, false); - input_point.sub(getCoord2D(t)); - distance = input_point.length(); - if (distance < minDistance) - minDistance = distance; - - input_point = otherSegment.getEndXY(); - t = getClosestCoordinate(input_point, false); - input_point.sub(getCoord2D(t)); - distance = input_point.length(); - if (distance < minDistance) - minDistance = distance; - - return minDistance; - } + double m_xStart; + + double m_yStart; + + double m_xEnd; + + double m_yEnd; + + double[] m_attributes; + + // Header Definitions + /** + * Returns XY coordinates of the start point. + */ + public Point2D getStartXY() { + return Point2D.construct(m_xStart, m_yStart); + } + + public void getStartXY(Point2D pt) { + pt.x = m_xStart; + pt.y = m_yStart; + } + + /** + * Sets the XY coordinates of the start point. + */ + public void setStartXY(Point2D pt) { + _setXY(0, pt); + } + + public void setStartXY(double x, double y) { + _setXY(0, Point2D.construct(x, y)); + } + + /** + * Returns XYZ coordinates of the start point. Z if 0 if Z is missing. + */ + public Point3D getStartXYZ() { + return _getXYZ(0); + } + + /** + * Sets the XYZ coordinates of the start point. + */ + public void setStartXYZ(Point3D pt) { + _setXYZ(0, pt); + } + + public void setStartXYZ(double x, double y, double z) { + _setXYZ(0, Point3D.construct(x, y, z)); + } + + /** + * Returns coordinates of the start point in a Point class. + */ + public void queryStart(Point dstPoint) { + _get(0, dstPoint); + } + + /** + * Sets the coordinates of the start point in this segment. + * + * @param srcPoint + * The new start point of this segment. + */ + public void setStart(Point srcPoint) { + _set(0, srcPoint); + } + + /** + * Returns value of the start vertex attribute's ordinate. Throws if the + * Point is empty. + * + * @param semantics + * The attribute semantics. + * @param ordinate + * The attribute's ordinate. For example, the y coordinate of the + * NORMAL has ordinate of 1. + * @return Ordinate value as double. + */ + public double getStartAttributeAsDbl(int semantics, int ordinate) { + return _getAttributeAsDbl(0, semantics, ordinate); + } + + /** + * Returns the value of the start vertex attribute's ordinate. The ordinate + * is always 0 because integer attributes always have one component. + * + * @param semantics + * The attribute semantics. + * @param ordinate + * The attribute's ordinate. For example, the y coordinate of the + * NORMAL has ordinate of 1. + * @return Ordinate value truncated to 32 bit integer. + */ + public int getStartAttributeAsInt(int semantics, int ordinate) { + return _getAttributeAsInt(0, semantics, ordinate); + } + + /** + * Sets the value of the start vertex attribute. + * + * @param semantics + * The attribute semantics. + * @param value + * is the array to write values to. The attribute type and the + * number of elements must match the persistence type, as well as + * the number of components of the attribute. + */ + public void setStartAttribute(int semantics, int ordinate, double value) { + _setAttribute(0, semantics, ordinate, value); + } + + public void setStartAttribute(int semantics, int ordinate, int value) { + _setAttribute(0, semantics, ordinate, value); + } + + /** + * Returns the X coordinate of starting point. + * + * @return The X coordinate of starting point. + */ + public double getStartX() { + return m_xStart; + } + + /** + * Returns the Y coordinate of starting point. + * + * @return The Y coordinate of starting point. + */ + public double getStartY() { + return m_yStart; + } + + /** + * Returns the X coordinate of ending point. + * + * @return The X coordinate of ending point. + */ + public double getEndX() { + return m_xEnd; + } + + /** + * Returns the Y coordinate of ending point. + * + * @return The Y coordinate of ending point. + */ + public double getEndY() { + return m_yEnd; + } + + /** + * Returns XY coordinates of the end point. + * + * @return The XY coordinates of the end point. + */ + public Point2D getEndXY() { + return Point2D.construct(m_xEnd, m_yEnd); + } + + public void getEndXY(Point2D pt) { + pt.x = m_xEnd; + pt.y = m_yEnd; + } + + /** + * Sets the XY coordinates of the end point. + * + * @param pt + * The end point of the segment. + */ + public void setEndXY(Point2D pt) { + _setXY(1, pt); + } + + public void setEndXY(double x, double y) { + _setXY(1, Point2D.construct(x, y)); + } + + /** + * Returns XYZ coordinates of the end point. Z if 0 if Z is missing. + * + * @return The XYZ coordinates of the end point. + */ + public Point3D getEndXYZ() { + return _getXYZ(1); + } + + /** + * Sets the XYZ coordinates of the end point. + */ + public void setEndXYZ(Point3D pt) { + _setXYZ(1, pt); + } + + public void setEndXYZ(double x, double y, double z) { + _setXYZ(1, Point3D.construct(x, y, z)); + } + + /** + * Returns coordinates of the end point in this segment. + * + * @param dstPoint + * The end point of this segment. + */ + public void queryEnd(Point dstPoint) { + _get(1, dstPoint); + } + + /** + * Sets the coordinates of the end point in a Point class. + * + * @param srcPoint + * The new end point of this segment. + */ + public void setEnd(Point srcPoint) { + _set(1, srcPoint); + } + + /** + * Returns value of the end vertex attribute's ordinate. Throws if the Point + * is empty. + * + * @param semantics + * The attribute semantics. + * @param ordinate + * The attribute's ordinate. For example, the y coordinate of the + * NORMAL has ordinate of 1. + * @return Ordinate value as double. + */ + public double getEndAttributeAsDbl(int semantics, int ordinate) { + return _getAttributeAsDbl(1, semantics, ordinate); + } + + /** + * Returns the value of the end vertex attribute's ordinate. The ordinate is + * always 0 because integer attributes always have one component. + * + * @param semantics + * The attribute semantics. + * @param ordinate + * The attribute's ordinate. For example, the y coordinate of the + * NORMAL has ordinate of 1. + * @return The ordinate value truncated to 32 bit integer. + */ + public int getEndAttributeAsInt(int semantics, int ordinate) { + return _getAttributeAsInt(1, semantics, ordinate); + } + + /** + * Sets the value of end vertex attribute. + * + * @param semantics + * The attribute semantics. + * @param ordinate + * The attribute's ordinate. + * @param value + * Is the array to write values to. The attribute type and the + * number of elements must match the persistence type, as well as + * the number of components of the attribute. + */ + public void setEndAttribute(int semantics, int ordinate, double value) { + _setAttribute(1, semantics, ordinate, value); + } + + public void setEndAttribute(int semantics, int ordinate, int value) { + _setAttribute(1, semantics, ordinate, value); + } + + @Override + public final int getDimension() { + return 1; + } + + @Override + public final boolean isEmpty() { + return isEmptyImpl(); + } + + @Override + public final void setEmpty() { + + } + + @Override + public double calculateArea2D() { + return 0; + } + + /** + * Calculates intersections of this segment with another segment. + *

+ * Note: This is not a topological operation. It needs to be paired with the + * Segment.Overlap call. + * + * @param other + * The segment to calculate intersection with. + * @param intersectionPoints + * The intersection points. Can be NULL. + * @param paramThis + * The value of the parameter in the intersection points for this + * Segment (between 0 and 1). Can be NULL. + * @param paramOther + * The value of the parameter in the intersection points for the + * other Segment (between 0 and 1). Can be NULL. + * @param tolerance + * The tolerance value for the intersection calculation. Can be + * 0. + * @return The number of intersection points, 0 when no intersection points + * exist. + */ + int intersect(Segment other, Point2D[] intersectionPoints, + double[] paramThis, double[] paramOther, double tolerance) { + return _intersect(other, intersectionPoints, paramThis, paramOther, + tolerance); + } + + /** + * Returns TRUE if this segment intersects with the other segment with the + * given tolerance. + */ + public boolean isIntersecting(Segment other, double tolerance) { + return _isIntersecting(other, tolerance, false) != 0; + } + + /** + * Returns TRUE if the point and segment intersect (not disjoint) for the + * given tolerance. + */ + public boolean isIntersecting(Point2D pt, double tolerance) { + return _isIntersectingPoint(pt, tolerance, false); + } + + /** + * Non public abstract version of the function. + */ + public boolean isEmptyImpl() { + return false; + } + + // Header Definitions + + // Cpp definitions + /** + * Creates a segment with start and end points (0,0). + */ + public Segment() { + m_xStart = 0; + m_yStart = 0; + m_xEnd = 0; + m_yEnd = 0; + m_attributes = null; + } + + void _resizeAttributes(int newSize) { + _touch(); + if (m_attributes == null && newSize > 0) { + m_attributes = new double[newSize * 2]; + } else if (m_attributes != null && m_attributes.length < newSize * 2) { + double[] newbuffer = new double[newSize * 2]; + System.arraycopy(m_attributes, 0, newbuffer, 0, m_attributes.length); + m_attributes = newbuffer; + } + } + + static void _attributeCopy(double[] src, int srcStart, double[] dst, + int dstStart, int count) { + if (count > 0) + System.arraycopy(src, srcStart, dst, dstStart, count); + } + + private Point2D _getXY(int endPoint) { + Point2D pt = new Point2D(); + if (endPoint != 0) { + pt.setCoords(m_xEnd, m_yEnd); + } else { + pt.setCoords(m_xStart, m_yStart); + } + return pt; + } + + private void _setXY(int endPoint, Point2D pt) { + if (endPoint != 0) { + m_xEnd = pt.x; + m_yEnd = pt.y; + } else { + m_xStart = pt.x; + m_yStart = pt.y; + } + } + + private Point3D _getXYZ(int endPoint) { + Point3D pt = new Point3D(); + if (endPoint != 0) { + pt.x = m_xEnd; + pt.y = m_yEnd; + } else { + pt.x = m_xStart; + pt.y = m_yStart; + } + + if (m_description.hasZ()) + pt.z = m_attributes[_getEndPointOffset(m_description, endPoint)]; + else + pt.z = VertexDescription.getDefaultValue(Semantics.Z); + + return pt; + } + + private void _setXYZ(int endPoint, Point3D pt) { + _touch(); + boolean bHasZ = hasAttribute(Semantics.Z); + if (!bHasZ && !VertexDescription.isDefaultValue(Semantics.Z, pt.z)) {// add + // Z + // only + // if + // pt.z + // is + // not + // a + // default + // value. + addAttribute(Semantics.Z); + bHasZ = true; + } + + if (endPoint != 0) { + m_xEnd = pt.x; + m_yEnd = pt.y; + } else { + m_xStart = pt.x; + m_yStart = pt.y; + } + + if (bHasZ) + m_attributes[_getEndPointOffset(m_description, endPoint)] = pt.z; + + } + + @Override + protected void _assignVertexDescriptionImpl(VertexDescription newDescription) { + if (m_attributes == null) { + m_description = newDescription; + return; + } + + int[] mapping = VertexDescriptionDesignerImpl.mapAttributes(newDescription, m_description); + + double[] newAttributes = new double[(newDescription.getTotalComponentCount() - 2) * 2]; + + int old_offset0 = _getEndPointOffset(m_description, 0); + int old_offset1 = _getEndPointOffset(m_description, 1); + + int new_offset0 = _getEndPointOffset(newDescription, 0); + int new_offset1 = _getEndPointOffset(newDescription, 1); + + int j = 0; + for (int i = 1, n = newDescription.getAttributeCount(); i < n; i++) { + int semantics = newDescription.getSemantics(i); + int nords = VertexDescription.getComponentCount(semantics); + if (mapping[i] == -1) + { + double d = VertexDescription.getDefaultValue(semantics); + for (int ord = 0; ord < nords; ord++) + { + newAttributes[new_offset0 + j] = d; + newAttributes[new_offset1 + j] = d; + j++; + } + } + else { + int m = mapping[i]; + int offset = m_description._getPointAttributeOffset(m) - 2; + for (int ord = 0; ord < nords; ord++) + { + newAttributes[new_offset0 + j] = m_attributes[old_offset0 + offset]; + newAttributes[new_offset1 + j] = m_attributes[old_offset1 + offset]; + j++; + offset++; + } + } + + } + + m_attributes = newAttributes; + m_description = newDescription; + } + + private void _get(int endPoint, Point outPoint) { + if (isEmptyImpl()) + throw new GeometryException("empty geometry");// ._setToDefault(); + + outPoint.assignVertexDescription(m_description); + + for (int attributeIndex = 0; attributeIndex < m_description + .getAttributeCount(); attributeIndex++) { + int semantics = m_description._getSemanticsImpl(attributeIndex); + for (int icomp = 0, ncomp = VertexDescription + .getComponentCount(semantics); icomp < ncomp; icomp++) { + double v = _getAttributeAsDbl(endPoint, semantics, icomp); + outPoint.setAttribute(semantics, icomp, v); + } + } + } + + private void _set(int endPoint, Point src) { + _touch(); + Point point = src; + + if (src.isEmptyImpl())// can not assign an empty point + throw new GeometryException("empty_Geometry"); + + VertexDescription vdin = point.getDescription(); + for (int attributeIndex = 0, nattrib = vdin.getAttributeCount(); attributeIndex < nattrib; attributeIndex++) { + int semantics = vdin._getSemanticsImpl(attributeIndex); + int ncomp = VertexDescription.getComponentCount(semantics); + for (int icomp = 0; icomp < ncomp; icomp++) { + double v = point.getAttributeAsDbl(semantics, icomp); + _setAttribute(endPoint, semantics, icomp, v); + } + } + } + + double _getAttributeAsDbl(int endPoint, int semantics, int ordinate) { + if (isEmptyImpl()) + throw new GeometryException( + "This operation was performed on an Empty Geometry."); + + if (semantics == Semantics.POSITION) { + if (endPoint != 0) { + return (ordinate != 0) ? m_yEnd : m_xEnd; + } else { + return (ordinate != 0) ? m_yStart : m_xStart; + } + } + + int ncomps = VertexDescription.getComponentCount(semantics); + if (ordinate >= ncomps) + throw new IndexOutOfBoundsException(); + + int attributeIndex = m_description.getAttributeIndex(semantics); + if (attributeIndex >= 0) { + if (m_attributes != null) + _resizeAttributes(m_description.getTotalComponentCount() - 2); + + return m_attributes[_getEndPointOffset(m_description, endPoint) + + m_description._getPointAttributeOffset(attributeIndex) + - 2 + ordinate]; + } else + return VertexDescription.getDefaultValue(semantics); + } + + private int _getAttributeAsInt(int endPoint, int semantics, int ordinate) { + if (isEmptyImpl()) + throw new GeometryException("Empty_Geometry."); + + return (int) _getAttributeAsDbl(endPoint, semantics, ordinate); + } + + void _setAttribute(int endPoint, int semantics, int ordinate, double value) { + _touch(); + int ncomps = VertexDescription.getComponentCount(semantics); + if (ordinate >= ncomps) + throw new IndexOutOfBoundsException(); + + int attributeIndex = m_description.getAttributeIndex(semantics); + if (attributeIndex < 0) { + addAttribute(semantics); + attributeIndex = m_description.getAttributeIndex(semantics); + } + + if (semantics == Semantics.POSITION) { + if (endPoint != 0) { + if (ordinate != 0) + m_yEnd = value; + else + m_xEnd = value; + } + else if (ordinate != 0) + m_yStart = value; + else + m_xStart = value; + return; + } + + if (m_attributes == null) + _resizeAttributes(m_description.getTotalComponentCount() - 2); + + m_attributes[_getEndPointOffset(m_description, endPoint) + + m_description._getPointAttributeOffset(attributeIndex) - 2 + + ordinate] = value; + + } + + void _setAttribute(int endPoint, int semantics, int ordinate, int value) { + _setAttribute(endPoint, semantics, ordinate, (double) value); + } + + @Override + public void copyTo(Geometry dst) { + if (dst.getType() != getType()) + throw new IllegalArgumentException(); + + Segment segDst = (Segment) dst; + segDst.m_description = m_description; + segDst._resizeAttributes(m_description.getTotalComponentCount() - 2); + _attributeCopy(m_attributes, 0, segDst.m_attributes, 0, + (m_description.getTotalComponentCount() - 2) * 2); + segDst.m_xStart = m_xStart; + segDst.m_yStart = m_yStart; + segDst.m_xEnd = m_xEnd; + segDst.m_yEnd = m_yEnd; + dst._touch(); + + _copyToImpl(segDst); + } + + @Override + public Envelope1D queryInterval(int semantics, int ordinate) { + Envelope1D env = new Envelope1D(); + if (isEmptyImpl()) { + env.setEmpty(); + return env; + } + + env.vmin = _getAttributeAsDbl(0, semantics, ordinate); + env.vmax = env.vmin; + env.mergeNE(_getAttributeAsDbl(1, semantics, ordinate)); + return env; + } + + void queryCoord(double t, Point point) { + point.assignVertexDescription(m_description); + point.setXY(getCoord2D(t)); + for (int iattrib = 1, nattrib = m_description.getAttributeCount(); iattrib < nattrib; iattrib++) { + int semantics = m_description._getSemanticsImpl(iattrib); + int ncomp = VertexDescription.getComponentCount(semantics); + for (int iord = 0; iord < ncomp; iord++) { + double value = getAttributeAsDbl(t, semantics, iord); + point.setAttribute(semantics, iord, value); + } + } + } + + boolean _equalsImpl(Segment other) { + if (m_description != other.m_description) + return false; + + if (m_xStart != other.m_xStart || m_xEnd != other.m_xEnd + || m_yStart != other.m_yStart || m_yEnd != other.m_yEnd) + return false; + for (int i = 0; i < (m_description.getTotalComponentCount() - 2) * 2; i++) + if (!NumberUtils.isEqualNonIEEE(m_attributes[i], other.m_attributes[i])) + return false; + + return true; + } + + @Override + public int hashCode() { + int hash = m_description.hashCode(); + hash = NumberUtils.hash(hash, m_xStart); + hash = NumberUtils.hash(hash, m_yStart); + hash = NumberUtils.hash(hash, m_xEnd); + hash = NumberUtils.hash(hash, m_yEnd); + for (int i = 0; i < (m_description.getTotalComponentCount() - 2) * 2; i++) { + hash = NumberUtils.hash(hash, m_attributes[i]); + } + + return hash; + } + + /** + * Returns true, when this segment is a closed curve (start point is equal + * to end point exactly). + * + * Note, this will return true for lines, that are degenerate to a point + * too. + */ + boolean isClosed() { + return m_xStart == m_xEnd && m_yStart == m_yEnd; + } + + void reverse() { + _reverseImpl(); + double origxStart = m_xStart; + double origxEnd = m_xEnd; + m_xStart = origxEnd; + m_xEnd = origxStart; + double origyStart = m_yStart; + double origyEnd = m_yEnd; + m_yStart = origyEnd; + m_yEnd = origyStart; + + for (int i = 1, n = m_description.getAttributeCount(); i < n; i++) { + int semantics = m_description.getSemantics(i);// VertexDescription.Semantics + // semantics = + // m_description.getSemantics(i); + for (int iord = 0, nord = VertexDescription + .getComponentCount(semantics); iord < nord; iord++) { + double v1 = _getAttributeAsDbl(0, semantics, iord); + double v2 = _getAttributeAsDbl(1, semantics, iord); + _setAttribute(0, semantics, iord, v2); + _setAttribute(1, semantics, iord, v1); + } + } + } + + int _isIntersecting(Segment other, double tolerance, + boolean bExcludeExactEndpoints) { + int gtThis = getType().value(); + int gtOther = other.getType().value(); + switch (gtThis) { + case Geometry.GeometryType.Line: + if (gtOther == Geometry.GeometryType.Line) + return Line._isIntersectingLineLine((Line) this, (Line) other, + tolerance, bExcludeExactEndpoints); + else + throw GeometryException.GeometryInternalError(); + default: + throw GeometryException.GeometryInternalError(); + } + } + + int _intersect(Segment other, Point2D[] intersectionPoints, + double[] paramThis, double[] paramOther, double tolerance) { + int gtThis = getType().value(); + int gtOther = other.getType().value(); + switch (gtThis) { + case Geometry.GeometryType.Line: + if (gtOther == Geometry.GeometryType.Line) + return Line._intersectLineLine((Line) this, (Line) other, + intersectionPoints, paramThis, paramOther, tolerance); + else + throw GeometryException.GeometryInternalError(); + default: + throw GeometryException.GeometryInternalError(); + } + } + + /** + * A helper function for area calculation. Calculates the Integral(y(t) * + * x'(t) * dt) for t = [0, 1]. The area of a ring is caluclated as a sum of + * the results of CalculateArea2DHelper. + */ + abstract double _calculateArea2DHelper(double xorg, double yorg); + + static int _getEndPointOffset(VertexDescription vd, int endPoint) { + return endPoint * (vd.getTotalComponentCount() - 2); + } + + /** + * Returns the coordinate of the point on this segment for the given + * parameter value. + */ + public Point2D getCoord2D(double t) { + Point2D pt = new Point2D(); + getCoord2D(t, pt); + return pt; + } + + /** + * Returns the coordinate of the point on this segment for the given + * parameter value (segments are parametric curves). + * + * @param t + * the parameter coordinate along the segment from 0.0 to 1.0. + * Value of 0 returns the start point, 1 returns end point. + * @param dst + * the coordinate where result will be placed. + */ + public abstract void getCoord2D(double t, Point2D dst); + + /** + * Finds a closest coordinate on this segment. + * + * @param inputPoint + * The 2D point to find the closest coordinate on this segment. + * @param bExtrapolate + * TRUE if the segment is extrapolated at the end points along + * the end point tangents. Otherwise the result is limited to + * values between 0 and 1. + * @return The parametric coordinate t on the segment (0 corresponds to the + * start point, 1 corresponds to the end point). Use getCoord2D to + * obtain the 2D coordinate on the segment from t. To find the + * distance, call (inputPoint.sub(seg.getCoord2D(t))).length(); + */ + public abstract double getClosestCoordinate(Point2D inputPoint, + boolean bExtrapolate); + + /** + * Splits this segment into Y monotonic parts and places them into the input + * array. + * + * @param monotonicSegments + * The in/out array of SegmentBuffer structures that will be + * filled with the monotonic parts. The monotonicSegments array + * must contain at least 3 elements. + * @return The number of monotonic parts if the split had happened. Returns + * 0 if the segment is already monotonic. + */ + abstract int getYMonotonicParts(SegmentBuffer[] monotonicSegments); + + /** + * Calculates intersection points of this segment with an infinite line, + * parallel to one of the axes. + * + * @param bAxisX + * TRUE if the function works with the line parallel to the axis + * X. + * @param ordinate + * The ordinate value of the line (x for axis Y, y for axis X). + * @param resultOrdinates + * The value of ordinate in the intersection points One ordinate + * is equal to the ordinate parameter. This parameter can be + * NULL. + * @param parameters + * The value of the parameter in the intersection points (between + * 0 and 1). This parameter can be NULL. + * @return The number of intersection points, 0 when no intersection points + * exist, -1 when the segment coincides with the line (infinite + * number of intersection points). + */ + public abstract int intersectionWithAxis2D(boolean bAxisX, double ordinate, + double[] resultOrdinates, double[] parameters); + + void _reverseImpl() { + } + + /** + * Returns True if the segment is degenerate to a point with relation to the + * given tolerance. For Lines this means the line length is not longer than + * the tolerance. For the curves, the distance between the segment endpoints + * should not be longer than the tolerance and the distance from the line, + * connecting the endpoints to the furtherst point on the segment is not + * larger than the tolerance. + */ + abstract boolean isDegenerate(double tolerance); + + // Cpp definitions + + abstract boolean isCurve(); + + abstract Point2D _getTangent(double t); + + abstract boolean _isDegenerate(double tolerance); + + double _calculateSubLength(double t) { return tToLength(t); } + + double _calculateSubLength(double t1, double t2) { return tToLength(t2) - tToLength(t1); } + + abstract void _copyToImpl(Segment dst); + + /** + * Returns subsegment between parameters t1 and t2. The attributes are + * interpolated along the length of the curve. + */ + public abstract Segment cut(double t1, double t2); + + /** + * Calculates the subsegment between parameters t1 and t2, and stores the + * result in subSegmentBuffer. The attributes are interpolated along the + * length of the curve. + */ + abstract void cut(double t1, double t2, SegmentBuffer subSegmentBuffer); + + /** + * Returns the attribute on the segment for the given parameter value. The + * interpolation of attribute is given by the attribute interpolation type. + */ + public abstract double getAttributeAsDbl(double t, int semantics, + int ordinate); + + abstract boolean _isIntersectingPoint(Point2D pt, double tolerance, + boolean bExcludeExactEndpoints); + + /** + * Calculates intersection point of this segment with an infinite line, + * parallel to axis X. This segment must be to be y-monotonic (or + * horizontal). + * + * @param y + * The y coordinate of the line. + * @param xParallel + * For segments, that are horizontal, and have y coordinate, this + * value is returned. + * @return X coordinate of the intersection, or NaN, if no intersection. + */ + abstract double intersectionOfYMonotonicWithAxisX(double y, double xParallel); + + /** + * Converts curves parameter t to the curve length. Can be expensive for curves. + */ + abstract double tToLength(double t); + + abstract double lengthToT(double len); + + public double distance(/* const */Segment otherSegment, + boolean bSegmentsKnownDisjoint) + { + // if the segments are not known to be disjoint, and + // the segments are found to touch in any way, then return 0.0 + if (!bSegmentsKnownDisjoint + && _isIntersecting(otherSegment, 0, false) != 0) { + return 0.0; + } + + double minDistance = NumberUtils.doubleMax(); + + Point2D input_point; + double t; + double distance; + + input_point = getStartXY(); + t = otherSegment.getClosestCoordinate(input_point, false); + input_point.sub(otherSegment.getCoord2D(t)); + distance = input_point.length(); + if (distance < minDistance) + minDistance = distance; + + input_point = getEndXY(); + t = otherSegment.getClosestCoordinate(input_point, false); + input_point.sub(otherSegment.getCoord2D(t)); + distance = input_point.length(); + if (distance < minDistance) + minDistance = distance; + + input_point = otherSegment.getStartXY(); + t = getClosestCoordinate(input_point, false); + input_point.sub(getCoord2D(t)); + distance = input_point.length(); + if (distance < minDistance) + minDistance = distance; + + input_point = otherSegment.getEndXY(); + t = getClosestCoordinate(input_point, false); + input_point.sub(getCoord2D(t)); + distance = input_point.length(); + if (distance < minDistance) + minDistance = distance; + + return minDistance; + } public Geometry getBoundary() { return Boundary.calculate(this, null); diff --git a/src/main/java/com/esri/core/geometry/SegmentBuffer.java b/src/main/java/com/esri/core/geometry/SegmentBuffer.java index fbf7a594..b043c3a2 100644 --- a/src/main/java/com/esri/core/geometry/SegmentBuffer.java +++ b/src/main/java/com/esri/core/geometry/SegmentBuffer.java @@ -33,45 +33,45 @@ */ class SegmentBuffer implements Serializable { - private static final long serialVersionUID = 1L; - - Line m_line; - - // PointerOf(Bezier) m_bez; - Segment m_seg; - - public SegmentBuffer() { - m_line = null; - m_seg = null; - } - - public Segment get() { - return m_seg; - } - - public void set(Segment seg) { - m_seg = seg; - if (seg != null) { - if (seg.getType() == Type.Line) { - Line ln = (Line) seg; - m_line = ln; - } - throw GeometryException.GeometryInternalError(); - } - } - - public void create(Geometry.Type type) { - if (type == Geometry.Type.Line) - createLine(); - else - throw new GeometryException("not implemented"); - } - - public void createLine() { - if (null == m_line) { - m_line = new Line(); - - } - m_seg = m_line; - } + private static final long serialVersionUID = 1L; + + Line m_line; + + // PointerOf(Bezier) m_bez; + Segment m_seg; + + public SegmentBuffer() { + m_line = null; + m_seg = null; + } + + public Segment get() { + return m_seg; + } + + public void set(Segment seg) { + m_seg = seg; + if (seg != null) { + if (seg.getType() == Type.Line) { + Line ln = (Line) seg; + m_line = ln; + } + throw GeometryException.GeometryInternalError(); + } + } + + public void create(Geometry.Type type) { + if (type == Geometry.Type.Line) + createLine(); + else + throw new GeometryException("not implemented"); + } + + public void createLine() { + if (null == m_line) { + m_line = new Line(); + + } + m_seg = m_line; + } } diff --git a/src/main/java/com/esri/core/geometry/SegmentFlags.java b/src/main/java/com/esri/core/geometry/SegmentFlags.java index 1722b6c7..d15da3f0 100644 --- a/src/main/java/com/esri/core/geometry/SegmentFlags.java +++ b/src/main/java/com/esri/core/geometry/SegmentFlags.java @@ -25,12 +25,12 @@ package com.esri.core.geometry; interface SegmentFlags { - public static final int enumLineSeg = 1; - public static final int enumBezierSeg = 2; - public static final int enumArcSeg = 4; - public static final int enumNonlinearSegmentMask = 6; - public static final int enumSegmentMask = 7; - public static final int enumDensified = 8; // set for segments that have - // been produced from a - // densified non-linear segment. + public static final int enumLineSeg = 1; + public static final int enumBezierSeg = 2; + public static final int enumArcSeg = 4; + public static final int enumNonlinearSegmentMask = 6; + public static final int enumSegmentMask = 7; + public static final int enumDensified = 8; // set for segments that have + // been produced from a + // densified non-linear segment. } diff --git a/src/main/java/com/esri/core/geometry/SegmentIntersector.java b/src/main/java/com/esri/core/geometry/SegmentIntersector.java index a096b4da..e8748a84 100644 --- a/src/main/java/com/esri/core/geometry/SegmentIntersector.java +++ b/src/main/java/com/esri/core/geometry/SegmentIntersector.java @@ -30,414 +30,414 @@ import java.util.ArrayList; class SegmentIntersector { - private static class IntersectionPart { - public Segment seg; - // Weight controls the snapping. When points of the same rank are - // snapped together, - // The new posistion is calculated as a weighted average. - public double weight_start; - public double weight_end; - // The rank controls the snapping. The point with lower rank will be - // snapped to the point with the higher rank. - public int rank_start; // the rank of the start point - public int rank_end; // the rank of the end point - public int rank_interior; // the rank of the interior point - - IntersectionPart(Segment _seg) { - seg = _seg; - weight_start = 1.0; - weight_end = 1.0; - rank_start = 0; - rank_end = 0; - rank_interior = 0; - } - } - - // typedef std::shared_ptr segment_buffer_sptr; - // typedef std::shared_ptr intersection_part_sptr; - // typedef Dynamic_array intersection_parts; - - private ArrayList m_input_segments; - private ArrayList m_result_segments_1; - private ArrayList m_result_segments_2; - private ArrayList m_recycled_intersection_parts; - private ArrayList m_recycled_segments; - private double[] m_param_1 = new double[15]; - private double[] m_param_2 = new double[15]; - private Point m_point = new Point(); - - private int m_used_recycled_segments; - - private void recycle_(ArrayList parts) { - if (parts == null) - return; - - for (int i = 0, n = (int) parts.size(); i < n; i++) { - recycle_(parts.get(i)); - } - - parts.clear(); - } - - private void recycle_(IntersectionPart part) { - part.seg = null; - m_recycled_intersection_parts.add(part); - } - - private IntersectionPart newIntersectionPart_(Segment _seg) { - if (m_recycled_intersection_parts.isEmpty()) { - IntersectionPart part = new IntersectionPart(_seg); - return part; - } else { - IntersectionPart part = m_recycled_intersection_parts - .get(m_recycled_intersection_parts.size() - 1); - part.seg = _seg; - m_recycled_intersection_parts.remove(m_recycled_intersection_parts - .size() - 1); - return part; - } - } - - private IntersectionPart getResultPart_(int input_segment_index, - int segment_index) { - if (input_segment_index == 0) { - return m_result_segments_1.get(segment_index); - } else { - assert (input_segment_index == 1); - return m_result_segments_2.get(segment_index); - } - } - - private SegmentBuffer newSegmentBuffer_() { - if (m_used_recycled_segments >= m_recycled_segments.size()) { - m_recycled_segments.add(new SegmentBuffer()); - } - - SegmentBuffer p = m_recycled_segments.get(m_used_recycled_segments); - m_used_recycled_segments++; - return p; - } - - private double m_tolerance; - - public SegmentIntersector() { - m_used_recycled_segments = 0; - m_tolerance = 0; - m_input_segments = new ArrayList(); - m_result_segments_1 = new ArrayList(); - m_result_segments_2 = new ArrayList(); - m_recycled_intersection_parts = new ArrayList(); - m_recycled_segments = new ArrayList(); - } - - // Clears the results and input segments - public void clear() { - recycle_(m_input_segments); - recycle_(m_result_segments_1); - recycle_(m_result_segments_2); - m_used_recycled_segments = 0; - } - - // Adds a segment to intersect and returns an index of the segment. - // Two segments has to be pushed for the intersect method to succeed. - public int pushSegment(Segment seg) { - assert (m_input_segments.size() < 2); - m_input_segments.add(newIntersectionPart_(seg)); - // m_param_1.resize(15); - // m_param_2.resize(15); - return (int) m_input_segments.size() - 1; - } - - public void setRankAndWeight(int input_segment_index, double start_weight, - int start_rank, double end_weight, int end_rank, int interior_rank) { - IntersectionPart part = m_input_segments.get(input_segment_index); - part.rank_end = end_rank; - part.weight_start = start_weight; - part.weight_end = end_weight; - part.rank_start = start_rank; - part.rank_end = end_rank; - part.rank_interior = interior_rank; - } - - // Returns the number of segments the input segment has been split to. - public int getResultSegmentCount(int input_segment_index) { - if (input_segment_index == 0) { - return (int) m_result_segments_1.size(); - } else { - assert (input_segment_index == 1); - return (int) m_result_segments_2.size(); - } - } - - // Returns a part of the input segment that is the result of the - // intersection with another segment. - // input_segment_index is the index of the input segment. - // segment_index is between 0 and - // get_result_segment_count(input_segment_index) - 1 - public Segment getResultSegment(int input_segment_index, int segment_index) { - return getResultPart_(input_segment_index, segment_index).seg; - } - - // double get_result_segment_start_point_weight(int input_segment_index, int - // segment_index); - // int get_result_segment_start_point_rank(int input_segment_index, int - // segment_index); - // double get_result_segment_end_point_weight(int input_segment_index, int - // segment_index); - // int get_result_segment_end_point_rank(int input_segment_index, int - // segment_index); - // int get_result_segment_interior_rank(int input_segment_index, int - // segment_index); - public Point getResultPoint() { - return m_point; - } - - // Performs the intersection - public boolean intersect(double tolerance, boolean b_intersecting) { - if (m_input_segments.size() != 2) - throw GeometryException.GeometryInternalError(); - - m_tolerance = tolerance; - double small_tolerance_sqr = MathUtils.sqr(tolerance * 0.01); - boolean bigmove = false; - - IntersectionPart part1 = m_input_segments.get(0); - IntersectionPart part2 = m_input_segments.get(1); - if (b_intersecting - || (part1.seg._isIntersecting(part2.seg, tolerance, true) & 5) != 0) { - if (part1.seg.getType().value() == Geometry.GeometryType.Line) { - Line line_1 = (Line) part1.seg; - if (part2.seg.getType().value() == Geometry.GeometryType.Line) { - Line line_2 = (Line) part2.seg; - int count = Line._intersectLineLine(line_1, line_2, null, - m_param_1, m_param_2, tolerance); - if (count == 0) { - assert (count > 0); - throw GeometryException.GeometryInternalError(); - } - Point2D[] points = new Point2D[9]; - for (int i = 0; i < count; i++) { - // For each point of intersection, we calculate a - // weighted point - // based on the ranks and weights of the endpoints and - // the interior. - double t1 = m_param_1[i]; - double t2 = m_param_2[i]; - int rank1 = part1.rank_interior; - double weight1 = 1.0; - - if (t1 == 0) { - rank1 = part1.rank_start; - weight1 = part1.weight_start; - } else if (t1 == 1.0) { - rank1 = part1.rank_end; - weight1 = part1.weight_end; - } - - int rank2 = part2.rank_interior; - double weight2 = 1.0; - if (t2 == 0) { - rank2 = part2.rank_start; - weight2 = part2.weight_start; - } else if (t2 == 1.0) { - rank2 = part2.rank_end; - weight2 = part2.weight_end; - } - - double ptWeight; - - Point2D pt = new Point2D(); - if (rank1 == rank2) {// for equal ranks use weighted sum - Point2D pt_1 = new Point2D(); - line_1.getCoord2D(t1, pt_1); - Point2D pt_2 = new Point2D(); - line_2.getCoord2D(t2, pt_2); - ptWeight = weight1 + weight2; - double t = weight2 / ptWeight; - MathUtils.lerp(pt_1, pt_2, t, pt); - if (Point2D.sqrDistance(pt, pt_1) - + Point2D.sqrDistance(pt, pt_2) > small_tolerance_sqr) - bigmove = true; - - } else {// for non-equal ranks, the higher rank wins - if (rank1 > rank2) { - line_1.getCoord2D(t1, pt); - ptWeight = weight1; - Point2D pt_2 = new Point2D(); - line_2.getCoord2D(t2, pt_2); - if (Point2D.sqrDistance(pt, pt_2) > small_tolerance_sqr) - bigmove = true; - } else { - line_2.getCoord2D(t2, pt); - ptWeight = weight2; - Point2D pt_1 = new Point2D(); - line_1.getCoord2D(t1, pt_1); - if (Point2D.sqrDistance(pt, pt_1) > small_tolerance_sqr) - bigmove = true; - } - } - points[i] = pt; - } - - // Split the line_1, making sure the endpoints are adusted - // to the weighted - double t0 = 0; - int i0 = -1; - for (int i = 0; i <= count; i++) { - double t = i < count ? m_param_1[i] : 1.0; - if (t != t0) { - SegmentBuffer seg_buffer = newSegmentBuffer_(); - line_1.cut(t0, t, seg_buffer); - if (i0 != -1) - seg_buffer.get().setStartXY(points[i0]); - if (i != count) - seg_buffer.get().setEndXY(points[i]); - - t0 = t; - m_result_segments_1 - .add(newIntersectionPart_(seg_buffer.get())); - } - i0 = i; - } - - int[] indices = new int[9]; - for (int i = 0; i < count; i++) - indices[i] = i; - - if (count > 1) { - if (m_param_2[0] > m_param_2[1]) { - double t = m_param_2[0]; - m_param_2[0] = m_param_2[1]; - m_param_2[1] = t; - int i = indices[0]; - indices[0] = indices[1]; - indices[1] = i; - } - } - - // Split the line_2 - t0 = 0; - i0 = -1; - for (int i = 0; i <= count; i++) { - double t = i < count ? m_param_2[i] : 1.0; - if (t != t0) { - SegmentBuffer seg_buffer = newSegmentBuffer_(); - line_2.cut(t0, t, seg_buffer); - if (i0 != -1) { - int ind = indices[i0]; - seg_buffer.get().setStartXY(points[ind]); - } - if (i != count) { - int ind = indices[i]; - seg_buffer.get().setEndXY(points[ind]); - } - - t0 = t; - m_result_segments_2 - .add(newIntersectionPart_(seg_buffer.get())); - } - i0 = i; - } - - return bigmove; - } - - throw GeometryException.GeometryInternalError(); - } - - throw GeometryException.GeometryInternalError(); - } - - return false; - } - - public void intersect(double tolerance, Point pt_intersector_point, - int point_rank, double point_weight, boolean b_intersecting) { - pt_intersector_point.copyTo(m_point); - if (m_input_segments.size() != 1) - throw GeometryException.GeometryInternalError(); - - m_tolerance = tolerance; - - IntersectionPart part1 = m_input_segments.get(0); - if (b_intersecting - || part1.seg._isIntersectingPoint(pt_intersector_point.getXY(), - tolerance, true)) { - if (part1.seg.getType().value() == Geometry.GeometryType.Line) { - Line line_1 = (Line) (part1.seg); - double t1 = line_1.getClosestCoordinate( - pt_intersector_point.getXY(), false); - m_param_1[0] = t1; - // For each point of intersection, we calculate a weighted point - // based on the ranks and weights of the endpoints and the - // interior. - int rank1 = part1.rank_interior; - double weight1 = 1.0; - - if (t1 == 0) { - rank1 = part1.rank_start; - weight1 = part1.weight_start; - } else if (t1 == 1.0) { - rank1 = part1.rank_end; - weight1 = part1.weight_end; - } - - int rank2 = point_rank; - double weight2 = point_weight; - - double ptWeight; - - Point2D pt = new Point2D(); - if (rank1 == rank2) {// for equal ranks use weighted sum - Point2D pt_1 = new Point2D(); - line_1.getCoord2D(t1, pt_1); - Point2D pt_2 = pt_intersector_point.getXY(); - ptWeight = weight1 + weight2; - double t = weight2 / ptWeight; - MathUtils.lerp(pt_1, pt_2, t, pt); - } else {// for non-equal ranks, the higher rank wins - if (rank1 > rank2) { - pt = new Point2D(); - line_1.getCoord2D(t1, pt); - ptWeight = weight1; - } else { - pt = pt_intersector_point.getXY(); - ptWeight = weight2; - } - } - - // Split the line_1, making sure the endpoints are adusted to - // the weighted - double t0 = 0; - int i0 = -1; - int count = 1; - for (int i = 0; i <= count; i++) { - double t = i < count ? m_param_1[i] : 1.0; - if (t != t0) { - SegmentBuffer seg_buffer = newSegmentBuffer_(); - line_1.cut(t0, t, seg_buffer); - if (i0 != -1) - seg_buffer.get().setStartXY(pt); - if (i != count) - seg_buffer.get().setEndXY(pt); - - t0 = t; - m_result_segments_1.add(newIntersectionPart_(seg_buffer - .get())); - } - i0 = i; - } - - m_point.setXY(pt); - - return; - } - - throw GeometryException.GeometryInternalError(); - } - } - - public double get_tolerance_() { - return m_tolerance; - } + private static class IntersectionPart { + public Segment seg; + // Weight controls the snapping. When points of the same rank are + // snapped together, + // The new posistion is calculated as a weighted average. + public double weight_start; + public double weight_end; + // The rank controls the snapping. The point with lower rank will be + // snapped to the point with the higher rank. + public int rank_start; // the rank of the start point + public int rank_end; // the rank of the end point + public int rank_interior; // the rank of the interior point + + IntersectionPart(Segment _seg) { + seg = _seg; + weight_start = 1.0; + weight_end = 1.0; + rank_start = 0; + rank_end = 0; + rank_interior = 0; + } + } + + // typedef std::shared_ptr segment_buffer_sptr; + // typedef std::shared_ptr intersection_part_sptr; + // typedef Dynamic_array intersection_parts; + + private ArrayList m_input_segments; + private ArrayList m_result_segments_1; + private ArrayList m_result_segments_2; + private ArrayList m_recycled_intersection_parts; + private ArrayList m_recycled_segments; + private double[] m_param_1 = new double[15]; + private double[] m_param_2 = new double[15]; + private Point m_point = new Point(); + + private int m_used_recycled_segments; + + private void recycle_(ArrayList parts) { + if (parts == null) + return; + + for (int i = 0, n = (int) parts.size(); i < n; i++) { + recycle_(parts.get(i)); + } + + parts.clear(); + } + + private void recycle_(IntersectionPart part) { + part.seg = null; + m_recycled_intersection_parts.add(part); + } + + private IntersectionPart newIntersectionPart_(Segment _seg) { + if (m_recycled_intersection_parts.isEmpty()) { + IntersectionPart part = new IntersectionPart(_seg); + return part; + } else { + IntersectionPart part = m_recycled_intersection_parts + .get(m_recycled_intersection_parts.size() - 1); + part.seg = _seg; + m_recycled_intersection_parts.remove(m_recycled_intersection_parts + .size() - 1); + return part; + } + } + + private IntersectionPart getResultPart_(int input_segment_index, + int segment_index) { + if (input_segment_index == 0) { + return m_result_segments_1.get(segment_index); + } else { + assert (input_segment_index == 1); + return m_result_segments_2.get(segment_index); + } + } + + private SegmentBuffer newSegmentBuffer_() { + if (m_used_recycled_segments >= m_recycled_segments.size()) { + m_recycled_segments.add(new SegmentBuffer()); + } + + SegmentBuffer p = m_recycled_segments.get(m_used_recycled_segments); + m_used_recycled_segments++; + return p; + } + + private double m_tolerance; + + public SegmentIntersector() { + m_used_recycled_segments = 0; + m_tolerance = 0; + m_input_segments = new ArrayList(); + m_result_segments_1 = new ArrayList(); + m_result_segments_2 = new ArrayList(); + m_recycled_intersection_parts = new ArrayList(); + m_recycled_segments = new ArrayList(); + } + + // Clears the results and input segments + public void clear() { + recycle_(m_input_segments); + recycle_(m_result_segments_1); + recycle_(m_result_segments_2); + m_used_recycled_segments = 0; + } + + // Adds a segment to intersect and returns an index of the segment. + // Two segments has to be pushed for the intersect method to succeed. + public int pushSegment(Segment seg) { + assert (m_input_segments.size() < 2); + m_input_segments.add(newIntersectionPart_(seg)); + // m_param_1.resize(15); + // m_param_2.resize(15); + return (int) m_input_segments.size() - 1; + } + + public void setRankAndWeight(int input_segment_index, double start_weight, + int start_rank, double end_weight, int end_rank, int interior_rank) { + IntersectionPart part = m_input_segments.get(input_segment_index); + part.rank_end = end_rank; + part.weight_start = start_weight; + part.weight_end = end_weight; + part.rank_start = start_rank; + part.rank_end = end_rank; + part.rank_interior = interior_rank; + } + + // Returns the number of segments the input segment has been split to. + public int getResultSegmentCount(int input_segment_index) { + if (input_segment_index == 0) { + return (int) m_result_segments_1.size(); + } else { + assert (input_segment_index == 1); + return (int) m_result_segments_2.size(); + } + } + + // Returns a part of the input segment that is the result of the + // intersection with another segment. + // input_segment_index is the index of the input segment. + // segment_index is between 0 and + // get_result_segment_count(input_segment_index) - 1 + public Segment getResultSegment(int input_segment_index, int segment_index) { + return getResultPart_(input_segment_index, segment_index).seg; + } + + // double get_result_segment_start_point_weight(int input_segment_index, int + // segment_index); + // int get_result_segment_start_point_rank(int input_segment_index, int + // segment_index); + // double get_result_segment_end_point_weight(int input_segment_index, int + // segment_index); + // int get_result_segment_end_point_rank(int input_segment_index, int + // segment_index); + // int get_result_segment_interior_rank(int input_segment_index, int + // segment_index); + public Point getResultPoint() { + return m_point; + } + + // Performs the intersection + public boolean intersect(double tolerance, boolean b_intersecting) { + if (m_input_segments.size() != 2) + throw GeometryException.GeometryInternalError(); + + m_tolerance = tolerance; + double small_tolerance_sqr = MathUtils.sqr(tolerance * 0.01); + boolean bigmove = false; + + IntersectionPart part1 = m_input_segments.get(0); + IntersectionPart part2 = m_input_segments.get(1); + if (b_intersecting + || (part1.seg._isIntersecting(part2.seg, tolerance, true) & 5) != 0) { + if (part1.seg.getType().value() == Geometry.GeometryType.Line) { + Line line_1 = (Line) part1.seg; + if (part2.seg.getType().value() == Geometry.GeometryType.Line) { + Line line_2 = (Line) part2.seg; + int count = Line._intersectLineLine(line_1, line_2, null, + m_param_1, m_param_2, tolerance); + if (count == 0) { + assert (count > 0); + throw GeometryException.GeometryInternalError(); + } + Point2D[] points = new Point2D[9]; + for (int i = 0; i < count; i++) { + // For each point of intersection, we calculate a + // weighted point + // based on the ranks and weights of the endpoints and + // the interior. + double t1 = m_param_1[i]; + double t2 = m_param_2[i]; + int rank1 = part1.rank_interior; + double weight1 = 1.0; + + if (t1 == 0) { + rank1 = part1.rank_start; + weight1 = part1.weight_start; + } else if (t1 == 1.0) { + rank1 = part1.rank_end; + weight1 = part1.weight_end; + } + + int rank2 = part2.rank_interior; + double weight2 = 1.0; + if (t2 == 0) { + rank2 = part2.rank_start; + weight2 = part2.weight_start; + } else if (t2 == 1.0) { + rank2 = part2.rank_end; + weight2 = part2.weight_end; + } + + double ptWeight; + + Point2D pt = new Point2D(); + if (rank1 == rank2) {// for equal ranks use weighted sum + Point2D pt_1 = new Point2D(); + line_1.getCoord2D(t1, pt_1); + Point2D pt_2 = new Point2D(); + line_2.getCoord2D(t2, pt_2); + ptWeight = weight1 + weight2; + double t = weight2 / ptWeight; + MathUtils.lerp(pt_1, pt_2, t, pt); + if (Point2D.sqrDistance(pt, pt_1) + + Point2D.sqrDistance(pt, pt_2) > small_tolerance_sqr) + bigmove = true; + + } else {// for non-equal ranks, the higher rank wins + if (rank1 > rank2) { + line_1.getCoord2D(t1, pt); + ptWeight = weight1; + Point2D pt_2 = new Point2D(); + line_2.getCoord2D(t2, pt_2); + if (Point2D.sqrDistance(pt, pt_2) > small_tolerance_sqr) + bigmove = true; + } else { + line_2.getCoord2D(t2, pt); + ptWeight = weight2; + Point2D pt_1 = new Point2D(); + line_1.getCoord2D(t1, pt_1); + if (Point2D.sqrDistance(pt, pt_1) > small_tolerance_sqr) + bigmove = true; + } + } + points[i] = pt; + } + + // Split the line_1, making sure the endpoints are adusted + // to the weighted + double t0 = 0; + int i0 = -1; + for (int i = 0; i <= count; i++) { + double t = i < count ? m_param_1[i] : 1.0; + if (t != t0) { + SegmentBuffer seg_buffer = newSegmentBuffer_(); + line_1.cut(t0, t, seg_buffer); + if (i0 != -1) + seg_buffer.get().setStartXY(points[i0]); + if (i != count) + seg_buffer.get().setEndXY(points[i]); + + t0 = t; + m_result_segments_1 + .add(newIntersectionPart_(seg_buffer.get())); + } + i0 = i; + } + + int[] indices = new int[9]; + for (int i = 0; i < count; i++) + indices[i] = i; + + if (count > 1) { + if (m_param_2[0] > m_param_2[1]) { + double t = m_param_2[0]; + m_param_2[0] = m_param_2[1]; + m_param_2[1] = t; + int i = indices[0]; + indices[0] = indices[1]; + indices[1] = i; + } + } + + // Split the line_2 + t0 = 0; + i0 = -1; + for (int i = 0; i <= count; i++) { + double t = i < count ? m_param_2[i] : 1.0; + if (t != t0) { + SegmentBuffer seg_buffer = newSegmentBuffer_(); + line_2.cut(t0, t, seg_buffer); + if (i0 != -1) { + int ind = indices[i0]; + seg_buffer.get().setStartXY(points[ind]); + } + if (i != count) { + int ind = indices[i]; + seg_buffer.get().setEndXY(points[ind]); + } + + t0 = t; + m_result_segments_2 + .add(newIntersectionPart_(seg_buffer.get())); + } + i0 = i; + } + + return bigmove; + } + + throw GeometryException.GeometryInternalError(); + } + + throw GeometryException.GeometryInternalError(); + } + + return false; + } + + public void intersect(double tolerance, Point pt_intersector_point, + int point_rank, double point_weight, boolean b_intersecting) { + pt_intersector_point.copyTo(m_point); + if (m_input_segments.size() != 1) + throw GeometryException.GeometryInternalError(); + + m_tolerance = tolerance; + + IntersectionPart part1 = m_input_segments.get(0); + if (b_intersecting + || part1.seg._isIntersectingPoint(pt_intersector_point.getXY(), + tolerance, true)) { + if (part1.seg.getType().value() == Geometry.GeometryType.Line) { + Line line_1 = (Line) (part1.seg); + double t1 = line_1.getClosestCoordinate( + pt_intersector_point.getXY(), false); + m_param_1[0] = t1; + // For each point of intersection, we calculate a weighted point + // based on the ranks and weights of the endpoints and the + // interior. + int rank1 = part1.rank_interior; + double weight1 = 1.0; + + if (t1 == 0) { + rank1 = part1.rank_start; + weight1 = part1.weight_start; + } else if (t1 == 1.0) { + rank1 = part1.rank_end; + weight1 = part1.weight_end; + } + + int rank2 = point_rank; + double weight2 = point_weight; + + double ptWeight; + + Point2D pt = new Point2D(); + if (rank1 == rank2) {// for equal ranks use weighted sum + Point2D pt_1 = new Point2D(); + line_1.getCoord2D(t1, pt_1); + Point2D pt_2 = pt_intersector_point.getXY(); + ptWeight = weight1 + weight2; + double t = weight2 / ptWeight; + MathUtils.lerp(pt_1, pt_2, t, pt); + } else {// for non-equal ranks, the higher rank wins + if (rank1 > rank2) { + pt = new Point2D(); + line_1.getCoord2D(t1, pt); + ptWeight = weight1; + } else { + pt = pt_intersector_point.getXY(); + ptWeight = weight2; + } + } + + // Split the line_1, making sure the endpoints are adusted to + // the weighted + double t0 = 0; + int i0 = -1; + int count = 1; + for (int i = 0; i <= count; i++) { + double t = i < count ? m_param_1[i] : 1.0; + if (t != t0) { + SegmentBuffer seg_buffer = newSegmentBuffer_(); + line_1.cut(t0, t, seg_buffer); + if (i0 != -1) + seg_buffer.get().setStartXY(pt); + if (i != count) + seg_buffer.get().setEndXY(pt); + + t0 = t; + m_result_segments_1.add(newIntersectionPart_(seg_buffer + .get())); + } + i0 = i; + } + + m_point.setXY(pt); + + return; + } + + throw GeometryException.GeometryInternalError(); + } + } + + public double get_tolerance_() { + return m_tolerance; + } } diff --git a/src/main/java/com/esri/core/geometry/SegmentIterator.java b/src/main/java/com/esri/core/geometry/SegmentIterator.java index 8cb3abcb..b2f7a430 100644 --- a/src/main/java/com/esri/core/geometry/SegmentIterator.java +++ b/src/main/java/com/esri/core/geometry/SegmentIterator.java @@ -38,189 +38,189 @@ * */ public class SegmentIterator { - private SegmentIteratorImpl m_impl; - - SegmentIterator(Object obj) { - m_impl = (SegmentIteratorImpl) obj; - } - - /** - * Moves the iterator to the next path. Returns the TRUE if successful. - * - * @return TRUE if the next path exists. - */ - public boolean nextPath() { - return m_impl.nextPath(); - } - - /** - * Moves the iterator to the previous path. Returns the TRUE if successful. - * - * @return TRUE if the previous path exists. - */ - public boolean previousPath() { - return m_impl.previousPath(); - } - - /** - * Resets the iterator such that a subsequent call to NextPath will set the - * iterator to the first path. - */ - public void resetToFirstPath() { - m_impl.resetToFirstPath(); - } - - /** - * Resets the iterator such that a subsequent call to PreviousPath will set - * the iterator to the last path. - */ - public void resetToLastPath() { - m_impl.resetToLastPath(); - } - - /** - * Resets the iterator such that a subsequent call to NextPath will set the - * iterator to the given path index. A call to PreviousPath will set the - * iterator to the path at pathIndex - 1. - */ - public void resetToPath(int pathIndex) { - m_impl.resetToPath(pathIndex); - } - - /** - * Indicates whether the iterator points to the first segment in the current - * path. - * - * @return TRUE if the iterator points to the first segment in the current - * path. - */ - public boolean isFirstSegmentInPath() { - return m_impl.isFirstSegmentInPath(); - } - - /** - * Indicates whether the iterator points to the last segment in the current - * path. - * - * @return TRUE if the iterator points to the last segment in the current - * path. - */ - public boolean isLastSegmentInPath() { - return m_impl.isLastSegmentInPath(); - } - - /** - * Resets the iterator so that the call to NextSegment will return the first - * segment of the current path. - */ - public void resetToFirstSegment() { - m_impl.resetToFirstSegment(); - } - - /** - * Resets the iterator so that the call to PreviousSegment will return the - * last segment of the current path. - */ - public void resetToLastSegment() { - m_impl.resetToLastSegment(); - } - - /** - * Resets the iterator to a specific vertex. - * The call to next_segment will return the segment that starts at the vertex. - * Call to previous_segment will return the segment that starts at the previous vertex. - * - * @param vertexIndex The vertex index to reset the iterator to. - * @param pathIndex The path index to reset the iterator to. Used as a hint. If the path_index is wrong or -1, then the path_index is automatically calculated. - */ - public void resetToVertex(int vertexIndex, int pathIndex) { - m_impl.resetToVertex(vertexIndex, pathIndex); - } - - /** - * Indicates whether a next segment exists for the path. - * - * @return TRUE is the next segment exists. - */ - public boolean hasNextSegment() { - return m_impl.hasNextSegment(); - } - - /** - * Indicates whether a previous segment exists in the path. - * - * @return TRUE if the previous segment exists. - */ - public boolean hasPreviousSegment() { - return m_impl.hasPreviousSegment(); - } - - /** - * Moves the iterator to the next segment and returns the segment. - *

- * The Segment is returned by value and is owned by the iterator. - */ - public Segment nextSegment() { - return m_impl.nextSegment(); - } - - /** - * Moves the iterator to previous segment and returns the segment. - *

- * The Segment is returned by value and is owned by the iterator. - */ - public Segment previousSegment() { - return m_impl.previousSegment(); - } - - /** - * Returns the index of the current path. - */ - public int getPathIndex() { - return m_impl.getPathIndex(); - } - - /** - * Returns the index of the start point of this segment. - */ - public int getStartPointIndex() { - return m_impl.getStartPointIndex(); - } - - /** - * Returns the index of the end point of the current segment. - */ - public int getEndPointIndex() { - return m_impl.getEndPointIndex(); - } - - /** - * Returns TRUE, if the segment is the closing segment of the closed path - */ - public boolean isClosingSegment() { - return m_impl.isClosingSegment(); - } - - /** - * Switches the iterator to navigation mode. - * - * @param bYesNo If TRUE, the iterator loops over the current path infinitely - * (unless the multipath is empty). - */ - public void setCirculator(boolean bYesNo) { - m_impl.setCirculator(bYesNo); - } - - /** - * Copies this SegmentIterator. - * - * @return SegmentIterator. - */ - public Object copy() { - return new SegmentIterator(m_impl.copy()); - } - - protected Object _getImpl() { - return (SegmentIteratorImpl) m_impl; - } + private SegmentIteratorImpl m_impl; + + SegmentIterator(Object obj) { + m_impl = (SegmentIteratorImpl) obj; + } + + /** + * Moves the iterator to the next path. Returns the TRUE if successful. + * + * @return TRUE if the next path exists. + */ + public boolean nextPath() { + return m_impl.nextPath(); + } + + /** + * Moves the iterator to the previous path. Returns the TRUE if successful. + * + * @return TRUE if the previous path exists. + */ + public boolean previousPath() { + return m_impl.previousPath(); + } + + /** + * Resets the iterator such that a subsequent call to NextPath will set the + * iterator to the first path. + */ + public void resetToFirstPath() { + m_impl.resetToFirstPath(); + } + + /** + * Resets the iterator such that a subsequent call to PreviousPath will set + * the iterator to the last path. + */ + public void resetToLastPath() { + m_impl.resetToLastPath(); + } + + /** + * Resets the iterator such that a subsequent call to NextPath will set the + * iterator to the given path index. A call to PreviousPath will set the + * iterator to the path at pathIndex - 1. + */ + public void resetToPath(int pathIndex) { + m_impl.resetToPath(pathIndex); + } + + /** + * Indicates whether the iterator points to the first segment in the current + * path. + * + * @return TRUE if the iterator points to the first segment in the current + * path. + */ + public boolean isFirstSegmentInPath() { + return m_impl.isFirstSegmentInPath(); + } + + /** + * Indicates whether the iterator points to the last segment in the current + * path. + * + * @return TRUE if the iterator points to the last segment in the current + * path. + */ + public boolean isLastSegmentInPath() { + return m_impl.isLastSegmentInPath(); + } + + /** + * Resets the iterator so that the call to NextSegment will return the first + * segment of the current path. + */ + public void resetToFirstSegment() { + m_impl.resetToFirstSegment(); + } + + /** + * Resets the iterator so that the call to PreviousSegment will return the + * last segment of the current path. + */ + public void resetToLastSegment() { + m_impl.resetToLastSegment(); + } + + /** + * Resets the iterator to a specific vertex. + * The call to next_segment will return the segment that starts at the vertex. + * Call to previous_segment will return the segment that starts at the previous vertex. + * + * @param vertexIndex The vertex index to reset the iterator to. + * @param pathIndex The path index to reset the iterator to. Used as a hint. If the path_index is wrong or -1, then the path_index is automatically calculated. + */ + public void resetToVertex(int vertexIndex, int pathIndex) { + m_impl.resetToVertex(vertexIndex, pathIndex); + } + + /** + * Indicates whether a next segment exists for the path. + * + * @return TRUE is the next segment exists. + */ + public boolean hasNextSegment() { + return m_impl.hasNextSegment(); + } + + /** + * Indicates whether a previous segment exists in the path. + * + * @return TRUE if the previous segment exists. + */ + public boolean hasPreviousSegment() { + return m_impl.hasPreviousSegment(); + } + + /** + * Moves the iterator to the next segment and returns the segment. + *

+ * The Segment is returned by value and is owned by the iterator. + */ + public Segment nextSegment() { + return m_impl.nextSegment(); + } + + /** + * Moves the iterator to previous segment and returns the segment. + *

+ * The Segment is returned by value and is owned by the iterator. + */ + public Segment previousSegment() { + return m_impl.previousSegment(); + } + + /** + * Returns the index of the current path. + */ + public int getPathIndex() { + return m_impl.getPathIndex(); + } + + /** + * Returns the index of the start point of this segment. + */ + public int getStartPointIndex() { + return m_impl.getStartPointIndex(); + } + + /** + * Returns the index of the end point of the current segment. + */ + public int getEndPointIndex() { + return m_impl.getEndPointIndex(); + } + + /** + * Returns TRUE, if the segment is the closing segment of the closed path + */ + public boolean isClosingSegment() { + return m_impl.isClosingSegment(); + } + + /** + * Switches the iterator to navigation mode. + * + * @param bYesNo If TRUE, the iterator loops over the current path infinitely + * (unless the multipath is empty). + */ + public void setCirculator(boolean bYesNo) { + m_impl.setCirculator(bYesNo); + } + + /** + * Copies this SegmentIterator. + * + * @return SegmentIterator. + */ + public Object copy() { + return new SegmentIterator(m_impl.copy()); + } + + protected Object _getImpl() { + return (SegmentIteratorImpl) m_impl; + } } diff --git a/src/main/java/com/esri/core/geometry/SegmentIteratorImpl.java b/src/main/java/com/esri/core/geometry/SegmentIteratorImpl.java index 4b112335..d4580770 100644 --- a/src/main/java/com/esri/core/geometry/SegmentIteratorImpl.java +++ b/src/main/java/com/esri/core/geometry/SegmentIteratorImpl.java @@ -30,446 +30,446 @@ */ final class SegmentIteratorImpl { - protected Line m_line; - - // Bezier m_bezier: - // Arc m_arc; - protected Segment m_currentSegment; - protected Point2D m_dummyPoint; - - protected int m_currentPathIndex; - - protected int m_nextPathIndex; - - protected int m_prevPathIndex; - - protected int m_currentSegmentIndex; - - protected int m_nextSegmentIndex; - - protected int m_prevSegmentIndex; - - protected int m_segmentCount; - - protected int m_pathBegin; - - protected MultiPathImpl m_parent; // parent of the iterator. - - protected boolean m_bCirculator; // If true, the iterator circulates around - // the current Path. - - protected boolean m_bNeedsUpdate; - - public SegmentIteratorImpl(MultiPathImpl parent) { - m_currentSegmentIndex = -1; - m_nextSegmentIndex = 0; - m_nextPathIndex = 0; - m_currentPathIndex = -1; - m_parent = parent; - m_segmentCount = _getSegmentCount(m_nextPathIndex); - m_bCirculator = false; - m_currentSegment = null; - m_pathBegin = -1; - m_dummyPoint = new Point2D(); - } - - public SegmentIteratorImpl(MultiPathImpl parent, int pointIndex) { - if (pointIndex < 0 || pointIndex >= parent.getPointCount()) - throw new IndexOutOfBoundsException(); - - m_currentSegmentIndex = -1; - int path = parent.getPathIndexFromPointIndex(pointIndex); - m_nextSegmentIndex = pointIndex - parent.getPathStart(path); - - m_nextPathIndex = path + 1; - m_currentPathIndex = path; - m_parent = parent; - m_segmentCount = _getSegmentCount(m_currentPathIndex); - m_bCirculator = false; - m_currentSegment = null; - m_pathBegin = m_parent.getPathStart(m_currentPathIndex); - m_dummyPoint = new Point2D(); - } - - public SegmentIteratorImpl(MultiPathImpl parent, int pathIndex, - int segmentIndex) { - if (pathIndex < 0 || pathIndex >= parent.getPathCount() - || segmentIndex < 0) - throw new IndexOutOfBoundsException(); - - int d = parent.isClosedPath(pathIndex) ? 0 : 1; - if (segmentIndex >= parent.getPathSize(pathIndex) - d) - throw new IndexOutOfBoundsException(); - - m_currentSegmentIndex = -1; - m_nextSegmentIndex = segmentIndex; - m_currentPathIndex = pathIndex; - m_nextPathIndex = m_nextSegmentIndex + 1; - m_parent = parent; - m_segmentCount = _getSegmentCount(m_nextPathIndex); - m_bCirculator = false; - m_currentSegment = null; - m_pathBegin = m_parent.getPathStart(m_currentPathIndex); - m_dummyPoint = new Point2D(); - } - - void resetTo(SegmentIteratorImpl src) { - if (m_parent != src.m_parent) - throw new GeometryException("invalid_call"); - - m_currentSegmentIndex = src.m_currentSegmentIndex; - m_nextSegmentIndex = src.m_nextSegmentIndex; - m_currentPathIndex = src.m_currentPathIndex; - m_nextPathIndex = src.m_nextPathIndex; - m_segmentCount = src.m_segmentCount; - m_bCirculator = src.m_bCirculator; - m_pathBegin = src.m_pathBegin; - m_currentSegment = null; - } - - /** - * Moves the iterator to the next curve segment and returns the segment. - *

- * The Segment is returned by value and is owned by the iterator. Note: The - * method can return null if there are no curves in the part. - */ - public Segment nextCurve() { - return null; - // TODO: Fix me. This method is supposed to go only through the curves - // and skip the Line classes!! - // It must be very efficient. - } - - /** - * Moves the iterator to next segment and returns the segment. - *

- * The Segment is returned by value and is owned by the iterator. - */ - public Segment nextSegment() { - if (m_currentSegmentIndex != m_nextSegmentIndex) - _updateSegment(); - - if (m_bCirculator) { - m_nextSegmentIndex = (m_nextSegmentIndex + 1) % m_segmentCount; - } else { - if (m_nextSegmentIndex == m_segmentCount) - throw new IndexOutOfBoundsException(); - - m_nextSegmentIndex++; - } - - return m_currentSegment; - } - - /** - * Moves the iterator to previous segment and returns the segment. - *

- * The Segment is returned by value and is owned by the iterator. - */ - public Segment previousSegment() { - if (m_bCirculator) { - m_nextSegmentIndex = (m_segmentCount + m_nextSegmentIndex - 1) - % m_segmentCount; - } else { - if (m_nextSegmentIndex == 0) - throw new IndexOutOfBoundsException(); - m_nextSegmentIndex--; - } - - if (m_nextSegmentIndex != m_currentSegmentIndex) - _updateSegment(); - - return m_currentSegment; - } - - /** - * Resets the iterator so that the call to NextSegment will return the first - * segment of the current path. - */ - public void resetToFirstSegment() { - m_currentSegmentIndex = -1; - m_nextSegmentIndex = 0; - } - - /** - * Resets the iterator so that the call to PreviousSegment will return the - * last segment of the current path. - */ - public void resetToLastSegment() { - m_nextSegmentIndex = m_segmentCount; - m_currentSegmentIndex = -1; - } - - public void resetToVertex(int vertexIndex) { - resetToVertex(vertexIndex, -1); - } - - public void resetToVertex(int vertexIndex, int _pathIndex) { - if (m_currentPathIndex >= 0 - && m_currentPathIndex < m_parent.getPathCount()) {// check if we - // are in - // the - // current - // path - int start = _getPathBegin(); - if (vertexIndex >= start - && vertexIndex < m_parent.getPathEnd(m_currentPathIndex)) { - m_currentSegmentIndex = -1; - m_nextSegmentIndex = vertexIndex - start; - return; - } - } - - int path_index; - if (_pathIndex >= 0 && _pathIndex < m_parent.getPathCount() - && vertexIndex >= m_parent.getPathStart(_pathIndex) - && vertexIndex < m_parent.getPathEnd(_pathIndex)) { - path_index = _pathIndex; - } else { - path_index = m_parent.getPathIndexFromPointIndex(vertexIndex); - } - - m_nextPathIndex = path_index + 1; - m_currentPathIndex = path_index; - m_currentSegmentIndex = -1; - m_nextSegmentIndex = vertexIndex - m_parent.getPathStart(path_index); - m_segmentCount = _getSegmentCount(path_index); - m_pathBegin = m_parent.getPathStart(m_currentPathIndex); - } - - /** - * Moves the iterator to next path and returns true if successful. - */ - public boolean nextPath() { - // post-increment - m_currentPathIndex = m_nextPathIndex; - if (m_currentPathIndex >= m_parent.getPathCount()) - return false; - - m_currentSegmentIndex = -1; - m_nextSegmentIndex = 0; - m_segmentCount = _getSegmentCount(m_currentPathIndex); - m_pathBegin = m_parent.getPathStart(m_currentPathIndex); - m_nextPathIndex++; - return true; - } - - /** - * Moves the iterator to next path and returns true if successful. - */ - public boolean previousPath() { - // pre-decrement - if (m_nextPathIndex == 0) - return false; - - m_nextPathIndex--; - m_currentSegmentIndex = -1; - m_nextSegmentIndex = 0; - m_segmentCount = _getSegmentCount(m_nextPathIndex); - m_currentPathIndex = m_nextPathIndex; - m_pathBegin = m_parent.getPathStart(m_currentPathIndex); - resetToLastSegment(); - return true; - } - - /** - * Resets the iterator such that the subsequent call to the NextPath will - * set the iterator to the first segment of the first path. - */ - public void resetToFirstPath() { - - m_currentSegmentIndex = -1; - m_nextSegmentIndex = -1; - m_segmentCount = -1; - m_nextPathIndex = 0; - m_currentPathIndex = -1; - m_pathBegin = -1; - } - - /** - * Resets the iterator such that the subsequent call to the PreviousPath - * will set the iterator to the last segment of the last path. - */ - public void resetToLastPath() { - m_nextPathIndex = m_parent.getPathCount(); - m_currentPathIndex = -1; - m_currentSegmentIndex = -1; - m_nextSegmentIndex = -1; - m_segmentCount = -1; - m_pathBegin = -1; - } - - /** - * Resets the iterator such that the subsequent call to the NextPath will - * set the iterator to the first segment of the given path. The call to - * PreviousPath will reset the iterator to the last segment of path - * pathIndex - 1. - */ - public void resetToPath(int pathIndex) { - if (pathIndex < 0) - throw new IndexOutOfBoundsException(); - - m_nextPathIndex = pathIndex; - m_currentPathIndex = -1; - m_currentSegmentIndex = -1; - m_nextSegmentIndex = -1; - m_segmentCount = -1; - m_pathBegin = -1; - } - - public int _getSegmentCount(int pathIndex) { - if (m_parent.isEmptyImpl()) - return 0; - - int d = 1; - if (m_parent.isClosedPath(pathIndex)) - d = 0; - - return m_parent.getPathSize(pathIndex) - d; - } - - /** - * Returns True, if the segment is the closing segment of the closed path - */ - public boolean isClosingSegment() { - return m_currentSegmentIndex == m_segmentCount - 1 - && m_parent.isClosedPath(m_currentPathIndex); - } - - /** - * Switches the iterator navigation mode. - * - * @param bYesNo If True, the iterator loops over the current path infinitely - * (unless the MultiPath is empty). - */ - public void setCirculator(boolean bYesNo) { - m_bCirculator = bYesNo; - } - - /** - * Returns the index of the current path. - */ - public int getPathIndex() { - return m_currentPathIndex; - } - - /** - * Returns the index of the start Point of the current Segment. - */ - public int getStartPointIndex() { - return _getPathBegin() + m_currentSegmentIndex; - } - - public int _getPathBegin() { - return m_parent.getPathStart(m_currentPathIndex); - } - - /** - * Returns the index of the end Point of the current Segment. - */ - public int getEndPointIndex() { - if (isClosingSegment()) { - return m_parent.getPathStart(m_currentPathIndex); - } else { - return getStartPointIndex() + 1; - } - } - - /** - * Returns True if the segment is first one in the current Path. - */ - public boolean isFirstSegmentInPath() { - return m_currentSegmentIndex == 0; - } - - /** - * Returns True if the segment is last one in the current Path. - */ - public boolean isLastSegmentInPath() { - return m_currentSegmentIndex == m_segmentCount - 1; - } - - /** - * Returns True if the call to the NextSegment will succeed. - */ - public boolean hasNextSegment() { - return m_nextSegmentIndex < m_segmentCount; - } - - /** - * Returns True if the call to the NextSegment will succeed. - */ - public boolean hasPreviousSegment() { - return m_nextSegmentIndex > 0; - } - - public SegmentIteratorImpl copy() { - SegmentIteratorImpl clone = new SegmentIteratorImpl(m_parent); - clone.m_currentSegmentIndex = m_currentSegmentIndex; - clone.m_nextSegmentIndex = m_nextSegmentIndex; - clone.m_segmentCount = m_segmentCount; - clone.m_currentPathIndex = m_currentPathIndex; - clone.m_nextPathIndex = m_nextPathIndex; - clone.m_parent = m_parent; - clone.m_bCirculator = m_bCirculator; - return clone; - } - - public void _updateSegment() { - if (m_nextSegmentIndex < 0 || m_nextSegmentIndex >= m_segmentCount) - throw new IndexOutOfBoundsException(); - m_currentSegmentIndex = m_nextSegmentIndex; - - int startVertexIndex = getStartPointIndex(); - m_parent._verifyAllStreams(); - AttributeStreamOfInt8 segFlagStream = m_parent - .getSegmentFlagsStreamRef(); - - int segFlag = SegmentFlags.enumLineSeg; - if (segFlagStream != null) - segFlag = (segFlagStream.read(startVertexIndex) & SegmentFlags.enumSegmentMask); - - VertexDescription vertexDescr = m_parent.getDescription(); - switch (segFlag) { - case SegmentFlags.enumLineSeg: - if (m_line == null) - m_line = new Line(); - m_currentSegment = (Line) m_line; - break; - case SegmentFlags.enumBezierSeg: - throw GeometryException.GeometryInternalError(); - // break; - case SegmentFlags.enumArcSeg: - throw GeometryException.GeometryInternalError(); - // break; - default: - throw GeometryException.GeometryInternalError(); - } - - m_currentSegment.assignVertexDescription(vertexDescr); - - int endVertexIndex = getEndPointIndex(); - m_parent.getXY(startVertexIndex, m_dummyPoint); - m_currentSegment.setStartXY(m_dummyPoint); - m_parent.getXY(endVertexIndex, m_dummyPoint); - m_currentSegment.setEndXY(m_dummyPoint); - - for (int i = 1, nattr = vertexDescr.getAttributeCount(); i < nattr; i++) { - int semantics = vertexDescr.getSemantics(i); - int ncomp = VertexDescription.getComponentCount(semantics); - for (int ord = 0; ord < ncomp; ord++) { - double vs = m_parent.getAttributeAsDbl(semantics, - startVertexIndex, ord); - m_currentSegment.setStartAttribute(semantics, ord, vs); - double ve = m_parent.getAttributeAsDbl(semantics, - endVertexIndex, ord); - m_currentSegment.setEndAttribute(semantics, ord, ve); - } - } - } - - boolean isLastPath() { - return m_currentPathIndex == m_parent.getPathCount() - 1; - } + protected Line m_line; + + // Bezier m_bezier: + // Arc m_arc; + protected Segment m_currentSegment; + protected Point2D m_dummyPoint; + + protected int m_currentPathIndex; + + protected int m_nextPathIndex; + + protected int m_prevPathIndex; + + protected int m_currentSegmentIndex; + + protected int m_nextSegmentIndex; + + protected int m_prevSegmentIndex; + + protected int m_segmentCount; + + protected int m_pathBegin; + + protected MultiPathImpl m_parent; // parent of the iterator. + + protected boolean m_bCirculator; // If true, the iterator circulates around + // the current Path. + + protected boolean m_bNeedsUpdate; + + public SegmentIteratorImpl(MultiPathImpl parent) { + m_currentSegmentIndex = -1; + m_nextSegmentIndex = 0; + m_nextPathIndex = 0; + m_currentPathIndex = -1; + m_parent = parent; + m_segmentCount = _getSegmentCount(m_nextPathIndex); + m_bCirculator = false; + m_currentSegment = null; + m_pathBegin = -1; + m_dummyPoint = new Point2D(); + } + + public SegmentIteratorImpl(MultiPathImpl parent, int pointIndex) { + if (pointIndex < 0 || pointIndex >= parent.getPointCount()) + throw new IndexOutOfBoundsException(); + + m_currentSegmentIndex = -1; + int path = parent.getPathIndexFromPointIndex(pointIndex); + m_nextSegmentIndex = pointIndex - parent.getPathStart(path); + + m_nextPathIndex = path + 1; + m_currentPathIndex = path; + m_parent = parent; + m_segmentCount = _getSegmentCount(m_currentPathIndex); + m_bCirculator = false; + m_currentSegment = null; + m_pathBegin = m_parent.getPathStart(m_currentPathIndex); + m_dummyPoint = new Point2D(); + } + + public SegmentIteratorImpl(MultiPathImpl parent, int pathIndex, + int segmentIndex) { + if (pathIndex < 0 || pathIndex >= parent.getPathCount() + || segmentIndex < 0) + throw new IndexOutOfBoundsException(); + + int d = parent.isClosedPath(pathIndex) ? 0 : 1; + if (segmentIndex >= parent.getPathSize(pathIndex) - d) + throw new IndexOutOfBoundsException(); + + m_currentSegmentIndex = -1; + m_nextSegmentIndex = segmentIndex; + m_currentPathIndex = pathIndex; + m_nextPathIndex = m_nextSegmentIndex + 1; + m_parent = parent; + m_segmentCount = _getSegmentCount(m_nextPathIndex); + m_bCirculator = false; + m_currentSegment = null; + m_pathBegin = m_parent.getPathStart(m_currentPathIndex); + m_dummyPoint = new Point2D(); + } + + void resetTo(SegmentIteratorImpl src) { + if (m_parent != src.m_parent) + throw new GeometryException("invalid_call"); + + m_currentSegmentIndex = src.m_currentSegmentIndex; + m_nextSegmentIndex = src.m_nextSegmentIndex; + m_currentPathIndex = src.m_currentPathIndex; + m_nextPathIndex = src.m_nextPathIndex; + m_segmentCount = src.m_segmentCount; + m_bCirculator = src.m_bCirculator; + m_pathBegin = src.m_pathBegin; + m_currentSegment = null; + } + + /** + * Moves the iterator to the next curve segment and returns the segment. + *

+ * The Segment is returned by value and is owned by the iterator. Note: The + * method can return null if there are no curves in the part. + */ + public Segment nextCurve() { + return null; + // TODO: Fix me. This method is supposed to go only through the curves + // and skip the Line classes!! + // It must be very efficient. + } + + /** + * Moves the iterator to next segment and returns the segment. + *

+ * The Segment is returned by value and is owned by the iterator. + */ + public Segment nextSegment() { + if (m_currentSegmentIndex != m_nextSegmentIndex) + _updateSegment(); + + if (m_bCirculator) { + m_nextSegmentIndex = (m_nextSegmentIndex + 1) % m_segmentCount; + } else { + if (m_nextSegmentIndex == m_segmentCount) + throw new IndexOutOfBoundsException(); + + m_nextSegmentIndex++; + } + + return m_currentSegment; + } + + /** + * Moves the iterator to previous segment and returns the segment. + *

+ * The Segment is returned by value and is owned by the iterator. + */ + public Segment previousSegment() { + if (m_bCirculator) { + m_nextSegmentIndex = (m_segmentCount + m_nextSegmentIndex - 1) + % m_segmentCount; + } else { + if (m_nextSegmentIndex == 0) + throw new IndexOutOfBoundsException(); + m_nextSegmentIndex--; + } + + if (m_nextSegmentIndex != m_currentSegmentIndex) + _updateSegment(); + + return m_currentSegment; + } + + /** + * Resets the iterator so that the call to NextSegment will return the first + * segment of the current path. + */ + public void resetToFirstSegment() { + m_currentSegmentIndex = -1; + m_nextSegmentIndex = 0; + } + + /** + * Resets the iterator so that the call to PreviousSegment will return the + * last segment of the current path. + */ + public void resetToLastSegment() { + m_nextSegmentIndex = m_segmentCount; + m_currentSegmentIndex = -1; + } + + public void resetToVertex(int vertexIndex) { + resetToVertex(vertexIndex, -1); + } + + public void resetToVertex(int vertexIndex, int _pathIndex) { + if (m_currentPathIndex >= 0 + && m_currentPathIndex < m_parent.getPathCount()) {// check if we + // are in + // the + // current + // path + int start = _getPathBegin(); + if (vertexIndex >= start + && vertexIndex < m_parent.getPathEnd(m_currentPathIndex)) { + m_currentSegmentIndex = -1; + m_nextSegmentIndex = vertexIndex - start; + return; + } + } + + int path_index; + if (_pathIndex >= 0 && _pathIndex < m_parent.getPathCount() + && vertexIndex >= m_parent.getPathStart(_pathIndex) + && vertexIndex < m_parent.getPathEnd(_pathIndex)) { + path_index = _pathIndex; + } else { + path_index = m_parent.getPathIndexFromPointIndex(vertexIndex); + } + + m_nextPathIndex = path_index + 1; + m_currentPathIndex = path_index; + m_currentSegmentIndex = -1; + m_nextSegmentIndex = vertexIndex - m_parent.getPathStart(path_index); + m_segmentCount = _getSegmentCount(path_index); + m_pathBegin = m_parent.getPathStart(m_currentPathIndex); + } + + /** + * Moves the iterator to next path and returns true if successful. + */ + public boolean nextPath() { + // post-increment + m_currentPathIndex = m_nextPathIndex; + if (m_currentPathIndex >= m_parent.getPathCount()) + return false; + + m_currentSegmentIndex = -1; + m_nextSegmentIndex = 0; + m_segmentCount = _getSegmentCount(m_currentPathIndex); + m_pathBegin = m_parent.getPathStart(m_currentPathIndex); + m_nextPathIndex++; + return true; + } + + /** + * Moves the iterator to next path and returns true if successful. + */ + public boolean previousPath() { + // pre-decrement + if (m_nextPathIndex == 0) + return false; + + m_nextPathIndex--; + m_currentSegmentIndex = -1; + m_nextSegmentIndex = 0; + m_segmentCount = _getSegmentCount(m_nextPathIndex); + m_currentPathIndex = m_nextPathIndex; + m_pathBegin = m_parent.getPathStart(m_currentPathIndex); + resetToLastSegment(); + return true; + } + + /** + * Resets the iterator such that the subsequent call to the NextPath will + * set the iterator to the first segment of the first path. + */ + public void resetToFirstPath() { + + m_currentSegmentIndex = -1; + m_nextSegmentIndex = -1; + m_segmentCount = -1; + m_nextPathIndex = 0; + m_currentPathIndex = -1; + m_pathBegin = -1; + } + + /** + * Resets the iterator such that the subsequent call to the PreviousPath + * will set the iterator to the last segment of the last path. + */ + public void resetToLastPath() { + m_nextPathIndex = m_parent.getPathCount(); + m_currentPathIndex = -1; + m_currentSegmentIndex = -1; + m_nextSegmentIndex = -1; + m_segmentCount = -1; + m_pathBegin = -1; + } + + /** + * Resets the iterator such that the subsequent call to the NextPath will + * set the iterator to the first segment of the given path. The call to + * PreviousPath will reset the iterator to the last segment of path + * pathIndex - 1. + */ + public void resetToPath(int pathIndex) { + if (pathIndex < 0) + throw new IndexOutOfBoundsException(); + + m_nextPathIndex = pathIndex; + m_currentPathIndex = -1; + m_currentSegmentIndex = -1; + m_nextSegmentIndex = -1; + m_segmentCount = -1; + m_pathBegin = -1; + } + + public int _getSegmentCount(int pathIndex) { + if (m_parent.isEmptyImpl()) + return 0; + + int d = 1; + if (m_parent.isClosedPath(pathIndex)) + d = 0; + + return m_parent.getPathSize(pathIndex) - d; + } + + /** + * Returns True, if the segment is the closing segment of the closed path + */ + public boolean isClosingSegment() { + return m_currentSegmentIndex == m_segmentCount - 1 + && m_parent.isClosedPath(m_currentPathIndex); + } + + /** + * Switches the iterator navigation mode. + * + * @param bYesNo If True, the iterator loops over the current path infinitely + * (unless the MultiPath is empty). + */ + public void setCirculator(boolean bYesNo) { + m_bCirculator = bYesNo; + } + + /** + * Returns the index of the current path. + */ + public int getPathIndex() { + return m_currentPathIndex; + } + + /** + * Returns the index of the start Point of the current Segment. + */ + public int getStartPointIndex() { + return _getPathBegin() + m_currentSegmentIndex; + } + + public int _getPathBegin() { + return m_parent.getPathStart(m_currentPathIndex); + } + + /** + * Returns the index of the end Point of the current Segment. + */ + public int getEndPointIndex() { + if (isClosingSegment()) { + return m_parent.getPathStart(m_currentPathIndex); + } else { + return getStartPointIndex() + 1; + } + } + + /** + * Returns True if the segment is first one in the current Path. + */ + public boolean isFirstSegmentInPath() { + return m_currentSegmentIndex == 0; + } + + /** + * Returns True if the segment is last one in the current Path. + */ + public boolean isLastSegmentInPath() { + return m_currentSegmentIndex == m_segmentCount - 1; + } + + /** + * Returns True if the call to the NextSegment will succeed. + */ + public boolean hasNextSegment() { + return m_nextSegmentIndex < m_segmentCount; + } + + /** + * Returns True if the call to the NextSegment will succeed. + */ + public boolean hasPreviousSegment() { + return m_nextSegmentIndex > 0; + } + + public SegmentIteratorImpl copy() { + SegmentIteratorImpl clone = new SegmentIteratorImpl(m_parent); + clone.m_currentSegmentIndex = m_currentSegmentIndex; + clone.m_nextSegmentIndex = m_nextSegmentIndex; + clone.m_segmentCount = m_segmentCount; + clone.m_currentPathIndex = m_currentPathIndex; + clone.m_nextPathIndex = m_nextPathIndex; + clone.m_parent = m_parent; + clone.m_bCirculator = m_bCirculator; + return clone; + } + + public void _updateSegment() { + if (m_nextSegmentIndex < 0 || m_nextSegmentIndex >= m_segmentCount) + throw new IndexOutOfBoundsException(); + m_currentSegmentIndex = m_nextSegmentIndex; + + int startVertexIndex = getStartPointIndex(); + m_parent._verifyAllStreams(); + AttributeStreamOfInt8 segFlagStream = m_parent + .getSegmentFlagsStreamRef(); + + int segFlag = SegmentFlags.enumLineSeg; + if (segFlagStream != null) + segFlag = (segFlagStream.read(startVertexIndex) & SegmentFlags.enumSegmentMask); + + VertexDescription vertexDescr = m_parent.getDescription(); + switch (segFlag) { + case SegmentFlags.enumLineSeg: + if (m_line == null) + m_line = new Line(); + m_currentSegment = (Line) m_line; + break; + case SegmentFlags.enumBezierSeg: + throw GeometryException.GeometryInternalError(); + // break; + case SegmentFlags.enumArcSeg: + throw GeometryException.GeometryInternalError(); + // break; + default: + throw GeometryException.GeometryInternalError(); + } + + m_currentSegment.assignVertexDescription(vertexDescr); + + int endVertexIndex = getEndPointIndex(); + m_parent.getXY(startVertexIndex, m_dummyPoint); + m_currentSegment.setStartXY(m_dummyPoint); + m_parent.getXY(endVertexIndex, m_dummyPoint); + m_currentSegment.setEndXY(m_dummyPoint); + + for (int i = 1, nattr = vertexDescr.getAttributeCount(); i < nattr; i++) { + int semantics = vertexDescr.getSemantics(i); + int ncomp = VertexDescription.getComponentCount(semantics); + for (int ord = 0; ord < ncomp; ord++) { + double vs = m_parent.getAttributeAsDbl(semantics, + startVertexIndex, ord); + m_currentSegment.setStartAttribute(semantics, ord, vs); + double ve = m_parent.getAttributeAsDbl(semantics, + endVertexIndex, ord); + m_currentSegment.setEndAttribute(semantics, ord, ve); + } + } + } + + boolean isLastPath() { + return m_currentPathIndex == m_parent.getPathCount() - 1; + } } diff --git a/src/main/java/com/esri/core/geometry/ShapeExportFlags.java b/src/main/java/com/esri/core/geometry/ShapeExportFlags.java index 92a0f5fe..cbf69bc4 100644 --- a/src/main/java/com/esri/core/geometry/ShapeExportFlags.java +++ b/src/main/java/com/esri/core/geometry/ShapeExportFlags.java @@ -28,17 +28,17 @@ * Flags used by the OperatorExportToEsriShape. */ public interface ShapeExportFlags { - public static final int ShapeExportDefaults = 0;//! m_ids; - private ArrayDeque m_byteBufferDeque; - private ArrayDeque m_simpleStates; - private ArrayDeque m_featureIDs; - private long m_current_id = -1; - private SimpleStateEnum m_currentSimpleState = SimpleStateEnum.SIMPLE_UNKNOWN; - private String m_currentFeatureID = ""; - - @Deprecated - public SimpleByteBufferCursor(ByteBuffer byteBuffer) { - m_byteBufferDeque = new ArrayDeque<>(); - m_byteBufferDeque.add(byteBuffer); - } - - public SimpleByteBufferCursor(ByteBuffer byteBuffer, long id) { - m_byteBufferDeque = new ArrayDeque<>(1); - m_byteBufferDeque.add(byteBuffer); - m_ids = new ArrayDeque<>(1); - m_ids.push(id); - } - - public SimpleByteBufferCursor(ByteBuffer byteBuffer, long id, SimpleStateEnum simpleState) { - m_byteBufferDeque = new ArrayDeque<>(1); - m_byteBufferDeque.add(byteBuffer); - m_ids = new ArrayDeque<>(1); - m_ids.push(id); - m_simpleStates = new ArrayDeque<>(1); - m_simpleStates.push(simpleState); - } - - public SimpleByteBufferCursor(ByteBuffer byteBuffer, long id, SimpleStateEnum simpleState, String featureID) { - m_byteBufferDeque = new ArrayDeque<>(1); - m_byteBufferDeque.add(byteBuffer); - m_ids = new ArrayDeque<>(1); - m_ids.push(id); - m_simpleStates = new ArrayDeque<>(1); - m_simpleStates.push(simpleState); - m_featureIDs = new ArrayDeque<>(1); - m_featureIDs.push(featureID); - } - - @Deprecated - public SimpleByteBufferCursor(ByteBuffer[] byteBufferArray) { - m_byteBufferDeque = Arrays.stream(byteBufferArray).collect(Collectors.toCollection(ArrayDeque::new)); - } - - @Deprecated - public SimpleByteBufferCursor(List byteBufferArray) { - m_byteBufferDeque = new ArrayDeque<>(byteBufferArray); - } - - public SimpleByteBufferCursor(ArrayDeque byteBufferArrayDeque, ArrayDeque ids) { - m_byteBufferDeque = byteBufferArrayDeque; - m_ids = ids; - } - - public SimpleByteBufferCursor(ArrayDeque arrayDeque, - ArrayDeque ids, - ArrayDeque simpleStates, - ArrayDeque featureIDs) { - if ((arrayDeque.size() & ids.size() & simpleStates.size() & featureIDs.size()) != arrayDeque.size()) { - throw new GeometryException("arrays must be same size"); - } - m_byteBufferDeque = arrayDeque; - m_ids = ids; - m_simpleStates = simpleStates; - m_featureIDs = featureIDs; - } - - @Override - public boolean hasNext() { - return m_byteBufferDeque.size() > 0; - } - - @Override - public long getByteBufferID() { - return m_current_id; - } - - @Override - public SimpleStateEnum getSimpleState() { - return m_currentSimpleState; - } - - @Override - public String getFeatureID() { return m_currentFeatureID; } - - void _incrementInternals() { - if (m_ids != null && !m_ids.isEmpty()) { - m_current_id = m_ids.pop(); - } else { - m_current_id++; - } - - if (m_simpleStates != null && !m_simpleStates.isEmpty()) { - m_currentSimpleState = m_simpleStates.pop(); - } - if (m_featureIDs != null && !m_featureIDs.isEmpty()) { - m_currentFeatureID = m_featureIDs.pop(); - } - } - - @Override - public ByteBuffer next() { - if (hasNext()) { - _incrementInternals(); - return m_byteBufferDeque.pop(); - } - - return null; - } + private ArrayDeque m_ids; + private ArrayDeque m_byteBufferDeque; + private ArrayDeque m_simpleStates; + private ArrayDeque m_featureIDs; + private long m_current_id = -1; + private SimpleStateEnum m_currentSimpleState = SimpleStateEnum.SIMPLE_UNKNOWN; + private String m_currentFeatureID = ""; + + @Deprecated + public SimpleByteBufferCursor(ByteBuffer byteBuffer) { + m_byteBufferDeque = new ArrayDeque<>(); + m_byteBufferDeque.add(byteBuffer); + } + + public SimpleByteBufferCursor(ByteBuffer byteBuffer, long id) { + m_byteBufferDeque = new ArrayDeque<>(1); + m_byteBufferDeque.add(byteBuffer); + m_ids = new ArrayDeque<>(1); + m_ids.push(id); + } + + public SimpleByteBufferCursor(ByteBuffer byteBuffer, long id, SimpleStateEnum simpleState) { + m_byteBufferDeque = new ArrayDeque<>(1); + m_byteBufferDeque.add(byteBuffer); + m_ids = new ArrayDeque<>(1); + m_ids.push(id); + m_simpleStates = new ArrayDeque<>(1); + m_simpleStates.push(simpleState); + } + + public SimpleByteBufferCursor(ByteBuffer byteBuffer, long id, SimpleStateEnum simpleState, String featureID) { + m_byteBufferDeque = new ArrayDeque<>(1); + m_byteBufferDeque.add(byteBuffer); + m_ids = new ArrayDeque<>(1); + m_ids.push(id); + m_simpleStates = new ArrayDeque<>(1); + m_simpleStates.push(simpleState); + m_featureIDs = new ArrayDeque<>(1); + m_featureIDs.push(featureID); + } + + @Deprecated + public SimpleByteBufferCursor(ByteBuffer[] byteBufferArray) { + m_byteBufferDeque = Arrays.stream(byteBufferArray).collect(Collectors.toCollection(ArrayDeque::new)); + } + + @Deprecated + public SimpleByteBufferCursor(List byteBufferArray) { + m_byteBufferDeque = new ArrayDeque<>(byteBufferArray); + } + + public SimpleByteBufferCursor(ArrayDeque byteBufferArrayDeque, ArrayDeque ids) { + m_byteBufferDeque = byteBufferArrayDeque; + m_ids = ids; + } + + public SimpleByteBufferCursor(ArrayDeque arrayDeque, + ArrayDeque ids, + ArrayDeque simpleStates, + ArrayDeque featureIDs) { + if ((arrayDeque.size() & ids.size() & simpleStates.size() & featureIDs.size()) != arrayDeque.size()) { + throw new GeometryException("arrays must be same size"); + } + m_byteBufferDeque = arrayDeque; + m_ids = ids; + m_simpleStates = simpleStates; + m_featureIDs = featureIDs; + } + + @Override + public boolean hasNext() { + return m_byteBufferDeque.size() > 0; + } + + @Override + public long getByteBufferID() { + return m_current_id; + } + + @Override + public SimpleStateEnum getSimpleState() { + return m_currentSimpleState; + } + + @Override + public String getFeatureID() { + return m_currentFeatureID; + } + + void _incrementInternals() { + if (m_ids != null && !m_ids.isEmpty()) { + m_current_id = m_ids.pop(); + } else { + m_current_id++; + } + + if (m_simpleStates != null && !m_simpleStates.isEmpty()) { + m_currentSimpleState = m_simpleStates.pop(); + } + if (m_featureIDs != null && !m_featureIDs.isEmpty()) { + m_currentFeatureID = m_featureIDs.pop(); + } + } + + @Override + public ByteBuffer next() { + if (hasNext()) { + _incrementInternals(); + return m_byteBufferDeque.pop(); + } + + return null; + } } diff --git a/src/main/java/com/esri/core/geometry/SimpleGeometryCursor.java b/src/main/java/com/esri/core/geometry/SimpleGeometryCursor.java index 5a5d7102..33f740cc 100644 --- a/src/main/java/com/esri/core/geometry/SimpleGeometryCursor.java +++ b/src/main/java/com/esri/core/geometry/SimpleGeometryCursor.java @@ -32,70 +32,74 @@ */ public class SimpleGeometryCursor extends GeometryCursor { - private long m_index = -1; - private String m_currentFeatureId = ""; - private SimpleStateEnum m_simpleState = SimpleStateEnum.SIMPLE_UNKNOWN; - private MapGeometryCursor m_mapGeometryCursor = null; - private ArrayDeque m_geometryDeque = null; - - private long m_current_id = -1; - - public SimpleGeometryCursor(Geometry geom) { - m_geometryDeque = new ArrayDeque<>(1); - m_geometryDeque.add(geom); - } - - public SimpleGeometryCursor(Geometry[] geoms) { - m_geometryDeque = Arrays.stream(geoms).collect(Collectors.toCollection(ArrayDeque::new)); - } - - @Deprecated - public SimpleGeometryCursor(List geoms) { - m_geometryDeque = new ArrayDeque<>(geoms); - } - - public SimpleGeometryCursor(ArrayDeque geoms) { - m_geometryDeque = geoms; - } - - public SimpleGeometryCursor(MapGeometryCursor mapGeometryCursor) { - m_mapGeometryCursor = mapGeometryCursor; - } - - @Override - public boolean hasNext() { - return (m_geometryDeque != null && m_geometryDeque.size() > 0) || (m_mapGeometryCursor != null && m_mapGeometryCursor.hasNext()); - } - - @Override - public long getGeometryID() { - return m_current_id; - } - - @Override - public SimpleStateEnum getSimpleState() { return m_simpleState; } - - @Override - public String getFeatureID() { return m_currentFeatureId; } - - @Override - public Geometry next() { - m_index++; - Geometry geometry = null; - if (m_geometryDeque != null && !m_geometryDeque.isEmpty()) { - geometry = m_geometryDeque.pop(); - - // TODO get id off of geometry if exists - m_current_id = m_index; - m_simpleState = geometry.getSimpleState(); - } else if (m_mapGeometryCursor != null && m_mapGeometryCursor.hasNext()) { - geometry = m_mapGeometryCursor.next().m_geometry; - - // TODO get id off of geometry if exists - m_current_id = m_mapGeometryCursor.getGeometryID(); - m_simpleState = m_mapGeometryCursor.getSimpleState(); - } - - return geometry; - } + private long m_index = -1; + private String m_currentFeatureId = ""; + private SimpleStateEnum m_simpleState = SimpleStateEnum.SIMPLE_UNKNOWN; + private MapGeometryCursor m_mapGeometryCursor = null; + private ArrayDeque m_geometryDeque = null; + + private long m_current_id = -1; + + public SimpleGeometryCursor(Geometry geom) { + m_geometryDeque = new ArrayDeque<>(1); + m_geometryDeque.add(geom); + } + + public SimpleGeometryCursor(Geometry[] geoms) { + m_geometryDeque = Arrays.stream(geoms).collect(Collectors.toCollection(ArrayDeque::new)); + } + + @Deprecated + public SimpleGeometryCursor(List geoms) { + m_geometryDeque = new ArrayDeque<>(geoms); + } + + public SimpleGeometryCursor(ArrayDeque geoms) { + m_geometryDeque = geoms; + } + + public SimpleGeometryCursor(MapGeometryCursor mapGeometryCursor) { + m_mapGeometryCursor = mapGeometryCursor; + } + + @Override + public boolean hasNext() { + return (m_geometryDeque != null && m_geometryDeque.size() > 0) || (m_mapGeometryCursor != null && m_mapGeometryCursor.hasNext()); + } + + @Override + public long getGeometryID() { + return m_current_id; + } + + @Override + public SimpleStateEnum getSimpleState() { + return m_simpleState; + } + + @Override + public String getFeatureID() { + return m_currentFeatureId; + } + + @Override + public Geometry next() { + m_index++; + Geometry geometry = null; + if (m_geometryDeque != null && !m_geometryDeque.isEmpty()) { + geometry = m_geometryDeque.pop(); + + // TODO get id off of geometry if exists + m_current_id = m_index; + m_simpleState = geometry.getSimpleState(); + } else if (m_mapGeometryCursor != null && m_mapGeometryCursor.hasNext()) { + geometry = m_mapGeometryCursor.next().m_geometry; + + // TODO get id off of geometry if exists + m_current_id = m_mapGeometryCursor.getGeometryID(); + m_simpleState = m_mapGeometryCursor.getSimpleState(); + } + + return geometry; + } } diff --git a/src/main/java/com/esri/core/geometry/SimpleJsonCursor.java b/src/main/java/com/esri/core/geometry/SimpleJsonCursor.java index 1fb5dd26..1af987a9 100644 --- a/src/main/java/com/esri/core/geometry/SimpleJsonCursor.java +++ b/src/main/java/com/esri/core/geometry/SimpleJsonCursor.java @@ -25,38 +25,38 @@ class SimpleJsonCursor extends JsonCursor { - String m_jsonString; - String[] m_jsonStringArray; - - int m_index; - int m_count; - - public SimpleJsonCursor(String jsonString) { - m_jsonString = jsonString; - m_index = -1; - m_count = 1; - } - - public SimpleJsonCursor(String[] jsonStringArray) { - m_jsonStringArray = jsonStringArray; - m_index = -1; - m_count = jsonStringArray.length; - } - - @Override - public int getID() { - return m_index; - } - - @Override - public String next() { - if (m_index < m_count - 1) { - m_index++; - return m_jsonString != null ? m_jsonString - : m_jsonStringArray[m_index]; - } - - return null; - } + String m_jsonString; + String[] m_jsonStringArray; + + int m_index; + int m_count; + + public SimpleJsonCursor(String jsonString) { + m_jsonString = jsonString; + m_index = -1; + m_count = 1; + } + + public SimpleJsonCursor(String[] jsonStringArray) { + m_jsonStringArray = jsonStringArray; + m_index = -1; + m_count = jsonStringArray.length; + } + + @Override + public int getID() { + return m_index; + } + + @Override + public String next() { + if (m_index < m_count - 1) { + m_index++; + return m_jsonString != null ? m_jsonString + : m_jsonStringArray[m_index]; + } + + return null; + } } diff --git a/src/main/java/com/esri/core/geometry/SimpleJsonReaderCursor.java b/src/main/java/com/esri/core/geometry/SimpleJsonReaderCursor.java index 671947bf..e74aca20 100644 --- a/src/main/java/com/esri/core/geometry/SimpleJsonReaderCursor.java +++ b/src/main/java/com/esri/core/geometry/SimpleJsonReaderCursor.java @@ -28,46 +28,48 @@ import java.util.stream.Collectors; public class SimpleJsonReaderCursor extends JsonReaderCursor { - private ArrayDeque m_jsonDeque; - private int m_index= -1; - private String currentFeatureID = ""; - private SimpleStateEnum simpleState = SimpleStateEnum.SIMPLE_UNKNOWN; - - public SimpleJsonReaderCursor(JsonReader jsonString) { - m_jsonDeque = new ArrayDeque<>(1); - m_jsonDeque.add(jsonString); - } - - public SimpleJsonReaderCursor(JsonReader[] jsonStringArray) { - m_jsonDeque = Arrays.stream(jsonStringArray).collect(Collectors.toCollection(ArrayDeque::new)); - } - - @Override - public int getID() { - return m_index; - } - - @Override - public SimpleStateEnum getSimpleState() { - return simpleState; - } - - @Override - public String getFeatureID() { return currentFeatureID ; } - - @Override - public boolean hasNext() { - return m_jsonDeque.size() > 0; - } - - @Override - public JsonReader next() { - if (!m_jsonDeque.isEmpty()) { - m_index++; - return m_jsonDeque.pop(); - } - - return null; - } + private ArrayDeque m_jsonDeque; + private int m_index = -1; + private String currentFeatureID = ""; + private SimpleStateEnum simpleState = SimpleStateEnum.SIMPLE_UNKNOWN; + + public SimpleJsonReaderCursor(JsonReader jsonString) { + m_jsonDeque = new ArrayDeque<>(1); + m_jsonDeque.add(jsonString); + } + + public SimpleJsonReaderCursor(JsonReader[] jsonStringArray) { + m_jsonDeque = Arrays.stream(jsonStringArray).collect(Collectors.toCollection(ArrayDeque::new)); + } + + @Override + public int getID() { + return m_index; + } + + @Override + public SimpleStateEnum getSimpleState() { + return simpleState; + } + + @Override + public String getFeatureID() { + return currentFeatureID; + } + + @Override + public boolean hasNext() { + return m_jsonDeque.size() > 0; + } + + @Override + public JsonReader next() { + if (!m_jsonDeque.isEmpty()) { + m_index++; + return m_jsonDeque.pop(); + } + + return null; + } } diff --git a/src/main/java/com/esri/core/geometry/SimpleMapGeometryCursor.java b/src/main/java/com/esri/core/geometry/SimpleMapGeometryCursor.java index 5b44cf8b..380c8db4 100644 --- a/src/main/java/com/esri/core/geometry/SimpleMapGeometryCursor.java +++ b/src/main/java/com/esri/core/geometry/SimpleMapGeometryCursor.java @@ -32,48 +32,50 @@ * an array of MapGeometry classes */ class SimpleMapGeometryCursor extends MapGeometryCursor { - private ArrayDeque m_geomDeque; - private long m_index = -1; - private String m_currentFeatureID = ""; - private SimpleStateEnum m_simpleState = SimpleStateEnum.SIMPLE_UNKNOWN; - - - public SimpleMapGeometryCursor(MapGeometry geom) { - m_geomDeque = new ArrayDeque<>(1); - } - - public SimpleMapGeometryCursor(MapGeometry[] geoms) { - m_geomDeque = Arrays.stream(geoms).collect(Collectors.toCollection(ArrayDeque::new)); - } - - @Override - public long getGeometryID() { - return m_index; - } - - @Override - public SimpleStateEnum getSimpleState() { - return m_simpleState; - } - - @Override - public String getFeatureID() { return m_currentFeatureID; } - - - @Override - public boolean hasNext() { - return m_geomDeque.size() > 0; - } - - @Override - public MapGeometry next() { - if (hasNext()) { - m_index++; - MapGeometry mapGeometry = m_geomDeque.pop(); - m_simpleState = mapGeometry.m_geometry.getSimpleState(); - return mapGeometry; - } - - return null; - } + private ArrayDeque m_geomDeque; + private long m_index = -1; + private String m_currentFeatureID = ""; + private SimpleStateEnum m_simpleState = SimpleStateEnum.SIMPLE_UNKNOWN; + + + public SimpleMapGeometryCursor(MapGeometry geom) { + m_geomDeque = new ArrayDeque<>(1); + } + + public SimpleMapGeometryCursor(MapGeometry[] geoms) { + m_geomDeque = Arrays.stream(geoms).collect(Collectors.toCollection(ArrayDeque::new)); + } + + @Override + public long getGeometryID() { + return m_index; + } + + @Override + public SimpleStateEnum getSimpleState() { + return m_simpleState; + } + + @Override + public String getFeatureID() { + return m_currentFeatureID; + } + + + @Override + public boolean hasNext() { + return m_geomDeque.size() > 0; + } + + @Override + public MapGeometry next() { + if (hasNext()) { + m_index++; + MapGeometry mapGeometry = m_geomDeque.pop(); + m_simpleState = mapGeometry.m_geometry.getSimpleState(); + return mapGeometry; + } + + return null; + } } diff --git a/src/main/java/com/esri/core/geometry/SimpleRasterizer.java b/src/main/java/com/esri/core/geometry/SimpleRasterizer.java index 1d5fb614..8c6d7e46 100644 --- a/src/main/java/com/esri/core/geometry/SimpleRasterizer.java +++ b/src/main/java/com/esri/core/geometry/SimpleRasterizer.java @@ -24,527 +24,558 @@ package com.esri.core.geometry; -import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.Comparator; +import static com.esri.core.geometry.SizeOf.SIZE_OF_EDGE; +import static com.esri.core.geometry.SizeOf.SIZE_OF_SIMPLE_RASTERIZER; +import static com.esri.core.geometry.SizeOf.sizeOfIntArray; +import static com.esri.core.geometry.SizeOf.sizeOfObjectArray; + /** * Simple scanline rasterizer. Caller provides a callback to draw pixels to actual surface. + * */ public class SimpleRasterizer { - - /** - * Even odd fill rule - */ - public final static int EVEN_ODD = 0; - - /** - * Winding fill rule - */ - public final static int WINDING = 1; - - public static interface ScanCallback { - /** - * Rasterizer calls this method for each scan it produced - * - * @param scans array of scans. Scans are triplets of numbers. The start X coordinate for the scan (inclusive), - * the end X coordinate of the scan (exclusive), the Y coordinate for the scan. - * @param scanCount3 The number of initialized elements in the scans array. The scan count is scanCount3 / 3. - */ - public abstract void drawScan(int[] scans, int scanCount3); - } - - public SimpleRasterizer() { - width_ = -1; - height_ = -1; - } - - /** - * Sets up the rasterizer. - */ - public void setup(int width, int height, ScanCallback callback) { - width_ = width; - height_ = height; - ySortedEdges_ = null; - activeEdgesTable_ = null; - numEdges_ = 0; - callback_ = callback; - if (scanBuffer_ == null) - scanBuffer_ = new int[128 * 3]; - - startAddingEdges(); - } - - public final int getWidth() { - return width_; - } - - public final int getHeight() { - return height_; - } - - /** - * Flushes any cached scans. - */ - public final void flush() { - if (scanPtr_ > 0) { - callback_.drawScan(scanBuffer_, scanPtr_); - scanPtr_ = 0; - } - } - - /** - * Adds edges of a triangle. - */ - public final void addTriangle(double x1, double y1, double x2, double y2, double x3, double y3) { - addEdge(x1, y1, x2, y2); - addEdge(x2, y2, x3, y3); - addEdge(x1, y1, x3, y3); - } - - /** - * Adds edges of the ring to the rasterizer. - * - * @param xy interleaved coordinates x1, y1, x2, y2,... - */ - public final void addRing(double xy[]) { - for (int i = 2; i < xy.length; i += 2) { - addEdge(xy[i - 2], xy[i - 1], xy[i], xy[i + 1]); - } - } - - /** - * Call before starting the edges. - *

- * For example to render two polygons that consist of a single ring: - * startAddingEdges(); - * addRing(...); - * renderEdges(Rasterizer.EVEN_ODD); - * addRing(...); - * renderEdges(Rasterizer.EVEN_ODD); - *

- * For example to render a polygon consisting of three rings: - * startAddingEdges(); - * addRing(...); - * addRing(...); - * addRing(...); - * renderEdges(Rasterizer.EVEN_ODD); - */ - public final void startAddingEdges() { - if (numEdges_ > 0) { - for (int i = 0; i < height_; i++) { - for (Edge e = ySortedEdges_[i]; e != null; ) { - Edge p = e; - e = e.next; - p.next = null; - } - - ySortedEdges_[i] = null; - } - - activeEdgesTable_ = null; - } - - minY_ = height_; - maxY_ = -1; - numEdges_ = 0; - } - - /** - * Renders all edges added so far, and removes them. - * Calls startAddingEdges after it's done. - * - * @param fillMode Fill mode for the polygon fill can be one of two values: EVEN_ODD or WINDING. - *

- * Note, as any other graphics algorithm, the scan line rasterizer doesn't require polygons - * to be topologically simple, or have correct ring orientation. - */ - public final void renderEdges(int fillMode) { - evenOdd_ = fillMode == EVEN_ODD; - for (int line = minY_; line <= maxY_; line++) { - advanceAET_(); - addNewEdgesToAET_(line); - emitScans_(); - } - - startAddingEdges();//reset for new edges - } - - /** - * Add a single edge. - * - * @param x1 - * @param y1 - * @param x2 - * @param y2 - */ - public final void addEdge(double x1, double y1, double x2, double y2) { - if (y1 == y2) - return; - - int dir = 1; - if (y1 > y2) { - double temp; - temp = x1; - x1 = x2; - x2 = temp; - temp = y1; - y1 = y2; - y2 = temp; - dir = -1; - } - - if (y2 < 0 || y1 >= height_) - return; - - if (x1 < 0 && x2 < 0) { - x1 = -1; - x2 = -1; - } else if (x1 >= width_ && x2 >= width_) { - x1 = width_; - x2 = width_; - } - - //clip to extent - double dxdy = (x2 - x1) / (y2 - y1); - - if (y2 > height_) { - y2 = height_; - x2 = dxdy * (y2 - y1) + x1; - } - - if (y1 < 0) { - x1 = dxdy * (0 - y1) + x1; - y1 = 0; - } - - //do not clip x unless it is too small or too big - int bigX = Math.max(width_ + 1, 0x7fffff); - if (x1 < -0x7fffff) { - //from earlier logic, x2 >= -1, therefore dxdy is not 0 - y1 = (0 - x1) / dxdy + y1; - x1 = 0; - } else if (x1 > bigX) { - //from earlier logic, x2 <= width_, therefore dxdy is not 0 - y1 = (width_ - x1) / dxdy + y1; - x1 = width_; - } - - if (x2 < -0x7fffff) { - //from earlier logic, x1 >= -1, therefore dxdy is not 0 - y2 = (0 - x1) / dxdy + y1; - x2 = 0; - } else if (x2 > bigX) { - //from earlier logic, x1 <= width_, therefore dxdy is not 0 - y2 = (width_ - x1) / dxdy + y1; - x2 = width_; - } - - int ystart = (int) y1; - int yend = (int) y2; - if (ystart == yend) - return; - - Edge e = new Edge(); - - e.x = (long) (x1 * 4294967296.0); - e.y = ystart; - e.ymax = yend; - e.dxdy = (long) (dxdy * 4294967296.0); - e.dir = dir; - - if (ySortedEdges_ == null) { - ySortedEdges_ = new Edge[height_]; - } - - e.next = ySortedEdges_[e.y]; - ySortedEdges_[e.y] = e; - - if (e.y < minY_) - minY_ = e.y; - - if (e.ymax > maxY_) - maxY_ = e.ymax; - - numEdges_++; - } - - public final void fillEnvelope(Envelope2D envIn) { - Envelope2D env = new Envelope2D(0, 0, width_, height_); - if (!env.intersect(envIn)) - return; - - int x0 = (int) env.xmin; - int x = (int) env.xmax; - - int xn = NumberUtils.snap(x0, 0, width_); - int xm = NumberUtils.snap(x, 0, width_); - if (x0 < width_ && xn < xm) { - int y0 = (int) env.ymin; - int y1 = (int) env.ymax; - y0 = NumberUtils.snap(y0, 0, height_); - y1 = NumberUtils.snap(y1, 0, height_); - if (y0 < height_) { - for (int y = y0; y < y1; y++) { - scanBuffer_[scanPtr_++] = xn; - scanBuffer_[scanPtr_++] = xm; - scanBuffer_[scanPtr_++] = y; - if (scanPtr_ == scanBuffer_.length) { - callback_.drawScan(scanBuffer_, scanPtr_); - scanPtr_ = 0; - } - } - } - } - } - - final boolean addSegmentStroke(double x1, double y1, double x2, double y2, double half_width, boolean skip_short, double[] helper_xy_10_elm) { - double vec_x = x2 - x1; - double vec_y = y2 - y1; - double len = Math.sqrt(vec_x * vec_x + vec_y * vec_y); - if (skip_short && len < 0.5) - return false; - - boolean bshort = len < 0.00001; - if (bshort) { - len = 0.00001; - vec_x = len; - vec_y = 0.0; - } - - double f = half_width / len; - vec_x *= f; - vec_y *= f; - double vecA_x = -vec_y; - double vecA_y = vec_x; - double vecB_x = vec_y; - double vecB_y = -vec_x; - //extend by half width - x1 -= vec_x; - y1 -= vec_y; - x2 += vec_x; - y2 += vec_y; - //create rotated rectangle - double[] fan = helper_xy_10_elm; - assert (fan.length == 10); - fan[0] = x1 + vecA_x; - fan[1] = y1 + vecA_y;//fan[0].add(pt_start, vecA); - fan[2] = x1 + vecB_x; - fan[3] = y1 + vecB_y;//fan[1].add(pt_start, vecB); - fan[4] = x2 + vecB_x; - fan[5] = y2 + vecB_y;//fan[2].add(pt_end, vecB) - fan[6] = x2 + vecA_x; - fan[7] = y2 + vecA_y;//fan[3].add(pt_end, vecA) - fan[8] = fan[0]; - fan[9] = fan[1]; - addRing(fan); - return true; - } - - public final ScanCallback getScanCallback() { - return callback_; - } - - - //PRIVATE - - private static class Edge { - long x; - long dxdy; - int y; - int ymax; - int dir; - Edge next; - } - - private final void advanceAET_() { - if (activeEdgesTable_ == null) - return; - - boolean needSort = false; - Edge prev = null; - for (Edge e = activeEdgesTable_; e != null; ) { - e.y++; - if (e.y == e.ymax) { - Edge p = e; - e = e.next; - if (prev != null) - prev.next = e; - else - activeEdgesTable_ = e; - - p.next = null; - continue; - } - - e.x += e.dxdy; - if (prev != null && prev.x > e.x) - needSort = true; - - prev = e; - e = e.next; - } - - if (needSort) { - //resort to fix the order - activeEdgesTable_ = sortAET_(activeEdgesTable_); - } - } - - private final void addNewEdgesToAET_(int y) { - if (y >= height_) - return; - - Edge edgesOnLine = ySortedEdges_[y]; - if (edgesOnLine != null) { - ySortedEdges_[y] = null; - edgesOnLine = sortAET_(edgesOnLine);//sort new edges - numEdges_ -= sortedNum_;//set in the sortAET - - // merge the edges with sorted AET - O(n) operation - Edge aet = activeEdgesTable_; - boolean first = true; - Edge newEdge = edgesOnLine; - Edge prev_aet = null; - while (aet != null && newEdge != null) { - if (aet.x > newEdge.x) { - if (first) - activeEdgesTable_ = newEdge; - - Edge p = newEdge.next; - newEdge.next = aet; - if (prev_aet != null) { - prev_aet.next = newEdge; - } - - prev_aet = newEdge; - newEdge = p; - } else { // aet.x <= newEdges.x - Edge p = aet.next; - aet.next = newEdge; - if (prev_aet != null) - prev_aet.next = aet; - - prev_aet = aet; - aet = p; - } - - first = false; - } - - if (activeEdgesTable_ == null) - activeEdgesTable_ = edgesOnLine; - } - } - - private static int snap_(int x, int mi, int ma) { - return x < mi ? mi : x > ma ? ma : x; - } - - private final void emitScans_() { - if (activeEdgesTable_ == null) - return; - - int w = 0; - Edge e0 = activeEdgesTable_; - int x0 = (int) (e0.x >> 32); - for (Edge e = e0.next; e != null; e = e.next) { - if (evenOdd_) - w ^= 1; - else - w += e.dir; - - if (e.x > e0.x) { - int x = (int) (e.x >> 32); - if (w != 0) { - int xx0 = snap_(x0, 0, width_); - int xx = snap_(x, 0, width_); - if (xx > xx0 && xx0 < width_) { - scanBuffer_[scanPtr_++] = xx0; - scanBuffer_[scanPtr_++] = xx; - scanBuffer_[scanPtr_++] = e.y; - if (scanPtr_ == scanBuffer_.length) { - callback_.drawScan(scanBuffer_, scanPtr_); - scanPtr_ = 0; - } - } - } - - e0 = e; - x0 = x; - } - } - } - - static private class EdgeComparator implements Comparator { - @Override - public int compare(Edge o1, Edge o2) { - if (o1 == o2) - return 0; - - return o1.x < o2.x ? -1 : o1.x > o2.x ? 1 : 0; - } - } - - private final static EdgeComparator edgeCompare_ = new EdgeComparator(); - - private final Edge sortAET_(Edge aet) { - int num = 0; - for (Edge e = aet; e != null; e = e.next) - num++; - - sortedNum_ = num; - if (num == 1) - return aet; - - if (sortBuffer_ == null) - sortBuffer_ = new Edge[Math.max(num, 16)]; - - else if (sortBuffer_.length < num) - sortBuffer_ = new Edge[Math.max(num, sortBuffer_.length * 2)]; - - { - int i = 0; - for (Edge e = aet; e != null; e = e.next) - sortBuffer_[i++] = e; - } - - if (num == 2) { - if (sortBuffer_[0].x > sortBuffer_[1].x) { - Edge tmp = sortBuffer_[0]; - sortBuffer_[0] = sortBuffer_[1]; - sortBuffer_[1] = tmp; - } - } else { - Arrays.sort(sortBuffer_, 0, num, edgeCompare_); - } - - aet = sortBuffer_[0]; - sortBuffer_[0] = null; - Edge prev = aet; - for (int i = 1; i < num; i++) { - prev.next = sortBuffer_[i]; - prev = sortBuffer_[i]; - sortBuffer_[i] = null; - } - - prev.next = null; - return aet; - } - - private Edge activeEdgesTable_; - private Edge[] ySortedEdges_; - private Edge[] sortBuffer_; - private int[] scanBuffer_; - int scanPtr_; - private ScanCallback callback_; - private int width_; - private int height_; - private int minY_; - private int maxY_; - private int numEdges_; - private int sortedNum_; - private boolean evenOdd_; + + /** + * Even odd fill rule + */ + public final static int EVEN_ODD = 0; + + /** + * Winding fill rule + */ + public final static int WINDING = 1; + + public interface ScanCallback { + /** + * Rasterizer calls this method for each scan it produced + * @param scans array of scans. Scans are triplets of numbers. The start X coordinate for the scan (inclusive), + * the end X coordinate of the scan (exclusive), the Y coordinate for the scan. + * @param scanCount3 The number of initialized elements in the scans array. The scan count is scanCount3 / 3. + */ + void drawScan(int[] scans, int scanCount3); + } + + public SimpleRasterizer() { + width_ = -1; + height_ = -1; + } + + /** + * Sets up the rasterizer. + */ + public void setup(int width, int height, ScanCallback callback) + { + width_ = width; height_ = height; + ySortedEdges_ = null; + activeEdgesTable_ = null; + numEdges_ = 0; + callback_ = callback; + if (scanBuffer_ == null) + scanBuffer_ = new int[128 * 3]; + + startAddingEdges(); + } + + public final int getWidth() { + return width_; + } + + public final int getHeight() { + return height_; + } + + /** + * Flushes any cached scans. + */ + public final void flush() { + if (scanPtr_ > 0) { + callback_.drawScan(scanBuffer_, scanPtr_); + scanPtr_ = 0; + } + } + + /** + * Adds edges of a triangle. + */ + public final void addTriangle(double x1, double y1, double x2, double y2, double x3, double y3) { + addEdge(x1, y1, x2, y2); + addEdge(x2, y2, x3, y3); + addEdge(x1, y1, x3, y3); + } + + /** + * Adds edges of the ring to the rasterizer. + * @param xy interleaved coordinates x1, y1, x2, y2,... + */ + public final void addRing(double xy[]) { + for (int i = 2; i < xy.length; i += 2) { + addEdge(xy[i-2], xy[i - 1], xy[i], xy[i + 1]); + } + } + + /** + * Call before starting the edges. + * + * For example to render two polygons that consist of a single ring: + * startAddingEdges(); + * addRing(...); + * renderEdges(Rasterizer.EVEN_ODD); + * addRing(...); + * renderEdges(Rasterizer.EVEN_ODD); + * + * For example to render a polygon consisting of three rings: + * startAddingEdges(); + * addRing(...); + * addRing(...); + * addRing(...); + * renderEdges(Rasterizer.EVEN_ODD); + */ + public final void startAddingEdges() { + if (numEdges_ > 0) { + for (int i = 0; i < height_; i++) { + for (Edge e = ySortedEdges_[i]; e != null;) { + Edge p = e; + e = e.next; + p.next = null; + } + + ySortedEdges_[i] = null; + } + + activeEdgesTable_ = null; + } + + minY_ = height_; + maxY_ = -1; + numEdges_ = 0; + } + + /** + * Renders all edges added so far, and removes them. + * Calls startAddingEdges after it's done. + * @param fillMode Fill mode for the polygon fill can be one of two values: EVEN_ODD or WINDING. + * + * Note, as any other graphics algorithm, the scan line rasterizer doesn't require polygons + * to be topologically simple, or have correct ring orientation. + */ + public final void renderEdges(int fillMode) { + evenOdd_ = fillMode == EVEN_ODD; + for (int line = minY_; line <= maxY_; line++) { + advanceAET_(); + addNewEdgesToAET_(line); + emitScans_(); + } + + startAddingEdges();//reset for new edges + } + + /** + * Add a single edge. + * @param x1 + * @param y1 + * @param x2 + * @param y2 + */ + public final void addEdge(double x1, double y1, double x2, double y2) { + if (y1 == y2) + return; + + int dir = 1; + if (y1 > y2) { + double temp; + temp = x1; x1 = x2; x2 = temp; + temp = y1; y1 = y2; y2 = temp; + dir = -1; + } + + if (y2 < 0 || y1 >= height_) + return; + + if (x1 < 0 && x2 < 0) + { + x1 = -1; x2 = -1; + } + else if (x1 >= width_ && x2 >= width_) + { + x1 = width_; x2 = width_; + } + + //clip to extent + double dxdy = (x2 - x1) / (y2 - y1); + + if (y2 > height_) { + y2 = height_; + x2 = dxdy * (y2 - y1) + x1; + } + + if (y1 < 0) { + x1 = dxdy * (0 - y1) + x1; + y1 = 0; + } + + //do not clip x unless it is too small or too big + int bigX = Math.max(width_ + 1, 0x7fffff); + if (x1 < -0x7fffff) { + //from earlier logic, x2 >= -1, therefore dxdy is not 0 + y1 = (0 - x1) / dxdy + y1; + x1 = 0; + } + else if (x1 > bigX) { + //from earlier logic, x2 <= width_, therefore dxdy is not 0 + y1 = (width_ - x1) / dxdy + y1; + x1 = width_; + } + + if (x2 < -0x7fffff) { + //from earlier logic, x1 >= -1, therefore dxdy is not 0 + y2 = (0 - x1) / dxdy + y1; + x2 = 0; + } + else if (x2 > bigX) { + //from earlier logic, x1 <= width_, therefore dxdy is not 0 + y2 = (width_ - x1) / dxdy + y1; + x2 = width_; + } + + int ystart = (int)y1; + int yend = (int)y2; + if (ystart == yend) + return; + + Edge e = new Edge(); + + e.x = (long)(x1 * 4294967296.0); + e.y = ystart; + e.ymax = yend; + e.dxdy = (long)(dxdy * 4294967296.0); + e.dir = dir; + + if (ySortedEdges_ == null) { + ySortedEdges_ = new Edge[height_]; + } + + e.next = ySortedEdges_[e.y]; + ySortedEdges_[e.y] = e; + + if (e.y < minY_) + minY_ = e.y; + + if (e.ymax > maxY_) + maxY_ = e.ymax; + + numEdges_++; + } + + public final void fillEnvelope(Envelope2D envIn) { + Envelope2D env = new Envelope2D(0, 0, width_, height_); + if (!env.intersect(envIn)) + return; + + int x0 = (int)env.xmin; + int x = (int)env.xmax; + + int xn = NumberUtils.snap(x0, 0, width_); + int xm = NumberUtils.snap(x, 0, width_); + if (x0 < width_ && xn < xm) { + int y0 = (int)env.ymin; + int y1 = (int)env.ymax; + y0 = NumberUtils.snap(y0, 0, height_); + y1 = NumberUtils.snap(y1, 0, height_); + if (y0 < height_) { + for (int y = y0; y < y1; y++) { + scanBuffer_[scanPtr_++] = xn; + scanBuffer_[scanPtr_++] = xm; + scanBuffer_[scanPtr_++] = y; + if (scanPtr_ == scanBuffer_.length) { + callback_.drawScan(scanBuffer_, scanPtr_); + scanPtr_ = 0; + } + } + } + } + } + + final boolean addSegmentStroke(double x1, double y1, double x2, double y2, double half_width, boolean skip_short, + double[] helper_xy_10_elm) { + double vec_x = x2 - x1; + double vec_y = y2 - y1; + double sqr_len = vec_x * vec_x + vec_y * vec_y; + if (skip_short && sqr_len < (0.5 * 0.5)) { + return false; + } + + boolean veryShort = !skip_short && (sqr_len < (0.00001 * 0.00001)); + if (veryShort) { + vec_x = half_width + 0.00001; + vec_y = 0.0; + } else { + double f = half_width / Math.sqrt(sqr_len); + vec_x *= f; + vec_y *= f; + } + + double vecA_x = -vec_y; + double vecA_y = vec_x; + double vecB_x = vec_y; + double vecB_y = -vec_x; + // extend by half width + x1 -= vec_x; + y1 -= vec_y; + x2 += vec_x; + y2 += vec_y; + // create rotated rectangle + double[] fan = helper_xy_10_elm; + assert (fan.length == 10); + fan[0] = x1 + vecA_x; + fan[1] = y1 + vecA_y;// fan[0].add(pt_start, vecA); + fan[2] = x1 + vecB_x; + fan[3] = y1 + vecB_y;// fan[1].add(pt_start, vecB); + fan[4] = x2 + vecB_x; + fan[5] = y2 + vecB_y;// fan[2].add(pt_end, vecB) + fan[6] = x2 + vecA_x; + fan[7] = y2 + vecA_y;// fan[3].add(pt_end, vecA) + fan[8] = fan[0]; + fan[9] = fan[1]; + addRing(fan); + return true; + } + + public final ScanCallback getScanCallback() { return callback_; } + + public long estimateMemorySize() + { + // callback_ is only a pointer, the actual size is accounted for in the caller of setup() + long size = SIZE_OF_SIMPLE_RASTERIZER + + (activeEdgesTable_ != null ? activeEdgesTable_.estimateMemorySize() : 0) + + (scanBuffer_ != null ? sizeOfIntArray(scanBuffer_.length) : 0); + + if (ySortedEdges_ != null) { + size += sizeOfObjectArray(ySortedEdges_.length); + for (int i = 0; i < ySortedEdges_.length; i++) { + if (ySortedEdges_[i] != null) { + size += ySortedEdges_[i].estimateMemorySize(); + } + } + } + + if (sortBuffer_ != null) { + size += sizeOfObjectArray(sortBuffer_.length); + for (int i = 0; i < sortBuffer_.length; i++) { + if (sortBuffer_[i] != null) { + size += sortBuffer_[i].estimateMemorySize(); + } + } + } + + return size; + } + + //PRIVATE + + static class Edge { + long x; + long dxdy; + int y; + int ymax; + int dir; + Edge next; + + long estimateMemorySize() + { + // next is only a pointer, the actual size is accounted for in SimpleRasterizer#estimateMemorySize + return SIZE_OF_EDGE; + } + } + + private final void advanceAET_() { + if (activeEdgesTable_ == null) + return; + + boolean needSort = false; + Edge prev = null; + for (Edge e = activeEdgesTable_; e != null; ) { + e.y++; + if (e.y == e.ymax) { + Edge p = e; e = e.next; + if (prev != null) + prev.next = e; + else + activeEdgesTable_ = e; + + p.next = null; + continue; + } + + e.x += e.dxdy; + if (prev != null && prev.x > e.x) + needSort = true; + + prev = e; + e = e.next; + } + + if (needSort) { + //resort to fix the order + activeEdgesTable_ = sortAET_(activeEdgesTable_); + } + } + + private final void addNewEdgesToAET_(int y) { + if (y >= height_) + return; + + Edge edgesOnLine = ySortedEdges_[y]; + if (edgesOnLine != null) { + ySortedEdges_[y] = null; + edgesOnLine = sortAET_(edgesOnLine);//sort new edges + numEdges_ -= sortedNum_;//set in the sortAET + + // merge the edges with sorted AET - O(n) operation + Edge aet = activeEdgesTable_; + boolean first = true; + Edge newEdge = edgesOnLine; + Edge prev_aet = null; + while (aet != null && newEdge != null) { + if (aet.x > newEdge.x) { + if (first) + activeEdgesTable_ = newEdge; + + Edge p = newEdge.next; + newEdge.next = aet; + if (prev_aet != null) { + prev_aet.next = newEdge; + } + + prev_aet = newEdge; + newEdge = p; + } else { // aet.x <= newEdges.x + Edge p = aet.next; + aet.next = newEdge; + if (prev_aet != null) + prev_aet.next = aet; + + prev_aet = aet; + aet = p; + } + + first = false; + } + + if (activeEdgesTable_ == null) + activeEdgesTable_ = edgesOnLine; + } + } + + private static int snap_(int x, int mi, int ma) { + return x < mi ? mi : x > ma ? ma : x; + } + + private final void emitScans_() { + if (activeEdgesTable_ == null) + return; + + int w = 0; + Edge e0 = activeEdgesTable_; + int x0 = (int)(e0.x >> 32); + for (Edge e = e0.next; e != null; e = e.next) { + if (evenOdd_) + w ^= 1; + else + w += e.dir; + + if (e.x > e0.x) { + int x = (int)(e.x >> 32); + if (w != 0) { + int xx0 = snap_(x0, 0, width_); + int xx = snap_(x, 0, width_); + if (xx > xx0 && xx0 < width_) { + scanBuffer_[scanPtr_++] = xx0; + scanBuffer_[scanPtr_++] = xx; + scanBuffer_[scanPtr_++] = e.y; + if (scanPtr_ == scanBuffer_.length) { + callback_.drawScan(scanBuffer_, scanPtr_); + scanPtr_ = 0; + } + } + } + + e0 = e; + x0 = x; + } + } + } + + static private class EdgeComparator implements Comparator { + @Override + public int compare(Edge o1, Edge o2) { + if (o1 == o2) + return 0; + + return o1.x < o2.x ? -1 : o1.x > o2.x ? 1 : 0; + } + } + + private final static EdgeComparator edgeCompare_ = new EdgeComparator(); + + private final Edge sortAET_(Edge aet) { + int num = 0; + for (Edge e = aet; e != null; e = e.next) + num++; + + sortedNum_ = num; + if (num == 1) + return aet; + + if (sortBuffer_ == null) + sortBuffer_ = new Edge[Math.max(num, 16)]; + + else if (sortBuffer_.length < num) + sortBuffer_ = new Edge[Math.max(num, sortBuffer_.length * 2)]; + + { + int i = 0; + for (Edge e = aet; e != null; e = e.next) + sortBuffer_[i++] = e; + } + + if (num == 2) { + if (sortBuffer_[0].x > sortBuffer_[1].x) { + Edge tmp = sortBuffer_[0]; + sortBuffer_[0] = sortBuffer_[1]; + sortBuffer_[1] = tmp; + } + } + else { + Arrays.sort(sortBuffer_, 0, num, edgeCompare_); + } + + aet = sortBuffer_[0]; sortBuffer_[0] = null; + Edge prev = aet; + for (int i = 1; i < num; i++) { + prev.next = sortBuffer_[i]; + prev = sortBuffer_[i]; + sortBuffer_[i] = null; + } + + prev.next = null; + return aet; + } + + private Edge activeEdgesTable_; + private Edge[] ySortedEdges_; + private Edge[] sortBuffer_; + private int[] scanBuffer_; + int scanPtr_; + private ScanCallback callback_; + private int width_; + private int height_; + private int minY_; + private int maxY_; + private int numEdges_; + private int sortedNum_; + private boolean evenOdd_; } diff --git a/src/main/java/com/esri/core/geometry/SimpleStateEnum.java b/src/main/java/com/esri/core/geometry/SimpleStateEnum.java index d0802ebc..87e209d0 100644 --- a/src/main/java/com/esri/core/geometry/SimpleStateEnum.java +++ b/src/main/java/com/esri/core/geometry/SimpleStateEnum.java @@ -1,24 +1,24 @@ package com.esri.core.geometry; public enum SimpleStateEnum { - // on creation, after projection and after generalization a geometry has state simple unknown (not know if simple or not) - SIMPLE_UNKNOWN, - // weak simple (no self intersections, ring orientation is correct, but ring order is not) - WEAK_SIMPLE, - // same as weak simple + OGC ring order. - STRONG_SIMPLE, - // is_simple method has been run on the geometry and it is known to be non-simple, but the reason is unknown - NON_SIMPLE, - // non-simple, because the structure is bad (0 size path, for example). - STRUCTURE_FLAW, - // Non-simple, because there are degenerate segments. - DEGENERATE_SEGMENTS, - // Non-simple, because not clustered properly, that is there are non-coincident vertices closer than tolerance. - CLUSTERING, - // Non-simple, because not cracked properly (intersecting segments, overlaping segments) - CRACKING, - // Non-simple, because there are crossovers (self intersections that are not cracking case). - CROSS_OVER, - // Non-simple, because holes or exteriors have wrong orientation. - RING_ORIENTATION, + // on creation, after projection and after generalization a geometry has state simple unknown (not know if simple or not) + SIMPLE_UNKNOWN, + // weak simple (no self intersections, ring orientation is correct, but ring order is not) + WEAK_SIMPLE, + // same as weak simple + OGC ring order. + STRONG_SIMPLE, + // is_simple method has been run on the geometry and it is known to be non-simple, but the reason is unknown + NON_SIMPLE, + // non-simple, because the structure is bad (0 size path, for example). + STRUCTURE_FLAW, + // Non-simple, because there are degenerate segments. + DEGENERATE_SEGMENTS, + // Non-simple, because not clustered properly, that is there are non-coincident vertices closer than tolerance. + CLUSTERING, + // Non-simple, because not cracked properly (intersecting segments, overlaping segments) + CRACKING, + // Non-simple, because there are crossovers (self intersections that are not cracking case). + CROSS_OVER, + // Non-simple, because holes or exteriors have wrong orientation. + RING_ORIENTATION, } diff --git a/src/main/java/com/esri/core/geometry/SimpleStringCursor.java b/src/main/java/com/esri/core/geometry/SimpleStringCursor.java index 4b9509b6..e3a0b836 100644 --- a/src/main/java/com/esri/core/geometry/SimpleStringCursor.java +++ b/src/main/java/com/esri/core/geometry/SimpleStringCursor.java @@ -7,116 +7,122 @@ import java.util.stream.Collectors; public class SimpleStringCursor extends StringCursor { - private ArrayDeque m_arrayDeque; - private ArrayDeque m_simpleStates; - private ArrayDeque m_ids; - private ArrayDeque m_featureIDs; - private String m_currentFeatureID = ""; - private long m_current_id = -1L; - private SimpleStateEnum m_current_state = SimpleStateEnum.SIMPLE_UNKNOWN; - - @Deprecated - public SimpleStringCursor(String inputString) { - m_arrayDeque = new ArrayDeque<>(1); - m_arrayDeque.push(inputString); - } - - public SimpleStringCursor(String inputString, long id) { - m_arrayDeque = new ArrayDeque<>(1); - m_arrayDeque.push(inputString); - m_ids = new ArrayDeque<>(1); - m_ids.push(id); - } - - public SimpleStringCursor(String inputString, long id, SimpleStateEnum simpleState) { - m_arrayDeque = new ArrayDeque<>(1); - m_arrayDeque.push(inputString); - m_ids = new ArrayDeque<>(1); - m_ids.push(id); - m_simpleStates = new ArrayDeque<>(1); - m_simpleStates.push(simpleState); - } - - public SimpleStringCursor(String inputString, long id, SimpleStateEnum simpleState, String featureID) { - m_arrayDeque = new ArrayDeque<>(1); - m_arrayDeque.push(inputString); - m_ids = new ArrayDeque<>(1); - m_ids.push(id); - m_simpleStates = new ArrayDeque<>(1); - m_simpleStates.push(simpleState); - m_featureIDs = new ArrayDeque<>(1); - m_featureIDs.push(featureID); - } - - @Deprecated - public SimpleStringCursor(String[] inputStringArray) { - m_arrayDeque = Arrays.stream(inputStringArray).collect(Collectors.toCollection(ArrayDeque::new)); - } - - @Deprecated - public SimpleStringCursor(List inputStringArray) { - m_arrayDeque = new ArrayDeque<>(inputStringArray); - } - - public SimpleStringCursor(ArrayDeque arrayDeque, ArrayDeque ids) { - m_ids = ids; - m_arrayDeque = arrayDeque; - } - - public SimpleStringCursor(ArrayDeque arrayDeque, ArrayDeque ids, ArrayDeque simpleStates) { - m_ids = ids; - m_arrayDeque = arrayDeque; - m_simpleStates = simpleStates; - } - - public SimpleStringCursor(ArrayDeque arrayDeque, - ArrayDeque ids, - ArrayDeque simpleStates, - ArrayDeque featureIDs) { - if ((arrayDeque.size() & ids.size() & simpleStates.size() & featureIDs.size()) != arrayDeque.size()) { - throw new GeometryException("arrays must be same size"); - } - m_arrayDeque = arrayDeque; - m_ids = ids; - m_simpleStates = simpleStates; - m_featureIDs = featureIDs; - } - - @Override - public boolean hasNext() { return m_arrayDeque.size() > 0; } - - @Override - public long getID() { - return m_current_id; - } - - @Override - public SimpleStateEnum getSimpleState() { return m_current_state; } - - @Override - public String getFeatureID() { return m_currentFeatureID; } - - void _incrementInternals() { - if (m_ids != null && !m_ids.isEmpty()) { - m_current_id = m_ids.pop(); - } else { - m_current_id++; - } - - if (m_simpleStates != null && !m_simpleStates.isEmpty()) { - m_current_state = m_simpleStates.pop(); - } - if (m_featureIDs != null && !m_featureIDs.isEmpty()) { - m_currentFeatureID = m_featureIDs.pop(); - } - } - - public String next() { - if (hasNext()) { - _incrementInternals(); - return m_arrayDeque.pop(); - } - - return null; - } + private ArrayDeque m_arrayDeque; + private ArrayDeque m_simpleStates; + private ArrayDeque m_ids; + private ArrayDeque m_featureIDs; + private String m_currentFeatureID = ""; + private long m_current_id = -1L; + private SimpleStateEnum m_current_state = SimpleStateEnum.SIMPLE_UNKNOWN; + + @Deprecated + public SimpleStringCursor(String inputString) { + m_arrayDeque = new ArrayDeque<>(1); + m_arrayDeque.push(inputString); + } + + public SimpleStringCursor(String inputString, long id) { + m_arrayDeque = new ArrayDeque<>(1); + m_arrayDeque.push(inputString); + m_ids = new ArrayDeque<>(1); + m_ids.push(id); + } + + public SimpleStringCursor(String inputString, long id, SimpleStateEnum simpleState) { + m_arrayDeque = new ArrayDeque<>(1); + m_arrayDeque.push(inputString); + m_ids = new ArrayDeque<>(1); + m_ids.push(id); + m_simpleStates = new ArrayDeque<>(1); + m_simpleStates.push(simpleState); + } + + public SimpleStringCursor(String inputString, long id, SimpleStateEnum simpleState, String featureID) { + m_arrayDeque = new ArrayDeque<>(1); + m_arrayDeque.push(inputString); + m_ids = new ArrayDeque<>(1); + m_ids.push(id); + m_simpleStates = new ArrayDeque<>(1); + m_simpleStates.push(simpleState); + m_featureIDs = new ArrayDeque<>(1); + m_featureIDs.push(featureID); + } + + @Deprecated + public SimpleStringCursor(String[] inputStringArray) { + m_arrayDeque = Arrays.stream(inputStringArray).collect(Collectors.toCollection(ArrayDeque::new)); + } + + @Deprecated + public SimpleStringCursor(List inputStringArray) { + m_arrayDeque = new ArrayDeque<>(inputStringArray); + } + + public SimpleStringCursor(ArrayDeque arrayDeque, ArrayDeque ids) { + m_ids = ids; + m_arrayDeque = arrayDeque; + } + + public SimpleStringCursor(ArrayDeque arrayDeque, ArrayDeque ids, ArrayDeque simpleStates) { + m_ids = ids; + m_arrayDeque = arrayDeque; + m_simpleStates = simpleStates; + } + + public SimpleStringCursor(ArrayDeque arrayDeque, + ArrayDeque ids, + ArrayDeque simpleStates, + ArrayDeque featureIDs) { + if ((arrayDeque.size() & ids.size() & simpleStates.size() & featureIDs.size()) != arrayDeque.size()) { + throw new GeometryException("arrays must be same size"); + } + m_arrayDeque = arrayDeque; + m_ids = ids; + m_simpleStates = simpleStates; + m_featureIDs = featureIDs; + } + + @Override + public boolean hasNext() { + return m_arrayDeque.size() > 0; + } + + @Override + public long getID() { + return m_current_id; + } + + @Override + public SimpleStateEnum getSimpleState() { + return m_current_state; + } + + @Override + public String getFeatureID() { + return m_currentFeatureID; + } + + void _incrementInternals() { + if (m_ids != null && !m_ids.isEmpty()) { + m_current_id = m_ids.pop(); + } else { + m_current_id++; + } + + if (m_simpleStates != null && !m_simpleStates.isEmpty()) { + m_current_state = m_simpleStates.pop(); + } + if (m_featureIDs != null && !m_featureIDs.isEmpty()) { + m_currentFeatureID = m_featureIDs.pop(); + } + } + + public String next() { + if (hasNext()) { + _incrementInternals(); + return m_arrayDeque.pop(); + } + + return null; + } } diff --git a/src/main/java/com/esri/core/geometry/Simplificator.java b/src/main/java/com/esri/core/geometry/Simplificator.java index 3f9bf314..a5102528 100644 --- a/src/main/java/com/esri/core/geometry/Simplificator.java +++ b/src/main/java/com/esri/core/geometry/Simplificator.java @@ -24,1019 +24,919 @@ package com.esri.core.geometry; class Simplificator { - private EditShape m_shape; - private int m_geometry; - private IndexMultiDCList m_sortedVertices; - - private AttributeStreamOfInt32 m_bunchEdgeEndPoints; - private AttributeStreamOfInt32 m_bunchEdgeCenterPoints; - private AttributeStreamOfInt32 m_bunchEdgeIndices; - // private AttributeStreamOfInt32 m_orphanVertices; - - private int m_dbgCounter; - private int m_sortedVerticesListIndex; - private int m_userIndexSortedIndexToVertex; - private int m_userIndexSortedAngleIndexToVertex; - private int m_nextVertexToProcess; - private int m_firstCoincidentVertex; - private int m_knownSimpleResult; - private boolean m_bWinding; - private boolean m_fixSelfTangency; - private ProgressTracker m_progressTracker; - - private void _beforeRemoveVertex(int vertex, boolean bChangePathFirst) { - int vertexlistIndex = m_shape.getUserIndex(vertex, - m_userIndexSortedIndexToVertex); - - if (m_nextVertexToProcess == vertexlistIndex) { - m_nextVertexToProcess = m_sortedVertices - .getNext(m_nextVertexToProcess); - } - - if (m_firstCoincidentVertex == vertexlistIndex) - m_firstCoincidentVertex = m_sortedVertices - .getNext(m_firstCoincidentVertex); - - m_sortedVertices.deleteElement(m_sortedVerticesListIndex, - vertexlistIndex); - _removeAngleSortInfo(vertex); - if (bChangePathFirst) { - int path = m_shape.getPathFromVertex(vertex); - if (path != -1) { - int first = m_shape.getFirstVertex(path); - if (first == vertex) { - int next = m_shape.getNextVertex(vertex); - if (next != vertex) { - int p = m_shape.getPathFromVertex(next); - if (p == path) { - m_shape.setFirstVertex_(path, next); - return; - } else { - int prev = m_shape.getPrevVertex(vertex); - if (prev != vertex) { - p = m_shape.getPathFromVertex(prev); - if (p == path) { - m_shape.setFirstVertex_(path, prev); - return; - } - } - } - } - - m_shape.setFirstVertex_(path, -1); - m_shape.setLastVertex_(path, -1); - } - } - } - } - - static class SimplificatorAngleComparer extends - AttributeStreamOfInt32.IntComparator { - Simplificator m_parent; - - public SimplificatorAngleComparer(Simplificator parent) { - m_parent = parent; - } - - @Override - public int compare(int v1, int v2) { - return m_parent._compareAngles(v1, v2); - } - - } - - private boolean _processBunch() { - boolean bModified = false; - int iter = 0; - Point2D ptCenter = new Point2D(); - while (true) { - m_dbgCounter++;// only for debugging - iter++; - // _ASSERT(iter < 10); - if (m_bunchEdgeEndPoints == null) { - m_bunchEdgeEndPoints = new AttributeStreamOfInt32(0); - m_bunchEdgeCenterPoints = new AttributeStreamOfInt32(0); - m_bunchEdgeIndices = new AttributeStreamOfInt32(0); - } else { - m_bunchEdgeEndPoints.clear(false); - m_bunchEdgeCenterPoints.clear(false); - m_bunchEdgeIndices.clear(false); - } - - int currentVertex = m_firstCoincidentVertex; - int index = 0; - boolean bFirst = true; - while (currentVertex != m_nextVertexToProcess) { - int v = m_sortedVertices.getData(currentVertex); - {// debug - Point2D pt = new Point2D(); - m_shape.getXY(v, pt); - double y = pt.x; - } - if (bFirst) { - m_shape.getXY(v, ptCenter); - bFirst = false; - } - int vertP = m_shape.getPrevVertex(v); - int vertN = m_shape.getNextVertex(v); - // _ASSERT(vertP != vertN || m_shape.getPrevVertex(vertN) == v - // && m_shape.getNextVertex(vertP) == v); - - int id = m_shape.getUserIndex(vertP, - m_userIndexSortedAngleIndexToVertex); - if (id != 0xdeadbeef)// avoid adding a point twice - { - // _ASSERT(id == -1); - m_bunchEdgeEndPoints.add(vertP); - m_shape.setUserIndex(vertP, - m_userIndexSortedAngleIndexToVertex, 0xdeadbeef);// mark - // that - // it - // has - // been - // already - // added - m_bunchEdgeCenterPoints.add(v); - m_bunchEdgeIndices.add(index++); - } - - int id2 = m_shape.getUserIndex(vertN, - m_userIndexSortedAngleIndexToVertex); - if (id2 != 0xdeadbeef) // avoid adding a point twice - { - // _ASSERT(id2 == -1); - m_bunchEdgeEndPoints.add(vertN); - m_shape.setUserIndex(vertN, - m_userIndexSortedAngleIndexToVertex, 0xdeadbeef);// mark - // that - // it - // has - // been - // already - // added - m_bunchEdgeCenterPoints.add(v); - m_bunchEdgeIndices.add(index++); - } - - currentVertex = m_sortedVertices.getNext(currentVertex); - } - - if (m_bunchEdgeEndPoints.size() < 2) - break; - - // Sort the bunch edpoints by angle (angle between the axis x and - // the edge, connecting the endpoint with the bunch center) - m_bunchEdgeIndices.Sort(0, m_bunchEdgeIndices.size(), - new SimplificatorAngleComparer(this)); - // SORTDYNAMICARRAYEX(m_bunchEdgeIndices, int, 0, - // m_bunchEdgeIndices.size(), SimplificatorAngleComparer, this); - - for (int i = 0, n = m_bunchEdgeIndices.size(); i < n; i++) { - int indexL = m_bunchEdgeIndices.get(i); - int vertex = m_bunchEdgeEndPoints.get(indexL); - m_shape.setUserIndex(vertex, - m_userIndexSortedAngleIndexToVertex, i);// rember the - // sort by angle - // order - {// debug - Point2D pt = new Point2D(); - m_shape.getXY(vertex, pt); - double y = pt.x; - } - } - - boolean bCrossOverResolved = _processCrossOvers(ptCenter);// see of - // there - // are - // crossing - // over - // edges. - for (int i = 0, n = m_bunchEdgeIndices.size(); i < n; i++) { - int indexL = m_bunchEdgeIndices.get(i); - if (indexL == -1) - continue; - int vertex = m_bunchEdgeEndPoints.get(indexL); - m_shape.setUserIndex(vertex, - m_userIndexSortedAngleIndexToVertex, -1);// remove - // mapping - } - - if (bCrossOverResolved) { - bModified = true; - continue; - } - - break; - } - - return bModified; - } - - private boolean _processCrossOvers(Point2D ptCenter) { - boolean bFound = false; - - // Resolve all overlaps - boolean bContinue = true; - while (bContinue) { - // The nearest pairts in the middle of the list - bContinue = false; - int index1 = 0; - if (m_bunchEdgeIndices.get(index1) == -1) - index1 = _getNextEdgeIndex(index1); - - int index2 = _getNextEdgeIndex(index1); - - for (int i = 0, n = m_bunchEdgeIndices.size(); i < n - && index1 != -1 && index2 != -1 && index1 != index2; i++) { - int edgeindex1 = m_bunchEdgeIndices.get(index1); - int edgeindex2 = m_bunchEdgeIndices.get(index2); - - int vertexB1 = m_bunchEdgeEndPoints.get(edgeindex1); - int vertexB2 = m_bunchEdgeEndPoints.get(edgeindex2); - // _ASSERT(vertexB2 != vertexB1); - - int vertexA1 = m_shape.getNextVertex(vertexB1); - if (!m_shape.isEqualXY(vertexA1, ptCenter)) - vertexA1 = m_shape.getPrevVertex(vertexB1); - int vertexA2 = m_shape.getNextVertex(vertexB2); - if (!m_shape.isEqualXY(vertexA2, ptCenter)) - vertexA2 = m_shape.getPrevVertex(vertexB2); - - // _ASSERT(m_shape.isEqualXY(vertexA1, vertexA2)); - // _ASSERT(m_shape.isEqualXY(vertexA1, ptCenter)); - - boolean bDirection1 = _getDirection(vertexA1, vertexB1); - boolean bDirection2 = _getDirection(vertexA2, vertexB2); - int vertexC1 = bDirection1 ? m_shape.getPrevVertex(vertexA1) - : m_shape.getNextVertex(vertexA1); - int vertexC2 = bDirection2 ? m_shape.getPrevVertex(vertexA2) - : m_shape.getNextVertex(vertexA2); - - boolean bOverlap = false; - if (_removeSpike(vertexA1)) - bOverlap = true; - else if (_removeSpike(vertexA2)) - bOverlap = true; - else if (_removeSpike(vertexB1)) - bOverlap = true; - else if (_removeSpike(vertexB2)) - bOverlap = true; - else if (_removeSpike(vertexC1)) - bOverlap = true; - else if (_removeSpike(vertexC2)) - bOverlap = true; - - if (!bOverlap && m_shape.isEqualXY(vertexB1, vertexB2)) { - bOverlap = true; - _resolveOverlap(bDirection1, bDirection2, vertexA1, - vertexB1, vertexA2, vertexB2); - } - - if (!bOverlap && m_shape.isEqualXY(vertexC1, vertexC2)) { - bOverlap = true; - _resolveOverlap(!bDirection1, !bDirection2, vertexA1, - vertexC1, vertexA2, vertexC2); - } - - if (bOverlap) - bFound = true; - - bContinue |= bOverlap; - - index1 = _getNextEdgeIndex(index1); - index2 = _getNextEdgeIndex(index1); - } - } - - if (!bFound) {// resolve all cross overs - int index1 = 0; - if (m_bunchEdgeIndices.get(index1) == -1) - index1 = _getNextEdgeIndex(index1); - - int index2 = _getNextEdgeIndex(index1); - - for (int i = 0, n = m_bunchEdgeIndices.size(); i < n - && index1 != -1 && index2 != -1 && index1 != index2; i++) { - int edgeindex1 = m_bunchEdgeIndices.get(index1); - int edgeindex2 = m_bunchEdgeIndices.get(index2); - - int vertexB1 = m_bunchEdgeEndPoints.get(edgeindex1); - int vertexB2 = m_bunchEdgeEndPoints.get(edgeindex2); - - int vertexA1 = m_shape.getNextVertex(vertexB1); - if (!m_shape.isEqualXY(vertexA1, ptCenter)) - vertexA1 = m_shape.getPrevVertex(vertexB1); - int vertexA2 = m_shape.getNextVertex(vertexB2); - if (!m_shape.isEqualXY(vertexA2, ptCenter)) - vertexA2 = m_shape.getPrevVertex(vertexB2); - - // _ASSERT(m_shape.isEqualXY(vertexA1, vertexA2)); - // _ASSERT(m_shape.isEqualXY(vertexA1, ptCenter)); - - boolean bDirection1 = _getDirection(vertexA1, vertexB1); - boolean bDirection2 = _getDirection(vertexA2, vertexB2); - int vertexC1 = bDirection1 ? m_shape.getPrevVertex(vertexA1) - : m_shape.getNextVertex(vertexA1); - int vertexC2 = bDirection2 ? m_shape.getPrevVertex(vertexA2) - : m_shape.getNextVertex(vertexA2); - - if (_detectAndResolveCrossOver(bDirection1, bDirection2, - vertexB1, vertexA1, vertexC1, vertexB2, vertexA2, - vertexC2)) { - bFound = true; - } - - index1 = _getNextEdgeIndex(index1); - index2 = _getNextEdgeIndex(index1); - } - } - - return bFound; - } - - static class SimplificatorVertexComparer extends - AttributeStreamOfInt32.IntComparator { - Simplificator m_parent; - - SimplificatorVertexComparer(Simplificator parent) { - m_parent = parent; - } - - @Override - public int compare(int v1, int v2) { - return m_parent._compareVerticesSimple(v1, v2); - } - - } - - private boolean _simplify() { - if (m_shape.getGeometryType(m_geometry) == Polygon.Type.Polygon.value() - && m_shape.getFillRule(m_geometry) == Polygon.FillRule.enumFillRuleWinding) - - { - TopologicalOperations ops = new TopologicalOperations(); - ops.planarSimplifyNoCrackingAndCluster(m_fixSelfTangency, - m_shape, m_geometry, m_progressTracker); - assert (m_shape.getFillRule(m_geometry) == Polygon.FillRule.enumFillRuleOddEven); - } - boolean bChanged = false; - boolean bNeedWindingRepeat = true; - boolean bWinding = false; - - m_userIndexSortedIndexToVertex = -1; - m_userIndexSortedAngleIndexToVertex = -1; - - int pointCount = m_shape.getPointCount(m_geometry); - - // Sort vertices lexicographically - // Firstly copy allvertices to an array. - AttributeStreamOfInt32 verticesSorter = new AttributeStreamOfInt32(0); - verticesSorter.reserve(pointCount); - - for (int path = m_shape.getFirstPath(m_geometry); path != -1; path = m_shape - .getNextPath(path)) { - int vertex = m_shape.getFirstVertex(path); - for (int index = 0, n = m_shape.getPathSize(path); index < n; index++) { - verticesSorter.add(vertex); - vertex = m_shape.getNextVertex(vertex); - } - } - - // Sort - verticesSorter.Sort(0, pointCount, - new SimplificatorVertexComparer(this)); - // SORTDYNAMICARRAYEX(verticesSorter, int, 0, pointCount, - // SimplificatorVertexComparer, this); - - // Copy sorted vertices to the m_sortedVertices list. Make a mapping - // from the edit shape vertices to the sorted vertices. - m_userIndexSortedIndexToVertex = m_shape.createUserIndex();// this index - // is used - // to map - // from edit - // shape - // vertex to - // the - // m_sortedVertices - // list - m_sortedVertices = new IndexMultiDCList(); - m_sortedVerticesListIndex = m_sortedVertices.createList(0); - for (int i = 0; i < pointCount; i++) { - int vertex = verticesSorter.get(i); - {// debug - Point2D pt = new Point2D(); - m_shape.getXY(vertex, pt);// for debugging - double y = pt.x; - } - int vertexlistIndex = m_sortedVertices.addElement( - m_sortedVerticesListIndex, vertex); - m_shape.setUserIndex(vertex, m_userIndexSortedIndexToVertex, - vertexlistIndex);// remember the sorted list element on the - // vertex. - // When we remove a vertex, we also remove associated sorted list - // element. - } - - m_userIndexSortedAngleIndexToVertex = m_shape.createUserIndex();// create - // additional - // list - // to - // store - // angular - // sort - // mapping. - - m_nextVertexToProcess = -1; - - if (_cleanupSpikes())// cleanup any spikes on the polygon. - bChanged = true; - - // External iteration loop for the simplificator. - // ST. I am not sure if it actually needs this loop. TODO: figure this - // out. - while (bNeedWindingRepeat) { - bNeedWindingRepeat = false; - - int max_iter = m_shape.getPointCount(m_geometry) + 10 > 30 ? 1000 - : (m_shape.getPointCount(m_geometry) + 10) - * (m_shape.getPointCount(m_geometry) + 10); - - // Simplify polygon - int iRepeatNum = 0; - boolean bNeedRepeat = false; - - // Internal iteration loop for the simplificator. - // ST. I am not sure if it actually needs this loop. TODO: figure - // this out. - do// while (bNeedRepeat); - { - bNeedRepeat = false; - - boolean bVertexRecheck = false; - m_firstCoincidentVertex = -1; - int coincidentCount = 0; - Point2D ptFirst = new Point2D(); - Point2D pt = new Point2D(); - // Main loop of the simplificator. Go through the vertices and - // for those that have same coordinates, - for (int vlistindex = m_sortedVertices - .getFirst(m_sortedVerticesListIndex); vlistindex != IndexMultiDCList - .nullNode(); ) { - int vertex = m_sortedVertices.getData(vlistindex); - {// debug - // Point2D pt = new Point2D(); - m_shape.getXY(vertex, pt); - double d = pt.x; - } - - if (m_firstCoincidentVertex != -1) { - // Point2D pt = new Point2D(); - m_shape.getXY(vertex, pt); - if (ptFirst.isEqual(pt)) { - coincidentCount++; - } else { - ptFirst.setCoords(pt); - m_nextVertexToProcess = vlistindex;// we remeber the - // next index in - // the member - // variable to - // allow it to - // be updated if - // a vertex is - // removed - // inside of the - // _ProcessBunch. - if (coincidentCount > 0) { - boolean result = _processBunch();// process a - // bunch of - // coinciding - // vertices - if (result) {// something has changed. - // Note that ProcessBunch may - // change m_nextVertexToProcess - // and m_firstCoincidentVertex. - bNeedRepeat = true; - if (m_nextVertexToProcess != IndexMultiDCList - .nullNode()) { - int v = m_sortedVertices - .getData(m_nextVertexToProcess); - m_shape.getXY(v, ptFirst); - } - } - } - - vlistindex = m_nextVertexToProcess; - m_firstCoincidentVertex = vlistindex; - coincidentCount = 0; - } - } else { - m_firstCoincidentVertex = vlistindex; - m_shape.getXY(m_sortedVertices.getData(vlistindex), - ptFirst); - coincidentCount = 0; - } - - if (vlistindex != -1)//vlistindex can be set to -1 after ProcessBunch call above - vlistindex = m_sortedVertices.getNext(vlistindex); - } - - m_nextVertexToProcess = -1; - - if (coincidentCount > 0) { - boolean result = _processBunch(); - if (result) - bNeedRepeat = true; - } - - if (iRepeatNum++ > 10) { - throw GeometryException.GeometryInternalError(); - } - - if (bNeedRepeat) - _fixOrphanVertices();// fix broken structure of the shape - - if (_cleanupSpikes()) - bNeedRepeat = true; - - bNeedWindingRepeat |= bNeedRepeat && bWinding; - - bChanged |= bNeedRepeat; - - } while (bNeedRepeat); - - }// while (bNeedWindingRepeat) - - // Now process rings. Fix ring orientation and determine rings that need - // to be deleted. - - m_shape.removeUserIndex(m_userIndexSortedIndexToVertex); - m_shape.removeUserIndex(m_userIndexSortedAngleIndexToVertex); - - bChanged |= RingOrientationFixer.execute(m_shape, m_geometry, - m_sortedVertices, m_fixSelfTangency); - - return bChanged; - } - - private boolean _getDirection(int vert1, int vert2) { - if (m_shape.getNextVertex(vert2) == vert1) { - // _ASSERT(m_shape.getPrevVertex(vert1) == vert2); - return false; - } else { - // _ASSERT(m_shape.getPrevVertex(vert2) == vert1); - // _ASSERT(m_shape.getNextVertex(vert1) == vert2); - return true; - } - } - - private boolean _detectAndResolveCrossOver(boolean bDirection1, - boolean bDirection2, int vertexB1, int vertexA1, int vertexC1, - int vertexB2, int vertexA2, int vertexC2) { - // _ASSERT(!m_shape.isEqualXY(vertexB1, vertexB2)); - // _ASSERT(!m_shape.isEqualXY(vertexC1, vertexC2)); - - if (vertexA1 == vertexA2) { - _removeAngleSortInfo(vertexB1); - _removeAngleSortInfo(vertexB2); - return false; - } - - // _ASSERT(!m_shape.isEqualXY(vertexB1, vertexC2)); - // _ASSERT(!m_shape.isEqualXY(vertexB1, vertexC1)); - // _ASSERT(!m_shape.isEqualXY(vertexB2, vertexC2)); - // _ASSERT(!m_shape.isEqualXY(vertexB2, vertexC1)); - // _ASSERT(!m_shape.isEqualXY(vertexA1, vertexB1)); - // _ASSERT(!m_shape.isEqualXY(vertexA1, vertexC1)); - // _ASSERT(!m_shape.isEqualXY(vertexA2, vertexB2)); - // _ASSERT(!m_shape.isEqualXY(vertexA2, vertexC2)); - - // _ASSERT(m_shape.isEqualXY(vertexA1, vertexA2)); - - // get indices of the vertices for the angle sort. - int iB1 = m_shape.getUserIndex(vertexB1, - m_userIndexSortedAngleIndexToVertex); - int iC1 = m_shape.getUserIndex(vertexC1, - m_userIndexSortedAngleIndexToVertex); - int iB2 = m_shape.getUserIndex(vertexB2, - m_userIndexSortedAngleIndexToVertex); - int iC2 = m_shape.getUserIndex(vertexC2, - m_userIndexSortedAngleIndexToVertex); - // _ASSERT(iB1 >= 0); - // _ASSERT(iC1 >= 0); - // _ASSERT(iB2 >= 0); - // _ASSERT(iC2 >= 0); - // Sort the indices to restore the angle-sort order - int[] ar = new int[8]; - int[] br = new int[4]; - - ar[0] = 0; - br[0] = iB1; - ar[1] = 0; - br[1] = iC1; - ar[2] = 1; - br[2] = iB2; - ar[3] = 1; - br[3] = iC2; - for (int j = 1; j < 4; j++)// insertion sort - { - int key = br[j]; - int data = ar[j]; - int i = j - 1; - while (i >= 0 && br[i] > key) { - br[i + 1] = br[i]; - ar[i + 1] = ar[i]; - i--; - } - br[i + 1] = key; - ar[i + 1] = data; - } - - int detector = 0; - if (ar[0] != 0) - detector |= 1; - if (ar[1] != 0) - detector |= 2; - if (ar[2] != 0) - detector |= 4; - if (ar[3] != 0) - detector |= 8; - if (detector != 5 && detector != 10)// not an overlap - return false; - - if (bDirection1 == bDirection2) { - if (bDirection1) { - m_shape.setNextVertex_(vertexC2, vertexA1); // B1< >B2 - m_shape.setPrevVertex_(vertexA1, vertexC2); // \ / - m_shape.setNextVertex_(vertexC1, vertexA2); // A1A2 - m_shape.setPrevVertex_(vertexA2, vertexC1); // / \ // - // C2> C1 - } - } else { - if (bDirection1) { - m_shape.setPrevVertex_(vertexA1, vertexB2); // B1< >B2 - m_shape.setPrevVertex_(vertexB2, vertexA1); // \ / - m_shape.setNextVertex_(vertexA2, vertexC1); // A1A2 - m_shape.setPrevVertex_(vertexC1, vertexA2); // / \ // - // C2> >C1 - - } - } - - return true; - } - - private void _resolveOverlap(boolean bDirection1, boolean bDirection2, - int vertexA1, int vertexB1, int vertexA2, int vertexB2) { - if (m_bWinding) { - _resolveOverlapWinding(bDirection1, bDirection2, vertexA1, - vertexB1, vertexA2, vertexB2); - } else { - _resolveOverlapOddEven(bDirection1, bDirection2, vertexA1, - vertexB1, vertexA2, vertexB2); - } - } - - private void _resolveOverlapWinding(boolean bDirection1, - boolean bDirection2, int vertexA1, int vertexB1, int vertexA2, - int vertexB2) { - throw new GeometryException("not implemented."); - } - - private void _resolveOverlapOddEven(boolean bDirection1, - boolean bDirection2, int vertexA1, int vertexB1, int vertexA2, - int vertexB2) { - if (bDirection1 != bDirection2) { - if (bDirection1) { - // _ASSERT(m_shape.getNextVertex(vertexA1) == vertexB1); - // _ASSERT(m_shape.getNextVertex(vertexB2) == vertexA2); - m_shape.setNextVertex_(vertexA1, vertexA2); // B1< B2 - m_shape.setPrevVertex_(vertexA2, vertexA1); // | | - m_shape.setNextVertex_(vertexB2, vertexB1); // | | - m_shape.setPrevVertex_(vertexB1, vertexB2); // A1 >A2 - - _transferVertexData(vertexA2, vertexA1); - _beforeRemoveVertex(vertexA2, true); - m_shape.removeVertexInternal_(vertexA2, true); - _removeAngleSortInfo(vertexA1); - _transferVertexData(vertexB2, vertexB1); - _beforeRemoveVertex(vertexB2, true); - m_shape.removeVertexInternal_(vertexB2, false); - _removeAngleSortInfo(vertexB1); - } else { - m_shape.setNextVertex_(vertexA2, vertexA1); // B1 B2< - m_shape.setPrevVertex_(vertexA1, vertexA2); // | | - m_shape.setNextVertex_(vertexB1, vertexB2); // | | - m_shape.setPrevVertex_(vertexB2, vertexB1); // A1< A2 - - _transferVertexData(vertexA2, vertexA1); - _beforeRemoveVertex(vertexA2, true); - m_shape.removeVertexInternal_(vertexA2, false); - _removeAngleSortInfo(vertexA1); - _transferVertexData(vertexB2, vertexB1); - _beforeRemoveVertex(vertexB2, true); - m_shape.removeVertexInternal_(vertexB2, true); - _removeAngleSortInfo(vertexB1); - } - } else// bDirection1 == bDirection2 - { - if (!bDirection1) { - // _ASSERT(m_shape.getNextVertex(vertexB1) == vertexA1); - // _ASSERT(m_shape.getNextVertex(vertexB2) == vertexA2); - } else { - // _ASSERT(m_shape.getNextVertex(vertexA1) == vertexB1); - // _ASSERT(m_shape.getNextVertex(vertexA2) == vertexB2); - } - - // if (m_shape._RingParentageCheckInternal(vertexA1, vertexA2)) - { - int a1 = bDirection1 ? vertexA1 : vertexB1; - int a2 = bDirection2 ? vertexA2 : vertexB2; - int b1 = bDirection1 ? vertexB1 : vertexA1; - int b2 = bDirection2 ? vertexB2 : vertexA2; - - // m_shape.dbgVerifyIntegrity(a1);//debug - // m_shape.dbgVerifyIntegrity(a2);//debug - - boolean bVisitedA1 = false; - m_shape.setNextVertex_(a1, a2); - m_shape.setNextVertex_(a2, a1); - m_shape.setPrevVertex_(b1, b2); - m_shape.setPrevVertex_(b2, b1); - int v = b2; - while (v != a2) { - int prev = m_shape.getPrevVertex(v); - int next = m_shape.getNextVertex(v); - - m_shape.setPrevVertex_(v, next); - m_shape.setNextVertex_(v, prev); - bVisitedA1 |= v == a1; - v = next; - } - - if (!bVisitedA1) { - // a case of two rings being merged - int prev = m_shape.getPrevVertex(a2); - int next = m_shape.getNextVertex(a2); - m_shape.setPrevVertex_(a2, next); - m_shape.setNextVertex_(a2, prev); - } else { - // merge happend on the same ring. - } - - // m_shape.dbgVerifyIntegrity(b1);//debug - // m_shape.dbgVerifyIntegrity(a1);//debug - - _transferVertexData(a2, a1); - _beforeRemoveVertex(a2, true); - m_shape.removeVertexInternal_(a2, false); - _removeAngleSortInfo(a1); - _transferVertexData(b2, b1); - _beforeRemoveVertex(b2, true); - m_shape.removeVertexInternal_(b2, false); - _removeAngleSortInfo(b1); - - // m_shape.dbgVerifyIntegrity(b1);//debug - // m_shape.dbgVerifyIntegrity(a1);//debug - } - } - } - - private boolean _cleanupSpikes() { - boolean bModified = false; - for (int path = m_shape.getFirstPath(m_geometry); path != -1; ) { - int vertex = m_shape.getFirstVertex(path); - for (int vindex = 0, n = m_shape.getPathSize(path); vindex < n - && n > 1; ) { - int prev = m_shape.getPrevVertex(vertex); - int next = m_shape.getNextVertex(vertex); - if (m_shape.isEqualXY(prev, next)) { - bModified = true; - _beforeRemoveVertex(vertex, false); - m_shape.removeVertex(vertex, true);// not internal, because - // path is valid at this - // point - _beforeRemoveVertex(next, false); - m_shape.removeVertex(next, true); - vertex = prev; - vindex = 0; - n = m_shape.getPathSize(path); - } else { - vertex = next; - vindex++; - } - } - - if (m_shape.getPathSize(path) < 2) { - int vertexL = m_shape.getFirstVertex(path); - for (int vindex = 0, n = m_shape.getPathSize(path); vindex < n; vindex++) { - _beforeRemoveVertex(vertexL, false); - vertexL = m_shape.getNextVertex(vertexL); - } - - path = m_shape.removePath(path); - bModified = true; - } else - path = m_shape.getNextPath(path); - } - - return bModified; - } - - private boolean _removeSpike(int vertexIn) { - // m_shape.dbgVerifyIntegrity(vertex);//debug - int vertex = vertexIn; - - // _ASSERT(m_shape.isEqualXY(m_shape.getNextVertex(vertex), - // m_shape.getPrevVertex(vertex))); - boolean bFound = false; - while (true) { - int next = m_shape.getNextVertex(vertex); - int prev = m_shape.getPrevVertex(vertex); - if (next == vertex) {// last vertex in a ring - _beforeRemoveVertex(vertex, true); - m_shape.removeVertexInternal_(vertex, false); - return true; - } - - if (!m_shape.isEqualXY(next, prev)) - break; - - bFound = true; - _removeAngleSortInfo(prev); - _removeAngleSortInfo(next); - _beforeRemoveVertex(vertex, true); - m_shape.removeVertexInternal_(vertex, false); - // m_shape.dbgVerifyIntegrity(prev);//debug - _transferVertexData(next, prev); - _beforeRemoveVertex(next, true); - m_shape.removeVertexInternal_(next, true); - if (next == prev) - break;// deleted the last vertex - - // m_shape.dbgVerifyIntegrity(prev);//debug - - vertex = prev; - } - return bFound; - } - - private void _fixOrphanVertices() { - int pathCount = 0; - // clean any path info - for (int node = m_sortedVertices.getFirst(m_sortedVertices - .getFirstList()); node != -1; node = m_sortedVertices - .getNext(node)) { - int vertex = m_sortedVertices.getData(node); - m_shape.setPathToVertex_(vertex, -1); - } - int geometrySize = 0; - for (int path = m_shape.getFirstPath(m_geometry); path != -1; ) { - int first = m_shape.getFirstVertex(path); - if (first == -1 || m_shape.getPathFromVertex(first) != -1) { - int p = path; - path = m_shape.getNextPath(path); - m_shape.removePathOnly_(p); - continue; - } - - m_shape.setPathToVertex_(first, path); - int pathSize = 1; - for (int vertex = m_shape.getNextVertex(first); vertex != first; vertex = m_shape - .getNextVertex(vertex)) { - m_shape.setPathToVertex_(vertex, path); - pathSize++; - } - m_shape.setRingAreaValid_(path, false); - m_shape.setPathSize_(path, pathSize); - m_shape.setLastVertex_(path, m_shape.getPrevVertex(first)); - geometrySize += pathSize; - pathCount++; - path = m_shape.getNextPath(path); - } - - // Some vertices do not belong to any path. We have to create new path - // objects for those. - // Produce new paths for the orphan vertices. - for (int node = m_sortedVertices.getFirst(m_sortedVertices - .getFirstList()); node != -1; node = m_sortedVertices - .getNext(node)) { - int vertex = m_sortedVertices.getData(node); - if (m_shape.getPathFromVertex(vertex) != -1) - continue; - - int path = m_shape.insertClosedPath_(m_geometry, -1, vertex, vertex, null); - geometrySize += m_shape.getPathSize(path); - pathCount++; - } - - m_shape.setGeometryPathCount_(m_geometry, pathCount); - m_shape.setGeometryVertexCount_(m_geometry, geometrySize); - int totalPointCount = 0; - for (int geometry = m_shape.getFirstGeometry(); geometry != -1; geometry = m_shape.getNextGeometry(geometry)) { - totalPointCount += m_shape.getPointCount(geometry); - } - - m_shape.setTotalPointCount_(totalPointCount); - } - - private int _getNextEdgeIndex(int indexIn) { - int index = indexIn; - for (int i = 0, n = m_bunchEdgeIndices.size() - 1; i < n; i++) { - index = (index + 1) % m_bunchEdgeIndices.size(); - if (m_bunchEdgeIndices.get(index) != -1) - return index; - } - return -1; - } - - private void _transferVertexData(int vertexFrom, int vertexTo) { - int v1 = m_shape.getUserIndex(vertexTo, m_userIndexSortedIndexToVertex); - int v2 = m_shape.getUserIndex(vertexTo, - m_userIndexSortedAngleIndexToVertex); - m_shape.transferAllDataToTheVertex(vertexFrom, vertexTo); - m_shape.setUserIndex(vertexTo, m_userIndexSortedIndexToVertex, v1); - m_shape.setUserIndex(vertexTo, m_userIndexSortedAngleIndexToVertex, v2); - } - - private void _removeAngleSortInfo(int vertex) { - int angleIndex = m_shape.getUserIndex(vertex, - m_userIndexSortedAngleIndexToVertex); - if (angleIndex != -1) { - m_bunchEdgeIndices.set(angleIndex, -1); - m_shape.setUserIndex(vertex, m_userIndexSortedAngleIndexToVertex, - -1); - } - } - - protected Simplificator() { - m_dbgCounter = 0; - } - - public static boolean execute(EditShape shape, int geometry, - int knownSimpleResult, boolean fixSelfTangency, ProgressTracker progressTracker) { - Simplificator simplificator = new Simplificator(); - simplificator.m_shape = shape; - // simplificator.m_bWinding = bWinding; - simplificator.m_geometry = geometry; - simplificator.m_knownSimpleResult = knownSimpleResult; - simplificator.m_fixSelfTangency = fixSelfTangency; - simplificator.m_progressTracker = progressTracker; - return simplificator._simplify(); - } - - int _compareVerticesSimple(int v1, int v2) { - Point2D pt1 = new Point2D(); - m_shape.getXY(v1, pt1); - Point2D pt2 = new Point2D(); - m_shape.getXY(v2, pt2); - int res = pt1.compare(pt2); - if (res == 0) {// sort equal vertices by the path ID - int i1 = m_shape.getPathFromVertex(v1); - int i2 = m_shape.getPathFromVertex(v2); - res = i1 < i2 ? -1 : (i1 == i2 ? 0 : 1); - } - - return res; - } - - int _compareAngles(int index1, int index2) { - int vert1 = m_bunchEdgeEndPoints.get(index1); - Point2D pt1 = new Point2D(); - m_shape.getXY(vert1, pt1); - Point2D pt2 = new Point2D(); - int vert2 = m_bunchEdgeEndPoints.get(index2); - m_shape.getXY(vert2, pt2); - - if (pt1.isEqual(pt2)) - return 0;// overlap case - - int vert10 = m_bunchEdgeCenterPoints.get(index1); - Point2D pt10 = new Point2D(); - m_shape.getXY(vert10, pt10); - - int vert20 = m_bunchEdgeCenterPoints.get(index2); - Point2D pt20 = new Point2D(); - m_shape.getXY(vert20, pt20); - // _ASSERT(pt10.isEqual(pt20)); - - Point2D v1 = new Point2D(); - v1.sub(pt1, pt10); - Point2D v2 = new Point2D(); - v2.sub(pt2, pt20); - int result = Point2D._compareVectors(v1, v2); - return result; - } + private EditShape m_shape; + private int m_geometry; + private IndexMultiDCList m_sortedVertices; + + private AttributeStreamOfInt32 m_bunchEdgeEndPoints; + private AttributeStreamOfInt32 m_bunchEdgeCenterPoints; + private AttributeStreamOfInt32 m_bunchEdgeIndices; + // private AttributeStreamOfInt32 m_orphanVertices; + + private int m_sortedVerticesListIndex; + private int m_userIndexSortedIndexToVertex; + private int m_userIndexSortedAngleIndexToVertex; + private int m_nextVertexToProcess; + private int m_firstCoincidentVertex; + //private int m_knownSimpleResult; + private boolean m_fixSelfTangency; + private ProgressTracker m_progressTracker; + private int[] m_ar = null; + private int[] m_br = null; + + private void _beforeRemoveVertex(int vertex, boolean bChangePathFirst) { + int vertexlistIndex = m_shape.getUserIndex(vertex, + m_userIndexSortedIndexToVertex); + + if (m_nextVertexToProcess == vertexlistIndex) { + m_nextVertexToProcess = m_sortedVertices + .getNext(m_nextVertexToProcess); + } + + if (m_firstCoincidentVertex == vertexlistIndex) + m_firstCoincidentVertex = m_sortedVertices + .getNext(m_firstCoincidentVertex); + + m_sortedVertices.deleteElement(m_sortedVerticesListIndex, + vertexlistIndex); + _removeAngleSortInfo(vertex); + if (bChangePathFirst) { + int path = m_shape.getPathFromVertex(vertex); + if (path != -1) { + int first = m_shape.getFirstVertex(path); + if (first == vertex) { + int next = m_shape.getNextVertex(vertex); + if (next != vertex) { + int p = m_shape.getPathFromVertex(next); + if (p == path) { + m_shape.setFirstVertex_(path, next); + return; + } + else { + int prev = m_shape.getPrevVertex(vertex); + if (prev != vertex) { + p = m_shape.getPathFromVertex(prev); + if (p == path) { + m_shape.setFirstVertex_(path, prev); + return; + } + } + } + } + + m_shape.setFirstVertex_(path, -1); + m_shape.setLastVertex_(path, -1); + } + } + } + } + + static private class SimplificatorAngleComparer extends + AttributeStreamOfInt32.IntComparator { + private Simplificator m_parent; + private Point2D pt1 = new Point2D(); + private Point2D pt2 = new Point2D(); + private Point2D pt10 = new Point2D(); + private Point2D pt20 = new Point2D(); + private Point2D v1 = new Point2D(); + private Point2D v2 = new Point2D(); + + public SimplificatorAngleComparer(Simplificator parent) { + m_parent = parent; + } + + @Override + public int compare(int v1, int v2) { + return _compareAngles(v1, v2); + } + + private int _compareAngles(int index1, int index2) { + int vert1 = m_parent.m_bunchEdgeEndPoints.get(index1); + m_parent.m_shape.getXY(vert1, pt1); + int vert2 = m_parent.m_bunchEdgeEndPoints.get(index2); + m_parent.m_shape.getXY(vert2, pt2); + + if (pt1.isEqual(pt2)) + return 0;// overlap case + + int vert10 = m_parent.m_bunchEdgeCenterPoints.get(index1); + m_parent.m_shape.getXY(vert10, pt10); + + int vert20 = m_parent.m_bunchEdgeCenterPoints.get(index2); + m_parent.m_shape.getXY(vert20, pt20); + + v1.sub(pt1, pt10); + v2.sub(pt2, pt20); + int result = Point2D._compareVectors(v1, v2); + return result; + } + } + + private boolean _processBunch() { + boolean bModified = false; + Point2D ptCenter = new Point2D(); + while (true) { + if (m_bunchEdgeEndPoints == null) { + m_bunchEdgeEndPoints = new AttributeStreamOfInt32(0); + m_bunchEdgeCenterPoints = new AttributeStreamOfInt32(0); + m_bunchEdgeIndices = new AttributeStreamOfInt32(0); + } else { + m_bunchEdgeEndPoints.clear(false); + m_bunchEdgeCenterPoints.clear(false); + m_bunchEdgeIndices.clear(false); + } + + int currentVertex = m_firstCoincidentVertex; + int index = 0; + boolean bFirst = true; + while (currentVertex != m_nextVertexToProcess) { + int v = m_sortedVertices.getData(currentVertex); + if (bFirst) { + m_shape.getXY(v, ptCenter); + bFirst = false; + } + int vertP = m_shape.getPrevVertex(v); + int vertN = m_shape.getNextVertex(v); + + int id = m_shape.getUserIndex(vertP, + m_userIndexSortedAngleIndexToVertex); + if (id != 0xdeadbeef)// avoid adding a point twice + { + m_bunchEdgeEndPoints.add(vertP); + m_shape.setUserIndex(vertP, + m_userIndexSortedAngleIndexToVertex, 0xdeadbeef);// mark + // that + // it + // has + // been + // already + // added + m_bunchEdgeCenterPoints.add(v); + m_bunchEdgeIndices.add(index++); + } + + int id2 = m_shape.getUserIndex(vertN, + m_userIndexSortedAngleIndexToVertex); + if (id2 != 0xdeadbeef) // avoid adding a point twice + { + m_bunchEdgeEndPoints.add(vertN); + m_shape.setUserIndex(vertN, + m_userIndexSortedAngleIndexToVertex, 0xdeadbeef);// mark + // that + // it + // has + // been + // already + // added + m_bunchEdgeCenterPoints.add(v); + m_bunchEdgeIndices.add(index++); + } + + currentVertex = m_sortedVertices.getNext(currentVertex); + } + + if (m_bunchEdgeEndPoints.size() < 2) + break; + + // Sort the bunch edpoints by angle (angle between the axis x and + // the edge, connecting the endpoint with the bunch center) + m_bunchEdgeIndices.Sort(0, m_bunchEdgeIndices.size(), + new SimplificatorAngleComparer(this)); + + for (int i = 0, n = m_bunchEdgeIndices.size(); i < n; i++) { + int indexL = m_bunchEdgeIndices.get(i); + int vertex = m_bunchEdgeEndPoints.get(indexL); + m_shape.setUserIndex(vertex, + m_userIndexSortedAngleIndexToVertex, i);// rember the + // sort by angle + // order + } + + boolean bCrossOverResolved = _processCrossOvers(ptCenter);// see of + // there + // are + // crossing + // over + // edges. + for (int i = 0, n = m_bunchEdgeIndices.size(); i < n; i++) { + int indexL = m_bunchEdgeIndices.get(i); + if (indexL == -1) + continue; + int vertex = m_bunchEdgeEndPoints.get(indexL); + m_shape.setUserIndex(vertex, + m_userIndexSortedAngleIndexToVertex, -1);// remove + // mapping + } + + if (bCrossOverResolved) { + bModified = true; + continue; + } + + break; + } + + return bModified; + } + + private boolean _processCrossOvers(Point2D ptCenter) { + boolean bFound = false; + + // Resolve all overlaps + boolean bContinue = true; + while (bContinue) { + // The nearest pairts in the middle of the list + bContinue = false; + int index1 = 0; + if (m_bunchEdgeIndices.get(index1) == -1) + index1 = _getNextEdgeIndex(index1); + + int index2 = _getNextEdgeIndex(index1); + + for (int i = 0, n = m_bunchEdgeIndices.size(); i < n + && index1 != -1 && index2 != -1 && index1 != index2; i++) { + int edgeindex1 = m_bunchEdgeIndices.get(index1); + int edgeindex2 = m_bunchEdgeIndices.get(index2); + + int vertexB1 = m_bunchEdgeEndPoints.get(edgeindex1); + int vertexB2 = m_bunchEdgeEndPoints.get(edgeindex2); + + int vertexA1 = m_shape.getNextVertex(vertexB1); + if (!m_shape.isEqualXY(vertexA1, ptCenter)) + vertexA1 = m_shape.getPrevVertex(vertexB1); + int vertexA2 = m_shape.getNextVertex(vertexB2); + if (!m_shape.isEqualXY(vertexA2, ptCenter)) + vertexA2 = m_shape.getPrevVertex(vertexB2); + + boolean bDirection1 = _getDirection(vertexA1, vertexB1); + boolean bDirection2 = _getDirection(vertexA2, vertexB2); + int vertexC1 = bDirection1 ? m_shape.getPrevVertex(vertexA1) + : m_shape.getNextVertex(vertexA1); + int vertexC2 = bDirection2 ? m_shape.getPrevVertex(vertexA2) + : m_shape.getNextVertex(vertexA2); + + boolean bOverlap = false; + if (_removeSpike(vertexA1)) + bOverlap = true; + else if (_removeSpike(vertexA2)) + bOverlap = true; + else if (_removeSpike(vertexB1)) + bOverlap = true; + else if (_removeSpike(vertexB2)) + bOverlap = true; + else if (_removeSpike(vertexC1)) + bOverlap = true; + else if (_removeSpike(vertexC2)) + bOverlap = true; + + if (!bOverlap && m_shape.isEqualXY(vertexB1, vertexB2)) { + bOverlap = true; + _resolveOverlap(bDirection1, bDirection2, vertexA1, + vertexB1, vertexA2, vertexB2); + } + + if (!bOverlap && m_shape.isEqualXY(vertexC1, vertexC2)) { + bOverlap = true; + _resolveOverlap(!bDirection1, !bDirection2, vertexA1, + vertexC1, vertexA2, vertexC2); + } + + if (bOverlap) + bFound = true; + + bContinue |= bOverlap; + + index1 = _getNextEdgeIndex(index1); + index2 = _getNextEdgeIndex(index1); + } + } + + if (!bFound) {// resolve all cross overs + int index1 = 0; + if (m_bunchEdgeIndices.get(index1) == -1) + index1 = _getNextEdgeIndex(index1); + + int index2 = _getNextEdgeIndex(index1); + + for (int i = 0, n = m_bunchEdgeIndices.size(); i < n + && index1 != -1 && index2 != -1 && index1 != index2; i++) { + int edgeindex1 = m_bunchEdgeIndices.get(index1); + int edgeindex2 = m_bunchEdgeIndices.get(index2); + + int vertexB1 = m_bunchEdgeEndPoints.get(edgeindex1); + int vertexB2 = m_bunchEdgeEndPoints.get(edgeindex2); + + int vertexA1 = m_shape.getNextVertex(vertexB1); + if (!m_shape.isEqualXY(vertexA1, ptCenter)) + vertexA1 = m_shape.getPrevVertex(vertexB1); + int vertexA2 = m_shape.getNextVertex(vertexB2); + if (!m_shape.isEqualXY(vertexA2, ptCenter)) + vertexA2 = m_shape.getPrevVertex(vertexB2); + + boolean bDirection1 = _getDirection(vertexA1, vertexB1); + boolean bDirection2 = _getDirection(vertexA2, vertexB2); + int vertexC1 = bDirection1 ? m_shape.getPrevVertex(vertexA1) + : m_shape.getNextVertex(vertexA1); + int vertexC2 = bDirection2 ? m_shape.getPrevVertex(vertexA2) + : m_shape.getNextVertex(vertexA2); + + if (_detectAndResolveCrossOver(bDirection1, bDirection2, + vertexB1, vertexA1, vertexC1, vertexB2, vertexA2, + vertexC2)) { + bFound = true; + } + + index1 = _getNextEdgeIndex(index1); + index2 = _getNextEdgeIndex(index1); + } + } + + return bFound; + } + + static private class SimplificatorVertexComparer extends + AttributeStreamOfInt32.IntComparator { + private Simplificator m_parent; + private Point2D pt1 = new Point2D(); + private Point2D pt2 = new Point2D(); + + SimplificatorVertexComparer(Simplificator parent) { + m_parent = parent; + } + + @Override + public int compare(int v1, int v2) { + return _compareVerticesSimple(v1, v2); + } + + private int _compareVerticesSimple(int v1, int v2) { + m_parent.m_shape.getXY(v1, pt1); + m_parent.m_shape.getXY(v2, pt2); + int res = pt1.compare(pt2); + if (res == 0) {// sort equal vertices by the path ID + int i1 = m_parent.m_shape.getPathFromVertex(v1); + int i2 = m_parent.m_shape.getPathFromVertex(v2); + res = i1 < i2 ? -1 : (i1 == i2 ? 0 : 1); + } + + return res; + } + } + + private boolean _simplify() { + if (m_shape.getGeometryType(m_geometry) == Polygon.Type.Polygon.value() + && m_shape.getFillRule(m_geometry) == Polygon.FillRule.enumFillRuleWinding) + + { + TopologicalOperations ops = new TopologicalOperations(); + ops.planarSimplifyNoCrackingAndCluster(m_fixSelfTangency, + m_shape, m_geometry, m_progressTracker); + assert (m_shape.getFillRule(m_geometry) == Polygon.FillRule.enumFillRuleOddEven); + } + boolean bChanged = false; + + m_userIndexSortedIndexToVertex = -1; + m_userIndexSortedAngleIndexToVertex = -1; + + int pointCount = m_shape.getPointCount(m_geometry); + + // Sort vertices lexicographically + // Firstly copy allvertices to an array. + AttributeStreamOfInt32 verticesSorter = new AttributeStreamOfInt32(0); + verticesSorter.reserve(pointCount); + + for (int path = m_shape.getFirstPath(m_geometry); path != -1; path = m_shape + .getNextPath(path)) { + int vertex = m_shape.getFirstVertex(path); + for (int index = 0, n = m_shape.getPathSize(path); index < n; index++) { + verticesSorter.add(vertex); + vertex = m_shape.getNextVertex(vertex); + } + } + + // Sort + verticesSorter.Sort(0, pointCount, + new SimplificatorVertexComparer(this)); + + // Copy sorted vertices to the m_sortedVertices list. Make a mapping + // from the edit shape vertices to the sorted vertices. + m_userIndexSortedIndexToVertex = m_shape.createUserIndex();// this index + // is used + // to map + // from edit + // shape + // vertex to + // the + // m_sortedVertices + // list + m_sortedVertices = new IndexMultiDCList(); + m_sortedVerticesListIndex = m_sortedVertices.createList(0); + for (int i = 0; i < pointCount; i++) { + int vertex = verticesSorter.get(i); + int vertexlistIndex = m_sortedVertices.addElement( + m_sortedVerticesListIndex, vertex); + m_shape.setUserIndex(vertex, m_userIndexSortedIndexToVertex, + vertexlistIndex);// remember the sorted list element on the + // vertex. + // When we remove a vertex, we also remove associated sorted list + // element. + } + + m_userIndexSortedAngleIndexToVertex = m_shape.createUserIndex();// create + // additional + // list + // to + // store + // angular + // sort + // mapping. + + m_nextVertexToProcess = -1; + + if (_cleanupSpikes())// cleanup any spikes on the polygon. + bChanged = true; + + // Simplify polygon + int iRepeatNum = 0; + boolean bNeedRepeat = false; + + // Internal iteration loop for the simplificator. + // ST. I am not sure if it actually needs this loop. TODO: figure + // this out. + do// while (bNeedRepeat); + { + bNeedRepeat = false; + + m_firstCoincidentVertex = -1; + int coincidentCount = 0; + Point2D ptFirst = new Point2D(); + Point2D pt = new Point2D(); + // Main loop of the simplificator. Go through the vertices and + // for those that have same coordinates, + for (int vlistindex = m_sortedVertices + .getFirst(m_sortedVerticesListIndex); vlistindex != IndexMultiDCList + .nullNode();) { + int vertex = m_sortedVertices.getData(vlistindex); + + if (m_firstCoincidentVertex != -1) { + // Point2D pt = new Point2D(); + m_shape.getXY(vertex, pt); + if (ptFirst.isEqual(pt)) { + coincidentCount++; + } else { + ptFirst.setCoords(pt); + m_nextVertexToProcess = vlistindex;// we remeber the + // next index in + // the member + // variable to + // allow it to + // be updated if + // a vertex is + // removed + // inside of the + // _ProcessBunch. + if (coincidentCount > 0) { + boolean result = _processBunch();// process a + // bunch of + // coinciding + // vertices + if (result) {// something has changed. + // Note that ProcessBunch may + // change m_nextVertexToProcess + // and m_firstCoincidentVertex. + bNeedRepeat = true; + if (m_nextVertexToProcess != IndexMultiDCList + .nullNode()) { + int v = m_sortedVertices + .getData(m_nextVertexToProcess); + m_shape.getXY(v, ptFirst); + } + } + } + + vlistindex = m_nextVertexToProcess; + m_firstCoincidentVertex = vlistindex; + coincidentCount = 0; + } + } else { + m_firstCoincidentVertex = vlistindex; + m_shape.getXY(m_sortedVertices.getData(vlistindex), + ptFirst); + coincidentCount = 0; + } + + if (vlistindex != -1)//vlistindex can be set to -1 after ProcessBunch call above + vlistindex = m_sortedVertices.getNext(vlistindex); + } + + m_nextVertexToProcess = -1; + + if (coincidentCount > 0) { + boolean result = _processBunch(); + if (result) + bNeedRepeat = true; + } + + if (iRepeatNum++ > 10) { + throw GeometryException.GeometryInternalError(); + } + + if (bNeedRepeat) + _fixOrphanVertices();// fix broken structure of the shape + + if (_cleanupSpikes()) + bNeedRepeat = true; + + bChanged |= bNeedRepeat; + + } while (bNeedRepeat); + + // Now process rings. Fix ring orientation and determine rings that need + // to be deleted. + + m_shape.removeUserIndex(m_userIndexSortedIndexToVertex); + m_shape.removeUserIndex(m_userIndexSortedAngleIndexToVertex); + + bChanged |= RingOrientationFixer.execute(m_shape, m_geometry, + m_sortedVertices, m_fixSelfTangency); + + return bChanged; + } + + private boolean _getDirection(int vert1, int vert2) { + if (m_shape.getNextVertex(vert2) == vert1) { + return false; + } else { + return true; + } + } + + private boolean _detectAndResolveCrossOver(boolean bDirection1, + boolean bDirection2, int vertexB1, int vertexA1, int vertexC1, + int vertexB2, int vertexA2, int vertexC2) { + + if (vertexA1 == vertexA2) { + _removeAngleSortInfo(vertexB1); + _removeAngleSortInfo(vertexB2); + return false; + } + + // get indices of the vertices for the angle sort. + int iB1 = m_shape.getUserIndex(vertexB1, + m_userIndexSortedAngleIndexToVertex); + int iC1 = m_shape.getUserIndex(vertexC1, + m_userIndexSortedAngleIndexToVertex); + int iB2 = m_shape.getUserIndex(vertexB2, + m_userIndexSortedAngleIndexToVertex); + int iC2 = m_shape.getUserIndex(vertexC2, + m_userIndexSortedAngleIndexToVertex); + // Sort the indices to restore the angle-sort order + + if (m_ar == null) { + m_ar = new int[8]; + m_br = new int[4]; + } + m_ar[0] = 0; + m_br[0] = iB1; + m_ar[1] = 0; + m_br[1] = iC1; + m_ar[2] = 1; + m_br[2] = iB2; + m_ar[3] = 1; + m_br[3] = iC2; + for (int j = 1; j < 4; j++)// insertion sort + { + int key = m_br[j]; + int data = m_ar[j]; + int i = j - 1; + while (i >= 0 && m_br[i] > key) { + m_br[i + 1] = m_br[i]; + m_ar[i + 1] = m_ar[i]; + i--; + } + m_br[i + 1] = key; + m_ar[i + 1] = data; + } + + int detector = 0; + if (m_ar[0] != 0) + detector |= 1; + if (m_ar[1] != 0) + detector |= 2; + if (m_ar[2] != 0) + detector |= 4; + if (m_ar[3] != 0) + detector |= 8; + if (detector != 5 && detector != 10)// not an overlap + return false; + + if (bDirection1 == bDirection2) { + if (bDirection1) { + m_shape.setNextVertex_(vertexC2, vertexA1); // B1< >B2 + m_shape.setPrevVertex_(vertexA1, vertexC2); // \ / + m_shape.setNextVertex_(vertexC1, vertexA2); // A1A2 + m_shape.setPrevVertex_(vertexA2, vertexC1); // / \ // + // C2> C1 + } + } else { + if (bDirection1) { + m_shape.setPrevVertex_(vertexA1, vertexB2); // B1< >B2 + m_shape.setPrevVertex_(vertexB2, vertexA1); // \ / + m_shape.setNextVertex_(vertexA2, vertexC1); // A1A2 + m_shape.setPrevVertex_(vertexC1, vertexA2); // / \ // + // C2> >C1 + + } + } + + return true; + } + + private void _resolveOverlap(boolean bDirection1, boolean bDirection2, + int vertexA1, int vertexB1, int vertexA2, int vertexB2) { + _resolveOverlapOddEven(bDirection1, bDirection2, vertexA1, + vertexB1, vertexA2, vertexB2); + } + + private void _resolveOverlapOddEven(boolean bDirection1, + boolean bDirection2, int vertexA1, int vertexB1, int vertexA2, + int vertexB2) { + if (bDirection1 != bDirection2) { + if (bDirection1) { + m_shape.setNextVertex_(vertexA1, vertexA2); // B1< B2 + m_shape.setPrevVertex_(vertexA2, vertexA1); // | | + m_shape.setNextVertex_(vertexB2, vertexB1); // | | + m_shape.setPrevVertex_(vertexB1, vertexB2); // A1 >A2 + + _transferVertexData(vertexA2, vertexA1); + _beforeRemoveVertex(vertexA2, true); + m_shape.removeVertexInternal_(vertexA2, true); + _removeAngleSortInfo(vertexA1); + _transferVertexData(vertexB2, vertexB1); + _beforeRemoveVertex(vertexB2, true); + m_shape.removeVertexInternal_(vertexB2, false); + _removeAngleSortInfo(vertexB1); + } else { + m_shape.setNextVertex_(vertexA2, vertexA1); // B1 B2< + m_shape.setPrevVertex_(vertexA1, vertexA2); // | | + m_shape.setNextVertex_(vertexB1, vertexB2); // | | + m_shape.setPrevVertex_(vertexB2, vertexB1); // A1< A2 + + _transferVertexData(vertexA2, vertexA1); + _beforeRemoveVertex(vertexA2, true); + m_shape.removeVertexInternal_(vertexA2, false); + _removeAngleSortInfo(vertexA1); + _transferVertexData(vertexB2, vertexB1); + _beforeRemoveVertex(vertexB2, true); + m_shape.removeVertexInternal_(vertexB2, true); + _removeAngleSortInfo(vertexB1); + } + } else// bDirection1 == bDirection2 + { + { + int a1 = bDirection1 ? vertexA1 : vertexB1; + int a2 = bDirection2 ? vertexA2 : vertexB2; + int b1 = bDirection1 ? vertexB1 : vertexA1; + int b2 = bDirection2 ? vertexB2 : vertexA2; + + // m_shape.dbgVerifyIntegrity(a1);//debug + // m_shape.dbgVerifyIntegrity(a2);//debug + + boolean bVisitedA1 = false; + m_shape.setNextVertex_(a1, a2); + m_shape.setNextVertex_(a2, a1); + m_shape.setPrevVertex_(b1, b2); + m_shape.setPrevVertex_(b2, b1); + int v = b2; + while (v != a2) + { + int prev = m_shape.getPrevVertex(v); + int next = m_shape.getNextVertex(v); + + m_shape.setPrevVertex_(v, next); + m_shape.setNextVertex_(v, prev); + bVisitedA1 |= v == a1; + v = next; + } + + if (!bVisitedA1) { + // a case of two rings being merged + int prev = m_shape.getPrevVertex(a2); + int next = m_shape.getNextVertex(a2); + m_shape.setPrevVertex_(a2, next); + m_shape.setNextVertex_(a2, prev); + } else { + // merge happend on the same ring. + } + + // m_shape.dbgVerifyIntegrity(b1);//debug + // m_shape.dbgVerifyIntegrity(a1);//debug + + _transferVertexData(a2, a1); + _beforeRemoveVertex(a2, true); + m_shape.removeVertexInternal_(a2, false); + _removeAngleSortInfo(a1); + _transferVertexData(b2, b1); + _beforeRemoveVertex(b2, true); + m_shape.removeVertexInternal_(b2, false); + _removeAngleSortInfo(b1); + + // m_shape.dbgVerifyIntegrity(b1);//debug + // m_shape.dbgVerifyIntegrity(a1);//debug + } + } + } + + private boolean _cleanupSpikes() { + boolean bModified = false; + for (int path = m_shape.getFirstPath(m_geometry); path != -1;) { + int vertex = m_shape.getFirstVertex(path); + for (int vindex = 0, n = m_shape.getPathSize(path); vindex < n + && n > 1;) { + int prev = m_shape.getPrevVertex(vertex); + int next = m_shape.getNextVertex(vertex); + if (m_shape.isEqualXY(prev, next)) { + bModified = true; + _beforeRemoveVertex(vertex, false); + m_shape.removeVertex(vertex, true);// not internal, because + // path is valid at this + // point + _beforeRemoveVertex(next, false); + m_shape.removeVertex(next, true); + vertex = prev; + vindex = 0; + n = m_shape.getPathSize(path); + } else { + vertex = next; + vindex++; + } + } + + if (m_shape.getPathSize(path) < 2) { + int vertexL = m_shape.getFirstVertex(path); + for (int vindex = 0, n = m_shape.getPathSize(path); vindex < n; vindex++) { + _beforeRemoveVertex(vertexL, false); + vertexL = m_shape.getNextVertex(vertexL); + } + + path = m_shape.removePath(path); + bModified = true; + } else + path = m_shape.getNextPath(path); + } + + return bModified; + } + + private boolean _removeSpike(int vertexIn) { + // m_shape.dbgVerifyIntegrity(vertex);//debug + int vertex = vertexIn; + + // m_shape.getPrevVertex(vertex))); + boolean bFound = false; + while (true) { + int next = m_shape.getNextVertex(vertex); + int prev = m_shape.getPrevVertex(vertex); + if (next == vertex) {// last vertex in a ring + _beforeRemoveVertex(vertex, true); + m_shape.removeVertexInternal_(vertex, false); + return true; + } + + if (!m_shape.isEqualXY(next, prev)) + break; + + bFound = true; + _removeAngleSortInfo(prev); + _removeAngleSortInfo(next); + _beforeRemoveVertex(vertex, true); + m_shape.removeVertexInternal_(vertex, false); + // m_shape.dbgVerifyIntegrity(prev);//debug + _transferVertexData(next, prev); + _beforeRemoveVertex(next, true); + m_shape.removeVertexInternal_(next, true); + if (next == prev) + break;// deleted the last vertex + + // m_shape.dbgVerifyIntegrity(prev);//debug + + vertex = prev; + } + return bFound; + } + + private void _fixOrphanVertices() { + int pathCount = 0; + // clean any path info + for (int node = m_sortedVertices.getFirst(m_sortedVertices + .getFirstList()); node != -1; node = m_sortedVertices + .getNext(node)) { + int vertex = m_sortedVertices.getData(node); + m_shape.setPathToVertex_(vertex, -1); + } + int geometrySize = 0; + for (int path = m_shape.getFirstPath(m_geometry); path != -1;) { + int first = m_shape.getFirstVertex(path); + if (first == -1 || m_shape.getPathFromVertex(first) != -1) { + int p = path; + path = m_shape.getNextPath(path); + m_shape.removePathOnly_(p); + continue; + } + + m_shape.setPathToVertex_(first, path); + int pathSize = 1; + for (int vertex = m_shape.getNextVertex(first); vertex != first; vertex = m_shape + .getNextVertex(vertex)) { + m_shape.setPathToVertex_(vertex, path); + pathSize++; + } + m_shape.setRingAreaValid_(path,false); + m_shape.setPathSize_(path, pathSize); + m_shape.setLastVertex_(path, m_shape.getPrevVertex(first)); + geometrySize += pathSize; + pathCount++; + path = m_shape.getNextPath(path); + } + + // Some vertices do not belong to any path. We have to create new path + // objects for those. + // Produce new paths for the orphan vertices. + for (int node = m_sortedVertices.getFirst(m_sortedVertices + .getFirstList()); node != -1; node = m_sortedVertices + .getNext(node)) { + int vertex = m_sortedVertices.getData(node); + if (m_shape.getPathFromVertex(vertex) != -1) + continue; + + int path = m_shape.insertClosedPath_(m_geometry, -1, vertex, vertex, null); + geometrySize += m_shape.getPathSize(path); + pathCount++; + } + + m_shape.setGeometryPathCount_(m_geometry, pathCount); + m_shape.setGeometryVertexCount_(m_geometry, geometrySize); + int totalPointCount = 0; + for (int geometry = m_shape.getFirstGeometry(); geometry != -1; geometry = m_shape.getNextGeometry(geometry)) { + totalPointCount += m_shape.getPointCount(geometry); + } + + m_shape.setTotalPointCount_(totalPointCount); + } + + private int _getNextEdgeIndex(int indexIn) { + int index = indexIn; + for (int i = 0, n = m_bunchEdgeIndices.size() - 1; i < n; i++) { + index = (index + 1) % m_bunchEdgeIndices.size(); + if (m_bunchEdgeIndices.get(index) != -1) + return index; + } + return -1; + } + + private void _transferVertexData(int vertexFrom, int vertexTo) { + int v1 = m_shape.getUserIndex(vertexTo, m_userIndexSortedIndexToVertex); + int v2 = m_shape.getUserIndex(vertexTo, + m_userIndexSortedAngleIndexToVertex); + m_shape.transferAllDataToTheVertex(vertexFrom, vertexTo); + m_shape.setUserIndex(vertexTo, m_userIndexSortedIndexToVertex, v1); + m_shape.setUserIndex(vertexTo, m_userIndexSortedAngleIndexToVertex, v2); + } + + private void _removeAngleSortInfo(int vertex) { + int angleIndex = m_shape.getUserIndex(vertex, + m_userIndexSortedAngleIndexToVertex); + if (angleIndex != -1) { + m_bunchEdgeIndices.set(angleIndex, -1); + m_shape.setUserIndex(vertex, m_userIndexSortedAngleIndexToVertex, + -1); + } + } + + protected Simplificator() { + } + + public static boolean execute(EditShape shape, int geometry, + int knownSimpleResult, boolean fixSelfTangency, ProgressTracker progressTracker) { + Simplificator simplificator = new Simplificator(); + simplificator.m_shape = shape; + simplificator.m_geometry = geometry; + //simplificator.m_knownSimpleResult = knownSimpleResult; + simplificator.m_fixSelfTangency = fixSelfTangency; + simplificator.m_progressTracker = progressTracker; + return simplificator._simplify(); + } } diff --git a/src/main/java/com/esri/core/geometry/SizeOf.java b/src/main/java/com/esri/core/geometry/SizeOf.java index 43cc05cb..4de3f4c3 100644 --- a/src/main/java/com/esri/core/geometry/SizeOf.java +++ b/src/main/java/com/esri/core/geometry/SizeOf.java @@ -53,7 +53,7 @@ public final class SizeOf { static final int SIZE_OF_MULTI_POINT_IMPL = 56; - static final int SIZE_OF_POINT = 24; + static final int SIZE_OF_POINT = 40; static final int SIZE_OF_POLYGON = 24; @@ -72,14 +72,30 @@ public final class SizeOf { public static final int SIZE_OF_OGC_POINT = 24; public static final int SIZE_OF_OGC_POLYGON = 24; - - static final int SIZE_OF_MAPGEOMETRY = 24; - static long sizeOfByteArray(int length) { + public static final int SIZE_OF_MAPGEOMETRY = 24; + + public static final int SIZE_OF_RASTERIZED_GEOMETRY_2D_IMPL = 112; + + public static final int SIZE_OF_SCAN_CALLBACK_IMPL = 32; + + public static final int SIZE_OF_TRANSFORMATION_2D = 64; + + public static final int SIZE_OF_SIMPLE_RASTERIZER = 64; + + public static final int SIZE_OF_EDGE = 48; + + public static final int SIZE_OF_QUAD_TREE_IMPL = 48; + + public static final int SIZE_OF_DATA = 24; + + public static final int SIZE_OF_STRIDED_INDEX_TYPE_COLLECTION = 48; + + public static long sizeOfByteArray(int length) { return Unsafe.ARRAY_BYTE_BASE_OFFSET + (((long) Unsafe.ARRAY_BYTE_INDEX_SCALE) * length); } - static long sizeOfShortArray(int length) { + public static long sizeOfShortArray(int length) { return Unsafe.ARRAY_SHORT_BASE_OFFSET + (((long) Unsafe.ARRAY_SHORT_INDEX_SCALE) * length); } @@ -87,22 +103,27 @@ public static long sizeOfCharArray(int length) { return Unsafe.ARRAY_CHAR_BASE_OFFSET + (((long) Unsafe.ARRAY_CHAR_INDEX_SCALE) * length); } - static long sizeOfIntArray(int length) { + public static long sizeOfIntArray(int length) { return Unsafe.ARRAY_INT_BASE_OFFSET + (((long) Unsafe.ARRAY_INT_INDEX_SCALE) * length); } - static long sizeOfLongArray(int length) { + public static long sizeOfLongArray(int length) { return Unsafe.ARRAY_LONG_BASE_OFFSET + (((long) Unsafe.ARRAY_LONG_INDEX_SCALE) * length); } - static long sizeOfFloatArray(int length) { + public static long sizeOfFloatArray(int length) { return Unsafe.ARRAY_FLOAT_BASE_OFFSET + (((long) Unsafe.ARRAY_FLOAT_INDEX_SCALE) * length); } - static long sizeOfDoubleArray(int length) { + public static long sizeOfDoubleArray(int length) { return Unsafe.ARRAY_DOUBLE_BASE_OFFSET + (((long) Unsafe.ARRAY_DOUBLE_INDEX_SCALE) * length); } + public static long sizeOfObjectArray(int length) + { + return Unsafe.ARRAY_OBJECT_BASE_OFFSET + (((long) Unsafe.ARRAY_OBJECT_INDEX_SCALE) * length); + } + private SizeOf() { } } diff --git a/src/main/java/com/esri/core/geometry/SpatialReference.java b/src/main/java/com/esri/core/geometry/SpatialReference.java index 8f251f9b..fb06195e 100644 --- a/src/main/java/com/esri/core/geometry/SpatialReference.java +++ b/src/main/java/com/esri/core/geometry/SpatialReference.java @@ -35,282 +35,283 @@ * This class provide tolerance value for the topological and relational operations. */ public abstract class SpatialReference implements Serializable { - // Note: We use writeReplace with SpatialReferenceSerializer. This field is - // irrelevant. Needs to be removed after final. - private static final long serialVersionUID = 2L; - - enum CoordinateSystemType { - Uknown, Local, GEOGRAPHIC, PROJECTED - } - - /** - * Creates an instance of the spatial reference based on the provided well - * known ID for the horizontal coordinate system. - * - * @param wkid The well-known ID. - * @return SpatialReference The spatial reference. - * @throws IllegalArgumentException if wkid is not supported or does not exist. - */ - public static SpatialReference create(int wkid) { - SpatialReferenceImpl spatRef = SpatialReferenceImpl.createImpl(wkid); - return spatRef; - } - - /** - * From a lat long wgs84 geometry, get the utm zone for the geometries center - * @param geometry - * @return - */ - public static SpatialReference createUTM(Geometry geometry) { - // TODO this will fail for multipart geometries on either side of the dateline - Envelope envelope = new Envelope(); - geometry.queryEnvelope(envelope); - - // if the geometry is outside of the -180 to 180 range shift it back into range - Point point = (Point)OperatorProjectLocal.foldInto360Range(envelope.getCenter(), SpatialReference.create(4326)); - return createUTM(point.getX(), point.getY()); - } - - /** - * choose the UTM zone that contains the longitude and latitude - * @param longitude - * @param latitude - * @return - */ - public static SpatialReference createUTM(double longitude, double latitude) { - // epsg code for N1 32601 - int epsg_code = 32601; - if (latitude < 0) { - // epsg code for S1 32701 - epsg_code += 100; - } - - double diff = longitude + 180.0; - - // TODO ugly - if (diff == 0.0) { - return SpatialReference.create(epsg_code); - } - - // 6 degrees of separation between zones, started with zone one, so subtract 1 - Double interval_count = Math.ceil(diff / 6); - int bump = interval_count.intValue() - 1; - - return SpatialReference.create(epsg_code + bump); - } - - public static SpatialReference createEqualArea(double lon_0, double lat_0) { - // create projection transformation that goes from input to input's equal area azimuthal projection - // +proj=laea +lat_0=52 +lon_0=10 +x_0=4321000 +y_0=3210000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs - String proj4 = String.format( - "+proj=laea +lat_0=%f +lon_0=%f +x_0=4321000 +y_0=3210000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs", - lat_0, - lon_0); - return SpatialReference.createFromProj4(proj4); - } - - public static SpatialReference createEqualArea(Geometry geometry, SpatialReference spatialReference) { - Point2D ptCenter = GeoDist.getEnvCenter(geometry, spatialReference); - double longitude = ptCenter.x; - double latitude = ptCenter.y; - - return createEqualArea(longitude, latitude); - } - - /** - * Creates an instance of the spatial reference based on the provided well - * known text representation for the horizontal coordinate system. - * - * @param wktext The well-known text string representation of spatial - * reference. - * @return SpatialReference The spatial reference. - */ - public static SpatialReference create(String wktext) { - return SpatialReferenceImpl.createImpl(wktext); - } - - - - public static SpatialReference createFromProj4(String proj4test) { - return SpatialReferenceImpl.createFromProj4Impl(proj4test); - } - - /** - * @return boolean Is spatial reference local? - */ - boolean isLocal() { - return false; - } - - /** - * Returns spatial reference from the JsonParser. - * - * @param parser The JSON parser. - * @return The spatial reference or null if there is no spatial reference - * information, or the parser does not point to an object start. - * @throws Exception if parsing has failed - */ - public static SpatialReference fromJson(JsonParser parser) throws Exception { - return fromJson(new JsonParserReader(parser)); - } - - public static SpatialReference fromJson(String string) throws Exception { - return fromJson(JsonParserReader.createFromString(string)); - } - - public static SpatialReference fromJson(JsonReader parser) throws Exception { - // Note this class is processed specially: it is expected that the - // iterator points to the first element of the SR object. - boolean bFoundWkid = false; - boolean bFoundLatestWkid = false; - boolean bFoundVcsWkid = false; - boolean bFoundLatestVcsWkid = false; - boolean bFoundWkt = false; - - int wkid = -1; - int latestWkid = -1; - int vcs_wkid = -1; - int latestVcsWkid = -1; - String wkt = null; - while (parser.nextToken() != JsonReader.Token.END_OBJECT) { - String name = parser.currentString(); - parser.nextToken(); - - if (!bFoundWkid && name.equals("wkid")) { - bFoundWkid = true; - - if (parser.currentToken() == JsonReader.Token.VALUE_NUMBER_INT) - wkid = parser.currentIntValue(); - } else if (!bFoundLatestWkid && name.equals("latestWkid")) { - bFoundLatestWkid = true; - - if (parser.currentToken() == JsonReader.Token.VALUE_NUMBER_INT) - latestWkid = parser.currentIntValue(); - } else if (!bFoundWkt && name.equals("wkt")) { - bFoundWkt = true; - - if (parser.currentToken() == JsonReader.Token.VALUE_STRING) - wkt = parser.currentString(); - } else if (!bFoundVcsWkid && name.equals("vcsWkid")) { - bFoundVcsWkid = true; - - if (parser.currentToken() == JsonReader.Token.VALUE_NUMBER_INT) - vcs_wkid = parser.currentIntValue(); - } else if (!bFoundLatestVcsWkid && name.equals("latestVcsWkid")) { - bFoundLatestVcsWkid = true; - - if (parser.currentToken() == JsonReader.Token.VALUE_NUMBER_INT) - latestVcsWkid = parser.currentIntValue(); - } - } - - if (latestVcsWkid <= 0 && vcs_wkid > 0) { - latestVcsWkid = vcs_wkid; - } - - // iter.step_out_after(); do not step out for the spatial reference, - // because this method is used standalone - - SpatialReference spatial_reference = null; - - if (wkt != null && wkt.length() != 0) { - try { - spatial_reference = SpatialReference.create(wkt); - } catch (Exception e) { - } - } - - if (spatial_reference == null && latestWkid > 0) { - try { - spatial_reference = SpatialReference.create(latestWkid); - } catch (Exception e) { - } - } - - if (spatial_reference == null && wkid > 0) { - try { - spatial_reference = SpatialReference.create(wkid); - } catch (Exception e) { - } - } - - return spatial_reference; - } - - /** - * Returns the well known ID for the horizontal coordinate system of the - * spatial reference. - * - * @return wkid The well known ID. - */ - public abstract int getID(); - - public abstract String getText(); - - public abstract String getProj4(); - - - public abstract double getMajorAxis(); - - public abstract double getEccentricitySquared(); - - /** - * Returns the oldest value of the well known ID for the horizontal - * coordinate system of the spatial reference. This ID is used for JSON - * serialization. Not public. - */ - abstract int getOldID(); - - /** - * Returns the latest value of the well known ID for the horizontal - * coordinate system of the spatial reference. This ID is used for JSON - * serialization. Not public. - */ - abstract int getLatestID(); - - /** - * Returns the XY tolerance of the spatial reference. - *

- * The tolerance value defines the precision of topological operations, and - * "thickness" of boundaries of geometries for relational operations. - *

- * When two points have xy coordinates closer than the tolerance value, they - * are considered equal. As well as when a point is within tolerance from - * the line, the point is assumed to be on the line. - *

- * During topological operations the tolerance is increased by a factor of - * about 1.41 and any two points within that distance are snapped - * together. - * - * @return The XY tolerance of the spatial reference. - */ - public double getTolerance() { - return getTolerance(VertexDescription.Semantics.POSITION); - } - - /** - * Get the XY tolerance of the spatial reference - * - * @return The XY tolerance of the spatial reference as double. - */ - abstract double getTolerance(int semantics); - - Object writeReplace() throws ObjectStreamException { - SpatialReferenceSerializer srSerializer = new SpatialReferenceSerializer(); - srSerializer.setSpatialReferenceByValue(this); - return srSerializer; - } - - abstract CoordinateSystemType getCoordinateSystemType(); - - /** - * Returns string representation of the class for debugging purposes. The - * format and content of the returned string is not part of the contract of - * the method and is subject to change in any future release or patch - * without further notice. - */ - public String toString() { - return "[ tol: " + getTolerance() + "; wkid: " + getID() + "; wkt: " - + getText() + "]"; - } + // Note: We use writeReplace with SpatialReferenceSerializer. This field is + // irrelevant. Needs to be removed after final. + private static final long serialVersionUID = 2L; + + enum CoordinateSystemType { + Uknown, Local, GEOGRAPHIC, PROJECTED + } + + /** + * Creates an instance of the spatial reference based on the provided well + * known ID for the horizontal coordinate system. + * + * @param wkid The well-known ID. + * @return SpatialReference The spatial reference. + * @throws IllegalArgumentException if wkid is not supported or does not exist. + */ + public static SpatialReference create(int wkid) { + SpatialReferenceImpl spatRef = SpatialReferenceImpl.createImpl(wkid); + return spatRef; + } + + /** + * From a lat long wgs84 geometry, get the utm zone for the geometries center + * + * @param geometry + * @return + */ + public static SpatialReference createUTM(Geometry geometry) { + // TODO this will fail for multipart geometries on either side of the dateline + Envelope envelope = new Envelope(); + geometry.queryEnvelope(envelope); + + // if the geometry is outside of the -180 to 180 range shift it back into range + Point point = (Point) OperatorProjectLocal.foldInto360Range(envelope.getCenter(), SpatialReference.create(4326)); + return createUTM(point.getX(), point.getY()); + } + + /** + * choose the UTM zone that contains the longitude and latitude + * + * @param longitude + * @param latitude + * @return + */ + public static SpatialReference createUTM(double longitude, double latitude) { + // epsg code for N1 32601 + int epsg_code = 32601; + if (latitude < 0) { + // epsg code for S1 32701 + epsg_code += 100; + } + + double diff = longitude + 180.0; + + // TODO ugly + if (diff == 0.0) { + return SpatialReference.create(epsg_code); + } + + // 6 degrees of separation between zones, started with zone one, so subtract 1 + Double interval_count = Math.ceil(diff / 6); + int bump = interval_count.intValue() - 1; + + return SpatialReference.create(epsg_code + bump); + } + + public static SpatialReference createEqualArea(double lon_0, double lat_0) { + // create projection transformation that goes from input to input's equal area azimuthal projection + // +proj=laea +lat_0=52 +lon_0=10 +x_0=4321000 +y_0=3210000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs + String proj4 = String.format( + "+proj=laea +lat_0=%f +lon_0=%f +x_0=4321000 +y_0=3210000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs", + lat_0, + lon_0); + return SpatialReference.createFromProj4(proj4); + } + + public static SpatialReference createEqualArea(Geometry geometry, SpatialReference spatialReference) { + Point2D ptCenter = GeoDist.getEnvCenter(geometry, spatialReference); + double longitude = ptCenter.x; + double latitude = ptCenter.y; + + return createEqualArea(longitude, latitude); + } + + /** + * Creates an instance of the spatial reference based on the provided well + * known text representation for the horizontal coordinate system. + * + * @param wktext The well-known text string representation of spatial + * reference. + * @return SpatialReference The spatial reference. + */ + public static SpatialReference create(String wktext) { + return SpatialReferenceImpl.createImpl(wktext); + } + + + public static SpatialReference createFromProj4(String proj4test) { + return SpatialReferenceImpl.createFromProj4Impl(proj4test); + } + + /** + * @return boolean Is spatial reference local? + */ + boolean isLocal() { + return false; + } + + /** + * Returns spatial reference from the JsonParser. + * + * @param parser The JSON parser. + * @return The spatial reference or null if there is no spatial reference + * information, or the parser does not point to an object start. + * @throws Exception if parsing has failed + */ + public static SpatialReference fromJson(JsonParser parser) throws Exception { + return fromJson(new JsonParserReader(parser)); + } + + public static SpatialReference fromJson(String string) throws Exception { + return fromJson(JsonParserReader.createFromString(string)); + } + + public static SpatialReference fromJson(JsonReader parser) throws Exception { + // Note this class is processed specially: it is expected that the + // iterator points to the first element of the SR object. + boolean bFoundWkid = false; + boolean bFoundLatestWkid = false; + boolean bFoundVcsWkid = false; + boolean bFoundLatestVcsWkid = false; + boolean bFoundWkt = false; + + int wkid = -1; + int latestWkid = -1; + int vcs_wkid = -1; + int latestVcsWkid = -1; + String wkt = null; + while (parser.nextToken() != JsonReader.Token.END_OBJECT) { + String name = parser.currentString(); + parser.nextToken(); + + if (!bFoundWkid && name.equals("wkid")) { + bFoundWkid = true; + + if (parser.currentToken() == JsonReader.Token.VALUE_NUMBER_INT) + wkid = parser.currentIntValue(); + } else if (!bFoundLatestWkid && name.equals("latestWkid")) { + bFoundLatestWkid = true; + + if (parser.currentToken() == JsonReader.Token.VALUE_NUMBER_INT) + latestWkid = parser.currentIntValue(); + } else if (!bFoundWkt && name.equals("wkt")) { + bFoundWkt = true; + + if (parser.currentToken() == JsonReader.Token.VALUE_STRING) + wkt = parser.currentString(); + } else if (!bFoundVcsWkid && name.equals("vcsWkid")) { + bFoundVcsWkid = true; + + if (parser.currentToken() == JsonReader.Token.VALUE_NUMBER_INT) + vcs_wkid = parser.currentIntValue(); + } else if (!bFoundLatestVcsWkid && name.equals("latestVcsWkid")) { + bFoundLatestVcsWkid = true; + + if (parser.currentToken() == JsonReader.Token.VALUE_NUMBER_INT) + latestVcsWkid = parser.currentIntValue(); + } + } + + if (latestVcsWkid <= 0 && vcs_wkid > 0) { + latestVcsWkid = vcs_wkid; + } + + // iter.step_out_after(); do not step out for the spatial reference, + // because this method is used standalone + + SpatialReference spatial_reference = null; + + if (wkt != null && wkt.length() != 0) { + try { + spatial_reference = SpatialReference.create(wkt); + } catch (Exception e) { + } + } + + if (spatial_reference == null && latestWkid > 0) { + try { + spatial_reference = SpatialReference.create(latestWkid); + } catch (Exception e) { + } + } + + if (spatial_reference == null && wkid > 0) { + try { + spatial_reference = SpatialReference.create(wkid); + } catch (Exception e) { + } + } + + return spatial_reference; + } + + /** + * Returns the well known ID for the horizontal coordinate system of the + * spatial reference. + * + * @return wkid The well known ID. + */ + public abstract int getID(); + + public abstract String getText(); + + public abstract String getProj4(); + + + public abstract double getMajorAxis(); + + public abstract double getEccentricitySquared(); + + /** + * Returns the oldest value of the well known ID for the horizontal + * coordinate system of the spatial reference. This ID is used for JSON + * serialization. Not public. + */ + abstract int getOldID(); + + /** + * Returns the latest value of the well known ID for the horizontal + * coordinate system of the spatial reference. This ID is used for JSON + * serialization. Not public. + */ + abstract int getLatestID(); + + /** + * Returns the XY tolerance of the spatial reference. + *

+ * The tolerance value defines the precision of topological operations, and + * "thickness" of boundaries of geometries for relational operations. + *

+ * When two points have xy coordinates closer than the tolerance value, they + * are considered equal. As well as when a point is within tolerance from + * the line, the point is assumed to be on the line. + *

+ * During topological operations the tolerance is increased by a factor of + * about 1.41 and any two points within that distance are snapped + * together. + * + * @return The XY tolerance of the spatial reference. + */ + public double getTolerance() { + return getTolerance(VertexDescription.Semantics.POSITION); + } + + /** + * Get the XY tolerance of the spatial reference + * + * @return The XY tolerance of the spatial reference as double. + */ + abstract double getTolerance(int semantics); + + Object writeReplace() throws ObjectStreamException { + SpatialReferenceSerializer srSerializer = new SpatialReferenceSerializer(); + srSerializer.setSpatialReferenceByValue(this); + return srSerializer; + } + + abstract CoordinateSystemType getCoordinateSystemType(); + + /** + * Returns string representation of the class for debugging purposes. The + * format and content of the returned string is not part of the contract of + * the method and is subject to change in any future release or patch + * without further notice. + */ + public String toString() { + return "[ tol: " + getTolerance() + "; wkid: " + getID() + "; wkt: " + + getText() + "]"; + } } diff --git a/src/main/java/com/esri/core/geometry/SpatialReferenceImpl.java b/src/main/java/com/esri/core/geometry/SpatialReferenceImpl.java index 14c15f96..87149a59 100644 --- a/src/main/java/com/esri/core/geometry/SpatialReferenceImpl.java +++ b/src/main/java/com/esri/core/geometry/SpatialReferenceImpl.java @@ -32,89 +32,89 @@ import org.proj4.PJ; class SpatialReferenceImpl extends SpatialReference { - public final static int c_SULIMIT32 = 2147483645; - public final static long c_SULIMIT64 = 9007199254740990L; - // https://regex101.com/r/F0FAUw/1 - public final static Pattern m_pattern = Pattern.compile("^([\\w\\W]+AUTHORITY[\\s]*\\[[\\s]*\"EPSG\"[\\s]*,[\\s]*[\"]*([\\d]+)[\"]*[\\s]*][\\s]*][\\s\\]]*)$"); - public final static Pattern m_proj4wkid = Pattern.compile("^\\+init=epsg:([\\d]+)"); - - - enum Precision { - Integer32, Integer64, FloatingPoint - } - - - int m_userWkid;// this wkid is provided by user to the create method. - int m_userLatestWkid; - int m_userOldestWkid; - String m_proj4; - String m_userWkt;// a string, the well-known text. - PJ m_pj; - double m_a; - double m_e2; - // public SgCoordRef m_sgCoordRef; - - private final static ReentrantLock m_lock = new ReentrantLock(); - - // TODO If one was going to create member object for locking it would be - // here. - SpatialReferenceImpl() { - m_userWkid = 0; - m_userLatestWkid = -1; - m_userOldestWkid = -1; - m_userWkt = null; - m_proj4 = null; - m_pj = null; - m_a = Double.NEGATIVE_INFINITY; - m_e2 = Double.NEGATIVE_INFINITY; - } - - @Override - public int getID() { - return m_userWkid; - } - - double getFalseX() { - return 0; - } - - double getFalseY() { - return 0; - } - - double getFalseZ() { - return 0; - } - - double getFalseM() { - return 0; - } - - double getGridUnitsXY() { - return 1 / (1.0e-9 * 0.0174532925199433/* getOneDegreeGCSUnit() */); - } - - double getGridUnitsZ() { - return 1 / 0.001; - } - - double getGridUnitsM() { - return 1 / 0.001; - } - - Precision getPrecision() { - return Precision.Integer64; - } - - - PJ getPJ() { - if (m_pj == null) { - m_pj = new PJ(this.getProj4()); - } - return m_pj; - } - - CoordinateSystemType getCoordinateSystemType() { + public final static int c_SULIMIT32 = 2147483645; + public final static long c_SULIMIT64 = 9007199254740990L; + // https://regex101.com/r/F0FAUw/1 + public final static Pattern m_pattern = Pattern.compile("^([\\w\\W]+AUTHORITY[\\s]*\\[[\\s]*\"EPSG\"[\\s]*,[\\s]*[\"]*([\\d]+)[\"]*[\\s]*][\\s]*][\\s\\]]*)$"); + public final static Pattern m_proj4wkid = Pattern.compile("^\\+init=epsg:([\\d]+)"); + + + enum Precision { + Integer32, Integer64, FloatingPoint + } + + + int m_userWkid;// this wkid is provided by user to the create method. + int m_userLatestWkid; + int m_userOldestWkid; + String m_proj4; + String m_userWkt;// a string, the well-known text. + PJ m_pj; + double m_a; + double m_e2; + // public SgCoordRef m_sgCoordRef; + + private final static ReentrantLock m_lock = new ReentrantLock(); + + // TODO If one was going to create member object for locking it would be + // here. + SpatialReferenceImpl() { + m_userWkid = 0; + m_userLatestWkid = -1; + m_userOldestWkid = -1; + m_userWkt = null; + m_proj4 = null; + m_pj = null; + m_a = Double.NEGATIVE_INFINITY; + m_e2 = Double.NEGATIVE_INFINITY; + } + + @Override + public int getID() { + return m_userWkid; + } + + double getFalseX() { + return 0; + } + + double getFalseY() { + return 0; + } + + double getFalseZ() { + return 0; + } + + double getFalseM() { + return 0; + } + + double getGridUnitsXY() { + return 1 / (1.0e-9 * 0.0174532925199433/* getOneDegreeGCSUnit() */); + } + + double getGridUnitsZ() { + return 1 / 0.001; + } + + double getGridUnitsM() { + return 1 / 0.001; + } + + Precision getPrecision() { + return Precision.Integer64; + } + + + PJ getPJ() { + if (m_pj == null) { + m_pj = new PJ(this.getProj4()); + } + return m_pj; + } + + CoordinateSystemType getCoordinateSystemType() { // if (m_userWkid != 0) { // if (Wkid.m_gcsToTol.containsKey(m_userWkid)) { // return CoordinateSystemType.GEOGRAPHIC; @@ -129,279 +129,279 @@ CoordinateSystemType getCoordinateSystemType() { // return CoordinateSystemType.PROJECTED; // } // } - // TODO GEOCENTRIC - if (m_userWkt != null) { - if (m_userWkt.contains("PROJCS")) { - return CoordinateSystemType.PROJECTED; - } else { - return CoordinateSystemType.GEOGRAPHIC; - } - - } - if (getPJ().getType() == PJ.Type.GEOGRAPHIC) { - return CoordinateSystemType.GEOGRAPHIC; - } else if (getPJ().getType() == PJ.Type.PROJECTED) { - return CoordinateSystemType.PROJECTED; - } - - return CoordinateSystemType.Uknown; - } - - @Override - double getTolerance(int semantics) { - double tolerance = 0.001; - if (m_userWkid != 0) { - tolerance = Wkid.find_tolerance_from_wkid(m_userWkid); - } else if (m_userWkt != null) { - tolerance = Wkt.find_tolerance_from_wkt(m_userWkt); - } - return tolerance; - } - - public void queryValidCoordinateRange(Envelope2D env2D) { - double delta = 0; - switch (getPrecision()) { - case Integer32: - delta = c_SULIMIT32 / getGridUnitsXY(); - break; - case Integer64: - delta = c_SULIMIT64 / getGridUnitsXY(); - break; - default: - // TODO - throw GeometryException.GeometryInternalError(); - } - - env2D.setCoords(getFalseX(), getFalseY(), getFalseX() + delta, - getFalseY() + delta); - } - - public boolean requiresReSimplify(SpatialReference dst) { - return dst != this; - } - - @Override - public String getText() { - return m_userWkt; - } - - - @Override - public String getProj4() { - return m_proj4; - } - - /** - * Returns the oldest value of the well known ID for the horizontal - * coordinate system of the spatial reference. This ID is used for JSON - * serialization. Not public. - */ - @Override - int getOldID() { - int ID_ = getID(); - - if (m_userOldestWkid != -1) - return m_userOldestWkid; - - m_userOldestWkid = Wkid.wkid_to_old(ID_); - - if (m_userOldestWkid != -1) - return m_userOldestWkid; - - return ID_; - } - - /** - * Returns the latest value of the well known ID for the horizontal - * coordinate system of the spatial reference. This ID is used for JSON - * serialization. Not public. - */ - @Override - int getLatestID() { - int ID_ = getID(); - - if (m_userLatestWkid != -1) - return m_userLatestWkid; - - m_userLatestWkid = Wkid.wkid_to_new(ID_); - - if (m_userLatestWkid != -1) - return m_userLatestWkid; - - return ID_; - } - - @Override - public double getMajorAxis() { - if (Double.isInfinite(m_a)) { - m_a = this.getPJ().getSemiMajorAxis(); - } - return m_a; - } - - @Override - public double getEccentricitySquared() { - if (Double.isInfinite(m_e2)) { - m_e2 = this.getPJ().getEccentricitySquared(); - } - return m_e2; - } - - public static SpatialReferenceImpl createImpl(int wkid) { - if (wkid <= 0) - throw new IllegalArgumentException("Invalid or unsupported wkid: " - + wkid); - - SpatialReferenceImpl spatRef = new SpatialReferenceImpl(); - spatRef.m_userWkid = wkid; - spatRef.m_proj4 = "+init=epsg:" + Integer.toString(wkid); - - return spatRef; - } - - public static SpatialReferenceImpl createImpl(String wkt) { - if (wkt == null || wkt.length() == 0) - throw new IllegalArgumentException( - "Cannot create SpatialReference from null or empty text."); - - int wkid = __wkid_from_wkt(wkt); - if (wkid == 0) { - SpatialReferenceImpl spatRef = new SpatialReferenceImpl(); - spatRef.m_userWkt = wkt; - return spatRef; - } - - return createImpl(wkid); - } - - private static int __wkid_from_wkt(String wkt) { - Matcher matcher = m_pattern.matcher(wkt); - if (matcher.find()) { - return Integer.parseInt(matcher.group(2)); - } - return 0; - } - - - protected static SpatialReferenceImpl createFromProj4Impl(String proj4Text) { - SpatialReferenceImpl spatRef = new SpatialReferenceImpl(); - spatRef.m_proj4 = proj4Text; - - Matcher matcher = m_proj4wkid.matcher(spatRef.m_proj4); - if (matcher.find()) { - spatRef.m_userWkid = Integer.parseInt(matcher.group(1)); - } - - return spatRef; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - - SpatialReferenceImpl sr = (SpatialReferenceImpl) obj; - if (m_userWkid != sr.m_userWkid) - return false; - - - if (m_userWkid == 0) { - if (m_userWkt != null && sr.m_userWkt != null && m_userWkt.equals(sr.m_userWkt)) { - return true; - } - - if (m_proj4 != null && sr.m_proj4 != null && m_proj4.equals(sr.m_proj4)) { - return true; - } - - if ((m_proj4 != null || m_userWkt != null) && (sr.m_proj4 != null || sr.m_userWkt != null)) { - return false; - } - } - - return true; - } - - static double geodesicDistanceOnWGS84Impl(Point ptFrom, Point ptTo) { - double a = 6378137.0; // radius of spheroid for WGS_1984 - double e2 = 0.0066943799901413165; // ellipticity for WGS_1984 - double rpu = Math.PI / 180.0; - PeDouble answer = new PeDouble(); - GeoDist.geodesic_distance_ngs(a, e2, ptFrom.getX() * rpu, - ptFrom.getY() * rpu, ptTo.getX() * rpu, ptTo.getY() - * rpu, answer, null, null); - return answer.val; - } - - public String getAuthority() { - int latestWKID = getLatestID(); - if (latestWKID <= 0) - return new String(""); - - return getAuthority_(latestWKID); - } - - private String getAuthority_(int latestWKID) { - String authority; - - if (latestWKID >= 1024 && latestWKID <= 32767) { - - int index = Arrays.binarySearch(m_esri_codes, latestWKID); - - if (index >= 0) - authority = new String("ESRI"); - else - authority = new String("EPSG"); - } else { - authority = new String("ESRI"); - } - - return authority; - } - - private static final int[] m_esri_codes = { - 2181, // ED_1950_Turkey_9 - 2182, // ED_1950_Turkey_10 - 2183, // ED_1950_Turkey_11 - 2184, // ED_1950_Turkey_12 - 2185, // ED_1950_Turkey_13 - 2186, // ED_1950_Turkey_14 - 2187, // ED_1950_Turkey_15 - 4305, // GCS_Voirol_Unifie_1960 - 4812, // GCS_Voirol_Unifie_1960_Paris - 20002, // Pulkovo_1995_GK_Zone_2 - 20003, // Pulkovo_1995_GK_Zone_3 - 20062, // Pulkovo_1995_GK_Zone_2N - 20063, // Pulkovo_1995_GK_Zone_3N - 24721, // La_Canoa_UTM_Zone_21N - 26761, // NAD_1927_StatePlane_Hawaii_1_FIPS_5101 - 26762, // NAD_1927_StatePlane_Hawaii_2_FIPS_5102 - 26763, // NAD_1927_StatePlane_Hawaii_3_FIPS_5103 - 26764, // NAD_1927_StatePlane_Hawaii_4_FIPS_5104 - 26765, // NAD_1927_StatePlane_Hawaii_5_FIPS_5105 - 26788, // NAD_1927_StatePlane_Michigan_North_FIPS_2111 - 26789, // NAD_1927_StatePlane_Michigan_Central_FIPS_2112 - 26790, // NAD_1927_StatePlane_Michigan_South_FIPS_2113 - 30591, // Nord_Algerie - 30592, // Sud_Algerie - 31491, // Germany_Zone_1 - 31492, // Germany_Zone_2 - 31493, // Germany_Zone_3 - 31494, // Germany_Zone_4 - 31495, // Germany_Zone_5 - 32059, // NAD_1927_StatePlane_Puerto_Rico_FIPS_5201 - 32060, // NAD_1927_StatePlane_Virgin_Islands_St_Croix_FIPS_5202 - }; - - @Override - public int hashCode() { - if (m_userWkid != 0) - return NumberUtils.hash(m_userWkid); - - return m_userWkt.hashCode(); - } + // TODO GEOCENTRIC + if (m_userWkt != null) { + if (m_userWkt.contains("PROJCS")) { + return CoordinateSystemType.PROJECTED; + } else { + return CoordinateSystemType.GEOGRAPHIC; + } + + } + if (getPJ().getType() == PJ.Type.GEOGRAPHIC) { + return CoordinateSystemType.GEOGRAPHIC; + } else if (getPJ().getType() == PJ.Type.PROJECTED) { + return CoordinateSystemType.PROJECTED; + } + + return CoordinateSystemType.Uknown; + } + + @Override + double getTolerance(int semantics) { + double tolerance = 0.001; + if (m_userWkid != 0) { + tolerance = Wkid.find_tolerance_from_wkid(m_userWkid); + } else if (m_userWkt != null) { + tolerance = Wkt.find_tolerance_from_wkt(m_userWkt); + } + return tolerance; + } + + public void queryValidCoordinateRange(Envelope2D env2D) { + double delta = 0; + switch (getPrecision()) { + case Integer32: + delta = c_SULIMIT32 / getGridUnitsXY(); + break; + case Integer64: + delta = c_SULIMIT64 / getGridUnitsXY(); + break; + default: + // TODO + throw GeometryException.GeometryInternalError(); + } + + env2D.setCoords(getFalseX(), getFalseY(), getFalseX() + delta, + getFalseY() + delta); + } + + public boolean requiresReSimplify(SpatialReference dst) { + return dst != this; + } + + @Override + public String getText() { + return m_userWkt; + } + + + @Override + public String getProj4() { + return m_proj4; + } + + /** + * Returns the oldest value of the well known ID for the horizontal + * coordinate system of the spatial reference. This ID is used for JSON + * serialization. Not public. + */ + @Override + int getOldID() { + int ID_ = getID(); + + if (m_userOldestWkid != -1) + return m_userOldestWkid; + + m_userOldestWkid = Wkid.wkid_to_old(ID_); + + if (m_userOldestWkid != -1) + return m_userOldestWkid; + + return ID_; + } + + /** + * Returns the latest value of the well known ID for the horizontal + * coordinate system of the spatial reference. This ID is used for JSON + * serialization. Not public. + */ + @Override + int getLatestID() { + int ID_ = getID(); + + if (m_userLatestWkid != -1) + return m_userLatestWkid; + + m_userLatestWkid = Wkid.wkid_to_new(ID_); + + if (m_userLatestWkid != -1) + return m_userLatestWkid; + + return ID_; + } + + @Override + public double getMajorAxis() { + if (Double.isInfinite(m_a)) { + m_a = this.getPJ().getSemiMajorAxis(); + } + return m_a; + } + + @Override + public double getEccentricitySquared() { + if (Double.isInfinite(m_e2)) { + m_e2 = this.getPJ().getEccentricitySquared(); + } + return m_e2; + } + + public static SpatialReferenceImpl createImpl(int wkid) { + if (wkid <= 0) + throw new IllegalArgumentException("Invalid or unsupported wkid: " + + wkid); + + SpatialReferenceImpl spatRef = new SpatialReferenceImpl(); + spatRef.m_userWkid = wkid; + spatRef.m_proj4 = "+init=epsg:" + Integer.toString(wkid); + + return spatRef; + } + + public static SpatialReferenceImpl createImpl(String wkt) { + if (wkt == null || wkt.length() == 0) + throw new IllegalArgumentException( + "Cannot create SpatialReference from null or empty text."); + + int wkid = __wkid_from_wkt(wkt); + if (wkid == 0) { + SpatialReferenceImpl spatRef = new SpatialReferenceImpl(); + spatRef.m_userWkt = wkt; + return spatRef; + } + + return createImpl(wkid); + } + + private static int __wkid_from_wkt(String wkt) { + Matcher matcher = m_pattern.matcher(wkt); + if (matcher.find()) { + return Integer.parseInt(matcher.group(2)); + } + return 0; + } + + + protected static SpatialReferenceImpl createFromProj4Impl(String proj4Text) { + SpatialReferenceImpl spatRef = new SpatialReferenceImpl(); + spatRef.m_proj4 = proj4Text; + + Matcher matcher = m_proj4wkid.matcher(spatRef.m_proj4); + if (matcher.find()) { + spatRef.m_userWkid = Integer.parseInt(matcher.group(1)); + } + + return spatRef; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + + SpatialReferenceImpl sr = (SpatialReferenceImpl) obj; + if (m_userWkid != sr.m_userWkid) + return false; + + + if (m_userWkid == 0) { + if (m_userWkt != null && sr.m_userWkt != null && m_userWkt.equals(sr.m_userWkt)) { + return true; + } + + if (m_proj4 != null && sr.m_proj4 != null && m_proj4.equals(sr.m_proj4)) { + return true; + } + + if ((m_proj4 != null || m_userWkt != null) && (sr.m_proj4 != null || sr.m_userWkt != null)) { + return false; + } + } + + return true; + } + + static double geodesicDistanceOnWGS84Impl(Point ptFrom, Point ptTo) { + double a = 6378137.0; // radius of spheroid for WGS_1984 + double e2 = 0.0066943799901413165; // ellipticity for WGS_1984 + double rpu = Math.PI / 180.0; + PeDouble answer = new PeDouble(); + GeoDist.geodesic_distance_ngs(a, e2, ptFrom.getX() * rpu, + ptFrom.getY() * rpu, ptTo.getX() * rpu, ptTo.getY() + * rpu, answer, null, null); + return answer.val; + } + + public String getAuthority() { + int latestWKID = getLatestID(); + if (latestWKID <= 0) + return new String(""); + + return getAuthority_(latestWKID); + } + + private String getAuthority_(int latestWKID) { + String authority; + + if (latestWKID >= 1024 && latestWKID <= 32767) { + + int index = Arrays.binarySearch(m_esri_codes, latestWKID); + + if (index >= 0) + authority = new String("ESRI"); + else + authority = new String("EPSG"); + } else { + authority = new String("ESRI"); + } + + return authority; + } + + private static final int[] m_esri_codes = { + 2181, // ED_1950_Turkey_9 + 2182, // ED_1950_Turkey_10 + 2183, // ED_1950_Turkey_11 + 2184, // ED_1950_Turkey_12 + 2185, // ED_1950_Turkey_13 + 2186, // ED_1950_Turkey_14 + 2187, // ED_1950_Turkey_15 + 4305, // GCS_Voirol_Unifie_1960 + 4812, // GCS_Voirol_Unifie_1960_Paris + 20002, // Pulkovo_1995_GK_Zone_2 + 20003, // Pulkovo_1995_GK_Zone_3 + 20062, // Pulkovo_1995_GK_Zone_2N + 20063, // Pulkovo_1995_GK_Zone_3N + 24721, // La_Canoa_UTM_Zone_21N + 26761, // NAD_1927_StatePlane_Hawaii_1_FIPS_5101 + 26762, // NAD_1927_StatePlane_Hawaii_2_FIPS_5102 + 26763, // NAD_1927_StatePlane_Hawaii_3_FIPS_5103 + 26764, // NAD_1927_StatePlane_Hawaii_4_FIPS_5104 + 26765, // NAD_1927_StatePlane_Hawaii_5_FIPS_5105 + 26788, // NAD_1927_StatePlane_Michigan_North_FIPS_2111 + 26789, // NAD_1927_StatePlane_Michigan_Central_FIPS_2112 + 26790, // NAD_1927_StatePlane_Michigan_South_FIPS_2113 + 30591, // Nord_Algerie + 30592, // Sud_Algerie + 31491, // Germany_Zone_1 + 31492, // Germany_Zone_2 + 31493, // Germany_Zone_3 + 31494, // Germany_Zone_4 + 31495, // Germany_Zone_5 + 32059, // NAD_1927_StatePlane_Puerto_Rico_FIPS_5201 + 32060, // NAD_1927_StatePlane_Virgin_Islands_St_Croix_FIPS_5202 + }; + + @Override + public int hashCode() { + if (m_userWkid != 0) + return NumberUtils.hash(m_userWkid); + + return m_userWkt.hashCode(); + } } diff --git a/src/main/java/com/esri/core/geometry/SpatialReferenceSerializer.java b/src/main/java/com/esri/core/geometry/SpatialReferenceSerializer.java index 89cad20f..0cf25e6c 100644 --- a/src/main/java/com/esri/core/geometry/SpatialReferenceSerializer.java +++ b/src/main/java/com/esri/core/geometry/SpatialReferenceSerializer.java @@ -31,33 +31,33 @@ import com.esri.core.geometry.SpatialReference; final class SpatialReferenceSerializer implements Serializable { - private static final long serialVersionUID = 10000L; - String wkt = null; - int wkid = 0; - - Object readResolve() throws ObjectStreamException { - SpatialReference sr = null; - try { - if (wkid > 0) - sr = SpatialReference.create(wkid); - else - sr = SpatialReference.create(wkt); - } catch (Exception ex) { - throw new InvalidObjectException( - "Cannot read spatial reference from stream"); - } - return sr; - } - - public void setSpatialReferenceByValue(SpatialReference sr) - throws ObjectStreamException { - try { - if (sr.getID() > 0) - wkid = sr.getID(); - else - wkt = sr.getText(); - } catch (Exception ex) { - throw new InvalidObjectException("Cannot serialize this geometry"); - } - } + private static final long serialVersionUID = 10000L; + String wkt = null; + int wkid = 0; + + Object readResolve() throws ObjectStreamException { + SpatialReference sr = null; + try { + if (wkid > 0) + sr = SpatialReference.create(wkid); + else + sr = SpatialReference.create(wkt); + } catch (Exception ex) { + throw new InvalidObjectException( + "Cannot read spatial reference from stream"); + } + return sr; + } + + public void setSpatialReferenceByValue(SpatialReference sr) + throws ObjectStreamException { + try { + if (sr.getID() > 0) + wkid = sr.getID(); + else + wkt = sr.getText(); + } catch (Exception ex) { + throw new InvalidObjectException("Cannot serialize this geometry"); + } + } } diff --git a/src/main/java/com/esri/core/geometry/StridedIndexTypeCollection.java b/src/main/java/com/esri/core/geometry/StridedIndexTypeCollection.java index 1246b4c1..ae1f4dca 100644 --- a/src/main/java/com/esri/core/geometry/StridedIndexTypeCollection.java +++ b/src/main/java/com/esri/core/geometry/StridedIndexTypeCollection.java @@ -1,5 +1,5 @@ /* - Copyright 1995-2015 Esri + Copyright 1995-2018 Esri Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -23,254 +23,276 @@ */ package com.esri.core.geometry; +import java.io.Serializable; + +import static com.esri.core.geometry.SizeOf.SIZE_OF_STRIDED_INDEX_TYPE_COLLECTION; +import static com.esri.core.geometry.SizeOf.sizeOfIntArray; +import static com.esri.core.geometry.SizeOf.sizeOfObjectArray; + /** * A collection of strides of Index_type elements. To be used when one needs a * collection of homogeneous elements that contain only integer fields (i.e. * structs with Index_type members) Recycles the strides. Allows for constant * time creation and deletion of an element. */ -final class StridedIndexTypeCollection { - private int[][] m_buffer = null; - private int m_firstFree = -1; - private int m_last = 0; - private int m_size = 0; - private int m_capacity = 0; - private int m_bufferSize = 0; - private int m_stride; - private int m_realStride; - private int m_blockSize; +final class StridedIndexTypeCollection implements Serializable { + private static final long serialVersionUID = 1L; + + private int[][] m_buffer = null; + private int m_firstFree = -1; + private int m_last = 0; + private int m_size = 0; + private int m_capacity = 0; + private int m_bufferSize = 0; + private int m_stride; + private int m_realStride; + private int m_blockSize; /* - private final static int m_realBlockSize = 2048;//if you change this, change m_blockSize, m_blockPower, m_blockMask, and st_sizes + private final static int m_realBlockSize = 2048;//if you change this, change m_blockSize, m_blockPower, m_blockMask, and st_sizes private final static int m_blockMask = 0x7FF; private final static int m_blockPower = 11; private final static int[] st_sizes = {16, 32, 64, 128, 256, 512, 1024, 2048}; */ - private final static int m_realBlockSize = 16384;// if you change this, - // change m_blockSize, - // m_blockPower, - // m_blockMask, and - // st_sizes - private final static int m_blockMask = 0x3FFF; - private final static int m_blockPower = 14; - private final static int[] st_sizes = {16, 32, 64, 128, 256, 512, 1024, - 2048, 4096, 8192, 16384}; - - StridedIndexTypeCollection(int stride) { - m_stride = stride; - m_realStride = stride; - m_blockSize = m_realBlockSize / m_realStride; - } - - private boolean dbgdelete_(int element) { - m_buffer[element >> m_blockPower][(element & m_blockMask) + 1] = -0x7eadbeed; - return true; - } - - void deleteElement(int element) { - assert (dbgdelete_(element)); - int totalStrides = (element >> m_blockPower) * m_blockSize - * m_realStride + (element & m_blockMask); - if (totalStrides < m_last * m_realStride) { - m_buffer[element >> m_blockPower][element & m_blockMask] = m_firstFree; - m_firstFree = element; - } else { - assert (totalStrides == m_last * m_realStride); - m_last--; - } - m_size--; - } - - // Returns the given field of the element. - int getField(int element, int field) { - assert (m_buffer[element >> m_blockPower][(element & m_blockMask) + 1] != -0x7eadbeed); - return m_buffer[element >> m_blockPower][(element & m_blockMask) - + field]; - } - - // Sets the given field of the element. - void setField(int element, int field, int value) { - assert (m_buffer[element >> m_blockPower][(element & m_blockMask) + 1] != -0x7eadbeed); - m_buffer[element >> m_blockPower][(element & m_blockMask) + field] = value; - } - - // Returns the stride size - int getStride() { - return m_stride; - } - - // Creates the new element. This is a constant time operation. - // All fields are initialized to -1. - int newElement() { - int element = m_firstFree; - if (element == -1) { - if (m_last == m_capacity) { - long newcap = m_capacity != 0 ? (((long) m_capacity + 1) * 3 / 2) - : (long) 1; - if (newcap > Integer.MAX_VALUE) - newcap = Integer.MAX_VALUE;// cannot grow past 2gb elements - // presently - - if (newcap == m_capacity) - throw new IndexOutOfBoundsException(); - - grow_(newcap); - } - - element = ((m_last / m_blockSize) << m_blockPower) - + (m_last % m_blockSize) * m_realStride; - m_last++; - } else { - m_firstFree = m_buffer[element >> m_blockPower][element - & m_blockMask]; - } - - m_size++; - int ar[] = m_buffer[element >> m_blockPower]; - int ind = element & m_blockMask; - for (int i = 0; i < m_stride; i++) { - ar[ind + i] = -1; - } - return element; - } - - int elementToIndex(int element) { - return (element >> m_blockPower) * m_blockSize - + (element & m_blockMask) / m_realStride; - } - - // Deletes all elements and frees all the memory if b_free_memory is True. - void deleteAll(boolean b_free_memory) { - m_firstFree = -1; - m_last = 0; - m_size = 0; - if (b_free_memory) { - m_buffer = null; - m_capacity = 0; - } - } - - // Returns the count of existing elements - int size() { - return m_size; - } - - // Sets the capcity of the collection. Only applied if current capacity is - // smaller. - void setCapacity(int capacity) { - if (capacity > m_capacity) - grow_(capacity); - } - - // Returns the capacity of the collection - int capacity() { - return m_capacity; - } - - // Swaps content of two elements (each field of the stride) - void swap(int element1, int element2) { - int ar1[] = m_buffer[element1 >> m_blockPower]; - int ar2[] = m_buffer[element2 >> m_blockPower]; - int ind1 = element1 & m_blockMask; - int ind2 = element2 & m_blockMask; - for (int i = 0; i < m_stride; i++) { - int tmp = ar1[ind1 + i]; - ar1[ind1 + i] = ar2[ind2 + i]; - ar2[ind2 + i] = tmp; - } - } - - // Swaps content of two fields - void swapField(int element1, int element2, int field) { - int ar1[] = m_buffer[element1 >> m_blockPower]; - int ar2[] = m_buffer[element2 >> m_blockPower]; - int ind1 = (element1 & m_blockMask) + field; - int ind2 = (element2 & m_blockMask) + field; - int tmp = ar1[ind1]; - ar1[ind1] = ar2[ind2]; - ar2[ind2] = tmp; - } - - // Returns a value of the index, that never will be returned by new_element - // and is neither -1 nor impossible_index_3. - static int impossibleIndex2() { - return -2; - } - - // Returns a value of the index, that never will be returned by new_element - // and is neither -1 nor impossible_index_2. - static int impossibleIndex3() { - return -3; - } - - static boolean isValidElement(int element) { - return element >= 0; - } - - private void ensureBufferBlocksCapacity(int blocks) { - if (m_buffer.length < blocks) { - int[][] newBuffer = new int[blocks][]; - for (int i = 0; i < m_buffer.length; i++) { - newBuffer[i] = m_buffer[i]; - } - - m_buffer = newBuffer; - } - } - - private void grow_(long newsize) { - if (m_buffer == null) { - m_bufferSize = 0; - m_buffer = new int[8][]; - } - - assert (newsize > m_capacity); - - long nblocks = (newsize + m_blockSize - 1) / m_blockSize; - if (nblocks > Integer.MAX_VALUE) - throw new IndexOutOfBoundsException(); - - ensureBufferBlocksCapacity((int) nblocks); - if (nblocks == 1) { - // When less than one block is needed we allocate smaller arrays - // than m_realBlockSize to avoid initialization cost. - int oldsz = m_capacity > 0 ? m_capacity : 0; - assert (oldsz < newsize); - int i = 0; - int realnewsize = (int) newsize * m_realStride; - while (realnewsize > st_sizes[i]) - // get the size to allocate. Using fixed sizes to reduce - // fragmentation. - i++; - int[] b = new int[st_sizes[i]]; - if (m_bufferSize == 1) { - System.arraycopy(m_buffer[0], 0, b, 0, m_buffer[0].length); - m_buffer[0] = b; - } else { - m_buffer[m_bufferSize] = b; - m_bufferSize++; - } - m_capacity = b.length / m_realStride; - } else { - if (nblocks * m_blockSize > Integer.MAX_VALUE) - throw new IndexOutOfBoundsException(); - - if (m_bufferSize == 1) { - if (m_buffer[0].length < m_realBlockSize) { - // resize the first buffer to ensure it is equal the - // m_realBlockSize. - int[] b = new int[m_realBlockSize]; - System.arraycopy(m_buffer[0], 0, b, 0, m_buffer[0].length); - m_buffer[0] = b; - m_capacity = m_blockSize; - } - } - - while (m_bufferSize < nblocks) { - m_buffer[m_bufferSize++] = new int[m_realBlockSize]; - m_capacity += m_blockSize; - } - } - } + private final static int m_realBlockSize = 16384;// if you change this, + // change m_blockSize, + // m_blockPower, + // m_blockMask, and + // st_sizes + private final static int m_blockMask = 0x3FFF; + private final static int m_blockPower = 14; + private final static int[] st_sizes = { 16, 32, 64, 128, 256, 512, 1024, + 2048, 4096, 8192, 16384 }; + + StridedIndexTypeCollection(int stride) { + m_stride = stride; + m_realStride = stride; + m_blockSize = m_realBlockSize / m_realStride; + } + + private boolean dbgdelete_(int element) { + m_buffer[element >> m_blockPower][(element & m_blockMask) + 1] = -0x7eadbeed; + return true; + } + + void deleteElement(int element) { + assert(dbgdelete_(element)); + int totalStrides = (element >> m_blockPower) * m_blockSize + * m_realStride + (element & m_blockMask); + if (totalStrides < m_last * m_realStride) { + m_buffer[element >> m_blockPower][element & m_blockMask] = m_firstFree; + m_firstFree = element; + } else { + assert (totalStrides == m_last * m_realStride); + m_last--; + } + m_size--; + } + + // Returns the given field of the element. + int getField(int element, int field) { + assert(m_buffer[element >> m_blockPower][(element & m_blockMask) + 1] != -0x7eadbeed); + return m_buffer[element >> m_blockPower][(element & m_blockMask) + + field]; + } + + // Sets the given field of the element. + void setField(int element, int field, int value) { + assert(m_buffer[element >> m_blockPower][(element & m_blockMask) + 1] != -0x7eadbeed); + m_buffer[element >> m_blockPower][(element & m_blockMask) + field] = value; + } + + // Returns the stride size + int getStride() { + return m_stride; + } + + // Creates the new element. This is a constant time operation. + // All fields are initialized to -1. + int newElement() { + int element = m_firstFree; + if (element == -1) { + if (m_last == m_capacity) { + long newcap = m_capacity != 0 ? (((long) m_capacity + 1) * 3 / 2) + : (long) 1; + if (newcap > Integer.MAX_VALUE) + newcap = Integer.MAX_VALUE;// cannot grow past 2gb elements + // presently + + if (newcap == m_capacity) + throw new IndexOutOfBoundsException(); + + grow_(newcap); + } + + element = ((m_last / m_blockSize) << m_blockPower) + + (m_last % m_blockSize) * m_realStride; + m_last++; + } else { + m_firstFree = m_buffer[element >> m_blockPower][element + & m_blockMask]; + } + + m_size++; + int ar[] = m_buffer[element >> m_blockPower]; + int ind = element & m_blockMask; + for (int i = 0; i < m_stride; i++) { + ar[ind + i] = -1; + } + return element; + } + + int elementToIndex(int element) { + return (element >> m_blockPower) * m_blockSize + + (element & m_blockMask) / m_realStride; + } + + // Deletes all elements and frees all the memory if b_free_memory is True. + void deleteAll(boolean b_free_memory) { + m_firstFree = -1; + m_last = 0; + m_size = 0; + if (b_free_memory) { + m_buffer = null; + m_capacity = 0; + } + } + + // Returns the count of existing elements + int size() { + return m_size; + } + + // Sets the capcity of the collection. Only applied if current capacity is + // smaller. + void setCapacity(int capacity) { + if (capacity > m_capacity) + grow_(capacity); + } + + // Returns the capacity of the collection + int capacity() { + return m_capacity; + } + + // Swaps content of two elements (each field of the stride) + void swap(int element1, int element2) { + int ar1[] = m_buffer[element1 >> m_blockPower]; + int ar2[] = m_buffer[element2 >> m_blockPower]; + int ind1 = element1 & m_blockMask; + int ind2 = element2 & m_blockMask; + for (int i = 0; i < m_stride; i++) { + int tmp = ar1[ind1 + i]; + ar1[ind1 + i] = ar2[ind2 + i]; + ar2[ind2 + i] = tmp; + } + } + + // Swaps content of two fields + void swapField(int element1, int element2, int field) { + int ar1[] = m_buffer[element1 >> m_blockPower]; + int ar2[] = m_buffer[element2 >> m_blockPower]; + int ind1 = (element1 & m_blockMask) + field; + int ind2 = (element2 & m_blockMask) + field; + int tmp = ar1[ind1]; + ar1[ind1] = ar2[ind2]; + ar2[ind2] = tmp; + } + + // Returns a value of the index, that never will be returned by new_element + // and is neither -1 nor impossible_index_3. + static int impossibleIndex2() { + return -2; + } + + // Returns a value of the index, that never will be returned by new_element + // and is neither -1 nor impossible_index_2. + static int impossibleIndex3() { + return -3; + } + + static boolean isValidElement(int element) { + return element >= 0; + } + + private void ensureBufferBlocksCapacity(int blocks) { + if (m_buffer.length < blocks) { + int[][] newBuffer = new int[blocks][]; + for (int i = 0; i < m_buffer.length; i++) { + newBuffer[i] = m_buffer[i]; + } + + m_buffer = newBuffer; + } + } + + private void grow_(long newsize) { + if (m_buffer == null) { + m_bufferSize = 0; + m_buffer = new int[8][]; + } + + assert (newsize > m_capacity); + + long nblocks = (newsize + m_blockSize - 1) / m_blockSize; + if (nblocks > Integer.MAX_VALUE) + throw new IndexOutOfBoundsException(); + + ensureBufferBlocksCapacity((int) nblocks); + if (nblocks == 1) { + // When less than one block is needed we allocate smaller arrays + // than m_realBlockSize to avoid initialization cost. + int oldsz = m_capacity > 0 ? m_capacity : 0; + assert (oldsz < newsize); + int i = 0; + int realnewsize = (int) newsize * m_realStride; + while (realnewsize > st_sizes[i]) + // get the size to allocate. Using fixed sizes to reduce + // fragmentation. + i++; + int[] b = new int[st_sizes[i]]; + if (m_bufferSize == 1) { + System.arraycopy(m_buffer[0], 0, b, 0, m_buffer[0].length); + m_buffer[0] = b; + } else { + m_buffer[m_bufferSize] = b; + m_bufferSize++; + } + m_capacity = b.length / m_realStride; + } else { + if (nblocks * m_blockSize > Integer.MAX_VALUE) + throw new IndexOutOfBoundsException(); + + if (m_bufferSize == 1) { + if (m_buffer[0].length < m_realBlockSize) { + // resize the first buffer to ensure it is equal the + // m_realBlockSize. + int[] b = new int[m_realBlockSize]; + System.arraycopy(m_buffer[0], 0, b, 0, m_buffer[0].length); + m_buffer[0] = b; + m_capacity = m_blockSize; + } + } + + while (m_bufferSize < nblocks) { + m_buffer[m_bufferSize++] = new int[m_realBlockSize]; + m_capacity += m_blockSize; + } + } + } + + public long estimateMemorySize() + { + long size = SIZE_OF_STRIDED_INDEX_TYPE_COLLECTION; + if (m_buffer != null) { + size += sizeOfObjectArray(m_buffer.length); + for (int i = 0; i< m_buffer.length; i++) { + if (m_buffer[i] != null) { + size += sizeOfIntArray(m_buffer[i].length); + } + } + } + return size; + } } diff --git a/src/main/java/com/esri/core/geometry/StringCursor.java b/src/main/java/com/esri/core/geometry/StringCursor.java index 35d47156..c1faebe5 100644 --- a/src/main/java/com/esri/core/geometry/StringCursor.java +++ b/src/main/java/com/esri/core/geometry/StringCursor.java @@ -3,13 +3,13 @@ import java.util.Iterator; public abstract class StringCursor implements Iterator { - public abstract String next(); + public abstract String next(); - public abstract long getID(); + public abstract long getID(); - public abstract SimpleStateEnum getSimpleState(); + public abstract SimpleStateEnum getSimpleState(); - public abstract String getFeatureID(); + public abstract String getFeatureID(); - public abstract boolean hasNext(); + public abstract boolean hasNext(); } diff --git a/src/main/java/com/esri/core/geometry/StringUtils.java b/src/main/java/com/esri/core/geometry/StringUtils.java index 3c5d4c3c..9a3cd781 100644 --- a/src/main/java/com/esri/core/geometry/StringUtils.java +++ b/src/main/java/com/esri/core/geometry/StringUtils.java @@ -27,85 +27,85 @@ class StringUtils { - static void appendDouble(double value, int precision, - StringBuilder stringBuilder) { - if (precision < 0) { - precision = 0; - } else if (precision > 17) { - precision = 17; - } - - String format = "%." + precision + "g"; - - String str_dbl = String.format(Locale.US, format, value); - - boolean b_found_dot = false; - boolean b_found_exponent = false; - - for (int i = 0; i < str_dbl.length(); i++) { - char c = str_dbl.charAt(i); - - if (c == '.') { - b_found_dot = true; - } else if (c == 'e' || c == 'E') { - b_found_exponent = true; - break; - } - } - - if (b_found_dot && !b_found_exponent) { - StringBuilder buffer = removeTrailingZeros_(str_dbl); - stringBuilder.append(buffer); - } else { - stringBuilder.append(str_dbl); - } - } - - static void appendDoubleF(double value, int decimals, - StringBuilder stringBuilder) { - if (decimals < 0) { - decimals = 0; - } else if (decimals > 17) { - decimals = 17; - } - - String format = "%." + decimals + "f"; - - String str_dbl = String.format(Locale.US, format, value); - - boolean b_found_dot = false; - - for (int i = 0; i < str_dbl.length(); i++) { - char c = str_dbl.charAt(i); - - if (c == '.') { - b_found_dot = true; - break; - } - } - - if (b_found_dot) { - StringBuilder buffer = removeTrailingZeros_(str_dbl); - stringBuilder.append(buffer); - } else { - stringBuilder.append(str_dbl); - } - } - - static private StringBuilder removeTrailingZeros_(String str_dbl) { - StringBuilder buffer = new StringBuilder(str_dbl); - int non_zero = buffer.length() - 1; - - while (buffer.charAt(non_zero) == '0') { - non_zero--; - } - - buffer.delete(non_zero + 1, buffer.length()); - - if (buffer.charAt(non_zero) == '.') { - buffer.deleteCharAt(non_zero); - } - - return buffer; - } + static void appendDouble(double value, int precision, + StringBuilder stringBuilder) { + if (precision < 0) { + precision = 0; + } else if (precision > 17) { + precision = 17; + } + + String format = "%." + precision + "g"; + + String str_dbl = String.format(Locale.US, format, value); + + boolean b_found_dot = false; + boolean b_found_exponent = false; + + for (int i = 0; i < str_dbl.length(); i++) { + char c = str_dbl.charAt(i); + + if (c == '.') { + b_found_dot = true; + } else if (c == 'e' || c == 'E') { + b_found_exponent = true; + break; + } + } + + if (b_found_dot && !b_found_exponent) { + StringBuilder buffer = removeTrailingZeros_(str_dbl); + stringBuilder.append(buffer); + } else { + stringBuilder.append(str_dbl); + } + } + + static void appendDoubleF(double value, int decimals, + StringBuilder stringBuilder) { + if (decimals < 0) { + decimals = 0; + } else if (decimals > 17) { + decimals = 17; + } + + String format = "%." + decimals + "f"; + + String str_dbl = String.format(Locale.US, format, value); + + boolean b_found_dot = false; + + for (int i = 0; i < str_dbl.length(); i++) { + char c = str_dbl.charAt(i); + + if (c == '.') { + b_found_dot = true; + break; + } + } + + if (b_found_dot) { + StringBuilder buffer = removeTrailingZeros_(str_dbl); + stringBuilder.append(buffer); + } else { + stringBuilder.append(str_dbl); + } + } + + static private StringBuilder removeTrailingZeros_(String str_dbl) { + StringBuilder buffer = new StringBuilder(str_dbl); + int non_zero = buffer.length() - 1; + + while (buffer.charAt(non_zero) == '0') { + non_zero--; + } + + buffer.delete(non_zero + 1, buffer.length()); + + if (buffer.charAt(non_zero) == '.') { + buffer.deleteCharAt(non_zero); + } + + return buffer; + } } diff --git a/src/main/java/com/esri/core/geometry/SweepComparator.java b/src/main/java/com/esri/core/geometry/SweepComparator.java index c7ea2996..2ea54aa9 100644 --- a/src/main/java/com/esri/core/geometry/SweepComparator.java +++ b/src/main/java/com/esri/core/geometry/SweepComparator.java @@ -30,647 +30,647 @@ import java.util.ArrayList; class SweepComparator extends Treap.Comparator { - static final class SimpleEdge { - int m_value; - Line m_line; - Segment m_segment; - Envelope1D m_env; - double m_dxdy; - boolean m_b_horizontal; - boolean m_b_curve; - - SimpleEdge() { - m_value = -1; - m_line = new Line(); - m_dxdy = 55555555; - m_b_horizontal = false; - m_b_curve = false; - - m_env = new Envelope1D(); - m_env.setCoordsNoNaN_(0, 0); - } - } - - private EditShape m_shape; - boolean m_b_intersection_detected; - NonSimpleResult m_non_simple_result; - // Index 1 corresponds to the left segments, index 2 - right, e.g. m_line_1, - // m_line_2 - SimpleEdge m_temp_simple_edge_1; - SimpleEdge m_temp_simple_edge_2; - - int m_prev_1; - int m_prev_2; - int m_vertex_1; - int m_vertex_2; - int m_current_node; - double m_prevx_1; - double m_prevx_2; - double m_prev_y; - double m_prev_x; - double m_sweep_y; - double m_sweep_x; - double m_tolerance; - double m_tolerance_10; - boolean m_b_is_simple; - - ArrayList m_simple_edges_cache; - ArrayList m_simple_edges_recycle; - ArrayList m_simple_edges_buffer; - - // Returns a cached edge for the given value. May return NULL. - SimpleEdge tryGetCachedEdge_(int value) { - SimpleEdge se = m_simple_edges_cache.get((value & NumberUtils.intMax()) % m_simple_edges_cache.size()); - if (se != null) { - if (se.m_value == value) - return se; - else { - // int i = 0; - // cache collision - } - } - return null; - } - - // Removes cached edge from the cache for the given value. - void tryDeleteCachedEdge_(int value) { - int ind = (value & NumberUtils.intMax()) % m_simple_edges_cache.size(); - SimpleEdge se = m_simple_edges_cache.get(ind); - if (se != null && se.m_value == value) {// this value is cached - m_simple_edges_recycle.add(se); - m_simple_edges_cache.set(ind, null); - } else { - // The value has not been cached - } - } - - // Creates a cached edge. May fail and return NULL. - SimpleEdge tryCreateCachedEdge_(int value) { - int ind = (value & NumberUtils.intMax()) % m_simple_edges_cache.size(); - SimpleEdge se = m_simple_edges_cache.get(ind); - if (se == null) { - if (m_simple_edges_recycle.isEmpty()) { - // assert(m_simple_edges_buffer.size() < - // m_simple_edges_buffer.capacity());//should never happen - // assert(m_simple_edges_buffer.size() < - // m_simple_edges_cache.size());//should never happen - m_simple_edges_buffer.add(new SimpleEdge()); - se = m_simple_edges_buffer - .get(m_simple_edges_buffer.size() - 1); - } else { - se = m_simple_edges_recycle - .get(m_simple_edges_recycle.size() - 1); - m_simple_edges_recycle - .remove(m_simple_edges_recycle.size() - 1); - } - - se.m_value = value; - m_simple_edges_cache.set(ind, se); - return se; - } else { - assert (se.m_value != value);// do not call TryCreateCachedEdge - // twice. - } - - return null; - } - - void initSimpleEdge_(SweepComparator.SimpleEdge se, int vertex) { - se.m_segment = m_shape.getSegment(vertex); - se.m_b_curve = se.m_segment != null; - if (!se.m_b_curve) { - m_shape.queryLineConnector(vertex, se.m_line); - se.m_segment = se.m_line; - se.m_env.setCoordsNoNaN_(se.m_line.getStartX(), se.m_line.getEndX()); - se.m_env.vmax += m_tolerance; - se.m_line.orientBottomUp_(); - se.m_b_horizontal = se.m_line.getEndY() == se.m_line.getStartY(); - if (!se.m_b_horizontal) { - se.m_dxdy = (se.m_line.getEndX() - se.m_line.getStartX()) - / (se.m_line.getEndY() - se.m_line.getStartY()); - } - } else { - // se.m_segment = se.m_segment_sptr.get(); - } - } - - // Compares seg_1 and seg_2 x coordinates of intersection with the line - // parallel to axis x, passing through the coordinate y. - // If segments intersect not at the endpoint, the m_b_intersection_detected - // is set. - int compareTwoSegments_(Segment seg_1, Segment seg_2) { - int res = seg_1._isIntersecting(seg_2, m_tolerance, true); - if (res != 0) { - if (res == 2) - return errorCoincident(); - else - return errorCracking(); - } - - Point2D start_1 = seg_1.getStartXY(); - Point2D end1 = seg_1.getEndXY(); - Point2D start2 = seg_2.getStartXY(); - Point2D end2 = seg_2.getEndXY(); - Point2D ptSweep = new Point2D(); - ptSweep.setCoords(m_sweep_x, m_sweep_y); - if (start_1.isEqual(start2) && m_sweep_y == start_1.y) { - assert (start_1.compare(end1) < 0 && start2.compare(end2) < 0); - if (end1.compare(end2) < 0) - ptSweep.setCoords(end1); - else - ptSweep.setCoords(end2); - } else if (start_1.isEqual(end2) && m_sweep_y == start_1.y) { - assert (start_1.compare(end1) < 0 && start2.compare(end2) > 0); - if (end1.compare(start2) < 0) - ptSweep.setCoords(end1); - else - ptSweep.setCoords(start2); - } else if (start2.isEqual(end1) && m_sweep_y == start2.y) { - assert (end1.compare(start_1) < 0 && start2.compare(end2) < 0); - if (start_1.compare(end2) < 0) - ptSweep.setCoords(start_1); - else - ptSweep.setCoords(end2); - } else if (end1.isEqual(end2) && m_sweep_y == end1.y) { - assert (start_1.compare(end1) > 0 && start2.compare(end2) > 0); - if (start_1.compare(start2) < 0) - ptSweep.setCoords(start_1); - else - ptSweep.setCoords(start2); - } - - double xleft = seg_1.intersectionOfYMonotonicWithAxisX(ptSweep.y, - ptSweep.x); - double xright = seg_2.intersectionOfYMonotonicWithAxisX(ptSweep.y, - ptSweep.x); - assert (xleft != xright); - return xleft < xright ? -1 : 1; - } - - int compareNonHorizontal_(SimpleEdge line_1, SimpleEdge line_2) { - if (line_1.m_line.getStartY() == line_2.m_line.getStartY() - && line_1.m_line.getStartX() == line_2.m_line.getStartX()) {// connected - // at - // the - // start - // V - // shape - if (line_1.m_line.getEndY() == line_2.m_line.getEndY() - && line_1.m_line.getEndX() == line_2.m_line.getEndX()) {// connected - // at - // another - // end - // also - if (m_b_is_simple) - return errorCoincident(); - return 0; - } - - return compareNonHorizontalUpperEnd_(line_1, line_2); - } - - if (line_1.m_line.getEndY() == line_2.m_line.getEndY() - && line_1.m_line.getEndX() == line_2.m_line.getEndX()) { - // the case of upside-down V. - return compareNonHorizontalLowerEnd_(line_1, line_2); - } - - int lower = compareNonHorizontalLowerEnd_(line_1, line_2); - int upper = compareNonHorizontalUpperEnd_(line_1, line_2); - if (lower < 0 && upper < 0) - return -1; - if (lower > 0 && upper > 0) - return 1; - - return errorCracking(); - } - - int compareHorizontal1Case1_(Line line_1, Line line_2) { - // line_2 goes up and line_1 is horizontal connected at the start going - // to the right. - if (line_1.getEndX() > line_2.getEndX()) { - // / - // / - // +------------------ - if (line_2.getEndX() > line_2.getStartX() - && line_2.getEndY() - line_2.getStartY() < 2 * m_tolerance - && line_1._isIntersectingPoint(line_2.getEndXY(), - m_tolerance, true)) - return errorCracking(); - } else { - // / - // / - // / - // +-- - assert (line_2.getEndX() - line_2.getStartX() != 0); - // Note: line_2 cannot be vertical here - // Avoid expensive is_intersecting_ by providing a simple estimate. - double dydx = (line_2.getEndY() - line_2.getStartY()) - / (line_2.getEndX() - line_2.getStartX()); - double d = dydx * (line_1.getEndX() - line_1.getStartX()); - if (d < m_tolerance_10 - && line_2._isIntersectingPoint(line_1.getEndXY(), - m_tolerance, true)) - return errorCracking(); - } - - return 1; - } - - int compareHorizontal1Case2_(Line line_1, Line line_2) { - // -----------------+ - // / - // / - // / - // line_2 goes up and below line_1. line_1 is horizontal connected at - // the end to the line_2 end. - if (line_1.getStartX() < line_2.getStartX()) { - if (line_2.getEndX() > line_2.getStartX() - && line_2.getEndY() - line_2.getStartY() < 2 * m_tolerance - && line_1._isIntersectingPoint(line_2.getEndXY(), - m_tolerance, true)) - return errorCracking(); - } else { - // --+ - // / - // / - // / - // Avoid expensive is_intersecting_ by providing a simple estimate. - double dydx = (line_2.getEndY() - line_2.getStartY()) - / (line_2.getEndX() - line_2.getStartX()); - double d = dydx * (line_1.getStartX() - line_1.getEndX()); - if (d < m_tolerance_10 - && line_2._isIntersectingPoint(line_1.getStartXY(), - m_tolerance, true)) - return errorCracking(); - } - - return -1; - } - - int compareHorizontal1Case3_(Line line_1, Line line_2) { - Point2D v0 = new Point2D(); - v0.sub(line_2.getEndXY(), line_2.getStartXY()); - v0.rightPerpendicular(); - v0.normalize(); - Point2D v_1 = new Point2D(); - v_1.sub(line_1.getStartXY(), line_2.getStartXY()); - Point2D v_2 = new Point2D(); - v_2.sub(line_1.getEndXY(), line_2.getStartXY()); - double d_1 = v_1.dotProduct(v0); - double d_2 = v_2.dotProduct(v0); - - double ad1 = Math.abs(d_1); - double ad2 = Math.abs(d_2); - - if (ad1 < ad2) { - if (ad1 < m_tolerance_10 - && line_2._isIntersectingPoint(line_1.getStartXY(), - m_tolerance, true)) - return errorCracking(); - } else { - if (ad2 < m_tolerance_10 - && line_2._isIntersectingPoint(line_1.getEndXY(), - m_tolerance, true)) - return errorCracking(); - } - - if (d_1 < 0 && d_2 < 0) - return -1; - - if (d_1 > 0 && d_2 > 0) - return 1; - - return errorCracking(); - } - - int compareHorizontal1_(Line line_1, Line line_2) { - // Two most important cases of connecting edges - if (line_1.getStartY() == line_2.getStartY() - && line_1.getStartX() == line_2.getStartX()) { - return compareHorizontal1Case1_(line_1, line_2); - } - - if (line_1.getEndY() == line_2.getEndY() - && line_1.getEndX() == line_2.getEndX()) { - return compareHorizontal1Case2_(line_1, line_2); - } - - return compareHorizontal1Case3_(line_1, line_2); - } - - int compareHorizontal2_(Line line_1, Line line_2) { - if (line_1.getEndY() == line_2.getEndY() - && line_1.getEndX() == line_2.getEndX() - && line_1.getStartY() == line_2.getStartY() - && line_1.getStartX() == line_2.getStartX()) {// both lines - // coincide - if (m_b_is_simple) - return errorCoincident(); - return 0; - } else - return errorCracking(); - } - - int compareNonHorizontalLowerEnd_(SimpleEdge line_1, SimpleEdge line_2) { - int sign = 1; - if (line_1.m_line.getStartY() < line_2.m_line.getStartY()) { - sign = -1; - SimpleEdge tmp = line_1; - line_1 = line_2; - line_2 = tmp; - } - - Line l1 = line_1.m_line; - Line l2 = line_2.m_line; - // Now line_1 has Start point higher than line_2 startpoint. - double x_1 = l1.getStartX() - l2.getStartX(); - double x2 = line_2.m_dxdy * (l1.getStartY() - l2.getStartY()); - double tol = m_tolerance_10; - if (x_1 < x2 - tol) - return -sign; - else if (x_1 > x2 + tol) - return sign; - else // Possible problem - { - if (l2._isIntersectingPoint(l1.getStartXY(), m_tolerance, true)) - return errorCracking(); - return x_1 < x2 ? -sign : sign; - } - } - - int compareNonHorizontalUpperEnd_(SimpleEdge line_1, SimpleEdge line_2) { - int sign = 1; - if (line_2.m_line.getEndY() < line_1.m_line.getEndY()) { - sign = -1; - SimpleEdge tmp = line_1; - line_1 = line_2; - line_2 = tmp; - } - - Line l1 = line_1.m_line; - Line l2 = line_2.m_line; - // Now line_1 has End point lower than line_2 endpoint. - double x_1 = l1.getEndX() - l2.getStartX(); - double x2 = line_2.m_dxdy * (l1.getEndY() - l2.getStartY()); - double tol = m_tolerance_10; - if (x_1 < x2 - tol) - return -sign; - else if (x_1 > x2 + tol) - return sign; - else // Possible problem - { - if (l2._isIntersectingPoint(l1.getEndXY(), m_tolerance, true)) - return errorCracking(); - return x_1 < x2 ? -sign : sign; - } - } - - int errorCoincident() {// two segments coincide. - m_b_intersection_detected = true; - assert (m_b_is_simple); - NonSimpleResult.Reason reason = NonSimpleResult.Reason.CrossOver; - m_non_simple_result = new NonSimpleResult(reason, m_vertex_1, - m_vertex_2); - return -1; - } - - int errorCracking() {// cracking error - m_b_intersection_detected = true; - if (m_b_is_simple) {// only report the reason in IsSimple. Do not do - // that for regular cracking. - NonSimpleResult.Reason reason = NonSimpleResult.Reason.Cracking; - m_non_simple_result = new NonSimpleResult(reason, m_vertex_1, - m_vertex_2); - } else {// reset cached data after detected intersection - m_prev_1 = -1; - m_prev_2 = -1; - m_vertex_1 = -1; - m_vertex_2 = -1; - } - return -1; - } - - int compareSegments_(int left, int right, SimpleEdge segLeft, - SimpleEdge segRight) { - if (m_b_intersection_detected) - return -1; - - boolean sameY = m_prev_y == m_sweep_y && m_prev_x == m_sweep_x; - double xleft; - if (sameY && left == m_prev_1) - xleft = m_prevx_1; - else { - xleft = NumberUtils.NaN(); - m_prev_1 = -1; - } - double xright; - if (sameY && right == m_prev_2) - xright = m_prevx_2; - else { - xright = NumberUtils.NaN(); - m_prev_2 = -1; - } - - // Quickly compare x projections. - Envelope1D envLeft = segLeft.m_segment.queryInterval( - VertexDescription.Semantics.POSITION, 0); - Envelope1D envRight = segRight.m_segment.queryInterval( - VertexDescription.Semantics.POSITION, 0); - if (envLeft.vmax < envRight.vmin) - return -1; - if (envRight.vmax < envLeft.vmin) - return 1; - - m_prev_y = m_sweep_y; - m_prev_x = m_sweep_x; - - // Now do intersection with the sweep line (it is a line parallel to the - // axis x.) - if (NumberUtils.isNaN(xleft)) { - m_prev_1 = left; - double x = segLeft.m_segment.intersectionOfYMonotonicWithAxisX( - m_sweep_y, m_sweep_x); - xleft = x; - m_prevx_1 = x; - } - if (NumberUtils.isNaN(xright)) { - m_prev_2 = right; - double x = segRight.m_segment.intersectionOfYMonotonicWithAxisX( - m_sweep_y, m_sweep_x); - xright = x; - m_prevx_2 = x; - } - - if (Math.abs(xleft - xright) <= m_tolerance) { - // special processing as we cannot decide in a simple way. - return compareTwoSegments_(segLeft.m_segment, segRight.m_segment); - } else { - return xleft < xright ? -1 : xleft > xright ? 1 : 0; - } - } - - SweepComparator(EditShape shape, double tol, boolean bIsSimple) { - super(true); - m_shape = shape; - m_sweep_y = NumberUtils.TheNaN; - m_sweep_x = 0; - m_prev_x = 0; - m_prev_y = NumberUtils.TheNaN; - m_tolerance = tol; - m_tolerance_10 = 10 * tol; - m_prevx_2 = NumberUtils.TheNaN; - m_prevx_1 = NumberUtils.TheNaN; - m_b_intersection_detected = false; - m_prev_1 = -1; - m_prev_2 = -1; - m_vertex_1 = -1; - m_vertex_2 = -1; - m_current_node = -1; - m_b_is_simple = bIsSimple; - m_temp_simple_edge_1 = new SimpleEdge(); - m_temp_simple_edge_2 = new SimpleEdge(); - - int s = Math.min(shape.getTotalPointCount() * 3 / 2, - (int) (67 /* SIMPLEDGE_CACHESIZE */)); - int cache_size = Math.min((int) 7, s); - // m_simple_edges_buffer.reserve(cache_size);//must be reserved and - // never grow beyond reserved size - - m_simple_edges_buffer = new ArrayList(); - m_simple_edges_recycle = new ArrayList(); - m_simple_edges_cache = new ArrayList(); - - for (int i = 0; i < cache_size; i++) - m_simple_edges_cache.add(null); - } - - // Makes the comparator to forget about the last detected intersection. - // Need to be called after the intersection has been resolved. - void clearIntersectionDetectedFlag() { - m_b_intersection_detected = false; - } - - // Returns True if there has been intersection detected during compare call. - // Once intersection is detected subsequent calls to compare method do - // nothing until clear_intersection_detected_flag is called. - boolean intersectionDetected() { - return m_b_intersection_detected; - } - - // Returns the node at which the intersection has been detected - int getLastComparedNode() { - return m_current_node; - } - - // When used in IsSimple (see corresponding parameter in ctor), returns the - // reason of non-simplicity - NonSimpleResult getResult() { - return m_non_simple_result; - } - - // Sets new sweep line position. - void setSweepY(double y, double x) { - // _ASSERT(m_sweep_y != y || m_sweep_x != x); - m_sweep_y = y; - m_sweep_x = x; - m_prev_1 = -1; - m_prev_2 = -1; - m_vertex_1 = -1; - m_vertex_2 = -1; - } - - // The compare method. Compares x values of the edge given by its origin - // (elm) and the edge in the sweep structure and checks them for - // intersection at the same time. - @Override - int compare(Treap treap, int left, int node) { - // Compares two segments on a sweep line passing through m_sweep_y, - // m_sweep_x. - if (m_b_intersection_detected) - return -1; - - int right = treap.getElement(node); - m_current_node = node; - return compareSegments(left, left, right, right); - } - - int compareSegments(int leftElm, int left_vertex, int right_elm, - int right_vertex) { - SimpleEdge edgeLeft = tryGetCachedEdge_(leftElm); - if (edgeLeft == null) { - if (m_vertex_1 == left_vertex) - edgeLeft = m_temp_simple_edge_1; - else { - m_vertex_1 = left_vertex; - edgeLeft = tryCreateCachedEdge_(leftElm); - if (edgeLeft == null) { - edgeLeft = m_temp_simple_edge_1; - m_temp_simple_edge_1.m_value = leftElm; - } - initSimpleEdge_(edgeLeft, left_vertex); - } - } else - m_vertex_1 = left_vertex; - - SimpleEdge edgeRight = tryGetCachedEdge_(right_elm); - if (edgeRight == null) { - if (m_vertex_2 == right_vertex) - edgeRight = m_temp_simple_edge_2; - else { - m_vertex_2 = right_vertex; - edgeRight = tryCreateCachedEdge_(right_elm); - if (edgeRight == null) { - edgeRight = m_temp_simple_edge_2; - m_temp_simple_edge_2.m_value = right_elm; - } - initSimpleEdge_(edgeRight, right_vertex); - } - } else - m_vertex_2 = right_vertex; - - if (edgeLeft.m_b_curve || edgeRight.m_b_curve) - return compareSegments_(left_vertex, right_vertex, edgeLeft, - edgeRight); - - // Usually we work with lines, so process them in the fastest way. - // First check - assume segments are far apart. compare x intervals - if (edgeLeft.m_env.vmax < edgeRight.m_env.vmin) - return -1; - if (edgeRight.m_env.vmax < edgeLeft.m_env.vmin) - return 1; - - // compare case by case. - int kind = edgeLeft.m_b_horizontal ? 1 : 0; - kind |= edgeRight.m_b_horizontal ? 2 : 0; - if (kind == 0)// both segments are non-horizontal - return compareNonHorizontal_(edgeLeft, edgeRight); - else if (kind == 1) // line_1 horizontal, line_2 is not - return compareHorizontal1_(edgeLeft.m_line, edgeRight.m_line); - else if (kind == 2) // line_2 horizontal, line_1 is not - return compareHorizontal1_(edgeRight.m_line, edgeLeft.m_line) * -1; - else - // if (kind == 3) //both horizontal - return compareHorizontal2_(edgeLeft.m_line, edgeRight.m_line); - } - - @Override - void onDelete(int elm) { - tryDeleteCachedEdge_(elm); - } - - @Override - void onSet(int oldelm) { - tryDeleteCachedEdge_(oldelm); - } - - @Override - void onEndSearch(int elm) { - tryDeleteCachedEdge_(elm); - } - - @Override - void onAddUniqueElementFailed(int elm) { - tryDeleteCachedEdge_(elm); - } + static final class SimpleEdge { + int m_value; + Line m_line; + Segment m_segment; + Envelope1D m_env; + double m_dxdy; + boolean m_b_horizontal; + boolean m_b_curve; + + SimpleEdge() { + m_value = -1; + m_line = new Line(); + m_dxdy = 55555555; + m_b_horizontal = false; + m_b_curve = false; + + m_env = new Envelope1D(); + m_env.setCoordsNoNaN_(0, 0); + } + } + + private EditShape m_shape; + boolean m_b_intersection_detected; + NonSimpleResult m_non_simple_result; + // Index 1 corresponds to the left segments, index 2 - right, e.g. m_line_1, + // m_line_2 + SimpleEdge m_temp_simple_edge_1; + SimpleEdge m_temp_simple_edge_2; + + int m_prev_1; + int m_prev_2; + int m_vertex_1; + int m_vertex_2; + int m_current_node; + double m_prevx_1; + double m_prevx_2; + double m_prev_y; + double m_prev_x; + double m_sweep_y; + double m_sweep_x; + double m_tolerance; + double m_tolerance_10; + boolean m_b_is_simple; + + ArrayList m_simple_edges_cache; + ArrayList m_simple_edges_recycle; + ArrayList m_simple_edges_buffer; + + // Returns a cached edge for the given value. May return NULL. + SimpleEdge tryGetCachedEdge_(int value) { + SimpleEdge se = m_simple_edges_cache.get((value & NumberUtils.intMax()) % m_simple_edges_cache.size()); + if (se != null) { + if (se.m_value == value) + return se; + else { + // int i = 0; + // cache collision + } + } + return null; + } + + // Removes cached edge from the cache for the given value. + void tryDeleteCachedEdge_(int value) { + int ind = (value & NumberUtils.intMax()) % m_simple_edges_cache.size(); + SimpleEdge se = m_simple_edges_cache.get(ind); + if (se != null && se.m_value == value) {// this value is cached + m_simple_edges_recycle.add(se); + m_simple_edges_cache.set(ind, null); + } else { + // The value has not been cached + } + } + + // Creates a cached edge. May fail and return NULL. + SimpleEdge tryCreateCachedEdge_(int value) { + int ind = (value & NumberUtils.intMax()) % m_simple_edges_cache.size(); + SimpleEdge se = m_simple_edges_cache.get(ind); + if (se == null) { + if (m_simple_edges_recycle.isEmpty()) { + // assert(m_simple_edges_buffer.size() < + // m_simple_edges_buffer.capacity());//should never happen + // assert(m_simple_edges_buffer.size() < + // m_simple_edges_cache.size());//should never happen + m_simple_edges_buffer.add(new SimpleEdge()); + se = m_simple_edges_buffer + .get(m_simple_edges_buffer.size() - 1); + } else { + se = m_simple_edges_recycle + .get(m_simple_edges_recycle.size() - 1); + m_simple_edges_recycle + .remove(m_simple_edges_recycle.size() - 1); + } + + se.m_value = value; + m_simple_edges_cache.set(ind, se); + return se; + } else { + assert (se.m_value != value);// do not call TryCreateCachedEdge + // twice. + } + + return null; + } + + void initSimpleEdge_(SweepComparator.SimpleEdge se, int vertex) { + se.m_segment = m_shape.getSegment(vertex); + se.m_b_curve = se.m_segment != null; + if (!se.m_b_curve) { + m_shape.queryLineConnector(vertex, se.m_line); + se.m_segment = se.m_line; + se.m_env.setCoordsNoNaN_(se.m_line.getStartX(), se.m_line.getEndX()); + se.m_env.vmax += m_tolerance; + se.m_line.orientBottomUp_(); + se.m_b_horizontal = se.m_line.getEndY() == se.m_line.getStartY(); + if (!se.m_b_horizontal) { + se.m_dxdy = (se.m_line.getEndX() - se.m_line.getStartX()) + / (se.m_line.getEndY() - se.m_line.getStartY()); + } + } else { + // se.m_segment = se.m_segment_sptr.get(); + } + } + + // Compares seg_1 and seg_2 x coordinates of intersection with the line + // parallel to axis x, passing through the coordinate y. + // If segments intersect not at the endpoint, the m_b_intersection_detected + // is set. + int compareTwoSegments_(Segment seg_1, Segment seg_2) { + int res = seg_1._isIntersecting(seg_2, m_tolerance, true); + if (res != 0) { + if (res == 2) + return errorCoincident(); + else + return errorCracking(); + } + + Point2D start_1 = seg_1.getStartXY(); + Point2D end1 = seg_1.getEndXY(); + Point2D start2 = seg_2.getStartXY(); + Point2D end2 = seg_2.getEndXY(); + Point2D ptSweep = new Point2D(); + ptSweep.setCoords(m_sweep_x, m_sweep_y); + if (start_1.isEqual(start2) && m_sweep_y == start_1.y) { + assert (start_1.compare(end1) < 0 && start2.compare(end2) < 0); + if (end1.compare(end2) < 0) + ptSweep.setCoords(end1); + else + ptSweep.setCoords(end2); + } else if (start_1.isEqual(end2) && m_sweep_y == start_1.y) { + assert (start_1.compare(end1) < 0 && start2.compare(end2) > 0); + if (end1.compare(start2) < 0) + ptSweep.setCoords(end1); + else + ptSweep.setCoords(start2); + } else if (start2.isEqual(end1) && m_sweep_y == start2.y) { + assert (end1.compare(start_1) < 0 && start2.compare(end2) < 0); + if (start_1.compare(end2) < 0) + ptSweep.setCoords(start_1); + else + ptSweep.setCoords(end2); + } else if (end1.isEqual(end2) && m_sweep_y == end1.y) { + assert (start_1.compare(end1) > 0 && start2.compare(end2) > 0); + if (start_1.compare(start2) < 0) + ptSweep.setCoords(start_1); + else + ptSweep.setCoords(start2); + } + + double xleft = seg_1.intersectionOfYMonotonicWithAxisX(ptSweep.y, + ptSweep.x); + double xright = seg_2.intersectionOfYMonotonicWithAxisX(ptSweep.y, + ptSweep.x); + assert (xleft != xright); + return xleft < xright ? -1 : 1; + } + + int compareNonHorizontal_(SimpleEdge line_1, SimpleEdge line_2) { + if (line_1.m_line.getStartY() == line_2.m_line.getStartY() + && line_1.m_line.getStartX() == line_2.m_line.getStartX()) {// connected + // at + // the + // start + // V + // shape + if (line_1.m_line.getEndY() == line_2.m_line.getEndY() + && line_1.m_line.getEndX() == line_2.m_line.getEndX()) {// connected + // at + // another + // end + // also + if (m_b_is_simple) + return errorCoincident(); + return 0; + } + + return compareNonHorizontalUpperEnd_(line_1, line_2); + } + + if (line_1.m_line.getEndY() == line_2.m_line.getEndY() + && line_1.m_line.getEndX() == line_2.m_line.getEndX()) { + // the case of upside-down V. + return compareNonHorizontalLowerEnd_(line_1, line_2); + } + + int lower = compareNonHorizontalLowerEnd_(line_1, line_2); + int upper = compareNonHorizontalUpperEnd_(line_1, line_2); + if (lower < 0 && upper < 0) + return -1; + if (lower > 0 && upper > 0) + return 1; + + return errorCracking(); + } + + int compareHorizontal1Case1_(Line line_1, Line line_2) { + // line_2 goes up and line_1 is horizontal connected at the start going + // to the right. + if (line_1.getEndX() > line_2.getEndX()) { + // / + // / + // +------------------ + if (line_2.getEndX() > line_2.getStartX() + && line_2.getEndY() - line_2.getStartY() < 2 * m_tolerance + && line_1._isIntersectingPoint(line_2.getEndXY(), + m_tolerance, true)) + return errorCracking(); + } else { + // / + // / + // / + // +-- + assert (line_2.getEndX() - line_2.getStartX() != 0); + // Note: line_2 cannot be vertical here + // Avoid expensive is_intersecting_ by providing a simple estimate. + double dydx = (line_2.getEndY() - line_2.getStartY()) + / (line_2.getEndX() - line_2.getStartX()); + double d = dydx * (line_1.getEndX() - line_1.getStartX()); + if (d < m_tolerance_10 + && line_2._isIntersectingPoint(line_1.getEndXY(), + m_tolerance, true)) + return errorCracking(); + } + + return 1; + } + + int compareHorizontal1Case2_(Line line_1, Line line_2) { + // -----------------+ + // / + // / + // / + // line_2 goes up and below line_1. line_1 is horizontal connected at + // the end to the line_2 end. + if (line_1.getStartX() < line_2.getStartX()) { + if (line_2.getEndX() > line_2.getStartX() + && line_2.getEndY() - line_2.getStartY() < 2 * m_tolerance + && line_1._isIntersectingPoint(line_2.getEndXY(), + m_tolerance, true)) + return errorCracking(); + } else { + // --+ + // / + // / + // / + // Avoid expensive is_intersecting_ by providing a simple estimate. + double dydx = (line_2.getEndY() - line_2.getStartY()) + / (line_2.getEndX() - line_2.getStartX()); + double d = dydx * (line_1.getStartX() - line_1.getEndX()); + if (d < m_tolerance_10 + && line_2._isIntersectingPoint(line_1.getStartXY(), + m_tolerance, true)) + return errorCracking(); + } + + return -1; + } + + int compareHorizontal1Case3_(Line line_1, Line line_2) { + Point2D v0 = new Point2D(); + v0.sub(line_2.getEndXY(), line_2.getStartXY()); + v0.rightPerpendicular(); + v0.normalize(); + Point2D v_1 = new Point2D(); + v_1.sub(line_1.getStartXY(), line_2.getStartXY()); + Point2D v_2 = new Point2D(); + v_2.sub(line_1.getEndXY(), line_2.getStartXY()); + double d_1 = v_1.dotProduct(v0); + double d_2 = v_2.dotProduct(v0); + + double ad1 = Math.abs(d_1); + double ad2 = Math.abs(d_2); + + if (ad1 < ad2) { + if (ad1 < m_tolerance_10 + && line_2._isIntersectingPoint(line_1.getStartXY(), + m_tolerance, true)) + return errorCracking(); + } else { + if (ad2 < m_tolerance_10 + && line_2._isIntersectingPoint(line_1.getEndXY(), + m_tolerance, true)) + return errorCracking(); + } + + if (d_1 < 0 && d_2 < 0) + return -1; + + if (d_1 > 0 && d_2 > 0) + return 1; + + return errorCracking(); + } + + int compareHorizontal1_(Line line_1, Line line_2) { + // Two most important cases of connecting edges + if (line_1.getStartY() == line_2.getStartY() + && line_1.getStartX() == line_2.getStartX()) { + return compareHorizontal1Case1_(line_1, line_2); + } + + if (line_1.getEndY() == line_2.getEndY() + && line_1.getEndX() == line_2.getEndX()) { + return compareHorizontal1Case2_(line_1, line_2); + } + + return compareHorizontal1Case3_(line_1, line_2); + } + + int compareHorizontal2_(Line line_1, Line line_2) { + if (line_1.getEndY() == line_2.getEndY() + && line_1.getEndX() == line_2.getEndX() + && line_1.getStartY() == line_2.getStartY() + && line_1.getStartX() == line_2.getStartX()) {// both lines + // coincide + if (m_b_is_simple) + return errorCoincident(); + return 0; + } else + return errorCracking(); + } + + int compareNonHorizontalLowerEnd_(SimpleEdge line_1, SimpleEdge line_2) { + int sign = 1; + if (line_1.m_line.getStartY() < line_2.m_line.getStartY()) { + sign = -1; + SimpleEdge tmp = line_1; + line_1 = line_2; + line_2 = tmp; + } + + Line l1 = line_1.m_line; + Line l2 = line_2.m_line; + // Now line_1 has Start point higher than line_2 startpoint. + double x_1 = l1.getStartX() - l2.getStartX(); + double x2 = line_2.m_dxdy * (l1.getStartY() - l2.getStartY()); + double tol = m_tolerance_10; + if (x_1 < x2 - tol) + return -sign; + else if (x_1 > x2 + tol) + return sign; + else // Possible problem + { + if (l2._isIntersectingPoint(l1.getStartXY(), m_tolerance, true)) + return errorCracking(); + return x_1 < x2 ? -sign : sign; + } + } + + int compareNonHorizontalUpperEnd_(SimpleEdge line_1, SimpleEdge line_2) { + int sign = 1; + if (line_2.m_line.getEndY() < line_1.m_line.getEndY()) { + sign = -1; + SimpleEdge tmp = line_1; + line_1 = line_2; + line_2 = tmp; + } + + Line l1 = line_1.m_line; + Line l2 = line_2.m_line; + // Now line_1 has End point lower than line_2 endpoint. + double x_1 = l1.getEndX() - l2.getStartX(); + double x2 = line_2.m_dxdy * (l1.getEndY() - l2.getStartY()); + double tol = m_tolerance_10; + if (x_1 < x2 - tol) + return -sign; + else if (x_1 > x2 + tol) + return sign; + else // Possible problem + { + if (l2._isIntersectingPoint(l1.getEndXY(), m_tolerance, true)) + return errorCracking(); + return x_1 < x2 ? -sign : sign; + } + } + + int errorCoincident() {// two segments coincide. + m_b_intersection_detected = true; + assert (m_b_is_simple); + NonSimpleResult.Reason reason = NonSimpleResult.Reason.CrossOver; + m_non_simple_result = new NonSimpleResult(reason, m_vertex_1, + m_vertex_2); + return -1; + } + + int errorCracking() {// cracking error + m_b_intersection_detected = true; + if (m_b_is_simple) {// only report the reason in IsSimple. Do not do + // that for regular cracking. + NonSimpleResult.Reason reason = NonSimpleResult.Reason.Cracking; + m_non_simple_result = new NonSimpleResult(reason, m_vertex_1, + m_vertex_2); + } else {// reset cached data after detected intersection + m_prev_1 = -1; + m_prev_2 = -1; + m_vertex_1 = -1; + m_vertex_2 = -1; + } + return -1; + } + + int compareSegments_(int left, int right, SimpleEdge segLeft, + SimpleEdge segRight) { + if (m_b_intersection_detected) + return -1; + + boolean sameY = m_prev_y == m_sweep_y && m_prev_x == m_sweep_x; + double xleft; + if (sameY && left == m_prev_1) + xleft = m_prevx_1; + else { + xleft = NumberUtils.NaN(); + m_prev_1 = -1; + } + double xright; + if (sameY && right == m_prev_2) + xright = m_prevx_2; + else { + xright = NumberUtils.NaN(); + m_prev_2 = -1; + } + + // Quickly compare x projections. + Envelope1D envLeft = segLeft.m_segment.queryInterval( + VertexDescription.Semantics.POSITION, 0); + Envelope1D envRight = segRight.m_segment.queryInterval( + VertexDescription.Semantics.POSITION, 0); + if (envLeft.vmax < envRight.vmin) + return -1; + if (envRight.vmax < envLeft.vmin) + return 1; + + m_prev_y = m_sweep_y; + m_prev_x = m_sweep_x; + + // Now do intersection with the sweep line (it is a line parallel to the + // axis x.) + if (NumberUtils.isNaN(xleft)) { + m_prev_1 = left; + double x = segLeft.m_segment.intersectionOfYMonotonicWithAxisX( + m_sweep_y, m_sweep_x); + xleft = x; + m_prevx_1 = x; + } + if (NumberUtils.isNaN(xright)) { + m_prev_2 = right; + double x = segRight.m_segment.intersectionOfYMonotonicWithAxisX( + m_sweep_y, m_sweep_x); + xright = x; + m_prevx_2 = x; + } + + if (Math.abs(xleft - xright) <= m_tolerance) { + // special processing as we cannot decide in a simple way. + return compareTwoSegments_(segLeft.m_segment, segRight.m_segment); + } else { + return xleft < xright ? -1 : xleft > xright ? 1 : 0; + } + } + + SweepComparator(EditShape shape, double tol, boolean bIsSimple) { + super(true); + m_shape = shape; + m_sweep_y = NumberUtils.TheNaN; + m_sweep_x = 0; + m_prev_x = 0; + m_prev_y = NumberUtils.TheNaN; + m_tolerance = tol; + m_tolerance_10 = 10 * tol; + m_prevx_2 = NumberUtils.TheNaN; + m_prevx_1 = NumberUtils.TheNaN; + m_b_intersection_detected = false; + m_prev_1 = -1; + m_prev_2 = -1; + m_vertex_1 = -1; + m_vertex_2 = -1; + m_current_node = -1; + m_b_is_simple = bIsSimple; + m_temp_simple_edge_1 = new SimpleEdge(); + m_temp_simple_edge_2 = new SimpleEdge(); + + int s = Math.min(shape.getTotalPointCount() * 3 / 2, + (int) (67 /* SIMPLEDGE_CACHESIZE */)); + int cache_size = Math.min((int) 7, s); + // m_simple_edges_buffer.reserve(cache_size);//must be reserved and + // never grow beyond reserved size + + m_simple_edges_buffer = new ArrayList(); + m_simple_edges_recycle = new ArrayList(); + m_simple_edges_cache = new ArrayList(); + + for (int i = 0; i < cache_size; i++) + m_simple_edges_cache.add(null); + } + + // Makes the comparator to forget about the last detected intersection. + // Need to be called after the intersection has been resolved. + void clearIntersectionDetectedFlag() { + m_b_intersection_detected = false; + } + + // Returns True if there has been intersection detected during compare call. + // Once intersection is detected subsequent calls to compare method do + // nothing until clear_intersection_detected_flag is called. + boolean intersectionDetected() { + return m_b_intersection_detected; + } + + // Returns the node at which the intersection has been detected + int getLastComparedNode() { + return m_current_node; + } + + // When used in IsSimple (see corresponding parameter in ctor), returns the + // reason of non-simplicity + NonSimpleResult getResult() { + return m_non_simple_result; + } + + // Sets new sweep line position. + void setSweepY(double y, double x) { + // _ASSERT(m_sweep_y != y || m_sweep_x != x); + m_sweep_y = y; + m_sweep_x = x; + m_prev_1 = -1; + m_prev_2 = -1; + m_vertex_1 = -1; + m_vertex_2 = -1; + } + + // The compare method. Compares x values of the edge given by its origin + // (elm) and the edge in the sweep structure and checks them for + // intersection at the same time. + @Override + int compare(Treap treap, int left, int node) { + // Compares two segments on a sweep line passing through m_sweep_y, + // m_sweep_x. + if (m_b_intersection_detected) + return -1; + + int right = treap.getElement(node); + m_current_node = node; + return compareSegments(left, left, right, right); + } + + int compareSegments(int leftElm, int left_vertex, int right_elm, + int right_vertex) { + SimpleEdge edgeLeft = tryGetCachedEdge_(leftElm); + if (edgeLeft == null) { + if (m_vertex_1 == left_vertex) + edgeLeft = m_temp_simple_edge_1; + else { + m_vertex_1 = left_vertex; + edgeLeft = tryCreateCachedEdge_(leftElm); + if (edgeLeft == null) { + edgeLeft = m_temp_simple_edge_1; + m_temp_simple_edge_1.m_value = leftElm; + } + initSimpleEdge_(edgeLeft, left_vertex); + } + } else + m_vertex_1 = left_vertex; + + SimpleEdge edgeRight = tryGetCachedEdge_(right_elm); + if (edgeRight == null) { + if (m_vertex_2 == right_vertex) + edgeRight = m_temp_simple_edge_2; + else { + m_vertex_2 = right_vertex; + edgeRight = tryCreateCachedEdge_(right_elm); + if (edgeRight == null) { + edgeRight = m_temp_simple_edge_2; + m_temp_simple_edge_2.m_value = right_elm; + } + initSimpleEdge_(edgeRight, right_vertex); + } + } else + m_vertex_2 = right_vertex; + + if (edgeLeft.m_b_curve || edgeRight.m_b_curve) + return compareSegments_(left_vertex, right_vertex, edgeLeft, + edgeRight); + + // Usually we work with lines, so process them in the fastest way. + // First check - assume segments are far apart. compare x intervals + if (edgeLeft.m_env.vmax < edgeRight.m_env.vmin) + return -1; + if (edgeRight.m_env.vmax < edgeLeft.m_env.vmin) + return 1; + + // compare case by case. + int kind = edgeLeft.m_b_horizontal ? 1 : 0; + kind |= edgeRight.m_b_horizontal ? 2 : 0; + if (kind == 0)// both segments are non-horizontal + return compareNonHorizontal_(edgeLeft, edgeRight); + else if (kind == 1) // line_1 horizontal, line_2 is not + return compareHorizontal1_(edgeLeft.m_line, edgeRight.m_line); + else if (kind == 2) // line_2 horizontal, line_1 is not + return compareHorizontal1_(edgeRight.m_line, edgeLeft.m_line) * -1; + else + // if (kind == 3) //both horizontal + return compareHorizontal2_(edgeLeft.m_line, edgeRight.m_line); + } + + @Override + void onDelete(int elm) { + tryDeleteCachedEdge_(elm); + } + + @Override + void onSet(int oldelm) { + tryDeleteCachedEdge_(oldelm); + } + + @Override + void onEndSearch(int elm) { + tryDeleteCachedEdge_(elm); + } + + @Override + void onAddUniqueElementFailed(int elm) { + tryDeleteCachedEdge_(elm); + } } diff --git a/src/main/java/com/esri/core/geometry/SweepMonkierComparator.java b/src/main/java/com/esri/core/geometry/SweepMonkierComparator.java index eba6bd3a..2edeef22 100644 --- a/src/main/java/com/esri/core/geometry/SweepMonkierComparator.java +++ b/src/main/java/com/esri/core/geometry/SweepMonkierComparator.java @@ -28,107 +28,107 @@ package com.esri.core.geometry; class SweepMonkierComparator extends Treap.MonikerComparator { - protected EditShape m_shape; - protected boolean m_b_intersection_detected; - protected Point2D m_point_of_interest; - protected Line m_line_1; - protected Envelope1D m_env; - protected int m_vertex_1; - protected int m_current_node; - protected double m_min_dist; - protected double m_tolerance; - - SweepMonkierComparator(EditShape shape, double tol) { - m_shape = shape; - m_tolerance = tol; - m_b_intersection_detected = false; - m_vertex_1 = -1; - m_env = new Envelope1D(); - m_point_of_interest = new Point2D(); - m_point_of_interest.setNaN(); - m_line_1 = new Line(); - m_current_node = -1; - m_min_dist = NumberUtils.doubleMax(); - } - - int getCurrentNode() { - return m_current_node; - } - - // Makes the comparator to forget about the last detected intersection. - // Need to be called after the intersection has been resolved. - void clearIntersectionDetectedFlag() { - m_b_intersection_detected = false; - m_min_dist = NumberUtils.doubleMax(); - } - - // Returns True if there has been intersection detected during compare call. - // Once intersection is detected subsequent calls to compare method do - // nothing until clear_intersection_detected_flag is called. - boolean intersectionDetected() { - return m_b_intersection_detected; - } - - void setPoint(Point2D pt) { - m_point_of_interest.setCoords(pt); - } - - // Compares the moniker, contained in the Moniker_comparator with the - // element contained in the given node. - @Override - int compare(Treap treap, int node) { - int vertex = treap.getElement(node); - return compareVertex_(treap, node, vertex); - } - - protected int compareVertex_(Treap treap, int node, int vertex) { - boolean bCurve = m_shape.getSegment(vertex) != null; - if (!bCurve) { - m_shape.queryLineConnector(vertex, m_line_1); - m_env.setCoordsNoNaN_(m_line_1.getStartX(), m_line_1.getEndX()); - } - - if (bCurve) { - throw new GeometryException("not implemented"); - } - - if (m_point_of_interest.x + m_tolerance < m_env.vmin) - return -1; - - if (m_point_of_interest.x - m_tolerance > m_env.vmax) - return 1; - - if (m_line_1.getStartY() == m_line_1.getEndY()) { - m_current_node = node; - m_b_intersection_detected = true; - return 0; - } - - m_line_1.orientBottomUp_(); - Point2D start = m_line_1.getStartXY(); - Point2D vector = new Point2D(); - vector.sub(m_line_1.getEndXY(), start); - vector.rightPerpendicular(); - Point2D v_2 = new Point2D(); - v_2.sub(m_point_of_interest, start); - double dot = vector.dotProduct(v_2); - dot /= vector.length(); - if (dot < -m_tolerance * 10) - return -1; - if (dot > m_tolerance * 10) - return 1; - - if (m_line_1.isIntersecting(m_point_of_interest, m_tolerance)) { - double absDot = Math.abs(dot); - if (absDot < m_min_dist) { - m_current_node = node; - m_min_dist = absDot; - } - m_b_intersection_detected = true; - if (absDot < 0.25 * m_tolerance) - return 0; - } - - return dot < 0 ? -1 : 1; - } + protected EditShape m_shape; + protected boolean m_b_intersection_detected; + protected Point2D m_point_of_interest; + protected Line m_line_1; + protected Envelope1D m_env; + protected int m_vertex_1; + protected int m_current_node; + protected double m_min_dist; + protected double m_tolerance; + + SweepMonkierComparator(EditShape shape, double tol) { + m_shape = shape; + m_tolerance = tol; + m_b_intersection_detected = false; + m_vertex_1 = -1; + m_env = new Envelope1D(); + m_point_of_interest = new Point2D(); + m_point_of_interest.setNaN(); + m_line_1 = new Line(); + m_current_node = -1; + m_min_dist = NumberUtils.doubleMax(); + } + + int getCurrentNode() { + return m_current_node; + } + + // Makes the comparator to forget about the last detected intersection. + // Need to be called after the intersection has been resolved. + void clearIntersectionDetectedFlag() { + m_b_intersection_detected = false; + m_min_dist = NumberUtils.doubleMax(); + } + + // Returns True if there has been intersection detected during compare call. + // Once intersection is detected subsequent calls to compare method do + // nothing until clear_intersection_detected_flag is called. + boolean intersectionDetected() { + return m_b_intersection_detected; + } + + void setPoint(Point2D pt) { + m_point_of_interest.setCoords(pt); + } + + // Compares the moniker, contained in the Moniker_comparator with the + // element contained in the given node. + @Override + int compare(Treap treap, int node) { + int vertex = treap.getElement(node); + return compareVertex_(treap, node, vertex); + } + + protected int compareVertex_(Treap treap, int node, int vertex) { + boolean bCurve = m_shape.getSegment(vertex) != null; + if (!bCurve) { + m_shape.queryLineConnector(vertex, m_line_1); + m_env.setCoordsNoNaN_(m_line_1.getStartX(), m_line_1.getEndX()); + } + + if (bCurve) { + throw new GeometryException("not implemented"); + } + + if (m_point_of_interest.x + m_tolerance < m_env.vmin) + return -1; + + if (m_point_of_interest.x - m_tolerance > m_env.vmax) + return 1; + + if (m_line_1.getStartY() == m_line_1.getEndY()) { + m_current_node = node; + m_b_intersection_detected = true; + return 0; + } + + m_line_1.orientBottomUp_(); + Point2D start = m_line_1.getStartXY(); + Point2D vector = new Point2D(); + vector.sub(m_line_1.getEndXY(), start); + vector.rightPerpendicular(); + Point2D v_2 = new Point2D(); + v_2.sub(m_point_of_interest, start); + double dot = vector.dotProduct(v_2); + dot /= vector.length(); + if (dot < -m_tolerance * 10) + return -1; + if (dot > m_tolerance * 10) + return 1; + + if (m_line_1.isIntersecting(m_point_of_interest, m_tolerance)) { + double absDot = Math.abs(dot); + if (absDot < m_min_dist) { + m_current_node = node; + m_min_dist = absDot; + } + m_b_intersection_detected = true; + if (absDot < 0.25 * m_tolerance) + return 0; + } + + return dot < 0 ? -1 : 1; + } } diff --git a/src/main/java/com/esri/core/geometry/TopoGraph.java b/src/main/java/com/esri/core/geometry/TopoGraph.java index 9816dfd8..b5b2397a 100644 --- a/src/main/java/com/esri/core/geometry/TopoGraph.java +++ b/src/main/java/com/esri/core/geometry/TopoGraph.java @@ -29,2585 +29,2585 @@ final class TopoGraph { - static interface EnumInputMode { - - final static int enumInputModeBuildGraph = 0; - final static int enumInputModeSimplifyAlternate = 4 + 0; - final static int enumInputModeSimplifyWinding = 4 + 1; - final static int enumInputModeIsSimplePolygon = 4 + 3; - } - - EditShape m_shape; - - // cluster data: index, parentage, halfEdge, globalPrev, globalNext - StridedIndexTypeCollection m_clusterData; - StridedIndexTypeCollection m_clusterVertices; - int m_firstCluster; - int m_lastCluster; - // edge data: index, origin, faceParentage, edgeParentage, twin, prev, next - StridedIndexTypeCollection m_halfEdgeData; - // chain data index, half_edge, parentage, parentChain, firstIsland, - // nextInParent, prev, next - StridedIndexTypeCollection m_chainData; - AttributeStreamOfDbl m_chainAreas; - AttributeStreamOfDbl m_chainPerimeters; - - final int c_edgeParentageMask; - final int c_edgeBitMask; - int m_universeChain; - ArrayList m_edgeIndices; - ArrayList m_clusterIndices; - ArrayList m_chainIndices; - - int m_geometryIDIndex; // index of geometryIDs in the m_shape - int m_clusterIndex; // vertex index of cluster handles in the m_shape - int m_halfEdgeIndex; // vertex index of half-edges in the m_shape - int m_tmpHalfEdgeParentageIndex; - int m_tmpHalfEdgeWindingNumberIndex; - int m_tmpHalfEdgeOddEvenNumberIndex = -1; - - int m_universe_geomID = -1; - - boolean m_buildChains = true; - - private boolean m_dirty_check_failed = false; - private double m_check_dirty_planesweep_tolerance = Double.NaN; - - void check_dirty_planesweep(double tolerance) { - m_check_dirty_planesweep_tolerance = tolerance; - } - - boolean dirty_check_failed() { - return m_dirty_check_failed; - } - - NonSimpleResult m_non_simple_result = new NonSimpleResult(); - - int m_pointCount;// point count processed in this Topo_graph. Used to - // reserve data. - - static final class PlaneSweepComparator extends Treap.Comparator { - TopoGraph m_helper; - SegmentBuffer m_buffer_left; - SegmentBuffer m_buffer_right; - Envelope1D interval_left; - Envelope1D interval_right; - double m_y_scanline; - - PlaneSweepComparator(TopoGraph helper) { - m_helper = helper; - m_y_scanline = NumberUtils.TheNaN; - m_buffer_left = new SegmentBuffer(); - m_buffer_right = new SegmentBuffer(); - interval_left = new Envelope1D(); - interval_right = new Envelope1D(); - } - - @Override - int compare(Treap treap, int left, int node) { - int right = treap.getElement(node); - // can be sped up a little, because left or right stay the same - // while an edge is inserted into the tree. - m_helper.querySegmentXY(left, m_buffer_left); - m_helper.querySegmentXY(right, m_buffer_right); - Segment segLeft = m_buffer_left.get(); - Segment segRight = m_buffer_right.get(); - - // Prerequisite: The segments have the start point lexicographically - // above the end point. - assert (segLeft.getStartXY().compare(segLeft.getEndXY()) < 0); - assert (segRight.getStartXY().compare(segRight.getEndXY()) < 0); - - // Simple test for faraway segments - interval_left.setCoords(segLeft.getStartX(), segLeft.getEndX()); - interval_right.setCoords(segRight.getStartX(), segRight.getEndX()); - if (interval_left.vmax < interval_right.vmin) - return -1; - if (interval_left.vmin > interval_right.vmax) - return 1; - - boolean bLeftHorz = segLeft.getStartY() == segLeft.getEndY(); - boolean bRightHorz = segRight.getStartY() == segRight.getEndY(); - if (bLeftHorz || bRightHorz) { - if (bLeftHorz && bRightHorz) { - assert (interval_left.equals(interval_right)); - return 0; - } - - // left segment is horizontal. The right one is not. - // Prerequisite of this algorithm is that this can only happen - // when: - // left - // |right -------------------- end == end - // | | - // | left | - // -------------------- right | - // start == start - // or: - // right segment is horizontal. The left one is not. - // Prerequisite of this algorithm is that his can only happen - // when: - // right - // |left -------------------- end == end - // | | - // | right | - // -------------------- left | - // start == start - - if (segLeft.getStartY() == segRight.getStartY() - && segLeft.getStartX() == segRight.getStartX()) - return bLeftHorz ? 1 : -1; - else if (segLeft.getEndY() == segRight.getEndY() - && segLeft.getEndX() == segRight.getEndX()) - return bLeftHorz ? -1 : 1; - } - - // Now do actual intersections - double xLeft = segLeft.intersectionOfYMonotonicWithAxisX( - m_y_scanline, interval_left.vmin); - double xRight = segRight.intersectionOfYMonotonicWithAxisX( - m_y_scanline, interval_right.vmin); - - if (xLeft == xRight) { - // apparently these edges originate from same vertex and the - // scanline is on the vertex. move scanline a little. - double yLeft = segLeft.getEndY(); - double yRight = segRight.getEndY(); - double miny = Math.min(yLeft, yRight); - double y = (miny + m_y_scanline) * 0.5; - if (y == m_y_scanline) { - // assert(0);//ST: not a bug. just curious to see this - // happens. - y = miny; // apparently, one of the segments is almost - // horizontal line. - } - xLeft = segLeft.intersectionOfYMonotonicWithAxisX(y, - interval_left.vmin); - xRight = segRight.intersectionOfYMonotonicWithAxisX(y, - interval_right.vmin); - } - - return xLeft < xRight ? -1 : (xLeft > xRight ? 1 : 0); - } - - void setY(double y) { - m_y_scanline = y; - } - // void operator=(const Plane_sweep_comparator&); // do not allow - // operator = - } - - ; - - static final class TopoGraphAngleComparer extends IntComparator { - TopoGraph m_parent; - - TopoGraphAngleComparer(TopoGraph parent_) { - m_parent = parent_; - } - - @Override - public int compare(int v1, int v2) { - return m_parent.compareEdgeAngles_(v1, v2); - } - } - - ; - - static final class ClusterSweepMonikerComparator extends - Treap.MonikerComparator { - TopoGraph m_parent; - SegmentBuffer m_segment_buffer; - Point2D m_point; - Envelope1D m_interval; - - ClusterSweepMonikerComparator(TopoGraph parent) { - m_parent = parent; - m_segment_buffer = new SegmentBuffer(); - m_point = new Point2D(); - m_interval = new Envelope1D(); - } - - void setPointXY(Point2D pt) { - m_point.setCoords(pt); - } - - @Override - int compare(Treap treap, int node) { - int half_edge = treap.getElement(node); - - // can be sped up a little, because left or right stay the same - // while an edge is inserted into the tree. - m_parent.querySegmentXY(half_edge, m_segment_buffer); - Segment seg = m_segment_buffer.get(); - - // Simple test for faraway segments - m_interval.setCoords(seg.getStartX(), seg.getEndX()); - if (m_point.x < m_interval.vmin) - return -1; - - if (m_point.x > m_interval.vmax) - return 1; - - // Now do actual intersections - double x = seg.intersectionOfYMonotonicWithAxisX(m_point.y, - m_point.x); - - assert (x != m_point.x); - - return m_point.x < x ? -1 : (m_point.x > x ? 1 : 0); - } - } - - int newCluster_() { - if (m_clusterData == null) - m_clusterData = new StridedIndexTypeCollection(8); - - int cluster = m_clusterData.newElement(); - // m_clusterData->add(-1);//first vertex - m_clusterData.setField(cluster, 1, 0);// parentage - // m_clusterData->add(-1);//first half edge - // m_clusterData->add(-1);//prev cluster - // m_clusterData->add(-1);//next cluster - return cluster; - } - - int newHalfEdgePair_() { - if (m_halfEdgeData == null) - m_halfEdgeData = new StridedIndexTypeCollection(8); - - int halfEdge = m_halfEdgeData.newElement(); - // m_halfEdgeData.add(-1);//origin cluster - m_halfEdgeData.setField(halfEdge, 2, 0);// chain parentage - m_halfEdgeData.setField(halfEdge, 3, 0);// edge parentage - // m_halfEdgeData.add(-1);//twin - // m_halfEdgeData.add(-1);//prev - // m_halfEdgeData.add(-1);//next - int twinHalfEdge = m_halfEdgeData.newElement(); - // m_halfEdgeData.add(-1);//origin cluster - m_halfEdgeData.setField(twinHalfEdge, 2, 0);// chain parentage - m_halfEdgeData.setField(twinHalfEdge, 3, 0);// edge parentage - // m_halfEdgeData.add(-1);//twin - // m_halfEdgeData.add(-1);//prev - // m_halfEdgeData.add(-1);//next - setHalfEdgeTwin_(halfEdge, twinHalfEdge); - setHalfEdgeTwin_(twinHalfEdge, halfEdge); - return halfEdge; - } - - int newChain_() { - if (m_chainData == null) - m_chainData = new StridedIndexTypeCollection(8); - - int chain = m_chainData.newElement(); - // m_chainData->write(chain, + 1, -1);//half_edge - m_chainData.setField(chain, 2, 0);// parentage (geometric) - // m_chainData->write(m_chainReserved + 3, -1);//parent chain - // m_chainData->write(m_chainReserved + 4, -1);//firstIsland - // m_chainData->write(m_chainReserved + 5, -1);//nextInParent - // m_chainData->write(m_chainReserved + 6, -1);//prev - // m_chainData->write(m_chainReserved + 7, -1);//next - // m_chainReserved += 8; - return chain; - } - - int deleteChain_(int chain) { - // Note: this method cannot be after _PlaneSweep - assert (m_universeChain != chain); - int n = getChainNext(chain); - m_chainData.deleteElement(chain); - // Note: no need to update the first chain, because one should never try - // deleting the first (the universe) chain. - return n; - } - - int getClusterIndex_(int cluster) { - return m_clusterData.elementToIndex(cluster); - } - - void setClusterVertexIterator_(int cluster, int verticeList) { - m_clusterData.setField(cluster, 7, verticeList); - } - - void setClusterHalfEdge_(int cluster, int half_edge) { - m_clusterData.setField(cluster, 2, half_edge); - } - - void setClusterParentage_(int cluster, int parentage) { - m_clusterData.setField(cluster, 1, parentage); - } - - void setPrevCluster_(int cluster, int nextCluster) { - m_clusterData.setField(cluster, 3, nextCluster); - } - - void setNextCluster_(int cluster, int nextCluster) { - m_clusterData.setField(cluster, 4, nextCluster); - } - - void setClusterVertexIndex_(int cluster, int index) { - m_clusterData.setField(cluster, 5, index); - } - - int getClusterVertexIndex_(int cluster) { - return m_clusterData.getField(cluster, 5); - } - - void setClusterChain_(int cluster, int chain) { - m_clusterData.setField(cluster, 6, chain); - } - - void addClusterToExteriorChain_(int chain, int cluster) { - assert (getClusterChain(cluster) == -1); - setClusterChain_(cluster, chain); - // There is no link from the chain to the cluster. Only vice versa. - // Consider for change? - } - - int getHalfEdgeIndex_(int he) { - return m_halfEdgeData.elementToIndex(he); - } - - void setHalfEdgeOrigin_(int half_edge, int cluster) { - m_halfEdgeData.setField(half_edge, 1, cluster); - } - - void setHalfEdgeTwin_(int half_edge, int twinHalfEdge) { - m_halfEdgeData.setField(half_edge, 4, twinHalfEdge); - } - - void setHalfEdgePrev_(int half_edge, int prevHalfEdge) { - m_halfEdgeData.setField(half_edge, 5, prevHalfEdge); - } - - void setHalfEdgeNext_(int half_edge, int nextHalfEdge) { - m_halfEdgeData.setField(half_edge, 6, nextHalfEdge); - } - - // void set_half_edge_chain_parentage_(int half_edge, int - // chainParentageMask) { m_halfEdgeData.setField(half_edge + 2, - // chainParentageMask); } - void setHalfEdgeChain_(int half_edge, int chain) { - m_halfEdgeData.setField(half_edge, 2, chain); - } - - void setHalfEdgeParentage_(int half_edge, int parentageMask) { - m_halfEdgeData.setField(half_edge, 3, parentageMask); - } - - int getHalfEdgeParentageMask_(int half_edge) { - return m_halfEdgeData.getField(half_edge, 3); - } - - void setHalfEdgeVertexIterator_(int half_edge, int vertexIterator) { - m_halfEdgeData.setField(half_edge, 7, vertexIterator); - } - - void updateVertexToHalfEdgeConnectionHelper_(int half_edge, boolean bClear) { - int viter = getHalfEdgeVertexIterator(half_edge); - if (viter != -1) { - int he = bClear ? -1 : half_edge; - for (int viter_ = getHalfEdgeVertexIterator(half_edge); viter_ != -1; viter_ = incrementVertexIterator(viter_)) { - int vertex = getVertexFromVertexIterator(viter_); - m_shape.setUserIndex(vertex, m_halfEdgeIndex, he); - } - } - } - - void updateVertexToHalfEdgeConnection_(int half_edge, boolean bClear) { - if (half_edge == -1) - return; - updateVertexToHalfEdgeConnectionHelper_(half_edge, bClear); - updateVertexToHalfEdgeConnectionHelper_(getHalfEdgeTwin(half_edge), - bClear); - } - - int getChainIndex_(int chain) { - return m_chainData.elementToIndex(chain); - } - - void setChainHalfEdge_(int chain, int half_edge) { - m_chainData.setField(chain, 1, half_edge); - } - - void setChainParentage_(int chain, int parentage) { - m_chainData.setField(chain, 2, parentage); - } - - void setChainParent_(int chain, int parentChain) { - assert (m_chainData.getField(chain, 3) != parentChain); - m_chainData.setField(chain, 3, parentChain); - int firstIsland = getChainFirstIsland(parentChain); - setChainNextInParent_(chain, firstIsland); - setChainFirstIsland_(parentChain, chain); - } - - void setChainFirstIsland_(int chain, int islandChain) { - m_chainData.setField(chain, 4, islandChain); - } - - void setChainNextInParent_(int chain, int nextInParent) { - m_chainData.setField(chain, 5, nextInParent); - } - - void setChainPrev_(int chain, int prev) { - m_chainData.setField(chain, 6, prev); - } - - void setChainNext_(int chain, int next) { - m_chainData.setField(chain, 7, next); - } - - void setChainArea_(int chain, double area) { - int chainIndex = getChainIndex_(chain); - m_chainAreas.write(chainIndex, area); - } - - void setChainPerimeter_(int chain, double perimeter) { - int chainIndex = getChainIndex_(chain); - m_chainPerimeters.write(chainIndex, perimeter); - } - - void updateChainAreaAndPerimeter_(int chain) { - double area = 0; - double perimeter = 0; - int firstHalfEdge = getChainHalfEdge(chain); - Point2D origin = new Point2D(), from = new Point2D(), to = new Point2D(); - getHalfEdgeFromXY(firstHalfEdge, origin); - from.setCoords(origin); - int half_edge = firstHalfEdge; - do { - getHalfEdgeToXY(half_edge, to); - perimeter += Point2D.distance(from, to); - int twinChain = getHalfEdgeChain(getHalfEdgeTwin(half_edge)); - if (twinChain != chain)// only count edges are not dangling segments - // of polylines - { - area += ((to.x - origin.x) - (from.x - origin.x)) - * ((to.y - origin.y) + (from.y - origin.y)) * 0.5; - } - - from.setCoords(to); - half_edge = getHalfEdgeNext(half_edge); - } while (half_edge != firstHalfEdge); - - int ind = getChainIndex_(chain); - m_chainAreas.write(ind, area); - m_chainPerimeters.write(ind, perimeter); - } - - int getChainTopMostEdge_(int chain) { - int firstHalfEdge = getChainHalfEdge(chain); - Point2D top = new Point2D(); - getHalfEdgeFromXY(firstHalfEdge, top); - int topEdge = firstHalfEdge; - Point2D v = new Point2D(); - int half_edge = firstHalfEdge; - do { - getHalfEdgeFromXY(half_edge, v); - if (v.compare(top) > 0) { - top.setCoords(v); - topEdge = half_edge; - } - half_edge = getHalfEdgeNext(half_edge); - } while (half_edge != firstHalfEdge); - return topEdge; - } - - void planeSweepParentage_(int inputMode, ProgressTracker progress_tracker) { - PlaneSweepComparator comparator = new PlaneSweepComparator(this); - Treap aet = new Treap(); - aet.setCapacity(m_pointCount / 2); - aet.setComparator(comparator); - - AttributeStreamOfInt32 new_edges = new AttributeStreamOfInt32(0); - int treeNodeIndex = createUserIndexForHalfEdges(); - - ClusterSweepMonikerComparator clusterMoniker = null; - int counter = 0; - // Clusters are sorted by the y, x coordinate in ascending order. - Point2D pt = new Point2D(); - // Each cluster is an event of the sweep-line algorithm. - for (int cluster = getFirstCluster(); cluster != -1; cluster = getNextCluster(cluster)) { - counter++; - if ((counter & 0xFF) == 0) { - if ((progress_tracker != null) - && !(progress_tracker.progress(-1, -1))) - throw new UserCancelException(); - } - - int firstHalfEdge = getClusterHalfEdge(cluster); - if (firstHalfEdge != -1) { - new_edges.resizePreserveCapacity(0); - if (!tryOptimizedInsertion_(aet, treeNodeIndex, new_edges, - cluster, firstHalfEdge))// optimized insertion is for a - // simple chain, in that case we - // simply replace an old edge - // with a new one in AET - O(1) - {// This is more complex than a simple chain of edges - getXY(cluster, pt); - comparator.setY(pt.y); - int clusterHalfEdge = firstHalfEdge; - // Delete all edges that end at the cluster. - do {// edges that end at the cluster have been assigned an - // AET node in the treeNodeIndex. - int attachedTreeNode = getHalfEdgeUserIndex( - clusterHalfEdge, treeNodeIndex); - if (attachedTreeNode != -1) { - assert (attachedTreeNode != StridedIndexTypeCollection - .impossibleIndex2()); - aet.deleteNode(attachedTreeNode, -1); - setHalfEdgeUserIndex(clusterHalfEdge, - treeNodeIndex, - StridedIndexTypeCollection - .impossibleIndex2());// set it to -2 - } - - clusterHalfEdge = getHalfEdgeNext(getHalfEdgeTwin(clusterHalfEdge)); - assert (getHalfEdgeOrigin(clusterHalfEdge) == cluster); - } while (firstHalfEdge != clusterHalfEdge); - - // insert edges that start at the cluster. - // We need to insert only the edges that have the from point - // below the to point. - // This is ensured by the logic of the algorithm. - clusterHalfEdge = firstHalfEdge; - do { - int attachedTreeNode = getHalfEdgeUserIndex( - clusterHalfEdge, treeNodeIndex); - if (attachedTreeNode == -1) { - int newTreeNode = aet.addElement(clusterHalfEdge, - -1); - new_edges.add(newTreeNode); - } - clusterHalfEdge = getHalfEdgeNext(getHalfEdgeTwin(clusterHalfEdge)); - assert (getHalfEdgeOrigin(clusterHalfEdge) == cluster); - } while (firstHalfEdge != clusterHalfEdge); - } - - // Analyze new edges. - // We go in the opposite order, because of the way how the half - // edges are sorted on a cluster. - // We want to go from the left to the right. - for (int i = new_edges.size() - 1; i >= 0; i--) { - int newTreeNode = new_edges.get(i); - int clusterHalfEdge = aet.getElement(newTreeNode); - int twinEdge = getHalfEdgeTwin(clusterHalfEdge); - assert (getHalfEdgeUserIndex(twinEdge, treeNodeIndex) == -1); - setHalfEdgeUserIndex(twinEdge, treeNodeIndex, newTreeNode); - - planeSweepParentagePropagateParentage_(aet, newTreeNode, - inputMode); - } - } else if (getClusterChain(cluster) == -1) { - // get the left half edge of a face. The point belongs to the - // face. - if (clusterMoniker == null) - clusterMoniker = new ClusterSweepMonikerComparator(this); - - getXY(cluster, pt); - clusterMoniker.setPointXY(pt); - int leftNode = aet.searchLowerBound(clusterMoniker, -1); - int chain = m_universeChain; - - if (leftNode != -1) { - int edge = aet.getElement(leftNode); - int leftChain = getHalfEdgeChain(edge); - if (leftChain == getHalfEdgeChain(getHalfEdgeTwin(edge))) { - edge = getLeftSkipPolylines_(aet, leftNode); - } - - if (edge != -1) - chain = getHalfEdgeChain(edge); - } - - addClusterToExteriorChain_(chain, cluster); - } - } - - deleteUserIndexForHalfEdges(treeNodeIndex); - } - - void planeSweepParentagePropagateParentage_(Treap aet, int treeNode, - int inputMode) { - int edge = aet.getElement(treeNode); - int edgeChain = getHalfEdgeChain(edge); - int edgeChainParent = getChainParent(edgeChain); - if (edgeChainParent != -1) - return;// this edge has been processed already. - - // get contributing left edge. - int leftEdge = getLeftSkipPolylines_(aet, treeNode); - - int twinEdge = getHalfEdgeTwin(edge); - int twinHalfEdgeChain = getHalfEdgeChain(twinEdge); - - double chainArea = getChainArea(edgeChain); - double twinChainArea = getChainArea(twinHalfEdgeChain); - - int parentChain = getChainParent(edgeChain); - int twinParentChain = getChainParent(twinHalfEdgeChain); - if (leftEdge == -1 && parentChain == -1) { - // This edge/twin pair does not have a neighbour edge to the left. - // twin parent is not yet been assigned. - if (twinHalfEdgeChain == edgeChain) {// set parentage of a polyline - // edge (any edge for which - // the edge ant its twin - // belong to the same chain) - setChainParent_(twinHalfEdgeChain, getFirstChain()); - twinParentChain = getFirstChain(); - parentChain = twinParentChain; - } else { - // We have two touching chains that do not have parent chain - // set. - // The edge is directed up, the twin edge is directed down. - // There is no edge to the left. THat means there is no other - // than the universe surrounding this edge. - // The edge must belong to a clockwise chain, and the twin edge - // must belong to a ccw chain that encloses this edge. This - // follows from the way how we connect edges around clusters. - assert (twinChainArea < 0 && chainArea > 0); - if (twinParentChain == -1) { - setChainParent_(twinHalfEdgeChain, m_universeChain); - twinParentChain = m_universeChain; - } else { - assert (getFirstChain() == twinParentChain); - } - - setChainParent_(edgeChain, twinHalfEdgeChain); - parentChain = twinHalfEdgeChain; - } - } - - if (leftEdge != -1) { - int leftEdgeChain = getHalfEdgeChain(leftEdge); - // the twin edge has not been processed yet - if (twinParentChain == -1) { - double leftArea = getChainArea(leftEdgeChain); - if (leftArea <= 0) {// if left Edge's chain area is negative, - // then it is a chain that ends at the left - // edge, so we need to get the parent of the - // left chain and it will be the parent of - // this one. - int leftChainParent = getChainParent(leftEdgeChain); - assert (leftChainParent != -1); - - setChainParent_(twinHalfEdgeChain, leftChainParent); - twinParentChain = leftChainParent; - } else // (leftArea > 0) - {// left edge is an edge of positive chain. It surrounds the - // twin chain. - setChainParent_(twinHalfEdgeChain, leftEdgeChain); - twinParentChain = leftEdgeChain; - } - - if (twinHalfEdgeChain == edgeChain) // if this is a polyline - // chain - parentChain = twinParentChain; - } - } - - if (parentChain == -1) { - trySetChainParentFromTwin_(edgeChain, twinHalfEdgeChain); - parentChain = getChainParent(edgeChain); - } - - assert (parentChain != -1); - - if (inputMode == EnumInputMode.enumInputModeBuildGraph) { - propagate_parentage_build_graph_(aet, treeNode, edge, leftEdge, edgeChain, edgeChainParent, twinHalfEdgeChain); - } else if (inputMode == EnumInputMode.enumInputModeSimplifyWinding) { - propagate_parentage_winding_(aet, treeNode, edge, leftEdge, twinEdge, edgeChain, edgeChainParent, twinHalfEdgeChain); - } else if (inputMode == EnumInputMode.enumInputModeSimplifyAlternate) { - propagate_parentage_alternate_(aet, treeNode, edge, leftEdge, twinEdge, edgeChain, edgeChainParent, twinHalfEdgeChain); - } - - } - - void propagate_parentage_build_graph_(Treap aet, int treeNode, int edge, int leftEdge, - int edgeChain, int edgeChainParent, int twinHalfEdgeChain) { - // Now do specific sweep calculations - int chainParentage = getChainParentage(edgeChain); - - if (leftEdge != -1) { - // borrow the parentage from the left edge also - int leftEdgeChain = getHalfEdgeChain(leftEdge); - - // We take parentage from the left edge (that edge has been - // already processed), and move its face parentage accross this - // edge/twin pair. - // While the parentage is moved, accross, any bits of the - // parentage that is present in the twin are removed, because - // the twin is the right edge of the current face. - // The remaining bits are added to the face parentage of this - // edge, indicating that the face this edge borders, belongs to - // all the parents that are still active to the left. - int twinChainParentage = getChainParentage(twinHalfEdgeChain); - int leftChainParentage = getChainParentage(leftEdgeChain); - - int edgeParentage = getHalfEdgeParentage(edge); - int spikeParentage = chainParentage & twinChainParentage - & leftChainParentage; // parentage that needs to stay - leftChainParentage = leftChainParentage - ^ (leftChainParentage & edgeParentage); - leftChainParentage |= spikeParentage; - - if (leftChainParentage != 0) { - // propagate left parentage to the current edge and its - // twin. - setChainParentage_(twinHalfEdgeChain, twinChainParentage - | leftChainParentage); - setChainParentage_(edgeChain, leftChainParentage - | chainParentage); - chainParentage |= leftChainParentage; - } - - // dbg_print_edge_(edge); - } - - for (int rightNode = aet.getNext(treeNode); rightNode != -1; rightNode = aet - .getNext(rightNode)) { - int rightEdge = aet.getElement(rightNode); - int rightTwin = getHalfEdgeTwin(rightEdge); - - int rightTwinChain = getHalfEdgeChain(rightTwin); - int rightTwinChainParentage = getChainParentage(rightTwinChain); - int rightEdgeParentage = getHalfEdgeParentage(rightEdge); - int rightEdgeChain = getHalfEdgeChain(rightEdge); - int rightChainParentage = getChainParentage(rightEdgeChain); - - int spikeParentage = rightTwinChainParentage - & rightChainParentage & chainParentage; // parentage - // that needs to - // stay - chainParentage = chainParentage - ^ (chainParentage & rightEdgeParentage);// only - // parentage - // that is - // abscent in - // the twin is - // propagated to - // the right - chainParentage |= spikeParentage; - - if (chainParentage == 0) - break; - - setChainParentage_(rightTwinChain, rightTwinChainParentage - | chainParentage); - setChainParentage_(rightEdgeChain, rightChainParentage - | chainParentage); - } - } - - void propagate_parentage_winding_(Treap aet, int treeNode, int edge, int leftEdge, int twinEdge, - int edgeChain, int edgeChainParent, int twinHalfEdgeChain) { - - if (edgeChain == twinHalfEdgeChain) - return; - // starting from the left most edge, calculate winding. - int edgeWinding = getHalfEdgeUserIndex(edge, - m_tmpHalfEdgeWindingNumberIndex); - edgeWinding += getHalfEdgeUserIndex(twinEdge, - m_tmpHalfEdgeWindingNumberIndex); - int winding = 0; - AttributeStreamOfInt32 chainStack = new AttributeStreamOfInt32(0); - AttributeStreamOfInt32 windingStack = new AttributeStreamOfInt32(0); - windingStack.add(0); - for (int leftNode = aet.getFirst(-1); leftNode != treeNode; leftNode = aet - .getNext(leftNode)) { - int leftEdge1 = aet.getElement(leftNode); - int leftTwin = getHalfEdgeTwin(leftEdge1); - int l_chain = getHalfEdgeChain(leftEdge1); - int lt_chain = getHalfEdgeChain(leftTwin); - - if (l_chain != lt_chain) { - int leftWinding = getHalfEdgeUserIndex(leftEdge1, - m_tmpHalfEdgeWindingNumberIndex); - leftWinding += getHalfEdgeUserIndex(leftTwin, - m_tmpHalfEdgeWindingNumberIndex); - winding += leftWinding; - - boolean popped = false; - if (chainStack.size() != 0 - && chainStack.getLast() == lt_chain) { - windingStack.removeLast(); - chainStack.removeLast(); - popped = true; - } - - if (getChainParent(lt_chain) == -1) - throw GeometryException.GeometryInternalError(); - - if (!popped || getChainParent(lt_chain) != l_chain) { - windingStack.add(winding); - chainStack.add(l_chain); - } - } - } - - winding += edgeWinding; - - if (chainStack.size() != 0 - && chainStack.getLast() == twinHalfEdgeChain) { - windingStack.removeLast(); - chainStack.removeLast(); - } - - if (winding != 0) { - if (windingStack.getLast() == 0) { - int geometry = m_shape.getFirstGeometry(); - int geometryID = getGeometryID(geometry); - setChainParentage_(edgeChain, geometryID); - } - } else { - if (windingStack.getLast() != 0) { - int geometry = m_shape.getFirstGeometry(); - int geometryID = getGeometryID(geometry); - setChainParentage_(edgeChain, geometryID); - } - } - } - - void propagate_parentage_alternate_(Treap aet, int treeNode, int edge, - int leftEdge, int twinEdge, int edgeChain, int edgeChainParent, - int twinHalfEdgeChain) { - // Now do specific sweep calculations - // This one is done when we are doing a topological operation. - int geometry = m_shape.getFirstGeometry(); - int geometryID = getGeometryID(geometry); - - if (leftEdge == -1) { - // no left edge neighbour means the twin chain is surrounded by the - // universe - assert (getChainParent(twinHalfEdgeChain) == m_universeChain); - assert (getChainParentage(twinHalfEdgeChain) == 0 || getChainParentage(twinHalfEdgeChain) == m_universe_geomID); - assert (getChainParentage(edgeChain) == 0); - setChainParentage_(twinHalfEdgeChain, m_universe_geomID); - int parity = getHalfEdgeUserIndex(edge, - m_tmpHalfEdgeOddEvenNumberIndex); - if ((parity & 1) != 0) - setChainParentage_(edgeChain, geometryID);// set the parenentage - // from the parity - else - setChainParentage_(edgeChain, m_universe_geomID);// this chain - // does not - // belong to - // geometry - } else { - int twin_parentage = getChainParentage(twinHalfEdgeChain); - if (twin_parentage == 0) { - int leftEdgeChain = getHalfEdgeChain(leftEdge); - int left_parentage = getChainParentage(leftEdgeChain); - setChainParentage_(twinHalfEdgeChain, left_parentage); - int parity = getHalfEdgeUserIndex(edge, - m_tmpHalfEdgeOddEvenNumberIndex); - if ((parity & 1) != 0) - setChainParentage_(edgeChain, - (left_parentage == geometryID) ? m_universe_geomID - : geometryID); - else - setChainParentage_(edgeChain, left_parentage); - - } else { - int parity = getHalfEdgeUserIndex(edge, - m_tmpHalfEdgeOddEvenNumberIndex); - if ((parity & 1) != 0) - setChainParentage_(edgeChain, - (twin_parentage == geometryID) ? m_universe_geomID - : geometryID); - else - setChainParentage_(edgeChain, twin_parentage); - } - - } - } - - boolean tryOptimizedInsertion_(Treap aet, int treeNodeIndex, - AttributeStreamOfInt32 new_edges, int cluster, int firstHalfEdge) { - int clusterHalfEdge = firstHalfEdge; - int attachedTreeNode = -1; - int newEdge = -1; - // Delete all edges that end at the cluster. - int count = 0; - do { - if (count == 2) - return false; - int n = getHalfEdgeUserIndex(clusterHalfEdge, treeNodeIndex); - if (n != -1) { - if (attachedTreeNode != -1) - return false;// two edges end at the cluster - attachedTreeNode = n; - } else { - if (newEdge != -1) - return false; // two edges start from the cluster - newEdge = clusterHalfEdge; - } - assert (getHalfEdgeOrigin(clusterHalfEdge) == cluster); - count++; - clusterHalfEdge = getHalfEdgeNext(getHalfEdgeTwin(clusterHalfEdge)); - } while (firstHalfEdge != clusterHalfEdge); - - if (newEdge == -1 || attachedTreeNode == -1) - return false; - - setHalfEdgeUserIndex(aet.getElement(attachedTreeNode), treeNodeIndex, - StridedIndexTypeCollection.impossibleIndex2()); - aet.setElement(attachedTreeNode, newEdge); - new_edges.add(attachedTreeNode); - return true; - } - - boolean trySetChainParentFromTwin_(int chainToSet, int twinChain) { - assert (getChainParent(chainToSet) == -1); - double area = getChainArea(chainToSet); - if (area == 0) - return false; - double twinArea = getChainArea(twinChain); - assert (twinArea != 0); - if (area > 0 && twinArea < 0) { - setChainParent_(chainToSet, twinChain); - return true; - } - if (area < 0 && twinArea > 0) { - setChainParent_(chainToSet, twinChain); - return true; - } else { - int twinParent = getChainParent(twinChain); - if (twinParent != -1) { - setChainParent_(chainToSet, twinParent); - return true; - } - } - - return false; - } - - void createHalfEdges_(int inputMode, AttributeStreamOfInt32 sorted_vertices) { - // After this loop all halfedges will be created. - // This loop also sets the known parentage on the edges. - // The half edges are connected with each other in a random order - m_halfEdgeIndex = m_shape.createUserIndex(); - - for (int i = 0, nvert = sorted_vertices.size(); i < nvert; i++) { - int vertex = sorted_vertices.get(i); - int cluster = m_shape.getUserIndex(vertex, m_clusterIndex); - - int path = m_shape.getPathFromVertex(vertex); - int geometry = m_shape.getGeometryFromPath(path); - int gt = m_shape.getGeometryType(geometry); - if (Geometry.isMultiPath(gt)) { - int next = m_shape.getNextVertex(vertex); - if (next == -1) - continue; - - int clusterTo = m_shape.getUserIndex(next, m_clusterIndex); - assert (clusterTo != -1); - if (cluster == clusterTo) { - if (m_shape.getSegment(vertex) != null) { - assert (m_shape.getSegment(vertex).calculateLength2D() == 0); - } else { - assert (m_shape.getXY(vertex).isEqual(m_shape.getXY(next))); - } - - continue; - } - - int half_edge = newHalfEdgePair_(); - int twinEdge = getHalfEdgeTwin(half_edge); - - // add vertex to the half edge. - int vertIndex = m_clusterVertices.newElement(); - m_clusterVertices.setField(vertIndex, 0, vertex); - m_clusterVertices.setField(vertIndex, 1, -1); - setHalfEdgeVertexIterator_(half_edge, vertIndex); - - setHalfEdgeOrigin_(half_edge, cluster); - int firstHalfEdge = getClusterHalfEdge(cluster); - if (firstHalfEdge == -1) { - setClusterHalfEdge_(cluster, half_edge); - setHalfEdgePrev_(half_edge, twinEdge); - setHalfEdgeNext_(twinEdge, half_edge); - } else { - // It does not matter what order we insert the new edges in. - // We fix the order later. - int firstPrev = getHalfEdgePrev(firstHalfEdge); - assert (getHalfEdgeNext(firstPrev) == firstHalfEdge); - setHalfEdgePrev_(firstHalfEdge, twinEdge); - setHalfEdgeNext_(twinEdge, firstHalfEdge); - assert (getHalfEdgePrev(firstHalfEdge) == twinEdge); - assert (getHalfEdgeNext(twinEdge) == firstHalfEdge); - setHalfEdgeNext_(firstPrev, half_edge); - setHalfEdgePrev_(half_edge, firstPrev); - assert (getHalfEdgePrev(half_edge) == firstPrev); - assert (getHalfEdgeNext(firstPrev) == half_edge); - } - - setHalfEdgeOrigin_(twinEdge, clusterTo); - int firstTo = getClusterHalfEdge(clusterTo); - if (firstTo == -1) { - setClusterHalfEdge_(clusterTo, twinEdge); - setHalfEdgeNext_(half_edge, twinEdge); - setHalfEdgePrev_(twinEdge, half_edge); - } else { - int firstToPrev = getHalfEdgePrev(firstTo); - assert (getHalfEdgeNext(firstToPrev) == firstTo); - setHalfEdgePrev_(firstTo, half_edge); - setHalfEdgeNext_(half_edge, firstTo); - assert (getHalfEdgePrev(firstTo) == half_edge); - assert (getHalfEdgeNext(half_edge) == firstTo); - setHalfEdgeNext_(firstToPrev, twinEdge); - setHalfEdgePrev_(twinEdge, firstToPrev); - assert (getHalfEdgePrev(twinEdge) == firstToPrev); - assert (getHalfEdgeNext(firstToPrev) == twinEdge); - } - - int geometryID = getGeometryID(geometry); - // No chains yet exists, so we use a temporary user index to - // store chain parentage. - // The input polygons has been already simplified so their edges - // directed such that the hole is to the left from the edge - // (each edge is directed from the "from" to "to" point). - if (inputMode == EnumInputMode.enumInputModeBuildGraph) { - setHalfEdgeUserIndex(twinEdge, m_tmpHalfEdgeParentageIndex, - 0); // Hole is always to the left. left side here is - // the twin. - setHalfEdgeUserIndex(half_edge, - m_tmpHalfEdgeParentageIndex, - gt == Geometry.GeometryType.Polygon ? geometryID - : 0); - } else if (inputMode == EnumInputMode.enumInputModeSimplifyWinding) { - Point2D pt_1 = new Point2D(); - m_shape.getXY(vertex, pt_1); - Point2D pt_2 = new Point2D(); - m_shape.getXY(next, pt_2); - int windingNumber = 0; - int windingNumberTwin = 0; - if (pt_1.compare(pt_2) < 0) { - // The edge is directed bottom-up. That means it has the - // winding number of +1. - // The half-edge direction coincides with the edge - // direction. THe twin is directed top-down. - // The half edge will have the winding number of 1 and - // its twin the winding number of 0. - // When crossing the half-edge/twin pair from left to - // right, the winding number is changed by +1 - windingNumber = 1; - } else { - // The edge is directed top-down. That means it has the - // winding number of -1. - // The half-edge direction coincides with the edge - // direction. The twin is directed bottom-up. - // The half edge will have the winding number of 0 and - // its twin the winding number of -1. - // When crossing the half-edge/twin pair from left to - // right, the winding number is changed by -1. - windingNumberTwin = -1; - } - - // When we get a half-edge/twin pair, we can determine the - // winding number of the underlying edge - // by summing up the half-edge and twin's - // winding numbers. - - setHalfEdgeUserIndex(twinEdge, m_tmpHalfEdgeParentageIndex, - 0); - setHalfEdgeUserIndex(half_edge, - m_tmpHalfEdgeParentageIndex, 0); - // We split the winding number between the half edge and its - // twin. - // This allows us to determine which half edge goes in the - // direction of the edge, and also it allows to calculate - // the - // winging number by summing up the winding number of half - // edge and its twin. - setHalfEdgeUserIndex(half_edge, - m_tmpHalfEdgeWindingNumberIndex, windingNumber); - setHalfEdgeUserIndex(twinEdge, - m_tmpHalfEdgeWindingNumberIndex, windingNumberTwin); - } else if (inputMode == EnumInputMode.enumInputModeIsSimplePolygon) { - setHalfEdgeUserIndex(twinEdge, m_tmpHalfEdgeParentageIndex, - m_universe_geomID); - setHalfEdgeUserIndex(half_edge, - m_tmpHalfEdgeParentageIndex, - gt == Geometry.GeometryType.Polygon ? geometryID - : 0); - } else if (inputMode == EnumInputMode.enumInputModeSimplifyAlternate) { - setHalfEdgeUserIndex(twinEdge, m_tmpHalfEdgeParentageIndex, - 0); - setHalfEdgeUserIndex(half_edge, - m_tmpHalfEdgeParentageIndex, 0); - setHalfEdgeUserIndex(half_edge, - m_tmpHalfEdgeOddEvenNumberIndex, 1); - setHalfEdgeUserIndex(twinEdge, - m_tmpHalfEdgeOddEvenNumberIndex, 1); - } - - int edgeBit = gt == Geometry.GeometryType.Polygon ? c_edgeBitMask - : 0; - setHalfEdgeParentage_(half_edge, geometryID | edgeBit); - setHalfEdgeParentage_(twinEdge, geometryID | edgeBit); - } - } - } - - void mergeVertexListsOfEdges_(int eDst, int eSrc) { - assert (getHalfEdgeTo(eDst) == getHalfEdgeTo(eSrc)); - assert (getHalfEdgeOrigin(eDst) == getHalfEdgeOrigin(eSrc)); - - { - int vertFirst2 = getHalfEdgeVertexIterator(eSrc); - if (vertFirst2 != -1) { - int vertFirst1 = getHalfEdgeVertexIterator(eDst); - m_clusterVertices.setField(vertFirst2, 1, vertFirst1); - setHalfEdgeVertexIterator_(eDst, vertFirst2); - setHalfEdgeVertexIterator_(eSrc, -1); - } - } - - int eDstTwin = getHalfEdgeTwin(eDst); - int eSrcTwin = getHalfEdgeTwin(eSrc); - { - int vertFirst2 = getHalfEdgeVertexIterator(eSrcTwin); - if (vertFirst2 != -1) { - int vertFirst1 = getHalfEdgeVertexIterator(eDstTwin); - m_clusterVertices.setField(vertFirst2, 1, vertFirst1); - setHalfEdgeVertexIterator_(eDstTwin, vertFirst2); - setHalfEdgeVertexIterator_(eSrcTwin, -1); - } - } - } - - void sortHalfEdgesByAngle_(int inputMode) { - AttributeStreamOfInt32 angleSorter = new AttributeStreamOfInt32(0); - angleSorter.reserve(10); - TopoGraphAngleComparer tgac = new TopoGraphAngleComparer(this); - // Now go through the clusters, sort edges in each cluster by angle, and - // reconnect the halfedges of sorted edges in the sorted order. - // Also share the parentage information between coinciding edges and - // remove duplicates. - for (int cluster = getFirstCluster(); cluster != -1; cluster = getNextCluster(cluster)) { - angleSorter.clear(false); - int first = getClusterHalfEdge(cluster); - if (first != -1) { - // 1. sort edges originating at the cluster by angle (counter - - // clockwise). - int edge = first; - do { - angleSorter.add(edge);// edges have the cluster in their - // origin and are directed away from - // it. The twin edges are directed - // towards the cluster. - edge = getHalfEdgeNext(getHalfEdgeTwin(edge)); - } while (edge != first); - - if (angleSorter.size() > 1) { - boolean changed_order = true; - if (angleSorter.size() > 2) { - angleSorter.Sort(0, angleSorter.size(), - tgac); // std::sort(angleSorter.get_ptr(), - // angleSorter.get_ptr() - // + - // angleSorter.size(), - // TopoGraphAngleComparer(this)); - angleSorter.add(angleSorter.get(0)); - } else { - //no need to sort most two edge cases. we only need to make sure that edges going up are sorted - if (compareEdgeAnglesForPair_(angleSorter.get(0), - angleSorter.get(1)) > 0) { - int tmp = angleSorter.get(0); - angleSorter.set(0, angleSorter.get(1)); - angleSorter.set(1, tmp); - } else { - changed_order = false; - } - } - // 2. get rid of duplicate edges by merging them (duplicate - // edges appear at this step because we converted all - // segments into the edges, including overlapping). - int e0 = angleSorter.get(0); - int ePrev = e0; - int ePrevTo = getHalfEdgeTo(ePrev); - int ePrevTwin = getHalfEdgeTwin(ePrev); - int prevMerged = -1; - for (int i = 1, n = angleSorter.size(); i < n; i++) { - int e = angleSorter.get(i); - int eTwin = getHalfEdgeTwin(e); - int eTo = getHalfEdgeOrigin(eTwin); - assert (getHalfEdgeOrigin(e) == getHalfEdgeOrigin(ePrev));// e - // origin - // and - // ePrev - // origin - // are - // equal - // by - // definition - // (e - // and - // ePrev - // emanate - // from - // the - // same - // cluster) - if (eTo == ePrevTo && e != ePrev)// e's To cluster and - // ePrev's To - // cluster are - // equal, means the - // edges coincide - // and need to be - // merged. - {// remove duplicate edge. Before removing, propagate - // the parentage to the remaning edge - if (inputMode == EnumInputMode.enumInputModeBuildGraph) { - int newEdgeParentage = getHalfEdgeParentageMask_(ePrev) - | getHalfEdgeParentageMask_(e); - setHalfEdgeParentage_(ePrev, newEdgeParentage); - setHalfEdgeParentage_(ePrevTwin, - newEdgeParentage); - assert (getHalfEdgeParentageMask_(ePrev) == getHalfEdgeParentageMask_(ePrevTwin)); - - setHalfEdgeUserIndex( - ePrev, - m_tmpHalfEdgeParentageIndex, - getHalfEdgeUserIndex(ePrev, - m_tmpHalfEdgeParentageIndex) - | getHalfEdgeUserIndex(e, - m_tmpHalfEdgeParentageIndex)); - setHalfEdgeUserIndex( - ePrevTwin, - m_tmpHalfEdgeParentageIndex, - getHalfEdgeUserIndex(ePrevTwin, - m_tmpHalfEdgeParentageIndex) - | getHalfEdgeUserIndex(eTwin, - m_tmpHalfEdgeParentageIndex)); - } else if (m_tmpHalfEdgeWindingNumberIndex != -1) { - // when doing simplify the - // m_tmpHalfEdgeWindingNumberIndex contains the - // winding number. - // When edges are merged their winding numbers - // are added. - int newHalfEdgeWinding = getHalfEdgeUserIndex( - ePrev, m_tmpHalfEdgeWindingNumberIndex) - + getHalfEdgeUserIndex(e, - m_tmpHalfEdgeWindingNumberIndex); - int newTwinEdgeWinding = getHalfEdgeUserIndex( - ePrevTwin, - m_tmpHalfEdgeWindingNumberIndex) - + getHalfEdgeUserIndex(eTwin, - m_tmpHalfEdgeWindingNumberIndex); - setHalfEdgeUserIndex(ePrev, - m_tmpHalfEdgeWindingNumberIndex, - newHalfEdgeWinding); - setHalfEdgeUserIndex(ePrevTwin, - m_tmpHalfEdgeWindingNumberIndex, - newTwinEdgeWinding); - // The winding number of an edge is a sum of the - // winding numbers of the half edge and its - // twin. - // To determine which half edge direction - // coincides with the edge direction, determine - // which half edge has larger abs value of - // winding number. If half edge and twin winding - // numbers cancel each other, the edge winding - // number is zero, meaning there are - // even number of edges coinciding there and - // half of them has opposite direction to - // another half. - } else if (inputMode == EnumInputMode.enumInputModeIsSimplePolygon) { - m_non_simple_result = new NonSimpleResult(NonSimpleResult.Reason.CrossOver, cluster, -1); - return; - } else if (m_tmpHalfEdgeOddEvenNumberIndex != -1) { - int newHalfEdgeWinding = getHalfEdgeUserIndex( - ePrev, m_tmpHalfEdgeOddEvenNumberIndex) - + getHalfEdgeUserIndex(e, - m_tmpHalfEdgeOddEvenNumberIndex); - int newTwinEdgeWinding = getHalfEdgeUserIndex( - ePrevTwin, - m_tmpHalfEdgeOddEvenNumberIndex) - + getHalfEdgeUserIndex(eTwin, - m_tmpHalfEdgeOddEvenNumberIndex); - setHalfEdgeUserIndex(ePrev, - m_tmpHalfEdgeOddEvenNumberIndex, - newHalfEdgeWinding); - setHalfEdgeUserIndex(ePrevTwin, - m_tmpHalfEdgeOddEvenNumberIndex, - newTwinEdgeWinding); - } - - mergeVertexListsOfEdges_(ePrev, e); - deleteEdgeImpl_(e); - assert (n < 3 || e0 == angleSorter.getLast()); - prevMerged = ePrev; - angleSorter.set(i, -1); - if (e == e0) { - angleSorter.set(0, -1); - e0 = -1; - } - - continue; - } else { - //edges do not coincide - } - - updateVertexToHalfEdgeConnection_(prevMerged, false); - prevMerged = -1; - ePrev = e; - ePrevTo = eTo; - ePrevTwin = eTwin; - } - - - updateVertexToHalfEdgeConnection_(prevMerged, false); - prevMerged = -1; - - if (!changed_order) { - //small optimization to avoid reconnecting if nothing changed - e0 = -1; - for (int i = 0, n = angleSorter.size(); i < n; i++) { - int e = angleSorter.get(i); - if (e == -1) - continue; - e0 = e; - break; - } - - if (first != e0) - setClusterHalfEdge_(cluster, e0); - - continue; //next cluster - } - - - // 3. Reconnect edges in the sorted order. The edges are - // sorted counter clockwise. - // We connect them such that every right turn is made in the - // clockwise order. - // This guarantees that the smallest faces are clockwise. - e0 = -1; - for (int i = 0, n = angleSorter.size(); i < n; i++) { - int e = angleSorter.get(i); - if (e == -1) - continue; - if (e0 == -1) { - e0 = e; - ePrev = e0; - ePrevTo = getHalfEdgeTo(ePrev); - ePrevTwin = getHalfEdgeTwin(ePrev); - continue; - } - - if (e == ePrev) { - // This condition can only happen if all edges in - // the bunch coincide. - assert (i == n - 1); - continue; - } - - int eTwin = getHalfEdgeTwin(e); - int eTo = getHalfEdgeOrigin(eTwin); - assert (getHalfEdgeOrigin(e) == getHalfEdgeOrigin(ePrev)); - assert (eTo != ePrevTo); - setHalfEdgeNext_(ePrevTwin, e); - setHalfEdgePrev_(e, ePrevTwin); - ePrev = e; - ePrevTo = eTo; - ePrevTwin = eTwin; - if (inputMode == EnumInputMode.enumInputModeIsSimplePolygon) { - int par1 = getHalfEdgeUserIndex(e, m_tmpHalfEdgeParentageIndex) | - getHalfEdgeUserIndex(getHalfEdgePrev(e), m_tmpHalfEdgeParentageIndex); - if (par1 == (m_universe_geomID | 1)) { - //violation of face parentage - m_non_simple_result = new NonSimpleResult(NonSimpleResult.Reason.CrossOver, cluster, -1); - return; - } - } - - } - - setClusterHalfEdge_(cluster, e0);// smallest angle goes - // first. - } - } - } - } - - void buildChains_(int inputMode) { - // Creates chains and puts them in the list of chains. - // Does not set the chain parentage - // Does not connect chains - - int firstChain = -1; - int visitedHalfEdgeIndex = createUserIndexForHalfEdges(); - // Visit all the clusters - for (int cluster = getFirstCluster(); cluster != -1; cluster = getNextCluster(cluster)) { - // For each cluster visit all half edges on the cluster - int first = getClusterHalfEdge(cluster); - if (first != -1) { - int edge = first; - do { - if (getHalfEdgeUserIndex(edge, visitedHalfEdgeIndex) != 1)// check - // if - // we - // have - // visited - // this - // halfedge - // already - {// if we have not visited this halfedge yet, then we have - // not created a chain for it yet. - int chain = newChain_();// new chain's parentage is set - // to 0. - setChainHalfEdge_(chain, edge);// Note, the half-edge's - // Origin is the lowest - // point of the chain. - setChainNext_(chain, firstChain);// add the new chain to - // the list of - // chains. - if (firstChain != -1) { - setChainPrev_(firstChain, chain); - } - firstChain = chain; - // go thorough all halfedges until return back to the - // same one. Thus forming a chain. - int parentage = 0; - int e = edge; - do { - // accumulate chain parentage from all the chain - // edges m_tmpHalfEdgeParentageIndex. - parentage |= getHalfEdgeUserIndex(e, - m_tmpHalfEdgeParentageIndex); - assert (getHalfEdgeUserIndex(e, - visitedHalfEdgeIndex) != 1); - setHalfEdgeChain_(e, chain); - setHalfEdgeUserIndex(e, visitedHalfEdgeIndex, 1);// mark - // the - // edge - // visited. - e = getHalfEdgeNext(e); - } while (e != edge); - - assert (inputMode != EnumInputMode.enumInputModeIsSimplePolygon || parentage != (1 | m_universe_geomID)); - - setChainParentage_(chain, parentage); - } - - edge = getHalfEdgeNext(getHalfEdgeTwin(edge));// next - // halfedge - // on the - // cluster - } while (edge != first); - } - } - - // add the Universe chain. We want it to be the one that getFirstChain - // returns. - int chain = newChain_(); - setChainHalfEdge_(chain, -1); - setChainNext_(chain, firstChain); - if (firstChain != -1) - setChainPrev_(firstChain, chain); - - m_universeChain = chain; - - m_chainAreas = new AttributeStreamOfDbl(m_chainData.size(), - NumberUtils.TheNaN); - m_chainPerimeters = new AttributeStreamOfDbl(m_chainData.size(), - NumberUtils.TheNaN); - - setChainArea_(m_universeChain, NumberUtils.positiveInf());// the - // Universe - // is - // infinite - setChainPerimeter_(m_universeChain, NumberUtils.positiveInf());// the - // Universe - // is - // infinite - - deleteUserIndexForHalfEdges(visitedHalfEdgeIndex); - } - - void simplify_(int inputMode) { - if (inputMode == EnumInputMode.enumInputModeSimplifyAlternate) { - simplifyAlternate_(); - } else if (inputMode == EnumInputMode.enumInputModeSimplifyWinding) { - simplifyWinding_(); - } - } - - void simplifyAlternate_() { - //there is nothing to do - } - - void simplifyWinding_() { - //there is nothing to do - } - - private int getFirstUnvisitedHalfEdgeOnCluster_(int cluster, int hintEdge, - int vistiedEdgesIndex) { - // finds first half edge which is unvisited (index is not set to 1. - // when hintEdge != -1, it is used to start going around the edges. - - int edge = hintEdge != -1 ? hintEdge : getClusterHalfEdge(cluster); - if (edge == -1) - return -1; - - int f = edge; - - while (true) { - int v = getHalfEdgeUserIndex(edge, vistiedEdgesIndex); - if (v != 1) { - return edge; - } - - int next = getHalfEdgeNext(getHalfEdgeTwin(edge)); - if (next == f) - return -1; - - edge = next; - } - } - - boolean removeSpikes_() { - boolean removed = false; - int visitedIndex = createUserIndexForHalfEdges(); - for (int cluster = getFirstCluster(); cluster != -1; cluster = getNextCluster(cluster)) { - int nextClusterEdge = -1; //a hint - while (true) { - int firstHalfEdge = getFirstUnvisitedHalfEdgeOnCluster_(cluster, nextClusterEdge, visitedIndex); - if (firstHalfEdge == -1) - break; - - nextClusterEdge = getHalfEdgeNext(getHalfEdgeTwin(firstHalfEdge)); - int faceHalfEdge = firstHalfEdge; - - while (true) { - int faceHalfEdgeNext = getHalfEdgeNext(faceHalfEdge); - int faceHalfEdgePrev = getHalfEdgePrev(faceHalfEdge); - int faceHalfEdgeTwin = getHalfEdgeTwin(faceHalfEdge); - - if (faceHalfEdgePrev == faceHalfEdgeTwin) { - deleteEdgeInternal_(faceHalfEdge); //deletes the edge and its twin - removed = true; - - if (nextClusterEdge == faceHalfEdge || nextClusterEdge == faceHalfEdgeTwin) - nextClusterEdge = -1; //deleted the hint edge - - if (faceHalfEdge == firstHalfEdge || faceHalfEdgePrev == firstHalfEdge) { - firstHalfEdge = faceHalfEdgeNext; - if (faceHalfEdge == firstHalfEdge || faceHalfEdgePrev == firstHalfEdge) { - //deleted all edges in a face - break; - } - - faceHalfEdge = faceHalfEdgeNext; - continue; - } - - } else { - setHalfEdgeUserIndex(faceHalfEdge, visitedIndex, 1); - } - - faceHalfEdge = faceHalfEdgeNext; - if (faceHalfEdge == firstHalfEdge) - break; - } - - } - } - - return removed; - } - - void setEditShapeImpl_(EditShape shape, int inputMode, - AttributeStreamOfInt32 editShapeGeometries, - ProgressTracker progress_tracker, boolean bBuildChains) { - assert (!m_dirty_check_failed); - assert (editShapeGeometries == null || editShapeGeometries.size() > 0); - - removeShape(); - m_buildChains = bBuildChains; - assert (m_shape == null); - m_shape = shape; - m_geometryIDIndex = m_shape.createGeometryUserIndex(); - // sort vertices lexicographically - // Firstly copy all vertices to an array. - AttributeStreamOfInt32 verticesSorter = new AttributeStreamOfInt32(0); - verticesSorter.reserve(editShapeGeometries != null ? m_shape - .getPointCount(editShapeGeometries.get(0)) : m_shape - .getTotalPointCount()); - int path_count = 0; - int geomID = 1; - {// scope - int geometry = editShapeGeometries != null ? editShapeGeometries - .get(0) : m_shape.getFirstGeometry(); - int ind = 1; - while (geometry != -1) { - m_shape.setGeometryUserIndex(geometry, m_geometryIDIndex, - geomID); - geomID = geomID << 1; - for (int path = m_shape.getFirstPath(geometry); path != -1; path = m_shape - .getNextPath(path)) { - int vertex = m_shape.getFirstVertex(path); - for (int index = 0, n = m_shape.getPathSize(path); index < n; index++) { - verticesSorter.add(vertex); - vertex = m_shape.getNextVertex(vertex); - } - } - - if (!Geometry.isPoint(m_shape.getGeometryType(geometry))) - path_count += m_shape.getPathCount(geometry); - - if (editShapeGeometries != null) { - geometry = ind < editShapeGeometries.size() ? editShapeGeometries - .get(ind) : -1; - ind++; - } else - geometry = m_shape.getNextGeometry(geometry); - } - } - - m_universe_geomID = geomID; - - m_pointCount = verticesSorter.size(); - - // sort - m_shape.sortVerticesSimpleByY_(verticesSorter, 0, m_pointCount); - - if (m_clusterVertices == null) { - m_clusterVertices = new StridedIndexTypeCollection(2); - m_clusterData = new StridedIndexTypeCollection(8); - m_halfEdgeData = new StridedIndexTypeCollection(8); - m_chainData = new StridedIndexTypeCollection(8); - } - - m_clusterVertices.setCapacity(m_pointCount); - - ProgressTracker.checkAndThrow(progress_tracker); - - m_clusterData.setCapacity(m_pointCount + 10);// 10 for some self - // intersections - m_halfEdgeData.setCapacity(2 * m_pointCount + 32); - m_chainData.setCapacity(Math.max((int) 32, path_count)); - - // create all clusters - assert (m_clusterIndex == -1);// cleanup was incorrect - m_clusterIndex = m_shape.createUserIndex(); - Point2D ptFirst = new Point2D(); - int ifirst = 0; - Point2D pt = new Point2D(); - ptFirst.setNaN(); - for (int i = 0; i <= m_pointCount; i++) { - if (i < m_pointCount) { - int vertex = verticesSorter.get(i); - m_shape.getXY(vertex, pt); - } else { - pt.setNaN();// makes it to go into the following "if" statement. - } - if (!ptFirst.isEqual(pt)) { - if (ifirst < i) { - int cluster = newCluster_(); - int vertFirst = -1; - int vert = -1; - for (int ind = ifirst; ind < i; ind++) { - vert = verticesSorter.get(ind); - m_shape.setUserIndex(vert, m_clusterIndex, cluster); - - // add vertex to the cluster's vertex list - int vertIndex = m_clusterVertices.newElement(); - m_clusterVertices.setField(vertIndex, 0, vert); - m_clusterVertices.setField(vertIndex, 1, vertFirst); - vertFirst = vertIndex; - - int path = m_shape.getPathFromVertex(vert); - int geometry = m_shape.getGeometryFromPath(path); - int geometryID = getGeometryID(geometry); - setClusterParentage_(cluster, - getClusterParentage(cluster) | geometryID); - } - setClusterVertexIterator_(cluster, vertFirst); - setClusterVertexIndex_(cluster, - m_shape.getVertexIndex(vert)); - - if (m_lastCluster != -1) - setNextCluster_(m_lastCluster, cluster); - - setPrevCluster_(cluster, m_lastCluster); - - m_lastCluster = cluster; - if (m_firstCluster == -1) - m_firstCluster = cluster; - } - ifirst = i; - ptFirst.setCoords(pt); - } - } - - ProgressTracker.checkAndThrow(progress_tracker); - - m_tmpHalfEdgeParentageIndex = createUserIndexForHalfEdges(); - if (inputMode == EnumInputMode.enumInputModeSimplifyWinding) { - m_tmpHalfEdgeWindingNumberIndex = createUserIndexForHalfEdges(); - } - - if (inputMode == EnumInputMode.enumInputModeSimplifyAlternate) { - m_tmpHalfEdgeOddEvenNumberIndex = createUserIndexForHalfEdges(); - } - - createHalfEdges_(inputMode, verticesSorter);// For each geometry produce - // clusters and half edges - - if (m_non_simple_result.m_reason != NonSimpleResult.Reason.NotDetermined) - return; - - sortHalfEdgesByAngle_(inputMode); - if (m_non_simple_result.m_reason != NonSimpleResult.Reason.NotDetermined) - return; - - if (!NumberUtils.isNaN(m_check_dirty_planesweep_tolerance)) { - if (!check_structure_after_dirty_sweep_())// checks the edges. - { - m_dirty_check_failed = true;// set m_dirty_check_failed when an - // issue is found. We'll rerun the - // planesweep using robust crack and - // cluster approach. - return; - } - } - - buildChains_(inputMode); - if (m_non_simple_result.m_reason != NonSimpleResult.Reason.NotDetermined) - return; - - deleteUserIndexForHalfEdges(m_tmpHalfEdgeParentageIndex); - m_tmpHalfEdgeParentageIndex = -1; - - if (m_buildChains) - planeSweepParentage_(inputMode, progress_tracker); - - - simplify_(inputMode); - } - - void deleteEdgeImpl_(int half_edge) { - int halfEdgeNext = getHalfEdgeNext(half_edge); - int halfEdgePrev = getHalfEdgePrev(half_edge); - int halfEdgeTwin = getHalfEdgeTwin(half_edge); - int halfEdgeTwinNext = getHalfEdgeNext(halfEdgeTwin); - int halfEdgeTwinPrev = getHalfEdgePrev(halfEdgeTwin); - - if (halfEdgeNext != halfEdgeTwin) { - setHalfEdgeNext_(halfEdgeTwinPrev, halfEdgeNext); - setHalfEdgePrev_(halfEdgeNext, halfEdgeTwinPrev); - } - - if (halfEdgePrev != halfEdgeTwin) { - setHalfEdgeNext_(halfEdgePrev, halfEdgeTwinNext); - setHalfEdgePrev_(halfEdgeTwinNext, halfEdgePrev); - } - - int cluster_1 = getHalfEdgeOrigin(half_edge); - int clusterFirstEdge1 = getClusterHalfEdge(cluster_1); - if (clusterFirstEdge1 == half_edge) { - if (halfEdgeTwinNext != half_edge) - setClusterHalfEdge_(cluster_1, halfEdgeTwinNext); - else - setClusterHalfEdge_(cluster_1, -1);// cluster has no more edges - } - - int cluster2 = getHalfEdgeOrigin(halfEdgeTwin); - int clusterFirstEdge2 = getClusterHalfEdge(cluster2); - if (clusterFirstEdge2 == halfEdgeTwin) { - if (halfEdgeNext != halfEdgeTwin) - setClusterHalfEdge_(cluster2, halfEdgeNext); - else - setClusterHalfEdge_(cluster2, -1);// cluster has no more edges - } - - m_halfEdgeData.deleteElement(half_edge); - m_halfEdgeData.deleteElement(halfEdgeTwin); - } - - int getLeftSkipPolylines_(Treap aet, int treeNode) { - int leftNode = treeNode; - - for (; ; ) { - leftNode = aet.getPrev(leftNode); - if (leftNode != -1) { - int e = aet.getElement(leftNode); - int leftChain = getHalfEdgeChain(e); - if (leftChain != getHalfEdgeChain(getHalfEdgeTwin(e))) { - return e; - } else { - // the left edge is a piece of polyline - does not - // contribute to the face parentage - } - } else { - return -1; - } - } - } - - TopoGraph() { - c_edgeParentageMask = ((int) -1) - ^ ((int) 1 << (NumberUtils.sizeOf((int) 0) * 8 - 1)); - c_edgeBitMask = (int) 1 << (NumberUtils.sizeOf((int) 0) * 8 - 1); - m_firstCluster = -1; - m_lastCluster = -1; - m_geometryIDIndex = -1; - m_clusterIndex = -1; - m_halfEdgeIndex = -1; - m_universeChain = -1; - m_tmpHalfEdgeParentageIndex = -1; - m_tmpHalfEdgeWindingNumberIndex = -1; - m_pointCount = 0; - } - - EditShape getShape() { - return m_shape; - } - - // Sets an edit shape. The geometry has to be cracked and clustered before - // calling this! - void setEditShape(EditShape shape, ProgressTracker progress_tracker) { - setEditShapeImpl_(shape, EnumInputMode.enumInputModeBuildGraph, null, - progress_tracker, true); - } - - void setEditShape(EditShape shape, ProgressTracker progress_tracker, boolean bBuildChains) { - setEditShapeImpl_(shape, EnumInputMode.enumInputModeBuildGraph, null, - progress_tracker, bBuildChains); - } - - void setAndSimplifyEditShapeAlternate(EditShape shape, int geometry, ProgressTracker progressTracker) { - AttributeStreamOfInt32 geoms = new AttributeStreamOfInt32(0); - geoms.add(geometry); - setEditShapeImpl_(shape, EnumInputMode.enumInputModeSimplifyAlternate, - geoms, progressTracker, shape.getGeometryType(geometry) == Geometry.Type.Polygon.value()); - } - - void setAndSimplifyEditShapeWinding(EditShape shape, int geometry, ProgressTracker progressTracker) { - AttributeStreamOfInt32 geoms = new AttributeStreamOfInt32(0); - geoms.add(geometry); - setEditShapeImpl_(shape, EnumInputMode.enumInputModeSimplifyWinding, - geoms, progressTracker, true); - } - - // Removes shape from the topograph and removes any user index created on - // the edit shape. - void removeShape() { - if (m_shape == null) - return; - - if (m_geometryIDIndex != -1) { - m_shape.removeGeometryUserIndex(m_geometryIDIndex); - m_geometryIDIndex = -1; - } - - if (m_clusterIndex != -1) { - m_shape.removeUserIndex(m_clusterIndex); - m_clusterIndex = -1; - } - - if (m_halfEdgeIndex != -1) { - m_shape.removeUserIndex(m_halfEdgeIndex); - m_halfEdgeIndex = -1; - } - - if (m_tmpHalfEdgeParentageIndex != -1) { - deleteUserIndexForHalfEdges(m_tmpHalfEdgeParentageIndex); - m_tmpHalfEdgeParentageIndex = -1; - } - - if (m_tmpHalfEdgeWindingNumberIndex != -1) { - deleteUserIndexForHalfEdges(m_tmpHalfEdgeWindingNumberIndex); - m_tmpHalfEdgeWindingNumberIndex = -1; - } - - if (m_tmpHalfEdgeOddEvenNumberIndex != -1) { - deleteUserIndexForHalfEdges(m_tmpHalfEdgeOddEvenNumberIndex); - m_tmpHalfEdgeOddEvenNumberIndex = -1; - } - - m_shape = null; - m_clusterData.deleteAll(true); - m_clusterVertices.deleteAll(true); - m_firstCluster = -1; - m_lastCluster = -1; - - if (m_halfEdgeData != null) - m_halfEdgeData.deleteAll(true); - if (m_edgeIndices != null) - m_edgeIndices.clear(); - if (m_clusterIndices != null) - m_clusterIndices.clear(); - if (m_chainIndices != null) - m_chainIndices.clear(); - if (m_chainData != null) - m_chainData.deleteAll(true); - m_universeChain = -1; - m_chainAreas = null; - } - - // Returns a half-edge emanating the cluster. All other half-edges can be - // visited with: - // incident_half_edge = getHalfEdgeTwin(half_edge);//get twin of the - // half_edge, it has the vertex as the end point. - // emanating_half_edge = getHalfEdgeTwin(incident_half_edge); //get next - // emanating half-edge - int getClusterHalfEdge(int cluster) { - return m_clusterData.getField(cluster, 2); - } - - // Returns the coordinates of the cluster - void getXY(int cluster, Point2D pt) { - int vindex = getClusterVertexIndex_(cluster); - m_shape.getXYWithIndex(vindex, pt); - } - - // Returns parentage mask of the cluster - int getClusterParentage(int cluster) { - return m_clusterData.getField(cluster, 1); - } - - // Returns first cluster in the Topo_graph (has lowest y, x coordinates). - int getFirstCluster() { - return m_firstCluster; - } - - // Returns previous cluster in the Topo_graph (in the sorted order of y,x - // coordinates). - int getPrevCluster(int cluster) { - return m_clusterData.getField(cluster, 3); - } - - // Returns next cluster in the Topo_graph (in the sorted order of y,x - // coordinates). - int getNextCluster(int cluster) { - return m_clusterData.getField(cluster, 4); - } - - // Returns an exterior chain of a face this cluster belongs to (belongs only - // to interior). set only for the clusters that are standalone clusters (do - // not have half-edges with them). - int getClusterChain(int cluster) { - return m_clusterData.getField(cluster, 6); - } - - // Returns iterator for cluster vertices - int getClusterVertexIterator(int cluster) { - return m_clusterData.getField(cluster, 7); - } - - // Increments iterator. Returns -1 if no more vertices in the cluster - int incrementVertexIterator(int vertexIterator) { - return m_clusterVertices.getField(vertexIterator, 1); - } - - // Dereference the iterator - int getVertexFromVertexIterator(int vertexIterator) { - return m_clusterVertices.getField(vertexIterator, 0); - } - - // Returns a user index value for the cluster. - int getClusterUserIndex(int cluster, int index) { - int i = getClusterIndex_(cluster); - AttributeStreamOfInt32 stream = m_clusterIndices.get(index); - if (stream.size() <= i) - return -1; - return stream.read(i); - } - - // Sets a user index value for the cluster. - void setClusterUserIndex(int cluster, int index, int value) { - int i = getClusterIndex_(cluster); - AttributeStreamOfInt32 stream = m_clusterIndices.get(index); - if (stream.size() <= i) - stream.resize(m_clusterData.size(), -1); - - stream.write(i, value); - } - - // Creates a new user index for the cluster. The index values are set to -1. - int createUserIndexForClusters() { - if (m_clusterIndices == null) { - m_clusterIndices = new ArrayList(3); - } - - AttributeStreamOfInt32 new_stream = new AttributeStreamOfInt32( - m_clusterData.capacity(), -1); - for (int i = 0, n = m_clusterIndices.size(); i < n; i++) { - if (m_clusterIndices.get(i) == null) { - m_clusterIndices.set(i, new_stream); - return i; - } - } - m_clusterIndices.add(new_stream); - return m_clusterIndices.size() - 1; - } - - // Deletes user index - void deleteUserIndexForClusters(int userIndex) { - assert (m_clusterIndices.get(userIndex) != null); - m_clusterIndices.set(userIndex, null); - } - - // Returns origin of this half edge. To get the other end: - // incident_half_edge = getHalfEdgeTwin(half_edge); - // edge_end_point = getHalfEdgeOrigin(incident_half_edge); - int getHalfEdgeOrigin(int half_edge) { - return m_halfEdgeData.getField(half_edge, 1); - } - - // Returns the to point of the half edge - int getHalfEdgeTo(int half_edge) { - return getHalfEdgeOrigin(getHalfEdgeTwin(half_edge)); - } - - // Twin of this halfedge, it has opposite direction and same endpoints - int getHalfEdgeTwin(int half_edge) { - return m_halfEdgeData.getField(half_edge, 4); - } - - // Returns previous halfedge. It ends, where this halfedge starts. - int getHalfEdgePrev(int half_edge) { - return m_halfEdgeData.getField(half_edge, 5); - } - - // Returns next halfedge. It starts, where this halfedge ends. - int getHalfEdgeNext(int half_edge) { - return m_halfEdgeData.getField(half_edge, 6); - } - - // Returns half edge chain. Chain is on the right from the halfedge - int getHalfEdgeChain(int half_edge) { - return m_halfEdgeData.getField(half_edge, 2); - } - - // Returns half edge chain parentage. The call is implemented as as - // getChainParentage(getHalfEdgeChain()); - int getHalfEdgeFaceParentage(int half_edge) { - return getChainParentage(m_halfEdgeData.getField(half_edge, 2)); - } - - // Returns iterator for cluster vertices - int getHalfEdgeVertexIterator(int half_edge) { - return m_halfEdgeData.getField(half_edge, 7); - } - - // Returns the coordinates of the origin of the half_edge - void getHalfEdgeFromXY(int half_edge, Point2D pt) { - getXY(getHalfEdgeOrigin(half_edge), pt); - } - - // Returns the coordinates of the end of the half_edge - void getHalfEdgeToXY(int half_edge, Point2D pt) { - getXY(getHalfEdgeTo(half_edge), pt); - } - - // Returns parentage mask of this halfedge. Parentage mask of halfedge and - // its twin are the same - int getHalfEdgeParentage(int half_edge) { - return m_halfEdgeData.getField(half_edge, 3) & c_edgeParentageMask; - } - - // Returns a user index value for the half edge - int getHalfEdgeUserIndex(int half_edge, int index) { - int i = getHalfEdgeIndex_(half_edge); - AttributeStreamOfInt32 stream = m_edgeIndices.get(index); - if (stream.size() <= i) - return -1; - - return stream.read(i); - } - - // Sets a user index value for a half edge - void setHalfEdgeUserIndex(int half_edge, int index, int value) { - int i = getHalfEdgeIndex_(half_edge); - AttributeStreamOfInt32 stream = m_edgeIndices.get(index); - if (stream.size() <= i) - stream.resize(m_halfEdgeData.size(), -1); - - stream.write(i, value); - } - - // create a new user index for half edges. The index values are set to -1. - int createUserIndexForHalfEdges() { - if (m_edgeIndices == null) - m_edgeIndices = new ArrayList(3); - - AttributeStreamOfInt32 new_stream = new AttributeStreamOfInt32( - m_halfEdgeData.capacity(), -1); - for (int i = 0, n = m_edgeIndices.size(); i < n; i++) { - if (m_edgeIndices.get(i) == null) { - m_edgeIndices.set(i, new_stream); - return i; - } - } - m_edgeIndices.add(new_stream); - return m_edgeIndices.size() - 1; - } - - // Deletes the given user index for half edges - void deleteUserIndexForHalfEdges(int userIndex) { - assert (m_edgeIndices.get(userIndex) != null); - m_edgeIndices.set(userIndex, null); - } - - // Deletes the half_edge and it's twin. It works presently when removing a - // spike only. - // Returns next valid half-edge, or -1 if no more half edges. - // Use with care. - int deleteEdgeInternal_(int half_edge) { - int chain = getHalfEdgeChain(half_edge); - int halfEdgeTwin = getHalfEdgeTwin(half_edge); - int chainTwin = getHalfEdgeChain(halfEdgeTwin); - // This function only works for spikes. These two asserts check for that - assert (chainTwin == chain); - assert (half_edge == getHalfEdgeNext(halfEdgeTwin) || halfEdgeTwin == getHalfEdgeNext(half_edge)); - - int n = getHalfEdgeNext(half_edge); - if (n == halfEdgeTwin) { - n = getHalfEdgeNext(n); - if (n == half_edge) - n = -1; - } - - if (getChainHalfEdge(chain) == half_edge) { - setChainHalfEdge_(chain, n); - } - - int chainIndex = getChainIndex_(chain); - double v = m_chainAreas.read(chainIndex); - if (!NumberUtils.isNaN(v)) { - setChainArea_(chain, NumberUtils.TheNaN); - setChainPerimeter_(chain, NumberUtils.TheNaN); - } - - updateVertexToHalfEdgeConnection_(half_edge, true); - - deleteEdgeImpl_(half_edge);// does not change chain information - return n; - } - - // Deletes the halfEdges and their twin. The chains are broken after this - // call. - // For every chain the halfedges belong to, it will set the first edge to - // -1. - // However, the halfedge will still reference the chain so one can get the - // parentage information still. - void deleteEdgesBreakFaces_(AttributeStreamOfInt32 edgesToDelete) { - for (int i = 0, n = edgesToDelete.size(); i < n; i++) { - int half_edge = edgesToDelete.get(i); - int chain = getHalfEdgeChain(half_edge); - int halfEdgeTwin = getHalfEdgeTwin(half_edge); - int chainTwin = getHalfEdgeChain(halfEdgeTwin); - setChainHalfEdge_(chain, -1); - setChainHalfEdge_(chainTwin, -1); - updateVertexToHalfEdgeConnection_(half_edge, true); - deleteEdgeImpl_(half_edge); - } - } - - boolean doesHalfEdgeBelongToAPolygonInterior(int half_edge, int polygonId) { - // Half edge belongs to polygon interior if both it and its twin belong - // to boundary of faces that have the polygon parentage (the poygon both - // to the left and to the right of the edge). - int p_1 = getHalfEdgeFaceParentage(half_edge); - int p_2 = getHalfEdgeFaceParentage(getHalfEdgeTwin(half_edge)); - return (p_1 & polygonId) != 0 && (p_2 & polygonId) != 0; - } - - boolean doesHalfEdgeBelongToAPolygonExterior(int half_edge, int polygonId) { - // Half edge belongs to polygon interior if both it and its twin belong - // to boundary of faces that have the polygon parentage (the poygon both - // to the left and to the right of the edge). - int p_1 = getHalfEdgeFaceParentage(half_edge); - int p_2 = getHalfEdgeFaceParentage(getHalfEdgeTwin(half_edge)); - return (p_1 & polygonId) == 0 && (p_2 & polygonId) == 0; - } - - boolean doesHalfEdgeBelongToAPolygonBoundary(int half_edge, int polygonId) { - // Half edge overlaps polygon boundary - int p_1 = getHalfEdgeParentage(half_edge); - return (p_1 & polygonId) != 0; - } - - boolean doesHalfEdgeBelongToAPolylineInterior(int half_edge, int polylineId) { - // Half-edge belongs to a polyline interioir if it has the polyline - // parentage (1D intersection (aka overlap)). - int p_1 = getHalfEdgeParentage(half_edge); - if ((p_1 & polylineId) != 0) { - return true; - } - - return false; - } - - boolean doesHalfEdgeBelongToAPolylineExterior(int half_edge, int polylineId) { - // Half-edge belongs to a polyline Exterioir if it does not have the - // polyline parentage and both its clusters also do not have polyline's - // parentage (to exclude touch at point). - int p_1 = getHalfEdgeParentage(half_edge); - if ((p_1 & polylineId) == 0) { - int c = getHalfEdgeOrigin(half_edge); - int pc = getClusterParentage(c); - if ((pc & polylineId) == 0) { - c = getHalfEdgeTo(half_edge); - pc = getClusterParentage(c); - if ((pc & polylineId) == 0) { - return true; - } - } - } - - return false; - } - - boolean doesClusterBelongToAPolygonInterior(int cluster, int polygonId) { - // cluster belongs to a polygon interior when - // 1) It is a standalone cluster that has face parentage of this polygon - // GetClusterFaceParentage() - // 2) or It is a cluster with half edges attached and - // a) It is not on the polygon boundrary (get_cluster_parentage) - // b) Any half edge associated with it has face parentage of the polygon - // (get_half_edge_face_parentage(getClusterHalfEdge())) - - int chain = getClusterChain(cluster); - if (chain != -1) { - if ((getChainParentage(chain) & polygonId) != 0) { - return true; - } - } else { - int p_1 = getClusterParentage(cluster); - if ((p_1 & polygonId) == 0)// not on the polygon boundary - { - int half_edge = getClusterHalfEdge(cluster); - assert (half_edge != -1); - - int p_2 = getHalfEdgeFaceParentage(half_edge); - if ((p_2 & polygonId) != 0) { - return true; - } - } - } - - return false; - } - - boolean doesClusterBelongToAPolygonExterior(int cluster, int polygonId) { - int p_1 = getClusterParentage(cluster); - if ((p_1 & polygonId) == 0) { - return doesClusterBelongToAPolygonInterior(cluster, polygonId); - } - - return false; - } - - boolean doesClusterBelongToAPolygonBoundary(int cluster, int polygonId) { - int p_1 = getClusterParentage(cluster); - if ((p_1 & polygonId) != 0) { - return true; - } - - return false; - } - - // bool DoesClusterBelongToAPolylineInterioir(int cluster, int polylineId); - // bool does_cluster_belong_to_a_polyline_exterior(int cluster, int - // polylineId); - // bool does_cluster_belong_to_a_polyline_boundary(int cluster, int - // polylineId); - - // Returns the first chain, which is always the Universe chain. - int getFirstChain() { - return m_universeChain; - } - - // Returns the chain half edge. - int getChainHalfEdge(int chain) { - return m_chainData.getField(chain, 1); - } - - // Returns the chain's face parentage. That is the parentage of a face this - // chain borders with. - int getChainParentage(int chain) { - return m_chainData.getField(chain, 2); - } - - // Returns the parent of the chain (the chain, this chain is inside of). - int getChainParent(int chain) { - return m_chainData.getField(chain, 3); - } - - // Returns the first island chain in that chain. Island chains are always - // counterclockwise. - // Each island chain will have its complement chain, which is a chain of a - // twin of any halfedge of that chain. - int getChainFirstIsland(int chain) { - return m_chainData.getField(chain, 4); - } - - // Returns the first island chain in that chain. Island chains are always - // counterclockwise. - int getChainNextInParent(int chain) { - return m_chainData.getField(chain, 5); - } - - // Returns the next chain in arbitrary order. - int getChainNext(int chain) { - return m_chainData.getField(chain, 7); - } - - // Returns the area of the chain. The area does not include any islands. - // +Inf is returned for the universe chain. - double getChainArea(int chain) { - int chainIndex = getChainIndex_(chain); - double v = m_chainAreas.read(chainIndex); - if (NumberUtils.isNaN(v)) { - updateChainAreaAndPerimeter_(chain); - v = m_chainAreas.read(chainIndex); - } - - return v; - } - - // Returns the perimeter of the chain (> 0). +Inf is returned for the - // universe chain. - double getChainPerimeter(int chain) { - int chainIndex = getChainIndex_(chain); - double v = m_chainPerimeters.read(chainIndex); - if (NumberUtils.isNaN(v)) { - updateChainAreaAndPerimeter_(chain); - v = m_chainPerimeters.read(chainIndex); - } - - return v; - } - - // Returns a user index value for the chain. - int getChainUserIndex(int chain, int index) { - int i = getChainIndex_(chain); - AttributeStreamOfInt32 stream = m_chainIndices.get(index); - if (stream.size() <= i) - return -1; - return stream.read(i); - } - - // Sets a user index value for the chain. - void setChainUserIndex(int chain, int index, int value) { - int i = getChainIndex_(chain); - AttributeStreamOfInt32 stream = m_chainIndices.get(index); - if (stream.size() <= i) - stream.resize(m_chainData.size(), -1); - - stream.write(i, value); - } - - // Creates a new user index for the chains. The index values are set to -1. - int createUserIndexForChains() { - if (m_chainIndices == null) { - m_chainIndices = new ArrayList(3); - } - - AttributeStreamOfInt32 new_stream = new AttributeStreamOfInt32( - m_chainData.capacity(), -1); - for (int i = 0, n = m_chainIndices.size(); i < n; i++) { - if (m_chainIndices.get(i) == null) { - m_chainIndices.set(i, new_stream); - return i; - } - } - m_chainIndices.add(new_stream); - return m_chainIndices.size() - 1; - } - - // Deletes user index - void deleteUserIndexForChains(int userIndex) { - assert (m_chainIndices.get(userIndex) != null); - m_chainIndices.set(userIndex, null); - } - - // Returns geometry ID mask from the geometry handle. - // Topo_graph creates a user index for geometries in the shape, which exists - // until the topo graph is destroyed. - int getGeometryID(int geometry) { - return m_shape.getGeometryUserIndex(geometry, m_geometryIDIndex); - } - - // Returns cluster from vertex handle. - // Topo_graph creates a user index for vertices in the shape to hold cluster - // handles. The index exists until the topo graph is destroyed. - int getClusterFromVertex(int vertex) { - return m_shape.getUserIndex(vertex, m_clusterIndex); - } - - int getHalfEdgeFromVertex(int vertex) { - return m_shape.getUserIndex(vertex, m_halfEdgeIndex); - } - - // Finds an edge connecting the two clusters. Returns -1 if not found. - // Could be a slow operation when valency of each cluster is high. - int getHalfEdgeConnector(int clusterFrom, int clusterTo) { - int first_edge = getClusterHalfEdge(clusterFrom); - if (first_edge == -1) - return -1; - int edge = first_edge; - int firstEdgeTo = -1; - int eTo = -1; - // Doing two loops in parallel - one on the half-edges attached to the - // clusterFrom, another - attached to clusterTo. - do { - if (getHalfEdgeTo(edge) == clusterTo) - return edge; - - if (firstEdgeTo == -1) { - firstEdgeTo = getClusterHalfEdge(clusterTo); - if (firstEdgeTo == -1) - return -1; - eTo = firstEdgeTo; - } - - if (getHalfEdgeTo(eTo) == clusterFrom) { - edge = getHalfEdgeTwin(eTo); - assert (getHalfEdgeTo(edge) == clusterTo && getHalfEdgeOrigin(edge) == clusterFrom); - return edge; - } - - edge = getHalfEdgeNext(getHalfEdgeTwin(edge)); - eTo = getHalfEdgeNext(getHalfEdgeTwin(eTo)); - } while (edge != first_edge && eTo != firstEdgeTo); - - return -1; - } - - // Queries segment for the edge (only xy coordinates, no attributes) - void querySegmentXY(int half_edge, SegmentBuffer outBuffer) { - outBuffer.createLine(); - Segment seg = outBuffer.get(); - Point2D pt = new Point2D(); - getHalfEdgeFromXY(half_edge, pt); - seg.setStartXY(pt); - getHalfEdgeToXY(half_edge, pt); - seg.setEndXY(pt); - } - - int compareEdgeAngles_(int edge1, int edge2) { - if (edge1 == edge2) - return 0; - - Point2D pt_1 = new Point2D(); - getHalfEdgeToXY(edge1, pt_1); - - Point2D pt_2 = new Point2D(); - getHalfEdgeToXY(edge2, pt_2); - - if (pt_1.isEqual(pt_2)) - return 0;// overlap case - - Point2D pt10 = new Point2D(); - getHalfEdgeFromXY(edge1, pt10); - - Point2D v_1 = new Point2D(); - v_1.sub(pt_1, pt10); - Point2D v_2 = new Point2D(); - v_2.sub(pt_2, pt10); - int result = Point2D._compareVectors(v_1, v_2); - return result; - } - - int compareEdgeAnglesForPair_(int edge1, int edge2) { - if (edge1 == edge2) - return 0; - - Point2D pt_1 = new Point2D(); - getHalfEdgeToXY(edge1, pt_1); - - Point2D pt_2 = new Point2D(); - getHalfEdgeToXY(edge2, pt_2); - - if (pt_1.isEqual(pt_2)) - return 0;// overlap case - - Point2D pt10 = new Point2D(); - getHalfEdgeFromXY(edge1, pt10); - - Point2D v_1 = new Point2D(); - v_1.sub(pt_1, pt10); - Point2D v_2 = new Point2D(); - v_2.sub(pt_2, pt10); - - if (v_2.y >= 0 && v_1.y > 0) { - int result = Point2D._compareVectors(v_1, v_2); - return result; - } else { - return 0; - } - } - - boolean check_structure_after_dirty_sweep_() { - // for each cluster go through the cluster half edges and check that - // min(edge1_length, edge2_length) * angle_between is less than - // m_check_dirty_planesweep_tolerance. - // Doing this helps us weed out cases missed by the dirty plane sweep. - // We do not need absolute accuracy here. - assert (!m_dirty_check_failed); - assert (!NumberUtils.isNaN(m_check_dirty_planesweep_tolerance)); - double sqr_tol = MathUtils.sqr(m_check_dirty_planesweep_tolerance); - Point2D pt10 = new Point2D(); - Point2D pt_2 = new Point2D(); - Point2D pt_1 = new Point2D(); - Point2D v_1 = new Point2D(); - Point2D v_2 = new Point2D(); - for (int cluster = getFirstCluster(); cluster != -1; cluster = getNextCluster(cluster)) { - int first = getClusterHalfEdge(cluster); - if (first != -1) { - int edge = first; - getHalfEdgeFromXY(edge, pt10); - getHalfEdgeToXY(edge, pt_2); - v_2.sub(pt_2, pt10); - double sqr_len2 = v_2.sqrLength(); - - do { - int prev = edge; - edge = getHalfEdgeNext(getHalfEdgeTwin(edge)); - - if (edge != prev) { - getHalfEdgeToXY(edge, pt_1); - assert (!pt_1.isEqual(pt_2)); - v_1.sub(pt_1, pt10); - double sqr_len1 = v_1.sqrLength(); - - double cross = v_1.crossProduct(v_2); // cross_prod = - // len1 * len2 * - // sinA => sinA - // = cross_prod - // / (len1 * - // len2); - double sqr_sinA = (cross * cross) - / (sqr_len1 * sqr_len2); // sqr_sinA is - // approximately A^2 - // especially for - // smaller angles - double sqr_dist = Math.min(sqr_len1, sqr_len2) - * sqr_sinA; - if (sqr_dist <= sqr_tol) { - // these edges incident on the cluster form a narrow - // wedge and thei require cracking event that was - // missed. - return false; - } - - v_2.setCoords(v_1); - sqr_len2 = sqr_len1; - pt_2.setCoords(pt_1); - } - } while (edge != first); - } - } - - return true; - } + static interface EnumInputMode { + + final static int enumInputModeBuildGraph = 0; + final static int enumInputModeSimplifyAlternate = 4 + 0; + final static int enumInputModeSimplifyWinding = 4 + 1; + final static int enumInputModeIsSimplePolygon = 4 + 3; + } + + EditShape m_shape; + + // cluster data: index, parentage, halfEdge, globalPrev, globalNext + StridedIndexTypeCollection m_clusterData; + StridedIndexTypeCollection m_clusterVertices; + int m_firstCluster; + int m_lastCluster; + // edge data: index, origin, faceParentage, edgeParentage, twin, prev, next + StridedIndexTypeCollection m_halfEdgeData; + // chain data index, half_edge, parentage, parentChain, firstIsland, + // nextInParent, prev, next + StridedIndexTypeCollection m_chainData; + AttributeStreamOfDbl m_chainAreas; + AttributeStreamOfDbl m_chainPerimeters; + + final int c_edgeParentageMask; + final int c_edgeBitMask; + int m_universeChain; + ArrayList m_edgeIndices; + ArrayList m_clusterIndices; + ArrayList m_chainIndices; + + int m_geometryIDIndex; // index of geometryIDs in the m_shape + int m_clusterIndex; // vertex index of cluster handles in the m_shape + int m_halfEdgeIndex; // vertex index of half-edges in the m_shape + int m_tmpHalfEdgeParentageIndex; + int m_tmpHalfEdgeWindingNumberIndex; + int m_tmpHalfEdgeOddEvenNumberIndex = -1; + + int m_universe_geomID = -1; + + boolean m_buildChains = true; + + private boolean m_dirty_check_failed = false; + private double m_check_dirty_planesweep_tolerance = Double.NaN; + + void check_dirty_planesweep(double tolerance) { + m_check_dirty_planesweep_tolerance = tolerance; + } + + boolean dirty_check_failed() { + return m_dirty_check_failed; + } + + NonSimpleResult m_non_simple_result = new NonSimpleResult(); + + int m_pointCount;// point count processed in this Topo_graph. Used to + // reserve data. + + static final class PlaneSweepComparator extends Treap.Comparator { + TopoGraph m_helper; + SegmentBuffer m_buffer_left; + SegmentBuffer m_buffer_right; + Envelope1D interval_left; + Envelope1D interval_right; + double m_y_scanline; + + PlaneSweepComparator(TopoGraph helper) { + m_helper = helper; + m_y_scanline = NumberUtils.TheNaN; + m_buffer_left = new SegmentBuffer(); + m_buffer_right = new SegmentBuffer(); + interval_left = new Envelope1D(); + interval_right = new Envelope1D(); + } + + @Override + int compare(Treap treap, int left, int node) { + int right = treap.getElement(node); + // can be sped up a little, because left or right stay the same + // while an edge is inserted into the tree. + m_helper.querySegmentXY(left, m_buffer_left); + m_helper.querySegmentXY(right, m_buffer_right); + Segment segLeft = m_buffer_left.get(); + Segment segRight = m_buffer_right.get(); + + // Prerequisite: The segments have the start point lexicographically + // above the end point. + assert (segLeft.getStartXY().compare(segLeft.getEndXY()) < 0); + assert (segRight.getStartXY().compare(segRight.getEndXY()) < 0); + + // Simple test for faraway segments + interval_left.setCoords(segLeft.getStartX(), segLeft.getEndX()); + interval_right.setCoords(segRight.getStartX(), segRight.getEndX()); + if (interval_left.vmax < interval_right.vmin) + return -1; + if (interval_left.vmin > interval_right.vmax) + return 1; + + boolean bLeftHorz = segLeft.getStartY() == segLeft.getEndY(); + boolean bRightHorz = segRight.getStartY() == segRight.getEndY(); + if (bLeftHorz || bRightHorz) { + if (bLeftHorz && bRightHorz) { + assert (interval_left.equals(interval_right)); + return 0; + } + + // left segment is horizontal. The right one is not. + // Prerequisite of this algorithm is that this can only happen + // when: + // left + // |right -------------------- end == end + // | | + // | left | + // -------------------- right | + // start == start + // or: + // right segment is horizontal. The left one is not. + // Prerequisite of this algorithm is that his can only happen + // when: + // right + // |left -------------------- end == end + // | | + // | right | + // -------------------- left | + // start == start + + if (segLeft.getStartY() == segRight.getStartY() + && segLeft.getStartX() == segRight.getStartX()) + return bLeftHorz ? 1 : -1; + else if (segLeft.getEndY() == segRight.getEndY() + && segLeft.getEndX() == segRight.getEndX()) + return bLeftHorz ? -1 : 1; + } + + // Now do actual intersections + double xLeft = segLeft.intersectionOfYMonotonicWithAxisX( + m_y_scanline, interval_left.vmin); + double xRight = segRight.intersectionOfYMonotonicWithAxisX( + m_y_scanline, interval_right.vmin); + + if (xLeft == xRight) { + // apparently these edges originate from same vertex and the + // scanline is on the vertex. move scanline a little. + double yLeft = segLeft.getEndY(); + double yRight = segRight.getEndY(); + double miny = Math.min(yLeft, yRight); + double y = (miny + m_y_scanline) * 0.5; + if (y == m_y_scanline) { + // assert(0);//ST: not a bug. just curious to see this + // happens. + y = miny; // apparently, one of the segments is almost + // horizontal line. + } + xLeft = segLeft.intersectionOfYMonotonicWithAxisX(y, + interval_left.vmin); + xRight = segRight.intersectionOfYMonotonicWithAxisX(y, + interval_right.vmin); + } + + return xLeft < xRight ? -1 : (xLeft > xRight ? 1 : 0); + } + + void setY(double y) { + m_y_scanline = y; + } + // void operator=(const Plane_sweep_comparator&); // do not allow + // operator = + } + + ; + + static final class TopoGraphAngleComparer extends IntComparator { + TopoGraph m_parent; + + TopoGraphAngleComparer(TopoGraph parent_) { + m_parent = parent_; + } + + @Override + public int compare(int v1, int v2) { + return m_parent.compareEdgeAngles_(v1, v2); + } + } + + ; + + static final class ClusterSweepMonikerComparator extends + Treap.MonikerComparator { + TopoGraph m_parent; + SegmentBuffer m_segment_buffer; + Point2D m_point; + Envelope1D m_interval; + + ClusterSweepMonikerComparator(TopoGraph parent) { + m_parent = parent; + m_segment_buffer = new SegmentBuffer(); + m_point = new Point2D(); + m_interval = new Envelope1D(); + } + + void setPointXY(Point2D pt) { + m_point.setCoords(pt); + } + + @Override + int compare(Treap treap, int node) { + int half_edge = treap.getElement(node); + + // can be sped up a little, because left or right stay the same + // while an edge is inserted into the tree. + m_parent.querySegmentXY(half_edge, m_segment_buffer); + Segment seg = m_segment_buffer.get(); + + // Simple test for faraway segments + m_interval.setCoords(seg.getStartX(), seg.getEndX()); + if (m_point.x < m_interval.vmin) + return -1; + + if (m_point.x > m_interval.vmax) + return 1; + + // Now do actual intersections + double x = seg.intersectionOfYMonotonicWithAxisX(m_point.y, + m_point.x); + + assert (x != m_point.x); + + return m_point.x < x ? -1 : (m_point.x > x ? 1 : 0); + } + } + + int newCluster_() { + if (m_clusterData == null) + m_clusterData = new StridedIndexTypeCollection(8); + + int cluster = m_clusterData.newElement(); + // m_clusterData->add(-1);//first vertex + m_clusterData.setField(cluster, 1, 0);// parentage + // m_clusterData->add(-1);//first half edge + // m_clusterData->add(-1);//prev cluster + // m_clusterData->add(-1);//next cluster + return cluster; + } + + int newHalfEdgePair_() { + if (m_halfEdgeData == null) + m_halfEdgeData = new StridedIndexTypeCollection(8); + + int halfEdge = m_halfEdgeData.newElement(); + // m_halfEdgeData.add(-1);//origin cluster + m_halfEdgeData.setField(halfEdge, 2, 0);// chain parentage + m_halfEdgeData.setField(halfEdge, 3, 0);// edge parentage + // m_halfEdgeData.add(-1);//twin + // m_halfEdgeData.add(-1);//prev + // m_halfEdgeData.add(-1);//next + int twinHalfEdge = m_halfEdgeData.newElement(); + // m_halfEdgeData.add(-1);//origin cluster + m_halfEdgeData.setField(twinHalfEdge, 2, 0);// chain parentage + m_halfEdgeData.setField(twinHalfEdge, 3, 0);// edge parentage + // m_halfEdgeData.add(-1);//twin + // m_halfEdgeData.add(-1);//prev + // m_halfEdgeData.add(-1);//next + setHalfEdgeTwin_(halfEdge, twinHalfEdge); + setHalfEdgeTwin_(twinHalfEdge, halfEdge); + return halfEdge; + } + + int newChain_() { + if (m_chainData == null) + m_chainData = new StridedIndexTypeCollection(8); + + int chain = m_chainData.newElement(); + // m_chainData->write(chain, + 1, -1);//half_edge + m_chainData.setField(chain, 2, 0);// parentage (geometric) + // m_chainData->write(m_chainReserved + 3, -1);//parent chain + // m_chainData->write(m_chainReserved + 4, -1);//firstIsland + // m_chainData->write(m_chainReserved + 5, -1);//nextInParent + // m_chainData->write(m_chainReserved + 6, -1);//prev + // m_chainData->write(m_chainReserved + 7, -1);//next + // m_chainReserved += 8; + return chain; + } + + int deleteChain_(int chain) { + // Note: this method cannot be after _PlaneSweep + assert (m_universeChain != chain); + int n = getChainNext(chain); + m_chainData.deleteElement(chain); + // Note: no need to update the first chain, because one should never try + // deleting the first (the universe) chain. + return n; + } + + int getClusterIndex_(int cluster) { + return m_clusterData.elementToIndex(cluster); + } + + void setClusterVertexIterator_(int cluster, int verticeList) { + m_clusterData.setField(cluster, 7, verticeList); + } + + void setClusterHalfEdge_(int cluster, int half_edge) { + m_clusterData.setField(cluster, 2, half_edge); + } + + void setClusterParentage_(int cluster, int parentage) { + m_clusterData.setField(cluster, 1, parentage); + } + + void setPrevCluster_(int cluster, int nextCluster) { + m_clusterData.setField(cluster, 3, nextCluster); + } + + void setNextCluster_(int cluster, int nextCluster) { + m_clusterData.setField(cluster, 4, nextCluster); + } + + void setClusterVertexIndex_(int cluster, int index) { + m_clusterData.setField(cluster, 5, index); + } + + int getClusterVertexIndex_(int cluster) { + return m_clusterData.getField(cluster, 5); + } + + void setClusterChain_(int cluster, int chain) { + m_clusterData.setField(cluster, 6, chain); + } + + void addClusterToExteriorChain_(int chain, int cluster) { + assert (getClusterChain(cluster) == -1); + setClusterChain_(cluster, chain); + // There is no link from the chain to the cluster. Only vice versa. + // Consider for change? + } + + int getHalfEdgeIndex_(int he) { + return m_halfEdgeData.elementToIndex(he); + } + + void setHalfEdgeOrigin_(int half_edge, int cluster) { + m_halfEdgeData.setField(half_edge, 1, cluster); + } + + void setHalfEdgeTwin_(int half_edge, int twinHalfEdge) { + m_halfEdgeData.setField(half_edge, 4, twinHalfEdge); + } + + void setHalfEdgePrev_(int half_edge, int prevHalfEdge) { + m_halfEdgeData.setField(half_edge, 5, prevHalfEdge); + } + + void setHalfEdgeNext_(int half_edge, int nextHalfEdge) { + m_halfEdgeData.setField(half_edge, 6, nextHalfEdge); + } + + // void set_half_edge_chain_parentage_(int half_edge, int + // chainParentageMask) { m_halfEdgeData.setField(half_edge + 2, + // chainParentageMask); } + void setHalfEdgeChain_(int half_edge, int chain) { + m_halfEdgeData.setField(half_edge, 2, chain); + } + + void setHalfEdgeParentage_(int half_edge, int parentageMask) { + m_halfEdgeData.setField(half_edge, 3, parentageMask); + } + + int getHalfEdgeParentageMask_(int half_edge) { + return m_halfEdgeData.getField(half_edge, 3); + } + + void setHalfEdgeVertexIterator_(int half_edge, int vertexIterator) { + m_halfEdgeData.setField(half_edge, 7, vertexIterator); + } + + void updateVertexToHalfEdgeConnectionHelper_(int half_edge, boolean bClear) { + int viter = getHalfEdgeVertexIterator(half_edge); + if (viter != -1) { + int he = bClear ? -1 : half_edge; + for (int viter_ = getHalfEdgeVertexIterator(half_edge); viter_ != -1; viter_ = incrementVertexIterator(viter_)) { + int vertex = getVertexFromVertexIterator(viter_); + m_shape.setUserIndex(vertex, m_halfEdgeIndex, he); + } + } + } + + void updateVertexToHalfEdgeConnection_(int half_edge, boolean bClear) { + if (half_edge == -1) + return; + updateVertexToHalfEdgeConnectionHelper_(half_edge, bClear); + updateVertexToHalfEdgeConnectionHelper_(getHalfEdgeTwin(half_edge), + bClear); + } + + int getChainIndex_(int chain) { + return m_chainData.elementToIndex(chain); + } + + void setChainHalfEdge_(int chain, int half_edge) { + m_chainData.setField(chain, 1, half_edge); + } + + void setChainParentage_(int chain, int parentage) { + m_chainData.setField(chain, 2, parentage); + } + + void setChainParent_(int chain, int parentChain) { + assert (m_chainData.getField(chain, 3) != parentChain); + m_chainData.setField(chain, 3, parentChain); + int firstIsland = getChainFirstIsland(parentChain); + setChainNextInParent_(chain, firstIsland); + setChainFirstIsland_(parentChain, chain); + } + + void setChainFirstIsland_(int chain, int islandChain) { + m_chainData.setField(chain, 4, islandChain); + } + + void setChainNextInParent_(int chain, int nextInParent) { + m_chainData.setField(chain, 5, nextInParent); + } + + void setChainPrev_(int chain, int prev) { + m_chainData.setField(chain, 6, prev); + } + + void setChainNext_(int chain, int next) { + m_chainData.setField(chain, 7, next); + } + + void setChainArea_(int chain, double area) { + int chainIndex = getChainIndex_(chain); + m_chainAreas.write(chainIndex, area); + } + + void setChainPerimeter_(int chain, double perimeter) { + int chainIndex = getChainIndex_(chain); + m_chainPerimeters.write(chainIndex, perimeter); + } + + void updateChainAreaAndPerimeter_(int chain) { + double area = 0; + double perimeter = 0; + int firstHalfEdge = getChainHalfEdge(chain); + Point2D origin = new Point2D(), from = new Point2D(), to = new Point2D(); + getHalfEdgeFromXY(firstHalfEdge, origin); + from.setCoords(origin); + int half_edge = firstHalfEdge; + do { + getHalfEdgeToXY(half_edge, to); + perimeter += Point2D.distance(from, to); + int twinChain = getHalfEdgeChain(getHalfEdgeTwin(half_edge)); + if (twinChain != chain)// only count edges are not dangling segments + // of polylines + { + area += ((to.x - origin.x) - (from.x - origin.x)) + * ((to.y - origin.y) + (from.y - origin.y)) * 0.5; + } + + from.setCoords(to); + half_edge = getHalfEdgeNext(half_edge); + } while (half_edge != firstHalfEdge); + + int ind = getChainIndex_(chain); + m_chainAreas.write(ind, area); + m_chainPerimeters.write(ind, perimeter); + } + + int getChainTopMostEdge_(int chain) { + int firstHalfEdge = getChainHalfEdge(chain); + Point2D top = new Point2D(); + getHalfEdgeFromXY(firstHalfEdge, top); + int topEdge = firstHalfEdge; + Point2D v = new Point2D(); + int half_edge = firstHalfEdge; + do { + getHalfEdgeFromXY(half_edge, v); + if (v.compare(top) > 0) { + top.setCoords(v); + topEdge = half_edge; + } + half_edge = getHalfEdgeNext(half_edge); + } while (half_edge != firstHalfEdge); + return topEdge; + } + + void planeSweepParentage_(int inputMode, ProgressTracker progress_tracker) { + PlaneSweepComparator comparator = new PlaneSweepComparator(this); + Treap aet = new Treap(); + aet.setCapacity(m_pointCount / 2); + aet.setComparator(comparator); + + AttributeStreamOfInt32 new_edges = new AttributeStreamOfInt32(0); + int treeNodeIndex = createUserIndexForHalfEdges(); + + ClusterSweepMonikerComparator clusterMoniker = null; + int counter = 0; + // Clusters are sorted by the y, x coordinate in ascending order. + Point2D pt = new Point2D(); + // Each cluster is an event of the sweep-line algorithm. + for (int cluster = getFirstCluster(); cluster != -1; cluster = getNextCluster(cluster)) { + counter++; + if ((counter & 0xFF) == 0) { + if ((progress_tracker != null) + && !(progress_tracker.progress(-1, -1))) + throw new UserCancelException(); + } + + int firstHalfEdge = getClusterHalfEdge(cluster); + if (firstHalfEdge != -1) { + new_edges.resizePreserveCapacity(0); + if (!tryOptimizedInsertion_(aet, treeNodeIndex, new_edges, + cluster, firstHalfEdge))// optimized insertion is for a + // simple chain, in that case we + // simply replace an old edge + // with a new one in AET - O(1) + {// This is more complex than a simple chain of edges + getXY(cluster, pt); + comparator.setY(pt.y); + int clusterHalfEdge = firstHalfEdge; + // Delete all edges that end at the cluster. + do {// edges that end at the cluster have been assigned an + // AET node in the treeNodeIndex. + int attachedTreeNode = getHalfEdgeUserIndex( + clusterHalfEdge, treeNodeIndex); + if (attachedTreeNode != -1) { + assert (attachedTreeNode != StridedIndexTypeCollection + .impossibleIndex2()); + aet.deleteNode(attachedTreeNode, -1); + setHalfEdgeUserIndex(clusterHalfEdge, + treeNodeIndex, + StridedIndexTypeCollection + .impossibleIndex2());// set it to -2 + } + + clusterHalfEdge = getHalfEdgeNext(getHalfEdgeTwin(clusterHalfEdge)); + assert (getHalfEdgeOrigin(clusterHalfEdge) == cluster); + } while (firstHalfEdge != clusterHalfEdge); + + // insert edges that start at the cluster. + // We need to insert only the edges that have the from point + // below the to point. + // This is ensured by the logic of the algorithm. + clusterHalfEdge = firstHalfEdge; + do { + int attachedTreeNode = getHalfEdgeUserIndex( + clusterHalfEdge, treeNodeIndex); + if (attachedTreeNode == -1) { + int newTreeNode = aet.addElement(clusterHalfEdge, + -1); + new_edges.add(newTreeNode); + } + clusterHalfEdge = getHalfEdgeNext(getHalfEdgeTwin(clusterHalfEdge)); + assert (getHalfEdgeOrigin(clusterHalfEdge) == cluster); + } while (firstHalfEdge != clusterHalfEdge); + } + + // Analyze new edges. + // We go in the opposite order, because of the way how the half + // edges are sorted on a cluster. + // We want to go from the left to the right. + for (int i = new_edges.size() - 1; i >= 0; i--) { + int newTreeNode = new_edges.get(i); + int clusterHalfEdge = aet.getElement(newTreeNode); + int twinEdge = getHalfEdgeTwin(clusterHalfEdge); + assert (getHalfEdgeUserIndex(twinEdge, treeNodeIndex) == -1); + setHalfEdgeUserIndex(twinEdge, treeNodeIndex, newTreeNode); + + planeSweepParentagePropagateParentage_(aet, newTreeNode, + inputMode); + } + } else if (getClusterChain(cluster) == -1) { + // get the left half edge of a face. The point belongs to the + // face. + if (clusterMoniker == null) + clusterMoniker = new ClusterSweepMonikerComparator(this); + + getXY(cluster, pt); + clusterMoniker.setPointXY(pt); + int leftNode = aet.searchLowerBound(clusterMoniker, -1); + int chain = m_universeChain; + + if (leftNode != -1) { + int edge = aet.getElement(leftNode); + int leftChain = getHalfEdgeChain(edge); + if (leftChain == getHalfEdgeChain(getHalfEdgeTwin(edge))) { + edge = getLeftSkipPolylines_(aet, leftNode); + } + + if (edge != -1) + chain = getHalfEdgeChain(edge); + } + + addClusterToExteriorChain_(chain, cluster); + } + } + + deleteUserIndexForHalfEdges(treeNodeIndex); + } + + void planeSweepParentagePropagateParentage_(Treap aet, int treeNode, + int inputMode) { + int edge = aet.getElement(treeNode); + int edgeChain = getHalfEdgeChain(edge); + int edgeChainParent = getChainParent(edgeChain); + if (edgeChainParent != -1) + return;// this edge has been processed already. + + // get contributing left edge. + int leftEdge = getLeftSkipPolylines_(aet, treeNode); + + int twinEdge = getHalfEdgeTwin(edge); + int twinHalfEdgeChain = getHalfEdgeChain(twinEdge); + + double chainArea = getChainArea(edgeChain); + double twinChainArea = getChainArea(twinHalfEdgeChain); + + int parentChain = getChainParent(edgeChain); + int twinParentChain = getChainParent(twinHalfEdgeChain); + if (leftEdge == -1 && parentChain == -1) { + // This edge/twin pair does not have a neighbour edge to the left. + // twin parent is not yet been assigned. + if (twinHalfEdgeChain == edgeChain) {// set parentage of a polyline + // edge (any edge for which + // the edge ant its twin + // belong to the same chain) + setChainParent_(twinHalfEdgeChain, getFirstChain()); + twinParentChain = getFirstChain(); + parentChain = twinParentChain; + } else { + // We have two touching chains that do not have parent chain + // set. + // The edge is directed up, the twin edge is directed down. + // There is no edge to the left. THat means there is no other + // than the universe surrounding this edge. + // The edge must belong to a clockwise chain, and the twin edge + // must belong to a ccw chain that encloses this edge. This + // follows from the way how we connect edges around clusters. + assert (twinChainArea < 0 && chainArea > 0); + if (twinParentChain == -1) { + setChainParent_(twinHalfEdgeChain, m_universeChain); + twinParentChain = m_universeChain; + } else { + assert (getFirstChain() == twinParentChain); + } + + setChainParent_(edgeChain, twinHalfEdgeChain); + parentChain = twinHalfEdgeChain; + } + } + + if (leftEdge != -1) { + int leftEdgeChain = getHalfEdgeChain(leftEdge); + // the twin edge has not been processed yet + if (twinParentChain == -1) { + double leftArea = getChainArea(leftEdgeChain); + if (leftArea <= 0) {// if left Edge's chain area is negative, + // then it is a chain that ends at the left + // edge, so we need to get the parent of the + // left chain and it will be the parent of + // this one. + int leftChainParent = getChainParent(leftEdgeChain); + assert (leftChainParent != -1); + + setChainParent_(twinHalfEdgeChain, leftChainParent); + twinParentChain = leftChainParent; + } else // (leftArea > 0) + {// left edge is an edge of positive chain. It surrounds the + // twin chain. + setChainParent_(twinHalfEdgeChain, leftEdgeChain); + twinParentChain = leftEdgeChain; + } + + if (twinHalfEdgeChain == edgeChain) // if this is a polyline + // chain + parentChain = twinParentChain; + } + } + + if (parentChain == -1) { + trySetChainParentFromTwin_(edgeChain, twinHalfEdgeChain); + parentChain = getChainParent(edgeChain); + } + + assert (parentChain != -1); + + if (inputMode == EnumInputMode.enumInputModeBuildGraph) { + propagate_parentage_build_graph_(aet, treeNode, edge, leftEdge, edgeChain, edgeChainParent, twinHalfEdgeChain); + } else if (inputMode == EnumInputMode.enumInputModeSimplifyWinding) { + propagate_parentage_winding_(aet, treeNode, edge, leftEdge, twinEdge, edgeChain, edgeChainParent, twinHalfEdgeChain); + } else if (inputMode == EnumInputMode.enumInputModeSimplifyAlternate) { + propagate_parentage_alternate_(aet, treeNode, edge, leftEdge, twinEdge, edgeChain, edgeChainParent, twinHalfEdgeChain); + } + + } + + void propagate_parentage_build_graph_(Treap aet, int treeNode, int edge, int leftEdge, + int edgeChain, int edgeChainParent, int twinHalfEdgeChain) { + // Now do specific sweep calculations + int chainParentage = getChainParentage(edgeChain); + + if (leftEdge != -1) { + // borrow the parentage from the left edge also + int leftEdgeChain = getHalfEdgeChain(leftEdge); + + // We take parentage from the left edge (that edge has been + // already processed), and move its face parentage accross this + // edge/twin pair. + // While the parentage is moved, accross, any bits of the + // parentage that is present in the twin are removed, because + // the twin is the right edge of the current face. + // The remaining bits are added to the face parentage of this + // edge, indicating that the face this edge borders, belongs to + // all the parents that are still active to the left. + int twinChainParentage = getChainParentage(twinHalfEdgeChain); + int leftChainParentage = getChainParentage(leftEdgeChain); + + int edgeParentage = getHalfEdgeParentage(edge); + int spikeParentage = chainParentage & twinChainParentage + & leftChainParentage; // parentage that needs to stay + leftChainParentage = leftChainParentage + ^ (leftChainParentage & edgeParentage); + leftChainParentage |= spikeParentage; + + if (leftChainParentage != 0) { + // propagate left parentage to the current edge and its + // twin. + setChainParentage_(twinHalfEdgeChain, twinChainParentage + | leftChainParentage); + setChainParentage_(edgeChain, leftChainParentage + | chainParentage); + chainParentage |= leftChainParentage; + } + + // dbg_print_edge_(edge); + } + + for (int rightNode = aet.getNext(treeNode); rightNode != -1; rightNode = aet + .getNext(rightNode)) { + int rightEdge = aet.getElement(rightNode); + int rightTwin = getHalfEdgeTwin(rightEdge); + + int rightTwinChain = getHalfEdgeChain(rightTwin); + int rightTwinChainParentage = getChainParentage(rightTwinChain); + int rightEdgeParentage = getHalfEdgeParentage(rightEdge); + int rightEdgeChain = getHalfEdgeChain(rightEdge); + int rightChainParentage = getChainParentage(rightEdgeChain); + + int spikeParentage = rightTwinChainParentage + & rightChainParentage & chainParentage; // parentage + // that needs to + // stay + chainParentage = chainParentage + ^ (chainParentage & rightEdgeParentage);// only + // parentage + // that is + // abscent in + // the twin is + // propagated to + // the right + chainParentage |= spikeParentage; + + if (chainParentage == 0) + break; + + setChainParentage_(rightTwinChain, rightTwinChainParentage + | chainParentage); + setChainParentage_(rightEdgeChain, rightChainParentage + | chainParentage); + } + } + + void propagate_parentage_winding_(Treap aet, int treeNode, int edge, int leftEdge, int twinEdge, + int edgeChain, int edgeChainParent, int twinHalfEdgeChain) { + + if (edgeChain == twinHalfEdgeChain) + return; + // starting from the left most edge, calculate winding. + int edgeWinding = getHalfEdgeUserIndex(edge, + m_tmpHalfEdgeWindingNumberIndex); + edgeWinding += getHalfEdgeUserIndex(twinEdge, + m_tmpHalfEdgeWindingNumberIndex); + int winding = 0; + AttributeStreamOfInt32 chainStack = new AttributeStreamOfInt32(0); + AttributeStreamOfInt32 windingStack = new AttributeStreamOfInt32(0); + windingStack.add(0); + for (int leftNode = aet.getFirst(-1); leftNode != treeNode; leftNode = aet + .getNext(leftNode)) { + int leftEdge1 = aet.getElement(leftNode); + int leftTwin = getHalfEdgeTwin(leftEdge1); + int l_chain = getHalfEdgeChain(leftEdge1); + int lt_chain = getHalfEdgeChain(leftTwin); + + if (l_chain != lt_chain) { + int leftWinding = getHalfEdgeUserIndex(leftEdge1, + m_tmpHalfEdgeWindingNumberIndex); + leftWinding += getHalfEdgeUserIndex(leftTwin, + m_tmpHalfEdgeWindingNumberIndex); + winding += leftWinding; + + boolean popped = false; + if (chainStack.size() != 0 + && chainStack.getLast() == lt_chain) { + windingStack.removeLast(); + chainStack.removeLast(); + popped = true; + } + + if (getChainParent(lt_chain) == -1) + throw GeometryException.GeometryInternalError(); + + if (!popped || getChainParent(lt_chain) != l_chain) { + windingStack.add(winding); + chainStack.add(l_chain); + } + } + } + + winding += edgeWinding; + + if (chainStack.size() != 0 + && chainStack.getLast() == twinHalfEdgeChain) { + windingStack.removeLast(); + chainStack.removeLast(); + } + + if (winding != 0) { + if (windingStack.getLast() == 0) { + int geometry = m_shape.getFirstGeometry(); + int geometryID = getGeometryID(geometry); + setChainParentage_(edgeChain, geometryID); + } + } else { + if (windingStack.getLast() != 0) { + int geometry = m_shape.getFirstGeometry(); + int geometryID = getGeometryID(geometry); + setChainParentage_(edgeChain, geometryID); + } + } + } + + void propagate_parentage_alternate_(Treap aet, int treeNode, int edge, + int leftEdge, int twinEdge, int edgeChain, int edgeChainParent, + int twinHalfEdgeChain) { + // Now do specific sweep calculations + // This one is done when we are doing a topological operation. + int geometry = m_shape.getFirstGeometry(); + int geometryID = getGeometryID(geometry); + + if (leftEdge == -1) { + // no left edge neighbour means the twin chain is surrounded by the + // universe + assert (getChainParent(twinHalfEdgeChain) == m_universeChain); + assert (getChainParentage(twinHalfEdgeChain) == 0 || getChainParentage(twinHalfEdgeChain) == m_universe_geomID); + assert (getChainParentage(edgeChain) == 0); + setChainParentage_(twinHalfEdgeChain, m_universe_geomID); + int parity = getHalfEdgeUserIndex(edge, + m_tmpHalfEdgeOddEvenNumberIndex); + if ((parity & 1) != 0) + setChainParentage_(edgeChain, geometryID);// set the parenentage + // from the parity + else + setChainParentage_(edgeChain, m_universe_geomID);// this chain + // does not + // belong to + // geometry + } else { + int twin_parentage = getChainParentage(twinHalfEdgeChain); + if (twin_parentage == 0) { + int leftEdgeChain = getHalfEdgeChain(leftEdge); + int left_parentage = getChainParentage(leftEdgeChain); + setChainParentage_(twinHalfEdgeChain, left_parentage); + int parity = getHalfEdgeUserIndex(edge, + m_tmpHalfEdgeOddEvenNumberIndex); + if ((parity & 1) != 0) + setChainParentage_(edgeChain, + (left_parentage == geometryID) ? m_universe_geomID + : geometryID); + else + setChainParentage_(edgeChain, left_parentage); + + } else { + int parity = getHalfEdgeUserIndex(edge, + m_tmpHalfEdgeOddEvenNumberIndex); + if ((parity & 1) != 0) + setChainParentage_(edgeChain, + (twin_parentage == geometryID) ? m_universe_geomID + : geometryID); + else + setChainParentage_(edgeChain, twin_parentage); + } + + } + } + + boolean tryOptimizedInsertion_(Treap aet, int treeNodeIndex, + AttributeStreamOfInt32 new_edges, int cluster, int firstHalfEdge) { + int clusterHalfEdge = firstHalfEdge; + int attachedTreeNode = -1; + int newEdge = -1; + // Delete all edges that end at the cluster. + int count = 0; + do { + if (count == 2) + return false; + int n = getHalfEdgeUserIndex(clusterHalfEdge, treeNodeIndex); + if (n != -1) { + if (attachedTreeNode != -1) + return false;// two edges end at the cluster + attachedTreeNode = n; + } else { + if (newEdge != -1) + return false; // two edges start from the cluster + newEdge = clusterHalfEdge; + } + assert (getHalfEdgeOrigin(clusterHalfEdge) == cluster); + count++; + clusterHalfEdge = getHalfEdgeNext(getHalfEdgeTwin(clusterHalfEdge)); + } while (firstHalfEdge != clusterHalfEdge); + + if (newEdge == -1 || attachedTreeNode == -1) + return false; + + setHalfEdgeUserIndex(aet.getElement(attachedTreeNode), treeNodeIndex, + StridedIndexTypeCollection.impossibleIndex2()); + aet.setElement(attachedTreeNode, newEdge); + new_edges.add(attachedTreeNode); + return true; + } + + boolean trySetChainParentFromTwin_(int chainToSet, int twinChain) { + assert (getChainParent(chainToSet) == -1); + double area = getChainArea(chainToSet); + if (area == 0) + return false; + double twinArea = getChainArea(twinChain); + assert (twinArea != 0); + if (area > 0 && twinArea < 0) { + setChainParent_(chainToSet, twinChain); + return true; + } + if (area < 0 && twinArea > 0) { + setChainParent_(chainToSet, twinChain); + return true; + } else { + int twinParent = getChainParent(twinChain); + if (twinParent != -1) { + setChainParent_(chainToSet, twinParent); + return true; + } + } + + return false; + } + + void createHalfEdges_(int inputMode, AttributeStreamOfInt32 sorted_vertices) { + // After this loop all halfedges will be created. + // This loop also sets the known parentage on the edges. + // The half edges are connected with each other in a random order + m_halfEdgeIndex = m_shape.createUserIndex(); + + for (int i = 0, nvert = sorted_vertices.size(); i < nvert; i++) { + int vertex = sorted_vertices.get(i); + int cluster = m_shape.getUserIndex(vertex, m_clusterIndex); + + int path = m_shape.getPathFromVertex(vertex); + int geometry = m_shape.getGeometryFromPath(path); + int gt = m_shape.getGeometryType(geometry); + if (Geometry.isMultiPath(gt)) { + int next = m_shape.getNextVertex(vertex); + if (next == -1) + continue; + + int clusterTo = m_shape.getUserIndex(next, m_clusterIndex); + assert (clusterTo != -1); + if (cluster == clusterTo) { + if (m_shape.getSegment(vertex) != null) { + assert (m_shape.getSegment(vertex).calculateLength2D() == 0); + } else { + assert (m_shape.getXY(vertex).isEqual(m_shape.getXY(next))); + } + + continue; + } + + int half_edge = newHalfEdgePair_(); + int twinEdge = getHalfEdgeTwin(half_edge); + + // add vertex to the half edge. + int vertIndex = m_clusterVertices.newElement(); + m_clusterVertices.setField(vertIndex, 0, vertex); + m_clusterVertices.setField(vertIndex, 1, -1); + setHalfEdgeVertexIterator_(half_edge, vertIndex); + + setHalfEdgeOrigin_(half_edge, cluster); + int firstHalfEdge = getClusterHalfEdge(cluster); + if (firstHalfEdge == -1) { + setClusterHalfEdge_(cluster, half_edge); + setHalfEdgePrev_(half_edge, twinEdge); + setHalfEdgeNext_(twinEdge, half_edge); + } else { + // It does not matter what order we insert the new edges in. + // We fix the order later. + int firstPrev = getHalfEdgePrev(firstHalfEdge); + assert (getHalfEdgeNext(firstPrev) == firstHalfEdge); + setHalfEdgePrev_(firstHalfEdge, twinEdge); + setHalfEdgeNext_(twinEdge, firstHalfEdge); + assert (getHalfEdgePrev(firstHalfEdge) == twinEdge); + assert (getHalfEdgeNext(twinEdge) == firstHalfEdge); + setHalfEdgeNext_(firstPrev, half_edge); + setHalfEdgePrev_(half_edge, firstPrev); + assert (getHalfEdgePrev(half_edge) == firstPrev); + assert (getHalfEdgeNext(firstPrev) == half_edge); + } + + setHalfEdgeOrigin_(twinEdge, clusterTo); + int firstTo = getClusterHalfEdge(clusterTo); + if (firstTo == -1) { + setClusterHalfEdge_(clusterTo, twinEdge); + setHalfEdgeNext_(half_edge, twinEdge); + setHalfEdgePrev_(twinEdge, half_edge); + } else { + int firstToPrev = getHalfEdgePrev(firstTo); + assert (getHalfEdgeNext(firstToPrev) == firstTo); + setHalfEdgePrev_(firstTo, half_edge); + setHalfEdgeNext_(half_edge, firstTo); + assert (getHalfEdgePrev(firstTo) == half_edge); + assert (getHalfEdgeNext(half_edge) == firstTo); + setHalfEdgeNext_(firstToPrev, twinEdge); + setHalfEdgePrev_(twinEdge, firstToPrev); + assert (getHalfEdgePrev(twinEdge) == firstToPrev); + assert (getHalfEdgeNext(firstToPrev) == twinEdge); + } + + int geometryID = getGeometryID(geometry); + // No chains yet exists, so we use a temporary user index to + // store chain parentage. + // The input polygons has been already simplified so their edges + // directed such that the hole is to the left from the edge + // (each edge is directed from the "from" to "to" point). + if (inputMode == EnumInputMode.enumInputModeBuildGraph) { + setHalfEdgeUserIndex(twinEdge, m_tmpHalfEdgeParentageIndex, + 0); // Hole is always to the left. left side here is + // the twin. + setHalfEdgeUserIndex(half_edge, + m_tmpHalfEdgeParentageIndex, + gt == Geometry.GeometryType.Polygon ? geometryID + : 0); + } else if (inputMode == EnumInputMode.enumInputModeSimplifyWinding) { + Point2D pt_1 = new Point2D(); + m_shape.getXY(vertex, pt_1); + Point2D pt_2 = new Point2D(); + m_shape.getXY(next, pt_2); + int windingNumber = 0; + int windingNumberTwin = 0; + if (pt_1.compare(pt_2) < 0) { + // The edge is directed bottom-up. That means it has the + // winding number of +1. + // The half-edge direction coincides with the edge + // direction. THe twin is directed top-down. + // The half edge will have the winding number of 1 and + // its twin the winding number of 0. + // When crossing the half-edge/twin pair from left to + // right, the winding number is changed by +1 + windingNumber = 1; + } else { + // The edge is directed top-down. That means it has the + // winding number of -1. + // The half-edge direction coincides with the edge + // direction. The twin is directed bottom-up. + // The half edge will have the winding number of 0 and + // its twin the winding number of -1. + // When crossing the half-edge/twin pair from left to + // right, the winding number is changed by -1. + windingNumberTwin = -1; + } + + // When we get a half-edge/twin pair, we can determine the + // winding number of the underlying edge + // by summing up the half-edge and twin's + // winding numbers. + + setHalfEdgeUserIndex(twinEdge, m_tmpHalfEdgeParentageIndex, + 0); + setHalfEdgeUserIndex(half_edge, + m_tmpHalfEdgeParentageIndex, 0); + // We split the winding number between the half edge and its + // twin. + // This allows us to determine which half edge goes in the + // direction of the edge, and also it allows to calculate + // the + // winging number by summing up the winding number of half + // edge and its twin. + setHalfEdgeUserIndex(half_edge, + m_tmpHalfEdgeWindingNumberIndex, windingNumber); + setHalfEdgeUserIndex(twinEdge, + m_tmpHalfEdgeWindingNumberIndex, windingNumberTwin); + } else if (inputMode == EnumInputMode.enumInputModeIsSimplePolygon) { + setHalfEdgeUserIndex(twinEdge, m_tmpHalfEdgeParentageIndex, + m_universe_geomID); + setHalfEdgeUserIndex(half_edge, + m_tmpHalfEdgeParentageIndex, + gt == Geometry.GeometryType.Polygon ? geometryID + : 0); + } else if (inputMode == EnumInputMode.enumInputModeSimplifyAlternate) { + setHalfEdgeUserIndex(twinEdge, m_tmpHalfEdgeParentageIndex, + 0); + setHalfEdgeUserIndex(half_edge, + m_tmpHalfEdgeParentageIndex, 0); + setHalfEdgeUserIndex(half_edge, + m_tmpHalfEdgeOddEvenNumberIndex, 1); + setHalfEdgeUserIndex(twinEdge, + m_tmpHalfEdgeOddEvenNumberIndex, 1); + } + + int edgeBit = gt == Geometry.GeometryType.Polygon ? c_edgeBitMask + : 0; + setHalfEdgeParentage_(half_edge, geometryID | edgeBit); + setHalfEdgeParentage_(twinEdge, geometryID | edgeBit); + } + } + } + + void mergeVertexListsOfEdges_(int eDst, int eSrc) { + assert (getHalfEdgeTo(eDst) == getHalfEdgeTo(eSrc)); + assert (getHalfEdgeOrigin(eDst) == getHalfEdgeOrigin(eSrc)); + + { + int vertFirst2 = getHalfEdgeVertexIterator(eSrc); + if (vertFirst2 != -1) { + int vertFirst1 = getHalfEdgeVertexIterator(eDst); + m_clusterVertices.setField(vertFirst2, 1, vertFirst1); + setHalfEdgeVertexIterator_(eDst, vertFirst2); + setHalfEdgeVertexIterator_(eSrc, -1); + } + } + + int eDstTwin = getHalfEdgeTwin(eDst); + int eSrcTwin = getHalfEdgeTwin(eSrc); + { + int vertFirst2 = getHalfEdgeVertexIterator(eSrcTwin); + if (vertFirst2 != -1) { + int vertFirst1 = getHalfEdgeVertexIterator(eDstTwin); + m_clusterVertices.setField(vertFirst2, 1, vertFirst1); + setHalfEdgeVertexIterator_(eDstTwin, vertFirst2); + setHalfEdgeVertexIterator_(eSrcTwin, -1); + } + } + } + + void sortHalfEdgesByAngle_(int inputMode) { + AttributeStreamOfInt32 angleSorter = new AttributeStreamOfInt32(0); + angleSorter.reserve(10); + TopoGraphAngleComparer tgac = new TopoGraphAngleComparer(this); + // Now go through the clusters, sort edges in each cluster by angle, and + // reconnect the halfedges of sorted edges in the sorted order. + // Also share the parentage information between coinciding edges and + // remove duplicates. + for (int cluster = getFirstCluster(); cluster != -1; cluster = getNextCluster(cluster)) { + angleSorter.clear(false); + int first = getClusterHalfEdge(cluster); + if (first != -1) { + // 1. sort edges originating at the cluster by angle (counter - + // clockwise). + int edge = first; + do { + angleSorter.add(edge);// edges have the cluster in their + // origin and are directed away from + // it. The twin edges are directed + // towards the cluster. + edge = getHalfEdgeNext(getHalfEdgeTwin(edge)); + } while (edge != first); + + if (angleSorter.size() > 1) { + boolean changed_order = true; + if (angleSorter.size() > 2) { + angleSorter.Sort(0, angleSorter.size(), + tgac); // std::sort(angleSorter.get_ptr(), + // angleSorter.get_ptr() + // + + // angleSorter.size(), + // TopoGraphAngleComparer(this)); + angleSorter.add(angleSorter.get(0)); + } else { + //no need to sort most two edge cases. we only need to make sure that edges going up are sorted + if (compareEdgeAnglesForPair_(angleSorter.get(0), + angleSorter.get(1)) > 0) { + int tmp = angleSorter.get(0); + angleSorter.set(0, angleSorter.get(1)); + angleSorter.set(1, tmp); + } else { + changed_order = false; + } + } + // 2. get rid of duplicate edges by merging them (duplicate + // edges appear at this step because we converted all + // segments into the edges, including overlapping). + int e0 = angleSorter.get(0); + int ePrev = e0; + int ePrevTo = getHalfEdgeTo(ePrev); + int ePrevTwin = getHalfEdgeTwin(ePrev); + int prevMerged = -1; + for (int i = 1, n = angleSorter.size(); i < n; i++) { + int e = angleSorter.get(i); + int eTwin = getHalfEdgeTwin(e); + int eTo = getHalfEdgeOrigin(eTwin); + assert (getHalfEdgeOrigin(e) == getHalfEdgeOrigin(ePrev));// e + // origin + // and + // ePrev + // origin + // are + // equal + // by + // definition + // (e + // and + // ePrev + // emanate + // from + // the + // same + // cluster) + if (eTo == ePrevTo && e != ePrev)// e's To cluster and + // ePrev's To + // cluster are + // equal, means the + // edges coincide + // and need to be + // merged. + {// remove duplicate edge. Before removing, propagate + // the parentage to the remaning edge + if (inputMode == EnumInputMode.enumInputModeBuildGraph) { + int newEdgeParentage = getHalfEdgeParentageMask_(ePrev) + | getHalfEdgeParentageMask_(e); + setHalfEdgeParentage_(ePrev, newEdgeParentage); + setHalfEdgeParentage_(ePrevTwin, + newEdgeParentage); + assert (getHalfEdgeParentageMask_(ePrev) == getHalfEdgeParentageMask_(ePrevTwin)); + + setHalfEdgeUserIndex( + ePrev, + m_tmpHalfEdgeParentageIndex, + getHalfEdgeUserIndex(ePrev, + m_tmpHalfEdgeParentageIndex) + | getHalfEdgeUserIndex(e, + m_tmpHalfEdgeParentageIndex)); + setHalfEdgeUserIndex( + ePrevTwin, + m_tmpHalfEdgeParentageIndex, + getHalfEdgeUserIndex(ePrevTwin, + m_tmpHalfEdgeParentageIndex) + | getHalfEdgeUserIndex(eTwin, + m_tmpHalfEdgeParentageIndex)); + } else if (m_tmpHalfEdgeWindingNumberIndex != -1) { + // when doing simplify the + // m_tmpHalfEdgeWindingNumberIndex contains the + // winding number. + // When edges are merged their winding numbers + // are added. + int newHalfEdgeWinding = getHalfEdgeUserIndex( + ePrev, m_tmpHalfEdgeWindingNumberIndex) + + getHalfEdgeUserIndex(e, + m_tmpHalfEdgeWindingNumberIndex); + int newTwinEdgeWinding = getHalfEdgeUserIndex( + ePrevTwin, + m_tmpHalfEdgeWindingNumberIndex) + + getHalfEdgeUserIndex(eTwin, + m_tmpHalfEdgeWindingNumberIndex); + setHalfEdgeUserIndex(ePrev, + m_tmpHalfEdgeWindingNumberIndex, + newHalfEdgeWinding); + setHalfEdgeUserIndex(ePrevTwin, + m_tmpHalfEdgeWindingNumberIndex, + newTwinEdgeWinding); + // The winding number of an edge is a sum of the + // winding numbers of the half edge and its + // twin. + // To determine which half edge direction + // coincides with the edge direction, determine + // which half edge has larger abs value of + // winding number. If half edge and twin winding + // numbers cancel each other, the edge winding + // number is zero, meaning there are + // even number of edges coinciding there and + // half of them has opposite direction to + // another half. + } else if (inputMode == EnumInputMode.enumInputModeIsSimplePolygon) { + m_non_simple_result = new NonSimpleResult(NonSimpleResult.Reason.CrossOver, cluster, -1); + return; + } else if (m_tmpHalfEdgeOddEvenNumberIndex != -1) { + int newHalfEdgeWinding = getHalfEdgeUserIndex( + ePrev, m_tmpHalfEdgeOddEvenNumberIndex) + + getHalfEdgeUserIndex(e, + m_tmpHalfEdgeOddEvenNumberIndex); + int newTwinEdgeWinding = getHalfEdgeUserIndex( + ePrevTwin, + m_tmpHalfEdgeOddEvenNumberIndex) + + getHalfEdgeUserIndex(eTwin, + m_tmpHalfEdgeOddEvenNumberIndex); + setHalfEdgeUserIndex(ePrev, + m_tmpHalfEdgeOddEvenNumberIndex, + newHalfEdgeWinding); + setHalfEdgeUserIndex(ePrevTwin, + m_tmpHalfEdgeOddEvenNumberIndex, + newTwinEdgeWinding); + } + + mergeVertexListsOfEdges_(ePrev, e); + deleteEdgeImpl_(e); + assert (n < 3 || e0 == angleSorter.getLast()); + prevMerged = ePrev; + angleSorter.set(i, -1); + if (e == e0) { + angleSorter.set(0, -1); + e0 = -1; + } + + continue; + } else { + //edges do not coincide + } + + updateVertexToHalfEdgeConnection_(prevMerged, false); + prevMerged = -1; + ePrev = e; + ePrevTo = eTo; + ePrevTwin = eTwin; + } + + + updateVertexToHalfEdgeConnection_(prevMerged, false); + prevMerged = -1; + + if (!changed_order) { + //small optimization to avoid reconnecting if nothing changed + e0 = -1; + for (int i = 0, n = angleSorter.size(); i < n; i++) { + int e = angleSorter.get(i); + if (e == -1) + continue; + e0 = e; + break; + } + + if (first != e0) + setClusterHalfEdge_(cluster, e0); + + continue; //next cluster + } + + + // 3. Reconnect edges in the sorted order. The edges are + // sorted counter clockwise. + // We connect them such that every right turn is made in the + // clockwise order. + // This guarantees that the smallest faces are clockwise. + e0 = -1; + for (int i = 0, n = angleSorter.size(); i < n; i++) { + int e = angleSorter.get(i); + if (e == -1) + continue; + if (e0 == -1) { + e0 = e; + ePrev = e0; + ePrevTo = getHalfEdgeTo(ePrev); + ePrevTwin = getHalfEdgeTwin(ePrev); + continue; + } + + if (e == ePrev) { + // This condition can only happen if all edges in + // the bunch coincide. + assert (i == n - 1); + continue; + } + + int eTwin = getHalfEdgeTwin(e); + int eTo = getHalfEdgeOrigin(eTwin); + assert (getHalfEdgeOrigin(e) == getHalfEdgeOrigin(ePrev)); + assert (eTo != ePrevTo); + setHalfEdgeNext_(ePrevTwin, e); + setHalfEdgePrev_(e, ePrevTwin); + ePrev = e; + ePrevTo = eTo; + ePrevTwin = eTwin; + if (inputMode == EnumInputMode.enumInputModeIsSimplePolygon) { + int par1 = getHalfEdgeUserIndex(e, m_tmpHalfEdgeParentageIndex) | + getHalfEdgeUserIndex(getHalfEdgePrev(e), m_tmpHalfEdgeParentageIndex); + if (par1 == (m_universe_geomID | 1)) { + //violation of face parentage + m_non_simple_result = new NonSimpleResult(NonSimpleResult.Reason.CrossOver, cluster, -1); + return; + } + } + + } + + setClusterHalfEdge_(cluster, e0);// smallest angle goes + // first. + } + } + } + } + + void buildChains_(int inputMode) { + // Creates chains and puts them in the list of chains. + // Does not set the chain parentage + // Does not connect chains + + int firstChain = -1; + int visitedHalfEdgeIndex = createUserIndexForHalfEdges(); + // Visit all the clusters + for (int cluster = getFirstCluster(); cluster != -1; cluster = getNextCluster(cluster)) { + // For each cluster visit all half edges on the cluster + int first = getClusterHalfEdge(cluster); + if (first != -1) { + int edge = first; + do { + if (getHalfEdgeUserIndex(edge, visitedHalfEdgeIndex) != 1)// check + // if + // we + // have + // visited + // this + // halfedge + // already + {// if we have not visited this halfedge yet, then we have + // not created a chain for it yet. + int chain = newChain_();// new chain's parentage is set + // to 0. + setChainHalfEdge_(chain, edge);// Note, the half-edge's + // Origin is the lowest + // point of the chain. + setChainNext_(chain, firstChain);// add the new chain to + // the list of + // chains. + if (firstChain != -1) { + setChainPrev_(firstChain, chain); + } + firstChain = chain; + // go thorough all halfedges until return back to the + // same one. Thus forming a chain. + int parentage = 0; + int e = edge; + do { + // accumulate chain parentage from all the chain + // edges m_tmpHalfEdgeParentageIndex. + parentage |= getHalfEdgeUserIndex(e, + m_tmpHalfEdgeParentageIndex); + assert (getHalfEdgeUserIndex(e, + visitedHalfEdgeIndex) != 1); + setHalfEdgeChain_(e, chain); + setHalfEdgeUserIndex(e, visitedHalfEdgeIndex, 1);// mark + // the + // edge + // visited. + e = getHalfEdgeNext(e); + } while (e != edge); + + assert (inputMode != EnumInputMode.enumInputModeIsSimplePolygon || parentage != (1 | m_universe_geomID)); + + setChainParentage_(chain, parentage); + } + + edge = getHalfEdgeNext(getHalfEdgeTwin(edge));// next + // halfedge + // on the + // cluster + } while (edge != first); + } + } + + // add the Universe chain. We want it to be the one that getFirstChain + // returns. + int chain = newChain_(); + setChainHalfEdge_(chain, -1); + setChainNext_(chain, firstChain); + if (firstChain != -1) + setChainPrev_(firstChain, chain); + + m_universeChain = chain; + + m_chainAreas = new AttributeStreamOfDbl(m_chainData.size(), + NumberUtils.TheNaN); + m_chainPerimeters = new AttributeStreamOfDbl(m_chainData.size(), + NumberUtils.TheNaN); + + setChainArea_(m_universeChain, NumberUtils.positiveInf());// the + // Universe + // is + // infinite + setChainPerimeter_(m_universeChain, NumberUtils.positiveInf());// the + // Universe + // is + // infinite + + deleteUserIndexForHalfEdges(visitedHalfEdgeIndex); + } + + void simplify_(int inputMode) { + if (inputMode == EnumInputMode.enumInputModeSimplifyAlternate) { + simplifyAlternate_(); + } else if (inputMode == EnumInputMode.enumInputModeSimplifyWinding) { + simplifyWinding_(); + } + } + + void simplifyAlternate_() { + //there is nothing to do + } + + void simplifyWinding_() { + //there is nothing to do + } + + private int getFirstUnvisitedHalfEdgeOnCluster_(int cluster, int hintEdge, + int vistiedEdgesIndex) { + // finds first half edge which is unvisited (index is not set to 1. + // when hintEdge != -1, it is used to start going around the edges. + + int edge = hintEdge != -1 ? hintEdge : getClusterHalfEdge(cluster); + if (edge == -1) + return -1; + + int f = edge; + + while (true) { + int v = getHalfEdgeUserIndex(edge, vistiedEdgesIndex); + if (v != 1) { + return edge; + } + + int next = getHalfEdgeNext(getHalfEdgeTwin(edge)); + if (next == f) + return -1; + + edge = next; + } + } + + boolean removeSpikes_() { + boolean removed = false; + int visitedIndex = createUserIndexForHalfEdges(); + for (int cluster = getFirstCluster(); cluster != -1; cluster = getNextCluster(cluster)) { + int nextClusterEdge = -1; //a hint + while (true) { + int firstHalfEdge = getFirstUnvisitedHalfEdgeOnCluster_(cluster, nextClusterEdge, visitedIndex); + if (firstHalfEdge == -1) + break; + + nextClusterEdge = getHalfEdgeNext(getHalfEdgeTwin(firstHalfEdge)); + int faceHalfEdge = firstHalfEdge; + + while (true) { + int faceHalfEdgeNext = getHalfEdgeNext(faceHalfEdge); + int faceHalfEdgePrev = getHalfEdgePrev(faceHalfEdge); + int faceHalfEdgeTwin = getHalfEdgeTwin(faceHalfEdge); + + if (faceHalfEdgePrev == faceHalfEdgeTwin) { + deleteEdgeInternal_(faceHalfEdge); //deletes the edge and its twin + removed = true; + + if (nextClusterEdge == faceHalfEdge || nextClusterEdge == faceHalfEdgeTwin) + nextClusterEdge = -1; //deleted the hint edge + + if (faceHalfEdge == firstHalfEdge || faceHalfEdgePrev == firstHalfEdge) { + firstHalfEdge = faceHalfEdgeNext; + if (faceHalfEdge == firstHalfEdge || faceHalfEdgePrev == firstHalfEdge) { + //deleted all edges in a face + break; + } + + faceHalfEdge = faceHalfEdgeNext; + continue; + } + + } else { + setHalfEdgeUserIndex(faceHalfEdge, visitedIndex, 1); + } + + faceHalfEdge = faceHalfEdgeNext; + if (faceHalfEdge == firstHalfEdge) + break; + } + + } + } + + return removed; + } + + void setEditShapeImpl_(EditShape shape, int inputMode, + AttributeStreamOfInt32 editShapeGeometries, + ProgressTracker progress_tracker, boolean bBuildChains) { + assert (!m_dirty_check_failed); + assert (editShapeGeometries == null || editShapeGeometries.size() > 0); + + removeShape(); + m_buildChains = bBuildChains; + assert (m_shape == null); + m_shape = shape; + m_geometryIDIndex = m_shape.createGeometryUserIndex(); + // sort vertices lexicographically + // Firstly copy all vertices to an array. + AttributeStreamOfInt32 verticesSorter = new AttributeStreamOfInt32(0); + verticesSorter.reserve(editShapeGeometries != null ? m_shape + .getPointCount(editShapeGeometries.get(0)) : m_shape + .getTotalPointCount()); + int path_count = 0; + int geomID = 1; + {// scope + int geometry = editShapeGeometries != null ? editShapeGeometries + .get(0) : m_shape.getFirstGeometry(); + int ind = 1; + while (geometry != -1) { + m_shape.setGeometryUserIndex(geometry, m_geometryIDIndex, + geomID); + geomID = geomID << 1; + for (int path = m_shape.getFirstPath(geometry); path != -1; path = m_shape + .getNextPath(path)) { + int vertex = m_shape.getFirstVertex(path); + for (int index = 0, n = m_shape.getPathSize(path); index < n; index++) { + verticesSorter.add(vertex); + vertex = m_shape.getNextVertex(vertex); + } + } + + if (!Geometry.isPoint(m_shape.getGeometryType(geometry))) + path_count += m_shape.getPathCount(geometry); + + if (editShapeGeometries != null) { + geometry = ind < editShapeGeometries.size() ? editShapeGeometries + .get(ind) : -1; + ind++; + } else + geometry = m_shape.getNextGeometry(geometry); + } + } + + m_universe_geomID = geomID; + + m_pointCount = verticesSorter.size(); + + // sort + m_shape.sortVerticesSimpleByY_(verticesSorter, 0, m_pointCount); + + if (m_clusterVertices == null) { + m_clusterVertices = new StridedIndexTypeCollection(2); + m_clusterData = new StridedIndexTypeCollection(8); + m_halfEdgeData = new StridedIndexTypeCollection(8); + m_chainData = new StridedIndexTypeCollection(8); + } + + m_clusterVertices.setCapacity(m_pointCount); + + ProgressTracker.checkAndThrow(progress_tracker); + + m_clusterData.setCapacity(m_pointCount + 10);// 10 for some self + // intersections + m_halfEdgeData.setCapacity(2 * m_pointCount + 32); + m_chainData.setCapacity(Math.max((int) 32, path_count)); + + // create all clusters + assert (m_clusterIndex == -1);// cleanup was incorrect + m_clusterIndex = m_shape.createUserIndex(); + Point2D ptFirst = new Point2D(); + int ifirst = 0; + Point2D pt = new Point2D(); + ptFirst.setNaN(); + for (int i = 0; i <= m_pointCount; i++) { + if (i < m_pointCount) { + int vertex = verticesSorter.get(i); + m_shape.getXY(vertex, pt); + } else { + pt.setNaN();// makes it to go into the following "if" statement. + } + if (!ptFirst.isEqual(pt)) { + if (ifirst < i) { + int cluster = newCluster_(); + int vertFirst = -1; + int vert = -1; + for (int ind = ifirst; ind < i; ind++) { + vert = verticesSorter.get(ind); + m_shape.setUserIndex(vert, m_clusterIndex, cluster); + + // add vertex to the cluster's vertex list + int vertIndex = m_clusterVertices.newElement(); + m_clusterVertices.setField(vertIndex, 0, vert); + m_clusterVertices.setField(vertIndex, 1, vertFirst); + vertFirst = vertIndex; + + int path = m_shape.getPathFromVertex(vert); + int geometry = m_shape.getGeometryFromPath(path); + int geometryID = getGeometryID(geometry); + setClusterParentage_(cluster, + getClusterParentage(cluster) | geometryID); + } + setClusterVertexIterator_(cluster, vertFirst); + setClusterVertexIndex_(cluster, + m_shape.getVertexIndex(vert)); + + if (m_lastCluster != -1) + setNextCluster_(m_lastCluster, cluster); + + setPrevCluster_(cluster, m_lastCluster); + + m_lastCluster = cluster; + if (m_firstCluster == -1) + m_firstCluster = cluster; + } + ifirst = i; + ptFirst.setCoords(pt); + } + } + + ProgressTracker.checkAndThrow(progress_tracker); + + m_tmpHalfEdgeParentageIndex = createUserIndexForHalfEdges(); + if (inputMode == EnumInputMode.enumInputModeSimplifyWinding) { + m_tmpHalfEdgeWindingNumberIndex = createUserIndexForHalfEdges(); + } + + if (inputMode == EnumInputMode.enumInputModeSimplifyAlternate) { + m_tmpHalfEdgeOddEvenNumberIndex = createUserIndexForHalfEdges(); + } + + createHalfEdges_(inputMode, verticesSorter);// For each geometry produce + // clusters and half edges + + if (m_non_simple_result.m_reason != NonSimpleResult.Reason.NotDetermined) + return; + + sortHalfEdgesByAngle_(inputMode); + if (m_non_simple_result.m_reason != NonSimpleResult.Reason.NotDetermined) + return; + + if (!NumberUtils.isNaN(m_check_dirty_planesweep_tolerance)) { + if (!check_structure_after_dirty_sweep_())// checks the edges. + { + m_dirty_check_failed = true;// set m_dirty_check_failed when an + // issue is found. We'll rerun the + // planesweep using robust crack and + // cluster approach. + return; + } + } + + buildChains_(inputMode); + if (m_non_simple_result.m_reason != NonSimpleResult.Reason.NotDetermined) + return; + + deleteUserIndexForHalfEdges(m_tmpHalfEdgeParentageIndex); + m_tmpHalfEdgeParentageIndex = -1; + + if (m_buildChains) + planeSweepParentage_(inputMode, progress_tracker); + + + simplify_(inputMode); + } + + void deleteEdgeImpl_(int half_edge) { + int halfEdgeNext = getHalfEdgeNext(half_edge); + int halfEdgePrev = getHalfEdgePrev(half_edge); + int halfEdgeTwin = getHalfEdgeTwin(half_edge); + int halfEdgeTwinNext = getHalfEdgeNext(halfEdgeTwin); + int halfEdgeTwinPrev = getHalfEdgePrev(halfEdgeTwin); + + if (halfEdgeNext != halfEdgeTwin) { + setHalfEdgeNext_(halfEdgeTwinPrev, halfEdgeNext); + setHalfEdgePrev_(halfEdgeNext, halfEdgeTwinPrev); + } + + if (halfEdgePrev != halfEdgeTwin) { + setHalfEdgeNext_(halfEdgePrev, halfEdgeTwinNext); + setHalfEdgePrev_(halfEdgeTwinNext, halfEdgePrev); + } + + int cluster_1 = getHalfEdgeOrigin(half_edge); + int clusterFirstEdge1 = getClusterHalfEdge(cluster_1); + if (clusterFirstEdge1 == half_edge) { + if (halfEdgeTwinNext != half_edge) + setClusterHalfEdge_(cluster_1, halfEdgeTwinNext); + else + setClusterHalfEdge_(cluster_1, -1);// cluster has no more edges + } + + int cluster2 = getHalfEdgeOrigin(halfEdgeTwin); + int clusterFirstEdge2 = getClusterHalfEdge(cluster2); + if (clusterFirstEdge2 == halfEdgeTwin) { + if (halfEdgeNext != halfEdgeTwin) + setClusterHalfEdge_(cluster2, halfEdgeNext); + else + setClusterHalfEdge_(cluster2, -1);// cluster has no more edges + } + + m_halfEdgeData.deleteElement(half_edge); + m_halfEdgeData.deleteElement(halfEdgeTwin); + } + + int getLeftSkipPolylines_(Treap aet, int treeNode) { + int leftNode = treeNode; + + for (; ; ) { + leftNode = aet.getPrev(leftNode); + if (leftNode != -1) { + int e = aet.getElement(leftNode); + int leftChain = getHalfEdgeChain(e); + if (leftChain != getHalfEdgeChain(getHalfEdgeTwin(e))) { + return e; + } else { + // the left edge is a piece of polyline - does not + // contribute to the face parentage + } + } else { + return -1; + } + } + } + + TopoGraph() { + c_edgeParentageMask = ((int) -1) + ^ ((int) 1 << (NumberUtils.sizeOf((int) 0) * 8 - 1)); + c_edgeBitMask = (int) 1 << (NumberUtils.sizeOf((int) 0) * 8 - 1); + m_firstCluster = -1; + m_lastCluster = -1; + m_geometryIDIndex = -1; + m_clusterIndex = -1; + m_halfEdgeIndex = -1; + m_universeChain = -1; + m_tmpHalfEdgeParentageIndex = -1; + m_tmpHalfEdgeWindingNumberIndex = -1; + m_pointCount = 0; + } + + EditShape getShape() { + return m_shape; + } + + // Sets an edit shape. The geometry has to be cracked and clustered before + // calling this! + void setEditShape(EditShape shape, ProgressTracker progress_tracker) { + setEditShapeImpl_(shape, EnumInputMode.enumInputModeBuildGraph, null, + progress_tracker, true); + } + + void setEditShape(EditShape shape, ProgressTracker progress_tracker, boolean bBuildChains) { + setEditShapeImpl_(shape, EnumInputMode.enumInputModeBuildGraph, null, + progress_tracker, bBuildChains); + } + + void setAndSimplifyEditShapeAlternate(EditShape shape, int geometry, ProgressTracker progressTracker) { + AttributeStreamOfInt32 geoms = new AttributeStreamOfInt32(0); + geoms.add(geometry); + setEditShapeImpl_(shape, EnumInputMode.enumInputModeSimplifyAlternate, + geoms, progressTracker, shape.getGeometryType(geometry) == Geometry.Type.Polygon.value()); + } + + void setAndSimplifyEditShapeWinding(EditShape shape, int geometry, ProgressTracker progressTracker) { + AttributeStreamOfInt32 geoms = new AttributeStreamOfInt32(0); + geoms.add(geometry); + setEditShapeImpl_(shape, EnumInputMode.enumInputModeSimplifyWinding, + geoms, progressTracker, true); + } + + // Removes shape from the topograph and removes any user index created on + // the edit shape. + void removeShape() { + if (m_shape == null) + return; + + if (m_geometryIDIndex != -1) { + m_shape.removeGeometryUserIndex(m_geometryIDIndex); + m_geometryIDIndex = -1; + } + + if (m_clusterIndex != -1) { + m_shape.removeUserIndex(m_clusterIndex); + m_clusterIndex = -1; + } + + if (m_halfEdgeIndex != -1) { + m_shape.removeUserIndex(m_halfEdgeIndex); + m_halfEdgeIndex = -1; + } + + if (m_tmpHalfEdgeParentageIndex != -1) { + deleteUserIndexForHalfEdges(m_tmpHalfEdgeParentageIndex); + m_tmpHalfEdgeParentageIndex = -1; + } + + if (m_tmpHalfEdgeWindingNumberIndex != -1) { + deleteUserIndexForHalfEdges(m_tmpHalfEdgeWindingNumberIndex); + m_tmpHalfEdgeWindingNumberIndex = -1; + } + + if (m_tmpHalfEdgeOddEvenNumberIndex != -1) { + deleteUserIndexForHalfEdges(m_tmpHalfEdgeOddEvenNumberIndex); + m_tmpHalfEdgeOddEvenNumberIndex = -1; + } + + m_shape = null; + m_clusterData.deleteAll(true); + m_clusterVertices.deleteAll(true); + m_firstCluster = -1; + m_lastCluster = -1; + + if (m_halfEdgeData != null) + m_halfEdgeData.deleteAll(true); + if (m_edgeIndices != null) + m_edgeIndices.clear(); + if (m_clusterIndices != null) + m_clusterIndices.clear(); + if (m_chainIndices != null) + m_chainIndices.clear(); + if (m_chainData != null) + m_chainData.deleteAll(true); + m_universeChain = -1; + m_chainAreas = null; + } + + // Returns a half-edge emanating the cluster. All other half-edges can be + // visited with: + // incident_half_edge = getHalfEdgeTwin(half_edge);//get twin of the + // half_edge, it has the vertex as the end point. + // emanating_half_edge = getHalfEdgeTwin(incident_half_edge); //get next + // emanating half-edge + int getClusterHalfEdge(int cluster) { + return m_clusterData.getField(cluster, 2); + } + + // Returns the coordinates of the cluster + void getXY(int cluster, Point2D pt) { + int vindex = getClusterVertexIndex_(cluster); + m_shape.getXYWithIndex(vindex, pt); + } + + // Returns parentage mask of the cluster + int getClusterParentage(int cluster) { + return m_clusterData.getField(cluster, 1); + } + + // Returns first cluster in the Topo_graph (has lowest y, x coordinates). + int getFirstCluster() { + return m_firstCluster; + } + + // Returns previous cluster in the Topo_graph (in the sorted order of y,x + // coordinates). + int getPrevCluster(int cluster) { + return m_clusterData.getField(cluster, 3); + } + + // Returns next cluster in the Topo_graph (in the sorted order of y,x + // coordinates). + int getNextCluster(int cluster) { + return m_clusterData.getField(cluster, 4); + } + + // Returns an exterior chain of a face this cluster belongs to (belongs only + // to interior). set only for the clusters that are standalone clusters (do + // not have half-edges with them). + int getClusterChain(int cluster) { + return m_clusterData.getField(cluster, 6); + } + + // Returns iterator for cluster vertices + int getClusterVertexIterator(int cluster) { + return m_clusterData.getField(cluster, 7); + } + + // Increments iterator. Returns -1 if no more vertices in the cluster + int incrementVertexIterator(int vertexIterator) { + return m_clusterVertices.getField(vertexIterator, 1); + } + + // Dereference the iterator + int getVertexFromVertexIterator(int vertexIterator) { + return m_clusterVertices.getField(vertexIterator, 0); + } + + // Returns a user index value for the cluster. + int getClusterUserIndex(int cluster, int index) { + int i = getClusterIndex_(cluster); + AttributeStreamOfInt32 stream = m_clusterIndices.get(index); + if (stream.size() <= i) + return -1; + return stream.read(i); + } + + // Sets a user index value for the cluster. + void setClusterUserIndex(int cluster, int index, int value) { + int i = getClusterIndex_(cluster); + AttributeStreamOfInt32 stream = m_clusterIndices.get(index); + if (stream.size() <= i) + stream.resize(m_clusterData.size(), -1); + + stream.write(i, value); + } + + // Creates a new user index for the cluster. The index values are set to -1. + int createUserIndexForClusters() { + if (m_clusterIndices == null) { + m_clusterIndices = new ArrayList(3); + } + + AttributeStreamOfInt32 new_stream = new AttributeStreamOfInt32( + m_clusterData.capacity(), -1); + for (int i = 0, n = m_clusterIndices.size(); i < n; i++) { + if (m_clusterIndices.get(i) == null) { + m_clusterIndices.set(i, new_stream); + return i; + } + } + m_clusterIndices.add(new_stream); + return m_clusterIndices.size() - 1; + } + + // Deletes user index + void deleteUserIndexForClusters(int userIndex) { + assert (m_clusterIndices.get(userIndex) != null); + m_clusterIndices.set(userIndex, null); + } + + // Returns origin of this half edge. To get the other end: + // incident_half_edge = getHalfEdgeTwin(half_edge); + // edge_end_point = getHalfEdgeOrigin(incident_half_edge); + int getHalfEdgeOrigin(int half_edge) { + return m_halfEdgeData.getField(half_edge, 1); + } + + // Returns the to point of the half edge + int getHalfEdgeTo(int half_edge) { + return getHalfEdgeOrigin(getHalfEdgeTwin(half_edge)); + } + + // Twin of this halfedge, it has opposite direction and same endpoints + int getHalfEdgeTwin(int half_edge) { + return m_halfEdgeData.getField(half_edge, 4); + } + + // Returns previous halfedge. It ends, where this halfedge starts. + int getHalfEdgePrev(int half_edge) { + return m_halfEdgeData.getField(half_edge, 5); + } + + // Returns next halfedge. It starts, where this halfedge ends. + int getHalfEdgeNext(int half_edge) { + return m_halfEdgeData.getField(half_edge, 6); + } + + // Returns half edge chain. Chain is on the right from the halfedge + int getHalfEdgeChain(int half_edge) { + return m_halfEdgeData.getField(half_edge, 2); + } + + // Returns half edge chain parentage. The call is implemented as as + // getChainParentage(getHalfEdgeChain()); + int getHalfEdgeFaceParentage(int half_edge) { + return getChainParentage(m_halfEdgeData.getField(half_edge, 2)); + } + + // Returns iterator for cluster vertices + int getHalfEdgeVertexIterator(int half_edge) { + return m_halfEdgeData.getField(half_edge, 7); + } + + // Returns the coordinates of the origin of the half_edge + void getHalfEdgeFromXY(int half_edge, Point2D pt) { + getXY(getHalfEdgeOrigin(half_edge), pt); + } + + // Returns the coordinates of the end of the half_edge + void getHalfEdgeToXY(int half_edge, Point2D pt) { + getXY(getHalfEdgeTo(half_edge), pt); + } + + // Returns parentage mask of this halfedge. Parentage mask of halfedge and + // its twin are the same + int getHalfEdgeParentage(int half_edge) { + return m_halfEdgeData.getField(half_edge, 3) & c_edgeParentageMask; + } + + // Returns a user index value for the half edge + int getHalfEdgeUserIndex(int half_edge, int index) { + int i = getHalfEdgeIndex_(half_edge); + AttributeStreamOfInt32 stream = m_edgeIndices.get(index); + if (stream.size() <= i) + return -1; + + return stream.read(i); + } + + // Sets a user index value for a half edge + void setHalfEdgeUserIndex(int half_edge, int index, int value) { + int i = getHalfEdgeIndex_(half_edge); + AttributeStreamOfInt32 stream = m_edgeIndices.get(index); + if (stream.size() <= i) + stream.resize(m_halfEdgeData.size(), -1); + + stream.write(i, value); + } + + // create a new user index for half edges. The index values are set to -1. + int createUserIndexForHalfEdges() { + if (m_edgeIndices == null) + m_edgeIndices = new ArrayList(3); + + AttributeStreamOfInt32 new_stream = new AttributeStreamOfInt32( + m_halfEdgeData.capacity(), -1); + for (int i = 0, n = m_edgeIndices.size(); i < n; i++) { + if (m_edgeIndices.get(i) == null) { + m_edgeIndices.set(i, new_stream); + return i; + } + } + m_edgeIndices.add(new_stream); + return m_edgeIndices.size() - 1; + } + + // Deletes the given user index for half edges + void deleteUserIndexForHalfEdges(int userIndex) { + assert (m_edgeIndices.get(userIndex) != null); + m_edgeIndices.set(userIndex, null); + } + + // Deletes the half_edge and it's twin. It works presently when removing a + // spike only. + // Returns next valid half-edge, or -1 if no more half edges. + // Use with care. + int deleteEdgeInternal_(int half_edge) { + int chain = getHalfEdgeChain(half_edge); + int halfEdgeTwin = getHalfEdgeTwin(half_edge); + int chainTwin = getHalfEdgeChain(halfEdgeTwin); + // This function only works for spikes. These two asserts check for that + assert (chainTwin == chain); + assert (half_edge == getHalfEdgeNext(halfEdgeTwin) || halfEdgeTwin == getHalfEdgeNext(half_edge)); + + int n = getHalfEdgeNext(half_edge); + if (n == halfEdgeTwin) { + n = getHalfEdgeNext(n); + if (n == half_edge) + n = -1; + } + + if (getChainHalfEdge(chain) == half_edge) { + setChainHalfEdge_(chain, n); + } + + int chainIndex = getChainIndex_(chain); + double v = m_chainAreas.read(chainIndex); + if (!NumberUtils.isNaN(v)) { + setChainArea_(chain, NumberUtils.TheNaN); + setChainPerimeter_(chain, NumberUtils.TheNaN); + } + + updateVertexToHalfEdgeConnection_(half_edge, true); + + deleteEdgeImpl_(half_edge);// does not change chain information + return n; + } + + // Deletes the halfEdges and their twin. The chains are broken after this + // call. + // For every chain the halfedges belong to, it will set the first edge to + // -1. + // However, the halfedge will still reference the chain so one can get the + // parentage information still. + void deleteEdgesBreakFaces_(AttributeStreamOfInt32 edgesToDelete) { + for (int i = 0, n = edgesToDelete.size(); i < n; i++) { + int half_edge = edgesToDelete.get(i); + int chain = getHalfEdgeChain(half_edge); + int halfEdgeTwin = getHalfEdgeTwin(half_edge); + int chainTwin = getHalfEdgeChain(halfEdgeTwin); + setChainHalfEdge_(chain, -1); + setChainHalfEdge_(chainTwin, -1); + updateVertexToHalfEdgeConnection_(half_edge, true); + deleteEdgeImpl_(half_edge); + } + } + + boolean doesHalfEdgeBelongToAPolygonInterior(int half_edge, int polygonId) { + // Half edge belongs to polygon interior if both it and its twin belong + // to boundary of faces that have the polygon parentage (the poygon both + // to the left and to the right of the edge). + int p_1 = getHalfEdgeFaceParentage(half_edge); + int p_2 = getHalfEdgeFaceParentage(getHalfEdgeTwin(half_edge)); + return (p_1 & polygonId) != 0 && (p_2 & polygonId) != 0; + } + + boolean doesHalfEdgeBelongToAPolygonExterior(int half_edge, int polygonId) { + // Half edge belongs to polygon interior if both it and its twin belong + // to boundary of faces that have the polygon parentage (the poygon both + // to the left and to the right of the edge). + int p_1 = getHalfEdgeFaceParentage(half_edge); + int p_2 = getHalfEdgeFaceParentage(getHalfEdgeTwin(half_edge)); + return (p_1 & polygonId) == 0 && (p_2 & polygonId) == 0; + } + + boolean doesHalfEdgeBelongToAPolygonBoundary(int half_edge, int polygonId) { + // Half edge overlaps polygon boundary + int p_1 = getHalfEdgeParentage(half_edge); + return (p_1 & polygonId) != 0; + } + + boolean doesHalfEdgeBelongToAPolylineInterior(int half_edge, int polylineId) { + // Half-edge belongs to a polyline interioir if it has the polyline + // parentage (1D intersection (aka overlap)). + int p_1 = getHalfEdgeParentage(half_edge); + if ((p_1 & polylineId) != 0) { + return true; + } + + return false; + } + + boolean doesHalfEdgeBelongToAPolylineExterior(int half_edge, int polylineId) { + // Half-edge belongs to a polyline Exterioir if it does not have the + // polyline parentage and both its clusters also do not have polyline's + // parentage (to exclude touch at point). + int p_1 = getHalfEdgeParentage(half_edge); + if ((p_1 & polylineId) == 0) { + int c = getHalfEdgeOrigin(half_edge); + int pc = getClusterParentage(c); + if ((pc & polylineId) == 0) { + c = getHalfEdgeTo(half_edge); + pc = getClusterParentage(c); + if ((pc & polylineId) == 0) { + return true; + } + } + } + + return false; + } + + boolean doesClusterBelongToAPolygonInterior(int cluster, int polygonId) { + // cluster belongs to a polygon interior when + // 1) It is a standalone cluster that has face parentage of this polygon + // GetClusterFaceParentage() + // 2) or It is a cluster with half edges attached and + // a) It is not on the polygon boundrary (get_cluster_parentage) + // b) Any half edge associated with it has face parentage of the polygon + // (get_half_edge_face_parentage(getClusterHalfEdge())) + + int chain = getClusterChain(cluster); + if (chain != -1) { + if ((getChainParentage(chain) & polygonId) != 0) { + return true; + } + } else { + int p_1 = getClusterParentage(cluster); + if ((p_1 & polygonId) == 0)// not on the polygon boundary + { + int half_edge = getClusterHalfEdge(cluster); + assert (half_edge != -1); + + int p_2 = getHalfEdgeFaceParentage(half_edge); + if ((p_2 & polygonId) != 0) { + return true; + } + } + } + + return false; + } + + boolean doesClusterBelongToAPolygonExterior(int cluster, int polygonId) { + int p_1 = getClusterParentage(cluster); + if ((p_1 & polygonId) == 0) { + return doesClusterBelongToAPolygonInterior(cluster, polygonId); + } + + return false; + } + + boolean doesClusterBelongToAPolygonBoundary(int cluster, int polygonId) { + int p_1 = getClusterParentage(cluster); + if ((p_1 & polygonId) != 0) { + return true; + } + + return false; + } + + // bool DoesClusterBelongToAPolylineInterioir(int cluster, int polylineId); + // bool does_cluster_belong_to_a_polyline_exterior(int cluster, int + // polylineId); + // bool does_cluster_belong_to_a_polyline_boundary(int cluster, int + // polylineId); + + // Returns the first chain, which is always the Universe chain. + int getFirstChain() { + return m_universeChain; + } + + // Returns the chain half edge. + int getChainHalfEdge(int chain) { + return m_chainData.getField(chain, 1); + } + + // Returns the chain's face parentage. That is the parentage of a face this + // chain borders with. + int getChainParentage(int chain) { + return m_chainData.getField(chain, 2); + } + + // Returns the parent of the chain (the chain, this chain is inside of). + int getChainParent(int chain) { + return m_chainData.getField(chain, 3); + } + + // Returns the first island chain in that chain. Island chains are always + // counterclockwise. + // Each island chain will have its complement chain, which is a chain of a + // twin of any halfedge of that chain. + int getChainFirstIsland(int chain) { + return m_chainData.getField(chain, 4); + } + + // Returns the first island chain in that chain. Island chains are always + // counterclockwise. + int getChainNextInParent(int chain) { + return m_chainData.getField(chain, 5); + } + + // Returns the next chain in arbitrary order. + int getChainNext(int chain) { + return m_chainData.getField(chain, 7); + } + + // Returns the area of the chain. The area does not include any islands. + // +Inf is returned for the universe chain. + double getChainArea(int chain) { + int chainIndex = getChainIndex_(chain); + double v = m_chainAreas.read(chainIndex); + if (NumberUtils.isNaN(v)) { + updateChainAreaAndPerimeter_(chain); + v = m_chainAreas.read(chainIndex); + } + + return v; + } + + // Returns the perimeter of the chain (> 0). +Inf is returned for the + // universe chain. + double getChainPerimeter(int chain) { + int chainIndex = getChainIndex_(chain); + double v = m_chainPerimeters.read(chainIndex); + if (NumberUtils.isNaN(v)) { + updateChainAreaAndPerimeter_(chain); + v = m_chainPerimeters.read(chainIndex); + } + + return v; + } + + // Returns a user index value for the chain. + int getChainUserIndex(int chain, int index) { + int i = getChainIndex_(chain); + AttributeStreamOfInt32 stream = m_chainIndices.get(index); + if (stream.size() <= i) + return -1; + return stream.read(i); + } + + // Sets a user index value for the chain. + void setChainUserIndex(int chain, int index, int value) { + int i = getChainIndex_(chain); + AttributeStreamOfInt32 stream = m_chainIndices.get(index); + if (stream.size() <= i) + stream.resize(m_chainData.size(), -1); + + stream.write(i, value); + } + + // Creates a new user index for the chains. The index values are set to -1. + int createUserIndexForChains() { + if (m_chainIndices == null) { + m_chainIndices = new ArrayList(3); + } + + AttributeStreamOfInt32 new_stream = new AttributeStreamOfInt32( + m_chainData.capacity(), -1); + for (int i = 0, n = m_chainIndices.size(); i < n; i++) { + if (m_chainIndices.get(i) == null) { + m_chainIndices.set(i, new_stream); + return i; + } + } + m_chainIndices.add(new_stream); + return m_chainIndices.size() - 1; + } + + // Deletes user index + void deleteUserIndexForChains(int userIndex) { + assert (m_chainIndices.get(userIndex) != null); + m_chainIndices.set(userIndex, null); + } + + // Returns geometry ID mask from the geometry handle. + // Topo_graph creates a user index for geometries in the shape, which exists + // until the topo graph is destroyed. + int getGeometryID(int geometry) { + return m_shape.getGeometryUserIndex(geometry, m_geometryIDIndex); + } + + // Returns cluster from vertex handle. + // Topo_graph creates a user index for vertices in the shape to hold cluster + // handles. The index exists until the topo graph is destroyed. + int getClusterFromVertex(int vertex) { + return m_shape.getUserIndex(vertex, m_clusterIndex); + } + + int getHalfEdgeFromVertex(int vertex) { + return m_shape.getUserIndex(vertex, m_halfEdgeIndex); + } + + // Finds an edge connecting the two clusters. Returns -1 if not found. + // Could be a slow operation when valency of each cluster is high. + int getHalfEdgeConnector(int clusterFrom, int clusterTo) { + int first_edge = getClusterHalfEdge(clusterFrom); + if (first_edge == -1) + return -1; + int edge = first_edge; + int firstEdgeTo = -1; + int eTo = -1; + // Doing two loops in parallel - one on the half-edges attached to the + // clusterFrom, another - attached to clusterTo. + do { + if (getHalfEdgeTo(edge) == clusterTo) + return edge; + + if (firstEdgeTo == -1) { + firstEdgeTo = getClusterHalfEdge(clusterTo); + if (firstEdgeTo == -1) + return -1; + eTo = firstEdgeTo; + } + + if (getHalfEdgeTo(eTo) == clusterFrom) { + edge = getHalfEdgeTwin(eTo); + assert (getHalfEdgeTo(edge) == clusterTo && getHalfEdgeOrigin(edge) == clusterFrom); + return edge; + } + + edge = getHalfEdgeNext(getHalfEdgeTwin(edge)); + eTo = getHalfEdgeNext(getHalfEdgeTwin(eTo)); + } while (edge != first_edge && eTo != firstEdgeTo); + + return -1; + } + + // Queries segment for the edge (only xy coordinates, no attributes) + void querySegmentXY(int half_edge, SegmentBuffer outBuffer) { + outBuffer.createLine(); + Segment seg = outBuffer.get(); + Point2D pt = new Point2D(); + getHalfEdgeFromXY(half_edge, pt); + seg.setStartXY(pt); + getHalfEdgeToXY(half_edge, pt); + seg.setEndXY(pt); + } + + int compareEdgeAngles_(int edge1, int edge2) { + if (edge1 == edge2) + return 0; + + Point2D pt_1 = new Point2D(); + getHalfEdgeToXY(edge1, pt_1); + + Point2D pt_2 = new Point2D(); + getHalfEdgeToXY(edge2, pt_2); + + if (pt_1.isEqual(pt_2)) + return 0;// overlap case + + Point2D pt10 = new Point2D(); + getHalfEdgeFromXY(edge1, pt10); + + Point2D v_1 = new Point2D(); + v_1.sub(pt_1, pt10); + Point2D v_2 = new Point2D(); + v_2.sub(pt_2, pt10); + int result = Point2D._compareVectors(v_1, v_2); + return result; + } + + int compareEdgeAnglesForPair_(int edge1, int edge2) { + if (edge1 == edge2) + return 0; + + Point2D pt_1 = new Point2D(); + getHalfEdgeToXY(edge1, pt_1); + + Point2D pt_2 = new Point2D(); + getHalfEdgeToXY(edge2, pt_2); + + if (pt_1.isEqual(pt_2)) + return 0;// overlap case + + Point2D pt10 = new Point2D(); + getHalfEdgeFromXY(edge1, pt10); + + Point2D v_1 = new Point2D(); + v_1.sub(pt_1, pt10); + Point2D v_2 = new Point2D(); + v_2.sub(pt_2, pt10); + + if (v_2.y >= 0 && v_1.y > 0) { + int result = Point2D._compareVectors(v_1, v_2); + return result; + } else { + return 0; + } + } + + boolean check_structure_after_dirty_sweep_() { + // for each cluster go through the cluster half edges and check that + // min(edge1_length, edge2_length) * angle_between is less than + // m_check_dirty_planesweep_tolerance. + // Doing this helps us weed out cases missed by the dirty plane sweep. + // We do not need absolute accuracy here. + assert (!m_dirty_check_failed); + assert (!NumberUtils.isNaN(m_check_dirty_planesweep_tolerance)); + double sqr_tol = MathUtils.sqr(m_check_dirty_planesweep_tolerance); + Point2D pt10 = new Point2D(); + Point2D pt_2 = new Point2D(); + Point2D pt_1 = new Point2D(); + Point2D v_1 = new Point2D(); + Point2D v_2 = new Point2D(); + for (int cluster = getFirstCluster(); cluster != -1; cluster = getNextCluster(cluster)) { + int first = getClusterHalfEdge(cluster); + if (first != -1) { + int edge = first; + getHalfEdgeFromXY(edge, pt10); + getHalfEdgeToXY(edge, pt_2); + v_2.sub(pt_2, pt10); + double sqr_len2 = v_2.sqrLength(); + + do { + int prev = edge; + edge = getHalfEdgeNext(getHalfEdgeTwin(edge)); + + if (edge != prev) { + getHalfEdgeToXY(edge, pt_1); + assert (!pt_1.isEqual(pt_2)); + v_1.sub(pt_1, pt10); + double sqr_len1 = v_1.sqrLength(); + + double cross = v_1.crossProduct(v_2); // cross_prod = + // len1 * len2 * + // sinA => sinA + // = cross_prod + // / (len1 * + // len2); + double sqr_sinA = (cross * cross) + / (sqr_len1 * sqr_len2); // sqr_sinA is + // approximately A^2 + // especially for + // smaller angles + double sqr_dist = Math.min(sqr_len1, sqr_len2) + * sqr_sinA; + if (sqr_dist <= sqr_tol) { + // these edges incident on the cluster form a narrow + // wedge and thei require cracking event that was + // missed. + return false; + } + + v_2.setCoords(v_1); + sqr_len2 = sqr_len1; + pt_2.setCoords(pt_1); + } + } while (edge != first); + } + } + + return true; + } } diff --git a/src/main/java/com/esri/core/geometry/TopologicalOperations.java b/src/main/java/com/esri/core/geometry/TopologicalOperations.java index 01e9e97f..b5b800c6 100644 --- a/src/main/java/com/esri/core/geometry/TopologicalOperations.java +++ b/src/main/java/com/esri/core/geometry/TopologicalOperations.java @@ -30,2126 +30,2126 @@ import java.util.ArrayList; final class TopologicalOperations { - TopoGraph m_topo_graph = null; - Point2D m_dummy_pt_1 = new Point2D(); - Point2D m_dummy_pt_2 = new Point2D(); - int m_from_edge_for_polylines; - boolean m_mask_lookup[] = null; - boolean m_bOGCOutput = false; - - boolean isGoodParentage(int parentage) { - return parentage < m_mask_lookup.length ? m_mask_lookup[parentage] - : false; - } - - void cut(int sideIndex, int cuttee, int cutter, - AttributeStreamOfInt32 cutHandles) { - int gtCuttee = m_topo_graph.getShape().getGeometryType(cuttee); - int gtCutter = m_topo_graph.getShape().getGeometryType(cutter); - int dimCuttee = Geometry.getDimensionFromType(gtCuttee); - int dimCutter = Geometry.getDimensionFromType(gtCutter); - - if (dimCuttee == 2 && dimCutter == 1) { - cutPolygonPolyline_(sideIndex, cuttee, cutter, cutHandles); - return; - } - - throw GeometryException.GeometryInternalError(); - } - - static final class CompareCuts extends IntComparator { - private EditShape m_editShape; - - public CompareCuts(EditShape editShape) { - m_editShape = editShape; - } - - @Override - public int compare(int c1, int c2) { - int path1 = m_editShape.getFirstPath(c1); - double area1 = m_editShape.getRingArea(path1); - int path2 = m_editShape.getFirstPath(c2); - double area2 = m_editShape.getRingArea(path2); - if (area1 < area2) - return -1; - if (area1 == area2) - return 0; - return 1; - } - } - - public TopologicalOperations() { - m_from_edge_for_polylines = -1; - } - - void setEditShape(EditShape shape, ProgressTracker progressTracker) { - if (m_topo_graph == null) - m_topo_graph = new TopoGraph(); - m_topo_graph.setEditShape(shape, progressTracker); - } - - void setEditShapeCrackAndCluster(EditShape shape, double tolerance, - ProgressTracker progressTracker) { - CrackAndCluster.execute(shape, tolerance, progressTracker, true); - for (int geometry = shape.getFirstGeometry(); geometry != -1; geometry = shape - .getNextGeometry(geometry)) { - if (shape.getGeometryType(geometry) == Geometry.Type.Polygon - .value()) - Simplificator.execute(shape, geometry, -1, m_bOGCOutput, progressTracker); - } - - setEditShape(shape, progressTracker); - } - - private void collectPolygonPathsPreservingFrom_(int geometryFrom, - int newGeometry, int visitedEdges, int visitedClusters, - int geometry_dominant) { - // This function tries to create polygon paths using the paths that were - // in the input shape. - // This way we preserve original shape as much as possible. - EditShape shape = m_topo_graph.getShape(); - if (shape.getGeometryType(geometryFrom) != Geometry.Type.Polygon - .value()) - return; - - for (int path = shape.getFirstPath(geometryFrom); path != -1; path = shape - .getNextPath(path)) { - int first_vertex = shape.getFirstVertex(path); - int firstCluster = m_topo_graph.getClusterFromVertex(first_vertex); - assert (firstCluster != -1); - int secondVertex = shape.getNextVertex(first_vertex); - int secondCluster = m_topo_graph.getClusterFromVertex(secondVertex); - assert (secondCluster != -1); - - int firstHalfEdge = m_topo_graph - .getHalfEdgeFromVertex(first_vertex); - - if (firstHalfEdge == -1) - continue;// Usually there will be a half-edge that starts at - // first_vertex and goes to secondVertex, but it - // could happen that this half edge has been - // removed. - - assert (m_topo_graph.getHalfEdgeTo(firstHalfEdge) == secondCluster && m_topo_graph - .getHalfEdgeOrigin(firstHalfEdge) == firstCluster); - - int visited = m_topo_graph.getHalfEdgeUserIndex(firstHalfEdge, - visitedEdges); - if (visited == 1 || visited == 2) - continue; - - int parentage = m_topo_graph - .getHalfEdgeFaceParentage(firstHalfEdge); - if (!isGoodParentage(parentage)) { - m_topo_graph.setHalfEdgeUserIndex(firstHalfEdge, visitedEdges, - 2); - continue; - } - - m_topo_graph.setHalfEdgeUserIndex(firstHalfEdge, visitedEdges, 1); - - int newPath = shape.insertPath(newGeometry, -1);// add new path at - // the end - int half_edge = firstHalfEdge; - int vertex = first_vertex; - int cluster = m_topo_graph.getClusterFromVertex(vertex); - int dir = 1; - //Walk the chain of half edges, preferably selecting vertices that belong to the - //polygon path we have started from. - do { - int vertex_dominant = getVertexByID_(vertex, geometry_dominant); - shape.addVertex(newPath, vertex_dominant); - if (visitedClusters != -1) - m_topo_graph.setClusterUserIndex(cluster, visitedClusters, - 1); - - m_topo_graph.setHalfEdgeUserIndex(half_edge, visitedEdges, 1); - half_edge = m_topo_graph.getHalfEdgeNext(half_edge); - int v; - int cv; - do {// move in a loop through coincident vertices (probably - // vertical segments). - v = dir == 1 ? shape.getNextVertex(vertex) : shape - .getPrevVertex(vertex);// if we came to the polyline - // tail, the next may return - // -1. - cv = v != -1 ? m_topo_graph.getClusterFromVertex(v) : -1; - } while (cv == cluster); - - int originCluster = m_topo_graph.getHalfEdgeOrigin(half_edge); - if (originCluster != cv) { - // try going opposite way - do {// move in a loop through coincident vertices (probably - // vertical segments). - v = dir == 1 ? shape.getPrevVertex(vertex) : shape - .getNextVertex(vertex);// if we came to the - // polyline tail, the - // next may return -1. - cv = v != -1 ? m_topo_graph.getClusterFromVertex(v) - : -1; - } while (cv == cluster); - - if (originCluster != cv) {// pick any vertex. - cv = originCluster; - int iterator = m_topo_graph - .getClusterVertexIterator(cv); - v = m_topo_graph.getVertexFromVertexIterator(iterator); - } else { - dir = -dir;// remember direction we were going for - // performance - } - } - cluster = cv; - vertex = v; - } while (half_edge != firstHalfEdge); - - shape.setClosedPath(newPath, true); - } - } - - // processes Topo_graph and removes edges that border faces with good - // parentage - // If bAllowBrokenFaces is True the function will break face structure for - // dissolved faces. Only face parentage will be uasable. - void dissolveCommonEdges_() { - int visitedEdges = m_topo_graph.createUserIndexForHalfEdges(); - AttributeStreamOfInt32 edgesToDelete = new AttributeStreamOfInt32(0); - // Now extract paths that - for (int cluster = m_topo_graph.getFirstCluster(); cluster != -1; cluster = m_topo_graph - .getNextCluster(cluster)) { - int firstHalfEdge = m_topo_graph.getClusterHalfEdge(cluster); - int half_edge = firstHalfEdge; - if (firstHalfEdge == -1) - continue; - - do { - int visited = m_topo_graph.getHalfEdgeUserIndex(half_edge, - visitedEdges); - if (visited != 1) { - int halfEdgeTwin = m_topo_graph.getHalfEdgeTwin(half_edge); - m_topo_graph.setHalfEdgeUserIndex(halfEdgeTwin, - visitedEdges, 1); - m_topo_graph.setHalfEdgeUserIndex(half_edge, visitedEdges, - 1); - int parentage = m_topo_graph - .getHalfEdgeFaceParentage(half_edge); - if (isGoodParentage(parentage)) { - int twinParentage = m_topo_graph - .getHalfEdgeFaceParentage(halfEdgeTwin); - if (isGoodParentage(twinParentage)) { - // This half_edge pair is a border between two faces - // that share the parentage or it is a dangling edge - edgesToDelete.add(half_edge);// remember for - // subsequent delete - } - } - } - - half_edge = m_topo_graph.getHalfEdgeNext(m_topo_graph - .getHalfEdgeTwin(half_edge)); - } while (half_edge != firstHalfEdge); - } - - m_topo_graph.deleteUserIndexForHalfEdges(visitedEdges); - m_topo_graph.deleteEdgesBreakFaces_(edgesToDelete); - } - - int getVertexByID_(int vertex, int geometry_id) { - if (geometry_id == -1) - return vertex; - - return getVertexByIDImpl_(vertex, geometry_id); - } - - int getVertexByIDImpl_(int vertex, int geometry_id) { - EditShape shape = m_topo_graph.getShape(); - int v; - int geometry; - int vertex_iterator = m_topo_graph - .getClusterVertexIterator(m_topo_graph - .getClusterFromVertex(vertex)); - - do { - v = m_topo_graph.getVertexFromVertexIterator(vertex_iterator); - geometry = shape.getGeometryFromPath(shape.getPathFromVertex(v)); - - if (geometry == geometry_id) - return v; - - vertex_iterator = m_topo_graph - .incrementVertexIterator(vertex_iterator); - } while (vertex_iterator != -1); - - return vertex; - } - - private int topoOperationPolygonPolygon_(int geometry_a, int geometry_b, - int geometry_dominant) { - dissolveCommonEdges_();// faces are partially broken after this call. - // See help to this call. - - EditShape shape = m_topo_graph.getShape(); - int newGeometry = shape.createGeometry(Geometry.Type.Polygon); - int visitedEdges = m_topo_graph.createUserIndexForHalfEdges(); - - topoOperationPolygonPolygonHelper_(geometry_a, geometry_b, newGeometry, - geometry_dominant, visitedEdges, -1); - - m_topo_graph.deleteUserIndexForHalfEdges(visitedEdges); - Simplificator.execute(shape, newGeometry, - MultiVertexGeometryImpl.GeometryXSimple.Weak, m_bOGCOutput, null); - return newGeometry; - } - - private void topoOperationPolygonPolygonHelper_(int geometry_a, - int geometry_b, int newGeometryPolygon, int geometry_dominant, - int visitedEdges, int visitedClusters) { - collectPolygonPathsPreservingFrom_(geometry_a, newGeometryPolygon, - visitedEdges, visitedClusters, geometry_dominant); - if (geometry_b != -1) - collectPolygonPathsPreservingFrom_(geometry_b, newGeometryPolygon, - visitedEdges, visitedClusters, geometry_dominant); - - EditShape shape = m_topo_graph.getShape(); - // Now extract polygon paths that has not been extracted on the previous - // step. - for (int cluster = m_topo_graph.getFirstCluster(); cluster != -1; cluster = m_topo_graph - .getNextCluster(cluster)) { - int firstHalfEdge = m_topo_graph.getClusterHalfEdge(cluster); - if (firstHalfEdge == -1) - continue; - - int half_edge = firstHalfEdge; - do { - int visited = m_topo_graph.getHalfEdgeUserIndex(half_edge, - visitedEdges); - if (visited != 1 && visited != 2) { - int parentage = m_topo_graph - .getHalfEdgeFaceParentage(half_edge); - if (isGoodParentage(parentage)) {// Extract face. - int newPath = shape.insertPath(newGeometryPolygon, -1);// add - // new - // path - // at - // the - // end - int faceHalfEdge = half_edge; - do { - int viter = m_topo_graph - .getHalfEdgeVertexIterator(faceHalfEdge); - int v; - if (viter != -1) { - v = m_topo_graph - .getVertexFromVertexIterator(viter); - } else { - int viter1 = m_topo_graph - .getHalfEdgeVertexIterator(m_topo_graph - .getHalfEdgeTwin(faceHalfEdge)); - assert (viter1 != -1); - v = m_topo_graph - .getVertexFromVertexIterator(viter1); - v = m_topo_graph.getShape().getNextVertex(v); - } - - assert (v != -1); - int vertex_dominant = getVertexByID_(v, - geometry_dominant); - shape.addVertex(newPath, vertex_dominant); - assert (isGoodParentage(m_topo_graph - .getHalfEdgeFaceParentage(faceHalfEdge))); - m_topo_graph.setHalfEdgeUserIndex(faceHalfEdge, - visitedEdges, 1);// - - if (visitedClusters != -1) { - int c = m_topo_graph - .getClusterFromVertex(vertex_dominant); - m_topo_graph.setClusterUserIndex(c, - visitedClusters, 1); - } - - faceHalfEdge = m_topo_graph - .getHalfEdgeNext(faceHalfEdge); - } while (faceHalfEdge != half_edge); - - shape.setClosedPath(newPath, true); - } else { - // cannot extract a face - m_topo_graph.setHalfEdgeUserIndex(half_edge, - visitedEdges, 2); - } - - } - - half_edge = m_topo_graph.getHalfEdgeNext(m_topo_graph - .getHalfEdgeTwin(half_edge)); - } while (half_edge != firstHalfEdge); - } - } - - int[] topoOperationPolygonPolygonEx_(int geometry_a, int geometry_b, - int geometry_dominant) { - EditShape shape = m_topo_graph.getShape(); - int newGeometryPolygon = shape.createGeometry(Geometry.Type.Polygon); - int newGeometryPolyline = shape.createGeometry(Geometry.Type.Polyline); - int newGeometryMultipoint = shape - .createGeometry(Geometry.Type.MultiPoint); - - dissolveCommonEdges_();// faces are partially broken after this call. - // See help to this call. - - int multipointPath = -1; - int visitedEdges = m_topo_graph.createUserIndexForHalfEdges(); - int visitedClusters = m_topo_graph.createUserIndexForClusters(); - - topoOperationPolygonPolygonHelper_(geometry_a, geometry_b, - newGeometryPolygon, geometry_dominant, visitedEdges, - visitedClusters); - - for (int cluster = m_topo_graph.getFirstCluster(); cluster != -1; cluster = m_topo_graph - .getNextCluster(cluster)) { - int firstHalfEdge = m_topo_graph.getClusterHalfEdge(cluster); - if (firstHalfEdge == -1) - continue; - - int half_edge = firstHalfEdge; - do { - int visited1 = m_topo_graph.getHalfEdgeUserIndex(half_edge, - visitedEdges); - int visited2 = m_topo_graph.getHalfEdgeUserIndex( - m_topo_graph.getHalfEdgeTwin(half_edge), visitedEdges); - int visited = visited1 | visited2; - if (visited == 2) { - int parentage = m_topo_graph - .getHalfEdgeParentage(half_edge); - if (isGoodParentage(parentage)) {// Extract face. - int newPath = shape.insertPath(newGeometryPolyline, -1);// add - // new - // path - // at - // the - // end - int polyHalfEdge = half_edge; - int vert = selectVertex_(cluster, shape); - assert (vert != -1); - int vertex_dominant = getVertexByID_(vert, - geometry_dominant); - shape.addVertex(newPath, vertex_dominant); - m_topo_graph.setClusterUserIndex(cluster, - visitedClusters, 1); - - do { - int clusterTo = m_topo_graph - .getHalfEdgeTo(polyHalfEdge); - int vert1 = selectVertex_(clusterTo, shape); - assert (vert1 != -1); - int vertex_dominant1 = getVertexByID_(vert1, - geometry_dominant); - shape.addVertex(newPath, vertex_dominant1); - m_topo_graph.setHalfEdgeUserIndex(polyHalfEdge, - visitedEdges, 1);// - m_topo_graph.setHalfEdgeUserIndex( - m_topo_graph.getHalfEdgeTwin(polyHalfEdge), - visitedEdges, 1);// - m_topo_graph.setClusterUserIndex(clusterTo, - visitedClusters, 1); - - polyHalfEdge = m_topo_graph - .getHalfEdgeNext(polyHalfEdge); - visited1 = m_topo_graph.getHalfEdgeUserIndex( - polyHalfEdge, visitedEdges); - visited2 = m_topo_graph.getHalfEdgeUserIndex( - m_topo_graph.getHalfEdgeTwin(polyHalfEdge), - visitedEdges); - visited = visited1 | visited2; - if (visited != 2) - break; - - parentage = m_topo_graph - .getHalfEdgeParentage(polyHalfEdge); - if (!isGoodParentage(parentage)) { - m_topo_graph.setHalfEdgeUserIndex(polyHalfEdge, - visitedEdges, 1); - m_topo_graph.setHalfEdgeUserIndex(m_topo_graph - .getHalfEdgeTwin(polyHalfEdge), - visitedEdges, 1); - break; - } - - } while (polyHalfEdge != half_edge); - - } else { - m_topo_graph.setHalfEdgeUserIndex(half_edge, - visitedEdges, 1); - m_topo_graph.setHalfEdgeUserIndex( - m_topo_graph.getHalfEdgeTwin(half_edge), - visitedEdges, 1); - } - } - - half_edge = m_topo_graph.getHalfEdgeNext(m_topo_graph - .getHalfEdgeTwin(half_edge)); - } while (half_edge != firstHalfEdge); - } - - for (int cluster = m_topo_graph.getFirstCluster(); cluster != -1; cluster = m_topo_graph - .getNextCluster(cluster)) { - int visited = m_topo_graph.getClusterUserIndex(cluster, - visitedClusters); - if (visited == 1) - continue; - - int parentage = m_topo_graph.getClusterParentage(cluster); - if (isGoodParentage(parentage)) { - if (multipointPath == -1) - multipointPath = shape - .insertPath(newGeometryMultipoint, -1); - int viter = m_topo_graph.getClusterVertexIterator(cluster); - int v; - if (viter != -1) { - v = m_topo_graph.getVertexFromVertexIterator(viter); - int vertex_dominant = getVertexByID_(v, geometry_dominant); - shape.addVertex(multipointPath, vertex_dominant); - } - } - } - - m_topo_graph.deleteUserIndexForClusters(visitedClusters); - m_topo_graph.deleteUserIndexForHalfEdges(visitedEdges); - Simplificator.execute(shape, newGeometryPolygon, - MultiVertexGeometryImpl.GeometryXSimple.Weak, m_bOGCOutput, null); - int[] result = new int[3];// always returns size 3 result. - - result[0] = newGeometryMultipoint; - result[1] = newGeometryPolyline; - result[2] = newGeometryPolygon; - return result; - } - - int selectVertex_(int cluster, EditShape shape) { - int vert = -1; - for (int iterator = m_topo_graph.getClusterVertexIterator(cluster); iterator != -1; iterator = m_topo_graph - .incrementVertexIterator(iterator)) { - int vertex = m_topo_graph.getVertexFromVertexIterator(iterator); - if (vert == -1) - vert = vertex; - int geometry = shape.getGeometryFromPath(shape - .getPathFromVertex(vertex)); - int geomID = m_topo_graph.getGeometryID(geometry); - if (isGoodParentage(geomID)) { - vert = vertex; - break; - } - } - - return vert; - } - - private double prevailingDirection_(EditShape shape, int half_edge) { - int cluster = m_topo_graph.getHalfEdgeOrigin(half_edge); - int clusterTo = m_topo_graph.getHalfEdgeTo(half_edge); - int signTotal = 0; - int signCorrect = 0; - for (int iterator = m_topo_graph.getClusterVertexIterator(cluster); iterator != -1; iterator = m_topo_graph - .incrementVertexIterator(iterator)) { - int vertex = m_topo_graph.getVertexFromVertexIterator(iterator); - int path = shape.getPathFromVertex(vertex); - int geometry = shape.getGeometryFromPath(path); - int geomID = m_topo_graph.getGeometryID(geometry); - int nextVert = shape.getNextVertex(vertex); - int prevVert = shape.getPrevVertex(vertex); - - int firstVert = shape.getFirstVertex(path); - if (firstVert == vertex) {// remember the first half edge of the - // path. We use it to produce correct - // startpath for closed polyline loops - m_from_edge_for_polylines = half_edge; - } - - if (nextVert != -1 - && m_topo_graph.getClusterFromVertex(nextVert) == clusterTo) { - signTotal++; - if (isGoodParentage(geomID)) { - if (firstVert == nextVert) {// remember the first vertex of - // the path. We use it to - // produce correct startpath for - // closed polyline loops - m_from_edge_for_polylines = m_topo_graph - .getHalfEdgeNext(half_edge); - } - - // update the sign - signCorrect++; - } - } else if (prevVert != -1 - && m_topo_graph.getClusterFromVertex(prevVert) == clusterTo) { - signTotal--; - if (isGoodParentage(geomID)) { - if (firstVert == prevVert) {// remember the first vertex of - // the path. We use it to - // produce correct startpath for - // closed polyline loops - m_from_edge_for_polylines = m_topo_graph - .getHalfEdgeNext(half_edge); - } - - // update the sign - signCorrect--; - } - } - } - - m_topo_graph.getXY(cluster, m_dummy_pt_1); - m_topo_graph.getXY(clusterTo, m_dummy_pt_2); - double len = Point2D.distance(m_dummy_pt_1, m_dummy_pt_2); - return (signCorrect != 0 ? signCorrect : signTotal) * len; - } - - int getCombinedHalfEdgeParentage_(int e) { - return m_topo_graph.getHalfEdgeParentage(e) - | m_topo_graph.getHalfEdgeFaceParentage(e) - | m_topo_graph.getHalfEdgeFaceParentage(m_topo_graph - .getHalfEdgeTwin(e)); - } - - int tryMoveThroughCrossroadBackwards_(int half_edge) { - int e = m_topo_graph.getHalfEdgeTwin(m_topo_graph - .getHalfEdgePrev(half_edge)); - int goodEdge = -1; - while (e != half_edge) { - int parentage = getCombinedHalfEdgeParentage_(e); - if (isGoodParentage(parentage)) { - if (goodEdge != -1) - return -1; - - goodEdge = e; - } - - e = m_topo_graph.getHalfEdgeTwin(m_topo_graph.getHalfEdgePrev(e)); - } - - return goodEdge != -1 ? m_topo_graph.getHalfEdgeTwin(goodEdge) : -1; - } - - int tryMoveThroughCrossroadForward_(int half_edge) { - int e = m_topo_graph.getHalfEdgeTwin(m_topo_graph - .getHalfEdgeNext(half_edge)); - int goodEdge = -1; - while (e != half_edge) { - int parentage = getCombinedHalfEdgeParentage_(e); - if (isGoodParentage(parentage)) { - if (goodEdge != -1) - return -1;// more than one way to move through the - // intersection - goodEdge = e; - } - - e = m_topo_graph.getHalfEdgeTwin(m_topo_graph.getHalfEdgeNext(e)); - } - - return goodEdge != -1 ? m_topo_graph.getHalfEdgeTwin(goodEdge) : -1; - } - - private void restorePolylineParts_(int first_edge, int newGeometry, - int visitedEdges, int visitedClusters, int geometry_dominant) { - assert (isGoodParentage(getCombinedHalfEdgeParentage_(first_edge))); - EditShape shape = m_topo_graph.getShape(); - int half_edge = first_edge; - int halfEdgeTwin = m_topo_graph.getHalfEdgeTwin(half_edge); - m_topo_graph.setHalfEdgeUserIndex(half_edge, visitedEdges, 1); - m_topo_graph.setHalfEdgeUserIndex(halfEdgeTwin, visitedEdges, 1); - double prevailingLength = prevailingDirection_(shape, half_edge);// prevailing - // direction - // is - // used - // to - // figure - // out - // the - // polyline - // direction. - // Prevailing length is the sum of the length of vectors that constitute - // the polyline. - // Vector length is positive, if the halfedge direction coincides with - // the direction of the original geometry - // and negative otherwise. - - m_from_edge_for_polylines = -1; - int fromEdge = half_edge; - int toEdge = -1; - boolean b_found_impassable_crossroad = false; - int edgeCount = 1; - while (true) { - int halfEdgePrev = m_topo_graph.getHalfEdgePrev(half_edge); - if (halfEdgePrev == halfEdgeTwin) - break;// the end of a polyline - - int halfEdgeTwinNext = m_topo_graph.getHalfEdgeNext(halfEdgeTwin); - if (m_topo_graph.getHalfEdgeTwin(halfEdgePrev) != halfEdgeTwinNext) { - // Crossroads is here. We can move through the crossroad only if - // there is only a single way to pass through. - //When doing planar_simplify we'll never go through the crossroad. - half_edge = tryMoveThroughCrossroadBackwards_(half_edge); - if (half_edge == -1) - break; - else { - b_found_impassable_crossroad = true; - halfEdgeTwin = m_topo_graph.getHalfEdgeTwin(half_edge); - } - } else { - half_edge = halfEdgePrev; - halfEdgeTwin = halfEdgeTwinNext; - } - - if (half_edge == first_edge) {// we are in a loop. No need to search - // for the toEdge. Just remember the - // toEdge and skip the next while - // loop. - toEdge = first_edge; - break; - } - int parentage = getCombinedHalfEdgeParentage_(half_edge); - if (!isGoodParentage(parentage)) - break; - - m_topo_graph.setHalfEdgeUserIndex(half_edge, visitedEdges, 1); - m_topo_graph.setHalfEdgeUserIndex(halfEdgeTwin, visitedEdges, 1); - fromEdge = half_edge; - prevailingLength += prevailingDirection_(shape, half_edge); - edgeCount++; - } - - if (toEdge == -1) { - half_edge = first_edge; - halfEdgeTwin = m_topo_graph.getHalfEdgeTwin(half_edge); - toEdge = half_edge; - while (true) { - int halfEdgeNext = m_topo_graph.getHalfEdgeNext(half_edge); - if (halfEdgeNext == halfEdgeTwin) - break; - - int halfEdgeTwinPrev = m_topo_graph - .getHalfEdgePrev(halfEdgeTwin); - if (m_topo_graph.getHalfEdgeTwin(halfEdgeNext) != halfEdgeTwinPrev) { - // Crossroads is here. We can move through the crossroad - // only if there is only a single way to pass through. - half_edge = tryMoveThroughCrossroadForward_(half_edge); - if (half_edge == -1) { - b_found_impassable_crossroad = true; - break; - } else - halfEdgeTwin = m_topo_graph.getHalfEdgeTwin(half_edge); - } else { - half_edge = halfEdgeNext; - halfEdgeTwin = halfEdgeTwinPrev; - } - - int parentage = getCombinedHalfEdgeParentage_(half_edge); - if (!isGoodParentage(parentage)) - break; - - m_topo_graph.setHalfEdgeUserIndex(half_edge, visitedEdges, 1); - m_topo_graph - .setHalfEdgeUserIndex(halfEdgeTwin, visitedEdges, 1); - toEdge = half_edge; - prevailingLength += prevailingDirection_(shape, half_edge); - edgeCount++; - } - } else { - // toEdge has been found in the first while loop. This happens when - // we go around a face. - // Closed loops need special processing as we do not know where the - // polyline started or ended. - - if (m_from_edge_for_polylines != -1) { - fromEdge = m_from_edge_for_polylines; - toEdge = m_topo_graph - .getHalfEdgePrev(m_from_edge_for_polylines);// try - // simply - // getting - // prev - int fromEdgeTwin = m_topo_graph.getHalfEdgeTwin(fromEdge); - int fromEdgeTwinNext = m_topo_graph - .getHalfEdgeNext(fromEdgeTwin); - if (m_topo_graph.getHalfEdgeTwin(toEdge) != fromEdgeTwinNext) { - // Crossroads is here. Pass through the crossroad. - toEdge = tryMoveThroughCrossroadBackwards_(fromEdge); - if (toEdge == -1) - throw GeometryException.GeometryInternalError();// what? - } - - assert (isGoodParentage(getCombinedHalfEdgeParentage_(m_from_edge_for_polylines))); - assert (isGoodParentage(getCombinedHalfEdgeParentage_(toEdge))); - } - } - - boolean dir = prevailingLength >= 0; - if (!dir) { - int e = toEdge; - toEdge = fromEdge; - fromEdge = e; - toEdge = m_topo_graph.getHalfEdgeTwin(toEdge);// switch to twin so - // that we can use - // next instead of - // Prev - assert (isGoodParentage(getCombinedHalfEdgeParentage_(toEdge))); - fromEdge = m_topo_graph.getHalfEdgeTwin(fromEdge); - assert (isGoodParentage(getCombinedHalfEdgeParentage_(fromEdge))); - } - - int newPath = shape.insertPath(newGeometry, -1);// add new path at the - // end - half_edge = fromEdge; - int cluster = m_topo_graph.getHalfEdgeOrigin(fromEdge); - int clusterLast = m_topo_graph.getHalfEdgeTo(toEdge); - boolean b_closed = clusterLast == cluster; - // The linestrings can touch at boundary points only, while closed path - // has no boundary, therefore no other path can touch it. - // Therefore, if a closed path touches another path, we need to split - // the closed path in two to make the result OGC simple. - boolean b_closed_linestring_touches_other_linestring = b_closed - && b_found_impassable_crossroad; - - int vert = selectVertex_(cluster, shape); - assert (vert != -1); - int vertex_dominant = getVertexByID_(vert, geometry_dominant); - shape.addVertex(newPath, vertex_dominant); - - if (visitedClusters != -1) { - m_topo_graph.setClusterUserIndex(cluster, visitedClusters, 1); - } - - int counter = 0; - int splitAt = b_closed_linestring_touches_other_linestring ? (edgeCount + 1) / 2 : -1; - while (true) { - int clusterTo = m_topo_graph.getHalfEdgeTo(half_edge); - int vert_1 = selectVertex_(clusterTo, shape); - vertex_dominant = getVertexByID_(vert_1, geometry_dominant); - shape.addVertex(newPath, vertex_dominant); - counter++; - if (visitedClusters != -1) { - m_topo_graph.setClusterUserIndex(clusterTo, visitedClusters, 1); - } - - if (b_closed_linestring_touches_other_linestring - && counter == splitAt) { - newPath = shape.insertPath(newGeometry, -1);// add new path at - // the end - shape.addVertex(newPath, vertex_dominant); - } - - assert (isGoodParentage(getCombinedHalfEdgeParentage_(half_edge))); - if (half_edge == toEdge) - break; - - int halfEdgeNext = m_topo_graph.getHalfEdgeNext(half_edge); - if (m_topo_graph.getHalfEdgePrev(m_topo_graph - .getHalfEdgeTwin(half_edge)) != m_topo_graph - .getHalfEdgeTwin(halfEdgeNext)) {// crossroads. - half_edge = tryMoveThroughCrossroadForward_(half_edge); - if (half_edge == -1) - throw GeometryException.GeometryInternalError();// a bug. This - // shoulf - // never - // happen - } else - half_edge = halfEdgeNext; - } - } - - private int topoOperationPolylinePolylineOrPolygon_(int geometry_dominant) { - EditShape shape = m_topo_graph.getShape(); - int newGeometry = shape.createGeometry(Geometry.Type.Polyline); - int visitedEdges = m_topo_graph.createUserIndexForHalfEdges(); - - for (int cluster = m_topo_graph.getFirstCluster(); cluster != -1; cluster = m_topo_graph - .getNextCluster(cluster)) { - int firstClusterHalfEdge = m_topo_graph.getClusterHalfEdge(cluster); - int clusterHalfEdge = firstClusterHalfEdge; - do { - int visited = m_topo_graph.getHalfEdgeUserIndex( - clusterHalfEdge, visitedEdges); - if (visited != 1) { - int parentage = getCombinedHalfEdgeParentage_(clusterHalfEdge); - if (isGoodParentage(parentage)) { - restorePolylineParts_(clusterHalfEdge, newGeometry, - visitedEdges, -1, geometry_dominant); - } else { - // - } - } - - clusterHalfEdge = m_topo_graph.getHalfEdgeNext(m_topo_graph - .getHalfEdgeTwin(clusterHalfEdge)); - } while (clusterHalfEdge != firstClusterHalfEdge); - } - - m_topo_graph.deleteUserIndexForHalfEdges(visitedEdges); - return newGeometry; - } - - int[] topoOperationPolylinePolylineOrPolygonEx_(int geometry_dominant) { - EditShape shape = m_topo_graph.getShape(); - int newPolyline = shape.createGeometry(Geometry.Type.Polyline); - int newMultipoint = shape.createGeometry(Geometry.Type.MultiPoint); - int visitedEdges = m_topo_graph.createUserIndexForHalfEdges(); - int visitedClusters = m_topo_graph.createUserIndexForClusters(); - int multipointPath = -1; - for (int cluster = m_topo_graph.getFirstCluster(); cluster != -1; cluster = m_topo_graph - .getNextCluster(cluster)) { - int firstClusterHalfEdge = m_topo_graph.getClusterHalfEdge(cluster); - int clusterHalfEdge = firstClusterHalfEdge; - do { - int visited = m_topo_graph.getHalfEdgeUserIndex( - clusterHalfEdge, visitedEdges); - if (visited != 1) { - int parentage = getCombinedHalfEdgeParentage_(clusterHalfEdge); - if (isGoodParentage(parentage)) { - restorePolylineParts_(clusterHalfEdge, newPolyline, - visitedEdges, visitedClusters, - geometry_dominant); - } else { - // - } - } - - clusterHalfEdge = m_topo_graph.getHalfEdgeNext(m_topo_graph - .getHalfEdgeTwin(clusterHalfEdge)); - } while (clusterHalfEdge != firstClusterHalfEdge); - } - - for (int cluster = m_topo_graph.getFirstCluster(); cluster != -1; cluster = m_topo_graph - .getNextCluster(cluster)) { - int visited = m_topo_graph.getClusterUserIndex(cluster, - visitedClusters); - if (visited != 1) { - int parentage = m_topo_graph.getClusterParentage(cluster); - if (isGoodParentage(parentage)) { - if (multipointPath == -1) - multipointPath = shape.insertPath(newMultipoint, -1); - - int viter = m_topo_graph.getClusterVertexIterator(cluster); - int v; - if (viter != -1) { - v = m_topo_graph.getVertexFromVertexIterator(viter); - int vertex_dominant = getVertexByID_(v, - geometry_dominant); - shape.addVertex(multipointPath, vertex_dominant); - } - } else { - // - } - } - } - - m_topo_graph.deleteUserIndexForHalfEdges(visitedEdges); - m_topo_graph.deleteUserIndexForClusters(visitedClusters); - int[] result = new int[2]; - result[0] = newMultipoint; - result[1] = newPolyline; - return result; - } - - private int topoOperationMultiPoint_() { - EditShape shape = m_topo_graph.getShape(); - int newGeometry = shape.createGeometry(Geometry.Type.MultiPoint); - int newPath = shape.insertPath(newGeometry, -1);// add new path at the - // end - - // Now extract paths that - for (int cluster = m_topo_graph.getFirstCluster(); cluster != -1; cluster = m_topo_graph - .getNextCluster(cluster)) { - int parentage = m_topo_graph.getClusterParentage(cluster); - if (isGoodParentage(parentage)) { - int vert = -1; - for (int iterator = m_topo_graph - .getClusterVertexIterator(cluster); iterator != -1; iterator = m_topo_graph - .incrementVertexIterator(iterator)) { - int vertex = m_topo_graph - .getVertexFromVertexIterator(iterator); - if (vert == -1) - vert = vertex; - int geometry = shape.getGeometryFromPath(shape - .getPathFromVertex(vertex)); - int geomID = m_topo_graph.getGeometryID(geometry); - if (isGoodParentage(geomID)) { - vert = vertex; - break; - } - } - assert (vert != -1); - shape.addVertex(newPath, vert); - } - } - - return newGeometry; - } - - void initMaskLookupArray_(int len) { - m_mask_lookup = new boolean[len]; - for (int i = 0; i < len; i++) { - m_mask_lookup[i] = false; - } - } - - static MultiPoint processMultiPointIntersectOrDiff_(MultiPoint multi_point, - Geometry intersector, double tolerance, boolean bClipIn) { - MultiPoint multi_point_out = ((MultiPoint) multi_point.createInstance()); - Point2D[] input_points = new Point2D[1000]; - PolygonUtils.PiPResult[] test_results = new PolygonUtils.PiPResult[1000]; - int npoints = multi_point.getPointCount(); - boolean bFirstOut = true; - boolean bArea = (intersector.getDimension() == 2); - if (intersector.getDimension() != 1 && intersector.getDimension() != 2) - throw GeometryException.GeometryInternalError(); - - for (int ipoints = 0; ipoints < npoints; ) { - int num = multi_point.queryCoordinates(input_points, 1000, ipoints, - -1) - ipoints; - - if (bArea) - PolygonUtils.testPointsInArea2D(intersector, input_points, - (int) num, tolerance, test_results); - else - PolygonUtils.testPointsOnLine2D(intersector, input_points, - (int) num, tolerance, test_results); - int i0 = 0; - for (int i = 0; i < num; i++) { - boolean bTest = test_results[i] == PolygonUtils.PiPResult.PiPOutside; - if (!bClipIn) - bTest = !bTest; - - if (bTest) { - if (bFirstOut) { - bFirstOut = false; - multi_point_out.add(multi_point, 0, ipoints); - } - - if (i0 != i) - multi_point_out.add(multi_point, ipoints + i0, ipoints - + i); - - i0 = i + 1; - } - } - - if (!bFirstOut && i0 != num) - multi_point_out.add(multi_point, ipoints + i0, ipoints + num); - - ipoints += num; - } - - if (bFirstOut) - return multi_point; - - return multi_point_out; - } - - static MultiPoint intersection(MultiPoint multi_point, Geometry multi_path, - double tolerance) { - return processMultiPointIntersectOrDiff_(multi_point, multi_path, - tolerance, true); - } - - static MultiPoint difference(MultiPoint multi_point, Geometry multi_path, - double tolerance) { - return processMultiPointIntersectOrDiff_(multi_point, multi_path, - tolerance, false); - } - - static Point processPointIntersectOrDiff_(Point point, - Geometry intersector, double tolerance, boolean bClipIn) { - if (point.isEmpty()) - return ((Point) point.createInstance()); - if (intersector.isEmpty()) { - return bClipIn ? ((Point) point.createInstance()) : null; - } - - Point2D[] input_points = new Point2D[1]; - PolygonUtils.PiPResult[] test_results = new PolygonUtils.PiPResult[1]; - boolean bArea = intersector.getDimension() == 2; - if (intersector.getDimension() != 1 && intersector.getDimension() != 2) - throw GeometryException.GeometryInternalError(); - input_points[0] = point.getXY(); - if (bArea) - PolygonUtils.testPointsInArea2D(intersector, input_points, 1, - tolerance, test_results); - else - PolygonUtils.testPointsOnLine2D(intersector, input_points, 1, - tolerance, test_results); - - boolean bTest = test_results[0] == PolygonUtils.PiPResult.PiPOutside; - if (!bClipIn) - bTest = !bTest; - - if (!bTest) - return point; - else - return ((Point) point.createInstance()); - } - - static Point intersection(Point point, Geometry geom, double tolerance) { - return processPointIntersectOrDiff_(point, geom, tolerance, true); - } - - static Point difference(Point point, Geometry geom, double tolerance) { - return processPointIntersectOrDiff_(point, geom, tolerance, false); - } - - static Point intersection(Point point, Point point2, double tolerance) { - if (point.isEmpty() || point2.isEmpty()) - return (Point) point.createInstance(); - - if (CrackAndCluster.non_empty_points_need_to_cluster(tolerance, point, - point2)) { - return CrackAndCluster.cluster_non_empty_points(point, point2, 1, - 1, 1, 1); - } - - return (Point) point.createInstance(); - } - - static Point difference(Point point, Point point2, double tolerance) { - if (point.isEmpty()) - return (Point) point.createInstance(); - if (point2.isEmpty()) - return point; - - if (CrackAndCluster.non_empty_points_need_to_cluster(tolerance, point, - point2)) { - return (Point) point.createInstance(); - } - - return point; - } - - MultiVertexGeometry planarSimplifyImpl_(MultiVertexGeometry input_geom, - double tolerance, boolean b_use_winding_rule_for_polygons, - boolean dirty_result, ProgressTracker progress_tracker) { - if (input_geom.isEmpty()) - return input_geom; - - EditShape shape = new EditShape(); - int geom = shape.addGeometry(input_geom); - return planarSimplify(shape, geom, tolerance, - b_use_winding_rule_for_polygons, dirty_result, progress_tracker); - } - - MultiVertexGeometry planarSimplify(EditShape shape, int geom, - double tolerance, boolean b_use_winding_rule_for_polygons, - boolean dirty_result, ProgressTracker progress_tracker) { - // This method will produce a polygon from a polyline when - // b_use_winding_rule_for_polygons is true. This is used by buffer. - m_topo_graph = new TopoGraph(); - try { - if (dirty_result - && shape.getGeometryType(geom) != Geometry.Type.MultiPoint - .value()) { - PlaneSweepCrackerHelper plane_sweeper = new PlaneSweepCrackerHelper(); - plane_sweeper.sweepVertical(shape, tolerance); - if (plane_sweeper.hadCompications())// shame. The one pass - // planesweep had some - // complications. Need to do - // full crack and cluster. - { - CrackAndCluster.execute(shape, tolerance, progress_tracker, true); - dirty_result = false; - } else { - m_topo_graph.check_dirty_planesweep(tolerance); - } - } else { - CrackAndCluster.execute(shape, tolerance, progress_tracker, true); - dirty_result = false; - } - - if (!b_use_winding_rule_for_polygons - || shape.getGeometryType(geom) == Geometry.Type.MultiPoint - .value()) - m_topo_graph.setAndSimplifyEditShapeAlternate(shape, geom, progress_tracker); - else - m_topo_graph.setAndSimplifyEditShapeWinding(shape, geom, progress_tracker); - - if (m_topo_graph.dirty_check_failed()) { - // we ran the sweep_vertical() before and it produced some - // issues that where detected by topo graph only. - assert (dirty_result); - m_topo_graph.removeShape(); - m_topo_graph = null; - // that's at most two level recursion - return planarSimplify(shape, geom, tolerance, - b_use_winding_rule_for_polygons, false, - progress_tracker); - } else { - //can proceed - } - - m_topo_graph.check_dirty_planesweep(NumberUtils.TheNaN); - - int ID_a = m_topo_graph.getGeometryID(geom); - initMaskLookupArray_((ID_a) + 1); - m_mask_lookup[ID_a] = true; // Works only when there is a single - // geometry in the edit shape. - // To make it work when many geometries are present, this need to be - // modified. - - if (shape.getGeometryType(geom) == Geometry.Type.Polygon.value() - || (b_use_winding_rule_for_polygons && shape - .getGeometryType(geom) != Geometry.Type.MultiPoint - .value())) { - // geom can be a polygon or a polyline. - // It can be a polyline only when the winding rule is true. - shape.setFillRule(geom, Polygon.FillRule.enumFillRuleOddEven); - int resGeom = topoOperationPolygonPolygon_(geom, -1, -1); - - Polygon polygon = (Polygon) shape.getGeometry(resGeom); - polygon.setFillRule(Polygon.FillRule.enumFillRuleOddEven);//standardize the fill rule. - if (!dirty_result) { - ((MultiVertexGeometryImpl) polygon._getImpl()).setIsSimple( - GeometryXSimple.Strong, tolerance, false); - ((MultiPathImpl) polygon._getImpl())._updateOGCFlags(); - } else - ((MultiVertexGeometryImpl) polygon._getImpl()).setIsSimple( - GeometryXSimple.Weak, 0.0, false);// dirty result means - // simple but with 0 - // tolerance. - - return polygon; - } else if (shape.getGeometryType(geom) == Geometry.Type.Polyline - .value()) { - int resGeom = topoOperationPolylinePolylineOrPolygon_(-1); - - Polyline polyline = (Polyline) shape.getGeometry(resGeom); - if (!dirty_result) - ((MultiVertexGeometryImpl) polyline._getImpl()).setIsSimple( - GeometryXSimple.Strong, tolerance, false); - - return polyline; - } else if (shape.getGeometryType(geom) == Geometry.Type.MultiPoint - .value()) { - int resGeom = topoOperationMultiPoint_(); - - MultiPoint mp = (MultiPoint) shape.getGeometry(resGeom); - if (!dirty_result) - ((MultiVertexGeometryImpl) mp._getImpl()).setIsSimple( - GeometryXSimple.Strong, tolerance, false); - - return mp; - } else { - throw GeometryException.GeometryInternalError(); - } - } finally { - m_topo_graph.removeShape(); - } - } - - // static - static MultiVertexGeometry planarSimplify(MultiVertexGeometry input_geom, - double tolerance, boolean use_winding_rule_for_polygons, - boolean dirty_result, ProgressTracker progress_tracker) { - TopologicalOperations topoOps = new TopologicalOperations(); - return topoOps.planarSimplifyImpl_(input_geom, tolerance, - use_winding_rule_for_polygons, dirty_result, progress_tracker); - } - - boolean planarSimplifyNoCrackingAndCluster(boolean OGCoutput, EditShape shape, int geom, ProgressTracker progress_tracker) { - m_bOGCOutput = OGCoutput; - m_topo_graph = new TopoGraph(); - int rule = shape.getFillRule(geom); - int gt = shape.getGeometryType(geom); - if (rule != Polygon.FillRule.enumFillRuleWinding || gt == GeometryType.MultiPoint) - m_topo_graph.setAndSimplifyEditShapeAlternate(shape, geom, progress_tracker); - else - m_topo_graph.setAndSimplifyEditShapeWinding(shape, geom, progress_tracker); - - if (m_topo_graph.dirty_check_failed()) - return false; - - m_topo_graph.check_dirty_planesweep(NumberUtils.TheNaN); - - int ID_a = m_topo_graph.getGeometryID(geom); - initMaskLookupArray_((ID_a) + 1); - m_mask_lookup[ID_a] = true; //Works only when there is a single geometry in the edit shape. - //To make it work when many geometries are present, this need to be modified. - - if (shape.getGeometryType(geom) == GeometryType.Polygon || (rule == Polygon.FillRule.enumFillRuleWinding && shape.getGeometryType(geom) != GeometryType.MultiPoint)) { - //geom can be a polygon or a polyline. - //It can be a polyline only when the winding rule is true. - shape.setFillRule(geom, Polygon.FillRule.enumFillRuleOddEven); - int resGeom = topoOperationPolygonPolygon_(geom, -1, -1); - shape.swapGeometry(resGeom, geom); - shape.removeGeometry(resGeom); - } else if (shape.getGeometryType(geom) == GeometryType.Polyline) { - int resGeom = topoOperationPolylinePolylineOrPolygon_(-1); - shape.swapGeometry(resGeom, geom); - shape.removeGeometry(resGeom); - } else if (shape.getGeometryType(geom) == GeometryType.MultiPoint) { - int resGeom = topoOperationMultiPoint_(); - shape.swapGeometry(resGeom, geom); - shape.removeGeometry(resGeom); - } else { - throw new GeometryException("internal error"); - } - - return true; - } - - - static MultiVertexGeometry simplifyOGC(MultiVertexGeometry input_geom, double tolerance, boolean dirty_result, ProgressTracker progress_tracker) { - TopologicalOperations topoOps = new TopologicalOperations(); - topoOps.m_bOGCOutput = true; - return topoOps.planarSimplifyImpl_(input_geom, tolerance, false, dirty_result, progress_tracker); - } - - public int difference(int geometry_a, int geometry_b) { - int gtA = m_topo_graph.getShape().getGeometryType(geometry_a); - int gtB = m_topo_graph.getShape().getGeometryType(geometry_b); - int dim_a = Geometry.getDimensionFromType(gtA); - int dim_b = Geometry.getDimensionFromType(gtB); - if (dim_a > dim_b) { - return geometry_a; - } - - int ID_a = m_topo_graph.getGeometryID(geometry_a); - int ID_b = m_topo_graph.getGeometryID(geometry_b); - initMaskLookupArray_((ID_a | ID_b) + 1); - m_mask_lookup[m_topo_graph.getGeometryID(geometry_a)] = true; - - if (dim_a == 2 && dim_b == 2) - return topoOperationPolygonPolygon_(geometry_a, geometry_b, -1); - if (dim_a == 1 && dim_b == 2) - return topoOperationPolylinePolylineOrPolygon_(-1); - if (dim_a == 1 && dim_b == 1) - return topoOperationPolylinePolylineOrPolygon_(-1); - if (dim_a == 0) - return topoOperationMultiPoint_(); - - throw GeometryException.GeometryInternalError(); - } - - int dissolve(int geometry_a, int geometry_b) { - int gtA = m_topo_graph.getShape().getGeometryType(geometry_a); - int gtB = m_topo_graph.getShape().getGeometryType(geometry_b); - int dim_a = Geometry.getDimensionFromType(gtA); - int dim_b = Geometry.getDimensionFromType(gtB); - if (dim_a > dim_b) { - return geometry_a; - } - - if (dim_a < dim_b) { - return geometry_b; - } - - int ID_a = m_topo_graph.getGeometryID(geometry_a); - int ID_b = m_topo_graph.getGeometryID(geometry_b); - initMaskLookupArray_(((ID_a | ID_b) + 1)); - - m_mask_lookup[m_topo_graph.getGeometryID(geometry_a)] = true; - m_mask_lookup[m_topo_graph.getGeometryID(geometry_b)] = true; - m_mask_lookup[m_topo_graph.getGeometryID(geometry_a) - | m_topo_graph.getGeometryID(geometry_b)] = true; - - if (dim_a == 2 && dim_b == 2) - return topoOperationPolygonPolygon_(geometry_a, geometry_b, -1); - if (dim_a == 1 && dim_b == 1) - return topoOperationPolylinePolylineOrPolygon_(-1); - if (dim_a == 0 && dim_b == 0) - return topoOperationMultiPoint_(); - - throw GeometryException.GeometryInternalError(); - } - - public int intersection(int geometry_a, int geometry_b) { - int gtA = m_topo_graph.getShape().getGeometryType(geometry_a); - int gtB = m_topo_graph.getShape().getGeometryType(geometry_b); - int dim_a = Geometry.getDimensionFromType(gtA); - int dim_b = Geometry.getDimensionFromType(gtB); - - int ID_a = m_topo_graph.getGeometryID(geometry_a); - int ID_b = m_topo_graph.getGeometryID(geometry_b); - initMaskLookupArray_(((ID_a | ID_b) + 1)); - - m_mask_lookup[m_topo_graph.getGeometryID(geometry_a) - | m_topo_graph.getGeometryID(geometry_b)] = true; - - int geometry_dominant = -1; - boolean b_vertex_dominance = (m_topo_graph.getShape() - .getVertexDescription().getAttributeCount() > 1); - if (b_vertex_dominance) - geometry_dominant = geometry_a; - - if (dim_a == 2 && dim_b == 2)// intersect two polygons - return topoOperationPolygonPolygon_(geometry_a, geometry_b, - geometry_dominant); - if ((dim_a == 1 && dim_b > 0) || (dim_b == 1 && dim_a > 0))// intersect - // polyline - // with - // polyline - // or - // polygon - return topoOperationPolylinePolylineOrPolygon_(geometry_dominant); - if (dim_a == 0 || dim_b == 0)// intersect a multipoint with something - // else - return topoOperationMultiPoint_(); - - throw GeometryException.GeometryInternalError(); - } - - int[] intersectionEx(int geometry_a, int geometry_b) { - int gtA = m_topo_graph.getShape().getGeometryType(geometry_a); - int gtB = m_topo_graph.getShape().getGeometryType(geometry_b); - int dim_a = Geometry.getDimensionFromType(gtA); - int dim_b = Geometry.getDimensionFromType(gtB); - - int ID_a = m_topo_graph.getGeometryID(geometry_a); - int ID_b = m_topo_graph.getGeometryID(geometry_b); - initMaskLookupArray_(((ID_a | ID_b) + 1)); - - m_mask_lookup[m_topo_graph.getGeometryID(geometry_a) - | m_topo_graph.getGeometryID(geometry_b)] = true; - - int geometry_dominant = -1; - boolean b_vertex_dominance = (m_topo_graph.getShape() - .getVertexDescription().getAttributeCount() > 1); - if (b_vertex_dominance) - geometry_dominant = geometry_a; - - if (dim_a == 2 && dim_b == 2)// intersect two polygons - return topoOperationPolygonPolygonEx_(geometry_a, geometry_b, - geometry_dominant); - if ((dim_a == 1 && dim_b > 0) || (dim_b == 1 && dim_a > 0))// intersect - // polyline - // with - // polyline - // or - // polygon - return topoOperationPolylinePolylineOrPolygonEx_(geometry_dominant); - if (dim_a == 0 || dim_b == 0)// intersect a multipoint with something - // else - { - int[] res = new int[1]; - res[0] = topoOperationMultiPoint_(); - return res; - } - - throw GeometryException.GeometryInternalError(); - } - - public int symmetricDifference(int geometry_a, int geometry_b) { - int gtA = m_topo_graph.getShape().getGeometryType(geometry_a); - int gtB = m_topo_graph.getShape().getGeometryType(geometry_b); - int dim_a = Geometry.getDimensionFromType(gtA); - int dim_b = Geometry.getDimensionFromType(gtB); - - int ID_a = m_topo_graph.getGeometryID(geometry_a); - int ID_b = m_topo_graph.getGeometryID(geometry_b); - initMaskLookupArray_((ID_a | ID_b) + 1); - - m_mask_lookup[m_topo_graph.getGeometryID(geometry_a)] = true; - m_mask_lookup[m_topo_graph.getGeometryID(geometry_b)] = true; - - if (dim_a == 2 && dim_b == 2) - return topoOperationPolygonPolygon_(geometry_a, geometry_b, -1); - if (dim_a == 1 && dim_b == 1) - return topoOperationPolylinePolylineOrPolygon_(-1); - if (dim_a == 0 && dim_b == 0) - return topoOperationMultiPoint_(); - - throw GeometryException.GeometryInternalError(); - } - - int extractShape(int geometry_in) { - int gtA = m_topo_graph.getShape().getGeometryType(geometry_in); - int dim_a = Geometry.getDimensionFromType(gtA); - - int ID_a = m_topo_graph.getGeometryID(geometry_in); - initMaskLookupArray_((ID_a) + 1); - m_mask_lookup[m_topo_graph.getGeometryID(geometry_in)] = true; // Works - // only - // when - // there - // is a - // single - // geometry - // in - // the - // edit - // shape. - // To make it work when many geometries are present, this need to be - // modified. - - if (dim_a == 2) - return topoOperationPolygonPolygon_(geometry_in, -1, -1); - if (dim_a == 1) - return topoOperationPolylinePolylineOrPolygon_(-1); - if (dim_a == 0) - return topoOperationMultiPoint_(); - - throw GeometryException.GeometryInternalError(); - } - - static Geometry normalizeInputGeometry_(Geometry geom) { - Geometry.Type gt = geom.getType(); - if (gt == Geometry.Type.Envelope) { - Polygon poly = new Polygon(geom.getDescription()); - if (!geom.isEmpty()) - poly.addEnvelope((Envelope) geom, false); - return poly; - } - if (gt == Geometry.Type.Point) { - MultiPoint poly = new MultiPoint(geom.getDescription()); - if (!geom.isEmpty()) - poly.add((Point) geom); - return poly; - } - if (gt == Geometry.Type.Line) { - Polyline poly = new Polyline(geom.getDescription()); - if (!geom.isEmpty()) - poly.addSegment((Segment) geom, true); - return poly; - } - - return geom; - } - - static Geometry normalizeResult_(Geometry geomRes, Geometry geom_a, - Geometry dummy, char op) { - // assert(strchr("-&^|",op) != NULL); - Geometry.Type gtRes = geomRes.getType(); - if (gtRes == Geometry.Type.Envelope) { - Polygon poly = new Polygon(geomRes.getDescription()); - if (!geomRes.isEmpty()) - poly.addEnvelope((Envelope) geomRes, false); - return poly; - } - - if (gtRes == Geometry.Type.Point && (op == '|' || op == '^')) { - MultiPoint poly = new MultiPoint(geomRes.getDescription()); - if (!geomRes.isEmpty()) - poly.add((Point) geomRes); - return poly; - } - - if (gtRes == Geometry.Type.Line) { - Polyline poly = new Polyline(geomRes.getDescription()); - if (!geomRes.isEmpty()) - poly.addSegment((Segment) geomRes, true); - return poly; - } - - if (gtRes == Geometry.Type.Point && op == '-') { - if (geom_a.getType() == Geometry.Type.Point) { - Point pt = new Point(geomRes.getDescription()); - if (!geomRes.isEmpty()) { - assert (((MultiPoint) geomRes).getPointCount() == 1); - ((MultiPoint) geomRes).getPointByVal(0, pt); - } - return pt; - } - } - - if (gtRes == Geometry.Type.MultiPoint && op == '&') { - if (geom_a.getType() == Geometry.Type.Point) { - Point pt = new Point(geomRes.getDescription()); - if (!geomRes.isEmpty()) { - assert (((MultiPoint) geomRes).getPointCount() == 1); - ((MultiPoint) geomRes).getPointByVal(0, pt); - } - return pt; - } - } - - return geomRes; - } - - // static - public static Geometry difference(Geometry geometry_a, Geometry geometry_b, - SpatialReference sr, ProgressTracker progress_tracker) { - if (geometry_a.isEmpty() || geometry_b.isEmpty() - || geometry_a.getDimension() > geometry_b.getDimension()) - return normalizeResult_(normalizeInputGeometry_(geometry_a), - geometry_a, geometry_b, '-'); - - Envelope2D env2D_1 = new Envelope2D(); - geometry_a.queryEnvelope2D(env2D_1); - Envelope2D env2D_2 = new Envelope2D(); - geometry_b.queryEnvelope2D(env2D_2); - - if (!env2D_1.isIntersecting(env2D_2)) { - return normalizeResult_(normalizeInputGeometry_(geometry_a), - geometry_a, geometry_b, '-'); - } - - Envelope2D envMerged = new Envelope2D(); - envMerged.setCoords(env2D_1); - envMerged.merge(env2D_2); - double tolerance = InternalUtils.calculateToleranceFromGeometry(sr, - envMerged, true);// conservative to have same effect as simplify - - TopologicalOperations topoOps = new TopologicalOperations(); - EditShape edit_shape = new EditShape(); - int geom_a = edit_shape - .addGeometry(normalizeInputGeometry_(geometry_a)); - int geom_b = edit_shape - .addGeometry(normalizeInputGeometry_(geometry_b)); - topoOps.setEditShapeCrackAndCluster(edit_shape, tolerance, - progress_tracker); - int result = topoOps.difference(geom_a, geom_b); - Geometry resGeom = edit_shape.getGeometry(result); - - Geometry res_geom = normalizeResult_(resGeom, geometry_a, geometry_b, - '-'); - - if (Geometry.isMultiPath(res_geom.getType().value())) { - ((MultiVertexGeometryImpl) res_geom._getImpl()).setIsSimple( - GeometryXSimple.Strong, tolerance, false); - if (res_geom.getType() == Geometry.Type.Polygon) - ((MultiPathImpl) res_geom._getImpl())._updateOGCFlags(); - } - - return res_geom; - } - - public static Geometry dissolve(Geometry geometry_a, Geometry geometry_b, - SpatialReference sr, ProgressTracker progress_tracker) { - if (geometry_a.getDimension() > geometry_b.getDimension()) - return normalizeResult_(normalizeInputGeometry_(geometry_a), - geometry_a, geometry_b, '|'); - - if (geometry_a.getDimension() < geometry_b.getDimension()) - return normalizeResult_(normalizeInputGeometry_(geometry_b), - geometry_a, geometry_b, '|'); - - if (geometry_a.isEmpty()) - return normalizeResult_(normalizeInputGeometry_(geometry_b), - geometry_a, geometry_b, '|'); - - if (geometry_b.isEmpty()) - return normalizeResult_(normalizeInputGeometry_(geometry_a), - geometry_a, geometry_b, '|'); - - Envelope2D env2D_1 = new Envelope2D(); - geometry_a.queryEnvelope2D(env2D_1); - Envelope2D env2D_2 = new Envelope2D(); - geometry_b.queryEnvelope2D(env2D_2); - - Envelope2D envMerged = new Envelope2D(); - envMerged.setCoords(env2D_1); - envMerged.merge(env2D_2); - double tolerance = InternalUtils.calculateToleranceFromGeometry(sr, - envMerged, true);// conservative to have same effect as simplify - - if (!env2D_1.isIntersecting(env2D_2.getInflated(tolerance, tolerance))) { - // TODO: add optimization here to merge two geometries if the - // envelopes do not overlap. - Geometry geom1 = normalizeInputGeometry_(geometry_a); - assert (Geometry.isMultiVertex(geom1.getType().value())); - Geometry geom2 = normalizeInputGeometry_(geometry_b); - assert (Geometry.isMultiVertex(geom2.getType().value())); - assert (geom1.getType() == geom2.getType()); - switch (geom1.getType().value()) { - case Geometry.GeometryType.MultiPoint: { - Geometry res = Geometry._clone(geom1); - ((MultiPoint) res).add((MultiPoint) geom2, 0, -1); - return res; - } - // break; - case Geometry.GeometryType.Polyline: { - Geometry res = Geometry._clone(geom1); - ((Polyline) res).add((MultiPath) geom2, false); - return res; - } - // break; - case Geometry.GeometryType.Polygon: { - Geometry res = Geometry._clone(geom1); - ((Polygon) res).add((MultiPath) geom2, false); - return res; - } - // break; - default: - throw GeometryException.GeometryInternalError(); - } - } - - TopologicalOperations topoOps = new TopologicalOperations(); - EditShape edit_shape = new EditShape(); - int geom_a = edit_shape - .addGeometry(normalizeInputGeometry_(geometry_a)); - int geom_b = edit_shape - .addGeometry(normalizeInputGeometry_(geometry_b)); - topoOps.setEditShapeCrackAndCluster(edit_shape, tolerance, - progress_tracker); - int result = topoOps.dissolve(geom_a, geom_b); - - Geometry res_geom = normalizeResult_(edit_shape.getGeometry(result), - geometry_a, geometry_b, '|'); - - if (Geometry.isMultiPath(res_geom.getType().value())) { - ((MultiVertexGeometryImpl) res_geom._getImpl()).setIsSimple( - GeometryXSimple.Strong, tolerance, false); - if (res_geom.getType() == Geometry.Type.Polygon) - ((MultiPathImpl) res_geom._getImpl())._updateOGCFlags(); - } - - return res_geom; - } - - static Geometry dissolveDirty(ArrayList geometries, - SpatialReference sr, ProgressTracker progress_tracker) { - if (geometries.size() < 2) - throw new IllegalArgumentException( - "not enough geometries to dissolve"); - - int dim = 0; - for (int i = 0, n = geometries.size(); i < n; i++) { - dim = Math.max(geometries.get(i).getDimension(), dim); - } - - Envelope2D envMerged = new Envelope2D(); - envMerged.setEmpty(); - - EditShape shape = new EditShape(); - int geom = -1; - int count = 0; - int any_index = -1; - for (int i = 0, n = geometries.size(); i < n; i++) { - if (geometries.get(i).getDimension() == dim) { - if (!geometries.get(i).isEmpty()) { - any_index = i; - if (geom == -1) - geom = shape - .addGeometry(normalizeInputGeometry_(geometries - .get(i))); - else - shape.appendGeometry(geom, - normalizeInputGeometry_(geometries.get(i))); - - Envelope2D env = new Envelope2D(); - geometries.get(i).queryLooseEnvelope2D(env); - envMerged.merge(env); - count++; - } else if (any_index == -1) - any_index = i; - } - } - - if (count < 2) { - return normalizeInputGeometry_(geometries.get(any_index)); - } - - boolean winding = dim == 2; - - SpatialReference psr = dim == 0 ? sr : null;// if points, then use - // correct tolerance. - double tolerance = InternalUtils.calculateToleranceFromGeometry(psr, - envMerged, true); - TopologicalOperations topoOps = new TopologicalOperations(); - return topoOps.planarSimplify(shape, geom, tolerance, winding, true, - progress_tracker); - } - - // static - public static Geometry intersection(Geometry geometry_a, - Geometry geometry_b, SpatialReference sr, - ProgressTracker progress_tracker) { - - Envelope2D env2D_1 = new Envelope2D(); - geometry_a.queryEnvelope2D(env2D_1); - Envelope2D env2D_2 = new Envelope2D(); - geometry_b.queryEnvelope2D(env2D_2); - - Envelope2D envMerged = new Envelope2D(); - envMerged.setCoords(env2D_1); - envMerged.merge(env2D_2); - double tolerance = InternalUtils.calculateToleranceFromGeometry(sr, - envMerged, true);// conservative to have same effect as simplify - - Envelope2D e = new Envelope2D(); - e.setCoords(env2D_2); - double tol_cluster = InternalUtils - .adjust_tolerance_for_TE_clustering(tolerance); - e.inflate(tol_cluster, tol_cluster); - - if (!env2D_1.isIntersecting(e))// also includes the empty geometry - // cases - { - if (geometry_a.getDimension() <= geometry_b.getDimension()) - return normalizeResult_( - normalizeInputGeometry_(geometry_a.createInstance()), - geometry_a, geometry_b, '&'); - - if (geometry_a.getDimension() > geometry_b.getDimension()) - return normalizeResult_( - normalizeInputGeometry_(geometry_b.createInstance()), - geometry_a, geometry_b, '&'); - } - - TopologicalOperations topoOps = new TopologicalOperations(); - EditShape edit_shape = new EditShape(); - int geom_a = edit_shape - .addGeometry(normalizeInputGeometry_(geometry_a)); - int geom_b = edit_shape - .addGeometry(normalizeInputGeometry_(geometry_b)); - - topoOps.setEditShapeCrackAndCluster(edit_shape, tolerance, - progress_tracker); - int result = topoOps.intersection(geom_a, geom_b); - Geometry res_geom = normalizeResult_(edit_shape.getGeometry(result), - geometry_a, geometry_b, '&'); - - if (Geometry.isMultiPath(res_geom.getType().value())) { - ((MultiVertexGeometryImpl) res_geom._getImpl()).setIsSimple( - GeometryXSimple.Strong, tolerance, false); - if (res_geom.getType() == Geometry.Type.Polygon) - ((MultiPathImpl) res_geom._getImpl())._updateOGCFlags(); - } - - return res_geom; - } - - static Geometry[] intersectionEx(Geometry geometry_a, Geometry geometry_b, - SpatialReference sr, ProgressTracker progress_tracker) { - Geometry[] res_vec = new Geometry[3]; - - Envelope2D env2D_1 = new Envelope2D(); - geometry_a.queryEnvelope2D(env2D_1); - Envelope2D env2D_2 = new Envelope2D(); - geometry_b.queryEnvelope2D(env2D_2); - - Envelope2D envMerged = new Envelope2D(); - envMerged.setCoords(env2D_1); - envMerged.merge(env2D_2); - double tolerance = InternalUtils.calculateToleranceFromGeometry(sr, - envMerged, true);// conservative to have same effect as simplify - - Envelope2D e = new Envelope2D(); - e.setCoords(env2D_2); - double tol_cluster = InternalUtils - .adjust_tolerance_for_TE_clustering(tolerance); - e.inflate(tol_cluster, tol_cluster); - - if (!env2D_1.isIntersecting(e))// also includes the empty geometry - // cases - { - if (geometry_a.getDimension() <= geometry_b.getDimension()) { - Geometry geom = normalizeResult_( - normalizeInputGeometry_(geometry_a.createInstance()), - geometry_a, geometry_b, '&'); - res_vec[geom.getDimension()] = geom; - return res_vec; - } - - if (geometry_a.getDimension() > geometry_b.getDimension()) { - Geometry geom = normalizeResult_( - normalizeInputGeometry_(geometry_b.createInstance()), - geometry_a, geometry_b, '&'); - res_vec[geom.getDimension()] = geom; - return res_vec; - } - - } - - TopologicalOperations topoOps = new TopologicalOperations(); - EditShape edit_shape = new EditShape(); - int geom_a = edit_shape - .addGeometry(normalizeInputGeometry_(geometry_a)); - int geom_b = edit_shape - .addGeometry(normalizeInputGeometry_(geometry_b)); - - topoOps.setEditShapeCrackAndCluster(edit_shape, tolerance, - progress_tracker); - int[] result_geom_handles = topoOps.intersectionEx(geom_a, geom_b); - for (int i = 0; i < result_geom_handles.length; i++) { - Geometry res_geom = normalizeResult_( - edit_shape.getGeometry(result_geom_handles[i]), geometry_a, - geometry_b, '&'); - - if (Geometry.isMultiPath(res_geom.getType().value())) { - ((MultiVertexGeometryImpl) res_geom._getImpl()).setIsSimple( - MultiVertexGeometryImpl.GeometryXSimple.Strong, - tolerance, false); - if (res_geom.getType().value() == Geometry.GeometryType.Polygon) - ((MultiPathImpl) res_geom._getImpl())._updateOGCFlags(); - } - - res_vec[res_geom.getDimension()] = res_geom; - } - - return res_vec; - } - - // static - public static Geometry symmetricDifference(Geometry geometry_a, - Geometry geometry_b, SpatialReference sr, - ProgressTracker progress_tracker) { - if (geometry_a.getDimension() > geometry_b.getDimension()) - return normalizeResult_(normalizeInputGeometry_(geometry_a), - geometry_a, geometry_b, '^'); - - if (geometry_a.getDimension() < geometry_b.getDimension()) - return normalizeResult_(normalizeInputGeometry_(geometry_b), - geometry_a, geometry_b, '^'); - - if (geometry_a.isEmpty()) - return normalizeResult_(normalizeInputGeometry_(geometry_b), - geometry_a, geometry_b, '^'); - - if (geometry_b.isEmpty()) - return normalizeResult_(normalizeInputGeometry_(geometry_a), - geometry_a, geometry_b, '^'); - - Envelope2D env2D_1 = new Envelope2D(); - geometry_a.queryEnvelope2D(env2D_1); - Envelope2D env2D_2 = new Envelope2D(); - geometry_b.queryEnvelope2D(env2D_2); - // TODO: add optimization here to merge two geometries if the envelopes - // do not overlap. - - Envelope2D envMerged = new Envelope2D(); - envMerged.setCoords(env2D_1); - envMerged.merge(env2D_2); - double tolerance = InternalUtils.calculateToleranceFromGeometry(sr, - envMerged, true);// conservative to have same effect as simplify - - TopologicalOperations topoOps = new TopologicalOperations(); - EditShape edit_shape = new EditShape(); - int geom_a = edit_shape - .addGeometry(normalizeInputGeometry_(geometry_a)); - int geom_b = edit_shape - .addGeometry(normalizeInputGeometry_(geometry_b)); - topoOps.setEditShapeCrackAndCluster(edit_shape, tolerance, - progress_tracker); - int result = topoOps.symmetricDifference(geom_a, geom_b); - Geometry res_geom = normalizeResult_(edit_shape.getGeometry(result), - geometry_a, geometry_b, '^'); - - if (Geometry.isMultiPath(res_geom.getType().value())) { - ((MultiVertexGeometryImpl) res_geom._getImpl()).setIsSimple( - GeometryXSimple.Strong, tolerance, false); - if (res_geom.getType() == Geometry.Type.Polygon) - ((MultiPathImpl) res_geom._getImpl())._updateOGCFlags(); - } - - return res_geom; - } - - static Geometry _denormalizeGeometry(Geometry geom, Geometry geomA, - Geometry geomB) { - Geometry.Type gtA = geomA.getType(); - Geometry.Type gtB = geomB.getType(); - Geometry.Type gt = geom.getType(); - if (gt == Geometry.Type.MultiPoint) { - if (gtA == Geometry.Type.Point || gtB == Geometry.Type.Point) { - MultiPoint mp = (MultiPoint) geom; - if (mp.getPointCount() <= 1) { - Point pt = new Point(geom.getDescription()); - if (!mp.isEmpty()) - mp.getPointByVal(0, pt); - return (Geometry) pt; - } - } - } - return geom; - } - - private void flushVertices_(int geometry, AttributeStreamOfInt32 vertices) { - EditShape shape = m_topo_graph.getShape(); - int path = shape.insertPath(geometry, -1); - int size = vertices.size(); - // _ASSERT(size != 0); - for (int i = 0; i < size; i++) { - int vertex = vertices.get(i); - shape.addVertex(path, vertex); - } - shape.setClosedPath(path, true);// need to close polygon rings - } - - private void setHalfEdgeOrientations_(int orientationIndex, int cutter) { - EditShape shape = m_topo_graph.getShape(); - - for (int igeometry = shape.getFirstGeometry(); igeometry != -1; igeometry = shape - .getNextGeometry(igeometry)) { - if (igeometry != cutter) - continue; - - for (int ipath = shape.getFirstPath(igeometry); ipath != -1; ipath = shape - .getNextPath(ipath)) { - int ivertex = shape.getFirstVertex(ipath); - if (ivertex == -1) - continue; - - int ivertexNext = shape.getNextVertex(ivertex); - assert (ivertexNext != -1); - - while (ivertexNext != -1) { - int clusterFrom = m_topo_graph - .getClusterFromVertex(ivertex); - int clusterTo = m_topo_graph - .getClusterFromVertex(ivertexNext); - int half_edge = m_topo_graph.getHalfEdgeConnector( - clusterFrom, clusterTo); - - if (half_edge != -1) { - int halfEdgeTwin = m_topo_graph - .getHalfEdgeTwin(half_edge); - m_topo_graph.setHalfEdgeUserIndex(half_edge, - orientationIndex, 1); - m_topo_graph.setHalfEdgeUserIndex(halfEdgeTwin, - orientationIndex, 2); - } - - ivertex = ivertexNext; - ivertexNext = shape.getNextVertex(ivertex); - } - } - } - } - - private void processPolygonCuts_(int orientationIndex, int sideIndex, - int cuttee, int cutter) { - int idCuttee = m_topo_graph.getGeometryID(cuttee); - int idCutter = m_topo_graph.getGeometryID(cutter); - AttributeStreamOfInt32 vertices = new AttributeStreamOfInt32(0); - vertices.reserve(256); - EditShape shape = m_topo_graph.getShape(); - - int visitedIndex = m_topo_graph.createUserIndexForHalfEdges(); - for (int cluster = m_topo_graph.getFirstCluster(); cluster != -1; cluster = m_topo_graph - .getNextCluster(cluster)) { - int firstHalfEdge = m_topo_graph.getClusterHalfEdge(cluster); - - if (firstHalfEdge == -1) - continue; - - int half_edge = firstHalfEdge; - - do { - int visited = m_topo_graph.getHalfEdgeUserIndex(half_edge, - visitedIndex); - if (visited != 1) { - int faceHalfEdge = half_edge; - int toHalfEdge = half_edge; - boolean bFoundCutter = false; - int side = 0; - do { - m_topo_graph.setHalfEdgeUserIndex(faceHalfEdge, - visitedIndex, 1); - if (!bFoundCutter) { - int edgeParentage = m_topo_graph - .getHalfEdgeParentage(faceHalfEdge); - if ((edgeParentage & idCutter) != 0) { - int faceParentage = m_topo_graph - .getHalfEdgeFaceParentage(faceHalfEdge); - if ((faceParentage & idCuttee) != 0) { - toHalfEdge = faceHalfEdge;// reset the loop - bFoundCutter = true; - } - } - } - - if (bFoundCutter) { - int clusterOrigin = m_topo_graph - .getHalfEdgeOrigin(faceHalfEdge); - int iterator = m_topo_graph - .getClusterVertexIterator(clusterOrigin); - assert (iterator != -1); - int vertex = m_topo_graph - .getVertexFromVertexIterator(iterator); - vertices.add(vertex); - - // get side - if (orientationIndex != -1) { - int edgeParentage = m_topo_graph - .getHalfEdgeParentage(faceHalfEdge); - if ((edgeParentage & idCutter) != 0) { - int orientation = m_topo_graph - .getHalfEdgeUserIndex(faceHalfEdge, - orientationIndex); - assert (orientation == 1 || orientation == 2); - side |= orientation; - } - } - } - - int next = m_topo_graph.getHalfEdgeNext(faceHalfEdge); - faceHalfEdge = next; - } while (faceHalfEdge != toHalfEdge); - - if (bFoundCutter - && m_topo_graph.getChainArea(m_topo_graph - .getHalfEdgeChain(toHalfEdge)) > 0.0) {// if - // we - // found - // a - // cutter - // face - // and - // its - // area - // is - // positive, - // then - // add - // the - // cutter - // face - // as - // new - // polygon. - int geometry = shape - .createGeometry(Geometry.Type.Polygon); - flushVertices_(geometry, vertices);// adds the cutter - // face vertices to - // the new polygon - - if (sideIndex != -1) - shape.setGeometryUserIndex(geometry, sideIndex, - side); // what is that? - } - - vertices.clear(false); - } - half_edge = m_topo_graph.getHalfEdgeNext(m_topo_graph - .getHalfEdgeTwin(half_edge)); - } while (half_edge != firstHalfEdge); - } - - m_topo_graph.deleteUserIndexForHalfEdges(visitedIndex); - } - - private void cutPolygonPolyline_(int sideIndex, int cuttee, int cutter, - AttributeStreamOfInt32 cutHandles) { - m_topo_graph.removeSpikes_(); - - int orientationIndex = -1; - if (sideIndex != -1) { - orientationIndex = m_topo_graph.createUserIndexForHalfEdges(); - setHalfEdgeOrientations_(orientationIndex, cutter); - } - - processPolygonCuts_(orientationIndex, sideIndex, cuttee, cutter); - - EditShape shape = m_topo_graph.getShape(); - - int cutCount = 0; - for (int geometry_handle = shape.getFirstGeometry(); geometry_handle != -1; geometry_handle = shape - .getNextGeometry(geometry_handle)) { - if (geometry_handle != cuttee && geometry_handle != cutter) { - cutHandles.add(geometry_handle); - cutCount++; - } - } - - // sort - CompareCuts compareCuts = new CompareCuts(shape); - cutHandles.Sort(0, cutCount, compareCuts); - } - - //call this if EditShape instance has to survive the TopologicalOperations life. - void removeShape() { - if (m_topo_graph != null) { - m_topo_graph.removeShape(); - m_topo_graph = null; - } - - } + TopoGraph m_topo_graph = null; + Point2D m_dummy_pt_1 = new Point2D(); + Point2D m_dummy_pt_2 = new Point2D(); + int m_from_edge_for_polylines; + boolean m_mask_lookup[] = null; + boolean m_bOGCOutput = false; + + boolean isGoodParentage(int parentage) { + return parentage < m_mask_lookup.length ? m_mask_lookup[parentage] + : false; + } + + void cut(int sideIndex, int cuttee, int cutter, + AttributeStreamOfInt32 cutHandles) { + int gtCuttee = m_topo_graph.getShape().getGeometryType(cuttee); + int gtCutter = m_topo_graph.getShape().getGeometryType(cutter); + int dimCuttee = Geometry.getDimensionFromType(gtCuttee); + int dimCutter = Geometry.getDimensionFromType(gtCutter); + + if (dimCuttee == 2 && dimCutter == 1) { + cutPolygonPolyline_(sideIndex, cuttee, cutter, cutHandles); + return; + } + + throw GeometryException.GeometryInternalError(); + } + + static final class CompareCuts extends IntComparator { + private EditShape m_editShape; + + public CompareCuts(EditShape editShape) { + m_editShape = editShape; + } + + @Override + public int compare(int c1, int c2) { + int path1 = m_editShape.getFirstPath(c1); + double area1 = m_editShape.getRingArea(path1); + int path2 = m_editShape.getFirstPath(c2); + double area2 = m_editShape.getRingArea(path2); + if (area1 < area2) + return -1; + if (area1 == area2) + return 0; + return 1; + } + } + + public TopologicalOperations() { + m_from_edge_for_polylines = -1; + } + + void setEditShape(EditShape shape, ProgressTracker progressTracker) { + if (m_topo_graph == null) + m_topo_graph = new TopoGraph(); + m_topo_graph.setEditShape(shape, progressTracker); + } + + void setEditShapeCrackAndCluster(EditShape shape, double tolerance, + ProgressTracker progressTracker) { + CrackAndCluster.execute(shape, tolerance, progressTracker, true); + for (int geometry = shape.getFirstGeometry(); geometry != -1; geometry = shape + .getNextGeometry(geometry)) { + if (shape.getGeometryType(geometry) == Geometry.Type.Polygon + .value()) + Simplificator.execute(shape, geometry, -1, m_bOGCOutput, progressTracker); + } + + setEditShape(shape, progressTracker); + } + + private void collectPolygonPathsPreservingFrom_(int geometryFrom, + int newGeometry, int visitedEdges, int visitedClusters, + int geometry_dominant) { + // This function tries to create polygon paths using the paths that were + // in the input shape. + // This way we preserve original shape as much as possible. + EditShape shape = m_topo_graph.getShape(); + if (shape.getGeometryType(geometryFrom) != Geometry.Type.Polygon + .value()) + return; + + for (int path = shape.getFirstPath(geometryFrom); path != -1; path = shape + .getNextPath(path)) { + int first_vertex = shape.getFirstVertex(path); + int firstCluster = m_topo_graph.getClusterFromVertex(first_vertex); + assert (firstCluster != -1); + int secondVertex = shape.getNextVertex(first_vertex); + int secondCluster = m_topo_graph.getClusterFromVertex(secondVertex); + assert (secondCluster != -1); + + int firstHalfEdge = m_topo_graph + .getHalfEdgeFromVertex(first_vertex); + + if (firstHalfEdge == -1) + continue;// Usually there will be a half-edge that starts at + // first_vertex and goes to secondVertex, but it + // could happen that this half edge has been + // removed. + + assert (m_topo_graph.getHalfEdgeTo(firstHalfEdge) == secondCluster && m_topo_graph + .getHalfEdgeOrigin(firstHalfEdge) == firstCluster); + + int visited = m_topo_graph.getHalfEdgeUserIndex(firstHalfEdge, + visitedEdges); + if (visited == 1 || visited == 2) + continue; + + int parentage = m_topo_graph + .getHalfEdgeFaceParentage(firstHalfEdge); + if (!isGoodParentage(parentage)) { + m_topo_graph.setHalfEdgeUserIndex(firstHalfEdge, visitedEdges, + 2); + continue; + } + + m_topo_graph.setHalfEdgeUserIndex(firstHalfEdge, visitedEdges, 1); + + int newPath = shape.insertPath(newGeometry, -1);// add new path at + // the end + int half_edge = firstHalfEdge; + int vertex = first_vertex; + int cluster = m_topo_graph.getClusterFromVertex(vertex); + int dir = 1; + //Walk the chain of half edges, preferably selecting vertices that belong to the + //polygon path we have started from. + do { + int vertex_dominant = getVertexByID_(vertex, geometry_dominant); + shape.addVertex(newPath, vertex_dominant); + if (visitedClusters != -1) + m_topo_graph.setClusterUserIndex(cluster, visitedClusters, + 1); + + m_topo_graph.setHalfEdgeUserIndex(half_edge, visitedEdges, 1); + half_edge = m_topo_graph.getHalfEdgeNext(half_edge); + int v; + int cv; + do {// move in a loop through coincident vertices (probably + // vertical segments). + v = dir == 1 ? shape.getNextVertex(vertex) : shape + .getPrevVertex(vertex);// if we came to the polyline + // tail, the next may return + // -1. + cv = v != -1 ? m_topo_graph.getClusterFromVertex(v) : -1; + } while (cv == cluster); + + int originCluster = m_topo_graph.getHalfEdgeOrigin(half_edge); + if (originCluster != cv) { + // try going opposite way + do {// move in a loop through coincident vertices (probably + // vertical segments). + v = dir == 1 ? shape.getPrevVertex(vertex) : shape + .getNextVertex(vertex);// if we came to the + // polyline tail, the + // next may return -1. + cv = v != -1 ? m_topo_graph.getClusterFromVertex(v) + : -1; + } while (cv == cluster); + + if (originCluster != cv) {// pick any vertex. + cv = originCluster; + int iterator = m_topo_graph + .getClusterVertexIterator(cv); + v = m_topo_graph.getVertexFromVertexIterator(iterator); + } else { + dir = -dir;// remember direction we were going for + // performance + } + } + cluster = cv; + vertex = v; + } while (half_edge != firstHalfEdge); + + shape.setClosedPath(newPath, true); + } + } + + // processes Topo_graph and removes edges that border faces with good + // parentage + // If bAllowBrokenFaces is True the function will break face structure for + // dissolved faces. Only face parentage will be uasable. + void dissolveCommonEdges_() { + int visitedEdges = m_topo_graph.createUserIndexForHalfEdges(); + AttributeStreamOfInt32 edgesToDelete = new AttributeStreamOfInt32(0); + // Now extract paths that + for (int cluster = m_topo_graph.getFirstCluster(); cluster != -1; cluster = m_topo_graph + .getNextCluster(cluster)) { + int firstHalfEdge = m_topo_graph.getClusterHalfEdge(cluster); + int half_edge = firstHalfEdge; + if (firstHalfEdge == -1) + continue; + + do { + int visited = m_topo_graph.getHalfEdgeUserIndex(half_edge, + visitedEdges); + if (visited != 1) { + int halfEdgeTwin = m_topo_graph.getHalfEdgeTwin(half_edge); + m_topo_graph.setHalfEdgeUserIndex(halfEdgeTwin, + visitedEdges, 1); + m_topo_graph.setHalfEdgeUserIndex(half_edge, visitedEdges, + 1); + int parentage = m_topo_graph + .getHalfEdgeFaceParentage(half_edge); + if (isGoodParentage(parentage)) { + int twinParentage = m_topo_graph + .getHalfEdgeFaceParentage(halfEdgeTwin); + if (isGoodParentage(twinParentage)) { + // This half_edge pair is a border between two faces + // that share the parentage or it is a dangling edge + edgesToDelete.add(half_edge);// remember for + // subsequent delete + } + } + } + + half_edge = m_topo_graph.getHalfEdgeNext(m_topo_graph + .getHalfEdgeTwin(half_edge)); + } while (half_edge != firstHalfEdge); + } + + m_topo_graph.deleteUserIndexForHalfEdges(visitedEdges); + m_topo_graph.deleteEdgesBreakFaces_(edgesToDelete); + } + + int getVertexByID_(int vertex, int geometry_id) { + if (geometry_id == -1) + return vertex; + + return getVertexByIDImpl_(vertex, geometry_id); + } + + int getVertexByIDImpl_(int vertex, int geometry_id) { + EditShape shape = m_topo_graph.getShape(); + int v; + int geometry; + int vertex_iterator = m_topo_graph + .getClusterVertexIterator(m_topo_graph + .getClusterFromVertex(vertex)); + + do { + v = m_topo_graph.getVertexFromVertexIterator(vertex_iterator); + geometry = shape.getGeometryFromPath(shape.getPathFromVertex(v)); + + if (geometry == geometry_id) + return v; + + vertex_iterator = m_topo_graph + .incrementVertexIterator(vertex_iterator); + } while (vertex_iterator != -1); + + return vertex; + } + + private int topoOperationPolygonPolygon_(int geometry_a, int geometry_b, + int geometry_dominant) { + dissolveCommonEdges_();// faces are partially broken after this call. + // See help to this call. + + EditShape shape = m_topo_graph.getShape(); + int newGeometry = shape.createGeometry(Geometry.Type.Polygon); + int visitedEdges = m_topo_graph.createUserIndexForHalfEdges(); + + topoOperationPolygonPolygonHelper_(geometry_a, geometry_b, newGeometry, + geometry_dominant, visitedEdges, -1); + + m_topo_graph.deleteUserIndexForHalfEdges(visitedEdges); + Simplificator.execute(shape, newGeometry, + MultiVertexGeometryImpl.GeometryXSimple.Weak, m_bOGCOutput, null); + return newGeometry; + } + + private void topoOperationPolygonPolygonHelper_(int geometry_a, + int geometry_b, int newGeometryPolygon, int geometry_dominant, + int visitedEdges, int visitedClusters) { + collectPolygonPathsPreservingFrom_(geometry_a, newGeometryPolygon, + visitedEdges, visitedClusters, geometry_dominant); + if (geometry_b != -1) + collectPolygonPathsPreservingFrom_(geometry_b, newGeometryPolygon, + visitedEdges, visitedClusters, geometry_dominant); + + EditShape shape = m_topo_graph.getShape(); + // Now extract polygon paths that has not been extracted on the previous + // step. + for (int cluster = m_topo_graph.getFirstCluster(); cluster != -1; cluster = m_topo_graph + .getNextCluster(cluster)) { + int firstHalfEdge = m_topo_graph.getClusterHalfEdge(cluster); + if (firstHalfEdge == -1) + continue; + + int half_edge = firstHalfEdge; + do { + int visited = m_topo_graph.getHalfEdgeUserIndex(half_edge, + visitedEdges); + if (visited != 1 && visited != 2) { + int parentage = m_topo_graph + .getHalfEdgeFaceParentage(half_edge); + if (isGoodParentage(parentage)) {// Extract face. + int newPath = shape.insertPath(newGeometryPolygon, -1);// add + // new + // path + // at + // the + // end + int faceHalfEdge = half_edge; + do { + int viter = m_topo_graph + .getHalfEdgeVertexIterator(faceHalfEdge); + int v; + if (viter != -1) { + v = m_topo_graph + .getVertexFromVertexIterator(viter); + } else { + int viter1 = m_topo_graph + .getHalfEdgeVertexIterator(m_topo_graph + .getHalfEdgeTwin(faceHalfEdge)); + assert (viter1 != -1); + v = m_topo_graph + .getVertexFromVertexIterator(viter1); + v = m_topo_graph.getShape().getNextVertex(v); + } + + assert (v != -1); + int vertex_dominant = getVertexByID_(v, + geometry_dominant); + shape.addVertex(newPath, vertex_dominant); + assert (isGoodParentage(m_topo_graph + .getHalfEdgeFaceParentage(faceHalfEdge))); + m_topo_graph.setHalfEdgeUserIndex(faceHalfEdge, + visitedEdges, 1);// + + if (visitedClusters != -1) { + int c = m_topo_graph + .getClusterFromVertex(vertex_dominant); + m_topo_graph.setClusterUserIndex(c, + visitedClusters, 1); + } + + faceHalfEdge = m_topo_graph + .getHalfEdgeNext(faceHalfEdge); + } while (faceHalfEdge != half_edge); + + shape.setClosedPath(newPath, true); + } else { + // cannot extract a face + m_topo_graph.setHalfEdgeUserIndex(half_edge, + visitedEdges, 2); + } + + } + + half_edge = m_topo_graph.getHalfEdgeNext(m_topo_graph + .getHalfEdgeTwin(half_edge)); + } while (half_edge != firstHalfEdge); + } + } + + int[] topoOperationPolygonPolygonEx_(int geometry_a, int geometry_b, + int geometry_dominant) { + EditShape shape = m_topo_graph.getShape(); + int newGeometryPolygon = shape.createGeometry(Geometry.Type.Polygon); + int newGeometryPolyline = shape.createGeometry(Geometry.Type.Polyline); + int newGeometryMultipoint = shape + .createGeometry(Geometry.Type.MultiPoint); + + dissolveCommonEdges_();// faces are partially broken after this call. + // See help to this call. + + int multipointPath = -1; + int visitedEdges = m_topo_graph.createUserIndexForHalfEdges(); + int visitedClusters = m_topo_graph.createUserIndexForClusters(); + + topoOperationPolygonPolygonHelper_(geometry_a, geometry_b, + newGeometryPolygon, geometry_dominant, visitedEdges, + visitedClusters); + + for (int cluster = m_topo_graph.getFirstCluster(); cluster != -1; cluster = m_topo_graph + .getNextCluster(cluster)) { + int firstHalfEdge = m_topo_graph.getClusterHalfEdge(cluster); + if (firstHalfEdge == -1) + continue; + + int half_edge = firstHalfEdge; + do { + int visited1 = m_topo_graph.getHalfEdgeUserIndex(half_edge, + visitedEdges); + int visited2 = m_topo_graph.getHalfEdgeUserIndex( + m_topo_graph.getHalfEdgeTwin(half_edge), visitedEdges); + int visited = visited1 | visited2; + if (visited == 2) { + int parentage = m_topo_graph + .getHalfEdgeParentage(half_edge); + if (isGoodParentage(parentage)) {// Extract face. + int newPath = shape.insertPath(newGeometryPolyline, -1);// add + // new + // path + // at + // the + // end + int polyHalfEdge = half_edge; + int vert = selectVertex_(cluster, shape); + assert (vert != -1); + int vertex_dominant = getVertexByID_(vert, + geometry_dominant); + shape.addVertex(newPath, vertex_dominant); + m_topo_graph.setClusterUserIndex(cluster, + visitedClusters, 1); + + do { + int clusterTo = m_topo_graph + .getHalfEdgeTo(polyHalfEdge); + int vert1 = selectVertex_(clusterTo, shape); + assert (vert1 != -1); + int vertex_dominant1 = getVertexByID_(vert1, + geometry_dominant); + shape.addVertex(newPath, vertex_dominant1); + m_topo_graph.setHalfEdgeUserIndex(polyHalfEdge, + visitedEdges, 1);// + m_topo_graph.setHalfEdgeUserIndex( + m_topo_graph.getHalfEdgeTwin(polyHalfEdge), + visitedEdges, 1);// + m_topo_graph.setClusterUserIndex(clusterTo, + visitedClusters, 1); + + polyHalfEdge = m_topo_graph + .getHalfEdgeNext(polyHalfEdge); + visited1 = m_topo_graph.getHalfEdgeUserIndex( + polyHalfEdge, visitedEdges); + visited2 = m_topo_graph.getHalfEdgeUserIndex( + m_topo_graph.getHalfEdgeTwin(polyHalfEdge), + visitedEdges); + visited = visited1 | visited2; + if (visited != 2) + break; + + parentage = m_topo_graph + .getHalfEdgeParentage(polyHalfEdge); + if (!isGoodParentage(parentage)) { + m_topo_graph.setHalfEdgeUserIndex(polyHalfEdge, + visitedEdges, 1); + m_topo_graph.setHalfEdgeUserIndex(m_topo_graph + .getHalfEdgeTwin(polyHalfEdge), + visitedEdges, 1); + break; + } + + } while (polyHalfEdge != half_edge); + + } else { + m_topo_graph.setHalfEdgeUserIndex(half_edge, + visitedEdges, 1); + m_topo_graph.setHalfEdgeUserIndex( + m_topo_graph.getHalfEdgeTwin(half_edge), + visitedEdges, 1); + } + } + + half_edge = m_topo_graph.getHalfEdgeNext(m_topo_graph + .getHalfEdgeTwin(half_edge)); + } while (half_edge != firstHalfEdge); + } + + for (int cluster = m_topo_graph.getFirstCluster(); cluster != -1; cluster = m_topo_graph + .getNextCluster(cluster)) { + int visited = m_topo_graph.getClusterUserIndex(cluster, + visitedClusters); + if (visited == 1) + continue; + + int parentage = m_topo_graph.getClusterParentage(cluster); + if (isGoodParentage(parentage)) { + if (multipointPath == -1) + multipointPath = shape + .insertPath(newGeometryMultipoint, -1); + int viter = m_topo_graph.getClusterVertexIterator(cluster); + int v; + if (viter != -1) { + v = m_topo_graph.getVertexFromVertexIterator(viter); + int vertex_dominant = getVertexByID_(v, geometry_dominant); + shape.addVertex(multipointPath, vertex_dominant); + } + } + } + + m_topo_graph.deleteUserIndexForClusters(visitedClusters); + m_topo_graph.deleteUserIndexForHalfEdges(visitedEdges); + Simplificator.execute(shape, newGeometryPolygon, + MultiVertexGeometryImpl.GeometryXSimple.Weak, m_bOGCOutput, null); + int[] result = new int[3];// always returns size 3 result. + + result[0] = newGeometryMultipoint; + result[1] = newGeometryPolyline; + result[2] = newGeometryPolygon; + return result; + } + + int selectVertex_(int cluster, EditShape shape) { + int vert = -1; + for (int iterator = m_topo_graph.getClusterVertexIterator(cluster); iterator != -1; iterator = m_topo_graph + .incrementVertexIterator(iterator)) { + int vertex = m_topo_graph.getVertexFromVertexIterator(iterator); + if (vert == -1) + vert = vertex; + int geometry = shape.getGeometryFromPath(shape + .getPathFromVertex(vertex)); + int geomID = m_topo_graph.getGeometryID(geometry); + if (isGoodParentage(geomID)) { + vert = vertex; + break; + } + } + + return vert; + } + + private double prevailingDirection_(EditShape shape, int half_edge) { + int cluster = m_topo_graph.getHalfEdgeOrigin(half_edge); + int clusterTo = m_topo_graph.getHalfEdgeTo(half_edge); + int signTotal = 0; + int signCorrect = 0; + for (int iterator = m_topo_graph.getClusterVertexIterator(cluster); iterator != -1; iterator = m_topo_graph + .incrementVertexIterator(iterator)) { + int vertex = m_topo_graph.getVertexFromVertexIterator(iterator); + int path = shape.getPathFromVertex(vertex); + int geometry = shape.getGeometryFromPath(path); + int geomID = m_topo_graph.getGeometryID(geometry); + int nextVert = shape.getNextVertex(vertex); + int prevVert = shape.getPrevVertex(vertex); + + int firstVert = shape.getFirstVertex(path); + if (firstVert == vertex) {// remember the first half edge of the + // path. We use it to produce correct + // startpath for closed polyline loops + m_from_edge_for_polylines = half_edge; + } + + if (nextVert != -1 + && m_topo_graph.getClusterFromVertex(nextVert) == clusterTo) { + signTotal++; + if (isGoodParentage(geomID)) { + if (firstVert == nextVert) {// remember the first vertex of + // the path. We use it to + // produce correct startpath for + // closed polyline loops + m_from_edge_for_polylines = m_topo_graph + .getHalfEdgeNext(half_edge); + } + + // update the sign + signCorrect++; + } + } else if (prevVert != -1 + && m_topo_graph.getClusterFromVertex(prevVert) == clusterTo) { + signTotal--; + if (isGoodParentage(geomID)) { + if (firstVert == prevVert) {// remember the first vertex of + // the path. We use it to + // produce correct startpath for + // closed polyline loops + m_from_edge_for_polylines = m_topo_graph + .getHalfEdgeNext(half_edge); + } + + // update the sign + signCorrect--; + } + } + } + + m_topo_graph.getXY(cluster, m_dummy_pt_1); + m_topo_graph.getXY(clusterTo, m_dummy_pt_2); + double len = Point2D.distance(m_dummy_pt_1, m_dummy_pt_2); + return (signCorrect != 0 ? signCorrect : signTotal) * len; + } + + int getCombinedHalfEdgeParentage_(int e) { + return m_topo_graph.getHalfEdgeParentage(e) + | m_topo_graph.getHalfEdgeFaceParentage(e) + | m_topo_graph.getHalfEdgeFaceParentage(m_topo_graph + .getHalfEdgeTwin(e)); + } + + int tryMoveThroughCrossroadBackwards_(int half_edge) { + int e = m_topo_graph.getHalfEdgeTwin(m_topo_graph + .getHalfEdgePrev(half_edge)); + int goodEdge = -1; + while (e != half_edge) { + int parentage = getCombinedHalfEdgeParentage_(e); + if (isGoodParentage(parentage)) { + if (goodEdge != -1) + return -1; + + goodEdge = e; + } + + e = m_topo_graph.getHalfEdgeTwin(m_topo_graph.getHalfEdgePrev(e)); + } + + return goodEdge != -1 ? m_topo_graph.getHalfEdgeTwin(goodEdge) : -1; + } + + int tryMoveThroughCrossroadForward_(int half_edge) { + int e = m_topo_graph.getHalfEdgeTwin(m_topo_graph + .getHalfEdgeNext(half_edge)); + int goodEdge = -1; + while (e != half_edge) { + int parentage = getCombinedHalfEdgeParentage_(e); + if (isGoodParentage(parentage)) { + if (goodEdge != -1) + return -1;// more than one way to move through the + // intersection + goodEdge = e; + } + + e = m_topo_graph.getHalfEdgeTwin(m_topo_graph.getHalfEdgeNext(e)); + } + + return goodEdge != -1 ? m_topo_graph.getHalfEdgeTwin(goodEdge) : -1; + } + + private void restorePolylineParts_(int first_edge, int newGeometry, + int visitedEdges, int visitedClusters, int geometry_dominant) { + assert (isGoodParentage(getCombinedHalfEdgeParentage_(first_edge))); + EditShape shape = m_topo_graph.getShape(); + int half_edge = first_edge; + int halfEdgeTwin = m_topo_graph.getHalfEdgeTwin(half_edge); + m_topo_graph.setHalfEdgeUserIndex(half_edge, visitedEdges, 1); + m_topo_graph.setHalfEdgeUserIndex(halfEdgeTwin, visitedEdges, 1); + double prevailingLength = prevailingDirection_(shape, half_edge);// prevailing + // direction + // is + // used + // to + // figure + // out + // the + // polyline + // direction. + // Prevailing length is the sum of the length of vectors that constitute + // the polyline. + // Vector length is positive, if the halfedge direction coincides with + // the direction of the original geometry + // and negative otherwise. + + m_from_edge_for_polylines = -1; + int fromEdge = half_edge; + int toEdge = -1; + boolean b_found_impassable_crossroad = false; + int edgeCount = 1; + while (true) { + int halfEdgePrev = m_topo_graph.getHalfEdgePrev(half_edge); + if (halfEdgePrev == halfEdgeTwin) + break;// the end of a polyline + + int halfEdgeTwinNext = m_topo_graph.getHalfEdgeNext(halfEdgeTwin); + if (m_topo_graph.getHalfEdgeTwin(halfEdgePrev) != halfEdgeTwinNext) { + // Crossroads is here. We can move through the crossroad only if + // there is only a single way to pass through. + //When doing planar_simplify we'll never go through the crossroad. + half_edge = tryMoveThroughCrossroadBackwards_(half_edge); + if (half_edge == -1) + break; + else { + b_found_impassable_crossroad = true; + halfEdgeTwin = m_topo_graph.getHalfEdgeTwin(half_edge); + } + } else { + half_edge = halfEdgePrev; + halfEdgeTwin = halfEdgeTwinNext; + } + + if (half_edge == first_edge) {// we are in a loop. No need to search + // for the toEdge. Just remember the + // toEdge and skip the next while + // loop. + toEdge = first_edge; + break; + } + int parentage = getCombinedHalfEdgeParentage_(half_edge); + if (!isGoodParentage(parentage)) + break; + + m_topo_graph.setHalfEdgeUserIndex(half_edge, visitedEdges, 1); + m_topo_graph.setHalfEdgeUserIndex(halfEdgeTwin, visitedEdges, 1); + fromEdge = half_edge; + prevailingLength += prevailingDirection_(shape, half_edge); + edgeCount++; + } + + if (toEdge == -1) { + half_edge = first_edge; + halfEdgeTwin = m_topo_graph.getHalfEdgeTwin(half_edge); + toEdge = half_edge; + while (true) { + int halfEdgeNext = m_topo_graph.getHalfEdgeNext(half_edge); + if (halfEdgeNext == halfEdgeTwin) + break; + + int halfEdgeTwinPrev = m_topo_graph + .getHalfEdgePrev(halfEdgeTwin); + if (m_topo_graph.getHalfEdgeTwin(halfEdgeNext) != halfEdgeTwinPrev) { + // Crossroads is here. We can move through the crossroad + // only if there is only a single way to pass through. + half_edge = tryMoveThroughCrossroadForward_(half_edge); + if (half_edge == -1) { + b_found_impassable_crossroad = true; + break; + } else + halfEdgeTwin = m_topo_graph.getHalfEdgeTwin(half_edge); + } else { + half_edge = halfEdgeNext; + halfEdgeTwin = halfEdgeTwinPrev; + } + + int parentage = getCombinedHalfEdgeParentage_(half_edge); + if (!isGoodParentage(parentage)) + break; + + m_topo_graph.setHalfEdgeUserIndex(half_edge, visitedEdges, 1); + m_topo_graph + .setHalfEdgeUserIndex(halfEdgeTwin, visitedEdges, 1); + toEdge = half_edge; + prevailingLength += prevailingDirection_(shape, half_edge); + edgeCount++; + } + } else { + // toEdge has been found in the first while loop. This happens when + // we go around a face. + // Closed loops need special processing as we do not know where the + // polyline started or ended. + + if (m_from_edge_for_polylines != -1) { + fromEdge = m_from_edge_for_polylines; + toEdge = m_topo_graph + .getHalfEdgePrev(m_from_edge_for_polylines);// try + // simply + // getting + // prev + int fromEdgeTwin = m_topo_graph.getHalfEdgeTwin(fromEdge); + int fromEdgeTwinNext = m_topo_graph + .getHalfEdgeNext(fromEdgeTwin); + if (m_topo_graph.getHalfEdgeTwin(toEdge) != fromEdgeTwinNext) { + // Crossroads is here. Pass through the crossroad. + toEdge = tryMoveThroughCrossroadBackwards_(fromEdge); + if (toEdge == -1) + throw GeometryException.GeometryInternalError();// what? + } + + assert (isGoodParentage(getCombinedHalfEdgeParentage_(m_from_edge_for_polylines))); + assert (isGoodParentage(getCombinedHalfEdgeParentage_(toEdge))); + } + } + + boolean dir = prevailingLength >= 0; + if (!dir) { + int e = toEdge; + toEdge = fromEdge; + fromEdge = e; + toEdge = m_topo_graph.getHalfEdgeTwin(toEdge);// switch to twin so + // that we can use + // next instead of + // Prev + assert (isGoodParentage(getCombinedHalfEdgeParentage_(toEdge))); + fromEdge = m_topo_graph.getHalfEdgeTwin(fromEdge); + assert (isGoodParentage(getCombinedHalfEdgeParentage_(fromEdge))); + } + + int newPath = shape.insertPath(newGeometry, -1);// add new path at the + // end + half_edge = fromEdge; + int cluster = m_topo_graph.getHalfEdgeOrigin(fromEdge); + int clusterLast = m_topo_graph.getHalfEdgeTo(toEdge); + boolean b_closed = clusterLast == cluster; + // The linestrings can touch at boundary points only, while closed path + // has no boundary, therefore no other path can touch it. + // Therefore, if a closed path touches another path, we need to split + // the closed path in two to make the result OGC simple. + boolean b_closed_linestring_touches_other_linestring = b_closed + && b_found_impassable_crossroad; + + int vert = selectVertex_(cluster, shape); + assert (vert != -1); + int vertex_dominant = getVertexByID_(vert, geometry_dominant); + shape.addVertex(newPath, vertex_dominant); + + if (visitedClusters != -1) { + m_topo_graph.setClusterUserIndex(cluster, visitedClusters, 1); + } + + int counter = 0; + int splitAt = b_closed_linestring_touches_other_linestring ? (edgeCount + 1) / 2 : -1; + while (true) { + int clusterTo = m_topo_graph.getHalfEdgeTo(half_edge); + int vert_1 = selectVertex_(clusterTo, shape); + vertex_dominant = getVertexByID_(vert_1, geometry_dominant); + shape.addVertex(newPath, vertex_dominant); + counter++; + if (visitedClusters != -1) { + m_topo_graph.setClusterUserIndex(clusterTo, visitedClusters, 1); + } + + if (b_closed_linestring_touches_other_linestring + && counter == splitAt) { + newPath = shape.insertPath(newGeometry, -1);// add new path at + // the end + shape.addVertex(newPath, vertex_dominant); + } + + assert (isGoodParentage(getCombinedHalfEdgeParentage_(half_edge))); + if (half_edge == toEdge) + break; + + int halfEdgeNext = m_topo_graph.getHalfEdgeNext(half_edge); + if (m_topo_graph.getHalfEdgePrev(m_topo_graph + .getHalfEdgeTwin(half_edge)) != m_topo_graph + .getHalfEdgeTwin(halfEdgeNext)) {// crossroads. + half_edge = tryMoveThroughCrossroadForward_(half_edge); + if (half_edge == -1) + throw GeometryException.GeometryInternalError();// a bug. This + // shoulf + // never + // happen + } else + half_edge = halfEdgeNext; + } + } + + private int topoOperationPolylinePolylineOrPolygon_(int geometry_dominant) { + EditShape shape = m_topo_graph.getShape(); + int newGeometry = shape.createGeometry(Geometry.Type.Polyline); + int visitedEdges = m_topo_graph.createUserIndexForHalfEdges(); + + for (int cluster = m_topo_graph.getFirstCluster(); cluster != -1; cluster = m_topo_graph + .getNextCluster(cluster)) { + int firstClusterHalfEdge = m_topo_graph.getClusterHalfEdge(cluster); + int clusterHalfEdge = firstClusterHalfEdge; + do { + int visited = m_topo_graph.getHalfEdgeUserIndex( + clusterHalfEdge, visitedEdges); + if (visited != 1) { + int parentage = getCombinedHalfEdgeParentage_(clusterHalfEdge); + if (isGoodParentage(parentage)) { + restorePolylineParts_(clusterHalfEdge, newGeometry, + visitedEdges, -1, geometry_dominant); + } else { + // + } + } + + clusterHalfEdge = m_topo_graph.getHalfEdgeNext(m_topo_graph + .getHalfEdgeTwin(clusterHalfEdge)); + } while (clusterHalfEdge != firstClusterHalfEdge); + } + + m_topo_graph.deleteUserIndexForHalfEdges(visitedEdges); + return newGeometry; + } + + int[] topoOperationPolylinePolylineOrPolygonEx_(int geometry_dominant) { + EditShape shape = m_topo_graph.getShape(); + int newPolyline = shape.createGeometry(Geometry.Type.Polyline); + int newMultipoint = shape.createGeometry(Geometry.Type.MultiPoint); + int visitedEdges = m_topo_graph.createUserIndexForHalfEdges(); + int visitedClusters = m_topo_graph.createUserIndexForClusters(); + int multipointPath = -1; + for (int cluster = m_topo_graph.getFirstCluster(); cluster != -1; cluster = m_topo_graph + .getNextCluster(cluster)) { + int firstClusterHalfEdge = m_topo_graph.getClusterHalfEdge(cluster); + int clusterHalfEdge = firstClusterHalfEdge; + do { + int visited = m_topo_graph.getHalfEdgeUserIndex( + clusterHalfEdge, visitedEdges); + if (visited != 1) { + int parentage = getCombinedHalfEdgeParentage_(clusterHalfEdge); + if (isGoodParentage(parentage)) { + restorePolylineParts_(clusterHalfEdge, newPolyline, + visitedEdges, visitedClusters, + geometry_dominant); + } else { + // + } + } + + clusterHalfEdge = m_topo_graph.getHalfEdgeNext(m_topo_graph + .getHalfEdgeTwin(clusterHalfEdge)); + } while (clusterHalfEdge != firstClusterHalfEdge); + } + + for (int cluster = m_topo_graph.getFirstCluster(); cluster != -1; cluster = m_topo_graph + .getNextCluster(cluster)) { + int visited = m_topo_graph.getClusterUserIndex(cluster, + visitedClusters); + if (visited != 1) { + int parentage = m_topo_graph.getClusterParentage(cluster); + if (isGoodParentage(parentage)) { + if (multipointPath == -1) + multipointPath = shape.insertPath(newMultipoint, -1); + + int viter = m_topo_graph.getClusterVertexIterator(cluster); + int v; + if (viter != -1) { + v = m_topo_graph.getVertexFromVertexIterator(viter); + int vertex_dominant = getVertexByID_(v, + geometry_dominant); + shape.addVertex(multipointPath, vertex_dominant); + } + } else { + // + } + } + } + + m_topo_graph.deleteUserIndexForHalfEdges(visitedEdges); + m_topo_graph.deleteUserIndexForClusters(visitedClusters); + int[] result = new int[2]; + result[0] = newMultipoint; + result[1] = newPolyline; + return result; + } + + private int topoOperationMultiPoint_() { + EditShape shape = m_topo_graph.getShape(); + int newGeometry = shape.createGeometry(Geometry.Type.MultiPoint); + int newPath = shape.insertPath(newGeometry, -1);// add new path at the + // end + + // Now extract paths that + for (int cluster = m_topo_graph.getFirstCluster(); cluster != -1; cluster = m_topo_graph + .getNextCluster(cluster)) { + int parentage = m_topo_graph.getClusterParentage(cluster); + if (isGoodParentage(parentage)) { + int vert = -1; + for (int iterator = m_topo_graph + .getClusterVertexIterator(cluster); iterator != -1; iterator = m_topo_graph + .incrementVertexIterator(iterator)) { + int vertex = m_topo_graph + .getVertexFromVertexIterator(iterator); + if (vert == -1) + vert = vertex; + int geometry = shape.getGeometryFromPath(shape + .getPathFromVertex(vertex)); + int geomID = m_topo_graph.getGeometryID(geometry); + if (isGoodParentage(geomID)) { + vert = vertex; + break; + } + } + assert (vert != -1); + shape.addVertex(newPath, vert); + } + } + + return newGeometry; + } + + void initMaskLookupArray_(int len) { + m_mask_lookup = new boolean[len]; + for (int i = 0; i < len; i++) { + m_mask_lookup[i] = false; + } + } + + static MultiPoint processMultiPointIntersectOrDiff_(MultiPoint multi_point, + Geometry intersector, double tolerance, boolean bClipIn) { + MultiPoint multi_point_out = ((MultiPoint) multi_point.createInstance()); + Point2D[] input_points = new Point2D[1000]; + PolygonUtils.PiPResult[] test_results = new PolygonUtils.PiPResult[1000]; + int npoints = multi_point.getPointCount(); + boolean bFirstOut = true; + boolean bArea = (intersector.getDimension() == 2); + if (intersector.getDimension() != 1 && intersector.getDimension() != 2) + throw GeometryException.GeometryInternalError(); + + for (int ipoints = 0; ipoints < npoints; ) { + int num = multi_point.queryCoordinates(input_points, 1000, ipoints, + -1) - ipoints; + + if (bArea) + PolygonUtils.testPointsInArea2D(intersector, input_points, + (int) num, tolerance, test_results); + else + PolygonUtils.testPointsOnLine2D(intersector, input_points, + (int) num, tolerance, test_results); + int i0 = 0; + for (int i = 0; i < num; i++) { + boolean bTest = test_results[i] == PolygonUtils.PiPResult.PiPOutside; + if (!bClipIn) + bTest = !bTest; + + if (bTest) { + if (bFirstOut) { + bFirstOut = false; + multi_point_out.add(multi_point, 0, ipoints); + } + + if (i0 != i) + multi_point_out.add(multi_point, ipoints + i0, ipoints + + i); + + i0 = i + 1; + } + } + + if (!bFirstOut && i0 != num) + multi_point_out.add(multi_point, ipoints + i0, ipoints + num); + + ipoints += num; + } + + if (bFirstOut) + return multi_point; + + return multi_point_out; + } + + static MultiPoint intersection(MultiPoint multi_point, Geometry multi_path, + double tolerance) { + return processMultiPointIntersectOrDiff_(multi_point, multi_path, + tolerance, true); + } + + static MultiPoint difference(MultiPoint multi_point, Geometry multi_path, + double tolerance) { + return processMultiPointIntersectOrDiff_(multi_point, multi_path, + tolerance, false); + } + + static Point processPointIntersectOrDiff_(Point point, + Geometry intersector, double tolerance, boolean bClipIn) { + if (point.isEmpty()) + return ((Point) point.createInstance()); + if (intersector.isEmpty()) { + return bClipIn ? ((Point) point.createInstance()) : null; + } + + Point2D[] input_points = new Point2D[1]; + PolygonUtils.PiPResult[] test_results = new PolygonUtils.PiPResult[1]; + boolean bArea = intersector.getDimension() == 2; + if (intersector.getDimension() != 1 && intersector.getDimension() != 2) + throw GeometryException.GeometryInternalError(); + input_points[0] = point.getXY(); + if (bArea) + PolygonUtils.testPointsInArea2D(intersector, input_points, 1, + tolerance, test_results); + else + PolygonUtils.testPointsOnLine2D(intersector, input_points, 1, + tolerance, test_results); + + boolean bTest = test_results[0] == PolygonUtils.PiPResult.PiPOutside; + if (!bClipIn) + bTest = !bTest; + + if (!bTest) + return point; + else + return ((Point) point.createInstance()); + } + + static Point intersection(Point point, Geometry geom, double tolerance) { + return processPointIntersectOrDiff_(point, geom, tolerance, true); + } + + static Point difference(Point point, Geometry geom, double tolerance) { + return processPointIntersectOrDiff_(point, geom, tolerance, false); + } + + static Point intersection(Point point, Point point2, double tolerance) { + if (point.isEmpty() || point2.isEmpty()) + return (Point) point.createInstance(); + + if (CrackAndCluster.non_empty_points_need_to_cluster(tolerance, point, + point2)) { + return CrackAndCluster.cluster_non_empty_points(point, point2, 1, + 1, 1, 1); + } + + return (Point) point.createInstance(); + } + + static Point difference(Point point, Point point2, double tolerance) { + if (point.isEmpty()) + return (Point) point.createInstance(); + if (point2.isEmpty()) + return point; + + if (CrackAndCluster.non_empty_points_need_to_cluster(tolerance, point, + point2)) { + return (Point) point.createInstance(); + } + + return point; + } + + MultiVertexGeometry planarSimplifyImpl_(MultiVertexGeometry input_geom, + double tolerance, boolean b_use_winding_rule_for_polygons, + boolean dirty_result, ProgressTracker progress_tracker) { + if (input_geom.isEmpty()) + return input_geom; + + EditShape shape = new EditShape(); + int geom = shape.addGeometry(input_geom); + return planarSimplify(shape, geom, tolerance, + b_use_winding_rule_for_polygons, dirty_result, progress_tracker); + } + + MultiVertexGeometry planarSimplify(EditShape shape, int geom, + double tolerance, boolean b_use_winding_rule_for_polygons, + boolean dirty_result, ProgressTracker progress_tracker) { + // This method will produce a polygon from a polyline when + // b_use_winding_rule_for_polygons is true. This is used by buffer. + m_topo_graph = new TopoGraph(); + try { + if (dirty_result + && shape.getGeometryType(geom) != Geometry.Type.MultiPoint + .value()) { + PlaneSweepCrackerHelper plane_sweeper = new PlaneSweepCrackerHelper(); + plane_sweeper.sweepVertical(shape, tolerance); + if (plane_sweeper.hadCompications())// shame. The one pass + // planesweep had some + // complications. Need to do + // full crack and cluster. + { + CrackAndCluster.execute(shape, tolerance, progress_tracker, true); + dirty_result = false; + } else { + m_topo_graph.check_dirty_planesweep(tolerance); + } + } else { + CrackAndCluster.execute(shape, tolerance, progress_tracker, true); + dirty_result = false; + } + + if (!b_use_winding_rule_for_polygons + || shape.getGeometryType(geom) == Geometry.Type.MultiPoint + .value()) + m_topo_graph.setAndSimplifyEditShapeAlternate(shape, geom, progress_tracker); + else + m_topo_graph.setAndSimplifyEditShapeWinding(shape, geom, progress_tracker); + + if (m_topo_graph.dirty_check_failed()) { + // we ran the sweep_vertical() before and it produced some + // issues that where detected by topo graph only. + assert (dirty_result); + m_topo_graph.removeShape(); + m_topo_graph = null; + // that's at most two level recursion + return planarSimplify(shape, geom, tolerance, + b_use_winding_rule_for_polygons, false, + progress_tracker); + } else { + //can proceed + } + + m_topo_graph.check_dirty_planesweep(NumberUtils.TheNaN); + + int ID_a = m_topo_graph.getGeometryID(geom); + initMaskLookupArray_((ID_a) + 1); + m_mask_lookup[ID_a] = true; // Works only when there is a single + // geometry in the edit shape. + // To make it work when many geometries are present, this need to be + // modified. + + if (shape.getGeometryType(geom) == Geometry.Type.Polygon.value() + || (b_use_winding_rule_for_polygons && shape + .getGeometryType(geom) != Geometry.Type.MultiPoint + .value())) { + // geom can be a polygon or a polyline. + // It can be a polyline only when the winding rule is true. + shape.setFillRule(geom, Polygon.FillRule.enumFillRuleOddEven); + int resGeom = topoOperationPolygonPolygon_(geom, -1, -1); + + Polygon polygon = (Polygon) shape.getGeometry(resGeom); + polygon.setFillRule(Polygon.FillRule.enumFillRuleOddEven);//standardize the fill rule. + if (!dirty_result) { + ((MultiVertexGeometryImpl) polygon._getImpl()).setIsSimple( + GeometryXSimple.Strong, tolerance, false); + ((MultiPathImpl) polygon._getImpl())._updateOGCFlags(); + } else + ((MultiVertexGeometryImpl) polygon._getImpl()).setIsSimple( + GeometryXSimple.Weak, 0.0, false);// dirty result means + // simple but with 0 + // tolerance. + + return polygon; + } else if (shape.getGeometryType(geom) == Geometry.Type.Polyline + .value()) { + int resGeom = topoOperationPolylinePolylineOrPolygon_(-1); + + Polyline polyline = (Polyline) shape.getGeometry(resGeom); + if (!dirty_result) + ((MultiVertexGeometryImpl) polyline._getImpl()).setIsSimple( + GeometryXSimple.Strong, tolerance, false); + + return polyline; + } else if (shape.getGeometryType(geom) == Geometry.Type.MultiPoint + .value()) { + int resGeom = topoOperationMultiPoint_(); + + MultiPoint mp = (MultiPoint) shape.getGeometry(resGeom); + if (!dirty_result) + ((MultiVertexGeometryImpl) mp._getImpl()).setIsSimple( + GeometryXSimple.Strong, tolerance, false); + + return mp; + } else { + throw GeometryException.GeometryInternalError(); + } + } finally { + m_topo_graph.removeShape(); + } + } + + // static + static MultiVertexGeometry planarSimplify(MultiVertexGeometry input_geom, + double tolerance, boolean use_winding_rule_for_polygons, + boolean dirty_result, ProgressTracker progress_tracker) { + TopologicalOperations topoOps = new TopologicalOperations(); + return topoOps.planarSimplifyImpl_(input_geom, tolerance, + use_winding_rule_for_polygons, dirty_result, progress_tracker); + } + + boolean planarSimplifyNoCrackingAndCluster(boolean OGCoutput, EditShape shape, int geom, ProgressTracker progress_tracker) { + m_bOGCOutput = OGCoutput; + m_topo_graph = new TopoGraph(); + int rule = shape.getFillRule(geom); + int gt = shape.getGeometryType(geom); + if (rule != Polygon.FillRule.enumFillRuleWinding || gt == GeometryType.MultiPoint) + m_topo_graph.setAndSimplifyEditShapeAlternate(shape, geom, progress_tracker); + else + m_topo_graph.setAndSimplifyEditShapeWinding(shape, geom, progress_tracker); + + if (m_topo_graph.dirty_check_failed()) + return false; + + m_topo_graph.check_dirty_planesweep(NumberUtils.TheNaN); + + int ID_a = m_topo_graph.getGeometryID(geom); + initMaskLookupArray_((ID_a) + 1); + m_mask_lookup[ID_a] = true; //Works only when there is a single geometry in the edit shape. + //To make it work when many geometries are present, this need to be modified. + + if (shape.getGeometryType(geom) == GeometryType.Polygon || (rule == Polygon.FillRule.enumFillRuleWinding && shape.getGeometryType(geom) != GeometryType.MultiPoint)) { + //geom can be a polygon or a polyline. + //It can be a polyline only when the winding rule is true. + shape.setFillRule(geom, Polygon.FillRule.enumFillRuleOddEven); + int resGeom = topoOperationPolygonPolygon_(geom, -1, -1); + shape.swapGeometry(resGeom, geom); + shape.removeGeometry(resGeom); + } else if (shape.getGeometryType(geom) == GeometryType.Polyline) { + int resGeom = topoOperationPolylinePolylineOrPolygon_(-1); + shape.swapGeometry(resGeom, geom); + shape.removeGeometry(resGeom); + } else if (shape.getGeometryType(geom) == GeometryType.MultiPoint) { + int resGeom = topoOperationMultiPoint_(); + shape.swapGeometry(resGeom, geom); + shape.removeGeometry(resGeom); + } else { + throw new GeometryException("internal error"); + } + + return true; + } + + + static MultiVertexGeometry simplifyOGC(MultiVertexGeometry input_geom, double tolerance, boolean dirty_result, ProgressTracker progress_tracker) { + TopologicalOperations topoOps = new TopologicalOperations(); + topoOps.m_bOGCOutput = true; + return topoOps.planarSimplifyImpl_(input_geom, tolerance, false, dirty_result, progress_tracker); + } + + public int difference(int geometry_a, int geometry_b) { + int gtA = m_topo_graph.getShape().getGeometryType(geometry_a); + int gtB = m_topo_graph.getShape().getGeometryType(geometry_b); + int dim_a = Geometry.getDimensionFromType(gtA); + int dim_b = Geometry.getDimensionFromType(gtB); + if (dim_a > dim_b) { + return geometry_a; + } + + int ID_a = m_topo_graph.getGeometryID(geometry_a); + int ID_b = m_topo_graph.getGeometryID(geometry_b); + initMaskLookupArray_((ID_a | ID_b) + 1); + m_mask_lookup[m_topo_graph.getGeometryID(geometry_a)] = true; + + if (dim_a == 2 && dim_b == 2) + return topoOperationPolygonPolygon_(geometry_a, geometry_b, -1); + if (dim_a == 1 && dim_b == 2) + return topoOperationPolylinePolylineOrPolygon_(-1); + if (dim_a == 1 && dim_b == 1) + return topoOperationPolylinePolylineOrPolygon_(-1); + if (dim_a == 0) + return topoOperationMultiPoint_(); + + throw GeometryException.GeometryInternalError(); + } + + int dissolve(int geometry_a, int geometry_b) { + int gtA = m_topo_graph.getShape().getGeometryType(geometry_a); + int gtB = m_topo_graph.getShape().getGeometryType(geometry_b); + int dim_a = Geometry.getDimensionFromType(gtA); + int dim_b = Geometry.getDimensionFromType(gtB); + if (dim_a > dim_b) { + return geometry_a; + } + + if (dim_a < dim_b) { + return geometry_b; + } + + int ID_a = m_topo_graph.getGeometryID(geometry_a); + int ID_b = m_topo_graph.getGeometryID(geometry_b); + initMaskLookupArray_(((ID_a | ID_b) + 1)); + + m_mask_lookup[m_topo_graph.getGeometryID(geometry_a)] = true; + m_mask_lookup[m_topo_graph.getGeometryID(geometry_b)] = true; + m_mask_lookup[m_topo_graph.getGeometryID(geometry_a) + | m_topo_graph.getGeometryID(geometry_b)] = true; + + if (dim_a == 2 && dim_b == 2) + return topoOperationPolygonPolygon_(geometry_a, geometry_b, -1); + if (dim_a == 1 && dim_b == 1) + return topoOperationPolylinePolylineOrPolygon_(-1); + if (dim_a == 0 && dim_b == 0) + return topoOperationMultiPoint_(); + + throw GeometryException.GeometryInternalError(); + } + + public int intersection(int geometry_a, int geometry_b) { + int gtA = m_topo_graph.getShape().getGeometryType(geometry_a); + int gtB = m_topo_graph.getShape().getGeometryType(geometry_b); + int dim_a = Geometry.getDimensionFromType(gtA); + int dim_b = Geometry.getDimensionFromType(gtB); + + int ID_a = m_topo_graph.getGeometryID(geometry_a); + int ID_b = m_topo_graph.getGeometryID(geometry_b); + initMaskLookupArray_(((ID_a | ID_b) + 1)); + + m_mask_lookup[m_topo_graph.getGeometryID(geometry_a) + | m_topo_graph.getGeometryID(geometry_b)] = true; + + int geometry_dominant = -1; + boolean b_vertex_dominance = (m_topo_graph.getShape() + .getVertexDescription().getAttributeCount() > 1); + if (b_vertex_dominance) + geometry_dominant = geometry_a; + + if (dim_a == 2 && dim_b == 2)// intersect two polygons + return topoOperationPolygonPolygon_(geometry_a, geometry_b, + geometry_dominant); + if ((dim_a == 1 && dim_b > 0) || (dim_b == 1 && dim_a > 0))// intersect + // polyline + // with + // polyline + // or + // polygon + return topoOperationPolylinePolylineOrPolygon_(geometry_dominant); + if (dim_a == 0 || dim_b == 0)// intersect a multipoint with something + // else + return topoOperationMultiPoint_(); + + throw GeometryException.GeometryInternalError(); + } + + int[] intersectionEx(int geometry_a, int geometry_b) { + int gtA = m_topo_graph.getShape().getGeometryType(geometry_a); + int gtB = m_topo_graph.getShape().getGeometryType(geometry_b); + int dim_a = Geometry.getDimensionFromType(gtA); + int dim_b = Geometry.getDimensionFromType(gtB); + + int ID_a = m_topo_graph.getGeometryID(geometry_a); + int ID_b = m_topo_graph.getGeometryID(geometry_b); + initMaskLookupArray_(((ID_a | ID_b) + 1)); + + m_mask_lookup[m_topo_graph.getGeometryID(geometry_a) + | m_topo_graph.getGeometryID(geometry_b)] = true; + + int geometry_dominant = -1; + boolean b_vertex_dominance = (m_topo_graph.getShape() + .getVertexDescription().getAttributeCount() > 1); + if (b_vertex_dominance) + geometry_dominant = geometry_a; + + if (dim_a == 2 && dim_b == 2)// intersect two polygons + return topoOperationPolygonPolygonEx_(geometry_a, geometry_b, + geometry_dominant); + if ((dim_a == 1 && dim_b > 0) || (dim_b == 1 && dim_a > 0))// intersect + // polyline + // with + // polyline + // or + // polygon + return topoOperationPolylinePolylineOrPolygonEx_(geometry_dominant); + if (dim_a == 0 || dim_b == 0)// intersect a multipoint with something + // else + { + int[] res = new int[1]; + res[0] = topoOperationMultiPoint_(); + return res; + } + + throw GeometryException.GeometryInternalError(); + } + + public int symmetricDifference(int geometry_a, int geometry_b) { + int gtA = m_topo_graph.getShape().getGeometryType(geometry_a); + int gtB = m_topo_graph.getShape().getGeometryType(geometry_b); + int dim_a = Geometry.getDimensionFromType(gtA); + int dim_b = Geometry.getDimensionFromType(gtB); + + int ID_a = m_topo_graph.getGeometryID(geometry_a); + int ID_b = m_topo_graph.getGeometryID(geometry_b); + initMaskLookupArray_((ID_a | ID_b) + 1); + + m_mask_lookup[m_topo_graph.getGeometryID(geometry_a)] = true; + m_mask_lookup[m_topo_graph.getGeometryID(geometry_b)] = true; + + if (dim_a == 2 && dim_b == 2) + return topoOperationPolygonPolygon_(geometry_a, geometry_b, -1); + if (dim_a == 1 && dim_b == 1) + return topoOperationPolylinePolylineOrPolygon_(-1); + if (dim_a == 0 && dim_b == 0) + return topoOperationMultiPoint_(); + + throw GeometryException.GeometryInternalError(); + } + + int extractShape(int geometry_in) { + int gtA = m_topo_graph.getShape().getGeometryType(geometry_in); + int dim_a = Geometry.getDimensionFromType(gtA); + + int ID_a = m_topo_graph.getGeometryID(geometry_in); + initMaskLookupArray_((ID_a) + 1); + m_mask_lookup[m_topo_graph.getGeometryID(geometry_in)] = true; // Works + // only + // when + // there + // is a + // single + // geometry + // in + // the + // edit + // shape. + // To make it work when many geometries are present, this need to be + // modified. + + if (dim_a == 2) + return topoOperationPolygonPolygon_(geometry_in, -1, -1); + if (dim_a == 1) + return topoOperationPolylinePolylineOrPolygon_(-1); + if (dim_a == 0) + return topoOperationMultiPoint_(); + + throw GeometryException.GeometryInternalError(); + } + + static Geometry normalizeInputGeometry_(Geometry geom) { + Geometry.Type gt = geom.getType(); + if (gt == Geometry.Type.Envelope) { + Polygon poly = new Polygon(geom.getDescription()); + if (!geom.isEmpty()) + poly.addEnvelope((Envelope) geom, false); + return poly; + } + if (gt == Geometry.Type.Point) { + MultiPoint poly = new MultiPoint(geom.getDescription()); + if (!geom.isEmpty()) + poly.add((Point) geom); + return poly; + } + if (gt == Geometry.Type.Line) { + Polyline poly = new Polyline(geom.getDescription()); + if (!geom.isEmpty()) + poly.addSegment((Segment) geom, true); + return poly; + } + + return geom; + } + + static Geometry normalizeResult_(Geometry geomRes, Geometry geom_a, + Geometry dummy, char op) { + // assert(strchr("-&^|",op) != NULL); + Geometry.Type gtRes = geomRes.getType(); + if (gtRes == Geometry.Type.Envelope) { + Polygon poly = new Polygon(geomRes.getDescription()); + if (!geomRes.isEmpty()) + poly.addEnvelope((Envelope) geomRes, false); + return poly; + } + + if (gtRes == Geometry.Type.Point && (op == '|' || op == '^')) { + MultiPoint poly = new MultiPoint(geomRes.getDescription()); + if (!geomRes.isEmpty()) + poly.add((Point) geomRes); + return poly; + } + + if (gtRes == Geometry.Type.Line) { + Polyline poly = new Polyline(geomRes.getDescription()); + if (!geomRes.isEmpty()) + poly.addSegment((Segment) geomRes, true); + return poly; + } + + if (gtRes == Geometry.Type.Point && op == '-') { + if (geom_a.getType() == Geometry.Type.Point) { + Point pt = new Point(geomRes.getDescription()); + if (!geomRes.isEmpty()) { + assert (((MultiPoint) geomRes).getPointCount() == 1); + ((MultiPoint) geomRes).getPointByVal(0, pt); + } + return pt; + } + } + + if (gtRes == Geometry.Type.MultiPoint && op == '&') { + if (geom_a.getType() == Geometry.Type.Point) { + Point pt = new Point(geomRes.getDescription()); + if (!geomRes.isEmpty()) { + assert (((MultiPoint) geomRes).getPointCount() == 1); + ((MultiPoint) geomRes).getPointByVal(0, pt); + } + return pt; + } + } + + return geomRes; + } + + // static + public static Geometry difference(Geometry geometry_a, Geometry geometry_b, + SpatialReference sr, ProgressTracker progress_tracker) { + if (geometry_a.isEmpty() || geometry_b.isEmpty() + || geometry_a.getDimension() > geometry_b.getDimension()) + return normalizeResult_(normalizeInputGeometry_(geometry_a), + geometry_a, geometry_b, '-'); + + Envelope2D env2D_1 = new Envelope2D(); + geometry_a.queryEnvelope2D(env2D_1); + Envelope2D env2D_2 = new Envelope2D(); + geometry_b.queryEnvelope2D(env2D_2); + + if (!env2D_1.isIntersecting(env2D_2)) { + return normalizeResult_(normalizeInputGeometry_(geometry_a), + geometry_a, geometry_b, '-'); + } + + Envelope2D envMerged = new Envelope2D(); + envMerged.setCoords(env2D_1); + envMerged.merge(env2D_2); + double tolerance = InternalUtils.calculateToleranceFromGeometry(sr, + envMerged, true);// conservative to have same effect as simplify + + TopologicalOperations topoOps = new TopologicalOperations(); + EditShape edit_shape = new EditShape(); + int geom_a = edit_shape + .addGeometry(normalizeInputGeometry_(geometry_a)); + int geom_b = edit_shape + .addGeometry(normalizeInputGeometry_(geometry_b)); + topoOps.setEditShapeCrackAndCluster(edit_shape, tolerance, + progress_tracker); + int result = topoOps.difference(geom_a, geom_b); + Geometry resGeom = edit_shape.getGeometry(result); + + Geometry res_geom = normalizeResult_(resGeom, geometry_a, geometry_b, + '-'); + + if (Geometry.isMultiPath(res_geom.getType().value())) { + ((MultiVertexGeometryImpl) res_geom._getImpl()).setIsSimple( + GeometryXSimple.Strong, tolerance, false); + if (res_geom.getType() == Geometry.Type.Polygon) + ((MultiPathImpl) res_geom._getImpl())._updateOGCFlags(); + } + + return res_geom; + } + + public static Geometry dissolve(Geometry geometry_a, Geometry geometry_b, + SpatialReference sr, ProgressTracker progress_tracker) { + if (geometry_a.getDimension() > geometry_b.getDimension()) + return normalizeResult_(normalizeInputGeometry_(geometry_a), + geometry_a, geometry_b, '|'); + + if (geometry_a.getDimension() < geometry_b.getDimension()) + return normalizeResult_(normalizeInputGeometry_(geometry_b), + geometry_a, geometry_b, '|'); + + if (geometry_a.isEmpty()) + return normalizeResult_(normalizeInputGeometry_(geometry_b), + geometry_a, geometry_b, '|'); + + if (geometry_b.isEmpty()) + return normalizeResult_(normalizeInputGeometry_(geometry_a), + geometry_a, geometry_b, '|'); + + Envelope2D env2D_1 = new Envelope2D(); + geometry_a.queryEnvelope2D(env2D_1); + Envelope2D env2D_2 = new Envelope2D(); + geometry_b.queryEnvelope2D(env2D_2); + + Envelope2D envMerged = new Envelope2D(); + envMerged.setCoords(env2D_1); + envMerged.merge(env2D_2); + double tolerance = InternalUtils.calculateToleranceFromGeometry(sr, + envMerged, true);// conservative to have same effect as simplify + + if (!env2D_1.isIntersecting(env2D_2.getInflated(tolerance, tolerance))) { + // TODO: add optimization here to merge two geometries if the + // envelopes do not overlap. + Geometry geom1 = normalizeInputGeometry_(geometry_a); + assert (Geometry.isMultiVertex(geom1.getType().value())); + Geometry geom2 = normalizeInputGeometry_(geometry_b); + assert (Geometry.isMultiVertex(geom2.getType().value())); + assert (geom1.getType() == geom2.getType()); + switch (geom1.getType().value()) { + case Geometry.GeometryType.MultiPoint: { + Geometry res = Geometry._clone(geom1); + ((MultiPoint) res).add((MultiPoint) geom2, 0, -1); + return res; + } + // break; + case Geometry.GeometryType.Polyline: { + Geometry res = Geometry._clone(geom1); + ((Polyline) res).add((MultiPath) geom2, false); + return res; + } + // break; + case Geometry.GeometryType.Polygon: { + Geometry res = Geometry._clone(geom1); + ((Polygon) res).add((MultiPath) geom2, false); + return res; + } + // break; + default: + throw GeometryException.GeometryInternalError(); + } + } + + TopologicalOperations topoOps = new TopologicalOperations(); + EditShape edit_shape = new EditShape(); + int geom_a = edit_shape + .addGeometry(normalizeInputGeometry_(geometry_a)); + int geom_b = edit_shape + .addGeometry(normalizeInputGeometry_(geometry_b)); + topoOps.setEditShapeCrackAndCluster(edit_shape, tolerance, + progress_tracker); + int result = topoOps.dissolve(geom_a, geom_b); + + Geometry res_geom = normalizeResult_(edit_shape.getGeometry(result), + geometry_a, geometry_b, '|'); + + if (Geometry.isMultiPath(res_geom.getType().value())) { + ((MultiVertexGeometryImpl) res_geom._getImpl()).setIsSimple( + GeometryXSimple.Strong, tolerance, false); + if (res_geom.getType() == Geometry.Type.Polygon) + ((MultiPathImpl) res_geom._getImpl())._updateOGCFlags(); + } + + return res_geom; + } + + static Geometry dissolveDirty(ArrayList geometries, + SpatialReference sr, ProgressTracker progress_tracker) { + if (geometries.size() < 2) + throw new IllegalArgumentException( + "not enough geometries to dissolve"); + + int dim = 0; + for (int i = 0, n = geometries.size(); i < n; i++) { + dim = Math.max(geometries.get(i).getDimension(), dim); + } + + Envelope2D envMerged = new Envelope2D(); + envMerged.setEmpty(); + + EditShape shape = new EditShape(); + int geom = -1; + int count = 0; + int any_index = -1; + for (int i = 0, n = geometries.size(); i < n; i++) { + if (geometries.get(i).getDimension() == dim) { + if (!geometries.get(i).isEmpty()) { + any_index = i; + if (geom == -1) + geom = shape + .addGeometry(normalizeInputGeometry_(geometries + .get(i))); + else + shape.appendGeometry(geom, + normalizeInputGeometry_(geometries.get(i))); + + Envelope2D env = new Envelope2D(); + geometries.get(i).queryLooseEnvelope2D(env); + envMerged.merge(env); + count++; + } else if (any_index == -1) + any_index = i; + } + } + + if (count < 2) { + return normalizeInputGeometry_(geometries.get(any_index)); + } + + boolean winding = dim == 2; + + SpatialReference psr = dim == 0 ? sr : null;// if points, then use + // correct tolerance. + double tolerance = InternalUtils.calculateToleranceFromGeometry(psr, + envMerged, true); + TopologicalOperations topoOps = new TopologicalOperations(); + return topoOps.planarSimplify(shape, geom, tolerance, winding, true, + progress_tracker); + } + + // static + public static Geometry intersection(Geometry geometry_a, + Geometry geometry_b, SpatialReference sr, + ProgressTracker progress_tracker) { + + Envelope2D env2D_1 = new Envelope2D(); + geometry_a.queryEnvelope2D(env2D_1); + Envelope2D env2D_2 = new Envelope2D(); + geometry_b.queryEnvelope2D(env2D_2); + + Envelope2D envMerged = new Envelope2D(); + envMerged.setCoords(env2D_1); + envMerged.merge(env2D_2); + double tolerance = InternalUtils.calculateToleranceFromGeometry(sr, + envMerged, true);// conservative to have same effect as simplify + + Envelope2D e = new Envelope2D(); + e.setCoords(env2D_2); + double tol_cluster = InternalUtils + .adjust_tolerance_for_TE_clustering(tolerance); + e.inflate(tol_cluster, tol_cluster); + + if (!env2D_1.isIntersecting(e))// also includes the empty geometry + // cases + { + if (geometry_a.getDimension() <= geometry_b.getDimension()) + return normalizeResult_( + normalizeInputGeometry_(geometry_a.createInstance()), + geometry_a, geometry_b, '&'); + + if (geometry_a.getDimension() > geometry_b.getDimension()) + return normalizeResult_( + normalizeInputGeometry_(geometry_b.createInstance()), + geometry_a, geometry_b, '&'); + } + + TopologicalOperations topoOps = new TopologicalOperations(); + EditShape edit_shape = new EditShape(); + int geom_a = edit_shape + .addGeometry(normalizeInputGeometry_(geometry_a)); + int geom_b = edit_shape + .addGeometry(normalizeInputGeometry_(geometry_b)); + + topoOps.setEditShapeCrackAndCluster(edit_shape, tolerance, + progress_tracker); + int result = topoOps.intersection(geom_a, geom_b); + Geometry res_geom = normalizeResult_(edit_shape.getGeometry(result), + geometry_a, geometry_b, '&'); + + if (Geometry.isMultiPath(res_geom.getType().value())) { + ((MultiVertexGeometryImpl) res_geom._getImpl()).setIsSimple( + GeometryXSimple.Strong, tolerance, false); + if (res_geom.getType() == Geometry.Type.Polygon) + ((MultiPathImpl) res_geom._getImpl())._updateOGCFlags(); + } + + return res_geom; + } + + static Geometry[] intersectionEx(Geometry geometry_a, Geometry geometry_b, + SpatialReference sr, ProgressTracker progress_tracker) { + Geometry[] res_vec = new Geometry[3]; + + Envelope2D env2D_1 = new Envelope2D(); + geometry_a.queryEnvelope2D(env2D_1); + Envelope2D env2D_2 = new Envelope2D(); + geometry_b.queryEnvelope2D(env2D_2); + + Envelope2D envMerged = new Envelope2D(); + envMerged.setCoords(env2D_1); + envMerged.merge(env2D_2); + double tolerance = InternalUtils.calculateToleranceFromGeometry(sr, + envMerged, true);// conservative to have same effect as simplify + + Envelope2D e = new Envelope2D(); + e.setCoords(env2D_2); + double tol_cluster = InternalUtils + .adjust_tolerance_for_TE_clustering(tolerance); + e.inflate(tol_cluster, tol_cluster); + + if (!env2D_1.isIntersecting(e))// also includes the empty geometry + // cases + { + if (geometry_a.getDimension() <= geometry_b.getDimension()) { + Geometry geom = normalizeResult_( + normalizeInputGeometry_(geometry_a.createInstance()), + geometry_a, geometry_b, '&'); + res_vec[geom.getDimension()] = geom; + return res_vec; + } + + if (geometry_a.getDimension() > geometry_b.getDimension()) { + Geometry geom = normalizeResult_( + normalizeInputGeometry_(geometry_b.createInstance()), + geometry_a, geometry_b, '&'); + res_vec[geom.getDimension()] = geom; + return res_vec; + } + + } + + TopologicalOperations topoOps = new TopologicalOperations(); + EditShape edit_shape = new EditShape(); + int geom_a = edit_shape + .addGeometry(normalizeInputGeometry_(geometry_a)); + int geom_b = edit_shape + .addGeometry(normalizeInputGeometry_(geometry_b)); + + topoOps.setEditShapeCrackAndCluster(edit_shape, tolerance, + progress_tracker); + int[] result_geom_handles = topoOps.intersectionEx(geom_a, geom_b); + for (int i = 0; i < result_geom_handles.length; i++) { + Geometry res_geom = normalizeResult_( + edit_shape.getGeometry(result_geom_handles[i]), geometry_a, + geometry_b, '&'); + + if (Geometry.isMultiPath(res_geom.getType().value())) { + ((MultiVertexGeometryImpl) res_geom._getImpl()).setIsSimple( + MultiVertexGeometryImpl.GeometryXSimple.Strong, + tolerance, false); + if (res_geom.getType().value() == Geometry.GeometryType.Polygon) + ((MultiPathImpl) res_geom._getImpl())._updateOGCFlags(); + } + + res_vec[res_geom.getDimension()] = res_geom; + } + + return res_vec; + } + + // static + public static Geometry symmetricDifference(Geometry geometry_a, + Geometry geometry_b, SpatialReference sr, + ProgressTracker progress_tracker) { + if (geometry_a.getDimension() > geometry_b.getDimension()) + return normalizeResult_(normalizeInputGeometry_(geometry_a), + geometry_a, geometry_b, '^'); + + if (geometry_a.getDimension() < geometry_b.getDimension()) + return normalizeResult_(normalizeInputGeometry_(geometry_b), + geometry_a, geometry_b, '^'); + + if (geometry_a.isEmpty()) + return normalizeResult_(normalizeInputGeometry_(geometry_b), + geometry_a, geometry_b, '^'); + + if (geometry_b.isEmpty()) + return normalizeResult_(normalizeInputGeometry_(geometry_a), + geometry_a, geometry_b, '^'); + + Envelope2D env2D_1 = new Envelope2D(); + geometry_a.queryEnvelope2D(env2D_1); + Envelope2D env2D_2 = new Envelope2D(); + geometry_b.queryEnvelope2D(env2D_2); + // TODO: add optimization here to merge two geometries if the envelopes + // do not overlap. + + Envelope2D envMerged = new Envelope2D(); + envMerged.setCoords(env2D_1); + envMerged.merge(env2D_2); + double tolerance = InternalUtils.calculateToleranceFromGeometry(sr, + envMerged, true);// conservative to have same effect as simplify + + TopologicalOperations topoOps = new TopologicalOperations(); + EditShape edit_shape = new EditShape(); + int geom_a = edit_shape + .addGeometry(normalizeInputGeometry_(geometry_a)); + int geom_b = edit_shape + .addGeometry(normalizeInputGeometry_(geometry_b)); + topoOps.setEditShapeCrackAndCluster(edit_shape, tolerance, + progress_tracker); + int result = topoOps.symmetricDifference(geom_a, geom_b); + Geometry res_geom = normalizeResult_(edit_shape.getGeometry(result), + geometry_a, geometry_b, '^'); + + if (Geometry.isMultiPath(res_geom.getType().value())) { + ((MultiVertexGeometryImpl) res_geom._getImpl()).setIsSimple( + GeometryXSimple.Strong, tolerance, false); + if (res_geom.getType() == Geometry.Type.Polygon) + ((MultiPathImpl) res_geom._getImpl())._updateOGCFlags(); + } + + return res_geom; + } + + static Geometry _denormalizeGeometry(Geometry geom, Geometry geomA, + Geometry geomB) { + Geometry.Type gtA = geomA.getType(); + Geometry.Type gtB = geomB.getType(); + Geometry.Type gt = geom.getType(); + if (gt == Geometry.Type.MultiPoint) { + if (gtA == Geometry.Type.Point || gtB == Geometry.Type.Point) { + MultiPoint mp = (MultiPoint) geom; + if (mp.getPointCount() <= 1) { + Point pt = new Point(geom.getDescription()); + if (!mp.isEmpty()) + mp.getPointByVal(0, pt); + return (Geometry) pt; + } + } + } + return geom; + } + + private void flushVertices_(int geometry, AttributeStreamOfInt32 vertices) { + EditShape shape = m_topo_graph.getShape(); + int path = shape.insertPath(geometry, -1); + int size = vertices.size(); + // _ASSERT(size != 0); + for (int i = 0; i < size; i++) { + int vertex = vertices.get(i); + shape.addVertex(path, vertex); + } + shape.setClosedPath(path, true);// need to close polygon rings + } + + private void setHalfEdgeOrientations_(int orientationIndex, int cutter) { + EditShape shape = m_topo_graph.getShape(); + + for (int igeometry = shape.getFirstGeometry(); igeometry != -1; igeometry = shape + .getNextGeometry(igeometry)) { + if (igeometry != cutter) + continue; + + for (int ipath = shape.getFirstPath(igeometry); ipath != -1; ipath = shape + .getNextPath(ipath)) { + int ivertex = shape.getFirstVertex(ipath); + if (ivertex == -1) + continue; + + int ivertexNext = shape.getNextVertex(ivertex); + assert (ivertexNext != -1); + + while (ivertexNext != -1) { + int clusterFrom = m_topo_graph + .getClusterFromVertex(ivertex); + int clusterTo = m_topo_graph + .getClusterFromVertex(ivertexNext); + int half_edge = m_topo_graph.getHalfEdgeConnector( + clusterFrom, clusterTo); + + if (half_edge != -1) { + int halfEdgeTwin = m_topo_graph + .getHalfEdgeTwin(half_edge); + m_topo_graph.setHalfEdgeUserIndex(half_edge, + orientationIndex, 1); + m_topo_graph.setHalfEdgeUserIndex(halfEdgeTwin, + orientationIndex, 2); + } + + ivertex = ivertexNext; + ivertexNext = shape.getNextVertex(ivertex); + } + } + } + } + + private void processPolygonCuts_(int orientationIndex, int sideIndex, + int cuttee, int cutter) { + int idCuttee = m_topo_graph.getGeometryID(cuttee); + int idCutter = m_topo_graph.getGeometryID(cutter); + AttributeStreamOfInt32 vertices = new AttributeStreamOfInt32(0); + vertices.reserve(256); + EditShape shape = m_topo_graph.getShape(); + + int visitedIndex = m_topo_graph.createUserIndexForHalfEdges(); + for (int cluster = m_topo_graph.getFirstCluster(); cluster != -1; cluster = m_topo_graph + .getNextCluster(cluster)) { + int firstHalfEdge = m_topo_graph.getClusterHalfEdge(cluster); + + if (firstHalfEdge == -1) + continue; + + int half_edge = firstHalfEdge; + + do { + int visited = m_topo_graph.getHalfEdgeUserIndex(half_edge, + visitedIndex); + if (visited != 1) { + int faceHalfEdge = half_edge; + int toHalfEdge = half_edge; + boolean bFoundCutter = false; + int side = 0; + do { + m_topo_graph.setHalfEdgeUserIndex(faceHalfEdge, + visitedIndex, 1); + if (!bFoundCutter) { + int edgeParentage = m_topo_graph + .getHalfEdgeParentage(faceHalfEdge); + if ((edgeParentage & idCutter) != 0) { + int faceParentage = m_topo_graph + .getHalfEdgeFaceParentage(faceHalfEdge); + if ((faceParentage & idCuttee) != 0) { + toHalfEdge = faceHalfEdge;// reset the loop + bFoundCutter = true; + } + } + } + + if (bFoundCutter) { + int clusterOrigin = m_topo_graph + .getHalfEdgeOrigin(faceHalfEdge); + int iterator = m_topo_graph + .getClusterVertexIterator(clusterOrigin); + assert (iterator != -1); + int vertex = m_topo_graph + .getVertexFromVertexIterator(iterator); + vertices.add(vertex); + + // get side + if (orientationIndex != -1) { + int edgeParentage = m_topo_graph + .getHalfEdgeParentage(faceHalfEdge); + if ((edgeParentage & idCutter) != 0) { + int orientation = m_topo_graph + .getHalfEdgeUserIndex(faceHalfEdge, + orientationIndex); + assert (orientation == 1 || orientation == 2); + side |= orientation; + } + } + } + + int next = m_topo_graph.getHalfEdgeNext(faceHalfEdge); + faceHalfEdge = next; + } while (faceHalfEdge != toHalfEdge); + + if (bFoundCutter + && m_topo_graph.getChainArea(m_topo_graph + .getHalfEdgeChain(toHalfEdge)) > 0.0) {// if + // we + // found + // a + // cutter + // face + // and + // its + // area + // is + // positive, + // then + // add + // the + // cutter + // face + // as + // new + // polygon. + int geometry = shape + .createGeometry(Geometry.Type.Polygon); + flushVertices_(geometry, vertices);// adds the cutter + // face vertices to + // the new polygon + + if (sideIndex != -1) + shape.setGeometryUserIndex(geometry, sideIndex, + side); // what is that? + } + + vertices.clear(false); + } + half_edge = m_topo_graph.getHalfEdgeNext(m_topo_graph + .getHalfEdgeTwin(half_edge)); + } while (half_edge != firstHalfEdge); + } + + m_topo_graph.deleteUserIndexForHalfEdges(visitedIndex); + } + + private void cutPolygonPolyline_(int sideIndex, int cuttee, int cutter, + AttributeStreamOfInt32 cutHandles) { + m_topo_graph.removeSpikes_(); + + int orientationIndex = -1; + if (sideIndex != -1) { + orientationIndex = m_topo_graph.createUserIndexForHalfEdges(); + setHalfEdgeOrientations_(orientationIndex, cutter); + } + + processPolygonCuts_(orientationIndex, sideIndex, cuttee, cutter); + + EditShape shape = m_topo_graph.getShape(); + + int cutCount = 0; + for (int geometry_handle = shape.getFirstGeometry(); geometry_handle != -1; geometry_handle = shape + .getNextGeometry(geometry_handle)) { + if (geometry_handle != cuttee && geometry_handle != cutter) { + cutHandles.add(geometry_handle); + cutCount++; + } + } + + // sort + CompareCuts compareCuts = new CompareCuts(shape); + cutHandles.Sort(0, cutCount, compareCuts); + } + + //call this if EditShape instance has to survive the TopologicalOperations life. + void removeShape() { + if (m_topo_graph != null) { + m_topo_graph.removeShape(); + m_topo_graph = null; + } + + } } diff --git a/src/main/java/com/esri/core/geometry/Transformation2D.java b/src/main/java/com/esri/core/geometry/Transformation2D.java index e8c92ed7..1704628a 100644 --- a/src/main/java/com/esri/core/geometry/Transformation2D.java +++ b/src/main/java/com/esri/core/geometry/Transformation2D.java @@ -24,10 +24,12 @@ package com.esri.core.geometry; +import static com.esri.core.geometry.SizeOf.SIZE_OF_TRANSFORMATION_2D; + /** * The affine transformation class for 2D. - *

- * Vector is a row: + * + * Vector is a row: * *
|m11 m12 0| *
| x y 1| * |m21 m22 0| = |m11 * x + m21 * y + m31 m12 * x + m22 * y + m32 1| @@ -47,819 +49,882 @@ */ public final class Transformation2D { - /** - * Matrix coefficient XX of the transformation. - */ - public double xx; - /** - * Matrix coefficient XY of the transformation. - */ - public double xy; - /** - * X translation component of the transformation. - */ - public double xd; - /** - * Matrix coefficient YX of the transformation. - */ - - public double yx; - /** - * Matrix coefficient YY of the transformation. - */ - public double yy; - /** - * Y translation component of the transformation. - */ - - public double yd; - - /** - * Creates a 2D affine transformation with identity transformation. - */ - public Transformation2D() { - setIdentity(); - } - - /** - * Creates a 2D affine transformation with a specified scale. - * - * @param scale The scale to use for the transformation. - */ - public Transformation2D(double scale) { - setScale(scale); - } - - /** - * Initializes a zero transformation. Transforms any coordinate to (0, 0). - */ - public void setZero() { - xx = 0; - yy = 0; - xy = 0; - yx = 0; - xd = 0; - yd = 0; - } - - void transform(Point2D psrc, Point2D pdst) { - double x = xx * psrc.x + xy * psrc.y + xd; - double y = yx * psrc.x + yy * psrc.y + yd; - pdst.x = x; - pdst.y = y; - } - - /** - * Returns True when all members of this transformation are equal to the - * corresponding members of the other. - */ - - @Override - public boolean equals(Object other) { - if (this == other) - return true; - if (!(other instanceof Transformation2D)) - return false; - Transformation2D that = (Transformation2D) other; - - return (xx == that.xx && xy == that.xy && xd == that.xd - && yx == that.yx && yy == that.yy && yd == that.yd); - } - - /** - * Returns the hash code for the 2D transformation. - */ - - @Override - public int hashCode() { - int hash = NumberUtils.hash(xx); - hash = NumberUtils.hash(hash, xy); - hash = NumberUtils.hash(hash, xd); - hash = NumberUtils.hash(hash, yx); - hash = NumberUtils.hash(hash, yy); - hash = NumberUtils.hash(hash, yd); - return hash; - } - - void transform(Point2D[] points, int start, int count) { - int n = Math.min(points.length, start + count); - for (int i = count; i < n; i++) { - transform(points[i], points[i]); - } - } - - /** - * Transforms an array of points. - * - * @param pointsIn The points to be transformed. - * @param count The number of points to transform. - * @param pointsOut The transformed points are returned using this array. It - * should have the same or greater size as the input array. - */ - public void transform(Point[] pointsIn, int count, Point[] pointsOut) { - Point2D res = new Point2D(); - for (int i = 0; i < count; i++) { - Point2D p = pointsIn[i].getXY(); - res.x = xx * p.x + xy * p.y + xd; - res.y = yx * p.x + yy * p.y + yd; - pointsOut[i] = new Point(res.x, res.y); - } - } - - /** - * Transforms an array of points stored in an array of doubles as - * interleaved XY coordinates. - * - * @param pointsXYInterleaved The array of points with interleaved X, Y values to be - * transformed. - * @param start The start point index to transform from (the actual element - * index is 2 * start). - * @param count The number of points to transform (the actual element count is - * 2 * count). - */ - public void transform(double[] pointsXYInterleaved, int start, int count) { - int n = Math.min(pointsXYInterleaved.length, (start + count) * 2) / 2; - for (int i = count; i < n; i++) { - double px = pointsXYInterleaved[2 * i]; - double py = pointsXYInterleaved[2 * i + 1]; - pointsXYInterleaved[2 * i] = xx * px + xy * py + xd; - pointsXYInterleaved[2 * i + 1] = yx * px + yy * py + yd; - } - } - - /** - * Multiplies this matrix on the right with the "right" matrix. Stores the - * result into this matrix and returns a reference to it.
- * Equivalent to this *= right. - * - * @param right The matrix to be multiplied with. - */ - public void multiply(Transformation2D right) { - multiply(this, right, this); - } - - /** - * Multiplies this matrix on the left with the "left" matrix. Stores the - * result into this matrix and returns a reference to it.
- * Equivalent to this = left * this. - * - * @param left The matrix to be multiplied with. - */ - public void mulLeft(Transformation2D left) { - multiply(left, this, this); - } - - /** - * Performs multiplication of matrices a and b and places the result into - * this matrix. The a, b, and result could point to same objects.
- * Equivalent to result = a * b. - * - * @param a The 2D transformation to be multiplied. - * @param b The 2D transformation to be multiplied. - * @param result The 2D transformation created by multiplication of matrices. - */ - public static void multiply(Transformation2D a, Transformation2D b, - Transformation2D result) { - double xx, xy, xd, yx, yy, yd; - - xx = a.xx * b.xx + a.yx * b.xy; - xy = a.xy * b.xx + a.yy * b.xy; - xd = a.xd * b.xx + a.yd * b.xy + b.xd; - yx = a.xx * b.yx + a.yx * b.yy; - yy = a.xy * b.yx + a.yy * b.yy; - yd = a.xd * b.yx + a.yd * b.yy + b.yd; - - result.xx = xx; - result.xy = xy; - result.xd = xd; - result.yx = yx; - result.yy = yy; - result.yd = yd; - } - - /** - * Returns a copy of the Transformation2D object. - * - * @return A copy of this object. - */ - public Transformation2D copy() { - Transformation2D result = new Transformation2D(); - result.xx = xx; - result.xy = xy; - result.xd = xd; - result.yx = yx; - result.yy = yy; - result.yd = yd; - return result; - } - - /** - * Writes the matrix coefficients in the order XX, XY, XD, YX, YY, YD into - * the given array. - * - * @param coefs The array into which the coefficients are returned. Should be - * of size 6 elements. - */ - public void getCoefficients(double[] coefs) { - if (coefs.length < 6) - throw new GeometryException( - "Buffer is too small. coefs needs 6 members"); - - coefs[0] = xx; - coefs[1] = xy; - coefs[2] = xd; - coefs[3] = yx; - coefs[4] = yy; - coefs[5] = yd; - } - - /** - * Transforms envelope - * - * @param env The envelope that is to be transformed - */ - void transform(Envelope2D env) { - - if (env.isEmpty()) - return; - - Point2D[] buf = new Point2D[4]; - env.queryCorners(buf); - transform(buf, buf); - env.setFromPoints(buf, 4); - } - - void transform(Point2D[] pointsIn, Point2D[] pointsOut) { - for (int i = 0; i < pointsIn.length; i++) { - Point2D res = new Point2D(); - Point2D p = pointsIn[i]; - res.x = xx * p.x + xy * p.y + xd; - res.y = yx * p.x + yy * p.y + yd; - pointsOut[i] = res; - } - } - - /** - * Initialize transformation from two rectangles. - */ - void initializeFromRect(Envelope2D src, Envelope2D dest) { - if (src.isEmpty() || dest.isEmpty() || 0 == src.getWidth() - || 0 == src.getHeight()) - setZero(); - else { - xy = yx = 0; - xx = dest.getWidth() / src.getWidth(); - yy = dest.getHeight() / src.getHeight(); - xd = dest.xmin - src.xmin * xx; - yd = dest.ymin - src.ymin * yy; - } - } - - /** - * Initializes an orhtonormal transformation from the Src and Dest - * rectangles. - *

- * The result transformation proportionally fits the Src into the Dest. The - * center of the Src will be in the center of the Dest. - */ - void initializeFromRectIsotropic(Envelope2D src, Envelope2D dest) { - - if (src.isEmpty() || dest.isEmpty() || 0 == src.getWidth() - || 0 == src.getHeight()) - setZero(); - else { - yx = 0; - xy = 0; - xx = dest.getWidth() / src.getWidth(); - yy = dest.getHeight() / src.getHeight(); - if (xx > yy) - xx = yy; - else - yy = xx; - - Point2D destCenter = dest.getCenter(); - Point2D srcCenter = src.getCenter(); - xd = destCenter.x - srcCenter.x * xx; - yd = destCenter.y - srcCenter.y * yy; - } - } - - /** - * Initializes transformation from Position, Tangent vector and offset - * value. Tangent vector must have unity length - */ - void initializeFromCurveParameters(Point2D Position, Point2D Tangent, - double Offset) { - // TODO - } - - /** - * Transforms size. - *

- * Creates an AABB with width of SizeSrc.x and height of SizeSrc.y. - * Transforms that AABB and gets a quadrangle in new coordinate system. The - * result x contains the length of the quadrangle edge, which were parallel - * to X in the original system, and y contains the length of the edge, that - * were parallel to the Y axis in the original system. - */ - Point2D transformSize(Point2D SizeSrc) { - Point2D pt = new Point2D(); - pt.x = Math.sqrt(xx * xx + yx * yx) * SizeSrc.x; - pt.y = Math.sqrt(xy * xy + yy * yy) * SizeSrc.y; - return pt; - } - - /** - * Transforms a tolerance value. - * - * @param tolerance The tolerance value. - */ - public double transform(double tolerance) { - // the function should be implemented as follows: find encompassing - // circle for the transformed circle of radius = Tolerance. - - // this is approximation. - Point2D pt1 = new Point2D(); - Point2D pt2 = new Point2D(); - /* + /** + * Matrix coefficient XX of the transformation. + */ + public double xx; + /** + * Matrix coefficient XY of the transformation. + */ + public double xy; + /** + * X translation component of the transformation. + */ + public double xd; + /** + * Matrix coefficient YX of the transformation. + */ + + public double yx; + /** + * Matrix coefficient YY of the transformation. + */ + public double yy; + /** + * Y translation component of the transformation. + */ + + public double yd; + + /** + * Creates a 2D affine transformation with identity transformation. + */ + public Transformation2D() { + setIdentity(); + } + + /** + * Creates a 2D affine transformation with a specified scale. + * + * @param scale + * The scale to use for the transformation. + */ + public Transformation2D(double scale) { + setScale(scale); + } + + /** + * Initializes a zero transformation. Transforms any coordinate to (0, 0). + */ + public void setZero() { + xx = 0; + yy = 0; + xy = 0; + yx = 0; + xd = 0; + yd = 0; + } + + void transform(Point2D psrc, Point2D pdst) { + double x = xx * psrc.x + xy * psrc.y + xd; + double y = yx * psrc.x + yy * psrc.y + yd; + pdst.x = x; + pdst.y = y; + } + + /** + * Returns True when all members of this transformation are equal to the + * corresponding members of the other. + */ + + @Override + public boolean equals(Object other) { + if (this == other) + return true; + if (!(other instanceof Transformation2D)) + return false; + Transformation2D that = (Transformation2D) other; + + return (xx == that.xx && xy == that.xy && xd == that.xd + && yx == that.yx && yy == that.yy && yd == that.yd); + } + + /** + * Returns the hash code for the 2D transformation. + */ + + @Override + public int hashCode() { + int hash = NumberUtils.hash(xx); + hash = NumberUtils.hash(hash, xy); + hash = NumberUtils.hash(hash, xd); + hash = NumberUtils.hash(hash, yx); + hash = NumberUtils.hash(hash, yy); + hash = NumberUtils.hash(hash, yd); + return hash; + } + + void transform(Point2D[] points, int start, int count) { + int n = Math.min(points.length, start + count); + for (int i = count; i < n; i++) { + transform(points[i], points[i]); + } + } + + /** + * Transforms an array of points. + * + * @param pointsIn + * The points to be transformed. + * @param count + * The number of points to transform. + * @param pointsOut + * The transformed points are returned using this array. It + * should have the same or greater size as the input array. + */ + public void transform(Point[] pointsIn, int count, Point[] pointsOut) { + Point2D res = new Point2D(); + for (int i = 0; i < count; i++) { + Point2D p = pointsIn[i].getXY(); + res.x = xx * p.x + xy * p.y + xd; + res.y = yx * p.x + yy * p.y + yd; + pointsOut[i] = new Point(res.x, res.y); + } + } + + /** + * Transforms an array of points stored in an array of doubles as + * interleaved XY coordinates. + * + * @param pointsXYInterleaved + * The array of points with interleaved X, Y values to be + * transformed. + * @param start + * The start point index to transform from (the actual element + * index is 2 * start). + * @param count + * The number of points to transform (the actual element count is + * 2 * count). + */ + public void transform(double[] pointsXYInterleaved, int start, int count) { + int n = Math.min(pointsXYInterleaved.length, (start + count) * 2) / 2; + for (int i = count; i < n; i++) { + double px = pointsXYInterleaved[2 * i]; + double py = pointsXYInterleaved[2 * i + 1]; + pointsXYInterleaved[2 * i] = xx * px + xy * py + xd; + pointsXYInterleaved[2 * i + 1] = yx * px + yy * py + yd; + } + } + + /** + * Multiplies this matrix on the right with the "right" matrix. Stores the + * result into this matrix and returns a reference to it.
+ * Equivalent to this *= right. + * + * @param right + * The matrix to be multiplied with. + */ + public void multiply(Transformation2D right) { + multiply(this, right, this); + } + + /** + * Multiplies this matrix on the left with the "left" matrix. Stores the + * result into this matrix and returns a reference to it.
+ * Equivalent to this = left * this. + * + * @param left + * The matrix to be multiplied with. + */ + public void mulLeft(Transformation2D left) { + multiply(left, this, this); + } + + /** + * Performs multiplication of matrices a and b and places the result into + * this matrix. The a, b, and result could point to same objects.
+ * Equivalent to result = a * b. + * + * @param a + * The 2D transformation to be multiplied. + * @param b + * The 2D transformation to be multiplied. + * @param result + * The 2D transformation created by multiplication of matrices. + */ + public static void multiply(Transformation2D a, Transformation2D b, + Transformation2D result) { + double xx, xy, xd, yx, yy, yd; + + xx = a.xx * b.xx + a.yx * b.xy; + xy = a.xy * b.xx + a.yy * b.xy; + xd = a.xd * b.xx + a.yd * b.xy + b.xd; + yx = a.xx * b.yx + a.yx * b.yy; + yy = a.xy * b.yx + a.yy * b.yy; + yd = a.xd * b.yx + a.yd * b.yy + b.yd; + + result.xx = xx; + result.xy = xy; + result.xd = xd; + result.yx = yx; + result.yy = yy; + result.yd = yd; + } + + /** + * Returns a copy of the Transformation2D object. + * + * @return A copy of this object. + */ + public Transformation2D copy() { + Transformation2D result = new Transformation2D(); + result.xx = xx; + result.xy = xy; + result.xd = xd; + result.yx = yx; + result.yy = yy; + result.yd = yd; + return result; + } + + /** + * Writes the matrix coefficients in the order XX, XY, XD, YX, YY, YD into + * the given array. + * + * @param coefs + * The array into which the coefficients are returned. Should be + * of size 6 elements. + */ + public void getCoefficients(double[] coefs) { + if (coefs.length < 6) + throw new GeometryException( + "Buffer is too small. coefs needs 6 members"); + + coefs[0] = xx; + coefs[1] = xy; + coefs[2] = xd; + coefs[3] = yx; + coefs[4] = yy; + coefs[5] = yd; + } + + /** + * Transforms envelope + * + * @param env + * The envelope that is to be transformed + */ + void transform(Envelope2D env) { + + if (env.isEmpty()) + return; + + Point2D[] buf = new Point2D[4]; + env.queryCorners(buf); + transform(buf, buf); + env.setFromPoints(buf, 4); + } + + void transform(Point2D[] pointsIn, Point2D[] pointsOut) { + for (int i = 0; i < pointsIn.length; i++) { + Point2D res = new Point2D(); + Point2D p = pointsIn[i]; + res.x = xx * p.x + xy * p.y + xd; + res.y = yx * p.x + yy * p.y + yd; + pointsOut[i] = res; + } + } + + /** + * Initialize transformation from two rectangles. + */ + void initializeFromRect(Envelope2D src, Envelope2D dest) { + if (src.isEmpty() || dest.isEmpty() || 0 == src.getWidth() + || 0 == src.getHeight()) + setZero(); + else { + xy = yx = 0; + xx = dest.getWidth() / src.getWidth(); + yy = dest.getHeight() / src.getHeight(); + xd = dest.xmin - src.xmin * xx; + yd = dest.ymin - src.ymin * yy; + } + } + + /** + * Initializes an orhtonormal transformation from the Src and Dest + * rectangles. + * + * The result transformation proportionally fits the Src into the Dest. The + * center of the Src will be in the center of the Dest. + */ + void initializeFromRectIsotropic(Envelope2D src, Envelope2D dest) { + + if (src.isEmpty() || dest.isEmpty() || 0 == src.getWidth() + || 0 == src.getHeight()) + setZero(); + else { + yx = 0; + xy = 0; + xx = dest.getWidth() / src.getWidth(); + yy = dest.getHeight() / src.getHeight(); + if (xx > yy) + xx = yy; + else + yy = xx; + + Point2D destCenter = dest.getCenter(); + Point2D srcCenter = src.getCenter(); + xd = destCenter.x - srcCenter.x * xx; + yd = destCenter.y - srcCenter.y * yy; + } + } + + /** + * Initializes transformation from Position, Tangent vector and offset + * value. Tangent vector must have unity length + */ + void initializeFromCurveParameters(Point2D Position, Point2D Tangent, + double Offset) { + // TODO + } + + /** + * Transforms size. + * + * Creates an AABB with width of SizeSrc.x and height of SizeSrc.y. + * Transforms that AABB and gets a quadrangle in new coordinate system. The + * result x contains the length of the quadrangle edge, which were parallel + * to X in the original system, and y contains the length of the edge, that + * were parallel to the Y axis in the original system. + */ + Point2D transformSize(Point2D SizeSrc) { + Point2D pt = new Point2D(); + pt.x = Math.sqrt(xx * xx + yx * yx) * SizeSrc.x; + pt.y = Math.sqrt(xy * xy + yy * yy) * SizeSrc.y; + return pt; + } + + /** + * Transforms a tolerance value. + * + * @param tolerance + * The tolerance value. + */ + public double transform(double tolerance) { + // the function should be implemented as follows: find encompassing + // circle for the transformed circle of radius = Tolerance. + + // this is approximation. + Point2D pt1 = new Point2D(); + Point2D pt2 = new Point2D(); + /* * pt[0].Set(0, 0); pt[1].Set(1, 0); pt[2].Set(0, 1); Transform(pt); * pt[1] -= pt[0]; pt[2] -= pt[0]; */ - pt1.setCoords(xx, yx); - pt2.setCoords(xy, yy); - pt1.sub(pt1); - double d1 = pt1.sqrLength() * 0.5; - pt1.setCoords(xx, yx); - pt2.setCoords(xy, yy); - pt1.add(pt2); - double d2 = pt1.sqrLength() * 0.5; - return tolerance * ((d1 > d2) ? Math.sqrt(d1) : Math.sqrt(d2)); - } - - // Performs linear part of the transformation only. Same as if xd, yd would - // be zeroed. - void transformWithoutShift(Point2D[] pointsIn, int from, int count, - Point2D[] pointsOut) { - for (int i = from, n = from + count; i < n; i++) { - Point2D p = pointsIn[i]; - double new_x = xx * p.x + xy * p.y; - double new_y = yx * p.x + yy * p.y; - pointsOut[i].setCoords(new_x, new_y); - } - } - - Point2D transformWithoutShift(Point2D srcPoint) { - double new_x = xx * srcPoint.x + xy * srcPoint.y; - double new_y = yx * srcPoint.x + yy * srcPoint.y; - return Point2D.construct(new_x, new_y); - } - - /** - * Sets this matrix to be the identity matrix. - */ - public void setIdentity() { - xx = 1.0; - xy = 0; - xd = 0; - yx = 0; - yy = 1.0; - yd = 0; - } - - /** - * Returns TRUE if this matrix is the identity matrix. - */ - public boolean isIdentity() { - return xx == 1.0 && yy == 1.0 - && (0 == xy && 0 == xd && 0 == yx && 0 == yd); - } - - /** - * Returns TRUE if this matrix is an identity matrix within the given - * tolerance. - * - * @param tol The tolerance value. - */ - public boolean isIdentity(double tol) { - Point2D pt = Point2D.construct(0., 1.); - transform(pt, pt); - pt.sub(Point2D.construct(0., 1.)); - if (pt.sqrLength() > tol * tol) - return false; - - pt.setCoords(0, 0); - transform(pt, pt); - if (pt.sqrLength() > tol * tol) - return false; - - pt.setCoords(1.0, 0.0); - transform(pt, pt); - pt.sub(Point2D.construct(1.0, 0.0)); - return pt.sqrLength() <= tol * tol; - } - - /** - * Returns TRUE for reflective transformations. It inverts the sign of - * vector cross product. - */ - public boolean isReflective() { - return xx * yy - yx * xy < 0; - } - - /** - * Returns TRUE if this transformation is a uniform transformation. - *

- * The uniform transformation is a transformation, which transforms a square - * to a square. - */ - public boolean isUniform(double eps) { - double v1 = xx * xx + yx * yx; - double v2 = xy * xy + yy * yy; - double e = (v1 + v2) * eps; - return Math.abs(v1 - v2) <= e && Math.abs(xx * xy + yx * yy) <= e; - } - - /** - * Returns TRUE if this transformation is a shift transformation. The shift - * transformation performs shift only. - */ - public boolean isShift() { - return xx == 1.0 && yy == 1.0 && 0 == xy && 0 == yx; - } - - /** - * Returns TRUE if this transformation is a shift transformation within the - * given tolerance. - * - * @param tol The tolerance value. - */ - public boolean isShift(double tol) { - Point2D pt = transformWithoutShift(Point2D.construct(0.0, 1.0)); - pt.y -= 1.0; - if (pt.sqrLength() > tol * tol) - return false; - - pt = transformWithoutShift(Point2D.construct(1.0, 0.0)); - pt.x -= 1.0; - return pt.sqrLength() <= tol * tol; - } - - /** - * Returns TRUE if this is an orthonormal transformation with the given - * tolerance. The orthonormal: Rotation or rotoinversion and shift - * (preserves lengths of vectors and angles between vectors). - * - * @param tol The tolerance value. - */ - public boolean isOrthonormal(double tol) { - Transformation2D r = new Transformation2D(); - r.xx = xx * xx + xy * xy; - r.xy = xx * yx + xy * yy; - r.yx = yx * xx + yy * xy; - r.yy = yx * yx + yy * yy; - r.xd = 0; - r.yd = 0; - - return r.isIdentity(tol); - } - - /** - * Returns TRUE if this matrix is degenerated (does not have an inverse) - * within the given tolerance. - * - * @param tol The tolerance value. - */ - public boolean isDegenerate(double tol) { - return Math.abs(xx * yy - yx * xy) <= 2 * tol - * (Math.abs(xx * yy) + Math.abs(yx * xy)); - } - - /** - * Returns TRUE, if this transformation does not have rotation and shear - * within the given tolerance. - * - * @param tol The tolerance value. - */ - public boolean isScaleAndShift(double tol) { - return xy * xy + yx * yx < (xx * xx + yy * yy) * tol; - } - - /** - * Set this transformation to be a shift. - * - * @param x The X coordinate to shift to. - * @param y The Y coordinate to shift to. - */ - public void setShift(double x, double y) { - xx = 1; - xy = 0; - xd = x; - yx = 0; - yy = 1; - yd = y; - } - - /** - * Set this transformation to be a scale. - * - * @param x The X coordinate to scale to. - * @param y The Y coordinate to scale to. - */ - public void setScale(double x, double y) { - xx = x; - xy = 0; - xd = 0; - yx = 0; - yy = y; - yd = 0; - } - - /** - * Set transformation to be a uniform scale. - * - * @param _scale The scale of the transformation. - */ - public void setScale(double _scale) { - setScale(_scale, _scale); - } - - /** - * Sets the transformation to be a flip around the X axis. Flips the X - * coordinates so that the x0 becomes x1 and vice verse. - * - * @param x0 The X coordinate to flip. - * @param x1 The X coordinate to flip to. - */ - public void setFlipX(double x0, double x1) { - xx = -1; - xy = 0; - xd = x0 + x1; - yx = 0; - yy = 1; - yd = 0; - } - - /** - * Sets the transformation to be a flip around the Y axis. Flips the Y - * coordinates so that the y0 becomes y1 and vice verse. - * - * @param y0 The Y coordinate to flip. - * @param y1 The Y coordinate to flip to. - */ - public void setFlipY(double y0, double y1) { - xx = 1; - xy = 0; - xd = 0; - yx = 0; - yy = -1; - yd = y0 + y1; - } - - /** - * Set transformation to a shear. - * - * @param proportionX The proportion of shearing in x direction. - * @param proportionY The proportion of shearing in y direction. - */ - public void setShear(double proportionX, double proportionY) { - xx = 1; - xy = proportionX; - xd = 0; - yx = proportionY; - yy = 1; - yd = 0; - } - - /** - * Sets this transformation to be a rotation around point (0, 0). - *

- * When the axis Y is directed up and X is directed to the right, the - * positive angle corresponds to the anti-clockwise rotation. When the axis - * Y is directed down and X is directed to the right, the positive angle - * corresponds to the clockwise rotation. - * - * @param angle_in_Radians The rotation angle in radian. - */ - public void setRotate(double angle_in_Radians) { - setRotate(Math.cos(angle_in_Radians), Math.sin(angle_in_Radians)); - } - - /** - * Produces a transformation that swaps x and y coordinate values. xx = 0.0; - * xy = 1.0; xd = 0; yx = 1.0; yy = 0.0; yd = 0; - */ - Transformation2D setSwapCoordinates() { - xx = 0.0; - xy = 1.0; - xd = 0; - yx = 1.0; - yy = 0.0; - yd = 0; - return this; - } - - /** - * Sets this transformation to be a rotation around point rotationCenter. - *

- * When the axis Y is directed up and X is directed to the right, the - * positive angle corresponds to the anti-clockwise rotation. When the axis - * Y is directed down and X is directed to the right, the positive angle - * corresponds to the clockwise rotation. - * - * @param angle_in_Radians The rotation angle in radian. - * @param rotationCenter The center point of the rotation. - */ - void setRotate(double angle_in_Radians, Point2D rotationCenter) { - setRotate(Math.cos(angle_in_Radians), Math.sin(angle_in_Radians), - rotationCenter); - } - - /** - * Sets rotation for this transformation. - *

- * When the axis Y is directed up and X is directed to the right, the - * positive angle corresponds to the anti-clockwise rotation. When the axis - * Y is directed down and X is directed to the right, the positive angle - * corresponds to the clockwise rotation. - * - * @param cosA The rotation angle. - * @param sinA The rotation angle. - */ - - public void setRotate(double cosA, double sinA) { - xx = cosA; - xy = -sinA; - xd = 0; - yx = sinA; - yy = cosA; - yd = 0; - } - - /** - * Sets this transformation to be a rotation around point rotationCenter. - *

- * When the axis Y is directed up and X is directed to the right, the - * positive angle corresponds to the anti-clockwise rotation. When the axis - * Y is directed down and X is directed to the right, the positive angle - * corresponds to the clockwise rotation. - * - * @param cosA The cos of the rotation angle. - * @param sinA The sin of the rotation angle. - * @param rotationCenter The center point of the rotation. - */ - void setRotate(double cosA, double sinA, Point2D rotationCenter) { - setShift(-rotationCenter.x, -rotationCenter.y); - Transformation2D temp = new Transformation2D(); - temp.setRotate(cosA, sinA); - multiply(temp); - shift(rotationCenter.x, rotationCenter.y); - } - - /** - * Shifts the transformation. - * - * @param x The shift factor in X direction. - * @param y The shift factor in Y direction. - */ - public void shift(double x, double y) { - xd += x; - yd += y; - } - - /** - * Scales the transformation. - * - * @param x The scale factor in X direction. - * @param y The scale factor in Y direction. - */ - public void scale(double x, double y) { - xx *= x; - xy *= x; - xd *= x; - yx *= y; - yy *= y; - yd *= y; - } - - /** - * Flips the transformation around the X axis. - * - * @param x0 The X coordinate to flip. - * @param x1 The X coordinate to flip to. - */ - public void flipX(double x0, double x1) { - xx = -xx; - xy = -xy; - xd = x0 + x1 - xd; - } - - /** - * Flips the transformation around the Y axis. - * - * @param y0 The Y coordinate to flip. - * @param y1 The Y coordinate to flip to. - */ - public void flipY(double y0, double y1) { - yx = -yx; - yy = -yy; - yd = y0 + y1 - yd; - } - - /** - * Shears the transformation. - * - * @param proportionX The proportion of shearing in x direction. - * @param proportionY The proportion of shearing in y direction. - */ - public void shear(double proportionX, double proportionY) { - Transformation2D temp = new Transformation2D(); - temp.setShear(proportionX, proportionY); - multiply(temp); - } - - /** - * Rotates the transformation. - * - * @param angle_in_Radians The rotation angle in radian. - */ - public void rotate(double angle_in_Radians) { - Transformation2D temp = new Transformation2D(); - temp.setRotate(angle_in_Radians); - multiply(temp); - } - - /** - * Rotates the transformation. - * - * @param cos The cos angle of the rotation. - * @param sin The sin angle of the rotation. - */ - public void rotate(double cos, double sin) { - Transformation2D temp = new Transformation2D(); - temp.setRotate(cos, sin); - multiply(temp); - } - - /** - * Rotates the transformation aroung a center point. - * - * @param cos The cos angle of the rotation. - * @param sin sin angle of the rotation. - * @param rotationCenter The center point of the rotation. - */ - public void rotate(double cos, double sin, Point2D rotationCenter) { - Transformation2D temp = new Transformation2D(); - temp.setRotate(cos, sin, rotationCenter); - multiply(temp); - } - - /** - * Produces inverse matrix for this matrix and puts result into the inverse - * parameter. - * - * @param inverse The result inverse matrix. - */ - public void inverse(Transformation2D inverse) { - double det = xx * yy - xy * yx; - - if (det == 0) { - inverse.setZero(); - return; - } - - det = 1 / det; - - inverse.xd = (xy * yd - xd * yy) * det; - inverse.yd = (xd * yx - xx * yd) * det; - inverse.xx = yy * det; - inverse.xy = -xy * det; - inverse.yx = -yx * det; - inverse.yy = xx * det; - } - - /** - * Inverses the matrix. - */ - public void inverse() { - inverse(this); - } - - /** - * Extracts scaling part of the transformation. this == scale * - * rotateNshearNshift. - * - * @param scale The destination matrix where the scale part is copied. - * @param rotateNshearNshift The destination matrix where the part excluding rotation is - * copied. - */ - public void extractScaleTransform(Transformation2D scale, - Transformation2D rotateNshearNshift) { - - scale.setScale(Math.sqrt(xx * xx + xy * xy), - Math.sqrt(yx * yx + yy * yy)); - rotateNshearNshift.setScale(1.0 / scale.xx, 1.0 / scale.yy); - rotateNshearNshift.multiply(this); - } - + pt1.setCoords(xx, yx); + pt2.setCoords(xy, yy); + pt1.sub(pt1); + double d1 = pt1.sqrLength() * 0.5; + pt1.setCoords(xx, yx); + pt2.setCoords(xy, yy); + pt1.add(pt2); + double d2 = pt1.sqrLength() * 0.5; + return tolerance * ((d1 > d2) ? Math.sqrt(d1) : Math.sqrt(d2)); + } + + // Performs linear part of the transformation only. Same as if xd, yd would + // be zeroed. + void transformWithoutShift(Point2D[] pointsIn, int from, int count, + Point2D[] pointsOut) { + for (int i = from, n = from + count; i < n; i++) { + Point2D p = pointsIn[i]; + double new_x = xx * p.x + xy * p.y; + double new_y = yx * p.x + yy * p.y; + pointsOut[i].setCoords(new_x, new_y); + } + } + + Point2D transformWithoutShift(Point2D srcPoint) { + double new_x = xx * srcPoint.x + xy * srcPoint.y; + double new_y = yx * srcPoint.x + yy * srcPoint.y; + return Point2D.construct(new_x, new_y); + } + + /** + * Sets this matrix to be the identity matrix. + */ + public void setIdentity() { + xx = 1.0; + xy = 0; + xd = 0; + yx = 0; + yy = 1.0; + yd = 0; + } + + /** + * Returns TRUE if this matrix is the identity matrix. + */ + public boolean isIdentity() { + return xx == 1.0 && yy == 1.0 + && (0 == xy && 0 == xd && 0 == yx && 0 == yd); + } + + /** + * Returns TRUE if this matrix is an identity matrix within the given + * tolerance. + * + * @param tol + * The tolerance value. + */ + public boolean isIdentity(double tol) { + Point2D pt = Point2D.construct(0., 1.); + transform(pt, pt); + pt.sub(Point2D.construct(0., 1.)); + if (pt.sqrLength() > tol * tol) + return false; + + pt.setCoords(0, 0); + transform(pt, pt); + if (pt.sqrLength() > tol * tol) + return false; + + pt.setCoords(1.0, 0.0); + transform(pt, pt); + pt.sub(Point2D.construct(1.0, 0.0)); + return pt.sqrLength() <= tol * tol; + } + + /** + * Returns TRUE for reflective transformations. It inverts the sign of + * vector cross product. + */ + public boolean isReflective() { + return xx * yy - yx * xy < 0; + } + + /** + * Returns TRUE if this transformation is a uniform transformation. + * + * The uniform transformation is a transformation, which transforms a square + * to a square. + */ + public boolean isUniform(double eps) { + double v1 = xx * xx + yx * yx; + double v2 = xy * xy + yy * yy; + double e = (v1 + v2) * eps; + return Math.abs(v1 - v2) <= e && Math.abs(xx * xy + yx * yy) <= e; + } + + /** + * Returns TRUE if this transformation is a shift transformation. The shift + * transformation performs shift only. + */ + public boolean isShift() { + return xx == 1.0 && yy == 1.0 && 0 == xy && 0 == yx; + } + + /** + * Returns TRUE if this transformation is a shift transformation within the + * given tolerance. + * + * @param tol + * The tolerance value. + */ + public boolean isShift(double tol) { + Point2D pt = transformWithoutShift(Point2D.construct(0.0, 1.0)); + pt.y -= 1.0; + if (pt.sqrLength() > tol * tol) + return false; + + pt = transformWithoutShift(Point2D.construct(1.0, 0.0)); + pt.x -= 1.0; + return pt.sqrLength() <= tol * tol; + } + + /** + * Returns TRUE if this is an orthonormal transformation with the given + * tolerance. The orthonormal: Rotation or rotoinversion and shift + * (preserves lengths of vectors and angles between vectors). + * + * @param tol + * The tolerance value. + */ + public boolean isOrthonormal(double tol) { + Transformation2D r = new Transformation2D(); + r.xx = xx * xx + xy * xy; + r.xy = xx * yx + xy * yy; + r.yx = yx * xx + yy * xy; + r.yy = yx * yx + yy * yy; + r.xd = 0; + r.yd = 0; + + return r.isIdentity(tol); + } + + /** + * Returns TRUE if this matrix is degenerated (does not have an inverse) + * within the given tolerance. + * + * @param tol + * The tolerance value. + */ + public boolean isDegenerate(double tol) { + return Math.abs(xx * yy - yx * xy) <= 2 * tol + * (Math.abs(xx * yy) + Math.abs(yx * xy)); + } + + /** + * Returns TRUE, if this transformation does not have rotation and shear + * within the given tolerance. + * + * @param tol + * The tolerance value. + */ + public boolean isScaleAndShift(double tol) { + return xy * xy + yx * yx < (xx * xx + yy * yy) * tol; + } + + /** + * Set this transformation to be a shift. + * + * @param x + * The X coordinate to shift to. + * @param y + * The Y coordinate to shift to. + */ + public void setShift(double x, double y) { + xx = 1; + xy = 0; + xd = x; + yx = 0; + yy = 1; + yd = y; + } + + /** + * Set this transformation to be a scale. + * + * @param x + * The X coordinate to scale to. + * @param y + * The Y coordinate to scale to. + */ + public void setScale(double x, double y) { + xx = x; + xy = 0; + xd = 0; + yx = 0; + yy = y; + yd = 0; + } + + /** + * Set transformation to be a uniform scale. + * + * @param _scale + * The scale of the transformation. + */ + public void setScale(double _scale) { + setScale(_scale, _scale); + } + + /** + * Sets the transformation to be a flip around the X axis. Flips the X + * coordinates so that the x0 becomes x1 and vice verse. + * + * @param x0 + * The X coordinate to flip. + * @param x1 + * The X coordinate to flip to. + */ + public void setFlipX(double x0, double x1) { + xx = -1; + xy = 0; + xd = x0 + x1; + yx = 0; + yy = 1; + yd = 0; + } + + /** + * Sets the transformation to be a flip around the Y axis. Flips the Y + * coordinates so that the y0 becomes y1 and vice verse. + * + * @param y0 + * The Y coordinate to flip. + * @param y1 + * The Y coordinate to flip to. + */ + public void setFlipY(double y0, double y1) { + xx = 1; + xy = 0; + xd = 0; + yx = 0; + yy = -1; + yd = y0 + y1; + } + + /** + * Set transformation to a shear. + * + * @param proportionX + * The proportion of shearing in x direction. + * @param proportionY + * The proportion of shearing in y direction. + */ + public void setShear(double proportionX, double proportionY) { + xx = 1; + xy = proportionX; + xd = 0; + yx = proportionY; + yy = 1; + yd = 0; + } + + /** + * Sets this transformation to be a rotation around point (0, 0). + * + * When the axis Y is directed up and X is directed to the right, the + * positive angle corresponds to the anti-clockwise rotation. When the axis + * Y is directed down and X is directed to the right, the positive angle + * corresponds to the clockwise rotation. + * + * @param angle_in_Radians + * The rotation angle in radian. + */ + public void setRotate(double angle_in_Radians) { + setRotate(Math.cos(angle_in_Radians), Math.sin(angle_in_Radians)); + } + + /** + * Produces a transformation that swaps x and y coordinate values. xx = 0.0; + * xy = 1.0; xd = 0; yx = 1.0; yy = 0.0; yd = 0; + */ + Transformation2D setSwapCoordinates() { + xx = 0.0; + xy = 1.0; + xd = 0; + yx = 1.0; + yy = 0.0; + yd = 0; + return this; + } + + /** + * Sets this transformation to be a rotation around point rotationCenter. + * + * When the axis Y is directed up and X is directed to the right, the + * positive angle corresponds to the anti-clockwise rotation. When the axis + * Y is directed down and X is directed to the right, the positive angle + * corresponds to the clockwise rotation. + * + * @param angle_in_Radians + * The rotation angle in radian. + * @param rotationCenter + * The center point of the rotation. + */ + void setRotate(double angle_in_Radians, Point2D rotationCenter) { + setRotate(Math.cos(angle_in_Radians), Math.sin(angle_in_Radians), + rotationCenter); + } + + /** + * Sets rotation for this transformation. + * + * When the axis Y is directed up and X is directed to the right, the + * positive angle corresponds to the anti-clockwise rotation. When the axis + * Y is directed down and X is directed to the right, the positive angle + * corresponds to the clockwise rotation. + * + * @param cosA + * The rotation angle. + * @param sinA + * The rotation angle. + */ + + public void setRotate(double cosA, double sinA) { + xx = cosA; + xy = -sinA; + xd = 0; + yx = sinA; + yy = cosA; + yd = 0; + } + + /** + * Sets this transformation to be a rotation around point rotationCenter. + * + * When the axis Y is directed up and X is directed to the right, the + * positive angle corresponds to the anti-clockwise rotation. When the axis + * Y is directed down and X is directed to the right, the positive angle + * corresponds to the clockwise rotation. + * + * @param cosA + * The cos of the rotation angle. + * @param sinA + * The sin of the rotation angle. + * @param rotationCenter + * The center point of the rotation. + */ + void setRotate(double cosA, double sinA, Point2D rotationCenter) { + setShift(-rotationCenter.x, -rotationCenter.y); + Transformation2D temp = new Transformation2D(); + temp.setRotate(cosA, sinA); + multiply(temp); + shift(rotationCenter.x, rotationCenter.y); + } + + /** + * Shifts the transformation. + * + * @param x + * The shift factor in X direction. + * @param y + * The shift factor in Y direction. + */ + public void shift(double x, double y) { + xd += x; + yd += y; + } + + /** + * Scales the transformation. + * + * @param x + * The scale factor in X direction. + * @param y + * The scale factor in Y direction. + */ + public void scale(double x, double y) { + xx *= x; + xy *= x; + xd *= x; + yx *= y; + yy *= y; + yd *= y; + } + + /** + * Flips the transformation around the X axis. + * + * @param x0 + * The X coordinate to flip. + * @param x1 + * The X coordinate to flip to. + */ + public void flipX(double x0, double x1) { + xx = -xx; + xy = -xy; + xd = x0 + x1 - xd; + } + + /** + * Flips the transformation around the Y axis. + * + * @param y0 + * The Y coordinate to flip. + * @param y1 + * The Y coordinate to flip to. + */ + public void flipY(double y0, double y1) { + yx = -yx; + yy = -yy; + yd = y0 + y1 - yd; + } + + /** + * Shears the transformation. + * + * @param proportionX + * The proportion of shearing in x direction. + * @param proportionY + * The proportion of shearing in y direction. + */ + public void shear(double proportionX, double proportionY) { + Transformation2D temp = new Transformation2D(); + temp.setShear(proportionX, proportionY); + multiply(temp); + } + + /** + * Rotates the transformation. + * + * @param angle_in_Radians + * The rotation angle in radian. + */ + public void rotate(double angle_in_Radians) { + Transformation2D temp = new Transformation2D(); + temp.setRotate(angle_in_Radians); + multiply(temp); + } + + /** + * Rotates the transformation. + * + * @param cos + * The cos angle of the rotation. + * @param sin + * The sin angle of the rotation. + */ + public void rotate(double cos, double sin) { + Transformation2D temp = new Transformation2D(); + temp.setRotate(cos, sin); + multiply(temp); + } + + /** + * Rotates the transformation aroung a center point. + * + * @param cos + * The cos angle of the rotation. + * @param sin + * sin angle of the rotation. + * @param rotationCenter + * The center point of the rotation. + */ + public void rotate(double cos, double sin, Point2D rotationCenter) { + Transformation2D temp = new Transformation2D(); + temp.setRotate(cos, sin, rotationCenter); + multiply(temp); + } + + /** + * Produces inverse matrix for this matrix and puts result into the inverse + * parameter. + * + * @param inverse + * The result inverse matrix. + */ + public void inverse(Transformation2D inverse) { + double det = xx * yy - xy * yx; + + if (det == 0) { + inverse.setZero(); + return; + } + + det = 1 / det; + + inverse.xd = (xy * yd - xd * yy) * det; + inverse.yd = (xd * yx - xx * yd) * det; + inverse.xx = yy * det; + inverse.xy = -xy * det; + inverse.yx = -yx * det; + inverse.yy = xx * det; + } + + /** + * Inverses the matrix. + * + */ + public void inverse() { + inverse(this); + } + + /** + * Extracts scaling part of the transformation. this == scale * + * rotateNshearNshift. + * + * @param scale + * The destination matrix where the scale part is copied. + * @param rotateNshearNshift + * The destination matrix where the part excluding rotation is + * copied. + */ + public void extractScaleTransform(Transformation2D scale, + Transformation2D rotateNshearNshift) { + + scale.setScale(Math.sqrt(xx * xx + xy * xy), + Math.sqrt(yx * yx + yy * yy)); + rotateNshearNshift.setScale(1.0 / scale.xx, 1.0 / scale.yy); + rotateNshearNshift.multiply(this); + } + + public long estimateMemorySize() + { + return SIZE_OF_TRANSFORMATION_2D; + } } diff --git a/src/main/java/com/esri/core/geometry/Transformation3D.java b/src/main/java/com/esri/core/geometry/Transformation3D.java index 3890c370..1ac7465e 100644 --- a/src/main/java/com/esri/core/geometry/Transformation3D.java +++ b/src/main/java/com/esri/core/geometry/Transformation3D.java @@ -35,228 +35,228 @@ */ final class Transformation3D { - public double xx, yx, zx, xd, xy, yy, zy, yd, xz, yz, zz, zd; - - public Transformation3D() { - - } - - /** - * Sets all elements to 0, thus producing and invalid transformation. - */ - public void setZero() { - xx = 0.0; - yx = 0.0; - zx = 0.0; - xy = 0.0; - yy = 0.0; - zy = 0.0; - xz = 0.0; - yz = 0.0; - zz = 0.0; - xd = 0.0; - yd = 0.0; - zd = 0.0; - } - - public void setScale(double scaleX, double scaleY, double scaleZ) { - xx = scaleX; - yx = 0.0; - zx = 0.0; - xy = 0.0; - yy = scaleY; - zy = 0.0; - xz = 0.0; - yz = 0.0; - zz = scaleZ; - xd = 0.0; - yd = 0.0; - zd = 0.0; - } - - public void setTranslate(double deltax, double deltay, double deltaz) { - xx = 1.0; - yx = 0.0; - zx = 0.0; - xy = 0.0; - yy = 1.0; - zy = 0.0; - xz = 0.0; - yz = 0.0; - zz = 1.0; - xd = deltax; - yd = deltay; - zd = deltaz; - } - - public void translate(double deltax, double deltay, double deltaz) { - xd += deltax; - yd += deltay; - zd += deltaz; - } - - /** - * Transforms an envelope. The result is the bounding box of the transformed - * envelope. - */ - public Envelope3D transform(Envelope3D env) { - - if (env.isEmpty()) - return env; - - Point3D[] buf = new Point3D[8]; - env.queryCorners(buf); - - transform(buf, 8, buf); - env.setFromPoints(buf); - return env; - } - - void transform(Point3D[] pointsIn, int count, Point3D[] pointsOut) { - for (int i = 0; i < count; i++) { - Point3D res = new Point3D(); - Point3D src = pointsIn[i]; - res.x = xx * src.x + xy * src.y + xz * src.z + xd; - res.y = yx * src.x + yy * src.y + yz * src.z + yd; - res.z = zx * src.x + zy * src.y + zz * src.z + zd; - pointsOut[i] = res; - } - } - - public Point3D transform(Point3D src) { - Point3D res = new Point3D(); - res.x = xx * src.x + xy * src.y + xz * src.z + xd; - res.y = yx * src.x + yy * src.y + yz * src.z + yd; - res.z = zx * src.x + zy * src.y + zz * src.z + zd; - return res; - } - - public void transform(Point3D[] points, int start, int count) { - int n = Math.min(points.length, start + count); - for (int i = start; i < n; i++) { - Point3D res = new Point3D(); - Point3D src = points[i]; - res.x = xx * src.x + xy * src.y + xz * src.z + xd; - res.y = yx * src.x + yy * src.y + yz * src.z + yd; - res.z = zx * src.x + zy * src.y + zz * src.z + zd; - points[i] = res; - } - } - - public void mul(Transformation3D right) { - multiply(this, right, this); - } - - public void mulLeft(Transformation3D left) { - multiply(left, this, this); - } - - /** - * Performs multiplication of matrices a and b and places result into - * result. The a, b, and result could point to same objects.
- * Equivalent to result = a * b. - */ - // static - public static void multiply(Transformation3D a, Transformation3D b, - Transformation3D result) { - double xx, yx, zx; - double xy, yy, zy; - double xz, yz, zz; - double xd, yd, zd; - - xx = a.xx * b.xx + a.yx * b.xy + a.zx * b.xz; - yx = a.xx * b.yx + a.yx * b.yy + a.zx * b.yz; - zx = a.xx * b.zx + a.yx * b.zy + a.zx * b.zz; - xy = a.xy * b.xx + a.yy * b.xy + a.zy * b.xz; - yy = a.xy * b.yx + a.yy * b.yy + a.zy * b.yz; - zy = a.xy * b.zx + a.yy * b.zy + a.zy * b.zz; - xz = a.xz * b.xx + a.yz * b.xy + a.zz * b.xz; - yz = a.xz * b.yx + a.yz * b.yy + a.zz * b.yz; - zz = a.xz * b.zx + a.yz * b.zy + a.zz * b.zz; - xd = a.xd * b.xx + a.yd * b.xy + a.zd * b.xz + b.xd; - yd = a.xd * b.yx + a.yd * b.yy + a.zd * b.yz + b.yd; - zd = a.xd * b.zx + a.yd * b.zy + a.zd * b.zz + b.zd; - - result.xx = xx; - result.yx = yx; - result.zx = zx; - result.xy = xy; - result.yy = yy; - result.zy = zy; - result.xz = xz; - result.yz = yz; - result.zz = zz; - result.xd = xd; - result.yd = yd; - result.zd = zd; - } - - /** - * Calculates the Inverse transformation. - * - * @param src The input transformation. - * @param result The inverse of the input transformation. Throws the - * GeometryException("math singularity") exception if the Inverse - * can not be calculated. - */ - public static void inverse(Transformation3D src, Transformation3D result) { - double det = src.xx * (src.yy * src.zz - src.zy * src.yz) - src.yx - * (src.xy * src.zz - src.zy * src.xz) + src.zx - * (src.xy * src.yz - src.yy * src.xz); - if (det != 0) { - double xx, yx, zx; - double xy, yy, zy; - double xz, yz, zz; - double xd, yd, zd; - - double det_1 = 1.0 / det; - xx = (src.yy * src.zz - src.zy * src.yz) * det_1; - xy = -(src.xy * src.zz - src.zy * src.xz) * det_1; - xz = (src.xy * src.yz - src.yy * src.xz) * det_1; - - yx = -(src.yx * src.zz - src.yz * src.zx) * det_1; - yy = (src.xx * src.zz - src.zx * src.xz) * det_1; - yz = -(src.xx * src.yz - src.yx * src.xz) * det_1; - - zx = (src.yx * src.zy - src.zx * src.yy) * det_1; - zy = -(src.xx * src.zy - src.zx * src.xy) * det_1; - zz = (src.xx * src.yy - src.yx * src.xy) * det_1; - - xd = -(src.xd * xx + src.yd * xy + src.zd * xz); - yd = -(src.xd * yx + src.yd * yy + src.zd * yz); - zd = -(src.xd * zx + src.yd * zy + src.zd * zz); - - result.xx = xx; - result.yx = yx; - result.zx = zx; - result.xy = xy; - result.yy = yy; - result.zy = zy; - result.xz = xz; - result.yz = yz; - result.zz = zz; - result.xd = xd; - result.yd = yd; - result.zd = zd; - } else { - throw new GeometryException("math singularity"); - } - } - - public Transformation3D copy() { - Transformation3D result = new Transformation3D(); - result.xx = xx; - result.yx = yx; - result.zx = zx; - result.xy = xy; - result.yy = yy; - result.zy = zy; - result.xz = xz; - result.yz = yz; - result.zz = zz; - result.xd = xd; - result.yd = yd; - result.zd = zd; - return result; - } + public double xx, yx, zx, xd, xy, yy, zy, yd, xz, yz, zz, zd; + + public Transformation3D() { + + } + + /** + * Sets all elements to 0, thus producing and invalid transformation. + */ + public void setZero() { + xx = 0.0; + yx = 0.0; + zx = 0.0; + xy = 0.0; + yy = 0.0; + zy = 0.0; + xz = 0.0; + yz = 0.0; + zz = 0.0; + xd = 0.0; + yd = 0.0; + zd = 0.0; + } + + public void setScale(double scaleX, double scaleY, double scaleZ) { + xx = scaleX; + yx = 0.0; + zx = 0.0; + xy = 0.0; + yy = scaleY; + zy = 0.0; + xz = 0.0; + yz = 0.0; + zz = scaleZ; + xd = 0.0; + yd = 0.0; + zd = 0.0; + } + + public void setTranslate(double deltax, double deltay, double deltaz) { + xx = 1.0; + yx = 0.0; + zx = 0.0; + xy = 0.0; + yy = 1.0; + zy = 0.0; + xz = 0.0; + yz = 0.0; + zz = 1.0; + xd = deltax; + yd = deltay; + zd = deltaz; + } + + public void translate(double deltax, double deltay, double deltaz) { + xd += deltax; + yd += deltay; + zd += deltaz; + } + + /** + * Transforms an envelope. The result is the bounding box of the transformed + * envelope. + */ + public Envelope3D transform(Envelope3D env) { + + if (env.isEmpty()) + return env; + + Point3D[] buf = new Point3D[8]; + env.queryCorners(buf); + + transform(buf, 8, buf); + env.setFromPoints(buf); + return env; + } + + void transform(Point3D[] pointsIn, int count, Point3D[] pointsOut) { + for (int i = 0; i < count; i++) { + Point3D res = new Point3D(); + Point3D src = pointsIn[i]; + res.x = xx * src.x + xy * src.y + xz * src.z + xd; + res.y = yx * src.x + yy * src.y + yz * src.z + yd; + res.z = zx * src.x + zy * src.y + zz * src.z + zd; + pointsOut[i] = res; + } + } + + public Point3D transform(Point3D src) { + Point3D res = new Point3D(); + res.x = xx * src.x + xy * src.y + xz * src.z + xd; + res.y = yx * src.x + yy * src.y + yz * src.z + yd; + res.z = zx * src.x + zy * src.y + zz * src.z + zd; + return res; + } + + public void transform(Point3D[] points, int start, int count) { + int n = Math.min(points.length, start + count); + for (int i = start; i < n; i++) { + Point3D res = new Point3D(); + Point3D src = points[i]; + res.x = xx * src.x + xy * src.y + xz * src.z + xd; + res.y = yx * src.x + yy * src.y + yz * src.z + yd; + res.z = zx * src.x + zy * src.y + zz * src.z + zd; + points[i] = res; + } + } + + public void mul(Transformation3D right) { + multiply(this, right, this); + } + + public void mulLeft(Transformation3D left) { + multiply(left, this, this); + } + + /** + * Performs multiplication of matrices a and b and places result into + * result. The a, b, and result could point to same objects.
+ * Equivalent to result = a * b. + */ + // static + public static void multiply(Transformation3D a, Transformation3D b, + Transformation3D result) { + double xx, yx, zx; + double xy, yy, zy; + double xz, yz, zz; + double xd, yd, zd; + + xx = a.xx * b.xx + a.yx * b.xy + a.zx * b.xz; + yx = a.xx * b.yx + a.yx * b.yy + a.zx * b.yz; + zx = a.xx * b.zx + a.yx * b.zy + a.zx * b.zz; + xy = a.xy * b.xx + a.yy * b.xy + a.zy * b.xz; + yy = a.xy * b.yx + a.yy * b.yy + a.zy * b.yz; + zy = a.xy * b.zx + a.yy * b.zy + a.zy * b.zz; + xz = a.xz * b.xx + a.yz * b.xy + a.zz * b.xz; + yz = a.xz * b.yx + a.yz * b.yy + a.zz * b.yz; + zz = a.xz * b.zx + a.yz * b.zy + a.zz * b.zz; + xd = a.xd * b.xx + a.yd * b.xy + a.zd * b.xz + b.xd; + yd = a.xd * b.yx + a.yd * b.yy + a.zd * b.yz + b.yd; + zd = a.xd * b.zx + a.yd * b.zy + a.zd * b.zz + b.zd; + + result.xx = xx; + result.yx = yx; + result.zx = zx; + result.xy = xy; + result.yy = yy; + result.zy = zy; + result.xz = xz; + result.yz = yz; + result.zz = zz; + result.xd = xd; + result.yd = yd; + result.zd = zd; + } + + /** + * Calculates the Inverse transformation. + * + * @param src The input transformation. + * @param result The inverse of the input transformation. Throws the + * GeometryException("math singularity") exception if the Inverse + * can not be calculated. + */ + public static void inverse(Transformation3D src, Transformation3D result) { + double det = src.xx * (src.yy * src.zz - src.zy * src.yz) - src.yx + * (src.xy * src.zz - src.zy * src.xz) + src.zx + * (src.xy * src.yz - src.yy * src.xz); + if (det != 0) { + double xx, yx, zx; + double xy, yy, zy; + double xz, yz, zz; + double xd, yd, zd; + + double det_1 = 1.0 / det; + xx = (src.yy * src.zz - src.zy * src.yz) * det_1; + xy = -(src.xy * src.zz - src.zy * src.xz) * det_1; + xz = (src.xy * src.yz - src.yy * src.xz) * det_1; + + yx = -(src.yx * src.zz - src.yz * src.zx) * det_1; + yy = (src.xx * src.zz - src.zx * src.xz) * det_1; + yz = -(src.xx * src.yz - src.yx * src.xz) * det_1; + + zx = (src.yx * src.zy - src.zx * src.yy) * det_1; + zy = -(src.xx * src.zy - src.zx * src.xy) * det_1; + zz = (src.xx * src.yy - src.yx * src.xy) * det_1; + + xd = -(src.xd * xx + src.yd * xy + src.zd * xz); + yd = -(src.xd * yx + src.yd * yy + src.zd * yz); + zd = -(src.xd * zx + src.yd * zy + src.zd * zz); + + result.xx = xx; + result.yx = yx; + result.zx = zx; + result.xy = xy; + result.yy = yy; + result.zy = zy; + result.xz = xz; + result.yz = yz; + result.zz = zz; + result.xd = xd; + result.yd = yd; + result.zd = zd; + } else { + throw new GeometryException("math singularity"); + } + } + + public Transformation3D copy() { + Transformation3D result = new Transformation3D(); + result.xx = xx; + result.yx = yx; + result.zx = zx; + result.xy = xy; + result.yy = yy; + result.zy = zy; + result.xz = xz; + result.yz = yz; + result.zz = zz; + result.xd = xd; + result.yd = yd; + result.zd = zd; + return result; + } } diff --git a/src/main/java/com/esri/core/geometry/Treap.java b/src/main/java/com/esri/core/geometry/Treap.java index 3a815530..e67eaf6d 100644 --- a/src/main/java/com/esri/core/geometry/Treap.java +++ b/src/main/java/com/esri/core/geometry/Treap.java @@ -26,945 +26,945 @@ package com.esri.core.geometry; final class Treap { - static abstract class Comparator { - Comparator() { - m_b_notify_on_actions = false; - } - - Comparator(boolean bNotifyOnActions) { - m_b_notify_on_actions = bNotifyOnActions; - } - - // Compares the element elm to the element contained in the given node - abstract int compare(Treap treap, int elm, int node); - - // These virtual methods are called only when Comparator(true) ctro has - // been used. - void onDelete(int elm) { - } - - void onSet(int elm) { - } - - void onEndSearch(int elm) { - } - - void onAddUniqueElementFailed(int elm) { - } - - private boolean m_b_notify_on_actions; - - // void operator=(const Comparator&); // do not allow operator = - void onDeleteImpl_(Treap treap, int node) { - if (m_b_notify_on_actions) - onDelete(treap.getElement(node)); - } - - void onSetImpl_(Treap treap, int node) { - if (m_b_notify_on_actions) - onSet(treap.getElement(node)); - } - - void onAddUniqueElementFailedImpl_(int elm) { - if (m_b_notify_on_actions) - onAddUniqueElementFailed(elm); - } - - void onEndSearchImpl_(int elm) { - if (m_b_notify_on_actions) - onEndSearch(elm); - } - } - - ; - - static abstract class MonikerComparator { - // Compares the moniker, contained in the MonikerComparator with the - // element contained in the given node. - abstract int compare(Treap treap, int node); - } - - ; - - public Treap() { - m_random = 124234251; - m_b_balancing = true; - m_touchFlag = 0; - m_defaultTreap = nullNode(); - m_treapData = new StridedIndexTypeCollection(7); - m_comparator = null; - } - - // Sets the comparator - public void setComparator(Comparator comparator) { - m_comparator = comparator; - } - - // Returns the comparator - public Comparator getComparator() { - return m_comparator; - } - - // Stops auto-balancing - public void disableBalancing() { - m_b_balancing = false; - } - - // Reserves memory for nodes givne number of nodes - public void setCapacity(int capacity) { - m_treapData.setCapacity(capacity); - } - - // Create a new treap and returns the treap handle. - public int createTreap(int treap_data) { - int treap = m_treapData.newElement(); - setSize_(0, treap); - setTreapData_(treap_data, treap); - return treap; - } - - // Deletes the treap at the given treap handle. - public void deleteTreap(int treap) { - m_treapData.deleteElement(treap); - } - - // Adds new element to the treap. Allows duplicates to be added. - public int addElement(int element, int treap) { - int treap_; - if (treap == -1) { - if (m_defaultTreap == nullNode()) - m_defaultTreap = createTreap(-1); - treap_ = m_defaultTreap; - } else { - treap_ = treap; - } - - return addElement_(element, 0, treap_); - } - - // Adds new element to the treap if it is not equal to other elements. - // If the return value is -1, then get_duplicate_element reutrns the node of - // the already existing element equal to element. - public int addUniqueElement(int element, int treap) { - int treap_; - if (treap == -1) { - if (m_defaultTreap == nullNode()) - m_defaultTreap = createTreap(-1); - treap_ = m_defaultTreap; - } else { - treap_ = treap; - } - - return addElement_(element, 1, treap_); - } - - // Adds a new element to the treap that is known to be bigger or equal of - // all elements already in the treap. - // Use this method when adding elements from a sorted list for maximum - // performance (it does not call the treap comparator). - public int addBiggestElement(int element, int treap) { - int treap_; - if (treap == -1) { - if (m_defaultTreap == nullNode()) - m_defaultTreap = createTreap(-1); - treap_ = m_defaultTreap; - } else { - treap_ = treap; - } - - if (getRoot_(treap_) == nullNode()) { - int newNode = newNode_(element); - setRoot_(newNode, treap_); - addToList_(-1, newNode, treap_); - return newNode; - } - - int cur = getLast_(treap_); - int newNode = newNode_(element); - setRight_(cur, newNode); - setParent_(newNode, cur); - assert (m_b_balancing);// don't use this method for unbalanced tree, or - // the performance will be bad. - bubbleUp_(newNode); - if (getParent(newNode) == nullNode()) - setRoot_(newNode, treap_); - - addToList_(-1, newNode, treap_); - return newNode; - } - - // template void build_from_sorted(const Iterator& begin, - // const Iterator& end); - // Adds new element to the treap at the known position, thus avoiding a call - // to the comparator. - // If bCallCompare is True, the comparator will be called at most twice, - // once to compare with prevElement and once to compare with nextElement. - // When bUnique is true, if the return value is -1, then - // get_duplicate_element reutrns the node of the already existing element. - public int addElementAtPosition(int prevNode, int nextNode, int element, - boolean bUnique, boolean bCallCompare, int treap) { - int treap_ = treap; - if (treap_ == -1) { - if (m_defaultTreap == nullNode()) - m_defaultTreap = createTreap(-1); - treap_ = m_defaultTreap; - } - - // dbg_check_(m_root); - if (getRoot_(treap_) == nullNode()) { - assert (nextNode == nullNode() && prevNode == nullNode()); - int root = newNode_(element); - setRoot_(root, treap_); - addToList_(-1, root, treap_); - return root; - } - - int cmpNext; - int cmpPrev; - if (bCallCompare) { - cmpNext = nextNode != nullNode() ? m_comparator.compare(this, - element, nextNode) : -1; - assert (cmpNext <= 0); - cmpPrev = prevNode != nullNode() ? m_comparator.compare(this, - element, prevNode) : 1; - // cmpPrev can be negative in plane sweep when intersection is - // detected. - } else { - cmpNext = -1; - cmpPrev = 1; - } - - if (bUnique && (cmpNext == 0 || cmpPrev == 0)) { - m_comparator.onAddUniqueElementFailedImpl_(element); - int cur = cmpNext == 0 ? nextNode : prevNode; - setDuplicateElement_(cur, treap_); - return -1;// return negative value. - } - - int cur; - int cmp; - boolean bNext; - if (nextNode != nullNode() && prevNode != nullNode()) { - // randomize the the cost to insert a node. - bNext = m_random > NumberUtils.nextRand(m_random) >> 1; - } else - bNext = nextNode != nullNode(); - - if (bNext) { - cmp = cmpNext; - cur = nextNode; - } else { - cmp = cmpPrev; - cur = prevNode; - } - - int newNode = -1; - int before = -1; - boolean b_first = true; - for (; ; ) { - if (cmp < 0) { - int left = getLeft(cur); - if (left != nullNode()) - cur = left; - else { - before = cur; - newNode = newNode_(element); - setLeft_(cur, newNode); - setParent_(newNode, cur); - break; - } - } else { - int right = getRight(cur); - if (right != nullNode()) - cur = right; - else { - before = getNext(cur); - newNode = newNode_(element); - setRight_(cur, newNode); - setParent_(newNode, cur); - break; - } - } - - if (b_first) { - cmp *= -1; - b_first = false; - } - } - - bubbleUp_(newNode); - if (getParent(newNode) == nullNode()) - setRoot_(newNode, treap_); - - addToList_(before, newNode, treap_); - // dbg_check_(m_root); - return newNode; - } - - // Get duplicate element - public int getDuplicateElement(int treap) { - if (treap == -1) - return getDuplicateElement_(m_defaultTreap); - - return getDuplicateElement_(treap); - } - - // Removes a node from the treap. Throws if doesn't exist. - public void deleteNode(int treap_node_index, int treap) { - touch_(); - // assert(isValidNode(treap_node_index)); - if (m_comparator != null) - m_comparator.onDeleteImpl_(this, treap_node_index); - - int treap_; - if (treap == -1) - treap_ = m_defaultTreap; - else - treap_ = treap; - - if (!m_b_balancing) { - unbalancedDelete_(treap_node_index, treap_); - } else - deleteNode_(treap_node_index, treap_); - } - - // Finds an element in the treap and returns its node or -1. - public int search(int data, int treap) { - int cur = getRoot(treap); - while (cur != nullNode()) { - int res = m_comparator.compare(this, data, cur); - if (res == 0) - return cur; - else if (res < 0) - cur = getLeft(cur); - else - cur = getRight(cur); - } - - m_comparator.onEndSearchImpl_(data); - return nullNode(); - } - - // Find a first node in the treap which is less or equal the moniker. - // Returns closest smaller (Comparator::compare returns -1) or any equal. - public int searchLowerBound(MonikerComparator moniker, int treap) { - int cur = getRoot(treap); - int bound = -1; - while (cur != nullNode()) { - int res = moniker.compare(this, cur); - if (res == 0) - return cur; - else if (res < 0) - cur = getLeft(cur); - else { - bound = cur; - cur = getRight(cur); - } - } - - return bound; - } - - // Find a first node in the treap which is greater or equal the moniker. - // Returns closest greater (Comparator::compare returns 1) or any equal. - public int searchUpperBound(MonikerComparator moniker, int treap) { - int cur = getRoot(treap); - int bound = -1; - while (cur != nullNode()) { - int res = moniker.compare(this, cur); - if (res == 0) - return cur; - else if (res < 0) { - bound = cur; - cur = getLeft(cur); - } else { - cur = getRight(cur); - } - } - - return bound; - } - - // Returns treap node data (element) from the given node index. - public int getElement(int treap_node_index) { - return m_treapData.getField(treap_node_index, 3);// no error checking - // here - } - - // Returns treap node for the left node for the given treap node index - public int getLeft(int treap_node_index) { - return m_treapData.getField(treap_node_index, 0);// no error checking - // here - } - - // Returns treap index for the right node for the given treap node index - public int getRight(int treap_node_index) { - return m_treapData.getField(treap_node_index, 1);// no error checking - // here - } - - // Returns treap index for the parent node for the given treap node index - public int getParent(int treap_node_index) { - return m_treapData.getField(treap_node_index, 2);// no error checking - // here - } - - // Returns next treap index. Allows to navigate Treap in the sorted order - public int getNext(int treap_node_index) { - return m_treapData.getField(treap_node_index, 6); - } - - // Returns prev treap index. Allows to navigate Treap in the sorted order - // backwards - public int getPrev(int treap_node_index) { - return m_treapData.getField(treap_node_index, 5); - } - - // Returns the first element in the treap (least one). Used together with - // get_next to write a loop - public int getFirst(int treap) { - if (treap == -1) - return getFirst_(m_defaultTreap); - - return getFirst_(treap); - } - - // Returns the last element in the treap (greatest one). Used together with - // get_prev to write a loop - public int getLast(int treap) { - if (treap == -1) - return getLast_(m_defaultTreap); - - return getLast_(treap); - } - - // Gets the treap data associated with the treap. - public int getTreapData(int treap) { - if (treap == -1) - return getTreapData_(m_defaultTreap); - - return getTreapData_(treap); - } - - // Change the element value. Note: do not call this method if setting the - // element will change the sorted order. - public void setElement(int treap_node_index, int newElement) { - if (m_comparator != null) - m_comparator.onSetImpl_(this, treap_node_index); - setElement_(treap_node_index, newElement); - } - - // Returns the root of the treap. - public int getRoot(int treap) { - if (treap == -1) - return getRoot_(m_defaultTreap); - - return getRoot_(treap); - } - - // Check if the node is Null (does not exist). - public static int nullNode() { - return -1; - } - - // Clears all nodes - public void clear() { - m_treapData.deleteAll(false); - m_defaultTreap = nullNode(); - } - - // Total number of nodes - public int size(int treap) { - if (treap == -1) - return getSize_(m_defaultTreap); - - return getSize_(treap); - } - - // Returns the maximum depth of this Treap at given moment - public int getMaxDepth(int treap) { - return getMaxDepthHelper_(getRoot(treap)); - } - - public int getStateFlag() { - m_touchFlag &= 0x7FFFFFFF; - return m_touchFlag; - } - - private int m_defaultTreap; - private int m_random; - private Treap.Comparator m_comparator;// comparator used to arrange the - // nodes - private StridedIndexTypeCollection m_treapData; // m_left (0), m_right (1), - // m_parent (2), m_element - // (3), m_priority (4), - // m_prev (5), m_next (6) - // (optional: m_root (0), - // m_first (1), m_last (2), - // m_duplicate_element (3), - // m_treap_size (4), - // m_treapData (5)) - private int m_touchFlag; - private boolean m_b_balancing; - - private void touch_() { - if (m_touchFlag >= 0) { - m_touchFlag += 0x80000001; - } - } - - private int getPriority_(int treap_node_index) { - return m_treapData.getField(treap_node_index, 4);// no error checking - // here - } - - private void bubbleDown_(int treap_node_index) { - int left = getLeft(treap_node_index); - int right = getRight(treap_node_index); - int priority = getPriority_(treap_node_index); - while (left != nullNode() || right != nullNode()) { - int lcprior = left != nullNode() ? getPriority_(left) : NumberUtils - .intMax(); - int rcprior = right != nullNode() ? getPriority_(right) - : NumberUtils.intMax(); - int minprior = Math.min(lcprior, rcprior); - - if (priority <= minprior) - return; - - if (lcprior <= rcprior) - rotateRight_(left); - else - rotateLeft_(treap_node_index); - - left = getLeft(treap_node_index); - right = getRight(treap_node_index); - } - } - - private void bubbleUp_(int node) { - if (!m_b_balancing) - return; - int priority = getPriority_(node); - int parent = getParent(node); - while (parent != nullNode() && getPriority_(parent) > priority) { - if (getLeft(parent) == node) - rotateRight_(node); - else - rotateLeft_(parent); - - parent = getParent(node); - } - } - - private void rotateLeft_(int treap_node_index) { - int px = treap_node_index; - int py = getRight(treap_node_index); - int ptemp; - setParent_(py, getParent(px)); - setParent_(px, py); - - ptemp = getLeft(py); - setRight_(px, ptemp); - - if (ptemp != nullNode()) - setParent_(ptemp, px); - - setLeft_(py, px); - - ptemp = getParent(py); - if (ptemp != nullNode()) { - if (getLeft(ptemp) == px) - setLeft_(ptemp, py); - else { - assert (getRight(ptemp) == px); - setRight_(ptemp, py); - } - } - } - - private void rotateRight_(int treap_node_index) { - int py = getParent(treap_node_index); - int px = treap_node_index; - int ptemp; - - setParent_(px, getParent(py)); - setParent_(py, px); - - ptemp = getRight(px); - setLeft_(py, ptemp); - - if (ptemp != nullNode()) - setParent_(ptemp, py); - - setRight_(px, py); - - ptemp = getParent(px); - if (ptemp != nullNode()) { - if (getLeft(ptemp) == py) - setLeft_(ptemp, px); - else { - assert (getRight(ptemp) == py); - setRight_(ptemp, px); - } - } - } - - private void setParent_(int treap_node_index, int new_parent) { - m_treapData.setField(treap_node_index, 2, new_parent); // no error - // checking here - } - - private void setLeft_(int treap_node_index, int new_left) { - m_treapData.setField(treap_node_index, 0, new_left); // no error - // checking here - } - - private void setRight_(int treap_node_index, int new_right) { - m_treapData.setField(treap_node_index, 1, new_right); // no error - // checking here - } - - private void setPriority_(int treap_node_index, int new_priority) { - m_treapData.setField(treap_node_index, 4, new_priority); // no error - // checking - // here - } - - private void setPrev_(int treap_node_index, int prev) { - assert (prev != treap_node_index); - m_treapData.setField(treap_node_index, 5, prev); // no error checking - // here - } - - private void setNext_(int treap_node_index, int next) { - assert (next != treap_node_index); - m_treapData.setField(treap_node_index, 6, next); // no error checking - // here - } - - private void setRoot_(int root, int treap) { - m_treapData.setField(treap, 0, root); - } - - private void setFirst_(int first, int treap) { - m_treapData.setField(treap, 1, first); - } - - private void setLast_(int last, int treap) { - m_treapData.setField(treap, 2, last); - } - - private void setDuplicateElement_(int duplicate_element, int treap) { - m_treapData.setField(treap, 3, duplicate_element); - } - - private void setSize_(int size, int treap) { - m_treapData.setField(treap, 4, size); - } - - private void setTreapData_(int treap_data, int treap) { - m_treapData.setField(treap, 5, treap_data); - } - - private int getRoot_(int treap) { - if (treap == -1) - return nullNode(); - - return m_treapData.getField(treap, 0); - } - - private int getFirst_(int treap) { - if (treap == -1) - return nullNode(); - - return m_treapData.getField(treap, 1); - } - - private int getLast_(int treap) { - if (treap == -1) - return nullNode(); - - return m_treapData.getField(treap, 2); - } - - private int getDuplicateElement_(int treap) { - if (treap == -1) - return nullNode(); - - return m_treapData.getField(treap, 3); - } - - private int getSize_(int treap) { - if (treap == -1) - return 0; - - return m_treapData.getField(treap, 4); - } - - private int getTreapData_(int treap) { - return m_treapData.getField(treap, 5); - } - - private int newNode_(int element) { - touch_(); - int newNode = m_treapData.newElement(); - setPriority_(newNode, generatePriority_()); - setElement_(newNode, element); - return newNode; - } - - private void freeNode_(int treap_node_index, int treap) { - if (treap_node_index == nullNode()) - return; - - m_treapData.deleteElement(treap_node_index); - } - - private int generatePriority_() { - m_random = NumberUtils.nextRand(m_random); - return m_random & (NumberUtils.intMax() >> 1); - } - - private int getMaxDepthHelper_(int node) { - if (node == nullNode()) - return 0; - - return 1 + Math.max(getMaxDepthHelper_(getLeft(node)), - getMaxDepthHelper_(getRight(node))); - } - - private int addElement_(int element, int kind, int treap) { - // dbg_check_(m_root); - if (getRoot_(treap) == nullNode()) { - int newNode = newNode_(element); - setRoot_(newNode, treap); - addToList_(-1, newNode, treap); - return newNode; - } - - int cur = getRoot_(treap); - int newNode = -1; - int before = -1; - - for (; ; ) { - int cmp = kind == -1 ? 1 : m_comparator.compare(this, element, cur); - if (cmp < 0) { - int left = getLeft(cur); - if (left != nullNode()) - cur = left; - else { - before = cur; - newNode = newNode_(element); - setLeft_(cur, newNode); - setParent_(newNode, cur); - break; - } - } else { - if (kind == 1 && cmp == 0) { - m_comparator.onAddUniqueElementFailedImpl_(element); - setDuplicateElement_(cur, treap); - return -1;// return negative value. - } - - int right = getRight(cur); - if (right != nullNode()) - cur = right; - else { - before = getNext(cur); - newNode = newNode_(element); - setRight_(cur, newNode); - setParent_(newNode, cur); - break; - } - } - } - - bubbleUp_(newNode); - if (getParent(newNode) == nullNode()) - setRoot_(newNode, treap); - - addToList_(before, newNode, treap); - // dbg_check_(m_root); - return newNode; - } - - private void addToList_(int before, int node, int treap) { - assert (before != node); - int prev; - if (before != -1) { - prev = getPrev(before); - setPrev_(before, node); - } else - prev = getLast_(treap); - - setPrev_(node, prev); - if (prev != -1) - setNext_(prev, node); - setNext_(node, before); - - if (before == getFirst_(treap)) { - setFirst_(node, treap); - } - if (before == -1) { - setLast_(node, treap); - } - - setSize_(getSize_(treap) + 1, treap); - } - - private void removeFromList_(int node, int treap) { - int prev = getPrev(node); - int next = getNext(node); - if (prev != -1) - setNext_(prev, next); - else - setFirst_(next, treap); - - if (next != -1) - setPrev_(next, prev); - else - setLast_(prev, treap); - - setSize_(getSize_(treap) - 1, treap); - } - - private void unbalancedDelete_(int treap_node_index, int treap) { - assert (!m_b_balancing); - // dbg_check_(m_root); - removeFromList_(treap_node_index, treap); - int left = getLeft(treap_node_index); - int right = getRight(treap_node_index); - int parent = getParent(treap_node_index); - int x = treap_node_index; - if (left != -1 && right != -1) { - m_random = NumberUtils.nextRand(m_random); - int R; - if (m_random > (NumberUtils.intMax() >> 1)) - R = getNext(treap_node_index); - else - R = getPrev(treap_node_index); - - assert (R != -1);// cannot be NULL becaus the node has left and - // right - - boolean bFixMe = getParent(R) == treap_node_index; - - // swap left, right, and parent - m_treapData.swapField(treap_node_index, R, 0); - m_treapData.swapField(treap_node_index, R, 1); - m_treapData.swapField(treap_node_index, R, 2); - - if (parent != -1) { - // Connect ex-parent of int to R. - if (getLeft(parent) == treap_node_index) { - setLeft_(parent, R); - } else { - assert (getRight(parent) == treap_node_index); - setRight_(parent, R); - } - } else {// int was the root. Make R the Root. - setRoot_(R, treap); - } - - if (bFixMe) {// R was a child of int - if (left == R) { - setLeft_(R, treap_node_index); - setParent_(right, R); - } else if (right == R) { - setRight_(R, treap_node_index); - setParent_(left, R); - } - - setParent_(treap_node_index, R); - parent = R; - } else { - setParent_(left, R); - setParent_(right, R); - parent = getParent(treap_node_index); - x = R; - } - - assert (parent != -1); - left = getLeft(treap_node_index); - right = getRight(treap_node_index); - if (left != -1) - setParent_(left, treap_node_index); - if (right != -1) - setParent_(right, treap_node_index); - - assert (left == -1 || right == -1); - } - - // At most one child is not NULL. - int child = left != -1 ? left : right; - - if (parent == -1) { - setRoot_(child, treap); - } else { - if (getLeft(parent) == x) { - setLeft_(parent, child); - } else { - assert (getRight(parent) == x); - setRight_(parent, child); - } - } - - if (child != -1) - setParent_(child, parent); - - freeNode_(treap_node_index, treap); - // dbg_check_(m_root); - } - - private void deleteNode_(int treap_node_index, int treap) { - assert (m_b_balancing); - setPriority_(treap_node_index, NumberUtils.intMax()); // set the node - // priority high - int prl = nullNode(); - int prr = nullNode(); - int root = getRoot_(treap); - boolean isroot = (root == treap_node_index); - - if (isroot) { - // remember children of the root node, if the root node is to be - // deleted - prl = getLeft(root); - prr = getRight(root); - - if (prl == nullNode() && prr == nullNode()) { - removeFromList_(root, treap); - freeNode_(root, treap); - setRoot_(nullNode(), treap); - return; - } - } - - bubbleDown_(treap_node_index); // let the node to slide to the leaves of - // tree - - int p = getParent(treap_node_index); - - if (p != nullNode()) { - if (getLeft(p) == treap_node_index) - setLeft_(p, nullNode()); - else - setRight_(p, nullNode()); - } - - removeFromList_(treap_node_index, treap); - freeNode_(treap_node_index, treap); - - if (isroot) // if the root node is deleted, assign new root - setRoot_((prl == nullNode() || getParent(prl) != nullNode()) ? prr - : prl, treap); - - assert (getParent(getRoot(treap)) == nullNode()); - } - - private void setElement_(int treap_node_index, int newElement) { - touch_(); - m_treapData.setField(treap_node_index, 3, newElement);// no error - // checking here - } + static abstract class Comparator { + Comparator() { + m_b_notify_on_actions = false; + } + + Comparator(boolean bNotifyOnActions) { + m_b_notify_on_actions = bNotifyOnActions; + } + + // Compares the element elm to the element contained in the given node + abstract int compare(Treap treap, int elm, int node); + + // These virtual methods are called only when Comparator(true) ctro has + // been used. + void onDelete(int elm) { + } + + void onSet(int elm) { + } + + void onEndSearch(int elm) { + } + + void onAddUniqueElementFailed(int elm) { + } + + private boolean m_b_notify_on_actions; + + // void operator=(const Comparator&); // do not allow operator = + void onDeleteImpl_(Treap treap, int node) { + if (m_b_notify_on_actions) + onDelete(treap.getElement(node)); + } + + void onSetImpl_(Treap treap, int node) { + if (m_b_notify_on_actions) + onSet(treap.getElement(node)); + } + + void onAddUniqueElementFailedImpl_(int elm) { + if (m_b_notify_on_actions) + onAddUniqueElementFailed(elm); + } + + void onEndSearchImpl_(int elm) { + if (m_b_notify_on_actions) + onEndSearch(elm); + } + } + + ; + + static abstract class MonikerComparator { + // Compares the moniker, contained in the MonikerComparator with the + // element contained in the given node. + abstract int compare(Treap treap, int node); + } + + ; + + public Treap() { + m_random = 124234251; + m_b_balancing = true; + m_touchFlag = 0; + m_defaultTreap = nullNode(); + m_treapData = new StridedIndexTypeCollection(7); + m_comparator = null; + } + + // Sets the comparator + public void setComparator(Comparator comparator) { + m_comparator = comparator; + } + + // Returns the comparator + public Comparator getComparator() { + return m_comparator; + } + + // Stops auto-balancing + public void disableBalancing() { + m_b_balancing = false; + } + + // Reserves memory for nodes givne number of nodes + public void setCapacity(int capacity) { + m_treapData.setCapacity(capacity); + } + + // Create a new treap and returns the treap handle. + public int createTreap(int treap_data) { + int treap = m_treapData.newElement(); + setSize_(0, treap); + setTreapData_(treap_data, treap); + return treap; + } + + // Deletes the treap at the given treap handle. + public void deleteTreap(int treap) { + m_treapData.deleteElement(treap); + } + + // Adds new element to the treap. Allows duplicates to be added. + public int addElement(int element, int treap) { + int treap_; + if (treap == -1) { + if (m_defaultTreap == nullNode()) + m_defaultTreap = createTreap(-1); + treap_ = m_defaultTreap; + } else { + treap_ = treap; + } + + return addElement_(element, 0, treap_); + } + + // Adds new element to the treap if it is not equal to other elements. + // If the return value is -1, then get_duplicate_element reutrns the node of + // the already existing element equal to element. + public int addUniqueElement(int element, int treap) { + int treap_; + if (treap == -1) { + if (m_defaultTreap == nullNode()) + m_defaultTreap = createTreap(-1); + treap_ = m_defaultTreap; + } else { + treap_ = treap; + } + + return addElement_(element, 1, treap_); + } + + // Adds a new element to the treap that is known to be bigger or equal of + // all elements already in the treap. + // Use this method when adding elements from a sorted list for maximum + // performance (it does not call the treap comparator). + public int addBiggestElement(int element, int treap) { + int treap_; + if (treap == -1) { + if (m_defaultTreap == nullNode()) + m_defaultTreap = createTreap(-1); + treap_ = m_defaultTreap; + } else { + treap_ = treap; + } + + if (getRoot_(treap_) == nullNode()) { + int newNode = newNode_(element); + setRoot_(newNode, treap_); + addToList_(-1, newNode, treap_); + return newNode; + } + + int cur = getLast_(treap_); + int newNode = newNode_(element); + setRight_(cur, newNode); + setParent_(newNode, cur); + assert (m_b_balancing);// don't use this method for unbalanced tree, or + // the performance will be bad. + bubbleUp_(newNode); + if (getParent(newNode) == nullNode()) + setRoot_(newNode, treap_); + + addToList_(-1, newNode, treap_); + return newNode; + } + + // template void build_from_sorted(const Iterator& begin, + // const Iterator& end); + // Adds new element to the treap at the known position, thus avoiding a call + // to the comparator. + // If bCallCompare is True, the comparator will be called at most twice, + // once to compare with prevElement and once to compare with nextElement. + // When bUnique is true, if the return value is -1, then + // get_duplicate_element reutrns the node of the already existing element. + public int addElementAtPosition(int prevNode, int nextNode, int element, + boolean bUnique, boolean bCallCompare, int treap) { + int treap_ = treap; + if (treap_ == -1) { + if (m_defaultTreap == nullNode()) + m_defaultTreap = createTreap(-1); + treap_ = m_defaultTreap; + } + + // dbg_check_(m_root); + if (getRoot_(treap_) == nullNode()) { + assert (nextNode == nullNode() && prevNode == nullNode()); + int root = newNode_(element); + setRoot_(root, treap_); + addToList_(-1, root, treap_); + return root; + } + + int cmpNext; + int cmpPrev; + if (bCallCompare) { + cmpNext = nextNode != nullNode() ? m_comparator.compare(this, + element, nextNode) : -1; + assert (cmpNext <= 0); + cmpPrev = prevNode != nullNode() ? m_comparator.compare(this, + element, prevNode) : 1; + // cmpPrev can be negative in plane sweep when intersection is + // detected. + } else { + cmpNext = -1; + cmpPrev = 1; + } + + if (bUnique && (cmpNext == 0 || cmpPrev == 0)) { + m_comparator.onAddUniqueElementFailedImpl_(element); + int cur = cmpNext == 0 ? nextNode : prevNode; + setDuplicateElement_(cur, treap_); + return -1;// return negative value. + } + + int cur; + int cmp; + boolean bNext; + if (nextNode != nullNode() && prevNode != nullNode()) { + // randomize the the cost to insert a node. + bNext = m_random > NumberUtils.nextRand(m_random) >> 1; + } else + bNext = nextNode != nullNode(); + + if (bNext) { + cmp = cmpNext; + cur = nextNode; + } else { + cmp = cmpPrev; + cur = prevNode; + } + + int newNode = -1; + int before = -1; + boolean b_first = true; + for (; ; ) { + if (cmp < 0) { + int left = getLeft(cur); + if (left != nullNode()) + cur = left; + else { + before = cur; + newNode = newNode_(element); + setLeft_(cur, newNode); + setParent_(newNode, cur); + break; + } + } else { + int right = getRight(cur); + if (right != nullNode()) + cur = right; + else { + before = getNext(cur); + newNode = newNode_(element); + setRight_(cur, newNode); + setParent_(newNode, cur); + break; + } + } + + if (b_first) { + cmp *= -1; + b_first = false; + } + } + + bubbleUp_(newNode); + if (getParent(newNode) == nullNode()) + setRoot_(newNode, treap_); + + addToList_(before, newNode, treap_); + // dbg_check_(m_root); + return newNode; + } + + // Get duplicate element + public int getDuplicateElement(int treap) { + if (treap == -1) + return getDuplicateElement_(m_defaultTreap); + + return getDuplicateElement_(treap); + } + + // Removes a node from the treap. Throws if doesn't exist. + public void deleteNode(int treap_node_index, int treap) { + touch_(); + // assert(isValidNode(treap_node_index)); + if (m_comparator != null) + m_comparator.onDeleteImpl_(this, treap_node_index); + + int treap_; + if (treap == -1) + treap_ = m_defaultTreap; + else + treap_ = treap; + + if (!m_b_balancing) { + unbalancedDelete_(treap_node_index, treap_); + } else + deleteNode_(treap_node_index, treap_); + } + + // Finds an element in the treap and returns its node or -1. + public int search(int data, int treap) { + int cur = getRoot(treap); + while (cur != nullNode()) { + int res = m_comparator.compare(this, data, cur); + if (res == 0) + return cur; + else if (res < 0) + cur = getLeft(cur); + else + cur = getRight(cur); + } + + m_comparator.onEndSearchImpl_(data); + return nullNode(); + } + + // Find a first node in the treap which is less or equal the moniker. + // Returns closest smaller (Comparator::compare returns -1) or any equal. + public int searchLowerBound(MonikerComparator moniker, int treap) { + int cur = getRoot(treap); + int bound = -1; + while (cur != nullNode()) { + int res = moniker.compare(this, cur); + if (res == 0) + return cur; + else if (res < 0) + cur = getLeft(cur); + else { + bound = cur; + cur = getRight(cur); + } + } + + return bound; + } + + // Find a first node in the treap which is greater or equal the moniker. + // Returns closest greater (Comparator::compare returns 1) or any equal. + public int searchUpperBound(MonikerComparator moniker, int treap) { + int cur = getRoot(treap); + int bound = -1; + while (cur != nullNode()) { + int res = moniker.compare(this, cur); + if (res == 0) + return cur; + else if (res < 0) { + bound = cur; + cur = getLeft(cur); + } else { + cur = getRight(cur); + } + } + + return bound; + } + + // Returns treap node data (element) from the given node index. + public int getElement(int treap_node_index) { + return m_treapData.getField(treap_node_index, 3);// no error checking + // here + } + + // Returns treap node for the left node for the given treap node index + public int getLeft(int treap_node_index) { + return m_treapData.getField(treap_node_index, 0);// no error checking + // here + } + + // Returns treap index for the right node for the given treap node index + public int getRight(int treap_node_index) { + return m_treapData.getField(treap_node_index, 1);// no error checking + // here + } + + // Returns treap index for the parent node for the given treap node index + public int getParent(int treap_node_index) { + return m_treapData.getField(treap_node_index, 2);// no error checking + // here + } + + // Returns next treap index. Allows to navigate Treap in the sorted order + public int getNext(int treap_node_index) { + return m_treapData.getField(treap_node_index, 6); + } + + // Returns prev treap index. Allows to navigate Treap in the sorted order + // backwards + public int getPrev(int treap_node_index) { + return m_treapData.getField(treap_node_index, 5); + } + + // Returns the first element in the treap (least one). Used together with + // get_next to write a loop + public int getFirst(int treap) { + if (treap == -1) + return getFirst_(m_defaultTreap); + + return getFirst_(treap); + } + + // Returns the last element in the treap (greatest one). Used together with + // get_prev to write a loop + public int getLast(int treap) { + if (treap == -1) + return getLast_(m_defaultTreap); + + return getLast_(treap); + } + + // Gets the treap data associated with the treap. + public int getTreapData(int treap) { + if (treap == -1) + return getTreapData_(m_defaultTreap); + + return getTreapData_(treap); + } + + // Change the element value. Note: do not call this method if setting the + // element will change the sorted order. + public void setElement(int treap_node_index, int newElement) { + if (m_comparator != null) + m_comparator.onSetImpl_(this, treap_node_index); + setElement_(treap_node_index, newElement); + } + + // Returns the root of the treap. + public int getRoot(int treap) { + if (treap == -1) + return getRoot_(m_defaultTreap); + + return getRoot_(treap); + } + + // Check if the node is Null (does not exist). + public static int nullNode() { + return -1; + } + + // Clears all nodes + public void clear() { + m_treapData.deleteAll(false); + m_defaultTreap = nullNode(); + } + + // Total number of nodes + public int size(int treap) { + if (treap == -1) + return getSize_(m_defaultTreap); + + return getSize_(treap); + } + + // Returns the maximum depth of this Treap at given moment + public int getMaxDepth(int treap) { + return getMaxDepthHelper_(getRoot(treap)); + } + + public int getStateFlag() { + m_touchFlag &= 0x7FFFFFFF; + return m_touchFlag; + } + + private int m_defaultTreap; + private int m_random; + private Treap.Comparator m_comparator;// comparator used to arrange the + // nodes + private StridedIndexTypeCollection m_treapData; // m_left (0), m_right (1), + // m_parent (2), m_element + // (3), m_priority (4), + // m_prev (5), m_next (6) + // (optional: m_root (0), + // m_first (1), m_last (2), + // m_duplicate_element (3), + // m_treap_size (4), + // m_treapData (5)) + private int m_touchFlag; + private boolean m_b_balancing; + + private void touch_() { + if (m_touchFlag >= 0) { + m_touchFlag += 0x80000001; + } + } + + private int getPriority_(int treap_node_index) { + return m_treapData.getField(treap_node_index, 4);// no error checking + // here + } + + private void bubbleDown_(int treap_node_index) { + int left = getLeft(treap_node_index); + int right = getRight(treap_node_index); + int priority = getPriority_(treap_node_index); + while (left != nullNode() || right != nullNode()) { + int lcprior = left != nullNode() ? getPriority_(left) : NumberUtils + .intMax(); + int rcprior = right != nullNode() ? getPriority_(right) + : NumberUtils.intMax(); + int minprior = Math.min(lcprior, rcprior); + + if (priority <= minprior) + return; + + if (lcprior <= rcprior) + rotateRight_(left); + else + rotateLeft_(treap_node_index); + + left = getLeft(treap_node_index); + right = getRight(treap_node_index); + } + } + + private void bubbleUp_(int node) { + if (!m_b_balancing) + return; + int priority = getPriority_(node); + int parent = getParent(node); + while (parent != nullNode() && getPriority_(parent) > priority) { + if (getLeft(parent) == node) + rotateRight_(node); + else + rotateLeft_(parent); + + parent = getParent(node); + } + } + + private void rotateLeft_(int treap_node_index) { + int px = treap_node_index; + int py = getRight(treap_node_index); + int ptemp; + setParent_(py, getParent(px)); + setParent_(px, py); + + ptemp = getLeft(py); + setRight_(px, ptemp); + + if (ptemp != nullNode()) + setParent_(ptemp, px); + + setLeft_(py, px); + + ptemp = getParent(py); + if (ptemp != nullNode()) { + if (getLeft(ptemp) == px) + setLeft_(ptemp, py); + else { + assert (getRight(ptemp) == px); + setRight_(ptemp, py); + } + } + } + + private void rotateRight_(int treap_node_index) { + int py = getParent(treap_node_index); + int px = treap_node_index; + int ptemp; + + setParent_(px, getParent(py)); + setParent_(py, px); + + ptemp = getRight(px); + setLeft_(py, ptemp); + + if (ptemp != nullNode()) + setParent_(ptemp, py); + + setRight_(px, py); + + ptemp = getParent(px); + if (ptemp != nullNode()) { + if (getLeft(ptemp) == py) + setLeft_(ptemp, px); + else { + assert (getRight(ptemp) == py); + setRight_(ptemp, px); + } + } + } + + private void setParent_(int treap_node_index, int new_parent) { + m_treapData.setField(treap_node_index, 2, new_parent); // no error + // checking here + } + + private void setLeft_(int treap_node_index, int new_left) { + m_treapData.setField(treap_node_index, 0, new_left); // no error + // checking here + } + + private void setRight_(int treap_node_index, int new_right) { + m_treapData.setField(treap_node_index, 1, new_right); // no error + // checking here + } + + private void setPriority_(int treap_node_index, int new_priority) { + m_treapData.setField(treap_node_index, 4, new_priority); // no error + // checking + // here + } + + private void setPrev_(int treap_node_index, int prev) { + assert (prev != treap_node_index); + m_treapData.setField(treap_node_index, 5, prev); // no error checking + // here + } + + private void setNext_(int treap_node_index, int next) { + assert (next != treap_node_index); + m_treapData.setField(treap_node_index, 6, next); // no error checking + // here + } + + private void setRoot_(int root, int treap) { + m_treapData.setField(treap, 0, root); + } + + private void setFirst_(int first, int treap) { + m_treapData.setField(treap, 1, first); + } + + private void setLast_(int last, int treap) { + m_treapData.setField(treap, 2, last); + } + + private void setDuplicateElement_(int duplicate_element, int treap) { + m_treapData.setField(treap, 3, duplicate_element); + } + + private void setSize_(int size, int treap) { + m_treapData.setField(treap, 4, size); + } + + private void setTreapData_(int treap_data, int treap) { + m_treapData.setField(treap, 5, treap_data); + } + + private int getRoot_(int treap) { + if (treap == -1) + return nullNode(); + + return m_treapData.getField(treap, 0); + } + + private int getFirst_(int treap) { + if (treap == -1) + return nullNode(); + + return m_treapData.getField(treap, 1); + } + + private int getLast_(int treap) { + if (treap == -1) + return nullNode(); + + return m_treapData.getField(treap, 2); + } + + private int getDuplicateElement_(int treap) { + if (treap == -1) + return nullNode(); + + return m_treapData.getField(treap, 3); + } + + private int getSize_(int treap) { + if (treap == -1) + return 0; + + return m_treapData.getField(treap, 4); + } + + private int getTreapData_(int treap) { + return m_treapData.getField(treap, 5); + } + + private int newNode_(int element) { + touch_(); + int newNode = m_treapData.newElement(); + setPriority_(newNode, generatePriority_()); + setElement_(newNode, element); + return newNode; + } + + private void freeNode_(int treap_node_index, int treap) { + if (treap_node_index == nullNode()) + return; + + m_treapData.deleteElement(treap_node_index); + } + + private int generatePriority_() { + m_random = NumberUtils.nextRand(m_random); + return m_random & (NumberUtils.intMax() >> 1); + } + + private int getMaxDepthHelper_(int node) { + if (node == nullNode()) + return 0; + + return 1 + Math.max(getMaxDepthHelper_(getLeft(node)), + getMaxDepthHelper_(getRight(node))); + } + + private int addElement_(int element, int kind, int treap) { + // dbg_check_(m_root); + if (getRoot_(treap) == nullNode()) { + int newNode = newNode_(element); + setRoot_(newNode, treap); + addToList_(-1, newNode, treap); + return newNode; + } + + int cur = getRoot_(treap); + int newNode = -1; + int before = -1; + + for (; ; ) { + int cmp = kind == -1 ? 1 : m_comparator.compare(this, element, cur); + if (cmp < 0) { + int left = getLeft(cur); + if (left != nullNode()) + cur = left; + else { + before = cur; + newNode = newNode_(element); + setLeft_(cur, newNode); + setParent_(newNode, cur); + break; + } + } else { + if (kind == 1 && cmp == 0) { + m_comparator.onAddUniqueElementFailedImpl_(element); + setDuplicateElement_(cur, treap); + return -1;// return negative value. + } + + int right = getRight(cur); + if (right != nullNode()) + cur = right; + else { + before = getNext(cur); + newNode = newNode_(element); + setRight_(cur, newNode); + setParent_(newNode, cur); + break; + } + } + } + + bubbleUp_(newNode); + if (getParent(newNode) == nullNode()) + setRoot_(newNode, treap); + + addToList_(before, newNode, treap); + // dbg_check_(m_root); + return newNode; + } + + private void addToList_(int before, int node, int treap) { + assert (before != node); + int prev; + if (before != -1) { + prev = getPrev(before); + setPrev_(before, node); + } else + prev = getLast_(treap); + + setPrev_(node, prev); + if (prev != -1) + setNext_(prev, node); + setNext_(node, before); + + if (before == getFirst_(treap)) { + setFirst_(node, treap); + } + if (before == -1) { + setLast_(node, treap); + } + + setSize_(getSize_(treap) + 1, treap); + } + + private void removeFromList_(int node, int treap) { + int prev = getPrev(node); + int next = getNext(node); + if (prev != -1) + setNext_(prev, next); + else + setFirst_(next, treap); + + if (next != -1) + setPrev_(next, prev); + else + setLast_(prev, treap); + + setSize_(getSize_(treap) - 1, treap); + } + + private void unbalancedDelete_(int treap_node_index, int treap) { + assert (!m_b_balancing); + // dbg_check_(m_root); + removeFromList_(treap_node_index, treap); + int left = getLeft(treap_node_index); + int right = getRight(treap_node_index); + int parent = getParent(treap_node_index); + int x = treap_node_index; + if (left != -1 && right != -1) { + m_random = NumberUtils.nextRand(m_random); + int R; + if (m_random > (NumberUtils.intMax() >> 1)) + R = getNext(treap_node_index); + else + R = getPrev(treap_node_index); + + assert (R != -1);// cannot be NULL becaus the node has left and + // right + + boolean bFixMe = getParent(R) == treap_node_index; + + // swap left, right, and parent + m_treapData.swapField(treap_node_index, R, 0); + m_treapData.swapField(treap_node_index, R, 1); + m_treapData.swapField(treap_node_index, R, 2); + + if (parent != -1) { + // Connect ex-parent of int to R. + if (getLeft(parent) == treap_node_index) { + setLeft_(parent, R); + } else { + assert (getRight(parent) == treap_node_index); + setRight_(parent, R); + } + } else {// int was the root. Make R the Root. + setRoot_(R, treap); + } + + if (bFixMe) {// R was a child of int + if (left == R) { + setLeft_(R, treap_node_index); + setParent_(right, R); + } else if (right == R) { + setRight_(R, treap_node_index); + setParent_(left, R); + } + + setParent_(treap_node_index, R); + parent = R; + } else { + setParent_(left, R); + setParent_(right, R); + parent = getParent(treap_node_index); + x = R; + } + + assert (parent != -1); + left = getLeft(treap_node_index); + right = getRight(treap_node_index); + if (left != -1) + setParent_(left, treap_node_index); + if (right != -1) + setParent_(right, treap_node_index); + + assert (left == -1 || right == -1); + } + + // At most one child is not NULL. + int child = left != -1 ? left : right; + + if (parent == -1) { + setRoot_(child, treap); + } else { + if (getLeft(parent) == x) { + setLeft_(parent, child); + } else { + assert (getRight(parent) == x); + setRight_(parent, child); + } + } + + if (child != -1) + setParent_(child, parent); + + freeNode_(treap_node_index, treap); + // dbg_check_(m_root); + } + + private void deleteNode_(int treap_node_index, int treap) { + assert (m_b_balancing); + setPriority_(treap_node_index, NumberUtils.intMax()); // set the node + // priority high + int prl = nullNode(); + int prr = nullNode(); + int root = getRoot_(treap); + boolean isroot = (root == treap_node_index); + + if (isroot) { + // remember children of the root node, if the root node is to be + // deleted + prl = getLeft(root); + prr = getRight(root); + + if (prl == nullNode() && prr == nullNode()) { + removeFromList_(root, treap); + freeNode_(root, treap); + setRoot_(nullNode(), treap); + return; + } + } + + bubbleDown_(treap_node_index); // let the node to slide to the leaves of + // tree + + int p = getParent(treap_node_index); + + if (p != nullNode()) { + if (getLeft(p) == treap_node_index) + setLeft_(p, nullNode()); + else + setRight_(p, nullNode()); + } + + removeFromList_(treap_node_index, treap); + freeNode_(treap_node_index, treap); + + if (isroot) // if the root node is deleted, assign new root + setRoot_((prl == nullNode() || getParent(prl) != nullNode()) ? prr + : prl, treap); + + assert (getParent(getRoot(treap)) == nullNode()); + } + + private void setElement_(int treap_node_index, int newElement) { + touch_(); + m_treapData.setField(treap_node_index, 3, newElement);// no error + // checking here + } } diff --git a/src/main/java/com/esri/core/geometry/UserCancelException.java b/src/main/java/com/esri/core/geometry/UserCancelException.java index 2d495a0b..d72479a1 100644 --- a/src/main/java/com/esri/core/geometry/UserCancelException.java +++ b/src/main/java/com/esri/core/geometry/UserCancelException.java @@ -24,9 +24,9 @@ package com.esri.core.geometry; class UserCancelException extends GeometryException { - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 1L; - public UserCancelException() { - super("user cancel"); - } + public UserCancelException() { + super("user cancel"); + } } diff --git a/src/main/java/com/esri/core/geometry/VertexDescription.java b/src/main/java/com/esri/core/geometry/VertexDescription.java index 032e27d5..5b4efd40 100644 --- a/src/main/java/com/esri/core/geometry/VertexDescription.java +++ b/src/main/java/com/esri/core/geometry/VertexDescription.java @@ -43,331 +43,331 @@ * database table, and the VertexDescription defines the fields of the table. */ public final class VertexDescription { - /** - * Describes the attribute and, in case of predefined attributes, provides a - * hint of the attribute use. - */ - public interface Semantics { - static final int POSITION = 0; // xy coordinates of a point (2D - // vector of double, linear - // interpolation) - - static final int Z = 1; // z coordinates of a point (double, - // linear interpolation) - - static final int M = 2; // m attribute (double, linear - // interpolation) - - static final int ID = 3; // id (int, no interpolation) - - static final int NORMAL = 4; // xyz coordinates of normal vector - // (float, angular interpolation) - - static final int TEXTURE1D = 5; // u coordinates of texture - // (float, linear interpolation) - - static final int TEXTURE2D = 6; // uv coordinates of texture - // (float, linear interpolation) - - static final int TEXTURE3D = 7; // uvw coordinates of texture - // (float, linear interpolation) - - static final int ID2 = 8; // two component ID - - static final int MAXSEMANTICS = 8; // the max semantics value - } - - /** - * Specifies how the attribute is interpolated along the segments. are - * represented as int64 - */ - interface Interpolation { - public static final int NONE = 0; - - public static final int LINEAR = 1; - - public static final int ANGULAR = 2; - } - - /** - * Specifies the type of the attribute. - */ - interface Persistence { - public static final int enumFloat = 0; - - public static final int enumDouble = 1; - - public static final int enumInt32 = 2; - - public static final int enumInt64 = 3; - - public static final int enumInt8 = 4; // 8 bit integer. Can be signed or - // unsigned depending on - // platform. - - public static final int enumInt16 = 5; - } - - ; - - /** - * Returns the attribute count of this description. The value is always - * greater or equal to 1. The first attribute is always a POSITION. - */ - public final int getAttributeCount() { - return m_attributeCount; - } - - /** - * Returns the semantics of the given attribute. - * - * @param attributeIndex The index of the attribute in the description. Max value is - * getAttributeCount() - 1. - */ - public final int getSemantics(int attributeIndex) { - return m_indexToSemantics[attributeIndex]; - } - - /** - * Returns the index the given attribute in the vertex description. - * - * @param semantics - * @return Returns the attribute index or -1 of the attribute does not exist - */ - public final int getAttributeIndex(int semantics) { - return m_semanticsToIndexMap[semantics]; - } - - /** - * Returns the interpolation type for the attribute. - * - * @param semantics The semantics of the attribute. - */ - static int getInterpolation(int semantics) { - return _interpolation[semantics]; - } - - /** - * Returns the persistence type for the attribute. - * - * @param semantics The semantics of the attribute. - */ - static int getPersistence(int semantics) { - return _persistence[semantics]; - } - - /** - * Returns the size of the persistence type in bytes. - * - * @param persistence The persistence type to query. - */ - static int getPersistenceSize(int persistence) { - return _persistencesize[persistence]; - } - - /** - * Returns the size of the semantics in bytes. - */ - static int getPersistenceSizeSemantics(int semantics) { - return getPersistenceSize(getPersistence(semantics)) - * getComponentCount(semantics); - } - - /** - * Returns the number of the components of the given semantics. For example, - * it returns 2 for the POSITION. - * - * @param semantics The semantics of the attribute. - */ - public static int getComponentCount(int semantics) { - return _components[semantics]; - } - - /** - * Returns True if the attribute with the given name and given set exists. - * - * @param semantics The semantics of the attribute. - */ - public boolean hasAttribute(int semantics) { - return (m_semanticsBitArray & (1 << semantics)) != 0; - } - - /** - * Returns True if this vertex description includes all attributes from the - * src. - * - * @param src The Vertex_description to compare with. - * @return The function returns false, only when this description does not - * have some of the attribute that src has. - */ - public final boolean hasAttributesFrom(VertexDescription src) { - return (m_semanticsBitArray & src.m_semanticsBitArray) == src.m_semanticsBitArray; - } - - /** - * Returns True, if the vertex has Z attribute. - */ - public final boolean hasZ() { - return hasAttribute(Semantics.Z); - } - - /** - * Returns True, if the vertex has M attribute. - */ - public final boolean hasM() { - return hasAttribute(Semantics.M); - } - - /** - * Returns True, if the vertex has ID attribute. - */ - public final boolean hasID() { - return hasAttribute(Semantics.ID); - } - - /** - * Returns default value for each ordinate of the vertex attribute with - * given semantics. - */ - public static double getDefaultValue(int semantics) { - return _defaultValues[semantics]; - } - - int getPointAttributeOffset_(int attributeIndex) { - return m_pointAttributeOffsets[attributeIndex]; - } - - /** - * Returns the total component count. - */ - public int getTotalComponentCount() { - return m_totalComponentCount; - } - - /** - * Checks if the given value is the default one. The simple equality test - * with GetDefaultValue does not work due to the use of NaNs as default - * value for some parameters. - */ - public static boolean isDefaultValue(int semantics, double v) { - return NumberUtils.doubleToInt64Bits(_defaultValues[semantics]) == NumberUtils - .doubleToInt64Bits(v); - } - - static boolean isIntegerPersistence(int persistence) { - return persistence >= Persistence.enumInt32; - } - - static boolean isIntegerSemantics(int semantics) { - return isIntegerPersistence(getPersistence(semantics)); - } - - @Override - public boolean equals(Object _other) { - return (Object) this == _other; - } - - /** - * Returns a packed array of double representation of all ordinates of - * attributes of a point, i.e.: X, Y, Z, ID, TEXTURE2D.u, TEXTURE2D.v - */ - double[] _getDefaultPointAttributes() { - return m_defaultPointAttributes; - } - - double _getDefaultPointAttributeValue(int attributeIndex, int ordinate) { - return m_defaultPointAttributes[_getPointAttributeOffset(attributeIndex) - + ordinate]; - } - - /** - * Returns an offset to the first ordinate of the given attribute. This - * method is used for the cases when one wants to have a packed array of - * ordinates of all attributes, i.e.: X, Y, Z, ID, TEXTURE2D.u, TEXTURE2D.v - */ - int _getPointAttributeOffset(int attributeIndex) { - return m_pointAttributeOffsets[attributeIndex]; - } - - int _getPointAttributeOffsetFromSemantics(int semantics) { - return m_pointAttributeOffsets[getAttributeIndex(semantics)]; - } - - @Override - public int hashCode() { - return m_hash; - } - - int _getSemanticsImpl(int attributeIndex) { - return m_indexToSemantics[attributeIndex]; - } - - VertexDescription(int bitMask) { - m_semanticsBitArray = bitMask; - m_attributeCount = 0; - m_totalComponentCount = 0; - m_semanticsToIndexMap = new int[Semantics.MAXSEMANTICS + 1]; - Arrays.fill(m_semanticsToIndexMap, -1); - for (int i = 0, flag = 1, n = Semantics.MAXSEMANTICS + 1; i < n; i++) { - if ((bitMask & flag) != 0) { - m_semanticsToIndexMap[i] = m_attributeCount; - m_attributeCount++; - int comps = getComponentCount(i); - m_totalComponentCount += comps; - } - - flag <<= 1; - } - - m_indexToSemantics = new int[m_attributeCount]; - for (int i = 0, n = Semantics.MAXSEMANTICS + 1; i < n; i++) { - int attrib = m_semanticsToIndexMap[i]; - if (attrib >= 0) - m_indexToSemantics[attrib] = i; - } - - m_defaultPointAttributes = new double[m_totalComponentCount]; - m_pointAttributeOffsets = new int[m_attributeCount]; - int offset = 0; - for (int i = 0, n = m_attributeCount; i < n; i++) { - int semantics = getSemantics(i); - int comps = getComponentCount(semantics); - double v = getDefaultValue(semantics); - m_pointAttributeOffsets[i] = offset; - for (int icomp = 0; icomp < comps; icomp++) { - m_defaultPointAttributes[offset] = v; - offset++; - } - } - - m_hash = NumberUtils.hash(m_semanticsBitArray); - } - - private int m_attributeCount; - int m_semanticsBitArray; //the main component - private int m_totalComponentCount; - private int m_hash; - - private int[] m_semanticsToIndexMap; - private int[] m_indexToSemantics; - private int[] m_pointAttributeOffsets; - private double[] m_defaultPointAttributes; - - static final double[] _defaultValues = {0, 0, NumberUtils.NaN(), 0, 0, 0, - 0, 0, 0}; - - static final int[] _interpolation = {Interpolation.LINEAR, - Interpolation.LINEAR, Interpolation.LINEAR, Interpolation.NONE, - Interpolation.ANGULAR, Interpolation.LINEAR, Interpolation.LINEAR, - Interpolation.LINEAR, Interpolation.NONE,}; - - static final int[] _persistence = {Persistence.enumDouble, - Persistence.enumDouble, Persistence.enumDouble, - Persistence.enumInt32, Persistence.enumFloat, - Persistence.enumFloat, Persistence.enumFloat, - Persistence.enumFloat, Persistence.enumInt32,}; - - static final int[] _persistencesize = {4, 8, 4, 8, 1, 2}; - - static final int[] _components = {2, 1, 1, 1, 3, 1, 2, 3, 2,}; + /** + * Describes the attribute and, in case of predefined attributes, provides a + * hint of the attribute use. + */ + public interface Semantics { + static final int POSITION = 0; // xy coordinates of a point (2D + // vector of double, linear + // interpolation) + + static final int Z = 1; // z coordinates of a point (double, + // linear interpolation) + + static final int M = 2; // m attribute (double, linear + // interpolation) + + static final int ID = 3; // id (int, no interpolation) + + static final int NORMAL = 4; // xyz coordinates of normal vector + // (float, angular interpolation) + + static final int TEXTURE1D = 5; // u coordinates of texture + // (float, linear interpolation) + + static final int TEXTURE2D = 6; // uv coordinates of texture + // (float, linear interpolation) + + static final int TEXTURE3D = 7; // uvw coordinates of texture + // (float, linear interpolation) + + static final int ID2 = 8; // two component ID + + static final int MAXSEMANTICS = 8; // the max semantics value + } + + /** + * Specifies how the attribute is interpolated along the segments. are + * represented as int64 + */ + interface Interpolation { + public static final int NONE = 0; + + public static final int LINEAR = 1; + + public static final int ANGULAR = 2; + } + + /** + * Specifies the type of the attribute. + */ + interface Persistence { + public static final int enumFloat = 0; + + public static final int enumDouble = 1; + + public static final int enumInt32 = 2; + + public static final int enumInt64 = 3; + + public static final int enumInt8 = 4; // 8 bit integer. Can be signed or + // unsigned depending on + // platform. + + public static final int enumInt16 = 5; + } + + ; + + /** + * Returns the attribute count of this description. The value is always + * greater or equal to 1. The first attribute is always a POSITION. + */ + public final int getAttributeCount() { + return m_attributeCount; + } + + /** + * Returns the semantics of the given attribute. + * + * @param attributeIndex The index of the attribute in the description. Max value is + * getAttributeCount() - 1. + */ + public final int getSemantics(int attributeIndex) { + return m_indexToSemantics[attributeIndex]; + } + + /** + * Returns the index the given attribute in the vertex description. + * + * @param semantics + * @return Returns the attribute index or -1 of the attribute does not exist + */ + public final int getAttributeIndex(int semantics) { + return m_semanticsToIndexMap[semantics]; + } + + /** + * Returns the interpolation type for the attribute. + * + * @param semantics The semantics of the attribute. + */ + static int getInterpolation(int semantics) { + return _interpolation[semantics]; + } + + /** + * Returns the persistence type for the attribute. + * + * @param semantics The semantics of the attribute. + */ + static int getPersistence(int semantics) { + return _persistence[semantics]; + } + + /** + * Returns the size of the persistence type in bytes. + * + * @param persistence The persistence type to query. + */ + static int getPersistenceSize(int persistence) { + return _persistencesize[persistence]; + } + + /** + * Returns the size of the semantics in bytes. + */ + static int getPersistenceSizeSemantics(int semantics) { + return getPersistenceSize(getPersistence(semantics)) + * getComponentCount(semantics); + } + + /** + * Returns the number of the components of the given semantics. For example, + * it returns 2 for the POSITION. + * + * @param semantics The semantics of the attribute. + */ + public static int getComponentCount(int semantics) { + return _components[semantics]; + } + + /** + * Returns True if the attribute with the given name and given set exists. + * + * @param semantics The semantics of the attribute. + */ + public boolean hasAttribute(int semantics) { + return (m_semanticsBitArray & (1 << semantics)) != 0; + } + + /** + * Returns True if this vertex description includes all attributes from the + * src. + * + * @param src The Vertex_description to compare with. + * @return The function returns false, only when this description does not + * have some of the attribute that src has. + */ + public final boolean hasAttributesFrom(VertexDescription src) { + return (m_semanticsBitArray & src.m_semanticsBitArray) == src.m_semanticsBitArray; + } + + /** + * Returns True, if the vertex has Z attribute. + */ + public final boolean hasZ() { + return hasAttribute(Semantics.Z); + } + + /** + * Returns True, if the vertex has M attribute. + */ + public final boolean hasM() { + return hasAttribute(Semantics.M); + } + + /** + * Returns True, if the vertex has ID attribute. + */ + public final boolean hasID() { + return hasAttribute(Semantics.ID); + } + + /** + * Returns default value for each ordinate of the vertex attribute with + * given semantics. + */ + public static double getDefaultValue(int semantics) { + return _defaultValues[semantics]; + } + + int getPointAttributeOffset_(int attributeIndex) { + return m_pointAttributeOffsets[attributeIndex]; + } + + /** + * Returns the total component count. + */ + public int getTotalComponentCount() { + return m_totalComponentCount; + } + + /** + * Checks if the given value is the default one. The simple equality test + * with GetDefaultValue does not work due to the use of NaNs as default + * value for some parameters. + */ + public static boolean isDefaultValue(int semantics, double v) { + return NumberUtils.doubleToInt64Bits(_defaultValues[semantics]) == NumberUtils + .doubleToInt64Bits(v); + } + + static boolean isIntegerPersistence(int persistence) { + return persistence >= Persistence.enumInt32; + } + + static boolean isIntegerSemantics(int semantics) { + return isIntegerPersistence(getPersistence(semantics)); + } + + @Override + public boolean equals(Object _other) { + return (Object) this == _other; + } + + /** + * Returns a packed array of double representation of all ordinates of + * attributes of a point, i.e.: X, Y, Z, ID, TEXTURE2D.u, TEXTURE2D.v + */ + double[] _getDefaultPointAttributes() { + return m_defaultPointAttributes; + } + + double _getDefaultPointAttributeValue(int attributeIndex, int ordinate) { + return m_defaultPointAttributes[_getPointAttributeOffset(attributeIndex) + + ordinate]; + } + + /** + * Returns an offset to the first ordinate of the given attribute. This + * method is used for the cases when one wants to have a packed array of + * ordinates of all attributes, i.e.: X, Y, Z, ID, TEXTURE2D.u, TEXTURE2D.v + */ + int _getPointAttributeOffset(int attributeIndex) { + return m_pointAttributeOffsets[attributeIndex]; + } + + int _getPointAttributeOffsetFromSemantics(int semantics) { + return m_pointAttributeOffsets[getAttributeIndex(semantics)]; + } + + @Override + public int hashCode() { + return m_hash; + } + + int _getSemanticsImpl(int attributeIndex) { + return m_indexToSemantics[attributeIndex]; + } + + VertexDescription(int bitMask) { + m_semanticsBitArray = bitMask; + m_attributeCount = 0; + m_totalComponentCount = 0; + m_semanticsToIndexMap = new int[Semantics.MAXSEMANTICS + 1]; + Arrays.fill(m_semanticsToIndexMap, -1); + for (int i = 0, flag = 1, n = Semantics.MAXSEMANTICS + 1; i < n; i++) { + if ((bitMask & flag) != 0) { + m_semanticsToIndexMap[i] = m_attributeCount; + m_attributeCount++; + int comps = getComponentCount(i); + m_totalComponentCount += comps; + } + + flag <<= 1; + } + + m_indexToSemantics = new int[m_attributeCount]; + for (int i = 0, n = Semantics.MAXSEMANTICS + 1; i < n; i++) { + int attrib = m_semanticsToIndexMap[i]; + if (attrib >= 0) + m_indexToSemantics[attrib] = i; + } + + m_defaultPointAttributes = new double[m_totalComponentCount]; + m_pointAttributeOffsets = new int[m_attributeCount]; + int offset = 0; + for (int i = 0, n = m_attributeCount; i < n; i++) { + int semantics = getSemantics(i); + int comps = getComponentCount(semantics); + double v = getDefaultValue(semantics); + m_pointAttributeOffsets[i] = offset; + for (int icomp = 0; icomp < comps; icomp++) { + m_defaultPointAttributes[offset] = v; + offset++; + } + } + + m_hash = NumberUtils.hash(m_semanticsBitArray); + } + + private int m_attributeCount; + int m_semanticsBitArray; //the main component + private int m_totalComponentCount; + private int m_hash; + + private int[] m_semanticsToIndexMap; + private int[] m_indexToSemantics; + private int[] m_pointAttributeOffsets; + private double[] m_defaultPointAttributes; + + static final double[] _defaultValues = {0, 0, NumberUtils.NaN(), 0, 0, 0, + 0, 0, 0}; + + static final int[] _interpolation = {Interpolation.LINEAR, + Interpolation.LINEAR, Interpolation.LINEAR, Interpolation.NONE, + Interpolation.ANGULAR, Interpolation.LINEAR, Interpolation.LINEAR, + Interpolation.LINEAR, Interpolation.NONE,}; + + static final int[] _persistence = {Persistence.enumDouble, + Persistence.enumDouble, Persistence.enumDouble, + Persistence.enumInt32, Persistence.enumFloat, + Persistence.enumFloat, Persistence.enumFloat, + Persistence.enumFloat, Persistence.enumInt32,}; + + static final int[] _persistencesize = {4, 8, 4, 8, 1, 2}; + + static final int[] _components = {2, 1, 1, 1, 3, 1, 2, 3, 2,}; } diff --git a/src/main/java/com/esri/core/geometry/VertexDescriptionDesignerImpl.java b/src/main/java/com/esri/core/geometry/VertexDescriptionDesignerImpl.java index 2334ec50..c6d69b15 100644 --- a/src/main/java/com/esri/core/geometry/VertexDescriptionDesignerImpl.java +++ b/src/main/java/com/esri/core/geometry/VertexDescriptionDesignerImpl.java @@ -33,58 +33,58 @@ * instance. */ final class VertexDescriptionDesignerImpl { - static VertexDescription getVertexDescription(int descriptionBitMask) { - return VertexDescriptionHash.getInstance() - .FindOrAdd(descriptionBitMask); - } - - static VertexDescription getMergedVertexDescription( - VertexDescription descr1, VertexDescription descr2) { - int mask = descr1.m_semanticsBitArray | descr2.m_semanticsBitArray; - if ((mask & descr1.m_semanticsBitArray) == mask) { - return descr1; - } else if ((mask & descr2.m_semanticsBitArray) == mask) { - return descr2; - } - - return getVertexDescription(mask); - } - - static VertexDescription getMergedVertexDescription( - VertexDescription descr, int semantics) { - int mask = descr.m_semanticsBitArray | (1 << semantics); - if ((mask & descr.m_semanticsBitArray) == mask) { - return descr; - } - - return getVertexDescription(mask); - } - - static VertexDescription removeSemanticsFromVertexDescription( - VertexDescription descr, int semanticsToRemove) { - int mask = (descr.m_semanticsBitArray | (1 << (int) semanticsToRemove)) - - (1 << (int) semanticsToRemove); - if (mask == descr.m_semanticsBitArray) { - return descr; - } - - return getVertexDescription(mask); - } - - static VertexDescription getDefaultDescriptor2D() { - return VertexDescriptionHash.getInstance().getVD2D(); - } - - static VertexDescription getDefaultDescriptor3D() { - return VertexDescriptionHash.getInstance().getVD3D(); - } - - static int[] mapAttributes(VertexDescription src, VertexDescription dest) { - int[] srcToDst = new int[src.getAttributeCount()]; - Arrays.fill(srcToDst, -1); - for (int i = 0, nsrc = src.getAttributeCount(); i < nsrc; i++) { - srcToDst[i] = dest.getAttributeIndex(src.getSemantics(i)); - } - return srcToDst; - } + static VertexDescription getVertexDescription(int descriptionBitMask) { + return VertexDescriptionHash.getInstance() + .FindOrAdd(descriptionBitMask); + } + + static VertexDescription getMergedVertexDescription( + VertexDescription descr1, VertexDescription descr2) { + int mask = descr1.m_semanticsBitArray | descr2.m_semanticsBitArray; + if ((mask & descr1.m_semanticsBitArray) == mask) { + return descr1; + } else if ((mask & descr2.m_semanticsBitArray) == mask) { + return descr2; + } + + return getVertexDescription(mask); + } + + static VertexDescription getMergedVertexDescription( + VertexDescription descr, int semantics) { + int mask = descr.m_semanticsBitArray | (1 << semantics); + if ((mask & descr.m_semanticsBitArray) == mask) { + return descr; + } + + return getVertexDescription(mask); + } + + static VertexDescription removeSemanticsFromVertexDescription( + VertexDescription descr, int semanticsToRemove) { + int mask = (descr.m_semanticsBitArray | (1 << (int) semanticsToRemove)) + - (1 << (int) semanticsToRemove); + if (mask == descr.m_semanticsBitArray) { + return descr; + } + + return getVertexDescription(mask); + } + + static VertexDescription getDefaultDescriptor2D() { + return VertexDescriptionHash.getInstance().getVD2D(); + } + + static VertexDescription getDefaultDescriptor3D() { + return VertexDescriptionHash.getInstance().getVD3D(); + } + + static int[] mapAttributes(VertexDescription src, VertexDescription dest) { + int[] srcToDst = new int[src.getAttributeCount()]; + Arrays.fill(srcToDst, -1); + for (int i = 0, nsrc = src.getAttributeCount(); i < nsrc; i++) { + srcToDst[i] = dest.getAttributeIndex(src.getSemantics(i)); + } + return srcToDst; + } } diff --git a/src/main/java/com/esri/core/geometry/VertexDescriptionHash.java b/src/main/java/com/esri/core/geometry/VertexDescriptionHash.java index 9009e9b7..8e12dfec 100644 --- a/src/main/java/com/esri/core/geometry/VertexDescriptionHash.java +++ b/src/main/java/com/esri/core/geometry/VertexDescriptionHash.java @@ -37,45 +37,45 @@ * VertexDescription instances to prevent duplicates. */ final class VertexDescriptionHash { - HashMap m_map = new HashMap(); - - private static VertexDescription m_vd2D = new VertexDescription(1); - private static VertexDescription m_vd3D = new VertexDescription(3); - - private static final VertexDescriptionHash INSTANCE = new VertexDescriptionHash(); - - private VertexDescriptionHash() { - m_map.put(1, m_vd2D); - m_map.put(3, m_vd3D); - } - - public static VertexDescriptionHash getInstance() { - return INSTANCE; - } - - public final VertexDescription getVD2D() { - return m_vd2D; - } - - public final VertexDescription getVD3D() { - return m_vd3D; - } - - public final VertexDescription FindOrAdd(int bitSet) { - if (bitSet == 1) - return m_vd2D; - if (bitSet == 3) - return m_vd3D; - - synchronized (this) { - VertexDescription vd = m_map.get(bitSet); - if (vd == null) { - vd = new VertexDescription(bitSet); - m_map.put(bitSet, vd); - } - - return vd; - } - } + HashMap m_map = new HashMap(); + + private static VertexDescription m_vd2D = new VertexDescription(1); + private static VertexDescription m_vd3D = new VertexDescription(3); + + private static final VertexDescriptionHash INSTANCE = new VertexDescriptionHash(); + + private VertexDescriptionHash() { + m_map.put(1, m_vd2D); + m_map.put(3, m_vd3D); + } + + public static VertexDescriptionHash getInstance() { + return INSTANCE; + } + + public final VertexDescription getVD2D() { + return m_vd2D; + } + + public final VertexDescription getVD3D() { + return m_vd3D; + } + + public final VertexDescription FindOrAdd(int bitSet) { + if (bitSet == 1) + return m_vd2D; + if (bitSet == 3) + return m_vd3D; + + synchronized (this) { + VertexDescription vd = m_map.get(bitSet); + if (vd == null) { + vd = new VertexDescription(bitSet); + m_map.put(bitSet, vd); + } + + return vd; + } + } } diff --git a/src/main/java/com/esri/core/geometry/WkbByteOrder.java b/src/main/java/com/esri/core/geometry/WkbByteOrder.java index cba07658..c973d82e 100644 --- a/src/main/java/com/esri/core/geometry/WkbByteOrder.java +++ b/src/main/java/com/esri/core/geometry/WkbByteOrder.java @@ -25,6 +25,6 @@ package com.esri.core.geometry; interface WkbByteOrder { - public static final int wkbXDR = 0; // Big Endian - public static final int wkbNDR = 1; // Little Endian + public static final int wkbXDR = 0; // Big Endian + public static final int wkbNDR = 1; // Little Endian } diff --git a/src/main/java/com/esri/core/geometry/WkbExportFlags.java b/src/main/java/com/esri/core/geometry/WkbExportFlags.java index 88b11b8a..61b25286 100644 --- a/src/main/java/com/esri/core/geometry/WkbExportFlags.java +++ b/src/main/java/com/esri/core/geometry/WkbExportFlags.java @@ -28,14 +28,14 @@ * Flags used by the OperatorExpotToWkb. */ public interface WkbExportFlags { - public static final int wkbExportDefaults = 0;//! readTolerances(String resourceName) { - try { - ArrayList tolerances = new ArrayList(); - InputStream input = Wkid.class.getResourceAsStream(resourceName); - BufferedReader reader = new BufferedReader(new InputStreamReader( - input)); - while (true) { - String s = reader.readLine(); - if (s == null) - break; - int sep = s.indexOf('\t', 0); - String id_s = s.substring(0, sep); - int tol_index = Integer.parseInt(id_s); - if (tol_index != tolerances.size()) - throw new IllegalArgumentException("Wkid.readTolerances"); - String tol_val = s.substring(sep + 1, s.length()); - tolerances.add(Double.parseDouble(tol_val)); - } - - return tolerances; - } catch (IOException ex) { - - } - return null; - } - - static HashMap readToleranceMap(String resourceName) { - try { - HashMap hashMap = new HashMap( - 600); - InputStream input = Wkid.class.getResourceAsStream(resourceName); - BufferedReader reader = new BufferedReader(new InputStreamReader( - input)); - while (true) { - String s = reader.readLine(); - if (s == null) - break; - int sep = s.indexOf('\t', 0); - String id_s = s.substring(0, sep); - int wkid = Integer.parseInt(id_s); - String id_t = s.substring(sep + 1, s.length()); - int tol = Integer.parseInt(id_t); - hashMap.put(wkid, tol); - } - return hashMap; - } catch (IOException ex) { - } - return null; - - } - - static ArrayList m_gcs_tolerances = readTolerances("gcs_tolerances.txt"); - static ArrayList m_pcs_tolerances = readTolerances("pcs_tolerances.txt"); - static HashMap m_gcsToTol = readToleranceMap("gcs_id_to_tolerance.txt"); - static HashMap m_pcsToTol = readToleranceMap("pcs_id_to_tolerance.txt"); - static HashMap m_wkid_to_new; - static HashMap m_wkid_to_old; - - static { - try { - m_wkid_to_new = new HashMap(100); - m_wkid_to_old = new HashMap(100); - { - InputStream input = Wkid.class.getResourceAsStream("new_to_old_wkid.txt"); - BufferedReader reader = new BufferedReader( - new InputStreamReader(input)); - while (true) { - String s = reader.readLine(); - if (s == null) - break; - s = s.trim(); - if (s.length() == 0) - continue; - int sep = s.indexOf('\t', 0); - String id_s = s.substring(0, sep); - int wkid_new = Integer.parseInt(id_s); - String id_t = s.substring(sep + 1, s.length()); - int wkid_old = Integer.parseInt(id_t); - m_wkid_to_new.put(wkid_old, wkid_new); - m_wkid_to_old.put(wkid_new, wkid_old); - } - } - { - InputStream input = Wkid.class - .getResourceAsStream("intermediate_to_old_wkid.txt"); - BufferedReader reader = new BufferedReader( - new InputStreamReader(input)); - while (true) { - String s = reader.readLine(); - if (s == null) - break; - s = s.trim(); - if (s.length() == 0) - continue; - int sep = s.indexOf('\t', 0); - String id_s = s.substring(0, sep); - int wkid = Integer.parseInt(id_s); - String id_t = s.substring(sep + 1, s.length()); - int wkid_old = Integer.parseInt(id_t); - m_wkid_to_old.put(wkid, wkid_old); - m_wkid_to_new.put(wkid, m_wkid_to_new.get(wkid_old)); - } - } - - } catch (IOException ex) { - - } - } - - public static double find_tolerance_from_wkid(int wkid) { - double tol = find_tolerance_from_wkid_helper(wkid); - if (tol == 1e38) { - int old = wkid_to_old(wkid); - if (old != wkid) - tol = find_tolerance_from_wkid_helper(old); - if (tol == 1e38) - return 1e-10; - } - - return tol; - } - - private static double find_tolerance_from_wkid_helper(int wkid) { - if (m_gcsToTol.containsKey(wkid)) { - return m_gcs_tolerances.get(m_gcsToTol.get(wkid)); - } - - if (m_pcsToTol.containsKey(wkid)) { - return m_pcs_tolerances.get(m_pcsToTol.get(wkid)); - } - - return 1e38; - } - - public static int wkid_to_new(int wkid) { - if (m_wkid_to_new.containsKey(wkid)) { - return m_wkid_to_new.get(wkid); - } - return wkid; - } - - public static int wkid_to_old(int wkid) { - if (m_wkid_to_old.containsKey(wkid)) { - return m_wkid_to_old.get(wkid); - } - return wkid; - } + static ArrayList readTolerances(String resourceName) { + try { + ArrayList tolerances = new ArrayList(); + InputStream input = Wkid.class.getResourceAsStream(resourceName); + BufferedReader reader = new BufferedReader(new InputStreamReader( + input)); + while (true) { + String s = reader.readLine(); + if (s == null) + break; + int sep = s.indexOf('\t', 0); + String id_s = s.substring(0, sep); + int tol_index = Integer.parseInt(id_s); + if (tol_index != tolerances.size()) + throw new IllegalArgumentException("Wkid.readTolerances"); + String tol_val = s.substring(sep + 1, s.length()); + tolerances.add(Double.parseDouble(tol_val)); + } + + return tolerances; + } catch (IOException ex) { + + } + return null; + } + + static HashMap readToleranceMap(String resourceName) { + try { + HashMap hashMap = new HashMap( + 600); + InputStream input = Wkid.class.getResourceAsStream(resourceName); + BufferedReader reader = new BufferedReader(new InputStreamReader( + input)); + while (true) { + String s = reader.readLine(); + if (s == null) + break; + int sep = s.indexOf('\t', 0); + String id_s = s.substring(0, sep); + int wkid = Integer.parseInt(id_s); + String id_t = s.substring(sep + 1, s.length()); + int tol = Integer.parseInt(id_t); + hashMap.put(wkid, tol); + } + return hashMap; + } catch (IOException ex) { + } + return null; + + } + + static ArrayList m_gcs_tolerances = readTolerances("gcs_tolerances.txt"); + static ArrayList m_pcs_tolerances = readTolerances("pcs_tolerances.txt"); + static HashMap m_gcsToTol = readToleranceMap("gcs_id_to_tolerance.txt"); + static HashMap m_pcsToTol = readToleranceMap("pcs_id_to_tolerance.txt"); + static HashMap m_wkid_to_new; + static HashMap m_wkid_to_old; + + static { + try { + m_wkid_to_new = new HashMap(100); + m_wkid_to_old = new HashMap(100); + { + InputStream input = Wkid.class.getResourceAsStream("new_to_old_wkid.txt"); + BufferedReader reader = new BufferedReader( + new InputStreamReader(input)); + while (true) { + String s = reader.readLine(); + if (s == null) + break; + s = s.trim(); + if (s.length() == 0) + continue; + int sep = s.indexOf('\t', 0); + String id_s = s.substring(0, sep); + int wkid_new = Integer.parseInt(id_s); + String id_t = s.substring(sep + 1, s.length()); + int wkid_old = Integer.parseInt(id_t); + m_wkid_to_new.put(wkid_old, wkid_new); + m_wkid_to_old.put(wkid_new, wkid_old); + } + } + { + InputStream input = Wkid.class + .getResourceAsStream("intermediate_to_old_wkid.txt"); + BufferedReader reader = new BufferedReader( + new InputStreamReader(input)); + while (true) { + String s = reader.readLine(); + if (s == null) + break; + s = s.trim(); + if (s.length() == 0) + continue; + int sep = s.indexOf('\t', 0); + String id_s = s.substring(0, sep); + int wkid = Integer.parseInt(id_s); + String id_t = s.substring(sep + 1, s.length()); + int wkid_old = Integer.parseInt(id_t); + m_wkid_to_old.put(wkid, wkid_old); + m_wkid_to_new.put(wkid, m_wkid_to_new.get(wkid_old)); + } + } + + } catch (IOException ex) { + + } + } + + public static double find_tolerance_from_wkid(int wkid) { + double tol = find_tolerance_from_wkid_helper(wkid); + if (tol == 1e38) { + int old = wkid_to_old(wkid); + if (old != wkid) + tol = find_tolerance_from_wkid_helper(old); + if (tol == 1e38) + return 1e-10; + } + + return tol; + } + + private static double find_tolerance_from_wkid_helper(int wkid) { + if (m_gcsToTol.containsKey(wkid)) { + return m_gcs_tolerances.get(m_gcsToTol.get(wkid)); + } + + if (m_pcsToTol.containsKey(wkid)) { + return m_pcs_tolerances.get(m_pcsToTol.get(wkid)); + } + + return 1e38; + } + + public static int wkid_to_new(int wkid) { + if (m_wkid_to_new.containsKey(wkid)) { + return m_wkid_to_new.get(wkid); + } + return wkid; + } + + public static int wkid_to_old(int wkid) { + if (m_wkid_to_old.containsKey(wkid)) { + return m_wkid_to_old.get(wkid); + } + return wkid; + } } diff --git a/src/main/java/com/esri/core/geometry/Wkt.java b/src/main/java/com/esri/core/geometry/Wkt.java index 933bafc2..675baf72 100644 --- a/src/main/java/com/esri/core/geometry/Wkt.java +++ b/src/main/java/com/esri/core/geometry/Wkt.java @@ -25,85 +25,85 @@ package com.esri.core.geometry; final class Wkt { - public static double find_tolerance_from_wkt(String buffer) { - double tolerance = -1.0; + public static double find_tolerance_from_wkt(String buffer) { + double tolerance = -1.0; - if (buffer != null && buffer.length() > 0) { - int n1, n2; + if (buffer != null && buffer.length() > 0) { + int n1, n2; - n1 = buffer.indexOf("PROJCS"); - if (n1 >= 0) { - double factor = 0.0; + n1 = buffer.indexOf("PROJCS"); + if (n1 >= 0) { + double factor = 0.0; - n1 = buffer.lastIndexOf("UNIT"); - if (n1 >= 0) { - n1 = buffer.indexOf(',', n1 + 4); - if (n1 > 0) { - n1++; - n2 = buffer.indexOf(']', n1 + 1); - if (n2 > 0) { - try { - factor = Double.parseDouble(buffer.substring( - n1, n2)); - } catch (NumberFormatException e) { - factor = 0.0; - } - } - } - } + n1 = buffer.lastIndexOf("UNIT"); + if (n1 >= 0) { + n1 = buffer.indexOf(',', n1 + 4); + if (n1 > 0) { + n1++; + n2 = buffer.indexOf(']', n1 + 1); + if (n2 > 0) { + try { + factor = Double.parseDouble(buffer.substring( + n1, n2)); + } catch (NumberFormatException e) { + factor = 0.0; + } + } + } + } - if (factor > 0.0) - tolerance = (0.001 / factor); - } else { - n1 = buffer.indexOf("GEOGCS"); - if (n1 >= 0) { - double axis = 0.0; - double factor = 0.0; + if (factor > 0.0) + tolerance = (0.001 / factor); + } else { + n1 = buffer.indexOf("GEOGCS"); + if (n1 >= 0) { + double axis = 0.0; + double factor = 0.0; - n1 = buffer.indexOf("SPHEROID", n1 + 6); - if (n1 > 0) { - n1 = buffer.indexOf(',', n1 + 8); - if (n1 > 0) { - n1++; - n2 = buffer.indexOf(',', n1 + 1); - if (n2 > 0) { - try { - axis = Double.parseDouble(buffer.substring( - n1, n2)); - } catch (NumberFormatException e) { - axis = 0.0; - } - } + n1 = buffer.indexOf("SPHEROID", n1 + 6); + if (n1 > 0) { + n1 = buffer.indexOf(',', n1 + 8); + if (n1 > 0) { + n1++; + n2 = buffer.indexOf(',', n1 + 1); + if (n2 > 0) { + try { + axis = Double.parseDouble(buffer.substring( + n1, n2)); + } catch (NumberFormatException e) { + axis = 0.0; + } + } - if (axis > 0.0) { - n1 = buffer.indexOf("UNIT", n2 + 1); - if (n1 >= 0) { - n1 = buffer.indexOf(',', n1 + 4); - if (n1 > 0) { - n1++; - n2 = buffer.indexOf(',', n1 + 1); - if (n2 > 0) { - try { - factor = Double - .parseDouble(buffer - .substring(n1, - n2)); - } catch (NumberFormatException e) { - factor = 0.0; - } - } - } - } - } - } - } + if (axis > 0.0) { + n1 = buffer.indexOf("UNIT", n2 + 1); + if (n1 >= 0) { + n1 = buffer.indexOf(',', n1 + 4); + if (n1 > 0) { + n1++; + n2 = buffer.indexOf(',', n1 + 1); + if (n2 > 0) { + try { + factor = Double + .parseDouble(buffer + .substring(n1, + n2)); + } catch (NumberFormatException e) { + factor = 0.0; + } + } + } + } + } + } + } - if (axis > 0.0 && factor > 0.0) - tolerance = (0.001 / (axis * factor)); - } - } - } + if (axis > 0.0 && factor > 0.0) + tolerance = (0.001 / (axis * factor)); + } + } + } - return tolerance; - } + return tolerance; + } } diff --git a/src/main/java/com/esri/core/geometry/WktExportFlags.java b/src/main/java/com/esri/core/geometry/WktExportFlags.java index cea6bbdb..66fe7cad 100644 --- a/src/main/java/com/esri/core/geometry/WktExportFlags.java +++ b/src/main/java/com/esri/core/geometry/WktExportFlags.java @@ -27,21 +27,21 @@ * Flags used by the OperatorExportToWkt */ public interface WktExportFlags { - public static final int wktExportDefaults = 0; - public static final int wktExportPoint = 1; - public static final int wktExportMultiPoint = 2; - public static final int wktExportLineString = 4; - public static final int wktExportMultiLineString = 8; - public static final int wktExportPolygon = 16; - public static final int wktExportMultiPolygon = 32; - public static final int wktExportStripZs = 64; - public static final int wktExportStripMs = 128; - public static final int wktExportFailIfNotSimple = 4096; - public static final int wktExportPrecision16 = 0x2000; - public static final int wktExportPrecision15 = 0x4000; - public static final int wktExportPrecision14 = 0x6000; - public static final int wktExportPrecision13 = 0x8000; - public static final int wktExportPrecision12 = 0xa000; - public static final int wktExportPrecision11 = 0xc000; - public static final int wktExportPrecision10 = 0xe000; + public static final int wktExportDefaults = 0; + public static final int wktExportPoint = 1; + public static final int wktExportMultiPoint = 2; + public static final int wktExportLineString = 4; + public static final int wktExportMultiLineString = 8; + public static final int wktExportPolygon = 16; + public static final int wktExportMultiPolygon = 32; + public static final int wktExportStripZs = 64; + public static final int wktExportStripMs = 128; + public static final int wktExportFailIfNotSimple = 4096; + public static final int wktExportPrecision16 = 0x2000; + public static final int wktExportPrecision15 = 0x4000; + public static final int wktExportPrecision14 = 0x6000; + public static final int wktExportPrecision13 = 0x8000; + public static final int wktExportPrecision12 = 0xa000; + public static final int wktExportPrecision11 = 0xc000; + public static final int wktExportPrecision10 = 0xe000; } diff --git a/src/main/java/com/esri/core/geometry/WktImportFlags.java b/src/main/java/com/esri/core/geometry/WktImportFlags.java index 4e197239..16c4429d 100644 --- a/src/main/java/com/esri/core/geometry/WktImportFlags.java +++ b/src/main/java/com/esri/core/geometry/WktImportFlags.java @@ -27,6 +27,6 @@ * Flags used by the OperatorImportFromWkt. */ public interface WktImportFlags { - public static final int wktImportDefaults = 0;//! 200 ? m_wkt_string - // .substring(0, 200) + "..." : m_wkt_string); - //throw new IllegalArgumentException( - // "Could not parse Well-Known Text: " + snippet); - throw new IllegalArgumentException( - "Could not parse Well-Known Text around position: " + m_end_token); - } - - m_function_stack.add(State.attributes); - } - - private void attributes_() { - skipWhiteSpace_(); - m_start_token = m_end_token; - m_function_stack.removeLast(); - - // Z and M is not allowed to have a space between them - boolean b_has_zs = false, b_has_ms = false; - - if (m_wkt_string.charAt(m_end_token) == 'z' - || m_wkt_string.charAt(m_end_token) == 'Z') { - b_has_zs = true; - - if (++m_end_token >= m_wkt_string.length()) - throw new IllegalArgumentException(); - } - - if (m_wkt_string.charAt(m_end_token) == 'm' - || m_wkt_string.charAt(m_end_token) == 'M') { - b_has_ms = true; - - if (++m_end_token >= m_wkt_string.length()) - throw new IllegalArgumentException(); - } - - if (m_b_check_consistent_attributes) { - if (b_has_zs != m_b_has_zs || b_has_ms != m_b_has_ms) - throw new IllegalArgumentException(); - } - - m_b_has_zs = b_has_zs; - m_b_has_ms = b_has_ms; - - if (m_b_has_zs || m_b_has_ms) { - if (m_b_has_zs && !m_b_has_ms) - m_current_token_type = WktToken.attribute_z; - else if (m_b_has_ms && !m_b_has_zs) - m_current_token_type = WktToken.attribute_m; - else - m_current_token_type = WktToken.attribute_zm; - } else { - nextToken(); - } - } - - private void geometryCollectionStart_() { - skipWhiteSpace_(); - m_start_token = m_end_token; - m_b_check_consistent_attributes = true; - - if (empty_()) { - m_function_stack.removeLast(); - } else if (leftParen_()) { - m_function_stack.removeLast(); - m_function_stack.add(State.geometryCollectionEnd); - m_function_stack.add(State.geometry); - } else { - throw new IllegalArgumentException(); - } - } - - private void geometryCollectionEnd_() { - skipWhiteSpace_(); - m_start_token = m_end_token; - - if (comma_()) { - m_function_stack.add(State.geometry); - geometry_(); - } else if (rightParen_()) { - m_function_stack.removeLast(); - } else { - throw new IllegalArgumentException(); - } - } - - private void multiPolygonStart_() { - skipWhiteSpace_(); - m_start_token = m_end_token; - - if (empty_()) { - m_function_stack.removeLast(); - } else if (leftParen_()) { - m_function_stack.removeLast(); - m_function_stack.add(State.multiPolygonEnd); - m_function_stack.add(State.polygonStart); - } else { - throw new IllegalArgumentException(); - } - } - - private void multiPolygonEnd_() { - skipWhiteSpace_(); - m_start_token = m_end_token; - - if (comma_()) { - m_function_stack.add(State.polygonStart); - polygonStart_(); - } else if (rightParen_()) { - m_function_stack.removeLast(); - } else { - throw new IllegalArgumentException(); - } - } - - private void multiLineStringStart_() { - skipWhiteSpace_(); - m_start_token = m_end_token; - - if (empty_()) { - m_function_stack.removeLast(); - } else if (leftParen_()) { - m_function_stack.removeLast(); - m_function_stack.add(State.multiLineStringEnd); - m_function_stack.add(State.lineStringStart); - } else { - throw new IllegalArgumentException(); - } - } - - private void multiLineStringEnd_() { - skipWhiteSpace_(); - m_start_token = m_end_token; - - if (comma_()) { - m_function_stack.add(State.lineStringStart); - lineStringStart_(); - } else if (rightParen_()) { - m_function_stack.removeLast(); - } else { - throw new IllegalArgumentException(); - } - } - - private void multiPointStart_() { - skipWhiteSpace_(); - m_start_token = m_end_token; - - if (empty_()) { - m_function_stack.removeLast(); - } else if (leftParen_()) { - m_function_stack.removeLast(); - m_function_stack.add(State.multiPointEnd); - m_function_stack.add(State.pointStartAlt); - } else { - throw new IllegalArgumentException(); - } - } - - private void multiPointEnd_() { - skipWhiteSpace_(); - m_start_token = m_end_token; - - if (comma_()) { - m_function_stack.add(State.pointStart); - pointStart_(); - } else if (rightParen_()) { - m_function_stack.removeLast(); - } else { - throw new IllegalArgumentException(); - } - } - - private void polygonStart_() { - skipWhiteSpace_(); - m_start_token = m_end_token; - - if (empty_()) { - m_function_stack.removeLast(); - } else if (leftParen_()) { - m_function_stack.removeLast(); - m_function_stack.add(State.polygonEnd); - m_function_stack.add(State.lineStringStart); - } else { - throw new IllegalArgumentException(); - } - } - - private void polygonEnd_() { - skipWhiteSpace_(); - m_start_token = m_end_token; - - if (comma_()) { - m_function_stack.add(State.lineStringStart); - lineStringStart_(); - } else if (rightParen_()) { - m_function_stack.removeLast(); - } else { - throw new IllegalArgumentException(); - } - } - - private void lineStringStart_() { - skipWhiteSpace_(); - m_start_token = m_end_token; - - if (empty_()) { - m_function_stack.removeLast(); - } else if (leftParen_()) { - m_function_stack.removeLast(); - m_function_stack.add(State.lineStringEnd); - m_function_stack.add(State.xLiteral); - } else { - throw new IllegalArgumentException(); - } - } - - private void lineStringEnd_() { - skipWhiteSpace_(); - m_start_token = m_end_token; - - if (comma_()) { - m_function_stack.add(State.xLiteral); - xLiteral_(); - } else if (rightParen_()) { - m_function_stack.removeLast(); - } else { - throw new IllegalArgumentException(); - } - } - - private void pointStart_() { - skipWhiteSpace_(); - m_start_token = m_end_token; - - if (empty_()) { - m_function_stack.removeLast(); - } else if (leftParen_()) { - m_function_stack.removeLast(); - m_function_stack.add(State.pointEnd); - m_function_stack.add(State.xLiteral); - } else { - throw new IllegalArgumentException(); - } - } - - private void pointStartAlt_() { - skipWhiteSpace_(); - m_start_token = m_end_token; - - if (empty_()) {// ogc standard - m_function_stack.removeLast(); - } else if (leftParen_()) {// ogc standard - m_function_stack.removeLast(); - m_function_stack.add(State.pointEnd); - m_function_stack.add(State.xLiteral); - } else {// not ogc standard. treat as linestring - m_function_stack.removeLast(); - m_function_stack.removeLast(); - m_function_stack.add(State.lineStringEnd); - m_function_stack.add(State.xLiteral); - nextToken(); - } - } - - private void pointEnd_() { - skipWhiteSpace_(); - m_start_token = m_end_token; - - if (rightParen_()) { - m_function_stack.removeLast(); - } else { - throw new IllegalArgumentException(); - } - } - - private void xLiteral_() { - signedNumericLiteral_(); - m_current_token_type = WktToken.x_literal; - m_function_stack.removeLast(); - m_function_stack.add(State.yLiteral); - } - - private void yLiteral_() { - signedNumericLiteral_(); - m_current_token_type = WktToken.y_literal; - m_function_stack.removeLast(); - - if (m_b_has_zs) - m_function_stack.add(State.zLiteral); - else if (m_b_has_ms) - m_function_stack.add(State.mLiteral); - } - - private void zLiteral_() { - signedNumericLiteral_(); - m_current_token_type = WktToken.z_literal; - m_function_stack.removeLast(); - - if (m_b_has_ms) - m_function_stack.add(State.mLiteral); - } - - private void mLiteral_() { - signedNumericLiteral_(); - m_current_token_type = WktToken.m_literal; - m_function_stack.removeLast(); - } - - private boolean nan_() { - if (m_start_token + 3 <= m_wkt_string.length() - && m_wkt_string.regionMatches(true, m_start_token, "nan", 0, 3)) { - m_end_token += 3; - m_b_nan = true; - return true; - } - - m_b_nan = false; - return false; - } - - private void sign_() { - // Optional - or + sign - if (m_wkt_string.charAt(m_end_token) == '-' - || m_wkt_string.charAt(m_end_token) == '+') { - if (++m_end_token >= m_wkt_string.length()) - throw new IllegalArgumentException(); - } - } - - private void signedNumericLiteral_() { - skipWhiteSpace_(); - m_start_token = m_end_token; - - if (nan_()) - return; - - sign_(); // Optional - unsignedNumericLiteral_(); - } - - private void unsignedNumericLiteral_() { - exactNumericLiteral_(); - exp_(); // Optional - } - - private void exactNumericLiteral_() { - if (Character.isDigit(m_wkt_string.charAt(m_end_token))) { - digits_(); - - // Optional - if (m_wkt_string.charAt(m_end_token) == '.') { - if (++m_end_token >= m_wkt_string.length()) - throw new IllegalArgumentException(); - - // Optional - if (Character.isDigit(m_wkt_string.charAt(m_end_token))) - digits_(); - } - } else if (m_wkt_string.charAt(m_end_token) == '.') { - if (++m_end_token >= m_wkt_string.length()) - throw new IllegalArgumentException(); - - if (!Character.isDigit(m_wkt_string.charAt(m_end_token))) - throw new IllegalArgumentException(); - - digits_(); - } else { - throw new IllegalArgumentException(); - } - } - - private void digits_() { - do { - if (++m_end_token >= m_wkt_string.length()) - throw new IllegalArgumentException(); - - } while (Character.isDigit(m_wkt_string.charAt(m_end_token))); - } - - private void exp_() { - // This is an optional state - if (m_wkt_string.charAt(m_end_token) == 'e' - || m_wkt_string.charAt(m_end_token) == 'E') { - if (++m_end_token >= m_wkt_string.length()) - throw new IllegalArgumentException(); - - sign_(); // optional - - if (!Character.isDigit(m_wkt_string.charAt(m_end_token))) - throw new IllegalArgumentException(); - - digits_(); - } - } - - private void skipWhiteSpace_() { - if (m_end_token >= m_wkt_string.length()) - throw new IllegalArgumentException(); - - while (Character.isWhitespace(m_wkt_string.charAt(m_end_token))) { - if (++m_end_token >= m_wkt_string.length()) - throw new IllegalArgumentException(); - } - } - - private boolean empty_() { - if (m_start_token + 5 <= m_wkt_string.length() - && m_wkt_string.regionMatches(true, m_start_token, "empty", 0, 5)) { - m_end_token += 5; - m_current_token_type = WktToken.empty; - return true; - } - - return false; - } - - private boolean comma_() { - if (m_wkt_string.charAt(m_end_token) == ',') { - m_end_token++; - return true; - } - - return false; - } - - private boolean leftParen_() { - if (m_wkt_string.charAt(m_end_token) == '(') { - m_end_token++; - m_current_token_type = WktToken.left_paren; - return true; - } - - return false; - } - - private boolean rightParen_() { - if (m_wkt_string.charAt(m_end_token) == ')') { - m_end_token++; - m_current_token_type = WktToken.right_paren; - return true; - } - - return false; - } + interface WktToken { + static final int not_available = 0; + static final int empty = 50; + static final int left_paren = 51; + static final int right_paren = 52; + static final int x_literal = 0x80000000; + static final int y_literal = 0x40000000; + static final int z_literal = 0x20000000; + static final int m_literal = 0x10000000; + static final int point = 1; + static final int linestring = 2; + static final int polygon = 3; + static final int multipoint = 4; + static final int multilinestring = 5; + static final int multipolygon = 6; + static final int geometrycollection = 7; + static final int attribute_z = 1000; + static final int attribute_m = 2000; + static final int attribute_zm = 3000; + } + + WktParser() { + } + + WktParser(String string) { + resetParser(string); + } + + void resetParser(String string) { + if (m_function_stack == null) + m_function_stack = new AttributeStreamOfInt32(0); + + reset_(); + m_wkt_string = string; + } + + int nextToken() { + switch (m_function_stack.getLast()) { + case State.xLiteral: + xLiteral_(); + break; + case State.yLiteral: + yLiteral_(); + break; + case State.zLiteral: + zLiteral_(); + break; + case State.mLiteral: + mLiteral_(); + break; + case State.pointStart: + pointStart_(); + break; + case State.pointStartAlt: + pointStartAlt_(); + break; + case State.pointEnd: + pointEnd_(); + break; + case State.lineStringStart: + lineStringStart_(); + break; + case State.lineStringEnd: + lineStringEnd_(); + break; + case State.multiPointStart: + multiPointStart_(); + break; + case State.multiPointEnd: + multiPointEnd_(); + break; + case State.polygonStart: + polygonStart_(); + break; + case State.polygonEnd: + polygonEnd_(); + break; + case State.multiLineStringStart: + multiLineStringStart_(); + break; + case State.multiLineStringEnd: + multiLineStringEnd_(); + break; + case State.multiPolygonStart: + multiPolygonStart_(); + break; + case State.multiPolygonEnd: + multiPolygonEnd_(); + break; + case State.geometryCollectionStart: + geometryCollectionStart_(); + break; + case State.geometryCollectionEnd: + geometryCollectionEnd_(); + break; + case State.accept: + accept_(); + break; + case State.geometry: + geometry_(); + break; + case State.attributes: + attributes_(); + break; + } + + return m_current_token_type; + } + + double currentNumericLiteral() { + if (((int) m_current_token_type & (int) Number.signed_numeric_literal) == 0) + throw new GeometryException("runtime error"); + + if (m_b_nan) + return NumberUtils.TheNaN; + + double value = Double.parseDouble(m_wkt_string.substring(m_start_token, + m_end_token)); + return value; + } + + int currentToken() { + return m_current_token_type; + } + + boolean hasZs() { + return m_b_has_zs; + } + + boolean hasMs() { + return m_b_has_ms; + } + + private String m_wkt_string; + private int m_start_token; + private int m_end_token; + private int m_current_token_type; + + private boolean m_b_has_zs; + private boolean m_b_has_ms; + private boolean m_b_check_consistent_attributes; + private boolean m_b_nan; + + private AttributeStreamOfInt32 m_function_stack; + + private interface State { + static final int xLiteral = 0; + static final int yLiteral = 1; + static final int zLiteral = 2; + static final int mLiteral = 3; + static final int pointStart = 4; + static final int pointStartAlt = 5; + static final int pointEnd = 6; + static final int lineStringStart = 7; + static final int lineStringEnd = 8; + static final int multiPointStart = 9; + static final int multiPointEnd = 10; + static final int polygonStart = 11; + static final int polygonEnd = 12; + static final int multiLineStringStart = 13; + static final int multiLineStringEnd = 14; + static final int multiPolygonStart = 15; + static final int multiPolygonEnd = 16; + static final int geometryCollectionStart = 17; + static final int geometryCollectionEnd = 18; + static final int accept = 19; + static final int geometry = 20; + static final int attributes = 21; + } + + private interface Number { + static final int signed_numeric_literal = WktToken.x_literal + | WktToken.y_literal | WktToken.z_literal | WktToken.m_literal; + } + + private void reset_() { + m_function_stack.add(State.accept); + m_function_stack.add(State.geometry); + m_start_token = -1; + m_end_token = 0; + m_current_token_type = WktToken.not_available; + m_b_has_zs = false; + m_b_has_ms = false; + m_b_check_consistent_attributes = false; + m_b_nan = false; + } + + private void accept_() { + m_start_token = m_end_token; + m_current_token_type = WktToken.not_available; + } + + private void geometry_() { + skipWhiteSpace_(); + m_start_token = m_end_token; + m_function_stack.removeLast(); + + if (m_start_token + 5 <= m_wkt_string.length() + && m_wkt_string.regionMatches(true, m_start_token, "point", 0, + 5)) { + m_end_token = m_start_token + 5; + m_current_token_type = WktToken.point; + m_function_stack.add(State.pointStart); + } else if (m_start_token + 10 <= m_wkt_string.length() + && m_wkt_string.regionMatches(true, m_start_token, + "linestring", 0, 10)) { + m_end_token = m_start_token + 10; + m_current_token_type = WktToken.linestring; + m_function_stack.add(State.lineStringStart); + } else if (m_start_token + 10 <= m_wkt_string.length() + && m_wkt_string.regionMatches(true, m_start_token, + "multipoint", 0, 10)) { + m_end_token = m_start_token + 10; + m_current_token_type = WktToken.multipoint; + m_function_stack.add(State.multiPointStart); + } else if (m_start_token + 7 <= m_wkt_string.length() + && m_wkt_string.regionMatches(true, m_start_token, "polygon", + 0, 7)) { + m_end_token = m_start_token + 7; + m_current_token_type = WktToken.polygon; + m_function_stack.add(State.polygonStart); + } else if (m_start_token + 15 <= m_wkt_string.length() + && m_wkt_string.regionMatches(true, m_start_token, + "multilinestring", 0, 15)) { + m_end_token = m_start_token + 15; + m_current_token_type = WktToken.multilinestring; + m_function_stack.add(State.multiLineStringStart); + } else if (m_start_token + 12 <= m_wkt_string.length() + && m_wkt_string.regionMatches(true, m_start_token, + "multipolygon", 0, 12)) { + m_end_token = m_start_token + 12; + m_current_token_type = WktToken.multipolygon; + m_function_stack.add(State.multiPolygonStart); + } else if (m_start_token + 18 <= m_wkt_string.length() + && m_wkt_string.regionMatches(true, m_start_token, + "geometrycollection", 0, 18)) { + m_end_token = m_start_token + 18; + m_current_token_type = WktToken.geometrycollection; + m_function_stack.add(State.geometryCollectionStart); + } else { + //String snippet = (m_wkt_string.length() > 200 ? m_wkt_string + // .substring(0, 200) + "..." : m_wkt_string); + //throw new IllegalArgumentException( + // "Could not parse Well-Known Text: " + snippet); + throw new IllegalArgumentException( + "Could not parse Well-Known Text around position: " + m_end_token); + } + + m_function_stack.add(State.attributes); + } + + private void attributes_() { + skipWhiteSpace_(); + m_start_token = m_end_token; + m_function_stack.removeLast(); + + // Z and M is not allowed to have a space between them + boolean b_has_zs = false, b_has_ms = false; + + if (m_wkt_string.charAt(m_end_token) == 'z' + || m_wkt_string.charAt(m_end_token) == 'Z') { + b_has_zs = true; + + if (++m_end_token >= m_wkt_string.length()) + throw new IllegalArgumentException(); + } + + if (m_wkt_string.charAt(m_end_token) == 'm' + || m_wkt_string.charAt(m_end_token) == 'M') { + b_has_ms = true; + + if (++m_end_token >= m_wkt_string.length()) + throw new IllegalArgumentException(); + } + + if (m_b_check_consistent_attributes) { + if (b_has_zs != m_b_has_zs || b_has_ms != m_b_has_ms) + throw new IllegalArgumentException(); + } + + m_b_has_zs = b_has_zs; + m_b_has_ms = b_has_ms; + + if (m_b_has_zs || m_b_has_ms) { + if (m_b_has_zs && !m_b_has_ms) + m_current_token_type = WktToken.attribute_z; + else if (m_b_has_ms && !m_b_has_zs) + m_current_token_type = WktToken.attribute_m; + else + m_current_token_type = WktToken.attribute_zm; + } else { + nextToken(); + } + } + + private void geometryCollectionStart_() { + skipWhiteSpace_(); + m_start_token = m_end_token; + m_b_check_consistent_attributes = true; + + if (empty_()) { + m_function_stack.removeLast(); + } else if (leftParen_()) { + m_function_stack.removeLast(); + m_function_stack.add(State.geometryCollectionEnd); + m_function_stack.add(State.geometry); + } else { + throw new IllegalArgumentException(); + } + } + + private void geometryCollectionEnd_() { + skipWhiteSpace_(); + m_start_token = m_end_token; + + if (comma_()) { + m_function_stack.add(State.geometry); + geometry_(); + } else if (rightParen_()) { + m_function_stack.removeLast(); + } else { + throw new IllegalArgumentException(); + } + } + + private void multiPolygonStart_() { + skipWhiteSpace_(); + m_start_token = m_end_token; + + if (empty_()) { + m_function_stack.removeLast(); + } else if (leftParen_()) { + m_function_stack.removeLast(); + m_function_stack.add(State.multiPolygonEnd); + m_function_stack.add(State.polygonStart); + } else { + throw new IllegalArgumentException(); + } + } + + private void multiPolygonEnd_() { + skipWhiteSpace_(); + m_start_token = m_end_token; + + if (comma_()) { + m_function_stack.add(State.polygonStart); + polygonStart_(); + } else if (rightParen_()) { + m_function_stack.removeLast(); + } else { + throw new IllegalArgumentException(); + } + } + + private void multiLineStringStart_() { + skipWhiteSpace_(); + m_start_token = m_end_token; + + if (empty_()) { + m_function_stack.removeLast(); + } else if (leftParen_()) { + m_function_stack.removeLast(); + m_function_stack.add(State.multiLineStringEnd); + m_function_stack.add(State.lineStringStart); + } else { + throw new IllegalArgumentException(); + } + } + + private void multiLineStringEnd_() { + skipWhiteSpace_(); + m_start_token = m_end_token; + + if (comma_()) { + m_function_stack.add(State.lineStringStart); + lineStringStart_(); + } else if (rightParen_()) { + m_function_stack.removeLast(); + } else { + throw new IllegalArgumentException(); + } + } + + private void multiPointStart_() { + skipWhiteSpace_(); + m_start_token = m_end_token; + + if (empty_()) { + m_function_stack.removeLast(); + } else if (leftParen_()) { + m_function_stack.removeLast(); + m_function_stack.add(State.multiPointEnd); + m_function_stack.add(State.pointStartAlt); + } else { + throw new IllegalArgumentException(); + } + } + + private void multiPointEnd_() { + skipWhiteSpace_(); + m_start_token = m_end_token; + + if (comma_()) { + m_function_stack.add(State.pointStart); + pointStart_(); + } else if (rightParen_()) { + m_function_stack.removeLast(); + } else { + throw new IllegalArgumentException(); + } + } + + private void polygonStart_() { + skipWhiteSpace_(); + m_start_token = m_end_token; + + if (empty_()) { + m_function_stack.removeLast(); + } else if (leftParen_()) { + m_function_stack.removeLast(); + m_function_stack.add(State.polygonEnd); + m_function_stack.add(State.lineStringStart); + } else { + throw new IllegalArgumentException(); + } + } + + private void polygonEnd_() { + skipWhiteSpace_(); + m_start_token = m_end_token; + + if (comma_()) { + m_function_stack.add(State.lineStringStart); + lineStringStart_(); + } else if (rightParen_()) { + m_function_stack.removeLast(); + } else { + throw new IllegalArgumentException(); + } + } + + private void lineStringStart_() { + skipWhiteSpace_(); + m_start_token = m_end_token; + + if (empty_()) { + m_function_stack.removeLast(); + } else if (leftParen_()) { + m_function_stack.removeLast(); + m_function_stack.add(State.lineStringEnd); + m_function_stack.add(State.xLiteral); + } else { + throw new IllegalArgumentException(); + } + } + + private void lineStringEnd_() { + skipWhiteSpace_(); + m_start_token = m_end_token; + + if (comma_()) { + m_function_stack.add(State.xLiteral); + xLiteral_(); + } else if (rightParen_()) { + m_function_stack.removeLast(); + } else { + throw new IllegalArgumentException(); + } + } + + private void pointStart_() { + skipWhiteSpace_(); + m_start_token = m_end_token; + + if (empty_()) { + m_function_stack.removeLast(); + } else if (leftParen_()) { + m_function_stack.removeLast(); + m_function_stack.add(State.pointEnd); + m_function_stack.add(State.xLiteral); + } else { + throw new IllegalArgumentException(); + } + } + + private void pointStartAlt_() { + skipWhiteSpace_(); + m_start_token = m_end_token; + + if (empty_()) {// ogc standard + m_function_stack.removeLast(); + } else if (leftParen_()) {// ogc standard + m_function_stack.removeLast(); + m_function_stack.add(State.pointEnd); + m_function_stack.add(State.xLiteral); + } else {// not ogc standard. treat as linestring + m_function_stack.removeLast(); + m_function_stack.removeLast(); + m_function_stack.add(State.lineStringEnd); + m_function_stack.add(State.xLiteral); + nextToken(); + } + } + + private void pointEnd_() { + skipWhiteSpace_(); + m_start_token = m_end_token; + + if (rightParen_()) { + m_function_stack.removeLast(); + } else { + throw new IllegalArgumentException(); + } + } + + private void xLiteral_() { + signedNumericLiteral_(); + m_current_token_type = WktToken.x_literal; + m_function_stack.removeLast(); + m_function_stack.add(State.yLiteral); + } + + private void yLiteral_() { + signedNumericLiteral_(); + m_current_token_type = WktToken.y_literal; + m_function_stack.removeLast(); + + if (m_b_has_zs) + m_function_stack.add(State.zLiteral); + else if (m_b_has_ms) + m_function_stack.add(State.mLiteral); + } + + private void zLiteral_() { + signedNumericLiteral_(); + m_current_token_type = WktToken.z_literal; + m_function_stack.removeLast(); + + if (m_b_has_ms) + m_function_stack.add(State.mLiteral); + } + + private void mLiteral_() { + signedNumericLiteral_(); + m_current_token_type = WktToken.m_literal; + m_function_stack.removeLast(); + } + + private boolean nan_() { + if (m_start_token + 3 <= m_wkt_string.length() + && m_wkt_string.regionMatches(true, m_start_token, "nan", 0, 3)) { + m_end_token += 3; + m_b_nan = true; + return true; + } + + m_b_nan = false; + return false; + } + + private void sign_() { + // Optional - or + sign + if (m_wkt_string.charAt(m_end_token) == '-' + || m_wkt_string.charAt(m_end_token) == '+') { + if (++m_end_token >= m_wkt_string.length()) + throw new IllegalArgumentException(); + } + } + + private void signedNumericLiteral_() { + skipWhiteSpace_(); + m_start_token = m_end_token; + + if (nan_()) + return; + + sign_(); // Optional + unsignedNumericLiteral_(); + } + + private void unsignedNumericLiteral_() { + exactNumericLiteral_(); + exp_(); // Optional + } + + private void exactNumericLiteral_() { + if (Character.isDigit(m_wkt_string.charAt(m_end_token))) { + digits_(); + + // Optional + if (m_wkt_string.charAt(m_end_token) == '.') { + if (++m_end_token >= m_wkt_string.length()) + throw new IllegalArgumentException(); + + // Optional + if (Character.isDigit(m_wkt_string.charAt(m_end_token))) + digits_(); + } + } else if (m_wkt_string.charAt(m_end_token) == '.') { + if (++m_end_token >= m_wkt_string.length()) + throw new IllegalArgumentException(); + + if (!Character.isDigit(m_wkt_string.charAt(m_end_token))) + throw new IllegalArgumentException(); + + digits_(); + } else { + throw new IllegalArgumentException(); + } + } + + private void digits_() { + do { + if (++m_end_token >= m_wkt_string.length()) + throw new IllegalArgumentException(); + + } while (Character.isDigit(m_wkt_string.charAt(m_end_token))); + } + + private void exp_() { + // This is an optional state + if (m_wkt_string.charAt(m_end_token) == 'e' + || m_wkt_string.charAt(m_end_token) == 'E') { + if (++m_end_token >= m_wkt_string.length()) + throw new IllegalArgumentException(); + + sign_(); // optional + + if (!Character.isDigit(m_wkt_string.charAt(m_end_token))) + throw new IllegalArgumentException(); + + digits_(); + } + } + + private void skipWhiteSpace_() { + if (m_end_token >= m_wkt_string.length()) + throw new IllegalArgumentException(); + + while (Character.isWhitespace(m_wkt_string.charAt(m_end_token))) { + if (++m_end_token >= m_wkt_string.length()) + throw new IllegalArgumentException(); + } + } + + private boolean empty_() { + if (m_start_token + 5 <= m_wkt_string.length() + && m_wkt_string.regionMatches(true, m_start_token, "empty", 0, 5)) { + m_end_token += 5; + m_current_token_type = WktToken.empty; + return true; + } + + return false; + } + + private boolean comma_() { + if (m_wkt_string.charAt(m_end_token) == ',') { + m_end_token++; + return true; + } + + return false; + } + + private boolean leftParen_() { + if (m_wkt_string.charAt(m_end_token) == '(') { + m_end_token++; + m_current_token_type = WktToken.left_paren; + return true; + } + + return false; + } + + private boolean rightParen_() { + if (m_wkt_string.charAt(m_end_token) == ')') { + m_end_token++; + m_current_token_type = WktToken.right_paren; + return true; + } + + return false; + } } diff --git a/src/main/java/com/esri/core/geometry/ogc/OGCConcreteGeometryCollection.java b/src/main/java/com/esri/core/geometry/ogc/OGCConcreteGeometryCollection.java index 4947470f..161cb83a 100644 --- a/src/main/java/com/esri/core/geometry/ogc/OGCConcreteGeometryCollection.java +++ b/src/main/java/com/esri/core/geometry/ogc/OGCConcreteGeometryCollection.java @@ -1,5 +1,5 @@ /* - Copyright 1995-2017 Esri + Copyright 1995-2018 Esri Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -25,13 +25,26 @@ package com.esri.core.geometry.ogc; import com.esri.core.geometry.Envelope; +import com.esri.core.geometry.GeoJsonExportFlags; import com.esri.core.geometry.Geometry; import com.esri.core.geometry.GeometryCursor; +import com.esri.core.geometry.GeometryException; +import com.esri.core.geometry.MultiPath; +import com.esri.core.geometry.MultiPoint; +import com.esri.core.geometry.MultiVertexGeometry; import com.esri.core.geometry.NumberUtils; +import com.esri.core.geometry.OGCStructureInternal; +import com.esri.core.geometry.OperatorConvexHull; +import com.esri.core.geometry.OperatorDifference; +import com.esri.core.geometry.OperatorExportToGeoJson; +import com.esri.core.geometry.OperatorIntersection; +import com.esri.core.geometry.OperatorUnion; +import com.esri.core.geometry.Point; import com.esri.core.geometry.Polygon; +import com.esri.core.geometry.Polyline; +import com.esri.core.geometry.SimpleGeometryCursor; import com.esri.core.geometry.SpatialReference; -import com.esri.core.geometry.GeoJsonExportFlags; -import com.esri.core.geometry.OperatorExportToGeoJson; +import com.esri.core.geometry.VertexDescription; import java.nio.ByteBuffer; import java.nio.ByteOrder; @@ -41,71 +54,91 @@ import static com.esri.core.geometry.SizeOf.SIZE_OF_OGC_CONCRETE_GEOMETRY_COLLECTION; public class OGCConcreteGeometryCollection extends OGCGeometryCollection { - public OGCConcreteGeometryCollection(List geoms, - SpatialReference sr) { - geometries = geoms; - esriSR = sr; - } - - public OGCConcreteGeometryCollection(OGCGeometry geom, SpatialReference sr) { - geometries = new ArrayList(1); - geometries.add(geom); - esriSR = sr; - } - - @Override - public int dimension() { - int maxD = 0; - for (int i = 0, n = numGeometries(); i < n; i++) - maxD = Math.max(geometryN(i).dimension(), maxD); - - return maxD; - } - - @Override - public int coordinateDimension() { - return isEmpty() ? 2 : geometryN(0).coordinateDimension(); - } - - @Override - public boolean is3D() { - return !isEmpty() && geometries.get(0).is3D(); - } - - @Override - public boolean isMeasured() { - return !isEmpty() && geometries.get(0).isMeasured(); - } - - @Override - public OGCGeometry envelope() { - GeometryCursor gc = getEsriGeometryCursor(); - Envelope env = new Envelope(); - for (Geometry g = gc.next(); g != null; g = gc.next()) { - Envelope e = new Envelope(); - g.queryEnvelope(e); - env.merge(e); - } - - Polygon polygon = new Polygon(); - polygon.addEnvelope(env, false); - return new OGCPolygon(polygon, esriSR); - } - - @Override - public int numGeometries() { - return geometries.size(); - } - - @Override - public OGCGeometry geometryN(int n) { - return geometries.get(n); - } - - @Override - public String geometryType() { - return "GeometryCollection"; - } + static public String TYPE = "GeometryCollection"; + + List geometries; + + public OGCConcreteGeometryCollection(List geoms, + SpatialReference sr) { + geometries = geoms; + esriSR = sr; + } + + public OGCConcreteGeometryCollection(GeometryCursor geoms, + SpatialReference sr) { + List ogcGeoms = new ArrayList(10); + for (Geometry g = geoms.next(); g != null; g = geoms.next()) { + ogcGeoms.add(createFromEsriGeometry(g, sr)); + } + + geometries = ogcGeoms; + esriSR = sr; + } + + public OGCConcreteGeometryCollection(OGCGeometry geom, SpatialReference sr) { + geometries = new ArrayList(1); + geometries.add(geom); + esriSR = sr; + } + + public OGCConcreteGeometryCollection(SpatialReference sr) { + geometries = new ArrayList(); + esriSR = sr; + } + + @Override + public int dimension() { + int maxD = 0; + for (int i = 0, n = numGeometries(); i < n; i++) + maxD = Math.max(geometryN(i).dimension(), maxD); + + return maxD; + } + + @Override + public int coordinateDimension() { + return isEmpty() ? 2 : geometryN(0).coordinateDimension(); + } + + @Override + public boolean is3D() { + return !isEmpty() && geometries.get(0).is3D(); + } + + @Override + public boolean isMeasured() { + return !isEmpty() && geometries.get(0).isMeasured(); + } + + @Override + public OGCGeometry envelope() { + GeometryCursor gc = getEsriGeometryCursor(); + Envelope env = new Envelope(); + for (Geometry g = gc.next(); g != null; g = gc.next()) { + Envelope e = new Envelope(); + g.queryEnvelope(e); + env.merge(e); + } + + Polygon polygon = new Polygon(); + polygon.addEnvelope(env, false); + return new OGCPolygon(polygon, esriSR); + } + + @Override + public int numGeometries() { + return geometries.size(); + } + + @Override + public OGCGeometry geometryN(int n) { + return geometries.get(n); + } + + @Override + public String geometryType() { + return TYPE; + } @Override public long estimateMemorySize() @@ -131,313 +164,798 @@ public String asText() { if (is3D() || isMeasured()) sb.append(' '); - int n = numGeometries(); + int n = numGeometries(); + + if (n == 0) { + sb.append("EMPTY"); + return sb.toString(); + } + + sb.append('('); + for (int i = 0; i < n; i++) { + if (i > 0) + sb.append(", "); + + sb.append(geometryN(i).asText()); + } + sb.append(')'); + + return sb.toString(); + } + + @Override + public ByteBuffer asBinary() { + + ArrayList buffers = new ArrayList(0); + + int size = 9; + int n = numGeometries(); + for (int i = 0; i < n; i++) { + ByteBuffer buffer = geometryN(i).asBinary(); + buffers.add(buffer); + size += buffer.capacity(); + } + + ByteBuffer wkbBuffer = ByteBuffer.allocate(size).order( + ByteOrder.nativeOrder()); + + byte byteOrder = (byte) (wkbBuffer.order() == ByteOrder.LITTLE_ENDIAN ? 1 + : 0); + int wkbType = 7; + + if (is3D()) + wkbType += 1000; + if (isMeasured()) + wkbType += 2000; + + wkbBuffer.put(0, byteOrder); + wkbBuffer.putInt(1, wkbType); + wkbBuffer.putInt(5, n); + + int offset = 9; + for (int i = 0; i < n; i++) { + byte[] arr = buffers.get(i).array(); + System.arraycopy(arr, 0, wkbBuffer.array(), offset, arr.length); + offset += arr.length; + } + + return wkbBuffer; + } + + @Override + public String asGeoJson() { + return asGeoJsonImpl(GeoJsonExportFlags.geoJsonExportDefaults); + } + + @Override + String asGeoJsonImpl(int export_flags) { + StringBuilder sb = new StringBuilder(); + + sb.append("{\"type\":\"GeometryCollection\",\"geometries\":"); + + sb.append("["); + for (int i = 0, n = numGeometries(); i < n; i++) { + if (i > 0) + sb.append(","); + + if (geometryN(i) != null) + sb.append(geometryN(i).asGeoJsonImpl(GeoJsonExportFlags.geoJsonExportSkipCRS)); + } + + sb.append("],\"crs\":"); + + if (esriSR != null) { + String crs_value = OperatorExportToGeoJson.local().exportSpatialReference(0, esriSR); + sb.append(crs_value); + } else { + sb.append("\"null\""); + } + + sb.append("}"); + + return sb.toString(); + } + + @Override + public boolean isEmpty() { + return numGeometries() == 0; + } + + @Override + public double MinZ() { + double z = Double.NaN; + for (int i = 0, n = numGeometries(); i < n; i++) + z = i == 0 ? geometryN(i).MinZ() : Math.min(geometryN(i).MinZ(), z); + return z; + } + + @Override + public double MaxZ() { + double z = Double.NaN; + for (int i = 0, n = numGeometries(); i < n; i++) + z = i == 0 ? geometryN(i).MaxZ() : Math.min(geometryN(i).MaxZ(), z); + return z; + } + + @Override + public double MinMeasure() { + double z = Double.NaN; + for (int i = 0, n = numGeometries(); i < n; i++) + z = i == 0 ? geometryN(i).MinMeasure() : Math.min(geometryN(i) + .MinMeasure(), z); + return z; + } + + @Override + public double MaxMeasure() { + double z = Double.NaN; + for (int i = 0, n = numGeometries(); i < n; i++) + z = i == 0 ? geometryN(i).MaxMeasure() : Math.min(geometryN(i) + .MaxMeasure(), z); + return z; + } + + @Override + public boolean isSimple() { + for (int i = 0, n = numGeometries(); i < n; i++) + if (!geometryN(i).isSimple()) + return false; + + return true; + } + + /** + * makeSimpleRelaxed is not supported for the GeometryCollection instance. + * + */ + @Override + public OGCGeometry makeSimple() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean isSimpleRelaxed() { + for (int i = 0, n = numGeometries(); i < n; i++) + if (!geometryN(i).isSimpleRelaxed()) + return false; + return true; + } + + /** + * makeSimpleRelaxed is not supported for the GeometryCollection instance. + * + */ + @Override + public OGCGeometry makeSimpleRelaxed(boolean forceProcessing) { + throw new UnsupportedOperationException(); + } + + @Override + public OGCGeometry boundary() { + throw new UnsupportedOperationException(); + } + + @Override + public OGCGeometry locateAlong(double mValue) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException(); + } + + @Override + public OGCGeometry locateBetween(double mStart, double mEnd) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException(); + } - if (n == 0) { - sb.append("EMPTY"); - return sb.toString(); - } - - sb.append('('); - for (int i = 0; i < n; i++) { - if (i > 0) - sb.append(", "); - - sb.append(geometryN(i).asText()); - } - sb.append(')'); - - return sb.toString(); - } - - @Override - public ByteBuffer asBinary() { - - ArrayList buffers = new ArrayList(0); - - int size = 9; - int n = numGeometries(); - for (int i = 0; i < n; i++) { - ByteBuffer buffer = geometryN(i).asBinary(); - buffers.add(buffer); - size += buffer.capacity(); - } - - ByteBuffer wkbBuffer = ByteBuffer.allocate(size).order( - ByteOrder.nativeOrder()); - - byte byteOrder = (byte) (wkbBuffer.order() == ByteOrder.LITTLE_ENDIAN ? 1 - : 0); - int wkbType = 7; - - if (is3D()) - wkbType += 1000; - if (isMeasured()) - wkbType += 2000; - - wkbBuffer.put(0, byteOrder); - wkbBuffer.putInt(1, wkbType); - wkbBuffer.putInt(5, n); - - int offset = 9; - for (int i = 0; i < n; i++) { - byte[] arr = buffers.get(i).array(); - System.arraycopy(arr, 0, wkbBuffer.array(), offset, arr.length); - offset += arr.length; - } - - return wkbBuffer; - } - - @Override - public String asGeoJson() { - return asGeoJsonImpl(GeoJsonExportFlags.geoJsonExportDefaults); - } - - @Override - String asGeoJsonImpl(int export_flags) { - StringBuilder sb = new StringBuilder(); - - sb.append("{\"type\":\"GeometryCollection\",\"geometries\":"); - - sb.append("["); - for (int i = 0, n = numGeometries(); i < n; i++) { - if (i > 0) - sb.append(","); - - if (geometryN(i) != null) - sb.append(geometryN(i).asGeoJsonImpl(GeoJsonExportFlags.geoJsonExportSkipCRS)); - } - - sb.append("],\"crs\":"); - - if (esriSR != null) { - String crs_value = OperatorExportToGeoJson.local().exportSpatialReference(0, esriSR); - sb.append(crs_value); - } else { - sb.append("\"null\""); - } - - sb.append("}"); - - return sb.toString(); - } - - @Override - public boolean isEmpty() { - return numGeometries() == 0; - } - - @Override - public double MinZ() { - double z = Double.NaN; - for (int i = 0, n = numGeometries(); i < n; i++) - z = i == 0 ? geometryN(i).MinZ() : Math.min(geometryN(i).MinZ(), z); - return z; - } - - @Override - public double MaxZ() { - double z = Double.NaN; - for (int i = 0, n = numGeometries(); i < n; i++) - z = i == 0 ? geometryN(i).MaxZ() : Math.min(geometryN(i).MaxZ(), z); - return z; - } - - @Override - public double MinMeasure() { - double z = Double.NaN; - for (int i = 0, n = numGeometries(); i < n; i++) - z = i == 0 ? geometryN(i).MinMeasure() : Math.min(geometryN(i) - .MinMeasure(), z); - return z; - } - - @Override - public double MaxMeasure() { - double z = Double.NaN; - for (int i = 0, n = numGeometries(); i < n; i++) - z = i == 0 ? geometryN(i).MaxMeasure() : Math.min(geometryN(i) - .MaxMeasure(), z); - return z; - } - - @Override - public boolean isSimple() { - for (int i = 0, n = numGeometries(); i < n; i++) - if (!geometryN(i).isSimple()) - return false; - return true; - } - - /** - * makeSimpleRelaxed is not supported for the GeometryCollection instance. - */ - @Override - public OGCGeometry makeSimple() { - throw new UnsupportedOperationException(); - } - - @Override - public boolean isSimpleRelaxed() { - for (int i = 0, n = numGeometries(); i < n; i++) - if (!geometryN(i).isSimpleRelaxed()) - return false; - return true; - } - - /** - * makeSimpleRelaxed is not supported for the GeometryCollection instance. - */ - @Override - public OGCGeometry makeSimpleRelaxed(boolean forceProcessing) { - throw new UnsupportedOperationException(); - } - - @Override - public OGCGeometry boundary() { - throw new UnsupportedOperationException(); - } - - @Override - public OGCGeometry locateAlong(double mValue) { - // TODO Auto-generated method stub - throw new UnsupportedOperationException(); - } - - @Override - public OGCGeometry locateBetween(double mStart, double mEnd) { - // TODO Auto-generated method stub - throw new UnsupportedOperationException(); - } - - @Override - public Geometry getEsriGeometry() { - return null; - } - - @Override - public GeometryCursor getEsriGeometryCursor() { - return new GeometryCursorOGC(geometries); - } - - @Override - protected boolean isConcreteGeometryCollection() { - return true; - } - - static class GeometryCursorOGC extends GeometryCursor { - private int m_index; - private int m_ind; - private List m_geoms; - GeometryCursor m_curs; - - GeometryCursorOGC(List geoms) { - m_geoms = geoms; - m_index = -1; - m_curs = null; - m_ind = 0; - } - - @Override - public boolean hasNext() { return m_curs != null && m_curs.hasNext(); } - - @Override - public Geometry next() { - while (true) { - if (m_curs != null) { - Geometry g = m_curs.next(); - if (g != null) { - m_index++; - return g; - } - m_curs = null; - } - if (m_ind >= m_geoms.size()) - return null; - - int i = m_ind; - m_ind++; - if (m_geoms.get(i) == null) - continue;// filter out nulls - if (!m_geoms.get(i).isConcreteGeometryCollection()) { - m_index++; - return m_geoms.get(i).getEsriGeometry(); - } else { - OGCConcreteGeometryCollection gc = (OGCConcreteGeometryCollection) m_geoms - .get(i); - m_curs = new GeometryCursorOGC(gc.geometries); - return next(); - } - } - } - - @Override - public long getGeometryID() { - return m_index; - } - - } - - List geometries; - - @Override - public void setSpatialReference(SpatialReference esriSR_) { - esriSR = esriSR_; - for (int i = 0, n = geometries.size(); i < n; i++) { - if (geometries.get(i) != null) - geometries.get(i).setSpatialReference(esriSR_); - } - } - - @Override - public OGCGeometry convertToMulti() { - return this; - } - - @Override - public String asJson() { - throw new UnsupportedOperationException(); - } - - @Override - public boolean equals(Object other) { - if (other == null) - return false; - - if (other == this) - return true; - - if (other.getClass() != getClass()) - return false; - - OGCConcreteGeometryCollection another = (OGCConcreteGeometryCollection) other; - if (geometries != null) { - if (!geometries.equals(another.geometries)) - return false; - } else if (another.geometries != null) - return false; - - if (esriSR == another.esriSR) { - return true; - } - - if (esriSR != null && another.esriSR != null) { - return esriSR.equals(another.esriSR); - } - - return false; - } - - @Override - public int hashCode() { - int hash = 1; - if (geometries != null) - hash = geometries.hashCode(); - - if (esriSR != null) - hash = NumberUtils.hashCombine(hash, esriSR.hashCode()); - - return hash; - } + @Override + public Geometry getEsriGeometry() { + return null; + } + + @Override + public GeometryCursor getEsriGeometryCursor() { + return new GeometryCursorOGC(geometries); + } + + @Override + protected boolean isConcreteGeometryCollection() { + return true; + } + + static class GeometryCursorOGC extends GeometryCursor { + private int m_index; + private int m_ind; + private List m_geoms; + GeometryCursor m_curs; + + GeometryCursorOGC(List geoms) { + m_geoms = geoms; + m_index = -1; + m_curs = null; + m_ind = 0; + } + + @Override + public boolean hasNext() { + return m_curs != null && m_curs.hasNext(); + } + + @Override + public Geometry next() { + while (true) { + if (m_curs != null) { + Geometry g = m_curs.next(); + if (g != null) { + m_index++; + return g; + } + m_curs = null; + } + if (m_ind >= m_geoms.size()) + return null; + + int i = m_ind; + m_ind++; + if (m_geoms.get(i) == null) + continue;// filter out nulls + if (!m_geoms.get(i).isConcreteGeometryCollection()) { + m_index++; + return m_geoms.get(i).getEsriGeometry(); + } else { + OGCConcreteGeometryCollection gc = (OGCConcreteGeometryCollection) m_geoms + .get(i); + m_curs = new GeometryCursorOGC(gc.geometries); + return next(); + } + } + } + + @Override + public long getGeometryID() { + return m_index; + } + + } + + @Override + public OGCGeometry convexHull() { + GeometryCursor cursor = OperatorConvexHull.local().execute( + getEsriGeometryCursor(), false, null); + MultiPoint mp = new MultiPoint(); + Polygon polygon = new Polygon(); + VertexDescription vd = null; + for (Geometry geom = cursor.next(); geom != null; geom = cursor.next()) { + vd = geom.getDescription(); + if (geom.isEmpty()) + continue; + + if (geom.getType() == Geometry.Type.Polygon) { + polygon.add((MultiPath) geom, false); + } + else if (geom.getType() == Geometry.Type.Polyline) { + mp.add((MultiVertexGeometry) geom, 0, -1); + } + else if (geom.getType() == Geometry.Type.Point) { + mp.add((Point) geom); + } + else { + throw new GeometryException("internal error"); + } + } + + Geometry resultGeom = null; + if (!mp.isEmpty()) { + resultGeom = OperatorConvexHull.local().execute(mp, null); + } + + if (!polygon.isEmpty()) { + if (resultGeom != null && !resultGeom.isEmpty()) { + Geometry[] geoms = { resultGeom, polygon }; + resultGeom = OperatorConvexHull.local().execute( + new SimpleGeometryCursor(geoms), true, null).next(); + } + else { + resultGeom = OperatorConvexHull.local().execute(polygon, null); + } + } + + if (resultGeom == null) { + Point pt = new Point(); + if (vd != null) + pt.assignVertexDescription(vd); + + return new OGCPoint(pt, getEsriSpatialReference()); + } + + return OGCGeometry.createFromEsriGeometry(resultGeom, getEsriSpatialReference(), false); + } + + @Override + public void setSpatialReference(SpatialReference esriSR_) { + esriSR = esriSR_; + for (int i = 0, n = geometries.size(); i < n; i++) { + if (geometries.get(i) != null) + geometries.get(i).setSpatialReference(esriSR_); + } + } + + @Override + public OGCGeometry convertToMulti() { + return this; + } + + @Override + public OGCGeometry reduceFromMulti() { + int n = numGeometries(); + if (n == 0) { + return this; + } + + if (n == 1) { + return geometryN(0).reduceFromMulti(); + } + + return this; + } + + @Override + public String asJson() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean equals(Object other) { + if (other == null) + return false; + + if (other == this) + return true; + + if (other.getClass() != getClass()) + return false; + + OGCConcreteGeometryCollection another = (OGCConcreteGeometryCollection) other; + if (geometries != null) { + if (!geometries.equals(another.geometries)) + return false; + } else if (another.geometries != null) + return false; + + if (esriSR == another.esriSR) { + return true; + } + + if (esriSR != null && another.esriSR != null) { + return esriSR.equals(another.esriSR); + } + return false; + } + + @Override + public int hashCode() { + int hash = 1; + if (geometries != null) + hash = geometries.hashCode(); + + if (esriSR != null) + hash = NumberUtils.hashCombine(hash, esriSR.hashCode()); + + return hash; + } + + @Override + public double distance(OGCGeometry another) { + if (this == another) + return isEmpty() ? Double.NaN : 0; + + double minD = Double.NaN; + for (int i = 0, n = numGeometries(); i < n; ++i) { + // TODO Skip expensive distance computation if bounding boxes are further away than minD + double d = geometryN(i).distance(another); + if (d < minD || Double.isNaN(minD)) { + minD = d; + // TODO Replace zero with tolerance defined by the spatial reference + if (minD == 0) { + break; + } + } + } + + return minD; + } + + // + //Relational operations + @Override + public boolean overlaps(OGCGeometry another) { + //TODO + throw new UnsupportedOperationException(); + } + + @Override + public boolean touches(OGCGeometry another) { + //TODO + throw new UnsupportedOperationException(); + } + + @Override + public boolean crosses(OGCGeometry another) { + //TODO + throw new UnsupportedOperationException(); + } + + @Override + public boolean relate(OGCGeometry another, String matrix) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean disjoint(OGCGeometry another) { + if (isEmpty() || another.isEmpty()) + return true; + + if (this == another) + return false; + + //TODO: a simple envelope test + + OGCConcreteGeometryCollection flattened1 = flatten(); + if (flattened1.isEmpty()) + return true; + OGCConcreteGeometryCollection otherCol = new OGCConcreteGeometryCollection(another, esriSR); + OGCConcreteGeometryCollection flattened2 = otherCol.flatten(); + if (flattened2.isEmpty()) + return true; + + for (int i = 0, n1 = flattened1.numGeometries(); i < n1; ++i) { + OGCGeometry g1 = flattened1.geometryN(i); + for (int j = 0, n2 = flattened2.numGeometries(); j < n2; ++j) { + OGCGeometry g2 = flattened2.geometryN(j); + if (!g1.disjoint(g2)) + return false; + } + } + + return true; + } + + @Override + public boolean contains(OGCGeometry another) { + if (isEmpty() || another.isEmpty()) + return false; + + if (this == another) + return true; + + return another.difference(this).isEmpty(); + } + + @Override + public boolean Equals(OGCGeometry another) { + if (this == another) + return !isEmpty(); + + if (another == null) + return false; + + + OGCGeometry g1 = reduceFromMulti(); + String t1 = g1.geometryType(); + OGCGeometry g2 = reduceFromMulti(); + if (t1 != g2.geometryType()) { + return false; + } + + if (t1 != OGCConcreteGeometryCollection.TYPE) { + return g1.Equals(g2); + } + + OGCConcreteGeometryCollection gc1 = (OGCConcreteGeometryCollection)g1; + OGCConcreteGeometryCollection gc2 = (OGCConcreteGeometryCollection)g2; + // TODO Assuming input geometries are simple and valid, remove-overlaps would be a no-op. + // Hence, calling flatten() should be sufficient. + gc1 = gc1.flattenAndRemoveOverlaps(); + gc2 = gc2.flattenAndRemoveOverlaps(); + int n = gc1.numGeometries(); + if (n != gc2.numGeometries()) { + return false; + } + + for (int i = 0; i < n; ++i) { + if (!gc1.geometryN(i).Equals(gc2.geometryN(i))) { + return false; + } + } + + return n > 0; + } + + private static OGCConcreteGeometryCollection toGeometryCollection(OGCGeometry geometry) + { + if (geometry.geometryType() != OGCConcreteGeometryCollection.TYPE) { + return new OGCConcreteGeometryCollection(geometry, geometry.getEsriSpatialReference()); + } + + return (OGCConcreteGeometryCollection) geometry; + } + + private static List toList(GeometryCursor cursor) + { + List geometries = new ArrayList(); + for (Geometry geometry = cursor.next(); geometry != null; geometry = cursor.next()) { + geometries.add(geometry); + } + return geometries; + } + + //Topological + @Override + public OGCGeometry difference(OGCGeometry another) { + if (isEmpty() || another.isEmpty()) { + return this; + } + + List geometries = toList(prepare_for_ops_(toGeometryCollection(this))); + List otherGeometries = toList(prepare_for_ops_(toGeometryCollection(another))); + + List result = new ArrayList(); + for (Geometry geometry : geometries) { + for (Geometry otherGeometry : otherGeometries) { + if (geometry.getDimension() > otherGeometry.getDimension()) { + continue; //subtracting lower dimension has no effect. + } + + geometry = OperatorDifference.local().execute(geometry, otherGeometry, esriSR, null); + if (geometry.isEmpty()) { + break; + } + } + + if (!geometry.isEmpty()) { + result.add(OGCGeometry.createFromEsriGeometry(geometry, esriSR)); + } + } + + if (result.size() == 1) { + return result.get(0).reduceFromMulti(); + } + + return new OGCConcreteGeometryCollection(result, esriSR).flattenAndRemoveOverlaps(); + } + + @Override + public OGCGeometry intersection(OGCGeometry another) { + if (isEmpty() || another.isEmpty()) { + return new OGCConcreteGeometryCollection(esriSR); + } + + List geometries = toList(prepare_for_ops_(toGeometryCollection(this))); + List otherGeometries = toList(prepare_for_ops_(toGeometryCollection(another))); + + List result = new ArrayList(); + for (Geometry geometry : geometries) { + for (Geometry otherGeometry : otherGeometries) { + GeometryCursor intersectionCursor = OperatorIntersection.local().execute(new SimpleGeometryCursor(geometry), new SimpleGeometryCursor(otherGeometry), esriSR, null, 7); + OGCGeometry intersection = OGCGeometry.createFromEsriCursor(intersectionCursor, esriSR, true); + if (!intersection.isEmpty()) { + result.add(intersection); + } + } + } + + if (result.size() == 1) { + return result.get(0).reduceFromMulti(); + } + + return new OGCConcreteGeometryCollection(result, esriSR).flattenAndRemoveOverlaps(); + } + + @Override + public OGCGeometry symDifference(OGCGeometry another) { + //TODO + throw new UnsupportedOperationException(); + } + + /** + * Checks if collection is flattened. + * @return True for the flattened collection. A flattened collection contains up to three non-empty geometries: + * an OGCMultiPoint, an OGCMultiPolygon, and an OGCMultiLineString. + */ + public boolean isFlattened() { + int n = numGeometries(); + if (n > 3) + return false; + + int dimension = -1; + for (int i = 0; i < n; ++i) { + OGCGeometry g = geometryN(i); + if (g.isEmpty()) + return false;//no empty allowed + + String t = g.geometryType(); + if (t != OGCMultiPoint.TYPE && t != OGCMultiPolygon.TYPE && t != OGCMultiLineString.TYPE) + return false; + + //check strict order of geometry dimensions + int d = g.dimension(); + if (d <= dimension) + return false; + + dimension = d; + } + + return true; + } + + /** + * Flattens Geometry Collection. + * The result collection contains up to three geometries: + * an OGCMultiPoint, an OGCMultilineString, and an OGCMultiPolygon (in that order). + * @return A flattened Geometry Collection, or self if already flattened. + */ + public OGCConcreteGeometryCollection flatten() { + if (isFlattened()) { + return this; + } + + OGCMultiPoint multiPoint = null; + ArrayList polygons = null; + OGCMultiLineString polyline = null; + GeometryCursor gc = getEsriGeometryCursor(); + for (Geometry g = gc.next(); g != null; g = gc.next()) { + if (g.isEmpty()) + continue; + + Geometry.Type t = g.getType(); + + if (t == Geometry.Type.Point) { + if (multiPoint == null) { + multiPoint = new OGCMultiPoint(esriSR); + } + + ((MultiPoint)multiPoint.getEsriGeometry()).add((Point)g); + continue; + } + + if (t == Geometry.Type.MultiPoint) { + if (multiPoint == null) + multiPoint = new OGCMultiPoint(esriSR); + + ((MultiPoint)multiPoint.getEsriGeometry()).add((MultiPoint)g, 0, -1); + continue; + } + + if (t == Geometry.Type.Polyline) { + if (polyline == null) + polyline = new OGCMultiLineString(esriSR); + + ((MultiPath)polyline.getEsriGeometry()).add((Polyline)g, false); + continue; + } + + if (t == Geometry.Type.Polygon) { + if (polygons == null) + polygons = new ArrayList(); + + polygons.add(g); + continue; + } + + throw new GeometryException("internal error");//what else? + } + + List list = new ArrayList(); + + if (multiPoint != null) + list.add(multiPoint); + + if (polyline != null) + list.add(polyline); + + if (polygons != null) { + GeometryCursor unionedPolygons = OperatorUnion.local().execute(new SimpleGeometryCursor(polygons), esriSR, null); + Geometry g = unionedPolygons.next(); + if (!g.isEmpty()) { + list.add(new OGCMultiPolygon((Polygon)g, esriSR)); + } + + } + + return new OGCConcreteGeometryCollection(list, esriSR); + } + + /** + * Fixes topological overlaps in the GeometryCollecion. + * This is equivalent to union of the geometry collection elements. + * + * TODO "flattened" collection is supposed to contain only mutli-geometries, but this method may return single geometries + * e.g. for GEOMETRYCOLLECTION (LINESTRING (...)) it returns GEOMETRYCOLLECTION (LINESTRING (...)) + * and not GEOMETRYCOLLECTION (MULTILINESTRING (...)) + * @return A geometry collection that is flattened and has no overlapping elements. + */ + public OGCConcreteGeometryCollection flattenAndRemoveOverlaps() { + + //flatten and crack/cluster + GeometryCursor cursor = OGCStructureInternal.prepare_for_ops_(flatten().getEsriGeometryCursor(), esriSR); + + //make sure geometries don't overlap + return new OGCConcreteGeometryCollection(removeOverlapsHelper_(toList(cursor)), esriSR); + } + + private GeometryCursor removeOverlapsHelper_(List geoms) { + List result = new ArrayList(); + for (int i = 0; i < geoms.size(); ++i) { + Geometry current = geoms.get(i); + if (current.isEmpty()) + continue; + + for (int j = i + 1; j < geoms.size(); ++j) { + Geometry subG = geoms.get(j); + current = OperatorDifference.local().execute(current, subG, esriSR, null); + if (current.isEmpty()) + break; + } + + if (current.isEmpty()) + continue; + + result.add(current); + } + + return new SimpleGeometryCursor(result); + } + + private static class FlatteningCollectionCursor extends GeometryCursor { + private List m_collections; + private GeometryCursor m_current; + private int m_index; + FlatteningCollectionCursor(List collections) { + m_collections = collections; + m_index = -1; + m_current = null; + } + + @Override + public Geometry next() { + while (m_collections != null) { + if (m_current != null) { + Geometry g = m_current.next(); + if (g == null) { + m_current = null; + continue; + } + + return g; + } + else { + m_index++; + if (m_index < m_collections.size()) { + m_current = m_collections.get(m_index).flatten().getEsriGeometryCursor(); + continue; + } + else { + m_collections = null; + m_index = -1; + } + } + } + + return null; + } + + @Override + public int getGeometryID() { + return m_index; + } + + }; + + //Collectively processes group of geometry collections (intersects all segments and clusters points). + //Flattens collections, removes overlaps. + //Once done, the result collections would work well for topological and relational operations. + private GeometryCursor prepare_for_ops_(OGCConcreteGeometryCollection collection) { + assert(collection != null && !collection.isEmpty()); + GeometryCursor prepared = OGCStructureInternal.prepare_for_ops_(collection.flatten().getEsriGeometryCursor(), esriSR); + return removeOverlapsHelper_(toList(prepared)); + } } diff --git a/src/main/java/com/esri/core/geometry/ogc/OGCCurve.java b/src/main/java/com/esri/core/geometry/ogc/OGCCurve.java index 9f421294..dd229e5e 100644 --- a/src/main/java/com/esri/core/geometry/ogc/OGCCurve.java +++ b/src/main/java/com/esri/core/geometry/ogc/OGCCurve.java @@ -27,24 +27,27 @@ import com.esri.core.geometry.MultiPoint; public abstract class OGCCurve extends OGCGeometry { - public abstract double length(); + public abstract double length(); - public abstract OGCPoint startPoint(); + public abstract OGCPoint startPoint(); - public abstract OGCPoint endPoint(); + public abstract OGCPoint endPoint(); - public abstract boolean isClosed(); + public abstract boolean isClosed(); - public boolean isRing() { - return isSimple() && isClosed(); - } + public boolean isRing() { + return isSimple() && isClosed(); + } - @Override - public OGCGeometry boundary() { - if (isClosed()) - return new OGCMultiPoint(new MultiPoint(getEsriGeometry() - .getDescription()), esriSR);// return empty multipoint; - else - return new OGCMultiPoint(startPoint(), endPoint()); - } + @Override + public OGCGeometry boundary() { + if (isEmpty()) + return new OGCMultiPoint(this.getEsriSpatialReference()); + + if (isClosed()) + return new OGCMultiPoint(new MultiPoint(getEsriGeometry() + .getDescription()), esriSR);// return empty multipoint; + else + return new OGCMultiPoint(startPoint(), endPoint()); + } } diff --git a/src/main/java/com/esri/core/geometry/ogc/OGCGeometry.java b/src/main/java/com/esri/core/geometry/ogc/OGCGeometry.java index d6ae9d23..17ef2f8f 100644 --- a/src/main/java/com/esri/core/geometry/ogc/OGCGeometry.java +++ b/src/main/java/com/esri/core/geometry/ogc/OGCGeometry.java @@ -38,6 +38,7 @@ import com.esri.core.geometry.OGCStructure; import com.esri.core.geometry.Operator; import com.esri.core.geometry.OperatorBuffer; +import com.esri.core.geometry.OperatorCentroid2D; import com.esri.core.geometry.OperatorConvexHull; import com.esri.core.geometry.OperatorExportToGeoJson; import com.esri.core.geometry.OperatorExportToWkb; @@ -51,6 +52,7 @@ import com.esri.core.geometry.OperatorSimplifyOGC; import com.esri.core.geometry.OperatorUnion; import com.esri.core.geometry.Point; +import com.esri.core.geometry.Point2D; import com.esri.core.geometry.Polygon; import com.esri.core.geometry.Polyline; import com.esri.core.geometry.SimpleGeometryCursor; @@ -58,31 +60,31 @@ import com.esri.core.geometry.VertexDescription; import java.nio.ByteBuffer; -import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Arrays; /** * OGC Simple Feature Access specification v.1.2.1 + * */ public abstract class OGCGeometry { - public int dimension() { - return getEsriGeometry().getDimension(); - } + public int dimension() { + return getEsriGeometry().getDimension(); + } - public int coordinateDimension() { - int d = 2; - if (getEsriGeometry().getDescription().hasAttribute( - VertexDescription.Semantics.M)) - d++; - if (getEsriGeometry().getDescription().hasAttribute( - VertexDescription.Semantics.Z)) - d++; + public int coordinateDimension() { + int d = 2; + if (getEsriGeometry().getDescription().hasAttribute( + VertexDescription.Semantics.M)) + d++; + if (getEsriGeometry().getDescription().hasAttribute( + VertexDescription.Semantics.Z)) + d++; - return d; - } + return d; + } - abstract public String geometryType(); + abstract public String geometryType(); /** * Returns an estimate of this object size in bytes. @@ -99,667 +101,755 @@ public int SRID() { if (esriSR == null) return 0; - return esriSR.getID(); - } - - public OGCGeometry envelope() { - com.esri.core.geometry.Envelope env = new com.esri.core.geometry.Envelope(); - getEsriGeometry().queryEnvelope(env); - com.esri.core.geometry.Polygon polygon = new com.esri.core.geometry.Polygon(); - polygon.addEnvelope(env, false); - return new OGCPolygon(polygon, esriSR); - } - - public String asText() { - return GeometryEngine.geometryToWkt(getEsriGeometry(), 0); - } - - public ByteBuffer asBinary() { - OperatorExportToWkb op = (OperatorExportToWkb) OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.ExportToWkb); - return op.execute(0, getEsriGeometry(), null); - } - - public String asGeoJson() { - OperatorExportToGeoJson op = (OperatorExportToGeoJson) OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.ExportToGeoJson); - return op.execute(esriSR, getEsriGeometry()); - } - - String asGeoJsonImpl(int export_flags) { - OperatorExportToGeoJson op = (OperatorExportToGeoJson) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ExportToGeoJson); - return op.execute(export_flags, esriSR, getEsriGeometry()); - } - - /** - * @return Convert to REST JSON. - */ - public String asJson() { - return GeometryEngine.geometryToJson(esriSR, getEsriGeometry()); - } - - - public boolean isEmpty() { - return getEsriGeometry().isEmpty(); - } - - public double MinZ() { - Envelope1D e = getEsriGeometry().queryInterval( - VertexDescription.Semantics.Z, 0); - return e.vmin; - } - - public double MaxZ() { - Envelope1D e = getEsriGeometry().queryInterval( - VertexDescription.Semantics.Z, 0); - return e.vmax; - } - - public double MinMeasure() { - Envelope1D e = getEsriGeometry().queryInterval( - VertexDescription.Semantics.M, 0); - return e.vmin; - } - - public double MaxMeasure() { - Envelope1D e = getEsriGeometry().queryInterval( - VertexDescription.Semantics.M, 0); - return e.vmax; - } - - /** - * Returns true if this geometric object has no anomalous geometric points, - * such as self intersection or self tangency. See the - * "Simple feature access - Part 1" document (OGC 06-103r4) for meaning of - * "simple" for each geometry type. - *

- * The method has O(n log n) complexity when the input geometry is simple. - * For non-simple geometries, it terminates immediately when the first issue - * is encountered. - * - * @return True if geometry is simple and false otherwise. - *

- * Note: If isSimple is true, then isSimpleRelaxed is true too. - */ - public boolean isSimple() { - return OperatorSimplifyOGC.local().isSimpleOGC(getEsriGeometry(), - esriSR, true, null, null); - } - - /** - * Extension method - checks if geometry is simple for Geodatabase. - * - * @return Returns true if geometry is simple, false otherwise. - *

- * Note: If isSimpleRelaxed is true, then isSimple is either true or false. Geodatabase has more relaxed requirements for simple geometries than OGC. - */ - public boolean isSimpleRelaxed() { - OperatorSimplify op = (OperatorSimplify) OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Simplify); - return op.isSimpleAsFeature(getEsriGeometry(), esriSR, true, null, null); - } - - @Deprecated - /** - * Use makeSimpleRelaxed instead. - */ - public OGCGeometry MakeSimpleRelaxed(boolean forceProcessing) { - return makeSimpleRelaxed(forceProcessing); - } - - /** - * Makes a simple geometry for Geodatabase. - * - * @return Returns simplified geometry. - *

- * Note: isSimpleRelaxed should return true after this operation. - */ - public OGCGeometry makeSimpleRelaxed(boolean forceProcessing) { - OperatorSimplify op = (OperatorSimplify) OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Simplify); - return OGCGeometry.createFromEsriGeometry( - op.execute(getEsriGeometry(), esriSR, forceProcessing, null), - esriSR); - } - - /** - * Resolves topological issues in this geometry and makes it Simple according to OGC specification. - * - * @return Returns simplified geometry. - *

- * Note: isSimple and isSimpleRelaxed should return true after this operation. - */ - public OGCGeometry makeSimple() { - return simplifyBunch_(getEsriGeometryCursor()); - } - - public boolean is3D() { - return getEsriGeometry().getDescription().hasAttribute( - VertexDescription.Semantics.Z); - } - - public boolean isMeasured() { - return getEsriGeometry().getDescription().hasAttribute( - VertexDescription.Semantics.M); - } - - abstract public OGCGeometry boundary(); - - /** - * OGC equals. Performs topological comparison with tolerance. - * This is different from equals(Object), that uses exact comparison. - */ - public boolean Equals(OGCGeometry another) { - if (this == another) - return true; - - if (another == null) - return false; - - com.esri.core.geometry.Geometry geom1 = getEsriGeometry(); - com.esri.core.geometry.Geometry geom2 = another.getEsriGeometry(); - return com.esri.core.geometry.GeometryEngine.equals(geom1, geom2, - getEsriSpatialReference()); - } - - @Deprecated - public boolean equals(OGCGeometry another) { - return Equals(another); - } - - public boolean disjoint(OGCGeometry another) { - com.esri.core.geometry.Geometry geom1 = getEsriGeometry(); - com.esri.core.geometry.Geometry geom2 = another.getEsriGeometry(); - return com.esri.core.geometry.GeometryEngine.disjoint(geom1, geom2, - getEsriSpatialReference()); - } - - public boolean intersects(OGCGeometry another) { - return !disjoint(another); - } - - public boolean touches(OGCGeometry another) { - com.esri.core.geometry.Geometry geom1 = getEsriGeometry(); - com.esri.core.geometry.Geometry geom2 = another.getEsriGeometry(); - return com.esri.core.geometry.GeometryEngine.touches(geom1, geom2, - getEsriSpatialReference()); - } - - public boolean crosses(OGCGeometry another) { - com.esri.core.geometry.Geometry geom1 = getEsriGeometry(); - com.esri.core.geometry.Geometry geom2 = another.getEsriGeometry(); - return com.esri.core.geometry.GeometryEngine.crosses(geom1, geom2, - getEsriSpatialReference()); - } - - public boolean within(OGCGeometry another) { - com.esri.core.geometry.Geometry geom1 = getEsriGeometry(); - com.esri.core.geometry.Geometry geom2 = another.getEsriGeometry(); - return com.esri.core.geometry.GeometryEngine.within(geom1, geom2, - getEsriSpatialReference()); - } - - public boolean contains(OGCGeometry another) { - com.esri.core.geometry.Geometry geom1 = getEsriGeometry(); - com.esri.core.geometry.Geometry geom2 = another.getEsriGeometry(); - return com.esri.core.geometry.GeometryEngine.contains(geom1, geom2, - getEsriSpatialReference()); - } - - public boolean overlaps(OGCGeometry another) { - com.esri.core.geometry.Geometry geom1 = getEsriGeometry(); - com.esri.core.geometry.Geometry geom2 = another.getEsriGeometry(); - return com.esri.core.geometry.GeometryEngine.overlaps(geom1, geom2, - getEsriSpatialReference()); - } - - public boolean relate(OGCGeometry another, String matrix) { - com.esri.core.geometry.Geometry geom1 = getEsriGeometry(); - com.esri.core.geometry.Geometry geom2 = another.getEsriGeometry(); - return com.esri.core.geometry.GeometryEngine.relate(geom1, geom2, - getEsriSpatialReference(), matrix); - } - - abstract public OGCGeometry locateAlong(double mValue); - - abstract public OGCGeometry locateBetween(double mStart, double mEnd); - - // analysis - public double distance(OGCGeometry another) { - com.esri.core.geometry.Geometry geom1 = getEsriGeometry(); - com.esri.core.geometry.Geometry geom2 = another.getEsriGeometry(); - return com.esri.core.geometry.GeometryEngine.distance(geom1, geom2, - getEsriSpatialReference()); - } - - // This method firstly groups geometries by dimension (points, lines, - // areas), - // then simplifies each group such that each group is reduced to a single - // geometry. - // As a result there are at most three geometries, each geometry is Simple. - // Afterwards - // it produces a single OGCGeometry. - private OGCGeometry simplifyBunch_(GeometryCursor gc) { - // Combines geometries into multipoint, polyline, and polygon types, - // simplifying them and unioning them, - // then produces OGCGeometry from the result. - // Can produce OGCConcreteGoemetryCollection - MultiPoint dstMultiPoint = null; - ArrayDeque dstPolylines = new ArrayDeque<>(); - ArrayDeque dstPolygons = new ArrayDeque<>(); - for (com.esri.core.geometry.Geometry g = gc.next(); g != null; g = gc - .next()) { - switch (g.getType()) { - case Point: - if (dstMultiPoint == null) - dstMultiPoint = new MultiPoint(); - dstMultiPoint.add((Point) g); - break; - case MultiPoint: - if (dstMultiPoint == null) - dstMultiPoint = new MultiPoint(); - dstMultiPoint.add((MultiPoint) g, 0, -1); - break; - case Polyline: - dstPolylines.add((Polyline) g.copy()); - break; - case Polygon: - dstPolygons.add((Polygon) g.copy()); - break; - default: - throw new UnsupportedOperationException(); - } - } - - ArrayDeque result = new ArrayDeque<>(3); - if (dstMultiPoint != null) { - Geometry resMP = OperatorSimplifyOGC.local().execute(dstMultiPoint, - esriSR, true, null); - result.add(resMP); - } - - if (dstPolylines.size() > 0) { - if (dstPolylines.size() == 1) { - Geometry resMP = OperatorSimplifyOGC.local().execute(dstPolylines.pop(), esriSR, true, null); - result.add(resMP); - } else { - GeometryCursor res = OperatorUnion.local().execute(new SimpleGeometryCursor(dstPolylines), esriSR, null); - Geometry resPolyline = res.next(); - Geometry resMP = OperatorSimplifyOGC.local().execute( - resPolyline, esriSR, true, null); - result.add(resMP); - } - } - - if (dstPolygons.size() > 0) { - if (dstPolygons.size() == 1) { - Geometry resMP = OperatorSimplifyOGC.local().execute(dstPolygons.pop(), esriSR, true, null); - result.add(resMP); - } else { - GeometryCursor res = OperatorUnion.local().execute(new SimpleGeometryCursor(dstPolygons), esriSR, null); - Geometry resPolygon = res.next(); - Geometry resMP = OperatorSimplifyOGC.local().execute( - resPolygon, esriSR, true, null); - result.add(resMP); - } - } - - return OGCGeometry.createFromEsriCursor(new SimpleGeometryCursor(result), esriSR); - } - - public OGCGeometry buffer(double distance) { - OperatorBuffer op = (OperatorBuffer) OperatorFactoryLocal.getInstance() - .getOperator(Operator.Type.Buffer); - if (distance == 0) {// when distance is 0, return self (maybe we should - // create a copy instead). - return this; - } - - double d[] = {distance}; - com.esri.core.geometry.GeometryCursor cursor = op.execute( - getEsriGeometryCursor(), getEsriSpatialReference(), d, true, - null); - return OGCGeometry.createFromEsriGeometry(cursor.next(), esriSR); - } - - public OGCGeometry convexHull() { - com.esri.core.geometry.OperatorConvexHull op = (OperatorConvexHull) OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.ConvexHull); - com.esri.core.geometry.GeometryCursor cursor = op.execute( - getEsriGeometryCursor(), true, null); - return OGCGeometry.createFromEsriCursor(cursor, esriSR); - } - - public OGCGeometry intersection(OGCGeometry another) { - com.esri.core.geometry.OperatorIntersection op = (OperatorIntersection) OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Intersection); - com.esri.core.geometry.GeometryCursor cursor = op.execute( - getEsriGeometryCursor(), another.getEsriGeometryCursor(), - getEsriSpatialReference(), null, 7); - return OGCGeometry.createFromEsriCursor(cursor, esriSR, true); - } - - public OGCGeometry union(OGCGeometry another) { - OperatorUnion op = (OperatorUnion) OperatorFactoryLocal.getInstance() - .getOperator(Operator.Type.Union); - GeometryCursorAppend ap = new GeometryCursorAppend( - getEsriGeometryCursor(), another.getEsriGeometryCursor()); - com.esri.core.geometry.GeometryCursor cursor = op.execute(ap, - getEsriSpatialReference(), null); - return OGCGeometry.createFromEsriCursor(cursor, esriSR); - } - - public OGCGeometry difference(OGCGeometry another) { - com.esri.core.geometry.Geometry geom1 = getEsriGeometry(); - com.esri.core.geometry.Geometry geom2 = another.getEsriGeometry(); - return createFromEsriGeometry( - com.esri.core.geometry.GeometryEngine.difference(geom1, geom2, - getEsriSpatialReference()), esriSR); - } - - public OGCGeometry symDifference(OGCGeometry another) { - com.esri.core.geometry.Geometry geom1 = getEsriGeometry(); - com.esri.core.geometry.Geometry geom2 = another.getEsriGeometry(); - return createFromEsriGeometry( - com.esri.core.geometry.GeometryEngine.symmetricDifference( - geom1, geom2, getEsriSpatialReference()), esriSR); - } - - public abstract com.esri.core.geometry.Geometry getEsriGeometry(); - - public GeometryCursor getEsriGeometryCursor() { - return new SimpleGeometryCursor(getEsriGeometry()); - } - - public com.esri.core.geometry.SpatialReference getEsriSpatialReference() { - return esriSR; - } - - /** - * Create an OGCGeometry instance from the GeometryCursor. - * - * @param gc - * @param sr - * @return Geometry instance created from the geometry cursor. - */ - public static OGCGeometry createFromEsriCursor(GeometryCursor gc, - SpatialReference sr) { - return createFromEsriCursor(gc, sr, false); - } - - public static OGCGeometry createFromEsriCursor(GeometryCursor gc, - SpatialReference sr, boolean skipEmpty) { - ArrayList geoms = new ArrayList(10); - Geometry emptyGeom = null; - for (Geometry g = gc.next(); g != null; g = gc.next()) { - emptyGeom = g; - if (!skipEmpty || !g.isEmpty()) - geoms.add(createFromEsriGeometry(g, sr)); - } - - if (geoms.size() == 1) { - return geoms.get(0); - } else if (geoms.size() == 0) - return createFromEsriGeometry(emptyGeom, sr); - else - return new OGCConcreteGeometryCollection(geoms, sr); - } - - public static OGCGeometry fromText(String text) { - OperatorImportFromWkt op = (OperatorImportFromWkt) OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.ImportFromWkt); - OGCStructure ogcStructure = op.executeOGC(0, text, null); - return OGCGeometry.createFromOGCStructure(ogcStructure, - SpatialReference.create(4326)); - } - - public static OGCGeometry fromBinary(ByteBuffer binary) { - OperatorImportFromWkb op = (OperatorImportFromWkb) OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.ImportFromWkb); - OGCStructure ogcStructure = op.executeOGC(0, binary, null); - return OGCGeometry.createFromOGCStructure(ogcStructure, - SpatialReference.create(4326)); - } - - public static OGCGeometry fromEsriShape(ByteBuffer buffer) { - OperatorImportFromESRIShape op = (OperatorImportFromESRIShape) OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.ImportFromESRIShape); - Geometry g = op.execute(0, Geometry.Type.Unknown, buffer); - return OGCGeometry.createFromEsriGeometry(g, - SpatialReference.create(4326)); - } - - public static OGCGeometry fromJson(String string) { - MapGeometry mapGeom = GeometryEngine.jsonToGeometry(JsonParserReader.createFromString(string)); - return OGCGeometry.createFromEsriGeometry(mapGeom.getGeometry(), - mapGeom.getSpatialReference()); - } - - public static OGCGeometry fromGeoJson(String string) { - OperatorImportFromGeoJson op = (OperatorImportFromGeoJson) OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.ImportFromGeoJson); - MapOGCStructure mapOGCStructure = op.executeOGC(0, string, null); - return OGCGeometry.createFromOGCStructure( - mapOGCStructure.m_ogcStructure, - mapOGCStructure.m_spatialReference); - } - - public static OGCGeometry createFromEsriGeometry(Geometry geom, - SpatialReference sr) { - return createFromEsriGeometry(geom, sr, false); - } - - public static OGCGeometry createFromEsriGeometry(Geometry geom, - SpatialReference sr, boolean multiType) { - if (geom == null) - return null; - Geometry.Type t = geom.getType(); - if (t == Geometry.Type.Polygon) { - if (!multiType && ((Polygon) geom).getExteriorRingCount() == 1) - return new OGCPolygon((Polygon) geom, sr); - else - return new OGCMultiPolygon((Polygon) geom, sr); - } - if (t == Geometry.Type.Polyline) { - if (!multiType && ((Polyline) geom).getPathCount() == 1) - return new OGCLineString((Polyline) geom, 0, sr); - else - return new OGCMultiLineString((Polyline) geom, sr); - } - if (t == Geometry.Type.MultiPoint) { - if (!multiType && ((MultiPoint) geom).getPointCount() <= 1) { - if (geom.isEmpty()) - return new OGCPoint(new Point(), sr); - else - return new OGCPoint(((MultiPoint) geom).getPoint(0), sr); - } else - return new OGCMultiPoint((MultiPoint) geom, sr); - } - if (t == Geometry.Type.Point) { - if (!multiType) { - return new OGCPoint((Point) geom, sr); - } else { - return new OGCMultiPoint((Point) geom, sr); - } - } - if (t == Geometry.Type.Envelope) { - Polygon p = new Polygon(); - p.addEnvelope((Envelope) geom, false); - return createFromEsriGeometry(p, sr, multiType); - } - - throw new UnsupportedOperationException(); - } - - public static OGCGeometry createFromOGCStructure(OGCStructure ogcStructure, - SpatialReference sr) { - ArrayList collectionStack = new ArrayList( - 0); - ArrayList structureStack = new ArrayList(0); - ArrayList indices = new ArrayList(0); - - OGCGeometry[] geometries = new OGCGeometry[1]; - OGCConcreteGeometryCollection root = new OGCConcreteGeometryCollection( - Arrays.asList(geometries), sr); - - structureStack.add(ogcStructure); - collectionStack.add(root); - indices.add(0); - - while (!structureStack.isEmpty()) { - OGCStructure lastStructure = structureStack.get(structureStack - .size() - 1); - if (indices.get(indices.size() - 1) == lastStructure.m_structures - .size()) { - structureStack.remove(structureStack.size() - 1); - collectionStack.remove(collectionStack.size() - 1); - indices.remove(indices.size() - 1); - continue; - } - - OGCConcreteGeometryCollection lastCollection = collectionStack - .get(collectionStack.size() - 1); - OGCGeometry g; - int i = indices.get(indices.size() - 1); - - int type = lastStructure.m_structures.get(i).m_type; - - switch (type) { - case 1: - g = new OGCPoint( - (Point) lastStructure.m_structures.get(i).m_geometry, - sr); - lastCollection.geometries.set(i, g); - indices.set(indices.size() - 1, i + 1); - break; - case 2: - g = new OGCLineString( - (Polyline) lastStructure.m_structures.get(i).m_geometry, - 0, sr); - lastCollection.geometries.set(i, g); - indices.set(indices.size() - 1, i + 1); - break; - case 3: - g = new OGCPolygon( - (Polygon) lastStructure.m_structures.get(i).m_geometry, - 0, sr); - lastCollection.geometries.set(i, g); - indices.set(indices.size() - 1, i + 1); - break; - case 4: - g = new OGCMultiPoint( - (MultiPoint) lastStructure.m_structures.get(i).m_geometry, - sr); - lastCollection.geometries.set(i, g); - indices.set(indices.size() - 1, i + 1); - break; - case 5: - g = new OGCMultiLineString( - (Polyline) lastStructure.m_structures.get(i).m_geometry, - sr); - lastCollection.geometries.set(i, g); - indices.set(indices.size() - 1, i + 1); - break; - case 6: - g = new OGCMultiPolygon( - (Polygon) lastStructure.m_structures.get(i).m_geometry, - sr); - lastCollection.geometries.set(i, g); - indices.set(indices.size() - 1, i + 1); - break; - case 7: - geometries = new OGCGeometry[lastStructure.m_structures.get(i).m_structures - .size()]; - g = new OGCConcreteGeometryCollection( - Arrays.asList(geometries), sr); - lastCollection.geometries.set(i, g); - indices.set(indices.size() - 1, i + 1); - structureStack.add(lastStructure.m_structures.get(i)); - collectionStack.add((OGCConcreteGeometryCollection) g); - indices.add(0); - break; - default: - throw new UnsupportedOperationException(); - } - } - - return root.geometries.get(0); - } - - protected boolean isConcreteGeometryCollection() { - return false; - } - - /** - * SpatialReference of the Geometry. - */ - public com.esri.core.geometry.SpatialReference esriSR; - - public void setSpatialReference(SpatialReference esriSR_) { - esriSR = esriSR_; - } - - /** - * Converts this Geometry to the OGCMulti* if it is not OGCMulti* or - * OGCGeometryCollection already. - * - * @return OGCMulti* or OGCGeometryCollection instance. - */ - public abstract OGCGeometry convertToMulti(); - - @Override - public String toString() { - String snippet = asText(); - if (snippet.length() > 200) { - snippet = snippet.substring(0, 197) + "..."; - } - return String - .format("%s: %s", this.getClass().getSimpleName(), snippet); - } - - @Override - public boolean equals(Object other) { - if (other == null) - return false; - - if (other == this) - return true; - - if (other.getClass() != getClass()) - return false; - - OGCGeometry another = (OGCGeometry) other; - com.esri.core.geometry.Geometry geom1 = getEsriGeometry(); - com.esri.core.geometry.Geometry geom2 = another.getEsriGeometry(); - - if (geom1 == null) { - if (geom2 != null) - return false; - } else if (!geom1.equals(geom2)) { - return false; - } - - if (esriSR == another.esriSR) { - return true; - } - - if (esriSR != null && another.esriSR != null) { - return esriSR.equals(another.esriSR); - } - - return false; - } - - @Override - public int hashCode() { - int hash = 1; - com.esri.core.geometry.Geometry geom1 = getEsriGeometry(); - if (geom1 != null) - hash = geom1.hashCode(); - - if (esriSR != null) - hash = NumberUtils.hashCombine(hash, esriSR.hashCode()); - - return hash; - } + return esriSR.getID(); + } + + public OGCGeometry envelope() { + com.esri.core.geometry.Envelope env = new com.esri.core.geometry.Envelope(); + getEsriGeometry().queryEnvelope(env); + com.esri.core.geometry.Polygon polygon = new com.esri.core.geometry.Polygon(); + polygon.addEnvelope(env, false); + return new OGCPolygon(polygon, esriSR); + } + + public String asText() { + return GeometryEngine.geometryToWkt(getEsriGeometry(), 0); + } + + public ByteBuffer asBinary() { + OperatorExportToWkb op = (OperatorExportToWkb) OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.ExportToWkb); + return op.execute(0, getEsriGeometry(), null); + } + + public String asGeoJson() { + OperatorExportToGeoJson op = (OperatorExportToGeoJson) OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.ExportToGeoJson); + return op.execute(esriSR, getEsriGeometry()); + } + + String asGeoJsonImpl(int export_flags) { + OperatorExportToGeoJson op = (OperatorExportToGeoJson) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ExportToGeoJson); + return op.execute(export_flags, esriSR, getEsriGeometry()); + } + + /** + * + * @return Convert to REST JSON. + */ + public String asJson() { + return GeometryEngine.geometryToJson(esriSR, getEsriGeometry()); + } + + + public boolean isEmpty() { + return getEsriGeometry().isEmpty(); + } + + public double MinZ() { + Envelope1D e = getEsriGeometry().queryInterval( + VertexDescription.Semantics.Z, 0); + return e.vmin; + } + + public double MaxZ() { + Envelope1D e = getEsriGeometry().queryInterval( + VertexDescription.Semantics.Z, 0); + return e.vmax; + } + + public double MinMeasure() { + Envelope1D e = getEsriGeometry().queryInterval( + VertexDescription.Semantics.M, 0); + return e.vmin; + } + + public double MaxMeasure() { + Envelope1D e = getEsriGeometry().queryInterval( + VertexDescription.Semantics.M, 0); + return e.vmax; + } + + /** + * Returns true if this geometric object has no anomalous geometric points, + * such as self intersection or self tangency. See the + * "Simple feature access - Part 1" document (OGC 06-103r4) for meaning of + * "simple" for each geometry type. + * + * The method has O(n log n) complexity when the input geometry is simple. + * For non-simple geometries, it terminates immediately when the first issue + * is encountered. + * + * @return True if geometry is simple and false otherwise. + * + * Note: If isSimple is true, then isSimpleRelaxed is true too. + */ + public boolean isSimple() { + return OperatorSimplifyOGC.local().isSimpleOGC(getEsriGeometry(), + esriSR, true, null, null); + } + + /** + * Extension method - checks if geometry is simple for Geodatabase. + * + * @return Returns true if geometry is simple, false otherwise. + * + * Note: If isSimpleRelaxed is true, then isSimple is either true or false. Geodatabase has more relaxed requirements for simple geometries than OGC. + */ + public boolean isSimpleRelaxed() { + OperatorSimplify op = (OperatorSimplify) OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Simplify); + return op.isSimpleAsFeature(getEsriGeometry(), esriSR, true, null, null); + } + + @Deprecated + /** + * Use makeSimpleRelaxed instead. + */ + public OGCGeometry MakeSimpleRelaxed(boolean forceProcessing) { + return makeSimpleRelaxed(forceProcessing); + } + /** + * Makes a simple geometry for Geodatabase. + * + * @return Returns simplified geometry. + * + * Note: isSimpleRelaxed should return true after this operation. + */ + public OGCGeometry makeSimpleRelaxed(boolean forceProcessing) { + OperatorSimplify op = (OperatorSimplify) OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Simplify); + return OGCGeometry.createFromEsriGeometry( + op.execute(getEsriGeometry(), esriSR, forceProcessing, null), + esriSR); + } + + /** + * Resolves topological issues in this geometry and makes it Simple according to OGC specification. + * + * @return Returns simplified geometry. + * + * Note: isSimple and isSimpleRelaxed should return true after this operation. + */ + public OGCGeometry makeSimple() { + return simplifyBunch_(getEsriGeometryCursor()); + } + + public boolean is3D() { + return getEsriGeometry().getDescription().hasAttribute( + VertexDescription.Semantics.Z); + } + + public boolean isMeasured() { + return getEsriGeometry().getDescription().hasAttribute( + VertexDescription.Semantics.M); + } + + abstract public OGCGeometry boundary(); + + /** + * OGC equals. Performs topological comparison with tolerance. + * This is different from equals(Object), that uses exact comparison. + */ + public boolean Equals(OGCGeometry another) { + if (this == another) + return !isEmpty(); + + if (another == null) + return false; + + if (another.geometryType() == OGCConcreteGeometryCollection.TYPE) { + return another.Equals(this); + } + + com.esri.core.geometry.Geometry geom1 = getEsriGeometry(); + com.esri.core.geometry.Geometry geom2 = another.getEsriGeometry(); + return com.esri.core.geometry.GeometryEngine.equals(geom1, geom2, + getEsriSpatialReference()); + } + + @Deprecated + public boolean equals(OGCGeometry another) { + return Equals(another); + } + + public boolean disjoint(OGCGeometry another) { + if (another.geometryType() == OGCConcreteGeometryCollection.TYPE) { + return another.disjoint(this); + } + + com.esri.core.geometry.Geometry geom1 = getEsriGeometry(); + com.esri.core.geometry.Geometry geom2 = another.getEsriGeometry(); + return com.esri.core.geometry.GeometryEngine.disjoint(geom1, geom2, + getEsriSpatialReference()); + } + + public boolean intersects(OGCGeometry another) { + return !disjoint(another); + } + + public boolean touches(OGCGeometry another) { + if (another.geometryType() == OGCConcreteGeometryCollection.TYPE) { + //TODO + throw new UnsupportedOperationException(); + } + + com.esri.core.geometry.Geometry geom1 = getEsriGeometry(); + com.esri.core.geometry.Geometry geom2 = another.getEsriGeometry(); + return com.esri.core.geometry.GeometryEngine.touches(geom1, geom2, + getEsriSpatialReference()); + } + + public boolean crosses(OGCGeometry another) { + if (another.geometryType() == OGCConcreteGeometryCollection.TYPE) { + //TODO + throw new UnsupportedOperationException(); + } + + com.esri.core.geometry.Geometry geom1 = getEsriGeometry(); + com.esri.core.geometry.Geometry geom2 = another.getEsriGeometry(); + return com.esri.core.geometry.GeometryEngine.crosses(geom1, geom2, + getEsriSpatialReference()); + } + + public boolean within(OGCGeometry another) { + return another.contains(this); + } + + public boolean contains(OGCGeometry another) { + if (another.geometryType() == OGCConcreteGeometryCollection.TYPE) { + return new OGCConcreteGeometryCollection(this, esriSR).contains(another); + } + + com.esri.core.geometry.Geometry geom1 = getEsriGeometry(); + com.esri.core.geometry.Geometry geom2 = another.getEsriGeometry(); + return com.esri.core.geometry.GeometryEngine.contains(geom1, geom2, + getEsriSpatialReference()); + } + + public boolean overlaps(OGCGeometry another) { + if (another.geometryType() == OGCConcreteGeometryCollection.TYPE) { + // TODO + throw new UnsupportedOperationException(); + } + + com.esri.core.geometry.Geometry geom1 = getEsriGeometry(); + com.esri.core.geometry.Geometry geom2 = another.getEsriGeometry(); + return com.esri.core.geometry.GeometryEngine.overlaps(geom1, geom2, + getEsriSpatialReference()); + } + + public boolean relate(OGCGeometry another, String matrix) { + if (another.geometryType() == OGCConcreteGeometryCollection.TYPE) { + //TODO + throw new UnsupportedOperationException(); + } + + com.esri.core.geometry.Geometry geom1 = getEsriGeometry(); + com.esri.core.geometry.Geometry geom2 = another.getEsriGeometry(); + return com.esri.core.geometry.GeometryEngine.relate(geom1, geom2, + getEsriSpatialReference(), matrix); + } + + abstract public OGCGeometry locateAlong(double mValue); + + abstract public OGCGeometry locateBetween(double mStart, double mEnd); + + // analysis + public double distance(OGCGeometry another) { + if (this == another) { + return isEmpty() ? Double.NaN : 0; + } + + if (another.geometryType() == OGCConcreteGeometryCollection.TYPE) { + return another.distance(this); + } + + com.esri.core.geometry.Geometry geom1 = getEsriGeometry(); + com.esri.core.geometry.Geometry geom2 = another.getEsriGeometry(); + return com.esri.core.geometry.GeometryEngine.distance(geom1, geom2, + getEsriSpatialReference()); + } + + // This method firstly groups geometries by dimension (points, lines, + // areas), + // then simplifies each group such that each group is reduced to a single + // geometry. + // As a result there are at most three geometries, each geometry is Simple. + // Afterwards + // it produces a single OGCGeometry. + private OGCGeometry simplifyBunch_(GeometryCursor gc) { + // Combines geometries into multipoint, polyline, and polygon types, + // simplifying them and unioning them, + // then produces OGCGeometry from the result. + // Can produce OGCConcreteGoemetryCollection + MultiPoint dstMultiPoint = null; + ArrayList dstPolylines = new ArrayList(); + ArrayList dstPolygons = new ArrayList(); + for (com.esri.core.geometry.Geometry g = gc.next(); g != null; g = gc + .next()) { + switch (g.getType()) { + case Point: + if (dstMultiPoint == null) + dstMultiPoint = new MultiPoint(); + dstMultiPoint.add((Point) g); + break; + case MultiPoint: + if (dstMultiPoint == null) + dstMultiPoint = new MultiPoint(); + dstMultiPoint.add((MultiPoint) g, 0, -1); + break; + case Polyline: + dstPolylines.add((Polyline) g.copy()); + break; + case Polygon: + dstPolygons.add((Polygon) g.copy()); + break; + default: + throw new UnsupportedOperationException(); + } + } + + ArrayList result = new ArrayList(3); + if (dstMultiPoint != null) { + Geometry resMP = OperatorSimplifyOGC.local().execute(dstMultiPoint, + esriSR, true, null); + result.add(resMP); + } + + if (dstPolylines.size() > 0) { + if (dstPolylines.size() == 1) { + Geometry resMP = OperatorSimplifyOGC.local().execute( + dstPolylines.get(0), esriSR, true, null); + result.add(resMP); + } else { + GeometryCursor res = OperatorUnion.local().execute( + new SimpleGeometryCursor(dstPolylines), esriSR, null); + Geometry resPolyline = res.next(); + Geometry resMP = OperatorSimplifyOGC.local().execute( + resPolyline, esriSR, true, null); + result.add(resMP); + } + } + + if (dstPolygons.size() > 0) { + if (dstPolygons.size() == 1) { + Geometry resMP = OperatorSimplifyOGC.local().execute( + dstPolygons.get(0), esriSR, true, null); + result.add(resMP); + } else { + GeometryCursor res = OperatorUnion.local().execute( + new SimpleGeometryCursor(dstPolygons), esriSR, null); + Geometry resPolygon = res.next(); + Geometry resMP = OperatorSimplifyOGC.local().execute( + resPolygon, esriSR, true, null); + result.add(resMP); + } + } + + return OGCGeometry.createFromEsriCursor( + new SimpleGeometryCursor(result), esriSR); + } + + public OGCGeometry buffer(double distance) { + OperatorBuffer op = (OperatorBuffer) OperatorFactoryLocal.getInstance() + .getOperator(Operator.Type.Buffer); + if (distance == 0) {// when distance is 0, return self (maybe we should + // create a copy instead). + return this; + } + + double d[] = { distance }; + com.esri.core.geometry.GeometryCursor cursor = op.execute( + getEsriGeometryCursor(), getEsriSpatialReference(), d, true, + null); + return OGCGeometry.createFromEsriGeometry(cursor.next(), esriSR); + } + + public OGCGeometry centroid() { + OperatorCentroid2D op = (OperatorCentroid2D) OperatorFactoryLocal.getInstance() + .getOperator(Operator.Type.Centroid2D); + + Point2D centroid = op.execute(getEsriGeometry(), null); + if (centroid == null) { + return OGCGeometry.createFromEsriGeometry(new Point(), esriSR); + } + return OGCGeometry.createFromEsriGeometry(new Point(centroid), esriSR); + } + + public OGCGeometry convexHull() { + com.esri.core.geometry.GeometryCursor cursor = OperatorConvexHull.local().execute( + getEsriGeometryCursor(), false, null); + return OGCGeometry.createFromEsriCursor(cursor, esriSR); + } + + public OGCGeometry intersection(OGCGeometry another) { + if (another.geometryType() == OGCConcreteGeometryCollection.TYPE) { + return (new OGCConcreteGeometryCollection(this, esriSR)).intersection(another); + } + + com.esri.core.geometry.OperatorIntersection op = (OperatorIntersection) OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Intersection); + com.esri.core.geometry.GeometryCursor cursor = op.execute( + getEsriGeometryCursor(), another.getEsriGeometryCursor(), + getEsriSpatialReference(), null, 7); + return OGCGeometry.createFromEsriCursor(cursor, esriSR, true); + } + + public OGCGeometry union(OGCGeometry another) { + String thisType = geometryType(); + String anotherType = another.geometryType(); + if (thisType != anotherType || thisType == OGCConcreteGeometryCollection.TYPE) { + //heterogeneous union. + //We make a geometry collection, then process to union parts and remove overlaps. + ArrayList geoms = new ArrayList(); + geoms.add(this); + geoms.add(another); + OGCConcreteGeometryCollection geomCol = new OGCConcreteGeometryCollection(geoms, esriSR); + return geomCol.flattenAndRemoveOverlaps().reduceFromMulti(); + } + + OperatorUnion op = (OperatorUnion) OperatorFactoryLocal.getInstance() + .getOperator(Operator.Type.Union); + GeometryCursorAppend ap = new GeometryCursorAppend( + getEsriGeometryCursor(), another.getEsriGeometryCursor()); + com.esri.core.geometry.GeometryCursor cursor = op.execute(ap, + getEsriSpatialReference(), null); + return OGCGeometry.createFromEsriCursor(cursor, esriSR); + } + + public OGCGeometry difference(OGCGeometry another) { + if (another.geometryType() == OGCConcreteGeometryCollection.TYPE) { + return (new OGCConcreteGeometryCollection(this, esriSR)).difference(another); + } + + com.esri.core.geometry.Geometry geom1 = getEsriGeometry(); + com.esri.core.geometry.Geometry geom2 = another.getEsriGeometry(); + return createFromEsriGeometry( + com.esri.core.geometry.GeometryEngine.difference(geom1, geom2, + getEsriSpatialReference()), esriSR); + } + + public OGCGeometry symDifference(OGCGeometry another) { + if (another.geometryType() == OGCConcreteGeometryCollection.TYPE) { + // TODO + throw new UnsupportedOperationException(); + } + + com.esri.core.geometry.Geometry geom1 = getEsriGeometry(); + com.esri.core.geometry.Geometry geom2 = another.getEsriGeometry(); + return createFromEsriGeometry( + com.esri.core.geometry.GeometryEngine.symmetricDifference( + geom1, geom2, getEsriSpatialReference()), esriSR); + } + + public abstract com.esri.core.geometry.Geometry getEsriGeometry(); + + public GeometryCursor getEsriGeometryCursor() { + return new SimpleGeometryCursor(getEsriGeometry()); + } + + public com.esri.core.geometry.SpatialReference getEsriSpatialReference() { + return esriSR; + } + + /** + * Create an OGCGeometry instance from the GeometryCursor. + * + * @param gc + * @param sr + * @return Geometry instance created from the geometry cursor. + */ + public static OGCGeometry createFromEsriCursor(GeometryCursor gc, + SpatialReference sr) { + return createFromEsriCursor(gc, sr, false); + } + + public static OGCGeometry createFromEsriCursor(GeometryCursor gc, + SpatialReference sr, boolean skipEmpty) { + ArrayList geoms = new ArrayList(10); + Geometry emptyGeom = null; + for (Geometry g = gc.next(); g != null; g = gc.next()) { + emptyGeom = g; + if (!skipEmpty || !g.isEmpty()) + geoms.add(createFromEsriGeometry(g, sr)); + } + + if (geoms.size() == 1) { + return geoms.get(0); + } else if (geoms.size() == 0) + return createFromEsriGeometry(emptyGeom, sr); + else + return new OGCConcreteGeometryCollection(geoms, sr); + } + + public static OGCGeometry fromText(String text) { + OperatorImportFromWkt op = (OperatorImportFromWkt) OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.ImportFromWkt); + OGCStructure ogcStructure = op.executeOGC(0, text, null); + return OGCGeometry.createFromOGCStructure(ogcStructure, + SpatialReference.create(4326)); + } + + public static OGCGeometry fromBinary(ByteBuffer binary) { + OperatorImportFromWkb op = (OperatorImportFromWkb) OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.ImportFromWkb); + OGCStructure ogcStructure = op.executeOGC(0, binary, null); + return OGCGeometry.createFromOGCStructure(ogcStructure, + SpatialReference.create(4326)); + } + + public static OGCGeometry fromEsriShape(ByteBuffer buffer) { + OperatorImportFromESRIShape op = (OperatorImportFromESRIShape) OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.ImportFromESRIShape); + Geometry g = op.execute(0, Geometry.Type.Unknown, buffer); + return OGCGeometry.createFromEsriGeometry(g, + SpatialReference.create(4326)); + } + + public static OGCGeometry fromJson(String string) { + MapGeometry mapGeom = GeometryEngine.jsonToGeometry(JsonParserReader.createFromString(string)); + return OGCGeometry.createFromEsriGeometry(mapGeom.getGeometry(), + mapGeom.getSpatialReference()); + } + + public static OGCGeometry fromGeoJson(String string) { + OperatorImportFromGeoJson op = (OperatorImportFromGeoJson) OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.ImportFromGeoJson); + MapOGCStructure mapOGCStructure = op.executeOGC(0, string, null); + return OGCGeometry.createFromOGCStructure( + mapOGCStructure.m_ogcStructure, + mapOGCStructure.m_spatialReference); + } + + public static OGCGeometry createFromEsriGeometry(Geometry geom, + SpatialReference sr) { + return createFromEsriGeometry(geom, sr, false); + } + + public static OGCGeometry createFromEsriGeometry(Geometry geom, + SpatialReference sr, boolean multiType) { + if (geom == null) + return null; + Geometry.Type t = geom.getType(); + if (t == Geometry.Type.Polygon) { + if (!multiType && ((Polygon) geom).getExteriorRingCount() == 1) + return new OGCPolygon((Polygon) geom, sr); + else + return new OGCMultiPolygon((Polygon) geom, sr); + } + if (t == Geometry.Type.Polyline) { + if (!multiType && ((Polyline) geom).getPathCount() == 1) + return new OGCLineString((Polyline) geom, 0, sr); + else + return new OGCMultiLineString((Polyline) geom, sr); + } + if (t == Geometry.Type.MultiPoint) { + if (!multiType && ((MultiPoint) geom).getPointCount() <= 1) { + if (geom.isEmpty()) + return new OGCPoint(new Point(), sr); + else + return new OGCPoint(((MultiPoint) geom).getPoint(0), sr); + } else + return new OGCMultiPoint((MultiPoint) geom, sr); + } + if (t == Geometry.Type.Point) { + if (!multiType) { + return new OGCPoint((Point) geom, sr); + } else { + return new OGCMultiPoint((Point) geom, sr); + } + } + if (t == Geometry.Type.Envelope) { + Polygon p = new Polygon(); + p.addEnvelope((Envelope) geom, false); + return createFromEsriGeometry(p, sr, multiType); + } + + throw new UnsupportedOperationException(); + } + + public static OGCGeometry createFromOGCStructure(OGCStructure ogcStructure, + SpatialReference sr) { + ArrayList collectionStack = new ArrayList( + 0); + ArrayList structureStack = new ArrayList(0); + ArrayList indices = new ArrayList(0); + + OGCGeometry[] geometries = new OGCGeometry[1]; + OGCConcreteGeometryCollection root = new OGCConcreteGeometryCollection( + Arrays.asList(geometries), sr); + + structureStack.add(ogcStructure); + collectionStack.add(root); + indices.add(0); + + while (!structureStack.isEmpty()) { + OGCStructure lastStructure = structureStack.get(structureStack + .size() - 1); + if (indices.get(indices.size() - 1) == lastStructure.m_structures + .size()) { + structureStack.remove(structureStack.size() - 1); + collectionStack.remove(collectionStack.size() - 1); + indices.remove(indices.size() - 1); + continue; + } + + OGCConcreteGeometryCollection lastCollection = collectionStack + .get(collectionStack.size() - 1); + OGCGeometry g; + int i = indices.get(indices.size() - 1); + + int type = lastStructure.m_structures.get(i).m_type; + + switch (type) { + case 1: + g = new OGCPoint( + (Point) lastStructure.m_structures.get(i).m_geometry, + sr); + lastCollection.geometries.set(i, g); + indices.set(indices.size() - 1, i + 1); + break; + case 2: + g = new OGCLineString( + (Polyline) lastStructure.m_structures.get(i).m_geometry, + 0, sr); + lastCollection.geometries.set(i, g); + indices.set(indices.size() - 1, i + 1); + break; + case 3: + g = new OGCPolygon( + (Polygon) lastStructure.m_structures.get(i).m_geometry, + 0, sr); + lastCollection.geometries.set(i, g); + indices.set(indices.size() - 1, i + 1); + break; + case 4: + g = new OGCMultiPoint( + (MultiPoint) lastStructure.m_structures.get(i).m_geometry, + sr); + lastCollection.geometries.set(i, g); + indices.set(indices.size() - 1, i + 1); + break; + case 5: + g = new OGCMultiLineString( + (Polyline) lastStructure.m_structures.get(i).m_geometry, + sr); + lastCollection.geometries.set(i, g); + indices.set(indices.size() - 1, i + 1); + break; + case 6: + g = new OGCMultiPolygon( + (Polygon) lastStructure.m_structures.get(i).m_geometry, + sr); + lastCollection.geometries.set(i, g); + indices.set(indices.size() - 1, i + 1); + break; + case 7: + geometries = new OGCGeometry[lastStructure.m_structures.get(i).m_structures + .size()]; + g = new OGCConcreteGeometryCollection( + Arrays.asList(geometries), sr); + lastCollection.geometries.set(i, g); + indices.set(indices.size() - 1, i + 1); + structureStack.add(lastStructure.m_structures.get(i)); + collectionStack.add((OGCConcreteGeometryCollection) g); + indices.add(0); + break; + default: + throw new UnsupportedOperationException(); + } + } + + return root.geometries.get(0); + } + + protected boolean isConcreteGeometryCollection() { + return false; + } + + /** + * SpatialReference of the Geometry. + */ + public com.esri.core.geometry.SpatialReference esriSR; + + public void setSpatialReference(SpatialReference esriSR_) { + esriSR = esriSR_; + } + + /** + * Converts this Geometry to the OGCMulti* if it is not OGCMulti* or + * OGCGeometryCollection already. + * + * @return OGCMulti* or OGCGeometryCollection instance. + */ + public abstract OGCGeometry convertToMulti(); + + /** + * For the geometry collection types, when it has 1 or 0 elements, converts a MultiPolygon to Polygon, + * MultiPoint to Point, MultiLineString to a LineString, and + * OGCConcretGeometryCollection to the reduced element it contains. + * + * If OGCConcretGeometryCollection is empty, returns self. + * + * @return A reduced geometry or this. + */ + public abstract OGCGeometry reduceFromMulti(); + + @Override + public String toString() { + String snippet = asText(); + if (snippet.length() > 200) { + snippet = snippet.substring(0, 197) + "..."; + } + return String + .format("%s: %s", this.getClass().getSimpleName(), snippet); + } + + @Override + public boolean equals(Object other) { + if (other == null) + return false; + + if (other == this) + return true; + + if (other.getClass() != getClass()) + return false; + + OGCGeometry another = (OGCGeometry)other; + com.esri.core.geometry.Geometry geom1 = getEsriGeometry(); + com.esri.core.geometry.Geometry geom2 = another.getEsriGeometry(); + + if (geom1 == null) { + if (geom2 != null) + return false; + } + else if (!geom1.equals(geom2)) { + return false; + } + + if (esriSR == another.esriSR) { + return true; + } + + if (esriSR != null && another.esriSR != null) { + return esriSR.equals(another.esriSR); + } + + return false; + } + + @Override + public int hashCode() { + int hash = 1; + com.esri.core.geometry.Geometry geom1 = getEsriGeometry(); + if (geom1 != null) + hash = geom1.hashCode(); + + if (esriSR != null) + hash = NumberUtils.hashCombine(hash, esriSR.hashCode()); + + return hash; + } } diff --git a/src/main/java/com/esri/core/geometry/ogc/OGCGeometryCollection.java b/src/main/java/com/esri/core/geometry/ogc/OGCGeometryCollection.java index 840d8728..5d5cddf2 100644 --- a/src/main/java/com/esri/core/geometry/ogc/OGCGeometryCollection.java +++ b/src/main/java/com/esri/core/geometry/ogc/OGCGeometryCollection.java @@ -25,15 +25,15 @@ package com.esri.core.geometry.ogc; public abstract class OGCGeometryCollection extends OGCGeometry { - /** - * Returns the number of geometries in this GeometryCollection. - */ - public abstract int numGeometries(); - - /** - * Returns the Nth geometry in this GeometryCollection. - * - * @param n The 0 based index of the geometry. - */ - public abstract OGCGeometry geometryN(int n); + /** + * Returns the number of geometries in this GeometryCollection. + */ + public abstract int numGeometries(); + + /** + * Returns the Nth geometry in this GeometryCollection. + * + * @param n The 0 based index of the geometry. + */ + public abstract OGCGeometry geometryN(int n); } diff --git a/src/main/java/com/esri/core/geometry/ogc/OGCLineString.java b/src/main/java/com/esri/core/geometry/ogc/OGCLineString.java index 2d892e62..f044128d 100644 --- a/src/main/java/com/esri/core/geometry/ogc/OGCLineString.java +++ b/src/main/java/com/esri/core/geometry/ogc/OGCLineString.java @@ -1,5 +1,5 @@ /* - Copyright 1995-2017 Esri + Copyright 1995-2018 Esri Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -40,7 +40,8 @@ import static com.esri.core.geometry.SizeOf.SIZE_OF_OGC_LINE_STRING; public class OGCLineString extends OGCCurve { - + static public String TYPE = "LineString"; + /** * The number of Points in this LineString. */ @@ -51,75 +52,77 @@ public int numPoints() { return multiPath.getPointCount() + d; } - @Override - public String asText() { - return GeometryEngine.geometryToWkt(getEsriGeometry(), - WktExportFlags.wktExportLineString); - } - - @Override - public ByteBuffer asBinary() { - OperatorExportToWkb op = (OperatorExportToWkb) OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.ExportToWkb); - return op.execute(WkbExportFlags.wkbExportLineString, - getEsriGeometry(), null); - } - - /** - * Returns the specified Point N in this LineString. - * - * @param n The 0 based index of the Point. - */ - public OGCPoint pointN(int n) { - int nn; - if (multiPath.isClosedPath(0) && n == multiPath.getPathSize(0)) { - nn = multiPath.getPathStart(0); - } else - nn = n + multiPath.getPathStart(0); - - return (OGCPoint) OGCGeometry.createFromEsriGeometry( - multiPath.getPoint(nn), esriSR); - } - - @Override - public boolean isClosed() { - return multiPath.isClosedPathInXYPlane(0); - } - - public OGCLineString(MultiPath mp, int pathIndex, SpatialReference sr) { - multiPath = new Polyline(); - if (!mp.isEmpty()) - multiPath.addPath(mp, pathIndex, true); - esriSR = sr; - } - - public OGCLineString(MultiPath mp, int pathIndex, SpatialReference sr, - boolean reversed) { - multiPath = new Polyline(); - if (!mp.isEmpty()) - multiPath.addPath(mp, pathIndex, !reversed); - esriSR = sr; - } - - @Override - public double length() { - return multiPath.calculateLength2D(); - } - - @Override - public OGCPoint startPoint() { - return pointN(0); - } - - @Override - public OGCPoint endPoint() { - return pointN(numPoints() - 1); - } - - @Override - public String geometryType() { - return "LineString"; - } + @Override + public String asText() { + return GeometryEngine.geometryToWkt(getEsriGeometry(), + WktExportFlags.wktExportLineString); + } + + @Override + public ByteBuffer asBinary() { + OperatorExportToWkb op = (OperatorExportToWkb) OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.ExportToWkb); + return op.execute(WkbExportFlags.wkbExportLineString, + getEsriGeometry(), null); + } + + /** + * Returns the specified Point N in this LineString. + * @param n The 0 based index of the Point. + */ + public OGCPoint pointN(int n) { + int nn; + if (multiPath.isClosedPath(0) && n == multiPath.getPathSize(0)) { + nn = multiPath.getPathStart(0); + } else + nn = n + multiPath.getPathStart(0); + + return (OGCPoint) OGCGeometry.createFromEsriGeometry( + multiPath.getPoint(nn), esriSR); + } + + @Override + public boolean isClosed() { + if (isEmpty()) + return false; + + return multiPath.isClosedPathInXYPlane(0); + } + + public OGCLineString(MultiPath mp, int pathIndex, SpatialReference sr) { + multiPath = new Polyline(); + if (!mp.isEmpty()) + multiPath.addPath(mp, pathIndex, true); + esriSR = sr; + } + + public OGCLineString(MultiPath mp, int pathIndex, SpatialReference sr, + boolean reversed) { + multiPath = new Polyline(); + if (!mp.isEmpty()) + multiPath.addPath(mp, pathIndex, !reversed); + esriSR = sr; + } + + @Override + public double length() { + return multiPath.calculateLength2D(); + } + + @Override + public OGCPoint startPoint() { + return pointN(0); + } + + @Override + public OGCPoint endPoint() { + return pointN(numPoints() - 1); + } + + @Override + public String geometryType() { + return TYPE; + } @Override public long estimateMemorySize() @@ -132,20 +135,26 @@ public OGCGeometry locateAlong(double mValue) { throw new UnsupportedOperationException(); } - @Override - public OGCGeometry locateBetween(double mStart, double mEnd) { - throw new UnsupportedOperationException(); - } - - @Override - public Geometry getEsriGeometry() { - return multiPath; - } + @Override + public OGCGeometry locateBetween(double mStart, double mEnd) { + throw new UnsupportedOperationException(); + } - @Override - public OGCGeometry convertToMulti() { - return new OGCMultiLineString((Polyline) multiPath, esriSR); - } + @Override + public Geometry getEsriGeometry() { + return multiPath; + } - MultiPath multiPath; + @Override + public OGCGeometry convertToMulti() + { + return new OGCMultiLineString((Polyline)multiPath, esriSR); + } + + @Override + public OGCGeometry reduceFromMulti() { + return this; + } + + MultiPath multiPath; } diff --git a/src/main/java/com/esri/core/geometry/ogc/OGCLinearRing.java b/src/main/java/com/esri/core/geometry/ogc/OGCLinearRing.java index e2ceefeb..fe7d1215 100644 --- a/src/main/java/com/esri/core/geometry/ogc/OGCLinearRing.java +++ b/src/main/java/com/esri/core/geometry/ogc/OGCLinearRing.java @@ -29,36 +29,36 @@ public class OGCLinearRing extends OGCLineString { - public OGCLinearRing(MultiPath mp, int pathIndex, SpatialReference sr, - boolean reversed) { - super(mp, pathIndex, sr, reversed); - if (!mp.isClosedPath(0)) - throw new IllegalArgumentException("LinearRing path must be closed"); - } + public OGCLinearRing(MultiPath mp, int pathIndex, SpatialReference sr, + boolean reversed) { + super(mp, pathIndex, sr, reversed); + if (!mp.isClosedPath(0)) + throw new IllegalArgumentException("LinearRing path must be closed"); + } - public int numPoints() { - if (multiPath.isEmpty()) - return 0; - return multiPath.getPointCount() + 1; - } + public int numPoints() { + if (multiPath.isEmpty()) + return 0; + return multiPath.getPointCount() + 1; + } - public boolean isClosed() { - return true; - } + public boolean isClosed() { + return true; + } - public boolean isRing() { - return true; - } + public boolean isRing() { + return true; + } - @Override - public OGCPoint pointN(int n) { - int nn; - if (n == multiPath.getPathSize(0)) { - nn = multiPath.getPathStart(0); - } else - nn = multiPath.getPathStart(0) + n; + @Override + public OGCPoint pointN(int n) { + int nn; + if (n == multiPath.getPathSize(0)) { + nn = multiPath.getPathStart(0); + } else + nn = multiPath.getPathStart(0) + n; - return (OGCPoint) OGCGeometry.createFromEsriGeometry( - multiPath.getPoint(nn), esriSR); - } + return (OGCPoint) OGCGeometry.createFromEsriGeometry( + multiPath.getPoint(nn), esriSR); + } } diff --git a/src/main/java/com/esri/core/geometry/ogc/OGCMultiCurve.java b/src/main/java/com/esri/core/geometry/ogc/OGCMultiCurve.java index d4ed738d..9aae3bee 100644 --- a/src/main/java/com/esri/core/geometry/ogc/OGCMultiCurve.java +++ b/src/main/java/com/esri/core/geometry/ogc/OGCMultiCurve.java @@ -27,22 +27,22 @@ import com.esri.core.geometry.MultiPath; public abstract class OGCMultiCurve extends OGCGeometryCollection { - public int numGeometries() { - MultiPath mp = (MultiPath) getEsriGeometry(); - return mp.getPathCount(); - } - - public boolean isClosed() { - MultiPath mp = (MultiPath) getEsriGeometry(); - for (int i = 0, n = mp.getPathCount(); i < n; i++) { - if (!mp.isClosedPathInXYPlane(i)) - return false; - } - - return true; - } - - public double length() { - return getEsriGeometry().calculateLength2D(); - } + public int numGeometries() { + MultiPath mp = (MultiPath) getEsriGeometry(); + return mp.getPathCount(); + } + + public boolean isClosed() { + MultiPath mp = (MultiPath) getEsriGeometry(); + for (int i = 0, n = mp.getPathCount(); i < n; i++) { + if (!mp.isClosedPathInXYPlane(i)) + return false; + } + + return true; + } + + public double length() { + return getEsriGeometry().calculateLength2D(); + } } diff --git a/src/main/java/com/esri/core/geometry/ogc/OGCMultiLineString.java b/src/main/java/com/esri/core/geometry/ogc/OGCMultiLineString.java index da102f76..6a2381e3 100644 --- a/src/main/java/com/esri/core/geometry/ogc/OGCMultiLineString.java +++ b/src/main/java/com/esri/core/geometry/ogc/OGCMultiLineString.java @@ -1,5 +1,5 @@ /* - Copyright 1995-2017 Esri + Copyright 1995-2018 Esri Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -42,43 +42,49 @@ import static com.esri.core.geometry.SizeOf.SIZE_OF_OGC_MULTI_LINE_STRING; public class OGCMultiLineString extends OGCMultiCurve { + static public String TYPE = "MultiLineString"; + + public OGCMultiLineString(Polyline poly, SpatialReference sr) { + polyline = poly; + esriSR = sr; + } + + public OGCMultiLineString(SpatialReference sr) { + polyline = new Polyline(); + esriSR = sr; + } + + @Override + public String asText() { + return GeometryEngine.geometryToWkt(getEsriGeometry(), + WktExportFlags.wktExportMultiLineString); + } - public OGCMultiLineString(Polyline poly, SpatialReference sr) { - polyline = poly; - esriSR = sr; - } - - @Override - public String asText() { - return GeometryEngine.geometryToWkt(getEsriGeometry(), - WktExportFlags.wktExportMultiLineString); - } - - @Override - public String asGeoJson() { - OperatorExportToGeoJson op = (OperatorExportToGeoJson) OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.ExportToGeoJson); - return op.execute(GeoJsonExportFlags.geoJsonExportPreferMultiGeometry, null, getEsriGeometry()); - } - - @Override - public ByteBuffer asBinary() { - OperatorExportToWkb op = (OperatorExportToWkb) OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.ExportToWkb); - return op.execute(WkbExportFlags.wkbExportMultiLineString, - getEsriGeometry(), null); - } - - @Override - public OGCGeometry geometryN(int n) { - OGCLineString ls = new OGCLineString(polyline, n, esriSR); - return ls; - } - - @Override - public String geometryType() { - return "MultiLineString"; - } + @Override + public String asGeoJson() { + OperatorExportToGeoJson op = (OperatorExportToGeoJson) OperatorFactoryLocal.getInstance() + .getOperator(Operator.Type.ExportToGeoJson); + return op.execute(GeoJsonExportFlags.geoJsonExportPreferMultiGeometry, null, getEsriGeometry()); + } + + @Override + public ByteBuffer asBinary() { + OperatorExportToWkb op = (OperatorExportToWkb) OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.ExportToWkb); + return op.execute(WkbExportFlags.wkbExportMultiLineString, + getEsriGeometry(), null); + } + + @Override + public OGCGeometry geometryN(int n) { + OGCLineString ls = new OGCLineString(polyline, n, esriSR); + return ls; + } + + @Override + public String geometryType() { + return TYPE; + } @Override public long estimateMemorySize() @@ -94,27 +100,42 @@ public OGCGeometry boundary() { return OGCGeometry.createFromEsriGeometry(g, esriSR, true); } - @Override - public OGCGeometry locateAlong(double mValue) { - // TODO Auto-generated method stub - throw new UnsupportedOperationException(); - } - - @Override - public OGCGeometry locateBetween(double mStart, double mEnd) { - // TODO Auto-generated method stub - throw new UnsupportedOperationException(); - } - - @Override - public Geometry getEsriGeometry() { - return polyline; - } - - @Override - public OGCGeometry convertToMulti() { - return this; - } - - Polyline polyline; + @Override + public OGCGeometry locateAlong(double mValue) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException(); + } + + @Override + public OGCGeometry locateBetween(double mStart, double mEnd) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException(); + } + + @Override + public Geometry getEsriGeometry() { + return polyline; + } + + @Override + public OGCGeometry convertToMulti() + { + return this; + } + + @Override + public OGCGeometry reduceFromMulti() { + int n = numGeometries(); + if (n == 0) { + return new OGCLineString(new Polyline(polyline.getDescription()), 0, esriSR); + } + + if (n == 1) { + return geometryN(0); + } + + return this; + } + + Polyline polyline; } diff --git a/src/main/java/com/esri/core/geometry/ogc/OGCMultiPoint.java b/src/main/java/com/esri/core/geometry/ogc/OGCMultiPoint.java index 38c1fac6..b1c70a02 100644 --- a/src/main/java/com/esri/core/geometry/ogc/OGCMultiPoint.java +++ b/src/main/java/com/esri/core/geometry/ogc/OGCMultiPoint.java @@ -40,33 +40,35 @@ import static com.esri.core.geometry.SizeOf.SIZE_OF_OGC_MULTI_POINT; public class OGCMultiPoint extends OGCGeometryCollection { - public int numGeometries() { - return multiPoint.getPointCount(); - } - - @Override - public String asText() { - return GeometryEngine.geometryToWkt(getEsriGeometry(), - WktExportFlags.wktExportMultiPoint); - } - - @Override - public ByteBuffer asBinary() { - OperatorExportToWkb op = (OperatorExportToWkb) OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.ExportToWkb); - return op.execute(WkbExportFlags.wkbExportMultiPoint, - getEsriGeometry(), null); - } - - public OGCGeometry geometryN(int n) { - return OGCGeometry.createFromEsriGeometry(multiPoint.getPoint(n), - esriSR); - } - - @Override - public String geometryType() { - return "MultiPoint"; - } + public static String TYPE = "MultiPoint"; + + public int numGeometries() { + return multiPoint.getPointCount(); + } + + @Override + public String asText() { + return GeometryEngine.geometryToWkt(getEsriGeometry(), + WktExportFlags.wktExportMultiPoint); + } + + @Override + public ByteBuffer asBinary() { + OperatorExportToWkb op = (OperatorExportToWkb) OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.ExportToWkb); + return op.execute(WkbExportFlags.wkbExportMultiPoint, + getEsriGeometry(), null); + } + + public OGCGeometry geometryN(int n) { + return OGCGeometry.createFromEsriGeometry(multiPoint.getPoint(n), + esriSR); + } + + @Override + public String geometryType() { + return TYPE; + } @Override public long estimateMemorySize() @@ -84,51 +86,66 @@ public OGCMultiPoint(MultiPoint mp, SpatialReference sr) { esriSR = sr; } - public OGCMultiPoint(Point startPoint, SpatialReference sr) { - multiPoint = new MultiPoint(); - multiPoint.add((Point) startPoint); - esriSR = sr; - } - - public OGCMultiPoint(OGCPoint startPoint, OGCPoint endPoint) { - multiPoint = new MultiPoint(); - multiPoint.add((Point) startPoint.getEsriGeometry()); - multiPoint.add((Point) endPoint.getEsriGeometry()); - esriSR = startPoint.esriSR; - } - - public OGCMultiPoint(SpatialReference sr) { - esriSR = sr; - multiPoint = new MultiPoint(); - } - - @Override - public OGCGeometry boundary() { - return new OGCMultiPoint((MultiPoint) multiPoint.createInstance(), - esriSR);// return empty multipoint - } - - @Override - public OGCGeometry locateAlong(double mValue) { - // TODO Auto-generated method stub - throw new UnsupportedOperationException(); - } - - @Override - public OGCGeometry locateBetween(double mStart, double mEnd) { - // TODO Auto-generated method stub - throw new UnsupportedOperationException(); - } - - @Override - public Geometry getEsriGeometry() { - return multiPoint; - } - - @Override - public OGCGeometry convertToMulti() { - return this; - } - - private com.esri.core.geometry.MultiPoint multiPoint; + public OGCMultiPoint(Point startPoint, SpatialReference sr) { + multiPoint = new MultiPoint(); + multiPoint.add((Point) startPoint); + esriSR = sr; + } + + public OGCMultiPoint(OGCPoint startPoint, OGCPoint endPoint) { + multiPoint = new MultiPoint(); + multiPoint.add((Point) startPoint.getEsriGeometry()); + multiPoint.add((Point) endPoint.getEsriGeometry()); + esriSR = startPoint.esriSR; + } + + public OGCMultiPoint(SpatialReference sr) { + esriSR = sr; + multiPoint = new MultiPoint(); + } + + @Override + public OGCGeometry boundary() { + return new OGCMultiPoint((MultiPoint) multiPoint.createInstance(), + esriSR);// return empty multipoint + } + + @Override + public OGCGeometry locateAlong(double mValue) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException(); + } + + @Override + public OGCGeometry locateBetween(double mStart, double mEnd) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException(); + } + + @Override + public Geometry getEsriGeometry() { + return multiPoint; + } + + @Override + public OGCGeometry convertToMulti() + { + return this; + } + + @Override + public OGCGeometry reduceFromMulti() { + int n = numGeometries(); + if (n == 0) { + return new OGCPoint(new Point(multiPoint.getDescription()), esriSR); + } + + if (n == 1) { + return geometryN(0); + } + + return this; + } + + private com.esri.core.geometry.MultiPoint multiPoint; } diff --git a/src/main/java/com/esri/core/geometry/ogc/OGCMultiPolygon.java b/src/main/java/com/esri/core/geometry/ogc/OGCMultiPolygon.java index f9d8ec04..52afbe86 100644 --- a/src/main/java/com/esri/core/geometry/ogc/OGCMultiPolygon.java +++ b/src/main/java/com/esri/core/geometry/ogc/OGCMultiPolygon.java @@ -1,5 +1,5 @@ /* - Copyright 1995-2017 Esri + Copyright 1995-2018 Esri Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -42,57 +42,61 @@ import static com.esri.core.geometry.SizeOf.SIZE_OF_OGC_MULTI_POLYGON; public class OGCMultiPolygon extends OGCMultiSurface { + static public String TYPE = "MultiPolygon"; + + public OGCMultiPolygon(Polygon src, SpatialReference sr) { + polygon = src; + esriSR = sr; + } - public OGCMultiPolygon(Polygon src, SpatialReference sr) { - polygon = src; - esriSR = sr; - } - - @Override - public String asText() { - return GeometryEngine.geometryToWkt(getEsriGeometry(), - WktExportFlags.wktExportMultiPolygon); - } - - @Override - public ByteBuffer asBinary() { - OperatorExportToWkb op = (OperatorExportToWkb) OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.ExportToWkb); - return op.execute(WkbExportFlags.wkbExportMultiPolygon, - getEsriGeometry(), null); - } + public OGCMultiPolygon(SpatialReference sr) { + polygon = new Polygon(); + esriSR = sr; + } + + @Override + public String asText() { + return GeometryEngine.geometryToWkt(getEsriGeometry(), + WktExportFlags.wktExportMultiPolygon); + } - @Override + @Override + public ByteBuffer asBinary() { + OperatorExportToWkb op = (OperatorExportToWkb) OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.ExportToWkb); + return op.execute(WkbExportFlags.wkbExportMultiPolygon, + getEsriGeometry(), null); + } + @Override public String asGeoJson() { OperatorExportToGeoJson op = (OperatorExportToGeoJson) OperatorFactoryLocal .getInstance().getOperator(Operator.Type.ExportToGeoJson); return op.execute(GeoJsonExportFlags.geoJsonExportPreferMultiGeometry, null, getEsriGeometry()); } + @Override + public int numGeometries() { + return polygon.getExteriorRingCount(); + } - @Override - public int numGeometries() { - return polygon.getExteriorRingCount(); - } - - @Override - public OGCGeometry geometryN(int n) { - int exterior = 0; - for (int i = 0; i < polygon.getPathCount(); i++) { - if (polygon.isExteriorRing(i)) - exterior++; - - if (exterior == n + 1) { - return new OGCPolygon(polygon, i, esriSR); - } - } - - throw new IllegalArgumentException("geometryN: n out of range"); - } + @Override + public OGCGeometry geometryN(int n) { + int exterior = 0; + for (int i = 0; i < polygon.getPathCount(); i++) { + if (polygon.isExteriorRing(i)) + exterior++; + + if (exterior == n + 1) { + return new OGCPolygon(polygon, i, esriSR); + } + } + + throw new IllegalArgumentException("geometryN: n out of range"); + } - @Override - public String geometryType() { - return "MultiPolygon"; - } + @Override + public String geometryType() { + return TYPE; + } @Override public long estimateMemorySize() @@ -108,27 +112,42 @@ public OGCGeometry boundary() { esriSR, true); } - @Override - public OGCGeometry locateAlong(double mValue) { - // TODO Auto-generated method stub - throw new UnsupportedOperationException(); - } - - @Override - public OGCGeometry locateBetween(double mStart, double mEnd) { - // TODO Auto-generated method stub - throw new UnsupportedOperationException(); - } + @Override + public OGCGeometry locateAlong(double mValue) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException(); + } - @Override - public Geometry getEsriGeometry() { - return polygon; - } + @Override + public OGCGeometry locateBetween(double mStart, double mEnd) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException(); + } - @Override - public OGCGeometry convertToMulti() { - return this; - } + @Override + public Geometry getEsriGeometry() { + return polygon; + } - Polygon polygon; + @Override + public OGCGeometry convertToMulti() + { + return this; + } + + @Override + public OGCGeometry reduceFromMulti() { + int n = numGeometries(); + if (n == 0) { + return new OGCPolygon(new Polygon(polygon.getDescription()), 0, esriSR); + } + + if (n == 1) { + return geometryN(0); + } + + return this; + } + + Polygon polygon; } diff --git a/src/main/java/com/esri/core/geometry/ogc/OGCMultiSurface.java b/src/main/java/com/esri/core/geometry/ogc/OGCMultiSurface.java index 243e06f9..5a36dd0e 100644 --- a/src/main/java/com/esri/core/geometry/ogc/OGCMultiSurface.java +++ b/src/main/java/com/esri/core/geometry/ogc/OGCMultiSurface.java @@ -25,17 +25,12 @@ package com.esri.core.geometry.ogc; public abstract class OGCMultiSurface extends OGCGeometryCollection { - public double area() { - return getEsriGeometry().calculateArea2D(); - } - - public OGCPoint centroid() { - // TODO - throw new UnsupportedOperationException(); - } - - public OGCPoint pointOnSurface() { - // TODO - throw new UnsupportedOperationException(); - } + public double area() { + return getEsriGeometry().calculateArea2D(); + } + + public OGCPoint pointOnSurface() { + // TODO + throw new UnsupportedOperationException(); + } } diff --git a/src/main/java/com/esri/core/geometry/ogc/OGCPoint.java b/src/main/java/com/esri/core/geometry/ogc/OGCPoint.java index 24e65ef1..d0fba6e7 100644 --- a/src/main/java/com/esri/core/geometry/ogc/OGCPoint.java +++ b/src/main/java/com/esri/core/geometry/ogc/OGCPoint.java @@ -1,5 +1,5 @@ /* - Copyright 1995-2017 Esri + Copyright 1995-2018 Esri Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -39,45 +39,47 @@ import static com.esri.core.geometry.SizeOf.SIZE_OF_OGC_POINT; public final class OGCPoint extends OGCGeometry { - public OGCPoint(Point pt, SpatialReference sr) { - point = pt; - esriSR = sr; - } - - @Override - public String asText() { - return GeometryEngine.geometryToWkt(getEsriGeometry(), - WktExportFlags.wktExportPoint); - } - - @Override - public ByteBuffer asBinary() { - OperatorExportToWkb op = (OperatorExportToWkb) OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.ExportToWkb); - return op.execute(WkbExportFlags.wkbExportPoint, getEsriGeometry(), - null); - } - - public double X() { - return point.getX(); - } - - public double Y() { - return point.getY(); - } - - public double Z() { - return point.getZ(); - } - - public double M() { - return point.getM(); - } - - @Override - public String geometryType() { - return "Point"; - } + public static String TYPE = "Point"; + + public OGCPoint(Point pt, SpatialReference sr) { + point = pt; + esriSR = sr; + } + + @Override + public String asText() { + return GeometryEngine.geometryToWkt(getEsriGeometry(), + WktExportFlags.wktExportPoint); + } + + @Override + public ByteBuffer asBinary() { + OperatorExportToWkb op = (OperatorExportToWkb) OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.ExportToWkb); + return op.execute(WkbExportFlags.wkbExportPoint, getEsriGeometry(), + null); + } + + public double X() { + return point.getX(); + } + + public double Y() { + return point.getY(); + } + + public double Z() { + return point.getZ(); + } + + public double M() { + return point.getM(); + } + + @Override + public String geometryType() { + return TYPE; + } @Override public long estimateMemorySize() @@ -91,28 +93,34 @@ public OGCGeometry boundary() { .getDescription()), esriSR);// return empty point } - @Override - public OGCGeometry locateAlong(double mValue) { - // TODO Auto-generated method stub - throw new UnsupportedOperationException(); - } - - @Override - public OGCGeometry locateBetween(double mStart, double mEnd) { - // TODO Auto-generated method stub - throw new UnsupportedOperationException(); - } - - @Override - public com.esri.core.geometry.Geometry getEsriGeometry() { - return point; - } - - @Override - public OGCGeometry convertToMulti() { - return new OGCMultiPoint(point, esriSR); - } - - com.esri.core.geometry.Point point; + @Override + public OGCGeometry locateAlong(double mValue) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException(); + } + + @Override + public OGCGeometry locateBetween(double mStart, double mEnd) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException(); + } + + @Override + public com.esri.core.geometry.Geometry getEsriGeometry() { + return point; + } + + @Override + public OGCGeometry convertToMulti() + { + return new OGCMultiPoint(point, esriSR); + } + + @Override + public OGCGeometry reduceFromMulti() { + return this; + } + + com.esri.core.geometry.Point point; } diff --git a/src/main/java/com/esri/core/geometry/ogc/OGCPolygon.java b/src/main/java/com/esri/core/geometry/ogc/OGCPolygon.java index 9deeb69e..4c95250a 100644 --- a/src/main/java/com/esri/core/geometry/ogc/OGCPolygon.java +++ b/src/main/java/com/esri/core/geometry/ogc/OGCPolygon.java @@ -1,5 +1,5 @@ /* - Copyright 1995-2017 Esri + Copyright 1995-2018 Esri Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -40,79 +40,79 @@ import static com.esri.core.geometry.SizeOf.SIZE_OF_OGC_POLYGON; public class OGCPolygon extends OGCSurface { - public OGCPolygon(Polygon src, int exteriorRing, SpatialReference sr) { - polygon = new Polygon(); - for (int i = exteriorRing, n = src.getPathCount(); i < n; i++) { - if (i > exteriorRing && src.isExteriorRing(i)) - break; - polygon.addPath(src, i, true); - } - esriSR = sr; - } - - public OGCPolygon(Polygon geom, SpatialReference sr) { - polygon = geom; - if (geom.getExteriorRingCount() > 1) - throw new IllegalArgumentException( - "Polygon has to have one exterior ring. Simplify geom with OperatorSimplify."); - esriSR = sr; - } - - @Override - public String asText() { - return GeometryEngine.geometryToWkt(getEsriGeometry(), - WktExportFlags.wktExportPolygon); - } - - @Override - public ByteBuffer asBinary() { - OperatorExportToWkb op = (OperatorExportToWkb) OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.ExportToWkb); - return op.execute(WkbExportFlags.wkbExportPolygon, getEsriGeometry(), - null); - } - - /** - * Returns the exterior ring of this Polygon. - * - * @return OGCLinearRing instance. - */ - public OGCLineString exteriorRing() { - if (polygon.isEmpty()) - return new OGCLinearRing((Polygon) polygon.createInstance(), 0, - esriSR, true); - return new OGCLinearRing(polygon, 0, esriSR, true); - } - - /** - * Returns the number of interior rings in this Polygon. - */ - public int numInteriorRing() { - return polygon.getPathCount() - 1; - } - - /** - * Returns the Nth interior ring for this Polygon as a LineString. - * - * @param n The 0 based index of the interior ring. - * @return OGCLinearRing instance. - */ - public OGCLineString interiorRingN(int n) { - return new OGCLinearRing(polygon, n + 1, esriSR, true); - } - - @Override - public OGCMultiCurve boundary() { - Polyline polyline = new Polyline(); - polyline.add(polygon, true); // adds reversed path - return (OGCMultiCurve) OGCGeometry.createFromEsriGeometry(polyline, - esriSR, true); - } - - @Override - public String geometryType() { - return "Polygon"; - } + public static String TYPE = "Polygon"; + + public OGCPolygon(Polygon src, int exteriorRing, SpatialReference sr) { + polygon = new Polygon(); + for (int i = exteriorRing, n = src.getPathCount(); i < n; i++) { + if (i > exteriorRing && src.isExteriorRing(i)) + break; + polygon.addPath(src, i, true); + } + esriSR = sr; + } + + public OGCPolygon(Polygon geom, SpatialReference sr) { + polygon = geom; + if (geom.getExteriorRingCount() > 1) + throw new IllegalArgumentException( + "Polygon has to have one exterior ring. Simplify geom with OperatorSimplify."); + esriSR = sr; + } + + @Override + public String asText() { + return GeometryEngine.geometryToWkt(getEsriGeometry(), + WktExportFlags.wktExportPolygon); + } + + @Override + public ByteBuffer asBinary() { + OperatorExportToWkb op = (OperatorExportToWkb) OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.ExportToWkb); + return op.execute(WkbExportFlags.wkbExportPolygon, getEsriGeometry(), + null); + } + + /** + * Returns the exterior ring of this Polygon. + * @return OGCLinearRing instance. + */ + public OGCLineString exteriorRing() { + if (polygon.isEmpty()) + return new OGCLinearRing((Polygon) polygon.createInstance(), 0, + esriSR, true); + return new OGCLinearRing(polygon, 0, esriSR, true); + } + + /** + * Returns the number of interior rings in this Polygon. + */ + public int numInteriorRing() { + return polygon.getPathCount() - 1; + } + + /** + * Returns the Nth interior ring for this Polygon as a LineString. + * @param n The 0 based index of the interior ring. + * @return OGCLinearRing instance. + */ + public OGCLineString interiorRingN(int n) { + return new OGCLinearRing(polygon, n + 1, esriSR, true); + } + + @Override + public OGCMultiCurve boundary() { + Polyline polyline = new Polyline(); + polyline.add(polygon, true); // adds reversed path + return (OGCMultiCurve) OGCGeometry.createFromEsriGeometry(polyline, + esriSR, true); + } + + @Override + public String geometryType() { + return TYPE; + } @Override public long estimateMemorySize() @@ -126,21 +126,27 @@ public OGCGeometry locateAlong(double mValue) { throw new UnsupportedOperationException(); } - @Override - public OGCGeometry locateBetween(double mStart, double mEnd) { - // TODO Auto-generated method stub - throw new UnsupportedOperationException(); - } - - @Override - public Geometry getEsriGeometry() { - return polygon; - } + @Override + public OGCGeometry locateBetween(double mStart, double mEnd) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException(); + } - @Override - public OGCGeometry convertToMulti() { - return new OGCMultiPolygon(polygon, esriSR); - } + @Override + public Geometry getEsriGeometry() { + return polygon; + } - Polygon polygon; + @Override + public OGCGeometry convertToMulti() + { + return new OGCMultiPolygon(polygon, esriSR); + } + + @Override + public OGCGeometry reduceFromMulti() { + return this; + } + + Polygon polygon; } diff --git a/src/main/java/com/esri/core/geometry/ogc/OGCSurface.java b/src/main/java/com/esri/core/geometry/ogc/OGCSurface.java index 5e255cac..989dfec8 100644 --- a/src/main/java/com/esri/core/geometry/ogc/OGCSurface.java +++ b/src/main/java/com/esri/core/geometry/ogc/OGCSurface.java @@ -25,20 +25,15 @@ package com.esri.core.geometry.ogc; public abstract class OGCSurface extends OGCGeometry { - public double area() { - return getEsriGeometry().calculateArea2D(); - } + public double area() { + return getEsriGeometry().calculateArea2D(); + } - public OGCPoint centroid() { - // TODO: implement me; - throw new UnsupportedOperationException(); - } + public OGCPoint pointOnSurface() { + // TODO: support this (need to port OperatorLabelPoint) + throw new UnsupportedOperationException(); + } - public OGCPoint pointOnSurface() { - // TODO: support this (need to port OperatorLabelPoint) - throw new UnsupportedOperationException(); - } - - public abstract OGCMultiCurve boundary(); + public abstract OGCMultiCurve boundary(); } diff --git a/src/main/resources/com/esri/core/geometry/gcs_id_to_tolerance.txt b/src/main/resources/com/esri/core/geometry/gcs_id_to_tolerance.txt index 1db43ec8..b6c40819 100644 --- a/src/main/resources/com/esri/core/geometry/gcs_id_to_tolerance.txt +++ b/src/main/resources/com/esri/core/geometry/gcs_id_to_tolerance.txt @@ -227,7 +227,7 @@ 4319 0 4322 0 4324 0 -4326 61 +4326 0 4466 0 4469 0 4475 0 diff --git a/src/main/resources/com/esri/core/geometry/gcs_tolerances.txt b/src/main/resources/com/esri/core/geometry/gcs_tolerances.txt index 9b9ccd62..e593f472 100644 --- a/src/main/resources/com/esri/core/geometry/gcs_tolerances.txt +++ b/src/main/resources/com/esri/core/geometry/gcs_tolerances.txt @@ -59,4 +59,3 @@ 58 6.98729e-006 59 9.24125e-006 60 1.14592e-005 -61 8.983152841195213e-009 \ No newline at end of file diff --git a/src/test/java/com/esri/core/geometry/GeometryUtils.java b/src/test/java/com/esri/core/geometry/GeometryUtils.java index 1197eba1..2734db7c 100644 --- a/src/test/java/com/esri/core/geometry/GeometryUtils.java +++ b/src/test/java/com/esri/core/geometry/GeometryUtils.java @@ -29,97 +29,97 @@ import java.util.Scanner; public class GeometryUtils { - public static String getGeometryType(Geometry geomIn) { - // there are five types: esriGeometryPoint - // esriGeometryMultipoint - // esriGeometryPolyline - // esriGeometryPolygon - // esriGeometryEnvelope - if (geomIn instanceof Point) - return "esriGeometryPoint"; - if (geomIn instanceof MultiPoint) - return "esriGeometryMultipoint"; - if (geomIn instanceof Polyline) - return "esriGeometryPolyline"; - if (geomIn instanceof Polygon) - return "esriGeometryPolygon"; - if (geomIn instanceof Envelope) - return "esriGeometryEnvelope"; - else - return null; - } - - static Geometry getGeometryFromJSon(String jsonStr) { - try { - Geometry geom = GeometryEngine.jsonToGeometry(jsonStr).getGeometry(); - return geom; - } catch (Exception ex) { - return null; - } - } - - public enum SpatialRelationType { - esriGeometryRelationCross, esriGeometryRelationDisjoint, esriGeometryRelationIn, esriGeometryRelationInteriorIntersection, esriGeometryRelationIntersection, esriGeometryRelationLineCoincidence, esriGeometryRelationLineTouch, esriGeometryRelationOverlap, esriGeometryRelationPointTouch, esriGeometryRelationTouch, esriGeometryRelationWithin, esriGeometryRelationRelation - } - - static String getJSonStringFromGeometry(Geometry geomIn, SpatialReference sr) { - String jsonStr4Geom = GeometryEngine.geometryToJson(sr, geomIn); - String jsonStrNew = "{\"geometryType\":\"" + getGeometryType(geomIn) - + "\",\"geometries\":[" + jsonStr4Geom + "]}"; - return jsonStrNew; - } - - public static Geometry loadFromTextFileDbg(String textFileName) - throws FileNotFoundException { - String fullPath = textFileName; - // string fullCSVPathName = System.IO.Path.Combine( directoryPath , - // CsvFileName); - File fileInfo = new File(fullPath); - - Scanner scanner = new Scanner(fileInfo); - - Geometry geom = null; - - // grab first line - String line = scanner.nextLine(); - String geomTypeString = line.substring(1); - if (geomTypeString.equalsIgnoreCase("polygon")) - geom = new Polygon(); - else if (geomTypeString.equalsIgnoreCase("polyline")) - geom = new Polyline(); - else if (geomTypeString.equalsIgnoreCase("multipoint")) - geom = new MultiPoint(); - else if (geomTypeString.equalsIgnoreCase("point")) - geom = new Point(); - - while (line.startsWith("*")) - if (scanner.hasNextLine()) - line = scanner.nextLine(); - - int j = 0; - Geometry.Type geomType = geom.getType(); - while (scanner.hasNextLine()) { - String[] parsedLine = line.split("\\s+"); - double xVal = Double.parseDouble(parsedLine[0]); - double yVal = Double.parseDouble(parsedLine[1]); - if (j == 0 - && (geomType == Geometry.Type.Polygon || geomType == Geometry.Type.Polyline)) - ((MultiPath) geom).startPath(xVal, yVal); - else { - if (geomType == Geometry.Type.Polygon - || geomType == Geometry.Type.Polyline) - ((MultiPath) geom).lineTo(xVal, yVal); - else if (geomType == Geometry.Type.MultiPoint) - ((MultiPoint) geom).add(xVal, yVal); - // else if(geomType == Geometry.Type.Point) - // Point geom = null;//new Point(xVal, yVal); - } - j++; - line = scanner.nextLine(); - } - - scanner.close(); - - return geom; - } + public static String getGeometryType(Geometry geomIn) { + // there are five types: esriGeometryPoint + // esriGeometryMultipoint + // esriGeometryPolyline + // esriGeometryPolygon + // esriGeometryEnvelope + if (geomIn instanceof Point) + return "esriGeometryPoint"; + if (geomIn instanceof MultiPoint) + return "esriGeometryMultipoint"; + if (geomIn instanceof Polyline) + return "esriGeometryPolyline"; + if (geomIn instanceof Polygon) + return "esriGeometryPolygon"; + if (geomIn instanceof Envelope) + return "esriGeometryEnvelope"; + else + return null; + } + + static Geometry getGeometryFromJSon(String jsonStr) { + try { + Geometry geom = GeometryEngine.jsonToGeometry(jsonStr).getGeometry(); + return geom; + } catch (Exception ex) { + return null; + } + } + + public enum SpatialRelationType { + esriGeometryRelationCross, esriGeometryRelationDisjoint, esriGeometryRelationIn, esriGeometryRelationInteriorIntersection, esriGeometryRelationIntersection, esriGeometryRelationLineCoincidence, esriGeometryRelationLineTouch, esriGeometryRelationOverlap, esriGeometryRelationPointTouch, esriGeometryRelationTouch, esriGeometryRelationWithin, esriGeometryRelationRelation + } + + static String getJSonStringFromGeometry(Geometry geomIn, SpatialReference sr) { + String jsonStr4Geom = GeometryEngine.geometryToJson(sr, geomIn); + String jsonStrNew = "{\"geometryType\":\"" + getGeometryType(geomIn) + + "\",\"geometries\":[" + jsonStr4Geom + "]}"; + return jsonStrNew; + } + + public static Geometry loadFromTextFileDbg(String textFileName) + throws FileNotFoundException { + String fullPath = textFileName; + // string fullCSVPathName = System.IO.Path.Combine( directoryPath , + // CsvFileName); + File fileInfo = new File(fullPath); + + Scanner scanner = new Scanner(fileInfo); + + Geometry geom = null; + + // grab first line + String line = scanner.nextLine(); + String geomTypeString = line.substring(1); + if (geomTypeString.equalsIgnoreCase("polygon")) + geom = new Polygon(); + else if (geomTypeString.equalsIgnoreCase("polyline")) + geom = new Polyline(); + else if (geomTypeString.equalsIgnoreCase("multipoint")) + geom = new MultiPoint(); + else if (geomTypeString.equalsIgnoreCase("point")) + geom = new Point(); + + while (line.startsWith("*")) + if (scanner.hasNextLine()) + line = scanner.nextLine(); + + int j = 0; + Geometry.Type geomType = geom.getType(); + while (scanner.hasNextLine()) { + String[] parsedLine = line.split("\\s+"); + double xVal = Double.parseDouble(parsedLine[0]); + double yVal = Double.parseDouble(parsedLine[1]); + if (j == 0 + && (geomType == Geometry.Type.Polygon || geomType == Geometry.Type.Polyline)) + ((MultiPath) geom).startPath(xVal, yVal); + else { + if (geomType == Geometry.Type.Polygon + || geomType == Geometry.Type.Polyline) + ((MultiPath) geom).lineTo(xVal, yVal); + else if (geomType == Geometry.Type.MultiPoint) + ((MultiPoint) geom).add(xVal, yVal); + // else if(geomType == Geometry.Type.Point) + // Point geom = null;//new Point(xVal, yVal); + } + j++; + line = scanner.nextLine(); + } + + scanner.close(); + + return geom; + } } diff --git a/src/test/java/com/esri/core/geometry/RandomCoordinateGenerator.java b/src/test/java/com/esri/core/geometry/RandomCoordinateGenerator.java index 449f0f8b..dcaa0444 100644 --- a/src/test/java/com/esri/core/geometry/RandomCoordinateGenerator.java +++ b/src/test/java/com/esri/core/geometry/RandomCoordinateGenerator.java @@ -29,384 +29,384 @@ public class RandomCoordinateGenerator { - // final Point openString[] = { new Point(1220, 1320), - // new Point(1220, 2320), new Point(3000, 2320), - // new Point(3520, 1720), new Point(3000, 1320), }; - // - // final Point3D openString3[] = { new Point3D(1220, 1320, 11), - // new Point3D(1220, 2320, 2), new Point3D(3000, 2320, 3), - // new Point3D(3520, 1720, 4), new Point3D(3000, 1320, 5), }; + // final Point openString[] = { new Point(1220, 1320), + // new Point(1220, 2320), new Point(3000, 2320), + // new Point(3520, 1720), new Point(3000, 1320), }; + // + // final Point3D openString3[] = { new Point3D(1220, 1320, 11), + // new Point3D(1220, 2320, 2), new Point3D(3000, 2320, 3), + // new Point3D(3520, 1720, 4), new Point3D(3000, 1320, 5), }; - Vector points; - Envelope env; - int maxcount; - double tolerance; - double maxlen; - Random random = new Random(1973); + Vector points; + Envelope env; + int maxcount; + double tolerance; + double maxlen; + Random random = new Random(1973); - Point _GenerateNewPoint() { - if (points.size() == maxcount) - return _RandomizeExisting(); - Point pt; - double f = random.nextDouble() - 0.5; - if (points.size() == 0) - pt = env.getCenter(); - else - pt = points.lastElement(); - // pt.x = pt.x + env.Width() * f; - pt.setX(pt.getX() + maxlen * f); - f = 1.0 * random.nextDouble() - 0.5; - pt.setY(pt.getY() + env.getHeight() * f); - pt.setY(pt.getY() + maxlen * f); - pt = _snapClip(pt, env); - points.add(pt); - return pt; - } + Point _GenerateNewPoint() { + if (points.size() == maxcount) + return _RandomizeExisting(); + Point pt; + double f = random.nextDouble() - 0.5; + if (points.size() == 0) + pt = env.getCenter(); + else + pt = points.lastElement(); + // pt.x = pt.x + env.Width() * f; + pt.setX(pt.getX() + maxlen * f); + f = 1.0 * random.nextDouble() - 0.5; + pt.setY(pt.getY() + env.getHeight() * f); + pt.setY(pt.getY() + maxlen * f); + pt = _snapClip(pt, env); + points.add(pt); + return pt; + } - Point _RandomizeExisting() { - if (points.size() == 0) { - return _GenerateNewPoint(); - } + Point _RandomizeExisting() { + if (points.size() == 0) { + return _GenerateNewPoint(); + } - double f = random.nextDouble(); - int num = (int) (f * points.size()); - Point pt = points.get(num); + double f = random.nextDouble(); + int num = (int) (f * points.size()); + Point pt = points.get(num); - f = random.nextDouble(); + f = random.nextDouble(); - // if (f > 0.9) - if (f > 2) { - f = random.nextDouble(); - pt.setX(pt.getX() + (1 - 2 * f) * 2 * tolerance); - f = random.nextDouble(); - pt.setY(pt.getY() + (1 - 2 * f) * 2 * tolerance); - pt = _snapClip(pt, env); - } - return pt; - } + // if (f > 0.9) + if (f > 2) { + f = random.nextDouble(); + pt.setX(pt.getX() + (1 - 2 * f) * 2 * tolerance); + f = random.nextDouble(); + pt.setY(pt.getY() + (1 - 2 * f) * 2 * tolerance); + pt = _snapClip(pt, env); + } + return pt; + } - public RandomCoordinateGenerator(int count, Envelope e, double tol) { - env = e; - maxlen = (env.getWidth() + env.getHeight()) / 2 * 0.1; - points = new Vector(); - points.ensureCapacity(count); - tolerance = tol; - maxcount = count; - } + public RandomCoordinateGenerator(int count, Envelope e, double tol) { + env = e; + maxlen = (env.getWidth() + env.getHeight()) / 2 * 0.1; + points = new Vector(); + points.ensureCapacity(count); + tolerance = tol; + maxcount = count; + } - Point GetRandomCoord() { - double f = random.nextDouble(); - Point pt; - if (f > 0.9) - pt = _RandomizeExisting(); - else - pt = _GenerateNewPoint(); + Point GetRandomCoord() { + double f = random.nextDouble(); + Point pt; + if (f > 0.9) + pt = _RandomizeExisting(); + else + pt = _GenerateNewPoint(); - return pt; - } + return pt; + } - Point _snapClip(Point pt, Envelope env) { - double x = pt.getX(); - if (x < env.getXMin()) - x = env.getXMin(); - if (x > env.getXMax()) - x = env.getXMax(); - double y = pt.getY(); - if (y < env.getYMin()) - y = env.getYMin(); - if (y > env.getYMax()) - y = env.getYMax(); - return new Point(x, y); - } + Point _snapClip(Point pt, Envelope env) { + double x = pt.getX(); + if (x < env.getXMin()) + x = env.getXMin(); + if (x > env.getXMax()) + x = env.getXMax(); + double y = pt.getY(); + if (y < env.getYMin()) + y = env.getYMin(); + if (y > env.getYMax()) + y = env.getYMax(); + return new Point(x, y); + } - // void CompareGeometryContent(MultiVertexGeometry geom, Point buf[], int - // sz) { - // Assert.assertTrue(!geom.isEmpty()); - // Assert.assertTrue(geom.getPointCount() == sz); - // // Go through the geometry points - // for (int i = 0; i < geom.getPointCount(); i++) { - // Point point = new Point(); // not a right pattern the point has to - // // be created outside of the loop. - // geom.getPointByVal(i, point); - // Assert.assertTrue(point.getX() == buf[i].getX()); - // Assert.assertTrue(point.getY() == buf[i].getY()); - // Assert.assertTrue(point.getX() == buf[i].getX()); - // Assert.assertTrue(point.getY() == buf[i].getY()); - // } - // if (geom.getType() == Geometry.Type.Polygon - // || geom.getType() == Geometry.Type.Polyline) { - // CompareGeometryContent((MultiPath) geom, buf, sz); - // } - // } - // - // void CompareGeometryContent(MultiPath geom, Point buf[], int sz) { - // // Go through the geometry parts - // int j = 0; - // for (int ipart = 0; ipart < geom.getPathCount(); ipart++) { - // int start = geom.getPathStart(ipart); - // for (int i = 0; i < geom.getPathSize(ipart); i++, j++) { - // Point point = geom.getPoint(start + i); - // Assert.assertTrue(point.getX() == buf[j].getX()); - // Assert.assertTrue(point.getY() == buf[j].getY()); - // - // } - // } - // } + // void CompareGeometryContent(MultiVertexGeometry geom, Point buf[], int + // sz) { + // Assert.assertTrue(!geom.isEmpty()); + // Assert.assertTrue(geom.getPointCount() == sz); + // // Go through the geometry points + // for (int i = 0; i < geom.getPointCount(); i++) { + // Point point = new Point(); // not a right pattern the point has to + // // be created outside of the loop. + // geom.getPointByVal(i, point); + // Assert.assertTrue(point.getX() == buf[i].getX()); + // Assert.assertTrue(point.getY() == buf[i].getY()); + // Assert.assertTrue(point.getX() == buf[i].getX()); + // Assert.assertTrue(point.getY() == buf[i].getY()); + // } + // if (geom.getType() == Geometry.Type.Polygon + // || geom.getType() == Geometry.Type.Polyline) { + // CompareGeometryContent((MultiPath) geom, buf, sz); + // } + // } + // + // void CompareGeometryContent(MultiPath geom, Point buf[], int sz) { + // // Go through the geometry parts + // int j = 0; + // for (int ipart = 0; ipart < geom.getPathCount(); ipart++) { + // int start = geom.getPathStart(ipart); + // for (int i = 0; i < geom.getPathSize(ipart); i++, j++) { + // Point point = geom.getPoint(start + i); + // Assert.assertTrue(point.getX() == buf[j].getX()); + // Assert.assertTrue(point.getY() == buf[j].getY()); + // + // } + // } + // } - // void CompareGeometryContent(MultiVertexGeometry geom, Point3D buf[], int - // sz) { - // Assert.assertTrue(!geom.isEmpty()); - // Assert.assertTrue(geom.getPointCount() == sz); - // // Go through the geometry points - // for (int i = 0; i < geom.getPointCount(); i++) { - // Point point = new Point(); // not a right pattern the point has to - // // be created outside of the loop. - // geom.getPointByVal(i, point); - // Assert.assertTrue(point.getX() == buf[i].x); - // Assert.assertTrue(point.getY() == buf[i].y); - // Assert.assertTrue(point.getZ() == buf[i].z); - // Point3D pt = point.getXYZ(); - // Assert.assertTrue(pt.x == buf[i].x); - // Assert.assertTrue(pt.y == buf[i].y); - // Assert.assertTrue(pt.z == buf[i].z); - // } - // - // { - // MultiVertexGeometryImpl mpGeom = (MultiVertexGeometryImpl) geom - // ._getImpl(); - // AttributeStreamOfDbl streamPos = (AttributeStreamOfDbl) mpGeom - // .getAttributeStreamRef(VertexDescription.Semantics.POSITION); - // AttributeStreamOfDbl streamZ = (AttributeStreamOfDbl) mpGeom - // .getAttributeStreamRef(VertexDescription.Semantics.Z); - // for (int i = 0; i < geom.getPointCount(); i++) { - // double x = streamPos.read(2 * i); - // double y = streamPos.read(2 * i + 1); - // double z = streamZ.read(i); - // - // Assert.assertTrue(x == buf[i].x); - // Assert.assertTrue(y == buf[i].y); - // Assert.assertTrue(z == buf[i].z); - // } - // } - // - // if (geom.getType() == Geometry.Type.Polygon - // || geom.getType() == Geometry.Type.Polyline) { - // CompareGeometryContent((MultiPath) geom, buf, sz); - // } - // } + // void CompareGeometryContent(MultiVertexGeometry geom, Point3D buf[], int + // sz) { + // Assert.assertTrue(!geom.isEmpty()); + // Assert.assertTrue(geom.getPointCount() == sz); + // // Go through the geometry points + // for (int i = 0; i < geom.getPointCount(); i++) { + // Point point = new Point(); // not a right pattern the point has to + // // be created outside of the loop. + // geom.getPointByVal(i, point); + // Assert.assertTrue(point.getX() == buf[i].x); + // Assert.assertTrue(point.getY() == buf[i].y); + // Assert.assertTrue(point.getZ() == buf[i].z); + // Point3D pt = point.getXYZ(); + // Assert.assertTrue(pt.x == buf[i].x); + // Assert.assertTrue(pt.y == buf[i].y); + // Assert.assertTrue(pt.z == buf[i].z); + // } + // + // { + // MultiVertexGeometryImpl mpGeom = (MultiVertexGeometryImpl) geom + // ._getImpl(); + // AttributeStreamOfDbl streamPos = (AttributeStreamOfDbl) mpGeom + // .getAttributeStreamRef(VertexDescription.Semantics.POSITION); + // AttributeStreamOfDbl streamZ = (AttributeStreamOfDbl) mpGeom + // .getAttributeStreamRef(VertexDescription.Semantics.Z); + // for (int i = 0; i < geom.getPointCount(); i++) { + // double x = streamPos.read(2 * i); + // double y = streamPos.read(2 * i + 1); + // double z = streamZ.read(i); + // + // Assert.assertTrue(x == buf[i].x); + // Assert.assertTrue(y == buf[i].y); + // Assert.assertTrue(z == buf[i].z); + // } + // } + // + // if (geom.getType() == Geometry.Type.Polygon + // || geom.getType() == Geometry.Type.Polyline) { + // CompareGeometryContent((MultiPath) geom, buf, sz); + // } + // } - // void CompareGeometryContent(MultiPath geom, Point3D buf[], int sz) { - // Assert.assertTrue(!geom.isEmpty()); - // Assert.assertTrue(geom.getPointCount() == sz); - // - // // Go through the geometry parts - // int j = 0; - // for (int ipart = 0; ipart < geom.getPathCount(); ipart++) { - // int start = geom.getPathStart(ipart); - // for (int i = 0; i < geom.getPathSize(ipart); i++, j++) { - // double x = geom.getAttributeAsDbl( - // VertexDescription.Semantics.POSITION, i + start, 0); - // double y = geom.getAttributeAsDbl( - // VertexDescription.Semantics.POSITION, i + start, 1); - // double z = geom.getAttributeAsDbl( - // VertexDescription.Semantics.Z, i + start, 0); - // Assert.assertTrue(x == buf[j].x); - // Assert.assertTrue(y == buf[j].y); - // Assert.assertTrue(z == buf[j].z); - // - // Point point = new Point(); // not a right pattern the point has - // // to be created outside of the - // // loop. - // geom.getPointByVal(start + i, point); - // Assert.assertTrue(point.getX() == buf[j].x); - // Assert.assertTrue(point.getY() == buf[j].y); - // Assert.assertTrue(point.getZ() == buf[j].z); - // Point3D pt = point.getXYZ(); - // Assert.assertTrue(pt.x == buf[j].x); - // Assert.assertTrue(pt.y == buf[j].y); - // Assert.assertTrue(pt.z == buf[j].z); - // } - // } - // } + // void CompareGeometryContent(MultiPath geom, Point3D buf[], int sz) { + // Assert.assertTrue(!geom.isEmpty()); + // Assert.assertTrue(geom.getPointCount() == sz); + // + // // Go through the geometry parts + // int j = 0; + // for (int ipart = 0; ipart < geom.getPathCount(); ipart++) { + // int start = geom.getPathStart(ipart); + // for (int i = 0; i < geom.getPathSize(ipart); i++, j++) { + // double x = geom.getAttributeAsDbl( + // VertexDescription.Semantics.POSITION, i + start, 0); + // double y = geom.getAttributeAsDbl( + // VertexDescription.Semantics.POSITION, i + start, 1); + // double z = geom.getAttributeAsDbl( + // VertexDescription.Semantics.Z, i + start, 0); + // Assert.assertTrue(x == buf[j].x); + // Assert.assertTrue(y == buf[j].y); + // Assert.assertTrue(z == buf[j].z); + // + // Point point = new Point(); // not a right pattern the point has + // // to be created outside of the + // // loop. + // geom.getPointByVal(start + i, point); + // Assert.assertTrue(point.getX() == buf[j].x); + // Assert.assertTrue(point.getY() == buf[j].y); + // Assert.assertTrue(point.getZ() == buf[j].z); + // Point3D pt = point.getXYZ(); + // Assert.assertTrue(pt.x == buf[j].x); + // Assert.assertTrue(pt.y == buf[j].y); + // Assert.assertTrue(pt.z == buf[j].z); + // } + // } + // } - // void CompareGeometryContent(MultiVertexGeometry geom1, - // MultiVertexGeometry geom2) { - // // Geometry types - // Assert.assertTrue(geom1.getType() == geom2.getType()); - // - // // Envelopes - // Envelope env1 = new Envelope(); - // geom1.queryEnvelope(env1); - // - // Envelope env2 = new Envelope(); - // geom2.queryEnvelope(env2); - // - // Assert.assertTrue(env1.getXMin() == env2.getXMin() - // && env1.getXMax() == env2.getXMax() - // && env1.getYMin() == env2.getYMin() - // && env1.getYMax() == env2.getYMax()); - // - // int type = geom1.getType(); - // if (type == Geometry.Type.Polyline || type == Geometry.Type.Polygon) { - // // Part Count - // int partCount1 = ((MultiPath) geom1).getPathCount(); - // int partCount2 = ((MultiPath) geom2).getPathCount(); - // Assert.assertTrue(partCount1 == partCount2); - // - // // Part indices - // for (int i = 0; i < partCount1; i++) { - // int start1 = ((MultiPath) geom1).getPathStart(i); - // int start2 = ((MultiPath) geom2).getPathStart(i); - // Assert.assertTrue(start1 == start2); - // int end1 = ((MultiPath) geom1).getPathEnd(i); - // int end2 = ((MultiPath) geom2).getPathEnd(i); - // Assert.assertTrue(end1 == end2); - // } - // } - // - // // Point count - // int pointCount1 = geom1.getPointCount(); - // int pointCount2 = geom2.getPointCount(); - // Assert.assertTrue(pointCount1 == pointCount2); - // - // if (type == Geometry.Type.MultiPoint || type == Geometry.Type.Polyline - // || type == Geometry.Type.Polygon) { - // MultiVertexGeometryImpl mpGeom1 = (MultiVertexGeometryImpl) geom1 - // ._getImpl(); - // MultiVertexGeometryImpl mpGeom2 = (MultiVertexGeometryImpl) geom2 - // ._getImpl(); - // // POSITION - // AttributeStreamBase positionStream1 = mpGeom1 - // .getAttributeStreamRef(VertexDescription.Semantics.POSITION); - // AttributeStreamOfDbl position1 = (AttributeStreamOfDbl) positionStream1; - // - // AttributeStreamBase positionStream2 = mpGeom2 - // .getAttributeStreamRef(VertexDescription.Semantics.POSITION); - // AttributeStreamOfDbl position2 = (AttributeStreamOfDbl) positionStream2; - // - // for (int i = 0; i < pointCount1; i++) { - // double x1 = position1.read(2 * i); - // double x2 = position2.read(2 * i); - // Assert.assertTrue(x1 == x2); - // - // double y1 = position1.read(2 * i + 1); - // double y2 = position2.read(2 * i + 1); - // Assert.assertTrue(y1 == y2); - // } - // - // // Zs - // boolean bHasZs1 = mpGeom1 - // .hasAttribute(VertexDescription.Semantics.Z); - // boolean bHasZs2 = mpGeom2 - // .hasAttribute(VertexDescription.Semantics.Z); - // Assert.assertTrue(bHasZs1 == bHasZs2); - // - // if (bHasZs1) { - // AttributeStreamBase zStream1 = mpGeom1 - // .getAttributeStreamRef(VertexDescription.Semantics.Z); - // AttributeStreamOfDbl zs1 = (AttributeStreamOfDbl) zStream1; - // - // AttributeStreamBase zStream2 = mpGeom2 - // .getAttributeStreamRef(VertexDescription.Semantics.Z); - // AttributeStreamOfDbl zs2 = (AttributeStreamOfDbl) zStream2; - // - // for (int i = 0; i < pointCount1; i++) { - // double z1 = zs1.read(i); - // double z2 = zs2.read(i); - // Assert.assertTrue(z1 == z2); - // } - // } - // - // // Ms - // boolean bHasMs1 = mpGeom1 - // .hasAttribute(VertexDescription.Semantics.M); - // boolean bHasMs2 = mpGeom2 - // .hasAttribute(VertexDescription.Semantics.M); - // Assert.assertTrue(bHasMs1 == bHasMs2); - // - // if (bHasMs1) { - // AttributeStreamBase mStream1 = mpGeom1 - // .getAttributeStreamRef(VertexDescription.Semantics.M); - // AttributeStreamOfDbl ms1 = (AttributeStreamOfDbl) mStream1; - // - // AttributeStreamBase mStream2 = mpGeom2 - // .getAttributeStreamRef(VertexDescription.Semantics.M); - // AttributeStreamOfDbl ms2 = (AttributeStreamOfDbl) mStream2; - // - // for (int i = 0; i < pointCount1; i++) { - // double m1 = ms1.read(i); - // double m2 = ms2.read(i); - // Assert.assertTrue(m1 == m2); - // } - // } - // - // // IDs - // boolean bHasIDs1 = mpGeom1 - // .hasAttribute(VertexDescription.Semantics.ID); - // boolean bHasIDs2 = mpGeom2 - // .hasAttribute(VertexDescription.Semantics.ID); - // Assert.assertTrue(bHasIDs1 == bHasIDs2); - // - // if (bHasIDs1) { - // AttributeStreamBase idStream1 = mpGeom1 - // .getAttributeStreamRef(VertexDescription.Semantics.ID); - // AttributeStreamOfInt32 ids1 = (AttributeStreamOfInt32) idStream1; - // - // AttributeStreamBase idStream2 = mpGeom2 - // .getAttributeStreamRef(VertexDescription.Semantics.ID); - // AttributeStreamOfInt32 ids2 = (AttributeStreamOfInt32) idStream2; - // - // for (int i = 0; i < pointCount1; i++) { - // int id1 = ids1.read(i); - // int id2 = ids2.read(i); - // Assert.assertTrue(id1 == id2); - // } - // } - // } - // } - // - // void SimpleTest(Geometry point) { - // Assert.assertTrue(point != null); - // point.addAttribute(VertexDescription.Semantics.Z); - // Assert.assertTrue(point - // .hasAttribute(VertexDescription.Semantics.POSITION)); - // Assert.assertTrue(point.hasAttribute(VertexDescription.Semantics.Z)); - // point.addAttribute(VertexDescription.Semantics.Z);// duplicate call - // Assert.assertTrue(point.getDescription().getAttributeCount() == 2); - // Assert - // .assertTrue(point.getDescription().getSemantics(1) == - // VertexDescription.Semantics.Z); - // point.dropAttribute(VertexDescription.Semantics.Z); - // Assert.assertTrue(!point.hasAttribute(VertexDescription.Semantics.Z)); - // point.dropAttribute(VertexDescription.Semantics.Z);// duplicate call - // Assert.assertTrue(!point.hasAttribute(VertexDescription.Semantics.Z)); - // Assert.assertTrue(point.getDescription().getAttributeCount() == 1); - // Assert - // .assertTrue(point.getDescription().getSemantics(0) == - // VertexDescription.Semantics.POSITION); - // - // point.addAttribute(VertexDescription.Semantics.M); - // Assert.assertTrue(point - // .hasAttribute(VertexDescription.Semantics.POSITION)); - // Assert.assertTrue(!point.hasAttribute(VertexDescription.Semantics.Z)); - // Assert.assertTrue(point.hasAttribute(VertexDescription.Semantics.M)); - // point.dropAttribute(VertexDescription.Semantics.M); - // Assert.assertTrue(!point.hasAttribute(VertexDescription.Semantics.M)); - // - // point.addAttribute(VertexDescription.Semantics.ID); - // Assert.assertTrue(point - // .hasAttribute(VertexDescription.Semantics.POSITION)); - // Assert.assertTrue(!point.hasAttribute(VertexDescription.Semantics.Z)); - // Assert.assertTrue(!point.hasAttribute(VertexDescription.Semantics.M)); - // point.dropAttribute(VertexDescription.Semantics.ID); - // Assert.assertTrue(!point.hasAttribute(VertexDescription.Semantics.ID)); - // - // // TEST_ASSERT(point->IsEmpty()); - // // TEST_ASSERT(point->GetPointCount() == 0); - // // TEST_ASSERT(point->GetPartCount() == 0); - // - // point = null; - // Assert.assertTrue(point == null); - // } + // void CompareGeometryContent(MultiVertexGeometry geom1, + // MultiVertexGeometry geom2) { + // // Geometry types + // Assert.assertTrue(geom1.getType() == geom2.getType()); + // + // // Envelopes + // Envelope env1 = new Envelope(); + // geom1.queryEnvelope(env1); + // + // Envelope env2 = new Envelope(); + // geom2.queryEnvelope(env2); + // + // Assert.assertTrue(env1.getXMin() == env2.getXMin() + // && env1.getXMax() == env2.getXMax() + // && env1.getYMin() == env2.getYMin() + // && env1.getYMax() == env2.getYMax()); + // + // int type = geom1.getType(); + // if (type == Geometry.Type.Polyline || type == Geometry.Type.Polygon) { + // // Part Count + // int partCount1 = ((MultiPath) geom1).getPathCount(); + // int partCount2 = ((MultiPath) geom2).getPathCount(); + // Assert.assertTrue(partCount1 == partCount2); + // + // // Part indices + // for (int i = 0; i < partCount1; i++) { + // int start1 = ((MultiPath) geom1).getPathStart(i); + // int start2 = ((MultiPath) geom2).getPathStart(i); + // Assert.assertTrue(start1 == start2); + // int end1 = ((MultiPath) geom1).getPathEnd(i); + // int end2 = ((MultiPath) geom2).getPathEnd(i); + // Assert.assertTrue(end1 == end2); + // } + // } + // + // // Point count + // int pointCount1 = geom1.getPointCount(); + // int pointCount2 = geom2.getPointCount(); + // Assert.assertTrue(pointCount1 == pointCount2); + // + // if (type == Geometry.Type.MultiPoint || type == Geometry.Type.Polyline + // || type == Geometry.Type.Polygon) { + // MultiVertexGeometryImpl mpGeom1 = (MultiVertexGeometryImpl) geom1 + // ._getImpl(); + // MultiVertexGeometryImpl mpGeom2 = (MultiVertexGeometryImpl) geom2 + // ._getImpl(); + // // POSITION + // AttributeStreamBase positionStream1 = mpGeom1 + // .getAttributeStreamRef(VertexDescription.Semantics.POSITION); + // AttributeStreamOfDbl position1 = (AttributeStreamOfDbl) positionStream1; + // + // AttributeStreamBase positionStream2 = mpGeom2 + // .getAttributeStreamRef(VertexDescription.Semantics.POSITION); + // AttributeStreamOfDbl position2 = (AttributeStreamOfDbl) positionStream2; + // + // for (int i = 0; i < pointCount1; i++) { + // double x1 = position1.read(2 * i); + // double x2 = position2.read(2 * i); + // Assert.assertTrue(x1 == x2); + // + // double y1 = position1.read(2 * i + 1); + // double y2 = position2.read(2 * i + 1); + // Assert.assertTrue(y1 == y2); + // } + // + // // Zs + // boolean bHasZs1 = mpGeom1 + // .hasAttribute(VertexDescription.Semantics.Z); + // boolean bHasZs2 = mpGeom2 + // .hasAttribute(VertexDescription.Semantics.Z); + // Assert.assertTrue(bHasZs1 == bHasZs2); + // + // if (bHasZs1) { + // AttributeStreamBase zStream1 = mpGeom1 + // .getAttributeStreamRef(VertexDescription.Semantics.Z); + // AttributeStreamOfDbl zs1 = (AttributeStreamOfDbl) zStream1; + // + // AttributeStreamBase zStream2 = mpGeom2 + // .getAttributeStreamRef(VertexDescription.Semantics.Z); + // AttributeStreamOfDbl zs2 = (AttributeStreamOfDbl) zStream2; + // + // for (int i = 0; i < pointCount1; i++) { + // double z1 = zs1.read(i); + // double z2 = zs2.read(i); + // Assert.assertTrue(z1 == z2); + // } + // } + // + // // Ms + // boolean bHasMs1 = mpGeom1 + // .hasAttribute(VertexDescription.Semantics.M); + // boolean bHasMs2 = mpGeom2 + // .hasAttribute(VertexDescription.Semantics.M); + // Assert.assertTrue(bHasMs1 == bHasMs2); + // + // if (bHasMs1) { + // AttributeStreamBase mStream1 = mpGeom1 + // .getAttributeStreamRef(VertexDescription.Semantics.M); + // AttributeStreamOfDbl ms1 = (AttributeStreamOfDbl) mStream1; + // + // AttributeStreamBase mStream2 = mpGeom2 + // .getAttributeStreamRef(VertexDescription.Semantics.M); + // AttributeStreamOfDbl ms2 = (AttributeStreamOfDbl) mStream2; + // + // for (int i = 0; i < pointCount1; i++) { + // double m1 = ms1.read(i); + // double m2 = ms2.read(i); + // Assert.assertTrue(m1 == m2); + // } + // } + // + // // IDs + // boolean bHasIDs1 = mpGeom1 + // .hasAttribute(VertexDescription.Semantics.ID); + // boolean bHasIDs2 = mpGeom2 + // .hasAttribute(VertexDescription.Semantics.ID); + // Assert.assertTrue(bHasIDs1 == bHasIDs2); + // + // if (bHasIDs1) { + // AttributeStreamBase idStream1 = mpGeom1 + // .getAttributeStreamRef(VertexDescription.Semantics.ID); + // AttributeStreamOfInt32 ids1 = (AttributeStreamOfInt32) idStream1; + // + // AttributeStreamBase idStream2 = mpGeom2 + // .getAttributeStreamRef(VertexDescription.Semantics.ID); + // AttributeStreamOfInt32 ids2 = (AttributeStreamOfInt32) idStream2; + // + // for (int i = 0; i < pointCount1; i++) { + // int id1 = ids1.read(i); + // int id2 = ids2.read(i); + // Assert.assertTrue(id1 == id2); + // } + // } + // } + // } + // + // void SimpleTest(Geometry point) { + // Assert.assertTrue(point != null); + // point.addAttribute(VertexDescription.Semantics.Z); + // Assert.assertTrue(point + // .hasAttribute(VertexDescription.Semantics.POSITION)); + // Assert.assertTrue(point.hasAttribute(VertexDescription.Semantics.Z)); + // point.addAttribute(VertexDescription.Semantics.Z);// duplicate call + // Assert.assertTrue(point.getDescription().getAttributeCount() == 2); + // Assert + // .assertTrue(point.getDescription().getSemantics(1) == + // VertexDescription.Semantics.Z); + // point.dropAttribute(VertexDescription.Semantics.Z); + // Assert.assertTrue(!point.hasAttribute(VertexDescription.Semantics.Z)); + // point.dropAttribute(VertexDescription.Semantics.Z);// duplicate call + // Assert.assertTrue(!point.hasAttribute(VertexDescription.Semantics.Z)); + // Assert.assertTrue(point.getDescription().getAttributeCount() == 1); + // Assert + // .assertTrue(point.getDescription().getSemantics(0) == + // VertexDescription.Semantics.POSITION); + // + // point.addAttribute(VertexDescription.Semantics.M); + // Assert.assertTrue(point + // .hasAttribute(VertexDescription.Semantics.POSITION)); + // Assert.assertTrue(!point.hasAttribute(VertexDescription.Semantics.Z)); + // Assert.assertTrue(point.hasAttribute(VertexDescription.Semantics.M)); + // point.dropAttribute(VertexDescription.Semantics.M); + // Assert.assertTrue(!point.hasAttribute(VertexDescription.Semantics.M)); + // + // point.addAttribute(VertexDescription.Semantics.ID); + // Assert.assertTrue(point + // .hasAttribute(VertexDescription.Semantics.POSITION)); + // Assert.assertTrue(!point.hasAttribute(VertexDescription.Semantics.Z)); + // Assert.assertTrue(!point.hasAttribute(VertexDescription.Semantics.M)); + // point.dropAttribute(VertexDescription.Semantics.ID); + // Assert.assertTrue(!point.hasAttribute(VertexDescription.Semantics.ID)); + // + // // TEST_ASSERT(point->IsEmpty()); + // // TEST_ASSERT(point->GetPointCount() == 0); + // // TEST_ASSERT(point->GetPartCount() == 0); + // + // point = null; + // Assert.assertTrue(point == null); + // } } diff --git a/src/test/java/com/esri/core/geometry/TestAttributes.java b/src/test/java/com/esri/core/geometry/TestAttributes.java index f16ddb1a..7fc21555 100644 --- a/src/test/java/com/esri/core/geometry/TestAttributes.java +++ b/src/test/java/com/esri/core/geometry/TestAttributes.java @@ -29,319 +29,319 @@ public class TestAttributes extends TestCase { - @Test - public void testPoint() { - Point pt = new Point(); - pt.setXY(100, 200); - assertFalse(pt.hasAttribute(VertexDescription.Semantics.M)); - pt.addAttribute(VertexDescription.Semantics.M); - assertTrue(pt.hasAttribute(VertexDescription.Semantics.M)); - assertTrue(Double.isNaN(pt.getM())); - pt.setAttribute(VertexDescription.Semantics.M, 0, 13); - assertTrue(pt.getM() == 13); - pt.addAttribute(VertexDescription.Semantics.Z); - assertTrue(pt.getZ() == 0); - assertTrue(pt.getM() == 13); - pt.setAttribute(VertexDescription.Semantics.Z, 0, 11); - assertTrue(pt.getZ() == 11); - assertTrue(pt.getM() == 13); - pt.addAttribute(VertexDescription.Semantics.ID); - assertTrue(pt.getID() == 0); - assertTrue(pt.getZ() == 11); - assertTrue(pt.getM() == 13); - pt.setAttribute(VertexDescription.Semantics.ID, 0, 1); - assertTrue(pt.getID() == 1); - assertTrue(pt.getZ() == 11); - assertTrue(pt.getM() == 13); - pt.dropAttribute(VertexDescription.Semantics.M); - assertTrue(pt.getID() == 1); - assertTrue(pt.getZ() == 11); - assertFalse(pt.hasAttribute(VertexDescription.Semantics.M)); - - Point pt1 = new Point(); - assertFalse(pt1.hasAttribute(VertexDescription.Semantics.M)); - assertFalse(pt1.hasAttribute(VertexDescription.Semantics.Z)); - assertFalse(pt1.hasAttribute(VertexDescription.Semantics.ID)); - pt1.mergeVertexDescription(pt.getDescription()); - assertFalse(pt1.hasAttribute(VertexDescription.Semantics.M)); - assertTrue(pt1.hasAttribute(VertexDescription.Semantics.Z)); - assertTrue(pt1.hasAttribute(VertexDescription.Semantics.ID)); - } - - @Test - public void testEnvelope() { - Envelope env = new Envelope(); - env.setCoords(100, 200, 250, 300); - assertFalse(env.hasAttribute(VertexDescription.Semantics.M)); - env.addAttribute(VertexDescription.Semantics.M); - assertTrue(env.hasAttribute(VertexDescription.Semantics.M)); - assertTrue(env.queryInterval(VertexDescription.Semantics.M, 0).isEmpty()); - env.setInterval(VertexDescription.Semantics.M, 0, 1, 2); - assertTrue(env.queryInterval(VertexDescription.Semantics.M, 0).vmin == 1); - assertTrue(env.queryInterval(VertexDescription.Semantics.M, 0).vmax == 2); - - assertFalse(env.hasAttribute(VertexDescription.Semantics.Z)); - env.addAttribute(VertexDescription.Semantics.Z); - assertTrue(env.hasAttribute(VertexDescription.Semantics.Z)); - assertTrue(env.queryInterval(VertexDescription.Semantics.Z, 0).vmin == 0); - assertTrue(env.queryInterval(VertexDescription.Semantics.Z, 0).vmax == 0); - env.setInterval(VertexDescription.Semantics.Z, 0, 3, 4); - assertTrue(env.queryInterval(VertexDescription.Semantics.Z, 0).vmin == 3); - assertTrue(env.queryInterval(VertexDescription.Semantics.Z, 0).vmax == 4); - - - assertFalse(env.hasAttribute(VertexDescription.Semantics.ID)); - env.addAttribute(VertexDescription.Semantics.ID); - assertTrue(env.hasAttribute(VertexDescription.Semantics.ID)); - assertTrue(env.queryInterval(VertexDescription.Semantics.ID, 0).vmin == 0); - assertTrue(env.queryInterval(VertexDescription.Semantics.ID, 0).vmax == 0); - env.setInterval(VertexDescription.Semantics.ID, 0, 5, 6); - assertTrue(env.queryInterval(VertexDescription.Semantics.ID, 0).vmin == 5); - assertTrue(env.queryInterval(VertexDescription.Semantics.ID, 0).vmax == 6); - assertTrue(env.queryInterval(VertexDescription.Semantics.Z, 0).vmin == 3); - assertTrue(env.queryInterval(VertexDescription.Semantics.Z, 0).vmax == 4); - assertTrue(env.queryInterval(VertexDescription.Semantics.M, 0).vmin == 1); - assertTrue(env.queryInterval(VertexDescription.Semantics.M, 0).vmax == 2); - - env.dropAttribute(VertexDescription.Semantics.M); - assertFalse(env.hasAttribute(VertexDescription.Semantics.M)); - assertTrue(env.queryInterval(VertexDescription.Semantics.ID, 0).vmin == 5); - assertTrue(env.queryInterval(VertexDescription.Semantics.ID, 0).vmax == 6); - assertTrue(env.queryInterval(VertexDescription.Semantics.Z, 0).vmin == 3); - assertTrue(env.queryInterval(VertexDescription.Semantics.Z, 0).vmax == 4); - - Envelope env1 = new Envelope(); - env.copyTo(env1); - assertFalse(env1.hasAttribute(VertexDescription.Semantics.M)); - assertTrue(env1.queryInterval(VertexDescription.Semantics.ID, 0).vmin == 5); - assertTrue(env1.queryInterval(VertexDescription.Semantics.ID, 0).vmax == 6); - assertTrue(env1.queryInterval(VertexDescription.Semantics.Z, 0).vmin == 3); - assertTrue(env1.queryInterval(VertexDescription.Semantics.Z, 0).vmax == 4); - } - - @Test - public void testLine() { - Line env = new Line(); - env.setStartXY(100, 200); - env.setEndXY(250, 300); - assertFalse(env.hasAttribute(VertexDescription.Semantics.M)); - env.addAttribute(VertexDescription.Semantics.M); - assertTrue(env.hasAttribute(VertexDescription.Semantics.M)); - env.setStartAttribute(VertexDescription.Semantics.M, 0, 1); - env.setEndAttribute(VertexDescription.Semantics.M, 0, 2); - assertTrue(env.getStartAttributeAsDbl(VertexDescription.Semantics.M, 0) == 1); - assertTrue(env.getEndAttributeAsDbl(VertexDescription.Semantics.M, 0) == 2); - - assertFalse(env.hasAttribute(VertexDescription.Semantics.Z)); - env.addAttribute(VertexDescription.Semantics.Z); - assertTrue(env.hasAttribute(VertexDescription.Semantics.Z)); - env.setStartAttribute(VertexDescription.Semantics.Z, 0, 3); - env.setEndAttribute(VertexDescription.Semantics.Z, 0, 4); - assertTrue(env.getStartAttributeAsDbl(VertexDescription.Semantics.Z, 0) == 3); - assertTrue(env.getEndAttributeAsDbl(VertexDescription.Semantics.Z, 0) == 4); - - - assertFalse(env.hasAttribute(VertexDescription.Semantics.ID)); - env.addAttribute(VertexDescription.Semantics.ID); - assertTrue(env.hasAttribute(VertexDescription.Semantics.ID)); - env.setStartAttribute(VertexDescription.Semantics.ID, 0, 5); - env.setEndAttribute(VertexDescription.Semantics.ID, 0, 6); - assertTrue(env.getStartAttributeAsDbl(VertexDescription.Semantics.ID, 0) == 5); - assertTrue(env.getEndAttributeAsDbl(VertexDescription.Semantics.ID, 0) == 6); - - assertTrue(env.getStartAttributeAsDbl(VertexDescription.Semantics.M, 0) == 1); - assertTrue(env.getEndAttributeAsDbl(VertexDescription.Semantics.M, 0) == 2); - assertTrue(env.getStartAttributeAsDbl(VertexDescription.Semantics.Z, 0) == 3); - assertTrue(env.getEndAttributeAsDbl(VertexDescription.Semantics.Z, 0) == 4); - - env.dropAttribute(VertexDescription.Semantics.M); - assertFalse(env.hasAttribute(VertexDescription.Semantics.M)); - assertTrue(env.getStartAttributeAsDbl(VertexDescription.Semantics.ID, 0) == 5); - assertTrue(env.getEndAttributeAsDbl(VertexDescription.Semantics.ID, 0) == 6); - assertTrue(env.getStartAttributeAsDbl(VertexDescription.Semantics.Z, 0) == 3); - assertTrue(env.getEndAttributeAsDbl(VertexDescription.Semantics.Z, 0) == 4); - - Line env1 = new Line(); - env.copyTo(env1); - assertFalse(env1.hasAttribute(VertexDescription.Semantics.M)); - assertTrue(env.getStartAttributeAsDbl(VertexDescription.Semantics.ID, 0) == 5); - assertTrue(env.getEndAttributeAsDbl(VertexDescription.Semantics.ID, 0) == 6); - assertTrue(env.getStartAttributeAsDbl(VertexDescription.Semantics.Z, 0) == 3); - assertTrue(env.getEndAttributeAsDbl(VertexDescription.Semantics.Z, 0) == 4); - } - - @Test - public void testMultiPoint() { - MultiPoint mp = new MultiPoint(); - mp.add(new Point(100, 200)); - mp.add(new Point(101, 201)); - mp.add(new Point(102, 202)); - assertFalse(mp.hasAttribute(VertexDescription.Semantics.M)); - mp.addAttribute(VertexDescription.Semantics.M); - assertTrue(mp.hasAttribute(VertexDescription.Semantics.M)); - assertTrue(Double.isNaN(mp.getAttributeAsDbl(VertexDescription.Semantics.M, 0, 0))); - assertTrue(Double.isNaN(mp.getAttributeAsDbl(VertexDescription.Semantics.M, 1, 0))); - assertTrue(Double.isNaN(mp.getAttributeAsDbl(VertexDescription.Semantics.M, 2, 0))); - mp.setAttribute(VertexDescription.Semantics.M, 0, 0, 1); - mp.setAttribute(VertexDescription.Semantics.M, 1, 0, 2); - mp.setAttribute(VertexDescription.Semantics.M, 2, 0, 3); - assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.M, 0, 0) == 1); - assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.M, 1, 0) == 2); - assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.M, 2, 0) == 3); - - assertFalse(mp.hasAttribute(VertexDescription.Semantics.Z)); - mp.addAttribute(VertexDescription.Semantics.Z); - assertTrue(mp.hasAttribute(VertexDescription.Semantics.Z)); - assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.Z, 0, 0) == 0); - assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.Z, 1, 0) == 0); - assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.Z, 2, 0) == 0); - mp.setAttribute(VertexDescription.Semantics.Z, 0, 0, 11); - mp.setAttribute(VertexDescription.Semantics.Z, 1, 0, 21); - mp.setAttribute(VertexDescription.Semantics.Z, 2, 0, 31); - assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.M, 0, 0) == 1); - assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.M, 1, 0) == 2); - assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.M, 2, 0) == 3); - assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.Z, 0, 0) == 11); - assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.Z, 1, 0) == 21); - assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.Z, 2, 0) == 31); - - assertFalse(mp.hasAttribute(VertexDescription.Semantics.ID)); - mp.addAttribute(VertexDescription.Semantics.ID); - assertTrue(mp.hasAttribute(VertexDescription.Semantics.ID)); - assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.ID, 0, 0) == 0); - assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.ID, 1, 0) == 0); - assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.ID, 2, 0) == 0); - mp.setAttribute(VertexDescription.Semantics.ID, 0, 0, -11); - mp.setAttribute(VertexDescription.Semantics.ID, 1, 0, -21); - mp.setAttribute(VertexDescription.Semantics.ID, 2, 0, -31); - assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.M, 0, 0) == 1); - assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.M, 1, 0) == 2); - assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.M, 2, 0) == 3); - assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.Z, 0, 0) == 11); - assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.Z, 1, 0) == 21); - assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.Z, 2, 0) == 31); - assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.ID, 0, 0) == -11); - assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.ID, 1, 0) == -21); - assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.ID, 2, 0) == -31); - - mp.dropAttribute(VertexDescription.Semantics.M); - assertFalse(mp.hasAttribute(VertexDescription.Semantics.M)); - assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.Z, 0, 0) == 11); - assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.Z, 1, 0) == 21); - assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.Z, 2, 0) == 31); - assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.ID, 0, 0) == -11); - assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.ID, 1, 0) == -21); - assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.ID, 2, 0) == -31); - - MultiPoint mp1 = new MultiPoint(); - mp.copyTo(mp1); - assertFalse(mp1.hasAttribute(VertexDescription.Semantics.M)); - assertTrue(mp1.getAttributeAsDbl(VertexDescription.Semantics.Z, 0, 0) == 11); - assertTrue(mp1.getAttributeAsDbl(VertexDescription.Semantics.Z, 1, 0) == 21); - assertTrue(mp1.getAttributeAsDbl(VertexDescription.Semantics.Z, 2, 0) == 31); - assertTrue(mp1.getAttributeAsDbl(VertexDescription.Semantics.ID, 0, 0) == -11); - assertTrue(mp1.getAttributeAsDbl(VertexDescription.Semantics.ID, 1, 0) == -21); - assertTrue(mp1.getAttributeAsDbl(VertexDescription.Semantics.ID, 2, 0) == -31); - - mp1.dropAllAttributes(); - mp1.mergeVertexDescription(mp.getDescription()); - assertTrue(mp1.getAttributeAsDbl(VertexDescription.Semantics.Z, 0, 0) == 0); - assertTrue(mp1.getAttributeAsDbl(VertexDescription.Semantics.Z, 1, 0) == 0); - assertTrue(mp1.getAttributeAsDbl(VertexDescription.Semantics.Z, 2, 0) == 0); - assertTrue(Double.isNaN(mp1.getAttributeAsDbl(VertexDescription.Semantics.M, 0, 0))); - assertTrue(Double.isNaN(mp1.getAttributeAsDbl(VertexDescription.Semantics.M, 1, 0))); - assertTrue(Double.isNaN(mp1.getAttributeAsDbl(VertexDescription.Semantics.M, 2, 0))); - assertTrue(mp1.getAttributeAsDbl(VertexDescription.Semantics.ID, 0, 0) == 0); - assertTrue(mp1.getAttributeAsDbl(VertexDescription.Semantics.ID, 1, 0) == 0); - assertTrue(mp1.getAttributeAsDbl(VertexDescription.Semantics.ID, 2, 0) == 0); - - } - - @Test - public void testPolygon() { - Polygon mp = new Polygon(); - mp.startPath(new Point(100, 200)); - mp.lineTo(new Point(101, 201)); - mp.lineTo(new Point(102, 202)); - assertFalse(mp.hasAttribute(VertexDescription.Semantics.M)); - mp.addAttribute(VertexDescription.Semantics.M); - assertTrue(mp.hasAttribute(VertexDescription.Semantics.M)); - assertTrue(Double.isNaN(mp.getAttributeAsDbl(VertexDescription.Semantics.M, 0, 0))); - assertTrue(Double.isNaN(mp.getAttributeAsDbl(VertexDescription.Semantics.M, 1, 0))); - assertTrue(Double.isNaN(mp.getAttributeAsDbl(VertexDescription.Semantics.M, 2, 0))); - mp.setAttribute(VertexDescription.Semantics.M, 0, 0, 1); - mp.setAttribute(VertexDescription.Semantics.M, 1, 0, 2); - mp.setAttribute(VertexDescription.Semantics.M, 2, 0, 3); - assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.M, 0, 0) == 1); - assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.M, 1, 0) == 2); - assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.M, 2, 0) == 3); - - assertFalse(mp.hasAttribute(VertexDescription.Semantics.Z)); - mp.addAttribute(VertexDescription.Semantics.Z); - assertTrue(mp.hasAttribute(VertexDescription.Semantics.Z)); - assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.Z, 0, 0) == 0); - assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.Z, 1, 0) == 0); - assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.Z, 2, 0) == 0); - mp.setAttribute(VertexDescription.Semantics.Z, 0, 0, 11); - mp.setAttribute(VertexDescription.Semantics.Z, 1, 0, 21); - mp.setAttribute(VertexDescription.Semantics.Z, 2, 0, 31); - assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.M, 0, 0) == 1); - assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.M, 1, 0) == 2); - assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.M, 2, 0) == 3); - assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.Z, 0, 0) == 11); - assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.Z, 1, 0) == 21); - assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.Z, 2, 0) == 31); - - assertFalse(mp.hasAttribute(VertexDescription.Semantics.ID)); - mp.addAttribute(VertexDescription.Semantics.ID); - assertTrue(mp.hasAttribute(VertexDescription.Semantics.ID)); - assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.ID, 0, 0) == 0); - assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.ID, 1, 0) == 0); - assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.ID, 2, 0) == 0); - mp.setAttribute(VertexDescription.Semantics.ID, 0, 0, -11); - mp.setAttribute(VertexDescription.Semantics.ID, 1, 0, -21); - mp.setAttribute(VertexDescription.Semantics.ID, 2, 0, -31); - assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.M, 0, 0) == 1); - assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.M, 1, 0) == 2); - assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.M, 2, 0) == 3); - assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.Z, 0, 0) == 11); - assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.Z, 1, 0) == 21); - assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.Z, 2, 0) == 31); - assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.ID, 0, 0) == -11); - assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.ID, 1, 0) == -21); - assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.ID, 2, 0) == -31); - - mp.dropAttribute(VertexDescription.Semantics.M); - assertFalse(mp.hasAttribute(VertexDescription.Semantics.M)); - assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.Z, 0, 0) == 11); - assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.Z, 1, 0) == 21); - assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.Z, 2, 0) == 31); - assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.ID, 0, 0) == -11); - assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.ID, 1, 0) == -21); - assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.ID, 2, 0) == -31); - - Polygon mp1 = new Polygon(); - mp.copyTo(mp1); - assertFalse(mp1.hasAttribute(VertexDescription.Semantics.M)); - assertTrue(mp1.getAttributeAsDbl(VertexDescription.Semantics.Z, 0, 0) == 11); - assertTrue(mp1.getAttributeAsDbl(VertexDescription.Semantics.Z, 1, 0) == 21); - assertTrue(mp1.getAttributeAsDbl(VertexDescription.Semantics.Z, 2, 0) == 31); - assertTrue(mp1.getAttributeAsDbl(VertexDescription.Semantics.ID, 0, 0) == -11); - assertTrue(mp1.getAttributeAsDbl(VertexDescription.Semantics.ID, 1, 0) == -21); - assertTrue(mp1.getAttributeAsDbl(VertexDescription.Semantics.ID, 2, 0) == -31); - - mp1.dropAllAttributes(); - mp1.mergeVertexDescription(mp.getDescription()); - assertTrue(mp1.getAttributeAsDbl(VertexDescription.Semantics.Z, 0, 0) == 0); - assertTrue(mp1.getAttributeAsDbl(VertexDescription.Semantics.Z, 1, 0) == 0); - assertTrue(mp1.getAttributeAsDbl(VertexDescription.Semantics.Z, 2, 0) == 0); - assertTrue(Double.isNaN(mp1.getAttributeAsDbl(VertexDescription.Semantics.M, 0, 0))); - assertTrue(Double.isNaN(mp1.getAttributeAsDbl(VertexDescription.Semantics.M, 1, 0))); - assertTrue(Double.isNaN(mp1.getAttributeAsDbl(VertexDescription.Semantics.M, 2, 0))); - assertTrue(mp1.getAttributeAsDbl(VertexDescription.Semantics.ID, 0, 0) == 0); - assertTrue(mp1.getAttributeAsDbl(VertexDescription.Semantics.ID, 1, 0) == 0); - assertTrue(mp1.getAttributeAsDbl(VertexDescription.Semantics.ID, 2, 0) == 0); - - } + @Test + public void testPoint() { + Point pt = new Point(); + pt.setXY(100, 200); + assertFalse(pt.hasAttribute(VertexDescription.Semantics.M)); + pt.addAttribute(VertexDescription.Semantics.M); + assertTrue(pt.hasAttribute(VertexDescription.Semantics.M)); + assertTrue(Double.isNaN(pt.getM())); + pt.setAttribute(VertexDescription.Semantics.M, 0, 13); + assertTrue(pt.getM() == 13); + pt.addAttribute(VertexDescription.Semantics.Z); + assertTrue(pt.getZ() == 0); + assertTrue(pt.getM() == 13); + pt.setAttribute(VertexDescription.Semantics.Z, 0, 11); + assertTrue(pt.getZ() == 11); + assertTrue(pt.getM() == 13); + pt.addAttribute(VertexDescription.Semantics.ID); + assertTrue(pt.getID() == 0); + assertTrue(pt.getZ() == 11); + assertTrue(pt.getM() == 13); + pt.setAttribute(VertexDescription.Semantics.ID, 0, 1); + assertTrue(pt.getID() == 1); + assertTrue(pt.getZ() == 11); + assertTrue(pt.getM() == 13); + pt.dropAttribute(VertexDescription.Semantics.M); + assertTrue(pt.getID() == 1); + assertTrue(pt.getZ() == 11); + assertFalse(pt.hasAttribute(VertexDescription.Semantics.M)); + + Point pt1 = new Point(); + assertFalse(pt1.hasAttribute(VertexDescription.Semantics.M)); + assertFalse(pt1.hasAttribute(VertexDescription.Semantics.Z)); + assertFalse(pt1.hasAttribute(VertexDescription.Semantics.ID)); + pt1.mergeVertexDescription(pt.getDescription()); + assertFalse(pt1.hasAttribute(VertexDescription.Semantics.M)); + assertTrue(pt1.hasAttribute(VertexDescription.Semantics.Z)); + assertTrue(pt1.hasAttribute(VertexDescription.Semantics.ID)); + } + + @Test + public void testEnvelope() { + Envelope env = new Envelope(); + env.setCoords(100, 200, 250, 300); + assertFalse(env.hasAttribute(VertexDescription.Semantics.M)); + env.addAttribute(VertexDescription.Semantics.M); + assertTrue(env.hasAttribute(VertexDescription.Semantics.M)); + assertTrue(env.queryInterval(VertexDescription.Semantics.M, 0).isEmpty()); + env.setInterval(VertexDescription.Semantics.M, 0, 1, 2); + assertTrue(env.queryInterval(VertexDescription.Semantics.M, 0).vmin == 1); + assertTrue(env.queryInterval(VertexDescription.Semantics.M, 0).vmax == 2); + + assertFalse(env.hasAttribute(VertexDescription.Semantics.Z)); + env.addAttribute(VertexDescription.Semantics.Z); + assertTrue(env.hasAttribute(VertexDescription.Semantics.Z)); + assertTrue(env.queryInterval(VertexDescription.Semantics.Z, 0).vmin == 0); + assertTrue(env.queryInterval(VertexDescription.Semantics.Z, 0).vmax == 0); + env.setInterval(VertexDescription.Semantics.Z, 0, 3, 4); + assertTrue(env.queryInterval(VertexDescription.Semantics.Z, 0).vmin == 3); + assertTrue(env.queryInterval(VertexDescription.Semantics.Z, 0).vmax == 4); + + + assertFalse(env.hasAttribute(VertexDescription.Semantics.ID)); + env.addAttribute(VertexDescription.Semantics.ID); + assertTrue(env.hasAttribute(VertexDescription.Semantics.ID)); + assertTrue(env.queryInterval(VertexDescription.Semantics.ID, 0).vmin == 0); + assertTrue(env.queryInterval(VertexDescription.Semantics.ID, 0).vmax == 0); + env.setInterval(VertexDescription.Semantics.ID, 0, 5, 6); + assertTrue(env.queryInterval(VertexDescription.Semantics.ID, 0).vmin == 5); + assertTrue(env.queryInterval(VertexDescription.Semantics.ID, 0).vmax == 6); + assertTrue(env.queryInterval(VertexDescription.Semantics.Z, 0).vmin == 3); + assertTrue(env.queryInterval(VertexDescription.Semantics.Z, 0).vmax == 4); + assertTrue(env.queryInterval(VertexDescription.Semantics.M, 0).vmin == 1); + assertTrue(env.queryInterval(VertexDescription.Semantics.M, 0).vmax == 2); + + env.dropAttribute(VertexDescription.Semantics.M); + assertFalse(env.hasAttribute(VertexDescription.Semantics.M)); + assertTrue(env.queryInterval(VertexDescription.Semantics.ID, 0).vmin == 5); + assertTrue(env.queryInterval(VertexDescription.Semantics.ID, 0).vmax == 6); + assertTrue(env.queryInterval(VertexDescription.Semantics.Z, 0).vmin == 3); + assertTrue(env.queryInterval(VertexDescription.Semantics.Z, 0).vmax == 4); + + Envelope env1 = new Envelope(); + env.copyTo(env1); + assertFalse(env1.hasAttribute(VertexDescription.Semantics.M)); + assertTrue(env1.queryInterval(VertexDescription.Semantics.ID, 0).vmin == 5); + assertTrue(env1.queryInterval(VertexDescription.Semantics.ID, 0).vmax == 6); + assertTrue(env1.queryInterval(VertexDescription.Semantics.Z, 0).vmin == 3); + assertTrue(env1.queryInterval(VertexDescription.Semantics.Z, 0).vmax == 4); + } + + @Test + public void testLine() { + Line env = new Line(); + env.setStartXY(100, 200); + env.setEndXY(250, 300); + assertFalse(env.hasAttribute(VertexDescription.Semantics.M)); + env.addAttribute(VertexDescription.Semantics.M); + assertTrue(env.hasAttribute(VertexDescription.Semantics.M)); + env.setStartAttribute(VertexDescription.Semantics.M, 0, 1); + env.setEndAttribute(VertexDescription.Semantics.M, 0, 2); + assertTrue(env.getStartAttributeAsDbl(VertexDescription.Semantics.M, 0) == 1); + assertTrue(env.getEndAttributeAsDbl(VertexDescription.Semantics.M, 0) == 2); + + assertFalse(env.hasAttribute(VertexDescription.Semantics.Z)); + env.addAttribute(VertexDescription.Semantics.Z); + assertTrue(env.hasAttribute(VertexDescription.Semantics.Z)); + env.setStartAttribute(VertexDescription.Semantics.Z, 0, 3); + env.setEndAttribute(VertexDescription.Semantics.Z, 0, 4); + assertTrue(env.getStartAttributeAsDbl(VertexDescription.Semantics.Z, 0) == 3); + assertTrue(env.getEndAttributeAsDbl(VertexDescription.Semantics.Z, 0) == 4); + + + assertFalse(env.hasAttribute(VertexDescription.Semantics.ID)); + env.addAttribute(VertexDescription.Semantics.ID); + assertTrue(env.hasAttribute(VertexDescription.Semantics.ID)); + env.setStartAttribute(VertexDescription.Semantics.ID, 0, 5); + env.setEndAttribute(VertexDescription.Semantics.ID, 0, 6); + assertTrue(env.getStartAttributeAsDbl(VertexDescription.Semantics.ID, 0) == 5); + assertTrue(env.getEndAttributeAsDbl(VertexDescription.Semantics.ID, 0) == 6); + + assertTrue(env.getStartAttributeAsDbl(VertexDescription.Semantics.M, 0) == 1); + assertTrue(env.getEndAttributeAsDbl(VertexDescription.Semantics.M, 0) == 2); + assertTrue(env.getStartAttributeAsDbl(VertexDescription.Semantics.Z, 0) == 3); + assertTrue(env.getEndAttributeAsDbl(VertexDescription.Semantics.Z, 0) == 4); + + env.dropAttribute(VertexDescription.Semantics.M); + assertFalse(env.hasAttribute(VertexDescription.Semantics.M)); + assertTrue(env.getStartAttributeAsDbl(VertexDescription.Semantics.ID, 0) == 5); + assertTrue(env.getEndAttributeAsDbl(VertexDescription.Semantics.ID, 0) == 6); + assertTrue(env.getStartAttributeAsDbl(VertexDescription.Semantics.Z, 0) == 3); + assertTrue(env.getEndAttributeAsDbl(VertexDescription.Semantics.Z, 0) == 4); + + Line env1 = new Line(); + env.copyTo(env1); + assertFalse(env1.hasAttribute(VertexDescription.Semantics.M)); + assertTrue(env.getStartAttributeAsDbl(VertexDescription.Semantics.ID, 0) == 5); + assertTrue(env.getEndAttributeAsDbl(VertexDescription.Semantics.ID, 0) == 6); + assertTrue(env.getStartAttributeAsDbl(VertexDescription.Semantics.Z, 0) == 3); + assertTrue(env.getEndAttributeAsDbl(VertexDescription.Semantics.Z, 0) == 4); + } + + @Test + public void testMultiPoint() { + MultiPoint mp = new MultiPoint(); + mp.add(new Point(100, 200)); + mp.add(new Point(101, 201)); + mp.add(new Point(102, 202)); + assertFalse(mp.hasAttribute(VertexDescription.Semantics.M)); + mp.addAttribute(VertexDescription.Semantics.M); + assertTrue(mp.hasAttribute(VertexDescription.Semantics.M)); + assertTrue(Double.isNaN(mp.getAttributeAsDbl(VertexDescription.Semantics.M, 0, 0))); + assertTrue(Double.isNaN(mp.getAttributeAsDbl(VertexDescription.Semantics.M, 1, 0))); + assertTrue(Double.isNaN(mp.getAttributeAsDbl(VertexDescription.Semantics.M, 2, 0))); + mp.setAttribute(VertexDescription.Semantics.M, 0, 0, 1); + mp.setAttribute(VertexDescription.Semantics.M, 1, 0, 2); + mp.setAttribute(VertexDescription.Semantics.M, 2, 0, 3); + assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.M, 0, 0) == 1); + assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.M, 1, 0) == 2); + assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.M, 2, 0) == 3); + + assertFalse(mp.hasAttribute(VertexDescription.Semantics.Z)); + mp.addAttribute(VertexDescription.Semantics.Z); + assertTrue(mp.hasAttribute(VertexDescription.Semantics.Z)); + assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.Z, 0, 0) == 0); + assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.Z, 1, 0) == 0); + assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.Z, 2, 0) == 0); + mp.setAttribute(VertexDescription.Semantics.Z, 0, 0, 11); + mp.setAttribute(VertexDescription.Semantics.Z, 1, 0, 21); + mp.setAttribute(VertexDescription.Semantics.Z, 2, 0, 31); + assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.M, 0, 0) == 1); + assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.M, 1, 0) == 2); + assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.M, 2, 0) == 3); + assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.Z, 0, 0) == 11); + assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.Z, 1, 0) == 21); + assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.Z, 2, 0) == 31); + + assertFalse(mp.hasAttribute(VertexDescription.Semantics.ID)); + mp.addAttribute(VertexDescription.Semantics.ID); + assertTrue(mp.hasAttribute(VertexDescription.Semantics.ID)); + assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.ID, 0, 0) == 0); + assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.ID, 1, 0) == 0); + assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.ID, 2, 0) == 0); + mp.setAttribute(VertexDescription.Semantics.ID, 0, 0, -11); + mp.setAttribute(VertexDescription.Semantics.ID, 1, 0, -21); + mp.setAttribute(VertexDescription.Semantics.ID, 2, 0, -31); + assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.M, 0, 0) == 1); + assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.M, 1, 0) == 2); + assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.M, 2, 0) == 3); + assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.Z, 0, 0) == 11); + assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.Z, 1, 0) == 21); + assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.Z, 2, 0) == 31); + assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.ID, 0, 0) == -11); + assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.ID, 1, 0) == -21); + assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.ID, 2, 0) == -31); + + mp.dropAttribute(VertexDescription.Semantics.M); + assertFalse(mp.hasAttribute(VertexDescription.Semantics.M)); + assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.Z, 0, 0) == 11); + assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.Z, 1, 0) == 21); + assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.Z, 2, 0) == 31); + assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.ID, 0, 0) == -11); + assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.ID, 1, 0) == -21); + assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.ID, 2, 0) == -31); + + MultiPoint mp1 = new MultiPoint(); + mp.copyTo(mp1); + assertFalse(mp1.hasAttribute(VertexDescription.Semantics.M)); + assertTrue(mp1.getAttributeAsDbl(VertexDescription.Semantics.Z, 0, 0) == 11); + assertTrue(mp1.getAttributeAsDbl(VertexDescription.Semantics.Z, 1, 0) == 21); + assertTrue(mp1.getAttributeAsDbl(VertexDescription.Semantics.Z, 2, 0) == 31); + assertTrue(mp1.getAttributeAsDbl(VertexDescription.Semantics.ID, 0, 0) == -11); + assertTrue(mp1.getAttributeAsDbl(VertexDescription.Semantics.ID, 1, 0) == -21); + assertTrue(mp1.getAttributeAsDbl(VertexDescription.Semantics.ID, 2, 0) == -31); + + mp1.dropAllAttributes(); + mp1.mergeVertexDescription(mp.getDescription()); + assertTrue(mp1.getAttributeAsDbl(VertexDescription.Semantics.Z, 0, 0) == 0); + assertTrue(mp1.getAttributeAsDbl(VertexDescription.Semantics.Z, 1, 0) == 0); + assertTrue(mp1.getAttributeAsDbl(VertexDescription.Semantics.Z, 2, 0) == 0); + assertTrue(Double.isNaN(mp1.getAttributeAsDbl(VertexDescription.Semantics.M, 0, 0))); + assertTrue(Double.isNaN(mp1.getAttributeAsDbl(VertexDescription.Semantics.M, 1, 0))); + assertTrue(Double.isNaN(mp1.getAttributeAsDbl(VertexDescription.Semantics.M, 2, 0))); + assertTrue(mp1.getAttributeAsDbl(VertexDescription.Semantics.ID, 0, 0) == 0); + assertTrue(mp1.getAttributeAsDbl(VertexDescription.Semantics.ID, 1, 0) == 0); + assertTrue(mp1.getAttributeAsDbl(VertexDescription.Semantics.ID, 2, 0) == 0); + + } + + @Test + public void testPolygon() { + Polygon mp = new Polygon(); + mp.startPath(new Point(100, 200)); + mp.lineTo(new Point(101, 201)); + mp.lineTo(new Point(102, 202)); + assertFalse(mp.hasAttribute(VertexDescription.Semantics.M)); + mp.addAttribute(VertexDescription.Semantics.M); + assertTrue(mp.hasAttribute(VertexDescription.Semantics.M)); + assertTrue(Double.isNaN(mp.getAttributeAsDbl(VertexDescription.Semantics.M, 0, 0))); + assertTrue(Double.isNaN(mp.getAttributeAsDbl(VertexDescription.Semantics.M, 1, 0))); + assertTrue(Double.isNaN(mp.getAttributeAsDbl(VertexDescription.Semantics.M, 2, 0))); + mp.setAttribute(VertexDescription.Semantics.M, 0, 0, 1); + mp.setAttribute(VertexDescription.Semantics.M, 1, 0, 2); + mp.setAttribute(VertexDescription.Semantics.M, 2, 0, 3); + assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.M, 0, 0) == 1); + assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.M, 1, 0) == 2); + assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.M, 2, 0) == 3); + + assertFalse(mp.hasAttribute(VertexDescription.Semantics.Z)); + mp.addAttribute(VertexDescription.Semantics.Z); + assertTrue(mp.hasAttribute(VertexDescription.Semantics.Z)); + assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.Z, 0, 0) == 0); + assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.Z, 1, 0) == 0); + assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.Z, 2, 0) == 0); + mp.setAttribute(VertexDescription.Semantics.Z, 0, 0, 11); + mp.setAttribute(VertexDescription.Semantics.Z, 1, 0, 21); + mp.setAttribute(VertexDescription.Semantics.Z, 2, 0, 31); + assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.M, 0, 0) == 1); + assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.M, 1, 0) == 2); + assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.M, 2, 0) == 3); + assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.Z, 0, 0) == 11); + assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.Z, 1, 0) == 21); + assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.Z, 2, 0) == 31); + + assertFalse(mp.hasAttribute(VertexDescription.Semantics.ID)); + mp.addAttribute(VertexDescription.Semantics.ID); + assertTrue(mp.hasAttribute(VertexDescription.Semantics.ID)); + assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.ID, 0, 0) == 0); + assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.ID, 1, 0) == 0); + assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.ID, 2, 0) == 0); + mp.setAttribute(VertexDescription.Semantics.ID, 0, 0, -11); + mp.setAttribute(VertexDescription.Semantics.ID, 1, 0, -21); + mp.setAttribute(VertexDescription.Semantics.ID, 2, 0, -31); + assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.M, 0, 0) == 1); + assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.M, 1, 0) == 2); + assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.M, 2, 0) == 3); + assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.Z, 0, 0) == 11); + assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.Z, 1, 0) == 21); + assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.Z, 2, 0) == 31); + assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.ID, 0, 0) == -11); + assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.ID, 1, 0) == -21); + assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.ID, 2, 0) == -31); + + mp.dropAttribute(VertexDescription.Semantics.M); + assertFalse(mp.hasAttribute(VertexDescription.Semantics.M)); + assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.Z, 0, 0) == 11); + assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.Z, 1, 0) == 21); + assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.Z, 2, 0) == 31); + assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.ID, 0, 0) == -11); + assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.ID, 1, 0) == -21); + assertTrue(mp.getAttributeAsDbl(VertexDescription.Semantics.ID, 2, 0) == -31); + + Polygon mp1 = new Polygon(); + mp.copyTo(mp1); + assertFalse(mp1.hasAttribute(VertexDescription.Semantics.M)); + assertTrue(mp1.getAttributeAsDbl(VertexDescription.Semantics.Z, 0, 0) == 11); + assertTrue(mp1.getAttributeAsDbl(VertexDescription.Semantics.Z, 1, 0) == 21); + assertTrue(mp1.getAttributeAsDbl(VertexDescription.Semantics.Z, 2, 0) == 31); + assertTrue(mp1.getAttributeAsDbl(VertexDescription.Semantics.ID, 0, 0) == -11); + assertTrue(mp1.getAttributeAsDbl(VertexDescription.Semantics.ID, 1, 0) == -21); + assertTrue(mp1.getAttributeAsDbl(VertexDescription.Semantics.ID, 2, 0) == -31); + + mp1.dropAllAttributes(); + mp1.mergeVertexDescription(mp.getDescription()); + assertTrue(mp1.getAttributeAsDbl(VertexDescription.Semantics.Z, 0, 0) == 0); + assertTrue(mp1.getAttributeAsDbl(VertexDescription.Semantics.Z, 1, 0) == 0); + assertTrue(mp1.getAttributeAsDbl(VertexDescription.Semantics.Z, 2, 0) == 0); + assertTrue(Double.isNaN(mp1.getAttributeAsDbl(VertexDescription.Semantics.M, 0, 0))); + assertTrue(Double.isNaN(mp1.getAttributeAsDbl(VertexDescription.Semantics.M, 1, 0))); + assertTrue(Double.isNaN(mp1.getAttributeAsDbl(VertexDescription.Semantics.M, 2, 0))); + assertTrue(mp1.getAttributeAsDbl(VertexDescription.Semantics.ID, 0, 0) == 0); + assertTrue(mp1.getAttributeAsDbl(VertexDescription.Semantics.ID, 1, 0) == 0); + assertTrue(mp1.getAttributeAsDbl(VertexDescription.Semantics.ID, 2, 0) == 0); + + } } diff --git a/src/test/java/com/esri/core/geometry/TestBuffer.java b/src/test/java/com/esri/core/geometry/TestBuffer.java index 5008834a..e60145bb 100755 --- a/src/test/java/com/esri/core/geometry/TestBuffer.java +++ b/src/test/java/com/esri/core/geometry/TestBuffer.java @@ -27,373 +27,391 @@ import junit.framework.TestCase; import org.junit.Test; +import com.esri.core.geometry.ogc.OGCGeometry; + public class TestBuffer extends TestCase { - @Override - protected void setUp() throws Exception { - super.setUp(); - } - - @Override - protected void tearDown() throws Exception { - super.tearDown(); - } - - @Test - public void testBufferPolytonWKT() { - String wkt = "MULTIPOLYGON (((-98.42049 46.08456, -98.42052 46.08682, -98.40509 46.08681, -98.40511 46.08456, -98.42049 46.08456)))"; - SpatialReference sr = SpatialReference.create(4326); - com.esri.core.geometry.Geometry geom = com.esri.core.geometry.OperatorImportFromWkt.local().execute(0, com.esri.core.geometry.Geometry.Type.Unknown, wkt, null); - com.esri.core.geometry.Geometry buffered = com.esri.core.geometry.OperatorBuffer.local().execute(geom, sr, 2.0, null); - String exportedGeom = com.esri.core.geometry.OperatorExportToWkt.local().execute(0, buffered, null); - int position = exportedGeom.indexOf('('); - assertEquals("MULTIPOLYGON", exportedGeom.substring(0, position - 1)); - } - - @Test - public void testBufferPoint() { - SpatialReference sr = SpatialReference.create(4326); - Point inputGeom = new Point(12, 120); - OperatorBuffer buffer = (OperatorBuffer) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.Buffer); - OperatorSimplify simplify = (OperatorSimplify) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.Simplify); - Geometry result = buffer.execute(inputGeom, sr, 40.0, null); - assertTrue(result.getType().value() == Geometry.GeometryType.Polygon); - Polygon poly = (Polygon) result; - int pathCount = poly.getPathCount(); - assertTrue(pathCount == 1); - int pointCount = poly.getPointCount(); - assertTrue(Math.abs(pointCount - 100.0) < 10); - Envelope2D env2D = new Envelope2D(); - result.queryEnvelope2D(env2D); - assertTrue(Math.abs(env2D.getWidth() - 80) < 0.01 - && Math.abs(env2D.getHeight() - 80) < 0.01); - assertTrue(Math.abs(env2D.getCenterX() - 12) < 0.001 - && Math.abs(env2D.getCenterY() - 120) < 0.001); - NonSimpleResult nsr = new NonSimpleResult(); - boolean is_simple = simplify.isSimpleAsFeature(result, sr, true, nsr, - null); - assertTrue(is_simple); - - { - result = buffer.execute(inputGeom, sr, 0, null); - assertTrue(result.getType().value() == Geometry.GeometryType.Polygon); - assertTrue(result.isEmpty()); - } - - { - result = buffer.execute(inputGeom, sr, -1, null); - assertTrue(result.getType().value() == Geometry.GeometryType.Polygon); - assertTrue(result.isEmpty()); - } - } - - @Test - public void testBufferEnvelope() { - SpatialReference sr = SpatialReference.create(4326); - Envelope inputGeom = new Envelope(1, 0, 200, 400); - OperatorBuffer buffer = (OperatorBuffer) OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Buffer); - OperatorSimplify simplify = (OperatorSimplify) OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Simplify); - Geometry result = buffer.execute(inputGeom, sr, 40.0, null); - assertTrue(result.getType().value() == Geometry.GeometryType.Polygon); - Polygon poly = (Polygon) (result); - Envelope2D env2D = new Envelope2D(); - result.queryEnvelope2D(env2D); - assertTrue(Math.abs(env2D.getWidth() - (80 + 199)) < 0.001 - && Math.abs(env2D.getHeight() - (80 + 400)) < 0.001); - assertTrue(Math.abs(env2D.getCenterX() - 201.0 / 2) < 0.001 - && Math.abs(env2D.getCenterY() - 400 / 2.0) < 0.001); - int pathCount = poly.getPathCount(); - assertTrue(pathCount == 1); - int pointCount = poly.getPointCount(); - assertTrue(Math.abs(pointCount - 104.0) < 10); - NonSimpleResult nsr = new NonSimpleResult(); - assertTrue(simplify.isSimpleAsFeature(result, sr, true, nsr, null)); - - { - result = buffer.execute(inputGeom, sr, -200.0, null); - assertTrue(result.getType().value() == Geometry.GeometryType.Polygon); - assertTrue(result.isEmpty()); - } - - { - result = buffer.execute(inputGeom, sr, -200.0, null); - assertTrue(result.getType().value() == Geometry.GeometryType.Polygon); - assertTrue(result.isEmpty()); - } - - { - result = buffer.execute(inputGeom, sr, -199 / 2.0, null); - assertTrue(result.getType().value() == Geometry.GeometryType.Polygon); - assertTrue(result.isEmpty()); - } - - { - result = buffer.execute(inputGeom, sr, -50.0, null); - poly = (Polygon) (result); - result.queryEnvelope2D(env2D); - assertTrue(Math.abs(env2D.getWidth() - (199 - 100)) < 0.001 - && Math.abs(env2D.getHeight() - (400 - 100)) < 0.001); - assertTrue(Math.abs(env2D.getCenterX() - 201.0 / 2) < 0.001 - && Math.abs(env2D.getCenterY() - 400 / 2.0) < 0.001); - pathCount = poly.getPathCount(); - assertTrue(pathCount == 1); - pointCount = poly.getPointCount(); - assertTrue(Math.abs(pointCount - 4.0) < 10); - assertTrue(simplify.isSimpleAsFeature(result, sr, null)); - } - } - - @Test - public void testBufferMultiPoint() { - SpatialReference sr = SpatialReference.create(4326); - OperatorBuffer buffer = (OperatorBuffer) OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Buffer); - OperatorSimplify simplify = (OperatorSimplify) OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Simplify); - MultiPoint inputGeom = new MultiPoint(); - inputGeom.add(12, 120); - inputGeom.add(20, 120); - Geometry result = buffer.execute(inputGeom, sr, 40.0, null); - assertTrue(result.getType().value() == Geometry.GeometryType.Polygon); - Polygon poly = (Polygon) (result); - Envelope2D env2D = new Envelope2D(); - result.queryEnvelope2D(env2D); - assertTrue(Math.abs(env2D.getWidth() - 80 - 8) < 0.001 - && Math.abs(env2D.getHeight() - 80) < 0.001); - assertTrue(Math.abs(env2D.getCenterX() - 16) < 0.001 - && Math.abs(env2D.getCenterY() - 120) < 0.001); - int pathCount = poly.getPathCount(); - assertTrue(pathCount == 1); - int pointCount = poly.getPointCount(); - assertTrue(Math.abs(pointCount - 108.0) < 10); - assertTrue(simplify.isSimpleAsFeature(result, sr, null)); - - { - result = buffer.execute(inputGeom, sr, 0, null); - assertTrue(result.getType().value() == Geometry.GeometryType.Polygon); - assertTrue(result.isEmpty()); - } - - { - result = buffer.execute(inputGeom, sr, -1, null); - assertTrue(result.getType().value() == Geometry.GeometryType.Polygon); - assertTrue(result.isEmpty()); - } - } - - @Test - public void testBufferLine() { - SpatialReference sr = SpatialReference.create(4326); - Line inputGeom = new Line(12, 120, 20, 120); - OperatorBuffer buffer = (OperatorBuffer) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.Buffer); - OperatorSimplify simplify = (OperatorSimplify) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.Simplify); - Geometry result = buffer.execute(inputGeom, sr, 40.0, null); - assertTrue(result.getType().value() == Geometry.GeometryType.Polygon); - Polygon poly = (Polygon) (result); - Envelope2D env2D = new Envelope2D(); - result.queryEnvelope2D(env2D); - assertTrue(Math.abs(env2D.getWidth() - 80 - 8) < 0.001 - && Math.abs(env2D.getHeight() - 80) < 0.001); - assertTrue(Math.abs(env2D.getCenterX() - 16) < 0.001 - && Math.abs(env2D.getCenterY() - 120) < 0.001); - int pathCount = poly.getPathCount(); - assertTrue(pathCount == 1); - int pointCount = poly.getPointCount(); - assertTrue(Math.abs(pointCount - 100.0) < 10); - assertTrue(simplify.isSimpleAsFeature(result, sr, null)); - - { - result = buffer.execute(inputGeom, sr, 0, null); - assertTrue(result.getType().value() == Geometry.GeometryType.Polygon); - assertTrue(result.isEmpty()); - } - - { - result = buffer.execute(inputGeom, sr, -1, null); - assertTrue(result.getType().value() == Geometry.GeometryType.Polygon); - assertTrue(result.isEmpty()); - } - } - - @Test - public void testBufferPolyline() { - SpatialReference sr = SpatialReference.create(4326); - Polyline inputGeom = new Polyline(); - OperatorBuffer buffer = (OperatorBuffer) OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Buffer); - OperatorSimplify simplify = (OperatorSimplify) OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Simplify); - inputGeom.startPath(0, 0); - inputGeom.lineTo(50, 50); - inputGeom.lineTo(50, 0); - inputGeom.lineTo(0, 50); - - { - Geometry result = buffer.execute(inputGeom, sr, 0, null); - assertTrue(result.getType().value() == Geometry.GeometryType.Polygon); - assertTrue(result.isEmpty()); - } - - { - Geometry result = buffer.execute(inputGeom, sr, -1, null); - assertTrue(result.getType().value() == Geometry.GeometryType.Polygon); - assertTrue(result.isEmpty()); - } - - { - Geometry result = buffer.execute(inputGeom, sr, 40.0, null); - assertTrue(result.getType().value() == Geometry.GeometryType.Polygon); - Polygon poly = (Polygon) (result); - Envelope2D env2D = new Envelope2D(); - result.queryEnvelope2D(env2D); - assertTrue(Math.abs(env2D.getWidth() - 80 - 50) < 0.1 - && Math.abs(env2D.getHeight() - 80 - 50) < 0.1); - assertTrue(Math.abs(env2D.getCenterX() - 25) < 0.1 - && Math.abs(env2D.getCenterY() - 25) < 0.1); - int pathCount = poly.getPathCount(); - assertTrue(pathCount == 1); - int pointCount = poly.getPointCount(); - assertTrue(Math.abs(pointCount - 171.0) < 10); - assertTrue(simplify.isSimpleAsFeature(result, sr, null)); - } - - { - Geometry result = buffer.execute(inputGeom, sr, 4.0, null); - assertTrue(result.getType().value() == Geometry.GeometryType.Polygon); - Polygon poly = (Polygon) (result); - Envelope2D env2D = new Envelope2D(); - result.queryEnvelope2D(env2D); - assertTrue(Math.abs(env2D.getWidth() - 8 - 50) < 0.1 - && Math.abs(env2D.getHeight() - 8 - 50) < 0.1); - assertTrue(Math.abs(env2D.getCenterX() - 25) < 0.1 - && Math.abs(env2D.getCenterY() - 25) < 0.1); - int pathCount = poly.getPathCount(); - assertTrue(pathCount == 2); - int pointCount = poly.getPointCount(); - assertTrue(Math.abs(pointCount - 186.0) < 10); - assertTrue(simplify.isSimpleAsFeature(result, sr, null)); - } - - { - inputGeom = new Polyline(); - inputGeom.startPath(0, 0); - inputGeom.lineTo(50, 50); - inputGeom.startPath(50, 0); - inputGeom.lineTo(0, 50); - - Geometry result = buffer.execute(inputGeom, sr, 4.0, null); - assertTrue(result.getType().value() == Geometry.GeometryType.Polygon); - Polygon poly = (Polygon) (result); - Envelope2D env2D = new Envelope2D(); - result.queryEnvelope2D(env2D); - assertTrue(Math.abs(env2D.getWidth() - 8 - 50) < 0.1 - && Math.abs(env2D.getHeight() - 8 - 50) < 0.1); - assertTrue(Math.abs(env2D.getCenterX() - 25) < 0.1 - && Math.abs(env2D.getCenterY() - 25) < 0.1); - int pathCount = poly.getPathCount(); - assertTrue(pathCount == 1); - int pointCount = poly.getPointCount(); - assertTrue(Math.abs(pointCount - 208.0) < 10); - assertTrue(simplify.isSimpleAsFeature(result, sr, null)); - } - - { - inputGeom = new Polyline(); - inputGeom.startPath(1.762614, 0.607368); - inputGeom.lineTo(1.762414, 0.606655); - inputGeom.lineTo(1.763006, 0.607034); - inputGeom.lineTo(1.762548, 0.607135); - - Geometry result = buffer.execute(inputGeom, sr, 0.005, null); - assertTrue(simplify.isSimpleAsFeature(result, sr, null)); - } - } - - @Test - public void testBufferPolygon() { - SpatialReference sr = SpatialReference.create(4326); - Polygon inputGeom = new Polygon(); - OperatorBuffer buffer = (OperatorBuffer) OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Buffer); - OperatorSimplify simplify = (OperatorSimplify) OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Simplify); - inputGeom.startPath(0, 0); - inputGeom.lineTo(50, 50); - inputGeom.lineTo(50, 0); - - { - Geometry result = buffer.execute(inputGeom, sr, 0, null); - assertTrue(result.getType().value() == Geometry.GeometryType.Polygon); - assertTrue(result == inputGeom); - } - - { - Geometry result = buffer.execute(inputGeom, sr, 10, null); - assertTrue(result.getType().value() == Geometry.GeometryType.Polygon); - Polygon poly = (Polygon) (result); - Envelope2D env2D = new Envelope2D(); - result.queryEnvelope2D(env2D); - assertTrue(Math.abs(env2D.getWidth() - 20 - 50) < 0.1 - && Math.abs(env2D.getHeight() - 20 - 50) < 0.1); - assertTrue(Math.abs(env2D.getCenterX() - 25) < 0.1 - && Math.abs(env2D.getCenterY() - 25) < 0.1); - int pathCount = poly.getPathCount(); - assertTrue(pathCount == 1); - int pointCount = poly.getPointCount(); - assertTrue(Math.abs(pointCount - 104.0) < 10); - assertTrue(simplify.isSimpleAsFeature(result, sr, null)); - } - - { - sr = SpatialReference.create(4326); - inputGeom = new Polygon(); - inputGeom.startPath(0, 0); - inputGeom.lineTo(50, 50); - inputGeom.lineTo(50, 0); - - Geometry result = buffer.execute(inputGeom, sr, -10, null); - assertTrue(result.getType().value() == Geometry.GeometryType.Polygon); - Polygon poly = (Polygon) (result); - Envelope2D env2D = new Envelope2D(); - result.queryEnvelope2D(env2D); - assertTrue(Math.abs(env2D.getWidth() - 15.85) < 0.1 - && Math.abs(env2D.getHeight() - 15.85) < 0.1); - assertTrue(Math.abs(env2D.getCenterX() - 32.07) < 0.1 - && Math.abs(env2D.getCenterY() - 17.93) < 0.1); - int pathCount = poly.getPathCount(); - assertTrue(pathCount == 1); - int pointCount = poly.getPointCount(); - assertTrue(pointCount == 3); - assertTrue(simplify.isSimpleAsFeature(result, sr, null)); - } - - { - sr = SpatialReference.create(4326); - inputGeom = new Polygon(); - inputGeom.startPath(0, 0); - inputGeom.lineTo(0, 50); - inputGeom.lineTo(50, 50); - inputGeom.lineTo(50, 0); - inputGeom.startPath(10, 10); - inputGeom.lineTo(40, 10); - inputGeom.lineTo(40, 40); - inputGeom.lineTo(10, 40); - - Geometry result = buffer.execute(inputGeom, sr, -2, null); - assertTrue(result.getType().value() == Geometry.GeometryType.Polygon); - Polygon poly = (Polygon) (result); - Envelope2D env2D = new Envelope2D(); - result.queryEnvelope2D(env2D); - assertTrue(Math.abs(env2D.getWidth() + 4 - 50) < 0.1 - && Math.abs(env2D.getHeight() + 4 - 50) < 0.1); - assertTrue(Math.abs(env2D.getCenterX() - 25) < 0.1 - && Math.abs(env2D.getCenterY() - 25) < 0.1); - int pathCount = poly.getPathCount(); - assertTrue(pathCount == 2); - int pointCount = poly.getPointCount(); - assertTrue(Math.abs(pointCount - 108) < 10); - assertTrue(simplify.isSimpleAsFeature(result, sr, null)); - } - } + @Override + protected void setUp() throws Exception { + super.setUp(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + } + + @Test + public void testBufferPoint() { + SpatialReference sr = SpatialReference.create(4326); + Point inputGeom = new Point(12, 120); + OperatorBuffer buffer = (OperatorBuffer) OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Buffer); + OperatorSimplify simplify = (OperatorSimplify) OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Simplify); + Geometry result = buffer.execute(inputGeom, sr, 40.0, null); + assertTrue(result.getType().value() == Geometry.GeometryType.Polygon); + Polygon poly = (Polygon) result; + int pathCount = poly.getPathCount(); + assertTrue(pathCount == 1); + int pointCount = poly.getPointCount(); + assertTrue(Math.abs(pointCount - 100.0) < 10); + Envelope2D env2D = new Envelope2D(); + result.queryEnvelope2D(env2D); + assertTrue(Math.abs(env2D.getWidth() - 80) < 0.01 + && Math.abs(env2D.getHeight() - 80) < 0.01); + assertTrue(Math.abs(env2D.getCenterX() - 12) < 0.001 + && Math.abs(env2D.getCenterY() - 120) < 0.001); + NonSimpleResult nsr = new NonSimpleResult(); + boolean is_simple = simplify.isSimpleAsFeature(result, sr, true, nsr, + null); + assertTrue(is_simple); + + { + result = buffer.execute(inputGeom, sr, 0, null); + assertTrue(result.getType().value() == Geometry.GeometryType.Polygon); + assertTrue(result.isEmpty()); + } + + { + result = buffer.execute(inputGeom, sr, -1, null); + assertTrue(result.getType().value() == Geometry.GeometryType.Polygon); + assertTrue(result.isEmpty()); + } + } + + @Test + public void testBufferEnvelope() { + SpatialReference sr = SpatialReference.create(4326); + Envelope inputGeom = new Envelope(1, 0, 200, 400); + OperatorBuffer buffer = (OperatorBuffer) OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Buffer); + OperatorSimplify simplify = (OperatorSimplify) OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Simplify); + Geometry result = buffer.execute(inputGeom, sr, 40.0, null); + assertTrue(result.getType().value() == Geometry.GeometryType.Polygon); + Polygon poly = (Polygon) (result); + Envelope2D env2D = new Envelope2D(); + result.queryEnvelope2D(env2D); + assertTrue(Math.abs(env2D.getWidth() - (80 + 199)) < 0.001 + && Math.abs(env2D.getHeight() - (80 + 400)) < 0.001); + assertTrue(Math.abs(env2D.getCenterX() - 201.0 / 2) < 0.001 + && Math.abs(env2D.getCenterY() - 400 / 2.0) < 0.001); + int pathCount = poly.getPathCount(); + assertTrue(pathCount == 1); + int pointCount = poly.getPointCount(); + assertTrue(Math.abs(pointCount - 104.0) < 10); + NonSimpleResult nsr = new NonSimpleResult(); + assertTrue(simplify.isSimpleAsFeature(result, sr, true, nsr, null)); + + { + result = buffer.execute(inputGeom, sr, -200.0, null); + assertTrue(result.getType().value() == Geometry.GeometryType.Polygon); + assertTrue(result.isEmpty()); + } + + { + result = buffer.execute(inputGeom, sr, -200.0, null); + assertTrue(result.getType().value() == Geometry.GeometryType.Polygon); + assertTrue(result.isEmpty()); + } + + { + result = buffer.execute(inputGeom, sr, -199 / 2.0, null); + assertTrue(result.getType().value() == Geometry.GeometryType.Polygon); + assertTrue(result.isEmpty()); + } + + { + result = buffer.execute(inputGeom, sr, -50.0, null); + poly = (Polygon) (result); + result.queryEnvelope2D(env2D); + assertTrue(Math.abs(env2D.getWidth() - (199 - 100)) < 0.001 + && Math.abs(env2D.getHeight() - (400 - 100)) < 0.001); + assertTrue(Math.abs(env2D.getCenterX() - 201.0 / 2) < 0.001 + && Math.abs(env2D.getCenterY() - 400 / 2.0) < 0.001); + pathCount = poly.getPathCount(); + assertTrue(pathCount == 1); + pointCount = poly.getPointCount(); + assertTrue(Math.abs(pointCount - 4.0) < 10); + assertTrue(simplify.isSimpleAsFeature(result, sr, null)); + } + } + + @Test + public void testBufferMultiPoint() { + SpatialReference sr = SpatialReference.create(4326); + OperatorBuffer buffer = (OperatorBuffer) OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Buffer); + OperatorSimplify simplify = (OperatorSimplify) OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Simplify); + MultiPoint inputGeom = new MultiPoint(); + inputGeom.add(12, 120); + inputGeom.add(20, 120); + Geometry result = buffer.execute(inputGeom, sr, 40.0, null); + assertTrue(result.getType().value() == Geometry.GeometryType.Polygon); + Polygon poly = (Polygon) (result); + Envelope2D env2D = new Envelope2D(); + result.queryEnvelope2D(env2D); + assertTrue(Math.abs(env2D.getWidth() - 80 - 8) < 0.001 + && Math.abs(env2D.getHeight() - 80) < 0.001); + assertTrue(Math.abs(env2D.getCenterX() - 16) < 0.001 + && Math.abs(env2D.getCenterY() - 120) < 0.001); + int pathCount = poly.getPathCount(); + assertTrue(pathCount == 1); + int pointCount = poly.getPointCount(); + assertTrue(Math.abs(pointCount - 108.0) < 10); + assertTrue(simplify.isSimpleAsFeature(result, sr, null)); + + { + result = buffer.execute(inputGeom, sr, 0, null); + assertTrue(result.getType().value() == Geometry.GeometryType.Polygon); + assertTrue(result.isEmpty()); + } + + { + result = buffer.execute(inputGeom, sr, -1, null); + assertTrue(result.getType().value() == Geometry.GeometryType.Polygon); + assertTrue(result.isEmpty()); + } + } + + @Test + public void testBufferLine() { + SpatialReference sr = SpatialReference.create(4326); + Line inputGeom = new Line(12, 120, 20, 120); + OperatorBuffer buffer = (OperatorBuffer) OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Buffer); + OperatorSimplify simplify = (OperatorSimplify) OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Simplify); + Geometry result = buffer.execute(inputGeom, sr, 40.0, null); + assertTrue(result.getType().value() == Geometry.GeometryType.Polygon); + Polygon poly = (Polygon) (result); + Envelope2D env2D = new Envelope2D(); + result.queryEnvelope2D(env2D); + assertTrue(Math.abs(env2D.getWidth() - 80 - 8) < 0.001 + && Math.abs(env2D.getHeight() - 80) < 0.001); + assertTrue(Math.abs(env2D.getCenterX() - 16) < 0.001 + && Math.abs(env2D.getCenterY() - 120) < 0.001); + int pathCount = poly.getPathCount(); + assertTrue(pathCount == 1); + int pointCount = poly.getPointCount(); + assertTrue(Math.abs(pointCount - 100.0) < 10); + assertTrue(simplify.isSimpleAsFeature(result, sr, null)); + + { + result = buffer.execute(inputGeom, sr, 0, null); + assertTrue(result.getType().value() == Geometry.GeometryType.Polygon); + assertTrue(result.isEmpty()); + } + + { + result = buffer.execute(inputGeom, sr, -1, null); + assertTrue(result.getType().value() == Geometry.GeometryType.Polygon); + assertTrue(result.isEmpty()); + } + } + + @Test + public void testBufferPolyline() { + SpatialReference sr = SpatialReference.create(4326); + Polyline inputGeom = new Polyline(); + OperatorBuffer buffer = (OperatorBuffer) OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Buffer); + OperatorSimplify simplify = (OperatorSimplify) OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Simplify); + inputGeom.startPath(0, 0); + inputGeom.lineTo(50, 50); + inputGeom.lineTo(50, 0); + inputGeom.lineTo(0, 50); + + { + Geometry result = buffer.execute(inputGeom, sr, 0, null); + assertTrue(result.getType().value() == Geometry.GeometryType.Polygon); + assertTrue(result.isEmpty()); + } + + { + Geometry result = buffer.execute(inputGeom, sr, -1, null); + assertTrue(result.getType().value() == Geometry.GeometryType.Polygon); + assertTrue(result.isEmpty()); + } + + { + Geometry result = buffer.execute(inputGeom, sr, 40.0, null); + assertTrue(result.getType().value() == Geometry.GeometryType.Polygon); + Polygon poly = (Polygon) (result); + Envelope2D env2D = new Envelope2D(); + result.queryEnvelope2D(env2D); + assertTrue(Math.abs(env2D.getWidth() - 80 - 50) < 0.1 + && Math.abs(env2D.getHeight() - 80 - 50) < 0.1); + assertTrue(Math.abs(env2D.getCenterX() - 25) < 0.1 + && Math.abs(env2D.getCenterY() - 25) < 0.1); + int pathCount = poly.getPathCount(); + assertTrue(pathCount == 1); + int pointCount = poly.getPointCount(); + assertTrue(Math.abs(pointCount - 171.0) < 10); + assertTrue(simplify.isSimpleAsFeature(result, sr, null)); + } + + { + Geometry result = buffer.execute(inputGeom, sr, 4.0, null); + assertTrue(result.getType().value() == Geometry.GeometryType.Polygon); + Polygon poly = (Polygon) (result); + Envelope2D env2D = new Envelope2D(); + result.queryEnvelope2D(env2D); + assertTrue(Math.abs(env2D.getWidth() - 8 - 50) < 0.1 + && Math.abs(env2D.getHeight() - 8 - 50) < 0.1); + assertTrue(Math.abs(env2D.getCenterX() - 25) < 0.1 + && Math.abs(env2D.getCenterY() - 25) < 0.1); + int pathCount = poly.getPathCount(); + assertTrue(pathCount == 2); + int pointCount = poly.getPointCount(); + assertTrue(Math.abs(pointCount - 186.0) < 10); + assertTrue(simplify.isSimpleAsFeature(result, sr, null)); + } + + { + inputGeom = new Polyline(); + inputGeom.startPath(0, 0); + inputGeom.lineTo(50, 50); + inputGeom.startPath(50, 0); + inputGeom.lineTo(0, 50); + + Geometry result = buffer.execute(inputGeom, sr, 4.0, null); + assertTrue(result.getType().value() == Geometry.GeometryType.Polygon); + Polygon poly = (Polygon) (result); + Envelope2D env2D = new Envelope2D(); + result.queryEnvelope2D(env2D); + assertTrue(Math.abs(env2D.getWidth() - 8 - 50) < 0.1 + && Math.abs(env2D.getHeight() - 8 - 50) < 0.1); + assertTrue(Math.abs(env2D.getCenterX() - 25) < 0.1 + && Math.abs(env2D.getCenterY() - 25) < 0.1); + int pathCount = poly.getPathCount(); + assertTrue(pathCount == 1); + int pointCount = poly.getPointCount(); + assertTrue(Math.abs(pointCount - 208.0) < 10); + assertTrue(simplify.isSimpleAsFeature(result, sr, null)); + } + + { + inputGeom = new Polyline(); + inputGeom.startPath(1.762614,0.607368); + inputGeom.lineTo(1.762414,0.606655); + inputGeom.lineTo(1.763006,0.607034); + inputGeom.lineTo(1.762548,0.607135); + + Geometry result = buffer.execute(inputGeom, sr, 0.005, null); + assertTrue(simplify.isSimpleAsFeature(result, sr, null)); + } + } + + @Test + public void testBufferPolygon() { + SpatialReference sr = SpatialReference.create(4326); + Polygon inputGeom = new Polygon(); + OperatorBuffer buffer = (OperatorBuffer) OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Buffer); + OperatorSimplify simplify = (OperatorSimplify) OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Simplify); + inputGeom.startPath(0, 0); + inputGeom.lineTo(50, 50); + inputGeom.lineTo(50, 0); + + { + Geometry result = buffer.execute(inputGeom, sr, 0, null); + assertTrue(result.getType().value() == Geometry.GeometryType.Polygon); + assertTrue(result == inputGeom); + } + + { + Geometry result = buffer.execute(inputGeom, sr, 10, null); + assertTrue(result.getType().value() == Geometry.GeometryType.Polygon); + Polygon poly = (Polygon) (result); + Envelope2D env2D = new Envelope2D(); + result.queryEnvelope2D(env2D); + assertTrue(Math.abs(env2D.getWidth() - 20 - 50) < 0.1 + && Math.abs(env2D.getHeight() - 20 - 50) < 0.1); + assertTrue(Math.abs(env2D.getCenterX() - 25) < 0.1 + && Math.abs(env2D.getCenterY() - 25) < 0.1); + int pathCount = poly.getPathCount(); + assertTrue(pathCount == 1); + int pointCount = poly.getPointCount(); + assertTrue(Math.abs(pointCount - 104.0) < 10); + assertTrue(simplify.isSimpleAsFeature(result, sr, null)); + } + + { + sr = SpatialReference.create(4326); + inputGeom = new Polygon(); + inputGeom.startPath(0, 0); + inputGeom.lineTo(50, 50); + inputGeom.lineTo(50, 0); + + Geometry result = buffer.execute(inputGeom, sr, -10, null); + assertTrue(result.getType().value() == Geometry.GeometryType.Polygon); + Polygon poly = (Polygon) (result); + Envelope2D env2D = new Envelope2D(); + result.queryEnvelope2D(env2D); + assertTrue(Math.abs(env2D.getWidth() - 15.85) < 0.1 + && Math.abs(env2D.getHeight() - 15.85) < 0.1); + assertTrue(Math.abs(env2D.getCenterX() - 32.07) < 0.1 + && Math.abs(env2D.getCenterY() - 17.93) < 0.1); + int pathCount = poly.getPathCount(); + assertTrue(pathCount == 1); + int pointCount = poly.getPointCount(); + assertTrue(pointCount == 3); + assertTrue(simplify.isSimpleAsFeature(result, sr, null)); + } + + { + sr = SpatialReference.create(4326); + inputGeom = new Polygon(); + inputGeom.startPath(0, 0); + inputGeom.lineTo(0, 50); + inputGeom.lineTo(50, 50); + inputGeom.lineTo(50, 0); + inputGeom.startPath(10, 10); + inputGeom.lineTo(40, 10); + inputGeom.lineTo(40, 40); + inputGeom.lineTo(10, 40); + + Geometry result = buffer.execute(inputGeom, sr, -2, null); + assertTrue(result.getType().value() == Geometry.GeometryType.Polygon); + Polygon poly = (Polygon) (result); + Envelope2D env2D = new Envelope2D(); + result.queryEnvelope2D(env2D); + assertTrue(Math.abs(env2D.getWidth() + 4 - 50) < 0.1 + && Math.abs(env2D.getHeight() + 4 - 50) < 0.1); + assertTrue(Math.abs(env2D.getCenterX() - 25) < 0.1 + && Math.abs(env2D.getCenterY() - 25) < 0.1); + int pathCount = poly.getPathCount(); + assertTrue(pathCount == 2); + int pointCount = poly.getPointCount(); + assertTrue(Math.abs(pointCount - 108) < 10); + assertTrue(simplify.isSimpleAsFeature(result, sr, null)); + } + } + + @Test + public static void testTinyBufferOfPoint() { + { + Geometry result1 = OperatorBuffer.local().execute(new Point(0, 0), SpatialReference.create(4326), 1e-9, null); + assertTrue(result1 != null); + assertTrue(result1.isEmpty()); + Geometry geom1 = OperatorImportFromWkt.local().execute(0, Geometry.Type.Unknown, "POLYGON ((177.0 64.0, 177.0000000001 64.0, 177.0000000001 64.0000000001, 177.0 64.0000000001, 177.0 64.0))", null); + Geometry result2 = OperatorBuffer.local().execute(geom1, SpatialReference.create(4326), 0.01, null); + assertTrue(result2 != null); + assertTrue(result2.isEmpty()); + + } + + { + OGCGeometry p = OGCGeometry.fromText( + "POLYGON ((177.0 64.0, 177.0000000001 64.0, 177.0000000001 64.0000000001, 177.0 64.0000000001, 177.0 64.0))"); + OGCGeometry buffered = p.buffer(0.01); + assertTrue(buffered != null); + } + + + } } diff --git a/src/test/java/com/esri/core/geometry/TestCentroid.java b/src/test/java/com/esri/core/geometry/TestCentroid.java new file mode 100644 index 00000000..3065ec9e --- /dev/null +++ b/src/test/java/com/esri/core/geometry/TestCentroid.java @@ -0,0 +1,169 @@ +/* + Copyright 1995-2017 Esri + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + For additional information, contact: + Environmental Systems Research Institute, Inc. + Attn: Contracts Dept + 380 New York Street + Redlands, California, USA 92373 + + email: contracts@esri.com + */ +package com.esri.core.geometry; + +import org.junit.Assert; +import org.junit.Test; + +public class TestCentroid { + @Test + public void testPoint() { + assertCentroid(new Point(1, 2), new Point2D(1, 2)); + } + + @Test + public void testLine() { + assertCentroid(new Line(0, 0, 10, 20), new Point2D(5, 10)); + } + + @Test + public void testEnvelope() { + assertCentroid(new Envelope(1, 2, 3, 4), new Point2D(2, 3)); + assertCentroidEmpty(new Envelope()); + } + + @Test + public void testMultiPoint() { + MultiPoint multiPoint = new MultiPoint(); + multiPoint.add(0, 0); + multiPoint.add(1, 2); + multiPoint.add(3, 1); + multiPoint.add(0, 1); + + assertCentroid(multiPoint, new Point2D(1, 1)); + assertCentroidEmpty(new MultiPoint()); + } + + @Test + public void testPolyline() { + Polyline polyline = new Polyline(); + polyline.startPath(0, 0); + polyline.lineTo(1, 2); + polyline.lineTo(3, 4); + assertCentroid(polyline, new Point2D(1.3377223398316207, 2.1169631197754946)); + + polyline.startPath(1, -1); + polyline.lineTo(2, 0); + polyline.lineTo(10, 1); + assertCentroid(polyline, new Point2D(3.93851092460519, 0.9659173294165462)); + + assertCentroidEmpty(new Polyline()); + } + + @Test + public void testPolygon() { + Polygon polygon = new Polygon(); + polygon.startPath(0, 0); + polygon.lineTo(1, 2); + polygon.lineTo(3, 4); + polygon.lineTo(5, 2); + polygon.lineTo(0, 0); + assertCentroid(polygon, new Point2D(2.5, 2)); + + // add a hole + polygon.startPath(2, 2); + polygon.lineTo(2.3, 2); + polygon.lineTo(2.3, 2.4); + polygon.lineTo(2, 2); + assertCentroid(polygon, new Point2D(2.5022670025188916, 1.9989924433249369)); + + // add another polygon + polygon.startPath(-1, -1); + polygon.lineTo(3, -1); + polygon.lineTo(0.5, -2); + polygon.lineTo(-1, -1); + assertCentroid(polygon, new Point2D(2.166465459423206, 1.3285043594902748)); + + assertCentroidEmpty(new Polygon()); + } + + @Test + public void testSmallPolygon() { + // https://github.com/Esri/geometry-api-java/issues/225 + + Polygon polygon = new Polygon(); + polygon.startPath(153.492818, -28.13729); + polygon.lineTo(153.492821, -28.137291); + polygon.lineTo(153.492816, -28.137289); + polygon.lineTo(153.492818, -28.13729); + + assertCentroid(polygon, new Point2D(153.492818333333333, -28.13729)); + } + + @Test + public void testZeroAreaPolygon() { + Polygon polygon = new Polygon(); + polygon.startPath(153, 28); + polygon.lineTo(163, 28); + polygon.lineTo(153, 28); + + Polyline polyline = (Polyline) polygon.getBoundary(); + Point2D expectedCentroid = new Point2D(158, 28); + + assertCentroid(polyline, expectedCentroid); + assertCentroid(polygon, expectedCentroid); + } + + @Test + public void testDegeneratesToPointPolygon() { + Polygon polygon = new Polygon(); + polygon.startPath(-8406364, 560828); + polygon.lineTo(-8406364, 560828); + polygon.lineTo(-8406364, 560828); + polygon.lineTo(-8406364, 560828); + + assertCentroid(polygon, new Point2D(-8406364, 560828)); + } + + @Test + public void testZeroLengthPolyline() { + Polyline polyline = new Polyline(); + polyline.startPath(153, 28); + polyline.lineTo(153, 28); + + assertCentroid(polyline, new Point2D(153, 28)); + } + + @Test + public void testDegeneratesToPointPolyline() { + Polyline polyline = new Polyline(); + polyline.startPath(-8406364, 560828); + polyline.lineTo(-8406364, 560828); + + assertCentroid(polyline, new Point2D(-8406364, 560828)); + } + + private static void assertCentroid(Geometry geometry, Point2D expectedCentroid) { + + Point2D actualCentroid = OperatorCentroid2D.local().execute(geometry, null); + Assert.assertEquals(expectedCentroid.x, actualCentroid.x, 1e-13); + Assert.assertEquals(expectedCentroid.y, actualCentroid.y, 1e-13); + } + + private static void assertCentroidEmpty(Geometry geometry) { + + Point2D actualCentroid = OperatorCentroid2D.local().execute(geometry, null); + Assert.assertTrue(actualCentroid == null); + } +} diff --git a/src/test/java/com/esri/core/geometry/TestCircles.java b/src/test/java/com/esri/core/geometry/TestCircles.java index 3e2a68eb..4bff60d2 100644 --- a/src/test/java/com/esri/core/geometry/TestCircles.java +++ b/src/test/java/com/esri/core/geometry/TestCircles.java @@ -7,162 +7,162 @@ import java.util.HashMap; public class TestCircles extends TestCase { - @Test - public void testSquare() { - Polygon polygon = new Polygon(); - polygon.startPath(-2, -2); - polygon.lineTo(-2, 2); - polygon.lineTo(2, 2); - polygon.lineTo(2, -2); - polygon.closeAllPaths(); - OperatorEnclosingCircleCursor operatorEnclosingCircleCursor = new OperatorEnclosingCircleCursor(new SimpleGeometryCursor(polygon), null, null); - Geometry geometry = operatorEnclosingCircleCursor.next(); - double radius = Math.sqrt(2*2 + 2*2); - double area = Math.PI * radius * radius; - assertEquals(geometry.calculateArea2D(), area, 1e-1); - } - - @Test - public void testBuffered() { - Point center = new Point(0,0); - Geometry buffered = GeometryEngine.buffer(center, SpatialReference.create(4326), 20); - OperatorEnclosingCircleCursor operatorEnclosingCircleCursor = new OperatorEnclosingCircleCursor(new SimpleGeometryCursor(buffered), null, null); - Geometry geometry = operatorEnclosingCircleCursor.next(); - assertEquals(geometry.calculateArea2D(), buffered.calculateArea2D(), 1e-10); - assertTrue(GeometryEngine.equals(geometry, buffered, null)); - } - - @Test - public void testGeodesicBuffer() { - Point center = new Point(0,0); - Geometry buffered = OperatorGeodesicBuffer.local().execute(center, - SpatialReference.create(4326), - GeodeticCurveType.Geodesic, - 4000, - 20, - false, - null); - - OperatorEnclosingCircleCursor operatorEnclosingCircleCursor = new OperatorEnclosingCircleCursor( - new SimpleGeometryCursor(buffered), - SpatialReference.create(4326), - null); - - Geometry geometry = operatorEnclosingCircleCursor.next(); - // This tests fails without multiVertexGeometry._setDirtyFlag(DirtyFlags.dirtyAll, true); in project - assertEquals(geometry.calculateArea2D(), buffered.calculateArea2D(), 1e-4); - - Geometry bufferedContainer = OperatorGeodesicBuffer.local().execute(center, - SpatialReference.create(4326), - GeodeticCurveType.Geodesic, - 4050, - 20, - false, - null); - assertTrue(GeometryEngine.contains(bufferedContainer, geometry, SpatialReference.create(4326))); - } - - @Test - public void testBufferedClipped() { - Point center = new Point(0,0); - Geometry buffered = GeometryEngine.buffer(center, SpatialReference.create(4326), 20); - Geometry clipped = GeometryEngine.clip(buffered, new Envelope(0, -20, 40, 40), null); - OperatorEnclosingCircleCursor operatorEnclosingCircleCursor = new OperatorEnclosingCircleCursor(new SimpleGeometryCursor(clipped), null, null); - Geometry geometry = operatorEnclosingCircleCursor.next(); - assertEquals(geometry.calculateArea2D(), buffered.calculateArea2D(), 1e-10); - assertTrue(GeometryEngine.equals(geometry, buffered, null)); - } - - @Test - public void testBufferedClippedUnionedSmall() { - Point center = new Point(0,0); - Geometry buffered = GeometryEngine.buffer(center, SpatialReference.create(4326), 20); - Geometry clipped = GeometryEngine.clip(buffered, new Envelope(0, -20, 40, 40), null); - Geometry bufferedSmall = GeometryEngine.buffer(center, SpatialReference.create(4326), 10); - Geometry[] two = new Geometry[] {bufferedSmall, clipped}; - Geometry unionedGeom = GeometryEngine.union(two, null); - OperatorEnclosingCircleCursor operatorEnclosingCircleCursor = new OperatorEnclosingCircleCursor(new SimpleGeometryCursor(unionedGeom), null, null); - Geometry geometry = operatorEnclosingCircleCursor.next(); - assertEquals(geometry.calculateArea2D(), buffered.calculateArea2D(), 1e-10); - assertTrue(GeometryEngine.equals(geometry, buffered, null)); - } - - - @Test - public void testRandomPoints() { - int count = 400; - Envelope e = new Envelope(0,0,40, 40); - RandomCoordinateGenerator randomCoordinateGenerator = new RandomCoordinateGenerator(count, e, SpatialReference.create(4326).getTolerance()); - MultiPoint multiPoint = new MultiPoint(); - for (int i = 0; i < count; i++) { - multiPoint.add(randomCoordinateGenerator._GenerateNewPoint()); - } - - int run_count = 10; - ArrayDeque geometries = new ArrayDeque<>(); - for (int i = 0; i < run_count; i++) { - OperatorEnclosingCircleCursor operatorEnclosingCircleCursor = new OperatorEnclosingCircleCursor(new SimpleGeometryCursor(multiPoint), SpatialReference.create(4326), null); - Geometry geometry = operatorEnclosingCircleCursor.next(); - geometries.add(geometry); - } + @Test + public void testSquare() { + Polygon polygon = new Polygon(); + polygon.startPath(-2, -2); + polygon.lineTo(-2, 2); + polygon.lineTo(2, 2); + polygon.lineTo(2, -2); + polygon.closeAllPaths(); + OperatorEnclosingCircleCursor operatorEnclosingCircleCursor = new OperatorEnclosingCircleCursor(new SimpleGeometryCursor(polygon), null, null); + Geometry geometry = operatorEnclosingCircleCursor.next(); + double radius = Math.sqrt(2 * 2 + 2 * 2); + double area = Math.PI * radius * radius; + assertEquals(geometry.calculateArea2D(), area, 1e-1); + } + + @Test + public void testBuffered() { + Point center = new Point(0, 0); + Geometry buffered = GeometryEngine.buffer(center, SpatialReference.create(4326), 20); + OperatorEnclosingCircleCursor operatorEnclosingCircleCursor = new OperatorEnclosingCircleCursor(new SimpleGeometryCursor(buffered), null, null); + Geometry geometry = operatorEnclosingCircleCursor.next(); + assertEquals(geometry.calculateArea2D(), buffered.calculateArea2D(), 1e-10); + assertTrue(GeometryEngine.equals(geometry, buffered, null)); + } + + @Test + public void testGeodesicBuffer() { + Point center = new Point(0, 0); + Geometry buffered = OperatorGeodesicBuffer.local().execute(center, + SpatialReference.create(4326), + GeodeticCurveType.Geodesic, + 4000, + 20, + false, + null); + + OperatorEnclosingCircleCursor operatorEnclosingCircleCursor = new OperatorEnclosingCircleCursor( + new SimpleGeometryCursor(buffered), + SpatialReference.create(4326), + null); + + Geometry geometry = operatorEnclosingCircleCursor.next(); + // This tests fails without multiVertexGeometry._setDirtyFlag(DirtyFlags.dirtyAll, true); in project + assertEquals(geometry.calculateArea2D(), buffered.calculateArea2D(), 1e-4); + + Geometry bufferedContainer = OperatorGeodesicBuffer.local().execute(center, + SpatialReference.create(4326), + GeodeticCurveType.Geodesic, + 4050, + 20, + false, + null); + assertTrue(GeometryEngine.contains(bufferedContainer, geometry, SpatialReference.create(4326))); + } + + @Test + public void testBufferedClipped() { + Point center = new Point(0, 0); + Geometry buffered = GeometryEngine.buffer(center, SpatialReference.create(4326), 20); + Geometry clipped = GeometryEngine.clip(buffered, new Envelope(0, -20, 40, 40), null); + OperatorEnclosingCircleCursor operatorEnclosingCircleCursor = new OperatorEnclosingCircleCursor(new SimpleGeometryCursor(clipped), null, null); + Geometry geometry = operatorEnclosingCircleCursor.next(); + assertEquals(geometry.calculateArea2D(), buffered.calculateArea2D(), 1e-10); + assertTrue(GeometryEngine.equals(geometry, buffered, null)); + } + + @Test + public void testBufferedClippedUnionedSmall() { + Point center = new Point(0, 0); + Geometry buffered = GeometryEngine.buffer(center, SpatialReference.create(4326), 20); + Geometry clipped = GeometryEngine.clip(buffered, new Envelope(0, -20, 40, 40), null); + Geometry bufferedSmall = GeometryEngine.buffer(center, SpatialReference.create(4326), 10); + Geometry[] two = new Geometry[]{bufferedSmall, clipped}; + Geometry unionedGeom = GeometryEngine.union(two, null); + OperatorEnclosingCircleCursor operatorEnclosingCircleCursor = new OperatorEnclosingCircleCursor(new SimpleGeometryCursor(unionedGeom), null, null); + Geometry geometry = operatorEnclosingCircleCursor.next(); + assertEquals(geometry.calculateArea2D(), buffered.calculateArea2D(), 1e-10); + assertTrue(GeometryEngine.equals(geometry, buffered, null)); + } + + + @Test + public void testRandomPoints() { + int count = 400; + Envelope e = new Envelope(0, 0, 40, 40); + RandomCoordinateGenerator randomCoordinateGenerator = new RandomCoordinateGenerator(count, e, SpatialReference.create(4326).getTolerance()); + MultiPoint multiPoint = new MultiPoint(); + for (int i = 0; i < count; i++) { + multiPoint.add(randomCoordinateGenerator._GenerateNewPoint()); + } + + int run_count = 10; + ArrayDeque geometries = new ArrayDeque<>(); + for (int i = 0; i < run_count; i++) { + OperatorEnclosingCircleCursor operatorEnclosingCircleCursor = new OperatorEnclosingCircleCursor(new SimpleGeometryCursor(multiPoint), SpatialReference.create(4326), null); + Geometry geometry = operatorEnclosingCircleCursor.next(); + geometries.add(geometry); + } // http://opensourceconnections.com/blog/2014/04/11/indexing-polygons-in-lucene-with-accuracy/ // http://my-spatial4j-project.blogspot.be/2014/01/minimum-bounding-circle-algorithm-jts.html - Geometry firstGeometry = geometries.peekFirst(); - OperatorEquals operatorEquals = (OperatorEquals) (OperatorFactoryLocal.getInstance().getOperator(Operator.Type.Equals)); - HashMap results = operatorEquals.execute(firstGeometry, new SimpleGeometryCursor(geometries), SpatialReference.create(4326), null); - for (Long key : results.keySet()) { - assertTrue(results.get(key)); - } - } - - @Test - public void testReproject() { - String wktGeom = "MULTIPOLYGON (((-70.64802717477117 43.128706076602874, -70.6479465414909 43.128714649179535, -70.64788357509747 43.1287487128581, -70.64783854531692 43.12880812176545, -70.64781164513992 43.12889262152996, -70.64780298999258 43.12900185036985, -70.64781261723796 43.12913534064154, -70.6478404860113 43.12929252084091, -70.64788647738838 43.129472718047886, -70.64795039488814 43.129675160806016, -70.6480319653057 43.129898982422475, -70.64813083987421 43.13014322467642, -70.64824659574889 43.13040684191825, -70.64837873780841 43.13068870554328, -70.64852670076544 43.1309876088204, -70.64868985157774 43.131302272055365, -70.64886749214907 43.13163134806583, -70.64905886230987 43.13197342794668, -70.64926314306291 43.132327047097704, -70.64947946008277 43.13269069149233, -70.64970688745207 43.13306280415637, -70.64994445161977 43.13344179183187, -70.65019113556465 43.133826031796644, -70.65044588314564 43.134213878809994, -70.6507076036211 43.13460367215594, -70.65097517631722 43.134993742752336, -70.6512474554263 43.135382420297674, -70.65152327491325 43.135768040422036, -70.65180145351054 43.13614895181459, -70.65208079977953 43.13652352329523, -70.652360117216 43.13689015080003, -70.65263820937935 43.1372472642522, -70.65291388502193 43.137593334287445, -70.65318596319706 43.13792687880496, -70.65345327832425 43.138246469317686, -70.65371468518873 43.138550737072336, -70.65396906385456 43.138838378914386, -70.65421532446969 43.139108162872276, -70.65445241194281 43.139358933437414, -70.65467931047083 43.13958961651619, -70.6548950478984 43.13979922403416, -70.65509869988989 43.1399868581709, -70.65528939389672 43.14015171520967, -70.65546631290157 43.14029308898237, -70.65562869892466 43.140410373897815, -70.65577585627611 43.140503067538305, -70.65590715454054 43.14057077281427, -70.65602203128121 43.14061319966741, -70.65611999445184 43.14063016631512, -70.65620062450573 43.14062160003068, -70.65626357619321 43.14058753745568, -70.65630858004002 43.14052812444448, -70.65633544349907 43.14044361543887, -70.65634405177256 43.1403343723787, -70.6563343682994 43.14020086315083, -70.6563064349065 43.14004365958389, -70.65626037162373 43.13986343499769, -70.65619637616243 43.13966096131707, -70.65611472306145 43.13943710576406, -70.65601576250236 43.139192827140086, -70.65589991880132 43.13892917171714, -70.65576768858229 43.13864726875311, -70.65561963864108 43.13834832565221, -70.65545640350835 43.13803362279019, -70.65527868272287 43.13770450802718, -70.65508723782693 43.13736239093172, -70.65488288909637 43.137008736740526, -70.65466651201972 43.13664506007974, -70.65443903354196 43.136272918475676, -70.6542014280886 43.13589390568142, -70.65395471338735 43.13550964484906, -70.65369994610545 43.13512178157618, -70.65343821732164 43.13473197685713, -70.65317064785184 43.13434189996841, -70.65289838344866 43.1339532213195, -70.6526225898955 43.133567605299014, -70.65234444801612 43.13318670314755, -70.652065148621 43.13281214588721, -70.65178588741227 43.132445537338526, -70.6515078598685 43.13208844725394, -70.65123225613159 43.13174240459792, -70.65096025591802 43.13140889100291, -70.65069302347425 43.131089334426754, -70.65043170260032 43.13078510304208, -70.65017741176095 43.130497499381256, -70.64993123930526 43.130227754762316, -70.64969423881631 43.12997702402096, -70.64946742460877 43.12974638056925, -70.64925176739531 43.12953681180378, -70.64904819013898 43.12934921488169, -70.64885756410969 43.12918439288311, -70.64868070516164 43.12904305137656, -70.64851837024698 43.128925795401116, -70.64837125418116 43.12883312687935, -70.64823998667316 43.12876544247107, -70.64812512963337 43.128723031877364, -70.64802717477117 43.128706076602874)))"; - Geometry geometry = OperatorImportFromWkt.local().execute(0, Geometry.Type.Unknown, wktGeom, null); - ProjectionTransformation projectionTransformation = ProjectionTransformation.getEqualArea(geometry, SpatialReference.create(4326)); - Geometry projected = OperatorProject.local().execute(geometry, projectionTransformation, null); - Envelope envelope = new Envelope(); - projected.queryEnvelope(envelope); - Point2D centerXY = envelope.getCenter2D(); - - double minRadius = Double.MAX_VALUE; - double maxRadius = Double.MIN_VALUE; - for (Point2D point2D : ((MultiVertexGeometry)geometry).getCoordinates2D()) { - double radius = Point2D.distance(point2D, centerXY); - if (radius > maxRadius) { - maxRadius = radius; - } - if (radius < minRadius) { - minRadius = radius; - } - } - assertEquals(minRadius, maxRadius, 0.01); - } - - @Test - public void testVsGeodesicBuffer() { - // POINT (-70.651886936570745 43.134525834585826) - Point point = new Point(-70.651886936570745, 43.1345088834585826); - SpatialReference spatialReferenceWGS84 = SpatialReference.create(4326); - Geometry geodesicBuffered = OperatorGeodesicBuffer.local().execute( - point, - spatialReferenceWGS84, - GeodeticCurveType.Geodesic, - 148.7, - 0.07, - false, - null); - - String wktInput = "POLYGON ((-70.651656936570745 43.135157834585826,-70.651570654984525 43.135150076925918,-70.651511247908587 43.135155437576621,-70.651490101488349 43.135169249238288,-70.651490181628759 43.135200763774868,-70.651510336532638 43.135249995303397,-70.651530872098633 43.135299226354952,-70.651527230781454 43.13533529757845,-70.651492643684321 43.135349305799508,-70.651420172717224 43.135354852495823,-70.651358095085072 43.135346745253884,-70.651247805462717 43.1353033127629,-70.651151361236941 43.135246176463966,-70.651124154255413 43.135206047556842,-70.651131534466685 43.135151913051203,-70.651155914561755 43.135115542493892,-70.651228730259774 43.135051460048707,-70.651305024993519 43.134973818456416,-70.651360674948108 43.134914489191551,-70.651385078643216 43.134864606853156,-70.651402827815218 43.134810322639233,-70.651410310326284 43.134688652284062,-70.651418383361829 43.134517448375689,-70.651411370788409 43.134413996600074,-70.651390876709428 43.134337752182525,-70.651346755889904 43.134225832686319,-70.651289063395154 43.134109606122337,-70.651241242017051 43.133988734078358,-70.651230854601764 43.133916846697829,-70.651221013347353 43.133822439140715,-70.651200519724128 43.133746194674302,-70.651218268699594 43.133691907971006,-70.651249886578313 43.133610413350418,-70.651273539332081 43.133547040518167,-70.651322422674269 43.133478800504768,-70.651363984222755 43.133424172537978,-70.651409243106613 43.133378494590104,-70.651437060507462 43.133355583224628,-70.651492145648632 43.133332275678633,-70.651599176252716 43.133326227462319,-70.651675204034788 43.133338636120527,-70.65179240423565 43.133381970944697,-70.651905761872953 43.133425353603045,-70.652022336036893 43.133459688797871,-70.652087607730962 43.133472252516562,-70.652149929372143 43.133489361765591,-70.652232540703992 43.133546699550045,-70.652400720753761 43.133656829257461,-70.652544825855031 43.133771806958798,-70.652698657471404 43.133891149422396,-70.652757214424 43.133939825915917,-70.652829643131227 43.133961291723317,-70.652898471779253 43.133991812912122,-70.652963804959569 43.134049399817712,-70.652994471176711 43.134089475795044,-70.653000937222828 43.134129903976664,-70.653000836372897 43.134197439788288,-70.652972837499135 43.134256375321229,-70.652903321638362 43.134342923487154,-70.652853489821567 43.134447199036558,-70.652811504521395 43.134528843881576,-70.652776716073816 43.134592380423527,-70.652745241323998 43.134664872485907,-70.652703717209832 43.134692485155824,-70.65263790191085 43.134702441934749,-70.652537796343609 43.13469488220742,-70.652481986521252 43.134691185475688,-70.652416288981371 43.134705643385693,-70.652347112331768 43.134733655368471,-70.652274294763117 43.134797738553125,-70.652239263183958 43.134852272522785,-70.652214826278225 43.134929165745028,-70.652217533236211 43.135001163954207,-70.652248296977746 43.135059250554882,-70.652327397729081 43.135157158057844,-70.652414500765317 43.135209927851037,-70.6524582645621 43.135222802033766,-70.652470512866358 43.135249637832572,-70.652646824360005 43.135404671730349,-70.652680946443695 43.135444700365824,-70.652691113545444 43.135494075980539,-70.652680299690047 43.135534756334458,-70.652642334694633 43.135580326883741,-70.6525831461027 43.135608197219,-70.65250042683256 43.135618395612582,-70.652403778584315 43.1356107883392,-70.652328034290349 43.135580366756479,-70.652207940292428 43.135501055652128,-70.652084166050003 43.135399292820672,-70.651994153636025 43.135324055019495,-70.651897729053019 43.13525341019011,-70.651815354685922 43.135205077192047,-70.651746646220062 43.135179051560065,-70.651656936570745 43.135157834585826))"; - Geometry input = OperatorImportFromWkt.local().execute(0, Geometry.Type.Unknown, wktInput, null); - Geometry encircled = OperatorEnclosingCircle.local().execute(input, spatialReferenceWGS84, null); + Geometry firstGeometry = geometries.peekFirst(); + OperatorEquals operatorEquals = (OperatorEquals) (OperatorFactoryLocal.getInstance().getOperator(Operator.Type.Equals)); + HashMap results = operatorEquals.execute(firstGeometry, new SimpleGeometryCursor(geometries), SpatialReference.create(4326), null); + for (Long key : results.keySet()) { + assertTrue(results.get(key)); + } + } + + @Test + public void testReproject() { + String wktGeom = "MULTIPOLYGON (((-70.64802717477117 43.128706076602874, -70.6479465414909 43.128714649179535, -70.64788357509747 43.1287487128581, -70.64783854531692 43.12880812176545, -70.64781164513992 43.12889262152996, -70.64780298999258 43.12900185036985, -70.64781261723796 43.12913534064154, -70.6478404860113 43.12929252084091, -70.64788647738838 43.129472718047886, -70.64795039488814 43.129675160806016, -70.6480319653057 43.129898982422475, -70.64813083987421 43.13014322467642, -70.64824659574889 43.13040684191825, -70.64837873780841 43.13068870554328, -70.64852670076544 43.1309876088204, -70.64868985157774 43.131302272055365, -70.64886749214907 43.13163134806583, -70.64905886230987 43.13197342794668, -70.64926314306291 43.132327047097704, -70.64947946008277 43.13269069149233, -70.64970688745207 43.13306280415637, -70.64994445161977 43.13344179183187, -70.65019113556465 43.133826031796644, -70.65044588314564 43.134213878809994, -70.6507076036211 43.13460367215594, -70.65097517631722 43.134993742752336, -70.6512474554263 43.135382420297674, -70.65152327491325 43.135768040422036, -70.65180145351054 43.13614895181459, -70.65208079977953 43.13652352329523, -70.652360117216 43.13689015080003, -70.65263820937935 43.1372472642522, -70.65291388502193 43.137593334287445, -70.65318596319706 43.13792687880496, -70.65345327832425 43.138246469317686, -70.65371468518873 43.138550737072336, -70.65396906385456 43.138838378914386, -70.65421532446969 43.139108162872276, -70.65445241194281 43.139358933437414, -70.65467931047083 43.13958961651619, -70.6548950478984 43.13979922403416, -70.65509869988989 43.1399868581709, -70.65528939389672 43.14015171520967, -70.65546631290157 43.14029308898237, -70.65562869892466 43.140410373897815, -70.65577585627611 43.140503067538305, -70.65590715454054 43.14057077281427, -70.65602203128121 43.14061319966741, -70.65611999445184 43.14063016631512, -70.65620062450573 43.14062160003068, -70.65626357619321 43.14058753745568, -70.65630858004002 43.14052812444448, -70.65633544349907 43.14044361543887, -70.65634405177256 43.1403343723787, -70.6563343682994 43.14020086315083, -70.6563064349065 43.14004365958389, -70.65626037162373 43.13986343499769, -70.65619637616243 43.13966096131707, -70.65611472306145 43.13943710576406, -70.65601576250236 43.139192827140086, -70.65589991880132 43.13892917171714, -70.65576768858229 43.13864726875311, -70.65561963864108 43.13834832565221, -70.65545640350835 43.13803362279019, -70.65527868272287 43.13770450802718, -70.65508723782693 43.13736239093172, -70.65488288909637 43.137008736740526, -70.65466651201972 43.13664506007974, -70.65443903354196 43.136272918475676, -70.6542014280886 43.13589390568142, -70.65395471338735 43.13550964484906, -70.65369994610545 43.13512178157618, -70.65343821732164 43.13473197685713, -70.65317064785184 43.13434189996841, -70.65289838344866 43.1339532213195, -70.6526225898955 43.133567605299014, -70.65234444801612 43.13318670314755, -70.652065148621 43.13281214588721, -70.65178588741227 43.132445537338526, -70.6515078598685 43.13208844725394, -70.65123225613159 43.13174240459792, -70.65096025591802 43.13140889100291, -70.65069302347425 43.131089334426754, -70.65043170260032 43.13078510304208, -70.65017741176095 43.130497499381256, -70.64993123930526 43.130227754762316, -70.64969423881631 43.12997702402096, -70.64946742460877 43.12974638056925, -70.64925176739531 43.12953681180378, -70.64904819013898 43.12934921488169, -70.64885756410969 43.12918439288311, -70.64868070516164 43.12904305137656, -70.64851837024698 43.128925795401116, -70.64837125418116 43.12883312687935, -70.64823998667316 43.12876544247107, -70.64812512963337 43.128723031877364, -70.64802717477117 43.128706076602874)))"; + Geometry geometry = OperatorImportFromWkt.local().execute(0, Geometry.Type.Unknown, wktGeom, null); + ProjectionTransformation projectionTransformation = ProjectionTransformation.getEqualArea(geometry, SpatialReference.create(4326)); + Geometry projected = OperatorProject.local().execute(geometry, projectionTransformation, null); + Envelope envelope = new Envelope(); + projected.queryEnvelope(envelope); + Point2D centerXY = envelope.getCenter2D(); + + double minRadius = Double.MAX_VALUE; + double maxRadius = Double.MIN_VALUE; + for (Point2D point2D : ((MultiVertexGeometry) geometry).getCoordinates2D()) { + double radius = Point2D.distance(point2D, centerXY); + if (radius > maxRadius) { + maxRadius = radius; + } + if (radius < minRadius) { + minRadius = radius; + } + } + assertEquals(minRadius, maxRadius, 0.01); + } + + @Test + public void testVsGeodesicBuffer() { + // POINT (-70.651886936570745 43.134525834585826) + Point point = new Point(-70.651886936570745, 43.1345088834585826); + SpatialReference spatialReferenceWGS84 = SpatialReference.create(4326); + Geometry geodesicBuffered = OperatorGeodesicBuffer.local().execute( + point, + spatialReferenceWGS84, + GeodeticCurveType.Geodesic, + 148.7, + 0.07, + false, + null); + + String wktInput = "POLYGON ((-70.651656936570745 43.135157834585826,-70.651570654984525 43.135150076925918,-70.651511247908587 43.135155437576621,-70.651490101488349 43.135169249238288,-70.651490181628759 43.135200763774868,-70.651510336532638 43.135249995303397,-70.651530872098633 43.135299226354952,-70.651527230781454 43.13533529757845,-70.651492643684321 43.135349305799508,-70.651420172717224 43.135354852495823,-70.651358095085072 43.135346745253884,-70.651247805462717 43.1353033127629,-70.651151361236941 43.135246176463966,-70.651124154255413 43.135206047556842,-70.651131534466685 43.135151913051203,-70.651155914561755 43.135115542493892,-70.651228730259774 43.135051460048707,-70.651305024993519 43.134973818456416,-70.651360674948108 43.134914489191551,-70.651385078643216 43.134864606853156,-70.651402827815218 43.134810322639233,-70.651410310326284 43.134688652284062,-70.651418383361829 43.134517448375689,-70.651411370788409 43.134413996600074,-70.651390876709428 43.134337752182525,-70.651346755889904 43.134225832686319,-70.651289063395154 43.134109606122337,-70.651241242017051 43.133988734078358,-70.651230854601764 43.133916846697829,-70.651221013347353 43.133822439140715,-70.651200519724128 43.133746194674302,-70.651218268699594 43.133691907971006,-70.651249886578313 43.133610413350418,-70.651273539332081 43.133547040518167,-70.651322422674269 43.133478800504768,-70.651363984222755 43.133424172537978,-70.651409243106613 43.133378494590104,-70.651437060507462 43.133355583224628,-70.651492145648632 43.133332275678633,-70.651599176252716 43.133326227462319,-70.651675204034788 43.133338636120527,-70.65179240423565 43.133381970944697,-70.651905761872953 43.133425353603045,-70.652022336036893 43.133459688797871,-70.652087607730962 43.133472252516562,-70.652149929372143 43.133489361765591,-70.652232540703992 43.133546699550045,-70.652400720753761 43.133656829257461,-70.652544825855031 43.133771806958798,-70.652698657471404 43.133891149422396,-70.652757214424 43.133939825915917,-70.652829643131227 43.133961291723317,-70.652898471779253 43.133991812912122,-70.652963804959569 43.134049399817712,-70.652994471176711 43.134089475795044,-70.653000937222828 43.134129903976664,-70.653000836372897 43.134197439788288,-70.652972837499135 43.134256375321229,-70.652903321638362 43.134342923487154,-70.652853489821567 43.134447199036558,-70.652811504521395 43.134528843881576,-70.652776716073816 43.134592380423527,-70.652745241323998 43.134664872485907,-70.652703717209832 43.134692485155824,-70.65263790191085 43.134702441934749,-70.652537796343609 43.13469488220742,-70.652481986521252 43.134691185475688,-70.652416288981371 43.134705643385693,-70.652347112331768 43.134733655368471,-70.652274294763117 43.134797738553125,-70.652239263183958 43.134852272522785,-70.652214826278225 43.134929165745028,-70.652217533236211 43.135001163954207,-70.652248296977746 43.135059250554882,-70.652327397729081 43.135157158057844,-70.652414500765317 43.135209927851037,-70.6524582645621 43.135222802033766,-70.652470512866358 43.135249637832572,-70.652646824360005 43.135404671730349,-70.652680946443695 43.135444700365824,-70.652691113545444 43.135494075980539,-70.652680299690047 43.135534756334458,-70.652642334694633 43.135580326883741,-70.6525831461027 43.135608197219,-70.65250042683256 43.135618395612582,-70.652403778584315 43.1356107883392,-70.652328034290349 43.135580366756479,-70.652207940292428 43.135501055652128,-70.652084166050003 43.135399292820672,-70.651994153636025 43.135324055019495,-70.651897729053019 43.13525341019011,-70.651815354685922 43.135205077192047,-70.651746646220062 43.135179051560065,-70.651656936570745 43.135157834585826))"; + Geometry input = OperatorImportFromWkt.local().execute(0, Geometry.Type.Unknown, wktInput, null); + Geometry encircled = OperatorEnclosingCircle.local().execute(input, spatialReferenceWGS84, null); // assertEquals(encircled.calculateArea2D(), geodesicBuffered.calculateArea2D(), 1e-8); // assertEquals(0.0, OperatorDifference.local().execute(encircled, geodesicBuffered, spatialReferenceWGS84, null).calculateArea2D(), 1e-8); - assertTrue(GeometryEngine.contains(geodesicBuffered, encircled, spatialReferenceWGS84)); - } + assertTrue(GeometryEngine.contains(geodesicBuffered, encircled, spatialReferenceWGS84)); + } // @Test // public void testCircleVertexContain() { diff --git a/src/test/java/com/esri/core/geometry/TestClip.java b/src/test/java/com/esri/core/geometry/TestClip.java index 544a3ce4..3dcca075 100644 --- a/src/test/java/com/esri/core/geometry/TestClip.java +++ b/src/test/java/com/esri/core/geometry/TestClip.java @@ -28,390 +28,390 @@ import org.junit.Test; public class TestClip extends TestCase { - @Override - protected void setUp() throws Exception { - super.setUp(); - } - - @Override - protected void tearDown() throws Exception { - super.tearDown(); - } - - @Test - public static void testClipGeometries() { - // RandomTest(); - OperatorFactoryLocal engine = OperatorFactoryLocal.getInstance(); - OperatorClip clipOp = (OperatorClip) engine - .getOperator(Operator.Type.Clip); - - Polygon polygon = makePolygon(); - SimpleGeometryCursor polygonCurs = new SimpleGeometryCursor(polygon); - - Polyline polyline = makePolyline(); - SimpleGeometryCursor polylineCurs = new SimpleGeometryCursor(polyline); - - MultiPoint multipoint = makeMultiPoint(); - SimpleGeometryCursor multipointCurs = new SimpleGeometryCursor( - multipoint); - - Point point = makePoint(); - SimpleGeometryCursor pointCurs = new SimpleGeometryCursor(point); - - SpatialReference spatialRef = SpatialReference.create(3857); - - Envelope2D envelope = new Envelope2D(); - envelope.xmin = 0; - envelope.xmax = 20; - envelope.ymin = 5; - envelope.ymax = 15; - - // Cursor implementation - GeometryCursor clipPolygonCurs = clipOp.execute(polygonCurs, envelope, - spatialRef, null); - Polygon clippedPolygon = (Polygon) clipPolygonCurs.next(); - double area = clippedPolygon.calculateArea2D(); - assertTrue(Math.abs(area - 25) < 0.00001); - - // Single Geometry implementation - clippedPolygon = (Polygon) clipOp.execute(polygon, envelope, - spatialRef, null); - area = clippedPolygon.calculateArea2D(); - assertTrue(Math.abs(area - 25) < 0.00001); - - // Cursor implementation - GeometryCursor clipPolylineCurs = clipOp.execute(polylineCurs, - envelope, spatialRef, null); - Polyline clippedPolyline = (Polyline) clipPolylineCurs.next(); - double length = clippedPolyline.calculateLength2D(); - assertTrue(Math.abs(length - 10 * Math.sqrt(2.0)) < 1e-10); - - // Single Geometry implementation - clippedPolyline = (Polyline) clipOp.execute(polyline, envelope, - spatialRef, null); - length = clippedPolyline.calculateLength2D(); - assertTrue(Math.abs(length - 10 * Math.sqrt(2.0)) < 1e-10); - - // Cursor implementation - GeometryCursor clipMulti_pointCurs = clipOp.execute(multipointCurs, - envelope, spatialRef, null); - MultiPoint clipped_multi_point = (MultiPoint) clipMulti_pointCurs - .next(); - int pointCount = clipped_multi_point.getPointCount(); - assertTrue(pointCount == 2); - - // Cursor implementation - GeometryCursor clipPointCurs = clipOp.execute(pointCurs, envelope, - spatialRef, null); - Point clippedPoint = (Point) clipPointCurs.next(); - assertTrue(clippedPoint != null); - - // RandomTest(); - - Polyline _poly = new Polyline(); - _poly.startPath(2, 2); - _poly.lineTo(0, 0); - - Envelope2D _env = new Envelope2D(); - _env.setCoords(2, 1, 5, 3); - - Polyline _clippedPolyline = (Polyline) clipOp.execute(_poly, _env, - spatialRef, null); - assertTrue(_clippedPolyline.isEmpty()); - - { - Polygon poly = new Polygon(); - poly.addEnvelope(new Envelope2D(0, 0, 100, 100), false); - poly.addEnvelope(new Envelope2D(5, 5, 95, 95), true); - - Polygon clippedPoly = (Polygon) clipOp.execute(poly, - new Envelope2D(-10, -10, 110, 50), spatialRef, null); - assertTrue(clippedPoly.getPathCount() == 1); - assertTrue(clippedPoly.getPointCount() == 8); - } - } - - static Polygon makePolygon() { - Polygon poly = new Polygon(); - poly.startPath(0, 0); - poly.lineTo(10, 10); - poly.lineTo(20, 0); - - return poly; - } - - static Polyline makePolyline() { - Polyline poly = new Polyline(); - poly.startPath(0, 0); - poly.lineTo(10, 10); - poly.lineTo(20, 0); - - return poly; - } - - @Test - public static void testGetXCorrectCR185697() { - OperatorFactoryLocal engine = OperatorFactoryLocal.getInstance(); - OperatorClip clipOp = (OperatorClip) engine - .getOperator(Operator.Type.Clip); - - Polyline polylineCR = makePolylineCR(); - @SuppressWarnings("unused") - SimpleGeometryCursor polylineCursCR = new SimpleGeometryCursor( - polylineCR); - - SpatialReference gcsWGS84 = SpatialReference.create(4326); - - Envelope2D envelopeCR = new Envelope2D(); - envelopeCR.xmin = -180; - envelopeCR.xmax = 180; - envelopeCR.ymin = -90; - envelopeCR.ymax = 90; - // CR - Polyline clippedPolylineCR = (Polyline) clipOp.execute(polylineCR, - envelopeCR, gcsWGS84, null); - Point pointResult = new Point(); - clippedPolylineCR.getPointByVal(0, pointResult); - assertTrue(pointResult.getX() == -180); - clippedPolylineCR.getPointByVal(1, pointResult); - assertTrue(pointResult.getX() == -90); - clippedPolylineCR.getPointByVal(2, pointResult); - assertTrue(pointResult.getX() == 0); - clippedPolylineCR.getPointByVal(3, pointResult); - assertTrue(pointResult.getX() == 100); - clippedPolylineCR.getPointByVal(4, pointResult); - assertTrue(pointResult.getX() == 170); - clippedPolylineCR.getPointByVal(5, pointResult); - assertTrue(pointResult.getX() == 180); - } - - @Test - public static void testArcObjectsFailureCR196492() { - OperatorFactoryLocal engine = OperatorFactoryLocal.getInstance(); - OperatorClip clipOp = (OperatorClip) engine - .getOperator(Operator.Type.Clip); - - Polygon polygon = new Polygon(); - polygon.addEnvelope(new Envelope2D(0, 0, 600, 600), false); - polygon.startPath(30, 300); - polygon.lineTo(20, 310); - polygon.lineTo(10, 300); - - SpatialReference gcsWGS84 = SpatialReference.create(4326); - - Envelope2D envelopeCR = new Envelope2D(10, 10, 500, 500); - - Polygon clippedPolygon = (Polygon) clipOp.execute(polygon, envelopeCR, - gcsWGS84, null); - assertTrue(clippedPolygon.getPointCount() == 7); - // ((MultiPathImpl::SPtr)clippedPolygon._GetImpl()).SaveToTextFileDbg("c:\\temp\\test_ArcObjects_failure_CR196492.txt"); - } - - static Polyline makePolylineCR() { - Polyline polyline = new Polyline(); - - polyline.startPath(-200, -90); - polyline.lineTo(-180, -85); - polyline.lineTo(-90, -70); - polyline.lineTo(0, 0); - polyline.lineTo(100, 25); - polyline.lineTo(170, 45); - polyline.lineTo(225, 65); - - return polyline; - } - - static MultiPoint makeMultiPoint() { - MultiPoint mpoint = new MultiPoint(); - - Point2D pt1 = new Point2D(); - pt1.x = 10; - pt1.y = 10; - - Point2D pt2 = new Point2D(); - pt2.x = 15; - pt2.y = 10; - - Point2D pt3 = new Point2D(); - pt3.x = 10; - pt3.y = 20; - - mpoint.add(pt1.x, pt1.y); - mpoint.add(pt2.x, pt2.y); - mpoint.add(pt3.x, pt3.y); - - return mpoint; - } - - static Point makePoint() { - Point point = new Point(); - - Point2D pt = new Point2D(); - pt.setCoords(10, 20); - point.setXY(pt); - - return point; - } - - @Test - public static void testClipOfCoinciding() { - OperatorFactoryLocal engine = OperatorFactoryLocal.getInstance(); - OperatorClip clipOp = (OperatorClip) engine - .getOperator(Operator.Type.Clip); - - Polygon polygon = new Polygon(); - Envelope2D envelopeCR = new Envelope2D(); - envelopeCR.xmin = -180; - envelopeCR.xmax = 180; - envelopeCR.ymin = -90; - envelopeCR.ymax = 90; - - polygon.addEnvelope(envelopeCR, false); - - SpatialReference gcsWGS84 = SpatialReference.create(4326); - // CR - Polygon clippedPolygon = (Polygon) clipOp.execute(polygon, envelopeCR, - gcsWGS84, null); - assertTrue(clippedPolygon.getPathCount() == 1); - assertTrue(clippedPolygon.getPointCount() == 4); - - OperatorDensifyByLength densifyOp = (OperatorDensifyByLength) engine - .getOperator(Operator.Type.DensifyByLength); - polygon.setEmpty(); - polygon.addEnvelope(envelopeCR, false); - polygon = (Polygon) densifyOp.execute(polygon, 1, null); - - int pc = polygon.getPointCount(); - int pathc = polygon.getPathCount(); - assertTrue(pc == 1080); - assertTrue(pathc == 1); - clippedPolygon = (Polygon) clipOp.execute(polygon, envelopeCR, - gcsWGS84, null); - int _pathc = clippedPolygon.getPathCount(); - int _pc = clippedPolygon.getPointCount(); - assertTrue(_pathc == 1); - assertTrue(_pc == pc); - } - - @Test - public static void testClipAttributes() { - OperatorFactoryLocal engine = OperatorFactoryLocal.getInstance(); - OperatorClip clipOp = (OperatorClip) engine - .getOperator(Operator.Type.Clip); - { - Polygon polygon = new Polygon(); - polygon.addAttribute(VertexDescription.Semantics.M); - - polygon.startPath(0, 0); - polygon.lineTo(30, 30); - polygon.lineTo(60, 0); - - polygon.setAttribute(VertexDescription.Semantics.M, 0, 0, 0); - polygon.setAttribute(VertexDescription.Semantics.M, 1, 0, 60); - polygon.setAttribute(VertexDescription.Semantics.M, 2, 0, 120); - - Envelope2D clipper = new Envelope2D(); - clipper.setCoords(10, 0, 50, 20); - Polygon clippedPolygon = (Polygon) clipOp.execute(polygon, clipper, - SpatialReference.create(4326), null); - - assertTrue(clippedPolygon.getAttributeAsDbl( - VertexDescription.Semantics.M, 0, 0) == 100); - assertTrue(clippedPolygon.getAttributeAsDbl( - VertexDescription.Semantics.M, 1, 0) == 19.999999999999996); // 20.0 - assertTrue(clippedPolygon.getAttributeAsDbl( - VertexDescription.Semantics.M, 2, 0) == 20); - assertTrue(clippedPolygon.getAttributeAsDbl( - VertexDescription.Semantics.M, 3, 0) == 40); - assertTrue(clippedPolygon.getAttributeAsDbl( - VertexDescription.Semantics.M, 4, 0) == 80); - assertTrue(clippedPolygon.getAttributeAsDbl( - VertexDescription.Semantics.M, 5, 0) == 100); - } - - { - Polygon polygon = new Polygon(); - polygon.addAttribute(VertexDescription.Semantics.M); - - polygon.startPath(0, 0); - polygon.lineTo(0, 40); - polygon.lineTo(20, 40); - polygon.lineTo(20, 0); - - polygon.setAttribute(VertexDescription.Semantics.M, 0, 0, 0); - polygon.setAttribute(VertexDescription.Semantics.M, 1, 0, 60); - polygon.setAttribute(VertexDescription.Semantics.M, 2, 0, 120); - polygon.setAttribute(VertexDescription.Semantics.M, 3, 0, 180); - - Envelope2D clipper = new Envelope2D(); - clipper.setCoords(0, 10, 20, 20); - Polygon clippedPolygon = (Polygon) clipOp.execute(polygon, clipper, - SpatialReference.create(4326), null); - - assertTrue(clippedPolygon.getAttributeAsDbl( - VertexDescription.Semantics.M, 0, 0) == 15); - assertTrue(clippedPolygon.getAttributeAsDbl( - VertexDescription.Semantics.M, 1, 0) == 30); - assertTrue(clippedPolygon.getAttributeAsDbl( - VertexDescription.Semantics.M, 2, 0) == 150); - assertTrue(clippedPolygon.getAttributeAsDbl( - VertexDescription.Semantics.M, 3, 0) == 165); - } - } - - @Test - public static void testClipIssue258243() { - Polygon poly1 = new Polygon(); - poly1.startPath(21.476191371901479, 41.267022001907215); - poly1.lineTo(59.669186665158051, 36.62700518555863); - poly1.lineTo(20.498578117352313, 30.363180148246094); - poly1.lineTo(18.342565836615044, 46.303295352085627); - poly1.lineTo(17.869569458621626, 23.886816966894159); - poly1.lineTo(19.835465558090434, 20); - poly1.lineTo(18.83911285048551, 43.515995498114791); - poly1.lineTo(20.864485260298004, 20.235921201027757); - poly1.lineTo(18.976127544787012, 20); - poly1.lineTo(34.290201277718218, 61.801369014954794); - poly1.lineTo(20.734727419368866, 20); - poly1.lineTo(18.545865698148113, 20); - poly1.lineTo(19.730260558565515, 20); - poly1.lineTo(19.924806216827005, 23.780315893949187); - poly1.lineTo(21.675168105421452, 36.699924873001258); - poly1.lineTo(22.500527828912158, 43.703424859922983); - poly1.lineTo(42.009527116514818, 36.995486982256089); - poly1.lineTo(24.469729873835782, 58.365871758247039); - poly1.lineTo(24.573736036545878, 36.268390409195824); - poly1.lineTo(22.726502169802746, 20); - poly1.lineTo(23.925834885228145, 20); - poly1.lineTo(25.495346880936729, 20); - poly1.lineTo(23.320941499288317, 20); - poly1.lineTo(24.05655665646276, 28.659578774758632); - poly1.lineTo(23.205940789341135, 38.491506888710504); - poly1.lineTo(21.472847203385509, 53.057228182018044); - poly1.lineTo(25.04257681654104, 20); - poly1.lineTo(25.880572351149542, 25.16102863979474); - poly1.lineTo(26.756283333879658, 20); - poly1.lineTo(21.476191371901479, 41.267022001907215); - Envelope2D env = new Envelope2D(); - env.setCoords(24.269517325186033, 19.999998900000001, - 57.305574253225409, 61.801370114954793); - - try { - Geometry output_geom = OperatorClip.local().execute(poly1, env, - SpatialReference.create(4326), null); - Envelope envPoly = new Envelope(); - poly1.queryEnvelope(envPoly); - Envelope e = new Envelope(env); - e.intersect(envPoly); - Envelope clippedEnv = new Envelope(); - output_geom.queryEnvelope(clippedEnv); - assertTrue(Math.abs(clippedEnv.getXMin() - e.getXMin()) < 1e-10 && - Math.abs(clippedEnv.getYMin() - e.getYMin()) < 1e-10 && - Math.abs(clippedEnv.getXMax() - e.getXMax()) < 1e-10 && - Math.abs(clippedEnv.getYMax() - e.getYMax()) < 1e-10); - } catch (Exception e) { - assertTrue(false); - } - - } + @Override + protected void setUp() throws Exception { + super.setUp(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + } + + @Test + public static void testClipGeometries() { + // RandomTest(); + OperatorFactoryLocal engine = OperatorFactoryLocal.getInstance(); + OperatorClip clipOp = (OperatorClip) engine + .getOperator(Operator.Type.Clip); + + Polygon polygon = makePolygon(); + SimpleGeometryCursor polygonCurs = new SimpleGeometryCursor(polygon); + + Polyline polyline = makePolyline(); + SimpleGeometryCursor polylineCurs = new SimpleGeometryCursor(polyline); + + MultiPoint multipoint = makeMultiPoint(); + SimpleGeometryCursor multipointCurs = new SimpleGeometryCursor( + multipoint); + + Point point = makePoint(); + SimpleGeometryCursor pointCurs = new SimpleGeometryCursor(point); + + SpatialReference spatialRef = SpatialReference.create(3857); + + Envelope2D envelope = new Envelope2D(); + envelope.xmin = 0; + envelope.xmax = 20; + envelope.ymin = 5; + envelope.ymax = 15; + + // Cursor implementation + GeometryCursor clipPolygonCurs = clipOp.execute(polygonCurs, envelope, + spatialRef, null); + Polygon clippedPolygon = (Polygon) clipPolygonCurs.next(); + double area = clippedPolygon.calculateArea2D(); + assertTrue(Math.abs(area - 25) < 0.00001); + + // Single Geometry implementation + clippedPolygon = (Polygon) clipOp.execute(polygon, envelope, + spatialRef, null); + area = clippedPolygon.calculateArea2D(); + assertTrue(Math.abs(area - 25) < 0.00001); + + // Cursor implementation + GeometryCursor clipPolylineCurs = clipOp.execute(polylineCurs, + envelope, spatialRef, null); + Polyline clippedPolyline = (Polyline) clipPolylineCurs.next(); + double length = clippedPolyline.calculateLength2D(); + assertTrue(Math.abs(length - 10 * Math.sqrt(2.0)) < 1e-10); + + // Single Geometry implementation + clippedPolyline = (Polyline) clipOp.execute(polyline, envelope, + spatialRef, null); + length = clippedPolyline.calculateLength2D(); + assertTrue(Math.abs(length - 10 * Math.sqrt(2.0)) < 1e-10); + + // Cursor implementation + GeometryCursor clipMulti_pointCurs = clipOp.execute(multipointCurs, + envelope, spatialRef, null); + MultiPoint clipped_multi_point = (MultiPoint) clipMulti_pointCurs + .next(); + int pointCount = clipped_multi_point.getPointCount(); + assertTrue(pointCount == 2); + + // Cursor implementation + GeometryCursor clipPointCurs = clipOp.execute(pointCurs, envelope, + spatialRef, null); + Point clippedPoint = (Point) clipPointCurs.next(); + assertTrue(clippedPoint != null); + + // RandomTest(); + + Polyline _poly = new Polyline(); + _poly.startPath(2, 2); + _poly.lineTo(0, 0); + + Envelope2D _env = new Envelope2D(); + _env.setCoords(2, 1, 5, 3); + + Polyline _clippedPolyline = (Polyline) clipOp.execute(_poly, _env, + spatialRef, null); + assertTrue(_clippedPolyline.isEmpty()); + + { + Polygon poly = new Polygon(); + poly.addEnvelope(new Envelope2D(0, 0, 100, 100), false); + poly.addEnvelope(new Envelope2D(5, 5, 95, 95), true); + + Polygon clippedPoly = (Polygon) clipOp.execute(poly, + new Envelope2D(-10, -10, 110, 50), spatialRef, null); + assertTrue(clippedPoly.getPathCount() == 1); + assertTrue(clippedPoly.getPointCount() == 8); + } + } + + static Polygon makePolygon() { + Polygon poly = new Polygon(); + poly.startPath(0, 0); + poly.lineTo(10, 10); + poly.lineTo(20, 0); + + return poly; + } + + static Polyline makePolyline() { + Polyline poly = new Polyline(); + poly.startPath(0, 0); + poly.lineTo(10, 10); + poly.lineTo(20, 0); + + return poly; + } + + @Test + public static void testGetXCorrectCR185697() { + OperatorFactoryLocal engine = OperatorFactoryLocal.getInstance(); + OperatorClip clipOp = (OperatorClip) engine + .getOperator(Operator.Type.Clip); + + Polyline polylineCR = makePolylineCR(); + @SuppressWarnings("unused") + SimpleGeometryCursor polylineCursCR = new SimpleGeometryCursor( + polylineCR); + + SpatialReference gcsWGS84 = SpatialReference.create(4326); + + Envelope2D envelopeCR = new Envelope2D(); + envelopeCR.xmin = -180; + envelopeCR.xmax = 180; + envelopeCR.ymin = -90; + envelopeCR.ymax = 90; + // CR + Polyline clippedPolylineCR = (Polyline) clipOp.execute(polylineCR, + envelopeCR, gcsWGS84, null); + Point pointResult = new Point(); + clippedPolylineCR.getPointByVal(0, pointResult); + assertTrue(pointResult.getX() == -180); + clippedPolylineCR.getPointByVal(1, pointResult); + assertTrue(pointResult.getX() == -90); + clippedPolylineCR.getPointByVal(2, pointResult); + assertTrue(pointResult.getX() == 0); + clippedPolylineCR.getPointByVal(3, pointResult); + assertTrue(pointResult.getX() == 100); + clippedPolylineCR.getPointByVal(4, pointResult); + assertTrue(pointResult.getX() == 170); + clippedPolylineCR.getPointByVal(5, pointResult); + assertTrue(pointResult.getX() == 180); + } + + @Test + public static void testArcObjectsFailureCR196492() { + OperatorFactoryLocal engine = OperatorFactoryLocal.getInstance(); + OperatorClip clipOp = (OperatorClip) engine + .getOperator(Operator.Type.Clip); + + Polygon polygon = new Polygon(); + polygon.addEnvelope(new Envelope2D(0, 0, 600, 600), false); + polygon.startPath(30, 300); + polygon.lineTo(20, 310); + polygon.lineTo(10, 300); + + SpatialReference gcsWGS84 = SpatialReference.create(4326); + + Envelope2D envelopeCR = new Envelope2D(10, 10, 500, 500); + + Polygon clippedPolygon = (Polygon) clipOp.execute(polygon, envelopeCR, + gcsWGS84, null); + assertTrue(clippedPolygon.getPointCount() == 7); + // ((MultiPathImpl::SPtr)clippedPolygon._GetImpl()).SaveToTextFileDbg("c:\\temp\\test_ArcObjects_failure_CR196492.txt"); + } + + static Polyline makePolylineCR() { + Polyline polyline = new Polyline(); + + polyline.startPath(-200, -90); + polyline.lineTo(-180, -85); + polyline.lineTo(-90, -70); + polyline.lineTo(0, 0); + polyline.lineTo(100, 25); + polyline.lineTo(170, 45); + polyline.lineTo(225, 65); + + return polyline; + } + + static MultiPoint makeMultiPoint() { + MultiPoint mpoint = new MultiPoint(); + + Point2D pt1 = new Point2D(); + pt1.x = 10; + pt1.y = 10; + + Point2D pt2 = new Point2D(); + pt2.x = 15; + pt2.y = 10; + + Point2D pt3 = new Point2D(); + pt3.x = 10; + pt3.y = 20; + + mpoint.add(pt1.x, pt1.y); + mpoint.add(pt2.x, pt2.y); + mpoint.add(pt3.x, pt3.y); + + return mpoint; + } + + static Point makePoint() { + Point point = new Point(); + + Point2D pt = new Point2D(); + pt.setCoords(10, 20); + point.setXY(pt); + + return point; + } + + @Test + public static void testClipOfCoinciding() { + OperatorFactoryLocal engine = OperatorFactoryLocal.getInstance(); + OperatorClip clipOp = (OperatorClip) engine + .getOperator(Operator.Type.Clip); + + Polygon polygon = new Polygon(); + Envelope2D envelopeCR = new Envelope2D(); + envelopeCR.xmin = -180; + envelopeCR.xmax = 180; + envelopeCR.ymin = -90; + envelopeCR.ymax = 90; + + polygon.addEnvelope(envelopeCR, false); + + SpatialReference gcsWGS84 = SpatialReference.create(4326); + // CR + Polygon clippedPolygon = (Polygon) clipOp.execute(polygon, envelopeCR, + gcsWGS84, null); + assertTrue(clippedPolygon.getPathCount() == 1); + assertTrue(clippedPolygon.getPointCount() == 4); + + OperatorDensifyByLength densifyOp = (OperatorDensifyByLength) engine + .getOperator(Operator.Type.DensifyByLength); + polygon.setEmpty(); + polygon.addEnvelope(envelopeCR, false); + polygon = (Polygon) densifyOp.execute(polygon, 1, null); + + int pc = polygon.getPointCount(); + int pathc = polygon.getPathCount(); + assertTrue(pc == 1080); + assertTrue(pathc == 1); + clippedPolygon = (Polygon) clipOp.execute(polygon, envelopeCR, + gcsWGS84, null); + int _pathc = clippedPolygon.getPathCount(); + int _pc = clippedPolygon.getPointCount(); + assertTrue(_pathc == 1); + assertTrue(_pc == pc); + } + + @Test + public static void testClipAttributes() { + OperatorFactoryLocal engine = OperatorFactoryLocal.getInstance(); + OperatorClip clipOp = (OperatorClip) engine + .getOperator(Operator.Type.Clip); + { + Polygon polygon = new Polygon(); + polygon.addAttribute(VertexDescription.Semantics.M); + + polygon.startPath(0, 0); + polygon.lineTo(30, 30); + polygon.lineTo(60, 0); + + polygon.setAttribute(VertexDescription.Semantics.M, 0, 0, 0); + polygon.setAttribute(VertexDescription.Semantics.M, 1, 0, 60); + polygon.setAttribute(VertexDescription.Semantics.M, 2, 0, 120); + + Envelope2D clipper = new Envelope2D(); + clipper.setCoords(10, 0, 50, 20); + Polygon clippedPolygon = (Polygon) clipOp.execute(polygon, clipper, + SpatialReference.create(4326), null); + + assertTrue(clippedPolygon.getAttributeAsDbl( + VertexDescription.Semantics.M, 0, 0) == 100); + assertTrue(clippedPolygon.getAttributeAsDbl( + VertexDescription.Semantics.M, 1, 0) == 19.999999999999996); // 20.0 + assertTrue(clippedPolygon.getAttributeAsDbl( + VertexDescription.Semantics.M, 2, 0) == 20); + assertTrue(clippedPolygon.getAttributeAsDbl( + VertexDescription.Semantics.M, 3, 0) == 40); + assertTrue(clippedPolygon.getAttributeAsDbl( + VertexDescription.Semantics.M, 4, 0) == 80); + assertTrue(clippedPolygon.getAttributeAsDbl( + VertexDescription.Semantics.M, 5, 0) == 100); + } + + { + Polygon polygon = new Polygon(); + polygon.addAttribute(VertexDescription.Semantics.M); + + polygon.startPath(0, 0); + polygon.lineTo(0, 40); + polygon.lineTo(20, 40); + polygon.lineTo(20, 0); + + polygon.setAttribute(VertexDescription.Semantics.M, 0, 0, 0); + polygon.setAttribute(VertexDescription.Semantics.M, 1, 0, 60); + polygon.setAttribute(VertexDescription.Semantics.M, 2, 0, 120); + polygon.setAttribute(VertexDescription.Semantics.M, 3, 0, 180); + + Envelope2D clipper = new Envelope2D(); + clipper.setCoords(0, 10, 20, 20); + Polygon clippedPolygon = (Polygon) clipOp.execute(polygon, clipper, + SpatialReference.create(4326), null); + + assertTrue(clippedPolygon.getAttributeAsDbl( + VertexDescription.Semantics.M, 0, 0) == 15); + assertTrue(clippedPolygon.getAttributeAsDbl( + VertexDescription.Semantics.M, 1, 0) == 30); + assertTrue(clippedPolygon.getAttributeAsDbl( + VertexDescription.Semantics.M, 2, 0) == 150); + assertTrue(clippedPolygon.getAttributeAsDbl( + VertexDescription.Semantics.M, 3, 0) == 165); + } + } + + @Test + public static void testClipIssue258243() { + Polygon poly1 = new Polygon(); + poly1.startPath(21.476191371901479, 41.267022001907215); + poly1.lineTo(59.669186665158051, 36.62700518555863); + poly1.lineTo(20.498578117352313, 30.363180148246094); + poly1.lineTo(18.342565836615044, 46.303295352085627); + poly1.lineTo(17.869569458621626, 23.886816966894159); + poly1.lineTo(19.835465558090434, 20); + poly1.lineTo(18.83911285048551, 43.515995498114791); + poly1.lineTo(20.864485260298004, 20.235921201027757); + poly1.lineTo(18.976127544787012, 20); + poly1.lineTo(34.290201277718218, 61.801369014954794); + poly1.lineTo(20.734727419368866, 20); + poly1.lineTo(18.545865698148113, 20); + poly1.lineTo(19.730260558565515, 20); + poly1.lineTo(19.924806216827005, 23.780315893949187); + poly1.lineTo(21.675168105421452, 36.699924873001258); + poly1.lineTo(22.500527828912158, 43.703424859922983); + poly1.lineTo(42.009527116514818, 36.995486982256089); + poly1.lineTo(24.469729873835782, 58.365871758247039); + poly1.lineTo(24.573736036545878, 36.268390409195824); + poly1.lineTo(22.726502169802746, 20); + poly1.lineTo(23.925834885228145, 20); + poly1.lineTo(25.495346880936729, 20); + poly1.lineTo(23.320941499288317, 20); + poly1.lineTo(24.05655665646276, 28.659578774758632); + poly1.lineTo(23.205940789341135, 38.491506888710504); + poly1.lineTo(21.472847203385509, 53.057228182018044); + poly1.lineTo(25.04257681654104, 20); + poly1.lineTo(25.880572351149542, 25.16102863979474); + poly1.lineTo(26.756283333879658, 20); + poly1.lineTo(21.476191371901479, 41.267022001907215); + Envelope2D env = new Envelope2D(); + env.setCoords(24.269517325186033, 19.999998900000001, + 57.305574253225409, 61.801370114954793); + + try { + Geometry output_geom = OperatorClip.local().execute(poly1, env, + SpatialReference.create(4326), null); + Envelope envPoly = new Envelope(); + poly1.queryEnvelope(envPoly); + Envelope e = new Envelope(env); + e.intersect(envPoly); + Envelope clippedEnv = new Envelope(); + output_geom.queryEnvelope(clippedEnv); + assertTrue(Math.abs(clippedEnv.getXMin() - e.getXMin()) < 1e-10 && + Math.abs(clippedEnv.getYMin() - e.getYMin()) < 1e-10 && + Math.abs(clippedEnv.getXMax() - e.getXMax()) < 1e-10 && + Math.abs(clippedEnv.getYMax() - e.getYMax()) < 1e-10); + } catch (Exception e) { + assertTrue(false); + } + + } } diff --git a/src/test/java/com/esri/core/geometry/TestCommonMethods.java b/src/test/java/com/esri/core/geometry/TestCommonMethods.java index 59e40789..39ca5b92 100644 --- a/src/test/java/com/esri/core/geometry/TestCommonMethods.java +++ b/src/test/java/com/esri/core/geometry/TestCommonMethods.java @@ -30,237 +30,237 @@ import java.io.*; public class TestCommonMethods extends TestCase { - public static boolean compareDouble(double a, double b, double tol) { - double diff = Math.abs(a - b); - return diff <= tol * Math.abs(a) + tol; - } - - public static Point[] pointsFromMultiPath(MultiPath geom) { - int numberOfPoints = geom.getPointCount(); - Point[] points = new Point[numberOfPoints]; - for (int i = 0; i < geom.getPointCount(); i++) { - points[i] = geom.getPoint(i); - } - return points; - } - - @Test - public static void compareGeometryContent(MultiVertexGeometry geom1, - MultiVertexGeometry geom2) { - // Geometry types - assertTrue(geom1.getType().value() == geom2.getType().value()); - - // Envelopes - Envelope2D env1 = new Envelope2D(); - geom1.queryEnvelope2D(env1); - - Envelope2D env2 = new Envelope2D(); - geom2.queryEnvelope2D(env2); - - assertTrue(env1.xmin == env2.xmin && env1.xmax == env2.xmax - && env1.ymin == env2.ymin && env1.ymax == env2.ymax); - - int type = geom1.getType().value(); - if (type == Geometry.GeometryType.Polyline - || type == Geometry.GeometryType.Polygon) { - // Part Count - int partCount1 = ((MultiPath) geom1).getPathCount(); - int partCount2 = ((MultiPath) geom2).getPathCount(); - assertTrue(partCount1 == partCount2); - - // Part indices - for (int i = 0; i < partCount1; i++) { - int start1 = ((MultiPath) geom1).getPathStart(i); - int start2 = ((MultiPath) geom2).getPathStart(i); - assertTrue(start1 == start2); - int end1 = ((MultiPath) geom1).getPathEnd(i); - int end2 = ((MultiPath) geom2).getPathEnd(i); - assertTrue(end1 == end2); - } - } - - // Point count - int pointCount1 = geom1.getPointCount(); - int pointCount2 = geom2.getPointCount(); - assertTrue(pointCount1 == pointCount2); - - if (type == Geometry.GeometryType.MultiPoint - || type == Geometry.GeometryType.Polyline - || type == Geometry.GeometryType.Polygon) { - // POSITION - AttributeStreamBase positionStream1 = ((MultiVertexGeometryImpl) geom1 - ._getImpl()) - .getAttributeStreamRef(VertexDescription.Semantics.POSITION); - AttributeStreamOfDbl position1 = (AttributeStreamOfDbl) (positionStream1); - - AttributeStreamBase positionStream2 = ((MultiVertexGeometryImpl) geom2 - ._getImpl()) - .getAttributeStreamRef(VertexDescription.Semantics.POSITION); - AttributeStreamOfDbl position2 = (AttributeStreamOfDbl) (positionStream2); - - for (int i = 0; i < pointCount1; i++) { - double x1 = position1.read(2 * i); - double x2 = position2.read(2 * i); - assertTrue(x1 == x2); - - double y1 = position1.read(2 * i + 1); - double y2 = position2.read(2 * i + 1); - assertTrue(y1 == y2); - } - - // Zs - boolean bHasZs1 = geom1.hasAttribute(VertexDescription.Semantics.Z); - boolean bHasZs2 = geom2.hasAttribute(VertexDescription.Semantics.Z); - assertTrue(bHasZs1 == bHasZs2); - - if (bHasZs1) { - AttributeStreamBase zStream1 = ((MultiVertexGeometryImpl) geom1 - ._getImpl()) - .getAttributeStreamRef(VertexDescription.Semantics.Z); - AttributeStreamOfDbl zs1 = (AttributeStreamOfDbl) (zStream1); - - AttributeStreamBase zStream2 = ((MultiVertexGeometryImpl) geom2 - ._getImpl()) - .getAttributeStreamRef(VertexDescription.Semantics.Z); - AttributeStreamOfDbl zs2 = (AttributeStreamOfDbl) (zStream2); - - for (int i = 0; i < pointCount1; i++) { - double z1 = zs1.read(i); - double z2 = zs2.read(i); - assertTrue(z1 == z2); - } - } - - // Ms - boolean bHasMs1 = geom1.hasAttribute(VertexDescription.Semantics.M); - boolean bHasMs2 = geom2.hasAttribute(VertexDescription.Semantics.M); - assertTrue(bHasMs1 == bHasMs2); - - if (bHasMs1) { - AttributeStreamBase mStream1 = ((MultiVertexGeometryImpl) geom1 - ._getImpl()) - .getAttributeStreamRef(VertexDescription.Semantics.M); - AttributeStreamOfDbl ms1 = (AttributeStreamOfDbl) (mStream1); - - AttributeStreamBase mStream2 = ((MultiVertexGeometryImpl) geom2 - ._getImpl()) - .getAttributeStreamRef(VertexDescription.Semantics.M); - AttributeStreamOfDbl ms2 = (AttributeStreamOfDbl) (mStream2); - - for (int i = 0; i < pointCount1; i++) { - double m1 = ms1.read(i); - double m2 = ms2.read(i); - assertTrue(m1 == m2); - } - } - - // IDs - boolean bHasIDs1 = geom1 - .hasAttribute(VertexDescription.Semantics.ID); - boolean bHasIDs2 = geom2 - .hasAttribute(VertexDescription.Semantics.ID); - assertTrue(bHasIDs1 == bHasIDs2); - - if (bHasIDs1) { - AttributeStreamBase idStream1 = ((MultiVertexGeometryImpl) geom1 - ._getImpl()) - .getAttributeStreamRef(VertexDescription.Semantics.ID); - AttributeStreamOfInt32 ids1 = (AttributeStreamOfInt32) (idStream1); - - AttributeStreamBase idStream2 = ((MultiVertexGeometryImpl) geom2 - ._getImpl()) - .getAttributeStreamRef(VertexDescription.Semantics.ID); - AttributeStreamOfInt32 ids2 = (AttributeStreamOfInt32) (idStream2); - - for (int i = 0; i < pointCount1; i++) { - int id1 = ids1.read(i); - int id2 = ids2.read(i); - assertTrue(id1 == id2); - } - } - } - } - - @Test - public static void compareGeometryContent(MultiPoint geom1, MultiPoint geom2) { - // Geometry types - assertTrue(geom1.getType().value() == geom2.getType().value()); - - // Envelopes - Envelope env1 = new Envelope(); - geom1.queryEnvelope(env1); - - Envelope env2 = new Envelope(); - geom2.queryEnvelope(env2); - - assertTrue(env1.getXMin() == env2.getXMin() - && env1.getXMax() == env2.getXMax() - && env1.getYMin() == env2.getYMin() - && env1.getYMax() == env2.getYMax()); - - // Point count - int pointCount1 = geom1.getPointCount(); - int pointCount2 = geom2.getPointCount(); - assertTrue(pointCount1 == pointCount2); - - Point point1; - Point point2; - - for (int i = 0; i < pointCount1; i++) { - point1 = geom1.getPoint(i); - point2 = geom2.getPoint(i); - - double x1 = point1.getX(); - double x2 = point2.getX(); - assertTrue(x1 == x2); - - double y1 = point1.getY(); - double y2 = point2.getY(); - assertTrue(y1 == y2); - } - } - - @Test - public static void testNothing() { - - } - - public static boolean writeObjectToFile(String fileName, Object obj) { - try { - File f = new File(fileName); - f.setWritable(true); - - FileOutputStream fout = new FileOutputStream(f); - ObjectOutputStream oo = new ObjectOutputStream(fout); - oo.writeObject(obj); - fout.close(); - return true; - } catch (Exception ex) { - return false; - } - } - - public static Object readObjectFromFile(String fileName) { - try { - File f = new File(fileName); - f.setReadable(true); - - FileInputStream streamIn = new FileInputStream(f); - ObjectInputStream ii = new ObjectInputStream(streamIn); - Object obj = ii.readObject(); - streamIn.close(); - return obj; - } catch (Exception ex) { - return null; - } - } - - public static MapGeometry fromJson(String jsonString) { - try { - return OperatorImportFromJson.local().execute(Geometry.Type.Unknown, jsonString); - } catch (Exception ex) { - } - - return null; - } + public static boolean compareDouble(double a, double b, double tol) { + double diff = Math.abs(a - b); + return diff <= tol * Math.abs(a) + tol; + } + + public static Point[] pointsFromMultiPath(MultiPath geom) { + int numberOfPoints = geom.getPointCount(); + Point[] points = new Point[numberOfPoints]; + for (int i = 0; i < geom.getPointCount(); i++) { + points[i] = geom.getPoint(i); + } + return points; + } + + @Test + public static void compareGeometryContent(MultiVertexGeometry geom1, + MultiVertexGeometry geom2) { + // Geometry types + assertTrue(geom1.getType().value() == geom2.getType().value()); + + // Envelopes + Envelope2D env1 = new Envelope2D(); + geom1.queryEnvelope2D(env1); + + Envelope2D env2 = new Envelope2D(); + geom2.queryEnvelope2D(env2); + + assertTrue(env1.xmin == env2.xmin && env1.xmax == env2.xmax + && env1.ymin == env2.ymin && env1.ymax == env2.ymax); + + int type = geom1.getType().value(); + if (type == Geometry.GeometryType.Polyline + || type == Geometry.GeometryType.Polygon) { + // Part Count + int partCount1 = ((MultiPath) geom1).getPathCount(); + int partCount2 = ((MultiPath) geom2).getPathCount(); + assertTrue(partCount1 == partCount2); + + // Part indices + for (int i = 0; i < partCount1; i++) { + int start1 = ((MultiPath) geom1).getPathStart(i); + int start2 = ((MultiPath) geom2).getPathStart(i); + assertTrue(start1 == start2); + int end1 = ((MultiPath) geom1).getPathEnd(i); + int end2 = ((MultiPath) geom2).getPathEnd(i); + assertTrue(end1 == end2); + } + } + + // Point count + int pointCount1 = geom1.getPointCount(); + int pointCount2 = geom2.getPointCount(); + assertTrue(pointCount1 == pointCount2); + + if (type == Geometry.GeometryType.MultiPoint + || type == Geometry.GeometryType.Polyline + || type == Geometry.GeometryType.Polygon) { + // POSITION + AttributeStreamBase positionStream1 = ((MultiVertexGeometryImpl) geom1 + ._getImpl()) + .getAttributeStreamRef(VertexDescription.Semantics.POSITION); + AttributeStreamOfDbl position1 = (AttributeStreamOfDbl) (positionStream1); + + AttributeStreamBase positionStream2 = ((MultiVertexGeometryImpl) geom2 + ._getImpl()) + .getAttributeStreamRef(VertexDescription.Semantics.POSITION); + AttributeStreamOfDbl position2 = (AttributeStreamOfDbl) (positionStream2); + + for (int i = 0; i < pointCount1; i++) { + double x1 = position1.read(2 * i); + double x2 = position2.read(2 * i); + assertTrue(x1 == x2); + + double y1 = position1.read(2 * i + 1); + double y2 = position2.read(2 * i + 1); + assertTrue(y1 == y2); + } + + // Zs + boolean bHasZs1 = geom1.hasAttribute(VertexDescription.Semantics.Z); + boolean bHasZs2 = geom2.hasAttribute(VertexDescription.Semantics.Z); + assertTrue(bHasZs1 == bHasZs2); + + if (bHasZs1) { + AttributeStreamBase zStream1 = ((MultiVertexGeometryImpl) geom1 + ._getImpl()) + .getAttributeStreamRef(VertexDescription.Semantics.Z); + AttributeStreamOfDbl zs1 = (AttributeStreamOfDbl) (zStream1); + + AttributeStreamBase zStream2 = ((MultiVertexGeometryImpl) geom2 + ._getImpl()) + .getAttributeStreamRef(VertexDescription.Semantics.Z); + AttributeStreamOfDbl zs2 = (AttributeStreamOfDbl) (zStream2); + + for (int i = 0; i < pointCount1; i++) { + double z1 = zs1.read(i); + double z2 = zs2.read(i); + assertTrue(z1 == z2); + } + } + + // Ms + boolean bHasMs1 = geom1.hasAttribute(VertexDescription.Semantics.M); + boolean bHasMs2 = geom2.hasAttribute(VertexDescription.Semantics.M); + assertTrue(bHasMs1 == bHasMs2); + + if (bHasMs1) { + AttributeStreamBase mStream1 = ((MultiVertexGeometryImpl) geom1 + ._getImpl()) + .getAttributeStreamRef(VertexDescription.Semantics.M); + AttributeStreamOfDbl ms1 = (AttributeStreamOfDbl) (mStream1); + + AttributeStreamBase mStream2 = ((MultiVertexGeometryImpl) geom2 + ._getImpl()) + .getAttributeStreamRef(VertexDescription.Semantics.M); + AttributeStreamOfDbl ms2 = (AttributeStreamOfDbl) (mStream2); + + for (int i = 0; i < pointCount1; i++) { + double m1 = ms1.read(i); + double m2 = ms2.read(i); + assertTrue(m1 == m2); + } + } + + // IDs + boolean bHasIDs1 = geom1 + .hasAttribute(VertexDescription.Semantics.ID); + boolean bHasIDs2 = geom2 + .hasAttribute(VertexDescription.Semantics.ID); + assertTrue(bHasIDs1 == bHasIDs2); + + if (bHasIDs1) { + AttributeStreamBase idStream1 = ((MultiVertexGeometryImpl) geom1 + ._getImpl()) + .getAttributeStreamRef(VertexDescription.Semantics.ID); + AttributeStreamOfInt32 ids1 = (AttributeStreamOfInt32) (idStream1); + + AttributeStreamBase idStream2 = ((MultiVertexGeometryImpl) geom2 + ._getImpl()) + .getAttributeStreamRef(VertexDescription.Semantics.ID); + AttributeStreamOfInt32 ids2 = (AttributeStreamOfInt32) (idStream2); + + for (int i = 0; i < pointCount1; i++) { + int id1 = ids1.read(i); + int id2 = ids2.read(i); + assertTrue(id1 == id2); + } + } + } + } + + @Test + public static void compareGeometryContent(MultiPoint geom1, MultiPoint geom2) { + // Geometry types + assertTrue(geom1.getType().value() == geom2.getType().value()); + + // Envelopes + Envelope env1 = new Envelope(); + geom1.queryEnvelope(env1); + + Envelope env2 = new Envelope(); + geom2.queryEnvelope(env2); + + assertTrue(env1.getXMin() == env2.getXMin() + && env1.getXMax() == env2.getXMax() + && env1.getYMin() == env2.getYMin() + && env1.getYMax() == env2.getYMax()); + + // Point count + int pointCount1 = geom1.getPointCount(); + int pointCount2 = geom2.getPointCount(); + assertTrue(pointCount1 == pointCount2); + + Point point1; + Point point2; + + for (int i = 0; i < pointCount1; i++) { + point1 = geom1.getPoint(i); + point2 = geom2.getPoint(i); + + double x1 = point1.getX(); + double x2 = point2.getX(); + assertTrue(x1 == x2); + + double y1 = point1.getY(); + double y2 = point2.getY(); + assertTrue(y1 == y2); + } + } + + @Test + public static void testNothing() { + + } + + public static boolean writeObjectToFile(String fileName, Object obj) { + try { + File f = new File(fileName); + f.setWritable(true); + + FileOutputStream fout = new FileOutputStream(f); + ObjectOutputStream oo = new ObjectOutputStream(fout); + oo.writeObject(obj); + fout.close(); + return true; + } catch (Exception ex) { + return false; + } + } + + public static Object readObjectFromFile(String fileName) { + try { + File f = new File(fileName); + f.setReadable(true); + + FileInputStream streamIn = new FileInputStream(f); + ObjectInputStream ii = new ObjectInputStream(streamIn); + Object obj = ii.readObject(); + streamIn.close(); + return obj; + } catch (Exception ex) { + return null; + } + } + + public static MapGeometry fromJson(String jsonString) { + try { + return OperatorImportFromJson.local().execute(Geometry.Type.Unknown, jsonString); + } catch (Exception ex) { + } + + return null; + } } diff --git a/src/test/java/com/esri/core/geometry/TestContains.java b/src/test/java/com/esri/core/geometry/TestContains.java index 3cfa443f..1b96b598 100644 --- a/src/test/java/com/esri/core/geometry/TestContains.java +++ b/src/test/java/com/esri/core/geometry/TestContains.java @@ -33,24 +33,24 @@ import java.io.IOException; public class TestContains extends TestCase { - @Override - protected void setUp() throws Exception { - super.setUp(); - } - - @Override - protected void tearDown() throws Exception { - super.tearDown(); - } - - @Test - public static void testContainsFailureCR186456() throws JsonParseException, IOException { - String str = "{\"rings\":[[[406944.399999999,287461.450000001],[406947.750000011,287462.299999997],[406946.44999999,287467.450000001],[406943.050000005,287466.550000005],[406927.799999992,287456.849999994],[406926.949999996,287456.599999995],[406924.800000005,287455.999999998],[406924.300000007,287455.849999999],[406924.200000008,287456.099999997],[406923.450000011,287458.449999987],[406922.999999987,287459.800000008],[406922.29999999,287462.099999998],[406921.949999991,287463.449999992],[406921.449999993,287465.050000011],[406920.749999996,287466.700000004],[406919.800000001,287468.599999996],[406919.050000004,287469.99999999],[406917.800000009,287471.800000008],[406916.04999999,287473.550000001],[406915.449999993,287473.999999999],[406913.700000001,287475.449999993],[406913.300000002,287475.899999991],[406912.050000008,287477.250000011],[406913.450000002,287478.150000007],[406915.199999994,287478.650000005],[406915.999999991,287478.800000005],[406918.300000007,287479.200000003],[406920.649999997,287479.450000002],[406923.100000013,287479.550000001],[406925.750000001,287479.450000002],[406928.39999999,287479.150000003],[406929.80000001,287478.950000004],[406932.449999998,287478.350000006],[406935.099999987,287477.60000001],[406938.699999998,287476.349999989],[406939.649999994,287473.949999999],[406939.799999993,287473.949999999],[406941.249999987,287473.75],[406942.700000007,287473.250000002],[406943.100000005,287473.100000003],[406943.950000001,287472.750000004],[406944.799999998,287472.300000006],[406944.999999997,287472.200000007],[406946.099999992,287471.200000011],[406946.299999991,287470.950000012],[406948.00000001,287468.599999996],[406948.10000001,287468.399999997],[406950.100000001,287465.050000011],[406951.949999993,287461.450000001],[406952.049999993,287461.300000001],[406952.69999999,287459.900000007],[406953.249999987,287458.549999987],[406953.349999987,287458.299999988],[406953.650000012,287457.299999992],[406953.900000011,287456.349999996],[406954.00000001,287455.300000001],[406954.00000001,287454.750000003],[406953.850000011,287453.750000008],[406953.550000012,287452.900000011],[406953.299999987,287452.299999988],[406954.500000008,287450.299999996],[406954.00000001,287449.000000002],[406953.399999987,287447.950000006],[406953.199999988,287447.550000008],[406952.69999999,287446.850000011],[406952.149999992,287446.099999988],[406951.499999995,287445.499999991],[406951.149999996,287445.249999992],[406950.449999999,287444.849999994],[406949.600000003,287444.599999995],[406949.350000004,287444.549999995],[406948.250000009,287444.499999995],[406947.149999987,287444.699999994],[406946.849999989,287444.749999994],[406945.899999993,287444.949999993],[406944.999999997,287445.349999991],[406944.499999999,287445.64999999],[406943.650000003,287446.349999987],[406942.900000006,287447.10000001],[406942.500000008,287447.800000007],[406942.00000001,287448.700000003],[406941.600000011,287449.599999999],[406941.350000013,287450.849999994],[406941.350000013,287451.84999999],[406941.450000012,287452.850000012],[406941.750000011,287453.850000007],[406941.800000011,287454.000000007],[406942.150000009,287454.850000003],[406942.650000007,287455.6],[406943.150000005,287456.299999997],[406944.499999999,287457.299999992],[406944.899999997,287457.599999991],[406945.299999995,287457.949999989],[406944.399999999,287461.450000001],[406941.750000011,287461.999999998],[406944.399999999,287461.450000001]],[[406944.399999999,287461.450000001],[406947.750000011,287462.299999997],[406946.44999999,287467.450000001],[406943.050000005,287466.550000005],[406927.799999992,287456.849999994],[406944.399999999,287461.450000001]]]}"; - JsonFactory jsonFactory = new JsonFactory(); - JsonParser jsonParser = jsonFactory.createParser(str); - MapGeometry mg = GeometryEngine.jsonToGeometry(jsonParser); - boolean res = GeometryEngine.contains(mg.getGeometry(), - mg.getGeometry(), null); - assertTrue(res); - } + @Override + protected void setUp() throws Exception { + super.setUp(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + } + + @Test + public static void testContainsFailureCR186456() throws JsonParseException, IOException { + String str = "{\"rings\":[[[406944.399999999,287461.450000001],[406947.750000011,287462.299999997],[406946.44999999,287467.450000001],[406943.050000005,287466.550000005],[406927.799999992,287456.849999994],[406926.949999996,287456.599999995],[406924.800000005,287455.999999998],[406924.300000007,287455.849999999],[406924.200000008,287456.099999997],[406923.450000011,287458.449999987],[406922.999999987,287459.800000008],[406922.29999999,287462.099999998],[406921.949999991,287463.449999992],[406921.449999993,287465.050000011],[406920.749999996,287466.700000004],[406919.800000001,287468.599999996],[406919.050000004,287469.99999999],[406917.800000009,287471.800000008],[406916.04999999,287473.550000001],[406915.449999993,287473.999999999],[406913.700000001,287475.449999993],[406913.300000002,287475.899999991],[406912.050000008,287477.250000011],[406913.450000002,287478.150000007],[406915.199999994,287478.650000005],[406915.999999991,287478.800000005],[406918.300000007,287479.200000003],[406920.649999997,287479.450000002],[406923.100000013,287479.550000001],[406925.750000001,287479.450000002],[406928.39999999,287479.150000003],[406929.80000001,287478.950000004],[406932.449999998,287478.350000006],[406935.099999987,287477.60000001],[406938.699999998,287476.349999989],[406939.649999994,287473.949999999],[406939.799999993,287473.949999999],[406941.249999987,287473.75],[406942.700000007,287473.250000002],[406943.100000005,287473.100000003],[406943.950000001,287472.750000004],[406944.799999998,287472.300000006],[406944.999999997,287472.200000007],[406946.099999992,287471.200000011],[406946.299999991,287470.950000012],[406948.00000001,287468.599999996],[406948.10000001,287468.399999997],[406950.100000001,287465.050000011],[406951.949999993,287461.450000001],[406952.049999993,287461.300000001],[406952.69999999,287459.900000007],[406953.249999987,287458.549999987],[406953.349999987,287458.299999988],[406953.650000012,287457.299999992],[406953.900000011,287456.349999996],[406954.00000001,287455.300000001],[406954.00000001,287454.750000003],[406953.850000011,287453.750000008],[406953.550000012,287452.900000011],[406953.299999987,287452.299999988],[406954.500000008,287450.299999996],[406954.00000001,287449.000000002],[406953.399999987,287447.950000006],[406953.199999988,287447.550000008],[406952.69999999,287446.850000011],[406952.149999992,287446.099999988],[406951.499999995,287445.499999991],[406951.149999996,287445.249999992],[406950.449999999,287444.849999994],[406949.600000003,287444.599999995],[406949.350000004,287444.549999995],[406948.250000009,287444.499999995],[406947.149999987,287444.699999994],[406946.849999989,287444.749999994],[406945.899999993,287444.949999993],[406944.999999997,287445.349999991],[406944.499999999,287445.64999999],[406943.650000003,287446.349999987],[406942.900000006,287447.10000001],[406942.500000008,287447.800000007],[406942.00000001,287448.700000003],[406941.600000011,287449.599999999],[406941.350000013,287450.849999994],[406941.350000013,287451.84999999],[406941.450000012,287452.850000012],[406941.750000011,287453.850000007],[406941.800000011,287454.000000007],[406942.150000009,287454.850000003],[406942.650000007,287455.6],[406943.150000005,287456.299999997],[406944.499999999,287457.299999992],[406944.899999997,287457.599999991],[406945.299999995,287457.949999989],[406944.399999999,287461.450000001],[406941.750000011,287461.999999998],[406944.399999999,287461.450000001]],[[406944.399999999,287461.450000001],[406947.750000011,287462.299999997],[406946.44999999,287467.450000001],[406943.050000005,287466.550000005],[406927.799999992,287456.849999994],[406944.399999999,287461.450000001]]]}"; + JsonFactory jsonFactory = new JsonFactory(); + JsonParser jsonParser = jsonFactory.createParser(str); + MapGeometry mg = GeometryEngine.jsonToGeometry(jsonParser); + boolean res = GeometryEngine.contains(mg.getGeometry(), + mg.getGeometry(), null); + assertTrue(res); + } } diff --git a/src/test/java/com/esri/core/geometry/TestConvexHull.java b/src/test/java/com/esri/core/geometry/TestConvexHull.java index 16166fda..ee9c764e 100644 --- a/src/test/java/com/esri/core/geometry/TestConvexHull.java +++ b/src/test/java/com/esri/core/geometry/TestConvexHull.java @@ -27,970 +27,1046 @@ import junit.framework.TestCase; import org.junit.Test; -public class TestConvexHull extends TestCase { - @Override - protected void setUp() throws Exception { - super.setUp(); - } - - @Override - protected void tearDown() throws Exception { - super.tearDown(); - } - - @Test - public static void testFewPoints() { - { - Polygon polygon = new Polygon(); - polygon.addPath((Point2D[]) null, 0, true); - polygon.insertPoint(0, -1, Point2D.construct(5, 5)); - - Point convex_hull = (Point) OperatorConvexHull.local().execute(polygon, null); - assertTrue(convex_hull.getXY().equals(Point2D.construct(5, 5))); - } - - { - Point2D[] pts = new Point2D[3]; - - pts[0] = Point2D.construct(0, 0); - pts[1] = Point2D.construct(0, 0); - pts[2] = Point2D.construct(0, 0); - - int[] out_pts = new int[3]; - int res = ConvexHull.construct(pts, 3, out_pts); - assertTrue(res == 1); - assertTrue(out_pts[0] == 0); - } - - { - Point2D[] pts = new Point2D[1]; - pts[0] = Point2D.construct(0, 0); - - int[] out_pts = new int[1]; - int res = ConvexHull.construct(pts, 1, out_pts); - assertTrue(res == 1); - assertTrue(out_pts[0] == 0); - } - } - - @Test - public static void testDegenerate() { - OperatorConvexHull bounding = (OperatorConvexHull) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ConvexHull); - OperatorDensifyByLength densify = (OperatorDensifyByLength) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.DensifyByLength); - - { - Polygon polygon = new Polygon(); - polygon.startPath(0, 0); - polygon.lineTo(1, 0); - polygon.lineTo(0, 0); - polygon.lineTo(2, 0); - polygon.lineTo(1, 0); - polygon.lineTo(3, 0); - - polygon.startPath(0, 0); - polygon.lineTo(1, 0); - polygon.lineTo(0, 0); - polygon.lineTo(2, 0); - polygon.lineTo(1, 0); - polygon.lineTo(3, 0); - - Polygon densified = (Polygon) (densify.execute(polygon, .5, null)); - Polyline convex_hull = (Polyline) (bounding.execute(densified, null)); - assertTrue(bounding.isConvex(convex_hull, null)); - assertTrue(convex_hull.calculateArea2D() == 0.0); - - Point2D p1 = convex_hull.getXY(0); - Point2D p2 = convex_hull.getXY(1); - assertTrue(p1.x == 0.0 && p1.y == 0.0); - assertTrue(p2.x == 3.0 && p2.y == 0.0); - } - - { - Polygon polygon = new Polygon(); - polygon.startPath(0, 0); - polygon.lineTo(0, 0); - polygon.lineTo(0, 0); - polygon.lineTo(NumberUtils.doubleEps(), 0); - polygon.lineTo(0, NumberUtils.doubleEps()); - polygon.lineTo(10, 0); - polygon.lineTo(10, 0); - polygon.lineTo(10, 5); - polygon.lineTo(10, 10); - polygon.lineTo(5, 10); - polygon.lineTo(10, 0); - polygon.lineTo(10, 10); - polygon.lineTo(5, 10); - polygon.lineTo(0, 10); - polygon.lineTo(0, 0); - - polygon.startPath(0, 0); - polygon.lineTo(0, 0); - polygon.lineTo(0, 0); - polygon.lineTo(10, 0); - polygon.lineTo(10, 0); - polygon.lineTo(10, 5); - polygon.lineTo(10, 10); - polygon.lineTo(5, 10); - polygon.lineTo(10, 0); - polygon.lineTo(10, 10); - polygon.lineTo(5, 10); - polygon.lineTo(0, 10); - polygon.lineTo(0, 0); - - polygon.startPath(0, 0); - polygon.lineTo(0, 0); - polygon.lineTo(0, 0); - polygon.lineTo(10, 0); - polygon.lineTo(5, 0); - polygon.lineTo(10, 0); - polygon.lineTo(10, 5); - polygon.lineTo(10, 0); - polygon.lineTo(10, 10); - polygon.lineTo(5, 10); - polygon.lineTo(10, 10); - polygon.lineTo(5, 10); - polygon.lineTo(0, 10); - polygon.lineTo(5, 10); - polygon.lineTo(0, 0); - - Polygon densified = (Polygon) (densify.execute(polygon, 1, null)); - Polygon convex_hull = (Polygon) (bounding.execute(densified, null)); - - double area = convex_hull.calculateArea2D(); - assertTrue(bounding.isConvex(convex_hull, null)); - assertTrue(area == 100.0); - - Point2D p1 = convex_hull.getXY(0); - Point2D p2 = convex_hull.getXY(1); - Point2D p3 = convex_hull.getXY(2); - Point2D p4 = convex_hull.getXY(3); - assertTrue(p1.x == 0.0 && p1.y == 0.0); - assertTrue(p2.x == 0.0 && p2.y == 10.0); - assertTrue(p3.x == 10.0 && p3.y == 10.0); - assertTrue(p4.x == 10.0 && p4.y == 0.0); - } - - { - Polygon polygon = new Polygon(); - polygon.startPath(0, 0); - polygon.lineTo(0, 10); - polygon.lineTo(5, 10); - polygon.lineTo(5, 5); - polygon.lineTo(5, 8); - polygon.lineTo(10, 10); - polygon.lineTo(10, 0); - - Polygon densified = (Polygon) (densify.execute(polygon, 1, null)); - Polygon convex_hull = (Polygon) (bounding.execute(densified, null)); - - double area = convex_hull.calculateArea2D(); - assertTrue(bounding.isConvex(convex_hull, null)); - assertTrue(area == 100.0); - - Point2D p1 = convex_hull.getXY(0); - Point2D p2 = convex_hull.getXY(1); - Point2D p3 = convex_hull.getXY(2); - Point2D p4 = convex_hull.getXY(3); - assertTrue(p1.x == 0.0 && p1.y == 0.0); - assertTrue(p2.x == 0.0 && p2.y == 10.0); - assertTrue(p3.x == 10.0 && p3.y == 10.0); - assertTrue(p4.x == 10.0 && p4.y == 0.0); - } - - { - Polygon polygon = new Polygon(); - polygon.startPath(0, 0); - polygon.lineTo(0, 0); - polygon.lineTo(0, 0); - polygon.lineTo(10, 0); - polygon.lineTo(5, 0); - polygon.lineTo(10, 0); - polygon.lineTo(10, 5); - polygon.lineTo(10, 0); - polygon.lineTo(10, 10); - polygon.lineTo(5, 10); - polygon.lineTo(10, 10); - polygon.lineTo(5, 10); - polygon.lineTo(0, 10); - polygon.lineTo(5, 10); - polygon.lineTo(0, 0); - Polygon densified = (Polygon) (densify.execute(polygon, 1, null)); - Polygon convex_hull = (Polygon) (bounding.execute(densified, null)); - double area = convex_hull.calculateArea2D(); - assertTrue(bounding.isConvex(convex_hull, null)); - assertTrue(area == 100.0); - - Point2D p1 = convex_hull.getXY(0); - Point2D p2 = convex_hull.getXY(1); - Point2D p3 = convex_hull.getXY(2); - Point2D p4 = convex_hull.getXY(3); - assertTrue(p1.x == 0.0 && p1.y == 0.0); - assertTrue(p2.x == 0.0 && p2.y == 10.0); - assertTrue(p3.x == 10.0 && p3.y == 10.0); - assertTrue(p4.x == 10.0 && p4.y == 0.0); - } - - { - Polygon polygon = new Polygon(); - polygon.startPath(0, 0); - polygon.lineTo(0, 0); - polygon.lineTo(0, 10); - polygon.lineTo(0, 0); - polygon.lineTo(10, 10); - polygon.lineTo(0, 0); - polygon.lineTo(10, 0); - polygon.lineTo(0, 0); - - polygon.startPath(0, 10); - polygon.lineTo(0, 10); - polygon.lineTo(10, 10); - polygon.lineTo(0, 10); - polygon.lineTo(10, 0); - polygon.lineTo(0, 10); - polygon.lineTo(0, 0); - polygon.lineTo(0, 10); - - polygon.startPath(10, 10); - polygon.lineTo(10, 10); - polygon.lineTo(10, 0); - polygon.lineTo(10, 10); - polygon.lineTo(0, 0); - polygon.lineTo(10, 10); - polygon.lineTo(0, 10); - polygon.lineTo(10, 10); - - polygon.startPath(10, 0); - polygon.lineTo(10, 0); - polygon.lineTo(0, 0); - polygon.lineTo(10, 0); - polygon.lineTo(0, 10); - polygon.lineTo(10, 0); - polygon.lineTo(10, 10); - polygon.lineTo(10, 0); - - Polygon densified = (Polygon) (densify.execute(polygon, 1, null)); - Polygon convex_hull = (Polygon) (bounding.execute(densified, null)); - assertTrue(bounding.isConvex(convex_hull, null)); - - Point2D p1 = convex_hull.getXY(0); - Point2D p2 = convex_hull.getXY(1); - Point2D p3 = convex_hull.getXY(2); - Point2D p4 = convex_hull.getXY(3); - assertTrue(p1.x == 0.0 && p1.y == 0.0); - assertTrue(p2.x == 0.0 && p2.y == 10.0); - assertTrue(p3.x == 10.0 && p3.y == 10.0); - assertTrue(p4.x == 10.0 && p4.y == 0.0); - } - - { - MultiPoint mpoint = new MultiPoint(); - mpoint.add(4, 4); - mpoint.add(4, 4); - mpoint.add(4, 4); - mpoint.add(4, 4); - - Point convex_hull = (Point) bounding.execute(mpoint, null); - assertTrue(convex_hull.calculateArea2D() == 0.0); - assertTrue(bounding.isConvex(convex_hull, null)); - assertTrue(convex_hull.getXY().equals(Point2D.construct(4, 4))); - } - - { - MultiPoint mpoint = new MultiPoint(); - mpoint.add(4, 4); - - Point convex_hull = (Point) bounding.execute(mpoint, null); - assertTrue(bounding.isConvex(convex_hull, null)); - assertTrue(convex_hull.getXY().equals(Point2D.construct(4, 4))); - } - - { - MultiPoint mpoint = new MultiPoint(); - mpoint.add(4, 4); - mpoint.add(4, 5); - - Polyline convex_hull = (Polyline) bounding.execute(mpoint, null); - assertTrue(convex_hull.getPointCount() == 2); - assertTrue(bounding.isConvex(convex_hull, null)); - assertTrue(convex_hull.calculateLength2D() == 1.0); - } - - { - Line line = new Line(); - line.setStartXY(0, 0); - line.setEndXY(0, 1); - - Polyline convex_hull = (Polyline) bounding.execute(line, null); - assertTrue(convex_hull.getPointCount() == 2); - assertTrue(bounding.isConvex(convex_hull, null)); - assertTrue(convex_hull.calculateLength2D() == 1.0); - } - - { - Polyline polyline = new Polyline(); - polyline.startPath(0, 0); - polyline.lineTo(0, 1); - - Polyline convex_hull = (Polyline) bounding.execute(polyline, null); - assertTrue(convex_hull.getPointCount() == 2); - assertTrue(bounding.isConvex(convex_hull, null)); - assertTrue(polyline == convex_hull); - assertTrue(convex_hull.calculateLength2D() == 1.0); - } - - { - Envelope env = new Envelope(0, 0, 10, 10); - assertTrue(OperatorConvexHull.local().isConvex(env, null)); - - Polygon convex_hull = (Polygon) bounding.execute(env, null); - assertTrue(bounding.isConvex(convex_hull, null)); - assertTrue(convex_hull.getPointCount() == 4); - assertTrue(convex_hull.getXY(0).equals(Point2D.construct(0, 0))); - assertTrue(convex_hull.getXY(1).equals(Point2D.construct(0, 10))); - assertTrue(convex_hull.getXY(2).equals(Point2D.construct(10, 10))); - assertTrue(convex_hull.getXY(3).equals(Point2D.construct(10, 0))); - } - - { - Envelope env = new Envelope(0, 0, 0, 10); - assertTrue(!OperatorConvexHull.local().isConvex(env, null)); - - Polyline convex_hull = (Polyline) bounding.execute(env, null); - assertTrue(bounding.isConvex(convex_hull, null)); - assertTrue(convex_hull.getPointCount() == 2); - assertTrue(convex_hull.getXY(0).equals(Point2D.construct(0, 0))); - assertTrue(convex_hull.getXY(1).equals(Point2D.construct(0, 10))); - } - - { - Envelope env = new Envelope(0, 0, 0, 10); - assertTrue(!OperatorConvexHull.local().isConvex(env, null)); - - Polyline convex_hull = (Polyline) bounding.execute(env, null); - assertTrue(bounding.isConvex(convex_hull, null)); - assertTrue(convex_hull.getPointCount() == 2); - assertTrue(convex_hull.getXY(0).equals(Point2D.construct(0, 0))); - assertTrue(convex_hull.getXY(1).equals(Point2D.construct(0, 10))); - } - - { - Envelope env = new Envelope(5, 5, 5, 5); - assertTrue(!OperatorConvexHull.local().isConvex(env, null)); - - Point convex_hull = (Point) bounding.execute(env, null); - assertTrue(bounding.isConvex(convex_hull, null)); - assertTrue(convex_hull.getXY().equals(Point2D.construct(5, 5))); - } - } - - @Test - public static void testSegment() { - { - Line line = new Line(); - line.setStartXY(5, 5); - line.setEndXY(5, 5); - - assertTrue(!OperatorConvexHull.local().isConvex(line, null)); - Point point = (Point) OperatorConvexHull.local().execute(line, null); - assertTrue(point.getXY().equals(Point2D.construct(5, 5))); - } - - { - Line line = new Line(); - line.setStartXY(5, 5); - line.setEndXY(5, 6); - - assertTrue(OperatorConvexHull.local().isConvex(line, null)); - Polyline polyline = (Polyline) OperatorConvexHull.local().execute(line, null); - assertTrue(polyline.getPointCount() == 2); - assertTrue(polyline.getXY(0).equals(Point2D.construct(5, 5))); - assertTrue(polyline.getXY(1).equals(Point2D.construct(5, 6))); - } - } - - - @Test - public static void testSquare() { - OperatorConvexHull bounding = (OperatorConvexHull) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ConvexHull); - OperatorDensifyByLength densify = (OperatorDensifyByLength) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.DensifyByLength); - OperatorDifference difference = (OperatorDifference) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.Difference); - OperatorContains contains = (OperatorContains) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.Contains); - - Polygon square = new Polygon(); - square.startPath(0, 0); - square.lineTo(2, 3); - square.lineTo(1, 4); - square.lineTo(0, 5); - square.lineTo(0, 7); - square.lineTo(2, 7); - square.lineTo(0, 10); - square.lineTo(4, 7); - square.lineTo(6, 7); - square.lineTo(7, 10); - square.lineTo(8, 10); - square.lineTo(10, 10); - square.lineTo(8, 7); - square.lineTo(10, 5); - square.lineTo(8, 3); - square.lineTo(10, 1); - square.lineTo(10, 0); - square.lineTo(5, 5); - square.lineTo(8, 0); - square.lineTo(4, 3); - square.lineTo(5, 0); - square.lineTo(3, 1); - square.lineTo(3, 0); - square.lineTo(2, 1); - - Polygon densified = (Polygon) (densify.execute(square, 1.0, null)); - - densified.addAttribute(VertexDescription.Semantics.ID); - for (int i = 0; i < densified.getPointCount(); i++) - densified.setAttribute(VertexDescription.Semantics.ID, i, 0, i); - - Polygon convex_hull = (Polygon) (bounding.execute(densified, null)); - Polygon differenced = (Polygon) (difference.execute(densified, convex_hull, SpatialReference.create(4326), null)); - - assertTrue(differenced.isEmpty()); - assertTrue(bounding.isConvex(convex_hull, null)); - } - - @Test - public static void testPolygons() { - OperatorConvexHull bounding = (OperatorConvexHull) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ConvexHull); - OperatorDensifyByLength densify = (OperatorDensifyByLength) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.DensifyByLength); - OperatorDifference difference = (OperatorDifference) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.Difference); - - { - Polygon shape = (Polygon) (TestCommonMethods.fromJson("{\"rings\":[[[1.3734426370715553,-90],[-24.377532184629967,-63.428606327053856],[-25.684686546621553,90],[-24.260574484321914,80.526315789473699],[-25.414389575040037,90],[-23.851448513708718,90],[-23.100135788742072,87.435887853000679],[5.6085096351011448,-48.713222410606306],[1.3734426370715553,-90]]]}").getGeometry()); - Polygon convex_hull = (Polygon) (bounding.execute(shape, null)); - Polygon differenced = (Polygon) (difference.execute(shape, convex_hull, SpatialReference.create(4326), null)); - assertTrue(differenced.isEmpty()); - assertTrue(bounding.isConvex(convex_hull, null)); - } - - { - Polygon polygon = (Polygon) (TestCommonMethods.fromJson("{\"rings\":[[[-179.64843749999693,-43.3535476539993],[-179.99999999999696,-43.430006211999284],[-179.99999999999696,39.329644416999436],[-179.64843749999693,38.98862638799943],[-89.99999999999838,29.008084980999506],[-112.8515624999981,-16.20113770599962],[-115.66406249999804,-18.882554574999688],[-124.80468749999788,-23.7925511709996],[-138.86718749999767,-30.6635901109995],[-157.49999999999736,-38.468358112999354],[-162.42187499999724,-39.56498442199932],[-179.64843749999693,-43.3535476539993]],[[179.99999999999696,-43.430006211999284],[179.64843749999693,-43.50646476999926],[162.0703124999973,-42.36267115399919],[160.3124999999973,-42.24790485699929],[143.78906249999756,-41.1680427339993],[138.16406249999767,-39.64744846799925],[98.43749999999845,-28.523889212999524],[78.39843749999878,-5.1644422999998705],[75.9374999999988,19.738611663999766],[88.2421874999986,33.51651305599954],[108.63281249999815,44.160795160999356],[138.16406249999767,51.02062617799914],[140.9765624999976,51.68129673399923],[160.3124999999973,52.8064856429991],[162.0703124999973,52.908902047999206],[163.12499999999727,52.97036560499911],[165.93749999999716,52.97036560499911],[179.99999999999696,39.329644416999436],[179.99999999999696,-43.430006211999284]]]}").getGeometry()); - Polygon densified = (Polygon) (densify.execute(polygon, 10.0, null)); - Polygon convex_hull = (Polygon) (bounding.execute(densified, null)); - Polygon differenced = (Polygon) (difference.execute(densified, convex_hull, SpatialReference.create(4326), null)); - assertTrue(differenced.isEmpty()); - assertTrue(bounding.isConvex(convex_hull, null)); - } - - { - Polygon polygon = new Polygon(); - polygon.startPath(1, 0); - polygon.lineTo(-1, 0); - polygon.lineTo(0, -1); - Polygon convex_hull = (Polygon) (bounding.execute(polygon, null)); - Polygon differenced = (Polygon) (difference.execute(polygon, convex_hull, SpatialReference.create(4326), null)); - assertTrue(differenced.isEmpty()); - assertTrue(bounding.isConvex(convex_hull, null)); - } - - { - Polygon polygon = (Polygon) (TestCommonMethods.fromJson("{\"rings\":[[[-38.554566833914528,21.902000764339238],[-30.516168471666138,90],[-38.554566833914528,21.902000764339238]],[[-43.013227444613932,28.423410187206883],[-43.632473335895916,90],[-42.342268693420237,62.208637129146894],[-37.218731802058755,63.685357222187029],[-32.522681335230686,47.080307818055296],[-40.537308829621097,-21.881392019745604],[-47.59510451722663,18.812521648505964],[-53.25344489340366,30.362745244224911],[-46.629060462410138,90],[-50.069277433245119,18.254168921734287],[-42.171214434397982,72.623347387008081],[-43.000844452530551,90],[-46.162281544954659,90],[-39.462049205071331,90],[-47.434856316742902,38.662565208814371],[-52.13115779642537,-19.952586632199857],[-56.025328966335081,90],[-60.056846215416158,-44.023645282268355],[-60.12338894192289,50.374596189881942],[-35.787508034048379,-7.8839007676038513],[-60.880218074135605,-46.447995750907815],[-67.782542852117956,-85.106300958016107],[-65.053131764313761,-0.96651520578494665],[-72.375821140304154,90],[-78.561502106749245,90],[-83.809168672565946,33.234498214085811],[-60.880218054506344,-46.447995733653201],[-75.637095425108981,59.886574792622838],[-71.364085965028096,31.976373491332097],[-67.89968380886117,90],[-67.544349171474749,8.8435794458927504],[-70.780047377934707,80.683454463576624],[-64.996733940204948,34.349882797035313],[-56.631753638680905,39.815838152456926],[-60.392350183516896,52.75446132093407],[-58.51633728692137,90],[-64.646972065627097,41.444197803942579],[-73.355591244695518,-0.15370205145035776],[-43.013227444613932,28.423410187206883]],[[-69.646471076946,-85.716191379686904],[-62.854465128320491,-45.739046580967972],[-71.377481570643141,-90],[-66.613495837251435,-90],[-66.9765142407159,-90],[-66.870099169607329,-90],[-67.23180828626819,-61.248439074609649],[-58.889775875438851,-90],[-53.391995883729322,-69.476385967096491],[-69.646471076946,-85.716191379686904]]]}").getGeometry()); - Polygon densified = (Polygon) (densify.execute(polygon, 10.0, null)); - Polygon convex_hull = (Polygon) (bounding.execute(densified, null)); - Polygon differenced = (Polygon) (difference.execute(densified, convex_hull, SpatialReference.create(4326), null)); - assertTrue(differenced.isEmpty()); - // assertTrue(bounding.isConvex(*convex_hull, null)); - } - - { - Polygon polygon = (Polygon) (TestCommonMethods.fromJson("{\"rings\":[[[-38.554566833914528,21.902000764339238],[-30.516168471666138,90],[-38.554566833914528,21.902000764339238]],[[-43.013227444613932,28.423410187206883],[-43.632473335895916,90],[-42.342268693420237,62.208637129146894],[-37.218731802058755,63.685357222187029],[-32.522681335230686,47.080307818055296],[-40.537308829621097,-21.881392019745604],[-47.59510451722663,18.812521648505964],[-53.25344489340366,30.362745244224911],[-46.629060462410138,90],[-50.069277433245119,18.254168921734287],[-42.171214434397982,72.623347387008081],[-43.000844452530551,90],[-46.162281544954659,90],[-39.462049205071331,90],[-47.434856316742902,38.662565208814371],[-52.13115779642537,-19.952586632199857],[-56.025328966335081,90],[-60.056846215416158,-44.023645282268355],[-60.12338894192289,50.374596189881942],[-35.787508034048379,-7.8839007676038513],[-60.880218074135605,-46.447995750907815],[-67.782542852117956,-85.106300958016107],[-65.053131764313761,-0.96651520578494665],[-72.375821140304154,90],[-78.561502106749245,90],[-83.809168672565946,33.234498214085811],[-60.880218054506344,-46.447995733653201],[-75.637095425108981,59.886574792622838],[-71.364085965028096,31.976373491332097],[-67.89968380886117,90],[-67.544349171474749,8.8435794458927504],[-70.780047377934707,80.683454463576624],[-64.996733940204948,34.349882797035313],[-56.631753638680905,39.815838152456926],[-60.392350183516896,52.75446132093407],[-58.51633728692137,90],[-64.646972065627097,41.444197803942579],[-73.355591244695518,-0.15370205145035776],[-43.013227444613932,28.423410187206883]],[[-69.646471076946,-85.716191379686904],[-62.854465128320491,-45.739046580967972],[-71.377481570643141,-90],[-66.613495837251435,-90],[-66.9765142407159,-90],[-66.870099169607329,-90],[-67.23180828626819,-61.248439074609649],[-58.889775875438851,-90],[-53.391995883729322,-69.476385967096491],[-69.646471076946,-85.716191379686904]]]}").getGeometry()); - Polygon convex_hull = (Polygon) (bounding.execute(polygon, null)); - Polygon differenced = (Polygon) (difference.execute(polygon, convex_hull, SpatialReference.create(4326), null)); - assertTrue(differenced.isEmpty()); - assertTrue(bounding.isConvex(convex_hull, null)); - } - - { - Polygon polygon = (Polygon) (TestCommonMethods.fromJson("{\"rings\":[[[-36.269498017702901,-26.37490682626369],[-49.146436641060951,-49.881862499696126],[-37.560006446488146,-45.592052597656789],[-39.13770692863632,-69.085816352131204],[-65.415587331361877,-90],[-51.462290812033373,-16.760787566546721],[-28.454456182408332,90],[-36.269498017702901,-26.37490682626369]],[[-40.542178258552283,-90],[-39.13770692863632,-69.085816352131204],[-16.295804332590937,-50.906277575066262],[-40.542178258552283,-90]],[[-16.295804332590937,-50.906277575066262],[-5.6790432913971927,-33.788307256548933],[14.686101893282586,-26.248228042967728],[-16.295804332590937,-50.906277575066262]],[[-37.560006446488146,-45.592052597656789],[-36.269498017702901,-26.37490682626369],[27.479825940672225,90],[71.095881152477034,90],[-5.6790432913971927,-33.788307256548933],[-37.560006446488146,-45.592052597656789]]]}").getGeometry()); - Polygon convex_hull = (Polygon) (bounding.execute(polygon, null)); - Polygon differenced = (Polygon) (difference.execute(polygon, convex_hull, SpatialReference.create(4326), null)); - assertTrue(differenced.isEmpty()); - assertTrue(bounding.isConvex(convex_hull, null)); - } - - { - Polygon polygon = (Polygon) (TestCommonMethods.fromJson("{\"rings\":[[[-77.020281185856106,-80.085419699581706],[-77.328568930885723,-83.404479889897416],[-80.495259564600545,-90],[-77.020281185856106,-80.085419699581706]],[[-77.941187535385211,-90],[-77.328568930885723,-83.404479889897416],[-39.252034383972621,-4.0994329574862469],[-39.29471328421063,-6.5269494453154593],[-77.941187535385211,-90]],[[-77.020281185856106,-80.085419699581706],[-62.688864277996522,74.208210509833052],[-38.108861278327581,80.371071656873013],[-37.597643844595929,90],[-38.663943358642484,29.350366647752089],[-77.020281185856106,-80.085419699581706]],[[-40.265125886194951,-61.722668598742551],[-39.29471328421063,-6.5269494453154593],[-15.554402498931253,44.750073899273843],[-8.4447006412989474,13.127318978368956],[-5.310206313296316,-4.5170390491918795],[-40.265125886194951,-61.722668598742551]],[[-39.252034383972621,-4.0994329574862469],[-38.663943358642484,29.350366647752089],[-22.476078360563164,75.536520897660651],[-15.632105532320049,45.095683888365997],[-39.252034383972621,-4.0994329574862469]],[[-15.554402498931253,44.750073899273843],[-15.632105532320049,45.095683888365997],[-8.9755856576261941,58.959750756602595],[-15.554402498931253,44.750073899273843]]]}").getGeometry()); - Polygon convex_hull = (Polygon) (bounding.execute(polygon, null)); - Polygon differenced = (Polygon) (difference.execute(polygon, convex_hull, SpatialReference.create(4326), null)); - assertTrue(differenced.isEmpty()); - assertTrue(bounding.isConvex(convex_hull, null)); - } - - { - Polygon polygon = (Polygon) (TestCommonMethods.fromJson("{\"rings\":[[[-68.840007952128175,37.060080998089632],[-68.145986924561413,31.114096694815196],[-69.187773850176768,30.693518246958952],[-68.840007952128175,37.060080998089632]],[[-75.780513355389928,-90],[-69.21567111077384,30.182802098042274],[-50.875629803516389,37.146119571446704],[-75.780513355389928,-90]],[[4.2911006174797457,-1.144569312564311],[-66.484019915251849,80.191238371060038],[-65.948228008382316,90],[4.2911006174797457,-1.144569312564311]],[[-90,22.291441435181515],[-69.187773850176768,30.693518246958952],[-69.21567111077384,30.182802098042274],[-90,22.291441435181515]],[[-68.840007952128175,37.060080998089632],[-75.019206401201359,90],[-66.484019915251849,80.191238371060038],[-68.840007952128175,37.060080998089632]]]}").getGeometry()); - Polygon convex_hull = (Polygon) (bounding.execute(polygon, null)); - Polygon differenced = (Polygon) (difference.execute(polygon, convex_hull, SpatialReference.create(4326), null)); - assertTrue(differenced.isEmpty()); - assertTrue(bounding.isConvex(convex_hull, null)); - } - - { - Polygon polygon = (Polygon) (TestCommonMethods.fromJson("{\"rings\":[[[27.570109889215438,22.850616190228489],[75.703105729477357,-90],[2.1548000876241362,-15.817792950796967],[27.570109889215438,22.850616190228489]],[[-0.069915984436478951,-90],[-46.602410662754053,-89.999999998014729],[-14.977190481820156,-41.883452819243004],[-0.069915984436478951,-90]],[[-14.977190481820156,-41.883452819243004],[-34.509989609682322,21.163004866431177],[2.1548000876241362,-15.817792950796967],[-14.977190481820156,-41.883452819243004]]]}").getGeometry()); - Polygon convex_hull = (Polygon) (bounding.execute(polygon, null)); - Polygon differenced = (Polygon) (difference.execute(polygon, convex_hull, SpatialReference.create(4326), null)); - assertTrue(differenced.isEmpty()); - assertTrue(bounding.isConvex(convex_hull, null)); - } - - { - Polygon polygon = (Polygon) (TestCommonMethods.fromJson("{\"rings\":[[[28.865673900286581,33.379551302126075],[39.505669183485338,-34.957993133630559],[7.152466542048213,-90],[28.865673900286581,33.379551302126075]],[[-64.597291313620858,2.4515644574812248],[20.050002923927103,90],[24.375150856531356,62.220853377417541],[-64.597291313620858,2.4515644574812248]],[[28.865673900286581,33.379551302126075],[24.375150856531356,62.220853377417541],[35.223952527956932,69.508785974507163],[28.865673900286581,33.379551302126075]]]}").getGeometry()); - Polygon convex_hull = (Polygon) (bounding.execute(polygon, null)); - Polygon differenced = (Polygon) (difference.execute(polygon, convex_hull, SpatialReference.create(4326), null)); - assertTrue(differenced.isEmpty()); - assertTrue(bounding.isConvex(convex_hull, null)); - } - - { - Polygon polygon = (Polygon) (TestCommonMethods.fromJson("{\"rings\":[[[-66.582505384413167,-51.305212522944061],[-60.169897093348865,-90],[-90,-90],[-66.582505384413167,-51.305212522944061]],[[20.858462934004656,-90],[-35.056287147954386,0.78833269359179781],[18.933251883215579,90],[20.858462934004656,-90]],[[-66.582505384413167,-51.305212522944061],[-90,90],[-35.056287147954386,0.78833269359179781],[-66.582505384413167,-51.305212522944061]]]}").getGeometry()); - Polygon convex_hull = (Polygon) (bounding.execute(polygon, null)); - Polygon differenced = (Polygon) (difference.execute(polygon, convex_hull, SpatialReference.create(4326), null)); - assertTrue(differenced.isEmpty()); - assertTrue(bounding.isConvex(convex_hull, null)); - } - - { - Polygon polygon = (Polygon) (TestCommonMethods.fromJson("{\"rings\":[[[36.692916710279974,-90],[-31.182443792600079,6.434474852744998],[-90,90],[52.245260790065387,57.329280208760991],[36.692916710279974,-90]]]}").getGeometry()); - Polygon convex_hull = (Polygon) (bounding.execute(polygon, null)); - Polygon differenced = (Polygon) (difference.execute(polygon, convex_hull, SpatialReference.create(4326), null)); - assertTrue(differenced.isEmpty()); - assertTrue(bounding.isConvex(convex_hull, null)); - } - - { - Polygon polygon = (Polygon) (TestCommonMethods.fromJson("{\"rings\":[[[-17.959089916602533,-4.3577640799248218],[-29.181784251472308,-90],[-65.493717350127127,15.053615507086979],[-17.959089916602533,-4.3577640799248218]],[[-21.884657435973146,-34.517617672142393],[-17.94005076020704,-4.3655389655558539],[9.3768748358343359,-15.520758655380195],[-21.884657435973146,-34.517617672142393]],[[-17.94005076020704,-4.3655389655558539],[-17.959089916602533,-4.3577640799248218],[-5.8963967801936494,87.694641571893939],[-17.94005076020704,-4.3655389655558539]]]}").getGeometry()); - Polygon convex_hull = (Polygon) (bounding.execute(polygon, null)); - Polygon differenced = (Polygon) (difference.execute(polygon, convex_hull, SpatialReference.create(4326), null)); - assertTrue(differenced.isEmpty()); - assertTrue(bounding.isConvex(convex_hull, null)); - } - - { - Polygon polygon = (Polygon) (TestCommonMethods.fromJson("{\"rings\":[[[17.198360589495572,-77.168667157542373],[-24.835678541343281,-83.717338556412017],[-30.259244993378722,61.914816728303791],[17.198360589495572,-77.168667157542373]],[[-8.3544985146710644,-90],[17.979891823366039,-79.459092168186686],[21.576625471325329,-90],[-8.3544985146710644,-90]],[[17.979891823366039,-79.459092168186686],[17.198360589495572,-77.168667157542373],[27.846596597209441,-75.509730732825361],[17.979891823366039,-79.459092168186686]]]}").getGeometry()); - Polygon convex_hull = (Polygon) (bounding.execute(polygon, null)); - Polygon differenced = (Polygon) (difference.execute(polygon, convex_hull, SpatialReference.create(4326), null)); - assertTrue(differenced.isEmpty()); - assertTrue(bounding.isConvex(convex_hull, null)); - } - - { - Polygon polygon = (Polygon) (TestCommonMethods.fromJson("{\"rings\":[[[-1.2588613620456419,13.607321860624268],[61.845346679259052,48.415944386573557],[15.226225965240992,-5.3702891526017318],[0.92681706095183469,1.6819284384951441],[3.8469417404317623,-14.250715301799051],[7.2615297628459139,-14.559458820527061],[4.4896578086498238,-17.757471781424698],[14.589138845678622,-72.861774161244625],[-10.508572009494033,-35.06149380752737],[-58.12642296329372,-90],[-15.260062192400673,90],[-1.2588613620456419,13.607321860624268]],[[0.92681706095183469,1.6819284384951441],[-1.2588613620456419,13.607321860624268],[-11.641308877525201,7.8803076458946304],[0.92681706095183469,1.6819284384951441]],[[-10.508572009494033,-35.06149380752737],[4.4896578086498238,-17.757471781424698],[3.8469417404317623,-14.250715301799051],[-26.125369947914503,-11.54064986657559],[-10.508572009494033,-35.06149380752737]],[[39.829571435268129,-17.504227477249202],[7.2615297628459139,-14.559458820527061],[15.226225965240992,-5.3702891526017318],[39.829571435268129,-17.504227477249202]]]}").getGeometry()); - Polygon convex_hull = (Polygon) (bounding.execute(polygon, null)); - Polygon differenced = (Polygon) (difference.execute(polygon, convex_hull, SpatialReference.create(4326), null)); - assertTrue(differenced.isEmpty()); - assertTrue(bounding.isConvex(convex_hull, null)); - } - - { - Polygon polygon = (Polygon) (TestCommonMethods.fromJson("{\"rings\":[[[-19.681975166855118,-34.10344217707847],[-90,89.999999998418275],[53.036316534501381,90],[-19.681975166855118,-34.10344217707847]],[[-52.434509065706855,-90],[-29.2339442498794,-50.405148598356135],[-2.8515119199232331,-90],[-52.434509065706855,-90]],[[18.310881874573923,-90],[-25.473718245381271,-43.987822508814972],[-19.681975166855118,-34.10344217707847],[-15.406194071963924,-41.649717163101563],[18.310881874573923,-90]],[[-29.2339442498794,-50.405148598356135],[-52.27954259799813,-15.81822990020261],[-25.473718245381271,-43.987822508814972],[-29.2339442498794,-50.405148598356135]]]}").getGeometry()); - Polygon convex_hull = (Polygon) (bounding.execute(polygon, null)); - Polygon differenced = (Polygon) (difference.execute(polygon, convex_hull, SpatialReference.create(4326), null)); - assertTrue(differenced.isEmpty()); - assertTrue(bounding.isConvex(convex_hull, null)); - } - - { - Polygon polygon = (Polygon) (TestCommonMethods.fromJson("{\"rings\":[[[49.939516827702498,-90],[-20.470128740962011,-68.102019032647391],[-20.124197553433845,-67.213968219799824],[34.438329237618149,-61.893901496061034],[49.939516827702498,-90]],[[-82.380918375714089,-73.284249936115529],[-4.7432060543229699,9.1484031048644194],[-11.790524932251525,21.926303986370414],[-3.4862200343039369,10.483021157965428],[19.753975453441285,35.158541777575607],[5.5896897290794696,-1.2030408273476854],[73.839023528563189,-58.052174675157325],[34.438329237618149,-61.893901496061034],[3.6757233436274213,-6.1164440290327313],[-20.124197553433845,-67.213968219799824],[-82.380918375714089,-73.284249936115529]],[[5.5896897290794696,-1.2030408273476854],[4.0842948437219349,0.050896618883412792],[-3.4862200343039369,10.483021157965428],[-4.7432060543229699,9.1484031048644194],[3.6757233436274213,-6.1164440290327313],[5.5896897290794696,-1.2030408273476854]]]}").getGeometry()); - Polygon convex_hull = (Polygon) (bounding.execute(polygon, null)); - Polygon differenced = (Polygon) (difference.execute(polygon, convex_hull, SpatialReference.create(4326), null)); - assertTrue(differenced.isEmpty()); - assertTrue(bounding.isConvex(convex_hull, null)); - } - - { - Polygon polygon = (Polygon) (TestCommonMethods.fromJson("{\"rings\":[[[4.7618727814345867,-14.245890151885444],[-7.1675180359486266,-90],[-83.232840716292529,40.620187389409224],[-29.219286930421923,6.9418934044755334],[-29.378277853968513,6.9629531745072839],[-28.933835455648254,6.7639099538036529],[4.7618727814345867,-14.245890151885444]],[[51.056303527367277,-43.111190419066219],[4.7618727814345867,-14.245890151885444],[5.632592229367642,-8.716640778187827],[-28.933835455648254,6.7639099538036529],[-29.219286930421923,6.9418934044755334],[2.700964609629902,2.7137705544807242],[12.385960896403816,0.48342578457646468],[51.056303527367277,-43.111190419066219]]]}").getGeometry()); - Polygon convex_hull = (Polygon) (bounding.execute(polygon, null)); - Polygon differenced = (Polygon) (difference.execute(polygon, convex_hull, SpatialReference.create(4326), null)); - assertTrue(differenced.isEmpty()); - assertTrue(bounding.isConvex(convex_hull, null)); - } - - { - Polygon polygon = (Polygon) (TestCommonMethods.fromJson("{\"rings\":[[[-21.426619830983732,-89.379667629404466],[-72.784461583687971,-88.999754827814016],[-81.94289434769162,25.456737039611831],[-38.382426191605546,-57.204127144336077],[-41.663734179022256,-78.439084394036513],[-29.749353943865881,-73.586348060869426],[-21.426619830983732,-89.379667629404466]],[[-21.09971823441461,-90],[-21.426619830983732,-89.379667629404466],[-21.080965849893449,-89.382224558742934],[-21.09971823441461,-90]],[[62.431917153693021,-90],[-21.080965849893449,-89.382224558742934],[-20.486971473666468,-69.813772479288062],[19.166418765782844,-53.662915804391695],[63.671046682728601,-90],[62.431917153693021,-90]],[[-29.749353943865881,-73.586348060869426],[-38.382426191605546,-57.204127144336077],[-31.449272112025476,-12.336278393150847],[-41.028899505665962,-4.5147159296945967],[-30.750049689226596,-7.8112663207986941],[-15.63587330244308,90],[-18.721998818789388,-11.66880646480822],[60.158611185675326,-36.966763960486929],[19.166418765782844,-53.662915804391695],[-19.049573405176112,-22.46036923493498],[-20.486971473666468,-69.813772479288062],[-29.749353943865881,-73.586348060869426]],[[-19.049573405176112,-22.46036923493498],[-18.721998818789388,-11.66880646480822],[-30.750049689226596,-7.8112663207986941],[-31.449272112025476,-12.336278393150847],[-19.049573405176112,-22.46036923493498]]]}").getGeometry()); - Polygon convex_hull = (Polygon) (bounding.execute(polygon, null)); - Polygon differenced = (Polygon) (difference.execute(polygon, convex_hull, SpatialReference.create(4326), null)); - assertTrue(differenced.isEmpty()); - assertTrue(bounding.isConvex(convex_hull, null)); - } - - { - Polygon polygon = (Polygon) (TestCommonMethods.fromJson("{\"rings\":[[[-17.906614911617162,-53.670186894017093],[-72.687715727164573,-90],[-77.889582483879749,90],[-47.149885004784061,16.372797801863811],[-58.874489264131405,8.3403055152440846],[-44.017112148517498,8.8692333739436133],[-43.760297522359615,8.2541153357643502],[-48.398890069305921,4.7201397602360009],[-38.665987052649818,-3.9476907252248874],[-17.906614911617162,-53.670186894017093]],[[-2.7387498969355368,-90],[-17.906614911617162,-53.670186894017093],[-6.8038688963847829,-46.30705103709559],[-2.7387498969355368,-90]],[[-6.8038688963847829,-46.30705103709559],[-8.2224486207861638,-31.0597897622158],[2.1962303277340673,-40.338351652092697],[-6.8038688963847829,-46.30705103709559]],[[-8.2224486207861638,-31.0597897622158],[-38.665987052649818,-3.9476907252248874],[-43.760297522359615,8.2541153357643502],[-42.90074612601282,8.9089763975751382],[-44.017112148517498,8.8692333739436133],[-47.149885004784061,16.372797801863811],[45.190674429223662,79.635046572817728],[40.490070954305672,72.441418146356597],[63.53694979672099,90],[75.056911135062407,13.108310545642606],[-0.027204347469059975,10.435289586728711],[-10.580480746811602,-5.715051428780245],[-8.2224486207861638,-31.0597897622158]],[[-42.90074612601282,8.9089763975751382],[-0.027204347469059975,10.435289586728711],[40.490070954305672,72.441418146356597],[-42.90074612601282,8.9089763975751382]]]}").getGeometry()); - Polygon convex_hull = (Polygon) (bounding.execute(polygon, null)); - Polygon differenced = (Polygon) (difference.execute(polygon, convex_hull, SpatialReference.create(4326), null)); - assertTrue(differenced.isEmpty()); - assertTrue(bounding.isConvex(convex_hull, null)); - } - } - - @Test - public static void testPolylines() { - OperatorConvexHull bounding = (OperatorConvexHull) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ConvexHull); - OperatorDensifyByLength densify = (OperatorDensifyByLength) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.DensifyByLength); - OperatorDifference difference = (OperatorDifference) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.Difference); - OperatorContains contains = (OperatorContains) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.Contains); - - { - Polyline poly = new Polyline(); - poly.startPath(0, 0); - poly.lineTo(0, 10); - poly.lineTo(0, 20); - poly.lineTo(0, 40); - poly.lineTo(0, 500); - - Polyline densified = (Polyline) (densify.execute(poly, 10.0, null)); - Polyline convex_hull = (Polyline) (bounding.execute(densified, null)); - Polyline differenced = (Polyline) (difference.execute(densified, convex_hull, SpatialReference.create(4326), null)); - assertTrue(differenced.isEmpty()); - assertTrue(bounding.isConvex(convex_hull, null)); - } - - { - Polyline polyline = new Polyline(); - polyline.startPath(-200, -90); - polyline.lineTo(-180, -85); - polyline.lineTo(-90, -70); - polyline.lineTo(0, 0); - polyline.lineTo(100, 25); - polyline.lineTo(170, 45); - polyline.lineTo(225, 65); - - Polyline densified = (Polyline) (densify.execute(polyline, 10.0, null)); - Polygon convex_hull = (Polygon) (bounding.execute(densified, null)); - boolean bcontains = contains.execute(convex_hull, densified, SpatialReference.create(4326), null); - - assertTrue(bcontains); - assertTrue(bounding.isConvex(convex_hull, null)); - } - } - - @Test - public static void testNonSimpleShape() { - OperatorConvexHull bounding = (OperatorConvexHull) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ConvexHull); - OperatorDensifyByLength densify = (OperatorDensifyByLength) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.DensifyByLength); - OperatorDifference difference = (OperatorDifference) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.Difference); - OperatorContains contains = (OperatorContains) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.Contains); - - { - Polygon shape = (Polygon) (TestCommonMethods.fromJson("{\"rings\":[[[6.7260599916745036,-90],[15.304037095218971,-18.924146439950675],[6.3163297788539232,-90],[5.2105387036445823,-59.980719950158637],[5.1217504663506981,-60.571174400735508],[8.2945138368731044,-27.967042187979146],[15.76606600357545,28.594953216378414],[8.4365340991447919,66.880924521951329],[10.115022726199774,65.247385313781265],[12.721206966604395,-23.793016208456883],[12.051875868947576,-11.368909618476637],[11.867118776841318,44.968896646914239],[7.5326099218274614,35.095776924526533],[8.86765609460479,90],[3.2036592678446922,55.507964789691712],[0.23585282258761486,-42.620591380394039],[-1.2660432762142744,90],[5.5580612840503001,-9.4879902323389196],[12.258387597532487,-35.945231749575591],[-48.746716054894101,90],[7.2294405148356846,-15.719232058488402],[13.798313011339591,-10.467172541381753],[7.4430022048746718,6.3951685161785656],[6.4876332898327815,31.10016146737189],[9.3645424359058911,47.123308099298804],[13.398605254542668,-6.4398318586014325],[-90,90],[13.360786277212718,82.971274676174545],[7.9405631778693566,90],[10.512482079680538,90],[16.994982794293946,19.60673041736408],[16.723893839323615,22.728853852102926],[23.178783416627525,90],[6.7260599916745036,-90]],[[26.768777234301993,90],[20.949797955126346,90],[11.967758262201434,-0.45048849056049711],[17.535751576687339,52.767528591651441],[26.768777234301993,90]],[[18.677765775891793,12.559680067559942],[19.060218406331451,90],[17.123595624401705,90],[-2.3805299720687887,-90],[-11.882782057881979,-90],[21.640575461689693,90],[11.368255808198477,85.501555553904794],[17.390084032215348,90],[23.999392897519989,78.255909006554603],[-6.8860811786563101,69.49189433189926],[29.232578855788898,90],[25.951412073846683,90],[-5.5572284181160772,-16.763772082849457],[18.677765775891793,12.559680067559942]]]}").getGeometry()); - Polygon densified = (Polygon) (densify.execute(shape, 10.0, null)); - Polygon convex_hull = (Polygon) (bounding.execute(densified, null)); - Polygon differenced = (Polygon) (difference.execute(densified, convex_hull, SpatialReference.create(4326), null)); - assertTrue(differenced.isEmpty()); - assertTrue(bounding.isConvex(convex_hull, null)); - } - - { - Polygon shape = (Polygon) (TestCommonMethods.fromJson("{\"rings\":[[[-13.630596027421603,3.6796011190640709],[-10.617275202716886,-28.133054337834409],[-81.617315194491695,90],[-4.0763362539824293,-90],[2.8213537979804073,-90],[-5.1515857979973365,-11.605767592612787],[43.477754021411123,35.507543731267589],[-45.818261267516704,-90],[-4.8545715514870018,-64.204371906322223],[-1.744951154293144,-30.257848194381509],[-7.8524748309267149,15.513561279453089],[-10.657563385538953,-81.785061432086309],[-6.3487369893289411,-31.849779201388415],[-14.768278524737962,-12.004393281111058],[-27.001635582579841,90],[-14.967554248940855,-78.970629918591811],[-12.999635147475825,-38.584472796107939],[-13.630596027421603,3.6796011190640709]],[[-16.338143621861352,-37.415690513288375],[-21.553879270366266,-90],[-18.649338100909404,-90],[-24.880584966233631,1.3133858590648728],[-16.483464632078249,-53.979692212288882],[-24.836979215403964,-68.69859399640147],[-29.708282990385214,-90],[-27.469962102507036,-1.6392995673644872],[-20.405051753708271,61.943199597870034],[-18.242567838912599,24.405109362934219],[-66.334547696572528,-52.678390155566603],[-13.471083255903507,-33.782708412943229],[-7.092757068096085,33.673785662500464],[-2.7427100969018205,74.386868339212668],[-8.2174861339989675,90],[-15.699459164009667,90],[-9.5910045204059156,90],[-8.4504603287557369,90],[-1.5498862802092637,2.5144190340747681],[-6.5326327868410639,-17.428029961128306],[-10.947786354404593,31.516236387466538],[-7.4777936485986354,12.486727826508769],[-13.89052186883092,12.397126427870356],[-10.530672679779606,-55.463541447339118],[-8.7161833631330374,-90],[-4.7231067612639519,-90],[-3.9692500849117041,-32.204677519048822],[3.740804266163555,32.88191805391007],[6.2021313886056246,76.617541950091564],[6.1183997672398194,90],[0.59730820015390673,90],[7.3242950674530753,18.030401540676614],[1.8252371571535342,90],[-16.338143621861352,-37.415690513288375]]]}").getGeometry()); - Polygon densified = (Polygon) (densify.execute(shape, 10.0, null)); - Polygon convex_hull = (Polygon) (bounding.execute(densified, null)); - Polygon differenced = (Polygon) (difference.execute(densified, convex_hull, SpatialReference.create(4326), null)); - assertTrue(differenced.isEmpty()); - assertTrue(bounding.isConvex(convex_hull, null)); - } - - { - Polygon shape = (Polygon) (TestCommonMethods.fromJson("{\"rings\":[[[-11.752662474672046,-90],[-76.236530072126513,7.3247326417920817],[18.933251883215579,90],[51.538924439116798,90],[52.253017336758049,80.352482145105284],[41.767201918260639,51.890297432229289],[21.697252770910882,-1.3185641048567049],[45.112193442818935,60.758441021743636],[48.457184967377231,69.626584611257954],[49.531808284502759,70.202152706968036],[52.394797054144334,71.533541126234581],[ 52.9671102343993,70.704964290210626],[58.527850348069251,16.670036266565845],[62.310807912773328,-34.249918700039238],[62.775020703241523,-43.541598916699364],[64.631871865114277,-80.708319783339874],[65.096084655582459,-90],[-11.752662474672046,-90]]]}").getGeometry()); - Polygon convex_hull = (Polygon) (bounding.execute(shape, null)); - Polygon differenced = (Polygon) (difference.execute(shape, convex_hull, SpatialReference.create(4326), null)); - assertTrue(differenced.isEmpty()); - assertTrue(bounding.isConvex(convex_hull, null)); - } - - { - Polygon polygon = new Polygon(); - polygon.startPath(0, 0); - polygon.lineTo(0, 10); - polygon.lineTo(4, 10); - polygon.lineTo(9, 1); - polygon.lineTo(1, 1); - polygon.lineTo(5, 10); - polygon.lineTo(10, 10); - polygon.lineTo(10, 0); - - Polygon densified = (Polygon) (densify.execute(polygon, 1, null)); - Polygon convex_hull = (Polygon) (bounding.execute(densified, null)); - - double area = convex_hull.calculateArea2D(); - assertTrue(bounding.isConvex(convex_hull, null)); - assertTrue(area == 100.0); - - Point2D p1 = convex_hull.getXY(0); - Point2D p2 = convex_hull.getXY(1); - Point2D p3 = convex_hull.getXY(2); - Point2D p4 = convex_hull.getXY(3); - assertTrue(p1.x == 0.0 && p1.y == 0.0); - assertTrue(p2.x == 0.0 && p2.y == 10.0); - assertTrue(p3.x == 10.0 && p3.y == 10.0); - assertTrue(p4.x == 10.0 && p4.y == 0.0); - } - - { - Polygon polygon = new Polygon(); - polygon.startPath(0, 0); - polygon.lineTo(0, 10); - polygon.lineTo(8, 10); - polygon.lineTo(10, 8); - polygon.lineTo(10, 0); - polygon.lineTo(0, 0); - polygon.lineTo(0, 10); - polygon.lineTo(10, 10); - polygon.lineTo(10, 0); - - // Polygon densified = (Polygon)(densify.execute(polygon, 1, null)); - Polygon convex_hull = (Polygon) (bounding.execute(polygon, null)); - - double area = convex_hull.calculateArea2D(); - assertTrue(bounding.isConvex(convex_hull, null)); - assertTrue(area == 100.0); - - Point2D p1 = convex_hull.getXY(0); - Point2D p2 = convex_hull.getXY(1); - Point2D p3 = convex_hull.getXY(2); - Point2D p4 = convex_hull.getXY(3); - assertTrue(p1.x == 0.0 && p1.y == 0.0); - assertTrue(p2.x == 0.0 && p2.y == 10.0); - assertTrue(p3.x == 10.0 && p3.y == 10.0); - assertTrue(p4.x == 10.0 && p4.y == 0.0); - } - } - - @Test - public static void testStar() { - OperatorConvexHull bounding = (OperatorConvexHull) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ConvexHull); - OperatorDensifyByLength densify = (OperatorDensifyByLength) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.DensifyByLength); - - Polygon star = new Polygon(); - star.startPath(0, 0); - star.lineTo(0, 0); - star.lineTo(5, 10); - star.lineTo(5, 10); - star.lineTo(10, 0); - star.lineTo(10, 0); - star.startPath(0, 5); - star.lineTo(0, 5); - star.lineTo(10, 5); - star.lineTo(10, 5); - star.lineTo(5, -5); - star.lineTo(5, -5); - - star.reversePath(1); - - Polygon densified = (Polygon) (densify.execute(star, 1.0, null)); - Polygon convex_hull = (Polygon) (bounding.execute(densified, null)); - - assertTrue(bounding.isConvex(convex_hull, null)); - - Point2D p1 = convex_hull.getXY(0); - Point2D p2 = convex_hull.getXY(1); - Point2D p3 = convex_hull.getXY(2); - Point2D p4 = convex_hull.getXY(3); - Point2D p5 = convex_hull.getXY(4); - Point2D p6 = convex_hull.getXY(5); - assertTrue(p1.x == 0.0 && p1.y == 0.0); - assertTrue(p2.x == 0.0 && p2.y == 5.0); - assertTrue(p3.x == 5.0 && p3.y == 10.0); - assertTrue(p4.x == 10.0 && p4.y == 5.0); - assertTrue(p5.x == 10.0 && p5.y == 0.0); - assertTrue(p6.x == 5.0 && p6.y == -5.0); - } - - @Test - public static void testPointsArray() { - Point2D[] points = new Point2D[6]; - int[] convex_hull = new int[6]; - - for (int i = 0; i < 6; i++) - points[i] = new Point2D(); - - points[0].x = 0; - points[0].y = 0; - points[1].x = 5; - points[1].y = 10; - points[2].x = 10; - points[2].y = 0; - points[3].x = 0; - points[3].y = 5; - points[4].x = 10; - points[4].y = 5; - points[5].x = 5; - points[5].y = -5; - - ConvexHull.construct(points, 6, convex_hull); - assertTrue(convex_hull[0] == 0); - assertTrue(convex_hull[1] == 3); - assertTrue(convex_hull[2] == 1); - assertTrue(convex_hull[3] == 4); - assertTrue(convex_hull[4] == 2); - assertTrue(convex_hull[5] == 5); - } - - @Test - public static void testMergeCursor() { - OperatorConvexHull bounding = (OperatorConvexHull) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ConvexHull); - - Polygon geom1 = new Polygon(); - Polygon geom2 = new Polygon(); - Point geom3 = new Point(); - Line geom4 = new Line(); - Envelope geom5 = new Envelope(); - MultiPoint geom6 = new MultiPoint(); - - // polygon - geom1.startPath(0, 0); - geom1.lineTo(0, 0); - geom1.lineTo(5, 11); - geom1.lineTo(5, 11); - geom1.lineTo(10, 0); - geom1.lineTo(10, 0); - - // polygon - geom2.startPath(0, 5); - geom2.lineTo(0, 5); - geom2.lineTo(10, 5); - geom2.lineTo(10, 5); - geom2.lineTo(5, -5); - geom2.lineTo(5, -5); - - // point - geom3.setXY(15, 1.25); - - // segment - geom4.setEndXY(-5, 1.25); - geom4.setStartXY(0, 0); - - // envelope - geom5.setCoords(0, 0, 5, 10); - - // multi_point - geom6.add(10, 5); - geom6.add(10, 10); - - // create cursor - Geometry[] geoms = new Geometry[6]; - geoms[0] = geom1; - geoms[1] = geom2; - geoms[2] = geom3; - geoms[3] = geom4; - geoms[4] = geom5; - geoms[5] = geom6; - GeometryCursor cursor = new SimpleGeometryCursor(geoms); - - // create convex hull from the cursor with b_merge set to true - GeometryCursor convex_hull_curs = bounding.execute(cursor, true, null); - Polygon convex_hull = (Polygon) (convex_hull_curs.next()); - assertTrue(convex_hull_curs.next() == null); - - assertTrue(bounding.isConvex(convex_hull, null)); - - Point2D p1 = convex_hull.getXY(0); - Point2D p2 = convex_hull.getXY(1); - Point2D p3 = convex_hull.getXY(2); - Point2D p4 = convex_hull.getXY(3); - Point2D p5 = convex_hull.getXY(4); - Point2D p6 = convex_hull.getXY(5); - assertTrue(p1.x == 5.0 && p1.y == 11.0); - assertTrue(p2.x == 10.0 && p2.y == 10); - assertTrue(p3.x == 15.0 && p3.y == 1.25); - assertTrue(p4.x == 5.0 && p4.y == -5.0); - assertTrue(p5.x == -5.0 && p5.y == 1.25); - assertTrue(p6.x == 0.0 && p6.y == 10.0); - - // Test GeometryEngine - Geometry[] merged_hull = GeometryEngine.convexHull(geoms, true); - convex_hull = (Polygon) merged_hull[0]; - p1 = convex_hull.getXY(0); - p2 = convex_hull.getXY(1); - p3 = convex_hull.getXY(2); - p4 = convex_hull.getXY(3); - p5 = convex_hull.getXY(4); - p6 = convex_hull.getXY(5); - assertTrue(p1.x == 5.0 && p1.y == 11.0); - assertTrue(p2.x == 10.0 && p2.y == 10); - assertTrue(p3.x == 15.0 && p3.y == 1.25); - assertTrue(p4.x == 5.0 && p4.y == -5.0); - assertTrue(p5.x == -5.0 && p5.y == 1.25); - assertTrue(p6.x == 0.0 && p6.y == 10.0); - - } - - @Test - public void testHullTickTock() { - Polygon geom1 = new Polygon(); - Polygon geom2 = new Polygon(); - Point geom3 = new Point(); - Line geom4 = new Line(); - Envelope geom5 = new Envelope(); - MultiPoint geom6 = new MultiPoint(); - - // polygon - geom1.startPath(0, 0); - geom1.lineTo(0, 0); - geom1.lineTo(5, 11); - geom1.lineTo(5, 11); - geom1.lineTo(10, 0); - geom1.lineTo(10, 0); - - // polygon - geom2.startPath(0, 5); - geom2.lineTo(0, 5); - geom2.lineTo(10, 5); - geom2.lineTo(10, 5); - geom2.lineTo(5, -5); - geom2.lineTo(5, -5); - - // point - geom3.setXY(15, 1.25); - - // segment - geom4.setEndXY(-5, 1.25); - geom4.setStartXY(0, 0); - - // envelope - geom5.setCoords(0, 0, 5, 10); - - // multi_point - geom6.add(10, 5); - geom6.add(10, 10); - - // Create - ListeningGeometryCursor gc = new ListeningGeometryCursor(); - GeometryCursor ticktock = OperatorConvexHull.local().execute(gc, true, null); - - // Use tick-tock to push a geometry and do a piece of work. - gc.tick(geom1); - ticktock.tock(); - gc.tick(geom2); - ticktock.tock(); - gc.tick(geom3);// skiped one tock just for testing. - ticktock.tock(); - gc.tick(geom4); - ticktock.tock(); - gc.tick(geom5); - ticktock.tock(); - gc.tick(geom6); - ticktock.tock(); - // Get the result - Geometry result = ticktock.next(); - Polygon convex_hull = (Polygon) result; - assertTrue(OperatorConvexHull.local().isConvex(convex_hull, null)); - - Point2D p1 = convex_hull.getXY(0); - Point2D p2 = convex_hull.getXY(1); - Point2D p3 = convex_hull.getXY(2); - Point2D p4 = convex_hull.getXY(3); - Point2D p5 = convex_hull.getXY(4); - Point2D p6 = convex_hull.getXY(5); - assertTrue(p1.x == 5.0 && p1.y == 11.0); - assertTrue(p2.x == 10.0 && p2.y == 10); - assertTrue(p3.x == 15.0 && p3.y == 1.25); - assertTrue(p4.x == 5.0 && p4.y == -5.0); - assertTrue(p5.x == -5.0 && p5.y == 1.25); - assertTrue(p6.x == 0.0 && p6.y == 10.0); - } +import com.esri.core.geometry.ogc.OGCGeometry; +public class TestConvexHull extends TestCase { + @Override + protected void setUp() throws Exception { + super.setUp(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + } + + @Test + public static void testFewPoints() { + { + Polygon polygon = new Polygon(); + polygon.addPath((Point2D[]) null, 0, true); + polygon.insertPoint(0, -1, Point2D.construct(5, 5)); + + Point convex_hull = (Point) OperatorConvexHull.local().execute(polygon, null); + assertTrue(convex_hull.getXY().equals(Point2D.construct(5, 5))); + } + + { + Point2D[] pts = new Point2D[3]; + + pts[0] = Point2D.construct(0, 0); + pts[1] = Point2D.construct(0, 0); + pts[2] = Point2D.construct(0, 0); + + int[] out_pts = new int[3]; + int res = ConvexHull.construct(pts, 3, out_pts); + assertTrue(res == 1); + assertTrue(out_pts[0] == 0); + } + + { + Point2D[] pts = new Point2D[1]; + pts[0] = Point2D.construct(0, 0); + + int[] out_pts = new int[1]; + int res = ConvexHull.construct(pts, 1, out_pts); + assertTrue(res == 1); + assertTrue(out_pts[0] == 0); + } + } + + @Test + public static void testDegenerate() { + OperatorConvexHull bounding = (OperatorConvexHull) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ConvexHull); + OperatorDensifyByLength densify = (OperatorDensifyByLength) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.DensifyByLength); + + { + Polygon polygon = new Polygon(); + polygon.startPath(0, 0); + polygon.lineTo(1, 0); + polygon.lineTo(0, 0); + polygon.lineTo(2, 0); + polygon.lineTo(1, 0); + polygon.lineTo(3, 0); + + polygon.startPath(0, 0); + polygon.lineTo(1, 0); + polygon.lineTo(0, 0); + polygon.lineTo(2, 0); + polygon.lineTo(1, 0); + polygon.lineTo(3, 0); + + Polygon densified = (Polygon) (densify.execute(polygon, .5, null)); + Polyline convex_hull = (Polyline) (bounding.execute(densified, null)); + assertTrue(bounding.isConvex(convex_hull, null)); + assertTrue(convex_hull.calculateArea2D() == 0.0); + + Point2D p1 = convex_hull.getXY(0); + Point2D p2 = convex_hull.getXY(1); + assertTrue(p1.x == 0.0 && p1.y == 0.0); + assertTrue(p2.x == 3.0 && p2.y == 0.0); + } + + { + Polygon polygon = new Polygon(); + polygon.startPath(0, 0); + polygon.lineTo(0, 0); + polygon.lineTo(0, 0); + polygon.lineTo(NumberUtils.doubleEps(), 0); + polygon.lineTo(0, NumberUtils.doubleEps()); + polygon.lineTo(10, 0); + polygon.lineTo(10, 0); + polygon.lineTo(10, 5); + polygon.lineTo(10, 10); + polygon.lineTo(5, 10); + polygon.lineTo(10, 0); + polygon.lineTo(10, 10); + polygon.lineTo(5, 10); + polygon.lineTo(0, 10); + polygon.lineTo(0, 0); + + polygon.startPath(0, 0); + polygon.lineTo(0, 0); + polygon.lineTo(0, 0); + polygon.lineTo(10, 0); + polygon.lineTo(10, 0); + polygon.lineTo(10, 5); + polygon.lineTo(10, 10); + polygon.lineTo(5, 10); + polygon.lineTo(10, 0); + polygon.lineTo(10, 10); + polygon.lineTo(5, 10); + polygon.lineTo(0, 10); + polygon.lineTo(0, 0); + + polygon.startPath(0, 0); + polygon.lineTo(0, 0); + polygon.lineTo(0, 0); + polygon.lineTo(10, 0); + polygon.lineTo(5, 0); + polygon.lineTo(10, 0); + polygon.lineTo(10, 5); + polygon.lineTo(10, 0); + polygon.lineTo(10, 10); + polygon.lineTo(5, 10); + polygon.lineTo(10, 10); + polygon.lineTo(5, 10); + polygon.lineTo(0, 10); + polygon.lineTo(5, 10); + polygon.lineTo(0, 0); + + Polygon densified = (Polygon) (densify.execute(polygon, 1, null)); + Polygon convex_hull = (Polygon) (bounding.execute(densified, null)); + + double area = convex_hull.calculateArea2D(); + assertTrue(bounding.isConvex(convex_hull, null)); + assertTrue(area == 100.0); + + Point2D p1 = convex_hull.getXY(0); + Point2D p2 = convex_hull.getXY(1); + Point2D p3 = convex_hull.getXY(2); + Point2D p4 = convex_hull.getXY(3); + assertTrue(p1.x == 0.0 && p1.y == 0.0); + assertTrue(p2.x == 0.0 && p2.y == 10.0); + assertTrue(p3.x == 10.0 && p3.y == 10.0); + assertTrue(p4.x == 10.0 && p4.y == 0.0); + } + + { + Polygon polygon = new Polygon(); + polygon.startPath(0, 0); + polygon.lineTo(0, 10); + polygon.lineTo(5, 10); + polygon.lineTo(5, 5); + polygon.lineTo(5, 8); + polygon.lineTo(10, 10); + polygon.lineTo(10, 0); + + Polygon densified = (Polygon) (densify.execute(polygon, 1, null)); + Polygon convex_hull = (Polygon) (bounding.execute(densified, null)); + + double area = convex_hull.calculateArea2D(); + assertTrue(bounding.isConvex(convex_hull, null)); + assertTrue(area == 100.0); + + Point2D p1 = convex_hull.getXY(0); + Point2D p2 = convex_hull.getXY(1); + Point2D p3 = convex_hull.getXY(2); + Point2D p4 = convex_hull.getXY(3); + assertTrue(p1.x == 0.0 && p1.y == 0.0); + assertTrue(p2.x == 0.0 && p2.y == 10.0); + assertTrue(p3.x == 10.0 && p3.y == 10.0); + assertTrue(p4.x == 10.0 && p4.y == 0.0); + } + + { + Polygon polygon = new Polygon(); + polygon.startPath(0, 0); + polygon.lineTo(0, 0); + polygon.lineTo(0, 0); + polygon.lineTo(10, 0); + polygon.lineTo(5, 0); + polygon.lineTo(10, 0); + polygon.lineTo(10, 5); + polygon.lineTo(10, 0); + polygon.lineTo(10, 10); + polygon.lineTo(5, 10); + polygon.lineTo(10, 10); + polygon.lineTo(5, 10); + polygon.lineTo(0, 10); + polygon.lineTo(5, 10); + polygon.lineTo(0, 0); + Polygon densified = (Polygon) (densify.execute(polygon, 1, null)); + Polygon convex_hull = (Polygon) (bounding.execute(densified, null)); + double area = convex_hull.calculateArea2D(); + assertTrue(bounding.isConvex(convex_hull, null)); + assertTrue(area == 100.0); + + Point2D p1 = convex_hull.getXY(0); + Point2D p2 = convex_hull.getXY(1); + Point2D p3 = convex_hull.getXY(2); + Point2D p4 = convex_hull.getXY(3); + assertTrue(p1.x == 0.0 && p1.y == 0.0); + assertTrue(p2.x == 0.0 && p2.y == 10.0); + assertTrue(p3.x == 10.0 && p3.y == 10.0); + assertTrue(p4.x == 10.0 && p4.y == 0.0); + } + + { + Polygon polygon = new Polygon(); + polygon.startPath(0, 0); + polygon.lineTo(0, 0); + polygon.lineTo(0, 10); + polygon.lineTo(0, 0); + polygon.lineTo(10, 10); + polygon.lineTo(0, 0); + polygon.lineTo(10, 0); + polygon.lineTo(0, 0); + + polygon.startPath(0, 10); + polygon.lineTo(0, 10); + polygon.lineTo(10, 10); + polygon.lineTo(0, 10); + polygon.lineTo(10, 0); + polygon.lineTo(0, 10); + polygon.lineTo(0, 0); + polygon.lineTo(0, 10); + + polygon.startPath(10, 10); + polygon.lineTo(10, 10); + polygon.lineTo(10, 0); + polygon.lineTo(10, 10); + polygon.lineTo(0, 0); + polygon.lineTo(10, 10); + polygon.lineTo(0, 10); + polygon.lineTo(10, 10); + + polygon.startPath(10, 0); + polygon.lineTo(10, 0); + polygon.lineTo(0, 0); + polygon.lineTo(10, 0); + polygon.lineTo(0, 10); + polygon.lineTo(10, 0); + polygon.lineTo(10, 10); + polygon.lineTo(10, 0); + + Polygon densified = (Polygon) (densify.execute(polygon, 1, null)); + Polygon convex_hull = (Polygon) (bounding.execute(densified, null)); + assertTrue(bounding.isConvex(convex_hull, null)); + + Point2D p1 = convex_hull.getXY(0); + Point2D p2 = convex_hull.getXY(1); + Point2D p3 = convex_hull.getXY(2); + Point2D p4 = convex_hull.getXY(3); + assertTrue(p1.x == 0.0 && p1.y == 0.0); + assertTrue(p2.x == 0.0 && p2.y == 10.0); + assertTrue(p3.x == 10.0 && p3.y == 10.0); + assertTrue(p4.x == 10.0 && p4.y == 0.0); + } + + { + MultiPoint mpoint = new MultiPoint(); + mpoint.add(4, 4); + mpoint.add(4, 4); + mpoint.add(4, 4); + mpoint.add(4, 4); + + Point convex_hull = (Point) bounding.execute(mpoint, null); + assertTrue(convex_hull.calculateArea2D() == 0.0); + assertTrue(bounding.isConvex(convex_hull, null)); + assertTrue(convex_hull.getXY().equals(Point2D.construct(4, 4))); + } + + { + MultiPoint mpoint = new MultiPoint(); + mpoint.add(4, 4); + + Point convex_hull = (Point) bounding.execute(mpoint, null); + assertTrue(bounding.isConvex(convex_hull, null)); + assertTrue(convex_hull.getXY().equals(Point2D.construct(4, 4))); + } + + { + MultiPoint mpoint = new MultiPoint(); + mpoint.add(4, 4); + mpoint.add(4, 5); + + Polyline convex_hull = (Polyline) bounding.execute(mpoint, null); + assertTrue(convex_hull.getPointCount() == 2); + assertTrue(bounding.isConvex(convex_hull, null)); + assertTrue(convex_hull.calculateLength2D() == 1.0); + } + + { + Line line = new Line(); + line.setStartXY(0, 0); + line.setEndXY(0, 1); + + Polyline convex_hull = (Polyline) bounding.execute(line, null); + assertTrue(convex_hull.getPointCount() == 2); + assertTrue(bounding.isConvex(convex_hull, null)); + assertTrue(convex_hull.calculateLength2D() == 1.0); + } + + { + Polyline polyline = new Polyline(); + polyline.startPath(0, 0); + polyline.lineTo(0, 1); + + Polyline convex_hull = (Polyline) bounding.execute(polyline, null); + assertTrue(convex_hull.getPointCount() == 2); + assertTrue(bounding.isConvex(convex_hull, null)); + assertTrue(polyline == convex_hull); + assertTrue(convex_hull.calculateLength2D() == 1.0); + } + + { + Envelope env = new Envelope(0, 0, 10, 10); + assertTrue(OperatorConvexHull.local().isConvex(env, null)); + + Polygon convex_hull = (Polygon) bounding.execute(env, null); + assertTrue(bounding.isConvex(convex_hull, null)); + assertTrue(convex_hull.getPointCount() == 4); + assertTrue(convex_hull.getXY(0).equals(Point2D.construct(0, 0))); + assertTrue(convex_hull.getXY(1).equals(Point2D.construct(0, 10))); + assertTrue(convex_hull.getXY(2).equals(Point2D.construct(10, 10))); + assertTrue(convex_hull.getXY(3).equals(Point2D.construct(10, 0))); + } + + { + Envelope env = new Envelope(0, 0, 0, 10); + assertTrue(!OperatorConvexHull.local().isConvex(env, null)); + + Polyline convex_hull = (Polyline) bounding.execute(env, null); + assertTrue(bounding.isConvex(convex_hull, null)); + assertTrue(convex_hull.getPointCount() == 2); + assertTrue(convex_hull.getXY(0).equals(Point2D.construct(0, 0))); + assertTrue(convex_hull.getXY(1).equals(Point2D.construct(0, 10))); + } + + { + Envelope env = new Envelope(0, 0, 0, 10); + assertTrue(!OperatorConvexHull.local().isConvex(env, null)); + + Polyline convex_hull = (Polyline) bounding.execute(env, null); + assertTrue(bounding.isConvex(convex_hull, null)); + assertTrue(convex_hull.getPointCount() == 2); + assertTrue(convex_hull.getXY(0).equals(Point2D.construct(0, 0))); + assertTrue(convex_hull.getXY(1).equals(Point2D.construct(0, 10))); + } + + { + Envelope env = new Envelope(5, 5, 5, 5); + assertTrue(!OperatorConvexHull.local().isConvex(env, null)); + + Point convex_hull = (Point) bounding.execute(env, null); + assertTrue(bounding.isConvex(convex_hull, null)); + assertTrue(convex_hull.getXY().equals(Point2D.construct(5, 5))); + } + } + + @Test + public static void testSegment() { + { + Line line = new Line(); + line.setStartXY(5, 5); + line.setEndXY(5, 5); + + assertTrue(!OperatorConvexHull.local().isConvex(line, null)); + Point point = (Point) OperatorConvexHull.local().execute(line, null); + assertTrue(point.getXY().equals(Point2D.construct(5, 5))); + } + + { + Line line = new Line(); + line.setStartXY(5, 5); + line.setEndXY(5, 6); + + assertTrue(OperatorConvexHull.local().isConvex(line, null)); + Polyline polyline = (Polyline) OperatorConvexHull.local().execute(line, null); + assertTrue(polyline.getPointCount() == 2); + assertTrue(polyline.getXY(0).equals(Point2D.construct(5, 5))); + assertTrue(polyline.getXY(1).equals(Point2D.construct(5, 6))); + } + } + + + @Test + public static void testSquare() { + OperatorConvexHull bounding = (OperatorConvexHull) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ConvexHull); + OperatorDensifyByLength densify = (OperatorDensifyByLength) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.DensifyByLength); + OperatorDifference difference = (OperatorDifference) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.Difference); + OperatorContains contains = (OperatorContains) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.Contains); + + Polygon square = new Polygon(); + square.startPath(0, 0); + square.lineTo(2, 3); + square.lineTo(1, 4); + square.lineTo(0, 5); + square.lineTo(0, 7); + square.lineTo(2, 7); + square.lineTo(0, 10); + square.lineTo(4, 7); + square.lineTo(6, 7); + square.lineTo(7, 10); + square.lineTo(8, 10); + square.lineTo(10, 10); + square.lineTo(8, 7); + square.lineTo(10, 5); + square.lineTo(8, 3); + square.lineTo(10, 1); + square.lineTo(10, 0); + square.lineTo(5, 5); + square.lineTo(8, 0); + square.lineTo(4, 3); + square.lineTo(5, 0); + square.lineTo(3, 1); + square.lineTo(3, 0); + square.lineTo(2, 1); + + Polygon densified = (Polygon) (densify.execute(square, 1.0, null)); + + densified.addAttribute(VertexDescription.Semantics.ID); + for (int i = 0; i < densified.getPointCount(); i++) + densified.setAttribute(VertexDescription.Semantics.ID, i, 0, i); + + Polygon convex_hull = (Polygon) (bounding.execute(densified, null)); + Polygon differenced = (Polygon) (difference.execute(densified, convex_hull, SpatialReference.create(4326), null)); + + assertTrue(differenced.isEmpty()); + assertTrue(bounding.isConvex(convex_hull, null)); + } + + @Test + public static void testPolygons() { + OperatorConvexHull bounding = (OperatorConvexHull) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ConvexHull); + OperatorDensifyByLength densify = (OperatorDensifyByLength) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.DensifyByLength); + OperatorDifference difference = (OperatorDifference) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.Difference); + + { + Polygon shape = (Polygon) (TestCommonMethods.fromJson("{\"rings\":[[[1.3734426370715553,-90],[-24.377532184629967,-63.428606327053856],[-25.684686546621553,90],[-24.260574484321914,80.526315789473699],[-25.414389575040037,90],[-23.851448513708718,90],[-23.100135788742072,87.435887853000679],[5.6085096351011448,-48.713222410606306],[1.3734426370715553,-90]]]}").getGeometry()); + Polygon convex_hull = (Polygon) (bounding.execute(shape, null)); + Polygon differenced = (Polygon) (difference.execute(shape, convex_hull, SpatialReference.create(4326), null)); + assertTrue(differenced.isEmpty()); + assertTrue(bounding.isConvex(convex_hull, null)); + } + + { + Polygon polygon = (Polygon) (TestCommonMethods.fromJson("{\"rings\":[[[-179.64843749999693,-43.3535476539993],[-179.99999999999696,-43.430006211999284],[-179.99999999999696,39.329644416999436],[-179.64843749999693,38.98862638799943],[-89.99999999999838,29.008084980999506],[-112.8515624999981,-16.20113770599962],[-115.66406249999804,-18.882554574999688],[-124.80468749999788,-23.7925511709996],[-138.86718749999767,-30.6635901109995],[-157.49999999999736,-38.468358112999354],[-162.42187499999724,-39.56498442199932],[-179.64843749999693,-43.3535476539993]],[[179.99999999999696,-43.430006211999284],[179.64843749999693,-43.50646476999926],[162.0703124999973,-42.36267115399919],[160.3124999999973,-42.24790485699929],[143.78906249999756,-41.1680427339993],[138.16406249999767,-39.64744846799925],[98.43749999999845,-28.523889212999524],[78.39843749999878,-5.1644422999998705],[75.9374999999988,19.738611663999766],[88.2421874999986,33.51651305599954],[108.63281249999815,44.160795160999356],[138.16406249999767,51.02062617799914],[140.9765624999976,51.68129673399923],[160.3124999999973,52.8064856429991],[162.0703124999973,52.908902047999206],[163.12499999999727,52.97036560499911],[165.93749999999716,52.97036560499911],[179.99999999999696,39.329644416999436],[179.99999999999696,-43.430006211999284]]]}").getGeometry()); + Polygon densified = (Polygon) (densify.execute(polygon, 10.0, null)); + Polygon convex_hull = (Polygon) (bounding.execute(densified, null)); + Polygon differenced = (Polygon) (difference.execute(densified, convex_hull, SpatialReference.create(4326), null)); + assertTrue(differenced.isEmpty()); + assertTrue(bounding.isConvex(convex_hull, null)); + } + + { + Polygon polygon = new Polygon(); + polygon.startPath(1, 0); + polygon.lineTo(-1, 0); + polygon.lineTo(0, -1); + Polygon convex_hull = (Polygon) (bounding.execute(polygon, null)); + Polygon differenced = (Polygon) (difference.execute(polygon, convex_hull, SpatialReference.create(4326), null)); + assertTrue(differenced.isEmpty()); + assertTrue(bounding.isConvex(convex_hull, null)); + } + + { + Polygon polygon = (Polygon) (TestCommonMethods.fromJson("{\"rings\":[[[-38.554566833914528,21.902000764339238],[-30.516168471666138,90],[-38.554566833914528,21.902000764339238]],[[-43.013227444613932,28.423410187206883],[-43.632473335895916,90],[-42.342268693420237,62.208637129146894],[-37.218731802058755,63.685357222187029],[-32.522681335230686,47.080307818055296],[-40.537308829621097,-21.881392019745604],[-47.59510451722663,18.812521648505964],[-53.25344489340366,30.362745244224911],[-46.629060462410138,90],[-50.069277433245119,18.254168921734287],[-42.171214434397982,72.623347387008081],[-43.000844452530551,90],[-46.162281544954659,90],[-39.462049205071331,90],[-47.434856316742902,38.662565208814371],[-52.13115779642537,-19.952586632199857],[-56.025328966335081,90],[-60.056846215416158,-44.023645282268355],[-60.12338894192289,50.374596189881942],[-35.787508034048379,-7.8839007676038513],[-60.880218074135605,-46.447995750907815],[-67.782542852117956,-85.106300958016107],[-65.053131764313761,-0.96651520578494665],[-72.375821140304154,90],[-78.561502106749245,90],[-83.809168672565946,33.234498214085811],[-60.880218054506344,-46.447995733653201],[-75.637095425108981,59.886574792622838],[-71.364085965028096,31.976373491332097],[-67.89968380886117,90],[-67.544349171474749,8.8435794458927504],[-70.780047377934707,80.683454463576624],[-64.996733940204948,34.349882797035313],[-56.631753638680905,39.815838152456926],[-60.392350183516896,52.75446132093407],[-58.51633728692137,90],[-64.646972065627097,41.444197803942579],[-73.355591244695518,-0.15370205145035776],[-43.013227444613932,28.423410187206883]],[[-69.646471076946,-85.716191379686904],[-62.854465128320491,-45.739046580967972],[-71.377481570643141,-90],[-66.613495837251435,-90],[-66.9765142407159,-90],[-66.870099169607329,-90],[-67.23180828626819,-61.248439074609649],[-58.889775875438851,-90],[-53.391995883729322,-69.476385967096491],[-69.646471076946,-85.716191379686904]]]}").getGeometry()); + Polygon densified = (Polygon) (densify.execute(polygon, 10.0, null)); + Polygon convex_hull = (Polygon) (bounding.execute(densified, null)); + Polygon differenced = (Polygon) (difference.execute(densified, convex_hull, SpatialReference.create(4326), null)); + assertTrue(differenced.isEmpty()); + // assertTrue(bounding.isConvex(*convex_hull, null)); + } + + { + Polygon polygon = (Polygon) (TestCommonMethods.fromJson("{\"rings\":[[[-38.554566833914528,21.902000764339238],[-30.516168471666138,90],[-38.554566833914528,21.902000764339238]],[[-43.013227444613932,28.423410187206883],[-43.632473335895916,90],[-42.342268693420237,62.208637129146894],[-37.218731802058755,63.685357222187029],[-32.522681335230686,47.080307818055296],[-40.537308829621097,-21.881392019745604],[-47.59510451722663,18.812521648505964],[-53.25344489340366,30.362745244224911],[-46.629060462410138,90],[-50.069277433245119,18.254168921734287],[-42.171214434397982,72.623347387008081],[-43.000844452530551,90],[-46.162281544954659,90],[-39.462049205071331,90],[-47.434856316742902,38.662565208814371],[-52.13115779642537,-19.952586632199857],[-56.025328966335081,90],[-60.056846215416158,-44.023645282268355],[-60.12338894192289,50.374596189881942],[-35.787508034048379,-7.8839007676038513],[-60.880218074135605,-46.447995750907815],[-67.782542852117956,-85.106300958016107],[-65.053131764313761,-0.96651520578494665],[-72.375821140304154,90],[-78.561502106749245,90],[-83.809168672565946,33.234498214085811],[-60.880218054506344,-46.447995733653201],[-75.637095425108981,59.886574792622838],[-71.364085965028096,31.976373491332097],[-67.89968380886117,90],[-67.544349171474749,8.8435794458927504],[-70.780047377934707,80.683454463576624],[-64.996733940204948,34.349882797035313],[-56.631753638680905,39.815838152456926],[-60.392350183516896,52.75446132093407],[-58.51633728692137,90],[-64.646972065627097,41.444197803942579],[-73.355591244695518,-0.15370205145035776],[-43.013227444613932,28.423410187206883]],[[-69.646471076946,-85.716191379686904],[-62.854465128320491,-45.739046580967972],[-71.377481570643141,-90],[-66.613495837251435,-90],[-66.9765142407159,-90],[-66.870099169607329,-90],[-67.23180828626819,-61.248439074609649],[-58.889775875438851,-90],[-53.391995883729322,-69.476385967096491],[-69.646471076946,-85.716191379686904]]]}").getGeometry()); + Polygon convex_hull = (Polygon) (bounding.execute(polygon, null)); + Polygon differenced = (Polygon) (difference.execute(polygon, convex_hull, SpatialReference.create(4326), null)); + assertTrue(differenced.isEmpty()); + assertTrue(bounding.isConvex(convex_hull, null)); + } + + { + Polygon polygon = (Polygon) (TestCommonMethods.fromJson("{\"rings\":[[[-36.269498017702901,-26.37490682626369],[-49.146436641060951,-49.881862499696126],[-37.560006446488146,-45.592052597656789],[-39.13770692863632,-69.085816352131204],[-65.415587331361877,-90],[-51.462290812033373,-16.760787566546721],[-28.454456182408332,90],[-36.269498017702901,-26.37490682626369]],[[-40.542178258552283,-90],[-39.13770692863632,-69.085816352131204],[-16.295804332590937,-50.906277575066262],[-40.542178258552283,-90]],[[-16.295804332590937,-50.906277575066262],[-5.6790432913971927,-33.788307256548933],[14.686101893282586,-26.248228042967728],[-16.295804332590937,-50.906277575066262]],[[-37.560006446488146,-45.592052597656789],[-36.269498017702901,-26.37490682626369],[27.479825940672225,90],[71.095881152477034,90],[-5.6790432913971927,-33.788307256548933],[-37.560006446488146,-45.592052597656789]]]}").getGeometry()); + Polygon convex_hull = (Polygon) (bounding.execute(polygon, null)); + Polygon differenced = (Polygon) (difference.execute(polygon, convex_hull, SpatialReference.create(4326), null)); + assertTrue(differenced.isEmpty()); + assertTrue(bounding.isConvex(convex_hull, null)); + } + + { + Polygon polygon = (Polygon) (TestCommonMethods.fromJson("{\"rings\":[[[-77.020281185856106,-80.085419699581706],[-77.328568930885723,-83.404479889897416],[-80.495259564600545,-90],[-77.020281185856106,-80.085419699581706]],[[-77.941187535385211,-90],[-77.328568930885723,-83.404479889897416],[-39.252034383972621,-4.0994329574862469],[-39.29471328421063,-6.5269494453154593],[-77.941187535385211,-90]],[[-77.020281185856106,-80.085419699581706],[-62.688864277996522,74.208210509833052],[-38.108861278327581,80.371071656873013],[-37.597643844595929,90],[-38.663943358642484,29.350366647752089],[-77.020281185856106,-80.085419699581706]],[[-40.265125886194951,-61.722668598742551],[-39.29471328421063,-6.5269494453154593],[-15.554402498931253,44.750073899273843],[-8.4447006412989474,13.127318978368956],[-5.310206313296316,-4.5170390491918795],[-40.265125886194951,-61.722668598742551]],[[-39.252034383972621,-4.0994329574862469],[-38.663943358642484,29.350366647752089],[-22.476078360563164,75.536520897660651],[-15.632105532320049,45.095683888365997],[-39.252034383972621,-4.0994329574862469]],[[-15.554402498931253,44.750073899273843],[-15.632105532320049,45.095683888365997],[-8.9755856576261941,58.959750756602595],[-15.554402498931253,44.750073899273843]]]}").getGeometry()); + Polygon convex_hull = (Polygon) (bounding.execute(polygon, null)); + Polygon differenced = (Polygon) (difference.execute(polygon, convex_hull, SpatialReference.create(4326), null)); + assertTrue(differenced.isEmpty()); + assertTrue(bounding.isConvex(convex_hull, null)); + } + + { + Polygon polygon = (Polygon) (TestCommonMethods.fromJson("{\"rings\":[[[-68.840007952128175,37.060080998089632],[-68.145986924561413,31.114096694815196],[-69.187773850176768,30.693518246958952],[-68.840007952128175,37.060080998089632]],[[-75.780513355389928,-90],[-69.21567111077384,30.182802098042274],[-50.875629803516389,37.146119571446704],[-75.780513355389928,-90]],[[4.2911006174797457,-1.144569312564311],[-66.484019915251849,80.191238371060038],[-65.948228008382316,90],[4.2911006174797457,-1.144569312564311]],[[-90,22.291441435181515],[-69.187773850176768,30.693518246958952],[-69.21567111077384,30.182802098042274],[-90,22.291441435181515]],[[-68.840007952128175,37.060080998089632],[-75.019206401201359,90],[-66.484019915251849,80.191238371060038],[-68.840007952128175,37.060080998089632]]]}").getGeometry()); + Polygon convex_hull = (Polygon) (bounding.execute(polygon, null)); + Polygon differenced = (Polygon) (difference.execute(polygon, convex_hull, SpatialReference.create(4326), null)); + assertTrue(differenced.isEmpty()); + assertTrue(bounding.isConvex(convex_hull, null)); + } + + { + Polygon polygon = (Polygon) (TestCommonMethods.fromJson("{\"rings\":[[[27.570109889215438,22.850616190228489],[75.703105729477357,-90],[2.1548000876241362,-15.817792950796967],[27.570109889215438,22.850616190228489]],[[-0.069915984436478951,-90],[-46.602410662754053,-89.999999998014729],[-14.977190481820156,-41.883452819243004],[-0.069915984436478951,-90]],[[-14.977190481820156,-41.883452819243004],[-34.509989609682322,21.163004866431177],[2.1548000876241362,-15.817792950796967],[-14.977190481820156,-41.883452819243004]]]}").getGeometry()); + Polygon convex_hull = (Polygon) (bounding.execute(polygon, null)); + Polygon differenced = (Polygon) (difference.execute(polygon, convex_hull, SpatialReference.create(4326), null)); + assertTrue(differenced.isEmpty()); + assertTrue(bounding.isConvex(convex_hull, null)); + } + + { + Polygon polygon = (Polygon) (TestCommonMethods.fromJson("{\"rings\":[[[28.865673900286581,33.379551302126075],[39.505669183485338,-34.957993133630559],[7.152466542048213,-90],[28.865673900286581,33.379551302126075]],[[-64.597291313620858,2.4515644574812248],[20.050002923927103,90],[24.375150856531356,62.220853377417541],[-64.597291313620858,2.4515644574812248]],[[28.865673900286581,33.379551302126075],[24.375150856531356,62.220853377417541],[35.223952527956932,69.508785974507163],[28.865673900286581,33.379551302126075]]]}").getGeometry()); + Polygon convex_hull = (Polygon) (bounding.execute(polygon, null)); + Polygon differenced = (Polygon) (difference.execute(polygon, convex_hull, SpatialReference.create(4326), null)); + assertTrue(differenced.isEmpty()); + assertTrue(bounding.isConvex(convex_hull, null)); + } + + { + Polygon polygon = (Polygon) (TestCommonMethods.fromJson("{\"rings\":[[[-66.582505384413167,-51.305212522944061],[-60.169897093348865,-90],[-90,-90],[-66.582505384413167,-51.305212522944061]],[[20.858462934004656,-90],[-35.056287147954386,0.78833269359179781],[18.933251883215579,90],[20.858462934004656,-90]],[[-66.582505384413167,-51.305212522944061],[-90,90],[-35.056287147954386,0.78833269359179781],[-66.582505384413167,-51.305212522944061]]]}").getGeometry()); + Polygon convex_hull = (Polygon) (bounding.execute(polygon, null)); + Polygon differenced = (Polygon) (difference.execute(polygon, convex_hull, SpatialReference.create(4326), null)); + assertTrue(differenced.isEmpty()); + assertTrue(bounding.isConvex(convex_hull, null)); + } + + { + Polygon polygon = (Polygon) (TestCommonMethods.fromJson("{\"rings\":[[[36.692916710279974,-90],[-31.182443792600079,6.434474852744998],[-90,90],[52.245260790065387,57.329280208760991],[36.692916710279974,-90]]]}").getGeometry()); + Polygon convex_hull = (Polygon) (bounding.execute(polygon, null)); + Polygon differenced = (Polygon) (difference.execute(polygon, convex_hull, SpatialReference.create(4326), null)); + assertTrue(differenced.isEmpty()); + assertTrue(bounding.isConvex(convex_hull, null)); + } + + { + Polygon polygon = (Polygon) (TestCommonMethods.fromJson("{\"rings\":[[[-17.959089916602533,-4.3577640799248218],[-29.181784251472308,-90],[-65.493717350127127,15.053615507086979],[-17.959089916602533,-4.3577640799248218]],[[-21.884657435973146,-34.517617672142393],[-17.94005076020704,-4.3655389655558539],[9.3768748358343359,-15.520758655380195],[-21.884657435973146,-34.517617672142393]],[[-17.94005076020704,-4.3655389655558539],[-17.959089916602533,-4.3577640799248218],[-5.8963967801936494,87.694641571893939],[-17.94005076020704,-4.3655389655558539]]]}").getGeometry()); + Polygon convex_hull = (Polygon) (bounding.execute(polygon, null)); + Polygon differenced = (Polygon) (difference.execute(polygon, convex_hull, SpatialReference.create(4326), null)); + assertTrue(differenced.isEmpty()); + assertTrue(bounding.isConvex(convex_hull, null)); + } + + { + Polygon polygon = (Polygon) (TestCommonMethods.fromJson("{\"rings\":[[[17.198360589495572,-77.168667157542373],[-24.835678541343281,-83.717338556412017],[-30.259244993378722,61.914816728303791],[17.198360589495572,-77.168667157542373]],[[-8.3544985146710644,-90],[17.979891823366039,-79.459092168186686],[21.576625471325329,-90],[-8.3544985146710644,-90]],[[17.979891823366039,-79.459092168186686],[17.198360589495572,-77.168667157542373],[27.846596597209441,-75.509730732825361],[17.979891823366039,-79.459092168186686]]]}").getGeometry()); + Polygon convex_hull = (Polygon) (bounding.execute(polygon, null)); + Polygon differenced = (Polygon) (difference.execute(polygon, convex_hull, SpatialReference.create(4326), null)); + assertTrue(differenced.isEmpty()); + assertTrue(bounding.isConvex(convex_hull, null)); + } + + { + Polygon polygon = (Polygon) (TestCommonMethods.fromJson("{\"rings\":[[[-1.2588613620456419,13.607321860624268],[61.845346679259052,48.415944386573557],[15.226225965240992,-5.3702891526017318],[0.92681706095183469,1.6819284384951441],[3.8469417404317623,-14.250715301799051],[7.2615297628459139,-14.559458820527061],[4.4896578086498238,-17.757471781424698],[14.589138845678622,-72.861774161244625],[-10.508572009494033,-35.06149380752737],[-58.12642296329372,-90],[-15.260062192400673,90],[-1.2588613620456419,13.607321860624268]],[[0.92681706095183469,1.6819284384951441],[-1.2588613620456419,13.607321860624268],[-11.641308877525201,7.8803076458946304],[0.92681706095183469,1.6819284384951441]],[[-10.508572009494033,-35.06149380752737],[4.4896578086498238,-17.757471781424698],[3.8469417404317623,-14.250715301799051],[-26.125369947914503,-11.54064986657559],[-10.508572009494033,-35.06149380752737]],[[39.829571435268129,-17.504227477249202],[7.2615297628459139,-14.559458820527061],[15.226225965240992,-5.3702891526017318],[39.829571435268129,-17.504227477249202]]]}").getGeometry()); + Polygon convex_hull = (Polygon) (bounding.execute(polygon, null)); + Polygon differenced = (Polygon) (difference.execute(polygon, convex_hull, SpatialReference.create(4326), null)); + assertTrue(differenced.isEmpty()); + assertTrue(bounding.isConvex(convex_hull, null)); + } + + { + Polygon polygon = (Polygon) (TestCommonMethods.fromJson("{\"rings\":[[[-19.681975166855118,-34.10344217707847],[-90,89.999999998418275],[53.036316534501381,90],[-19.681975166855118,-34.10344217707847]],[[-52.434509065706855,-90],[-29.2339442498794,-50.405148598356135],[-2.8515119199232331,-90],[-52.434509065706855,-90]],[[18.310881874573923,-90],[-25.473718245381271,-43.987822508814972],[-19.681975166855118,-34.10344217707847],[-15.406194071963924,-41.649717163101563],[18.310881874573923,-90]],[[-29.2339442498794,-50.405148598356135],[-52.27954259799813,-15.81822990020261],[-25.473718245381271,-43.987822508814972],[-29.2339442498794,-50.405148598356135]]]}").getGeometry()); + Polygon convex_hull = (Polygon) (bounding.execute(polygon, null)); + Polygon differenced = (Polygon) (difference.execute(polygon, convex_hull, SpatialReference.create(4326), null)); + assertTrue(differenced.isEmpty()); + assertTrue(bounding.isConvex(convex_hull, null)); + } + + { + Polygon polygon = (Polygon) (TestCommonMethods.fromJson("{\"rings\":[[[49.939516827702498,-90],[-20.470128740962011,-68.102019032647391],[-20.124197553433845,-67.213968219799824],[34.438329237618149,-61.893901496061034],[49.939516827702498,-90]],[[-82.380918375714089,-73.284249936115529],[-4.7432060543229699,9.1484031048644194],[-11.790524932251525,21.926303986370414],[-3.4862200343039369,10.483021157965428],[19.753975453441285,35.158541777575607],[5.5896897290794696,-1.2030408273476854],[73.839023528563189,-58.052174675157325],[34.438329237618149,-61.893901496061034],[3.6757233436274213,-6.1164440290327313],[-20.124197553433845,-67.213968219799824],[-82.380918375714089,-73.284249936115529]],[[5.5896897290794696,-1.2030408273476854],[4.0842948437219349,0.050896618883412792],[-3.4862200343039369,10.483021157965428],[-4.7432060543229699,9.1484031048644194],[3.6757233436274213,-6.1164440290327313],[5.5896897290794696,-1.2030408273476854]]]}").getGeometry()); + Polygon convex_hull = (Polygon) (bounding.execute(polygon, null)); + Polygon differenced = (Polygon) (difference.execute(polygon, convex_hull, SpatialReference.create(4326), null)); + assertTrue(differenced.isEmpty()); + assertTrue(bounding.isConvex(convex_hull, null)); + } + + { + Polygon polygon = (Polygon) (TestCommonMethods.fromJson("{\"rings\":[[[4.7618727814345867,-14.245890151885444],[-7.1675180359486266,-90],[-83.232840716292529,40.620187389409224],[-29.219286930421923,6.9418934044755334],[-29.378277853968513,6.9629531745072839],[-28.933835455648254,6.7639099538036529],[4.7618727814345867,-14.245890151885444]],[[51.056303527367277,-43.111190419066219],[4.7618727814345867,-14.245890151885444],[5.632592229367642,-8.716640778187827],[-28.933835455648254,6.7639099538036529],[-29.219286930421923,6.9418934044755334],[2.700964609629902,2.7137705544807242],[12.385960896403816,0.48342578457646468],[51.056303527367277,-43.111190419066219]]]}").getGeometry()); + Polygon convex_hull = (Polygon) (bounding.execute(polygon, null)); + Polygon differenced = (Polygon) (difference.execute(polygon, convex_hull, SpatialReference.create(4326), null)); + assertTrue(differenced.isEmpty()); + assertTrue(bounding.isConvex(convex_hull, null)); + } + + { + Polygon polygon = (Polygon) (TestCommonMethods.fromJson("{\"rings\":[[[-21.426619830983732,-89.379667629404466],[-72.784461583687971,-88.999754827814016],[-81.94289434769162,25.456737039611831],[-38.382426191605546,-57.204127144336077],[-41.663734179022256,-78.439084394036513],[-29.749353943865881,-73.586348060869426],[-21.426619830983732,-89.379667629404466]],[[-21.09971823441461,-90],[-21.426619830983732,-89.379667629404466],[-21.080965849893449,-89.382224558742934],[-21.09971823441461,-90]],[[62.431917153693021,-90],[-21.080965849893449,-89.382224558742934],[-20.486971473666468,-69.813772479288062],[19.166418765782844,-53.662915804391695],[63.671046682728601,-90],[62.431917153693021,-90]],[[-29.749353943865881,-73.586348060869426],[-38.382426191605546,-57.204127144336077],[-31.449272112025476,-12.336278393150847],[-41.028899505665962,-4.5147159296945967],[-30.750049689226596,-7.8112663207986941],[-15.63587330244308,90],[-18.721998818789388,-11.66880646480822],[60.158611185675326,-36.966763960486929],[19.166418765782844,-53.662915804391695],[-19.049573405176112,-22.46036923493498],[-20.486971473666468,-69.813772479288062],[-29.749353943865881,-73.586348060869426]],[[-19.049573405176112,-22.46036923493498],[-18.721998818789388,-11.66880646480822],[-30.750049689226596,-7.8112663207986941],[-31.449272112025476,-12.336278393150847],[-19.049573405176112,-22.46036923493498]]]}").getGeometry()); + Polygon convex_hull = (Polygon) (bounding.execute(polygon, null)); + Polygon differenced = (Polygon) (difference.execute(polygon, convex_hull, SpatialReference.create(4326), null)); + assertTrue(differenced.isEmpty()); + assertTrue(bounding.isConvex(convex_hull, null)); + } + + { + Polygon polygon = (Polygon) (TestCommonMethods.fromJson("{\"rings\":[[[-17.906614911617162,-53.670186894017093],[-72.687715727164573,-90],[-77.889582483879749,90],[-47.149885004784061,16.372797801863811],[-58.874489264131405,8.3403055152440846],[-44.017112148517498,8.8692333739436133],[-43.760297522359615,8.2541153357643502],[-48.398890069305921,4.7201397602360009],[-38.665987052649818,-3.9476907252248874],[-17.906614911617162,-53.670186894017093]],[[-2.7387498969355368,-90],[-17.906614911617162,-53.670186894017093],[-6.8038688963847829,-46.30705103709559],[-2.7387498969355368,-90]],[[-6.8038688963847829,-46.30705103709559],[-8.2224486207861638,-31.0597897622158],[2.1962303277340673,-40.338351652092697],[-6.8038688963847829,-46.30705103709559]],[[-8.2224486207861638,-31.0597897622158],[-38.665987052649818,-3.9476907252248874],[-43.760297522359615,8.2541153357643502],[-42.90074612601282,8.9089763975751382],[-44.017112148517498,8.8692333739436133],[-47.149885004784061,16.372797801863811],[45.190674429223662,79.635046572817728],[40.490070954305672,72.441418146356597],[63.53694979672099,90],[75.056911135062407,13.108310545642606],[-0.027204347469059975,10.435289586728711],[-10.580480746811602,-5.715051428780245],[-8.2224486207861638,-31.0597897622158]],[[-42.90074612601282,8.9089763975751382],[-0.027204347469059975,10.435289586728711],[40.490070954305672,72.441418146356597],[-42.90074612601282,8.9089763975751382]]]}").getGeometry()); + Polygon convex_hull = (Polygon) (bounding.execute(polygon, null)); + Polygon differenced = (Polygon) (difference.execute(polygon, convex_hull, SpatialReference.create(4326), null)); + assertTrue(differenced.isEmpty()); + assertTrue(bounding.isConvex(convex_hull, null)); + } + } + + @Test + public static void testPolylines() { + OperatorConvexHull bounding = (OperatorConvexHull) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ConvexHull); + OperatorDensifyByLength densify = (OperatorDensifyByLength) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.DensifyByLength); + OperatorDifference difference = (OperatorDifference) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.Difference); + OperatorContains contains = (OperatorContains) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.Contains); + + { + Polyline poly = new Polyline(); + poly.startPath(0, 0); + poly.lineTo(0, 10); + poly.lineTo(0, 20); + poly.lineTo(0, 40); + poly.lineTo(0, 500); + + Polyline densified = (Polyline) (densify.execute(poly, 10.0, null)); + Polyline convex_hull = (Polyline) (bounding.execute(densified, null)); + Polyline differenced = (Polyline) (difference.execute(densified, convex_hull, SpatialReference.create(4326), null)); + assertTrue(differenced.isEmpty()); + assertTrue(bounding.isConvex(convex_hull, null)); + } + + { + Polyline polyline = new Polyline(); + polyline.startPath(-200, -90); + polyline.lineTo(-180, -85); + polyline.lineTo(-90, -70); + polyline.lineTo(0, 0); + polyline.lineTo(100, 25); + polyline.lineTo(170, 45); + polyline.lineTo(225, 65); + + Polyline densified = (Polyline) (densify.execute(polyline, 10.0, null)); + Polygon convex_hull = (Polygon) (bounding.execute(densified, null)); + boolean bcontains = contains.execute(convex_hull, densified, SpatialReference.create(4326), null); + + assertTrue(bcontains); + assertTrue(bounding.isConvex(convex_hull, null)); + } + } + + @Test + public static void testNonSimpleShape() { + OperatorConvexHull bounding = (OperatorConvexHull) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ConvexHull); + OperatorDensifyByLength densify = (OperatorDensifyByLength) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.DensifyByLength); + OperatorDifference difference = (OperatorDifference) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.Difference); + OperatorContains contains = (OperatorContains) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.Contains); + + { + Polygon shape = (Polygon) (TestCommonMethods.fromJson("{\"rings\":[[[6.7260599916745036,-90],[15.304037095218971,-18.924146439950675],[6.3163297788539232,-90],[5.2105387036445823,-59.980719950158637],[5.1217504663506981,-60.571174400735508],[8.2945138368731044,-27.967042187979146],[15.76606600357545,28.594953216378414],[8.4365340991447919,66.880924521951329],[10.115022726199774,65.247385313781265],[12.721206966604395,-23.793016208456883],[12.051875868947576,-11.368909618476637],[11.867118776841318,44.968896646914239],[7.5326099218274614,35.095776924526533],[8.86765609460479,90],[3.2036592678446922,55.507964789691712],[0.23585282258761486,-42.620591380394039],[-1.2660432762142744,90],[5.5580612840503001,-9.4879902323389196],[12.258387597532487,-35.945231749575591],[-48.746716054894101,90],[7.2294405148356846,-15.719232058488402],[13.798313011339591,-10.467172541381753],[7.4430022048746718,6.3951685161785656],[6.4876332898327815,31.10016146737189],[9.3645424359058911,47.123308099298804],[13.398605254542668,-6.4398318586014325],[-90,90],[13.360786277212718,82.971274676174545],[7.9405631778693566,90],[10.512482079680538,90],[16.994982794293946,19.60673041736408],[16.723893839323615,22.728853852102926],[23.178783416627525,90],[6.7260599916745036,-90]],[[26.768777234301993,90],[20.949797955126346,90],[11.967758262201434,-0.45048849056049711],[17.535751576687339,52.767528591651441],[26.768777234301993,90]],[[18.677765775891793,12.559680067559942],[19.060218406331451,90],[17.123595624401705,90],[-2.3805299720687887,-90],[-11.882782057881979,-90],[21.640575461689693,90],[11.368255808198477,85.501555553904794],[17.390084032215348,90],[23.999392897519989,78.255909006554603],[-6.8860811786563101,69.49189433189926],[29.232578855788898,90],[25.951412073846683,90],[-5.5572284181160772,-16.763772082849457],[18.677765775891793,12.559680067559942]]]}").getGeometry()); + Polygon densified = (Polygon) (densify.execute(shape, 10.0, null)); + Polygon convex_hull = (Polygon) (bounding.execute(densified, null)); + Polygon differenced = (Polygon) (difference.execute(densified, convex_hull, SpatialReference.create(4326), null)); + assertTrue(differenced.isEmpty()); + assertTrue(bounding.isConvex(convex_hull, null)); + } + + { + Polygon shape = (Polygon) (TestCommonMethods.fromJson("{\"rings\":[[[-13.630596027421603,3.6796011190640709],[-10.617275202716886,-28.133054337834409],[-81.617315194491695,90],[-4.0763362539824293,-90],[2.8213537979804073,-90],[-5.1515857979973365,-11.605767592612787],[43.477754021411123,35.507543731267589],[-45.818261267516704,-90],[-4.8545715514870018,-64.204371906322223],[-1.744951154293144,-30.257848194381509],[-7.8524748309267149,15.513561279453089],[-10.657563385538953,-81.785061432086309],[-6.3487369893289411,-31.849779201388415],[-14.768278524737962,-12.004393281111058],[-27.001635582579841,90],[-14.967554248940855,-78.970629918591811],[-12.999635147475825,-38.584472796107939],[-13.630596027421603,3.6796011190640709]],[[-16.338143621861352,-37.415690513288375],[-21.553879270366266,-90],[-18.649338100909404,-90],[-24.880584966233631,1.3133858590648728],[-16.483464632078249,-53.979692212288882],[-24.836979215403964,-68.69859399640147],[-29.708282990385214,-90],[-27.469962102507036,-1.6392995673644872],[-20.405051753708271,61.943199597870034],[-18.242567838912599,24.405109362934219],[-66.334547696572528,-52.678390155566603],[-13.471083255903507,-33.782708412943229],[-7.092757068096085,33.673785662500464],[-2.7427100969018205,74.386868339212668],[-8.2174861339989675,90],[-15.699459164009667,90],[-9.5910045204059156,90],[-8.4504603287557369,90],[-1.5498862802092637,2.5144190340747681],[-6.5326327868410639,-17.428029961128306],[-10.947786354404593,31.516236387466538],[-7.4777936485986354,12.486727826508769],[-13.89052186883092,12.397126427870356],[-10.530672679779606,-55.463541447339118],[-8.7161833631330374,-90],[-4.7231067612639519,-90],[-3.9692500849117041,-32.204677519048822],[3.740804266163555,32.88191805391007],[6.2021313886056246,76.617541950091564],[6.1183997672398194,90],[0.59730820015390673,90],[7.3242950674530753,18.030401540676614],[1.8252371571535342,90],[-16.338143621861352,-37.415690513288375]]]}").getGeometry()); + Polygon densified = (Polygon) (densify.execute(shape, 10.0, null)); + Polygon convex_hull = (Polygon) (bounding.execute(densified, null)); + Polygon differenced = (Polygon) (difference.execute(densified, convex_hull, SpatialReference.create(4326), null)); + assertTrue(differenced.isEmpty()); + assertTrue(bounding.isConvex(convex_hull, null)); + } + + { + Polygon shape = (Polygon) (TestCommonMethods.fromJson("{\"rings\":[[[-11.752662474672046,-90],[-76.236530072126513,7.3247326417920817],[18.933251883215579,90],[51.538924439116798,90],[52.253017336758049,80.352482145105284],[41.767201918260639,51.890297432229289],[21.697252770910882,-1.3185641048567049],[45.112193442818935,60.758441021743636],[48.457184967377231,69.626584611257954],[49.531808284502759,70.202152706968036],[52.394797054144334,71.533541126234581],[ 52.9671102343993,70.704964290210626],[58.527850348069251,16.670036266565845],[62.310807912773328,-34.249918700039238],[62.775020703241523,-43.541598916699364],[64.631871865114277,-80.708319783339874],[65.096084655582459,-90],[-11.752662474672046,-90]]]}").getGeometry()); + Polygon convex_hull = (Polygon) (bounding.execute(shape, null)); + Polygon differenced = (Polygon) (difference.execute(shape, convex_hull, SpatialReference.create(4326), null)); + assertTrue(differenced.isEmpty()); + assertTrue(bounding.isConvex(convex_hull, null)); + } + + { + Polygon polygon = new Polygon(); + polygon.startPath(0, 0); + polygon.lineTo(0, 10); + polygon.lineTo(4, 10); + polygon.lineTo(9, 1); + polygon.lineTo(1, 1); + polygon.lineTo(5, 10); + polygon.lineTo(10, 10); + polygon.lineTo(10, 0); + + Polygon densified = (Polygon) (densify.execute(polygon, 1, null)); + Polygon convex_hull = (Polygon) (bounding.execute(densified, null)); + + double area = convex_hull.calculateArea2D(); + assertTrue(bounding.isConvex(convex_hull, null)); + assertTrue(area == 100.0); + + Point2D p1 = convex_hull.getXY(0); + Point2D p2 = convex_hull.getXY(1); + Point2D p3 = convex_hull.getXY(2); + Point2D p4 = convex_hull.getXY(3); + assertTrue(p1.x == 0.0 && p1.y == 0.0); + assertTrue(p2.x == 0.0 && p2.y == 10.0); + assertTrue(p3.x == 10.0 && p3.y == 10.0); + assertTrue(p4.x == 10.0 && p4.y == 0.0); + } + + { + Polygon polygon = new Polygon(); + polygon.startPath(0, 0); + polygon.lineTo(0, 10); + polygon.lineTo(8, 10); + polygon.lineTo(10, 8); + polygon.lineTo(10, 0); + polygon.lineTo(0, 0); + polygon.lineTo(0, 10); + polygon.lineTo(10, 10); + polygon.lineTo(10, 0); + + // Polygon densified = (Polygon)(densify.execute(polygon, 1, null)); + Polygon convex_hull = (Polygon) (bounding.execute(polygon, null)); + + double area = convex_hull.calculateArea2D(); + assertTrue(bounding.isConvex(convex_hull, null)); + assertTrue(area == 100.0); + + Point2D p1 = convex_hull.getXY(0); + Point2D p2 = convex_hull.getXY(1); + Point2D p3 = convex_hull.getXY(2); + Point2D p4 = convex_hull.getXY(3); + assertTrue(p1.x == 0.0 && p1.y == 0.0); + assertTrue(p2.x == 0.0 && p2.y == 10.0); + assertTrue(p3.x == 10.0 && p3.y == 10.0); + assertTrue(p4.x == 10.0 && p4.y == 0.0); + } + } + + @Test + public static void testStar() { + OperatorConvexHull bounding = (OperatorConvexHull) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ConvexHull); + OperatorDensifyByLength densify = (OperatorDensifyByLength) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.DensifyByLength); + + Polygon star = new Polygon(); + star.startPath(0, 0); + star.lineTo(0, 0); + star.lineTo(5, 10); + star.lineTo(5, 10); + star.lineTo(10, 0); + star.lineTo(10, 0); + star.startPath(0, 5); + star.lineTo(0, 5); + star.lineTo(10, 5); + star.lineTo(10, 5); + star.lineTo(5, -5); + star.lineTo(5, -5); + + star.reversePath(1); + + Polygon densified = (Polygon) (densify.execute(star, 1.0, null)); + Polygon convex_hull = (Polygon) (bounding.execute(densified, null)); + + assertTrue(bounding.isConvex(convex_hull, null)); + + Point2D p1 = convex_hull.getXY(0); + Point2D p2 = convex_hull.getXY(1); + Point2D p3 = convex_hull.getXY(2); + Point2D p4 = convex_hull.getXY(3); + Point2D p5 = convex_hull.getXY(4); + Point2D p6 = convex_hull.getXY(5); + assertTrue(p1.x == 0.0 && p1.y == 0.0); + assertTrue(p2.x == 0.0 && p2.y == 5.0); + assertTrue(p3.x == 5.0 && p3.y == 10.0); + assertTrue(p4.x == 10.0 && p4.y == 5.0); + assertTrue(p5.x == 10.0 && p5.y == 0.0); + assertTrue(p6.x == 5.0 && p6.y == -5.0); + } + + @Test + public static void testPointsArray() { + Point2D[] points = new Point2D[6]; + int[] convex_hull = new int[6]; + + for (int i = 0; i < 6; i++) + points[i] = new Point2D(); + + points[0].x = 0; + points[0].y = 0; + points[1].x = 5; + points[1].y = 10; + points[2].x = 10; + points[2].y = 0; + points[3].x = 0; + points[3].y = 5; + points[4].x = 10; + points[4].y = 5; + points[5].x = 5; + points[5].y = -5; + + ConvexHull.construct(points, 6, convex_hull); + assertTrue(convex_hull[0] == 0); + assertTrue(convex_hull[1] == 3); + assertTrue(convex_hull[2] == 1); + assertTrue(convex_hull[3] == 4); + assertTrue(convex_hull[4] == 2); + assertTrue(convex_hull[5] == 5); + } + + @Test + public static void testMergeCursor() { + OperatorConvexHull bounding = (OperatorConvexHull) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ConvexHull); + + Polygon geom1 = new Polygon(); + Polygon geom2 = new Polygon(); + Point geom3 = new Point(); + Line geom4 = new Line(); + Envelope geom5 = new Envelope(); + MultiPoint geom6 = new MultiPoint(); + + // polygon + geom1.startPath(0, 0); + geom1.lineTo(0, 0); + geom1.lineTo(5, 11); + geom1.lineTo(5, 11); + geom1.lineTo(10, 0); + geom1.lineTo(10, 0); + + // polygon + geom2.startPath(0, 5); + geom2.lineTo(0, 5); + geom2.lineTo(10, 5); + geom2.lineTo(10, 5); + geom2.lineTo(5, -5); + geom2.lineTo(5, -5); + + // point + geom3.setXY(15, 1.25); + + // segment + geom4.setEndXY(-5, 1.25); + geom4.setStartXY(0, 0); + + // envelope + geom5.setCoords(0, 0, 5, 10); + + // multi_point + geom6.add(10, 5); + geom6.add(10, 10); + + // create cursor + Geometry[] geoms = new Geometry[6]; + geoms[0] = geom1; + geoms[1] = geom2; + geoms[2] = geom3; + geoms[3] = geom4; + geoms[4] = geom5; + geoms[5] = geom6; + GeometryCursor cursor = new SimpleGeometryCursor(geoms); + + // create convex hull from the cursor with b_merge set to true + GeometryCursor convex_hull_curs = bounding.execute(cursor, true, null); + Polygon convex_hull = (Polygon) (convex_hull_curs.next()); + assertTrue(convex_hull_curs.next() == null); + + assertTrue(bounding.isConvex(convex_hull, null)); + + Point2D p1 = convex_hull.getXY(0); + Point2D p2 = convex_hull.getXY(1); + Point2D p3 = convex_hull.getXY(2); + Point2D p4 = convex_hull.getXY(3); + Point2D p5 = convex_hull.getXY(4); + Point2D p6 = convex_hull.getXY(5); + assertTrue(p1.x == 5.0 && p1.y == 11.0); + assertTrue(p2.x == 10.0 && p2.y == 10); + assertTrue(p3.x == 15.0 && p3.y == 1.25); + assertTrue(p4.x == 5.0 && p4.y == -5.0); + assertTrue(p5.x == -5.0 && p5.y == 1.25); + assertTrue(p6.x == 0.0 && p6.y == 10.0); + + // Test GeometryEngine + Geometry[] merged_hull = GeometryEngine.convexHull(geoms, true); + convex_hull = (Polygon) merged_hull[0]; + p1 = convex_hull.getXY(0); + p2 = convex_hull.getXY(1); + p3 = convex_hull.getXY(2); + p4 = convex_hull.getXY(3); + p5 = convex_hull.getXY(4); + p6 = convex_hull.getXY(5); + assertTrue(p1.x == 5.0 && p1.y == 11.0); + assertTrue(p2.x == 10.0 && p2.y == 10); + assertTrue(p3.x == 15.0 && p3.y == 1.25); + assertTrue(p4.x == 5.0 && p4.y == -5.0); + assertTrue(p5.x == -5.0 && p5.y == 1.25); + assertTrue(p6.x == 0.0 && p6.y == 10.0); + + } + + @Test + public void testHullTickTock() { + Polygon geom1 = new Polygon(); + Polygon geom2 = new Polygon(); + Point geom3 = new Point(); + Line geom4 = new Line(); + Envelope geom5 = new Envelope(); + MultiPoint geom6 = new MultiPoint(); + + // polygon + geom1.startPath(0, 0); + geom1.lineTo(0, 0); + geom1.lineTo(5, 11); + geom1.lineTo(5, 11); + geom1.lineTo(10, 0); + geom1.lineTo(10, 0); + + // polygon + geom2.startPath(0, 5); + geom2.lineTo(0, 5); + geom2.lineTo(10, 5); + geom2.lineTo(10, 5); + geom2.lineTo(5, -5); + geom2.lineTo(5, -5); + + // point + geom3.setXY(15, 1.25); + + // segment + geom4.setEndXY(-5, 1.25); + geom4.setStartXY(0, 0); + + // envelope + geom5.setCoords(0, 0, 5, 10); + + // multi_point + geom6.add(10, 5); + geom6.add(10, 10); + + // Create + ListeningGeometryCursor gc = new ListeningGeometryCursor(); + GeometryCursor ticktock = OperatorConvexHull.local().execute(gc, true, null); + + // Use tick-tock to push a geometry and do a piece of work. + gc.tick(geom1); + ticktock.tock(); + gc.tick(geom2); + ticktock.tock(); + gc.tick(geom3);// skiped one tock just for testing. + ticktock.tock(); + gc.tick(geom4); + ticktock.tock(); + gc.tick(geom5); + ticktock.tock(); + gc.tick(geom6); + ticktock.tock(); + // Get the result + Geometry result = ticktock.next(); + Polygon convex_hull = (Polygon) result; + assertTrue(OperatorConvexHull.local().isConvex(convex_hull, null)); + + Point2D p1 = convex_hull.getXY(0); + Point2D p2 = convex_hull.getXY(1); + Point2D p3 = convex_hull.getXY(2); + Point2D p4 = convex_hull.getXY(3); + Point2D p5 = convex_hull.getXY(4); + Point2D p6 = convex_hull.getXY(5); + assertTrue(p1.x == 5.0 && p1.y == 11.0); + assertTrue(p2.x == 10.0 && p2.y == 10); + assertTrue(p3.x == 15.0 && p3.y == 1.25); + assertTrue(p4.x == 5.0 && p4.y == -5.0); + assertTrue(p5.x == -5.0 && p5.y == 1.25); + assertTrue(p6.x == 0.0 && p6.y == 10.0); + } + + @Test + public void testHullIssueGithub172() { + { + //empty + OGCGeometry geom = OGCGeometry.fromText("MULTIPOINT EMPTY"); + OGCGeometry result = geom.convexHull(); + String text = result.asText(); + assertTrue(text.compareTo("POINT EMPTY") == 0); + } + { + //Point + OGCGeometry geom = OGCGeometry.fromText("POINT (1 2)"); + OGCGeometry result = geom.convexHull(); + String text = result.asText(); + assertTrue(text.compareTo("POINT (1 2)") == 0); + } + { + //line + OGCGeometry geom = OGCGeometry.fromText("MULTIPOINT (1 1, 2 2)"); + OGCGeometry result = geom.convexHull(); + String text = result.asText(); + assertTrue(text.compareTo("LINESTRING (1 1, 2 2)") == 0); + } + { + //empty + OGCGeometry geom = OGCGeometry.fromText("GEOMETRYCOLLECTION EMPTY"); + OGCGeometry result = geom.convexHull(); + String text = result.asText(); + assertTrue(text.compareTo("POINT EMPTY") == 0); + } + + { + //empty + OGCGeometry geom = OGCGeometry.fromText("GEOMETRYCOLLECTION (POINT (1 2))"); + OGCGeometry result = geom.convexHull(); + String text = result.asText(); + assertTrue(text.compareTo("POINT (1 2)") == 0); + } + + { + //empty + OGCGeometry geom = OGCGeometry.fromText("GEOMETRYCOLLECTION(POLYGON EMPTY, POINT(1 1), LINESTRING EMPTY, MULTIPOLYGON EMPTY, MULTILINESTRING EMPTY)"); + OGCGeometry result = geom.convexHull(); + String text = result.asText(); + assertTrue(text.compareTo("POINT (1 1)") == 0); + } + + { + //empty + OGCGeometry geom = OGCGeometry.fromText("GEOMETRYCOLLECTION(POLYGON EMPTY, LINESTRING (1 1, 2 2), POINT(3 3), LINESTRING EMPTY, MULTIPOLYGON EMPTY, MULTILINESTRING EMPTY)"); + OGCGeometry result = geom.convexHull(); + String text = result.asText(); + assertTrue(text.compareTo("LINESTRING (1 1, 3 3)") == 0); + } + + { + //empty + OGCGeometry geom = OGCGeometry.fromText("GEOMETRYCOLLECTION(POLYGON EMPTY, LINESTRING (1 1, 2 2), POINT(3 3), LINESTRING EMPTY, POLYGON((-10 -10, 10 -10, 10 10, -10 10, -10 -10), (-5 -5, -5 5, 5 5, 5 -5, -5 -5)))"); + OGCGeometry result = geom.convexHull(); + String text = result.asText(); + assertTrue(text.compareTo("POLYGON ((-10 -10, 10 -10, 10 10, -10 10, -10 -10))") == 0); + } + } + + @Test + public void testHullIssueGithub194() { + { + //empty + OGCGeometry geom = OGCGeometry.fromText("GEOMETRYCOLLECTION(POLYGON EMPTY, POLYGON((0 0, 1 0, 1 1, 0 0)), POLYGON((-10 -10, 10 -10, 10 10, -10 10, -10 -10), (-5 -5, -5 5, 5 5, 5 -5, -5 -5)))"); + OGCGeometry result = geom.convexHull(); + String text = result.asText(); + assertTrue(text.compareTo("POLYGON ((-10 -10, 10 -10, 10 10, -10 10, -10 -10))") == 0); + } + } } diff --git a/src/test/java/com/esri/core/geometry/TestCut.java b/src/test/java/com/esri/core/geometry/TestCut.java index e6c1fbb3..1cfd7f08 100644 --- a/src/test/java/com/esri/core/geometry/TestCut.java +++ b/src/test/java/com/esri/core/geometry/TestCut.java @@ -30,555 +30,571 @@ import java.util.ArrayDeque; public class TestCut extends TestCase { - @Override - protected void setUp() throws Exception { - super.setUp(); - } - - @Override - protected void tearDown() throws Exception { - super.tearDown(); - } - - @Test - public static void testCut4326() { - SpatialReference sr = SpatialReference.create(4326); - testConsiderTouch1(sr); - testConsiderTouch2(sr); - testPolygon5(sr); - testPolygon7(sr); - testPolygon8(sr); - testPolygon9(sr); - testEngine(sr); - - } - - public static void testConsiderTouch1(SpatialReference spatialReference) { - OperatorFactoryLocal engine = OperatorFactoryLocal.getInstance(); - OperatorCut opCut = (OperatorCut) engine.getOperator(Operator.Type.Cut); - - Polyline polyline1 = makePolyline1(); - Polyline polyline11 = makePolyline1(); - Polyline cutter1 = makePolylineCutter1(); - - ArrayDeque polylines = new ArrayDeque<>(); - polylines.push(polyline1); - polylines.push(polyline11); - - SimpleGeometryCursor simpleGeometryCursor = new SimpleGeometryCursor(polylines); - GeometryCursor cursor = opCut.execute(true, simpleGeometryCursor, cutter1, - spatialReference, null); - Polyline cut; - int pathCount; - int segmentCount; - double length; - - cut = (Polyline) cursor.next(); - pathCount = cut.getPathCount(); - segmentCount = cut.getSegmentCount(); - length = cut.calculateLength2D(); - assertTrue(pathCount == 4); - assertTrue(segmentCount == 4); - assertTrue(length == 6); - - cut = (Polyline) cursor.next(); - pathCount = cut.getPathCount(); - segmentCount = cut.getSegmentCount(); - length = cut.calculateLength2D(); - assertTrue(pathCount == 6); - assertTrue(segmentCount == 8); - assertTrue(length == 12); - - cut = (Polyline) cursor.next(); - pathCount = cut.getPathCount(); - segmentCount = cut.getSegmentCount(); - length = cut.calculateLength2D(); - assertTrue(pathCount == 1); - assertTrue(segmentCount == 1); - assertTrue(length == 1); - - cut = (Polyline) cursor.next(); - pathCount = cut.getPathCount(); - segmentCount = cut.getSegmentCount(); - length = cut.calculateLength2D(); - assertTrue(pathCount == 1); - assertTrue(segmentCount == 1); - assertTrue(length == 1); - - cut = (Polyline) cursor.next(); - pathCount = cut.getPathCount(); - segmentCount = cut.getSegmentCount(); - length = cut.calculateLength2D(); - assertTrue(pathCount == 4); - assertTrue(segmentCount == 4); - assertTrue(length == 6); - - cut = (Polyline) cursor.next(); - pathCount = cut.getPathCount(); - segmentCount = cut.getSegmentCount(); - length = cut.calculateLength2D(); - assertTrue(pathCount == 6); - assertTrue(segmentCount == 8); - assertTrue(length == 12); - - cut = (Polyline) cursor.next(); - pathCount = cut.getPathCount(); - segmentCount = cut.getSegmentCount(); - length = cut.calculateLength2D(); - assertTrue(pathCount == 1); - assertTrue(segmentCount == 1); - assertTrue(length == 1); - - cut = (Polyline) cursor.next(); - pathCount = cut.getPathCount(); - segmentCount = cut.getSegmentCount(); - length = cut.calculateLength2D(); - assertTrue(pathCount == 1); - assertTrue(segmentCount == 1); - assertTrue(length == 1); - - cut = (Polyline) cursor.next(); - assertTrue(cut == null); - } - - public static void testConsiderTouch2(SpatialReference spatialReference) { - OperatorFactoryLocal engine = OperatorFactoryLocal.getInstance(); - OperatorCut opCut = (OperatorCut) engine.getOperator(Operator.Type.Cut); - - Polyline polyline2 = makePolyline2(); - Polyline cutter2 = makePolylineCutter2(); - - GeometryCursor cursor = opCut.execute(true, polyline2, cutter2, - spatialReference, null); - Polyline cut; - int pathCount; - int segmentCount; - double length; - - cut = (Polyline) cursor.next(); - pathCount = cut.getPathCount(); - segmentCount = cut.getSegmentCount(); - length = cut.calculateLength2D(); - assertTrue(pathCount == 4); - assertTrue(segmentCount == 4); - assertTrue(Math.abs(length - 5.74264068) <= 0.001); - - cut = (Polyline) cursor.next(); - pathCount = cut.getPathCount(); - segmentCount = cut.getSegmentCount(); - length = cut.calculateLength2D(); - assertTrue(pathCount == 6); - assertTrue(segmentCount == 8); - assertTrue(length == 6.75); - - cut = (Polyline) cursor.next(); - pathCount = cut.getPathCount(); - segmentCount = cut.getSegmentCount(); - length = cut.calculateLength2D(); - assertTrue(pathCount == 1); - assertTrue(segmentCount == 1); - assertTrue(Math.abs(length - 0.5) <= 0.001); - - cut = (Polyline) cursor.next(); - pathCount = cut.getPathCount(); - segmentCount = cut.getSegmentCount(); - length = cut.calculateLength2D(); - assertTrue(pathCount == 1); - assertTrue(segmentCount == 1); - assertTrue(Math.abs(length - 0.25) <= 0.001); - - cut = (Polyline) cursor.next(); - pathCount = cut.getPathCount(); - segmentCount = cut.getSegmentCount(); - length = cut.calculateLength2D(); - assertTrue(pathCount == 1); - assertTrue(segmentCount == 1); - assertTrue(Math.abs(length - 1) <= 0.001); - - cut = (Polyline) cursor.next(); - pathCount = cut.getPathCount(); - segmentCount = cut.getSegmentCount(); - length = cut.calculateLength2D(); - assertTrue(pathCount == 1); - assertTrue(segmentCount == 1); - assertTrue(Math.abs(length - 1.41421356) <= 0.001); - - cut = (Polyline) cursor.next(); - assertTrue(cut == null); - } - - public static void testPolygon5(SpatialReference spatialReference) { - OperatorFactoryLocal engine = OperatorFactoryLocal.getInstance(); - OperatorCut opCut = (OperatorCut) engine.getOperator(Operator.Type.Cut); - - Polygon polygon5 = makePolygon5(); - Polyline cutter5 = makePolygonCutter5(); - - GeometryCursor cursor = opCut.execute(true, polygon5, cutter5, - spatialReference, null); - Polygon cut; - int pathCount; - int pointCount; - double area; - - cut = (Polygon) cursor.next(); - pathCount = cut.getPathCount(); - pointCount = cut.getPointCount(); - area = cut.calculateArea2D(); - assertTrue(pathCount == 4); - assertTrue(pointCount == 12); - assertTrue(area == 450); - - cut = (Polygon) cursor.next(); - pathCount = cut.getPathCount(); - pointCount = cut.getPointCount(); - area = cut.calculateArea2D(); - assertTrue(pathCount == 1); - assertTrue(pointCount == 4); - assertTrue(area == 450); - - cut = (Polygon) cursor.next(); - assertTrue(cut == null); - } - - public static void testPolygon7(SpatialReference spatialReference) { - OperatorFactoryLocal engine = OperatorFactoryLocal.getInstance(); - OperatorCut opCut = (OperatorCut) engine.getOperator(Operator.Type.Cut); - - Polygon cut; - int path_count; - int point_count; - double area; - - Polygon polygon7 = makePolygon7(); - Polyline cutter7 = makePolygonCutter7(); - GeometryCursor cursor = opCut.execute(false, polygon7, cutter7, - spatialReference, null); - - cut = (Polygon) cursor.next(); - path_count = cut.getPathCount(); - point_count = cut.getPointCount(); - area = cut.calculateArea2D(); - assertTrue(path_count == 1); - assertTrue(point_count == 4); - assertTrue(area == 100); - - cut = (Polygon) cursor.next(); - assertTrue(cut.isEmpty()); - - cut = (Polygon) cursor.next(); - path_count = cut.getPathCount(); - point_count = cut.getPointCount(); - area = cut.calculateArea2D(); - assertTrue(path_count == 2); - assertTrue(point_count == 8); - assertTrue(area == 800); - - cut = (Polygon) cursor.next(); - assertTrue(cut == null); - } - - public static void testPolygon8(SpatialReference spatialReference) { - OperatorFactoryLocal engine = OperatorFactoryLocal.getInstance(); - OperatorCut opCut = (OperatorCut) engine.getOperator(Operator.Type.Cut); - - Polygon polygon8 = makePolygon8(); - Polyline cutter8 = makePolygonCutter8(); - - GeometryCursor cursor = opCut.execute(true, polygon8, cutter8, - spatialReference, null); - Polygon cut; - int pathCount; - int pointCount; - double area; - - cut = (Polygon) cursor.next(); - assertTrue(cut.isEmpty()); - - cut = (Polygon) cursor.next(); - pathCount = cut.getPathCount(); - pointCount = cut.getPointCount(); - area = cut.calculateArea2D(); - assertTrue(pathCount == 1); - assertTrue(pointCount == 4); - assertTrue(area == 100); - - cut = (Polygon) cursor.next(); - pathCount = cut.getPathCount(); - pointCount = cut.getPointCount(); - area = cut.calculateArea2D(); - assertTrue(pathCount == 2); - assertTrue(pointCount == 8); - assertTrue(area == 800); - - cut = (Polygon) cursor.next(); - assertTrue(cut == null); - } - - public static void testPolygon9(SpatialReference spatialReference) { - OperatorFactoryLocal engine = OperatorFactoryLocal.getInstance(); - OperatorCut opCut = (OperatorCut) engine.getOperator(Operator.Type.Cut); - - Polygon cut; - int path_count; - int point_count; - double area; - - Polygon polygon9 = makePolygon9(); - Polyline cutter9 = makePolygonCutter9(); - GeometryCursor cursor = opCut.execute(false, polygon9, cutter9, - spatialReference, null); - - cut = (Polygon) cursor.next(); - path_count = cut.getPathCount(); - point_count = cut.getPointCount(); - area = cut.calculateArea2D(); - assertTrue(path_count == 3); - assertTrue(point_count == 12); - assertTrue(area == 150); - - cut = (Polygon) cursor.next(); - path_count = cut.getPathCount(); - point_count = cut.getPointCount(); - area = cut.calculateArea2D(); - assertTrue(path_count == 3); - assertTrue(point_count == 12); - assertTrue(area == 150); - - cut = (Polygon) cursor.next(); - assertTrue(cut == null); - } - - public static void testEngine(SpatialReference spatialReference) { - Polygon polygon8 = makePolygon8(); - Polyline cutter8 = makePolygonCutter8(); - - Geometry[] cuts = GeometryEngine.cut(polygon8, cutter8, - spatialReference); - Polygon cut; - int pathCount; - int pointCount; - double area; - - cut = (Polygon) cuts[0]; - pathCount = cut.getPathCount(); - pointCount = cut.getPointCount(); - area = cut.calculateArea2D(); - assertTrue(pathCount == 1); - assertTrue(pointCount == 4); - assertTrue(area == 100); - - cut = (Polygon) cuts[1]; - pathCount = cut.getPathCount(); - pointCount = cut.getPointCount(); - area = cut.calculateArea2D(); - assertTrue(pathCount == 2); - assertTrue(pointCount == 8); - assertTrue(area == 800); - } - - public static Polyline makePolyline1() { - Polyline poly = new Polyline(); - - poly.startPath(0, 0); - poly.lineTo(2, 0); - poly.lineTo(4, 0); - poly.lineTo(6, 0); - poly.lineTo(8, 0); - poly.lineTo(10, 0); - poly.lineTo(12, 0); - poly.lineTo(14, 0); - poly.lineTo(16, 0); - poly.lineTo(18, 0); - poly.lineTo(20, 0); - - return poly; - } - - public static Polyline makePolylineCutter1() { - Polyline poly = new Polyline(); - - poly.startPath(1, 0); - poly.lineTo(4, 0); - - poly.startPath(6, -1); - poly.lineTo(6, 1); - - poly.startPath(6, 0); - poly.lineTo(8, 0); - - poly.startPath(9, -1); - poly.lineTo(9, 1); - - poly.startPath(10, 0); - poly.lineTo(12, 0); - - poly.startPath(12, 1); - poly.lineTo(12, -1); - - poly.startPath(12, 0); - poly.lineTo(15, 0); - - poly.startPath(15, 1); - poly.lineTo(15, -1); - - poly.startPath(16, 0); - poly.lineTo(16, -1); - poly.lineTo(17, -1); - poly.lineTo(17, 1); - poly.lineTo(17, 0); - poly.lineTo(18, 0); - - poly.startPath(18, 0); - poly.lineTo(18, -1); - - return poly; - } - - public static Polyline makePolyline2() { - Polyline poly = new Polyline(); - - poly.startPath(-2, 0); - poly.lineTo(-1, 0); - poly.lineTo(0, 0); - poly.lineTo(2, 0); - poly.lineTo(4, 2); - poly.lineTo(8, 2); - poly.lineTo(10, 4); - poly.lineTo(12, 4); - - return poly; - } - - public static Polyline makePolylineCutter2() { - Polyline poly = new Polyline(); - - poly.startPath(-1.5, 0); - poly.lineTo(-.75, 0); - - poly.startPath(-.5, 0); - poly.lineTo(1, 0); - poly.lineTo(1, 2); - poly.lineTo(3, -2); - poly.lineTo(4, 2); - poly.lineTo(5, -2); - poly.lineTo(5, 4); - poly.lineTo(8, 2); - poly.lineTo(6, 0); - poly.lineTo(6, 3); - - poly.startPath(9, 5); - poly.lineTo(9, 2); - poly.lineTo(10, 2); - poly.lineTo(10, 5); - poly.lineTo(10.5, 5); - poly.lineTo(10.5, 3); - - poly.startPath(11, 4); - poly.lineTo(11, 5); + @Override + protected void setUp() throws Exception { + super.setUp(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + } + + @Test + public static void testCut4326() { + SpatialReference sr = SpatialReference.create(4326); + testConsiderTouch1(sr); + testConsiderTouch2(sr); + testPolygon5(sr); + testPolygon7(sr); + testPolygon8(sr); + testPolygon9(sr); + testEngine(sr); + + } + + public static void testConsiderTouch1(SpatialReference spatialReference) { + OperatorFactoryLocal engine = OperatorFactoryLocal.getInstance(); + OperatorCut opCut = (OperatorCut) engine.getOperator(Operator.Type.Cut); + + Polyline polyline1 = makePolyline1(); + Polyline polyline11 = makePolyline1(); + Polyline cutter1 = makePolylineCutter1(); + + ArrayDeque polylines = new ArrayDeque<>(); + polylines.push(polyline1); + polylines.push(polyline11); + + SimpleGeometryCursor simpleGeometryCursor = new SimpleGeometryCursor(polylines); + GeometryCursor cursor = opCut.execute(true, simpleGeometryCursor, cutter1, + spatialReference, null); + Polyline cut; + int pathCount; + int segmentCount; + double length; + + cut = (Polyline) cursor.next(); + pathCount = cut.getPathCount(); + segmentCount = cut.getSegmentCount(); + length = cut.calculateLength2D(); + assertTrue(pathCount == 4); + assertTrue(segmentCount == 4); + assertTrue(length == 6); + + cut = (Polyline) cursor.next(); + pathCount = cut.getPathCount(); + segmentCount = cut.getSegmentCount(); + length = cut.calculateLength2D(); + assertTrue(pathCount == 6); + assertTrue(segmentCount == 8); + assertTrue(length == 12); + + cut = (Polyline) cursor.next(); + pathCount = cut.getPathCount(); + segmentCount = cut.getSegmentCount(); + length = cut.calculateLength2D(); + assertTrue(pathCount == 1); + assertTrue(segmentCount == 1); + assertTrue(length == 1); + + cut = (Polyline) cursor.next(); + pathCount = cut.getPathCount(); + segmentCount = cut.getSegmentCount(); + length = cut.calculateLength2D(); + assertTrue(pathCount == 1); + assertTrue(segmentCount == 1); + assertTrue(length == 1); + + cut = (Polyline) cursor.next(); + pathCount = cut.getPathCount(); + segmentCount = cut.getSegmentCount(); + length = cut.calculateLength2D(); + assertTrue(pathCount == 4); + assertTrue(segmentCount == 4); + assertTrue(length == 6); + + cut = (Polyline) cursor.next(); + pathCount = cut.getPathCount(); + segmentCount = cut.getSegmentCount(); + length = cut.calculateLength2D(); + assertTrue(pathCount == 6); + assertTrue(segmentCount == 8); + assertTrue(length == 12); + + cut = (Polyline) cursor.next(); + pathCount = cut.getPathCount(); + segmentCount = cut.getSegmentCount(); + length = cut.calculateLength2D(); + assertTrue(pathCount == 1); + assertTrue(segmentCount == 1); + assertTrue(length == 1); + + cut = (Polyline) cursor.next(); + pathCount = cut.getPathCount(); + segmentCount = cut.getSegmentCount(); + length = cut.calculateLength2D(); + assertTrue(pathCount == 1); + assertTrue(segmentCount == 1); + assertTrue(length == 1); + + cut = (Polyline) cursor.next(); + assertTrue(cut == null); + } + + public static void testConsiderTouch2(SpatialReference spatialReference) { + OperatorFactoryLocal engine = OperatorFactoryLocal.getInstance(); + OperatorCut opCut = (OperatorCut) engine.getOperator(Operator.Type.Cut); + + Polyline polyline2 = makePolyline2(); + Polyline cutter2 = makePolylineCutter2(); + + GeometryCursor cursor = opCut.execute(true, polyline2, cutter2, + spatialReference, null); + Polyline cut; + int pathCount; + int segmentCount; + double length; + + cut = (Polyline) cursor.next(); + pathCount = cut.getPathCount(); + segmentCount = cut.getSegmentCount(); + length = cut.calculateLength2D(); + assertTrue(pathCount == 4); + assertTrue(segmentCount == 4); + assertTrue(Math.abs(length - 5.74264068) <= 0.001); + + cut = (Polyline) cursor.next(); + pathCount = cut.getPathCount(); + segmentCount = cut.getSegmentCount(); + length = cut.calculateLength2D(); + assertTrue(pathCount == 6); + assertTrue(segmentCount == 8); + assertTrue(length == 6.75); + + cut = (Polyline) cursor.next(); + pathCount = cut.getPathCount(); + segmentCount = cut.getSegmentCount(); + length = cut.calculateLength2D(); + assertTrue(pathCount == 1); + assertTrue(segmentCount == 1); + assertTrue(Math.abs(length - 0.5) <= 0.001); + + cut = (Polyline) cursor.next(); + pathCount = cut.getPathCount(); + segmentCount = cut.getSegmentCount(); + length = cut.calculateLength2D(); + assertTrue(pathCount == 1); + assertTrue(segmentCount == 1); + assertTrue(Math.abs(length - 0.25) <= 0.001); + + cut = (Polyline) cursor.next(); + pathCount = cut.getPathCount(); + segmentCount = cut.getSegmentCount(); + length = cut.calculateLength2D(); + assertTrue(pathCount == 1); + assertTrue(segmentCount == 1); + assertTrue(Math.abs(length - 1) <= 0.001); + + cut = (Polyline) cursor.next(); + pathCount = cut.getPathCount(); + segmentCount = cut.getSegmentCount(); + length = cut.calculateLength2D(); + assertTrue(pathCount == 1); + assertTrue(segmentCount == 1); + assertTrue(Math.abs(length - 1.41421356) <= 0.001); + + cut = (Polyline) cursor.next(); + assertTrue(cut == null); + } + + public static void testPolygon5(SpatialReference spatialReference) { + OperatorFactoryLocal engine = OperatorFactoryLocal.getInstance(); + OperatorCut opCut = (OperatorCut) engine.getOperator(Operator.Type.Cut); + + Polygon polygon5 = makePolygon5(); + Polyline cutter5 = makePolygonCutter5(); + + GeometryCursor cursor = opCut.execute(true, polygon5, cutter5, + spatialReference, null); + Polygon cut; + int pathCount; + int pointCount; + double area; + + cut = (Polygon) cursor.next(); + pathCount = cut.getPathCount(); + pointCount = cut.getPointCount(); + area = cut.calculateArea2D(); + assertTrue(pathCount == 4); + assertTrue(pointCount == 12); + assertTrue(area == 450); + + cut = (Polygon) cursor.next(); + pathCount = cut.getPathCount(); + pointCount = cut.getPointCount(); + area = cut.calculateArea2D(); + assertTrue(pathCount == 1); + assertTrue(pointCount == 4); + assertTrue(area == 450); + + cut = (Polygon) cursor.next(); + assertTrue(cut == null); + } + + public static void testPolygon7(SpatialReference spatialReference) { + OperatorFactoryLocal engine = OperatorFactoryLocal.getInstance(); + OperatorCut opCut = (OperatorCut) engine.getOperator(Operator.Type.Cut); + + Polygon cut; + int path_count; + int point_count; + double area; + + Polygon polygon7 = makePolygon7(); + Polyline cutter7 = makePolygonCutter7(); + GeometryCursor cursor = opCut.execute(false, polygon7, cutter7, + spatialReference, null); + + cut = (Polygon) cursor.next(); + path_count = cut.getPathCount(); + point_count = cut.getPointCount(); + area = cut.calculateArea2D(); + assertTrue(path_count == 1); + assertTrue(point_count == 4); + assertTrue(area == 100); + + cut = (Polygon) cursor.next(); + assertTrue(cut.isEmpty()); + + cut = (Polygon) cursor.next(); + path_count = cut.getPathCount(); + point_count = cut.getPointCount(); + area = cut.calculateArea2D(); + assertTrue(path_count == 2); + assertTrue(point_count == 8); + assertTrue(area == 800); + + cut = (Polygon) cursor.next(); + assertTrue(cut == null); + } + + public static void testPolygon8(SpatialReference spatialReference) { + OperatorFactoryLocal engine = OperatorFactoryLocal.getInstance(); + OperatorCut opCut = (OperatorCut) engine.getOperator(Operator.Type.Cut); + + Polygon polygon8 = makePolygon8(); + Polyline cutter8 = makePolygonCutter8(); + + GeometryCursor cursor = opCut.execute(true, polygon8, cutter8, + spatialReference, null); + Polygon cut; + int pathCount; + int pointCount; + double area; + + cut = (Polygon) cursor.next(); + assertTrue(cut.isEmpty()); + + cut = (Polygon) cursor.next(); + pathCount = cut.getPathCount(); + pointCount = cut.getPointCount(); + area = cut.calculateArea2D(); + assertTrue(pathCount == 1); + assertTrue(pointCount == 4); + assertTrue(area == 100); + + cut = (Polygon) cursor.next(); + pathCount = cut.getPathCount(); + pointCount = cut.getPointCount(); + area = cut.calculateArea2D(); + assertTrue(pathCount == 2); + assertTrue(pointCount == 8); + assertTrue(area == 800); + + cut = (Polygon) cursor.next(); + assertTrue(cut == null); + } + + public static void testPolygon9(SpatialReference spatialReference) { + OperatorFactoryLocal engine = OperatorFactoryLocal.getInstance(); + OperatorCut opCut = (OperatorCut) engine.getOperator(Operator.Type.Cut); + + Polygon cut; + int path_count; + int point_count; + double area; + + Polygon polygon9 = makePolygon9(); + Polyline cutter9 = makePolygonCutter9(); + GeometryCursor cursor = opCut.execute(false, polygon9, cutter9, + spatialReference, null); + + cut = (Polygon) cursor.next(); + path_count = cut.getPathCount(); + point_count = cut.getPointCount(); + area = cut.calculateArea2D(); + assertTrue(path_count == 3); + assertTrue(point_count == 12); + assertTrue(area == 150); + + cut = (Polygon) cursor.next(); + path_count = cut.getPathCount(); + point_count = cut.getPointCount(); + area = cut.calculateArea2D(); + assertTrue(path_count == 3); + assertTrue(point_count == 12); + assertTrue(area == 150); + + cut = (Polygon) cursor.next(); + assertTrue(cut == null); + } + + public static void testEngine(SpatialReference spatialReference) { + Polygon polygon8 = makePolygon8(); + Polyline cutter8 = makePolygonCutter8(); + + Geometry[] cuts = GeometryEngine.cut(polygon8, cutter8, + spatialReference); + Polygon cut; + int pathCount; + int pointCount; + double area; + + cut = (Polygon) cuts[0]; + pathCount = cut.getPathCount(); + pointCount = cut.getPointCount(); + area = cut.calculateArea2D(); + assertTrue(pathCount == 1); + assertTrue(pointCount == 4); + assertTrue(area == 100); + + cut = (Polygon) cuts[1]; + pathCount = cut.getPathCount(); + pointCount = cut.getPointCount(); + area = cut.calculateArea2D(); + assertTrue(pathCount == 2); + assertTrue(pointCount == 8); + assertTrue(area == 800); + } + + public static Polyline makePolyline1() { + Polyline poly = new Polyline(); + + poly.startPath(0, 0); + poly.lineTo(2, 0); + poly.lineTo(4, 0); + poly.lineTo(6, 0); + poly.lineTo(8, 0); + poly.lineTo(10, 0); + poly.lineTo(12, 0); + poly.lineTo(14, 0); + poly.lineTo(16, 0); + poly.lineTo(18, 0); + poly.lineTo(20, 0); + + return poly; + } + + public static Polyline makePolylineCutter1() { + Polyline poly = new Polyline(); + + poly.startPath(1, 0); + poly.lineTo(4, 0); + + poly.startPath(6, -1); + poly.lineTo(6, 1); + + poly.startPath(6, 0); + poly.lineTo(8, 0); + + poly.startPath(9, -1); + poly.lineTo(9, 1); + + poly.startPath(10, 0); + poly.lineTo(12, 0); + + poly.startPath(12, 1); + poly.lineTo(12, -1); + + poly.startPath(12, 0); + poly.lineTo(15, 0); + + poly.startPath(15, 1); + poly.lineTo(15, -1); + + poly.startPath(16, 0); + poly.lineTo(16, -1); + poly.lineTo(17, -1); + poly.lineTo(17, 1); + poly.lineTo(17, 0); + poly.lineTo(18, 0); + + poly.startPath(18, 0); + poly.lineTo(18, -1); + + return poly; + } + + public static Polyline makePolyline2() { + Polyline poly = new Polyline(); + + poly.startPath(-2, 0); + poly.lineTo(-1, 0); + poly.lineTo(0, 0); + poly.lineTo(2, 0); + poly.lineTo(4, 2); + poly.lineTo(8, 2); + poly.lineTo(10, 4); + poly.lineTo(12, 4); + + return poly; + } + + public static Polyline makePolylineCutter2() { + Polyline poly = new Polyline(); + + poly.startPath(-1.5, 0); + poly.lineTo(-.75, 0); + + poly.startPath(-.5, 0); + poly.lineTo(1, 0); + poly.lineTo(1, 2); + poly.lineTo(3, -2); + poly.lineTo(4, 2); + poly.lineTo(5, -2); + poly.lineTo(5, 4); + poly.lineTo(8, 2); + poly.lineTo(6, 0); + poly.lineTo(6, 3); + + poly.startPath(9, 5); + poly.lineTo(9, 2); + poly.lineTo(10, 2); + poly.lineTo(10, 5); + poly.lineTo(10.5, 5); + poly.lineTo(10.5, 3); + + poly.startPath(11, 4); + poly.lineTo(11, 5); - poly.startPath(12, 5); - poly.lineTo(12, 4); + poly.startPath(12, 5); + poly.lineTo(12, 4); - return poly; - } + return poly; + } - public static Polygon makePolygon5() { - Polygon poly = new Polygon(); + public static Polygon makePolygon5() { + Polygon poly = new Polygon(); - poly.startPath(0, 0); - poly.lineTo(0, 30); - poly.lineTo(30, 30); - poly.lineTo(30, 0); + poly.startPath(0, 0); + poly.lineTo(0, 30); + poly.lineTo(30, 30); + poly.lineTo(30, 0); - return poly; - } + return poly; + } - public static Polyline makePolygonCutter5() { - Polyline poly = new Polyline(); + public static Polyline makePolygonCutter5() { + Polyline poly = new Polyline(); + + poly.startPath(15, 0); + poly.lineTo(0, 15); + poly.lineTo(15, 30); + poly.lineTo(30, 15); + poly.lineTo(15, 0); + + return poly; + } + + public static Polygon makePolygon7() { + Polygon poly = new Polygon(); + + poly.startPath(0, 0); + poly.lineTo(0, 30); + poly.lineTo(30, 30); + poly.lineTo(30, 0); + + return poly; + } + + public static Polyline makePolygonCutter7() { + Polyline poly = new Polyline(); + + poly.startPath(10, 10); + poly.lineTo(20, 10); + poly.lineTo(20, 20); + poly.lineTo(10, 20); + poly.lineTo(10, 10); + + return poly; + } + + public static Polygon makePolygon8() { + Polygon poly = new Polygon(); + + poly.startPath(0, 0); + poly.lineTo(0, 30); + poly.lineTo(30, 30); + poly.lineTo(30, 0); + + return poly; + } + + public static Polyline makePolygonCutter8() { + Polyline poly = new Polyline(); + + poly.startPath(10, 10); + poly.lineTo(10, 20); + poly.lineTo(20, 20); + poly.lineTo(20, 10); + poly.lineTo(10, 10); + + return poly; + } + + public static Polygon makePolygon9() { + Polygon poly = new Polygon(); + + poly.startPath(0, 0); + poly.lineTo(0, 10); + poly.lineTo(10, 10); + poly.lineTo(10, 0); + + poly.startPath(0, 20); + poly.lineTo(0, 30); + poly.lineTo(10, 30); + poly.lineTo(10, 20); + + poly.startPath(0, 40); + poly.lineTo(0, 50); + poly.lineTo(10, 50); + poly.lineTo(10, 40); + + return poly; + } - poly.startPath(15, 0); - poly.lineTo(0, 15); - poly.lineTo(15, 30); - poly.lineTo(30, 15); - poly.lineTo(15, 0); + public static Polyline makePolygonCutter9() { + Polyline poly = new Polyline(); - return poly; - } + poly.startPath(5, -1); + poly.lineTo(5, 51); - public static Polygon makePolygon7() { - Polygon poly = new Polygon(); - - poly.startPath(0, 0); - poly.lineTo(0, 30); - poly.lineTo(30, 30); - poly.lineTo(30, 0); - - return poly; - } - - public static Polyline makePolygonCutter7() { - Polyline poly = new Polyline(); - - poly.startPath(10, 10); - poly.lineTo(20, 10); - poly.lineTo(20, 20); - poly.lineTo(10, 20); - poly.lineTo(10, 10); - - return poly; - } - - public static Polygon makePolygon8() { - Polygon poly = new Polygon(); - - poly.startPath(0, 0); - poly.lineTo(0, 30); - poly.lineTo(30, 30); - poly.lineTo(30, 0); - - return poly; - } - - public static Polyline makePolygonCutter8() { - Polyline poly = new Polyline(); - - poly.startPath(10, 10); - poly.lineTo(10, 20); - poly.lineTo(20, 20); - poly.lineTo(20, 10); - poly.lineTo(10, 10); - - return poly; - } - - public static Polygon makePolygon9() { - Polygon poly = new Polygon(); - - poly.startPath(0, 0); - poly.lineTo(0, 10); - poly.lineTo(10, 10); - poly.lineTo(10, 0); - - poly.startPath(0, 20); - poly.lineTo(0, 30); - poly.lineTo(10, 30); - poly.lineTo(10, 20); - - poly.startPath(0, 40); - poly.lineTo(0, 50); - poly.lineTo(10, 50); - poly.lineTo(10, 40); - - return poly; - } - - public static Polyline makePolygonCutter9() { - Polyline poly = new Polyline(); - - poly.startPath(5, -1); - poly.lineTo(5, 51); - - return poly; - } + return poly; + } + + @Test + public void testGithubIssue253() { + //https://github.com/Esri/geometry-api-java/issues/253 + SpatialReference spatialReference = SpatialReference.create(3857); + Polyline poly1 = new Polyline(); + poly1.startPath(610, 552); + poly1.lineTo(610, 552); + Polyline poly2 = new Polyline(); + poly2.startPath(610, 552); + poly2.lineTo(610, 552); + GeometryCursor cursor = OperatorCut.local().execute(true, poly1, poly2, spatialReference, null); + + Geometry res = cursor.next(); + assertTrue(res == null); + } } diff --git a/src/test/java/com/esri/core/geometry/TestDifference.java b/src/test/java/com/esri/core/geometry/TestDifference.java index dd0e9225..2ea73ffc 100644 --- a/src/test/java/com/esri/core/geometry/TestDifference.java +++ b/src/test/java/com/esri/core/geometry/TestDifference.java @@ -1,5 +1,5 @@ /* - Copyright 1995-2017 Esri + Copyright 1995-2018 Esri Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -24,651 +24,661 @@ package com.esri.core.geometry; + import junit.framework.TestCase; + import org.junit.Test; public class TestDifference extends TestCase { - @Override - protected void setUp() throws Exception { - super.setUp(); - } - - @Override - protected void tearDown() throws Exception { - super.tearDown(); - } - - @Test - public static void testDifferenceAndSymmetricDifference() { - OperatorFactoryLocal engine = OperatorFactoryLocal.getInstance(); - OperatorDifference differenceOp = (OperatorDifference) engine - .getOperator(Operator.Type.Difference); - - SpatialReference spatialRef = SpatialReference.create(102113); - Polygon polygon1 = makePolygon1(); - Polygon polygon2 = makePolygon2(); - Polyline polyline1 = makePolyline1(); - MultiPoint multipoint1 = makeMultiPoint1(); - MultiPoint multipoint2 = makeMultiPoint2(); - MultiPoint multipoint3 = makeMultiPoint3(); - Point point1 = makePoint1(); - Point point2 = makePoint2(); - Envelope envelope1 = makeEnvelope1(); - Envelope envelope2 = makeEnvelope2(); - Envelope envelope3 = makeEnvelope3(); - - Polygon outputPolygon = (Polygon) differenceOp.execute(polygon1, - polygon2, spatialRef, null); - double area = outputPolygon.calculateArea2D(); - assertTrue(Math.abs(area - 75) <= 0.001); - - { - Point point_1 = new Point(-130, 10); - Point point_2 = new Point(-130, 10); - Geometry baseGeom = new Point(point_1.getX(), point_1.getY()); - Geometry comparisonGeom = new Point(point_2.getX(), point2.getY()); - SpatialReference sr = SpatialReference.create(4326); - @SuppressWarnings("unused") - Geometry geom = differenceOp.execute(baseGeom, comparisonGeom, sr, - null); - } - - OperatorSymmetricDifference symDifferenceOp = (OperatorSymmetricDifference) engine - .getOperator(Operator.Type.SymmetricDifference); - outputPolygon = (Polygon) symDifferenceOp.execute(polygon1, polygon2, - spatialRef, null); - - area = outputPolygon.calculateArea2D(); - assertTrue(Math.abs(area - 150) <= 0.001); - - Polyline outputPolyline = (Polyline) differenceOp.execute(polyline1, - polygon1, spatialRef, null); - double length = outputPolyline.calculateLength2D(); - assertTrue(Math.abs(length * length - 50) < 0.001); - - MultiPoint outputMultiPoint = (MultiPoint) differenceOp.execute( - multipoint1, polygon1, spatialRef, null); - int pointCount = outputMultiPoint.getPointCount(); - assertTrue(pointCount == 1); - - outputMultiPoint = (MultiPoint) (symDifferenceOp.execute(multipoint1, - point1, spatialRef, null)); - pointCount = outputMultiPoint.getPointCount(); - assertTrue(pointCount == 2); - - outputMultiPoint = (MultiPoint) (symDifferenceOp.execute(multipoint1, - point2, spatialRef, null)); - pointCount = outputMultiPoint.getPointCount(); - assertTrue(pointCount == 4); - - outputMultiPoint = (MultiPoint) (differenceOp.execute(multipoint1, - point1, spatialRef, null)); - pointCount = outputMultiPoint.getPointCount(); - assertTrue(pointCount == 2); - - outputMultiPoint = (MultiPoint) (differenceOp.execute(multipoint1, - point2, spatialRef, null)); - pointCount = outputMultiPoint.getPointCount(); - assertTrue(pointCount == 3); - - outputPolygon = (Polygon) (differenceOp.execute(polygon1, envelope1, - spatialRef, null)); - area = outputPolygon.calculateArea2D(); - assertTrue(Math.abs(area - 75) <= 0.001); - - outputPolygon = (Polygon) (differenceOp.execute(polygon2, envelope2, - spatialRef, null)); - area = outputPolygon.calculateArea2D(); - assertTrue(Math.abs(area - 75) <= 0.001); - - outputPolyline = (Polyline) (differenceOp.execute(polyline1, envelope2, - spatialRef, null)); - length = outputPolyline.calculateLength2D(); - assertTrue(Math.abs(length * length - 50) <= 0.001); - - outputMultiPoint = (MultiPoint) (differenceOp.execute(multipoint1, - envelope2, spatialRef, null)); - pointCount = outputMultiPoint.getPointCount(); - assertTrue(pointCount == 1); - - outputMultiPoint = (MultiPoint) (differenceOp.execute(multipoint2, - envelope2, spatialRef, null)); - pointCount = outputMultiPoint.getPointCount(); - assertTrue(pointCount == 6); - - outputMultiPoint = (MultiPoint) (differenceOp.execute(multipoint3, - envelope2, spatialRef, null)); - pointCount = outputMultiPoint.getPointCount(); - assertTrue(pointCount == 0); - - Point outputPoint = (Point) (differenceOp.execute(point1, envelope2, - spatialRef, null)); - assertTrue(!outputPoint.isEmpty()); - - outputPoint = (Point) (differenceOp.execute(point2, envelope2, - spatialRef, null)); - assertTrue(outputPoint.isEmpty()); - - outputPolygon = (Polygon) (differenceOp.execute(envelope3, envelope2, - spatialRef, null)); - assertTrue(outputPolygon != null && outputPolygon.isEmpty()); - - outputPolygon = (Polygon) (symDifferenceOp.execute(envelope3, - envelope3, spatialRef, null)); - assertTrue(outputPolygon != null && outputPolygon.isEmpty()); - - outputPoint = (Point) (differenceOp.execute(point1, polygon1, - spatialRef, null)); - assertTrue(outputPoint != null); - } - - @Test - public static void testPointTypes() { - OperatorFactoryLocal engine = OperatorFactoryLocal.getInstance(); - OperatorDifference difference = (OperatorDifference) engine - .getOperator(Operator.Type.Difference); - OperatorSymmetricDifference sym_difference = (OperatorSymmetricDifference) engine - .getOperator(Operator.Type.SymmetricDifference); - - {// point/point - Point point_1 = new Point(); - Point point_2 = new Point(); - point_1.setXY(0, 0); - point_2.setXY(0.0000000009, 0.0000000009); - Point differenced = (Point) (difference.execute(point_1, point_2, - SpatialReference.create(4326), null)); - assertTrue(differenced.isEmpty()); - - MultiPoint sym_differenced = (MultiPoint) (sym_difference.execute( - point_1, point_2, SpatialReference.create(4326), null)); - assertTrue(sym_differenced.isEmpty()); - } - - {// point/point - Point point_1 = new Point(); - Point point_2 = new Point(); - point_1.setXY(0, 0); - point_2.setXY(0.000000009, 0.0); - Point differenced = (Point) (difference.execute(point_1, point_2, - SpatialReference.create(4326), null)); - assertTrue(differenced.isEmpty()); - - MultiPoint sym_differenced = (MultiPoint) (sym_difference.execute( - point_1, point_2, SpatialReference.create(4326), null)); - assertTrue(sym_differenced.isEmpty()); - } - - {// point/point - Point point_1 = new Point(); - Point point_2 = new Point(); - point_1.setXY(0, 0); - point_2.setXY(0.00000002, 0.00000002); - Point differenced_1 = (Point) (difference.execute(point_1, point_2, - SpatialReference.create(4326), null)); - assertTrue(!differenced_1.isEmpty()); - - Point differenced_2 = (Point) (difference.execute(point_2, point_1, - SpatialReference.create(4326), null)); - assertTrue(!differenced_2.isEmpty()); - - MultiPoint sym_differenced = (MultiPoint) (sym_difference.execute( - point_1, point_2, SpatialReference.create(4326), null)); - assertTrue(!sym_differenced.isEmpty()); - assertTrue(sym_differenced.getXY(0).x == 0 - && sym_differenced.getXY(0).y == 0); - assertTrue(sym_differenced.getXY(1).x == 0.00000002 - && sym_differenced.getXY(1).y == 0.00000002); - } - - {// multi_point/point - MultiPoint multi_point_1 = new MultiPoint(); - Point point_2 = new Point(); - multi_point_1.add(0, 0); - multi_point_1.add(1, 1); - point_2.setXY(0.0000000009, 0.0000000009); - MultiPoint differenced_1 = (MultiPoint) (difference - .execute(multi_point_1, point_2, - SpatialReference.create(4326), null)); - assertTrue(!differenced_1.isEmpty()); - assertTrue(differenced_1.getPointCount() == 1); - assertTrue(differenced_1.getXY(0).x == 1 - && differenced_1.getXY(0).y == 1); - - Point differenced_2 = (Point) (difference.execute(point_2, - multi_point_1, SpatialReference.create(4326), null)); - assertTrue(differenced_2.isEmpty()); - } - - {// multi_point/point - MultiPoint multi_point_1 = new MultiPoint(); - Point point_2 = new Point(); - multi_point_1.add(0, 0); - multi_point_1.add(1, 1); - point_2.setXY(0.000000009, 0.0); - MultiPoint differenced_1 = (MultiPoint) (difference - .execute(multi_point_1, point_2, - SpatialReference.create(4326), null)); - assertTrue(!differenced_1.isEmpty()); - assertTrue(differenced_1.getXY(0).x == 1.0 - && differenced_1.getXY(0).y == 1.0); - - Point differenced_2 = (Point) (difference.execute(point_2, - multi_point_1, SpatialReference.create(4326), null)); - assertTrue(differenced_2.isEmpty()); - - MultiPoint sym_differenced = (MultiPoint) (sym_difference - .execute(multi_point_1, point_2, - SpatialReference.create(4326), null)); - assertTrue(!sym_differenced.isEmpty()); - assertTrue(sym_differenced.getPointCount() == 1); - assertTrue(sym_differenced.getXY(0).x == 1 - && sym_differenced.getXY(0).y == 1); - } - - {// multi_point/point - MultiPoint multi_point_1 = new MultiPoint(); - Point point_2 = new Point(); - multi_point_1.add(0, 0); - multi_point_1.add(0, 0); - point_2.setXY(0.000000009, 0.0); - MultiPoint differenced_1 = (MultiPoint) (difference - .execute(multi_point_1, point_2, - SpatialReference.create(4326), null)); - assertTrue(differenced_1.isEmpty()); - - MultiPoint sym_differenced = (MultiPoint) (sym_difference - .execute(multi_point_1, point_2, - SpatialReference.create(4326), null)); - assertTrue(sym_differenced.isEmpty()); - } - - {// multi_point/polygon - MultiPoint multi_point_1 = new MultiPoint(); - Polygon polygon_2 = new Polygon(); - multi_point_1.add(0, 0); - multi_point_1.add(0, 0); - multi_point_1.add(2, 2); - - polygon_2.startPath(-1, -1); - polygon_2.lineTo(-1, 1); - polygon_2.lineTo(1, 1); - polygon_2.lineTo(1, -1); - MultiPoint differenced_1 = (MultiPoint) (difference.execute( - multi_point_1, polygon_2, SpatialReference.create(4326), - null)); - assertTrue(!differenced_1.isEmpty()); - assertTrue(differenced_1.getPointCount() == 1); - assertTrue(differenced_1.getXY(0).x == 2 - && differenced_1.getXY(0).y == 2); - } - - {// multi_point/polygon - MultiPoint multi_point_1 = new MultiPoint(); - Polygon polygon_2 = new Polygon(); - multi_point_1.add(0, 0); - multi_point_1.add(0, 0); - multi_point_1.add(1, 1); - - polygon_2.startPath(-1, -1); - polygon_2.lineTo(-1, 1); - polygon_2.lineTo(1, 1); - polygon_2.lineTo(1, -1); - MultiPoint differenced_1 = (MultiPoint) (difference.execute( - multi_point_1, polygon_2, SpatialReference.create(4326), - null)); - assertTrue(differenced_1.isEmpty()); - } - - {// multi_point/envelope - MultiPoint multi_point_1 = new MultiPoint(); - Envelope envelope_2 = new Envelope(); - multi_point_1.add(-2, 0); - multi_point_1.add(0, 2); - multi_point_1.add(2, 0); - multi_point_1.add(0, -2); - - envelope_2.setCoords(-1, -1, 1, 1); - MultiPoint differenced_1 = (MultiPoint) (difference.execute( - multi_point_1, envelope_2, SpatialReference.create(4326), - null)); - assertTrue(!differenced_1.isEmpty() - && differenced_1 == multi_point_1); - } - - {// multi_point/polygon - MultiPoint multi_point_1 = new MultiPoint(); - Polygon polygon_2 = new Polygon(); - multi_point_1.add(2, 2); - multi_point_1.add(2, 2); - multi_point_1.add(-2, -2); - - polygon_2.startPath(-1, -1); - polygon_2.lineTo(-1, 1); - polygon_2.lineTo(1, 1); - polygon_2.lineTo(1, -1); - MultiPoint differenced_1 = (MultiPoint) (difference.execute( - multi_point_1, polygon_2, SpatialReference.create(4326), - null)); - assertTrue(!differenced_1.isEmpty() - && differenced_1 == multi_point_1); - } - - {// point/polygon - Point point_1 = new Point(); - Polygon polygon_2 = new Polygon(); - point_1.setXY(0, 0); - - polygon_2.startPath(-1, -1); - polygon_2.lineTo(-1, 1); - polygon_2.lineTo(1, 1); - polygon_2.lineTo(1, -1); - Point differenced_1 = (Point) (difference.execute(point_1, - polygon_2, SpatialReference.create(4326), null)); - assertTrue(differenced_1.isEmpty()); - - polygon_2.setEmpty(); - polygon_2.startPath(1, 1); - polygon_2.lineTo(1, 2); - polygon_2.lineTo(2, 2); - polygon_2.lineTo(2, 1); - differenced_1 = (Point) (difference.execute(point_1, polygon_2, - SpatialReference.create(4326), null)); - assertTrue(!differenced_1.isEmpty()); - assertTrue(differenced_1 == point_1); - } - - {// point/polygon - Point point_1 = new Point(); - Polygon polygon_2 = new Polygon(); - point_1.setXY(0, 0); - - polygon_2.startPath(1, 0); - polygon_2.lineTo(0, 1); - polygon_2.lineTo(1, 1); - Point differenced_1 = (Point) (difference.execute(point_1, - polygon_2, SpatialReference.create(4326), null)); - assertTrue(!differenced_1.isEmpty()); - assertTrue(differenced_1 == point_1); - - point_1.setEmpty(); - point_1.setXY(0.5, 0.5); - - polygon_2.setEmpty(); - polygon_2.startPath(1, 0); - polygon_2.lineTo(0, 1); - polygon_2.lineTo(1, 1); - differenced_1 = (Point) (difference.execute(point_1, polygon_2, - SpatialReference.create(4326), null)); - assertTrue(differenced_1.isEmpty()); - } - - {// point/envelope - Point point_1 = new Point(); - Envelope envelope_2 = new Envelope(); - point_1.setXY(0, 0); - - envelope_2.setCoords(-1, -1, 1, 1); - Point differenced_1 = (Point) (difference.execute(point_1, - envelope_2, SpatialReference.create(4326), null)); - assertTrue(differenced_1.isEmpty()); - - envelope_2.setEmpty(); - envelope_2.setCoords(1, 1, 2, 2); - differenced_1 = (Point) (difference.execute(point_1, envelope_2, - SpatialReference.create(4326), null)); - assertTrue(!differenced_1.isEmpty()); - assertTrue(differenced_1 == point_1); - } - - {// point/polyline - Point point_1 = new Point(); - Polyline polyline_2 = new Polyline(); - point_1.setXY(0, 0); - - polyline_2.startPath(-1, 0); - polyline_2.lineTo(1, 0); - Point differenced_1 = (Point) (difference.execute(point_1, - polyline_2, SpatialReference.create(4326), null)); - assertTrue(differenced_1.isEmpty()); - - polyline_2.setEmpty(); - polyline_2.startPath(1, 0); - polyline_2.lineTo(2, 0); - differenced_1 = (Point) (difference.execute(point_1, polyline_2, - SpatialReference.create(4326), null)); - assertTrue(!differenced_1.isEmpty()); - assertTrue(differenced_1 == point_1); - - polyline_2.setEmpty(); - polyline_2.startPath(-1, -1); - polyline_2.lineTo(-1, 1); - polyline_2.lineTo(1, 1); - polyline_2.lineTo(1, -1); - differenced_1 = (Point) (difference.execute(point_1, polyline_2, - SpatialReference.create(4326), null)); - assertTrue(!differenced_1.isEmpty()); - assertTrue(differenced_1 == point_1); - } - } - - @Test - public static void testDifferenceOnPolyline() { - // # * * # - // # * @ - // # @ * - // # * - // - // /////////////////////////////// - // - // The polyline drawn in *s represents basePl - // The polyline drawn in #s represents compPl - // The @ represents their intersection points, so that - // the difference polyline will be basePl with two new vertices @ added. - - Polyline basePl = new Polyline(); - basePl.startPath(new Point(-117, 20)); - basePl.lineTo(new Point(-130, 10)); - basePl.lineTo(new Point(-120, 50)); - - Polyline compPl = new Polyline(); - compPl.startPath(new Point(-116, 20)); - compPl.lineTo(new Point(-131, 10)); - compPl.lineTo(new Point(-121, 50)); - - Geometry diffGeom = GeometryEngine.difference(basePl, compPl, - SpatialReference.create(4326)); - assertTrue(diffGeom instanceof Polyline); - Polyline diffPolyline = (Polyline) diffGeom; - int pointCountDiffPolyline = diffPolyline.getPointCount(); - - // first line in comp_pl is 3y = 2x + 292 - assertEquals(3 * 20, 2 * (-116) + 292); - assertEquals(3 * 10, 2 * (-131) + 292); - - // new points should also lie on this line - assertTrue(3.0 * diffPolyline.getCoordinates2D()[1].y - 2.0 - * diffPolyline.getCoordinates2D()[1].x - 292.0 == 0.0); - assertTrue(3.0 * diffPolyline.getCoordinates2D()[3].y - 2.0 - * diffPolyline.getCoordinates2D()[3].x - 292.0 == 0.0); - - for (int i = 0; i < 3; i++) { - assertTrue(basePl.getCoordinates2D()[i].x == diffPolyline - .getCoordinates2D()[2 * i].x); - assertTrue(basePl.getCoordinates2D()[i].y == diffPolyline - .getCoordinates2D()[2 * i].y); - } - - assertEquals(5, pointCountDiffPolyline); - } - - public static Polygon makePolygon1() { - Polygon poly = new Polygon(); - poly.startPath(0, 0); - poly.lineTo(0, 10); - poly.lineTo(10, 10); - poly.lineTo(10, 0); - - return poly; - } - - public static Polygon makePolygon2() { - Polygon poly = new Polygon(); - - poly.startPath(5, 5); - poly.lineTo(5, 15); - poly.lineTo(15, 15); - poly.lineTo(15, 5); - - return poly; - } - - public static Polyline makePolyline1() { - Polyline poly = new Polyline(); - poly.startPath(0, 0); - poly.lineTo(15, 15); - - return poly; - } - - public static MultiPoint makeMultiPoint1() { - MultiPoint mpoint = new MultiPoint(); - Point2D pt1 = new Point2D(); - pt1.x = 1.0; - pt1.y = 1.0; - - Point2D pt2 = new Point2D(); - pt2.x = 5.0; - pt2.y = 5.0; - - Point2D pt3 = new Point2D(); - pt3.x = 15.0; - pt3.y = 15.0; - - mpoint.add(pt1.x, pt1.y); - mpoint.add(pt2.x, pt2.y); - mpoint.add(pt3.x, pt3.y); - - return mpoint; - } - - public static MultiPoint makeMultiPoint2() { - MultiPoint mpoint = new MultiPoint(); - Point2D pt1 = new Point2D(); - pt1.x = 1.0; - pt1.y = 1.0; - - Point2D pt2 = new Point2D(); - pt2.x = 1.0; - pt2.y = 1.0; - - Point2D pt3 = new Point2D(); - pt3.x = 15.0; - pt3.y = 15.0; - - Point2D pt4 = new Point2D(); - pt4.x = 15.0; - pt4.y = 15.0; - - Point2D pt5 = new Point2D(); - pt5.x = 1.0; - pt5.y = 1.0; - - Point2D pt6 = new Point2D(); - pt6.x = 1.0; - pt6.y = 1.0; - - Point2D pt7 = new Point2D(); - pt7.x = 15.0; - pt7.y = 15.0; - - Point2D pt8 = new Point2D(); - pt8.x = 15.0; - pt8.y = 15.0; - - Point2D pt9 = new Point2D(); - pt9.x = 15.0; - pt9.y = 15.0; - - Point2D pt10 = new Point2D(); - pt10.x = 1.0; - pt10.y = 1.0; - - Point2D pt11 = new Point2D(); - pt11.x = 15.0; - pt11.y = 15.0; - - mpoint.add(pt1.x, pt1.y); - mpoint.add(pt2.x, pt2.y); - mpoint.add(pt3.x, pt3.y); - mpoint.add(pt4.x, pt4.y); - mpoint.add(pt5.x, pt5.y); - mpoint.add(pt6.x, pt6.y); - mpoint.add(pt7.x, pt7.y); - mpoint.add(pt8.x, pt8.y); - mpoint.add(pt9.x, pt9.y); - mpoint.add(pt10.x, pt10.y); - mpoint.add(pt11.x, pt11.y); - - return mpoint; - } - - public static MultiPoint makeMultiPoint3() { - MultiPoint mpoint = new MultiPoint(); - Point2D pt1 = new Point2D(); - pt1.x = 1.0; - pt1.y = 1.0; - - Point2D pt2 = new Point2D(); - pt2.x = 5.0; - pt2.y = 5.0; - - mpoint.add(pt1.x, pt1.y); - mpoint.add(pt2.x, pt2.y); - - return mpoint; - } - - public static Point makePoint1() { - Point point = new Point(); - - Point2D pt = new Point2D(); - pt.setCoords(15, 15); - point.setXY(pt); - - return point; - } - - public static Point makePoint2() { - Point point = new Point(); - - Point2D pt = new Point2D(); - pt.setCoords(7, 7); - point.setXY(pt); - - return point; - } - - public static Envelope makeEnvelope1() { - Envelope2D env = new Envelope2D(); - env.setCoords(5, 5, 15, 15); - Envelope envelope = new Envelope(env); - - return envelope; - } - - public static Envelope makeEnvelope2() { - Envelope2D env = new Envelope2D(); - env.setCoords(0, 0, 10, 10); - Envelope envelope = new Envelope(env); + @Override + protected void setUp() throws Exception { + super.setUp(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + } + + @Test + public static void testDifferenceAndSymmetricDifference() { + OperatorFactoryLocal engine = OperatorFactoryLocal.getInstance(); + OperatorDifference differenceOp = (OperatorDifference) engine + .getOperator(Operator.Type.Difference); + + SpatialReference spatialRef = SpatialReference.create(102113); + Polygon polygon1 = makePolygon1(); + Polygon polygon2 = makePolygon2(); + Polyline polyline1 = makePolyline1(); + MultiPoint multipoint1 = makeMultiPoint1(); + MultiPoint multipoint2 = makeMultiPoint2(); + MultiPoint multipoint3 = makeMultiPoint3(); + Point point1 = makePoint1(); + Point point2 = makePoint2(); + Envelope envelope1 = makeEnvelope1(); + Envelope envelope2 = makeEnvelope2(); + Envelope envelope3 = makeEnvelope3(); + + Polygon outputPolygon = (Polygon) differenceOp.execute(polygon1, + polygon2, spatialRef, null); + double area = outputPolygon.calculateArea2D(); + assertTrue(Math.abs(area - 75) <= 0.001); + + { + Point point_1 = new Point(-130, 10); + Point point_2 = new Point(-130, 10); + Geometry baseGeom = new Point(point_1.getX(), point_1.getY()); + Geometry comparisonGeom = new Point(point_2.getX(), point2.getY()); + SpatialReference sr = SpatialReference.create(4326); + @SuppressWarnings("unused") + Geometry geom = differenceOp.execute(baseGeom, comparisonGeom, sr, + null); + } + + OperatorSymmetricDifference symDifferenceOp = (OperatorSymmetricDifference) engine + .getOperator(Operator.Type.SymmetricDifference); + outputPolygon = (Polygon) symDifferenceOp.execute(polygon1, polygon2, + spatialRef, null); + + area = outputPolygon.calculateArea2D(); + assertTrue(Math.abs(area - 150) <= 0.001); + + Polyline outputPolyline = (Polyline) differenceOp.execute(polyline1, + polygon1, spatialRef, null); + double length = outputPolyline.calculateLength2D(); + assertTrue(Math.abs(length * length - 50) < 0.001); + + MultiPoint outputMultiPoint = (MultiPoint) differenceOp.execute( + multipoint1, polygon1, spatialRef, null); + int pointCount = outputMultiPoint.getPointCount(); + assertTrue(pointCount == 1); + + outputMultiPoint = (MultiPoint) (symDifferenceOp.execute(multipoint1, + point1, spatialRef, null)); + pointCount = outputMultiPoint.getPointCount(); + assertTrue(pointCount == 2); + + outputMultiPoint = (MultiPoint) (symDifferenceOp.execute(multipoint1, + point2, spatialRef, null)); + pointCount = outputMultiPoint.getPointCount(); + assertTrue(pointCount == 4); + + outputMultiPoint = (MultiPoint) (differenceOp.execute(multipoint1, + point1, spatialRef, null)); + pointCount = outputMultiPoint.getPointCount(); + assertTrue(pointCount == 2); + + outputMultiPoint = (MultiPoint) (differenceOp.execute(multipoint1, + point2, spatialRef, null)); + pointCount = outputMultiPoint.getPointCount(); + assertTrue(pointCount == 3); + + outputPolygon = (Polygon) (differenceOp.execute(polygon1, envelope1, + spatialRef, null)); + area = outputPolygon.calculateArea2D(); + assertTrue(Math.abs(area - 75) <= 0.001); + + outputPolygon = (Polygon) (differenceOp.execute(polygon2, envelope2, + spatialRef, null)); + area = outputPolygon.calculateArea2D(); + assertTrue(Math.abs(area - 75) <= 0.001); + + outputPolyline = (Polyline) (differenceOp.execute(polyline1, envelope2, + spatialRef, null)); + length = outputPolyline.calculateLength2D(); + assertTrue(Math.abs(length * length - 50) <= 0.001); + + outputMultiPoint = (MultiPoint) (differenceOp.execute(multipoint1, + envelope2, spatialRef, null)); + pointCount = outputMultiPoint.getPointCount(); + assertTrue(pointCount == 1); + + outputMultiPoint = (MultiPoint) (differenceOp.execute(multipoint2, + envelope2, spatialRef, null)); + pointCount = outputMultiPoint.getPointCount(); + assertTrue(pointCount == 6); + + outputMultiPoint = (MultiPoint) (differenceOp.execute(multipoint3, + envelope2, spatialRef, null)); + pointCount = outputMultiPoint.getPointCount(); + assertTrue(pointCount == 0); + + Point outputPoint = (Point) (differenceOp.execute(point1, envelope2, + spatialRef, null)); + assertTrue(!outputPoint.isEmpty()); + + outputPoint = (Point) (differenceOp.execute(point2, envelope2, + spatialRef, null)); + assertTrue(outputPoint.isEmpty()); + + outputPolygon = (Polygon) (differenceOp.execute(envelope3, envelope2, + spatialRef, null)); + assertTrue(outputPolygon != null && outputPolygon.isEmpty()); + + outputPolygon = (Polygon) (symDifferenceOp.execute(envelope3, + envelope3, spatialRef, null)); + assertTrue(outputPolygon != null && outputPolygon.isEmpty()); + + outputPoint = (Point) (differenceOp.execute(point1, polygon1, + spatialRef, null)); + assertTrue(outputPoint != null); + } + + @Test + public static void testPointTypes() { + OperatorFactoryLocal engine = OperatorFactoryLocal.getInstance(); + OperatorDifference difference = (OperatorDifference) engine + .getOperator(Operator.Type.Difference); + OperatorSymmetricDifference sym_difference = (OperatorSymmetricDifference) engine + .getOperator(Operator.Type.SymmetricDifference); + + {// point/point + Point point_1 = new Point(); + Point point_2 = new Point(); + point_1.setXY(0, 0); + point_2.setXY(0.000000009, 0.000000009); + Point differenced = (Point) (difference.execute(point_1, point_2, + SpatialReference.create(4326), null)); + assertTrue(differenced.isEmpty()); + + MultiPoint sym_differenced = (MultiPoint) (sym_difference.execute( + point_1, point_2, SpatialReference.create(4326), null)); + assertTrue(sym_differenced.isEmpty()); + } + + {// point/point + Point point_1 = new Point(); + Point point_2 = new Point(); + point_1.setXY(0, 0); + point_2.setXY(0.000000009, 0.0); + Point differenced = (Point) (difference.execute(point_1, point_2, + SpatialReference.create(4326), null)); + assertTrue(differenced.isEmpty()); + + MultiPoint sym_differenced = (MultiPoint) (sym_difference.execute( + point_1, point_2, SpatialReference.create(4326), null)); + assertTrue(sym_differenced.isEmpty()); + } + + {// point/point + Point point_1 = new Point(); + Point point_2 = new Point(); + point_1.setXY(0, 0); + point_2.setXY(0.00000002, 0.00000002); + Point differenced_1 = (Point) (difference.execute(point_1, point_2, + SpatialReference.create(4326), null)); + assertTrue(!differenced_1.isEmpty()); + + Point differenced_2 = (Point) (difference.execute(point_2, point_1, + SpatialReference.create(4326), null)); + assertTrue(!differenced_2.isEmpty()); + + MultiPoint sym_differenced = (MultiPoint) (sym_difference.execute( + point_1, point_2, SpatialReference.create(4326), null)); + assertTrue(!sym_differenced.isEmpty()); + assertTrue(sym_differenced.getXY(0).x == 0 + && sym_differenced.getXY(0).y == 0); + assertTrue(sym_differenced.getXY(1).x == 0.00000002 + && sym_differenced.getXY(1).y == 0.00000002); + } + + {// multi_point/point + MultiPoint multi_point_1 = new MultiPoint(); + Point point_2 = new Point(); + multi_point_1.add(0, 0); + multi_point_1.add(1, 1); + point_2.setXY(0.000000009, 0.000000009); + MultiPoint differenced_1 = (MultiPoint) (difference + .execute(multi_point_1, point_2, + SpatialReference.create(4326), null)); + assertTrue(!differenced_1.isEmpty()); + assertTrue(differenced_1.getPointCount() == 1); + assertTrue(differenced_1.getXY(0).x == 1 + && differenced_1.getXY(0).y == 1); + + Point differenced_2 = (Point) (difference.execute(point_2, + multi_point_1, SpatialReference.create(4326), null)); + assertTrue(differenced_2.isEmpty()); + } + + {// multi_point/point + MultiPoint multi_point_1 = new MultiPoint(); + Point point_2 = new Point(); + multi_point_1.add(0, 0); + multi_point_1.add(1, 1); + point_2.setXY(0.000000009, 0.0); + MultiPoint differenced_1 = (MultiPoint) (difference + .execute(multi_point_1, point_2, + SpatialReference.create(4326), null)); + assertTrue(!differenced_1.isEmpty()); + assertTrue(differenced_1.getXY(0).x == 1.0 + && differenced_1.getXY(0).y == 1.0); + + Point differenced_2 = (Point) (difference.execute(point_2, + multi_point_1, SpatialReference.create(4326), null)); + assertTrue(differenced_2.isEmpty()); + + MultiPoint sym_differenced = (MultiPoint) (sym_difference + .execute(multi_point_1, point_2, + SpatialReference.create(4326), null)); + assertTrue(!sym_differenced.isEmpty()); + assertTrue(sym_differenced.getPointCount() == 1); + assertTrue(sym_differenced.getXY(0).x == 1 + && sym_differenced.getXY(0).y == 1); + } + + {// multi_point/point + MultiPoint multi_point_1 = new MultiPoint(); + Point point_2 = new Point(); + multi_point_1.add(0, 0); + multi_point_1.add(0, 0); + point_2.setXY(0.000000009, 0.0); + MultiPoint differenced_1 = (MultiPoint) (difference + .execute(multi_point_1, point_2, + SpatialReference.create(4326), null)); + assertTrue(differenced_1.isEmpty()); + + MultiPoint sym_differenced = (MultiPoint) (sym_difference + .execute(multi_point_1, point_2, + SpatialReference.create(4326), null)); + assertTrue(sym_differenced.isEmpty()); + } + + {// multi_point/polygon + MultiPoint multi_point_1 = new MultiPoint(); + Polygon polygon_2 = new Polygon(); + multi_point_1.add(0, 0); + multi_point_1.add(0, 0); + multi_point_1.add(2, 2); + + polygon_2.startPath(-1, -1); + polygon_2.lineTo(-1, 1); + polygon_2.lineTo(1, 1); + polygon_2.lineTo(1, -1); + MultiPoint differenced_1 = (MultiPoint) (difference.execute( + multi_point_1, polygon_2, SpatialReference.create(4326), + null)); + assertTrue(!differenced_1.isEmpty()); + assertTrue(differenced_1.getPointCount() == 1); + assertTrue(differenced_1.getXY(0).x == 2 + && differenced_1.getXY(0).y == 2); + } + + {// multi_point/polygon + MultiPoint multi_point_1 = new MultiPoint(); + Polygon polygon_2 = new Polygon(); + multi_point_1.add(0, 0); + multi_point_1.add(0, 0); + multi_point_1.add(1, 1); + + polygon_2.startPath(-1, -1); + polygon_2.lineTo(-1, 1); + polygon_2.lineTo(1, 1); + polygon_2.lineTo(1, -1); + MultiPoint differenced_1 = (MultiPoint) (difference.execute( + multi_point_1, polygon_2, SpatialReference.create(4326), + null)); + assertTrue(differenced_1.isEmpty()); + } + + {// multi_point/envelope + MultiPoint multi_point_1 = new MultiPoint(); + Envelope envelope_2 = new Envelope(); + multi_point_1.add(-2, 0); + multi_point_1.add(0, 2); + multi_point_1.add(2, 0); + multi_point_1.add(0, -2); + + envelope_2.setCoords(-1, -1, 1, 1); + MultiPoint differenced_1 = (MultiPoint) (difference.execute( + multi_point_1, envelope_2, SpatialReference.create(4326), + null)); + assertTrue(!differenced_1.isEmpty() + && differenced_1 == multi_point_1); + } + + {// multi_point/polygon + MultiPoint multi_point_1 = new MultiPoint(); + Polygon polygon_2 = new Polygon(); + multi_point_1.add(2, 2); + multi_point_1.add(2, 2); + multi_point_1.add(-2, -2); + + polygon_2.startPath(-1, -1); + polygon_2.lineTo(-1, 1); + polygon_2.lineTo(1, 1); + polygon_2.lineTo(1, -1); + MultiPoint differenced_1 = (MultiPoint) (difference.execute( + multi_point_1, polygon_2, SpatialReference.create(4326), + null)); + assertTrue(!differenced_1.isEmpty() + && differenced_1 == multi_point_1); + } + + {// point/polygon + Point point_1 = new Point(); + Polygon polygon_2 = new Polygon(); + point_1.setXY(0, 0); + + polygon_2.startPath(-1, -1); + polygon_2.lineTo(-1, 1); + polygon_2.lineTo(1, 1); + polygon_2.lineTo(1, -1); + Point differenced_1 = (Point) (difference.execute(point_1, + polygon_2, SpatialReference.create(4326), null)); + assertTrue(differenced_1.isEmpty()); + + polygon_2.setEmpty(); + polygon_2.startPath(1, 1); + polygon_2.lineTo(1, 2); + polygon_2.lineTo(2, 2); + polygon_2.lineTo(2, 1); + differenced_1 = (Point) (difference.execute(point_1, polygon_2, + SpatialReference.create(4326), null)); + assertTrue(!differenced_1.isEmpty()); + assertTrue(differenced_1 == point_1); + } + + {// point/polygon + Point point_1 = new Point(); + Polygon polygon_2 = new Polygon(); + point_1.setXY(0, 0); + + polygon_2.startPath(1, 0); + polygon_2.lineTo(0, 1); + polygon_2.lineTo(1, 1); + Point differenced_1 = (Point) (difference.execute(point_1, + polygon_2, SpatialReference.create(4326), null)); + assertTrue(!differenced_1.isEmpty()); + assertTrue(differenced_1 == point_1); + + point_1.setEmpty(); + point_1.setXY(0.5, 0.5); + + polygon_2.setEmpty(); + polygon_2.startPath(1, 0); + polygon_2.lineTo(0, 1); + polygon_2.lineTo(1, 1); + differenced_1 = (Point) (difference.execute(point_1, polygon_2, + SpatialReference.create(4326), null)); + assertTrue(differenced_1.isEmpty()); + } + + {// point/envelope + Point point_1 = new Point(); + Envelope envelope_2 = new Envelope(); + point_1.setXY(0, 0); + + envelope_2.setCoords(-1, -1, 1, 1); + Point differenced_1 = (Point) (difference.execute(point_1, + envelope_2, SpatialReference.create(4326), null)); + assertTrue(differenced_1.isEmpty()); + + envelope_2.setEmpty(); + envelope_2.setCoords(1, 1, 2, 2); + differenced_1 = (Point) (difference.execute(point_1, envelope_2, + SpatialReference.create(4326), null)); + assertTrue(!differenced_1.isEmpty()); + assertTrue(differenced_1 == point_1); + } + + {// point/polyline + Point point_1 = new Point(); + Polyline polyline_2 = new Polyline(); + point_1.setXY(0, 0); + + polyline_2.startPath(-1, 0); + polyline_2.lineTo(1, 0); + Point differenced_1 = (Point) (difference.execute(point_1, + polyline_2, SpatialReference.create(4326), null)); + assertTrue(differenced_1.isEmpty()); + + polyline_2.setEmpty(); + polyline_2.startPath(1, 0); + polyline_2.lineTo(2, 0); + differenced_1 = (Point) (difference.execute(point_1, polyline_2, + SpatialReference.create(4326), null)); + assertTrue(!differenced_1.isEmpty()); + assertTrue(differenced_1 == point_1); + + polyline_2.setEmpty(); + polyline_2.startPath(-1, -1); + polyline_2.lineTo(-1, 1); + polyline_2.lineTo(1, 1); + polyline_2.lineTo(1, -1); + differenced_1 = (Point) (difference.execute(point_1, polyline_2, + SpatialReference.create(4326), null)); + assertTrue(!differenced_1.isEmpty()); + assertTrue(differenced_1 == point_1); + } + } + + @Test + public static void testDifferenceOnPolyline() { + // # * * # + // # * @ + // # @ * + // # * + // + // /////////////////////////////// + // + // The polyline drawn in *s represents basePl + // The polyline drawn in #s represents compPl + // The @ represents their intersection points, so that + // the difference polyline will be basePl with two new vertices @ added. + + Polyline basePl = new Polyline(); + basePl.startPath(new Point(-117, 20)); + basePl.lineTo(new Point(-130, 10)); + basePl.lineTo(new Point(-120, 50)); + + Polyline compPl = new Polyline(); + compPl.startPath(new Point(-116, 20)); + compPl.lineTo(new Point(-131, 10)); + compPl.lineTo(new Point(-121, 50)); + + Geometry diffGeom = GeometryEngine.difference(basePl, compPl, + SpatialReference.create(4326)); + assertTrue(diffGeom instanceof Polyline); + Polyline diffPolyline = (Polyline) diffGeom; + int pointCountDiffPolyline = diffPolyline.getPointCount(); + + // first line in comp_pl is 3y = 2x + 292 + assertEquals(3 * 20, 2 * (-116) + 292); + assertEquals(3 * 10, 2 * (-131) + 292); + + // new points should also lie on this line + assertTrue(3.0 * diffPolyline.getCoordinates2D()[1].y - 2.0 + * diffPolyline.getCoordinates2D()[1].x - 292.0 == 0.0); + assertTrue(3.0 * diffPolyline.getCoordinates2D()[3].y - 2.0 + * diffPolyline.getCoordinates2D()[3].x - 292.0 == 0.0); + + for (int i = 0; i < 3; i++) { + assertTrue(basePl.getCoordinates2D()[i].x == diffPolyline + .getCoordinates2D()[2 * i].x); + assertTrue(basePl.getCoordinates2D()[i].y == diffPolyline + .getCoordinates2D()[2 * i].y); + } + + assertEquals(5, pointCountDiffPolyline); + } + + @Test + public static void testDifferencePolylineAlongPolygonBoundary() { + Polyline polyline = (Polyline)GeometryEngine.geometryFromWkt("LINESTRING(0 0, 0 5, -2 5)", 0, Geometry.Type.Unknown); + Polygon polygon = (Polygon)GeometryEngine.geometryFromWkt("POLYGON((0 0, 5 0, 5 5, 0 5, 0 0))", 0, Geometry.Type.Unknown); + Geometry result = OperatorDifference.local().execute(polyline, polygon, null, null); + assertEquals(GeometryEngine.geometryToJson(null, result), "{\"paths\":[[[0,5],[-2,5]]]}"); + } + + public static Polygon makePolygon1() { + Polygon poly = new Polygon(); + poly.startPath(0, 0); + poly.lineTo(0, 10); + poly.lineTo(10, 10); + poly.lineTo(10, 0); + + return poly; + } + + public static Polygon makePolygon2() { + Polygon poly = new Polygon(); + + poly.startPath(5, 5); + poly.lineTo(5, 15); + poly.lineTo(15, 15); + poly.lineTo(15, 5); + + return poly; + } + + public static Polyline makePolyline1() { + Polyline poly = new Polyline(); + poly.startPath(0, 0); + poly.lineTo(15, 15); + + return poly; + } + + public static MultiPoint makeMultiPoint1() { + MultiPoint mpoint = new MultiPoint(); + Point2D pt1 = new Point2D(); + pt1.x = 1.0; + pt1.y = 1.0; + + Point2D pt2 = new Point2D(); + pt2.x = 5.0; + pt2.y = 5.0; + + Point2D pt3 = new Point2D(); + pt3.x = 15.0; + pt3.y = 15.0; + + mpoint.add(pt1.x, pt1.y); + mpoint.add(pt2.x, pt2.y); + mpoint.add(pt3.x, pt3.y); + + return mpoint; + } + + public static MultiPoint makeMultiPoint2() { + MultiPoint mpoint = new MultiPoint(); + Point2D pt1 = new Point2D(); + pt1.x = 1.0; + pt1.y = 1.0; + + Point2D pt2 = new Point2D(); + pt2.x = 1.0; + pt2.y = 1.0; + + Point2D pt3 = new Point2D(); + pt3.x = 15.0; + pt3.y = 15.0; + + Point2D pt4 = new Point2D(); + pt4.x = 15.0; + pt4.y = 15.0; + + Point2D pt5 = new Point2D(); + pt5.x = 1.0; + pt5.y = 1.0; + + Point2D pt6 = new Point2D(); + pt6.x = 1.0; + pt6.y = 1.0; + + Point2D pt7 = new Point2D(); + pt7.x = 15.0; + pt7.y = 15.0; + + Point2D pt8 = new Point2D(); + pt8.x = 15.0; + pt8.y = 15.0; + + Point2D pt9 = new Point2D(); + pt9.x = 15.0; + pt9.y = 15.0; + + Point2D pt10 = new Point2D(); + pt10.x = 1.0; + pt10.y = 1.0; + + Point2D pt11 = new Point2D(); + pt11.x = 15.0; + pt11.y = 15.0; + + mpoint.add(pt1.x, pt1.y); + mpoint.add(pt2.x, pt2.y); + mpoint.add(pt3.x, pt3.y); + mpoint.add(pt4.x, pt4.y); + mpoint.add(pt5.x, pt5.y); + mpoint.add(pt6.x, pt6.y); + mpoint.add(pt7.x, pt7.y); + mpoint.add(pt8.x, pt8.y); + mpoint.add(pt9.x, pt9.y); + mpoint.add(pt10.x, pt10.y); + mpoint.add(pt11.x, pt11.y); + + return mpoint; + } + + public static MultiPoint makeMultiPoint3() { + MultiPoint mpoint = new MultiPoint(); + Point2D pt1 = new Point2D(); + pt1.x = 1.0; + pt1.y = 1.0; + + Point2D pt2 = new Point2D(); + pt2.x = 5.0; + pt2.y = 5.0; + + mpoint.add(pt1.x, pt1.y); + mpoint.add(pt2.x, pt2.y); + + return mpoint; + } + + public static Point makePoint1() { + Point point = new Point(); + + Point2D pt = new Point2D(); + pt.setCoords(15, 15); + point.setXY(pt); + + return point; + } + + public static Point makePoint2() { + Point point = new Point(); + + Point2D pt = new Point2D(); + pt.setCoords(7, 7); + point.setXY(pt); + + return point; + } + + public static Envelope makeEnvelope1() { + Envelope2D env = new Envelope2D(); + env.setCoords(5, 5, 15, 15); + Envelope envelope = new Envelope(env); + + return envelope; + } + + public static Envelope makeEnvelope2() { + Envelope2D env = new Envelope2D(); + env.setCoords(0, 0, 10, 10); + Envelope envelope = new Envelope(env); - return envelope; - } - - public static Envelope makeEnvelope3() { - Envelope2D env = new Envelope2D(); - env.setCoords(5, 5, 6, 6); - Envelope envelope = new Envelope(env); + return envelope; + } + + public static Envelope makeEnvelope3() { + Envelope2D env = new Envelope2D(); + env.setCoords(5, 5, 6, 6); + Envelope envelope = new Envelope(env); - return envelope; - } + return envelope; + } } diff --git a/src/test/java/com/esri/core/geometry/TestDistance.java b/src/test/java/com/esri/core/geometry/TestDistance.java index 9d47f276..50399967 100644 --- a/src/test/java/com/esri/core/geometry/TestDistance.java +++ b/src/test/java/com/esri/core/geometry/TestDistance.java @@ -28,155 +28,153 @@ import org.junit.Test; public class TestDistance extends TestCase { - @Override - protected void setUp() throws Exception { - super.setUp(); - } + @Override + protected void setUp() throws Exception { + super.setUp(); + } - @Override - protected void tearDown() throws Exception { - super.tearDown(); - } + @Override + protected void tearDown() throws Exception { + super.tearDown(); + } - @Test - public static void testDistanceBetweenVariousGeometries() { - Polygon polygon = makePolygon(); - Polyline polyline = makePolyline(); - MultiPoint multipoint = makeMultiPoint(); - Point point = makePoint(); - // SpatialReference spatialRef = - // SpatialReference.create(3857);//PCS_WGS_1984_WEB_MERCATOR_AUXSPHERE + @Test + public static void testDistanceBetweenVariousGeometries() { + Polygon polygon = makePolygon(); + Polyline polyline = makePolyline(); + MultiPoint multipoint = makeMultiPoint(); + Point point = makePoint(); + // SpatialReference spatialRef = + // SpatialReference.create(3857);//PCS_WGS_1984_WEB_MERCATOR_AUXSPHERE - double distance; + double distance; - distance = GeometryEngine.distance(polygon, polyline, null); - assertTrue(Math.abs(distance - 5.0) < 0.00001); + distance = GeometryEngine.distance(polygon, polyline, null); + assertTrue(Math.abs(distance - 5.0) < 0.00001); - distance = GeometryEngine.distance(polygon, multipoint, null); - assertTrue(Math.abs(distance - 5.0) < 0.00001); + distance = GeometryEngine.distance(polygon, multipoint, null); + assertTrue(Math.abs(distance - 5.0) < 0.00001); - distance = GeometryEngine.distance(polygon, point, null); - assertTrue(Math.abs(distance - 5.0) < 0.00001); - } + distance = GeometryEngine.distance(polygon, point, null); + assertTrue(Math.abs(distance - 5.0) < 0.00001); + } - @Test - public static void testDistanceBetweenTriangles() { - double distance; + @Test + public static void testDistanceBetweenTriangles() { + double distance; - Polygon poly = new Polygon(); - Polygon poly2 = new Polygon(); + Polygon poly = new Polygon(); + Polygon poly2 = new Polygon(); - poly.startPath(0.0, 0.0); - poly.lineTo(1.0, 2.0); - poly.lineTo(0.0, 2.0); + poly.startPath(0.0, 0.0); + poly.lineTo(1.0, 2.0); + poly.lineTo(0.0, 2.0); - double xSeparation = 0.1; - double ySeparation = 0.1; + double xSeparation = 0.1; + double ySeparation = 0.1; - poly2.startPath(xSeparation + 1.0, 2.0 - ySeparation); - poly2.lineTo(xSeparation + 2.0, 2.0 - ySeparation); - poly2.lineTo(xSeparation + 2.0, 4.0 - ySeparation); + poly2.startPath(xSeparation + 1.0, 2.0 - ySeparation); + poly2.lineTo(xSeparation + 2.0, 2.0 - ySeparation); + poly2.lineTo(xSeparation + 2.0, 4.0 - ySeparation); - distance = GeometryEngine.distance(poly, poly2, null); + distance = GeometryEngine.distance(poly, poly2, null); - assertTrue(0.0 < distance && distance < xSeparation + ySeparation); - } + assertTrue(0.0 < distance && distance < xSeparation + ySeparation); + } - @Test - public static void testDistanceBetweenPointAndEnvelope() { - Envelope env = new Envelope(23, 23, 23, 23); + @Test + public static void testDistanceBetweenPointAndEnvelope() { + Envelope env = new Envelope(23,23, 23,23); Point pt = new Point(30, 30); double dist = GeometryEngine.distance(env, pt, null); // expect just under 10. - assertTrue(Math.abs(dist - 9.8994949) < 0.0001); - } - - @Test - public static void testDistanceBetweenHugeGeometries() { - /* const */ - int N = 1000; // Should be even - /* const */ - double theoreticalDistance = 0.77; - - Polygon poly = new Polygon(); - Polygon poly2 = new Polygon(); - - double theta = 0.0; - double thetaPlusPi = Math.PI; - double dTheta = 2.0 * Math.PI / N; - double distance; - - poly.startPath(Math.cos(theta), Math.sin(theta)); - // Add something so that poly2's bounding box is in poly's. Deleting - // this should not affect answer. - poly.lineTo(1.0, 1.5 + theoreticalDistance); - poly.lineTo(3.5 + theoreticalDistance, 1.5 + theoreticalDistance); - poly.lineTo(3.5 + theoreticalDistance, 2.0 + theoreticalDistance); - poly.lineTo(0.95, 2.0 + theoreticalDistance); - // /////////////////////////////////////////////////////////// - poly2.startPath(2.0 + theoreticalDistance + Math.cos(thetaPlusPi), - Math.sin(thetaPlusPi)); - for (double i = 1; i < N; i++) { - theta += dTheta; - thetaPlusPi += dTheta; - poly.lineTo(Math.cos(theta), Math.sin(theta)); - poly2.lineTo(2.0 + theoreticalDistance + Math.cos(thetaPlusPi), - Math.sin(thetaPlusPi)); - } - - distance = GeometryEngine.distance(poly, poly2, null); - - assertTrue(Math.abs(distance - theoreticalDistance) < 1.0e-10); - } - - private static Polygon makePolygon() { - Polygon poly = new Polygon(); - - poly.startPath(0, 0); - poly.lineTo(0, 10); - poly.lineTo(10, 10); - poly.lineTo(10, 0); - - poly.startPath(3, 3); - poly.lineTo(7, 3); - poly.lineTo(7, 7); - poly.lineTo(3, 7); - - return poly; - } - - private static Polyline makePolyline() { - Polyline poly = new Polyline(); - poly.startPath(0, 15); - poly.lineTo(15, 15); - return poly; - } - - private static MultiPoint makeMultiPoint() { - MultiPoint mpoint = new MultiPoint(); - mpoint.add(0, 30); - mpoint.add(15, 15); - mpoint.add(0, 15); - return mpoint; - } - - private static Point makePoint() { - Point point = new Point(); - Point2D pt = new Point2D(); - pt.setCoords(0, 15); - point.setXY(pt); - return point; - } - - @Test - public static void testDistanceWithNullSpatialReference() { - // There was a bug that distance op did not work with null Spatial - // Reference. - String str1 = "{\"paths\":[[[-117.138791850991,34.017492675023],[-117.138762336971,34.0174925550462]]]}"; - String str2 = "{\"paths\":[[[-117.138867827972,34.0174854109623],[-117.138850197027,34.0174929160126],[-117.138791850991,34.017492675023]]]}"; - MapGeometry geom1 = GeometryEngine.jsonToGeometry(JsonParserReader.createFromString(str1)); - MapGeometry geom2 = GeometryEngine.jsonToGeometry(JsonParserReader.createFromString(str2)); - double distance = GeometryEngine.distance(geom1.getGeometry(), - geom2.getGeometry(), null); - assertTrue(distance == 0); - } + assertTrue(Math.abs(dist - 9.8994949) < 0.0001); + } + + @Test + public static void testDistanceBetweenHugeGeometries() { + /* const */int N = 1000; // Should be even + /* const */double theoreticalDistance = 0.77; + + Polygon poly = new Polygon(); + Polygon poly2 = new Polygon(); + + double theta = 0.0; + double thetaPlusPi = Math.PI; + double dTheta = 2.0 * Math.PI / N; + double distance; + + poly.startPath(Math.cos(theta), Math.sin(theta)); + // Add something so that poly2's bounding box is in poly's. Deleting + // this should not affect answer. + poly.lineTo(1.0, 1.5 + theoreticalDistance); + poly.lineTo(3.5 + theoreticalDistance, 1.5 + theoreticalDistance); + poly.lineTo(3.5 + theoreticalDistance, 2.0 + theoreticalDistance); + poly.lineTo(0.95, 2.0 + theoreticalDistance); + // /////////////////////////////////////////////////////////// + poly2.startPath(2.0 + theoreticalDistance + Math.cos(thetaPlusPi), + Math.sin(thetaPlusPi)); + for (double i = 1; i < N; i++) { + theta += dTheta; + thetaPlusPi += dTheta; + poly.lineTo(Math.cos(theta), Math.sin(theta)); + poly2.lineTo(2.0 + theoreticalDistance + Math.cos(thetaPlusPi), + Math.sin(thetaPlusPi)); + } + + distance = GeometryEngine.distance(poly, poly2, null); + + assertTrue(Math.abs(distance - theoreticalDistance) < 1.0e-10); + } + + private static Polygon makePolygon() { + Polygon poly = new Polygon(); + + poly.startPath(0, 0); + poly.lineTo(0, 10); + poly.lineTo(10, 10); + poly.lineTo(10, 0); + + poly.startPath(3, 3); + poly.lineTo(7, 3); + poly.lineTo(7, 7); + poly.lineTo(3, 7); + + return poly; + } + + private static Polyline makePolyline() { + Polyline poly = new Polyline(); + poly.startPath(0, 15); + poly.lineTo(15, 15); + return poly; + } + + private static MultiPoint makeMultiPoint() { + MultiPoint mpoint = new MultiPoint(); + mpoint.add(0, 30); + mpoint.add(15, 15); + mpoint.add(0, 15); + return mpoint; + } + + private static Point makePoint() { + Point point = new Point(); + Point2D pt = new Point2D(); + pt.setCoords(0, 15); + point.setXY(pt); + return point; + } + + @Test + public static void testDistanceWithNullSpatialReference() { + // There was a bug that distance op did not work with null Spatial + // Reference. + String str1 = "{\"paths\":[[[-117.138791850991,34.017492675023],[-117.138762336971,34.0174925550462]]]}"; + String str2 = "{\"paths\":[[[-117.138867827972,34.0174854109623],[-117.138850197027,34.0174929160126],[-117.138791850991,34.017492675023]]]}"; + MapGeometry geom1 = GeometryEngine.jsonToGeometry(JsonParserReader.createFromString(str1)); + MapGeometry geom2 = GeometryEngine.jsonToGeometry(JsonParserReader.createFromString(str2)); + double distance = GeometryEngine.distance(geom1.getGeometry(), + geom2.getGeometry(), null); + assertTrue(distance == 0); + } } diff --git a/src/test/java/com/esri/core/geometry/TestEditShape.java b/src/test/java/com/esri/core/geometry/TestEditShape.java index a95e1ed1..95b5ea30 100644 --- a/src/test/java/com/esri/core/geometry/TestEditShape.java +++ b/src/test/java/com/esri/core/geometry/TestEditShape.java @@ -28,392 +28,392 @@ import org.junit.Test; public class TestEditShape extends TestCase { - @Override - protected void setUp() throws Exception { - super.setUp(); - } - - @Override - protected void tearDown() throws Exception { - super.tearDown(); - } - - @Test - public static void testEditShape() { - { - // Single part polygon - Polygon poly = new Polygon(); - poly.startPath(10, 10); - poly.lineTo(10, 12); - poly.lineTo(14, 15); - poly.lineTo(10, 11); - EditShape editShape = new EditShape(); - int geom = editShape.addGeometry(poly); - Polygon poly2 = (Polygon) editShape.getGeometry(geom); - assertTrue(poly.equals(poly2)); - } - - { - // Two part poly - Polygon poly = new Polygon(); - poly.startPath(10, 10); - poly.lineTo(10, 12); - poly.lineTo(14, 15); - poly.lineTo(10, 11); - - poly.startPath(100, 10); - poly.lineTo(100, 12); - poly.lineTo(14, 150); - poly.lineTo(10, 101); - poly.lineTo(100, 11); - - EditShape editShape = new EditShape(); - int geom = editShape.addGeometry(poly); - Polygon poly2 = (Polygon) editShape.getGeometry(geom); - assertTrue(poly.equals(poly2)); - } - - { - // Single part polyline - Polyline poly = new Polyline(); - poly.startPath(10, 10); - poly.lineTo(10, 12); - poly.lineTo(14, 15); - poly.lineTo(10, 11); - EditShape editShape = new EditShape(); - int geom = editShape.addGeometry(poly); - Polyline poly2 = (Polyline) editShape.getGeometry(geom); - assertTrue(poly.equals(poly2)); - } - - { - // Two part poly - Polyline poly = new Polyline(); - poly.startPath(10, 10); - poly.lineTo(10, 12); - poly.lineTo(14, 15); - poly.lineTo(10, 11); - - poly.startPath(100, 10); - poly.lineTo(100, 12); - poly.lineTo(14, 150); - poly.lineTo(10, 101); - poly.lineTo(100, 11); - - EditShape editShape = new EditShape(); - int geom = editShape.addGeometry(poly); - Polyline poly2 = (Polyline) editShape.getGeometry(geom); - assertTrue(poly.equals(poly2)); - } - - { - // Five part poly. Close one of parts to test if it works. - Polyline poly = new Polyline(); - poly.startPath(10, 10); - poly.lineTo(10, 12); - poly.lineTo(14, 15); - poly.lineTo(10, 11); - - poly.startPath(100, 10); - poly.lineTo(100, 12); - poly.lineTo(14, 150); - poly.lineTo(10, 101); - poly.lineTo(100, 11); - - poly.startPath(1100, 101); - poly.lineTo(1300, 132); - poly.lineTo(144, 150); - poly.lineTo(106, 1051); - poly.lineTo(1600, 161); - - poly.startPath(100, 190); - poly.lineTo(1800, 192); - poly.lineTo(184, 8150); - poly.lineTo(1080, 181); - - poly.startPath(1030, 10); - poly.lineTo(1300, 132); - poly.lineTo(314, 3150); - poly.lineTo(310, 1301); - poly.lineTo(3100, 311); - - EditShape editShape = new EditShape(); - int geom = editShape.addGeometry(poly); - editShape.setClosedPath( - editShape.getNextPath(editShape.getFirstPath(geom)), true); - ((MultiPathImpl) poly._getImpl()).closePathWithLine(1); - Polyline poly2 = (Polyline) editShape.getGeometry(geom); - assertTrue(poly.equals(poly2)); - } - - { - // Test erase - Polyline poly = new Polyline(); - poly.startPath(10, 10); - poly.lineTo(10, 12); - poly.lineTo(314, 3150); - poly.lineTo(310, 1301); - poly.lineTo(3100, 311); - - EditShape editShape = new EditShape(); - int geom = editShape.addGeometry(poly); - int vertex = editShape.getFirstVertex(editShape.getFirstPath(geom)); - vertex = editShape.removeVertex(vertex, true); - vertex = editShape.getNextVertex(vertex); - editShape.removeVertex(vertex, true); - Polyline poly2 = (Polyline) editShape.getGeometry(geom); - - poly.setEmpty(); - poly.startPath(10, 12); - poly.lineTo(310, 1301); - poly.lineTo(3100, 311); - - assertTrue(poly.equals(poly2)); - } - - { - // Test erase - Polygon poly = new Polygon(); - poly.startPath(10, 10); - poly.lineTo(10, 12); - poly.lineTo(314, 3150); - poly.lineTo(310, 1301); - poly.lineTo(3100, 311); - - EditShape editShape = new EditShape(); - int geom = editShape.addGeometry(poly); - int vertex = editShape.getFirstVertex(editShape.getFirstPath(geom)); - vertex = editShape.removeVertex(vertex, true); - vertex = editShape.getNextVertex(vertex); - editShape.removeVertex(vertex, true); - Polygon poly2 = (Polygon) editShape.getGeometry(geom); - - poly.setEmpty(); - poly.startPath(10, 12); - poly.lineTo(310, 1301); - poly.lineTo(3100, 311); - - assertTrue(poly.equals(poly2)); - } - - { - // Test Filter Close Points - Polygon poly = new Polygon(); - poly.startPath(10, 10); - poly.lineTo(10, 10.001); - poly.lineTo(10.001, 10); - - EditShape editShape = new EditShape(); - int geom = editShape.addGeometry(poly); - editShape.filterClosePoints(0.002, true, false); - Polygon poly2 = (Polygon) editShape.getGeometry(geom); - assertTrue(poly2.isEmpty()); - } - - { - // Test Filter Close Points - Polygon poly = new Polygon(); - poly.startPath(10, 10); - poly.lineTo(10, 10.0025); - poly.lineTo(11.0, 10); - - EditShape editShape = new EditShape(); - int geom = editShape.addGeometry(poly); - editShape.filterClosePoints(0.002, true, false); - Polygon poly2 = (Polygon) editShape.getGeometry(geom); - assertTrue(!poly2.isEmpty()); - } - - { - // Test Filter Close Points - Polygon poly = new Polygon(); - poly.startPath(10, 10); - poly.lineTo(10, 10.001); - poly.lineTo(11.0, 10); - - EditShape editShape = new EditShape(); - int geom = editShape.addGeometry(poly); - editShape.filterClosePoints(0.002, true, false); - Polygon poly2 = (Polygon) editShape.getGeometry(geom); - assertTrue(poly2.isEmpty()); - } - - { - // Test attribute splitting 1 - Polyline polyline = new Polyline(); - polyline.startPath(0, 0); - polyline.lineTo(1, 1); - polyline.lineTo(2, 2); - polyline.lineTo(3, 3); - polyline.lineTo(4, 4); - - polyline.startPath(5, 5); - polyline.lineTo(6, 6); - polyline.lineTo(7, 7); - polyline.lineTo(8, 8); - polyline.lineTo(9, 9); - - polyline.addAttribute(VertexDescription.Semantics.Z); - polyline.setAttribute(VertexDescription.Semantics.Z, 0, 0, 4); - polyline.setAttribute(VertexDescription.Semantics.Z, 1, 0, 8); - polyline.setAttribute(VertexDescription.Semantics.Z, 2, 0, 12); - polyline.setAttribute(VertexDescription.Semantics.Z, 3, 0, 16); - polyline.setAttribute(VertexDescription.Semantics.Z, 4, 0, 20); - - polyline.setAttribute(VertexDescription.Semantics.Z, 5, 0, 22); - polyline.setAttribute(VertexDescription.Semantics.Z, 6, 0, 26); - polyline.setAttribute(VertexDescription.Semantics.Z, 7, 0, 30); - polyline.setAttribute(VertexDescription.Semantics.Z, 8, 0, 34); - polyline.setAttribute(VertexDescription.Semantics.Z, 9, 0, 38); - - EditShape shape = new EditShape(); - int geometry = shape.addGeometry(polyline); - - AttributeStreamOfInt32 vertex_handles = new AttributeStreamOfInt32( - 0); - - for (int path = shape.getFirstPath(geometry); path != -1; path = shape - .getNextPath(path)) { - for (int vertex = shape.getFirstVertex(path); vertex != -1; vertex = shape - .getNextVertex(vertex)) { - if (vertex != shape.getLastVertex(path)) - vertex_handles.add(vertex); - } - } - - double[] t = new double[1]; - for (int i = 0; i < vertex_handles.size(); i++) { - int vertex = vertex_handles.read(i); - t[0] = 0.5; - shape.splitSegment(vertex, t, 1); - } - - Polyline chopped_polyline = (Polyline) shape.getGeometry(geometry); - assertTrue(chopped_polyline.getPointCount() == 18); - - double att_ = 4; - for (int i = 0; i < 18; i++) { - double att = chopped_polyline.getAttributeAsDbl( - VertexDescription.Semantics.Z, i, 0); - assertTrue(att == att_); - att_ += 2; - } - - } - - { // Test attribute splitting 2 - Polyline line1 = new Polyline(), line2 = new Polyline(); - line1.addAttribute(VertexDescription.Semantics.M); - line2.addAttribute(VertexDescription.Semantics.M); - line1.startPath(0, 0); - line1.lineTo(10, 10); - line2.startPath(10, 0); - line2.lineTo(0, 10); - line1.setAttribute(VertexDescription.Semantics.M, 0, 0, 7); - line1.setAttribute(VertexDescription.Semantics.M, 1, 0, 17); - line2.setAttribute(VertexDescription.Semantics.M, 0, 0, 5); - line2.setAttribute(VertexDescription.Semantics.M, 1, 0, 15); - - EditShape shape = new EditShape(); - int g1 = shape.addGeometry(line1); - int g2 = shape.addGeometry(line2); - CrackAndCluster.execute(shape, 0.001, null, true); - - Polyline chopped_line1 = (Polyline) shape.getGeometry(g1); - Polyline chopped_line2 = (Polyline) shape.getGeometry(g2); - - double att1 = chopped_line1.getAttributeAsDbl( - VertexDescription.Semantics.M, 1, 0); - double att2 = chopped_line2.getAttributeAsDbl( - VertexDescription.Semantics.M, 1, 0); - assertTrue(att1 == 12); - assertTrue(att2 == 10); - } - - { // Test attribute splitting 3 - Polygon polygon = new Polygon(); - polygon.addAttribute(VertexDescription.Semantics.M); - polygon.startPath(0, 0); - polygon.lineTo(0, 10); - polygon.lineTo(10, 10); - polygon.lineTo(10, 0); - - polygon.setAttribute(VertexDescription.Semantics.M, 0, 0, 7); - polygon.setAttribute(VertexDescription.Semantics.M, 1, 0, 17); - polygon.setAttribute(VertexDescription.Semantics.M, 2, 0, 23); - polygon.setAttribute(VertexDescription.Semantics.M, 3, 0, 43); - - EditShape shape = new EditShape(); - int geometry = shape.addGeometry(polygon); - - AttributeStreamOfInt32 vertex_handles = new AttributeStreamOfInt32( - 0); - - int start_v = shape.getFirstVertex(shape.getFirstPath(geometry)); - int v = start_v; - - do { - vertex_handles.add(v); - v = shape.getNextVertex(v); - } while (v != start_v); - - double[] t = new double[1]; - for (int i = 0; i < vertex_handles.size(); i++) { - int v1 = vertex_handles.read(i); - t[0] = 0.5; - shape.splitSegment(v1, t, 1); - } - - Polygon cut_polygon = (Polygon) shape.getGeometry(geometry); - assertTrue(cut_polygon.getPointCount() == 8); - - @SuppressWarnings("unused") - Point2D pt0 = cut_polygon.getXY(0); - double a0 = cut_polygon.getAttributeAsDbl( - VertexDescription.Semantics.M, 0, 0); - assertTrue(a0 == 25); - - @SuppressWarnings("unused") - Point2D pt1 = cut_polygon.getXY(1); - double a1 = cut_polygon.getAttributeAsDbl( - VertexDescription.Semantics.M, 1, 0); - assertTrue(a1 == 7); - - @SuppressWarnings("unused") - Point2D pt2 = cut_polygon.getXY(2); - double a2 = cut_polygon.getAttributeAsDbl( - VertexDescription.Semantics.M, 2, 0); - assertTrue(a2 == 12); - - @SuppressWarnings("unused") - Point2D pt3 = cut_polygon.getXY(3); - double a3 = cut_polygon.getAttributeAsDbl( - VertexDescription.Semantics.M, 3, 0); - assertTrue(a3 == 17); - - @SuppressWarnings("unused") - Point2D pt4 = cut_polygon.getXY(4); - double a4 = cut_polygon.getAttributeAsDbl( - VertexDescription.Semantics.M, 4, 0); - assertTrue(a4 == 20); - - @SuppressWarnings("unused") - Point2D pt5 = cut_polygon.getXY(5); - double a5 = cut_polygon.getAttributeAsDbl( - VertexDescription.Semantics.M, 5, 0); - assertTrue(a5 == 23); - - @SuppressWarnings("unused") - Point2D pt6 = cut_polygon.getXY(6); - double a6 = cut_polygon.getAttributeAsDbl( - VertexDescription.Semantics.M, 6, 0); - assertTrue(a6 == 33); - - @SuppressWarnings("unused") - Point2D pt7 = cut_polygon.getXY(7); - double a7 = cut_polygon.getAttributeAsDbl( - VertexDescription.Semantics.M, 7, 0); - assertTrue(a7 == 43); - } - } + @Override + protected void setUp() throws Exception { + super.setUp(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + } + + @Test + public static void testEditShape() { + { + // Single part polygon + Polygon poly = new Polygon(); + poly.startPath(10, 10); + poly.lineTo(10, 12); + poly.lineTo(14, 15); + poly.lineTo(10, 11); + EditShape editShape = new EditShape(); + int geom = editShape.addGeometry(poly); + Polygon poly2 = (Polygon) editShape.getGeometry(geom); + assertTrue(poly.equals(poly2)); + } + + { + // Two part poly + Polygon poly = new Polygon(); + poly.startPath(10, 10); + poly.lineTo(10, 12); + poly.lineTo(14, 15); + poly.lineTo(10, 11); + + poly.startPath(100, 10); + poly.lineTo(100, 12); + poly.lineTo(14, 150); + poly.lineTo(10, 101); + poly.lineTo(100, 11); + + EditShape editShape = new EditShape(); + int geom = editShape.addGeometry(poly); + Polygon poly2 = (Polygon) editShape.getGeometry(geom); + assertTrue(poly.equals(poly2)); + } + + { + // Single part polyline + Polyline poly = new Polyline(); + poly.startPath(10, 10); + poly.lineTo(10, 12); + poly.lineTo(14, 15); + poly.lineTo(10, 11); + EditShape editShape = new EditShape(); + int geom = editShape.addGeometry(poly); + Polyline poly2 = (Polyline) editShape.getGeometry(geom); + assertTrue(poly.equals(poly2)); + } + + { + // Two part poly + Polyline poly = new Polyline(); + poly.startPath(10, 10); + poly.lineTo(10, 12); + poly.lineTo(14, 15); + poly.lineTo(10, 11); + + poly.startPath(100, 10); + poly.lineTo(100, 12); + poly.lineTo(14, 150); + poly.lineTo(10, 101); + poly.lineTo(100, 11); + + EditShape editShape = new EditShape(); + int geom = editShape.addGeometry(poly); + Polyline poly2 = (Polyline) editShape.getGeometry(geom); + assertTrue(poly.equals(poly2)); + } + + { + // Five part poly. Close one of parts to test if it works. + Polyline poly = new Polyline(); + poly.startPath(10, 10); + poly.lineTo(10, 12); + poly.lineTo(14, 15); + poly.lineTo(10, 11); + + poly.startPath(100, 10); + poly.lineTo(100, 12); + poly.lineTo(14, 150); + poly.lineTo(10, 101); + poly.lineTo(100, 11); + + poly.startPath(1100, 101); + poly.lineTo(1300, 132); + poly.lineTo(144, 150); + poly.lineTo(106, 1051); + poly.lineTo(1600, 161); + + poly.startPath(100, 190); + poly.lineTo(1800, 192); + poly.lineTo(184, 8150); + poly.lineTo(1080, 181); + + poly.startPath(1030, 10); + poly.lineTo(1300, 132); + poly.lineTo(314, 3150); + poly.lineTo(310, 1301); + poly.lineTo(3100, 311); + + EditShape editShape = new EditShape(); + int geom = editShape.addGeometry(poly); + editShape.setClosedPath( + editShape.getNextPath(editShape.getFirstPath(geom)), true); + ((MultiPathImpl) poly._getImpl()).closePathWithLine(1); + Polyline poly2 = (Polyline) editShape.getGeometry(geom); + assertTrue(poly.equals(poly2)); + } + + { + // Test erase + Polyline poly = new Polyline(); + poly.startPath(10, 10); + poly.lineTo(10, 12); + poly.lineTo(314, 3150); + poly.lineTo(310, 1301); + poly.lineTo(3100, 311); + + EditShape editShape = new EditShape(); + int geom = editShape.addGeometry(poly); + int vertex = editShape.getFirstVertex(editShape.getFirstPath(geom)); + vertex = editShape.removeVertex(vertex, true); + vertex = editShape.getNextVertex(vertex); + editShape.removeVertex(vertex, true); + Polyline poly2 = (Polyline) editShape.getGeometry(geom); + + poly.setEmpty(); + poly.startPath(10, 12); + poly.lineTo(310, 1301); + poly.lineTo(3100, 311); + + assertTrue(poly.equals(poly2)); + } + + { + // Test erase + Polygon poly = new Polygon(); + poly.startPath(10, 10); + poly.lineTo(10, 12); + poly.lineTo(314, 3150); + poly.lineTo(310, 1301); + poly.lineTo(3100, 311); + + EditShape editShape = new EditShape(); + int geom = editShape.addGeometry(poly); + int vertex = editShape.getFirstVertex(editShape.getFirstPath(geom)); + vertex = editShape.removeVertex(vertex, true); + vertex = editShape.getNextVertex(vertex); + editShape.removeVertex(vertex, true); + Polygon poly2 = (Polygon) editShape.getGeometry(geom); + + poly.setEmpty(); + poly.startPath(10, 12); + poly.lineTo(310, 1301); + poly.lineTo(3100, 311); + + assertTrue(poly.equals(poly2)); + } + + { + // Test Filter Close Points + Polygon poly = new Polygon(); + poly.startPath(10, 10); + poly.lineTo(10, 10.001); + poly.lineTo(10.001, 10); + + EditShape editShape = new EditShape(); + int geom = editShape.addGeometry(poly); + editShape.filterClosePoints(0.002, true, false); + Polygon poly2 = (Polygon) editShape.getGeometry(geom); + assertTrue(poly2.isEmpty()); + } + + { + // Test Filter Close Points + Polygon poly = new Polygon(); + poly.startPath(10, 10); + poly.lineTo(10, 10.0025); + poly.lineTo(11.0, 10); + + EditShape editShape = new EditShape(); + int geom = editShape.addGeometry(poly); + editShape.filterClosePoints(0.002, true, false); + Polygon poly2 = (Polygon) editShape.getGeometry(geom); + assertTrue(!poly2.isEmpty()); + } + + { + // Test Filter Close Points + Polygon poly = new Polygon(); + poly.startPath(10, 10); + poly.lineTo(10, 10.001); + poly.lineTo(11.0, 10); + + EditShape editShape = new EditShape(); + int geom = editShape.addGeometry(poly); + editShape.filterClosePoints(0.002, true, false); + Polygon poly2 = (Polygon) editShape.getGeometry(geom); + assertTrue(poly2.isEmpty()); + } + + { + // Test attribute splitting 1 + Polyline polyline = new Polyline(); + polyline.startPath(0, 0); + polyline.lineTo(1, 1); + polyline.lineTo(2, 2); + polyline.lineTo(3, 3); + polyline.lineTo(4, 4); + + polyline.startPath(5, 5); + polyline.lineTo(6, 6); + polyline.lineTo(7, 7); + polyline.lineTo(8, 8); + polyline.lineTo(9, 9); + + polyline.addAttribute(VertexDescription.Semantics.Z); + polyline.setAttribute(VertexDescription.Semantics.Z, 0, 0, 4); + polyline.setAttribute(VertexDescription.Semantics.Z, 1, 0, 8); + polyline.setAttribute(VertexDescription.Semantics.Z, 2, 0, 12); + polyline.setAttribute(VertexDescription.Semantics.Z, 3, 0, 16); + polyline.setAttribute(VertexDescription.Semantics.Z, 4, 0, 20); + + polyline.setAttribute(VertexDescription.Semantics.Z, 5, 0, 22); + polyline.setAttribute(VertexDescription.Semantics.Z, 6, 0, 26); + polyline.setAttribute(VertexDescription.Semantics.Z, 7, 0, 30); + polyline.setAttribute(VertexDescription.Semantics.Z, 8, 0, 34); + polyline.setAttribute(VertexDescription.Semantics.Z, 9, 0, 38); + + EditShape shape = new EditShape(); + int geometry = shape.addGeometry(polyline); + + AttributeStreamOfInt32 vertex_handles = new AttributeStreamOfInt32( + 0); + + for (int path = shape.getFirstPath(geometry); path != -1; path = shape + .getNextPath(path)) { + for (int vertex = shape.getFirstVertex(path); vertex != -1; vertex = shape + .getNextVertex(vertex)) { + if (vertex != shape.getLastVertex(path)) + vertex_handles.add(vertex); + } + } + + double[] t = new double[1]; + for (int i = 0; i < vertex_handles.size(); i++) { + int vertex = vertex_handles.read(i); + t[0] = 0.5; + shape.splitSegment(vertex, t, 1); + } + + Polyline chopped_polyline = (Polyline) shape.getGeometry(geometry); + assertTrue(chopped_polyline.getPointCount() == 18); + + double att_ = 4; + for (int i = 0; i < 18; i++) { + double att = chopped_polyline.getAttributeAsDbl( + VertexDescription.Semantics.Z, i, 0); + assertTrue(att == att_); + att_ += 2; + } + + } + + { // Test attribute splitting 2 + Polyline line1 = new Polyline(), line2 = new Polyline(); + line1.addAttribute(VertexDescription.Semantics.M); + line2.addAttribute(VertexDescription.Semantics.M); + line1.startPath(0, 0); + line1.lineTo(10, 10); + line2.startPath(10, 0); + line2.lineTo(0, 10); + line1.setAttribute(VertexDescription.Semantics.M, 0, 0, 7); + line1.setAttribute(VertexDescription.Semantics.M, 1, 0, 17); + line2.setAttribute(VertexDescription.Semantics.M, 0, 0, 5); + line2.setAttribute(VertexDescription.Semantics.M, 1, 0, 15); + + EditShape shape = new EditShape(); + int g1 = shape.addGeometry(line1); + int g2 = shape.addGeometry(line2); + CrackAndCluster.execute(shape, 0.001, null, true); + + Polyline chopped_line1 = (Polyline) shape.getGeometry(g1); + Polyline chopped_line2 = (Polyline) shape.getGeometry(g2); + + double att1 = chopped_line1.getAttributeAsDbl( + VertexDescription.Semantics.M, 1, 0); + double att2 = chopped_line2.getAttributeAsDbl( + VertexDescription.Semantics.M, 1, 0); + assertTrue(att1 == 12); + assertTrue(att2 == 10); + } + + { // Test attribute splitting 3 + Polygon polygon = new Polygon(); + polygon.addAttribute(VertexDescription.Semantics.M); + polygon.startPath(0, 0); + polygon.lineTo(0, 10); + polygon.lineTo(10, 10); + polygon.lineTo(10, 0); + + polygon.setAttribute(VertexDescription.Semantics.M, 0, 0, 7); + polygon.setAttribute(VertexDescription.Semantics.M, 1, 0, 17); + polygon.setAttribute(VertexDescription.Semantics.M, 2, 0, 23); + polygon.setAttribute(VertexDescription.Semantics.M, 3, 0, 43); + + EditShape shape = new EditShape(); + int geometry = shape.addGeometry(polygon); + + AttributeStreamOfInt32 vertex_handles = new AttributeStreamOfInt32( + 0); + + int start_v = shape.getFirstVertex(shape.getFirstPath(geometry)); + int v = start_v; + + do { + vertex_handles.add(v); + v = shape.getNextVertex(v); + } while (v != start_v); + + double[] t = new double[1]; + for (int i = 0; i < vertex_handles.size(); i++) { + int v1 = vertex_handles.read(i); + t[0] = 0.5; + shape.splitSegment(v1, t, 1); + } + + Polygon cut_polygon = (Polygon) shape.getGeometry(geometry); + assertTrue(cut_polygon.getPointCount() == 8); + + @SuppressWarnings("unused") + Point2D pt0 = cut_polygon.getXY(0); + double a0 = cut_polygon.getAttributeAsDbl( + VertexDescription.Semantics.M, 0, 0); + assertTrue(a0 == 25); + + @SuppressWarnings("unused") + Point2D pt1 = cut_polygon.getXY(1); + double a1 = cut_polygon.getAttributeAsDbl( + VertexDescription.Semantics.M, 1, 0); + assertTrue(a1 == 7); + + @SuppressWarnings("unused") + Point2D pt2 = cut_polygon.getXY(2); + double a2 = cut_polygon.getAttributeAsDbl( + VertexDescription.Semantics.M, 2, 0); + assertTrue(a2 == 12); + + @SuppressWarnings("unused") + Point2D pt3 = cut_polygon.getXY(3); + double a3 = cut_polygon.getAttributeAsDbl( + VertexDescription.Semantics.M, 3, 0); + assertTrue(a3 == 17); + + @SuppressWarnings("unused") + Point2D pt4 = cut_polygon.getXY(4); + double a4 = cut_polygon.getAttributeAsDbl( + VertexDescription.Semantics.M, 4, 0); + assertTrue(a4 == 20); + + @SuppressWarnings("unused") + Point2D pt5 = cut_polygon.getXY(5); + double a5 = cut_polygon.getAttributeAsDbl( + VertexDescription.Semantics.M, 5, 0); + assertTrue(a5 == 23); + + @SuppressWarnings("unused") + Point2D pt6 = cut_polygon.getXY(6); + double a6 = cut_polygon.getAttributeAsDbl( + VertexDescription.Semantics.M, 6, 0); + assertTrue(a6 == 33); + + @SuppressWarnings("unused") + Point2D pt7 = cut_polygon.getXY(7); + double a7 = cut_polygon.getAttributeAsDbl( + VertexDescription.Semantics.M, 7, 0); + assertTrue(a7 == 43); + } + } } diff --git a/src/test/java/com/esri/core/geometry/TestEnvelope.java b/src/test/java/com/esri/core/geometry/TestEnvelope.java new file mode 100644 index 00000000..6b5622e8 --- /dev/null +++ b/src/test/java/com/esri/core/geometry/TestEnvelope.java @@ -0,0 +1,78 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.esri.core.geometry; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class TestEnvelope +{ + @Test + public void testIntersect() { + assertIntersection(new Envelope(0, 0, 5, 5), new Envelope(0, 0, 5, 5), new Envelope(0, 0, 5, 5)); + assertIntersection(new Envelope(0, 0, 5, 5), new Envelope(1, 1, 6, 6), new Envelope(1, 1, 5, 5)); + assertIntersection(new Envelope(1, 2, 3, 4), new Envelope(0, 0, 2, 3), new Envelope(1, 2, 2, 3)); + + assertNoIntersection(new Envelope(), new Envelope()); + assertNoIntersection(new Envelope(0, 0, 5, 5), new Envelope()); + assertNoIntersection(new Envelope(), new Envelope(0, 0, 5, 5)); + } + + @Test + public void testEquals() { + Envelope env1 = new Envelope(10, 9, 11, 12); + Envelope env2 = new Envelope(10, 9, 11, 13); + Envelope1D emptyInterval = new Envelope1D(); + emptyInterval.setEmpty(); + assertFalse(env1.equals(env2)); + env1.queryInterval(VertexDescription.Semantics.M, 0).equals(emptyInterval); + env2.setCoords(10, 9, 11, 12); + assertTrue(env1.equals(env2)); + env1.addAttribute(VertexDescription.Semantics.M); + env1.queryInterval(VertexDescription.Semantics.M, 0).equals(emptyInterval); + assertFalse(env1.equals(env2)); + env2.addAttribute(VertexDescription.Semantics.M); + assertTrue(env1.equals(env2)); + Envelope1D nonEmptyInterval = new Envelope1D(); + nonEmptyInterval.setCoords(1, 2); + env1.setInterval(VertexDescription.Semantics.M, 0, emptyInterval); + assertTrue(env1.equals(env2)); + env2.setInterval(VertexDescription.Semantics.M, 0, emptyInterval); + assertTrue(env1.equals(env2)); + env2.setInterval(VertexDescription.Semantics.M, 0, nonEmptyInterval); + assertFalse(env1.equals(env2)); + env1.setInterval(VertexDescription.Semantics.M, 0, nonEmptyInterval); + assertTrue(env1.equals(env2)); + env1.queryInterval(VertexDescription.Semantics.M, 0).equals(nonEmptyInterval); + env1.queryInterval(VertexDescription.Semantics.POSITION, 0).equals(new Envelope1D(10, 11)); + env1.queryInterval(VertexDescription.Semantics.POSITION, 0).equals(new Envelope1D(9, 13)); + } + + private static void assertIntersection(Envelope envelope, Envelope other, Envelope intersection) { + boolean intersects = envelope.intersect(other); + assertTrue(intersects); + assertEquals(envelope, intersection); + } + + private static void assertNoIntersection(Envelope envelope, Envelope other) { + boolean intersects = envelope.intersect(other); + assertFalse(intersects); + assertTrue(envelope.isEmpty()); + } + +} + diff --git a/src/test/java/com/esri/core/geometry/TestEnvelope2DIntersector.java b/src/test/java/com/esri/core/geometry/TestEnvelope2DIntersector.java index 32c07b43..6416b430 100644 --- a/src/test/java/com/esri/core/geometry/TestEnvelope2DIntersector.java +++ b/src/test/java/com/esri/core/geometry/TestEnvelope2DIntersector.java @@ -31,336 +31,336 @@ import java.util.Random; public class TestEnvelope2DIntersector extends TestCase { - @Override - protected void setUp() throws Exception { - super.setUp(); - } - - @Override - protected void tearDown() throws Exception { - super.tearDown(); - } - - @Test - public static void testEnvelope2Dintersector() { - ArrayList envelopes = new ArrayList(0); - - Envelope2D env0 = new Envelope2D(2, 3, 4, 4); - Envelope2D env1 = new Envelope2D(5, 13, 9, 15); - Envelope2D env2 = new Envelope2D(6, 9, 11, 12); - Envelope2D env3 = new Envelope2D(8, 10, 9, 17); - Envelope2D env4 = new Envelope2D(11.001, 12, 14, 14); - Envelope2D env5 = new Envelope2D(1, 3, 3, 4); - Envelope2D env6 = new Envelope2D(0, 2, 5, 10); - Envelope2D env7 = new Envelope2D(4, 7, 5, 10); - Envelope2D env8 = new Envelope2D(3, 15, 15, 15); - Envelope2D env9 = new Envelope2D(0, 9, 14, 9); - Envelope2D env10 = new Envelope2D(0, 8.999, 14, 8.999); - - envelopes.add(env0); - envelopes.add(env1); - envelopes.add(env2); - envelopes.add(env3); - envelopes.add(env4); - envelopes.add(env5); - envelopes.add(env6); - envelopes.add(env7); - envelopes.add(env8); - envelopes.add(env9); - envelopes.add(env10); - - Envelope2DIntersectorImpl intersector = new Envelope2DIntersectorImpl(); - intersector.setTolerance(0.001); - - intersector.startConstruction(); - for (int i = 0; i < envelopes.size(); i++) - intersector.addEnvelope(i, envelopes.get(i)); - intersector.endConstruction(); - - int count = 0; - while (intersector.next()) { - int env_a = intersector.getHandleA(); - int env_b = intersector.getHandleB(); - count++; - Envelope2D env = new Envelope2D(); - env.setCoords(envelopes.get(env_a)); - env.inflate(0.001, 0.001); - assertTrue(env.isIntersecting(envelopes.get(env_b))); - } - - assert (count == 16); - - Envelope2DIntersectorImpl intersector2 = new Envelope2DIntersectorImpl(); - intersector2.setTolerance(0.0); - intersector2.startConstruction(); - for (int i = 0; i < envelopes.size(); i++) - intersector2.addEnvelope(i, envelopes.get(i)); - intersector2.endConstruction(); - - count = 0; - while (intersector2.next()) { - int env_a = intersector2.getHandleA(); - int env_b = intersector2.getHandleB(); - count++; - Envelope2D env = new Envelope2D(); - env.setCoords(envelopes.get(env_a)); - assertTrue(env.isIntersecting(envelopes.get(env_b))); - } - - assert (count == 13); - - env0 = new Envelope2D(0, 0, 0, 10); - env1 = new Envelope2D(0, 10, 10, 10); - env2 = new Envelope2D(10, 0, 10, 10); - env3 = new Envelope2D(0, 0, 10, 0); - envelopes.clear(); - - envelopes.add(env0); - envelopes.add(env1); - envelopes.add(env2); - envelopes.add(env3); - - Envelope2DIntersectorImpl intersector3 = new Envelope2DIntersectorImpl(); - intersector3.setTolerance(0.001); - - intersector3.startConstruction(); - for (int i = 0; i < envelopes.size(); i++) - intersector3.addEnvelope(i, envelopes.get(i)); - intersector3.endConstruction(); - ; - count = 0; - while (intersector3.next()) { - int env_a = intersector3.getHandleA(); - int env_b = intersector3.getHandleB(); - count++; - Envelope2D env = new Envelope2D(); - env.setCoords(envelopes.get(env_a)); - assertTrue(env.isIntersecting(envelopes.get(env_b))); - } - - assertTrue(count == 4); - - env0 = new Envelope2D(0, 0, 0, 10); - envelopes.clear(); - - envelopes.add(env0); - envelopes.add(env0); - envelopes.add(env0); - envelopes.add(env0); - - Envelope2DIntersectorImpl intersector4 = new Envelope2DIntersectorImpl(); - intersector4.setTolerance(0.001); - - intersector4.startConstruction(); - for (int i = 0; i < envelopes.size(); i++) - intersector4.addEnvelope(i, envelopes.get(i)); - intersector4.endConstruction(); - - count = 0; - while (intersector4.next()) { - int env_a = intersector4.getHandleA(); - int env_b = intersector4.getHandleB(); - count++; - Envelope2D env = new Envelope2D(); - env.setCoords(envelopes.get(env_a)); - assertTrue(env.isIntersecting(envelopes.get(env_b))); - } - - assert (count == 6); - - env0 = new Envelope2D(0, 10, 10, 10); - envelopes.clear(); - - envelopes.add(env0); - envelopes.add(env0); - envelopes.add(env0); - envelopes.add(env0); - - Envelope2DIntersectorImpl intersector5 = new Envelope2DIntersectorImpl(); - intersector5.setTolerance(0.001); - - intersector5.startConstruction(); - for (int i = 0; i < envelopes.size(); i++) - intersector5.addEnvelope(i, envelopes.get(i)); - intersector5.endConstruction(); - - count = 0; - while (intersector5.next()) { - int env_a = intersector5.getHandleA(); - int env_b = intersector5.getHandleB(); - count++; - Envelope2D env = new Envelope2D(); - env.setCoords(envelopes.get(env_a)); - assertTrue(env.isIntersecting(envelopes.get(env_b))); - } - - assertTrue(count == 6); - } - - @Test - public static void testRandom() { - int passcount = 10; - int figureSize = 100; - int figureSize2 = 100; - Envelope extent1 = new Envelope(), extent2 = new Envelope(), extent3 = new Envelope(), extent4 = new Envelope(); - extent1.setCoords(-10000, 5000, 10000, 25000);// red - extent2.setCoords(-10000, 2000, 10000, 8000);// blue - extent3.setCoords(-10000, -8000, 10000, -2000);// blue - extent4.setCoords(-10000, -25000, 10000, -5000);// red - - RandomCoordinateGenerator generator1 = new RandomCoordinateGenerator( - Math.max(figureSize, 10000), extent1, 0.001); - RandomCoordinateGenerator generator2 = new RandomCoordinateGenerator( - Math.max(figureSize, 10000), extent2, 0.001); - RandomCoordinateGenerator generator3 = new RandomCoordinateGenerator( - Math.max(figureSize, 10000), extent3, 0.001); - RandomCoordinateGenerator generator4 = new RandomCoordinateGenerator( - Math.max(figureSize, 10000), extent4, 0.001); - - Random random = new Random(1982); - int rand_max = 511; - - int qCount = 0; - int eCount = 0; - @SuppressWarnings("unused") - int bCount = 0; - for (int c = 0; c < passcount; c++) { - Polygon polyRed = new Polygon(); - Polygon polyBlue = new Polygon(); - - int r = figureSize; - if (r < 3) - continue; - - Point pt; - for (int j = 0; j < r; j++) { - int rand = random.nextInt(rand_max); - boolean bRandomNew = (r > 10) - && ((1.0 * rand) / rand_max > 0.95); - pt = generator1.GetRandomCoord(); - if (j == 0 || bRandomNew) - polyRed.startPath(pt); - else - polyRed.lineTo(pt); - } - - for (int j = 0; j < r; j++) { - int rand = random.nextInt(rand_max); - boolean bRandomNew = (r > 10) - && ((1.0 * rand) / rand_max > 0.95); - pt = generator4.GetRandomCoord(); - if (j == 0 || bRandomNew) - polyRed.startPath(pt); - else - polyRed.lineTo(pt); - } - - r = figureSize2; - if (r < 3) - continue; - - for (int j = 0; j < r; j++) { - int rand = random.nextInt(rand_max); - boolean bRandomNew = (r > 10) - && ((1.0 * rand) / rand_max > 0.95); - pt = generator2.GetRandomCoord(); - if (j == 0 || bRandomNew) - polyBlue.startPath(pt); - else - polyBlue.lineTo(pt); - } - - for (int j = 0; j < r; j++) { - int rand = random.nextInt(rand_max); - boolean bRandomNew = (r > 10) - && ((1.0 * rand) / rand_max > 0.95); - pt = generator3.GetRandomCoord(); - if (j == 0 || bRandomNew) - polyBlue.startPath(pt); - else - polyBlue.lineTo(pt); - } - - Envelope2D env = new Envelope2D(); - - // Quad_tree - QuadTree quadTree = buildQuadTree(polyBlue); - QuadTree.QuadTreeIterator iterator = quadTree.getIterator(); - - SegmentIteratorImpl _segIterRed = ((MultiPathImpl) polyRed - ._getImpl()).querySegmentIterator(); - - while (_segIterRed.nextPath()) { - while (_segIterRed.hasNextSegment()) { - Segment segmentRed = _segIterRed.nextSegment(); - segmentRed.queryEnvelope2D(env); - iterator.resetIterator(env, 0.001); - while (iterator.next() != -1) - qCount++; - } - } - - // Envelope_2D_intersector - - ArrayList envelopes_red = new ArrayList(); - ArrayList envelopes_blue = new ArrayList(); - - SegmentIterator segIterRed = polyRed.querySegmentIterator(); - while (segIterRed.nextPath()) { - while (segIterRed.hasNextSegment()) { - Segment segment = segIterRed.nextSegment(); - env = new Envelope2D(); - segment.queryEnvelope2D(env); - envelopes_red.add(env); - } - } - - SegmentIterator segIterBlue = polyBlue.querySegmentIterator(); - while (segIterBlue.nextPath()) { - while (segIterBlue.hasNextSegment()) { - Segment segment = segIterBlue.nextSegment(); - env = new Envelope2D(); - segment.queryEnvelope2D(env); - envelopes_blue.add(env); - } - } - - Envelope2DIntersectorImpl intersector = new Envelope2DIntersectorImpl(); - intersector.setTolerance(0.001); - - intersector.startRedConstruction(); - for (int i = 0; i < envelopes_red.size(); i++) - intersector.addRedEnvelope(i, envelopes_red.get(i)); - intersector.endRedConstruction(); - - intersector.startBlueConstruction(); - for (int i = 0; i < envelopes_blue.size(); i++) - intersector.addBlueEnvelope(i, envelopes_blue.get(i)); - intersector.endBlueConstruction(); - - while (intersector.next()) - eCount++; - - assertTrue(qCount == eCount); - } - } - - public static QuadTree buildQuadTree(MultiPath multipath) { - Envelope2D extent = new Envelope2D(); - multipath.queryEnvelope2D(extent); - QuadTree quadTree = new QuadTree(extent, 8); - int hint_index = -1; - SegmentIterator seg_iter = multipath.querySegmentIterator(); - while (seg_iter.nextPath()) { - while (seg_iter.hasNextSegment()) { - Segment segment = seg_iter.nextSegment(); - int index = seg_iter.getStartPointIndex(); - Envelope2D boundingbox = new Envelope2D(); - segment.queryEnvelope2D(boundingbox); - hint_index = quadTree.insert(index, boundingbox, hint_index); - } - } - - return quadTree; - } + @Override + protected void setUp() throws Exception { + super.setUp(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + } + + @Test + public static void testEnvelope2Dintersector() { + ArrayList envelopes = new ArrayList(0); + + Envelope2D env0 = new Envelope2D(2, 3, 4, 4); + Envelope2D env1 = new Envelope2D(5, 13, 9, 15); + Envelope2D env2 = new Envelope2D(6, 9, 11, 12); + Envelope2D env3 = new Envelope2D(8, 10, 9, 17); + Envelope2D env4 = new Envelope2D(11.001, 12, 14, 14); + Envelope2D env5 = new Envelope2D(1, 3, 3, 4); + Envelope2D env6 = new Envelope2D(0, 2, 5, 10); + Envelope2D env7 = new Envelope2D(4, 7, 5, 10); + Envelope2D env8 = new Envelope2D(3, 15, 15, 15); + Envelope2D env9 = new Envelope2D(0, 9, 14, 9); + Envelope2D env10 = new Envelope2D(0, 8.999, 14, 8.999); + + envelopes.add(env0); + envelopes.add(env1); + envelopes.add(env2); + envelopes.add(env3); + envelopes.add(env4); + envelopes.add(env5); + envelopes.add(env6); + envelopes.add(env7); + envelopes.add(env8); + envelopes.add(env9); + envelopes.add(env10); + + Envelope2DIntersectorImpl intersector = new Envelope2DIntersectorImpl(); + intersector.setTolerance(0.001); + + intersector.startConstruction(); + for (int i = 0; i < envelopes.size(); i++) + intersector.addEnvelope(i, envelopes.get(i)); + intersector.endConstruction(); + + int count = 0; + while (intersector.next()) { + int env_a = intersector.getHandleA(); + int env_b = intersector.getHandleB(); + count++; + Envelope2D env = new Envelope2D(); + env.setCoords(envelopes.get(env_a)); + env.inflate(0.001, 0.001); + assertTrue(env.isIntersecting(envelopes.get(env_b))); + } + + assert (count == 16); + + Envelope2DIntersectorImpl intersector2 = new Envelope2DIntersectorImpl(); + intersector2.setTolerance(0.0); + intersector2.startConstruction(); + for (int i = 0; i < envelopes.size(); i++) + intersector2.addEnvelope(i, envelopes.get(i)); + intersector2.endConstruction(); + + count = 0; + while (intersector2.next()) { + int env_a = intersector2.getHandleA(); + int env_b = intersector2.getHandleB(); + count++; + Envelope2D env = new Envelope2D(); + env.setCoords(envelopes.get(env_a)); + assertTrue(env.isIntersecting(envelopes.get(env_b))); + } + + assert (count == 13); + + env0 = new Envelope2D(0, 0, 0, 10); + env1 = new Envelope2D(0, 10, 10, 10); + env2 = new Envelope2D(10, 0, 10, 10); + env3 = new Envelope2D(0, 0, 10, 0); + envelopes.clear(); + + envelopes.add(env0); + envelopes.add(env1); + envelopes.add(env2); + envelopes.add(env3); + + Envelope2DIntersectorImpl intersector3 = new Envelope2DIntersectorImpl(); + intersector3.setTolerance(0.001); + + intersector3.startConstruction(); + for (int i = 0; i < envelopes.size(); i++) + intersector3.addEnvelope(i, envelopes.get(i)); + intersector3.endConstruction(); + ; + count = 0; + while (intersector3.next()) { + int env_a = intersector3.getHandleA(); + int env_b = intersector3.getHandleB(); + count++; + Envelope2D env = new Envelope2D(); + env.setCoords(envelopes.get(env_a)); + assertTrue(env.isIntersecting(envelopes.get(env_b))); + } + + assertTrue(count == 4); + + env0 = new Envelope2D(0, 0, 0, 10); + envelopes.clear(); + + envelopes.add(env0); + envelopes.add(env0); + envelopes.add(env0); + envelopes.add(env0); + + Envelope2DIntersectorImpl intersector4 = new Envelope2DIntersectorImpl(); + intersector4.setTolerance(0.001); + + intersector4.startConstruction(); + for (int i = 0; i < envelopes.size(); i++) + intersector4.addEnvelope(i, envelopes.get(i)); + intersector4.endConstruction(); + + count = 0; + while (intersector4.next()) { + int env_a = intersector4.getHandleA(); + int env_b = intersector4.getHandleB(); + count++; + Envelope2D env = new Envelope2D(); + env.setCoords(envelopes.get(env_a)); + assertTrue(env.isIntersecting(envelopes.get(env_b))); + } + + assert (count == 6); + + env0 = new Envelope2D(0, 10, 10, 10); + envelopes.clear(); + + envelopes.add(env0); + envelopes.add(env0); + envelopes.add(env0); + envelopes.add(env0); + + Envelope2DIntersectorImpl intersector5 = new Envelope2DIntersectorImpl(); + intersector5.setTolerance(0.001); + + intersector5.startConstruction(); + for (int i = 0; i < envelopes.size(); i++) + intersector5.addEnvelope(i, envelopes.get(i)); + intersector5.endConstruction(); + + count = 0; + while (intersector5.next()) { + int env_a = intersector5.getHandleA(); + int env_b = intersector5.getHandleB(); + count++; + Envelope2D env = new Envelope2D(); + env.setCoords(envelopes.get(env_a)); + assertTrue(env.isIntersecting(envelopes.get(env_b))); + } + + assertTrue(count == 6); + } + + @Test + public static void testRandom() { + int passcount = 10; + int figureSize = 100; + int figureSize2 = 100; + Envelope extent1 = new Envelope(), extent2 = new Envelope(), extent3 = new Envelope(), extent4 = new Envelope(); + extent1.setCoords(-10000, 5000, 10000, 25000);// red + extent2.setCoords(-10000, 2000, 10000, 8000);// blue + extent3.setCoords(-10000, -8000, 10000, -2000);// blue + extent4.setCoords(-10000, -25000, 10000, -5000);// red + + RandomCoordinateGenerator generator1 = new RandomCoordinateGenerator( + Math.max(figureSize, 10000), extent1, 0.001); + RandomCoordinateGenerator generator2 = new RandomCoordinateGenerator( + Math.max(figureSize, 10000), extent2, 0.001); + RandomCoordinateGenerator generator3 = new RandomCoordinateGenerator( + Math.max(figureSize, 10000), extent3, 0.001); + RandomCoordinateGenerator generator4 = new RandomCoordinateGenerator( + Math.max(figureSize, 10000), extent4, 0.001); + + Random random = new Random(1982); + int rand_max = 511; + + int qCount = 0; + int eCount = 0; + @SuppressWarnings("unused") + int bCount = 0; + for (int c = 0; c < passcount; c++) { + Polygon polyRed = new Polygon(); + Polygon polyBlue = new Polygon(); + + int r = figureSize; + if (r < 3) + continue; + + Point pt; + for (int j = 0; j < r; j++) { + int rand = random.nextInt(rand_max); + boolean bRandomNew = (r > 10) + && ((1.0 * rand) / rand_max > 0.95); + pt = generator1.GetRandomCoord(); + if (j == 0 || bRandomNew) + polyRed.startPath(pt); + else + polyRed.lineTo(pt); + } + + for (int j = 0; j < r; j++) { + int rand = random.nextInt(rand_max); + boolean bRandomNew = (r > 10) + && ((1.0 * rand) / rand_max > 0.95); + pt = generator4.GetRandomCoord(); + if (j == 0 || bRandomNew) + polyRed.startPath(pt); + else + polyRed.lineTo(pt); + } + + r = figureSize2; + if (r < 3) + continue; + + for (int j = 0; j < r; j++) { + int rand = random.nextInt(rand_max); + boolean bRandomNew = (r > 10) + && ((1.0 * rand) / rand_max > 0.95); + pt = generator2.GetRandomCoord(); + if (j == 0 || bRandomNew) + polyBlue.startPath(pt); + else + polyBlue.lineTo(pt); + } + + for (int j = 0; j < r; j++) { + int rand = random.nextInt(rand_max); + boolean bRandomNew = (r > 10) + && ((1.0 * rand) / rand_max > 0.95); + pt = generator3.GetRandomCoord(); + if (j == 0 || bRandomNew) + polyBlue.startPath(pt); + else + polyBlue.lineTo(pt); + } + + Envelope2D env = new Envelope2D(); + + // Quad_tree + QuadTree quadTree = buildQuadTree(polyBlue); + QuadTree.QuadTreeIterator iterator = quadTree.getIterator(); + + SegmentIteratorImpl _segIterRed = ((MultiPathImpl) polyRed + ._getImpl()).querySegmentIterator(); + + while (_segIterRed.nextPath()) { + while (_segIterRed.hasNextSegment()) { + Segment segmentRed = _segIterRed.nextSegment(); + segmentRed.queryEnvelope2D(env); + iterator.resetIterator(env, 0.001); + while (iterator.next() != -1) + qCount++; + } + } + + // Envelope_2D_intersector + + ArrayList envelopes_red = new ArrayList(); + ArrayList envelopes_blue = new ArrayList(); + + SegmentIterator segIterRed = polyRed.querySegmentIterator(); + while (segIterRed.nextPath()) { + while (segIterRed.hasNextSegment()) { + Segment segment = segIterRed.nextSegment(); + env = new Envelope2D(); + segment.queryEnvelope2D(env); + envelopes_red.add(env); + } + } + + SegmentIterator segIterBlue = polyBlue.querySegmentIterator(); + while (segIterBlue.nextPath()) { + while (segIterBlue.hasNextSegment()) { + Segment segment = segIterBlue.nextSegment(); + env = new Envelope2D(); + segment.queryEnvelope2D(env); + envelopes_blue.add(env); + } + } + + Envelope2DIntersectorImpl intersector = new Envelope2DIntersectorImpl(); + intersector.setTolerance(0.001); + + intersector.startRedConstruction(); + for (int i = 0; i < envelopes_red.size(); i++) + intersector.addRedEnvelope(i, envelopes_red.get(i)); + intersector.endRedConstruction(); + + intersector.startBlueConstruction(); + for (int i = 0; i < envelopes_blue.size(); i++) + intersector.addBlueEnvelope(i, envelopes_blue.get(i)); + intersector.endBlueConstruction(); + + while (intersector.next()) + eCount++; + + assertTrue(qCount == eCount); + } + } + + public static QuadTree buildQuadTree(MultiPath multipath) { + Envelope2D extent = new Envelope2D(); + multipath.queryEnvelope2D(extent); + QuadTree quadTree = new QuadTree(extent, 8); + int hint_index = -1; + SegmentIterator seg_iter = multipath.querySegmentIterator(); + while (seg_iter.nextPath()) { + while (seg_iter.hasNextSegment()) { + Segment segment = seg_iter.nextSegment(); + int index = seg_iter.getStartPointIndex(); + Envelope2D boundingbox = new Envelope2D(); + segment.queryEnvelope2D(boundingbox); + hint_index = quadTree.insert(index, boundingbox, hint_index); + } + } + + return quadTree; + } } diff --git a/src/test/java/com/esri/core/geometry/TestEquals.java b/src/test/java/com/esri/core/geometry/TestEquals.java index 3dda17be..90ed71a0 100644 --- a/src/test/java/com/esri/core/geometry/TestEquals.java +++ b/src/test/java/com/esri/core/geometry/TestEquals.java @@ -28,165 +28,165 @@ import org.junit.Test; public class TestEquals extends TestCase { - @Override - protected void setUp() throws Exception { - super.setUp(); - } - - @Override - protected void tearDown() throws Exception { - super.tearDown(); - } - - @Test - public void testEqualsOnEnvelopes() { - SpatialReference sr = SpatialReference.create(4326); - - Point p = new Point(-130, 10); - Envelope env = new Envelope(p, 12, 12); - Envelope env2 = new Envelope(-136, 4, -124, 16); - - boolean isEqual; - try { - isEqual = GeometryEngine.equals(env, env2, sr); - - } catch (IllegalArgumentException ex) { - isEqual = false; - } - assertTrue(isEqual); - } - - @Test - public void testEqualsOnPoints() { - SpatialReference sr = SpatialReference.create(4326); - - Point p1 = new Point(-116, 40); - @SuppressWarnings("unused") - Point p2 = new Point(-120, 39); - @SuppressWarnings("unused") - Point p3 = new Point(-121, 10); - @SuppressWarnings("unused") - Point p4 = new Point(-130, 12); - @SuppressWarnings("unused") - Point p5 = new Point(-108, 25); - - Point p12 = new Point(-116, 40); - @SuppressWarnings("unused") - Point p22 = new Point(-120, 39); - @SuppressWarnings("unused") - Point p32 = new Point(-121, 10); - @SuppressWarnings("unused") - Point p42 = new Point(-130, 12); - @SuppressWarnings("unused") - Point p52 = new Point(-108, 25); - - boolean isEqual1 = false; - boolean isEqual2 = false; - boolean isEqual3 = false; - boolean isEqual4 = false; - boolean isEqual5 = false; - - try { - isEqual1 = GeometryEngine.equals(p1, p12, sr); - isEqual2 = GeometryEngine.equals(p1, p12, sr); - isEqual3 = GeometryEngine.equals(p1, p12, sr); - isEqual4 = GeometryEngine.equals(p1, p12, sr); - isEqual5 = GeometryEngine.equals(p1, p12, sr); - } catch (IllegalArgumentException ex) { - - } - - assertTrue(isEqual1 && isEqual2 && isEqual3 && isEqual4 && isEqual5); - } - - @Test - public void testEqualsOnPolygons() { - SpatialReference sr = SpatialReference.create(4326); - - Polygon baseMp = new Polygon(); - Polygon compMp = new Polygon(); - - baseMp.startPath(-116, 40); - baseMp.lineTo(-120, 39); - baseMp.lineTo(-121, 10); - baseMp.lineTo(-130, 12); - baseMp.lineTo(-108, 25); - - compMp.startPath(-116, 40); - compMp.lineTo(-120, 39); - compMp.lineTo(-121, 10); - compMp.lineTo(-130, 12); - compMp.lineTo(-108, 25); - - boolean isEqual; - - try { - isEqual = GeometryEngine.equals(baseMp, compMp, sr); - - } catch (IllegalArgumentException ex) { - isEqual = false; - } - - assertTrue(isEqual); - } - - @Test - public void testEqualsOnPolylines() { - SpatialReference sr = SpatialReference.create(4326); - - Polyline baseMp = new Polyline(); - Polyline compMp = new Polyline(); - - baseMp.startPath(-116, 40); - baseMp.lineTo(-120, 39); - baseMp.lineTo(-121, 10); - baseMp.lineTo(-130, 12); - baseMp.lineTo(-108, 25); - - compMp.startPath(-116, 40); - compMp.lineTo(-120, 39); - compMp.lineTo(-121, 10); - compMp.lineTo(-130, 12); - compMp.lineTo(-108, 25); - - boolean isEqual; - - try { - isEqual = GeometryEngine.equals(baseMp, compMp, sr); - } catch (IllegalArgumentException ex) { - isEqual = false; - } - - assertTrue(isEqual); - } - - @Test - public void testEqualsOnMultiPoints() { - SpatialReference sr = SpatialReference.create(4326); - - MultiPoint baseMp = new MultiPoint(); - MultiPoint compMp = new MultiPoint(); - - baseMp.add(new Point(-116, 40)); - baseMp.add(new Point(-120, 39)); - baseMp.add(new Point(-121, 10)); - baseMp.add(new Point(-130, 12)); - baseMp.add(new Point(-108, 25)); - - compMp.add(new Point(-116, 40)); - compMp.add(new Point(-120, 39)); - compMp.add(new Point(-121, 10)); - compMp.add(new Point(-130, 12)); - compMp.add(new Point(-108, 25)); - - boolean isEqual; - - try { - isEqual = GeometryEngine.equals(baseMp, compMp, sr); - } catch (IllegalArgumentException ex) { - isEqual = false; - } - - assertTrue(isEqual); - } + @Override + protected void setUp() throws Exception { + super.setUp(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + } + + @Test + public void testEqualsOnEnvelopes() { + SpatialReference sr = SpatialReference.create(4326); + + Point p = new Point(-130, 10); + Envelope env = new Envelope(p, 12, 12); + Envelope env2 = new Envelope(-136, 4, -124, 16); + + boolean isEqual; + try { + isEqual = GeometryEngine.equals(env, env2, sr); + + } catch (IllegalArgumentException ex) { + isEqual = false; + } + assertTrue(isEqual); + } + + @Test + public void testEqualsOnPoints() { + SpatialReference sr = SpatialReference.create(4326); + + Point p1 = new Point(-116, 40); + @SuppressWarnings("unused") + Point p2 = new Point(-120, 39); + @SuppressWarnings("unused") + Point p3 = new Point(-121, 10); + @SuppressWarnings("unused") + Point p4 = new Point(-130, 12); + @SuppressWarnings("unused") + Point p5 = new Point(-108, 25); + + Point p12 = new Point(-116, 40); + @SuppressWarnings("unused") + Point p22 = new Point(-120, 39); + @SuppressWarnings("unused") + Point p32 = new Point(-121, 10); + @SuppressWarnings("unused") + Point p42 = new Point(-130, 12); + @SuppressWarnings("unused") + Point p52 = new Point(-108, 25); + + boolean isEqual1 = false; + boolean isEqual2 = false; + boolean isEqual3 = false; + boolean isEqual4 = false; + boolean isEqual5 = false; + + try { + isEqual1 = GeometryEngine.equals(p1, p12, sr); + isEqual2 = GeometryEngine.equals(p1, p12, sr); + isEqual3 = GeometryEngine.equals(p1, p12, sr); + isEqual4 = GeometryEngine.equals(p1, p12, sr); + isEqual5 = GeometryEngine.equals(p1, p12, sr); + } catch (IllegalArgumentException ex) { + + } + + assertTrue(isEqual1 && isEqual2 && isEqual3 && isEqual4 && isEqual5); + } + + @Test + public void testEqualsOnPolygons() { + SpatialReference sr = SpatialReference.create(4326); + + Polygon baseMp = new Polygon(); + Polygon compMp = new Polygon(); + + baseMp.startPath(-116, 40); + baseMp.lineTo(-120, 39); + baseMp.lineTo(-121, 10); + baseMp.lineTo(-130, 12); + baseMp.lineTo(-108, 25); + + compMp.startPath(-116, 40); + compMp.lineTo(-120, 39); + compMp.lineTo(-121, 10); + compMp.lineTo(-130, 12); + compMp.lineTo(-108, 25); + + boolean isEqual; + + try { + isEqual = GeometryEngine.equals(baseMp, compMp, sr); + + } catch (IllegalArgumentException ex) { + isEqual = false; + } + + assertTrue(isEqual); + } + + @Test + public void testEqualsOnPolylines() { + SpatialReference sr = SpatialReference.create(4326); + + Polyline baseMp = new Polyline(); + Polyline compMp = new Polyline(); + + baseMp.startPath(-116, 40); + baseMp.lineTo(-120, 39); + baseMp.lineTo(-121, 10); + baseMp.lineTo(-130, 12); + baseMp.lineTo(-108, 25); + + compMp.startPath(-116, 40); + compMp.lineTo(-120, 39); + compMp.lineTo(-121, 10); + compMp.lineTo(-130, 12); + compMp.lineTo(-108, 25); + + boolean isEqual; + + try { + isEqual = GeometryEngine.equals(baseMp, compMp, sr); + } catch (IllegalArgumentException ex) { + isEqual = false; + } + + assertTrue(isEqual); + } + + @Test + public void testEqualsOnMultiPoints() { + SpatialReference sr = SpatialReference.create(4326); + + MultiPoint baseMp = new MultiPoint(); + MultiPoint compMp = new MultiPoint(); + + baseMp.add(new Point(-116, 40)); + baseMp.add(new Point(-120, 39)); + baseMp.add(new Point(-121, 10)); + baseMp.add(new Point(-130, 12)); + baseMp.add(new Point(-108, 25)); + + compMp.add(new Point(-116, 40)); + compMp.add(new Point(-120, 39)); + compMp.add(new Point(-121, 10)); + compMp.add(new Point(-130, 12)); + compMp.add(new Point(-108, 25)); + + boolean isEqual; + + try { + isEqual = GeometryEngine.equals(baseMp, compMp, sr); + } catch (IllegalArgumentException ex) { + isEqual = false; + } + + assertTrue(isEqual); + } } diff --git a/src/test/java/com/esri/core/geometry/TestEstimateMemorySize.java b/src/test/java/com/esri/core/geometry/TestEstimateMemorySize.java index 64d2bfc2..b1b40b22 100644 --- a/src/test/java/com/esri/core/geometry/TestEstimateMemorySize.java +++ b/src/test/java/com/esri/core/geometry/TestEstimateMemorySize.java @@ -1,5 +1,30 @@ -package com.esri.core.geometry; +/* + Copyright 1995-2018 Esri + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + For additional information, contact: + Environmental Systems Research Institute, Inc. + Attn: Contracts Dept + 380 New York Street + Redlands, California, USA 92373 + + email: contracts@esri.com + */ + + package com.esri.core.geometry; + +import com.esri.core.geometry.Geometry.GeometryAccelerationDegree; import com.esri.core.geometry.ogc.OGCConcreteGeometryCollection; import com.esri.core.geometry.ogc.OGCGeometry; import com.esri.core.geometry.ogc.OGCLineString; @@ -42,6 +67,14 @@ public void testInstanceSizes() { assertEquals(getInstanceSize(OGCMultiPolygon.class), SizeOf.SIZE_OF_OGC_MULTI_POLYGON); assertEquals(getInstanceSize(OGCPoint.class), SizeOf.SIZE_OF_OGC_POINT); assertEquals(getInstanceSize(OGCPolygon.class), SizeOf.SIZE_OF_OGC_POLYGON); + assertEquals(getInstanceSize(RasterizedGeometry2DImpl.class), SizeOf.SIZE_OF_RASTERIZED_GEOMETRY_2D_IMPL); + assertEquals(getInstanceSize(RasterizedGeometry2DImpl.ScanCallbackImpl.class), SizeOf.SIZE_OF_SCAN_CALLBACK_IMPL); + assertEquals(getInstanceSize(Transformation2D.class), SizeOf.SIZE_OF_TRANSFORMATION_2D); + assertEquals(getInstanceSize(SimpleRasterizer.class), SizeOf.SIZE_OF_SIMPLE_RASTERIZER); + assertEquals(getInstanceSize(SimpleRasterizer.Edge.class), SizeOf.SIZE_OF_EDGE); + assertEquals(getInstanceSize(QuadTreeImpl.class), SizeOf.SIZE_OF_QUAD_TREE_IMPL); + assertEquals(getInstanceSize(QuadTreeImpl.Data.class), SizeOf.SIZE_OF_DATA); + assertEquals(getInstanceSize(StridedIndexTypeCollection.class), SizeOf.SIZE_OF_STRIDED_INDEX_TYPE_COLLECTION); } private static long getInstanceSize(Class clazz) { @@ -53,29 +86,59 @@ public void testPoint() { testGeometry(parseWkt("POINT (1 2)")); } + @Test + public void testEmptyPoint() { + testGeometry(parseWkt("POINT EMPTY")); + } + @Test public void testMultiPoint() { testGeometry(parseWkt("MULTIPOINT (0 0, 1 1, 2 3)")); } @Test - public void testLineString() { + public void testEmptyMultiPoint() { + testGeometry(parseWkt("MULTIPOINT EMPTY")); + } + + @Test + public void testAcceleratedGeometry() { testGeometry(parseWkt("LINESTRING (0 1, 2 3, 4 5)")); } + @Test + public void testEmptyLineString() { + testGeometry(parseWkt("LINESTRING EMPTY")); + } + @Test public void testMultiLineString() { - testGeometry(parseWkt("MULTILINESTRING ((0 1, 2 3, 4 5), (1 1, 2 2))")); + testAcceleratedGeometry(parseWkt("MULTILINESTRING ((0 1, 2 3, 4 5), (1 1, 2 2))")); + } + + @Test + public void testEmptyMultiLineString() { + testGeometry(parseWkt("MULTILINESTRING EMPTY")); } @Test public void testPolygon() { - testGeometry(parseWkt("POLYGON ((30 10, 40 40, 20 40, 10 20, 30 10))")); + testAcceleratedGeometry(parseWkt("POLYGON ((30 10, 40 40, 20 40, 10 20, 30 10))")); + } + + @Test + public void testEmptyPolygon() { + testGeometry(parseWkt("POLYGON EMPTY")); } @Test public void testMultiPolygon() { - testGeometry(parseWkt("MULTIPOLYGON (((30 20, 45 40, 10 40, 30 20)), ((15 5, 40 10, 10 20, 5 10, 15 5)))")); + testAcceleratedGeometry(parseWkt("MULTIPOLYGON (((30 20, 45 40, 10 40, 30 20)), ((15 5, 40 10, 10 20, 5 10, 15 5)))")); + } + + @Test + public void testEmptyMultiPolygon() { + testGeometry(parseWkt("MULTIPOLYGON EMPTY")); } @Test @@ -83,10 +146,45 @@ public void testGeometryCollection() { testGeometry(parseWkt("GEOMETRYCOLLECTION (POINT(4 6), LINESTRING(4 6,7 10))")); } + @Test + public void testEmptyGeometryCollection() { + testGeometry(parseWkt("GEOMETRYCOLLECTION EMPTY")); + } + private void testGeometry(OGCGeometry geometry) { assertTrue(geometry.estimateMemorySize() > 0); } + private void testAcceleratedGeometry(OGCGeometry geometry) { + long initialSize = geometry.estimateMemorySize(); + assertTrue(initialSize > 0); + + Envelope envelope = new Envelope(); + geometry.getEsriGeometry().queryEnvelope(envelope); + + long withEnvelopeSize = geometry.estimateMemorySize(); + assertTrue(withEnvelopeSize > initialSize); + + accelerate(geometry, GeometryAccelerationDegree.enumMild); + long mildAcceleratedSize = geometry.estimateMemorySize(); + assertTrue(mildAcceleratedSize > withEnvelopeSize); + + accelerate(geometry, GeometryAccelerationDegree.enumMedium); + long mediumAcceleratedSize = geometry.estimateMemorySize(); + assertTrue(mediumAcceleratedSize > mildAcceleratedSize); + + accelerate(geometry, GeometryAccelerationDegree.enumHot); + long hotAcceleratedSize = geometry.estimateMemorySize(); + assertTrue(hotAcceleratedSize > mediumAcceleratedSize); + } + + private void accelerate(OGCGeometry geometry, GeometryAccelerationDegree accelerationDegree) + { + Operator relateOperator = OperatorFactoryLocal.getInstance().getOperator(Operator.Type.Relate); + boolean accelerated = relateOperator.accelerateGeometry(geometry.getEsriGeometry(), geometry.getEsriSpatialReference(), accelerationDegree); + assertTrue(accelerated); + } + private static OGCGeometry parseWkt(String wkt) { OGCGeometry geometry = OGCGeometry.fromText(wkt); geometry.setSpatialReference(null); diff --git a/src/test/java/com/esri/core/geometry/TestFailed.java b/src/test/java/com/esri/core/geometry/TestFailed.java index f8c8875c..05bede19 100644 --- a/src/test/java/com/esri/core/geometry/TestFailed.java +++ b/src/test/java/com/esri/core/geometry/TestFailed.java @@ -28,61 +28,61 @@ import org.junit.Test; public class TestFailed extends TestCase { - @Override - protected void setUp() throws Exception { - super.setUp(); - } + @Override + protected void setUp() throws Exception { + super.setUp(); + } - @Override - protected void tearDown() throws Exception { - super.tearDown(); - } + @Override + protected void tearDown() throws Exception { + super.tearDown(); + } - @Test - public void testCenterXY() { - Envelope env = new Envelope(-130, 30, -70, 50); - assertEquals(-100, env.getCenterX(), 0); - assertEquals(40, env.getCenterY(), 0); - } + @Test + public void testCenterXY() { + Envelope env = new Envelope(-130, 30, -70, 50); + assertEquals(-100, env.getCenterX(), 0); + assertEquals(40, env.getCenterY(), 0); + } - @Test - public void testGeometryOperationSupport() { - Geometry baseGeom = new Point(-130, 10); - Geometry comparisonGeom = new Point(-130, 10); - SpatialReference sr = SpatialReference.create(4326); + @Test + public void testGeometryOperationSupport() { + Geometry baseGeom = new Point(-130, 10); + Geometry comparisonGeom = new Point(-130, 10); + SpatialReference sr = SpatialReference.create(4326); - @SuppressWarnings("unused") - Geometry diffGeom = null; - int noException = 1; // no exception - try { - diffGeom = GeometryEngine.difference(baseGeom, comparisonGeom, sr); + @SuppressWarnings("unused") + Geometry diffGeom = null; + int noException = 1; // no exception + try { + diffGeom = GeometryEngine.difference(baseGeom, comparisonGeom, sr); - } catch (IllegalArgumentException ex) { - noException = 0; - } catch (GeometryException ex) { - noException = 0; - } - assertEquals(noException, 1); - } + } catch (IllegalArgumentException ex) { + noException = 0; + } catch (GeometryException ex) { + noException = 0; + } + assertEquals(noException, 1); + } - @Test - public void TestIntersection() { - OperatorIntersects op = (OperatorIntersects) OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Intersects); - Polygon polygon = new Polygon(); - // outer ring1 - polygon.startPath(0, 0); - polygon.lineTo(10, 10); - polygon.lineTo(20, 0); + @Test + public void TestIntersection() { + OperatorIntersects op = (OperatorIntersects) OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Intersects); + Polygon polygon = new Polygon(); + // outer ring1 + polygon.startPath(0, 0); + polygon.lineTo(10, 10); + polygon.lineTo(20, 0); - Point point1 = new Point(15, 10); - Point point2 = new Point(2, 10); - Point point3 = new Point(5, 5); - boolean res = op.execute(polygon, point1, null, null); - assertTrue(!res); - res = op.execute(polygon, point2, null, null); - assertTrue(!res); - res = op.execute(polygon, point3, null, null); - assertTrue(res); - } + Point point1 = new Point(15, 10); + Point point2 = new Point(2, 10); + Point point3 = new Point(5, 5); + boolean res = op.execute(polygon, point1, null, null); + assertTrue(!res); + res = op.execute(polygon, point2, null, null); + assertTrue(!res); + res = op.execute(polygon, point3, null, null); + assertTrue(res); + } } diff --git a/src/test/java/com/esri/core/geometry/TestGeneralize.java b/src/test/java/com/esri/core/geometry/TestGeneralize.java index f8e99d0d..259c2a6c 100644 --- a/src/test/java/com/esri/core/geometry/TestGeneralize.java +++ b/src/test/java/com/esri/core/geometry/TestGeneralize.java @@ -28,222 +28,222 @@ import org.junit.Test; public class TestGeneralize extends TestCase { - @Override - protected void setUp() throws Exception { - super.setUp(); - } - - @Override - protected void tearDown() throws Exception { - super.tearDown(); - } - - @Test - public void test1() { - OperatorFactoryLocal engine = OperatorFactoryLocal.getInstance(); - OperatorGeneralize op = (OperatorGeneralize) engine.getOperator(Operator.Type.Generalize); - - Polygon poly = new Polygon(); - poly.startPath(0, 0); - poly.lineTo(1, 1); - poly.lineTo(2, 0); - poly.lineTo(3, 2); - poly.lineTo(4, 1); - poly.lineTo(5, 0); - poly.lineTo(5, 10); - poly.lineTo(0, 10); - Geometry geom = op.execute(poly, 2, true, null); - Polygon p = (Polygon) geom; - Point2D[] points = p.getCoordinates2D(); - assertTrue(points.length == 4); - assertTrue(points[0].x == 0 && points[0].y == 0); - assertTrue(points[1].x == 5 && points[1].y == 0); - assertTrue(points[2].x == 5 && points[2].y == 10); - assertTrue(points[3].x == 0 && points[3].y == 10); - - Geometry geom1 = op.execute(geom, 5, false, null); - p = (Polygon) geom1; - points = p.getCoordinates2D(); - assertTrue(points.length == 3); - assertTrue(points[0].x == 0 && points[0].y == 0); - assertTrue(points[1].x == 5 && points[1].y == 10); - assertTrue(points[2].x == 5 && points[2].y == 10); - - geom1 = op.execute(geom, 5, true, null); - p = (Polygon) geom1; - points = p.getCoordinates2D(); - assertTrue(points.length == 0); - } - - @Test - public void test2() { - OperatorFactoryLocal engine = OperatorFactoryLocal.getInstance(); - OperatorGeneralize op = (OperatorGeneralize) engine.getOperator(Operator.Type.Generalize); - - Polyline polyline = new Polyline(); - polyline.startPath(0, 0); - polyline.lineTo(1, 1); - polyline.lineTo(2, 0); - polyline.lineTo(3, 2); - polyline.lineTo(4, 1); - polyline.lineTo(5, 0); - polyline.lineTo(5, 10); - polyline.lineTo(0, 10); - Geometry geom = op.execute(polyline, 2, true, null); - Polyline p = (Polyline) geom; - Point2D[] points = p.getCoordinates2D(); - assertTrue(points.length == 4); - assertTrue(points[0].x == 0 && points[0].y == 0); - assertTrue(points[1].x == 5 && points[1].y == 0); - assertTrue(points[2].x == 5 && points[2].y == 10); - assertTrue(points[3].x == 0 && points[3].y == 10); - - Geometry geom1 = op.execute(geom, 5, false, null); - p = (Polyline) geom1; - points = p.getCoordinates2D(); - assertTrue(points.length == 2); - assertTrue(points[0].x == 0 && points[0].y == 0); - assertTrue(points[1].x == 0 && points[1].y == 10); - - geom1 = op.execute(geom, 5, true, null); - p = (Polyline) geom1; - points = p.getCoordinates2D(); - assertTrue(points.length == 2); - assertTrue(points[0].x == 0 && points[0].y == 0); - assertTrue(points[1].x == 0 && points[1].y == 10); - } - - @Test - public void testLargeDeviation() { - { - Polygon input_polygon = new Polygon(); - input_polygon - .addEnvelope(Envelope2D.construct(0, 0, 20, 10), false); - Geometry densified_geom = OperatorDensifyByLength.local().execute( - input_polygon, 1, null); - - Geometry geom = OperatorGeneralize.local().execute( - densified_geom, - 1, - true, - null); - - int pc = ((MultiPath) geom).getPointCount(); - assertTrue(pc == 4); - - Geometry large_dev1 = OperatorGeneralize.local().execute( - densified_geom, - 40, - true, - null); - - int pc1 = ((MultiPath) large_dev1).getPointCount(); - assertTrue(pc1 == 0); - - Geometry large_dev2 = OperatorGeneralize.local().execute( - densified_geom, 40, false, null); - int pc2 = ((MultiPath) large_dev2).getPointCount(); - assertTrue(pc2 == 3); - } - } - - @Test - public void test1Area() { - OperatorFactoryLocal engine = OperatorFactoryLocal.getInstance(); - OperatorGeneralizeByArea op = (OperatorGeneralizeByArea) engine.getOperator(Operator.Type.GeneralizeByArea); - - assertNotNull(op); - - Polygon poly = new Polygon(); - poly.startPath(0, 0); - poly.lineTo(1, 1); - poly.lineTo(2, 0); - poly.lineTo(3, 2); - poly.lineTo(4, 1); - poly.lineTo(5, 0); - poly.lineTo(5, 10); - poly.lineTo(0, 10); - poly = (Polygon) GeometryEngine.simplify(poly, SpatialReference.create(4326)); - String words2 = GeometryEngine.geometryToWkt(poly, 0); - Geometry geom = op.execute(poly, 50.0, true, GeneralizeType.Neither, SpatialReference.create(4326), null); - String words = GeometryEngine.geometryToWkt(geom, 0); - assertNotNull(geom); - Polygon p = (Polygon) geom; - Point2D[] points = p.getCoordinates2D(); - assertTrue(points.length == 4); - assertTrue(points[0].x == 0 && points[0].y == 0); - assertTrue(points[1].x == 0 && points[1].y == 10); - assertTrue(points[2].x == 5 && points[2].y == 10); - assertTrue(points[3].x == 5 && points[3].y == 0); - - OperatorContains operatorContains = (OperatorContains) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.Contains); - - Geometry geomContainer = op.execute(poly, 35, true, GeneralizeType.ResultContainsOriginal, SpatialReference.create(4326),null); - words = GeometryEngine.geometryToWkt(geomContainer, 0); - assertTrue(operatorContains.execute(geomContainer, poly, null, null)); - - Geometry geomContained = op.execute(poly, 30, true, GeneralizeType.ResultWithinOriginal, SpatialReference.create(4326),null); - assertTrue(operatorContains.execute(poly, geomContained, null, null)); - } - - @Test - public void testTreapTriangleManagement() { - Geometry geom = GeometryEngine.geometryFromWkt("POLYGON ((-70.651656936570745 43.135157834585826,-70.651570654984525 43.135150076925918,-70.651511247908587 43.135155437576621,-70.651490101488349 43.135169249238288,-70.651490181628759 43.135200763774868,-70.651510336532638 43.135249995303397,-70.651530872098633 43.135299226354952,-70.651527230781454 43.13533529757845,-70.651492643684321 43.135349305799508,-70.651420172717224 43.135354852495823,-70.651358095085072 43.135346745253884,-70.651247805462717 43.1353033127629,-70.651151361236941 43.135246176463966,-70.651124154255413 43.135206047556842,-70.651131534466685 43.135151913051203,-70.651155914561755 43.135115542493892,-70.651228730259774 43.135051460048707,-70.651305024993519 43.134973818456416,-70.651360674948108 43.134914489191551,-70.651385078643216 43.134864606853156,-70.651402827815218 43.134810322639233,-70.651410310326284 43.134688652284062,-70.651418383361829 43.134517448375689,-70.651411370788409 43.134413996600074,-70.651390876709428 43.134337752182525,-70.651346755889904 43.134225832686319,-70.651289063395154 43.134109606122337,-70.651241242017051 43.133988734078358,-70.651230854601764 43.133916846697829,-70.651221013347353 43.133822439140715,-70.651200519724128 43.133746194674302,-70.651218268699594 43.133691907971006,-70.651249886578313 43.133610413350418,-70.651273539332081 43.133547040518167,-70.651322422674269 43.133478800504768,-70.651363984222755 43.133424172537978,-70.651409243106613 43.133378494590104,-70.651437060507462 43.133355583224628,-70.651492145648632 43.133332275678633,-70.651599176252716 43.133326227462319,-70.651675204034788 43.133338636120527,-70.65179240423565 43.133381970944697,-70.651905761872953 43.133425353603045,-70.652022336036893 43.133459688797871,-70.652087607730962 43.133472252516562,-70.652149929372143 43.133489361765591,-70.652232540703992 43.133546699550045,-70.652400720753761 43.133656829257461,-70.652544825855031 43.133771806958798,-70.652698657471404 43.133891149422396,-70.652757214424 43.133939825915917,-70.652829643131227 43.133961291723317,-70.652898471779253 43.133991812912122,-70.652963804959569 43.134049399817712,-70.652994471176711 43.134089475795044,-70.653000937222828 43.134129903976664,-70.653000836372897 43.134197439788288,-70.652972837499135 43.134256375321229,-70.652903321638362 43.134342923487154,-70.652853489821567 43.134447199036558,-70.652811504521395 43.134528843881576,-70.652776716073816 43.134592380423527,-70.652745241323998 43.134664872485907,-70.652703717209832 43.134692485155824,-70.65263790191085 43.134702441934749,-70.652537796343609 43.13469488220742,-70.652481986521252 43.134691185475688,-70.652416288981371 43.134705643385693,-70.652347112331768 43.134733655368471,-70.652274294763117 43.134797738553125,-70.652239263183958 43.134852272522785,-70.652214826278225 43.134929165745028,-70.652217533236211 43.135001163954207,-70.652248296977746 43.135059250554882,-70.652327397729081 43.135157158057844,-70.652414500765317 43.135209927851037,-70.6524582645621 43.135222802033766,-70.652470512866358 43.135249637832572,-70.652646824360005 43.135404671730349,-70.652680946443695 43.135444700365824,-70.652691113545444 43.135494075980539,-70.652680299690047 43.135534756334458,-70.652642334694633 43.135580326883741,-70.6525831461027 43.135608197219,-70.65250042683256 43.135618395612582,-70.652403778584315 43.1356107883392,-70.652328034290349 43.135580366756479,-70.652207940292428 43.135501055652128,-70.652084166050003 43.135399292820672,-70.651994153636025 43.135324055019495,-70.651897729053019 43.13525341019011,-70.651815354685922 43.135205077192047,-70.651746646220062 43.135179051560065,-70.651656936570745 43.135157834585826))", 0, Geometry.Type.Unknown); - geom = GeometryEngine.simplify(geom, SpatialReference.create(4326)); - - OperatorFactoryLocal engine = OperatorFactoryLocal.getInstance(); - OperatorGeneralizeByArea op = (OperatorGeneralizeByArea) engine.getOperator(Operator.Type.GeneralizeByArea); - OperatorContains operatorContains = (OperatorContains) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.Contains); - - Geometry geomContainer = op.execute(geom, 15, true, GeneralizeType.ResultContainsOriginal, SpatialReference.create(4326),null); - String words = GeometryEngine.geometryToWkt(geomContainer, 0); - assertTrue(operatorContains.execute(geomContainer, geom, null, null)); - } - - @Test - public void testCompleteRemoval() { - - OperatorFactoryLocal engine = OperatorFactoryLocal.getInstance(); - OperatorGeneralizeByArea op = (OperatorGeneralizeByArea) engine.getOperator(Operator.Type.GeneralizeByArea); - - assertNotNull(op); - - Polygon poly = new Polygon(); - poly.startPath(0, 0); - poly.lineTo(1, 1); - poly.lineTo(2, 0); - poly.lineTo(3, 2); - poly.lineTo(4, 1); - poly.lineTo(5, 0); - poly.lineTo(5, 10); - poly.lineTo(0, 10); - Geometry geom = op.execute(poly, 100.0, true, GeneralizeType.Neither, SpatialReference.create(4326),null); - assertTrue(geom.isEmpty()); - } - - - @Test - public void testNonSimple() { - String wktInput = "MULTIPOLYGON (((5 -2, 5.1308062584602858 -1.9957178464772056, 5.2610523844401031 -1.9828897227476183, 5.3901806440322559 -1.9615705608064609, 5.5176380902050415 -1.9318516525781355, 5.6428789306063223 -1.8938602589902089, 5.7427813527082074 -1.8569533817705199, 30.742781352708207 8.1430466182294818, 30.765366864730179 8.1522409349774279, 30.884577380438003 8.2062545169346244, 31 8.2679491924311233, 31.111140466039203 8.3370607753949102, 31.217522858017439 8.4132933194175301, 31.318691630200139 8.4963203850420452, 31.414213562373096 8.585786437626906, 31.503679614957953 8.6813083697998632, 31.58670668058247 8.7824771419825591, 31.66293922460509 8.8888595339607956, 31.732050807568879 9, 31.788854381999833 9.1055728090000834, 36.788854381999833 19.105572809000083, 36.793745483065379 19.115422619561997, 36.847759065022572 19.234633135269821, 36.893860258990209 19.357121069393678, 36.931851652578139 19.48236190979496, 36.961570560806464 19.609819355967744, 36.982889722747622 19.738947615559898, 36.995717846477206 19.869193741539714, 37 20, 36.995717846477206 20.130806258460286, 36.982889722747622 20.261052384440102, 36.961570560806457 20.390180644032256, 36.931851652578132 20.51763809020504, 36.893860258990209 20.642878930606322, 36.847759065022572 20.765366864730179, 36.793745483065379 20.884577380438003, 36.788854381999833 20.894427190999917, 31.788854381999833 30.894427190999917, 31.732050807568875 31, 31.66293922460509 31.111140466039203, 31.58670668058247 31.217522858017439, 31.503679614957953 31.318691630200135, 31.414213562373096 31.414213562373092, 31.318691630200139 31.503679614957953, 31.217522858017443 31.58670668058247, 31.111140466039203 31.66293922460509, 31 31.732050807568875, 30.884577380438003 31.793745483065376, 30.765366864730179 31.847759065022572, 30.642878930606322 31.893860258990209, 30.568176659382747 31.917596225416773, 3.5681766593827478 39.917596225416773, 3.5176380902050415 39.931851652578132, 3.3901806440322564 39.961570560806464, 3.2610523844401031 39.982889722747622, 3.1308062584602863 39.995717846477206, 3 40, 2.8691937415397142 39.995717846477206, 2.7389476155598973 39.982889722747615, 2.6098193559677441 39.961570560806464, 2.482361909794959 39.931851652578132, 2.3571210693936773 39.893860258990209, 2.2346331352698212 39.847759065022572, 2.1154226195619983 39.793745483065379, 2.0000000000000009 39.732050807568875, 1.8888595339607963 39.66293922460509, 1.7824771419825594 39.586706680582466, 1.681308369799863 39.503679614957953, 1.5857864376269055 39.414213562373092, 1.4963203850420457 39.318691630200135, 1.4132933194175301 39.217522858017446, 1.33706077539491 39.111140466039203, 1.267949192431123 39, 1.2062545169346237 38.884577380438003, 1.1522409349774267 38.765366864730183, 1.1061397410097888 38.642878930606322, 1.0681483474218634 38.51763809020504, 1.0384294391935391 38.390180644032256, 1.0171102772523792 38.261052384440106, 1.004282153522793 38.130806258460282, 1 38, 1.0042821535227944 37.869193741539718, 1.0171102772523806 37.738947615559894, 1.0384294391935405 37.609819355967744, 1.0681483474218647 37.48236190979496, 1.1061397410097897 37.357121069393678, 1.1522409349774274 37.234633135269817, 1.2062545169346244 37.115422619561997, 1.2679491924311235 37, 1.3370607753949102 36.888859533960797, 1.4132933194175301 36.782477141982561, 1.4963203850420457 36.681308369799865, 1.5857864376269053 36.585786437626908, 1.6813083697998625 36.496320385042047, 1.7824771419825589 36.413293319417534, 1.8888595339607956 36.33706077539491, 2 36.267949192431118, 2.1154226195619974 36.206254516934621, 2.2346331352698208 36.152240934977428, 2.3571210693936768 36.106139741009784, 2.4318233406172522 36.082403774583227, 28.599409577746219 28.329044889507976, 32.763932022500207 20, 28.551206229908889 11.574548414817356, 6.3845784837230717 2.7078973163430327, 6.3268887828044376 2.9386561200175683, 19.26118525018893 13.447771999767468, 19.318691630200139 13.496320385042045, 19.414213562373096 13.585786437626906, 19.503679614957953 13.681308369799863, 19.58670668058247 13.782477141982559, 19.66293922460509 13.888859533960796, 19.732050807568879 14, 19.793745483065376 14.115422619561997, 19.847759065022572 14.234633135269821, 19.893860258990212 14.357121069393678, 19.931851652578136 14.482361909794959, 19.961570560806461 14.609819355967744, 19.982889722747622 14.738947615559898, 19.995717846477206 14.869193741539714, 20 15, 19.995717846477206 15.130806258460286, 19.982889722747618 15.261052384440102, 19.961570560806461 15.390180644032256, 19.931851652578136 15.517638090205041, 19.893860258990209 15.642878930606322, 19.847759065022572 15.765366864730179, 19.793745483065376 15.884577380438001, 19.732050807568875 16, 19.66293922460509 16.111140466039203, 19.58670668058247 16.217522858017439, 19.503679614957953 16.318691630200135, 19.414213562373096 16.414213562373092, 19.318691630200139 16.503679614957953, 19.217522858017443 16.58670668058247, 19.111140466039203 16.66293922460509, 19 16.732050807568875, 18.884577380438003 16.793745483065376, 18.765366864730179 16.847759065022572, 18.642878930606322 16.893860258990209, 18.51763809020504 16.931851652578139, 18.390180644032256 16.961570560806461, 18.261052384440102 16.982889722747622, 18.130806258460286 16.995717846477206, 18 17, 17.869193741539714 16.995717846477206, 17.738947615559898 16.982889722747622, 17.609819355967744 16.961570560806457, 17.48236190979496 16.931851652578136, 17.357121069393678 16.893860258990209, 17.234633135269821 16.847759065022572, 17.115422619561997 16.793745483065376, 17 16.732050807568875, 16.888859533960797 16.66293922460509, 16.782477141982561 16.58670668058247, 16.73881474981107 16.552228000232532, 5.2559522566699819 7.2224022245553954, 1.9402850002906638 20.485071250072664, 1.9318516525781353 20.51763809020504, 1.8938602589902103 20.642878930606322, 1.8477590650225726 20.765366864730179, 1.7937454830653756 20.884577380438003, 1.7320508075688765 21, 1.6629392246050898 21.111140466039203, 1.5867066805824699 21.217522858017439, 1.5036796149579543 21.318691630200139, 1.4142135623730947 21.414213562373096, 1.3186916302001375 21.503679614957953, 1.2175228580174411 21.58670668058247, 1.1111404660392044 21.66293922460509, 0.99999999999999989 21.732050807568879, 0.88457738043800249 21.793745483065376, 0.76536686473017945 21.847759065022572, 0.64287893060632306 21.893860258990212, 0.51763809020504148 21.931851652578136, 0.3901806440322565 21.961570560806461, 0.26105238444010315 21.982889722747622, 0.13080625846028612 21.995717846477206, 0 22, -0.13080625846028585 21.995717846477206, -0.26105238444010281 21.982889722747618, -0.39018064403225611 21.961570560806461, -0.51763809020504103 21.931851652578136, -0.64287893060632262 21.893860258990209, -0.7653668647301789 21.847759065022572, -0.88457738043800183 21.793745483065376, -0.99999999999999922 21.732050807568875, -1.1111404660392037 21.66293922460509, -1.2175228580174406 21.58670668058247, -1.318691630200137 21.503679614957953, -1.4142135623730945 21.414213562373096, -1.5036796149579543 21.318691630200139, -1.5867066805824699 21.217522858017443, -1.66293922460509 21.111140466039203, -1.732050807568877 21, -1.7937454830653763 20.884577380438003, -1.8477590650225733 20.765366864730179, -1.8938602589902112 20.642878930606322, -1.9318516525781366 20.51763809020504, -1.9615705608064609 20.390180644032256, -1.9828897227476208 20.261052384440102, -1.995717846477207 20.130806258460286, -2 20, -1.9957178464772056 19.869193741539714, -1.9828897227476194 19.738947615559898, -1.9615705608064595 19.609819355967744, -1.9402850002906638 19.514928749927336, 1.4516369470040571 5.947240960748454, 1.3901806440322564 5.9615705608064609, 1.2610523844401031 5.982889722747621, 1.130806258460286 5.9957178464772074, 1 6, 0.86919374153971418 5.9957178464772056, 0.73894761555989719 5.9828897227476192, 0.60981935596774384 5.9615705608064591, 0.48236190979495897 5.9318516525781355, 0.35712106939367738 5.8938602589902107, 0.2346331352698211 5.8477590650225721, 0.11542261956199817 5.7937454830653756, 7.7715611723760958E-16 5.7320508075688767, -0.11114046603920369 5.6629392246050898, -0.21752285801744065 5.5867066805824699, -0.31869163020013702 5.5036796149579548, -0.41421356237309448 5.4142135623730949, -0.50367961495795432 5.3186916302001377, -0.58670668058246989 5.2175228580174409, -0.66293922460509003 5.1111404660392044, -0.73205080756887697 5, -0.79374548306537629 4.8845773804380022, -0.84775906502257325 4.7653668647301792, -0.89386025899021115 4.6428789306063232, -0.93185165257813662 4.5176380902050415, -0.96157056080646086 4.3901806440322568, -0.98288972274762076 4.2610523844401031, -0.99571784647720696 4.1308062584602858, -1 4, -0.99571784647720563 3.8691937415397142, -0.98288972274761943 3.7389476155598973, -0.96157056080645953 3.6098193559677441, -0.93185165257813529 3.482361909794959, -0.89386025899021027 3.3571210693936773, -0.84775906502257259 3.2346331352698212, -0.79374548306537562 3.1154226195619983, -0.78885438199983171 3.1055728090000843, 0.21114561800016829 1.1055728090000843, 0.26794919243112347 1.0000000000000009, 0.33706077539491019 0.88885953396079653, 0.41329331941753011 0.78247714198255913, 0.49632038504204568 0.6813083697998632, 0.5857864376269053 0.58578643762690552, 0.68130836979986253 0.49632038504204568, 0.78247714198255891 0.41329331941753011, 0.88885953396079564 0.33706077539491019, 1 0.26794919243112325, 1.1154226195619974 0.20625451693462349, 1.2346331352698205 0.15224093497742697, 1.3571210693936768 0.10613974100978885, 1.4823619097949585 0.068148347421863598, 1.6098193559677436 0.038429439193539139, 1.7389476155598969 0.017110277252379014, 1.8691937415397137 0.0042821535227930418, 2 0, 2.1308062584602858 0.0042821535227943741, 2.2610523844401027 0.01711027725238079, 2.3901806440322559 0.038429439193540471, 2.517638090205041 0.068148347421864486, 2.6428789306063227 0.10613974100978973, 2.7653668647301788 0.15224093497742741, 2.8845773804380017 0.20625451693462438, 2.8866117144161265 0.20734189110017509, 3.0597149997093362 -0.48507125007266438, 3.0681483474218645 -0.5176380902050397, 3.1061397410097897 -0.64287893060632229, 3.1522409349774274 -0.76536686473017923, 3.2062545169346244 -0.88457738043800305, 3.2679491924311233 -1, 3.3370607753949102 -1.1111404660392026, 3.4132933194175301 -1.2175228580174391, 3.4963203850420457 -1.3186916302001386, 3.5857864376269051 -1.4142135623730958, 3.6813083697998623 -1.503679614957953, 3.7824771419825591 -1.5867066805824699, 3.8888595339607956 -1.6629392246050898, 4 -1.7320508075688785, 4.1154226195619978 -1.7937454830653756, 4.2346331352698208 -1.8477590650225721, 4.3571210693936768 -1.8938602589902125, 4.4823619097949585 -1.9318516525781355, 4.6098193559677432 -1.9615705608064609, 4.7389476155598969 -1.9828897227476219, 4.8691937415397142 -1.9957178464772056, 5 -2)))"; - double percentReduce = 60; - boolean removedDegenerates = true; - GeneralizeType generalizeType = GeneralizeType.ResultContainsOriginal; - Geometry geometry = ((OperatorGeneralizeByArea)OperatorFactoryLocal - .getInstance() - .getOperator(Operator.Type.GeneralizeByArea)) - .execute( - GeometryEngine.geometryFromWkt( - wktInput, - 0, - Geometry.Type.Unknown), - percentReduce, - removedDegenerates, - generalizeType, - SpatialReference.create(4326), - null); - - assertTrue(GeometryEngine.isSimple(geometry, SpatialReference.create(4326))); - // TODO fix this sample + @Override + protected void setUp() throws Exception { + super.setUp(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + } + + @Test + public void test1() { + OperatorFactoryLocal engine = OperatorFactoryLocal.getInstance(); + OperatorGeneralize op = (OperatorGeneralize) engine.getOperator(Operator.Type.Generalize); + + Polygon poly = new Polygon(); + poly.startPath(0, 0); + poly.lineTo(1, 1); + poly.lineTo(2, 0); + poly.lineTo(3, 2); + poly.lineTo(4, 1); + poly.lineTo(5, 0); + poly.lineTo(5, 10); + poly.lineTo(0, 10); + Geometry geom = op.execute(poly, 2, true, null); + Polygon p = (Polygon) geom; + Point2D[] points = p.getCoordinates2D(); + assertTrue(points.length == 4); + assertTrue(points[0].x == 0 && points[0].y == 0); + assertTrue(points[1].x == 5 && points[1].y == 0); + assertTrue(points[2].x == 5 && points[2].y == 10); + assertTrue(points[3].x == 0 && points[3].y == 10); + + Geometry geom1 = op.execute(geom, 5, false, null); + p = (Polygon) geom1; + points = p.getCoordinates2D(); + assertTrue(points.length == 3); + assertTrue(points[0].x == 0 && points[0].y == 0); + assertTrue(points[1].x == 5 && points[1].y == 10); + assertTrue(points[2].x == 5 && points[2].y == 10); + + geom1 = op.execute(geom, 5, true, null); + p = (Polygon) geom1; + points = p.getCoordinates2D(); + assertTrue(points.length == 0); + } + + @Test + public void test2() { + OperatorFactoryLocal engine = OperatorFactoryLocal.getInstance(); + OperatorGeneralize op = (OperatorGeneralize) engine.getOperator(Operator.Type.Generalize); + + Polyline polyline = new Polyline(); + polyline.startPath(0, 0); + polyline.lineTo(1, 1); + polyline.lineTo(2, 0); + polyline.lineTo(3, 2); + polyline.lineTo(4, 1); + polyline.lineTo(5, 0); + polyline.lineTo(5, 10); + polyline.lineTo(0, 10); + Geometry geom = op.execute(polyline, 2, true, null); + Polyline p = (Polyline) geom; + Point2D[] points = p.getCoordinates2D(); + assertTrue(points.length == 4); + assertTrue(points[0].x == 0 && points[0].y == 0); + assertTrue(points[1].x == 5 && points[1].y == 0); + assertTrue(points[2].x == 5 && points[2].y == 10); + assertTrue(points[3].x == 0 && points[3].y == 10); + + Geometry geom1 = op.execute(geom, 5, false, null); + p = (Polyline) geom1; + points = p.getCoordinates2D(); + assertTrue(points.length == 2); + assertTrue(points[0].x == 0 && points[0].y == 0); + assertTrue(points[1].x == 0 && points[1].y == 10); + + geom1 = op.execute(geom, 5, true, null); + p = (Polyline) geom1; + points = p.getCoordinates2D(); + assertTrue(points.length == 2); + assertTrue(points[0].x == 0 && points[0].y == 0); + assertTrue(points[1].x == 0 && points[1].y == 10); + } + + @Test + public void testLargeDeviation() { + { + Polygon input_polygon = new Polygon(); + input_polygon + .addEnvelope(Envelope2D.construct(0, 0, 20, 10), false); + Geometry densified_geom = OperatorDensifyByLength.local().execute( + input_polygon, 1, null); + + Geometry geom = OperatorGeneralize.local().execute( + densified_geom, + 1, + true, + null); + + int pc = ((MultiPath) geom).getPointCount(); + assertTrue(pc == 4); + + Geometry large_dev1 = OperatorGeneralize.local().execute( + densified_geom, + 40, + true, + null); + + int pc1 = ((MultiPath) large_dev1).getPointCount(); + assertTrue(pc1 == 0); + + Geometry large_dev2 = OperatorGeneralize.local().execute( + densified_geom, 40, false, null); + int pc2 = ((MultiPath) large_dev2).getPointCount(); + assertTrue(pc2 == 3); + } + } + + @Test + public void test1Area() { + OperatorFactoryLocal engine = OperatorFactoryLocal.getInstance(); + OperatorGeneralizeByArea op = (OperatorGeneralizeByArea) engine.getOperator(Operator.Type.GeneralizeByArea); + + assertNotNull(op); + + Polygon poly = new Polygon(); + poly.startPath(0, 0); + poly.lineTo(1, 1); + poly.lineTo(2, 0); + poly.lineTo(3, 2); + poly.lineTo(4, 1); + poly.lineTo(5, 0); + poly.lineTo(5, 10); + poly.lineTo(0, 10); + poly = (Polygon) GeometryEngine.simplify(poly, SpatialReference.create(4326)); + String words2 = GeometryEngine.geometryToWkt(poly, 0); + Geometry geom = op.execute(poly, 50.0, true, GeneralizeType.Neither, SpatialReference.create(4326), null); + String words = GeometryEngine.geometryToWkt(geom, 0); + assertNotNull(geom); + Polygon p = (Polygon) geom; + Point2D[] points = p.getCoordinates2D(); + assertTrue(points.length == 4); + assertTrue(points[0].x == 0 && points[0].y == 0); + assertTrue(points[1].x == 0 && points[1].y == 10); + assertTrue(points[2].x == 5 && points[2].y == 10); + assertTrue(points[3].x == 5 && points[3].y == 0); + + OperatorContains operatorContains = (OperatorContains) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.Contains); + + Geometry geomContainer = op.execute(poly, 35, true, GeneralizeType.ResultContainsOriginal, SpatialReference.create(4326), null); + words = GeometryEngine.geometryToWkt(geomContainer, 0); + assertTrue(operatorContains.execute(geomContainer, poly, null, null)); + + Geometry geomContained = op.execute(poly, 30, true, GeneralizeType.ResultWithinOriginal, SpatialReference.create(4326), null); + assertTrue(operatorContains.execute(poly, geomContained, null, null)); + } + + @Test + public void testTreapTriangleManagement() { + Geometry geom = GeometryEngine.geometryFromWkt("POLYGON ((-70.651656936570745 43.135157834585826,-70.651570654984525 43.135150076925918,-70.651511247908587 43.135155437576621,-70.651490101488349 43.135169249238288,-70.651490181628759 43.135200763774868,-70.651510336532638 43.135249995303397,-70.651530872098633 43.135299226354952,-70.651527230781454 43.13533529757845,-70.651492643684321 43.135349305799508,-70.651420172717224 43.135354852495823,-70.651358095085072 43.135346745253884,-70.651247805462717 43.1353033127629,-70.651151361236941 43.135246176463966,-70.651124154255413 43.135206047556842,-70.651131534466685 43.135151913051203,-70.651155914561755 43.135115542493892,-70.651228730259774 43.135051460048707,-70.651305024993519 43.134973818456416,-70.651360674948108 43.134914489191551,-70.651385078643216 43.134864606853156,-70.651402827815218 43.134810322639233,-70.651410310326284 43.134688652284062,-70.651418383361829 43.134517448375689,-70.651411370788409 43.134413996600074,-70.651390876709428 43.134337752182525,-70.651346755889904 43.134225832686319,-70.651289063395154 43.134109606122337,-70.651241242017051 43.133988734078358,-70.651230854601764 43.133916846697829,-70.651221013347353 43.133822439140715,-70.651200519724128 43.133746194674302,-70.651218268699594 43.133691907971006,-70.651249886578313 43.133610413350418,-70.651273539332081 43.133547040518167,-70.651322422674269 43.133478800504768,-70.651363984222755 43.133424172537978,-70.651409243106613 43.133378494590104,-70.651437060507462 43.133355583224628,-70.651492145648632 43.133332275678633,-70.651599176252716 43.133326227462319,-70.651675204034788 43.133338636120527,-70.65179240423565 43.133381970944697,-70.651905761872953 43.133425353603045,-70.652022336036893 43.133459688797871,-70.652087607730962 43.133472252516562,-70.652149929372143 43.133489361765591,-70.652232540703992 43.133546699550045,-70.652400720753761 43.133656829257461,-70.652544825855031 43.133771806958798,-70.652698657471404 43.133891149422396,-70.652757214424 43.133939825915917,-70.652829643131227 43.133961291723317,-70.652898471779253 43.133991812912122,-70.652963804959569 43.134049399817712,-70.652994471176711 43.134089475795044,-70.653000937222828 43.134129903976664,-70.653000836372897 43.134197439788288,-70.652972837499135 43.134256375321229,-70.652903321638362 43.134342923487154,-70.652853489821567 43.134447199036558,-70.652811504521395 43.134528843881576,-70.652776716073816 43.134592380423527,-70.652745241323998 43.134664872485907,-70.652703717209832 43.134692485155824,-70.65263790191085 43.134702441934749,-70.652537796343609 43.13469488220742,-70.652481986521252 43.134691185475688,-70.652416288981371 43.134705643385693,-70.652347112331768 43.134733655368471,-70.652274294763117 43.134797738553125,-70.652239263183958 43.134852272522785,-70.652214826278225 43.134929165745028,-70.652217533236211 43.135001163954207,-70.652248296977746 43.135059250554882,-70.652327397729081 43.135157158057844,-70.652414500765317 43.135209927851037,-70.6524582645621 43.135222802033766,-70.652470512866358 43.135249637832572,-70.652646824360005 43.135404671730349,-70.652680946443695 43.135444700365824,-70.652691113545444 43.135494075980539,-70.652680299690047 43.135534756334458,-70.652642334694633 43.135580326883741,-70.6525831461027 43.135608197219,-70.65250042683256 43.135618395612582,-70.652403778584315 43.1356107883392,-70.652328034290349 43.135580366756479,-70.652207940292428 43.135501055652128,-70.652084166050003 43.135399292820672,-70.651994153636025 43.135324055019495,-70.651897729053019 43.13525341019011,-70.651815354685922 43.135205077192047,-70.651746646220062 43.135179051560065,-70.651656936570745 43.135157834585826))", 0, Geometry.Type.Unknown); + geom = GeometryEngine.simplify(geom, SpatialReference.create(4326)); + + OperatorFactoryLocal engine = OperatorFactoryLocal.getInstance(); + OperatorGeneralizeByArea op = (OperatorGeneralizeByArea) engine.getOperator(Operator.Type.GeneralizeByArea); + OperatorContains operatorContains = (OperatorContains) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.Contains); + + Geometry geomContainer = op.execute(geom, 15, true, GeneralizeType.ResultContainsOriginal, SpatialReference.create(4326), null); + String words = GeometryEngine.geometryToWkt(geomContainer, 0); + assertTrue(operatorContains.execute(geomContainer, geom, null, null)); + } + + @Test + public void testCompleteRemoval() { + + OperatorFactoryLocal engine = OperatorFactoryLocal.getInstance(); + OperatorGeneralizeByArea op = (OperatorGeneralizeByArea) engine.getOperator(Operator.Type.GeneralizeByArea); + + assertNotNull(op); + + Polygon poly = new Polygon(); + poly.startPath(0, 0); + poly.lineTo(1, 1); + poly.lineTo(2, 0); + poly.lineTo(3, 2); + poly.lineTo(4, 1); + poly.lineTo(5, 0); + poly.lineTo(5, 10); + poly.lineTo(0, 10); + Geometry geom = op.execute(poly, 100.0, true, GeneralizeType.Neither, SpatialReference.create(4326), null); + assertTrue(geom.isEmpty()); + } + + + @Test + public void testNonSimple() { + String wktInput = "MULTIPOLYGON (((5 -2, 5.1308062584602858 -1.9957178464772056, 5.2610523844401031 -1.9828897227476183, 5.3901806440322559 -1.9615705608064609, 5.5176380902050415 -1.9318516525781355, 5.6428789306063223 -1.8938602589902089, 5.7427813527082074 -1.8569533817705199, 30.742781352708207 8.1430466182294818, 30.765366864730179 8.1522409349774279, 30.884577380438003 8.2062545169346244, 31 8.2679491924311233, 31.111140466039203 8.3370607753949102, 31.217522858017439 8.4132933194175301, 31.318691630200139 8.4963203850420452, 31.414213562373096 8.585786437626906, 31.503679614957953 8.6813083697998632, 31.58670668058247 8.7824771419825591, 31.66293922460509 8.8888595339607956, 31.732050807568879 9, 31.788854381999833 9.1055728090000834, 36.788854381999833 19.105572809000083, 36.793745483065379 19.115422619561997, 36.847759065022572 19.234633135269821, 36.893860258990209 19.357121069393678, 36.931851652578139 19.48236190979496, 36.961570560806464 19.609819355967744, 36.982889722747622 19.738947615559898, 36.995717846477206 19.869193741539714, 37 20, 36.995717846477206 20.130806258460286, 36.982889722747622 20.261052384440102, 36.961570560806457 20.390180644032256, 36.931851652578132 20.51763809020504, 36.893860258990209 20.642878930606322, 36.847759065022572 20.765366864730179, 36.793745483065379 20.884577380438003, 36.788854381999833 20.894427190999917, 31.788854381999833 30.894427190999917, 31.732050807568875 31, 31.66293922460509 31.111140466039203, 31.58670668058247 31.217522858017439, 31.503679614957953 31.318691630200135, 31.414213562373096 31.414213562373092, 31.318691630200139 31.503679614957953, 31.217522858017443 31.58670668058247, 31.111140466039203 31.66293922460509, 31 31.732050807568875, 30.884577380438003 31.793745483065376, 30.765366864730179 31.847759065022572, 30.642878930606322 31.893860258990209, 30.568176659382747 31.917596225416773, 3.5681766593827478 39.917596225416773, 3.5176380902050415 39.931851652578132, 3.3901806440322564 39.961570560806464, 3.2610523844401031 39.982889722747622, 3.1308062584602863 39.995717846477206, 3 40, 2.8691937415397142 39.995717846477206, 2.7389476155598973 39.982889722747615, 2.6098193559677441 39.961570560806464, 2.482361909794959 39.931851652578132, 2.3571210693936773 39.893860258990209, 2.2346331352698212 39.847759065022572, 2.1154226195619983 39.793745483065379, 2.0000000000000009 39.732050807568875, 1.8888595339607963 39.66293922460509, 1.7824771419825594 39.586706680582466, 1.681308369799863 39.503679614957953, 1.5857864376269055 39.414213562373092, 1.4963203850420457 39.318691630200135, 1.4132933194175301 39.217522858017446, 1.33706077539491 39.111140466039203, 1.267949192431123 39, 1.2062545169346237 38.884577380438003, 1.1522409349774267 38.765366864730183, 1.1061397410097888 38.642878930606322, 1.0681483474218634 38.51763809020504, 1.0384294391935391 38.390180644032256, 1.0171102772523792 38.261052384440106, 1.004282153522793 38.130806258460282, 1 38, 1.0042821535227944 37.869193741539718, 1.0171102772523806 37.738947615559894, 1.0384294391935405 37.609819355967744, 1.0681483474218647 37.48236190979496, 1.1061397410097897 37.357121069393678, 1.1522409349774274 37.234633135269817, 1.2062545169346244 37.115422619561997, 1.2679491924311235 37, 1.3370607753949102 36.888859533960797, 1.4132933194175301 36.782477141982561, 1.4963203850420457 36.681308369799865, 1.5857864376269053 36.585786437626908, 1.6813083697998625 36.496320385042047, 1.7824771419825589 36.413293319417534, 1.8888595339607956 36.33706077539491, 2 36.267949192431118, 2.1154226195619974 36.206254516934621, 2.2346331352698208 36.152240934977428, 2.3571210693936768 36.106139741009784, 2.4318233406172522 36.082403774583227, 28.599409577746219 28.329044889507976, 32.763932022500207 20, 28.551206229908889 11.574548414817356, 6.3845784837230717 2.7078973163430327, 6.3268887828044376 2.9386561200175683, 19.26118525018893 13.447771999767468, 19.318691630200139 13.496320385042045, 19.414213562373096 13.585786437626906, 19.503679614957953 13.681308369799863, 19.58670668058247 13.782477141982559, 19.66293922460509 13.888859533960796, 19.732050807568879 14, 19.793745483065376 14.115422619561997, 19.847759065022572 14.234633135269821, 19.893860258990212 14.357121069393678, 19.931851652578136 14.482361909794959, 19.961570560806461 14.609819355967744, 19.982889722747622 14.738947615559898, 19.995717846477206 14.869193741539714, 20 15, 19.995717846477206 15.130806258460286, 19.982889722747618 15.261052384440102, 19.961570560806461 15.390180644032256, 19.931851652578136 15.517638090205041, 19.893860258990209 15.642878930606322, 19.847759065022572 15.765366864730179, 19.793745483065376 15.884577380438001, 19.732050807568875 16, 19.66293922460509 16.111140466039203, 19.58670668058247 16.217522858017439, 19.503679614957953 16.318691630200135, 19.414213562373096 16.414213562373092, 19.318691630200139 16.503679614957953, 19.217522858017443 16.58670668058247, 19.111140466039203 16.66293922460509, 19 16.732050807568875, 18.884577380438003 16.793745483065376, 18.765366864730179 16.847759065022572, 18.642878930606322 16.893860258990209, 18.51763809020504 16.931851652578139, 18.390180644032256 16.961570560806461, 18.261052384440102 16.982889722747622, 18.130806258460286 16.995717846477206, 18 17, 17.869193741539714 16.995717846477206, 17.738947615559898 16.982889722747622, 17.609819355967744 16.961570560806457, 17.48236190979496 16.931851652578136, 17.357121069393678 16.893860258990209, 17.234633135269821 16.847759065022572, 17.115422619561997 16.793745483065376, 17 16.732050807568875, 16.888859533960797 16.66293922460509, 16.782477141982561 16.58670668058247, 16.73881474981107 16.552228000232532, 5.2559522566699819 7.2224022245553954, 1.9402850002906638 20.485071250072664, 1.9318516525781353 20.51763809020504, 1.8938602589902103 20.642878930606322, 1.8477590650225726 20.765366864730179, 1.7937454830653756 20.884577380438003, 1.7320508075688765 21, 1.6629392246050898 21.111140466039203, 1.5867066805824699 21.217522858017439, 1.5036796149579543 21.318691630200139, 1.4142135623730947 21.414213562373096, 1.3186916302001375 21.503679614957953, 1.2175228580174411 21.58670668058247, 1.1111404660392044 21.66293922460509, 0.99999999999999989 21.732050807568879, 0.88457738043800249 21.793745483065376, 0.76536686473017945 21.847759065022572, 0.64287893060632306 21.893860258990212, 0.51763809020504148 21.931851652578136, 0.3901806440322565 21.961570560806461, 0.26105238444010315 21.982889722747622, 0.13080625846028612 21.995717846477206, 0 22, -0.13080625846028585 21.995717846477206, -0.26105238444010281 21.982889722747618, -0.39018064403225611 21.961570560806461, -0.51763809020504103 21.931851652578136, -0.64287893060632262 21.893860258990209, -0.7653668647301789 21.847759065022572, -0.88457738043800183 21.793745483065376, -0.99999999999999922 21.732050807568875, -1.1111404660392037 21.66293922460509, -1.2175228580174406 21.58670668058247, -1.318691630200137 21.503679614957953, -1.4142135623730945 21.414213562373096, -1.5036796149579543 21.318691630200139, -1.5867066805824699 21.217522858017443, -1.66293922460509 21.111140466039203, -1.732050807568877 21, -1.7937454830653763 20.884577380438003, -1.8477590650225733 20.765366864730179, -1.8938602589902112 20.642878930606322, -1.9318516525781366 20.51763809020504, -1.9615705608064609 20.390180644032256, -1.9828897227476208 20.261052384440102, -1.995717846477207 20.130806258460286, -2 20, -1.9957178464772056 19.869193741539714, -1.9828897227476194 19.738947615559898, -1.9615705608064595 19.609819355967744, -1.9402850002906638 19.514928749927336, 1.4516369470040571 5.947240960748454, 1.3901806440322564 5.9615705608064609, 1.2610523844401031 5.982889722747621, 1.130806258460286 5.9957178464772074, 1 6, 0.86919374153971418 5.9957178464772056, 0.73894761555989719 5.9828897227476192, 0.60981935596774384 5.9615705608064591, 0.48236190979495897 5.9318516525781355, 0.35712106939367738 5.8938602589902107, 0.2346331352698211 5.8477590650225721, 0.11542261956199817 5.7937454830653756, 7.7715611723760958E-16 5.7320508075688767, -0.11114046603920369 5.6629392246050898, -0.21752285801744065 5.5867066805824699, -0.31869163020013702 5.5036796149579548, -0.41421356237309448 5.4142135623730949, -0.50367961495795432 5.3186916302001377, -0.58670668058246989 5.2175228580174409, -0.66293922460509003 5.1111404660392044, -0.73205080756887697 5, -0.79374548306537629 4.8845773804380022, -0.84775906502257325 4.7653668647301792, -0.89386025899021115 4.6428789306063232, -0.93185165257813662 4.5176380902050415, -0.96157056080646086 4.3901806440322568, -0.98288972274762076 4.2610523844401031, -0.99571784647720696 4.1308062584602858, -1 4, -0.99571784647720563 3.8691937415397142, -0.98288972274761943 3.7389476155598973, -0.96157056080645953 3.6098193559677441, -0.93185165257813529 3.482361909794959, -0.89386025899021027 3.3571210693936773, -0.84775906502257259 3.2346331352698212, -0.79374548306537562 3.1154226195619983, -0.78885438199983171 3.1055728090000843, 0.21114561800016829 1.1055728090000843, 0.26794919243112347 1.0000000000000009, 0.33706077539491019 0.88885953396079653, 0.41329331941753011 0.78247714198255913, 0.49632038504204568 0.6813083697998632, 0.5857864376269053 0.58578643762690552, 0.68130836979986253 0.49632038504204568, 0.78247714198255891 0.41329331941753011, 0.88885953396079564 0.33706077539491019, 1 0.26794919243112325, 1.1154226195619974 0.20625451693462349, 1.2346331352698205 0.15224093497742697, 1.3571210693936768 0.10613974100978885, 1.4823619097949585 0.068148347421863598, 1.6098193559677436 0.038429439193539139, 1.7389476155598969 0.017110277252379014, 1.8691937415397137 0.0042821535227930418, 2 0, 2.1308062584602858 0.0042821535227943741, 2.2610523844401027 0.01711027725238079, 2.3901806440322559 0.038429439193540471, 2.517638090205041 0.068148347421864486, 2.6428789306063227 0.10613974100978973, 2.7653668647301788 0.15224093497742741, 2.8845773804380017 0.20625451693462438, 2.8866117144161265 0.20734189110017509, 3.0597149997093362 -0.48507125007266438, 3.0681483474218645 -0.5176380902050397, 3.1061397410097897 -0.64287893060632229, 3.1522409349774274 -0.76536686473017923, 3.2062545169346244 -0.88457738043800305, 3.2679491924311233 -1, 3.3370607753949102 -1.1111404660392026, 3.4132933194175301 -1.2175228580174391, 3.4963203850420457 -1.3186916302001386, 3.5857864376269051 -1.4142135623730958, 3.6813083697998623 -1.503679614957953, 3.7824771419825591 -1.5867066805824699, 3.8888595339607956 -1.6629392246050898, 4 -1.7320508075688785, 4.1154226195619978 -1.7937454830653756, 4.2346331352698208 -1.8477590650225721, 4.3571210693936768 -1.8938602589902125, 4.4823619097949585 -1.9318516525781355, 4.6098193559677432 -1.9615705608064609, 4.7389476155598969 -1.9828897227476219, 4.8691937415397142 -1.9957178464772056, 5 -2)))"; + double percentReduce = 60; + boolean removedDegenerates = true; + GeneralizeType generalizeType = GeneralizeType.ResultContainsOriginal; + Geometry geometry = ((OperatorGeneralizeByArea) OperatorFactoryLocal + .getInstance() + .getOperator(Operator.Type.GeneralizeByArea)) + .execute( + GeometryEngine.geometryFromWkt( + wktInput, + 0, + Geometry.Type.Unknown), + percentReduce, + removedDegenerates, + generalizeType, + SpatialReference.create(4326), + null); + + assertTrue(GeometryEngine.isSimple(geometry, SpatialReference.create(4326))); + // TODO fix this sample // assertTrue(GeometryEngine.contains( // geometry, // GeometryEngine.geometryFromWkt( @@ -251,22 +251,22 @@ public void testNonSimple() { // 0, // Geometry.Type.Unknown), // SpatialReference.create(4326))); - } - - @Test - public void testCorruptedTreapSearch() { - String wktInput = "MULTIPOLYGON (((5 2, 5.1308062584602858 2.0042821535227944, 5.2610523844401031 2.0171102772523808, 5.3901806440322559 2.0384294391935405, 5.5176380902050415 2.0681483474218645, 5.6428789306063223 2.1061397410097897, 5.7653668647301792 2.1522409349774274, 5.8845773804380022 2.2062545169346244, 5.9999999999999991 2.2679491924311233, 6.1111404660392035 2.3370607753949102, 6.2175228580174409 2.4132933194175301, 6.3186916302001368 2.4963203850420457, 6.414213562373094 2.5857864376269051, 6.5036796149579548 2.6813083697998623, 6.5867066805824699 2.7824771419825591, 6.6629392246050898 2.8888595339607956, 6.7320508075688767 3, 6.7937454830653765 3.1154226195619974, 6.847759065022573 3.2346331352698208, 6.8938602589902107 3.3571210693936768, 6.9318516525781364 3.4823619097949585, 6.9615705608064609 3.6098193559677436, 6.982889722747621 3.7389476155598969, 6.9957178464772074 3.8691937415397137, 7 4, 6.9992288413054364 4.0555341344807063, 6.6947736951561883 15.015919395853626, 11.905851560026523 31.393592685446105, 11.931851652578136 31.48236190979496, 11.961570560806461 31.609819355967744, 11.982889722747622 31.738947615559898, 11.995717846477207 31.869193741539714, 12 32, 11.995717846477206 32.130806258460282, 11.982889722747618 32.261052384440106, 11.961570560806459 32.390180644032256, 11.931851652578136 32.51763809020504, 11.893860258990211 32.642878930606322, 11.847759065022572 32.765366864730183, 11.793745483065376 32.884577380438003, 11.732050807568877 33, 11.66293922460509 33.111140466039203, 11.6 33.200000000000003, 5.5999999999999996 41.200000000000003, 5.5867066805824699 41.217522858017439, 5.5036796149579548 41.318691630200135, 5.4142135623730949 41.414213562373092, 5.3186916302001377 41.503679614957953, 5.2175228580174409 41.586706680582466, 5.1111404660392044 41.66293922460509, 5 41.732050807568875, 4.8845773804380022 41.793745483065379, 4.7653668647301792 41.847759065022572, 4.6428789306063232 41.893860258990209, 4.5176380902050415 41.931851652578139, 4.3901806440322568 41.961570560806464, 4.2610523844401031 41.982889722747622, 4.1308062584602858 41.995717846477206, 4 42, 3.8691937415397142 41.995717846477206, 3.7389476155598973 41.982889722747622, 3.6098193559677441 41.961570560806457, 3.482361909794959 41.931851652578132, 3.3571210693936773 41.893860258990209, 3.2346331352698212 41.847759065022572, 3.1154226195619983 41.793745483065379, 3.0000000000000009 41.732050807568875, 2.8888595339607965 41.66293922460509, 2.7824771419825591 41.586706680582466, 2.6813083697998632 41.503679614957953, 2.5857864376269055 41.414213562373092, 2.4963203850420457 41.318691630200135, 2.4132933194175301 41.217522858017439, 2.3370607753949102 41.111140466039203, 2.2679491924311233 41, 2.2062545169346235 40.884577380438003, 2.152240934977427 40.765366864730183, 2.1061397410097888 40.642878930606322, 2.0681483474218636 40.51763809020504, 2.0384294391935391 40.390180644032256, 2.017110277252379 40.261052384440106, 2.004282153522793 40.130806258460289, 2 40, 2.0007711586945636 39.944465865519291, 2.6774890785664391 15.582620750131777, 1.094148439973476 10.606407314553895, 1.0681483474218636 10.517638090205041, 1.0384294391935391 10.390180644032256, 1.017110277252379 10.261052384440102, 1.004282153522793 10.130806258460286, 1 10, 1.0042821535227944 9.8691937415397142, 1.0171102772523808 9.7389476155598977, 1.0384294391935405 9.6098193559677441, 1.0681483474218645 9.4823619097949585, 1.1061397410097897 9.3571210693936777, 1.1522409349774274 9.2346331352698208, 1.2062545169346244 9.115422619561997, 1.2679491924311233 9, 1.3370607753949102 8.8888595339607974, 1.4132933194175301 8.7824771419825591, 1.4963203850420457 8.6813083697998632, 1.5857864376269051 8.585786437626906, 1.6813083697998623 8.4963203850420452, 1.7824771419825591 8.4132933194175301, 1.8888595339607956 8.3370607753949102, 2 8.2679491924311233, 2.1154226195619974 8.2062545169346244, 2.2346331352698208 8.1522409349774279, 2.3571210693936768 8.1061397410097893, 2.4823619097949585 8.0681483474218645, 2.6098193559677436 8.0384294391935391, 2.7389476155598969 8.0171102772523781, 2.8691937415397137 8.0042821535227926, 2.888015599689953 8.0036659896852811, 3.0007711586945636 3.9444658655192932, 3.0042821535227944 3.8691937415397142, 3.0171102772523808 3.7389476155598973, 3.0384294391935405 3.6098193559677441, 3.0681483474218645 3.482361909794959, 3.1061397410097897 3.3571210693936773, 3.1522409349774274 3.2346331352698212, 3.2062545169346244 3.1154226195619983, 3.2679491924311233 3.0000000000000009, 3.3370607753949102 2.8888595339607965, 3.4132933194175301 2.7824771419825591, 3.4963203850420457 2.6813083697998632, 3.5857864376269051 2.5857864376269055, 3.6813083697998623 2.4963203850420457, 3.7824771419825591 2.4132933194175301, 3.8888595339607956 2.3370607753949102, 4 2.2679491924311233, 4.1154226195619978 2.2062545169346235, 4.2346331352698208 2.152240934977427, 4.3571210693936768 2.1061397410097888, 4.4823619097949585 2.0681483474218636, 4.6098193559677432 2.0384294391935391, 4.7389476155598969 2.017110277252379, 4.8691937415397142 2.004282153522793, 5 2), (6.3577402241893219 27.149124350660838, 6.1738780506195123 33.768162599173976, 7.7816940790703999 31.624407894572798, 6.3577402241893219 27.149124350660838)))\n" + - "MULTIPOLYGON (((5 -2, 5.1308062584602858 -1.9957178464772056, 5.2610523844401031 -1.9828897227476183, 5.3901806440322559 -1.9615705608064609, 5.5176380902050415 -1.9318516525781355, 5.6428789306063223 -1.8938602589902089, 5.7427813527082074 -1.8569533817705199, 30.742781352708207 8.1430466182294818, 30.765366864730179 8.1522409349774279, 30.884577380438003 8.2062545169346244, 31 8.2679491924311233, 31.111140466039203 8.3370607753949102, 31.217522858017439 8.4132933194175301, 31.318691630200139 8.4963203850420452, 31.414213562373096 8.585786437626906, 31.503679614957953 8.6813083697998632, 31.58670668058247 8.7824771419825591, 31.66293922460509 8.8888595339607956, 31.732050807568879 9, 31.788854381999833 9.1055728090000834, 36.788854381999833 19.105572809000083, 36.793745483065379 19.115422619561997, 36.847759065022572 19.234633135269821, 36.893860258990209 19.357121069393678, 36.931851652578139 19.48236190979496, 36.961570560806464 19.609819355967744, 36.982889722747622 19.738947615559898, 36.995717846477206 19.869193741539714, 37 20, 36.995717846477206 20.130806258460286, 36.982889722747622 20.261052384440102, 36.961570560806457 20.390180644032256, 36.931851652578132 20.51763809020504, 36.893860258990209 20.642878930606322, 36.847759065022572 20.765366864730179, 36.793745483065379 20.884577380438003, 36.788854381999833 20.894427190999917, 31.788854381999833 30.894427190999917, 31.732050807568875 31, 31.66293922460509 31.111140466039203, 31.58670668058247 31.217522858017439, 31.503679614957953 31.318691630200135, 31.414213562373096 31.414213562373092, 31.318691630200139 31.503679614957953, 31.217522858017443 31.58670668058247, 31.111140466039203 31.66293922460509, 31 31.732050807568875, 30.884577380438003 31.793745483065376, 30.765366864730179 31.847759065022572, 30.642878930606322 31.893860258990209, 30.568176659382747 31.917596225416773, 3.5681766593827478 39.917596225416773, 3.5176380902050415 39.931851652578132, 3.3901806440322564 39.961570560806464, 3.2610523844401031 39.982889722747622, 3.1308062584602863 39.995717846477206, 3 40, 2.8691937415397142 39.995717846477206, 2.7389476155598973 39.982889722747615, 2.6098193559677441 39.961570560806464, 2.482361909794959 39.931851652578132, 2.3571210693936773 39.893860258990209, 2.2346331352698212 39.847759065022572, 2.1154226195619983 39.793745483065379, 2.0000000000000009 39.732050807568875, 1.8888595339607963 39.66293922460509, 1.7824771419825594 39.586706680582466, 1.681308369799863 39.503679614957953, 1.5857864376269055 39.414213562373092, 1.4963203850420457 39.318691630200135, 1.4132933194175301 39.217522858017446, 1.33706077539491 39.111140466039203, 1.267949192431123 39, 1.2062545169346237 38.884577380438003, 1.1522409349774267 38.765366864730183, 1.1061397410097888 38.642878930606322, 1.0681483474218634 38.51763809020504, 1.0384294391935391 38.390180644032256, 1.0171102772523792 38.261052384440106, 1.004282153522793 38.130806258460282, 1 38, 1.0042821535227944 37.869193741539718, 1.0171102772523806 37.738947615559894, 1.0384294391935405 37.609819355967744, 1.0681483474218647 37.48236190979496, 1.1061397410097897 37.357121069393678, 1.1522409349774274 37.234633135269817, 1.2062545169346244 37.115422619561997, 1.2679491924311235 37, 1.3370607753949102 36.888859533960797, 1.4132933194175301 36.782477141982561, 1.4963203850420457 36.681308369799865, 1.5857864376269053 36.585786437626908, 1.6813083697998625 36.496320385042047, 1.7824771419825589 36.413293319417534, 1.8888595339607956 36.33706077539491, 2 36.267949192431118, 2.1154226195619974 36.206254516934621, 2.2346331352698208 36.152240934977428, 2.3571210693936768 36.106139741009784, 2.4318233406172522 36.082403774583227, 28.599409577746219 28.329044889507976, 32.763932022500207 20, 28.551206229908889 11.574548414817356, 6.3845784837230717 2.7078973163430327, 6.3268887828044376 2.9386561200175683, 19.26118525018893 13.447771999767468, 19.318691630200139 13.496320385042045, 19.414213562373096 13.585786437626906, 19.503679614957953 13.681308369799863, 19.58670668058247 13.782477141982559, 19.66293922460509 13.888859533960796, 19.732050807568879 14, 19.793745483065376 14.115422619561997, 19.847759065022572 14.234633135269821, 19.893860258990212 14.357121069393678, 19.931851652578136 14.482361909794959, 19.961570560806461 14.609819355967744, 19.982889722747622 14.738947615559898, 19.995717846477206 14.869193741539714, 20 15, 19.995717846477206 15.130806258460286, 19.982889722747618 15.261052384440102, 19.961570560806461 15.390180644032256, 19.931851652578136 15.517638090205041, 19.893860258990209 15.642878930606322, 19.847759065022572 15.765366864730179, 19.793745483065376 15.884577380438001, 19.732050807568875 16, 19.66293922460509 16.111140466039203, 19.58670668058247 16.217522858017439, 19.503679614957953 16.318691630200135, 19.414213562373096 16.414213562373092, 19.318691630200139 16.503679614957953, 19.217522858017443 16.58670668058247, 19.111140466039203 16.66293922460509, 19 16.732050807568875, 18.884577380438003 16.793745483065376, 18.765366864730179 16.847759065022572, 18.642878930606322 16.893860258990209, 18.51763809020504 16.931851652578139, 18.390180644032256 16.961570560806461, 18.261052384440102 16.982889722747622, 18.130806258460286 16.995717846477206, 18 17, 17.869193741539714 16.995717846477206, 17.738947615559898 16.982889722747622, 17.609819355967744 16.961570560806457, 17.48236190979496 16.931851652578136, 17.357121069393678 16.893860258990209, 17.234633135269821 16.847759065022572, 17.115422619561997 16.793745483065376, 17 16.732050807568875, 16.888859533960797 16.66293922460509, 16.782477141982561 16.58670668058247, 16.73881474981107 16.552228000232532, 5.2559522566699819 7.2224022245553954, 1.9402850002906638 20.485071250072664, 1.9318516525781353 20.51763809020504, 1.8938602589902103 20.642878930606322, 1.8477590650225726 20.765366864730179, 1.7937454830653756 20.884577380438003, 1.7320508075688765 21, 1.6629392246050898 21.111140466039203, 1.5867066805824699 21.217522858017439, 1.5036796149579543 21.318691630200139, 1.4142135623730947 21.414213562373096, 1.3186916302001375 21.503679614957953, 1.2175228580174411 21.58670668058247, 1.1111404660392044 21.66293922460509, 0.99999999999999989 21.732050807568879, 0.88457738043800249 21.793745483065376, 0.76536686473017945 21.847759065022572, 0.64287893060632306 21.893860258990212, 0.51763809020504148 21.931851652578136, 0.3901806440322565 21.961570560806461, 0.26105238444010315 21.982889722747622, 0.13080625846028612 21.995717846477206, 0 22, -0.13080625846028585 21.995717846477206, -0.26105238444010281 21.982889722747618, -0.39018064403225611 21.961570560806461, -0.51763809020504103 21.931851652578136, -0.64287893060632262 21.893860258990209, -0.7653668647301789 21.847759065022572, -0.88457738043800183 21.793745483065376, -0.99999999999999922 21.732050807568875, -1.1111404660392037 21.66293922460509, -1.2175228580174406 21.58670668058247, -1.318691630200137 21.503679614957953, -1.4142135623730945 21.414213562373096, -1.5036796149579543 21.318691630200139, -1.5867066805824699 21.217522858017443, -1.66293922460509 21.111140466039203, -1.732050807568877 21, -1.7937454830653763 20.884577380438003, -1.8477590650225733 20.765366864730179, -1.8938602589902112 20.642878930606322, -1.9318516525781366 20.51763809020504, -1.9615705608064609 20.390180644032256, -1.9828897227476208 20.261052384440102, -1.995717846477207 20.130806258460286, -2 20, -1.9957178464772056 19.869193741539714, -1.9828897227476194 19.738947615559898, -1.9615705608064595 19.609819355967744, -1.9402850002906638 19.514928749927336, 1.4516369470040571 5.947240960748454, 1.3901806440322564 5.9615705608064609, 1.2610523844401031 5.982889722747621, 1.130806258460286 5.9957178464772074, 1 6, 0.86919374153971418 5.9957178464772056, 0.73894761555989719 5.9828897227476192, 0.60981935596774384 5.9615705608064591, 0.48236190979495897 5.9318516525781355, 0.35712106939367738 5.8938602589902107, 0.2346331352698211 5.8477590650225721, 0.11542261956199817 5.7937454830653756, 7.7715611723760958E-16 5.7320508075688767, -0.11114046603920369 5.6629392246050898, -0.21752285801744065 5.5867066805824699, -0.31869163020013702 5.5036796149579548, -0.41421356237309448 5.4142135623730949, -0.50367961495795432 5.3186916302001377, -0.58670668058246989 5.2175228580174409, -0.66293922460509003 5.1111404660392044, -0.73205080756887697 5, -0.79374548306537629 4.8845773804380022, -0.84775906502257325 4.7653668647301792, -0.89386025899021115 4.6428789306063232, -0.93185165257813662 4.5176380902050415, -0.96157056080646086 4.3901806440322568, -0.98288972274762076 4.2610523844401031, -0.99571784647720696 4.1308062584602858, -1 4, -0.99571784647720563 3.8691937415397142, -0.98288972274761943 3.7389476155598973, -0.96157056080645953 3.6098193559677441, -0.93185165257813529 3.482361909794959, -0.89386025899021027 3.3571210693936773, -0.84775906502257259 3.2346331352698212, -0.79374548306537562 3.1154226195619983, -0.78885438199983171 3.1055728090000843, 0.21114561800016829 1.1055728090000843, 0.26794919243112347 1.0000000000000009, 0.33706077539491019 0.88885953396079653, 0.41329331941753011 0.78247714198255913, 0.49632038504204568 0.6813083697998632, 0.5857864376269053 0.58578643762690552, 0.68130836979986253 0.49632038504204568, 0.78247714198255891 0.41329331941753011, 0.88885953396079564 0.33706077539491019, 1 0.26794919243112325, 1.1154226195619974 0.20625451693462349, 1.2346331352698205 0.15224093497742697, 1.3571210693936768 0.10613974100978885, 1.4823619097949585 0.068148347421863598, 1.6098193559677436 0.038429439193539139, 1.7389476155598969 0.017110277252379014, 1.8691937415397137 0.0042821535227930418, 2 0, 2.1308062584602858 0.0042821535227943741, 2.2610523844401027 0.01711027725238079, 2.3901806440322559 0.038429439193540471, 2.517638090205041 0.068148347421864486, 2.6428789306063227 0.10613974100978973, 2.7653668647301788 0.15224093497742741, 2.8845773804380017 0.20625451693462438, 2.8866117144161265 0.20734189110017509, 3.0597149997093362 -0.48507125007266438, 3.0681483474218645 -0.5176380902050397, 3.1061397410097897 -0.64287893060632229, 3.1522409349774274 -0.76536686473017923, 3.2062545169346244 -0.88457738043800305, 3.2679491924311233 -1, 3.3370607753949102 -1.1111404660392026, 3.4132933194175301 -1.2175228580174391, 3.4963203850420457 -1.3186916302001386, 3.5857864376269051 -1.4142135623730958, 3.6813083697998623 -1.503679614957953, 3.7824771419825591 -1.5867066805824699, 3.8888595339607956 -1.6629392246050898, 4 -1.7320508075688785, 4.1154226195619978 -1.7937454830653756, 4.2346331352698208 -1.8477590650225721, 4.3571210693936768 -1.8938602589902125, 4.4823619097949585 -1.9318516525781355, 4.6098193559677432 -1.9615705608064609, 4.7389476155598969 -1.9828897227476219, 4.8691937415397142 -1.9957178464772056, 5 -2)))"; - Geometry poly = GeometryEngine.geometryFromWkt(wktInput, 0, Geometry.Type.Unknown); - OperatorFactoryLocal engine = OperatorFactoryLocal.getInstance(); - OperatorGeneralizeByArea op = (OperatorGeneralizeByArea) engine.getOperator(Operator.Type.GeneralizeByArea); - Geometry geom = op.execute(poly, 5, true, GeneralizeType.Neither, SpatialReference.create(4326),null); - int res = ((MultiVertexGeometry)geom).getPointCount(); - int original = ((MultiVertexGeometry)poly).getPointCount(); - double ratio = (double)res/original; - assertTrue(res/(double)original < 0.95); - Geometry geom2 = op.execute(poly, true, res, GeneralizeType.Neither, SpatialReference.create(4326),null); - assertTrue(((MultiVertexGeometry)geom2).getPointCount() <= res); + } + + @Test + public void testCorruptedTreapSearch() { + String wktInput = "MULTIPOLYGON (((5 2, 5.1308062584602858 2.0042821535227944, 5.2610523844401031 2.0171102772523808, 5.3901806440322559 2.0384294391935405, 5.5176380902050415 2.0681483474218645, 5.6428789306063223 2.1061397410097897, 5.7653668647301792 2.1522409349774274, 5.8845773804380022 2.2062545169346244, 5.9999999999999991 2.2679491924311233, 6.1111404660392035 2.3370607753949102, 6.2175228580174409 2.4132933194175301, 6.3186916302001368 2.4963203850420457, 6.414213562373094 2.5857864376269051, 6.5036796149579548 2.6813083697998623, 6.5867066805824699 2.7824771419825591, 6.6629392246050898 2.8888595339607956, 6.7320508075688767 3, 6.7937454830653765 3.1154226195619974, 6.847759065022573 3.2346331352698208, 6.8938602589902107 3.3571210693936768, 6.9318516525781364 3.4823619097949585, 6.9615705608064609 3.6098193559677436, 6.982889722747621 3.7389476155598969, 6.9957178464772074 3.8691937415397137, 7 4, 6.9992288413054364 4.0555341344807063, 6.6947736951561883 15.015919395853626, 11.905851560026523 31.393592685446105, 11.931851652578136 31.48236190979496, 11.961570560806461 31.609819355967744, 11.982889722747622 31.738947615559898, 11.995717846477207 31.869193741539714, 12 32, 11.995717846477206 32.130806258460282, 11.982889722747618 32.261052384440106, 11.961570560806459 32.390180644032256, 11.931851652578136 32.51763809020504, 11.893860258990211 32.642878930606322, 11.847759065022572 32.765366864730183, 11.793745483065376 32.884577380438003, 11.732050807568877 33, 11.66293922460509 33.111140466039203, 11.6 33.200000000000003, 5.5999999999999996 41.200000000000003, 5.5867066805824699 41.217522858017439, 5.5036796149579548 41.318691630200135, 5.4142135623730949 41.414213562373092, 5.3186916302001377 41.503679614957953, 5.2175228580174409 41.586706680582466, 5.1111404660392044 41.66293922460509, 5 41.732050807568875, 4.8845773804380022 41.793745483065379, 4.7653668647301792 41.847759065022572, 4.6428789306063232 41.893860258990209, 4.5176380902050415 41.931851652578139, 4.3901806440322568 41.961570560806464, 4.2610523844401031 41.982889722747622, 4.1308062584602858 41.995717846477206, 4 42, 3.8691937415397142 41.995717846477206, 3.7389476155598973 41.982889722747622, 3.6098193559677441 41.961570560806457, 3.482361909794959 41.931851652578132, 3.3571210693936773 41.893860258990209, 3.2346331352698212 41.847759065022572, 3.1154226195619983 41.793745483065379, 3.0000000000000009 41.732050807568875, 2.8888595339607965 41.66293922460509, 2.7824771419825591 41.586706680582466, 2.6813083697998632 41.503679614957953, 2.5857864376269055 41.414213562373092, 2.4963203850420457 41.318691630200135, 2.4132933194175301 41.217522858017439, 2.3370607753949102 41.111140466039203, 2.2679491924311233 41, 2.2062545169346235 40.884577380438003, 2.152240934977427 40.765366864730183, 2.1061397410097888 40.642878930606322, 2.0681483474218636 40.51763809020504, 2.0384294391935391 40.390180644032256, 2.017110277252379 40.261052384440106, 2.004282153522793 40.130806258460289, 2 40, 2.0007711586945636 39.944465865519291, 2.6774890785664391 15.582620750131777, 1.094148439973476 10.606407314553895, 1.0681483474218636 10.517638090205041, 1.0384294391935391 10.390180644032256, 1.017110277252379 10.261052384440102, 1.004282153522793 10.130806258460286, 1 10, 1.0042821535227944 9.8691937415397142, 1.0171102772523808 9.7389476155598977, 1.0384294391935405 9.6098193559677441, 1.0681483474218645 9.4823619097949585, 1.1061397410097897 9.3571210693936777, 1.1522409349774274 9.2346331352698208, 1.2062545169346244 9.115422619561997, 1.2679491924311233 9, 1.3370607753949102 8.8888595339607974, 1.4132933194175301 8.7824771419825591, 1.4963203850420457 8.6813083697998632, 1.5857864376269051 8.585786437626906, 1.6813083697998623 8.4963203850420452, 1.7824771419825591 8.4132933194175301, 1.8888595339607956 8.3370607753949102, 2 8.2679491924311233, 2.1154226195619974 8.2062545169346244, 2.2346331352698208 8.1522409349774279, 2.3571210693936768 8.1061397410097893, 2.4823619097949585 8.0681483474218645, 2.6098193559677436 8.0384294391935391, 2.7389476155598969 8.0171102772523781, 2.8691937415397137 8.0042821535227926, 2.888015599689953 8.0036659896852811, 3.0007711586945636 3.9444658655192932, 3.0042821535227944 3.8691937415397142, 3.0171102772523808 3.7389476155598973, 3.0384294391935405 3.6098193559677441, 3.0681483474218645 3.482361909794959, 3.1061397410097897 3.3571210693936773, 3.1522409349774274 3.2346331352698212, 3.2062545169346244 3.1154226195619983, 3.2679491924311233 3.0000000000000009, 3.3370607753949102 2.8888595339607965, 3.4132933194175301 2.7824771419825591, 3.4963203850420457 2.6813083697998632, 3.5857864376269051 2.5857864376269055, 3.6813083697998623 2.4963203850420457, 3.7824771419825591 2.4132933194175301, 3.8888595339607956 2.3370607753949102, 4 2.2679491924311233, 4.1154226195619978 2.2062545169346235, 4.2346331352698208 2.152240934977427, 4.3571210693936768 2.1061397410097888, 4.4823619097949585 2.0681483474218636, 4.6098193559677432 2.0384294391935391, 4.7389476155598969 2.017110277252379, 4.8691937415397142 2.004282153522793, 5 2), (6.3577402241893219 27.149124350660838, 6.1738780506195123 33.768162599173976, 7.7816940790703999 31.624407894572798, 6.3577402241893219 27.149124350660838)))\n" + + "MULTIPOLYGON (((5 -2, 5.1308062584602858 -1.9957178464772056, 5.2610523844401031 -1.9828897227476183, 5.3901806440322559 -1.9615705608064609, 5.5176380902050415 -1.9318516525781355, 5.6428789306063223 -1.8938602589902089, 5.7427813527082074 -1.8569533817705199, 30.742781352708207 8.1430466182294818, 30.765366864730179 8.1522409349774279, 30.884577380438003 8.2062545169346244, 31 8.2679491924311233, 31.111140466039203 8.3370607753949102, 31.217522858017439 8.4132933194175301, 31.318691630200139 8.4963203850420452, 31.414213562373096 8.585786437626906, 31.503679614957953 8.6813083697998632, 31.58670668058247 8.7824771419825591, 31.66293922460509 8.8888595339607956, 31.732050807568879 9, 31.788854381999833 9.1055728090000834, 36.788854381999833 19.105572809000083, 36.793745483065379 19.115422619561997, 36.847759065022572 19.234633135269821, 36.893860258990209 19.357121069393678, 36.931851652578139 19.48236190979496, 36.961570560806464 19.609819355967744, 36.982889722747622 19.738947615559898, 36.995717846477206 19.869193741539714, 37 20, 36.995717846477206 20.130806258460286, 36.982889722747622 20.261052384440102, 36.961570560806457 20.390180644032256, 36.931851652578132 20.51763809020504, 36.893860258990209 20.642878930606322, 36.847759065022572 20.765366864730179, 36.793745483065379 20.884577380438003, 36.788854381999833 20.894427190999917, 31.788854381999833 30.894427190999917, 31.732050807568875 31, 31.66293922460509 31.111140466039203, 31.58670668058247 31.217522858017439, 31.503679614957953 31.318691630200135, 31.414213562373096 31.414213562373092, 31.318691630200139 31.503679614957953, 31.217522858017443 31.58670668058247, 31.111140466039203 31.66293922460509, 31 31.732050807568875, 30.884577380438003 31.793745483065376, 30.765366864730179 31.847759065022572, 30.642878930606322 31.893860258990209, 30.568176659382747 31.917596225416773, 3.5681766593827478 39.917596225416773, 3.5176380902050415 39.931851652578132, 3.3901806440322564 39.961570560806464, 3.2610523844401031 39.982889722747622, 3.1308062584602863 39.995717846477206, 3 40, 2.8691937415397142 39.995717846477206, 2.7389476155598973 39.982889722747615, 2.6098193559677441 39.961570560806464, 2.482361909794959 39.931851652578132, 2.3571210693936773 39.893860258990209, 2.2346331352698212 39.847759065022572, 2.1154226195619983 39.793745483065379, 2.0000000000000009 39.732050807568875, 1.8888595339607963 39.66293922460509, 1.7824771419825594 39.586706680582466, 1.681308369799863 39.503679614957953, 1.5857864376269055 39.414213562373092, 1.4963203850420457 39.318691630200135, 1.4132933194175301 39.217522858017446, 1.33706077539491 39.111140466039203, 1.267949192431123 39, 1.2062545169346237 38.884577380438003, 1.1522409349774267 38.765366864730183, 1.1061397410097888 38.642878930606322, 1.0681483474218634 38.51763809020504, 1.0384294391935391 38.390180644032256, 1.0171102772523792 38.261052384440106, 1.004282153522793 38.130806258460282, 1 38, 1.0042821535227944 37.869193741539718, 1.0171102772523806 37.738947615559894, 1.0384294391935405 37.609819355967744, 1.0681483474218647 37.48236190979496, 1.1061397410097897 37.357121069393678, 1.1522409349774274 37.234633135269817, 1.2062545169346244 37.115422619561997, 1.2679491924311235 37, 1.3370607753949102 36.888859533960797, 1.4132933194175301 36.782477141982561, 1.4963203850420457 36.681308369799865, 1.5857864376269053 36.585786437626908, 1.6813083697998625 36.496320385042047, 1.7824771419825589 36.413293319417534, 1.8888595339607956 36.33706077539491, 2 36.267949192431118, 2.1154226195619974 36.206254516934621, 2.2346331352698208 36.152240934977428, 2.3571210693936768 36.106139741009784, 2.4318233406172522 36.082403774583227, 28.599409577746219 28.329044889507976, 32.763932022500207 20, 28.551206229908889 11.574548414817356, 6.3845784837230717 2.7078973163430327, 6.3268887828044376 2.9386561200175683, 19.26118525018893 13.447771999767468, 19.318691630200139 13.496320385042045, 19.414213562373096 13.585786437626906, 19.503679614957953 13.681308369799863, 19.58670668058247 13.782477141982559, 19.66293922460509 13.888859533960796, 19.732050807568879 14, 19.793745483065376 14.115422619561997, 19.847759065022572 14.234633135269821, 19.893860258990212 14.357121069393678, 19.931851652578136 14.482361909794959, 19.961570560806461 14.609819355967744, 19.982889722747622 14.738947615559898, 19.995717846477206 14.869193741539714, 20 15, 19.995717846477206 15.130806258460286, 19.982889722747618 15.261052384440102, 19.961570560806461 15.390180644032256, 19.931851652578136 15.517638090205041, 19.893860258990209 15.642878930606322, 19.847759065022572 15.765366864730179, 19.793745483065376 15.884577380438001, 19.732050807568875 16, 19.66293922460509 16.111140466039203, 19.58670668058247 16.217522858017439, 19.503679614957953 16.318691630200135, 19.414213562373096 16.414213562373092, 19.318691630200139 16.503679614957953, 19.217522858017443 16.58670668058247, 19.111140466039203 16.66293922460509, 19 16.732050807568875, 18.884577380438003 16.793745483065376, 18.765366864730179 16.847759065022572, 18.642878930606322 16.893860258990209, 18.51763809020504 16.931851652578139, 18.390180644032256 16.961570560806461, 18.261052384440102 16.982889722747622, 18.130806258460286 16.995717846477206, 18 17, 17.869193741539714 16.995717846477206, 17.738947615559898 16.982889722747622, 17.609819355967744 16.961570560806457, 17.48236190979496 16.931851652578136, 17.357121069393678 16.893860258990209, 17.234633135269821 16.847759065022572, 17.115422619561997 16.793745483065376, 17 16.732050807568875, 16.888859533960797 16.66293922460509, 16.782477141982561 16.58670668058247, 16.73881474981107 16.552228000232532, 5.2559522566699819 7.2224022245553954, 1.9402850002906638 20.485071250072664, 1.9318516525781353 20.51763809020504, 1.8938602589902103 20.642878930606322, 1.8477590650225726 20.765366864730179, 1.7937454830653756 20.884577380438003, 1.7320508075688765 21, 1.6629392246050898 21.111140466039203, 1.5867066805824699 21.217522858017439, 1.5036796149579543 21.318691630200139, 1.4142135623730947 21.414213562373096, 1.3186916302001375 21.503679614957953, 1.2175228580174411 21.58670668058247, 1.1111404660392044 21.66293922460509, 0.99999999999999989 21.732050807568879, 0.88457738043800249 21.793745483065376, 0.76536686473017945 21.847759065022572, 0.64287893060632306 21.893860258990212, 0.51763809020504148 21.931851652578136, 0.3901806440322565 21.961570560806461, 0.26105238444010315 21.982889722747622, 0.13080625846028612 21.995717846477206, 0 22, -0.13080625846028585 21.995717846477206, -0.26105238444010281 21.982889722747618, -0.39018064403225611 21.961570560806461, -0.51763809020504103 21.931851652578136, -0.64287893060632262 21.893860258990209, -0.7653668647301789 21.847759065022572, -0.88457738043800183 21.793745483065376, -0.99999999999999922 21.732050807568875, -1.1111404660392037 21.66293922460509, -1.2175228580174406 21.58670668058247, -1.318691630200137 21.503679614957953, -1.4142135623730945 21.414213562373096, -1.5036796149579543 21.318691630200139, -1.5867066805824699 21.217522858017443, -1.66293922460509 21.111140466039203, -1.732050807568877 21, -1.7937454830653763 20.884577380438003, -1.8477590650225733 20.765366864730179, -1.8938602589902112 20.642878930606322, -1.9318516525781366 20.51763809020504, -1.9615705608064609 20.390180644032256, -1.9828897227476208 20.261052384440102, -1.995717846477207 20.130806258460286, -2 20, -1.9957178464772056 19.869193741539714, -1.9828897227476194 19.738947615559898, -1.9615705608064595 19.609819355967744, -1.9402850002906638 19.514928749927336, 1.4516369470040571 5.947240960748454, 1.3901806440322564 5.9615705608064609, 1.2610523844401031 5.982889722747621, 1.130806258460286 5.9957178464772074, 1 6, 0.86919374153971418 5.9957178464772056, 0.73894761555989719 5.9828897227476192, 0.60981935596774384 5.9615705608064591, 0.48236190979495897 5.9318516525781355, 0.35712106939367738 5.8938602589902107, 0.2346331352698211 5.8477590650225721, 0.11542261956199817 5.7937454830653756, 7.7715611723760958E-16 5.7320508075688767, -0.11114046603920369 5.6629392246050898, -0.21752285801744065 5.5867066805824699, -0.31869163020013702 5.5036796149579548, -0.41421356237309448 5.4142135623730949, -0.50367961495795432 5.3186916302001377, -0.58670668058246989 5.2175228580174409, -0.66293922460509003 5.1111404660392044, -0.73205080756887697 5, -0.79374548306537629 4.8845773804380022, -0.84775906502257325 4.7653668647301792, -0.89386025899021115 4.6428789306063232, -0.93185165257813662 4.5176380902050415, -0.96157056080646086 4.3901806440322568, -0.98288972274762076 4.2610523844401031, -0.99571784647720696 4.1308062584602858, -1 4, -0.99571784647720563 3.8691937415397142, -0.98288972274761943 3.7389476155598973, -0.96157056080645953 3.6098193559677441, -0.93185165257813529 3.482361909794959, -0.89386025899021027 3.3571210693936773, -0.84775906502257259 3.2346331352698212, -0.79374548306537562 3.1154226195619983, -0.78885438199983171 3.1055728090000843, 0.21114561800016829 1.1055728090000843, 0.26794919243112347 1.0000000000000009, 0.33706077539491019 0.88885953396079653, 0.41329331941753011 0.78247714198255913, 0.49632038504204568 0.6813083697998632, 0.5857864376269053 0.58578643762690552, 0.68130836979986253 0.49632038504204568, 0.78247714198255891 0.41329331941753011, 0.88885953396079564 0.33706077539491019, 1 0.26794919243112325, 1.1154226195619974 0.20625451693462349, 1.2346331352698205 0.15224093497742697, 1.3571210693936768 0.10613974100978885, 1.4823619097949585 0.068148347421863598, 1.6098193559677436 0.038429439193539139, 1.7389476155598969 0.017110277252379014, 1.8691937415397137 0.0042821535227930418, 2 0, 2.1308062584602858 0.0042821535227943741, 2.2610523844401027 0.01711027725238079, 2.3901806440322559 0.038429439193540471, 2.517638090205041 0.068148347421864486, 2.6428789306063227 0.10613974100978973, 2.7653668647301788 0.15224093497742741, 2.8845773804380017 0.20625451693462438, 2.8866117144161265 0.20734189110017509, 3.0597149997093362 -0.48507125007266438, 3.0681483474218645 -0.5176380902050397, 3.1061397410097897 -0.64287893060632229, 3.1522409349774274 -0.76536686473017923, 3.2062545169346244 -0.88457738043800305, 3.2679491924311233 -1, 3.3370607753949102 -1.1111404660392026, 3.4132933194175301 -1.2175228580174391, 3.4963203850420457 -1.3186916302001386, 3.5857864376269051 -1.4142135623730958, 3.6813083697998623 -1.503679614957953, 3.7824771419825591 -1.5867066805824699, 3.8888595339607956 -1.6629392246050898, 4 -1.7320508075688785, 4.1154226195619978 -1.7937454830653756, 4.2346331352698208 -1.8477590650225721, 4.3571210693936768 -1.8938602589902125, 4.4823619097949585 -1.9318516525781355, 4.6098193559677432 -1.9615705608064609, 4.7389476155598969 -1.9828897227476219, 4.8691937415397142 -1.9957178464772056, 5 -2)))"; + Geometry poly = GeometryEngine.geometryFromWkt(wktInput, 0, Geometry.Type.Unknown); + OperatorFactoryLocal engine = OperatorFactoryLocal.getInstance(); + OperatorGeneralizeByArea op = (OperatorGeneralizeByArea) engine.getOperator(Operator.Type.GeneralizeByArea); + Geometry geom = op.execute(poly, 5, true, GeneralizeType.Neither, SpatialReference.create(4326), null); + int res = ((MultiVertexGeometry) geom).getPointCount(); + int original = ((MultiVertexGeometry) poly).getPointCount(); + double ratio = (double) res / original; + assertTrue(res / (double) original < 0.95); + Geometry geom2 = op.execute(poly, true, res, GeneralizeType.Neither, SpatialReference.create(4326), null); + assertTrue(((MultiVertexGeometry) geom2).getPointCount() <= res); // String geojson = "{ \"type\": \"Feature\", \"properties\": { \"COUNTY\": \"Penobscot\", \"CNTYCODE\": \"19\", \"LAND\": \"n\", \"ISLAND\": \"n\", \"TAG\": \"n\", \"Shape_area\": 6530336.8256299999, \"Shape_len\": 56904.047782399997 }, \"geometry\": { \"type\": \"Polygon\", \"coordinates\": [ [ [ -68.695451692814189, 44.822195593602991 ], [ -68.695816087325994, 44.821903991195327 ], [ -68.696174426639388, 44.821711397443501 ], [ -68.696558567568886, 44.821572884584675 ], [ -68.696949609800058, 44.821474899471852 ], [ -68.697256901116091, 44.8213676875367 ], [ -68.697320799660304, 44.821318345186519 ], [ -68.697615556845776, 44.821188592823191 ], [ -68.698378545976411, 44.820938550102532 ], [ -68.698435156506562, 44.820920695108391 ], [ -68.69883192031557, 44.820710189947867 ], [ -68.699062657760294, 44.820652282960367 ], [ -68.699370360284775, 44.820617084374163 ], [ -68.701141054792856, 44.820558717280676 ], [ -68.701487605435759, 44.82057762811877 ], [ -68.701911437797563, 44.820632748628718 ], [ -68.70283548793708, 44.820648659500918 ], [ -68.703681639952507, 44.820515825631873 ], [ -68.704181264140928, 44.820359582185233 ], [ -68.704489092967719, 44.820297362137836 ], [ -68.704989474238957, 44.820303155036257 ], [ -68.705297799299089, 44.820375971553318 ], [ -68.705567458318939, 44.820358662585058 ], [ -68.70591330097642, 44.820283033953537 ], [ -68.706259025405714, 44.820153393000268 ], [ -68.707028672758838, 44.820060845749843 ], [ -68.707374910353323, 44.819985216211904 ], [ -68.707592100462804, 44.819868742036917 ], [ -68.707694462929339, 44.819792486857864 ], [ -68.707770875016166, 44.819689157189472 ], [ -68.707789007679523, 44.819464146139595 ], [ -68.707730751490473, 44.819337968108044 ], [ -68.707659880441298, 44.819283773228037 ], [ -68.707576200438197, 44.819261052747741 ], [ -68.707108550110888, 44.81927335711427 ], [ -68.707697862979572, 44.818806752534506 ], [ -68.70819004704336, 44.818866526433681 ], [ -68.708376591172751, 44.818948021908511 ], [ -68.708563304168294, 44.81907453000612 ], [ -68.708559320346566, 44.819551637731571 ], [ -68.708617601218435, 44.819673316158109 ], [ -68.709048345319403, 44.8197689360547 ], [ -68.709261373718149, 44.820008038747282 ], [ -68.709377173200522, 44.820089354962377 ], [ -68.709608623084335, 44.820202467396875 ], [ -68.709833368515561, 44.820234548383922 ], [ -68.710231130402889, 44.820208550305409 ], [ -68.710391390599668, 44.820172947827515 ], [ -68.710596166348765, 44.820087946208503 ], [ -68.710750055965008, 44.820061330585148 ], [ -68.710942502233308, 44.82007081882567 ], [ -68.712135677071814, 44.820015319829345 ], [ -68.712443387278597, 44.819975584283789 ], [ -68.712686784165612, 44.819913182395688 ], [ -68.713392560919672, 44.819865441533217 ], [ -68.716009635307771, 44.819772953313979 ], [ -68.716792482087286, 44.819725388080997 ], [ -68.717401129352595, 44.819573858831298 ], [ -68.71832380500507, 44.819382590539817 ], [ -68.719099748128428, 44.819289977453316 ], [ -68.719901181063932, 44.819156913377398 ], [ -68.720676944833869, 44.819100298125058 ], [ -68.721548389776331, 44.818872869458616 ], [ -68.721971165718969, 44.818738866992419 ], [ -68.722945234603259, 44.818538685443407 ], [ -68.72342783755235, 44.818373312940288 ], [ -68.724468363700822, 44.81782669204572 ], [ -68.725485044780186, 44.817221491552786 ], [ -68.726452730121551, 44.817025763931447 ], [ -68.726606732, 44.816972121695052 ], [ -68.726823714448699, 44.816806098626316 ], [ -68.727393063882147, 44.816510385999273 ], [ -68.727744531541006, 44.816236657577228 ], [ -68.728108807421563, 44.81601247031989 ], [ -68.728882984707582, 44.815609210628736 ], [ -68.730205742580338, 44.814694115634502 ], [ -68.731142364712213, 44.814111181554438 ], [ -68.732194707686304, 44.81354201139667 ], [ -68.732322590398056, 44.813492799414071 ], [ -68.73285922495063, 44.813079954581475 ], [ -68.734847494451969, 44.811882789630445 ], [ -68.735519196861276, 44.811569269299596 ], [ -68.736075846860587, 44.811264482694284 ], [ -68.736542748338991, 44.811054008218079 ], [ -68.737285361231272, 44.81078565106511 ], [ -68.738194206280426, 44.810373634066408 ], [ -68.738577747792448, 44.81015396161547 ], [ -68.739011942544209, 44.809830873214104 ], [ -68.73916496247854, 44.809637674764268 ], [ -68.739278067404385, 44.809268841467606 ], [ -68.739289709728382, 44.809052816213381 ], [ -68.739379110604645, 44.808944993089099 ], [ -68.739801306658848, 44.808738907447292 ], [ -68.739928746369046, 44.808608661744117 ], [ -68.740159550798651, 44.808604685341628 ], [ -68.740275082530914, 44.808573440839666 ], [ -68.740415719594239, 44.808497243215427 ], [ -68.740941485561748, 44.80845792622285 ], [ -68.740980130502123, 44.808476018407177 ], [ -68.741188152281438, 44.80897161333133 ], [ -68.741252758676168, 44.809016769790588 ], [ -68.741361708869633, 44.809044022116524 ], [ -68.741483822462598, 44.80904429859779 ], [ -68.74171365109278, 44.808905284132514 ], [ -68.742406737337902, 44.808920354782721 ], [ -68.742560307914303, 44.808866687471998 ], [ -68.742739175008836, 44.808723054290901 ], [ -68.74285433058246, 44.808687304572757 ], [ -68.744393775156766, 44.808641248574901 ], [ -68.744701934997593, 44.808659942387102 ], [ -68.745393760471003, 44.80851294880722 ], [ -68.745604783762118, 44.808423396405175 ], [ -68.746890030152656, 44.807674565996791 ], [ -68.747784232064419, 44.807059893372035 ], [ -68.748115961513975, 44.806745547369985 ], [ -68.748292659098013, 44.806277818981066 ], [ -68.748586111067979, 44.805949884424457 ], [ -68.748713008452199, 44.805756615538854 ], [ -68.748762966462394, 44.805536171721116 ], [ -68.749338094387127, 44.805132334560987 ], [ -68.749479853677684, 44.805065129206461 ], [ -68.749630403318932, 44.804975436641236 ], [ -68.74980313149544, 44.804782266975039 ], [ -68.750227707815029, 44.804558138285152 ], [ -68.750652420232754, 44.804392526210989 ], [ -68.751539169978301, 44.804110890388202 ], [ -68.752079552768663, 44.803878005653502 ], [ -68.752324621496953, 44.803675985622874 ], [ -68.752576316023536, 44.803401963737414 ], [ -68.752917756208078, 44.803209154691054 ], [ -68.753741243831598, 44.802837342083969 ], [ -68.754178847472929, 44.802608727462719 ], [ -68.755246495802211, 44.80214740397647 ], [ -68.75621141192336, 44.801681351966444 ], [ -68.756379046675562, 44.801564681346385 ], [ -68.75649457459167, 44.801528918622907 ], [ -68.757041406400404, 44.801255513179669 ], [ -68.75731807201862, 44.801143574835528 ], [ -68.758540273874985, 44.80056101862634 ], [ -68.759833086856261, 44.80000110411347 ], [ -68.761351548576656, 44.799234595471795 ], [ -68.762399850969942, 44.798741657051664 ], [ -68.762528590996538, 44.798660905543066 ], [ -68.76311593193843, 44.798419064966623 ], [ -68.764290928989183, 44.797854351064849 ], [ -68.765056928664066, 44.797396819296736 ], [ -68.765359260254357, 44.797280409912119 ], [ -68.765744398973183, 44.797204683019253 ], [ -68.765853702644392, 44.797141889927616 ], [ -68.765989228060278, 44.797043143839083 ], [ -68.766196183736781, 44.79676899993494 ], [ -68.766595968516938, 44.796391721736214 ], [ -68.766931270087539, 44.796131341497535 ], [ -68.767092762035375, 44.79596063129938 ], [ -68.767356401061235, 44.795835134142663 ], [ -68.767407976443195, 44.795781225479288 ], [ -68.76835318064613, 44.794365289549297 ], [ -68.768573712505116, 44.793951636411805 ], [ -68.769058260418049, 44.793412482442264 ], [ -68.76919335878452, 44.793318230884395 ], [ -68.769308808570628, 44.793295957794278 ], [ -68.76953992717155, 44.793296424408801 ], [ -68.769604074352173, 44.793260547187714 ], [ -68.769643115624532, 44.793179604079413 ], [ -68.769605239337722, 44.79306700093634 ], [ -68.769413805420456, 44.792922577945546 ], [ -68.76940782742426, 44.792837044746591 ], [ -68.769562890416026, 44.792589795367036 ], [ -68.769756273185465, 44.792441646971689 ], [ -68.769878888626124, 44.7923068609933 ], [ -68.769956858171582, 44.792171984959602 ], [ -68.770262293423301, 44.791862022606956 ], [ -68.770276886312146, 44.791668503311932 ], [ -68.770526109892913, 44.79138543276629 ], [ -68.770739470414171, 44.791079783315702 ], [ -68.771004883596888, 44.790697720220322 ], [ -68.771014027482607, 44.790283635542679 ], [ -68.771150097202366, 44.790040847588322 ], [ -68.771196291810568, 44.789847391433852 ], [ -68.771191239872593, 44.789626824453514 ], [ -68.771090828991603, 44.789244027558006 ], [ -68.771098701882494, 44.7890504945995 ], [ -68.771144273277073, 44.788915552738281 ], [ -68.771234896308329, 44.78877619933079 ], [ -68.771518169421824, 44.78856971482768 ], [ -68.77159532693554, 44.788538361751385 ], [ -68.77171121437479, 44.78850258427093 ], [ -68.771942028882165, 44.788476037269348 ], [ -68.772288408005508, 44.788494733020507 ], [ -68.772378332010533, 44.788431897456157 ], [ -68.772391578804118, 44.788377910073592 ], [ -68.772327760780144, 44.788332770127056 ], [ -68.771822295691948, 44.788183225330179 ], [ -68.771726119812556, 44.788129019349938 ], [ -68.771701064263524, 44.788070453703497 ], [ -68.771895643813892, 44.787715254867287 ], [ -68.772166177882255, 44.787531247137345 ], [ -68.772527879215332, 44.787068352872602 ], [ -68.772800635192027, 44.786519759289412 ], [ -68.772905311210849, 44.786218388531772 ], [ -68.772907724515406, 44.785804289992655 ], [ -68.77278089085523, 44.785610488866176 ], [ -68.772525281400803, 44.785416431171129 ], [ -68.772333653091337, 44.785326026307239 ], [ -68.772135082617311, 44.785294122861785 ], [ -68.772039284844894, 44.78524441965115 ], [ -68.772081361511141, 44.78469086264171 ], [ -68.772191773002305, 44.784439020950785 ], [ -68.772314057949743, 44.784380749206775 ], [ -68.772737335188012, 44.784327578460491 ], [ -68.772904815783903, 44.7842288875257 ], [ -68.77299528256475, 44.784125541511813 ], [ -68.773105565594264, 44.78390520358392 ], [ -68.773176588818572, 44.783824325179275 ], [ -68.773524412407554, 44.783568451654375 ], [ -68.773679116333085, 44.783402215061926 ], [ -68.773891903578175, 44.783231593994579 ], [ -68.774233890651587, 44.782849674443177 ], [ -68.774324996768641, 44.78268331121533 ], [ -68.774583316607917, 44.782382247238466 ], [ -68.774828285748882, 44.782162173338413 ], [ -68.775228105320053, 44.781735354463095 ], [ -68.775447251533606, 44.781551237617272 ], [ -68.775868718530432, 44.780836385125433 ], [ -68.776042953339157, 44.780620671503648 ], [ -68.776231174258058, 44.780260950562095 ], [ -68.776405922404592, 44.780013729911275 ], [ -68.777425927468428, 44.778845426855298 ], [ -68.777677066903919, 44.778656868709596 ], [ -68.778076030902696, 44.778441589156301 ], [ -68.778577135026822, 44.778267017313013 ], [ -68.779276940137763, 44.778083826402529 ], [ -68.779553572030622, 44.777940323684398 ], [ -68.780139375146547, 44.777509344353462 ], [ -68.780868818538025, 44.776691536858401 ], [ -68.781010948003328, 44.776498260311399 ], [ -68.781352729415701, 44.776147826074464 ], [ -68.781559435632545, 44.775900661047963 ], [ -68.781636566207993, 44.775765772534605 ], [ -68.781894622447126, 44.775622231079431 ], [ -68.782048293716926, 44.775613520875787 ], [ -68.782317545871479, 44.775641042606495 ], [ -68.782478189103387, 44.775564828358974 ], [ -68.782600654699593, 44.775452529435526 ], [ -68.78310278458811, 44.775097898251445 ], [ -68.784041816359917, 44.774613552553895 ], [ -68.784376287524552, 44.77441613601593 ], [ -68.784646853631486, 44.774196089069271 ], [ -68.784995648255915, 44.773755636317958 ], [ -68.785073557522978, 44.773620746898153 ], [ -68.785292878751847, 44.773373593721793 ], [ -68.785629120078838, 44.772906109661022 ], [ -68.785668228566422, 44.772798155199482 ], [ -68.785592127255271, 44.772658476989569 ], [ -68.785592327104851, 44.772604463431101 ], [ -68.785777644692217, 44.772366251526016 ], [ -68.785851453775592, 44.772163839567746 ], [ -68.785768355406873, 44.772100666203279 ], [ -68.785429575577126, 44.771973997684732 ], [ -68.785334142003123, 44.771829783681163 ], [ -68.785341473455944, 44.771663253845652 ], [ -68.785406926454442, 44.771478831091862 ], [ -68.785459811421063, 44.771168349632276 ], [ -68.785434819423855, 44.771091784805002 ], [ -68.785351789730825, 44.77101060660501 ], [ -68.785250916723996, 44.770735847941545 ], [ -68.785310182710745, 44.770515404276829 ], [ -68.785311494572341, 44.770267843410664 ], [ -68.785096318028863, 44.769826325977917 ], [ -68.784803545143774, 44.769438675883706 ], [ -68.784714527045139, 44.769375493078655 ], [ -68.784669524743251, 44.769370906446809 ], [ -68.784470834648246, 44.769384034518389 ], [ -68.78420130177291, 44.76943753950647 ], [ -68.784008264186326, 44.769522696071554 ], [ -68.783694089009984, 44.769580617214714 ], [ -68.783070626604243, 44.769867506633268 ], [ -68.782800597749329, 44.769948015603781 ], [ -68.78264697185837, 44.769947723333424 ], [ -68.782340318809389, 44.769789599225568 ], [ -68.782109891596903, 44.769735145875238 ], [ -68.782020552481555, 44.76965395570739 ], [ -68.782020670997156, 44.769622445906052 ], [ -68.782329413534242, 44.769433987151317 ], [ -68.782677143951545, 44.76916908133898 ], [ -68.782870161924663, 44.769088426262144 ], [ -68.783088655857583, 44.768953810300239 ], [ -68.783512222182253, 44.768896098227884 ], [ -68.783896880060539, 44.768892324937006 ], [ -68.784589406005708, 44.768826116407126 ], [ -68.784782390276106, 44.768754461613682 ], [ -68.785000865353041, 44.768624341230989 ], [ -68.78519341681563, 44.768561685998975 ], [ -68.785296753995596, 44.768489861684486 ], [ -68.785541690218764, 44.768251762054298 ], [ -68.785709868064387, 44.767945998534941 ], [ -68.785736214318959, 44.767869530046532 ], [ -68.785714471154591, 44.767234826848487 ], [ -68.785755081576923, 44.766825300110298 ], [ -68.785865690797962, 44.766600448006521 ], [ -68.785988080959882, 44.766501653023312 ], [ -68.785994450004765, 44.766488164598549 ], [ -68.78601394837284, 44.766447687501191 ], [ -68.786310208734392, 44.766209682289976 ], [ -68.786683532705723, 44.76595381308983 ], [ -68.786741485453618, 44.765872901578966 ], [ -68.787043992843081, 44.765652910771593 ], [ -68.787373526185192, 44.765491482758996 ], [ -68.787636098766797, 44.765284918885285 ], [ -68.78782871866386, 44.765199755348142 ], [ -68.788150546741875, 44.764984296759529 ], [ -68.788549377660019, 44.764768979850153 ], [ -68.788934548746496, 44.76461665389634 ], [ -68.789165998837333, 44.764495550508443 ], [ -68.789578047801001, 44.764226242886195 ], [ -68.789944442257621, 44.76402436418455 ], [ -68.790440190545254, 44.763647179305771 ], [ -68.790902955034028, 44.763436473216785 ], [ -68.790979906295107, 44.763450116955511 ], [ -68.791183996118704, 44.76357652300991 ], [ -68.791452533843938, 44.763680539931251 ], [ -68.791721839222916, 44.763681031378603 ], [ -68.792562104483238, 44.763579034429227 ], [ -68.793275917937265, 44.763170723018241 ], [ -68.793506473957919, 44.763184642989323 ], [ -68.793814940286381, 44.76305466829114 ], [ -68.793956685527107, 44.762946896054288 ], [ -68.794072148804759, 44.762902093872832 ], [ -68.794572353236305, 44.762817470609775 ], [ -68.794701529717074, 44.762691672670101 ], [ -68.794663512813727, 44.762610582026241 ], [ -68.794471182829113, 44.762619239661383 ], [ -68.794349621667408, 44.762601016156793 ], [ -68.794118260940593, 44.762704125575887 ], [ -68.794002483359108, 44.762726423276774 ], [ -68.79385526284679, 44.762708150450358 ], [ -68.79390059677911, 44.762618211399527 ], [ -68.794119598828289, 44.762438559637651 ], [ -68.794434913389793, 44.762268084441047 ], [ -68.794710993262086, 44.762138046492609 ], [ -68.795064349741864, 44.76203965914754 ], [ -68.7952057308094, 44.761922881092943 ], [ -68.795488596574572, 44.761770346948495 ], [ -68.795719843637599, 44.761698742093969 ], [ -68.796258622435687, 44.761645693000666 ], [ -68.796566581438384, 44.761542713183211 ], [ -68.796759412699828, 44.761502547858363 ], [ -68.797336179343631, 44.761427052287225 ], [ -68.797811208691854, 44.761310865086898 ], [ -68.79814495421958, 44.76117191980493 ], [ -68.798414345497292, 44.761145387345685 ], [ -68.799360911865662, 44.760548402916378 ], [ -68.799617180855279, 44.760431821147115 ], [ -68.800246592436537, 44.760198865374868 ], [ -68.800401188211723, 44.760023590621124 ], [ -68.800768126199941, 44.759758662850373 ], [ -68.800877274876569, 44.759709340948426 ], [ -68.800992552899757, 44.759714041168571 ], [ -68.80120348813486, 44.759804431958621 ], [ -68.801460585740003, 44.75967434710396 ], [ -68.801743547241756, 44.759485790710741 ], [ -68.801885944102992, 44.759296987349536 ], [ -68.802272006567179, 44.75897807633347 ], [ -68.80266564742729, 44.758519638865074 ], [ -68.803084230627647, 44.758155768264771 ], [ -68.80342470412505, 44.758003313674507 ], [ -68.804194879401265, 44.757815586202938 ], [ -68.804548648734837, 44.757582133698442 ], [ -68.804780826893264, 44.757343970511108 ], [ -68.804960853251316, 44.75723175064612 ], [ -68.805076202350875, 44.757213942883766 ], [ -68.805293772194744, 44.757326841465698 ], [ -68.805562563048056, 44.757354307693056 ], [ -68.805755054931097, 44.757291617566459 ], [ -68.805908948238255, 44.757318887501718 ], [ -68.806178528770531, 44.757229321859654 ], [ -68.806255426783181, 44.757256458122548 ], [ -68.806331178203592, 44.757391623058766 ], [ -68.806369798141887, 44.757414192525808 ], [ -68.8064468202152, 44.757405321994305 ], [ -68.806549701505531, 44.757337979335439 ], [ -68.806672423590101, 44.757122130821102 ], [ -68.806782136958716, 44.757018790126281 ], [ -68.807051801098638, 44.75690221677317 ], [ -68.807142104391929, 44.756816842607641 ], [ -68.807373407075289, 44.75671821091067 ], [ -68.807502054348006, 44.75661940325157 ], [ -68.807848780585701, 44.75648045388499 ], [ -68.808087002091739, 44.756318809663526 ], [ -68.808401654355606, 44.756206807988619 ], [ -68.808652446374822, 44.756063193386673 ], [ -68.808960045872851, 44.756054704733806 ], [ -68.80923601569333, 44.755938136750906 ], [ -68.809274898779066, 44.755879685796785 ], [ -68.809268850764056, 44.755798655811283 ], [ -68.809340557228253, 44.7556052256623 ], [ -68.809456533074552, 44.755515398232312 ], [ -68.809533581743025, 44.75549751954474 ], [ -68.810071718902236, 44.755498415742906 ], [ -68.810264114913323, 44.755462726140244 ], [ -68.810533408317383, 44.755454172113957 ], [ -68.810571854526643, 44.755409222885284 ], [ -68.810546670768289, 44.755382175318204 ], [ -68.810322610327518, 44.755323287513349 ], [ -68.81013757596466, 44.755160937756699 ], [ -68.810080577238011, 44.755084324892891 ], [ -68.810106431855303, 44.755025851980591 ], [ -68.810421014346346, 44.754931849301087 ], [ -68.810691541071961, 44.754666731838874 ], [ -68.810884618676084, 44.754541018805909 ], [ -68.811076352390984, 44.754586346635811 ], [ -68.811460957745311, 44.754568977507525 ], [ -68.811467845914279, 44.754514977283314 ], [ -68.811136643462973, 44.754379393534357 ], [ -68.811078065598863, 44.754302776035644 ], [ -68.811413084639341, 44.753992750485338 ], [ -68.811593438767929, 44.75377249241383 ], [ -68.811824287084306, 44.753808879906828 ], [ -68.81197786696552, 44.753809132852403 ], [ -68.81220914944889, 44.75371048876476 ], [ -68.812171099296066, 44.753633908080275 ], [ -68.811857549310361, 44.753534364842139 ], [ -68.811800568034371, 44.753453251039495 ], [ -68.811891296985777, 44.753232844750222 ], [ -68.811872624675729, 44.753147292266561 ], [ -68.811899119471633, 44.753012299351546 ], [ -68.811996165067612, 44.752791903365285 ], [ -68.812164363504536, 44.752544613505961 ], [ -68.812204164261757, 44.75232412567113 ], [ -68.812255837535332, 44.752216182372628 ], [ -68.812449191208287, 44.752000443544198 ], [ -68.812834601986424, 44.751852538837198 ], [ -68.81300918073957, 44.751582754142532 ], [ -68.81318295723068, 44.751439000840321 ], [ -68.813235210961196, 44.751272544599409 ], [ -68.813538471808641, 44.750885940049244 ], [ -68.813776929072503, 44.750638764929661 ], [ -68.814098572584356, 44.750427734168696 ], [ -68.814493642638681, 44.75009078877234 ], [ -68.814533968932153, 44.750072849550847 ], [ -68.814560139463936, 44.750036882614744 ], [ -68.814663392873143, 44.749969533163053 ], [ -68.814773386808668, 44.749893193446468 ], [ -68.814818433917466, 44.749879761076379 ], [ -68.814857210230826, 44.749852818123784 ], [ -68.81489595425569, 44.749834876208666 ], [ -68.814934278432105, 44.749825937213885 ], [ -68.814973018891862, 44.74980799526675 ], [ -68.81501171246758, 44.749808057947561 ], [ -68.815050456414866, 44.749790115979764 ], [ -68.815088780546034, 44.749781174422246 ], [ -68.815127524451597, 44.749763232428137 ], [ -68.81515953116056, 44.749754283131111 ], [ -68.815236993715445, 44.749727400143961 ], [ -68.815282029765385, 44.749718471890482 ], [ -68.815320325142594, 44.749718533822687 ], [ -68.815359097599938, 44.749691588181918 ], [ -68.815397841362241, 44.749673646095587 ], [ -68.815436559970905, 44.749664707569551 ], [ -68.81547530369933, 44.74964676294605 ], [ -68.815513627662639, 44.749637823756224 ], [ -68.815539259613928, 44.749646866261664 ], [ -68.815565400696954, 44.749619902659148 ], [ -68.815591118519407, 44.749601939470558 ], [ -68.815629862150189, 44.749583997305024 ], [ -68.81566818604837, 44.749575058063108 ], [ -68.815707356378638, 44.749548115456356 ], [ -68.815745691028283, 44.749534671887794 ], [ -68.815810550405317, 44.749498769583887 ], [ -68.815926375444491, 44.749449441465714 ], [ -68.816036381012623, 44.749368598737128 ], [ -68.816081427414701, 44.749355168377228 ], [ -68.816107177031967, 44.749328201508106 ], [ -68.816145920320508, 44.749310259166087 ], [ -68.816210384593958, 44.749274353486854 ], [ -68.816249550946083, 44.749247410686294 ], [ -68.816281571458703, 44.749233959288794 ], [ -68.816352786742598, 44.749184558966114 ], [ -68.816391533390586, 44.749166614034941 ], [ -68.816429796376184, 44.749175681668724 ], [ -68.816442939601913, 44.749139693355396 ], [ -68.816481711151056, 44.749112747329249 ], [ -68.816507855078356, 44.749085783513038 ], [ -68.816546569601087, 44.749076844603188 ], [ -68.816572286879023, 44.74905888119104 ], [ -68.816578646901021, 44.749045385982988 ], [ -68.816753533874532, 44.748919636197307 ], [ -68.816977810085774, 44.748780457365989 ], [ -68.817871923954471, 44.748169728708909 ], [ -68.817981399117343, 44.748129394495869 ], [ -68.819118677868175, 44.74738850841338 ], [ -68.81931299844598, 44.747231275296443 ], [ -68.819596944516107, 44.747069681643779 ], [ -68.820600610661103, 44.746756181179748 ], [ -68.820980842951059, 44.746603741410304 ], [ -68.821360519127069, 44.746500806852715 ], [ -68.821411979647792, 44.746455874259482 ], [ -68.821502013540552, 44.746447013903001 ], [ -68.821528150408852, 44.74642004891377 ], [ -68.822107527128807, 44.746204896097659 ], [ -68.822636062298287, 44.745962655550038 ], [ -68.822674746278807, 44.74596271561964 ], [ -68.823913000987631, 44.745343469555706 ], [ -68.824455107174913, 44.745047229790259 ], [ -68.824779449224906, 44.744701136133102 ], [ -68.825145060820077, 44.744152558364988 ], [ -68.825250330848689, 44.743932155830194 ], [ -68.825347774336592, 44.743819777171197 ], [ -68.825639512068122, 44.743550154402548 ], [ -68.82571698853684, 44.743514263185517 ], [ -68.826001967737042, 44.743258132088243 ], [ -68.826092498510377, 44.743213256878036 ], [ -68.826092987541358, 44.743181749958786 ], [ -68.826274736171015, 44.742992978069964 ], [ -68.826585357960383, 44.742741383798169 ], [ -68.827103903445632, 44.742256044512274 ], [ -68.827792028265009, 44.741554899230536 ], [ -68.828000465874297, 44.741280645385359 ], [ -68.828064940576041, 44.741235729351779 ], [ -68.828430960316567, 44.7406646322722 ], [ -68.828717376257302, 44.740313970878702 ], [ -68.828809535576255, 44.740116059345254 ], [ -68.82881057703618, 44.740030538981124 ], [ -68.828856684710985, 44.739922579594392 ], [ -68.828954588641025, 44.739783190089696 ], [ -68.82902114321972, 44.739567232756301 ], [ -68.829009555336853, 44.739481693474197 ], [ -68.829049896124886, 44.739319711113907 ], [ -68.829042592012641, 44.738851579162706 ], [ -68.829011651380185, 44.738770510204212 ], [ -68.828983396478918, 44.73844638486203 ], [ -68.828933037038013, 44.738392297692926 ], [ -68.82887076833903, 44.73822565980808 ], [ -68.82871935254623, 44.738040883468251 ], [ -68.828491051386735, 44.737828985609433 ], [ -68.827855235578454, 44.737413922145521 ], [ -68.827830636590292, 44.737323861282306 ], [ -68.827882488310493, 44.737274424473483 ], [ -68.827998188786637, 44.737256596536071 ], [ -68.828397230644569, 44.737122162390939 ], [ -68.828397705055409, 44.73709515471235 ], [ -68.828656919430031, 44.736861482048852 ], [ -68.828939181523381, 44.736308264480869 ], [ -68.829081150873833, 44.736213948906361 ], [ -68.829177493359865, 44.736200590105739 ], [ -68.829306807281213, 44.73611526146567 ], [ -68.829821654428969, 44.735922479237459 ], [ -68.830041522467653, 44.735778768555541 ], [ -68.830171465837125, 44.735612419693254 ], [ -68.830303881295663, 44.735275027848502 ], [ -68.830259850829663, 44.734676305893345 ], [ -68.830186480356275, 44.734392624905261 ], [ -68.829985341957737, 44.734072741681857 ], [ -68.829928218893954, 44.734036647097625 ], [ -68.829569115154101, 44.733482468299613 ], [ -68.829531913909165, 44.733383385293763 ], [ -68.829462296402056, 44.733302261154122 ], [ -68.829475397948642, 44.733275272307367 ], [ -68.829317773713001, 44.733058982121293 ], [ -68.828906619461691, 44.732626249904555 ], [ -68.828800394486848, 44.732378530755966 ], [ -68.828800868664587, 44.732351523052863 ], [ -68.828890879554251, 44.732342656814211 ], [ -68.829005608478639, 44.732383337501261 ], [ -68.829246003969317, 44.732635763980362 ], [ -68.829308370202071, 44.732766389916996 ], [ -68.82943036356447, 44.732753069228963 ], [ -68.829516219301652, 44.732546143806033 ], [ -68.829490592708922, 44.732537104418519 ], [ -68.829492567473608, 44.732402072831889 ], [ -68.829442878074715, 44.732253456125427 ], [ -68.829426125258408, 44.732046379981803 ], [ -68.829447596220263, 44.73185736066857 ], [ -68.829423448021132, 44.731749298470184 ], [ -68.82945276169859, 44.731443261076713 ], [ -68.829432340874419, 44.731006616646113 ], [ -68.82945893742162, 44.730952642034332 ], [ -68.829433811865556, 44.730907593825883 ], [ -68.829435962199966, 44.730714046309252 ], [ -68.829476809151288, 44.730511552925805 ], [ -68.829451604407467, 44.730493510511664 ], [ -68.82945165348211, 44.729939866764241 ], [ -68.829492340423286, 44.729255748343704 ], [ -68.829562540999063, 44.728733716931735 ], [ -68.829629501415539, 44.728508758292868 ], [ -68.829623792229512, 44.728436730637284 ], [ -68.829669345814409, 44.728378282406844 ], [ -68.829644691427688, 44.728306226494041 ], [ -68.82968396329872, 44.728238767748948 ], [ -68.829727390920212, 44.727829226758928 ], [ -68.829819592842227, 44.727608804916379 ], [ -68.829821158974539, 44.7274782744229 ], [ -68.82990113775513, 44.727253332461949 ], [ -68.829875579406334, 44.727221786640698 ], [ -68.829916389797575, 44.727032798396209 ], [ -68.829995456481413, 44.726848368908968 ], [ -68.830063425981905, 44.726546890455154 ], [ -68.830104797490321, 44.72629938926665 ], [ -68.830109467475623, 44.725916793752461 ], [ -68.830097986058647, 44.72579524494784 ], [ -68.829924540759578, 44.725326862148158 ], [ -68.829705169793812, 44.724912427475232 ], [ -68.829536620124074, 44.724525074156929 ], [ -68.829537594069521, 44.724462060075552 ], [ -68.829374835695731, 44.724254763114665 ], [ -68.829386742188802, 44.724232274276915 ], [ -68.829192550933783, 44.723844882096294 ], [ -68.829194038884168, 44.723741357352353 ], [ -68.829155840102587, 44.723714294272902 ], [ -68.829188884070703, 44.723615316043968 ], [ -68.829157447344272, 44.723570258277555 ], [ -68.829192979958805, 44.723295737587819 ], [ -68.829245321827614, 44.723210293679266 ], [ -68.829233799487199, 44.723102250153232 ], [ -68.829272630626406, 44.723048293802513 ], [ -68.829267343315706, 44.722967263034278 ], [ -68.829341152598801, 44.72269280199454 ], [ -68.829365727795363, 44.722251722279978 ], [ -68.829273135886254, 44.721936501074545 ], [ -68.829179398515109, 44.721742809877199 ], [ -68.828870460232409, 44.721332741169498 ], [ -68.828776804833907, 44.721112041276847 ], [ -68.828798761088322, 44.720891517173435 ], [ -68.828851608166616, 44.72076556271859 ], [ -68.828881361546067, 44.719910382574234 ], [ -68.828915378323558, 44.719748390228617 ], [ -68.828967292935658, 44.719671946904974 ], [ -68.82904477519746, 44.719622550305594 ], [ -68.829225343370226, 44.719537298217716 ], [ -68.829379730880788, 44.719501519342074 ], [ -68.829476151309606, 44.719452153250259 ], [ -68.829546795727538, 44.71944775436566 ], [ -68.829688656742974, 44.719375946748812 ], [ -68.829804350893895, 44.719349113252754 ], [ -68.830023258311016, 44.719241410381784 ], [ -68.830164513146144, 44.719241620525032 ], [ -68.830409543423031, 44.719106949789094 ], [ -68.830681779999651, 44.718841783325878 ], [ -68.830766615338916, 44.718706874206383 ], [ -68.830825143178046, 44.718661947623303 ], [ -68.830858207623209, 44.718553967701041 ], [ -68.830929924486668, 44.718450549336076 ], [ -68.830981691144245, 44.718423617478031 ], [ -68.830995278248068, 44.718365121303421 ], [ -68.831072822526068, 44.71829321675969 ], [ -68.831145037828549, 44.71815378433601 ], [ -68.831216231947948, 44.718095378310458 ], [ -68.831191045130765, 44.718072834435411 ], [ -68.831204142408623, 44.718045847822459 ], [ -68.831295298857896, 44.717906443290524 ], [ -68.831347074408853, 44.717875011955904 ], [ -68.831341315317033, 44.717820988996301 ], [ -68.831490997357022, 44.717636662435147 ], [ -68.831478447960819, 44.717609635434464 ], [ -68.831523991145161, 44.717551188848162 ], [ -68.831627695464434, 44.717438811033098 ], [ -68.831802020947336, 44.717326539660291 ], [ -68.831866335702301, 44.71732663436056 ], [ -68.831879436033105, 44.717299642649515 ], [ -68.832027589734622, 44.71723234570657 ], [ -68.832213965004271, 44.717183107038942 ], [ -68.832362629382899, 44.717075298935931 ], [ -68.832820189397793, 44.716846406284048 ], [ -68.833556578930853, 44.716383860815327 ], [ -68.833827857875391, 44.716168197966915 ], [ -68.835549895834205, 44.714703303497821 ], [ -68.83562834575477, 44.714586383791527 ], [ -68.835738334118005, 44.714478515574598 ], [ -68.835770696324317, 44.714474060280494 ], [ -68.836977660178562, 44.713188447838974 ], [ -68.837212666436002, 44.712815185887379 ], [ -68.837335318638054, 44.712549789960185 ], [ -68.837746388780104, 44.712136265987411 ], [ -68.837864241952218, 44.711893369316655 ], [ -68.837817114646299, 44.711533205647136 ], [ -68.837742774893911, 44.71131254266497 ], [ -68.837756362560555, 44.711249543775935 ], [ -68.837705557684615, 44.711217963750478 ], [ -68.837661598821384, 44.711136880752562 ], [ -68.837606498865213, 44.710947752855375 ], [ -68.837653594721516, 44.710754268403797 ], [ -68.83782113423689, 44.710659980394482 ], [ -68.838199584702309, 44.710620005656708 ], [ -68.838315723511855, 44.710566155608987 ], [ -68.838470722804786, 44.710440343555121 ], [ -68.838575805688109, 44.710246940704465 ], [ -68.838564309556077, 44.71012538988429 ], [ -68.838475868143405, 44.710008234612374 ], [ -68.837993622433544, 44.70963845351573 ], [ -68.83791241375549, 44.70947629720046 ], [ -68.837944877008823, 44.709435831739818 ], [ -68.837952267563139, 44.709332314994434 ], [ -68.838102867516611, 44.709084962577315 ], [ -68.838199761417997, 44.708999577497138 ], [ -68.838335310840293, 44.708914247057798 ], [ -68.838676567902183, 44.708770690830427 ], [ -68.838857657375044, 44.708622405863984 ], [ -68.838942924445462, 44.70846048502009 ], [ -68.838996717502681, 44.708267009374119 ], [ -68.838985727507065, 44.708104950240113 ], [ -68.838885766961113, 44.707875248064859 ], [ -68.838671555590025, 44.707591369909515 ], [ -68.838126509124621, 44.707113473887148 ], [ -68.83806323627806, 44.707027861768239 ], [ -68.838013962018806, 44.707014286368832 ], [ -68.837340693329821, 44.706405668792115 ], [ -68.837264289253284, 44.706360549068286 ], [ -68.837150697412767, 44.706211846473785 ], [ -68.837086893790897, 44.706175745768221 ], [ -68.837017773911995, 44.706063118687439 ], [ -68.836988404927027, 44.705847018500585 ], [ -68.837165278639802, 44.70551418222189 ], [ -68.8372237720843, 44.705473751537212 ], [ -68.837184550328644, 44.705253140514593 ], [ -68.837076358500013, 44.705149458917333 ], [ -68.836597193358529, 44.704824686898448 ], [ -68.835540335855413, 44.704287528460739 ], [ -68.835437808326546, 44.704273877757366 ], [ -68.835240879931561, 44.704165567177029 ], [ -68.835219131420899, 44.704183538150986 ], [ -68.835055593270837, 44.7041247856518 ], [ -68.834902323722858, 44.704061548430019 ], [ -68.834832656945125, 44.704007433113681 ], [ -68.83475576123486, 44.703998318195445 ], [ -68.834220201070124, 44.703812994099962 ], [ -68.834169443169714, 44.703767906998472 ], [ -68.834143777127537, 44.703776873415372 ], [ -68.834022423602448, 44.703727184373221 ], [ -68.833517832917693, 44.703613918921796 ], [ -68.833210065141728, 44.703640478423324 ], [ -68.832631782331134, 44.703774667653548 ], [ -68.832249157481954, 44.703634569229592 ], [ -68.832032948400169, 44.703512719253787 ], [ -68.83200728214976, 44.703521682679849 ], [ -68.831663368285362, 44.703363634357707 ], [ -68.830987189272491, 44.703115069448778 ], [ -68.830872989647531, 44.703047382775971 ], [ -68.830502538460067, 44.70292980321927 ], [ -68.830316614968794, 44.702974538046092 ], [ -68.83015501668234, 44.703064322165851 ], [ -68.829627939742679, 44.703761222447639 ], [ -68.829367811142419, 44.704089423466165 ], [ -68.829089888437309, 44.70429606255162 ], [ -68.82896113227882, 44.704349884381898 ], [ -68.828819883624035, 44.704358673935388 ], [ -68.828743449060937, 44.704327051467686 ], [ -68.828661809402263, 44.704187391972077 ], [ -68.828734583195754, 44.703989447646023 ], [ -68.828786311413495, 44.703971522853855 ], [ -68.828761158191611, 44.703939974751094 ], [ -68.828946519440748, 44.70341811400364 ], [ -68.829338984025767, 44.702757025485994 ], [ -68.829355711458547, 44.702432962882952 ], [ -68.829332681468813, 44.70221687257267 ], [ -68.829346736499687, 44.702131371080277 ], [ -68.829424761109749, 44.702023458430936 ], [ -68.829656573220348, 44.701933780074313 ], [ -68.830080005006408, 44.701871392546948 ], [ -68.830131261183368, 44.701880472484405 ], [ -68.830156962961397, 44.701858003995454 ], [ -68.830388260713647, 44.701808834969256 ], [ -68.831157640927003, 44.701742454845906 ], [ -68.831228355199642, 44.701706552137942 ], [ -68.831614009089805, 44.701612595193957 ], [ -68.831929567348411, 44.701478024739743 ], [ -68.832059428275784, 44.701311672602799 ], [ -68.832171378314783, 44.701064270818662 ], [ -68.832203788840019, 44.701041811724075 ], [ -68.83219124618752, 44.701014787243757 ], [ -68.832295938534727, 44.700821389277273 ], [ -68.8323764078648, 44.700546932475241 ], [ -68.832432445172316, 44.70012840327675 ], [ -68.832471583778172, 44.70009695279191 ], [ -68.832452794127036, 44.700047412451219 ], [ -68.83251141860616, 44.699961975912508 ], [ -68.832491342310988, 44.699948440929283 ], [ -68.832513462877515, 44.6997999350341 ], [ -68.832701396569121, 44.699053011871314 ], [ -68.832703423787649, 44.698895472785914 ], [ -68.83276939681565, 44.698724521804785 ], [ -68.83275737823466, 44.698652487200995 ], [ -68.832798164818172, 44.698458995094718 ], [ -68.832904858307657, 44.698117058520829 ], [ -68.832943626922997, 44.6980766036259 ], [ -68.832971792493581, 44.697883095486965 ], [ -68.833010551487007, 44.69784714240167 ], [ -68.83299215636886, 44.697797600196232 ], [ -68.833056058398569, 44.69765815641501 ], [ -68.83309889568433, 44.697437661096195 ], [ -68.833251685932069, 44.696974259151517 ], [ -68.833290967549132, 44.696893295772405 ], [ -68.83334273969372, 44.696857361562486 ], [ -68.833337436059779, 44.696780834945621 ], [ -68.833408653359328, 44.696704417460118 ], [ -68.83350750678872, 44.696479501796432 ], [ -68.833565577126649, 44.696448078513356 ], [ -68.833572424801801, 44.696398573172281 ], [ -68.833670702416541, 44.696236677386075 ], [ -68.833728823960868, 44.696187244184806 ], [ -68.83376857589279, 44.696079275239576 ], [ -68.834151119452713, 44.695679227032841 ], [ -68.834611711827748, 44.695292788585363 ], [ -68.834773450521965, 44.695004944446005 ], [ -68.834883913664868, 44.694577491171025 ], [ -68.834886960524045, 44.6943389301249 ], [ -68.834442325071066, 44.693280504549278 ], [ -68.834375742625681, 44.692978826622529 ], [ -68.834201939359033, 44.69279852547006 ], [ -68.833921779612012, 44.692708093927315 ], [ -68.833270461600222, 44.692630626014626 ], [ -68.832621770008856, 44.69246313123255 ], [ -68.832061072373804, 44.692282259139517 ], [ -68.831288985646353, 44.692101074727489 ], [ -68.830903103677556, 44.6920239825929 ], [ -68.830551429295753, 44.691982949711829 ], [ -68.828481327604109, 44.691565749390804 ], [ -68.828059995426074, 44.691475091349936 ], [ -68.827254122063906, 44.691257818961056 ], [ -68.826182456390683, 44.691035632306281 ], [ -68.823973887592544, 44.690393079343721 ], [ -68.822572464667417, 44.689940788137669 ], [ -68.821941144956909, 44.689786765163653 ], [ -68.821308766910505, 44.68972276157637 ], [ -68.820727632597709, 44.689793870483136 ], [ -68.820443421671129, 44.689878946686363 ], [ -68.819946688401288, 44.69020225045292 ], [ -68.819786424888264, 44.690377544880114 ], [ -68.819678102551563, 44.690588930906458 ], [ -68.819583198641809, 44.691178438474907 ], [ -68.81959167209537, 44.692132709103063 ], [ -68.819644755605509, 44.692438873715879 ], [ -68.819780973286072, 44.692898212384478 ], [ -68.820115748205964, 44.693429883345395 ], [ -68.820103764925719, 44.693605411570353 ], [ -68.820065314928442, 44.693668366875499 ], [ -68.819998563391437, 44.693699769627507 ], [ -68.819957220782257, 44.693677200225885 ], [ -68.819856177456643, 44.693573515886342 ], [ -68.819806427048235, 44.693465405521657 ], [ -68.819711727065979, 44.693352727355325 ], [ -68.819705977644077, 44.693298701081261 ], [ -68.819433430913918, 44.693050703808964 ], [ -68.819250327782612, 44.692829858578442 ], [ -68.818887663918758, 44.692140596050976 ], [ -68.818813895598353, 44.691892912299942 ], [ -68.818803453796832, 44.691699346191591 ], [ -68.818950867707471, 44.691096417018599 ], [ -68.818953072076496, 44.690893869747129 ], [ -68.818944564082926, 44.690839839038418 ], [ -68.818821642145522, 44.690799132443047 ], [ -68.818784782309478, 44.690731556201854 ], [ -68.818793118028864, 44.690461495862557 ], [ -68.818716298944167, 44.690434367851616 ], [ -68.818524207958347, 44.690443063981114 ], [ -68.818305497028874, 44.69051473586287 ], [ -68.818208636530443, 44.690591103198479 ], [ -68.818149521821454, 44.690703537855683 ], [ -68.818026068654902, 44.690833877399328 ], [ -68.817929217841098, 44.690905742655531 ], [ -68.817691152525569, 44.690986383694799 ], [ -68.817312717042782, 44.691057798592176 ], [ -68.817037000280422, 44.691070860275069 ], [ -68.816696859281834, 44.691128831422887 ], [ -68.816575405050258, 44.691124134573045 ], [ -68.816549319264325, 44.691142097577732 ], [ -68.816402187620838, 44.691150862345083 ], [ -68.816268775941481, 44.691060625796808 ], [ -68.81616371085461, 44.69073636846651 ], [ -68.81617833677393, 44.690601356482908 ], [ -68.816140620506488, 44.690556284765954 ], [ -68.816118220087645, 44.690281673275294 ], [ -68.816030884724753, 44.690087980519998 ], [ -68.815791767453959, 44.689754505582506 ], [ -68.815792304329477, 44.689709495436205 ], [ -68.815715910403085, 44.689673362380397 ], [ -68.815405697045406, 44.689375781686209 ], [ -68.814986114081378, 44.68911853468493 ], [ -68.814794611106251, 44.6890687089141 ], [ -68.814532385031313, 44.689059282178242 ], [ -68.814295951071387, 44.689000381397747 ], [ -68.81409917146442, 44.688874029407856 ], [ -68.813706322928752, 44.6885222947869 ], [ -68.813797793347149, 44.688405410776603 ], [ -68.813785901341305, 44.688301863774925 ], [ -68.813747678822196, 44.688292800247503 ], [ -68.81368489983717, 44.688193669580109 ], [ -68.813731019483882, 44.688076714135192 ], [ -68.814008789289204, 44.687910623268259 ], [ -68.814060084714555, 44.687901703080449 ], [ -68.814124987839662, 44.687829789077014 ], [ -68.814254201535888, 44.687748978445335 ], [ -68.814448930607071, 44.687528734160679 ], [ -68.814514868936186, 44.687380302609895 ], [ -68.814444803832885, 44.687339677111254 ], [ -68.814284214390256, 44.687366424715975 ], [ -68.814207738152177, 44.687357296619261 ], [ -68.814144475310769, 44.687285174028702 ], [ -68.814132438962261, 44.687226640350772 ], [ -68.814171184557125, 44.687195192915766 ], [ -68.814258586852759, 44.686871249124856 ], [ -68.814233535214314, 44.686812691774627 ], [ -68.814125784021343, 44.686717995043921 ], [ -68.814094859452439, 44.686645920021931 ], [ -68.814208471651398, 44.686263504798511 ], [ -68.814196012496168, 44.686213969121866 ], [ -68.814145737236558, 44.686150871360624 ], [ -68.813871531829818, 44.68606940393439 ], [ -68.813712564501813, 44.685961115239074 ], [ -68.813625240087418, 44.685767420515667 ], [ -68.813614805693689, 44.685578353084459 ], [ -68.813628969859877, 44.685465844819234 ], [ -68.813674447972417, 44.685425407324281 ], [ -68.813656174247825, 44.685344356622203 ], [ -68.813800594708141, 44.685070019000655 ], [ -68.813917344058439, 44.68493967297001 ], [ -68.814009447406249, 44.68474627070939 ], [ -68.814036639774471, 44.684629284245247 ], [ -68.81401107992555, 44.684606735842301 ], [ -68.814000637433878, 44.684417668394566 ], [ -68.81396721783284, 44.68426457336372 ], [ -68.814538748797048, 44.684098956708908 ], [ -68.815793432051422, 44.683754394335573 ], [ -68.815861151241165, 44.684285647574541 ], [ -68.815991758912759, 44.684758485437683 ], [ -68.816245188077957, 44.685299038616805 ], [ -68.816536985352116, 44.685803642983807 ], [ -68.816853652557825, 44.686177752671973 ], [ -68.817085974038648, 44.686412186410479 ], [ -68.81760049872247, 44.686822620532695 ], [ -68.818313474461092, 44.687206359553102 ], [ -68.81868250932645, 44.687359989058471 ], [ -68.819249902963875, 44.687513928956633 ], [ -68.819929129108132, 44.687596022755692 ], [ -68.821056148778823, 44.687615799057312 ], [ -68.821822613758343, 44.687671012132455 ], [ -68.822415526231566, 44.687739453394265 ], [ -68.822959014092561, 44.687848326654645 ], [ -68.825623538791064, 44.688563616242504 ], [ -68.827411734831074, 44.689047960703519 ], [ -68.831223528226218, 44.690061929657659 ], [ -68.83287621236758, 44.69052348384961 ], [ -68.834886450375862, 44.691048547476079 ], [ -68.835612923435662, 44.691319668979119 ], [ -68.83594490510545, 44.691491191649462 ], [ -68.836499238022569, 44.691834077186201 ], [ -68.837024749951439, 44.692329961787891 ], [ -68.83741401626672, 44.692893167790352 ], [ -68.837619495184128, 44.693316573937778 ], [ -68.837738817832545, 44.693663335880466 ], [ -68.837834086338404, 44.694010063525305 ], [ -68.837843867577348, 44.694320659939464 ], [ -68.837811838601695, 44.694914773379992 ], [ -68.837720859762669, 44.695292746841183 ], [ -68.837442265903235, 44.695764977100055 ], [ -68.836543009134488, 44.697024033137872 ], [ -68.836241571360233, 44.697617757445421 ], [ -68.836253670163302, 44.69766278574297 ], [ -68.836207436766401, 44.697973304283934 ], [ -68.836218079933218, 44.698535967663894 ], [ -68.836301004784374, 44.699062727369174 ], [ -68.836299466845887, 44.699188759307845 ], [ -68.836330930490675, 44.699220314820209 ], [ -68.836366994311078, 44.699440924355848 ], [ -68.836545071953935, 44.700075846828923 ], [ -68.837004240726756, 44.70132783794584 ], [ -68.837042441101588, 44.701350399174032 ], [ -68.837205774918374, 44.701620702649755 ], [ -68.837256587267973, 44.701647783626811 ], [ -68.837337669797236, 44.701850452034357 ], [ -68.837528604867728, 44.702125298688166 ], [ -68.837875928145849, 44.702053772783948 ], [ -68.839752499027838, 44.701718830577107 ], [ -68.839766650861392, 44.701736855302237 ], [ -68.839726943416409, 44.701831325777277 ], [ -68.839777703956358, 44.701876407917183 ], [ -68.839889760323032, 44.702151137426398 ], [ -68.84016001974652, 44.702561126091872 ], [ -68.840234829672653, 44.702754782453795 ], [ -68.840312890165492, 44.703200508906214 ], [ -68.840294246879438, 44.703668609301332 ], [ -68.840354957583273, 44.703970272494182 ], [ -68.840760172048007, 44.704366945156302 ], [ -68.840878082022996, 44.704668690283036 ], [ -68.840960220011809, 44.704781333184265 ], [ -68.84115035587611, 44.704925636673615 ], [ -68.841276995920779, 44.705065349773768 ], [ -68.841338328794748, 44.705285992629051 ], [ -68.8413304890136, 44.705412015743171 ], [ -68.841367741798862, 44.705493088096176 ], [ -68.841501237895599, 44.705578798395827 ], [ -68.841808451490849, 44.705610732206537 ], [ -68.841910474800272, 44.705664885534986 ], [ -68.841960735829133, 44.705750480049176 ], [ -68.842011550487967, 44.705777558894432 ], [ -68.84226141871963, 44.706300037557284 ], [ -68.842285522764698, 44.706430609181297 ], [ -68.842336240429532, 44.706493694942957 ], [ -68.842459931250048, 44.706849460864376 ], [ -68.842760542735746, 44.707430529738019 ], [ -68.842822344093008, 44.707624166329232 ], [ -68.842845417702534, 44.707844755616108 ], [ -68.84285142768961, 44.708393910531093 ], [ -68.842798618773301, 44.708519871791751 ], [ -68.842824175948422, 44.708551414822985 ], [ -68.842816460754548, 44.708632424764197 ], [ -68.842704000720431, 44.70893385049277 ], [ -68.842716549967079, 44.708960873790261 ], [ -68.842363891755824, 44.709532040799481 ], [ -68.84223208190231, 44.709837938634209 ], [ -68.842154070530754, 44.70994585739308 ], [ -68.842139540190715, 44.710067371884797 ], [ -68.842303922145547, 44.71026115040916 ], [ -68.842341570203246, 44.71034222543215 ], [ -68.842408140398206, 44.710670903786138 ], [ -68.842483053662036, 44.710833048188604 ], [ -68.842666362745277, 44.711031354105891 ], [ -68.842653268854193, 44.711058344582277 ], [ -68.842742309673, 44.711103478064736 ], [ -68.842945418354205, 44.711274802271681 ], [ -68.843059067884994, 44.71140999604917 ], [ -68.843108868246361, 44.711522592830384 ], [ -68.843057483390695, 44.711558531906796 ], [ -68.842939331289884, 44.71177442753951 ], [ -68.84289910948911, 44.711913909081204 ], [ -68.84294574900656, 44.71231908079443 ], [ -68.842852662082606, 44.712602525767558 ], [ -68.842412370131669, 44.713038534439157 ], [ -68.842205193310846, 44.713200291883609 ], [ -68.842049222314643, 44.713393627606301 ], [ -68.841891699493445, 44.713721995943274 ], [ -68.841676173708123, 44.71405028616158 ], [ -68.841624391352042, 44.714086224026111 ], [ -68.841617523866105, 44.714144728317684 ], [ -68.841539086592732, 44.714261652165021 ], [ -68.841190425885245, 44.714508731140697 ], [ -68.841112480170423, 44.71458964571373 ], [ -68.840929377501453, 44.714890973588936 ], [ -68.840630595626607, 44.715219140754336 ], [ -68.840501279603359, 44.71532698918918 ], [ -68.840424265524618, 44.715353887592485 ], [ -68.840152682424474, 44.715547059055808 ], [ -68.839514135366201, 44.715892754552549 ], [ -68.839404179730991, 44.715991627779196 ], [ -68.839181229696848, 44.716427929145063 ], [ -68.839077076071106, 44.71656731918474 ], [ -68.838824308244497, 44.716801022923327 ], [ -68.838553204051181, 44.716958181567179 ], [ -68.838251068562244, 44.717065782989394 ], [ -68.837838607508814, 44.717258749284035 ], [ -68.837735044839306, 44.71732611963877 ], [ -68.837514682479608, 44.71753736234286 ], [ -68.837292261582121, 44.717919646200656 ], [ -68.837277639815838, 44.718068165744107 ], [ -68.837170925967314, 44.718414604496182 ], [ -68.837039475510167, 44.718715997050623 ], [ -68.836948427101049, 44.718823895992486 ], [ -68.836959943290069, 44.718936440644498 ], [ -68.836843316153548, 44.719017297013551 ], [ -68.836843214964048, 44.719053303987415 ], [ -68.836608781580182, 44.719354548845224 ], [ -68.836128789271541, 44.719839988573646 ], [ -68.835753444623066, 44.720154532341333 ], [ -68.835546672776303, 44.72029827327512 ], [ -68.835507996641013, 44.720302719407421 ], [ -68.835352486490265, 44.72045553495537 ], [ -68.835042089661272, 44.720684647747973 ], [ -68.834827483692365, 44.720945406051925 ], [ -68.834775091550014, 44.721053359118415 ], [ -68.834792921748772, 44.721165915589829 ], [ -68.834912898672016, 44.721296622051085 ], [ -68.835097717723755, 44.721382411263384 ], [ -68.835353727846439, 44.721409789089392 ], [ -68.835391873435924, 44.721454854837134 ], [ -68.835443220766379, 44.721436924025561 ], [ -68.83551969423614, 44.721464042652634 ], [ -68.835608630709842, 44.721549692907132 ], [ -68.835620237565308, 44.721630729987389 ], [ -68.835374635538926, 44.721828429094842 ], [ -68.83534805794099, 44.721877903369354 ], [ -68.835290408604862, 44.721891323219168 ], [ -68.835167449578748, 44.721976668020879 ], [ -68.835133958399936, 44.722098151485966 ], [ -68.835151229010151, 44.72226922331518 ], [ -68.835122437599878, 44.722543753130566 ], [ -68.835068563595058, 44.722755231151488 ], [ -68.834937169134307, 44.723029612678289 ], [ -68.834833404206236, 44.723164497419191 ], [ -68.834819819831097, 44.723222994005134 ], [ -68.834781096215892, 44.723240942793545 ], [ -68.834806248239587, 44.723276988779354 ], [ -68.834792154084028, 44.723375993542462 ], [ -68.834918818926127, 44.72351571327674 ], [ -68.834995291363867, 44.723542832243652 ], [ -68.83525734955937, 44.723529707585158 ], [ -68.835365404125938, 44.723552367517811 ], [ -68.835422062030318, 44.723610965406365 ], [ -68.835286383052733, 44.723867336320168 ], [ -68.835130446250105, 44.724029154509211 ], [ -68.835064496609462, 44.724186603156241 ], [ -68.834856634538838, 44.724429363784978 ], [ -68.834737800514404, 44.724726269786558 ], [ -68.834488663966965, 44.72518953438329 ], [ -68.834435311545079, 44.725355997010467 ], [ -68.834407621587445, 44.725518000014588 ], [ -68.834418130465338, 44.7257070643304 ], [ -68.83451606401313, 44.72609880989215 ], [ -68.834463778627722, 44.726166251462992 ], [ -68.834310362568047, 44.726688165428335 ], [ -68.834273818911655, 44.727048208202035 ], [ -68.834283230247337, 44.727345299617546 ], [ -68.834332491366837, 44.727507411666849 ], [ -68.834534146846678, 44.727782277640614 ], [ -68.834558220159934, 44.72792184898497 ], [ -68.834475660651734, 44.728367344668534 ], [ -68.834472978717443, 44.728614903432245 ], [ -68.834540066420459, 44.728889574227338 ], [ -68.83466580334516, 44.729083307111587 ], [ -68.834888851810192, 44.729196160311268 ], [ -68.835048614399369, 44.729218897775162 ], [ -68.835414128235001, 44.729192416675936 ], [ -68.835478519951053, 44.729170002847376 ], [ -68.835594141730596, 44.729174668659688 ], [ -68.83569577707577, 44.729237835426396 ], [ -68.835719846732644, 44.729377406485057 ], [ -68.835692145670265, 44.729543908982492 ], [ -68.835612682633311, 44.729732841068369 ], [ -68.83542990144764, 44.730034159785127 ], [ -68.835390112870428, 44.730146632944383 ], [ -68.835325210607451, 44.73020955485341 ], [ -68.835308517288354, 44.730529114977223 ], [ -68.835344125211691, 44.730776731387081 ], [ -68.835297081873335, 44.730943205859916 ], [ -68.835019109606833, 44.731131853547694 ], [ -68.834823734330939, 44.731415145740151 ], [ -68.834655709820822, 44.73151842692566 ], [ -68.834519575738341, 44.731648767512901 ], [ -68.834431150260841, 44.732071750289251 ], [ -68.83431382878571, 44.732247126055896 ], [ -68.83400395229674, 44.732408719037082 ], [ -68.833965119269934, 44.732462674394171 ], [ -68.833957860211797, 44.732516678156784 ], [ -68.833995595257306, 44.732570747327571 ], [ -68.834065702831168, 44.73262036170393 ], [ -68.834180942678444, 44.732620529079583 ], [ -68.834566839374517, 44.732513060082979 ], [ -68.834643327013069, 44.732540179265094 ], [ -68.834693052113636, 44.732679787601711 ], [ -68.834679478167089, 44.732733782267672 ], [ -68.834523425930868, 44.732927106928912 ], [ -68.834173211534704, 44.733255184135047 ], [ -68.833525959060765, 44.733803386697502 ], [ -68.833389322704278, 44.733969729666008 ], [ -68.833375743717383, 44.734023724157375 ], [ -68.8334192288618, 44.734136318013405 ], [ -68.833495679360482, 44.734176938338827 ], [ -68.833726570309977, 44.734177274723059 ], [ -68.833764796834757, 44.734195337647542 ], [ -68.833827149135942, 44.734334962188591 ], [ -68.833798813653445, 44.734582485858688 ], [ -68.833580562701911, 44.735131312102389 ], [ -68.833584664350184, 44.735351874546531 ], [ -68.833659662026236, 44.735487018268387 ], [ -68.833695339773286, 44.735707629190898 ], [ -68.833746099373869, 44.735761717378949 ], [ -68.833822578019252, 44.735793336389605 ], [ -68.834168743764053, 44.735784835915752 ], [ -68.834476100265846, 44.73582129131136 ], [ -68.834929619389172, 44.735952482853698 ], [ -68.835543469934223, 44.73605239336402 ], [ -68.836278694867758, 44.736219994367154 ], [ -68.836624341550319, 44.736256498862794 ], [ -68.836688206770759, 44.736283593578946 ], [ -68.836700301216723, 44.736333125845796 ], [ -68.836648495864026, 44.736369061279902 ], [ -68.836372940714028, 44.736391173397777 ], [ -68.836340524717045, 44.736409131709976 ], [ -68.835494308747897, 44.736407915948703 ], [ -68.835275945591988, 44.736443610727058 ], [ -68.835083717513953, 44.736447835128452 ], [ -68.834852276284593, 44.736501517481095 ], [ -68.834543253931372, 44.736631600317331 ], [ -68.834362152283177, 44.736748367481731 ], [ -68.83415521482263, 44.736928114751073 ], [ -68.833998758512053, 44.737121437965762 ], [ -68.833830166748115, 44.737278733789722 ], [ -68.833394438106723, 44.737822740968262 ], [ -68.833295994898037, 44.73801614780416 ], [ -68.833189272025692, 44.738344576853081 ], [ -68.833187137375575, 44.738538124204254 ], [ -68.83322432227078, 44.738646207027074 ], [ -68.833210182788235, 44.738758714197679 ], [ -68.832949994730981, 44.739059912883711 ], [ -68.832458267412477, 44.739441789138766 ], [ -68.832455107181758, 44.739716360072208 ], [ -68.832430691136636, 44.739833353863617 ], [ -68.832372039096796, 44.739914287905783 ], [ -68.831959030967056, 44.740098230264209 ], [ -68.831878614921294, 44.740197136771975 ], [ -68.831871248574942, 44.740287149665349 ], [ -68.831908422607881, 44.740399734681809 ], [ -68.832199166680638, 44.740728746970753 ], [ -68.83221068492584, 44.740841291671416 ], [ -68.832144769721864, 44.740976231657996 ], [ -68.831936822038756, 44.74122349296362 ], [ -68.831898115124517, 44.741232434603589 ], [ -68.83191061410885, 44.741277463605407 ], [ -68.831819530170179, 44.741380858674091 ], [ -68.831326225564553, 44.741888760772973 ], [ -68.831279083052863, 44.742082238975748 ], [ -68.831270230706721, 44.742275778750169 ], [ -68.831221183845258, 44.742446752570643 ], [ -68.831104831837536, 44.742685141486888 ], [ -68.830591498157133, 44.7432875361757 ], [ -68.830526628549194, 44.743332453033418 ], [ -68.83009715326186, 44.743871954518511 ], [ -68.829965216962719, 44.74417333685679 ], [ -68.829937949232459, 44.74431733413504 ], [ -68.829967870972041, 44.744479418784444 ], [ -68.830024372320224, 44.744596534915203 ], [ -68.830157424715935, 44.74472276097314 ], [ -68.830289494483679, 44.744916510065657 ], [ -68.830269928378385, 44.745128035966353 ], [ -68.830149726622423, 44.745330411123717 ], [ -68.83012869662366, 44.745501426046559 ], [ -68.830289977224027, 44.745965281970719 ], [ -68.83047808062841, 44.746303149371464 ], [ -68.830617928388776, 44.746402384126633 ], [ -68.83074615856998, 44.746425078260792 ], [ -68.831195629081719, 44.746344723464517 ], [ -68.831350135601312, 44.746290937543662 ], [ -68.831465406113537, 44.746291107705161 ], [ -68.832596723372589, 44.746585344007443 ], [ -68.832673202640578, 44.746621470560058 ], [ -68.833071940425569, 44.747022654834346 ], [ -68.833285182615256, 44.747410066655917 ], [ -68.833322363918342, 44.747522651082107 ], [ -68.833342334330609, 44.74799080053166 ], [ -68.833316574489402, 44.748026772384442 ], [ -68.8333407624947, 44.748125832403282 ], [ -68.833287320784422, 44.748314805244036 ], [ -68.833318259517256, 44.748400372203164 ], [ -68.833423775719595, 44.748499550864636 ], [ -68.833124875337688, 44.748656655197095 ], [ -68.832962876000821, 44.748705933240757 ], [ -68.832540918920515, 44.748822342233858 ], [ -68.832523665994401, 44.748781808197251 ], [ -68.83223557299786, 44.748340270954643 ], [ -68.832217726541359, 44.74823221640559 ], [ -68.832160575139511, 44.748200624793846 ], [ -68.832009726106321, 44.747943837590718 ], [ -68.832037026006901, 44.747786337041752 ], [ -68.832297326676283, 44.74746263453072 ], [ -68.832415604403138, 44.74724225215094 ], [ -68.832397848989814, 44.747102690100455 ], [ -68.832265767208597, 44.746908946013207 ], [ -68.83214479795582, 44.746832247568626 ], [ -68.831991327648225, 44.746800514260144 ], [ -68.831792774065207, 44.746795720189319 ], [ -68.831091946574574, 44.746974733109553 ], [ -68.830905540192845, 44.747001463103963 ], [ -68.830790745179314, 44.746974287248051 ], [ -68.830764638624032, 44.746992253291857 ], [ -68.83064936672254, 44.746992082420974 ], [ -68.830098897858221, 44.746914744126478 ], [ -68.82995797024239, 44.746914534388068 ], [ -68.829721271776691, 44.746860167546096 ], [ -68.829562499711798, 44.746751902352813 ], [ -68.829461917243208, 44.746589712170987 ], [ -68.829251325859488, 44.745981738561767 ], [ -68.82926490798566, 44.745927747189882 ], [ -68.829226744087805, 44.745882677050943 ], [ -68.829190052944014, 44.745743086152693 ], [ -68.829088946043953, 44.745625905400217 ], [ -68.829000353982508, 44.745549252055689 ], [ -68.828847425962493, 44.745468002945309 ], [ -68.828808715733473, 44.745476946037236 ], [ -68.828642656899518, 44.745431686430614 ], [ -68.828449980899848, 44.745444900096807 ], [ -68.828135084397616, 44.745538952124022 ], [ -68.827651172366103, 44.745785787298367 ], [ -68.827262584987196, 44.746100281734712 ], [ -68.82650993463686, 44.746841831504504 ], [ -68.826249540612636, 44.747188024741014 ], [ -68.826117097643674, 44.747516410028545 ], [ -68.826102925143516, 44.747633417901838 ], [ -68.825930128382538, 44.74812378148917 ], [ -68.82587768149132, 44.748236229171226 ], [ -68.825760423040521, 44.748371087006774 ], [ -68.825618934907467, 44.748424885223763 ], [ -68.825542511816451, 44.7483707543444 ], [ -68.825504217307724, 44.74837069584121 ], [ -68.82546648347487, 44.74831662401666 ], [ -68.82547432314874, 44.748204105856608 ], [ -68.825417297402481, 44.748131999809289 ], [ -68.825405780914778, 44.748023953868341 ], [ -68.825342887054589, 44.747933836598307 ], [ -68.825215661930542, 44.747839114026938 ], [ -68.825018088227282, 44.747771296912362 ], [ -68.824729989832704, 44.74774384680061 ], [ -68.824124580249801, 44.747949971669421 ], [ -68.824034939021772, 44.747958834695979 ], [ -68.823970062643198, 44.748003745271156 ], [ -68.823229402816281, 44.748286175026969 ], [ -68.822874262330814, 44.748492677830285 ], [ -68.822667278370147, 44.748663402733577 ], [ -68.82180349501634, 44.749053657772635 ], [ -68.821649477664479, 44.749071422076653 ], [ -68.821623900386228, 44.749044376307509 ], [ -68.821559498630165, 44.749062280422216 ], [ -68.821316412686144, 44.749030392728351 ], [ -68.821123622397252, 44.749075101478162 ], [ -68.820968648820596, 44.749146877524126 ], [ -68.820645378916694, 44.749384930950271 ], [ -68.820129428535097, 44.749631683766445 ], [ -68.820013659054425, 44.749663009005047 ], [ -68.819783234169876, 44.749622136900342 ], [ -68.819667918645891, 44.749635457787228 ], [ -68.819267246444909, 44.749877886855124 ], [ -68.81903885674582, 44.750071075276104 ], [ -68.819019453679317, 44.75008904924659 ], [ -68.818352512418841, 44.750515599274706 ], [ -68.817747667911718, 44.751027766247546 ], [ -68.816961512637519, 44.751818716319193 ], [ -68.816555394987958, 44.752277183566839 ], [ -68.815889938364634, 44.753216854329906 ], [ -68.815837447458946, 44.753459831972947 ], [ -68.815584964703149, 44.753896036766619 ], [ -68.815396715705944, 44.754368354218684 ], [ -68.815332187917093, 44.754422264006088 ], [ -68.815178520313111, 44.754449018716748 ], [ -68.815101316878753, 44.754516415779705 ], [ -68.815215936456354, 44.754602122995372 ], [ -68.815241298054005, 44.754696686827963 ], [ -68.815173469073144, 44.754795604190726 ], [ -68.814906550467612, 44.754925704112402 ], [ -68.814809972347717, 44.755002068155086 ], [ -68.814809799837676, 44.755056081976939 ], [ -68.81489284808552, 44.755137236507871 ], [ -68.814911626066703, 44.755191278531242 ], [ -68.814878632457507, 44.755384777460812 ], [ -68.81478760306662, 44.755578179760306 ], [ -68.81462687409433, 44.755712952973354 ], [ -68.814170268839206, 44.756018290794827 ], [ -68.814008954848035, 44.756211578068374 ], [ -68.813911617591003, 44.756400467566898 ], [ -68.813571007326786, 44.756606964817927 ], [ -68.813500334472721, 44.756606849431421 ], [ -68.813185762354095, 44.756696358780601 ], [ -68.812928718714133, 44.756821970897789 ], [ -68.812587942437176, 44.757077977210585 ], [ -68.81241971803361, 44.757329766744014 ], [ -68.812291135833263, 44.757410575344544 ], [ -68.811442697434316, 44.757877297201709 ], [ -68.810433826295338, 44.758379755916145 ], [ -68.809491268302196, 44.758882318820412 ], [ -68.80928333122155, 44.75895848981316 ], [ -68.809129826632784, 44.758931227592939 ], [ -68.809014121624656, 44.758935535960475 ], [ -68.808552150654691, 44.759056293498602 ], [ -68.808256740260632, 44.759195333614137 ], [ -68.80797957597899, 44.759428926363476 ], [ -68.807895919796223, 44.759532311997724 ], [ -68.806778475046571, 44.759895022424708 ], [ -68.805474297387136, 44.760477956969851 ], [ -68.805050170373846, 44.760729299337747 ], [ -68.804773012631642, 44.760953883167225 ], [ -68.804386404119597, 44.761317814548704 ], [ -68.804308935897495, 44.761457217479737 ], [ -68.804282324809307, 44.761619213997683 ], [ -68.80424343283498, 44.761677660666756 ], [ -68.803934802735668, 44.761866181628136 ], [ -68.803805514519539, 44.762032500992412 ], [ -68.803715635084359, 44.762104365267142 ], [ -68.803484228377059, 44.762225498268307 ], [ -68.803137533739118, 44.762341930333477 ], [ -68.802925092944406, 44.762458595601025 ], [ -68.802429401687448, 44.76284483844848 ], [ -68.801717250100268, 44.763019146699342 ], [ -68.801569196716116, 44.763126917607259 ], [ -68.801401520983788, 44.763315679001423 ], [ -68.801176281025747, 44.763477324145548 ], [ -68.801060477213213, 44.763508632545069 ], [ -68.800875102633157, 44.763445291873531 ], [ -68.800836341651433, 44.763463228959218 ], [ -68.800765289196391, 44.763571133071146 ], [ -68.80084745580173, 44.763791831743134 ], [ -68.800821023071265, 44.763899813682052 ], [ -68.800678897759056, 44.764120123583993 ], [ -68.800573922853573, 44.764561050998736 ], [ -68.800470100267276, 44.764781427492267 ], [ -68.800500162676755, 44.765110063336607 ], [ -68.800485979493018, 44.765330593861918 ], [ -68.800554951722987, 44.765713314137898 ], [ -68.800528796387866, 44.765740274203026 ], [ -68.800375045479143, 44.765780516688899 ], [ -68.80033009122134, 44.765762433437047 ], [ -68.800146492954724, 44.765411022550616 ], [ -68.799929856925729, 44.765136071434114 ], [ -68.799827799595022, 44.765072877517916 ], [ -68.799712495468043, 44.765072675364451 ], [ -68.799629065338493, 44.765104036562803 ], [ -68.79921707227588, 44.765368881222983 ], [ -68.798991646523078, 44.765580038901376 ], [ -68.798733419095228, 44.765912669194051 ], [ -68.798681313640301, 44.766020605351464 ], [ -68.798533187881915, 44.766146376803945 ], [ -68.798436346834677, 44.766285741456258 ], [ -68.798198452178084, 44.766447360818226 ], [ -68.797967189193272, 44.766518970603066 ], [ -68.797812788494994, 44.766631227139456 ], [ -68.797631080959974, 44.766986496775814 ], [ -68.797636329725279, 44.767180053056769 ], [ -68.797571472451949, 44.767319476128719 ], [ -68.797378190468891, 44.767481172818492 ], [ -68.797287702261613, 44.767611546659879 ], [ -68.797159028911736, 44.767705840781794 ], [ -68.796857417097584, 44.767790828714318 ], [ -68.796760667497281, 44.767903183823151 ], [ -68.796631613690323, 44.767992977387124 ], [ -68.796400705727706, 44.768073585686523 ], [ -68.796265963678039, 44.768095851850688 ], [ -68.79597792077621, 44.768027820802672 ], [ -68.795914103158637, 44.767982693875801 ], [ -68.795894959911521, 44.767924146405335 ], [ -68.795978933460745, 44.767852277809304 ], [ -68.796325485587502, 44.767789881315835 ], [ -68.796415347864439, 44.767727023973634 ], [ -68.796699249318806, 44.767398946527464 ], [ -68.796892513625636, 44.767241750235378 ], [ -68.797459960639685, 44.766684615953203 ], [ -68.797595687457189, 44.766491307068954 ], [ -68.798078158188616, 44.766177078227464 ], [ -68.798309564145285, 44.766064962362755 ], [ -68.798412705094435, 44.765930108216118 ], [ -68.798465108324677, 44.765736651167494 ], [ -68.798805763501917, 44.765548204049558 ], [ -68.798903043983998, 44.765395339477429 ], [ -68.799199223517633, 44.765161797415793 ], [ -68.799282953629827, 44.765044915511027 ], [ -68.7995203880415, 44.76501382249841 ], [ -68.799982953307691, 44.764740064229066 ], [ -68.799959026586734, 44.764465452986435 ], [ -68.800036888490339, 44.764330555564932 ], [ -68.80003718351297, 44.764245034521466 ], [ -68.799974165434861, 44.764082882123539 ], [ -68.800014020629604, 44.76386239405948 ], [ -68.800262668896579, 44.763669279588456 ], [ -68.800464033083685, 44.763561603538761 ], [ -68.800554402909825, 44.763462736942891 ], [ -68.800619155761765, 44.763350322677091 ], [ -68.800619937518363, 44.763237794200158 ], [ -68.800549926583628, 44.763156652175056 ], [ -68.800402795872827, 44.763111382190239 ], [ -68.80016006981441, 44.762962421038822 ], [ -68.800044738834771, 44.762971220256127 ], [ -68.799350728241407, 44.763262577145774 ], [ -68.799081455876347, 44.763253102664187 ], [ -68.798965948906286, 44.763311417730023 ], [ -68.798579808074166, 44.763639318268901 ], [ -68.798579526550299, 44.763720337545529 ], [ -68.798739079918136, 44.763828646865711 ], [ -68.798783399574802, 44.763914246525509 ], [ -68.798705441529989, 44.764076151195837 ], [ -68.798589256319772, 44.764215481932069 ], [ -68.798473860008897, 44.764242286627791 ], [ -68.798161031556248, 44.764039181009181 ], [ -68.798084093487546, 44.764021040338029 ], [ -68.797975075502976, 44.764029848624659 ], [ -68.797132586603084, 44.764541487077373 ], [ -68.797125683851192, 44.764595488826238 ], [ -68.797176923693996, 44.764622588096351 ], [ -68.797369326403, 44.764595921366826 ], [ -68.797433235821387, 44.764614039409736 ], [ -68.797407379855443, 44.764668007556409 ], [ -68.795713002133667, 44.765097098866185 ], [ -68.794018025198156, 44.765575678641348 ], [ -68.793671423293773, 44.765656072734373 ], [ -68.793556130560248, 44.765651362591534 ], [ -68.793324977398839, 44.765691455645758 ], [ -68.792246040100608, 44.76604959136565 ], [ -68.791410567030397, 44.766453169690756 ], [ -68.791255930419538, 44.766628432000118 ], [ -68.791114284692156, 44.766704693463709 ], [ -68.790767733506271, 44.76676707415767 ], [ -68.790356262052114, 44.766982373024618 ], [ -68.790118345566398, 44.767143980516195 ], [ -68.789982699426119, 44.767305773109577 ], [ -68.789853998580242, 44.767404560748133 ], [ -68.789120448438069, 44.767898335529331 ], [ -68.788991117121938, 44.768060136072577 ], [ -68.788848348636492, 44.768334443875347 ], [ -68.788461558084677, 44.768707321607806 ], [ -68.788402815733349, 44.76889626042766 ], [ -68.788354373799777, 44.76950832895087 ], [ -68.78827608307931, 44.769751245411932 ], [ -68.788235278029248, 44.770111260309264 ], [ -68.788246318352051, 44.770439861285688 ], [ -68.788167417247365, 44.770741294753797 ], [ -68.78816641372093, 44.770907836535351 ], [ -68.788254858794701, 44.771128555626795 ], [ -68.78824676274121, 44.771398610349628 ], [ -68.788289813395693, 44.77172277131536 ], [ -68.788260948803753, 44.772271858269697 ], [ -68.788194964587092, 44.77260482059674 ], [ -68.788025206353439, 44.773126637801724 ], [ -68.788124237330067, 44.773693964027075 ], [ -68.787979142499012, 44.77438236784694 ], [ -68.78792749945579, 44.774463294092214 ], [ -68.787882430551605, 44.774476715756201 ], [ -68.787805382985596, 44.774485573692772 ], [ -68.787536537774642, 44.774453566375172 ], [ -68.787305444497719, 44.77446663908038 ], [ -68.787202560019438, 44.774520461341652 ], [ -68.787163655137377, 44.774574402760422 ], [ -68.787118202112424, 44.774691346938027 ], [ -68.786723320354824, 44.775316270704401 ], [ -68.786611815623246, 44.775779678640745 ], [ -68.786642551282029, 44.776013796309449 ], [ -68.786762480088697, 44.776266082651738 ], [ -68.786704334645364, 44.776396508288428 ], [ -68.786556126709826, 44.77653126488282 ], [ -68.786221126566403, 44.776764698515038 ], [ -68.786079209700645, 44.776903968043023 ], [ -68.785448414906782, 44.777339395160659 ], [ -68.785095393697816, 44.777424252782765 ], [ -68.784864662600981, 44.77744182300836 ], [ -68.784243402638481, 44.777328121465708 ], [ -68.784128040693233, 44.777336907038475 ], [ -68.78406338760449, 44.777408803331902 ], [ -68.783997897045936, 44.77760222862203 ], [ -68.783830199053682, 44.777768452258236 ], [ -68.78352126902837, 44.777997425477409 ], [ -68.78347603791984, 44.77805135361529 ], [ -68.783482055590056, 44.778132387102097 ], [ -68.783365960524904, 44.778231191137962 ], [ -68.782477616172542, 44.778873167362299 ], [ -68.782421858666439, 44.778891063264759 ], [ -68.782387461944381, 44.778899998786414 ], [ -68.782374223138632, 44.778953987433887 ], [ -68.781936502851593, 44.779290738571667 ], [ -68.781743513855389, 44.779353384846132 ], [ -68.781589832619517, 44.779362094614548 ], [ -68.78072663171146, 44.780031110848299 ], [ -68.780378946469497, 44.780264500332088 ], [ -68.780095694320934, 44.780484512505261 ], [ -68.779798478511225, 44.780844029701711 ], [ -68.779792263928755, 44.780817012046747 ], [ -68.779618090316944, 44.781019226153198 ], [ -68.779617575628421, 44.781050732613679 ], [ -68.779431122505287, 44.78115840037227 ], [ -68.779258322576538, 44.781104052657518 ], [ -68.779104739318299, 44.781085751086408 ], [ -68.778924039333333, 44.781238439431831 ], [ -68.778916911433413, 44.781346453336312 ], [ -68.779102044464793, 44.78148184494011 ], [ -68.779076181012471, 44.781531309490397 ], [ -68.778896166447424, 44.781607478859982 ], [ -68.778730146599443, 44.781535138860065 ], [ -68.778653019463292, 44.781561997583587 ], [ -68.778105549805204, 44.78197503885233 ], [ -68.777660343036374, 44.782397280161952 ], [ -68.776988914708951, 44.783197172519557 ], [ -68.776651642021108, 44.783795164831979 ], [ -68.776287397953851, 44.784622661366129 ], [ -68.775948621469269, 44.785504217884125 ], [ -68.775767118742579, 44.785859451951261 ], [ -68.775521250641532, 44.786205555656217 ], [ -68.775501581237236, 44.78628653895494 ], [ -68.775358822376575, 44.786529319097717 ], [ -68.774909007255545, 44.787716731924476 ], [ -68.774863781542066, 44.787766154792678 ], [ -68.774765804751596, 44.788072039741813 ], [ -68.774764657189408, 44.788265583739786 ], [ -68.774777195297943, 44.788292616614306 ], [ -68.774943673345149, 44.788351460359905 ], [ -68.775045726873557, 44.788419178024235 ], [ -68.775249188356142, 44.788721154927146 ], [ -68.775261394949212, 44.78883370326318 ], [ -68.775168716150375, 44.78930164025401 ], [ -68.775057738520047, 44.789598496225594 ], [ -68.774972175741937, 44.789962921247742 ], [ -68.7747115633221, 44.790642077529839 ], [ -68.774516354383763, 44.791060297046165 ], [ -68.774224967763431, 44.791523336311009 ], [ -68.774126984691591, 44.791829220497561 ], [ -68.773997245189392, 44.792072024449809 ], [ -68.773931626924536, 44.792283447797317 ], [ -68.773841543915609, 44.792386795164482 ], [ -68.773815899633291, 44.792377740832841 ], [ -68.773751290773191, 44.792431626603339 ], [ -68.773609203385192, 44.792597888039552 ], [ -68.773293345136707, 44.792849320589205 ], [ -68.773035984057003, 44.792992848574428 ], [ -68.772346968397812, 44.793495602912436 ], [ -68.772140248380126, 44.793720249141742 ], [ -68.771843895196298, 44.793931208131511 ], [ -68.771572992757342, 44.794200735263324 ], [ -68.771502181885197, 44.794223099958593 ], [ -68.771348601896648, 44.794195784461088 ], [ -68.771277833550329, 44.794209148069704 ], [ -68.77109055040313, 44.79441132243754 ], [ -68.770988152746739, 44.794429121726338 ], [ -68.770413503062727, 44.795076130135541 ], [ -68.770387715337435, 44.795103083896826 ], [ -68.77037455083007, 44.795134567315074 ], [ -68.770297187439454, 44.79521543106415 ], [ -68.770284044252918, 44.795242410232575 ], [ -68.770226164020215, 44.795291808255186 ], [ -68.770206698447296, 44.79531877469406 ], [ -68.770180892649577, 44.795350230141935 ], [ -68.770109847511662, 44.795431108985895 ], [ -68.770097099115134, 44.795458088926473 ], [ -68.770058164182572, 44.795512024258286 ], [ -68.770019375727628, 44.795529950727399 ], [ -68.769961566521332, 44.795561341673825 ], [ -68.769903685704236, 44.795610737018293 ], [ -68.769896843188434, 44.7956422331157 ], [ -68.769851589104263, 44.795696153132553 ], [ -68.769838840518702, 44.795723135553409 ], [ -68.769799905166678, 44.795777070793804 ], [ -68.769774009454267, 44.795831032307497 ], [ -68.769780206570829, 44.795862552171499 ], [ -68.769805780190282, 44.795889609321534 ], [ -68.76981201311402, 44.795912128225666 ], [ -68.769830851541471, 44.795943673564928 ], [ -68.769843762512096, 44.795975206955639 ], [ -68.769830636826114, 44.795997686843982 ], [ -68.769811170820631, 44.796024655721958 ], [ -68.769804723145299, 44.796056150096604 ], [ -68.769772235238989, 44.796078590949584 ], [ -68.769753167646115, 44.79610555810968 ], [ -68.769726962792689, 44.796137012646099 ], [ -68.769714210525009, 44.796163995043514 ], [ -68.76968840408162, 44.796195450374135 ], [ -68.76967526038743, 44.796222429466823 ], [ -68.769643167269436, 44.796244871078599 ], [ -68.769623683191455, 44.796276339146338 ], [ -68.769597930379931, 44.796294291764582 ], [ -68.769572141720886, 44.796321247844759 ], [ -68.76954004851811, 44.796343686916266 ], [ -68.769520564350685, 44.796375154965659 ], [ -68.769481771614565, 44.796393083751546 ], [ -68.769456000792232, 44.796415535560314 ], [ -68.769430194096145, 44.796446990830653 ], [ -68.769391383364024, 44.796469418808485 ], [ -68.769378634392467, 44.796496401173499 ], [ -68.769307715794611, 44.796545769879316 ], [ -68.769249797561542, 44.796604165837131 ], [ -68.769185215612794, 44.796649048009712 ], [ -68.769159426613328, 44.796676001483561 ], [ -68.76912106792723, 44.796684927483781 ], [ -68.769075955909727, 44.79670284084488 ], [ -68.76904388025018, 44.796720780551908 ], [ -68.769017678258493, 44.796752234927958 ], [ -68.76897928005971, 44.796770161829166 ], [ -68.768966135903881, 44.796797140836567 ], [ -68.768942375290678, 44.796810598076512 ], [ -68.768914593459243, 44.796842049232126 ], [ -68.768882409874209, 44.796886994271205 ], [ -68.76886915430552, 44.79694098114814 ], [ -68.768875368995936, 44.79696800434261 ], [ -68.768875135431202, 44.797026514319981 ], [ -68.768868313682859, 44.797053508620458 ], [ -68.768868098061247, 44.797107521885316 ], [ -68.768874309262557, 44.797134540050493 ], [ -68.768886846522307, 44.797161573527866 ], [ -68.768890688108087, 44.797188586896603 ], [ -68.768911464911696, 44.797328163701749 ], [ -68.768949360557102, 44.797436267771488 ], [ -68.76894914501824, 44.797490278522297 ], [ -68.768961678863079, 44.797517311982851 ], [ -68.768967875713969, 44.797548831881066 ], [ -68.768987127102903, 44.797575878927496 ], [ -68.768986516646862, 44.797629891388972 ], [ -68.768999449016917, 44.797656923140103 ], [ -68.76900566385369, 44.797683943813624 ], [ -68.769024520373065, 44.797710987543738 ], [ -68.769024304892241, 44.797765000802947 ], [ -68.769022563508557, 44.797805508179692 ], [ -68.76898563662823, 44.797850443647043 ], [ -68.768985474987176, 44.797890954218069 ], [ -68.769094237907936, 44.797963192427794 ], [ -68.769175685554629, 44.798048875613489 ], [ -68.769211280723951, 44.798138972880139 ], [ -68.769237447875383, 44.798314569621951 ], [ -68.769281739525169, 44.798503705762982 ], [ -68.769326171406519, 44.798656833039729 ], [ -68.769298640353639, 44.798724293908968 ], [ -68.769198442716075, 44.798782606915083 ], [ -68.769116078520071, 44.798827450582692 ], [ -68.76910875049208, 44.798881449452246 ], [ -68.769137308759781, 44.798953525430157 ], [ -68.769192838649346, 44.799097674155291 ], [ -68.769819767640939, 44.800719342139466 ], [ -68.770070039301999, 44.80137701126835 ], [ -68.770111203199491, 44.8014581133706 ], [ -68.770267953239298, 44.801787012504697 ], [ -68.770315982122639, 44.801832119232337 ], [ -68.770385275118883, 44.801895273245414 ], [ -68.770593781854899, 44.802026225891041 ], [ -68.771019391335628, 44.802315150326216 ], [ -68.771273109486515, 44.802504707776215 ], [ -68.771359505504279, 44.802540889873342 ], [ -68.771372902628457, 44.802549917713101 ], [ -68.771500009573458, 44.802581679429707 ], [ -68.771662023461062, 44.802582003466902 ], [ -68.771770954714057, 44.802613728540756 ], [ -68.771861279695344, 44.802654419874223 ], [ -68.771897923644858, 44.80268150114798 ], [ -68.771933756423763, 44.802713080044256 ], [ -68.77196994876131, 44.802753660666269 ], [ -68.772106201156731, 44.802771937182854 ], [ -68.772208884223517, 44.802785647331476 ], [ -68.772230122628088, 44.802911719022234 ], [ -68.772242078280115, 44.803087286584926 ], [ -68.771288229436266, 44.802878329317771 ], [ -68.771057140420439, 44.802760837987151 ], [ -68.770079281805167, 44.802034189764228 ], [ -68.76995745309145, 44.801867406723368 ], [ -68.769000257498575, 44.799533893489787 ], [ -68.768823119932037, 44.799168944609292 ], [ -68.768757674110617, 44.799033779164894 ], [ -68.7687153434279, 44.798948172409524 ], [ -68.768657853849632, 44.798898541543579 ], [ -68.768526463537583, 44.798754238824365 ], [ -68.768517951095717, 44.798709211421723 ], [ -68.768499094490053, 44.798682167612554 ], [ -68.768492879784574, 44.798655146916445 ], [ -68.768467305563561, 44.798628089484303 ], [ -68.768390887986484, 44.79856941656994 ], [ -68.768377955688706, 44.79854238726513 ], [ -68.768339703713337, 44.798524305117262 ], [ -68.768314147646578, 44.798492743407955 ], [ -68.768288950510836, 44.798470188468443 ], [ -68.768250336177516, 44.798443102018489 ], [ -68.768194434327256, 44.798393476647455 ], [ -68.768168856834777, 44.798366419140613 ], [ -68.767727545773823, 44.797964922797505 ], [ -68.767394180845585, 44.797937236211958 ], [ -68.767201584846958, 44.797981856451962 ], [ -68.767085994641079, 44.79803563195555 ], [ -68.766248483942562, 44.79859206230951 ], [ -68.765515041945548, 44.799009160445678 ], [ -68.764368596206822, 44.799740486024405 ], [ -68.763953638602359, 44.8000502058702 ], [ -68.763228614943614, 44.800525824559784 ], [ -68.762617271403073, 44.800835132192056 ], [ -68.761575496855826, 44.801269570626516 ], [ -68.760777378103882, 44.801736017498278 ], [ -68.760430212266257, 44.80188832972501 ], [ -68.758887395562965, 44.802411711664043 ], [ -68.757730069170591, 44.802872878964486 ], [ -68.756667844498708, 44.803455764719743 ], [ -68.756158862458989, 44.803837276361648 ], [ -68.755780081286318, 44.804079527103397 ], [ -68.755630785446996, 44.804155725181261 ], [ -68.755591796684243, 44.804218658910514 ], [ -68.755476221288959, 44.804263421618735 ], [ -68.755154144801267, 44.804456279793996 ], [ -68.754188243643512, 44.805048352315531 ], [ -68.753814520248341, 44.805304112660778 ], [ -68.753080431938088, 44.805739136099184 ], [ -68.752096003081562, 44.806218621741891 ], [ -68.751272050538347, 44.806684945695594 ], [ -68.750469250966219, 44.807191820716923 ], [ -68.749852402834165, 44.807645083893668 ], [ -68.749479895890076, 44.807977349981059 ], [ -68.749457686732953, 44.807995305793696 ], [ -68.749214998760323, 44.808188321224733 ], [ -68.749112953874999, 44.808300626048712 ], [ -68.74907458089983, 44.808309542755033 ], [ -68.747836365653541, 44.809333071206531 ], [ -68.747785428777945, 44.809413977848507 ], [ -68.74773401562409, 44.809422867814455 ], [ -68.747095860694202, 44.809948086962436 ], [ -68.746533174831058, 44.810293424767622 ], [ -68.745336355261941, 44.810781383697922 ], [ -68.744190106825002, 44.811089398106546 ], [ -68.743882365721788, 44.811151722955479 ], [ -68.743010320110557, 44.811203775036518 ], [ -68.742945984972451, 44.811185628238015 ], [ -68.742920038647085, 44.811154062548944 ], [ -68.742787959992242, 44.810906201090496 ], [ -68.742444531209983, 44.810995452236732 ], [ -68.742176430849923, 44.811206399817308 ], [ -68.741984210105159, 44.811241974755013 ], [ -68.741907341138671, 44.811286811115046 ], [ -68.741435651454736, 44.811776365491383 ], [ -68.741410391492352, 44.811857329895801 ], [ -68.741371938042732, 44.811884248346111 ], [ -68.740571565337319, 44.812166001079632 ], [ -68.739605369610615, 44.812586909633936 ], [ -68.738889049186639, 44.812981368498768 ], [ -68.738690449470297, 44.813201475235715 ], [ -68.73855796805023, 44.813394714926012 ], [ -68.738136860318477, 44.813789849462445 ], [ -68.737767117891138, 44.814185097861404 ], [ -68.737409555955509, 44.814508357507215 ], [ -68.737064274809867, 44.814737119980521 ], [ -68.736386416467866, 44.815095642522891 ], [ -68.736091934043458, 44.815189489223194 ], [ -68.734002917560744, 44.815670762018222 ], [ -68.733695765622301, 44.815769069753934 ], [ -68.732696235865532, 44.816023299538877 ], [ -68.732119884185607, 44.816215494413811 ], [ -68.731192662437095, 44.816726442913762 ], [ -68.730707362773529, 44.817139403217361 ], [ -68.730548134467654, 44.817382087185671 ], [ -68.730369773276621, 44.817575213999788 ], [ -68.72964152280575, 44.818127127606381 ], [ -68.729193425850198, 44.81835562269449 ], [ -68.728617290155327, 44.818579310080928 ], [ -68.728194287122264, 44.818681829370227 ], [ -68.726939925317708, 44.81923247230192 ], [ -68.725902862907191, 44.819630588691979 ], [ -68.725518409590123, 44.819769199554514 ], [ -68.725281416129334, 44.819818141452259 ], [ -68.72462827953693, 44.820019117161692 ], [ -68.723898182669117, 44.820278418327604 ], [ -68.723712375795245, 44.820367991438253 ], [ -68.72348201246281, 44.820434950128892 ], [ -68.722366874947667, 44.8207023120668 ], [ -68.720334853666742, 44.821021432493708 ], [ -68.719610627300952, 44.821204203378066 ], [ -68.718958178599593, 44.821337632089701 ], [ -68.71893127924686, 44.821342065130928 ], [ -68.717431968806906, 44.821756970372952 ], [ -68.715847032500847, 44.821735033429746 ], [ -68.715391903426976, 44.82176990910105 ], [ -68.714545667137045, 44.821920833981743 ], [ -68.713846130315105, 44.821901078874482 ], [ -68.713499739695067, 44.821927218419027 ], [ -68.713307440081977, 44.821967244061945 ], [ -68.712878273023989, 44.822105700059829 ], [ -68.71266080176953, 44.822199677298528 ], [ -68.712506859052681, 44.822235298851595 ], [ -68.712352684763331, 44.822239412389322 ], [ -68.711967542703078, 44.822188927467849 ], [ -68.711614236033299, 44.822174533125647 ], [ -68.711029311224635, 44.822078532931847 ], [ -68.710424050684864, 44.822018484644417 ], [ -68.709399829300352, 44.821952868617103 ], [ -68.708808507360089, 44.821793823803432 ], [ -68.708487710868383, 44.821761495675894 ], [ -68.708294741556571, 44.821697988499935 ], [ -68.707896987792381, 44.821719478097904 ], [ -68.707396958623349, 44.821799217023148 ], [ -68.707333162726698, 44.821830560782189 ], [ -68.706935852353368, 44.82191956437056 ], [ -68.706580982279675, 44.821981670145512 ], [ -68.706061346791003, 44.822029845619106 ], [ -68.705211934438069, 44.822023154519435 ], [ -68.705042129031881, 44.821991208864766 ], [ -68.704723217219623, 44.821976882029915 ], [ -68.703545289554327, 44.821978329678359 ], [ -68.702802442776289, 44.822079924155659 ], [ -68.701889463008442, 44.822059540167125 ], [ -68.701020172555914, 44.821998755049208 ], [ -68.700481022895715, 44.821997342330654 ], [ -68.700327143265426, 44.822019442383642 ], [ -68.699801597166598, 44.822139591813581 ], [ -68.699417067548424, 44.822201597358585 ], [ -68.699186273933293, 44.822268505886186 ], [ -68.69902002464643, 44.822389597525628 ], [ -68.698764046133689, 44.822510452279921 ], [ -68.698342092551243, 44.82277490406058 ], [ -68.698214504640234, 44.822909599364429 ], [ -68.698138278439359, 44.823048932039342 ], [ -68.697732110659956, 44.823997591079404 ], [ -68.6977100011201, 44.824672696798231 ], [ -68.696123278357163, 44.824600969714965 ], [ -68.694359126627134, 44.824519744896591 ], [ -68.694372198638902, 44.824438758465995 ], [ -68.69449946028422, 44.824218548475557 ], [ -68.694453308573841, 44.823975363263443 ], [ -68.694471328030374, 44.823781863922889 ], [ -68.69473074163686, 44.823012869114393 ], [ -68.694889425037132, 44.822680211449196 ], [ -68.695068066101427, 44.822460132988944 ], [ -68.695451692814189, 44.822195593602991 ] ], [ [ -68.768674936508816, 44.798479971962571 ], [ -68.768706133452909, 44.79848453691617 ], [ -68.768746848623479, 44.79848011759816 ], [ -68.768775349323178, 44.798466672510592 ], [ -68.768806690061055, 44.798435228602386 ], [ -68.768819439729484, 44.798408246311837 ], [ -68.768819547562941, 44.798381240941104 ], [ -68.768816535293894, 44.798345228228222 ], [ -68.768804497082826, 44.798291187658819 ], [ -68.768788875471571, 44.798246145880931 ], [ -68.768764611976039, 44.798187581297753 ], [ -68.76872429258502, 44.798092975067973 ], [ -68.768699598304963, 44.798043413134444 ], [ -68.768670308616635, 44.797957832758549 ], [ -68.768664093897556, 44.797930814579054 ], [ -68.768626090543663, 44.797849715797511 ], [ -68.768600480640046, 44.797831659346073 ], [ -68.768562229063548, 44.797813577271306 ], [ -68.76852395598651, 44.797799996908992 ], [ -68.768485219516592, 44.79780442015926 ], [ -68.768446820454542, 44.797822346876359 ], [ -68.768433672283678, 44.797849325809331 ], [ -68.768407885914371, 44.797876281623843 ], [ -68.768420437595367, 44.797898813409297 ], [ -68.768427047140648, 44.797925832402804 ], [ -68.76844588546335, 44.797957377959143 ], [ -68.768445777447155, 44.7979843858419 ], [ -68.768458332702494, 44.798006915119281 ], [ -68.768499437961978, 44.798101523037353 ], [ -68.768533129375186, 44.798173609581156 ], [ -68.768551935379605, 44.798214156079517 ], [ -68.768551396483787, 44.798250164114272 ], [ -68.768557503218659, 44.798304190179799 ], [ -68.768572747693696, 44.798344734477709 ], [ -68.768613210933637, 44.798403329411819 ], [ -68.768637941271407, 44.798443887897193 ], [ -68.768656402907723, 44.798470933395251 ], [ -68.768674936508816, 44.798479971962571 ] ], [ [ -68.833682325085277, 44.736805895583146 ], [ -68.833644093338975, 44.736787835142458 ], [ -68.833592757673301, 44.736796763989538 ], [ -68.833541001639674, 44.736814693324618 ], [ -68.833508979067545, 44.736832648894392 ], [ -68.833476536098644, 44.736859609987434 ], [ -68.833437806479452, 44.736877558268304 ], [ -68.833399047468049, 44.736904507616742 ], [ -68.833360275483969, 44.736935961260947 ], [ -68.833321545777892, 44.73695390950202 ], [ -68.833282799597015, 44.736976357012217 ], [ -68.833192197054203, 44.737052745565109 ], [ -68.833153463695666, 44.737070693743483 ], [ -68.833121046324621, 44.737088651137682 ], [ -68.833089001092844, 44.737115610189811 ], [ -68.833056570723656, 44.737138069363574 ], [ -68.833036742943165, 44.737169548076047 ], [ -68.833036665222266, 44.737196556353538 ], [ -68.833061873988711, 44.737214597961234 ], [ -68.833100516837931, 44.737228157379299 ], [ -68.833151852960583, 44.73721922875486 ], [ -68.833203253761965, 44.737187796138457 ], [ -68.833241987183442, 44.737169847943676 ], [ -68.833268114410401, 44.737142880209326 ], [ -68.833313147341542, 44.737129443003766 ], [ -68.833358678212761, 44.737079994481341 ], [ -68.833416828084452, 44.737035068674949 ], [ -68.833448850804132, 44.737017110621089 ], [ -68.833474977873294, 44.736990140327713 ], [ -68.833513707549074, 44.736972194545437 ], [ -68.833539414207095, 44.736954227258579 ], [ -68.833623231704237, 44.73690483442644 ], [ -68.833681762820049, 44.736864410856398 ], [ -68.833694866744437, 44.736837419035133 ], [ -68.833682325085277, 44.736805895583146 ] ], [ [ -68.740186150626997, 44.808753283859232 ], [ -68.740096483544065, 44.808744076314731 ], [ -68.7400580517685, 44.808766495137334 ], [ -68.740038982831621, 44.8087889580232 ], [ -68.740026213949179, 44.808815931985777 ], [ -68.740019752135694, 44.808847427086071 ], [ -68.740020025830447, 44.808874435758746 ], [ -68.740032943620164, 44.808901470703056 ], [ -68.740046219525851, 44.808937509980915 ], [ -68.740084824069925, 44.80896460589468 ], [ -68.740123472605703, 44.808982698375459 ], [ -68.7401875306211, 44.808973840602135 ], [ -68.740257743135572, 44.808915487473321 ], [ -68.740276304793937, 44.808830006289099 ], [ -68.740250739317048, 44.808802942606846 ], [ -68.740224839466336, 44.808762372877801 ], [ -68.740186150626997, 44.808753283859232 ] ] ] } }"; // // try { @@ -275,16 +275,16 @@ public void testCorruptedTreapSearch() { // } catch (Exception e) { // // } - } - - @Test - public void testCircle() { - String wkt = "MULTIPOLYGON (((1 1.003617493421433, 1 1.003617493421433, 0.9997649519467132 1.003609747854938, 0.999530910495817 1.003586544337746, 0.9992988779321902 1.003547982273469, 0.9990698479248393 1.003494226857979, 0.9988448012666893 1.003425508366702, 0.9986247016712343 1.003342121161815, 0.9984104916443466 1.003244422424226, 0.9982030884490086 1.003132830616434, 0.9980033801801327 1.00300782368356, 0.9978122219659593 1.002869937000829, 0.9976304323118294 1.0027197610768, 0.9974587896014011 1.002557939022455, 0.9972980287696582 1.002385163797099, 0.9971488381613458 1.002202175242747, 0.9970118565877482 1.002009756919397, 0.9968876705940221 1.001808732754287, 0.9967768119485581 1.001599963518935, 0.9966797553651014 1.00138434314843, 0.9965969164675547 1.001162794918189, 0.9965286500065195 1.000936267494034, 0.996475248335696 1.000705730872183, 0.9964369401552167 1.000472172226337, 0.9964138895278762 1.000236591679669, 0.9964061951730092 0.9999999980200158, 0.9964138900413748 0.9997634043769587, 0.9964369411734271 0.9995278238797968, 0.9964752498411954 0.9992942653155188, 0.996528651973547 0.9990637288059012, 0.9965969188624519 0.9988372015227254, 0.9966797581468895 0.9986156534597946, 0.9967768150696379 0.9984000332800704, 0.9968876740009895 0.998191264255702, 0.9970118602223078 0.9979902403181697, 0.9971488419613082 0.9977978222350962, 0.9972980326700053 0.9976148339296087, 0.9974587935353963 0.997442058957447, 0.9976304362121615 0.9972802371562934, 0.9978122257658933 0.9971300614811209, 0.9980033838146521 0.996992175038654, 0.9982030918559268 0.9968671683333408, 0.9984104947653715 0.996755576736514, 0.9986247044529655 0.9966578781896839, 0.9988448036615318 0.9965744911520876, 0.9990698498918178 0.9965057728017697, 0.9992988794376493 0.9964520174984963, 0.9995309115139988 0.996413455515775, 0.999764952460197 0.9963902520480808, 1 0.9963825064981803, 1.000235047539803 0.9963902520480808, 1.000469088486001 0.9964134555157748, 1.000701120562351 0.9964520174984965, 1.000930150108182 0.9965057728017697, 1.001155196338468 0.9965744911520876, 1.001375295547035 0.9966578781896839, 1.001589505234629 0.996755576736514, 1.001796908144073 0.9968671683333408, 1.001996616185348 0.996992175038654, 1.002187774234107 0.9971300614811212, 1.002369563787838 0.9972802371562934, 1.002541206464604 0.997442058957447, 1.002701967329995 0.9976148339296087, 1.002851158038692 0.9977978222350962, 1.002988139777692 0.99799024031817, 1.00311232599901 0.998191264255702, 1.003223184930362 0.9984000332800704, 1.00332024185311 0.9986156534597949, 1.003403081137548 0.9988372015227254, 1.003471348026453 0.9990637288059014, 1.003524750158804 0.9992942653155188, 1.003563058826573 0.9995278238797968, 1.003586109958625 0.9997634043769587, 1.003593804826991 0.9999999980200158, 1.003586110472124 1.00023659167967, 1.003563059844783 1.000472172226337, 1.003524751664304 1.000705730872183, 1.003471349993481 1.000936267494034, 1.003403083532445 1.001162794918189, 1.003320244634899 1.00138434314843, 1.003223188051442 1.001599963518935, 1.003112329405978 1.001808732754287, 1.002988143412252 1.002009756919397, 1.002851161838654 1.002202175242747, 1.002701971230342 1.002385163797099, 1.002541210398599 1.002557939022455, 1.002369567688171 1.0027197610768, 1.002187778034041 1.002869937000829, 1.001996619819867 1.00300782368356, 1.001796911550991 1.003132830616434, 1.001589508355653 1.003244422424226, 1.001375298328766 1.003342121161815, 1.001155198733311 1.003425508366702, 1.000930152075161 1.003494226857979, 1.00070112206781 1.003547982273469, 1.000469089504183 1.003586544337747, 1.000235048053287 1.003609747854938, 1 1.003617493421433)))"; - Geometry poly = GeometryEngine.geometryFromWkt(wkt, 0, Geometry.Type.Unknown); - OperatorFactoryLocal engine = OperatorFactoryLocal.getInstance(); - OperatorGeneralizeByArea op = (OperatorGeneralizeByArea) engine.getOperator(Operator.Type.GeneralizeByArea); - Geometry geom = op.execute(poly, 95, true, GeneralizeType.Neither, SpatialReference.create(4326),null); - int res = ((MultiVertexGeometry)geom).getPointCount(); - int original = ((MultiVertexGeometry)poly).getPointCount(); - } + } + + @Test + public void testCircle() { + String wkt = "MULTIPOLYGON (((1 1.003617493421433, 1 1.003617493421433, 0.9997649519467132 1.003609747854938, 0.999530910495817 1.003586544337746, 0.9992988779321902 1.003547982273469, 0.9990698479248393 1.003494226857979, 0.9988448012666893 1.003425508366702, 0.9986247016712343 1.003342121161815, 0.9984104916443466 1.003244422424226, 0.9982030884490086 1.003132830616434, 0.9980033801801327 1.00300782368356, 0.9978122219659593 1.002869937000829, 0.9976304323118294 1.0027197610768, 0.9974587896014011 1.002557939022455, 0.9972980287696582 1.002385163797099, 0.9971488381613458 1.002202175242747, 0.9970118565877482 1.002009756919397, 0.9968876705940221 1.001808732754287, 0.9967768119485581 1.001599963518935, 0.9966797553651014 1.00138434314843, 0.9965969164675547 1.001162794918189, 0.9965286500065195 1.000936267494034, 0.996475248335696 1.000705730872183, 0.9964369401552167 1.000472172226337, 0.9964138895278762 1.000236591679669, 0.9964061951730092 0.9999999980200158, 0.9964138900413748 0.9997634043769587, 0.9964369411734271 0.9995278238797968, 0.9964752498411954 0.9992942653155188, 0.996528651973547 0.9990637288059012, 0.9965969188624519 0.9988372015227254, 0.9966797581468895 0.9986156534597946, 0.9967768150696379 0.9984000332800704, 0.9968876740009895 0.998191264255702, 0.9970118602223078 0.9979902403181697, 0.9971488419613082 0.9977978222350962, 0.9972980326700053 0.9976148339296087, 0.9974587935353963 0.997442058957447, 0.9976304362121615 0.9972802371562934, 0.9978122257658933 0.9971300614811209, 0.9980033838146521 0.996992175038654, 0.9982030918559268 0.9968671683333408, 0.9984104947653715 0.996755576736514, 0.9986247044529655 0.9966578781896839, 0.9988448036615318 0.9965744911520876, 0.9990698498918178 0.9965057728017697, 0.9992988794376493 0.9964520174984963, 0.9995309115139988 0.996413455515775, 0.999764952460197 0.9963902520480808, 1 0.9963825064981803, 1.000235047539803 0.9963902520480808, 1.000469088486001 0.9964134555157748, 1.000701120562351 0.9964520174984965, 1.000930150108182 0.9965057728017697, 1.001155196338468 0.9965744911520876, 1.001375295547035 0.9966578781896839, 1.001589505234629 0.996755576736514, 1.001796908144073 0.9968671683333408, 1.001996616185348 0.996992175038654, 1.002187774234107 0.9971300614811212, 1.002369563787838 0.9972802371562934, 1.002541206464604 0.997442058957447, 1.002701967329995 0.9976148339296087, 1.002851158038692 0.9977978222350962, 1.002988139777692 0.99799024031817, 1.00311232599901 0.998191264255702, 1.003223184930362 0.9984000332800704, 1.00332024185311 0.9986156534597949, 1.003403081137548 0.9988372015227254, 1.003471348026453 0.9990637288059014, 1.003524750158804 0.9992942653155188, 1.003563058826573 0.9995278238797968, 1.003586109958625 0.9997634043769587, 1.003593804826991 0.9999999980200158, 1.003586110472124 1.00023659167967, 1.003563059844783 1.000472172226337, 1.003524751664304 1.000705730872183, 1.003471349993481 1.000936267494034, 1.003403083532445 1.001162794918189, 1.003320244634899 1.00138434314843, 1.003223188051442 1.001599963518935, 1.003112329405978 1.001808732754287, 1.002988143412252 1.002009756919397, 1.002851161838654 1.002202175242747, 1.002701971230342 1.002385163797099, 1.002541210398599 1.002557939022455, 1.002369567688171 1.0027197610768, 1.002187778034041 1.002869937000829, 1.001996619819867 1.00300782368356, 1.001796911550991 1.003132830616434, 1.001589508355653 1.003244422424226, 1.001375298328766 1.003342121161815, 1.001155198733311 1.003425508366702, 1.000930152075161 1.003494226857979, 1.00070112206781 1.003547982273469, 1.000469089504183 1.003586544337747, 1.000235048053287 1.003609747854938, 1 1.003617493421433)))"; + Geometry poly = GeometryEngine.geometryFromWkt(wkt, 0, Geometry.Type.Unknown); + OperatorFactoryLocal engine = OperatorFactoryLocal.getInstance(); + OperatorGeneralizeByArea op = (OperatorGeneralizeByArea) engine.getOperator(Operator.Type.GeneralizeByArea); + Geometry geom = op.execute(poly, 95, true, GeneralizeType.Neither, SpatialReference.create(4326), null); + int res = ((MultiVertexGeometry) geom).getPointCount(); + int original = ((MultiVertexGeometry) poly).getPointCount(); + } } diff --git a/src/test/java/com/esri/core/geometry/TestGeodetic.java b/src/test/java/com/esri/core/geometry/TestGeodetic.java index c4b69078..f00b48ee 100644 --- a/src/test/java/com/esri/core/geometry/TestGeodetic.java +++ b/src/test/java/com/esri/core/geometry/TestGeodetic.java @@ -4,468 +4,468 @@ import org.junit.Test; public class TestGeodetic extends TestCase { - @Override - protected void setUp() throws Exception { - super.setUp(); - } - - @Override - protected void tearDown() throws Exception { - super.tearDown(); - } - - @Test - public void testCoastalPolyline() throws Exception { - SpatialReference sr = SpatialReference.create(4326); - String geoJSON = "{ \"type\": \"LineString\", \"coordinates\": [ [ -90.418136, 46.566094 ], [ -90.348407, 46.600635 ], [ -90.327626, 46.607744 ], [ -90.306609, 46.602741 ], [ -90.265294, 46.618516 ], [ -90.237609, 46.624485 ], [ -90.164026, 46.645515 ], [ -90.100695, 46.655132 ], [ -90.045420, 46.668272 ], [ -90.028392, 46.674390 ], [ -89.996034, 46.693225 ], [ -89.985817, 46.703190 ], [ -89.973803, 46.710322 ], [ -89.957101, 46.716929 ], [ -89.918466, 46.740324 ], [ -89.892355, 46.763088 ], [ -89.848652, 46.795711 ], [ -89.831956, 46.804053 ], [ -89.790663, 46.818469 ], [ -89.720277, 46.830413 ], [ -89.673375, 46.833229 ], [ -89.660625, 46.831056 ], [ -89.642255, 46.825340 ], [ -89.634938, 46.819488 ], [ -89.619329, 46.818890 ], [ -89.569808, 46.831859 ], [ -89.535683, 46.835878 ], [ -89.513938, 46.841835 ], [ -89.499080, 46.841621 ], [ -89.491252, 46.838448 ], [ -89.471540, 46.837359 ], [ -89.437047, 46.839512 ], [ -89.415154, 46.843983 ], [ -89.372032, 46.857386 ], [ -89.249143, 46.903326 ], [ -89.227914, 46.912954 ], [ -89.201511, 46.931149 ], [ -89.168244, 46.965536 ], [ -89.142595, 46.984859 ], [ -89.128698, 46.992599 ], [ -89.118339, 46.994220 ], [ -89.113158, 46.989356 ], [ -89.106277, 46.986480 ], [ -89.086742, 46.985298 ], [ -89.063103, 46.988522 ], [ -89.039490, 46.999419 ], [ -89.028930, 47.001140 ], [ -89.022994, 46.995120 ], [ -88.998417, 46.995314 ], [ -88.987197, 46.997239 ], [ -88.972802, 47.002096 ], [ -88.959409, 47.008496 ], [ -88.944045, 47.020129 ], [ -88.924492, 47.042156 ], [ -88.914189, 47.059246 ], [ -88.903706, 47.086161 ], [ -88.889140, 47.100575 ], [ -88.855372, 47.114263 ], [ -88.848176, 47.115065 ], [ -88.814834, 47.141399 ], [ -88.789813, 47.150925 ], [ -88.778022, 47.150465 ], [ -88.764351, 47.155762 ], [ -88.729688, 47.185834 ], [ -88.699660, 47.204831 ], [ -88.672395, 47.219137 ], [ -88.656359, 47.225624 ], [ -88.640323, 47.226784 ], [ -88.623579, 47.232352 ], [ -88.609830, 47.238894 ], [ -88.584912, 47.242361 ], [ -88.573997, 47.245989 ], [ -88.500780, 47.293503 ], [ -88.477733, 47.313460 ], [ -88.470484, 47.327653 ], [ -88.459262, 47.339903 ], [ -88.418673, 47.371188 ], [ -88.389459, 47.384431 ], [ -88.324083, 47.403542 ], [ -88.303447, 47.412204 ], [ -88.285195, 47.422392 ], [ -88.239161, 47.429969 ], [ -88.227446, 47.435093 ], [ -88.218424, 47.441585 ], [ -88.216977, 47.445493 ], [ -88.217822, 47.448738 ], [ -88.181820, 47.457657 ], [ -88.150571, 47.460093 ], [ -88.139651, 47.462693 ], [ -88.085252, 47.468961 ], [ -88.076388, 47.467752 ], [ -88.049326, 47.469785 ], [ -88.048226, 47.470008 ], [ -88.048077, 47.474973 ], [ -88.040291, 47.475999 ], [ -87.978934, 47.479420 ], [ -87.929269, 47.478737 ], [ -87.902416, 47.477045 ], [ -87.898036, 47.474872 ], [ -87.816958, 47.471998 ], [ -87.801184, 47.473301 ], [ -87.756739, 47.460717 ], [ -87.730804, 47.449112 ], [ -87.715942, 47.439816 ], [ -87.710471, 47.406200 ], [ -87.712421, 47.401400 ], [ -87.721274, 47.401032 ], [ -87.742417, 47.405823 ], [ -87.751380, 47.405066 ], [ -87.759057, 47.403013 ], [ -87.765019, 47.398652 ], [ -87.800294, 47.392148 ], [ -87.815371, 47.384790 ], [ -87.827115, 47.386160 ], [ -87.834822, 47.390478 ], [ -87.848252, 47.394864 ], [ -87.856700, 47.395387 ], [ -87.882245, 47.395588 ], [ -87.941613, 47.390073 ], [ -87.957058, 47.387260 ], [ -87.965063, 47.374430 ], [ -87.965598, 47.368645 ], [ -87.962567, 47.362543 ], [ -87.954796, 47.356809 ], [ -87.947397, 47.355461 ], [ -87.938787, 47.346777 ], [ -87.938250, 47.342299 ], [ -87.943360, 47.335899 ], [ -87.946352, 47.334254 ], [ -87.958386, 47.334435 ], [ -87.968604, 47.332582 ], [ -87.989133, 47.322633 ], [ -88.016478, 47.306275 ], [ -88.054849, 47.298240 ], [ -88.060090, 47.295796 ], [ -88.071476, 47.286768 ], [ -88.096851, 47.261351 ], [ -88.108833, 47.259131 ], [ -88.117456, 47.255174 ], [ -88.131943, 47.239554 ], [ -88.163059, 47.216278 ], [ -88.194218, 47.209242 ], [ -88.204849, 47.210498 ], [ -88.212361, 47.209423 ], [ -88.228987, 47.199042 ], [ -88.236892, 47.189236 ], [ -88.242006, 47.174767 ], [ -88.242660, 47.158426 ], [ -88.239470, 47.151137 ], [ -88.236721, 47.149287 ], [ -88.231797, 47.149609 ], [ -88.232164, 47.145975 ], [ -88.239895, 47.139436 ], [ -88.247628, 47.135981 ], [ -88.249571, 47.136231 ], [ -88.250785, 47.140209 ], [ -88.255303, 47.143640 ], [ -88.262972, 47.145174 ], [ -88.272017, 47.143511 ], [ -88.281701, 47.138212 ], [ -88.289040, 47.129689 ], [ -88.289543, 47.126604 ], [ -88.287870, 47.125374 ], [ -88.287173, 47.120420 ], [ -88.288347, 47.114547 ], [ -88.297625, 47.098505 ], [ -88.340052, 47.080494 ], [ -88.346709, 47.079372 ], [ -88.349952, 47.076377 ], [ -88.353191, 47.069063 ], [ -88.353952, 47.058047 ], [ -88.359054, 47.039739 ], [ -88.367624, 47.019213 ], [ -88.373966, 47.012262 ], [ -88.385606, 47.004522 ], [ -88.404498, 46.983353 ], [ -88.411145, 46.977984 ], [ -88.443901, 46.972251 ], [ -88.448570, 46.946769 ], [ -88.455404, 46.923321 ], [ -88.475859, 46.886042 ], [ -88.477935, 46.850560 ], [ -88.483748, 46.831727 ], [ -88.482579, 46.826197 ], [ -88.473342, 46.806226 ], [ -88.462349, 46.786711 ], [ -88.438427, 46.786714 ], [ -88.433835, 46.793502 ], [ -88.415225, 46.811715 ], [ -88.381410, 46.838466 ], [ -88.382204, 46.844477 ], [ -88.382052, 46.845437 ], [ -88.390135, 46.851595 ], [ -88.404008, 46.848331 ], [ -88.389727, 46.867100 ], [ -88.372591, 46.872812 ], [ -88.375855, 46.863428 ], [ -88.369848, 46.857568 ], [ -88.368767, 46.857313 ], [ -88.360868, 46.856202 ], [ -88.351940, 46.857028 ], [ -88.310290, 46.889748 ], [ -88.281244, 46.906632 ], [ -88.261593, 46.915516 ], [ -88.244437, 46.929612 ], [ -88.167227, 46.958855 ], [ -88.155374, 46.965069 ], [ -88.143688, 46.966665 ], [ -88.132876, 46.962204 ], [ -88.150114, 46.943630 ], [ -88.187522, 46.918999 ], [ -88.175197, 46.904580 ], [ -88.161913, 46.904941 ], [ -88.126927, 46.909840 ], [ -88.101315, 46.917207 ], [ -88.081870, 46.920458 ], [ -88.065192, 46.918563 ], [ -88.032408, 46.908890 ], [ -88.004298, 46.906982 ], [ -87.986113, 46.905957 ], [ -87.956000, 46.909051 ], [ -87.900339, 46.909686 ], [ -87.874538, 46.892578 ], [ -87.846195, 46.883905 ], [ -87.841228, 46.884363 ], [ -87.827162, 46.889713 ], [ -87.816794, 46.891154 ], [ -87.813226, 46.888023 ], [ -87.793194, 46.880822 ], [ -87.782461, 46.879859 ], [ -87.776930, 46.876726 ], [ -87.776313, 46.872591 ], [ -87.778752, 46.870422 ], [ -87.776804, 46.866823 ], [ -87.765989, 46.861316 ], [ -87.755868, 46.860453 ], [ -87.746646, 46.865427 ], [ -87.741014, 46.865247 ], [ -87.734870, 46.850120 ], [ -87.736732, 46.847216 ], [ -87.734325, 46.836955 ], [ -87.731522, 46.831196 ], [ -87.727358, 46.827656 ], [ -87.713737, 46.825534 ], [ -87.694590, 46.827182 ], [ -87.685698, 46.832530 ], [ -87.687930, 46.839159 ], [ -87.687164, 46.841742 ], [ -87.680668, 46.842496 ], [ -87.674541, 46.836964 ], [ -87.673177, 46.827593 ], [ -87.674345, 46.824050 ], [ -87.672015, 46.820415 ], [ -87.662261, 46.815157 ], [ -87.651510, 46.812411 ], [ -87.641887, 46.813733 ], [ -87.633300, 46.812107 ], [ -87.628081, 46.805157 ], [ -87.607988, 46.788408 ], [ -87.595307, 46.782950 ], [ -87.590767, 46.753009 ], [ -87.582745, 46.730527 ], [ -87.573203, 46.720471 ], [ -87.523308, 46.688488 ], [ -87.524444, 46.677586 ], [ -87.503025, 46.647497 ], [ -87.492860, 46.642561 ], [ -87.467965, 46.635623 ], [ -87.466537, 46.631555 ], [ -87.467563, 46.626228 ], [ -87.464108, 46.614811 ], [ -87.451368, 46.605923 ], [ -87.442612, 46.602776 ], [ -87.411167, 46.601669 ], [ -87.403275, 46.595215 ], [ -87.383961, 46.593070 ], [ -87.381649, 46.580059 ], [ -87.392974, 46.572523 ], [ -87.392828, 46.570852 ], [ -87.382206, 46.553681 ], [ -87.375613, 46.547140 ], [ -87.390300, 46.542577 ], [ -87.393985, 46.533183 ], [ -87.389290, 46.524472 ], [ -87.381349, 46.517292 ], [ -87.366767, 46.507303 ], [ -87.351071, 46.500749 ], [ -87.310755, 46.492017 ], [ -87.258732, 46.488255 ], [ -87.202404, 46.490827 ], [ -87.175065, 46.497548 ], [ -87.127440, 46.494014 ], [ -87.107559, 46.496124 ], [ -87.098760, 46.503609 ], [ -87.077279, 46.515339 ], [ -87.046022, 46.519956 ], [ -87.029892, 46.525599 ], [ -87.017136, 46.533550 ], [ -87.008724, 46.532723 ], [ -86.976958, 46.526581 ], [ -86.964534, 46.516549 ], [ -86.962842, 46.509646 ], [ -86.946980, 46.484567 ], [ -86.946218, 46.479059 ], [ -86.949526, 46.476315 ], [ -86.947077, 46.472064 ], [ -86.927725, 46.464566 ], [ -86.903742, 46.466138 ], [ -86.889094, 46.458499 ], [ -86.883976, 46.450976 ], [ -86.883919, 46.441514 ], [ -86.875151, 46.437280 ], [ -86.850111, 46.434114 ], [ -86.837448, 46.434186 ], [ -86.816026, 46.437892 ], [ -86.810967, 46.449663 ], [ -86.808817, 46.460611 ], [ -86.803557, 46.466669 ], [ -86.787905, 46.477729 ], [ -86.768516, 46.479072 ], [ -86.750157, 46.479109 ], [ -86.735929, 46.475231 ], [ -86.731096, 46.471760 ], [ -86.730829, 46.468057 ], [ -86.710573, 46.444908 ], [ -86.703230, 46.439378 ], [ -86.698139, 46.438624 ], [ -86.686412, 46.454965 ], [ -86.688816, 46.463152 ], [ -86.686468, 46.471655 ], [ -86.683819, 46.498079 ], [ -86.696001, 46.503160 ], [ -86.701929, 46.511571 ], [ -86.709325, 46.543914 ], [ -86.695645, 46.555026 ], [ -86.678182, 46.561039 ], [ -86.675764, 46.557061 ], [ -86.670927, 46.556489 ], [ -86.656479, 46.558453 ], [ -86.652865, 46.560555 ], [ -86.627380, 46.533710 ], [ -86.629086, 46.518144 ], [ -86.632109, 46.508865 ], [ -86.634530, 46.504523 ], [ -86.641088, 46.500438 ], [ -86.645528, 46.492039 ], [ -86.646393, 46.485776 ], [ -86.636671, 46.478298 ], [ -86.627441, 46.477540 ], [ -86.620603, 46.483873 ], [ -86.618061, 46.489452 ], [ -86.612173, 46.493295 ], [ -86.609393, 46.492976 ], [ -86.606932, 46.478531 ], [ -86.609039, 46.470239 ], [ -86.586168, 46.463324 ], [ -86.557731, 46.487434 ], [ -86.524959, 46.505381 ], [ -86.495054, 46.524874 ], [ -86.484003, 46.535965 ], [ -86.481956, 46.542709 ], [ -86.469306, 46.551422 ], [ -86.459930, 46.551928 ], [ -86.444390, 46.548137 ], [ -86.437167, 46.548960 ], [ -86.390409, 46.563194 ], [ -86.349890, 46.578035 ], [ -86.188024, 46.654008 ], [ -86.161681, 46.669475 ], [ -86.138295, 46.672935 ], [ -86.119862, 46.657256 ], [ -86.112126, 46.655044 ], [ -86.099843, 46.654615 ], [ -86.074219, 46.657799 ], [ -86.036969, 46.667627 ], [ -85.995044, 46.673676 ], [ -85.953670, 46.676869 ], [ -85.924047, 46.684733 ], [ -85.877908, 46.690914 ], [ -85.841057, 46.688896 ], [ -85.794923, 46.681083 ], [ -85.750606, 46.677368 ], [ -85.714415, 46.677156 ], [ -85.668753, 46.680404 ], [ -85.624573, 46.678862 ], [ -85.587345, 46.674627 ], [ -85.542517, 46.674263 ], [ -85.509510, 46.675786 ], [ -85.482096, 46.680432 ], [ -85.369805, 46.713754 ], [ -85.289846, 46.744644 ], [ -85.256860, 46.753380 ], [ -85.173042, 46.763634 ], [ -85.063556, 46.757856 ], [ -85.036286, 46.760435 ], [ -85.009240, 46.769224 ], [ -84.989497, 46.772403 ], [ -84.964652, 46.772845 ], [ -84.954009, 46.771362 ], [ -84.951580, 46.769488 ], [ -84.987539, 46.745483 ], [ -85.007616, 46.728339 ], [ -85.020159, 46.712463 ], [ -85.027513, 46.697451 ], [ -85.030078, 46.684769 ], [ -85.028291, 46.675125 ], [ -85.035504, 46.625021 ], [ -85.037056, 46.600995 ], [ -85.035476, 46.581547 ], [ -85.031507, 46.568703 ], [ -85.029594, 46.554419 ], [ -85.027374, 46.553756 ], [ -85.025491, 46.546397 ], [ -85.027083, 46.543038 ], [ -85.045534, 46.537694 ], [ -85.052954, 46.532827 ], [ -85.056133, 46.526520 ], [ -85.054943, 46.514750 ], [ -85.049847, 46.503963 ], [ -85.033766, 46.487670 ], [ -85.025598, 46.483028 ], [ -85.015211, 46.479712 ], [ -84.969464, 46.476290 ], [ -84.955307, 46.480269 ], [ -84.947269, 46.487399 ], [ -84.937145, 46.489252 ], [ -84.934432, 46.480315 ], [ -84.921931, 46.469962 ], [ -84.915184, 46.467515 ], [ -84.893423, 46.465406 ], [ -84.875070, 46.466781 ], [ -84.861448, 46.469930 ], [ -84.849767, 46.460245 ], [ -84.843907, 46.448661 ], [ -84.829491, 46.444071 ], [ -84.800101, 46.446219 ], [ -84.769151, 46.453523 ], [ -84.723338, 46.468266 ], [ -84.689672, 46.483923 ], [ -84.678423, 46.487694 ], [ -84.653880, 46.482250 ], [ -84.631020, 46.484868 ], [ -84.616489, 46.471870 ], [ -84.607945, 46.456747 ], [ -84.584167, 46.439410 ], [ -84.573522, 46.427895 ], [ -84.551496, 46.418522 ], [ -84.503719, 46.439190 ], [ -84.493401, 46.440313 ], [ -84.479513, 46.432573 ], [ -84.471848, 46.434289 ], [ -84.462597, 46.440940 ], [ -84.455527, 46.453897 ], [ -84.455256, 46.462785 ], [ -84.463322, 46.467435 ] ] }"; - OperatorImportFromGeoJson importerGeoJson = (OperatorImportFromGeoJson) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ImportFromGeoJson); - Geometry geom = importerGeoJson.execute(0, Geometry.Type.Unknown, geoJSON, null).getGeometry(); - - - double distance = 9000; - OperatorGeodesicBuffer opBuf = (OperatorGeodesicBuffer) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.GeodesicBuffer); - Polygon poly = (Polygon) opBuf.execute(geom, sr, GeodeticCurveType.Geodesic, distance, 100.0, false, null); - - String words = GeometryEngine.geometryToWkt(poly, 0); - assertTrue(poly.getType() == Geometry.Type.Polygon); - } - - @Test - public void testTriangleLength() { - Point pt_0 = new Point(10, 10); - Point pt_1 = new Point(20, 20); - Point pt_2 = new Point(20, 10); - double length = 0.0; - length += GeometryEngine.geodesicDistanceOnWGS84(pt_0, pt_1); - length += GeometryEngine.geodesicDistanceOnWGS84(pt_1, pt_2); - length += GeometryEngine.geodesicDistanceOnWGS84(pt_2, pt_0); - assertTrue(Math.abs(length - 3744719.4094597572) < 1e-13 * 3744719.4094597572); - } - - - @Test - public void testGeodesicForward() { - double latitude = 0; - double longitude = 0; - double distance = 1000; - double azimuth = 0; - double a = 6378137.0; // radius of spheroid for WGS_1984 - double e2 = 0.0066943799901413165; // ellipticity for WGS_1984 - double rpu = Math.PI / 180.0; - PeDouble lam2 = new PeDouble(); - PeDouble phi2 = new PeDouble(); - GeoDist.geodesic_forward(a, e2, longitude, latitude, distance, azimuth, lam2, phi2); - assertEquals(longitude, lam2.val / rpu, 0.00001); - } - - @Test - public void testRotationInvariance() { - Point pt_0 = new Point(10, 40); - Point pt_1 = new Point(20, 60); - Point pt_2 = new Point(20, 40); - double length = 0.0; - length += GeometryEngine.geodesicDistanceOnWGS84(pt_0, pt_1); - length += GeometryEngine.geodesicDistanceOnWGS84(pt_1, pt_2); - length += GeometryEngine.geodesicDistanceOnWGS84(pt_2, pt_0); - assertTrue(Math.abs(length - 5409156.3896271614) < 1e-13 * 5409156.3896271614); - - for (int i = -540; i < 540; i += 5) { - pt_0.setXY(i + 10, 40); - pt_1.setXY(i + 20, 60); - pt_2.setXY(i + 20, 40); - length = 0.0; - length += GeometryEngine.geodesicDistanceOnWGS84(pt_0, pt_1); - length += GeometryEngine.geodesicDistanceOnWGS84(pt_1, pt_2); - length += GeometryEngine.geodesicDistanceOnWGS84(pt_2, pt_0); - assertTrue(Math.abs(length - 5409156.3896271614) < 1e-13 * 5409156.3896271614); - } - } - - @Test - public void testDistanceFailure() { - { - Point p1 = new Point(-60.668485, -31.996013333333334); - Point p2 = new Point(119.13731666666666, 32.251583333333336); - double d = GeometryEngine.geodesicDistanceOnWGS84(p1, p2); - assertTrue(Math.abs(d - 19973410.50579736) < 1e-13 * 19973410.50579736); - } - - { - Point p1 = new Point(121.27343833333333, 27.467438333333334); - Point p2 = new Point(-58.55804833333333, -27.035613333333334); - double d = GeometryEngine.geodesicDistanceOnWGS84(p1, p2); - assertTrue(Math.abs(d - 19954707.428360686) < 1e-13 * 19954707.428360686); - } - - { - Point p1 = new Point(-53.329865, -36.08110166666667); - Point p2 = new Point(126.52895166666667, 35.97385); - double d = GeometryEngine.geodesicDistanceOnWGS84(p1, p2); - assertTrue(Math.abs(d - 19990586.700431127) < 1e-13 * 19990586.700431127); - } - - { - Point p1 = new Point(-4.7181166667, 36.1160166667); - Point p2 = new Point(175.248925, -35.7606716667); - double d = GeometryEngine.geodesicDistanceOnWGS84(p1, p2); - assertTrue(Math.abs(d - 19964450.206594173) < 1e-12 * 19964450.206594173); - } - } - - @Test - public void testDensifyPolyline() { - SpatialReference sr = SpatialReference.create(4326); - { - Polyline polyline = new Polyline(); - polyline.startPath(0, 0); - polyline.lineTo(4, 4); - polyline.lineTo(4, 8); - polyline.lineTo(8, 20); - - OperatorGeodeticDensifyByLength op = (OperatorGeodeticDensifyByLength) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.GeodeticDensifyByLength); - Polyline polylineDense = (Polyline) op.execute(polyline, sr, 5000, GeodeticCurveType.Geodesic, null); - assertEquals(polyline.calculateLength2D(), polylineDense.calculateLength2D(), .001); - assertEquals(polyline.getPoint(polyline.getPointCount() - 1).getX(), polylineDense.getPoint(polylineDense.getPointCount() - 1).getX()); - assertEquals(polyline.getPoint(polyline.getPointCount() - 1).getY(), polylineDense.getPoint(polylineDense.getPointCount() - 1).getY()); - assertEquals(polyline.getPoint(0).getX(), polylineDense.getPoint(0).getX()); - assertEquals(polyline.getPoint(0).getY(), polylineDense.getPoint(0).getY()); - - polyline.startPath(-2, -2); - polyline.lineTo(-4, -4); - polyline.lineTo(-8, -8); - polylineDense = (Polyline) op.execute(polyline, sr, 5000, GeodeticCurveType.Geodesic, null); - assertEquals(polyline.calculateLength2D(), polylineDense.calculateLength2D(), .001); - assertEquals(polyline.calculatePathLength2D(0), polylineDense.calculatePathLength2D(0), .001); - assertEquals(polyline.calculatePathLength2D(1), polylineDense.calculatePathLength2D(1), .001); - } - - { - Polyline polyline = new Polyline(); - polyline.startPath(0, 0); - polyline.lineTo(0, 1); - OperatorGeodeticDensifyByLength op = (OperatorGeodeticDensifyByLength) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.GeodeticDensifyByLength); - Polyline polylineDense = (Polyline) op.execute(polyline, sr, 100000, GeodeticCurveType.Geodesic, null); - assertEquals(polyline.getPoint(polyline.getPointCount() - 1).getX(), polylineDense.getPoint(polylineDense.getPointCount() - 1).getX()); - assertEquals(polyline.getPoint(polyline.getPointCount() - 1).getY(), polylineDense.getPoint(polylineDense.getPointCount() - 1).getY()); - assertEquals(polyline.getPoint(0).getX(), polylineDense.getPoint(0).getX()); - assertEquals(polyline.getPoint(0).getY(), polylineDense.getPoint(0).getY()); - assertEquals(3, polylineDense.getPointCount()); - - assertEquals( - GeometryEngine.geodesicDistanceOnWGS84( - polyline.getPoint(0), - polylineDense.getPoint(1)) + - GeometryEngine.geodesicDistanceOnWGS84( - polylineDense.getPoint(1), - polyline.getPoint(1)), - GeometryEngine.geodesicDistanceOnWGS84( - polyline.getPoint(0), - polyline.getPoint(1)) - ); - } - - { - Polyline polyline = new Polyline(); - polyline.startPath(0, 0); - polyline.lineTo(1, 0); - polyline.lineTo(2, 0); - OperatorGeodeticDensifyByLength op = (OperatorGeodeticDensifyByLength) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.GeodeticDensifyByLength); - Polyline polylineDense = (Polyline) op.execute(polyline, sr, 100000, GeodeticCurveType.Geodesic, null); - assertEquals(polyline.getPoint(polyline.getPointCount() - 1).getX(), polylineDense.getPoint(polylineDense.getPointCount() - 1).getX()); - assertEquals(polyline.getPoint(polyline.getPointCount() - 1).getY(), polylineDense.getPoint(polylineDense.getPointCount() - 1).getY()); - assertEquals(polyline.getPoint(0).getX(), polylineDense.getPoint(0).getX()); - assertEquals(polyline.getPoint(0).getY(), polylineDense.getPoint(0).getY()); - assertEquals(5, polylineDense.getPointCount()); - - assertEquals(polyline.getPoint(1).getX(), polylineDense.getPoint(2).getX()); - assertEquals(polyline.getPoint(1).getY(), polylineDense.getPoint(2).getY()); - assertEquals( - GeometryEngine.geodesicDistanceOnWGS84( - polyline.getPoint(0), - polylineDense.getPoint(1)) + - GeometryEngine.geodesicDistanceOnWGS84( - polylineDense.getPoint(1), - polyline.getPoint(1)), - GeometryEngine.geodesicDistanceOnWGS84( - polyline.getPoint(0), - polyline.getPoint(1)), - .0000001 - ); - } - - { - Polyline polyline = new Polyline(); - polyline.startPath(0, 0); - polyline.lineTo(4, 4); - polyline.lineTo(4, 8); - polyline.lineTo(8, 20); - double max_distance = 55000 / 3.5; - OperatorGeodeticDensifyByLength op = (OperatorGeodeticDensifyByLength) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.GeodeticDensifyByLength); - Polyline polylineDense = (Polyline) op.execute(polyline, sr, max_distance, GeodeticCurveType.Geodesic, null); - String words = GeometryEngine.geometryToWkt(polylineDense, 0); - assertEquals( - GeometryEngine.geodesicDistanceOnWGS84( - polyline.getPoint(0), - polyline.getPoint(polyline.getPointCount() - 1)), - GeometryEngine.geodesicDistanceOnWGS84( - polylineDense.getPoint(0), - polylineDense.getPoint(polylineDense.getPointCount() - 1)), - .0000001 - ); - } - } - - @Test - public void testDensifyPolygon() { - { - Polygon polygon = new Polygon(); - polygon.startPath(0, 0); - polygon.lineTo(0, 4); - polygon.lineTo(4, 4); - polygon.lineTo(4, 0); - polygon.closeAllPaths(); - SpatialReference sr = SpatialReference.create(4326); - OperatorGeodeticDensifyByLength op = (OperatorGeodeticDensifyByLength) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.GeodeticDensifyByLength); - Polygon polygonDense = (Polygon) op.execute(polygon, sr, 5000, GeodeticCurveType.Geodesic, null); - assertEquals(polygon.calculateLength2D(), polygonDense.calculateLength2D(), .005); - assertEquals(polygon.calculateArea2D(), polygonDense.calculateArea2D(), 0.007); - - polygon.startPath(-2, -2); - polygon.lineTo(-4, -4); - polygon.lineTo(-8, -8); - polygon.closeAllPaths(); - polygonDense = (Polygon) op.execute(polygon, sr, 5000, GeodeticCurveType.Geodesic, null); - assertEquals(polygon.calculateLength2D(), polygonDense.calculateLength2D(), .004); - assertEquals(polygon.calculateArea2D(), polygonDense.calculateArea2D(), 0.1); - } - } - - @Test - public void testInflateEnv2D() { - Envelope2D envOrig = new Envelope2D(0, -4, 4, 8); - Envelope2D env2D = new Envelope2D(0, -4, 4, 8); - - double a = 6378137.0; // radius of spheroid for WGS_1984 - double e2 = 0.0066943799901413165; // ellipticity for WGS_1984 - - GeoDist.inflateEnv2D(a, e2, env2D, 1000, 2000); - assertTrue(env2D.xmin < envOrig.xmin); - assertTrue(env2D.ymax > envOrig.ymax); - assertTrue(env2D.xmax > envOrig.xmax); - assertTrue(env2D.ymin < envOrig.ymin); - } - - @Test - public void testDeflateEnv2D() { - Envelope2D envOrig = new Envelope2D(0, -4, 4, 8); - Envelope2D env2D = new Envelope2D(0, -4, 4, 8); - - double a = 6378137.0; // radius of spheroid for WGS_1984 - double e2 = 0.0066943799901413165; // ellipticity for WGS_1984 - - GeoDist.inflateEnv2D(a, e2, env2D, -100, 2000); - assertTrue(env2D.xmin > envOrig.xmin); - assertTrue(env2D.ymax > envOrig.ymax); - assertTrue(env2D.xmax < envOrig.xmax); - assertTrue(env2D.ymin < envOrig.ymin); - } - - @Test - public void testVicenty() { - // test data from - // http://geographiclib.sourceforge.net/cgi-bin/GeodSolve - - double a = 6378137.0; // radius of spheroid for WGS_1984 - double e2 = 0.0066943799901413165; // ellipticity for WGS_1984 - double rpu = Math.PI / 180.0; - double dpu = 180.0 / Math.PI; - double distance = 2000.0; - { - Point p1 = new Point(0.0, 0.0); - PeDouble lam = new PeDouble(); - PeDouble phi = new PeDouble(); - GeoDist.geodesic_forward(a, e2, p1.getX() * rpu, p1.getY() * rpu, distance, 0.0 * rpu, lam, phi); - assertEquals(0.0, lam.val * dpu, 0.000001); - assertEquals(0.01808739, phi.val * dpu, 0.000001); - - PeDouble actualDistance = new PeDouble(); - GeoDist.geodesic_distance_ngs(a, e2, p1.getX() * rpu, p1.getY() * rpu, lam.val, phi.val, actualDistance, null, null); - assertEquals(actualDistance.val, distance, .02); - - } - { - Point p1 = new Point(45.0, 45.0); - PeDouble lam = new PeDouble(); - PeDouble phi = new PeDouble(); - GeoDist.geodesic_forward(a, e2, p1.getX() * rpu, p1.getY() * rpu, distance, 20.0 * rpu, lam, phi); - - assertEquals(45.01691097, phi.val * dpu, 0.000001); - assertEquals(45.00867811, lam.val * dpu, 0.000001); - } - { - Point p1 = new Point(60.0, 45.0); - PeDouble lam = new PeDouble(); - PeDouble phi = new PeDouble(); - GeoDist.geodesic_forward(a, e2, p1.getX() * rpu, p1.getY() * rpu, distance, 20.0 * rpu, lam, phi); - - //45.01691097 - assertEquals(45.01691097, phi.val * dpu, 0.000001); - assertEquals(60.00867811, lam.val * dpu, 0.000001); - } - { - Point p1 = new Point(-65.0, -45.0); - PeDouble lam = new PeDouble(); - PeDouble phi = new PeDouble(); - GeoDist.geodesic_forward(a, e2, p1.getX() * rpu, p1.getY() * rpu, distance, -20.0 * rpu, lam, phi); - - //-44.98308832 -65.00867301 - assertEquals(-44.98308832, phi.val * dpu, 0.000001); - assertEquals(-65.00867301, lam.val * dpu, 0.000001); - } - { - Point p1 = new Point(-165.0, -45.0); - PeDouble lam = new PeDouble(); - PeDouble phi = new PeDouble(); - GeoDist.geodesic_forward(a, e2, p1.getX() * rpu, p1.getY() * rpu, distance, 220.0 * rpu, lam, phi); - - //-45.01378505 -165.01630863 - assertEquals(-45.01378505, phi.val * dpu, 0.000001); - assertEquals(-165.01630863, lam.val * dpu, 0.000001); - } - } - - @Test - public void testGeodeticBufferPoint() { - { - SpatialReference sr = SpatialReference.create(4326); - Point p1 = new Point(0.0, 0.0); - OperatorGeodesicBuffer opBuf = (OperatorGeodesicBuffer) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.GeodesicBuffer); - double distance = 1000; - Polygon poly = (Polygon) opBuf.execute(p1, sr, GeodeticCurveType.Geodesic, distance, 0.1, false, null); - //String words = GeometryEngine.geometryToWkt(poly, 0); - assertNotNull(poly); - assertTrue(poly.getType() == Geometry.Type.Polygon); - double area = poly.calculateArea2D(); - assertEquals(2.550450219554701E-4, area, 0.0000000001); - assertEquals(97, poly.getPointCount()); - - assertTrue(OperatorContains.local().execute(poly, p1, sr, null)); - } - } - - @Test - public void testGeodeticBufferMultiPoint() { - { - SpatialReference sr = SpatialReference.create(4326); - MultiPoint mp = new MultiPoint(); - mp.add(0.0, 0.0); - mp.add(20.0, 0.0); - OperatorGeodesicBuffer opBuf = (OperatorGeodesicBuffer) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.GeodesicBuffer); - double distance = 100000; - Polygon poly = (Polygon) opBuf.execute(mp, sr, GeodeticCurveType.Geodesic, distance, 150, false, null); - String words = GeometryEngine.geometryToWkt(poly, 0); - assertNotNull(poly); - assertTrue(poly.getType() == Geometry.Type.Polygon); - assertEquals(2, poly.getPathCount()); - double area = poly.calculateArea2D(); - assertEquals(5.095268886272399, area, 0.0000000001); - assertEquals(120, poly.getPointCount()); - - assertTrue(OperatorContains.local().execute(poly, mp, sr, null)); - } - } - - @Test - public void testGeodeticBufferPolyline() { - { - Polyline polyline = new Polyline(); - polyline.startPath(0, 0); - polyline.lineTo(4, 4); - polyline.lineTo(4, 8); - polyline.lineTo(8, 20); - SpatialReference sr = SpatialReference.create(4326); - - OperatorBuffer opBufNorm = (OperatorBuffer) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.Buffer); - Polygon polyNorm = (Polygon) opBufNorm.execute(polyline, sr, .7, null); - - - String words = GeometryEngine.geometryToWkt(polyline, 0); - double distance = 55000; - OperatorGeodesicBuffer opBuf = (OperatorGeodesicBuffer) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.GeodesicBuffer); - Polygon poly = (Polygon) opBuf.execute(polyline, sr, GeodeticCurveType.Geodesic, distance, 150.0, false, null); - - words = GeometryEngine.geometryToWkt(poly, 0); - assertNotNull(poly); - assertTrue(poly.getType() == Geometry.Type.Polygon); - double area = poly.calculateArea2D(); - assertEquals(23.296270856192834, area, 0.00000000001); - } - } - - @Test - public void testBufferGeodeticPolyline2() { - SpatialReference sr = SpatialReference.create(4326); - Polyline inputGeom = new Polyline(); - OperatorGeodesicBuffer buffer = (OperatorGeodesicBuffer) OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.GeodesicBuffer); - OperatorSimplify simplify = (OperatorSimplify) OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Simplify); - inputGeom.startPath(0, 0); - inputGeom.lineTo(50, 50); - inputGeom.lineTo(50, 0); - inputGeom.lineTo(0, 50); - - { - Geometry result = buffer.execute(inputGeom, sr, 0, 0, 0, false, null); - assertTrue(result.getType().value() == Geometry.GeometryType.Polygon); - assertTrue(result.isEmpty()); - } - - { - Geometry result = buffer.execute(inputGeom, sr, 0, -1, 0, false, null); - assertTrue(result.getType().value() == Geometry.GeometryType.Polygon); - assertTrue(result.isEmpty()); - } - - { - String words = GeometryEngine.geometryToWkt(inputGeom, 0); - Geometry result = buffer.execute(inputGeom, sr, 0, 40.0, 50, false, null); - assertTrue(result.getType().value() == Geometry.GeometryType.Polygon); - Polygon poly = (Polygon) (result); - - words = GeometryEngine.geometryToWkt(poly, 0); + @Override + protected void setUp() throws Exception { + super.setUp(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + } + + @Test + public void testCoastalPolyline() throws Exception { + SpatialReference sr = SpatialReference.create(4326); + String geoJSON = "{ \"type\": \"LineString\", \"coordinates\": [ [ -90.418136, 46.566094 ], [ -90.348407, 46.600635 ], [ -90.327626, 46.607744 ], [ -90.306609, 46.602741 ], [ -90.265294, 46.618516 ], [ -90.237609, 46.624485 ], [ -90.164026, 46.645515 ], [ -90.100695, 46.655132 ], [ -90.045420, 46.668272 ], [ -90.028392, 46.674390 ], [ -89.996034, 46.693225 ], [ -89.985817, 46.703190 ], [ -89.973803, 46.710322 ], [ -89.957101, 46.716929 ], [ -89.918466, 46.740324 ], [ -89.892355, 46.763088 ], [ -89.848652, 46.795711 ], [ -89.831956, 46.804053 ], [ -89.790663, 46.818469 ], [ -89.720277, 46.830413 ], [ -89.673375, 46.833229 ], [ -89.660625, 46.831056 ], [ -89.642255, 46.825340 ], [ -89.634938, 46.819488 ], [ -89.619329, 46.818890 ], [ -89.569808, 46.831859 ], [ -89.535683, 46.835878 ], [ -89.513938, 46.841835 ], [ -89.499080, 46.841621 ], [ -89.491252, 46.838448 ], [ -89.471540, 46.837359 ], [ -89.437047, 46.839512 ], [ -89.415154, 46.843983 ], [ -89.372032, 46.857386 ], [ -89.249143, 46.903326 ], [ -89.227914, 46.912954 ], [ -89.201511, 46.931149 ], [ -89.168244, 46.965536 ], [ -89.142595, 46.984859 ], [ -89.128698, 46.992599 ], [ -89.118339, 46.994220 ], [ -89.113158, 46.989356 ], [ -89.106277, 46.986480 ], [ -89.086742, 46.985298 ], [ -89.063103, 46.988522 ], [ -89.039490, 46.999419 ], [ -89.028930, 47.001140 ], [ -89.022994, 46.995120 ], [ -88.998417, 46.995314 ], [ -88.987197, 46.997239 ], [ -88.972802, 47.002096 ], [ -88.959409, 47.008496 ], [ -88.944045, 47.020129 ], [ -88.924492, 47.042156 ], [ -88.914189, 47.059246 ], [ -88.903706, 47.086161 ], [ -88.889140, 47.100575 ], [ -88.855372, 47.114263 ], [ -88.848176, 47.115065 ], [ -88.814834, 47.141399 ], [ -88.789813, 47.150925 ], [ -88.778022, 47.150465 ], [ -88.764351, 47.155762 ], [ -88.729688, 47.185834 ], [ -88.699660, 47.204831 ], [ -88.672395, 47.219137 ], [ -88.656359, 47.225624 ], [ -88.640323, 47.226784 ], [ -88.623579, 47.232352 ], [ -88.609830, 47.238894 ], [ -88.584912, 47.242361 ], [ -88.573997, 47.245989 ], [ -88.500780, 47.293503 ], [ -88.477733, 47.313460 ], [ -88.470484, 47.327653 ], [ -88.459262, 47.339903 ], [ -88.418673, 47.371188 ], [ -88.389459, 47.384431 ], [ -88.324083, 47.403542 ], [ -88.303447, 47.412204 ], [ -88.285195, 47.422392 ], [ -88.239161, 47.429969 ], [ -88.227446, 47.435093 ], [ -88.218424, 47.441585 ], [ -88.216977, 47.445493 ], [ -88.217822, 47.448738 ], [ -88.181820, 47.457657 ], [ -88.150571, 47.460093 ], [ -88.139651, 47.462693 ], [ -88.085252, 47.468961 ], [ -88.076388, 47.467752 ], [ -88.049326, 47.469785 ], [ -88.048226, 47.470008 ], [ -88.048077, 47.474973 ], [ -88.040291, 47.475999 ], [ -87.978934, 47.479420 ], [ -87.929269, 47.478737 ], [ -87.902416, 47.477045 ], [ -87.898036, 47.474872 ], [ -87.816958, 47.471998 ], [ -87.801184, 47.473301 ], [ -87.756739, 47.460717 ], [ -87.730804, 47.449112 ], [ -87.715942, 47.439816 ], [ -87.710471, 47.406200 ], [ -87.712421, 47.401400 ], [ -87.721274, 47.401032 ], [ -87.742417, 47.405823 ], [ -87.751380, 47.405066 ], [ -87.759057, 47.403013 ], [ -87.765019, 47.398652 ], [ -87.800294, 47.392148 ], [ -87.815371, 47.384790 ], [ -87.827115, 47.386160 ], [ -87.834822, 47.390478 ], [ -87.848252, 47.394864 ], [ -87.856700, 47.395387 ], [ -87.882245, 47.395588 ], [ -87.941613, 47.390073 ], [ -87.957058, 47.387260 ], [ -87.965063, 47.374430 ], [ -87.965598, 47.368645 ], [ -87.962567, 47.362543 ], [ -87.954796, 47.356809 ], [ -87.947397, 47.355461 ], [ -87.938787, 47.346777 ], [ -87.938250, 47.342299 ], [ -87.943360, 47.335899 ], [ -87.946352, 47.334254 ], [ -87.958386, 47.334435 ], [ -87.968604, 47.332582 ], [ -87.989133, 47.322633 ], [ -88.016478, 47.306275 ], [ -88.054849, 47.298240 ], [ -88.060090, 47.295796 ], [ -88.071476, 47.286768 ], [ -88.096851, 47.261351 ], [ -88.108833, 47.259131 ], [ -88.117456, 47.255174 ], [ -88.131943, 47.239554 ], [ -88.163059, 47.216278 ], [ -88.194218, 47.209242 ], [ -88.204849, 47.210498 ], [ -88.212361, 47.209423 ], [ -88.228987, 47.199042 ], [ -88.236892, 47.189236 ], [ -88.242006, 47.174767 ], [ -88.242660, 47.158426 ], [ -88.239470, 47.151137 ], [ -88.236721, 47.149287 ], [ -88.231797, 47.149609 ], [ -88.232164, 47.145975 ], [ -88.239895, 47.139436 ], [ -88.247628, 47.135981 ], [ -88.249571, 47.136231 ], [ -88.250785, 47.140209 ], [ -88.255303, 47.143640 ], [ -88.262972, 47.145174 ], [ -88.272017, 47.143511 ], [ -88.281701, 47.138212 ], [ -88.289040, 47.129689 ], [ -88.289543, 47.126604 ], [ -88.287870, 47.125374 ], [ -88.287173, 47.120420 ], [ -88.288347, 47.114547 ], [ -88.297625, 47.098505 ], [ -88.340052, 47.080494 ], [ -88.346709, 47.079372 ], [ -88.349952, 47.076377 ], [ -88.353191, 47.069063 ], [ -88.353952, 47.058047 ], [ -88.359054, 47.039739 ], [ -88.367624, 47.019213 ], [ -88.373966, 47.012262 ], [ -88.385606, 47.004522 ], [ -88.404498, 46.983353 ], [ -88.411145, 46.977984 ], [ -88.443901, 46.972251 ], [ -88.448570, 46.946769 ], [ -88.455404, 46.923321 ], [ -88.475859, 46.886042 ], [ -88.477935, 46.850560 ], [ -88.483748, 46.831727 ], [ -88.482579, 46.826197 ], [ -88.473342, 46.806226 ], [ -88.462349, 46.786711 ], [ -88.438427, 46.786714 ], [ -88.433835, 46.793502 ], [ -88.415225, 46.811715 ], [ -88.381410, 46.838466 ], [ -88.382204, 46.844477 ], [ -88.382052, 46.845437 ], [ -88.390135, 46.851595 ], [ -88.404008, 46.848331 ], [ -88.389727, 46.867100 ], [ -88.372591, 46.872812 ], [ -88.375855, 46.863428 ], [ -88.369848, 46.857568 ], [ -88.368767, 46.857313 ], [ -88.360868, 46.856202 ], [ -88.351940, 46.857028 ], [ -88.310290, 46.889748 ], [ -88.281244, 46.906632 ], [ -88.261593, 46.915516 ], [ -88.244437, 46.929612 ], [ -88.167227, 46.958855 ], [ -88.155374, 46.965069 ], [ -88.143688, 46.966665 ], [ -88.132876, 46.962204 ], [ -88.150114, 46.943630 ], [ -88.187522, 46.918999 ], [ -88.175197, 46.904580 ], [ -88.161913, 46.904941 ], [ -88.126927, 46.909840 ], [ -88.101315, 46.917207 ], [ -88.081870, 46.920458 ], [ -88.065192, 46.918563 ], [ -88.032408, 46.908890 ], [ -88.004298, 46.906982 ], [ -87.986113, 46.905957 ], [ -87.956000, 46.909051 ], [ -87.900339, 46.909686 ], [ -87.874538, 46.892578 ], [ -87.846195, 46.883905 ], [ -87.841228, 46.884363 ], [ -87.827162, 46.889713 ], [ -87.816794, 46.891154 ], [ -87.813226, 46.888023 ], [ -87.793194, 46.880822 ], [ -87.782461, 46.879859 ], [ -87.776930, 46.876726 ], [ -87.776313, 46.872591 ], [ -87.778752, 46.870422 ], [ -87.776804, 46.866823 ], [ -87.765989, 46.861316 ], [ -87.755868, 46.860453 ], [ -87.746646, 46.865427 ], [ -87.741014, 46.865247 ], [ -87.734870, 46.850120 ], [ -87.736732, 46.847216 ], [ -87.734325, 46.836955 ], [ -87.731522, 46.831196 ], [ -87.727358, 46.827656 ], [ -87.713737, 46.825534 ], [ -87.694590, 46.827182 ], [ -87.685698, 46.832530 ], [ -87.687930, 46.839159 ], [ -87.687164, 46.841742 ], [ -87.680668, 46.842496 ], [ -87.674541, 46.836964 ], [ -87.673177, 46.827593 ], [ -87.674345, 46.824050 ], [ -87.672015, 46.820415 ], [ -87.662261, 46.815157 ], [ -87.651510, 46.812411 ], [ -87.641887, 46.813733 ], [ -87.633300, 46.812107 ], [ -87.628081, 46.805157 ], [ -87.607988, 46.788408 ], [ -87.595307, 46.782950 ], [ -87.590767, 46.753009 ], [ -87.582745, 46.730527 ], [ -87.573203, 46.720471 ], [ -87.523308, 46.688488 ], [ -87.524444, 46.677586 ], [ -87.503025, 46.647497 ], [ -87.492860, 46.642561 ], [ -87.467965, 46.635623 ], [ -87.466537, 46.631555 ], [ -87.467563, 46.626228 ], [ -87.464108, 46.614811 ], [ -87.451368, 46.605923 ], [ -87.442612, 46.602776 ], [ -87.411167, 46.601669 ], [ -87.403275, 46.595215 ], [ -87.383961, 46.593070 ], [ -87.381649, 46.580059 ], [ -87.392974, 46.572523 ], [ -87.392828, 46.570852 ], [ -87.382206, 46.553681 ], [ -87.375613, 46.547140 ], [ -87.390300, 46.542577 ], [ -87.393985, 46.533183 ], [ -87.389290, 46.524472 ], [ -87.381349, 46.517292 ], [ -87.366767, 46.507303 ], [ -87.351071, 46.500749 ], [ -87.310755, 46.492017 ], [ -87.258732, 46.488255 ], [ -87.202404, 46.490827 ], [ -87.175065, 46.497548 ], [ -87.127440, 46.494014 ], [ -87.107559, 46.496124 ], [ -87.098760, 46.503609 ], [ -87.077279, 46.515339 ], [ -87.046022, 46.519956 ], [ -87.029892, 46.525599 ], [ -87.017136, 46.533550 ], [ -87.008724, 46.532723 ], [ -86.976958, 46.526581 ], [ -86.964534, 46.516549 ], [ -86.962842, 46.509646 ], [ -86.946980, 46.484567 ], [ -86.946218, 46.479059 ], [ -86.949526, 46.476315 ], [ -86.947077, 46.472064 ], [ -86.927725, 46.464566 ], [ -86.903742, 46.466138 ], [ -86.889094, 46.458499 ], [ -86.883976, 46.450976 ], [ -86.883919, 46.441514 ], [ -86.875151, 46.437280 ], [ -86.850111, 46.434114 ], [ -86.837448, 46.434186 ], [ -86.816026, 46.437892 ], [ -86.810967, 46.449663 ], [ -86.808817, 46.460611 ], [ -86.803557, 46.466669 ], [ -86.787905, 46.477729 ], [ -86.768516, 46.479072 ], [ -86.750157, 46.479109 ], [ -86.735929, 46.475231 ], [ -86.731096, 46.471760 ], [ -86.730829, 46.468057 ], [ -86.710573, 46.444908 ], [ -86.703230, 46.439378 ], [ -86.698139, 46.438624 ], [ -86.686412, 46.454965 ], [ -86.688816, 46.463152 ], [ -86.686468, 46.471655 ], [ -86.683819, 46.498079 ], [ -86.696001, 46.503160 ], [ -86.701929, 46.511571 ], [ -86.709325, 46.543914 ], [ -86.695645, 46.555026 ], [ -86.678182, 46.561039 ], [ -86.675764, 46.557061 ], [ -86.670927, 46.556489 ], [ -86.656479, 46.558453 ], [ -86.652865, 46.560555 ], [ -86.627380, 46.533710 ], [ -86.629086, 46.518144 ], [ -86.632109, 46.508865 ], [ -86.634530, 46.504523 ], [ -86.641088, 46.500438 ], [ -86.645528, 46.492039 ], [ -86.646393, 46.485776 ], [ -86.636671, 46.478298 ], [ -86.627441, 46.477540 ], [ -86.620603, 46.483873 ], [ -86.618061, 46.489452 ], [ -86.612173, 46.493295 ], [ -86.609393, 46.492976 ], [ -86.606932, 46.478531 ], [ -86.609039, 46.470239 ], [ -86.586168, 46.463324 ], [ -86.557731, 46.487434 ], [ -86.524959, 46.505381 ], [ -86.495054, 46.524874 ], [ -86.484003, 46.535965 ], [ -86.481956, 46.542709 ], [ -86.469306, 46.551422 ], [ -86.459930, 46.551928 ], [ -86.444390, 46.548137 ], [ -86.437167, 46.548960 ], [ -86.390409, 46.563194 ], [ -86.349890, 46.578035 ], [ -86.188024, 46.654008 ], [ -86.161681, 46.669475 ], [ -86.138295, 46.672935 ], [ -86.119862, 46.657256 ], [ -86.112126, 46.655044 ], [ -86.099843, 46.654615 ], [ -86.074219, 46.657799 ], [ -86.036969, 46.667627 ], [ -85.995044, 46.673676 ], [ -85.953670, 46.676869 ], [ -85.924047, 46.684733 ], [ -85.877908, 46.690914 ], [ -85.841057, 46.688896 ], [ -85.794923, 46.681083 ], [ -85.750606, 46.677368 ], [ -85.714415, 46.677156 ], [ -85.668753, 46.680404 ], [ -85.624573, 46.678862 ], [ -85.587345, 46.674627 ], [ -85.542517, 46.674263 ], [ -85.509510, 46.675786 ], [ -85.482096, 46.680432 ], [ -85.369805, 46.713754 ], [ -85.289846, 46.744644 ], [ -85.256860, 46.753380 ], [ -85.173042, 46.763634 ], [ -85.063556, 46.757856 ], [ -85.036286, 46.760435 ], [ -85.009240, 46.769224 ], [ -84.989497, 46.772403 ], [ -84.964652, 46.772845 ], [ -84.954009, 46.771362 ], [ -84.951580, 46.769488 ], [ -84.987539, 46.745483 ], [ -85.007616, 46.728339 ], [ -85.020159, 46.712463 ], [ -85.027513, 46.697451 ], [ -85.030078, 46.684769 ], [ -85.028291, 46.675125 ], [ -85.035504, 46.625021 ], [ -85.037056, 46.600995 ], [ -85.035476, 46.581547 ], [ -85.031507, 46.568703 ], [ -85.029594, 46.554419 ], [ -85.027374, 46.553756 ], [ -85.025491, 46.546397 ], [ -85.027083, 46.543038 ], [ -85.045534, 46.537694 ], [ -85.052954, 46.532827 ], [ -85.056133, 46.526520 ], [ -85.054943, 46.514750 ], [ -85.049847, 46.503963 ], [ -85.033766, 46.487670 ], [ -85.025598, 46.483028 ], [ -85.015211, 46.479712 ], [ -84.969464, 46.476290 ], [ -84.955307, 46.480269 ], [ -84.947269, 46.487399 ], [ -84.937145, 46.489252 ], [ -84.934432, 46.480315 ], [ -84.921931, 46.469962 ], [ -84.915184, 46.467515 ], [ -84.893423, 46.465406 ], [ -84.875070, 46.466781 ], [ -84.861448, 46.469930 ], [ -84.849767, 46.460245 ], [ -84.843907, 46.448661 ], [ -84.829491, 46.444071 ], [ -84.800101, 46.446219 ], [ -84.769151, 46.453523 ], [ -84.723338, 46.468266 ], [ -84.689672, 46.483923 ], [ -84.678423, 46.487694 ], [ -84.653880, 46.482250 ], [ -84.631020, 46.484868 ], [ -84.616489, 46.471870 ], [ -84.607945, 46.456747 ], [ -84.584167, 46.439410 ], [ -84.573522, 46.427895 ], [ -84.551496, 46.418522 ], [ -84.503719, 46.439190 ], [ -84.493401, 46.440313 ], [ -84.479513, 46.432573 ], [ -84.471848, 46.434289 ], [ -84.462597, 46.440940 ], [ -84.455527, 46.453897 ], [ -84.455256, 46.462785 ], [ -84.463322, 46.467435 ] ] }"; + OperatorImportFromGeoJson importerGeoJson = (OperatorImportFromGeoJson) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ImportFromGeoJson); + Geometry geom = importerGeoJson.execute(0, Geometry.Type.Unknown, geoJSON, null).getGeometry(); + + + double distance = 9000; + OperatorGeodesicBuffer opBuf = (OperatorGeodesicBuffer) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.GeodesicBuffer); + Polygon poly = (Polygon) opBuf.execute(geom, sr, GeodeticCurveType.Geodesic, distance, 100.0, false, null); + + String words = GeometryEngine.geometryToWkt(poly, 0); + assertTrue(poly.getType() == Geometry.Type.Polygon); + } + + @Test + public void testTriangleLength() { + Point pt_0 = new Point(10, 10); + Point pt_1 = new Point(20, 20); + Point pt_2 = new Point(20, 10); + double length = 0.0; + length += GeometryEngine.geodesicDistanceOnWGS84(pt_0, pt_1); + length += GeometryEngine.geodesicDistanceOnWGS84(pt_1, pt_2); + length += GeometryEngine.geodesicDistanceOnWGS84(pt_2, pt_0); + assertTrue(Math.abs(length - 3744719.4094597572) < 1e-13 * 3744719.4094597572); + } + + + @Test + public void testGeodesicForward() { + double latitude = 0; + double longitude = 0; + double distance = 1000; + double azimuth = 0; + double a = 6378137.0; // radius of spheroid for WGS_1984 + double e2 = 0.0066943799901413165; // ellipticity for WGS_1984 + double rpu = Math.PI / 180.0; + PeDouble lam2 = new PeDouble(); + PeDouble phi2 = new PeDouble(); + GeoDist.geodesic_forward(a, e2, longitude, latitude, distance, azimuth, lam2, phi2); + assertEquals(longitude, lam2.val / rpu, 0.00001); + } + + @Test + public void testRotationInvariance() { + Point pt_0 = new Point(10, 40); + Point pt_1 = new Point(20, 60); + Point pt_2 = new Point(20, 40); + double length = 0.0; + length += GeometryEngine.geodesicDistanceOnWGS84(pt_0, pt_1); + length += GeometryEngine.geodesicDistanceOnWGS84(pt_1, pt_2); + length += GeometryEngine.geodesicDistanceOnWGS84(pt_2, pt_0); + assertTrue(Math.abs(length - 5409156.3896271614) < 1e-13 * 5409156.3896271614); + + for (int i = -540; i < 540; i += 5) { + pt_0.setXY(i + 10, 40); + pt_1.setXY(i + 20, 60); + pt_2.setXY(i + 20, 40); + length = 0.0; + length += GeometryEngine.geodesicDistanceOnWGS84(pt_0, pt_1); + length += GeometryEngine.geodesicDistanceOnWGS84(pt_1, pt_2); + length += GeometryEngine.geodesicDistanceOnWGS84(pt_2, pt_0); + assertTrue(Math.abs(length - 5409156.3896271614) < 1e-13 * 5409156.3896271614); + } + } + + @Test + public void testDistanceFailure() { + { + Point p1 = new Point(-60.668485, -31.996013333333334); + Point p2 = new Point(119.13731666666666, 32.251583333333336); + double d = GeometryEngine.geodesicDistanceOnWGS84(p1, p2); + assertTrue(Math.abs(d - 19973410.50579736) < 1e-13 * 19973410.50579736); + } + + { + Point p1 = new Point(121.27343833333333, 27.467438333333334); + Point p2 = new Point(-58.55804833333333, -27.035613333333334); + double d = GeometryEngine.geodesicDistanceOnWGS84(p1, p2); + assertTrue(Math.abs(d - 19954707.428360686) < 1e-13 * 19954707.428360686); + } + + { + Point p1 = new Point(-53.329865, -36.08110166666667); + Point p2 = new Point(126.52895166666667, 35.97385); + double d = GeometryEngine.geodesicDistanceOnWGS84(p1, p2); + assertTrue(Math.abs(d - 19990586.700431127) < 1e-13 * 19990586.700431127); + } + + { + Point p1 = new Point(-4.7181166667, 36.1160166667); + Point p2 = new Point(175.248925, -35.7606716667); + double d = GeometryEngine.geodesicDistanceOnWGS84(p1, p2); + assertTrue(Math.abs(d - 19964450.206594173) < 1e-12 * 19964450.206594173); + } + } + + @Test + public void testDensifyPolyline() { + SpatialReference sr = SpatialReference.create(4326); + { + Polyline polyline = new Polyline(); + polyline.startPath(0, 0); + polyline.lineTo(4, 4); + polyline.lineTo(4, 8); + polyline.lineTo(8, 20); + + OperatorGeodeticDensifyByLength op = (OperatorGeodeticDensifyByLength) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.GeodeticDensifyByLength); + Polyline polylineDense = (Polyline) op.execute(polyline, sr, 5000, GeodeticCurveType.Geodesic, null); + assertEquals(polyline.calculateLength2D(), polylineDense.calculateLength2D(), .001); + assertEquals(polyline.getPoint(polyline.getPointCount() - 1).getX(), polylineDense.getPoint(polylineDense.getPointCount() - 1).getX()); + assertEquals(polyline.getPoint(polyline.getPointCount() - 1).getY(), polylineDense.getPoint(polylineDense.getPointCount() - 1).getY()); + assertEquals(polyline.getPoint(0).getX(), polylineDense.getPoint(0).getX()); + assertEquals(polyline.getPoint(0).getY(), polylineDense.getPoint(0).getY()); + + polyline.startPath(-2, -2); + polyline.lineTo(-4, -4); + polyline.lineTo(-8, -8); + polylineDense = (Polyline) op.execute(polyline, sr, 5000, GeodeticCurveType.Geodesic, null); + assertEquals(polyline.calculateLength2D(), polylineDense.calculateLength2D(), .001); + assertEquals(polyline.calculatePathLength2D(0), polylineDense.calculatePathLength2D(0), .001); + assertEquals(polyline.calculatePathLength2D(1), polylineDense.calculatePathLength2D(1), .001); + } + + { + Polyline polyline = new Polyline(); + polyline.startPath(0, 0); + polyline.lineTo(0, 1); + OperatorGeodeticDensifyByLength op = (OperatorGeodeticDensifyByLength) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.GeodeticDensifyByLength); + Polyline polylineDense = (Polyline) op.execute(polyline, sr, 100000, GeodeticCurveType.Geodesic, null); + assertEquals(polyline.getPoint(polyline.getPointCount() - 1).getX(), polylineDense.getPoint(polylineDense.getPointCount() - 1).getX()); + assertEquals(polyline.getPoint(polyline.getPointCount() - 1).getY(), polylineDense.getPoint(polylineDense.getPointCount() - 1).getY()); + assertEquals(polyline.getPoint(0).getX(), polylineDense.getPoint(0).getX()); + assertEquals(polyline.getPoint(0).getY(), polylineDense.getPoint(0).getY()); + assertEquals(3, polylineDense.getPointCount()); + + assertEquals( + GeometryEngine.geodesicDistanceOnWGS84( + polyline.getPoint(0), + polylineDense.getPoint(1)) + + GeometryEngine.geodesicDistanceOnWGS84( + polylineDense.getPoint(1), + polyline.getPoint(1)), + GeometryEngine.geodesicDistanceOnWGS84( + polyline.getPoint(0), + polyline.getPoint(1)) + ); + } + + { + Polyline polyline = new Polyline(); + polyline.startPath(0, 0); + polyline.lineTo(1, 0); + polyline.lineTo(2, 0); + OperatorGeodeticDensifyByLength op = (OperatorGeodeticDensifyByLength) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.GeodeticDensifyByLength); + Polyline polylineDense = (Polyline) op.execute(polyline, sr, 100000, GeodeticCurveType.Geodesic, null); + assertEquals(polyline.getPoint(polyline.getPointCount() - 1).getX(), polylineDense.getPoint(polylineDense.getPointCount() - 1).getX()); + assertEquals(polyline.getPoint(polyline.getPointCount() - 1).getY(), polylineDense.getPoint(polylineDense.getPointCount() - 1).getY()); + assertEquals(polyline.getPoint(0).getX(), polylineDense.getPoint(0).getX()); + assertEquals(polyline.getPoint(0).getY(), polylineDense.getPoint(0).getY()); + assertEquals(5, polylineDense.getPointCount()); + + assertEquals(polyline.getPoint(1).getX(), polylineDense.getPoint(2).getX()); + assertEquals(polyline.getPoint(1).getY(), polylineDense.getPoint(2).getY()); + assertEquals( + GeometryEngine.geodesicDistanceOnWGS84( + polyline.getPoint(0), + polylineDense.getPoint(1)) + + GeometryEngine.geodesicDistanceOnWGS84( + polylineDense.getPoint(1), + polyline.getPoint(1)), + GeometryEngine.geodesicDistanceOnWGS84( + polyline.getPoint(0), + polyline.getPoint(1)), + .0000001 + ); + } + + { + Polyline polyline = new Polyline(); + polyline.startPath(0, 0); + polyline.lineTo(4, 4); + polyline.lineTo(4, 8); + polyline.lineTo(8, 20); + double max_distance = 55000 / 3.5; + OperatorGeodeticDensifyByLength op = (OperatorGeodeticDensifyByLength) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.GeodeticDensifyByLength); + Polyline polylineDense = (Polyline) op.execute(polyline, sr, max_distance, GeodeticCurveType.Geodesic, null); + String words = GeometryEngine.geometryToWkt(polylineDense, 0); + assertEquals( + GeometryEngine.geodesicDistanceOnWGS84( + polyline.getPoint(0), + polyline.getPoint(polyline.getPointCount() - 1)), + GeometryEngine.geodesicDistanceOnWGS84( + polylineDense.getPoint(0), + polylineDense.getPoint(polylineDense.getPointCount() - 1)), + .0000001 + ); + } + } + + @Test + public void testDensifyPolygon() { + { + Polygon polygon = new Polygon(); + polygon.startPath(0, 0); + polygon.lineTo(0, 4); + polygon.lineTo(4, 4); + polygon.lineTo(4, 0); + polygon.closeAllPaths(); + SpatialReference sr = SpatialReference.create(4326); + OperatorGeodeticDensifyByLength op = (OperatorGeodeticDensifyByLength) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.GeodeticDensifyByLength); + Polygon polygonDense = (Polygon) op.execute(polygon, sr, 5000, GeodeticCurveType.Geodesic, null); + assertEquals(polygon.calculateLength2D(), polygonDense.calculateLength2D(), .005); + assertEquals(polygon.calculateArea2D(), polygonDense.calculateArea2D(), 0.007); + + polygon.startPath(-2, -2); + polygon.lineTo(-4, -4); + polygon.lineTo(-8, -8); + polygon.closeAllPaths(); + polygonDense = (Polygon) op.execute(polygon, sr, 5000, GeodeticCurveType.Geodesic, null); + assertEquals(polygon.calculateLength2D(), polygonDense.calculateLength2D(), .004); + assertEquals(polygon.calculateArea2D(), polygonDense.calculateArea2D(), 0.1); + } + } + + @Test + public void testInflateEnv2D() { + Envelope2D envOrig = new Envelope2D(0, -4, 4, 8); + Envelope2D env2D = new Envelope2D(0, -4, 4, 8); + + double a = 6378137.0; // radius of spheroid for WGS_1984 + double e2 = 0.0066943799901413165; // ellipticity for WGS_1984 + + GeoDist.inflateEnv2D(a, e2, env2D, 1000, 2000); + assertTrue(env2D.xmin < envOrig.xmin); + assertTrue(env2D.ymax > envOrig.ymax); + assertTrue(env2D.xmax > envOrig.xmax); + assertTrue(env2D.ymin < envOrig.ymin); + } + + @Test + public void testDeflateEnv2D() { + Envelope2D envOrig = new Envelope2D(0, -4, 4, 8); + Envelope2D env2D = new Envelope2D(0, -4, 4, 8); + + double a = 6378137.0; // radius of spheroid for WGS_1984 + double e2 = 0.0066943799901413165; // ellipticity for WGS_1984 + + GeoDist.inflateEnv2D(a, e2, env2D, -100, 2000); + assertTrue(env2D.xmin > envOrig.xmin); + assertTrue(env2D.ymax > envOrig.ymax); + assertTrue(env2D.xmax < envOrig.xmax); + assertTrue(env2D.ymin < envOrig.ymin); + } + + @Test + public void testVicenty() { + // test data from + // http://geographiclib.sourceforge.net/cgi-bin/GeodSolve + + double a = 6378137.0; // radius of spheroid for WGS_1984 + double e2 = 0.0066943799901413165; // ellipticity for WGS_1984 + double rpu = Math.PI / 180.0; + double dpu = 180.0 / Math.PI; + double distance = 2000.0; + { + Point p1 = new Point(0.0, 0.0); + PeDouble lam = new PeDouble(); + PeDouble phi = new PeDouble(); + GeoDist.geodesic_forward(a, e2, p1.getX() * rpu, p1.getY() * rpu, distance, 0.0 * rpu, lam, phi); + assertEquals(0.0, lam.val * dpu, 0.000001); + assertEquals(0.01808739, phi.val * dpu, 0.000001); + + PeDouble actualDistance = new PeDouble(); + GeoDist.geodesic_distance_ngs(a, e2, p1.getX() * rpu, p1.getY() * rpu, lam.val, phi.val, actualDistance, null, null); + assertEquals(actualDistance.val, distance, .02); + + } + { + Point p1 = new Point(45.0, 45.0); + PeDouble lam = new PeDouble(); + PeDouble phi = new PeDouble(); + GeoDist.geodesic_forward(a, e2, p1.getX() * rpu, p1.getY() * rpu, distance, 20.0 * rpu, lam, phi); + + assertEquals(45.01691097, phi.val * dpu, 0.000001); + assertEquals(45.00867811, lam.val * dpu, 0.000001); + } + { + Point p1 = new Point(60.0, 45.0); + PeDouble lam = new PeDouble(); + PeDouble phi = new PeDouble(); + GeoDist.geodesic_forward(a, e2, p1.getX() * rpu, p1.getY() * rpu, distance, 20.0 * rpu, lam, phi); + + //45.01691097 + assertEquals(45.01691097, phi.val * dpu, 0.000001); + assertEquals(60.00867811, lam.val * dpu, 0.000001); + } + { + Point p1 = new Point(-65.0, -45.0); + PeDouble lam = new PeDouble(); + PeDouble phi = new PeDouble(); + GeoDist.geodesic_forward(a, e2, p1.getX() * rpu, p1.getY() * rpu, distance, -20.0 * rpu, lam, phi); + + //-44.98308832 -65.00867301 + assertEquals(-44.98308832, phi.val * dpu, 0.000001); + assertEquals(-65.00867301, lam.val * dpu, 0.000001); + } + { + Point p1 = new Point(-165.0, -45.0); + PeDouble lam = new PeDouble(); + PeDouble phi = new PeDouble(); + GeoDist.geodesic_forward(a, e2, p1.getX() * rpu, p1.getY() * rpu, distance, 220.0 * rpu, lam, phi); + + //-45.01378505 -165.01630863 + assertEquals(-45.01378505, phi.val * dpu, 0.000001); + assertEquals(-165.01630863, lam.val * dpu, 0.000001); + } + } + + @Test + public void testGeodeticBufferPoint() { + { + SpatialReference sr = SpatialReference.create(4326); + Point p1 = new Point(0.0, 0.0); + OperatorGeodesicBuffer opBuf = (OperatorGeodesicBuffer) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.GeodesicBuffer); + double distance = 1000; + Polygon poly = (Polygon) opBuf.execute(p1, sr, GeodeticCurveType.Geodesic, distance, 0.1, false, null); + //String words = GeometryEngine.geometryToWkt(poly, 0); + assertNotNull(poly); + assertTrue(poly.getType() == Geometry.Type.Polygon); + double area = poly.calculateArea2D(); + assertEquals(2.550450219554701E-4, area, 0.0000000001); + assertEquals(97, poly.getPointCount()); + + assertTrue(OperatorContains.local().execute(poly, p1, sr, null)); + } + } + + @Test + public void testGeodeticBufferMultiPoint() { + { + SpatialReference sr = SpatialReference.create(4326); + MultiPoint mp = new MultiPoint(); + mp.add(0.0, 0.0); + mp.add(20.0, 0.0); + OperatorGeodesicBuffer opBuf = (OperatorGeodesicBuffer) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.GeodesicBuffer); + double distance = 100000; + Polygon poly = (Polygon) opBuf.execute(mp, sr, GeodeticCurveType.Geodesic, distance, 150, false, null); + String words = GeometryEngine.geometryToWkt(poly, 0); + assertNotNull(poly); + assertTrue(poly.getType() == Geometry.Type.Polygon); + assertEquals(2, poly.getPathCount()); + double area = poly.calculateArea2D(); + assertEquals(5.095268886272399, area, 0.0000000001); + assertEquals(120, poly.getPointCount()); + + assertTrue(OperatorContains.local().execute(poly, mp, sr, null)); + } + } + + @Test + public void testGeodeticBufferPolyline() { + { + Polyline polyline = new Polyline(); + polyline.startPath(0, 0); + polyline.lineTo(4, 4); + polyline.lineTo(4, 8); + polyline.lineTo(8, 20); + SpatialReference sr = SpatialReference.create(4326); + + OperatorBuffer opBufNorm = (OperatorBuffer) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.Buffer); + Polygon polyNorm = (Polygon) opBufNorm.execute(polyline, sr, .7, null); + + + String words = GeometryEngine.geometryToWkt(polyline, 0); + double distance = 55000; + OperatorGeodesicBuffer opBuf = (OperatorGeodesicBuffer) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.GeodesicBuffer); + Polygon poly = (Polygon) opBuf.execute(polyline, sr, GeodeticCurveType.Geodesic, distance, 150.0, false, null); + + words = GeometryEngine.geometryToWkt(poly, 0); + assertNotNull(poly); + assertTrue(poly.getType() == Geometry.Type.Polygon); + double area = poly.calculateArea2D(); + assertEquals(23.296270856192834, area, 0.00000000001); + } + } + + @Test + public void testBufferGeodeticPolyline2() { + SpatialReference sr = SpatialReference.create(4326); + Polyline inputGeom = new Polyline(); + OperatorGeodesicBuffer buffer = (OperatorGeodesicBuffer) OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.GeodesicBuffer); + OperatorSimplify simplify = (OperatorSimplify) OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Simplify); + inputGeom.startPath(0, 0); + inputGeom.lineTo(50, 50); + inputGeom.lineTo(50, 0); + inputGeom.lineTo(0, 50); + + { + Geometry result = buffer.execute(inputGeom, sr, 0, 0, 0, false, null); + assertTrue(result.getType().value() == Geometry.GeometryType.Polygon); + assertTrue(result.isEmpty()); + } + + { + Geometry result = buffer.execute(inputGeom, sr, 0, -1, 0, false, null); + assertTrue(result.getType().value() == Geometry.GeometryType.Polygon); + assertTrue(result.isEmpty()); + } + + { + String words = GeometryEngine.geometryToWkt(inputGeom, 0); + Geometry result = buffer.execute(inputGeom, sr, 0, 40.0, 50, false, null); + assertTrue(result.getType().value() == Geometry.GeometryType.Polygon); + Polygon poly = (Polygon) (result); + + words = GeometryEngine.geometryToWkt(poly, 0); // Envelope2D env2D = new Envelope2D(); // result.queryEnvelope2D(env2D); // assertTrue(Math.abs(env2D.getWidth() - 80 - 50) < 0.1 // && Math.abs(env2D.getHeight() - 80 - 50) < 0.1); // assertTrue(Math.abs(env2D.getCenterX() - 25) < 0.1 // && Math.abs(env2D.getCenterY() - 25) < 0.1); - int pathCount = poly.getPathCount(); - // should have a hole in it - assertEquals(pathCount, 2); + int pathCount = poly.getPathCount(); + // should have a hole in it + assertEquals(pathCount, 2); - assertTrue(simplify.isSimpleAsFeature(result, sr, null)); - } + assertTrue(simplify.isSimpleAsFeature(result, sr, null)); + } - { - String words = GeometryEngine.geometryToWkt(inputGeom, 0); - Geometry result = buffer.execute(inputGeom, sr, 0, 3000000.0, 50, false, null); - assertTrue(result.getType().value() == Geometry.GeometryType.Polygon); - Polygon poly = (Polygon) (result); + { + String words = GeometryEngine.geometryToWkt(inputGeom, 0); + Geometry result = buffer.execute(inputGeom, sr, 0, 3000000.0, 50, false, null); + assertTrue(result.getType().value() == Geometry.GeometryType.Polygon); + Polygon poly = (Polygon) (result); - words = GeometryEngine.geometryToWkt(poly, 0); + words = GeometryEngine.geometryToWkt(poly, 0); // Envelope2D env2D = new Envelope2D(); // result.queryEnvelope2D(env2D); // assertTrue(Math.abs(env2D.getWidth() - 80 - 50) < 0.1 // && Math.abs(env2D.getHeight() - 80 - 50) < 0.1); // assertTrue(Math.abs(env2D.getCenterX() - 25) < 0.1 // && Math.abs(env2D.getCenterY() - 25) < 0.1); - int pathCount = poly.getPathCount(); - // should have a hole in it - assertEquals(pathCount, 1); + int pathCount = poly.getPathCount(); + // should have a hole in it + assertEquals(pathCount, 1); - assertTrue(simplify.isSimpleAsFeature(result, sr, null)); - } + assertTrue(simplify.isSimpleAsFeature(result, sr, null)); + } // // { // Geometry result = buffer.execute(inputGeom, sr, 4.0, null); @@ -506,169 +506,169 @@ public void testBufferGeodeticPolyline2() { // assertTrue(Math.abs(pointCount - 208.0) < 10); // assertTrue(simplify.isSimpleAsFeature(result, sr, null)); // } - } - - @Test - public void testGeodeticBufferSegment() { - { - Polyline polyline = new Polyline(); - polyline.startPath(0, 0); - polyline.lineTo(4, 4); - SegmentIterator segmentIterator = polyline.querySegmentIterator(); - segmentIterator.nextPath(); - Segment segment = segmentIterator.nextSegment(); - SpatialReference sr = SpatialReference.create(4326); - - - double distance = 55000; - OperatorGeodesicBuffer opBuf = (OperatorGeodesicBuffer) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.GeodesicBuffer); - Polygon poly = (Polygon) opBuf.execute(segment, sr, GeodeticCurveType.Geodesic, distance, 300.0, false, null); - - String words = GeometryEngine.geometryToWkt(poly, 0); - assertNotNull(poly); - assertTrue(poly.getType() == Geometry.Type.Polygon); - double area = poly.calculateArea2D(); - assertEquals(6.379702184244028, area, .0001); - } - } - - @Test - public void testBufferArcs() { - Polyline polyline = new Polyline(); - polyline.startPath(5, 25); - polyline.lineTo(10, 32); - SpatialReference sr = SpatialReference.create(4326); - OperatorGeodesicBuffer op = (OperatorGeodesicBuffer) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.GeodesicBuffer); - Polygon poly = (Polygon) op.execute(polyline, sr, 0, 3000, 500, false, null); - String words = GeometryEngine.geometryToWkt(poly, 0); - assertEquals(13, poly.getPointCount()); - } - - @Test - public void testPolygonBoundaryBug() { - SpatialReference sr = SpatialReference.create(4326); - OperatorImportFromWkt opWKT = (OperatorImportFromWkt) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ImportFromWkt); - OperatorGeodesicBuffer opBuf = (OperatorGeodesicBuffer) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.GeodesicBuffer); - double distance = 59000; - { - String wkt = "MULTILINESTRING ((5 0,3 38,3.9 37.7,4 40,30 10,5 0))"; - Geometry geom = opWKT.execute(0, Geometry.Type.Polyline, wkt, null); - Polygon poly = (Polygon) opBuf.execute(geom, sr, GeodeticCurveType.Geodesic, distance, 2000, false, null); - String words = GeometryEngine.geometryToWkt(poly, 0); - Envelope2D env2D = new Envelope2D(); - poly.queryEnvelope2D(env2D); - assertTrue(env2D.xmin < 3); - assertTrue(env2D.ymin < 0); - assertTrue(env2D.xmax > 30); - assertTrue(env2D.ymax > 40); - assertEquals(Geometry.Type.Polygon, poly.getType()); - assertEquals(24, poly.getPointCount()); - } - { - String wkt = "MULTILINESTRING ((15 5, 5 10, 10 20, 10 30, 16.666666666666664 33.333333333333329, 10 40, 20 40, 28.333333333333339 40, 20 45, 40 40, 45 40, 42 36, 45 30, 39.827586206896555 33.103448275862071, 36 28, 35.277777777777779 25.833333333333332, 45 20, 36.25 11.25, 40 10, 33.75 8.7500000000000018, 30 5, 23.333333333333336 6.6666666666666661, 15 5))"; - Geometry geom = opWKT.execute(0, Geometry.Type.Polyline, wkt, null); - Polygon poly = (Polygon) opBuf.execute(geom, sr, GeodeticCurveType.Geodesic, distance, 2000, false, null); - Envelope2D env2D = new Envelope2D(); - poly.queryEnvelope2D(env2D); - assertTrue(env2D.xmin < 5); - assertTrue(env2D.ymin < 5); - assertTrue(env2D.xmax > 45); - assertTrue(env2D.ymax > 45); - distance = 200000; - poly = (Polygon) opBuf.execute(geom, sr, GeodeticCurveType.Geodesic, distance, 2000, false, null); - env2D = new Envelope2D(); - poly.queryEnvelope2D(env2D); - assertTrue(env2D.xmin < 5); - assertTrue(env2D.ymin < 5); - assertTrue(env2D.xmax > 45); - assertTrue(env2D.ymax > 45); - distance = 20045; - poly = (Polygon) opBuf.execute(geom, sr, GeodeticCurveType.Geodesic, distance, 200, false, null); - env2D = new Envelope2D(); - poly.queryEnvelope2D(env2D); - assertTrue(env2D.xmin < 5); - assertTrue(env2D.ymin < 5); - assertTrue(env2D.xmax > 45); - assertTrue(env2D.ymax > 45); - } - } - - @Test - public void testImperfectArcEndings() throws Exception { - SpatialReference sr = SpatialReference.create(4326); - String wkt = "MULTILINESTRING ((79.599689290259803 80.056892196564064, 79.679967837449936 80.045572571657544, 79.760065736245338 80.034233827076164, 79.839983299288846 80.022876027925264, 79.919720840553722 80.011499239123168, 80 80))"; - Polyline polyline = new Polyline(); - polyline.startPath(79, 80); - polyline.lineTo(82, 82); - OperatorImportFromWkt opWKT = (OperatorImportFromWkt) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ImportFromWkt); - Geometry geom = opWKT.execute(0, Geometry.Type.Polyline, wkt, null); - OperatorGeodesicBuffer opBuf = (OperatorGeodesicBuffer) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.GeodesicBuffer); - double distance = 300; - Polygon poly = (Polygon) opBuf.execute(polyline, sr, GeodeticCurveType.Geodesic, distance, 5, false, null); - String words = GeometryEngine.geometryToWkt(poly, 0); - assertEquals(Geometry.Type.Polygon, poly.getType()); - assertEquals(21, poly.getPointCount()); - } - - @Test - public void testPolygon() { - SpatialReference sr = SpatialReference.create(4326); - OperatorImportFromWkt opWKT = (OperatorImportFromWkt) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ImportFromWkt); - OperatorGeodesicBuffer opBuf = (OperatorGeodesicBuffer) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.GeodesicBuffer); - String wkt = "MULTIPOLYGON (((15 5, 23.333333333333336 6.6666666666666661, 30 5, 33.75 8.7500000000000018, 40 10, 36.25 11.25, 45 20, 35.277777777777779 25.833333333333332, 36 28, 39.827586206896555 33.103448275862071, 45 30, 42 36, 45 40, 40 40, 20 45, 28.333333333333339 40, 20 40, 10 40, 16.666666666666664 33.333333333333329, 10 30, 10 20, 5 10, 15 5)))"; - Geometry geom = opWKT.execute(0, Geometry.Type.Polygon, wkt, null); - Envelope2D env2DOrig = new Envelope2D(); - geom.queryEnvelope2D(env2DOrig); - double distance = 300; - Polygon poly = (Polygon) opBuf.execute(geom, sr, GeodeticCurveType.Geodesic, distance, 5, false, null); - Envelope2D env2DPositiveBuff = new Envelope2D(); - poly.queryEnvelope2D(env2DPositiveBuff); - assertTrue(env2DPositiveBuff.xmax > env2DOrig.xmax); - assertTrue(env2DPositiveBuff.ymax > env2DOrig.ymax); - assertTrue(env2DPositiveBuff.xmin < env2DOrig.xmin); - assertTrue(env2DPositiveBuff.ymin < env2DOrig.ymin); - - distance = -300; - poly = (Polygon) opBuf.execute(geom, sr, GeodeticCurveType.Geodesic, distance, 5, false, null); - Envelope2D env2DNegativeBuff = new Envelope2D(); - poly.queryEnvelope2D(env2DNegativeBuff); - assertTrue(env2DNegativeBuff.xmax < env2DOrig.xmax); - assertTrue(env2DNegativeBuff.ymax < env2DOrig.ymax); - assertTrue(env2DNegativeBuff.xmin > env2DOrig.xmin); - assertTrue(env2DNegativeBuff.ymin > env2DOrig.ymin); - } - - @Test - public void testEnvelop() { - SpatialReference sr = SpatialReference.create(4326); - OperatorImportFromWkt opWKT = (OperatorImportFromWkt) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ImportFromWkt); - OperatorGeodesicBuffer opBuf = (OperatorGeodesicBuffer) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.GeodesicBuffer); - String wkt = "MULTIPOLYGON (((15 5, 23.333333333333336 6.6666666666666661, 30 5, 33.75 8.7500000000000018, 40 10, 36.25 11.25, 45 20, 35.277777777777779 25.833333333333332, 36 28, 39.827586206896555 33.103448275862071, 45 30, 42 36, 45 40, 40 40, 20 45, 28.333333333333339 40, 20 40, 10 40, 16.666666666666664 33.333333333333329, 10 30, 10 20, 5 10, 15 5)))"; - Geometry geom = opWKT.execute(0, Geometry.Type.Polygon, wkt, null); - Envelope envOrig = new Envelope(); - geom.queryEnvelope(envOrig); - double distance = 300; - Polygon poly = (Polygon) opBuf.execute(envOrig, sr, GeodeticCurveType.Geodesic, distance, 5, false, null); - OperatorContains opContains = (OperatorContains) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.Contains); - assertTrue(opContains.execute(poly, geom, sr, null)); - String words = GeometryEngine.geometryToWkt(poly, 0); - assertTrue(opContains.execute(poly, envOrig, sr, null)); - } - - - @Test - public void testDegeneratePolyline() { - String wkt = "LINESTRING (0 0, 0 80)"; - SpatialReference sr = SpatialReference.create(4326); - OperatorImportFromWkt opWKT = (OperatorImportFromWkt) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ImportFromWkt); - OperatorGeodesicBuffer opBuf = (OperatorGeodesicBuffer) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.GeodesicBuffer); - Geometry geom = opWKT.execute(0, Geometry.Type.Unknown, wkt, null); - double distance = 30000; - Polygon poly = (Polygon) opBuf.execute(geom, sr, GeodeticCurveType.Geodesic, distance, 500, false, null); - OperatorContains opContains = (OperatorContains) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.Contains); - String words = GeometryEngine.geometryToWkt(poly, 0); - assertTrue(opContains.execute(poly, geom, sr, null)); - } + } + + @Test + public void testGeodeticBufferSegment() { + { + Polyline polyline = new Polyline(); + polyline.startPath(0, 0); + polyline.lineTo(4, 4); + SegmentIterator segmentIterator = polyline.querySegmentIterator(); + segmentIterator.nextPath(); + Segment segment = segmentIterator.nextSegment(); + SpatialReference sr = SpatialReference.create(4326); + + + double distance = 55000; + OperatorGeodesicBuffer opBuf = (OperatorGeodesicBuffer) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.GeodesicBuffer); + Polygon poly = (Polygon) opBuf.execute(segment, sr, GeodeticCurveType.Geodesic, distance, 300.0, false, null); + + String words = GeometryEngine.geometryToWkt(poly, 0); + assertNotNull(poly); + assertTrue(poly.getType() == Geometry.Type.Polygon); + double area = poly.calculateArea2D(); + assertEquals(6.379702184244028, area, .0001); + } + } + + @Test + public void testBufferArcs() { + Polyline polyline = new Polyline(); + polyline.startPath(5, 25); + polyline.lineTo(10, 32); + SpatialReference sr = SpatialReference.create(4326); + OperatorGeodesicBuffer op = (OperatorGeodesicBuffer) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.GeodesicBuffer); + Polygon poly = (Polygon) op.execute(polyline, sr, 0, 3000, 500, false, null); + String words = GeometryEngine.geometryToWkt(poly, 0); + assertEquals(13, poly.getPointCount()); + } + + @Test + public void testPolygonBoundaryBug() { + SpatialReference sr = SpatialReference.create(4326); + OperatorImportFromWkt opWKT = (OperatorImportFromWkt) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ImportFromWkt); + OperatorGeodesicBuffer opBuf = (OperatorGeodesicBuffer) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.GeodesicBuffer); + double distance = 59000; + { + String wkt = "MULTILINESTRING ((5 0,3 38,3.9 37.7,4 40,30 10,5 0))"; + Geometry geom = opWKT.execute(0, Geometry.Type.Polyline, wkt, null); + Polygon poly = (Polygon) opBuf.execute(geom, sr, GeodeticCurveType.Geodesic, distance, 2000, false, null); + String words = GeometryEngine.geometryToWkt(poly, 0); + Envelope2D env2D = new Envelope2D(); + poly.queryEnvelope2D(env2D); + assertTrue(env2D.xmin < 3); + assertTrue(env2D.ymin < 0); + assertTrue(env2D.xmax > 30); + assertTrue(env2D.ymax > 40); + assertEquals(Geometry.Type.Polygon, poly.getType()); + assertEquals(24, poly.getPointCount()); + } + { + String wkt = "MULTILINESTRING ((15 5, 5 10, 10 20, 10 30, 16.666666666666664 33.333333333333329, 10 40, 20 40, 28.333333333333339 40, 20 45, 40 40, 45 40, 42 36, 45 30, 39.827586206896555 33.103448275862071, 36 28, 35.277777777777779 25.833333333333332, 45 20, 36.25 11.25, 40 10, 33.75 8.7500000000000018, 30 5, 23.333333333333336 6.6666666666666661, 15 5))"; + Geometry geom = opWKT.execute(0, Geometry.Type.Polyline, wkt, null); + Polygon poly = (Polygon) opBuf.execute(geom, sr, GeodeticCurveType.Geodesic, distance, 2000, false, null); + Envelope2D env2D = new Envelope2D(); + poly.queryEnvelope2D(env2D); + assertTrue(env2D.xmin < 5); + assertTrue(env2D.ymin < 5); + assertTrue(env2D.xmax > 45); + assertTrue(env2D.ymax > 45); + distance = 200000; + poly = (Polygon) opBuf.execute(geom, sr, GeodeticCurveType.Geodesic, distance, 2000, false, null); + env2D = new Envelope2D(); + poly.queryEnvelope2D(env2D); + assertTrue(env2D.xmin < 5); + assertTrue(env2D.ymin < 5); + assertTrue(env2D.xmax > 45); + assertTrue(env2D.ymax > 45); + distance = 20045; + poly = (Polygon) opBuf.execute(geom, sr, GeodeticCurveType.Geodesic, distance, 200, false, null); + env2D = new Envelope2D(); + poly.queryEnvelope2D(env2D); + assertTrue(env2D.xmin < 5); + assertTrue(env2D.ymin < 5); + assertTrue(env2D.xmax > 45); + assertTrue(env2D.ymax > 45); + } + } + + @Test + public void testImperfectArcEndings() throws Exception { + SpatialReference sr = SpatialReference.create(4326); + String wkt = "MULTILINESTRING ((79.599689290259803 80.056892196564064, 79.679967837449936 80.045572571657544, 79.760065736245338 80.034233827076164, 79.839983299288846 80.022876027925264, 79.919720840553722 80.011499239123168, 80 80))"; + Polyline polyline = new Polyline(); + polyline.startPath(79, 80); + polyline.lineTo(82, 82); + OperatorImportFromWkt opWKT = (OperatorImportFromWkt) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ImportFromWkt); + Geometry geom = opWKT.execute(0, Geometry.Type.Polyline, wkt, null); + OperatorGeodesicBuffer opBuf = (OperatorGeodesicBuffer) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.GeodesicBuffer); + double distance = 300; + Polygon poly = (Polygon) opBuf.execute(polyline, sr, GeodeticCurveType.Geodesic, distance, 5, false, null); + String words = GeometryEngine.geometryToWkt(poly, 0); + assertEquals(Geometry.Type.Polygon, poly.getType()); + assertEquals(21, poly.getPointCount()); + } + + @Test + public void testPolygon() { + SpatialReference sr = SpatialReference.create(4326); + OperatorImportFromWkt opWKT = (OperatorImportFromWkt) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ImportFromWkt); + OperatorGeodesicBuffer opBuf = (OperatorGeodesicBuffer) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.GeodesicBuffer); + String wkt = "MULTIPOLYGON (((15 5, 23.333333333333336 6.6666666666666661, 30 5, 33.75 8.7500000000000018, 40 10, 36.25 11.25, 45 20, 35.277777777777779 25.833333333333332, 36 28, 39.827586206896555 33.103448275862071, 45 30, 42 36, 45 40, 40 40, 20 45, 28.333333333333339 40, 20 40, 10 40, 16.666666666666664 33.333333333333329, 10 30, 10 20, 5 10, 15 5)))"; + Geometry geom = opWKT.execute(0, Geometry.Type.Polygon, wkt, null); + Envelope2D env2DOrig = new Envelope2D(); + geom.queryEnvelope2D(env2DOrig); + double distance = 300; + Polygon poly = (Polygon) opBuf.execute(geom, sr, GeodeticCurveType.Geodesic, distance, 5, false, null); + Envelope2D env2DPositiveBuff = new Envelope2D(); + poly.queryEnvelope2D(env2DPositiveBuff); + assertTrue(env2DPositiveBuff.xmax > env2DOrig.xmax); + assertTrue(env2DPositiveBuff.ymax > env2DOrig.ymax); + assertTrue(env2DPositiveBuff.xmin < env2DOrig.xmin); + assertTrue(env2DPositiveBuff.ymin < env2DOrig.ymin); + + distance = -300; + poly = (Polygon) opBuf.execute(geom, sr, GeodeticCurveType.Geodesic, distance, 5, false, null); + Envelope2D env2DNegativeBuff = new Envelope2D(); + poly.queryEnvelope2D(env2DNegativeBuff); + assertTrue(env2DNegativeBuff.xmax < env2DOrig.xmax); + assertTrue(env2DNegativeBuff.ymax < env2DOrig.ymax); + assertTrue(env2DNegativeBuff.xmin > env2DOrig.xmin); + assertTrue(env2DNegativeBuff.ymin > env2DOrig.ymin); + } + + @Test + public void testEnvelop() { + SpatialReference sr = SpatialReference.create(4326); + OperatorImportFromWkt opWKT = (OperatorImportFromWkt) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ImportFromWkt); + OperatorGeodesicBuffer opBuf = (OperatorGeodesicBuffer) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.GeodesicBuffer); + String wkt = "MULTIPOLYGON (((15 5, 23.333333333333336 6.6666666666666661, 30 5, 33.75 8.7500000000000018, 40 10, 36.25 11.25, 45 20, 35.277777777777779 25.833333333333332, 36 28, 39.827586206896555 33.103448275862071, 45 30, 42 36, 45 40, 40 40, 20 45, 28.333333333333339 40, 20 40, 10 40, 16.666666666666664 33.333333333333329, 10 30, 10 20, 5 10, 15 5)))"; + Geometry geom = opWKT.execute(0, Geometry.Type.Polygon, wkt, null); + Envelope envOrig = new Envelope(); + geom.queryEnvelope(envOrig); + double distance = 300; + Polygon poly = (Polygon) opBuf.execute(envOrig, sr, GeodeticCurveType.Geodesic, distance, 5, false, null); + OperatorContains opContains = (OperatorContains) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.Contains); + assertTrue(opContains.execute(poly, geom, sr, null)); + String words = GeometryEngine.geometryToWkt(poly, 0); + assertTrue(opContains.execute(poly, envOrig, sr, null)); + } + + + @Test + public void testDegeneratePolyline() { + String wkt = "LINESTRING (0 0, 0 80)"; + SpatialReference sr = SpatialReference.create(4326); + OperatorImportFromWkt opWKT = (OperatorImportFromWkt) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ImportFromWkt); + OperatorGeodesicBuffer opBuf = (OperatorGeodesicBuffer) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.GeodesicBuffer); + Geometry geom = opWKT.execute(0, Geometry.Type.Unknown, wkt, null); + double distance = 30000; + Polygon poly = (Polygon) opBuf.execute(geom, sr, GeodeticCurveType.Geodesic, distance, 500, false, null); + OperatorContains opContains = (OperatorContains) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.Contains); + String words = GeometryEngine.geometryToWkt(poly, 0); + assertTrue(opContains.execute(poly, geom, sr, null)); + } // @Test @@ -714,51 +714,51 @@ public void testDegeneratePolyline() { // */ // } - @Test - public void testEnvelopeMidpoint() { - Envelope2D envelope2D = new Envelope2D(45, -10, 55, 10); - Point2D centerPoint = new Point2D(); - double a = 6378137.0; // radius of spheroid for WGS_1984 - double e2 = 0.0066943799901413165; // ellipticity for WGS_1984 - GeoDist.getEnvCenter(a, e2, envelope2D, centerPoint); - assertEquals(50, centerPoint.x, 1e-12); - assertEquals(0, centerPoint.y, 1e-4); - } - - @Test - public void testEnvelopeMidpointDateline() { - Envelope2D envelope2D = new Envelope2D(175, -10, -175, 10); - Point2D centerPoint = new Point2D(); - double a = 6378137.0; // radius of spheroid for WGS_1984 - double e2 = 0.0066943799901413165; // ellipticity for WGS_1984 - GeoDist.getEnvCenter(a, e2, envelope2D, centerPoint); - assertEquals(180, Math.abs(centerPoint.x), 1e-12); - assertEquals(0, centerPoint.y, 1e-4); - } - - @Test - public void testDifferentDatums() { - SpatialReference spatialReferenceWgs = SpatialReference.create(4326); - SpatialReference spatialReferenceNad = SpatialReference.create(4269); - - Polyline polyline = new Polyline(); - polyline.startPath(-172.54, 23.81); - polyline.lineTo(-47.74, 86.46); - - Geometry geometryW = OperatorGeodeticDensifyByLength.local().execute(polyline, spatialReferenceWgs, 5000, GeodeticCurveType.Geodesic, null); - Geometry geometryW2 = OperatorGeodeticDensifyByLength.local().execute(polyline, spatialReferenceWgs, 5000, GeodeticCurveType.Geodesic, null); - Geometry geometryN = OperatorGeodeticDensifyByLength.local().execute(polyline, spatialReferenceNad, 5000, GeodeticCurveType.Geodesic, null); - assertFalse(geometryN.equals(geometryW)); - assertTrue(geometryW.equals(geometryW2)); - - Geometry geometryWBuff = OperatorGeodesicBuffer.local().execute(polyline, spatialReferenceWgs, GeodeticCurveType.Geodesic, 200, 20, false, null); - Geometry geometryNBuff = OperatorGeodesicBuffer.local().execute(polyline, spatialReferenceNad, GeodeticCurveType.Geodesic, 200, 20, false, null); - assertFalse(geometryNBuff.equals(geometryWBuff)); - - } - - @Test - public void testProjectedGeodetic() { + @Test + public void testEnvelopeMidpoint() { + Envelope2D envelope2D = new Envelope2D(45, -10, 55, 10); + Point2D centerPoint = new Point2D(); + double a = 6378137.0; // radius of spheroid for WGS_1984 + double e2 = 0.0066943799901413165; // ellipticity for WGS_1984 + GeoDist.getEnvCenter(a, e2, envelope2D, centerPoint); + assertEquals(50, centerPoint.x, 1e-12); + assertEquals(0, centerPoint.y, 1e-4); + } + + @Test + public void testEnvelopeMidpointDateline() { + Envelope2D envelope2D = new Envelope2D(175, -10, -175, 10); + Point2D centerPoint = new Point2D(); + double a = 6378137.0; // radius of spheroid for WGS_1984 + double e2 = 0.0066943799901413165; // ellipticity for WGS_1984 + GeoDist.getEnvCenter(a, e2, envelope2D, centerPoint); + assertEquals(180, Math.abs(centerPoint.x), 1e-12); + assertEquals(0, centerPoint.y, 1e-4); + } + + @Test + public void testDifferentDatums() { + SpatialReference spatialReferenceWgs = SpatialReference.create(4326); + SpatialReference spatialReferenceNad = SpatialReference.create(4269); + + Polyline polyline = new Polyline(); + polyline.startPath(-172.54, 23.81); + polyline.lineTo(-47.74, 86.46); + + Geometry geometryW = OperatorGeodeticDensifyByLength.local().execute(polyline, spatialReferenceWgs, 5000, GeodeticCurveType.Geodesic, null); + Geometry geometryW2 = OperatorGeodeticDensifyByLength.local().execute(polyline, spatialReferenceWgs, 5000, GeodeticCurveType.Geodesic, null); + Geometry geometryN = OperatorGeodeticDensifyByLength.local().execute(polyline, spatialReferenceNad, 5000, GeodeticCurveType.Geodesic, null); + assertFalse(geometryN.equals(geometryW)); + assertTrue(geometryW.equals(geometryW2)); + + Geometry geometryWBuff = OperatorGeodesicBuffer.local().execute(polyline, spatialReferenceWgs, GeodeticCurveType.Geodesic, 200, 20, false, null); + Geometry geometryNBuff = OperatorGeodesicBuffer.local().execute(polyline, spatialReferenceNad, GeodeticCurveType.Geodesic, 200, 20, false, null); + assertFalse(geometryNBuff.equals(geometryWBuff)); + + } + + @Test + public void testProjectedGeodetic() { /* // POINT (4322181.519435114 3212199.338618969) proj4: "+proj=laea +lat_0=31.593750 +lon_0=-94.718750 +x_0=4321000 +y_0=3210000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs" SpatialReferenceData spatialReferenceData = SpatialReferenceData.newBuilder().setProj4("+proj=laea +lat_0=31.593750 +lon_0=-94.718750 +x_0=4321000 +y_0=3210000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs").build(); @@ -784,17 +784,17 @@ public void testProjectedGeodetic() { GeometryResponse geometryResponse1 = stub.geometryOperationUnary(geometryRequest1); assertTrue(geometryResponse1.getSpatialRelationship()); */ - Geometry point = GeometryEngine.geometryFromWkt("POINT (4322181.519435114 3212199.338618969)", 0, Geometry.Type.Unknown); - SpatialReference spatialReference = SpatialReference.createFromProj4("+proj=laea +lat_0=31.593750 +lon_0=-94.718750 +x_0=4321000 +y_0=3210000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs"); - OperatorGeodesicBuffer operatorGeodesicBuffer = (OperatorGeodesicBuffer)OperatorFactoryLocal.getInstance().getOperator(Operator.Type.GeodesicBuffer); - Geometry buffered = operatorGeodesicBuffer.execute(point, spatialReference, GeodeticCurveType.Geodesic, 400, Double.NaN, false, null); + Geometry point = GeometryEngine.geometryFromWkt("POINT (4322181.519435114 3212199.338618969)", 0, Geometry.Type.Unknown); + SpatialReference spatialReference = SpatialReference.createFromProj4("+proj=laea +lat_0=31.593750 +lon_0=-94.718750 +x_0=4321000 +y_0=3210000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs"); + OperatorGeodesicBuffer operatorGeodesicBuffer = (OperatorGeodesicBuffer) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.GeodesicBuffer); + Geometry buffered = operatorGeodesicBuffer.execute(point, spatialReference, GeodeticCurveType.Geodesic, 400, Double.NaN, false, null); - assertFalse(GeometryEngine.disjoint(buffered, point, spatialReference)); - } + assertFalse(GeometryEngine.disjoint(buffered, point, spatialReference)); + } - public void testLengthAccurateCR191313() { - /* + public void testLengthAccurateCR191313() { + /* * // random_test(); OperatorFactoryLocal engine = * OperatorFactoryLocal.getInstance(); //TODO: Make this: * OperatorShapePreservingLength geoLengthOp = @@ -811,139 +811,139 @@ public void testLengthAccurateCR191313() { * geoLengthOp.execute(polyline, spatialRef, null); * assertTrue(Math.abs(length - 2738362.3249366437) < 2e-9 * length); */ - } - - public void testGeodeticLength() { - Polyline polyline = new Polyline(); - polyline.startPath(0,0); - polyline.lineTo(1, 0); - double length = OperatorGeodeticLength.local().execute(polyline, SpatialReference.create(4326), GeodeticCurveType.Geodesic, null); - assertEquals(111319.4907932264, length); - - polyline = new Polyline(); - polyline.startPath(0,0); - polyline.lineTo(-1, 0); - length = OperatorGeodeticLength.local().execute(polyline, SpatialReference.create(4326), GeodeticCurveType.Geodesic, null); - assertEquals(111319.4907932264, length); - - polyline = new Polyline(); - polyline.startPath(179,0); - polyline.lineTo(-180, 0); - length = OperatorGeodeticLength.local().execute(polyline, SpatialReference.create(4326), GeodeticCurveType.Geodesic, null); - assertEquals(111319.4907932264, length, 14); - - polyline = new Polyline(); - polyline.startPath(-179,0); - polyline.lineTo(-180, 0); - length = OperatorGeodeticLength.local().execute(polyline, SpatialReference.create(4326), GeodeticCurveType.Geodesic, null); - assertEquals(111319.4907932264, length, 14); - - polyline = new Polyline(); - polyline.startPath(179,0); - polyline.lineTo(180, 0); - length = OperatorGeodeticLength.local().execute(polyline, SpatialReference.create(4326), GeodeticCurveType.Geodesic, null); - assertEquals(111319.4907932264, length, 14); - - polyline = new Polyline(); - polyline.startPath(180,0); - polyline.lineTo(179, 0); - length = OperatorGeodeticLength.local().execute(polyline, SpatialReference.create(4326), GeodeticCurveType.Geodesic, null); - assertEquals(111319.4907932264, length, 14); - - polyline = new Polyline(); - polyline.startPath(180,0); - polyline.lineTo(177, 0); - length = OperatorGeodeticLength.local().execute(polyline, SpatialReference.create(4326), GeodeticCurveType.Geodesic, null); - assertEquals(3 * 111319.4907932264, length, 14); - - polyline = new Polyline(); - polyline.startPath(0,90); - polyline.lineTo(0, 0); - length = OperatorGeodeticLength.local().execute(polyline, SpatialReference.create(4326), GeodeticCurveType.Geodesic, null); - assertEquals(10001.96572931 * 1000, length, 14); - - polyline = new Polyline(); - polyline.startPath(1,0); - polyline.lineTo(1, 90); - length = OperatorGeodeticLength.local().execute(polyline, SpatialReference.create(4326), GeodeticCurveType.Geodesic, null); - assertEquals(10001.96572931 * 1000, length, 14); - - polyline = new Polyline(); - polyline.startPath(1,90); - polyline.lineTo(1, 0); - polyline.lineTo(0, 0); - polyline.lineTo(0,90); - length = OperatorGeodeticLength.local().execute(polyline, SpatialReference.create(4326), GeodeticCurveType.Geodesic, null); - assertEquals(10001.96572931 * 1000 * 2 + 111319.4907932264, length, 14); - - Polygon polygon = new Polygon(); - polygon.startPath(1,90); - polygon.lineTo(1, 0); - polygon.lineTo(0, 0); - polygon.lineTo(0,90); - length = OperatorGeodeticLength.local().execute(polygon, SpatialReference.create(4326), GeodeticCurveType.Geodesic, null); - assertEquals(10001.96572931 * 1000 * 2 + 111319.4907932264, length, 14); - - - polygon = new Polygon(); - polygon.startPath(10,90); - polygon.lineTo(10, 0); - polygon.lineTo(0, 0); - polygon.lineTo(0,90); - polygon.closeAllPaths(); - length = OperatorGeodeticLength.local().execute(polygon, SpatialReference.create(4326), GeodeticCurveType.Geodesic, null); - assertEquals(2.11171263665557E7, length, 14); - - polygon = new Polygon(); - polygon.startPath(10,90); - polygon.lineTo(10, 0); - polygon.lineTo(0, 0); - polygon.lineTo(0,90); - polygon.startPath(8, 3); - polygon.lineTo(2, 3); - polygon.lineTo(5, 80); - length = OperatorGeodeticLength.local().execute(polygon, SpatialReference.create(4326), GeodeticCurveType.Geodesic, null); - assertEquals(3.889408543061711E7, length, 14); - - } - - public void testInverse() { - SpatialReference sr = SpatialReference.create(4326); - Point point1 = new Point(0,0); - Point point2 = new Point(-1, 0); - InverseResult inverseResult = OperatorGeodeticInverse.local().execute(point1, point2, sr, sr, GeodeticCurveType.Geodesic, null); - - assertEquals(111319.4907932264, inverseResult.getDistance_m()); - assertEquals(-Math.PI / 2, inverseResult.getAz12_rad()); - assertEquals(Math.PI / 2, inverseResult.getAz21_rad()); - - point1 = new Point(179,0); - point2 = new Point(-180, 0); - inverseResult = OperatorGeodeticInverse.local().execute(point1, point2, sr, sr, GeodeticCurveType.Geodesic, null); - assertEquals(111319.4907932264, inverseResult.getDistance_m(), 14); - assertEquals(Math.PI / 2, inverseResult.getAz12_rad()); - assertEquals(-Math.PI / 2, inverseResult.getAz21_rad()); - - point2 = new Point(179,0); - point1 = new Point(-180, 0); - inverseResult = OperatorGeodeticInverse.local().execute(point1, point2, sr, sr, GeodeticCurveType.Geodesic, null); - assertEquals(111319.4907932264, inverseResult.getDistance_m(), 14); - assertEquals(-Math.PI / 2, inverseResult.getAz12_rad()); - assertEquals(Math.PI / 2, inverseResult.getAz21_rad()); - - - point1 = new Point(0,90); - point2 = new Point(0, 0); - inverseResult = OperatorGeodeticInverse.local().execute(point1, point2, sr, sr, GeodeticCurveType.Geodesic, null); - assertEquals(10001.96572931 * 1000, inverseResult.getDistance_m(), 14); - assertEquals(Math.PI, inverseResult.getAz12_rad()); - assertEquals(0, inverseResult.getAz21_rad(), 14); - - point1 = new Point(1,0); - point2 = new Point(1, 90); - inverseResult = OperatorGeodeticInverse.local().execute(point1, point2, sr, sr, GeodeticCurveType.Geodesic, null); - assertEquals(10001.96572931 * 1000, inverseResult.getDistance_m(), 14); - assertEquals(0, inverseResult.getAz12_rad(), 14); - assertEquals(Math.PI, inverseResult.getAz21_rad(), 14); - } + } + + public void testGeodeticLength() { + Polyline polyline = new Polyline(); + polyline.startPath(0, 0); + polyline.lineTo(1, 0); + double length = OperatorGeodeticLength.local().execute(polyline, SpatialReference.create(4326), GeodeticCurveType.Geodesic, null); + assertEquals(111319.4907932264, length); + + polyline = new Polyline(); + polyline.startPath(0, 0); + polyline.lineTo(-1, 0); + length = OperatorGeodeticLength.local().execute(polyline, SpatialReference.create(4326), GeodeticCurveType.Geodesic, null); + assertEquals(111319.4907932264, length); + + polyline = new Polyline(); + polyline.startPath(179, 0); + polyline.lineTo(-180, 0); + length = OperatorGeodeticLength.local().execute(polyline, SpatialReference.create(4326), GeodeticCurveType.Geodesic, null); + assertEquals(111319.4907932264, length, 14); + + polyline = new Polyline(); + polyline.startPath(-179, 0); + polyline.lineTo(-180, 0); + length = OperatorGeodeticLength.local().execute(polyline, SpatialReference.create(4326), GeodeticCurveType.Geodesic, null); + assertEquals(111319.4907932264, length, 14); + + polyline = new Polyline(); + polyline.startPath(179, 0); + polyline.lineTo(180, 0); + length = OperatorGeodeticLength.local().execute(polyline, SpatialReference.create(4326), GeodeticCurveType.Geodesic, null); + assertEquals(111319.4907932264, length, 14); + + polyline = new Polyline(); + polyline.startPath(180, 0); + polyline.lineTo(179, 0); + length = OperatorGeodeticLength.local().execute(polyline, SpatialReference.create(4326), GeodeticCurveType.Geodesic, null); + assertEquals(111319.4907932264, length, 14); + + polyline = new Polyline(); + polyline.startPath(180, 0); + polyline.lineTo(177, 0); + length = OperatorGeodeticLength.local().execute(polyline, SpatialReference.create(4326), GeodeticCurveType.Geodesic, null); + assertEquals(3 * 111319.4907932264, length, 14); + + polyline = new Polyline(); + polyline.startPath(0, 90); + polyline.lineTo(0, 0); + length = OperatorGeodeticLength.local().execute(polyline, SpatialReference.create(4326), GeodeticCurveType.Geodesic, null); + assertEquals(10001.96572931 * 1000, length, 14); + + polyline = new Polyline(); + polyline.startPath(1, 0); + polyline.lineTo(1, 90); + length = OperatorGeodeticLength.local().execute(polyline, SpatialReference.create(4326), GeodeticCurveType.Geodesic, null); + assertEquals(10001.96572931 * 1000, length, 14); + + polyline = new Polyline(); + polyline.startPath(1, 90); + polyline.lineTo(1, 0); + polyline.lineTo(0, 0); + polyline.lineTo(0, 90); + length = OperatorGeodeticLength.local().execute(polyline, SpatialReference.create(4326), GeodeticCurveType.Geodesic, null); + assertEquals(10001.96572931 * 1000 * 2 + 111319.4907932264, length, 14); + + Polygon polygon = new Polygon(); + polygon.startPath(1, 90); + polygon.lineTo(1, 0); + polygon.lineTo(0, 0); + polygon.lineTo(0, 90); + length = OperatorGeodeticLength.local().execute(polygon, SpatialReference.create(4326), GeodeticCurveType.Geodesic, null); + assertEquals(10001.96572931 * 1000 * 2 + 111319.4907932264, length, 14); + + + polygon = new Polygon(); + polygon.startPath(10, 90); + polygon.lineTo(10, 0); + polygon.lineTo(0, 0); + polygon.lineTo(0, 90); + polygon.closeAllPaths(); + length = OperatorGeodeticLength.local().execute(polygon, SpatialReference.create(4326), GeodeticCurveType.Geodesic, null); + assertEquals(2.11171263665557E7, length, 14); + + polygon = new Polygon(); + polygon.startPath(10, 90); + polygon.lineTo(10, 0); + polygon.lineTo(0, 0); + polygon.lineTo(0, 90); + polygon.startPath(8, 3); + polygon.lineTo(2, 3); + polygon.lineTo(5, 80); + length = OperatorGeodeticLength.local().execute(polygon, SpatialReference.create(4326), GeodeticCurveType.Geodesic, null); + assertEquals(3.889408543061711E7, length, 14); + + } + + public void testInverse() { + SpatialReference sr = SpatialReference.create(4326); + Point point1 = new Point(0, 0); + Point point2 = new Point(-1, 0); + InverseResult inverseResult = OperatorGeodeticInverse.local().execute(point1, point2, sr, sr, GeodeticCurveType.Geodesic, null); + + assertEquals(111319.4907932264, inverseResult.getDistance_m()); + assertEquals(-Math.PI / 2, inverseResult.getAz12_rad()); + assertEquals(Math.PI / 2, inverseResult.getAz21_rad()); + + point1 = new Point(179, 0); + point2 = new Point(-180, 0); + inverseResult = OperatorGeodeticInverse.local().execute(point1, point2, sr, sr, GeodeticCurveType.Geodesic, null); + assertEquals(111319.4907932264, inverseResult.getDistance_m(), 14); + assertEquals(Math.PI / 2, inverseResult.getAz12_rad()); + assertEquals(-Math.PI / 2, inverseResult.getAz21_rad()); + + point2 = new Point(179, 0); + point1 = new Point(-180, 0); + inverseResult = OperatorGeodeticInverse.local().execute(point1, point2, sr, sr, GeodeticCurveType.Geodesic, null); + assertEquals(111319.4907932264, inverseResult.getDistance_m(), 14); + assertEquals(-Math.PI / 2, inverseResult.getAz12_rad()); + assertEquals(Math.PI / 2, inverseResult.getAz21_rad()); + + + point1 = new Point(0, 90); + point2 = new Point(0, 0); + inverseResult = OperatorGeodeticInverse.local().execute(point1, point2, sr, sr, GeodeticCurveType.Geodesic, null); + assertEquals(10001.96572931 * 1000, inverseResult.getDistance_m(), 14); + assertEquals(Math.PI, inverseResult.getAz12_rad()); + assertEquals(0, inverseResult.getAz21_rad(), 14); + + point1 = new Point(1, 0); + point2 = new Point(1, 90); + inverseResult = OperatorGeodeticInverse.local().execute(point1, point2, sr, sr, GeodeticCurveType.Geodesic, null); + assertEquals(10001.96572931 * 1000, inverseResult.getDistance_m(), 14); + assertEquals(0, inverseResult.getAz12_rad(), 14); + assertEquals(Math.PI, inverseResult.getAz21_rad(), 14); + } } diff --git a/src/test/java/com/esri/core/geometry/TestGeomToGeoJson.java b/src/test/java/com/esri/core/geometry/TestGeomToGeoJson.java index 2700ff1a..1202e973 100644 --- a/src/test/java/com/esri/core/geometry/TestGeomToGeoJson.java +++ b/src/test/java/com/esri/core/geometry/TestGeomToGeoJson.java @@ -33,456 +33,456 @@ import java.util.List; public class TestGeomToGeoJson extends TestCase { - OperatorFactoryLocal factory = OperatorFactoryLocal.getInstance(); - - @Override - protected void setUp() throws Exception { - super.setUp(); - } - - @Override - protected void tearDown() throws Exception { - super.tearDown(); - } - - @Test - public void testPoint() { - Point p = new Point(10.0, 20.0); - OperatorExportToGeoJson exporter = (OperatorExportToGeoJson) factory.getOperator(Operator.Type.ExportToGeoJson); - String result = exporter.execute(p); - assertEquals("{\"type\":\"Point\",\"coordinates\":[10,20]}", result); - } - - @Test - public void testEmptyPoint() { - Point p = new Point(); - OperatorExportToGeoJson exporter = (OperatorExportToGeoJson) factory.getOperator(Operator.Type.ExportToGeoJson); - String result = exporter.execute(p); - assertEquals("{\"type\":\"Point\",\"coordinates\":[]}", result); - } - - @Test - public void testPointGeometryEngine() { - Point p = new Point(10.0, 20.0); - String result = GeometryEngine.geometryToGeoJson(p); - assertEquals("{\"type\":\"Point\",\"coordinates\":[10,20]}", result); - } - - @Test - public void testOGCPoint() { - Point p = new Point(10.0, 20.0); - OGCGeometry ogcPoint = new OGCPoint(p, null); - String result = ogcPoint.asGeoJson(); - assertEquals("{\"type\":\"Point\",\"coordinates\":[10,20],\"crs\":null}", result); - } - - @Test - public void testMultiPoint() { - MultiPoint mp = new MultiPoint(); - mp.add(10.0, 20.0); - mp.add(20.0, 30.0); - OperatorExportToGeoJson exporter = (OperatorExportToGeoJson) factory.getOperator(Operator.Type.ExportToGeoJson); - String result = exporter.execute(mp); - assertEquals("{\"type\":\"MultiPoint\",\"coordinates\":[[10,20],[20,30]]}", result); - } - - @Test - public void testEmptyMultiPoint() { - MultiPoint mp = new MultiPoint(); - OperatorExportToGeoJson exporter = (OperatorExportToGeoJson) factory.getOperator(Operator.Type.ExportToGeoJson); - String result = exporter.execute(mp); - assertEquals("{\"type\":\"MultiPoint\",\"coordinates\":[]}", result); - } - - @Test - public void testMultiPointGeometryEngine() { - MultiPoint mp = new MultiPoint(); - mp.add(10.0, 20.0); - mp.add(20.0, 30.0); - String result = GeometryEngine.geometryToGeoJson(mp); - assertEquals("{\"type\":\"MultiPoint\",\"coordinates\":[[10,20],[20,30]]}", result); - } - - @Test - public void testOGCMultiPoint() { - MultiPoint mp = new MultiPoint(); - mp.add(10.0, 20.0); - mp.add(20.0, 30.0); - OGCMultiPoint ogcMultiPoint = new OGCMultiPoint(mp, null); - String result = ogcMultiPoint.asGeoJson(); - assertEquals("{\"type\":\"MultiPoint\",\"coordinates\":[[10,20],[20,30]],\"crs\":null}", result); - } - - @Test - public void testPolyline() { - Polyline p = new Polyline(); - p.startPath(100.0, 0.0); - p.lineTo(101.0, 0.0); - p.lineTo(101.0, 1.0); - p.lineTo(100.0, 1.0); - OperatorExportToGeoJson exporter = (OperatorExportToGeoJson) factory.getOperator(Operator.Type.ExportToGeoJson); - String result = exporter.execute(p); - assertEquals("{\"type\":\"LineString\",\"coordinates\":[[100,0],[101,0],[101,1],[100,1]]}", result); - } - - @Test - public void testEmptyPolyline() { - Polyline p = new Polyline(); - OperatorExportToGeoJson exporter = (OperatorExportToGeoJson) factory.getOperator(Operator.Type.ExportToGeoJson); - String result = exporter.execute(p); - assertEquals("{\"type\":\"LineString\",\"coordinates\":[]}", result); - } - - @Test - public void testPolylineGeometryEngine() { - Polyline p = new Polyline(); - p.startPath(100.0, 0.0); - p.lineTo(101.0, 0.0); - p.lineTo(101.0, 1.0); - p.lineTo(100.0, 1.0); - String result = GeometryEngine.geometryToGeoJson(p); - assertEquals("{\"type\":\"LineString\",\"coordinates\":[[100,0],[101,0],[101,1],[100,1]]}", result); - } - - @Test - public void testOGCLineString() { - Polyline p = new Polyline(); - p.startPath(100.0, 0.0); - p.lineTo(101.0, 0.0); - p.lineTo(101.0, 1.0); - p.lineTo(100.0, 1.0); - OGCLineString ogcLineString = new OGCLineString(p, 0, null); - String result = ogcLineString.asGeoJson(); - assertEquals("{\"type\":\"LineString\",\"coordinates\":[[100,0],[101,0],[101,1],[100,1]],\"crs\":null}", result); - } - - @Test - public void testPolygon() { - Polygon p = new Polygon(); - p.startPath(100.0, 0.0); - p.lineTo(101.0, 0.0); - p.lineTo(101.0, 1.0); - p.lineTo(100.0, 1.0); - p.closePathWithLine(); - OperatorExportToGeoJson exporter = (OperatorExportToGeoJson) factory.getOperator(Operator.Type.ExportToGeoJson); - String result = exporter.execute(p); - assertEquals("{\"type\":\"Polygon\",\"coordinates\":[[[100,0],[100,1],[101,1],[101,0],[100,0]]]}", result); - } - - @Test - public void testPolygonWithHole() { - Polygon p = new Polygon(); - - //exterior ring - has to be clockwise for Esri - p.startPath(100.0, 0.0); - p.lineTo(100.0, 1.0); - p.lineTo(101.0, 1.0); - p.lineTo(101.0, 0.0); - p.closePathWithLine(); - - //hole - counterclockwise for Esri - p.startPath(100.2, 0.2); - p.lineTo(100.8, 0.2); - p.lineTo(100.8, 0.8); - p.lineTo(100.2, 0.8); - p.closePathWithLine(); - - OperatorExportToGeoJson exporter = (OperatorExportToGeoJson) factory.getOperator(Operator.Type.ExportToGeoJson); - String result = exporter.execute(p); - assertEquals("{\"type\":\"Polygon\",\"coordinates\":[[[100,0],[101,0],[101,1],[100,1],[100,0]],[[100.2,0.2],[100.2,0.8],[100.8,0.8],[100.8,0.2],[100.2,0.2]]]}", result); - } - - @Test - public void testPolygonWithHoleReversed() { - Polygon p = new Polygon(); - - //exterior ring - has to be clockwise for Esri - p.startPath(100.0, 0.0); - p.lineTo(100.0, 1.0); - p.lineTo(101.0, 1.0); - p.lineTo(101.0, 0.0); - p.closePathWithLine(); - - //hole - counterclockwise for Esri - p.startPath(100.2, 0.2); - p.lineTo(100.8, 0.2); - p.lineTo(100.8, 0.8); - p.lineTo(100.2, 0.8); - p.closePathWithLine(); - - p.reverseAllPaths();//make it reversed. Exterior ring - ccw, hole - cw. - - OperatorExportToGeoJson exporter = (OperatorExportToGeoJson) factory.getOperator(Operator.Type.ExportToGeoJson); - String result = exporter.execute(p); - assertEquals("{\"type\":\"Polygon\",\"coordinates\":[[[100,0],[100,1],[101,1],[101,0],[100,0]],[[100.2,0.2],[100.8,0.2],[100.8,0.8],[100.2,0.8],[100.2,0.2]]]}", result); - // TODO make a pull request on this bug - // OperatorImportFromGeoJson importer = (OperatorImportFromGeoJson) factory.getOperator(Operator.Type.ImportFromGeoJson); - // MapGeometry resultGeom = importer.execute(GeoJsonImportFlags.geoJsonImportSkipCRS, Geometry.Type.Unknown, result, null); - // assertTrue(resultGeom.m_geometry.equals(p)); - } - - @Test - public void testMultiPolygon() throws IOException { - JsonFactory jsonFactory = new JsonFactory(); - - //String geoJsonPolygon = "{\"type\":\"MultiPolygon\",\"coordinates\":[[[[-100,-100],[-100,100],[100,100],[100,-100],[-100,-100]],[[-90,-90],[90,90],[-90,90],[90,-90],[-90,-90]]],[[[-10.0,-10.0],[-10.0,10.0],[10.0,10.0],[10.0,-10.0],[-10.0,-10.0]]]]}"; - String esriJsonPolygon = "{\"rings\": [[[-100, -100], [-100, 100], [100, 100], [100, -100], [-100, -100]], [[-90, -90], [90, 90], [-90, 90], [90, -90], [-90, -90]], [[-10, -10], [-10, 10], [10, 10], [10, -10], [-10, -10]]]}"; - - JsonParser parser = jsonFactory.createParser(esriJsonPolygon); - MapGeometry parsedPoly = GeometryEngine.jsonToGeometry(parser); - //MapGeometry parsedPoly = GeometryEngine.geometryFromGeoJson(jsonPolygon, 0, Geometry.Type.Polygon); - - Polygon poly = (Polygon) parsedPoly.getGeometry(); - - OperatorExportToGeoJson exporter = (OperatorExportToGeoJson) factory.getOperator(Operator.Type.ExportToGeoJson); - //String result = exporter.execute(parsedPoly.getGeometry()); - String result = exporter.execute(poly); - assertEquals("{\"type\":\"MultiPolygon\",\"coordinates\":[[[[-100,-100],[100,-100],[100,100],[-100,100],[-100,-100]],[[-90,-90],[90,-90],[-90,90],[90,90],[-90,-90]]],[[[-10,-10],[10,-10],[10,10],[-10,10],[-10,-10]]]]}", result); - } - - @Test - public void testMultiPolygonCursor() throws IOException { - Polygon p = new Polygon(); - - //exterior ring - has to be clockwise for Esri - p.startPath(100.0, 0.0); - p.lineTo(100.0, 1.0); - p.lineTo(101.0, 1.0); - p.lineTo(101.0, 0.0); - p.closePathWithLine(); - - //hole - counterclockwise for Esri - p.startPath(100.2, 0.2); - p.lineTo(100.8, 0.2); - p.lineTo(100.8, 0.8); - p.lineTo(100.2, 0.8); - p.closePathWithLine(); - - SimpleGeometryCursor simpleGeometryCursor = new SimpleGeometryCursor(p); - OperatorExportToGeoJsonCursor exportToGeoJsonCursor = new OperatorExportToGeoJsonCursor(GeoJsonExportFlags.geoJsonExportSkipCRS, null, simpleGeometryCursor); - String result = exportToGeoJsonCursor.next(); - assertEquals("{\"type\":\"Polygon\",\"coordinates\":[[[100,0],[101,0],[101,1],[100,1],[100,0]],[[100.2,0.2],[100.2,0.8],[100.8,0.8],[100.8,0.2],[100.2,0.2]]]}", result); - - SimpleStringCursor simpleStringCursor = new SimpleStringCursor(result); - - OperatorImportFromGeoJsonCursor importFromGeoJsonCursor = new OperatorImportFromGeoJsonCursor(GeoJsonImportFlags.geoJsonImportSkipCRS, simpleStringCursor, null); - MapGeometry mapGeometry = importFromGeoJsonCursor.next(); - - assertTrue(p.equals(mapGeometry.m_geometry)); - } - - - @Test - public void testEmptyPolygon() { - Polygon p = new Polygon(); - OperatorExportToGeoJson exporter = (OperatorExportToGeoJson) factory.getOperator(Operator.Type.ExportToGeoJson); - String result = exporter.execute(p); - assertEquals("{\"type\":\"Polygon\",\"coordinates\":[]}", result); - - MapGeometry imported = OperatorImportFromGeoJson.local().execute(0, Geometry.Type.Unknown, result, null); - assertTrue(imported.getGeometry().isEmpty()); - assertTrue(imported.getGeometry().getType() == Geometry.Type.Polygon); - } - - @Test - public void testPolygonGeometryEngine() { - Polygon p = new Polygon(); - p.startPath(100.0, 0.0); - p.lineTo(101.0, 0.0); - p.lineTo(101.0, 1.0); - p.lineTo(100.0, 1.0); - p.closePathWithLine(); - String result = GeometryEngine.geometryToGeoJson(p); - assertEquals("{\"type\":\"Polygon\",\"coordinates\":[[[100,0],[100,1],[101,1],[101,0],[100,0]]]}", result); - } - - @Test - public void testOGCPolygon() { - Polygon p = new Polygon(); - p.startPath(100.0, 0.0); - p.lineTo(101.0, 0.0); - p.lineTo(101.0, 1.0); - p.lineTo(100.0, 1.0); - p.closePathWithLine(); - OGCPolygon ogcPolygon = new OGCPolygon(p, null); - String result = ogcPolygon.asGeoJson(); - assertEquals("{\"type\":\"Polygon\",\"coordinates\":[[[100,0],[100,1],[101,1],[101,0],[100,0]]],\"crs\":null}", result); - } - - @Test - public void testPolygonWithHoleGeometryEngine() { - Polygon p = new Polygon(); - - p.startPath(100.0, 0.0);//clockwise exterior - p.lineTo(100.0, 1.0); - p.lineTo(101.0, 1.0); - p.lineTo(101.0, 0.0); - p.closePathWithLine(); - - p.startPath(100.2, 0.2);//counterclockwise hole - p.lineTo(100.8, 0.2); - p.lineTo(100.8, 0.8); - p.lineTo(100.2, 0.8); - p.closePathWithLine(); - - String result = GeometryEngine.geometryToGeoJson(p); - assertEquals("{\"type\":\"Polygon\",\"coordinates\":[[[100,0],[101,0],[101,1],[100,1],[100,0]],[[100.2,0.2],[100.2,0.8],[100.8,0.8],[100.8,0.2],[100.2,0.2]]]}", result); - } - - @Test - public void testPolylineWithTwoPaths() { - Polyline p = new Polyline(); - - p.startPath(100.0, 0.0); - p.lineTo(100.0, 1.0); - - p.startPath(100.2, 0.2); - p.lineTo(100.8, 0.2); - - String result = GeometryEngine.geometryToGeoJson(p); - assertEquals("{\"type\":\"MultiLineString\",\"coordinates\":[[[100,0],[100,1]],[[100.2,0.2],[100.8,0.2]]]}", result); - } - - @Test - public void testOGCPolygonWithHole() { - Polygon p = new Polygon(); - - p.startPath(100.0, 0.0); - p.lineTo(100.0, 1.0); - p.lineTo(101.0, 1.0); - p.lineTo(101.0, 0.0); - p.closePathWithLine(); - - p.startPath(100.2, 0.2); - p.lineTo(100.8, 0.2); - p.lineTo(100.8, 0.8); - p.lineTo(100.2, 0.8); - p.closePathWithLine(); - - OGCPolygon ogcPolygon = new OGCPolygon(p, null); - String result = ogcPolygon.asGeoJson(); - assertEquals("{\"type\":\"Polygon\",\"coordinates\":[[[100,0],[101,0],[101,1],[100,1],[100,0]],[[100.2,0.2],[100.2,0.8],[100.8,0.8],[100.8,0.2],[100.2,0.2]]],\"crs\":null}", result); - } - - @Test - public void testGeometryCollection() { - SpatialReference sr = SpatialReference.create(4326); - - StringBuilder geometrySb = new StringBuilder(); - geometrySb - .append("{\"type\" : \"GeometryCollection\", \"geometries\" : ["); - - OGCPoint point = new OGCPoint(new Point(1.0, 1.0), sr); - assertEquals("{\"x\":1,\"y\":1,\"spatialReference\":{\"wkid\":4326}}", - point.asJson()); - assertEquals( - "{\"type\":\"Point\",\"coordinates\":[1,1],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:4326\"}}}", - point.asGeoJson()); - geometrySb.append(point.asGeoJson()).append(", "); - - OGCLineString line = new OGCLineString(new Polyline( - new Point(1.0, 1.0), new Point(2.0, 2.0)), 0, sr); - assertEquals( - "{\"paths\":[[[1,1],[2,2]]],\"spatialReference\":{\"wkid\":4326}}", - line.asJson()); - assertEquals( - "{\"type\":\"LineString\",\"coordinates\":[[1,1],[2,2]],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:4326\"}}}", - line.asGeoJson()); - geometrySb.append(line.asGeoJson()).append(", "); - - Polygon p = new Polygon(); - p.startPath(1.0, 1.0); - p.lineTo(2.0, 2.0); - p.lineTo(3.0, 1.0); - p.lineTo(2.0, 0.0); - - OGCPolygon polygon = new OGCPolygon(p, sr); - assertEquals( - "{\"rings\":[[[1,1],[2,2],[3,1],[2,0],[1,1]]],\"spatialReference\":{\"wkid\":4326}}", - polygon.asJson()); - assertEquals( - "{\"type\":\"Polygon\",\"coordinates\":[[[1,1],[2,0],[3,1],[2,2],[1,1]]],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:4326\"}}}", - polygon.asGeoJson()); - geometrySb.append(polygon.asGeoJson()).append("]}"); - - List geoms = new ArrayList(3); - geoms.add(point); - geoms.add(line); - geoms.add(polygon); - OGCConcreteGeometryCollection collection = new OGCConcreteGeometryCollection( - geoms, sr); - String s2 = collection.asGeoJson(); - - assertEquals("{\"type\":\"GeometryCollection\",\"geometries\":[{\"type\":\"Point\",\"coordinates\":[1,1]},{\"type\":\"LineString\",\"coordinates\":[[1,1],[2,2]]},{\"type\":\"Polygon\",\"coordinates\":[[[1,1],[2,0],[3,1],[2,2],[1,1]]]}],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:4326\"}}}", collection.asGeoJson()); - } - - @Test - public void testEmptyGeometryCollection() { - SpatialReference sr = SpatialReference.create(4326); - OGCConcreteGeometryCollection collection = new OGCConcreteGeometryCollection( - new ArrayList(), sr); - String s2 = collection.asGeoJson(); - assertEquals( - "{\"type\":\"GeometryCollection\",\"geometries\":[],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:4326\"}}}", - collection.asGeoJson()); - } - - //Envelope is exported as a polygon (we don't support bbox, as it is not a GeoJson geometry, but simply a field)! - @Test - public void testEnvelope() { - Envelope e = new Envelope(); - e.setCoords(-180.0, -90.0, 180.0, 90.0); - String result = OperatorExportToGeoJson.local().execute(e); - assertEquals("{\"type\":\"Polygon\",\"coordinates\":[[[-180,-90],[180,-90],[180,90],[-180,90],[-180,-90]]]}", result); - } - - @Test - public void testEmptyEnvelope() { - Envelope e = new Envelope(); - String result = OperatorExportToGeoJson.local().execute(e); - assertEquals("{\"type\":\"Polygon\",\"coordinates\":[]}", result); - } - - @Test - public void testEnvelopeGeometryEngine() { - Envelope e = new Envelope(); - e.setCoords(-180.0, -90.0, 180.0, 90.0); - String result = GeometryEngine.geometryToGeoJson(e); - assertEquals("{\"type\":\"Polygon\",\"coordinates\":[[[-180,-90],[180,-90],[180,90],[-180,90],[-180,-90]]]}", result); - } - - @Test - public void testOldCRS() { - String inputStr = "{\"type\":\"Polygon\",\"coordinates\":[[[-180,-90],[180,-90],[180,90],[-180,90],[-180,-90]]], \"crs\":\"EPSG:4267\"}"; - MapGeometry mg = OperatorImportFromGeoJson.local().execute(GeoJsonImportFlags.geoJsonImportDefaults, Geometry.Type.Unknown, inputStr, null); - String result = GeometryEngine.geometryToGeoJson(mg.getSpatialReference(), mg.getGeometry()); - assertEquals("{\"type\":\"Polygon\",\"coordinates\":[[[-180,-90],[180,-90],[180,90],[-180,90],[-180,-90]]],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:4267\"}}}", result); - } - - // bbox is not supported anymore. - // @Test - // public void testEnvelope() { - // Envelope e = new Envelope(); - // e.setCoords(-180.0, -90.0, 180.0, 90.0); - // OperatorExportToGeoJson exporter = (OperatorExportToGeoJson) factory.getOperator(Operator.Type.ExportToGeoJson); - // String result = exporter.execute(e); - // assertEquals("{\"bbox\":[-180.0,-90.0,180.0,90.0]}", result); - // } - // - // @Test - // public void testEmptyEnvelope() { - // Envelope e = new Envelope(); - // OperatorExportToGeoJson exporter = (OperatorExportToGeoJson) factory.getOperator(Operator.Type.ExportToGeoJson); - // String result = exporter.execute(e); - // assertEquals("{\"bbox\":null}", result); - // } - // - // @Test - // public void testEnvelopeGeometryEngine() { - // Envelope e = new Envelope(); - // e.setCoords(-180.0, -90.0, 180.0, 90.0); - // String result = GeometryEngine.geometryToGeoJson(e); - // assertEquals("{\"bbox\":[-180.0,-90.0,180.0,90.0]}", result); - // } + OperatorFactoryLocal factory = OperatorFactoryLocal.getInstance(); + + @Override + protected void setUp() throws Exception { + super.setUp(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + } + + @Test + public void testPoint() { + Point p = new Point(10.0, 20.0); + OperatorExportToGeoJson exporter = (OperatorExportToGeoJson) factory.getOperator(Operator.Type.ExportToGeoJson); + String result = exporter.execute(p); + assertEquals("{\"type\":\"Point\",\"coordinates\":[10,20]}", result); + } + + @Test + public void testEmptyPoint() { + Point p = new Point(); + OperatorExportToGeoJson exporter = (OperatorExportToGeoJson) factory.getOperator(Operator.Type.ExportToGeoJson); + String result = exporter.execute(p); + assertEquals("{\"type\":\"Point\",\"coordinates\":[]}", result); + } + + @Test + public void testPointGeometryEngine() { + Point p = new Point(10.0, 20.0); + String result = GeometryEngine.geometryToGeoJson(p); + assertEquals("{\"type\":\"Point\",\"coordinates\":[10,20]}", result); + } + + @Test + public void testOGCPoint() { + Point p = new Point(10.0, 20.0); + OGCGeometry ogcPoint = new OGCPoint(p, null); + String result = ogcPoint.asGeoJson(); + assertEquals("{\"type\":\"Point\",\"coordinates\":[10,20],\"crs\":null}", result); + } + + @Test + public void testMultiPoint() { + MultiPoint mp = new MultiPoint(); + mp.add(10.0, 20.0); + mp.add(20.0, 30.0); + OperatorExportToGeoJson exporter = (OperatorExportToGeoJson) factory.getOperator(Operator.Type.ExportToGeoJson); + String result = exporter.execute(mp); + assertEquals("{\"type\":\"MultiPoint\",\"coordinates\":[[10,20],[20,30]]}", result); + } + + @Test + public void testEmptyMultiPoint() { + MultiPoint mp = new MultiPoint(); + OperatorExportToGeoJson exporter = (OperatorExportToGeoJson) factory.getOperator(Operator.Type.ExportToGeoJson); + String result = exporter.execute(mp); + assertEquals("{\"type\":\"MultiPoint\",\"coordinates\":[]}", result); + } + + @Test + public void testMultiPointGeometryEngine() { + MultiPoint mp = new MultiPoint(); + mp.add(10.0, 20.0); + mp.add(20.0, 30.0); + String result = GeometryEngine.geometryToGeoJson(mp); + assertEquals("{\"type\":\"MultiPoint\",\"coordinates\":[[10,20],[20,30]]}", result); + } + + @Test + public void testOGCMultiPoint() { + MultiPoint mp = new MultiPoint(); + mp.add(10.0, 20.0); + mp.add(20.0, 30.0); + OGCMultiPoint ogcMultiPoint = new OGCMultiPoint(mp, null); + String result = ogcMultiPoint.asGeoJson(); + assertEquals("{\"type\":\"MultiPoint\",\"coordinates\":[[10,20],[20,30]],\"crs\":null}", result); + } + + @Test + public void testPolyline() { + Polyline p = new Polyline(); + p.startPath(100.0, 0.0); + p.lineTo(101.0, 0.0); + p.lineTo(101.0, 1.0); + p.lineTo(100.0, 1.0); + OperatorExportToGeoJson exporter = (OperatorExportToGeoJson) factory.getOperator(Operator.Type.ExportToGeoJson); + String result = exporter.execute(p); + assertEquals("{\"type\":\"LineString\",\"coordinates\":[[100,0],[101,0],[101,1],[100,1]]}", result); + } + + @Test + public void testEmptyPolyline() { + Polyline p = new Polyline(); + OperatorExportToGeoJson exporter = (OperatorExportToGeoJson) factory.getOperator(Operator.Type.ExportToGeoJson); + String result = exporter.execute(p); + assertEquals("{\"type\":\"LineString\",\"coordinates\":[]}", result); + } + + @Test + public void testPolylineGeometryEngine() { + Polyline p = new Polyline(); + p.startPath(100.0, 0.0); + p.lineTo(101.0, 0.0); + p.lineTo(101.0, 1.0); + p.lineTo(100.0, 1.0); + String result = GeometryEngine.geometryToGeoJson(p); + assertEquals("{\"type\":\"LineString\",\"coordinates\":[[100,0],[101,0],[101,1],[100,1]]}", result); + } + + @Test + public void testOGCLineString() { + Polyline p = new Polyline(); + p.startPath(100.0, 0.0); + p.lineTo(101.0, 0.0); + p.lineTo(101.0, 1.0); + p.lineTo(100.0, 1.0); + OGCLineString ogcLineString = new OGCLineString(p, 0, null); + String result = ogcLineString.asGeoJson(); + assertEquals("{\"type\":\"LineString\",\"coordinates\":[[100,0],[101,0],[101,1],[100,1]],\"crs\":null}", result); + } + + @Test + public void testPolygon() { + Polygon p = new Polygon(); + p.startPath(100.0, 0.0); + p.lineTo(101.0, 0.0); + p.lineTo(101.0, 1.0); + p.lineTo(100.0, 1.0); + p.closePathWithLine(); + OperatorExportToGeoJson exporter = (OperatorExportToGeoJson) factory.getOperator(Operator.Type.ExportToGeoJson); + String result = exporter.execute(p); + assertEquals("{\"type\":\"Polygon\",\"coordinates\":[[[100,0],[100,1],[101,1],[101,0],[100,0]]]}", result); + } + + @Test + public void testPolygonWithHole() { + Polygon p = new Polygon(); + + //exterior ring - has to be clockwise for Esri + p.startPath(100.0, 0.0); + p.lineTo(100.0, 1.0); + p.lineTo(101.0, 1.0); + p.lineTo(101.0, 0.0); + p.closePathWithLine(); + + //hole - counterclockwise for Esri + p.startPath(100.2, 0.2); + p.lineTo(100.8, 0.2); + p.lineTo(100.8, 0.8); + p.lineTo(100.2, 0.8); + p.closePathWithLine(); + + OperatorExportToGeoJson exporter = (OperatorExportToGeoJson) factory.getOperator(Operator.Type.ExportToGeoJson); + String result = exporter.execute(p); + assertEquals("{\"type\":\"Polygon\",\"coordinates\":[[[100,0],[101,0],[101,1],[100,1],[100,0]],[[100.2,0.2],[100.2,0.8],[100.8,0.8],[100.8,0.2],[100.2,0.2]]]}", result); + } + + @Test + public void testPolygonWithHoleReversed() { + Polygon p = new Polygon(); + + //exterior ring - has to be clockwise for Esri + p.startPath(100.0, 0.0); + p.lineTo(100.0, 1.0); + p.lineTo(101.0, 1.0); + p.lineTo(101.0, 0.0); + p.closePathWithLine(); + + //hole - counterclockwise for Esri + p.startPath(100.2, 0.2); + p.lineTo(100.8, 0.2); + p.lineTo(100.8, 0.8); + p.lineTo(100.2, 0.8); + p.closePathWithLine(); + + p.reverseAllPaths();//make it reversed. Exterior ring - ccw, hole - cw. + + OperatorExportToGeoJson exporter = (OperatorExportToGeoJson) factory.getOperator(Operator.Type.ExportToGeoJson); + String result = exporter.execute(p); + assertEquals("{\"type\":\"Polygon\",\"coordinates\":[[[100,0],[100,1],[101,1],[101,0],[100,0]],[[100.2,0.2],[100.8,0.2],[100.8,0.8],[100.2,0.8],[100.2,0.2]]]}", result); + // TODO make a pull request on this bug + // OperatorImportFromGeoJson importer = (OperatorImportFromGeoJson) factory.getOperator(Operator.Type.ImportFromGeoJson); + // MapGeometry resultGeom = importer.execute(GeoJsonImportFlags.geoJsonImportSkipCRS, Geometry.Type.Unknown, result, null); + // assertTrue(resultGeom.m_geometry.equals(p)); + } + + @Test + public void testMultiPolygon() throws IOException { + JsonFactory jsonFactory = new JsonFactory(); + + //String geoJsonPolygon = "{\"type\":\"MultiPolygon\",\"coordinates\":[[[[-100,-100],[-100,100],[100,100],[100,-100],[-100,-100]],[[-90,-90],[90,90],[-90,90],[90,-90],[-90,-90]]],[[[-10.0,-10.0],[-10.0,10.0],[10.0,10.0],[10.0,-10.0],[-10.0,-10.0]]]]}"; + String esriJsonPolygon = "{\"rings\": [[[-100, -100], [-100, 100], [100, 100], [100, -100], [-100, -100]], [[-90, -90], [90, 90], [-90, 90], [90, -90], [-90, -90]], [[-10, -10], [-10, 10], [10, 10], [10, -10], [-10, -10]]]}"; + + JsonParser parser = jsonFactory.createParser(esriJsonPolygon); + MapGeometry parsedPoly = GeometryEngine.jsonToGeometry(parser); + //MapGeometry parsedPoly = GeometryEngine.geometryFromGeoJson(jsonPolygon, 0, Geometry.Type.Polygon); + + Polygon poly = (Polygon) parsedPoly.getGeometry(); + + OperatorExportToGeoJson exporter = (OperatorExportToGeoJson) factory.getOperator(Operator.Type.ExportToGeoJson); + //String result = exporter.execute(parsedPoly.getGeometry()); + String result = exporter.execute(poly); + assertEquals("{\"type\":\"MultiPolygon\",\"coordinates\":[[[[-100,-100],[100,-100],[100,100],[-100,100],[-100,-100]],[[-90,-90],[90,-90],[-90,90],[90,90],[-90,-90]]],[[[-10,-10],[10,-10],[10,10],[-10,10],[-10,-10]]]]}", result); + } + + @Test + public void testMultiPolygonCursor() throws IOException { + Polygon p = new Polygon(); + + //exterior ring - has to be clockwise for Esri + p.startPath(100.0, 0.0); + p.lineTo(100.0, 1.0); + p.lineTo(101.0, 1.0); + p.lineTo(101.0, 0.0); + p.closePathWithLine(); + + //hole - counterclockwise for Esri + p.startPath(100.2, 0.2); + p.lineTo(100.8, 0.2); + p.lineTo(100.8, 0.8); + p.lineTo(100.2, 0.8); + p.closePathWithLine(); + + SimpleGeometryCursor simpleGeometryCursor = new SimpleGeometryCursor(p); + OperatorExportToGeoJsonCursor exportToGeoJsonCursor = new OperatorExportToGeoJsonCursor(GeoJsonExportFlags.geoJsonExportSkipCRS, null, simpleGeometryCursor); + String result = exportToGeoJsonCursor.next(); + assertEquals("{\"type\":\"Polygon\",\"coordinates\":[[[100,0],[101,0],[101,1],[100,1],[100,0]],[[100.2,0.2],[100.2,0.8],[100.8,0.8],[100.8,0.2],[100.2,0.2]]]}", result); + + SimpleStringCursor simpleStringCursor = new SimpleStringCursor(result); + + OperatorImportFromGeoJsonCursor importFromGeoJsonCursor = new OperatorImportFromGeoJsonCursor(GeoJsonImportFlags.geoJsonImportSkipCRS, simpleStringCursor, null); + MapGeometry mapGeometry = importFromGeoJsonCursor.next(); + + assertTrue(p.equals(mapGeometry.m_geometry)); + } + + + @Test + public void testEmptyPolygon() { + Polygon p = new Polygon(); + OperatorExportToGeoJson exporter = (OperatorExportToGeoJson) factory.getOperator(Operator.Type.ExportToGeoJson); + String result = exporter.execute(p); + assertEquals("{\"type\":\"Polygon\",\"coordinates\":[]}", result); + + MapGeometry imported = OperatorImportFromGeoJson.local().execute(0, Geometry.Type.Unknown, result, null); + assertTrue(imported.getGeometry().isEmpty()); + assertTrue(imported.getGeometry().getType() == Geometry.Type.Polygon); + } + + @Test + public void testPolygonGeometryEngine() { + Polygon p = new Polygon(); + p.startPath(100.0, 0.0); + p.lineTo(101.0, 0.0); + p.lineTo(101.0, 1.0); + p.lineTo(100.0, 1.0); + p.closePathWithLine(); + String result = GeometryEngine.geometryToGeoJson(p); + assertEquals("{\"type\":\"Polygon\",\"coordinates\":[[[100,0],[100,1],[101,1],[101,0],[100,0]]]}", result); + } + + @Test + public void testOGCPolygon() { + Polygon p = new Polygon(); + p.startPath(100.0, 0.0); + p.lineTo(101.0, 0.0); + p.lineTo(101.0, 1.0); + p.lineTo(100.0, 1.0); + p.closePathWithLine(); + OGCPolygon ogcPolygon = new OGCPolygon(p, null); + String result = ogcPolygon.asGeoJson(); + assertEquals("{\"type\":\"Polygon\",\"coordinates\":[[[100,0],[100,1],[101,1],[101,0],[100,0]]],\"crs\":null}", result); + } + + @Test + public void testPolygonWithHoleGeometryEngine() { + Polygon p = new Polygon(); + + p.startPath(100.0, 0.0);//clockwise exterior + p.lineTo(100.0, 1.0); + p.lineTo(101.0, 1.0); + p.lineTo(101.0, 0.0); + p.closePathWithLine(); + + p.startPath(100.2, 0.2);//counterclockwise hole + p.lineTo(100.8, 0.2); + p.lineTo(100.8, 0.8); + p.lineTo(100.2, 0.8); + p.closePathWithLine(); + + String result = GeometryEngine.geometryToGeoJson(p); + assertEquals("{\"type\":\"Polygon\",\"coordinates\":[[[100,0],[101,0],[101,1],[100,1],[100,0]],[[100.2,0.2],[100.2,0.8],[100.8,0.8],[100.8,0.2],[100.2,0.2]]]}", result); + } + + @Test + public void testPolylineWithTwoPaths() { + Polyline p = new Polyline(); + + p.startPath(100.0, 0.0); + p.lineTo(100.0, 1.0); + + p.startPath(100.2, 0.2); + p.lineTo(100.8, 0.2); + + String result = GeometryEngine.geometryToGeoJson(p); + assertEquals("{\"type\":\"MultiLineString\",\"coordinates\":[[[100,0],[100,1]],[[100.2,0.2],[100.8,0.2]]]}", result); + } + + @Test + public void testOGCPolygonWithHole() { + Polygon p = new Polygon(); + + p.startPath(100.0, 0.0); + p.lineTo(100.0, 1.0); + p.lineTo(101.0, 1.0); + p.lineTo(101.0, 0.0); + p.closePathWithLine(); + + p.startPath(100.2, 0.2); + p.lineTo(100.8, 0.2); + p.lineTo(100.8, 0.8); + p.lineTo(100.2, 0.8); + p.closePathWithLine(); + + OGCPolygon ogcPolygon = new OGCPolygon(p, null); + String result = ogcPolygon.asGeoJson(); + assertEquals("{\"type\":\"Polygon\",\"coordinates\":[[[100,0],[101,0],[101,1],[100,1],[100,0]],[[100.2,0.2],[100.2,0.8],[100.8,0.8],[100.8,0.2],[100.2,0.2]]],\"crs\":null}", result); + } + + @Test + public void testGeometryCollection() { + SpatialReference sr = SpatialReference.create(4326); + + StringBuilder geometrySb = new StringBuilder(); + geometrySb + .append("{\"type\" : \"GeometryCollection\", \"geometries\" : ["); + + OGCPoint point = new OGCPoint(new Point(1.0, 1.0), sr); + assertEquals("{\"x\":1,\"y\":1,\"spatialReference\":{\"wkid\":4326}}", + point.asJson()); + assertEquals( + "{\"type\":\"Point\",\"coordinates\":[1,1],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:4326\"}}}", + point.asGeoJson()); + geometrySb.append(point.asGeoJson()).append(", "); + + OGCLineString line = new OGCLineString(new Polyline( + new Point(1.0, 1.0), new Point(2.0, 2.0)), 0, sr); + assertEquals( + "{\"paths\":[[[1,1],[2,2]]],\"spatialReference\":{\"wkid\":4326}}", + line.asJson()); + assertEquals( + "{\"type\":\"LineString\",\"coordinates\":[[1,1],[2,2]],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:4326\"}}}", + line.asGeoJson()); + geometrySb.append(line.asGeoJson()).append(", "); + + Polygon p = new Polygon(); + p.startPath(1.0, 1.0); + p.lineTo(2.0, 2.0); + p.lineTo(3.0, 1.0); + p.lineTo(2.0, 0.0); + + OGCPolygon polygon = new OGCPolygon(p, sr); + assertEquals( + "{\"rings\":[[[1,1],[2,2],[3,1],[2,0],[1,1]]],\"spatialReference\":{\"wkid\":4326}}", + polygon.asJson()); + assertEquals( + "{\"type\":\"Polygon\",\"coordinates\":[[[1,1],[2,0],[3,1],[2,2],[1,1]]],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:4326\"}}}", + polygon.asGeoJson()); + geometrySb.append(polygon.asGeoJson()).append("]}"); + + List geoms = new ArrayList(3); + geoms.add(point); + geoms.add(line); + geoms.add(polygon); + OGCConcreteGeometryCollection collection = new OGCConcreteGeometryCollection( + geoms, sr); + String s2 = collection.asGeoJson(); + + assertEquals("{\"type\":\"GeometryCollection\",\"geometries\":[{\"type\":\"Point\",\"coordinates\":[1,1]},{\"type\":\"LineString\",\"coordinates\":[[1,1],[2,2]]},{\"type\":\"Polygon\",\"coordinates\":[[[1,1],[2,0],[3,1],[2,2],[1,1]]]}],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:4326\"}}}", collection.asGeoJson()); + } + + @Test + public void testEmptyGeometryCollection() { + SpatialReference sr = SpatialReference.create(4326); + OGCConcreteGeometryCollection collection = new OGCConcreteGeometryCollection( + new ArrayList(), sr); + String s2 = collection.asGeoJson(); + assertEquals( + "{\"type\":\"GeometryCollection\",\"geometries\":[],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:4326\"}}}", + collection.asGeoJson()); + } + + //Envelope is exported as a polygon (we don't support bbox, as it is not a GeoJson geometry, but simply a field)! + @Test + public void testEnvelope() { + Envelope e = new Envelope(); + e.setCoords(-180.0, -90.0, 180.0, 90.0); + String result = OperatorExportToGeoJson.local().execute(e); + assertEquals("{\"type\":\"Polygon\",\"coordinates\":[[[-180,-90],[180,-90],[180,90],[-180,90],[-180,-90]]]}", result); + } + + @Test + public void testEmptyEnvelope() { + Envelope e = new Envelope(); + String result = OperatorExportToGeoJson.local().execute(e); + assertEquals("{\"type\":\"Polygon\",\"coordinates\":[]}", result); + } + + @Test + public void testEnvelopeGeometryEngine() { + Envelope e = new Envelope(); + e.setCoords(-180.0, -90.0, 180.0, 90.0); + String result = GeometryEngine.geometryToGeoJson(e); + assertEquals("{\"type\":\"Polygon\",\"coordinates\":[[[-180,-90],[180,-90],[180,90],[-180,90],[-180,-90]]]}", result); + } + + @Test + public void testOldCRS() { + String inputStr = "{\"type\":\"Polygon\",\"coordinates\":[[[-180,-90],[180,-90],[180,90],[-180,90],[-180,-90]]], \"crs\":\"EPSG:4267\"}"; + MapGeometry mg = OperatorImportFromGeoJson.local().execute(GeoJsonImportFlags.geoJsonImportDefaults, Geometry.Type.Unknown, inputStr, null); + String result = GeometryEngine.geometryToGeoJson(mg.getSpatialReference(), mg.getGeometry()); + assertEquals("{\"type\":\"Polygon\",\"coordinates\":[[[-180,-90],[180,-90],[180,90],[-180,90],[-180,-90]]],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:4267\"}}}", result); + } + + // bbox is not supported anymore. + // @Test + // public void testEnvelope() { + // Envelope e = new Envelope(); + // e.setCoords(-180.0, -90.0, 180.0, 90.0); + // OperatorExportToGeoJson exporter = (OperatorExportToGeoJson) factory.getOperator(Operator.Type.ExportToGeoJson); + // String result = exporter.execute(e); + // assertEquals("{\"bbox\":[-180.0,-90.0,180.0,90.0]}", result); + // } + // + // @Test + // public void testEmptyEnvelope() { + // Envelope e = new Envelope(); + // OperatorExportToGeoJson exporter = (OperatorExportToGeoJson) factory.getOperator(Operator.Type.ExportToGeoJson); + // String result = exporter.execute(e); + // assertEquals("{\"bbox\":null}", result); + // } + // + // @Test + // public void testEnvelopeGeometryEngine() { + // Envelope e = new Envelope(); + // e.setCoords(-180.0, -90.0, 180.0, 90.0); + // String result = GeometryEngine.geometryToGeoJson(e); + // assertEquals("{\"bbox\":[-180.0,-90.0,180.0,90.0]}", result); + // } } diff --git a/src/test/java/com/esri/core/geometry/TestGeomToJSonExportSRFromWkiOrWkt_CR181369.java b/src/test/java/com/esri/core/geometry/TestGeomToJSonExportSRFromWkiOrWkt_CR181369.java index 3055d990..672f033a 100644 --- a/src/test/java/com/esri/core/geometry/TestGeomToJSonExportSRFromWkiOrWkt_CR181369.java +++ b/src/test/java/com/esri/core/geometry/TestGeomToJSonExportSRFromWkiOrWkt_CR181369.java @@ -33,557 +33,557 @@ import java.io.IOException; public class TestGeomToJSonExportSRFromWkiOrWkt_CR181369 extends TestCase { - @Override - protected void setUp() throws Exception { - super.setUp(); - } - - @Override - protected void tearDown() throws Exception { - super.tearDown(); - } - - JsonFactory factory = new JsonFactory(); - SpatialReference spatialReferenceWebMerc1 = SpatialReference.create(102100); - SpatialReference spatialReferenceWebMerc2 = SpatialReference - .create(spatialReferenceWebMerc1.getLatestID()); - SpatialReference spatialReferenceWGS84 = SpatialReference.create(4326); - - @Test - public void testLocalExport() - throws JsonParseException, IOException { - String s = OperatorExportToJson.local().execute(null, new Point(1000000.2, 2000000.3)); - //assertTrue(s.contains(".")); - //assertFalse(s.contains(",")); - Polyline line = new Polyline(); - line.startPath(1.1, 2.2); - line.lineTo(2.3, 4.5); - String s1 = OperatorExportToJson.local().execute(null, line); - assertTrue(s.contains(".")); - } - - boolean testPoint() throws JsonParseException, IOException { - boolean bAnswer = true; - Point point1 = new Point(10.0, 20.0); - Point pointEmpty = new Point(); - { - JsonParser pointWebMerc1Parser = factory - .createParser(GeometryEngine.geometryToJson( - spatialReferenceWebMerc1, point1)); - MapGeometry pointWebMerc1MP = GeometryEngine - .jsonToGeometry(pointWebMerc1Parser); - assertTrue(point1.getX() == ((Point) pointWebMerc1MP.getGeometry()) - .getX()); - assertTrue(point1.getY() == ((Point) pointWebMerc1MP.getGeometry()) - .getY()); - assertTrue(spatialReferenceWebMerc1.getID() == pointWebMerc1MP - .getSpatialReference().getID() - || pointWebMerc1MP.getSpatialReference().getID() == 3857); - - if (!checkResultSpatialRef(pointWebMerc1MP, 102100, 3857)) { - bAnswer = false; - } - - pointWebMerc1Parser = factory.createParser(GeometryEngine - .geometryToJson(null, point1)); - pointWebMerc1MP = GeometryEngine - .jsonToGeometry(pointWebMerc1Parser); - assertTrue(null == pointWebMerc1MP.getSpatialReference()); - - if (pointWebMerc1MP.getSpatialReference() != null) { - if (!checkResultSpatialRef(pointWebMerc1MP, 102100, 3857)) { - bAnswer = false; - } - } - - String pointEmptyString = GeometryEngine.geometryToJson( - spatialReferenceWebMerc1, pointEmpty); - pointWebMerc1Parser = factory.createParser(pointEmptyString); - } - - JsonParser pointWebMerc2Parser = factory - .createParser(GeometryEngine.geometryToJson( - spatialReferenceWebMerc2, point1)); - MapGeometry pointWebMerc2MP = GeometryEngine - .jsonToGeometry(pointWebMerc2Parser); - assertTrue(point1.getX() == ((Point) pointWebMerc2MP.getGeometry()) - .getX()); - assertTrue(point1.getY() == ((Point) pointWebMerc2MP.getGeometry()) - .getY()); - assertTrue(spatialReferenceWebMerc2.getLatestID() == pointWebMerc2MP - .getSpatialReference().getLatestID()); - if (!checkResultSpatialRef(pointWebMerc2MP, - spatialReferenceWebMerc2.getLatestID(), 0)) { - bAnswer = false; - } - - { - JsonParser pointWgs84Parser = factory - .createParser(GeometryEngine.geometryToJson( - spatialReferenceWGS84, point1)); - MapGeometry pointWgs84MP = GeometryEngine - .jsonToGeometry(pointWgs84Parser); - assertTrue(point1.getX() == ((Point) pointWgs84MP.getGeometry()) - .getX()); - assertTrue(point1.getY() == ((Point) pointWgs84MP.getGeometry()) - .getY()); - assertTrue(spatialReferenceWGS84.getID() == pointWgs84MP - .getSpatialReference().getID()); - if (!checkResultSpatialRef(pointWgs84MP, 4326, 0)) { - bAnswer = false; - } - } - - { - Point p = new Point(); - String s = GeometryEngine.geometryToJson(spatialReferenceWebMerc1, - p); - assertTrue(s - .equals("{\"x\":null,\"y\":null,\"spatialReference\":{\"wkid\":102100,\"latestWkid\":3857}}")); - - p.addAttribute(VertexDescription.Semantics.Z); - p.addAttribute(VertexDescription.Semantics.M); - s = GeometryEngine.geometryToJson(spatialReferenceWebMerc1, p); - assertTrue(s - .equals("{\"x\":null,\"y\":null,\"z\":null,\"m\":null,\"spatialReference\":{\"wkid\":102100,\"latestWkid\":3857}}")); - - } - - { - Point p = new Point(10.0, 20.0, 30.0); - p.addAttribute(VertexDescription.Semantics.M); - String s = GeometryEngine.geometryToJson(spatialReferenceWebMerc1, - p); - assertTrue(s - .equals("{\"x\":10,\"y\":20,\"z\":30,\"m\":null,\"spatialReference\":{\"wkid\":102100,\"latestWkid\":3857}}")); - } - - {// import - String s = "{\"x\":0.0,\"y\":1.0,\"z\":5.0,\"m\":11.0,\"spatialReference\":{\"wkid\":102100,\"latestWkid\":3857}}"; - JsonParser parser = factory.createParser(s); - MapGeometry map_pt = GeometryEngine.jsonToGeometry(parser); - Point pt = (Point) map_pt.getGeometry(); - assertTrue(pt.getX() == 0.0); - assertTrue(pt.getY() == 1.0); - assertTrue(pt.getZ() == 5.0); - assertTrue(pt.getM() == 11.0); - } - - { - String s = "{\"x\" : 5.0, \"y\" : null, \"spatialReference\" : {\"wkid\" : 4326}} "; - JsonParser parser = factory.createParser(s); - MapGeometry map_pt = GeometryEngine.jsonToGeometry(parser); - Point pt = (Point) map_pt.getGeometry(); - assertTrue(pt.isEmpty()); - SpatialReference spatial_reference = map_pt.getSpatialReference(); - assertTrue(spatial_reference.getID() == 4326); - } - - return bAnswer; - } - - boolean testMultiPoint() throws JsonParseException, IOException { - boolean bAnswer = true; - - MultiPoint multiPoint1 = new MultiPoint(); - multiPoint1.add(-97.06138, 32.837); - multiPoint1.add(-97.06133, 32.836); - multiPoint1.add(-97.06124, 32.834); - multiPoint1.add(-97.06127, 32.832); - - { - String s = GeometryEngine.geometryToJson(spatialReferenceWGS84, - multiPoint1); - JsonParser mPointWgs84Parser = factory.createParser(s); - MapGeometry mPointWgs84MP = GeometryEngine - .jsonToGeometry(mPointWgs84Parser); - assertTrue(multiPoint1.getPointCount() == ((MultiPoint) mPointWgs84MP - .getGeometry()).getPointCount()); - assertTrue(multiPoint1.getPoint(0).getX() == ((MultiPoint) mPointWgs84MP - .getGeometry()).getPoint(0).getX()); - assertTrue(multiPoint1.getPoint(0).getY() == ((MultiPoint) mPointWgs84MP - .getGeometry()).getPoint(0).getY()); - int lastIndex = multiPoint1.getPointCount() - 1; - assertTrue(multiPoint1.getPoint(lastIndex).getX() == ((MultiPoint) mPointWgs84MP - .getGeometry()).getPoint(lastIndex).getX()); - assertTrue(multiPoint1.getPoint(lastIndex).getY() == ((MultiPoint) mPointWgs84MP - .getGeometry()).getPoint(lastIndex).getY()); - - assertTrue(spatialReferenceWGS84.getID() == mPointWgs84MP - .getSpatialReference().getID()); - if (!checkResultSpatialRef(mPointWgs84MP, 4326, 0)) { - bAnswer = false; - } - - } - - { - MultiPoint p = new MultiPoint(); - p.addAttribute(VertexDescription.Semantics.Z); - p.addAttribute(VertexDescription.Semantics.M); - String s = GeometryEngine.geometryToJson(spatialReferenceWebMerc1, - p); - assertTrue(s - .equals("{\"hasZ\":true,\"hasM\":true,\"points\":[],\"spatialReference\":{\"wkid\":102100,\"latestWkid\":3857}}")); - - p.add(10.0, 20.0, 30.0); - p.add(20.0, 40.0, 60.0); - s = GeometryEngine.geometryToJson(spatialReferenceWebMerc1, p); - assertTrue(s - .equals("{\"hasZ\":true,\"hasM\":true,\"points\":[[10,20,30,null],[20,40,60,null]],\"spatialReference\":{\"wkid\":102100,\"latestWkid\":3857}}")); - } - { - String points = "{\"hasM\" : false, \"hasZ\" : true, \"uncle remus\" : null, \"points\" : [ [0,0,1], [0.0,10.0,1], [10.0,10.0,1], [10.0,0.0,1, 6666] ],\"spatialReference\" : {\"wkid\" : 4326}}"; - MapGeometry mp = GeometryEngine.jsonToGeometry(factory - .createParser(points)); - MultiPoint multipoint = (MultiPoint) mp.getGeometry(); - assertTrue(multipoint.getPointCount() == 4); - Point2D point2d; - point2d = multipoint.getXY(0); - assertTrue(point2d.x == 0.0 && point2d.y == 0.0); - point2d = multipoint.getXY(1); - assertTrue(point2d.x == 0.0 && point2d.y == 10.0); - point2d = multipoint.getXY(2); - assertTrue(point2d.x == 10.0 && point2d.y == 10.0); - point2d = multipoint.getXY(3); - assertTrue(point2d.x == 10.0 && point2d.y == 0.0); - assertTrue(multipoint.hasAttribute(VertexDescription.Semantics.Z)); - assertTrue(!multipoint.hasAttribute(VertexDescription.Semantics.M)); - double z = multipoint.getAttributeAsDbl( - VertexDescription.Semantics.Z, 0, 0); - assertTrue(z == 1); - SpatialReference spatial_reference = mp.getSpatialReference(); - assertTrue(spatial_reference.getID() == 4326); - } - - return bAnswer; - } - - boolean testPolyline() throws JsonParseException, IOException { - boolean bAnswer = true; - - Polyline polyline = new Polyline(); - polyline.startPath(-97.06138, 32.837); - polyline.lineTo(-97.06133, 32.836); - polyline.lineTo(-97.06124, 32.834); - polyline.lineTo(-97.06127, 32.832); - - polyline.startPath(-97.06326, 32.759); - polyline.lineTo(-97.06298, 32.755); - - { - JsonParser polylinePathsWgs84Parser = factory - .createParser(GeometryEngine.geometryToJson( - spatialReferenceWGS84, polyline)); - MapGeometry mPolylineWGS84MP = GeometryEngine - .jsonToGeometry(polylinePathsWgs84Parser); - - assertTrue(polyline.getPointCount() == ((Polyline) mPolylineWGS84MP - .getGeometry()).getPointCount()); - assertTrue(polyline.getPoint(0).getX() == ((Polyline) mPolylineWGS84MP - .getGeometry()).getPoint(0).getX()); - assertTrue(polyline.getPoint(0).getY() == ((Polyline) mPolylineWGS84MP - .getGeometry()).getPoint(0).getY()); - - assertTrue(polyline.getPathCount() == ((Polyline) mPolylineWGS84MP - .getGeometry()).getPathCount()); - assertTrue(polyline.getSegmentCount() == ((Polyline) mPolylineWGS84MP - .getGeometry()).getSegmentCount()); - assertTrue(polyline.getSegmentCount(0) == ((Polyline) mPolylineWGS84MP - .getGeometry()).getSegmentCount(0)); - assertTrue(polyline.getSegmentCount(1) == ((Polyline) mPolylineWGS84MP - .getGeometry()).getSegmentCount(1)); - - int lastIndex = polyline.getPointCount() - 1; - assertTrue(polyline.getPoint(lastIndex).getX() == ((Polyline) mPolylineWGS84MP - .getGeometry()).getPoint(lastIndex).getX()); - assertTrue(polyline.getPoint(lastIndex).getY() == ((Polyline) mPolylineWGS84MP - .getGeometry()).getPoint(lastIndex).getY()); - - assertTrue(spatialReferenceWGS84.getID() == mPolylineWGS84MP - .getSpatialReference().getID()); - - if (!checkResultSpatialRef(mPolylineWGS84MP, 4326, 0)) { - bAnswer = false; - } - } - - { - Polyline p = new Polyline(); - p.addAttribute(VertexDescription.Semantics.Z); - p.addAttribute(VertexDescription.Semantics.M); - String s = GeometryEngine.geometryToJson(spatialReferenceWebMerc1, - p); - assertTrue(s - .equals("{\"hasZ\":true,\"hasM\":true,\"paths\":[],\"spatialReference\":{\"wkid\":102100,\"latestWkid\":3857}}")); - - p.startPath(0, 0); - p.lineTo(0, 1); - p.startPath(2, 2); - p.lineTo(3, 3); - - p.setAttribute(VertexDescription.Semantics.Z, 0, 0, 3); - p.setAttribute(VertexDescription.Semantics.M, 1, 0, 5); - s = GeometryEngine.geometryToJson(spatialReferenceWebMerc1, p); - assertTrue(s - .equals("{\"hasZ\":true,\"hasM\":true,\"paths\":[[[0,0,3,null],[0,1,0,5]],[[2,2,0,null],[3,3,0,null]]],\"spatialReference\":{\"wkid\":102100,\"latestWkid\":3857}}")); - } - - { - String paths = "{\"hasZ\" : true, \"paths\" : [ [ [0.0, 0.0,3], [0, 10.0,3], [10.0, 10.0,3, 6666], [10.0, 0.0,3, 6666] ], [ [1.0, 1,3], [1.0, 9.0,3], [9.0, 9.0,3], [1.0, 9.0,3] ] ], \"spatialReference\" : {\"wkid\" : 4326}, \"hasM\" : false}"; - MapGeometry mapGeometry = GeometryEngine.jsonToGeometry(factory - .createParser(paths)); - Polyline p = (Polyline) mapGeometry.getGeometry(); - assertTrue(p.getPathCount() == 2); - @SuppressWarnings("unused") - int count = p.getPathCount(); - assertTrue(p.getPointCount() == 8); - assertTrue(p.hasAttribute(VertexDescription.Semantics.Z)); - assertTrue(!p.hasAttribute(VertexDescription.Semantics.M)); - double z = p.getAttributeAsDbl(VertexDescription.Semantics.Z, 0, 0); - assertTrue(z == 3); - double length = p.calculateLength2D(); - assertTrue(Math.abs(length - 54.0) <= 0.001); - SpatialReference spatial_reference = mapGeometry - .getSpatialReference(); - assertTrue(spatial_reference.getID() == 4326); - } - - return bAnswer; - } - - boolean testPolygon() throws JsonParseException, IOException { - boolean bAnswer = true; - - Polygon polygon = new Polygon(); - polygon.startPath(-97.06138, 32.837); - polygon.lineTo(-97.06133, 32.836); - polygon.lineTo(-97.06124, 32.834); - polygon.lineTo(-97.06127, 32.832); - - polygon.startPath(-97.06326, 32.759); - polygon.lineTo(-97.06298, 32.755); - - { - JsonParser polygonPathsWgs84Parser = factory - .createParser(GeometryEngine.geometryToJson( - spatialReferenceWGS84, polygon)); - MapGeometry mPolygonWGS84MP = GeometryEngine - .jsonToGeometry(polygonPathsWgs84Parser); - - assertTrue(polygon.getPointCount() + 1 == ((Polygon) mPolygonWGS84MP - .getGeometry()).getPointCount()); - assertTrue(polygon.getPoint(0).getX() == ((Polygon) mPolygonWGS84MP - .getGeometry()).getPoint(0).getX()); - assertTrue(polygon.getPoint(0).getY() == ((Polygon) mPolygonWGS84MP - .getGeometry()).getPoint(0).getY()); - - assertTrue(polygon.getPathCount() == ((Polygon) mPolygonWGS84MP - .getGeometry()).getPathCount()); - assertTrue(polygon.getSegmentCount() + 1 == ((Polygon) mPolygonWGS84MP - .getGeometry()).getSegmentCount()); - assertTrue(polygon.getSegmentCount(0) == ((Polygon) mPolygonWGS84MP - .getGeometry()).getSegmentCount(0)); - assertTrue(polygon.getSegmentCount(1) + 1 == ((Polygon) mPolygonWGS84MP - .getGeometry()).getSegmentCount(1)); - - int lastIndex = polygon.getPointCount() - 1; - assertTrue(polygon.getPoint(lastIndex).getX() == ((Polygon) mPolygonWGS84MP - .getGeometry()).getPoint(lastIndex).getX()); - assertTrue(polygon.getPoint(lastIndex).getY() == ((Polygon) mPolygonWGS84MP - .getGeometry()).getPoint(lastIndex).getY()); - - assertTrue(spatialReferenceWGS84.getID() == mPolygonWGS84MP - .getSpatialReference().getID()); - - if (!checkResultSpatialRef(mPolygonWGS84MP, 4326, 0)) { - bAnswer = false; - } - } - - { - Polygon p = new Polygon(); - p.addAttribute(VertexDescription.Semantics.Z); - p.addAttribute(VertexDescription.Semantics.M); - String s = GeometryEngine.geometryToJson(spatialReferenceWebMerc1, - p); - assertTrue(s - .equals("{\"hasZ\":true,\"hasM\":true,\"rings\":[],\"spatialReference\":{\"wkid\":102100,\"latestWkid\":3857}}")); - - p.startPath(0, 0); - p.lineTo(0, 1); - p.lineTo(4, 4); - p.startPath(2, 2); - p.lineTo(3, 3); - p.lineTo(7, 8); - - p.setAttribute(VertexDescription.Semantics.Z, 0, 0, 3); - p.setAttribute(VertexDescription.Semantics.M, 1, 0, 7); - p.setAttribute(VertexDescription.Semantics.M, 2, 0, 5); - p.setAttribute(VertexDescription.Semantics.M, 5, 0, 5); - s = GeometryEngine.geometryToJson(spatialReferenceWebMerc1, p); - assertTrue(s - .equals("{\"hasZ\":true,\"hasM\":true,\"rings\":[[[0,0,3,null],[0,1,0,7],[4,4,0,5],[0,0,3,null]],[[2,2,0,null],[3,3,0,null],[7,8,0,5],[2,2,0,null]]],\"spatialReference\":{\"wkid\":102100,\"latestWkid\":3857}}")); - } - - { - // Test Import Polygon from Polygon - String rings = "{\"hasZ\": true, \"rings\" : [ [ [0,0, 5], [0.0, 10.0, 5], [10.0,10.0, 5, 66666], [10.0,0.0, 5] ], [ [12, 12] ], [ [13 , 17], [13 , 17] ], [ [1.0, 1.0, 5, 66666], [9.0,1.0, 5], [9.0,9.0, 5], [1.0,9.0, 5], [1.0, 1.0, 5] ] ] }"; - MapGeometry mapGeometry = GeometryEngine.jsonToGeometry(factory - .createParser(rings)); - Polygon p = (Polygon) mapGeometry.getGeometry(); - @SuppressWarnings("unused") - double area = p.calculateArea2D(); - @SuppressWarnings("unused") - double length = p.calculateLength2D(); - assertTrue(p.getPathCount() == 4); - int count = p.getPointCount(); - assertTrue(count == 15); - assertTrue(p.hasAttribute(VertexDescription.Semantics.Z)); - assertTrue(!p.hasAttribute(VertexDescription.Semantics.M)); - } - - return bAnswer; - } - - boolean testEnvelope() throws JsonParseException, IOException { - boolean bAnswer = true; - - Envelope envelope = new Envelope(); - envelope.setCoords(-109.55, 25.76, -86.39, 49.94); - - { - JsonParser envelopeWGS84Parser = factory - .createParser(GeometryEngine.geometryToJson( - spatialReferenceWGS84, envelope)); - MapGeometry envelopeWGS84MP = GeometryEngine - .jsonToGeometry(envelopeWGS84Parser); - assertTrue(envelope.isEmpty() == envelopeWGS84MP.getGeometry() - .isEmpty()); - assertTrue(envelope.getXMax() == ((Envelope) envelopeWGS84MP - .getGeometry()).getXMax()); - assertTrue(envelope.getYMax() == ((Envelope) envelopeWGS84MP - .getGeometry()).getYMax()); - assertTrue(envelope.getXMin() == ((Envelope) envelopeWGS84MP - .getGeometry()).getXMin()); - assertTrue(envelope.getYMin() == ((Envelope) envelopeWGS84MP - .getGeometry()).getYMin()); - assertTrue(spatialReferenceWGS84.getID() == envelopeWGS84MP - .getSpatialReference().getID()); - if (!checkResultSpatialRef(envelopeWGS84MP, 4326, 0)) { - bAnswer = false; - } - } - - {// export - Envelope e = new Envelope(); - e.addAttribute(VertexDescription.Semantics.Z); - e.addAttribute(VertexDescription.Semantics.M); - String s = GeometryEngine.geometryToJson(spatialReferenceWebMerc1, - e); - assertTrue(s - .equals("{\"xmin\":null,\"ymin\":null,\"xmax\":null,\"ymax\":null,\"zmin\":null,\"zmax\":null,\"mmin\":null,\"mmax\":null,\"spatialReference\":{\"wkid\":102100,\"latestWkid\":3857}}")); - - e.setCoords(0, 1, 2, 3); - - Envelope1D z = new Envelope1D(); - Envelope1D m = new Envelope1D(); - z.setCoords(5, 7); - m.setCoords(11, 13); - - e.setInterval(VertexDescription.Semantics.Z, 0, z); - e.setInterval(VertexDescription.Semantics.M, 0, m); - s = GeometryEngine.geometryToJson(spatialReferenceWebMerc1, e); - assertTrue(s - .equals("{\"xmin\":0,\"ymin\":1,\"xmax\":2,\"ymax\":3,\"zmin\":5,\"zmax\":7,\"mmin\":11,\"mmax\":13,\"spatialReference\":{\"wkid\":102100,\"latestWkid\":3857}}")); - } - - {// import - String s = "{\"xmin\":0.0,\"ymin\":1.0,\"xmax\":2.0,\"ymax\":3.0,\"zmin\":5.0,\"zmax\":7.0,\"mmin\":11.0,\"mmax\":13.0,\"spatialReference\":{\"wkid\":102100,\"latestWkid\":3857}}"; - JsonParser parser = factory.createParser(s); - MapGeometry map_env = GeometryEngine.jsonToGeometry(parser); - Envelope env = (Envelope) map_env.getGeometry(); - Envelope1D z = env.queryInterval(VertexDescription.Semantics.Z, 0); - Envelope1D m = env.queryInterval(VertexDescription.Semantics.M, 0); - assertTrue(z.vmin == 5.0); - assertTrue(z.vmax == 7.0); - assertTrue(m.vmin == 11.0); - assertTrue(m.vmax == 13.0); - } - - { - String s = "{ \"zmin\" : 33, \"xmin\" : -109.55, \"zmax\" : 53, \"ymin\" : 25.76, \"xmax\" : -86.39, \"ymax\" : 49.94, \"mmax\" : 13}"; - JsonParser parser = factory.createParser(s); - MapGeometry map_env = GeometryEngine.jsonToGeometry(parser); - Envelope env = (Envelope) map_env.getGeometry(); - Envelope2D e = new Envelope2D(); - env.queryEnvelope2D(e); - assertTrue(e.xmin == -109.55 && e.ymin == 25.76 && e.xmax == -86.39 - && e.ymax == 49.94); - - Envelope1D e1D; - assertTrue(env.hasAttribute(VertexDescription.Semantics.Z)); - e1D = env.queryInterval(VertexDescription.Semantics.Z, 0); - assertTrue(e1D.vmin == 33 && e1D.vmax == 53); - - assertTrue(!env.hasAttribute(VertexDescription.Semantics.M)); - } - - return bAnswer; - } - - boolean testCR181369() throws JsonParseException, IOException { - // CR181369 - boolean bAnswer = true; - - String jsonStringPointAndWKT = "{\"x\":10.0,\"y\":20.0,\"spatialReference\":{\"wkt\" : \"PROJCS[\\\"NAD83_UTM_zone_15N\\\",GEOGCS[\\\"GCS_North_American_1983\\\",DATUM[\\\"D_North_American_1983\\\",SPHEROID[\\\"GRS_1980\\\",6378137.0,298.257222101]],PRIMEM[\\\"Greenwich\\\",0.0],UNIT[\\\"Degree\\\",0.0174532925199433]],PROJECTION[\\\"Transverse_Mercator\\\"],PARAMETER[\\\"false_easting\\\",500000.0],PARAMETER[\\\"false_northing\\\",0.0],PARAMETER[\\\"central_meridian\\\",-93.0],PARAMETER[\\\"scale_factor\\\",0.9996],PARAMETER[\\\"latitude_of_origin\\\",0.0],UNIT[\\\"Meter\\\",1.0]]\"} }"; - JsonParser jsonParserPointAndWKT = factory - .createParser(jsonStringPointAndWKT); - MapGeometry mapGeom2 = GeometryEngine - .jsonToGeometry(jsonParserPointAndWKT); - String jsonStringPointAndWKT2 = GeometryEngine.geometryToJson( - mapGeom2.getSpatialReference(), mapGeom2.getGeometry()); - JsonParser jsonParserPointAndWKT2 = factory - .createParser(jsonStringPointAndWKT2); - MapGeometry mapGeom3 = GeometryEngine - .jsonToGeometry(jsonParserPointAndWKT2); - assertTrue(((Point) mapGeom2.getGeometry()).getX() == ((Point) mapGeom3 - .getGeometry()).getX()); - assertTrue(((Point) mapGeom2.getGeometry()).getY() == ((Point) mapGeom3 - .getGeometry()).getY()); - - String s1 = mapGeom2.getSpatialReference().getText(); - String s2 = mapGeom3.getSpatialReference().getText(); - assertTrue(s1.equals(s2)); - - int id2 = mapGeom2.getSpatialReference().getID(); - int id3 = mapGeom3.getSpatialReference().getID(); - assertTrue(id2 == id3); - if (!checkResultSpatialRef(mapGeom3, mapGeom2.getSpatialReference() - .getID(), 0)) { - bAnswer = false; - } - return bAnswer; - } - - boolean checkResultSpatialRef(MapGeometry mapGeometry, int expectWki1, - int expectWki2) { - SpatialReference sr = mapGeometry.getSpatialReference(); - String Wkt = sr.getText(); - int wki1 = sr.getLatestID(); - if (!(wki1 == expectWki1 || wki1 == expectWki2)) - return false; - if (!(Wkt != null && Wkt.length() > 0)) - return false; - SpatialReference sr2 = SpatialReference.create(Wkt); - int wki2 = sr2.getID(); - if (expectWki2 > 0) { - if (!(wki2 == expectWki1 || wki2 == expectWki2)) - return false; - } else { - if (!(wki2 == expectWki1)) - return false; - } - return true; - } + @Override + protected void setUp() throws Exception { + super.setUp(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + } + + JsonFactory factory = new JsonFactory(); + SpatialReference spatialReferenceWebMerc1 = SpatialReference.create(102100); + SpatialReference spatialReferenceWebMerc2 = SpatialReference + .create(spatialReferenceWebMerc1.getLatestID()); + SpatialReference spatialReferenceWGS84 = SpatialReference.create(4326); + + @Test + public void testLocalExport() + throws JsonParseException, IOException { + String s = OperatorExportToJson.local().execute(null, new Point(1000000.2, 2000000.3)); + //assertTrue(s.contains(".")); + //assertFalse(s.contains(",")); + Polyline line = new Polyline(); + line.startPath(1.1, 2.2); + line.lineTo(2.3, 4.5); + String s1 = OperatorExportToJson.local().execute(null, line); + assertTrue(s.contains(".")); + } + + boolean testPoint() throws JsonParseException, IOException { + boolean bAnswer = true; + Point point1 = new Point(10.0, 20.0); + Point pointEmpty = new Point(); + { + JsonParser pointWebMerc1Parser = factory + .createParser(GeometryEngine.geometryToJson( + spatialReferenceWebMerc1, point1)); + MapGeometry pointWebMerc1MP = GeometryEngine + .jsonToGeometry(pointWebMerc1Parser); + assertTrue(point1.getX() == ((Point) pointWebMerc1MP.getGeometry()) + .getX()); + assertTrue(point1.getY() == ((Point) pointWebMerc1MP.getGeometry()) + .getY()); + assertTrue(spatialReferenceWebMerc1.getID() == pointWebMerc1MP + .getSpatialReference().getID() + || pointWebMerc1MP.getSpatialReference().getID() == 3857); + + if (!checkResultSpatialRef(pointWebMerc1MP, 102100, 3857)) { + bAnswer = false; + } + + pointWebMerc1Parser = factory.createParser(GeometryEngine + .geometryToJson(null, point1)); + pointWebMerc1MP = GeometryEngine + .jsonToGeometry(pointWebMerc1Parser); + assertTrue(null == pointWebMerc1MP.getSpatialReference()); + + if (pointWebMerc1MP.getSpatialReference() != null) { + if (!checkResultSpatialRef(pointWebMerc1MP, 102100, 3857)) { + bAnswer = false; + } + } + + String pointEmptyString = GeometryEngine.geometryToJson( + spatialReferenceWebMerc1, pointEmpty); + pointWebMerc1Parser = factory.createParser(pointEmptyString); + } + + JsonParser pointWebMerc2Parser = factory + .createParser(GeometryEngine.geometryToJson( + spatialReferenceWebMerc2, point1)); + MapGeometry pointWebMerc2MP = GeometryEngine + .jsonToGeometry(pointWebMerc2Parser); + assertTrue(point1.getX() == ((Point) pointWebMerc2MP.getGeometry()) + .getX()); + assertTrue(point1.getY() == ((Point) pointWebMerc2MP.getGeometry()) + .getY()); + assertTrue(spatialReferenceWebMerc2.getLatestID() == pointWebMerc2MP + .getSpatialReference().getLatestID()); + if (!checkResultSpatialRef(pointWebMerc2MP, + spatialReferenceWebMerc2.getLatestID(), 0)) { + bAnswer = false; + } + + { + JsonParser pointWgs84Parser = factory + .createParser(GeometryEngine.geometryToJson( + spatialReferenceWGS84, point1)); + MapGeometry pointWgs84MP = GeometryEngine + .jsonToGeometry(pointWgs84Parser); + assertTrue(point1.getX() == ((Point) pointWgs84MP.getGeometry()) + .getX()); + assertTrue(point1.getY() == ((Point) pointWgs84MP.getGeometry()) + .getY()); + assertTrue(spatialReferenceWGS84.getID() == pointWgs84MP + .getSpatialReference().getID()); + if (!checkResultSpatialRef(pointWgs84MP, 4326, 0)) { + bAnswer = false; + } + } + + { + Point p = new Point(); + String s = GeometryEngine.geometryToJson(spatialReferenceWebMerc1, + p); + assertTrue(s + .equals("{\"x\":null,\"y\":null,\"spatialReference\":{\"wkid\":102100,\"latestWkid\":3857}}")); + + p.addAttribute(VertexDescription.Semantics.Z); + p.addAttribute(VertexDescription.Semantics.M); + s = GeometryEngine.geometryToJson(spatialReferenceWebMerc1, p); + assertTrue(s + .equals("{\"x\":null,\"y\":null,\"z\":null,\"m\":null,\"spatialReference\":{\"wkid\":102100,\"latestWkid\":3857}}")); + + } + + { + Point p = new Point(10.0, 20.0, 30.0); + p.addAttribute(VertexDescription.Semantics.M); + String s = GeometryEngine.geometryToJson(spatialReferenceWebMerc1, + p); + assertTrue(s + .equals("{\"x\":10,\"y\":20,\"z\":30,\"m\":null,\"spatialReference\":{\"wkid\":102100,\"latestWkid\":3857}}")); + } + + {// import + String s = "{\"x\":0.0,\"y\":1.0,\"z\":5.0,\"m\":11.0,\"spatialReference\":{\"wkid\":102100,\"latestWkid\":3857}}"; + JsonParser parser = factory.createParser(s); + MapGeometry map_pt = GeometryEngine.jsonToGeometry(parser); + Point pt = (Point) map_pt.getGeometry(); + assertTrue(pt.getX() == 0.0); + assertTrue(pt.getY() == 1.0); + assertTrue(pt.getZ() == 5.0); + assertTrue(pt.getM() == 11.0); + } + + { + String s = "{\"x\" : 5.0, \"y\" : null, \"spatialReference\" : {\"wkid\" : 4326}} "; + JsonParser parser = factory.createParser(s); + MapGeometry map_pt = GeometryEngine.jsonToGeometry(parser); + Point pt = (Point) map_pt.getGeometry(); + assertTrue(pt.isEmpty()); + SpatialReference spatial_reference = map_pt.getSpatialReference(); + assertTrue(spatial_reference.getID() == 4326); + } + + return bAnswer; + } + + boolean testMultiPoint() throws JsonParseException, IOException { + boolean bAnswer = true; + + MultiPoint multiPoint1 = new MultiPoint(); + multiPoint1.add(-97.06138, 32.837); + multiPoint1.add(-97.06133, 32.836); + multiPoint1.add(-97.06124, 32.834); + multiPoint1.add(-97.06127, 32.832); + + { + String s = GeometryEngine.geometryToJson(spatialReferenceWGS84, + multiPoint1); + JsonParser mPointWgs84Parser = factory.createParser(s); + MapGeometry mPointWgs84MP = GeometryEngine + .jsonToGeometry(mPointWgs84Parser); + assertTrue(multiPoint1.getPointCount() == ((MultiPoint) mPointWgs84MP + .getGeometry()).getPointCount()); + assertTrue(multiPoint1.getPoint(0).getX() == ((MultiPoint) mPointWgs84MP + .getGeometry()).getPoint(0).getX()); + assertTrue(multiPoint1.getPoint(0).getY() == ((MultiPoint) mPointWgs84MP + .getGeometry()).getPoint(0).getY()); + int lastIndex = multiPoint1.getPointCount() - 1; + assertTrue(multiPoint1.getPoint(lastIndex).getX() == ((MultiPoint) mPointWgs84MP + .getGeometry()).getPoint(lastIndex).getX()); + assertTrue(multiPoint1.getPoint(lastIndex).getY() == ((MultiPoint) mPointWgs84MP + .getGeometry()).getPoint(lastIndex).getY()); + + assertTrue(spatialReferenceWGS84.getID() == mPointWgs84MP + .getSpatialReference().getID()); + if (!checkResultSpatialRef(mPointWgs84MP, 4326, 0)) { + bAnswer = false; + } + + } + + { + MultiPoint p = new MultiPoint(); + p.addAttribute(VertexDescription.Semantics.Z); + p.addAttribute(VertexDescription.Semantics.M); + String s = GeometryEngine.geometryToJson(spatialReferenceWebMerc1, + p); + assertTrue(s + .equals("{\"hasZ\":true,\"hasM\":true,\"points\":[],\"spatialReference\":{\"wkid\":102100,\"latestWkid\":3857}}")); + + p.add(10.0, 20.0, 30.0); + p.add(20.0, 40.0, 60.0); + s = GeometryEngine.geometryToJson(spatialReferenceWebMerc1, p); + assertTrue(s + .equals("{\"hasZ\":true,\"hasM\":true,\"points\":[[10,20,30,null],[20,40,60,null]],\"spatialReference\":{\"wkid\":102100,\"latestWkid\":3857}}")); + } + { + String points = "{\"hasM\" : false, \"hasZ\" : true, \"uncle remus\" : null, \"points\" : [ [0,0,1], [0.0,10.0,1], [10.0,10.0,1], [10.0,0.0,1, 6666] ],\"spatialReference\" : {\"wkid\" : 4326}}"; + MapGeometry mp = GeometryEngine.jsonToGeometry(factory + .createParser(points)); + MultiPoint multipoint = (MultiPoint) mp.getGeometry(); + assertTrue(multipoint.getPointCount() == 4); + Point2D point2d; + point2d = multipoint.getXY(0); + assertTrue(point2d.x == 0.0 && point2d.y == 0.0); + point2d = multipoint.getXY(1); + assertTrue(point2d.x == 0.0 && point2d.y == 10.0); + point2d = multipoint.getXY(2); + assertTrue(point2d.x == 10.0 && point2d.y == 10.0); + point2d = multipoint.getXY(3); + assertTrue(point2d.x == 10.0 && point2d.y == 0.0); + assertTrue(multipoint.hasAttribute(VertexDescription.Semantics.Z)); + assertTrue(!multipoint.hasAttribute(VertexDescription.Semantics.M)); + double z = multipoint.getAttributeAsDbl( + VertexDescription.Semantics.Z, 0, 0); + assertTrue(z == 1); + SpatialReference spatial_reference = mp.getSpatialReference(); + assertTrue(spatial_reference.getID() == 4326); + } + + return bAnswer; + } + + boolean testPolyline() throws JsonParseException, IOException { + boolean bAnswer = true; + + Polyline polyline = new Polyline(); + polyline.startPath(-97.06138, 32.837); + polyline.lineTo(-97.06133, 32.836); + polyline.lineTo(-97.06124, 32.834); + polyline.lineTo(-97.06127, 32.832); + + polyline.startPath(-97.06326, 32.759); + polyline.lineTo(-97.06298, 32.755); + + { + JsonParser polylinePathsWgs84Parser = factory + .createParser(GeometryEngine.geometryToJson( + spatialReferenceWGS84, polyline)); + MapGeometry mPolylineWGS84MP = GeometryEngine + .jsonToGeometry(polylinePathsWgs84Parser); + + assertTrue(polyline.getPointCount() == ((Polyline) mPolylineWGS84MP + .getGeometry()).getPointCount()); + assertTrue(polyline.getPoint(0).getX() == ((Polyline) mPolylineWGS84MP + .getGeometry()).getPoint(0).getX()); + assertTrue(polyline.getPoint(0).getY() == ((Polyline) mPolylineWGS84MP + .getGeometry()).getPoint(0).getY()); + + assertTrue(polyline.getPathCount() == ((Polyline) mPolylineWGS84MP + .getGeometry()).getPathCount()); + assertTrue(polyline.getSegmentCount() == ((Polyline) mPolylineWGS84MP + .getGeometry()).getSegmentCount()); + assertTrue(polyline.getSegmentCount(0) == ((Polyline) mPolylineWGS84MP + .getGeometry()).getSegmentCount(0)); + assertTrue(polyline.getSegmentCount(1) == ((Polyline) mPolylineWGS84MP + .getGeometry()).getSegmentCount(1)); + + int lastIndex = polyline.getPointCount() - 1; + assertTrue(polyline.getPoint(lastIndex).getX() == ((Polyline) mPolylineWGS84MP + .getGeometry()).getPoint(lastIndex).getX()); + assertTrue(polyline.getPoint(lastIndex).getY() == ((Polyline) mPolylineWGS84MP + .getGeometry()).getPoint(lastIndex).getY()); + + assertTrue(spatialReferenceWGS84.getID() == mPolylineWGS84MP + .getSpatialReference().getID()); + + if (!checkResultSpatialRef(mPolylineWGS84MP, 4326, 0)) { + bAnswer = false; + } + } + + { + Polyline p = new Polyline(); + p.addAttribute(VertexDescription.Semantics.Z); + p.addAttribute(VertexDescription.Semantics.M); + String s = GeometryEngine.geometryToJson(spatialReferenceWebMerc1, + p); + assertTrue(s + .equals("{\"hasZ\":true,\"hasM\":true,\"paths\":[],\"spatialReference\":{\"wkid\":102100,\"latestWkid\":3857}}")); + + p.startPath(0, 0); + p.lineTo(0, 1); + p.startPath(2, 2); + p.lineTo(3, 3); + + p.setAttribute(VertexDescription.Semantics.Z, 0, 0, 3); + p.setAttribute(VertexDescription.Semantics.M, 1, 0, 5); + s = GeometryEngine.geometryToJson(spatialReferenceWebMerc1, p); + assertTrue(s + .equals("{\"hasZ\":true,\"hasM\":true,\"paths\":[[[0,0,3,null],[0,1,0,5]],[[2,2,0,null],[3,3,0,null]]],\"spatialReference\":{\"wkid\":102100,\"latestWkid\":3857}}")); + } + + { + String paths = "{\"hasZ\" : true, \"paths\" : [ [ [0.0, 0.0,3], [0, 10.0,3], [10.0, 10.0,3, 6666], [10.0, 0.0,3, 6666] ], [ [1.0, 1,3], [1.0, 9.0,3], [9.0, 9.0,3], [1.0, 9.0,3] ] ], \"spatialReference\" : {\"wkid\" : 4326}, \"hasM\" : false}"; + MapGeometry mapGeometry = GeometryEngine.jsonToGeometry(factory + .createParser(paths)); + Polyline p = (Polyline) mapGeometry.getGeometry(); + assertTrue(p.getPathCount() == 2); + @SuppressWarnings("unused") + int count = p.getPathCount(); + assertTrue(p.getPointCount() == 8); + assertTrue(p.hasAttribute(VertexDescription.Semantics.Z)); + assertTrue(!p.hasAttribute(VertexDescription.Semantics.M)); + double z = p.getAttributeAsDbl(VertexDescription.Semantics.Z, 0, 0); + assertTrue(z == 3); + double length = p.calculateLength2D(); + assertTrue(Math.abs(length - 54.0) <= 0.001); + SpatialReference spatial_reference = mapGeometry + .getSpatialReference(); + assertTrue(spatial_reference.getID() == 4326); + } + + return bAnswer; + } + + boolean testPolygon() throws JsonParseException, IOException { + boolean bAnswer = true; + + Polygon polygon = new Polygon(); + polygon.startPath(-97.06138, 32.837); + polygon.lineTo(-97.06133, 32.836); + polygon.lineTo(-97.06124, 32.834); + polygon.lineTo(-97.06127, 32.832); + + polygon.startPath(-97.06326, 32.759); + polygon.lineTo(-97.06298, 32.755); + + { + JsonParser polygonPathsWgs84Parser = factory + .createParser(GeometryEngine.geometryToJson( + spatialReferenceWGS84, polygon)); + MapGeometry mPolygonWGS84MP = GeometryEngine + .jsonToGeometry(polygonPathsWgs84Parser); + + assertTrue(polygon.getPointCount() + 1 == ((Polygon) mPolygonWGS84MP + .getGeometry()).getPointCount()); + assertTrue(polygon.getPoint(0).getX() == ((Polygon) mPolygonWGS84MP + .getGeometry()).getPoint(0).getX()); + assertTrue(polygon.getPoint(0).getY() == ((Polygon) mPolygonWGS84MP + .getGeometry()).getPoint(0).getY()); + + assertTrue(polygon.getPathCount() == ((Polygon) mPolygonWGS84MP + .getGeometry()).getPathCount()); + assertTrue(polygon.getSegmentCount() + 1 == ((Polygon) mPolygonWGS84MP + .getGeometry()).getSegmentCount()); + assertTrue(polygon.getSegmentCount(0) == ((Polygon) mPolygonWGS84MP + .getGeometry()).getSegmentCount(0)); + assertTrue(polygon.getSegmentCount(1) + 1 == ((Polygon) mPolygonWGS84MP + .getGeometry()).getSegmentCount(1)); + + int lastIndex = polygon.getPointCount() - 1; + assertTrue(polygon.getPoint(lastIndex).getX() == ((Polygon) mPolygonWGS84MP + .getGeometry()).getPoint(lastIndex).getX()); + assertTrue(polygon.getPoint(lastIndex).getY() == ((Polygon) mPolygonWGS84MP + .getGeometry()).getPoint(lastIndex).getY()); + + assertTrue(spatialReferenceWGS84.getID() == mPolygonWGS84MP + .getSpatialReference().getID()); + + if (!checkResultSpatialRef(mPolygonWGS84MP, 4326, 0)) { + bAnswer = false; + } + } + + { + Polygon p = new Polygon(); + p.addAttribute(VertexDescription.Semantics.Z); + p.addAttribute(VertexDescription.Semantics.M); + String s = GeometryEngine.geometryToJson(spatialReferenceWebMerc1, + p); + assertTrue(s + .equals("{\"hasZ\":true,\"hasM\":true,\"rings\":[],\"spatialReference\":{\"wkid\":102100,\"latestWkid\":3857}}")); + + p.startPath(0, 0); + p.lineTo(0, 1); + p.lineTo(4, 4); + p.startPath(2, 2); + p.lineTo(3, 3); + p.lineTo(7, 8); + + p.setAttribute(VertexDescription.Semantics.Z, 0, 0, 3); + p.setAttribute(VertexDescription.Semantics.M, 1, 0, 7); + p.setAttribute(VertexDescription.Semantics.M, 2, 0, 5); + p.setAttribute(VertexDescription.Semantics.M, 5, 0, 5); + s = GeometryEngine.geometryToJson(spatialReferenceWebMerc1, p); + assertTrue(s + .equals("{\"hasZ\":true,\"hasM\":true,\"rings\":[[[0,0,3,null],[0,1,0,7],[4,4,0,5],[0,0,3,null]],[[2,2,0,null],[3,3,0,null],[7,8,0,5],[2,2,0,null]]],\"spatialReference\":{\"wkid\":102100,\"latestWkid\":3857}}")); + } + + { + // Test Import Polygon from Polygon + String rings = "{\"hasZ\": true, \"rings\" : [ [ [0,0, 5], [0.0, 10.0, 5], [10.0,10.0, 5, 66666], [10.0,0.0, 5] ], [ [12, 12] ], [ [13 , 17], [13 , 17] ], [ [1.0, 1.0, 5, 66666], [9.0,1.0, 5], [9.0,9.0, 5], [1.0,9.0, 5], [1.0, 1.0, 5] ] ] }"; + MapGeometry mapGeometry = GeometryEngine.jsonToGeometry(factory + .createParser(rings)); + Polygon p = (Polygon) mapGeometry.getGeometry(); + @SuppressWarnings("unused") + double area = p.calculateArea2D(); + @SuppressWarnings("unused") + double length = p.calculateLength2D(); + assertTrue(p.getPathCount() == 4); + int count = p.getPointCount(); + assertTrue(count == 15); + assertTrue(p.hasAttribute(VertexDescription.Semantics.Z)); + assertTrue(!p.hasAttribute(VertexDescription.Semantics.M)); + } + + return bAnswer; + } + + boolean testEnvelope() throws JsonParseException, IOException { + boolean bAnswer = true; + + Envelope envelope = new Envelope(); + envelope.setCoords(-109.55, 25.76, -86.39, 49.94); + + { + JsonParser envelopeWGS84Parser = factory + .createParser(GeometryEngine.geometryToJson( + spatialReferenceWGS84, envelope)); + MapGeometry envelopeWGS84MP = GeometryEngine + .jsonToGeometry(envelopeWGS84Parser); + assertTrue(envelope.isEmpty() == envelopeWGS84MP.getGeometry() + .isEmpty()); + assertTrue(envelope.getXMax() == ((Envelope) envelopeWGS84MP + .getGeometry()).getXMax()); + assertTrue(envelope.getYMax() == ((Envelope) envelopeWGS84MP + .getGeometry()).getYMax()); + assertTrue(envelope.getXMin() == ((Envelope) envelopeWGS84MP + .getGeometry()).getXMin()); + assertTrue(envelope.getYMin() == ((Envelope) envelopeWGS84MP + .getGeometry()).getYMin()); + assertTrue(spatialReferenceWGS84.getID() == envelopeWGS84MP + .getSpatialReference().getID()); + if (!checkResultSpatialRef(envelopeWGS84MP, 4326, 0)) { + bAnswer = false; + } + } + + {// export + Envelope e = new Envelope(); + e.addAttribute(VertexDescription.Semantics.Z); + e.addAttribute(VertexDescription.Semantics.M); + String s = GeometryEngine.geometryToJson(spatialReferenceWebMerc1, + e); + assertTrue(s + .equals("{\"xmin\":null,\"ymin\":null,\"xmax\":null,\"ymax\":null,\"zmin\":null,\"zmax\":null,\"mmin\":null,\"mmax\":null,\"spatialReference\":{\"wkid\":102100,\"latestWkid\":3857}}")); + + e.setCoords(0, 1, 2, 3); + + Envelope1D z = new Envelope1D(); + Envelope1D m = new Envelope1D(); + z.setCoords(5, 7); + m.setCoords(11, 13); + + e.setInterval(VertexDescription.Semantics.Z, 0, z); + e.setInterval(VertexDescription.Semantics.M, 0, m); + s = GeometryEngine.geometryToJson(spatialReferenceWebMerc1, e); + assertTrue(s + .equals("{\"xmin\":0,\"ymin\":1,\"xmax\":2,\"ymax\":3,\"zmin\":5,\"zmax\":7,\"mmin\":11,\"mmax\":13,\"spatialReference\":{\"wkid\":102100,\"latestWkid\":3857}}")); + } + + {// import + String s = "{\"xmin\":0.0,\"ymin\":1.0,\"xmax\":2.0,\"ymax\":3.0,\"zmin\":5.0,\"zmax\":7.0,\"mmin\":11.0,\"mmax\":13.0,\"spatialReference\":{\"wkid\":102100,\"latestWkid\":3857}}"; + JsonParser parser = factory.createParser(s); + MapGeometry map_env = GeometryEngine.jsonToGeometry(parser); + Envelope env = (Envelope) map_env.getGeometry(); + Envelope1D z = env.queryInterval(VertexDescription.Semantics.Z, 0); + Envelope1D m = env.queryInterval(VertexDescription.Semantics.M, 0); + assertTrue(z.vmin == 5.0); + assertTrue(z.vmax == 7.0); + assertTrue(m.vmin == 11.0); + assertTrue(m.vmax == 13.0); + } + + { + String s = "{ \"zmin\" : 33, \"xmin\" : -109.55, \"zmax\" : 53, \"ymin\" : 25.76, \"xmax\" : -86.39, \"ymax\" : 49.94, \"mmax\" : 13}"; + JsonParser parser = factory.createParser(s); + MapGeometry map_env = GeometryEngine.jsonToGeometry(parser); + Envelope env = (Envelope) map_env.getGeometry(); + Envelope2D e = new Envelope2D(); + env.queryEnvelope2D(e); + assertTrue(e.xmin == -109.55 && e.ymin == 25.76 && e.xmax == -86.39 + && e.ymax == 49.94); + + Envelope1D e1D; + assertTrue(env.hasAttribute(VertexDescription.Semantics.Z)); + e1D = env.queryInterval(VertexDescription.Semantics.Z, 0); + assertTrue(e1D.vmin == 33 && e1D.vmax == 53); + + assertTrue(!env.hasAttribute(VertexDescription.Semantics.M)); + } + + return bAnswer; + } + + boolean testCR181369() throws JsonParseException, IOException { + // CR181369 + boolean bAnswer = true; + + String jsonStringPointAndWKT = "{\"x\":10.0,\"y\":20.0,\"spatialReference\":{\"wkt\" : \"PROJCS[\\\"NAD83_UTM_zone_15N\\\",GEOGCS[\\\"GCS_North_American_1983\\\",DATUM[\\\"D_North_American_1983\\\",SPHEROID[\\\"GRS_1980\\\",6378137.0,298.257222101]],PRIMEM[\\\"Greenwich\\\",0.0],UNIT[\\\"Degree\\\",0.0174532925199433]],PROJECTION[\\\"Transverse_Mercator\\\"],PARAMETER[\\\"false_easting\\\",500000.0],PARAMETER[\\\"false_northing\\\",0.0],PARAMETER[\\\"central_meridian\\\",-93.0],PARAMETER[\\\"scale_factor\\\",0.9996],PARAMETER[\\\"latitude_of_origin\\\",0.0],UNIT[\\\"Meter\\\",1.0]]\"} }"; + JsonParser jsonParserPointAndWKT = factory + .createParser(jsonStringPointAndWKT); + MapGeometry mapGeom2 = GeometryEngine + .jsonToGeometry(jsonParserPointAndWKT); + String jsonStringPointAndWKT2 = GeometryEngine.geometryToJson( + mapGeom2.getSpatialReference(), mapGeom2.getGeometry()); + JsonParser jsonParserPointAndWKT2 = factory + .createParser(jsonStringPointAndWKT2); + MapGeometry mapGeom3 = GeometryEngine + .jsonToGeometry(jsonParserPointAndWKT2); + assertTrue(((Point) mapGeom2.getGeometry()).getX() == ((Point) mapGeom3 + .getGeometry()).getX()); + assertTrue(((Point) mapGeom2.getGeometry()).getY() == ((Point) mapGeom3 + .getGeometry()).getY()); + + String s1 = mapGeom2.getSpatialReference().getText(); + String s2 = mapGeom3.getSpatialReference().getText(); + assertTrue(s1.equals(s2)); + + int id2 = mapGeom2.getSpatialReference().getID(); + int id3 = mapGeom3.getSpatialReference().getID(); + assertTrue(id2 == id3); + if (!checkResultSpatialRef(mapGeom3, mapGeom2.getSpatialReference() + .getID(), 0)) { + bAnswer = false; + } + return bAnswer; + } + + boolean checkResultSpatialRef(MapGeometry mapGeometry, int expectWki1, + int expectWki2) { + SpatialReference sr = mapGeometry.getSpatialReference(); + String Wkt = sr.getText(); + int wki1 = sr.getLatestID(); + if (!(wki1 == expectWki1 || wki1 == expectWki2)) + return false; + if (!(Wkt != null && Wkt.length() > 0)) + return false; + SpatialReference sr2 = SpatialReference.create(Wkt); + int wki2 = sr2.getID(); + if (expectWki2 > 0) { + if (!(wki2 == expectWki1 || wki2 == expectWki2)) + return false; + } else { + if (!(wki2 == expectWki1)) + return false; + } + return true; + } } diff --git a/src/test/java/com/esri/core/geometry/TestImportExport.java b/src/test/java/com/esri/core/geometry/TestImportExport.java index 4b249cc1..5f94539e 100644 --- a/src/test/java/com/esri/core/geometry/TestImportExport.java +++ b/src/test/java/com/esri/core/geometry/TestImportExport.java @@ -36,18 +36,18 @@ public class TestImportExport extends TestCase { - @Override - protected void setUp() throws Exception { - super.setUp(); - } - - @Override - protected void tearDown() throws Exception { - super.tearDown(); - } - - @Test - public static void testImportExportShapePolygon() { + @Override + protected void setUp() throws Exception { + super.setUp(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + } + + @Test + public static void testImportExportShapePolygon() { // { // String s = "MULTIPOLYGON (((-1.4337158203098852 53.42590083930004, -1.4346462383651897 53.42590083930004, -1.4349713164114632 53.42426406667512, -1.4344808816770183 53.42391134176576, -1.4337158203098852 53.424339319373516, -1.4337158203098852 53.42590083930004, -1.4282226562499147 53.42590083930004, -1.4282226562499147 53.42262754610009, -1.423659941537096 53.42262754610009, -1.4227294921872726 53.42418897437618, -1.4199829101572732 53.42265258737483, -1.4172363281222147 53.42418897437334, -1.4144897460898278 53.42265258737625, -1.4144897460898278 53.42099079900008, -1.4117431640598568 53.42099079712516, -1.4117431640598568 53.41849780932388, -1.4112778948070286 53.41771711805022, -1.4114404909237805 53.41689867267529, -1.411277890108579 53.416080187950215, -1.4117431640598568 53.4152995338453, -1.4117431657531654 53.40953184824072, -1.41723632610001 53.40953184402311, -1.4172363281199125 53.406257299700044, -1.4227294921899158 53.406257299700044, -1.4227294921899158 53.40789459668797, -1.4254760767598498 53.40789460061099, -1.4262193642339867 53.40914148401417, -1.4273828468095076 53.409531853100034, -1.4337158203098852 53.409531790075235, -1.4337158203098852 53.41280609140024, -1.4392089843723568 53.41280609140024, -1.439208984371362 53.41608014067522, -1.441160015802268 53.41935368587538, -1.4427511170075604 53.41935368587538, -1.4447021484373863 53.42099064750012, -1.4501953124999432 53.42099064750012, -1.4501953124999432 53.43214683850347, -1.4513643355446106 53.434108816701794, -1.4502702625278232 53.43636597733034, -1.4494587195580948 53.437354845300334, -1.4431075935937656 53.437354845300334, -1.4372459179209045 53.43244635455021, -1.433996276212838 53.42917388040006, -1.4337158203098852 53.42917388040006, -1.4337158203098852 53.42590083930004)))"; // Geometry g = OperatorImportFromWkt.local().execute(0, Geometry.Type.Unknown, s, null); @@ -57,2139 +57,2139 @@ public static void testImportExportShapePolygon() { // OperatorFactoryLocal.saveToWKTFileDbg("c:/temp/simplifiedeeee", simple, null); // int i = 0; // } - OperatorExportToESRIShape exporterShape = (OperatorExportToESRIShape) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ExportToESRIShape); - OperatorImportFromESRIShape importerShape = (OperatorImportFromESRIShape) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ImportFromESRIShape); - - Polygon polygon = makePolygon(); - - byte[] esriShape = GeometryEngine.geometryToEsriShape(polygon); - Geometry imported = GeometryEngine.geometryFromEsriShape(esriShape, Geometry.Type.Unknown); - TestCommonMethods.compareGeometryContent((MultiPath) imported, polygon); - - // Test Import Polygon from Polygon - ByteBuffer polygonShapeBuffer = exporterShape.execute(0, polygon); - Geometry polygonShapeGeometry = importerShape.execute(0, Geometry.Type.Polygon, polygonShapeBuffer); - - TestCommonMethods.compareGeometryContent((MultiPath) polygonShapeGeometry, polygon); - - // Test Import Envelope from Polygon - Geometry envelopeShapeGeometry = importerShape.execute(0, Geometry.Type.Envelope, polygonShapeBuffer); - Envelope envelope = (Envelope) envelopeShapeGeometry; - - @SuppressWarnings("unused") Envelope env = new Envelope(), otherenv = new Envelope(); - polygon.queryEnvelope(otherenv); - assertTrue(envelope.getXMin() == otherenv.getXMin()); - assertTrue(envelope.getXMax() == otherenv.getXMax()); - assertTrue(envelope.getYMin() == otherenv.getYMin()); - assertTrue(envelope.getYMax() == otherenv.getYMax()); - - Envelope1D interval, otherinterval; - interval = envelope.queryInterval(VertexDescription.Semantics.Z, 0); - otherinterval = polygon.queryInterval(VertexDescription.Semantics.Z, 0); - assertTrue(interval.vmin == otherinterval.vmin); - assertTrue(interval.vmax == otherinterval.vmax); - } - - @Test - public static void testImportExportShapePolyline() { - OperatorExportToESRIShape exporterShape = (OperatorExportToESRIShape) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ExportToESRIShape); - OperatorImportFromESRIShape importerShape = (OperatorImportFromESRIShape) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ImportFromESRIShape); - - Polyline polyline = makePolyline(); - - // Test Import Polyline from Polyline - ByteBuffer polylineShapeBuffer = exporterShape.execute(0, polyline); - Geometry polylineShapeGeometry = importerShape.execute(0, Geometry.Type.Polyline, polylineShapeBuffer); - - // TODO test this - TestCommonMethods.compareGeometryContent((MultiPath) polylineShapeGeometry, polyline); - - // Test Import Envelope from Polyline; - Geometry envelopeShapeGeometry = importerShape.execute(0, Geometry.Type.Envelope, polylineShapeBuffer); - Envelope envelope = (Envelope) envelopeShapeGeometry; - - Envelope env = new Envelope(), otherenv = new Envelope(); - envelope.queryEnvelope(env); - polyline.queryEnvelope(otherenv); - assertTrue(env.getXMin() == otherenv.getXMin()); - assertTrue(env.getXMax() == otherenv.getXMax()); - assertTrue(env.getYMin() == otherenv.getYMin()); - assertTrue(env.getYMax() == otherenv.getYMax()); - - Envelope1D interval, otherinterval; - interval = envelope.queryInterval(VertexDescription.Semantics.Z, 0); - otherinterval = polyline.queryInterval(VertexDescription.Semantics.Z, 0); - assertTrue(interval.vmin == otherinterval.vmin); - assertTrue(interval.vmax == otherinterval.vmax); - } - - @Test - public static void testImportExportShapeMultiPoint() { - OperatorExportToESRIShape exporterShape = (OperatorExportToESRIShape) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ExportToESRIShape); - OperatorImportFromESRIShape importerShape = (OperatorImportFromESRIShape) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ImportFromESRIShape); - - MultiPoint multipoint = makeMultiPoint(); - - // Test Import MultiPoint from MultiPoint - ByteBuffer multipointShapeBuffer = exporterShape.execute(0, multipoint); - MultiPoint multipointShapeGeometry = (MultiPoint) importerShape.execute(0, Geometry.Type.MultiPoint, multipointShapeBuffer); - - TestCommonMethods.compareGeometryContent((MultiPoint) multipointShapeGeometry, multipoint); - - // Test Import Envelope from MultiPoint - Geometry envelopeShapeGeometry = importerShape.execute(0, Geometry.Type.Envelope, multipointShapeBuffer); - Envelope envelope = (Envelope) envelopeShapeGeometry; - - Envelope env = new Envelope(), otherenv = new Envelope(); - envelope.queryEnvelope(env); - multipoint.queryEnvelope(otherenv); - assertTrue(env.getXMin() == otherenv.getXMin()); - assertTrue(env.getXMax() == otherenv.getXMax()); - assertTrue(env.getYMin() == otherenv.getYMin()); - assertTrue(env.getYMax() == otherenv.getYMax()); - - Envelope1D interval, otherinterval; - interval = envelope.queryInterval(VertexDescription.Semantics.Z, 0); - otherinterval = multipoint.queryInterval(VertexDescription.Semantics.Z, 0); - assertTrue(interval.vmin == otherinterval.vmin); - assertTrue(interval.vmax == otherinterval.vmax); - - interval = envelope.queryInterval(VertexDescription.Semantics.ID, 0); - otherinterval = multipoint.queryInterval(VertexDescription.Semantics.ID, 0); - assertTrue(interval.vmin == otherinterval.vmin); - assertTrue(interval.vmax == otherinterval.vmax); - } - - @Test - public static void testImportExportShapePoint() { - OperatorExportToESRIShape exporterShape = (OperatorExportToESRIShape) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ExportToESRIShape); - OperatorImportFromESRIShape importerShape = (OperatorImportFromESRIShape) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ImportFromESRIShape); - - // Point - Point point = makePoint(); - - // Test Import Point from Point - ByteBuffer pointShapeBuffer = exporterShape.execute(0, point); - Point pointShapeGeometry = (Point) importerShape.execute(0, Geometry.Type.Point, pointShapeBuffer); - - double x1 = point.getX(); - double x2 = pointShapeGeometry.getX(); - assertTrue(x1 == x2); - - double y1 = point.getY(); - double y2 = pointShapeGeometry.getY(); - assertTrue(y1 == y2); - - double z1 = point.getZ(); - double z2 = pointShapeGeometry.getZ(); - assertTrue(z1 == z2); - - double m1 = point.getM(); - double m2 = pointShapeGeometry.getM(); - assertTrue(m1 == m2); - - int id1 = point.getID(); - int id2 = pointShapeGeometry.getID(); - assertTrue(id1 == id2); - - // Test Import Multipoint from Point - MultiPoint multipointShapeGeometry = (MultiPoint) importerShape.execute(0, Geometry.Type.MultiPoint, pointShapeBuffer); - Point point2d = multipointShapeGeometry.getPoint(0); - assertTrue(x1 == point2d.getX() && y1 == point2d.getY()); - - int pointCount = multipointShapeGeometry.getPointCount(); - assertTrue(pointCount == 1); - - z2 = multipointShapeGeometry.getAttributeAsDbl(VertexDescription.Semantics.Z, 0, 0); - assertTrue(z1 == z2); - - m2 = multipointShapeGeometry.getAttributeAsDbl(VertexDescription.Semantics.M, 0, 0); - assertTrue(m1 == m2); - - id2 = multipointShapeGeometry.getAttributeAsInt(VertexDescription.Semantics.ID, 0, 0); - assertTrue(id1 == id2); - - // Test Import Envelope from Point - Geometry envelopeShapeGeometry = importerShape.execute(0, Geometry.Type.Envelope, pointShapeBuffer); - Envelope envelope = (Envelope) envelopeShapeGeometry; - - Envelope env = new Envelope(), otherenv = new Envelope(); - envelope.queryEnvelope(env); - point.queryEnvelope(otherenv); - assertTrue(env.getXMin() == otherenv.getXMin()); - assertTrue(env.getXMax() == otherenv.getXMax()); - assertTrue(env.getYMin() == otherenv.getYMin()); - assertTrue(env.getYMax() == otherenv.getYMax()); - - Envelope1D interval, otherinterval; - interval = envelope.queryInterval(VertexDescription.Semantics.Z, 0); - otherinterval = point.queryInterval(VertexDescription.Semantics.Z, 0); - assertTrue(interval.vmin == otherinterval.vmin); - assertTrue(interval.vmax == otherinterval.vmax); - - interval = envelope.queryInterval(VertexDescription.Semantics.ID, 0); - otherinterval = point.queryInterval(VertexDescription.Semantics.ID, 0); - assertTrue(interval.vmin == otherinterval.vmin); - assertTrue(interval.vmax == otherinterval.vmax); - } - - @Test - public static void testImportExportShapeEnvelope() { - OperatorExportToESRIShape exporterShape = (OperatorExportToESRIShape) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ExportToESRIShape); - OperatorImportFromESRIShape importerShape = (OperatorImportFromESRIShape) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ImportFromESRIShape); - - // Test Export Envelope to Polygon - Envelope envelope = makeEnvelope(); - - ByteBuffer polygonShapeBuffer = exporterShape.execute(0, envelope); - Polygon polygon = (Polygon) importerShape.execute(0, Geometry.Type.Polygon, polygonShapeBuffer); - int pointCount = polygon.getPointCount(); - assertTrue(pointCount == 4); - - Envelope env = new Envelope(); - - envelope.queryEnvelope(env); - // interval = envelope.queryInterval(VertexDescription.Semantics.Z, 0); - Point point3d; - point3d = polygon.getPoint(0); - assertTrue(point3d.getX() == env.getXMin() && point3d.getY() == env.getYMin());// && point3d.z == - // interval.vmin); - point3d = polygon.getPoint(1); - assertTrue(point3d.getX() == env.getXMin() && point3d.getY() == env.getYMax());// && point3d.z == - // interval.vmax); - point3d = polygon.getPoint(2); - assertTrue(point3d.getX() == env.getXMax() && point3d.getY() == env.getYMax());// && point3d.z == - // interval.vmin); - point3d = polygon.getPoint(3); - assertTrue(point3d.getX() == env.getXMax() && point3d.getY() == env.getYMin());// && point3d.z == - // interval.vmax); - - Envelope1D interval; - interval = envelope.queryInterval(VertexDescription.Semantics.M, 0); - double m = polygon.getAttributeAsDbl(VertexDescription.Semantics.M, 0, 0); - assertTrue(m == interval.vmin); - m = polygon.getAttributeAsDbl(VertexDescription.Semantics.M, 1, 0); - assertTrue(m == interval.vmax); - m = polygon.getAttributeAsDbl(VertexDescription.Semantics.M, 2, 0); - assertTrue(m == interval.vmin); - m = polygon.getAttributeAsDbl(VertexDescription.Semantics.M, 3, 0); - assertTrue(m == interval.vmax); - - interval = envelope.queryInterval(VertexDescription.Semantics.ID, 0); - double id = polygon.getAttributeAsDbl(VertexDescription.Semantics.ID, 0, 0); - assertTrue(id == interval.vmin); - id = polygon.getAttributeAsDbl(VertexDescription.Semantics.ID, 1, 0); - assertTrue(id == interval.vmax); - id = polygon.getAttributeAsDbl(VertexDescription.Semantics.ID, 2, 0); - assertTrue(id == interval.vmin); - id = polygon.getAttributeAsDbl(VertexDescription.Semantics.ID, 3, 0); - assertTrue(id == interval.vmax); - } - - @Test - public static void testImportExportWkbGeometryCollection() { - OperatorImportFromWkb importerWKB = (OperatorImportFromWkb) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ImportFromWkb); - - int offset = 0; - ByteBuffer wkbBuffer = ByteBuffer.allocate(600).order(ByteOrder.nativeOrder()); - wkbBuffer.put(offset, (byte) WkbByteOrder.wkbNDR); - offset += 1; // byte order - wkbBuffer.putInt(offset, WkbGeometryType.wkbGeometryCollection); - offset += 4; // type - wkbBuffer.putInt(offset, 3); // 3 geometries - offset += 4; - wkbBuffer.put(offset, (byte) WkbByteOrder.wkbNDR); - offset += 1; - wkbBuffer.putInt(offset, WkbGeometryType.wkbPoint); - offset += 4; - wkbBuffer.putDouble(offset, 0); - offset += 8; - wkbBuffer.putDouble(offset, 0); - offset += 8; - wkbBuffer.put(offset, (byte) WkbByteOrder.wkbNDR); - offset += 1; // byte order - wkbBuffer.putInt(offset, WkbGeometryType.wkbGeometryCollection); - offset += 4; // type - wkbBuffer.putInt(offset, 7); // 7 empty geometries - offset += 4; - wkbBuffer.put(offset, (byte) WkbByteOrder.wkbNDR); - offset += 1; - wkbBuffer.putInt(offset, WkbGeometryType.wkbLineString); - offset += 4; - wkbBuffer.putInt(offset, 0); // 0 points, for empty linestring - offset += 4; - wkbBuffer.put(offset, (byte) WkbByteOrder.wkbNDR); - offset += 1; - wkbBuffer.putInt(offset, WkbGeometryType.wkbPolygon); - offset += 4; - wkbBuffer.putInt(offset, 0); // 0 points, for empty polygon - offset += 4; - wkbBuffer.put(offset, (byte) WkbByteOrder.wkbNDR); - offset += 1; - wkbBuffer.putInt(offset, WkbGeometryType.wkbMultiPolygon); - offset += 4; - wkbBuffer.putInt(offset, 0); // 0 points, for empty multipolygon - offset += 4; - wkbBuffer.put(offset, (byte) WkbByteOrder.wkbNDR); - offset += 1; - wkbBuffer.putInt(offset, WkbGeometryType.wkbMultiLineString); - offset += 4; - wkbBuffer.putInt(offset, 0); // 0 points, for empty multilinestring - offset += 4; - wkbBuffer.put(offset, (byte) WkbByteOrder.wkbNDR); - offset += 1; - wkbBuffer.putInt(offset, WkbGeometryType.wkbGeometryCollection); - offset += 4; - wkbBuffer.putInt(offset, 0); // 0 geometries, for empty - // geometrycollection - offset += 4; - wkbBuffer.put(offset, (byte) WkbByteOrder.wkbNDR); - offset += 1; - wkbBuffer.putInt(offset, WkbGeometryType.wkbMultiPoint); - offset += 4; - wkbBuffer.putInt(offset, 0); // 0 points, for empty multipoint - offset += 4; - wkbBuffer.put(offset, (byte) WkbByteOrder.wkbNDR); - offset += 1; - wkbBuffer.putInt(offset, WkbGeometryType.wkbPoint); - offset += 4; - wkbBuffer.putDouble(offset, 66); - offset += 8; - wkbBuffer.putDouble(offset, 88); - offset += 8; - wkbBuffer.put(offset, (byte) WkbByteOrder.wkbNDR); - offset += 1; - wkbBuffer.putInt(offset, WkbGeometryType.wkbPoint); - offset += 4; - wkbBuffer.putDouble(offset, 13); - offset += 8; - wkbBuffer.putDouble(offset, 17); - offset += 8; - - // "GeometryCollection( Point (0 0), GeometryCollection( LineString empty, Polygon empty, MultiPolygon empty, MultiLineString empty, MultiPoint empty ), Point (13 17) )"; - OGCStructure structure = importerWKB.executeOGC(0, wkbBuffer, null).m_structures.get(0); - - assertTrue(structure.m_type == 7); - assertTrue(structure.m_structures.get(0).m_type == 1); - assertTrue(structure.m_structures.get(1).m_type == 7); - assertTrue(structure.m_structures.get(2).m_type == 1); - - assertTrue(structure.m_structures.get(1).m_structures.get(0).m_type == 2); - assertTrue(structure.m_structures.get(1).m_structures.get(1).m_type == 3); - assertTrue(structure.m_structures.get(1).m_structures.get(2).m_type == 6); - assertTrue(structure.m_structures.get(1).m_structures.get(3).m_type == 5); - assertTrue(structure.m_structures.get(1).m_structures.get(4).m_type == 7); - assertTrue(structure.m_structures.get(1).m_structures.get(5).m_type == 4); - assertTrue(structure.m_structures.get(1).m_structures.get(6).m_type == 1); - - Point p = (Point) structure.m_structures.get(1).m_structures.get(6).m_geometry; - assertTrue(p.getX() == 66); - assertTrue(p.getY() == 88); - - p = (Point) structure.m_structures.get(2).m_geometry; - assertTrue(p.getX() == 13); - assertTrue(p.getY() == 17); - } - - @Test - public static void testImportExportWKBPolygon() { - OperatorExportToWkb exporterWKB = (OperatorExportToWkb) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ExportToWkb); - OperatorExportToWkt exporterWKT = (OperatorExportToWkt) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ExportToWkt); - OperatorImportFromWkb importerWKB = (OperatorImportFromWkb) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ImportFromWkb); - - // Test Import Polygon with bad rings - int offset = 0; - ByteBuffer wkbBuffer = ByteBuffer.allocate(500).order(ByteOrder.nativeOrder()); - wkbBuffer.put(offset, (byte) WkbByteOrder.wkbNDR); - offset += 1; // byte order - wkbBuffer.putInt(offset, WkbGeometryType.wkbPolygon); - offset += 4; // type - wkbBuffer.putInt(offset, 8); - offset += 4; // num rings - wkbBuffer.putInt(offset, 4); - offset += 4; // num points - wkbBuffer.putDouble(offset, 0.0); - offset += 8; // x - wkbBuffer.putDouble(offset, 0.0); - offset += 8; // y - wkbBuffer.putDouble(offset, 0.0); - offset += 8; // x - wkbBuffer.putDouble(offset, 10.0); - offset += 8; // y - wkbBuffer.putDouble(offset, 10.0); - offset += 8; // x - wkbBuffer.putDouble(offset, 10.0); - offset += 8; // y - wkbBuffer.putDouble(offset, 0.0); - offset += 8; // x - wkbBuffer.putDouble(offset, 0.0); - offset += 8; // y - wkbBuffer.putInt(offset, 1); - offset += 4; // num points - wkbBuffer.putDouble(offset, 36.0); - offset += 8; // x - wkbBuffer.putDouble(offset, 17.0); - offset += 8; // y - wkbBuffer.putInt(offset, 2); - offset += 4; // num points - wkbBuffer.putDouble(offset, 19.0); - offset += 8; // x - wkbBuffer.putDouble(offset, 19.0); - offset += 8; // y - wkbBuffer.putDouble(offset, -19.0); - offset += 8; // x - wkbBuffer.putDouble(offset, -19.0); - offset += 8; // y - wkbBuffer.putInt(offset, 4); - offset += 4; // num points - wkbBuffer.putDouble(offset, 23.0); - offset += 8; // x - wkbBuffer.putDouble(offset, 88); - offset += 8; // y - wkbBuffer.putDouble(offset, 13.0); - offset += 8; // x - wkbBuffer.putDouble(offset, 43.0); - offset += 8; // y - wkbBuffer.putDouble(offset, 59.0); - offset += 8; // x - wkbBuffer.putDouble(offset, 79.0); - offset += 8; // y - wkbBuffer.putDouble(offset, 83.0); - offset += 8; // x - wkbBuffer.putDouble(offset, 87.0); - offset += 8; // y - wkbBuffer.putInt(offset, 3); - offset += 4; // num points - wkbBuffer.putDouble(offset, 23.0); - offset += 8; // x - wkbBuffer.putDouble(offset, 88); - offset += 8; // y - wkbBuffer.putDouble(offset, 88); - offset += 8; // x - wkbBuffer.putDouble(offset, 43.0); - offset += 8; // y - wkbBuffer.putDouble(offset, 67.0); - offset += 8; // x - wkbBuffer.putDouble(offset, 79.0); - offset += 8; // y - wkbBuffer.putInt(offset, 0); - offset += 4; // num points - wkbBuffer.putInt(offset, 3); - offset += 4; // num points - wkbBuffer.putDouble(offset, 23.0); - offset += 8; // x - wkbBuffer.putDouble(offset, 88); - offset += 8; // y - wkbBuffer.putDouble(offset, 88); - offset += 8; // x - wkbBuffer.putDouble(offset, 43.0); - offset += 8; // y - wkbBuffer.putDouble(offset, 67.0); - offset += 8; // x - wkbBuffer.putDouble(offset, 88); - offset += 8; // y - wkbBuffer.putInt(offset, 2); - offset += 4; // num points - wkbBuffer.putDouble(offset, 23.0); - offset += 8; // x - wkbBuffer.putDouble(offset, 67.0); - offset += 8; // y - wkbBuffer.putDouble(offset, 43.0); - offset += 8; // x - wkbBuffer.putDouble(offset, 67.0); - offset += 8; // y - - Geometry p = importerWKB.execute(0, Geometry.Type.Polygon, wkbBuffer, null); - int pc = ((Polygon) p).getPathCount(); - String wktString = exporterWKT.execute(0, p, null); - assertTrue(wktString.equals("MULTIPOLYGON (((0 0, 10 10, 0 10, 0 0), (36 17, 36 17, 36 17), (19 19, -19 -19, 19 19), (23 88, 83 87, 59 79, 13 43, 23 88), (23 88, 67 79, 88 43, 23 88), (23 88, 67 88, 88 43, 23 88), (23 67, 43 67, 23 67)))")); - - wktString = exporterWKT.execute(WktExportFlags.wktExportPolygon, p, null); - assertTrue(wktString.equals("POLYGON ((0 0, 10 10, 0 10, 0 0), (36 17, 36 17, 36 17), (19 19, -19 -19, 19 19), (23 88, 83 87, 59 79, 13 43, 23 88), (23 88, 67 79, 88 43, 23 88), (23 88, 67 88, 88 43, 23 88), (23 67, 43 67, 23 67))")); - - Polygon polygon = makePolygon(); - - // Test Import Polygon from Polygon8 - ByteBuffer polygonWKBBuffer = exporterWKB.execute(0, polygon, null); - int wkbType = polygonWKBBuffer.getInt(1); - assertTrue(wkbType == WkbGeometryType.wkbMultiPolygonZM); - Geometry polygonWKBGeometry = importerWKB.execute(0, Geometry.Type.Polygon, polygonWKBBuffer, null); - TestCommonMethods.compareGeometryContent((MultiVertexGeometry) polygonWKBGeometry, polygon); - - // Test WKB_export_multi_polygon on nonempty single part polygon - Polygon polygon2 = makePolygon2(); - assertTrue(polygon2.getPathCount() == 1); - polygonWKBBuffer = exporterWKB.execute(WkbExportFlags.wkbExportMultiPolygon, polygon2, null); - polygonWKBGeometry = importerWKB.execute(0, Geometry.Type.Polygon, polygonWKBBuffer, null); - TestCommonMethods.compareGeometryContent((MultiVertexGeometry) polygonWKBGeometry, polygon2); - wkbType = polygonWKBBuffer.getInt(1); - assertTrue(wkbType == WkbGeometryType.wkbMultiPolygonZM); - - // Test WKB_export_polygon on nonempty single part polygon - assertTrue(polygon2.getPathCount() == 1); - polygonWKBBuffer = exporterWKB.execute(WkbExportFlags.wkbExportPolygon, polygon2, null); - polygonWKBGeometry = importerWKB.execute(0, Geometry.Type.Polygon, polygonWKBBuffer, null); - TestCommonMethods.compareGeometryContent((MultiVertexGeometry) polygonWKBGeometry, polygon2); - wkbType = polygonWKBBuffer.getInt(1); - assertTrue(wkbType == WkbGeometryType.wkbPolygonZM); - - // Test WKB_export_polygon on empty polygon - Polygon polygon3 = new Polygon(); - polygonWKBBuffer = exporterWKB.execute(WkbExportFlags.wkbExportPolygon, polygon3, null); - polygonWKBGeometry = importerWKB.execute(0, Geometry.Type.Polygon, polygonWKBBuffer, null); - assertTrue(polygonWKBGeometry.isEmpty() == true); - wkbType = polygonWKBBuffer.getInt(1); - assertTrue(wkbType == WkbGeometryType.wkbPolygon); - - // Test WKB_export_defaults on empty polygon - polygonWKBBuffer = exporterWKB.execute(0, polygon3, null); - polygonWKBGeometry = importerWKB.execute(0, Geometry.Type.Polygon, polygonWKBBuffer, null); - assertTrue(polygonWKBGeometry.isEmpty() == true); - wkbType = polygonWKBBuffer.getInt(1); - assertTrue(wkbType == WkbGeometryType.wkbMultiPolygon); - } - - @Test - public static void testImportExportWKBPolyline() { - OperatorExportToWkb exporterWKB = (OperatorExportToWkb) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ExportToWkb); - OperatorExportToWkt exporterWKT = (OperatorExportToWkt) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ExportToWkt); - OperatorImportFromWkb importerWKB = (OperatorImportFromWkb) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ImportFromWkb); - - // Test Import Polyline with bad paths (i.e. paths with one point or - // zero points) - int offset = 0; - ByteBuffer wkbBuffer = ByteBuffer.allocate(500).order(ByteOrder.nativeOrder()); - wkbBuffer.put(offset, (byte) WkbByteOrder.wkbNDR); - offset += 1; // byte order - wkbBuffer.putInt(offset, WkbGeometryType.wkbMultiLineString); - offset += 4; // type - wkbBuffer.putInt(offset, 4); - offset += 4; // num paths - wkbBuffer.put(offset, (byte) WkbByteOrder.wkbNDR); - offset += 1; // byte order - wkbBuffer.putInt(offset, WkbGeometryType.wkbLineString); - offset += 4; // type - wkbBuffer.putInt(offset, 1); - offset += 4; // num points - wkbBuffer.putDouble(offset, 36.0); - offset += 8; // x - wkbBuffer.putDouble(offset, 17.0); - offset += 8; // y - wkbBuffer.put(offset, (byte) WkbByteOrder.wkbNDR); - offset += 1; // byte order - wkbBuffer.putInt(offset, WkbGeometryType.wkbLineString); - offset += 4; // type - wkbBuffer.putInt(offset, 0); - offset += 4; // num points - wkbBuffer.put(offset, (byte) WkbByteOrder.wkbNDR); - offset += 1; // byte order - wkbBuffer.putInt(offset, WkbGeometryType.wkbLineString); - offset += 4; // type - wkbBuffer.putInt(offset, 1); - offset += 4; // num points - wkbBuffer.putDouble(offset, 19.0); - offset += 8; // x - wkbBuffer.putDouble(offset, 19.0); - offset += 8; // y - wkbBuffer.put(offset, (byte) WkbByteOrder.wkbNDR); - offset += 1; // byte order - wkbBuffer.putInt(offset, WkbGeometryType.wkbLineString); - offset += 4; // type - wkbBuffer.putInt(offset, 3); - offset += 4; // num points - wkbBuffer.putDouble(offset, 88); - offset += 8; // x - wkbBuffer.putDouble(offset, 29.0); - offset += 8; // y - wkbBuffer.putDouble(offset, 13.0); - offset += 8; // x - wkbBuffer.putDouble(offset, 43.0); - offset += 8; // y - wkbBuffer.putDouble(offset, 59.0); - offset += 8; // x - wkbBuffer.putDouble(offset, 88); - offset += 8; // y - - Polyline p = (Polyline) (importerWKB.execute(0, Geometry.Type.Polyline, wkbBuffer, null)); - int pc = p.getPointCount(); - int pac = p.getPathCount(); - assertTrue(p.getPointCount() == 7); - assertTrue(p.getPathCount() == 3); - - String wktString = exporterWKT.execute(0, p, null); - assertTrue(wktString.equals("MULTILINESTRING ((36 17, 36 17), (19 19, 19 19), (88 29, 13 43, 59 88))")); - - Polyline polyline = makePolyline(); - polyline.dropAttribute(VertexDescription.Semantics.ID); - - // Test Import Polyline from Polyline - ByteBuffer polylineWKBBuffer = exporterWKB.execute(0, polyline, null); - int wkbType = polylineWKBBuffer.getInt(1); - assertTrue(wkbType == WkbGeometryType.wkbMultiLineStringZM); - Geometry polylineWKBGeometry = importerWKB.execute(0, Geometry.Type.Polyline, polylineWKBBuffer, null); - TestCommonMethods.compareGeometryContent((MultiVertexGeometry) polylineWKBGeometry, polyline); - - // Test wkbExportMultiPolyline on nonempty single part polyline - Polyline polyline2 = makePolyline2(); - assertTrue(polyline2.getPathCount() == 1); - polylineWKBBuffer = exporterWKB.execute(WkbExportFlags.wkbExportMultiLineString, polyline2, null); - polylineWKBGeometry = importerWKB.execute(0, Geometry.Type.Polyline, polylineWKBBuffer, null); - TestCommonMethods.compareGeometryContent((MultiVertexGeometry) polylineWKBGeometry, polyline2); - wkbType = polylineWKBBuffer.getInt(1); - assertTrue(wkbType == WkbGeometryType.wkbMultiLineStringZM); - - // Test wkbExportPolyline on nonempty single part polyline - assertTrue(polyline2.getPathCount() == 1); - polylineWKBBuffer = exporterWKB.execute(WkbExportFlags.wkbExportLineString, polyline2, null); - polylineWKBGeometry = importerWKB.execute(0, Geometry.Type.Polyline, polylineWKBBuffer, null); - TestCommonMethods.compareGeometryContent((MultiVertexGeometry) polylineWKBGeometry, polyline2); - wkbType = polylineWKBBuffer.getInt(1); - assertTrue(wkbType == WkbGeometryType.wkbLineStringZM); - - // Test wkbExportPolyline on empty polyline - Polyline polyline3 = new Polyline(); - polylineWKBBuffer = exporterWKB.execute(WkbExportFlags.wkbExportLineString, polyline3, null); - polylineWKBGeometry = importerWKB.execute(0, Geometry.Type.Polyline, polylineWKBBuffer, null); - assertTrue(polylineWKBGeometry.isEmpty() == true); - wkbType = polylineWKBBuffer.getInt(1); - assertTrue(wkbType == WkbGeometryType.wkbLineString); - - // Test WKB_export_defaults on empty polyline - polylineWKBBuffer = exporterWKB.execute(0, polyline3, null); - polylineWKBGeometry = importerWKB.execute(0, Geometry.Type.Polyline, polylineWKBBuffer, null); - assertTrue(polylineWKBGeometry.isEmpty() == true); - wkbType = polylineWKBBuffer.getInt(1); - assertTrue(wkbType == WkbGeometryType.wkbMultiLineString); - } - - @Test - public static void testImportExportWKBMultiPoint() { - OperatorExportToWkb exporterWKB = (OperatorExportToWkb) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ExportToWkb); - OperatorImportFromWkb importerWKB = (OperatorImportFromWkb) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ImportFromWkb); - - MultiPoint multipoint = makeMultiPoint(); - multipoint.dropAttribute(VertexDescription.Semantics.ID); - - // Test Import Multi_point from Multi_point - ByteBuffer multipointWKBBuffer = exporterWKB.execute(0, multipoint, null); - int wkbType = multipointWKBBuffer.getInt(1); - assertTrue(wkbType == WkbGeometryType.wkbMultiPointZ); - MultiPoint multipointWKBGeometry = (MultiPoint) (importerWKB.execute(0, Geometry.Type.MultiPoint, multipointWKBBuffer, null)); - TestCommonMethods.compareGeometryContent((MultiVertexGeometry) multipointWKBGeometry, multipoint); - - // Test WKB_export_point on nonempty single point Multi_point - MultiPoint multipoint2 = makeMultiPoint2(); - assertTrue(multipoint2.getPointCount() == 1); - ByteBuffer pointWKBBuffer = exporterWKB.execute(WkbExportFlags.wkbExportPoint, multipoint2, null); - Point pointWKBGeometry = (Point) (importerWKB.execute(0, Geometry.Type.Point, pointWKBBuffer, null)); - Point3D point3d, mpoint3d; - point3d = pointWKBGeometry.getXYZ(); - mpoint3d = multipoint2.getXYZ(0); - assertTrue(point3d.x == mpoint3d.x && point3d.y == mpoint3d.y && point3d.z == mpoint3d.z); - wkbType = pointWKBBuffer.getInt(1); - assertTrue(wkbType == WkbGeometryType.wkbPointZ); - - // Test WKB_export_point on empty Multi_point - MultiPoint multipoint3 = new MultiPoint(); - pointWKBBuffer = exporterWKB.execute(WkbExportFlags.wkbExportPoint, multipoint3, null); - pointWKBGeometry = (Point) (importerWKB.execute(0, Geometry.Type.Point, pointWKBBuffer, null)); - assertTrue(pointWKBGeometry.isEmpty() == true); - wkbType = pointWKBBuffer.getInt(1); - assertTrue(wkbType == WkbGeometryType.wkbPoint); - - // Test WKB_export_defaults on empty Multi_point - multipointWKBBuffer = exporterWKB.execute(0, multipoint3, null); - multipointWKBGeometry = (MultiPoint) (importerWKB.execute(0, Geometry.Type.MultiPoint, multipointWKBBuffer, null)); - assertTrue(multipointWKBGeometry.isEmpty() == true); - wkbType = multipointWKBBuffer.getInt(1); - assertTrue(wkbType == WkbGeometryType.wkbMultiPoint); - } - - @Test - public static void testImportExportWKBPoint() { - OperatorExportToWkb exporterWKB = (OperatorExportToWkb) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ExportToWkb); - OperatorImportFromWkb importerWKB = (OperatorImportFromWkb) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ImportFromWkb); - - // Point - Point point = makePoint(); - - // Test Import Point from Point - ByteBuffer pointWKBBuffer = exporterWKB.execute(0, point, null); - int wkbType = pointWKBBuffer.getInt(1); - assertTrue(wkbType == WkbGeometryType.wkbPointZM); - Point pointWKBGeometry = (Point) (importerWKB.execute(0, Geometry.Type.Point, pointWKBBuffer, null)); - - double x_1 = point.getX(); - double x2 = pointWKBGeometry.getX(); - assertTrue(x_1 == x2); - - double y1 = point.getY(); - double y2 = pointWKBGeometry.getY(); - assertTrue(y1 == y2); - - double z_1 = point.getZ(); - double z_2 = pointWKBGeometry.getZ(); - assertTrue(z_1 == z_2); - - double m1 = point.getM(); - double m2 = pointWKBGeometry.getM(); - assertTrue(m1 == m2); - - // Test WKB_export_defaults on empty point - Point point2 = new Point(); - pointWKBBuffer = exporterWKB.execute(0, point2, null); - pointWKBGeometry = (Point) (importerWKB.execute(0, Geometry.Type.Point, pointWKBBuffer, null)); - assertTrue(pointWKBGeometry.isEmpty() == true); - wkbType = pointWKBBuffer.getInt(1); - assertTrue(wkbType == WkbGeometryType.wkbPoint); - - // Test WKB_export_point on empty point - pointWKBBuffer = exporterWKB.execute(WkbExportFlags.wkbExportPoint, point2, null); - pointWKBGeometry = (Point) (importerWKB.execute(0, Geometry.Type.Point, pointWKBBuffer, null)); - assertTrue(pointWKBGeometry.isEmpty() == true); - wkbType = pointWKBBuffer.getInt(1); - assertTrue(wkbType == WkbGeometryType.wkbPoint); - - // Test WKB_export_multi_point on empty point - MultiPoint multipoint = new MultiPoint(); - ByteBuffer multipointWKBBuffer = exporterWKB.execute(WkbExportFlags.wkbExportMultiPoint, multipoint, null); - MultiPoint multipointWKBGeometry = (MultiPoint) (importerWKB.execute(0, Geometry.Type.MultiPoint, multipointWKBBuffer, null)); - assertTrue(multipointWKBGeometry.isEmpty() == true); - wkbType = multipointWKBBuffer.getInt(1); - assertTrue(wkbType == WkbGeometryType.wkbMultiPoint); - - // Test WKB_export_point on nonempty single point Multi_point - MultiPoint multipoint2 = makeMultiPoint2(); - assertTrue(multipoint2.getPointCount() == 1); - pointWKBBuffer = exporterWKB.execute(WkbExportFlags.wkbExportPoint, multipoint2, null); - pointWKBGeometry = (Point) (importerWKB.execute(0, Geometry.Type.Point, pointWKBBuffer, null)); - Point3D point3d, mpoint3d; - point3d = pointWKBGeometry.getXYZ(); - mpoint3d = multipoint2.getXYZ(0); - assertTrue(point3d.x == mpoint3d.x && point3d.y == mpoint3d.y && point3d.z == mpoint3d.z); - wkbType = pointWKBBuffer.getInt(1); - assertTrue(wkbType == WkbGeometryType.wkbPointZ); - } - - @Test - public static void testImportExportWKBEnvelope() { - OperatorExportToWkb exporterWKB = (OperatorExportToWkb) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ExportToWkb); - OperatorImportFromWkb importerWKB = (OperatorImportFromWkb) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ImportFromWkb); - - // Test Export Envelope to Polygon (WKB_export_defaults) - Envelope envelope = makeEnvelope(); - envelope.dropAttribute(VertexDescription.Semantics.ID); - - ByteBuffer polygonWKBBuffer = exporterWKB.execute(0, envelope, null); - int wkbType = polygonWKBBuffer.getInt(1); - assertTrue(wkbType == WkbGeometryType.wkbPolygonZM); - Polygon polygon = (Polygon) (importerWKB.execute(0, Geometry.Type.Polygon, polygonWKBBuffer, null)); - int point_count = polygon.getPointCount(); - assertTrue(point_count == 4); - - Envelope2D env = new Envelope2D(); - Envelope1D interval; - - envelope.queryEnvelope2D(env); - interval = envelope.queryInterval(VertexDescription.Semantics.Z, 0); - Point3D point3d; - point3d = polygon.getXYZ(0); - assertTrue(point3d.x == env.xmin && point3d.y == env.ymin && point3d.z == interval.vmin); - point3d = polygon.getXYZ(1); - assertTrue(point3d.x == env.xmin && point3d.y == env.ymax && point3d.z == interval.vmax); - point3d = polygon.getXYZ(2); - assertTrue(point3d.x == env.xmax && point3d.y == env.ymax && point3d.z == interval.vmin); - point3d = polygon.getXYZ(3); - assertTrue(point3d.x == env.xmax && point3d.y == env.ymin && point3d.z == interval.vmax); - - interval = envelope.queryInterval(VertexDescription.Semantics.M, 0); - double m = polygon.getAttributeAsDbl(VertexDescription.Semantics.M, 0, 0); - assertTrue(m == interval.vmin); - m = polygon.getAttributeAsDbl(VertexDescription.Semantics.M, 1, 0); - assertTrue(m == interval.vmax); - m = polygon.getAttributeAsDbl(VertexDescription.Semantics.M, 2, 0); - assertTrue(m == interval.vmin); - m = polygon.getAttributeAsDbl(VertexDescription.Semantics.M, 3, 0); - assertTrue(m == interval.vmax); - - // Test WKB_export_multi_polygon on nonempty Envelope - polygonWKBBuffer = exporterWKB.execute(WkbExportFlags.wkbExportMultiPolygon, envelope, null); - wkbType = polygonWKBBuffer.getInt(1); - assertTrue(wkbType == WkbGeometryType.wkbMultiPolygonZM); - polygon = (Polygon) (importerWKB.execute(0, Geometry.Type.Polygon, polygonWKBBuffer, null)); - point_count = polygon.getPointCount(); - assertTrue(point_count == 4); - - envelope.queryEnvelope2D(env); - interval = envelope.queryInterval(VertexDescription.Semantics.Z, 0); - point3d = polygon.getXYZ(0); - assertTrue(point3d.x == env.xmin && point3d.y == env.ymin && point3d.z == interval.vmin); - point3d = polygon.getXYZ(1); - assertTrue(point3d.x == env.xmin && point3d.y == env.ymax && point3d.z == interval.vmax); - point3d = polygon.getXYZ(2); - assertTrue(point3d.x == env.xmax && point3d.y == env.ymax && point3d.z == interval.vmin); - point3d = polygon.getXYZ(3); - assertTrue(point3d.x == env.xmax && point3d.y == env.ymin && point3d.z == interval.vmax); - - interval = envelope.queryInterval(VertexDescription.Semantics.M, 0); - m = polygon.getAttributeAsDbl(VertexDescription.Semantics.M, 0, 0); - assertTrue(m == interval.vmin); - m = polygon.getAttributeAsDbl(VertexDescription.Semantics.M, 1, 0); - assertTrue(m == interval.vmax); - m = polygon.getAttributeAsDbl(VertexDescription.Semantics.M, 2, 0); - assertTrue(m == interval.vmin); - m = polygon.getAttributeAsDbl(VertexDescription.Semantics.M, 3, 0); - assertTrue(m == interval.vmax); - - // Test WKB_export_defaults on empty Envelope - Envelope envelope2 = new Envelope(); - polygonWKBBuffer = exporterWKB.execute(0, envelope2, null); - wkbType = polygonWKBBuffer.getInt(1); - assertTrue(wkbType == WkbGeometryType.wkbPolygon); - polygon = (Polygon) (importerWKB.execute(0, Geometry.Type.Polygon, polygonWKBBuffer, null)); - assertTrue(polygon.isEmpty()); - - // Test WKB_export_polygon on empty Envelope - polygonWKBBuffer = exporterWKB.execute(WkbExportFlags.wkbExportPolygon, envelope2, null); - wkbType = polygonWKBBuffer.getInt(1); - assertTrue(wkbType == WkbGeometryType.wkbPolygon); - polygon = (Polygon) (importerWKB.execute(0, Geometry.Type.Polygon, polygonWKBBuffer, null)); - assertTrue(polygon.isEmpty()); - } - - @Test - public static void testImportExportWktGeometryCollection() { - OperatorImportFromWkt importerWKT = (OperatorImportFromWkt) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ImportFromWkt); - OperatorExportToWkt exporterWKT = (OperatorExportToWkt) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ExportToWkt); - - String wktString; - Envelope2D envelope = new Envelope2D(); - WktParser wktParser = new WktParser(); - - wktString = "GeometryCollection( Point (0 0), GeometryCollection( Point (0 0) , Point (1 1) , Point (2 2), LineString empty ), Point (1 1), Point (2 2) )"; - OGCStructure structure = importerWKT.executeOGC(0, wktString, null).m_structures.get(0); - - assertTrue(structure.m_type == 7); - assertTrue(structure.m_structures.get(0).m_type == 1); - assertTrue(structure.m_structures.get(0).m_type == 1); - assertTrue(structure.m_structures.get(1).m_type == 7); - assertTrue(structure.m_structures.get(2).m_type == 1); - assertTrue(structure.m_structures.get(3).m_type == 1); - - assertTrue(structure.m_structures.get(1).m_structures.get(0).m_type == 1); - assertTrue(structure.m_structures.get(1).m_structures.get(1).m_type == 1); - assertTrue(structure.m_structures.get(1).m_structures.get(2).m_type == 1); - assertTrue(structure.m_structures.get(1).m_structures.get(3).m_type == 2); - } - - @Test - public static void testImportExportWktMultiPolygon() { - OperatorImportFromWkt importerWKT = (OperatorImportFromWkt) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ImportFromWkt); - OperatorExportToWkt exporterWKT = (OperatorExportToWkt) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ExportToWkt); - - Polygon polygon; - String wktString; - Envelope2D envelope = new Envelope2D(); - WktParser wktParser = new WktParser(); - - // Test Import from MultiPolygon - wktString = "Multipolygon M empty"; - polygon = (Polygon) importerWKT.execute(0, Geometry.Type.Polygon, wktString, null); - assertTrue(polygon != null); - assertTrue(polygon.isEmpty()); - assertTrue(polygon.hasAttribute(VertexDescription.Semantics.M)); - - polygon = (Polygon) GeometryEngine.geometryFromWkt(wktString, 0, Geometry.Type.Unknown); - assertTrue(polygon != null); - assertTrue(polygon.isEmpty()); - assertTrue(polygon.hasAttribute(VertexDescription.Semantics.M)); - - wktString = exporterWKT.execute(0, polygon, null); - assertTrue(wktString.equals("MULTIPOLYGON M EMPTY")); - - wktString = GeometryEngine.geometryToWkt(polygon, 0); - assertTrue(wktString.equals("MULTIPOLYGON M EMPTY")); - - wktString = "Multipolygon Z (empty, (empty, (10 10 5, 20 10 5, 20 20 5, 10 20 5, 10 10 5), (12 12 3), empty, (10 10 1, 12 12 1)), empty, ((90 90 88, 60 90 7, 60 60 7), empty, (70 70 7, 80 80 7, 70 80 7, 70 70 7)), empty)"; - polygon = (Polygon) (importerWKT.execute(0, Geometry.Type.Polygon, wktString, null)); - assertTrue(polygon != null); - polygon.queryEnvelope2D(envelope); - assertTrue(envelope.xmin == 10 && envelope.xmax == 90 && envelope.ymin == 10 && envelope.ymax == 90); - assertTrue(polygon.getPointCount() == 14); - assertTrue(polygon.getPathCount() == 5); - // assertTrue(polygon.calculate_area_2D() > 0.0); - assertTrue(polygon.hasAttribute(VertexDescription.Semantics.Z)); - - double z = polygon.getAttributeAsDbl(VertexDescription.Semantics.Z, 0, 0); - assertTrue(z == 5); - - // Test Export to WKT MultiPolygon - wktString = exporterWKT.execute(0, polygon, null); - assertTrue(wktString.equals("MULTIPOLYGON Z (((10 10 5, 20 10 5, 20 20 5, 10 20 5, 10 10 5), (12 12 3, 12 12 3, 12 12 3), (10 10 1, 12 12 1, 10 10 1)), ((90 90 88, 60 90 7, 60 60 7, 90 90 88), (70 70 7, 70 80 7, 80 80 7, 70 70 7)))")); - wktParser.resetParser(wktString); - while (wktParser.nextToken() != WktParser.WktToken.not_available) { - } - - // Test import Polygon - wktString = "POLYGON z (EMPTY, EMPTY, (10 10 5, 10 20 5, 20 20 5, 20 10 5), (12 12 3), EMPTY, (10 10 1, 12 12 1), EMPTY, (60 60 7, 60 90 7, 90 90 7, 60 60 7), EMPTY, (70 70 7, 70 80 7, 80 80 7), EMPTY)"; - polygon = (Polygon) (importerWKT.execute(0, Geometry.Type.Polygon, wktString, null)); - assertTrue(polygon != null); - assertTrue(polygon.getPointCount() == 14); - assertTrue(polygon.getPathCount() == 5); - assertTrue(polygon.hasAttribute(VertexDescription.Semantics.Z)); - - // Test Export to WKT Polygon - wktString = exporterWKT.execute(WktExportFlags.wktExportPolygon, polygon, null); - assertTrue(wktString.equals("POLYGON Z ((10 10 5, 20 10 5, 20 20 5, 10 20 5, 10 10 5), (12 12 3, 12 12 3, 12 12 3), (10 10 1, 12 12 1, 10 10 1), (60 60 7, 60 90 7, 90 90 7, 60 60 7), (70 70 7, 70 80 7, 80 80 7, 70 70 7))")); - wktParser.resetParser(wktString); - while (wktParser.nextToken() != WktParser.WktToken.not_available) { - } - - Envelope env = new Envelope(); - env.addAttribute(VertexDescription.Semantics.Z); - polygon.queryEnvelope(env); - - wktString = exporterWKT.execute(0, env, null); - assertTrue(wktString.equals("POLYGON Z ((10 10 1, 90 10 7, 90 90 1, 10 90 7, 10 10 1))")); - wktParser.resetParser(wktString); - while (wktParser.nextToken() != WktParser.WktToken.not_available) { - } - - wktString = exporterWKT.execute(WktExportFlags.wktExportMultiPolygon, env, null); - assertTrue(wktString.equals("MULTIPOLYGON Z (((10 10 1, 90 10 7, 90 90 1, 10 90 7, 10 10 1)))")); - wktParser.resetParser(wktString); - while (wktParser.nextToken() != WktParser.WktToken.not_available) { - } - - env.setEmpty(); - - wktString = exporterWKT.execute(0, env, null); - assertTrue(wktString.equals("POLYGON Z EMPTY")); - wktParser.resetParser(wktString); - while (wktParser.nextToken() != WktParser.WktToken.not_available) { - } - - wktString = exporterWKT.execute(WktExportFlags.wktExportMultiPolygon, env, null); - assertTrue(wktString.equals("MULTIPOLYGON Z EMPTY")); - wktParser.resetParser(wktString); - while (wktParser.nextToken() != WktParser.WktToken.not_available) { - } - - wktString = "MULTIPOLYGON (((5 10, 8 10, 10 10, 10 0, 0 0, 0 10, 2 10, 5 10)))"; // ring - // is - // oriented - // clockwise - polygon = (Polygon) (importerWKT.execute(0, Geometry.Type.Polygon, wktString, null)); - assertTrue(polygon != null); - assertTrue(polygon.calculateArea2D() > 0); - - wktString = "MULTIPOLYGON Z (((90 10 7, 10 10 1, 10 90 7, 90 90 1, 90 10 7)))"; // ring - // is - // oriented - // clockwise - polygon = (Polygon) (importerWKT.execute(0, Geometry.Type.Polygon, wktString, null)); - assertTrue(polygon != null); - assertTrue(polygon.getPointCount() == 4); - assertTrue(polygon.getPathCount() == 1); - assertTrue(polygon.hasAttribute(VertexDescription.Semantics.Z)); - assertTrue(polygon.calculateArea2D() > 0); - - wktString = exporterWKT.execute(WktExportFlags.wktExportMultiPolygon, polygon, null); - assertTrue(wktString.equals("MULTIPOLYGON Z (((90 10 7, 90 90 1, 10 90 7, 10 10 1, 90 10 7)))")); - } - - @Test - public static void testImportExportWktPolygon() { - OperatorImportFromWkt importerWKT = (OperatorImportFromWkt) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ImportFromWkt); - // OperatorExportToWkt exporterWKT = - // (OperatorExportToWkt)OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ExportToWkt); - - Polygon polygon; - String wktString; - Envelope2D envelope = new Envelope2D(); - - // Test Import from Polygon - wktString = "Polygon ZM empty"; - polygon = (Polygon) (importerWKT.execute(0, Geometry.Type.Unknown, wktString, null)); - assertTrue(polygon != null); - assertTrue(polygon.isEmpty()); - assertTrue(polygon.hasAttribute(VertexDescription.Semantics.Z)); - assertTrue(polygon.hasAttribute(VertexDescription.Semantics.M)); - - wktString = "Polygon z (empty, (10 10 5, 20 10 5, 20 20 5, 10 20 5, 10 10 5), (12 12 3), empty, (10 10 1, 12 12 1))"; - polygon = (Polygon) (importerWKT.execute(0, Geometry.Type.Unknown, wktString, null)); - assertTrue(polygon != null); - polygon.queryEnvelope2D(envelope); - assertTrue(envelope.xmin == 10 && envelope.xmax == 20 && envelope.ymin == 10 && envelope.ymax == 20); - assertTrue(polygon.getPointCount() == 8); - assertTrue(polygon.getPathCount() == 3); - assertTrue(polygon.hasAttribute(VertexDescription.Semantics.Z)); - - wktString = "polygon ((35 10, 10 20, 15 40, 45 45, 35 10), (20 30, 35 35, 30 20, 20 30))"; - Polygon polygon2 = (Polygon) (importerWKT.execute(0, Geometry.Type.Unknown, wktString, null)); - assertTrue(polygon2 != null); - - // wktString = exporterWKT.execute(0, *polygon2, null); - } - - @Test - public static void testImportExportWktLineString() { - OperatorImportFromWkt importerWKT = (OperatorImportFromWkt) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ImportFromWkt); - // OperatorExportToWkt exporterWKT = - // (OperatorExportToWkt)OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ExportToWkt); - - Polyline polyline; - String wktString; - Envelope2D envelope = new Envelope2D(); - - // Test Import from LineString - wktString = "LineString ZM empty"; - polyline = (Polyline) (importerWKT.execute(0, Geometry.Type.Unknown, wktString, null)); - assertTrue(polyline != null); - assertTrue(polyline.isEmpty()); - assertTrue(polyline.hasAttribute(VertexDescription.Semantics.Z)); - assertTrue(polyline.hasAttribute(VertexDescription.Semantics.M)); - - wktString = "LineString m (10 10 5, 10 20 5, 20 20 5, 20 10 5)"; - polyline = (Polyline) (importerWKT.execute(0, Geometry.Type.Unknown, wktString, null)); - assertTrue(polyline != null); - polyline.queryEnvelope2D(envelope); - assertTrue(envelope.xmin == 10 && envelope.xmax == 20 && envelope.ymin == 10 && envelope.ymax == 20); - assertTrue(polyline.getPointCount() == 4); - assertTrue(polyline.getPathCount() == 1); - assertTrue(polyline.hasAttribute(VertexDescription.Semantics.M)); - } - - @Test - public static void testImportExportWktMultiLineString() { - OperatorImportFromWkt importerWKT = (OperatorImportFromWkt) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ImportFromWkt); - OperatorExportToWkt exporterWKT = (OperatorExportToWkt) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ExportToWkt); - - Polyline polyline; - String wktString; - Envelope2D envelope = new Envelope2D(); - WktParser wktParser = new WktParser(); - - // Test Import from MultiLineString - wktString = "MultiLineStringZMempty"; - polyline = (Polyline) (importerWKT.execute(0, Geometry.Type.Unknown, wktString, null)); - assertTrue(polyline != null); - assertTrue(polyline.isEmpty()); - assertTrue(polyline.hasAttribute(VertexDescription.Semantics.Z)); - assertTrue(polyline.hasAttribute(VertexDescription.Semantics.M)); - - wktString = "MultiLineStringm(empty, empty, (10 10 5, 10 20 5, 20 88 5, 20 10 5), (12 88 3), empty, (10 10 1, 12 12 1), empty, (88 60 7, 60 90 7, 90 90 7), empty, (70 70 7, 70 80 7, 80 80 7), empty)"; - polyline = (Polyline) (importerWKT.execute(0, Geometry.Type.Unknown, wktString, null)); - assertTrue(polyline != null); - polyline.queryEnvelope2D(envelope); - assertTrue(envelope.xmin == 10 && envelope.xmax == 90 && envelope.ymin == 10 && envelope.ymax == 90); - assertTrue(polyline.getPointCount() == 14); - assertTrue(polyline.getPathCount() == 5); - assertTrue(polyline.hasAttribute(VertexDescription.Semantics.M)); - - wktString = exporterWKT.execute(0, polyline, null); - assertTrue(wktString.equals("MULTILINESTRING M ((10 10 5, 10 20 5, 20 88 5, 20 10 5), (12 88 3, 12 88 3), (10 10 1, 12 12 1), (88 60 7, 60 90 7, 90 90 7), (70 70 7, 70 80 7, 80 80 7))")); - wktParser.resetParser(wktString); - while (wktParser.nextToken() != WktParser.WktToken.not_available) { - } - - // Test Import LineString - wktString = "Linestring Z(10 10 5, 10 20 5, 20 20 5, 20 10 5)"; - polyline = (Polyline) (importerWKT.execute(0, Geometry.Type.Unknown, wktString, null)); - assertTrue(polyline.getPointCount() == 4); - wktString = exporterWKT.execute(WktExportFlags.wktExportLineString, polyline, null); - assertTrue(wktString.equals("LINESTRING Z (10 10 5, 10 20 5, 20 20 5, 20 10 5)")); - wktParser.resetParser(wktString); - while (wktParser.nextToken() != WktParser.WktToken.not_available) { - } - - wktString = exporterWKT.execute(0, polyline, null); - assertTrue(wktString.equals("MULTILINESTRING Z ((10 10 5, 10 20 5, 20 20 5, 20 10 5))")); - wktParser.resetParser(wktString); - while (wktParser.nextToken() != WktParser.WktToken.not_available) { - } - } - - @Test - public static void testImportExportWktMultiPoint() { - OperatorImportFromWkt importerWKT = (OperatorImportFromWkt) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ImportFromWkt); - OperatorExportToWkt exporterWKT = (OperatorExportToWkt) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ExportToWkt); - - MultiPoint multipoint; - String wktString; - Envelope2D envelope = new Envelope2D(); - WktParser wktParser = new WktParser(); - - // Test Import from Multi_point - wktString = " MultiPoint ZM empty"; - multipoint = (MultiPoint) (importerWKT.execute(0, Geometry.Type.Unknown, wktString, null)); - assertTrue(multipoint != null); - assertTrue(multipoint.isEmpty()); - assertTrue(multipoint.hasAttribute(VertexDescription.Semantics.Z)); - assertTrue(multipoint.hasAttribute(VertexDescription.Semantics.M)); - - wktString = exporterWKT.execute(0, multipoint, null); - assertTrue(wktString.equals("MULTIPOINT ZM EMPTY")); - wktParser.resetParser(wktString); - while (wktParser.nextToken() != WktParser.WktToken.not_available) { - } - - wktString = exporterWKT.execute(WktExportFlags.wktExportPoint, multipoint, null); - assertTrue(wktString.equals("POINT ZM EMPTY")); - wktParser.resetParser(wktString); - while (wktParser.nextToken() != WktParser.WktToken.not_available) { - } - - multipoint = new MultiPoint(); - multipoint.add(118.15114354234563, 33.82234433423462345); - multipoint.add(88, 88); - - wktString = exporterWKT.execute(WktExportFlags.wktExportPrecision10, multipoint, null); - assertTrue(wktString.equals("MULTIPOINT ((118.1511435 33.82234433), (88 88))")); - wktParser.resetParser(wktString); - while (wktParser.nextToken() != WktParser.WktToken.not_available) { - } - - multipoint = new MultiPoint(); - multipoint.add(88, 2); - multipoint.add(88, 88); - - wktString = exporterWKT.execute(0, multipoint, null); - assertTrue(wktString.equals("MULTIPOINT ((88 2), (88 88))")); - wktParser.resetParser(wktString); - while (wktParser.nextToken() != WktParser.WktToken.not_available) { - } - - wktString = "Multipoint zm (empty, empty, (10 88 88 33), (10 20 5 33), (20 20 5 33), (20 10 5 33), (12 12 3 33), empty, (10 10 1 33), (12 12 1 33), empty, (60 60 7 33), (60 90.1 7 33), (90 90 7 33), empty, (70 70 7 33), (70 80 7 33), (80 80 7 33), empty)"; - multipoint = (MultiPoint) (importerWKT.execute(0, Geometry.Type.Unknown, wktString, null)); - assertTrue(multipoint != null); - multipoint.queryEnvelope2D(envelope); - // assertTrue(envelope.xmin == 10 && envelope.xmax == 90 && - // envelope.ymin == 10 && Math.abs(envelope.ymax - 90.1) <= 0.001); - assertTrue(multipoint.getPointCount() == 13); - assertTrue(multipoint.hasAttribute(VertexDescription.Semantics.Z)); - assertTrue(multipoint.hasAttribute(VertexDescription.Semantics.M)); - - wktString = "Multipoint zm (10 88 88 33, 10 20 5 33, 20 20 5 33, 20 10 5 33, 12 12 3 33, 10 10 1 33, 12 12 1 33, 60 60 7 33, 60 90.1 7 33, 90 90 7 33, 70 70 7 33, 70 80 7 33, 80 80 7 33)"; - multipoint = (MultiPoint) (importerWKT.execute(0, Geometry.Type.Unknown, wktString, null)); - assertTrue(multipoint != null); - // assertTrue(envelope.xmin == 10 && envelope.xmax == 90 && - // envelope.ymin == 10 && ::fabs(envelope.ymax - 90.1) <= 0.001); - assertTrue(multipoint.getPointCount() == 13); - assertTrue(multipoint.hasAttribute(VertexDescription.Semantics.Z)); - assertTrue(multipoint.hasAttribute(VertexDescription.Semantics.M)); - - wktString = exporterWKT.execute(WktExportFlags.wktExportPrecision15, multipoint, null); - assertTrue(wktString.equals("MULTIPOINT ZM ((10 88 88 33), (10 20 5 33), (20 20 5 33), (20 10 5 33), (12 12 3 33), (10 10 1 33), (12 12 1 33), (60 60 7 33), (60 90.1 7 33), (90 90 7 33), (70 70 7 33), (70 80 7 33), (80 80 7 33))")); - wktParser.resetParser(wktString); - while (wktParser.nextToken() != WktParser.WktToken.not_available) { - } - - wktString = "Multipoint zm (empty, empty, (10 10 5 33))"; - multipoint = (MultiPoint) (importerWKT.execute(0, Geometry.Type.Unknown, wktString, null)); - - wktString = exporterWKT.execute(WktExportFlags.wktExportPoint, multipoint, null); - assertTrue(wktString.equals("POINT ZM (10 10 5 33)")); - wktParser.resetParser(wktString); - while (wktParser.nextToken() != WktParser.WktToken.not_available) { - } - } - - @Test - public static void testImportExportWktPoint() { - OperatorImportFromWkt importerWKT = (OperatorImportFromWkt) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ImportFromWkt); - OperatorExportToWkt exporterWKT = (OperatorExportToWkt) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ExportToWkt); - - Point point; - String wktString; - WktParser wktParser = new WktParser(); - - // Test Import from Point - wktString = "Point ZM empty"; - point = (Point) (importerWKT.execute(0, Geometry.Type.Unknown, wktString, null)); - assertTrue(point != null); - assertTrue(point.isEmpty()); - assertTrue(point.hasAttribute(VertexDescription.Semantics.Z)); - assertTrue(point.hasAttribute(VertexDescription.Semantics.M)); - - wktString = exporterWKT.execute(0, point, null); - assertTrue(wktString.equals("POINT ZM EMPTY")); - wktParser.resetParser(wktString); - while (wktParser.nextToken() != WktParser.WktToken.not_available) { - } - - wktString = exporterWKT.execute(WktExportFlags.wktExportMultiPoint, point, null); - assertTrue(wktString.equals("MULTIPOINT ZM EMPTY")); - wktParser.resetParser(wktString); - while (wktParser.nextToken() != WktParser.WktToken.not_available) { - } - - wktString = "Point zm (30.1 10.6 5.1 33.1)"; - point = (Point) (importerWKT.execute(0, Geometry.Type.Unknown, wktString, null)); - assertTrue(point != null); - assertTrue(point.hasAttribute(VertexDescription.Semantics.Z)); - assertTrue(point.hasAttribute(VertexDescription.Semantics.M)); - double x = point.getX(); - double y = point.getY(); - double z = point.getZ(); - double m = point.getM(); - - assertTrue(x == 30.1); - assertTrue(y == 10.6); - assertTrue(z == 5.1); - assertTrue(m == 33.1); - - wktString = exporterWKT.execute(WktExportFlags.wktExportPrecision15, point, null); - assertTrue(wktString.equals("POINT ZM (30.1 10.6 5.1 33.1)")); - wktParser.resetParser(wktString); - while (wktParser.nextToken() != WktParser.WktToken.not_available) { - } - - wktString = exporterWKT.execute(WktExportFlags.wktExportMultiPoint | WktExportFlags.wktExportPrecision15, point, null); - assertTrue(wktString.equals("MULTIPOINT ZM ((30.1 10.6 5.1 33.1))")); - wktParser.resetParser(wktString); - while (wktParser.nextToken() != WktParser.WktToken.not_available) { - } - } - - @Deprecated - @Test - public static void testImportGeoJsonGeometryCollection() { - OperatorImportFromGeoJson importer = (OperatorImportFromGeoJson) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ImportFromGeoJson); - - String geoJsonString; - Envelope2D envelope = new Envelope2D(); - WktParser wktParser = new WktParser(); - - geoJsonString = "{\"type\" : \"GeometryCollection\", \"geometries\" : [{\"type\" : \"Point\", \"coordinates\": [0,0]}, {\"type\" : \"GeometryCollection\" , \"geometries\" : [ {\"type\" : \"Point\", \"coordinates\" : [0, 0]} , {\"type\" : \"Point\", \"coordinates\" : [1, 1]} ,{ \"type\" : \"Point\", \"coordinates\" : [2, 2]}, {\"type\" : \"LineString\", \"coordinates\" : []}]} , {\"type\" : \"Point\", \"coordinates\" : [1, 1]}, {\"type\" : \"Point\" , \"coordinates\" : [2, 2]} ] }"; - OGCStructure structure = importer.executeOGC(0, geoJsonString, null).m_ogcStructure.m_structures.get(0); - - assertTrue(structure.m_type == 7); - assertTrue(structure.m_structures.get(0).m_type == 1); - assertTrue(structure.m_structures.get(0).m_type == 1); - assertTrue(structure.m_structures.get(1).m_type == 7); - assertTrue(structure.m_structures.get(2).m_type == 1); - assertTrue(structure.m_structures.get(3).m_type == 1); - - assertTrue(structure.m_structures.get(1).m_structures.get(0).m_type == 1); - assertTrue(structure.m_structures.get(1).m_structures.get(1).m_type == 1); - assertTrue(structure.m_structures.get(1).m_structures.get(2).m_type == 1); - assertTrue(structure.m_structures.get(1).m_structures.get(3).m_type == 2); - } - - @Test - public static void testImportGeoJsonMultiPolygon() throws Exception { - OperatorImportFromGeoJson importerGeoJson = (OperatorImportFromGeoJson) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ImportFromGeoJson); - OperatorExportToGeoJson exporterGeoJson = (OperatorExportToGeoJson) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ExportToGeoJson); - - MapGeometry map_geometry; - Polygon polygon; - SpatialReference spatial_reference; - String geoJsonString; - Envelope2D envelope = new Envelope2D(); - - // Test Import from MultiPolygon - geoJsonString = "{\"type\": \"MultiPolygon\", \"coordinates\": []}"; - polygon = (Polygon) (importerGeoJson.execute(0, Geometry.Type.Polygon, geoJsonString, null).getGeometry()); - assertTrue(polygon != null); - assertTrue(polygon.isEmpty()); - assertTrue(!polygon.hasAttribute(VertexDescription.Semantics.M)); - - geoJsonString = "{\"coordinates\" : [], \"type\": \"MultiPolygon\", \"crs\": {\"type\": \"name\", \"some\": \"stuff\", \"properties\": {\"some\" : \"stuff\", \"name\": \"urn:ogc:def:crs:OGC:1.3:CRS84\"}}}"; - map_geometry = importerGeoJson.execute(0, Geometry.Type.Polygon, geoJsonString, null); - polygon = (Polygon) map_geometry.getGeometry(); - spatial_reference = map_geometry.getSpatialReference(); - assertTrue(polygon != null); - assertTrue(polygon.isEmpty()); - assertTrue(spatial_reference.getLatestID() == 4326); - - geoJsonString = "{\"coordinates\" : null, \"crs\": null, \"type\": \"MultiPolygon\"}"; - map_geometry = importerGeoJson.execute(0, Geometry.Type.Polygon, geoJsonString, null); - polygon = (Polygon) map_geometry.getGeometry(); - spatial_reference = map_geometry.getSpatialReference(); - assertTrue(polygon != null); - assertTrue(polygon.isEmpty()); - assertTrue(spatial_reference == null); - - geoJsonString = "{\"type\": \"MultiPolygon\", \"coordinates\" : [[], [], [[[]]]], \"crsURN\": \"urn:ogc:def:crs:OGC:1.3:CRS27\"}"; - map_geometry = importerGeoJson.execute(0, Geometry.Type.Polygon, geoJsonString, null); - polygon = (Polygon) map_geometry.getGeometry(); - spatial_reference = map_geometry.getSpatialReference(); - assertTrue(polygon != null); - assertTrue(polygon.isEmpty()); - assertTrue(spatial_reference != null); - assertTrue(spatial_reference.getLatestID() == 4267); - - geoJsonString = "{\"coordinates\" : [[], [[], [[10, 10, 5], [20, 10, 5], [20, 20, 5], [10, 20, 5], [10, 10, 5]], [[12, 12, 3]], [], [[10, 10, 1], [12, 12, 1]]], [], [[[90, 90, 88], [60, 90, 7], [60, 60, 7]], [], [[70, 70, 7], [80, 80, 7], [70, 80, 7], [70, 70, 7]]], []], \"crs\": {\"type\": \"link\", \"properties\": {\"href\": \"http://spatialreference.org/ref/sr-org/6928/ogcwkt/\"}}, \"type\": \"MultiPolygon\"}"; - map_geometry = importerGeoJson.execute(0, Geometry.Type.Unknown, geoJsonString, null); - polygon = (Polygon) map_geometry.getGeometry(); - spatial_reference = map_geometry.getSpatialReference(); - assertTrue(polygon != null); - polygon.queryEnvelope2D(envelope); - assertTrue(envelope.xmin == 10 && envelope.xmax == 90 && envelope.ymin == 10 && envelope.ymax == 90); - assertTrue(polygon.getPointCount() == 14); - assertTrue(polygon.getPathCount() == 5); - assertTrue(spatial_reference.getLatestID() == 3857); - - map_geometry = importerGeoJson.execute(0, Geometry.Type.Unknown, geoJsonString, null); - polygon = (Polygon) map_geometry.getGeometry(); - spatial_reference = map_geometry.getSpatialReference(); - assertTrue(polygon != null); - polygon.queryEnvelope2D(envelope); - assertTrue(envelope.xmin == 10 && envelope.xmax == 90 && envelope.ymin == 10 && envelope.ymax == 90); - assertTrue(polygon.getPointCount() == 14); - assertTrue(polygon.getPathCount() == 5); - assertTrue(spatial_reference.getLatestID() == 3857); - - // Test Export to GeoJSON MultiPolygon - geoJsonString = exporterGeoJson.execute(GeoJsonExportFlags.geoJsonExportSkipCRS, spatial_reference, polygon); - assertTrue(geoJsonString.equals("{\"type\":\"MultiPolygon\",\"coordinates\":[[[[10,10,5],[20,10,5],[20,20,5],[10,20,5],[10,10,5]],[[12,12,3],[12,12,3],[12,12,3]],[[10,10,1],[12,12,1],[10,10,1]]],[[[90,90,88],[60,90,7],[60,60,7],[90,90,88]],[[70,70,7],[70,80,7],[80,80,7],[70,70,7]]]]}")); - - geoJsonString = exporterGeoJson.execute(0, spatial_reference, polygon); - assertTrue(geoJsonString.equals("{\"type\":\"MultiPolygon\",\"coordinates\":[[[[10,10,5],[20,10,5],[20,20,5],[10,20,5],[10,10,5]],[[12,12,3],[12,12,3],[12,12,3]],[[10,10,1],[12,12,1],[10,10,1]]],[[[90,90,88],[60,90,7],[60,60,7],[90,90,88]],[[70,70,7],[70,80,7],[80,80,7],[70,70,7]]]],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:3857\"}}}")); - - geoJsonString = "{\"type\": \"MultiPolygon\", \"coordinates\": [[[[90, 10, 7], [10, 10, 1], [10, 90, 7], [90, 90, 1], [90, 10, 7]]]] }"; // ring - // i // clockwise - polygon = (Polygon) (importerGeoJson.execute(0, Geometry.Type.Polygon, geoJsonString, null).getGeometry()); - assertTrue(polygon != null); - assertTrue(polygon.getPointCount() == 4); - assertTrue(polygon.getPathCount() == 1); - assertTrue(polygon.hasAttribute(VertexDescription.Semantics.Z)); - assertTrue(polygon.calculateArea2D() > 0); - - // Test import Polygon - geoJsonString = "{\"type\": \"Polygon\", \"coordinates\": [[], [], [[10, 10, 5], [10, 20, 5], [20, 20, 5], [20, 10, 5]], [[12, 12, 3]], [], [[10, 10, 1], [12, 12, 1]], [], [[60, 60, 7], [60, 90, 7], [90, 90, 7], [60, 60, 7]], [], [[70, 70, 7], [70, 80, 7], [80, 80, 7]], []] }"; - map_geometry = importerGeoJson.execute(0, Geometry.Type.Polygon, geoJsonString, null); - polygon = (Polygon) map_geometry.getGeometry(); - spatial_reference = map_geometry.getSpatialReference(); - assertTrue(polygon != null); - assertTrue(polygon.getPointCount() == 14); - assertTrue(polygon.getPathCount() == 5); - assertTrue(spatial_reference.getLatestID() == 4326); - - geoJsonString = exporterGeoJson.execute(0, spatial_reference, polygon); - assertTrue(geoJsonString.equals("{\"type\":\"Polygon\",\"coordinates\":[[[10,10,5],[20,10,5],[20,20,5],[10,20,5],[10,10,5]],[[12,12,3],[12,12,3],[12,12,3]],[[10,10,1],[12,12,1],[10,10,1]],[[60,60,7],[60,90,7],[90,90,7],[60,60,7]],[[70,70,7],[70,80,7],[80,80,7],[70,70,7]]],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:4326\"}}}")); - - Envelope env = new Envelope(); - env.addAttribute(VertexDescription.Semantics.Z); - polygon.queryEnvelope(env); - - geoJsonString = "{\"coordinates\" : [], \"type\": \"MultiPolygon\", \"crs\":{\"esriwkt\":\"PROJCS[\\\"Gnomonic\\\",GEOGCS[\\\"GCS_WGS_1984\\\",DATUM[\\\"D_WGS_1984\\\",SPHEROID[\\\"WGS_1984\\\",6378137.0,298.257223563]],PRIMEM[\\\"Greenwich\\\",0.0],UNIT[\\\"Degree\\\",0.0174532925199433]],PROJECTION[\\\"Gnomonic\\\"],PARAMETER[\\\"Longitude_Of_Center\\\",0.0],PARAMETER[\\\"Latitude_Of_Center\\\",-45.0],UNIT[\\\"Meter\\\",1.0]]\"}}"; - map_geometry = importerGeoJson.execute(0, Geometry.Type.Polygon, geoJsonString, null); - polygon = (Polygon) map_geometry.getGeometry(); - spatial_reference = map_geometry.getSpatialReference(); - String wkt = spatial_reference.getText(); - assertTrue(wkt.equals( - "PROJCS[\"Gnomonic\",GEOGCS[\"GCS_WGS_1984\",DATUM[\"D_WGS_1984\",SPHEROID[\"WGS_1984\",6378137.0,298.257223563]],PRIMEM[\"Greenwich\",0.0],UNIT[\"Degree\",0.0174532925199433]],PROJECTION[\"Gnomonic\"],PARAMETER[\"Longitude_Of_Center\",0.0],PARAMETER[\"Latitude_Of_Center\",-45.0],UNIT[\"Meter\",1.0]]")); - - geoJsonString = "{\"coordinates\" : [], \"type\": \"MultiPolygon\", \"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"PROJCS[\\\"Gnomonic\\\",GEOGCS[\\\"GCS_WGS_1984\\\",DATUM[\\\"D_WGS_1984\\\",SPHEROID[\\\"WGS_1984\\\",6378137.0,298.257223563]],PRIMEM[\\\"Greenwich\\\",0.0],UNIT[\\\"Degree\\\",0.0174532925199433]],PROJECTION[\\\"Gnomonic\\\"],PARAMETER[\\\"Longitude_Of_Center\\\",0.0],PARAMETER[\\\"Latitude_Of_Center\\\",-45.0],UNIT[\\\"Meter\\\",1.0]]\"}}}"; - map_geometry = importerGeoJson.execute(0, Geometry.Type.Polygon, geoJsonString, null); - polygon = (Polygon) map_geometry.getGeometry(); - spatial_reference = map_geometry.getSpatialReference(); - wkt = spatial_reference.getText(); - assertTrue(wkt.equals( - "PROJCS[\"Gnomonic\",GEOGCS[\"GCS_WGS_1984\",DATUM[\"D_WGS_1984\",SPHEROID[\"WGS_1984\",6378137.0,298.257223563]],PRIMEM[\"Greenwich\",0.0],UNIT[\"Degree\",0.0174532925199433]],PROJECTION[\"Gnomonic\"],PARAMETER[\"Longitude_Of_Center\",0.0],PARAMETER[\"Latitude_Of_Center\",-45.0],UNIT[\"Meter\",1.0]]")); - assertTrue(polygon != null); - assertTrue(polygon.isEmpty()); - - // AGOL exports wkt like this... - geoJsonString = "{\"coordinates\" : [], \"type\": \"MultiPolygon\", \"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"ESRI:PROJCS[\\\"Gnomonic\\\",GEOGCS[\\\"GCS_WGS_1984\\\",DATUM[\\\"D_WGS_1984\\\",SPHEROID[\\\"WGS_1984\\\",6378137.0,298.257223563]],PRIMEM[\\\"Greenwich\\\",0.0],UNIT[\\\"Degree\\\",0.0174532925199433]],PROJECTION[\\\"Gnomonic\\\"],PARAMETER[\\\"Longitude_Of_Center\\\",0.0],PARAMETER[\\\"Latitude_Of_Center\\\",-45.0],UNIT[\\\"Meter\\\",1.0]]\"}}}"; - map_geometry = importerGeoJson.execute(0, Geometry.Type.Polygon, geoJsonString, null); - polygon = (Polygon) map_geometry.getGeometry(); - spatial_reference = map_geometry.getSpatialReference(); - wkt = spatial_reference.getText(); - assertTrue(wkt.equals( - "PROJCS[\"Gnomonic\",GEOGCS[\"GCS_WGS_1984\",DATUM[\"D_WGS_1984\",SPHEROID[\"WGS_1984\",6378137.0,298.257223563]],PRIMEM[\"Greenwich\",0.0],UNIT[\"Degree\",0.0174532925199433]],PROJECTION[\"Gnomonic\"],PARAMETER[\"Longitude_Of_Center\",0.0],PARAMETER[\"Latitude_Of_Center\",-45.0],UNIT[\"Meter\",1.0]]")); - assertTrue(polygon != null); - assertTrue(polygon.isEmpty()); - - boolean exceptionThrownNoWKT = false; - - try { - geoJsonString = exporterGeoJson.execute(GeoJsonExportFlags.geoJsonExportPreferMultiGeometry, - spatial_reference, polygon); - } catch (Exception e) { - exceptionThrownNoWKT = true; - } - - assertTrue(exceptionThrownNoWKT); - } - - @Test - public static void testImportGeoJsonMultiLineString() throws Exception { - OperatorImportFromGeoJson importerGeoJson = (OperatorImportFromGeoJson) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ImportFromGeoJson); - OperatorExportToGeoJson exporterGeoJson = (OperatorExportToGeoJson) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ExportToGeoJson); - MapGeometry map_geometry; - Polyline polyline; - SpatialReference spatial_reference; - String geoJsonString; - Envelope2D envelope = new Envelope2D(); - - // Test Import from MultiLineString - geoJsonString = "{\"type\":\"MultiLineString\",\"coordinates\":[], \"crs\" : {\"type\" : \"URL\", \"properties\" : {\"url\" : \"http://www.opengis.net/def/crs/EPSG/0/3857\"}}}"; - map_geometry = importerGeoJson.execute(0, Geometry.Type.Unknown, geoJsonString, null); - polyline = (Polyline) map_geometry.getGeometry(); - spatial_reference = map_geometry.getSpatialReference(); - assertTrue(polyline != null); - assertTrue(spatial_reference != null); - assertTrue(polyline.isEmpty()); - assertTrue(spatial_reference.getLatestID() == 3857); - - geoJsonString = "{\"crs\" : {\"type\" : \"link\", \"properties\" : {\"href\" : \"www.spatialreference.org/ref/epsg/4309/\"}}, \"type\":\"MultiLineString\",\"coordinates\":[[], [], [[10, 10, 5], [10, 20, 5], [20, 88, 5], [20, 10, 5]], [[12, 88, 3]], [], [[10, 10, 1], [12, 12, 1]], [], [[88, 60, 7], [60, 90, 7], [90, 90, 7]], [], [[70, 70, 7], [70, 80, 7], [80, 80, 7]], []]}"; - map_geometry = importerGeoJson.execute(0, Geometry.Type.Unknown, geoJsonString, null); - polyline = (Polyline) map_geometry.getGeometry(); - spatial_reference = map_geometry.getSpatialReference(); - assertTrue(polyline != null); - polyline.queryEnvelope2D(envelope); - assertTrue(envelope.xmin == 10 && envelope.xmax == 90 && envelope.ymin == 10 && envelope.ymax == 90); - assertTrue(polyline.getPointCount() == 14); - assertTrue(polyline.getPathCount() == 5); - assertTrue(polyline.hasAttribute(VertexDescription.Semantics.Z)); - assertTrue(spatial_reference.getLatestID() == 4309); - - geoJsonString = exporterGeoJson.execute(0, spatial_reference, polyline); - assertTrue(geoJsonString.equals("{\"type\":\"MultiLineString\",\"coordinates\":[[[10,10,5],[10,20,5],[20,88,5],[20,10,5]],[[12,88,3],[12,88,3]],[[10,10,1],[12,12,1]],[[88,60,7],[60,90,7],[90,90,7]],[[70,70,7],[70,80,7],[80,80,7]]],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:4309\"}}}")); - - // Test Import LineString - geoJsonString = "{\"type\": \"LineString\", \"coordinates\": [[10, 10, 5], [10, 20, 5], [20, 20, 5], [20, 10, 5]]}"; - polyline = (Polyline) (importerGeoJson.execute(0, Geometry.Type.Unknown, geoJsonString, null).getGeometry()); - assertTrue(polyline.getPointCount() == 4); - assertTrue(polyline.hasAttribute(VertexDescription.Semantics.Z)); - - geoJsonString = "{\"type\": \"LineString\", \"coordinates\": [[10, 10, 5], [10, 20, 5, 3], [20, 20, 5], [20, 10, 5]]}"; - polyline = (Polyline) (importerGeoJson.execute(0, Geometry.Type.Unknown, geoJsonString, null).getGeometry()); - assertTrue(polyline.getPointCount() == 4); - assertTrue(polyline.hasAttribute(VertexDescription.Semantics.Z)); - assertTrue(polyline.hasAttribute(VertexDescription.Semantics.M)); - - geoJsonString = "{\"type\":\"LineString\",\"coordinates\": [[10, 10, 5], [10, 20, 5], [20, 20, 5], [], [20, 10, 5]],\"crs\" : {\"type\" : \"link\", \"properties\" : {\"href\" : \"www.opengis.net/def/crs/EPSG/0/3857\"}}}"; - map_geometry = importerGeoJson.execute(0, Geometry.Type.Unknown, geoJsonString, null); - polyline = (Polyline) (map_geometry.getGeometry()); - spatial_reference = map_geometry.getSpatialReference(); - assertTrue(polyline.getPointCount() == 4); - assertTrue(spatial_reference.getLatestID() == 3857); - geoJsonString = exporterGeoJson.execute(0, spatial_reference, polyline); - assertTrue(geoJsonString.equals("{\"type\":\"LineString\",\"coordinates\":[[10,10,5],[10,20,5],[20,20,5],[20,10,5]],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:3857\"}}}")); - - geoJsonString = exporterGeoJson.execute(0, null, polyline); - assertTrue(geoJsonString.equals("{\"type\":\"LineString\",\"coordinates\":[[10,10,5],[10,20,5],[20,20,5],[20,10,5]],\"crs\":null}")); - } - - @Test - public static void testImportGeoJsonMultiPoint() throws Exception { - OperatorImportFromGeoJson importerGeoJson = (OperatorImportFromGeoJson) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ImportFromGeoJson); - OperatorExportToGeoJson exporterGeoJson = (OperatorExportToGeoJson) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ExportToGeoJson); - MapGeometry map_geometry; - MultiPoint multipoint; - SpatialReference spatial_reference; - String geoJsonString; - Envelope2D envelope = new Envelope2D(); - - // Test Import from Multi_point - - geoJsonString = "{\"type\":\"MultiPoint\",\"coordinates\":[]}"; - map_geometry = importerGeoJson.execute(0, Geometry.Type.Unknown, geoJsonString, null); - multipoint = (MultiPoint) map_geometry.getGeometry(); - spatial_reference = map_geometry.getSpatialReference(); - assertTrue(multipoint != null); - assertTrue(multipoint.isEmpty()); - assertTrue(spatial_reference.getLatestID() == 4326); - - geoJsonString = exporterGeoJson.execute(0, null, multipoint); - assertTrue(geoJsonString.equals("{\"type\":\"MultiPoint\",\"coordinates\":[],\"crs\":null}")); - - multipoint = new MultiPoint(); - multipoint.add(118.15, 2); - multipoint.add(88, 88); - - geoJsonString = exporterGeoJson.execute(GeoJsonExportFlags.geoJsonExportPrecision16, SpatialReference.create(4269), multipoint); - assertTrue(geoJsonString.equals("{\"type\":\"MultiPoint\",\"coordinates\":[[118.15,2],[88,88]],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:4269\"}}}")); - - multipoint.setEmpty(); - multipoint.add(88, 2); - multipoint.add(88, 88); - - geoJsonString = exporterGeoJson.execute(0, SpatialReference.create(102100), multipoint); - assertTrue(geoJsonString.equals("{\"type\":\"MultiPoint\",\"coordinates\":[[88,2],[88,88]],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:3857\"}}}")); - - geoJsonString = "{\"type\":\"MultiPoint\",\"coordinates\":[[], [], [10, 88, 88, 33], [10, 20, 5, 33], [20, 20, 5, 33], [20, 10, 5, 33], [12, 12, 3, 33], [], [10, 10, 1, 33], [12, 12, 1, 33], [], [60, 60, 7, 33], [60, 90.1, 7, 33], [90, 90, 7, 33], [], [70, 70, 7, 33], [70, 80, 7, 33], [80, 80, 7, 33], []],\"crs\":{\"type\":\"OGC\",\"properties\":{\"urn\":\"urn:ogc:def:crs:OGC:1.3:CRS83\"}}}"; - map_geometry = importerGeoJson.execute(0, Geometry.Type.Unknown, geoJsonString, null); - multipoint = (MultiPoint) map_geometry.getGeometry(); - spatial_reference = map_geometry.getSpatialReference(); - assertTrue(multipoint != null); - assertTrue(multipoint.getPointCount() == 13); - assertTrue(multipoint.hasAttribute(VertexDescription.Semantics.Z)); - assertTrue(multipoint.hasAttribute(VertexDescription.Semantics.M)); - assertTrue(spatial_reference.getLatestID() == 4269); - - geoJsonString = "{\"type\":\"MultiPoint\",\"coordinates\": [[10, 88, 88, 33], [10, 20, 5, 33], [20, 20, 5, 33], [], [20, 10, 5, 33], [12, 12, 3, 33], [], [10, 10, 1, 33], [12, 12, 1, 33], [60, 60, 7, 33], [60, 90.1, 7, 33], [90, 90, 7, 33], [70, 70, 7, 33], [70, 80, 7, 33], [80, 80, 7, 33]]}"; - multipoint = (MultiPoint) importerGeoJson.execute(0, Geometry.Type.Unknown, geoJsonString, null).getGeometry(); - assertTrue(multipoint != null); - assertTrue(multipoint.getPointCount() == 13); - assertTrue(multipoint.hasAttribute(VertexDescription.Semantics.Z)); - assertTrue(multipoint.hasAttribute(VertexDescription.Semantics.M)); - - geoJsonString = exporterGeoJson.execute(GeoJsonExportFlags.geoJsonExportPrecision15, null, multipoint); - assertTrue(geoJsonString.equals("{\"type\":\"MultiPoint\",\"coordinates\":[[10,88,88,33],[10,20,5,33],[20,20,5,33],[20,10,5,33],[12,12,3,33],[10,10,1,33],[12,12,1,33],[60,60,7,33],[60,90.1,7,33],[90,90,7,33],[70,70,7,33],[70,80,7,33],[80,80,7,33]],\"crs\":null}")); - - geoJsonString = "{\"type\":\"MultiPoint\",\"coordinates\":[[], [], [10, 10, 5, 33]]}"; - multipoint = (MultiPoint) importerGeoJson.execute(0, Geometry.Type.Unknown, geoJsonString, null).getGeometry(); - - geoJsonString = exporterGeoJson.execute(0, null, multipoint); - assertTrue(geoJsonString.equals("{\"type\":\"MultiPoint\",\"coordinates\":[[10,10,5,33]],\"crs\":null}")); - } - - @Test - public static void testImportGeoJsonPolygon() throws Exception { - OperatorImportFromGeoJson importerGeoJson = (OperatorImportFromGeoJson) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ImportFromGeoJson); - - Polygon polygon; - String geoJsonString; - Envelope2D envelope = new Envelope2D(); - - // Test Import from Polygon - geoJsonString = "{\"type\": \"Polygon\", \"coordinates\": []}"; - polygon = (Polygon) (importerGeoJson.execute(0, Geometry.Type.Unknown, geoJsonString, null).getGeometry()); - assertTrue(polygon != null); - assertTrue(polygon.isEmpty()); - assertTrue(!polygon.hasAttribute(VertexDescription.Semantics.Z)); - assertTrue(!polygon.hasAttribute(VertexDescription.Semantics.M)); - - geoJsonString = "{\"type\": \"Polygon\", \"coordinates\": [[], [[10, 10, 5], [20, 10, 5], [20, 20, 5], [10, 20, 5], [10, 10, 5]], [[12, 12, 3]], [], [[10, 10, 1], [12, 12, 1]]]}"; - polygon = (Polygon) (importerGeoJson.execute(0, Geometry.Type.Unknown, geoJsonString, null).getGeometry()); - assertTrue(polygon != null); - polygon.queryEnvelope2D(envelope); - assertTrue(envelope.xmin == 10 && envelope.xmax == 20 && envelope.ymin == 10 && envelope.ymax == 20); - assertTrue(polygon.getPointCount() == 8); - assertTrue(polygon.getPathCount() == 3); - assertTrue(polygon.hasAttribute(VertexDescription.Semantics.Z)); - - geoJsonString = "{\"type\": \"Polygon\", \"coordinates\": [[[35, 10], [10, 20], [15, 40], [45, 45], [35, 10]], [[20, 30], [35, 35], [30, 20], [20, 30]]]}"; - Polygon polygon2 = (Polygon) (importerGeoJson.execute(0, Geometry.Type.Unknown, geoJsonString, null).getGeometry()); - assertTrue(polygon2 != null); - } - - @Test - public static void testImportGeoJsonLineString() throws Exception { - OperatorImportFromGeoJson importerGeoJson = (OperatorImportFromGeoJson) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ImportFromGeoJson); - - Polyline polyline; - String geoJsonString; - Envelope2D envelope = new Envelope2D(); - - // Test Import from LineString - geoJsonString = "{\"type\": \"LineString\", \"coordinates\": []}"; - polyline = (Polyline) (importerGeoJson.execute(0, Geometry.Type.Unknown, geoJsonString, null).getGeometry()); - assertTrue(polyline != null); - assertTrue(polyline.isEmpty()); - assertTrue(!polyline.hasAttribute(VertexDescription.Semantics.Z)); - assertTrue(!polyline.hasAttribute(VertexDescription.Semantics.M)); - - geoJsonString = "{\"type\": \"LineString\", \"coordinates\": [[10, 10, 5], [10, 20, 5], [20, 20, 5], [20, 10, 5]]}"; - polyline = (Polyline) (importerGeoJson.execute(0, Geometry.Type.Unknown, geoJsonString, null).getGeometry()); - assertTrue(polyline != null); - polyline.queryEnvelope2D(envelope); - assertTrue(envelope.xmin == 10 && envelope.xmax == 20 && envelope.ymin == 10 && envelope.ymax == 20); - assertTrue(polyline.getPointCount() == 4); - assertTrue(polyline.getPathCount() == 1); - assertTrue(!polyline.hasAttribute(VertexDescription.Semantics.M)); - } - - @Test - public static void testImportGeoJsonPoint() throws Exception { - OperatorImportFromGeoJson importerGeoJson = (OperatorImportFromGeoJson) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ImportFromGeoJson); - OperatorExportToGeoJson exporterGeoJson = (OperatorExportToGeoJson) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ExportToGeoJson); - MapGeometry map_geometry; - SpatialReference spatial_reference; - Point point; - String geoJsonString; - - // Test Import from Point - geoJsonString = "{\"type\":\"Point\",\"coordinates\":[],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:3857\"}}}"; - map_geometry = importerGeoJson.execute(0, Geometry.Type.Unknown, geoJsonString, null); - point = (Point) map_geometry.getGeometry(); - spatial_reference = map_geometry.getSpatialReference(); - assertTrue(spatial_reference.getLatestID() == 3857); - - assertTrue(point != null); - assertTrue(point.isEmpty()); - - geoJsonString = exporterGeoJson.execute(0, null, point); - assertTrue(geoJsonString.equals("{\"type\":\"Point\",\"coordinates\":[],\"crs\":null}")); - - geoJsonString = exporterGeoJson.execute(GeoJsonExportFlags.geoJsonExportPreferMultiGeometry, null, point); - assertTrue(geoJsonString.equals("{\"type\":\"MultiPoint\",\"coordinates\":[],\"crs\":null}")); - - geoJsonString = "{\"type\":\"Point\",\"coordinates\":[30.1,10.6,5.1,33.1],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"urn:ogc:def:crs:ESRI::54051\"}}}"; - map_geometry = importerGeoJson.execute(0, Geometry.Type.Unknown, geoJsonString, null); - point = (Point) map_geometry.getGeometry(); - spatial_reference = map_geometry.getSpatialReference(); - assertTrue(point != null); - assertTrue(point.hasAttribute(VertexDescription.Semantics.Z)); - assertTrue(point.hasAttribute(VertexDescription.Semantics.M)); - assertTrue(spatial_reference.getLatestID() == 54051); - double x = point.getX(); - double y = point.getY(); - double z = point.getZ(); - double m = point.getM(); - - assertTrue(x == 30.1); - assertTrue(y == 10.6); - assertTrue(z == 5.1); - assertTrue(m == 33.1); - - geoJsonString = exporterGeoJson.execute(GeoJsonExportFlags.geoJsonExportPrecision15, spatial_reference, point); - assertTrue(geoJsonString.equals("{\"type\":\"Point\",\"coordinates\":[30.1,10.6,5.1,33.1],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"ESRI:54051\"}}}")); - - geoJsonString = exporterGeoJson.execute(GeoJsonExportFlags.geoJsonExportPrecision15, SpatialReference.create(4287), point); - assertTrue(geoJsonString.equals("{\"type\":\"Point\",\"coordinates\":[30.1,10.6,5.1,33.1],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:4287\"}}}")); - - geoJsonString = exporterGeoJson.execute(GeoJsonExportFlags.geoJsonExportPreferMultiGeometry | GeoJsonExportFlags.geoJsonExportPrecision15, null, point); - assertTrue(geoJsonString.equals("{\"type\":\"MultiPoint\",\"coordinates\":[[30.1,10.6,5.1,33.1]],\"crs\":null}")); - } - - @Test - public static void testImportExportGeoJsonMalformed() { - OperatorImportFromGeoJson importerGeoJson = (OperatorImportFromGeoJson) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ImportFromGeoJson); - OperatorExportToGeoJson exporterGeoJson = (OperatorExportToGeoJson) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ExportToGeoJson); - - String geoJsonString; - - try { - geoJsonString = "{\"type\":\"MultiPolygon\",\"coordinates\":[[[2,2,2],[3,3,3],[4,4,4],[2,2,2]]]}"; - importerGeoJson.execute(0, Geometry.Type.Unknown, geoJsonString, null); - assertTrue(false); - } catch (Exception e) { - } - - try { - geoJsonString = "{\"type\":\"Polygon\",\"coordinates\":[[2,2,2],[3,3,3],[4,4,4],[2,2,2]]}"; - importerGeoJson.execute(0, Geometry.Type.Unknown, geoJsonString, null); - assertTrue(false); - } catch (Exception e) { - } - - try { - geoJsonString = "{\"type\":\"Polygon\",\"coordinates\":[[[2,2,2],[3,3,3],[4,4,4],[2,2,2]],2,4]}"; - importerGeoJson.execute(0, Geometry.Type.Unknown, geoJsonString, null); - assertTrue(false); - } catch (Exception e) { - } - - try { - geoJsonString = "{\"type\":\"MultiPoint\",\"coordinates\":[[[2,2,2],[3,3,3],[4,4,4],[2,2,2]]]}"; - importerGeoJson.execute(0, Geometry.Type.Unknown, geoJsonString, null); - assertTrue(false); - } catch (Exception e) { - } - - try { - geoJsonString = "{\"type\":\"LineString\",\"coordinates\":[[[2,2,2],[3,3,3],[4,4,4],[2,2,2]]]}"; - importerGeoJson.execute(0, Geometry.Type.Unknown, geoJsonString, null); - assertTrue(false); - } catch (Exception e) { - } - - try { - geoJsonString = "{\"type\":\"MultiPoint\",\"coordinates\":[[2,2,2],[3,3,3],[4,4,4],[2,2,2],[[]]]}"; - importerGeoJson.execute(0, Geometry.Type.Unknown, geoJsonString, null); - assertTrue(false); - } catch (Exception e) { - } - - try { - geoJsonString = "{\"type\":\"MultiPolygon\",\"coordinates\":[[[[2,2,2],[3,3,3],[4,4,4],[2,2,2],[[]]]]]}"; - importerGeoJson.execute(0, Geometry.Type.Unknown, geoJsonString, null); - assertTrue(false); - } catch (Exception e) { - } - - try { - geoJsonString = "{\"type\":\"MultiPolygon\",\"coordinates\":[[[[2,2,2],[3,3,3],[4,4,4],[2,2,2]],[1,1,1],[2,2,2],[3,3,3],[1,1,1]]]}"; - importerGeoJson.execute(0, Geometry.Type.Unknown, geoJsonString, null); - assertTrue(false); - } catch (Exception e) { - } - - try { - geoJsonString = "{\"type\":\"Polygon\",\"coordinates\":[[[2,2,2],[3,3,3],[4,4,4],[2,2,2]],[1,1,1],[2,2,2],[3,3,3],[1,1,1]]}"; - importerGeoJson.execute(0, Geometry.Type.Unknown, geoJsonString, null); - assertTrue(false); - } catch (Exception e) { - } - - try { - geoJsonString = "{\"type\":\"MultiPolygon\",\"coordinates\":[[[[[]]]]}"; - importerGeoJson.execute(0, Geometry.Type.Unknown, geoJsonString, null); - assertTrue(false); - } catch (Exception e) { - } - - try { - geoJsonString = "{\"type\":\"MultiPolygon\",\"coordinates\":[[[[{}]]]}"; - importerGeoJson.execute(0, Geometry.Type.Unknown, geoJsonString, null); - assertTrue(false); - } catch (Exception e) { - } - - try { - geoJsonString = "{\"type\":\"Point\",\"coordinates\":[30.1,10.6,[],33.1],\"crs\":\"EPSG:3857\"}"; - importerGeoJson.execute(0, Geometry.Type.Unknown, geoJsonString, null); - assertTrue(false); - } catch (Exception e) { - } - } - - @Test - public static void testImportGeoJsonSpatialReference() throws Exception { - OperatorImportFromGeoJson importerGeoJson = (OperatorImportFromGeoJson) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ImportFromGeoJson); - - String geoJsonString4326; - String geoJsonString3857; - - // Test Import from Point - geoJsonString4326 = "{\"type\": \"Point\", \"coordinates\": [3.0, 5.0], \"crs\": \"EPSG:4326\"}"; - geoJsonString3857 = "{\"type\": \"Point\", \"coordinates\": [3.0, 5.0], \"crs\": \"EPSG:3857\"}"; - - MapGeometry mapGeometry4326 = importerGeoJson.execute(0, Geometry.Type.Unknown, geoJsonString4326, null); - MapGeometry mapGeometry3857 = importerGeoJson.execute(0, Geometry.Type.Unknown, geoJsonString3857, null); - - assertTrue(mapGeometry4326.equals(mapGeometry3857) == false); - assertTrue(mapGeometry4326.getGeometry().equals(mapGeometry3857.getGeometry())); - } - - @Test - public static void testImportExportESRICursors() { - Polygon poly1 = new Polygon(); - Envelope2D env1 = new Envelope2D(); - env1.setCoords(855277, 3892059, 855277 + 100, 3892059 + 100); - poly1.addEnvelope(env1, false); - - Polygon poly2 = new Polygon(); - Envelope2D env2 = new Envelope2D(); - env2.setCoords(855277, 3892059, 855277 + 300, 3892059 + 200); - poly2.addEnvelope(env2, false); - List list2 = new ArrayList<>(); - list2.add(poly1); - list2.add(poly2); - SimpleGeometryCursor simpleGeometryCursor2 = new SimpleGeometryCursor(new ArrayDeque(list2)); - - OperatorExportToESRIShapeCursor operatorExportToESRIShapeCursor = new OperatorExportToESRIShapeCursor(0, simpleGeometryCursor2); - OperatorImportFromESRIShapeCursor operatorImportFromESRIShapeCursor = new OperatorImportFromESRIShapeCursor(0, 0, operatorExportToESRIShapeCursor); - - SpatialReference inputSR = SpatialReference.create(3857); - OperatorFactoryLocal projEnv = OperatorFactoryLocal.getInstance(); - OperatorCrosses operatorCrosses = (OperatorCrosses) (projEnv.getOperator(Operator.Type.Crosses)); - HashMap relate_map = operatorCrosses.execute(poly1, - operatorImportFromESRIShapeCursor, inputSR, null); - - assertNotNull(relate_map); - - assertTrue(!relate_map.get(0L)); - assertTrue(!relate_map.get(1L)); - } - - @Test - public static void testImportExportWKBCursors() { - Polygon poly1 = new Polygon(); - Envelope2D env1 = new Envelope2D(); - env1.setCoords(855277, 3892059, 855277 + 100, 3892059 + 100); - poly1.addEnvelope(env1, false); - - Polygon poly2 = new Polygon(); - Envelope2D env2 = new Envelope2D(); - env2.setCoords(855277, 3892059, 855277 + 300, 3892059 + 200); - poly2.addEnvelope(env2, false); - List list2 = new ArrayList<>(); - list2.add(poly1); - list2.add(poly2); - SimpleGeometryCursor simpleGeometryCursor2 = new SimpleGeometryCursor(new ArrayDeque(list2)); - - OperatorExportToWkbCursor operatorExportToWkbCursor = new OperatorExportToWkbCursor(0, simpleGeometryCursor2); - OperatorImportFromWkbCursor operatorImportFromWkbCursor = new OperatorImportFromWkbCursor(0, operatorExportToWkbCursor); - - SpatialReference inputSR = SpatialReference.create(3857); - OperatorFactoryLocal projEnv = OperatorFactoryLocal.getInstance(); - OperatorCrosses operatorCrosses = (OperatorCrosses) (projEnv.getOperator(Operator.Type.Crosses)); - HashMap relate_map = operatorCrosses.execute(poly1, - operatorImportFromWkbCursor, inputSR, null); - - assertNotNull(relate_map); - assertTrue(!relate_map.get(0L)); - assertTrue(!relate_map.get(1L)); - - simpleGeometryCursor2 = new SimpleGeometryCursor(new ArrayDeque(list2)); - operatorExportToWkbCursor = new OperatorExportToWkbCursor(0, simpleGeometryCursor2); - operatorImportFromWkbCursor = new OperatorImportFromWkbCursor(0, operatorExportToWkbCursor); - double[] distances = {400, 400}; - - OperatorBufferCursor operatorBufferCursor = new OperatorBufferCursor(operatorImportFromWkbCursor, null, distances, NumberUtils.NaN(), 96, false, null); - relate_map = ((OperatorWithin) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.Within)).execute(poly2, operatorBufferCursor, inputSR, null); - assertNotNull(relate_map); - assertTrue(relate_map.get(0L)); - assertTrue(relate_map.get(1L)); - } - - static double randomWithRange(double min, double max) { - double range = Math.abs(max - min); - return (Math.random() * range) + (min <= max ? min : max); - } - - @Test - public static void testImportExportWKTCursors() { - Polygon poly1 = new Polygon(); - Envelope2D env1 = new Envelope2D(); - env1.setCoords(855277, 3892059, 855277 + 100, 3892059 + 100); - poly1.addEnvelope(env1, false); - - Polygon poly2 = new Polygon(); - Envelope2D env2 = new Envelope2D(); - env2.setCoords(855277, 3892059, 855277 + 300, 3892059 + 200); - poly2.addEnvelope(env2, false); - List list2 = new ArrayList<>(); - list2.add(poly1); - list2.add(poly2); - - int size = 1000; - String[] points = new String[size]; - List pointList = new ArrayList<>(size); - ArrayDeque pointArrayDeque = new ArrayDeque<>(size); - ArrayDeque ids = new ArrayDeque<>(size); - for (int i = 0; i < size; i++) { - pointList.add(new Point(randomWithRange(-20, 20), randomWithRange(-20, 20))); - ids.push((long) i + size); - points[i] = (String.format("Point(%f %f)", pointList.get(i).getX(), pointList.get(i).getY())); - pointArrayDeque.push(points[i]); - } - - SimpleStringCursor simpleStringCursor = new SimpleStringCursor(points); - OperatorImportFromWktCursor operatorImportFromWktCursor = new OperatorImportFromWktCursor(0, simpleStringCursor); - int index = 0; - while (operatorImportFromWktCursor.hasNext()) { - Point point_orig = pointList.get(index); - - Point geom = (Point) operatorImportFromWktCursor.next(); - long geometryID = operatorImportFromWktCursor.getGeometryID(); - assertEquals(geometryID, index); - index++; - assertEquals(point_orig.getX(), geom.getX(), 0.000001); - assertEquals(point_orig.getY(), geom.getY(), 0.000001); - } - - - SimpleGeometryCursor simpleGeometryCursor2 = new SimpleGeometryCursor(new ArrayDeque(list2)); - OperatorExportToWktCursor operatorExportToWktCursor = new OperatorExportToWktCursor(0, simpleGeometryCursor2, null); - operatorImportFromWktCursor = new OperatorImportFromWktCursor(0, operatorExportToWktCursor); - - SpatialReference inputSR = SpatialReference.create(3857); - OperatorFactoryLocal projEnv = OperatorFactoryLocal.getInstance(); - OperatorCrosses operatorCrosses = (OperatorCrosses) (projEnv.getOperator(Operator.Type.Crosses)); - HashMap relate_map = operatorCrosses.execute(poly1, - operatorImportFromWktCursor, inputSR, null); - - assertNotNull(relate_map); - assertTrue(!relate_map.get(0L)); - assertTrue(!relate_map.get(1L)); - - simpleGeometryCursor2 = new SimpleGeometryCursor(new ArrayDeque(list2)); - operatorExportToWktCursor = new OperatorExportToWktCursor(0, simpleGeometryCursor2, null); - operatorImportFromWktCursor = new OperatorImportFromWktCursor(0, operatorExportToWktCursor); - double[] distances = {400, 400}; - OperatorBufferCursor operatorBufferCursor = new OperatorBufferCursor(operatorImportFromWktCursor, null, distances, NumberUtils.NaN(), 96, false, null); - relate_map = ((OperatorWithin) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.Within)).execute(poly2, operatorBufferCursor, inputSR, null); - assertNotNull(relate_map); - assertTrue(relate_map.get(0L)); - assertTrue(relate_map.get(1L)); - - - } - - @Test - public void testWKTID() { - Polygon poly1 = new Polygon(); - Envelope2D env1 = new Envelope2D(); - env1.setCoords(855277, 3892059, 855277 + 100, 3892059 + 100); - poly1.addEnvelope(env1, false); - - Polygon poly2 = new Polygon(); - Envelope2D env2 = new Envelope2D(); - env2.setCoords(855277, 3892059, 855277 + 300, 3892059 + 200); - poly2.addEnvelope(env2, false); - List list2 = new ArrayList<>(); - list2.add(poly1); - list2.add(poly2); - - int size = 1000; - String[] points = new String[size]; - List pointList = new ArrayList<>(size); - List stringList = new ArrayList<>(size); - ArrayDeque pointArrayDeque = new ArrayDeque<>(size); - ArrayDeque ids = new ArrayDeque<>(size); - for (int i = 0; i < size; i++) { - pointList.add(new Point(randomWithRange(-20, 20), randomWithRange(-20, 20))); - ids.addLast((long) i + size); - points[i] = (String.format("Point(%f %f)", pointList.get(i).getX(), pointList.get(i).getY())); - pointArrayDeque.addLast(points[i]); - stringList.add(points[i]); - } - - SimpleStringCursor simpleStringCursor1 = new SimpleStringCursor(points); - SimpleStringCursor simpleStringCursor2 = new SimpleStringCursor(pointArrayDeque.clone(), ids.clone()); - SimpleStringCursor simpleStringCursor3 = new SimpleStringCursor(stringList); - - OperatorImportFromWktCursor operatorImportFromWktCursor1 = new OperatorImportFromWktCursor(0, simpleStringCursor1); - OperatorImportFromWktCursor operatorImportFromWktCursor2 = new OperatorImportFromWktCursor(0, simpleStringCursor2); - OperatorImportFromWktCursor operatorImportFromWktCursor3 = new OperatorImportFromWktCursor(0, simpleStringCursor3); - - while (operatorImportFromWktCursor1.hasNext()) { - Geometry geometry1 = operatorImportFromWktCursor1.next(); - Geometry geometry2 = operatorImportFromWktCursor2.next(); - Geometry geometry3 = operatorImportFromWktCursor3.next(); - assertTrue(geometry1.equals(geometry3)); - assertTrue(geometry1.equals(geometry2)); - } - - SimpleStringCursor simpleStringCursor = new SimpleStringCursor(pointArrayDeque.clone(), ids.clone()); - OperatorImportFromWktCursor operatorImportFromWktCursor = new OperatorImportFromWktCursor(0, simpleStringCursor); - int index = 0; - while (operatorImportFromWktCursor.hasNext()) { - Point point_orig = pointList.get(index); - - Point geom = (Point) operatorImportFromWktCursor.next(); - long geometryID = operatorImportFromWktCursor.getGeometryID(); - assertEquals(geometryID, index + size); - index++; - assertEquals(point_orig.getX(), geom.getX(), 0.000001); - assertEquals(point_orig.getY(), geom.getY(), 0.000001); - } - assertTrue(index > 0); - - simpleStringCursor = new SimpleStringCursor(pointArrayDeque.clone(), ids.clone()); - operatorImportFromWktCursor = new OperatorImportFromWktCursor(0, simpleStringCursor); - OperatorProjectCursor operatorProjectCursor = new OperatorProjectCursor(operatorImportFromWktCursor, new ProjectionTransformation(SpatialReference.create(3857), SpatialReference.create(4326)), null); - double[]stuff = new double[] {3000}; - OperatorGeodesicBufferCursor operatorGeodesicBufferCursor = new OperatorGeodesicBufferCursor(operatorProjectCursor, SpatialReference.create(4326), stuff, 10, false, false, null); - index = 0; - while (operatorGeodesicBufferCursor.hasNext()) { - Geometry polygon = operatorGeodesicBufferCursor.next(); - long geometryID = operatorGeodesicBufferCursor.getGeometryID(); - assertEquals(geometryID, index + size); - index ++; - } - assertTrue(index > 0); - - - } - - @Test - public void testMultiPointOrdering() { - MultiPoint multiPoint = new MultiPoint(); - for (double longitude = -180; longitude < 180; longitude+=10.0) { - for (double latitude = -80; latitude < 80; latitude+=10.0) { - multiPoint.add(longitude, latitude); - } - } - String wktGeom = OperatorExportToWkt.local().execute(0, multiPoint, null); - Geometry roundTripGeom = OperatorImportFromWkt.local().execute(0, Geometry.Type.Unknown, wktGeom, null); - assertTrue(roundTripGeom.equals(multiPoint)); - } - - - public static Polygon makePolygon() { - Polygon poly = new Polygon(); - poly.startPath(0, 0); - poly.lineTo(0, 10); - poly.lineTo(10, 10); - poly.lineTo(10, 0); - - poly.startPath(3, 3); - poly.lineTo(7, 3); - poly.lineTo(7, 7); - poly.lineTo(3, 7); - - poly.startPath(15, 0); - poly.lineTo(15, 15); - poly.lineTo(30, 15); - poly.lineTo(30, 0); - - poly.setAttribute(VertexDescription.Semantics.Z, 0, 0, 2); - poly.setAttribute(VertexDescription.Semantics.Z, 1, 0, 3); - poly.setAttribute(VertexDescription.Semantics.Z, 2, 0, 5); - poly.setAttribute(VertexDescription.Semantics.Z, 3, 0, 7); - poly.setAttribute(VertexDescription.Semantics.Z, 4, 0, 11); - poly.setAttribute(VertexDescription.Semantics.Z, 5, 0, 13); - poly.setAttribute(VertexDescription.Semantics.Z, 6, 0, 17); - poly.setAttribute(VertexDescription.Semantics.Z, 7, 0, 19); - poly.setAttribute(VertexDescription.Semantics.Z, 8, 0, 23); - poly.setAttribute(VertexDescription.Semantics.Z, 9, 0, 29); - poly.setAttribute(VertexDescription.Semantics.Z, 10, 0, 31); - poly.setAttribute(VertexDescription.Semantics.Z, 11, 0, 37); - - poly.setAttribute(VertexDescription.Semantics.M, 0, 0, 2); - poly.setAttribute(VertexDescription.Semantics.M, 1, 0, 4); - poly.setAttribute(VertexDescription.Semantics.M, 2, 0, 8); - poly.setAttribute(VertexDescription.Semantics.M, 3, 0, 16); - poly.setAttribute(VertexDescription.Semantics.M, 4, 0, 32); - poly.setAttribute(VertexDescription.Semantics.M, 5, 0, 64); - poly.setAttribute(VertexDescription.Semantics.M, 6, 0, 128); - poly.setAttribute(VertexDescription.Semantics.M, 7, 0, 256); - poly.setAttribute(VertexDescription.Semantics.M, 8, 0, 512); - poly.setAttribute(VertexDescription.Semantics.M, 9, 0, 1024); - poly.setAttribute(VertexDescription.Semantics.M, 10, 0, 2048); - poly.setAttribute(VertexDescription.Semantics.M, 11, 0, 4096); - - return poly; - } - - public static Polygon makePolygon2() { - Polygon poly = new Polygon(); - poly.startPath(0, 0); - poly.lineTo(0, 10); - poly.lineTo(10, 10); - poly.lineTo(10, 0); - - poly.setAttribute(VertexDescription.Semantics.Z, 0, 0, 2); - poly.setAttribute(VertexDescription.Semantics.Z, 1, 0, 3); - poly.setAttribute(VertexDescription.Semantics.Z, 2, 0, 5); - poly.setAttribute(VertexDescription.Semantics.Z, 3, 0, 7); - - poly.setAttribute(VertexDescription.Semantics.M, 0, 0, 2); - poly.setAttribute(VertexDescription.Semantics.M, 1, 0, 4); - poly.setAttribute(VertexDescription.Semantics.M, 2, 0, 8); - poly.setAttribute(VertexDescription.Semantics.M, 3, 0, 16); - - return poly; - } - - public static Polyline makePolyline() { - Polyline poly = new Polyline(); - poly.startPath(10, 1); - poly.lineTo(15, 20); - poly.lineTo(30, 14); - poly.lineTo(60, 144); - - poly.startPath(20, 13); - poly.lineTo(150, 120); - poly.lineTo(300, 414); - poly.lineTo(610, 14); - - poly.setAttribute(VertexDescription.Semantics.Z, 0, 0, 2); - poly.setAttribute(VertexDescription.Semantics.Z, 1, 0, 3); - poly.setAttribute(VertexDescription.Semantics.Z, 2, 0, 5); - poly.setAttribute(VertexDescription.Semantics.Z, 3, 0, 7); - poly.setAttribute(VertexDescription.Semantics.Z, 4, 0, 11); - poly.setAttribute(VertexDescription.Semantics.Z, 5, 0, 13); - poly.setAttribute(VertexDescription.Semantics.Z, 6, 0, 17); - poly.setAttribute(VertexDescription.Semantics.Z, 7, 0, 19); - - poly.setAttribute(VertexDescription.Semantics.M, 0, 0, 2); - poly.setAttribute(VertexDescription.Semantics.M, 1, 0, 4); - poly.setAttribute(VertexDescription.Semantics.M, 2, 0, 8); - poly.setAttribute(VertexDescription.Semantics.M, 3, 0, 16); - poly.setAttribute(VertexDescription.Semantics.M, 4, 0, 32); - poly.setAttribute(VertexDescription.Semantics.M, 5, 0, 64); - poly.setAttribute(VertexDescription.Semantics.M, 6, 0, 128); - poly.setAttribute(VertexDescription.Semantics.M, 7, 0, 256); - - poly.setAttribute(VertexDescription.Semantics.ID, 0, 0, 1); - poly.setAttribute(VertexDescription.Semantics.ID, 1, 0, 2); - poly.setAttribute(VertexDescription.Semantics.ID, 2, 0, 3); - poly.setAttribute(VertexDescription.Semantics.ID, 3, 0, 5); - poly.setAttribute(VertexDescription.Semantics.ID, 4, 0, 8); - poly.setAttribute(VertexDescription.Semantics.ID, 5, 0, 13); - poly.setAttribute(VertexDescription.Semantics.ID, 6, 0, 21); - poly.setAttribute(VertexDescription.Semantics.ID, 7, 0, 34); - - return poly; - } - - public static Polyline makePolyline2() { - Polyline poly = new Polyline(); - poly.startPath(10, 1); - poly.lineTo(15, 20); - poly.lineTo(30, 14); - poly.lineTo(60, 144); - - poly.setAttribute(VertexDescription.Semantics.Z, 0, 0, 2); - poly.setAttribute(VertexDescription.Semantics.Z, 1, 0, 3); - poly.setAttribute(VertexDescription.Semantics.Z, 2, 0, 5); - poly.setAttribute(VertexDescription.Semantics.Z, 3, 0, 7); - - poly.setAttribute(VertexDescription.Semantics.M, 0, 0, 2); - poly.setAttribute(VertexDescription.Semantics.M, 1, 0, 4); - poly.setAttribute(VertexDescription.Semantics.M, 2, 0, 8); - poly.setAttribute(VertexDescription.Semantics.M, 3, 0, 16); - - return poly; - } - - public static Point makePoint() { - Point point = new Point(); - point.setXY(11, 13); - - point.setZ(32); - point.setM(243); - point.setID(1024); - - return point; - } - - public static MultiPoint makeMultiPoint() { - MultiPoint mpoint = new MultiPoint(); - Point pt1 = new Point(); - pt1.setXY(0, 0); - pt1.setZ(-1); - - Point pt2 = new Point(); - pt2.setXY(0, 0); - pt2.setZ(1); - - Point pt3 = new Point(); - pt3.setXY(0, 1); - pt3.setZ(1); - - mpoint.add(pt1); - mpoint.add(pt2); - mpoint.add(pt3); - - mpoint.setAttribute(VertexDescription.Semantics.ID, 0, 0, 7); - mpoint.setAttribute(VertexDescription.Semantics.ID, 1, 0, 11); - mpoint.setAttribute(VertexDescription.Semantics.ID, 2, 0, 13); - - return mpoint; - } - - public static MultiPoint makeMultiPoint2() { - MultiPoint mpoint = new MultiPoint(); - Point pt1 = new Point(); - pt1.setX(0.0); - pt1.setY(0.0); - pt1.setZ(-1.0); - - mpoint.add(pt1); - - return mpoint; - } - - public static Envelope makeEnvelope() { - Envelope envelope; - - Envelope env = new Envelope(0.0, 0.0, 5.0, 5.0); - envelope = env; - - Envelope1D interval = new Envelope1D(); - interval.vmin = -3.0; - interval.vmax = -7.0; - envelope.setInterval(VertexDescription.Semantics.Z, 0, interval); - - interval.vmin = 16.0; - interval.vmax = 32.0; - envelope.setInterval(VertexDescription.Semantics.M, 0, interval); - - interval.vmin = 5.0; - interval.vmax = 11.0; - envelope.setInterval(VertexDescription.Semantics.ID, 0, interval); - - return envelope; - } + OperatorExportToESRIShape exporterShape = (OperatorExportToESRIShape) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ExportToESRIShape); + OperatorImportFromESRIShape importerShape = (OperatorImportFromESRIShape) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ImportFromESRIShape); + + Polygon polygon = makePolygon(); + + byte[] esriShape = GeometryEngine.geometryToEsriShape(polygon); + Geometry imported = GeometryEngine.geometryFromEsriShape(esriShape, Geometry.Type.Unknown); + TestCommonMethods.compareGeometryContent((MultiPath) imported, polygon); + + // Test Import Polygon from Polygon + ByteBuffer polygonShapeBuffer = exporterShape.execute(0, polygon); + Geometry polygonShapeGeometry = importerShape.execute(0, Geometry.Type.Polygon, polygonShapeBuffer); + + TestCommonMethods.compareGeometryContent((MultiPath) polygonShapeGeometry, polygon); + + // Test Import Envelope from Polygon + Geometry envelopeShapeGeometry = importerShape.execute(0, Geometry.Type.Envelope, polygonShapeBuffer); + Envelope envelope = (Envelope) envelopeShapeGeometry; + + @SuppressWarnings("unused") Envelope env = new Envelope(), otherenv = new Envelope(); + polygon.queryEnvelope(otherenv); + assertTrue(envelope.getXMin() == otherenv.getXMin()); + assertTrue(envelope.getXMax() == otherenv.getXMax()); + assertTrue(envelope.getYMin() == otherenv.getYMin()); + assertTrue(envelope.getYMax() == otherenv.getYMax()); + + Envelope1D interval, otherinterval; + interval = envelope.queryInterval(VertexDescription.Semantics.Z, 0); + otherinterval = polygon.queryInterval(VertexDescription.Semantics.Z, 0); + assertTrue(interval.vmin == otherinterval.vmin); + assertTrue(interval.vmax == otherinterval.vmax); + } + + @Test + public static void testImportExportShapePolyline() { + OperatorExportToESRIShape exporterShape = (OperatorExportToESRIShape) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ExportToESRIShape); + OperatorImportFromESRIShape importerShape = (OperatorImportFromESRIShape) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ImportFromESRIShape); + + Polyline polyline = makePolyline(); + + // Test Import Polyline from Polyline + ByteBuffer polylineShapeBuffer = exporterShape.execute(0, polyline); + Geometry polylineShapeGeometry = importerShape.execute(0, Geometry.Type.Polyline, polylineShapeBuffer); + + // TODO test this + TestCommonMethods.compareGeometryContent((MultiPath) polylineShapeGeometry, polyline); + + // Test Import Envelope from Polyline; + Geometry envelopeShapeGeometry = importerShape.execute(0, Geometry.Type.Envelope, polylineShapeBuffer); + Envelope envelope = (Envelope) envelopeShapeGeometry; + + Envelope env = new Envelope(), otherenv = new Envelope(); + envelope.queryEnvelope(env); + polyline.queryEnvelope(otherenv); + assertTrue(env.getXMin() == otherenv.getXMin()); + assertTrue(env.getXMax() == otherenv.getXMax()); + assertTrue(env.getYMin() == otherenv.getYMin()); + assertTrue(env.getYMax() == otherenv.getYMax()); + + Envelope1D interval, otherinterval; + interval = envelope.queryInterval(VertexDescription.Semantics.Z, 0); + otherinterval = polyline.queryInterval(VertexDescription.Semantics.Z, 0); + assertTrue(interval.vmin == otherinterval.vmin); + assertTrue(interval.vmax == otherinterval.vmax); + } + + @Test + public static void testImportExportShapeMultiPoint() { + OperatorExportToESRIShape exporterShape = (OperatorExportToESRIShape) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ExportToESRIShape); + OperatorImportFromESRIShape importerShape = (OperatorImportFromESRIShape) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ImportFromESRIShape); + + MultiPoint multipoint = makeMultiPoint(); + + // Test Import MultiPoint from MultiPoint + ByteBuffer multipointShapeBuffer = exporterShape.execute(0, multipoint); + MultiPoint multipointShapeGeometry = (MultiPoint) importerShape.execute(0, Geometry.Type.MultiPoint, multipointShapeBuffer); + + TestCommonMethods.compareGeometryContent((MultiPoint) multipointShapeGeometry, multipoint); + + // Test Import Envelope from MultiPoint + Geometry envelopeShapeGeometry = importerShape.execute(0, Geometry.Type.Envelope, multipointShapeBuffer); + Envelope envelope = (Envelope) envelopeShapeGeometry; + + Envelope env = new Envelope(), otherenv = new Envelope(); + envelope.queryEnvelope(env); + multipoint.queryEnvelope(otherenv); + assertTrue(env.getXMin() == otherenv.getXMin()); + assertTrue(env.getXMax() == otherenv.getXMax()); + assertTrue(env.getYMin() == otherenv.getYMin()); + assertTrue(env.getYMax() == otherenv.getYMax()); + + Envelope1D interval, otherinterval; + interval = envelope.queryInterval(VertexDescription.Semantics.Z, 0); + otherinterval = multipoint.queryInterval(VertexDescription.Semantics.Z, 0); + assertTrue(interval.vmin == otherinterval.vmin); + assertTrue(interval.vmax == otherinterval.vmax); + + interval = envelope.queryInterval(VertexDescription.Semantics.ID, 0); + otherinterval = multipoint.queryInterval(VertexDescription.Semantics.ID, 0); + assertTrue(interval.vmin == otherinterval.vmin); + assertTrue(interval.vmax == otherinterval.vmax); + } + + @Test + public static void testImportExportShapePoint() { + OperatorExportToESRIShape exporterShape = (OperatorExportToESRIShape) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ExportToESRIShape); + OperatorImportFromESRIShape importerShape = (OperatorImportFromESRIShape) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ImportFromESRIShape); + + // Point + Point point = makePoint(); + + // Test Import Point from Point + ByteBuffer pointShapeBuffer = exporterShape.execute(0, point); + Point pointShapeGeometry = (Point) importerShape.execute(0, Geometry.Type.Point, pointShapeBuffer); + + double x1 = point.getX(); + double x2 = pointShapeGeometry.getX(); + assertTrue(x1 == x2); + + double y1 = point.getY(); + double y2 = pointShapeGeometry.getY(); + assertTrue(y1 == y2); + + double z1 = point.getZ(); + double z2 = pointShapeGeometry.getZ(); + assertTrue(z1 == z2); + + double m1 = point.getM(); + double m2 = pointShapeGeometry.getM(); + assertTrue(m1 == m2); + + int id1 = point.getID(); + int id2 = pointShapeGeometry.getID(); + assertTrue(id1 == id2); + + // Test Import Multipoint from Point + MultiPoint multipointShapeGeometry = (MultiPoint) importerShape.execute(0, Geometry.Type.MultiPoint, pointShapeBuffer); + Point point2d = multipointShapeGeometry.getPoint(0); + assertTrue(x1 == point2d.getX() && y1 == point2d.getY()); + + int pointCount = multipointShapeGeometry.getPointCount(); + assertTrue(pointCount == 1); + + z2 = multipointShapeGeometry.getAttributeAsDbl(VertexDescription.Semantics.Z, 0, 0); + assertTrue(z1 == z2); + + m2 = multipointShapeGeometry.getAttributeAsDbl(VertexDescription.Semantics.M, 0, 0); + assertTrue(m1 == m2); + + id2 = multipointShapeGeometry.getAttributeAsInt(VertexDescription.Semantics.ID, 0, 0); + assertTrue(id1 == id2); + + // Test Import Envelope from Point + Geometry envelopeShapeGeometry = importerShape.execute(0, Geometry.Type.Envelope, pointShapeBuffer); + Envelope envelope = (Envelope) envelopeShapeGeometry; + + Envelope env = new Envelope(), otherenv = new Envelope(); + envelope.queryEnvelope(env); + point.queryEnvelope(otherenv); + assertTrue(env.getXMin() == otherenv.getXMin()); + assertTrue(env.getXMax() == otherenv.getXMax()); + assertTrue(env.getYMin() == otherenv.getYMin()); + assertTrue(env.getYMax() == otherenv.getYMax()); + + Envelope1D interval, otherinterval; + interval = envelope.queryInterval(VertexDescription.Semantics.Z, 0); + otherinterval = point.queryInterval(VertexDescription.Semantics.Z, 0); + assertTrue(interval.vmin == otherinterval.vmin); + assertTrue(interval.vmax == otherinterval.vmax); + + interval = envelope.queryInterval(VertexDescription.Semantics.ID, 0); + otherinterval = point.queryInterval(VertexDescription.Semantics.ID, 0); + assertTrue(interval.vmin == otherinterval.vmin); + assertTrue(interval.vmax == otherinterval.vmax); + } + + @Test + public static void testImportExportShapeEnvelope() { + OperatorExportToESRIShape exporterShape = (OperatorExportToESRIShape) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ExportToESRIShape); + OperatorImportFromESRIShape importerShape = (OperatorImportFromESRIShape) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ImportFromESRIShape); + + // Test Export Envelope to Polygon + Envelope envelope = makeEnvelope(); + + ByteBuffer polygonShapeBuffer = exporterShape.execute(0, envelope); + Polygon polygon = (Polygon) importerShape.execute(0, Geometry.Type.Polygon, polygonShapeBuffer); + int pointCount = polygon.getPointCount(); + assertTrue(pointCount == 4); + + Envelope env = new Envelope(); + + envelope.queryEnvelope(env); + // interval = envelope.queryInterval(VertexDescription.Semantics.Z, 0); + Point point3d; + point3d = polygon.getPoint(0); + assertTrue(point3d.getX() == env.getXMin() && point3d.getY() == env.getYMin());// && point3d.z == + // interval.vmin); + point3d = polygon.getPoint(1); + assertTrue(point3d.getX() == env.getXMin() && point3d.getY() == env.getYMax());// && point3d.z == + // interval.vmax); + point3d = polygon.getPoint(2); + assertTrue(point3d.getX() == env.getXMax() && point3d.getY() == env.getYMax());// && point3d.z == + // interval.vmin); + point3d = polygon.getPoint(3); + assertTrue(point3d.getX() == env.getXMax() && point3d.getY() == env.getYMin());// && point3d.z == + // interval.vmax); + + Envelope1D interval; + interval = envelope.queryInterval(VertexDescription.Semantics.M, 0); + double m = polygon.getAttributeAsDbl(VertexDescription.Semantics.M, 0, 0); + assertTrue(m == interval.vmin); + m = polygon.getAttributeAsDbl(VertexDescription.Semantics.M, 1, 0); + assertTrue(m == interval.vmax); + m = polygon.getAttributeAsDbl(VertexDescription.Semantics.M, 2, 0); + assertTrue(m == interval.vmin); + m = polygon.getAttributeAsDbl(VertexDescription.Semantics.M, 3, 0); + assertTrue(m == interval.vmax); + + interval = envelope.queryInterval(VertexDescription.Semantics.ID, 0); + double id = polygon.getAttributeAsDbl(VertexDescription.Semantics.ID, 0, 0); + assertTrue(id == interval.vmin); + id = polygon.getAttributeAsDbl(VertexDescription.Semantics.ID, 1, 0); + assertTrue(id == interval.vmax); + id = polygon.getAttributeAsDbl(VertexDescription.Semantics.ID, 2, 0); + assertTrue(id == interval.vmin); + id = polygon.getAttributeAsDbl(VertexDescription.Semantics.ID, 3, 0); + assertTrue(id == interval.vmax); + } + + @Test + public static void testImportExportWkbGeometryCollection() { + OperatorImportFromWkb importerWKB = (OperatorImportFromWkb) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ImportFromWkb); + + int offset = 0; + ByteBuffer wkbBuffer = ByteBuffer.allocate(600).order(ByteOrder.nativeOrder()); + wkbBuffer.put(offset, (byte) WkbByteOrder.wkbNDR); + offset += 1; // byte order + wkbBuffer.putInt(offset, WkbGeometryType.wkbGeometryCollection); + offset += 4; // type + wkbBuffer.putInt(offset, 3); // 3 geometries + offset += 4; + wkbBuffer.put(offset, (byte) WkbByteOrder.wkbNDR); + offset += 1; + wkbBuffer.putInt(offset, WkbGeometryType.wkbPoint); + offset += 4; + wkbBuffer.putDouble(offset, 0); + offset += 8; + wkbBuffer.putDouble(offset, 0); + offset += 8; + wkbBuffer.put(offset, (byte) WkbByteOrder.wkbNDR); + offset += 1; // byte order + wkbBuffer.putInt(offset, WkbGeometryType.wkbGeometryCollection); + offset += 4; // type + wkbBuffer.putInt(offset, 7); // 7 empty geometries + offset += 4; + wkbBuffer.put(offset, (byte) WkbByteOrder.wkbNDR); + offset += 1; + wkbBuffer.putInt(offset, WkbGeometryType.wkbLineString); + offset += 4; + wkbBuffer.putInt(offset, 0); // 0 points, for empty linestring + offset += 4; + wkbBuffer.put(offset, (byte) WkbByteOrder.wkbNDR); + offset += 1; + wkbBuffer.putInt(offset, WkbGeometryType.wkbPolygon); + offset += 4; + wkbBuffer.putInt(offset, 0); // 0 points, for empty polygon + offset += 4; + wkbBuffer.put(offset, (byte) WkbByteOrder.wkbNDR); + offset += 1; + wkbBuffer.putInt(offset, WkbGeometryType.wkbMultiPolygon); + offset += 4; + wkbBuffer.putInt(offset, 0); // 0 points, for empty multipolygon + offset += 4; + wkbBuffer.put(offset, (byte) WkbByteOrder.wkbNDR); + offset += 1; + wkbBuffer.putInt(offset, WkbGeometryType.wkbMultiLineString); + offset += 4; + wkbBuffer.putInt(offset, 0); // 0 points, for empty multilinestring + offset += 4; + wkbBuffer.put(offset, (byte) WkbByteOrder.wkbNDR); + offset += 1; + wkbBuffer.putInt(offset, WkbGeometryType.wkbGeometryCollection); + offset += 4; + wkbBuffer.putInt(offset, 0); // 0 geometries, for empty + // geometrycollection + offset += 4; + wkbBuffer.put(offset, (byte) WkbByteOrder.wkbNDR); + offset += 1; + wkbBuffer.putInt(offset, WkbGeometryType.wkbMultiPoint); + offset += 4; + wkbBuffer.putInt(offset, 0); // 0 points, for empty multipoint + offset += 4; + wkbBuffer.put(offset, (byte) WkbByteOrder.wkbNDR); + offset += 1; + wkbBuffer.putInt(offset, WkbGeometryType.wkbPoint); + offset += 4; + wkbBuffer.putDouble(offset, 66); + offset += 8; + wkbBuffer.putDouble(offset, 88); + offset += 8; + wkbBuffer.put(offset, (byte) WkbByteOrder.wkbNDR); + offset += 1; + wkbBuffer.putInt(offset, WkbGeometryType.wkbPoint); + offset += 4; + wkbBuffer.putDouble(offset, 13); + offset += 8; + wkbBuffer.putDouble(offset, 17); + offset += 8; + + // "GeometryCollection( Point (0 0), GeometryCollection( LineString empty, Polygon empty, MultiPolygon empty, MultiLineString empty, MultiPoint empty ), Point (13 17) )"; + OGCStructure structure = importerWKB.executeOGC(0, wkbBuffer, null).m_structures.get(0); + + assertTrue(structure.m_type == 7); + assertTrue(structure.m_structures.get(0).m_type == 1); + assertTrue(structure.m_structures.get(1).m_type == 7); + assertTrue(structure.m_structures.get(2).m_type == 1); + + assertTrue(structure.m_structures.get(1).m_structures.get(0).m_type == 2); + assertTrue(structure.m_structures.get(1).m_structures.get(1).m_type == 3); + assertTrue(structure.m_structures.get(1).m_structures.get(2).m_type == 6); + assertTrue(structure.m_structures.get(1).m_structures.get(3).m_type == 5); + assertTrue(structure.m_structures.get(1).m_structures.get(4).m_type == 7); + assertTrue(structure.m_structures.get(1).m_structures.get(5).m_type == 4); + assertTrue(structure.m_structures.get(1).m_structures.get(6).m_type == 1); + + Point p = (Point) structure.m_structures.get(1).m_structures.get(6).m_geometry; + assertTrue(p.getX() == 66); + assertTrue(p.getY() == 88); + + p = (Point) structure.m_structures.get(2).m_geometry; + assertTrue(p.getX() == 13); + assertTrue(p.getY() == 17); + } + + @Test + public static void testImportExportWKBPolygon() { + OperatorExportToWkb exporterWKB = (OperatorExportToWkb) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ExportToWkb); + OperatorExportToWkt exporterWKT = (OperatorExportToWkt) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ExportToWkt); + OperatorImportFromWkb importerWKB = (OperatorImportFromWkb) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ImportFromWkb); + + // Test Import Polygon with bad rings + int offset = 0; + ByteBuffer wkbBuffer = ByteBuffer.allocate(500).order(ByteOrder.nativeOrder()); + wkbBuffer.put(offset, (byte) WkbByteOrder.wkbNDR); + offset += 1; // byte order + wkbBuffer.putInt(offset, WkbGeometryType.wkbPolygon); + offset += 4; // type + wkbBuffer.putInt(offset, 8); + offset += 4; // num rings + wkbBuffer.putInt(offset, 4); + offset += 4; // num points + wkbBuffer.putDouble(offset, 0.0); + offset += 8; // x + wkbBuffer.putDouble(offset, 0.0); + offset += 8; // y + wkbBuffer.putDouble(offset, 0.0); + offset += 8; // x + wkbBuffer.putDouble(offset, 10.0); + offset += 8; // y + wkbBuffer.putDouble(offset, 10.0); + offset += 8; // x + wkbBuffer.putDouble(offset, 10.0); + offset += 8; // y + wkbBuffer.putDouble(offset, 0.0); + offset += 8; // x + wkbBuffer.putDouble(offset, 0.0); + offset += 8; // y + wkbBuffer.putInt(offset, 1); + offset += 4; // num points + wkbBuffer.putDouble(offset, 36.0); + offset += 8; // x + wkbBuffer.putDouble(offset, 17.0); + offset += 8; // y + wkbBuffer.putInt(offset, 2); + offset += 4; // num points + wkbBuffer.putDouble(offset, 19.0); + offset += 8; // x + wkbBuffer.putDouble(offset, 19.0); + offset += 8; // y + wkbBuffer.putDouble(offset, -19.0); + offset += 8; // x + wkbBuffer.putDouble(offset, -19.0); + offset += 8; // y + wkbBuffer.putInt(offset, 4); + offset += 4; // num points + wkbBuffer.putDouble(offset, 23.0); + offset += 8; // x + wkbBuffer.putDouble(offset, 88); + offset += 8; // y + wkbBuffer.putDouble(offset, 13.0); + offset += 8; // x + wkbBuffer.putDouble(offset, 43.0); + offset += 8; // y + wkbBuffer.putDouble(offset, 59.0); + offset += 8; // x + wkbBuffer.putDouble(offset, 79.0); + offset += 8; // y + wkbBuffer.putDouble(offset, 83.0); + offset += 8; // x + wkbBuffer.putDouble(offset, 87.0); + offset += 8; // y + wkbBuffer.putInt(offset, 3); + offset += 4; // num points + wkbBuffer.putDouble(offset, 23.0); + offset += 8; // x + wkbBuffer.putDouble(offset, 88); + offset += 8; // y + wkbBuffer.putDouble(offset, 88); + offset += 8; // x + wkbBuffer.putDouble(offset, 43.0); + offset += 8; // y + wkbBuffer.putDouble(offset, 67.0); + offset += 8; // x + wkbBuffer.putDouble(offset, 79.0); + offset += 8; // y + wkbBuffer.putInt(offset, 0); + offset += 4; // num points + wkbBuffer.putInt(offset, 3); + offset += 4; // num points + wkbBuffer.putDouble(offset, 23.0); + offset += 8; // x + wkbBuffer.putDouble(offset, 88); + offset += 8; // y + wkbBuffer.putDouble(offset, 88); + offset += 8; // x + wkbBuffer.putDouble(offset, 43.0); + offset += 8; // y + wkbBuffer.putDouble(offset, 67.0); + offset += 8; // x + wkbBuffer.putDouble(offset, 88); + offset += 8; // y + wkbBuffer.putInt(offset, 2); + offset += 4; // num points + wkbBuffer.putDouble(offset, 23.0); + offset += 8; // x + wkbBuffer.putDouble(offset, 67.0); + offset += 8; // y + wkbBuffer.putDouble(offset, 43.0); + offset += 8; // x + wkbBuffer.putDouble(offset, 67.0); + offset += 8; // y + + Geometry p = importerWKB.execute(0, Geometry.Type.Polygon, wkbBuffer, null); + int pc = ((Polygon) p).getPathCount(); + String wktString = exporterWKT.execute(0, p, null); + assertTrue(wktString.equals("MULTIPOLYGON (((0 0, 10 10, 0 10, 0 0), (36 17, 36 17, 36 17), (19 19, -19 -19, 19 19), (23 88, 83 87, 59 79, 13 43, 23 88), (23 88, 67 79, 88 43, 23 88), (23 88, 67 88, 88 43, 23 88), (23 67, 43 67, 23 67)))")); + + wktString = exporterWKT.execute(WktExportFlags.wktExportPolygon, p, null); + assertTrue(wktString.equals("POLYGON ((0 0, 10 10, 0 10, 0 0), (36 17, 36 17, 36 17), (19 19, -19 -19, 19 19), (23 88, 83 87, 59 79, 13 43, 23 88), (23 88, 67 79, 88 43, 23 88), (23 88, 67 88, 88 43, 23 88), (23 67, 43 67, 23 67))")); + + Polygon polygon = makePolygon(); + + // Test Import Polygon from Polygon8 + ByteBuffer polygonWKBBuffer = exporterWKB.execute(0, polygon, null); + int wkbType = polygonWKBBuffer.getInt(1); + assertTrue(wkbType == WkbGeometryType.wkbMultiPolygonZM); + Geometry polygonWKBGeometry = importerWKB.execute(0, Geometry.Type.Polygon, polygonWKBBuffer, null); + TestCommonMethods.compareGeometryContent((MultiVertexGeometry) polygonWKBGeometry, polygon); + + // Test WKB_export_multi_polygon on nonempty single part polygon + Polygon polygon2 = makePolygon2(); + assertTrue(polygon2.getPathCount() == 1); + polygonWKBBuffer = exporterWKB.execute(WkbExportFlags.wkbExportMultiPolygon, polygon2, null); + polygonWKBGeometry = importerWKB.execute(0, Geometry.Type.Polygon, polygonWKBBuffer, null); + TestCommonMethods.compareGeometryContent((MultiVertexGeometry) polygonWKBGeometry, polygon2); + wkbType = polygonWKBBuffer.getInt(1); + assertTrue(wkbType == WkbGeometryType.wkbMultiPolygonZM); + + // Test WKB_export_polygon on nonempty single part polygon + assertTrue(polygon2.getPathCount() == 1); + polygonWKBBuffer = exporterWKB.execute(WkbExportFlags.wkbExportPolygon, polygon2, null); + polygonWKBGeometry = importerWKB.execute(0, Geometry.Type.Polygon, polygonWKBBuffer, null); + TestCommonMethods.compareGeometryContent((MultiVertexGeometry) polygonWKBGeometry, polygon2); + wkbType = polygonWKBBuffer.getInt(1); + assertTrue(wkbType == WkbGeometryType.wkbPolygonZM); + + // Test WKB_export_polygon on empty polygon + Polygon polygon3 = new Polygon(); + polygonWKBBuffer = exporterWKB.execute(WkbExportFlags.wkbExportPolygon, polygon3, null); + polygonWKBGeometry = importerWKB.execute(0, Geometry.Type.Polygon, polygonWKBBuffer, null); + assertTrue(polygonWKBGeometry.isEmpty() == true); + wkbType = polygonWKBBuffer.getInt(1); + assertTrue(wkbType == WkbGeometryType.wkbPolygon); + + // Test WKB_export_defaults on empty polygon + polygonWKBBuffer = exporterWKB.execute(0, polygon3, null); + polygonWKBGeometry = importerWKB.execute(0, Geometry.Type.Polygon, polygonWKBBuffer, null); + assertTrue(polygonWKBGeometry.isEmpty() == true); + wkbType = polygonWKBBuffer.getInt(1); + assertTrue(wkbType == WkbGeometryType.wkbMultiPolygon); + } + + @Test + public static void testImportExportWKBPolyline() { + OperatorExportToWkb exporterWKB = (OperatorExportToWkb) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ExportToWkb); + OperatorExportToWkt exporterWKT = (OperatorExportToWkt) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ExportToWkt); + OperatorImportFromWkb importerWKB = (OperatorImportFromWkb) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ImportFromWkb); + + // Test Import Polyline with bad paths (i.e. paths with one point or + // zero points) + int offset = 0; + ByteBuffer wkbBuffer = ByteBuffer.allocate(500).order(ByteOrder.nativeOrder()); + wkbBuffer.put(offset, (byte) WkbByteOrder.wkbNDR); + offset += 1; // byte order + wkbBuffer.putInt(offset, WkbGeometryType.wkbMultiLineString); + offset += 4; // type + wkbBuffer.putInt(offset, 4); + offset += 4; // num paths + wkbBuffer.put(offset, (byte) WkbByteOrder.wkbNDR); + offset += 1; // byte order + wkbBuffer.putInt(offset, WkbGeometryType.wkbLineString); + offset += 4; // type + wkbBuffer.putInt(offset, 1); + offset += 4; // num points + wkbBuffer.putDouble(offset, 36.0); + offset += 8; // x + wkbBuffer.putDouble(offset, 17.0); + offset += 8; // y + wkbBuffer.put(offset, (byte) WkbByteOrder.wkbNDR); + offset += 1; // byte order + wkbBuffer.putInt(offset, WkbGeometryType.wkbLineString); + offset += 4; // type + wkbBuffer.putInt(offset, 0); + offset += 4; // num points + wkbBuffer.put(offset, (byte) WkbByteOrder.wkbNDR); + offset += 1; // byte order + wkbBuffer.putInt(offset, WkbGeometryType.wkbLineString); + offset += 4; // type + wkbBuffer.putInt(offset, 1); + offset += 4; // num points + wkbBuffer.putDouble(offset, 19.0); + offset += 8; // x + wkbBuffer.putDouble(offset, 19.0); + offset += 8; // y + wkbBuffer.put(offset, (byte) WkbByteOrder.wkbNDR); + offset += 1; // byte order + wkbBuffer.putInt(offset, WkbGeometryType.wkbLineString); + offset += 4; // type + wkbBuffer.putInt(offset, 3); + offset += 4; // num points + wkbBuffer.putDouble(offset, 88); + offset += 8; // x + wkbBuffer.putDouble(offset, 29.0); + offset += 8; // y + wkbBuffer.putDouble(offset, 13.0); + offset += 8; // x + wkbBuffer.putDouble(offset, 43.0); + offset += 8; // y + wkbBuffer.putDouble(offset, 59.0); + offset += 8; // x + wkbBuffer.putDouble(offset, 88); + offset += 8; // y + + Polyline p = (Polyline) (importerWKB.execute(0, Geometry.Type.Polyline, wkbBuffer, null)); + int pc = p.getPointCount(); + int pac = p.getPathCount(); + assertTrue(p.getPointCount() == 7); + assertTrue(p.getPathCount() == 3); + + String wktString = exporterWKT.execute(0, p, null); + assertTrue(wktString.equals("MULTILINESTRING ((36 17, 36 17), (19 19, 19 19), (88 29, 13 43, 59 88))")); + + Polyline polyline = makePolyline(); + polyline.dropAttribute(VertexDescription.Semantics.ID); + + // Test Import Polyline from Polyline + ByteBuffer polylineWKBBuffer = exporterWKB.execute(0, polyline, null); + int wkbType = polylineWKBBuffer.getInt(1); + assertTrue(wkbType == WkbGeometryType.wkbMultiLineStringZM); + Geometry polylineWKBGeometry = importerWKB.execute(0, Geometry.Type.Polyline, polylineWKBBuffer, null); + TestCommonMethods.compareGeometryContent((MultiVertexGeometry) polylineWKBGeometry, polyline); + + // Test wkbExportMultiPolyline on nonempty single part polyline + Polyline polyline2 = makePolyline2(); + assertTrue(polyline2.getPathCount() == 1); + polylineWKBBuffer = exporterWKB.execute(WkbExportFlags.wkbExportMultiLineString, polyline2, null); + polylineWKBGeometry = importerWKB.execute(0, Geometry.Type.Polyline, polylineWKBBuffer, null); + TestCommonMethods.compareGeometryContent((MultiVertexGeometry) polylineWKBGeometry, polyline2); + wkbType = polylineWKBBuffer.getInt(1); + assertTrue(wkbType == WkbGeometryType.wkbMultiLineStringZM); + + // Test wkbExportPolyline on nonempty single part polyline + assertTrue(polyline2.getPathCount() == 1); + polylineWKBBuffer = exporterWKB.execute(WkbExportFlags.wkbExportLineString, polyline2, null); + polylineWKBGeometry = importerWKB.execute(0, Geometry.Type.Polyline, polylineWKBBuffer, null); + TestCommonMethods.compareGeometryContent((MultiVertexGeometry) polylineWKBGeometry, polyline2); + wkbType = polylineWKBBuffer.getInt(1); + assertTrue(wkbType == WkbGeometryType.wkbLineStringZM); + + // Test wkbExportPolyline on empty polyline + Polyline polyline3 = new Polyline(); + polylineWKBBuffer = exporterWKB.execute(WkbExportFlags.wkbExportLineString, polyline3, null); + polylineWKBGeometry = importerWKB.execute(0, Geometry.Type.Polyline, polylineWKBBuffer, null); + assertTrue(polylineWKBGeometry.isEmpty() == true); + wkbType = polylineWKBBuffer.getInt(1); + assertTrue(wkbType == WkbGeometryType.wkbLineString); + + // Test WKB_export_defaults on empty polyline + polylineWKBBuffer = exporterWKB.execute(0, polyline3, null); + polylineWKBGeometry = importerWKB.execute(0, Geometry.Type.Polyline, polylineWKBBuffer, null); + assertTrue(polylineWKBGeometry.isEmpty() == true); + wkbType = polylineWKBBuffer.getInt(1); + assertTrue(wkbType == WkbGeometryType.wkbMultiLineString); + } + + @Test + public static void testImportExportWKBMultiPoint() { + OperatorExportToWkb exporterWKB = (OperatorExportToWkb) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ExportToWkb); + OperatorImportFromWkb importerWKB = (OperatorImportFromWkb) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ImportFromWkb); + + MultiPoint multipoint = makeMultiPoint(); + multipoint.dropAttribute(VertexDescription.Semantics.ID); + + // Test Import Multi_point from Multi_point + ByteBuffer multipointWKBBuffer = exporterWKB.execute(0, multipoint, null); + int wkbType = multipointWKBBuffer.getInt(1); + assertTrue(wkbType == WkbGeometryType.wkbMultiPointZ); + MultiPoint multipointWKBGeometry = (MultiPoint) (importerWKB.execute(0, Geometry.Type.MultiPoint, multipointWKBBuffer, null)); + TestCommonMethods.compareGeometryContent((MultiVertexGeometry) multipointWKBGeometry, multipoint); + + // Test WKB_export_point on nonempty single point Multi_point + MultiPoint multipoint2 = makeMultiPoint2(); + assertTrue(multipoint2.getPointCount() == 1); + ByteBuffer pointWKBBuffer = exporterWKB.execute(WkbExportFlags.wkbExportPoint, multipoint2, null); + Point pointWKBGeometry = (Point) (importerWKB.execute(0, Geometry.Type.Point, pointWKBBuffer, null)); + Point3D point3d, mpoint3d; + point3d = pointWKBGeometry.getXYZ(); + mpoint3d = multipoint2.getXYZ(0); + assertTrue(point3d.x == mpoint3d.x && point3d.y == mpoint3d.y && point3d.z == mpoint3d.z); + wkbType = pointWKBBuffer.getInt(1); + assertTrue(wkbType == WkbGeometryType.wkbPointZ); + + // Test WKB_export_point on empty Multi_point + MultiPoint multipoint3 = new MultiPoint(); + pointWKBBuffer = exporterWKB.execute(WkbExportFlags.wkbExportPoint, multipoint3, null); + pointWKBGeometry = (Point) (importerWKB.execute(0, Geometry.Type.Point, pointWKBBuffer, null)); + assertTrue(pointWKBGeometry.isEmpty() == true); + wkbType = pointWKBBuffer.getInt(1); + assertTrue(wkbType == WkbGeometryType.wkbPoint); + + // Test WKB_export_defaults on empty Multi_point + multipointWKBBuffer = exporterWKB.execute(0, multipoint3, null); + multipointWKBGeometry = (MultiPoint) (importerWKB.execute(0, Geometry.Type.MultiPoint, multipointWKBBuffer, null)); + assertTrue(multipointWKBGeometry.isEmpty() == true); + wkbType = multipointWKBBuffer.getInt(1); + assertTrue(wkbType == WkbGeometryType.wkbMultiPoint); + } + + @Test + public static void testImportExportWKBPoint() { + OperatorExportToWkb exporterWKB = (OperatorExportToWkb) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ExportToWkb); + OperatorImportFromWkb importerWKB = (OperatorImportFromWkb) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ImportFromWkb); + + // Point + Point point = makePoint(); + + // Test Import Point from Point + ByteBuffer pointWKBBuffer = exporterWKB.execute(0, point, null); + int wkbType = pointWKBBuffer.getInt(1); + assertTrue(wkbType == WkbGeometryType.wkbPointZM); + Point pointWKBGeometry = (Point) (importerWKB.execute(0, Geometry.Type.Point, pointWKBBuffer, null)); + + double x_1 = point.getX(); + double x2 = pointWKBGeometry.getX(); + assertTrue(x_1 == x2); + + double y1 = point.getY(); + double y2 = pointWKBGeometry.getY(); + assertTrue(y1 == y2); + + double z_1 = point.getZ(); + double z_2 = pointWKBGeometry.getZ(); + assertTrue(z_1 == z_2); + + double m1 = point.getM(); + double m2 = pointWKBGeometry.getM(); + assertTrue(m1 == m2); + + // Test WKB_export_defaults on empty point + Point point2 = new Point(); + pointWKBBuffer = exporterWKB.execute(0, point2, null); + pointWKBGeometry = (Point) (importerWKB.execute(0, Geometry.Type.Point, pointWKBBuffer, null)); + assertTrue(pointWKBGeometry.isEmpty() == true); + wkbType = pointWKBBuffer.getInt(1); + assertTrue(wkbType == WkbGeometryType.wkbPoint); + + // Test WKB_export_point on empty point + pointWKBBuffer = exporterWKB.execute(WkbExportFlags.wkbExportPoint, point2, null); + pointWKBGeometry = (Point) (importerWKB.execute(0, Geometry.Type.Point, pointWKBBuffer, null)); + assertTrue(pointWKBGeometry.isEmpty() == true); + wkbType = pointWKBBuffer.getInt(1); + assertTrue(wkbType == WkbGeometryType.wkbPoint); + + // Test WKB_export_multi_point on empty point + MultiPoint multipoint = new MultiPoint(); + ByteBuffer multipointWKBBuffer = exporterWKB.execute(WkbExportFlags.wkbExportMultiPoint, multipoint, null); + MultiPoint multipointWKBGeometry = (MultiPoint) (importerWKB.execute(0, Geometry.Type.MultiPoint, multipointWKBBuffer, null)); + assertTrue(multipointWKBGeometry.isEmpty() == true); + wkbType = multipointWKBBuffer.getInt(1); + assertTrue(wkbType == WkbGeometryType.wkbMultiPoint); + + // Test WKB_export_point on nonempty single point Multi_point + MultiPoint multipoint2 = makeMultiPoint2(); + assertTrue(multipoint2.getPointCount() == 1); + pointWKBBuffer = exporterWKB.execute(WkbExportFlags.wkbExportPoint, multipoint2, null); + pointWKBGeometry = (Point) (importerWKB.execute(0, Geometry.Type.Point, pointWKBBuffer, null)); + Point3D point3d, mpoint3d; + point3d = pointWKBGeometry.getXYZ(); + mpoint3d = multipoint2.getXYZ(0); + assertTrue(point3d.x == mpoint3d.x && point3d.y == mpoint3d.y && point3d.z == mpoint3d.z); + wkbType = pointWKBBuffer.getInt(1); + assertTrue(wkbType == WkbGeometryType.wkbPointZ); + } + + @Test + public static void testImportExportWKBEnvelope() { + OperatorExportToWkb exporterWKB = (OperatorExportToWkb) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ExportToWkb); + OperatorImportFromWkb importerWKB = (OperatorImportFromWkb) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ImportFromWkb); + + // Test Export Envelope to Polygon (WKB_export_defaults) + Envelope envelope = makeEnvelope(); + envelope.dropAttribute(VertexDescription.Semantics.ID); + + ByteBuffer polygonWKBBuffer = exporterWKB.execute(0, envelope, null); + int wkbType = polygonWKBBuffer.getInt(1); + assertTrue(wkbType == WkbGeometryType.wkbPolygonZM); + Polygon polygon = (Polygon) (importerWKB.execute(0, Geometry.Type.Polygon, polygonWKBBuffer, null)); + int point_count = polygon.getPointCount(); + assertTrue(point_count == 4); + + Envelope2D env = new Envelope2D(); + Envelope1D interval; + + envelope.queryEnvelope2D(env); + interval = envelope.queryInterval(VertexDescription.Semantics.Z, 0); + Point3D point3d; + point3d = polygon.getXYZ(0); + assertTrue(point3d.x == env.xmin && point3d.y == env.ymin && point3d.z == interval.vmin); + point3d = polygon.getXYZ(1); + assertTrue(point3d.x == env.xmin && point3d.y == env.ymax && point3d.z == interval.vmax); + point3d = polygon.getXYZ(2); + assertTrue(point3d.x == env.xmax && point3d.y == env.ymax && point3d.z == interval.vmin); + point3d = polygon.getXYZ(3); + assertTrue(point3d.x == env.xmax && point3d.y == env.ymin && point3d.z == interval.vmax); + + interval = envelope.queryInterval(VertexDescription.Semantics.M, 0); + double m = polygon.getAttributeAsDbl(VertexDescription.Semantics.M, 0, 0); + assertTrue(m == interval.vmin); + m = polygon.getAttributeAsDbl(VertexDescription.Semantics.M, 1, 0); + assertTrue(m == interval.vmax); + m = polygon.getAttributeAsDbl(VertexDescription.Semantics.M, 2, 0); + assertTrue(m == interval.vmin); + m = polygon.getAttributeAsDbl(VertexDescription.Semantics.M, 3, 0); + assertTrue(m == interval.vmax); + + // Test WKB_export_multi_polygon on nonempty Envelope + polygonWKBBuffer = exporterWKB.execute(WkbExportFlags.wkbExportMultiPolygon, envelope, null); + wkbType = polygonWKBBuffer.getInt(1); + assertTrue(wkbType == WkbGeometryType.wkbMultiPolygonZM); + polygon = (Polygon) (importerWKB.execute(0, Geometry.Type.Polygon, polygonWKBBuffer, null)); + point_count = polygon.getPointCount(); + assertTrue(point_count == 4); + + envelope.queryEnvelope2D(env); + interval = envelope.queryInterval(VertexDescription.Semantics.Z, 0); + point3d = polygon.getXYZ(0); + assertTrue(point3d.x == env.xmin && point3d.y == env.ymin && point3d.z == interval.vmin); + point3d = polygon.getXYZ(1); + assertTrue(point3d.x == env.xmin && point3d.y == env.ymax && point3d.z == interval.vmax); + point3d = polygon.getXYZ(2); + assertTrue(point3d.x == env.xmax && point3d.y == env.ymax && point3d.z == interval.vmin); + point3d = polygon.getXYZ(3); + assertTrue(point3d.x == env.xmax && point3d.y == env.ymin && point3d.z == interval.vmax); + + interval = envelope.queryInterval(VertexDescription.Semantics.M, 0); + m = polygon.getAttributeAsDbl(VertexDescription.Semantics.M, 0, 0); + assertTrue(m == interval.vmin); + m = polygon.getAttributeAsDbl(VertexDescription.Semantics.M, 1, 0); + assertTrue(m == interval.vmax); + m = polygon.getAttributeAsDbl(VertexDescription.Semantics.M, 2, 0); + assertTrue(m == interval.vmin); + m = polygon.getAttributeAsDbl(VertexDescription.Semantics.M, 3, 0); + assertTrue(m == interval.vmax); + + // Test WKB_export_defaults on empty Envelope + Envelope envelope2 = new Envelope(); + polygonWKBBuffer = exporterWKB.execute(0, envelope2, null); + wkbType = polygonWKBBuffer.getInt(1); + assertTrue(wkbType == WkbGeometryType.wkbPolygon); + polygon = (Polygon) (importerWKB.execute(0, Geometry.Type.Polygon, polygonWKBBuffer, null)); + assertTrue(polygon.isEmpty()); + + // Test WKB_export_polygon on empty Envelope + polygonWKBBuffer = exporterWKB.execute(WkbExportFlags.wkbExportPolygon, envelope2, null); + wkbType = polygonWKBBuffer.getInt(1); + assertTrue(wkbType == WkbGeometryType.wkbPolygon); + polygon = (Polygon) (importerWKB.execute(0, Geometry.Type.Polygon, polygonWKBBuffer, null)); + assertTrue(polygon.isEmpty()); + } + + @Test + public static void testImportExportWktGeometryCollection() { + OperatorImportFromWkt importerWKT = (OperatorImportFromWkt) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ImportFromWkt); + OperatorExportToWkt exporterWKT = (OperatorExportToWkt) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ExportToWkt); + + String wktString; + Envelope2D envelope = new Envelope2D(); + WktParser wktParser = new WktParser(); + + wktString = "GeometryCollection( Point (0 0), GeometryCollection( Point (0 0) , Point (1 1) , Point (2 2), LineString empty ), Point (1 1), Point (2 2) )"; + OGCStructure structure = importerWKT.executeOGC(0, wktString, null).m_structures.get(0); + + assertTrue(structure.m_type == 7); + assertTrue(structure.m_structures.get(0).m_type == 1); + assertTrue(structure.m_structures.get(0).m_type == 1); + assertTrue(structure.m_structures.get(1).m_type == 7); + assertTrue(structure.m_structures.get(2).m_type == 1); + assertTrue(structure.m_structures.get(3).m_type == 1); + + assertTrue(structure.m_structures.get(1).m_structures.get(0).m_type == 1); + assertTrue(structure.m_structures.get(1).m_structures.get(1).m_type == 1); + assertTrue(structure.m_structures.get(1).m_structures.get(2).m_type == 1); + assertTrue(structure.m_structures.get(1).m_structures.get(3).m_type == 2); + } + + @Test + public static void testImportExportWktMultiPolygon() { + OperatorImportFromWkt importerWKT = (OperatorImportFromWkt) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ImportFromWkt); + OperatorExportToWkt exporterWKT = (OperatorExportToWkt) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ExportToWkt); + + Polygon polygon; + String wktString; + Envelope2D envelope = new Envelope2D(); + WktParser wktParser = new WktParser(); + + // Test Import from MultiPolygon + wktString = "Multipolygon M empty"; + polygon = (Polygon) importerWKT.execute(0, Geometry.Type.Polygon, wktString, null); + assertTrue(polygon != null); + assertTrue(polygon.isEmpty()); + assertTrue(polygon.hasAttribute(VertexDescription.Semantics.M)); + + polygon = (Polygon) GeometryEngine.geometryFromWkt(wktString, 0, Geometry.Type.Unknown); + assertTrue(polygon != null); + assertTrue(polygon.isEmpty()); + assertTrue(polygon.hasAttribute(VertexDescription.Semantics.M)); + + wktString = exporterWKT.execute(0, polygon, null); + assertTrue(wktString.equals("MULTIPOLYGON M EMPTY")); + + wktString = GeometryEngine.geometryToWkt(polygon, 0); + assertTrue(wktString.equals("MULTIPOLYGON M EMPTY")); + + wktString = "Multipolygon Z (empty, (empty, (10 10 5, 20 10 5, 20 20 5, 10 20 5, 10 10 5), (12 12 3), empty, (10 10 1, 12 12 1)), empty, ((90 90 88, 60 90 7, 60 60 7), empty, (70 70 7, 80 80 7, 70 80 7, 70 70 7)), empty)"; + polygon = (Polygon) (importerWKT.execute(0, Geometry.Type.Polygon, wktString, null)); + assertTrue(polygon != null); + polygon.queryEnvelope2D(envelope); + assertTrue(envelope.xmin == 10 && envelope.xmax == 90 && envelope.ymin == 10 && envelope.ymax == 90); + assertTrue(polygon.getPointCount() == 14); + assertTrue(polygon.getPathCount() == 5); + // assertTrue(polygon.calculate_area_2D() > 0.0); + assertTrue(polygon.hasAttribute(VertexDescription.Semantics.Z)); + + double z = polygon.getAttributeAsDbl(VertexDescription.Semantics.Z, 0, 0); + assertTrue(z == 5); + + // Test Export to WKT MultiPolygon + wktString = exporterWKT.execute(0, polygon, null); + assertTrue(wktString.equals("MULTIPOLYGON Z (((10 10 5, 20 10 5, 20 20 5, 10 20 5, 10 10 5), (12 12 3, 12 12 3, 12 12 3), (10 10 1, 12 12 1, 10 10 1)), ((90 90 88, 60 90 7, 60 60 7, 90 90 88), (70 70 7, 70 80 7, 80 80 7, 70 70 7)))")); + wktParser.resetParser(wktString); + while (wktParser.nextToken() != WktParser.WktToken.not_available) { + } + + // Test import Polygon + wktString = "POLYGON z (EMPTY, EMPTY, (10 10 5, 10 20 5, 20 20 5, 20 10 5), (12 12 3), EMPTY, (10 10 1, 12 12 1), EMPTY, (60 60 7, 60 90 7, 90 90 7, 60 60 7), EMPTY, (70 70 7, 70 80 7, 80 80 7), EMPTY)"; + polygon = (Polygon) (importerWKT.execute(0, Geometry.Type.Polygon, wktString, null)); + assertTrue(polygon != null); + assertTrue(polygon.getPointCount() == 14); + assertTrue(polygon.getPathCount() == 5); + assertTrue(polygon.hasAttribute(VertexDescription.Semantics.Z)); + + // Test Export to WKT Polygon + wktString = exporterWKT.execute(WktExportFlags.wktExportPolygon, polygon, null); + assertTrue(wktString.equals("POLYGON Z ((10 10 5, 20 10 5, 20 20 5, 10 20 5, 10 10 5), (12 12 3, 12 12 3, 12 12 3), (10 10 1, 12 12 1, 10 10 1), (60 60 7, 60 90 7, 90 90 7, 60 60 7), (70 70 7, 70 80 7, 80 80 7, 70 70 7))")); + wktParser.resetParser(wktString); + while (wktParser.nextToken() != WktParser.WktToken.not_available) { + } + + Envelope env = new Envelope(); + env.addAttribute(VertexDescription.Semantics.Z); + polygon.queryEnvelope(env); + + wktString = exporterWKT.execute(0, env, null); + assertTrue(wktString.equals("POLYGON Z ((10 10 1, 90 10 7, 90 90 1, 10 90 7, 10 10 1))")); + wktParser.resetParser(wktString); + while (wktParser.nextToken() != WktParser.WktToken.not_available) { + } + + wktString = exporterWKT.execute(WktExportFlags.wktExportMultiPolygon, env, null); + assertTrue(wktString.equals("MULTIPOLYGON Z (((10 10 1, 90 10 7, 90 90 1, 10 90 7, 10 10 1)))")); + wktParser.resetParser(wktString); + while (wktParser.nextToken() != WktParser.WktToken.not_available) { + } + + env.setEmpty(); + + wktString = exporterWKT.execute(0, env, null); + assertTrue(wktString.equals("POLYGON Z EMPTY")); + wktParser.resetParser(wktString); + while (wktParser.nextToken() != WktParser.WktToken.not_available) { + } + + wktString = exporterWKT.execute(WktExportFlags.wktExportMultiPolygon, env, null); + assertTrue(wktString.equals("MULTIPOLYGON Z EMPTY")); + wktParser.resetParser(wktString); + while (wktParser.nextToken() != WktParser.WktToken.not_available) { + } + + wktString = "MULTIPOLYGON (((5 10, 8 10, 10 10, 10 0, 0 0, 0 10, 2 10, 5 10)))"; // ring + // is + // oriented + // clockwise + polygon = (Polygon) (importerWKT.execute(0, Geometry.Type.Polygon, wktString, null)); + assertTrue(polygon != null); + assertTrue(polygon.calculateArea2D() > 0); + + wktString = "MULTIPOLYGON Z (((90 10 7, 10 10 1, 10 90 7, 90 90 1, 90 10 7)))"; // ring + // is + // oriented + // clockwise + polygon = (Polygon) (importerWKT.execute(0, Geometry.Type.Polygon, wktString, null)); + assertTrue(polygon != null); + assertTrue(polygon.getPointCount() == 4); + assertTrue(polygon.getPathCount() == 1); + assertTrue(polygon.hasAttribute(VertexDescription.Semantics.Z)); + assertTrue(polygon.calculateArea2D() > 0); + + wktString = exporterWKT.execute(WktExportFlags.wktExportMultiPolygon, polygon, null); + assertTrue(wktString.equals("MULTIPOLYGON Z (((90 10 7, 90 90 1, 10 90 7, 10 10 1, 90 10 7)))")); + } + + @Test + public static void testImportExportWktPolygon() { + OperatorImportFromWkt importerWKT = (OperatorImportFromWkt) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ImportFromWkt); + // OperatorExportToWkt exporterWKT = + // (OperatorExportToWkt)OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ExportToWkt); + + Polygon polygon; + String wktString; + Envelope2D envelope = new Envelope2D(); + + // Test Import from Polygon + wktString = "Polygon ZM empty"; + polygon = (Polygon) (importerWKT.execute(0, Geometry.Type.Unknown, wktString, null)); + assertTrue(polygon != null); + assertTrue(polygon.isEmpty()); + assertTrue(polygon.hasAttribute(VertexDescription.Semantics.Z)); + assertTrue(polygon.hasAttribute(VertexDescription.Semantics.M)); + + wktString = "Polygon z (empty, (10 10 5, 20 10 5, 20 20 5, 10 20 5, 10 10 5), (12 12 3), empty, (10 10 1, 12 12 1))"; + polygon = (Polygon) (importerWKT.execute(0, Geometry.Type.Unknown, wktString, null)); + assertTrue(polygon != null); + polygon.queryEnvelope2D(envelope); + assertTrue(envelope.xmin == 10 && envelope.xmax == 20 && envelope.ymin == 10 && envelope.ymax == 20); + assertTrue(polygon.getPointCount() == 8); + assertTrue(polygon.getPathCount() == 3); + assertTrue(polygon.hasAttribute(VertexDescription.Semantics.Z)); + + wktString = "polygon ((35 10, 10 20, 15 40, 45 45, 35 10), (20 30, 35 35, 30 20, 20 30))"; + Polygon polygon2 = (Polygon) (importerWKT.execute(0, Geometry.Type.Unknown, wktString, null)); + assertTrue(polygon2 != null); + + // wktString = exporterWKT.execute(0, *polygon2, null); + } + + @Test + public static void testImportExportWktLineString() { + OperatorImportFromWkt importerWKT = (OperatorImportFromWkt) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ImportFromWkt); + // OperatorExportToWkt exporterWKT = + // (OperatorExportToWkt)OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ExportToWkt); + + Polyline polyline; + String wktString; + Envelope2D envelope = new Envelope2D(); + + // Test Import from LineString + wktString = "LineString ZM empty"; + polyline = (Polyline) (importerWKT.execute(0, Geometry.Type.Unknown, wktString, null)); + assertTrue(polyline != null); + assertTrue(polyline.isEmpty()); + assertTrue(polyline.hasAttribute(VertexDescription.Semantics.Z)); + assertTrue(polyline.hasAttribute(VertexDescription.Semantics.M)); + + wktString = "LineString m (10 10 5, 10 20 5, 20 20 5, 20 10 5)"; + polyline = (Polyline) (importerWKT.execute(0, Geometry.Type.Unknown, wktString, null)); + assertTrue(polyline != null); + polyline.queryEnvelope2D(envelope); + assertTrue(envelope.xmin == 10 && envelope.xmax == 20 && envelope.ymin == 10 && envelope.ymax == 20); + assertTrue(polyline.getPointCount() == 4); + assertTrue(polyline.getPathCount() == 1); + assertTrue(polyline.hasAttribute(VertexDescription.Semantics.M)); + } + + @Test + public static void testImportExportWktMultiLineString() { + OperatorImportFromWkt importerWKT = (OperatorImportFromWkt) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ImportFromWkt); + OperatorExportToWkt exporterWKT = (OperatorExportToWkt) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ExportToWkt); + + Polyline polyline; + String wktString; + Envelope2D envelope = new Envelope2D(); + WktParser wktParser = new WktParser(); + + // Test Import from MultiLineString + wktString = "MultiLineStringZMempty"; + polyline = (Polyline) (importerWKT.execute(0, Geometry.Type.Unknown, wktString, null)); + assertTrue(polyline != null); + assertTrue(polyline.isEmpty()); + assertTrue(polyline.hasAttribute(VertexDescription.Semantics.Z)); + assertTrue(polyline.hasAttribute(VertexDescription.Semantics.M)); + + wktString = "MultiLineStringm(empty, empty, (10 10 5, 10 20 5, 20 88 5, 20 10 5), (12 88 3), empty, (10 10 1, 12 12 1), empty, (88 60 7, 60 90 7, 90 90 7), empty, (70 70 7, 70 80 7, 80 80 7), empty)"; + polyline = (Polyline) (importerWKT.execute(0, Geometry.Type.Unknown, wktString, null)); + assertTrue(polyline != null); + polyline.queryEnvelope2D(envelope); + assertTrue(envelope.xmin == 10 && envelope.xmax == 90 && envelope.ymin == 10 && envelope.ymax == 90); + assertTrue(polyline.getPointCount() == 14); + assertTrue(polyline.getPathCount() == 5); + assertTrue(polyline.hasAttribute(VertexDescription.Semantics.M)); + + wktString = exporterWKT.execute(0, polyline, null); + assertTrue(wktString.equals("MULTILINESTRING M ((10 10 5, 10 20 5, 20 88 5, 20 10 5), (12 88 3, 12 88 3), (10 10 1, 12 12 1), (88 60 7, 60 90 7, 90 90 7), (70 70 7, 70 80 7, 80 80 7))")); + wktParser.resetParser(wktString); + while (wktParser.nextToken() != WktParser.WktToken.not_available) { + } + + // Test Import LineString + wktString = "Linestring Z(10 10 5, 10 20 5, 20 20 5, 20 10 5)"; + polyline = (Polyline) (importerWKT.execute(0, Geometry.Type.Unknown, wktString, null)); + assertTrue(polyline.getPointCount() == 4); + wktString = exporterWKT.execute(WktExportFlags.wktExportLineString, polyline, null); + assertTrue(wktString.equals("LINESTRING Z (10 10 5, 10 20 5, 20 20 5, 20 10 5)")); + wktParser.resetParser(wktString); + while (wktParser.nextToken() != WktParser.WktToken.not_available) { + } + + wktString = exporterWKT.execute(0, polyline, null); + assertTrue(wktString.equals("MULTILINESTRING Z ((10 10 5, 10 20 5, 20 20 5, 20 10 5))")); + wktParser.resetParser(wktString); + while (wktParser.nextToken() != WktParser.WktToken.not_available) { + } + } + + @Test + public static void testImportExportWktMultiPoint() { + OperatorImportFromWkt importerWKT = (OperatorImportFromWkt) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ImportFromWkt); + OperatorExportToWkt exporterWKT = (OperatorExportToWkt) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ExportToWkt); + + MultiPoint multipoint; + String wktString; + Envelope2D envelope = new Envelope2D(); + WktParser wktParser = new WktParser(); + + // Test Import from Multi_point + wktString = " MultiPoint ZM empty"; + multipoint = (MultiPoint) (importerWKT.execute(0, Geometry.Type.Unknown, wktString, null)); + assertTrue(multipoint != null); + assertTrue(multipoint.isEmpty()); + assertTrue(multipoint.hasAttribute(VertexDescription.Semantics.Z)); + assertTrue(multipoint.hasAttribute(VertexDescription.Semantics.M)); + + wktString = exporterWKT.execute(0, multipoint, null); + assertTrue(wktString.equals("MULTIPOINT ZM EMPTY")); + wktParser.resetParser(wktString); + while (wktParser.nextToken() != WktParser.WktToken.not_available) { + } + + wktString = exporterWKT.execute(WktExportFlags.wktExportPoint, multipoint, null); + assertTrue(wktString.equals("POINT ZM EMPTY")); + wktParser.resetParser(wktString); + while (wktParser.nextToken() != WktParser.WktToken.not_available) { + } + + multipoint = new MultiPoint(); + multipoint.add(118.15114354234563, 33.82234433423462345); + multipoint.add(88, 88); + + wktString = exporterWKT.execute(WktExportFlags.wktExportPrecision10, multipoint, null); + assertTrue(wktString.equals("MULTIPOINT ((118.1511435 33.82234433), (88 88))")); + wktParser.resetParser(wktString); + while (wktParser.nextToken() != WktParser.WktToken.not_available) { + } + + multipoint = new MultiPoint(); + multipoint.add(88, 2); + multipoint.add(88, 88); + + wktString = exporterWKT.execute(0, multipoint, null); + assertTrue(wktString.equals("MULTIPOINT ((88 2), (88 88))")); + wktParser.resetParser(wktString); + while (wktParser.nextToken() != WktParser.WktToken.not_available) { + } + + wktString = "Multipoint zm (empty, empty, (10 88 88 33), (10 20 5 33), (20 20 5 33), (20 10 5 33), (12 12 3 33), empty, (10 10 1 33), (12 12 1 33), empty, (60 60 7 33), (60 90.1 7 33), (90 90 7 33), empty, (70 70 7 33), (70 80 7 33), (80 80 7 33), empty)"; + multipoint = (MultiPoint) (importerWKT.execute(0, Geometry.Type.Unknown, wktString, null)); + assertTrue(multipoint != null); + multipoint.queryEnvelope2D(envelope); + // assertTrue(envelope.xmin == 10 && envelope.xmax == 90 && + // envelope.ymin == 10 && Math.abs(envelope.ymax - 90.1) <= 0.001); + assertTrue(multipoint.getPointCount() == 13); + assertTrue(multipoint.hasAttribute(VertexDescription.Semantics.Z)); + assertTrue(multipoint.hasAttribute(VertexDescription.Semantics.M)); + + wktString = "Multipoint zm (10 88 88 33, 10 20 5 33, 20 20 5 33, 20 10 5 33, 12 12 3 33, 10 10 1 33, 12 12 1 33, 60 60 7 33, 60 90.1 7 33, 90 90 7 33, 70 70 7 33, 70 80 7 33, 80 80 7 33)"; + multipoint = (MultiPoint) (importerWKT.execute(0, Geometry.Type.Unknown, wktString, null)); + assertTrue(multipoint != null); + // assertTrue(envelope.xmin == 10 && envelope.xmax == 90 && + // envelope.ymin == 10 && ::fabs(envelope.ymax - 90.1) <= 0.001); + assertTrue(multipoint.getPointCount() == 13); + assertTrue(multipoint.hasAttribute(VertexDescription.Semantics.Z)); + assertTrue(multipoint.hasAttribute(VertexDescription.Semantics.M)); + + wktString = exporterWKT.execute(WktExportFlags.wktExportPrecision15, multipoint, null); + assertTrue(wktString.equals("MULTIPOINT ZM ((10 88 88 33), (10 20 5 33), (20 20 5 33), (20 10 5 33), (12 12 3 33), (10 10 1 33), (12 12 1 33), (60 60 7 33), (60 90.1 7 33), (90 90 7 33), (70 70 7 33), (70 80 7 33), (80 80 7 33))")); + wktParser.resetParser(wktString); + while (wktParser.nextToken() != WktParser.WktToken.not_available) { + } + + wktString = "Multipoint zm (empty, empty, (10 10 5 33))"; + multipoint = (MultiPoint) (importerWKT.execute(0, Geometry.Type.Unknown, wktString, null)); + + wktString = exporterWKT.execute(WktExportFlags.wktExportPoint, multipoint, null); + assertTrue(wktString.equals("POINT ZM (10 10 5 33)")); + wktParser.resetParser(wktString); + while (wktParser.nextToken() != WktParser.WktToken.not_available) { + } + } + + @Test + public static void testImportExportWktPoint() { + OperatorImportFromWkt importerWKT = (OperatorImportFromWkt) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ImportFromWkt); + OperatorExportToWkt exporterWKT = (OperatorExportToWkt) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ExportToWkt); + + Point point; + String wktString; + WktParser wktParser = new WktParser(); + + // Test Import from Point + wktString = "Point ZM empty"; + point = (Point) (importerWKT.execute(0, Geometry.Type.Unknown, wktString, null)); + assertTrue(point != null); + assertTrue(point.isEmpty()); + assertTrue(point.hasAttribute(VertexDescription.Semantics.Z)); + assertTrue(point.hasAttribute(VertexDescription.Semantics.M)); + + wktString = exporterWKT.execute(0, point, null); + assertTrue(wktString.equals("POINT ZM EMPTY")); + wktParser.resetParser(wktString); + while (wktParser.nextToken() != WktParser.WktToken.not_available) { + } + + wktString = exporterWKT.execute(WktExportFlags.wktExportMultiPoint, point, null); + assertTrue(wktString.equals("MULTIPOINT ZM EMPTY")); + wktParser.resetParser(wktString); + while (wktParser.nextToken() != WktParser.WktToken.not_available) { + } + + wktString = "Point zm (30.1 10.6 5.1 33.1)"; + point = (Point) (importerWKT.execute(0, Geometry.Type.Unknown, wktString, null)); + assertTrue(point != null); + assertTrue(point.hasAttribute(VertexDescription.Semantics.Z)); + assertTrue(point.hasAttribute(VertexDescription.Semantics.M)); + double x = point.getX(); + double y = point.getY(); + double z = point.getZ(); + double m = point.getM(); + + assertTrue(x == 30.1); + assertTrue(y == 10.6); + assertTrue(z == 5.1); + assertTrue(m == 33.1); + + wktString = exporterWKT.execute(WktExportFlags.wktExportPrecision15, point, null); + assertTrue(wktString.equals("POINT ZM (30.1 10.6 5.1 33.1)")); + wktParser.resetParser(wktString); + while (wktParser.nextToken() != WktParser.WktToken.not_available) { + } + + wktString = exporterWKT.execute(WktExportFlags.wktExportMultiPoint | WktExportFlags.wktExportPrecision15, point, null); + assertTrue(wktString.equals("MULTIPOINT ZM ((30.1 10.6 5.1 33.1))")); + wktParser.resetParser(wktString); + while (wktParser.nextToken() != WktParser.WktToken.not_available) { + } + } + + @Deprecated + @Test + public static void testImportGeoJsonGeometryCollection() { + OperatorImportFromGeoJson importer = (OperatorImportFromGeoJson) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ImportFromGeoJson); + + String geoJsonString; + Envelope2D envelope = new Envelope2D(); + WktParser wktParser = new WktParser(); + + geoJsonString = "{\"type\" : \"GeometryCollection\", \"geometries\" : [{\"type\" : \"Point\", \"coordinates\": [0,0]}, {\"type\" : \"GeometryCollection\" , \"geometries\" : [ {\"type\" : \"Point\", \"coordinates\" : [0, 0]} , {\"type\" : \"Point\", \"coordinates\" : [1, 1]} ,{ \"type\" : \"Point\", \"coordinates\" : [2, 2]}, {\"type\" : \"LineString\", \"coordinates\" : []}]} , {\"type\" : \"Point\", \"coordinates\" : [1, 1]}, {\"type\" : \"Point\" , \"coordinates\" : [2, 2]} ] }"; + OGCStructure structure = importer.executeOGC(0, geoJsonString, null).m_ogcStructure.m_structures.get(0); + + assertTrue(structure.m_type == 7); + assertTrue(structure.m_structures.get(0).m_type == 1); + assertTrue(structure.m_structures.get(0).m_type == 1); + assertTrue(structure.m_structures.get(1).m_type == 7); + assertTrue(structure.m_structures.get(2).m_type == 1); + assertTrue(structure.m_structures.get(3).m_type == 1); + + assertTrue(structure.m_structures.get(1).m_structures.get(0).m_type == 1); + assertTrue(structure.m_structures.get(1).m_structures.get(1).m_type == 1); + assertTrue(structure.m_structures.get(1).m_structures.get(2).m_type == 1); + assertTrue(structure.m_structures.get(1).m_structures.get(3).m_type == 2); + } + + @Test + public static void testImportGeoJsonMultiPolygon() throws Exception { + OperatorImportFromGeoJson importerGeoJson = (OperatorImportFromGeoJson) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ImportFromGeoJson); + OperatorExportToGeoJson exporterGeoJson = (OperatorExportToGeoJson) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ExportToGeoJson); + + MapGeometry map_geometry; + Polygon polygon; + SpatialReference spatial_reference; + String geoJsonString; + Envelope2D envelope = new Envelope2D(); + + // Test Import from MultiPolygon + geoJsonString = "{\"type\": \"MultiPolygon\", \"coordinates\": []}"; + polygon = (Polygon) (importerGeoJson.execute(0, Geometry.Type.Polygon, geoJsonString, null).getGeometry()); + assertTrue(polygon != null); + assertTrue(polygon.isEmpty()); + assertTrue(!polygon.hasAttribute(VertexDescription.Semantics.M)); + + geoJsonString = "{\"coordinates\" : [], \"type\": \"MultiPolygon\", \"crs\": {\"type\": \"name\", \"some\": \"stuff\", \"properties\": {\"some\" : \"stuff\", \"name\": \"urn:ogc:def:crs:OGC:1.3:CRS84\"}}}"; + map_geometry = importerGeoJson.execute(0, Geometry.Type.Polygon, geoJsonString, null); + polygon = (Polygon) map_geometry.getGeometry(); + spatial_reference = map_geometry.getSpatialReference(); + assertTrue(polygon != null); + assertTrue(polygon.isEmpty()); + assertTrue(spatial_reference.getLatestID() == 4326); + + geoJsonString = "{\"coordinates\" : null, \"crs\": null, \"type\": \"MultiPolygon\"}"; + map_geometry = importerGeoJson.execute(0, Geometry.Type.Polygon, geoJsonString, null); + polygon = (Polygon) map_geometry.getGeometry(); + spatial_reference = map_geometry.getSpatialReference(); + assertTrue(polygon != null); + assertTrue(polygon.isEmpty()); + assertTrue(spatial_reference == null); + + geoJsonString = "{\"type\": \"MultiPolygon\", \"coordinates\" : [[], [], [[[]]]], \"crsURN\": \"urn:ogc:def:crs:OGC:1.3:CRS27\"}"; + map_geometry = importerGeoJson.execute(0, Geometry.Type.Polygon, geoJsonString, null); + polygon = (Polygon) map_geometry.getGeometry(); + spatial_reference = map_geometry.getSpatialReference(); + assertTrue(polygon != null); + assertTrue(polygon.isEmpty()); + assertTrue(spatial_reference != null); + assertTrue(spatial_reference.getLatestID() == 4267); + + geoJsonString = "{\"coordinates\" : [[], [[], [[10, 10, 5], [20, 10, 5], [20, 20, 5], [10, 20, 5], [10, 10, 5]], [[12, 12, 3]], [], [[10, 10, 1], [12, 12, 1]]], [], [[[90, 90, 88], [60, 90, 7], [60, 60, 7]], [], [[70, 70, 7], [80, 80, 7], [70, 80, 7], [70, 70, 7]]], []], \"crs\": {\"type\": \"link\", \"properties\": {\"href\": \"http://spatialreference.org/ref/sr-org/6928/ogcwkt/\"}}, \"type\": \"MultiPolygon\"}"; + map_geometry = importerGeoJson.execute(0, Geometry.Type.Unknown, geoJsonString, null); + polygon = (Polygon) map_geometry.getGeometry(); + spatial_reference = map_geometry.getSpatialReference(); + assertTrue(polygon != null); + polygon.queryEnvelope2D(envelope); + assertTrue(envelope.xmin == 10 && envelope.xmax == 90 && envelope.ymin == 10 && envelope.ymax == 90); + assertTrue(polygon.getPointCount() == 14); + assertTrue(polygon.getPathCount() == 5); + assertTrue(spatial_reference.getLatestID() == 3857); + + map_geometry = importerGeoJson.execute(0, Geometry.Type.Unknown, geoJsonString, null); + polygon = (Polygon) map_geometry.getGeometry(); + spatial_reference = map_geometry.getSpatialReference(); + assertTrue(polygon != null); + polygon.queryEnvelope2D(envelope); + assertTrue(envelope.xmin == 10 && envelope.xmax == 90 && envelope.ymin == 10 && envelope.ymax == 90); + assertTrue(polygon.getPointCount() == 14); + assertTrue(polygon.getPathCount() == 5); + assertTrue(spatial_reference.getLatestID() == 3857); + + // Test Export to GeoJSON MultiPolygon + geoJsonString = exporterGeoJson.execute(GeoJsonExportFlags.geoJsonExportSkipCRS, spatial_reference, polygon); + assertTrue(geoJsonString.equals("{\"type\":\"MultiPolygon\",\"coordinates\":[[[[10,10,5],[20,10,5],[20,20,5],[10,20,5],[10,10,5]],[[12,12,3],[12,12,3],[12,12,3]],[[10,10,1],[12,12,1],[10,10,1]]],[[[90,90,88],[60,90,7],[60,60,7],[90,90,88]],[[70,70,7],[70,80,7],[80,80,7],[70,70,7]]]]}")); + + geoJsonString = exporterGeoJson.execute(0, spatial_reference, polygon); + assertTrue(geoJsonString.equals("{\"type\":\"MultiPolygon\",\"coordinates\":[[[[10,10,5],[20,10,5],[20,20,5],[10,20,5],[10,10,5]],[[12,12,3],[12,12,3],[12,12,3]],[[10,10,1],[12,12,1],[10,10,1]]],[[[90,90,88],[60,90,7],[60,60,7],[90,90,88]],[[70,70,7],[70,80,7],[80,80,7],[70,70,7]]]],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:3857\"}}}")); + + geoJsonString = "{\"type\": \"MultiPolygon\", \"coordinates\": [[[[90, 10, 7], [10, 10, 1], [10, 90, 7], [90, 90, 1], [90, 10, 7]]]] }"; // ring + // i // clockwise + polygon = (Polygon) (importerGeoJson.execute(0, Geometry.Type.Polygon, geoJsonString, null).getGeometry()); + assertTrue(polygon != null); + assertTrue(polygon.getPointCount() == 4); + assertTrue(polygon.getPathCount() == 1); + assertTrue(polygon.hasAttribute(VertexDescription.Semantics.Z)); + assertTrue(polygon.calculateArea2D() > 0); + + // Test import Polygon + geoJsonString = "{\"type\": \"Polygon\", \"coordinates\": [[], [], [[10, 10, 5], [10, 20, 5], [20, 20, 5], [20, 10, 5]], [[12, 12, 3]], [], [[10, 10, 1], [12, 12, 1]], [], [[60, 60, 7], [60, 90, 7], [90, 90, 7], [60, 60, 7]], [], [[70, 70, 7], [70, 80, 7], [80, 80, 7]], []] }"; + map_geometry = importerGeoJson.execute(0, Geometry.Type.Polygon, geoJsonString, null); + polygon = (Polygon) map_geometry.getGeometry(); + spatial_reference = map_geometry.getSpatialReference(); + assertTrue(polygon != null); + assertTrue(polygon.getPointCount() == 14); + assertTrue(polygon.getPathCount() == 5); + assertTrue(spatial_reference.getLatestID() == 4326); + + geoJsonString = exporterGeoJson.execute(0, spatial_reference, polygon); + assertTrue(geoJsonString.equals("{\"type\":\"Polygon\",\"coordinates\":[[[10,10,5],[20,10,5],[20,20,5],[10,20,5],[10,10,5]],[[12,12,3],[12,12,3],[12,12,3]],[[10,10,1],[12,12,1],[10,10,1]],[[60,60,7],[60,90,7],[90,90,7],[60,60,7]],[[70,70,7],[70,80,7],[80,80,7],[70,70,7]]],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:4326\"}}}")); + + Envelope env = new Envelope(); + env.addAttribute(VertexDescription.Semantics.Z); + polygon.queryEnvelope(env); + + geoJsonString = "{\"coordinates\" : [], \"type\": \"MultiPolygon\", \"crs\":{\"esriwkt\":\"PROJCS[\\\"Gnomonic\\\",GEOGCS[\\\"GCS_WGS_1984\\\",DATUM[\\\"D_WGS_1984\\\",SPHEROID[\\\"WGS_1984\\\",6378137.0,298.257223563]],PRIMEM[\\\"Greenwich\\\",0.0],UNIT[\\\"Degree\\\",0.0174532925199433]],PROJECTION[\\\"Gnomonic\\\"],PARAMETER[\\\"Longitude_Of_Center\\\",0.0],PARAMETER[\\\"Latitude_Of_Center\\\",-45.0],UNIT[\\\"Meter\\\",1.0]]\"}}"; + map_geometry = importerGeoJson.execute(0, Geometry.Type.Polygon, geoJsonString, null); + polygon = (Polygon) map_geometry.getGeometry(); + spatial_reference = map_geometry.getSpatialReference(); + String wkt = spatial_reference.getText(); + assertTrue(wkt.equals( + "PROJCS[\"Gnomonic\",GEOGCS[\"GCS_WGS_1984\",DATUM[\"D_WGS_1984\",SPHEROID[\"WGS_1984\",6378137.0,298.257223563]],PRIMEM[\"Greenwich\",0.0],UNIT[\"Degree\",0.0174532925199433]],PROJECTION[\"Gnomonic\"],PARAMETER[\"Longitude_Of_Center\",0.0],PARAMETER[\"Latitude_Of_Center\",-45.0],UNIT[\"Meter\",1.0]]")); + + geoJsonString = "{\"coordinates\" : [], \"type\": \"MultiPolygon\", \"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"PROJCS[\\\"Gnomonic\\\",GEOGCS[\\\"GCS_WGS_1984\\\",DATUM[\\\"D_WGS_1984\\\",SPHEROID[\\\"WGS_1984\\\",6378137.0,298.257223563]],PRIMEM[\\\"Greenwich\\\",0.0],UNIT[\\\"Degree\\\",0.0174532925199433]],PROJECTION[\\\"Gnomonic\\\"],PARAMETER[\\\"Longitude_Of_Center\\\",0.0],PARAMETER[\\\"Latitude_Of_Center\\\",-45.0],UNIT[\\\"Meter\\\",1.0]]\"}}}"; + map_geometry = importerGeoJson.execute(0, Geometry.Type.Polygon, geoJsonString, null); + polygon = (Polygon) map_geometry.getGeometry(); + spatial_reference = map_geometry.getSpatialReference(); + wkt = spatial_reference.getText(); + assertTrue(wkt.equals( + "PROJCS[\"Gnomonic\",GEOGCS[\"GCS_WGS_1984\",DATUM[\"D_WGS_1984\",SPHEROID[\"WGS_1984\",6378137.0,298.257223563]],PRIMEM[\"Greenwich\",0.0],UNIT[\"Degree\",0.0174532925199433]],PROJECTION[\"Gnomonic\"],PARAMETER[\"Longitude_Of_Center\",0.0],PARAMETER[\"Latitude_Of_Center\",-45.0],UNIT[\"Meter\",1.0]]")); + assertTrue(polygon != null); + assertTrue(polygon.isEmpty()); + + // AGOL exports wkt like this... + geoJsonString = "{\"coordinates\" : [], \"type\": \"MultiPolygon\", \"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"ESRI:PROJCS[\\\"Gnomonic\\\",GEOGCS[\\\"GCS_WGS_1984\\\",DATUM[\\\"D_WGS_1984\\\",SPHEROID[\\\"WGS_1984\\\",6378137.0,298.257223563]],PRIMEM[\\\"Greenwich\\\",0.0],UNIT[\\\"Degree\\\",0.0174532925199433]],PROJECTION[\\\"Gnomonic\\\"],PARAMETER[\\\"Longitude_Of_Center\\\",0.0],PARAMETER[\\\"Latitude_Of_Center\\\",-45.0],UNIT[\\\"Meter\\\",1.0]]\"}}}"; + map_geometry = importerGeoJson.execute(0, Geometry.Type.Polygon, geoJsonString, null); + polygon = (Polygon) map_geometry.getGeometry(); + spatial_reference = map_geometry.getSpatialReference(); + wkt = spatial_reference.getText(); + assertTrue(wkt.equals( + "PROJCS[\"Gnomonic\",GEOGCS[\"GCS_WGS_1984\",DATUM[\"D_WGS_1984\",SPHEROID[\"WGS_1984\",6378137.0,298.257223563]],PRIMEM[\"Greenwich\",0.0],UNIT[\"Degree\",0.0174532925199433]],PROJECTION[\"Gnomonic\"],PARAMETER[\"Longitude_Of_Center\",0.0],PARAMETER[\"Latitude_Of_Center\",-45.0],UNIT[\"Meter\",1.0]]")); + assertTrue(polygon != null); + assertTrue(polygon.isEmpty()); + + boolean exceptionThrownNoWKT = false; + + try { + geoJsonString = exporterGeoJson.execute(GeoJsonExportFlags.geoJsonExportPreferMultiGeometry, + spatial_reference, polygon); + } catch (Exception e) { + exceptionThrownNoWKT = true; + } + + assertTrue(exceptionThrownNoWKT); + } + + @Test + public static void testImportGeoJsonMultiLineString() throws Exception { + OperatorImportFromGeoJson importerGeoJson = (OperatorImportFromGeoJson) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ImportFromGeoJson); + OperatorExportToGeoJson exporterGeoJson = (OperatorExportToGeoJson) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ExportToGeoJson); + MapGeometry map_geometry; + Polyline polyline; + SpatialReference spatial_reference; + String geoJsonString; + Envelope2D envelope = new Envelope2D(); + + // Test Import from MultiLineString + geoJsonString = "{\"type\":\"MultiLineString\",\"coordinates\":[], \"crs\" : {\"type\" : \"URL\", \"properties\" : {\"url\" : \"http://www.opengis.net/def/crs/EPSG/0/3857\"}}}"; + map_geometry = importerGeoJson.execute(0, Geometry.Type.Unknown, geoJsonString, null); + polyline = (Polyline) map_geometry.getGeometry(); + spatial_reference = map_geometry.getSpatialReference(); + assertTrue(polyline != null); + assertTrue(spatial_reference != null); + assertTrue(polyline.isEmpty()); + assertTrue(spatial_reference.getLatestID() == 3857); + + geoJsonString = "{\"crs\" : {\"type\" : \"link\", \"properties\" : {\"href\" : \"www.spatialreference.org/ref/epsg/4309/\"}}, \"type\":\"MultiLineString\",\"coordinates\":[[], [], [[10, 10, 5], [10, 20, 5], [20, 88, 5], [20, 10, 5]], [[12, 88, 3]], [], [[10, 10, 1], [12, 12, 1]], [], [[88, 60, 7], [60, 90, 7], [90, 90, 7]], [], [[70, 70, 7], [70, 80, 7], [80, 80, 7]], []]}"; + map_geometry = importerGeoJson.execute(0, Geometry.Type.Unknown, geoJsonString, null); + polyline = (Polyline) map_geometry.getGeometry(); + spatial_reference = map_geometry.getSpatialReference(); + assertTrue(polyline != null); + polyline.queryEnvelope2D(envelope); + assertTrue(envelope.xmin == 10 && envelope.xmax == 90 && envelope.ymin == 10 && envelope.ymax == 90); + assertTrue(polyline.getPointCount() == 14); + assertTrue(polyline.getPathCount() == 5); + assertTrue(polyline.hasAttribute(VertexDescription.Semantics.Z)); + assertTrue(spatial_reference.getLatestID() == 4309); + + geoJsonString = exporterGeoJson.execute(0, spatial_reference, polyline); + assertTrue(geoJsonString.equals("{\"type\":\"MultiLineString\",\"coordinates\":[[[10,10,5],[10,20,5],[20,88,5],[20,10,5]],[[12,88,3],[12,88,3]],[[10,10,1],[12,12,1]],[[88,60,7],[60,90,7],[90,90,7]],[[70,70,7],[70,80,7],[80,80,7]]],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:4309\"}}}")); + + // Test Import LineString + geoJsonString = "{\"type\": \"LineString\", \"coordinates\": [[10, 10, 5], [10, 20, 5], [20, 20, 5], [20, 10, 5]]}"; + polyline = (Polyline) (importerGeoJson.execute(0, Geometry.Type.Unknown, geoJsonString, null).getGeometry()); + assertTrue(polyline.getPointCount() == 4); + assertTrue(polyline.hasAttribute(VertexDescription.Semantics.Z)); + + geoJsonString = "{\"type\": \"LineString\", \"coordinates\": [[10, 10, 5], [10, 20, 5, 3], [20, 20, 5], [20, 10, 5]]}"; + polyline = (Polyline) (importerGeoJson.execute(0, Geometry.Type.Unknown, geoJsonString, null).getGeometry()); + assertTrue(polyline.getPointCount() == 4); + assertTrue(polyline.hasAttribute(VertexDescription.Semantics.Z)); + assertTrue(polyline.hasAttribute(VertexDescription.Semantics.M)); + + geoJsonString = "{\"type\":\"LineString\",\"coordinates\": [[10, 10, 5], [10, 20, 5], [20, 20, 5], [], [20, 10, 5]],\"crs\" : {\"type\" : \"link\", \"properties\" : {\"href\" : \"www.opengis.net/def/crs/EPSG/0/3857\"}}}"; + map_geometry = importerGeoJson.execute(0, Geometry.Type.Unknown, geoJsonString, null); + polyline = (Polyline) (map_geometry.getGeometry()); + spatial_reference = map_geometry.getSpatialReference(); + assertTrue(polyline.getPointCount() == 4); + assertTrue(spatial_reference.getLatestID() == 3857); + geoJsonString = exporterGeoJson.execute(0, spatial_reference, polyline); + assertTrue(geoJsonString.equals("{\"type\":\"LineString\",\"coordinates\":[[10,10,5],[10,20,5],[20,20,5],[20,10,5]],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:3857\"}}}")); + + geoJsonString = exporterGeoJson.execute(0, null, polyline); + assertTrue(geoJsonString.equals("{\"type\":\"LineString\",\"coordinates\":[[10,10,5],[10,20,5],[20,20,5],[20,10,5]],\"crs\":null}")); + } + + @Test + public static void testImportGeoJsonMultiPoint() throws Exception { + OperatorImportFromGeoJson importerGeoJson = (OperatorImportFromGeoJson) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ImportFromGeoJson); + OperatorExportToGeoJson exporterGeoJson = (OperatorExportToGeoJson) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ExportToGeoJson); + MapGeometry map_geometry; + MultiPoint multipoint; + SpatialReference spatial_reference; + String geoJsonString; + Envelope2D envelope = new Envelope2D(); + + // Test Import from Multi_point + + geoJsonString = "{\"type\":\"MultiPoint\",\"coordinates\":[]}"; + map_geometry = importerGeoJson.execute(0, Geometry.Type.Unknown, geoJsonString, null); + multipoint = (MultiPoint) map_geometry.getGeometry(); + spatial_reference = map_geometry.getSpatialReference(); + assertTrue(multipoint != null); + assertTrue(multipoint.isEmpty()); + assertTrue(spatial_reference.getLatestID() == 4326); + + geoJsonString = exporterGeoJson.execute(0, null, multipoint); + assertTrue(geoJsonString.equals("{\"type\":\"MultiPoint\",\"coordinates\":[],\"crs\":null}")); + + multipoint = new MultiPoint(); + multipoint.add(118.15, 2); + multipoint.add(88, 88); + + geoJsonString = exporterGeoJson.execute(GeoJsonExportFlags.geoJsonExportPrecision16, SpatialReference.create(4269), multipoint); + assertTrue(geoJsonString.equals("{\"type\":\"MultiPoint\",\"coordinates\":[[118.15,2],[88,88]],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:4269\"}}}")); + + multipoint.setEmpty(); + multipoint.add(88, 2); + multipoint.add(88, 88); + + geoJsonString = exporterGeoJson.execute(0, SpatialReference.create(102100), multipoint); + assertTrue(geoJsonString.equals("{\"type\":\"MultiPoint\",\"coordinates\":[[88,2],[88,88]],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:3857\"}}}")); + + geoJsonString = "{\"type\":\"MultiPoint\",\"coordinates\":[[], [], [10, 88, 88, 33], [10, 20, 5, 33], [20, 20, 5, 33], [20, 10, 5, 33], [12, 12, 3, 33], [], [10, 10, 1, 33], [12, 12, 1, 33], [], [60, 60, 7, 33], [60, 90.1, 7, 33], [90, 90, 7, 33], [], [70, 70, 7, 33], [70, 80, 7, 33], [80, 80, 7, 33], []],\"crs\":{\"type\":\"OGC\",\"properties\":{\"urn\":\"urn:ogc:def:crs:OGC:1.3:CRS83\"}}}"; + map_geometry = importerGeoJson.execute(0, Geometry.Type.Unknown, geoJsonString, null); + multipoint = (MultiPoint) map_geometry.getGeometry(); + spatial_reference = map_geometry.getSpatialReference(); + assertTrue(multipoint != null); + assertTrue(multipoint.getPointCount() == 13); + assertTrue(multipoint.hasAttribute(VertexDescription.Semantics.Z)); + assertTrue(multipoint.hasAttribute(VertexDescription.Semantics.M)); + assertTrue(spatial_reference.getLatestID() == 4269); + + geoJsonString = "{\"type\":\"MultiPoint\",\"coordinates\": [[10, 88, 88, 33], [10, 20, 5, 33], [20, 20, 5, 33], [], [20, 10, 5, 33], [12, 12, 3, 33], [], [10, 10, 1, 33], [12, 12, 1, 33], [60, 60, 7, 33], [60, 90.1, 7, 33], [90, 90, 7, 33], [70, 70, 7, 33], [70, 80, 7, 33], [80, 80, 7, 33]]}"; + multipoint = (MultiPoint) importerGeoJson.execute(0, Geometry.Type.Unknown, geoJsonString, null).getGeometry(); + assertTrue(multipoint != null); + assertTrue(multipoint.getPointCount() == 13); + assertTrue(multipoint.hasAttribute(VertexDescription.Semantics.Z)); + assertTrue(multipoint.hasAttribute(VertexDescription.Semantics.M)); + + geoJsonString = exporterGeoJson.execute(GeoJsonExportFlags.geoJsonExportPrecision15, null, multipoint); + assertTrue(geoJsonString.equals("{\"type\":\"MultiPoint\",\"coordinates\":[[10,88,88,33],[10,20,5,33],[20,20,5,33],[20,10,5,33],[12,12,3,33],[10,10,1,33],[12,12,1,33],[60,60,7,33],[60,90.1,7,33],[90,90,7,33],[70,70,7,33],[70,80,7,33],[80,80,7,33]],\"crs\":null}")); + + geoJsonString = "{\"type\":\"MultiPoint\",\"coordinates\":[[], [], [10, 10, 5, 33]]}"; + multipoint = (MultiPoint) importerGeoJson.execute(0, Geometry.Type.Unknown, geoJsonString, null).getGeometry(); + + geoJsonString = exporterGeoJson.execute(0, null, multipoint); + assertTrue(geoJsonString.equals("{\"type\":\"MultiPoint\",\"coordinates\":[[10,10,5,33]],\"crs\":null}")); + } + + @Test + public static void testImportGeoJsonPolygon() throws Exception { + OperatorImportFromGeoJson importerGeoJson = (OperatorImportFromGeoJson) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ImportFromGeoJson); + + Polygon polygon; + String geoJsonString; + Envelope2D envelope = new Envelope2D(); + + // Test Import from Polygon + geoJsonString = "{\"type\": \"Polygon\", \"coordinates\": []}"; + polygon = (Polygon) (importerGeoJson.execute(0, Geometry.Type.Unknown, geoJsonString, null).getGeometry()); + assertTrue(polygon != null); + assertTrue(polygon.isEmpty()); + assertTrue(!polygon.hasAttribute(VertexDescription.Semantics.Z)); + assertTrue(!polygon.hasAttribute(VertexDescription.Semantics.M)); + + geoJsonString = "{\"type\": \"Polygon\", \"coordinates\": [[], [[10, 10, 5], [20, 10, 5], [20, 20, 5], [10, 20, 5], [10, 10, 5]], [[12, 12, 3]], [], [[10, 10, 1], [12, 12, 1]]]}"; + polygon = (Polygon) (importerGeoJson.execute(0, Geometry.Type.Unknown, geoJsonString, null).getGeometry()); + assertTrue(polygon != null); + polygon.queryEnvelope2D(envelope); + assertTrue(envelope.xmin == 10 && envelope.xmax == 20 && envelope.ymin == 10 && envelope.ymax == 20); + assertTrue(polygon.getPointCount() == 8); + assertTrue(polygon.getPathCount() == 3); + assertTrue(polygon.hasAttribute(VertexDescription.Semantics.Z)); + + geoJsonString = "{\"type\": \"Polygon\", \"coordinates\": [[[35, 10], [10, 20], [15, 40], [45, 45], [35, 10]], [[20, 30], [35, 35], [30, 20], [20, 30]]]}"; + Polygon polygon2 = (Polygon) (importerGeoJson.execute(0, Geometry.Type.Unknown, geoJsonString, null).getGeometry()); + assertTrue(polygon2 != null); + } + + @Test + public static void testImportGeoJsonLineString() throws Exception { + OperatorImportFromGeoJson importerGeoJson = (OperatorImportFromGeoJson) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ImportFromGeoJson); + + Polyline polyline; + String geoJsonString; + Envelope2D envelope = new Envelope2D(); + + // Test Import from LineString + geoJsonString = "{\"type\": \"LineString\", \"coordinates\": []}"; + polyline = (Polyline) (importerGeoJson.execute(0, Geometry.Type.Unknown, geoJsonString, null).getGeometry()); + assertTrue(polyline != null); + assertTrue(polyline.isEmpty()); + assertTrue(!polyline.hasAttribute(VertexDescription.Semantics.Z)); + assertTrue(!polyline.hasAttribute(VertexDescription.Semantics.M)); + + geoJsonString = "{\"type\": \"LineString\", \"coordinates\": [[10, 10, 5], [10, 20, 5], [20, 20, 5], [20, 10, 5]]}"; + polyline = (Polyline) (importerGeoJson.execute(0, Geometry.Type.Unknown, geoJsonString, null).getGeometry()); + assertTrue(polyline != null); + polyline.queryEnvelope2D(envelope); + assertTrue(envelope.xmin == 10 && envelope.xmax == 20 && envelope.ymin == 10 && envelope.ymax == 20); + assertTrue(polyline.getPointCount() == 4); + assertTrue(polyline.getPathCount() == 1); + assertTrue(!polyline.hasAttribute(VertexDescription.Semantics.M)); + } + + @Test + public static void testImportGeoJsonPoint() throws Exception { + OperatorImportFromGeoJson importerGeoJson = (OperatorImportFromGeoJson) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ImportFromGeoJson); + OperatorExportToGeoJson exporterGeoJson = (OperatorExportToGeoJson) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ExportToGeoJson); + MapGeometry map_geometry; + SpatialReference spatial_reference; + Point point; + String geoJsonString; + + // Test Import from Point + geoJsonString = "{\"type\":\"Point\",\"coordinates\":[],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:3857\"}}}"; + map_geometry = importerGeoJson.execute(0, Geometry.Type.Unknown, geoJsonString, null); + point = (Point) map_geometry.getGeometry(); + spatial_reference = map_geometry.getSpatialReference(); + assertTrue(spatial_reference.getLatestID() == 3857); + + assertTrue(point != null); + assertTrue(point.isEmpty()); + + geoJsonString = exporterGeoJson.execute(0, null, point); + assertTrue(geoJsonString.equals("{\"type\":\"Point\",\"coordinates\":[],\"crs\":null}")); + + geoJsonString = exporterGeoJson.execute(GeoJsonExportFlags.geoJsonExportPreferMultiGeometry, null, point); + assertTrue(geoJsonString.equals("{\"type\":\"MultiPoint\",\"coordinates\":[],\"crs\":null}")); + + geoJsonString = "{\"type\":\"Point\",\"coordinates\":[30.1,10.6,5.1,33.1],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"urn:ogc:def:crs:ESRI::54051\"}}}"; + map_geometry = importerGeoJson.execute(0, Geometry.Type.Unknown, geoJsonString, null); + point = (Point) map_geometry.getGeometry(); + spatial_reference = map_geometry.getSpatialReference(); + assertTrue(point != null); + assertTrue(point.hasAttribute(VertexDescription.Semantics.Z)); + assertTrue(point.hasAttribute(VertexDescription.Semantics.M)); + assertTrue(spatial_reference.getLatestID() == 54051); + double x = point.getX(); + double y = point.getY(); + double z = point.getZ(); + double m = point.getM(); + + assertTrue(x == 30.1); + assertTrue(y == 10.6); + assertTrue(z == 5.1); + assertTrue(m == 33.1); + + geoJsonString = exporterGeoJson.execute(GeoJsonExportFlags.geoJsonExportPrecision15, spatial_reference, point); + assertTrue(geoJsonString.equals("{\"type\":\"Point\",\"coordinates\":[30.1,10.6,5.1,33.1],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"ESRI:54051\"}}}")); + + geoJsonString = exporterGeoJson.execute(GeoJsonExportFlags.geoJsonExportPrecision15, SpatialReference.create(4287), point); + assertTrue(geoJsonString.equals("{\"type\":\"Point\",\"coordinates\":[30.1,10.6,5.1,33.1],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:4287\"}}}")); + + geoJsonString = exporterGeoJson.execute(GeoJsonExportFlags.geoJsonExportPreferMultiGeometry | GeoJsonExportFlags.geoJsonExportPrecision15, null, point); + assertTrue(geoJsonString.equals("{\"type\":\"MultiPoint\",\"coordinates\":[[30.1,10.6,5.1,33.1]],\"crs\":null}")); + } + + @Test + public static void testImportExportGeoJsonMalformed() { + OperatorImportFromGeoJson importerGeoJson = (OperatorImportFromGeoJson) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ImportFromGeoJson); + OperatorExportToGeoJson exporterGeoJson = (OperatorExportToGeoJson) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ExportToGeoJson); + + String geoJsonString; + + try { + geoJsonString = "{\"type\":\"MultiPolygon\",\"coordinates\":[[[2,2,2],[3,3,3],[4,4,4],[2,2,2]]]}"; + importerGeoJson.execute(0, Geometry.Type.Unknown, geoJsonString, null); + assertTrue(false); + } catch (Exception e) { + } + + try { + geoJsonString = "{\"type\":\"Polygon\",\"coordinates\":[[2,2,2],[3,3,3],[4,4,4],[2,2,2]]}"; + importerGeoJson.execute(0, Geometry.Type.Unknown, geoJsonString, null); + assertTrue(false); + } catch (Exception e) { + } + + try { + geoJsonString = "{\"type\":\"Polygon\",\"coordinates\":[[[2,2,2],[3,3,3],[4,4,4],[2,2,2]],2,4]}"; + importerGeoJson.execute(0, Geometry.Type.Unknown, geoJsonString, null); + assertTrue(false); + } catch (Exception e) { + } + + try { + geoJsonString = "{\"type\":\"MultiPoint\",\"coordinates\":[[[2,2,2],[3,3,3],[4,4,4],[2,2,2]]]}"; + importerGeoJson.execute(0, Geometry.Type.Unknown, geoJsonString, null); + assertTrue(false); + } catch (Exception e) { + } + + try { + geoJsonString = "{\"type\":\"LineString\",\"coordinates\":[[[2,2,2],[3,3,3],[4,4,4],[2,2,2]]]}"; + importerGeoJson.execute(0, Geometry.Type.Unknown, geoJsonString, null); + assertTrue(false); + } catch (Exception e) { + } + + try { + geoJsonString = "{\"type\":\"MultiPoint\",\"coordinates\":[[2,2,2],[3,3,3],[4,4,4],[2,2,2],[[]]]}"; + importerGeoJson.execute(0, Geometry.Type.Unknown, geoJsonString, null); + assertTrue(false); + } catch (Exception e) { + } + + try { + geoJsonString = "{\"type\":\"MultiPolygon\",\"coordinates\":[[[[2,2,2],[3,3,3],[4,4,4],[2,2,2],[[]]]]]}"; + importerGeoJson.execute(0, Geometry.Type.Unknown, geoJsonString, null); + assertTrue(false); + } catch (Exception e) { + } + + try { + geoJsonString = "{\"type\":\"MultiPolygon\",\"coordinates\":[[[[2,2,2],[3,3,3],[4,4,4],[2,2,2]],[1,1,1],[2,2,2],[3,3,3],[1,1,1]]]}"; + importerGeoJson.execute(0, Geometry.Type.Unknown, geoJsonString, null); + assertTrue(false); + } catch (Exception e) { + } + + try { + geoJsonString = "{\"type\":\"Polygon\",\"coordinates\":[[[2,2,2],[3,3,3],[4,4,4],[2,2,2]],[1,1,1],[2,2,2],[3,3,3],[1,1,1]]}"; + importerGeoJson.execute(0, Geometry.Type.Unknown, geoJsonString, null); + assertTrue(false); + } catch (Exception e) { + } + + try { + geoJsonString = "{\"type\":\"MultiPolygon\",\"coordinates\":[[[[[]]]]}"; + importerGeoJson.execute(0, Geometry.Type.Unknown, geoJsonString, null); + assertTrue(false); + } catch (Exception e) { + } + + try { + geoJsonString = "{\"type\":\"MultiPolygon\",\"coordinates\":[[[[{}]]]}"; + importerGeoJson.execute(0, Geometry.Type.Unknown, geoJsonString, null); + assertTrue(false); + } catch (Exception e) { + } + + try { + geoJsonString = "{\"type\":\"Point\",\"coordinates\":[30.1,10.6,[],33.1],\"crs\":\"EPSG:3857\"}"; + importerGeoJson.execute(0, Geometry.Type.Unknown, geoJsonString, null); + assertTrue(false); + } catch (Exception e) { + } + } + + @Test + public static void testImportGeoJsonSpatialReference() throws Exception { + OperatorImportFromGeoJson importerGeoJson = (OperatorImportFromGeoJson) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ImportFromGeoJson); + + String geoJsonString4326; + String geoJsonString3857; + + // Test Import from Point + geoJsonString4326 = "{\"type\": \"Point\", \"coordinates\": [3.0, 5.0], \"crs\": \"EPSG:4326\"}"; + geoJsonString3857 = "{\"type\": \"Point\", \"coordinates\": [3.0, 5.0], \"crs\": \"EPSG:3857\"}"; + + MapGeometry mapGeometry4326 = importerGeoJson.execute(0, Geometry.Type.Unknown, geoJsonString4326, null); + MapGeometry mapGeometry3857 = importerGeoJson.execute(0, Geometry.Type.Unknown, geoJsonString3857, null); + + assertTrue(mapGeometry4326.equals(mapGeometry3857) == false); + assertTrue(mapGeometry4326.getGeometry().equals(mapGeometry3857.getGeometry())); + } + + @Test + public static void testImportExportESRICursors() { + Polygon poly1 = new Polygon(); + Envelope2D env1 = new Envelope2D(); + env1.setCoords(855277, 3892059, 855277 + 100, 3892059 + 100); + poly1.addEnvelope(env1, false); + + Polygon poly2 = new Polygon(); + Envelope2D env2 = new Envelope2D(); + env2.setCoords(855277, 3892059, 855277 + 300, 3892059 + 200); + poly2.addEnvelope(env2, false); + List list2 = new ArrayList<>(); + list2.add(poly1); + list2.add(poly2); + SimpleGeometryCursor simpleGeometryCursor2 = new SimpleGeometryCursor(new ArrayDeque(list2)); + + OperatorExportToESRIShapeCursor operatorExportToESRIShapeCursor = new OperatorExportToESRIShapeCursor(0, simpleGeometryCursor2); + OperatorImportFromESRIShapeCursor operatorImportFromESRIShapeCursor = new OperatorImportFromESRIShapeCursor(0, 0, operatorExportToESRIShapeCursor); + + SpatialReference inputSR = SpatialReference.create(3857); + OperatorFactoryLocal projEnv = OperatorFactoryLocal.getInstance(); + OperatorCrosses operatorCrosses = (OperatorCrosses) (projEnv.getOperator(Operator.Type.Crosses)); + HashMap relate_map = operatorCrosses.execute(poly1, + operatorImportFromESRIShapeCursor, inputSR, null); + + assertNotNull(relate_map); + + assertTrue(!relate_map.get(0L)); + assertTrue(!relate_map.get(1L)); + } + + @Test + public static void testImportExportWKBCursors() { + Polygon poly1 = new Polygon(); + Envelope2D env1 = new Envelope2D(); + env1.setCoords(855277, 3892059, 855277 + 100, 3892059 + 100); + poly1.addEnvelope(env1, false); + + Polygon poly2 = new Polygon(); + Envelope2D env2 = new Envelope2D(); + env2.setCoords(855277, 3892059, 855277 + 300, 3892059 + 200); + poly2.addEnvelope(env2, false); + List list2 = new ArrayList<>(); + list2.add(poly1); + list2.add(poly2); + SimpleGeometryCursor simpleGeometryCursor2 = new SimpleGeometryCursor(new ArrayDeque(list2)); + + OperatorExportToWkbCursor operatorExportToWkbCursor = new OperatorExportToWkbCursor(0, simpleGeometryCursor2); + OperatorImportFromWkbCursor operatorImportFromWkbCursor = new OperatorImportFromWkbCursor(0, operatorExportToWkbCursor); + + SpatialReference inputSR = SpatialReference.create(3857); + OperatorFactoryLocal projEnv = OperatorFactoryLocal.getInstance(); + OperatorCrosses operatorCrosses = (OperatorCrosses) (projEnv.getOperator(Operator.Type.Crosses)); + HashMap relate_map = operatorCrosses.execute(poly1, + operatorImportFromWkbCursor, inputSR, null); + + assertNotNull(relate_map); + assertTrue(!relate_map.get(0L)); + assertTrue(!relate_map.get(1L)); + + simpleGeometryCursor2 = new SimpleGeometryCursor(new ArrayDeque(list2)); + operatorExportToWkbCursor = new OperatorExportToWkbCursor(0, simpleGeometryCursor2); + operatorImportFromWkbCursor = new OperatorImportFromWkbCursor(0, operatorExportToWkbCursor); + double[] distances = {400, 400}; + + OperatorBufferCursor operatorBufferCursor = new OperatorBufferCursor(operatorImportFromWkbCursor, null, distances, NumberUtils.NaN(), 96, false, null); + relate_map = ((OperatorWithin) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.Within)).execute(poly2, operatorBufferCursor, inputSR, null); + assertNotNull(relate_map); + assertTrue(relate_map.get(0L)); + assertTrue(relate_map.get(1L)); + } + + static double randomWithRange(double min, double max) { + double range = Math.abs(max - min); + return (Math.random() * range) + (min <= max ? min : max); + } + + @Test + public static void testImportExportWKTCursors() { + Polygon poly1 = new Polygon(); + Envelope2D env1 = new Envelope2D(); + env1.setCoords(855277, 3892059, 855277 + 100, 3892059 + 100); + poly1.addEnvelope(env1, false); + + Polygon poly2 = new Polygon(); + Envelope2D env2 = new Envelope2D(); + env2.setCoords(855277, 3892059, 855277 + 300, 3892059 + 200); + poly2.addEnvelope(env2, false); + List list2 = new ArrayList<>(); + list2.add(poly1); + list2.add(poly2); + + int size = 1000; + String[] points = new String[size]; + List pointList = new ArrayList<>(size); + ArrayDeque pointArrayDeque = new ArrayDeque<>(size); + ArrayDeque ids = new ArrayDeque<>(size); + for (int i = 0; i < size; i++) { + pointList.add(new Point(randomWithRange(-20, 20), randomWithRange(-20, 20))); + ids.push((long) i + size); + points[i] = (String.format("Point(%f %f)", pointList.get(i).getX(), pointList.get(i).getY())); + pointArrayDeque.push(points[i]); + } + + SimpleStringCursor simpleStringCursor = new SimpleStringCursor(points); + OperatorImportFromWktCursor operatorImportFromWktCursor = new OperatorImportFromWktCursor(0, simpleStringCursor); + int index = 0; + while (operatorImportFromWktCursor.hasNext()) { + Point point_orig = pointList.get(index); + + Point geom = (Point) operatorImportFromWktCursor.next(); + long geometryID = operatorImportFromWktCursor.getGeometryID(); + assertEquals(geometryID, index); + index++; + assertEquals(point_orig.getX(), geom.getX(), 0.000001); + assertEquals(point_orig.getY(), geom.getY(), 0.000001); + } + + + SimpleGeometryCursor simpleGeometryCursor2 = new SimpleGeometryCursor(new ArrayDeque(list2)); + OperatorExportToWktCursor operatorExportToWktCursor = new OperatorExportToWktCursor(0, simpleGeometryCursor2, null); + operatorImportFromWktCursor = new OperatorImportFromWktCursor(0, operatorExportToWktCursor); + + SpatialReference inputSR = SpatialReference.create(3857); + OperatorFactoryLocal projEnv = OperatorFactoryLocal.getInstance(); + OperatorCrosses operatorCrosses = (OperatorCrosses) (projEnv.getOperator(Operator.Type.Crosses)); + HashMap relate_map = operatorCrosses.execute(poly1, + operatorImportFromWktCursor, inputSR, null); + + assertNotNull(relate_map); + assertTrue(!relate_map.get(0L)); + assertTrue(!relate_map.get(1L)); + + simpleGeometryCursor2 = new SimpleGeometryCursor(new ArrayDeque(list2)); + operatorExportToWktCursor = new OperatorExportToWktCursor(0, simpleGeometryCursor2, null); + operatorImportFromWktCursor = new OperatorImportFromWktCursor(0, operatorExportToWktCursor); + double[] distances = {400, 400}; + OperatorBufferCursor operatorBufferCursor = new OperatorBufferCursor(operatorImportFromWktCursor, null, distances, NumberUtils.NaN(), 96, false, null); + relate_map = ((OperatorWithin) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.Within)).execute(poly2, operatorBufferCursor, inputSR, null); + assertNotNull(relate_map); + assertTrue(relate_map.get(0L)); + assertTrue(relate_map.get(1L)); + + + } + + @Test + public void testWKTID() { + Polygon poly1 = new Polygon(); + Envelope2D env1 = new Envelope2D(); + env1.setCoords(855277, 3892059, 855277 + 100, 3892059 + 100); + poly1.addEnvelope(env1, false); + + Polygon poly2 = new Polygon(); + Envelope2D env2 = new Envelope2D(); + env2.setCoords(855277, 3892059, 855277 + 300, 3892059 + 200); + poly2.addEnvelope(env2, false); + List list2 = new ArrayList<>(); + list2.add(poly1); + list2.add(poly2); + + int size = 1000; + String[] points = new String[size]; + List pointList = new ArrayList<>(size); + List stringList = new ArrayList<>(size); + ArrayDeque pointArrayDeque = new ArrayDeque<>(size); + ArrayDeque ids = new ArrayDeque<>(size); + for (int i = 0; i < size; i++) { + pointList.add(new Point(randomWithRange(-20, 20), randomWithRange(-20, 20))); + ids.addLast((long) i + size); + points[i] = (String.format("Point(%f %f)", pointList.get(i).getX(), pointList.get(i).getY())); + pointArrayDeque.addLast(points[i]); + stringList.add(points[i]); + } + + SimpleStringCursor simpleStringCursor1 = new SimpleStringCursor(points); + SimpleStringCursor simpleStringCursor2 = new SimpleStringCursor(pointArrayDeque.clone(), ids.clone()); + SimpleStringCursor simpleStringCursor3 = new SimpleStringCursor(stringList); + + OperatorImportFromWktCursor operatorImportFromWktCursor1 = new OperatorImportFromWktCursor(0, simpleStringCursor1); + OperatorImportFromWktCursor operatorImportFromWktCursor2 = new OperatorImportFromWktCursor(0, simpleStringCursor2); + OperatorImportFromWktCursor operatorImportFromWktCursor3 = new OperatorImportFromWktCursor(0, simpleStringCursor3); + + while (operatorImportFromWktCursor1.hasNext()) { + Geometry geometry1 = operatorImportFromWktCursor1.next(); + Geometry geometry2 = operatorImportFromWktCursor2.next(); + Geometry geometry3 = operatorImportFromWktCursor3.next(); + assertTrue(geometry1.equals(geometry3)); + assertTrue(geometry1.equals(geometry2)); + } + + SimpleStringCursor simpleStringCursor = new SimpleStringCursor(pointArrayDeque.clone(), ids.clone()); + OperatorImportFromWktCursor operatorImportFromWktCursor = new OperatorImportFromWktCursor(0, simpleStringCursor); + int index = 0; + while (operatorImportFromWktCursor.hasNext()) { + Point point_orig = pointList.get(index); + + Point geom = (Point) operatorImportFromWktCursor.next(); + long geometryID = operatorImportFromWktCursor.getGeometryID(); + assertEquals(geometryID, index + size); + index++; + assertEquals(point_orig.getX(), geom.getX(), 0.000001); + assertEquals(point_orig.getY(), geom.getY(), 0.000001); + } + assertTrue(index > 0); + + simpleStringCursor = new SimpleStringCursor(pointArrayDeque.clone(), ids.clone()); + operatorImportFromWktCursor = new OperatorImportFromWktCursor(0, simpleStringCursor); + OperatorProjectCursor operatorProjectCursor = new OperatorProjectCursor(operatorImportFromWktCursor, new ProjectionTransformation(SpatialReference.create(3857), SpatialReference.create(4326)), null); + double[] stuff = new double[]{3000}; + OperatorGeodesicBufferCursor operatorGeodesicBufferCursor = new OperatorGeodesicBufferCursor(operatorProjectCursor, SpatialReference.create(4326), stuff, 10, false, false, null); + index = 0; + while (operatorGeodesicBufferCursor.hasNext()) { + Geometry polygon = operatorGeodesicBufferCursor.next(); + long geometryID = operatorGeodesicBufferCursor.getGeometryID(); + assertEquals(geometryID, index + size); + index++; + } + assertTrue(index > 0); + + + } + + @Test + public void testMultiPointOrdering() { + MultiPoint multiPoint = new MultiPoint(); + for (double longitude = -180; longitude < 180; longitude += 10.0) { + for (double latitude = -80; latitude < 80; latitude += 10.0) { + multiPoint.add(longitude, latitude); + } + } + String wktGeom = OperatorExportToWkt.local().execute(0, multiPoint, null); + Geometry roundTripGeom = OperatorImportFromWkt.local().execute(0, Geometry.Type.Unknown, wktGeom, null); + assertTrue(roundTripGeom.equals(multiPoint)); + } + + + public static Polygon makePolygon() { + Polygon poly = new Polygon(); + poly.startPath(0, 0); + poly.lineTo(0, 10); + poly.lineTo(10, 10); + poly.lineTo(10, 0); + + poly.startPath(3, 3); + poly.lineTo(7, 3); + poly.lineTo(7, 7); + poly.lineTo(3, 7); + + poly.startPath(15, 0); + poly.lineTo(15, 15); + poly.lineTo(30, 15); + poly.lineTo(30, 0); + + poly.setAttribute(VertexDescription.Semantics.Z, 0, 0, 2); + poly.setAttribute(VertexDescription.Semantics.Z, 1, 0, 3); + poly.setAttribute(VertexDescription.Semantics.Z, 2, 0, 5); + poly.setAttribute(VertexDescription.Semantics.Z, 3, 0, 7); + poly.setAttribute(VertexDescription.Semantics.Z, 4, 0, 11); + poly.setAttribute(VertexDescription.Semantics.Z, 5, 0, 13); + poly.setAttribute(VertexDescription.Semantics.Z, 6, 0, 17); + poly.setAttribute(VertexDescription.Semantics.Z, 7, 0, 19); + poly.setAttribute(VertexDescription.Semantics.Z, 8, 0, 23); + poly.setAttribute(VertexDescription.Semantics.Z, 9, 0, 29); + poly.setAttribute(VertexDescription.Semantics.Z, 10, 0, 31); + poly.setAttribute(VertexDescription.Semantics.Z, 11, 0, 37); + + poly.setAttribute(VertexDescription.Semantics.M, 0, 0, 2); + poly.setAttribute(VertexDescription.Semantics.M, 1, 0, 4); + poly.setAttribute(VertexDescription.Semantics.M, 2, 0, 8); + poly.setAttribute(VertexDescription.Semantics.M, 3, 0, 16); + poly.setAttribute(VertexDescription.Semantics.M, 4, 0, 32); + poly.setAttribute(VertexDescription.Semantics.M, 5, 0, 64); + poly.setAttribute(VertexDescription.Semantics.M, 6, 0, 128); + poly.setAttribute(VertexDescription.Semantics.M, 7, 0, 256); + poly.setAttribute(VertexDescription.Semantics.M, 8, 0, 512); + poly.setAttribute(VertexDescription.Semantics.M, 9, 0, 1024); + poly.setAttribute(VertexDescription.Semantics.M, 10, 0, 2048); + poly.setAttribute(VertexDescription.Semantics.M, 11, 0, 4096); + + return poly; + } + + public static Polygon makePolygon2() { + Polygon poly = new Polygon(); + poly.startPath(0, 0); + poly.lineTo(0, 10); + poly.lineTo(10, 10); + poly.lineTo(10, 0); + + poly.setAttribute(VertexDescription.Semantics.Z, 0, 0, 2); + poly.setAttribute(VertexDescription.Semantics.Z, 1, 0, 3); + poly.setAttribute(VertexDescription.Semantics.Z, 2, 0, 5); + poly.setAttribute(VertexDescription.Semantics.Z, 3, 0, 7); + + poly.setAttribute(VertexDescription.Semantics.M, 0, 0, 2); + poly.setAttribute(VertexDescription.Semantics.M, 1, 0, 4); + poly.setAttribute(VertexDescription.Semantics.M, 2, 0, 8); + poly.setAttribute(VertexDescription.Semantics.M, 3, 0, 16); + + return poly; + } + + public static Polyline makePolyline() { + Polyline poly = new Polyline(); + poly.startPath(10, 1); + poly.lineTo(15, 20); + poly.lineTo(30, 14); + poly.lineTo(60, 144); + + poly.startPath(20, 13); + poly.lineTo(150, 120); + poly.lineTo(300, 414); + poly.lineTo(610, 14); + + poly.setAttribute(VertexDescription.Semantics.Z, 0, 0, 2); + poly.setAttribute(VertexDescription.Semantics.Z, 1, 0, 3); + poly.setAttribute(VertexDescription.Semantics.Z, 2, 0, 5); + poly.setAttribute(VertexDescription.Semantics.Z, 3, 0, 7); + poly.setAttribute(VertexDescription.Semantics.Z, 4, 0, 11); + poly.setAttribute(VertexDescription.Semantics.Z, 5, 0, 13); + poly.setAttribute(VertexDescription.Semantics.Z, 6, 0, 17); + poly.setAttribute(VertexDescription.Semantics.Z, 7, 0, 19); + + poly.setAttribute(VertexDescription.Semantics.M, 0, 0, 2); + poly.setAttribute(VertexDescription.Semantics.M, 1, 0, 4); + poly.setAttribute(VertexDescription.Semantics.M, 2, 0, 8); + poly.setAttribute(VertexDescription.Semantics.M, 3, 0, 16); + poly.setAttribute(VertexDescription.Semantics.M, 4, 0, 32); + poly.setAttribute(VertexDescription.Semantics.M, 5, 0, 64); + poly.setAttribute(VertexDescription.Semantics.M, 6, 0, 128); + poly.setAttribute(VertexDescription.Semantics.M, 7, 0, 256); + + poly.setAttribute(VertexDescription.Semantics.ID, 0, 0, 1); + poly.setAttribute(VertexDescription.Semantics.ID, 1, 0, 2); + poly.setAttribute(VertexDescription.Semantics.ID, 2, 0, 3); + poly.setAttribute(VertexDescription.Semantics.ID, 3, 0, 5); + poly.setAttribute(VertexDescription.Semantics.ID, 4, 0, 8); + poly.setAttribute(VertexDescription.Semantics.ID, 5, 0, 13); + poly.setAttribute(VertexDescription.Semantics.ID, 6, 0, 21); + poly.setAttribute(VertexDescription.Semantics.ID, 7, 0, 34); + + return poly; + } + + public static Polyline makePolyline2() { + Polyline poly = new Polyline(); + poly.startPath(10, 1); + poly.lineTo(15, 20); + poly.lineTo(30, 14); + poly.lineTo(60, 144); + + poly.setAttribute(VertexDescription.Semantics.Z, 0, 0, 2); + poly.setAttribute(VertexDescription.Semantics.Z, 1, 0, 3); + poly.setAttribute(VertexDescription.Semantics.Z, 2, 0, 5); + poly.setAttribute(VertexDescription.Semantics.Z, 3, 0, 7); + + poly.setAttribute(VertexDescription.Semantics.M, 0, 0, 2); + poly.setAttribute(VertexDescription.Semantics.M, 1, 0, 4); + poly.setAttribute(VertexDescription.Semantics.M, 2, 0, 8); + poly.setAttribute(VertexDescription.Semantics.M, 3, 0, 16); + + return poly; + } + + public static Point makePoint() { + Point point = new Point(); + point.setXY(11, 13); + + point.setZ(32); + point.setM(243); + point.setID(1024); + + return point; + } + + public static MultiPoint makeMultiPoint() { + MultiPoint mpoint = new MultiPoint(); + Point pt1 = new Point(); + pt1.setXY(0, 0); + pt1.setZ(-1); + + Point pt2 = new Point(); + pt2.setXY(0, 0); + pt2.setZ(1); + + Point pt3 = new Point(); + pt3.setXY(0, 1); + pt3.setZ(1); + + mpoint.add(pt1); + mpoint.add(pt2); + mpoint.add(pt3); + + mpoint.setAttribute(VertexDescription.Semantics.ID, 0, 0, 7); + mpoint.setAttribute(VertexDescription.Semantics.ID, 1, 0, 11); + mpoint.setAttribute(VertexDescription.Semantics.ID, 2, 0, 13); + + return mpoint; + } + + public static MultiPoint makeMultiPoint2() { + MultiPoint mpoint = new MultiPoint(); + Point pt1 = new Point(); + pt1.setX(0.0); + pt1.setY(0.0); + pt1.setZ(-1.0); + + mpoint.add(pt1); + + return mpoint; + } + + public static Envelope makeEnvelope() { + Envelope envelope; + + Envelope env = new Envelope(0.0, 0.0, 5.0, 5.0); + envelope = env; + + Envelope1D interval = new Envelope1D(); + interval.vmin = -3.0; + interval.vmax = -7.0; + envelope.setInterval(VertexDescription.Semantics.Z, 0, interval); + + interval.vmin = 16.0; + interval.vmax = 32.0; + envelope.setInterval(VertexDescription.Semantics.M, 0, interval); + + interval.vmin = 5.0; + interval.vmax = 11.0; + envelope.setInterval(VertexDescription.Semantics.ID, 0, interval); + + return envelope; + } } diff --git a/src/test/java/com/esri/core/geometry/TestInterpolateAttributes.java b/src/test/java/com/esri/core/geometry/TestInterpolateAttributes.java index 0584267e..f20f3063 100644 --- a/src/test/java/com/esri/core/geometry/TestInterpolateAttributes.java +++ b/src/test/java/com/esri/core/geometry/TestInterpolateAttributes.java @@ -28,194 +28,194 @@ import org.junit.Test; public class TestInterpolateAttributes extends TestCase { - @Override - protected void setUp() throws Exception { - super.setUp(); - } - - @Override - protected void tearDown() throws Exception { - super.tearDown(); - } - - @Test - public static void test1() { - Polyline poly = new Polyline(); - - poly.startPath(0, 0); - poly.lineTo(0, 1.0 / 3.0); - poly.lineTo(0, 2.0 / 3.0); - poly.lineTo(0, 4.0 / 3.0); - poly.lineTo(0, Math.sqrt(6.0)); - poly.lineTo(0, Math.sqrt(7.0)); - - poly.setAttribute(VertexDescription.Semantics.M, 0, 0, 3); - poly.setAttribute(VertexDescription.Semantics.M, 1, 0, 5); - poly.setAttribute(VertexDescription.Semantics.M, 2, 0, 7); - poly.setAttribute(VertexDescription.Semantics.M, 5, 0, 11); - - poly.interpolateAttributes(VertexDescription.Semantics.M, 0, 1, 0, 1); - assertTrue(poly.getAttributeAsDbl(VertexDescription.Semantics.M, 0, 0) == 3); - assertTrue(poly.getAttributeAsDbl(VertexDescription.Semantics.M, 1, 0) == 5); - assertTrue(poly.getAttributeAsDbl(VertexDescription.Semantics.M, 2, 0) == 7); - assertTrue(NumberUtils.isNaN(poly.getAttributeAsDbl( - VertexDescription.Semantics.M, 3, 0))); - assertTrue(NumberUtils.isNaN(poly.getAttributeAsDbl( - VertexDescription.Semantics.M, 4, 0))); - assertTrue(poly.getAttributeAsDbl(VertexDescription.Semantics.M, 5, 0) == 11); - - poly.interpolateAttributes(VertexDescription.Semantics.M, 0, 1, 0, 2); - assertTrue(poly.getAttributeAsDbl(VertexDescription.Semantics.M, 0, 0) == 3); - assertTrue(poly.getAttributeAsDbl(VertexDescription.Semantics.M, 1, 0) == 5); - assertTrue(poly.getAttributeAsDbl(VertexDescription.Semantics.M, 2, 0) == 7); - assertTrue(NumberUtils.isNaN(poly.getAttributeAsDbl( - VertexDescription.Semantics.M, 3, 0))); - assertTrue(NumberUtils.isNaN(poly.getAttributeAsDbl( - VertexDescription.Semantics.M, 4, 0))); - assertTrue(poly.getAttributeAsDbl(VertexDescription.Semantics.M, 5, 0) == 11); - - poly.interpolateAttributes(VertexDescription.Semantics.M, 0, 2, 0, 5); - assertTrue(poly.getAttributeAsDbl(VertexDescription.Semantics.M, 0, 0) == 3); - assertTrue(poly.getAttributeAsDbl(VertexDescription.Semantics.M, 1, 0) == 5); - assertTrue(poly.getAttributeAsDbl(VertexDescription.Semantics.M, 2, 0) == 7); - double a3 = poly.getAttributeAsDbl(VertexDescription.Semantics.M, 3, 0); - assertTrue(a3 > 7 && a3 < 11); - double a4 = poly.getAttributeAsDbl(VertexDescription.Semantics.M, 4, 0); - assertTrue(a4 > a3 && a4 < 11); - assertTrue(poly.getAttributeAsDbl(VertexDescription.Semantics.M, 5, 0) == 11); - - poly.startPath(0, Math.sqrt(8.0)); - poly.lineTo(0, Math.sqrt(10.0)); - poly.lineTo(0, Math.sqrt(11.0)); - } - - @Test - public static void test2() { - Polyline poly = new Polyline(); - - poly.startPath(0, 0); - poly.lineTo(0, 1.0 / 3.0); - - poly.startPath(0, Math.sqrt(8.0)); - poly.lineTo(0, Math.sqrt(10.0)); - - poly.setAttribute(VertexDescription.Semantics.M, 1, 0, Math.sqrt(3.0)); - - poly.interpolateAttributes(VertexDescription.Semantics.M, 0, 1, 1, 0); - assertTrue(poly.getAttributeAsDbl(VertexDescription.Semantics.M, 1, 0) == Math - .sqrt(3.0)); - assertTrue(NumberUtils.isNaN(poly.getAttributeAsDbl( - VertexDescription.Semantics.M, 2, 0))); - - poly.setAttribute(VertexDescription.Semantics.M, 3, 0, Math.sqrt(5.0)); - poly.interpolateAttributes(VertexDescription.Semantics.M, 0, 1, 1, 1); - assertTrue(poly.getAttributeAsDbl(VertexDescription.Semantics.M, 1, 0) == Math - .sqrt(3.0)); - double a2 = poly.getAttributeAsDbl(VertexDescription.Semantics.M, 2, 0); - assertTrue(a2 == Math.sqrt(3.0)); - assertTrue(poly.getAttributeAsDbl(VertexDescription.Semantics.M, 3, 0) == Math - .sqrt(5.0)); - } - - @Test - public static void test3() { - Polyline poly = new Polyline(); - - poly.startPath(0, Math.sqrt(0.0)); - poly.lineTo(0, Math.sqrt(5.0)); - - poly.startPath(0, Math.sqrt(8.0)); - poly.lineTo(0, Math.sqrt(10.0)); - - poly.setAttribute(VertexDescription.Semantics.M, 0, 0, Math.sqrt(3.0)); - poly.setAttribute(VertexDescription.Semantics.M, 2, 0, Math.sqrt(5.0)); - - poly.interpolateAttributes(VertexDescription.Semantics.M, 0, 0, 1, 0); - assertTrue(poly.getAttributeAsDbl(VertexDescription.Semantics.M, 0, 0) == Math - .sqrt(3.0)); - assertTrue(poly.getAttributeAsDbl(VertexDescription.Semantics.M, 1, 0) == Math - .sqrt(5.0)); - assertTrue(poly.getAttributeAsDbl(VertexDescription.Semantics.M, 2, 0) == Math - .sqrt(5.0)); - } - - @Test - public static void test4() { - Polyline poly = new Polyline(); - - poly.startPath(0, Math.sqrt(0.0)); - poly.lineTo(0, Math.sqrt(1.0)); - - poly.startPath(0, Math.sqrt(1.0)); - poly.lineTo(0, Math.sqrt(2.0)); - - poly.startPath(0, Math.sqrt(2.0)); - poly.lineTo(0, Math.sqrt(3.0)); - - poly.startPath(0, Math.sqrt(3.0)); - poly.lineTo(0, Math.sqrt(4.0)); - - poly.startPath(0, Math.sqrt(4.0)); - poly.lineTo(0, Math.sqrt(5.0)); - - poly.setAttribute(VertexDescription.Semantics.M, 1, 0, Math.sqrt(1.0)); - poly.setAttribute(VertexDescription.Semantics.M, 8, 0, Math.sqrt(4.0)); - - poly.interpolateAttributes(VertexDescription.Semantics.M, 0, 1, 4, 0); - - assertTrue(NumberUtils.isNaN(poly.getAttributeAsDbl( - VertexDescription.Semantics.M, 0, 0))); - assertTrue(poly.getAttributeAsDbl(VertexDescription.Semantics.M, 1, 0) == Math - .sqrt(1.0)); - assertTrue(poly.getAttributeAsDbl(VertexDescription.Semantics.M, 2, 0) == Math - .sqrt(1.0)); - assertTrue(poly.getAttributeAsDbl(VertexDescription.Semantics.M, 3, 0) == Math - .sqrt(2.0)); - assertTrue(poly.getAttributeAsDbl(VertexDescription.Semantics.M, 4, 0) == Math - .sqrt(2.0)); - assertTrue(poly.getAttributeAsDbl(VertexDescription.Semantics.M, 5, 0) == Math - .sqrt(3.0)); - assertTrue(poly.getAttributeAsDbl(VertexDescription.Semantics.M, 6, 0) == Math - .sqrt(3.0)); - assertTrue(poly.getAttributeAsDbl(VertexDescription.Semantics.M, 7, 0) == Math - .sqrt(4.0)); - assertTrue(poly.getAttributeAsDbl(VertexDescription.Semantics.M, 8, 0) == Math - .sqrt(4.0)); - assertTrue(NumberUtils.isNaN(poly.getAttributeAsDbl( - VertexDescription.Semantics.M, 9, 0))); - } - - @Test - public static void test5() { - Polygon poly = new Polygon(); - - poly.startPath(0, 0); - poly.lineTo(0, 1); - poly.lineTo(1, 1); - poly.lineTo(1, 0); - - poly.startPath(2, 0); - poly.lineTo(2, 1); - poly.lineTo(3, 1); - poly.lineTo(3, 0); - - poly.setAttribute(VertexDescription.Semantics.M, 1, 0, 1); - poly.setAttribute(VertexDescription.Semantics.M, 3, 0, 3); - - poly.setAttribute(VertexDescription.Semantics.M, 6, 0, 1); - poly.setAttribute(VertexDescription.Semantics.M, 5, 0, 4); - - poly.interpolateAttributes(VertexDescription.Semantics.M, 0, 3, 1); - poly.interpolateAttributes(VertexDescription.Semantics.M, 0, 1, 3); - poly.interpolateAttributes(VertexDescription.Semantics.M, 1, 2, 1); - - assertTrue(poly.getAttributeAsDbl(VertexDescription.Semantics.M, 0, 0) == 2); - assertTrue(poly.getAttributeAsDbl(VertexDescription.Semantics.M, 1, 0) == 1); - assertTrue(poly.getAttributeAsDbl(VertexDescription.Semantics.M, 2, 0) == 2); - assertTrue(poly.getAttributeAsDbl(VertexDescription.Semantics.M, 3, 0) == 3); - assertTrue(poly.getAttributeAsDbl(VertexDescription.Semantics.M, 4, 0) == 3); - assertTrue(poly.getAttributeAsDbl(VertexDescription.Semantics.M, 5, 0) == 4); - assertTrue(poly.getAttributeAsDbl(VertexDescription.Semantics.M, 6, 0) == 1); - assertTrue(poly.getAttributeAsDbl(VertexDescription.Semantics.M, 7, 0) == 2); - } + @Override + protected void setUp() throws Exception { + super.setUp(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + } + + @Test + public static void test1() { + Polyline poly = new Polyline(); + + poly.startPath(0, 0); + poly.lineTo(0, 1.0 / 3.0); + poly.lineTo(0, 2.0 / 3.0); + poly.lineTo(0, 4.0 / 3.0); + poly.lineTo(0, Math.sqrt(6.0)); + poly.lineTo(0, Math.sqrt(7.0)); + + poly.setAttribute(VertexDescription.Semantics.M, 0, 0, 3); + poly.setAttribute(VertexDescription.Semantics.M, 1, 0, 5); + poly.setAttribute(VertexDescription.Semantics.M, 2, 0, 7); + poly.setAttribute(VertexDescription.Semantics.M, 5, 0, 11); + + poly.interpolateAttributes(VertexDescription.Semantics.M, 0, 1, 0, 1); + assertTrue(poly.getAttributeAsDbl(VertexDescription.Semantics.M, 0, 0) == 3); + assertTrue(poly.getAttributeAsDbl(VertexDescription.Semantics.M, 1, 0) == 5); + assertTrue(poly.getAttributeAsDbl(VertexDescription.Semantics.M, 2, 0) == 7); + assertTrue(NumberUtils.isNaN(poly.getAttributeAsDbl( + VertexDescription.Semantics.M, 3, 0))); + assertTrue(NumberUtils.isNaN(poly.getAttributeAsDbl( + VertexDescription.Semantics.M, 4, 0))); + assertTrue(poly.getAttributeAsDbl(VertexDescription.Semantics.M, 5, 0) == 11); + + poly.interpolateAttributes(VertexDescription.Semantics.M, 0, 1, 0, 2); + assertTrue(poly.getAttributeAsDbl(VertexDescription.Semantics.M, 0, 0) == 3); + assertTrue(poly.getAttributeAsDbl(VertexDescription.Semantics.M, 1, 0) == 5); + assertTrue(poly.getAttributeAsDbl(VertexDescription.Semantics.M, 2, 0) == 7); + assertTrue(NumberUtils.isNaN(poly.getAttributeAsDbl( + VertexDescription.Semantics.M, 3, 0))); + assertTrue(NumberUtils.isNaN(poly.getAttributeAsDbl( + VertexDescription.Semantics.M, 4, 0))); + assertTrue(poly.getAttributeAsDbl(VertexDescription.Semantics.M, 5, 0) == 11); + + poly.interpolateAttributes(VertexDescription.Semantics.M, 0, 2, 0, 5); + assertTrue(poly.getAttributeAsDbl(VertexDescription.Semantics.M, 0, 0) == 3); + assertTrue(poly.getAttributeAsDbl(VertexDescription.Semantics.M, 1, 0) == 5); + assertTrue(poly.getAttributeAsDbl(VertexDescription.Semantics.M, 2, 0) == 7); + double a3 = poly.getAttributeAsDbl(VertexDescription.Semantics.M, 3, 0); + assertTrue(a3 > 7 && a3 < 11); + double a4 = poly.getAttributeAsDbl(VertexDescription.Semantics.M, 4, 0); + assertTrue(a4 > a3 && a4 < 11); + assertTrue(poly.getAttributeAsDbl(VertexDescription.Semantics.M, 5, 0) == 11); + + poly.startPath(0, Math.sqrt(8.0)); + poly.lineTo(0, Math.sqrt(10.0)); + poly.lineTo(0, Math.sqrt(11.0)); + } + + @Test + public static void test2() { + Polyline poly = new Polyline(); + + poly.startPath(0, 0); + poly.lineTo(0, 1.0 / 3.0); + + poly.startPath(0, Math.sqrt(8.0)); + poly.lineTo(0, Math.sqrt(10.0)); + + poly.setAttribute(VertexDescription.Semantics.M, 1, 0, Math.sqrt(3.0)); + + poly.interpolateAttributes(VertexDescription.Semantics.M, 0, 1, 1, 0); + assertTrue(poly.getAttributeAsDbl(VertexDescription.Semantics.M, 1, 0) == Math + .sqrt(3.0)); + assertTrue(NumberUtils.isNaN(poly.getAttributeAsDbl( + VertexDescription.Semantics.M, 2, 0))); + + poly.setAttribute(VertexDescription.Semantics.M, 3, 0, Math.sqrt(5.0)); + poly.interpolateAttributes(VertexDescription.Semantics.M, 0, 1, 1, 1); + assertTrue(poly.getAttributeAsDbl(VertexDescription.Semantics.M, 1, 0) == Math + .sqrt(3.0)); + double a2 = poly.getAttributeAsDbl(VertexDescription.Semantics.M, 2, 0); + assertTrue(a2 == Math.sqrt(3.0)); + assertTrue(poly.getAttributeAsDbl(VertexDescription.Semantics.M, 3, 0) == Math + .sqrt(5.0)); + } + + @Test + public static void test3() { + Polyline poly = new Polyline(); + + poly.startPath(0, Math.sqrt(0.0)); + poly.lineTo(0, Math.sqrt(5.0)); + + poly.startPath(0, Math.sqrt(8.0)); + poly.lineTo(0, Math.sqrt(10.0)); + + poly.setAttribute(VertexDescription.Semantics.M, 0, 0, Math.sqrt(3.0)); + poly.setAttribute(VertexDescription.Semantics.M, 2, 0, Math.sqrt(5.0)); + + poly.interpolateAttributes(VertexDescription.Semantics.M, 0, 0, 1, 0); + assertTrue(poly.getAttributeAsDbl(VertexDescription.Semantics.M, 0, 0) == Math + .sqrt(3.0)); + assertTrue(poly.getAttributeAsDbl(VertexDescription.Semantics.M, 1, 0) == Math + .sqrt(5.0)); + assertTrue(poly.getAttributeAsDbl(VertexDescription.Semantics.M, 2, 0) == Math + .sqrt(5.0)); + } + + @Test + public static void test4() { + Polyline poly = new Polyline(); + + poly.startPath(0, Math.sqrt(0.0)); + poly.lineTo(0, Math.sqrt(1.0)); + + poly.startPath(0, Math.sqrt(1.0)); + poly.lineTo(0, Math.sqrt(2.0)); + + poly.startPath(0, Math.sqrt(2.0)); + poly.lineTo(0, Math.sqrt(3.0)); + + poly.startPath(0, Math.sqrt(3.0)); + poly.lineTo(0, Math.sqrt(4.0)); + + poly.startPath(0, Math.sqrt(4.0)); + poly.lineTo(0, Math.sqrt(5.0)); + + poly.setAttribute(VertexDescription.Semantics.M, 1, 0, Math.sqrt(1.0)); + poly.setAttribute(VertexDescription.Semantics.M, 8, 0, Math.sqrt(4.0)); + + poly.interpolateAttributes(VertexDescription.Semantics.M, 0, 1, 4, 0); + + assertTrue(NumberUtils.isNaN(poly.getAttributeAsDbl( + VertexDescription.Semantics.M, 0, 0))); + assertTrue(poly.getAttributeAsDbl(VertexDescription.Semantics.M, 1, 0) == Math + .sqrt(1.0)); + assertTrue(poly.getAttributeAsDbl(VertexDescription.Semantics.M, 2, 0) == Math + .sqrt(1.0)); + assertTrue(poly.getAttributeAsDbl(VertexDescription.Semantics.M, 3, 0) == Math + .sqrt(2.0)); + assertTrue(poly.getAttributeAsDbl(VertexDescription.Semantics.M, 4, 0) == Math + .sqrt(2.0)); + assertTrue(poly.getAttributeAsDbl(VertexDescription.Semantics.M, 5, 0) == Math + .sqrt(3.0)); + assertTrue(poly.getAttributeAsDbl(VertexDescription.Semantics.M, 6, 0) == Math + .sqrt(3.0)); + assertTrue(poly.getAttributeAsDbl(VertexDescription.Semantics.M, 7, 0) == Math + .sqrt(4.0)); + assertTrue(poly.getAttributeAsDbl(VertexDescription.Semantics.M, 8, 0) == Math + .sqrt(4.0)); + assertTrue(NumberUtils.isNaN(poly.getAttributeAsDbl( + VertexDescription.Semantics.M, 9, 0))); + } + + @Test + public static void test5() { + Polygon poly = new Polygon(); + + poly.startPath(0, 0); + poly.lineTo(0, 1); + poly.lineTo(1, 1); + poly.lineTo(1, 0); + + poly.startPath(2, 0); + poly.lineTo(2, 1); + poly.lineTo(3, 1); + poly.lineTo(3, 0); + + poly.setAttribute(VertexDescription.Semantics.M, 1, 0, 1); + poly.setAttribute(VertexDescription.Semantics.M, 3, 0, 3); + + poly.setAttribute(VertexDescription.Semantics.M, 6, 0, 1); + poly.setAttribute(VertexDescription.Semantics.M, 5, 0, 4); + + poly.interpolateAttributes(VertexDescription.Semantics.M, 0, 3, 1); + poly.interpolateAttributes(VertexDescription.Semantics.M, 0, 1, 3); + poly.interpolateAttributes(VertexDescription.Semantics.M, 1, 2, 1); + + assertTrue(poly.getAttributeAsDbl(VertexDescription.Semantics.M, 0, 0) == 2); + assertTrue(poly.getAttributeAsDbl(VertexDescription.Semantics.M, 1, 0) == 1); + assertTrue(poly.getAttributeAsDbl(VertexDescription.Semantics.M, 2, 0) == 2); + assertTrue(poly.getAttributeAsDbl(VertexDescription.Semantics.M, 3, 0) == 3); + assertTrue(poly.getAttributeAsDbl(VertexDescription.Semantics.M, 4, 0) == 3); + assertTrue(poly.getAttributeAsDbl(VertexDescription.Semantics.M, 5, 0) == 4); + assertTrue(poly.getAttributeAsDbl(VertexDescription.Semantics.M, 6, 0) == 1); + assertTrue(poly.getAttributeAsDbl(VertexDescription.Semantics.M, 7, 0) == 2); + } } diff --git a/src/test/java/com/esri/core/geometry/TestIntersect2.java b/src/test/java/com/esri/core/geometry/TestIntersect2.java index f4e0478f..a214b910 100644 --- a/src/test/java/com/esri/core/geometry/TestIntersect2.java +++ b/src/test/java/com/esri/core/geometry/TestIntersect2.java @@ -29,376 +29,376 @@ import org.junit.Test; public class TestIntersect2 extends TestCase { - @Override - protected void setUp() throws Exception { - super.setUp(); - } - - @Override - protected void tearDown() throws Exception { - super.tearDown(); - } - - @Test - /** - * Intersect - * throw InvalidShapeException when applying between polyline and polygon - * - * */ - public void testIntersectBetweenPolylineAndPolygon() { - Polyline basePl = new Polyline(); - basePl.startPath(new Point(-117, 20)); - basePl.lineTo(new Point(-117, 10)); - basePl.lineTo(new Point(-130, 10)); - basePl.lineTo(new Point(-130, 20)); - basePl.lineTo(new Point(-117, 20)); - - Polygon compPl = new Polygon(); - compPl.startPath(-116, 20); - compPl.lineTo(-131, 10); - compPl.lineTo(-121, 50); - - Geometry intersectGeom = null; - - @SuppressWarnings("unused") - int noException = 1; // no exception - try { - intersectGeom = GeometryEngine.intersect(basePl, compPl, - SpatialReference.create(4326)); - - } catch (Exception ex) { - noException = 0; - } - assertNotNull(intersectGeom); - - // Geometry[] geometries = new Geometry[1]; - // geometries[0] = basePl; - // BorgGeometryUtils.getIntersectFromRestWS(geometries, compPl, 4326); - } - - @Test - public void testIntersectBetweenPolylines() { - Polyline basePl = new Polyline(); - basePl.startPath(new Point(-117, 20)); - basePl.lineTo(new Point(-130, 10)); - basePl.lineTo(new Point(-120, 50)); - - Polyline compPl = new Polyline(); - compPl.startPath(new Point(-116, 20)); - compPl.lineTo(new Point(-131, 10)); - compPl.lineTo(new Point(-121, 50)); - - int noException = 1; // no exception - try { - @SuppressWarnings("unused") - Geometry intersectGeom = GeometryEngine.intersect(basePl, compPl, - SpatialReference.create(4326)); - - } catch (Exception ex) { - noException = 0; - } - assertEquals(noException, 1); - } - - @Test - public void testPointAndPolyline1() { - Point basePl = new Point(-116, 20); - - Polyline compPl = new Polyline(); - compPl.startPath(new Point(-116, 20)); - compPl.lineTo(new Point(-131, 10)); - compPl.lineTo(new Point(-121, 50)); - - int noException = 1; // no exception - Geometry intersectGeom = null; - try { - intersectGeom = GeometryEngine.intersect(basePl, compPl, - SpatialReference.create(4326)); - } catch (Exception ex) { - noException = 0; - } - assertEquals(noException, 1); - assertNotNull(intersectGeom); - assertTrue(intersectGeom.getType() == Type.Point); - - Point ip = (Point) intersectGeom; - assertEquals(ip.getX(), -116, 0.1E7); - assertEquals(ip.getY(), 20, 0.1E7); - } - - @Test - public void testPointAndPolyline2() { - Point basePl = new Point(-115, 20); - Polyline compPl = new Polyline(); - compPl.startPath(new Point(-116, 20)); - compPl.lineTo(new Point(-131, 10)); - compPl.lineTo(new Point(-121, 50)); - - int noException = 1; // no exception - Geometry intersectGeom = null; - try { - intersectGeom = GeometryEngine.intersect(basePl, compPl, - SpatialReference.create(4326)); - } catch (Exception ex) { - noException = 0; - } - assertEquals(noException, 1); - assertTrue(intersectGeom.isEmpty()); - } - - @Test - public void testPointAndPolygon1() { - Point basePl = new Point(-116, 20); - Polygon compPl = new Polygon(); - compPl.startPath(new Point(-116, 20)); - compPl.lineTo(new Point(-131, 10)); - compPl.lineTo(new Point(-121, 50)); - - int noException = 1; // no exception - Geometry intersectGeom = null; - try { - intersectGeom = GeometryEngine.intersect(basePl, compPl, - SpatialReference.create(4326)); - - } catch (Exception ex) { - noException = 0; - } - assertEquals(noException, 1); - assertNotNull(intersectGeom); - assertTrue(intersectGeom.getType() == Type.Point); - - Point ip = (Point) intersectGeom; - assertEquals(ip.getX(), -116, 0.1E7); - assertEquals(ip.getY(), 20, 0.1E7); - - try { - MultiPoint mp = new MultiPoint(); - mp.add(basePl); - intersectGeom = GeometryEngine.intersect(mp, compPl, SpatialReference.create(4326)); - } catch (Exception ex) { - noException = 0; - } - assertEquals(noException, 1); - assertNotNull(intersectGeom); - assertTrue(intersectGeom.getType() == Type.MultiPoint); - MultiPoint mpOut = (MultiPoint) intersectGeom; - assertTrue(mpOut.getPointCount() == 1); - assertEquals(mpOut.getPoint(0).getX(), -116, 0.1E7); - assertEquals(mpOut.getPoint(0).getY(), 20, 0.1E7); - } - - @Test - public void testPointAndPolygon2() { - Point basePl = new Point(-115, 20); - Polygon compPl = new Polygon(); - compPl.startPath(new Point(-116, 20)); - compPl.lineTo(new Point(-131, 10)); - compPl.lineTo(new Point(-121, 50)); - - int noException = 1; // no exception - Geometry intersectGeom = null; - try { - intersectGeom = GeometryEngine.intersect(basePl, compPl, - SpatialReference.create(4326)); - - } catch (Exception ex) { - noException = 0; - } - assertEquals(noException, 1); - assertTrue(intersectGeom.isEmpty()); - } - - @Test - public void testPointAndPolygon3() { - Point basePl = new Point(-121, 20); - Polygon compPl = new Polygon(); - compPl.startPath(new Point(-116, 20)); - compPl.lineTo(new Point(-131, 10)); - compPl.lineTo(new Point(-121, 50)); - - int noException = 1; // no exception - Geometry intersectGeom = null; - try { - intersectGeom = GeometryEngine.intersect(basePl, compPl, - SpatialReference.create(4326)); - - } catch (Exception ex) { - noException = 0; - } - assertEquals(noException, 1); - assertNotNull(intersectGeom); - assertTrue(intersectGeom.getType() == Type.Point); - - Point ip = (Point) intersectGeom; - assertEquals(ip.getX(), -121, 0.1E7); - assertEquals(ip.getY(), 20, 0.1E7); - } - - @Test - public void testPointAndPoint1() { - Point basePl = new Point(-116, 20); - Point compPl = new Point(-116, 20); - - int noException = 1; // no exception - Geometry intersectGeom = null; - try { - intersectGeom = GeometryEngine.intersect(basePl, compPl, - SpatialReference.create(4326)); - } catch (Exception ex) { - noException = 0; - } - assertEquals(noException, 1); - assertNotNull(intersectGeom); - assertTrue(intersectGeom.getType() == Type.Point); - - Point ip = (Point) intersectGeom; - assertEquals(ip.getX(), -116, 0.1E7); - assertEquals(ip.getY(), 20, 0.1E7); - } - - @Test - public void testPointAndPoint2() { - Point basePl = new Point(-115, 20); - Point compPl = new Point(-116, 20); - - int noException = 1; // no exception - Geometry intersectGeom = null; - try { - intersectGeom = GeometryEngine.intersect(basePl, compPl, - SpatialReference.create(4326)); - } catch (Exception ex) { - noException = 0; - } - assertEquals(noException, 1); - assertTrue(intersectGeom.isEmpty()); - } - - @Test - public void testPointAndMultiPoint1() { - Point basePl = new Point(-116, 20); - MultiPoint compPl = new MultiPoint(); - compPl.add(new Point(-116, 20)); - compPl.add(new Point(-118, 21)); - - int noException = 1; // no exception - Geometry intersectGeom = null; - try { - intersectGeom = GeometryEngine.intersect(basePl, compPl, - SpatialReference.create(4326)); - } catch (Exception ex) { - noException = 0; - } - assertEquals(noException, 1); - assertNotNull(intersectGeom); - assertTrue(intersectGeom.getType() == Type.Point); - - Point ip = (Point) intersectGeom; - assertEquals(ip.getX(), -116, 0.1E7); - assertEquals(ip.getY(), 20, 0.1E7); - } - - @Test - public void testPointAndMultiPoint2() { - Point basePl = new Point(-115, 20); - - MultiPoint compPl = new MultiPoint(); - compPl.add(new Point(-116, 20)); - compPl.add(new Point(-117, 21)); - compPl.add(new Point(-118, 20)); - compPl.add(new Point(-119, 21)); - - int noException = 1; // no exception - Geometry intersectGeom = null; - - try { - intersectGeom = GeometryEngine.intersect(basePl, compPl, - SpatialReference.create(4326)); - } catch (Exception ex) { - noException = 0; - } - assertEquals(noException, 1); - assertTrue(intersectGeom.isEmpty()); - } - - @Test - public void testMultiPointAndMultiPoint1() { - MultiPoint basePl = new MultiPoint(); - basePl.add(new Point(-116, 20)); - basePl.add(new Point(-117, 20)); - - MultiPoint compPl = new MultiPoint(); - compPl.add(new Point(-116, 20)); - compPl.add(new Point(-118, 21)); - - int noException = 1; // no exception - Geometry intersectGeom = null; - try { - intersectGeom = GeometryEngine.intersect(basePl, compPl, - SpatialReference.create(4326)); - } catch (Exception ex) { - noException = 0; - } - assertEquals(noException, 1); - assertNotNull(intersectGeom); - assertTrue(intersectGeom.getType() == Type.MultiPoint); - - MultiPoint imp = (MultiPoint) intersectGeom; - assertEquals(imp.getCoordinates2D().length, 1); - assertEquals(imp.getCoordinates2D()[0].x, -116, 0.0); - assertEquals(imp.getCoordinates2D()[0].y, 20, 0.0); - } - - @Test - public void testMultiPointAndMultiPoint2() { - MultiPoint basePl = new MultiPoint(); - basePl.add(new Point(-116, 20)); - basePl.add(new Point(-118, 21)); - - MultiPoint compPl = new MultiPoint(); - compPl.add(new Point(-116, 20)); - compPl.add(new Point(-118, 21)); - - int noException = 1; // no exception - Geometry intersectGeom = null; - try { - intersectGeom = GeometryEngine.intersect(basePl, compPl, - SpatialReference.create(4326)); - } catch (Exception ex) { - noException = 0; - } - - assertEquals(noException, 1); - assertNotNull(intersectGeom); - assertTrue(intersectGeom.getType() == Type.MultiPoint); - - MultiPoint ip = (MultiPoint) intersectGeom; - assertEquals(ip.getPoint(0).getX(), -116, 0.1E7); - assertEquals(ip.getPoint(0).getY(), 20, 0.1E7); - assertEquals(ip.getPoint(0).getX(), -118, 0.1E7); - assertEquals(ip.getPoint(0).getY(), 21, 0.1E7); - } - - @Test - public void testMultiPointAndMultiPoint3() { - MultiPoint basePl = new MultiPoint(); - basePl.add(new Point(-116, 21)); - basePl.add(new Point(-117, 20)); - - MultiPoint compPl = new MultiPoint(); - compPl.add(new Point(-116, 20)); - compPl.add(new Point(-117, 21)); - compPl.add(new Point(-118, 20)); - compPl.add(new Point(-119, 21)); - - int noException = 1; // no exception - Geometry intersectGeom = null; - try { - intersectGeom = GeometryEngine.intersect(basePl, compPl, - SpatialReference.create(4326)); - } catch (Exception ex) { - noException = 0; - } - assertEquals(noException, 1); - assertTrue(intersectGeom.isEmpty()); - } + @Override + protected void setUp() throws Exception { + super.setUp(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + } + + @Test + /** + * Intersect + * throw InvalidShapeException when applying between polyline and polygon + * + * */ + public void testIntersectBetweenPolylineAndPolygon() { + Polyline basePl = new Polyline(); + basePl.startPath(new Point(-117, 20)); + basePl.lineTo(new Point(-117, 10)); + basePl.lineTo(new Point(-130, 10)); + basePl.lineTo(new Point(-130, 20)); + basePl.lineTo(new Point(-117, 20)); + + Polygon compPl = new Polygon(); + compPl.startPath(-116, 20); + compPl.lineTo(-131, 10); + compPl.lineTo(-121, 50); + + Geometry intersectGeom = null; + + @SuppressWarnings("unused") + int noException = 1; // no exception + try { + intersectGeom = GeometryEngine.intersect(basePl, compPl, + SpatialReference.create(4326)); + + } catch (Exception ex) { + noException = 0; + } + assertNotNull(intersectGeom); + + // Geometry[] geometries = new Geometry[1]; + // geometries[0] = basePl; + // BorgGeometryUtils.getIntersectFromRestWS(geometries, compPl, 4326); + } + + @Test + public void testIntersectBetweenPolylines() { + Polyline basePl = new Polyline(); + basePl.startPath(new Point(-117, 20)); + basePl.lineTo(new Point(-130, 10)); + basePl.lineTo(new Point(-120, 50)); + + Polyline compPl = new Polyline(); + compPl.startPath(new Point(-116, 20)); + compPl.lineTo(new Point(-131, 10)); + compPl.lineTo(new Point(-121, 50)); + + int noException = 1; // no exception + try { + @SuppressWarnings("unused") + Geometry intersectGeom = GeometryEngine.intersect(basePl, compPl, + SpatialReference.create(4326)); + + } catch (Exception ex) { + noException = 0; + } + assertEquals(noException, 1); + } + + @Test + public void testPointAndPolyline1() { + Point basePl = new Point(-116, 20); + + Polyline compPl = new Polyline(); + compPl.startPath(new Point(-116, 20)); + compPl.lineTo(new Point(-131, 10)); + compPl.lineTo(new Point(-121, 50)); + + int noException = 1; // no exception + Geometry intersectGeom = null; + try { + intersectGeom = GeometryEngine.intersect(basePl, compPl, + SpatialReference.create(4326)); + } catch (Exception ex) { + noException = 0; + } + assertEquals(noException, 1); + assertNotNull(intersectGeom); + assertTrue(intersectGeom.getType() == Type.Point); + + Point ip = (Point) intersectGeom; + assertEquals(ip.getX(), -116, 0.1E7); + assertEquals(ip.getY(), 20, 0.1E7); + } + + @Test + public void testPointAndPolyline2() { + Point basePl = new Point(-115, 20); + Polyline compPl = new Polyline(); + compPl.startPath(new Point(-116, 20)); + compPl.lineTo(new Point(-131, 10)); + compPl.lineTo(new Point(-121, 50)); + + int noException = 1; // no exception + Geometry intersectGeom = null; + try { + intersectGeom = GeometryEngine.intersect(basePl, compPl, + SpatialReference.create(4326)); + } catch (Exception ex) { + noException = 0; + } + assertEquals(noException, 1); + assertTrue(intersectGeom.isEmpty()); + } + + @Test + public void testPointAndPolygon1() { + Point basePl = new Point(-116, 20); + Polygon compPl = new Polygon(); + compPl.startPath(new Point(-116, 20)); + compPl.lineTo(new Point(-131, 10)); + compPl.lineTo(new Point(-121, 50)); + + int noException = 1; // no exception + Geometry intersectGeom = null; + try { + intersectGeom = GeometryEngine.intersect(basePl, compPl, + SpatialReference.create(4326)); + + } catch (Exception ex) { + noException = 0; + } + assertEquals(noException, 1); + assertNotNull(intersectGeom); + assertTrue(intersectGeom.getType() == Type.Point); + + Point ip = (Point) intersectGeom; + assertEquals(ip.getX(), -116, 0.1E7); + assertEquals(ip.getY(), 20, 0.1E7); + + try { + MultiPoint mp = new MultiPoint(); + mp.add(basePl); + intersectGeom = GeometryEngine.intersect(mp, compPl, SpatialReference.create(4326)); + } catch (Exception ex) { + noException = 0; + } + assertEquals(noException, 1); + assertNotNull(intersectGeom); + assertTrue(intersectGeom.getType() == Type.MultiPoint); + MultiPoint mpOut = (MultiPoint) intersectGeom; + assertTrue(mpOut.getPointCount() == 1); + assertEquals(mpOut.getPoint(0).getX(), -116, 0.1E7); + assertEquals(mpOut.getPoint(0).getY(), 20, 0.1E7); + } + + @Test + public void testPointAndPolygon2() { + Point basePl = new Point(-115, 20); + Polygon compPl = new Polygon(); + compPl.startPath(new Point(-116, 20)); + compPl.lineTo(new Point(-131, 10)); + compPl.lineTo(new Point(-121, 50)); + + int noException = 1; // no exception + Geometry intersectGeom = null; + try { + intersectGeom = GeometryEngine.intersect(basePl, compPl, + SpatialReference.create(4326)); + + } catch (Exception ex) { + noException = 0; + } + assertEquals(noException, 1); + assertTrue(intersectGeom.isEmpty()); + } + + @Test + public void testPointAndPolygon3() { + Point basePl = new Point(-121, 20); + Polygon compPl = new Polygon(); + compPl.startPath(new Point(-116, 20)); + compPl.lineTo(new Point(-131, 10)); + compPl.lineTo(new Point(-121, 50)); + + int noException = 1; // no exception + Geometry intersectGeom = null; + try { + intersectGeom = GeometryEngine.intersect(basePl, compPl, + SpatialReference.create(4326)); + + } catch (Exception ex) { + noException = 0; + } + assertEquals(noException, 1); + assertNotNull(intersectGeom); + assertTrue(intersectGeom.getType() == Type.Point); + + Point ip = (Point) intersectGeom; + assertEquals(ip.getX(), -121, 0.1E7); + assertEquals(ip.getY(), 20, 0.1E7); + } + + @Test + public void testPointAndPoint1() { + Point basePl = new Point(-116, 20); + Point compPl = new Point(-116, 20); + + int noException = 1; // no exception + Geometry intersectGeom = null; + try { + intersectGeom = GeometryEngine.intersect(basePl, compPl, + SpatialReference.create(4326)); + } catch (Exception ex) { + noException = 0; + } + assertEquals(noException, 1); + assertNotNull(intersectGeom); + assertTrue(intersectGeom.getType() == Type.Point); + + Point ip = (Point) intersectGeom; + assertEquals(ip.getX(), -116, 0.1E7); + assertEquals(ip.getY(), 20, 0.1E7); + } + + @Test + public void testPointAndPoint2() { + Point basePl = new Point(-115, 20); + Point compPl = new Point(-116, 20); + + int noException = 1; // no exception + Geometry intersectGeom = null; + try { + intersectGeom = GeometryEngine.intersect(basePl, compPl, + SpatialReference.create(4326)); + } catch (Exception ex) { + noException = 0; + } + assertEquals(noException, 1); + assertTrue(intersectGeom.isEmpty()); + } + + @Test + public void testPointAndMultiPoint1() { + Point basePl = new Point(-116, 20); + MultiPoint compPl = new MultiPoint(); + compPl.add(new Point(-116, 20)); + compPl.add(new Point(-118, 21)); + + int noException = 1; // no exception + Geometry intersectGeom = null; + try { + intersectGeom = GeometryEngine.intersect(basePl, compPl, + SpatialReference.create(4326)); + } catch (Exception ex) { + noException = 0; + } + assertEquals(noException, 1); + assertNotNull(intersectGeom); + assertTrue(intersectGeom.getType() == Type.Point); + + Point ip = (Point) intersectGeom; + assertEquals(ip.getX(), -116, 0.1E7); + assertEquals(ip.getY(), 20, 0.1E7); + } + + @Test + public void testPointAndMultiPoint2() { + Point basePl = new Point(-115, 20); + + MultiPoint compPl = new MultiPoint(); + compPl.add(new Point(-116, 20)); + compPl.add(new Point(-117, 21)); + compPl.add(new Point(-118, 20)); + compPl.add(new Point(-119, 21)); + + int noException = 1; // no exception + Geometry intersectGeom = null; + + try { + intersectGeom = GeometryEngine.intersect(basePl, compPl, + SpatialReference.create(4326)); + } catch (Exception ex) { + noException = 0; + } + assertEquals(noException, 1); + assertTrue(intersectGeom.isEmpty()); + } + + @Test + public void testMultiPointAndMultiPoint1() { + MultiPoint basePl = new MultiPoint(); + basePl.add(new Point(-116, 20)); + basePl.add(new Point(-117, 20)); + + MultiPoint compPl = new MultiPoint(); + compPl.add(new Point(-116, 20)); + compPl.add(new Point(-118, 21)); + + int noException = 1; // no exception + Geometry intersectGeom = null; + try { + intersectGeom = GeometryEngine.intersect(basePl, compPl, + SpatialReference.create(4326)); + } catch (Exception ex) { + noException = 0; + } + assertEquals(noException, 1); + assertNotNull(intersectGeom); + assertTrue(intersectGeom.getType() == Type.MultiPoint); + + MultiPoint imp = (MultiPoint) intersectGeom; + assertEquals(imp.getCoordinates2D().length, 1); + assertEquals(imp.getCoordinates2D()[0].x, -116, 0.0); + assertEquals(imp.getCoordinates2D()[0].y, 20, 0.0); + } + + @Test + public void testMultiPointAndMultiPoint2() { + MultiPoint basePl = new MultiPoint(); + basePl.add(new Point(-116, 20)); + basePl.add(new Point(-118, 21)); + + MultiPoint compPl = new MultiPoint(); + compPl.add(new Point(-116, 20)); + compPl.add(new Point(-118, 21)); + + int noException = 1; // no exception + Geometry intersectGeom = null; + try { + intersectGeom = GeometryEngine.intersect(basePl, compPl, + SpatialReference.create(4326)); + } catch (Exception ex) { + noException = 0; + } + + assertEquals(noException, 1); + assertNotNull(intersectGeom); + assertTrue(intersectGeom.getType() == Type.MultiPoint); + + MultiPoint ip = (MultiPoint) intersectGeom; + assertEquals(ip.getPoint(0).getX(), -116, 0.1E7); + assertEquals(ip.getPoint(0).getY(), 20, 0.1E7); + assertEquals(ip.getPoint(0).getX(), -118, 0.1E7); + assertEquals(ip.getPoint(0).getY(), 21, 0.1E7); + } + + @Test + public void testMultiPointAndMultiPoint3() { + MultiPoint basePl = new MultiPoint(); + basePl.add(new Point(-116, 21)); + basePl.add(new Point(-117, 20)); + + MultiPoint compPl = new MultiPoint(); + compPl.add(new Point(-116, 20)); + compPl.add(new Point(-117, 21)); + compPl.add(new Point(-118, 20)); + compPl.add(new Point(-119, 21)); + + int noException = 1; // no exception + Geometry intersectGeom = null; + try { + intersectGeom = GeometryEngine.intersect(basePl, compPl, + SpatialReference.create(4326)); + } catch (Exception ex) { + noException = 0; + } + assertEquals(noException, 1); + assertTrue(intersectGeom.isEmpty()); + } } diff --git a/src/test/java/com/esri/core/geometry/TestIntersection.java b/src/test/java/com/esri/core/geometry/TestIntersection.java index 3d79354e..b9547383 100644 --- a/src/test/java/com/esri/core/geometry/TestIntersection.java +++ b/src/test/java/com/esri/core/geometry/TestIntersection.java @@ -30,1042 +30,1037 @@ //import java.util.Random; public class TestIntersection extends TestCase { - static OperatorFactoryLocal projEnv = OperatorFactoryLocal.getInstance(); - static int codeIn = 26910;// NAD_1983_UTM_Zone_10N : GEOGRAPHIC 6269 - static int codeOut = 32610;// WGS_1984_UTM_Zone_10N; : GEOGRAPHIC 4326 - static SpatialReference inputSR; - static SpatialReference outputSR; - - @Override - protected void setUp() throws Exception { - super.setUp(); - projEnv = OperatorFactoryLocal.getInstance(); - inputSR = SpatialReference.create(codeIn); - outputSR = SpatialReference.create(codeOut); - } - - @Override - protected void tearDown() throws Exception { - super.tearDown(); - } - - @Test - public void testIntersection1() { - // OperatorFactoryLocal projEnv = OperatorFactoryLocal.getInstance(); - // int codeIn = 26910;//NAD_1983_UTM_Zone_10N : GEOGRAPHIC 6269 - // int codeOut = 32610;//WGS_1984_UTM_Zone_10N; : GEOGRAPHIC 4326 - // int codeIn = SpatialReference::PCS_WGS_1984_UTM_10N; - // int codeOut = SpatialReference::PCS_WORLD_MOLLWEIDE; - // int codeOut = 102100; - inputSR = SpatialReference.create(codeIn); - assertTrue(inputSR.getID() == codeIn); - outputSR = SpatialReference.create(codeOut); - assertTrue(outputSR.getID() == codeOut); - - OperatorIntersection operatorIntersection = (OperatorIntersection) projEnv - .getOperator(Operator.Type.Intersection); - - Polygon poly1 = new Polygon(); - Envelope env1 = new Envelope(855277, 3892059, 855277 + 100, - 3892059 + 100); - // Envelope env1 = new Envelope(-1000000, -1000000, 1000000, 1000000); - // env1.SetCoords(-8552770, -3892059, 855277 + 100, 3892059 + 100); - poly1.addEnvelope(env1, false); - - Polygon poly2 = new Polygon(); - Envelope env2 = new Envelope(855277 + 1, 3892059 + 1, 855277 + 30, - 3892059 + 20); - poly2.addEnvelope(env2, false); - - GeometryCursor cursor1 = new SimpleGeometryCursor(poly1); - GeometryCursor cursor2 = new SimpleGeometryCursor(poly2); - - GeometryCursor outputGeoms = operatorIntersection.execute(cursor1, - cursor2, inputSR, null); - Geometry geomr = outputGeoms.next(); - assertNotNull(geomr); - assertTrue(geomr.getType() == Geometry.Type.Polygon); - Polygon geom = (Polygon) geomr; - assertTrue(geom.getPointCount() == 4); - Point[] points = TestCommonMethods.pointsFromMultiPath(geom);// SPtrOfArrayOf(Point2D) - // pts = - // geom.get.getCoordinates2D(); - assertTrue(Math.abs(points[0].getX() - 855278.000000000) < 1e-7); - assertTrue(Math.abs(points[0].getY() - 3892060.0000000000) < 1e-7); - assertTrue(Math.abs(points[2].getX() - 855307.00000000093) < 1e-7); - assertTrue(Math.abs(points[2].getY() - 3892079.0000000000) < 1e-7); - - geomr = operatorIntersection.execute(poly1, poly2, inputSR, null); - assertNotNull(geomr); - assertTrue(geomr.getType() == Geometry.Type.Polygon); - Polygon outputGeom = (Polygon) geomr; - - assertTrue(outputGeom.getPointCount() == 4); - points = TestCommonMethods.pointsFromMultiPath(outputGeom); - assertTrue(Math.abs(points[0].getX() - 855278.000000000) < 1e-7); - assertTrue(Math.abs(points[0].getY() - 3892060.0000000000) < 1e-7); - assertTrue(Math.abs(points[2].getX() - 855307.00000000093) < 1e-7); - assertTrue(Math.abs(points[2].getY() - 3892079.0000000000) < 1e-7); - } - - @Test - public void testSelfIntersecting() {// Test that we do not fail if there is - // self-intersection - // OperatorFactoryLocal projEnv = - // OperatorFactoryLocal.getInstance(); - OperatorIntersection operatorIntersection = (OperatorIntersection) projEnv - .getOperator(Operator.Type.Intersection); - SpatialReference sr = SpatialReference.create(4326); - Polygon poly1 = new Polygon(); - Envelope2D env1 = new Envelope2D(); - env1.setCoords(0, 0, 20, 30); - poly1.addEnvelope(env1, false); - Polygon poly2 = new Polygon(); - poly2.startPath(0, 0); - poly2.lineTo(10, 10); - poly2.lineTo(0, 10); - poly2.lineTo(10, 0); - @SuppressWarnings("unused") - Polygon res = (Polygon) (operatorIntersection.execute(poly1, poly2, sr, - null)); - // Operator_equals equals = - // (Operator_equals)projEnv.get_operator(Operator::equals); - // assertTrue(equals.execute(res, poly2, sr, NULL) == true); - } - - @Test - public void testMultipoint() { - Polygon poly1 = new Polygon(); - Envelope env1 = new Envelope(855277, 3892059, 855277 + 100, - 3892059 + 100); - - poly1.addEnvelope(env1, false); - MultiPoint multiPoint = new MultiPoint(); - multiPoint.add(855277 + 10, 3892059 + 10); - multiPoint.add(855277, 3892059); - multiPoint.add(855277 + 100, 3892059 + 100); - multiPoint.add(855277 + 100, 3892059 + 101); - multiPoint.add(855277 + 101, 3892059 + 100); - multiPoint.add(855277 + 101, 3892059 + 101); - OperatorIntersection operatorIntersection = (OperatorIntersection) projEnv - .getOperator(Operator.Type.Intersection); - - MultiPoint mpResult = (MultiPoint) operatorIntersection.execute(poly1, - multiPoint, inputSR, null); - assertTrue(mpResult.getPointCount() == 3); - assertTrue(mpResult.getPoint(0).getX() == 855277 + 10 - && mpResult.getPoint(0).getY() == 3892059 + 10); - assertTrue(mpResult.getPoint(1).getX() == 855277 - && mpResult.getPoint(1).getY() == 3892059); - assertTrue(mpResult.getPoint(2).getX() == 855277 + 100 - && mpResult.getPoint(2).getY() == 3892059 + 100); - - // Test intersection of Polygon with Envelope (calls Clip) - Polygon poly = new Polygon(); - poly.startPath(0, 0); - poly.lineTo(10, 10); - poly.lineTo(20, 0); - - env1.setXMin(0); - env1.setXMax(20); - env1.setYMin(5); - env1.setYMax(15); - - Envelope envelope1 = env1; - - Polygon clippedPoly = (Polygon) operatorIntersection.execute(poly, - envelope1, inputSR, null); - double area = clippedPoly.calculateArea2D(); - assertTrue(Math.abs(area - 25) < 0.00001); - - // Geometry res = GeometryEngine.difference(poly, envelope1, inputSR); - Envelope env2 = new Envelope(855277 + 1, 3892059 + 1, 855277 + 30, - 3892059 + 20); - env2.setXMin(5); - env2.setXMax(10); - env2.setYMin(0); - env2.setYMax(20); - - Envelope envelope2 = env2; - - Envelope clippedEnvelope = (Envelope) operatorIntersection.execute( - envelope1, envelope2, inputSR, null); - area = clippedEnvelope.calculateArea2D(); - assertTrue(Math.abs(area - 50) < 0.00001); - } - - @Test - public void testDifferenceOnPolyline() { - Polyline basePl = new Polyline(); - basePl.startPath(-117, 20); - basePl.lineTo(-130, 10); - basePl.lineTo(-120, 50); - - Polyline compPl = new Polyline(); - compPl.startPath(-116, 20); - compPl.lineTo(-131, 10); - compPl.lineTo(-121, 50); - - // OperatorFactoryLocal projEnv = OperatorFactoryLocal.getInstance(); - OperatorDifference op = (OperatorDifference) projEnv - .getOperator(Operator.Type.Difference); - Polyline diffGeom = (Polyline) (op.execute(basePl, compPl, - SpatialReference.create(4326), null)); - int pc = diffGeom.getPointCount(); - assertTrue(pc == 5); - } - - @Test - public void testDifferenceOnPolyline2() { - Polyline basePl = new Polyline(); - basePl.startPath(0, 0); - basePl.lineTo(10, 10); - basePl.lineTo(20, 20); - basePl.lineTo(10, 0); - basePl.lineTo(20, 10); - - Polyline compPl = new Polyline(); - compPl.startPath(5, 0); - compPl.lineTo(5, 10); - compPl.lineTo(0, 10); - compPl.lineTo(7.5, 2.5); - - // Operator_factory_local::SaveJSONToTextFileDbg("c:/temp/basePl.txt", - // *basePl, null); - // Operator_factory_local::SaveJSONToTextFileDbg("c:/temp/compPl.txt", - // *compPl, null); - // OperatorFactoryLocal projEnv = OperatorFactoryLocal.getInstance(); - OperatorDifference op = (OperatorDifference) projEnv - .getOperator(Operator.Type.Difference); - Polyline diffGeom = (Polyline) (op.execute(basePl, compPl, - SpatialReference.create(4326), null)); - // Operator_factory_local::SaveJSONToTextFileDbg("c:/temp/diffGeom.txt", - // *diffGeom, null); - int pathc = diffGeom.getPathCount(); - assertTrue(pathc == 1); - int pc = diffGeom.getPointCount(); - assertTrue(pc == 6); - - Polyline resPl = new Polyline(); - resPl.startPath(0, 0); - resPl.lineTo(5, 5); - resPl.lineTo(10, 10); - resPl.lineTo(20, 20); - resPl.lineTo(10, 0); - resPl.lineTo(20, 10); - // Operator_factory_local::SaveJSONToTextFileDbg("c:/temp/resPl.txt", - // *resPl, null); - assertTrue(resPl.equals(diffGeom)); - } - - @Test - public void testDifferencePointPolyline() { - Polyline basePl = new Polyline(); - basePl.startPath(0, 0); - basePl.lineTo(10, 10); - basePl.lineTo(20, 20); - basePl.lineTo(10, 0); - basePl.lineTo(20, 10); - - Point compPl = new Point(5, 5); - - // OperatorFactoryLocal projEnv = OperatorFactoryLocal.getInstance(); - OperatorDifference op = (OperatorDifference) projEnv - .getOperator(Operator.Type.Difference); - Polyline diffGeom = (Polyline) (op.execute(basePl, compPl, - SpatialReference.create(4326), null)); - int pathc = diffGeom.getPathCount(); - assertTrue(pathc == 1); - int pc = diffGeom.getPointCount(); - assertTrue(pc == 5); - - Polyline resPl = new Polyline(); - resPl.startPath(0, 0); - resPl.lineTo(10, 10); - resPl.lineTo(20, 20); - resPl.lineTo(10, 0); - resPl.lineTo(20, 10); - assertTrue(resPl.equals(diffGeom));// no change happens to the original - // polyline - } - - @Test - public void testIntersectionPolylinePolygon() { - { - Polygon polygon = new Polygon(); - polygon.startPath(0, 0); - polygon.lineTo(0, 10); - polygon.lineTo(20, 10); - polygon.lineTo(20, 0); - polygon.addAttribute(VertexDescription.Semantics.Z); - polygon.setAttribute(VertexDescription.Semantics.Z, 0, 0, 3); - polygon.setAttribute(VertexDescription.Semantics.Z, 3, 0, 3); - polygon.interpolateAttributes(0, 0, 3); - Polyline polyline = new Polyline(); - polyline.startPath(0, 10); - polyline.lineTo(5, 5); - polyline.lineTo(6, 4); - polyline.lineTo(7, -1); - polyline.addAttribute(VertexDescription.Semantics.Z); - polyline.setAttribute(VertexDescription.Semantics.Z, 0, 0, 5); - polyline.setAttribute(VertexDescription.Semantics.Z, 3, 0, 5); - polyline.interpolateAttributes(0, 0, 0, 3); - - // OperatorFactoryLocal projEnv = - // OperatorFactoryLocal.getInstance(); - OperatorIntersection operatorIntersection = (OperatorIntersection) projEnv - .getOperator(Operator.Type.Intersection); - Geometry geom = operatorIntersection.execute(polyline, polygon, - null, null); - assertTrue(!geom.isEmpty()); - Polyline poly = (Polyline) (geom); - for (int i = 0; i < poly.getPointCount(); i++) - assertTrue(poly.getAttributeAsDbl( - VertexDescription.Semantics.Z, i, 0) == 5); - - // std::shared_ptr jsonExport = - // (Operator_export_to_JSON>)Operator_factory_local::get_instance().get_operator(Operator::Operator_type::export_to_JSON); - // std::string str = jsonExport.execute(0, geom, null, null); - // OutputDebugStringA(str.c_str()); - // OutputDebugString(L"\n"); - // assertTrue(str=="{\"paths\":[[[0,10],[5,5],[6,4],[6.7999999999999998,4.4408922169635528e-016]]]}"); - } - - { - Polygon polygon = new Polygon(); - polygon.startPath(0, 0); - polygon.lineTo(0, 10); - polygon.lineTo(20, 10); - polygon.lineTo(20, 0); - polygon.addAttribute(VertexDescription.Semantics.Z); - polygon.setAttribute(VertexDescription.Semantics.Z, 0, 0, 3); - polygon.setAttribute(VertexDescription.Semantics.Z, 3, 0, 3); - polygon.interpolateAttributes(0, 0, 3); - Polyline polyline = new Polyline(); - polyline.startPath(0, 10); - polyline.lineTo(20, 0); - polyline.lineTo(5, 5); - polyline.addAttribute(VertexDescription.Semantics.Z); - polyline.setAttribute(VertexDescription.Semantics.Z, 0, 0, 5); - polyline.setAttribute(VertexDescription.Semantics.Z, 1, 0, 5); - polyline.setAttribute(VertexDescription.Semantics.Z, 2, 0, 5); - - // OperatorFactoryLocal projEnv = - // OperatorFactoryLocal.getInstance(); - OperatorIntersection operatorIntersection = (OperatorIntersection) projEnv - .getOperator(Operator.Type.Intersection); - Geometry geom = operatorIntersection.execute(polyline, polygon, - null, null); - assertTrue(!geom.isEmpty()); - Polyline poly = (Polyline) (geom); - for (int i = 0; i < poly.getPointCount(); i++) - assertTrue(poly.getAttributeAsDbl( - VertexDescription.Semantics.Z, i, 0) == 5); - - // Operator_export_to_JSON> jsonExport = - // (Operator_export_to_JSON>)Operator_factory_local::get_instance().get_operator(Operator::Operator_type::export_to_JSON); - // std::string str = jsonExport.execute(0, geom, null, null); - // OutputDebugStringA(str.c_str()); - // OutputDebugString(L"\n"); - // assertTrue(str=="{\"paths\":[[[0,10],[20,0],[5,5]]]}"); - } - - { - Polygon polygon = new Polygon(); - polygon.startPath(0, 0); - polygon.lineTo(0, 10); - polygon.lineTo(20, 10); - polygon.lineTo(20, 0); - polygon.addAttribute(VertexDescription.Semantics.Z); - polygon.setAttribute(VertexDescription.Semantics.Z, 0, 0, 3); - polygon.setAttribute(VertexDescription.Semantics.Z, 3, 0, 3); - polygon.interpolateAttributes(0, 0, 3); - Polyline polyline = new Polyline(); - polyline.startPath(0, 0); - polyline.lineTo(0, 10); - polyline.lineTo(20, 10); - polyline.addAttribute(VertexDescription.Semantics.Z); - polyline.setAttribute(VertexDescription.Semantics.Z, 0, 0, 5); - polyline.setAttribute(VertexDescription.Semantics.Z, 1, 0, 5); - polyline.setAttribute(VertexDescription.Semantics.Z, 2, 0, 5); - - // OperatorFactoryLocal projEnv = - // OperatorFactoryLocal.getInstance(); - OperatorIntersection operatorIntersection = (OperatorIntersection) projEnv - .getOperator(Operator.Type.Intersection); - Geometry geom = operatorIntersection.execute(polyline, polygon, - null, null); - assertTrue(!geom.isEmpty()); - Polyline poly = (Polyline) (geom); - for (int i = 0; i < poly.getPointCount(); i++) - assertTrue(poly.getAttributeAsDbl( - VertexDescription.Semantics.Z, i, 0) == 5); - - // Operator_export_to_JSON> jsonExport = - // (Operator_export_to_JSON>)Operator_factory_local::get_instance().get_operator(Operator::Operator_type::export_to_JSON); - // std::string str = jsonExport.execute(0, geom, null, null); - // OutputDebugStringA(str.c_str()); - // OutputDebugString(L"\n"); - // assertTrue(str=="{\"paths\":[[[0,0],[0,10],[20,10]]]}"); - } - - { - Polygon polygon = new Polygon(); - polygon.startPath(0, 0); - polygon.lineTo(0, 10); - polygon.lineTo(20, 10); - polygon.lineTo(20, 0); - Polyline polyline = new Polyline(); - polyline.startPath(3, -1); - polyline.lineTo(17, 1); - polyline.lineTo(10, 8); - polyline.lineTo(-1, 5); - polyline.addAttribute(VertexDescription.Semantics.Z); - polyline.setAttribute(VertexDescription.Semantics.Z, 0, 0, 5); - polyline.setAttribute(VertexDescription.Semantics.Z, 1, 0, 5); - polyline.setAttribute(VertexDescription.Semantics.Z, 2, 0, 5); - polyline.setAttribute(VertexDescription.Semantics.Z, 3, 0, 5); - - // OperatorFactoryLocal projEnv = - // OperatorFactoryLocal.getInstance(); - OperatorIntersection operatorIntersection = (OperatorIntersection) projEnv - .getOperator(Operator.Type.Intersection); - Geometry geom = operatorIntersection.execute(polyline, polygon, - null, null); - assertTrue(!geom.isEmpty()); - Polyline poly = (Polyline) geom; - for (int i = 0; i < poly.getPointCount(); i++) - assertTrue(poly.getAttributeAsDbl( - VertexDescription.Semantics.Z, i, 0) == 5); - - // Operator_export_to_JSON> jsonExport = - // (Operator_export_to_JSON>)Operator_factory_local::get_instance().get_operator(Operator::Operator_type::export_to_JSON); - // std::string str = jsonExport.execute(0, geom, null, null); - // OutputDebugStringA(str.c_str()); - // OutputDebugString(L"\n"); - // assertTrue(str=="{\"paths\":[[[10,0],[17,1],[10,8],[4.7377092701401439e-024,5.2727272727272734]]]}"); - } - - { - Polygon polygon = new Polygon(); - polygon.startPath(0, 0); - polygon.lineTo(0, 10); - polygon.lineTo(20, 10); - polygon.lineTo(20, 0); - Polyline polyline = new Polyline(); - polyline.startPath(0, 15); - polyline.lineTo(3, -1); - polyline.lineTo(17, 1); - polyline.lineTo(10, 8); - polyline.lineTo(-1, 5); - polyline.addAttribute(VertexDescription.Semantics.Z); - polyline.setAttribute(VertexDescription.Semantics.Z, 0, 0, 5); - polyline.setAttribute(VertexDescription.Semantics.Z, 4, 0, 5); - polyline.interpolateAttributes(0, 0, 0, 4); - OperatorIntersection operatorIntersection = (OperatorIntersection) projEnv - .getOperator(Operator.Type.Intersection); - Geometry geom = operatorIntersection.execute(polyline, polygon, - null, null); - assertTrue(!geom.isEmpty()); - Polyline poly = (Polyline) geom; - for (int i = 0; i < poly.getPointCount(); i++) - assertTrue(poly.getAttributeAsDbl( - VertexDescription.Semantics.Z, i, 0) == 5); - - // Operator_export_to_JSON> jsonExport = - // (Operator_export_to_JSON>)Operator_factory_local::get_instance().get_operator(Operator::Operator_type::export_to_JSON); - // std::string str = jsonExport.execute(0, geom, null, null); - // OutputDebugStringA(str.c_str()); - // OutputDebugString(L"\n"); - // assertTrue(str=="{\"paths\":[[[0.9375,10],[2.8125,9.476226333847234e-024]],[[10,0],[17,1],[10,8],[4.7377092701401439e-024,5.2727272727272734]]]}"); - } - - { - Polygon polygon = new Polygon(); - polygon.startPath(0, 0); - polygon.lineTo(0, 10); - polygon.lineTo(20, 10); - polygon.lineTo(20, 0); - Polyline polyline = new Polyline(); - polyline.startPath(5, 5); - polyline.lineTo(1, 1); - polyline.lineTo(-1, 1); - polyline.lineTo(-1, 10); - polyline.lineTo(0, 10); - polyline.lineTo(6, 6); - polyline.addAttribute(VertexDescription.Semantics.Z); - polyline.setAttribute(VertexDescription.Semantics.Z, 0, 0, 5); - polyline.setAttribute(VertexDescription.Semantics.Z, 5, 0, 5); - polyline.interpolateAttributes(0, 0, 0, 5); - - // OperatorFactoryLocal projEnv = - // OperatorFactoryLocal.getInstance(); - OperatorIntersection operatorIntersection = (OperatorIntersection) projEnv - .getOperator(Operator.Type.Intersection); - Geometry geom = operatorIntersection.execute(polyline, polygon, - null, null); - assertTrue(!geom.isEmpty()); - Polyline poly = (Polyline) geom; - for (int i = 0; i < poly.getPointCount(); i++) - assertTrue(poly.getAttributeAsDbl( - VertexDescription.Semantics.Z, i, 0) == 5); - - // Operator_export_to_JSON> jsonExport = - // (Operator_export_to_JSON>)Operator_factory_local::get_instance().get_operator(Operator::Operator_type::export_to_JSON); - // std::string str = jsonExport.execute(0, geom, null, null); - // OutputDebugStringA(str.c_str()); - // OutputDebugString(L"\n"); - // assertTrue(str=="{\"paths\":[[[5,5],[1,1],[4.738113166923617e-023,1]],[[0,10],[6,6]]]}"); - } - - { - Polygon polygon = new Polygon(); - polygon.startPath(0, 0); - polygon.lineTo(0, 10); - polygon.lineTo(20, 10); - polygon.lineTo(20, 0); - Polyline polyline = new Polyline(); - polyline.startPath(0, 15); - polyline.lineTo(3, -1); - polyline.lineTo(17, 1); - polyline.lineTo(10, 8); - polyline.lineTo(-1, 5); - polyline.startPath(19, 15); - polyline.lineTo(29, 9); - polyline.startPath(19, 15); - polyline.lineTo(29, 9); - polyline.startPath(5, 5); - polyline.lineTo(1, 1); - polyline.lineTo(-1, 1); - polyline.lineTo(-1, 10); - polyline.lineTo(0, 10); - polyline.lineTo(6, 6); - polyline.addAttribute(VertexDescription.Semantics.Z); - polyline.setAttribute(VertexDescription.Semantics.Z, 0, 0, 5); - polyline.setAttribute(VertexDescription.Semantics.Z, 14, 0, 5); - polyline.interpolateAttributes(0, 0, 3, 5); - - // OperatorFactoryLocal projEnv = - // OperatorFactoryLocal.getInstance(); - OperatorIntersection operatorIntersection = (OperatorIntersection) projEnv - .getOperator(Operator.Type.Intersection); - Geometry geom = operatorIntersection.execute(polyline, polygon, - null, null); - assertTrue(!geom.isEmpty()); - Polyline poly = (Polyline) geom; - for (int i = 0; i < poly.getPointCount(); i++) - assertTrue(poly.getAttributeAsDbl( - VertexDescription.Semantics.Z, i, 0) == 5); - - // Operator_export_to_JSON> jsonExport = - // (Operator_export_to_JSON>)Operator_factory_local::get_instance().get_operator(Operator::Operator_type::export_to_JSON); - // std::string str = jsonExport.execute(0, geom, null, null); - // OutputDebugStringA(str.c_str()); - // OutputDebugString(L"\n"); - // assertTrue(str=="{\"paths\":[[[0.9375,10],[2.8125,9.476226333847234e-024]],[[10,0],[17,1],[10,8],[4.7377092701401439e-024,5.2727272727272734]],[[5,5],[1,1],[4.738113166923617e-023,1]],[[0,10],[6,6]]]}"); - } - } - - @Test - public void testMultiPointPolyline() { - Polyline polyline = new Polyline(); - polyline.startPath(0, 0); - polyline.lineTo(0, 10); - polyline.lineTo(20, 10); - polyline.lineTo(20, 0); - MultiPoint mp = new MultiPoint(); - mp.add(0, 10, 7); - mp.add(0, 5, 7); - mp.add(1, 5, 7); - // OperatorFactoryLocal projEnv = OperatorFactoryLocal.getInstance(); - OperatorIntersection operatorIntersection = (OperatorIntersection) projEnv - .getOperator(Operator.Type.Intersection); - OperatorDifference operatorDifference = (OperatorDifference) projEnv - .getOperator(Operator.Type.Difference); - - {// intersect - Geometry geom = operatorIntersection.execute(polyline, mp, null, - null); - MultiPoint res = (MultiPoint) geom; - assertTrue(res.getPointCount() == 2); - Point2D pt_1 = res.getXY(0); - Point2D pt_2 = res.getXY(1); - assertTrue(Point2D.distance(pt_1, new Point2D(0, 10)) < 1e-10 - && Point2D.distance(pt_2, new Point2D(0, 5)) < 1e-10 - || Point2D.distance(pt_2, new Point2D(0, 10)) < 1e-10 - && Point2D.distance(pt_1, new Point2D(0, 5)) < 1e-10); - - assertTrue(res.getAttributeAsDbl(VertexDescription.Semantics.Z, 0, - 0) == 7); - assertTrue(res.getAttributeAsDbl(VertexDescription.Semantics.Z, 1, - 0) == 7); - } - - {// difference - Geometry geom = operatorDifference - .execute(polyline, mp, null, null); - // assertTrue(geom.getGeometryType() == - // Geometry.GeometryType.Polyline); - Polyline res = (Polyline) geom; - assertTrue(res.getPointCount() == 4); - } - {// difference - Geometry geom = operatorDifference - .execute(mp, polyline, null, null); - // assertTrue(geom.getType() == Geometry.GeometryType.MultiPoint); - MultiPoint res = (MultiPoint) geom; - assertTrue(res.getPointCount() == 1); - Point2D pt_1 = res.getXY(0); - assertTrue(Point2D.distance(pt_1, new Point2D(1, 5)) < 1e-10); - } - {// difference (subtract empty) - Geometry geom = operatorDifference.execute(mp, new Polyline(), - null, null); - // assertTrue(geom.getGeometryType() == - // Geometry.GeometryType.MultiPoint); - MultiPoint res = (MultiPoint) geom; - assertTrue(res.getPointCount() == 3); - Point2D pt_1 = res.getXY(0); - assertTrue(Point2D.distance(pt_1, new Point2D(0, 10)) < 1e-10); - } - - } - - @Test - public void testPointPolyline() { - Polyline polyline = new Polyline(); - polyline.startPath(0, 0); - polyline.lineTo(0, 10); - polyline.lineTo(20, 10); - polyline.lineTo(20, 0); - Point p_1 = new Point(0, 5, 7); - Point p_2 = new Point(0, 10, 7); - Point p3 = new Point(1, 5, 7); - // OperatorFactoryLocal projEnv = OperatorFactoryLocal.getInstance(); - OperatorIntersection operatorIntersection = (OperatorIntersection) projEnv - .getOperator(Operator.Type.Intersection); - OperatorDifference operatorDiff = (OperatorDifference) projEnv - .getOperator(Operator.Type.Difference); - OperatorUnion operatorUnion = (OperatorUnion) projEnv - .getOperator(Operator.Type.Union); - OperatorSymmetricDifference operatorSymDiff = (OperatorSymmetricDifference) projEnv - .getOperator(Operator.Type.SymmetricDifference); - - {// intersect case1 - Geometry geom = operatorIntersection.execute(polyline, p_1, null, - null); - // assertTrue(geom.getType() == Geometry::enum_point); - Point res = (Point) geom; - Point2D pt_1 = res.getXY(); - assertTrue(Point2D.distance(pt_1, new Point2D(0, 5)) < 1e-10); - assertTrue(res.getAttributeAsDbl(VertexDescription.Semantics.Z, 0) == 7); - } - {// intersect case2 - Geometry geom = operatorIntersection.execute(polyline, p_2, null, - null); - // assertTrue(geom.getType() == Geometry::enum_point); - Point res = (Point) geom; - Point2D pt_1 = res.getXY(); - assertTrue(Point2D.distance(pt_1, new Point2D(0, 10)) < 1e-10); - assertTrue(res.getAttributeAsDbl(VertexDescription.Semantics.Z, 0) == 7); - } - {// intersect case3 - Geometry geom = operatorIntersection.execute(polyline, p3, null, - null); - // assertTrue(geom.getType() == Geometry::enum_point); - assertTrue(geom.isEmpty()); - assertTrue(geom.hasAttribute(VertexDescription.Semantics.Z)); - } - - {// difference case1 - Geometry geom = operatorDiff.execute(polyline, p_1, null, null); - // assertTrue(geom.getType() == Geometry.GeometryType.Polyline); - Polyline res = (Polyline) geom; - assertTrue(res.getPointCount() == 4); - } - {// difference case2 - Geometry geom = operatorDiff.execute(p_1, polyline, null, null); - // assertTrue(geom.getType() == Geometry::enum_point); - Point res = (Point) geom; - assertTrue(res.isEmpty()); - } - {// difference case3 - Geometry geom = operatorDiff.execute(p_2, polyline, null, null); - // assertTrue(geom.getType() == Geometry::enum_point); - Point res = (Point) geom; - assertTrue(res.isEmpty()); - } - {// difference case4 - Geometry geom = operatorDiff.execute(p3, polyline, null, null); - // assertTrue(geom.getType() == Geometry::enum_point); - Point res = (Point) geom; - Point2D pt_1 = res.getXY(); - assertTrue(Point2D.distance(pt_1, new Point2D(1, 5)) < 1e-10); - } - - {// union case1 - Geometry geom = operatorUnion.execute(p_1, polyline, null, null); - // assertTrue(geom.getType() == Geometry.GeometryType.Polyline); - Polyline res = (Polyline) geom; - assertTrue(!res.isEmpty()); - } - {// union case2 - Geometry geom = operatorUnion.execute(polyline, p_1, null, null); - // assertTrue(geom.getType() == Geometry.GeometryType.Polyline); - Polyline res = (Polyline) geom; - assertTrue(!res.isEmpty()); - } - - {// symmetric difference case1 - Geometry geom = operatorSymDiff.execute(polyline, p_1, null, null); - assertTrue(geom.getType().value() == Geometry.GeometryType.Polyline); - Polyline res = (Polyline) (geom); - assertTrue(!res.isEmpty()); - } - {// symmetric difference case2 - Geometry geom = operatorSymDiff.execute(p_1, polyline, null, null); - assertTrue(geom.getType().value() == Geometry.GeometryType.Polyline); - Polyline res = (Polyline) (geom); - assertTrue(!res.isEmpty()); - } - } - - @Test - public void testPolylinePolylineIntersectionExtended() { - {// crossing intersection - Polyline basePl = new Polyline(); - basePl.startPath(0, 10); - basePl.lineTo(100, 10); - - Polyline compPl = new Polyline(); - compPl.startPath(50, 0); - compPl.lineTo(50, 100); - - OperatorIntersection op = (OperatorIntersection) projEnv - .getOperator(Operator.Type.Intersection); - GeometryCursor result_cursor = op.execute(new SimpleGeometryCursor( - basePl), new SimpleGeometryCursor(compPl), SpatialReference - .create(4326), null, 3); - - // dimension is 3, means it has to return a point and a polyline - Geometry geom1 = result_cursor.next(); - assertTrue(geom1 != null); - assertTrue(geom1.getDimension() == 0); - assertTrue(geom1.getType().value() == Geometry.GeometryType.MultiPoint); - assertTrue(((MultiPoint) geom1).getPointCount() == 1); - - Geometry geom2 = result_cursor.next(); - assertTrue(geom2 != null); - assertTrue(geom2.getDimension() == 1); - assertTrue(geom2.getType().value() == Geometry.GeometryType.Polyline); - assertTrue(((Polyline) geom2).getPointCount() == 0); - - Geometry geom3 = result_cursor.next(); - assertTrue(geom3 == null); - } - - {// crossing + overlapping intersection - Polyline basePl = new Polyline(); - basePl.startPath(0, 10); - basePl.lineTo(100, 10); - - Polyline compPl = new Polyline(); - compPl.startPath(50, 0); - compPl.lineTo(50, 100); - compPl.lineTo(70, 10); - compPl.lineTo(100, 10); - - OperatorIntersection op = (OperatorIntersection) projEnv - .getOperator(Operator.Type.Intersection); - GeometryCursor result_cursor = op.execute(new SimpleGeometryCursor( - basePl), new SimpleGeometryCursor(compPl), SpatialReference - .create(4326), null, 3); - - // dimension is 3, means it has to return a point and a polyline - Geometry geom1 = result_cursor.next(); - assertTrue(geom1 != null); - assertTrue(geom1.getDimension() == 0); - assertTrue(geom1.getType().value() == Geometry.GeometryType.MultiPoint); - assertTrue(((MultiPoint) geom1).getPointCount() == 1); - - Geometry geom2 = result_cursor.next(); - assertTrue(geom2 != null); - assertTrue(geom2.getDimension() == 1); - assertTrue(geom2.getType().value() == Geometry.GeometryType.Polyline); - assertTrue(((Polyline) geom2).getPathCount() == 1); - assertTrue(((Polyline) geom2).getPointCount() == 2); - - Geometry geom3 = result_cursor.next(); - assertTrue(geom3 == null); - } - } - - @Test - public void testPolygonPolygonIntersectionExtended() { - {// crossing intersection - Polygon basePl = new Polygon(); - basePl.startPath(0, 0); - basePl.lineTo(100, 0); - basePl.lineTo(100, 100); - basePl.lineTo(0, 100); - - Polygon compPl = new Polygon(); - compPl.startPath(100, 100); - compPl.lineTo(200, 100); - compPl.lineTo(200, 200); - compPl.lineTo(100, 200); - - OperatorIntersection op = (OperatorIntersection) projEnv - .getOperator(Operator.Type.Intersection); - GeometryCursor result_cursor = op.execute(new SimpleGeometryCursor( - basePl), new SimpleGeometryCursor(compPl), SpatialReference - .create(4326), null, 7); - - Geometry geom1 = result_cursor.next(); - assertTrue(geom1 != null); - assertTrue(geom1.getDimension() == 0); - assertTrue(geom1.getType().value() == Geometry.GeometryType.MultiPoint); - assertTrue(((MultiPoint) geom1).getPointCount() == 1); - - Geometry geom2 = result_cursor.next(); - assertTrue(geom2 != null); - assertTrue(geom2.getDimension() == 1); - assertTrue(geom2.getType().value() == Geometry.GeometryType.Polyline); - assertTrue(((Polyline) geom2).getPointCount() == 0); - - Geometry geom3 = result_cursor.next(); - assertTrue(geom3 != null); - assertTrue(geom3.getDimension() == 2); - assertTrue(geom3.getType().value() == Geometry.GeometryType.Polygon); - assertTrue(((Polygon) geom3).getPointCount() == 0); - - - - - - - - } - - {// crossing + overlapping intersection - Polygon basePl = new Polygon(); - basePl.startPath(0, 0); - basePl.lineTo(100, 0); - basePl.lineTo(100, 100); - basePl.lineTo(0, 100); - - Polygon compPl = new Polygon(); - compPl.startPath(100, 100); - compPl.lineTo(200, 100); - compPl.lineTo(200, 200); - compPl.lineTo(100, 200); - - compPl.startPath(100, 20); - compPl.lineTo(200, 20); - compPl.lineTo(200, 40); - compPl.lineTo(100, 40); - - compPl.startPath(-10, -10); - compPl.lineTo(-10, 10); - compPl.lineTo(10, 10); - compPl.lineTo(10, -10); - - OperatorIntersection op = (OperatorIntersection) projEnv - .getOperator(Operator.Type.Intersection); - GeometryCursor result_cursor = op.execute(new SimpleGeometryCursor( - basePl), new SimpleGeometryCursor(compPl), SpatialReference - .create(4326), null, 7); - - // dimension is 3, means it has to return a point and a polyline - - Geometry geom1 = result_cursor.next(); - assertTrue(geom1 != null); - assertEquals(geom1.getDimension(), 0); - assertTrue(geom1.getType().value() == Geometry.GeometryType.MultiPoint); - assertTrue(((MultiPoint) geom1).getPointCount() == 1); - - Geometry geom2 = result_cursor.next(); - assertTrue(geom2 != null); - assertTrue(geom2.getDimension() == 1); - assertTrue(geom2.getType().value() == Geometry.GeometryType.Polyline); - assertTrue(((Polyline) geom2).getPathCount() == 1); - assertTrue(((Polyline) geom2).getPointCount() == 2); - - Geometry geom3 = result_cursor.next(); - assertTrue(geom3 != null); - assertTrue(geom3.getDimension() == 2); - assertTrue(geom3.getType().value() == Geometry.GeometryType.Polygon); - assertTrue(((Polygon) geom3).getPathCount() == 1); - assertTrue(((Polygon) geom3).getPointCount() == 4); - - Geometry geom4 = result_cursor.next(); - assertTrue(geom4 == null); - } - } - - @Test - public void testFromProjection() { - MultiPoint multiPointInitial = new MultiPoint(); - multiPointInitial.add(-20037508.342789244, 3360107.7777777780); - multiPointInitial.add(-18924313.434856508, 3360107.7777777780); - multiPointInitial.add(-18924313.434856508, -3360107.7777777780); - multiPointInitial.add(-20037508.342789244, -3360107.7777777780); - Geometry geom1 = ((MultiPoint) multiPointInitial); - - SpatialReference sr = SpatialReference.create(102100); - - Envelope2D env = new Envelope2D(); - env.setCoords(/* xmin */-20037508.342788246, /* ymin */ - -30240971.958386172, /* xmax */20037508.342788246, /* ymax */ - 30240971.958386205); - // /*xmin*/ -20037508.342788246 - // /*ymin*/ -30240971.958386172 - // /*xmax*/ 20037508.342788246 - // /*ymax*/ 30240971.958386205 - - Polygon poly = new Polygon(); - poly.startPath(env.xmin, env.ymin); - poly.lineTo(env.xmin, env.ymax); - poly.lineTo(env.xmax, env.ymax); - poly.lineTo(env.xmax, env.ymin); - - Geometry geom2 = new Envelope(env); - // Geometry geom2 = poly; - - OperatorIntersection operatorIntersection = (OperatorIntersection) OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Intersection); - - MultiPoint multiPointOut = (MultiPoint) (operatorIntersection.execute( - geom1, geom2, sr, null)); - - assertTrue(multiPointOut.getCoordinates2D().length == 2); - assertTrue(multiPointOut.getCoordinates2D()[0].x == -18924313.434856508); - assertTrue(multiPointOut.getCoordinates2D()[0].y == 3360107.7777777780); - assertTrue(multiPointOut.getCoordinates2D()[1].x == -18924313.434856508); - assertTrue(multiPointOut.getCoordinates2D()[1].y == -3360107.7777777780); - } - - @Test - public void testIssue258128() { - Polygon poly1 = new Polygon(); - poly1.startPath(0, 0); - poly1.lineTo(0, 10); - poly1.lineTo(10, 10); - poly1.lineTo(10, 0); - - Polygon poly2 = new Polygon(); - poly2.startPath(10.5, 4); - poly2.lineTo(10.5, 8); - poly2.lineTo(14, 10); - - try { - GeometryCursor result_cursor = OperatorIntersection.local().execute(new SimpleGeometryCursor( - poly1), new SimpleGeometryCursor(poly2), SpatialReference - .create(4326), null, 1); - while (result_cursor.next() != null) { - - } - } catch (Exception e) { - assertTrue(false); - } - } - - @Test - public void testUnionTickTock() { - Polygon poly1 = new Polygon(); - poly1.startPath(0, 0); - poly1.lineTo(0, 10); - poly1.lineTo(10, 10); - poly1.lineTo(10, 0); - - Polygon poly2 = new Polygon(); - poly2.startPath(10.5, 4); - poly2.lineTo(10.5, 8); - poly2.lineTo(14, 10); - - Transformation2D trans = new Transformation2D(); - - Polygon poly3 = (Polygon) poly1.copy(); - trans.setShift(2, 3); - poly3.applyTransformation(trans); - - Polygon poly4 = (Polygon) poly1.copy(); - trans.setShift(-2, -3); - poly4.applyTransformation(trans); - - // Create - ListeningGeometryCursor gc = new ListeningGeometryCursor(); - GeometryCursor ticktock = OperatorUnion.local().execute(gc, null, null); - - // Use tick-tock to push a geometry and do a piece of work. - gc.tick(poly1); - ticktock.tock(); - gc.tick(poly2); - gc.tick(poly3);// skiped one tock just for testing. - ticktock.tock(); - gc.tick(poly4); - ticktock.tock(); - // Get the result - Geometry result = ticktock.next(); - - // Use ListeningGeometryCursor to put all geometries in. - ListeningGeometryCursor gc2 = new ListeningGeometryCursor(); - gc2.tick(poly1); - gc2.tick(poly2); - gc2.tick(poly3); - gc2.tick(poly4); - - GeometryCursor res = OperatorUnion.local().execute(gc2, null, null); - // Calling next will process all geometries at once. - Geometry result2 = res.next(); - assertTrue(result.equals(result2)); - } - - @Test - public void testIntersectionIssueLinePoly1() { - String wkt1 = new String("polygon((0 0, 10 0, 10 10, 0 10, 0 0))"); - String wkt2 = new String("linestring(9 5, 10 5, 9 4, 8 3)"); - Geometry g1 = OperatorImportFromWkt.local().execute(0, Geometry.Type.Unknown, wkt1, null); - Geometry g2 = OperatorImportFromWkt.local().execute(0, Geometry.Type.Unknown, wkt2, null); - Geometry res = OperatorIntersection.local().execute(g1, g2, null, null); - assertTrue(((Polyline) res).getPathCount() == 1); - assertTrue(((Polyline) res).getPointCount() == 4); - } - - @Test - public void testSharedEdgeIntersection_13() { - String s1 = "{\"rings\":[[[0.099604024000029767,0.2107958250000479],[0.14626826900007472,0.2107958250000479],[0.14626826900007472,0.18285316400005058],[0.099604024000029767,0.18285316400005058],[0.099604024000029767,0.2107958250000479]]]}"; - String s2 = "{\"paths\":[[[0.095692051000071388,0.15910190100004229],[0.10324853600002371,0.18285316400004228],[0.12359292700006108,0.18285316400004228],[0.12782611200003657,0.1705583920000322],[0.13537063000007138,0.18285316400004228]]]}"; - - Polygon polygon = (Polygon) TestCommonMethods.fromJson(s1).getGeometry(); - Polyline polyline = (Polyline) TestCommonMethods.fromJson(s2).getGeometry(); - SpatialReference sr = SpatialReference.create(4326); - - Geometry g = OperatorIntersection.local().execute(polygon, polyline, sr, null); - assertTrue(!g.isEmpty()); - } - - @Test - public void testIntersectionIssue2() { - String s1 = "{\"rings\":[[[-97.174860352323378,48.717174479818425],[-97.020624513410553,58.210155436624177],[-94.087641114245969,58.210155436624177],[-94.087641114245969,48.639781902013226],[-97.174860352323378,48.717174479818425]]]}"; - String s2 = "{\"rings\":[[[-94.08764111399995,52.68342763000004],[-94.08764111399995,56.835188018000053],[-90.285921520999977,62.345706350000057],[-94.08764111399995,52.68342763000004]]]}"; - - Polygon polygon1 = (Polygon) TestCommonMethods.fromJson(s1).getGeometry(); - Polygon polygon2 = (Polygon) TestCommonMethods.fromJson(s2).getGeometry(); - SpatialReference sr = SpatialReference.create(4326); - - GeometryCursor res = OperatorIntersection.local().execute(new SimpleGeometryCursor(polygon1), new SimpleGeometryCursor(polygon2), sr, null, 2); - Geometry g = res.next(); - assertTrue(g != null); - assertTrue(!g.isEmpty()); - Geometry g2 = res.next(); - assertTrue(g2 == null); - - String ss = "{\"paths\":[[[-94.08764111412296,52.68342763000004],[-94.08764111410767,56.83518801800005]]]}"; - Polyline polyline = (Polyline) TestCommonMethods.fromJson(ss).getGeometry(); - boolean eq = OperatorEquals.local().execute(g, polyline, sr, null); - assertTrue(eq); - } + static OperatorFactoryLocal projEnv = OperatorFactoryLocal.getInstance(); + static int codeIn = 26910;// NAD_1983_UTM_Zone_10N : GEOGRAPHIC 6269 + static int codeOut = 32610;// WGS_1984_UTM_Zone_10N; : GEOGRAPHIC 4326 + static SpatialReference inputSR; + static SpatialReference outputSR; + + @Override + protected void setUp() throws Exception { + super.setUp(); + projEnv = OperatorFactoryLocal.getInstance(); + inputSR = SpatialReference.create(codeIn); + outputSR = SpatialReference.create(codeOut); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + } + + @Test + public void testIntersection1() { + // OperatorFactoryLocal projEnv = OperatorFactoryLocal.getInstance(); + // int codeIn = 26910;//NAD_1983_UTM_Zone_10N : GEOGRAPHIC 6269 + // int codeOut = 32610;//WGS_1984_UTM_Zone_10N; : GEOGRAPHIC 4326 + // int codeIn = SpatialReference::PCS_WGS_1984_UTM_10N; + // int codeOut = SpatialReference::PCS_WORLD_MOLLWEIDE; + // int codeOut = 102100; + inputSR = SpatialReference.create(codeIn); + assertTrue(inputSR.getID() == codeIn); + outputSR = SpatialReference.create(codeOut); + assertTrue(outputSR.getID() == codeOut); + + OperatorIntersection operatorIntersection = (OperatorIntersection) projEnv + .getOperator(Operator.Type.Intersection); + + Polygon poly1 = new Polygon(); + Envelope env1 = new Envelope(855277, 3892059, 855277 + 100, + 3892059 + 100); + // Envelope env1 = new Envelope(-1000000, -1000000, 1000000, 1000000); + // env1.SetCoords(-8552770, -3892059, 855277 + 100, 3892059 + 100); + poly1.addEnvelope(env1, false); + + Polygon poly2 = new Polygon(); + Envelope env2 = new Envelope(855277 + 1, 3892059 + 1, 855277 + 30, + 3892059 + 20); + poly2.addEnvelope(env2, false); + + GeometryCursor cursor1 = new SimpleGeometryCursor(poly1); + GeometryCursor cursor2 = new SimpleGeometryCursor(poly2); + + GeometryCursor outputGeoms = operatorIntersection.execute(cursor1, + cursor2, inputSR, null); + Geometry geomr = outputGeoms.next(); + assertNotNull(geomr); + assertTrue(geomr.getType() == Geometry.Type.Polygon); + Polygon geom = (Polygon) geomr; + assertTrue(geom.getPointCount() == 4); + Point[] points = TestCommonMethods.pointsFromMultiPath(geom);// SPtrOfArrayOf(Point2D) + // pts = + // geom.get.getCoordinates2D(); + assertTrue(Math.abs(points[0].getX() - 855278.000000000) < 1e-7); + assertTrue(Math.abs(points[0].getY() - 3892060.0000000000) < 1e-7); + assertTrue(Math.abs(points[2].getX() - 855307.00000000093) < 1e-7); + assertTrue(Math.abs(points[2].getY() - 3892079.0000000000) < 1e-7); + + geomr = operatorIntersection.execute(poly1, poly2, inputSR, null); + assertNotNull(geomr); + assertTrue(geomr.getType() == Geometry.Type.Polygon); + Polygon outputGeom = (Polygon) geomr; + + assertTrue(outputGeom.getPointCount() == 4); + points = TestCommonMethods.pointsFromMultiPath(outputGeom); + assertTrue(Math.abs(points[0].getX() - 855278.000000000) < 1e-7); + assertTrue(Math.abs(points[0].getY() - 3892060.0000000000) < 1e-7); + assertTrue(Math.abs(points[2].getX() - 855307.00000000093) < 1e-7); + assertTrue(Math.abs(points[2].getY() - 3892079.0000000000) < 1e-7); + } + + @Test + public void testSelfIntersecting() {// Test that we do not fail if there is + // self-intersection + // OperatorFactoryLocal projEnv = + // OperatorFactoryLocal.getInstance(); + OperatorIntersection operatorIntersection = (OperatorIntersection) projEnv + .getOperator(Operator.Type.Intersection); + SpatialReference sr = SpatialReference.create(4326); + Polygon poly1 = new Polygon(); + Envelope2D env1 = new Envelope2D(); + env1.setCoords(0, 0, 20, 30); + poly1.addEnvelope(env1, false); + Polygon poly2 = new Polygon(); + poly2.startPath(0, 0); + poly2.lineTo(10, 10); + poly2.lineTo(0, 10); + poly2.lineTo(10, 0); + @SuppressWarnings("unused") + Polygon res = (Polygon) (operatorIntersection.execute(poly1, poly2, sr, + null)); + // Operator_equals equals = + // (Operator_equals)projEnv.get_operator(Operator::equals); + // assertTrue(equals.execute(res, poly2, sr, NULL) == true); + } + + @Test + public void testMultipoint() { + Polygon poly1 = new Polygon(); + Envelope env1 = new Envelope(855277, 3892059, 855277 + 100, + 3892059 + 100); + + poly1.addEnvelope(env1, false); + MultiPoint multiPoint = new MultiPoint(); + multiPoint.add(855277 + 10, 3892059 + 10); + multiPoint.add(855277, 3892059); + multiPoint.add(855277 + 100, 3892059 + 100); + multiPoint.add(855277 + 100, 3892059 + 101); + multiPoint.add(855277 + 101, 3892059 + 100); + multiPoint.add(855277 + 101, 3892059 + 101); + OperatorIntersection operatorIntersection = (OperatorIntersection) projEnv + .getOperator(Operator.Type.Intersection); + + MultiPoint mpResult = (MultiPoint) operatorIntersection.execute(poly1, + multiPoint, inputSR, null); + assertTrue(mpResult.getPointCount() == 3); + assertTrue(mpResult.getPoint(0).getX() == 855277 + 10 + && mpResult.getPoint(0).getY() == 3892059 + 10); + assertTrue(mpResult.getPoint(1).getX() == 855277 + && mpResult.getPoint(1).getY() == 3892059); + assertTrue(mpResult.getPoint(2).getX() == 855277 + 100 + && mpResult.getPoint(2).getY() == 3892059 + 100); + + // Test intersection of Polygon with Envelope (calls Clip) + Polygon poly = new Polygon(); + poly.startPath(0, 0); + poly.lineTo(10, 10); + poly.lineTo(20, 0); + + env1.setXMin(0); + env1.setXMax(20); + env1.setYMin(5); + env1.setYMax(15); + + Envelope envelope1 = env1; + + Polygon clippedPoly = (Polygon) operatorIntersection.execute(poly, + envelope1, inputSR, null); + double area = clippedPoly.calculateArea2D(); + assertTrue(Math.abs(area - 25) < 0.00001); + + // Geometry res = GeometryEngine.difference(poly, envelope1, inputSR); + Envelope env2 = new Envelope(855277 + 1, 3892059 + 1, 855277 + 30, + 3892059 + 20); + env2.setXMin(5); + env2.setXMax(10); + env2.setYMin(0); + env2.setYMax(20); + + Envelope envelope2 = env2; + + Envelope clippedEnvelope = (Envelope) operatorIntersection.execute( + envelope1, envelope2, inputSR, null); + area = clippedEnvelope.calculateArea2D(); + assertTrue(Math.abs(area - 50) < 0.00001); + } + + @Test + public void testDifferenceOnPolyline() { + Polyline basePl = new Polyline(); + basePl.startPath(-117, 20); + basePl.lineTo(-130, 10); + basePl.lineTo(-120, 50); + + Polyline compPl = new Polyline(); + compPl.startPath(-116, 20); + compPl.lineTo(-131, 10); + compPl.lineTo(-121, 50); + + // OperatorFactoryLocal projEnv = OperatorFactoryLocal.getInstance(); + OperatorDifference op = (OperatorDifference) projEnv + .getOperator(Operator.Type.Difference); + Polyline diffGeom = (Polyline) (op.execute(basePl, compPl, + SpatialReference.create(4326), null)); + int pc = diffGeom.getPointCount(); + assertTrue(pc == 5); + } + + @Test + public void testDifferenceOnPolyline2() { + Polyline basePl = new Polyline(); + basePl.startPath(0, 0); + basePl.lineTo(10, 10); + basePl.lineTo(20, 20); + basePl.lineTo(10, 0); + basePl.lineTo(20, 10); + + Polyline compPl = new Polyline(); + compPl.startPath(5, 0); + compPl.lineTo(5, 10); + compPl.lineTo(0, 10); + compPl.lineTo(7.5, 2.5); + + // Operator_factory_local::SaveJSONToTextFileDbg("c:/temp/basePl.txt", + // *basePl, null); + // Operator_factory_local::SaveJSONToTextFileDbg("c:/temp/compPl.txt", + // *compPl, null); + // OperatorFactoryLocal projEnv = OperatorFactoryLocal.getInstance(); + OperatorDifference op = (OperatorDifference) projEnv + .getOperator(Operator.Type.Difference); + Polyline diffGeom = (Polyline) (op.execute(basePl, compPl, + SpatialReference.create(4326), null)); + // Operator_factory_local::SaveJSONToTextFileDbg("c:/temp/diffGeom.txt", + // *diffGeom, null); + int pathc = diffGeom.getPathCount(); + assertTrue(pathc == 1); + int pc = diffGeom.getPointCount(); + assertTrue(pc == 6); + + Polyline resPl = new Polyline(); + resPl.startPath(0, 0); + resPl.lineTo(5, 5); + resPl.lineTo(10, 10); + resPl.lineTo(20, 20); + resPl.lineTo(10, 0); + resPl.lineTo(20, 10); + // Operator_factory_local::SaveJSONToTextFileDbg("c:/temp/resPl.txt", + // *resPl, null); + assertTrue(resPl.equals(diffGeom)); + } + + @Test + public void testDifferencePointPolyline() { + Polyline basePl = new Polyline(); + basePl.startPath(0, 0); + basePl.lineTo(10, 10); + basePl.lineTo(20, 20); + basePl.lineTo(10, 0); + basePl.lineTo(20, 10); + + Point compPl = new Point(5, 5); + + // OperatorFactoryLocal projEnv = OperatorFactoryLocal.getInstance(); + OperatorDifference op = (OperatorDifference) projEnv + .getOperator(Operator.Type.Difference); + Polyline diffGeom = (Polyline) (op.execute(basePl, compPl, + SpatialReference.create(4326), null)); + int pathc = diffGeom.getPathCount(); + assertTrue(pathc == 1); + int pc = diffGeom.getPointCount(); + assertTrue(pc == 5); + + Polyline resPl = new Polyline(); + resPl.startPath(0, 0); + resPl.lineTo(10, 10); + resPl.lineTo(20, 20); + resPl.lineTo(10, 0); + resPl.lineTo(20, 10); + assertTrue(resPl.equals(diffGeom));// no change happens to the original + // polyline + } + + @Test + public void testIntersectionPolylinePolygon() { + { + Polygon polygon = new Polygon(); + polygon.startPath(0, 0); + polygon.lineTo(0, 10); + polygon.lineTo(20, 10); + polygon.lineTo(20, 0); + polygon.addAttribute(VertexDescription.Semantics.Z); + polygon.setAttribute(VertexDescription.Semantics.Z, 0, 0, 3); + polygon.setAttribute(VertexDescription.Semantics.Z, 3, 0, 3); + polygon.interpolateAttributes(0, 0, 3); + Polyline polyline = new Polyline(); + polyline.startPath(0, 10); + polyline.lineTo(5, 5); + polyline.lineTo(6, 4); + polyline.lineTo(7, -1); + polyline.addAttribute(VertexDescription.Semantics.Z); + polyline.setAttribute(VertexDescription.Semantics.Z, 0, 0, 5); + polyline.setAttribute(VertexDescription.Semantics.Z, 3, 0, 5); + polyline.interpolateAttributes(0, 0, 0, 3); + + // OperatorFactoryLocal projEnv = + // OperatorFactoryLocal.getInstance(); + OperatorIntersection operatorIntersection = (OperatorIntersection) projEnv + .getOperator(Operator.Type.Intersection); + Geometry geom = operatorIntersection.execute(polyline, polygon, + null, null); + assertTrue(!geom.isEmpty()); + Polyline poly = (Polyline) (geom); + for (int i = 0; i < poly.getPointCount(); i++) + assertTrue(poly.getAttributeAsDbl( + VertexDescription.Semantics.Z, i, 0) == 5); + + // std::shared_ptr jsonExport = + // (Operator_export_to_JSON>)Operator_factory_local::get_instance().get_operator(Operator::Operator_type::export_to_JSON); + // std::string str = jsonExport.execute(0, geom, null, null); + // OutputDebugStringA(str.c_str()); + // OutputDebugString(L"\n"); + // assertTrue(str=="{\"paths\":[[[0,10],[5,5],[6,4],[6.7999999999999998,4.4408922169635528e-016]]]}"); + } + + { + Polygon polygon = new Polygon(); + polygon.startPath(0, 0); + polygon.lineTo(0, 10); + polygon.lineTo(20, 10); + polygon.lineTo(20, 0); + polygon.addAttribute(VertexDescription.Semantics.Z); + polygon.setAttribute(VertexDescription.Semantics.Z, 0, 0, 3); + polygon.setAttribute(VertexDescription.Semantics.Z, 3, 0, 3); + polygon.interpolateAttributes(0, 0, 3); + Polyline polyline = new Polyline(); + polyline.startPath(0, 10); + polyline.lineTo(20, 0); + polyline.lineTo(5, 5); + polyline.addAttribute(VertexDescription.Semantics.Z); + polyline.setAttribute(VertexDescription.Semantics.Z, 0, 0, 5); + polyline.setAttribute(VertexDescription.Semantics.Z, 1, 0, 5); + polyline.setAttribute(VertexDescription.Semantics.Z, 2, 0, 5); + + // OperatorFactoryLocal projEnv = + // OperatorFactoryLocal.getInstance(); + OperatorIntersection operatorIntersection = (OperatorIntersection) projEnv + .getOperator(Operator.Type.Intersection); + Geometry geom = operatorIntersection.execute(polyline, polygon, + null, null); + assertTrue(!geom.isEmpty()); + Polyline poly = (Polyline) (geom); + for (int i = 0; i < poly.getPointCount(); i++) + assertTrue(poly.getAttributeAsDbl( + VertexDescription.Semantics.Z, i, 0) == 5); + + // Operator_export_to_JSON> jsonExport = + // (Operator_export_to_JSON>)Operator_factory_local::get_instance().get_operator(Operator::Operator_type::export_to_JSON); + // std::string str = jsonExport.execute(0, geom, null, null); + // OutputDebugStringA(str.c_str()); + // OutputDebugString(L"\n"); + // assertTrue(str=="{\"paths\":[[[0,10],[20,0],[5,5]]]}"); + } + + { + Polygon polygon = new Polygon(); + polygon.startPath(0, 0); + polygon.lineTo(0, 10); + polygon.lineTo(20, 10); + polygon.lineTo(20, 0); + polygon.addAttribute(VertexDescription.Semantics.Z); + polygon.setAttribute(VertexDescription.Semantics.Z, 0, 0, 3); + polygon.setAttribute(VertexDescription.Semantics.Z, 3, 0, 3); + polygon.interpolateAttributes(0, 0, 3); + Polyline polyline = new Polyline(); + polyline.startPath(0, 0); + polyline.lineTo(0, 10); + polyline.lineTo(20, 10); + polyline.addAttribute(VertexDescription.Semantics.Z); + polyline.setAttribute(VertexDescription.Semantics.Z, 0, 0, 5); + polyline.setAttribute(VertexDescription.Semantics.Z, 1, 0, 5); + polyline.setAttribute(VertexDescription.Semantics.Z, 2, 0, 5); + + // OperatorFactoryLocal projEnv = + // OperatorFactoryLocal.getInstance(); + OperatorIntersection operatorIntersection = (OperatorIntersection) projEnv + .getOperator(Operator.Type.Intersection); + Geometry geom = operatorIntersection.execute(polyline, polygon, + null, null); + assertTrue(!geom.isEmpty()); + Polyline poly = (Polyline) (geom); + for (int i = 0; i < poly.getPointCount(); i++) + assertTrue(poly.getAttributeAsDbl( + VertexDescription.Semantics.Z, i, 0) == 5); + + // Operator_export_to_JSON> jsonExport = + // (Operator_export_to_JSON>)Operator_factory_local::get_instance().get_operator(Operator::Operator_type::export_to_JSON); + // std::string str = jsonExport.execute(0, geom, null, null); + // OutputDebugStringA(str.c_str()); + // OutputDebugString(L"\n"); + // assertTrue(str=="{\"paths\":[[[0,0],[0,10],[20,10]]]}"); + } + + { + Polygon polygon = new Polygon(); + polygon.startPath(0, 0); + polygon.lineTo(0, 10); + polygon.lineTo(20, 10); + polygon.lineTo(20, 0); + Polyline polyline = new Polyline(); + polyline.startPath(3, -1); + polyline.lineTo(17, 1); + polyline.lineTo(10, 8); + polyline.lineTo(-1, 5); + polyline.addAttribute(VertexDescription.Semantics.Z); + polyline.setAttribute(VertexDescription.Semantics.Z, 0, 0, 5); + polyline.setAttribute(VertexDescription.Semantics.Z, 1, 0, 5); + polyline.setAttribute(VertexDescription.Semantics.Z, 2, 0, 5); + polyline.setAttribute(VertexDescription.Semantics.Z, 3, 0, 5); + + // OperatorFactoryLocal projEnv = + // OperatorFactoryLocal.getInstance(); + OperatorIntersection operatorIntersection = (OperatorIntersection) projEnv + .getOperator(Operator.Type.Intersection); + Geometry geom = operatorIntersection.execute(polyline, polygon, + null, null); + assertTrue(!geom.isEmpty()); + Polyline poly = (Polyline) geom; + for (int i = 0; i < poly.getPointCount(); i++) + assertTrue(poly.getAttributeAsDbl( + VertexDescription.Semantics.Z, i, 0) == 5); + + // Operator_export_to_JSON> jsonExport = + // (Operator_export_to_JSON>)Operator_factory_local::get_instance().get_operator(Operator::Operator_type::export_to_JSON); + // std::string str = jsonExport.execute(0, geom, null, null); + // OutputDebugStringA(str.c_str()); + // OutputDebugString(L"\n"); + // assertTrue(str=="{\"paths\":[[[10,0],[17,1],[10,8],[4.7377092701401439e-024,5.2727272727272734]]]}"); + } + + { + Polygon polygon = new Polygon(); + polygon.startPath(0, 0); + polygon.lineTo(0, 10); + polygon.lineTo(20, 10); + polygon.lineTo(20, 0); + Polyline polyline = new Polyline(); + polyline.startPath(0, 15); + polyline.lineTo(3, -1); + polyline.lineTo(17, 1); + polyline.lineTo(10, 8); + polyline.lineTo(-1, 5); + polyline.addAttribute(VertexDescription.Semantics.Z); + polyline.setAttribute(VertexDescription.Semantics.Z, 0, 0, 5); + polyline.setAttribute(VertexDescription.Semantics.Z, 4, 0, 5); + polyline.interpolateAttributes(0, 0, 0, 4); + OperatorIntersection operatorIntersection = (OperatorIntersection) projEnv + .getOperator(Operator.Type.Intersection); + Geometry geom = operatorIntersection.execute(polyline, polygon, + null, null); + assertTrue(!geom.isEmpty()); + Polyline poly = (Polyline) geom; + for (int i = 0; i < poly.getPointCount(); i++) + assertTrue(poly.getAttributeAsDbl( + VertexDescription.Semantics.Z, i, 0) == 5); + + // Operator_export_to_JSON> jsonExport = + // (Operator_export_to_JSON>)Operator_factory_local::get_instance().get_operator(Operator::Operator_type::export_to_JSON); + // std::string str = jsonExport.execute(0, geom, null, null); + // OutputDebugStringA(str.c_str()); + // OutputDebugString(L"\n"); + // assertTrue(str=="{\"paths\":[[[0.9375,10],[2.8125,9.476226333847234e-024]],[[10,0],[17,1],[10,8],[4.7377092701401439e-024,5.2727272727272734]]]}"); + } + + { + Polygon polygon = new Polygon(); + polygon.startPath(0, 0); + polygon.lineTo(0, 10); + polygon.lineTo(20, 10); + polygon.lineTo(20, 0); + Polyline polyline = new Polyline(); + polyline.startPath(5, 5); + polyline.lineTo(1, 1); + polyline.lineTo(-1, 1); + polyline.lineTo(-1, 10); + polyline.lineTo(0, 10); + polyline.lineTo(6, 6); + polyline.addAttribute(VertexDescription.Semantics.Z); + polyline.setAttribute(VertexDescription.Semantics.Z, 0, 0, 5); + polyline.setAttribute(VertexDescription.Semantics.Z, 5, 0, 5); + polyline.interpolateAttributes(0, 0, 0, 5); + + // OperatorFactoryLocal projEnv = + // OperatorFactoryLocal.getInstance(); + OperatorIntersection operatorIntersection = (OperatorIntersection) projEnv + .getOperator(Operator.Type.Intersection); + Geometry geom = operatorIntersection.execute(polyline, polygon, + null, null); + assertTrue(!geom.isEmpty()); + Polyline poly = (Polyline) geom; + for (int i = 0; i < poly.getPointCount(); i++) + assertTrue(poly.getAttributeAsDbl( + VertexDescription.Semantics.Z, i, 0) == 5); + + // Operator_export_to_JSON> jsonExport = + // (Operator_export_to_JSON>)Operator_factory_local::get_instance().get_operator(Operator::Operator_type::export_to_JSON); + // std::string str = jsonExport.execute(0, geom, null, null); + // OutputDebugStringA(str.c_str()); + // OutputDebugString(L"\n"); + // assertTrue(str=="{\"paths\":[[[5,5],[1,1],[4.738113166923617e-023,1]],[[0,10],[6,6]]]}"); + } + + { + Polygon polygon = new Polygon(); + polygon.startPath(0, 0); + polygon.lineTo(0, 10); + polygon.lineTo(20, 10); + polygon.lineTo(20, 0); + Polyline polyline = new Polyline(); + polyline.startPath(0, 15); + polyline.lineTo(3, -1); + polyline.lineTo(17, 1); + polyline.lineTo(10, 8); + polyline.lineTo(-1, 5); + polyline.startPath(19, 15); + polyline.lineTo(29, 9); + polyline.startPath(19, 15); + polyline.lineTo(29, 9); + polyline.startPath(5, 5); + polyline.lineTo(1, 1); + polyline.lineTo(-1, 1); + polyline.lineTo(-1, 10); + polyline.lineTo(0, 10); + polyline.lineTo(6, 6); + polyline.addAttribute(VertexDescription.Semantics.Z); + polyline.setAttribute(VertexDescription.Semantics.Z, 0, 0, 5); + polyline.setAttribute(VertexDescription.Semantics.Z, 14, 0, 5); + polyline.interpolateAttributes(0, 0, 3, 5); + + // OperatorFactoryLocal projEnv = + // OperatorFactoryLocal.getInstance(); + OperatorIntersection operatorIntersection = (OperatorIntersection) projEnv + .getOperator(Operator.Type.Intersection); + Geometry geom = operatorIntersection.execute(polyline, polygon, + null, null); + assertTrue(!geom.isEmpty()); + Polyline poly = (Polyline) geom; + for (int i = 0; i < poly.getPointCount(); i++) + assertTrue(poly.getAttributeAsDbl( + VertexDescription.Semantics.Z, i, 0) == 5); + + // Operator_export_to_JSON> jsonExport = + // (Operator_export_to_JSON>)Operator_factory_local::get_instance().get_operator(Operator::Operator_type::export_to_JSON); + // std::string str = jsonExport.execute(0, geom, null, null); + // OutputDebugStringA(str.c_str()); + // OutputDebugString(L"\n"); + // assertTrue(str=="{\"paths\":[[[0.9375,10],[2.8125,9.476226333847234e-024]],[[10,0],[17,1],[10,8],[4.7377092701401439e-024,5.2727272727272734]],[[5,5],[1,1],[4.738113166923617e-023,1]],[[0,10],[6,6]]]}"); + } + } + + @Test + public void testMultiPointPolyline() { + Polyline polyline = new Polyline(); + polyline.startPath(0, 0); + polyline.lineTo(0, 10); + polyline.lineTo(20, 10); + polyline.lineTo(20, 0); + MultiPoint mp = new MultiPoint(); + mp.add(0, 10, 7); + mp.add(0, 5, 7); + mp.add(1, 5, 7); + // OperatorFactoryLocal projEnv = OperatorFactoryLocal.getInstance(); + OperatorIntersection operatorIntersection = (OperatorIntersection) projEnv + .getOperator(Operator.Type.Intersection); + OperatorDifference operatorDifference = (OperatorDifference) projEnv + .getOperator(Operator.Type.Difference); + + {// intersect + Geometry geom = operatorIntersection.execute(polyline, mp, null, + null); + MultiPoint res = (MultiPoint) geom; + assertTrue(res.getPointCount() == 2); + Point2D pt_1 = res.getXY(0); + Point2D pt_2 = res.getXY(1); + assertTrue(Point2D.distance(pt_1, new Point2D(0, 10)) < 1e-10 + && Point2D.distance(pt_2, new Point2D(0, 5)) < 1e-10 + || Point2D.distance(pt_2, new Point2D(0, 10)) < 1e-10 + && Point2D.distance(pt_1, new Point2D(0, 5)) < 1e-10); + + assertTrue(res.getAttributeAsDbl(VertexDescription.Semantics.Z, 0, + 0) == 7); + assertTrue(res.getAttributeAsDbl(VertexDescription.Semantics.Z, 1, + 0) == 7); + } + + {// difference + Geometry geom = operatorDifference + .execute(polyline, mp, null, null); + // assertTrue(geom.getGeometryType() == + // Geometry.GeometryType.Polyline); + Polyline res = (Polyline) geom; + assertTrue(res.getPointCount() == 4); + } + {// difference + Geometry geom = operatorDifference + .execute(mp, polyline, null, null); + // assertTrue(geom.getType() == Geometry.GeometryType.MultiPoint); + MultiPoint res = (MultiPoint) geom; + assertTrue(res.getPointCount() == 1); + Point2D pt_1 = res.getXY(0); + assertTrue(Point2D.distance(pt_1, new Point2D(1, 5)) < 1e-10); + } + {// difference (subtract empty) + Geometry geom = operatorDifference.execute(mp, new Polyline(), + null, null); + // assertTrue(geom.getGeometryType() == + // Geometry.GeometryType.MultiPoint); + MultiPoint res = (MultiPoint) geom; + assertTrue(res.getPointCount() == 3); + Point2D pt_1 = res.getXY(0); + assertTrue(Point2D.distance(pt_1, new Point2D(0, 10)) < 1e-10); + } + + } + + @Test + public void testPointPolyline() { + Polyline polyline = new Polyline(); + polyline.startPath(0, 0); + polyline.lineTo(0, 10); + polyline.lineTo(20, 10); + polyline.lineTo(20, 0); + Point p_1 = new Point(0, 5, 7); + Point p_2 = new Point(0, 10, 7); + Point p3 = new Point(1, 5, 7); + // OperatorFactoryLocal projEnv = OperatorFactoryLocal.getInstance(); + OperatorIntersection operatorIntersection = (OperatorIntersection) projEnv + .getOperator(Operator.Type.Intersection); + OperatorDifference operatorDiff = (OperatorDifference) projEnv + .getOperator(Operator.Type.Difference); + OperatorUnion operatorUnion = (OperatorUnion) projEnv + .getOperator(Operator.Type.Union); + OperatorSymmetricDifference operatorSymDiff = (OperatorSymmetricDifference) projEnv + .getOperator(Operator.Type.SymmetricDifference); + + {// intersect case1 + Geometry geom = operatorIntersection.execute(polyline, p_1, null, + null); + // assertTrue(geom.getType() == Geometry::enum_point); + Point res = (Point) geom; + Point2D pt_1 = res.getXY(); + assertTrue(Point2D.distance(pt_1, new Point2D(0, 5)) < 1e-10); + assertTrue(res.getAttributeAsDbl(VertexDescription.Semantics.Z, 0) == 7); + } + {// intersect case2 + Geometry geom = operatorIntersection.execute(polyline, p_2, null, + null); + // assertTrue(geom.getType() == Geometry::enum_point); + Point res = (Point) geom; + Point2D pt_1 = res.getXY(); + assertTrue(Point2D.distance(pt_1, new Point2D(0, 10)) < 1e-10); + assertTrue(res.getAttributeAsDbl(VertexDescription.Semantics.Z, 0) == 7); + } + {// intersect case3 + Geometry geom = operatorIntersection.execute(polyline, p3, null, + null); + // assertTrue(geom.getType() == Geometry::enum_point); + assertTrue(geom.isEmpty()); + assertTrue(geom.hasAttribute(VertexDescription.Semantics.Z)); + } + + {// difference case1 + Geometry geom = operatorDiff.execute(polyline, p_1, null, null); + // assertTrue(geom.getType() == Geometry.GeometryType.Polyline); + Polyline res = (Polyline) geom; + assertTrue(res.getPointCount() == 4); + } + {// difference case2 + Geometry geom = operatorDiff.execute(p_1, polyline, null, null); + // assertTrue(geom.getType() == Geometry::enum_point); + Point res = (Point) geom; + assertTrue(res.isEmpty()); + } + {// difference case3 + Geometry geom = operatorDiff.execute(p_2, polyline, null, null); + // assertTrue(geom.getType() == Geometry::enum_point); + Point res = (Point) geom; + assertTrue(res.isEmpty()); + } + {// difference case4 + Geometry geom = operatorDiff.execute(p3, polyline, null, null); + // assertTrue(geom.getType() == Geometry::enum_point); + Point res = (Point) geom; + Point2D pt_1 = res.getXY(); + assertTrue(Point2D.distance(pt_1, new Point2D(1, 5)) < 1e-10); + } + + {// union case1 + Geometry geom = operatorUnion.execute(p_1, polyline, null, null); + // assertTrue(geom.getType() == Geometry.GeometryType.Polyline); + Polyline res = (Polyline) geom; + assertTrue(!res.isEmpty()); + } + {// union case2 + Geometry geom = operatorUnion.execute(polyline, p_1, null, null); + // assertTrue(geom.getType() == Geometry.GeometryType.Polyline); + Polyline res = (Polyline) geom; + assertTrue(!res.isEmpty()); + } + + {// symmetric difference case1 + Geometry geom = operatorSymDiff.execute(polyline, p_1, null, null); + assertTrue(geom.getType().value() == Geometry.GeometryType.Polyline); + Polyline res = (Polyline) (geom); + assertTrue(!res.isEmpty()); + } + {// symmetric difference case2 + Geometry geom = operatorSymDiff.execute(p_1, polyline, null, null); + assertTrue(geom.getType().value() == Geometry.GeometryType.Polyline); + Polyline res = (Polyline) (geom); + assertTrue(!res.isEmpty()); + } + } + + @Test + public void testPolylinePolylineIntersectionExtended() { + {// crossing intersection + Polyline basePl = new Polyline(); + basePl.startPath(0, 10); + basePl.lineTo(100, 10); + + Polyline compPl = new Polyline(); + compPl.startPath(50, 0); + compPl.lineTo(50, 100); + + OperatorIntersection op = (OperatorIntersection) projEnv + .getOperator(Operator.Type.Intersection); + GeometryCursor result_cursor = op.execute(new SimpleGeometryCursor( + basePl), new SimpleGeometryCursor(compPl), SpatialReference + .create(4326), null, 3); + + // dimension is 3, means it has to return a point and a polyline + Geometry geom1 = result_cursor.next(); + assertTrue(geom1 != null); + assertTrue(geom1.getDimension() == 0); + assertTrue(geom1.getType().value() == Geometry.GeometryType.MultiPoint); + assertTrue(((MultiPoint) geom1).getPointCount() == 1); + + Geometry geom2 = result_cursor.next(); + assertTrue(geom2 != null); + assertTrue(geom2.getDimension() == 1); + assertTrue(geom2.getType().value() == Geometry.GeometryType.Polyline); + assertTrue(((Polyline) geom2).getPointCount() == 0); + + Geometry geom3 = result_cursor.next(); + assertTrue(geom3 == null); + } + + {// crossing + overlapping intersection + Polyline basePl = new Polyline(); + basePl.startPath(0, 10); + basePl.lineTo(100, 10); + + Polyline compPl = new Polyline(); + compPl.startPath(50, 0); + compPl.lineTo(50, 100); + compPl.lineTo(70, 10); + compPl.lineTo(100, 10); + + OperatorIntersection op = (OperatorIntersection) projEnv + .getOperator(Operator.Type.Intersection); + GeometryCursor result_cursor = op.execute(new SimpleGeometryCursor( + basePl), new SimpleGeometryCursor(compPl), SpatialReference + .create(4326), null, 3); + + // dimension is 3, means it has to return a point and a polyline + Geometry geom1 = result_cursor.next(); + assertTrue(geom1 != null); + assertTrue(geom1.getDimension() == 0); + assertTrue(geom1.getType().value() == Geometry.GeometryType.MultiPoint); + assertTrue(((MultiPoint) geom1).getPointCount() == 1); + + Geometry geom2 = result_cursor.next(); + assertTrue(geom2 != null); + assertTrue(geom2.getDimension() == 1); + assertTrue(geom2.getType().value() == Geometry.GeometryType.Polyline); + assertTrue(((Polyline) geom2).getPathCount() == 1); + assertTrue(((Polyline) geom2).getPointCount() == 2); + + Geometry geom3 = result_cursor.next(); + assertTrue(geom3 == null); + } + } + + @Test + public void testPolygonPolygonIntersectionExtended() { + {// crossing intersection + Polygon basePl = new Polygon(); + basePl.startPath(0, 0); + basePl.lineTo(100, 0); + basePl.lineTo(100, 100); + basePl.lineTo(0, 100); + + Polygon compPl = new Polygon(); + compPl.startPath(100, 100); + compPl.lineTo(200, 100); + compPl.lineTo(200, 200); + compPl.lineTo(100, 200); + + OperatorIntersection op = (OperatorIntersection) projEnv + .getOperator(Operator.Type.Intersection); + GeometryCursor result_cursor = op.execute(new SimpleGeometryCursor( + basePl), new SimpleGeometryCursor(compPl), SpatialReference + .create(4326), null, 7); + + Geometry geom1 = result_cursor.next(); + assertTrue(geom1 != null); + assertTrue(geom1.getDimension() == 0); + assertTrue(geom1.getType().value() == Geometry.GeometryType.MultiPoint); + assertTrue(((MultiPoint) geom1).getPointCount() == 1); + + Geometry geom2 = result_cursor.next(); + assertTrue(geom2 != null); + assertTrue(geom2.getDimension() == 1); + assertTrue(geom2.getType().value() == Geometry.GeometryType.Polyline); + assertTrue(((Polyline) geom2).getPointCount() == 0); + + Geometry geom3 = result_cursor.next(); + assertTrue(geom3 != null); + assertTrue(geom3.getDimension() == 2); + assertTrue(geom3.getType().value() == Geometry.GeometryType.Polygon); + assertTrue(((Polygon) geom3).getPointCount() == 0); + + + } + + {// crossing + overlapping intersection + Polygon basePl = new Polygon(); + basePl.startPath(0, 0); + basePl.lineTo(100, 0); + basePl.lineTo(100, 100); + basePl.lineTo(0, 100); + + Polygon compPl = new Polygon(); + compPl.startPath(100, 100); + compPl.lineTo(200, 100); + compPl.lineTo(200, 200); + compPl.lineTo(100, 200); + + compPl.startPath(100, 20); + compPl.lineTo(200, 20); + compPl.lineTo(200, 40); + compPl.lineTo(100, 40); + + compPl.startPath(-10, -10); + compPl.lineTo(-10, 10); + compPl.lineTo(10, 10); + compPl.lineTo(10, -10); + + OperatorIntersection op = (OperatorIntersection) projEnv + .getOperator(Operator.Type.Intersection); + GeometryCursor result_cursor = op.execute(new SimpleGeometryCursor( + basePl), new SimpleGeometryCursor(compPl), SpatialReference + .create(4326), null, 7); + + // dimension is 3, means it has to return a point and a polyline + + Geometry geom1 = result_cursor.next(); + assertTrue(geom1 != null); + assertEquals(geom1.getDimension(), 0); + assertTrue(geom1.getType().value() == Geometry.GeometryType.MultiPoint); + assertTrue(((MultiPoint) geom1).getPointCount() == 1); + + Geometry geom2 = result_cursor.next(); + assertTrue(geom2 != null); + assertTrue(geom2.getDimension() == 1); + assertTrue(geom2.getType().value() == Geometry.GeometryType.Polyline); + assertTrue(((Polyline) geom2).getPathCount() == 1); + assertTrue(((Polyline) geom2).getPointCount() == 2); + + Geometry geom3 = result_cursor.next(); + assertTrue(geom3 != null); + assertTrue(geom3.getDimension() == 2); + assertTrue(geom3.getType().value() == Geometry.GeometryType.Polygon); + assertTrue(((Polygon) geom3).getPathCount() == 1); + assertTrue(((Polygon) geom3).getPointCount() == 4); + + Geometry geom4 = result_cursor.next(); + assertTrue(geom4 == null); + } + } + + @Test + public void testFromProjection() { + MultiPoint multiPointInitial = new MultiPoint(); + multiPointInitial.add(-20037508.342789244, 3360107.7777777780); + multiPointInitial.add(-18924313.434856508, 3360107.7777777780); + multiPointInitial.add(-18924313.434856508, -3360107.7777777780); + multiPointInitial.add(-20037508.342789244, -3360107.7777777780); + Geometry geom1 = ((MultiPoint) multiPointInitial); + + SpatialReference sr = SpatialReference.create(102100); + + Envelope2D env = new Envelope2D(); + env.setCoords(/* xmin */-20037508.342788246, /* ymin */ + -30240971.958386172, /* xmax */20037508.342788246, /* ymax */ + 30240971.958386205); + // /*xmin*/ -20037508.342788246 + // /*ymin*/ -30240971.958386172 + // /*xmax*/ 20037508.342788246 + // /*ymax*/ 30240971.958386205 + + Polygon poly = new Polygon(); + poly.startPath(env.xmin, env.ymin); + poly.lineTo(env.xmin, env.ymax); + poly.lineTo(env.xmax, env.ymax); + poly.lineTo(env.xmax, env.ymin); + + Geometry geom2 = new Envelope(env); + // Geometry geom2 = poly; + + OperatorIntersection operatorIntersection = (OperatorIntersection) OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Intersection); + + MultiPoint multiPointOut = (MultiPoint) (operatorIntersection.execute( + geom1, geom2, sr, null)); + + assertTrue(multiPointOut.getCoordinates2D().length == 2); + assertTrue(multiPointOut.getCoordinates2D()[0].x == -18924313.434856508); + assertTrue(multiPointOut.getCoordinates2D()[0].y == 3360107.7777777780); + assertTrue(multiPointOut.getCoordinates2D()[1].x == -18924313.434856508); + assertTrue(multiPointOut.getCoordinates2D()[1].y == -3360107.7777777780); + } + + @Test + public void testIssue258128() { + Polygon poly1 = new Polygon(); + poly1.startPath(0, 0); + poly1.lineTo(0, 10); + poly1.lineTo(10, 10); + poly1.lineTo(10, 0); + + Polygon poly2 = new Polygon(); + poly2.startPath(10.5, 4); + poly2.lineTo(10.5, 8); + poly2.lineTo(14, 10); + + try { + GeometryCursor result_cursor = OperatorIntersection.local().execute(new SimpleGeometryCursor( + poly1), new SimpleGeometryCursor(poly2), SpatialReference + .create(4326), null, 1); + while (result_cursor.next() != null) { + + } + } catch (Exception e) { + assertTrue(false); + } + } + + @Test + public void testUnionTickTock() { + Polygon poly1 = new Polygon(); + poly1.startPath(0, 0); + poly1.lineTo(0, 10); + poly1.lineTo(10, 10); + poly1.lineTo(10, 0); + + Polygon poly2 = new Polygon(); + poly2.startPath(10.5, 4); + poly2.lineTo(10.5, 8); + poly2.lineTo(14, 10); + + Transformation2D trans = new Transformation2D(); + + Polygon poly3 = (Polygon) poly1.copy(); + trans.setShift(2, 3); + poly3.applyTransformation(trans); + + Polygon poly4 = (Polygon) poly1.copy(); + trans.setShift(-2, -3); + poly4.applyTransformation(trans); + + // Create + ListeningGeometryCursor gc = new ListeningGeometryCursor(); + GeometryCursor ticktock = OperatorUnion.local().execute(gc, null, null); + + // Use tick-tock to push a geometry and do a piece of work. + gc.tick(poly1); + ticktock.tock(); + gc.tick(poly2); + gc.tick(poly3);// skiped one tock just for testing. + ticktock.tock(); + gc.tick(poly4); + ticktock.tock(); + // Get the result + Geometry result = ticktock.next(); + + // Use ListeningGeometryCursor to put all geometries in. + ListeningGeometryCursor gc2 = new ListeningGeometryCursor(); + gc2.tick(poly1); + gc2.tick(poly2); + gc2.tick(poly3); + gc2.tick(poly4); + + GeometryCursor res = OperatorUnion.local().execute(gc2, null, null); + // Calling next will process all geometries at once. + Geometry result2 = res.next(); + assertTrue(result.equals(result2)); + } + + @Test + public void testIntersectionIssueLinePoly1() { + String wkt1 = new String("polygon((0 0, 10 0, 10 10, 0 10, 0 0))"); + String wkt2 = new String("linestring(9 5, 10 5, 9 4, 8 3)"); + Geometry g1 = OperatorImportFromWkt.local().execute(0, Geometry.Type.Unknown, wkt1, null); + Geometry g2 = OperatorImportFromWkt.local().execute(0, Geometry.Type.Unknown, wkt2, null); + Geometry res = OperatorIntersection.local().execute(g1, g2, null, null); + assertTrue(((Polyline) res).getPathCount() == 1); + assertTrue(((Polyline) res).getPointCount() == 4); + } + + @Test + public void testSharedEdgeIntersection_13() { + String s1 = "{\"rings\":[[[0.099604024000029767,0.2107958250000479],[0.14626826900007472,0.2107958250000479],[0.14626826900007472,0.18285316400005058],[0.099604024000029767,0.18285316400005058],[0.099604024000029767,0.2107958250000479]]]}"; + String s2 = "{\"paths\":[[[0.095692051000071388,0.15910190100004229],[0.10324853600002371,0.18285316400004228],[0.12359292700006108,0.18285316400004228],[0.12782611200003657,0.1705583920000322],[0.13537063000007138,0.18285316400004228]]]}"; + + Polygon polygon = (Polygon) TestCommonMethods.fromJson(s1).getGeometry(); + Polyline polyline = (Polyline) TestCommonMethods.fromJson(s2).getGeometry(); + SpatialReference sr = SpatialReference.create(4326); + + Geometry g = OperatorIntersection.local().execute(polygon, polyline, sr, null); + assertTrue(!g.isEmpty()); + } + + @Test + public void testIntersectionIssue2() { + String s1 = "{\"rings\":[[[-97.174860352323378,48.717174479818425],[-97.020624513410553,58.210155436624177],[-94.087641114245969,58.210155436624177],[-94.087641114245969,48.639781902013226],[-97.174860352323378,48.717174479818425]]]}"; + String s2 = "{\"rings\":[[[-94.08764111399995,52.68342763000004],[-94.08764111399995,56.835188018000053],[-90.285921520999977,62.345706350000057],[-94.08764111399995,52.68342763000004]]]}"; + + Polygon polygon1 = (Polygon) TestCommonMethods.fromJson(s1).getGeometry(); + Polygon polygon2 = (Polygon) TestCommonMethods.fromJson(s2).getGeometry(); + SpatialReference sr = SpatialReference.create(4326); + + GeometryCursor res = OperatorIntersection.local().execute(new SimpleGeometryCursor(polygon1), new SimpleGeometryCursor(polygon2), sr, null, 2); + Geometry g = res.next(); + assertTrue(g != null); + assertTrue(!g.isEmpty()); + Geometry g2 = res.next(); + assertTrue(g2 == null); + + String ss = "{\"paths\":[[[-94.08764111412296,52.68342763000004],[-94.08764111410767,56.83518801800005]]]}"; + Polyline polyline = (Polyline) TestCommonMethods.fromJson(ss).getGeometry(); + boolean eq = OperatorEquals.local().execute(g, polyline, sr, null); + assertTrue(eq); + } /* Point2D uniqueIntersectionPointOfNonDisjointGeometries(Geometry g1, Geometry g2, SpatialReference sr) { diff --git a/src/test/java/com/esri/core/geometry/TestIntervalTree.java b/src/test/java/com/esri/core/geometry/TestIntervalTree.java index ba82e1cc..43c1e300 100644 --- a/src/test/java/com/esri/core/geometry/TestIntervalTree.java +++ b/src/test/java/com/esri/core/geometry/TestIntervalTree.java @@ -31,317 +31,317 @@ import java.util.Random; public class TestIntervalTree extends TestCase { - @Override - protected void setUp() throws Exception { - super.setUp(); - } - - @Override - protected void tearDown() throws Exception { - super.tearDown(); - } - - static void construct(IntervalTreeImpl interval_tree, - ArrayList intervals) { - interval_tree.startConstruction(); - for (int i = 0; i < intervals.size(); i++) - interval_tree.addInterval(intervals.get(i)); - interval_tree.endConstruction(); - } - - @Test - public static void testIntervalTree() { - ArrayList intervals = new ArrayList(0); - - Envelope1D env0 = new Envelope1D(2, 3); - Envelope1D env1 = new Envelope1D(5, 13); - Envelope1D env2 = new Envelope1D(6, 9); - Envelope1D env3 = new Envelope1D(8, 10); - Envelope1D env4 = new Envelope1D(11, 12); - Envelope1D env5 = new Envelope1D(1, 3); - Envelope1D env6 = new Envelope1D(0, 2); - Envelope1D env7 = new Envelope1D(4, 7); - Envelope1D env8; - - intervals.add(env0); - intervals.add(env1); - intervals.add(env2); - intervals.add(env3); - intervals.add(env4); - intervals.add(env5); - intervals.add(env6); - intervals.add(env7); - - int counter; - IntervalTreeImpl intervalTree = new IntervalTreeImpl(false); - construct(intervalTree, intervals); - IntervalTreeImpl.IntervalTreeIteratorImpl iterator = intervalTree - .getIterator(new Envelope1D(-1, 14), 0.0); - - counter = 0; - while (iterator.next() != -1) - counter++; - assertTrue(counter == 8); - - iterator.resetIterator(new Envelope1D(2.5, 10.5), 0.0); - counter = 0; - while (iterator.next() != -1) - counter++; - assertTrue(counter == 6); - - iterator.resetIterator(5.0, 0.0); - counter = 0; - while (iterator.next() != -1) - counter++; - assertTrue(counter == 2); - - iterator.resetIterator(7, 0.0); - counter = 0; - while (iterator.next() != -1) - counter++; - assertTrue(counter == 3); - - iterator.resetIterator(new Envelope1D(2.0, 10.5), 0.0); - counter = 0; - while (iterator.next() != -1) - counter++; - assertTrue(counter == 7); - - iterator.resetIterator(new Envelope1D(2.5, 11), 0.0); - counter = 0; - while (iterator.next() != -1) - counter++; - assertTrue(counter == 7); - - iterator.resetIterator(new Envelope1D(2.1, 2.5), 0.0); - counter = 0; - while (iterator.next() != -1) - counter++; - assertTrue(counter == 2); - - iterator.resetIterator(new Envelope1D(2.1, 5), 0.0); - counter = 0; - while (iterator.next() != -1) - counter++; - assertTrue(counter == 4); - - iterator.resetIterator(new Envelope1D(2.0, 5), 0.0); - counter = 0; - while (iterator.next() != -1) - counter++; - assertTrue(counter == 5); - - iterator.resetIterator(new Envelope1D(5.0, 11), 0.0); - counter = 0; - while (iterator.next() != -1) - counter++; - assertTrue(counter == 5); - - iterator.resetIterator(new Envelope1D(8, 10.5), 0.0); - counter = 0; - while (iterator.next() != -1) - counter++; - assertTrue(counter == 3); - - iterator.resetIterator(new Envelope1D(10, 11), 0.0); - counter = 0; - while (iterator.next() != -1) - counter++; - assertTrue(counter == 3); - - iterator.resetIterator(new Envelope1D(10, 10.9), 0.0); - counter = 0; - while (iterator.next() != -1) - counter++; - assertTrue(counter == 2); - - iterator.resetIterator(new Envelope1D(11.5, 12), 0.0); - counter = 0; - while (iterator.next() != -1) - counter++; - assertTrue(counter == 2); - - env0 = new Envelope1D(0, 4); - env1 = new Envelope1D(6, 7); - env2 = new Envelope1D(9, 10); - env3 = new Envelope1D(9, 11); - env4 = new Envelope1D(7, 12); - env5 = new Envelope1D(13, 15); - env6 = new Envelope1D(1, 6); - env7 = new Envelope1D(3, 3); - env8 = new Envelope1D(8, 8); - - intervals.clear(); - intervals.add(env0); - intervals.add(env1); - intervals.add(env2); - intervals.add(env3); - intervals.add(env4); - intervals.add(env5); - intervals.add(env6); - intervals.add(env7); - intervals.add(env8); - - IntervalTreeImpl intervalTree2 = new IntervalTreeImpl(true); - construct(intervalTree2, intervals); - - intervalTree2.insert(0); - intervalTree2.insert(1); - intervalTree2.insert(2); - intervalTree2.insert(3); - intervalTree2.insert(4); - intervalTree2.insert(5); - intervalTree2.insert(6); - intervalTree2.insert(7); - intervalTree2.insert(8); - - iterator = intervalTree2.getIterator(new Envelope1D(8, 8), 0.0); - - counter = 0; - while (iterator.next() != -1) - counter++; - assertTrue(counter == 2); - - iterator.resetIterator(new Envelope1D(3, 7), 0.0); - counter = 0; - while (iterator.next() != -1) - counter++; - assertTrue(counter == 5); - - iterator.resetIterator(new Envelope1D(1, 3), 0.0); - counter = 0; - while (iterator.next() != -1) - counter++; - assertTrue(counter == 3); - - iterator.resetIterator(new Envelope1D(6, 9), 0.0); - counter = 0; - while (iterator.next() != -1) - counter++; - assertTrue(counter == 6); - - iterator.resetIterator(new Envelope1D(10, 14), 0.0); - counter = 0; - while (iterator.next() != -1) - counter++; - assertTrue(counter == 4); - - env0 = new Envelope1D(11, 14); - env1 = new Envelope1D(21, 36); - env2 = new Envelope1D(15, 19); - env3 = new Envelope1D(3, 8); - env4 = new Envelope1D(34, 38); - env5 = new Envelope1D(23, 27); - env6 = new Envelope1D(6, 36); - - intervals.clear(); - intervals.add(env0); - intervals.add(env1); - intervals.add(env2); - intervals.add(env3); - intervals.add(env4); - intervals.add(env5); - intervals.add(env6); - - IntervalTreeImpl intervalTree3 = new IntervalTreeImpl(false); - construct(intervalTree3, intervals); - iterator = intervalTree3.getIterator(new Envelope1D(50, 50), 0.0); - assert (iterator.next() == -1); - } - - @Test - public static void testIntervalTreeRandomConstruction() { - @SuppressWarnings("unused") - int pointcount = 0; - int passcount = 1000; - int figureSize = 50; - Envelope env = new Envelope(); - env.setCoords(-10000, -10000, 10000, 10000); - RandomCoordinateGenerator generator = new RandomCoordinateGenerator( - Math.max(figureSize, 10000), env, 0.001); - Random random = new Random(2013); - int rand_max = 98765; - ArrayList intervals = new ArrayList(); - AttributeStreamOfInt8 intervalsFound = new AttributeStreamOfInt8(0); - - for (int i = 0; i < passcount; i++) { - int r = figureSize; - if (r < 3) - continue; - Polygon poly = new Polygon(); - Point pt; - for (int j = 0; j < r; j++) { - int rand = random.nextInt(rand_max); - boolean bRandomNew = (r > 10) - && ((1.0 * rand) / rand_max > 0.95); - pt = generator.GetRandomCoord(); - if (j == 0 || bRandomNew) - poly.startPath(pt); - else - poly.lineTo(pt); - } - - { - intervals.clear(); - SegmentIterator seg_iter = poly.querySegmentIterator(); - Envelope1D interval; - - Envelope1D range = poly.queryInterval( - VertexDescription.Semantics.POSITION, 0); - range.vmin -= 0.01; - range.vmax += 0.01; - - while (seg_iter.nextPath()) { - while (seg_iter.hasNextSegment()) { - Segment segment = seg_iter.nextSegment(); - interval = segment.queryInterval( - VertexDescription.Semantics.POSITION, 0); - intervals.add(interval); - } - } - - intervalsFound.resize(intervals.size(), 0); - - // Just test construction for assertions - IntervalTreeImpl intervalTree = new IntervalTreeImpl(true); - construct(intervalTree, intervals); - - for (int j = 0; j < intervals.size(); j++) - intervalTree.insert(j); - - IntervalTreeImpl.IntervalTreeIteratorImpl iterator = intervalTree - .getIterator(range, 0.0); - - int count = 0; - int handle; - while ((handle = iterator.next()) != -1) { - count++; - intervalsFound.write(handle, (byte) 1); - } - - assertTrue(count == intervals.size()); - - for (int j = 0; j < intervalsFound.size(); j++) { - interval = intervals.get(j); - assertTrue(intervalsFound.read(j) == 1); - } - - for (int j = 0; j < intervals.size() >> 1; j++) - intervalTree.remove(j); - - iterator.resetIterator(range, 0.0); - - count = 0; - while ((handle = iterator.next()) != -1) { - count++; - intervalsFound.write(handle, (byte) 1); - } - - assertTrue(count == intervals.size() - (intervals.size() >> 1)); - - for (int j = (intervals.size() >> 1); j < intervals.size(); j++) - intervalTree.remove(j); - } - } - } + @Override + protected void setUp() throws Exception { + super.setUp(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + } + + static void construct(IntervalTreeImpl interval_tree, + ArrayList intervals) { + interval_tree.startConstruction(); + for (int i = 0; i < intervals.size(); i++) + interval_tree.addInterval(intervals.get(i)); + interval_tree.endConstruction(); + } + + @Test + public static void testIntervalTree() { + ArrayList intervals = new ArrayList(0); + + Envelope1D env0 = new Envelope1D(2, 3); + Envelope1D env1 = new Envelope1D(5, 13); + Envelope1D env2 = new Envelope1D(6, 9); + Envelope1D env3 = new Envelope1D(8, 10); + Envelope1D env4 = new Envelope1D(11, 12); + Envelope1D env5 = new Envelope1D(1, 3); + Envelope1D env6 = new Envelope1D(0, 2); + Envelope1D env7 = new Envelope1D(4, 7); + Envelope1D env8; + + intervals.add(env0); + intervals.add(env1); + intervals.add(env2); + intervals.add(env3); + intervals.add(env4); + intervals.add(env5); + intervals.add(env6); + intervals.add(env7); + + int counter; + IntervalTreeImpl intervalTree = new IntervalTreeImpl(false); + construct(intervalTree, intervals); + IntervalTreeImpl.IntervalTreeIteratorImpl iterator = intervalTree + .getIterator(new Envelope1D(-1, 14), 0.0); + + counter = 0; + while (iterator.next() != -1) + counter++; + assertTrue(counter == 8); + + iterator.resetIterator(new Envelope1D(2.5, 10.5), 0.0); + counter = 0; + while (iterator.next() != -1) + counter++; + assertTrue(counter == 6); + + iterator.resetIterator(5.0, 0.0); + counter = 0; + while (iterator.next() != -1) + counter++; + assertTrue(counter == 2); + + iterator.resetIterator(7, 0.0); + counter = 0; + while (iterator.next() != -1) + counter++; + assertTrue(counter == 3); + + iterator.resetIterator(new Envelope1D(2.0, 10.5), 0.0); + counter = 0; + while (iterator.next() != -1) + counter++; + assertTrue(counter == 7); + + iterator.resetIterator(new Envelope1D(2.5, 11), 0.0); + counter = 0; + while (iterator.next() != -1) + counter++; + assertTrue(counter == 7); + + iterator.resetIterator(new Envelope1D(2.1, 2.5), 0.0); + counter = 0; + while (iterator.next() != -1) + counter++; + assertTrue(counter == 2); + + iterator.resetIterator(new Envelope1D(2.1, 5), 0.0); + counter = 0; + while (iterator.next() != -1) + counter++; + assertTrue(counter == 4); + + iterator.resetIterator(new Envelope1D(2.0, 5), 0.0); + counter = 0; + while (iterator.next() != -1) + counter++; + assertTrue(counter == 5); + + iterator.resetIterator(new Envelope1D(5.0, 11), 0.0); + counter = 0; + while (iterator.next() != -1) + counter++; + assertTrue(counter == 5); + + iterator.resetIterator(new Envelope1D(8, 10.5), 0.0); + counter = 0; + while (iterator.next() != -1) + counter++; + assertTrue(counter == 3); + + iterator.resetIterator(new Envelope1D(10, 11), 0.0); + counter = 0; + while (iterator.next() != -1) + counter++; + assertTrue(counter == 3); + + iterator.resetIterator(new Envelope1D(10, 10.9), 0.0); + counter = 0; + while (iterator.next() != -1) + counter++; + assertTrue(counter == 2); + + iterator.resetIterator(new Envelope1D(11.5, 12), 0.0); + counter = 0; + while (iterator.next() != -1) + counter++; + assertTrue(counter == 2); + + env0 = new Envelope1D(0, 4); + env1 = new Envelope1D(6, 7); + env2 = new Envelope1D(9, 10); + env3 = new Envelope1D(9, 11); + env4 = new Envelope1D(7, 12); + env5 = new Envelope1D(13, 15); + env6 = new Envelope1D(1, 6); + env7 = new Envelope1D(3, 3); + env8 = new Envelope1D(8, 8); + + intervals.clear(); + intervals.add(env0); + intervals.add(env1); + intervals.add(env2); + intervals.add(env3); + intervals.add(env4); + intervals.add(env5); + intervals.add(env6); + intervals.add(env7); + intervals.add(env8); + + IntervalTreeImpl intervalTree2 = new IntervalTreeImpl(true); + construct(intervalTree2, intervals); + + intervalTree2.insert(0); + intervalTree2.insert(1); + intervalTree2.insert(2); + intervalTree2.insert(3); + intervalTree2.insert(4); + intervalTree2.insert(5); + intervalTree2.insert(6); + intervalTree2.insert(7); + intervalTree2.insert(8); + + iterator = intervalTree2.getIterator(new Envelope1D(8, 8), 0.0); + + counter = 0; + while (iterator.next() != -1) + counter++; + assertTrue(counter == 2); + + iterator.resetIterator(new Envelope1D(3, 7), 0.0); + counter = 0; + while (iterator.next() != -1) + counter++; + assertTrue(counter == 5); + + iterator.resetIterator(new Envelope1D(1, 3), 0.0); + counter = 0; + while (iterator.next() != -1) + counter++; + assertTrue(counter == 3); + + iterator.resetIterator(new Envelope1D(6, 9), 0.0); + counter = 0; + while (iterator.next() != -1) + counter++; + assertTrue(counter == 6); + + iterator.resetIterator(new Envelope1D(10, 14), 0.0); + counter = 0; + while (iterator.next() != -1) + counter++; + assertTrue(counter == 4); + + env0 = new Envelope1D(11, 14); + env1 = new Envelope1D(21, 36); + env2 = new Envelope1D(15, 19); + env3 = new Envelope1D(3, 8); + env4 = new Envelope1D(34, 38); + env5 = new Envelope1D(23, 27); + env6 = new Envelope1D(6, 36); + + intervals.clear(); + intervals.add(env0); + intervals.add(env1); + intervals.add(env2); + intervals.add(env3); + intervals.add(env4); + intervals.add(env5); + intervals.add(env6); + + IntervalTreeImpl intervalTree3 = new IntervalTreeImpl(false); + construct(intervalTree3, intervals); + iterator = intervalTree3.getIterator(new Envelope1D(50, 50), 0.0); + assert (iterator.next() == -1); + } + + @Test + public static void testIntervalTreeRandomConstruction() { + @SuppressWarnings("unused") + int pointcount = 0; + int passcount = 1000; + int figureSize = 50; + Envelope env = new Envelope(); + env.setCoords(-10000, -10000, 10000, 10000); + RandomCoordinateGenerator generator = new RandomCoordinateGenerator( + Math.max(figureSize, 10000), env, 0.001); + Random random = new Random(2013); + int rand_max = 98765; + ArrayList intervals = new ArrayList(); + AttributeStreamOfInt8 intervalsFound = new AttributeStreamOfInt8(0); + + for (int i = 0; i < passcount; i++) { + int r = figureSize; + if (r < 3) + continue; + Polygon poly = new Polygon(); + Point pt; + for (int j = 0; j < r; j++) { + int rand = random.nextInt(rand_max); + boolean bRandomNew = (r > 10) + && ((1.0 * rand) / rand_max > 0.95); + pt = generator.GetRandomCoord(); + if (j == 0 || bRandomNew) + poly.startPath(pt); + else + poly.lineTo(pt); + } + + { + intervals.clear(); + SegmentIterator seg_iter = poly.querySegmentIterator(); + Envelope1D interval; + + Envelope1D range = poly.queryInterval( + VertexDescription.Semantics.POSITION, 0); + range.vmin -= 0.01; + range.vmax += 0.01; + + while (seg_iter.nextPath()) { + while (seg_iter.hasNextSegment()) { + Segment segment = seg_iter.nextSegment(); + interval = segment.queryInterval( + VertexDescription.Semantics.POSITION, 0); + intervals.add(interval); + } + } + + intervalsFound.resize(intervals.size(), 0); + + // Just test construction for assertions + IntervalTreeImpl intervalTree = new IntervalTreeImpl(true); + construct(intervalTree, intervals); + + for (int j = 0; j < intervals.size(); j++) + intervalTree.insert(j); + + IntervalTreeImpl.IntervalTreeIteratorImpl iterator = intervalTree + .getIterator(range, 0.0); + + int count = 0; + int handle; + while ((handle = iterator.next()) != -1) { + count++; + intervalsFound.write(handle, (byte) 1); + } + + assertTrue(count == intervals.size()); + + for (int j = 0; j < intervalsFound.size(); j++) { + interval = intervals.get(j); + assertTrue(intervalsFound.read(j) == 1); + } + + for (int j = 0; j < intervals.size() >> 1; j++) + intervalTree.remove(j); + + iterator.resetIterator(range, 0.0); + + count = 0; + while ((handle = iterator.next()) != -1) { + count++; + intervalsFound.write(handle, (byte) 1); + } + + assertTrue(count == intervals.size() - (intervals.size() >> 1)); + + for (int j = (intervals.size() >> 1); j < intervals.size(); j++) + intervalTree.remove(j); + } + } + } } diff --git a/src/test/java/com/esri/core/geometry/TestJSonGeometry.java b/src/test/java/com/esri/core/geometry/TestJSonGeometry.java index 6959309e..786fe093 100644 --- a/src/test/java/com/esri/core/geometry/TestJSonGeometry.java +++ b/src/test/java/com/esri/core/geometry/TestJSonGeometry.java @@ -31,41 +31,41 @@ import java.util.Map; public class TestJSonGeometry extends TestCase { - @Override - protected void setUp() throws Exception { - super.setUp(); - } + @Override + protected void setUp() throws Exception { + super.setUp(); + } - @Override - protected void tearDown() throws Exception { - super.tearDown(); - } + @Override + protected void tearDown() throws Exception { + super.tearDown(); + } - @Test - public void testGetSpatialReferenceFor4326() { - String completeStr = "GEOGCS[\"GCS_Sphere\",DATUM[\"D_Sphere\"," - + "SPHEROID[\"Sphere\",6371000.0,0.0]],PRIMEM[\"Greenwich\",0.0]," - + "UNIT[\"Degree\",0.0174532925199433]]"; + @Test + public void testGetSpatialReferenceFor4326() { + String completeStr = "GEOGCS[\"GCS_Sphere\",DATUM[\"D_Sphere\"," + + "SPHEROID[\"Sphere\",6371000.0,0.0]],PRIMEM[\"Greenwich\",0.0]," + + "UNIT[\"Degree\",0.0174532925199433]]"; - // 4326 GCS_WGS_1984 - SpatialReference sr = SpatialReference.create(completeStr); - assertNotNull(sr); - } + // 4326 GCS_WGS_1984 + SpatialReference sr = SpatialReference.create(completeStr); + assertNotNull(sr); + } } final class HashMapClassForTesting { - static Map SR_WKI_WKTs = new HashMap() { - /** - * added to get rid of warning - */ - private static final long serialVersionUID = 8630934425353750539L; + static Map SR_WKI_WKTs = new HashMap() { + /** + * added to get rid of warning + */ + private static final long serialVersionUID = 8630934425353750539L; - { - put(4035, - "GEOGCS[\"GCS_Sphere\",DATUM[\"D_Sphere\"," - + "SPHEROID[\"Sphere\",6371000.0,0.0]],PRIMEM[\"Greenwich\",0.0]," - + "UNIT[\"Degree\",0.0174532925199433]]"); - } - }; + { + put(4035, + "GEOGCS[\"GCS_Sphere\",DATUM[\"D_Sphere\"," + + "SPHEROID[\"Sphere\",6371000.0,0.0]],PRIMEM[\"Greenwich\",0.0]," + + "UNIT[\"Degree\",0.0174532925199433]]"); + } + }; } diff --git a/src/test/java/com/esri/core/geometry/TestJSonToGeomFromWkiOrWkt_CR177613.java b/src/test/java/com/esri/core/geometry/TestJSonToGeomFromWkiOrWkt_CR177613.java index 234b3dad..2fb7c2af 100644 --- a/src/test/java/com/esri/core/geometry/TestJSonToGeomFromWkiOrWkt_CR177613.java +++ b/src/test/java/com/esri/core/geometry/TestJSonToGeomFromWkiOrWkt_CR177613.java @@ -34,115 +34,115 @@ import java.io.IOException; public class TestJSonToGeomFromWkiOrWkt_CR177613 extends TestCase { - JsonFactory factory = new JsonFactory(); - - @Override - protected void setUp() throws Exception { - super.setUp(); - } - - @Override - protected void tearDown() throws Exception { - super.tearDown(); - } - - @Test - public void testPolygonWithEmptyWKT_NoWKI() throws JsonParseException, - IOException { - String jsonStringPg = "{ \"rings\" :[ [ [-97.06138,32.837], [-97.06133,32.836], " - + "[-97.06124,32.834], [-97.06127,32.832], [-97.06138,32.837] ], " - + "[ [-97.06326,32.759], [-97.06298,32.755], [-97.06153,32.749], [-97.06326,32.759] ]], " - + "\"spatialReference\" : {\"wkt\" : \"\"}}"; - JsonParser jsonParserPg = factory.createParser(jsonStringPg); - jsonParserPg.nextToken(); - - MapGeometry mapGeom = GeometryEngine.jsonToGeometry(jsonParserPg); - Utils.showProjectedGeometryInfo(mapGeom); - SpatialReference sr = mapGeom.getSpatialReference(); - assertTrue(sr == null); - } - - @Test - public void testOnlyWKI() throws JsonParseException, IOException { - String jsonStringSR = "{\"wkid\" : 4326}"; - JsonParser jsonParserSR = factory.createParser(jsonStringSR); - jsonParserSR.nextToken(); - - MapGeometry mapGeom = GeometryEngine.jsonToGeometry(jsonParserSR); - Utils.showProjectedGeometryInfo(mapGeom); - SpatialReference sr = mapGeom.getSpatialReference(); - assertTrue(sr == null); - } - - @Test - public void testMP2onCR175871() throws Exception { - Polygon pg = new Polygon(); - pg.startPath(-50, 10); - pg.lineTo(-50, 12); - pg.lineTo(-45, 12); - pg.lineTo(-45, 10); - - Polygon pg1 = new Polygon(); - pg1.startPath(-45, 10); - pg1.lineTo(-40, 10); - pg1.lineTo(-40, 8); - pg.add(pg1, false); - - try { - String jSonStr = GeometryEngine.geometryToJson(4326, pg); - JsonFactory jf = new JsonFactory(); - - JsonParser jp = jf.createParser(jSonStr); - jp.nextToken(); - MapGeometry mg = GeometryEngine.jsonToGeometry(jp); - Geometry gm = mg.getGeometry(); - assertEquals(Geometry.Type.Polygon, gm.getType()); - - Polygon pgNew = (Polygon) gm; - - assertEquals(pgNew.getPathCount(), pg.getPathCount()); - assertEquals(pgNew.getPointCount(), pg.getPointCount()); - assertEquals(pgNew.getSegmentCount(), pg.getSegmentCount()); - - assertEquals(pgNew.getPoint(0).getX(), pg.getPoint(0).getX(), - 0.000000001); - assertEquals(pgNew.getPoint(1).getX(), pg.getPoint(1).getX(), - 0.000000001); - assertEquals(pgNew.getPoint(2).getX(), pg.getPoint(2).getX(), - 0.000000001); - assertEquals(pgNew.getPoint(3).getX(), pg.getPoint(3).getX(), - 0.000000001); - - assertEquals(pgNew.getPoint(0).getY(), pg.getPoint(0).getY(), - 0.000000001); - assertEquals(pgNew.getPoint(1).getY(), pg.getPoint(1).getY(), - 0.000000001); - assertEquals(pgNew.getPoint(2).getY(), pg.getPoint(2).getY(), - 0.000000001); - assertEquals(pgNew.getPoint(3).getY(), pg.getPoint(3).getY(), - 0.000000001); - } catch (Exception ex) { - String err = ex.getMessage(); - System.out.print(err); - throw ex; - } - } - - public static int fromJsonToWkid(JsonParser parser) - throws JsonParseException, IOException { - int wkid = 0; - if (parser.getCurrentToken() != JsonToken.START_OBJECT) { - return 0; - } - - while (parser.nextToken() != JsonToken.END_OBJECT) { - String fieldName = parser.getCurrentName(); - - if ("wkid".equals(fieldName)) { - parser.nextToken(); - wkid = parser.getIntValue(); - } - } - return wkid; - } + JsonFactory factory = new JsonFactory(); + + @Override + protected void setUp() throws Exception { + super.setUp(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + } + + @Test + public void testPolygonWithEmptyWKT_NoWKI() throws JsonParseException, + IOException { + String jsonStringPg = "{ \"rings\" :[ [ [-97.06138,32.837], [-97.06133,32.836], " + + "[-97.06124,32.834], [-97.06127,32.832], [-97.06138,32.837] ], " + + "[ [-97.06326,32.759], [-97.06298,32.755], [-97.06153,32.749], [-97.06326,32.759] ]], " + + "\"spatialReference\" : {\"wkt\" : \"\"}}"; + JsonParser jsonParserPg = factory.createParser(jsonStringPg); + jsonParserPg.nextToken(); + + MapGeometry mapGeom = GeometryEngine.jsonToGeometry(jsonParserPg); + Utils.showProjectedGeometryInfo(mapGeom); + SpatialReference sr = mapGeom.getSpatialReference(); + assertTrue(sr == null); + } + + @Test + public void testOnlyWKI() throws JsonParseException, IOException { + String jsonStringSR = "{\"wkid\" : 4326}"; + JsonParser jsonParserSR = factory.createParser(jsonStringSR); + jsonParserSR.nextToken(); + + MapGeometry mapGeom = GeometryEngine.jsonToGeometry(jsonParserSR); + Utils.showProjectedGeometryInfo(mapGeom); + SpatialReference sr = mapGeom.getSpatialReference(); + assertTrue(sr == null); + } + + @Test + public void testMP2onCR175871() throws Exception { + Polygon pg = new Polygon(); + pg.startPath(-50, 10); + pg.lineTo(-50, 12); + pg.lineTo(-45, 12); + pg.lineTo(-45, 10); + + Polygon pg1 = new Polygon(); + pg1.startPath(-45, 10); + pg1.lineTo(-40, 10); + pg1.lineTo(-40, 8); + pg.add(pg1, false); + + try { + String jSonStr = GeometryEngine.geometryToJson(4326, pg); + JsonFactory jf = new JsonFactory(); + + JsonParser jp = jf.createParser(jSonStr); + jp.nextToken(); + MapGeometry mg = GeometryEngine.jsonToGeometry(jp); + Geometry gm = mg.getGeometry(); + assertEquals(Geometry.Type.Polygon, gm.getType()); + + Polygon pgNew = (Polygon) gm; + + assertEquals(pgNew.getPathCount(), pg.getPathCount()); + assertEquals(pgNew.getPointCount(), pg.getPointCount()); + assertEquals(pgNew.getSegmentCount(), pg.getSegmentCount()); + + assertEquals(pgNew.getPoint(0).getX(), pg.getPoint(0).getX(), + 0.000000001); + assertEquals(pgNew.getPoint(1).getX(), pg.getPoint(1).getX(), + 0.000000001); + assertEquals(pgNew.getPoint(2).getX(), pg.getPoint(2).getX(), + 0.000000001); + assertEquals(pgNew.getPoint(3).getX(), pg.getPoint(3).getX(), + 0.000000001); + + assertEquals(pgNew.getPoint(0).getY(), pg.getPoint(0).getY(), + 0.000000001); + assertEquals(pgNew.getPoint(1).getY(), pg.getPoint(1).getY(), + 0.000000001); + assertEquals(pgNew.getPoint(2).getY(), pg.getPoint(2).getY(), + 0.000000001); + assertEquals(pgNew.getPoint(3).getY(), pg.getPoint(3).getY(), + 0.000000001); + } catch (Exception ex) { + String err = ex.getMessage(); + System.out.print(err); + throw ex; + } + } + + public static int fromJsonToWkid(JsonParser parser) + throws JsonParseException, IOException { + int wkid = 0; + if (parser.getCurrentToken() != JsonToken.START_OBJECT) { + return 0; + } + + while (parser.nextToken() != JsonToken.END_OBJECT) { + String fieldName = parser.getCurrentName(); + + if ("wkid".equals(fieldName)) { + parser.nextToken(); + wkid = parser.getIntValue(); + } + } + return wkid; + } } diff --git a/src/test/java/com/esri/core/geometry/TestJsonParser.java b/src/test/java/com/esri/core/geometry/TestJsonParser.java index 856f2045..3ba521bb 100644 --- a/src/test/java/com/esri/core/geometry/TestJsonParser.java +++ b/src/test/java/com/esri/core/geometry/TestJsonParser.java @@ -36,538 +36,538 @@ public class TestJsonParser extends TestCase { - JsonFactory factory = new JsonFactory(); - SpatialReference spatialReferenceWebMerc1 = SpatialReference.create(102100); - SpatialReference spatialReferenceWebMerc2 = SpatialReference.create(spatialReferenceWebMerc1.getLatestID()); - SpatialReference spatialReferenceWGS84 = SpatialReference.create(4326); - - @Override - protected void setUp() throws Exception { - super.setUp(); - } - - @Override - protected void tearDown() throws Exception { - super.tearDown(); - } - - @Test - public void test3DPoint() throws JsonParseException, IOException { - String jsonString3DPt = "{\"x\" : -118.15, \"y\" : 33.80, \"z\" : 10.0, \"spatialReference\" : {\"wkid\" : 4326}}"; - - JsonParser jsonParser3DPt = factory.createParser(jsonString3DPt); - MapGeometry point3DMP = GeometryEngine.jsonToGeometry(jsonParser3DPt); - assertTrue(-118.15 == ((Point) point3DMP.getGeometry()).getX()); - assertTrue(33.80 == ((Point) point3DMP.getGeometry()).getY()); - assertTrue(spatialReferenceWGS84.getID() == point3DMP.getSpatialReference().getID()); - } - - @Test - public void test3DPoint1() throws JsonParseException, IOException { - Point point1 = new Point(10.0, 20.0); - Point pointEmpty = new Point(); - { - JsonParser pointWebMerc1Parser = factory - .createParser(GeometryEngine.geometryToJson(spatialReferenceWebMerc1, point1)); - MapGeometry pointWebMerc1MP = GeometryEngine.jsonToGeometry(pointWebMerc1Parser); - assertTrue(point1.getX() == ((Point) pointWebMerc1MP.getGeometry()).getX()); - assertTrue(point1.getY() == ((Point) pointWebMerc1MP.getGeometry()).getY()); - int srIdOri = spatialReferenceWebMerc1.getID(); - int srIdAfter = pointWebMerc1MP.getSpatialReference().getID(); - assertTrue(srIdOri == srIdAfter || srIdAfter == 3857); - - pointWebMerc1Parser = factory.createParser(GeometryEngine.geometryToJson(null, point1)); - pointWebMerc1MP = GeometryEngine.jsonToGeometry(pointWebMerc1Parser); - assertTrue(null == pointWebMerc1MP.getSpatialReference()); - - String pointEmptyString = GeometryEngine.geometryToJson(spatialReferenceWebMerc1, pointEmpty); - pointWebMerc1Parser = factory.createParser(pointEmptyString); - - pointWebMerc1MP = GeometryEngine.jsonToGeometry(pointWebMerc1Parser); - assertTrue(pointWebMerc1MP.getGeometry().isEmpty()); - int srIdOri2 = spatialReferenceWebMerc1.getID(); - int srIdAfter2 = pointWebMerc1MP.getSpatialReference().getID(); - assertTrue(srIdOri2 == srIdAfter2 || srIdAfter2 == 3857); - } - } - - @Test - public void test3DPoint2() throws JsonParseException, IOException { - { - Point point1 = new Point(10.0, 20.0); - JsonParser pointWebMerc2Parser = factory - .createParser(GeometryEngine.geometryToJson(spatialReferenceWebMerc2, point1)); - MapGeometry pointWebMerc2MP = GeometryEngine.jsonToGeometry(pointWebMerc2Parser); - assertTrue(point1.getX() == ((Point) pointWebMerc2MP.getGeometry()).getX()); - assertTrue(point1.getY() == ((Point) pointWebMerc2MP.getGeometry()).getY()); - assertTrue(spatialReferenceWebMerc2.getLatestID() == pointWebMerc2MP.getSpatialReference().getLatestID()); - } - } - - @Test - public void test3DPoint3() throws JsonParseException, IOException { - { - Point point1 = new Point(10.0, 20.0); - JsonParser pointWgs84Parser = factory - .createParser(GeometryEngine.geometryToJson(spatialReferenceWGS84, point1)); - MapGeometry pointWgs84MP = GeometryEngine.jsonToGeometry(pointWgs84Parser); - assertTrue(point1.getX() == ((Point) pointWgs84MP.getGeometry()).getX()); - assertTrue(point1.getY() == ((Point) pointWgs84MP.getGeometry()).getY()); - assertTrue(spatialReferenceWGS84.getID() == pointWgs84MP.getSpatialReference().getID()); - } - } - - @Test - public void testMultiPoint() throws JsonParseException, IOException { - MultiPoint multiPoint1 = new MultiPoint(); - multiPoint1.add(-97.06138, 32.837); - multiPoint1.add(-97.06133, 32.836); - multiPoint1.add(-97.06124, 32.834); - multiPoint1.add(-97.06127, 32.832); - - { - JsonParser mPointWgs84Parser = factory - .createParser(GeometryEngine.geometryToJson(spatialReferenceWGS84, multiPoint1)); - MapGeometry mPointWgs84MP = GeometryEngine.jsonToGeometry(mPointWgs84Parser); - assertTrue(multiPoint1.getPointCount() == ((MultiPoint) mPointWgs84MP.getGeometry()).getPointCount()); - assertTrue(multiPoint1.getPoint(0).getX() == ((MultiPoint) mPointWgs84MP.getGeometry()).getPoint(0).getX()); - assertTrue(multiPoint1.getPoint(0).getY() == ((MultiPoint) mPointWgs84MP.getGeometry()).getPoint(0).getY()); - int lastIndex = multiPoint1.getPointCount() - 1; - assertTrue(multiPoint1.getPoint(lastIndex).getX() == ((MultiPoint) mPointWgs84MP.getGeometry()) - .getPoint(lastIndex).getX()); - assertTrue(multiPoint1.getPoint(lastIndex).getY() == ((MultiPoint) mPointWgs84MP.getGeometry()) - .getPoint(lastIndex).getY()); - - assertTrue(spatialReferenceWGS84.getID() == mPointWgs84MP.getSpatialReference().getID()); - - MultiPoint mPointEmpty = new MultiPoint(); - String mPointEmptyString = GeometryEngine.geometryToJson(spatialReferenceWGS84, mPointEmpty); - mPointWgs84Parser = factory.createParser(mPointEmptyString); - - mPointWgs84MP = GeometryEngine.jsonToGeometry(mPointWgs84Parser); - assertTrue(mPointWgs84MP.getGeometry().isEmpty()); - assertTrue(spatialReferenceWGS84.getID() == mPointWgs84MP.getSpatialReference().getID()); - - } - } - - @Test - public void testPolyline() throws JsonParseException, IOException { - Polyline polyline = new Polyline(); - polyline.startPath(-97.06138, 32.837); - polyline.lineTo(-97.06133, 32.836); - polyline.lineTo(-97.06124, 32.834); - polyline.lineTo(-97.06127, 32.832); - - polyline.startPath(-97.06326, 32.759); - polyline.lineTo(-97.06298, 32.755); - - { - JsonParser polylinePathsWgs84Parser = factory - .createParser(GeometryEngine.geometryToJson(spatialReferenceWGS84, polyline)); - MapGeometry mPolylineWGS84MP = GeometryEngine.jsonToGeometry(polylinePathsWgs84Parser); - - assertTrue(polyline.getPointCount() == ((Polyline) mPolylineWGS84MP.getGeometry()).getPointCount()); - assertTrue(polyline.getPoint(0).getX() == ((Polyline) mPolylineWGS84MP.getGeometry()).getPoint(0).getX()); - assertTrue(polyline.getPoint(0).getY() == ((Polyline) mPolylineWGS84MP.getGeometry()).getPoint(0).getY()); - - assertTrue(polyline.getPathCount() == ((Polyline) mPolylineWGS84MP.getGeometry()).getPathCount()); - assertTrue(polyline.getSegmentCount() == ((Polyline) mPolylineWGS84MP.getGeometry()).getSegmentCount()); - assertTrue(polyline.getSegmentCount(0) == ((Polyline) mPolylineWGS84MP.getGeometry()).getSegmentCount(0)); - assertTrue(polyline.getSegmentCount(1) == ((Polyline) mPolylineWGS84MP.getGeometry()).getSegmentCount(1)); - - int lastIndex = polyline.getPointCount() - 1; - assertTrue(polyline.getPoint(lastIndex).getX() == ((Polyline) mPolylineWGS84MP.getGeometry()) - .getPoint(lastIndex).getX()); - assertTrue(polyline.getPoint(lastIndex).getY() == ((Polyline) mPolylineWGS84MP.getGeometry()) - .getPoint(lastIndex).getY()); - - assertTrue(spatialReferenceWGS84.getID() == mPolylineWGS84MP.getSpatialReference().getID()); - - Polyline emptyPolyline = new Polyline(); - String emptyString = GeometryEngine.geometryToJson(spatialReferenceWGS84, emptyPolyline); - mPolylineWGS84MP = GeometryEngine.jsonToGeometry(factory.createParser(emptyString)); - assertTrue(mPolylineWGS84MP.getGeometry().isEmpty()); - assertTrue(spatialReferenceWGS84.getID() == mPolylineWGS84MP.getSpatialReference().getID()); - } - } - - @Test - public void testPolygon() throws JsonParseException, IOException { - Polygon polygon = new Polygon(); - polygon.startPath(-97.06138, 32.837); - polygon.lineTo(-97.06133, 32.836); - polygon.lineTo(-97.06124, 32.834); - polygon.lineTo(-97.06127, 32.832); - - polygon.startPath(-97.06326, 32.759); - polygon.lineTo(-97.06298, 32.755); - - { - JsonParser polygonPathsWgs84Parser = factory - .createParser(GeometryEngine.geometryToJson(spatialReferenceWGS84, polygon)); - MapGeometry mPolygonWGS84MP = GeometryEngine.jsonToGeometry(polygonPathsWgs84Parser); - - assertTrue(polygon.getPointCount() + 1 == ((Polygon) mPolygonWGS84MP.getGeometry()).getPointCount()); - assertTrue(polygon.getPoint(0).getX() == ((Polygon) mPolygonWGS84MP.getGeometry()).getPoint(0).getX()); - assertTrue(polygon.getPoint(0).getY() == ((Polygon) mPolygonWGS84MP.getGeometry()).getPoint(0).getY()); - - assertTrue(polygon.getPathCount() == ((Polygon) mPolygonWGS84MP.getGeometry()).getPathCount()); - assertTrue(polygon.getSegmentCount() + 1 == ((Polygon) mPolygonWGS84MP.getGeometry()).getSegmentCount()); - assertTrue(polygon.getSegmentCount(0) == ((Polygon) mPolygonWGS84MP.getGeometry()).getSegmentCount(0)); - assertTrue(polygon.getSegmentCount(1) + 1 == ((Polygon) mPolygonWGS84MP.getGeometry()).getSegmentCount(1)); - - int lastIndex = polygon.getPointCount() - 1; - assertTrue(polygon.getPoint(lastIndex).getX() == ((Polygon) mPolygonWGS84MP.getGeometry()) - .getPoint(lastIndex).getX()); - assertTrue(polygon.getPoint(lastIndex).getY() == ((Polygon) mPolygonWGS84MP.getGeometry()) - .getPoint(lastIndex).getY()); - - assertTrue(spatialReferenceWGS84.getID() == mPolygonWGS84MP.getSpatialReference().getID()); - - Polygon emptyPolygon = new Polygon(); - String emptyPolygonString = GeometryEngine.geometryToJson(spatialReferenceWGS84, emptyPolygon); - polygonPathsWgs84Parser = factory.createParser(emptyPolygonString); - mPolygonWGS84MP = GeometryEngine.jsonToGeometry(polygonPathsWgs84Parser); - - assertTrue(mPolygonWGS84MP.getGeometry().isEmpty()); - assertTrue(spatialReferenceWGS84.getID() == mPolygonWGS84MP.getSpatialReference().getID()); - } - } - - @Test - public void testEnvelope() throws JsonParseException, IOException { - Envelope envelope = new Envelope(); - envelope.setCoords(-109.55, 25.76, -86.39, 49.94); - - { - JsonParser envelopeWGS84Parser = factory - .createParser(GeometryEngine.geometryToJson(spatialReferenceWGS84, envelope)); - MapGeometry envelopeWGS84MP = GeometryEngine.jsonToGeometry(envelopeWGS84Parser); - assertTrue(envelope.isEmpty() == envelopeWGS84MP.getGeometry().isEmpty()); - assertTrue(envelope.getXMax() == ((Envelope) envelopeWGS84MP.getGeometry()).getXMax()); - assertTrue(envelope.getYMax() == ((Envelope) envelopeWGS84MP.getGeometry()).getYMax()); - assertTrue(envelope.getXMin() == ((Envelope) envelopeWGS84MP.getGeometry()).getXMin()); - assertTrue(envelope.getYMin() == ((Envelope) envelopeWGS84MP.getGeometry()).getYMin()); - assertTrue(spatialReferenceWGS84.getID() == envelopeWGS84MP.getSpatialReference().getID()); - - Envelope emptyEnvelope = new Envelope(); - String emptyEnvString = GeometryEngine.geometryToJson(spatialReferenceWGS84, emptyEnvelope); - envelopeWGS84Parser = factory.createParser(emptyEnvString); - envelopeWGS84MP = GeometryEngine.jsonToGeometry(envelopeWGS84Parser); - - assertTrue(envelopeWGS84MP.getGeometry().isEmpty()); - assertTrue(spatialReferenceWGS84.getID() == envelopeWGS84MP.getSpatialReference().getID()); - } - } - - @Test - public void testCR181369() throws JsonParseException, IOException { - // CR181369 - { - String jsonStringPointAndWKT = "{\"x\":10.0,\"y\":20.0,\"spatialReference\":{\"wkt\" : \"PROJCS[\\\"NAD83_UTM_zone_15N\\\",GEOGCS[\\\"GCS_North_American_1983\\\",DATUM[\\\"D_North_American_1983\\\",SPHEROID[\\\"GRS_1980\\\",6378137.0,298.257222101]],PRIMEM[\\\"Greenwich\\\",0.0],UNIT[\\\"Degree\\\",0.0174532925199433]],PROJECTION[\\\"Transverse_Mercator\\\"],PARAMETER[\\\"false_easting\\\",500000.0],PARAMETER[\\\"false_northing\\\",0.0],PARAMETER[\\\"central_meridian\\\",-93.0],PARAMETER[\\\"scale_factor\\\",0.9996],PARAMETER[\\\"latitude_of_origin\\\",0.0],UNIT[\\\"Meter\\\",1.0]]\"} }"; - JsonParser jsonParserPointAndWKT = factory.createParser(jsonStringPointAndWKT); - MapGeometry mapGeom2 = GeometryEngine.jsonToGeometry(jsonParserPointAndWKT); - String jsonStringPointAndWKT2 = GeometryEngine.geometryToJson(mapGeom2.getSpatialReference(), - mapGeom2.getGeometry()); - JsonParser jsonParserPointAndWKT2 = factory.createParser(jsonStringPointAndWKT2); - MapGeometry mapGeom3 = GeometryEngine.jsonToGeometry(jsonParserPointAndWKT2); - assertTrue(((Point) mapGeom2.getGeometry()).getX() == ((Point) mapGeom3.getGeometry()).getX()); - assertTrue(((Point) mapGeom2.getGeometry()).getY() == ((Point) mapGeom3.getGeometry()).getY()); - assertTrue(mapGeom2.getSpatialReference().getText().equals(mapGeom3.getSpatialReference().getText())); - assertTrue(mapGeom2.getSpatialReference().getID() == mapGeom3.getSpatialReference().getID()); - } - } - - @Test - public void testSpatialRef() throws JsonParseException, IOException { - // String jsonStringPt = - // "{\"x\":-20037508.342787,\"y\":20037508.342787},\"spatialReference\":{\"wkid\":102100}}"; - String jsonStringPt = "{\"x\":10.0,\"y\":20.0,\"spatialReference\":{\"wkid\": 102100}}";// 102100 - @SuppressWarnings("unused") - String jsonStringPt2 = "{\"x\":10.0,\"y\":20.0,\"spatialReference\":{\"wkid\":4326}}"; - String jsonStringMpt = "{ \"points\" : [ [-97.06138,32.837], [-97.06133,32.836], [-97.06124,32.834], [-97.06127,32.832] ], \"spatialReference\" : {\"wkid\" : 4326}}";// 4326 - String jsonStringMpt3D = "{\"hasZs\" : true,\"points\" : [ [-97.06138,32.837,35.0], [-97.06133,32.836,35.1], [-97.06124,32.834,35.2], [-97.06127,32.832,35.3] ],\"spatialReference\" : {\"wkid\" : 4326}}"; - String jsonStringPl = "{\"paths\" : [ [ [-97.06138,32.837], [-97.06133,32.836], [-97.06124,32.834], [-97.06127,32.832] ], [ [-97.06326,32.759], [-97.06298,32.755] ]],\"spatialReference\" : {\"wkid\" : 4326}}"; - String jsonStringPl3D = "{\"hasMs\" : true,\"paths\" : [[ [-97.06138,32.837,5], [-97.06133,32.836,6], [-97.06124,32.834,7], [-97.06127,32.832,8] ],[ [-97.06326,32.759], [-97.06298,32.755] ]],\"spatialReference\" : {\"wkid\" : 4326}}"; - String jsonStringPg = "{ \"rings\" :[ [ [-97.06138,32.837], [-97.06133,32.836], [-97.06124,32.834], [-97.06127,32.832], [-97.06138,32.837] ], [ [-97.06326,32.759], [-97.06298,32.755], [-97.06153,32.749], [-97.06326,32.759] ]], \"spatialReference\" : {\"wkt\" : \"\"}}"; - String jsonStringPg3D = "{\"hasZs\" : true,\"hasMs\" : true,\"rings\" : [ [ [-97.06138, 32.837, 35.1, 4], [-97.06133, 32.836, 35.2, 4.1], [-97.06124, 32.834, 35.3, 4.2], [-97.06127, 32.832, 35.2, 44.3], [-97.06138, 32.837, 35.1, 4] ],[ [-97.06326, 32.759, 35.4], [-97.06298, 32.755, 35.5], [-97.06153, 32.749, 35.6], [-97.06326, 32.759, 35.4] ]],\"spatialReference\" : {\"wkid\" : 4326}}"; - String jsonStringPg2 = "{ \"spatialReference\" : {\"wkid\" : 4326}, \"rings\" : [[[-118.35,32.81],[-118.42,32.806],[-118.511,32.892],[-118.35,32.81]]]}"; - String jsonStringPg3 = "{ \"spatialReference\": {\"layerName\":\"GAS_POINTS\",\"name\":null,\"sdesrid\":102100,\"wkid\":102100,\"wkt\":null}}"; - String jsonString2SpatialReferences = "{ \"spatialReference\": {\"layerName\":\"GAS_POINTS\",\"name\":null,\"sdesrid\":102100,\"wkid\":102100,\"wkt\":\"GEOGCS[\\\"GCS_WGS_1984\\\",DATUM[\\\"D_WGS_1984\\\",SPHEROID[\\\"WGS_1984\\\",6378137,298.257223563]],PRIMEM[\\\"Greenwich\\\",0],UNIT[\\\"Degree\\\",0.017453292519943295]]\"}}"; - String jsonString2SpatialReferences2 = "{ \"spatialReference\": {\"layerName\":\"GAS_POINTS\",\"name\":null,\"sdesrid\":10,\"wkid\":10,\"wkt\":\"GEOGCS[\\\"GCS_WGS_1984\\\",DATUM[\\\"D_WGS_1984\\\",SPHEROID[\\\"WGS_1984\\\",6378137,298.257223563]],PRIMEM[\\\"Greenwich\\\",0],UNIT[\\\"Degree\\\",0.017453292519943295]]\"}}"; - String jsonStringSR = "{\"wkid\" : 4326}"; - String jsonStringEnv = "{\"xmin\" : -109.55, \"ymin\" : 25.76, \"xmax\" : -86.39, \"ymax\" : 49.94,\"spatialReference\" : {\"wkid\" : 4326}}"; - String jsonStringHongKon = "{\"xmin\" : -122.55, \"ymin\" : 37.65, \"xmax\" : -122.28, \"ymax\" : 37.84,\"spatialReference\" : {\"wkid\" : 4326}}"; - @SuppressWarnings("unused") - String jsonStringWKT = " {\"wkt\" : \"GEOGCS[\\\"GCS_WGS_1984\\\",DATUM[\\\"D_WGS_1984\\\",SPHEROID[\\\"WGS_1984\\\",6378137,298.257223563]],PRIMEM[\\\"Greenwich\\\",0],UNIT[\\\"Degree\\\",0.017453292519943295]]\"}"; - String jsonStringInvalidWKID = "{\"x\":10.0,\"y\":20.0},\"spatialReference\":{\"wkid\":35253523}}"; - String jsonStringOregon = "{\"xmin\":7531831.219849482,\"ymin\":585702.9799639136,\"xmax\":7750143.589982405,\"ymax\":733289.6299999952,\"spatialReference\":{\"wkid\":102726}}"; - - JsonParser jsonParserPt = factory.createParser(jsonStringPt); - JsonParser jsonParserMpt = factory.createParser(jsonStringMpt); - JsonParser jsonParserMpt3D = factory.createParser(jsonStringMpt3D); - JsonParser jsonParserPl = factory.createParser(jsonStringPl); - JsonParser jsonParserPl3D = factory.createParser(jsonStringPl3D); - JsonParser jsonParserPg = factory.createParser(jsonStringPg); - JsonParser jsonParserPg3D = factory.createParser(jsonStringPg3D); - JsonParser jsonParserPg2 = factory.createParser(jsonStringPg2); - @SuppressWarnings("unused") - JsonParser jsonParserSR = factory.createParser(jsonStringSR); - JsonParser jsonParserEnv = factory.createParser(jsonStringEnv); - JsonParser jsonParserPg3 = factory.createParser(jsonStringPg3); - @SuppressWarnings("unused") - JsonParser jsonParserCrazy1 = factory.createParser(jsonString2SpatialReferences); - @SuppressWarnings("unused") - JsonParser jsonParserCrazy2 = factory.createParser(jsonString2SpatialReferences2); - JsonParser jsonParserInvalidWKID = factory.createParser(jsonStringInvalidWKID); - @SuppressWarnings("unused") - JsonParser jsonParseHongKon = factory.createParser(jsonStringHongKon); - JsonParser jsonParseOregon = factory.createParser(jsonStringOregon); - - MapGeometry mapGeom = GeometryEngine.jsonToGeometry(jsonParserPt); - // showProjectedGeometryInfo(mapGeom); - Assert.assertTrue(mapGeom.getSpatialReference().getID() == 102100); - - MapGeometry mapGeomOregon = GeometryEngine.jsonToGeometry(jsonParseOregon); - Assert.assertTrue(mapGeomOregon.getSpatialReference().getID() == 102726); - - mapGeom = GeometryEngine.jsonToGeometry(jsonParserMpt); - Assert.assertTrue(mapGeom.getSpatialReference().getID() == 4326); - - mapGeom = GeometryEngine.jsonToGeometry(jsonParserMpt3D); - Assert.assertTrue(mapGeom.getSpatialReference().getID() == 4326); - { - Assert.assertTrue(((MultiPoint) mapGeom.getGeometry()).getPoint(0).getX() == -97.06138); - Assert.assertTrue(((MultiPoint) mapGeom.getGeometry()).getPoint(0).getY() == 32.837); - Assert.assertTrue(((MultiPoint) mapGeom.getGeometry()).getPoint(3).getX() == -97.06127); - Assert.assertTrue(((MultiPoint) mapGeom.getGeometry()).getPoint(3).getY() == 32.832); - } - // showProjectedGeometryInfo(mapGeom); - - mapGeom = GeometryEngine.jsonToGeometry(jsonParserPl); - Assert.assertTrue(mapGeom.getSpatialReference().getID() == 4326); - // showProjectedGeometryInfo(mapGeom); - - mapGeom = GeometryEngine.jsonToGeometry(jsonParserPl3D); - { - // [[ [-97.06138,32.837,5], [-97.06133,32.836,6], - // [-97.06124,32.834,7], [-97.06127,32.832,8] ], - // [ [-97.06326,32.759], [-97.06298,32.755] ]]"; - Assert.assertTrue(((Polyline) mapGeom.getGeometry()).getPoint(0).getX() == -97.06138); - Assert.assertTrue(((Polyline) mapGeom.getGeometry()).getPoint(0).getY() == 32.837); - int lastIndex = ((Polyline) mapGeom.getGeometry()).getPointCount() - 1; - Assert.assertTrue(((Polyline) mapGeom.getGeometry()).getPoint(lastIndex).getX() == -97.06298);// -97.06153, - // 32.749 - Assert.assertTrue(((Polyline) mapGeom.getGeometry()).getPoint(lastIndex).getY() == 32.755); - int lastIndexFirstLine = ((Polyline) mapGeom.getGeometry()).getPathEnd(0) - 1; - Assert.assertTrue(((Polyline) mapGeom.getGeometry()).getPoint(lastIndexFirstLine).getX() == -97.06127);// -97.06153, - // 32.749 - Assert.assertTrue(((Polyline) mapGeom.getGeometry()).getPoint(lastIndexFirstLine).getY() == 32.832); - } - - mapGeom = GeometryEngine.jsonToGeometry(jsonParserPg); - Assert.assertTrue(mapGeom.getSpatialReference() == null); - - mapGeom = GeometryEngine.jsonToGeometry(jsonParserPg3D); - { - Assert.assertTrue(((Polygon) mapGeom.getGeometry()).getPoint(0).getX() == -97.06138); - Assert.assertTrue(((Polygon) mapGeom.getGeometry()).getPoint(0).getY() == 32.837); - int lastIndex = ((Polygon) mapGeom.getGeometry()).getPointCount() - 1; - Assert.assertTrue(((Polygon) mapGeom.getGeometry()).getPoint(lastIndex).getX() == -97.06153);// -97.06153, - // 32.749 - Assert.assertTrue(((Polygon) mapGeom.getGeometry()).getPoint(lastIndex).getY() == 32.749); - } - - mapGeom = GeometryEngine.jsonToGeometry(jsonParserPg2); - Assert.assertTrue(mapGeom.getSpatialReference().getID() == 4326); - // showProjectedGeometryInfo(mapGeom); - - mapGeom = GeometryEngine.jsonToGeometry(jsonParserPg3); - Assert.assertTrue(mapGeom.getSpatialReference().getID() == 102100); - // showProjectedGeometryInfo(mapGeom); - - // mapGeom = GeometryEngine.jsonToGeometry(jsonParserCrazy1); - // Assert.assertTrue(mapGeom.getSpatialReference().getText().equals("")); - // showProjectedGeometryInfo(mapGeom); - - mapGeom = GeometryEngine.jsonToGeometry(jsonParserEnv); - Assert.assertTrue(mapGeom.getSpatialReference().getID() == 4326); - // showProjectedGeometryInfo(mapGeom); - - try { - GeometryEngine.jsonToGeometry(jsonParserInvalidWKID); - } catch (Exception ex) { - Assert.assertTrue("Should not throw for invalid wkid", false); - } - } - - @Test - public void testMP2onCR175871() throws Exception { - Polygon pg = new Polygon(); - pg.startPath(-50, 10); - pg.lineTo(-50, 12); - pg.lineTo(-45, 12); - pg.lineTo(-45, 10); - - Polygon pg1 = new Polygon(); - pg1.startPath(-45, 10); - pg1.lineTo(-40, 10); - pg1.lineTo(-40, 8); - pg.add(pg1, false); - - SpatialReference spatialReference = SpatialReference.create(4326); - - try { - String jSonStr = GeometryEngine.geometryToJson(spatialReference, pg); - JsonFactory jf = new JsonFactory(); - - JsonParser jp = jf.createParser(jSonStr); - jp.nextToken(); - MapGeometry mg = GeometryEngine.jsonToGeometry(jp); - Geometry gm = mg.getGeometry(); - Assert.assertEquals(Geometry.Type.Polygon, gm.getType()); - Assert.assertTrue(mg.getSpatialReference().getID() == 4326); - - Polygon pgNew = (Polygon) gm; - - Assert.assertEquals(pgNew.getPathCount(), pg.getPathCount()); - Assert.assertEquals(pgNew.getPointCount(), pg.getPointCount()); - Assert.assertEquals(pgNew.getSegmentCount(), pg.getSegmentCount()); - - Assert.assertEquals(pgNew.getPoint(0).getX(), pg.getPoint(0).getX(), 0.000000001); - Assert.assertEquals(pgNew.getPoint(1).getX(), pg.getPoint(1).getX(), 0.000000001); - Assert.assertEquals(pgNew.getPoint(2).getX(), pg.getPoint(2).getX(), 0.000000001); - Assert.assertEquals(pgNew.getPoint(3).getX(), pg.getPoint(3).getX(), 0.000000001); - - Assert.assertEquals(pgNew.getPoint(0).getY(), pg.getPoint(0).getY(), 0.000000001); - Assert.assertEquals(pgNew.getPoint(1).getY(), pg.getPoint(1).getY(), 0.000000001); - Assert.assertEquals(pgNew.getPoint(2).getY(), pg.getPoint(2).getY(), 0.000000001); - Assert.assertEquals(pgNew.getPoint(3).getY(), pg.getPoint(3).getY(), 0.000000001); - } catch (Exception ex) { - String err = ex.getMessage(); - System.out.print(err); - throw ex; - } - } - - @Test - public static int fromJsonToWkid(JsonParser parser) throws JsonParseException, IOException { - int wkid = 0; - if (parser.getCurrentToken() != JsonToken.START_OBJECT) { - return 0; - } - - while (parser.nextToken() != JsonToken.END_OBJECT) { - String fieldName = parser.getCurrentName(); - - if ("wkid".equals(fieldName)) { - parser.nextToken(); - wkid = parser.getIntValue(); - } - } - return wkid; - } - - @SuppressWarnings("unused") - private static void showProjectedGeometryInfo(MapGeometry mapGeom) { - System.out.println("\n"); - MapGeometry geom = mapGeom; - // while ((geom = geomCursor.next()) != null) { - - if (geom.getGeometry() instanceof Point) { - Point pnt = (Point) geom.getGeometry(); - System.out.println("Point(" + pnt.getX() + " , " + pnt.getY() + ")"); - if (geom.getSpatialReference() == null) { - System.out.println("No spatial reference"); - } else { - System.out.println("wkid: " + geom.getSpatialReference().getID()); - } - - } else if (geom.getGeometry() instanceof MultiPoint) { - MultiPoint mp = (MultiPoint) geom.getGeometry(); - System.out.println("Multipoint has " + mp.getPointCount() + " points."); - - System.out.println("wkid: " + geom.getSpatialReference().getID()); - - } else if (geom.getGeometry() instanceof Polygon) { - Polygon mp = (Polygon) geom.getGeometry(); - System.out.println("Polygon has " + mp.getPointCount() + " points and " + mp.getPathCount() + " parts."); - if (mp.getPathCount() > 1) { - System.out.println("Part start of 2nd segment : " + mp.getPathStart(1)); - System.out.println("Part end of 2nd segment : " + mp.getPathEnd(1)); - System.out.println("Part size of 2nd segment : " + mp.getPathSize(1)); - - int start = mp.getPathStart(1); - int end = mp.getPathEnd(1); - for (int i = start; i < end; i++) { - Point pp = mp.getPoint(i); - System.out.println("Point(" + i + ") = (" + pp.getX() + ", " + pp.getY() + ")"); - } - } - System.out.println("wkid: " + geom.getSpatialReference().getID()); - - } else if (geom.getGeometry() instanceof Polyline) { - Polyline mp = (Polyline) geom.getGeometry(); - System.out.println("Polyline has " + mp.getPointCount() + " points and " + mp.getPathCount() + " parts."); - System.out.println("Part start of 2nd segment : " + mp.getPathStart(1)); - System.out.println("Part end of 2nd segment : " + mp.getPathEnd(1)); - System.out.println("Part size of 2nd segment : " + mp.getPathSize(1)); - int start = mp.getPathStart(1); - int end = mp.getPathEnd(1); - for (int i = start; i < end; i++) { - Point pp = mp.getPoint(i); - System.out.println("Point(" + i + ") = (" + pp.getX() + ", " + pp.getY() + ")"); - } - - System.out.println("wkid: " + geom.getSpatialReference().getID()); - } - } - - @Test - public void testGeometryToJSON() { - Polygon geom = new Polygon(); - geom.startPath(new Point(-113, 34)); - geom.lineTo(new Point(-105, 34)); - geom.lineTo(new Point(-108, 40)); - - String outputPolygon1 = GeometryEngine.geometryToJson(-1, geom);// Test - // WKID - // == -1 - // System.out.println("Geom JSON STRING is" + outputPolygon1); - String correctPolygon1 = "{\"rings\":[[[-113,34],[-105,34],[-108,40],[-113,34]]]}"; - - assertEquals(correctPolygon1, outputPolygon1); - - String outputPolygon2 = GeometryEngine.geometryToJson(4326, geom); - // System.out.println("Geom JSON STRING is" + outputPolygon2); - - String correctPolygon2 = "{\"rings\":[[[-113,34],[-105,34],[-108,40],[-113,34]]],\"spatialReference\":{\"wkid\":4326}}"; - assertEquals(correctPolygon2, outputPolygon2); - } - - @Test - public void testGeometryToJSONOldID() throws Exception {// CR - Polygon geom = new Polygon(); - geom.startPath(new Point(-113, 34)); - geom.lineTo(new Point(-105, 34)); - geom.lineTo(new Point(-108, 40)); - String outputPolygon = GeometryEngine.geometryToJson(SpatialReference.create(3857), geom);// Test - // WKID - // == - // -1 - String correctPolygon = "{\"rings\":[[[-113,34],[-105,34],[-108,40],[-113,34]]],\"spatialReference\":{\"wkid\":102100,\"latestWkid\":3857}}"; - assertTrue(outputPolygon.equals(correctPolygon)); - JsonFactory jf = new JsonFactory(); - JsonParser jp = jf.createParser(outputPolygon); - jp.nextToken(); - MapGeometry mg = GeometryEngine.jsonToGeometry(jp); - @SuppressWarnings("unused") - int srId = mg.getSpatialReference().getID(); - @SuppressWarnings("unused") - int srOldId = mg.getSpatialReference().getOldID(); - Assert.assertTrue(mg.getSpatialReference().getID() == 3857); - Assert.assertTrue(mg.getSpatialReference().getLatestID() == 3857); - Assert.assertTrue(mg.getSpatialReference().getOldID() == 102100); - } + JsonFactory factory = new JsonFactory(); + SpatialReference spatialReferenceWebMerc1 = SpatialReference.create(102100); + SpatialReference spatialReferenceWebMerc2 = SpatialReference.create(spatialReferenceWebMerc1.getLatestID()); + SpatialReference spatialReferenceWGS84 = SpatialReference.create(4326); + + @Override + protected void setUp() throws Exception { + super.setUp(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + } + + @Test + public void test3DPoint() throws JsonParseException, IOException { + String jsonString3DPt = "{\"x\" : -118.15, \"y\" : 33.80, \"z\" : 10.0, \"spatialReference\" : {\"wkid\" : 4326}}"; + + JsonParser jsonParser3DPt = factory.createParser(jsonString3DPt); + MapGeometry point3DMP = GeometryEngine.jsonToGeometry(jsonParser3DPt); + assertTrue(-118.15 == ((Point) point3DMP.getGeometry()).getX()); + assertTrue(33.80 == ((Point) point3DMP.getGeometry()).getY()); + assertTrue(spatialReferenceWGS84.getID() == point3DMP.getSpatialReference().getID()); + } + + @Test + public void test3DPoint1() throws JsonParseException, IOException { + Point point1 = new Point(10.0, 20.0); + Point pointEmpty = new Point(); + { + JsonParser pointWebMerc1Parser = factory + .createParser(GeometryEngine.geometryToJson(spatialReferenceWebMerc1, point1)); + MapGeometry pointWebMerc1MP = GeometryEngine.jsonToGeometry(pointWebMerc1Parser); + assertTrue(point1.getX() == ((Point) pointWebMerc1MP.getGeometry()).getX()); + assertTrue(point1.getY() == ((Point) pointWebMerc1MP.getGeometry()).getY()); + int srIdOri = spatialReferenceWebMerc1.getID(); + int srIdAfter = pointWebMerc1MP.getSpatialReference().getID(); + assertTrue(srIdOri == srIdAfter || srIdAfter == 3857); + + pointWebMerc1Parser = factory.createParser(GeometryEngine.geometryToJson(null, point1)); + pointWebMerc1MP = GeometryEngine.jsonToGeometry(pointWebMerc1Parser); + assertTrue(null == pointWebMerc1MP.getSpatialReference()); + + String pointEmptyString = GeometryEngine.geometryToJson(spatialReferenceWebMerc1, pointEmpty); + pointWebMerc1Parser = factory.createParser(pointEmptyString); + + pointWebMerc1MP = GeometryEngine.jsonToGeometry(pointWebMerc1Parser); + assertTrue(pointWebMerc1MP.getGeometry().isEmpty()); + int srIdOri2 = spatialReferenceWebMerc1.getID(); + int srIdAfter2 = pointWebMerc1MP.getSpatialReference().getID(); + assertTrue(srIdOri2 == srIdAfter2 || srIdAfter2 == 3857); + } + } + + @Test + public void test3DPoint2() throws JsonParseException, IOException { + { + Point point1 = new Point(10.0, 20.0); + JsonParser pointWebMerc2Parser = factory + .createParser(GeometryEngine.geometryToJson(spatialReferenceWebMerc2, point1)); + MapGeometry pointWebMerc2MP = GeometryEngine.jsonToGeometry(pointWebMerc2Parser); + assertTrue(point1.getX() == ((Point) pointWebMerc2MP.getGeometry()).getX()); + assertTrue(point1.getY() == ((Point) pointWebMerc2MP.getGeometry()).getY()); + assertTrue(spatialReferenceWebMerc2.getLatestID() == pointWebMerc2MP.getSpatialReference().getLatestID()); + } + } + + @Test + public void test3DPoint3() throws JsonParseException, IOException { + { + Point point1 = new Point(10.0, 20.0); + JsonParser pointWgs84Parser = factory + .createParser(GeometryEngine.geometryToJson(spatialReferenceWGS84, point1)); + MapGeometry pointWgs84MP = GeometryEngine.jsonToGeometry(pointWgs84Parser); + assertTrue(point1.getX() == ((Point) pointWgs84MP.getGeometry()).getX()); + assertTrue(point1.getY() == ((Point) pointWgs84MP.getGeometry()).getY()); + assertTrue(spatialReferenceWGS84.getID() == pointWgs84MP.getSpatialReference().getID()); + } + } + + @Test + public void testMultiPoint() throws JsonParseException, IOException { + MultiPoint multiPoint1 = new MultiPoint(); + multiPoint1.add(-97.06138, 32.837); + multiPoint1.add(-97.06133, 32.836); + multiPoint1.add(-97.06124, 32.834); + multiPoint1.add(-97.06127, 32.832); + + { + JsonParser mPointWgs84Parser = factory + .createParser(GeometryEngine.geometryToJson(spatialReferenceWGS84, multiPoint1)); + MapGeometry mPointWgs84MP = GeometryEngine.jsonToGeometry(mPointWgs84Parser); + assertTrue(multiPoint1.getPointCount() == ((MultiPoint) mPointWgs84MP.getGeometry()).getPointCount()); + assertTrue(multiPoint1.getPoint(0).getX() == ((MultiPoint) mPointWgs84MP.getGeometry()).getPoint(0).getX()); + assertTrue(multiPoint1.getPoint(0).getY() == ((MultiPoint) mPointWgs84MP.getGeometry()).getPoint(0).getY()); + int lastIndex = multiPoint1.getPointCount() - 1; + assertTrue(multiPoint1.getPoint(lastIndex).getX() == ((MultiPoint) mPointWgs84MP.getGeometry()) + .getPoint(lastIndex).getX()); + assertTrue(multiPoint1.getPoint(lastIndex).getY() == ((MultiPoint) mPointWgs84MP.getGeometry()) + .getPoint(lastIndex).getY()); + + assertTrue(spatialReferenceWGS84.getID() == mPointWgs84MP.getSpatialReference().getID()); + + MultiPoint mPointEmpty = new MultiPoint(); + String mPointEmptyString = GeometryEngine.geometryToJson(spatialReferenceWGS84, mPointEmpty); + mPointWgs84Parser = factory.createParser(mPointEmptyString); + + mPointWgs84MP = GeometryEngine.jsonToGeometry(mPointWgs84Parser); + assertTrue(mPointWgs84MP.getGeometry().isEmpty()); + assertTrue(spatialReferenceWGS84.getID() == mPointWgs84MP.getSpatialReference().getID()); + + } + } + + @Test + public void testPolyline() throws JsonParseException, IOException { + Polyline polyline = new Polyline(); + polyline.startPath(-97.06138, 32.837); + polyline.lineTo(-97.06133, 32.836); + polyline.lineTo(-97.06124, 32.834); + polyline.lineTo(-97.06127, 32.832); + + polyline.startPath(-97.06326, 32.759); + polyline.lineTo(-97.06298, 32.755); + + { + JsonParser polylinePathsWgs84Parser = factory + .createParser(GeometryEngine.geometryToJson(spatialReferenceWGS84, polyline)); + MapGeometry mPolylineWGS84MP = GeometryEngine.jsonToGeometry(polylinePathsWgs84Parser); + + assertTrue(polyline.getPointCount() == ((Polyline) mPolylineWGS84MP.getGeometry()).getPointCount()); + assertTrue(polyline.getPoint(0).getX() == ((Polyline) mPolylineWGS84MP.getGeometry()).getPoint(0).getX()); + assertTrue(polyline.getPoint(0).getY() == ((Polyline) mPolylineWGS84MP.getGeometry()).getPoint(0).getY()); + + assertTrue(polyline.getPathCount() == ((Polyline) mPolylineWGS84MP.getGeometry()).getPathCount()); + assertTrue(polyline.getSegmentCount() == ((Polyline) mPolylineWGS84MP.getGeometry()).getSegmentCount()); + assertTrue(polyline.getSegmentCount(0) == ((Polyline) mPolylineWGS84MP.getGeometry()).getSegmentCount(0)); + assertTrue(polyline.getSegmentCount(1) == ((Polyline) mPolylineWGS84MP.getGeometry()).getSegmentCount(1)); + + int lastIndex = polyline.getPointCount() - 1; + assertTrue(polyline.getPoint(lastIndex).getX() == ((Polyline) mPolylineWGS84MP.getGeometry()) + .getPoint(lastIndex).getX()); + assertTrue(polyline.getPoint(lastIndex).getY() == ((Polyline) mPolylineWGS84MP.getGeometry()) + .getPoint(lastIndex).getY()); + + assertTrue(spatialReferenceWGS84.getID() == mPolylineWGS84MP.getSpatialReference().getID()); + + Polyline emptyPolyline = new Polyline(); + String emptyString = GeometryEngine.geometryToJson(spatialReferenceWGS84, emptyPolyline); + mPolylineWGS84MP = GeometryEngine.jsonToGeometry(factory.createParser(emptyString)); + assertTrue(mPolylineWGS84MP.getGeometry().isEmpty()); + assertTrue(spatialReferenceWGS84.getID() == mPolylineWGS84MP.getSpatialReference().getID()); + } + } + + @Test + public void testPolygon() throws JsonParseException, IOException { + Polygon polygon = new Polygon(); + polygon.startPath(-97.06138, 32.837); + polygon.lineTo(-97.06133, 32.836); + polygon.lineTo(-97.06124, 32.834); + polygon.lineTo(-97.06127, 32.832); + + polygon.startPath(-97.06326, 32.759); + polygon.lineTo(-97.06298, 32.755); + + { + JsonParser polygonPathsWgs84Parser = factory + .createParser(GeometryEngine.geometryToJson(spatialReferenceWGS84, polygon)); + MapGeometry mPolygonWGS84MP = GeometryEngine.jsonToGeometry(polygonPathsWgs84Parser); + + assertTrue(polygon.getPointCount() + 1 == ((Polygon) mPolygonWGS84MP.getGeometry()).getPointCount()); + assertTrue(polygon.getPoint(0).getX() == ((Polygon) mPolygonWGS84MP.getGeometry()).getPoint(0).getX()); + assertTrue(polygon.getPoint(0).getY() == ((Polygon) mPolygonWGS84MP.getGeometry()).getPoint(0).getY()); + + assertTrue(polygon.getPathCount() == ((Polygon) mPolygonWGS84MP.getGeometry()).getPathCount()); + assertTrue(polygon.getSegmentCount() + 1 == ((Polygon) mPolygonWGS84MP.getGeometry()).getSegmentCount()); + assertTrue(polygon.getSegmentCount(0) == ((Polygon) mPolygonWGS84MP.getGeometry()).getSegmentCount(0)); + assertTrue(polygon.getSegmentCount(1) + 1 == ((Polygon) mPolygonWGS84MP.getGeometry()).getSegmentCount(1)); + + int lastIndex = polygon.getPointCount() - 1; + assertTrue(polygon.getPoint(lastIndex).getX() == ((Polygon) mPolygonWGS84MP.getGeometry()) + .getPoint(lastIndex).getX()); + assertTrue(polygon.getPoint(lastIndex).getY() == ((Polygon) mPolygonWGS84MP.getGeometry()) + .getPoint(lastIndex).getY()); + + assertTrue(spatialReferenceWGS84.getID() == mPolygonWGS84MP.getSpatialReference().getID()); + + Polygon emptyPolygon = new Polygon(); + String emptyPolygonString = GeometryEngine.geometryToJson(spatialReferenceWGS84, emptyPolygon); + polygonPathsWgs84Parser = factory.createParser(emptyPolygonString); + mPolygonWGS84MP = GeometryEngine.jsonToGeometry(polygonPathsWgs84Parser); + + assertTrue(mPolygonWGS84MP.getGeometry().isEmpty()); + assertTrue(spatialReferenceWGS84.getID() == mPolygonWGS84MP.getSpatialReference().getID()); + } + } + + @Test + public void testEnvelope() throws JsonParseException, IOException { + Envelope envelope = new Envelope(); + envelope.setCoords(-109.55, 25.76, -86.39, 49.94); + + { + JsonParser envelopeWGS84Parser = factory + .createParser(GeometryEngine.geometryToJson(spatialReferenceWGS84, envelope)); + MapGeometry envelopeWGS84MP = GeometryEngine.jsonToGeometry(envelopeWGS84Parser); + assertTrue(envelope.isEmpty() == envelopeWGS84MP.getGeometry().isEmpty()); + assertTrue(envelope.getXMax() == ((Envelope) envelopeWGS84MP.getGeometry()).getXMax()); + assertTrue(envelope.getYMax() == ((Envelope) envelopeWGS84MP.getGeometry()).getYMax()); + assertTrue(envelope.getXMin() == ((Envelope) envelopeWGS84MP.getGeometry()).getXMin()); + assertTrue(envelope.getYMin() == ((Envelope) envelopeWGS84MP.getGeometry()).getYMin()); + assertTrue(spatialReferenceWGS84.getID() == envelopeWGS84MP.getSpatialReference().getID()); + + Envelope emptyEnvelope = new Envelope(); + String emptyEnvString = GeometryEngine.geometryToJson(spatialReferenceWGS84, emptyEnvelope); + envelopeWGS84Parser = factory.createParser(emptyEnvString); + envelopeWGS84MP = GeometryEngine.jsonToGeometry(envelopeWGS84Parser); + + assertTrue(envelopeWGS84MP.getGeometry().isEmpty()); + assertTrue(spatialReferenceWGS84.getID() == envelopeWGS84MP.getSpatialReference().getID()); + } + } + + @Test + public void testCR181369() throws JsonParseException, IOException { + // CR181369 + { + String jsonStringPointAndWKT = "{\"x\":10.0,\"y\":20.0,\"spatialReference\":{\"wkt\" : \"PROJCS[\\\"NAD83_UTM_zone_15N\\\",GEOGCS[\\\"GCS_North_American_1983\\\",DATUM[\\\"D_North_American_1983\\\",SPHEROID[\\\"GRS_1980\\\",6378137.0,298.257222101]],PRIMEM[\\\"Greenwich\\\",0.0],UNIT[\\\"Degree\\\",0.0174532925199433]],PROJECTION[\\\"Transverse_Mercator\\\"],PARAMETER[\\\"false_easting\\\",500000.0],PARAMETER[\\\"false_northing\\\",0.0],PARAMETER[\\\"central_meridian\\\",-93.0],PARAMETER[\\\"scale_factor\\\",0.9996],PARAMETER[\\\"latitude_of_origin\\\",0.0],UNIT[\\\"Meter\\\",1.0]]\"} }"; + JsonParser jsonParserPointAndWKT = factory.createParser(jsonStringPointAndWKT); + MapGeometry mapGeom2 = GeometryEngine.jsonToGeometry(jsonParserPointAndWKT); + String jsonStringPointAndWKT2 = GeometryEngine.geometryToJson(mapGeom2.getSpatialReference(), + mapGeom2.getGeometry()); + JsonParser jsonParserPointAndWKT2 = factory.createParser(jsonStringPointAndWKT2); + MapGeometry mapGeom3 = GeometryEngine.jsonToGeometry(jsonParserPointAndWKT2); + assertTrue(((Point) mapGeom2.getGeometry()).getX() == ((Point) mapGeom3.getGeometry()).getX()); + assertTrue(((Point) mapGeom2.getGeometry()).getY() == ((Point) mapGeom3.getGeometry()).getY()); + assertTrue(mapGeom2.getSpatialReference().getText().equals(mapGeom3.getSpatialReference().getText())); + assertTrue(mapGeom2.getSpatialReference().getID() == mapGeom3.getSpatialReference().getID()); + } + } + + @Test + public void testSpatialRef() throws JsonParseException, IOException { + // String jsonStringPt = + // "{\"x\":-20037508.342787,\"y\":20037508.342787},\"spatialReference\":{\"wkid\":102100}}"; + String jsonStringPt = "{\"x\":10.0,\"y\":20.0,\"spatialReference\":{\"wkid\": 102100}}";// 102100 + @SuppressWarnings("unused") + String jsonStringPt2 = "{\"x\":10.0,\"y\":20.0,\"spatialReference\":{\"wkid\":4326}}"; + String jsonStringMpt = "{ \"points\" : [ [-97.06138,32.837], [-97.06133,32.836], [-97.06124,32.834], [-97.06127,32.832] ], \"spatialReference\" : {\"wkid\" : 4326}}";// 4326 + String jsonStringMpt3D = "{\"hasZs\" : true,\"points\" : [ [-97.06138,32.837,35.0], [-97.06133,32.836,35.1], [-97.06124,32.834,35.2], [-97.06127,32.832,35.3] ],\"spatialReference\" : {\"wkid\" : 4326}}"; + String jsonStringPl = "{\"paths\" : [ [ [-97.06138,32.837], [-97.06133,32.836], [-97.06124,32.834], [-97.06127,32.832] ], [ [-97.06326,32.759], [-97.06298,32.755] ]],\"spatialReference\" : {\"wkid\" : 4326}}"; + String jsonStringPl3D = "{\"hasMs\" : true,\"paths\" : [[ [-97.06138,32.837,5], [-97.06133,32.836,6], [-97.06124,32.834,7], [-97.06127,32.832,8] ],[ [-97.06326,32.759], [-97.06298,32.755] ]],\"spatialReference\" : {\"wkid\" : 4326}}"; + String jsonStringPg = "{ \"rings\" :[ [ [-97.06138,32.837], [-97.06133,32.836], [-97.06124,32.834], [-97.06127,32.832], [-97.06138,32.837] ], [ [-97.06326,32.759], [-97.06298,32.755], [-97.06153,32.749], [-97.06326,32.759] ]], \"spatialReference\" : {\"wkt\" : \"\"}}"; + String jsonStringPg3D = "{\"hasZs\" : true,\"hasMs\" : true,\"rings\" : [ [ [-97.06138, 32.837, 35.1, 4], [-97.06133, 32.836, 35.2, 4.1], [-97.06124, 32.834, 35.3, 4.2], [-97.06127, 32.832, 35.2, 44.3], [-97.06138, 32.837, 35.1, 4] ],[ [-97.06326, 32.759, 35.4], [-97.06298, 32.755, 35.5], [-97.06153, 32.749, 35.6], [-97.06326, 32.759, 35.4] ]],\"spatialReference\" : {\"wkid\" : 4326}}"; + String jsonStringPg2 = "{ \"spatialReference\" : {\"wkid\" : 4326}, \"rings\" : [[[-118.35,32.81],[-118.42,32.806],[-118.511,32.892],[-118.35,32.81]]]}"; + String jsonStringPg3 = "{ \"spatialReference\": {\"layerName\":\"GAS_POINTS\",\"name\":null,\"sdesrid\":102100,\"wkid\":102100,\"wkt\":null}}"; + String jsonString2SpatialReferences = "{ \"spatialReference\": {\"layerName\":\"GAS_POINTS\",\"name\":null,\"sdesrid\":102100,\"wkid\":102100,\"wkt\":\"GEOGCS[\\\"GCS_WGS_1984\\\",DATUM[\\\"D_WGS_1984\\\",SPHEROID[\\\"WGS_1984\\\",6378137,298.257223563]],PRIMEM[\\\"Greenwich\\\",0],UNIT[\\\"Degree\\\",0.017453292519943295]]\"}}"; + String jsonString2SpatialReferences2 = "{ \"spatialReference\": {\"layerName\":\"GAS_POINTS\",\"name\":null,\"sdesrid\":10,\"wkid\":10,\"wkt\":\"GEOGCS[\\\"GCS_WGS_1984\\\",DATUM[\\\"D_WGS_1984\\\",SPHEROID[\\\"WGS_1984\\\",6378137,298.257223563]],PRIMEM[\\\"Greenwich\\\",0],UNIT[\\\"Degree\\\",0.017453292519943295]]\"}}"; + String jsonStringSR = "{\"wkid\" : 4326}"; + String jsonStringEnv = "{\"xmin\" : -109.55, \"ymin\" : 25.76, \"xmax\" : -86.39, \"ymax\" : 49.94,\"spatialReference\" : {\"wkid\" : 4326}}"; + String jsonStringHongKon = "{\"xmin\" : -122.55, \"ymin\" : 37.65, \"xmax\" : -122.28, \"ymax\" : 37.84,\"spatialReference\" : {\"wkid\" : 4326}}"; + @SuppressWarnings("unused") + String jsonStringWKT = " {\"wkt\" : \"GEOGCS[\\\"GCS_WGS_1984\\\",DATUM[\\\"D_WGS_1984\\\",SPHEROID[\\\"WGS_1984\\\",6378137,298.257223563]],PRIMEM[\\\"Greenwich\\\",0],UNIT[\\\"Degree\\\",0.017453292519943295]]\"}"; + String jsonStringInvalidWKID = "{\"x\":10.0,\"y\":20.0},\"spatialReference\":{\"wkid\":35253523}}"; + String jsonStringOregon = "{\"xmin\":7531831.219849482,\"ymin\":585702.9799639136,\"xmax\":7750143.589982405,\"ymax\":733289.6299999952,\"spatialReference\":{\"wkid\":102726}}"; + + JsonParser jsonParserPt = factory.createParser(jsonStringPt); + JsonParser jsonParserMpt = factory.createParser(jsonStringMpt); + JsonParser jsonParserMpt3D = factory.createParser(jsonStringMpt3D); + JsonParser jsonParserPl = factory.createParser(jsonStringPl); + JsonParser jsonParserPl3D = factory.createParser(jsonStringPl3D); + JsonParser jsonParserPg = factory.createParser(jsonStringPg); + JsonParser jsonParserPg3D = factory.createParser(jsonStringPg3D); + JsonParser jsonParserPg2 = factory.createParser(jsonStringPg2); + @SuppressWarnings("unused") + JsonParser jsonParserSR = factory.createParser(jsonStringSR); + JsonParser jsonParserEnv = factory.createParser(jsonStringEnv); + JsonParser jsonParserPg3 = factory.createParser(jsonStringPg3); + @SuppressWarnings("unused") + JsonParser jsonParserCrazy1 = factory.createParser(jsonString2SpatialReferences); + @SuppressWarnings("unused") + JsonParser jsonParserCrazy2 = factory.createParser(jsonString2SpatialReferences2); + JsonParser jsonParserInvalidWKID = factory.createParser(jsonStringInvalidWKID); + @SuppressWarnings("unused") + JsonParser jsonParseHongKon = factory.createParser(jsonStringHongKon); + JsonParser jsonParseOregon = factory.createParser(jsonStringOregon); + + MapGeometry mapGeom = GeometryEngine.jsonToGeometry(jsonParserPt); + // showProjectedGeometryInfo(mapGeom); + Assert.assertTrue(mapGeom.getSpatialReference().getID() == 102100); + + MapGeometry mapGeomOregon = GeometryEngine.jsonToGeometry(jsonParseOregon); + Assert.assertTrue(mapGeomOregon.getSpatialReference().getID() == 102726); + + mapGeom = GeometryEngine.jsonToGeometry(jsonParserMpt); + Assert.assertTrue(mapGeom.getSpatialReference().getID() == 4326); + + mapGeom = GeometryEngine.jsonToGeometry(jsonParserMpt3D); + Assert.assertTrue(mapGeom.getSpatialReference().getID() == 4326); + { + Assert.assertTrue(((MultiPoint) mapGeom.getGeometry()).getPoint(0).getX() == -97.06138); + Assert.assertTrue(((MultiPoint) mapGeom.getGeometry()).getPoint(0).getY() == 32.837); + Assert.assertTrue(((MultiPoint) mapGeom.getGeometry()).getPoint(3).getX() == -97.06127); + Assert.assertTrue(((MultiPoint) mapGeom.getGeometry()).getPoint(3).getY() == 32.832); + } + // showProjectedGeometryInfo(mapGeom); + + mapGeom = GeometryEngine.jsonToGeometry(jsonParserPl); + Assert.assertTrue(mapGeom.getSpatialReference().getID() == 4326); + // showProjectedGeometryInfo(mapGeom); + + mapGeom = GeometryEngine.jsonToGeometry(jsonParserPl3D); + { + // [[ [-97.06138,32.837,5], [-97.06133,32.836,6], + // [-97.06124,32.834,7], [-97.06127,32.832,8] ], + // [ [-97.06326,32.759], [-97.06298,32.755] ]]"; + Assert.assertTrue(((Polyline) mapGeom.getGeometry()).getPoint(0).getX() == -97.06138); + Assert.assertTrue(((Polyline) mapGeom.getGeometry()).getPoint(0).getY() == 32.837); + int lastIndex = ((Polyline) mapGeom.getGeometry()).getPointCount() - 1; + Assert.assertTrue(((Polyline) mapGeom.getGeometry()).getPoint(lastIndex).getX() == -97.06298);// -97.06153, + // 32.749 + Assert.assertTrue(((Polyline) mapGeom.getGeometry()).getPoint(lastIndex).getY() == 32.755); + int lastIndexFirstLine = ((Polyline) mapGeom.getGeometry()).getPathEnd(0) - 1; + Assert.assertTrue(((Polyline) mapGeom.getGeometry()).getPoint(lastIndexFirstLine).getX() == -97.06127);// -97.06153, + // 32.749 + Assert.assertTrue(((Polyline) mapGeom.getGeometry()).getPoint(lastIndexFirstLine).getY() == 32.832); + } + + mapGeom = GeometryEngine.jsonToGeometry(jsonParserPg); + Assert.assertTrue(mapGeom.getSpatialReference() == null); + + mapGeom = GeometryEngine.jsonToGeometry(jsonParserPg3D); + { + Assert.assertTrue(((Polygon) mapGeom.getGeometry()).getPoint(0).getX() == -97.06138); + Assert.assertTrue(((Polygon) mapGeom.getGeometry()).getPoint(0).getY() == 32.837); + int lastIndex = ((Polygon) mapGeom.getGeometry()).getPointCount() - 1; + Assert.assertTrue(((Polygon) mapGeom.getGeometry()).getPoint(lastIndex).getX() == -97.06153);// -97.06153, + // 32.749 + Assert.assertTrue(((Polygon) mapGeom.getGeometry()).getPoint(lastIndex).getY() == 32.749); + } + + mapGeom = GeometryEngine.jsonToGeometry(jsonParserPg2); + Assert.assertTrue(mapGeom.getSpatialReference().getID() == 4326); + // showProjectedGeometryInfo(mapGeom); + + mapGeom = GeometryEngine.jsonToGeometry(jsonParserPg3); + Assert.assertTrue(mapGeom.getSpatialReference().getID() == 102100); + // showProjectedGeometryInfo(mapGeom); + + // mapGeom = GeometryEngine.jsonToGeometry(jsonParserCrazy1); + // Assert.assertTrue(mapGeom.getSpatialReference().getText().equals("")); + // showProjectedGeometryInfo(mapGeom); + + mapGeom = GeometryEngine.jsonToGeometry(jsonParserEnv); + Assert.assertTrue(mapGeom.getSpatialReference().getID() == 4326); + // showProjectedGeometryInfo(mapGeom); + + try { + GeometryEngine.jsonToGeometry(jsonParserInvalidWKID); + } catch (Exception ex) { + Assert.assertTrue("Should not throw for invalid wkid", false); + } + } + + @Test + public void testMP2onCR175871() throws Exception { + Polygon pg = new Polygon(); + pg.startPath(-50, 10); + pg.lineTo(-50, 12); + pg.lineTo(-45, 12); + pg.lineTo(-45, 10); + + Polygon pg1 = new Polygon(); + pg1.startPath(-45, 10); + pg1.lineTo(-40, 10); + pg1.lineTo(-40, 8); + pg.add(pg1, false); + + SpatialReference spatialReference = SpatialReference.create(4326); + + try { + String jSonStr = GeometryEngine.geometryToJson(spatialReference, pg); + JsonFactory jf = new JsonFactory(); + + JsonParser jp = jf.createParser(jSonStr); + jp.nextToken(); + MapGeometry mg = GeometryEngine.jsonToGeometry(jp); + Geometry gm = mg.getGeometry(); + Assert.assertEquals(Geometry.Type.Polygon, gm.getType()); + Assert.assertTrue(mg.getSpatialReference().getID() == 4326); + + Polygon pgNew = (Polygon) gm; + + Assert.assertEquals(pgNew.getPathCount(), pg.getPathCount()); + Assert.assertEquals(pgNew.getPointCount(), pg.getPointCount()); + Assert.assertEquals(pgNew.getSegmentCount(), pg.getSegmentCount()); + + Assert.assertEquals(pgNew.getPoint(0).getX(), pg.getPoint(0).getX(), 0.000000001); + Assert.assertEquals(pgNew.getPoint(1).getX(), pg.getPoint(1).getX(), 0.000000001); + Assert.assertEquals(pgNew.getPoint(2).getX(), pg.getPoint(2).getX(), 0.000000001); + Assert.assertEquals(pgNew.getPoint(3).getX(), pg.getPoint(3).getX(), 0.000000001); + + Assert.assertEquals(pgNew.getPoint(0).getY(), pg.getPoint(0).getY(), 0.000000001); + Assert.assertEquals(pgNew.getPoint(1).getY(), pg.getPoint(1).getY(), 0.000000001); + Assert.assertEquals(pgNew.getPoint(2).getY(), pg.getPoint(2).getY(), 0.000000001); + Assert.assertEquals(pgNew.getPoint(3).getY(), pg.getPoint(3).getY(), 0.000000001); + } catch (Exception ex) { + String err = ex.getMessage(); + System.out.print(err); + throw ex; + } + } + + @Test + public static int fromJsonToWkid(JsonParser parser) throws JsonParseException, IOException { + int wkid = 0; + if (parser.getCurrentToken() != JsonToken.START_OBJECT) { + return 0; + } + + while (parser.nextToken() != JsonToken.END_OBJECT) { + String fieldName = parser.getCurrentName(); + + if ("wkid".equals(fieldName)) { + parser.nextToken(); + wkid = parser.getIntValue(); + } + } + return wkid; + } + + @SuppressWarnings("unused") + private static void showProjectedGeometryInfo(MapGeometry mapGeom) { + System.out.println("\n"); + MapGeometry geom = mapGeom; + // while ((geom = geomCursor.next()) != null) { + + if (geom.getGeometry() instanceof Point) { + Point pnt = (Point) geom.getGeometry(); + System.out.println("Point(" + pnt.getX() + " , " + pnt.getY() + ")"); + if (geom.getSpatialReference() == null) { + System.out.println("No spatial reference"); + } else { + System.out.println("wkid: " + geom.getSpatialReference().getID()); + } + + } else if (geom.getGeometry() instanceof MultiPoint) { + MultiPoint mp = (MultiPoint) geom.getGeometry(); + System.out.println("Multipoint has " + mp.getPointCount() + " points."); + + System.out.println("wkid: " + geom.getSpatialReference().getID()); + + } else if (geom.getGeometry() instanceof Polygon) { + Polygon mp = (Polygon) geom.getGeometry(); + System.out.println("Polygon has " + mp.getPointCount() + " points and " + mp.getPathCount() + " parts."); + if (mp.getPathCount() > 1) { + System.out.println("Part start of 2nd segment : " + mp.getPathStart(1)); + System.out.println("Part end of 2nd segment : " + mp.getPathEnd(1)); + System.out.println("Part size of 2nd segment : " + mp.getPathSize(1)); + + int start = mp.getPathStart(1); + int end = mp.getPathEnd(1); + for (int i = start; i < end; i++) { + Point pp = mp.getPoint(i); + System.out.println("Point(" + i + ") = (" + pp.getX() + ", " + pp.getY() + ")"); + } + } + System.out.println("wkid: " + geom.getSpatialReference().getID()); + + } else if (geom.getGeometry() instanceof Polyline) { + Polyline mp = (Polyline) geom.getGeometry(); + System.out.println("Polyline has " + mp.getPointCount() + " points and " + mp.getPathCount() + " parts."); + System.out.println("Part start of 2nd segment : " + mp.getPathStart(1)); + System.out.println("Part end of 2nd segment : " + mp.getPathEnd(1)); + System.out.println("Part size of 2nd segment : " + mp.getPathSize(1)); + int start = mp.getPathStart(1); + int end = mp.getPathEnd(1); + for (int i = start; i < end; i++) { + Point pp = mp.getPoint(i); + System.out.println("Point(" + i + ") = (" + pp.getX() + ", " + pp.getY() + ")"); + } + + System.out.println("wkid: " + geom.getSpatialReference().getID()); + } + } + + @Test + public void testGeometryToJSON() { + Polygon geom = new Polygon(); + geom.startPath(new Point(-113, 34)); + geom.lineTo(new Point(-105, 34)); + geom.lineTo(new Point(-108, 40)); + + String outputPolygon1 = GeometryEngine.geometryToJson(-1, geom);// Test + // WKID + // == -1 + // System.out.println("Geom JSON STRING is" + outputPolygon1); + String correctPolygon1 = "{\"rings\":[[[-113,34],[-105,34],[-108,40],[-113,34]]]}"; + + assertEquals(correctPolygon1, outputPolygon1); + + String outputPolygon2 = GeometryEngine.geometryToJson(4326, geom); + // System.out.println("Geom JSON STRING is" + outputPolygon2); + + String correctPolygon2 = "{\"rings\":[[[-113,34],[-105,34],[-108,40],[-113,34]]],\"spatialReference\":{\"wkid\":4326}}"; + assertEquals(correctPolygon2, outputPolygon2); + } + + @Test + public void testGeometryToJSONOldID() throws Exception {// CR + Polygon geom = new Polygon(); + geom.startPath(new Point(-113, 34)); + geom.lineTo(new Point(-105, 34)); + geom.lineTo(new Point(-108, 40)); + String outputPolygon = GeometryEngine.geometryToJson(SpatialReference.create(3857), geom);// Test + // WKID + // == + // -1 + String correctPolygon = "{\"rings\":[[[-113,34],[-105,34],[-108,40],[-113,34]]],\"spatialReference\":{\"wkid\":102100,\"latestWkid\":3857}}"; + assertTrue(outputPolygon.equals(correctPolygon)); + JsonFactory jf = new JsonFactory(); + JsonParser jp = jf.createParser(outputPolygon); + jp.nextToken(); + MapGeometry mg = GeometryEngine.jsonToGeometry(jp); + @SuppressWarnings("unused") + int srId = mg.getSpatialReference().getID(); + @SuppressWarnings("unused") + int srOldId = mg.getSpatialReference().getOldID(); + Assert.assertTrue(mg.getSpatialReference().getID() == 3857); + Assert.assertTrue(mg.getSpatialReference().getLatestID() == 3857); + Assert.assertTrue(mg.getSpatialReference().getOldID() == 102100); + } } diff --git a/src/test/java/com/esri/core/geometry/TestMathUtils.java b/src/test/java/com/esri/core/geometry/TestMathUtils.java index e7e5721a..c6d39735 100644 --- a/src/test/java/com/esri/core/geometry/TestMathUtils.java +++ b/src/test/java/com/esri/core/geometry/TestMathUtils.java @@ -28,38 +28,38 @@ import org.junit.Test; public class TestMathUtils extends TestCase { - @Override - protected void setUp() throws Exception { - super.setUp(); - } + @Override + protected void setUp() throws Exception { + super.setUp(); + } - @Override - protected void tearDown() throws Exception { - super.tearDown(); - } + @Override + protected void tearDown() throws Exception { + super.tearDown(); + } - @Test - public static void testKahanSummation() { - double s = 0.0; - for (int i = 0; i < 10000; i++) { - if (i == 0) { - s += 1e6; - } else - s += 1e-7; - } + @Test + public static void testKahanSummation() { + double s = 0.0; + for (int i = 0; i < 10000; i++) { + if (i == 0) { + s += 1e6; + } else + s += 1e-7; + } - double trueAnswer = 1e6 + 9999 * 1e-7; - assertTrue(Math.abs(s - trueAnswer) > 1e-9); // precision loss - MathUtils.KahanSummator sum = new MathUtils.KahanSummator(0); - for (int i = 0; i < 10000; i++) { - if (i == 0) { - sum.add(1e6); - } else - sum.add(1e-7); - } - double kahanResult = sum.getResult(); - // 1000000.0009999000 //C++ - // 1000000.0009999 //Java - assertTrue(kahanResult == trueAnswer); // nice answer! - } + double trueAnswer = 1e6 + 9999 * 1e-7; + assertTrue(Math.abs(s - trueAnswer) > 1e-9); // precision loss + MathUtils.KahanSummator sum = new MathUtils.KahanSummator(0); + for (int i = 0; i < 10000; i++) { + if (i == 0) { + sum.add(1e6); + } else + sum.add(1e-7); + } + double kahanResult = sum.getResult(); + // 1000000.0009999000 //C++ + // 1000000.0009999 //Java + assertTrue(kahanResult == trueAnswer); // nice answer! + } } diff --git a/src/test/java/com/esri/core/geometry/TestMultiPoint.java b/src/test/java/com/esri/core/geometry/TestMultiPoint.java index 9263357a..765ac7c5 100644 --- a/src/test/java/com/esri/core/geometry/TestMultiPoint.java +++ b/src/test/java/com/esri/core/geometry/TestMultiPoint.java @@ -28,295 +28,295 @@ import org.junit.Test; public class TestMultiPoint extends TestCase { - @Override - protected void setUp() throws Exception { - super.setUp(); - } - - @Override - protected void tearDown() throws Exception { - super.tearDown(); - } - - static void simpleTest(Geometry point) { - assertTrue(point != null); - // point->AddAttribute(VertexDescription::Semantics::Z); - // assertTrue(point->HasAttribute(VertexDescription::Semantics::POSITION)); - // assertTrue(point.->HasAttribute(VertexDescription::Semantics::Z)); - // point->AddAttribute(VertexDescription::Semantics::Z);//duplicate call - // assertTrue(point->GetDescription()->GetAttributeCount() == 2); - // assertTrue(point->GetDescription()->GetSemantics(1) == - // VertexDescription::Semantics::Z); - // point->DropAttribute(VertexDescription::Semantics::Z); - // assertFalse(point->HasAttribute(VertexDescription::Semantics::Z)); - // point->DropAttribute(VertexDescription::Semantics::Z);//duplicate - // call - // assertFalse(point->HasAttribute(VertexDescription::Semantics::Z)); - // assertTrue(point->GetDescription()->GetAttributeCount() == 1); - // assertTrue(point->GetDescription()->GetSemantics(0) == - // VertexDescription::Semantics::POSITION); - - // point->AddAttribute(VertexDescription::Semantics::M); - // assertTrue(point->HasAttribute(VertexDescription::Semantics::POSITION)); - // assertFalse(point->HasAttribute(VertexDescription::Semantics::Z)); - // assertTrue(point->HasAttribute(VertexDescription::Semantics::M)); - // point->DropAttribute(VertexDescription::Semantics::M); - // assertFalse(point->HasAttribute(VertexDescription::Semantics::M)); - // - // point->AddAttribute(VertexDescription::Semantics::ID); - // assertTrue(point->HasAttribute(VertexDescription::Semantics::POSITION)); - // assertFalse(point->HasAttribute(VertexDescription::Semantics::Z)); - // assertFalse(point->HasAttribute(VertexDescription::Semantics::M)); - // point->DropAttribute(VertexDescription::Semantics::ID); - // assertFalse(point->HasAttribute(VertexDescription::Semantics::ID)); - // / - // assertTrue(point->IsEmpty()); - // assertTrue(point->GetPointCount() == 0); - // assertTrue(point->GetPartCount() == 0); - - point = null; - assertFalse(point != null); - } - - @Test - public static void testCreation() { - {// simple create - MultiPoint mpoint = new MultiPoint(); - assertTrue(mpoint.getClass() == MultiPoint.class); - // assertFalse(mpoint.getClass() == Polyline.class); - - assertTrue(mpoint != null); - assertTrue(mpoint.getType() == Geometry.Type.MultiPoint); - assertTrue(mpoint.isEmpty()); - assertTrue(mpoint.getPointCount() == 0); - mpoint = null; - assertFalse(mpoint != null); - } - {// play with default attributes - MultiPoint mpoint = new MultiPoint(); - simpleTest(mpoint); - } - - {// simple create 2D - MultiPoint mpoint = new MultiPoint(); - assertTrue(mpoint != null); - - - MultiPoint mpoint1 = new MultiPoint(); - assertTrue(mpoint1 != null); - - mpoint.setEmpty(); - Point pt = new Point(0, 0); - mpoint.add(pt); - Point pt3 = mpoint.getPoint(0); - assertTrue(pt3.getX() == 0 && pt3.getY() == 0/** && pt3.getZ() == 0 */ - ); - // assertFalse(mpoint->HasAttribute(VertexDescription::Semantics::Z)); - // pt3.setZ(115.0); - mpoint.setPoint(0, pt3); - pt3 = mpoint.getPoint(0); - assertTrue(pt3.getX() == 0 && pt3.getY() == 0/* && pt3.getZ() == 115 */); - // assertTrue(mpoint->HasAttribute(VertexDescription::Semantics::Z)); - // CompareGeometryContent(mpoint, &pt, 1); - } - - {// move 3d - MultiPoint mpoint = new MultiPoint(); - assertTrue(mpoint != null); - Point pt = new Point(0, 0); - mpoint.add(pt); - Point pt3 = mpoint.getPoint(0); - assertTrue(pt3.getX() == 0 && pt3.getY() == 0/* && pt3.getZ() == 0 */); - } - - { // test QueryInterval - MultiPoint mpoint = new MultiPoint(); - - Point pt1 = new Point(0.0, 0.0); - // pt1.setZ(-1.0); - - Point pt2 = new Point(0.0, 0.0); - // pt2.setZ(1.0); - - mpoint.add(pt1); - mpoint.add(pt2); - - // Envelope1D e = - // mpoint->QueryInterval(enum_value2(VertexDescription, Semantics, - // Z), 0); - Envelope e = new Envelope(); - mpoint.queryEnvelope(e); - // assertTrue(e.get == -1.0 && e.vmax == 1.0); - } - - { - @SuppressWarnings("unused") - MultiPoint geom = new MultiPoint(); - // int sz = sizeof(openString) / sizeof(openString[0]); - // for (int i = 0; i < sz; i++) - // geom.add(openString[i]); - // CompareGeometryContent(geom, openString, sz); - } - - { - @SuppressWarnings("unused") - MultiPoint geom = new MultiPoint(); - // int sz = sizeof(openString) / sizeof(openString[0]); - // Point point = GCNEW Point; - // for (int i = 0; i < sz; i++) - // { - // point.setXY(openString[i]); - // geom.add(point); - // } - // CompareGeometryContent(geom, openString, sz); - } - - // Test AddPoints - { - @SuppressWarnings("unused") - MultiPoint geom = new MultiPoint(); - // int sz = sizeof(openString) / sizeof(openString[0]); - // geom.addPoints(openString, sz, 0, -1); - // CompareGeometryContent((MultiVertexGeometry)geom, openString, - // sz); - } - - // Test InsertPoint(Point2D) - { - MultiPoint mpoint = new MultiPoint(); - Point pt0 = new Point(0.0, 0.0); - // pt0.setZ(-1.0); - // pt0.setID(7); - - Point pt1 = new Point(0.0, 0.0); - // pt1.setZ(1.0); - // pt1.setID(11); - - Point pt2 = new Point(0.0, 1.0); - // pt2.setZ(1.0); - // pt2.setID(13); - - mpoint.add(pt0); - mpoint.add(pt1); - mpoint.add(pt2); - - Point pt3 = new Point(-11.0, -13.0); - - mpoint.add(pt3); - mpoint.insertPoint(1, pt3); - assertTrue(mpoint.getPointCount() == 5); - - Point pt; - pt = mpoint.getPoint(0); - assertTrue(pt.getX() == pt0.getX() && pt.getY() == pt0.getY()/* - * && - * pt. - * getZ - * () == - * pt0 - * .getZ - * () - */); - - pt = mpoint.getPoint(1); - assertTrue(pt.getX() == pt3.getX() && pt.getY() == pt3.getY()); - - pt = mpoint.getPoint(2); - assertTrue(pt.getX() == pt1.getX() && pt.getY() == pt1.getY()/* - * && - * pt. - * getZ - * () == - * pt1 - * .getZ - * () - */); - - pt = mpoint.getPoint(3); - assertTrue(pt.getX() == pt2.getX() && pt.getY() == pt2.getY()/* - * && - * pt. - * getZ - * () == - * pt2 - * .getZ - * () - */); - - Point point = new Point(); - point.setXY(17.0, 19.0); - // point.setID(12); - // point.setM(5); - - mpoint.insertPoint(2, point); - mpoint.add(point); - - assertTrue(mpoint.getPointCount() == 7); - - // double m; - // int id; - // pt = mpoint.getXYZ(2); - // assertTrue(pt.x == 17.0 && pt.y == 19.0 && pt.z == defaultZ); - // m = mpoint.getAttributeAsDbl(enum_value2(VertexDescription, - // Semantics, M), 2, 0); - // assertTrue(m == 5); - // id = mpoint.getAttributeAsInt(enum_value2(VertexDescription, - // Semantics, ID), 2, 0); - // assertTrue(id == 23); - // - // pt = mpoint.getXYZ(3); - // assertTrue(pt.x == pt1.x && pt.y == pt1.y && pt.z == pt1.z); - // m = mpoint.getAttributeAsDbl(enum_value2(VertexDescription, - // Semantics, M), 3, 0); - // assertTrue(NumberUtils::IsNaN(m)); - // id = mpoint.getAttributeAsInt(enum_value2(VertexDescription, - // Semantics, ID), 3, 0); - // assertTrue(id == 11); - } - - MultiPoint mpoint = new MultiPoint(); - Point pt0 = new Point(0.0, 0.0, -1.0); - - Point pt1 = new Point(0.0, 0.0, 1.0); - - Point pt2 = new Point(0.0, 1.0, 1.0); - - mpoint.add(pt0); - mpoint.add(pt1); - mpoint.add(pt2); - - mpoint.removePoint(1); - - Point pt; - pt = mpoint.getPoint(0); - assertTrue(pt.getX() == pt0.getX() && pt.getY() == pt0.getY()); - pt = mpoint.getPoint(1); - assertTrue(pt.getX() == pt2.getX() && pt.getY() == pt2.getY()); - - assertTrue(mpoint.getPointCount() == 2); - } - - @Test - public static void testCopy() { - MultiPoint mpoint = new MultiPoint(); - Point pt0 = new Point(0.0, 0.0, -1.0); - Point pt1 = new Point(0.0, 0.0, 1.0); - Point pt2 = new Point(0.0, 1.0, 1.0); - - mpoint.add(pt0); - mpoint.add(pt1); - mpoint.add(pt2); - mpoint.removePoint(1); - - MultiPoint mpCopy = (MultiPoint) mpoint.copy(); - assertTrue(mpCopy.equals(mpoint)); - - Point pt; - pt = mpCopy.getPoint(0); - assertTrue(pt.getX() == pt0.getX() && pt.getY() == pt0.getY()); - pt = mpCopy.getPoint(1); - assertTrue(pt.getX() == pt2.getX() && pt.getY() == pt2.getY()); - - assertTrue(mpCopy.getPointCount() == 2); - } + @Override + protected void setUp() throws Exception { + super.setUp(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + } + + static void simpleTest(Geometry point) { + assertTrue(point != null); + // point->AddAttribute(VertexDescription::Semantics::Z); + // assertTrue(point->HasAttribute(VertexDescription::Semantics::POSITION)); + // assertTrue(point.->HasAttribute(VertexDescription::Semantics::Z)); + // point->AddAttribute(VertexDescription::Semantics::Z);//duplicate call + // assertTrue(point->GetDescription()->GetAttributeCount() == 2); + // assertTrue(point->GetDescription()->GetSemantics(1) == + // VertexDescription::Semantics::Z); + // point->DropAttribute(VertexDescription::Semantics::Z); + // assertFalse(point->HasAttribute(VertexDescription::Semantics::Z)); + // point->DropAttribute(VertexDescription::Semantics::Z);//duplicate + // call + // assertFalse(point->HasAttribute(VertexDescription::Semantics::Z)); + // assertTrue(point->GetDescription()->GetAttributeCount() == 1); + // assertTrue(point->GetDescription()->GetSemantics(0) == + // VertexDescription::Semantics::POSITION); + + // point->AddAttribute(VertexDescription::Semantics::M); + // assertTrue(point->HasAttribute(VertexDescription::Semantics::POSITION)); + // assertFalse(point->HasAttribute(VertexDescription::Semantics::Z)); + // assertTrue(point->HasAttribute(VertexDescription::Semantics::M)); + // point->DropAttribute(VertexDescription::Semantics::M); + // assertFalse(point->HasAttribute(VertexDescription::Semantics::M)); + // + // point->AddAttribute(VertexDescription::Semantics::ID); + // assertTrue(point->HasAttribute(VertexDescription::Semantics::POSITION)); + // assertFalse(point->HasAttribute(VertexDescription::Semantics::Z)); + // assertFalse(point->HasAttribute(VertexDescription::Semantics::M)); + // point->DropAttribute(VertexDescription::Semantics::ID); + // assertFalse(point->HasAttribute(VertexDescription::Semantics::ID)); + // / + // assertTrue(point->IsEmpty()); + // assertTrue(point->GetPointCount() == 0); + // assertTrue(point->GetPartCount() == 0); + + point = null; + assertFalse(point != null); + } + + @Test + public static void testCreation() { + {// simple create + MultiPoint mpoint = new MultiPoint(); + assertTrue(mpoint.getClass() == MultiPoint.class); + // assertFalse(mpoint.getClass() == Polyline.class); + + assertTrue(mpoint != null); + assertTrue(mpoint.getType() == Geometry.Type.MultiPoint); + assertTrue(mpoint.isEmpty()); + assertTrue(mpoint.getPointCount() == 0); + mpoint = null; + assertFalse(mpoint != null); + } + {// play with default attributes + MultiPoint mpoint = new MultiPoint(); + simpleTest(mpoint); + } + + {// simple create 2D + MultiPoint mpoint = new MultiPoint(); + assertTrue(mpoint != null); + + + MultiPoint mpoint1 = new MultiPoint(); + assertTrue(mpoint1 != null); + + mpoint.setEmpty(); + Point pt = new Point(0, 0); + mpoint.add(pt); + Point pt3 = mpoint.getPoint(0); + assertTrue(pt3.getX() == 0 && pt3.getY() == 0/** && pt3.getZ() == 0 */ + ); + // assertFalse(mpoint->HasAttribute(VertexDescription::Semantics::Z)); + // pt3.setZ(115.0); + mpoint.setPoint(0, pt3); + pt3 = mpoint.getPoint(0); + assertTrue(pt3.getX() == 0 && pt3.getY() == 0/* && pt3.getZ() == 115 */); + // assertTrue(mpoint->HasAttribute(VertexDescription::Semantics::Z)); + // CompareGeometryContent(mpoint, &pt, 1); + } + + {// move 3d + MultiPoint mpoint = new MultiPoint(); + assertTrue(mpoint != null); + Point pt = new Point(0, 0); + mpoint.add(pt); + Point pt3 = mpoint.getPoint(0); + assertTrue(pt3.getX() == 0 && pt3.getY() == 0/* && pt3.getZ() == 0 */); + } + + { // test QueryInterval + MultiPoint mpoint = new MultiPoint(); + + Point pt1 = new Point(0.0, 0.0); + // pt1.setZ(-1.0); + + Point pt2 = new Point(0.0, 0.0); + // pt2.setZ(1.0); + + mpoint.add(pt1); + mpoint.add(pt2); + + // Envelope1D e = + // mpoint->QueryInterval(enum_value2(VertexDescription, Semantics, + // Z), 0); + Envelope e = new Envelope(); + mpoint.queryEnvelope(e); + // assertTrue(e.get == -1.0 && e.vmax == 1.0); + } + + { + @SuppressWarnings("unused") + MultiPoint geom = new MultiPoint(); + // int sz = sizeof(openString) / sizeof(openString[0]); + // for (int i = 0; i < sz; i++) + // geom.add(openString[i]); + // CompareGeometryContent(geom, openString, sz); + } + + { + @SuppressWarnings("unused") + MultiPoint geom = new MultiPoint(); + // int sz = sizeof(openString) / sizeof(openString[0]); + // Point point = GCNEW Point; + // for (int i = 0; i < sz; i++) + // { + // point.setXY(openString[i]); + // geom.add(point); + // } + // CompareGeometryContent(geom, openString, sz); + } + + // Test AddPoints + { + @SuppressWarnings("unused") + MultiPoint geom = new MultiPoint(); + // int sz = sizeof(openString) / sizeof(openString[0]); + // geom.addPoints(openString, sz, 0, -1); + // CompareGeometryContent((MultiVertexGeometry)geom, openString, + // sz); + } + + // Test InsertPoint(Point2D) + { + MultiPoint mpoint = new MultiPoint(); + Point pt0 = new Point(0.0, 0.0); + // pt0.setZ(-1.0); + // pt0.setID(7); + + Point pt1 = new Point(0.0, 0.0); + // pt1.setZ(1.0); + // pt1.setID(11); + + Point pt2 = new Point(0.0, 1.0); + // pt2.setZ(1.0); + // pt2.setID(13); + + mpoint.add(pt0); + mpoint.add(pt1); + mpoint.add(pt2); + + Point pt3 = new Point(-11.0, -13.0); + + mpoint.add(pt3); + mpoint.insertPoint(1, pt3); + assertTrue(mpoint.getPointCount() == 5); + + Point pt; + pt = mpoint.getPoint(0); + assertTrue(pt.getX() == pt0.getX() && pt.getY() == pt0.getY()/* + * && + * pt. + * getZ + * () == + * pt0 + * .getZ + * () + */); + + pt = mpoint.getPoint(1); + assertTrue(pt.getX() == pt3.getX() && pt.getY() == pt3.getY()); + + pt = mpoint.getPoint(2); + assertTrue(pt.getX() == pt1.getX() && pt.getY() == pt1.getY()/* + * && + * pt. + * getZ + * () == + * pt1 + * .getZ + * () + */); + + pt = mpoint.getPoint(3); + assertTrue(pt.getX() == pt2.getX() && pt.getY() == pt2.getY()/* + * && + * pt. + * getZ + * () == + * pt2 + * .getZ + * () + */); + + Point point = new Point(); + point.setXY(17.0, 19.0); + // point.setID(12); + // point.setM(5); + + mpoint.insertPoint(2, point); + mpoint.add(point); + + assertTrue(mpoint.getPointCount() == 7); + + // double m; + // int id; + // pt = mpoint.getXYZ(2); + // assertTrue(pt.x == 17.0 && pt.y == 19.0 && pt.z == defaultZ); + // m = mpoint.getAttributeAsDbl(enum_value2(VertexDescription, + // Semantics, M), 2, 0); + // assertTrue(m == 5); + // id = mpoint.getAttributeAsInt(enum_value2(VertexDescription, + // Semantics, ID), 2, 0); + // assertTrue(id == 23); + // + // pt = mpoint.getXYZ(3); + // assertTrue(pt.x == pt1.x && pt.y == pt1.y && pt.z == pt1.z); + // m = mpoint.getAttributeAsDbl(enum_value2(VertexDescription, + // Semantics, M), 3, 0); + // assertTrue(NumberUtils::IsNaN(m)); + // id = mpoint.getAttributeAsInt(enum_value2(VertexDescription, + // Semantics, ID), 3, 0); + // assertTrue(id == 11); + } + + MultiPoint mpoint = new MultiPoint(); + Point pt0 = new Point(0.0, 0.0, -1.0); + + Point pt1 = new Point(0.0, 0.0, 1.0); + + Point pt2 = new Point(0.0, 1.0, 1.0); + + mpoint.add(pt0); + mpoint.add(pt1); + mpoint.add(pt2); + + mpoint.removePoint(1); + + Point pt; + pt = mpoint.getPoint(0); + assertTrue(pt.getX() == pt0.getX() && pt.getY() == pt0.getY()); + pt = mpoint.getPoint(1); + assertTrue(pt.getX() == pt2.getX() && pt.getY() == pt2.getY()); + + assertTrue(mpoint.getPointCount() == 2); + } + + @Test + public static void testCopy() { + MultiPoint mpoint = new MultiPoint(); + Point pt0 = new Point(0.0, 0.0, -1.0); + Point pt1 = new Point(0.0, 0.0, 1.0); + Point pt2 = new Point(0.0, 1.0, 1.0); + + mpoint.add(pt0); + mpoint.add(pt1); + mpoint.add(pt2); + mpoint.removePoint(1); + + MultiPoint mpCopy = (MultiPoint) mpoint.copy(); + assertTrue(mpCopy.equals(mpoint)); + + Point pt; + pt = mpCopy.getPoint(0); + assertTrue(pt.getX() == pt0.getX() && pt.getY() == pt0.getY()); + pt = mpCopy.getPoint(1); + assertTrue(pt.getX() == pt2.getX() && pt.getY() == pt2.getY()); + + assertTrue(mpCopy.getPointCount() == 2); + } } diff --git a/src/test/java/com/esri/core/geometry/TestOGC.java b/src/test/java/com/esri/core/geometry/TestOGC.java index fa0f61ef..f55dbb21 100644 --- a/src/test/java/com/esri/core/geometry/TestOGC.java +++ b/src/test/java/com/esri/core/geometry/TestOGC.java @@ -1,5 +1,5 @@ /* - Copyright 1995-2017 Esri + Copyright 1995-2018 Esri Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -24,893 +24,1025 @@ package com.esri.core.geometry; -import com.esri.core.geometry.ogc.*; import junit.framework.TestCase; + +import com.esri.core.geometry.ogc.OGCGeometry; +import com.esri.core.geometry.ogc.OGCGeometryCollection; +import com.esri.core.geometry.ogc.OGCLineString; +import com.esri.core.geometry.ogc.OGCMultiCurve; +import com.esri.core.geometry.ogc.OGCMultiLineString; +import com.esri.core.geometry.ogc.OGCMultiPoint; +import com.esri.core.geometry.ogc.OGCMultiPolygon; +import com.esri.core.geometry.ogc.OGCPoint; +import com.esri.core.geometry.ogc.OGCPolygon; +import com.esri.core.geometry.ogc.OGCConcreteGeometryCollection; + import org.junit.Test; +import java.io.IOException; import java.nio.ByteBuffer; public class TestOGC extends TestCase { - @Override - protected void setUp() throws Exception { - super.setUp(); - } - - @Override - protected void tearDown() throws Exception { - super.tearDown(); - } - - @Test - public void testPoint() { - OGCGeometry g = OGCGeometry.fromText("POINT(1 2)"); - assertTrue(g.geometryType().equals("Point")); - OGCPoint p = (OGCPoint) g; - assertTrue(p.X() == 1); - assertTrue(p.Y() == 2); - assertTrue(g.equals(OGCGeometry.fromText("POINT(1 2)"))); - assertTrue(!g.equals(OGCGeometry.fromText("POINT(1 3)"))); - assertTrue(g.equals((Object) OGCGeometry.fromText("POINT(1 2)"))); - assertTrue(!g.equals((Object) OGCGeometry.fromText("POINT(1 3)"))); - OGCGeometry buf = g.buffer(10); - assertTrue(buf.geometryType().equals("Polygon")); - OGCPolygon poly = (OGCPolygon) buf.envelope(); - double a = poly.area(); - assertTrue(Math.abs(a - 400) < 1e-1); - } - - @Test - public void testPolygon() throws Exception { - OGCGeometry g = OGCGeometry - .fromText("POLYGON((-10 -10, 10 -10, 10 10, -10 10, -10 -10), (-5 -5, -5 5, 5 5, 5 -5, -5 -5))"); - assertTrue(g.geometryType().equals("Polygon")); - OGCPolygon p = (OGCPolygon) g; - assertTrue(p.numInteriorRing() == 1); - OGCLineString ls = p.exteriorRing(); - // assertTrue(ls.pointN(1).equals(OGCGeometry.fromText("POINT(10 -10)"))); - boolean b = ls - .Equals(OGCGeometry - .fromText("LINESTRING(-10 -10, 10 -10, 10 10, -10 10, -10 -10)")); - assertTrue(b); - OGCLineString lsi = p.interiorRingN(0); - b = lsi.Equals(OGCGeometry - .fromText("LINESTRING(-5 -5, -5 5, 5 5, 5 -5, -5 -5)")); - assertTrue(b); - b = lsi.equals((Object) OGCGeometry - .fromText("LINESTRING(-5 -5, -5 5, 5 5, 5 -5, -5 -5)")); - assertTrue(!lsi.Equals(ls)); - OGCMultiCurve boundary = p.boundary(); - String s = boundary.asText(); - assertTrue(s.equals("MULTILINESTRING ((-10 -10, 10 -10, 10 10, -10 10, -10 -10), (-5 -5, -5 5, 5 5, 5 -5, -5 -5))")); - - { - OGCGeometry g2 = OGCGeometry.fromGeoJson( - "{\"type\": \"Polygon\", \"coordinates\": [[[1.00000001,1.00000001], [4.00000001,1.00000001], [4.00000001,4.00000001], [1.00000001,4.00000001]]]}"); - OGCGeometry - .fromGeoJson( - "{\"type\": \"LineString\", \"coordinates\": [[1.00000001,1.00000001], [7.00000001,8.00000001]]}") - .intersects(g2); - OGCGeometry - .fromGeoJson( - "{\"type\": \"LineString\", \"coordinates\": [[2.449,4.865], [7.00000001,8.00000001]]}") - .intersects(g2); - - OGCGeometry g3 = OGCGeometry.fromGeoJson( - "{\"type\": \"Polygon\", \"coordinates\": [[[1.00000001,1.00000001], [4.00000001,1.00000001], [4.00000001,4.00000001], [1.00000001,4.00000001]]]}"); - boolean bb = g2.equals((Object) g3); - assertTrue(bb); - } - } - - @Test - public void testGeometryCollection() throws Exception { - OGCGeometry g = OGCGeometry - .fromText("GEOMETRYCOLLECTION(POLYGON EMPTY, POINT(1 1), LINESTRING EMPTY, MULTIPOLYGON EMPTY, MULTILINESTRING EMPTY)"); - assertTrue(g.geometryType().equals("GeometryCollection")); - OGCConcreteGeometryCollection gc = (OGCConcreteGeometryCollection) g; - assertTrue(gc.numGeometries() == 5); - assertTrue(gc.geometryN(0).geometryType().equals("Polygon")); - assertTrue(gc.geometryN(1).geometryType().equals("Point")); - assertTrue(gc.geometryN(2).geometryType().equals("LineString")); - assertTrue(gc.geometryN(3).geometryType().equals("MultiPolygon")); - assertTrue(gc.geometryN(4).geometryType().equals("MultiLineString")); - - g = OGCGeometry - .fromText("GEOMETRYCOLLECTION(POLYGON EMPTY, POINT(1 1), GEOMETRYCOLLECTION EMPTY, LINESTRING EMPTY, GEOMETRYCOLLECTION(POLYGON EMPTY, POINT(1 1), LINESTRING EMPTY, MULTIPOLYGON EMPTY, MULTILINESTRING EMPTY, MULTIPOINT EMPTY), MULTIPOLYGON EMPTY, MULTILINESTRING EMPTY)"); - assertTrue(g.geometryType().equals("GeometryCollection")); - gc = (OGCConcreteGeometryCollection) g; - assertTrue(gc.numGeometries() == 7); - assertTrue(gc.geometryN(0).geometryType().equals("Polygon")); - assertTrue(gc.geometryN(1).geometryType().equals("Point")); - assertTrue(gc.geometryN(2).geometryType().equals("GeometryCollection")); - assertTrue(gc.geometryN(3).geometryType().equals("LineString")); - assertTrue(gc.geometryN(4).geometryType().equals("GeometryCollection")); - assertTrue(gc.geometryN(5).geometryType().equals("MultiPolygon")); - assertTrue(gc.geometryN(6).geometryType().equals("MultiLineString")); - - OGCConcreteGeometryCollection gc2 = (OGCConcreteGeometryCollection) gc - .geometryN(4); - assertTrue(gc2.numGeometries() == 6); - assertTrue(gc2.geometryN(0).geometryType().equals("Polygon")); - assertTrue(gc2.geometryN(1).geometryType().equals("Point")); - assertTrue(gc2.geometryN(2).geometryType().equals("LineString")); - assertTrue(gc2.geometryN(3).geometryType().equals("MultiPolygon")); - assertTrue(gc2.geometryN(4).geometryType().equals("MultiLineString")); - assertTrue(gc2.geometryN(5).geometryType().equals("MultiPoint")); - - ByteBuffer wkbBuffer = g.asBinary(); - g = OGCGeometry.fromBinary(wkbBuffer); - - assertTrue(g.geometryType().equals("GeometryCollection")); - gc = (OGCConcreteGeometryCollection) g; - assertTrue(gc.numGeometries() == 7); - assertTrue(gc.geometryN(0).geometryType().equals("Polygon")); - assertTrue(gc.geometryN(1).geometryType().equals("Point")); - assertTrue(gc.geometryN(2).geometryType().equals("GeometryCollection")); - assertTrue(gc.geometryN(3).geometryType().equals("LineString")); - assertTrue(gc.geometryN(4).geometryType().equals("GeometryCollection")); - assertTrue(gc.geometryN(5).geometryType().equals("MultiPolygon")); - assertTrue(gc.geometryN(6).geometryType().equals("MultiLineString")); - - gc2 = (OGCConcreteGeometryCollection) gc.geometryN(4); - assertTrue(gc2.numGeometries() == 6); - assertTrue(gc2.geometryN(0).geometryType().equals("Polygon")); - assertTrue(gc2.geometryN(1).geometryType().equals("Point")); - assertTrue(gc2.geometryN(2).geometryType().equals("LineString")); - assertTrue(gc2.geometryN(3).geometryType().equals("MultiPolygon")); - assertTrue(gc2.geometryN(4).geometryType().equals("MultiLineString")); - assertTrue(gc2.geometryN(5).geometryType().equals("MultiPoint")); - - String wktString = g.asText(); - assertTrue(wktString - .equals("GEOMETRYCOLLECTION (POLYGON EMPTY, POINT (1 1), GEOMETRYCOLLECTION EMPTY, LINESTRING EMPTY, GEOMETRYCOLLECTION (POLYGON EMPTY, POINT (1 1), LINESTRING EMPTY, MULTIPOLYGON EMPTY, MULTILINESTRING EMPTY, MULTIPOINT EMPTY), MULTIPOLYGON EMPTY, MULTILINESTRING EMPTY)")); - - g = OGCGeometry - .fromGeoJson("{\"type\" : \"GeometryCollection\", \"geometries\" : [{\"type\" : \"Polygon\", \"coordinates\" : []}, {\"type\" : \"Point\", \"coordinates\" : [1, 1]}, {\"type\" : \"GeometryCollection\", \"geometries\" : []}, {\"type\" : \"LineString\", \"coordinates\" : []}, {\"type\" : \"GeometryCollection\", \"geometries\" : [{\"type\": \"Polygon\", \"coordinates\" : []}, {\"type\" : \"Point\", \"coordinates\" : [1,1]}, {\"type\" : \"LineString\", \"coordinates\" : []}, {\"type\" : \"MultiPolygon\", \"coordinates\" : []}, {\"type\" : \"MultiLineString\", \"coordinates\" : []}, {\"type\" : \"MultiPoint\", \"coordinates\" : []}]}, {\"type\" : \"MultiPolygon\", \"coordinates\" : []}, {\"type\" : \"MultiLineString\", \"coordinates\" : []} ] }"); - - wktString = g.asText(); - assertTrue(wktString - .equals("GEOMETRYCOLLECTION (POLYGON EMPTY, POINT (1 1), GEOMETRYCOLLECTION EMPTY, LINESTRING EMPTY, GEOMETRYCOLLECTION (POLYGON EMPTY, POINT (1 1), LINESTRING EMPTY, MULTIPOLYGON EMPTY, MULTILINESTRING EMPTY, MULTIPOINT EMPTY), MULTIPOLYGON EMPTY, MULTILINESTRING EMPTY)")); - - assertTrue(g.equals((Object) OGCGeometry.fromText(wktString))); - - assertTrue(g.hashCode() == OGCGeometry.fromText(wktString).hashCode()); - - } - - @Test - public void testFirstPointOfPolygon() { - OGCGeometry g = OGCGeometry - .fromText("POLYGON((-10 -10, 10 -10, 10 10, -10 10, -10 -10), (-5 -5, -5 5, 5 5, 5 -5, -5 -5))"); - assertTrue(g.geometryType().equals("Polygon")); - OGCPolygon p = (OGCPolygon) g; - assertTrue(p.numInteriorRing() == 1); - OGCLineString ls = p.exteriorRing(); - OGCPoint p1 = ls.pointN(1); - assertTrue(ls.pointN(1).equals(OGCGeometry.fromText("POINT(10 -10)"))); - OGCPoint p2 = ls.pointN(3); - assertTrue(ls.pointN(3).equals(OGCGeometry.fromText("POINT(-10 10)"))); - OGCPoint p0 = ls.pointN(0); - assertTrue(ls.pointN(0).equals(OGCGeometry.fromText("POINT(-10 -10)"))); - String ms = g.convertToMulti().asText(); - assertTrue(ms.equals("MULTIPOLYGON (((-10 -10, 10 -10, 10 10, -10 10, -10 -10), (-5 -5, -5 5, 5 5, 5 -5, -5 -5)))")); - - } - - @Test - public void testFirstPointOfLineString() { - OGCGeometry g = OGCGeometry - .fromText("LINESTRING(-10 -10, 10 -10, 10 10, -10 10, -10 -10)"); - assertTrue(g.geometryType().equals("LineString")); - OGCLineString p = (OGCLineString) g; - assertTrue(p.numPoints() == 5); - assertTrue(p.isClosed()); - assertTrue(p.pointN(1).equals(OGCGeometry.fromText("POINT(10 -10)"))); - String ms = g.convertToMulti().asText(); - assertTrue(ms.equals("MULTILINESTRING ((-10 -10, 10 -10, 10 10, -10 10, -10 -10))")); - } - - @Test - public void testPointInPolygon() { - OGCGeometry g = OGCGeometry - .fromText("POLYGON((-10 -10, 10 -10, 10 10, -10 10, -10 -10), (-5 -5, -5 5, 5 5, 5 -5, -5 -5))"); - assertTrue(g.geometryType().equals("Polygon")); - assertTrue(!g.contains(OGCGeometry.fromText("POINT(0 0)"))); - assertTrue(g.contains(OGCGeometry.fromText("POINT(9 9)"))); - assertTrue(!g.contains(OGCGeometry.fromText("POINT(-20 1)"))); - assertTrue(g.disjoint(OGCGeometry.fromText("POINT(0 0)"))); - assertTrue(!g.disjoint(OGCGeometry.fromText("POINT(9 9)"))); - assertTrue(g.disjoint(OGCGeometry.fromText("POINT(-20 1)"))); - } - - @Test - public void testMultiPolygon() { - { - OGCGeometry g = OGCGeometry - .fromText("MULTIPOLYGON(((-10 -10, 10 -10, 10 10, -10 10, -10 -10), (-5 -5, -5 5, 5 5, 5 -5, -5 -5)))"); - assertTrue(g.geometryType().equals("MultiPolygon")); // the type is - // reduced - assertTrue(!g.contains(OGCGeometry.fromText("POINT(0 0)"))); - assertTrue(g.contains(OGCGeometry.fromText("POINT(9 9)"))); - assertTrue(!g.contains(OGCGeometry.fromText("POINT(-20 1)"))); - assertTrue(g.disjoint(OGCGeometry.fromText("POINT(0 0)"))); - assertTrue(!g.disjoint(OGCGeometry.fromText("POINT(9 9)"))); - assertTrue(g.disjoint(OGCGeometry.fromText("POINT(-20 1)"))); - assertTrue(g.convertToMulti() == g); - } - - { - OGCGeometry g = OGCGeometry - .fromText("MULTIPOLYGON(((-10 -10, 10 -10, 10 10, -10 10, -10 -10), (-5 -5, -5 5, 5 5, 5 -5, -5 -5)), ((90 90, 110 90, 110 110, 90 110, 90 90), (95 95, 95 105, 105 105, 105 95, 95 95)))"); - assertTrue(g.geometryType().equals("MultiPolygon")); // the type is - - OGCMultiPolygon mp = (OGCMultiPolygon) g; - assertTrue(mp.numGeometries() == 2); - OGCGeometry p1 = mp.geometryN(0); - assertTrue(p1.geometryType().equals("Polygon")); // the type is - assertTrue(p1.contains(OGCGeometry.fromText("POINT(9 9)"))); - assertTrue(!p1.contains(OGCGeometry.fromText("POINT(109 109)"))); - OGCGeometry p2 = mp.geometryN(1); - assertTrue(p2.geometryType().equals("Polygon")); // the type is - assertTrue(!p2.contains(OGCGeometry.fromText("POINT(9 9)"))); - assertTrue(p2.contains(OGCGeometry.fromText("POINT(109 109)"))); - } - } - - @Test - public void testMultiPolygonUnion() { - OGCGeometry g = OGCGeometry - .fromText("POLYGON((-10 -10, 10 -10, 10 10, -10 10, -10 -10), (-5 -5, -5 5, 5 5, 5 -5, -5 -5))"); - OGCGeometry g2 = OGCGeometry - .fromText("POLYGON((90 90, 110 90, 110 110, 90 110, 90 90))"); - OGCGeometry u = g.union(g2); - assertTrue(u.geometryType().equals("MultiPolygon")); - assertTrue(!u.contains(OGCGeometry.fromText("POINT(0 0)"))); - assertTrue(u.contains(OGCGeometry.fromText("POINT(9 9)"))); - assertTrue(!u.contains(OGCGeometry.fromText("POINT(-20 1)"))); - assertTrue(u.disjoint(OGCGeometry.fromText("POINT(0 0)"))); - assertTrue(!u.disjoint(OGCGeometry.fromText("POINT(9 9)"))); - assertTrue(u.disjoint(OGCGeometry.fromText("POINT(-20 1)"))); - assertTrue(u.contains(OGCGeometry.fromText("POINT(100 100)"))); - } - - @Test - public void testIntersection() { - OGCGeometry g = OGCGeometry.fromText("LINESTRING(0 0, 10 10)"); - OGCGeometry g2 = OGCGeometry.fromText("LINESTRING(10 0, 0 10)"); - OGCGeometry u = g.intersection(g2); - assertTrue(u.dimension() == 0); - String s = u.asText(); - assertTrue(u.equals(OGCGeometry.fromText("POINT(5 5)"))); - } - - @Test - public void testPointSymDif() { - OGCGeometry g1 = OGCGeometry.fromText("POINT(1 2)"); - OGCGeometry g2 = OGCGeometry.fromText("POINT(3 4)"); - OGCGeometry gg = g1.symDifference(g2); - assertTrue(gg.equals(OGCGeometry.fromText("MULTIPOINT(1 2, 3 4)"))); - - OGCGeometry g3 = OGCGeometry.fromText("POINT(1 2)"); - OGCGeometry gg1 = g1.symDifference(g3); - assertTrue(gg1 == null || gg1.isEmpty()); - - } - - @Test - public void testNullSr() { - String wkt = "point (0 0)"; - OGCGeometry g = OGCGeometry.fromText(wkt); - g.setSpatialReference(null); - assertTrue(g.SRID() < 1); - } - - @Test - public void testIsectPoint() { - String wkt = "point (0 0)"; - String wk2 = "point (0 0)"; - OGCGeometry g0 = OGCGeometry.fromText(wkt); - OGCGeometry g1 = OGCGeometry.fromText(wk2); - g0.setSpatialReference(null); - g1.setSpatialReference(null); - try { - OGCGeometry rslt = g0.intersection(g1); // ArrayIndexOutOfBoundsException - assertTrue(rslt != null); - } catch (Exception e) { - assertTrue(false); - } - } - - @Test - public void testIsectDisjoint() { - String wk3 = "linestring (0 0, 1 1)"; - String wk4 = "linestring (2 2, 4 4)"; - OGCGeometry g0 = OGCGeometry.fromText(wk3); - OGCGeometry g1 = OGCGeometry.fromText(wk4); - g0.setSpatialReference(null); - g1.setSpatialReference(null); - try { - OGCGeometry rslt = g0.intersection(g1); // null - assertTrue(rslt != null); - } catch (Exception e) { - assertTrue(false); - } - } - - @Test - public void test_polygon_is_simple_for_OGC() { - try { - { - String s = "{\"rings\":[[[0, 0], [0, 10], [10, 10], [10, 0], [0, 0]]]}"; - OGCGeometry g = OGCGeometry.fromJson(s); - boolean res = g.isSimple(); - assertTrue(res); - assertTrue(g.isSimpleRelaxed()); - } - - {// exterior ring is self-tangent - String s = "{\"rings\":[[[0, 0], [0, 10], [5, 5], [10, 10], [10, 0], [5, 5], [0, 0]]]}"; - OGCGeometry g = OGCGeometry.fromJson(s); - boolean res = g.isSimple(); - assertTrue(!res); - assertTrue(g.isSimpleRelaxed()); - } - - {// ring orientation (hole is cw) - String s = "{\"rings\":[[[-100, -100], [-100, 100], [100, 100], [100, -100], [-100, -100]], [[0, 0], [5, 5], [10, 0], [0, 0]]]}"; - OGCGeometry g = OGCGeometry.fromJson(s); - boolean res = g.isSimple(); - assertTrue(!res); - assertTrue(!g.isSimpleRelaxed()); - } - { - String s = "{\"rings\":[[[-100, -100], [-100, 100], [100, 100], [100, -100], [-100, -100]], [[0, 0], [10, 0], [5, 5], [0, 0]]]}"; - OGCGeometry g = OGCGeometry.fromJson(s); - boolean res = g.isSimple(); - assertTrue(res); - assertTrue(g.isSimpleRelaxed()); - } - - {// ring order - String s = "{\"rings\":[[[0, 0], [10, 0], [5, 5], [0, 0]], [[-100, -100], [-100, 100], [100, 100], [100, -100], [-100, -100]]]}"; - OGCGeometry g = OGCGeometry.fromJson(s); - boolean res = g.isSimple(); - assertTrue(!res); - assertTrue(g.isSimpleRelaxed()); - } - - { - // hole is self tangent - String s = "{\"rings\":[[[-100, -100], [-100, 100], [100, 100], [100, -100], [-100, -100]], [[0, 0], [5, 5], [10, 0], [10, 10], [5, 5], [0, 10], [0, 0]]]}"; - OGCGeometry g = OGCGeometry.fromJson(s); - boolean res = g.isSimple(); - assertTrue(!res); - assertTrue(g.isSimpleRelaxed()); - } - { - // two holes touch - String s = "{\"rings\":[[[-100, -100], [-100, 100], [100, 100], [100, -100], [-100, -100]], [[0, 0], [10, 0], [5, 5], [0, 0]], [[10, 10], [0, 10], [5, 5], [10, 10]]]}"; - OGCGeometry g = OGCGeometry.fromJson(s); - boolean res = g.isSimple(); - assertTrue(res); - assertTrue(g.isSimpleRelaxed()); - } - { - // two holes touch, bad orientation - String s = "{\"rings\":[[[-100, -100], [-100, 100], [100, 100], [100, -100], [-100, -100]], [[0, 0], [5, 5], [10, 0], [0, 0]], [[10, 10], [0, 10], [5, 5], [10, 10]]]}"; - OGCGeometry g = OGCGeometry.fromJson(s); - boolean res = g.isSimple(); - assertTrue(!res); - assertTrue(!g.isSimpleRelaxed()); - - } - - { - // hole touches exterior in two spots - String s = "{\"rings\":[[[-100, -100], [-100, 100], [0, 100], [100, 100], [100, -100], [0, -100], [-100, -100]], [[0, -100], [10, 0], [0, 100], [-10, 0], [0, -100]]]}"; - OGCGeometry g = OGCGeometry.fromJson(s); - boolean res = g.isSimple(); - assertTrue(!res); - assertTrue(g.isSimpleRelaxed()); - } - - { - // hole touches exterior in one spot - String s = "{\"rings\":[[[-100, -100], [-100, 100], [0, 100], [100, 100], [100, -100], [0, -100], [-100, -100]], [[0, -100], [10, 0], [0, 90], [-10, 0], [0, -100]]]}"; - OGCGeometry g = OGCGeometry.fromJson(s); - boolean res = g.isSimple(); - assertTrue(res); - assertTrue(g.isSimpleRelaxed()); - - } - - { - // exterior has inversion (planar simple) - String s = "{\"rings\":[[[-100, -100], [-100, 100], [0, 100], [100, 100], [100, -100], [0, -100], [10, 0], [0, 90], [-10, 0], [0, -100], [-100, -100]]]}"; - OGCGeometry g = OGCGeometry.fromJson(s); - boolean res = g.isSimple(); - assertTrue(!res); - assertTrue(g.isSimpleRelaxed()); - } - - { - // two holes touch in one spot, and they also touch exterior in - // two spots, producing disconnected interior - String s = "{\"rings\":[[[-100, -100], [-100, 100], [0, 100], [100, 100], [100, -100], [0, -100], [-100, -100]], [[0, -100], [10, -50], [0, 0], [-10, -50], [0, -100]], [[0, 0], [10, 50], [0, 100], [-10, 50], [0, 0]]]}"; - OGCGeometry g = OGCGeometry.fromJson(s); - boolean res = g.isSimple(); - assertTrue(!res); - assertTrue(g.isSimpleRelaxed()); - } - } catch (Exception ex) { - assertTrue(false); - } - } - - @Test - public void test_polygon_simplify_for_OGC() { - try { - { - //degenerate - String s = "{\"rings\":[[[0, 0], [0, 10], [10, 10], [10, 0], [20, 0], [10, 0], [0, 0]]]}"; - OGCGeometry g = OGCGeometry.fromJson(s); - boolean res = g.isSimple(); - assertTrue(!res); - Geometry resg = OperatorSimplifyOGC.local().execute(g.getEsriGeometry(), null, true, null); - OGCGeometry og = OGCGeometry.createFromEsriGeometry(resg, null); - String res_str = og.asText(); - assertTrue(og.isSimple()); - } - { - String s = "{\"rings\":[[[0, 0], [0, 10], [10, 10], [10, 0], [0, 0]]]}"; - OGCGeometry g = OGCGeometry.fromJson(s); - boolean res = g.isSimple(); - assertTrue(res); - assertTrue(g.isSimpleRelaxed()); - Geometry resg = OperatorSimplifyOGC.local().execute(g.getEsriGeometry(), null, true, null); - OGCGeometry og = OGCGeometry.createFromEsriGeometry(resg, null); - String res_str = og.asText(); - assertTrue(og.geometryType().equals("Polygon")); - assertTrue(((OGCPolygon) og).numInteriorRing() == 0); - assertTrue(og.isSimple()); - } - - {// exterior ring is self-tangent - String s = "{\"rings\":[[[0, 0], [0, 10], [5, 5], [10, 10], [10, 0], [5, 5], [0, 0]]]}"; - OGCGeometry g = OGCGeometry.fromJson(s); - boolean res = g.isSimple(); - assertTrue(!res); - assertTrue(g.isSimpleRelaxed()); - Geometry resg = OperatorSimplifyOGC.local().execute(g.getEsriGeometry(), null, true, null); - OGCGeometry og = OGCGeometry.createFromEsriGeometry(resg, null); - res = og.isSimple(); - assertTrue(res); - assertTrue(og.geometryType().equals("MultiPolygon")); - assertTrue(((OGCGeometryCollection) og).numGeometries() == 2); - } - - {// ring orientation (hole is cw) - String s = "{\"rings\":[[[-100, -100], [-100, 100], [100, 100], [100, -100], [-100, -100]], [[0, 0], [5, 5], [10, 0], [0, 0]]]}"; - OGCGeometry g = OGCGeometry.fromJson(s); - boolean res = g.isSimple(); - assertTrue(!res); - assertTrue(!g.isSimpleRelaxed()); - Geometry resg = OperatorSimplifyOGC.local().execute(g.getEsriGeometry(), null, true, null); - OGCGeometry og = OGCGeometry.createFromEsriGeometry(resg, null); - res = og.isSimple(); - assertTrue(res); - assertTrue(og.geometryType().equals("Polygon")); - assertTrue(((OGCPolygon) og).numInteriorRing() == 1); - } - - {// ring order - String s = "{\"rings\":[[[0, 0], [10, 0], [5, 5], [0, 0]], [[-100, -100], [-100, 100], [100, 100], [100, -100], [-100, -100]]]}"; - OGCGeometry g = OGCGeometry.fromJson(s); - boolean res = g.isSimple(); - assertTrue(!res); - assertTrue(g.isSimpleRelaxed()); - Geometry resg = OperatorSimplifyOGC.local().execute(g.getEsriGeometry(), null, true, null); - OGCGeometry og = OGCGeometry.createFromEsriGeometry(resg, null); - res = og.isSimple(); - assertTrue(res); - assertTrue(og.geometryType().equals("Polygon")); - } - - { - // hole is self tangent - String s = "{\"rings\":[[[-100, -100], [-100, 100], [100, 100], [100, -100], [-100, -100]], [[0, 0], [5, 5], [10, 0], [10, 10], [5, 5], [0, 10], [0, 0]]]}"; - OGCGeometry g = OGCGeometry.fromJson(s); - boolean res = g.isSimple(); - assertTrue(!res); - assertTrue(g.isSimpleRelaxed()); - Geometry resg = OperatorSimplifyOGC.local().execute(g.getEsriGeometry(), null, true, null); - OGCGeometry og = OGCGeometry.createFromEsriGeometry(resg, null); - String res_str = og.asText(); - res = og.isSimple(); - assertTrue(res); - assertTrue(og.geometryType().equals("Polygon")); - assertTrue(((OGCPolygon) og).numInteriorRing() == 2); - } - { - // two holes touch - String s = "{\"rings\":[[[-100, -100], [-100, 100], [100, 100], [100, -100], [-100, -100]], [[0, 0], [10, 0], [5, 5], [0, 0]], [[10, 10], [0, 10], [5, 5], [10, 10]]]}"; - OGCGeometry g = OGCGeometry.fromJson(s); - boolean res = g.isSimple(); - assertTrue(res); - assertTrue(g.isSimpleRelaxed()); - Geometry resg = OperatorSimplifyOGC.local().execute(g.getEsriGeometry(), null, true, null); - OGCGeometry og = OGCGeometry.createFromEsriGeometry(resg, null); - assertTrue(og.geometryType().equals("Polygon")); - assertTrue(((OGCPolygon) og).numInteriorRing() == 2); - } - { - // two holes touch, bad orientation - String s = "{\"rings\":[[[-100, -100], [-100, 100], [100, 100], [100, -100], [-100, -100]], [[0, 0], [5, 5], [10, 0], [0, 0]], [[10, 10], [0, 10], [5, 5], [10, 10]]]}"; - OGCGeometry g = OGCGeometry.fromJson(s); - boolean res = g.isSimple(); - assertTrue(!res); - assertTrue(!g.isSimpleRelaxed()); - Geometry resg = OperatorSimplifyOGC.local().execute(g.getEsriGeometry(), null, true, null); - OGCGeometry og = OGCGeometry.createFromEsriGeometry(resg, null); - assertTrue(og.geometryType().equals("Polygon")); - assertTrue(((OGCPolygon) og).numInteriorRing() == 2); - } - - { - // hole touches exterior in two spots - //OperatorSimplifyOGC produces a multipolygon with two polygons without holes. - String s = "{\"rings\":[[[-100, -100], [-100, 100], [0, 100], [100, 100], [100, -100], [0, -100], [-100, -100]], [[0, -100], [10, 0], [0, 100], [-10, 0], [0, -100]]]}"; - OGCGeometry g = OGCGeometry.fromJson(s); - boolean res = g.isSimple(); - assertTrue(!res); - assertTrue(g.isSimpleRelaxed()); - Geometry resg = OperatorSimplifyOGC.local().execute(g.getEsriGeometry(), null, true, null); - OGCGeometry og = OGCGeometry.createFromEsriGeometry(resg, null); - assertTrue(og.geometryType().equals("MultiPolygon")); - assertTrue(((OGCMultiPolygon) og).numGeometries() == 2); - assertTrue(((OGCPolygon) ((OGCMultiPolygon) og).geometryN(0)).numInteriorRing() == 0); - assertTrue(((OGCPolygon) ((OGCMultiPolygon) og).geometryN(1)).numInteriorRing() == 0); - } - - { - // hole touches exterior in one spot - //OperatorSimplifyOGC produces a polygons with a hole. - String s = "{\"rings\":[[[-100, -100], [-100, 100], [0, 100], [100, 100], [100, -100], [0, -100], [-100, -100]], [[0, -100], [10, 0], [0, 90], [-10, 0], [0, -100]]]}"; - OGCGeometry g = OGCGeometry.fromJson(s); - boolean res = g.isSimple(); - assertTrue(res); - assertTrue(g.isSimpleRelaxed()); - Geometry resg = OperatorSimplifyOGC.local().execute(g.getEsriGeometry(), null, true, null); - OGCGeometry og = OGCGeometry.createFromEsriGeometry(resg, null); - assertTrue(og.geometryType().equals("Polygon")); - assertTrue(((OGCPolygon) og).numInteriorRing() == 1); - } - - { - // exterior has inversion (non simple for OGC) - //OperatorSimplifyOGC produces a polygons with a hole. - String s = "{\"rings\":[[[-100, -100], [-100, 100], [0, 100], [100, 100], [100, -100], [0, -100], [10, 0], [0, 90], [-10, 0], [0, -100], [-100, -100]]]}"; - OGCGeometry g = OGCGeometry.fromJson(s); - boolean res = g.isSimple(); - assertTrue(!res); - assertTrue(g.isSimpleRelaxed()); - Geometry resg = OperatorSimplifyOGC.local().execute(g.getEsriGeometry(), null, true, null); - OGCGeometry og = OGCGeometry.createFromEsriGeometry(resg, null); - assertTrue(og.geometryType().equals("Polygon")); - assertTrue(((OGCPolygon) og).numInteriorRing() == 1); - } - - { - // two holes touch in one spot, and they also touch exterior in - // two spots, producing disconnected interior - //OperatorSimplifyOGC produces two polygons with no holes. - String s = "{\"rings\":[[[-100, -100], [-100, 100], [0, 100], [100, 100], [100, -100], [0, -100], [-100, -100]], [[0, -100], [10, -50], [0, 0], [-10, -50], [0, -100]], [[0, 0], [10, 50], [0, 100], [-10, 50], [0, 0]]]}"; - OGCGeometry g = OGCGeometry.fromJson(s); - boolean res = g.isSimple(); - assertTrue(!res); - assertTrue(g.isSimpleRelaxed()); - Geometry resg = OperatorSimplifyOGC.local().execute(g.getEsriGeometry(), null, true, null); - OGCGeometry og = OGCGeometry.createFromEsriGeometry(resg, null); - assertTrue(og.geometryType().equals("MultiPolygon")); - assertTrue(((OGCMultiPolygon) og).numGeometries() == 2); - assertTrue(((OGCPolygon) ((OGCMultiPolygon) og).geometryN(0)).numInteriorRing() == 0); - assertTrue(((OGCPolygon) ((OGCMultiPolygon) og).geometryN(1)).numInteriorRing() == 0); - } - - - { - OGCGeometry g = OGCGeometry.fromJson("{\"rings\":[[[-3,4],[6,4],[6,-3],[-3,-3],[-3,4]],[[0,2],[2,2],[0,0],[4,0],[4,2],[2,0],[2,2],[4,2],[3,3],[2,2],[1,3],[0,2]]], \"spatialReference\":{\"wkid\":4326}}"); - assertTrue(g.geometryType().equals("Polygon")); - boolean res = g.isSimple(); - assertTrue(!res); - assertTrue(!g.isSimpleRelaxed()); - OGCGeometry simpleG = g.makeSimple(); - assertTrue(simpleG.geometryType().equals("MultiPolygon")); - assertTrue(simpleG.isSimple()); - OGCMultiPolygon mp = (OGCMultiPolygon) simpleG; - assertTrue(mp.numGeometries() == 2); - OGCPolygon g1 = (OGCPolygon) mp.geometryN(0); - OGCPolygon g2 = (OGCPolygon) mp.geometryN(1); - assertTrue((g1.numInteriorRing() == 0 && g1.numInteriorRing() == 2) || - (g1.numInteriorRing() == 2 && g2.numInteriorRing() == 0)); - - OGCGeometry oldOutput = OGCGeometry.fromJson("{\"rings\":[[[-3,-3],[-3,4],[6,4],[6,-3],[-3,-3]],[[0,0],[2,0],[4,0],[4,2],[3,3],[2,2],[1,3],[0,2],[2,2],[0,0]],[[2,0],[2,2],[4,2],[2,0]]],\"spatialReference\":{\"wkid\":4326}}"); - assertTrue(oldOutput.isSimpleRelaxed()); - assertFalse(oldOutput.isSimple()); - } - } catch (Exception ex) { - assertTrue(false); - } - } - - @Test - public void test_polyline_is_simple_for_OGC() { - try { - { - String s = "{\"paths\":[[[0, 10], [8, 5], [5, 2], [6, 0]]]}"; - OGCGeometry g = OGCGeometry.fromJson(s); - boolean res = g.isSimple(); - assertTrue(res); - assertTrue(g.isSimpleRelaxed()); - } - { - String s = "{\"paths\":[[[0, 10], [6, 0], [7, 5], [0, 3]]]}";// self - // intersection - OGCGeometry g = OGCGeometry.fromJson(s); - boolean res = g.isSimple(); - assertTrue(!res); - assertTrue(g.isSimpleRelaxed()); - } - - { - String s = "{\"paths\":[[[0, 10], [6, 0], [0, 3], [0, 10]]]}"; // closed - OGCGeometry g = OGCGeometry.fromJson(s); - boolean res = g.isSimple(); - assertTrue(res); - assertTrue(g.isSimpleRelaxed()); - } - - { - String s = "{\"paths\":[[[0, 10], [5, 5], [6, 0], [0, 3], [5, 5], [0, 9], [0, 10]]]}"; // closed - // with - // self - // tangent - OGCGeometry g = OGCGeometry.fromJson(s); - boolean res = g.isSimple(); - assertTrue(!res); - assertTrue(g.isSimpleRelaxed()); - } - - { - String s = "{\"paths\":[[[0, 10], [5, 2]], [[5, 2], [6, 0]]]}";// two - // paths - // connected - // at - // a - // point - OGCGeometry g = OGCGeometry.fromJson(s); - boolean res = g.isSimple(); - assertTrue(res); - assertTrue(g.isSimpleRelaxed()); - } - - { - String s = "{\"paths\":[[[0, 0], [3, 3], [5, 0], [0, 0]], [[0, 10], [3, 3], [10, 10], [0, 10]]]}";// two - // closed - // rings - // touch - // at - // one - // point - OGCGeometry g = OGCGeometry.fromJson(s); - boolean res = g.isSimple(); - assertTrue(!res); - assertTrue(g.isSimpleRelaxed()); - } - - { - String s = "{\"paths\":[[[3, 3], [0, 0], [5, 0], [3, 3]], [[3, 3], [0, 10], [10, 10], [3, 3]]]}"; - // two closed rings touch at one point. The touch happens at the - // endpoints of the paths. - OGCGeometry g = OGCGeometry.fromJson(s); - boolean res = g.isSimple(); - assertTrue(!res); - assertTrue(g.isSimpleRelaxed()); - } - - { - String s = "{\"paths\":[[[0, 0], [10, 10]], [[0, 10], [10, 0]]]}";// two - // lines - // intersect - OGCGeometry g = OGCGeometry.fromJson(s); - boolean res = g.isSimple(); - assertTrue(!res); - assertTrue(g.isSimpleRelaxed()); - } - - { - String s = "{\"paths\":[[[0, 0], [5, 5], [0, 10]], [[10, 10], [5, 5], [10, 0]]]}";// two - // paths - // share - // mid - // point. - OGCGeometry g = OGCGeometry.fromJson(s); - boolean res = g.isSimple(); - assertTrue(!res); - assertTrue(g.isSimpleRelaxed()); - } - } catch (Exception ex) { - assertTrue(false); - } - - } - - @Test - public void test_multipoint_is_simple_for_OGC() { - try { - - SpatialReference sr = SpatialReference.create(4326); - { - String s = "{\"points\":[[0, 0], [5, 5], [0, 10]]}"; - OGCGeometry g = OGCGeometry.fromJson(s); - boolean res = g.isSimple(); - assertTrue(res); - assertTrue(g.isSimpleRelaxed()); - } - { - String s = "{\"points\":[[0, 0], [5, 5], [0, 0], [0, 10]]}"; - OGCGeometry g = OGCGeometry.fromJson(s); - boolean res = g.isSimple(); - assertTrue(!res); - assertTrue(!g.isSimpleRelaxed()); - } - { - String s = "{\"points\":[[0, 0], [5, 5], [1e-10, -1e-10], [0, 10]]}"; - OGCGeometry g = OGCGeometry.fromJson(s); - g.setSpatialReference(sr); - boolean res = g.isSimple(); - assertTrue(!res); - assertTrue(g.isSimpleRelaxed()); - } - } catch (Exception ex) { - assertTrue(false); - } - - } - - @Test - public void testGeometryCollectionBuffer() { - OGCGeometry g = OGCGeometry - .fromText("GEOMETRYCOLLECTION(POINT(1 1), POINT(1 1), POINT(1 2), LINESTRING (0 0, 1 1, 1 0, 0 1), MULTIPOLYGON EMPTY, MULTILINESTRING EMPTY)"); - OGCGeometry simpleG = g.buffer(0); - String t = simpleG.geometryType(); - String rt = simpleG.asText(); - assertTrue(simpleG.geometryType().equals("GeometryCollection")); - } - - @Test - public void testIsectTria1() { - String wkt = "polygon((1 0, 3 0, 1 2, 1 0))"; - String wk2 = "polygon((0 1, 2 1, 0 3, 0 1))"; - OGCGeometry g0 = OGCGeometry.fromText(wkt); - OGCGeometry g1 = OGCGeometry.fromText(wk2); - g0.setSpatialReference(SpatialReference.create(4326)); - g1.setSpatialReference(SpatialReference.create(4326)); - OGCGeometry rslt = g0.intersection(g1); - assertTrue(rslt != null); - assertTrue(rslt.geometryType().equals("Polygon")); - assertTrue(rslt.esriSR.getID() == 4326); - String s = rslt.asText(); - } - - @Test - public void testIsectTriaJson1() throws Exception { - String json1 = "{\"rings\":[[[1, 0], [3, 0], [1, 2], [1, 0]]], \"spatialReference\":{\"wkid\":4326}}"; - String json2 = "{\"rings\":[[[0, 1], [2, 1], [0, 3], [0, 1]]], \"spatialReference\":{\"wkid\":4326}}"; - OGCGeometry g0 = OGCGeometry.fromJson(json1); - OGCGeometry g1 = OGCGeometry.fromJson(json2); - OGCGeometry rslt = g0.intersection(g1); - assertTrue(rslt != null); - assertTrue(rslt.geometryType().equals("Polygon")); - assertTrue(rslt.esriSR.getID() == 4326); - String s = GeometryEngine.geometryToJson(rslt.getEsriSpatialReference().getID(), rslt.getEsriGeometry()); - } - - @Test - public void testIsectTria2() { - String wkt = "polygon((1 0, 3 0, 1 2, 1 0))"; - String wk2 = "polygon((0 3, 2 1, 3 1, 0 3))"; - OGCGeometry g0 = OGCGeometry.fromText(wkt); - OGCGeometry g1 = OGCGeometry.fromText(wk2); - g0.setSpatialReference(null); - g1.setSpatialReference(null); - OGCGeometry rslt = g0.intersection(g1); - assertTrue(rslt != null); - assertTrue(rslt.dimension() == 1); - assertTrue(rslt.geometryType().equals("LineString")); - String s = rslt.asText(); - } - - @Test - public void testIsectTria3() { - String wkt = "polygon((1 0, 3 0, 1 2, 1 0))"; - String wk2 = "polygon((2 2, 2 1, 3 1, 2 2))"; - OGCGeometry g0 = OGCGeometry.fromText(wkt); - OGCGeometry g1 = OGCGeometry.fromText(wk2); - g0.setSpatialReference(SpatialReference.create(4326)); - g1.setSpatialReference(SpatialReference.create(4326)); - OGCGeometry rslt = g0.intersection(g1); - assertTrue(rslt != null); - assertTrue(rslt.dimension() == 0); - assertTrue(rslt.geometryType().equals("Point")); - assertTrue(rslt.esriSR.getID() == 4326); - String s = rslt.asText(); - } - - @Test - public void testMultiPointSinglePoint() { - String wkt = "multipoint((1 0))"; - OGCGeometry g0 = OGCGeometry.fromText(wkt); - assertTrue(g0.dimension() == 0); - String gt = g0.geometryType(); - assertTrue(gt.equals("MultiPoint")); - OGCMultiPoint mp = (OGCMultiPoint) g0; - assertTrue(mp.numGeometries() == 1); - OGCGeometry p = mp.geometryN(0); - String s = p.asText(); - assertTrue(s.equals("POINT (1 0)")); - - String ms = p.convertToMulti().asText(); - assertTrue(ms.equals("MULTIPOINT ((1 0))")); - - } - - @Test - public void testWktMultiPolygon() { - String restJson = "{\"rings\": [[[-100, -100], [-100, 100], [100, 100], [100, -100], [-100, -100]], [[-90, -90], [90, 90], [-90, 90], [90, -90], [-90, -90]], [[-10, -10], [-10, 10], [10, 10], [10, -10], [-10, -10]]]}"; - MapGeometry g = null; - g = OperatorImportFromJson.local().execute(Geometry.Type.Unknown, restJson); - String wkt = OperatorExportToWkt.local().execute(0, g.getGeometry(), null); - assertTrue(wkt.equals("MULTIPOLYGON (((-100 -100, 100 -100, 100 100, -100 100, -100 -100), (-90 -90, 90 -90, -90 90, 90 90, -90 -90)), ((-10 -10, 10 -10, 10 10, -10 10, -10 -10)))")); - } - - @Test - public void testMultiPolygonArea() { - //MultiPolygon Area #36 - String wkt = "MULTIPOLYGON (((1001200 2432900, 1001420 2432691, 1001250 2432388, 1001498 2432325, 1001100 2432100, 1001500 2431900, 1002044 2431764, 1002059 2432120, 1002182 2432003, 1002400 2432300, 1002650 2432150, 1002610 2432323, 1002772 2432434, 1002410 2432821, 1002700 2433000, 1001824 2432866, 1001600 2433150, 1001200 2432900)), ((1000393 2433983, 1000914 2434018, 1000933 2433817, 1000568 2433834, 1000580 2433584, 1000700 2433750, 1000800 2433650, 1000700 2433450, 1000600 2433550, 1000200 2433350, 1000100 2433900, 1000393 2433983)), ((1001200 2432900, 1000878 2432891, 1000900 2433300, 1001659 2433509, 1001600 2433150, 1001200 2432900)), ((1002450 2431650, 1002300 2431650, 1002300 2431900, 1002500 2432100, 1002600 2431800, 1002450 2431800, 1002450 2431650)), ((999750 2433550, 999850 2433600, 999900 2433350, 999780 2433433, 999750 2433550)), ((1002950 2432050, 1003005 2431932, 1002850 2432250, 1002928 2432210, 1002950 2432050)), ((1002600 2431750, 1002642 2431882, 1002750 2431900, 1002750 2431750, 1002600 2431750)), ((1002950 2431750, 1003050 2431650, 1002968 2431609, 1002950 2431750)))"; - { - OGCGeometry ogcg = OGCGeometry.fromText(wkt); - assertTrue(ogcg.geometryType().equals("MultiPolygon")); - OGCMultiPolygon mp = (OGCMultiPolygon) ogcg; - double a = mp.area(); - assertTrue(Math.abs(mp.area() - 2037634.5) < a * 1e-14); - } - - { - OGCGeometry ogcg = OGCGeometry.fromText(wkt); - assertTrue(ogcg.geometryType().equals("MultiPolygon")); - Geometry g = ogcg.getEsriGeometry(); - double a = g.calculateArea2D(); - assertTrue(Math.abs(a - 2037634.5) < a * 1e-14); - } - } - - @Test - public void testPolylineSimplifyIssueGithub52() throws Exception { - String json = "{\"paths\":[[[2,0],[4,3],[5,1],[3.25,1.875],[1,3]]],\"spatialReference\":{\"wkid\":4326}}"; - { - OGCGeometry g = OGCGeometry.fromJson(json); - assertTrue(g.geometryType().equals("LineString")); - OGCGeometry simpleG = g.makeSimple();//make ogc simple - assertTrue(simpleG.geometryType().equals("MultiLineString")); - assertTrue(simpleG.isSimpleRelaxed());//geodatabase simple - assertTrue(simpleG.isSimple());//ogc simple - OGCMultiLineString mls = (OGCMultiLineString) simpleG; - assertTrue(mls.numGeometries() == 4); - OGCGeometry baseGeom = OGCGeometry.fromJson("{\"paths\":[[[2,0],[3.25,1.875]],[[3.25,1.875],[4,3],[5,1]],[[5,1],[3.25,1.875]],[[3.25,1.875],[1,3]]],\"spatialReference\":{\"wkid\":4326}}"); - assertTrue(simpleG.equals(baseGeom)); - - } - } - + @Override + protected void setUp() throws Exception { + super.setUp(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + } + + @Test + public void testPoint() { + OGCGeometry g = OGCGeometry.fromText("POINT(1 2)"); + assertTrue(g.geometryType().equals("Point")); + OGCPoint p = (OGCPoint) g; + assertTrue(p.X() == 1); + assertTrue(p.Y() == 2); + assertTrue(g.equals(OGCGeometry.fromText("POINT(1 2)"))); + assertTrue(!g.equals(OGCGeometry.fromText("POINT(1 3)"))); + assertTrue(g.equals((Object)OGCGeometry.fromText("POINT(1 2)"))); + assertTrue(!g.equals((Object)OGCGeometry.fromText("POINT(1 3)"))); + OGCGeometry buf = g.buffer(10); + assertTrue(buf.geometryType().equals("Polygon")); + OGCPolygon poly = (OGCPolygon) buf.envelope(); + double a = poly.area(); + assertTrue(Math.abs(a - 400) < 1e-1); + } + + @Test + public void testPolygon() throws Exception { + OGCGeometry g = OGCGeometry + .fromText("POLYGON((-10 -10, 10 -10, 10 10, -10 10, -10 -10), (-5 -5, -5 5, 5 5, 5 -5, -5 -5))"); + assertTrue(g.geometryType().equals("Polygon")); + OGCPolygon p = (OGCPolygon) g; + assertTrue(p.numInteriorRing() == 1); + OGCLineString ls = p.exteriorRing(); + // assertTrue(ls.pointN(1).equals(OGCGeometry.fromText("POINT(10 -10)"))); + boolean b = ls + .Equals(OGCGeometry + .fromText("LINESTRING(-10 -10, 10 -10, 10 10, -10 10, -10 -10)")); + assertTrue(b); + OGCLineString lsi = p.interiorRingN(0); + b = lsi.Equals(OGCGeometry + .fromText("LINESTRING(-5 -5, -5 5, 5 5, 5 -5, -5 -5)")); + assertTrue(b); + b = lsi.equals((Object)OGCGeometry + .fromText("LINESTRING(-5 -5, -5 5, 5 5, 5 -5, -5 -5)")); + assertTrue(!lsi.Equals(ls)); + OGCMultiCurve boundary = p.boundary(); + String s = boundary.asText(); + assertTrue(s.equals("MULTILINESTRING ((-10 -10, 10 -10, 10 10, -10 10, -10 -10), (-5 -5, -5 5, 5 5, 5 -5, -5 -5))")); + + { + OGCGeometry g2 = OGCGeometry.fromGeoJson( + "{\"type\": \"Polygon\", \"coordinates\": [[[1.00000001,1.00000001], [4.00000001,1.00000001], [4.00000001,4.00000001], [1.00000001,4.00000001]]]}"); + OGCGeometry + .fromGeoJson( + "{\"type\": \"LineString\", \"coordinates\": [[1.00000001,1.00000001], [7.00000001,8.00000001]]}") + .intersects(g2); + OGCGeometry + .fromGeoJson( + "{\"type\": \"LineString\", \"coordinates\": [[2.449,4.865], [7.00000001,8.00000001]]}") + .intersects(g2); + + OGCGeometry g3 = OGCGeometry.fromGeoJson( + "{\"type\": \"Polygon\", \"coordinates\": [[[1.00000001,1.00000001], [4.00000001,1.00000001], [4.00000001,4.00000001], [1.00000001,4.00000001]]]}"); + boolean bb = g2.equals((Object) g3); + assertTrue(bb); + } + } + + @Test + public void testGeometryCollection() throws Exception { + OGCGeometry g = OGCGeometry + .fromText("GEOMETRYCOLLECTION(POLYGON EMPTY, POINT(1 1), LINESTRING EMPTY, MULTIPOLYGON EMPTY, MULTILINESTRING EMPTY)"); + assertTrue(g.geometryType().equals("GeometryCollection")); + OGCConcreteGeometryCollection gc = (OGCConcreteGeometryCollection) g; + assertTrue(gc.numGeometries() == 5); + assertTrue(gc.geometryN(0).geometryType().equals("Polygon")); + assertTrue(gc.geometryN(1).geometryType().equals("Point")); + assertTrue(gc.geometryN(2).geometryType().equals("LineString")); + assertTrue(gc.geometryN(3).geometryType().equals("MultiPolygon")); + assertTrue(gc.geometryN(4).geometryType().equals("MultiLineString")); + + g = OGCGeometry + .fromText("GEOMETRYCOLLECTION(POLYGON EMPTY, POINT(1 1), GEOMETRYCOLLECTION EMPTY, LINESTRING EMPTY, GEOMETRYCOLLECTION(POLYGON EMPTY, POINT(1 1), LINESTRING EMPTY, MULTIPOLYGON EMPTY, MULTILINESTRING EMPTY, MULTIPOINT EMPTY), MULTIPOLYGON EMPTY, MULTILINESTRING EMPTY)"); + assertTrue(g.geometryType().equals("GeometryCollection")); + gc = (OGCConcreteGeometryCollection) g; + assertTrue(gc.numGeometries() == 7); + assertTrue(gc.geometryN(0).geometryType().equals("Polygon")); + assertTrue(gc.geometryN(1).geometryType().equals("Point")); + assertTrue(gc.geometryN(2).geometryType().equals("GeometryCollection")); + assertTrue(gc.geometryN(3).geometryType().equals("LineString")); + assertTrue(gc.geometryN(4).geometryType().equals("GeometryCollection")); + assertTrue(gc.geometryN(5).geometryType().equals("MultiPolygon")); + assertTrue(gc.geometryN(6).geometryType().equals("MultiLineString")); + + OGCConcreteGeometryCollection gc2 = (OGCConcreteGeometryCollection) gc + .geometryN(4); + assertTrue(gc2.numGeometries() == 6); + assertTrue(gc2.geometryN(0).geometryType().equals("Polygon")); + assertTrue(gc2.geometryN(1).geometryType().equals("Point")); + assertTrue(gc2.geometryN(2).geometryType().equals("LineString")); + assertTrue(gc2.geometryN(3).geometryType().equals("MultiPolygon")); + assertTrue(gc2.geometryN(4).geometryType().equals("MultiLineString")); + assertTrue(gc2.geometryN(5).geometryType().equals("MultiPoint")); + + ByteBuffer wkbBuffer = g.asBinary(); + g = OGCGeometry.fromBinary(wkbBuffer); + + assertTrue(g.geometryType().equals("GeometryCollection")); + gc = (OGCConcreteGeometryCollection) g; + assertTrue(gc.numGeometries() == 7); + assertTrue(gc.geometryN(0).geometryType().equals("Polygon")); + assertTrue(gc.geometryN(1).geometryType().equals("Point")); + assertTrue(gc.geometryN(2).geometryType().equals("GeometryCollection")); + assertTrue(gc.geometryN(3).geometryType().equals("LineString")); + assertTrue(gc.geometryN(4).geometryType().equals("GeometryCollection")); + assertTrue(gc.geometryN(5).geometryType().equals("MultiPolygon")); + assertTrue(gc.geometryN(6).geometryType().equals("MultiLineString")); + + gc2 = (OGCConcreteGeometryCollection) gc.geometryN(4); + assertTrue(gc2.numGeometries() == 6); + assertTrue(gc2.geometryN(0).geometryType().equals("Polygon")); + assertTrue(gc2.geometryN(1).geometryType().equals("Point")); + assertTrue(gc2.geometryN(2).geometryType().equals("LineString")); + assertTrue(gc2.geometryN(3).geometryType().equals("MultiPolygon")); + assertTrue(gc2.geometryN(4).geometryType().equals("MultiLineString")); + assertTrue(gc2.geometryN(5).geometryType().equals("MultiPoint")); + + String wktString = g.asText(); + assertTrue(wktString + .equals("GEOMETRYCOLLECTION (POLYGON EMPTY, POINT (1 1), GEOMETRYCOLLECTION EMPTY, LINESTRING EMPTY, GEOMETRYCOLLECTION (POLYGON EMPTY, POINT (1 1), LINESTRING EMPTY, MULTIPOLYGON EMPTY, MULTILINESTRING EMPTY, MULTIPOINT EMPTY), MULTIPOLYGON EMPTY, MULTILINESTRING EMPTY)")); + + g = OGCGeometry + .fromGeoJson("{\"type\" : \"GeometryCollection\", \"geometries\" : [{\"type\" : \"Polygon\", \"coordinates\" : []}, {\"type\" : \"Point\", \"coordinates\" : [1, 1]}, {\"type\" : \"GeometryCollection\", \"geometries\" : []}, {\"type\" : \"LineString\", \"coordinates\" : []}, {\"type\" : \"GeometryCollection\", \"geometries\" : [{\"type\": \"Polygon\", \"coordinates\" : []}, {\"type\" : \"Point\", \"coordinates\" : [1,1]}, {\"type\" : \"LineString\", \"coordinates\" : []}, {\"type\" : \"MultiPolygon\", \"coordinates\" : []}, {\"type\" : \"MultiLineString\", \"coordinates\" : []}, {\"type\" : \"MultiPoint\", \"coordinates\" : []}]}, {\"type\" : \"MultiPolygon\", \"coordinates\" : []}, {\"type\" : \"MultiLineString\", \"coordinates\" : []} ] }"); + + wktString = g.asText(); + assertTrue(wktString + .equals("GEOMETRYCOLLECTION (POLYGON EMPTY, POINT (1 1), GEOMETRYCOLLECTION EMPTY, LINESTRING EMPTY, GEOMETRYCOLLECTION (POLYGON EMPTY, POINT (1 1), LINESTRING EMPTY, MULTIPOLYGON EMPTY, MULTILINESTRING EMPTY, MULTIPOINT EMPTY), MULTIPOLYGON EMPTY, MULTILINESTRING EMPTY)")); + + assertTrue(g.equals((Object)OGCGeometry.fromText(wktString))); + + assertTrue(g.hashCode() == OGCGeometry.fromText(wktString).hashCode()); + + } + + @Test + public void testFirstPointOfPolygon() { + OGCGeometry g = OGCGeometry + .fromText("POLYGON((-10 -10, 10 -10, 10 10, -10 10, -10 -10), (-5 -5, -5 5, 5 5, 5 -5, -5 -5))"); + assertTrue(g.geometryType().equals("Polygon")); + OGCPolygon p = (OGCPolygon) g; + assertTrue(p.numInteriorRing() == 1); + OGCLineString ls = p.exteriorRing(); + OGCPoint p1 = ls.pointN(1); + assertTrue(ls.pointN(1).equals(OGCGeometry.fromText("POINT(10 -10)"))); + OGCPoint p2 = ls.pointN(3); + assertTrue(ls.pointN(3).equals(OGCGeometry.fromText("POINT(-10 10)"))); + OGCPoint p0 = ls.pointN(0); + assertTrue(ls.pointN(0).equals(OGCGeometry.fromText("POINT(-10 -10)"))); + String ms = g.convertToMulti().asText(); + assertTrue(ms.equals("MULTIPOLYGON (((-10 -10, 10 -10, 10 10, -10 10, -10 -10), (-5 -5, -5 5, 5 5, 5 -5, -5 -5)))")); + + } + + @Test + public void testFirstPointOfLineString() { + OGCGeometry g = OGCGeometry + .fromText("LINESTRING(-10 -10, 10 -10, 10 10, -10 10, -10 -10)"); + assertTrue(g.geometryType().equals("LineString")); + OGCLineString p = (OGCLineString) g; + assertTrue(p.numPoints() == 5); + assertTrue(p.isClosed()); + assertTrue(p.pointN(1).equals(OGCGeometry.fromText("POINT(10 -10)"))); + String ms = g.convertToMulti().asText(); + assertTrue(ms.equals("MULTILINESTRING ((-10 -10, 10 -10, 10 10, -10 10, -10 -10))")); + } + + @Test + public void testPointInPolygon() { + OGCGeometry g = OGCGeometry + .fromText("POLYGON((-10 -10, 10 -10, 10 10, -10 10, -10 -10), (-5 -5, -5 5, 5 5, 5 -5, -5 -5))"); + assertTrue(g.geometryType().equals("Polygon")); + assertTrue(!g.contains(OGCGeometry.fromText("POINT(0 0)"))); + assertTrue(g.contains(OGCGeometry.fromText("POINT(9 9)"))); + assertTrue(!g.contains(OGCGeometry.fromText("POINT(-20 1)"))); + assertTrue(g.disjoint(OGCGeometry.fromText("POINT(0 0)"))); + assertTrue(!g.disjoint(OGCGeometry.fromText("POINT(9 9)"))); + assertTrue(g.disjoint(OGCGeometry.fromText("POINT(-20 1)"))); + } + + @Test + public void testMultiPolygon() { + { + OGCGeometry g = OGCGeometry + .fromText("MULTIPOLYGON(((-10 -10, 10 -10, 10 10, -10 10, -10 -10), (-5 -5, -5 5, 5 5, 5 -5, -5 -5)))"); + assertTrue(g.geometryType().equals("MultiPolygon")); // the type is + // reduced + assertTrue(!g.contains(OGCGeometry.fromText("POINT(0 0)"))); + assertTrue(g.contains(OGCGeometry.fromText("POINT(9 9)"))); + assertTrue(!g.contains(OGCGeometry.fromText("POINT(-20 1)"))); + assertTrue(g.disjoint(OGCGeometry.fromText("POINT(0 0)"))); + assertTrue(!g.disjoint(OGCGeometry.fromText("POINT(9 9)"))); + assertTrue(g.disjoint(OGCGeometry.fromText("POINT(-20 1)"))); + assertTrue(g.convertToMulti() == g); + } + + { + OGCGeometry g = OGCGeometry + .fromText("MULTIPOLYGON(((-10 -10, 10 -10, 10 10, -10 10, -10 -10), (-5 -5, -5 5, 5 5, 5 -5, -5 -5)), ((90 90, 110 90, 110 110, 90 110, 90 90), (95 95, 95 105, 105 105, 105 95, 95 95)))"); + assertTrue(g.geometryType().equals("MultiPolygon")); // the type is + + OGCMultiPolygon mp = (OGCMultiPolygon)g; + assertTrue(mp.numGeometries() == 2); + OGCGeometry p1 = mp.geometryN(0); + assertTrue(p1.geometryType().equals("Polygon")); // the type is + assertTrue(p1.contains(OGCGeometry.fromText("POINT(9 9)"))); + assertTrue(!p1.contains(OGCGeometry.fromText("POINT(109 109)"))); + OGCGeometry p2 = mp.geometryN(1); + assertTrue(p2.geometryType().equals("Polygon")); // the type is + assertTrue(!p2.contains(OGCGeometry.fromText("POINT(9 9)"))); + assertTrue(p2.contains(OGCGeometry.fromText("POINT(109 109)"))); + } + } + + @Test + public void testMultiPolygonUnion() { + OGCGeometry g = OGCGeometry + .fromText("POLYGON((-10 -10, 10 -10, 10 10, -10 10, -10 -10), (-5 -5, -5 5, 5 5, 5 -5, -5 -5))"); + OGCGeometry g2 = OGCGeometry + .fromText("POLYGON((90 90, 110 90, 110 110, 90 110, 90 90))"); + OGCGeometry u = g.union(g2); + assertTrue(u.geometryType().equals("MultiPolygon")); + assertTrue(!u.contains(OGCGeometry.fromText("POINT(0 0)"))); + assertTrue(u.contains(OGCGeometry.fromText("POINT(9 9)"))); + assertTrue(!u.contains(OGCGeometry.fromText("POINT(-20 1)"))); + assertTrue(u.disjoint(OGCGeometry.fromText("POINT(0 0)"))); + assertTrue(!u.disjoint(OGCGeometry.fromText("POINT(9 9)"))); + assertTrue(u.disjoint(OGCGeometry.fromText("POINT(-20 1)"))); + assertTrue(u.contains(OGCGeometry.fromText("POINT(100 100)"))); + } + + @Test + public void testIntersection() { + OGCGeometry g = OGCGeometry.fromText("LINESTRING(0 0, 10 10)"); + OGCGeometry g2 = OGCGeometry.fromText("LINESTRING(10 0, 0 10)"); + OGCGeometry u = g.intersection(g2); + assertTrue(u.dimension() == 0); + String s = u.asText(); + assertTrue(u.equals(OGCGeometry.fromText("POINT(5 5)"))); + } + + @Test + public void testPointSymDif() { + OGCGeometry g1 = OGCGeometry.fromText("POINT(1 2)"); + OGCGeometry g2 = OGCGeometry.fromText("POINT(3 4)"); + OGCGeometry gg = g1.symDifference(g2); + assertTrue(gg.equals(OGCGeometry.fromText("MULTIPOINT(1 2, 3 4)"))); + + OGCGeometry g3 = OGCGeometry.fromText("POINT(1 2)"); + OGCGeometry gg1 = g1.symDifference(g3); + assertTrue(gg1 == null || gg1.isEmpty()); + + } + + @Test + public void testNullSr() { + String wkt = "point (0 0)"; + OGCGeometry g = OGCGeometry.fromText(wkt); + g.setSpatialReference(null); + assertTrue(g.SRID() < 1); + } + + @Test + public void testIsectPoint() { + String wkt = "point (0 0)"; + String wk2 = "point (0 0)"; + OGCGeometry g0 = OGCGeometry.fromText(wkt); + OGCGeometry g1 = OGCGeometry.fromText(wk2); + g0.setSpatialReference(null); + g1.setSpatialReference(null); + try { + OGCGeometry rslt = g0.intersection(g1); // ArrayIndexOutOfBoundsException + assertTrue(rslt != null); + } catch (Exception e) { + assertTrue(false); + } + } + + @Test + public void testIsectDisjoint() { + String wk3 = "linestring (0 0, 1 1)"; + String wk4 = "linestring (2 2, 4 4)"; + OGCGeometry g0 = OGCGeometry.fromText(wk3); + OGCGeometry g1 = OGCGeometry.fromText(wk4); + g0.setSpatialReference(null); + g1.setSpatialReference(null); + try { + OGCGeometry rslt = g0.intersection(g1); // null + assertTrue(rslt != null); + } catch (Exception e) { + assertTrue(false); + } + } + + @Test + public void test_polygon_is_simple_for_OGC() { + try { + { + String s = "{\"rings\":[[[0, 0], [0, 10], [10, 10], [10, 0], [0, 0]]]}"; + OGCGeometry g = OGCGeometry.fromJson(s); + boolean res = g.isSimple(); + assertTrue(res); + assertTrue(g.isSimpleRelaxed()); + } + + {// exterior ring is self-tangent + String s = "{\"rings\":[[[0, 0], [0, 10], [5, 5], [10, 10], [10, 0], [5, 5], [0, 0]]]}"; + OGCGeometry g = OGCGeometry.fromJson(s); + boolean res = g.isSimple(); + assertTrue(!res); + assertTrue(g.isSimpleRelaxed()); + } + + {// ring orientation (hole is cw) + String s = "{\"rings\":[[[-100, -100], [-100, 100], [100, 100], [100, -100], [-100, -100]], [[0, 0], [5, 5], [10, 0], [0, 0]]]}"; + OGCGeometry g = OGCGeometry.fromJson(s); + boolean res = g.isSimple(); + assertTrue(!res); + assertTrue(!g.isSimpleRelaxed()); + } + { + String s = "{\"rings\":[[[-100, -100], [-100, 100], [100, 100], [100, -100], [-100, -100]], [[0, 0], [10, 0], [5, 5], [0, 0]]]}"; + OGCGeometry g = OGCGeometry.fromJson(s); + boolean res = g.isSimple(); + assertTrue(res); + assertTrue(g.isSimpleRelaxed()); + } + + {// ring order + String s = "{\"rings\":[[[0, 0], [10, 0], [5, 5], [0, 0]], [[-100, -100], [-100, 100], [100, 100], [100, -100], [-100, -100]]]}"; + OGCGeometry g = OGCGeometry.fromJson(s); + boolean res = g.isSimple(); + assertTrue(!res); + assertTrue(g.isSimpleRelaxed()); + } + + { + // hole is self tangent + String s = "{\"rings\":[[[-100, -100], [-100, 100], [100, 100], [100, -100], [-100, -100]], [[0, 0], [5, 5], [10, 0], [10, 10], [5, 5], [0, 10], [0, 0]]]}"; + OGCGeometry g = OGCGeometry.fromJson(s); + boolean res = g.isSimple(); + assertTrue(!res); + assertTrue(g.isSimpleRelaxed()); + } + { + // two holes touch + String s = "{\"rings\":[[[-100, -100], [-100, 100], [100, 100], [100, -100], [-100, -100]], [[0, 0], [10, 0], [5, 5], [0, 0]], [[10, 10], [0, 10], [5, 5], [10, 10]]]}"; + OGCGeometry g = OGCGeometry.fromJson(s); + boolean res = g.isSimple(); + assertTrue(res); + assertTrue(g.isSimpleRelaxed()); + } + { + // two holes touch, bad orientation + String s = "{\"rings\":[[[-100, -100], [-100, 100], [100, 100], [100, -100], [-100, -100]], [[0, 0], [5, 5], [10, 0], [0, 0]], [[10, 10], [0, 10], [5, 5], [10, 10]]]}"; + OGCGeometry g = OGCGeometry.fromJson(s); + boolean res = g.isSimple(); + assertTrue(!res); + assertTrue(!g.isSimpleRelaxed()); + + } + + { + // hole touches exterior in two spots + String s = "{\"rings\":[[[-100, -100], [-100, 100], [0, 100], [100, 100], [100, -100], [0, -100], [-100, -100]], [[0, -100], [10, 0], [0, 100], [-10, 0], [0, -100]]]}"; + OGCGeometry g = OGCGeometry.fromJson(s); + boolean res = g.isSimple(); + assertTrue(!res); + assertTrue(g.isSimpleRelaxed()); + } + + { + // hole touches exterior in one spot + String s = "{\"rings\":[[[-100, -100], [-100, 100], [0, 100], [100, 100], [100, -100], [0, -100], [-100, -100]], [[0, -100], [10, 0], [0, 90], [-10, 0], [0, -100]]]}"; + OGCGeometry g = OGCGeometry.fromJson(s); + boolean res = g.isSimple(); + assertTrue(res); + assertTrue(g.isSimpleRelaxed()); + + } + + { + // exterior has inversion (planar simple) + String s = "{\"rings\":[[[-100, -100], [-100, 100], [0, 100], [100, 100], [100, -100], [0, -100], [10, 0], [0, 90], [-10, 0], [0, -100], [-100, -100]]]}"; + OGCGeometry g = OGCGeometry.fromJson(s); + boolean res = g.isSimple(); + assertTrue(!res); + assertTrue(g.isSimpleRelaxed()); + } + + { + // two holes touch in one spot, and they also touch exterior in + // two spots, producing disconnected interior + String s = "{\"rings\":[[[-100, -100], [-100, 100], [0, 100], [100, 100], [100, -100], [0, -100], [-100, -100]], [[0, -100], [10, -50], [0, 0], [-10, -50], [0, -100]], [[0, 0], [10, 50], [0, 100], [-10, 50], [0, 0]]]}"; + OGCGeometry g = OGCGeometry.fromJson(s); + boolean res = g.isSimple(); + assertTrue(!res); + assertTrue(g.isSimpleRelaxed()); + } + } catch (Exception ex) { + assertTrue(false); + } + } + + @Test + public void test_polygon_simplify_for_OGC() { + try { + { + //degenerate + String s = "{\"rings\":[[[0, 0], [0, 10], [10, 10], [10, 0], [20, 0], [10, 0], [0, 0]]]}"; + OGCGeometry g = OGCGeometry.fromJson(s); + boolean res = g.isSimple(); + assertTrue(!res); + Geometry resg = OperatorSimplifyOGC.local().execute(g.getEsriGeometry(), null, true, null); + OGCGeometry og = OGCGeometry.createFromEsriGeometry(resg, null); + String res_str = og.asText(); + assertTrue(og.isSimple()); + } + { + String s = "{\"rings\":[[[0, 0], [0, 10], [10, 10], [10, 0], [0, 0]]]}"; + OGCGeometry g = OGCGeometry.fromJson(s); + boolean res = g.isSimple(); + assertTrue(res); + assertTrue(g.isSimpleRelaxed()); + Geometry resg = OperatorSimplifyOGC.local().execute(g.getEsriGeometry(), null, true, null); + OGCGeometry og = OGCGeometry.createFromEsriGeometry(resg, null); + String res_str = og.asText(); + assertTrue(og.geometryType().equals("Polygon")); + assertTrue(((OGCPolygon)og).numInteriorRing() == 0); + assertTrue(og.isSimple()); + } + + {// exterior ring is self-tangent + String s = "{\"rings\":[[[0, 0], [0, 10], [5, 5], [10, 10], [10, 0], [5, 5], [0, 0]]]}"; + OGCGeometry g = OGCGeometry.fromJson(s); + boolean res = g.isSimple(); + assertTrue(!res); + assertTrue(g.isSimpleRelaxed()); + Geometry resg = OperatorSimplifyOGC.local().execute(g.getEsriGeometry(), null, true, null); + OGCGeometry og = OGCGeometry.createFromEsriGeometry(resg, null); + res = og.isSimple(); + assertTrue(res); + assertTrue(og.geometryType().equals("MultiPolygon")); + assertTrue(((OGCGeometryCollection)og).numGeometries() == 2); + } + + {// ring orientation (hole is cw) + String s = "{\"rings\":[[[-100, -100], [-100, 100], [100, 100], [100, -100], [-100, -100]], [[0, 0], [5, 5], [10, 0], [0, 0]]]}"; + OGCGeometry g = OGCGeometry.fromJson(s); + boolean res = g.isSimple(); + assertTrue(!res); + assertTrue(!g.isSimpleRelaxed()); + Geometry resg = OperatorSimplifyOGC.local().execute(g.getEsriGeometry(), null, true, null); + OGCGeometry og = OGCGeometry.createFromEsriGeometry(resg, null); + res = og.isSimple(); + assertTrue(res); + assertTrue(og.geometryType().equals("Polygon")); + assertTrue(((OGCPolygon)og).numInteriorRing() == 1); + } + + {// ring order + String s = "{\"rings\":[[[0, 0], [10, 0], [5, 5], [0, 0]], [[-100, -100], [-100, 100], [100, 100], [100, -100], [-100, -100]]]}"; + OGCGeometry g = OGCGeometry.fromJson(s); + boolean res = g.isSimple(); + assertTrue(!res); + assertTrue(g.isSimpleRelaxed()); + Geometry resg = OperatorSimplifyOGC.local().execute(g.getEsriGeometry(), null, true, null); + OGCGeometry og = OGCGeometry.createFromEsriGeometry(resg, null); + res = og.isSimple(); + assertTrue(res); + assertTrue(og.geometryType().equals("Polygon")); + } + + { + // hole is self tangent + String s = "{\"rings\":[[[-100, -100], [-100, 100], [100, 100], [100, -100], [-100, -100]], [[0, 0], [5, 5], [10, 0], [10, 10], [5, 5], [0, 10], [0, 0]]]}"; + OGCGeometry g = OGCGeometry.fromJson(s); + boolean res = g.isSimple(); + assertTrue(!res); + assertTrue(g.isSimpleRelaxed()); + Geometry resg = OperatorSimplifyOGC.local().execute(g.getEsriGeometry(), null, true, null); + OGCGeometry og = OGCGeometry.createFromEsriGeometry(resg, null); + String res_str = og.asText(); + res = og.isSimple(); + assertTrue(res); + assertTrue(og.geometryType().equals("Polygon")); + assertTrue(((OGCPolygon)og).numInteriorRing() == 2); + } + { + // two holes touch + String s = "{\"rings\":[[[-100, -100], [-100, 100], [100, 100], [100, -100], [-100, -100]], [[0, 0], [10, 0], [5, 5], [0, 0]], [[10, 10], [0, 10], [5, 5], [10, 10]]]}"; + OGCGeometry g = OGCGeometry.fromJson(s); + boolean res = g.isSimple(); + assertTrue(res); + assertTrue(g.isSimpleRelaxed()); + Geometry resg = OperatorSimplifyOGC.local().execute(g.getEsriGeometry(), null, true, null); + OGCGeometry og = OGCGeometry.createFromEsriGeometry(resg, null); + assertTrue(og.geometryType().equals("Polygon")); + assertTrue(((OGCPolygon)og).numInteriorRing() == 2); + } + { + // two holes touch, bad orientation + String s = "{\"rings\":[[[-100, -100], [-100, 100], [100, 100], [100, -100], [-100, -100]], [[0, 0], [5, 5], [10, 0], [0, 0]], [[10, 10], [0, 10], [5, 5], [10, 10]]]}"; + OGCGeometry g = OGCGeometry.fromJson(s); + boolean res = g.isSimple(); + assertTrue(!res); + assertTrue(!g.isSimpleRelaxed()); + Geometry resg = OperatorSimplifyOGC.local().execute(g.getEsriGeometry(), null, true, null); + OGCGeometry og = OGCGeometry.createFromEsriGeometry(resg, null); + assertTrue(og.geometryType().equals("Polygon")); + assertTrue(((OGCPolygon)og).numInteriorRing() == 2); + } + + { + // hole touches exterior in two spots + //OperatorSimplifyOGC produces a multipolygon with two polygons without holes. + String s = "{\"rings\":[[[-100, -100], [-100, 100], [0, 100], [100, 100], [100, -100], [0, -100], [-100, -100]], [[0, -100], [10, 0], [0, 100], [-10, 0], [0, -100]]]}"; + OGCGeometry g = OGCGeometry.fromJson(s); + boolean res = g.isSimple(); + assertTrue(!res); + assertTrue(g.isSimpleRelaxed()); + Geometry resg = OperatorSimplifyOGC.local().execute(g.getEsriGeometry(), null, true, null); + OGCGeometry og = OGCGeometry.createFromEsriGeometry(resg, null); + assertTrue(og.geometryType().equals("MultiPolygon")); + assertTrue(((OGCMultiPolygon)og).numGeometries() == 2); + assertTrue(((OGCPolygon)((OGCMultiPolygon)og).geometryN(0)).numInteriorRing() == 0); + assertTrue(((OGCPolygon)((OGCMultiPolygon)og).geometryN(1)).numInteriorRing() == 0); + } + + { + // hole touches exterior in one spot + //OperatorSimplifyOGC produces a polygons with a hole. + String s = "{\"rings\":[[[-100, -100], [-100, 100], [0, 100], [100, 100], [100, -100], [0, -100], [-100, -100]], [[0, -100], [10, 0], [0, 90], [-10, 0], [0, -100]]]}"; + OGCGeometry g = OGCGeometry.fromJson(s); + boolean res = g.isSimple(); + assertTrue(res); + assertTrue(g.isSimpleRelaxed()); + Geometry resg = OperatorSimplifyOGC.local().execute(g.getEsriGeometry(), null, true, null); + OGCGeometry og = OGCGeometry.createFromEsriGeometry(resg, null); + assertTrue(og.geometryType().equals("Polygon")); + assertTrue(((OGCPolygon)og).numInteriorRing() == 1); + } + + { + // exterior has inversion (non simple for OGC) + //OperatorSimplifyOGC produces a polygons with a hole. + String s = "{\"rings\":[[[-100, -100], [-100, 100], [0, 100], [100, 100], [100, -100], [0, -100], [10, 0], [0, 90], [-10, 0], [0, -100], [-100, -100]]]}"; + OGCGeometry g = OGCGeometry.fromJson(s); + boolean res = g.isSimple(); + assertTrue(!res); + assertTrue(g.isSimpleRelaxed()); + Geometry resg = OperatorSimplifyOGC.local().execute(g.getEsriGeometry(), null, true, null); + OGCGeometry og = OGCGeometry.createFromEsriGeometry(resg, null); + assertTrue(og.geometryType().equals("Polygon")); + assertTrue(((OGCPolygon)og).numInteriorRing() == 1); + } + + { + // two holes touch in one spot, and they also touch exterior in + // two spots, producing disconnected interior + //OperatorSimplifyOGC produces two polygons with no holes. + String s = "{\"rings\":[[[-100, -100], [-100, 100], [0, 100], [100, 100], [100, -100], [0, -100], [-100, -100]], [[0, -100], [10, -50], [0, 0], [-10, -50], [0, -100]], [[0, 0], [10, 50], [0, 100], [-10, 50], [0, 0]]]}"; + OGCGeometry g = OGCGeometry.fromJson(s); + boolean res = g.isSimple(); + assertTrue(!res); + assertTrue(g.isSimpleRelaxed()); + Geometry resg = OperatorSimplifyOGC.local().execute(g.getEsriGeometry(), null, true, null); + OGCGeometry og = OGCGeometry.createFromEsriGeometry(resg, null); + assertTrue(og.geometryType().equals("MultiPolygon")); + assertTrue(((OGCMultiPolygon)og).numGeometries() == 2); + assertTrue(((OGCPolygon)((OGCMultiPolygon)og).geometryN(0)).numInteriorRing() == 0); + assertTrue(((OGCPolygon)((OGCMultiPolygon)og).geometryN(1)).numInteriorRing() == 0); + } + + + { + OGCGeometry g = OGCGeometry.fromJson("{\"rings\":[[[-3,4],[6,4],[6,-3],[-3,-3],[-3,4]],[[0,2],[2,2],[0,0],[4,0],[4,2],[2,0],[2,2],[4,2],[3,3],[2,2],[1,3],[0,2]]], \"spatialReference\":{\"wkid\":4326}}"); + assertTrue(g.geometryType().equals("Polygon")); + boolean res = g.isSimple(); + assertTrue(!res); + assertTrue(!g.isSimpleRelaxed()); + OGCGeometry simpleG = g.makeSimple(); + assertTrue(simpleG.geometryType().equals("MultiPolygon")); + assertTrue(simpleG.isSimple()); + OGCMultiPolygon mp = (OGCMultiPolygon)simpleG; + assertTrue(mp.numGeometries() == 2); + OGCPolygon g1 = (OGCPolygon)mp.geometryN(0); + OGCPolygon g2 = (OGCPolygon)mp.geometryN(1); + assertTrue((g1.numInteriorRing() == 0 && g1.numInteriorRing() == 2) || + (g1.numInteriorRing() == 2 && g2.numInteriorRing() == 0)); + + OGCGeometry oldOutput = OGCGeometry.fromJson("{\"rings\":[[[-3,-3],[-3,4],[6,4],[6,-3],[-3,-3]],[[0,0],[2,0],[4,0],[4,2],[3,3],[2,2],[1,3],[0,2],[2,2],[0,0]],[[2,0],[2,2],[4,2],[2,0]]],\"spatialReference\":{\"wkid\":4326}}"); + assertTrue(oldOutput.isSimpleRelaxed()); + assertFalse(oldOutput.isSimple()); + } + } catch (Exception ex) { + assertTrue(false); + } + } + + @Test + public void test_polyline_is_simple_for_OGC() { + try { + { + String s = "{\"paths\":[[[0, 10], [8, 5], [5, 2], [6, 0]]]}"; + OGCGeometry g = OGCGeometry.fromJson(s); + boolean res = g.isSimple(); + assertTrue(res); + assertTrue(g.isSimpleRelaxed()); + } + { + String s = "{\"paths\":[[[0, 10], [6, 0], [7, 5], [0, 3]]]}";// self + // intersection + OGCGeometry g = OGCGeometry.fromJson(s); + boolean res = g.isSimple(); + assertTrue(!res); + assertTrue(g.isSimpleRelaxed()); + } + + { + String s = "{\"paths\":[[[0, 10], [6, 0], [0, 3], [0, 10]]]}"; // closed + OGCGeometry g = OGCGeometry.fromJson(s); + boolean res = g.isSimple(); + assertTrue(res); + assertTrue(g.isSimpleRelaxed()); + } + + { + String s = "{\"paths\":[[[0, 10], [5, 5], [6, 0], [0, 3], [5, 5], [0, 9], [0, 10]]]}"; // closed + // with + // self + // tangent + OGCGeometry g = OGCGeometry.fromJson(s); + boolean res = g.isSimple(); + assertTrue(!res); + assertTrue(g.isSimpleRelaxed()); + } + + { + String s = "{\"paths\":[[[0, 10], [5, 2]], [[5, 2], [6, 0]]]}";// two + // paths + // connected + // at + // a + // point + OGCGeometry g = OGCGeometry.fromJson(s); + boolean res = g.isSimple(); + assertTrue(res); + assertTrue(g.isSimpleRelaxed()); + } + + { + String s = "{\"paths\":[[[0, 0], [3, 3], [5, 0], [0, 0]], [[0, 10], [3, 3], [10, 10], [0, 10]]]}";// two + // closed + // rings + // touch + // at + // one + // point + OGCGeometry g = OGCGeometry.fromJson(s); + boolean res = g.isSimple(); + assertTrue(!res); + assertTrue(g.isSimpleRelaxed()); + } + + { + String s = "{\"paths\":[[[3, 3], [0, 0], [5, 0], [3, 3]], [[3, 3], [0, 10], [10, 10], [3, 3]]]}"; + // two closed rings touch at one point. The touch happens at the + // endpoints of the paths. + OGCGeometry g = OGCGeometry.fromJson(s); + boolean res = g.isSimple(); + assertTrue(!res); + assertTrue(g.isSimpleRelaxed()); + } + + { + String s = "{\"paths\":[[[0, 0], [10, 10]], [[0, 10], [10, 0]]]}";// two + // lines + // intersect + OGCGeometry g = OGCGeometry.fromJson(s); + boolean res = g.isSimple(); + assertTrue(!res); + assertTrue(g.isSimpleRelaxed()); + } + + { + String s = "{\"paths\":[[[0, 0], [5, 5], [0, 10]], [[10, 10], [5, 5], [10, 0]]]}";// two + // paths + // share + // mid + // point. + OGCGeometry g = OGCGeometry.fromJson(s); + boolean res = g.isSimple(); + assertTrue(!res); + assertTrue(g.isSimpleRelaxed()); + } + } catch (Exception ex) { + assertTrue(false); + } + + } + + @Test + public void test_multipoint_is_simple_for_OGC() { + try { + + SpatialReference sr = SpatialReference.create(4326); + { + String s = "{\"points\":[[0, 0], [5, 5], [0, 10]]}"; + OGCGeometry g = OGCGeometry.fromJson(s); + boolean res = g.isSimple(); + assertTrue(res); + assertTrue(g.isSimpleRelaxed()); + } + { + String s = "{\"points\":[[0, 0], [5, 5], [0, 0], [0, 10]]}"; + OGCGeometry g = OGCGeometry.fromJson(s); + boolean res = g.isSimple(); + assertTrue(!res); + assertTrue(!g.isSimpleRelaxed()); + } + { + String s = "{\"points\":[[0, 0], [5, 5], [1e-10, -1e-10], [0, 10]]}"; + OGCGeometry g = OGCGeometry.fromJson(s); + g.setSpatialReference(sr); + boolean res = g.isSimple(); + assertTrue(!res); + assertTrue(g.isSimpleRelaxed()); + } + } catch (Exception ex) { + assertTrue(false); + } + + } + + @Test + public void testGeometryCollectionBuffer() { + OGCGeometry g = OGCGeometry + .fromText("GEOMETRYCOLLECTION(POINT(1 1), POINT(1 1), POINT(1 2), LINESTRING (0 0, 1 1, 1 0, 0 1), MULTIPOLYGON EMPTY, MULTILINESTRING EMPTY)"); + OGCGeometry simpleG = g.buffer(0); + String t = simpleG.geometryType(); + String rt = simpleG.asText(); + assertTrue(simpleG.geometryType().equals("GeometryCollection")); + } + + @Test + public void testIsectTria1() { + String wkt = "polygon((1 0, 3 0, 1 2, 1 0))"; + String wk2 = "polygon((0 1, 2 1, 0 3, 0 1))"; + OGCGeometry g0 = OGCGeometry.fromText(wkt); + OGCGeometry g1 = OGCGeometry.fromText(wk2); + g0.setSpatialReference(SpatialReference.create(4326)); + g1.setSpatialReference(SpatialReference.create(4326)); + OGCGeometry rslt = g0.intersection(g1); + assertTrue(rslt != null); + assertTrue(rslt.geometryType().equals("Polygon")); + assertTrue(rslt.esriSR.getID() == 4326); + String s = rslt.asText(); + } + + @Test + public void testIsectTriaJson1() throws Exception { + String json1 = "{\"rings\":[[[1, 0], [3, 0], [1, 2], [1, 0]]], \"spatialReference\":{\"wkid\":4326}}"; + String json2 = "{\"rings\":[[[0, 1], [2, 1], [0, 3], [0, 1]]], \"spatialReference\":{\"wkid\":4326}}"; + OGCGeometry g0 = OGCGeometry.fromJson(json1); + OGCGeometry g1 = OGCGeometry.fromJson(json2); + OGCGeometry rslt = g0.intersection(g1); + assertTrue(rslt != null); + assertTrue(rslt.geometryType().equals("Polygon")); + assertTrue(rslt.esriSR.getID() == 4326); + String s = GeometryEngine.geometryToJson(rslt.getEsriSpatialReference().getID(), rslt.getEsriGeometry()); + } + + @Test + public void testIsectTria2() { + String wkt = "polygon((1 0, 3 0, 1 2, 1 0))"; + String wk2 = "polygon((0 3, 2 1, 3 1, 0 3))"; + OGCGeometry g0 = OGCGeometry.fromText(wkt); + OGCGeometry g1 = OGCGeometry.fromText(wk2); + g0.setSpatialReference(null); + g1.setSpatialReference(null); + OGCGeometry rslt = g0.intersection(g1); + assertTrue(rslt != null); + assertTrue(rslt.dimension() == 1); + assertTrue(rslt.geometryType().equals("LineString")); + String s = rslt.asText(); + } + + @Test + public void testIsectTria3() { + String wkt = "polygon((1 0, 3 0, 1 2, 1 0))"; + String wk2 = "polygon((2 2, 2 1, 3 1, 2 2))"; + OGCGeometry g0 = OGCGeometry.fromText(wkt); + OGCGeometry g1 = OGCGeometry.fromText(wk2); + g0.setSpatialReference(SpatialReference.create(4326)); + g1.setSpatialReference(SpatialReference.create(4326)); + OGCGeometry rslt = g0.intersection(g1); + assertTrue(rslt != null); + assertTrue(rslt.dimension() == 0); + assertTrue(rslt.geometryType().equals("Point")); + assertTrue(rslt.esriSR.getID() == 4326); + String s = rslt.asText(); + } + + @Test + public void testMultiPointSinglePoint() { + String wkt = "multipoint((1 0))"; + OGCGeometry g0 = OGCGeometry.fromText(wkt); + assertTrue(g0.dimension() == 0); + String gt = g0.geometryType(); + assertTrue(gt.equals("MultiPoint")); + OGCMultiPoint mp = (OGCMultiPoint)g0; + assertTrue(mp.numGeometries() == 1); + OGCGeometry p = mp.geometryN(0); + String s = p.asText(); + assertTrue(s.equals("POINT (1 0)")); + + String ms = p.convertToMulti().asText(); + assertTrue(ms.equals("MULTIPOINT ((1 0))")); + + } + + @Test + public void testWktMultiPolygon() { + String restJson = "{\"rings\": [[[-100, -100], [-100, 100], [100, 100], [100, -100], [-100, -100]], [[-90, -90], [90, 90], [-90, 90], [90, -90], [-90, -90]], [[-10, -10], [-10, 10], [10, 10], [10, -10], [-10, -10]]]}"; + MapGeometry g = null; + g = OperatorImportFromJson.local().execute(Geometry.Type.Unknown, restJson); + String wkt = OperatorExportToWkt.local().execute(0, g.getGeometry(), null); + assertTrue(wkt.equals("MULTIPOLYGON (((-100 -100, 100 -100, 100 100, -100 100, -100 -100), (-90 -90, 90 -90, -90 90, 90 90, -90 -90)), ((-10 -10, 10 -10, 10 10, -10 10, -10 -10)))")); + } + + @Test + public void testMultiPolygonArea() { + //MultiPolygon Area #36 + String wkt = "MULTIPOLYGON (((1001200 2432900, 1001420 2432691, 1001250 2432388, 1001498 2432325, 1001100 2432100, 1001500 2431900, 1002044 2431764, 1002059 2432120, 1002182 2432003, 1002400 2432300, 1002650 2432150, 1002610 2432323, 1002772 2432434, 1002410 2432821, 1002700 2433000, 1001824 2432866, 1001600 2433150, 1001200 2432900)), ((1000393 2433983, 1000914 2434018, 1000933 2433817, 1000568 2433834, 1000580 2433584, 1000700 2433750, 1000800 2433650, 1000700 2433450, 1000600 2433550, 1000200 2433350, 1000100 2433900, 1000393 2433983)), ((1001200 2432900, 1000878 2432891, 1000900 2433300, 1001659 2433509, 1001600 2433150, 1001200 2432900)), ((1002450 2431650, 1002300 2431650, 1002300 2431900, 1002500 2432100, 1002600 2431800, 1002450 2431800, 1002450 2431650)), ((999750 2433550, 999850 2433600, 999900 2433350, 999780 2433433, 999750 2433550)), ((1002950 2432050, 1003005 2431932, 1002850 2432250, 1002928 2432210, 1002950 2432050)), ((1002600 2431750, 1002642 2431882, 1002750 2431900, 1002750 2431750, 1002600 2431750)), ((1002950 2431750, 1003050 2431650, 1002968 2431609, 1002950 2431750)))"; + { + OGCGeometry ogcg = OGCGeometry.fromText(wkt); + assertTrue(ogcg.geometryType().equals("MultiPolygon")); + OGCMultiPolygon mp = (OGCMultiPolygon)ogcg; + double a = mp.area(); + assertTrue(Math.abs(mp.area() - 2037634.5) < a*1e-14); + } + + { + OGCGeometry ogcg = OGCGeometry.fromText(wkt); + assertTrue(ogcg.geometryType().equals("MultiPolygon")); + Geometry g = ogcg.getEsriGeometry(); + double a = g.calculateArea2D(); + assertTrue(Math.abs(a - 2037634.5) < a*1e-14); + } + } + + @Test + public void testPolylineSimplifyIssueGithub52() throws Exception { + String json = "{\"paths\":[[[2,0],[4,3],[5,1],[3.25,1.875],[1,3]]],\"spatialReference\":{\"wkid\":4326}}"; + { + OGCGeometry g = OGCGeometry.fromJson(json); + assertTrue(g.geometryType().equals("LineString")); + OGCGeometry simpleG = g.makeSimple();//make ogc simple + assertTrue(simpleG.geometryType().equals("MultiLineString")); + assertTrue(simpleG.isSimpleRelaxed());//geodatabase simple + assertTrue(simpleG.isSimple());//ogc simple + OGCMultiLineString mls =(OGCMultiLineString)simpleG; + assertTrue(mls.numGeometries() == 4); + OGCGeometry baseGeom = OGCGeometry.fromJson("{\"paths\":[[[2,0],[3.25,1.875]],[[3.25,1.875],[4,3],[5,1]],[[5,1],[3.25,1.875]],[[3.25,1.875],[1,3]]],\"spatialReference\":{\"wkid\":4326}}"); + assertTrue(simpleG.equals(baseGeom)); + + } + } + + @Test + public void testEmptyBoundary() throws Exception { + { + OGCGeometry g = OGCGeometry.fromText("POINT EMPTY"); + OGCGeometry b = g.boundary(); + assertTrue(b.asText().compareTo("MULTIPOINT EMPTY") == 0); + } + { + OGCGeometry g = OGCGeometry.fromText("MULTIPOINT EMPTY"); + OGCGeometry b = g.boundary(); + assertTrue(b.asText().compareTo("MULTIPOINT EMPTY") == 0); + } + { + OGCGeometry g = OGCGeometry.fromText("LINESTRING EMPTY"); + OGCGeometry b = g.boundary(); + assertTrue(b.asText().compareTo("MULTIPOINT EMPTY") == 0); + } + { + OGCGeometry g = OGCGeometry.fromText("POLYGON EMPTY"); + OGCGeometry b = g.boundary(); + assertTrue(b.asText().compareTo("MULTILINESTRING EMPTY") == 0); + } + { + OGCGeometry g = OGCGeometry.fromText("MULTIPOLYGON EMPTY"); + OGCGeometry b = g.boundary(); + assertTrue(b.asText().compareTo("MULTILINESTRING EMPTY") == 0); + } + } + + @Test + public void testUnionPointWithEmptyLineString() { + assertUnion("POINT (1 2)", "LINESTRING EMPTY", "POINT (1 2)"); + } + + @Test + public void testUnionPointWithLinestring() { + assertUnion("POINT (1 2)", "LINESTRING (3 4, 5 6)", "GEOMETRYCOLLECTION (POINT (1 2), LINESTRING (3 4, 5 6))"); + } + + @Test + public void testUnionLinestringWithEmptyPolygon() { + assertUnion("MULTILINESTRING ((1 2, 3 4))", "POLYGON EMPTY", "LINESTRING (1 2, 3 4)"); + } + + @Test + public void testUnionLinestringWithPolygon() { + assertUnion("LINESTRING (1 2, 3 4)", "POLYGON ((0 0, 1 1, 0 1, 0 0))", + "GEOMETRYCOLLECTION (LINESTRING (1 2, 3 4), POLYGON ((0 0, 1 1, 0 1, 0 0)))"); + } + + @Test + public void testUnionGeometryCollectionWithGeometryCollection() { + assertUnion("GEOMETRYCOLLECTION (LINESTRING (1 2, 3 4), POLYGON ((0 0, 1 1, 0 1, 0 0)))", + "GEOMETRYCOLLECTION (POINT (1 2), POINT (2 3), POINT (0.5 0.5), POINT (3 5), LINESTRING (3 4, 5 6), POLYGON ((0 0, 1 0, 1 1, 0 0)))", + "GEOMETRYCOLLECTION (POINT (3 5), LINESTRING (1 2, 2 3, 3 4, 5 6), POLYGON ((0 0, 1 0, 1 1, 0 1, 0 0)))"); + } + + @Test + public void testIntersectionGeometryCollectionWithGeometryCollection() { + assertIntersection("GEOMETRYCOLLECTION (LINESTRING (1 2, 3 4), POLYGON ((0 0, 1 1, 0 1, 0 0)))", + "GEOMETRYCOLLECTION (POINT (1 2), POINT (2 3), POINT (0.5 0.5), POINT (3 5), LINESTRING (3 4, 5 6), POLYGON ((0 0, 1 0, 1 1, 0 0)))", + "GEOMETRYCOLLECTION (MULTIPOINT ((1 2), (2 3), (3 4)), LINESTRING (0 0, 0.5 0.5, 1 1))"); + } + + private void assertIntersection(String leftWkt, String rightWkt, String expectedWkt) { + OGCGeometry intersection = OGCGeometry.fromText(leftWkt).intersection(OGCGeometry.fromText(rightWkt)); + assertEquals(expectedWkt, intersection.asText()); + } + + private void assertUnion(String leftWkt, String rightWkt, String expectedWkt) { + OGCGeometry union = OGCGeometry.fromText(leftWkt).union(OGCGeometry.fromText(rightWkt)); + assertEquals(expectedWkt, union.asText()); + } + + @Test + public void testDisjointOnGeometryCollection() { + OGCGeometry ogcGeometry = OGCGeometry.fromText("GEOMETRYCOLLECTION (POINT (1 1))"); + assertFalse(ogcGeometry.disjoint(OGCGeometry.fromText("POINT (1 1)"))); + } + + @Test + public void testContainsOnGeometryCollection() { + OGCGeometry ogcGeometry = OGCGeometry.fromText("GEOMETRYCOLLECTION (POINT (1 1))"); + assertTrue(ogcGeometry.contains(OGCGeometry.fromText("POINT (1 1)"))); + } + + @Test + public void testIntersectsOnGeometryCollection() { + OGCGeometry ogcGeometry = OGCGeometry.fromText("GEOMETRYCOLLECTION (POINT (1 1))"); + assertTrue(ogcGeometry.intersects(OGCGeometry.fromText("POINT (1 1)"))); + ogcGeometry = OGCGeometry.fromText("POINT (1 1)"); + assertTrue(ogcGeometry.intersects(OGCGeometry.fromText("GEOMETRYCOLLECTION (POINT (1 1))"))); + } + + @Test + public void testDistanceOnGeometryCollection() { + OGCGeometry ogcGeometry = OGCGeometry.fromText("GEOMETRYCOLLECTION (POINT (1 1))"); + assertTrue(ogcGeometry.distance(OGCGeometry.fromText("POINT (1 1)")) == 0); + + //distance to empty is NAN + ogcGeometry = OGCGeometry.fromText("GEOMETRYCOLLECTION (POINT (1 1))"); + assertTrue(Double.isNaN(ogcGeometry.distance(OGCGeometry.fromText("POINT EMPTY")))); + } + + @Test + public void testFlattened() { + OGCConcreteGeometryCollection ogcGeometry = (OGCConcreteGeometryCollection)OGCGeometry.fromText("GEOMETRYCOLLECTION (MULTILINESTRING ((1 2, 3 4)), MULTIPOLYGON (((1 2, 3 4, 5 6, 1 2))), MULTIPOINT (1 1))"); + assertFalse(ogcGeometry.isFlattened()); + ogcGeometry = (OGCConcreteGeometryCollection)OGCGeometry.fromText("GEOMETRYCOLLECTION (MULTIPOINT (1 1), MULTILINESTRING ((1 2, 3 4)), MULTIPOLYGON (((1 2, 3 4, 5 6, 1 2))))"); + assertTrue(ogcGeometry.isFlattened()); + } + + @Test + public void testIssue247IsSimple() { + //https://github.com/Esri/geometry-api-java/issues/247 + String wkt = "MULTILINESTRING ((-103.4894322 25.6164519, -103.4889647 25.6159054, -103.489434 25.615654), (-103.489434 25.615654, -103.4894322 25.6164519), (-103.4897361 25.6168342, -103.4894322 25.6164519))"; + OGCGeometry ogcGeom = OGCGeometry.fromText(wkt); + boolean b = ogcGeom.isSimple(); + assertTrue(b); + } } diff --git a/src/test/java/com/esri/core/geometry/TestOGCCentroid.java b/src/test/java/com/esri/core/geometry/TestOGCCentroid.java new file mode 100644 index 00000000..a64c67b5 --- /dev/null +++ b/src/test/java/com/esri/core/geometry/TestOGCCentroid.java @@ -0,0 +1,106 @@ +/* + Copyright 1995-2017 Esri + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + For additional information, contact: + Environmental Systems Research Institute, Inc. + Attn: Contracts Dept + 380 New York Street + Redlands, California, USA 92373 + + email: contracts@esri.com + */ +package com.esri.core.geometry; + +import com.esri.core.geometry.ogc.OGCGeometry; +import com.esri.core.geometry.ogc.OGCPoint; +import org.junit.Assert; +import org.junit.Test; + +public class TestOGCCentroid { + @Test + public void testPoint() { + assertCentroid("POINT (1 2)", new Point(1, 2)); + assertEmptyCentroid("POINT EMPTY"); + } + + @Test + public void testLineString() { + assertCentroid("LINESTRING (1 1, 2 2, 3 3)", new Point(2, 2)); + //closed path + assertCentroid("LINESTRING (0 0, 1 0, 1 1, 0 1, 0 0)", new Point(0.5, 0.5)); + //all points coincide + assertCentroid("LINESTRING (0 0, 0 0, 0 0, 0 0, 0 0)", new Point(0.0, 0.0)); + assertEmptyCentroid("LINESTRING EMPTY"); + } + + @Test + public void testPolygon() { + assertCentroid("POLYGON ((1 1, 1 4, 4 4, 4 1))'", new Point(2.5, 2.5)); + assertCentroid("POLYGON ((1 1, 5 1, 3 4))", new Point(3, 2)); + assertCentroid("POLYGON ((0 0, 0 5, 5 5, 5 0, 0 0), (1 1, 1 2, 2 2, 2 1, 1 1))", + new Point(2.5416666666666665, 2.5416666666666665)); + assertEmptyCentroid("POLYGON EMPTY"); + } + + @Test + public void testMultiPoint() { + assertCentroid("MULTIPOINT (1 2, 2 4, 3 6, 4 8)", new Point(2.5, 5)); + assertEmptyCentroid("MULTIPOINT EMPTY"); + } + + @Test + public void testMultiLineString() { + assertCentroid("MULTILINESTRING ((1 1, 5 1), (2 4, 4 4))')))", new Point(3, 2)); + assertCentroid("MULTILINESTRING ((1 1, 5 1), (2 4, 3 3, 4 4))')))", new Point(3, 2.0355339059327378)); + assertCentroid("MULTILINESTRING ((0 0, 0 0, 0 0), (1 1, 1 1, 1 1, 1 1))", new Point(0.571428571428571429, 0.571428571428571429)); + assertEmptyCentroid("MULTILINESTRING EMPTY"); + } + + @Test + public void testMultiPolygon() { + assertCentroid("MULTIPOLYGON (((0 0, 1 0, 1 1, 0 1, 0 0)), ((2 2, 3 2, 3 3, 2 3, 2 2)))", new Point(1.5, 1.5)); + assertCentroid("MULTIPOLYGON (((2 2, 3 2, 3 3, 2 3, 2 2)), ((4 4, 5 4, 5 5, 4 5, 4 4)))", new Point(3.5, 3.5)); + assertCentroid("MULTIPOLYGON (((1 1, 1 3, 3 3, 3 1)), ((2 4, 2 6, 6 6, 6 4)))", + new Point(3.3333333333333335, 4)); + + //hole is same as exterior - compute as polyline + assertCentroid("MULTIPOLYGON (((0 0, 1 0, 1 1, 0 1, 0 0), (0 0, 0 1, 1 1, 1 0, 0 0)))", new Point(0.5, 0.5)); + + //polygon is only vertices - compute as multipoint. Note that the closing vertex of the ring is not counted + assertCentroid("MULTIPOLYGON (((0 0, 0 0, 0 0), (1 1, 1 1, 1 1, 1 1)))", new Point(0.6, 0.6)); + + // test cases from https://github.com/Esri/geometry-api-java/issues/225 + assertCentroid( + "MULTIPOLYGON (((153.492818 -28.13729, 153.492821 -28.137291, 153.492816 -28.137289, 153.492818 -28.13729)))", + new Point(153.49281833333333, -28.13729)); + assertCentroid( + "MULTIPOLYGON (((153.112475 -28.360526, 153.1124759 -28.360527, 153.1124759 -28.360526, 153.112475 -28.360526)))", + new Point(153.1124756, -28.360526333333333)); + assertEmptyCentroid("MULTIPOLYGON EMPTY"); + } + + private static void assertCentroid(String wkt, Point expectedCentroid) { + OGCGeometry geometry = OGCGeometry.fromText(wkt); + OGCGeometry centroid = geometry.centroid(); + Assert.assertEquals(((OGCPoint)centroid).X(), expectedCentroid.getX(), 1e-13); + Assert.assertEquals(((OGCPoint)centroid).Y(), expectedCentroid.getY(), 1e-13); + } + + private static void assertEmptyCentroid(String wkt) { + OGCGeometry geometry = OGCGeometry.fromText(wkt); + OGCGeometry centroid = geometry.centroid(); + Assert.assertEquals(centroid, new OGCPoint(new Point(), geometry.getEsriSpatialReference())); + } +} diff --git a/src/test/java/com/esri/core/geometry/TestOGCContains.java b/src/test/java/com/esri/core/geometry/TestOGCContains.java new file mode 100644 index 00000000..04a328bf --- /dev/null +++ b/src/test/java/com/esri/core/geometry/TestOGCContains.java @@ -0,0 +1,88 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.esri.core.geometry; + +import com.esri.core.geometry.ogc.OGCGeometry; +import org.junit.Test; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class TestOGCContains { + @Test + public void testPoint() { + // point + assertContains("POINT (1 2)", "POINT (1 2)"); + assertContains("POINT (1 2)", "GEOMETRYCOLLECTION (POINT (1 2))"); + assertNotContains("POINT (1 2)", "POINT EMPTY"); + assertNotContains("POINT (1 2)", "POINT (3 4)"); + + // multi-point + assertContains("MULTIPOINT (1 2, 3 4)", "MULTIPOINT (1 2, 3 4)"); + assertContains("MULTIPOINT (1 2, 3 4)", "MULTIPOINT (1 2)"); + assertContains("MULTIPOINT (1 2, 3 4)", "POINT (3 4)"); + assertContains("MULTIPOINT (1 2, 3 4)", "GEOMETRYCOLLECTION (MULTIPOINT (1 2), POINT (3 4))"); + assertContains("MULTIPOINT (1 2, 3 4)", "GEOMETRYCOLLECTION (POINT (1 2))"); + assertNotContains("MULTIPOINT (1 2, 3 4)", "MULTIPOINT EMPTY"); + } + + @Test + public void testLineString() { + // TODO Add more tests + assertContains("LINESTRING (0 1, 5 1)", "POINT (2 1)"); + } + + @Test + public void testPolygon() { + // TODO Fill in + } + + @Test + public void testGeometryCollection() { + // TODO Add more tests + assertContains("GEOMETRYCOLLECTION (POINT (0 0), LINESTRING (0 1, 5 1))", + "GEOMETRYCOLLECTION (MULTIPOINT (0 0, 2 1))"); + } + + @Test + public void testAcceleratedPiP() { + String wkt = "MULTIPOLYGON (((-109.642707 30.5236901, -109.607932 30.5367411, -109.5820257 30.574184, -109.5728286 30.5874766, -109.568679 30.5934741, -109.5538097 30.5918356, -109.553714 30.5918251, -109.553289 30.596034, -109.550951 30.6191889, -109.5474935 30.6221179, -109.541059 30.6275689, -109.5373751 30.6326491, -109.522538 30.6531099, -109.514671 30.6611981, -109.456764 30.6548095, -109.4556456 30.6546861, -109.4536755 30.6544688, -109.4526481 30.6543554, -109.446824 30.6537129, -109.437751 30.6702901, -109.433968 30.6709781, -109.43338 30.6774591, -109.416243 30.7164651, -109.401643 30.7230741, -109.377583 30.7145241, -109.3487939 30.7073896, -109.348594 30.7073401, -109.3483718 30.7073797, -109.3477608 30.7074887, -109.3461903 30.7078834, -109.3451022 30.7081569, -109.3431732 30.7086416, -109.3423301 30.708844, -109.3419714 30.7089301, -109.3416347 30.709011, -109.3325693 30.7111874, -109.3323814 30.7112325, -109.332233 30.7112681, -109.332191 30.7112686, -109.3247809 30.7113581, -109.322215 30.7159391, -109.327776 30.7234381, -109.350134 30.7646001, -109.364505 30.8382481, -109.410211 30.8749199, -109.400048 30.8733419, -109.3847799 30.9652412, -109.3841625 30.9689575, -109.375268 31.0224939, -109.390544 31.0227899, -109.399749 31.0363341, -109.395787 31.0468411, -109.388174 31.0810249, -109.3912446 31.0891966, -109.3913452 31.0894644, -109.392735 31.0931629, -109.4000839 31.0979214, -109.402803 31.0996821, -109.4110458 31.1034586, -109.419153 31.1071729, -109.449782 31.1279489, -109.469654 31.1159979, -109.4734874 31.1131178, -109.473753 31.1129183, -109.4739754 31.1127512, -109.491296 31.0997381, -109.507789 31.0721811, -109.512776 31.0537519, -109.5271478 31.0606861, -109.5313703 31.0627234, -109.540698 31.0672239, -109.5805468 31.0674089, -109.5807399 31.0674209, -109.595423 31.0674779, -109.60347 31.0690241, -109.6048011 31.068808, -109.6050803 31.0687627, -109.6192237 31.0664664, -109.635432 31.0638349, -109.6520068 31.0955326, -109.6522294 31.0959584, -109.652373 31.0962329, -109.657709 31.0959719, -109.718258 31.0930099, -109.821036 31.0915909, -109.8183088 31.0793374, -109.8165128 31.0712679, -109.8140062 31.0600052, -109.8138512 31.0593089, -109.812707 31.0541679, -109.8188146 31.0531909, -109.8215447 31.0527542, -109.8436765 31.0492138, -109.8514316 31.0479733, -109.8620535 31.0462742, -109.8655958 31.0457076, -109.868388 31.0452609, -109.8795483 31.0359656, -109.909274 31.0112075, -109.9210382 31.0014092, -109.9216329 31.0009139, -109.920594 30.994183, -109.9195356 30.9873254, -109.9192113 30.9852243, -109.9186281 30.9814453, -109.917814 30.9761709, -109.933894 30.9748879, -109.94094 30.9768059, -109.944854 30.9719821, -109.950803 30.9702809, -109.954025 30.9652409, -109.9584129 30.9636033, -109.958471 30.9635809, -109.9590542 30.9644372, -109.959896 30.9656733, -109.9604184 30.9664405, -109.9606288 30.9667494, -109.9608462 30.9670686, -109.961225 30.9676249, -109.9611615 30.9702903, -109.9611179 30.9721175, -109.9610885 30.9733488, -109.9610882 30.9733604, -109.9610624 30.9744451, -109.961017 30.9763469, -109.962609 30.9786559, -109.9634437 30.9783167, -110.00172 30.9627641, -110.0021152 30.9627564, -110.0224353 30.9623622, -110.0365868 30.9620877, -110.037493 30.9620701, -110.0374055 30.961663, -110.033653 30.9442059, -110.0215506 30.9492932, -110.0180392 30.9507693, -110.011203 30.9536429, -110.0062891 30.9102124, -110.0058721 30.9065268, -110.004869 30.8976609, -109.996392 30.8957129, -109.985038 30.8870439, -109.969416 30.9006011, -109.967905 30.8687239, -109.903498 30.8447749, -109.882925 30.8458289, -109.865184 30.8206519, -109.86465 30.777698, -109.864515 30.7668429, -109.837007 30.7461781, -109.83453 30.7164469, -109.839017 30.7089009, -109.813394 30.6906529, -109.808694 30.6595701, -109.795334 30.6630041, -109.7943042 30.6427223, -109.7940456 30.6376287, -109.7940391 30.637501, -109.793823 30.6332449, -109.833511 30.6274289, -109.830299 30.6252799, -109.844198 30.6254801, -109.852442 30.6056949, -109.832973 30.6021201, -109.8050409 30.591211, -109.773847 30.5790279, -109.772859 30.5521999, -109.754427 30.5393969, -109.743293 30.5443401, -109.6966136 30.5417334, -109.6648181 30.5399578, -109.6560456 30.5394679, -109.6528439 30.5392912, -109.6504039 30.5391565, -109.6473602 30.5389885, -109.646906 30.5389634, -109.6414545 30.5386625, -109.639708 30.5385661, -109.6397729 30.5382443, -109.642707 30.5236901)))"; + String pointWkt = "POINT (-109.65 31.091666666673)"; + + OGCGeometry polygon = OGCGeometry.fromText(wkt); + OGCGeometry point = OGCGeometry.fromText(pointWkt); + assertTrue(polygon.contains(point)); + + OperatorContains.local() + .accelerateGeometry(polygon.getEsriGeometry(), null, Geometry.GeometryAccelerationDegree.enumMild); + assertTrue(polygon.contains(point));; + } + + private void assertContains(String wkt, String otherWkt) { + OGCGeometry geometry = OGCGeometry.fromText(wkt); + OGCGeometry otherGeometry = OGCGeometry.fromText(otherWkt); + + assertTrue(geometry.contains(otherGeometry)); + assertTrue(otherGeometry.within(geometry)); + assertFalse(geometry.disjoint(otherGeometry)); + } + + private void assertNotContains(String wkt, String otherWkt) { + OGCGeometry geometry = OGCGeometry.fromText(wkt); + OGCGeometry otherGeometry = OGCGeometry.fromText(otherWkt); + assertFalse(geometry.contains(otherGeometry)); + assertFalse(otherGeometry.within(geometry)); + } +} + diff --git a/src/test/java/com/esri/core/geometry/TestOGCDisjoint.java b/src/test/java/com/esri/core/geometry/TestOGCDisjoint.java new file mode 100644 index 00000000..45090e83 --- /dev/null +++ b/src/test/java/com/esri/core/geometry/TestOGCDisjoint.java @@ -0,0 +1,126 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.esri.core.geometry; + +import com.esri.core.geometry.ogc.OGCGeometry; +import org.junit.Test; + +import static java.lang.String.format; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class TestOGCDisjoint +{ + @Test + public void testPoint() + { + // point + assertDisjoint("POINT (1 2)", "POINT (3 4)"); + assertDisjoint("POINT (1 2)", "POINT EMPTY"); + assertNotDisjoint("POINT (1 2)", "POINT (1 2)", "POINT (1 2)"); + + // multi-point + assertDisjoint("POINT (1 2)", "MULTIPOINT (3 4, 5 6)"); + assertDisjoint("POINT (1 2)", "MULTIPOINT EMPTY"); + assertNotDisjoint("POINT (1 2)", "MULTIPOINT (1 2, 3 4, 5 6)", "POINT (1 2)"); + assertNotDisjoint("POINT (1 2)", "MULTIPOINT (1 2)", "POINT (1 2)"); + } + + @Test + public void testLinestring() + { + // TODO Fill in + } + + @Test + public void testPolygon() + { + // TODO Fill in + } + + @Test + public void testGeometryCollection() + { + assertDisjoint("GEOMETRYCOLLECTION (POINT (1 2))", "POINT (3 4)"); + // GeometryException: internal error + assertDisjoint("GEOMETRYCOLLECTION (POINT (1 2))", "POINT EMPTY"); + assertNotDisjoint("GEOMETRYCOLLECTION (POINT (1 2))", "POINT (1 2)", "POINT (1 2)"); + + assertDisjoint("GEOMETRYCOLLECTION (POINT (1 2), MULTIPOINT (3 4, 5 6))", "POINT (0 0)"); + assertNotDisjoint("GEOMETRYCOLLECTION (POINT (1 2), MULTIPOINT (3 4, 5 6))", "POINT (3 4)", "POINT (3 4)"); + + String wkt = "GEOMETRYCOLLECTION (POINT (1 2), LINESTRING (0 0, 5 0), POLYGON ((2 2, 3 2, 3 3, 2 2)))"; + assertDisjoint(wkt, gc("POINT (0 2)")); + + assertNotDisjoint(wkt, gc("POINT (1 2)"), "POINT (1 2)"); + // point within the line + assertNotDisjoint(wkt, gc("POINT (0 0)"), "POINT (0 0)"); + assertNotDisjoint(wkt, gc("POINT (1 0)"), "POINT (1 0)"); + // point within the polygon + assertNotDisjoint(wkt, gc("POINT (2 2)"), "POINT (2 2)"); + assertNotDisjoint(wkt, gc("POINT (2.5 2)"), "POINT (2.5 2)"); + assertNotDisjoint(wkt, gc("POINT (2.5 2.1)"), "POINT (2.5 2.1)"); + + assertDisjoint(wkt, gc("LINESTRING (0 2, 1 3)")); + + // line intersects the point + assertNotDisjoint(wkt, gc("LINESTRING (0 1, 2 3)"), "POINT (1 2)"); + // line intersects the line + assertNotDisjoint(wkt, gc("LINESTRING (0 0, 1 0)"), "LINESTRING (0 0, 1 0)"); + assertNotDisjoint(wkt, gc("LINESTRING (5 -1, 5 1)"), "POINT (5 0)"); + // line intersects the polygon + assertNotDisjoint(wkt, gc("LINESTRING (0 0, 5 5)"), gc("POINT (0 0), LINESTRING (2 2, 3 3)")); + assertNotDisjoint(wkt, gc("LINESTRING (0 2.5, 2.6 2.5)"), "LINESTRING (2.5 2.5, 2.6 2.5)"); + + assertDisjoint(wkt, gc("POLYGON ((5 5, 6 5, 6 6, 5 5))")); + assertDisjoint(wkt, gc("POLYGON ((-1 -1, 10 -1, 10 10, -1 10, -1 -1), (-0.1 -0.1, 5.1 -0.1, 5.1 5.1, -0.1 5.1, -0.1 -0.1))")); + + assertNotDisjoint(wkt, gc("POLYGON ((-1 -1, 10 -1, 10 10, -1 10, -1 -1))"), gc("POINT (1 2), LINESTRING (0 0, 5 0), POLYGON ((2 2, 3 2, 3 3, 2 2))")); + assertNotDisjoint(wkt, gc("POLYGON ((2 -1, 4 -1, 4 1, 2 1, 2 -1))"), "LINESTRING (2 0, 4 0)"); + assertNotDisjoint(wkt, gc("POLYGON ((0 1, 1.5 1, 1.5 2.5, 0 2.5, 0 1))"), "POINT (1 2)"); + assertNotDisjoint(wkt, gc("POLYGON ((5 0, 6 0, 6 5, 5 0))"), "POINT (5 0)"); + } + + private String gc(String wkts) + { + return format("GEOMETRYCOLLECTION (%s)", wkts); + } + + private void assertDisjoint(String wkt, String otherWkt) + { + OGCGeometry geometry = OGCGeometry.fromText(wkt); + OGCGeometry otherGeometry = OGCGeometry.fromText(otherWkt); + assertTrue(geometry.disjoint(otherGeometry)); + assertFalse(geometry.intersects(otherGeometry)); + assertTrue(geometry.intersection(otherGeometry).isEmpty()); + + assertTrue(otherGeometry.disjoint(geometry)); + assertFalse(otherGeometry.intersects(geometry)); + assertTrue(otherGeometry.intersection(geometry).isEmpty()); + } + + private void assertNotDisjoint(String wkt, String otherWkt, String intersectionWkt) + { + OGCGeometry geometry = OGCGeometry.fromText(wkt); + OGCGeometry otherGeometry = OGCGeometry.fromText(otherWkt); + assertFalse(geometry.disjoint(otherGeometry)); + assertTrue(geometry.intersects(otherGeometry)); + assertEquals(intersectionWkt, geometry.intersection(otherGeometry).asText()); + + assertFalse(otherGeometry.disjoint(geometry)); + assertTrue(otherGeometry.intersects(geometry)); + assertEquals(intersectionWkt, otherGeometry.intersection(geometry).asText()); + } +} diff --git a/src/test/java/com/esri/core/geometry/TestOGCDistance.java b/src/test/java/com/esri/core/geometry/TestOGCDistance.java new file mode 100644 index 00000000..dea491f9 --- /dev/null +++ b/src/test/java/com/esri/core/geometry/TestOGCDistance.java @@ -0,0 +1,59 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.esri.core.geometry; + +import org.junit.Test; + +import static com.esri.core.geometry.ogc.OGCGeometry.fromText; +import static java.lang.String.format; +import static org.junit.Assert.assertEquals; + +public class TestOGCDistance +{ + @Test + public void testPoint() + { + assertDistance("POINT (1 2)", "POINT (2 2)", 1); + assertDistance("POINT (1 2)", "POINT (1 2)", 0); + assertNanDistance("POINT (1 2)", "POINT EMPTY"); + + assertDistance(gc("POINT (1 2)"), "POINT (2 2)", 1); + assertDistance(gc("POINT (1 2)"), "POINT (1 2)", 0); + assertNanDistance(gc("POINT (1 2)"), "POINT EMPTY"); + assertDistance(gc("POINT (1 2)"), gc("POINT (2 2)"), 1); + + assertDistance("MULTIPOINT (1 0, 2 0, 3 0)", "POINT (2 1)", 1); + assertDistance(gc("MULTIPOINT (1 0, 2 0, 3 0)"), "POINT (2 1)", 1); + assertDistance(gc("POINT (1 0), POINT (2 0), POINT (3 0))"), "POINT (2 1)", 1); + + assertDistance(gc("POINT (1 0), POINT EMPTY"), "POINT (2 0)", 1); + } + + private void assertDistance(String wkt, String otherWkt, double distance) + { + assertEquals(distance, fromText(wkt).distance(fromText(otherWkt)), 0.000001); + assertEquals(distance, fromText(otherWkt).distance(fromText(wkt)), 0.000001); + } + + private void assertNanDistance(String wkt, String otherWkt) + { + assertEquals(Double.NaN, fromText(wkt).distance(fromText(otherWkt)), 0.000001); + assertEquals(Double.NaN, fromText(otherWkt).distance(fromText(wkt)), 0.000001); + } + + private String gc(String wkts) + { + return format("GEOMETRYCOLLECTION (%s)", wkts); + } +} diff --git a/src/test/java/com/esri/core/geometry/TestOGCGeometryCollection.java b/src/test/java/com/esri/core/geometry/TestOGCGeometryCollection.java new file mode 100644 index 00000000..53007166 --- /dev/null +++ b/src/test/java/com/esri/core/geometry/TestOGCGeometryCollection.java @@ -0,0 +1,237 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.esri.core.geometry; + +import com.esri.core.geometry.ogc.OGCGeometry; +import org.junit.Assert; +import org.junit.Test; + +public class TestOGCGeometryCollection { + @Test + public void testUnionPoint() { + // point - point + assertUnion("POINT (1 2)", "POINT (1 2)", "POINT (1 2)"); + assertUnion("POINT (1 2)", "POINT EMPTY", "POINT (1 2)"); + assertUnion("POINT (1 2)", "POINT (3 4)", "MULTIPOINT ((1 2), (3 4))"); + + // point - multi-point + assertUnion("POINT (1 2)", "MULTIPOINT (1 2)", "POINT (1 2)"); + assertUnion("POINT (1 2)", "MULTIPOINT EMPTY", "POINT (1 2)"); + assertUnion("POINT (1 2)", "MULTIPOINT (3 4)", "MULTIPOINT ((1 2), (3 4))"); + assertUnion("POINT (1 2)", "MULTIPOINT (1 2, 3 4)", "MULTIPOINT ((1 2), (3 4))"); + assertUnion("POINT (1 2)", "MULTIPOINT (3 4, 5 6)", "MULTIPOINT ((1 2), (3 4), (5 6))"); + + // point - linestring + assertUnion("POINT (1 2)", "LINESTRING (3 4, 5 6)", "GEOMETRYCOLLECTION (POINT (1 2), LINESTRING (3 4, 5 6))"); + assertUnion("POINT (1 2)", "LINESTRING EMPTY", "POINT (1 2)"); + assertUnion("POINT (1 2)", "LINESTRING (1 2, 3 4)", "LINESTRING (1 2, 3 4)"); + assertUnion("POINT (1 2)", "LINESTRING (1 1, 1 3, 3 4)", "LINESTRING (1 1, 1 2, 1 3, 3 4)"); + + // point - multi-linestring + assertUnion("POINT (1 2)", "MULTILINESTRING ((3 4, 5 6))", + "GEOMETRYCOLLECTION (POINT (1 2), LINESTRING (3 4, 5 6))"); + assertUnion("POINT (1 2)", "MULTILINESTRING EMPTY", "POINT (1 2)"); + assertUnion("POINT (1 2)", "MULTILINESTRING ((3 4, 5 6), (7 8, 9 10, 11 12))", + "GEOMETRYCOLLECTION (POINT (1 2), MULTILINESTRING ((3 4, 5 6), (7 8, 9 10, 11 12)))"); + assertUnion("POINT (1 2)", "MULTILINESTRING ((1 2, 3 4))", "LINESTRING (1 2, 3 4)"); + assertUnion("POINT (1 2)", "MULTILINESTRING ((1 1, 1 3, 3 4), (7 8, 9 10, 11 12))", + "MULTILINESTRING ((1 1, 1 2, 1 3, 3 4), (7 8, 9 10, 11 12))"); + + // point - polygon + assertUnion("POINT (1 2)", "POLYGON ((0 0, 1 0, 1 1, 0 0))", + "GEOMETRYCOLLECTION (POINT (1 2), POLYGON ((0 0, 1 0, 1 1, 0 0)))"); + assertUnion("POINT (1 2)", "POLYGON EMPTY", "POINT (1 2)"); + // point inside polygon + assertUnion("POINT (1 2)", "POLYGON ((0 0, 3 0, 3 3, 0 3, 0 0))", "POLYGON ((0 0, 3 0, 3 3, 0 3, 0 0))"); + // point inside polygon with a hole + assertUnion("POINT (1 2)", "POLYGON ((0 0, 3 0, 3 3, 0 3, 0 0), (2 2, 2 2.5, 2.5 2.5, 2.5 2, 2 2))", + "POLYGON ((0 0, 3 0, 3 3, 0 3, 0 0), (2 2, 2 2.5, 2.5 2.5, 2.5 2, 2 2))"); + // point inside polygon's hole + assertUnion("POINT (1 2)", "POLYGON ((0 0, 3 0, 3 3, 0 3, 0 0), (0.5 1, 0.5 2.5, 2.5 2.5, 2.5 1, 0.5 1))", + "GEOMETRYCOLLECTION (POINT (1 2), POLYGON ((0 0, 3 0, 3 3, 0 3, 0 0), (0.5 1, 0.5 2.5, 2.5 2.5, 2.5 1, 0.5 1)))"); + // point is a vertex of the polygon + assertUnion("POINT (1 2)", "POLYGON ((1 2, 2 2, 2 3, 1 3, 1 2))", "POLYGON ((1 2, 2 2, 2 3, 1 3, 1 2))"); + // point on the boundary of the polybon + assertUnion("POINT (1 2)", "POLYGON ((1 1, 2 1, 2 3, 1 3, 1 1))", "POLYGON ((1 1, 2 1, 2 3, 1 3, 1 2, 1 1))"); + + // point - multi-polygon + assertUnion("POINT (1 2)", "MULTIPOLYGON (((0 0, 1 0, 1 1, 0 0)))", + "GEOMETRYCOLLECTION (POINT (1 2), POLYGON ((0 0, 1 0, 1 1, 0 0)))"); + assertUnion("POINT (1 2)", "MULTIPOLYGON EMPTY", "POINT (1 2)"); + assertUnion("POINT (1 2)", "MULTIPOLYGON (((0 0, 3 0, 3 3, 0 3, 0 0)))", "POLYGON ((0 0, 3 0, 3 3, 0 3, 0 0))"); + assertUnion("POINT (1 2)", "MULTIPOLYGON (((0 0, 3 0, 3 3, 0 3, 0 0)), ((4 4, 5 4, 5 5, 4 4)))", + "MULTIPOLYGON (((0 0, 3 0, 3 3, 0 3, 0 0)), ((4 4, 5 4, 5 5, 4 4)))"); + assertUnion("POINT (1 2)", + "MULTIPOLYGON (((0 0, 3 0, 3 3, 0 3, 0 0), (0.5 1, 0.5 2.5, 2.5 2.5, 2.5 1, 0.5 1)))", + "GEOMETRYCOLLECTION (POINT (1 2), POLYGON ((0 0, 3 0, 3 3, 0 3, 0 0), (0.5 1, 0.5 2.5, 2.5 2.5, 2.5 1, 0.5 1)))"); + assertUnion("POINT (1 2)", + "MULTIPOLYGON (((0 0, 3 0, 3 3, 0 3, 0 0), (0.5 1, 0.5 2.5, 2.5 2.5, 2.5 1, 0.5 1)), ((4 4, 5 4, 5 5, 4 4)))", + "GEOMETRYCOLLECTION (POINT (1 2), MULTIPOLYGON (((0 0, 3 0, 3 3, 0 3, 0 0), (0.5 1, 0.5 2.5, 2.5 2.5, 2.5 1, 0.5 1)), ((4 4, 5 4, 5 5, 4 4))))"); + + // point - geometry collection + assertUnion("POINT (1 2)", "GEOMETRYCOLLECTION (POINT (1 2))", "POINT (1 2)"); + assertUnion("POINT (1 2)", "GEOMETRYCOLLECTION EMPTY", "POINT (1 2)"); + assertUnion("POINT (1 2)", "GEOMETRYCOLLECTION (POINT (1 2), POINT (2 3))", "MULTIPOINT ((1 2), (2 3))"); + assertUnion("POINT (1 2)", "GEOMETRYCOLLECTION (MULTIPOINT (1 2, 2 3))", "MULTIPOINT ((1 2), (2 3))"); + assertUnion("POINT (1 2)", "GEOMETRYCOLLECTION (LINESTRING (1 2, 3 4))", "LINESTRING (1 2, 3 4)"); + assertUnion("POINT (1 2)", "GEOMETRYCOLLECTION (POINT (0 0), LINESTRING (1 2, 3 4))", + "GEOMETRYCOLLECTION (POINT (0 0), LINESTRING (1 2, 3 4))"); + assertUnion("POINT (1 2)", "GEOMETRYCOLLECTION (POLYGON ((0 0, 3 0, 3 3, 0 3, 0 0)))", + "POLYGON ((0 0, 3 0, 3 3, 0 3, 0 0))"); + assertUnion("POINT (1 2)", "GEOMETRYCOLLECTION (POINT (5 5), POLYGON ((0 0, 3 0, 3 3, 0 3, 0 0)))", + "GEOMETRYCOLLECTION (POINT (5 5), POLYGON ((0 0, 3 0, 3 3, 0 3, 0 0)))"); + } + + @Test + public void testUnionLinestring() { + // linestring - linestring + assertUnion("LINESTRING (1 2, 3 4)", "LINESTRING (1 2, 3 4)", "LINESTRING (1 2, 3 4)"); + assertUnion("LINESTRING (1 2, 3 4)", "LINESTRING EMPTY", "LINESTRING (1 2, 3 4)"); + assertUnion("LINESTRING (1 2, 3 4)", "LINESTRING (3 4, 1 2)", "LINESTRING (1 2, 3 4)"); + assertUnion("LINESTRING (1 2, 3 4)", "LINESTRING (3 4, 5 6)", "LINESTRING (1 2, 3 4, 5 6)"); + assertUnion("LINESTRING (1 2, 3 4)", "LINESTRING (5 6, 7 8)", "MULTILINESTRING ((1 2, 3 4), (5 6, 7 8))"); + assertUnion("LINESTRING (1 2, 3 4)", "LINESTRING (2 1, 2 5)", + "MULTILINESTRING ((2 1, 2 3), (1 2, 2 3), (2 3, 3 4), (2 3, 2 5))"); + assertUnion("LINESTRING (1 2, 3 4)", "LINESTRING (1 2, 2 3, 4 3)", + "MULTILINESTRING ((1 2, 2 3), (2 3, 4 3), (2 3, 3 4))"); + assertUnion("LINESTRING (1 2, 3 4)", "LINESTRING (2 3, 2.1 3.1)", + "LINESTRING (1 2, 2 3, 2.0999999999999996 3.0999999999999996, 3 4)"); + + // linestring - polygon + assertUnion("LINESTRING (1 2, 3 4)", "POLYGON ((5 5, 6 5, 6 6, 5 5))", + "GEOMETRYCOLLECTION (LINESTRING (1 2, 3 4), POLYGON ((5 5, 6 5, 6 6, 5 5)))"); + assertUnion("LINESTRING (1 2, 3 4)", "POLYGON EMPTY", "LINESTRING (1 2, 3 4)"); + // linestring inside polygon + assertUnion("LINESTRING (1 2, 3 4)", "POLYGON ((0 0, 5 0, 5 5, 0 5, 0 0))", + "POLYGON ((0 0, 5 0, 5 5, 0 5, 0 0))"); + assertUnion("LINESTRING (0 0, 5 0)", "POLYGON ((0 0, 5 0, 5 5, 0 5, 0 0))", + "POLYGON ((0 0, 5 0, 5 5, 0 5, 0 0))"); + // linestring crosses polygon's vertex + assertUnion("LINESTRING (0 0, 6 6)", "POLYGON ((0 0, 5 0, 5 5, 0 5, 0 0))", + "GEOMETRYCOLLECTION (LINESTRING (5 5, 6 6), POLYGON ((0 0, 5 0, 5 5, 0 5, 0 0)))"); + assertUnion("LINESTRING (4 6, 6 4)", "POLYGON ((0 0, 5 0, 5 5, 0 5, 0 0))", + "GEOMETRYCOLLECTION (LINESTRING (4 6, 5 5, 6 4), POLYGON ((0 0, 5 0, 5 5, 0 5, 0 0)))"); + // linestring crosses polygon's boundary + assertUnion("LINESTRING (1 1, 1 6)", "POLYGON ((0 0, 5 0, 5 5, 0 5, 0 0))", + "GEOMETRYCOLLECTION (LINESTRING (1 5, 1 6), POLYGON ((0 0, 5 0, 5 5, 1 5, 0 5, 0 0)))"); + + // linestring - geometry collection + assertUnion("LINESTRING (1 2, 3 4)", "GEOMETRYCOLLECTION (LINESTRING (1 2, 3 4))", "LINESTRING (1 2, 3 4)"); + assertUnion("LINESTRING (1 2, 3 4)", "GEOMETRYCOLLECTION EMPTY", "LINESTRING (1 2, 3 4)"); + assertUnion("LINESTRING (1 2, 3 4)", "GEOMETRYCOLLECTION (LINESTRING (3 4, 5 6))", + "LINESTRING (1 2, 3 4, 5 6)"); + assertUnion("LINESTRING (1 2, 3 4)", "GEOMETRYCOLLECTION (LINESTRING (3 4, 5 6), LINESTRING (7 8, 9 10))", + "MULTILINESTRING ((1 2, 3 4, 5 6), (7 8, 9 10))"); + assertUnion("LINESTRING (1 2, 3 4)", "GEOMETRYCOLLECTION (POINT (1 2), LINESTRING (3 4, 5 6))", + "LINESTRING (1 2, 3 4, 5 6)"); + assertUnion("LINESTRING (1 2, 3 4)", + "GEOMETRYCOLLECTION (POINT (1 2), LINESTRING (3 4, 5 6), POLYGON ((3 0, 4 0, 4 1, 3 0)))", + "GEOMETRYCOLLECTION (LINESTRING (1 2, 3 4, 5 6), POLYGON ((3 0, 4 0, 4 1, 3 0)))"); + } + + @Test + public void testUnionPolygon() { + // polygon - polygon + assertUnion("POLYGON ((0 0, 1 0, 1 1, 0 0))", "POLYGON ((0 0, 1 0, 1 1, 0 0))", + "POLYGON ((0 0, 1 0, 1 1, 0 0))"); + assertUnion("POLYGON ((0 0, 1 0, 1 1, 0 0))", "POLYGON EMPTY", "POLYGON ((0 0, 1 0, 1 1, 0 0))"); + // one polygon contains the other + assertUnion("POLYGON ((0 0, 5 0, 5 5, 0 5, 0 0))", "POLYGON ((1 1, 2 1, 2 2, 1 1))", + "POLYGON ((0 0, 5 0, 5 5, 0 5, 0 0))"); + // The following test fails because vertex order in the union geometry depends + // on the order of union inputs + // assertUnion("POLYGON ((0 0, 1 0, 1 1, 0 0))", "POLYGON ((0 0, 0.5 0, 0.5 0.5, + // 0 0))", "POLYGON ((0 0, 0.5 0, 1 0, 1 1, 0.49999999999999994 + // 0.49999999999999994, 0 0))"); + // polygons intersect + assertUnion("POLYGON ((0 0, 1 0, 1 1, 0 0))", "POLYGON ((0 0.5, 2 0.5, 2 2, 0 2, 0 0.5))", + "POLYGON ((0 0, 1 0, 1 0.5, 2 0.5, 2 2, 0 2, 0 0.5, 0.5 0.5, 0 0))"); + // disjoint polygons + assertUnion("POLYGON ((0 0, 1 0, 1 1, 0 0))", "POLYGON ((3 3, 5 3, 5 5, 3 3))", + "MULTIPOLYGON (((0 0, 1 0, 1 1, 0 0)), ((3 3, 5 3, 5 5, 3 3)))"); + + // polygon - multi-polygon + assertUnion("POLYGON ((0 0, 1 0, 1 1, 0 0))", "MULTIPOLYGON (((0 0, 1 0, 1 1, 0 0)))", + "POLYGON ((0 0, 1 0, 1 1, 0 0))"); + assertUnion("POLYGON ((0 0, 1 0, 1 1, 0 0))", "MULTIPOLYGON EMPTY", "POLYGON ((0 0, 1 0, 1 1, 0 0))"); + assertUnion("POLYGON ((0 0, 1 0, 1 1, 0 0))", "MULTIPOLYGON (((0 0.5, 2 0.5, 2 2, 0 2, 0 0.5)))", + "POLYGON ((0 0, 1 0, 1 0.5, 2 0.5, 2 2, 0 2, 0 0.5, 0.5 0.5, 0 0))"); + assertUnion("POLYGON ((0 0, 1 0, 1 1, 0 0))", "MULTIPOLYGON (((3 3, 5 3, 5 5, 3 3)))", + "MULTIPOLYGON (((0 0, 1 0, 1 1, 0 0)), ((3 3, 5 3, 5 5, 3 3)))"); + + // polygon - geometry collection + assertUnion("POLYGON ((0 0, 1 0, 1 1, 0 0))", "GEOMETRYCOLLECTION (POLYGON ((0 0, 1 0, 1 1, 0 0)))", + "POLYGON ((0 0, 1 0, 1 1, 0 0))"); + assertUnion("POLYGON ((0 0, 1 0, 1 1, 0 0))", "GEOMETRYCOLLECTION EMPTY", "POLYGON ((0 0, 1 0, 1 1, 0 0))"); + assertUnion("POLYGON ((0 0, 1 0, 1 1, 0 0))", "GEOMETRYCOLLECTION (POLYGON ((3 3, 5 3, 5 5, 3 3)))", + "MULTIPOLYGON (((0 0, 1 0, 1 1, 0 0)), ((3 3, 5 3, 5 5, 3 3)))"); + assertUnion("POLYGON ((0 0, 1 0, 1 1, 0 0))", + "GEOMETRYCOLLECTION (POINT (0 0), POLYGON ((3 3, 5 3, 5 5, 3 3)))", + "MULTIPOLYGON (((0 0, 1 0, 1 1, 0 0)), ((3 3, 5 3, 5 5, 3 3)))"); + assertUnion("POLYGON ((0 0, 1 0, 1 1, 0 0))", + "GEOMETRYCOLLECTION (POINT (10 10), POLYGON ((3 3, 5 3, 5 5, 3 3)))", + "GEOMETRYCOLLECTION (POINT (10 10), MULTIPOLYGON (((0 0, 1 0, 1 1, 0 0)), ((3 3, 5 3, 5 5, 3 3))))"); + } + + private void assertUnion(String wkt, String otherWkt, String expectedWkt) { + OGCGeometry geometry = OGCGeometry.fromText(wkt); + OGCGeometry otherGeometry = OGCGeometry.fromText(otherWkt); + Assert.assertEquals(expectedWkt, geometry.union(otherGeometry).asText()); + Assert.assertEquals(expectedWkt, otherGeometry.union(geometry).asText()); + } + + @Test + public void testGeometryCollectionOverlappingContains() { + assertContains("GEOMETRYCOLLECTION (POINT (0 0), LINESTRING (0 1, 5 1))", + "GEOMETRYCOLLECTION (MULTIPOINT (0 0, 2 1))"); + } + + private void assertContains(String wkt, String otherWkt) { + OGCGeometry geometry = OGCGeometry.fromText(wkt); + OGCGeometry otherGeometry = OGCGeometry.fromText(otherWkt); + Assert.assertTrue(geometry.contains(otherGeometry)); + Assert.assertTrue(otherGeometry.within(geometry)); + } + + @Test + public void testGeometryCollectionDisjoint() { + assertDisjoint("GEOMETRYCOLLECTION (POINT (0 0), LINESTRING (0 1, 5 1))", + "GEOMETRYCOLLECTION (MULTIPOINT (10 0, 21 1), LINESTRING (30 0, 31 1), POLYGON ((40 0, 41 1, 40 1, 40 0)))"); + } + + private void assertDisjoint(String wkt, String otherWkt) { + OGCGeometry geometry = OGCGeometry.fromText(wkt); + OGCGeometry otherGeometry = OGCGeometry.fromText(otherWkt); + Assert.assertTrue(geometry.disjoint(otherGeometry)); + Assert.assertTrue(otherGeometry.disjoint(geometry)); + } + + @Test + public void testGeometryCollectionIntersect() { + assertIntersection("GEOMETRYCOLLECTION (POINT (1 2))", "POINT EMPTY", "GEOMETRYCOLLECTION EMPTY"); + assertIntersection("GEOMETRYCOLLECTION (POINT (1 2), MULTIPOINT (3 4, 5 6))", "POINT (3 4)", + "POINT (3 4)"); + assertIntersection("GEOMETRYCOLLECTION (POINT (1 2), MULTIPOINT (3 4, 5 6))", "POINT (30 40)", + "GEOMETRYCOLLECTION EMPTY"); + assertIntersection("POINT (30 40)", "GEOMETRYCOLLECTION (POINT (1 2), MULTIPOINT (3 4, 5 6))", + "GEOMETRYCOLLECTION EMPTY"); + } + + private void assertIntersection(String wkt, String otherWkt, String expectedWkt) { + OGCGeometry geometry = OGCGeometry.fromText(wkt); + OGCGeometry otherGeometry = OGCGeometry.fromText(otherWkt); + OGCGeometry result = geometry.intersection(otherGeometry); + Assert.assertEquals(expectedWkt, result.asText()); + } +} diff --git a/src/test/java/com/esri/core/geometry/TestOGCGeometryCollectionFlatten.java b/src/test/java/com/esri/core/geometry/TestOGCGeometryCollectionFlatten.java new file mode 100644 index 00000000..8a98d5d1 --- /dev/null +++ b/src/test/java/com/esri/core/geometry/TestOGCGeometryCollectionFlatten.java @@ -0,0 +1,48 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.esri.core.geometry; + +import com.esri.core.geometry.ogc.OGCConcreteGeometryCollection; +import org.junit.Test; + +import static com.esri.core.geometry.ogc.OGCGeometry.fromText; +import static java.lang.String.format; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +public class TestOGCGeometryCollectionFlatten +{ + @Test + public void test() + { + assertFlatten("GEOMETRYCOLLECTION EMPTY", "GEOMETRYCOLLECTION EMPTY"); + assertFlatten(gc("POINT (1 2)"), gc("MULTIPOINT ((1 2))")); + assertFlatten(gc("POINT (1 2), POINT EMPTY"), gc("MULTIPOINT ((1 2))")); + assertFlatten(gc("POINT (1 2), MULTIPOINT (3 4, 5 6)"), gc("MULTIPOINT ((1 2), (3 4), (5 6))")); + assertFlatten(gc("POINT (1 2), POINT (3 4), " + gc("POINT (5 6)")), gc("MULTIPOINT ((1 2), (3 4), (5 6))")); + } + + private void assertFlatten(String wkt, String flattenedWkt) + { + OGCConcreteGeometryCollection collection = (OGCConcreteGeometryCollection) fromText(wkt); + assertEquals(flattenedWkt, collection.flatten().asText()); + assertTrue(collection.flatten().isFlattened()); + assertEquals(flattenedWkt, collection.flatten().flatten().asText()); + } + + private String gc(String wkts) + { + return format("GEOMETRYCOLLECTION (%s)", wkts); + } +} diff --git a/src/test/java/com/esri/core/geometry/TestOGCReduceFromMulti.java b/src/test/java/com/esri/core/geometry/TestOGCReduceFromMulti.java new file mode 100644 index 00000000..f47c817c --- /dev/null +++ b/src/test/java/com/esri/core/geometry/TestOGCReduceFromMulti.java @@ -0,0 +1,80 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.esri.core.geometry; + +import org.junit.Test; + +import static com.esri.core.geometry.ogc.OGCGeometry.fromText; +import static java.lang.String.format; +import static org.junit.Assert.assertEquals; + +public class TestOGCReduceFromMulti +{ + @Test + public void testPoint() + { + assertReduceFromMulti("POINT (1 2)", "POINT (1 2)"); + assertReduceFromMulti("POINT EMPTY", "POINT EMPTY"); + assertReduceFromMulti("MULTIPOINT (1 2)", "POINT (1 2)"); + assertReduceFromMulti("MULTIPOINT (1 2, 3 4)", "MULTIPOINT ((1 2), (3 4))"); + assertReduceFromMulti("MULTIPOINT EMPTY", "POINT EMPTY"); + } + + @Test + public void testLineString() + { + assertReduceFromMulti("LINESTRING (0 0, 1 1, 2 3)", "LINESTRING (0 0, 1 1, 2 3)"); + assertReduceFromMulti("LINESTRING EMPTY", "LINESTRING EMPTY"); + assertReduceFromMulti("MULTILINESTRING ((0 0, 1 1, 2 3))", "LINESTRING (0 0, 1 1, 2 3)"); + assertReduceFromMulti("MULTILINESTRING ((0 0, 1 1, 2 3), (4 4, 5 5))", "MULTILINESTRING ((0 0, 1 1, 2 3), (4 4, 5 5))"); + assertReduceFromMulti("MULTILINESTRING EMPTY", "LINESTRING EMPTY"); + } + + @Test + public void testPolygon() + { + assertReduceFromMulti("POLYGON ((0 0, 1 0, 1 1, 0 0))", "POLYGON ((0 0, 1 0, 1 1, 0 0))"); + assertReduceFromMulti("POLYGON EMPTY", "POLYGON EMPTY"); + assertReduceFromMulti("MULTIPOLYGON (((0 0, 1 0, 1 1, 0 0)))", "POLYGON ((0 0, 1 0, 1 1, 0 0))"); + assertReduceFromMulti("MULTIPOLYGON (((0 0, 1 0, 1 1, 0 0)), ((2 2, 3 2, 3 3, 2 2)))", "MULTIPOLYGON (((0 0, 1 0, 1 1, 0 0)), ((2 2, 3 2, 3 3, 2 2)))"); + assertReduceFromMulti("MULTIPOLYGON EMPTY", "POLYGON EMPTY"); + } + + @Test + public void testGeometryCollection() + { + assertReduceFromMulti(gc("POINT (1 2)"), "POINT (1 2)"); + assertReduceFromMulti(gc("MULTIPOINT (1 2)"), "POINT (1 2)"); + assertReduceFromMulti(gc(gc("POINT (1 2)")), "POINT (1 2)"); + assertReduceFromMulti(gc("POINT EMPTY"), "POINT EMPTY"); + + assertReduceFromMulti(gc("LINESTRING (0 0, 1 1, 2 3)"), "LINESTRING (0 0, 1 1, 2 3)"); + assertReduceFromMulti(gc("POLYGON ((0 0, 1 0, 1 1, 0 0))"), "POLYGON ((0 0, 1 0, 1 1, 0 0))"); + + assertReduceFromMulti(gc("POINT (1 2), LINESTRING (0 0, 1 1, 2 3)"), gc("POINT (1 2), LINESTRING (0 0, 1 1, 2 3)")); + + assertReduceFromMulti("GEOMETRYCOLLECTION EMPTY", "GEOMETRYCOLLECTION EMPTY"); + assertReduceFromMulti(gc("GEOMETRYCOLLECTION EMPTY"), "GEOMETRYCOLLECTION EMPTY"); + } + + private void assertReduceFromMulti(String wkt, String reducedWkt) + { + assertEquals(reducedWkt, fromText(wkt).reduceFromMulti().asText()); + } + + private String gc(String wkts) + { + return format("GEOMETRYCOLLECTION (%s)", wkts); + } +} diff --git a/src/test/java/com/esri/core/geometry/TestOffset.java b/src/test/java/com/esri/core/geometry/TestOffset.java index 51fc59be..385e3504 100644 --- a/src/test/java/com/esri/core/geometry/TestOffset.java +++ b/src/test/java/com/esri/core/geometry/TestOffset.java @@ -29,148 +29,148 @@ import org.junit.Test; public class TestOffset extends TestCase { - @Override - protected void setUp() throws Exception { - super.setUp(); - } - - @Override - protected void tearDown() throws Exception { - super.tearDown(); - } - - @Test - public void testOffsetPoint() { - try { - Point point = new Point(); - point.setXY(0, 0); - - OperatorOffset offset = (OperatorOffset) OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Offset); - - Geometry outputGeom = offset.execute(point, null, 2, - JoinType.Round, 2, 0, null); - - assertNull(outputGeom); - } catch (Exception ex) { - } - - try { - MultiPoint mp = new MultiPoint(); - mp.add(0, 0); - mp.add(10, 10); - - OperatorOffset offset = (OperatorOffset) OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Offset); - - Geometry outputGeom = offset.execute(mp, null, 2, JoinType.Round, - 2, 0, null); - - assertNull(outputGeom); - } catch (Exception ex) { - } - } - - @Test - public void testOffsetPolyline() { - for (long i = -5; i <= 5; i++) { - try { - OffsetPolyline_(i, JoinType.Round); - } catch (Exception ex) { - fail("OffsetPolyline(Round) failure"); - } - - try { - OffsetPolyline_(i, JoinType.Miter); - } catch (Exception ex) { - fail("OffsetPolyline(Miter) failure"); - } - - try { - OffsetPolyline_(i, JoinType.Bevel); - } catch (Exception ex) { - fail("OffsetPolyline(Bevel) failure"); - } - - try { - OffsetPolyline_(i, JoinType.Square); - } catch (Exception ex) { - fail("OffsetPolyline(Square) failure"); - } - } - } - - public void OffsetPolyline_(double distance, JoinType joins) { - Polyline polyline = new Polyline(); - polyline.startPath(0, 0); - polyline.lineTo(6, 0); - polyline.lineTo(6, 1); - polyline.lineTo(4, 1); - polyline.lineTo(4, 2); - polyline.lineTo(10, 2); - - OperatorOffset offset = (OperatorOffset) OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Offset); - - Geometry outputGeom = offset.execute(polyline, null, distance, joins, - 2, 0, null); - - assertNotNull(outputGeom); - } - - @Test - public void testOffsetPolygon() { - for (long i = -5; i <= 5; i++) { - try { - OffsetPolygon_(i, JoinType.Round); - } catch (Exception ex) { - fail("OffsetPolyline(Round) failure"); - } - - try { - OffsetPolygon_(i, JoinType.Miter); - } catch (Exception ex) { - fail("OffsetPolyline(Miter) failure"); - } - - try { - OffsetPolygon_(i, JoinType.Bevel); - } catch (Exception ex) { - fail("OffsetPolyline(Bevel) failure"); - } - - try { - OffsetPolygon_(i, JoinType.Square); - } catch (Exception ex) { - fail("OffsetPolyline(Square) failure"); - } - } - } - - public void OffsetPolygon_(double distance, JoinType joins) { - Polygon polygon = new Polygon(); - polygon.startPath(0, 0); - polygon.lineTo(0, 16); - polygon.lineTo(16, 16); - polygon.lineTo(16, 11); - polygon.lineTo(10, 10); - polygon.lineTo(10, 12); - polygon.lineTo(3, 12); - polygon.lineTo(3, 4); - polygon.lineTo(10, 4); - polygon.lineTo(10, 6); - polygon.lineTo(16, 5); - polygon.lineTo(16, 0); - - OperatorOffset offset = (OperatorOffset) OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Offset); - - Geometry outputGeom = offset.execute(polygon, null, distance, joins, 2, - 0, null); - - assertNotNull(outputGeom); - if (distance > 2) { - assertTrue(outputGeom.isEmpty()); - } - } + @Override + protected void setUp() throws Exception { + super.setUp(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + } + + @Test + public void testOffsetPoint() { + try { + Point point = new Point(); + point.setXY(0, 0); + + OperatorOffset offset = (OperatorOffset) OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Offset); + + Geometry outputGeom = offset.execute(point, null, 2, + JoinType.Round, 2, 0, null); + + assertNull(outputGeom); + } catch (Exception ex) { + } + + try { + MultiPoint mp = new MultiPoint(); + mp.add(0, 0); + mp.add(10, 10); + + OperatorOffset offset = (OperatorOffset) OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Offset); + + Geometry outputGeom = offset.execute(mp, null, 2, JoinType.Round, + 2, 0, null); + + assertNull(outputGeom); + } catch (Exception ex) { + } + } + + @Test + public void testOffsetPolyline() { + for (long i = -5; i <= 5; i++) { + try { + OffsetPolyline_(i, JoinType.Round); + } catch (Exception ex) { + fail("OffsetPolyline(Round) failure"); + } + + try { + OffsetPolyline_(i, JoinType.Miter); + } catch (Exception ex) { + fail("OffsetPolyline(Miter) failure"); + } + + try { + OffsetPolyline_(i, JoinType.Bevel); + } catch (Exception ex) { + fail("OffsetPolyline(Bevel) failure"); + } + + try { + OffsetPolyline_(i, JoinType.Square); + } catch (Exception ex) { + fail("OffsetPolyline(Square) failure"); + } + } + } + + public void OffsetPolyline_(double distance, JoinType joins) { + Polyline polyline = new Polyline(); + polyline.startPath(0, 0); + polyline.lineTo(6, 0); + polyline.lineTo(6, 1); + polyline.lineTo(4, 1); + polyline.lineTo(4, 2); + polyline.lineTo(10, 2); + + OperatorOffset offset = (OperatorOffset) OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Offset); + + Geometry outputGeom = offset.execute(polyline, null, distance, joins, + 2, 0, null); + + assertNotNull(outputGeom); + } + + @Test + public void testOffsetPolygon() { + for (long i = -5; i <= 5; i++) { + try { + OffsetPolygon_(i, JoinType.Round); + } catch (Exception ex) { + fail("OffsetPolyline(Round) failure"); + } + + try { + OffsetPolygon_(i, JoinType.Miter); + } catch (Exception ex) { + fail("OffsetPolyline(Miter) failure"); + } + + try { + OffsetPolygon_(i, JoinType.Bevel); + } catch (Exception ex) { + fail("OffsetPolyline(Bevel) failure"); + } + + try { + OffsetPolygon_(i, JoinType.Square); + } catch (Exception ex) { + fail("OffsetPolyline(Square) failure"); + } + } + } + + public void OffsetPolygon_(double distance, JoinType joins) { + Polygon polygon = new Polygon(); + polygon.startPath(0, 0); + polygon.lineTo(0, 16); + polygon.lineTo(16, 16); + polygon.lineTo(16, 11); + polygon.lineTo(10, 10); + polygon.lineTo(10, 12); + polygon.lineTo(3, 12); + polygon.lineTo(3, 4); + polygon.lineTo(10, 4); + polygon.lineTo(10, 6); + polygon.lineTo(16, 5); + polygon.lineTo(16, 0); + + OperatorOffset offset = (OperatorOffset) OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Offset); + + Geometry outputGeom = offset.execute(polygon, null, distance, joins, 2, + 0, null); + + assertNotNull(outputGeom); + if (distance > 2) { + assertTrue(outputGeom.isEmpty()); + } + } } diff --git a/src/test/java/com/esri/core/geometry/TestPoint.java b/src/test/java/com/esri/core/geometry/TestPoint.java index 2b191d72..cc380865 100644 --- a/src/test/java/com/esri/core/geometry/TestPoint.java +++ b/src/test/java/com/esri/core/geometry/TestPoint.java @@ -30,214 +30,238 @@ import java.util.Random; public class TestPoint extends TestCase { - @Override - protected void setUp() throws Exception { - super.setUp(); - } - - @Override - protected void tearDown() throws Exception { - super.tearDown(); - } - - @Test - public void testPt() { - Point pt = new Point(); - assertTrue(pt.isEmpty()); - pt.setXY(10, 2); - assertFalse(pt.isEmpty()); - - pt.toString(); - } - - @Test - public void testEnvelope2000() { - Point points[] = new Point[2000]; - Random random = new Random(69); - for (int i = 0; i < 2000; i++) { - points[i] = new Point(); - points[i].setX(random.nextDouble() * 100); - points[i].setY(random.nextDouble() * 100); - } - for (int iter = 0; iter < 2; iter++) { - final long startTime = System.nanoTime(); - Envelope geomExtent = new Envelope(); - Envelope fullExtent = new Envelope(); - for (int i = 0; i < 2000; i++) { - points[i].queryEnvelope(geomExtent); - fullExtent.merge(geomExtent); - } - long endTime = System.nanoTime(); - } - } - - @Test - public void testBasic() { - assertTrue(Geometry.getDimensionFromType(Geometry.Type.Polygon.value()) == 2); - assertTrue(Geometry - .getDimensionFromType(Geometry.Type.Polyline.value()) == 1); - assertTrue(Geometry - .getDimensionFromType(Geometry.Type.Envelope.value()) == 2); - assertTrue(Geometry.getDimensionFromType(Geometry.Type.Line.value()) == 1); - assertTrue(Geometry.getDimensionFromType(Geometry.Type.Point.value()) == 0); - assertTrue(Geometry.getDimensionFromType(Geometry.Type.MultiPoint - .value()) == 0); - - assertTrue(Geometry.isLinear(Geometry.Type.Polygon.value())); - assertTrue(Geometry.isLinear(Geometry.Type.Polyline.value())); - assertTrue(Geometry.isLinear(Geometry.Type.Envelope.value())); - assertTrue(Geometry.isLinear(Geometry.Type.Line.value())); - assertTrue(!Geometry.isLinear(Geometry.Type.Point.value())); - assertTrue(!Geometry.isLinear(Geometry.Type.MultiPoint.value())); - - assertTrue(Geometry.isArea(Geometry.Type.Polygon.value())); - assertTrue(!Geometry.isArea(Geometry.Type.Polyline.value())); - assertTrue(Geometry.isArea(Geometry.Type.Envelope.value())); - assertTrue(!Geometry.isArea(Geometry.Type.Line.value())); - assertTrue(!Geometry.isArea(Geometry.Type.Point.value())); - assertTrue(!Geometry.isArea(Geometry.Type.MultiPoint.value())); - - assertTrue(!Geometry.isPoint(Geometry.Type.Polygon.value())); - assertTrue(!Geometry.isPoint(Geometry.Type.Polyline.value())); - assertTrue(!Geometry.isPoint(Geometry.Type.Envelope.value())); - assertTrue(!Geometry.isPoint(Geometry.Type.Line.value())); - assertTrue(Geometry.isPoint(Geometry.Type.Point.value())); - assertTrue(Geometry.isPoint(Geometry.Type.MultiPoint.value())); - - assertTrue(Geometry.isMultiVertex(Geometry.Type.Polygon.value())); - assertTrue(Geometry.isMultiVertex(Geometry.Type.Polyline.value())); - assertTrue(!Geometry.isMultiVertex(Geometry.Type.Envelope.value())); - assertTrue(!Geometry.isMultiVertex(Geometry.Type.Line.value())); - assertTrue(!Geometry.isMultiVertex(Geometry.Type.Point.value())); - assertTrue(Geometry.isMultiVertex(Geometry.Type.MultiPoint.value())); - - assertTrue(Geometry.isMultiPath(Geometry.Type.Polygon.value())); - assertTrue(Geometry.isMultiPath(Geometry.Type.Polyline.value())); - assertTrue(!Geometry.isMultiPath(Geometry.Type.Envelope.value())); - assertTrue(!Geometry.isMultiPath(Geometry.Type.Line.value())); - assertTrue(!Geometry.isMultiPath(Geometry.Type.Point.value())); - assertTrue(!Geometry.isMultiPath(Geometry.Type.MultiPoint.value())); - - assertTrue(!Geometry.isSegment(Geometry.Type.Polygon.value())); - assertTrue(!Geometry.isSegment(Geometry.Type.Polyline.value())); - assertTrue(!Geometry.isSegment(Geometry.Type.Envelope.value())); - assertTrue(Geometry.isSegment(Geometry.Type.Line.value())); - assertTrue(!Geometry.isSegment(Geometry.Type.Point.value())); - assertTrue(!Geometry.isSegment(Geometry.Type.MultiPoint.value())); - } - - @Test - public void testCopy() { - Point pt = new Point(); - Point copyPt = (Point) pt.copy(); - assertTrue(copyPt.equals(pt)); - - pt.setXY(11, 13); - copyPt = (Point) pt.copy(); - assertTrue(copyPt.equals(pt)); - assertTrue(copyPt.getXY().isEqual(new Point2D(11, 13))); - - assertTrue(copyPt.getXY().equals((Object) new Point2D(11, 13))); - } - - @Test - public void testEnvelope2D_corners() { - Envelope2D env = new Envelope2D(0, 1, 2, 3); - assertFalse(env.equals(null)); - assertTrue(env.equals((Object) new Envelope2D(0, 1, 2, 3))); - - Point2D pt2D = env.getLowerLeft(); - assertTrue(pt2D.equals(Point2D.construct(0, 1))); - pt2D = env.getUpperLeft(); - assertTrue(pt2D.equals(Point2D.construct(0, 3))); - pt2D = env.getUpperRight(); - assertTrue(pt2D.equals(Point2D.construct(2, 3))); - pt2D = env.getLowerRight(); - assertTrue(pt2D.equals(Point2D.construct(2, 1))); - - { - Point2D[] corners = new Point2D[4]; - env.queryCorners(corners); - assertTrue(corners[0].equals(Point2D.construct(0, 1))); - assertTrue(corners[1].equals(Point2D.construct(0, 3))); - assertTrue(corners[2].equals(Point2D.construct(2, 3))); - assertTrue(corners[3].equals(Point2D.construct(2, 1))); - - env.queryCorners(corners); - assertTrue(corners[0].equals(env.queryCorner(0))); - assertTrue(corners[1].equals(env.queryCorner(1))); - assertTrue(corners[2].equals(env.queryCorner(2))); - assertTrue(corners[3].equals(env.queryCorner(3))); - } - - { - Point2D[] corners = new Point2D[4]; - env.queryCornersReversed(corners); - assertTrue(corners[0].equals(Point2D.construct(0, 1))); - assertTrue(corners[1].equals(Point2D.construct(2, 1))); - assertTrue(corners[2].equals(Point2D.construct(2, 3))); - assertTrue(corners[3].equals(Point2D.construct(0, 3))); - - env.queryCornersReversed(corners); - assertTrue(corners[0].equals(env.queryCorner(0))); - assertTrue(corners[1].equals(env.queryCorner(3))); - assertTrue(corners[2].equals(env.queryCorner(2))); - assertTrue(corners[3].equals(env.queryCorner(1))); - } - - assertTrue(env.getCenter().equals(Point2D.construct(1, 2))); - - assertFalse(env.containsExclusive(env.getUpperLeft())); - assertTrue(env.contains(env.getUpperLeft())); - assertTrue(env.containsExclusive(env.getCenter())); - } - - @Test - public void testReplaceNaNs() { - Envelope env = new Envelope(); - Point pt = new Point(); - pt.setXY(1, 2); - pt.setZ(Double.NaN); - pt.queryEnvelope(env); - pt.replaceNaNs(VertexDescription.Semantics.Z, 5); - assertTrue(pt.equals(new Point(1, 2, 5))); - - assertTrue(env.hasZ()); - assertTrue(env.queryInterval(VertexDescription.Semantics.Z, 0).isEmpty()); - env.replaceNaNs(VertexDescription.Semantics.Z, 5); - assertTrue(env.queryInterval(VertexDescription.Semantics.Z, 0).equals(new Envelope1D(5, 5))); - } - - @Test - public void testTriangleArea() { - Point2D pt = new Point2D(0, 0); - Point2D pt2 = new Point2D(2, 2); - Point2D pt1 = new Point2D(0, 2); - double area = pt.calculateTriangleArea2D(pt1, pt2); - assertEquals(2.0, area); - double area2 = pt.calculateTriangleArea2D(pt2, pt1); - assertEquals(area, area2); - } - - @Test - public void testCircleCenter() { - Point2D pt = new Point2D(-2, -2); - Point2D pt2 = new Point2D(2, 2); - Point2D pt1 = new Point2D(-2, 2); - Point2D center = Point2D.calculateCircleCenterFromThreePoints(pt, pt2, pt1); - assertEquals(center.x, 0.0); - assertEquals(center.y, 0.0); - - center = Point2D.calculateCircleCenterFromThreePoints(pt1, pt, pt2); - assertEquals(center.x, 0.0); - assertEquals(center.y, 0.0); - - center = Point2D.calculateCircleCenterFromThreePoints(pt2, pt, pt1); - assertEquals(center.x, 0.0); - assertEquals(center.y, 0.0); - - center = Point2D.calculateCircleCenterFromThreePoints(pt1, pt2, pt); - assertEquals(center.x, 0.0); - assertEquals(center.y, 0.0); - } + @Override + protected void setUp() throws Exception { + super.setUp(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + } + + @Test + public void testPt() { + Point pt = new Point(); + assertTrue(pt.isEmpty()); + assertTrue(Double.isNaN(pt.getX())); + assertTrue(Double.isNaN(pt.getY())); + assertTrue(Double.isNaN(pt.getM())); + assertTrue(pt.getZ() == 0); + Point pt1 = new Point(); + assertTrue(pt.equals(pt1)); + int hash1 = pt.hashCode(); + pt.setXY(10, 2); + assertFalse(pt.isEmpty()); + assertTrue(pt.getX() == 10); + assertTrue(pt.getY() == 2); + assertTrue(pt.getXY().equals(new Point2D(10, 2))); + assertTrue(pt.getXYZ().x == 10); + assertTrue(pt.getXYZ().y == 2); + assertTrue(pt.getXYZ().z == 0); + assertFalse(pt.equals(pt1)); + pt.copyTo(pt1); + assertTrue(pt.equals(pt1)); + int hash2 = pt.hashCode(); + assertFalse(hash1 == hash2); + pt.setZ(5); + assertFalse(pt.equals(pt1)); + pt.copyTo(pt1); + assertTrue(pt.equals(pt1)); + assertFalse(hash1 == pt.hashCode()); + assertFalse(hash2 == pt.hashCode()); + assertTrue(pt.hasZ()); + assertTrue(pt.getZ() == 5); + assertTrue(pt.hasAttribute(VertexDescription.Semantics.Z)); + pt.toString(); + } + + @Test + public void testEnvelope2000() { + Point points[] = new Point[2000]; + Random random = new Random(69); + for (int i = 0; i < 2000; i++) { + points[i] = new Point(); + points[i].setX(random.nextDouble() * 100); + points[i].setY(random.nextDouble() * 100); + } + for (int iter = 0; iter < 2; iter++) { + final long startTime = System.nanoTime(); + Envelope geomExtent = new Envelope(); + Envelope fullExtent = new Envelope(); + for (int i = 0; i < 2000; i++) { + points[i].queryEnvelope(geomExtent); + fullExtent.merge(geomExtent); + } + long endTime = System.nanoTime(); + } + } + + @Test + public void testBasic() { + assertTrue(Geometry.getDimensionFromType(Geometry.Type.Polygon.value()) == 2); + assertTrue(Geometry + .getDimensionFromType(Geometry.Type.Polyline.value()) == 1); + assertTrue(Geometry + .getDimensionFromType(Geometry.Type.Envelope.value()) == 2); + assertTrue(Geometry.getDimensionFromType(Geometry.Type.Line.value()) == 1); + assertTrue(Geometry.getDimensionFromType(Geometry.Type.Point.value()) == 0); + assertTrue(Geometry.getDimensionFromType(Geometry.Type.MultiPoint + .value()) == 0); + + assertTrue(Geometry.isLinear(Geometry.Type.Polygon.value())); + assertTrue(Geometry.isLinear(Geometry.Type.Polyline.value())); + assertTrue(Geometry.isLinear(Geometry.Type.Envelope.value())); + assertTrue(Geometry.isLinear(Geometry.Type.Line.value())); + assertTrue(!Geometry.isLinear(Geometry.Type.Point.value())); + assertTrue(!Geometry.isLinear(Geometry.Type.MultiPoint.value())); + + assertTrue(Geometry.isArea(Geometry.Type.Polygon.value())); + assertTrue(!Geometry.isArea(Geometry.Type.Polyline.value())); + assertTrue(Geometry.isArea(Geometry.Type.Envelope.value())); + assertTrue(!Geometry.isArea(Geometry.Type.Line.value())); + assertTrue(!Geometry.isArea(Geometry.Type.Point.value())); + assertTrue(!Geometry.isArea(Geometry.Type.MultiPoint.value())); + + assertTrue(!Geometry.isPoint(Geometry.Type.Polygon.value())); + assertTrue(!Geometry.isPoint(Geometry.Type.Polyline.value())); + assertTrue(!Geometry.isPoint(Geometry.Type.Envelope.value())); + assertTrue(!Geometry.isPoint(Geometry.Type.Line.value())); + assertTrue(Geometry.isPoint(Geometry.Type.Point.value())); + assertTrue(Geometry.isPoint(Geometry.Type.MultiPoint.value())); + + assertTrue(Geometry.isMultiVertex(Geometry.Type.Polygon.value())); + assertTrue(Geometry.isMultiVertex(Geometry.Type.Polyline.value())); + assertTrue(!Geometry.isMultiVertex(Geometry.Type.Envelope.value())); + assertTrue(!Geometry.isMultiVertex(Geometry.Type.Line.value())); + assertTrue(!Geometry.isMultiVertex(Geometry.Type.Point.value())); + assertTrue(Geometry.isMultiVertex(Geometry.Type.MultiPoint.value())); + + assertTrue(Geometry.isMultiPath(Geometry.Type.Polygon.value())); + assertTrue(Geometry.isMultiPath(Geometry.Type.Polyline.value())); + assertTrue(!Geometry.isMultiPath(Geometry.Type.Envelope.value())); + assertTrue(!Geometry.isMultiPath(Geometry.Type.Line.value())); + assertTrue(!Geometry.isMultiPath(Geometry.Type.Point.value())); + assertTrue(!Geometry.isMultiPath(Geometry.Type.MultiPoint.value())); + + assertTrue(!Geometry.isSegment(Geometry.Type.Polygon.value())); + assertTrue(!Geometry.isSegment(Geometry.Type.Polyline.value())); + assertTrue(!Geometry.isSegment(Geometry.Type.Envelope.value())); + assertTrue(Geometry.isSegment(Geometry.Type.Line.value())); + assertTrue(!Geometry.isSegment(Geometry.Type.Point.value())); + assertTrue(!Geometry.isSegment(Geometry.Type.MultiPoint.value())); + } + + @Test + public void testCopy() { + Point pt = new Point(); + Point copyPt = (Point) pt.copy(); + assertTrue(copyPt.equals(pt)); + + pt.setXY(11, 13); + copyPt = (Point) pt.copy(); + assertTrue(copyPt.equals(pt)); + assertTrue(copyPt.getXY().isEqual(new Point2D(11, 13))); + + assertTrue(copyPt.getXY().equals((Object) new Point2D(11, 13))); + } + + @Test + public void testEnvelope2D_corners() { + Envelope2D env = new Envelope2D(0, 1, 2, 3); + assertFalse(env.equals(null)); + assertTrue(env.equals((Object) new Envelope2D(0, 1, 2, 3))); + Point2D pt2D = env.getLowerLeft(); + assertTrue(pt2D.equals(Point2D.construct(0, 1))); + pt2D = env.getUpperLeft(); + assertTrue(pt2D.equals(Point2D.construct(0, 3))); + pt2D = env.getUpperRight(); + assertTrue(pt2D.equals(Point2D.construct(2, 3))); + pt2D = env.getLowerRight(); + assertTrue(pt2D.equals(Point2D.construct(2, 1))); + + { + Point2D[] corners = new Point2D[4]; + env.queryCorners(corners); + assertTrue(corners[0].equals(Point2D.construct(0, 1))); + assertTrue(corners[1].equals(Point2D.construct(0, 3))); + assertTrue(corners[2].equals(Point2D.construct(2, 3))); + assertTrue(corners[3].equals(Point2D.construct(2, 1))); + + env.queryCorners(corners); + assertTrue(corners[0].equals(env.queryCorner(0))); + assertTrue(corners[1].equals(env.queryCorner(1))); + assertTrue(corners[2].equals(env.queryCorner(2))); + assertTrue(corners[3].equals(env.queryCorner(3))); + } + + { + Point2D[] corners = new Point2D[4]; + env.queryCornersReversed(corners); + assertTrue(corners[0].equals(Point2D.construct(0, 1))); + assertTrue(corners[1].equals(Point2D.construct(2, 1))); + assertTrue(corners[2].equals(Point2D.construct(2, 3))); + assertTrue(corners[3].equals(Point2D.construct(0, 3))); + + env.queryCornersReversed(corners); + assertTrue(corners[0].equals(env.queryCorner(0))); + assertTrue(corners[1].equals(env.queryCorner(3))); + assertTrue(corners[2].equals(env.queryCorner(2))); + assertTrue(corners[3].equals(env.queryCorner(1))); + } + + assertTrue(env.getCenter().equals(Point2D.construct(1, 2))); + assertFalse(env.containsExclusive(env.getUpperLeft())); + assertTrue(env.contains(env.getUpperLeft())); + assertTrue(env.containsExclusive(env.getCenter())); + } + + @Test + public void testReplaceNaNs() { + Envelope env = new Envelope(); + Point pt = new Point(); + pt.setXY(1, 2); + pt.setZ(Double.NaN); + pt.queryEnvelope(env); + pt.replaceNaNs(VertexDescription.Semantics.Z, 5); + assertTrue(pt.equals(new Point(1, 2, 5))); + + assertTrue(env.hasZ()); + assertTrue(env.queryInterval(VertexDescription.Semantics.Z, 0).isEmpty()); + env.replaceNaNs(VertexDescription.Semantics.Z, 5); + assertTrue(env.queryInterval(VertexDescription.Semantics.Z, 0).equals(new Envelope1D(5, 5))); + } + + @Test + public void testTriangleArea() { + Point2D pt = new Point2D(0, 0); + Point2D pt2 = new Point2D(2, 2); + Point2D pt1 = new Point2D(0, 2); + double area = pt.calculateTriangleArea2D(pt1, pt2); + assertEquals(2.0, area); + double area2 = pt.calculateTriangleArea2D(pt2, pt1); + assertEquals(area, area2); + } + + @Test + public void testCircleCenter() { + Point2D pt = new Point2D(-2, -2); + Point2D pt2 = new Point2D(2, 2); + Point2D pt1 = new Point2D(-2, 2); + Point2D center = Point2D.calculateCircleCenterFromThreePoints(pt, pt2, pt1); + assertEquals(center.x, 0.0); + assertEquals(center.y, 0.0); + + center = Point2D.calculateCircleCenterFromThreePoints(pt1, pt, pt2); + assertEquals(center.x, 0.0); + assertEquals(center.y, 0.0); + + center = Point2D.calculateCircleCenterFromThreePoints(pt2, pt, pt1); + assertEquals(center.x, 0.0); + assertEquals(center.y, 0.0); + + center = Point2D.calculateCircleCenterFromThreePoints(pt1, pt2, pt); + assertEquals(center.x, 0.0); + assertEquals(center.y, 0.0); + } } diff --git a/src/test/java/com/esri/core/geometry/TestPolygon.java b/src/test/java/com/esri/core/geometry/TestPolygon.java index e5633a13..4256e79e 100644 --- a/src/test/java/com/esri/core/geometry/TestPolygon.java +++ b/src/test/java/com/esri/core/geometry/TestPolygon.java @@ -28,1301 +28,1301 @@ import org.junit.Test; public class TestPolygon extends TestCase { - @Override - protected void setUp() throws Exception { - super.setUp(); - } - - @Override - protected void tearDown() throws Exception { - super.tearDown(); - } - - @Test - public void testCreation() { - // simple create - - Polygon poly = new Polygon(); - @SuppressWarnings("unused") - int number = poly.getStateFlag(); - - assertTrue(poly != null); - // assertTrue(poly.getClass() == Polygon.class); - // assertFalse(poly.getClass() == Envelope.class); - - assertTrue(poly.getType() == Geometry.Type.Polygon); - assertTrue(poly.isEmpty()); - assertTrue(poly.getPointCount() == 0); - assertTrue(poly.getPathCount() == 0); - number = poly.getStateFlag(); - poly = null; - assertFalse(poly != null); - - // play with default attributes - @SuppressWarnings("unused") - Polygon poly2 = new Polygon(); - // SimpleTest(poly2); - - // creation1(); - // creation2(); - // addpath(); - // addpath2(); - // removepath(); - // reversepath(); - // reverseallpaths(); - // openallpaths(); - // openpath(); - // insertpath(); - // insertpoints(); - // insertpoint(); - // removepoint(); - // insertpointsfromaray(); - // createWithStreams(); - // testBug1(); - } - - @Test - public void testCreation1() { - // Simple area and length calcul test - Polygon poly = new Polygon(); - @SuppressWarnings("unused") - int number = poly.getStateFlag(); - Envelope env = new Envelope(1000, 2000, 1010, 2010); - env.toString(); - poly.addEnvelope(env, false); - poly.toString(); - number = poly.getStateFlag(); - assertTrue(Math.abs(poly.calculateArea2D() - 100) < 1e-12); - assertTrue(Math.abs(poly.calculateLength2D() - 40) < 1e-12); - poly.setEmpty(); - number = poly.getStateFlag(); - poly.addEnvelope(env, true); - number = poly.getStateFlag(); - assertTrue(Math.abs(poly.calculateArea2D() + 100) < 1e-12); - number = poly.getStateFlag(); - } - - @Test - public void testCreation2() { - Polygon poly = new Polygon(); - int state1 = poly.getStateFlag(); - poly.startPath(10, 1); - poly.lineTo(15, 20); - poly.lineTo(30, 14); - poly.lineTo(60, 144); - poly.closePathWithLine(); - int state2 = poly.getStateFlag(); - assertTrue(state2 == state1 + 1); - - // MultiPathImpl::Pointer mpImpl = - // (MultiPathImpl::Pointer)poly->_GetImpl(); - // - // assertTrue(mpImpl.getPointCount() == 4); - // assertTrue(mpImpl.getPathCount() == 1); - // AttributeStreamBase xy = - // mpImpl.getAttributeStreamRef(enum_value2(VertexDescription, - // Semantics, POSITION)); - // double x, y; - // x = xy.readAsDbl(2 * 2); - // y = xy.readAsDbl(2 * 2 + 1); - // assertTrue(x == 30); assertTrue(y == 14); - // - // AttributeStreamOfIndexType parts = mpImpl.getPathStreamRef(); - // assertTrue(parts.size() == 2); - // assertTrue(parts.read(0) == 0); - // assertTrue(parts.read(1) == 4); - // assertTrue(mpImpl.isClosedPath(0)); - // assertTrue(mpImpl.getSegmentFlagsStreamRef() == NULLPTR); - // assertTrue(mpImpl.getSegmentIndexStreamRef() == NULLPTR); - // assertTrue(mpImpl.getSegmentDataStreamRef() == NULLPTR); - - poly.startPath(20, 13); - poly.lineTo(150, 120); - poly.lineTo(300, 414); - poly.lineTo(610, 14); - poly.lineTo(6210, 140); - poly.closePathWithLine(); - - // assertTrue(mpImpl.getPointCount() == 9); - // assertTrue(mpImpl.getPathCount() == 2); - // assertTrue(mpImpl.isClosedPath(1)); - // xy = mpImpl.getAttributeStreamRef(enum_value2(VertexDescription, - // Semantics, POSITION)); - // x = xy.readAsDbl(2 * 3); - // y = xy.readAsDbl(2 * 3 + 1); - // assertTrue(x == 60); assertTrue(y == 144); - // - // x = xy.readAsDbl(2 * 6); - // y = xy.readAsDbl(2 * 6 + 1); - // assertTrue(x == 300); assertTrue(y == 414); - - // parts = mpImpl.getPathStreamRef(); - // assertTrue(parts.size() == 3); - // assertTrue(parts.read(0) == 0); - // assertTrue(parts.read(1) == 4); - // assertTrue(parts.read(2) == 9); - // assertTrue(mpImpl.getSegmentIndexStreamRef() == NULLPTR); - // assertTrue(mpImpl.getSegmentFlagsStreamRef() == NULLPTR); - // assertTrue(mpImpl.getSegmentDataStreamRef() == NULLPTR); - - poly.startPath(200, 1333); - poly.lineTo(1150, 1120); - poly.lineTo(300, 4114); - poly.lineTo(6110, 114); - poly.lineTo(61210, 1140); - - assertTrue(poly.isClosedPath(2) == true); - poly.closeAllPaths(); - assertTrue(poly.isClosedPath(2) == true); - - { - Polygon poly2 = new Polygon(); - poly2.startPath(10, 10); - poly2.lineTo(100, 10); - poly2.lineTo(100, 100); - poly2.lineTo(10, 100); - } - - { - Polygon poly3 = new Polygon(); - // create a star (non-simple) - poly3.startPath(1, 0); - poly3.lineTo(5, 10); - poly3.lineTo(9, 0); - poly3.lineTo(0, 6); - poly3.lineTo(10, 6); - } - } - - @Test - public void testCreateWithStreams() { - // Polygon poly = new Polygon(); - // poly.addAttribute((int)Semantics.M); - // try - // { - // OutputDebugString(L"Test an assert\n"); - // GeometryException::m_assertOnException = false; - // ((MultiPathImpl::Pointer)poly->_GetImpl()).getPathStreamRef(); - // } - // catch(GeometryException except) - // { - // assertTrue(except->empty_geometry); - // GeometryException::m_assertOnException = true; - // } - // try - // { - // OutputDebugString(L"Test an assert\n"); - // GeometryException::m_assertOnException = false; - // ((MultiPathImpl::Pointer)poly->_GetImpl()).getAttributeStreamRef(enum_value2(VertexDescription, - // Semantics, POSITION)); - // } - // catch(GeometryException except) - // { - // assertTrue(except->empty_geometry); - // GeometryException::m_assertOnException = true; - // } - // - // MultiPathImpl::Pointer mpImpl = - // (MultiPathImpl::Pointer)poly->_GetImpl(); - // - // AttributeStreamOfIndexType parts = - // (AttributeStreamOfIndexType)AttributeStreamBase::CreateIndexStream(3); - // mpImpl.setPathStreamRef(parts); - // - // parts.write(0, 0); //first element is always 0 - // parts.write(1, 4); //second element is the index of the first vertex - // of the second part - // parts.write(2, 8); //the third element is the total point count. - // - // AttributeStreamOfInt8 flags = - // (AttributeStreamOfInt8)AttributeStreamBase::CreateByteStream(3); - // mpImpl.setPathFlagsStreamRef(flags); - // flags.write(0, enum_value1(PathFlags, enumClosed)); - // flags.write(1, enum_value1(PathFlags, enumClosed)); - // flags.write(2, 0); - // - // AttributeStreamOfDbl xy = - // (AttributeStreamOfDbl)AttributeStreamBase::CreateDoubleStream(16); - // //16 doubles means 8 points - // mpImpl.setAttributeStreamRef(enum_value2(VertexDescription, - // Semantics, POSITION), xy); - // - // Envelope2D env; - // env.SetCoords(-1000, -2000, 1000, 2000); - // Point2D buf[4]; - // env.QueryCorners(buf); - // xy.writeRange(0, 8, (double*)buf, 0, true); - // - // env.SetCoords(-100, -200, 100, 200); - // env.QueryCornersReversed(buf); //make a hole by quering reversed - // order - // xy.writeRange(8, 8, (double*)buf, 0, true); - // - // mpImpl.notifyModified(MultiVertexGeometryImpl::DirtyAll); //notify - // the path that the vertices had changed. - // - // assertTrue(poly.getPointCount() == 8); - // assertTrue(poly.getPathCount() == 2); - // assertTrue(poly.getPathSize(1) == 4); - // assertTrue(poly.isClosedPath(0)); - // assertTrue(poly.isClosedPath(1)); - } - - @Test - public void testCloneStuff() { - Polygon poly = new Polygon(); - poly.startPath(10, 1); - poly.lineTo(15, 20); - poly.lineTo(30, 14); - poly.lineTo(60, 144); - - poly.startPath(10, 1); - poly.lineTo(15, 20); - poly.lineTo(300, 14); - poly.lineTo(60, 144); - - poly.startPath(10, 1); - poly.lineTo(125, 20); - poly.lineTo(30, 14); - poly.lineTo(600, 144); - poly.closePathWithLine(); - - Polygon clone = (Polygon) poly.copy(); - assertTrue(clone.getPathCount() == 3); - assertTrue(clone.getPathStart(2) == 8); - assertTrue(clone.isClosedPath(0)); - assertTrue(clone.isClosedPath(1)); - assertTrue(clone.isClosedPath(2)); - assertTrue(clone.getXY(5).isEqual(new Point2D(15, 20))); - } - - @Test - public void testCloneStuffEnvelope() { - Envelope env = new Envelope(11, 12, 15, 24); - Envelope eCopy = (Envelope) env.copy(); - assertTrue(eCopy.equals(env)); - assertTrue(eCopy.getXMin() == 11); - assertTrue(eCopy.getYMin() == 12); - assertTrue(eCopy.getXMax() == 15); - assertTrue(eCopy.getYMax() == 24); - } - - @Test - public void testCloneStuffPolyline() { - Polyline poly = new Polyline(); - poly.startPath(10, 1); - poly.lineTo(15, 20); - poly.lineTo(30, 14); - poly.lineTo(60, 144); - - poly.startPath(10, 1); - poly.lineTo(15, 20); - poly.lineTo(300, 14); - poly.lineTo(60, 144); - - poly.startPath(10, 1); - poly.lineTo(125, 20); - poly.lineTo(30, 14); - poly.lineTo(600, 144); - poly.closePathWithLine(); - - Polyline clone = (Polyline) poly.copy(); - assertTrue(clone.getPathCount() == 3); - assertTrue(clone.getPathStart(2) == 8); - assertTrue(!clone.isClosedPath(0)); - assertTrue(!clone.isClosedPath(1)); - assertTrue(clone.isClosedPath(2)); - assertTrue(clone.getXY(5).isEqual(new Point2D(15, 20))); - } - - @Test - public void testAddpath() { - Polygon poly = new Polygon(); - poly.startPath(10, 1); - poly.lineTo(15, 20); - poly.lineTo(30, 14); - poly.lineTo(60, 144); - - poly.startPath(10, 1); - poly.lineTo(15, 20); - poly.lineTo(300, 14); - poly.lineTo(60, 144); - - poly.startPath(10, 1); - poly.lineTo(125, 20); - poly.lineTo(30, 14); - poly.lineTo(600, 144); - - Polygon poly1 = new Polygon(); - poly1.addPath(poly, 2, true); - poly1.addPath(poly, 0, true); - - assertTrue(poly1.getPathCount() == 2); - assertTrue(poly1.getPathStart(1) == 4); - assertTrue(poly1.isClosedPath(0)); - assertTrue(poly1.isClosedPath(1)); - Point ptOut = poly1.getPoint(6); - assertTrue(ptOut.getX() == 30 && ptOut.getY() == 14); - } - - @Test - public void testAddpath2() { - Polygon polygon = new Polygon(); - polygon.startPath(-179, 34); - polygon.lineTo(-154, 34); - polygon.lineTo(-179, 36); - polygon.lineTo(-180, 90); - polygon.lineTo(180, 90); - polygon.lineTo(180, 36); - polygon.lineTo(70, 46); - polygon.lineTo(-76, 80); - polygon.lineTo(12, 38); - polygon.lineTo(-69, 51); - polygon.lineTo(-95, 29); - polygon.lineTo(-105, 7); - polygon.lineTo(-112, -27); - polygon.lineTo(-149, -11); - polygon.lineTo(-149, -11); - polygon.lineTo(-166, -4); - polygon.lineTo(-179, 5); - - Polyline polyline = new Polyline(); - polyline.startPath(180, 5); - polyline.lineTo(140, 34); - polyline.lineTo(180, 34); - - polygon.addPath(polyline, 0, true); - - Point startpoint = polygon.getPoint(17); - assertTrue(startpoint.getX() == 180 && startpoint.getY() == 5); - } - - @Test - public void testRemovepath() { - Polygon poly = new Polygon(); - poly.startPath(10, 1); - poly.lineTo(15, 20); - poly.lineTo(30, 14); - poly.lineTo(60, 144); - - poly.startPath(10, 1); - poly.lineTo(15, 20); - poly.lineTo(300, 14); - poly.lineTo(60, 144); - - poly.startPath(10, 1); - poly.lineTo(125, 20); - poly.lineTo(30, 14); - poly.lineTo(600, 144); - - // poly->SetAttribute(enum_value2(VertexDescription, Semantics, Z), 0, - // 0, 2); - // poly->SetAttribute(enum_value2(VertexDescription, Semantics, Z), 1, - // 0, 3); - // poly->SetAttribute(enum_value2(VertexDescription, Semantics, Z), 2, - // 0, 5); - // poly->SetAttribute(enum_value2(VertexDescription, Semantics, Z), 3, - // 0, 7); - // poly->SetAttribute(enum_value2(VertexDescription, Semantics, Z), 4, - // 0, 11); - // poly->SetAttribute(enum_value2(VertexDescription, Semantics, Z), 5, - // 0, 13); - // poly->SetAttribute(enum_value2(VertexDescription, Semantics, Z), 6, - // 0, 17); - // poly->SetAttribute(enum_value2(VertexDescription, Semantics, Z), 7, - // 0, 19); - // poly->SetAttribute(enum_value2(VertexDescription, Semantics, Z), 8, - // 0, 23); - // poly->SetAttribute(enum_value2(VertexDescription, Semantics, Z), 9, - // 0, 29); - // poly->SetAttribute(enum_value2(VertexDescription, Semantics, Z), 10, - // 0, 31); - // poly->SetAttribute(enum_value2(VertexDescription, Semantics, Z), 11, - // 0, 37); - - poly.removePath(1); - - assertTrue(poly.getPathCount() == 2); - assertTrue(poly.getPathStart(1) == 4); - assertTrue(poly.isClosedPath(0)); - assertTrue(poly.isClosedPath(1)); - Point ptOut = poly.getPoint(4); - assertTrue(ptOut.getX() == 10 && ptOut.getY() == 1); - poly.removePath(0); - poly.removePath(0); - assertTrue(poly.getPathCount() == 0); - - Polygon poly2 = new Polygon(); - poly2.startPath(0, 0); - poly2.lineTo(0, 10); - poly2.lineTo(10, 10); - poly2.startPath(1, 1); - poly2.lineTo(2, 2); - poly2.removePath(0); - // poly2->StartPath(0, 0); - poly2.lineTo(0, 10); - poly2.lineTo(10, 10); - - // Polygon polygon2 = new Polygon(); - // polygon2.addPath(poly, -1, true); - // polygon2.addPath(poly, -1, true); - // polygon2.addPath(poly, -1, true); - // assertTrue(polygon2.getPathCount() == 3); - // polygon2.removePath(0); - // polygon2.removePath(0); - // polygon2.removePath(0); - // assertTrue(polygon2.getPathCount() == 0); - // polygon2.addPath(poly, -1, true); - - // Point point1 = new Point(); - // Point point2 = new Point(); - // point1.setX(0); - // point1.setY(0); - // point2.setX(0); - // point2.setY(0); - // polygon2.addPath(poly2, 0, true); - // polygon2.removePath(0); - // polygon2.insertPoint(0, 0, point1); - // polygon2.insertPoint(0, 0, point2); - // assertTrue(polygon2.getPathCount() == 1); - // assertTrue(polygon2.getPointCount() == 2); - - Polygon polygon3 = new Polygon(); - polygon3.startPath(0, 0); - polygon3.lineTo(0, 10); - polygon3.lineTo(10, 10); - double area = polygon3.calculateArea2D(); - polygon3.removePath(0); - - polygon3.startPath(0, 0); - polygon3.lineTo(0, 10); - polygon3.lineTo(10, 10); - area = polygon3.calculateArea2D(); - assertTrue(area > 0.0); - } - - @Test - public void testReversepath() { - Polygon poly = new Polygon(); - poly.startPath(10, 1); - poly.lineTo(15, 20); - poly.lineTo(30, 14); - poly.lineTo(60, 144); - - poly.startPath(10, 1); - poly.lineTo(15, 20); - poly.lineTo(300, 14); - poly.lineTo(60, 144); - - poly.startPath(10, 1); - poly.lineTo(125, 20); - poly.lineTo(30, 14); - poly.lineTo(600, 144); - - // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 0, 0, - // 2); - // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 1, 0, - // 3); - // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 2, 0, - // 5); - // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 3, 0, - // 7); - // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 4, 0, - // 11); - // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 5, 0, - // 13); - // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 6, 0, - // 17); - // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 7, 0, - // 19); - // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 8, 0, - // 23); - // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 9, 0, - // 29); - // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 10, - // 0, 31); - // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 11, - // 0, 37); - - poly.reversePath(1); - - assertTrue(poly.getPathCount() == 3); - assertTrue(poly.getPathStart(1) == 4); - assertTrue(poly.isClosedPath(0)); - assertTrue(poly.isClosedPath(1)); - Point ptOut = poly.getPoint(4); - assertTrue(ptOut.getX() == 10 && ptOut.getY() == 1); - } - - @Test - public void testReverseAllPaths() { - Polygon poly = new Polygon(); - poly.startPath(10, 1); - poly.lineTo(15, 20); - poly.lineTo(30, 14); - poly.lineTo(60, 144); - - poly.startPath(10, 1); - poly.lineTo(15, 20); - poly.lineTo(300, 14); - poly.lineTo(60, 144); - - poly.startPath(10, 1); - poly.lineTo(125, 20); - poly.lineTo(30, 14); - poly.lineTo(600, 144); - - // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 0, 0, - // 2); - // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 1, 0, - // 3); - // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 2, 0, - // 5); - // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 3, 0, - // 7); - // - // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 4, 0, - // 11); - // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 5, 0, - // 13); - // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 6, 0, - // 17); - // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 7, 0, - // 19); - // - // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 8, 0, - // 23); - // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 9, 0, - // 29); - // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 10, - // 0, 31); - // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 11, - // 0, 37); - - double area = poly.calculateArea2D(); - poly.reverseAllPaths(); - double areaReversed = poly.calculateArea2D(); - assertTrue(Math.abs(area + areaReversed) <= 0.001); - } - - @Test - public void testOpenAllPaths() { - Polyline poly = new Polyline(); - poly.startPath(10, 1); - poly.lineTo(15, 20); - poly.lineTo(30, 14); - poly.lineTo(60, 144); - poly.closePathWithLine(); - - poly.startPath(10, 1); - poly.lineTo(15, 20); - poly.lineTo(300, 14); - poly.lineTo(60, 144); - poly.closePathWithLine(); - - poly.startPath(10, 1); - poly.lineTo(125, 20); - poly.lineTo(30, 14); - poly.lineTo(600, 144); - poly.closePathWithLine(); - - // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 0, 0, - // 2); - // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 1, 0, - // 3); - // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 2, 0, - // 5); - // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 3, 0, - // 7); - // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 4, 0, - // 11); - // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 5, 0, - // 13); - // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 6, 0, - // 17); - // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 7, 0, - // 19); - // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 8, 0, - // 23); - // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 9, 0, - // 29); - // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 10, - // 0, 31); - // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 11, - // 0, 37); - - // MultiPathImpl::Pointer mpImpl = - // (MultiPathImpl::Pointer)poly->_GetImpl(); - // poly.openAllPathsAndDuplicateStartVertex(); - - // assertTrue(poly.getPathCount() == 3); - // assertTrue(poly.getPathStart(0) == 0); - // assertTrue(poly.getPathStart(1) == 5); - // assertTrue(poly.getPathStart(2) == 10); - // assertTrue(poly.getPointCount() == 15); - // Point ptstart = poly.getPoint(0); - // Point ptend = poly.getPoint(4); - // assertTrue(ptstart.getX() == ptend.getX() && ptstart.getY() == - // ptend.getY()); - // ptstart = poly.getPoint(5); - // ptend = poly.getPoint(9); - // assertTrue(ptstart.getX() == ptend.getX() && ptstart.getY() == - // ptend.getY()); - // ptstart = poly.getPoint(10); - // ptend = poly.getPoint(14); - // assertTrue(ptstart.getX() == ptend.getX() && ptstart.getY() == - // ptend.getY()); - } - - @Test - public void testOpenPath() { - Polyline poly = new Polyline(); - poly.startPath(10, 1); - poly.lineTo(15, 20); - poly.lineTo(30, 14); - poly.lineTo(60, 144); - poly.closePathWithLine(); - - poly.startPath(10, 1); - poly.lineTo(15, 20); - poly.lineTo(300, 14); - poly.lineTo(60, 144); - poly.closePathWithLine(); - - poly.startPath(10, 1); - poly.lineTo(125, 20); - poly.lineTo(30, 14); - poly.lineTo(600, 144); - poly.closePathWithLine(); - - // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 0, 0, - // 2); - // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 1, 0, - // 3); - // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 2, 0, - // 5); - // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 3, 0, - // 7); - // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 4, 0, - // 11); - // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 5, 0, - // 13); - // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 6, 0, - // 17); - // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 7, 0, - // 19); - // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 8, 0, - // 23); - // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 9, 0, - // 29); - // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 10, - // 0, 31); - // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 11, - // 0, 37); - // - // MultiPathImpl::Pointer mpImpl = - // (MultiPathImpl::Pointer)poly->_GetImpl(); - // poly.openPathAndDuplicateStartVertex(1); - - // assertTrue(poly.getPathCount() == 3); - // assertTrue(poly.getPathStart(0) == 0); - // assertTrue(poly.getPathStart(1) == 4); - // assertTrue(poly.getPathStart(2) == 9); - // assertTrue(poly.getPointCount() == 13); - // Point ptstart = poly.getPoint(4); - // Point ptend = poly.getPoint(8); - // assertTrue(ptstart.getX() == ptend.getX() && ptstart.getY() == - // ptend.getY()); - // ptstart = poly.getPoint(9); - // assertTrue(ptstart.getX() == 10 && ptstart.getY() == 1); - } - - @Test - public void testInsertPath() { - Polygon poly = new Polygon(); - poly.startPath(10, 1); - poly.lineTo(15, 20); - poly.lineTo(30, 14); - poly.lineTo(60, 144); - - poly.startPath(12, 2); - poly.lineTo(16, 21); - poly.lineTo(301, 15); - poly.lineTo(61, 145); - - poly.startPath(13, 3); - poly.lineTo(126, 22); - poly.lineTo(31, 16); - poly.lineTo(601, 146); - - // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 0, 0, - // 2); - // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 1, 0, - // 3); - // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 2, 0, - // 5); - // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 3, 0, - // 7); - // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 4, 0, - // 11); - // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 5, 0, - // 13); - // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 6, 0, - // 17); - // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 7, 0, - // 19); - // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 8, 0, - // 23); - // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 9, 0, - // 29); - // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 10, - // 0, 31); - // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 11, - // 0, 37); - - Polygon poly2 = new Polygon(); - poly2.startPath(12, 2); - poly2.lineTo(16, 21); - poly2.lineTo(301, 15); - poly2.lineTo(61, 145); - - poly.insertPath(0, poly2, 0, false); - - assertTrue(poly.getPathCount() == 4); - assertTrue(poly.getPathStart(0) == 0); - assertTrue(poly.getPathStart(1) == 4); - assertTrue(poly.getPathStart(2) == 8); - assertTrue(poly.getPathStart(3) == 12); - assertTrue(poly.getPointCount() == 16); - - Point2D pt0 = poly.getXY(0); - assertTrue(pt0.x == 12 && pt0.y == 2); - Point2D pt1 = poly.getXY(1); - assertTrue(pt1.x == 61 && pt1.y == 145); - Point2D pt2 = poly.getXY(2); - assertTrue(pt2.x == 301 && pt2.y == 15); - Point2D pt3 = poly.getXY(3); - assertTrue(pt3.x == 16 && pt3.y == 21); - - Point pt2d = new Point(-27, -27); - - poly.insertPoint(1, 0, pt2d); - assertTrue(poly.getPathCount() == 4); - assertTrue(poly.getPathStart(0) == 0); - assertTrue(poly.getPathStart(1) == 4); - assertTrue(poly.getPathStart(2) == 9); - assertTrue(poly.getPathStart(3) == 13); - assertTrue(poly.getPointCount() == 17); - } - - @Test - public void testInsertPoints() { - {// forward insertion - Polygon poly = new Polygon(); - poly.startPath(10, 1); - poly.lineTo(15, 20); - poly.lineTo(30, 14); - poly.lineTo(60, 144); - - poly.startPath(10, 1); - poly.lineTo(15, 20); - poly.lineTo(300, 14); - poly.lineTo(314, 217); - poly.lineTo(60, 144); - - poly.startPath(10, 1); - poly.lineTo(125, 20); - poly.lineTo(30, 14); - poly.lineTo(600, 144); - - Polygon poly1 = new Polygon(); - poly1.startPath(1, 17); - poly1.lineTo(1, 207); - poly1.lineTo(3, 147); - poly1.lineTo(6, 1447); - - poly1.startPath(1000, 17); - poly1.lineTo(1250, 207); - poly1.lineTo(300, 147); - poly1.lineTo(6000, 1447); - - poly1.insertPoints(1, 2, poly, 1, 1, 3, true);// forward - - assertTrue(poly1.getPathCount() == 2); - assertTrue(poly1.getPathStart(1) == 4); - assertTrue(poly1.isClosedPath(0)); - assertTrue(poly1.isClosedPath(1)); - assertTrue(poly1.getPointCount() == 11); - assertTrue(poly1.getPathSize(1) == 7); - // Point2D ptOut; - // ptOut = poly1.getXY(5); - // assertTrue(ptOut.x == 1250 && ptOut.y == 207); - // ptOut = poly1.getXY(6); - // assertTrue(ptOut.x == 15 && ptOut.y == 20); - // ptOut = poly1.getXY(7); - // assertTrue(ptOut.x == 300 && ptOut.y == 14); - // ptOut = poly1.getXY(8); - // assertTrue(ptOut.x == 314 && ptOut.y == 217); - // ptOut = poly1.getXY(9); - // assertTrue(ptOut.x == 300 && ptOut.y == 147); - // ptOut = poly1.getXY(10); - // assertTrue(ptOut.x == 6000 && ptOut.y == 1447); - } - - {// reverse insertion - Polygon poly = new Polygon(); - poly.startPath(10, 1); - poly.lineTo(15, 20); - poly.lineTo(30, 14); - poly.lineTo(60, 144); - - poly.startPath(10, 1); - poly.lineTo(15, 20); - poly.lineTo(300, 14); - poly.lineTo(314, 217); - poly.lineTo(60, 144); - - poly.startPath(10, 1); - poly.lineTo(125, 20); - poly.lineTo(30, 14); - poly.lineTo(600, 144); - - Polygon poly1 = new Polygon(); - poly1.startPath(1, 17); - poly1.lineTo(1, 207); - poly1.lineTo(3, 147); - poly1.lineTo(6, 1447); - - poly1.startPath(1000, 17); - poly1.lineTo(1250, 207); - poly1.lineTo(300, 147); - poly1.lineTo(6000, 1447); - - poly1.insertPoints(1, 2, poly, 1, 1, 3, false);// reverse - - assertTrue(poly1.getPathCount() == 2); - assertTrue(poly1.getPathStart(1) == 4); - assertTrue(poly1.isClosedPath(0)); - assertTrue(poly1.isClosedPath(1)); - assertTrue(poly1.getPointCount() == 11); - assertTrue(poly1.getPathSize(1) == 7); - // Point2D ptOut; - // ptOut = poly1.getXY(5); - // assertTrue(ptOut.x == 1250 && ptOut.y == 207); - // ptOut = poly1.getXY(6); - // assertTrue(ptOut.x == 314 && ptOut.y == 217); - // ptOut = poly1.getXY(7); - // assertTrue(ptOut.x == 300 && ptOut.y == 14); - // ptOut = poly1.getXY(8); - // assertTrue(ptOut.x == 15 && ptOut.y == 20); - // ptOut = poly1.getXY(9); - // assertTrue(ptOut.x == 300 && ptOut.y == 147); - // ptOut = poly1.getXY(10); - // assertTrue(ptOut.x == 6000 && ptOut.y == 1447); - } - } - - @Test - public void testInsertPoint() { - Polygon poly = new Polygon(); - poly.startPath(10, 1); - poly.lineTo(15, 20); - poly.lineTo(30, 14); - poly.lineTo(60, 144); - - poly.startPath(10, 1); - poly.lineTo(15, 20); - poly.lineTo(300, 14); - poly.lineTo(314, 217); - poly.lineTo(60, 144); - - poly.startPath(10, 1); - poly.lineTo(125, 20); - poly.lineTo(30, 14); - poly.lineTo(600, 144); - - Point pt = new Point(-33, -34); - poly.insertPoint(1, 1, pt); - - pt = poly.getPoint(4); - assertTrue(pt.getX() == 10 && pt.getY() == 1); - pt = poly.getPoint(5); - assertTrue(pt.getX() == -33 && pt.getY() == -34); - pt = poly.getPoint(6); - assertTrue(pt.getX() == 15 && pt.getY() == 20); - - assertTrue(poly.getPointCount() == 14); - assertTrue(poly.getPathSize(1) == 6); - assertTrue(poly.getPathSize(2) == 4); - assertTrue(poly.getPathCount() == 3); - } - - @Test - public void testRemovePoint() { - Polygon poly = new Polygon(); - poly.startPath(10, 1); - poly.lineTo(15, 20); - poly.lineTo(30, 14); - poly.lineTo(60, 144); - - poly.startPath(10, 1); - poly.lineTo(15, 20); - poly.lineTo(300, 14); - poly.lineTo(314, 217); - poly.lineTo(60, 144); - - poly.startPath(10, 1); - poly.lineTo(125, 20); - poly.lineTo(30, 14); - poly.lineTo(600, 144); - - poly.removePoint(1, 1); - - Point pt; - - pt = poly.getPoint(4); - assertTrue(pt.getX() == 10 && pt.getY() == 1); - pt = poly.getPoint(5); - assertTrue(pt.getX() == 300 && pt.getY() == 14); - - assertTrue(poly.getPointCount() == 12); - assertTrue(poly.getPathSize(0) == 4); - assertTrue(poly.getPathSize(1) == 4); - assertTrue(poly.getPathSize(2) == 4); - } - - @Test - public static void testPolygonAreaAndLength() { - Polygon poly; + @Override + protected void setUp() throws Exception { + super.setUp(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + } + + @Test + public void testCreation() { + // simple create + + Polygon poly = new Polygon(); + @SuppressWarnings("unused") + int number = poly.getStateFlag(); + + assertTrue(poly != null); + // assertTrue(poly.getClass() == Polygon.class); + // assertFalse(poly.getClass() == Envelope.class); + + assertTrue(poly.getType() == Geometry.Type.Polygon); + assertTrue(poly.isEmpty()); + assertTrue(poly.getPointCount() == 0); + assertTrue(poly.getPathCount() == 0); + number = poly.getStateFlag(); + poly = null; + assertFalse(poly != null); + + // play with default attributes + @SuppressWarnings("unused") + Polygon poly2 = new Polygon(); + // SimpleTest(poly2); + + // creation1(); + // creation2(); + // addpath(); + // addpath2(); + // removepath(); + // reversepath(); + // reverseallpaths(); + // openallpaths(); + // openpath(); + // insertpath(); + // insertpoints(); + // insertpoint(); + // removepoint(); + // insertpointsfromaray(); + // createWithStreams(); + // testBug1(); + } + + @Test + public void testCreation1() { + // Simple area and length calcul test + Polygon poly = new Polygon(); + @SuppressWarnings("unused") + int number = poly.getStateFlag(); + Envelope env = new Envelope(1000, 2000, 1010, 2010); + env.toString(); + poly.addEnvelope(env, false); + poly.toString(); + number = poly.getStateFlag(); + assertTrue(Math.abs(poly.calculateArea2D() - 100) < 1e-12); + assertTrue(Math.abs(poly.calculateLength2D() - 40) < 1e-12); + poly.setEmpty(); + number = poly.getStateFlag(); + poly.addEnvelope(env, true); + number = poly.getStateFlag(); + assertTrue(Math.abs(poly.calculateArea2D() + 100) < 1e-12); + number = poly.getStateFlag(); + } + + @Test + public void testCreation2() { + Polygon poly = new Polygon(); + int state1 = poly.getStateFlag(); + poly.startPath(10, 1); + poly.lineTo(15, 20); + poly.lineTo(30, 14); + poly.lineTo(60, 144); + poly.closePathWithLine(); + int state2 = poly.getStateFlag(); + assertTrue(state2 == state1 + 1); + + // MultiPathImpl::Pointer mpImpl = + // (MultiPathImpl::Pointer)poly->_GetImpl(); + // + // assertTrue(mpImpl.getPointCount() == 4); + // assertTrue(mpImpl.getPathCount() == 1); + // AttributeStreamBase xy = + // mpImpl.getAttributeStreamRef(enum_value2(VertexDescription, + // Semantics, POSITION)); + // double x, y; + // x = xy.readAsDbl(2 * 2); + // y = xy.readAsDbl(2 * 2 + 1); + // assertTrue(x == 30); assertTrue(y == 14); + // + // AttributeStreamOfIndexType parts = mpImpl.getPathStreamRef(); + // assertTrue(parts.size() == 2); + // assertTrue(parts.read(0) == 0); + // assertTrue(parts.read(1) == 4); + // assertTrue(mpImpl.isClosedPath(0)); + // assertTrue(mpImpl.getSegmentFlagsStreamRef() == NULLPTR); + // assertTrue(mpImpl.getSegmentIndexStreamRef() == NULLPTR); + // assertTrue(mpImpl.getSegmentDataStreamRef() == NULLPTR); + + poly.startPath(20, 13); + poly.lineTo(150, 120); + poly.lineTo(300, 414); + poly.lineTo(610, 14); + poly.lineTo(6210, 140); + poly.closePathWithLine(); + + // assertTrue(mpImpl.getPointCount() == 9); + // assertTrue(mpImpl.getPathCount() == 2); + // assertTrue(mpImpl.isClosedPath(1)); + // xy = mpImpl.getAttributeStreamRef(enum_value2(VertexDescription, + // Semantics, POSITION)); + // x = xy.readAsDbl(2 * 3); + // y = xy.readAsDbl(2 * 3 + 1); + // assertTrue(x == 60); assertTrue(y == 144); + // + // x = xy.readAsDbl(2 * 6); + // y = xy.readAsDbl(2 * 6 + 1); + // assertTrue(x == 300); assertTrue(y == 414); + + // parts = mpImpl.getPathStreamRef(); + // assertTrue(parts.size() == 3); + // assertTrue(parts.read(0) == 0); + // assertTrue(parts.read(1) == 4); + // assertTrue(parts.read(2) == 9); + // assertTrue(mpImpl.getSegmentIndexStreamRef() == NULLPTR); + // assertTrue(mpImpl.getSegmentFlagsStreamRef() == NULLPTR); + // assertTrue(mpImpl.getSegmentDataStreamRef() == NULLPTR); + + poly.startPath(200, 1333); + poly.lineTo(1150, 1120); + poly.lineTo(300, 4114); + poly.lineTo(6110, 114); + poly.lineTo(61210, 1140); + + assertTrue(poly.isClosedPath(2) == true); + poly.closeAllPaths(); + assertTrue(poly.isClosedPath(2) == true); + + { + Polygon poly2 = new Polygon(); + poly2.startPath(10, 10); + poly2.lineTo(100, 10); + poly2.lineTo(100, 100); + poly2.lineTo(10, 100); + } + + { + Polygon poly3 = new Polygon(); + // create a star (non-simple) + poly3.startPath(1, 0); + poly3.lineTo(5, 10); + poly3.lineTo(9, 0); + poly3.lineTo(0, 6); + poly3.lineTo(10, 6); + } + } + + @Test + public void testCreateWithStreams() { + // Polygon poly = new Polygon(); + // poly.addAttribute((int)Semantics.M); + // try + // { + // OutputDebugString(L"Test an assert\n"); + // GeometryException::m_assertOnException = false; + // ((MultiPathImpl::Pointer)poly->_GetImpl()).getPathStreamRef(); + // } + // catch(GeometryException except) + // { + // assertTrue(except->empty_geometry); + // GeometryException::m_assertOnException = true; + // } + // try + // { + // OutputDebugString(L"Test an assert\n"); + // GeometryException::m_assertOnException = false; + // ((MultiPathImpl::Pointer)poly->_GetImpl()).getAttributeStreamRef(enum_value2(VertexDescription, + // Semantics, POSITION)); + // } + // catch(GeometryException except) + // { + // assertTrue(except->empty_geometry); + // GeometryException::m_assertOnException = true; + // } + // + // MultiPathImpl::Pointer mpImpl = + // (MultiPathImpl::Pointer)poly->_GetImpl(); + // + // AttributeStreamOfIndexType parts = + // (AttributeStreamOfIndexType)AttributeStreamBase::CreateIndexStream(3); + // mpImpl.setPathStreamRef(parts); + // + // parts.write(0, 0); //first element is always 0 + // parts.write(1, 4); //second element is the index of the first vertex + // of the second part + // parts.write(2, 8); //the third element is the total point count. + // + // AttributeStreamOfInt8 flags = + // (AttributeStreamOfInt8)AttributeStreamBase::CreateByteStream(3); + // mpImpl.setPathFlagsStreamRef(flags); + // flags.write(0, enum_value1(PathFlags, enumClosed)); + // flags.write(1, enum_value1(PathFlags, enumClosed)); + // flags.write(2, 0); + // + // AttributeStreamOfDbl xy = + // (AttributeStreamOfDbl)AttributeStreamBase::CreateDoubleStream(16); + // //16 doubles means 8 points + // mpImpl.setAttributeStreamRef(enum_value2(VertexDescription, + // Semantics, POSITION), xy); + // + // Envelope2D env; + // env.SetCoords(-1000, -2000, 1000, 2000); + // Point2D buf[4]; + // env.QueryCorners(buf); + // xy.writeRange(0, 8, (double*)buf, 0, true); + // + // env.SetCoords(-100, -200, 100, 200); + // env.QueryCornersReversed(buf); //make a hole by quering reversed + // order + // xy.writeRange(8, 8, (double*)buf, 0, true); + // + // mpImpl.notifyModified(MultiVertexGeometryImpl::DirtyAll); //notify + // the path that the vertices had changed. + // + // assertTrue(poly.getPointCount() == 8); + // assertTrue(poly.getPathCount() == 2); + // assertTrue(poly.getPathSize(1) == 4); + // assertTrue(poly.isClosedPath(0)); + // assertTrue(poly.isClosedPath(1)); + } + + @Test + public void testCloneStuff() { + Polygon poly = new Polygon(); + poly.startPath(10, 1); + poly.lineTo(15, 20); + poly.lineTo(30, 14); + poly.lineTo(60, 144); + + poly.startPath(10, 1); + poly.lineTo(15, 20); + poly.lineTo(300, 14); + poly.lineTo(60, 144); + + poly.startPath(10, 1); + poly.lineTo(125, 20); + poly.lineTo(30, 14); + poly.lineTo(600, 144); + poly.closePathWithLine(); + + Polygon clone = (Polygon) poly.copy(); + assertTrue(clone.getPathCount() == 3); + assertTrue(clone.getPathStart(2) == 8); + assertTrue(clone.isClosedPath(0)); + assertTrue(clone.isClosedPath(1)); + assertTrue(clone.isClosedPath(2)); + assertTrue(clone.getXY(5).isEqual(new Point2D(15, 20))); + } + + @Test + public void testCloneStuffEnvelope() { + Envelope env = new Envelope(11, 12, 15, 24); + Envelope eCopy = (Envelope) env.copy(); + assertTrue(eCopy.equals(env)); + assertTrue(eCopy.getXMin() == 11); + assertTrue(eCopy.getYMin() == 12); + assertTrue(eCopy.getXMax() == 15); + assertTrue(eCopy.getYMax() == 24); + } + + @Test + public void testCloneStuffPolyline() { + Polyline poly = new Polyline(); + poly.startPath(10, 1); + poly.lineTo(15, 20); + poly.lineTo(30, 14); + poly.lineTo(60, 144); + + poly.startPath(10, 1); + poly.lineTo(15, 20); + poly.lineTo(300, 14); + poly.lineTo(60, 144); + + poly.startPath(10, 1); + poly.lineTo(125, 20); + poly.lineTo(30, 14); + poly.lineTo(600, 144); + poly.closePathWithLine(); + + Polyline clone = (Polyline) poly.copy(); + assertTrue(clone.getPathCount() == 3); + assertTrue(clone.getPathStart(2) == 8); + assertTrue(!clone.isClosedPath(0)); + assertTrue(!clone.isClosedPath(1)); + assertTrue(clone.isClosedPath(2)); + assertTrue(clone.getXY(5).isEqual(new Point2D(15, 20))); + } + + @Test + public void testAddpath() { + Polygon poly = new Polygon(); + poly.startPath(10, 1); + poly.lineTo(15, 20); + poly.lineTo(30, 14); + poly.lineTo(60, 144); + + poly.startPath(10, 1); + poly.lineTo(15, 20); + poly.lineTo(300, 14); + poly.lineTo(60, 144); + + poly.startPath(10, 1); + poly.lineTo(125, 20); + poly.lineTo(30, 14); + poly.lineTo(600, 144); + + Polygon poly1 = new Polygon(); + poly1.addPath(poly, 2, true); + poly1.addPath(poly, 0, true); + + assertTrue(poly1.getPathCount() == 2); + assertTrue(poly1.getPathStart(1) == 4); + assertTrue(poly1.isClosedPath(0)); + assertTrue(poly1.isClosedPath(1)); + Point ptOut = poly1.getPoint(6); + assertTrue(ptOut.getX() == 30 && ptOut.getY() == 14); + } + + @Test + public void testAddpath2() { + Polygon polygon = new Polygon(); + polygon.startPath(-179, 34); + polygon.lineTo(-154, 34); + polygon.lineTo(-179, 36); + polygon.lineTo(-180, 90); + polygon.lineTo(180, 90); + polygon.lineTo(180, 36); + polygon.lineTo(70, 46); + polygon.lineTo(-76, 80); + polygon.lineTo(12, 38); + polygon.lineTo(-69, 51); + polygon.lineTo(-95, 29); + polygon.lineTo(-105, 7); + polygon.lineTo(-112, -27); + polygon.lineTo(-149, -11); + polygon.lineTo(-149, -11); + polygon.lineTo(-166, -4); + polygon.lineTo(-179, 5); + + Polyline polyline = new Polyline(); + polyline.startPath(180, 5); + polyline.lineTo(140, 34); + polyline.lineTo(180, 34); + + polygon.addPath(polyline, 0, true); + + Point startpoint = polygon.getPoint(17); + assertTrue(startpoint.getX() == 180 && startpoint.getY() == 5); + } + + @Test + public void testRemovepath() { + Polygon poly = new Polygon(); + poly.startPath(10, 1); + poly.lineTo(15, 20); + poly.lineTo(30, 14); + poly.lineTo(60, 144); + + poly.startPath(10, 1); + poly.lineTo(15, 20); + poly.lineTo(300, 14); + poly.lineTo(60, 144); + + poly.startPath(10, 1); + poly.lineTo(125, 20); + poly.lineTo(30, 14); + poly.lineTo(600, 144); + + // poly->SetAttribute(enum_value2(VertexDescription, Semantics, Z), 0, + // 0, 2); + // poly->SetAttribute(enum_value2(VertexDescription, Semantics, Z), 1, + // 0, 3); + // poly->SetAttribute(enum_value2(VertexDescription, Semantics, Z), 2, + // 0, 5); + // poly->SetAttribute(enum_value2(VertexDescription, Semantics, Z), 3, + // 0, 7); + // poly->SetAttribute(enum_value2(VertexDescription, Semantics, Z), 4, + // 0, 11); + // poly->SetAttribute(enum_value2(VertexDescription, Semantics, Z), 5, + // 0, 13); + // poly->SetAttribute(enum_value2(VertexDescription, Semantics, Z), 6, + // 0, 17); + // poly->SetAttribute(enum_value2(VertexDescription, Semantics, Z), 7, + // 0, 19); + // poly->SetAttribute(enum_value2(VertexDescription, Semantics, Z), 8, + // 0, 23); + // poly->SetAttribute(enum_value2(VertexDescription, Semantics, Z), 9, + // 0, 29); + // poly->SetAttribute(enum_value2(VertexDescription, Semantics, Z), 10, + // 0, 31); + // poly->SetAttribute(enum_value2(VertexDescription, Semantics, Z), 11, + // 0, 37); + + poly.removePath(1); + + assertTrue(poly.getPathCount() == 2); + assertTrue(poly.getPathStart(1) == 4); + assertTrue(poly.isClosedPath(0)); + assertTrue(poly.isClosedPath(1)); + Point ptOut = poly.getPoint(4); + assertTrue(ptOut.getX() == 10 && ptOut.getY() == 1); + poly.removePath(0); + poly.removePath(0); + assertTrue(poly.getPathCount() == 0); + + Polygon poly2 = new Polygon(); + poly2.startPath(0, 0); + poly2.lineTo(0, 10); + poly2.lineTo(10, 10); + poly2.startPath(1, 1); + poly2.lineTo(2, 2); + poly2.removePath(0); + // poly2->StartPath(0, 0); + poly2.lineTo(0, 10); + poly2.lineTo(10, 10); + + // Polygon polygon2 = new Polygon(); + // polygon2.addPath(poly, -1, true); + // polygon2.addPath(poly, -1, true); + // polygon2.addPath(poly, -1, true); + // assertTrue(polygon2.getPathCount() == 3); + // polygon2.removePath(0); + // polygon2.removePath(0); + // polygon2.removePath(0); + // assertTrue(polygon2.getPathCount() == 0); + // polygon2.addPath(poly, -1, true); + + // Point point1 = new Point(); + // Point point2 = new Point(); + // point1.setX(0); + // point1.setY(0); + // point2.setX(0); + // point2.setY(0); + // polygon2.addPath(poly2, 0, true); + // polygon2.removePath(0); + // polygon2.insertPoint(0, 0, point1); + // polygon2.insertPoint(0, 0, point2); + // assertTrue(polygon2.getPathCount() == 1); + // assertTrue(polygon2.getPointCount() == 2); + + Polygon polygon3 = new Polygon(); + polygon3.startPath(0, 0); + polygon3.lineTo(0, 10); + polygon3.lineTo(10, 10); + double area = polygon3.calculateArea2D(); + polygon3.removePath(0); + + polygon3.startPath(0, 0); + polygon3.lineTo(0, 10); + polygon3.lineTo(10, 10); + area = polygon3.calculateArea2D(); + assertTrue(area > 0.0); + } + + @Test + public void testReversepath() { + Polygon poly = new Polygon(); + poly.startPath(10, 1); + poly.lineTo(15, 20); + poly.lineTo(30, 14); + poly.lineTo(60, 144); + + poly.startPath(10, 1); + poly.lineTo(15, 20); + poly.lineTo(300, 14); + poly.lineTo(60, 144); + + poly.startPath(10, 1); + poly.lineTo(125, 20); + poly.lineTo(30, 14); + poly.lineTo(600, 144); + + // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 0, 0, + // 2); + // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 1, 0, + // 3); + // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 2, 0, + // 5); + // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 3, 0, + // 7); + // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 4, 0, + // 11); + // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 5, 0, + // 13); + // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 6, 0, + // 17); + // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 7, 0, + // 19); + // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 8, 0, + // 23); + // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 9, 0, + // 29); + // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 10, + // 0, 31); + // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 11, + // 0, 37); + + poly.reversePath(1); + + assertTrue(poly.getPathCount() == 3); + assertTrue(poly.getPathStart(1) == 4); + assertTrue(poly.isClosedPath(0)); + assertTrue(poly.isClosedPath(1)); + Point ptOut = poly.getPoint(4); + assertTrue(ptOut.getX() == 10 && ptOut.getY() == 1); + } + + @Test + public void testReverseAllPaths() { + Polygon poly = new Polygon(); + poly.startPath(10, 1); + poly.lineTo(15, 20); + poly.lineTo(30, 14); + poly.lineTo(60, 144); + + poly.startPath(10, 1); + poly.lineTo(15, 20); + poly.lineTo(300, 14); + poly.lineTo(60, 144); + + poly.startPath(10, 1); + poly.lineTo(125, 20); + poly.lineTo(30, 14); + poly.lineTo(600, 144); + + // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 0, 0, + // 2); + // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 1, 0, + // 3); + // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 2, 0, + // 5); + // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 3, 0, + // 7); + // + // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 4, 0, + // 11); + // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 5, 0, + // 13); + // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 6, 0, + // 17); + // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 7, 0, + // 19); + // + // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 8, 0, + // 23); + // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 9, 0, + // 29); + // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 10, + // 0, 31); + // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 11, + // 0, 37); + + double area = poly.calculateArea2D(); + poly.reverseAllPaths(); + double areaReversed = poly.calculateArea2D(); + assertTrue(Math.abs(area + areaReversed) <= 0.001); + } + + @Test + public void testOpenAllPaths() { + Polyline poly = new Polyline(); + poly.startPath(10, 1); + poly.lineTo(15, 20); + poly.lineTo(30, 14); + poly.lineTo(60, 144); + poly.closePathWithLine(); + + poly.startPath(10, 1); + poly.lineTo(15, 20); + poly.lineTo(300, 14); + poly.lineTo(60, 144); + poly.closePathWithLine(); + + poly.startPath(10, 1); + poly.lineTo(125, 20); + poly.lineTo(30, 14); + poly.lineTo(600, 144); + poly.closePathWithLine(); + + // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 0, 0, + // 2); + // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 1, 0, + // 3); + // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 2, 0, + // 5); + // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 3, 0, + // 7); + // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 4, 0, + // 11); + // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 5, 0, + // 13); + // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 6, 0, + // 17); + // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 7, 0, + // 19); + // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 8, 0, + // 23); + // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 9, 0, + // 29); + // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 10, + // 0, 31); + // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 11, + // 0, 37); + + // MultiPathImpl::Pointer mpImpl = + // (MultiPathImpl::Pointer)poly->_GetImpl(); + // poly.openAllPathsAndDuplicateStartVertex(); + + // assertTrue(poly.getPathCount() == 3); + // assertTrue(poly.getPathStart(0) == 0); + // assertTrue(poly.getPathStart(1) == 5); + // assertTrue(poly.getPathStart(2) == 10); + // assertTrue(poly.getPointCount() == 15); + // Point ptstart = poly.getPoint(0); + // Point ptend = poly.getPoint(4); + // assertTrue(ptstart.getX() == ptend.getX() && ptstart.getY() == + // ptend.getY()); + // ptstart = poly.getPoint(5); + // ptend = poly.getPoint(9); + // assertTrue(ptstart.getX() == ptend.getX() && ptstart.getY() == + // ptend.getY()); + // ptstart = poly.getPoint(10); + // ptend = poly.getPoint(14); + // assertTrue(ptstart.getX() == ptend.getX() && ptstart.getY() == + // ptend.getY()); + } + + @Test + public void testOpenPath() { + Polyline poly = new Polyline(); + poly.startPath(10, 1); + poly.lineTo(15, 20); + poly.lineTo(30, 14); + poly.lineTo(60, 144); + poly.closePathWithLine(); + + poly.startPath(10, 1); + poly.lineTo(15, 20); + poly.lineTo(300, 14); + poly.lineTo(60, 144); + poly.closePathWithLine(); + + poly.startPath(10, 1); + poly.lineTo(125, 20); + poly.lineTo(30, 14); + poly.lineTo(600, 144); + poly.closePathWithLine(); + + // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 0, 0, + // 2); + // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 1, 0, + // 3); + // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 2, 0, + // 5); + // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 3, 0, + // 7); + // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 4, 0, + // 11); + // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 5, 0, + // 13); + // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 6, 0, + // 17); + // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 7, 0, + // 19); + // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 8, 0, + // 23); + // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 9, 0, + // 29); + // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 10, + // 0, 31); + // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 11, + // 0, 37); + // + // MultiPathImpl::Pointer mpImpl = + // (MultiPathImpl::Pointer)poly->_GetImpl(); + // poly.openPathAndDuplicateStartVertex(1); + + // assertTrue(poly.getPathCount() == 3); + // assertTrue(poly.getPathStart(0) == 0); + // assertTrue(poly.getPathStart(1) == 4); + // assertTrue(poly.getPathStart(2) == 9); + // assertTrue(poly.getPointCount() == 13); + // Point ptstart = poly.getPoint(4); + // Point ptend = poly.getPoint(8); + // assertTrue(ptstart.getX() == ptend.getX() && ptstart.getY() == + // ptend.getY()); + // ptstart = poly.getPoint(9); + // assertTrue(ptstart.getX() == 10 && ptstart.getY() == 1); + } + + @Test + public void testInsertPath() { + Polygon poly = new Polygon(); + poly.startPath(10, 1); + poly.lineTo(15, 20); + poly.lineTo(30, 14); + poly.lineTo(60, 144); + + poly.startPath(12, 2); + poly.lineTo(16, 21); + poly.lineTo(301, 15); + poly.lineTo(61, 145); + + poly.startPath(13, 3); + poly.lineTo(126, 22); + poly.lineTo(31, 16); + poly.lineTo(601, 146); + + // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 0, 0, + // 2); + // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 1, 0, + // 3); + // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 2, 0, + // 5); + // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 3, 0, + // 7); + // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 4, 0, + // 11); + // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 5, 0, + // 13); + // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 6, 0, + // 17); + // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 7, 0, + // 19); + // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 8, 0, + // 23); + // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 9, 0, + // 29); + // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 10, + // 0, 31); + // poly.setAttribute(enum_value2(VertexDescription, Semantics, Z), 11, + // 0, 37); + + Polygon poly2 = new Polygon(); + poly2.startPath(12, 2); + poly2.lineTo(16, 21); + poly2.lineTo(301, 15); + poly2.lineTo(61, 145); + + poly.insertPath(0, poly2, 0, false); + + assertTrue(poly.getPathCount() == 4); + assertTrue(poly.getPathStart(0) == 0); + assertTrue(poly.getPathStart(1) == 4); + assertTrue(poly.getPathStart(2) == 8); + assertTrue(poly.getPathStart(3) == 12); + assertTrue(poly.getPointCount() == 16); + + Point2D pt0 = poly.getXY(0); + assertTrue(pt0.x == 12 && pt0.y == 2); + Point2D pt1 = poly.getXY(1); + assertTrue(pt1.x == 61 && pt1.y == 145); + Point2D pt2 = poly.getXY(2); + assertTrue(pt2.x == 301 && pt2.y == 15); + Point2D pt3 = poly.getXY(3); + assertTrue(pt3.x == 16 && pt3.y == 21); + + Point pt2d = new Point(-27, -27); + + poly.insertPoint(1, 0, pt2d); + assertTrue(poly.getPathCount() == 4); + assertTrue(poly.getPathStart(0) == 0); + assertTrue(poly.getPathStart(1) == 4); + assertTrue(poly.getPathStart(2) == 9); + assertTrue(poly.getPathStart(3) == 13); + assertTrue(poly.getPointCount() == 17); + } + + @Test + public void testInsertPoints() { + {// forward insertion + Polygon poly = new Polygon(); + poly.startPath(10, 1); + poly.lineTo(15, 20); + poly.lineTo(30, 14); + poly.lineTo(60, 144); + + poly.startPath(10, 1); + poly.lineTo(15, 20); + poly.lineTo(300, 14); + poly.lineTo(314, 217); + poly.lineTo(60, 144); + + poly.startPath(10, 1); + poly.lineTo(125, 20); + poly.lineTo(30, 14); + poly.lineTo(600, 144); + + Polygon poly1 = new Polygon(); + poly1.startPath(1, 17); + poly1.lineTo(1, 207); + poly1.lineTo(3, 147); + poly1.lineTo(6, 1447); + + poly1.startPath(1000, 17); + poly1.lineTo(1250, 207); + poly1.lineTo(300, 147); + poly1.lineTo(6000, 1447); + + poly1.insertPoints(1, 2, poly, 1, 1, 3, true);// forward + + assertTrue(poly1.getPathCount() == 2); + assertTrue(poly1.getPathStart(1) == 4); + assertTrue(poly1.isClosedPath(0)); + assertTrue(poly1.isClosedPath(1)); + assertTrue(poly1.getPointCount() == 11); + assertTrue(poly1.getPathSize(1) == 7); + // Point2D ptOut; + // ptOut = poly1.getXY(5); + // assertTrue(ptOut.x == 1250 && ptOut.y == 207); + // ptOut = poly1.getXY(6); + // assertTrue(ptOut.x == 15 && ptOut.y == 20); + // ptOut = poly1.getXY(7); + // assertTrue(ptOut.x == 300 && ptOut.y == 14); + // ptOut = poly1.getXY(8); + // assertTrue(ptOut.x == 314 && ptOut.y == 217); + // ptOut = poly1.getXY(9); + // assertTrue(ptOut.x == 300 && ptOut.y == 147); + // ptOut = poly1.getXY(10); + // assertTrue(ptOut.x == 6000 && ptOut.y == 1447); + } + + {// reverse insertion + Polygon poly = new Polygon(); + poly.startPath(10, 1); + poly.lineTo(15, 20); + poly.lineTo(30, 14); + poly.lineTo(60, 144); + + poly.startPath(10, 1); + poly.lineTo(15, 20); + poly.lineTo(300, 14); + poly.lineTo(314, 217); + poly.lineTo(60, 144); + + poly.startPath(10, 1); + poly.lineTo(125, 20); + poly.lineTo(30, 14); + poly.lineTo(600, 144); + + Polygon poly1 = new Polygon(); + poly1.startPath(1, 17); + poly1.lineTo(1, 207); + poly1.lineTo(3, 147); + poly1.lineTo(6, 1447); + + poly1.startPath(1000, 17); + poly1.lineTo(1250, 207); + poly1.lineTo(300, 147); + poly1.lineTo(6000, 1447); + + poly1.insertPoints(1, 2, poly, 1, 1, 3, false);// reverse + + assertTrue(poly1.getPathCount() == 2); + assertTrue(poly1.getPathStart(1) == 4); + assertTrue(poly1.isClosedPath(0)); + assertTrue(poly1.isClosedPath(1)); + assertTrue(poly1.getPointCount() == 11); + assertTrue(poly1.getPathSize(1) == 7); + // Point2D ptOut; + // ptOut = poly1.getXY(5); + // assertTrue(ptOut.x == 1250 && ptOut.y == 207); + // ptOut = poly1.getXY(6); + // assertTrue(ptOut.x == 314 && ptOut.y == 217); + // ptOut = poly1.getXY(7); + // assertTrue(ptOut.x == 300 && ptOut.y == 14); + // ptOut = poly1.getXY(8); + // assertTrue(ptOut.x == 15 && ptOut.y == 20); + // ptOut = poly1.getXY(9); + // assertTrue(ptOut.x == 300 && ptOut.y == 147); + // ptOut = poly1.getXY(10); + // assertTrue(ptOut.x == 6000 && ptOut.y == 1447); + } + } + + @Test + public void testInsertPoint() { + Polygon poly = new Polygon(); + poly.startPath(10, 1); + poly.lineTo(15, 20); + poly.lineTo(30, 14); + poly.lineTo(60, 144); + + poly.startPath(10, 1); + poly.lineTo(15, 20); + poly.lineTo(300, 14); + poly.lineTo(314, 217); + poly.lineTo(60, 144); + + poly.startPath(10, 1); + poly.lineTo(125, 20); + poly.lineTo(30, 14); + poly.lineTo(600, 144); + + Point pt = new Point(-33, -34); + poly.insertPoint(1, 1, pt); + + pt = poly.getPoint(4); + assertTrue(pt.getX() == 10 && pt.getY() == 1); + pt = poly.getPoint(5); + assertTrue(pt.getX() == -33 && pt.getY() == -34); + pt = poly.getPoint(6); + assertTrue(pt.getX() == 15 && pt.getY() == 20); + + assertTrue(poly.getPointCount() == 14); + assertTrue(poly.getPathSize(1) == 6); + assertTrue(poly.getPathSize(2) == 4); + assertTrue(poly.getPathCount() == 3); + } + + @Test + public void testRemovePoint() { + Polygon poly = new Polygon(); + poly.startPath(10, 1); + poly.lineTo(15, 20); + poly.lineTo(30, 14); + poly.lineTo(60, 144); + + poly.startPath(10, 1); + poly.lineTo(15, 20); + poly.lineTo(300, 14); + poly.lineTo(314, 217); + poly.lineTo(60, 144); + + poly.startPath(10, 1); + poly.lineTo(125, 20); + poly.lineTo(30, 14); + poly.lineTo(600, 144); + + poly.removePoint(1, 1); + + Point pt; + + pt = poly.getPoint(4); + assertTrue(pt.getX() == 10 && pt.getY() == 1); + pt = poly.getPoint(5); + assertTrue(pt.getX() == 300 && pt.getY() == 14); + + assertTrue(poly.getPointCount() == 12); + assertTrue(poly.getPathSize(0) == 4); + assertTrue(poly.getPathSize(1) == 4); + assertTrue(poly.getPathSize(2) == 4); + } + + @Test + public static void testPolygonAreaAndLength() { + Polygon poly; /* const */ - double r = 1.0; - /* const */ - double epsilon = 1.0e-14; + double r = 1.0; /* const */ - int nMax = 40; - - // If r == 1.0 and nMax == 40 and epsilon == 1.0e-14, it will pass. - // But if r == 1.0 and nMax == 40 and epsilon == 1.0e-15, it will fail. - - for (int n = 3; n < nMax; n++) { - // regular polygon with n vertices and length from center to vertex - // = r - poly = new Polygon(); - double theta = 0.0; - poly.startPath(r, 0.0); - for (int k = 1; k <= n; k++) { - theta -= 2 * Math.PI / n; - poly.lineTo(r * Math.cos(theta), r * Math.sin(theta)); - } - double sinPiOverN = Math.sin(Math.PI / n); - double sinTwoPiOverN = Math.sin(2.0 * Math.PI / n); - double analyticalLength = 2.0 * n * r * sinPiOverN; - double analyticalArea = 0.5 * n * r * r * sinTwoPiOverN; - double calculatedLength = poly.calculateLength2D(); - double calculatedArea = poly.calculateArea2D(); - assertTrue(Math.abs(analyticalLength - calculatedLength) < epsilon); - assertTrue(Math.abs(analyticalArea - calculatedArea) < epsilon); - } - } - - @Test - public void testInsertPointsFromArray() { - {// Test forward insertion of an array of Point2D - // ArrayOf(Point2D) arr = new ArrayOf(Point2D)(5); - // arr[0].SetCoords(10, 1); - // arr[1].SetCoords(15, 20); - // arr[2].SetCoords(300, 14); - // arr[3].SetCoords(314, 217); - // arr[4].SetCoords(60, 144); - - Polygon poly1 = new Polygon(); - poly1.startPath(1, 17); - poly1.lineTo(1, 207); - poly1.lineTo(3, 147); - poly1.lineTo(6, 1447); - - poly1.startPath(1000, 17); - poly1.lineTo(1250, 207); - poly1.lineTo(300, 147); - poly1.lineTo(6000, 1447); - - assertTrue(poly1.getPathCount() == 2); - assertTrue(poly1.getPathStart(1) == 4); - assertTrue(poly1.isClosedPath(0)); - assertTrue(poly1.isClosedPath(1)); - } - - {// Test reversed insertion of an array of Point2D - } - } - - @Test - public void testCR177477() { - Polygon pg = new Polygon(); - pg.startPath(-130, 40); - pg.lineTo(-70, 40); - pg.lineTo(-70, 10); - pg.lineTo(-130, 10); - - Polygon pg2 = new Polygon(); - pg2.startPath(-60, 40); - pg2.lineTo(-50, 40); - pg2.lineTo(-50, 10); - pg2.lineTo(-60, 10); - - pg.add(pg2, false); - } - - @Test - public void testCR177477getPathEnd() { - Polygon pg = new Polygon(); - pg.startPath(-130, 40); - pg.lineTo(-70, 40); - pg.lineTo(-70, 10); - pg.lineTo(-130, 10); - - pg.startPath(-60, 40); - pg.lineTo(-50, 40); - pg.lineTo(-50, 10); - pg.lineTo(-60, 10); - - pg.startPath(-40, 40); - pg.lineTo(-30, 40); - pg.lineTo(-30, 10); - pg.lineTo(-40, 10); - - int pathCount = pg.getPathCount(); - assertTrue(pathCount == 3); - - // int startIndex = pg.getPathStart(pathCount - 1); - - // int endIndex = pg.getPathEnd(pathCount - 1); - - Line line = new Line(); - line.toString(); - - line.setStart(new Point(0, 0)); - line.setEnd(new Point(1, 0)); - - line.toString(); - - double geoLength = GeometryEngine.geodesicDistanceOnWGS84(new Point(0, - 0), new Point(1, 0)); - assertTrue(Math.abs(geoLength - 111319) < 1); - } - - @Test - public void testBug1() { - Polygon pg = new Polygon(); - pg.startPath(-130, 40); - for (int i = 0; i < 1000; i++) - pg.lineTo(-70, 40); - for (int i = 0; i < 999; i++) - pg.removePoint(0, pg.getPointCount() - 1); - - pg.lineTo(-70, 40); - } - - @Test - public void testGeometryCopy() { - boolean noException = true; - - Polyline polyline = new Polyline(); - - Point p1 = new Point(-85.59285621496956, 38.26004727491098); - Point p2 = new Point(-85.56417866635002, 38.28084064314639); - Point p3 = new Point(-85.56845156650877, 38.24659881865461); - Point p4 = new Point(-85.55341069949853, 38.26671513050464); - - polyline.startPath(p1); - try { - polyline.lineTo(p2); - polyline.copy(); - polyline.lineTo(p3); - polyline.copy(); - polyline.lineTo(p4); // exception thrown here!!! - - } catch (Exception e) { - e.printStackTrace(); - noException = false; - } - - assertTrue(noException); - }// end of method - - @Test - public void testBoundary() { - Geometry g = OperatorImportFromWkt - .local() - .execute( - 0, - Geometry.Type.Unknown, - "POLYGON((-10 -10, 10 -10, 10 10, -10 10, -10 -10), (-5 -5, -5 5, 5 5, 5 -5, -5 -5))", - null); - - Geometry boundary = OperatorBoundary.local().execute(g, null); - Polyline polyline = (Polyline) boundary; - polyline.reverseAllPaths(); - String s = OperatorExportToWkt.local().execute(0, boundary, null); - assertTrue(s - .equals("MULTILINESTRING ((-10 -10, 10 -10, 10 10, -10 10, -10 -10), (-5 -5, -5 5, 5 5, 5 -5, -5 -5))")); - } - - @Test - public void testReplaceNaNs() { - { - MultiPoint mp = new MultiPoint(); - Point pt = new Point(); - pt.setXY(1, 2); - pt.setZ(Double.NaN); - mp.add(pt); - pt = new Point(); - pt.setXY(11, 12); - pt.setZ(3); - mp.add(pt); - - mp.replaceNaNs(VertexDescription.Semantics.Z, 5); - assertTrue(mp.getPoint(0).equals(new Point(1, 2, 5))); - assertTrue(mp.getPoint(1).equals(new Point(11, 12, 3))); - } - - { - Polygon mp = new Polygon(); - Point pt = new Point(); - pt.setXY(1, 2); - pt.setZ(Double.NaN); - mp.startPath(pt); - pt = new Point(); - pt.setXY(11, 12); - pt.setZ(3); - mp.lineTo(pt); - - mp.replaceNaNs(VertexDescription.Semantics.Z, 5); - assertTrue(mp.getPoint(0).equals(new Point(1, 2, 5))); - assertTrue(mp.getPoint(1).equals(new Point(11, 12, 3))); - } - - { - Polygon mp = new Polygon(); - Point pt1 = new Point(); - pt1.setXY(1, 2); - pt1.setM(Double.NaN); - mp.startPath(pt1); - Point pt2 = new Point(); - pt2.setXY(11, 12); - pt2.setM(3); - mp.lineTo(pt2); - - mp.replaceNaNs(VertexDescription.Semantics.M, 5); - Point p = new Point(1, 2); - p.setM(5); - boolean b = mp.getPoint(0).equals(p); - assertTrue(b); - p = new Point(11, 12); - p.setM(3); - b = mp.getPoint(1).equals(p); - assertTrue(b); - } - - } - - @Test - public void testPolygon2PolygonFails() { - OperatorFactoryLocal factory = OperatorFactoryLocal.getInstance(); - OperatorExportToGeoJson exporter = (OperatorExportToGeoJson) factory - .getOperator(Operator.Type.ExportToGeoJson); - String result = exporter.execute(birmingham()); - - OperatorImportFromGeoJson importer = (OperatorImportFromGeoJson) factory - .getOperator(Operator.Type.ImportFromGeoJson); - MapGeometry mapGeometry = importer.execute( - GeoJsonImportFlags.geoJsonImportDefaults, - Geometry.Type.Polygon, result, null); - Polygon polygon = (Polygon) mapGeometry.getGeometry(); - assertEquals(birmingham(), polygon); - } - - @Test - public void testPolygon2PolygonFails2() { - String birminghamGeojson = GeometryEngine - .geometryToGeoJson(birmingham()); - MapGeometry returnedGeometry = GeometryEngine.geoJsonToGeometry( - birminghamGeojson, GeoJsonImportFlags.geoJsonImportDefaults, - Geometry.Type.Polygon); - Polygon polygon = (Polygon) returnedGeometry.getGeometry(); - assertEquals(polygon, birmingham()); - } - - @Test - public void testPolygon2PolygonWorks() { - String birminghamGeojson = GeometryEngine - .geometryToGeoJson(birmingham()); - MapGeometry returnedGeometry = GeometryEngine.geoJsonToGeometry( - birminghamGeojson, GeoJsonImportFlags.geoJsonImportDefaults, - Geometry.Type.Polygon); - Polygon polygon = (Polygon) returnedGeometry.getGeometry(); - assertEquals(polygon.toString(), birmingham().toString()); - } - - @Test - public void testPolygon2Polygon2Works() { - String birminghamJson = GeometryEngine.geometryToJson(4326, - birmingham()); - MapGeometry returnedGeometry = GeometryEngine - .jsonToGeometry(birminghamJson); - Polygon polygon = (Polygon) returnedGeometry.getGeometry(); - assertEquals(polygon, birmingham()); - String s = polygon.toString(); - } - - @Test - public void testSegmentIteratorCrash() { - Polygon poly = new Polygon(); - - // clockwise => outer ring - poly.startPath(0, 0); - poly.lineTo(-0.5, 0.5); - poly.lineTo(0.5, 1); - poly.lineTo(1, 0.5); - poly.lineTo(0.5, 0); - - // hole - poly.startPath(0.5, 0.2); - poly.lineTo(0.6, 0.5); - poly.lineTo(0.2, 0.9); - poly.lineTo(-0.2, 0.5); - poly.lineTo(0.1, 0.2); - poly.lineTo(0.2, 0.3); - - // island - poly.startPath(0.1, 0.7); - poly.lineTo(0.3, 0.7); - poly.lineTo(0.3, 0.4); - poly.lineTo(0.1, 0.4); - - assertEquals(poly.getSegmentCount(), 15); - assertEquals(poly.getPathCount(), 3); - SegmentIterator segmentIterator = poly.querySegmentIterator(); - int paths = 0; - int segments = 0; - while (segmentIterator.nextPath()) { - paths++; - Segment segment; - while (segmentIterator.hasNextSegment()) { - segment = segmentIterator.nextSegment(); - segments++; - } - } - assertEquals(paths, 3); - assertEquals(segments, 15); - } - - private static Polygon birmingham() { - Polygon poly = new Polygon(); - poly.addEnvelope(new Envelope(-1.954245, 52.513531, -1.837357, - 52.450123), false); - poly.addEnvelope(new Envelope(0, 0, 1, 1), false); - return poly; - } + double epsilon = 1.0e-14; + /* const */ + int nMax = 40; + + // If r == 1.0 and nMax == 40 and epsilon == 1.0e-14, it will pass. + // But if r == 1.0 and nMax == 40 and epsilon == 1.0e-15, it will fail. + + for (int n = 3; n < nMax; n++) { + // regular polygon with n vertices and length from center to vertex + // = r + poly = new Polygon(); + double theta = 0.0; + poly.startPath(r, 0.0); + for (int k = 1; k <= n; k++) { + theta -= 2 * Math.PI / n; + poly.lineTo(r * Math.cos(theta), r * Math.sin(theta)); + } + double sinPiOverN = Math.sin(Math.PI / n); + double sinTwoPiOverN = Math.sin(2.0 * Math.PI / n); + double analyticalLength = 2.0 * n * r * sinPiOverN; + double analyticalArea = 0.5 * n * r * r * sinTwoPiOverN; + double calculatedLength = poly.calculateLength2D(); + double calculatedArea = poly.calculateArea2D(); + assertTrue(Math.abs(analyticalLength - calculatedLength) < epsilon); + assertTrue(Math.abs(analyticalArea - calculatedArea) < epsilon); + } + } + + @Test + public void testInsertPointsFromArray() { + {// Test forward insertion of an array of Point2D + // ArrayOf(Point2D) arr = new ArrayOf(Point2D)(5); + // arr[0].SetCoords(10, 1); + // arr[1].SetCoords(15, 20); + // arr[2].SetCoords(300, 14); + // arr[3].SetCoords(314, 217); + // arr[4].SetCoords(60, 144); + + Polygon poly1 = new Polygon(); + poly1.startPath(1, 17); + poly1.lineTo(1, 207); + poly1.lineTo(3, 147); + poly1.lineTo(6, 1447); + + poly1.startPath(1000, 17); + poly1.lineTo(1250, 207); + poly1.lineTo(300, 147); + poly1.lineTo(6000, 1447); + + assertTrue(poly1.getPathCount() == 2); + assertTrue(poly1.getPathStart(1) == 4); + assertTrue(poly1.isClosedPath(0)); + assertTrue(poly1.isClosedPath(1)); + } + + {// Test reversed insertion of an array of Point2D + } + } + + @Test + public void testCR177477() { + Polygon pg = new Polygon(); + pg.startPath(-130, 40); + pg.lineTo(-70, 40); + pg.lineTo(-70, 10); + pg.lineTo(-130, 10); + + Polygon pg2 = new Polygon(); + pg2.startPath(-60, 40); + pg2.lineTo(-50, 40); + pg2.lineTo(-50, 10); + pg2.lineTo(-60, 10); + + pg.add(pg2, false); + } + + @Test + public void testCR177477getPathEnd() { + Polygon pg = new Polygon(); + pg.startPath(-130, 40); + pg.lineTo(-70, 40); + pg.lineTo(-70, 10); + pg.lineTo(-130, 10); + + pg.startPath(-60, 40); + pg.lineTo(-50, 40); + pg.lineTo(-50, 10); + pg.lineTo(-60, 10); + + pg.startPath(-40, 40); + pg.lineTo(-30, 40); + pg.lineTo(-30, 10); + pg.lineTo(-40, 10); + + int pathCount = pg.getPathCount(); + assertTrue(pathCount == 3); + + // int startIndex = pg.getPathStart(pathCount - 1); + + // int endIndex = pg.getPathEnd(pathCount - 1); + + Line line = new Line(); + line.toString(); + + line.setStart(new Point(0, 0)); + line.setEnd(new Point(1, 0)); + + line.toString(); + + double geoLength = GeometryEngine.geodesicDistanceOnWGS84(new Point(0, + 0), new Point(1, 0)); + assertTrue(Math.abs(geoLength - 111319) < 1); + } + + @Test + public void testBug1() { + Polygon pg = new Polygon(); + pg.startPath(-130, 40); + for (int i = 0; i < 1000; i++) + pg.lineTo(-70, 40); + for (int i = 0; i < 999; i++) + pg.removePoint(0, pg.getPointCount() - 1); + + pg.lineTo(-70, 40); + } + + @Test + public void testGeometryCopy() { + boolean noException = true; + + Polyline polyline = new Polyline(); + + Point p1 = new Point(-85.59285621496956, 38.26004727491098); + Point p2 = new Point(-85.56417866635002, 38.28084064314639); + Point p3 = new Point(-85.56845156650877, 38.24659881865461); + Point p4 = new Point(-85.55341069949853, 38.26671513050464); + + polyline.startPath(p1); + try { + polyline.lineTo(p2); + polyline.copy(); + polyline.lineTo(p3); + polyline.copy(); + polyline.lineTo(p4); // exception thrown here!!! + + } catch (Exception e) { + e.printStackTrace(); + noException = false; + } + + assertTrue(noException); + }// end of method + + @Test + public void testBoundary() { + Geometry g = OperatorImportFromWkt + .local() + .execute( + 0, + Geometry.Type.Unknown, + "POLYGON((-10 -10, 10 -10, 10 10, -10 10, -10 -10), (-5 -5, -5 5, 5 5, 5 -5, -5 -5))", + null); + + Geometry boundary = OperatorBoundary.local().execute(g, null); + Polyline polyline = (Polyline) boundary; + polyline.reverseAllPaths(); + String s = OperatorExportToWkt.local().execute(0, boundary, null); + assertTrue(s + .equals("MULTILINESTRING ((-10 -10, 10 -10, 10 10, -10 10, -10 -10), (-5 -5, -5 5, 5 5, 5 -5, -5 -5))")); + } + + @Test + public void testReplaceNaNs() { + { + MultiPoint mp = new MultiPoint(); + Point pt = new Point(); + pt.setXY(1, 2); + pt.setZ(Double.NaN); + mp.add(pt); + pt = new Point(); + pt.setXY(11, 12); + pt.setZ(3); + mp.add(pt); + + mp.replaceNaNs(VertexDescription.Semantics.Z, 5); + assertTrue(mp.getPoint(0).equals(new Point(1, 2, 5))); + assertTrue(mp.getPoint(1).equals(new Point(11, 12, 3))); + } + + { + Polygon mp = new Polygon(); + Point pt = new Point(); + pt.setXY(1, 2); + pt.setZ(Double.NaN); + mp.startPath(pt); + pt = new Point(); + pt.setXY(11, 12); + pt.setZ(3); + mp.lineTo(pt); + + mp.replaceNaNs(VertexDescription.Semantics.Z, 5); + assertTrue(mp.getPoint(0).equals(new Point(1, 2, 5))); + assertTrue(mp.getPoint(1).equals(new Point(11, 12, 3))); + } + + { + Polygon mp = new Polygon(); + Point pt1 = new Point(); + pt1.setXY(1, 2); + pt1.setM(Double.NaN); + mp.startPath(pt1); + Point pt2 = new Point(); + pt2.setXY(11, 12); + pt2.setM(3); + mp.lineTo(pt2); + + mp.replaceNaNs(VertexDescription.Semantics.M, 5); + Point p = new Point(1, 2); + p.setM(5); + boolean b = mp.getPoint(0).equals(p); + assertTrue(b); + p = new Point(11, 12); + p.setM(3); + b = mp.getPoint(1).equals(p); + assertTrue(b); + } + + } + + @Test + public void testPolygon2PolygonFails() { + OperatorFactoryLocal factory = OperatorFactoryLocal.getInstance(); + OperatorExportToGeoJson exporter = (OperatorExportToGeoJson) factory + .getOperator(Operator.Type.ExportToGeoJson); + String result = exporter.execute(birmingham()); + + OperatorImportFromGeoJson importer = (OperatorImportFromGeoJson) factory + .getOperator(Operator.Type.ImportFromGeoJson); + MapGeometry mapGeometry = importer.execute( + GeoJsonImportFlags.geoJsonImportDefaults, + Geometry.Type.Polygon, result, null); + Polygon polygon = (Polygon) mapGeometry.getGeometry(); + assertEquals(birmingham(), polygon); + } + + @Test + public void testPolygon2PolygonFails2() { + String birminghamGeojson = GeometryEngine + .geometryToGeoJson(birmingham()); + MapGeometry returnedGeometry = GeometryEngine.geoJsonToGeometry( + birminghamGeojson, GeoJsonImportFlags.geoJsonImportDefaults, + Geometry.Type.Polygon); + Polygon polygon = (Polygon) returnedGeometry.getGeometry(); + assertEquals(polygon, birmingham()); + } + + @Test + public void testPolygon2PolygonWorks() { + String birminghamGeojson = GeometryEngine + .geometryToGeoJson(birmingham()); + MapGeometry returnedGeometry = GeometryEngine.geoJsonToGeometry( + birminghamGeojson, GeoJsonImportFlags.geoJsonImportDefaults, + Geometry.Type.Polygon); + Polygon polygon = (Polygon) returnedGeometry.getGeometry(); + assertEquals(polygon.toString(), birmingham().toString()); + } + + @Test + public void testPolygon2Polygon2Works() { + String birminghamJson = GeometryEngine.geometryToJson(4326, + birmingham()); + MapGeometry returnedGeometry = GeometryEngine + .jsonToGeometry(birminghamJson); + Polygon polygon = (Polygon) returnedGeometry.getGeometry(); + assertEquals(polygon, birmingham()); + String s = polygon.toString(); + } + + @Test + public void testSegmentIteratorCrash() { + Polygon poly = new Polygon(); + + // clockwise => outer ring + poly.startPath(0, 0); + poly.lineTo(-0.5, 0.5); + poly.lineTo(0.5, 1); + poly.lineTo(1, 0.5); + poly.lineTo(0.5, 0); + + // hole + poly.startPath(0.5, 0.2); + poly.lineTo(0.6, 0.5); + poly.lineTo(0.2, 0.9); + poly.lineTo(-0.2, 0.5); + poly.lineTo(0.1, 0.2); + poly.lineTo(0.2, 0.3); + + // island + poly.startPath(0.1, 0.7); + poly.lineTo(0.3, 0.7); + poly.lineTo(0.3, 0.4); + poly.lineTo(0.1, 0.4); + + assertEquals(poly.getSegmentCount(), 15); + assertEquals(poly.getPathCount(), 3); + SegmentIterator segmentIterator = poly.querySegmentIterator(); + int paths = 0; + int segments = 0; + while (segmentIterator.nextPath()) { + paths++; + Segment segment; + while (segmentIterator.hasNextSegment()) { + segment = segmentIterator.nextSegment(); + segments++; + } + } + assertEquals(paths, 3); + assertEquals(segments, 15); + } + + private static Polygon birmingham() { + Polygon poly = new Polygon(); + poly.addEnvelope(new Envelope(-1.954245, 52.513531, -1.837357, + 52.450123), false); + poly.addEnvelope(new Envelope(0, 0, 1, 1), false); + return poly; + } } diff --git a/src/test/java/com/esri/core/geometry/TestPolygonUtils.java b/src/test/java/com/esri/core/geometry/TestPolygonUtils.java index 6f1f7e1d..d0fc72bc 100644 --- a/src/test/java/com/esri/core/geometry/TestPolygonUtils.java +++ b/src/test/java/com/esri/core/geometry/TestPolygonUtils.java @@ -28,129 +28,129 @@ import org.junit.Test; public class TestPolygonUtils extends TestCase { - @Override - protected void setUp() throws Exception { - super.setUp(); - } - - @Override - protected void tearDown() throws Exception { - super.tearDown(); - } - - @Test - public static void testPointInAnyOuterRing() { - Polygon polygon = new Polygon(); - // outer ring1 - polygon.startPath(-200, -100); - polygon.lineTo(200, -100); - polygon.lineTo(200, 100); - polygon.lineTo(-190, 100); - polygon.lineTo(-190, 90); - polygon.lineTo(-200, 90); - - // hole - polygon.startPath(-100, 50); - polygon.lineTo(100, 50); - polygon.lineTo(100, -40); - polygon.lineTo(90, -40); - polygon.lineTo(90, -50); - polygon.lineTo(-100, -50); - - // island - polygon.startPath(-10, -10); - polygon.lineTo(10, -10); - polygon.lineTo(10, 10); - polygon.lineTo(-10, 10); - - // outer ring2 - polygon.startPath(300, 300); - polygon.lineTo(310, 300); - polygon.lineTo(310, 310); - polygon.lineTo(300, 310); - - polygon.reverseAllPaths(); - - Point2D testPointIn1 = new Point2D(1, 2); // inside the island - Point2D testPointIn2 = new Point2D(190, 90); // inside, betwen outer - // ring1 and the hole - Point2D testPointIn3 = new Point2D(305, 305); // inside the outer ring2 - Point2D testPointOut1 = new Point2D(300, 2); // outside any - Point2D testPointOut2 = new Point2D(-195, 95); // outside any (in the - // concave area of outer - // ring 2) - Point2D testPointOut3 = new Point2D(99, 49); // outside (in the hole) - - PolygonUtils.PiPResult res; - // is_point_in_polygon_2D - res = PolygonUtils.isPointInPolygon2D(polygon, testPointIn1, 0); - assertTrue(res == PolygonUtils.PiPResult.PiPInside); - res = PolygonUtils.isPointInPolygon2D(polygon, testPointIn2, 0); - assertTrue(res == PolygonUtils.PiPResult.PiPInside); - res = PolygonUtils.isPointInPolygon2D(polygon, testPointIn3, 0); - assertTrue(res == PolygonUtils.PiPResult.PiPInside); - - res = PolygonUtils.isPointInPolygon2D(polygon, testPointOut1, 0); - assertTrue(res == PolygonUtils.PiPResult.PiPOutside); - res = PolygonUtils.isPointInPolygon2D(polygon, testPointOut2, 0); - assertTrue(res == PolygonUtils.PiPResult.PiPOutside); - res = PolygonUtils.isPointInPolygon2D(polygon, testPointOut3, 0); - assertTrue(res == PolygonUtils.PiPResult.PiPOutside); - - // Ispoint_in_any_outer_ring - res = PolygonUtils.isPointInAnyOuterRing(polygon, testPointIn1, 0); - assertTrue(res == PolygonUtils.PiPResult.PiPInside); - res = PolygonUtils.isPointInAnyOuterRing(polygon, testPointIn2, 0); - assertTrue(res == PolygonUtils.PiPResult.PiPInside); - res = PolygonUtils.isPointInAnyOuterRing(polygon, testPointIn3, 0); - assertTrue(res == PolygonUtils.PiPResult.PiPInside); - - res = PolygonUtils.isPointInAnyOuterRing(polygon, testPointOut1, 0); - assertTrue(res == PolygonUtils.PiPResult.PiPOutside); - res = PolygonUtils.isPointInAnyOuterRing(polygon, testPointOut2, 0); - assertTrue(res == PolygonUtils.PiPResult.PiPOutside); - res = PolygonUtils.isPointInAnyOuterRing(polygon, testPointOut3, 0); - assertTrue(res == PolygonUtils.PiPResult.PiPInside);// inside of outer - // ring - } - - @Test - public static void testPointInPolygonBugCR181840() { - PolygonUtils.PiPResult res; - {// pointInPolygonBugCR181840 - point in polygon bug - Polygon polygon = new Polygon(); - // outer ring1 - polygon.startPath(0, 0); - polygon.lineTo(10, 10); - polygon.lineTo(20, 0); - - res = PolygonUtils.isPointInPolygon2D(polygon, - Point2D.construct(15, 10), 0); - assertTrue(res == PolygonUtils.PiPResult.PiPOutside); - res = PolygonUtils.isPointInPolygon2D(polygon, - Point2D.construct(2, 10), 0); - assertTrue(res == PolygonUtils.PiPResult.PiPOutside); - res = PolygonUtils.isPointInPolygon2D(polygon, - Point2D.construct(5, 5), 0); - assertTrue(res == PolygonUtils.PiPResult.PiPInside); - } - - {// CR181840 - point in polygon bug - Polygon polygon = new Polygon(); - // outer ring1 - polygon.startPath(10, 10); - polygon.lineTo(20, 0); - polygon.lineTo(0, 0); - - res = PolygonUtils.isPointInPolygon2D(polygon, - Point2D.construct(15, 10), 0); - assertTrue(res == PolygonUtils.PiPResult.PiPOutside); - res = PolygonUtils.isPointInPolygon2D(polygon, - Point2D.construct(2, 10), 0); - assertTrue(res == PolygonUtils.PiPResult.PiPOutside); - res = PolygonUtils.isPointInPolygon2D(polygon, - Point2D.construct(5, 5), 0); - assertTrue(res == PolygonUtils.PiPResult.PiPInside); - } - } + @Override + protected void setUp() throws Exception { + super.setUp(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + } + + @Test + public static void testPointInAnyOuterRing() { + Polygon polygon = new Polygon(); + // outer ring1 + polygon.startPath(-200, -100); + polygon.lineTo(200, -100); + polygon.lineTo(200, 100); + polygon.lineTo(-190, 100); + polygon.lineTo(-190, 90); + polygon.lineTo(-200, 90); + + // hole + polygon.startPath(-100, 50); + polygon.lineTo(100, 50); + polygon.lineTo(100, -40); + polygon.lineTo(90, -40); + polygon.lineTo(90, -50); + polygon.lineTo(-100, -50); + + // island + polygon.startPath(-10, -10); + polygon.lineTo(10, -10); + polygon.lineTo(10, 10); + polygon.lineTo(-10, 10); + + // outer ring2 + polygon.startPath(300, 300); + polygon.lineTo(310, 300); + polygon.lineTo(310, 310); + polygon.lineTo(300, 310); + + polygon.reverseAllPaths(); + + Point2D testPointIn1 = new Point2D(1, 2); // inside the island + Point2D testPointIn2 = new Point2D(190, 90); // inside, betwen outer + // ring1 and the hole + Point2D testPointIn3 = new Point2D(305, 305); // inside the outer ring2 + Point2D testPointOut1 = new Point2D(300, 2); // outside any + Point2D testPointOut2 = new Point2D(-195, 95); // outside any (in the + // concave area of outer + // ring 2) + Point2D testPointOut3 = new Point2D(99, 49); // outside (in the hole) + + PolygonUtils.PiPResult res; + // is_point_in_polygon_2D + res = PolygonUtils.isPointInPolygon2D(polygon, testPointIn1, 0); + assertTrue(res == PolygonUtils.PiPResult.PiPInside); + res = PolygonUtils.isPointInPolygon2D(polygon, testPointIn2, 0); + assertTrue(res == PolygonUtils.PiPResult.PiPInside); + res = PolygonUtils.isPointInPolygon2D(polygon, testPointIn3, 0); + assertTrue(res == PolygonUtils.PiPResult.PiPInside); + + res = PolygonUtils.isPointInPolygon2D(polygon, testPointOut1, 0); + assertTrue(res == PolygonUtils.PiPResult.PiPOutside); + res = PolygonUtils.isPointInPolygon2D(polygon, testPointOut2, 0); + assertTrue(res == PolygonUtils.PiPResult.PiPOutside); + res = PolygonUtils.isPointInPolygon2D(polygon, testPointOut3, 0); + assertTrue(res == PolygonUtils.PiPResult.PiPOutside); + + // Ispoint_in_any_outer_ring + res = PolygonUtils.isPointInAnyOuterRing(polygon, testPointIn1, 0); + assertTrue(res == PolygonUtils.PiPResult.PiPInside); + res = PolygonUtils.isPointInAnyOuterRing(polygon, testPointIn2, 0); + assertTrue(res == PolygonUtils.PiPResult.PiPInside); + res = PolygonUtils.isPointInAnyOuterRing(polygon, testPointIn3, 0); + assertTrue(res == PolygonUtils.PiPResult.PiPInside); + + res = PolygonUtils.isPointInAnyOuterRing(polygon, testPointOut1, 0); + assertTrue(res == PolygonUtils.PiPResult.PiPOutside); + res = PolygonUtils.isPointInAnyOuterRing(polygon, testPointOut2, 0); + assertTrue(res == PolygonUtils.PiPResult.PiPOutside); + res = PolygonUtils.isPointInAnyOuterRing(polygon, testPointOut3, 0); + assertTrue(res == PolygonUtils.PiPResult.PiPInside);// inside of outer + // ring + } + + @Test + public static void testPointInPolygonBugCR181840() { + PolygonUtils.PiPResult res; + {// pointInPolygonBugCR181840 - point in polygon bug + Polygon polygon = new Polygon(); + // outer ring1 + polygon.startPath(0, 0); + polygon.lineTo(10, 10); + polygon.lineTo(20, 0); + + res = PolygonUtils.isPointInPolygon2D(polygon, + Point2D.construct(15, 10), 0); + assertTrue(res == PolygonUtils.PiPResult.PiPOutside); + res = PolygonUtils.isPointInPolygon2D(polygon, + Point2D.construct(2, 10), 0); + assertTrue(res == PolygonUtils.PiPResult.PiPOutside); + res = PolygonUtils.isPointInPolygon2D(polygon, + Point2D.construct(5, 5), 0); + assertTrue(res == PolygonUtils.PiPResult.PiPInside); + } + + {// CR181840 - point in polygon bug + Polygon polygon = new Polygon(); + // outer ring1 + polygon.startPath(10, 10); + polygon.lineTo(20, 0); + polygon.lineTo(0, 0); + + res = PolygonUtils.isPointInPolygon2D(polygon, + Point2D.construct(15, 10), 0); + assertTrue(res == PolygonUtils.PiPResult.PiPOutside); + res = PolygonUtils.isPointInPolygon2D(polygon, + Point2D.construct(2, 10), 0); + assertTrue(res == PolygonUtils.PiPResult.PiPOutside); + res = PolygonUtils.isPointInPolygon2D(polygon, + Point2D.construct(5, 5), 0); + assertTrue(res == PolygonUtils.PiPResult.PiPInside); + } + } } diff --git a/src/test/java/com/esri/core/geometry/TestProjection.java b/src/test/java/com/esri/core/geometry/TestProjection.java index 13d4cc54..80387a8d 100644 --- a/src/test/java/com/esri/core/geometry/TestProjection.java +++ b/src/test/java/com/esri/core/geometry/TestProjection.java @@ -18,467 +18,467 @@ */ public class TestProjection extends TestCase { - static { - System.loadLibrary("proj"); - } - - SpatialReference spatialReferenceWGS = SpatialReference.create(4326); - SpatialReference spatialReferenceMerc = SpatialReference.create(3857); - ProjectionTransformation projectionTransformationToMerc = new ProjectionTransformation(spatialReferenceWGS, spatialReferenceMerc); - ProjectionTransformation projectionTransformationToWGS = new ProjectionTransformation(spatialReferenceMerc, spatialReferenceWGS); - - @Before - public void setUp() { - - } - - @Test - public void testProj4() throws Exception { - PJ sourcePJ = new PJ("+init=epsg:32632"); // (x,y) axis order - PJ targetPJ = new PJ("+proj=latlong +datum=WGS84"); // (λ,φ) axis order - PJ sourcePJ_utm = new PJ("+proj=utm +zone=32 +datum=WGS84 +units=m +no_defs "); - PJ targetPJ_4326 = new PJ("+init=epsg:4326"); - - double[] coordinates_32632 = { - 500000, 0, // First coordinate - 400000, 100000, // Second coordinate - 600000, -100000 // Third coordinate - }; - - double[] coordinates_WGS84 = Arrays.copyOf(coordinates_32632, coordinates_32632.length); - double[] coordinates_4326 = Arrays.copyOf(coordinates_32632, coordinates_32632.length); - - sourcePJ.transform(targetPJ, 2, coordinates_WGS84, 0, 3); - sourcePJ.transform(targetPJ_4326, 2, coordinates_4326, 0, 3); - - for (int i = 0; i < coordinates_WGS84.length; i++) { - if (i == 1) - continue; - - assertTrue((Math.abs(coordinates_WGS84[i] - coordinates_32632[i])) > 1); - assertTrue((Math.abs(coordinates_4326[i] - coordinates_32632[i])) > 1); - assertEquals(coordinates_4326[i], coordinates_WGS84[i]); - } - } - - @Test - public void testProj4Strings() { - SpatialReference spatialReference = SpatialReference.create(4326); - assertEquals("+init=epsg:4326", spatialReference.getProj4()); - - spatialReference = SpatialReference.create(32632); - assertEquals("+init=epsg:32632", spatialReference.getProj4()); - } - - @Test - public void testProjectionCursor_1() { - ProjectionTransformation projectionTransformation = new ProjectionTransformation(SpatialReference.create(32632), SpatialReference.create(4326)); - Point point = new Point(500000, 0); - Point pointOut = (Point) OperatorProject.local().execute(point, projectionTransformation, null); - assertNotNull(pointOut); - assertTrue(Math.abs(point.getX() - pointOut.getY()) > 1); - projectionTransformation = new ProjectionTransformation(SpatialReference.create(4326), SpatialReference.create(32632)); - Point originalPoint = (Point) OperatorProject.local().execute(pointOut, projectionTransformation, null); - assertEquals(originalPoint.getX(), point.getX()); - assertEquals(originalPoint.getY(), point.getY()); - } - - @Test - public void testProjectMultiPoint() { - ProjectionTransformation projectionTransformation = new ProjectionTransformation(SpatialReference.create(32632), SpatialReference.create(4326)); - MultiPoint multiPoint = new MultiPoint(); - multiPoint.add(500000, 0); - multiPoint.add(400000, 100000); - multiPoint.add(600000, -100000); - MultiPoint multiPointOut = (MultiPoint) OperatorProject.local().execute(multiPoint, projectionTransformation, null); - assertNotNull(multiPointOut); - assertFalse(multiPointOut.equals(multiPoint)); - assertEquals(multiPoint.getPointCount(), multiPointOut.getPointCount()); - projectionTransformation = new ProjectionTransformation(SpatialReference.create(4326), SpatialReference.create(32632)); - MultiPoint originalMultiPoint = (MultiPoint) OperatorProject.local().execute(multiPointOut, projectionTransformation, null); - - for (int i = 0; i < multiPoint.getPointCount(); i++) { - assertEquals(multiPoint.getPoint(i).getX(), originalMultiPoint.getPoint(i).getX(), 1e-9); - assertEquals(multiPoint.getPoint(i).getY(), originalMultiPoint.getPoint(i).getY(), 1e-9); - } - } - - @Test - public void testProjectPolyline() { - ProjectionTransformation projectionTransformation = new ProjectionTransformation(SpatialReference.create(32632), SpatialReference.create(4326)); - Polyline polyline = new Polyline(); - polyline.startPath(500000, 0); - polyline.lineTo(400000, 100000); - polyline.lineTo(600000, -100000); - Polyline polylineOut = (Polyline) OperatorProject.local().execute(polyline, projectionTransformation, null); - assertNotNull(polylineOut); - assertFalse(polylineOut.equals(polyline)); - - MultiPathImpl polyline_impl = (MultiPathImpl) polylineOut._getImpl(); - int point_count = polyline_impl.getPointCount(); - int path_count = polyline_impl.getPathCount(); - assertEquals(point_count, 3); - assertEquals(path_count, 1); - - assertEquals(polyline.getPointCount(), polylineOut.getPointCount()); - projectionTransformation = new ProjectionTransformation(SpatialReference.create(4326), SpatialReference.create(32632)); - Polyline originalPolyline = (Polyline) OperatorProject.local().execute(polylineOut, projectionTransformation, null); - for (int i = 0; i < polyline.getPointCount(); i++) { - assertEquals(polyline.getPoint(i).getX(), originalPolyline.getPoint(i).getX(), 1e-9); - assertEquals(polyline.getPoint(i).getY(), originalPolyline.getPoint(i).getY(), 1e-9); - } - } - - @Test - public void testProjectPolygon() { - ProjectionTransformation projectionTransformation = new ProjectionTransformation(SpatialReference.create(32632), SpatialReference.create(4326)); - Polygon polygon = new Polygon(); - polygon.startPath(500000, 0); - polygon.lineTo(400000, 100000); - polygon.lineTo(600000, -100000); - polygon.closeAllPaths(); - Polygon polygonOut = (Polygon) OperatorProject.local().execute(polygon, projectionTransformation, null); - assertNotNull(polygonOut); - assertFalse(polygonOut.equals(polygon)); - assertEquals(polygon.getPointCount(), polygonOut.getPointCount()); - projectionTransformation = new ProjectionTransformation(SpatialReference.create(4326), SpatialReference.create(32632)); - Polygon originalPolygon = (Polygon) OperatorProject.local().execute(polygonOut, projectionTransformation, null); - - for (int i = 0; i < polygon.getPointCount(); i++) { - assertEquals(polygon.getPoint(i).getX(), originalPolygon.getPoint(i).getX(), 1e-9); - assertEquals(polygon.getPoint(i).getY(), originalPolygon.getPoint(i).getY(), 1e-9); - } - } - - @Test - public void testProjectEnvelope() { - Envelope2D envelope2D = new Envelope2D(-10000, -10000, 10000, 10000); - String proj4 = String.format( - "+proj=laea +lat_0=%f +lon_0=%f +x_0=0.0 +y_0=0.0 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs", - 0f, 0f); - - SpatialReference spatialReference = SpatialReference.createFromProj4(proj4); - SpatialReference spatialReferenceWgs84 = SpatialReference.create(4326); - ProjectionTransformation projectionTransformation = new ProjectionTransformation(spatialReference, spatialReferenceWgs84); - Polygon polygon = (Polygon) OperatorProject.local().execute(new Envelope(envelope2D), projectionTransformation, null); - assertNotNull(polygon); - Point2D point2D = new Point2D(); - double a = 6378137.0; // radius of spheroid for WGS_1984 - double e2 = 0.0066943799901413165; // ellipticity for WGS_1984 - Envelope2D gcsEnvelope = new Envelope2D(); - polygon.queryEnvelope2D(gcsEnvelope); - GeoDist.getEnvCenter(a, e2, gcsEnvelope, point2D); - assertEquals(point2D.x, 0, 1e-14); - assertEquals(point2D.y, 0, 1e-6); - - // TODO - } - - @Test - public void testEPSGCodes() { - String wktGeom = "MULTIPOLYGON (((6311583.246999994 1871386.1630000025, 6311570 1871325, 6311749.093999997 1871285.9699999988, 6311768.118000001 1871345.9619999975, 6311583.246999994 1871386.1630000025)))"; - SpatialReference spatialReference = SpatialReference.create(2230); - SpatialReference spatialReferenceWgs84 = SpatialReference.create(4326); - ProjectionTransformation projectionTransformation = new ProjectionTransformation(spatialReference, spatialReferenceWgs84); - SimpleStringCursor simpleStringCursor = new SimpleStringCursor(wktGeom); - OperatorImportFromWktCursor wktCursor = new OperatorImportFromWktCursor(0, simpleStringCursor); - OperatorProjectCursor projectCursor = new OperatorProjectCursor(wktCursor, projectionTransformation, null); - Geometry geometry = projectCursor.next(); - - assertNotNull(geometry); - } - - @Test - public void testFoldInto360() { - String wktGeom = "POLYGON((120 48.2246726495652,140 48.2246726495652,140 25.799891182088334,120 25.799891182088334,120 48.2246726495652))"; - SimpleStringCursor result = new SimpleStringCursor(wktGeom); - - OperatorImportFromWktCursor wktCursor = new OperatorImportFromWktCursor(0, result); - Geometry expectedGeometry = wktCursor.next(); - - String wktGeom360 = "POLYGON((480 48.2246726495652,500 48.2246726495652,500 25.799891182088334,480 25.799891182088334,480 48.2246726495652))"; - SimpleStringCursor test = new SimpleStringCursor(wktGeom360); - wktCursor = new OperatorImportFromWktCursor(0, test); - OperatorProjectCursor projectCursor = new OperatorProjectCursor(wktCursor, this.projectionTransformationToMerc, null); - OperatorProjectCursor reProjectCursor = new OperatorProjectCursor(projectCursor, this.projectionTransformationToWGS, null); - - Polygon actualGeometry = (Polygon) reProjectCursor.next(); - - assertTrue(GeometryEngine.equals(actualGeometry, expectedGeometry, spatialReferenceWGS)); - } - - - @Test - public void testWrapTriangle() { - String wktGeom = "POLYGON((167 30, 201 49, 199 18, 167 30))"; - SimpleStringCursor simpleStringCursor = new SimpleStringCursor(wktGeom); - OperatorImportFromWktCursor wktCursor = new OperatorImportFromWktCursor(0, simpleStringCursor); - OperatorProjectCursor projectCursor = new OperatorProjectCursor(wktCursor, this.projectionTransformationToMerc, null); - OperatorProjectCursor reProjectCursor = new OperatorProjectCursor(projectCursor, this.projectionTransformationToWGS, null); - - Polygon result = (Polygon) reProjectCursor.next(); - NonSimpleResult nonSimpleResult = new NonSimpleResult(); - OperatorSimplify simplify = (OperatorSimplify) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.Simplify); - boolean isSimple = simplify.isSimpleAsFeature(result, spatialReferenceWGS, true, nonSimpleResult, null); - - simpleStringCursor = new SimpleStringCursor(wktGeom); - wktCursor = new OperatorImportFromWktCursor(0, simpleStringCursor); - Polygon expected = (Polygon) wktCursor.next(); - assertTrue(GeometryEngine.isSimple(expected, spatialReferenceWGS)); - - assertEquals(expected.calculateArea2D(), result.calculateArea2D(), 1e-10); - } - - @Test - public void testWrapTriangleOtherSide() { - String wktGeom = "POLYGON((-193 -30, -160 -29, -158 -40, -193 -30))"; - SimpleStringCursor simpleStringCursor = new SimpleStringCursor(wktGeom); - OperatorImportFromWktCursor wktCursor = new OperatorImportFromWktCursor(0, simpleStringCursor); - OperatorProjectCursor projectCursor = new OperatorProjectCursor(wktCursor, this.projectionTransformationToMerc, null); - OperatorProjectCursor reProjectCursor = new OperatorProjectCursor(projectCursor, this.projectionTransformationToWGS, null); - - Polygon result = (Polygon) reProjectCursor.next(); - NonSimpleResult nonSimpleResult = new NonSimpleResult(); - OperatorSimplify simplify = (OperatorSimplify) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.Simplify); - boolean isSimple = simplify.isSimpleAsFeature(result, spatialReferenceWGS, true, nonSimpleResult, null); - - simpleStringCursor = new SimpleStringCursor(wktGeom); - wktCursor = new OperatorImportFromWktCursor(0, simpleStringCursor); - Polygon expected = (Polygon) wktCursor.next(); - assertTrue(GeometryEngine.isSimple(expected, spatialReferenceWGS)); - - assertEquals(expected.calculateArea2D(), result.calculateArea2D(), .00000000001); - } - - @Test - public void testWrap() { - String wktGeom = "POLYGON((167.87109375 30.751277776257812," + - "201.43359375 49.38237278700955," + - "232.49609375 -5.266007882805485," + - "116.19500625 -17.308687886770024," + - "199.54296875 18.979025953255267," + - "126.03515625 12.897489183755892," + - "167.87109375 30.751277776257812))"; - SimpleStringCursor simpleStringCursor = new SimpleStringCursor(wktGeom); - OperatorImportFromWktCursor wktCursor = new OperatorImportFromWktCursor(0, simpleStringCursor); - OperatorProjectCursor projectCursor = new OperatorProjectCursor(wktCursor, this.projectionTransformationToMerc, null); - OperatorProjectCursor reProjectCursor = new OperatorProjectCursor(projectCursor, this.projectionTransformationToWGS, null); - - Polygon result = (Polygon) reProjectCursor.next(); - NonSimpleResult nonSimpleResult = new NonSimpleResult(); - OperatorSimplify simplify = (OperatorSimplify) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.Simplify); - boolean isSimple = simplify.isSimpleAsFeature(result, spatialReferenceWGS, true, nonSimpleResult, null); - - simpleStringCursor = new SimpleStringCursor(wktGeom); - wktCursor = new OperatorImportFromWktCursor(0, simpleStringCursor); - Polygon expected = (Polygon) wktCursor.next(); - assertTrue(GeometryEngine.isSimple(expected, spatialReferenceWGS)); - - assertEquals(expected.calculateArea2D(), result.calculateArea2D(), 1e-10); - } - - @Test - public void testAlbers() { - String wktGeom = "MULTIPOLYGON (((40 40, 20 45, 45 30, 40 40)), ((20 35, 45 20, 30 5, 10 10, 10 30, 20 35), (30 20, 20 25, 20 15, 30 20)))"; - - SpatialReference sr = SpatialReference.create(2163); - ProjectionTransformation projectionTransformation = new ProjectionTransformation(spatialReferenceWGS, sr); - - SimpleStringCursor simpleStringCursor = new SimpleStringCursor(wktGeom); - OperatorImportFromWktCursor wktCursor = new OperatorImportFromWktCursor(0, simpleStringCursor); - OperatorProjectCursor projectCursor = new OperatorProjectCursor(wktCursor, projectionTransformation, null); - OperatorProjectCursor reProjectCursor = new OperatorProjectCursor(projectCursor, projectionTransformation.getReverse(), null); - - Polygon result = (Polygon) reProjectCursor.next(); - NonSimpleResult nonSimpleResult = new NonSimpleResult(); - OperatorSimplify simplify = (OperatorSimplify) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.Simplify); - boolean isSimple = simplify.isSimpleAsFeature(result, spatialReferenceWGS, true, nonSimpleResult, null); - assertTrue(isSimple); - - simpleStringCursor = new SimpleStringCursor(wktGeom, 99); - wktCursor = new OperatorImportFromWktCursor(0, simpleStringCursor); - Polygon expected = (Polygon) wktCursor.next(); - assertTrue(GeometryEngine.isSimple(expected, spatialReferenceWGS)); - assertEquals(wktCursor.getGeometryID(), 99); - assertEquals(expected.calculateArea2D(), result.calculateArea2D(), 1e-10); - } - - @Test - public void testProjectionTransformation() { - int count = 400; - Envelope e = new Envelope(0,0,40, 40); - RandomCoordinateGenerator randomCoordinateGenerator = new RandomCoordinateGenerator(count, e, SpatialReference.create(4326).getTolerance()); - MultiPoint multiPoint = new MultiPoint(); - for (int i = 0; i < count; i++) { - multiPoint.add(randomCoordinateGenerator._GenerateNewPoint()); - } - - ProjectionTransformation projectionTransformation = ProjectionTransformation.getEqualArea(multiPoint, spatialReferenceWGS); - Geometry projected = OperatorProject.local().execute(multiPoint, projectionTransformation, null); - Geometry reprojected = OperatorProject.local().execute(projected, projectionTransformation.getReverse(), null); - - assertTrue(OperatorEquals.local().execute(reprojected, multiPoint, SpatialReference.create(104919), null)); - - Geometry reProjectedConvexhull = OperatorProject.local().execute(OperatorConvexHull.local().execute(projected, null), projectionTransformation.getReverse(), null); - Geometry convexHull = OperatorConvexHull.local().execute(multiPoint, null); - - assertEquals(convexHull.calculateArea2D(), reProjectedConvexhull.calculateArea2D(), 1); - } - - @Test - public void testGeometryEnvelope() { - MultiPoint multiPoint = new MultiPoint(); - multiPoint.add(0,0); - multiPoint.add(0,20); - multiPoint.add(40,40); - - ProjectionTransformation projectionTransformation = ProjectionTransformation.getEqualArea(multiPoint, spatialReferenceWGS); - Geometry projected = OperatorProject.local().execute(multiPoint, projectionTransformation, null); - - Envelope2D envelope2D = new Envelope2D(); - projected.queryEnvelope2D(envelope2D); - - assertTrue(envelope2D.xmax != 40); - - } - - @Test - public void testDateline() { - String wktGeom = "POLYGON((-185 0, -185 10, -170 10, -170 0),(-182 3, -172 3, -172 7, -182 7))"; - Geometry original = OperatorImportFromWkt.local().execute( - 0, - Geometry.Type.Unknown, - wktGeom, - null); - Geometry projected = OperatorProject.local().execute( - original, - projectionTransformationToMerc, null); - - assertNotNull(projected); - - Geometry reProjected = OperatorProject.local().execute(projected, projectionTransformationToWGS, null); - assertNotNull(reProjected); - - NonSimpleResult nonSimpleResult = new NonSimpleResult(); - assertTrue(OperatorSimplify.local().isSimpleAsFeature(reProjected, spatialReferenceWGS, true, nonSimpleResult, null)); - - assertEquals(original.calculateArea2D(), reProjected.calculateArea2D(), 0.00001); - } - - @Test - public void testWrapNotWGS84() { - String wktGeom = "POLYGON((-185 0, -185 10, -170 10, -170 0),(-182 3, -172 3, -172 7, -182 7))"; - Geometry original = OperatorImportFromWkt.local().execute(0,Geometry.Type.Unknown, wktGeom,null); - ProjectionTransformation projectionTransformation = new ProjectionTransformation(SpatialReference.create(4269), spatialReferenceMerc); - Geometry projected = OperatorProject.local().execute( - original, - projectionTransformation, null); - - assertNotNull(projected); - - Geometry reProjected = OperatorProject.local().execute(projected, projectionTransformation.getReverse(), null); - assertNotNull(reProjected); - - NonSimpleResult nonSimpleResult = new NonSimpleResult(); - assertTrue(OperatorSimplify.local().isSimpleAsFeature(reProjected, SpatialReference.create(4269), true, nonSimpleResult, null)); - - assertEquals(original.calculateArea2D(), reProjected.calculateArea2D(), 0.00001); - } - - @Test - public void testReProjectMultiPoint() { - MultiPoint multiPoint = new MultiPoint(); - for (double longitude = -180; longitude < 180; longitude+=10.0) { - for (double latitude = -80; latitude < 80; latitude+=10.0) { - multiPoint.add(longitude, latitude); - } - } - - ProjectionTransformation projectionTransformation = new ProjectionTransformation(SpatialReference.create(4326), SpatialReference.create(3857)); - Geometry projected = OperatorProject.local().execute(multiPoint, projectionTransformation, null); - Geometry reprojected = OperatorProject.local().execute(projected, projectionTransformation.getReverse(), null); - - assertTrue(OperatorEquals.local().execute(multiPoint, reprojected, SpatialReference.create(4326), null)); - } - - @Test - public void testExampleLAEA_bug() { - double distance = 800; - SpatialReference spatialReferenceLAEAeurope = SpatialReference.create(3035); - ProjectionTransformation projectionTransformation = new ProjectionTransformation(spatialReferenceWGS, spatialReferenceLAEAeurope); - Point europeCenter = new Point(10, 52); - Point projectedCenter = (Point)OperatorProject.local().execute(europeCenter, projectionTransformation, null); - Point projected200mN = new Point(projectedCenter.getX(), projectedCenter.getY() + distance); - Point projected200mE = new Point(projectedCenter.getX() - distance, projectedCenter.getY()); - Point reprojected200mN = (Point)OperatorProject.local().execute(projected200mN, projectionTransformation.getReverse(), null); - Point reprojected200mE = (Point)OperatorProject.local().execute(projected200mE, projectionTransformation.getReverse(), null); - double distanceEast = SpatialReferenceImpl.geodesicDistanceOnWGS84Impl(europeCenter, reprojected200mE); - double distanceNorth = SpatialReferenceImpl.geodesicDistanceOnWGS84Impl(europeCenter, reprojected200mN); - assertEquals(distance, distanceNorth, 1e-3); - assertEquals(distance, distanceEast, 1e-6); - - projectionTransformation = null; - ProjectionTransformation projectionTransformationEA = ProjectionTransformation.getEqualArea(europeCenter, spatialReferenceWGS); - projectedCenter = (Point)OperatorProject.local().execute(europeCenter, projectionTransformationEA, null); - projected200mN = new Point(projectedCenter.getX(), projectedCenter.getY() + distance); - projected200mE = new Point(projectedCenter.getX() - distance, projectedCenter.getY()); - reprojected200mN = (Point)OperatorProject.local().execute(projected200mN, projectionTransformationEA.getReverse(), null); - reprojected200mE = (Point)OperatorProject.local().execute(projected200mE, projectionTransformationEA.getReverse(), null); - distanceEast = SpatialReferenceImpl.geodesicDistanceOnWGS84Impl(europeCenter, reprojected200mE); - distanceNorth = SpatialReferenceImpl.geodesicDistanceOnWGS84Impl(europeCenter, reprojected200mN); - assertEquals(distance, distanceNorth, 1e-3); - assertEquals(distance, distanceEast, 1e-6); - - } - - @Test - public void testEqualAreaProjection() { - // POINT (-70.651886936570745 43.134525834585826) - Point point = new Point(-70.651886936570745, 43.1345088834585826); - SpatialReference utmZone = SpatialReference.createUTM(point); - SpatialReference spatialReferenceWGS84 = SpatialReference.create(4326); - ProjectionTransformation projectionTransformationUTM = new ProjectionTransformation(spatialReferenceWGS84, utmZone); - - ProjectionTransformation projectionTransformationEA = ProjectionTransformation.getEqualArea(point, spatialReferenceWGS84); - - Geometry geodesicBuffered = OperatorGeodesicBuffer.local().execute( - point, - spatialReferenceWGS84, - GeodeticCurveType.Geodesic, - 135.7, - 0.07, - false, - null); - - Geometry utmPoint = GeometryEngine.project(point, spatialReferenceWGS84, utmZone); - Geometry utmPoint2 = OperatorProject.local().execute(point, projectionTransformationUTM, null); - assertTrue(utmPoint.equals(utmPoint2)); - - Geometry utmReprojected = GeometryEngine.project(utmPoint, utmZone, spatialReferenceWGS84); - Geometry utmReprojected2 = OperatorProject.local().execute(utmPoint2, projectionTransformationUTM.getReverse(), null); - assertTrue(utmReprojected.equals(utmReprojected2)); - - Geometry utmBuffer = OperatorBuffer.local().execute(utmPoint, utmZone, 135.6, null); - Geometry reProjectedUTMBuffer = OperatorProject.local().execute(utmBuffer, projectionTransformationUTM.getReverse(), null); - double differenceVal = GeometryEngine.difference(reProjectedUTMBuffer, geodesicBuffered, spatialReferenceWGS84).calculateArea2D(); - assertEquals(differenceVal, 0.0, 1e-14); - - assertTrue(GeometryEngine.contains(geodesicBuffered, reProjectedUTMBuffer, spatialReferenceWGS84)); - - Geometry aziEAPoint = OperatorProject.local().execute(point, projectionTransformationEA, null); - Geometry aziEABuffere = OperatorBuffer.local().execute(aziEAPoint, null, 135.6, null); - assertEquals(aziEABuffere.calculateArea2D(), utmBuffer.calculateArea2D(), 1e-5); - Geometry reProjectedAZIBuffer = OperatorProject.local().execute(aziEABuffere, projectionTransformationEA.getReverse(), null); - - Geometry projectedGeodesicAZI = OperatorProject.local().execute(geodesicBuffered, projectionTransformationEA, null); - Geometry reprojectedGeodesicAZI = OperatorProject.local().execute(projectedGeodesicAZI, projectionTransformationEA.getReverse(), null); - differenceVal = GeometryEngine.difference(reProjectedAZIBuffer, reprojectedGeodesicAZI, spatialReferenceWGS84).calculateArea2D(); - assertEquals(differenceVal, 0.0, 1e-14); - - differenceVal = GeometryEngine.difference(reProjectedAZIBuffer, geodesicBuffered, spatialReferenceWGS84).calculateArea2D(); - assertEquals(differenceVal, 0.0, 1e-14); - - assertTrue(GeometryEngine.contains(geodesicBuffered, reProjectedAZIBuffer, spatialReferenceWGS84)); + static { + System.loadLibrary("proj"); + } + + SpatialReference spatialReferenceWGS = SpatialReference.create(4326); + SpatialReference spatialReferenceMerc = SpatialReference.create(3857); + ProjectionTransformation projectionTransformationToMerc = new ProjectionTransformation(spatialReferenceWGS, spatialReferenceMerc); + ProjectionTransformation projectionTransformationToWGS = new ProjectionTransformation(spatialReferenceMerc, spatialReferenceWGS); + + @Before + public void setUp() { + + } + + @Test + public void testProj4() throws Exception { + PJ sourcePJ = new PJ("+init=epsg:32632"); // (x,y) axis order + PJ targetPJ = new PJ("+proj=latlong +datum=WGS84"); // (λ,φ) axis order + PJ sourcePJ_utm = new PJ("+proj=utm +zone=32 +datum=WGS84 +units=m +no_defs "); + PJ targetPJ_4326 = new PJ("+init=epsg:4326"); + + double[] coordinates_32632 = { + 500000, 0, // First coordinate + 400000, 100000, // Second coordinate + 600000, -100000 // Third coordinate + }; + + double[] coordinates_WGS84 = Arrays.copyOf(coordinates_32632, coordinates_32632.length); + double[] coordinates_4326 = Arrays.copyOf(coordinates_32632, coordinates_32632.length); + + sourcePJ.transform(targetPJ, 2, coordinates_WGS84, 0, 3); + sourcePJ.transform(targetPJ_4326, 2, coordinates_4326, 0, 3); + + for (int i = 0; i < coordinates_WGS84.length; i++) { + if (i == 1) + continue; + + assertTrue((Math.abs(coordinates_WGS84[i] - coordinates_32632[i])) > 1); + assertTrue((Math.abs(coordinates_4326[i] - coordinates_32632[i])) > 1); + assertEquals(coordinates_4326[i], coordinates_WGS84[i]); + } + } + + @Test + public void testProj4Strings() { + SpatialReference spatialReference = SpatialReference.create(4326); + assertEquals("+init=epsg:4326", spatialReference.getProj4()); + + spatialReference = SpatialReference.create(32632); + assertEquals("+init=epsg:32632", spatialReference.getProj4()); + } + + @Test + public void testProjectionCursor_1() { + ProjectionTransformation projectionTransformation = new ProjectionTransformation(SpatialReference.create(32632), SpatialReference.create(4326)); + Point point = new Point(500000, 0); + Point pointOut = (Point) OperatorProject.local().execute(point, projectionTransformation, null); + assertNotNull(pointOut); + assertTrue(Math.abs(point.getX() - pointOut.getY()) > 1); + projectionTransformation = new ProjectionTransformation(SpatialReference.create(4326), SpatialReference.create(32632)); + Point originalPoint = (Point) OperatorProject.local().execute(pointOut, projectionTransformation, null); + assertEquals(originalPoint.getX(), point.getX()); + assertEquals(originalPoint.getY(), point.getY()); + } + + @Test + public void testProjectMultiPoint() { + ProjectionTransformation projectionTransformation = new ProjectionTransformation(SpatialReference.create(32632), SpatialReference.create(4326)); + MultiPoint multiPoint = new MultiPoint(); + multiPoint.add(500000, 0); + multiPoint.add(400000, 100000); + multiPoint.add(600000, -100000); + MultiPoint multiPointOut = (MultiPoint) OperatorProject.local().execute(multiPoint, projectionTransformation, null); + assertNotNull(multiPointOut); + assertFalse(multiPointOut.equals(multiPoint)); + assertEquals(multiPoint.getPointCount(), multiPointOut.getPointCount()); + projectionTransformation = new ProjectionTransformation(SpatialReference.create(4326), SpatialReference.create(32632)); + MultiPoint originalMultiPoint = (MultiPoint) OperatorProject.local().execute(multiPointOut, projectionTransformation, null); + + for (int i = 0; i < multiPoint.getPointCount(); i++) { + assertEquals(multiPoint.getPoint(i).getX(), originalMultiPoint.getPoint(i).getX(), 1e-9); + assertEquals(multiPoint.getPoint(i).getY(), originalMultiPoint.getPoint(i).getY(), 1e-9); + } + } + + @Test + public void testProjectPolyline() { + ProjectionTransformation projectionTransformation = new ProjectionTransformation(SpatialReference.create(32632), SpatialReference.create(4326)); + Polyline polyline = new Polyline(); + polyline.startPath(500000, 0); + polyline.lineTo(400000, 100000); + polyline.lineTo(600000, -100000); + Polyline polylineOut = (Polyline) OperatorProject.local().execute(polyline, projectionTransformation, null); + assertNotNull(polylineOut); + assertFalse(polylineOut.equals(polyline)); + + MultiPathImpl polyline_impl = (MultiPathImpl) polylineOut._getImpl(); + int point_count = polyline_impl.getPointCount(); + int path_count = polyline_impl.getPathCount(); + assertEquals(point_count, 3); + assertEquals(path_count, 1); + + assertEquals(polyline.getPointCount(), polylineOut.getPointCount()); + projectionTransformation = new ProjectionTransformation(SpatialReference.create(4326), SpatialReference.create(32632)); + Polyline originalPolyline = (Polyline) OperatorProject.local().execute(polylineOut, projectionTransformation, null); + for (int i = 0; i < polyline.getPointCount(); i++) { + assertEquals(polyline.getPoint(i).getX(), originalPolyline.getPoint(i).getX(), 1e-9); + assertEquals(polyline.getPoint(i).getY(), originalPolyline.getPoint(i).getY(), 1e-9); + } + } + + @Test + public void testProjectPolygon() { + ProjectionTransformation projectionTransformation = new ProjectionTransformation(SpatialReference.create(32632), SpatialReference.create(4326)); + Polygon polygon = new Polygon(); + polygon.startPath(500000, 0); + polygon.lineTo(400000, 100000); + polygon.lineTo(600000, -100000); + polygon.closeAllPaths(); + Polygon polygonOut = (Polygon) OperatorProject.local().execute(polygon, projectionTransformation, null); + assertNotNull(polygonOut); + assertFalse(polygonOut.equals(polygon)); + assertEquals(polygon.getPointCount(), polygonOut.getPointCount()); + projectionTransformation = new ProjectionTransformation(SpatialReference.create(4326), SpatialReference.create(32632)); + Polygon originalPolygon = (Polygon) OperatorProject.local().execute(polygonOut, projectionTransformation, null); + + for (int i = 0; i < polygon.getPointCount(); i++) { + assertEquals(polygon.getPoint(i).getX(), originalPolygon.getPoint(i).getX(), 1e-9); + assertEquals(polygon.getPoint(i).getY(), originalPolygon.getPoint(i).getY(), 1e-9); + } + } + + @Test + public void testProjectEnvelope() { + Envelope2D envelope2D = new Envelope2D(-10000, -10000, 10000, 10000); + String proj4 = String.format( + "+proj=laea +lat_0=%f +lon_0=%f +x_0=0.0 +y_0=0.0 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs", + 0f, 0f); + + SpatialReference spatialReference = SpatialReference.createFromProj4(proj4); + SpatialReference spatialReferenceWgs84 = SpatialReference.create(4326); + ProjectionTransformation projectionTransformation = new ProjectionTransformation(spatialReference, spatialReferenceWgs84); + Polygon polygon = (Polygon) OperatorProject.local().execute(new Envelope(envelope2D), projectionTransformation, null); + assertNotNull(polygon); + Point2D point2D = new Point2D(); + double a = 6378137.0; // radius of spheroid for WGS_1984 + double e2 = 0.0066943799901413165; // ellipticity for WGS_1984 + Envelope2D gcsEnvelope = new Envelope2D(); + polygon.queryEnvelope2D(gcsEnvelope); + GeoDist.getEnvCenter(a, e2, gcsEnvelope, point2D); + assertEquals(point2D.x, 0, 1e-14); + assertEquals(point2D.y, 0, 1e-6); + + // TODO + } + + @Test + public void testEPSGCodes() { + String wktGeom = "MULTIPOLYGON (((6311583.246999994 1871386.1630000025, 6311570 1871325, 6311749.093999997 1871285.9699999988, 6311768.118000001 1871345.9619999975, 6311583.246999994 1871386.1630000025)))"; + SpatialReference spatialReference = SpatialReference.create(2230); + SpatialReference spatialReferenceWgs84 = SpatialReference.create(4326); + ProjectionTransformation projectionTransformation = new ProjectionTransformation(spatialReference, spatialReferenceWgs84); + SimpleStringCursor simpleStringCursor = new SimpleStringCursor(wktGeom); + OperatorImportFromWktCursor wktCursor = new OperatorImportFromWktCursor(0, simpleStringCursor); + OperatorProjectCursor projectCursor = new OperatorProjectCursor(wktCursor, projectionTransformation, null); + Geometry geometry = projectCursor.next(); + + assertNotNull(geometry); + } + + @Test + public void testFoldInto360() { + String wktGeom = "POLYGON((120 48.2246726495652,140 48.2246726495652,140 25.799891182088334,120 25.799891182088334,120 48.2246726495652))"; + SimpleStringCursor result = new SimpleStringCursor(wktGeom); + + OperatorImportFromWktCursor wktCursor = new OperatorImportFromWktCursor(0, result); + Geometry expectedGeometry = wktCursor.next(); + + String wktGeom360 = "POLYGON((480 48.2246726495652,500 48.2246726495652,500 25.799891182088334,480 25.799891182088334,480 48.2246726495652))"; + SimpleStringCursor test = new SimpleStringCursor(wktGeom360); + wktCursor = new OperatorImportFromWktCursor(0, test); + OperatorProjectCursor projectCursor = new OperatorProjectCursor(wktCursor, this.projectionTransformationToMerc, null); + OperatorProjectCursor reProjectCursor = new OperatorProjectCursor(projectCursor, this.projectionTransformationToWGS, null); + + Polygon actualGeometry = (Polygon) reProjectCursor.next(); + + assertTrue(GeometryEngine.equals(actualGeometry, expectedGeometry, spatialReferenceWGS)); + } + + + @Test + public void testWrapTriangle() { + String wktGeom = "POLYGON((167 30, 201 49, 199 18, 167 30))"; + SimpleStringCursor simpleStringCursor = new SimpleStringCursor(wktGeom); + OperatorImportFromWktCursor wktCursor = new OperatorImportFromWktCursor(0, simpleStringCursor); + OperatorProjectCursor projectCursor = new OperatorProjectCursor(wktCursor, this.projectionTransformationToMerc, null); + OperatorProjectCursor reProjectCursor = new OperatorProjectCursor(projectCursor, this.projectionTransformationToWGS, null); + + Polygon result = (Polygon) reProjectCursor.next(); + NonSimpleResult nonSimpleResult = new NonSimpleResult(); + OperatorSimplify simplify = (OperatorSimplify) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.Simplify); + boolean isSimple = simplify.isSimpleAsFeature(result, spatialReferenceWGS, true, nonSimpleResult, null); + + simpleStringCursor = new SimpleStringCursor(wktGeom); + wktCursor = new OperatorImportFromWktCursor(0, simpleStringCursor); + Polygon expected = (Polygon) wktCursor.next(); + assertTrue(GeometryEngine.isSimple(expected, spatialReferenceWGS)); + + assertEquals(expected.calculateArea2D(), result.calculateArea2D(), 1e-10); + } + + @Test + public void testWrapTriangleOtherSide() { + String wktGeom = "POLYGON((-193 -30, -160 -29, -158 -40, -193 -30))"; + SimpleStringCursor simpleStringCursor = new SimpleStringCursor(wktGeom); + OperatorImportFromWktCursor wktCursor = new OperatorImportFromWktCursor(0, simpleStringCursor); + OperatorProjectCursor projectCursor = new OperatorProjectCursor(wktCursor, this.projectionTransformationToMerc, null); + OperatorProjectCursor reProjectCursor = new OperatorProjectCursor(projectCursor, this.projectionTransformationToWGS, null); + + Polygon result = (Polygon) reProjectCursor.next(); + NonSimpleResult nonSimpleResult = new NonSimpleResult(); + OperatorSimplify simplify = (OperatorSimplify) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.Simplify); + boolean isSimple = simplify.isSimpleAsFeature(result, spatialReferenceWGS, true, nonSimpleResult, null); + + simpleStringCursor = new SimpleStringCursor(wktGeom); + wktCursor = new OperatorImportFromWktCursor(0, simpleStringCursor); + Polygon expected = (Polygon) wktCursor.next(); + assertTrue(GeometryEngine.isSimple(expected, spatialReferenceWGS)); + + assertEquals(expected.calculateArea2D(), result.calculateArea2D(), .00000000001); + } + + @Test + public void testWrap() { + String wktGeom = "POLYGON((167.87109375 30.751277776257812," + + "201.43359375 49.38237278700955," + + "232.49609375 -5.266007882805485," + + "116.19500625 -17.308687886770024," + + "199.54296875 18.979025953255267," + + "126.03515625 12.897489183755892," + + "167.87109375 30.751277776257812))"; + SimpleStringCursor simpleStringCursor = new SimpleStringCursor(wktGeom); + OperatorImportFromWktCursor wktCursor = new OperatorImportFromWktCursor(0, simpleStringCursor); + OperatorProjectCursor projectCursor = new OperatorProjectCursor(wktCursor, this.projectionTransformationToMerc, null); + OperatorProjectCursor reProjectCursor = new OperatorProjectCursor(projectCursor, this.projectionTransformationToWGS, null); + + Polygon result = (Polygon) reProjectCursor.next(); + NonSimpleResult nonSimpleResult = new NonSimpleResult(); + OperatorSimplify simplify = (OperatorSimplify) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.Simplify); + boolean isSimple = simplify.isSimpleAsFeature(result, spatialReferenceWGS, true, nonSimpleResult, null); + + simpleStringCursor = new SimpleStringCursor(wktGeom); + wktCursor = new OperatorImportFromWktCursor(0, simpleStringCursor); + Polygon expected = (Polygon) wktCursor.next(); + assertTrue(GeometryEngine.isSimple(expected, spatialReferenceWGS)); + + assertEquals(expected.calculateArea2D(), result.calculateArea2D(), 1e-10); + } + + @Test + public void testAlbers() { + String wktGeom = "MULTIPOLYGON (((40 40, 20 45, 45 30, 40 40)), ((20 35, 45 20, 30 5, 10 10, 10 30, 20 35), (30 20, 20 25, 20 15, 30 20)))"; + + SpatialReference sr = SpatialReference.create(2163); + ProjectionTransformation projectionTransformation = new ProjectionTransformation(spatialReferenceWGS, sr); + + SimpleStringCursor simpleStringCursor = new SimpleStringCursor(wktGeom); + OperatorImportFromWktCursor wktCursor = new OperatorImportFromWktCursor(0, simpleStringCursor); + OperatorProjectCursor projectCursor = new OperatorProjectCursor(wktCursor, projectionTransformation, null); + OperatorProjectCursor reProjectCursor = new OperatorProjectCursor(projectCursor, projectionTransformation.getReverse(), null); + + Polygon result = (Polygon) reProjectCursor.next(); + NonSimpleResult nonSimpleResult = new NonSimpleResult(); + OperatorSimplify simplify = (OperatorSimplify) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.Simplify); + boolean isSimple = simplify.isSimpleAsFeature(result, spatialReferenceWGS, true, nonSimpleResult, null); + assertTrue(isSimple); + + simpleStringCursor = new SimpleStringCursor(wktGeom, 99); + wktCursor = new OperatorImportFromWktCursor(0, simpleStringCursor); + Polygon expected = (Polygon) wktCursor.next(); + assertTrue(GeometryEngine.isSimple(expected, spatialReferenceWGS)); + assertEquals(wktCursor.getGeometryID(), 99); + assertEquals(expected.calculateArea2D(), result.calculateArea2D(), 1e-10); + } + + @Test + public void testProjectionTransformation() { + int count = 400; + Envelope e = new Envelope(0, 0, 40, 40); + RandomCoordinateGenerator randomCoordinateGenerator = new RandomCoordinateGenerator(count, e, SpatialReference.create(4326).getTolerance()); + MultiPoint multiPoint = new MultiPoint(); + for (int i = 0; i < count; i++) { + multiPoint.add(randomCoordinateGenerator._GenerateNewPoint()); + } + + ProjectionTransformation projectionTransformation = ProjectionTransformation.getEqualArea(multiPoint, spatialReferenceWGS); + Geometry projected = OperatorProject.local().execute(multiPoint, projectionTransformation, null); + Geometry reprojected = OperatorProject.local().execute(projected, projectionTransformation.getReverse(), null); + + assertTrue(OperatorEquals.local().execute(reprojected, multiPoint, SpatialReference.create(104919), null)); + + Geometry reProjectedConvexhull = OperatorProject.local().execute(OperatorConvexHull.local().execute(projected, null), projectionTransformation.getReverse(), null); + Geometry convexHull = OperatorConvexHull.local().execute(multiPoint, null); + + assertEquals(convexHull.calculateArea2D(), reProjectedConvexhull.calculateArea2D(), 1); + } + + @Test + public void testGeometryEnvelope() { + MultiPoint multiPoint = new MultiPoint(); + multiPoint.add(0, 0); + multiPoint.add(0, 20); + multiPoint.add(40, 40); + + ProjectionTransformation projectionTransformation = ProjectionTransformation.getEqualArea(multiPoint, spatialReferenceWGS); + Geometry projected = OperatorProject.local().execute(multiPoint, projectionTransformation, null); + + Envelope2D envelope2D = new Envelope2D(); + projected.queryEnvelope2D(envelope2D); + + assertTrue(envelope2D.xmax != 40); + + } + + @Test + public void testDateline() { + String wktGeom = "POLYGON((-185 0, -185 10, -170 10, -170 0),(-182 3, -172 3, -172 7, -182 7))"; + Geometry original = OperatorImportFromWkt.local().execute( + 0, + Geometry.Type.Unknown, + wktGeom, + null); + Geometry projected = OperatorProject.local().execute( + original, + projectionTransformationToMerc, null); + + assertNotNull(projected); + + Geometry reProjected = OperatorProject.local().execute(projected, projectionTransformationToWGS, null); + assertNotNull(reProjected); + + NonSimpleResult nonSimpleResult = new NonSimpleResult(); + assertTrue(OperatorSimplify.local().isSimpleAsFeature(reProjected, spatialReferenceWGS, true, nonSimpleResult, null)); + + assertEquals(original.calculateArea2D(), reProjected.calculateArea2D(), 0.00001); + } + + @Test + public void testWrapNotWGS84() { + String wktGeom = "POLYGON((-185 0, -185 10, -170 10, -170 0),(-182 3, -172 3, -172 7, -182 7))"; + Geometry original = OperatorImportFromWkt.local().execute(0, Geometry.Type.Unknown, wktGeom, null); + ProjectionTransformation projectionTransformation = new ProjectionTransformation(SpatialReference.create(4269), spatialReferenceMerc); + Geometry projected = OperatorProject.local().execute( + original, + projectionTransformation, null); + + assertNotNull(projected); + + Geometry reProjected = OperatorProject.local().execute(projected, projectionTransformation.getReverse(), null); + assertNotNull(reProjected); + + NonSimpleResult nonSimpleResult = new NonSimpleResult(); + assertTrue(OperatorSimplify.local().isSimpleAsFeature(reProjected, SpatialReference.create(4269), true, nonSimpleResult, null)); + + assertEquals(original.calculateArea2D(), reProjected.calculateArea2D(), 0.00001); + } + + @Test + public void testReProjectMultiPoint() { + MultiPoint multiPoint = new MultiPoint(); + for (double longitude = -180; longitude < 180; longitude += 10.0) { + for (double latitude = -80; latitude < 80; latitude += 10.0) { + multiPoint.add(longitude, latitude); + } + } + + ProjectionTransformation projectionTransformation = new ProjectionTransformation(SpatialReference.create(4326), SpatialReference.create(3857)); + Geometry projected = OperatorProject.local().execute(multiPoint, projectionTransformation, null); + Geometry reprojected = OperatorProject.local().execute(projected, projectionTransformation.getReverse(), null); + + assertTrue(OperatorEquals.local().execute(multiPoint, reprojected, SpatialReference.create(4326), null)); + } + + @Test + public void testExampleLAEA_bug() { + double distance = 800; + SpatialReference spatialReferenceLAEAeurope = SpatialReference.create(3035); + ProjectionTransformation projectionTransformation = new ProjectionTransformation(spatialReferenceWGS, spatialReferenceLAEAeurope); + Point europeCenter = new Point(10, 52); + Point projectedCenter = (Point) OperatorProject.local().execute(europeCenter, projectionTransformation, null); + Point projected200mN = new Point(projectedCenter.getX(), projectedCenter.getY() + distance); + Point projected200mE = new Point(projectedCenter.getX() - distance, projectedCenter.getY()); + Point reprojected200mN = (Point) OperatorProject.local().execute(projected200mN, projectionTransformation.getReverse(), null); + Point reprojected200mE = (Point) OperatorProject.local().execute(projected200mE, projectionTransformation.getReverse(), null); + double distanceEast = SpatialReferenceImpl.geodesicDistanceOnWGS84Impl(europeCenter, reprojected200mE); + double distanceNorth = SpatialReferenceImpl.geodesicDistanceOnWGS84Impl(europeCenter, reprojected200mN); + assertEquals(distance, distanceNorth, 1e-3); + assertEquals(distance, distanceEast, 1e-6); + + projectionTransformation = null; + ProjectionTransformation projectionTransformationEA = ProjectionTransformation.getEqualArea(europeCenter, spatialReferenceWGS); + projectedCenter = (Point) OperatorProject.local().execute(europeCenter, projectionTransformationEA, null); + projected200mN = new Point(projectedCenter.getX(), projectedCenter.getY() + distance); + projected200mE = new Point(projectedCenter.getX() - distance, projectedCenter.getY()); + reprojected200mN = (Point) OperatorProject.local().execute(projected200mN, projectionTransformationEA.getReverse(), null); + reprojected200mE = (Point) OperatorProject.local().execute(projected200mE, projectionTransformationEA.getReverse(), null); + distanceEast = SpatialReferenceImpl.geodesicDistanceOnWGS84Impl(europeCenter, reprojected200mE); + distanceNorth = SpatialReferenceImpl.geodesicDistanceOnWGS84Impl(europeCenter, reprojected200mN); + assertEquals(distance, distanceNorth, 1e-3); + assertEquals(distance, distanceEast, 1e-6); + + } + + @Test + public void testEqualAreaProjection() { + // POINT (-70.651886936570745 43.134525834585826) + Point point = new Point(-70.651886936570745, 43.1345088834585826); + SpatialReference utmZone = SpatialReference.createUTM(point); + SpatialReference spatialReferenceWGS84 = SpatialReference.create(4326); + ProjectionTransformation projectionTransformationUTM = new ProjectionTransformation(spatialReferenceWGS84, utmZone); + + ProjectionTransformation projectionTransformationEA = ProjectionTransformation.getEqualArea(point, spatialReferenceWGS84); + + Geometry geodesicBuffered = OperatorGeodesicBuffer.local().execute( + point, + spatialReferenceWGS84, + GeodeticCurveType.Geodesic, + 135.7, + 0.07, + false, + null); + + Geometry utmPoint = GeometryEngine.project(point, spatialReferenceWGS84, utmZone); + Geometry utmPoint2 = OperatorProject.local().execute(point, projectionTransformationUTM, null); + assertTrue(utmPoint.equals(utmPoint2)); + + Geometry utmReprojected = GeometryEngine.project(utmPoint, utmZone, spatialReferenceWGS84); + Geometry utmReprojected2 = OperatorProject.local().execute(utmPoint2, projectionTransformationUTM.getReverse(), null); + assertTrue(utmReprojected.equals(utmReprojected2)); + + Geometry utmBuffer = OperatorBuffer.local().execute(utmPoint, utmZone, 135.6, null); + Geometry reProjectedUTMBuffer = OperatorProject.local().execute(utmBuffer, projectionTransformationUTM.getReverse(), null); + double differenceVal = GeometryEngine.difference(reProjectedUTMBuffer, geodesicBuffered, spatialReferenceWGS84).calculateArea2D(); + assertEquals(differenceVal, 0.0, 1e-14); + + assertTrue(GeometryEngine.contains(geodesicBuffered, reProjectedUTMBuffer, spatialReferenceWGS84)); + + Geometry aziEAPoint = OperatorProject.local().execute(point, projectionTransformationEA, null); + Geometry aziEABuffere = OperatorBuffer.local().execute(aziEAPoint, null, 135.6, null); + assertEquals(aziEABuffere.calculateArea2D(), utmBuffer.calculateArea2D(), 1e-5); + Geometry reProjectedAZIBuffer = OperatorProject.local().execute(aziEABuffere, projectionTransformationEA.getReverse(), null); + + Geometry projectedGeodesicAZI = OperatorProject.local().execute(geodesicBuffered, projectionTransformationEA, null); + Geometry reprojectedGeodesicAZI = OperatorProject.local().execute(projectedGeodesicAZI, projectionTransformationEA.getReverse(), null); + differenceVal = GeometryEngine.difference(reProjectedAZIBuffer, reprojectedGeodesicAZI, spatialReferenceWGS84).calculateArea2D(); + assertEquals(differenceVal, 0.0, 1e-14); + + differenceVal = GeometryEngine.difference(reProjectedAZIBuffer, geodesicBuffered, spatialReferenceWGS84).calculateArea2D(); + assertEquals(differenceVal, 0.0, 1e-14); + + assertTrue(GeometryEngine.contains(geodesicBuffered, reProjectedAZIBuffer, spatialReferenceWGS84)); // String wktInput = "POLYGON ((-70.651656936570745 43.135157834585826,-70.651570654984525 43.135150076925918,-70.651511247908587 43.135155437576621,-70.651490101488349 43.135169249238288,-70.651490181628759 43.135200763774868,-70.651510336532638 43.135249995303397,-70.651530872098633 43.135299226354952,-70.651527230781454 43.13533529757845,-70.651492643684321 43.135349305799508,-70.651420172717224 43.135354852495823,-70.651358095085072 43.135346745253884,-70.651247805462717 43.1353033127629,-70.651151361236941 43.135246176463966,-70.651124154255413 43.135206047556842,-70.651131534466685 43.135151913051203,-70.651155914561755 43.135115542493892,-70.651228730259774 43.135051460048707,-70.651305024993519 43.134973818456416,-70.651360674948108 43.134914489191551,-70.651385078643216 43.134864606853156,-70.651402827815218 43.134810322639233,-70.651410310326284 43.134688652284062,-70.651418383361829 43.134517448375689,-70.651411370788409 43.134413996600074,-70.651390876709428 43.134337752182525,-70.651346755889904 43.134225832686319,-70.651289063395154 43.134109606122337,-70.651241242017051 43.133988734078358,-70.651230854601764 43.133916846697829,-70.651221013347353 43.133822439140715,-70.651200519724128 43.133746194674302,-70.651218268699594 43.133691907971006,-70.651249886578313 43.133610413350418,-70.651273539332081 43.133547040518167,-70.651322422674269 43.133478800504768,-70.651363984222755 43.133424172537978,-70.651409243106613 43.133378494590104,-70.651437060507462 43.133355583224628,-70.651492145648632 43.133332275678633,-70.651599176252716 43.133326227462319,-70.651675204034788 43.133338636120527,-70.65179240423565 43.133381970944697,-70.651905761872953 43.133425353603045,-70.652022336036893 43.133459688797871,-70.652087607730962 43.133472252516562,-70.652149929372143 43.133489361765591,-70.652232540703992 43.133546699550045,-70.652400720753761 43.133656829257461,-70.652544825855031 43.133771806958798,-70.652698657471404 43.133891149422396,-70.652757214424 43.133939825915917,-70.652829643131227 43.133961291723317,-70.652898471779253 43.133991812912122,-70.652963804959569 43.134049399817712,-70.652994471176711 43.134089475795044,-70.653000937222828 43.134129903976664,-70.653000836372897 43.134197439788288,-70.652972837499135 43.134256375321229,-70.652903321638362 43.134342923487154,-70.652853489821567 43.134447199036558,-70.652811504521395 43.134528843881576,-70.652776716073816 43.134592380423527,-70.652745241323998 43.134664872485907,-70.652703717209832 43.134692485155824,-70.65263790191085 43.134702441934749,-70.652537796343609 43.13469488220742,-70.652481986521252 43.134691185475688,-70.652416288981371 43.134705643385693,-70.652347112331768 43.134733655368471,-70.652274294763117 43.134797738553125,-70.652239263183958 43.134852272522785,-70.652214826278225 43.134929165745028,-70.652217533236211 43.135001163954207,-70.652248296977746 43.135059250554882,-70.652327397729081 43.135157158057844,-70.652414500765317 43.135209927851037,-70.6524582645621 43.135222802033766,-70.652470512866358 43.135249637832572,-70.652646824360005 43.135404671730349,-70.652680946443695 43.135444700365824,-70.652691113545444 43.135494075980539,-70.652680299690047 43.135534756334458,-70.652642334694633 43.135580326883741,-70.6525831461027 43.135608197219,-70.65250042683256 43.135618395612582,-70.652403778584315 43.1356107883392,-70.652328034290349 43.135580366756479,-70.652207940292428 43.135501055652128,-70.652084166050003 43.135399292820672,-70.651994153636025 43.135324055019495,-70.651897729053019 43.13525341019011,-70.651815354685922 43.135205077192047,-70.651746646220062 43.135179051560065,-70.651656936570745 43.135157834585826))"; // Geometry input = OperatorImportFromWkt.local().execute(0, Geometry.Type.Unknown, wktInput, null); @@ -487,85 +487,85 @@ public void testEqualAreaProjection() { // assertEquals(encircled.calculateArea2D(), buffered.calculateArea2D(), 1e-8); // assertEquals(0.0, OperatorDifference.local().execute(encircled, buffered, spatialReferenceWGS84, null).calculateArea2D(), 1e-8); // assertTrue(GeometryEngine.contains(buffered, encircled, spatialReferenceWGS84)); - } - - @Test - public void testETRS() { - Point point = new Point(-180, -90); - SimpleGeometryCursor simpleGeometryCursor = new SimpleGeometryCursor(point); - - ProjectionTransformation projectionTransformation = new ProjectionTransformation(SpatialReference.create(4326), SpatialReference.create(3035)); - OperatorProjectCursor projectCursor = new OperatorProjectCursor(simpleGeometryCursor, projectionTransformation, null); - OperatorProjectCursor reProjectCursor = new OperatorProjectCursor(projectCursor, projectionTransformation.getReverse(), null); - - while (reProjectCursor.hasNext()) { - Geometry geometry = reProjectCursor.next(); - assertTrue(geometry.isEmpty()); - } - } - - @Test - public void testProjectionTrans() { - Point point = new Point(-180, -90); - SimpleGeometryCursor simpleGeometryCursor = new SimpleGeometryCursor(point); - - ProjectionTransformation projectionTransformation = new ProjectionTransformation(null, SpatialReference.create(3035)); - OperatorProjectCursor projectCursor = new OperatorProjectCursor(simpleGeometryCursor, projectionTransformation, null); - OperatorProjectCursor reProjectCursor = new OperatorProjectCursor(projectCursor, projectionTransformation.getReverse(), null); - - - while (reProjectCursor.hasNext()) { - try { - Geometry geometry = reProjectCursor.next(); - assertTrue(geometry.isEmpty()); - } catch (GeometryException exception) { - assertEquals("From and To Spatial references required to Project Geometry", exception.getMessage()); - } - } - } - - @Test - public void testIdNumber() { - assertEquals(0, Project.ordinal()); - assertEquals(1, ExportToJson.ordinal()); - } - - @Test - public void testAziEA() { - MultiPoint multiPoint = new MultiPoint(); - multiPoint.add(0,0); - multiPoint.add(1,1); - multiPoint.add(-1,-1); - SpatialReference utmZone = SpatialReference.createUTM(multiPoint); - SpatialReference spatialReferenceWGS84 = SpatialReference.create(4326); - ProjectionTransformation projectionTransformationUTM = new ProjectionTransformation(spatialReferenceWGS84, utmZone); - Geometry utmPoint = GeometryEngine.project(multiPoint, spatialReferenceWGS84, utmZone); - Geometry utmPoint2 = OperatorProject.local().execute(multiPoint, projectionTransformationUTM, null); - ProjectionTransformation projectionTransformationAziUTM = ProjectionTransformation.getEqualArea(utmPoint, utmZone); - ProjectionTransformation projectionTransformationAziWGS84 = ProjectionTransformation.getEqualArea(multiPoint, spatialReferenceWGS84); - Geometry aziPoint1 = OperatorProject.local().execute(utmPoint, projectionTransformationAziUTM, null); - Geometry aziPoint2 = OperatorProject.local().execute(multiPoint, projectionTransformationAziWGS84, null); - assertEquals(((MultiPoint)aziPoint1).getPoint(0).getX(), ((MultiPoint)aziPoint2).getPoint(0).getX()); - Geometry utmPoint1 = OperatorProject.local().execute(aziPoint1, projectionTransformationAziUTM.getReverse(), null); - Geometry wgs84Point1 = OperatorProject.local().execute(aziPoint2, projectionTransformationAziWGS84.getReverse(), null); - Geometry wgs84Point2 = OperatorProject.local().execute(utmPoint1, projectionTransformationUTM.getReverse(), null); - assertEquals(((MultiPoint)wgs84Point1).getPoint(2).getY(), ((MultiPoint)wgs84Point2).getPoint(2).getY(), 0.0000000000001); - } - - @Test - public void testAziRoundTrip() { - String wkt= "POLYGON ((39.99430071558862 19.99640653733888, 39.99430071558862 20.00359325081125, 40.00569928441138 20.00359325081125, 40.00569928441138 19.99640653733888, 39.99430071558862 19.99640653733888))"; - Geometry geometry = GeometryEngine.geometryFromWkt(wkt, 0, Geometry.Type.Unknown); - SpatialReference spatialReference4326 = SpatialReference.create(4326); - SpatialReference spatialReferenceAzi = SpatialReference.createEqualArea(40, 20); - - // TODO this loses data - Geometry roundTrip = GeometryEngine.project(GeometryEngine.project(geometry, spatialReference4326, spatialReferenceAzi), spatialReferenceAzi, spatialReference4326); - // TODO lost data if it were assertTrue(GeometryEngine.equals(geometry, roundTrip, spatialReference4326)); it would faile - - Geometry buffered = GeometryEngine.buffer(geometry, spatialReference4326, spatialReference4326.getTolerance() * 3); - assertTrue(GeometryEngine.contains(buffered, roundTrip, spatialReference4326)); - Geometry difference = GeometryEngine.difference(geometry, roundTrip, spatialReference4326); - assertEquals(difference.calculateArea2D(), 0.0); - } + } + + @Test + public void testETRS() { + Point point = new Point(-180, -90); + SimpleGeometryCursor simpleGeometryCursor = new SimpleGeometryCursor(point); + + ProjectionTransformation projectionTransformation = new ProjectionTransformation(SpatialReference.create(4326), SpatialReference.create(3035)); + OperatorProjectCursor projectCursor = new OperatorProjectCursor(simpleGeometryCursor, projectionTransformation, null); + OperatorProjectCursor reProjectCursor = new OperatorProjectCursor(projectCursor, projectionTransformation.getReverse(), null); + + while (reProjectCursor.hasNext()) { + Geometry geometry = reProjectCursor.next(); + assertTrue(geometry.isEmpty()); + } + } + + @Test + public void testProjectionTrans() { + Point point = new Point(-180, -90); + SimpleGeometryCursor simpleGeometryCursor = new SimpleGeometryCursor(point); + + ProjectionTransformation projectionTransformation = new ProjectionTransformation(null, SpatialReference.create(3035)); + OperatorProjectCursor projectCursor = new OperatorProjectCursor(simpleGeometryCursor, projectionTransformation, null); + OperatorProjectCursor reProjectCursor = new OperatorProjectCursor(projectCursor, projectionTransformation.getReverse(), null); + + + while (reProjectCursor.hasNext()) { + try { + Geometry geometry = reProjectCursor.next(); + assertTrue(geometry.isEmpty()); + } catch (GeometryException exception) { + assertEquals("From and To Spatial references required to Project Geometry", exception.getMessage()); + } + } + } + + @Test + public void testIdNumber() { + assertEquals(0, Project.ordinal()); + assertEquals(1, ExportToJson.ordinal()); + } + + @Test + public void testAziEA() { + MultiPoint multiPoint = new MultiPoint(); + multiPoint.add(0, 0); + multiPoint.add(1, 1); + multiPoint.add(-1, -1); + SpatialReference utmZone = SpatialReference.createUTM(multiPoint); + SpatialReference spatialReferenceWGS84 = SpatialReference.create(4326); + ProjectionTransformation projectionTransformationUTM = new ProjectionTransformation(spatialReferenceWGS84, utmZone); + Geometry utmPoint = GeometryEngine.project(multiPoint, spatialReferenceWGS84, utmZone); + Geometry utmPoint2 = OperatorProject.local().execute(multiPoint, projectionTransformationUTM, null); + ProjectionTransformation projectionTransformationAziUTM = ProjectionTransformation.getEqualArea(utmPoint, utmZone); + ProjectionTransformation projectionTransformationAziWGS84 = ProjectionTransformation.getEqualArea(multiPoint, spatialReferenceWGS84); + Geometry aziPoint1 = OperatorProject.local().execute(utmPoint, projectionTransformationAziUTM, null); + Geometry aziPoint2 = OperatorProject.local().execute(multiPoint, projectionTransformationAziWGS84, null); + assertEquals(((MultiPoint) aziPoint1).getPoint(0).getX(), ((MultiPoint) aziPoint2).getPoint(0).getX()); + Geometry utmPoint1 = OperatorProject.local().execute(aziPoint1, projectionTransformationAziUTM.getReverse(), null); + Geometry wgs84Point1 = OperatorProject.local().execute(aziPoint2, projectionTransformationAziWGS84.getReverse(), null); + Geometry wgs84Point2 = OperatorProject.local().execute(utmPoint1, projectionTransformationUTM.getReverse(), null); + assertEquals(((MultiPoint) wgs84Point1).getPoint(2).getY(), ((MultiPoint) wgs84Point2).getPoint(2).getY(), 0.0000000000001); + } + + @Test + public void testAziRoundTrip() { + String wkt = "POLYGON ((39.99430071558862 19.99640653733888, 39.99430071558862 20.00359325081125, 40.00569928441138 20.00359325081125, 40.00569928441138 19.99640653733888, 39.99430071558862 19.99640653733888))"; + Geometry geometry = GeometryEngine.geometryFromWkt(wkt, 0, Geometry.Type.Unknown); + SpatialReference spatialReference4326 = SpatialReference.create(4326); + SpatialReference spatialReferenceAzi = SpatialReference.createEqualArea(40, 20); + + // TODO this loses data + Geometry roundTrip = GeometryEngine.project(GeometryEngine.project(geometry, spatialReference4326, spatialReferenceAzi), spatialReferenceAzi, spatialReference4326); + // TODO lost data if it were assertTrue(GeometryEngine.equals(geometry, roundTrip, spatialReference4326)); it would faile + + Geometry buffered = GeometryEngine.buffer(geometry, spatialReference4326, spatialReference4326.getTolerance() * 3); + assertTrue(GeometryEngine.contains(buffered, roundTrip, spatialReference4326)); + Geometry difference = GeometryEngine.difference(geometry, roundTrip, spatialReference4326); + assertEquals(difference.calculateArea2D(), 0.0); + } } \ No newline at end of file diff --git a/src/test/java/com/esri/core/geometry/TestProjectionGigsData.java b/src/test/java/com/esri/core/geometry/TestProjectionGigsData.java index c7a6ec3f..3f31ea00 100644 --- a/src/test/java/com/esri/core/geometry/TestProjectionGigsData.java +++ b/src/test/java/com/esri/core/geometry/TestProjectionGigsData.java @@ -29,155 +29,155 @@ */ @RunWith(Parameterized.class) public class TestProjectionGigsData extends TestCase { - static { - System.loadLibrary("proj"); - } - - private Path path; - private String testName; - private String testData; - private String description; - private double[] tolConversions_i0 = new double[3]; - private double[] tolConversions_i1 = new double[3]; - private double[] tolRoundTrips_i0 = new double[3]; - private double[] tolRoundTrips_i1 = new double[3]; - private int roundTripTimes; - ProjectionTransformation leftToRightTransformation; - ProjectionTransformation rightToLeftTransformation; - private Polyline leftPolyline = new Polyline(); - private Polyline rightPolyline = new Polyline(); - private Polygon leftPolygon = new Polygon(); - private Polygon rightPolygon = new Polygon(); - private MultiPoint leftMultiPoint = new MultiPoint(); - private MultiPoint rightMultiPoint = new MultiPoint(); - - - public TestProjectionGigsData(Path path, String testName) throws java.io.IOException, org.json.JSONException { - this.path = path; - this.testName = testName; - // http://www.adam-bien.com/roller/abien/entry/java_8_reading_a_file - String content = new String(Files.readAllBytes(path), Charset.defaultCharset()); - JSONObject obj = new JSONObject(content); - this.description = obj.getString("description"); - JSONArray projectionsItems = obj.getJSONArray("projections"); - String leftProjection = projectionsItems.getString(0); - String rightProjection = projectionsItems.getString(1); - SpatialReference leftSR = SpatialReference.createFromProj4(leftProjection); - SpatialReference rightSR = SpatialReference.createFromProj4(rightProjection); - this.leftToRightTransformation = new ProjectionTransformation(leftSR, rightSR); - this.rightToLeftTransformation = new ProjectionTransformation(rightSR, leftSR); - - JSONArray coordinatePairs = obj.getJSONArray("coordinates"); - for (int i = 0; i < coordinatePairs.length(); i++) { - JSONArray coordinatePair = coordinatePairs.getJSONArray(i); - JSONArray pt1Array = coordinatePair.getJSONArray(0); - JSONArray pt2Array = coordinatePair.getJSONArray(1); - - Point pt1 = new Point(pt1Array.getDouble(0), pt1Array.getDouble(1)); - Point pt2 = new Point(pt2Array.getDouble(0), pt2Array.getDouble(1)); - if (coordinatePair.getJSONArray(0).length() == 3) { - // if point3d - pt1.setZ(pt1Array.getDouble(2)); - pt2.setZ(pt2Array.getDouble(2)); - } - - if (i == 0) { - leftPolyline.startPath(pt1); - leftPolygon.startPath(pt1); - - rightPolyline.startPath(pt2); - rightPolygon.startPath(pt2); - } else { - leftPolyline.lineTo(pt1); - leftPolygon.lineTo(pt1); - - rightPolyline.lineTo(pt2); - rightPolygon.lineTo(pt2); - } - leftMultiPoint.add(pt1); - rightMultiPoint.add(pt2); - } - - leftPolygon.closeAllPaths(); - rightPolygon.closeAllPaths(); - - /* - * "tests": [ - * {"tolerances": [2.7777777777777776e-07, 0.03], "type": "conversion"}, - * {"times": 1000, "tolerances": [5.555555555555556e-08, 0.006], "type": "roundtrip"}] - * */ - JSONArray testsItems = obj.getJSONArray("tests"); - JSONObject testObj1 = testsItems.getJSONObject(0); - JSONObject testObj2 = testsItems.getJSONObject(1); - - double tolObj1Index1 = testObj1.getJSONArray("tolerances").getDouble(0); - double tolObj2Index1 = testObj2.getJSONArray("tolerances").getDouble(0); - double[] tolObj1Index2 = new double[3]; - double[] tolObj2Index2 = new double[3]; - - if (testObj1.getJSONArray("tolerances").optJSONArray(1) != null) { - for (int i = 0; i < 3; i++) { - tolObj1Index2[i] = testObj1.getJSONArray("tolerances").getJSONArray(1).getDouble(i); - tolObj2Index2[i] = testObj2.getJSONArray("tolerances").getJSONArray(1).getDouble(i); - } - } else { - Arrays.fill(tolObj1Index2, testObj1.getJSONArray("tolerances").getDouble(1)); - Arrays.fill(tolObj2Index2, testObj2.getJSONArray("tolerances").getDouble(1)); - } - - if (testObj1.getString("type").equals("conversion")) { - Arrays.fill(this.tolConversions_i0, tolObj1Index1); - this.tolConversions_i1 = tolObj1Index2; - - Arrays.fill(this.tolRoundTrips_i0, tolObj2Index1); - this.tolRoundTrips_i1 = tolObj2Index2; - this.roundTripTimes = testObj2.getInt("times"); - } else { - Arrays.fill(this.tolConversions_i0, tolObj2Index1); - this.tolConversions_i1 = tolObj2Index2; - - Arrays.fill(this.tolRoundTrips_i0, tolObj1Index1); - this.tolRoundTrips_i1 = tolObj1Index2; - this.roundTripTimes = testObj1.getInt("times"); - } + static { + System.loadLibrary("proj"); + } + + private Path path; + private String testName; + private String testData; + private String description; + private double[] tolConversions_i0 = new double[3]; + private double[] tolConversions_i1 = new double[3]; + private double[] tolRoundTrips_i0 = new double[3]; + private double[] tolRoundTrips_i1 = new double[3]; + private int roundTripTimes; + ProjectionTransformation leftToRightTransformation; + ProjectionTransformation rightToLeftTransformation; + private Polyline leftPolyline = new Polyline(); + private Polyline rightPolyline = new Polyline(); + private Polygon leftPolygon = new Polygon(); + private Polygon rightPolygon = new Polygon(); + private MultiPoint leftMultiPoint = new MultiPoint(); + private MultiPoint rightMultiPoint = new MultiPoint(); + + + public TestProjectionGigsData(Path path, String testName) throws java.io.IOException, org.json.JSONException { + this.path = path; + this.testName = testName; + // http://www.adam-bien.com/roller/abien/entry/java_8_reading_a_file + String content = new String(Files.readAllBytes(path), Charset.defaultCharset()); + JSONObject obj = new JSONObject(content); + this.description = obj.getString("description"); + JSONArray projectionsItems = obj.getJSONArray("projections"); + String leftProjection = projectionsItems.getString(0); + String rightProjection = projectionsItems.getString(1); + SpatialReference leftSR = SpatialReference.createFromProj4(leftProjection); + SpatialReference rightSR = SpatialReference.createFromProj4(rightProjection); + this.leftToRightTransformation = new ProjectionTransformation(leftSR, rightSR); + this.rightToLeftTransformation = new ProjectionTransformation(rightSR, leftSR); + + JSONArray coordinatePairs = obj.getJSONArray("coordinates"); + for (int i = 0; i < coordinatePairs.length(); i++) { + JSONArray coordinatePair = coordinatePairs.getJSONArray(i); + JSONArray pt1Array = coordinatePair.getJSONArray(0); + JSONArray pt2Array = coordinatePair.getJSONArray(1); + + Point pt1 = new Point(pt1Array.getDouble(0), pt1Array.getDouble(1)); + Point pt2 = new Point(pt2Array.getDouble(0), pt2Array.getDouble(1)); + if (coordinatePair.getJSONArray(0).length() == 3) { + // if point3d + pt1.setZ(pt1Array.getDouble(2)); + pt2.setZ(pt2Array.getDouble(2)); + } + + if (i == 0) { + leftPolyline.startPath(pt1); + leftPolygon.startPath(pt1); + + rightPolyline.startPath(pt2); + rightPolygon.startPath(pt2); + } else { + leftPolyline.lineTo(pt1); + leftPolygon.lineTo(pt1); + + rightPolyline.lineTo(pt2); + rightPolygon.lineTo(pt2); + } + leftMultiPoint.add(pt1); + rightMultiPoint.add(pt2); + } + + leftPolygon.closeAllPaths(); + rightPolygon.closeAllPaths(); + + /* + * "tests": [ + * {"tolerances": [2.7777777777777776e-07, 0.03], "type": "conversion"}, + * {"times": 1000, "tolerances": [5.555555555555556e-08, 0.006], "type": "roundtrip"}] + * */ + JSONArray testsItems = obj.getJSONArray("tests"); + JSONObject testObj1 = testsItems.getJSONObject(0); + JSONObject testObj2 = testsItems.getJSONObject(1); + + double tolObj1Index1 = testObj1.getJSONArray("tolerances").getDouble(0); + double tolObj2Index1 = testObj2.getJSONArray("tolerances").getDouble(0); + double[] tolObj1Index2 = new double[3]; + double[] tolObj2Index2 = new double[3]; + + if (testObj1.getJSONArray("tolerances").optJSONArray(1) != null) { + for (int i = 0; i < 3; i++) { + tolObj1Index2[i] = testObj1.getJSONArray("tolerances").getJSONArray(1).getDouble(i); + tolObj2Index2[i] = testObj2.getJSONArray("tolerances").getJSONArray(1).getDouble(i); + } + } else { + Arrays.fill(tolObj1Index2, testObj1.getJSONArray("tolerances").getDouble(1)); + Arrays.fill(tolObj2Index2, testObj2.getJSONArray("tolerances").getDouble(1)); + } + + if (testObj1.getString("type").equals("conversion")) { + Arrays.fill(this.tolConversions_i0, tolObj1Index1); + this.tolConversions_i1 = tolObj1Index2; + + Arrays.fill(this.tolRoundTrips_i0, tolObj2Index1); + this.tolRoundTrips_i1 = tolObj2Index2; + this.roundTripTimes = testObj2.getInt("times"); + } else { + Arrays.fill(this.tolConversions_i0, tolObj2Index1); + this.tolConversions_i1 = tolObj2Index2; + + Arrays.fill(this.tolRoundTrips_i0, tolObj1Index1); + this.tolRoundTrips_i1 = tolObj1Index2; + this.roundTripTimes = testObj1.getInt("times"); + } // leftPolyline = (Polyline)leftPolygon.getBoundary(); // rightPolyline = (Polyline)rightPolyline.getBoundary(); - } + } - @Test - public void testConversionPoints() throws Exception { - assertTrue(this.description, true); + @Test + public void testConversionPoints() throws Exception { + assertTrue(this.description, true); - Point[] leftExpected = new Point[leftMultiPoint.getPointCount()]; - leftMultiPoint.queryCoordinates(leftExpected); + Point[] leftExpected = new Point[leftMultiPoint.getPointCount()]; + leftMultiPoint.queryCoordinates(leftExpected); - Point[] rightExpected = new Point[rightMultiPoint.getPointCount()]; - rightMultiPoint.queryCoordinates(rightExpected); + Point[] rightExpected = new Point[rightMultiPoint.getPointCount()]; + rightMultiPoint.queryCoordinates(rightExpected); - Point[] rightActual = IntStream.range(0, rightMultiPoint.getPointCount()) - .mapToObj(i -> new Point()) - .toArray(Point[]::new); + Point[] rightActual = IntStream.range(0, rightMultiPoint.getPointCount()) + .mapToObj(i -> new Point()) + .toArray(Point[]::new); - Point[] leftActual = IntStream.range(0, leftMultiPoint.getPointCount()) - .mapToObj(i -> new Point()) - .toArray(Point[]::new); + Point[] leftActual = IntStream.range(0, leftMultiPoint.getPointCount()) + .mapToObj(i -> new Point()) + .toArray(Point[]::new); - OperatorProject.local().transform(this.leftToRightTransformation, leftExpected, leftExpected.length, rightActual); - // test_right = self.transform(self.proj_left, self.proj_right, self.coords_left) - StringBuilder errorMessages = new StringBuilder(); - errorMessages.append("\n").append(this.testName); - errorMessages.append("\n").append(this.description); - int nonMatches = listCountMatches(rightActual, rightExpected, this.tolConversions_i1, errorMessages); - assertEquals(errorMessages.toString(), 0, nonMatches); + OperatorProject.local().transform(this.leftToRightTransformation, leftExpected, leftExpected.length, rightActual); + // test_right = self.transform(self.proj_left, self.proj_right, self.coords_left) + StringBuilder errorMessages = new StringBuilder(); + errorMessages.append("\n").append(this.testName); + errorMessages.append("\n").append(this.description); + int nonMatches = listCountMatches(rightActual, rightExpected, this.tolConversions_i1, errorMessages); + assertEquals(errorMessages.toString(), 0, nonMatches); - // results1 = list_count_matches(test_right, self.coords_right, tolerances[1]) + // results1 = list_count_matches(test_right, self.coords_right, tolerances[1]) - OperatorProject.local().transform(this.rightToLeftTransformation, rightExpected, rightExpected.length, leftActual); - // test_left = self.transform(self.proj_right, self.proj_left, self.coords_right) - nonMatches += listCountMatches(leftActual, leftExpected, this.tolConversions_i0, errorMessages); - // results2 = list_count_matches(test_left, self.coords_left, tolerances[0]) - assertEquals(errorMessages.toString(), 0, nonMatches); + OperatorProject.local().transform(this.rightToLeftTransformation, rightExpected, rightExpected.length, leftActual); + // test_left = self.transform(self.proj_right, self.proj_left, self.coords_right) + nonMatches += listCountMatches(leftActual, leftExpected, this.tolConversions_i0, errorMessages); + // results2 = list_count_matches(test_left, self.coords_left, tolerances[0]) + assertEquals(errorMessages.toString(), 0, nonMatches); // tolerances = kwargs.get('tolerances', [0.0000000000001, 0.0000000000001]) @@ -189,91 +189,91 @@ public void testConversionPoints() throws Exception { // results2 = list_count_matches(test_left, self.coords_left, tolerances[0]) // // return (results1[0] + results2[0], results1[1] + results2[1]) - } - - /** - * counts coordinates in lists that match and don't match. - * assumes that lists are the same length (they should be) - *

- * returns tuple (matches, non_matches) - * """ - * matches, non_matches = 0, 0 - * iter_ex_coords = iter(ex_coords) - * for c in coords: - * ex_coord = next(iter_ex_coords) - * if match_func(c, ex_coord, tolerance): - * matches = matches + 1 - * else: - * non_matches = non_matches + 1 - *

- * return (matches, non_matches) - */ - public static int listCountMatches(Point[] actualPoints, Point[] expectedPoints, double[] tolerances, StringBuilder errorMessages) { - // matches, non_matches = 0, 0 - int nonMatches = 0; - for (int i = 0; i < actualPoints.length; i++) { - Point actualPoint = actualPoints[i]; - Point expectedPoint = expectedPoints[i]; - String message = matchCheck(actualPoint, expectedPoint, tolerances); - if (message != null) { - nonMatches += 1; - errorMessages.append("\nError at index: ").append(i).append("\n"); - errorMessages.append(message); - } - } - - return nonMatches; - } - - /** - * Check if coordinate matches expected coordinate within a given tolerance. - * float coordinate elements will be checked based on this value - * list/tuple coordinate elements will be checked based on the - * corresponding values - * - * @param pt - * @param expectedPoint - * @param tolerance error rate - * @return string - */ - public static String matchCheck(Point pt, Point expectedPoint, double[] tolerance) { - double[] coord_diff = new double[]{Math.abs(pt.getX() - expectedPoint.getX()), Math.abs(pt.getY() - expectedPoint.getY())}; - if (pt.hasZ()) - coord_diff = new double[]{Math.abs(pt.getX() - expectedPoint.getX()), Math.abs(pt.getY() - expectedPoint.getY()), Math.abs(pt.getZ() - expectedPoint.getZ())}; - - boolean matching = true; - StringBuilder stringBuilder = new StringBuilder(); - for (int i = 0; i < coord_diff.length; i++) { - if (coord_diff[i] > tolerance[i]) { - matching = false; - - stringBuilder.append("Non-match at "); - if (i == 0) - stringBuilder.append(" x position\n"); - else if (i == 1) - stringBuilder.append(" y position\n"); - else - stringBuilder.append(" z position\n"); - stringBuilder.append("Actual coordinate:\n"); - stringBuilder.append(pt.toString()); - stringBuilder.append("\nExpected coordinate:\n"); - stringBuilder.append(expectedPoint.toString()); - stringBuilder.append("\nActual difference:\n"); - stringBuilder.append("x: ").append(coord_diff[0]).append(" y:").append(coord_diff[1]); - if (pt.hasZ()) - stringBuilder.append(" z:").append(coord_diff[2]); - stringBuilder.append("\nFor tolerances:\n"); - stringBuilder.append("x:").append(tolerance[0]).append(" y:").append(tolerance[1]); - if (pt.hasZ()) - stringBuilder.append(" z:").append(tolerance[2]); - stringBuilder.append("\n\n"); - } - } - if (!matching) - return stringBuilder.toString(); - - return null; - } + } + + /** + * counts coordinates in lists that match and don't match. + * assumes that lists are the same length (they should be) + *

+ * returns tuple (matches, non_matches) + * """ + * matches, non_matches = 0, 0 + * iter_ex_coords = iter(ex_coords) + * for c in coords: + * ex_coord = next(iter_ex_coords) + * if match_func(c, ex_coord, tolerance): + * matches = matches + 1 + * else: + * non_matches = non_matches + 1 + *

+ * return (matches, non_matches) + */ + public static int listCountMatches(Point[] actualPoints, Point[] expectedPoints, double[] tolerances, StringBuilder errorMessages) { + // matches, non_matches = 0, 0 + int nonMatches = 0; + for (int i = 0; i < actualPoints.length; i++) { + Point actualPoint = actualPoints[i]; + Point expectedPoint = expectedPoints[i]; + String message = matchCheck(actualPoint, expectedPoint, tolerances); + if (message != null) { + nonMatches += 1; + errorMessages.append("\nError at index: ").append(i).append("\n"); + errorMessages.append(message); + } + } + + return nonMatches; + } + + /** + * Check if coordinate matches expected coordinate within a given tolerance. + * float coordinate elements will be checked based on this value + * list/tuple coordinate elements will be checked based on the + * corresponding values + * + * @param pt + * @param expectedPoint + * @param tolerance error rate + * @return string + */ + public static String matchCheck(Point pt, Point expectedPoint, double[] tolerance) { + double[] coord_diff = new double[]{Math.abs(pt.getX() - expectedPoint.getX()), Math.abs(pt.getY() - expectedPoint.getY())}; + if (pt.hasZ()) + coord_diff = new double[]{Math.abs(pt.getX() - expectedPoint.getX()), Math.abs(pt.getY() - expectedPoint.getY()), Math.abs(pt.getZ() - expectedPoint.getZ())}; + + boolean matching = true; + StringBuilder stringBuilder = new StringBuilder(); + for (int i = 0; i < coord_diff.length; i++) { + if (coord_diff[i] > tolerance[i]) { + matching = false; + + stringBuilder.append("Non-match at "); + if (i == 0) + stringBuilder.append(" x position\n"); + else if (i == 1) + stringBuilder.append(" y position\n"); + else + stringBuilder.append(" z position\n"); + stringBuilder.append("Actual coordinate:\n"); + stringBuilder.append(pt.toString()); + stringBuilder.append("\nExpected coordinate:\n"); + stringBuilder.append(expectedPoint.toString()); + stringBuilder.append("\nActual difference:\n"); + stringBuilder.append("x: ").append(coord_diff[0]).append(" y:").append(coord_diff[1]); + if (pt.hasZ()) + stringBuilder.append(" z:").append(coord_diff[2]); + stringBuilder.append("\nFor tolerances:\n"); + stringBuilder.append("x:").append(tolerance[0]).append(" y:").append(tolerance[1]); + if (pt.hasZ()) + stringBuilder.append(" z:").append(tolerance[2]); + stringBuilder.append("\n\n"); + } + } + if (!matching) + return stringBuilder.toString(); + + return null; + } // if len(exc) == 3: // # coordinate triples @@ -297,61 +297,61 @@ else if (i == 1) // ''.format(c1=cor, c2=exc, res=coord_diff, tol=tolerance)) // - @Test - public void testRoundtripPoints() throws Exception { - assertTrue(this.description, true); - } - - - @Test - public void testConversionMultiPoints() throws Exception { - assertTrue(this.description, true); - } - - @Test - public void testRoundtripMultiPoints() throws Exception { - assertTrue(this.description, true); - } - - @Test - public void testConversionPolyline() throws Exception { - assertTrue(this.description, true); - } - - @Test - public void testRoundtripPolyline() throws Exception { - assertTrue(this.description, true); - } - - @Test - public void testConversionPolygon() throws Exception { - assertTrue(this.description, true); - } - - @Test - public void testRoundtripPolygon() throws Exception { - assertTrue(this.description, true); - } - - @Parameterized.Parameters(name = "{1}") - public static Collection data() throws java.io.IOException, java.net.URISyntaxException { - // load the files as you want - URL urls = TestProjectionGigsData.class.getResource("gigs"); - Path gigsDir = Paths.get(urls.toURI()); - - // https://stackoverflow.com/a/36815191/445372 - Stream paths = Files.walk(gigsDir, 1, FileVisitOption.FOLLOW_LINKS); - - Collection data = paths - // https://stackoverflow.com/a/20533064/445372 - .filter(p -> p.toString().toLowerCase().endsWith(".json")) - // https://www.mkyong.com/java8/java-8-filter-a-map-examples/ - .map(p -> new Object[]{p, p.getFileName().toString().split(".json")[0].replace('.', '_')}) - // https://www.javabrahman.com/java-8/java-8-how-to-use-collectors-tocollection-collector-with-examples/ - .collect(Collectors.toCollection(ArrayList::new)); - - return data; - } + @Test + public void testRoundtripPoints() throws Exception { + assertTrue(this.description, true); + } + + + @Test + public void testConversionMultiPoints() throws Exception { + assertTrue(this.description, true); + } + + @Test + public void testRoundtripMultiPoints() throws Exception { + assertTrue(this.description, true); + } + + @Test + public void testConversionPolyline() throws Exception { + assertTrue(this.description, true); + } + + @Test + public void testRoundtripPolyline() throws Exception { + assertTrue(this.description, true); + } + + @Test + public void testConversionPolygon() throws Exception { + assertTrue(this.description, true); + } + + @Test + public void testRoundtripPolygon() throws Exception { + assertTrue(this.description, true); + } + + @Parameterized.Parameters(name = "{1}") + public static Collection data() throws java.io.IOException, java.net.URISyntaxException { + // load the files as you want + URL urls = TestProjectionGigsData.class.getResource("gigs"); + Path gigsDir = Paths.get(urls.toURI()); + + // https://stackoverflow.com/a/36815191/445372 + Stream paths = Files.walk(gigsDir, 1, FileVisitOption.FOLLOW_LINKS); + + Collection data = paths + // https://stackoverflow.com/a/20533064/445372 + .filter(p -> p.toString().toLowerCase().endsWith(".json")) + // https://www.mkyong.com/java8/java-8-filter-a-map-examples/ + .map(p -> new Object[]{p, p.getFileName().toString().split(".json")[0].replace('.', '_')}) + // https://www.javabrahman.com/java-8/java-8-how-to-use-collectors-tocollection-collector-with-examples/ + .collect(Collectors.toCollection(ArrayList::new)); + + return data; + } } diff --git a/src/test/java/com/esri/core/geometry/TestProximity2D.java b/src/test/java/com/esri/core/geometry/TestProximity2D.java index 2ee1c681..9f6cd184 100644 --- a/src/test/java/com/esri/core/geometry/TestProximity2D.java +++ b/src/test/java/com/esri/core/geometry/TestProximity2D.java @@ -28,259 +28,259 @@ import org.junit.Test; public class TestProximity2D extends TestCase { - @Override - protected void setUp() throws Exception { - super.setUp(); - } - - @Override - protected void tearDown() throws Exception { - super.tearDown(); - } - - @Test - public void testProximity_2D_1() { - OperatorFactoryLocal engine = OperatorFactoryLocal.getInstance(); - - @SuppressWarnings("unused") - OperatorProximity2D proximityOp = (OperatorProximity2D) engine - .getOperator(Operator.Type.Proximity2D); - - Point inputPoint = new Point(3, 2); - - Point point0 = new Point(2.75, 2); - // Point point1 = new Point(3, 2.5); - // Point point2 = new Point(3.75, 2); - // Point point3 = new Point(2.25, 2.5); - // Point point4 = new Point(4, 2.25); - - // GetNearestVertices for Polygon (Native and DotNet) - Polygon polygon = MakePolygon(); - - Proximity2DResult[] resultArray = GeometryEngine.getNearestVertices( - polygon, inputPoint, 2.0, 8); - assertTrue(resultArray.length == 8); - - double lastdistance; - double distance; - - Proximity2DResult result0 = resultArray[0]; - lastdistance = result0.getDistance(); - assertTrue(lastdistance <= 2.0); - - Proximity2DResult result1 = resultArray[1]; - distance = result1.getDistance(); - assertTrue(distance <= 2.0 && distance >= lastdistance); - lastdistance = distance; - - Proximity2DResult result2 = resultArray[2]; - distance = result2.getDistance(); - assertTrue(distance <= 2.0 && distance >= lastdistance); - lastdistance = distance; - - Proximity2DResult result3 = resultArray[3]; - distance = result3.getDistance(); - assertTrue(distance <= 2.0 && distance >= lastdistance); - lastdistance = distance; - - Proximity2DResult result4 = resultArray[4]; - distance = result4.getDistance(); - assertTrue(distance <= 2.0 && distance >= lastdistance); - lastdistance = distance; - - Proximity2DResult result5 = resultArray[5]; - distance = result5.getDistance(); - assertTrue(distance <= 2.0 && distance >= lastdistance); - lastdistance = distance; - - Proximity2DResult result6 = resultArray[6]; - distance = result6.getDistance(); - assertTrue(distance <= 2.0 && distance >= lastdistance); - lastdistance = distance; - - Proximity2DResult result7 = resultArray[7]; - distance = result7.getDistance(); - assertTrue(distance <= 2.0 && distance >= lastdistance); - // lastdistance = distance; - - // Point[] coordinates = polygon.get.getCoordinates2D(); - // int pointCount = polygon.getPointCount(); - // - // int hits = 0; - // for (int i = 0; i < pointCount; i++) - // { - // Point ipoint = coordinates[i]; - // distance = Point::Distance(ipoint, inputPoint); - // - // if (distance < lastdistance) - // hits++; - // } - - // assertTrue(hits < 8); - - // GetNearestVertices for Point - Point point = MakePoint(); - resultArray = GeometryEngine.getNearestVertices(point, inputPoint, 1.0, - 1); - assertTrue(resultArray.length == 1); - result0 = resultArray[0]; - Point resultPoint0 = result0.getCoordinate(); - assertTrue(resultPoint0.getX() == point.getX() - && resultPoint0.getY() == point.getY()); - - // GetNearestVertex for Polygon - result0 = GeometryEngine.getNearestVertex(polygon, inputPoint); - resultPoint0 = result0.getCoordinate(); - assertTrue(resultPoint0.getX() == point0.getX() - && resultPoint0.getY() == point0.getY()); - - // GetNearestVertex for Point - result0 = GeometryEngine.getNearestVertex(point, inputPoint); - resultPoint0 = result0.getCoordinate(); - assertTrue(resultPoint0.getX() == point.getX() - && resultPoint0.getY() == point.getY()); - - // GetNearestCoordinate for Polygon - Polygon polygon2 = MakePolygon2(); - result0 = GeometryEngine.getNearestCoordinate(polygon2, inputPoint, - true); - resultPoint0 = result0.getCoordinate(); - assertTrue(resultPoint0.getX() == inputPoint.getX() - && resultPoint0.getY() == inputPoint.getY()); - - // GetNearestCoordinate for Polyline - Polyline polyline = MakePolyline(); - result0 = GeometryEngine.getNearestCoordinate(polyline, inputPoint, - true); - resultPoint0 = result0.getCoordinate(); - assertTrue(resultPoint0.getX() == 0.0 && resultPoint0.getY() == 2.0); - - Polygon pp = new Polygon(); - pp.startPath(0, 0); - pp.lineTo(0, 10); - pp.lineTo(10, 10); - pp.lineTo(10, 0); - - inputPoint.setXY(15, -5); - - result0 = proximityOp.getNearestCoordinate(pp, inputPoint, true, true); - boolean is_right = result0.isRightSide(); - assertTrue(!is_right); - } - - Polygon MakePolygon() { - Polygon poly = new Polygon(); - poly.startPath(3, -2); - poly.lineTo(2, -1); - poly.lineTo(3, 0); - poly.lineTo(4, 0); - - poly.startPath(1.75, 1); - poly.lineTo(0.75, 2); - poly.lineTo(1.75, 3); - poly.lineTo(2.25, 2.5); - poly.lineTo(2.75, 2); - - poly.startPath(3, 2.5); - poly.lineTo(2.5, 3); - poly.lineTo(2, 3.5); - poly.lineTo(3, 4.5); - poly.lineTo(4, 3.5); - - poly.startPath(4.75, 1); - poly.lineTo(3.75, 2); - poly.lineTo(4, 2.25); - poly.lineTo(4.75, 3); - poly.lineTo(5.75, 2); - - return poly; - } - - Polygon MakePolygon2() { - Polygon poly = new Polygon(); - poly.startPath(0, 0); - poly.lineTo(0, 10); - poly.lineTo(10, 10); - poly.lineTo(10, 0); - - return poly; - } - - Polyline MakePolyline() { - Polyline poly = new Polyline(); - poly.startPath(0, 0); - poly.lineTo(0, 10); - poly.lineTo(10, 10); - poly.lineTo(10, 0); - - return poly; - } - - Point MakePoint() { - Point point = new Point(3, 2.5); - - return point; - } - - @Test - public void testProximity2D_2() { - Point point1 = new Point(3, 2); - Point point2 = new Point(2, 4); - Envelope envelope = new Envelope(); - envelope.setCoords(4, 3, 7, 6); - Polygon polygonToTest = new Polygon(); - polygonToTest.addEnvelope(envelope, false); - Proximity2DResult prxResult1 = GeometryEngine.getNearestVertex( - envelope, point1); - Proximity2DResult prxResult2 = GeometryEngine.getNearestVertex( - polygonToTest, point1); - Proximity2DResult prxResult3 = GeometryEngine.getNearestCoordinate( - envelope, point2, false); - Proximity2DResult prxResult4 = GeometryEngine.getNearestCoordinate( - polygonToTest, point2, false); - - Point result1 = prxResult1.getCoordinate(); - Point result2 = prxResult2.getCoordinate(); - assertTrue(result1.getX() == result2.getX()); - Point result3 = prxResult3.getCoordinate(); - Point result4 = prxResult4.getCoordinate(); - assertTrue(result3.getX() == result4.getX()); - } - - @Test - public static void testProximity2D_3() { - OperatorFactoryLocal factory = OperatorFactoryLocal.getInstance(); - OperatorProximity2D proximity = (OperatorProximity2D) factory - .getOperator(com.esri.core.geometry.Operator.Type.Proximity2D); - - Polygon polygon = new Polygon(); - polygon.startPath(new Point(-120, 22)); - polygon.lineTo(new Point(-120, 10)); - polygon.lineTo(new Point(-110, 10)); - polygon.lineTo(new Point(-110, 22)); - - Point point = new Point(); - point.setXY(-110, 20); - Proximity2DResult result = proximity.getNearestCoordinate(polygon, - point, false); - Point point2 = new Point(); - point2.setXY(-120, 12); - @SuppressWarnings("unused") - Proximity2DResult[] results = proximity.getNearestVertices(polygon, - point2, 10, 12); - } - - @Test - public static void testCR254240() { - OperatorProximity2D proximityOp = OperatorProximity2D.local(); - - Point inputPoint = new Point(-12, 12); - Polyline line = new Polyline(); - line.startPath(-10, 0); - line.lineTo(0, 0); - - Proximity2DResult result = proximityOp.getNearestCoordinate(line, - inputPoint, false, true); - assertTrue(result.isRightSide() == false); - } + @Override + protected void setUp() throws Exception { + super.setUp(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + } + + @Test + public void testProximity_2D_1() { + OperatorFactoryLocal engine = OperatorFactoryLocal.getInstance(); + + @SuppressWarnings("unused") + OperatorProximity2D proximityOp = (OperatorProximity2D) engine + .getOperator(Operator.Type.Proximity2D); + + Point inputPoint = new Point(3, 2); + + Point point0 = new Point(2.75, 2); + // Point point1 = new Point(3, 2.5); + // Point point2 = new Point(3.75, 2); + // Point point3 = new Point(2.25, 2.5); + // Point point4 = new Point(4, 2.25); + + // GetNearestVertices for Polygon (Native and DotNet) + Polygon polygon = MakePolygon(); + + Proximity2DResult[] resultArray = GeometryEngine.getNearestVertices( + polygon, inputPoint, 2.0, 8); + assertTrue(resultArray.length == 8); + + double lastdistance; + double distance; + + Proximity2DResult result0 = resultArray[0]; + lastdistance = result0.getDistance(); + assertTrue(lastdistance <= 2.0); + + Proximity2DResult result1 = resultArray[1]; + distance = result1.getDistance(); + assertTrue(distance <= 2.0 && distance >= lastdistance); + lastdistance = distance; + + Proximity2DResult result2 = resultArray[2]; + distance = result2.getDistance(); + assertTrue(distance <= 2.0 && distance >= lastdistance); + lastdistance = distance; + + Proximity2DResult result3 = resultArray[3]; + distance = result3.getDistance(); + assertTrue(distance <= 2.0 && distance >= lastdistance); + lastdistance = distance; + + Proximity2DResult result4 = resultArray[4]; + distance = result4.getDistance(); + assertTrue(distance <= 2.0 && distance >= lastdistance); + lastdistance = distance; + + Proximity2DResult result5 = resultArray[5]; + distance = result5.getDistance(); + assertTrue(distance <= 2.0 && distance >= lastdistance); + lastdistance = distance; + + Proximity2DResult result6 = resultArray[6]; + distance = result6.getDistance(); + assertTrue(distance <= 2.0 && distance >= lastdistance); + lastdistance = distance; + + Proximity2DResult result7 = resultArray[7]; + distance = result7.getDistance(); + assertTrue(distance <= 2.0 && distance >= lastdistance); + // lastdistance = distance; + + // Point[] coordinates = polygon.get.getCoordinates2D(); + // int pointCount = polygon.getPointCount(); + // + // int hits = 0; + // for (int i = 0; i < pointCount; i++) + // { + // Point ipoint = coordinates[i]; + // distance = Point::Distance(ipoint, inputPoint); + // + // if (distance < lastdistance) + // hits++; + // } + + // assertTrue(hits < 8); + + // GetNearestVertices for Point + Point point = MakePoint(); + resultArray = GeometryEngine.getNearestVertices(point, inputPoint, 1.0, + 1); + assertTrue(resultArray.length == 1); + result0 = resultArray[0]; + Point resultPoint0 = result0.getCoordinate(); + assertTrue(resultPoint0.getX() == point.getX() + && resultPoint0.getY() == point.getY()); + + // GetNearestVertex for Polygon + result0 = GeometryEngine.getNearestVertex(polygon, inputPoint); + resultPoint0 = result0.getCoordinate(); + assertTrue(resultPoint0.getX() == point0.getX() + && resultPoint0.getY() == point0.getY()); + + // GetNearestVertex for Point + result0 = GeometryEngine.getNearestVertex(point, inputPoint); + resultPoint0 = result0.getCoordinate(); + assertTrue(resultPoint0.getX() == point.getX() + && resultPoint0.getY() == point.getY()); + + // GetNearestCoordinate for Polygon + Polygon polygon2 = MakePolygon2(); + result0 = GeometryEngine.getNearestCoordinate(polygon2, inputPoint, + true); + resultPoint0 = result0.getCoordinate(); + assertTrue(resultPoint0.getX() == inputPoint.getX() + && resultPoint0.getY() == inputPoint.getY()); + + // GetNearestCoordinate for Polyline + Polyline polyline = MakePolyline(); + result0 = GeometryEngine.getNearestCoordinate(polyline, inputPoint, + true); + resultPoint0 = result0.getCoordinate(); + assertTrue(resultPoint0.getX() == 0.0 && resultPoint0.getY() == 2.0); + + Polygon pp = new Polygon(); + pp.startPath(0, 0); + pp.lineTo(0, 10); + pp.lineTo(10, 10); + pp.lineTo(10, 0); + + inputPoint.setXY(15, -5); + + result0 = proximityOp.getNearestCoordinate(pp, inputPoint, true, true); + boolean is_right = result0.isRightSide(); + assertTrue(!is_right); + } + + Polygon MakePolygon() { + Polygon poly = new Polygon(); + poly.startPath(3, -2); + poly.lineTo(2, -1); + poly.lineTo(3, 0); + poly.lineTo(4, 0); + + poly.startPath(1.75, 1); + poly.lineTo(0.75, 2); + poly.lineTo(1.75, 3); + poly.lineTo(2.25, 2.5); + poly.lineTo(2.75, 2); + + poly.startPath(3, 2.5); + poly.lineTo(2.5, 3); + poly.lineTo(2, 3.5); + poly.lineTo(3, 4.5); + poly.lineTo(4, 3.5); + + poly.startPath(4.75, 1); + poly.lineTo(3.75, 2); + poly.lineTo(4, 2.25); + poly.lineTo(4.75, 3); + poly.lineTo(5.75, 2); + + return poly; + } + + Polygon MakePolygon2() { + Polygon poly = new Polygon(); + poly.startPath(0, 0); + poly.lineTo(0, 10); + poly.lineTo(10, 10); + poly.lineTo(10, 0); + + return poly; + } + + Polyline MakePolyline() { + Polyline poly = new Polyline(); + poly.startPath(0, 0); + poly.lineTo(0, 10); + poly.lineTo(10, 10); + poly.lineTo(10, 0); + + return poly; + } + + Point MakePoint() { + Point point = new Point(3, 2.5); + + return point; + } + + @Test + public void testProximity2D_2() { + Point point1 = new Point(3, 2); + Point point2 = new Point(2, 4); + Envelope envelope = new Envelope(); + envelope.setCoords(4, 3, 7, 6); + Polygon polygonToTest = new Polygon(); + polygonToTest.addEnvelope(envelope, false); + Proximity2DResult prxResult1 = GeometryEngine.getNearestVertex( + envelope, point1); + Proximity2DResult prxResult2 = GeometryEngine.getNearestVertex( + polygonToTest, point1); + Proximity2DResult prxResult3 = GeometryEngine.getNearestCoordinate( + envelope, point2, false); + Proximity2DResult prxResult4 = GeometryEngine.getNearestCoordinate( + polygonToTest, point2, false); + + Point result1 = prxResult1.getCoordinate(); + Point result2 = prxResult2.getCoordinate(); + assertTrue(result1.getX() == result2.getX()); + Point result3 = prxResult3.getCoordinate(); + Point result4 = prxResult4.getCoordinate(); + assertTrue(result3.getX() == result4.getX()); + } + + @Test + public static void testProximity2D_3() { + OperatorFactoryLocal factory = OperatorFactoryLocal.getInstance(); + OperatorProximity2D proximity = (OperatorProximity2D) factory + .getOperator(com.esri.core.geometry.Operator.Type.Proximity2D); + + Polygon polygon = new Polygon(); + polygon.startPath(new Point(-120, 22)); + polygon.lineTo(new Point(-120, 10)); + polygon.lineTo(new Point(-110, 10)); + polygon.lineTo(new Point(-110, 22)); + + Point point = new Point(); + point.setXY(-110, 20); + Proximity2DResult result = proximity.getNearestCoordinate(polygon, + point, false); + Point point2 = new Point(); + point2.setXY(-120, 12); + @SuppressWarnings("unused") + Proximity2DResult[] results = proximity.getNearestVertices(polygon, + point2, 10, 12); + } + + @Test + public static void testCR254240() { + OperatorProximity2D proximityOp = OperatorProximity2D.local(); + + Point inputPoint = new Point(-12, 12); + Polyline line = new Polyline(); + line.startPath(-10, 0); + line.lineTo(0, 0); + + Proximity2DResult result = proximityOp.getNearestCoordinate(line, + inputPoint, false, true); + assertTrue(result.isRightSide() == false); + } } diff --git a/src/test/java/com/esri/core/geometry/TestQuadTree.java b/src/test/java/com/esri/core/geometry/TestQuadTree.java index bbe2a01a..7374c3a9 100644 --- a/src/test/java/com/esri/core/geometry/TestQuadTree.java +++ b/src/test/java/com/esri/core/geometry/TestQuadTree.java @@ -9,428 +9,428 @@ import java.util.Random; public class TestQuadTree extends TestCase { - @Override - protected void setUp() throws Exception { - super.setUp(); - } + @Override + protected void setUp() throws Exception { + super.setUp(); + } - @Override - protected void tearDown() throws Exception { - super.tearDown(); - } - - @Test - public static void test1() { - - { - QuadTree quad_tree = new QuadTree(Envelope2D.construct(-10, -10, 10, 10), 8); - - QuadTree.QuadTreeIterator qt = quad_tree.getIterator(true); - assertTrue(qt.next() == -1); - - qt.resetIterator(Envelope2D.construct(0, 0, 0, 0), 0); - - assertTrue(quad_tree.getIntersectionCount(Envelope2D.construct(0, 0, 0, 0), 0, 10) == 0); - assertTrue(quad_tree.getElementCount() == 0); - } - - Polyline polyline; - polyline = makePolyline(); - - MultiPathImpl polylineImpl = (MultiPathImpl) polyline._getImpl(); - QuadTree quadtree = buildQuadTree_(polylineImpl, false); - - Line queryline = new Line(34, 9, 66, 46); - QuadTree.QuadTreeIterator qtIter = quadtree.getIterator(); - assertTrue(qtIter.next() == -1); - - qtIter.resetIterator(queryline, 0.0); - - int element_handle = qtIter.next(); - while (element_handle > 0) { - int index = quadtree.getElement(element_handle); - assertTrue(index == 6 || index == 8 || index == 14); - element_handle = qtIter.next(); - } - - Envelope2D envelope = new Envelope2D(34, 9, 66, 46); - Polygon queryPolygon = new Polygon(); - queryPolygon.addEnvelope(envelope, true); - - qtIter.resetIterator(queryline, 0.0); - - element_handle = qtIter.next(); - while (element_handle > 0) { - int index = quadtree.getElement(element_handle); - assertTrue(index == 6 || index == 8 || index == 14); - element_handle = qtIter.next(); - } - } - - @Test - public static void testQuadTreeWithDuplicates() { - int pass_count = 10; - int figure_size = 400; - int figure_size2 = 100; - Envelope extent1 = new Envelope(); - extent1.setCoords(-100000, -100000, 100000, 100000); - - RandomCoordinateGenerator generator1 = new RandomCoordinateGenerator(Math.max(figure_size, 10000), extent1, 0.001); - Random random = new Random(2013); - int rand_max = 32; - - Polygon poly_red = new Polygon(); - Polygon poly_blue = new Polygon(); - - int r = figure_size; - - for (int c = 0; c < pass_count; c++) { - Point pt; - for (int j = 0; j < r; j++) { - int rand = random.nextInt(rand_max); - boolean b_random_new = r > 10 && ((1.0 * rand) / rand_max > 0.95); - pt = generator1.GetRandomCoord(); - if (j == 0 || b_random_new) - poly_blue.startPath(pt); - else - poly_blue.lineTo(pt); - } - - Envelope2D env = new Envelope2D(); - - QuadTree quad_tree_blue = buildQuadTree_((MultiPathImpl) poly_blue._getImpl(), false); - QuadTree quad_tree_blue_duplicates = buildQuadTree_((MultiPathImpl) poly_blue._getImpl(), true); - - Envelope2D e1 = quad_tree_blue.getDataExtent(); - Envelope2D e2 = quad_tree_blue_duplicates.getDataExtent(); - assertTrue(e1.equals(e2)); - assertTrue(quad_tree_blue.getElementCount() == poly_blue.getSegmentCount()); - - SegmentIterator seg_iter_blue = poly_blue.querySegmentIterator(); - - poly_red.setEmpty(); - - r = figure_size2; - if (r < 3) - continue; - - for (int j = 0; j < r; j++) { - int rand = random.nextInt(rand_max); - boolean b_random_new = r > 10 && ((1.0 * rand) / rand_max > 0.95); - pt = generator1.GetRandomCoord(); - if (j == 0 || b_random_new) - poly_red.startPath(pt); - else - poly_red.lineTo(pt); - } - - QuadTree.QuadTreeIterator iterator = quad_tree_blue.getIterator(); - SegmentIteratorImpl seg_iter_red = ((MultiPathImpl) poly_red._getImpl()).querySegmentIterator(); - - HashMap map1 = new HashMap(0); - - int count = 0; - int intersections_per_query = 0; - while (seg_iter_red.nextPath()) { - while (seg_iter_red.hasNextSegment()) { - Segment segment_red = seg_iter_red.nextSegment(); - segment_red.queryEnvelope2D(env); - - iterator.resetIterator(env, 0.0); - - int count_upper = 0; - int element_handle; - while ((element_handle = iterator.next()) != -1) { - count_upper++; - int index = quad_tree_blue.getElement(element_handle); - Boolean iter = (Boolean) map1.get(index); - if (iter == null) { - count++; - map1.put(index, true); - } - - intersections_per_query++; - } - - int intersection_count = quad_tree_blue.getIntersectionCount(env, 0.0, -1); - assertTrue(intersection_count == count_upper); - } - } - - seg_iter_red.resetToFirstPath(); - - HashMap map2 = new HashMap(0); - QuadTree.QuadTreeIterator iterator_duplicates = quad_tree_blue_duplicates.getIterator(); - - int count_duplicates = 0; - int intersections_per_query_duplicates = 0; - while (seg_iter_red.nextPath()) { - while (seg_iter_red.hasNextSegment()) { - Segment segment_red = seg_iter_red.nextSegment(); - segment_red.queryEnvelope2D(env); - - iterator_duplicates.resetIterator(env, 0.0); - - int count_lower = 0; - HashMap map_per_query = new HashMap(0); - - int count_upper = 0; - int element_handle; - while ((element_handle = iterator_duplicates.next()) != -1) { - count_upper++; - int index = quad_tree_blue_duplicates.getElement(element_handle); - Boolean iter = (Boolean) map2.get(index); - if (iter == null) { - count_duplicates++; - map2.put(index, true); - } - - - Boolean iter_lower = (Boolean) map_per_query.get(index); - if (iter_lower == null) { - count_lower++; - intersections_per_query_duplicates++; - map_per_query.put(index, true); - } - - int q = quad_tree_blue_duplicates.getQuad(element_handle); - assertTrue(quad_tree_blue_duplicates.getSubTreeElementCount(q) >= quad_tree_blue_duplicates.getContainedSubTreeElementCount(q)); - } - - int intersection_count = quad_tree_blue_duplicates.getIntersectionCount(env, 0.0, -1); - boolean b_has_data = quad_tree_blue_duplicates.hasData(env, 0.0); - assertTrue(b_has_data || intersection_count == 0); - assertTrue(count_lower <= intersection_count && intersection_count <= count_upper); - assertTrue(count_upper <= 4 * count_lower); - } - } - - assertTrue(count == count_duplicates); - assertTrue(intersections_per_query == intersections_per_query_duplicates); - } - } - - @Test - public static void testSortedIterator() { - int pass_count = 10; - int figure_size = 400; - int figure_size2 = 100; - Envelope extent1 = new Envelope(); - extent1.setCoords(-100000, -100000, 100000, 100000); - - RandomCoordinateGenerator generator1 = new RandomCoordinateGenerator(Math.max(figure_size, 10000), extent1, 0.001); - - Random random = new Random(2013); - int rand_max = 32; - - Polygon poly_red = new Polygon(); - Polygon poly_blue = new Polygon(); - - int r = figure_size; - - for (int c = 0; c < pass_count; c++) { - Point pt; - for (int j = 0; j < r; j++) { - int rand = random.nextInt(rand_max); - boolean b_random_new = r > 10 && ((1.0 * rand) / rand_max > 0.95); - pt = generator1.GetRandomCoord(); - if (j == 0 || b_random_new) - poly_blue.startPath(pt); - else - poly_blue.lineTo(pt); - } - - Envelope2D env = new Envelope2D(); - - QuadTree quad_tree_blue = buildQuadTree_((MultiPathImpl) poly_blue._getImpl(), false); - - Envelope2D e1 = quad_tree_blue.getDataExtent(); - assertTrue(quad_tree_blue.getElementCount() == poly_blue.getSegmentCount()); - - SegmentIterator seg_iter_blue = poly_blue.querySegmentIterator(); - - poly_red.setEmpty(); - - r = figure_size2; - if (r < 3) - continue; - - for (int j = 0; j < r; j++) { - int rand = random.nextInt(rand_max); - boolean b_random_new = r > 10 && ((1.0 * rand) / rand_max > 0.95); - pt = generator1.GetRandomCoord(); - if (j == 0 || b_random_new) - poly_red.startPath(pt); - else - poly_red.lineTo(pt); - } - - QuadTree.QuadTreeIterator iterator = quad_tree_blue.getIterator(); - SegmentIteratorImpl seg_iter_red = ((MultiPathImpl) poly_red._getImpl()).querySegmentIterator(); - - HashMap map1 = new HashMap(0); - - int count = 0; - int intersections_per_query = 0; - while (seg_iter_red.nextPath()) { - while (seg_iter_red.hasNextSegment()) { - Segment segment_red = seg_iter_red.nextSegment(); - segment_red.queryEnvelope2D(env); - - iterator.resetIterator(env, 0.0); - - int count_upper = 0; - int element_handle; - while ((element_handle = iterator.next()) != -1) { - count_upper++; - int index = quad_tree_blue.getElement(element_handle); - Boolean iter = (Boolean) map1.get(index); - if (iter == null) { - count++; - map1.put(index, true); - } - - intersections_per_query++; - } - - int intersection_count = quad_tree_blue.getIntersectionCount(env, 0.0, -1); - assertTrue(intersection_count == count_upper); - } - } - - seg_iter_red.resetToFirstPath(); - - HashMap map2 = new HashMap(0); - QuadTree.QuadTreeIterator sorted_iterator = quad_tree_blue.getIterator(true); - - int count_sorted = 0; - int intersections_per_query_sorted = 0; - while (seg_iter_red.nextPath()) { - while (seg_iter_red.hasNextSegment()) { - Segment segment_red = seg_iter_red.nextSegment(); - segment_red.queryEnvelope2D(env); - - sorted_iterator.resetIterator(env, 0.0); - - int count_upper_sorted = 0; - int element_handle; - int last_index = -1; - while ((element_handle = sorted_iterator.next()) != -1) { - count_upper_sorted++; - int index = quad_tree_blue.getElement(element_handle); - assertTrue(last_index < index); // ensure the element handles are returned in sorted order - last_index = index; - Boolean iter = (Boolean) map2.get(index); - if (iter == null) { - count_sorted++; - map2.put(index, true); - } - - intersections_per_query_sorted++; - } - - int intersection_count = quad_tree_blue.getIntersectionCount(env, 0.0, -1); - assertTrue(intersection_count == count_upper_sorted); - } - } - - assertTrue(count == count_sorted); - assertTrue(intersections_per_query == intersections_per_query_sorted); - } - } - - @Test - public static void test_perf_quad_tree() { - Envelope extent1 = new Envelope(); - extent1.setCoords(-1000, -1000, 1000, 1000); - - RandomCoordinateGenerator generator1 = new RandomCoordinateGenerator(1000, extent1, 0.001); - //HiResTimer timer; - for (int N = 16; N <= 1024/**1024*/; N *= 2) { - //timer.StartMeasurement(); - - Envelope2D extent = new Envelope2D(); - extent.setCoords(-1000, -1000, 1000, 1000); - HashMap data = new HashMap(0); - QuadTree qt = new QuadTree(extent, 10); - for (int i = 0; i < N; i++) { - Envelope2D env = new Envelope2D(); - Point2D center = generator1.GetRandomCoord().getXY(); - double w = 10; - env.setCoords(center, w, w); - env.intersect(extent); - if (env.isEmpty()) - continue; - - int h = qt.insert(i, env); - data.put(h, env); - } - - int ecount = 0; - AttributeStreamOfInt32 handles = new AttributeStreamOfInt32(0); - QuadTree.QuadTreeIterator iter = qt.getIterator(); - - Iterator> pairs = data.entrySet().iterator(); - while (pairs.hasNext()) { - Map.Entry entry = pairs.next(); - iter.resetIterator((Envelope2D) entry.getValue(), 0.001); - boolean remove_self = false; - for (int h = iter.next(); h != -1; h = iter.next()) { - if (h != entry.getKey()) - handles.add(h); - else { - remove_self = true; - } - - ecount++; - } - - for (int i = 0; i < handles.size(); i++) { - qt.removeElement(handles.get(i));//remove elements that were selected. - } - - if (remove_self) - qt.removeElement(entry.getKey()); - handles.resize(0); - } - - //printf("%d %0.3f (%I64d, %f, mem %I64d)\n", N, timer.GetMilliseconds(), ecount, ecount / double(N * N), memsize); - } - } - - @Test - public static void test2() { - MultiPoint multipoint = new MultiPoint(); - - for (int i = 0; i < 100; i++) { - for (int j = 0; j < 100; j++) { - multipoint.add(i, j); - } - } - - Envelope2D extent = new Envelope2D(); - multipoint.queryEnvelope2D(extent); - - MultiPointImpl multipointImpl = (MultiPointImpl) multipoint._getImpl(); - QuadTree quadtree = buildQuadTree_(multipointImpl); - - QuadTree.QuadTreeIterator qtIter = quadtree.getIterator(); - assertTrue(qtIter.next() == -1); - - int count = 0; - qtIter.resetIterator(extent, 0.0); - - while (qtIter.next() != -1) { - count++; - } - - assertTrue(count == 10000); - } - - static double randomWithRange(double min, double max) { - double range = Math.abs(max - min); - return (Math.random() * range) + (min <= max ? min : max); - } + @Override + protected void tearDown() throws Exception { + super.tearDown(); + } + + @Test + public static void test1() { + + { + QuadTree quad_tree = new QuadTree(Envelope2D.construct(-10, -10, 10, 10), 8); + + QuadTree.QuadTreeIterator qt = quad_tree.getIterator(true); + assertTrue(qt.next() == -1); + + qt.resetIterator(Envelope2D.construct(0, 0, 0, 0), 0); + + assertTrue(quad_tree.getIntersectionCount(Envelope2D.construct(0, 0, 0, 0), 0, 10) == 0); + assertTrue(quad_tree.getElementCount() == 0); + } + + Polyline polyline; + polyline = makePolyline(); + + MultiPathImpl polylineImpl = (MultiPathImpl) polyline._getImpl(); + QuadTree quadtree = buildQuadTree_(polylineImpl, false); + + Line queryline = new Line(34, 9, 66, 46); + QuadTree.QuadTreeIterator qtIter = quadtree.getIterator(); + assertTrue(qtIter.next() == -1); + + qtIter.resetIterator(queryline, 0.0); + + int element_handle = qtIter.next(); + while (element_handle > 0) { + int index = quadtree.getElement(element_handle); + assertTrue(index == 6 || index == 8 || index == 14); + element_handle = qtIter.next(); + } + + Envelope2D envelope = new Envelope2D(34, 9, 66, 46); + Polygon queryPolygon = new Polygon(); + queryPolygon.addEnvelope(envelope, true); + + qtIter.resetIterator(queryline, 0.0); + + element_handle = qtIter.next(); + while (element_handle > 0) { + int index = quadtree.getElement(element_handle); + assertTrue(index == 6 || index == 8 || index == 14); + element_handle = qtIter.next(); + } + } + + @Test + public static void testQuadTreeWithDuplicates() { + int pass_count = 10; + int figure_size = 400; + int figure_size2 = 100; + Envelope extent1 = new Envelope(); + extent1.setCoords(-100000, -100000, 100000, 100000); + + RandomCoordinateGenerator generator1 = new RandomCoordinateGenerator(Math.max(figure_size, 10000), extent1, 0.001); + Random random = new Random(2013); + int rand_max = 32; + + Polygon poly_red = new Polygon(); + Polygon poly_blue = new Polygon(); + + int r = figure_size; + + for (int c = 0; c < pass_count; c++) { + Point pt; + for (int j = 0; j < r; j++) { + int rand = random.nextInt(rand_max); + boolean b_random_new = r > 10 && ((1.0 * rand) / rand_max > 0.95); + pt = generator1.GetRandomCoord(); + if (j == 0 || b_random_new) + poly_blue.startPath(pt); + else + poly_blue.lineTo(pt); + } + + Envelope2D env = new Envelope2D(); + + QuadTree quad_tree_blue = buildQuadTree_((MultiPathImpl) poly_blue._getImpl(), false); + QuadTree quad_tree_blue_duplicates = buildQuadTree_((MultiPathImpl) poly_blue._getImpl(), true); + + Envelope2D e1 = quad_tree_blue.getDataExtent(); + Envelope2D e2 = quad_tree_blue_duplicates.getDataExtent(); + assertTrue(e1.equals(e2)); + assertTrue(quad_tree_blue.getElementCount() == poly_blue.getSegmentCount()); + + SegmentIterator seg_iter_blue = poly_blue.querySegmentIterator(); + + poly_red.setEmpty(); + + r = figure_size2; + if (r < 3) + continue; + + for (int j = 0; j < r; j++) { + int rand = random.nextInt(rand_max); + boolean b_random_new = r > 10 && ((1.0 * rand) / rand_max > 0.95); + pt = generator1.GetRandomCoord(); + if (j == 0 || b_random_new) + poly_red.startPath(pt); + else + poly_red.lineTo(pt); + } + + QuadTree.QuadTreeIterator iterator = quad_tree_blue.getIterator(); + SegmentIteratorImpl seg_iter_red = ((MultiPathImpl) poly_red._getImpl()).querySegmentIterator(); + + HashMap map1 = new HashMap(0); + + int count = 0; + int intersections_per_query = 0; + while (seg_iter_red.nextPath()) { + while (seg_iter_red.hasNextSegment()) { + Segment segment_red = seg_iter_red.nextSegment(); + segment_red.queryEnvelope2D(env); + + iterator.resetIterator(env, 0.0); + + int count_upper = 0; + int element_handle; + while ((element_handle = iterator.next()) != -1) { + count_upper++; + int index = quad_tree_blue.getElement(element_handle); + Boolean iter = (Boolean) map1.get(index); + if (iter == null) { + count++; + map1.put(index, true); + } + + intersections_per_query++; + } + + int intersection_count = quad_tree_blue.getIntersectionCount(env, 0.0, -1); + assertTrue(intersection_count == count_upper); + } + } + + seg_iter_red.resetToFirstPath(); + + HashMap map2 = new HashMap(0); + QuadTree.QuadTreeIterator iterator_duplicates = quad_tree_blue_duplicates.getIterator(); + + int count_duplicates = 0; + int intersections_per_query_duplicates = 0; + while (seg_iter_red.nextPath()) { + while (seg_iter_red.hasNextSegment()) { + Segment segment_red = seg_iter_red.nextSegment(); + segment_red.queryEnvelope2D(env); + + iterator_duplicates.resetIterator(env, 0.0); + + int count_lower = 0; + HashMap map_per_query = new HashMap(0); + + int count_upper = 0; + int element_handle; + while ((element_handle = iterator_duplicates.next()) != -1) { + count_upper++; + int index = quad_tree_blue_duplicates.getElement(element_handle); + Boolean iter = (Boolean) map2.get(index); + if (iter == null) { + count_duplicates++; + map2.put(index, true); + } + + + Boolean iter_lower = (Boolean) map_per_query.get(index); + if (iter_lower == null) { + count_lower++; + intersections_per_query_duplicates++; + map_per_query.put(index, true); + } + + int q = quad_tree_blue_duplicates.getQuad(element_handle); + assertTrue(quad_tree_blue_duplicates.getSubTreeElementCount(q) >= quad_tree_blue_duplicates.getContainedSubTreeElementCount(q)); + } + + int intersection_count = quad_tree_blue_duplicates.getIntersectionCount(env, 0.0, -1); + boolean b_has_data = quad_tree_blue_duplicates.hasData(env, 0.0); + assertTrue(b_has_data || intersection_count == 0); + assertTrue(count_lower <= intersection_count && intersection_count <= count_upper); + assertTrue(count_upper <= 4 * count_lower); + } + } + + assertTrue(count == count_duplicates); + assertTrue(intersections_per_query == intersections_per_query_duplicates); + } + } + + @Test + public static void testSortedIterator() { + int pass_count = 10; + int figure_size = 400; + int figure_size2 = 100; + Envelope extent1 = new Envelope(); + extent1.setCoords(-100000, -100000, 100000, 100000); + + RandomCoordinateGenerator generator1 = new RandomCoordinateGenerator(Math.max(figure_size, 10000), extent1, 0.001); + + Random random = new Random(2013); + int rand_max = 32; + + Polygon poly_red = new Polygon(); + Polygon poly_blue = new Polygon(); + + int r = figure_size; + + for (int c = 0; c < pass_count; c++) { + Point pt; + for (int j = 0; j < r; j++) { + int rand = random.nextInt(rand_max); + boolean b_random_new = r > 10 && ((1.0 * rand) / rand_max > 0.95); + pt = generator1.GetRandomCoord(); + if (j == 0 || b_random_new) + poly_blue.startPath(pt); + else + poly_blue.lineTo(pt); + } + + Envelope2D env = new Envelope2D(); + + QuadTree quad_tree_blue = buildQuadTree_((MultiPathImpl) poly_blue._getImpl(), false); + + Envelope2D e1 = quad_tree_blue.getDataExtent(); + assertTrue(quad_tree_blue.getElementCount() == poly_blue.getSegmentCount()); + + SegmentIterator seg_iter_blue = poly_blue.querySegmentIterator(); + + poly_red.setEmpty(); + + r = figure_size2; + if (r < 3) + continue; + + for (int j = 0; j < r; j++) { + int rand = random.nextInt(rand_max); + boolean b_random_new = r > 10 && ((1.0 * rand) / rand_max > 0.95); + pt = generator1.GetRandomCoord(); + if (j == 0 || b_random_new) + poly_red.startPath(pt); + else + poly_red.lineTo(pt); + } + + QuadTree.QuadTreeIterator iterator = quad_tree_blue.getIterator(); + SegmentIteratorImpl seg_iter_red = ((MultiPathImpl) poly_red._getImpl()).querySegmentIterator(); + + HashMap map1 = new HashMap(0); + + int count = 0; + int intersections_per_query = 0; + while (seg_iter_red.nextPath()) { + while (seg_iter_red.hasNextSegment()) { + Segment segment_red = seg_iter_red.nextSegment(); + segment_red.queryEnvelope2D(env); + + iterator.resetIterator(env, 0.0); + + int count_upper = 0; + int element_handle; + while ((element_handle = iterator.next()) != -1) { + count_upper++; + int index = quad_tree_blue.getElement(element_handle); + Boolean iter = (Boolean) map1.get(index); + if (iter == null) { + count++; + map1.put(index, true); + } + + intersections_per_query++; + } + + int intersection_count = quad_tree_blue.getIntersectionCount(env, 0.0, -1); + assertTrue(intersection_count == count_upper); + } + } + + seg_iter_red.resetToFirstPath(); + + HashMap map2 = new HashMap(0); + QuadTree.QuadTreeIterator sorted_iterator = quad_tree_blue.getIterator(true); + + int count_sorted = 0; + int intersections_per_query_sorted = 0; + while (seg_iter_red.nextPath()) { + while (seg_iter_red.hasNextSegment()) { + Segment segment_red = seg_iter_red.nextSegment(); + segment_red.queryEnvelope2D(env); + + sorted_iterator.resetIterator(env, 0.0); + + int count_upper_sorted = 0; + int element_handle; + int last_index = -1; + while ((element_handle = sorted_iterator.next()) != -1) { + count_upper_sorted++; + int index = quad_tree_blue.getElement(element_handle); + assertTrue(last_index < index); // ensure the element handles are returned in sorted order + last_index = index; + Boolean iter = (Boolean) map2.get(index); + if (iter == null) { + count_sorted++; + map2.put(index, true); + } + + intersections_per_query_sorted++; + } + + int intersection_count = quad_tree_blue.getIntersectionCount(env, 0.0, -1); + assertTrue(intersection_count == count_upper_sorted); + } + } + + assertTrue(count == count_sorted); + assertTrue(intersections_per_query == intersections_per_query_sorted); + } + } + + @Test + public static void test_perf_quad_tree() { + Envelope extent1 = new Envelope(); + extent1.setCoords(-1000, -1000, 1000, 1000); + + RandomCoordinateGenerator generator1 = new RandomCoordinateGenerator(1000, extent1, 0.001); + //HiResTimer timer; + for (int N = 16; N <= 1024/**1024*/; N *= 2) { + //timer.StartMeasurement(); + + Envelope2D extent = new Envelope2D(); + extent.setCoords(-1000, -1000, 1000, 1000); + HashMap data = new HashMap(0); + QuadTree qt = new QuadTree(extent, 10); + for (int i = 0; i < N; i++) { + Envelope2D env = new Envelope2D(); + Point2D center = generator1.GetRandomCoord().getXY(); + double w = 10; + env.setCoords(center, w, w); + env.intersect(extent); + if (env.isEmpty()) + continue; + + int h = qt.insert(i, env); + data.put(h, env); + } + + int ecount = 0; + AttributeStreamOfInt32 handles = new AttributeStreamOfInt32(0); + QuadTree.QuadTreeIterator iter = qt.getIterator(); + + Iterator> pairs = data.entrySet().iterator(); + while (pairs.hasNext()) { + Map.Entry entry = pairs.next(); + iter.resetIterator((Envelope2D) entry.getValue(), 0.001); + boolean remove_self = false; + for (int h = iter.next(); h != -1; h = iter.next()) { + if (h != entry.getKey()) + handles.add(h); + else { + remove_self = true; + } + + ecount++; + } + + for (int i = 0; i < handles.size(); i++) { + qt.removeElement(handles.get(i));//remove elements that were selected. + } + + if (remove_self) + qt.removeElement(entry.getKey()); + handles.resize(0); + } + + //printf("%d %0.3f (%I64d, %f, mem %I64d)\n", N, timer.GetMilliseconds(), ecount, ecount / double(N * N), memsize); + } + } + + @Test + public static void test2() { + MultiPoint multipoint = new MultiPoint(); + + for (int i = 0; i < 100; i++) { + for (int j = 0; j < 100; j++) { + multipoint.add(i, j); + } + } + + Envelope2D extent = new Envelope2D(); + multipoint.queryEnvelope2D(extent); + + MultiPointImpl multipointImpl = (MultiPointImpl) multipoint._getImpl(); + QuadTree quadtree = buildQuadTree_(multipointImpl); + + QuadTree.QuadTreeIterator qtIter = quadtree.getIterator(); + assertTrue(qtIter.next() == -1); + + int count = 0; + qtIter.resetIterator(extent, 0.0); + + while (qtIter.next() != -1) { + count++; + } + + assertTrue(count == 10000); + } + + static double randomWithRange(double min, double max) { + double range = Math.abs(max - min); + return (Math.random() * range) + (min <= max ? min : max); + } // @Test // public static void test_quadTree() { @@ -468,76 +468,76 @@ static double randomWithRange(double min, double max) { // } - public static Polyline makePolyline() { - Polyline poly = new Polyline(); - - // 0 - poly.startPath(0, 40); - poly.lineTo(30, 0); - - // 1 - poly.startPath(20, 70); - poly.lineTo(45, 100); - - // 2 - poly.startPath(50, 100); - poly.lineTo(50, 60); - - // 3 - poly.startPath(35, 25); - poly.lineTo(65, 45); - - // 4 - poly.startPath(60, 10); - poly.lineTo(65, 35); - - // 5 - poly.startPath(60, 60); - poly.lineTo(100, 60); - - // 6 - poly.startPath(80, 10); - poly.lineTo(80, 99); - - // 7 - poly.startPath(60, 60); - poly.lineTo(65, 35); - - return poly; - } - - static QuadTree buildQuadTree_(MultiPathImpl multipathImpl, boolean bStoreDuplicates) { - Envelope2D extent = new Envelope2D(); - multipathImpl.queryEnvelope2D(extent); - QuadTree quadTree = new QuadTree(extent, 8, bStoreDuplicates); - int hint_index = -1; - Envelope2D boundingbox = new Envelope2D(); - SegmentIteratorImpl seg_iter = multipathImpl.querySegmentIterator(); - while (seg_iter.nextPath()) { - while (seg_iter.hasNextSegment()) { - Segment segment = seg_iter.nextSegment(); - int index = seg_iter.getStartPointIndex(); - segment.queryEnvelope2D(boundingbox); - hint_index = quadTree.insert(index, boundingbox, hint_index); - } - } - - return quadTree; - } - - static QuadTree buildQuadTree_(MultiPointImpl multipointImpl) { - Envelope2D extent = new Envelope2D(); - multipointImpl.queryEnvelope2D(extent); - QuadTree quadTree = new QuadTree(extent, 8); - Envelope2D boundingbox = new Envelope2D(); - Point2D pt; - - for (int i = 0; i < multipointImpl.getPointCount(); i++) { - pt = multipointImpl.getXY(i); - boundingbox.setCoords(pt.x, pt.y, pt.x, pt.y); - quadTree.insert(i, boundingbox, -1); - } - - return quadTree; - } + public static Polyline makePolyline() { + Polyline poly = new Polyline(); + + // 0 + poly.startPath(0, 40); + poly.lineTo(30, 0); + + // 1 + poly.startPath(20, 70); + poly.lineTo(45, 100); + + // 2 + poly.startPath(50, 100); + poly.lineTo(50, 60); + + // 3 + poly.startPath(35, 25); + poly.lineTo(65, 45); + + // 4 + poly.startPath(60, 10); + poly.lineTo(65, 35); + + // 5 + poly.startPath(60, 60); + poly.lineTo(100, 60); + + // 6 + poly.startPath(80, 10); + poly.lineTo(80, 99); + + // 7 + poly.startPath(60, 60); + poly.lineTo(65, 35); + + return poly; + } + + static QuadTree buildQuadTree_(MultiPathImpl multipathImpl, boolean bStoreDuplicates) { + Envelope2D extent = new Envelope2D(); + multipathImpl.queryEnvelope2D(extent); + QuadTree quadTree = new QuadTree(extent, 8, bStoreDuplicates); + int hint_index = -1; + Envelope2D boundingbox = new Envelope2D(); + SegmentIteratorImpl seg_iter = multipathImpl.querySegmentIterator(); + while (seg_iter.nextPath()) { + while (seg_iter.hasNextSegment()) { + Segment segment = seg_iter.nextSegment(); + int index = seg_iter.getStartPointIndex(); + segment.queryEnvelope2D(boundingbox); + hint_index = quadTree.insert(index, boundingbox, hint_index); + } + } + + return quadTree; + } + + static QuadTree buildQuadTree_(MultiPointImpl multipointImpl) { + Envelope2D extent = new Envelope2D(); + multipointImpl.queryEnvelope2D(extent); + QuadTree quadTree = new QuadTree(extent, 8); + Envelope2D boundingbox = new Envelope2D(); + Point2D pt; + + for (int i = 0; i < multipointImpl.getPointCount(); i++) { + pt = multipointImpl.getXY(i); + boundingbox.setCoords(pt.x, pt.y, pt.x, pt.y); + quadTree.insert(i, boundingbox, -1); + } + + return quadTree; + } } diff --git a/src/test/java/com/esri/core/geometry/TestRandomPoints.java b/src/test/java/com/esri/core/geometry/TestRandomPoints.java index ed2d346a..81b92429 100644 --- a/src/test/java/com/esri/core/geometry/TestRandomPoints.java +++ b/src/test/java/com/esri/core/geometry/TestRandomPoints.java @@ -7,89 +7,89 @@ * Created by davidraleigh on 5/10/17. */ public class TestRandomPoints extends TestCase { - @Override - protected void setUp() throws Exception { - super.setUp(); - } + @Override + protected void setUp() throws Exception { + super.setUp(); + } - @Override - protected void tearDown() throws Exception { - super.tearDown(); - } + @Override + protected void tearDown() throws Exception { + super.tearDown(); + } - @Test - public void testPointCreate() { - OperatorRandomPoints operatorRandomPoints = OperatorRandomPoints.local(); - Polygon poly = new Polygon(); - poly.startPath(0, 0); - poly.lineTo(0, 10); - poly.lineTo(10, 10); - poly.closePathWithLine(); - SpatialReference sr = SpatialReference.create(4326); - MultiPoint geometry = (MultiPoint) operatorRandomPoints.execute(poly, 1.3, 1977, sr, null); - assertNotNull(geometry); - assertEquals(788593, geometry.getPointCount()); - assertNotNull(geometry.getXY(0)); - assertNotNull(geometry.getXY(geometry.getPointCount() - 1)); - Polygon bufferedpoly = (Polygon) OperatorBuffer.local().execute(poly, sr, sr.getTolerance() * 2, null); - boolean t = OperatorContains.local().execute(bufferedpoly, geometry, sr, null); - assertTrue(t); - } + @Test + public void testPointCreate() { + OperatorRandomPoints operatorRandomPoints = OperatorRandomPoints.local(); + Polygon poly = new Polygon(); + poly.startPath(0, 0); + poly.lineTo(0, 10); + poly.lineTo(10, 10); + poly.closePathWithLine(); + SpatialReference sr = SpatialReference.create(4326); + MultiPoint geometry = (MultiPoint) operatorRandomPoints.execute(poly, 1.3, 1977, sr, null); + assertNotNull(geometry); + assertEquals(788593, geometry.getPointCount()); + assertNotNull(geometry.getXY(0)); + assertNotNull(geometry.getXY(geometry.getPointCount() - 1)); + Polygon bufferedpoly = (Polygon) OperatorBuffer.local().execute(poly, sr, sr.getTolerance() * 2, null); + boolean t = OperatorContains.local().execute(bufferedpoly, geometry, sr, null); + assertTrue(t); + } - @Test - public void testPolygonWithHole() { - String wktpolygon = "POLYGON((0 0, 0 10, 10 10, 10 0),(3 3, 7 3, 7 7, 3 7))"; - Geometry geometry = GeometryEngine.geometryFromWkt(wktpolygon, 0, Geometry.Type.Unknown); - MultiPoint multiPoint = (MultiPoint)OperatorRandomPoints.local().execute(geometry, .0013, 1977, SpatialReference.create(4326), null); + @Test + public void testPolygonWithHole() { + String wktpolygon = "POLYGON((0 0, 0 10, 10 10, 10 0),(3 3, 7 3, 7 7, 3 7))"; + Geometry geometry = GeometryEngine.geometryFromWkt(wktpolygon, 0, Geometry.Type.Unknown); + MultiPoint multiPoint = (MultiPoint) OperatorRandomPoints.local().execute(geometry, .0013, 1977, SpatialReference.create(4326), null); - String wktPolygonNoRing = "POLYGON((0 0, 0 10, 10 10, 10 0))"; - Geometry geometryNoRing = GeometryEngine.geometryFromWkt(wktPolygonNoRing, 0, Geometry.Type.Unknown); - MultiPoint multiPointNoRing = (MultiPoint)OperatorRandomPoints.local().execute(geometryNoRing, 0.0013, 1977, SpatialReference.create(4326), null); + String wktPolygonNoRing = "POLYGON((0 0, 0 10, 10 10, 10 0))"; + Geometry geometryNoRing = GeometryEngine.geometryFromWkt(wktPolygonNoRing, 0, Geometry.Type.Unknown); + MultiPoint multiPointNoRing = (MultiPoint) OperatorRandomPoints.local().execute(geometryNoRing, 0.0013, 1977, SpatialReference.create(4326), null); - Geometry intersector = OperatorGeodeticDensifyByLength.local().execute(geometry, SpatialReference.create(4326), 1232535.5660433513, GeodeticCurveType.Geodesic, null); - Geometry geom = GeometryEngine.intersect(intersector, multiPointNoRing, SpatialReference.create(4326)); + Geometry intersector = OperatorGeodeticDensifyByLength.local().execute(geometry, SpatialReference.create(4326), 1232535.5660433513, GeodeticCurveType.Geodesic, null); + Geometry geom = GeometryEngine.intersect(intersector, multiPointNoRing, SpatialReference.create(4326)); - assertEquals(multiPoint.getPointCount(), ((MultiPoint)geom).getPointCount()); - } + assertEquals(multiPoint.getPointCount(), ((MultiPoint) geom).getPointCount()); + } - @Test - public void testMultiPartPolygonCreate() { - String wktpolygon2 = "MULTIPOLYGON (((0 0, 0 10, 10 10, 10 0)), ((20 0, 20 10, 30 10, 30 0)))"; - Geometry geometry2 = GeometryEngine.geometryFromWkt(wktpolygon2, 0, Geometry.Type.Unknown); - MultiPoint multiPoint2 = (MultiPoint)OperatorRandomPoints.local().execute(geometry2, 1.3, 1977, SpatialReference.create(4326), null); + @Test + public void testMultiPartPolygonCreate() { + String wktpolygon2 = "MULTIPOLYGON (((0 0, 0 10, 10 10, 10 0)), ((20 0, 20 10, 30 10, 30 0)))"; + Geometry geometry2 = GeometryEngine.geometryFromWkt(wktpolygon2, 0, Geometry.Type.Unknown); + MultiPoint multiPoint2 = (MultiPoint) OperatorRandomPoints.local().execute(geometry2, 1.3, 1977, SpatialReference.create(4326), null); - String wktPolygon = "POLYGON((0 0, 0 10, 10 10, 10 0))"; - Geometry geometry = GeometryEngine.geometryFromWkt(wktPolygon, 0, Geometry.Type.Unknown); - MultiPoint multiPoint = (MultiPoint)OperatorRandomPoints.local().execute(geometry, 1.3, 1977, SpatialReference.create(4326), null); + String wktPolygon = "POLYGON((0 0, 0 10, 10 10, 10 0))"; + Geometry geometry = GeometryEngine.geometryFromWkt(wktPolygon, 0, Geometry.Type.Unknown); + MultiPoint multiPoint = (MultiPoint) OperatorRandomPoints.local().execute(geometry, 1.3, 1977, SpatialReference.create(4326), null); - assertTrue(multiPoint.getPointCount() * 2 > 3179429); - assertTrue(multiPoint2.getPointCount() * 2 > 3179429); - } + assertTrue(multiPoint.getPointCount() * 2 > 3179429); + assertTrue(multiPoint2.getPointCount() * 2 > 3179429); + } - @Test - public void testExcpetion() { - String wkt = "Polygon((0 0, 0 10, 10 10,10 0))"; - Geometry geometry = GeometryEngine.geometryFromWkt(wkt, 0, Geometry.Type.Unknown); - try { - // TODO exception java.lang.OutOfMemoryError: Java heap space for pointsPerSquareKm == 300 - MultiPoint multiPoint = (MultiPoint)OperatorRandomPoints.local().execute(geometry, 1000, 1977, SpatialReference.create(4326), null); - fail("Expected an GeometryException to be thrown"); - } catch (GeometryException geometryException) { - assertEquals(geometryException.getMessage(), "Random Point count outside of available"); - } - } + @Test + public void testExcpetion() { + String wkt = "Polygon((0 0, 0 10, 10 10,10 0))"; + Geometry geometry = GeometryEngine.geometryFromWkt(wkt, 0, Geometry.Type.Unknown); + try { + // TODO exception java.lang.OutOfMemoryError: Java heap space for pointsPerSquareKm == 300 + MultiPoint multiPoint = (MultiPoint) OperatorRandomPoints.local().execute(geometry, 1000, 1977, SpatialReference.create(4326), null); + fail("Expected an GeometryException to be thrown"); + } catch (GeometryException geometryException) { + assertEquals(geometryException.getMessage(), "Random Point count outside of available"); + } + } - @Test - public void testSpecificArea() { - double pointsPerKmSquare = 1; - Double areaKm = 16207.53; - int lowEstimate = areaKm.intValue() - 20; - String wkt = "POLYGON ((46.030485054706105 26.017389342815264, 45.997526070331105 25.016021311217134, 47.469694039081105 24.996108304947285, 47.447721382831105 26.007515943484098, 46.030485054706105 26.017389342815264))"; - Geometry geometry = GeometryEngine.geometryFromWkt(wkt, 0, Geometry.Type.Unknown); + @Test + public void testSpecificArea() { + double pointsPerKmSquare = 1; + Double areaKm = 16207.53; + int lowEstimate = areaKm.intValue() - 20; + String wkt = "POLYGON ((46.030485054706105 26.017389342815264, 45.997526070331105 25.016021311217134, 47.469694039081105 24.996108304947285, 47.447721382831105 26.007515943484098, 46.030485054706105 26.017389342815264))"; + Geometry geometry = GeometryEngine.geometryFromWkt(wkt, 0, Geometry.Type.Unknown); - MultiPoint multiPoint = (MultiPoint)OperatorRandomPoints.local().execute(geometry, pointsPerKmSquare, 1977, SpatialReference.create(4326), null); + MultiPoint multiPoint = (MultiPoint) OperatorRandomPoints.local().execute(geometry, pointsPerKmSquare, 1977, SpatialReference.create(4326), null); - assertTrue(multiPoint.getPointCount() > lowEstimate); - assertTrue(multiPoint.getPointCount() < lowEstimate + 20); - } + assertTrue(multiPoint.getPointCount() > lowEstimate); + assertTrue(multiPoint.getPointCount() < lowEstimate + 20); + } } diff --git a/src/test/java/com/esri/core/geometry/TestRasterizedGeometry2D.java b/src/test/java/com/esri/core/geometry/TestRasterizedGeometry2D.java index b0b806ee..2e035024 100644 --- a/src/test/java/com/esri/core/geometry/TestRasterizedGeometry2D.java +++ b/src/test/java/com/esri/core/geometry/TestRasterizedGeometry2D.java @@ -29,130 +29,130 @@ import org.junit.Test; public class TestRasterizedGeometry2D extends TestCase { - boolean rgHelper(RasterizedGeometry2D rg, MultiPath mp) { - SegmentIterator iter = mp.querySegmentIterator(); - while (iter.nextPath()) { - while (iter.hasNextSegment()) { - Segment seg = iter.nextSegment(); - int count = 20; - - for (int i = 0; i < count; i++) { - double t = (1.0 * i / count); - Point2D pt = seg.getCoord2D(t); - RasterizedGeometry2D.HitType hit = rg.queryPointInGeometry( - pt.x, pt.y); - if (hit != RasterizedGeometry2D.HitType.Border) - return false; - } - } - } - - if (mp.getType() != Geometry.Type.Polygon) - return true; - - Polygon poly = (Polygon) mp; - Envelope2D env = new Envelope2D(); - poly.queryEnvelope2D(env); - int count = 100; - for (int iy = 0; iy < count; iy++) { - double ty = 1.0 * iy / count; - double y = env.ymin * (1.0 - ty) + ty * env.ymax; - for (int ix = 0; ix < count; ix++) { - double tx = 1.0 * ix / count; - double x = env.xmin * (1.0 - tx) + tx * env.xmax; - - RasterizedGeometry2D.HitType hit = rg - .queryPointInGeometry(x, y); - PolygonUtils.PiPResult res = PolygonUtils.isPointInPolygon2D( - poly, new Point2D(x, y), 0); - if (res == PolygonUtils.PiPResult.PiPInside) { - boolean bgood = (hit == RasterizedGeometry2D.HitType.Border || hit == RasterizedGeometry2D.HitType.Inside); - if (!bgood) - return false; - } else if (res == PolygonUtils.PiPResult.PiPOutside) { - boolean bgood = (hit == RasterizedGeometry2D.HitType.Border || hit == RasterizedGeometry2D.HitType.Outside); - if (!bgood) - return false; - } else { - boolean bgood = (hit == RasterizedGeometry2D.HitType.Border); - if (!bgood) - return false; - } - } - } - - return true; - } - - @Test - public void test() { - { - Polygon poly = new Polygon(); - poly.startPath(10, 10); - poly.lineTo(100, 10); - poly.lineTo(100, 100); - poly.lineTo(10, 100); - - // create using move semantics. Usually we do not use this - // approach. - RasterizedGeometry2D rg = RasterizedGeometry2D - .create(poly, 0, 1024); - //rg.dbgSaveToBitmap("c:/temp/_dbg.bmp"); - RasterizedGeometry2D.HitType res; - res = rg.queryPointInGeometry(7, 10); - assertTrue(res == RasterizedGeometry2D.HitType.Outside); - res = rg.queryPointInGeometry(10, 10); - assertTrue(res == RasterizedGeometry2D.HitType.Border); - res = rg.queryPointInGeometry(50, 50); - assertTrue(res == RasterizedGeometry2D.HitType.Inside); - - assertTrue(rgHelper(rg, poly)); - } - - { - Polygon poly = new Polygon(); - // create a star (non-simple) - poly.startPath(1, 0); - poly.lineTo(5, 10); - poly.lineTo(9, 0); - poly.lineTo(0, 6); - poly.lineTo(10, 6); - - RasterizedGeometry2D rg = RasterizedGeometry2D - .create(poly, 0, 1024); - //rg.dbgSaveToBitmap("c:/temp/_dbg.bmp"); - RasterizedGeometry2D.HitType res; - res = rg.queryPointInGeometry(5, 5.5); - assertTrue(res == RasterizedGeometry2D.HitType.Outside); - res = rg.queryPointInGeometry(5, 8); - assertTrue(res == RasterizedGeometry2D.HitType.Inside); - res = rg.queryPointInGeometry(1.63, 0.77); - assertTrue(res == RasterizedGeometry2D.HitType.Inside); - res = rg.queryPointInGeometry(1, 3); - assertTrue(res == RasterizedGeometry2D.HitType.Outside); - res = rg.queryPointInGeometry(1.6, 0.1); - assertTrue(res == RasterizedGeometry2D.HitType.Outside); - assertTrue(rgHelper(rg, poly)); - } - - { - Polygon poly = new Polygon(); - // create a star (non-simple) - poly.startPath(1, 0); - poly.lineTo(5, 10); - poly.lineTo(9, 0); - poly.lineTo(0, 6); - poly.lineTo(10, 6); - - SpatialReference sr = SpatialReference.create(4326); - poly = (Polygon) OperatorSimplify.local().execute(poly, sr, true, null); - OperatorContains.local().accelerateGeometry(poly, sr, GeometryAccelerationDegree.enumMedium); - assertFalse(OperatorContains.local().execute(poly, new Point(5, 5.5), sr, null)); - assertTrue(OperatorContains.local().execute(poly, new Point(5, 8), sr, null)); - assertTrue(OperatorContains.local().execute(poly, new Point(1.63, 0.77), sr, null)); - assertFalse(OperatorContains.local().execute(poly, new Point(1, 3), sr, null)); - assertFalse(OperatorContains.local().execute(poly, new Point(1.6, 0.1), sr, null)); - } + boolean rgHelper(RasterizedGeometry2D rg, MultiPath mp) { + SegmentIterator iter = mp.querySegmentIterator(); + while (iter.nextPath()) { + while (iter.hasNextSegment()) { + Segment seg = iter.nextSegment(); + int count = 20; + + for (int i = 0; i < count; i++) { + double t = (1.0 * i / count); + Point2D pt = seg.getCoord2D(t); + RasterizedGeometry2D.HitType hit = rg.queryPointInGeometry( + pt.x, pt.y); + if (hit != RasterizedGeometry2D.HitType.Border) + return false; + } + } + } + + if (mp.getType() != Geometry.Type.Polygon) + return true; + + Polygon poly = (Polygon) mp; + Envelope2D env = new Envelope2D(); + poly.queryEnvelope2D(env); + int count = 100; + for (int iy = 0; iy < count; iy++) { + double ty = 1.0 * iy / count; + double y = env.ymin * (1.0 - ty) + ty * env.ymax; + for (int ix = 0; ix < count; ix++) { + double tx = 1.0 * ix / count; + double x = env.xmin * (1.0 - tx) + tx * env.xmax; + + RasterizedGeometry2D.HitType hit = rg + .queryPointInGeometry(x, y); + PolygonUtils.PiPResult res = PolygonUtils.isPointInPolygon2D( + poly, new Point2D(x, y), 0); + if (res == PolygonUtils.PiPResult.PiPInside) { + boolean bgood = (hit == RasterizedGeometry2D.HitType.Border || hit == RasterizedGeometry2D.HitType.Inside); + if (!bgood) + return false; + } else if (res == PolygonUtils.PiPResult.PiPOutside) { + boolean bgood = (hit == RasterizedGeometry2D.HitType.Border || hit == RasterizedGeometry2D.HitType.Outside); + if (!bgood) + return false; + } else { + boolean bgood = (hit == RasterizedGeometry2D.HitType.Border); + if (!bgood) + return false; + } + } + } + + return true; + } + + @Test + public void test() { + { + Polygon poly = new Polygon(); + poly.startPath(10, 10); + poly.lineTo(100, 10); + poly.lineTo(100, 100); + poly.lineTo(10, 100); + + // create using move semantics. Usually we do not use this + // approach. + RasterizedGeometry2D rg = RasterizedGeometry2D + .create(poly, 0, 1024); + //rg.dbgSaveToBitmap("c:/temp/_dbg.bmp"); + RasterizedGeometry2D.HitType res; + res = rg.queryPointInGeometry(7, 10); + assertTrue(res == RasterizedGeometry2D.HitType.Outside); + res = rg.queryPointInGeometry(10, 10); + assertTrue(res == RasterizedGeometry2D.HitType.Border); + res = rg.queryPointInGeometry(50, 50); + assertTrue(res == RasterizedGeometry2D.HitType.Inside); + + assertTrue(rgHelper(rg, poly)); + } + + { + Polygon poly = new Polygon(); + // create a star (non-simple) + poly.startPath(1, 0); + poly.lineTo(5, 10); + poly.lineTo(9, 0); + poly.lineTo(0, 6); + poly.lineTo(10, 6); + + RasterizedGeometry2D rg = RasterizedGeometry2D + .create(poly, 0, 1024); + //rg.dbgSaveToBitmap("c:/temp/_dbg.bmp"); + RasterizedGeometry2D.HitType res; + res = rg.queryPointInGeometry(5, 5.5); + assertTrue(res == RasterizedGeometry2D.HitType.Outside); + res = rg.queryPointInGeometry(5, 8); + assertTrue(res == RasterizedGeometry2D.HitType.Inside); + res = rg.queryPointInGeometry(1.63, 0.77); + assertTrue(res == RasterizedGeometry2D.HitType.Inside); + res = rg.queryPointInGeometry(1, 3); + assertTrue(res == RasterizedGeometry2D.HitType.Outside); + res = rg.queryPointInGeometry(1.6, 0.1); + assertTrue(res == RasterizedGeometry2D.HitType.Outside); + assertTrue(rgHelper(rg, poly)); + } + + { + Polygon poly = new Polygon(); + // create a star (non-simple) + poly.startPath(1, 0); + poly.lineTo(5, 10); + poly.lineTo(9, 0); + poly.lineTo(0, 6); + poly.lineTo(10, 6); + + SpatialReference sr = SpatialReference.create(4326); + poly = (Polygon) OperatorSimplify.local().execute(poly, sr, true, null); + OperatorContains.local().accelerateGeometry(poly, sr, GeometryAccelerationDegree.enumMedium); + assertFalse(OperatorContains.local().execute(poly, new Point(5, 5.5), sr, null)); + assertTrue(OperatorContains.local().execute(poly, new Point(5, 8), sr, null)); + assertTrue(OperatorContains.local().execute(poly, new Point(1.63, 0.77), sr, null)); + assertFalse(OperatorContains.local().execute(poly, new Point(1, 3), sr, null)); + assertFalse(OperatorContains.local().execute(poly, new Point(1.6, 0.1), sr, null)); + } /* { @@ -171,5 +171,5 @@ public void test() { rg.dbgSaveToBitmap("c:/temp/_dbg.bmp"); for (;;){} }*/ - } + } } diff --git a/src/test/java/com/esri/core/geometry/TestRelation.java b/src/test/java/com/esri/core/geometry/TestRelation.java index 50b8c0b9..fc912f22 100644 --- a/src/test/java/com/esri/core/geometry/TestRelation.java +++ b/src/test/java/com/esri/core/geometry/TestRelation.java @@ -11,71 +11,71 @@ public class TestRelation extends TestCase { - @Override - protected void setUp() throws Exception { - super.setUp(); - } - - @Override - protected void tearDown() throws Exception { - super.tearDown(); - } - - @Test - public void testCreation() { - { - OperatorFactoryLocal projEnv = OperatorFactoryLocal.getInstance(); - SpatialReference inputSR = SpatialReference.create(3857); - - Polygon poly1 = new Polygon(); - Envelope2D env1 = new Envelope2D(); - env1.setCoords(855277, 3892059, 855277 + 100, 3892059 + 100); - poly1.addEnvelope(env1, false); - - Polygon poly2 = new Polygon(); - Envelope2D env2 = new Envelope2D(); - env2.setCoords(855277, 3892059, 855277 + 300, 3892059 + 200); - poly2.addEnvelope(env2, false); - - Polygon poly3 = new Polygon(); - Envelope2D env3 = new Envelope2D(); - env3.setCoords(855277 + 100, 3892059 + 100, 855277 - 300, 3892059 - 200); - poly3.addEnvelope(env3, false); - - - List list2 = new ArrayList<>(); - list2.add(poly1); - list2.add(poly2); - - List list3 = new ArrayList<>(list2); - list3.add(poly3); - - - { - OperatorEquals operatorEquals = (OperatorEquals) (projEnv - .getOperator(Operator.Type.Equals)); - boolean result = operatorEquals.execute(poly1, poly2, inputSR, - null); - assertTrue(!result); - Polygon poly11 = new Polygon(); - poly1.copyTo(poly11); - result = operatorEquals.execute(poly1, poly11, inputSR, null); - assertTrue(result); - } - { - OperatorCrosses operatorCrosses = (OperatorCrosses) (projEnv - .getOperator(Operator.Type.Crosses)); - boolean result = operatorCrosses.execute(poly1, poly2, inputSR, - null); - assertTrue(!result); - - SimpleGeometryCursor simpleGeometryCursor1 = new SimpleGeometryCursor(poly1); - SimpleGeometryCursor simpleGeometryCursor2 = new SimpleGeometryCursor(new ArrayDeque(list2)); - HashMap relate_map = - operatorCrosses.execute(poly1, simpleGeometryCursor2, inputSR, null); - assertNotNull(relate_map); - assertTrue(!relate_map.get(0L)); - assertTrue(!relate_map.get(1L)); + @Override + protected void setUp() throws Exception { + super.setUp(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + } + + @Test + public void testCreation() { + { + OperatorFactoryLocal projEnv = OperatorFactoryLocal.getInstance(); + SpatialReference inputSR = SpatialReference.create(3857); + + Polygon poly1 = new Polygon(); + Envelope2D env1 = new Envelope2D(); + env1.setCoords(855277, 3892059, 855277 + 100, 3892059 + 100); + poly1.addEnvelope(env1, false); + + Polygon poly2 = new Polygon(); + Envelope2D env2 = new Envelope2D(); + env2.setCoords(855277, 3892059, 855277 + 300, 3892059 + 200); + poly2.addEnvelope(env2, false); + + Polygon poly3 = new Polygon(); + Envelope2D env3 = new Envelope2D(); + env3.setCoords(855277 + 100, 3892059 + 100, 855277 - 300, 3892059 - 200); + poly3.addEnvelope(env3, false); + + + List list2 = new ArrayList<>(); + list2.add(poly1); + list2.add(poly2); + + List list3 = new ArrayList<>(list2); + list3.add(poly3); + + + { + OperatorEquals operatorEquals = (OperatorEquals) (projEnv + .getOperator(Operator.Type.Equals)); + boolean result = operatorEquals.execute(poly1, poly2, inputSR, + null); + assertTrue(!result); + Polygon poly11 = new Polygon(); + poly1.copyTo(poly11); + result = operatorEquals.execute(poly1, poly11, inputSR, null); + assertTrue(result); + } + { + OperatorCrosses operatorCrosses = (OperatorCrosses) (projEnv + .getOperator(Operator.Type.Crosses)); + boolean result = operatorCrosses.execute(poly1, poly2, inputSR, + null); + assertTrue(!result); + + SimpleGeometryCursor simpleGeometryCursor1 = new SimpleGeometryCursor(poly1); + SimpleGeometryCursor simpleGeometryCursor2 = new SimpleGeometryCursor(new ArrayDeque(list2)); + HashMap relate_map = + operatorCrosses.execute(poly1, simpleGeometryCursor2, inputSR, null); + assertNotNull(relate_map); + assertTrue(!relate_map.get(0L)); + assertTrue(!relate_map.get(1L)); /*simpleGeometryCursor2 = new SimpleGeometryCursor(list2); SimpleGeometryCursor simpleGeometryCursor3 = new SimpleGeometryCursor(list3); @@ -87,5454 +87,5454 @@ public void testCreation() { assertTrue(!relate_map.get(1).get(1)); assertTrue(!relate_map.get(2).get(0)); assertTrue(!relate_map.get(2).get(1));*/ - } - { - OperatorWithin operatorWithin = (OperatorWithin) (projEnv - .getOperator(Operator.Type.Within)); - boolean result = operatorWithin.execute(poly1, poly2, inputSR, - null); - assertTrue(result); - } - - { - OperatorDisjoint operatorDisjoint = (OperatorDisjoint) (projEnv - .getOperator(Operator.Type.Disjoint)); - OperatorIntersects operatorIntersects = (OperatorIntersects) (projEnv - .getOperator(Operator.Type.Intersects)); - boolean result = operatorDisjoint.execute(poly1, poly2, - inputSR, null); - assertTrue(!result); - { - result = operatorIntersects.execute(poly1, poly2, inputSR, - null); - assertTrue(result); - } - } - - { - OperatorDisjoint operatorDisjoint = (OperatorDisjoint) (projEnv - .getOperator(Operator.Type.Disjoint)); - OperatorIntersects operatorIntersects = (OperatorIntersects) (projEnv - .getOperator(Operator.Type.Intersects)); - Envelope2D env2D = new Envelope2D(); - poly2.queryEnvelope2D(env2D); - Envelope envelope = new Envelope(env2D); - boolean result = operatorDisjoint.execute(envelope, poly2, - inputSR, null); - assertTrue(!result); - { - result = operatorIntersects.execute(envelope, poly2, - inputSR, null); - assertTrue(result); - } - } - - { - OperatorDisjoint operatorDisjoint = (OperatorDisjoint) (projEnv - .getOperator(Operator.Type.Disjoint)); - OperatorIntersects operatorIntersects = (OperatorIntersects) (projEnv - .getOperator(Operator.Type.Intersects)); - Polygon poly = new Polygon(); - - Envelope2D env2D = new Envelope2D(); - env2D.setCoords(855277, 3892059, 855277 + 100, 3892059 + 100); - poly.addEnvelope(env2D, false); - env2D.setCoords(855277 + 10, 3892059 + 10, 855277 + 90, - 3892059 + 90); - poly.addEnvelope(env2D, true); - - env2D.setCoords(855277 + 20, 3892059 + 20, 855277 + 200, - 3892059 + 80); - Envelope envelope = new Envelope(env2D); - boolean result = operatorDisjoint.execute(envelope, poly, - inputSR, null); - assertTrue(!result); - { - result = operatorIntersects.execute(envelope, poly, - inputSR, null); - assertTrue(result); - } - } - - { - OperatorTouches operatorTouches = (OperatorTouches) (projEnv - .getOperator(Operator.Type.Touches)); - boolean result = operatorTouches.execute(poly1, poly2, inputSR, - null); - assertTrue(!result); - } - - } - } - - @Test - public void testOperatorDisjoint() { - { - OperatorFactoryLocal projEnv = OperatorFactoryLocal.getInstance(); - SpatialReference inputSR = SpatialReference.create(3857); - - Polygon poly1 = new Polygon(); - Envelope2D env1 = new Envelope2D(); - env1.setCoords(855277, 3892059, 855277 + 100, 3892059 + 100); - poly1.addEnvelope(env1, false); - - Polygon poly2 = new Polygon(); - Envelope2D env2 = new Envelope2D(); - env2.setCoords(855277, 3892059, 855277 + 300, 3892059 + 200); - poly2.addEnvelope(env2, false); - - Polygon poly3 = new Polygon(); - Envelope2D env3 = new Envelope2D(); - env3.setCoords(855277 + 100, 3892059 + 100, 855277 + 100 + 100, - 3892059 + 100 + 100); - poly3.addEnvelope(env3, false); - - Polygon poly4 = new Polygon(); - Envelope2D env4 = new Envelope2D(); - env4.setCoords(855277 + 200, 3892059 + 200, 855277 + 200 + 100, - 3892059 + 200 + 100); - poly4.addEnvelope(env4, false); - - Point point1 = new Point(855277, 3892059); - Point point2 = new Point(855277 + 2, 3892059 + 3); - Point point3 = new Point(855277 - 2, 3892059 - 3); - - { - OperatorDisjoint operatorDisjoint = (OperatorDisjoint) (projEnv - .getOperator(Operator.Type.Disjoint)); - boolean result = operatorDisjoint.execute(poly1, poly2, - inputSR, null); - assertTrue(!result); - result = operatorDisjoint.execute(poly1, poly3, inputSR, null); - assertTrue(!result); - result = operatorDisjoint.execute(poly1, poly4, inputSR, null); - assertTrue(result); - - result = operatorDisjoint.execute(poly1, point1, inputSR, null); - assertTrue(!result); - result = operatorDisjoint.execute(point1, poly1, inputSR, null); - assertTrue(!result); - result = operatorDisjoint.execute(poly1, point2, inputSR, null); - assertTrue(!result); - result = operatorDisjoint.execute(point2, poly1, inputSR, null); - assertTrue(!result); - result = operatorDisjoint.execute(poly1, point3, inputSR, null); - assertTrue(result); - result = operatorDisjoint.execute(point3, poly1, inputSR, null); - assertTrue(result); - } - } - } - - @Test - public void testTouchPointLineCR183227() {// Tests CR 183227 - OperatorTouches operatorTouches = (OperatorTouches) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Touches)); - - Geometry baseGeom = new Point(-130, 10); - Polyline pl = new Polyline(); - // pl.startPath(std::make_shared(-130, 10)); - pl.startPath(-130, 10); - pl.lineTo(-131, 15); - pl.lineTo(-140, 20); - - SpatialReference sr = SpatialReference.create(4326); - - boolean isTouched; - boolean isTouched2; - isTouched = operatorTouches.execute(baseGeom, pl, sr, null); - isTouched2 = operatorTouches.execute(pl, baseGeom, sr, null); - assertTrue(isTouched && isTouched2); - - { - baseGeom = new Point(-131, 15); - isTouched = operatorTouches.execute(baseGeom, pl, sr, null); - isTouched2 = operatorTouches.execute(pl, baseGeom, sr, null); - assertTrue(!isTouched && !isTouched2); - } - } - - @Test - public void testTouchPointLineClosed() {// Tests CR 183227 - OperatorTouches operatorTouches = (OperatorTouches) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Touches)); - - Geometry baseGeom = new Point(-130, 10); - Polyline pl = new Polyline(); - pl.startPath(-130, 10); - pl.lineTo(-131, 15); - pl.lineTo(-140, 20); - pl.lineTo(-130, 10); - - SpatialReference sr = SpatialReference.create(4326); - - boolean isTouched; - boolean isTouched2; - isTouched = operatorTouches.execute(baseGeom, pl, sr, null); - isTouched2 = operatorTouches.execute(pl, baseGeom, sr, null); - assertTrue(!isTouched && !isTouched2);// this may change in future - - { - baseGeom = new Point(-131, 15); - isTouched = operatorTouches.execute(baseGeom, pl, sr, null); - isTouched2 = operatorTouches.execute(pl, baseGeom, sr, null); - assertTrue(!isTouched && !isTouched2); - } - } - - @Test - public void testTouchPolygonPolygon() { - OperatorTouches operatorTouches = (OperatorTouches) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Touches)); - - Polygon pg = new Polygon(); - pg.startPath(-130, 10); - pg.lineTo(-131, 15); - pg.lineTo(-140, 20); - - Polygon pg2 = new Polygon(); - pg2.startPath(-130, 10); - pg2.lineTo(-131, 15); - pg2.lineTo(-120, 20); - SpatialReference sr = SpatialReference.create(4326); - - boolean isTouched; - boolean isTouched2; - isTouched = operatorTouches.execute(pg, pg2, sr, null); - isTouched2 = operatorTouches.execute(pg2, pg, sr, null); - assertTrue(isTouched && isTouched2); - } - - @Test - public void testContainsFailureCR186456() { - { - OperatorContains op = (OperatorContains) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Contains)); - String str = "{\"rings\":[[[406944.399999999,287461.450000001],[406947.750000011,287462.299999997],[406946.44999999,287467.450000001],[406943.050000005,287466.550000005],[406927.799999992,287456.849999994],[406926.949999996,287456.599999995],[406924.800000005,287455.999999998],[406924.300000007,287455.849999999],[406924.200000008,287456.099999997],[406923.450000011,287458.449999987],[406922.999999987,287459.800000008],[406922.29999999,287462.099999998],[406921.949999991,287463.449999992],[406921.449999993,287465.050000011],[406920.749999996,287466.700000004],[406919.800000001,287468.599999996],[406919.050000004,287469.99999999],[406917.800000009,287471.800000008],[406916.04999999,287473.550000001],[406915.449999993,287473.999999999],[406913.700000001,287475.449999993],[406913.300000002,287475.899999991],[406912.050000008,287477.250000011],[406913.450000002,287478.150000007],[406915.199999994,287478.650000005],[406915.999999991,287478.800000005],[406918.300000007,287479.200000003],[406920.649999997,287479.450000002],[406923.100000013,287479.550000001],[406925.750000001,287479.450000002],[406928.39999999,287479.150000003],[406929.80000001,287478.950000004],[406932.449999998,287478.350000006],[406935.099999987,287477.60000001],[406938.699999998,287476.349999989],[406939.649999994,287473.949999999],[406939.799999993,287473.949999999],[406941.249999987,287473.75],[406942.700000007,287473.250000002],[406943.100000005,287473.100000003],[406943.950000001,287472.750000004],[406944.799999998,287472.300000006],[406944.999999997,287472.200000007],[406946.099999992,287471.200000011],[406946.299999991,287470.950000012],[406948.00000001,287468.599999996],[406948.10000001,287468.399999997],[406950.100000001,287465.050000011],[406951.949999993,287461.450000001],[406952.049999993,287461.300000001],[406952.69999999,287459.900000007],[406953.249999987,287458.549999987],[406953.349999987,287458.299999988],[406953.650000012,287457.299999992],[406953.900000011,287456.349999996],[406954.00000001,287455.300000001],[406954.00000001,287454.750000003],[406953.850000011,287453.750000008],[406953.550000012,287452.900000011],[406953.299999987,287452.299999988],[406954.500000008,287450.299999996],[406954.00000001,287449.000000002],[406953.399999987,287447.950000006],[406953.199999988,287447.550000008],[406952.69999999,287446.850000011],[406952.149999992,287446.099999988],[406951.499999995,287445.499999991],[406951.149999996,287445.249999992],[406950.449999999,287444.849999994],[406949.600000003,287444.599999995],[406949.350000004,287444.549999995],[406948.250000009,287444.499999995],[406947.149999987,287444.699999994],[406946.849999989,287444.749999994],[406945.899999993,287444.949999993],[406944.999999997,287445.349999991],[406944.499999999,287445.64999999],[406943.650000003,287446.349999987],[406942.900000006,287447.10000001],[406942.500000008,287447.800000007],[406942.00000001,287448.700000003],[406941.600000011,287449.599999999],[406941.350000013,287450.849999994],[406941.350000013,287451.84999999],[406941.450000012,287452.850000012],[406941.750000011,287453.850000007],[406941.800000011,287454.000000007],[406942.150000009,287454.850000003],[406942.650000007,287455.6],[406943.150000005,287456.299999997],[406944.499999999,287457.299999992],[406944.899999997,287457.599999991],[406945.299999995,287457.949999989],[406944.399999999,287461.450000001],[406941.750000011,287461.999999998],[406944.399999999,287461.450000001]],[[406944.399999999,287461.450000001],[406947.750000011,287462.299999997],[406946.44999999,287467.450000001],[406943.050000005,287466.550000005],[406927.799999992,287456.849999994],[406944.399999999,287461.450000001]]]}"; - MapGeometry mg = TestCommonMethods.fromJson(str); - boolean res = op.execute((mg.getGeometry()), (mg.getGeometry()), - null, null); - assertTrue(res); - } - } - - @Test - public void testWithin() { - { - OperatorWithin op = (OperatorWithin) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Within)); - String str1 = "{\"rings\":[[[0,0],[0,200],[200,200],[200,0],[0,0],[0,0],[0,0]]]}"; - MapGeometry mg1 = TestCommonMethods.fromJson(str1); - String str2 = "{\"x\":100,\"y\":100}"; - MapGeometry mg2 = TestCommonMethods.fromJson(str2); - - boolean res = op.execute((mg2.getGeometry()), (mg1.getGeometry()), - null, null); - assertTrue(res); - res = op.execute((mg1.getGeometry()), (mg2.getGeometry()), null, - null); - assertTrue(!res); - - } - - {// polygon - OperatorWithin op = (OperatorWithin) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Within)); - String str1 = "{\"rings\":[[[0,0],[0,200],[200,200],[200,0],[100,0]]]}"; - MapGeometry mg1 = TestCommonMethods.fromJson(str1); - String str2 = "{\"rings\":[[[10,10],[10,100],[100,100],[100,10]]]}"; - MapGeometry mg2 = TestCommonMethods.fromJson(str2); - - boolean res = op.execute((mg2.getGeometry()), (mg1.getGeometry()), - null, null); - assertTrue(res); - res = op.execute((mg1.getGeometry()), (mg2.getGeometry()), null, - null); - assertTrue(!res); - } - - {// Multi_point - OperatorWithin op = (OperatorWithin) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Within)); - String str1 = "{\"points\":[[0,0],[0,200],[200,200]]}"; - MapGeometry mg1 = TestCommonMethods.fromJson(str1); - String str2 = "{\"points\":[[0,0],[0,200]]}"; - MapGeometry mg2 = TestCommonMethods.fromJson(str2); - boolean res = op.execute((mg2.getGeometry()), (mg1.getGeometry()), - null, null); - assertTrue(res); - res = op.execute((mg1.getGeometry()), (mg2.getGeometry()), null, - null); - assertTrue(!res); - } - - {// Multi_point - OperatorWithin op = (OperatorWithin) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Within)); - String str1 = "{\"points\":[[0,0],[0,200]]}"; - MapGeometry mg1 = TestCommonMethods.fromJson(str1); - String str2 = "{\"points\":[[0,0],[0,200]]}"; - MapGeometry mg2 = TestCommonMethods.fromJson(str2); - boolean res = op.execute((mg2.getGeometry()), (mg1.getGeometry()), - null, null); - assertTrue(res); - res = op.execute((mg1.getGeometry()), (mg2.getGeometry()), null, - null); - assertTrue(res); - } - - {// Multi_point - OperatorWithin op = (OperatorWithin) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Within)); - String str1 = "{\"points\":[[0,0],[0,200],[200,200]]}"; - MapGeometry mg1 = TestCommonMethods.fromJson(str1); - String str2 = "{\"points\":[[0,0],[0,200], [1, 1]]}"; - MapGeometry mg2 = TestCommonMethods.fromJson(str2); - boolean res = op.execute((mg2.getGeometry()), (mg1.getGeometry()), - null, null); - assertTrue(!res); - res = op.execute((mg1.getGeometry()), (mg2.getGeometry()), null, - null); - assertTrue(!res); - } - } - - @Test - public void testContains() { - { - OperatorContains op = (OperatorContains) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Contains)); - String str1 = "{\"rings\":[[[0,0],[0,200],[200,200],[200,0],[0,0],[0,0],[0,0]]]}"; - MapGeometry mg1 = TestCommonMethods.fromJson(str1); - String str2 = "{\"x\":100,\"y\":100}"; - MapGeometry mg2 = TestCommonMethods.fromJson(str2); - - boolean res = op.execute((mg2.getGeometry()), (mg1.getGeometry()), - null, null); - assertTrue(!res); - res = op.execute((mg1.getGeometry()), (mg2.getGeometry()), null, - null); - assertTrue(res); - } - - {// polygon - OperatorContains op = (OperatorContains) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Contains)); - String str1 = "{\"rings\":[[[0,0],[0,200],[200,200],[200,0],[0,0]]]}"; - MapGeometry mg1 = TestCommonMethods.fromJson(str1); - String str2 = "{\"rings\":[[[10,10],[10,100],[100,100],[10,10]]]}"; - MapGeometry mg2 = TestCommonMethods.fromJson(str2); - - boolean res = op.execute((mg2.getGeometry()), (mg1.getGeometry()), - null, null); - assertTrue(!res); - res = op.execute((mg1.getGeometry()), (mg2.getGeometry()), null, - null); - assertTrue(res); - } - - {// Multi_point - OperatorContains op = (OperatorContains) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Contains)); - String str1 = "{\"points\":[[0,0],[0,200],[200,200]]}"; - MapGeometry mg1 = TestCommonMethods.fromJson(str1); - String str2 = "{\"points\":[[0,0],[0,200]]}"; - MapGeometry mg2 = TestCommonMethods.fromJson(str2); - boolean res = op.execute((mg2.getGeometry()), (mg1.getGeometry()), - null, null); - assertTrue(!res); - res = op.execute((mg1.getGeometry()), (mg2.getGeometry()), null, - null); - assertTrue(res); - } - - {// Multi_point - OperatorContains op = (OperatorContains) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Contains)); - String str1 = "{\"points\":[[0,0],[0,200]]}"; - MapGeometry mg1 = TestCommonMethods.fromJson(str1); - String str2 = "{\"points\":[[0,0],[0,200]]}"; - MapGeometry mg2 = TestCommonMethods.fromJson(str2); - boolean res = op.execute((mg2.getGeometry()), (mg1.getGeometry()), - null, null); - assertTrue(res); - res = op.execute((mg1.getGeometry()), (mg2.getGeometry()), null, - null); - assertTrue(res); - } - - {// Multi_point - OperatorContains op = (OperatorContains) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Contains)); - String str1 = "{\"points\":[[0,0],[0,200],[200,200]]}"; - MapGeometry mg1 = TestCommonMethods.fromJson(str1); - String str2 = "{\"points\":[[0,0],[0,200], [1, 1]]}"; - MapGeometry mg2 = TestCommonMethods.fromJson(str2); - boolean res = op.execute((mg2.getGeometry()), (mg1.getGeometry()), - null, null); - assertTrue(!res); - res = op.execute((mg1.getGeometry()), (mg2.getGeometry()), null, - null); - assertTrue(!res); - } - } - - @Test - public void testOverlaps() { - {// empty polygon - OperatorOverlaps op = (OperatorOverlaps) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Overlaps)); - Polygon poly1 = new Polygon(); - Polygon poly2 = new Polygon(); - - boolean res = op.execute(poly1, poly2, null, null); - assertTrue(!res); - res = op.execute(poly1, poly2, null, null); - assertTrue(!res); - } - {// polygon - OperatorOverlaps op = (OperatorOverlaps) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Overlaps)); - String str1 = "{\"rings\":[[[0,0],[0,200],[200,200],[200,0],[0,0],[0,0],[0,0]]]}"; - MapGeometry mg1 = TestCommonMethods.fromJson(str1); - String str2 = "{\"x\":100,\"y\":100}"; - MapGeometry mg2 = TestCommonMethods.fromJson(str2); - - boolean res = op.execute((mg2.getGeometry()), (mg1.getGeometry()), - null, null); - assertTrue(!res); - res = op.execute((mg1.getGeometry()), (mg2.getGeometry()), null, - null); - assertTrue(!res); - } - {// polygon - OperatorOverlaps op = (OperatorOverlaps) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Overlaps)); - String str1 = "{\"rings\":[[[0,0],[0,200],[200,200],[200,0],[0,0]]]}"; - MapGeometry mg1 = TestCommonMethods.fromJson(str1); - MapGeometry mg2 = TestCommonMethods.fromJson(str1); - Transformation2D trans = new Transformation2D(); - trans.setShift(300, 0); - mg2.getGeometry().applyTransformation(trans); - boolean res = op.execute((mg2.getGeometry()), (mg1.getGeometry()), - null, null); - assertTrue(!res); - res = op.execute((mg1.getGeometry()), (mg2.getGeometry()), null, - null); - assertTrue(!res); - } - {// polygon - OperatorOverlaps op = (OperatorOverlaps) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Overlaps)); - String str1 = "{\"rings\":[[[0,0],[0,200],[200,200],[200,0],[0,0]]]}"; - MapGeometry mg1 = TestCommonMethods.fromJson(str1); - MapGeometry mg2 = TestCommonMethods.fromJson(str1); - Transformation2D trans = new Transformation2D(); - trans.setShift(30, 0); - mg2.getGeometry().applyTransformation(trans); - boolean res = op.execute((mg2.getGeometry()), (mg1.getGeometry()), - null, null); - assertTrue(res); - res = op.execute((mg1.getGeometry()), (mg2.getGeometry()), null, - null); - assertTrue(res); - } - {// polygon - OperatorOverlaps op = (OperatorOverlaps) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Overlaps)); - String str1 = "{\"rings\":[[[0,0],[0,200],[200,200],[200,0],[0,0]]]}"; - MapGeometry mg1 = TestCommonMethods.fromJson(str1); - MapGeometry mg2 = TestCommonMethods.fromJson(str1); - Transformation2D trans = new Transformation2D(); - trans.setShift(0, 0); - mg2.getGeometry().applyTransformation(trans); - boolean res = op.execute((mg2.getGeometry()), (mg1.getGeometry()), - null, null); - assertTrue(!res); - res = op.execute((mg1.getGeometry()), (mg2.getGeometry()), null, - null); - assertTrue(!res); - } - - {// polyline - OperatorOverlaps op = (OperatorOverlaps) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Overlaps)); - String str1 = "{\"paths\":[[[0,0],[100,0],[200,0]]]}"; - MapGeometry mg1 = TestCommonMethods.fromJson(str1); - MapGeometry mg2 = TestCommonMethods.fromJson(str1); - Transformation2D trans = new Transformation2D(); - trans.setShift(0, 0); - mg2.getGeometry().applyTransformation(trans); - boolean res = op.execute((mg2.getGeometry()), (mg1.getGeometry()), - null, null); - assertTrue(!res); - res = op.execute((mg1.getGeometry()), (mg2.getGeometry()), null, - null); - assertTrue(!res); - } - - {// polyline - OperatorOverlaps op = (OperatorOverlaps) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Overlaps)); - String str1 = "{\"paths\":[[[0,0],[100,0],[200,0]]]}"; - MapGeometry mg1 = TestCommonMethods.fromJson(str1); - MapGeometry mg2 = TestCommonMethods.fromJson(str1); - Transformation2D trans = new Transformation2D(); - trans.setShift(10, 0); - mg2.getGeometry().applyTransformation(trans); - boolean res = op.execute((mg2.getGeometry()), (mg1.getGeometry()), - null, null); - assertTrue(res); - res = op.execute((mg1.getGeometry()), (mg2.getGeometry()), null, - null); - assertTrue(res); - } - - {// polyline - OperatorOverlaps op = (OperatorOverlaps) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Overlaps)); - String str1 = "{\"paths\":[[[0,0],[100,0],[200,0]]]}"; - MapGeometry mg1 = TestCommonMethods.fromJson(str1); - MapGeometry mg2 = TestCommonMethods.fromJson(str1); - Transformation2D trans = new Transformation2D(); - trans.setShift(200, 0); - mg2.getGeometry().applyTransformation(trans); - boolean res = op.execute((mg2.getGeometry()), (mg1.getGeometry()), - null, null); - assertTrue(!res); - res = op.execute((mg1.getGeometry()), (mg2.getGeometry()), null, - null); - assertTrue(!res); - } - - {// Multi_point - OperatorOverlaps op = (OperatorOverlaps) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Overlaps)); - String str1 = "{\"points\":[[0,0],[0,200],[200,200],[200,0]]}"; - MapGeometry mg1 = TestCommonMethods.fromJson(str1); - MapGeometry mg2 = TestCommonMethods.fromJson(str1); - Transformation2D trans = new Transformation2D(); - trans.setShift(0, 0); - mg2.getGeometry().applyTransformation(trans); - boolean res = op.execute((mg2.getGeometry()), (mg1.getGeometry()), - null, null); - assertTrue(!res); - res = op.execute((mg1.getGeometry()), (mg2.getGeometry()), null, - null); - assertTrue(!res); - } - {// Multi_point - OperatorOverlaps op = (OperatorOverlaps) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Overlaps)); - String str1 = "{\"points\":[[0,0],[0,200],[200,200]]}"; - MapGeometry mg1 = TestCommonMethods.fromJson(str1); - String str2 = "{\"points\":[[0,0],[0,200]]}"; - MapGeometry mg2 = TestCommonMethods.fromJson(str2); - boolean res = op.execute((mg2.getGeometry()), (mg1.getGeometry()), - null, null); - assertTrue(!res); - res = op.execute((mg1.getGeometry()), (mg2.getGeometry()), null, - null); - assertTrue(!res); - } - {// Multi_point - OperatorOverlaps op = (OperatorOverlaps) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Overlaps)); - String str1 = "{\"points\":[[0,0],[0,200],[200,200]]}"; - MapGeometry mg1 = TestCommonMethods.fromJson(str1); - String str2 = "{\"points\":[[0,0],[0,200], [0,2]]}"; - MapGeometry mg2 = TestCommonMethods.fromJson(str2); - boolean res = op.execute((mg2.getGeometry()), (mg1.getGeometry()), - null, null); - assertTrue(res); - res = op.execute((mg1.getGeometry()), (mg2.getGeometry()), null, - null); - assertTrue(res); - } - } - - @Test - public void testPolygonPolygonEquals() { - OperatorEquals equals = (OperatorEquals) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Equals)); - SpatialReference sr = SpatialReference.create(102100); - @SuppressWarnings("unused") - double tolerance = sr - .getTolerance(VertexDescription.Semantics.POSITION); - - // Polygon1 and Polygon2 are topologically equal, but have differing - // number of vertices - String str1 = "{\"rings\":[[[0,0],[0,5],[0,7],[0,10],[0,10],[10,10],[10,0],[0,0]],[[1,1],[9,1],[9,9],[1,9],[1,1],[1,1]]]}"; - String str2 = "{\"rings\":[[[0,10],[10,10],[10,0],[0,0],[0,10]],[[9,1],[9,6],[9,9],[1,9],[1,1],[1,1],[9,1]]]}"; - - Polygon polygon1 = (Polygon) TestCommonMethods.fromJson(str1) - .getGeometry(); - Polygon polygon2 = (Polygon) TestCommonMethods.fromJson(str2) - .getGeometry(); - // wiggleGeometry(polygon1, tolerance, 1982); - // wiggleGeometry(polygon2, tolerance, 511); - - equals.accelerateGeometry(polygon1, sr, - Geometry.GeometryAccelerationDegree.enumHot); - equals.accelerateGeometry(polygon2, sr, - Geometry.GeometryAccelerationDegree.enumHot); - - boolean res = equals.execute(polygon1, polygon2, sr, null); - assertTrue(res); - equals.execute(polygon2, polygon1, sr, null); - assertTrue(res); - - // The outer rings of Polygon1 and Polygon2 are equal, but Polygon1 has - // a hole. - str1 = "{\"rings\":[[[0,0],[0,5],[0,10],[10,10],[10,0],[0,0]],[[1,1],[9,1],[9,9],[1,9],[1,1],[1,1]]]}"; - str2 = "{\"rings\":[[[0,10],[10,10],[5,10],[10,10],[10,0],[0,0],[0,10]]]}"; - polygon1 = (Polygon) TestCommonMethods.fromJson(str1).getGeometry(); - polygon2 = (Polygon) TestCommonMethods.fromJson(str2).getGeometry(); - - res = equals.execute(polygon1, polygon2, sr, null); - assertTrue(!res); - res = equals.execute(polygon2, polygon1, sr, null); - assertTrue(!res); - - // The rings are equal but rotated - str1 = "{\"rings\":[[[0,0],[0,10],[10,10],[10,0],[0,0]]]}"; - str2 = "{\"rings\":[[[0,10],[10,10],[10,0],[0,0],[0,10]]]}"; - - polygon1 = (Polygon) TestCommonMethods.fromJson(str1).getGeometry(); - polygon2 = (Polygon) TestCommonMethods.fromJson(str2).getGeometry(); - - res = equals.execute(polygon1, polygon2, sr, null); - assertTrue(res); - res = equals.execute(polygon2, polygon1, sr, null); - assertTrue(res); - - // The rings are equal but opposite orientation - str1 = "{\"rings\":[[[0,0],[0,10],[10,10],[10,0],[0,0]]]}"; - str2 = "{\"rings\":[[[0,0],[10,0],[10,10],[0,10],[0,0]]]}"; - - polygon1 = (Polygon) TestCommonMethods.fromJson(str1).getGeometry(); - polygon2 = (Polygon) TestCommonMethods.fromJson(str2).getGeometry(); - - res = equals.execute(polygon1, polygon2, sr, null); - assertTrue(!res); - res = equals.execute(polygon2, polygon1, sr, null); - assertTrue(!res); - - // The rings are equal but first polygon has two rings stacked - str1 = "{\"rings\":[[[0,0],[0,10],[10,10],[10,0],[0,0]],[[0,10],[10,10],[10,0],[0,0],[0,10]]]}"; - str2 = "{\"rings\":[[[0,10],[10,10],[10,0],[0,0],[0,10]]]}"; - polygon1 = (Polygon) TestCommonMethods.fromJson(str1).getGeometry(); - polygon2 = (Polygon) TestCommonMethods.fromJson(str2).getGeometry(); - - res = equals.execute(polygon1, polygon2, sr, null); - assertTrue(!res); - res = equals.execute(polygon2, polygon1, sr, null); - assertTrue(!res); - } - - @Test - public void testMultiPointMultiPointEquals() { - OperatorEquals equals = (OperatorEquals) OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Equals); - SpatialReference sr = SpatialReference.create(102100); - @SuppressWarnings("unused") - double tolerance = sr - .getTolerance(VertexDescription.Semantics.POSITION); - - MultiPoint multipoint1 = new MultiPoint(); - MultiPoint multipoint2 = new MultiPoint(); - - multipoint1.add(0, 0); - multipoint1.add(1, 1); - multipoint1.add(2, 2); - multipoint1.add(3, 3); - multipoint1.add(4, 4); - multipoint1.add(1, 1); - multipoint1.add(0, 0); - - multipoint2.add(4, 4); - multipoint2.add(3, 3); - multipoint2.add(2, 2); - multipoint2.add(1, 1); - multipoint2.add(0, 0); - multipoint2.add(2, 2); - - wiggleGeometry(multipoint1, 0.001, 123); - wiggleGeometry(multipoint2, 0.001, 5937); - boolean res = equals.execute(multipoint1, multipoint2, sr, null); - assertTrue(res); - res = equals.execute(multipoint2, multipoint1, sr, null); - assertTrue(res); - - multipoint1.add(1, 2); - res = equals.execute(multipoint1, multipoint2, sr, null); - assertTrue(!res); - res = equals.execute(multipoint2, multipoint1, sr, null); - assertTrue(!res); - } - - @Test - public void testMultiPointPointEquals() { - OperatorEquals equals = (OperatorEquals) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Equals)); - OperatorWithin within = (OperatorWithin) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Within)); - SpatialReference sr = SpatialReference.create(102100); - @SuppressWarnings("unused") - double tolerance = sr - .getTolerance(VertexDescription.Semantics.POSITION); - - MultiPoint multipoint1 = new MultiPoint(); - Point point2 = new Point(); - - multipoint1.add(2, 2); - multipoint1.add(2, 2); - - point2.setXY(2, 2); - - wiggleGeometry(multipoint1, 0.001, 123); - boolean res = equals.execute(multipoint1, point2, sr, null); - assertTrue(res); - res = equals.execute(point2, multipoint1, sr, null); - assertTrue(res); - - res = within.execute(multipoint1, point2, sr, null); - assertTrue(res); - res = within.execute(point2, multipoint1, sr, null); - assertTrue(res); - - multipoint1.add(4, 4); - res = equals.execute(multipoint1, point2, sr, null); - assertTrue(!res); - res = equals.execute(point2, multipoint1, sr, null); - assertTrue(!res); - - res = within.execute(multipoint1, point2, sr, null); - assertTrue(!res); - res = within.execute(point2, multipoint1, sr, null); - assertTrue(res); - } - - @Test - public void testPointPointEquals() { - OperatorEquals equals = (OperatorEquals) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Equals)); - OperatorWithin within = (OperatorWithin) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Within)); - OperatorContains contains = (OperatorContains) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Contains)); - OperatorDisjoint disjoint = (OperatorDisjoint) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Disjoint)); - SpatialReference sr = SpatialReference.create(102100); - @SuppressWarnings("unused") - double tolerance = sr - .getTolerance(VertexDescription.Semantics.POSITION); - - Point point1 = new Point(); - Point point2 = new Point(); - - point1.setXY(2, 2); - point2.setXY(2, 2); - - boolean res = equals.execute(point1, point2, sr, null); - assertTrue(res); - res = equals.execute(point2, point1, sr, null); - assertTrue(res); - - res = within.execute(point1, point2, sr, null); - assertTrue(res); - res = within.execute(point2, point1, sr, null); - assertTrue(res); - - res = contains.execute(point1, point2, sr, null); - assertTrue(res); - res = contains.execute(point2, point1, sr, null); - assertTrue(res); - - res = disjoint.execute(point1, point2, sr, null); - assertTrue(!res); - res = disjoint.execute(point2, point1, sr, null); - assertTrue(!res); - - point2.setXY(2, 3); - res = equals.execute(point1, point2, sr, null); - assertTrue(!res); - res = equals.execute(point2, point1, sr, null); - assertTrue(!res); - - res = within.execute(point1, point2, sr, null); - assertTrue(!res); - res = within.execute(point2, point1, sr, null); - assertTrue(!res); - - res = contains.execute(point1, point2, sr, null); - assertTrue(!res); - res = contains.execute(point2, point1, sr, null); - assertTrue(!res); - - res = disjoint.execute(point1, point2, sr, null); - assertTrue(res); - res = disjoint.execute(point2, point1, sr, null); - assertTrue(res); - } - - @Test - public void testPolygonPolygonDisjoint() { - OperatorDisjoint disjoint = (OperatorDisjoint) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Disjoint)); - SpatialReference sr = SpatialReference.create(102100); - double tolerance = sr - .getTolerance(VertexDescription.Semantics.POSITION); - - // Polygon1 and Polygon2 are topologically equal, but have differing - // number of vertices - String str1 = "{\"rings\":[[[0,0],[0,5],[0,10],[10,10],[10,0],[0,0]],[[1,1],[9,1],[9,9],[1,9],[1,1],[1,1]]]}"; - String str2 = "{\"rings\":[[[0,10],[10,10],[10,0],[0,0],[0,10]],[[9,1],[9,6],[9,9],[1,9],[1,1],[1,1],[9,1]]]}"; - - Polygon polygon1 = (Polygon) (TestCommonMethods.fromJson(str1) - .getGeometry()); - Polygon polygon2 = (Polygon) (TestCommonMethods.fromJson(str2) - .getGeometry()); - - boolean res = disjoint.execute(polygon1, polygon2, sr, null); - assertTrue(!res); - res = disjoint.execute(polygon2, polygon1, sr, null); - assertTrue(!res); - - // Polygon1 and Polygon2 touch at a point - str1 = "{\"rings\":[[[0,0],[0,5],[0,10],[10,10],[10,0],[0,0]],[[1,1],[9,1],[9,9],[1,9],[1,1],[1,1]]]}"; - str2 = "{\"rings\":[[[10,10],[10,15],[15,15],[15,10],[10,10]]]}"; - - polygon1 = (Polygon) (TestCommonMethods.fromJson(str1).getGeometry()); - polygon2 = (Polygon) (TestCommonMethods.fromJson(str2).getGeometry()); - wiggleGeometry(polygon1, tolerance, 1982); - wiggleGeometry(polygon2, tolerance, 511); - - res = disjoint.execute(polygon1, polygon2, sr, null); - assertTrue(!res); - res = disjoint.execute(polygon2, polygon1, sr, null); - assertTrue(!res); - - // Polygon1 and Polygon2 touch along the boundary - str1 = "{\"rings\":[[[0,0],[0,5],[0,10],[10,10],[10,0],[0,0]],[[1,1],[9,1],[9,9],[1,9],[1,1],[1,1]]]}"; - str2 = "{\"rings\":[[[10,0],[10,10],[15,10],[15,0],[10,0]]]}"; - - polygon1 = (Polygon) (TestCommonMethods.fromJson(str1).getGeometry()); - polygon2 = (Polygon) (TestCommonMethods.fromJson(str2).getGeometry()); - wiggleGeometry(polygon1, tolerance, 1982); - wiggleGeometry(polygon2, tolerance, 511); - - res = disjoint.execute(polygon1, polygon2, sr, null); - assertTrue(!res); - res = disjoint.execute(polygon2, polygon1, sr, null); - assertTrue(!res); - - // Polygon2 is inside of the hole of polygon1 - str1 = "{\"rings\":[[[0,0],[0,5],[0,10],[10,10],[10,0],[0,0]],[[1,1],[9,1],[9,9],[1,9],[1,1],[1,1]]]}"; - str2 = "{\"rings\":[[[2,2],[2,8],[8,8],[8,2],[2,2]]]}"; - - polygon1 = (Polygon) (TestCommonMethods.fromJson(str1).getGeometry()); - polygon2 = (Polygon) (TestCommonMethods.fromJson(str2).getGeometry()); - - res = disjoint.execute(polygon1, polygon2, sr, null); - assertTrue(res); - res = disjoint.execute(polygon2, polygon1, sr, null); - assertTrue(res); - - // Polygon2 is inside of the hole of polygon1 - str1 = "{\"rings\":[[[0,0],[0,5],[5,5],[5,0]],[[10,0],[10,10],[20,10],[20,0]]]}"; - str2 = "{\"rings\":[[[0,-10],[0,-5],[5,-5],[5,-10]],[[11,1],[11,9],[19,9],[19,1]]]}"; - - polygon1 = (Polygon) (TestCommonMethods.fromJson(str1).getGeometry()); - polygon2 = (Polygon) (TestCommonMethods.fromJson(str2).getGeometry()); - - res = disjoint.execute(polygon1, polygon2, sr, null); - assertTrue(!res); - res = disjoint.execute(polygon2, polygon1, sr, null); - assertTrue(!res); - - polygon1 = (Polygon) OperatorDensifyByLength.local().execute(polygon1, 0.5, null); - disjoint.accelerateGeometry(polygon1, sr, GeometryAccelerationDegree.enumHot); - res = disjoint.execute(polygon1, polygon2, sr, null); - assertTrue(!res); - res = disjoint.execute(polygon2, polygon1, sr, null); - assertTrue(!res); - - polygon1.reverseAllPaths(); - polygon2.reverseAllPaths(); - res = disjoint.execute(polygon1, polygon2, sr, null); - assertTrue(!res); - res = disjoint.execute(polygon2, polygon1, sr, null); - assertTrue(!res); - - // Polygon1 contains polygon2, but polygon2 is counterclockwise. - str1 = "{\"rings\":[[[0,0],[10,0],[10,10],[0,10],[0,0]],[[11,0],[11,10],[21,10],[21,0],[11,0]]]}"; - str2 = "{\"rings\":[[[2,2],[8,2],[8,8],[2,8],[2,2]]]}"; - polygon1 = (Polygon) (TestCommonMethods.fromJson(str1).getGeometry()); - polygon2 = (Polygon) (TestCommonMethods.fromJson(str2).getGeometry()); - - - res = disjoint.execute(polygon1, polygon2, sr, null); - assertTrue(!res); - res = disjoint.execute(polygon2, polygon1, sr, null); - assertTrue(!res); - - polygon1 = (Polygon) OperatorDensifyByLength.local().execute(polygon1, 0.5, null); - disjoint.accelerateGeometry(polygon1, sr, GeometryAccelerationDegree.enumHot); - res = disjoint.execute(polygon1, polygon2, sr, null); - assertTrue(!res); - res = disjoint.execute(polygon2, polygon1, sr, null); - assertTrue(!res); - - str1 = "{\"rings\":[[[0,0],[0,10],[10,10],[10,0],[0,0]],[[0,20],[0,30],[10,30],[10,20],[0,20]],[[20,20],[20,30],[30,30],[30,20],[20,20]],[[20,0],[20,10],[30,10],[30,0],[20,0]]]}"; - str2 = "{\"rings\":[[[14,14],[14,16],[16,16],[16,14],[14,14]]]}"; - polygon1 = (Polygon) (TestCommonMethods.fromJson(str1).getGeometry()); - polygon2 = (Polygon) (TestCommonMethods.fromJson(str2).getGeometry()); - - - res = disjoint.execute(polygon1, polygon2, sr, null); - assertTrue(res); - res = disjoint.execute(polygon2, polygon1, sr, null); - assertTrue(res); - - polygon1 = (Polygon) OperatorDensifyByLength.local().execute(polygon1, 0.5, null); - disjoint.accelerateGeometry(polygon1, sr, GeometryAccelerationDegree.enumHot); - res = disjoint.execute(polygon1, polygon2, sr, null); - assertTrue(res); - res = disjoint.execute(polygon2, polygon1, sr, null); - assertTrue(res); - } - - @Test - public void testPolylinePolylineDisjoint() { - OperatorDisjoint disjoint = (OperatorDisjoint) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Disjoint)); - SpatialReference sr = SpatialReference.create(102100); - double tolerance = sr - .getTolerance(VertexDescription.Semantics.POSITION); - - // Polyline1 and Polyline2 touch at a point - String str1 = "{\"paths\":[[[0,0],[0,5],[0,10],[10,10],[10,0],[0,0]],[[1,1],[9,1],[9,9],[1,9],[1,1],[1,1]]]}"; - String str2 = "{\"paths\":[[[10,10],[10,15],[15,15],[15,10],[10,10]]]}"; - - Polyline polyline1 = (Polyline) (TestCommonMethods.fromJson(str1) - .getGeometry()); - Polyline polyline2 = (Polyline) (TestCommonMethods.fromJson(str2) - .getGeometry()); - wiggleGeometry(polyline1, tolerance, 1982); - wiggleGeometry(polyline2, tolerance, 511); - - boolean res = disjoint.execute(polyline1, polyline2, sr, null); - assertTrue(!res); - res = disjoint.execute(polyline2, polyline1, sr, null); - assertTrue(!res); - - // Polyline1 and Polyline2 touch along the boundary - str1 = "{\"paths\":[[[0,0],[0,5],[0,10],[10,10],[10,0],[0,0]],[[1,1],[9,1],[9,9],[1,9],[1,1],[1,1]]]}"; - str2 = "{\"paths\":[[[10,0],[10,10],[15,10],[15,0],[10,0]]]}"; - - polyline1 = (Polyline) (TestCommonMethods.fromJson(str1).getGeometry()); - polyline2 = (Polyline) (TestCommonMethods.fromJson(str2).getGeometry()); - wiggleGeometry(polyline1, tolerance, 1982); - wiggleGeometry(polyline2, tolerance, 511); - - res = disjoint.execute(polyline1, polyline2, sr, null); - assertTrue(!res); - res = disjoint.execute(polyline2, polyline1, sr, null); - assertTrue(!res); - - // Polyline2 does not intersect with Polyline1 - str1 = "{\"paths\":[[[0,0],[0,5],[0,10],[10,10],[10,0],[0,0]],[[1,1],[9,1],[9,9],[1,9],[1,1],[1,1]]]}"; - str2 = "{\"paths\":[[[2,2],[2,8],[8,8],[8,2],[2,2]]]}"; - - polyline1 = (Polyline) (TestCommonMethods.fromJson(str1).getGeometry()); - polyline2 = (Polyline) (TestCommonMethods.fromJson(str2).getGeometry()); - - res = disjoint.execute(polyline1, polyline2, sr, null); - assertTrue(res); - res = disjoint.execute(polyline2, polyline1, sr, null); - assertTrue(res); - } - - @Test - public void testPolygonPolylineDisjoint() { - OperatorDisjoint disjoint = (OperatorDisjoint) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Disjoint)); - SpatialReference sr = SpatialReference.create(102100); - @SuppressWarnings("unused") - double tolerance = sr - .getTolerance(VertexDescription.Semantics.POSITION); - - Polygon polygon1 = new Polygon(); - Polyline polyline2 = new Polyline(); - - polygon1.startPath(0, 0); - polygon1.lineTo(0, 10); - polygon1.lineTo(10, 10); - polygon1.lineTo(10, 0); - - polygon1.startPath(1, 1); - polygon1.lineTo(9, 1); - polygon1.lineTo(9, 9); - polygon1.lineTo(1, 9); - - polyline2.startPath(3, 3); - polyline2.lineTo(6, 6); - - boolean res = disjoint.execute(polyline2, polygon1, sr, null); - assertTrue(res); - res = disjoint.execute(polygon1, polyline2, sr, null); - assertTrue(res); - - polyline2.startPath(0, 0); - polyline2.lineTo(0, 5); - - res = disjoint.execute(polyline2, polygon1, sr, null); - assertTrue(!res); - res = disjoint.execute(polygon1, polyline2, sr, null); - assertTrue(!res); - - polygon1.setEmpty(); - polyline2.setEmpty(); - - polygon1.startPath(0, 0); - polygon1.lineTo(0, 10); - polygon1.lineTo(10, 10); - polygon1.lineTo(10, 0); - - polyline2.startPath(2, 2); - polyline2.lineTo(4, 4); - - OperatorFactoryLocal factory = OperatorFactoryLocal.getInstance(); - OperatorSimplify simplify_op = (OperatorSimplify) factory - .getOperator(Operator.Type.Simplify); - simplify_op.isSimpleAsFeature(polygon1, sr, null); - simplify_op.isSimpleAsFeature(polyline2, sr, null); - - res = disjoint.execute(polyline2, polygon1, sr, null); - assertTrue(!res); - res = disjoint.execute(polygon1, polyline2, sr, null); - assertTrue(!res); - } - - @Test - public void testPolylineMultiPointDisjoint() { - OperatorDisjoint disjoint = (OperatorDisjoint) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Disjoint)); - SpatialReference sr = SpatialReference.create(102100); - @SuppressWarnings("unused") - double tolerance = sr - .getTolerance(VertexDescription.Semantics.POSITION); - - Polyline polyline1 = new Polyline(); - MultiPoint multipoint2 = new MultiPoint(); - - polyline1.startPath(0, 0); - polyline1.lineTo(2, 0); - polyline1.lineTo(4, 2); - - multipoint2.add(1, 1); - multipoint2.add(2, 2); - multipoint2.add(3, 0); - - boolean res = disjoint.execute(polyline1, multipoint2, sr, null); - assertTrue(res); - res = disjoint.execute(multipoint2, polyline1, sr, null); - assertTrue(res); - - multipoint2.add(3, 1); - res = disjoint.execute(polyline1, multipoint2, sr, null); - assertTrue(!res); - res = disjoint.execute(multipoint2, polyline1, sr, null); - assertTrue(!res); - - polyline1.startPath(1, -4); - polyline1.lineTo(1, -3); - polyline1.lineTo(1, -2); - polyline1.lineTo(1, -1); - polyline1.lineTo(1, 0); - polyline1.lineTo(1, 1); - - disjoint.accelerateGeometry(polyline1, sr, - Geometry.GeometryAccelerationDegree.enumHot); - res = disjoint.execute(polyline1, multipoint2, sr, null); - assertTrue(!res); - res = disjoint.execute(multipoint2, polyline1, sr, null); - assertTrue(!res); - } - - @Test - public void testPolylinePointDisjoint() { - OperatorDisjoint disjoint = (OperatorDisjoint) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Disjoint)); - OperatorContains contains = (OperatorContains) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Contains)); - SpatialReference sr = SpatialReference.create(102100); - @SuppressWarnings("unused") - double tolerance = sr - .getTolerance(VertexDescription.Semantics.POSITION); - - Polyline polyline1 = new Polyline(); - Point point2 = new Point(); - - polyline1.startPath(0, 0); - polyline1.lineTo(2, 0); - polyline1.lineTo(4, 2); - - point2.setXY(1, 1); - - boolean res = disjoint.execute(polyline1, point2, sr, null); - assertTrue(res); - res = disjoint.execute(point2, polyline1, sr, null); - assertTrue(res); - - res = contains.execute(polyline1, point2, sr, null); - assertTrue(!res); - res = contains.execute(point2, polyline1, sr, null); - assertTrue(!res); - - point2.setXY(4, 2); - - polyline1 = (Polyline) OperatorDensifyByLength.local().execute( - polyline1, 0.1, null); - disjoint.accelerateGeometry(polyline1, sr, - Geometry.GeometryAccelerationDegree.enumHot); - - res = disjoint.execute(polyline1, point2, sr, null); - assertTrue(!res); - res = disjoint.execute(point2, polyline1, sr, null); - assertTrue(!res); - - res = contains.execute(polyline1, point2, sr, null); - assertTrue(!res); - res = contains.execute(point2, polyline1, sr, null); - assertTrue(!res); - - polyline1.setEmpty(); - point2.setEmpty(); - - polyline1.startPath(659062.37370000035, 153070.85220000148); - polyline1.lineTo(660916.47940000147, 151481.10269999877); - point2.setXY(659927.85020000115, 152328.77430000156); - - res = contains.execute(polyline1, point2, - SpatialReference.create(54004), null); - assertTrue(res); - } - - @Test - public void testMultiPointMultiPointDisjoint() { - OperatorDisjoint disjoint = (OperatorDisjoint) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Disjoint)); - SpatialReference sr = SpatialReference.create(102100); - @SuppressWarnings("unused") - double tolerance = sr - .getTolerance(VertexDescription.Semantics.POSITION); - - MultiPoint multipoint1 = new MultiPoint(); - MultiPoint multipoint2 = new MultiPoint(); - - multipoint1.add(2, 2); - multipoint1.add(2, 5); - multipoint1.add(4, 1); - multipoint1.add(4, 4); - multipoint1.add(4, 7); - multipoint1.add(6, 2); - multipoint1.add(6, 6); - multipoint1.add(4, 1); - multipoint1.add(6, 6); - - multipoint2.add(0, 1); - multipoint2.add(0, 7); - multipoint2.add(4, 2); - multipoint2.add(4, 6); - multipoint2.add(6, 4); - multipoint2.add(4, 2); - multipoint2.add(0, 1); - - boolean res = disjoint.execute(multipoint1, multipoint2, sr, null); - assertTrue(res); - res = disjoint.execute(multipoint2, multipoint1, sr, null); - assertTrue(res); - - multipoint2.add(2, 2); - res = disjoint.execute(multipoint1, multipoint2, sr, null); - assertTrue(!res); - res = disjoint.execute(multipoint2, multipoint1, sr, null); - assertTrue(!res); - } - - @Test - public void testMultiPointPointDisjoint() { - OperatorDisjoint disjoint = (OperatorDisjoint) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Disjoint)); - OperatorContains contains = (OperatorContains) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Contains)); - SpatialReference sr = SpatialReference.create(102100); - @SuppressWarnings("unused") - double tolerance = sr - .getTolerance(VertexDescription.Semantics.POSITION); - - MultiPoint multipoint1 = new MultiPoint(); - Point point2 = new Point(); - - multipoint1.add(2, 2); - multipoint1.add(2, 5); - multipoint1.add(4, 1); - multipoint1.add(4, 4); - multipoint1.add(4, 7); - multipoint1.add(6, 2); - multipoint1.add(6, 6); - multipoint1.add(4, 1); - multipoint1.add(6, 6); - - point2.setXY(2, 6); - - boolean res = disjoint.execute(multipoint1, point2, sr, null); - assertTrue(res); - res = disjoint.execute(point2, multipoint1, sr, null); - assertTrue(res); - - res = contains.execute(multipoint1, point2, sr, null); - assertTrue(!res); - res = contains.execute(point2, multipoint1, sr, null); - assertTrue(!res); - - multipoint1.add(2, 6); - res = disjoint.execute(multipoint1, point2, sr, null); - assertTrue(!res); - res = disjoint.execute(point2, multipoint1, sr, null); - assertTrue(!res); - - res = contains.execute(multipoint1, point2, sr, null); - assertTrue(res); - res = contains.execute(point2, multipoint1, sr, null); - assertTrue(!res); - } - - @Test - public void testPolygonMultiPointDisjoint() { - OperatorDisjoint disjoint = (OperatorDisjoint) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Disjoint)); - SpatialReference sr = SpatialReference.create(102100); - @SuppressWarnings("unused") - double tolerance = sr - .getTolerance(VertexDescription.Semantics.POSITION); - - Polygon polygon1 = new Polygon(); - MultiPoint multipoint2 = new MultiPoint(); - - polygon1.startPath(0, 0); - polygon1.lineTo(0, 10); - polygon1.lineTo(10, 10); - - multipoint2.add(-1, 5); - multipoint2.add(5, 11); - multipoint2.add(11, 5); - multipoint2.add(5, -1); - - boolean res = disjoint.execute(polygon1, multipoint2, sr, null); - assertTrue(res); - res = disjoint.execute(multipoint2, polygon1, sr, null); - assertTrue(res); - - polygon1.startPath(15, 0); - polygon1.lineTo(15, 10); - polygon1.lineTo(25, 10); - polygon1.lineTo(25, 0); - - multipoint2.add(14, 5); - multipoint2.add(20, 11); - multipoint2.add(26, 5); - multipoint2.add(20, -1); - - res = disjoint.execute(polygon1, multipoint2, sr, null); - assertTrue(res); - res = disjoint.execute(multipoint2, polygon1, sr, null); - assertTrue(res); - - multipoint2.add(20, 5); - - res = disjoint.execute(polygon1, multipoint2, sr, null); - assertTrue(!res); - res = disjoint.execute(multipoint2, polygon1, sr, null); - assertTrue(!res); - } - - @Test - public void testPolygonMultiPointTouches() { - OperatorTouches touches = (OperatorTouches) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Touches)); - SpatialReference sr = SpatialReference.create(102100); - @SuppressWarnings("unused") - double tolerance = sr - .getTolerance(VertexDescription.Semantics.POSITION); - - Polygon polygon1 = new Polygon(); - MultiPoint multipoint2 = new MultiPoint(); - - polygon1.startPath(0, 0); - polygon1.lineTo(0, 10); - polygon1.lineTo(10, 10); - polygon1.lineTo(10, 0); - - multipoint2.add(-1, 5); - multipoint2.add(5, 11); - multipoint2.add(11, 5); - multipoint2.add(5, -1); - - boolean res = touches.execute(polygon1, multipoint2, sr, null); - assertTrue(!res); - res = touches.execute(multipoint2, polygon1, sr, null); - assertTrue(!res); - - multipoint2.add(5, 10); - - res = touches.execute(polygon1, multipoint2, sr, null); - assertTrue(res); - res = touches.execute(multipoint2, polygon1, sr, null); - assertTrue(res); - - multipoint2.add(5, 5); - res = touches.execute(polygon1, multipoint2, sr, null); - assertTrue(!res); - res = touches.execute(multipoint2, polygon1, sr, null); - assertTrue(!res); - } - - @Test - public void testPolygonPointTouches() { - OperatorTouches touches = (OperatorTouches) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Touches)); - SpatialReference sr = SpatialReference.create(102100); - @SuppressWarnings("unused") - double tolerance = sr - .getTolerance(VertexDescription.Semantics.POSITION); - - Polygon polygon1 = new Polygon(); - Point point2 = new Point(); - - polygon1.startPath(0, 0); - polygon1.lineTo(0, 10); - polygon1.lineTo(10, 10); - polygon1.lineTo(10, 0); - - point2.setXY(5, 5); - - boolean res = touches.execute(polygon1, point2, sr, null); - assertTrue(!res); - res = touches.execute(point2, polygon1, sr, null); - assertTrue(!res); - - point2.setXY(5, 10); - - res = touches.execute(polygon1, point2, sr, null); - assertTrue(res); - res = touches.execute(point2, polygon1, sr, null); - assertTrue(res); - } - - @Test - public void testPolygonPolygonTouches() { - OperatorTouches touches = (OperatorTouches) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Touches)); - SpatialReference sr = SpatialReference.create(102100); - double tolerance = sr - .getTolerance(VertexDescription.Semantics.POSITION); - - // Polygon1 and Polygon2 touch at a point - String str1 = "{\"rings\":[[[0,0],[0,5],[0,10],[10,10],[10,0],[0,0]],[[1,1],[9,1],[9,9],[1,9],[1,1],[1,1]]]}"; - String str2 = "{\"rings\":[[[10,10],[10,15],[15,15],[15,10],[10,10]]]}"; - - Polygon polygon1 = (Polygon) (TestCommonMethods.fromJson(str1) - .getGeometry()); - Polygon polygon2 = (Polygon) (TestCommonMethods.fromJson(str2) - .getGeometry()); - wiggleGeometry(polygon1, tolerance, 1982); - wiggleGeometry(polygon2, tolerance, 511); - - boolean res = touches.execute(polygon1, polygon2, sr, null); - assertTrue(res); - res = touches.execute(polygon2, polygon1, sr, null); - assertTrue(res); - - // Polygon1 and Polygon2 touch along the boundary - str1 = "{\"rings\":[[[0,0],[0,5],[0,10],[10,10],[10,0],[0,0]],[[1,1],[9,1],[9,9],[1,9],[1,1],[1,1]]]}"; - str2 = "{\"rings\":[[[10,0],[10,10],[15,10],[15,0],[10,0]]]}"; - - polygon1 = (Polygon) (TestCommonMethods.fromJson(str1).getGeometry()); - polygon2 = (Polygon) (TestCommonMethods.fromJson(str2).getGeometry()); - wiggleGeometry(polygon1, tolerance, 1982); - wiggleGeometry(polygon2, tolerance, 511); - - res = touches.execute(polygon1, polygon2, sr, null); - assertTrue(res); - res = touches.execute(polygon2, polygon1, sr, null); - assertTrue(res); - - // Polygon1 and Polygon2 touch at a corner of Polygon1 and a diagonal of - // Polygon2 - str1 = "{\"rings\":[[[0,0],[0,5],[0,10],[10,10],[10,0],[0,0]],[[1,1],[9,1],[9,9],[1,9],[1,1],[1,1]]]}"; - str2 = "{\"rings\":[[[15,5],[5,15],[15,15],[15,5]]]}"; - - polygon1 = (Polygon) (TestCommonMethods.fromJson(str1).getGeometry()); - polygon2 = (Polygon) (TestCommonMethods.fromJson(str2).getGeometry()); - wiggleGeometry(polygon1, tolerance, 1982); - wiggleGeometry(polygon2, tolerance, 511); - - res = touches.execute(polygon1, polygon2, sr, null); - assertTrue(res); - res = touches.execute(polygon2, polygon1, sr, null); - assertTrue(res); - - // Polygon1 and Polygon2 do not touch - str1 = "{\"rings\":[[[0,0],[0,5],[0,10],[10,10],[10,0],[0,0]],[[1,1],[9,1],[9,9],[1,9],[1,1],[1,1]]]}"; - str2 = "{\"rings\":[[[5,5],[5,15],[15,15],[15,5],[5,5]]]}"; - - polygon1 = (Polygon) (TestCommonMethods.fromJson(str1).getGeometry()); - polygon2 = (Polygon) (TestCommonMethods.fromJson(str2).getGeometry()); - - res = touches.execute(polygon1, polygon2, sr, null); - assertTrue(!res); - res = touches.execute(polygon2, polygon1, sr, null); - assertTrue(!res); - - polygon1.setEmpty(); - polygon2.setEmpty(); - - polygon1.startPath(0, 0); - polygon1.lineTo(0, 1); - polygon1.lineTo(-1, 0); - - polygon2.startPath(0, 0); - polygon2.lineTo(0, 1); - polygon2.lineTo(1, 0); - - res = touches.execute(polygon1, polygon2, sr, null); - assertTrue(res); - res = touches.execute(polygon2, polygon1, sr, null); - assertTrue(res); - } - - @Test - public void testPolygonPolylineTouches() { - OperatorTouches touches = (OperatorTouches) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Touches)); - SpatialReference sr = SpatialReference.create(102100); - double tolerance = sr - .getTolerance(VertexDescription.Semantics.POSITION); - - // Polygon1 and Polyline2 touch at a point - String str1 = "{\"rings\":[[[0,0],[0,5],[0,10],[10,10],[10,0]],[[1,1],[9,1],[9,9],[1,9],[1,1],[1,1]]]}"; - String str2 = "{\"paths\":[[[10,10],[10,15],[15,15],[15,10]]]}"; - - Polygon polygon1 = (Polygon) (TestCommonMethods.fromJson(str1) - .getGeometry()); - Polyline polyline2 = (Polyline) (TestCommonMethods.fromJson(str2) - .getGeometry()); - wiggleGeometry(polygon1, tolerance, 1982); - wiggleGeometry(polyline2, tolerance, 511); - - boolean res = touches.execute(polygon1, polyline2, sr, null); - assertTrue(res); - res = touches.execute(polyline2, polygon1, sr, null); - assertTrue(res); - - // Polygon1 and Polyline2 overlap along the boundary - str1 = "{\"rings\":[[[0,0],[0,5],[0,10],[10,10],[10,0],[0,0]],[[1,1],[9,1],[9,9],[1,9],[1,1],[1,1]]]}"; - str2 = "{\"paths\":[[[10,0],[10,10],[15,10],[15,0]]]}"; - - polygon1 = (Polygon) (TestCommonMethods.fromJson(str1).getGeometry()); - polyline2 = (Polyline) (TestCommonMethods.fromJson(str2).getGeometry()); - wiggleGeometry(polygon1, tolerance, 1982); - wiggleGeometry(polyline2, tolerance, 511); - - res = touches.execute(polygon1, polyline2, sr, null); - assertTrue(res); - res = touches.execute(polyline2, polygon1, sr, null); - assertTrue(res); - - str1 = "{\"rings\":[[[0,0],[0,5],[0,10],[10,10],[10,0],[0,0]],[[1,1],[9,1],[9,9],[1,9],[1,1],[1,1]]]}"; - str2 = "{\"paths\":[[[15,5],[5,15],[15,15],[15,5]]]}"; - - polygon1 = (Polygon) (TestCommonMethods.fromJson(str1).getGeometry()); - polyline2 = (Polyline) (TestCommonMethods.fromJson(str2).getGeometry()); - wiggleGeometry(polygon1, tolerance, 1982); - wiggleGeometry(polyline2, tolerance, 511); - - res = touches.execute(polygon1, polyline2, sr, null); - assertTrue(res); - res = touches.execute(polyline2, polygon1, sr, null); - assertTrue(res); - - str1 = "{\"rings\":[[[10,10],[10,0],[0,0],[0,10],[10,10]],[[1,1],[9,1],[9,9],[1,9],[1,1],[1,1]]]}"; - str2 = "{\"paths\":[[[15,5],[5,15],[15,15]]]}"; - - polygon1 = (Polygon) (TestCommonMethods.fromJson(str1).getGeometry()); - polyline2 = (Polyline) (TestCommonMethods.fromJson(str2).getGeometry()); - wiggleGeometry(polygon1, tolerance, 1982); - wiggleGeometry(polyline2, tolerance, 511); - - res = touches.execute(polygon1, polyline2, sr, null); - assertTrue(res); - res = touches.execute(polyline2, polygon1, sr, null); - assertTrue(res); - } - - @Test - public void testPolylinePolylineTouches() { - OperatorTouches touches = (OperatorTouches) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Touches)); - SpatialReference sr = SpatialReference.create(102100); - double tolerance = sr - .getTolerance(VertexDescription.Semantics.POSITION); - - // Polyline1 and Polyline2 touch at a point - String str1 = "{\"paths\":[[[0,0],[0,5],[0,10],[10,10],[10,0]],[[1,1],[9,1],[9,9],[1,9],[1,1],[1,1]]]}"; - String str2 = "{\"paths\":[[[10,10],[10,15],[15,15],[15,10]]]}"; - - Polyline polyline1 = (Polyline) (TestCommonMethods.fromJson(str1) - .getGeometry()); - Polyline polyline2 = (Polyline) (TestCommonMethods.fromJson(str2) - .getGeometry()); - - boolean res = touches.execute(polyline1, polyline2, sr, null); - assertTrue(res); - res = touches.execute(polyline2, polyline1, sr, null); - assertTrue(res); - - // Polyline1 and Polyline2 overlap along the boundary - str1 = "{\"paths\":[[[0,0],[0,5],[0,10],[10,10],[10,0],[0,0]],[[1,1],[9,1],[9,9],[1,9],[1,1],[1,1]]]}"; - str2 = "{\"paths\":[[[10,0],[10,10],[15,10],[15,0],[10,0]]]}"; - - polyline1 = (Polyline) (TestCommonMethods.fromJson(str1).getGeometry()); - polyline2 = (Polyline) (TestCommonMethods.fromJson(str2).getGeometry()); - - res = touches.execute(polyline1, polyline2, sr, null); - assertTrue(!res); - res = touches.execute(polyline2, polyline1, sr, null); - assertTrue(!res); - - // Polyline1 and Polyline2 intersect at interiors - str1 = "{\"paths\":[[[0,0],[0,5],[0,10],[10,10],[10,0],[0,0]],[[1,1],[9,1],[9,9],[1,9],[1,1],[1,1]]]}"; - str2 = "{\"paths\":[[[15,5],[5,15],[15,15],[15,5]]]}"; - - polyline1 = (Polyline) (TestCommonMethods.fromJson(str1).getGeometry()); - polyline2 = (Polyline) (TestCommonMethods.fromJson(str2).getGeometry()); - - res = touches.execute(polyline1, polyline2, sr, null); - assertTrue(!res); - res = touches.execute(polyline2, polyline1, sr, null); - assertTrue(!res); - - // Polyline1 and Polyline2 touch at an endpoint of Polyline1 and - // interior of Polyline2 (but Polyline1 is closed) - str1 = "{\"paths\":[[[10,10],[10,0],[0,0],[0,10],[10,10]],[[1,1],[9,1],[9,9],[1,9],[1,1],[1,1]]]}"; - str2 = "{\"paths\":[[[15,5],[5,15],[15,15]]]}"; - - polyline1 = (Polyline) (TestCommonMethods.fromJson(str1).getGeometry()); - polyline2 = (Polyline) (TestCommonMethods.fromJson(str2).getGeometry()); - - res = touches.execute(polyline1, polyline2, sr, null); - assertTrue(!res); - res = touches.execute(polyline2, polyline1, sr, null); - assertTrue(!res); - - // Polyline1 and Polyline2 touch at an endpoint of Polyline1 and - // interior of Polyline2 (same as previous case, but Polyline1 is not - // closed) - str1 = "{\"paths\":[[[10,10],[10,0],[0,0],[0,10]],[[1,1],[9,1],[9,9],[1,9],[1,1],[1,1]]]}"; - str2 = "{\"paths\":[[[15,5],[5,15],[15,15]]]}"; - - polyline1 = (Polyline) (TestCommonMethods.fromJson(str1).getGeometry()); - polyline2 = (Polyline) (TestCommonMethods.fromJson(str2).getGeometry()); - - res = touches.execute(polyline1, polyline2, sr, null); - assertTrue(res); - res = touches.execute(polyline2, polyline1, sr, null); - assertTrue(res); - - str1 = "{\"paths\":[[[10,10],[10,0],[0,0],[0,10]],[[1,1],[9,1],[9,9],[1,9],[6, 9]]]}"; - str2 = "{\"paths\":[[[15,5],[5,15],[15,15],[15,5]]]}"; - - polyline1 = (Polyline) (TestCommonMethods.fromJson(str1).getGeometry()); - polyline2 = (Polyline) (TestCommonMethods.fromJson(str2).getGeometry()); - - res = touches.execute(polyline1, polyline2, sr, null); - assertTrue(res); - res = touches.execute(polyline2, polyline1, sr, null); - assertTrue(res); - - polyline1.setEmpty(); - polyline2.setEmpty(); - - polyline1.startPath(-2, -2); - polyline1.lineTo(-1, -1); - polyline1.lineTo(1, 1); - polyline1.lineTo(2, 2); - - polyline2.startPath(-2, 2); - polyline2.lineTo(-1, 1); - polyline2.lineTo(1, -1); - polyline2.lineTo(2, -2); - - res = touches.execute(polyline2, polyline1, sr, null); - assertTrue(!res); - - polyline1.setEmpty(); - polyline2.setEmpty(); - - polyline1.startPath(-2, -2); - polyline1.lineTo(-1, -1); - polyline1.lineTo(1, 1); - polyline1.lineTo(2, 2); - - polyline2.startPath(-2, 2); - polyline2.lineTo(-1, 1); - polyline2.lineTo(1, -1); - - res = touches.execute(polyline1, polyline2, sr, null); - assertTrue(!res); - - polyline1.setEmpty(); - polyline2.setEmpty(); - - polyline1.startPath(-1, -1); - polyline1.lineTo(0, 0); - polyline1.lineTo(1, 1); - - polyline2.startPath(-1, 1); - polyline2.lineTo(0, 0); - polyline2.lineTo(1, -1); - - res = touches.execute(polyline2, polyline1, sr, null); - assertTrue(!res); - - polyline1.setEmpty(); - polyline2.setEmpty(); - polyline1.startPath(0, 0); - polyline1.lineTo(0, 1); - polyline1.lineTo(0, 0); - polyline2.startPath(0, 1); - polyline2.lineTo(0, 2); - polyline2.lineTo(0, 1); - - res = touches.execute(polyline2, polyline1, sr, null); - assertTrue(!res); - - res = touches.execute(polyline1, polyline2, sr, null); - assertTrue(!res); - } - - @Test - public void testPolylineMultiPointTouches() { - OperatorTouches touches = (OperatorTouches) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Touches)); - SpatialReference sr = SpatialReference.create(102100); - @SuppressWarnings("unused") - double tolerance = sr - .getTolerance(VertexDescription.Semantics.POSITION); - - Polyline polyline1 = new Polyline(); - MultiPoint multipoint2 = new MultiPoint(); - - polyline1.startPath(0, 0); - polyline1.lineTo(2, 0); - polyline1.lineTo(4, 2); - - multipoint2.add(1, 1); - multipoint2.add(2, 2); - multipoint2.add(3, 0); - - boolean res = touches.execute(polyline1, multipoint2, sr, null); - assertTrue(!res); - res = touches.execute(multipoint2, polyline1, sr, null); - assertTrue(!res); - - polyline1.startPath(1, -4); - polyline1.lineTo(1, -3); - polyline1.lineTo(1, -2); - polyline1.lineTo(1, -1); - polyline1.lineTo(1, 0); - polyline1.lineTo(1, 1); - - touches.accelerateGeometry(polyline1, sr, - Geometry.GeometryAccelerationDegree.enumHot); - res = touches.execute(polyline1, multipoint2, sr, null); - assertTrue(res); - res = touches.execute(multipoint2, polyline1, sr, null); - assertTrue(res); - - multipoint2.add(3, 1); - res = touches.execute(polyline1, multipoint2, sr, null); - assertTrue(!res); - res = touches.execute(multipoint2, polyline1, sr, null); - assertTrue(!res); - - polyline1.startPath(0, 0); - polyline1.lineTo(2, 0); - - polyline1.startPath(2, 1); - polyline1.lineTo(2, -1); - - multipoint2.add(2, 0); - - res = touches.execute(polyline1, multipoint2, sr, null); - assertTrue(!res); - res = touches.execute(multipoint2, polyline1, sr, null); - assertTrue(!res); - } - - @Test - public void testPolylineMultiPointCrosses() { - OperatorCrosses crosses = (OperatorCrosses) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Crosses)); - SpatialReference sr = SpatialReference.create(102100); - double tolerance = sr - .getTolerance(VertexDescription.Semantics.POSITION); - - Polyline polyline1 = new Polyline(); - MultiPoint multipoint2 = new MultiPoint(); - - polyline1.startPath(0, 0); - polyline1.lineTo(2, 0); - polyline1.lineTo(4, 2); - - multipoint2.add(1, 1); - multipoint2.add(2, 2); - multipoint2.add(3, 0); - multipoint2.add(0, 0); - - boolean res = crosses.execute(polyline1, multipoint2, sr, null); - assertTrue(!res); - res = crosses.execute(multipoint2, polyline1, sr, null); - assertTrue(!res); - - polyline1.startPath(1, -4); - polyline1.lineTo(1, -3); - polyline1.lineTo(1, -2); - polyline1.lineTo(1, -1); - polyline1.lineTo(1, 0); - polyline1.lineTo(1, 1); - - res = crosses.execute(polyline1, multipoint2, sr, null); - assertTrue(!res); - res = crosses.execute(multipoint2, polyline1, sr, null); - assertTrue(!res); - - crosses.accelerateGeometry(polyline1, sr, - Geometry.GeometryAccelerationDegree.enumHot); - - multipoint2.add(1, 0); - res = crosses.execute(polyline1, multipoint2, sr, null); - assertTrue(res); - res = crosses.execute(multipoint2, polyline1, sr, null); - assertTrue(res); - - multipoint2.add(3, 1); - res = crosses.execute(polyline1, multipoint2, sr, null); - assertTrue(res); - res = crosses.execute(multipoint2, polyline1, sr, null); - assertTrue(res); - } - - @Test - public void testPolylinePointTouches() { - OperatorTouches touches = (OperatorTouches) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Touches)); - SpatialReference sr = SpatialReference.create(102100); - @SuppressWarnings("unused") - double tolerance = sr - .getTolerance(VertexDescription.Semantics.POSITION); - - Polyline polyline1 = new Polyline(); - Point point2 = new Point(); - - polyline1.startPath(0, 0); - polyline1.lineTo(2, 0); - - polyline1.startPath(2, 1); - polyline1.lineTo(2, -1); - - point2.setXY(2, 0); - - boolean res = touches.execute(polyline1, point2, sr, null); - assertTrue(res); - res = touches.execute(point2, polyline1, sr, null); - assertTrue(res); - } - - @Test - public void testPolygonPolygonOverlaps() { - OperatorOverlaps overlaps = (OperatorOverlaps) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Overlaps)); - SpatialReference sr = SpatialReference.create(102100); - double tolerance = sr - .getTolerance(VertexDescription.Semantics.POSITION); - - // Polygon1 and Polygon2 touch at a point - String str1 = "{\"rings\":[[[0,0],[0,5],[0,10],[10,10],[10,0],[0,0]],[[1,1],[9,1],[9,9],[1,9],[1,1],[1,1]]]}"; - String str2 = "{\"rings\":[[[10,10],[10,15],[15,15],[15,10],[10,10]]]}"; - - Polygon polygon1 = (Polygon) (TestCommonMethods.fromJson(str1) - .getGeometry()); - Polygon polygon2 = (Polygon) (TestCommonMethods.fromJson(str2) - .getGeometry()); - wiggleGeometry(polygon1, tolerance, 1982); - wiggleGeometry(polygon2, tolerance, 511); - - boolean res = overlaps.execute(polygon1, polygon2, sr, null); - assertTrue(!res); - res = overlaps.execute(polygon2, polygon1, sr, null); - assertTrue(!res); - - // Polygon1 and Polygon2 touch along the boundary - str1 = "{\"rings\":[[[0,0],[0,5],[0,10],[10,10],[10,0],[0,0]],[[1,1],[9,1],[9,9],[1,9],[1,1],[1,1]]]}"; - str2 = "{\"rings\":[[[10,0],[10,10],[15,10],[15,0],[10,0]]]}"; - - polygon1 = (Polygon) (TestCommonMethods.fromJson(str1).getGeometry()); - polygon2 = (Polygon) (TestCommonMethods.fromJson(str2).getGeometry()); - wiggleGeometry(polygon1, tolerance, 1982); - wiggleGeometry(polygon2, tolerance, 511); - - res = overlaps.execute(polygon1, polygon2, sr, null); - assertTrue(!res); - res = overlaps.execute(polygon2, polygon1, sr, null); - assertTrue(!res); - - // Polygon1 and Polygon2 touch at a corner of Polygon1 and a diagonal of - // Polygon2 - str1 = "{\"rings\":[[[0,0],[0,5],[0,10],[10,10],[10,0],[0,0]],[[1,1],[9,1],[9,9],[1,9],[1,1],[1,1]]]}"; - str2 = "{\"rings\":[[[15,5],[5,15],[15,15],[15,5]]]}"; - - polygon1 = (Polygon) (TestCommonMethods.fromJson(str1).getGeometry()); - polygon2 = (Polygon) (TestCommonMethods.fromJson(str2).getGeometry()); - wiggleGeometry(polygon1, tolerance, 1982); - wiggleGeometry(polygon2, tolerance, 511); - - res = overlaps.execute(polygon1, polygon2, sr, null); - assertTrue(!res); - res = overlaps.execute(polygon2, polygon1, sr, null); - assertTrue(!res); - - // Polygon1 and Polygon2 overlap at the upper right corner - str1 = "{\"rings\":[[[0,0],[0,5],[0,10],[10,10],[10,0],[0,0]],[[1,1],[9,1],[9,9],[1,9],[1,1],[1,1]]]}"; - str2 = "{\"rings\":[[[5,5],[5,15],[15,15],[15,5],[5,5]]]}"; - - polygon1 = (Polygon) (TestCommonMethods.fromJson(str1).getGeometry()); - polygon2 = (Polygon) (TestCommonMethods.fromJson(str2).getGeometry()); - - res = overlaps.execute(polygon1, polygon2, sr, null); - assertTrue(res); - res = overlaps.execute(polygon2, polygon1, sr, null); - assertTrue(res); - - str1 = "{\"rings\":[[[0,0],[0,5],[0,10],[10,10],[10,0],[0,0]],[[4,4],[6,4],[6,6],[4,6],[4,4],[4,4]]]}"; - str2 = "{\"rings\":[[[1,1],[1,9],[9,9],[9,1],[1,1]]]}"; - - polygon1 = (Polygon) (TestCommonMethods.fromJson(str1).getGeometry()); - polygon2 = (Polygon) (TestCommonMethods.fromJson(str2).getGeometry()); - - res = overlaps.execute(polygon1, polygon2, sr, null); - assertTrue(res); - res = overlaps.execute(polygon2, polygon1, sr, null); - assertTrue(res); - } - - @Test - public void testPolygonPolylineWithin() { - OperatorWithin within = (OperatorWithin) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Within)); - SpatialReference sr = SpatialReference.create(102100); - @SuppressWarnings("unused") - double tolerance = sr - .getTolerance(VertexDescription.Semantics.POSITION); - - Polygon polygon1 = new Polygon(); - Polyline polyline2 = new Polyline(); - - polygon1.startPath(0, 0); - polygon1.lineTo(0, 10); - polygon1.lineTo(10, 10); - polygon1.lineTo(10, 0); - - polyline2.startPath(5, 0); - polyline2.lineTo(5, 10); - - boolean res = within.execute(polygon1, polyline2, sr, null); - assertTrue(!res); - res = within.execute(polyline2, polygon1, sr, null); - assertTrue(res); - - polyline2.setEmpty(); - polyline2.startPath(0, 1); - polyline2.lineTo(0, 9); - - res = within.execute(polyline2, polygon1, sr, null); - assertTrue(!res); - } - - @Test - public void testMultiPointMultiPointWithin() { - OperatorWithin within = (OperatorWithin) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Within)); - SpatialReference sr = SpatialReference.create(102100); - @SuppressWarnings("unused") - double tolerance = sr - .getTolerance(VertexDescription.Semantics.POSITION); - - MultiPoint multipoint1 = new MultiPoint(); - MultiPoint multipoint2 = new MultiPoint(); - - multipoint1.add(0, 0); - multipoint1.add(3, 3); - multipoint1.add(0, 0); - multipoint1.add(5, 5); - multipoint1.add(3, 3); - multipoint1.add(2, 4); - multipoint1.add(2, 8); - - multipoint2.add(0, 0); - multipoint2.add(3, 3); - multipoint2.add(2, 4); - multipoint2.add(2, 8); - multipoint2.add(5, 5); - - boolean res = within.execute(multipoint1, multipoint2, sr, null); - assertTrue(res); - res = within.execute(multipoint2, multipoint1, sr, null); - assertTrue(res); - - multipoint2.add(10, 10); - multipoint2.add(10, 10); - - res = within.execute(multipoint1, multipoint2, sr, null); - assertTrue(res); - res = within.execute(multipoint2, multipoint1, sr, null); - assertTrue(!res); - - multipoint1.add(10, 10); - res = within.execute(multipoint1, multipoint2, sr, null); - assertTrue(res); - res = within.execute(multipoint2, multipoint1, sr, null); - assertTrue(res); - - multipoint1.add(-10, -10); - res = within.execute(multipoint1, multipoint2, sr, null); - assertTrue(!res); - res = within.execute(multipoint2, multipoint1, sr, null); - assertTrue(res); - } - - @Test - public void testPolylinePolylineOverlaps() { - OperatorOverlaps overlaps = (OperatorOverlaps) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Overlaps)); - SpatialReference sr = SpatialReference.create(102100); - double tolerance = sr - .getTolerance(VertexDescription.Semantics.POSITION); - - Polyline polyline1 = new Polyline(); - Polyline polyline2 = new Polyline(); - polyline1.startPath(0, 0); - polyline1.lineTo(2, 0); - polyline2.startPath(1, 0); - polyline2.lineTo(3, 0); - polyline2.lineTo(1, 1); - polyline2.lineTo(1, -1); - wiggleGeometry(polyline1, tolerance, 1982); - wiggleGeometry(polyline2, tolerance, 511); - - boolean res = overlaps.execute(polyline1, polyline2, sr, null); - assertTrue(res); - res = overlaps.execute(polyline2, polyline1, sr, null); - assertTrue(res); - - polyline1.setEmpty(); - polyline2.setEmpty(); - polyline1.startPath(0, 0); - polyline1.lineTo(2, 0); - polyline2.startPath(1.9989, 0); - polyline2.lineTo(2.0011, 0); - // wiggleGeometry(polyline1, tolerance, 1982); - // wiggleGeometry(polyline2, tolerance, 511); - - res = overlaps.execute(polyline1, polyline2, sr, null); - assertTrue(res); - res = overlaps.execute(polyline2, polyline1, sr, null); - assertTrue(res); - - polyline1.setEmpty(); - polyline2.setEmpty(); - polyline1.startPath(0, 0); - polyline1.lineTo(2, 0); - polyline2.startPath(1.9989, 0); - polyline2.lineTo(2.0009, 0); - wiggleGeometry(polyline1, tolerance, 1982); - wiggleGeometry(polyline2, tolerance, 511); - - res = overlaps.execute(polyline1, polyline2, sr, null); - assertTrue(!res); - res = overlaps.execute(polyline2, polyline1, sr, null); - assertTrue(!res); - - polyline1.setEmpty(); - polyline2.setEmpty(); - polyline1.startPath(0, 0); - polyline1.lineTo(2, 0); - polyline2.startPath(0, 0); - polyline2.lineTo(2, 0); - polyline2.startPath(0, -1); - polyline2.lineTo(2, -1); - - res = overlaps.execute(polyline1, polyline2, sr, null); - assertTrue(!res); - res = overlaps.execute(polyline2, polyline1, sr, null); - assertTrue(!res); - } - - @Test - public void testMultiPointMultiPointOverlaps() { - OperatorOverlaps overlaps = (OperatorOverlaps) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Overlaps)); - SpatialReference sr = SpatialReference.create(102100); - @SuppressWarnings("unused") - double tolerance = sr - .getTolerance(VertexDescription.Semantics.POSITION); - - MultiPoint multipoint1 = new MultiPoint(); - MultiPoint multipoint2 = new MultiPoint(); - - multipoint1.add(4, 4); - multipoint1.add(6, 4); - - multipoint2.add(6, 2); - multipoint2.add(2, 6); - - boolean res = overlaps.execute(multipoint1, multipoint2, sr, null); - assertTrue(!res); - res = overlaps.execute(multipoint2, multipoint1, sr, null); - assertTrue(!res); - - multipoint1.add(10, 10); - multipoint2.add(6, 2); - - res = overlaps.execute(multipoint1, multipoint2, sr, null); - assertTrue(!res); - res = overlaps.execute(multipoint2, multipoint1, sr, null); - assertTrue(!res); - - multipoint1.add(6, 2); - res = overlaps.execute(multipoint1, multipoint2, sr, null); - assertTrue(res); - res = overlaps.execute(multipoint2, multipoint1, sr, null); - assertTrue(res); - - multipoint1.add(2, 6); - res = overlaps.execute(multipoint1, multipoint2, sr, null); - assertTrue(!res); - res = overlaps.execute(multipoint2, multipoint1, sr, null); - assertTrue(!res); - - multipoint2.add(1, 1); - res = overlaps.execute(multipoint1, multipoint2, sr, null); - assertTrue(res); - res = overlaps.execute(multipoint2, multipoint1, sr, null); - assertTrue(res); - - multipoint2.add(10, 10); - multipoint2.add(4, 4); - multipoint2.add(6, 4); - res = overlaps.execute(multipoint1, multipoint2, sr, null); - assertTrue(!res); - res = overlaps.execute(multipoint2, multipoint1, sr, null); - assertTrue(!res); - } - - @Test - public void testPolygonPolygonWithin() { - OperatorWithin within = (OperatorWithin) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Within)); - SpatialReference sr = SpatialReference.create(102100); - double tolerance = sr - .getTolerance(VertexDescription.Semantics.POSITION); - - // Polygon1 is within Polygon2 - String str1 = "{\"rings\":[[[0,0],[0,5],[0,10],[10,10],[10,0],[0,0]],[[1,1],[9,1],[9,9],[1,9],[1,1],[1,1]]]}"; - String str2 = "{\"rings\":[[[-1,-1],[-1,11],[11,11],[11,-1],[-1,-1]]]}"; - - Polygon polygon1 = (Polygon) (TestCommonMethods.fromJson(str1) - .getGeometry()); - Polygon polygon2 = (Polygon) (TestCommonMethods.fromJson(str2) - .getGeometry()); - - boolean res = within.execute(polygon1, polygon2, sr, null); - assertTrue(res); - res = within.execute(polygon2, polygon1, sr, null); - assertTrue(!res); - - // Polygon1 is within Polygon2, and the boundaries intersect - str1 = "{\"rings\":[[[0,0],[0,5],[0,10],[10,10],[10,0],[0,0]],[[4,4],[6,4],[6,6],[4,6],[4,4],[4,4]]]}"; - str2 = "{\"rings\":[[[1,1],[1,9],[9,9],[9,1],[1,1]]]}"; - - polygon1 = (Polygon) (TestCommonMethods.fromJson(str1).getGeometry()); - polygon2 = (Polygon) (TestCommonMethods.fromJson(str2).getGeometry()); - wiggleGeometry(polygon1, tolerance, 1982); - wiggleGeometry(polygon2, tolerance, 511); - - res = within.execute(polygon2, polygon1, sr, null); - assertTrue(!res); - - // Polygon1 is within Polygon2, and the boundaries intersect - str1 = "{\"rings\":[[[0,0],[0,5],[0,10],[10,10],[10,0],[0,0]],[[1,1],[9,1],[9,9],[1,9],[1,1],[1,1]]]}"; - str2 = "{\"rings\":[[[-1,0],[-1,11],[11,11],[11,0],[-1,0]]]}"; - - polygon1 = (Polygon) (TestCommonMethods.fromJson(str1).getGeometry()); - polygon2 = (Polygon) (TestCommonMethods.fromJson(str2).getGeometry()); - wiggleGeometry(polygon1, tolerance, 1982); - wiggleGeometry(polygon2, tolerance, 511); - - res = within.execute(polygon1, polygon2, sr, null); - assertTrue(res); - - // Polygon2 is inside of the hole of polygon1 - str1 = "{\"rings\":[[[0,0],[0,5],[0,10],[10,10],[10,0],[0,0]],[[1,1],[9,1],[9,9],[1,9],[1,1],[1,1]]]}"; - str2 = "{\"rings\":[[[2,2],[2,8],[8,8],[8,2],[2,2]]]}"; - - polygon1 = (Polygon) (TestCommonMethods.fromJson(str1).getGeometry()); - polygon2 = (Polygon) (TestCommonMethods.fromJson(str2).getGeometry()); - - res = within.execute(polygon2, polygon1, sr, null); - assertTrue(!res); - - str1 = "{\"rings\":[[[0,0],[10,0],[10,10],[0,10]]]}"; - str2 = "{\"rings\":[[[2,2],[2,8],[8,8],[8,2],[2,2],[8,2],[8,8],[2,8],[2,2]]]}"; - - polygon1 = (Polygon) (TestCommonMethods.fromJson(str1).getGeometry()); - polygon2 = (Polygon) (TestCommonMethods.fromJson(str2).getGeometry()); - - res = within.execute(polygon2, polygon1, sr, null); - assertTrue(res); - - str1 = "{\"rings\":[[[0,0],[0,10],[10,10],[10,0]],[[12,8],[12,10],[18,10],[18,8],[12,8]]]}"; - str2 = "{\"paths\":[[[2,2],[2,8],[8,8],[8,2]],[[12,2],[12,4],[18,4],[18,2]]]}"; - - polygon1 = (Polygon) (TestCommonMethods.fromJson(str1).getGeometry()); - Polyline polyline2 = (Polyline) (TestCommonMethods.fromJson(str2).getGeometry()); - - res = within.execute(polyline2, polygon1, sr, null); - assertTrue(!res); - - str1 = "{\"rings\":[[[0,0],[0,10],[10,10],[10,0],[0,0]],[[4,4],[6,4],[6,6],[4,6],[4,4]]]}"; - str2 = "{\"rings\":[[[2,2],[2,8],[8,8],[8,2],[2,2],[2,8],[8,8],[8,2],[2,2]]]}"; - - polygon1 = (Polygon) (TestCommonMethods.fromJson(str1).getGeometry()); - polygon2 = (Polygon) (TestCommonMethods.fromJson(str2).getGeometry()); - - res = within.execute(polygon2, polygon1, sr, null); - assertTrue(res); - - // Same as above, but winding fill rule - str1 = "{\"rings\":[[[0,0],[0,10],[10,10],[10,0],[0,0]],[[4,4],[6,4],[6,6],[4,6],[4,4]]]}"; - str2 = "{\"rings\":[[[2,2],[2,8],[8,8],[8,2],[2,2],[2,8],[8,8],[8,2],[2,2]]]}"; - polygon1 = (Polygon) (TestCommonMethods.fromJson(str1).getGeometry()); - polygon2 = (Polygon) (TestCommonMethods.fromJson(str2).getGeometry()); - polygon1.setFillRule(Polygon.FillRule.enumFillRuleWinding); - polygon2.setFillRule(Polygon.FillRule.enumFillRuleWinding); - - res = within.execute(polygon2, polygon1, sr, null); - assertTrue(!res); - - str1 = "{\"rings\":[[[0,0],[0,10],[10,10],[10,0],[0,0]]]}"; - str2 = "{\"paths\":[[[2,2],[2,2]]]}"; - polygon1 = (Polygon) (TestCommonMethods.fromJson(str1).getGeometry()); - polyline2 = (Polyline) (TestCommonMethods.fromJson(str2).getGeometry()); - res = within.execute(polyline2, polygon1, sr, null); - assertTrue(res); - - str1 = "{\"rings\":[[[0,0],[0,10],[10,10],[10,0],[0,0]],[[11,11],[11,20],[20,20],[20,11],[11,11]]]}"; - str2 = "{\"rings\":[[[2,2],[2,8],[8,8],[15,15],[8,8],[8,2],[2,2]]]}"; - polygon1 = (Polygon) (TestCommonMethods.fromJson(str1).getGeometry()); - polygon2 = (Polygon) (TestCommonMethods.fromJson(str2).getGeometry()); - - res = within.execute(polygon2, polygon1, sr, null); - assertTrue(!res); - - str1 = "{\"rings\":[[[0,0],[0,10],[10,10],[10,0],[0,0]],[[10,10],[10,20],[20,20],[20,10],[10,10]]]}"; - str2 = "{\"rings\":[[[2,2],[2,8],[8,8],[15,15],[8,8],[8,2],[2,2]]]}"; - polygon1 = (Polygon) (TestCommonMethods.fromJson(str1).getGeometry()); - polygon2 = (Polygon) (TestCommonMethods.fromJson(str2).getGeometry()); - - res = within.execute(polygon2, polygon1, sr, null); - assertTrue(res); - - str1 = "{\"rings\":[[[0,0],[0,10],[10,10],[10,0],[0,0]]]}"; - str2 = "{\"rings\":[[[9.9999999925,4],[9.9999999925,6],[10.0000000075,6],[10.0000000075,4],[9.9999999925,4]]]}"; - polygon1 = (Polygon) (TestCommonMethods.fromJson(str1).getGeometry()); - polygon2 = (Polygon) (TestCommonMethods.fromJson(str2).getGeometry()); - - res = within.execute(polygon2, polygon1, sr, null); - assertTrue(!res); - - res = OperatorOverlaps.local().execute(polygon1, polygon2, sr, null); - assertTrue(!res); - - res = OperatorTouches.local().execute(polygon1, polygon2, sr, null); - assertTrue(res); - - str1 = "{\"rings\":[[[0,0],[0,10],[10,10],[10,0],[0,0]],[[10,10],[10,20],[20,20],[20,10],[10,10]]]}"; - str2 = "{\"rings\":[[[2,2],[2,8],[8,8],[15,15],[8,8],[8,2],[2,2]],[[15,5],[15,5],[15,5]]]}"; - polygon1 = (Polygon) (TestCommonMethods.fromJson(str1).getGeometry()); - polygon2 = (Polygon) (TestCommonMethods.fromJson(str2).getGeometry()); - res = within.execute(polygon2, polygon1, sr, null); - assertTrue(!res); - - str1 = "{\"rings\":[[[0,0],[0,10],[10,10],[10,0],[0,0]]]}"; - str2 = "{\"rings\":[[[2,2],[2,2],[2,2]],[[3,3],[3,3],[3,3]]]}"; - polygon1 = (Polygon) (TestCommonMethods.fromJson(str1).getGeometry()); - polygon2 = (Polygon) (TestCommonMethods.fromJson(str2).getGeometry()); - res = within.execute(polygon2, polygon1, sr, null); - assertTrue(res); - - str1 = "{\"rings\":[[[0,0],[0,10],[10,10],[10,0],[0,0]]]}"; - str2 = "{\"rings\":[[[2,2],[2,2],[2,2],[2,2]],[[3,3],[3,3],[3,3],[3,3]]]}"; - polygon1 = (Polygon) (TestCommonMethods.fromJson(str1).getGeometry()); - polygon2 = (Polygon) (TestCommonMethods.fromJson(str2).getGeometry()); - res = within.execute(polygon2, polygon1, sr, null); - assertTrue(res); - - str1 = "{\"rings\":[[[0,0],[0,10],[10,10],[10,0],[0,0]]]}"; - str2 = "{\"paths\":[[[2,2],[2,2]],[[3,3],[3,3]]]}"; - polygon1 = (Polygon) (TestCommonMethods.fromJson(str1).getGeometry()); - polyline2 = (Polyline) (TestCommonMethods.fromJson(str2).getGeometry()); - res = within.execute(polyline2, polygon1, sr, null); - assertTrue(res); - - str1 = "{\"rings\":[[[0,0],[0,10],[10,10],[10,0],[0,0]],[[10,10],[10,20],[20,20],[20,10],[10,10]]]}"; - str2 = "{\"paths\":[[[2,2],[2,8]],[[15,5],[15,5]]]}"; - polygon1 = (Polygon) (TestCommonMethods.fromJson(str1).getGeometry()); - polyline2 = (Polyline) (TestCommonMethods.fromJson(str2).getGeometry()); - res = within.execute(polyline2, polygon1, sr, null); - assertTrue(!res); - - str1 = "{\"rings\":[[[0,0],[0,10],[10,10],[10,0],[0,0]],[[10,10],[10,20],[20,20],[20,10],[10,10]]]}"; - str2 = "{\"paths\":[[[2,2],[2,8]],[[15,5],[15,5],[15,5],[15,5]]]}"; - polygon1 = (Polygon) (TestCommonMethods.fromJson(str1).getGeometry()); - polyline2 = (Polyline) (TestCommonMethods.fromJson(str2).getGeometry()); - res = within.execute(polyline2, polygon1, sr, null); - assertTrue(!res); - - str1 = "{\"rings\":[[[0,0],[0,10],[10,10],[10,0],[0,0]],[[10,10],[10,20],[20,20],[20,10],[10,10]]]}"; - str2 = "{\"paths\":[[[2,2],[2,2]],[[15,5],[15,6]]]}"; - polygon1 = (Polygon) (TestCommonMethods.fromJson(str1).getGeometry()); - polyline2 = (Polyline) (TestCommonMethods.fromJson(str2).getGeometry()); - res = within.execute(polyline2, polygon1, sr, null); - assertTrue(!res); - - str1 = "{\"rings\":[[[0,0],[0,10],[10,10],[10,0],[0,0]],[[10,10],[10,20],[20,20],[20,10],[10,10]]]}"; - str2 = "{\"paths\":[[[2,2],[2,2],[2,2],[2,2]],[[15,5],[15,6]]]}"; - polygon1 = (Polygon) (TestCommonMethods.fromJson(str1).getGeometry()); - polyline2 = (Polyline) (TestCommonMethods.fromJson(str2).getGeometry()); - res = within.execute(polyline2, polygon1, sr, null); - assertTrue(!res); - } - - @Test - public void testPolylinePolylineWithin() { - OperatorWithin within = (OperatorWithin) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Within)); - OperatorContains contains = (OperatorContains) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Contains)); - SpatialReference sr = SpatialReference.create(102100); - @SuppressWarnings("unused") - double tolerance = sr - .getTolerance(VertexDescription.Semantics.POSITION); - - Polyline polyline1 = new Polyline(); - Polyline polyline2 = new Polyline(); - - polyline1.setEmpty(); - polyline2.setEmpty(); - polyline1.startPath(0, 0); - polyline1.lineTo(2, 0); - polyline2.startPath(1.9989, 0); - polyline2.lineTo(2.0011, 0); - - boolean res = within.execute(polyline2, polyline1, sr, null); - assertTrue(!res); - - res = contains.execute(polyline1, polyline2, sr, null); - assertTrue(!res); - - polyline1.setEmpty(); - polyline2.setEmpty(); - polyline1.startPath(0, 0); - polyline1.lineTo(2, 0); - polyline2.startPath(1.9989, 0); - polyline2.lineTo(2.001, 0); - - res = within.execute(polyline2, polyline1, sr, null); - assertTrue(res); - - res = contains.execute(polyline1, polyline2, sr, null); - assertTrue(res); - - polyline1.setEmpty(); - polyline2.setEmpty(); - polyline1.startPath(0, 0); - polyline1.lineTo(2, 0); - polyline1.lineTo(3, 0); - polyline1.lineTo(4, 0); - polyline1.lineTo(5, 0); - polyline1.lineTo(6, 0); - polyline1.lineTo(7, 0); - polyline1.lineTo(8, 0); - - polyline2.startPath(0, 0); - polyline2.lineTo(.1, 0); - polyline2.lineTo(.2, 0); - polyline2.lineTo(.4, 0); - polyline2.lineTo(1.1, 0); - polyline2.lineTo(2.5, 0); - - polyline2.startPath(2.7, 0); - polyline2.lineTo(4, 0); - - res = within.execute(polyline2, polyline1, sr, null); - assertTrue(res); - - res = contains.execute(polyline1, polyline2, sr, null); - assertTrue(res); - } - - @Test - public void testPolylineMultiPointWithin() { - OperatorWithin within = (OperatorWithin) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Within)); - SpatialReference sr = SpatialReference.create(102100); - @SuppressWarnings("unused") - double tolerance = sr - .getTolerance(VertexDescription.Semantics.POSITION); - - Polyline polyline1 = new Polyline(); - MultiPoint multipoint2 = new MultiPoint(); - - polyline1.startPath(0, 0); - polyline1.lineTo(2, 0); - polyline1.lineTo(4, 2); - - multipoint2.add(1, 0); - multipoint2.add(2, 0); - multipoint2.add(3, 1); - multipoint2.add(2, 0); - - boolean res = within.execute(polyline1, multipoint2, sr, null); - assertTrue(!res); - res = within.execute(multipoint2, polyline1, sr, null); - assertTrue(res); - - polyline1.startPath(1, -2); - polyline1.lineTo(1, -1); - polyline1.lineTo(1, 0); - polyline1.lineTo(1, 1); - - res = within.execute(polyline1, multipoint2, sr, null); - assertTrue(!res); - res = within.execute(multipoint2, polyline1, sr, null); - assertTrue(res); - - multipoint2.add(1, 2); - res = within.execute(multipoint2, polyline1, sr, null); - assertTrue(!res); - - multipoint2.add(-1, -1); - multipoint2.add(4, 2); - multipoint2.add(0, 0); - - res = within.execute(multipoint2, polyline1, sr, null); - assertTrue(!res); - } - - @Test - public void testPolygonMultiPointWithin() { - OperatorWithin within = (OperatorWithin) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Within)); - SpatialReference sr = SpatialReference.create(102100); - @SuppressWarnings("unused") - double tolerance = sr - .getTolerance(VertexDescription.Semantics.POSITION); - - Polygon polygon1 = new Polygon(); - MultiPoint multipoint2 = new MultiPoint(); - - polygon1.startPath(0, 0); - polygon1.lineTo(0, 10); - polygon1.lineTo(10, 10); - polygon1.lineTo(10, 0); - - multipoint2.add(5, 0); - multipoint2.add(5, 10); - multipoint2.add(5, 5); - - boolean res = within.execute(polygon1, multipoint2, sr, null); - assertTrue(!res); - res = within.execute(multipoint2, polygon1, sr, null); - assertTrue(res); - - multipoint2.add(5, 11); - res = within.execute(multipoint2, polygon1, sr, null); - assertTrue(!res); - } - - @Test - public void testPolygonPolylineCrosses() { - OperatorCrosses crosses = (OperatorCrosses) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Crosses)); - SpatialReference sr = SpatialReference.create(102100); - @SuppressWarnings("unused") - double tolerance = sr - .getTolerance(VertexDescription.Semantics.POSITION); - - Polygon polygon1 = new Polygon(); - Polyline polyline2 = new Polyline(); - - polygon1.startPath(0, 0); - polygon1.lineTo(0, 10); - polygon1.lineTo(10, 10); - polygon1.lineTo(10, 0); - - polyline2.startPath(5, -5); - polyline2.lineTo(5, 15); - - boolean res = crosses.execute(polygon1, polyline2, sr, null); - assertTrue(res); - res = crosses.execute(polyline2, polygon1, sr, null); - assertTrue(res); - - polyline2.setEmpty(); - polyline2.startPath(5, 0); - polyline2.lineTo(5, 10); - - res = crosses.execute(polygon1, polyline2, sr, null); - assertTrue(!res); - res = crosses.execute(polyline2, polygon1, sr, null); - assertTrue(!res); - - polygon1.setEmpty(); - polyline2.setEmpty(); - - polygon1.startPath(0, 0); - polygon1.lineTo(0, 10); - polygon1.lineTo(10, 10); - polygon1.lineTo(10, 8); - polygon1.lineTo(15, 5); - polygon1.lineTo(10, 2); - polygon1.lineTo(10, 0); - - polyline2.startPath(10, 15); - polyline2.lineTo(10, -5); - - res = crosses.execute(polygon1, polyline2, sr, null); - assertTrue(res); - res = crosses.execute(polyline2, polygon1, sr, null); - assertTrue(res); - } - - @Test - public void testPolylinePolylineCrosses() { - OperatorCrosses crosses = (OperatorCrosses) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Crosses)); - SpatialReference sr = SpatialReference.create(102100); - double tolerance = sr - .getTolerance(VertexDescription.Semantics.POSITION); - - // Polyline1 and Polyline2 touch at a point - String str1 = "{\"paths\":[[[0,0],[0,5],[0,10],[10,10],[10,0]],[[1,1],[9,1],[9,9],[1,9],[1,1],[1,1]]]}"; - String str2 = "{\"paths\":[[[10,10],[10,15],[15,15],[15,10]]]}"; - - Polyline polyline1 = (Polyline) (TestCommonMethods.fromJson(str1) - .getGeometry()); - Polyline polyline2 = (Polyline) (TestCommonMethods.fromJson(str2) - .getGeometry()); - - boolean res = crosses.execute(polyline1, polyline2, sr, null); - assertTrue(!res); - res = crosses.execute(polyline2, polyline1, sr, null); - assertTrue(!res); - - // Polyline1 and Polyline2 intersect at interiors - str1 = "{\"paths\":[[[0,0],[0,5],[0,10],[10,10],[10,0],[0,0]],[[1,1],[9,1],[9,9],[1,9],[1,1],[1,1]]]}"; - str2 = "{\"paths\":[[[15,5],[5,15],[15,15],[15,5]]]}"; - - polyline1 = (Polyline) (TestCommonMethods.fromJson(str1).getGeometry()); - polyline2 = (Polyline) (TestCommonMethods.fromJson(str2).getGeometry()); - - res = crosses.execute(polyline1, polyline2, sr, null); - assertTrue(res); - res = crosses.execute(polyline2, polyline1, sr, null); - assertTrue(res); - - // Polyline1 and Polyline2 touch at an endpoint of Polyline1 and - // interior of Polyline2 (but Polyline1 is closed) - str1 = "{\"paths\":[[[10,10],[10,0],[0,0],[0,10],[10,10]],[[1,1],[9,1],[9,9],[1,9],[1,1],[1,1]]]}"; - str2 = "{\"paths\":[[[15,5],[5,15],[15,15]]]}"; - - polyline1 = (Polyline) (TestCommonMethods.fromJson(str1).getGeometry()); - polyline2 = (Polyline) (TestCommonMethods.fromJson(str2).getGeometry()); - ; - - res = crosses.execute(polyline1, polyline2, sr, null); - assertTrue(res); - res = crosses.execute(polyline2, polyline1, sr, null); - assertTrue(res); - - // Polyline1 and Polyline2 touch at an endpoint of Polyline1 and - // interior of Polyline2 (same as previous case, but Polyline1 is not - // closed) - str1 = "{\"paths\":[[[10,10],[10,0],[0,0],[0,10]],[[1,1],[9,1],[9,9],[1,9],[1,1],[1,1]]]}"; - str2 = "{\"paths\":[[[15,5],[5,15],[15,15]]]}"; - - polyline1 = (Polyline) (TestCommonMethods.fromJson(str1).getGeometry()); - polyline2 = (Polyline) (TestCommonMethods.fromJson(str2).getGeometry()); - - res = crosses.execute(polyline1, polyline2, sr, null); - assertTrue(!res); - res = crosses.execute(polyline2, polyline1, sr, null); - assertTrue(!res); - - str1 = "{\"paths\":[[[10,11],[10,0],[0,0],[0,10]],[[1,1],[9,1],[9,9],[1,9],[6, 9]]]}"; - str2 = "{\"paths\":[[[15,5],[5,15],[15,15],[15,5]]]}"; - - polyline1 = (Polyline) (TestCommonMethods.fromJson(str1).getGeometry()); - polyline2 = (Polyline) (TestCommonMethods.fromJson(str2).getGeometry()); - - res = crosses.execute(polyline1, polyline2, sr, null); - assertTrue(res); - res = crosses.execute(polyline2, polyline1, sr, null); - assertTrue(res); - - polyline1.setEmpty(); - polyline2.setEmpty(); - - polyline1.startPath(-2, -2); - polyline1.lineTo(-1, -1); - polyline1.lineTo(1, 1); - polyline1.lineTo(2, 2); - - polyline2.startPath(-2, 2); - polyline2.lineTo(-1, 1); - polyline2.lineTo(1, -1); - polyline2.lineTo(2, -2); - - res = crosses.execute(polyline2, polyline1, sr, null); - assertTrue(res); - } - - @Test - public void testPolygonEnvelope() { - OperatorEquals equals = (OperatorEquals) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Equals)); - OperatorContains contains = (OperatorContains) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Contains)); - OperatorDisjoint disjoint = (OperatorDisjoint) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Disjoint)); - OperatorCrosses crosses = (OperatorCrosses) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Crosses)); - @SuppressWarnings("unused") - OperatorWithin within = (OperatorWithin) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Within)); - OperatorOverlaps overlaps = (OperatorOverlaps) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Overlaps)); - OperatorTouches touches = (OperatorTouches) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Touches)); - OperatorDensifyByLength densify = (OperatorDensifyByLength) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.DensifyByLength)); - SpatialReference sr = SpatialReference.create(4326); - - { - Polygon polygon = (Polygon) (TestCommonMethods - .fromJson("{\"rings\":[[[0,0],[0,5],[0,10],[10,10],[10,0],[0,0]]]}") - .getGeometry()); - Polygon densified = (Polygon) (densify.execute(polygon, 1.0, null)); - Envelope envelope = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":10}") - .getGeometry()); - wiggleGeometry(densified, 0.00000001, 1982); - wiggleGeometry(envelope, 0.00000001, 511); - assertTrue(equals.execute(envelope, densified, sr, null)); // they - // cover - // the - // same - // space - assertTrue(contains.execute(densified, envelope, sr, null)); - assertTrue(!disjoint.execute(envelope, densified, sr, null)); - assertTrue(!touches.execute(envelope, densified, sr, null)); - assertTrue(!overlaps.execute(envelope, densified, sr, null)); - assertTrue(!crosses.execute(envelope, densified, sr, null)); - } - - { - Polygon polygon = (Polygon) (TestCommonMethods - .fromJson("{\"rings\":[[[0,0],[0,5],[0,10],[10,10],[10,0],[0,0]]]}") - .getGeometry()); - Polygon densified = (Polygon) (densify.execute(polygon, 1.0, null)); - Envelope envelope = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":5,\"ymin\":0,\"xmax\":10,\"ymax\":10}") - .getGeometry()); - wiggleGeometry(densified, 0.00000001, 1982); - wiggleGeometry(envelope, 0.00000001, 511); - assertTrue(!equals.execute(envelope, densified, sr, null)); // the - // polygon - // contains - // the - // envelope, - // but - // they - // aren't - // equal - assertTrue(contains.execute(densified, envelope, sr, null)); - assertTrue(!disjoint.execute(envelope, densified, sr, null)); - assertTrue(!touches.execute(envelope, densified, sr, null)); - assertTrue(!overlaps.execute(envelope, densified, sr, null)); - assertTrue(!crosses.execute(envelope, densified, sr, null)); - } - - { - Polygon polygon = (Polygon) (TestCommonMethods - .fromJson("{\"rings\":[[[0,0],[0,5],[0,10],[10,10],[10,0],[0,0]]]}") - .getGeometry()); - Polygon densified = (Polygon) (densify.execute(polygon, 1.0, null)); - Envelope envelope = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":15,\"ymax\":10}") - .getGeometry()); - wiggleGeometry(densified, 0.00000001, 1982); - wiggleGeometry(envelope, 0.00000001, 511); - assertTrue(!equals.execute(envelope, densified, sr, null)); // the - // envelope - // sticks - // outside - // of - // the - // polygon - // but - // they - // intersect - assertTrue(!contains.execute(densified, envelope, sr, null)); - assertTrue(!disjoint.execute(envelope, densified, sr, null)); - assertTrue(!touches.execute(envelope, densified, sr, null)); - assertTrue(!overlaps.execute(envelope, densified, sr, null)); - assertTrue(!crosses.execute(envelope, densified, sr, null)); - } - - { - Polygon polygon = (Polygon) (TestCommonMethods - .fromJson("{\"rings\":[[[0,0],[0,5],[0,10],[10,10],[10,0],[0,0]]]}") - .getGeometry()); - Polygon densified = (Polygon) (densify.execute(polygon, 1.0, null)); - Envelope envelope = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":5,\"ymin\":0,\"xmax\":15,\"ymax\":10}") - .getGeometry()); - wiggleGeometry(densified, 0.00000001, 1982); - wiggleGeometry(envelope, 0.00000001, 511); - assertTrue(!equals.execute(envelope, densified, sr, null)); // the - // envelope - // sticks - // outside - // of - // the - // polygon - // but - // they - // intersect - // and - // overlap - assertTrue(!contains.execute(densified, envelope, sr, null)); - assertTrue(!disjoint.execute(envelope, densified, sr, null)); - assertTrue(!touches.execute(envelope, densified, sr, null)); - assertTrue(overlaps.execute(envelope, densified, sr, null)); - assertTrue(!crosses.execute(envelope, densified, sr, null)); - } - - { - Polygon polygon = (Polygon) (TestCommonMethods - .fromJson("{\"rings\":[[[0,0],[0,5],[0,10],[10,10],[10,0],[0,0]]]}") - .getGeometry()); - Polygon densified = (Polygon) (densify.execute(polygon, 1.0, null)); - Envelope envelope = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":10,\"ymin\":0,\"xmax\":15,\"ymax\":5}") - .getGeometry()); - wiggleGeometry(densified, 0.00000001, 1982); - wiggleGeometry(envelope, 0.00000001, 511); - assertTrue(!equals.execute(envelope, densified, sr, null)); // the - // envelope - // rides - // the - // side - // of - // the - // polygon - // (they - // touch) - assertTrue(!contains.execute(densified, envelope, sr, null)); - assertTrue(!disjoint.execute(envelope, densified, sr, null)); - assertTrue(touches.execute(envelope, densified, sr, null)); - assertTrue(!overlaps.execute(envelope, densified, sr, null)); - assertTrue(!crosses.execute(envelope, densified, sr, null)); - } - - { - Polygon polygon = (Polygon) (TestCommonMethods - .fromJson("{\"rings\":[[[0,0],[0,5],[0,10],[10,10],[10,0],[0,0]]]}") - .getGeometry()); - Polygon densified = (Polygon) (densify.execute(polygon, 1.0, null)); - Envelope envelope = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":10}") - .getGeometry()); - wiggleGeometry(densified, 0.00000001, 1982); - wiggleGeometry(envelope, 0.00000001, 511); - assertTrue(contains.execute(densified, envelope, sr, null)); // polygon - // and - // envelope - // cover - // the - // same - // space - assertTrue(!disjoint.execute(densified, envelope, sr, null)); - assertTrue(!touches.execute(envelope, densified, sr, null)); - assertTrue(!overlaps.execute(envelope, densified, sr, null)); - assertTrue(!crosses.execute(envelope, densified, sr, null)); - } - - { - Polygon polygon = (Polygon) (TestCommonMethods - .fromJson("{\"rings\":[[[0,0],[0,5],[0,10],[10,0],[0,0]]]}") - .getGeometry()); - Polygon densified = (Polygon) (densify.execute(polygon, 1.0, null)); - Envelope envelope = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":10}") - .getGeometry()); - wiggleGeometry(densified, 0.00000001, 1982); - wiggleGeometry(envelope, 0.00000001, 511); - assertTrue(!equals.execute(envelope, densified, sr, null)); - assertTrue(!contains.execute(densified, envelope, sr, null)); // envelope - // sticks - // outside - // of - // polygon, - // but - // the - // envelopes - // are - // equal - assertTrue(!disjoint.execute(densified, envelope, sr, null)); - assertTrue(!touches.execute(envelope, densified, sr, null)); - assertTrue(!overlaps.execute(envelope, densified, sr, null)); - assertTrue(!crosses.execute(envelope, densified, sr, null)); - } - - { - Polygon polygon = (Polygon) (TestCommonMethods - .fromJson("{\"rings\":[[[0,0],[0,5],[0,10],[10,0],[0,0]]]}") - .getGeometry()); - Polygon densified = (Polygon) (densify.execute(polygon, 1.0, null)); - Envelope envelope = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":15,\"ymax\":10}") - .getGeometry()); - wiggleGeometry(densified, 0.00000001, 1982); - wiggleGeometry(envelope, 0.00000001, 511); - assertTrue(!equals.execute(envelope, densified, sr, null)); - assertTrue(!contains.execute(densified, envelope, sr, null)); // the - // polygon - // envelope - // doesn't - // contain - // the - // envelope, - // but - // they - // intersect - assertTrue(!disjoint.execute(densified, envelope, sr, null)); - assertTrue(!touches.execute(envelope, densified, sr, null)); - assertTrue(!overlaps.execute(envelope, densified, sr, null)); - assertTrue(!crosses.execute(envelope, densified, sr, null)); - } - - { - Polygon polygon = (Polygon) (TestCommonMethods - .fromJson("{\"rings\":[[[0,0],[0,5],[0,10],[10,10],[10,0],[0,0]]]}") - .getGeometry()); - Polygon densified = (Polygon) (densify.execute(polygon, 1.0, null)); - Envelope envelope = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":0,\"ymax\":0}") - .getGeometry()); - wiggleGeometry(densified, 0.00000001, 1982); - wiggleGeometry(envelope, 0.00000001, 511); - assertTrue(!equals.execute(envelope, densified, sr, null)); - assertTrue(!contains.execute(densified, envelope, sr, null)); // envelope - // degenerate - // to - // a - // point - // and - // is - // on - // border - // (i.e. - // touches) - assertTrue(!disjoint.execute(densified, envelope, sr, null)); - assertTrue(touches.execute(envelope, densified, sr, null)); - assertTrue(!overlaps.execute(envelope, densified, sr, null)); - assertTrue(!crosses.execute(envelope, densified, sr, null)); - } - - { - Polygon polygon = (Polygon) (TestCommonMethods - .fromJson("{\"rings\":[[[0,0],[0,5],[0,10],[10,10],[10,0],[0,0]]]}") - .getGeometry()); - Polygon densified = (Polygon) (densify.execute(polygon, 1.0, null)); - Envelope envelope = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":1,\"ymin\":1,\"xmax\":1,\"ymax\":1}") - .getGeometry()); - wiggleGeometry(densified, 0.00000001, 1982); - wiggleGeometry(envelope, 0.00000001, 511); - assertTrue(!equals.execute(envelope, densified, sr, null)); - assertTrue(contains.execute(densified, envelope, sr, null)); // envelope - // degenerate - // to - // a - // point - // and - // is - // properly - // inside - assertTrue(!disjoint.execute(densified, envelope, sr, null)); - assertTrue(!touches.execute(envelope, densified, sr, null)); - assertTrue(!overlaps.execute(envelope, densified, sr, null)); - assertTrue(!crosses.execute(envelope, densified, sr, null)); - } - - { - Polygon polygon = (Polygon) (TestCommonMethods - .fromJson("{\"rings\":[[[0,0],[0,5],[0,10],[10,10],[10,0],[0,0]]]}") - .getGeometry()); - Polygon densified = (Polygon) (densify.execute(polygon, 1.0, null)); - Envelope envelope = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":-1,\"ymin\":-1,\"xmax\":-1,\"ymax\":-1}") - .getGeometry()); - wiggleGeometry(densified, 0.00000001, 1982); - wiggleGeometry(envelope, 0.00000001, 511); - assertTrue(!equals.execute(envelope, densified, sr, null)); - assertTrue(!contains.execute(densified, envelope, sr, null)); // envelope - // degenerate - // to - // a - // point - // and - // is - // properly - // outside - assertTrue(disjoint.execute(densified, envelope, sr, null)); - assertTrue(!touches.execute(envelope, densified, sr, null)); - assertTrue(!overlaps.execute(envelope, densified, sr, null)); - assertTrue(!crosses.execute(envelope, densified, sr, null)); - } - - { - Polygon polygon = (Polygon) (TestCommonMethods - .fromJson("{\"rings\":[[[0,0],[0,5],[0,10],[10,10],[10,0],[0,0]]]}") - .getGeometry()); - Polygon densified = (Polygon) (densify.execute(polygon, 1.0, null)); - Envelope envelope = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":1,\"ymax\":0}") - .getGeometry()); - wiggleGeometry(densified, 0.00000001, 1982); - wiggleGeometry(envelope, 0.00000001, 511); - assertTrue(!equals.execute(envelope, densified, sr, null)); - assertTrue(!contains.execute(densified, envelope, sr, null)); // envelope - // degenerate - // to - // a - // line - // and - // rides - // the - // bottom - // of - // the - // polygon - // (no - // interior - // intersection) - assertTrue(!disjoint.execute(densified, envelope, sr, null)); - assertTrue(touches.execute(envelope, densified, sr, null)); - assertTrue(!overlaps.execute(envelope, densified, sr, null)); - assertTrue(!crosses.execute(envelope, densified, sr, null)); - } - - { - Polygon polygon = (Polygon) (TestCommonMethods - .fromJson("{\"rings\":[[[0,0],[0,5],[0,10],[10,10],[10,0],[0,0]]]}") - .getGeometry()); - Polygon densified = (Polygon) (densify.execute(polygon, 1.0, null)); - Envelope envelope = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":0,\"ymin\":1,\"xmax\":1,\"ymax\":1}") - .getGeometry()); - wiggleGeometry(densified, 0.00000001, 1982); - wiggleGeometry(envelope, 0.00000001, 511); - assertTrue(!equals.execute(envelope, densified, sr, null)); - assertTrue(contains.execute(densified, envelope, sr, null)); // envelope - // degenerate - // to - // a - // line, - // touches - // the - // border - // on - // the - // inside - // yet - // has - // interior - // intersection - assertTrue(!disjoint.execute(densified, envelope, sr, null)); - assertTrue(!touches.execute(envelope, densified, sr, null)); - assertTrue(!overlaps.execute(envelope, densified, sr, null)); - assertTrue(!crosses.execute(envelope, densified, sr, null)); - } - - { - Polygon polygon = (Polygon) (TestCommonMethods - .fromJson("{\"rings\":[[[0,0],[0,5],[0,10],[10,0],[0,0]]]}") - .getGeometry()); - Polygon densified = (Polygon) (densify.execute(polygon, 1.0, null)); - Envelope envelope = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":5,\"ymin\":5,\"xmax\":6,\"ymax\":5}") - .getGeometry()); - wiggleGeometry(densified, 0.00000001, 1982); - wiggleGeometry(envelope, 0.00000001, 511); - assertTrue(!equals.execute(envelope, densified, sr, null)); - assertTrue(!contains.execute(densified, envelope, sr, null)); // envelope - // degenerate - // to - // a - // line, - // touches - // the - // boundary, - // and - // is - // outside - assertTrue(!disjoint.execute(densified, envelope, sr, null)); - assertTrue(touches.execute(envelope, densified, sr, null)); - assertTrue(!overlaps.execute(envelope, densified, sr, null)); - assertTrue(!crosses.execute(envelope, densified, sr, null)); - } - - { - Polygon polygon = (Polygon) (TestCommonMethods - .fromJson("{\"rings\":[[[0,0],[0,5],[0,10],[10,0],[0,0]]]}") - .getGeometry()); - Polygon densified = (Polygon) (densify.execute(polygon, 1.0, null)); - Envelope envelope = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":6,\"ymin\":5,\"xmax\":7,\"ymax\":5}") - .getGeometry()); - wiggleGeometry(densified, 0.00000001, 1982); - wiggleGeometry(envelope, 0.00000001, 511); - assertTrue(!equals.execute(envelope, densified, sr, null)); - assertTrue(!contains.execute(densified, envelope, sr, null)); // envelope - // degenerate - // to - // a - // line, - // and - // is - // outside - assertTrue(disjoint.execute(densified, envelope, sr, null)); - assertTrue(!touches.execute(envelope, densified, sr, null)); - assertTrue(!overlaps.execute(envelope, densified, sr, null)); - assertTrue(!crosses.execute(envelope, densified, sr, null)); - } - - { - Polygon polygon = (Polygon) (TestCommonMethods - .fromJson("{\"rings\":[[[0,0],[0,5],[0,10],[10,0],[0,0]]]}") - .getGeometry()); - Polygon densified = (Polygon) (densify.execute(polygon, 1.0, null)); - Envelope envelope = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":4,\"ymin\":5,\"xmax\":7,\"ymax\":5}") - .getGeometry()); - wiggleGeometry(densified, 0.00000001, 1982); - wiggleGeometry(envelope, 0.00000001, 511); - assertTrue(!equals.execute(envelope, densified, sr, null)); - assertTrue(!contains.execute(densified, envelope, sr, null)); // envelope - // degenerate - // to - // a - // line, - // and - // crosses - // polygon - assertTrue(!disjoint.execute(densified, envelope, sr, null)); - assertTrue(!touches.execute(envelope, densified, sr, null)); - assertTrue(!overlaps.execute(envelope, densified, sr, null)); - assertTrue(crosses.execute(envelope, densified, sr, null)); - } - } - - @Test - public void testPolylineEnvelope() { - OperatorEquals equals = (OperatorEquals) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Equals)); - OperatorContains contains = (OperatorContains) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Contains)); - OperatorDisjoint disjoint = (OperatorDisjoint) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Disjoint)); - OperatorCrosses crosses = (OperatorCrosses) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Crosses)); - @SuppressWarnings("unused") - OperatorWithin within = (OperatorWithin) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Within)); - OperatorOverlaps overlaps = (OperatorOverlaps) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Overlaps)); - OperatorTouches touches = (OperatorTouches) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Touches)); - OperatorDensifyByLength densify = (OperatorDensifyByLength) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.DensifyByLength)); - - SpatialReference sr = SpatialReference.create(4326); - - { - Polyline polyline = (Polyline) (TestCommonMethods - .fromJson("{\"paths\":[[[0,0],[0,5],[0,10],[10,10],[10,0]]]}") - .getGeometry()); - Polyline densified = (Polyline) (densify.execute(polyline, 1.0, - null)); - Envelope envelope = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":10}") - .getGeometry()); - wiggleGeometry(densified, 0.00000001, 1982); - wiggleGeometry(envelope, 0.00000001, 511); - assertTrue(!equals.execute(envelope, densified, sr, null)); // polyline - // straddles - // the - // envelope - // like - // a hat - assertTrue(!contains.execute(densified, envelope, sr, null)); - assertTrue(!disjoint.execute(envelope, densified, sr, null)); - assertTrue(touches.execute(envelope, densified, sr, null)); - assertTrue(!overlaps.execute(envelope, densified, sr, null)); - assertTrue(!crosses.execute(envelope, densified, sr, null)); - } - - { - Polyline polyline = (Polyline) (TestCommonMethods - .fromJson("{\"paths\":[[[-10,0],[0,10]]]}").getGeometry()); - Polyline densified = (Polyline) (densify.execute(polyline, 1.0, - null)); - Envelope envelope = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":10}") - .getGeometry()); - wiggleGeometry(densified, 0.00000001, 1982); - wiggleGeometry(envelope, 0.00000001, 511); - assertTrue(!equals.execute(envelope, densified, sr, null)); - assertTrue(!contains.execute(densified, envelope, sr, null)); - assertTrue(!disjoint.execute(envelope, densified, sr, null)); - assertTrue(touches.execute(envelope, densified, sr, null)); - assertTrue(touches.execute(densified, envelope, sr, null)); - assertTrue(!overlaps.execute(envelope, densified, sr, null)); - assertTrue(!crosses.execute(envelope, densified, sr, null)); - } - - { - Polyline polyline = (Polyline) (TestCommonMethods - .fromJson("{\"paths\":[[[-11,0],[1,12]]]}").getGeometry()); - Polyline densified = (Polyline) (densify.execute(polyline, 1.0, - null)); - Envelope envelope = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":10}") - .getGeometry()); - wiggleGeometry(densified, 0.00000001, 1982); - wiggleGeometry(envelope, 0.00000001, 511); - assertTrue(!equals.execute(envelope, densified, sr, null)); - assertTrue(!contains.execute(densified, envelope, sr, null)); - assertTrue(disjoint.execute(envelope, densified, sr, null)); - assertTrue(!touches.execute(envelope, densified, sr, null)); - assertTrue(!touches.execute(densified, envelope, sr, null)); - assertTrue(!overlaps.execute(envelope, densified, sr, null)); - assertTrue(!crosses.execute(envelope, densified, sr, null)); - } - - { - Polyline polyline = (Polyline) (TestCommonMethods - .fromJson("{\"paths\":[[[5,5],[6,6]]]}").getGeometry()); - Polyline densified = (Polyline) (densify.execute(polyline, 1.0, - null)); - Envelope envelope = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":10}") - .getGeometry()); - wiggleGeometry(densified, 0.00000001, 1982); - wiggleGeometry(envelope, 0.00000001, 511); - assertTrue(!equals.execute(envelope, densified, sr, null)); // polyline - // properly - // inside - assertTrue(contains.execute(envelope, densified, sr, null)); - assertTrue(!disjoint.execute(envelope, densified, sr, null)); - assertTrue(!touches.execute(envelope, densified, sr, null)); - assertTrue(!overlaps.execute(envelope, densified, sr, null)); - assertTrue(!crosses.execute(envelope, densified, sr, null)); - } - - { - Polyline polyline = (Polyline) (TestCommonMethods - .fromJson("{\"paths\":[[[5,5],[10,10]]]}").getGeometry()); - Polyline densified = (Polyline) (densify.execute(polyline, 1.0, - null)); - Envelope envelope = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":10}") - .getGeometry()); - wiggleGeometry(densified, 0.00000001, 1982); - wiggleGeometry(envelope, 0.00000001, 511); - assertTrue(!equals.execute(envelope, densified, sr, null)); - assertTrue(contains.execute(envelope, densified, sr, null)); - assertTrue(!disjoint.execute(envelope, densified, sr, null)); - assertTrue(!touches.execute(envelope, densified, sr, null)); - assertTrue(!overlaps.execute(envelope, densified, sr, null)); - assertTrue(!crosses.execute(envelope, densified, sr, null)); - } - - { - Polyline polyline = (Polyline) (TestCommonMethods - .fromJson("{\"paths\":[[[-5,5],[15,5]]]}").getGeometry()); - Polyline densified = (Polyline) (densify.execute(polyline, 1.0, - null)); - Envelope envelope = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":10}") - .getGeometry()); - wiggleGeometry(densified, 0.00000001, 1982); - wiggleGeometry(envelope, 0.00000001, 511); - assertTrue(!equals.execute(envelope, densified, sr, null)); - assertTrue(!contains.execute(envelope, densified, sr, null)); - assertTrue(!disjoint.execute(envelope, densified, sr, null)); - assertTrue(!touches.execute(envelope, densified, sr, null)); - assertTrue(!overlaps.execute(envelope, densified, sr, null)); - assertTrue(crosses.execute(envelope, densified, sr, null)); - assertTrue(crosses.execute(densified, envelope, sr, null)); - } - - { - Polyline polyline = (Polyline) (TestCommonMethods - .fromJson("{\"paths\":[[[5,5],[5,15]]]}").getGeometry()); - Polyline densified = (Polyline) (densify.execute(polyline, 1.0, - null)); - Envelope envelope = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":10}") - .getGeometry()); - wiggleGeometry(densified, 0.00000001, 1982); - wiggleGeometry(envelope, 0.00000001, 511); - assertTrue(!equals.execute(envelope, densified, sr, null)); // polyline - // slices - // through - // the - // envelope - // (interior - // and - // exterior - // intersection) - assertTrue(!contains.execute(densified, envelope, sr, null)); - assertTrue(!disjoint.execute(envelope, densified, sr, null)); - assertTrue(!touches.execute(envelope, densified, sr, null)); - assertTrue(!overlaps.execute(envelope, densified, sr, null)); - assertTrue(crosses.execute(envelope, densified, sr, null)); - } - - { - Polyline polyline = (Polyline) (TestCommonMethods - .fromJson("{\"paths\":[[[5,11],[5,15]]]}").getGeometry()); - Polyline densified = (Polyline) (densify.execute(polyline, 1.0, - null)); - Envelope envelope = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":10}") - .getGeometry()); - wiggleGeometry(densified, 0.00000001, 1982); - wiggleGeometry(envelope, 0.00000001, 511); - assertTrue(!equals.execute(envelope, densified, sr, null)); // polyline - // outside - // of - // envelope - assertTrue(!contains.execute(densified, envelope, sr, null)); - assertTrue(disjoint.execute(envelope, densified, sr, null)); - assertTrue(!touches.execute(envelope, densified, sr, null)); - assertTrue(!overlaps.execute(envelope, densified, sr, null)); - assertTrue(!crosses.execute(envelope, densified, sr, null)); - } - - { - Polyline polyline = (Polyline) (TestCommonMethods - .fromJson("{\"paths\":[[[0,0],[0,5],[0,10],[10,10],[10,0]]]}") - .getGeometry()); - Polyline densified = (Polyline) (densify.execute(polyline, 1.0, - null)); - Envelope envelope = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":0,\"ymin\":10,\"xmax\":10,\"ymax\":10}") - .getGeometry()); - wiggleGeometry(densified, 0.00000001, 1982); - wiggleGeometry(envelope, 0.00000001, 511); - assertTrue(!equals.execute(envelope, densified, sr, null)); // polyline - // straddles - // the - // degenerate - // envelope - // like - // a hat - assertTrue(contains.execute(densified, envelope, sr, null)); - assertTrue(!disjoint.execute(envelope, densified, sr, null)); - assertTrue(!touches.execute(envelope, densified, sr, null)); - assertTrue(!overlaps.execute(envelope, densified, sr, null)); - assertTrue(!crosses.execute(envelope, densified, sr, null)); - } - - { - Polyline polyline = (Polyline) (TestCommonMethods - .fromJson("{\"paths\":[[[0,0],[0,5],[0,10],[10,10],[10,0]]]}") - .getGeometry()); - Polyline densified = (Polyline) (densify.execute(polyline, 1.0, - null)); - Envelope envelope = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":0,\"ymin\":-5,\"xmax\":0,\"ymax\":10}") - .getGeometry()); - wiggleGeometry(densified, 0.00000001, 1982); - wiggleGeometry(envelope, 0.00000001, 511); - assertTrue(!equals.execute(envelope, densified, sr, null)); - assertTrue(!contains.execute(densified, envelope, sr, null)); - assertTrue(!disjoint.execute(envelope, densified, sr, null)); - assertTrue(!touches.execute(envelope, densified, sr, null)); - assertTrue(overlaps.execute(envelope, densified, sr, null)); - assertTrue(!crosses.execute(envelope, densified, sr, null)); - } - - { - Polyline polyline = (Polyline) (TestCommonMethods - .fromJson("{\"paths\":[[[0,0],[0,5],[0,10],[10,10],[10,0]]]}") - .getGeometry()); - Polyline densified = (Polyline) (densify.execute(polyline, 1.0, - null)); - Envelope envelope = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":0,\"ymax\":0}") - .getGeometry()); - wiggleGeometry(densified, 0.00000001, 511); - wiggleGeometry(envelope, 0.00000001, 1982); - assertTrue(!equals.execute(envelope, densified, sr, null)); // degenerate - // envelope - // is at - // the - // end - // point - // of - // polyline - assertTrue(!contains.execute(densified, envelope, sr, null)); - assertTrue(!disjoint.execute(envelope, densified, sr, null)); - assertTrue(touches.execute(envelope, densified, sr, null)); - assertTrue(!overlaps.execute(envelope, densified, sr, null)); - assertTrue(!crosses.execute(envelope, densified, sr, null)); - } - - { - Polyline polyline = (Polyline) (TestCommonMethods - .fromJson("{\"paths\":[[[0,0],[0,5],[0,10],[10,10],[10,0]]]}") - .getGeometry()); - Polyline densified = (Polyline) (densify.execute(polyline, 1.0, - null)); - Envelope envelope = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":0,\"ymin\":5,\"xmax\":0,\"ymax\":5}") - .getGeometry()); - wiggleGeometry(densified, 0.00000001, 1982); - wiggleGeometry(envelope, 0.00000001, 511); - assertTrue(!equals.execute(envelope, densified, sr, null)); // degenerate - // envelope - // is at - // the - // interior - // of - // polyline - assertTrue(contains.execute(densified, envelope, sr, null)); - assertTrue(!disjoint.execute(envelope, densified, sr, null)); - assertTrue(!touches.execute(envelope, densified, sr, null)); - assertTrue(!overlaps.execute(envelope, densified, sr, null)); - assertTrue(!crosses.execute(envelope, densified, sr, null)); - } - - { - Polyline polyline = (Polyline) (TestCommonMethods - .fromJson("{\"paths\":[[[2,-2],[2,2]]]}").getGeometry()); - Polyline densified = (Polyline) (densify.execute(polyline, 1.0, - null)); - Envelope envelope = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":5,\"ymax\":0}") - .getGeometry()); - wiggleGeometry(densified, 0.00000001, 1982); - wiggleGeometry(envelope, 0.00000001, 511); - assertTrue(!equals.execute(envelope, densified, sr, null)); // degenerate - // envelope - // crosses - // polyline - assertTrue(!contains.execute(densified, envelope, sr, null)); - assertTrue(!disjoint.execute(envelope, densified, sr, null)); - assertTrue(!touches.execute(envelope, densified, sr, null)); - assertTrue(!overlaps.execute(envelope, densified, sr, null)); - assertTrue(crosses.execute(envelope, densified, sr, null)); - } - - { - Polyline polyline = (Polyline) (TestCommonMethods - .fromJson("{\"paths\":[[[2,0],[2,2]]]}").getGeometry()); - Polyline densified = (Polyline) (densify.execute(polyline, 1.0, - null)); - Envelope envelope = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":5,\"ymax\":0}") - .getGeometry()); - wiggleGeometry(densified, 0.00000001, 1982); - wiggleGeometry(envelope, 0.00000001, 511); - assertTrue(!equals.execute(envelope, densified, sr, null)); // degenerate - // envelope - // crosses - // polyline - assertTrue(!contains.execute(densified, envelope, sr, null)); - assertTrue(!disjoint.execute(envelope, densified, sr, null)); - assertTrue(touches.execute(envelope, densified, sr, null)); - assertTrue(!overlaps.execute(envelope, densified, sr, null)); - assertTrue(!crosses.execute(envelope, densified, sr, null)); - } - - { - Polyline polyline = (Polyline) (TestCommonMethods - .fromJson("{\"paths\":[[[2,0],[2,2]]]}").getGeometry()); - Polyline densified = (Polyline) (densify.execute(polyline, 1.0, - null)); - Envelope envelope = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":2,\"ymin\":0,\"xmax\":2,\"ymax\":3}") - .getGeometry()); - wiggleGeometry(densified, 0.00000001, 1982); - wiggleGeometry(envelope, 0.00000001, 511); - assertTrue(!equals.execute(envelope, densified, sr, null)); // degenerate - // envelope - // contains - // polyline - assertTrue(!contains.execute(densified, envelope, sr, null)); - assertTrue(contains.execute(envelope, densified, sr, null)); - assertTrue(!disjoint.execute(envelope, densified, sr, null)); - assertTrue(!touches.execute(envelope, densified, sr, null)); - assertTrue(!overlaps.execute(envelope, densified, sr, null)); - assertTrue(!crosses.execute(envelope, densified, sr, null)); - } - - { - Polyline polyline = (Polyline) (TestCommonMethods - .fromJson("{\"paths\":[[[5,5],[6,6]]]}").getGeometry()); - Polyline densified = (Polyline) (densify.execute(polyline, 1.0, - null)); - Envelope envelope = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":5,\"ymax\":5}") - .getGeometry()); - wiggleGeometry(densified, 0.00000001, 1982); - wiggleGeometry(envelope, 0.00000001, 511); - assertTrue(!equals.execute(envelope, densified, sr, null)); // polyline - // properly - // inside - assertTrue(!contains.execute(envelope, densified, sr, null)); - assertTrue(!disjoint.execute(envelope, densified, sr, null)); - assertTrue(touches.execute(envelope, densified, sr, null)); - assertTrue(!overlaps.execute(envelope, densified, sr, null)); - assertTrue(!crosses.execute(envelope, densified, sr, null)); - } - - { - Polyline polyline = (Polyline) (TestCommonMethods - .fromJson("{\"paths\":[[[5,5],[5,10]]]}").getGeometry()); - Polyline densified = (Polyline) (densify.execute(polyline, 1.0, - null)); - Envelope envelope = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":5,\"ymin\":5,\"xmax\":5,\"ymax\":10}") - .getGeometry()); - wiggleGeometry(densified, 0.00000001, 1982); - wiggleGeometry(envelope, 0.00000001, 511); - assertTrue(equals.execute(envelope, densified, sr, null)); // polyline - // properly - // inside - assertTrue(contains.execute(envelope, densified, sr, null)); - assertTrue(!disjoint.execute(envelope, densified, sr, null)); - assertTrue(!touches.execute(envelope, densified, sr, null)); - assertTrue(!overlaps.execute(envelope, densified, sr, null)); - assertTrue(!crosses.execute(envelope, densified, sr, null)); - } - } - - @Test - public void testMultiPointEnvelope() { - OperatorEquals equals = (OperatorEquals) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Equals)); - OperatorContains contains = (OperatorContains) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Contains)); - OperatorDisjoint disjoint = (OperatorDisjoint) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Disjoint)); - OperatorCrosses crosses = (OperatorCrosses) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Crosses)); - @SuppressWarnings("unused") - OperatorWithin within = (OperatorWithin) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Within)); - OperatorOverlaps overlaps = (OperatorOverlaps) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Overlaps)); - OperatorTouches touches = (OperatorTouches) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Touches)); - @SuppressWarnings("unused") - OperatorDensifyByLength densify = (OperatorDensifyByLength) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.DensifyByLength)); - - SpatialReference sr = SpatialReference.create(4326); - - { - MultiPoint multi_point = (MultiPoint) (TestCommonMethods - .fromJson("{\"points\":[[0,0],[0,10],[10,10],[10,0]]}") - .getGeometry()); - Envelope envelope = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":10}") - .getGeometry()); - wiggleGeometry(multi_point, 0.00000001, 1982); - wiggleGeometry(envelope, 0.00000001, 511); - assertTrue(!equals.execute(envelope, multi_point, sr, null)); // all - // points - // on - // boundary - assertTrue(!contains.execute(envelope, multi_point, sr, null)); - assertTrue(!disjoint.execute(envelope, multi_point, sr, null)); - assertTrue(touches.execute(envelope, multi_point, sr, null)); - assertTrue(!overlaps.execute(envelope, multi_point, sr, null)); - assertTrue(!crosses.execute(envelope, multi_point, sr, null)); - } - - { - MultiPoint multi_point = (MultiPoint) (TestCommonMethods - .fromJson("{\"points\":[[0,0],[0,10],[10,10],[5,5]]}") - .getGeometry()); - Envelope envelope = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":10}") - .getGeometry()); - wiggleGeometry(multi_point, 0.00000001, 1982); - wiggleGeometry(envelope, 0.00000001, 511); - assertTrue(!equals.execute(envelope, multi_point, sr, null)); // points - // on - // boundary - // and - // one - // point - // in - // interior - assertTrue(contains.execute(envelope, multi_point, sr, null)); - assertTrue(!disjoint.execute(envelope, multi_point, sr, null)); - assertTrue(!touches.execute(envelope, multi_point, sr, null)); - assertTrue(!overlaps.execute(envelope, multi_point, sr, null)); - assertTrue(!crosses.execute(envelope, multi_point, sr, null)); - } - - { - MultiPoint multi_point = (MultiPoint) (TestCommonMethods - .fromJson("{\"points\":[[0,0],[0,10],[10,10],[5,5],[15,15]]}") - .getGeometry()); - Envelope envelope = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":10}") - .getGeometry()); - wiggleGeometry(multi_point, 0.00000001, 1982); - wiggleGeometry(envelope, 0.00000001, 511); - assertTrue(!equals.execute(envelope, multi_point, sr, null)); // points - // on - // boundary, - // one - // interior, - // one - // exterior - assertTrue(!contains.execute(envelope, multi_point, sr, null)); - assertTrue(!disjoint.execute(envelope, multi_point, sr, null)); - assertTrue(!touches.execute(envelope, multi_point, sr, null)); - assertTrue(!overlaps.execute(envelope, multi_point, sr, null)); - assertTrue(crosses.execute(envelope, multi_point, sr, null)); - } - - { - MultiPoint multi_point = (MultiPoint) (TestCommonMethods - .fromJson("{\"points\":[[0,0],[0,10],[10,10],[15,15]]}") - .getGeometry()); - Envelope envelope = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":10}") - .getGeometry()); - wiggleGeometry(multi_point, 0.00000001, 1982); - wiggleGeometry(envelope, 0.00000001, 511); - assertTrue(!equals.execute(envelope, multi_point, sr, null)); // points - // on - // boundary, - // one - // exterior - assertTrue(!contains.execute(envelope, multi_point, sr, null)); - assertTrue(!disjoint.execute(envelope, multi_point, sr, null)); - assertTrue(touches.execute(envelope, multi_point, sr, null)); - assertTrue(!overlaps.execute(envelope, multi_point, sr, null)); - assertTrue(!crosses.execute(envelope, multi_point, sr, null)); - } - - { - MultiPoint multi_point = (MultiPoint) (TestCommonMethods - .fromJson("{\"points\":[[0,-1],[0,11],[11,11],[15,15]]}") - .getGeometry()); - Envelope envelope = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":10}") - .getGeometry()); - wiggleGeometry(multi_point, 0.00000001, 1982); - wiggleGeometry(envelope, 0.00000001, 511); - assertTrue(!equals.execute(envelope, multi_point, sr, null)); // all - // points - // exterior - assertTrue(!contains.execute(envelope, multi_point, sr, null)); - assertTrue(disjoint.execute(envelope, multi_point, sr, null)); - assertTrue(!touches.execute(envelope, multi_point, sr, null)); - assertTrue(!overlaps.execute(envelope, multi_point, sr, null)); - assertTrue(!crosses.execute(envelope, multi_point, sr, null)); - } - - { - MultiPoint multi_point = (MultiPoint) (TestCommonMethods - .fromJson("{\"points\":[[0,0],[0,10],[10,10],[10,0]]}") - .getGeometry()); - Envelope envelope = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":0,\"ymin\":10,\"xmax\":10,\"ymax\":10}") - .getGeometry()); - wiggleGeometry(multi_point, 0.00000001, 1982); - wiggleGeometry(envelope, 0.00000001, 511); - assertTrue(!equals.execute(envelope, multi_point, sr, null)); // degenerate - // envelope - // slices - // through - // some - // points, - // but - // some - // points - // are - // off - // the - // line - assertTrue(!contains.execute(envelope, multi_point, sr, null)); - assertTrue(!disjoint.execute(envelope, multi_point, sr, null)); - assertTrue(touches.execute(envelope, multi_point, sr, null)); - assertTrue(!overlaps.execute(envelope, multi_point, sr, null)); - assertTrue(!crosses.execute(envelope, multi_point, sr, null)); - } - - { - MultiPoint multi_point = (MultiPoint) (TestCommonMethods - .fromJson("{\"points\":[[0,0],[1,10],[10,10],[10,0]]}") - .getGeometry()); - Envelope envelope = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":0,\"ymin\":10,\"xmax\":10,\"ymax\":10}") - .getGeometry()); - wiggleGeometry(multi_point, 0.00000001, 1982); - wiggleGeometry(envelope, 0.00000001, 511); - assertTrue(!equals.execute(envelope, multi_point, sr, null)); // degenerate - // envelope - // slices - // through - // some - // points, - // but - // some - // points - // are - // off - // the - // line - assertTrue(!contains.execute(envelope, multi_point, sr, null)); - assertTrue(!disjoint.execute(envelope, multi_point, sr, null)); - assertTrue(!touches.execute(envelope, multi_point, sr, null)); - assertTrue(!overlaps.execute(envelope, multi_point, sr, null)); - assertTrue(crosses.execute(envelope, multi_point, sr, null)); - } - - { - MultiPoint multi_point = (MultiPoint) (TestCommonMethods - .fromJson("{\"points\":[[0,10],[10,10]]}").getGeometry()); - Envelope envelope = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":0,\"ymin\":10,\"xmax\":10,\"ymax\":10}") - .getGeometry()); - wiggleGeometry(multi_point, 0.00000001, 1982); - wiggleGeometry(envelope, 0.00000001, 511); - assertTrue(!equals.execute(envelope, multi_point, sr, null)); // degenerate - // envelopes - // slices - // through - // all - // the - // points, - // and - // they - // are - // at - // the - // end - // points - // of - // the - // line - assertTrue(!contains.execute(envelope, multi_point, sr, null)); - assertTrue(!disjoint.execute(envelope, multi_point, sr, null)); - assertTrue(touches.execute(envelope, multi_point, sr, null)); - assertTrue(!overlaps.execute(envelope, multi_point, sr, null)); - assertTrue(!crosses.execute(envelope, multi_point, sr, null)); - } - - { - MultiPoint multi_point = (MultiPoint) (TestCommonMethods - .fromJson("{\"points\":[[1,10],[9,10]]}").getGeometry()); - Envelope envelope = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":0,\"ymin\":10,\"xmax\":10,\"ymax\":10}") - .getGeometry()); - wiggleGeometry(multi_point, 0.00000001, 1982); - wiggleGeometry(envelope, 0.00000001, 511); - assertTrue(!equals.execute(envelope, multi_point, sr, null)); // degenerate - // envelopes - // slices - // through - // all - // the - // points, - // and - // they - // are - // in - // the - // interior - // of - // the - // line - assertTrue(contains.execute(envelope, multi_point, sr, null)); - assertTrue(!disjoint.execute(envelope, multi_point, sr, null)); - assertTrue(!touches.execute(envelope, multi_point, sr, null)); - assertTrue(!overlaps.execute(envelope, multi_point, sr, null)); - assertTrue(!crosses.execute(envelope, multi_point, sr, null)); - } - - { - MultiPoint multi_point = (MultiPoint) (TestCommonMethods - .fromJson("{\"points\":[[0,-1],[0,11],[11,11],[15,15]]}") - .getGeometry()); - Envelope envelope = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":0,\"ymin\":10,\"xmax\":10,\"ymax\":10}") - .getGeometry()); - wiggleGeometry(multi_point, 0.00000001, 1982); - wiggleGeometry(envelope, 0.00000001, 511); - assertTrue(!equals.execute(envelope, multi_point, sr, null)); // all - // points - // exterior - assertTrue(!contains.execute(envelope, multi_point, sr, null)); - assertTrue(disjoint.execute(envelope, multi_point, sr, null)); - assertTrue(!touches.execute(envelope, multi_point, sr, null)); - assertTrue(!overlaps.execute(envelope, multi_point, sr, null)); - assertTrue(!crosses.execute(envelope, multi_point, sr, null)); - } - - { - MultiPoint multi_point = (MultiPoint) (TestCommonMethods - .fromJson("{\"points\":[[0,-1],[0,11],[11,11],[15,15]]}") - .getGeometry()); - Envelope envelope = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":10,\"ymin\":10,\"xmax\":10,\"ymax\":10}") - .getGeometry()); - wiggleGeometry(multi_point, 0.00000001, 1982); - wiggleGeometry(envelope, 0.00000001, 511); - assertTrue(!equals.execute(envelope, multi_point, sr, null)); // all - // points - // exterior - assertTrue(!contains.execute(envelope, multi_point, sr, null)); - assertTrue(disjoint.execute(envelope, multi_point, sr, null)); - assertTrue(!touches.execute(envelope, multi_point, sr, null)); - assertTrue(!overlaps.execute(envelope, multi_point, sr, null)); - assertTrue(!crosses.execute(envelope, multi_point, sr, null)); - } - - { - MultiPoint multi_point = (MultiPoint) (TestCommonMethods - .fromJson("{\"points\":[[0,-1],[0,11],[11,11],[15,15]]}") - .getGeometry()); - Envelope envelope = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":11,\"ymax\":11}") - .getGeometry()); - wiggleGeometry(multi_point, 0.00000001, 1982); - wiggleGeometry(envelope, 0.00000001, 511); - assertTrue(!equals.execute(envelope, multi_point, sr, null)); // all - // points - // exterior - assertTrue(!contains.execute(multi_point, envelope, sr, null)); - assertTrue(!contains.execute(envelope, multi_point, sr, null)); - assertTrue(!disjoint.execute(envelope, multi_point, sr, null)); - assertTrue(touches.execute(envelope, multi_point, sr, null)); - assertTrue(!overlaps.execute(envelope, multi_point, sr, null)); - assertTrue(!crosses.execute(envelope, multi_point, sr, null)); - } - - { - MultiPoint multi_point = (MultiPoint) (TestCommonMethods - .fromJson("{\"points\":[[0,-1],[0,-1]]}").getGeometry()); - Envelope envelope = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":0,\"ymin\":-1,\"xmax\":0,\"ymax\":-1}") - .getGeometry()); - wiggleGeometry(multi_point, 0.00000001, 1982); - wiggleGeometry(envelope, 0.00000001, 511); - assertTrue(equals.execute(envelope, multi_point, sr, null)); // all - // points - // exterior - assertTrue(contains.execute(multi_point, envelope, sr, null)); - assertTrue(contains.execute(envelope, multi_point, sr, null)); - assertTrue(!disjoint.execute(envelope, multi_point, sr, null)); - assertTrue(!touches.execute(envelope, multi_point, sr, null)); - assertTrue(!overlaps.execute(envelope, multi_point, sr, null)); - assertTrue(!crosses.execute(envelope, multi_point, sr, null)); - } - } - - @Test - public void testPointEnvelope() { - OperatorEquals equals = (OperatorEquals) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Equals)); - OperatorContains contains = (OperatorContains) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Contains)); - OperatorDisjoint disjoint = (OperatorDisjoint) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Disjoint)); - OperatorCrosses crosses = (OperatorCrosses) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Crosses)); - @SuppressWarnings("unused") - OperatorWithin within = (OperatorWithin) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Within)); - OperatorOverlaps overlaps = (OperatorOverlaps) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Overlaps)); - OperatorTouches touches = (OperatorTouches) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Touches)); - SpatialReference sr = SpatialReference.create(4326); - - { - Point point = (Point) (TestCommonMethods - .fromJson("{\"x\":5,\"y\":6}").getGeometry()); - Envelope envelope = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":10}") - .getGeometry()); - wiggleGeometry(point, 0.00000001, 1982); - wiggleGeometry(envelope, 0.00000001, 511); - assertTrue(!equals.execute(envelope, point, sr, null)); - assertTrue(contains.execute(envelope, point, sr, null)); - assertTrue(!contains.execute(point, envelope, sr, null)); - assertTrue(!disjoint.execute(envelope, point, sr, null)); - assertTrue(!touches.execute(envelope, point, sr, null)); - assertTrue(!overlaps.execute(envelope, point, sr, null)); - assertTrue(!crosses.execute(envelope, point, sr, null)); - } - - { - Point point = (Point) (TestCommonMethods - .fromJson("{\"x\":0,\"y\":10}").getGeometry()); - Envelope envelope = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":10}") - .getGeometry()); - wiggleGeometry(point, 0.00000001, 1982); - wiggleGeometry(envelope, 0.00000001, 511); - assertTrue(!equals.execute(envelope, point, sr, null)); - assertTrue(!contains.execute(envelope, point, sr, null)); - assertTrue(!contains.execute(point, envelope, sr, null)); - assertTrue(!disjoint.execute(envelope, point, sr, null)); - assertTrue(touches.execute(envelope, point, sr, null)); - assertTrue(!overlaps.execute(envelope, point, sr, null)); - assertTrue(!crosses.execute(envelope, point, sr, null)); - } - - { - Point point = (Point) (TestCommonMethods - .fromJson("{\"x\":0,\"y\":11}").getGeometry()); - Envelope envelope = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":10}") - .getGeometry()); - wiggleGeometry(point, 0.00000001, 1982); - wiggleGeometry(envelope, 0.00000001, 511); - assertTrue(!equals.execute(envelope, point, sr, null)); - assertTrue(!contains.execute(envelope, point, sr, null)); - assertTrue(!contains.execute(point, envelope, sr, null)); - assertTrue(disjoint.execute(envelope, point, sr, null)); - assertTrue(!touches.execute(envelope, point, sr, null)); - assertTrue(!overlaps.execute(envelope, point, sr, null)); - assertTrue(!crosses.execute(envelope, point, sr, null)); - } - - { - Point point = (Point) (TestCommonMethods - .fromJson("{\"x\":0,\"y\":0}").getGeometry()); - Envelope envelope = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":0}") - .getGeometry()); - wiggleGeometry(point, 0.00000001, 1982); - wiggleGeometry(envelope, 0.00000001, 511); - assertTrue(!equals.execute(envelope, point, sr, null)); - assertTrue(!contains.execute(envelope, point, sr, null)); - assertTrue(!contains.execute(point, envelope, sr, null)); - assertTrue(!disjoint.execute(envelope, point, sr, null)); - assertTrue(touches.execute(envelope, point, sr, null)); - assertTrue(!overlaps.execute(envelope, point, sr, null)); - assertTrue(!crosses.execute(envelope, point, sr, null)); - } - - { - Point point = (Point) (TestCommonMethods - .fromJson("{\"x\":5,\"y\":0}").getGeometry()); - Envelope envelope = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":0}") - .getGeometry()); - wiggleGeometry(point, 0.00000001, 1982); - wiggleGeometry(envelope, 0.00000001, 511); - assertTrue(!equals.execute(envelope, point, sr, null)); - assertTrue(contains.execute(envelope, point, sr, null)); - assertTrue(!contains.execute(point, envelope, sr, null)); - assertTrue(!disjoint.execute(envelope, point, sr, null)); - assertTrue(!touches.execute(envelope, point, sr, null)); - assertTrue(!overlaps.execute(envelope, point, sr, null)); - assertTrue(!crosses.execute(envelope, point, sr, null)); - } - - { - Point point = (Point) (TestCommonMethods - .fromJson("{\"x\":11,\"y\":0}").getGeometry()); - Envelope envelope = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":0}") - .getGeometry()); - wiggleGeometry(point, 0.00000001, 1982); - wiggleGeometry(envelope, 0.00000001, 511); - assertTrue(!equals.execute(envelope, point, sr, null)); - assertTrue(!contains.execute(envelope, point, sr, null)); - assertTrue(!contains.execute(point, envelope, sr, null)); - assertTrue(disjoint.execute(envelope, point, sr, null)); - assertTrue(!touches.execute(envelope, point, sr, null)); - assertTrue(!overlaps.execute(envelope, point, sr, null)); - assertTrue(!crosses.execute(envelope, point, sr, null)); - } - - { - Point point = (Point) (TestCommonMethods - .fromJson("{\"x\":0,\"y\":0}").getGeometry()); - Envelope envelope = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":0,\"ymax\":0}") - .getGeometry()); - wiggleGeometry(point, 0.00000001, 1982); - wiggleGeometry(envelope, 0.00000001, 511); - assertTrue(equals.execute(envelope, point, sr, null)); - assertTrue(contains.execute(envelope, point, sr, null)); - assertTrue(contains.execute(point, envelope, sr, null)); - assertTrue(!disjoint.execute(envelope, point, sr, null)); - assertTrue(!touches.execute(envelope, point, sr, null)); - assertTrue(!overlaps.execute(envelope, point, sr, null)); - assertTrue(!crosses.execute(envelope, point, sr, null)); - } - } - - @Test - public void testEnvelopeEnvelope() { - OperatorEquals equals = (OperatorEquals) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Equals)); - OperatorContains contains = (OperatorContains) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Contains)); - OperatorDisjoint disjoint = (OperatorDisjoint) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Disjoint)); - OperatorCrosses crosses = (OperatorCrosses) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Crosses)); - @SuppressWarnings("unused") - OperatorWithin within = (OperatorWithin) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Within)); - OperatorOverlaps overlaps = (OperatorOverlaps) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Overlaps)); - OperatorTouches touches = (OperatorTouches) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Touches)); - SpatialReference sr = SpatialReference.create(4326); - - { - Envelope env1 = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":10}") - .getGeometry()); - Envelope env2 = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":10}") - .getGeometry()); - wiggleGeometry(env1, 0.00000001, 1982); - wiggleGeometry(env2, 0.00000001, 511); - assertTrue(equals.execute(env1, env2, sr, null)); - assertTrue(contains.execute(env1, env2, sr, null)); - assertTrue(contains.execute(env2, env1, sr, null)); - assertTrue(!disjoint.execute(env1, env2, sr, null)); - assertTrue(!touches.execute(env1, env2, sr, null)); - assertTrue(!touches.execute(env2, env1, sr, null)); - assertTrue(!overlaps.execute(env1, env2, sr, null)); - assertTrue(!overlaps.execute(env2, env1, sr, null)); - assertTrue(!crosses.execute(env1, env2, sr, null)); - assertTrue(!crosses.execute(env2, env1, sr, null)); - } - - { - Envelope env1 = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":5,\"ymin\":5,\"xmax\":10,\"ymax\":10}") - .getGeometry()); - Envelope env2 = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":10}") - .getGeometry()); - wiggleGeometry(env1, 0.00000001, 1982); - wiggleGeometry(env2, 0.00000001, 511); - assertTrue(!equals.execute(env1, env2, sr, null)); - assertTrue(!contains.execute(env1, env2, sr, null)); - assertTrue(contains.execute(env2, env1, sr, null)); - assertTrue(!disjoint.execute(env1, env2, sr, null)); - assertTrue(!touches.execute(env1, env2, sr, null)); - assertTrue(!overlaps.execute(env1, env2, sr, null)); - assertTrue(!overlaps.execute(env2, env1, sr, null)); - assertTrue(!crosses.execute(env1, env2, sr, null)); - assertTrue(!crosses.execute(env2, env1, sr, null)); - } - - { - Envelope env1 = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":5,\"ymin\":5,\"xmax\":15,\"ymax\":15}") - .getGeometry()); - Envelope env2 = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":10}") - .getGeometry()); - wiggleGeometry(env1, 0.00000001, 1982); - wiggleGeometry(env2, 0.00000001, 511); - assertTrue(!equals.execute(env1, env2, sr, null)); - assertTrue(!contains.execute(env1, env2, sr, null)); - assertTrue(!contains.execute(env2, env1, sr, null)); - assertTrue(!disjoint.execute(env1, env2, sr, null)); - assertTrue(!touches.execute(env1, env2, sr, null)); - assertTrue(overlaps.execute(env1, env2, sr, null)); - assertTrue(overlaps.execute(env2, env1, sr, null)); - assertTrue(!crosses.execute(env1, env2, sr, null)); - assertTrue(!crosses.execute(env2, env1, sr, null)); - } - - { - Envelope env1 = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":10,\"ymin\":0,\"xmax\":20,\"ymax\":10}") - .getGeometry()); - Envelope env2 = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":10}") - .getGeometry()); - wiggleGeometry(env1, 0.00000001, 1982); - wiggleGeometry(env2, 0.00000001, 511); - assertTrue(!equals.execute(env1, env2, sr, null)); - assertTrue(!contains.execute(env1, env2, sr, null)); - assertTrue(!contains.execute(env2, env1, sr, null)); - assertTrue(!disjoint.execute(env1, env2, sr, null)); - assertTrue(touches.execute(env1, env2, sr, null)); - assertTrue(!overlaps.execute(env1, env2, sr, null)); - assertTrue(!overlaps.execute(env2, env1, sr, null)); - assertTrue(!crosses.execute(env1, env2, sr, null)); - assertTrue(!crosses.execute(env2, env1, sr, null)); - } - - { - Envelope env1 = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":10,\"ymin\":0,\"xmax\":20,\"ymax\":10}") - .getGeometry()); - Envelope env2 = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":10}") - .getGeometry()); - wiggleGeometry(env1, 0.00000001, 1982); - wiggleGeometry(env2, 0.00000001, 511); - assertTrue(!equals.execute(env1, env2, sr, null)); - assertTrue(!contains.execute(env1, env2, sr, null)); - assertTrue(!contains.execute(env2, env1, sr, null)); - assertTrue(!disjoint.execute(env1, env2, sr, null)); - assertTrue(touches.execute(env1, env2, sr, null)); - assertTrue(!overlaps.execute(env1, env2, sr, null)); - assertTrue(!overlaps.execute(env2, env1, sr, null)); - assertTrue(!crosses.execute(env1, env2, sr, null)); - assertTrue(!crosses.execute(env2, env1, sr, null)); - } - - { - Envelope env1 = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":10,\"ymin\":0,\"xmax\":20,\"ymax\":10}") - .getGeometry()); - Envelope env2 = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":0,\"ymin\":10,\"xmax\":10,\"ymax\":20}") - .getGeometry()); - wiggleGeometry(env1, 0.00000001, 1982); - wiggleGeometry(env2, 0.00000001, 511); - assertTrue(!equals.execute(env1, env2, sr, null)); - assertTrue(!contains.execute(env1, env2, sr, null)); - assertTrue(!contains.execute(env2, env1, sr, null)); - assertTrue(!disjoint.execute(env1, env2, sr, null)); - assertTrue(touches.execute(env1, env2, sr, null)); - assertTrue(!overlaps.execute(env1, env2, sr, null)); - assertTrue(!overlaps.execute(env2, env1, sr, null)); - assertTrue(!crosses.execute(env1, env2, sr, null)); - assertTrue(!crosses.execute(env2, env1, sr, null)); - } - - { - Envelope env1 = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":10}") - .getGeometry()); - Envelope env2 = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":0}") - .getGeometry()); - wiggleGeometry(env1, 0.00000001, 1982); - wiggleGeometry(env2, 0.00000001, 511); - assertTrue(!equals.execute(env1, env2, sr, null)); - assertTrue(!contains.execute(env1, env2, sr, null)); - assertTrue(!contains.execute(env2, env1, sr, null)); - assertTrue(!disjoint.execute(env1, env2, sr, null)); - assertTrue(touches.execute(env1, env2, sr, null)); - assertTrue(!overlaps.execute(env1, env2, sr, null)); - assertTrue(!overlaps.execute(env2, env1, sr, null)); - assertTrue(!crosses.execute(env1, env2, sr, null)); - assertTrue(!crosses.execute(env2, env1, sr, null)); - } - - { - Envelope env1 = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":10}") - .getGeometry()); - Envelope env2 = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":15,\"ymax\":0}") - .getGeometry()); - wiggleGeometry(env1, 0.00000001, 1982); - wiggleGeometry(env2, 0.00000001, 511); - assertTrue(!equals.execute(env1, env2, sr, null)); - assertTrue(!contains.execute(env1, env2, sr, null)); - assertTrue(!contains.execute(env2, env1, sr, null)); - assertTrue(!disjoint.execute(env1, env2, sr, null)); - assertTrue(touches.execute(env1, env2, sr, null)); - assertTrue(!overlaps.execute(env1, env2, sr, null)); - assertTrue(!overlaps.execute(env2, env1, sr, null)); - assertTrue(!crosses.execute(env1, env2, sr, null)); - assertTrue(!crosses.execute(env2, env1, sr, null)); - } - - { - Envelope env1 = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":10}") - .getGeometry()); - Envelope env2 = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":-5,\"ymin\":5,\"xmax\":0,\"ymax\":5}") - .getGeometry()); - wiggleGeometry(env1, 0.00000001, 1982); - wiggleGeometry(env2, 0.00000001, 511); - assertTrue(!equals.execute(env1, env2, sr, null)); - assertTrue(!contains.execute(env1, env2, sr, null)); - assertTrue(!contains.execute(env2, env1, sr, null)); - assertTrue(!disjoint.execute(env1, env2, sr, null)); - assertTrue(touches.execute(env1, env2, sr, null)); - assertTrue(!overlaps.execute(env1, env2, sr, null)); - assertTrue(!overlaps.execute(env2, env1, sr, null)); - assertTrue(!crosses.execute(env1, env2, sr, null)); - assertTrue(!crosses.execute(env2, env1, sr, null)); - } - - { - Envelope env1 = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":10}") - .getGeometry()); - Envelope env2 = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":-5,\"ymin\":5,\"xmax\":5,\"ymax\":5}") - .getGeometry()); - wiggleGeometry(env1, 0.00000001, 1982); - wiggleGeometry(env2, 0.00000001, 511); - assertTrue(!equals.execute(env1, env2, sr, null)); - assertTrue(!contains.execute(env1, env2, sr, null)); - assertTrue(!contains.execute(env2, env1, sr, null)); - assertTrue(!disjoint.execute(env1, env2, sr, null)); - assertTrue(!touches.execute(env1, env2, sr, null)); - assertTrue(!overlaps.execute(env1, env2, sr, null)); - assertTrue(!overlaps.execute(env2, env1, sr, null)); - assertTrue(crosses.execute(env1, env2, sr, null)); - assertTrue(crosses.execute(env2, env1, sr, null)); - } - - { - Envelope env1 = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":10}") - .getGeometry()); - Envelope env2 = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":3,\"ymin\":5,\"xmax\":5,\"ymax\":5}") - .getGeometry()); - wiggleGeometry(env1, 0.00000001, 1982); - wiggleGeometry(env2, 0.00000001, 511); - assertTrue(!equals.execute(env1, env2, sr, null)); - assertTrue(contains.execute(env1, env2, sr, null)); - assertTrue(!contains.execute(env2, env1, sr, null)); - assertTrue(!disjoint.execute(env1, env2, sr, null)); - assertTrue(!touches.execute(env1, env2, sr, null)); - assertTrue(!overlaps.execute(env1, env2, sr, null)); - assertTrue(!overlaps.execute(env2, env1, sr, null)); - assertTrue(!crosses.execute(env1, env2, sr, null)); - assertTrue(!crosses.execute(env2, env1, sr, null)); - } - - { - Envelope env1 = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":10}") - .getGeometry()); - Envelope env2 = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":3,\"ymin\":5,\"xmax\":10,\"ymax\":5}") - .getGeometry()); - wiggleGeometry(env1, 0.00000001, 1982); - wiggleGeometry(env2, 0.00000001, 511); - assertTrue(!equals.execute(env1, env2, sr, null)); - assertTrue(contains.execute(env1, env2, sr, null)); - assertTrue(!contains.execute(env2, env1, sr, null)); - assertTrue(!disjoint.execute(env1, env2, sr, null)); - assertTrue(!touches.execute(env1, env2, sr, null)); - assertTrue(!overlaps.execute(env1, env2, sr, null)); - assertTrue(!overlaps.execute(env2, env1, sr, null)); - assertTrue(!crosses.execute(env1, env2, sr, null)); - assertTrue(!crosses.execute(env2, env1, sr, null)); - } - - { - Envelope env1 = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":10}") - .getGeometry()); - Envelope env2 = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":-5,\"ymin\":0,\"xmax\":0,\"ymax\":0}") - .getGeometry()); - wiggleGeometry(env1, 0.00000001, 1982); - wiggleGeometry(env2, 0.00000001, 511); - assertTrue(!equals.execute(env1, env2, sr, null)); - assertTrue(!contains.execute(env1, env2, sr, null)); - assertTrue(!contains.execute(env2, env1, sr, null)); - assertTrue(!disjoint.execute(env1, env2, sr, null)); - assertTrue(touches.execute(env1, env2, sr, null)); - assertTrue(!overlaps.execute(env1, env2, sr, null)); - assertTrue(!overlaps.execute(env2, env1, sr, null)); - assertTrue(!crosses.execute(env1, env2, sr, null)); - assertTrue(!crosses.execute(env2, env1, sr, null)); - } - - { - Envelope env1 = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":0}") - .getGeometry()); - Envelope env2 = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":0}") - .getGeometry()); - wiggleGeometry(env1, 0.00000001, 1982); - wiggleGeometry(env2, 0.00000001, 511); - assertTrue(equals.execute(env1, env2, sr, null)); - assertTrue(contains.execute(env1, env2, sr, null)); - assertTrue(contains.execute(env2, env1, sr, null)); - assertTrue(!disjoint.execute(env1, env2, sr, null)); - assertTrue(!touches.execute(env1, env2, sr, null)); - assertTrue(!overlaps.execute(env1, env2, sr, null)); - assertTrue(!overlaps.execute(env2, env1, sr, null)); - assertTrue(!crosses.execute(env1, env2, sr, null)); - assertTrue(!crosses.execute(env2, env1, sr, null)); - } - - { - Envelope env1 = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":15,\"ymax\":0}") - .getGeometry()); - Envelope env2 = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":0}") - .getGeometry()); - wiggleGeometry(env1, 0.00000001, 1982); - wiggleGeometry(env2, 0.00000001, 511); - assertTrue(!equals.execute(env1, env2, sr, null)); - assertTrue(contains.execute(env1, env2, sr, null)); - assertTrue(!contains.execute(env2, env1, sr, null)); - assertTrue(!disjoint.execute(env1, env2, sr, null)); - assertTrue(!touches.execute(env1, env2, sr, null)); - assertTrue(!overlaps.execute(env1, env2, sr, null)); - assertTrue(!overlaps.execute(env2, env1, sr, null)); - assertTrue(!crosses.execute(env1, env2, sr, null)); - assertTrue(!crosses.execute(env2, env1, sr, null)); - } - - { - Envelope env1 = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":15,\"ymax\":0}") - .getGeometry()); - Envelope env2 = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":-5,\"ymin\":0,\"xmax\":10,\"ymax\":0}") - .getGeometry()); - wiggleGeometry(env1, 0.00000001, 1982); - wiggleGeometry(env2, 0.00000001, 511); - assertTrue(!equals.execute(env1, env2, sr, null)); - assertTrue(!contains.execute(env1, env2, sr, null)); - assertTrue(!contains.execute(env2, env1, sr, null)); - assertTrue(!disjoint.execute(env1, env2, sr, null)); - assertTrue(!touches.execute(env1, env2, sr, null)); - assertTrue(overlaps.execute(env1, env2, sr, null)); - assertTrue(overlaps.execute(env2, env1, sr, null)); - assertTrue(!crosses.execute(env1, env2, sr, null)); - assertTrue(!crosses.execute(env2, env1, sr, null)); - } - - { - Envelope env1 = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":5,\"ymax\":0}") - .getGeometry()); - Envelope env2 = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":-5,\"ymin\":0,\"xmax\":0,\"ymax\":0}") - .getGeometry()); - wiggleGeometry(env1, 0.00000001, 1982); - wiggleGeometry(env2, 0.00000001, 511); - assertTrue(!equals.execute(env1, env2, sr, null)); - assertTrue(!contains.execute(env1, env2, sr, null)); - assertTrue(!contains.execute(env2, env1, sr, null)); - assertTrue(!disjoint.execute(env1, env2, sr, null)); - assertTrue(touches.execute(env1, env2, sr, null)); - assertTrue(!overlaps.execute(env1, env2, sr, null)); - assertTrue(!overlaps.execute(env2, env1, sr, null)); - assertTrue(!crosses.execute(env1, env2, sr, null)); - assertTrue(!crosses.execute(env2, env1, sr, null)); - } - - { - Envelope env1 = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":0}") - .getGeometry()); - Envelope env2 = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":5,\"ymin\":-5,\"xmax\":5,\"ymax\":5}") - .getGeometry()); - wiggleGeometry(env1, 0.00000001, 1982); - wiggleGeometry(env2, 0.00000001, 511); - assertTrue(!equals.execute(env1, env2, sr, null)); - assertTrue(!contains.execute(env1, env2, sr, null)); - assertTrue(!contains.execute(env2, env1, sr, null)); - assertTrue(!disjoint.execute(env1, env2, sr, null)); - assertTrue(!touches.execute(env1, env2, sr, null)); - assertTrue(!overlaps.execute(env1, env2, sr, null)); - assertTrue(!overlaps.execute(env2, env1, sr, null)); - assertTrue(crosses.execute(env1, env2, sr, null)); - assertTrue(crosses.execute(env2, env1, sr, null)); - } - - { - Envelope env1 = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":0}") - .getGeometry()); - Envelope env2 = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":10,\"ymin\":0,\"xmax\":20,\"ymax\":0}") - .getGeometry()); - wiggleGeometry(env1, 0.00000001, 1982); - wiggleGeometry(env2, 0.00000001, 511); - assertTrue(!equals.execute(env1, env2, sr, null)); - assertTrue(!contains.execute(env1, env2, sr, null)); - assertTrue(!contains.execute(env2, env1, sr, null)); - assertTrue(!disjoint.execute(env1, env2, sr, null)); - assertTrue(touches.execute(env1, env2, sr, null)); - assertTrue(!overlaps.execute(env1, env2, sr, null)); - assertTrue(!overlaps.execute(env2, env1, sr, null)); - assertTrue(!crosses.execute(env1, env2, sr, null)); - assertTrue(!crosses.execute(env2, env1, sr, null)); - } - - { - Envelope env1 = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":0}") - .getGeometry()); - Envelope env2 = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":5,\"ymin\":0,\"xmax\":5,\"ymax\":5}") - .getGeometry()); - wiggleGeometry(env1, 0.00000001, 1982); - wiggleGeometry(env2, 0.00000001, 511); - assertTrue(!equals.execute(env1, env2, sr, null)); - assertTrue(!contains.execute(env1, env2, sr, null)); - assertTrue(!contains.execute(env2, env1, sr, null)); - assertTrue(!disjoint.execute(env1, env2, sr, null)); - assertTrue(touches.execute(env1, env2, sr, null)); - assertTrue(touches.execute(env2, env1, sr, null)); - assertTrue(!overlaps.execute(env1, env2, sr, null)); - assertTrue(!overlaps.execute(env2, env1, sr, null)); - assertTrue(!crosses.execute(env1, env2, sr, null)); - assertTrue(!crosses.execute(env2, env1, sr, null)); - } - - { - Envelope env1 = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":0,\"ymax\":0}") - .getGeometry()); - Envelope env2 = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":10}") - .getGeometry()); - wiggleGeometry(env1, 0.00000001, 1982); - wiggleGeometry(env2, 0.00000001, 511); - assertTrue(!equals.execute(env1, env2, sr, null)); - assertTrue(!contains.execute(env1, env2, sr, null)); - assertTrue(!contains.execute(env2, env1, sr, null)); - assertTrue(!disjoint.execute(env1, env2, sr, null)); - assertTrue(touches.execute(env1, env2, sr, null)); - assertTrue(touches.execute(env2, env1, sr, null)); - assertTrue(!overlaps.execute(env1, env2, sr, null)); - assertTrue(!overlaps.execute(env2, env1, sr, null)); - assertTrue(!crosses.execute(env1, env2, sr, null)); - assertTrue(!crosses.execute(env2, env1, sr, null)); - } - - { - Envelope env1 = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":5,\"ymin\":0,\"xmax\":5,\"ymax\":0}") - .getGeometry()); - Envelope env2 = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":10}") - .getGeometry()); - wiggleGeometry(env1, 0.00000001, 1982); - wiggleGeometry(env2, 0.00000001, 511); - assertTrue(!equals.execute(env1, env2, sr, null)); - assertTrue(!contains.execute(env1, env2, sr, null)); - assertTrue(!contains.execute(env2, env1, sr, null)); - assertTrue(!disjoint.execute(env1, env2, sr, null)); - assertTrue(touches.execute(env1, env2, sr, null)); - assertTrue(touches.execute(env2, env1, sr, null)); - assertTrue(!overlaps.execute(env1, env2, sr, null)); - assertTrue(!overlaps.execute(env2, env1, sr, null)); - assertTrue(!crosses.execute(env1, env2, sr, null)); - assertTrue(!crosses.execute(env2, env1, sr, null)); - } - - { - Envelope env1 = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":5,\"ymin\":5,\"xmax\":5,\"ymax\":5}") - .getGeometry()); - Envelope env2 = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":10}") - .getGeometry()); - wiggleGeometry(env1, 0.00000001, 1982); - wiggleGeometry(env2, 0.00000001, 511); - assertTrue(!equals.execute(env1, env2, sr, null)); - assertTrue(!contains.execute(env1, env2, sr, null)); - assertTrue(contains.execute(env2, env1, sr, null)); - assertTrue(!disjoint.execute(env1, env2, sr, null)); - assertTrue(!touches.execute(env1, env2, sr, null)); - assertTrue(!touches.execute(env2, env1, sr, null)); - assertTrue(!overlaps.execute(env1, env2, sr, null)); - assertTrue(!overlaps.execute(env2, env1, sr, null)); - assertTrue(!crosses.execute(env1, env2, sr, null)); - assertTrue(!crosses.execute(env2, env1, sr, null)); - } - - { - Envelope env1 = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":0,\"ymax\":0}") - .getGeometry()); - Envelope env2 = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":0}") - .getGeometry()); - wiggleGeometry(env1, 0.00000001, 1982); - wiggleGeometry(env2, 0.00000001, 511); - assertTrue(!equals.execute(env1, env2, sr, null)); - assertTrue(!contains.execute(env1, env2, sr, null)); - assertTrue(!contains.execute(env2, env1, sr, null)); - assertTrue(!disjoint.execute(env1, env2, sr, null)); - assertTrue(touches.execute(env1, env2, sr, null)); - assertTrue(touches.execute(env2, env1, sr, null)); - assertTrue(!overlaps.execute(env1, env2, sr, null)); - assertTrue(!overlaps.execute(env2, env1, sr, null)); - assertTrue(!crosses.execute(env1, env2, sr, null)); - assertTrue(!crosses.execute(env2, env1, sr, null)); - } - - { - Envelope env1 = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":5,\"ymin\":0,\"xmax\":5,\"ymax\":0}") - .getGeometry()); - Envelope env2 = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":0}") - .getGeometry()); - wiggleGeometry(env1, 0.00000001, 1982); - wiggleGeometry(env2, 0.00000001, 511); - assertTrue(!equals.execute(env1, env2, sr, null)); - assertTrue(!contains.execute(env1, env2, sr, null)); - assertTrue(contains.execute(env2, env1, sr, null)); - assertTrue(!disjoint.execute(env1, env2, sr, null)); - assertTrue(!touches.execute(env1, env2, sr, null)); - assertTrue(!touches.execute(env2, env1, sr, null)); - assertTrue(!overlaps.execute(env1, env2, sr, null)); - assertTrue(!overlaps.execute(env2, env1, sr, null)); - assertTrue(!crosses.execute(env1, env2, sr, null)); - assertTrue(!crosses.execute(env2, env1, sr, null)); - } - - { - Envelope env1 = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":5,\"ymin\":0,\"xmax\":5,\"ymax\":0}") - .getGeometry()); - Envelope env2 = (Envelope) (TestCommonMethods - .fromJson("{\"xmin\":5,\"ymin\":0,\"xmax\":5,\"ymax\":0}") - .getGeometry()); - wiggleGeometry(env1, 0.00000001, 1982); - wiggleGeometry(env2, 0.00000001, 511); - assertTrue(equals.execute(env1, env2, sr, null)); - assertTrue(contains.execute(env1, env2, sr, null)); - assertTrue(contains.execute(env2, env1, sr, null)); - assertTrue(!disjoint.execute(env1, env2, sr, null)); - assertTrue(!touches.execute(env1, env2, sr, null)); - assertTrue(!touches.execute(env2, env1, sr, null)); - assertTrue(!overlaps.execute(env1, env2, sr, null)); - assertTrue(!overlaps.execute(env2, env1, sr, null)); - assertTrue(!crosses.execute(env1, env2, sr, null)); - assertTrue(!crosses.execute(env2, env1, sr, null)); - } - } - - static void wiggleGeometry(Geometry geometry, double tolerance, int rand) { - int type = geometry.getType().value(); - - if (type == Geometry.GeometryType.Polygon - || type == Geometry.GeometryType.Polyline - || type == Geometry.GeometryType.MultiPoint) { - MultiVertexGeometry mvGeom = (MultiVertexGeometry) geometry; - for (int i = 0; i < mvGeom.getPointCount(); i++) { - Point2D pt = mvGeom.getXY(i); - - // create random vector and normalize it to 0.49 * tolerance - Point2D randomV = new Point2D(); - rand = NumberUtils.nextRand(rand); - randomV.x = 1.0 * rand / NumberUtils.intMax() - 0.5; - rand = NumberUtils.nextRand(rand); - randomV.y = 1.0 * rand / NumberUtils.intMax() - 0.5; - randomV.normalize(); - randomV.scale(0.45 * tolerance); - pt.add(randomV); - mvGeom.setXY(i, pt); - } - } else if (type == Geometry.GeometryType.Point) { - Point ptGeom = (Point) (geometry); - Point2D pt = ptGeom.getXY(); - // create random vector and normalize it to 0.49 * tolerance - Point2D randomV = new Point2D(); - rand = NumberUtils.nextRand(rand); - randomV.x = 1.0 * rand / NumberUtils.intMax() - 0.5; - rand = NumberUtils.nextRand(rand); - randomV.y = 1.0 * rand / NumberUtils.intMax() - 0.5; - randomV.normalize(); - randomV.scale(0.45 * tolerance); - pt.add(randomV); - ptGeom.setXY(pt); - } else if (type == Geometry.GeometryType.Envelope) { - Envelope envGeom = (Envelope) (geometry); - Envelope2D env = new Envelope2D(); - envGeom.queryEnvelope2D(env); - double xmin, xmax, ymin, ymax; - Point2D pt = new Point2D(); - env.queryLowerLeft(pt); - // create random vector and normalize it to 0.49 * tolerance - Point2D randomV = new Point2D(); - rand = NumberUtils.nextRand(rand); - randomV.x = 1.0 * rand / NumberUtils.intMax() - 0.5; - rand = NumberUtils.nextRand(rand); - randomV.y = 1.0 * rand / NumberUtils.intMax() - 0.5; - randomV.normalize(); - randomV.scale(0.45 * tolerance); - xmin = (pt.x + randomV.x); - ymin = (pt.y + randomV.y); - - env.queryUpperRight(pt); - // create random vector and normalize it to 0.49 * tolerance - rand = NumberUtils.nextRand(rand); - randomV.x = 1.0 * rand / NumberUtils.intMax() - 0.5; - rand = NumberUtils.nextRand(rand); - randomV.y = 1.0 * rand / NumberUtils.intMax() - 0.5; - randomV.normalize(); - randomV.scale(0.45 * tolerance); - xmax = (pt.x + randomV.x); - ymax = (pt.y + randomV.y); - - if (xmin > xmax) { - double swap = xmin; - xmin = xmax; - xmax = swap; - } - - if (ymin > ymax) { - double swap = ymin; - ymin = ymax; - ymax = swap; - } - - envGeom.setCoords(xmin, ymin, xmax, ymax); - } - - } - - @Test - public void testDisjointRelationFalse() { - { - OperatorDisjoint op = (OperatorDisjoint) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Disjoint)); - Envelope env1 = new Envelope(50, 50, 150, 150); - Envelope env2 = new Envelope(25, 25, 175, 175); - boolean result = op.execute(env1, env2, - SpatialReference.create(4326), null); - assertTrue(!result); - } - { - OperatorIntersects op = (OperatorIntersects) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Intersects)); - Envelope env1 = new Envelope(50, 50, 150, 150); - Envelope env2 = new Envelope(25, 25, 175, 175); - boolean result = op.execute(env1, env2, - SpatialReference.create(4326), null); - assertTrue(result); - } - { - OperatorContains op = (OperatorContains) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Contains)); - Envelope env1 = new Envelope(100, 175, 200, 225); - Polyline polyline = new Polyline(); - polyline.startPath(200, 175); - polyline.lineTo(200, 225); - polyline.lineTo(125, 200); - boolean result = op.execute(env1, polyline, - SpatialReference.create(4326), null); - assertTrue(result); - } - { - OperatorTouches op = (OperatorTouches) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Touches)); - Envelope env1 = new Envelope(100, 200, 400, 400); - Polyline polyline = new Polyline(); - polyline.startPath(300, 60); - polyline.lineTo(300, 200); - polyline.lineTo(400, 50); - boolean result = op.execute(env1, polyline, - SpatialReference.create(4326), null); - assertTrue(result); - } - - { - OperatorTouches op = (OperatorTouches) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Touches)); - Envelope env1 = new Envelope(50, 50, 150, 150); - Polyline polyline = new Polyline(); - polyline.startPath(100, 20); - polyline.lineTo(100, 50); - polyline.lineTo(150, 10); - boolean result = op.execute(polyline, env1, - SpatialReference.create(4326), null); - assertTrue(result); - } - - { - OperatorDisjoint op = (OperatorDisjoint) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Disjoint)); - Polygon polygon = new Polygon(); - Polyline polyline = new Polyline(); - polygon.startPath(0, 0); - polygon.lineTo(0, 10); - polygon.lineTo(10, 10); - polygon.lineTo(10, 0); - polyline.startPath(-5, 4); - polyline.lineTo(5, -6); - boolean result = op.execute(polyline, polygon, - SpatialReference.create(4326), null); - assertTrue(result); - } - } - - @Test - public void testPolylinePolylineRelate() { - OperatorRelate op = OperatorRelate.local(); - SpatialReference sr = SpatialReference.create(4326); - boolean res; - String scl; - - Polyline polyline1 = new Polyline(); - Polyline polyline2 = new Polyline(); - - polyline1.startPath(0, 0); - polyline1.lineTo(1, 1); - - polyline2.startPath(1, 1); - polyline2.lineTo(2, 0); - - scl = "FF1FT01T2"; - res = op.execute(polyline1, polyline2, sr, scl, null); - assertTrue(res); - - scl = "****TF*T*"; - res = op.execute(polyline1, polyline2, sr, scl, null); - assertTrue(!res); - - scl = "****F****"; - res = op.execute(polyline1, polyline2, sr, scl, null); - assertTrue(!res); - - scl = "**1*0*T**"; - res = op.execute(polyline1, polyline2, sr, scl, null); - assertTrue(res); - - scl = "****1****"; - res = op.execute(polyline1, polyline2, sr, scl, null); - assertTrue(!res); - - scl = "**T*001*T"; - res = op.execute(polyline1, polyline2, sr, scl, null); - assertTrue(res); - - scl = "T********"; - res = op.execute(polyline1, polyline2, sr, scl, null); - assertTrue(!res); - - scl = "F********"; - res = op.execute(polyline1, polyline2, sr, scl, null); - assertTrue(res); - - polyline1.setEmpty(); - polyline2.setEmpty(); - - polyline1.startPath(0, 0); - polyline1.lineTo(1, 0); - - polyline2.startPath(0, 0); - polyline2.lineTo(1, 0); - - scl = "1FFFTFFFT"; - res = op.execute(polyline1, polyline2, sr, scl, null); - assertTrue(res); - - scl = "1*T*T****"; - res = op.execute(polyline1, polyline2, sr, scl, null); - assertTrue(!res); - - scl = "1T**T****"; - res = op.execute(polyline1, polyline2, sr, scl, null); - assertTrue(!res); - - polyline1.setEmpty(); - polyline2.setEmpty(); - - polyline1.startPath(0, 0); - polyline1.lineTo(0.5, 0.5); - polyline1.lineTo(1, 1); - - polyline2.startPath(1, 0); - polyline2.lineTo(0.5, 0.5); - polyline2.lineTo(0, 1); - - scl = "0F1FFTT0T"; - res = op.execute(polyline1, polyline2, sr, scl, null); - assertTrue(res); - - scl = "*T*******"; - res = op.execute(polyline1, polyline2, sr, scl, null); - assertTrue(!res); - - scl = "*F*F*****"; - res = op.execute(polyline1, polyline2, sr, scl, null); - assertTrue(res); - - polyline1.setEmpty(); - polyline2.setEmpty(); - - polyline1.startPath(0, 0); - polyline1.lineTo(1, 0); + } + { + OperatorWithin operatorWithin = (OperatorWithin) (projEnv + .getOperator(Operator.Type.Within)); + boolean result = operatorWithin.execute(poly1, poly2, inputSR, + null); + assertTrue(result); + } + + { + OperatorDisjoint operatorDisjoint = (OperatorDisjoint) (projEnv + .getOperator(Operator.Type.Disjoint)); + OperatorIntersects operatorIntersects = (OperatorIntersects) (projEnv + .getOperator(Operator.Type.Intersects)); + boolean result = operatorDisjoint.execute(poly1, poly2, + inputSR, null); + assertTrue(!result); + { + result = operatorIntersects.execute(poly1, poly2, inputSR, + null); + assertTrue(result); + } + } + + { + OperatorDisjoint operatorDisjoint = (OperatorDisjoint) (projEnv + .getOperator(Operator.Type.Disjoint)); + OperatorIntersects operatorIntersects = (OperatorIntersects) (projEnv + .getOperator(Operator.Type.Intersects)); + Envelope2D env2D = new Envelope2D(); + poly2.queryEnvelope2D(env2D); + Envelope envelope = new Envelope(env2D); + boolean result = operatorDisjoint.execute(envelope, poly2, + inputSR, null); + assertTrue(!result); + { + result = operatorIntersects.execute(envelope, poly2, + inputSR, null); + assertTrue(result); + } + } + + { + OperatorDisjoint operatorDisjoint = (OperatorDisjoint) (projEnv + .getOperator(Operator.Type.Disjoint)); + OperatorIntersects operatorIntersects = (OperatorIntersects) (projEnv + .getOperator(Operator.Type.Intersects)); + Polygon poly = new Polygon(); + + Envelope2D env2D = new Envelope2D(); + env2D.setCoords(855277, 3892059, 855277 + 100, 3892059 + 100); + poly.addEnvelope(env2D, false); + env2D.setCoords(855277 + 10, 3892059 + 10, 855277 + 90, + 3892059 + 90); + poly.addEnvelope(env2D, true); + + env2D.setCoords(855277 + 20, 3892059 + 20, 855277 + 200, + 3892059 + 80); + Envelope envelope = new Envelope(env2D); + boolean result = operatorDisjoint.execute(envelope, poly, + inputSR, null); + assertTrue(!result); + { + result = operatorIntersects.execute(envelope, poly, + inputSR, null); + assertTrue(result); + } + } + + { + OperatorTouches operatorTouches = (OperatorTouches) (projEnv + .getOperator(Operator.Type.Touches)); + boolean result = operatorTouches.execute(poly1, poly2, inputSR, + null); + assertTrue(!result); + } + + } + } + + @Test + public void testOperatorDisjoint() { + { + OperatorFactoryLocal projEnv = OperatorFactoryLocal.getInstance(); + SpatialReference inputSR = SpatialReference.create(3857); + + Polygon poly1 = new Polygon(); + Envelope2D env1 = new Envelope2D(); + env1.setCoords(855277, 3892059, 855277 + 100, 3892059 + 100); + poly1.addEnvelope(env1, false); + + Polygon poly2 = new Polygon(); + Envelope2D env2 = new Envelope2D(); + env2.setCoords(855277, 3892059, 855277 + 300, 3892059 + 200); + poly2.addEnvelope(env2, false); + + Polygon poly3 = new Polygon(); + Envelope2D env3 = new Envelope2D(); + env3.setCoords(855277 + 100, 3892059 + 100, 855277 + 100 + 100, + 3892059 + 100 + 100); + poly3.addEnvelope(env3, false); + + Polygon poly4 = new Polygon(); + Envelope2D env4 = new Envelope2D(); + env4.setCoords(855277 + 200, 3892059 + 200, 855277 + 200 + 100, + 3892059 + 200 + 100); + poly4.addEnvelope(env4, false); + + Point point1 = new Point(855277, 3892059); + Point point2 = new Point(855277 + 2, 3892059 + 3); + Point point3 = new Point(855277 - 2, 3892059 - 3); + + { + OperatorDisjoint operatorDisjoint = (OperatorDisjoint) (projEnv + .getOperator(Operator.Type.Disjoint)); + boolean result = operatorDisjoint.execute(poly1, poly2, + inputSR, null); + assertTrue(!result); + result = operatorDisjoint.execute(poly1, poly3, inputSR, null); + assertTrue(!result); + result = operatorDisjoint.execute(poly1, poly4, inputSR, null); + assertTrue(result); + + result = operatorDisjoint.execute(poly1, point1, inputSR, null); + assertTrue(!result); + result = operatorDisjoint.execute(point1, poly1, inputSR, null); + assertTrue(!result); + result = operatorDisjoint.execute(poly1, point2, inputSR, null); + assertTrue(!result); + result = operatorDisjoint.execute(point2, poly1, inputSR, null); + assertTrue(!result); + result = operatorDisjoint.execute(poly1, point3, inputSR, null); + assertTrue(result); + result = operatorDisjoint.execute(point3, poly1, inputSR, null); + assertTrue(result); + } + } + } + + @Test + public void testTouchPointLineCR183227() {// Tests CR 183227 + OperatorTouches operatorTouches = (OperatorTouches) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Touches)); + + Geometry baseGeom = new Point(-130, 10); + Polyline pl = new Polyline(); + // pl.startPath(std::make_shared(-130, 10)); + pl.startPath(-130, 10); + pl.lineTo(-131, 15); + pl.lineTo(-140, 20); + + SpatialReference sr = SpatialReference.create(4326); + + boolean isTouched; + boolean isTouched2; + isTouched = operatorTouches.execute(baseGeom, pl, sr, null); + isTouched2 = operatorTouches.execute(pl, baseGeom, sr, null); + assertTrue(isTouched && isTouched2); + + { + baseGeom = new Point(-131, 15); + isTouched = operatorTouches.execute(baseGeom, pl, sr, null); + isTouched2 = operatorTouches.execute(pl, baseGeom, sr, null); + assertTrue(!isTouched && !isTouched2); + } + } + + @Test + public void testTouchPointLineClosed() {// Tests CR 183227 + OperatorTouches operatorTouches = (OperatorTouches) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Touches)); + + Geometry baseGeom = new Point(-130, 10); + Polyline pl = new Polyline(); + pl.startPath(-130, 10); + pl.lineTo(-131, 15); + pl.lineTo(-140, 20); + pl.lineTo(-130, 10); + + SpatialReference sr = SpatialReference.create(4326); + + boolean isTouched; + boolean isTouched2; + isTouched = operatorTouches.execute(baseGeom, pl, sr, null); + isTouched2 = operatorTouches.execute(pl, baseGeom, sr, null); + assertTrue(!isTouched && !isTouched2);// this may change in future + + { + baseGeom = new Point(-131, 15); + isTouched = operatorTouches.execute(baseGeom, pl, sr, null); + isTouched2 = operatorTouches.execute(pl, baseGeom, sr, null); + assertTrue(!isTouched && !isTouched2); + } + } + + @Test + public void testTouchPolygonPolygon() { + OperatorTouches operatorTouches = (OperatorTouches) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Touches)); + + Polygon pg = new Polygon(); + pg.startPath(-130, 10); + pg.lineTo(-131, 15); + pg.lineTo(-140, 20); + + Polygon pg2 = new Polygon(); + pg2.startPath(-130, 10); + pg2.lineTo(-131, 15); + pg2.lineTo(-120, 20); + SpatialReference sr = SpatialReference.create(4326); + + boolean isTouched; + boolean isTouched2; + isTouched = operatorTouches.execute(pg, pg2, sr, null); + isTouched2 = operatorTouches.execute(pg2, pg, sr, null); + assertTrue(isTouched && isTouched2); + } + + @Test + public void testContainsFailureCR186456() { + { + OperatorContains op = (OperatorContains) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Contains)); + String str = "{\"rings\":[[[406944.399999999,287461.450000001],[406947.750000011,287462.299999997],[406946.44999999,287467.450000001],[406943.050000005,287466.550000005],[406927.799999992,287456.849999994],[406926.949999996,287456.599999995],[406924.800000005,287455.999999998],[406924.300000007,287455.849999999],[406924.200000008,287456.099999997],[406923.450000011,287458.449999987],[406922.999999987,287459.800000008],[406922.29999999,287462.099999998],[406921.949999991,287463.449999992],[406921.449999993,287465.050000011],[406920.749999996,287466.700000004],[406919.800000001,287468.599999996],[406919.050000004,287469.99999999],[406917.800000009,287471.800000008],[406916.04999999,287473.550000001],[406915.449999993,287473.999999999],[406913.700000001,287475.449999993],[406913.300000002,287475.899999991],[406912.050000008,287477.250000011],[406913.450000002,287478.150000007],[406915.199999994,287478.650000005],[406915.999999991,287478.800000005],[406918.300000007,287479.200000003],[406920.649999997,287479.450000002],[406923.100000013,287479.550000001],[406925.750000001,287479.450000002],[406928.39999999,287479.150000003],[406929.80000001,287478.950000004],[406932.449999998,287478.350000006],[406935.099999987,287477.60000001],[406938.699999998,287476.349999989],[406939.649999994,287473.949999999],[406939.799999993,287473.949999999],[406941.249999987,287473.75],[406942.700000007,287473.250000002],[406943.100000005,287473.100000003],[406943.950000001,287472.750000004],[406944.799999998,287472.300000006],[406944.999999997,287472.200000007],[406946.099999992,287471.200000011],[406946.299999991,287470.950000012],[406948.00000001,287468.599999996],[406948.10000001,287468.399999997],[406950.100000001,287465.050000011],[406951.949999993,287461.450000001],[406952.049999993,287461.300000001],[406952.69999999,287459.900000007],[406953.249999987,287458.549999987],[406953.349999987,287458.299999988],[406953.650000012,287457.299999992],[406953.900000011,287456.349999996],[406954.00000001,287455.300000001],[406954.00000001,287454.750000003],[406953.850000011,287453.750000008],[406953.550000012,287452.900000011],[406953.299999987,287452.299999988],[406954.500000008,287450.299999996],[406954.00000001,287449.000000002],[406953.399999987,287447.950000006],[406953.199999988,287447.550000008],[406952.69999999,287446.850000011],[406952.149999992,287446.099999988],[406951.499999995,287445.499999991],[406951.149999996,287445.249999992],[406950.449999999,287444.849999994],[406949.600000003,287444.599999995],[406949.350000004,287444.549999995],[406948.250000009,287444.499999995],[406947.149999987,287444.699999994],[406946.849999989,287444.749999994],[406945.899999993,287444.949999993],[406944.999999997,287445.349999991],[406944.499999999,287445.64999999],[406943.650000003,287446.349999987],[406942.900000006,287447.10000001],[406942.500000008,287447.800000007],[406942.00000001,287448.700000003],[406941.600000011,287449.599999999],[406941.350000013,287450.849999994],[406941.350000013,287451.84999999],[406941.450000012,287452.850000012],[406941.750000011,287453.850000007],[406941.800000011,287454.000000007],[406942.150000009,287454.850000003],[406942.650000007,287455.6],[406943.150000005,287456.299999997],[406944.499999999,287457.299999992],[406944.899999997,287457.599999991],[406945.299999995,287457.949999989],[406944.399999999,287461.450000001],[406941.750000011,287461.999999998],[406944.399999999,287461.450000001]],[[406944.399999999,287461.450000001],[406947.750000011,287462.299999997],[406946.44999999,287467.450000001],[406943.050000005,287466.550000005],[406927.799999992,287456.849999994],[406944.399999999,287461.450000001]]]}"; + MapGeometry mg = TestCommonMethods.fromJson(str); + boolean res = op.execute((mg.getGeometry()), (mg.getGeometry()), + null, null); + assertTrue(res); + } + } + + @Test + public void testWithin() { + { + OperatorWithin op = (OperatorWithin) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Within)); + String str1 = "{\"rings\":[[[0,0],[0,200],[200,200],[200,0],[0,0],[0,0],[0,0]]]}"; + MapGeometry mg1 = TestCommonMethods.fromJson(str1); + String str2 = "{\"x\":100,\"y\":100}"; + MapGeometry mg2 = TestCommonMethods.fromJson(str2); + + boolean res = op.execute((mg2.getGeometry()), (mg1.getGeometry()), + null, null); + assertTrue(res); + res = op.execute((mg1.getGeometry()), (mg2.getGeometry()), null, + null); + assertTrue(!res); + + } + + {// polygon + OperatorWithin op = (OperatorWithin) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Within)); + String str1 = "{\"rings\":[[[0,0],[0,200],[200,200],[200,0],[100,0]]]}"; + MapGeometry mg1 = TestCommonMethods.fromJson(str1); + String str2 = "{\"rings\":[[[10,10],[10,100],[100,100],[100,10]]]}"; + MapGeometry mg2 = TestCommonMethods.fromJson(str2); + + boolean res = op.execute((mg2.getGeometry()), (mg1.getGeometry()), + null, null); + assertTrue(res); + res = op.execute((mg1.getGeometry()), (mg2.getGeometry()), null, + null); + assertTrue(!res); + } + + {// Multi_point + OperatorWithin op = (OperatorWithin) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Within)); + String str1 = "{\"points\":[[0,0],[0,200],[200,200]]}"; + MapGeometry mg1 = TestCommonMethods.fromJson(str1); + String str2 = "{\"points\":[[0,0],[0,200]]}"; + MapGeometry mg2 = TestCommonMethods.fromJson(str2); + boolean res = op.execute((mg2.getGeometry()), (mg1.getGeometry()), + null, null); + assertTrue(res); + res = op.execute((mg1.getGeometry()), (mg2.getGeometry()), null, + null); + assertTrue(!res); + } + + {// Multi_point + OperatorWithin op = (OperatorWithin) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Within)); + String str1 = "{\"points\":[[0,0],[0,200]]}"; + MapGeometry mg1 = TestCommonMethods.fromJson(str1); + String str2 = "{\"points\":[[0,0],[0,200]]}"; + MapGeometry mg2 = TestCommonMethods.fromJson(str2); + boolean res = op.execute((mg2.getGeometry()), (mg1.getGeometry()), + null, null); + assertTrue(res); + res = op.execute((mg1.getGeometry()), (mg2.getGeometry()), null, + null); + assertTrue(res); + } + + {// Multi_point + OperatorWithin op = (OperatorWithin) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Within)); + String str1 = "{\"points\":[[0,0],[0,200],[200,200]]}"; + MapGeometry mg1 = TestCommonMethods.fromJson(str1); + String str2 = "{\"points\":[[0,0],[0,200], [1, 1]]}"; + MapGeometry mg2 = TestCommonMethods.fromJson(str2); + boolean res = op.execute((mg2.getGeometry()), (mg1.getGeometry()), + null, null); + assertTrue(!res); + res = op.execute((mg1.getGeometry()), (mg2.getGeometry()), null, + null); + assertTrue(!res); + } + } + + @Test + public void testContains() { + { + OperatorContains op = (OperatorContains) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Contains)); + String str1 = "{\"rings\":[[[0,0],[0,200],[200,200],[200,0],[0,0],[0,0],[0,0]]]}"; + MapGeometry mg1 = TestCommonMethods.fromJson(str1); + String str2 = "{\"x\":100,\"y\":100}"; + MapGeometry mg2 = TestCommonMethods.fromJson(str2); + + boolean res = op.execute((mg2.getGeometry()), (mg1.getGeometry()), + null, null); + assertTrue(!res); + res = op.execute((mg1.getGeometry()), (mg2.getGeometry()), null, + null); + assertTrue(res); + } + + {// polygon + OperatorContains op = (OperatorContains) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Contains)); + String str1 = "{\"rings\":[[[0,0],[0,200],[200,200],[200,0],[0,0]]]}"; + MapGeometry mg1 = TestCommonMethods.fromJson(str1); + String str2 = "{\"rings\":[[[10,10],[10,100],[100,100],[10,10]]]}"; + MapGeometry mg2 = TestCommonMethods.fromJson(str2); + + boolean res = op.execute((mg2.getGeometry()), (mg1.getGeometry()), + null, null); + assertTrue(!res); + res = op.execute((mg1.getGeometry()), (mg2.getGeometry()), null, + null); + assertTrue(res); + } + + {// Multi_point + OperatorContains op = (OperatorContains) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Contains)); + String str1 = "{\"points\":[[0,0],[0,200],[200,200]]}"; + MapGeometry mg1 = TestCommonMethods.fromJson(str1); + String str2 = "{\"points\":[[0,0],[0,200]]}"; + MapGeometry mg2 = TestCommonMethods.fromJson(str2); + boolean res = op.execute((mg2.getGeometry()), (mg1.getGeometry()), + null, null); + assertTrue(!res); + res = op.execute((mg1.getGeometry()), (mg2.getGeometry()), null, + null); + assertTrue(res); + } + + {// Multi_point + OperatorContains op = (OperatorContains) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Contains)); + String str1 = "{\"points\":[[0,0],[0,200]]}"; + MapGeometry mg1 = TestCommonMethods.fromJson(str1); + String str2 = "{\"points\":[[0,0],[0,200]]}"; + MapGeometry mg2 = TestCommonMethods.fromJson(str2); + boolean res = op.execute((mg2.getGeometry()), (mg1.getGeometry()), + null, null); + assertTrue(res); + res = op.execute((mg1.getGeometry()), (mg2.getGeometry()), null, + null); + assertTrue(res); + } + + {// Multi_point + OperatorContains op = (OperatorContains) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Contains)); + String str1 = "{\"points\":[[0,0],[0,200],[200,200]]}"; + MapGeometry mg1 = TestCommonMethods.fromJson(str1); + String str2 = "{\"points\":[[0,0],[0,200], [1, 1]]}"; + MapGeometry mg2 = TestCommonMethods.fromJson(str2); + boolean res = op.execute((mg2.getGeometry()), (mg1.getGeometry()), + null, null); + assertTrue(!res); + res = op.execute((mg1.getGeometry()), (mg2.getGeometry()), null, + null); + assertTrue(!res); + } + } + + @Test + public void testOverlaps() { + {// empty polygon + OperatorOverlaps op = (OperatorOverlaps) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Overlaps)); + Polygon poly1 = new Polygon(); + Polygon poly2 = new Polygon(); + + boolean res = op.execute(poly1, poly2, null, null); + assertTrue(!res); + res = op.execute(poly1, poly2, null, null); + assertTrue(!res); + } + {// polygon + OperatorOverlaps op = (OperatorOverlaps) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Overlaps)); + String str1 = "{\"rings\":[[[0,0],[0,200],[200,200],[200,0],[0,0],[0,0],[0,0]]]}"; + MapGeometry mg1 = TestCommonMethods.fromJson(str1); + String str2 = "{\"x\":100,\"y\":100}"; + MapGeometry mg2 = TestCommonMethods.fromJson(str2); + + boolean res = op.execute((mg2.getGeometry()), (mg1.getGeometry()), + null, null); + assertTrue(!res); + res = op.execute((mg1.getGeometry()), (mg2.getGeometry()), null, + null); + assertTrue(!res); + } + {// polygon + OperatorOverlaps op = (OperatorOverlaps) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Overlaps)); + String str1 = "{\"rings\":[[[0,0],[0,200],[200,200],[200,0],[0,0]]]}"; + MapGeometry mg1 = TestCommonMethods.fromJson(str1); + MapGeometry mg2 = TestCommonMethods.fromJson(str1); + Transformation2D trans = new Transformation2D(); + trans.setShift(300, 0); + mg2.getGeometry().applyTransformation(trans); + boolean res = op.execute((mg2.getGeometry()), (mg1.getGeometry()), + null, null); + assertTrue(!res); + res = op.execute((mg1.getGeometry()), (mg2.getGeometry()), null, + null); + assertTrue(!res); + } + {// polygon + OperatorOverlaps op = (OperatorOverlaps) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Overlaps)); + String str1 = "{\"rings\":[[[0,0],[0,200],[200,200],[200,0],[0,0]]]}"; + MapGeometry mg1 = TestCommonMethods.fromJson(str1); + MapGeometry mg2 = TestCommonMethods.fromJson(str1); + Transformation2D trans = new Transformation2D(); + trans.setShift(30, 0); + mg2.getGeometry().applyTransformation(trans); + boolean res = op.execute((mg2.getGeometry()), (mg1.getGeometry()), + null, null); + assertTrue(res); + res = op.execute((mg1.getGeometry()), (mg2.getGeometry()), null, + null); + assertTrue(res); + } + {// polygon + OperatorOverlaps op = (OperatorOverlaps) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Overlaps)); + String str1 = "{\"rings\":[[[0,0],[0,200],[200,200],[200,0],[0,0]]]}"; + MapGeometry mg1 = TestCommonMethods.fromJson(str1); + MapGeometry mg2 = TestCommonMethods.fromJson(str1); + Transformation2D trans = new Transformation2D(); + trans.setShift(0, 0); + mg2.getGeometry().applyTransformation(trans); + boolean res = op.execute((mg2.getGeometry()), (mg1.getGeometry()), + null, null); + assertTrue(!res); + res = op.execute((mg1.getGeometry()), (mg2.getGeometry()), null, + null); + assertTrue(!res); + } + + {// polyline + OperatorOverlaps op = (OperatorOverlaps) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Overlaps)); + String str1 = "{\"paths\":[[[0,0],[100,0],[200,0]]]}"; + MapGeometry mg1 = TestCommonMethods.fromJson(str1); + MapGeometry mg2 = TestCommonMethods.fromJson(str1); + Transformation2D trans = new Transformation2D(); + trans.setShift(0, 0); + mg2.getGeometry().applyTransformation(trans); + boolean res = op.execute((mg2.getGeometry()), (mg1.getGeometry()), + null, null); + assertTrue(!res); + res = op.execute((mg1.getGeometry()), (mg2.getGeometry()), null, + null); + assertTrue(!res); + } + + {// polyline + OperatorOverlaps op = (OperatorOverlaps) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Overlaps)); + String str1 = "{\"paths\":[[[0,0],[100,0],[200,0]]]}"; + MapGeometry mg1 = TestCommonMethods.fromJson(str1); + MapGeometry mg2 = TestCommonMethods.fromJson(str1); + Transformation2D trans = new Transformation2D(); + trans.setShift(10, 0); + mg2.getGeometry().applyTransformation(trans); + boolean res = op.execute((mg2.getGeometry()), (mg1.getGeometry()), + null, null); + assertTrue(res); + res = op.execute((mg1.getGeometry()), (mg2.getGeometry()), null, + null); + assertTrue(res); + } + + {// polyline + OperatorOverlaps op = (OperatorOverlaps) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Overlaps)); + String str1 = "{\"paths\":[[[0,0],[100,0],[200,0]]]}"; + MapGeometry mg1 = TestCommonMethods.fromJson(str1); + MapGeometry mg2 = TestCommonMethods.fromJson(str1); + Transformation2D trans = new Transformation2D(); + trans.setShift(200, 0); + mg2.getGeometry().applyTransformation(trans); + boolean res = op.execute((mg2.getGeometry()), (mg1.getGeometry()), + null, null); + assertTrue(!res); + res = op.execute((mg1.getGeometry()), (mg2.getGeometry()), null, + null); + assertTrue(!res); + } + + {// Multi_point + OperatorOverlaps op = (OperatorOverlaps) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Overlaps)); + String str1 = "{\"points\":[[0,0],[0,200],[200,200],[200,0]]}"; + MapGeometry mg1 = TestCommonMethods.fromJson(str1); + MapGeometry mg2 = TestCommonMethods.fromJson(str1); + Transformation2D trans = new Transformation2D(); + trans.setShift(0, 0); + mg2.getGeometry().applyTransformation(trans); + boolean res = op.execute((mg2.getGeometry()), (mg1.getGeometry()), + null, null); + assertTrue(!res); + res = op.execute((mg1.getGeometry()), (mg2.getGeometry()), null, + null); + assertTrue(!res); + } + {// Multi_point + OperatorOverlaps op = (OperatorOverlaps) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Overlaps)); + String str1 = "{\"points\":[[0,0],[0,200],[200,200]]}"; + MapGeometry mg1 = TestCommonMethods.fromJson(str1); + String str2 = "{\"points\":[[0,0],[0,200]]}"; + MapGeometry mg2 = TestCommonMethods.fromJson(str2); + boolean res = op.execute((mg2.getGeometry()), (mg1.getGeometry()), + null, null); + assertTrue(!res); + res = op.execute((mg1.getGeometry()), (mg2.getGeometry()), null, + null); + assertTrue(!res); + } + {// Multi_point + OperatorOverlaps op = (OperatorOverlaps) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Overlaps)); + String str1 = "{\"points\":[[0,0],[0,200],[200,200]]}"; + MapGeometry mg1 = TestCommonMethods.fromJson(str1); + String str2 = "{\"points\":[[0,0],[0,200], [0,2]]}"; + MapGeometry mg2 = TestCommonMethods.fromJson(str2); + boolean res = op.execute((mg2.getGeometry()), (mg1.getGeometry()), + null, null); + assertTrue(res); + res = op.execute((mg1.getGeometry()), (mg2.getGeometry()), null, + null); + assertTrue(res); + } + } + + @Test + public void testPolygonPolygonEquals() { + OperatorEquals equals = (OperatorEquals) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Equals)); + SpatialReference sr = SpatialReference.create(102100); + @SuppressWarnings("unused") + double tolerance = sr + .getTolerance(VertexDescription.Semantics.POSITION); + + // Polygon1 and Polygon2 are topologically equal, but have differing + // number of vertices + String str1 = "{\"rings\":[[[0,0],[0,5],[0,7],[0,10],[0,10],[10,10],[10,0],[0,0]],[[1,1],[9,1],[9,9],[1,9],[1,1],[1,1]]]}"; + String str2 = "{\"rings\":[[[0,10],[10,10],[10,0],[0,0],[0,10]],[[9,1],[9,6],[9,9],[1,9],[1,1],[1,1],[9,1]]]}"; + + Polygon polygon1 = (Polygon) TestCommonMethods.fromJson(str1) + .getGeometry(); + Polygon polygon2 = (Polygon) TestCommonMethods.fromJson(str2) + .getGeometry(); + // wiggleGeometry(polygon1, tolerance, 1982); + // wiggleGeometry(polygon2, tolerance, 511); + + equals.accelerateGeometry(polygon1, sr, + Geometry.GeometryAccelerationDegree.enumHot); + equals.accelerateGeometry(polygon2, sr, + Geometry.GeometryAccelerationDegree.enumHot); + + boolean res = equals.execute(polygon1, polygon2, sr, null); + assertTrue(res); + equals.execute(polygon2, polygon1, sr, null); + assertTrue(res); + + // The outer rings of Polygon1 and Polygon2 are equal, but Polygon1 has + // a hole. + str1 = "{\"rings\":[[[0,0],[0,5],[0,10],[10,10],[10,0],[0,0]],[[1,1],[9,1],[9,9],[1,9],[1,1],[1,1]]]}"; + str2 = "{\"rings\":[[[0,10],[10,10],[5,10],[10,10],[10,0],[0,0],[0,10]]]}"; + polygon1 = (Polygon) TestCommonMethods.fromJson(str1).getGeometry(); + polygon2 = (Polygon) TestCommonMethods.fromJson(str2).getGeometry(); + + res = equals.execute(polygon1, polygon2, sr, null); + assertTrue(!res); + res = equals.execute(polygon2, polygon1, sr, null); + assertTrue(!res); + + // The rings are equal but rotated + str1 = "{\"rings\":[[[0,0],[0,10],[10,10],[10,0],[0,0]]]}"; + str2 = "{\"rings\":[[[0,10],[10,10],[10,0],[0,0],[0,10]]]}"; + + polygon1 = (Polygon) TestCommonMethods.fromJson(str1).getGeometry(); + polygon2 = (Polygon) TestCommonMethods.fromJson(str2).getGeometry(); + + res = equals.execute(polygon1, polygon2, sr, null); + assertTrue(res); + res = equals.execute(polygon2, polygon1, sr, null); + assertTrue(res); + + // The rings are equal but opposite orientation + str1 = "{\"rings\":[[[0,0],[0,10],[10,10],[10,0],[0,0]]]}"; + str2 = "{\"rings\":[[[0,0],[10,0],[10,10],[0,10],[0,0]]]}"; + + polygon1 = (Polygon) TestCommonMethods.fromJson(str1).getGeometry(); + polygon2 = (Polygon) TestCommonMethods.fromJson(str2).getGeometry(); + + res = equals.execute(polygon1, polygon2, sr, null); + assertTrue(!res); + res = equals.execute(polygon2, polygon1, sr, null); + assertTrue(!res); + + // The rings are equal but first polygon has two rings stacked + str1 = "{\"rings\":[[[0,0],[0,10],[10,10],[10,0],[0,0]],[[0,10],[10,10],[10,0],[0,0],[0,10]]]}"; + str2 = "{\"rings\":[[[0,10],[10,10],[10,0],[0,0],[0,10]]]}"; + polygon1 = (Polygon) TestCommonMethods.fromJson(str1).getGeometry(); + polygon2 = (Polygon) TestCommonMethods.fromJson(str2).getGeometry(); + + res = equals.execute(polygon1, polygon2, sr, null); + assertTrue(!res); + res = equals.execute(polygon2, polygon1, sr, null); + assertTrue(!res); + } + + @Test + public void testMultiPointMultiPointEquals() { + OperatorEquals equals = (OperatorEquals) OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Equals); + SpatialReference sr = SpatialReference.create(102100); + @SuppressWarnings("unused") + double tolerance = sr + .getTolerance(VertexDescription.Semantics.POSITION); + + MultiPoint multipoint1 = new MultiPoint(); + MultiPoint multipoint2 = new MultiPoint(); + + multipoint1.add(0, 0); + multipoint1.add(1, 1); + multipoint1.add(2, 2); + multipoint1.add(3, 3); + multipoint1.add(4, 4); + multipoint1.add(1, 1); + multipoint1.add(0, 0); + + multipoint2.add(4, 4); + multipoint2.add(3, 3); + multipoint2.add(2, 2); + multipoint2.add(1, 1); + multipoint2.add(0, 0); + multipoint2.add(2, 2); + + wiggleGeometry(multipoint1, 0.001, 123); + wiggleGeometry(multipoint2, 0.001, 5937); + boolean res = equals.execute(multipoint1, multipoint2, sr, null); + assertTrue(res); + res = equals.execute(multipoint2, multipoint1, sr, null); + assertTrue(res); + + multipoint1.add(1, 2); + res = equals.execute(multipoint1, multipoint2, sr, null); + assertTrue(!res); + res = equals.execute(multipoint2, multipoint1, sr, null); + assertTrue(!res); + } + + @Test + public void testMultiPointPointEquals() { + OperatorEquals equals = (OperatorEquals) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Equals)); + OperatorWithin within = (OperatorWithin) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Within)); + SpatialReference sr = SpatialReference.create(102100); + @SuppressWarnings("unused") + double tolerance = sr + .getTolerance(VertexDescription.Semantics.POSITION); + + MultiPoint multipoint1 = new MultiPoint(); + Point point2 = new Point(); + + multipoint1.add(2, 2); + multipoint1.add(2, 2); + + point2.setXY(2, 2); + + wiggleGeometry(multipoint1, 0.001, 123); + boolean res = equals.execute(multipoint1, point2, sr, null); + assertTrue(res); + res = equals.execute(point2, multipoint1, sr, null); + assertTrue(res); + + res = within.execute(multipoint1, point2, sr, null); + assertTrue(res); + res = within.execute(point2, multipoint1, sr, null); + assertTrue(res); + + multipoint1.add(4, 4); + res = equals.execute(multipoint1, point2, sr, null); + assertTrue(!res); + res = equals.execute(point2, multipoint1, sr, null); + assertTrue(!res); + + res = within.execute(multipoint1, point2, sr, null); + assertTrue(!res); + res = within.execute(point2, multipoint1, sr, null); + assertTrue(res); + } + + @Test + public void testPointPointEquals() { + OperatorEquals equals = (OperatorEquals) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Equals)); + OperatorWithin within = (OperatorWithin) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Within)); + OperatorContains contains = (OperatorContains) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Contains)); + OperatorDisjoint disjoint = (OperatorDisjoint) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Disjoint)); + SpatialReference sr = SpatialReference.create(102100); + @SuppressWarnings("unused") + double tolerance = sr + .getTolerance(VertexDescription.Semantics.POSITION); + + Point point1 = new Point(); + Point point2 = new Point(); + + point1.setXY(2, 2); + point2.setXY(2, 2); + + boolean res = equals.execute(point1, point2, sr, null); + assertTrue(res); + res = equals.execute(point2, point1, sr, null); + assertTrue(res); + + res = within.execute(point1, point2, sr, null); + assertTrue(res); + res = within.execute(point2, point1, sr, null); + assertTrue(res); + + res = contains.execute(point1, point2, sr, null); + assertTrue(res); + res = contains.execute(point2, point1, sr, null); + assertTrue(res); + + res = disjoint.execute(point1, point2, sr, null); + assertTrue(!res); + res = disjoint.execute(point2, point1, sr, null); + assertTrue(!res); + + point2.setXY(2, 3); + res = equals.execute(point1, point2, sr, null); + assertTrue(!res); + res = equals.execute(point2, point1, sr, null); + assertTrue(!res); + + res = within.execute(point1, point2, sr, null); + assertTrue(!res); + res = within.execute(point2, point1, sr, null); + assertTrue(!res); + + res = contains.execute(point1, point2, sr, null); + assertTrue(!res); + res = contains.execute(point2, point1, sr, null); + assertTrue(!res); + + res = disjoint.execute(point1, point2, sr, null); + assertTrue(res); + res = disjoint.execute(point2, point1, sr, null); + assertTrue(res); + } + + @Test + public void testPolygonPolygonDisjoint() { + OperatorDisjoint disjoint = (OperatorDisjoint) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Disjoint)); + SpatialReference sr = SpatialReference.create(102100); + double tolerance = sr + .getTolerance(VertexDescription.Semantics.POSITION); + + // Polygon1 and Polygon2 are topologically equal, but have differing + // number of vertices + String str1 = "{\"rings\":[[[0,0],[0,5],[0,10],[10,10],[10,0],[0,0]],[[1,1],[9,1],[9,9],[1,9],[1,1],[1,1]]]}"; + String str2 = "{\"rings\":[[[0,10],[10,10],[10,0],[0,0],[0,10]],[[9,1],[9,6],[9,9],[1,9],[1,1],[1,1],[9,1]]]}"; + + Polygon polygon1 = (Polygon) (TestCommonMethods.fromJson(str1) + .getGeometry()); + Polygon polygon2 = (Polygon) (TestCommonMethods.fromJson(str2) + .getGeometry()); + + boolean res = disjoint.execute(polygon1, polygon2, sr, null); + assertTrue(!res); + res = disjoint.execute(polygon2, polygon1, sr, null); + assertTrue(!res); + + // Polygon1 and Polygon2 touch at a point + str1 = "{\"rings\":[[[0,0],[0,5],[0,10],[10,10],[10,0],[0,0]],[[1,1],[9,1],[9,9],[1,9],[1,1],[1,1]]]}"; + str2 = "{\"rings\":[[[10,10],[10,15],[15,15],[15,10],[10,10]]]}"; + + polygon1 = (Polygon) (TestCommonMethods.fromJson(str1).getGeometry()); + polygon2 = (Polygon) (TestCommonMethods.fromJson(str2).getGeometry()); + wiggleGeometry(polygon1, tolerance, 1982); + wiggleGeometry(polygon2, tolerance, 511); + + res = disjoint.execute(polygon1, polygon2, sr, null); + assertTrue(!res); + res = disjoint.execute(polygon2, polygon1, sr, null); + assertTrue(!res); + + // Polygon1 and Polygon2 touch along the boundary + str1 = "{\"rings\":[[[0,0],[0,5],[0,10],[10,10],[10,0],[0,0]],[[1,1],[9,1],[9,9],[1,9],[1,1],[1,1]]]}"; + str2 = "{\"rings\":[[[10,0],[10,10],[15,10],[15,0],[10,0]]]}"; + + polygon1 = (Polygon) (TestCommonMethods.fromJson(str1).getGeometry()); + polygon2 = (Polygon) (TestCommonMethods.fromJson(str2).getGeometry()); + wiggleGeometry(polygon1, tolerance, 1982); + wiggleGeometry(polygon2, tolerance, 511); + + res = disjoint.execute(polygon1, polygon2, sr, null); + assertTrue(!res); + res = disjoint.execute(polygon2, polygon1, sr, null); + assertTrue(!res); + + // Polygon2 is inside of the hole of polygon1 + str1 = "{\"rings\":[[[0,0],[0,5],[0,10],[10,10],[10,0],[0,0]],[[1,1],[9,1],[9,9],[1,9],[1,1],[1,1]]]}"; + str2 = "{\"rings\":[[[2,2],[2,8],[8,8],[8,2],[2,2]]]}"; + + polygon1 = (Polygon) (TestCommonMethods.fromJson(str1).getGeometry()); + polygon2 = (Polygon) (TestCommonMethods.fromJson(str2).getGeometry()); + + res = disjoint.execute(polygon1, polygon2, sr, null); + assertTrue(res); + res = disjoint.execute(polygon2, polygon1, sr, null); + assertTrue(res); + + // Polygon2 is inside of the hole of polygon1 + str1 = "{\"rings\":[[[0,0],[0,5],[5,5],[5,0]],[[10,0],[10,10],[20,10],[20,0]]]}"; + str2 = "{\"rings\":[[[0,-10],[0,-5],[5,-5],[5,-10]],[[11,1],[11,9],[19,9],[19,1]]]}"; + + polygon1 = (Polygon) (TestCommonMethods.fromJson(str1).getGeometry()); + polygon2 = (Polygon) (TestCommonMethods.fromJson(str2).getGeometry()); + + res = disjoint.execute(polygon1, polygon2, sr, null); + assertTrue(!res); + res = disjoint.execute(polygon2, polygon1, sr, null); + assertTrue(!res); + + polygon1 = (Polygon) OperatorDensifyByLength.local().execute(polygon1, 0.5, null); + disjoint.accelerateGeometry(polygon1, sr, GeometryAccelerationDegree.enumHot); + res = disjoint.execute(polygon1, polygon2, sr, null); + assertTrue(!res); + res = disjoint.execute(polygon2, polygon1, sr, null); + assertTrue(!res); + + polygon1.reverseAllPaths(); + polygon2.reverseAllPaths(); + res = disjoint.execute(polygon1, polygon2, sr, null); + assertTrue(!res); + res = disjoint.execute(polygon2, polygon1, sr, null); + assertTrue(!res); + + // Polygon1 contains polygon2, but polygon2 is counterclockwise. + str1 = "{\"rings\":[[[0,0],[10,0],[10,10],[0,10],[0,0]],[[11,0],[11,10],[21,10],[21,0],[11,0]]]}"; + str2 = "{\"rings\":[[[2,2],[8,2],[8,8],[2,8],[2,2]]]}"; + polygon1 = (Polygon) (TestCommonMethods.fromJson(str1).getGeometry()); + polygon2 = (Polygon) (TestCommonMethods.fromJson(str2).getGeometry()); + + + res = disjoint.execute(polygon1, polygon2, sr, null); + assertTrue(!res); + res = disjoint.execute(polygon2, polygon1, sr, null); + assertTrue(!res); + + polygon1 = (Polygon) OperatorDensifyByLength.local().execute(polygon1, 0.5, null); + disjoint.accelerateGeometry(polygon1, sr, GeometryAccelerationDegree.enumHot); + res = disjoint.execute(polygon1, polygon2, sr, null); + assertTrue(!res); + res = disjoint.execute(polygon2, polygon1, sr, null); + assertTrue(!res); + + str1 = "{\"rings\":[[[0,0],[0,10],[10,10],[10,0],[0,0]],[[0,20],[0,30],[10,30],[10,20],[0,20]],[[20,20],[20,30],[30,30],[30,20],[20,20]],[[20,0],[20,10],[30,10],[30,0],[20,0]]]}"; + str2 = "{\"rings\":[[[14,14],[14,16],[16,16],[16,14],[14,14]]]}"; + polygon1 = (Polygon) (TestCommonMethods.fromJson(str1).getGeometry()); + polygon2 = (Polygon) (TestCommonMethods.fromJson(str2).getGeometry()); + + + res = disjoint.execute(polygon1, polygon2, sr, null); + assertTrue(res); + res = disjoint.execute(polygon2, polygon1, sr, null); + assertTrue(res); + + polygon1 = (Polygon) OperatorDensifyByLength.local().execute(polygon1, 0.5, null); + disjoint.accelerateGeometry(polygon1, sr, GeometryAccelerationDegree.enumHot); + res = disjoint.execute(polygon1, polygon2, sr, null); + assertTrue(res); + res = disjoint.execute(polygon2, polygon1, sr, null); + assertTrue(res); + } + + @Test + public void testPolylinePolylineDisjoint() { + OperatorDisjoint disjoint = (OperatorDisjoint) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Disjoint)); + SpatialReference sr = SpatialReference.create(102100); + double tolerance = sr + .getTolerance(VertexDescription.Semantics.POSITION); + + // Polyline1 and Polyline2 touch at a point + String str1 = "{\"paths\":[[[0,0],[0,5],[0,10],[10,10],[10,0],[0,0]],[[1,1],[9,1],[9,9],[1,9],[1,1],[1,1]]]}"; + String str2 = "{\"paths\":[[[10,10],[10,15],[15,15],[15,10],[10,10]]]}"; + + Polyline polyline1 = (Polyline) (TestCommonMethods.fromJson(str1) + .getGeometry()); + Polyline polyline2 = (Polyline) (TestCommonMethods.fromJson(str2) + .getGeometry()); + wiggleGeometry(polyline1, tolerance, 1982); + wiggleGeometry(polyline2, tolerance, 511); + + boolean res = disjoint.execute(polyline1, polyline2, sr, null); + assertTrue(!res); + res = disjoint.execute(polyline2, polyline1, sr, null); + assertTrue(!res); + + // Polyline1 and Polyline2 touch along the boundary + str1 = "{\"paths\":[[[0,0],[0,5],[0,10],[10,10],[10,0],[0,0]],[[1,1],[9,1],[9,9],[1,9],[1,1],[1,1]]]}"; + str2 = "{\"paths\":[[[10,0],[10,10],[15,10],[15,0],[10,0]]]}"; + + polyline1 = (Polyline) (TestCommonMethods.fromJson(str1).getGeometry()); + polyline2 = (Polyline) (TestCommonMethods.fromJson(str2).getGeometry()); + wiggleGeometry(polyline1, tolerance, 1982); + wiggleGeometry(polyline2, tolerance, 511); + + res = disjoint.execute(polyline1, polyline2, sr, null); + assertTrue(!res); + res = disjoint.execute(polyline2, polyline1, sr, null); + assertTrue(!res); + + // Polyline2 does not intersect with Polyline1 + str1 = "{\"paths\":[[[0,0],[0,5],[0,10],[10,10],[10,0],[0,0]],[[1,1],[9,1],[9,9],[1,9],[1,1],[1,1]]]}"; + str2 = "{\"paths\":[[[2,2],[2,8],[8,8],[8,2],[2,2]]]}"; + + polyline1 = (Polyline) (TestCommonMethods.fromJson(str1).getGeometry()); + polyline2 = (Polyline) (TestCommonMethods.fromJson(str2).getGeometry()); + + res = disjoint.execute(polyline1, polyline2, sr, null); + assertTrue(res); + res = disjoint.execute(polyline2, polyline1, sr, null); + assertTrue(res); + } + + @Test + public void testPolygonPolylineDisjoint() { + OperatorDisjoint disjoint = (OperatorDisjoint) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Disjoint)); + SpatialReference sr = SpatialReference.create(102100); + @SuppressWarnings("unused") + double tolerance = sr + .getTolerance(VertexDescription.Semantics.POSITION); + + Polygon polygon1 = new Polygon(); + Polyline polyline2 = new Polyline(); + + polygon1.startPath(0, 0); + polygon1.lineTo(0, 10); + polygon1.lineTo(10, 10); + polygon1.lineTo(10, 0); + + polygon1.startPath(1, 1); + polygon1.lineTo(9, 1); + polygon1.lineTo(9, 9); + polygon1.lineTo(1, 9); + + polyline2.startPath(3, 3); + polyline2.lineTo(6, 6); + + boolean res = disjoint.execute(polyline2, polygon1, sr, null); + assertTrue(res); + res = disjoint.execute(polygon1, polyline2, sr, null); + assertTrue(res); + + polyline2.startPath(0, 0); + polyline2.lineTo(0, 5); + + res = disjoint.execute(polyline2, polygon1, sr, null); + assertTrue(!res); + res = disjoint.execute(polygon1, polyline2, sr, null); + assertTrue(!res); + + polygon1.setEmpty(); + polyline2.setEmpty(); + + polygon1.startPath(0, 0); + polygon1.lineTo(0, 10); + polygon1.lineTo(10, 10); + polygon1.lineTo(10, 0); + + polyline2.startPath(2, 2); + polyline2.lineTo(4, 4); + + OperatorFactoryLocal factory = OperatorFactoryLocal.getInstance(); + OperatorSimplify simplify_op = (OperatorSimplify) factory + .getOperator(Operator.Type.Simplify); + simplify_op.isSimpleAsFeature(polygon1, sr, null); + simplify_op.isSimpleAsFeature(polyline2, sr, null); + + res = disjoint.execute(polyline2, polygon1, sr, null); + assertTrue(!res); + res = disjoint.execute(polygon1, polyline2, sr, null); + assertTrue(!res); + } + + @Test + public void testPolylineMultiPointDisjoint() { + OperatorDisjoint disjoint = (OperatorDisjoint) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Disjoint)); + SpatialReference sr = SpatialReference.create(102100); + @SuppressWarnings("unused") + double tolerance = sr + .getTolerance(VertexDescription.Semantics.POSITION); + + Polyline polyline1 = new Polyline(); + MultiPoint multipoint2 = new MultiPoint(); + + polyline1.startPath(0, 0); + polyline1.lineTo(2, 0); + polyline1.lineTo(4, 2); + + multipoint2.add(1, 1); + multipoint2.add(2, 2); + multipoint2.add(3, 0); + + boolean res = disjoint.execute(polyline1, multipoint2, sr, null); + assertTrue(res); + res = disjoint.execute(multipoint2, polyline1, sr, null); + assertTrue(res); + + multipoint2.add(3, 1); + res = disjoint.execute(polyline1, multipoint2, sr, null); + assertTrue(!res); + res = disjoint.execute(multipoint2, polyline1, sr, null); + assertTrue(!res); + + polyline1.startPath(1, -4); + polyline1.lineTo(1, -3); + polyline1.lineTo(1, -2); + polyline1.lineTo(1, -1); + polyline1.lineTo(1, 0); + polyline1.lineTo(1, 1); + + disjoint.accelerateGeometry(polyline1, sr, + Geometry.GeometryAccelerationDegree.enumHot); + res = disjoint.execute(polyline1, multipoint2, sr, null); + assertTrue(!res); + res = disjoint.execute(multipoint2, polyline1, sr, null); + assertTrue(!res); + } + + @Test + public void testPolylinePointDisjoint() { + OperatorDisjoint disjoint = (OperatorDisjoint) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Disjoint)); + OperatorContains contains = (OperatorContains) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Contains)); + SpatialReference sr = SpatialReference.create(102100); + @SuppressWarnings("unused") + double tolerance = sr + .getTolerance(VertexDescription.Semantics.POSITION); + + Polyline polyline1 = new Polyline(); + Point point2 = new Point(); + + polyline1.startPath(0, 0); + polyline1.lineTo(2, 0); + polyline1.lineTo(4, 2); + + point2.setXY(1, 1); + + boolean res = disjoint.execute(polyline1, point2, sr, null); + assertTrue(res); + res = disjoint.execute(point2, polyline1, sr, null); + assertTrue(res); + + res = contains.execute(polyline1, point2, sr, null); + assertTrue(!res); + res = contains.execute(point2, polyline1, sr, null); + assertTrue(!res); + + point2.setXY(4, 2); + + polyline1 = (Polyline) OperatorDensifyByLength.local().execute( + polyline1, 0.1, null); + disjoint.accelerateGeometry(polyline1, sr, + Geometry.GeometryAccelerationDegree.enumHot); + + res = disjoint.execute(polyline1, point2, sr, null); + assertTrue(!res); + res = disjoint.execute(point2, polyline1, sr, null); + assertTrue(!res); + + res = contains.execute(polyline1, point2, sr, null); + assertTrue(!res); + res = contains.execute(point2, polyline1, sr, null); + assertTrue(!res); + + polyline1.setEmpty(); + point2.setEmpty(); + + polyline1.startPath(659062.37370000035, 153070.85220000148); + polyline1.lineTo(660916.47940000147, 151481.10269999877); + point2.setXY(659927.85020000115, 152328.77430000156); + + res = contains.execute(polyline1, point2, + SpatialReference.create(54004), null); + assertTrue(res); + } + + @Test + public void testMultiPointMultiPointDisjoint() { + OperatorDisjoint disjoint = (OperatorDisjoint) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Disjoint)); + SpatialReference sr = SpatialReference.create(102100); + @SuppressWarnings("unused") + double tolerance = sr + .getTolerance(VertexDescription.Semantics.POSITION); + + MultiPoint multipoint1 = new MultiPoint(); + MultiPoint multipoint2 = new MultiPoint(); + + multipoint1.add(2, 2); + multipoint1.add(2, 5); + multipoint1.add(4, 1); + multipoint1.add(4, 4); + multipoint1.add(4, 7); + multipoint1.add(6, 2); + multipoint1.add(6, 6); + multipoint1.add(4, 1); + multipoint1.add(6, 6); + + multipoint2.add(0, 1); + multipoint2.add(0, 7); + multipoint2.add(4, 2); + multipoint2.add(4, 6); + multipoint2.add(6, 4); + multipoint2.add(4, 2); + multipoint2.add(0, 1); + + boolean res = disjoint.execute(multipoint1, multipoint2, sr, null); + assertTrue(res); + res = disjoint.execute(multipoint2, multipoint1, sr, null); + assertTrue(res); + + multipoint2.add(2, 2); + res = disjoint.execute(multipoint1, multipoint2, sr, null); + assertTrue(!res); + res = disjoint.execute(multipoint2, multipoint1, sr, null); + assertTrue(!res); + } + + @Test + public void testMultiPointPointDisjoint() { + OperatorDisjoint disjoint = (OperatorDisjoint) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Disjoint)); + OperatorContains contains = (OperatorContains) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Contains)); + SpatialReference sr = SpatialReference.create(102100); + @SuppressWarnings("unused") + double tolerance = sr + .getTolerance(VertexDescription.Semantics.POSITION); + + MultiPoint multipoint1 = new MultiPoint(); + Point point2 = new Point(); + + multipoint1.add(2, 2); + multipoint1.add(2, 5); + multipoint1.add(4, 1); + multipoint1.add(4, 4); + multipoint1.add(4, 7); + multipoint1.add(6, 2); + multipoint1.add(6, 6); + multipoint1.add(4, 1); + multipoint1.add(6, 6); + + point2.setXY(2, 6); + + boolean res = disjoint.execute(multipoint1, point2, sr, null); + assertTrue(res); + res = disjoint.execute(point2, multipoint1, sr, null); + assertTrue(res); + + res = contains.execute(multipoint1, point2, sr, null); + assertTrue(!res); + res = contains.execute(point2, multipoint1, sr, null); + assertTrue(!res); + + multipoint1.add(2, 6); + res = disjoint.execute(multipoint1, point2, sr, null); + assertTrue(!res); + res = disjoint.execute(point2, multipoint1, sr, null); + assertTrue(!res); + + res = contains.execute(multipoint1, point2, sr, null); + assertTrue(res); + res = contains.execute(point2, multipoint1, sr, null); + assertTrue(!res); + } + + @Test + public void testPolygonMultiPointDisjoint() { + OperatorDisjoint disjoint = (OperatorDisjoint) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Disjoint)); + SpatialReference sr = SpatialReference.create(102100); + @SuppressWarnings("unused") + double tolerance = sr + .getTolerance(VertexDescription.Semantics.POSITION); + + Polygon polygon1 = new Polygon(); + MultiPoint multipoint2 = new MultiPoint(); + + polygon1.startPath(0, 0); + polygon1.lineTo(0, 10); + polygon1.lineTo(10, 10); + + multipoint2.add(-1, 5); + multipoint2.add(5, 11); + multipoint2.add(11, 5); + multipoint2.add(5, -1); + + boolean res = disjoint.execute(polygon1, multipoint2, sr, null); + assertTrue(res); + res = disjoint.execute(multipoint2, polygon1, sr, null); + assertTrue(res); + + polygon1.startPath(15, 0); + polygon1.lineTo(15, 10); + polygon1.lineTo(25, 10); + polygon1.lineTo(25, 0); + + multipoint2.add(14, 5); + multipoint2.add(20, 11); + multipoint2.add(26, 5); + multipoint2.add(20, -1); + + res = disjoint.execute(polygon1, multipoint2, sr, null); + assertTrue(res); + res = disjoint.execute(multipoint2, polygon1, sr, null); + assertTrue(res); + + multipoint2.add(20, 5); + + res = disjoint.execute(polygon1, multipoint2, sr, null); + assertTrue(!res); + res = disjoint.execute(multipoint2, polygon1, sr, null); + assertTrue(!res); + } + + @Test + public void testPolygonMultiPointTouches() { + OperatorTouches touches = (OperatorTouches) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Touches)); + SpatialReference sr = SpatialReference.create(102100); + @SuppressWarnings("unused") + double tolerance = sr + .getTolerance(VertexDescription.Semantics.POSITION); + + Polygon polygon1 = new Polygon(); + MultiPoint multipoint2 = new MultiPoint(); + + polygon1.startPath(0, 0); + polygon1.lineTo(0, 10); + polygon1.lineTo(10, 10); + polygon1.lineTo(10, 0); + + multipoint2.add(-1, 5); + multipoint2.add(5, 11); + multipoint2.add(11, 5); + multipoint2.add(5, -1); + + boolean res = touches.execute(polygon1, multipoint2, sr, null); + assertTrue(!res); + res = touches.execute(multipoint2, polygon1, sr, null); + assertTrue(!res); + + multipoint2.add(5, 10); + + res = touches.execute(polygon1, multipoint2, sr, null); + assertTrue(res); + res = touches.execute(multipoint2, polygon1, sr, null); + assertTrue(res); + + multipoint2.add(5, 5); + res = touches.execute(polygon1, multipoint2, sr, null); + assertTrue(!res); + res = touches.execute(multipoint2, polygon1, sr, null); + assertTrue(!res); + } + + @Test + public void testPolygonPointTouches() { + OperatorTouches touches = (OperatorTouches) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Touches)); + SpatialReference sr = SpatialReference.create(102100); + @SuppressWarnings("unused") + double tolerance = sr + .getTolerance(VertexDescription.Semantics.POSITION); + + Polygon polygon1 = new Polygon(); + Point point2 = new Point(); + + polygon1.startPath(0, 0); + polygon1.lineTo(0, 10); + polygon1.lineTo(10, 10); + polygon1.lineTo(10, 0); + + point2.setXY(5, 5); + + boolean res = touches.execute(polygon1, point2, sr, null); + assertTrue(!res); + res = touches.execute(point2, polygon1, sr, null); + assertTrue(!res); + + point2.setXY(5, 10); + + res = touches.execute(polygon1, point2, sr, null); + assertTrue(res); + res = touches.execute(point2, polygon1, sr, null); + assertTrue(res); + } + + @Test + public void testPolygonPolygonTouches() { + OperatorTouches touches = (OperatorTouches) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Touches)); + SpatialReference sr = SpatialReference.create(102100); + double tolerance = sr + .getTolerance(VertexDescription.Semantics.POSITION); + + // Polygon1 and Polygon2 touch at a point + String str1 = "{\"rings\":[[[0,0],[0,5],[0,10],[10,10],[10,0],[0,0]],[[1,1],[9,1],[9,9],[1,9],[1,1],[1,1]]]}"; + String str2 = "{\"rings\":[[[10,10],[10,15],[15,15],[15,10],[10,10]]]}"; + + Polygon polygon1 = (Polygon) (TestCommonMethods.fromJson(str1) + .getGeometry()); + Polygon polygon2 = (Polygon) (TestCommonMethods.fromJson(str2) + .getGeometry()); + wiggleGeometry(polygon1, tolerance, 1982); + wiggleGeometry(polygon2, tolerance, 511); + + boolean res = touches.execute(polygon1, polygon2, sr, null); + assertTrue(res); + res = touches.execute(polygon2, polygon1, sr, null); + assertTrue(res); + + // Polygon1 and Polygon2 touch along the boundary + str1 = "{\"rings\":[[[0,0],[0,5],[0,10],[10,10],[10,0],[0,0]],[[1,1],[9,1],[9,9],[1,9],[1,1],[1,1]]]}"; + str2 = "{\"rings\":[[[10,0],[10,10],[15,10],[15,0],[10,0]]]}"; + + polygon1 = (Polygon) (TestCommonMethods.fromJson(str1).getGeometry()); + polygon2 = (Polygon) (TestCommonMethods.fromJson(str2).getGeometry()); + wiggleGeometry(polygon1, tolerance, 1982); + wiggleGeometry(polygon2, tolerance, 511); + + res = touches.execute(polygon1, polygon2, sr, null); + assertTrue(res); + res = touches.execute(polygon2, polygon1, sr, null); + assertTrue(res); + + // Polygon1 and Polygon2 touch at a corner of Polygon1 and a diagonal of + // Polygon2 + str1 = "{\"rings\":[[[0,0],[0,5],[0,10],[10,10],[10,0],[0,0]],[[1,1],[9,1],[9,9],[1,9],[1,1],[1,1]]]}"; + str2 = "{\"rings\":[[[15,5],[5,15],[15,15],[15,5]]]}"; + + polygon1 = (Polygon) (TestCommonMethods.fromJson(str1).getGeometry()); + polygon2 = (Polygon) (TestCommonMethods.fromJson(str2).getGeometry()); + wiggleGeometry(polygon1, tolerance, 1982); + wiggleGeometry(polygon2, tolerance, 511); + + res = touches.execute(polygon1, polygon2, sr, null); + assertTrue(res); + res = touches.execute(polygon2, polygon1, sr, null); + assertTrue(res); + + // Polygon1 and Polygon2 do not touch + str1 = "{\"rings\":[[[0,0],[0,5],[0,10],[10,10],[10,0],[0,0]],[[1,1],[9,1],[9,9],[1,9],[1,1],[1,1]]]}"; + str2 = "{\"rings\":[[[5,5],[5,15],[15,15],[15,5],[5,5]]]}"; + + polygon1 = (Polygon) (TestCommonMethods.fromJson(str1).getGeometry()); + polygon2 = (Polygon) (TestCommonMethods.fromJson(str2).getGeometry()); + + res = touches.execute(polygon1, polygon2, sr, null); + assertTrue(!res); + res = touches.execute(polygon2, polygon1, sr, null); + assertTrue(!res); + + polygon1.setEmpty(); + polygon2.setEmpty(); + + polygon1.startPath(0, 0); + polygon1.lineTo(0, 1); + polygon1.lineTo(-1, 0); + + polygon2.startPath(0, 0); + polygon2.lineTo(0, 1); + polygon2.lineTo(1, 0); + + res = touches.execute(polygon1, polygon2, sr, null); + assertTrue(res); + res = touches.execute(polygon2, polygon1, sr, null); + assertTrue(res); + } + + @Test + public void testPolygonPolylineTouches() { + OperatorTouches touches = (OperatorTouches) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Touches)); + SpatialReference sr = SpatialReference.create(102100); + double tolerance = sr + .getTolerance(VertexDescription.Semantics.POSITION); + + // Polygon1 and Polyline2 touch at a point + String str1 = "{\"rings\":[[[0,0],[0,5],[0,10],[10,10],[10,0]],[[1,1],[9,1],[9,9],[1,9],[1,1],[1,1]]]}"; + String str2 = "{\"paths\":[[[10,10],[10,15],[15,15],[15,10]]]}"; + + Polygon polygon1 = (Polygon) (TestCommonMethods.fromJson(str1) + .getGeometry()); + Polyline polyline2 = (Polyline) (TestCommonMethods.fromJson(str2) + .getGeometry()); + wiggleGeometry(polygon1, tolerance, 1982); + wiggleGeometry(polyline2, tolerance, 511); + + boolean res = touches.execute(polygon1, polyline2, sr, null); + assertTrue(res); + res = touches.execute(polyline2, polygon1, sr, null); + assertTrue(res); + + // Polygon1 and Polyline2 overlap along the boundary + str1 = "{\"rings\":[[[0,0],[0,5],[0,10],[10,10],[10,0],[0,0]],[[1,1],[9,1],[9,9],[1,9],[1,1],[1,1]]]}"; + str2 = "{\"paths\":[[[10,0],[10,10],[15,10],[15,0]]]}"; + + polygon1 = (Polygon) (TestCommonMethods.fromJson(str1).getGeometry()); + polyline2 = (Polyline) (TestCommonMethods.fromJson(str2).getGeometry()); + wiggleGeometry(polygon1, tolerance, 1982); + wiggleGeometry(polyline2, tolerance, 511); + + res = touches.execute(polygon1, polyline2, sr, null); + assertTrue(res); + res = touches.execute(polyline2, polygon1, sr, null); + assertTrue(res); + + str1 = "{\"rings\":[[[0,0],[0,5],[0,10],[10,10],[10,0],[0,0]],[[1,1],[9,1],[9,9],[1,9],[1,1],[1,1]]]}"; + str2 = "{\"paths\":[[[15,5],[5,15],[15,15],[15,5]]]}"; + + polygon1 = (Polygon) (TestCommonMethods.fromJson(str1).getGeometry()); + polyline2 = (Polyline) (TestCommonMethods.fromJson(str2).getGeometry()); + wiggleGeometry(polygon1, tolerance, 1982); + wiggleGeometry(polyline2, tolerance, 511); + + res = touches.execute(polygon1, polyline2, sr, null); + assertTrue(res); + res = touches.execute(polyline2, polygon1, sr, null); + assertTrue(res); + + str1 = "{\"rings\":[[[10,10],[10,0],[0,0],[0,10],[10,10]],[[1,1],[9,1],[9,9],[1,9],[1,1],[1,1]]]}"; + str2 = "{\"paths\":[[[15,5],[5,15],[15,15]]]}"; + + polygon1 = (Polygon) (TestCommonMethods.fromJson(str1).getGeometry()); + polyline2 = (Polyline) (TestCommonMethods.fromJson(str2).getGeometry()); + wiggleGeometry(polygon1, tolerance, 1982); + wiggleGeometry(polyline2, tolerance, 511); + + res = touches.execute(polygon1, polyline2, sr, null); + assertTrue(res); + res = touches.execute(polyline2, polygon1, sr, null); + assertTrue(res); + } + + @Test + public void testPolylinePolylineTouches() { + OperatorTouches touches = (OperatorTouches) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Touches)); + SpatialReference sr = SpatialReference.create(102100); + double tolerance = sr + .getTolerance(VertexDescription.Semantics.POSITION); + + // Polyline1 and Polyline2 touch at a point + String str1 = "{\"paths\":[[[0,0],[0,5],[0,10],[10,10],[10,0]],[[1,1],[9,1],[9,9],[1,9],[1,1],[1,1]]]}"; + String str2 = "{\"paths\":[[[10,10],[10,15],[15,15],[15,10]]]}"; + + Polyline polyline1 = (Polyline) (TestCommonMethods.fromJson(str1) + .getGeometry()); + Polyline polyline2 = (Polyline) (TestCommonMethods.fromJson(str2) + .getGeometry()); + + boolean res = touches.execute(polyline1, polyline2, sr, null); + assertTrue(res); + res = touches.execute(polyline2, polyline1, sr, null); + assertTrue(res); + + // Polyline1 and Polyline2 overlap along the boundary + str1 = "{\"paths\":[[[0,0],[0,5],[0,10],[10,10],[10,0],[0,0]],[[1,1],[9,1],[9,9],[1,9],[1,1],[1,1]]]}"; + str2 = "{\"paths\":[[[10,0],[10,10],[15,10],[15,0],[10,0]]]}"; + + polyline1 = (Polyline) (TestCommonMethods.fromJson(str1).getGeometry()); + polyline2 = (Polyline) (TestCommonMethods.fromJson(str2).getGeometry()); + + res = touches.execute(polyline1, polyline2, sr, null); + assertTrue(!res); + res = touches.execute(polyline2, polyline1, sr, null); + assertTrue(!res); + + // Polyline1 and Polyline2 intersect at interiors + str1 = "{\"paths\":[[[0,0],[0,5],[0,10],[10,10],[10,0],[0,0]],[[1,1],[9,1],[9,9],[1,9],[1,1],[1,1]]]}"; + str2 = "{\"paths\":[[[15,5],[5,15],[15,15],[15,5]]]}"; + + polyline1 = (Polyline) (TestCommonMethods.fromJson(str1).getGeometry()); + polyline2 = (Polyline) (TestCommonMethods.fromJson(str2).getGeometry()); + + res = touches.execute(polyline1, polyline2, sr, null); + assertTrue(!res); + res = touches.execute(polyline2, polyline1, sr, null); + assertTrue(!res); + + // Polyline1 and Polyline2 touch at an endpoint of Polyline1 and + // interior of Polyline2 (but Polyline1 is closed) + str1 = "{\"paths\":[[[10,10],[10,0],[0,0],[0,10],[10,10]],[[1,1],[9,1],[9,9],[1,9],[1,1],[1,1]]]}"; + str2 = "{\"paths\":[[[15,5],[5,15],[15,15]]]}"; + + polyline1 = (Polyline) (TestCommonMethods.fromJson(str1).getGeometry()); + polyline2 = (Polyline) (TestCommonMethods.fromJson(str2).getGeometry()); + + res = touches.execute(polyline1, polyline2, sr, null); + assertTrue(!res); + res = touches.execute(polyline2, polyline1, sr, null); + assertTrue(!res); + + // Polyline1 and Polyline2 touch at an endpoint of Polyline1 and + // interior of Polyline2 (same as previous case, but Polyline1 is not + // closed) + str1 = "{\"paths\":[[[10,10],[10,0],[0,0],[0,10]],[[1,1],[9,1],[9,9],[1,9],[1,1],[1,1]]]}"; + str2 = "{\"paths\":[[[15,5],[5,15],[15,15]]]}"; + + polyline1 = (Polyline) (TestCommonMethods.fromJson(str1).getGeometry()); + polyline2 = (Polyline) (TestCommonMethods.fromJson(str2).getGeometry()); + + res = touches.execute(polyline1, polyline2, sr, null); + assertTrue(res); + res = touches.execute(polyline2, polyline1, sr, null); + assertTrue(res); + + str1 = "{\"paths\":[[[10,10],[10,0],[0,0],[0,10]],[[1,1],[9,1],[9,9],[1,9],[6, 9]]]}"; + str2 = "{\"paths\":[[[15,5],[5,15],[15,15],[15,5]]]}"; + + polyline1 = (Polyline) (TestCommonMethods.fromJson(str1).getGeometry()); + polyline2 = (Polyline) (TestCommonMethods.fromJson(str2).getGeometry()); + + res = touches.execute(polyline1, polyline2, sr, null); + assertTrue(res); + res = touches.execute(polyline2, polyline1, sr, null); + assertTrue(res); + + polyline1.setEmpty(); + polyline2.setEmpty(); + + polyline1.startPath(-2, -2); + polyline1.lineTo(-1, -1); + polyline1.lineTo(1, 1); + polyline1.lineTo(2, 2); + + polyline2.startPath(-2, 2); + polyline2.lineTo(-1, 1); + polyline2.lineTo(1, -1); + polyline2.lineTo(2, -2); + + res = touches.execute(polyline2, polyline1, sr, null); + assertTrue(!res); + + polyline1.setEmpty(); + polyline2.setEmpty(); + + polyline1.startPath(-2, -2); + polyline1.lineTo(-1, -1); + polyline1.lineTo(1, 1); + polyline1.lineTo(2, 2); + + polyline2.startPath(-2, 2); + polyline2.lineTo(-1, 1); + polyline2.lineTo(1, -1); + + res = touches.execute(polyline1, polyline2, sr, null); + assertTrue(!res); + + polyline1.setEmpty(); + polyline2.setEmpty(); + + polyline1.startPath(-1, -1); + polyline1.lineTo(0, 0); + polyline1.lineTo(1, 1); + + polyline2.startPath(-1, 1); + polyline2.lineTo(0, 0); + polyline2.lineTo(1, -1); + + res = touches.execute(polyline2, polyline1, sr, null); + assertTrue(!res); + + polyline1.setEmpty(); + polyline2.setEmpty(); + polyline1.startPath(0, 0); + polyline1.lineTo(0, 1); + polyline1.lineTo(0, 0); + polyline2.startPath(0, 1); + polyline2.lineTo(0, 2); + polyline2.lineTo(0, 1); + + res = touches.execute(polyline2, polyline1, sr, null); + assertTrue(!res); + + res = touches.execute(polyline1, polyline2, sr, null); + assertTrue(!res); + } + + @Test + public void testPolylineMultiPointTouches() { + OperatorTouches touches = (OperatorTouches) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Touches)); + SpatialReference sr = SpatialReference.create(102100); + @SuppressWarnings("unused") + double tolerance = sr + .getTolerance(VertexDescription.Semantics.POSITION); + + Polyline polyline1 = new Polyline(); + MultiPoint multipoint2 = new MultiPoint(); + + polyline1.startPath(0, 0); + polyline1.lineTo(2, 0); + polyline1.lineTo(4, 2); + + multipoint2.add(1, 1); + multipoint2.add(2, 2); + multipoint2.add(3, 0); + + boolean res = touches.execute(polyline1, multipoint2, sr, null); + assertTrue(!res); + res = touches.execute(multipoint2, polyline1, sr, null); + assertTrue(!res); + + polyline1.startPath(1, -4); + polyline1.lineTo(1, -3); + polyline1.lineTo(1, -2); + polyline1.lineTo(1, -1); + polyline1.lineTo(1, 0); + polyline1.lineTo(1, 1); + + touches.accelerateGeometry(polyline1, sr, + Geometry.GeometryAccelerationDegree.enumHot); + res = touches.execute(polyline1, multipoint2, sr, null); + assertTrue(res); + res = touches.execute(multipoint2, polyline1, sr, null); + assertTrue(res); + + multipoint2.add(3, 1); + res = touches.execute(polyline1, multipoint2, sr, null); + assertTrue(!res); + res = touches.execute(multipoint2, polyline1, sr, null); + assertTrue(!res); + + polyline1.startPath(0, 0); + polyline1.lineTo(2, 0); + + polyline1.startPath(2, 1); + polyline1.lineTo(2, -1); + + multipoint2.add(2, 0); + + res = touches.execute(polyline1, multipoint2, sr, null); + assertTrue(!res); + res = touches.execute(multipoint2, polyline1, sr, null); + assertTrue(!res); + } + + @Test + public void testPolylineMultiPointCrosses() { + OperatorCrosses crosses = (OperatorCrosses) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Crosses)); + SpatialReference sr = SpatialReference.create(102100); + double tolerance = sr + .getTolerance(VertexDescription.Semantics.POSITION); + + Polyline polyline1 = new Polyline(); + MultiPoint multipoint2 = new MultiPoint(); + + polyline1.startPath(0, 0); + polyline1.lineTo(2, 0); + polyline1.lineTo(4, 2); + + multipoint2.add(1, 1); + multipoint2.add(2, 2); + multipoint2.add(3, 0); + multipoint2.add(0, 0); + + boolean res = crosses.execute(polyline1, multipoint2, sr, null); + assertTrue(!res); + res = crosses.execute(multipoint2, polyline1, sr, null); + assertTrue(!res); + + polyline1.startPath(1, -4); + polyline1.lineTo(1, -3); + polyline1.lineTo(1, -2); + polyline1.lineTo(1, -1); + polyline1.lineTo(1, 0); + polyline1.lineTo(1, 1); + + res = crosses.execute(polyline1, multipoint2, sr, null); + assertTrue(!res); + res = crosses.execute(multipoint2, polyline1, sr, null); + assertTrue(!res); + + crosses.accelerateGeometry(polyline1, sr, + Geometry.GeometryAccelerationDegree.enumHot); + + multipoint2.add(1, 0); + res = crosses.execute(polyline1, multipoint2, sr, null); + assertTrue(res); + res = crosses.execute(multipoint2, polyline1, sr, null); + assertTrue(res); + + multipoint2.add(3, 1); + res = crosses.execute(polyline1, multipoint2, sr, null); + assertTrue(res); + res = crosses.execute(multipoint2, polyline1, sr, null); + assertTrue(res); + } + + @Test + public void testPolylinePointTouches() { + OperatorTouches touches = (OperatorTouches) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Touches)); + SpatialReference sr = SpatialReference.create(102100); + @SuppressWarnings("unused") + double tolerance = sr + .getTolerance(VertexDescription.Semantics.POSITION); + + Polyline polyline1 = new Polyline(); + Point point2 = new Point(); + + polyline1.startPath(0, 0); + polyline1.lineTo(2, 0); + + polyline1.startPath(2, 1); + polyline1.lineTo(2, -1); + + point2.setXY(2, 0); + + boolean res = touches.execute(polyline1, point2, sr, null); + assertTrue(res); + res = touches.execute(point2, polyline1, sr, null); + assertTrue(res); + } + + @Test + public void testPolygonPolygonOverlaps() { + OperatorOverlaps overlaps = (OperatorOverlaps) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Overlaps)); + SpatialReference sr = SpatialReference.create(102100); + double tolerance = sr + .getTolerance(VertexDescription.Semantics.POSITION); + + // Polygon1 and Polygon2 touch at a point + String str1 = "{\"rings\":[[[0,0],[0,5],[0,10],[10,10],[10,0],[0,0]],[[1,1],[9,1],[9,9],[1,9],[1,1],[1,1]]]}"; + String str2 = "{\"rings\":[[[10,10],[10,15],[15,15],[15,10],[10,10]]]}"; + + Polygon polygon1 = (Polygon) (TestCommonMethods.fromJson(str1) + .getGeometry()); + Polygon polygon2 = (Polygon) (TestCommonMethods.fromJson(str2) + .getGeometry()); + wiggleGeometry(polygon1, tolerance, 1982); + wiggleGeometry(polygon2, tolerance, 511); + + boolean res = overlaps.execute(polygon1, polygon2, sr, null); + assertTrue(!res); + res = overlaps.execute(polygon2, polygon1, sr, null); + assertTrue(!res); + + // Polygon1 and Polygon2 touch along the boundary + str1 = "{\"rings\":[[[0,0],[0,5],[0,10],[10,10],[10,0],[0,0]],[[1,1],[9,1],[9,9],[1,9],[1,1],[1,1]]]}"; + str2 = "{\"rings\":[[[10,0],[10,10],[15,10],[15,0],[10,0]]]}"; + + polygon1 = (Polygon) (TestCommonMethods.fromJson(str1).getGeometry()); + polygon2 = (Polygon) (TestCommonMethods.fromJson(str2).getGeometry()); + wiggleGeometry(polygon1, tolerance, 1982); + wiggleGeometry(polygon2, tolerance, 511); + + res = overlaps.execute(polygon1, polygon2, sr, null); + assertTrue(!res); + res = overlaps.execute(polygon2, polygon1, sr, null); + assertTrue(!res); + + // Polygon1 and Polygon2 touch at a corner of Polygon1 and a diagonal of + // Polygon2 + str1 = "{\"rings\":[[[0,0],[0,5],[0,10],[10,10],[10,0],[0,0]],[[1,1],[9,1],[9,9],[1,9],[1,1],[1,1]]]}"; + str2 = "{\"rings\":[[[15,5],[5,15],[15,15],[15,5]]]}"; + + polygon1 = (Polygon) (TestCommonMethods.fromJson(str1).getGeometry()); + polygon2 = (Polygon) (TestCommonMethods.fromJson(str2).getGeometry()); + wiggleGeometry(polygon1, tolerance, 1982); + wiggleGeometry(polygon2, tolerance, 511); + + res = overlaps.execute(polygon1, polygon2, sr, null); + assertTrue(!res); + res = overlaps.execute(polygon2, polygon1, sr, null); + assertTrue(!res); + + // Polygon1 and Polygon2 overlap at the upper right corner + str1 = "{\"rings\":[[[0,0],[0,5],[0,10],[10,10],[10,0],[0,0]],[[1,1],[9,1],[9,9],[1,9],[1,1],[1,1]]]}"; + str2 = "{\"rings\":[[[5,5],[5,15],[15,15],[15,5],[5,5]]]}"; + + polygon1 = (Polygon) (TestCommonMethods.fromJson(str1).getGeometry()); + polygon2 = (Polygon) (TestCommonMethods.fromJson(str2).getGeometry()); + + res = overlaps.execute(polygon1, polygon2, sr, null); + assertTrue(res); + res = overlaps.execute(polygon2, polygon1, sr, null); + assertTrue(res); + + str1 = "{\"rings\":[[[0,0],[0,5],[0,10],[10,10],[10,0],[0,0]],[[4,4],[6,4],[6,6],[4,6],[4,4],[4,4]]]}"; + str2 = "{\"rings\":[[[1,1],[1,9],[9,9],[9,1],[1,1]]]}"; + + polygon1 = (Polygon) (TestCommonMethods.fromJson(str1).getGeometry()); + polygon2 = (Polygon) (TestCommonMethods.fromJson(str2).getGeometry()); + + res = overlaps.execute(polygon1, polygon2, sr, null); + assertTrue(res); + res = overlaps.execute(polygon2, polygon1, sr, null); + assertTrue(res); + } + + @Test + public void testPolygonPolylineWithin() { + OperatorWithin within = (OperatorWithin) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Within)); + SpatialReference sr = SpatialReference.create(102100); + @SuppressWarnings("unused") + double tolerance = sr + .getTolerance(VertexDescription.Semantics.POSITION); + + Polygon polygon1 = new Polygon(); + Polyline polyline2 = new Polyline(); + + polygon1.startPath(0, 0); + polygon1.lineTo(0, 10); + polygon1.lineTo(10, 10); + polygon1.lineTo(10, 0); + + polyline2.startPath(5, 0); + polyline2.lineTo(5, 10); + + boolean res = within.execute(polygon1, polyline2, sr, null); + assertTrue(!res); + res = within.execute(polyline2, polygon1, sr, null); + assertTrue(res); + + polyline2.setEmpty(); + polyline2.startPath(0, 1); + polyline2.lineTo(0, 9); + + res = within.execute(polyline2, polygon1, sr, null); + assertTrue(!res); + } + + @Test + public void testMultiPointMultiPointWithin() { + OperatorWithin within = (OperatorWithin) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Within)); + SpatialReference sr = SpatialReference.create(102100); + @SuppressWarnings("unused") + double tolerance = sr + .getTolerance(VertexDescription.Semantics.POSITION); + + MultiPoint multipoint1 = new MultiPoint(); + MultiPoint multipoint2 = new MultiPoint(); + + multipoint1.add(0, 0); + multipoint1.add(3, 3); + multipoint1.add(0, 0); + multipoint1.add(5, 5); + multipoint1.add(3, 3); + multipoint1.add(2, 4); + multipoint1.add(2, 8); + + multipoint2.add(0, 0); + multipoint2.add(3, 3); + multipoint2.add(2, 4); + multipoint2.add(2, 8); + multipoint2.add(5, 5); + + boolean res = within.execute(multipoint1, multipoint2, sr, null); + assertTrue(res); + res = within.execute(multipoint2, multipoint1, sr, null); + assertTrue(res); + + multipoint2.add(10, 10); + multipoint2.add(10, 10); + + res = within.execute(multipoint1, multipoint2, sr, null); + assertTrue(res); + res = within.execute(multipoint2, multipoint1, sr, null); + assertTrue(!res); + + multipoint1.add(10, 10); + res = within.execute(multipoint1, multipoint2, sr, null); + assertTrue(res); + res = within.execute(multipoint2, multipoint1, sr, null); + assertTrue(res); + + multipoint1.add(-10, -10); + res = within.execute(multipoint1, multipoint2, sr, null); + assertTrue(!res); + res = within.execute(multipoint2, multipoint1, sr, null); + assertTrue(res); + } + + @Test + public void testPolylinePolylineOverlaps() { + OperatorOverlaps overlaps = (OperatorOverlaps) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Overlaps)); + SpatialReference sr = SpatialReference.create(102100); + double tolerance = sr + .getTolerance(VertexDescription.Semantics.POSITION); + + Polyline polyline1 = new Polyline(); + Polyline polyline2 = new Polyline(); + polyline1.startPath(0, 0); + polyline1.lineTo(2, 0); + polyline2.startPath(1, 0); + polyline2.lineTo(3, 0); + polyline2.lineTo(1, 1); + polyline2.lineTo(1, -1); + wiggleGeometry(polyline1, tolerance, 1982); + wiggleGeometry(polyline2, tolerance, 511); + + boolean res = overlaps.execute(polyline1, polyline2, sr, null); + assertTrue(res); + res = overlaps.execute(polyline2, polyline1, sr, null); + assertTrue(res); + + polyline1.setEmpty(); + polyline2.setEmpty(); + polyline1.startPath(0, 0); + polyline1.lineTo(2, 0); + polyline2.startPath(1.9989, 0); + polyline2.lineTo(2.0011, 0); + // wiggleGeometry(polyline1, tolerance, 1982); + // wiggleGeometry(polyline2, tolerance, 511); + + res = overlaps.execute(polyline1, polyline2, sr, null); + assertTrue(res); + res = overlaps.execute(polyline2, polyline1, sr, null); + assertTrue(res); + + polyline1.setEmpty(); + polyline2.setEmpty(); + polyline1.startPath(0, 0); + polyline1.lineTo(2, 0); + polyline2.startPath(1.9989, 0); + polyline2.lineTo(2.0009, 0); + wiggleGeometry(polyline1, tolerance, 1982); + wiggleGeometry(polyline2, tolerance, 511); + + res = overlaps.execute(polyline1, polyline2, sr, null); + assertTrue(!res); + res = overlaps.execute(polyline2, polyline1, sr, null); + assertTrue(!res); + + polyline1.setEmpty(); + polyline2.setEmpty(); + polyline1.startPath(0, 0); + polyline1.lineTo(2, 0); + polyline2.startPath(0, 0); + polyline2.lineTo(2, 0); + polyline2.startPath(0, -1); + polyline2.lineTo(2, -1); + + res = overlaps.execute(polyline1, polyline2, sr, null); + assertTrue(!res); + res = overlaps.execute(polyline2, polyline1, sr, null); + assertTrue(!res); + } + + @Test + public void testMultiPointMultiPointOverlaps() { + OperatorOverlaps overlaps = (OperatorOverlaps) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Overlaps)); + SpatialReference sr = SpatialReference.create(102100); + @SuppressWarnings("unused") + double tolerance = sr + .getTolerance(VertexDescription.Semantics.POSITION); + + MultiPoint multipoint1 = new MultiPoint(); + MultiPoint multipoint2 = new MultiPoint(); + + multipoint1.add(4, 4); + multipoint1.add(6, 4); + + multipoint2.add(6, 2); + multipoint2.add(2, 6); + + boolean res = overlaps.execute(multipoint1, multipoint2, sr, null); + assertTrue(!res); + res = overlaps.execute(multipoint2, multipoint1, sr, null); + assertTrue(!res); + + multipoint1.add(10, 10); + multipoint2.add(6, 2); + + res = overlaps.execute(multipoint1, multipoint2, sr, null); + assertTrue(!res); + res = overlaps.execute(multipoint2, multipoint1, sr, null); + assertTrue(!res); + + multipoint1.add(6, 2); + res = overlaps.execute(multipoint1, multipoint2, sr, null); + assertTrue(res); + res = overlaps.execute(multipoint2, multipoint1, sr, null); + assertTrue(res); + + multipoint1.add(2, 6); + res = overlaps.execute(multipoint1, multipoint2, sr, null); + assertTrue(!res); + res = overlaps.execute(multipoint2, multipoint1, sr, null); + assertTrue(!res); + + multipoint2.add(1, 1); + res = overlaps.execute(multipoint1, multipoint2, sr, null); + assertTrue(res); + res = overlaps.execute(multipoint2, multipoint1, sr, null); + assertTrue(res); + + multipoint2.add(10, 10); + multipoint2.add(4, 4); + multipoint2.add(6, 4); + res = overlaps.execute(multipoint1, multipoint2, sr, null); + assertTrue(!res); + res = overlaps.execute(multipoint2, multipoint1, sr, null); + assertTrue(!res); + } + + @Test + public void testPolygonPolygonWithin() { + OperatorWithin within = (OperatorWithin) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Within)); + SpatialReference sr = SpatialReference.create(102100); + double tolerance = sr + .getTolerance(VertexDescription.Semantics.POSITION); + + // Polygon1 is within Polygon2 + String str1 = "{\"rings\":[[[0,0],[0,5],[0,10],[10,10],[10,0],[0,0]],[[1,1],[9,1],[9,9],[1,9],[1,1],[1,1]]]}"; + String str2 = "{\"rings\":[[[-1,-1],[-1,11],[11,11],[11,-1],[-1,-1]]]}"; + + Polygon polygon1 = (Polygon) (TestCommonMethods.fromJson(str1) + .getGeometry()); + Polygon polygon2 = (Polygon) (TestCommonMethods.fromJson(str2) + .getGeometry()); + + boolean res = within.execute(polygon1, polygon2, sr, null); + assertTrue(res); + res = within.execute(polygon2, polygon1, sr, null); + assertTrue(!res); + + // Polygon1 is within Polygon2, and the boundaries intersect + str1 = "{\"rings\":[[[0,0],[0,5],[0,10],[10,10],[10,0],[0,0]],[[4,4],[6,4],[6,6],[4,6],[4,4],[4,4]]]}"; + str2 = "{\"rings\":[[[1,1],[1,9],[9,9],[9,1],[1,1]]]}"; + + polygon1 = (Polygon) (TestCommonMethods.fromJson(str1).getGeometry()); + polygon2 = (Polygon) (TestCommonMethods.fromJson(str2).getGeometry()); + wiggleGeometry(polygon1, tolerance, 1982); + wiggleGeometry(polygon2, tolerance, 511); + + res = within.execute(polygon2, polygon1, sr, null); + assertTrue(!res); + + // Polygon1 is within Polygon2, and the boundaries intersect + str1 = "{\"rings\":[[[0,0],[0,5],[0,10],[10,10],[10,0],[0,0]],[[1,1],[9,1],[9,9],[1,9],[1,1],[1,1]]]}"; + str2 = "{\"rings\":[[[-1,0],[-1,11],[11,11],[11,0],[-1,0]]]}"; + + polygon1 = (Polygon) (TestCommonMethods.fromJson(str1).getGeometry()); + polygon2 = (Polygon) (TestCommonMethods.fromJson(str2).getGeometry()); + wiggleGeometry(polygon1, tolerance, 1982); + wiggleGeometry(polygon2, tolerance, 511); + + res = within.execute(polygon1, polygon2, sr, null); + assertTrue(res); + + // Polygon2 is inside of the hole of polygon1 + str1 = "{\"rings\":[[[0,0],[0,5],[0,10],[10,10],[10,0],[0,0]],[[1,1],[9,1],[9,9],[1,9],[1,1],[1,1]]]}"; + str2 = "{\"rings\":[[[2,2],[2,8],[8,8],[8,2],[2,2]]]}"; + + polygon1 = (Polygon) (TestCommonMethods.fromJson(str1).getGeometry()); + polygon2 = (Polygon) (TestCommonMethods.fromJson(str2).getGeometry()); + + res = within.execute(polygon2, polygon1, sr, null); + assertTrue(!res); + + str1 = "{\"rings\":[[[0,0],[10,0],[10,10],[0,10]]]}"; + str2 = "{\"rings\":[[[2,2],[2,8],[8,8],[8,2],[2,2],[8,2],[8,8],[2,8],[2,2]]]}"; + + polygon1 = (Polygon) (TestCommonMethods.fromJson(str1).getGeometry()); + polygon2 = (Polygon) (TestCommonMethods.fromJson(str2).getGeometry()); + + res = within.execute(polygon2, polygon1, sr, null); + assertTrue(res); + + str1 = "{\"rings\":[[[0,0],[0,10],[10,10],[10,0]],[[12,8],[12,10],[18,10],[18,8],[12,8]]]}"; + str2 = "{\"paths\":[[[2,2],[2,8],[8,8],[8,2]],[[12,2],[12,4],[18,4],[18,2]]]}"; + + polygon1 = (Polygon) (TestCommonMethods.fromJson(str1).getGeometry()); + Polyline polyline2 = (Polyline) (TestCommonMethods.fromJson(str2).getGeometry()); + + res = within.execute(polyline2, polygon1, sr, null); + assertTrue(!res); + + str1 = "{\"rings\":[[[0,0],[0,10],[10,10],[10,0],[0,0]],[[4,4],[6,4],[6,6],[4,6],[4,4]]]}"; + str2 = "{\"rings\":[[[2,2],[2,8],[8,8],[8,2],[2,2],[2,8],[8,8],[8,2],[2,2]]]}"; + + polygon1 = (Polygon) (TestCommonMethods.fromJson(str1).getGeometry()); + polygon2 = (Polygon) (TestCommonMethods.fromJson(str2).getGeometry()); + + res = within.execute(polygon2, polygon1, sr, null); + assertTrue(res); + + // Same as above, but winding fill rule + str1 = "{\"rings\":[[[0,0],[0,10],[10,10],[10,0],[0,0]],[[4,4],[6,4],[6,6],[4,6],[4,4]]]}"; + str2 = "{\"rings\":[[[2,2],[2,8],[8,8],[8,2],[2,2],[2,8],[8,8],[8,2],[2,2]]]}"; + polygon1 = (Polygon) (TestCommonMethods.fromJson(str1).getGeometry()); + polygon2 = (Polygon) (TestCommonMethods.fromJson(str2).getGeometry()); + polygon1.setFillRule(Polygon.FillRule.enumFillRuleWinding); + polygon2.setFillRule(Polygon.FillRule.enumFillRuleWinding); + + res = within.execute(polygon2, polygon1, sr, null); + assertTrue(!res); + + str1 = "{\"rings\":[[[0,0],[0,10],[10,10],[10,0],[0,0]]]}"; + str2 = "{\"paths\":[[[2,2],[2,2]]]}"; + polygon1 = (Polygon) (TestCommonMethods.fromJson(str1).getGeometry()); + polyline2 = (Polyline) (TestCommonMethods.fromJson(str2).getGeometry()); + res = within.execute(polyline2, polygon1, sr, null); + assertTrue(res); + + str1 = "{\"rings\":[[[0,0],[0,10],[10,10],[10,0],[0,0]],[[11,11],[11,20],[20,20],[20,11],[11,11]]]}"; + str2 = "{\"rings\":[[[2,2],[2,8],[8,8],[15,15],[8,8],[8,2],[2,2]]]}"; + polygon1 = (Polygon) (TestCommonMethods.fromJson(str1).getGeometry()); + polygon2 = (Polygon) (TestCommonMethods.fromJson(str2).getGeometry()); + + res = within.execute(polygon2, polygon1, sr, null); + assertTrue(!res); + + str1 = "{\"rings\":[[[0,0],[0,10],[10,10],[10,0],[0,0]],[[10,10],[10,20],[20,20],[20,10],[10,10]]]}"; + str2 = "{\"rings\":[[[2,2],[2,8],[8,8],[15,15],[8,8],[8,2],[2,2]]]}"; + polygon1 = (Polygon) (TestCommonMethods.fromJson(str1).getGeometry()); + polygon2 = (Polygon) (TestCommonMethods.fromJson(str2).getGeometry()); + + res = within.execute(polygon2, polygon1, sr, null); + assertTrue(res); + + str1 = "{\"rings\":[[[0,0],[0,10],[10,10],[10,0],[0,0]]]}"; + str2 = "{\"rings\":[[[9.9999999925,4],[9.9999999925,6],[10.0000000075,6],[10.0000000075,4],[9.9999999925,4]]]}"; + polygon1 = (Polygon) (TestCommonMethods.fromJson(str1).getGeometry()); + polygon2 = (Polygon) (TestCommonMethods.fromJson(str2).getGeometry()); + + res = within.execute(polygon2, polygon1, sr, null); + assertTrue(!res); + + res = OperatorOverlaps.local().execute(polygon1, polygon2, sr, null); + assertTrue(!res); + + res = OperatorTouches.local().execute(polygon1, polygon2, sr, null); + assertTrue(res); + + str1 = "{\"rings\":[[[0,0],[0,10],[10,10],[10,0],[0,0]],[[10,10],[10,20],[20,20],[20,10],[10,10]]]}"; + str2 = "{\"rings\":[[[2,2],[2,8],[8,8],[15,15],[8,8],[8,2],[2,2]],[[15,5],[15,5],[15,5]]]}"; + polygon1 = (Polygon) (TestCommonMethods.fromJson(str1).getGeometry()); + polygon2 = (Polygon) (TestCommonMethods.fromJson(str2).getGeometry()); + res = within.execute(polygon2, polygon1, sr, null); + assertTrue(!res); + + str1 = "{\"rings\":[[[0,0],[0,10],[10,10],[10,0],[0,0]]]}"; + str2 = "{\"rings\":[[[2,2],[2,2],[2,2]],[[3,3],[3,3],[3,3]]]}"; + polygon1 = (Polygon) (TestCommonMethods.fromJson(str1).getGeometry()); + polygon2 = (Polygon) (TestCommonMethods.fromJson(str2).getGeometry()); + res = within.execute(polygon2, polygon1, sr, null); + assertTrue(res); + + str1 = "{\"rings\":[[[0,0],[0,10],[10,10],[10,0],[0,0]]]}"; + str2 = "{\"rings\":[[[2,2],[2,2],[2,2],[2,2]],[[3,3],[3,3],[3,3],[3,3]]]}"; + polygon1 = (Polygon) (TestCommonMethods.fromJson(str1).getGeometry()); + polygon2 = (Polygon) (TestCommonMethods.fromJson(str2).getGeometry()); + res = within.execute(polygon2, polygon1, sr, null); + assertTrue(res); + + str1 = "{\"rings\":[[[0,0],[0,10],[10,10],[10,0],[0,0]]]}"; + str2 = "{\"paths\":[[[2,2],[2,2]],[[3,3],[3,3]]]}"; + polygon1 = (Polygon) (TestCommonMethods.fromJson(str1).getGeometry()); + polyline2 = (Polyline) (TestCommonMethods.fromJson(str2).getGeometry()); + res = within.execute(polyline2, polygon1, sr, null); + assertTrue(res); + + str1 = "{\"rings\":[[[0,0],[0,10],[10,10],[10,0],[0,0]],[[10,10],[10,20],[20,20],[20,10],[10,10]]]}"; + str2 = "{\"paths\":[[[2,2],[2,8]],[[15,5],[15,5]]]}"; + polygon1 = (Polygon) (TestCommonMethods.fromJson(str1).getGeometry()); + polyline2 = (Polyline) (TestCommonMethods.fromJson(str2).getGeometry()); + res = within.execute(polyline2, polygon1, sr, null); + assertTrue(!res); + + str1 = "{\"rings\":[[[0,0],[0,10],[10,10],[10,0],[0,0]],[[10,10],[10,20],[20,20],[20,10],[10,10]]]}"; + str2 = "{\"paths\":[[[2,2],[2,8]],[[15,5],[15,5],[15,5],[15,5]]]}"; + polygon1 = (Polygon) (TestCommonMethods.fromJson(str1).getGeometry()); + polyline2 = (Polyline) (TestCommonMethods.fromJson(str2).getGeometry()); + res = within.execute(polyline2, polygon1, sr, null); + assertTrue(!res); + + str1 = "{\"rings\":[[[0,0],[0,10],[10,10],[10,0],[0,0]],[[10,10],[10,20],[20,20],[20,10],[10,10]]]}"; + str2 = "{\"paths\":[[[2,2],[2,2]],[[15,5],[15,6]]]}"; + polygon1 = (Polygon) (TestCommonMethods.fromJson(str1).getGeometry()); + polyline2 = (Polyline) (TestCommonMethods.fromJson(str2).getGeometry()); + res = within.execute(polyline2, polygon1, sr, null); + assertTrue(!res); + + str1 = "{\"rings\":[[[0,0],[0,10],[10,10],[10,0],[0,0]],[[10,10],[10,20],[20,20],[20,10],[10,10]]]}"; + str2 = "{\"paths\":[[[2,2],[2,2],[2,2],[2,2]],[[15,5],[15,6]]]}"; + polygon1 = (Polygon) (TestCommonMethods.fromJson(str1).getGeometry()); + polyline2 = (Polyline) (TestCommonMethods.fromJson(str2).getGeometry()); + res = within.execute(polyline2, polygon1, sr, null); + assertTrue(!res); + } + + @Test + public void testPolylinePolylineWithin() { + OperatorWithin within = (OperatorWithin) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Within)); + OperatorContains contains = (OperatorContains) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Contains)); + SpatialReference sr = SpatialReference.create(102100); + @SuppressWarnings("unused") + double tolerance = sr + .getTolerance(VertexDescription.Semantics.POSITION); + + Polyline polyline1 = new Polyline(); + Polyline polyline2 = new Polyline(); + + polyline1.setEmpty(); + polyline2.setEmpty(); + polyline1.startPath(0, 0); + polyline1.lineTo(2, 0); + polyline2.startPath(1.9989, 0); + polyline2.lineTo(2.0011, 0); + + boolean res = within.execute(polyline2, polyline1, sr, null); + assertTrue(!res); + + res = contains.execute(polyline1, polyline2, sr, null); + assertTrue(!res); + + polyline1.setEmpty(); + polyline2.setEmpty(); + polyline1.startPath(0, 0); + polyline1.lineTo(2, 0); + polyline2.startPath(1.9989, 0); + polyline2.lineTo(2.001, 0); + + res = within.execute(polyline2, polyline1, sr, null); + assertTrue(res); + + res = contains.execute(polyline1, polyline2, sr, null); + assertTrue(res); + + polyline1.setEmpty(); + polyline2.setEmpty(); + polyline1.startPath(0, 0); + polyline1.lineTo(2, 0); + polyline1.lineTo(3, 0); + polyline1.lineTo(4, 0); + polyline1.lineTo(5, 0); + polyline1.lineTo(6, 0); + polyline1.lineTo(7, 0); + polyline1.lineTo(8, 0); + + polyline2.startPath(0, 0); + polyline2.lineTo(.1, 0); + polyline2.lineTo(.2, 0); + polyline2.lineTo(.4, 0); + polyline2.lineTo(1.1, 0); + polyline2.lineTo(2.5, 0); + + polyline2.startPath(2.7, 0); + polyline2.lineTo(4, 0); + + res = within.execute(polyline2, polyline1, sr, null); + assertTrue(res); + + res = contains.execute(polyline1, polyline2, sr, null); + assertTrue(res); + } + + @Test + public void testPolylineMultiPointWithin() { + OperatorWithin within = (OperatorWithin) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Within)); + SpatialReference sr = SpatialReference.create(102100); + @SuppressWarnings("unused") + double tolerance = sr + .getTolerance(VertexDescription.Semantics.POSITION); + + Polyline polyline1 = new Polyline(); + MultiPoint multipoint2 = new MultiPoint(); + + polyline1.startPath(0, 0); + polyline1.lineTo(2, 0); + polyline1.lineTo(4, 2); + + multipoint2.add(1, 0); + multipoint2.add(2, 0); + multipoint2.add(3, 1); + multipoint2.add(2, 0); + + boolean res = within.execute(polyline1, multipoint2, sr, null); + assertTrue(!res); + res = within.execute(multipoint2, polyline1, sr, null); + assertTrue(res); + + polyline1.startPath(1, -2); + polyline1.lineTo(1, -1); + polyline1.lineTo(1, 0); + polyline1.lineTo(1, 1); + + res = within.execute(polyline1, multipoint2, sr, null); + assertTrue(!res); + res = within.execute(multipoint2, polyline1, sr, null); + assertTrue(res); + + multipoint2.add(1, 2); + res = within.execute(multipoint2, polyline1, sr, null); + assertTrue(!res); + + multipoint2.add(-1, -1); + multipoint2.add(4, 2); + multipoint2.add(0, 0); + + res = within.execute(multipoint2, polyline1, sr, null); + assertTrue(!res); + } + + @Test + public void testPolygonMultiPointWithin() { + OperatorWithin within = (OperatorWithin) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Within)); + SpatialReference sr = SpatialReference.create(102100); + @SuppressWarnings("unused") + double tolerance = sr + .getTolerance(VertexDescription.Semantics.POSITION); + + Polygon polygon1 = new Polygon(); + MultiPoint multipoint2 = new MultiPoint(); + + polygon1.startPath(0, 0); + polygon1.lineTo(0, 10); + polygon1.lineTo(10, 10); + polygon1.lineTo(10, 0); + + multipoint2.add(5, 0); + multipoint2.add(5, 10); + multipoint2.add(5, 5); + + boolean res = within.execute(polygon1, multipoint2, sr, null); + assertTrue(!res); + res = within.execute(multipoint2, polygon1, sr, null); + assertTrue(res); + + multipoint2.add(5, 11); + res = within.execute(multipoint2, polygon1, sr, null); + assertTrue(!res); + } + + @Test + public void testPolygonPolylineCrosses() { + OperatorCrosses crosses = (OperatorCrosses) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Crosses)); + SpatialReference sr = SpatialReference.create(102100); + @SuppressWarnings("unused") + double tolerance = sr + .getTolerance(VertexDescription.Semantics.POSITION); + + Polygon polygon1 = new Polygon(); + Polyline polyline2 = new Polyline(); + + polygon1.startPath(0, 0); + polygon1.lineTo(0, 10); + polygon1.lineTo(10, 10); + polygon1.lineTo(10, 0); + + polyline2.startPath(5, -5); + polyline2.lineTo(5, 15); + + boolean res = crosses.execute(polygon1, polyline2, sr, null); + assertTrue(res); + res = crosses.execute(polyline2, polygon1, sr, null); + assertTrue(res); + + polyline2.setEmpty(); + polyline2.startPath(5, 0); + polyline2.lineTo(5, 10); + + res = crosses.execute(polygon1, polyline2, sr, null); + assertTrue(!res); + res = crosses.execute(polyline2, polygon1, sr, null); + assertTrue(!res); + + polygon1.setEmpty(); + polyline2.setEmpty(); + + polygon1.startPath(0, 0); + polygon1.lineTo(0, 10); + polygon1.lineTo(10, 10); + polygon1.lineTo(10, 8); + polygon1.lineTo(15, 5); + polygon1.lineTo(10, 2); + polygon1.lineTo(10, 0); + + polyline2.startPath(10, 15); + polyline2.lineTo(10, -5); + + res = crosses.execute(polygon1, polyline2, sr, null); + assertTrue(res); + res = crosses.execute(polyline2, polygon1, sr, null); + assertTrue(res); + } + + @Test + public void testPolylinePolylineCrosses() { + OperatorCrosses crosses = (OperatorCrosses) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Crosses)); + SpatialReference sr = SpatialReference.create(102100); + double tolerance = sr + .getTolerance(VertexDescription.Semantics.POSITION); + + // Polyline1 and Polyline2 touch at a point + String str1 = "{\"paths\":[[[0,0],[0,5],[0,10],[10,10],[10,0]],[[1,1],[9,1],[9,9],[1,9],[1,1],[1,1]]]}"; + String str2 = "{\"paths\":[[[10,10],[10,15],[15,15],[15,10]]]}"; + + Polyline polyline1 = (Polyline) (TestCommonMethods.fromJson(str1) + .getGeometry()); + Polyline polyline2 = (Polyline) (TestCommonMethods.fromJson(str2) + .getGeometry()); + + boolean res = crosses.execute(polyline1, polyline2, sr, null); + assertTrue(!res); + res = crosses.execute(polyline2, polyline1, sr, null); + assertTrue(!res); + + // Polyline1 and Polyline2 intersect at interiors + str1 = "{\"paths\":[[[0,0],[0,5],[0,10],[10,10],[10,0],[0,0]],[[1,1],[9,1],[9,9],[1,9],[1,1],[1,1]]]}"; + str2 = "{\"paths\":[[[15,5],[5,15],[15,15],[15,5]]]}"; + + polyline1 = (Polyline) (TestCommonMethods.fromJson(str1).getGeometry()); + polyline2 = (Polyline) (TestCommonMethods.fromJson(str2).getGeometry()); + + res = crosses.execute(polyline1, polyline2, sr, null); + assertTrue(res); + res = crosses.execute(polyline2, polyline1, sr, null); + assertTrue(res); + + // Polyline1 and Polyline2 touch at an endpoint of Polyline1 and + // interior of Polyline2 (but Polyline1 is closed) + str1 = "{\"paths\":[[[10,10],[10,0],[0,0],[0,10],[10,10]],[[1,1],[9,1],[9,9],[1,9],[1,1],[1,1]]]}"; + str2 = "{\"paths\":[[[15,5],[5,15],[15,15]]]}"; + + polyline1 = (Polyline) (TestCommonMethods.fromJson(str1).getGeometry()); + polyline2 = (Polyline) (TestCommonMethods.fromJson(str2).getGeometry()); + ; + + res = crosses.execute(polyline1, polyline2, sr, null); + assertTrue(res); + res = crosses.execute(polyline2, polyline1, sr, null); + assertTrue(res); + + // Polyline1 and Polyline2 touch at an endpoint of Polyline1 and + // interior of Polyline2 (same as previous case, but Polyline1 is not + // closed) + str1 = "{\"paths\":[[[10,10],[10,0],[0,0],[0,10]],[[1,1],[9,1],[9,9],[1,9],[1,1],[1,1]]]}"; + str2 = "{\"paths\":[[[15,5],[5,15],[15,15]]]}"; + + polyline1 = (Polyline) (TestCommonMethods.fromJson(str1).getGeometry()); + polyline2 = (Polyline) (TestCommonMethods.fromJson(str2).getGeometry()); + + res = crosses.execute(polyline1, polyline2, sr, null); + assertTrue(!res); + res = crosses.execute(polyline2, polyline1, sr, null); + assertTrue(!res); + + str1 = "{\"paths\":[[[10,11],[10,0],[0,0],[0,10]],[[1,1],[9,1],[9,9],[1,9],[6, 9]]]}"; + str2 = "{\"paths\":[[[15,5],[5,15],[15,15],[15,5]]]}"; + + polyline1 = (Polyline) (TestCommonMethods.fromJson(str1).getGeometry()); + polyline2 = (Polyline) (TestCommonMethods.fromJson(str2).getGeometry()); + + res = crosses.execute(polyline1, polyline2, sr, null); + assertTrue(res); + res = crosses.execute(polyline2, polyline1, sr, null); + assertTrue(res); + + polyline1.setEmpty(); + polyline2.setEmpty(); + + polyline1.startPath(-2, -2); + polyline1.lineTo(-1, -1); + polyline1.lineTo(1, 1); + polyline1.lineTo(2, 2); + + polyline2.startPath(-2, 2); + polyline2.lineTo(-1, 1); + polyline2.lineTo(1, -1); + polyline2.lineTo(2, -2); + + res = crosses.execute(polyline2, polyline1, sr, null); + assertTrue(res); + } + + @Test + public void testPolygonEnvelope() { + OperatorEquals equals = (OperatorEquals) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Equals)); + OperatorContains contains = (OperatorContains) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Contains)); + OperatorDisjoint disjoint = (OperatorDisjoint) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Disjoint)); + OperatorCrosses crosses = (OperatorCrosses) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Crosses)); + @SuppressWarnings("unused") + OperatorWithin within = (OperatorWithin) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Within)); + OperatorOverlaps overlaps = (OperatorOverlaps) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Overlaps)); + OperatorTouches touches = (OperatorTouches) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Touches)); + OperatorDensifyByLength densify = (OperatorDensifyByLength) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.DensifyByLength)); + SpatialReference sr = SpatialReference.create(4326); + + { + Polygon polygon = (Polygon) (TestCommonMethods + .fromJson("{\"rings\":[[[0,0],[0,5],[0,10],[10,10],[10,0],[0,0]]]}") + .getGeometry()); + Polygon densified = (Polygon) (densify.execute(polygon, 1.0, null)); + Envelope envelope = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":10}") + .getGeometry()); + wiggleGeometry(densified, 0.00000001, 1982); + wiggleGeometry(envelope, 0.00000001, 511); + assertTrue(equals.execute(envelope, densified, sr, null)); // they + // cover + // the + // same + // space + assertTrue(contains.execute(densified, envelope, sr, null)); + assertTrue(!disjoint.execute(envelope, densified, sr, null)); + assertTrue(!touches.execute(envelope, densified, sr, null)); + assertTrue(!overlaps.execute(envelope, densified, sr, null)); + assertTrue(!crosses.execute(envelope, densified, sr, null)); + } + + { + Polygon polygon = (Polygon) (TestCommonMethods + .fromJson("{\"rings\":[[[0,0],[0,5],[0,10],[10,10],[10,0],[0,0]]]}") + .getGeometry()); + Polygon densified = (Polygon) (densify.execute(polygon, 1.0, null)); + Envelope envelope = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":5,\"ymin\":0,\"xmax\":10,\"ymax\":10}") + .getGeometry()); + wiggleGeometry(densified, 0.00000001, 1982); + wiggleGeometry(envelope, 0.00000001, 511); + assertTrue(!equals.execute(envelope, densified, sr, null)); // the + // polygon + // contains + // the + // envelope, + // but + // they + // aren't + // equal + assertTrue(contains.execute(densified, envelope, sr, null)); + assertTrue(!disjoint.execute(envelope, densified, sr, null)); + assertTrue(!touches.execute(envelope, densified, sr, null)); + assertTrue(!overlaps.execute(envelope, densified, sr, null)); + assertTrue(!crosses.execute(envelope, densified, sr, null)); + } + + { + Polygon polygon = (Polygon) (TestCommonMethods + .fromJson("{\"rings\":[[[0,0],[0,5],[0,10],[10,10],[10,0],[0,0]]]}") + .getGeometry()); + Polygon densified = (Polygon) (densify.execute(polygon, 1.0, null)); + Envelope envelope = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":15,\"ymax\":10}") + .getGeometry()); + wiggleGeometry(densified, 0.00000001, 1982); + wiggleGeometry(envelope, 0.00000001, 511); + assertTrue(!equals.execute(envelope, densified, sr, null)); // the + // envelope + // sticks + // outside + // of + // the + // polygon + // but + // they + // intersect + assertTrue(!contains.execute(densified, envelope, sr, null)); + assertTrue(!disjoint.execute(envelope, densified, sr, null)); + assertTrue(!touches.execute(envelope, densified, sr, null)); + assertTrue(!overlaps.execute(envelope, densified, sr, null)); + assertTrue(!crosses.execute(envelope, densified, sr, null)); + } + + { + Polygon polygon = (Polygon) (TestCommonMethods + .fromJson("{\"rings\":[[[0,0],[0,5],[0,10],[10,10],[10,0],[0,0]]]}") + .getGeometry()); + Polygon densified = (Polygon) (densify.execute(polygon, 1.0, null)); + Envelope envelope = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":5,\"ymin\":0,\"xmax\":15,\"ymax\":10}") + .getGeometry()); + wiggleGeometry(densified, 0.00000001, 1982); + wiggleGeometry(envelope, 0.00000001, 511); + assertTrue(!equals.execute(envelope, densified, sr, null)); // the + // envelope + // sticks + // outside + // of + // the + // polygon + // but + // they + // intersect + // and + // overlap + assertTrue(!contains.execute(densified, envelope, sr, null)); + assertTrue(!disjoint.execute(envelope, densified, sr, null)); + assertTrue(!touches.execute(envelope, densified, sr, null)); + assertTrue(overlaps.execute(envelope, densified, sr, null)); + assertTrue(!crosses.execute(envelope, densified, sr, null)); + } + + { + Polygon polygon = (Polygon) (TestCommonMethods + .fromJson("{\"rings\":[[[0,0],[0,5],[0,10],[10,10],[10,0],[0,0]]]}") + .getGeometry()); + Polygon densified = (Polygon) (densify.execute(polygon, 1.0, null)); + Envelope envelope = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":10,\"ymin\":0,\"xmax\":15,\"ymax\":5}") + .getGeometry()); + wiggleGeometry(densified, 0.00000001, 1982); + wiggleGeometry(envelope, 0.00000001, 511); + assertTrue(!equals.execute(envelope, densified, sr, null)); // the + // envelope + // rides + // the + // side + // of + // the + // polygon + // (they + // touch) + assertTrue(!contains.execute(densified, envelope, sr, null)); + assertTrue(!disjoint.execute(envelope, densified, sr, null)); + assertTrue(touches.execute(envelope, densified, sr, null)); + assertTrue(!overlaps.execute(envelope, densified, sr, null)); + assertTrue(!crosses.execute(envelope, densified, sr, null)); + } + + { + Polygon polygon = (Polygon) (TestCommonMethods + .fromJson("{\"rings\":[[[0,0],[0,5],[0,10],[10,10],[10,0],[0,0]]]}") + .getGeometry()); + Polygon densified = (Polygon) (densify.execute(polygon, 1.0, null)); + Envelope envelope = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":10}") + .getGeometry()); + wiggleGeometry(densified, 0.00000001, 1982); + wiggleGeometry(envelope, 0.00000001, 511); + assertTrue(contains.execute(densified, envelope, sr, null)); // polygon + // and + // envelope + // cover + // the + // same + // space + assertTrue(!disjoint.execute(densified, envelope, sr, null)); + assertTrue(!touches.execute(envelope, densified, sr, null)); + assertTrue(!overlaps.execute(envelope, densified, sr, null)); + assertTrue(!crosses.execute(envelope, densified, sr, null)); + } + + { + Polygon polygon = (Polygon) (TestCommonMethods + .fromJson("{\"rings\":[[[0,0],[0,5],[0,10],[10,0],[0,0]]]}") + .getGeometry()); + Polygon densified = (Polygon) (densify.execute(polygon, 1.0, null)); + Envelope envelope = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":10}") + .getGeometry()); + wiggleGeometry(densified, 0.00000001, 1982); + wiggleGeometry(envelope, 0.00000001, 511); + assertTrue(!equals.execute(envelope, densified, sr, null)); + assertTrue(!contains.execute(densified, envelope, sr, null)); // envelope + // sticks + // outside + // of + // polygon, + // but + // the + // envelopes + // are + // equal + assertTrue(!disjoint.execute(densified, envelope, sr, null)); + assertTrue(!touches.execute(envelope, densified, sr, null)); + assertTrue(!overlaps.execute(envelope, densified, sr, null)); + assertTrue(!crosses.execute(envelope, densified, sr, null)); + } + + { + Polygon polygon = (Polygon) (TestCommonMethods + .fromJson("{\"rings\":[[[0,0],[0,5],[0,10],[10,0],[0,0]]]}") + .getGeometry()); + Polygon densified = (Polygon) (densify.execute(polygon, 1.0, null)); + Envelope envelope = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":15,\"ymax\":10}") + .getGeometry()); + wiggleGeometry(densified, 0.00000001, 1982); + wiggleGeometry(envelope, 0.00000001, 511); + assertTrue(!equals.execute(envelope, densified, sr, null)); + assertTrue(!contains.execute(densified, envelope, sr, null)); // the + // polygon + // envelope + // doesn't + // contain + // the + // envelope, + // but + // they + // intersect + assertTrue(!disjoint.execute(densified, envelope, sr, null)); + assertTrue(!touches.execute(envelope, densified, sr, null)); + assertTrue(!overlaps.execute(envelope, densified, sr, null)); + assertTrue(!crosses.execute(envelope, densified, sr, null)); + } + + { + Polygon polygon = (Polygon) (TestCommonMethods + .fromJson("{\"rings\":[[[0,0],[0,5],[0,10],[10,10],[10,0],[0,0]]]}") + .getGeometry()); + Polygon densified = (Polygon) (densify.execute(polygon, 1.0, null)); + Envelope envelope = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":0,\"ymax\":0}") + .getGeometry()); + wiggleGeometry(densified, 0.00000001, 1982); + wiggleGeometry(envelope, 0.00000001, 511); + assertTrue(!equals.execute(envelope, densified, sr, null)); + assertTrue(!contains.execute(densified, envelope, sr, null)); // envelope + // degenerate + // to + // a + // point + // and + // is + // on + // border + // (i.e. + // touches) + assertTrue(!disjoint.execute(densified, envelope, sr, null)); + assertTrue(touches.execute(envelope, densified, sr, null)); + assertTrue(!overlaps.execute(envelope, densified, sr, null)); + assertTrue(!crosses.execute(envelope, densified, sr, null)); + } + + { + Polygon polygon = (Polygon) (TestCommonMethods + .fromJson("{\"rings\":[[[0,0],[0,5],[0,10],[10,10],[10,0],[0,0]]]}") + .getGeometry()); + Polygon densified = (Polygon) (densify.execute(polygon, 1.0, null)); + Envelope envelope = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":1,\"ymin\":1,\"xmax\":1,\"ymax\":1}") + .getGeometry()); + wiggleGeometry(densified, 0.00000001, 1982); + wiggleGeometry(envelope, 0.00000001, 511); + assertTrue(!equals.execute(envelope, densified, sr, null)); + assertTrue(contains.execute(densified, envelope, sr, null)); // envelope + // degenerate + // to + // a + // point + // and + // is + // properly + // inside + assertTrue(!disjoint.execute(densified, envelope, sr, null)); + assertTrue(!touches.execute(envelope, densified, sr, null)); + assertTrue(!overlaps.execute(envelope, densified, sr, null)); + assertTrue(!crosses.execute(envelope, densified, sr, null)); + } + + { + Polygon polygon = (Polygon) (TestCommonMethods + .fromJson("{\"rings\":[[[0,0],[0,5],[0,10],[10,10],[10,0],[0,0]]]}") + .getGeometry()); + Polygon densified = (Polygon) (densify.execute(polygon, 1.0, null)); + Envelope envelope = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":-1,\"ymin\":-1,\"xmax\":-1,\"ymax\":-1}") + .getGeometry()); + wiggleGeometry(densified, 0.00000001, 1982); + wiggleGeometry(envelope, 0.00000001, 511); + assertTrue(!equals.execute(envelope, densified, sr, null)); + assertTrue(!contains.execute(densified, envelope, sr, null)); // envelope + // degenerate + // to + // a + // point + // and + // is + // properly + // outside + assertTrue(disjoint.execute(densified, envelope, sr, null)); + assertTrue(!touches.execute(envelope, densified, sr, null)); + assertTrue(!overlaps.execute(envelope, densified, sr, null)); + assertTrue(!crosses.execute(envelope, densified, sr, null)); + } + + { + Polygon polygon = (Polygon) (TestCommonMethods + .fromJson("{\"rings\":[[[0,0],[0,5],[0,10],[10,10],[10,0],[0,0]]]}") + .getGeometry()); + Polygon densified = (Polygon) (densify.execute(polygon, 1.0, null)); + Envelope envelope = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":1,\"ymax\":0}") + .getGeometry()); + wiggleGeometry(densified, 0.00000001, 1982); + wiggleGeometry(envelope, 0.00000001, 511); + assertTrue(!equals.execute(envelope, densified, sr, null)); + assertTrue(!contains.execute(densified, envelope, sr, null)); // envelope + // degenerate + // to + // a + // line + // and + // rides + // the + // bottom + // of + // the + // polygon + // (no + // interior + // intersection) + assertTrue(!disjoint.execute(densified, envelope, sr, null)); + assertTrue(touches.execute(envelope, densified, sr, null)); + assertTrue(!overlaps.execute(envelope, densified, sr, null)); + assertTrue(!crosses.execute(envelope, densified, sr, null)); + } + + { + Polygon polygon = (Polygon) (TestCommonMethods + .fromJson("{\"rings\":[[[0,0],[0,5],[0,10],[10,10],[10,0],[0,0]]]}") + .getGeometry()); + Polygon densified = (Polygon) (densify.execute(polygon, 1.0, null)); + Envelope envelope = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":0,\"ymin\":1,\"xmax\":1,\"ymax\":1}") + .getGeometry()); + wiggleGeometry(densified, 0.00000001, 1982); + wiggleGeometry(envelope, 0.00000001, 511); + assertTrue(!equals.execute(envelope, densified, sr, null)); + assertTrue(contains.execute(densified, envelope, sr, null)); // envelope + // degenerate + // to + // a + // line, + // touches + // the + // border + // on + // the + // inside + // yet + // has + // interior + // intersection + assertTrue(!disjoint.execute(densified, envelope, sr, null)); + assertTrue(!touches.execute(envelope, densified, sr, null)); + assertTrue(!overlaps.execute(envelope, densified, sr, null)); + assertTrue(!crosses.execute(envelope, densified, sr, null)); + } + + { + Polygon polygon = (Polygon) (TestCommonMethods + .fromJson("{\"rings\":[[[0,0],[0,5],[0,10],[10,0],[0,0]]]}") + .getGeometry()); + Polygon densified = (Polygon) (densify.execute(polygon, 1.0, null)); + Envelope envelope = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":5,\"ymin\":5,\"xmax\":6,\"ymax\":5}") + .getGeometry()); + wiggleGeometry(densified, 0.00000001, 1982); + wiggleGeometry(envelope, 0.00000001, 511); + assertTrue(!equals.execute(envelope, densified, sr, null)); + assertTrue(!contains.execute(densified, envelope, sr, null)); // envelope + // degenerate + // to + // a + // line, + // touches + // the + // boundary, + // and + // is + // outside + assertTrue(!disjoint.execute(densified, envelope, sr, null)); + assertTrue(touches.execute(envelope, densified, sr, null)); + assertTrue(!overlaps.execute(envelope, densified, sr, null)); + assertTrue(!crosses.execute(envelope, densified, sr, null)); + } + + { + Polygon polygon = (Polygon) (TestCommonMethods + .fromJson("{\"rings\":[[[0,0],[0,5],[0,10],[10,0],[0,0]]]}") + .getGeometry()); + Polygon densified = (Polygon) (densify.execute(polygon, 1.0, null)); + Envelope envelope = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":6,\"ymin\":5,\"xmax\":7,\"ymax\":5}") + .getGeometry()); + wiggleGeometry(densified, 0.00000001, 1982); + wiggleGeometry(envelope, 0.00000001, 511); + assertTrue(!equals.execute(envelope, densified, sr, null)); + assertTrue(!contains.execute(densified, envelope, sr, null)); // envelope + // degenerate + // to + // a + // line, + // and + // is + // outside + assertTrue(disjoint.execute(densified, envelope, sr, null)); + assertTrue(!touches.execute(envelope, densified, sr, null)); + assertTrue(!overlaps.execute(envelope, densified, sr, null)); + assertTrue(!crosses.execute(envelope, densified, sr, null)); + } + + { + Polygon polygon = (Polygon) (TestCommonMethods + .fromJson("{\"rings\":[[[0,0],[0,5],[0,10],[10,0],[0,0]]]}") + .getGeometry()); + Polygon densified = (Polygon) (densify.execute(polygon, 1.0, null)); + Envelope envelope = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":4,\"ymin\":5,\"xmax\":7,\"ymax\":5}") + .getGeometry()); + wiggleGeometry(densified, 0.00000001, 1982); + wiggleGeometry(envelope, 0.00000001, 511); + assertTrue(!equals.execute(envelope, densified, sr, null)); + assertTrue(!contains.execute(densified, envelope, sr, null)); // envelope + // degenerate + // to + // a + // line, + // and + // crosses + // polygon + assertTrue(!disjoint.execute(densified, envelope, sr, null)); + assertTrue(!touches.execute(envelope, densified, sr, null)); + assertTrue(!overlaps.execute(envelope, densified, sr, null)); + assertTrue(crosses.execute(envelope, densified, sr, null)); + } + } + + @Test + public void testPolylineEnvelope() { + OperatorEquals equals = (OperatorEquals) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Equals)); + OperatorContains contains = (OperatorContains) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Contains)); + OperatorDisjoint disjoint = (OperatorDisjoint) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Disjoint)); + OperatorCrosses crosses = (OperatorCrosses) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Crosses)); + @SuppressWarnings("unused") + OperatorWithin within = (OperatorWithin) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Within)); + OperatorOverlaps overlaps = (OperatorOverlaps) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Overlaps)); + OperatorTouches touches = (OperatorTouches) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Touches)); + OperatorDensifyByLength densify = (OperatorDensifyByLength) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.DensifyByLength)); + + SpatialReference sr = SpatialReference.create(4326); + + { + Polyline polyline = (Polyline) (TestCommonMethods + .fromJson("{\"paths\":[[[0,0],[0,5],[0,10],[10,10],[10,0]]]}") + .getGeometry()); + Polyline densified = (Polyline) (densify.execute(polyline, 1.0, + null)); + Envelope envelope = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":10}") + .getGeometry()); + wiggleGeometry(densified, 0.00000001, 1982); + wiggleGeometry(envelope, 0.00000001, 511); + assertTrue(!equals.execute(envelope, densified, sr, null)); // polyline + // straddles + // the + // envelope + // like + // a hat + assertTrue(!contains.execute(densified, envelope, sr, null)); + assertTrue(!disjoint.execute(envelope, densified, sr, null)); + assertTrue(touches.execute(envelope, densified, sr, null)); + assertTrue(!overlaps.execute(envelope, densified, sr, null)); + assertTrue(!crosses.execute(envelope, densified, sr, null)); + } + + { + Polyline polyline = (Polyline) (TestCommonMethods + .fromJson("{\"paths\":[[[-10,0],[0,10]]]}").getGeometry()); + Polyline densified = (Polyline) (densify.execute(polyline, 1.0, + null)); + Envelope envelope = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":10}") + .getGeometry()); + wiggleGeometry(densified, 0.00000001, 1982); + wiggleGeometry(envelope, 0.00000001, 511); + assertTrue(!equals.execute(envelope, densified, sr, null)); + assertTrue(!contains.execute(densified, envelope, sr, null)); + assertTrue(!disjoint.execute(envelope, densified, sr, null)); + assertTrue(touches.execute(envelope, densified, sr, null)); + assertTrue(touches.execute(densified, envelope, sr, null)); + assertTrue(!overlaps.execute(envelope, densified, sr, null)); + assertTrue(!crosses.execute(envelope, densified, sr, null)); + } + + { + Polyline polyline = (Polyline) (TestCommonMethods + .fromJson("{\"paths\":[[[-11,0],[1,12]]]}").getGeometry()); + Polyline densified = (Polyline) (densify.execute(polyline, 1.0, + null)); + Envelope envelope = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":10}") + .getGeometry()); + wiggleGeometry(densified, 0.00000001, 1982); + wiggleGeometry(envelope, 0.00000001, 511); + assertTrue(!equals.execute(envelope, densified, sr, null)); + assertTrue(!contains.execute(densified, envelope, sr, null)); + assertTrue(disjoint.execute(envelope, densified, sr, null)); + assertTrue(!touches.execute(envelope, densified, sr, null)); + assertTrue(!touches.execute(densified, envelope, sr, null)); + assertTrue(!overlaps.execute(envelope, densified, sr, null)); + assertTrue(!crosses.execute(envelope, densified, sr, null)); + } + + { + Polyline polyline = (Polyline) (TestCommonMethods + .fromJson("{\"paths\":[[[5,5],[6,6]]]}").getGeometry()); + Polyline densified = (Polyline) (densify.execute(polyline, 1.0, + null)); + Envelope envelope = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":10}") + .getGeometry()); + wiggleGeometry(densified, 0.00000001, 1982); + wiggleGeometry(envelope, 0.00000001, 511); + assertTrue(!equals.execute(envelope, densified, sr, null)); // polyline + // properly + // inside + assertTrue(contains.execute(envelope, densified, sr, null)); + assertTrue(!disjoint.execute(envelope, densified, sr, null)); + assertTrue(!touches.execute(envelope, densified, sr, null)); + assertTrue(!overlaps.execute(envelope, densified, sr, null)); + assertTrue(!crosses.execute(envelope, densified, sr, null)); + } + + { + Polyline polyline = (Polyline) (TestCommonMethods + .fromJson("{\"paths\":[[[5,5],[10,10]]]}").getGeometry()); + Polyline densified = (Polyline) (densify.execute(polyline, 1.0, + null)); + Envelope envelope = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":10}") + .getGeometry()); + wiggleGeometry(densified, 0.00000001, 1982); + wiggleGeometry(envelope, 0.00000001, 511); + assertTrue(!equals.execute(envelope, densified, sr, null)); + assertTrue(contains.execute(envelope, densified, sr, null)); + assertTrue(!disjoint.execute(envelope, densified, sr, null)); + assertTrue(!touches.execute(envelope, densified, sr, null)); + assertTrue(!overlaps.execute(envelope, densified, sr, null)); + assertTrue(!crosses.execute(envelope, densified, sr, null)); + } + + { + Polyline polyline = (Polyline) (TestCommonMethods + .fromJson("{\"paths\":[[[-5,5],[15,5]]]}").getGeometry()); + Polyline densified = (Polyline) (densify.execute(polyline, 1.0, + null)); + Envelope envelope = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":10}") + .getGeometry()); + wiggleGeometry(densified, 0.00000001, 1982); + wiggleGeometry(envelope, 0.00000001, 511); + assertTrue(!equals.execute(envelope, densified, sr, null)); + assertTrue(!contains.execute(envelope, densified, sr, null)); + assertTrue(!disjoint.execute(envelope, densified, sr, null)); + assertTrue(!touches.execute(envelope, densified, sr, null)); + assertTrue(!overlaps.execute(envelope, densified, sr, null)); + assertTrue(crosses.execute(envelope, densified, sr, null)); + assertTrue(crosses.execute(densified, envelope, sr, null)); + } + + { + Polyline polyline = (Polyline) (TestCommonMethods + .fromJson("{\"paths\":[[[5,5],[5,15]]]}").getGeometry()); + Polyline densified = (Polyline) (densify.execute(polyline, 1.0, + null)); + Envelope envelope = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":10}") + .getGeometry()); + wiggleGeometry(densified, 0.00000001, 1982); + wiggleGeometry(envelope, 0.00000001, 511); + assertTrue(!equals.execute(envelope, densified, sr, null)); // polyline + // slices + // through + // the + // envelope + // (interior + // and + // exterior + // intersection) + assertTrue(!contains.execute(densified, envelope, sr, null)); + assertTrue(!disjoint.execute(envelope, densified, sr, null)); + assertTrue(!touches.execute(envelope, densified, sr, null)); + assertTrue(!overlaps.execute(envelope, densified, sr, null)); + assertTrue(crosses.execute(envelope, densified, sr, null)); + } + + { + Polyline polyline = (Polyline) (TestCommonMethods + .fromJson("{\"paths\":[[[5,11],[5,15]]]}").getGeometry()); + Polyline densified = (Polyline) (densify.execute(polyline, 1.0, + null)); + Envelope envelope = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":10}") + .getGeometry()); + wiggleGeometry(densified, 0.00000001, 1982); + wiggleGeometry(envelope, 0.00000001, 511); + assertTrue(!equals.execute(envelope, densified, sr, null)); // polyline + // outside + // of + // envelope + assertTrue(!contains.execute(densified, envelope, sr, null)); + assertTrue(disjoint.execute(envelope, densified, sr, null)); + assertTrue(!touches.execute(envelope, densified, sr, null)); + assertTrue(!overlaps.execute(envelope, densified, sr, null)); + assertTrue(!crosses.execute(envelope, densified, sr, null)); + } + + { + Polyline polyline = (Polyline) (TestCommonMethods + .fromJson("{\"paths\":[[[0,0],[0,5],[0,10],[10,10],[10,0]]]}") + .getGeometry()); + Polyline densified = (Polyline) (densify.execute(polyline, 1.0, + null)); + Envelope envelope = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":0,\"ymin\":10,\"xmax\":10,\"ymax\":10}") + .getGeometry()); + wiggleGeometry(densified, 0.00000001, 1982); + wiggleGeometry(envelope, 0.00000001, 511); + assertTrue(!equals.execute(envelope, densified, sr, null)); // polyline + // straddles + // the + // degenerate + // envelope + // like + // a hat + assertTrue(contains.execute(densified, envelope, sr, null)); + assertTrue(!disjoint.execute(envelope, densified, sr, null)); + assertTrue(!touches.execute(envelope, densified, sr, null)); + assertTrue(!overlaps.execute(envelope, densified, sr, null)); + assertTrue(!crosses.execute(envelope, densified, sr, null)); + } + + { + Polyline polyline = (Polyline) (TestCommonMethods + .fromJson("{\"paths\":[[[0,0],[0,5],[0,10],[10,10],[10,0]]]}") + .getGeometry()); + Polyline densified = (Polyline) (densify.execute(polyline, 1.0, + null)); + Envelope envelope = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":0,\"ymin\":-5,\"xmax\":0,\"ymax\":10}") + .getGeometry()); + wiggleGeometry(densified, 0.00000001, 1982); + wiggleGeometry(envelope, 0.00000001, 511); + assertTrue(!equals.execute(envelope, densified, sr, null)); + assertTrue(!contains.execute(densified, envelope, sr, null)); + assertTrue(!disjoint.execute(envelope, densified, sr, null)); + assertTrue(!touches.execute(envelope, densified, sr, null)); + assertTrue(overlaps.execute(envelope, densified, sr, null)); + assertTrue(!crosses.execute(envelope, densified, sr, null)); + } + + { + Polyline polyline = (Polyline) (TestCommonMethods + .fromJson("{\"paths\":[[[0,0],[0,5],[0,10],[10,10],[10,0]]]}") + .getGeometry()); + Polyline densified = (Polyline) (densify.execute(polyline, 1.0, + null)); + Envelope envelope = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":0,\"ymax\":0}") + .getGeometry()); + wiggleGeometry(densified, 0.00000001, 511); + wiggleGeometry(envelope, 0.00000001, 1982); + assertTrue(!equals.execute(envelope, densified, sr, null)); // degenerate + // envelope + // is at + // the + // end + // point + // of + // polyline + assertTrue(!contains.execute(densified, envelope, sr, null)); + assertTrue(!disjoint.execute(envelope, densified, sr, null)); + assertTrue(touches.execute(envelope, densified, sr, null)); + assertTrue(!overlaps.execute(envelope, densified, sr, null)); + assertTrue(!crosses.execute(envelope, densified, sr, null)); + } + + { + Polyline polyline = (Polyline) (TestCommonMethods + .fromJson("{\"paths\":[[[0,0],[0,5],[0,10],[10,10],[10,0]]]}") + .getGeometry()); + Polyline densified = (Polyline) (densify.execute(polyline, 1.0, + null)); + Envelope envelope = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":0,\"ymin\":5,\"xmax\":0,\"ymax\":5}") + .getGeometry()); + wiggleGeometry(densified, 0.00000001, 1982); + wiggleGeometry(envelope, 0.00000001, 511); + assertTrue(!equals.execute(envelope, densified, sr, null)); // degenerate + // envelope + // is at + // the + // interior + // of + // polyline + assertTrue(contains.execute(densified, envelope, sr, null)); + assertTrue(!disjoint.execute(envelope, densified, sr, null)); + assertTrue(!touches.execute(envelope, densified, sr, null)); + assertTrue(!overlaps.execute(envelope, densified, sr, null)); + assertTrue(!crosses.execute(envelope, densified, sr, null)); + } + + { + Polyline polyline = (Polyline) (TestCommonMethods + .fromJson("{\"paths\":[[[2,-2],[2,2]]]}").getGeometry()); + Polyline densified = (Polyline) (densify.execute(polyline, 1.0, + null)); + Envelope envelope = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":5,\"ymax\":0}") + .getGeometry()); + wiggleGeometry(densified, 0.00000001, 1982); + wiggleGeometry(envelope, 0.00000001, 511); + assertTrue(!equals.execute(envelope, densified, sr, null)); // degenerate + // envelope + // crosses + // polyline + assertTrue(!contains.execute(densified, envelope, sr, null)); + assertTrue(!disjoint.execute(envelope, densified, sr, null)); + assertTrue(!touches.execute(envelope, densified, sr, null)); + assertTrue(!overlaps.execute(envelope, densified, sr, null)); + assertTrue(crosses.execute(envelope, densified, sr, null)); + } + + { + Polyline polyline = (Polyline) (TestCommonMethods + .fromJson("{\"paths\":[[[2,0],[2,2]]]}").getGeometry()); + Polyline densified = (Polyline) (densify.execute(polyline, 1.0, + null)); + Envelope envelope = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":5,\"ymax\":0}") + .getGeometry()); + wiggleGeometry(densified, 0.00000001, 1982); + wiggleGeometry(envelope, 0.00000001, 511); + assertTrue(!equals.execute(envelope, densified, sr, null)); // degenerate + // envelope + // crosses + // polyline + assertTrue(!contains.execute(densified, envelope, sr, null)); + assertTrue(!disjoint.execute(envelope, densified, sr, null)); + assertTrue(touches.execute(envelope, densified, sr, null)); + assertTrue(!overlaps.execute(envelope, densified, sr, null)); + assertTrue(!crosses.execute(envelope, densified, sr, null)); + } + + { + Polyline polyline = (Polyline) (TestCommonMethods + .fromJson("{\"paths\":[[[2,0],[2,2]]]}").getGeometry()); + Polyline densified = (Polyline) (densify.execute(polyline, 1.0, + null)); + Envelope envelope = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":2,\"ymin\":0,\"xmax\":2,\"ymax\":3}") + .getGeometry()); + wiggleGeometry(densified, 0.00000001, 1982); + wiggleGeometry(envelope, 0.00000001, 511); + assertTrue(!equals.execute(envelope, densified, sr, null)); // degenerate + // envelope + // contains + // polyline + assertTrue(!contains.execute(densified, envelope, sr, null)); + assertTrue(contains.execute(envelope, densified, sr, null)); + assertTrue(!disjoint.execute(envelope, densified, sr, null)); + assertTrue(!touches.execute(envelope, densified, sr, null)); + assertTrue(!overlaps.execute(envelope, densified, sr, null)); + assertTrue(!crosses.execute(envelope, densified, sr, null)); + } + + { + Polyline polyline = (Polyline) (TestCommonMethods + .fromJson("{\"paths\":[[[5,5],[6,6]]]}").getGeometry()); + Polyline densified = (Polyline) (densify.execute(polyline, 1.0, + null)); + Envelope envelope = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":5,\"ymax\":5}") + .getGeometry()); + wiggleGeometry(densified, 0.00000001, 1982); + wiggleGeometry(envelope, 0.00000001, 511); + assertTrue(!equals.execute(envelope, densified, sr, null)); // polyline + // properly + // inside + assertTrue(!contains.execute(envelope, densified, sr, null)); + assertTrue(!disjoint.execute(envelope, densified, sr, null)); + assertTrue(touches.execute(envelope, densified, sr, null)); + assertTrue(!overlaps.execute(envelope, densified, sr, null)); + assertTrue(!crosses.execute(envelope, densified, sr, null)); + } + + { + Polyline polyline = (Polyline) (TestCommonMethods + .fromJson("{\"paths\":[[[5,5],[5,10]]]}").getGeometry()); + Polyline densified = (Polyline) (densify.execute(polyline, 1.0, + null)); + Envelope envelope = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":5,\"ymin\":5,\"xmax\":5,\"ymax\":10}") + .getGeometry()); + wiggleGeometry(densified, 0.00000001, 1982); + wiggleGeometry(envelope, 0.00000001, 511); + assertTrue(equals.execute(envelope, densified, sr, null)); // polyline + // properly + // inside + assertTrue(contains.execute(envelope, densified, sr, null)); + assertTrue(!disjoint.execute(envelope, densified, sr, null)); + assertTrue(!touches.execute(envelope, densified, sr, null)); + assertTrue(!overlaps.execute(envelope, densified, sr, null)); + assertTrue(!crosses.execute(envelope, densified, sr, null)); + } + } + + @Test + public void testMultiPointEnvelope() { + OperatorEquals equals = (OperatorEquals) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Equals)); + OperatorContains contains = (OperatorContains) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Contains)); + OperatorDisjoint disjoint = (OperatorDisjoint) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Disjoint)); + OperatorCrosses crosses = (OperatorCrosses) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Crosses)); + @SuppressWarnings("unused") + OperatorWithin within = (OperatorWithin) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Within)); + OperatorOverlaps overlaps = (OperatorOverlaps) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Overlaps)); + OperatorTouches touches = (OperatorTouches) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Touches)); + @SuppressWarnings("unused") + OperatorDensifyByLength densify = (OperatorDensifyByLength) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.DensifyByLength)); + + SpatialReference sr = SpatialReference.create(4326); + + { + MultiPoint multi_point = (MultiPoint) (TestCommonMethods + .fromJson("{\"points\":[[0,0],[0,10],[10,10],[10,0]]}") + .getGeometry()); + Envelope envelope = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":10}") + .getGeometry()); + wiggleGeometry(multi_point, 0.00000001, 1982); + wiggleGeometry(envelope, 0.00000001, 511); + assertTrue(!equals.execute(envelope, multi_point, sr, null)); // all + // points + // on + // boundary + assertTrue(!contains.execute(envelope, multi_point, sr, null)); + assertTrue(!disjoint.execute(envelope, multi_point, sr, null)); + assertTrue(touches.execute(envelope, multi_point, sr, null)); + assertTrue(!overlaps.execute(envelope, multi_point, sr, null)); + assertTrue(!crosses.execute(envelope, multi_point, sr, null)); + } + + { + MultiPoint multi_point = (MultiPoint) (TestCommonMethods + .fromJson("{\"points\":[[0,0],[0,10],[10,10],[5,5]]}") + .getGeometry()); + Envelope envelope = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":10}") + .getGeometry()); + wiggleGeometry(multi_point, 0.00000001, 1982); + wiggleGeometry(envelope, 0.00000001, 511); + assertTrue(!equals.execute(envelope, multi_point, sr, null)); // points + // on + // boundary + // and + // one + // point + // in + // interior + assertTrue(contains.execute(envelope, multi_point, sr, null)); + assertTrue(!disjoint.execute(envelope, multi_point, sr, null)); + assertTrue(!touches.execute(envelope, multi_point, sr, null)); + assertTrue(!overlaps.execute(envelope, multi_point, sr, null)); + assertTrue(!crosses.execute(envelope, multi_point, sr, null)); + } + + { + MultiPoint multi_point = (MultiPoint) (TestCommonMethods + .fromJson("{\"points\":[[0,0],[0,10],[10,10],[5,5],[15,15]]}") + .getGeometry()); + Envelope envelope = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":10}") + .getGeometry()); + wiggleGeometry(multi_point, 0.00000001, 1982); + wiggleGeometry(envelope, 0.00000001, 511); + assertTrue(!equals.execute(envelope, multi_point, sr, null)); // points + // on + // boundary, + // one + // interior, + // one + // exterior + assertTrue(!contains.execute(envelope, multi_point, sr, null)); + assertTrue(!disjoint.execute(envelope, multi_point, sr, null)); + assertTrue(!touches.execute(envelope, multi_point, sr, null)); + assertTrue(!overlaps.execute(envelope, multi_point, sr, null)); + assertTrue(crosses.execute(envelope, multi_point, sr, null)); + } + + { + MultiPoint multi_point = (MultiPoint) (TestCommonMethods + .fromJson("{\"points\":[[0,0],[0,10],[10,10],[15,15]]}") + .getGeometry()); + Envelope envelope = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":10}") + .getGeometry()); + wiggleGeometry(multi_point, 0.00000001, 1982); + wiggleGeometry(envelope, 0.00000001, 511); + assertTrue(!equals.execute(envelope, multi_point, sr, null)); // points + // on + // boundary, + // one + // exterior + assertTrue(!contains.execute(envelope, multi_point, sr, null)); + assertTrue(!disjoint.execute(envelope, multi_point, sr, null)); + assertTrue(touches.execute(envelope, multi_point, sr, null)); + assertTrue(!overlaps.execute(envelope, multi_point, sr, null)); + assertTrue(!crosses.execute(envelope, multi_point, sr, null)); + } + + { + MultiPoint multi_point = (MultiPoint) (TestCommonMethods + .fromJson("{\"points\":[[0,-1],[0,11],[11,11],[15,15]]}") + .getGeometry()); + Envelope envelope = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":10}") + .getGeometry()); + wiggleGeometry(multi_point, 0.00000001, 1982); + wiggleGeometry(envelope, 0.00000001, 511); + assertTrue(!equals.execute(envelope, multi_point, sr, null)); // all + // points + // exterior + assertTrue(!contains.execute(envelope, multi_point, sr, null)); + assertTrue(disjoint.execute(envelope, multi_point, sr, null)); + assertTrue(!touches.execute(envelope, multi_point, sr, null)); + assertTrue(!overlaps.execute(envelope, multi_point, sr, null)); + assertTrue(!crosses.execute(envelope, multi_point, sr, null)); + } + + { + MultiPoint multi_point = (MultiPoint) (TestCommonMethods + .fromJson("{\"points\":[[0,0],[0,10],[10,10],[10,0]]}") + .getGeometry()); + Envelope envelope = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":0,\"ymin\":10,\"xmax\":10,\"ymax\":10}") + .getGeometry()); + wiggleGeometry(multi_point, 0.00000001, 1982); + wiggleGeometry(envelope, 0.00000001, 511); + assertTrue(!equals.execute(envelope, multi_point, sr, null)); // degenerate + // envelope + // slices + // through + // some + // points, + // but + // some + // points + // are + // off + // the + // line + assertTrue(!contains.execute(envelope, multi_point, sr, null)); + assertTrue(!disjoint.execute(envelope, multi_point, sr, null)); + assertTrue(touches.execute(envelope, multi_point, sr, null)); + assertTrue(!overlaps.execute(envelope, multi_point, sr, null)); + assertTrue(!crosses.execute(envelope, multi_point, sr, null)); + } + + { + MultiPoint multi_point = (MultiPoint) (TestCommonMethods + .fromJson("{\"points\":[[0,0],[1,10],[10,10],[10,0]]}") + .getGeometry()); + Envelope envelope = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":0,\"ymin\":10,\"xmax\":10,\"ymax\":10}") + .getGeometry()); + wiggleGeometry(multi_point, 0.00000001, 1982); + wiggleGeometry(envelope, 0.00000001, 511); + assertTrue(!equals.execute(envelope, multi_point, sr, null)); // degenerate + // envelope + // slices + // through + // some + // points, + // but + // some + // points + // are + // off + // the + // line + assertTrue(!contains.execute(envelope, multi_point, sr, null)); + assertTrue(!disjoint.execute(envelope, multi_point, sr, null)); + assertTrue(!touches.execute(envelope, multi_point, sr, null)); + assertTrue(!overlaps.execute(envelope, multi_point, sr, null)); + assertTrue(crosses.execute(envelope, multi_point, sr, null)); + } + + { + MultiPoint multi_point = (MultiPoint) (TestCommonMethods + .fromJson("{\"points\":[[0,10],[10,10]]}").getGeometry()); + Envelope envelope = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":0,\"ymin\":10,\"xmax\":10,\"ymax\":10}") + .getGeometry()); + wiggleGeometry(multi_point, 0.00000001, 1982); + wiggleGeometry(envelope, 0.00000001, 511); + assertTrue(!equals.execute(envelope, multi_point, sr, null)); // degenerate + // envelopes + // slices + // through + // all + // the + // points, + // and + // they + // are + // at + // the + // end + // points + // of + // the + // line + assertTrue(!contains.execute(envelope, multi_point, sr, null)); + assertTrue(!disjoint.execute(envelope, multi_point, sr, null)); + assertTrue(touches.execute(envelope, multi_point, sr, null)); + assertTrue(!overlaps.execute(envelope, multi_point, sr, null)); + assertTrue(!crosses.execute(envelope, multi_point, sr, null)); + } + + { + MultiPoint multi_point = (MultiPoint) (TestCommonMethods + .fromJson("{\"points\":[[1,10],[9,10]]}").getGeometry()); + Envelope envelope = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":0,\"ymin\":10,\"xmax\":10,\"ymax\":10}") + .getGeometry()); + wiggleGeometry(multi_point, 0.00000001, 1982); + wiggleGeometry(envelope, 0.00000001, 511); + assertTrue(!equals.execute(envelope, multi_point, sr, null)); // degenerate + // envelopes + // slices + // through + // all + // the + // points, + // and + // they + // are + // in + // the + // interior + // of + // the + // line + assertTrue(contains.execute(envelope, multi_point, sr, null)); + assertTrue(!disjoint.execute(envelope, multi_point, sr, null)); + assertTrue(!touches.execute(envelope, multi_point, sr, null)); + assertTrue(!overlaps.execute(envelope, multi_point, sr, null)); + assertTrue(!crosses.execute(envelope, multi_point, sr, null)); + } + + { + MultiPoint multi_point = (MultiPoint) (TestCommonMethods + .fromJson("{\"points\":[[0,-1],[0,11],[11,11],[15,15]]}") + .getGeometry()); + Envelope envelope = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":0,\"ymin\":10,\"xmax\":10,\"ymax\":10}") + .getGeometry()); + wiggleGeometry(multi_point, 0.00000001, 1982); + wiggleGeometry(envelope, 0.00000001, 511); + assertTrue(!equals.execute(envelope, multi_point, sr, null)); // all + // points + // exterior + assertTrue(!contains.execute(envelope, multi_point, sr, null)); + assertTrue(disjoint.execute(envelope, multi_point, sr, null)); + assertTrue(!touches.execute(envelope, multi_point, sr, null)); + assertTrue(!overlaps.execute(envelope, multi_point, sr, null)); + assertTrue(!crosses.execute(envelope, multi_point, sr, null)); + } + + { + MultiPoint multi_point = (MultiPoint) (TestCommonMethods + .fromJson("{\"points\":[[0,-1],[0,11],[11,11],[15,15]]}") + .getGeometry()); + Envelope envelope = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":10,\"ymin\":10,\"xmax\":10,\"ymax\":10}") + .getGeometry()); + wiggleGeometry(multi_point, 0.00000001, 1982); + wiggleGeometry(envelope, 0.00000001, 511); + assertTrue(!equals.execute(envelope, multi_point, sr, null)); // all + // points + // exterior + assertTrue(!contains.execute(envelope, multi_point, sr, null)); + assertTrue(disjoint.execute(envelope, multi_point, sr, null)); + assertTrue(!touches.execute(envelope, multi_point, sr, null)); + assertTrue(!overlaps.execute(envelope, multi_point, sr, null)); + assertTrue(!crosses.execute(envelope, multi_point, sr, null)); + } + + { + MultiPoint multi_point = (MultiPoint) (TestCommonMethods + .fromJson("{\"points\":[[0,-1],[0,11],[11,11],[15,15]]}") + .getGeometry()); + Envelope envelope = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":11,\"ymax\":11}") + .getGeometry()); + wiggleGeometry(multi_point, 0.00000001, 1982); + wiggleGeometry(envelope, 0.00000001, 511); + assertTrue(!equals.execute(envelope, multi_point, sr, null)); // all + // points + // exterior + assertTrue(!contains.execute(multi_point, envelope, sr, null)); + assertTrue(!contains.execute(envelope, multi_point, sr, null)); + assertTrue(!disjoint.execute(envelope, multi_point, sr, null)); + assertTrue(touches.execute(envelope, multi_point, sr, null)); + assertTrue(!overlaps.execute(envelope, multi_point, sr, null)); + assertTrue(!crosses.execute(envelope, multi_point, sr, null)); + } + + { + MultiPoint multi_point = (MultiPoint) (TestCommonMethods + .fromJson("{\"points\":[[0,-1],[0,-1]]}").getGeometry()); + Envelope envelope = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":0,\"ymin\":-1,\"xmax\":0,\"ymax\":-1}") + .getGeometry()); + wiggleGeometry(multi_point, 0.00000001, 1982); + wiggleGeometry(envelope, 0.00000001, 511); + assertTrue(equals.execute(envelope, multi_point, sr, null)); // all + // points + // exterior + assertTrue(contains.execute(multi_point, envelope, sr, null)); + assertTrue(contains.execute(envelope, multi_point, sr, null)); + assertTrue(!disjoint.execute(envelope, multi_point, sr, null)); + assertTrue(!touches.execute(envelope, multi_point, sr, null)); + assertTrue(!overlaps.execute(envelope, multi_point, sr, null)); + assertTrue(!crosses.execute(envelope, multi_point, sr, null)); + } + } + + @Test + public void testPointEnvelope() { + OperatorEquals equals = (OperatorEquals) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Equals)); + OperatorContains contains = (OperatorContains) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Contains)); + OperatorDisjoint disjoint = (OperatorDisjoint) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Disjoint)); + OperatorCrosses crosses = (OperatorCrosses) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Crosses)); + @SuppressWarnings("unused") + OperatorWithin within = (OperatorWithin) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Within)); + OperatorOverlaps overlaps = (OperatorOverlaps) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Overlaps)); + OperatorTouches touches = (OperatorTouches) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Touches)); + SpatialReference sr = SpatialReference.create(4326); + + { + Point point = (Point) (TestCommonMethods + .fromJson("{\"x\":5,\"y\":6}").getGeometry()); + Envelope envelope = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":10}") + .getGeometry()); + wiggleGeometry(point, 0.00000001, 1982); + wiggleGeometry(envelope, 0.00000001, 511); + assertTrue(!equals.execute(envelope, point, sr, null)); + assertTrue(contains.execute(envelope, point, sr, null)); + assertTrue(!contains.execute(point, envelope, sr, null)); + assertTrue(!disjoint.execute(envelope, point, sr, null)); + assertTrue(!touches.execute(envelope, point, sr, null)); + assertTrue(!overlaps.execute(envelope, point, sr, null)); + assertTrue(!crosses.execute(envelope, point, sr, null)); + } + + { + Point point = (Point) (TestCommonMethods + .fromJson("{\"x\":0,\"y\":10}").getGeometry()); + Envelope envelope = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":10}") + .getGeometry()); + wiggleGeometry(point, 0.00000001, 1982); + wiggleGeometry(envelope, 0.00000001, 511); + assertTrue(!equals.execute(envelope, point, sr, null)); + assertTrue(!contains.execute(envelope, point, sr, null)); + assertTrue(!contains.execute(point, envelope, sr, null)); + assertTrue(!disjoint.execute(envelope, point, sr, null)); + assertTrue(touches.execute(envelope, point, sr, null)); + assertTrue(!overlaps.execute(envelope, point, sr, null)); + assertTrue(!crosses.execute(envelope, point, sr, null)); + } + + { + Point point = (Point) (TestCommonMethods + .fromJson("{\"x\":0,\"y\":11}").getGeometry()); + Envelope envelope = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":10}") + .getGeometry()); + wiggleGeometry(point, 0.00000001, 1982); + wiggleGeometry(envelope, 0.00000001, 511); + assertTrue(!equals.execute(envelope, point, sr, null)); + assertTrue(!contains.execute(envelope, point, sr, null)); + assertTrue(!contains.execute(point, envelope, sr, null)); + assertTrue(disjoint.execute(envelope, point, sr, null)); + assertTrue(!touches.execute(envelope, point, sr, null)); + assertTrue(!overlaps.execute(envelope, point, sr, null)); + assertTrue(!crosses.execute(envelope, point, sr, null)); + } + + { + Point point = (Point) (TestCommonMethods + .fromJson("{\"x\":0,\"y\":0}").getGeometry()); + Envelope envelope = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":0}") + .getGeometry()); + wiggleGeometry(point, 0.00000001, 1982); + wiggleGeometry(envelope, 0.00000001, 511); + assertTrue(!equals.execute(envelope, point, sr, null)); + assertTrue(!contains.execute(envelope, point, sr, null)); + assertTrue(!contains.execute(point, envelope, sr, null)); + assertTrue(!disjoint.execute(envelope, point, sr, null)); + assertTrue(touches.execute(envelope, point, sr, null)); + assertTrue(!overlaps.execute(envelope, point, sr, null)); + assertTrue(!crosses.execute(envelope, point, sr, null)); + } + + { + Point point = (Point) (TestCommonMethods + .fromJson("{\"x\":5,\"y\":0}").getGeometry()); + Envelope envelope = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":0}") + .getGeometry()); + wiggleGeometry(point, 0.00000001, 1982); + wiggleGeometry(envelope, 0.00000001, 511); + assertTrue(!equals.execute(envelope, point, sr, null)); + assertTrue(contains.execute(envelope, point, sr, null)); + assertTrue(!contains.execute(point, envelope, sr, null)); + assertTrue(!disjoint.execute(envelope, point, sr, null)); + assertTrue(!touches.execute(envelope, point, sr, null)); + assertTrue(!overlaps.execute(envelope, point, sr, null)); + assertTrue(!crosses.execute(envelope, point, sr, null)); + } + + { + Point point = (Point) (TestCommonMethods + .fromJson("{\"x\":11,\"y\":0}").getGeometry()); + Envelope envelope = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":0}") + .getGeometry()); + wiggleGeometry(point, 0.00000001, 1982); + wiggleGeometry(envelope, 0.00000001, 511); + assertTrue(!equals.execute(envelope, point, sr, null)); + assertTrue(!contains.execute(envelope, point, sr, null)); + assertTrue(!contains.execute(point, envelope, sr, null)); + assertTrue(disjoint.execute(envelope, point, sr, null)); + assertTrue(!touches.execute(envelope, point, sr, null)); + assertTrue(!overlaps.execute(envelope, point, sr, null)); + assertTrue(!crosses.execute(envelope, point, sr, null)); + } + + { + Point point = (Point) (TestCommonMethods + .fromJson("{\"x\":0,\"y\":0}").getGeometry()); + Envelope envelope = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":0,\"ymax\":0}") + .getGeometry()); + wiggleGeometry(point, 0.00000001, 1982); + wiggleGeometry(envelope, 0.00000001, 511); + assertTrue(equals.execute(envelope, point, sr, null)); + assertTrue(contains.execute(envelope, point, sr, null)); + assertTrue(contains.execute(point, envelope, sr, null)); + assertTrue(!disjoint.execute(envelope, point, sr, null)); + assertTrue(!touches.execute(envelope, point, sr, null)); + assertTrue(!overlaps.execute(envelope, point, sr, null)); + assertTrue(!crosses.execute(envelope, point, sr, null)); + } + } + + @Test + public void testEnvelopeEnvelope() { + OperatorEquals equals = (OperatorEquals) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Equals)); + OperatorContains contains = (OperatorContains) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Contains)); + OperatorDisjoint disjoint = (OperatorDisjoint) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Disjoint)); + OperatorCrosses crosses = (OperatorCrosses) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Crosses)); + @SuppressWarnings("unused") + OperatorWithin within = (OperatorWithin) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Within)); + OperatorOverlaps overlaps = (OperatorOverlaps) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Overlaps)); + OperatorTouches touches = (OperatorTouches) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Touches)); + SpatialReference sr = SpatialReference.create(4326); + + { + Envelope env1 = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":10}") + .getGeometry()); + Envelope env2 = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":10}") + .getGeometry()); + wiggleGeometry(env1, 0.00000001, 1982); + wiggleGeometry(env2, 0.00000001, 511); + assertTrue(equals.execute(env1, env2, sr, null)); + assertTrue(contains.execute(env1, env2, sr, null)); + assertTrue(contains.execute(env2, env1, sr, null)); + assertTrue(!disjoint.execute(env1, env2, sr, null)); + assertTrue(!touches.execute(env1, env2, sr, null)); + assertTrue(!touches.execute(env2, env1, sr, null)); + assertTrue(!overlaps.execute(env1, env2, sr, null)); + assertTrue(!overlaps.execute(env2, env1, sr, null)); + assertTrue(!crosses.execute(env1, env2, sr, null)); + assertTrue(!crosses.execute(env2, env1, sr, null)); + } + + { + Envelope env1 = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":5,\"ymin\":5,\"xmax\":10,\"ymax\":10}") + .getGeometry()); + Envelope env2 = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":10}") + .getGeometry()); + wiggleGeometry(env1, 0.00000001, 1982); + wiggleGeometry(env2, 0.00000001, 511); + assertTrue(!equals.execute(env1, env2, sr, null)); + assertTrue(!contains.execute(env1, env2, sr, null)); + assertTrue(contains.execute(env2, env1, sr, null)); + assertTrue(!disjoint.execute(env1, env2, sr, null)); + assertTrue(!touches.execute(env1, env2, sr, null)); + assertTrue(!overlaps.execute(env1, env2, sr, null)); + assertTrue(!overlaps.execute(env2, env1, sr, null)); + assertTrue(!crosses.execute(env1, env2, sr, null)); + assertTrue(!crosses.execute(env2, env1, sr, null)); + } + + { + Envelope env1 = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":5,\"ymin\":5,\"xmax\":15,\"ymax\":15}") + .getGeometry()); + Envelope env2 = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":10}") + .getGeometry()); + wiggleGeometry(env1, 0.00000001, 1982); + wiggleGeometry(env2, 0.00000001, 511); + assertTrue(!equals.execute(env1, env2, sr, null)); + assertTrue(!contains.execute(env1, env2, sr, null)); + assertTrue(!contains.execute(env2, env1, sr, null)); + assertTrue(!disjoint.execute(env1, env2, sr, null)); + assertTrue(!touches.execute(env1, env2, sr, null)); + assertTrue(overlaps.execute(env1, env2, sr, null)); + assertTrue(overlaps.execute(env2, env1, sr, null)); + assertTrue(!crosses.execute(env1, env2, sr, null)); + assertTrue(!crosses.execute(env2, env1, sr, null)); + } + + { + Envelope env1 = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":10,\"ymin\":0,\"xmax\":20,\"ymax\":10}") + .getGeometry()); + Envelope env2 = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":10}") + .getGeometry()); + wiggleGeometry(env1, 0.00000001, 1982); + wiggleGeometry(env2, 0.00000001, 511); + assertTrue(!equals.execute(env1, env2, sr, null)); + assertTrue(!contains.execute(env1, env2, sr, null)); + assertTrue(!contains.execute(env2, env1, sr, null)); + assertTrue(!disjoint.execute(env1, env2, sr, null)); + assertTrue(touches.execute(env1, env2, sr, null)); + assertTrue(!overlaps.execute(env1, env2, sr, null)); + assertTrue(!overlaps.execute(env2, env1, sr, null)); + assertTrue(!crosses.execute(env1, env2, sr, null)); + assertTrue(!crosses.execute(env2, env1, sr, null)); + } + + { + Envelope env1 = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":10,\"ymin\":0,\"xmax\":20,\"ymax\":10}") + .getGeometry()); + Envelope env2 = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":10}") + .getGeometry()); + wiggleGeometry(env1, 0.00000001, 1982); + wiggleGeometry(env2, 0.00000001, 511); + assertTrue(!equals.execute(env1, env2, sr, null)); + assertTrue(!contains.execute(env1, env2, sr, null)); + assertTrue(!contains.execute(env2, env1, sr, null)); + assertTrue(!disjoint.execute(env1, env2, sr, null)); + assertTrue(touches.execute(env1, env2, sr, null)); + assertTrue(!overlaps.execute(env1, env2, sr, null)); + assertTrue(!overlaps.execute(env2, env1, sr, null)); + assertTrue(!crosses.execute(env1, env2, sr, null)); + assertTrue(!crosses.execute(env2, env1, sr, null)); + } + + { + Envelope env1 = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":10,\"ymin\":0,\"xmax\":20,\"ymax\":10}") + .getGeometry()); + Envelope env2 = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":0,\"ymin\":10,\"xmax\":10,\"ymax\":20}") + .getGeometry()); + wiggleGeometry(env1, 0.00000001, 1982); + wiggleGeometry(env2, 0.00000001, 511); + assertTrue(!equals.execute(env1, env2, sr, null)); + assertTrue(!contains.execute(env1, env2, sr, null)); + assertTrue(!contains.execute(env2, env1, sr, null)); + assertTrue(!disjoint.execute(env1, env2, sr, null)); + assertTrue(touches.execute(env1, env2, sr, null)); + assertTrue(!overlaps.execute(env1, env2, sr, null)); + assertTrue(!overlaps.execute(env2, env1, sr, null)); + assertTrue(!crosses.execute(env1, env2, sr, null)); + assertTrue(!crosses.execute(env2, env1, sr, null)); + } + + { + Envelope env1 = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":10}") + .getGeometry()); + Envelope env2 = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":0}") + .getGeometry()); + wiggleGeometry(env1, 0.00000001, 1982); + wiggleGeometry(env2, 0.00000001, 511); + assertTrue(!equals.execute(env1, env2, sr, null)); + assertTrue(!contains.execute(env1, env2, sr, null)); + assertTrue(!contains.execute(env2, env1, sr, null)); + assertTrue(!disjoint.execute(env1, env2, sr, null)); + assertTrue(touches.execute(env1, env2, sr, null)); + assertTrue(!overlaps.execute(env1, env2, sr, null)); + assertTrue(!overlaps.execute(env2, env1, sr, null)); + assertTrue(!crosses.execute(env1, env2, sr, null)); + assertTrue(!crosses.execute(env2, env1, sr, null)); + } + + { + Envelope env1 = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":10}") + .getGeometry()); + Envelope env2 = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":15,\"ymax\":0}") + .getGeometry()); + wiggleGeometry(env1, 0.00000001, 1982); + wiggleGeometry(env2, 0.00000001, 511); + assertTrue(!equals.execute(env1, env2, sr, null)); + assertTrue(!contains.execute(env1, env2, sr, null)); + assertTrue(!contains.execute(env2, env1, sr, null)); + assertTrue(!disjoint.execute(env1, env2, sr, null)); + assertTrue(touches.execute(env1, env2, sr, null)); + assertTrue(!overlaps.execute(env1, env2, sr, null)); + assertTrue(!overlaps.execute(env2, env1, sr, null)); + assertTrue(!crosses.execute(env1, env2, sr, null)); + assertTrue(!crosses.execute(env2, env1, sr, null)); + } + + { + Envelope env1 = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":10}") + .getGeometry()); + Envelope env2 = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":-5,\"ymin\":5,\"xmax\":0,\"ymax\":5}") + .getGeometry()); + wiggleGeometry(env1, 0.00000001, 1982); + wiggleGeometry(env2, 0.00000001, 511); + assertTrue(!equals.execute(env1, env2, sr, null)); + assertTrue(!contains.execute(env1, env2, sr, null)); + assertTrue(!contains.execute(env2, env1, sr, null)); + assertTrue(!disjoint.execute(env1, env2, sr, null)); + assertTrue(touches.execute(env1, env2, sr, null)); + assertTrue(!overlaps.execute(env1, env2, sr, null)); + assertTrue(!overlaps.execute(env2, env1, sr, null)); + assertTrue(!crosses.execute(env1, env2, sr, null)); + assertTrue(!crosses.execute(env2, env1, sr, null)); + } + + { + Envelope env1 = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":10}") + .getGeometry()); + Envelope env2 = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":-5,\"ymin\":5,\"xmax\":5,\"ymax\":5}") + .getGeometry()); + wiggleGeometry(env1, 0.00000001, 1982); + wiggleGeometry(env2, 0.00000001, 511); + assertTrue(!equals.execute(env1, env2, sr, null)); + assertTrue(!contains.execute(env1, env2, sr, null)); + assertTrue(!contains.execute(env2, env1, sr, null)); + assertTrue(!disjoint.execute(env1, env2, sr, null)); + assertTrue(!touches.execute(env1, env2, sr, null)); + assertTrue(!overlaps.execute(env1, env2, sr, null)); + assertTrue(!overlaps.execute(env2, env1, sr, null)); + assertTrue(crosses.execute(env1, env2, sr, null)); + assertTrue(crosses.execute(env2, env1, sr, null)); + } + + { + Envelope env1 = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":10}") + .getGeometry()); + Envelope env2 = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":3,\"ymin\":5,\"xmax\":5,\"ymax\":5}") + .getGeometry()); + wiggleGeometry(env1, 0.00000001, 1982); + wiggleGeometry(env2, 0.00000001, 511); + assertTrue(!equals.execute(env1, env2, sr, null)); + assertTrue(contains.execute(env1, env2, sr, null)); + assertTrue(!contains.execute(env2, env1, sr, null)); + assertTrue(!disjoint.execute(env1, env2, sr, null)); + assertTrue(!touches.execute(env1, env2, sr, null)); + assertTrue(!overlaps.execute(env1, env2, sr, null)); + assertTrue(!overlaps.execute(env2, env1, sr, null)); + assertTrue(!crosses.execute(env1, env2, sr, null)); + assertTrue(!crosses.execute(env2, env1, sr, null)); + } + + { + Envelope env1 = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":10}") + .getGeometry()); + Envelope env2 = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":3,\"ymin\":5,\"xmax\":10,\"ymax\":5}") + .getGeometry()); + wiggleGeometry(env1, 0.00000001, 1982); + wiggleGeometry(env2, 0.00000001, 511); + assertTrue(!equals.execute(env1, env2, sr, null)); + assertTrue(contains.execute(env1, env2, sr, null)); + assertTrue(!contains.execute(env2, env1, sr, null)); + assertTrue(!disjoint.execute(env1, env2, sr, null)); + assertTrue(!touches.execute(env1, env2, sr, null)); + assertTrue(!overlaps.execute(env1, env2, sr, null)); + assertTrue(!overlaps.execute(env2, env1, sr, null)); + assertTrue(!crosses.execute(env1, env2, sr, null)); + assertTrue(!crosses.execute(env2, env1, sr, null)); + } + + { + Envelope env1 = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":10}") + .getGeometry()); + Envelope env2 = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":-5,\"ymin\":0,\"xmax\":0,\"ymax\":0}") + .getGeometry()); + wiggleGeometry(env1, 0.00000001, 1982); + wiggleGeometry(env2, 0.00000001, 511); + assertTrue(!equals.execute(env1, env2, sr, null)); + assertTrue(!contains.execute(env1, env2, sr, null)); + assertTrue(!contains.execute(env2, env1, sr, null)); + assertTrue(!disjoint.execute(env1, env2, sr, null)); + assertTrue(touches.execute(env1, env2, sr, null)); + assertTrue(!overlaps.execute(env1, env2, sr, null)); + assertTrue(!overlaps.execute(env2, env1, sr, null)); + assertTrue(!crosses.execute(env1, env2, sr, null)); + assertTrue(!crosses.execute(env2, env1, sr, null)); + } + + { + Envelope env1 = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":0}") + .getGeometry()); + Envelope env2 = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":0}") + .getGeometry()); + wiggleGeometry(env1, 0.00000001, 1982); + wiggleGeometry(env2, 0.00000001, 511); + assertTrue(equals.execute(env1, env2, sr, null)); + assertTrue(contains.execute(env1, env2, sr, null)); + assertTrue(contains.execute(env2, env1, sr, null)); + assertTrue(!disjoint.execute(env1, env2, sr, null)); + assertTrue(!touches.execute(env1, env2, sr, null)); + assertTrue(!overlaps.execute(env1, env2, sr, null)); + assertTrue(!overlaps.execute(env2, env1, sr, null)); + assertTrue(!crosses.execute(env1, env2, sr, null)); + assertTrue(!crosses.execute(env2, env1, sr, null)); + } + + { + Envelope env1 = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":15,\"ymax\":0}") + .getGeometry()); + Envelope env2 = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":0}") + .getGeometry()); + wiggleGeometry(env1, 0.00000001, 1982); + wiggleGeometry(env2, 0.00000001, 511); + assertTrue(!equals.execute(env1, env2, sr, null)); + assertTrue(contains.execute(env1, env2, sr, null)); + assertTrue(!contains.execute(env2, env1, sr, null)); + assertTrue(!disjoint.execute(env1, env2, sr, null)); + assertTrue(!touches.execute(env1, env2, sr, null)); + assertTrue(!overlaps.execute(env1, env2, sr, null)); + assertTrue(!overlaps.execute(env2, env1, sr, null)); + assertTrue(!crosses.execute(env1, env2, sr, null)); + assertTrue(!crosses.execute(env2, env1, sr, null)); + } + + { + Envelope env1 = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":15,\"ymax\":0}") + .getGeometry()); + Envelope env2 = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":-5,\"ymin\":0,\"xmax\":10,\"ymax\":0}") + .getGeometry()); + wiggleGeometry(env1, 0.00000001, 1982); + wiggleGeometry(env2, 0.00000001, 511); + assertTrue(!equals.execute(env1, env2, sr, null)); + assertTrue(!contains.execute(env1, env2, sr, null)); + assertTrue(!contains.execute(env2, env1, sr, null)); + assertTrue(!disjoint.execute(env1, env2, sr, null)); + assertTrue(!touches.execute(env1, env2, sr, null)); + assertTrue(overlaps.execute(env1, env2, sr, null)); + assertTrue(overlaps.execute(env2, env1, sr, null)); + assertTrue(!crosses.execute(env1, env2, sr, null)); + assertTrue(!crosses.execute(env2, env1, sr, null)); + } + + { + Envelope env1 = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":5,\"ymax\":0}") + .getGeometry()); + Envelope env2 = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":-5,\"ymin\":0,\"xmax\":0,\"ymax\":0}") + .getGeometry()); + wiggleGeometry(env1, 0.00000001, 1982); + wiggleGeometry(env2, 0.00000001, 511); + assertTrue(!equals.execute(env1, env2, sr, null)); + assertTrue(!contains.execute(env1, env2, sr, null)); + assertTrue(!contains.execute(env2, env1, sr, null)); + assertTrue(!disjoint.execute(env1, env2, sr, null)); + assertTrue(touches.execute(env1, env2, sr, null)); + assertTrue(!overlaps.execute(env1, env2, sr, null)); + assertTrue(!overlaps.execute(env2, env1, sr, null)); + assertTrue(!crosses.execute(env1, env2, sr, null)); + assertTrue(!crosses.execute(env2, env1, sr, null)); + } + + { + Envelope env1 = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":0}") + .getGeometry()); + Envelope env2 = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":5,\"ymin\":-5,\"xmax\":5,\"ymax\":5}") + .getGeometry()); + wiggleGeometry(env1, 0.00000001, 1982); + wiggleGeometry(env2, 0.00000001, 511); + assertTrue(!equals.execute(env1, env2, sr, null)); + assertTrue(!contains.execute(env1, env2, sr, null)); + assertTrue(!contains.execute(env2, env1, sr, null)); + assertTrue(!disjoint.execute(env1, env2, sr, null)); + assertTrue(!touches.execute(env1, env2, sr, null)); + assertTrue(!overlaps.execute(env1, env2, sr, null)); + assertTrue(!overlaps.execute(env2, env1, sr, null)); + assertTrue(crosses.execute(env1, env2, sr, null)); + assertTrue(crosses.execute(env2, env1, sr, null)); + } + + { + Envelope env1 = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":0}") + .getGeometry()); + Envelope env2 = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":10,\"ymin\":0,\"xmax\":20,\"ymax\":0}") + .getGeometry()); + wiggleGeometry(env1, 0.00000001, 1982); + wiggleGeometry(env2, 0.00000001, 511); + assertTrue(!equals.execute(env1, env2, sr, null)); + assertTrue(!contains.execute(env1, env2, sr, null)); + assertTrue(!contains.execute(env2, env1, sr, null)); + assertTrue(!disjoint.execute(env1, env2, sr, null)); + assertTrue(touches.execute(env1, env2, sr, null)); + assertTrue(!overlaps.execute(env1, env2, sr, null)); + assertTrue(!overlaps.execute(env2, env1, sr, null)); + assertTrue(!crosses.execute(env1, env2, sr, null)); + assertTrue(!crosses.execute(env2, env1, sr, null)); + } + + { + Envelope env1 = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":0}") + .getGeometry()); + Envelope env2 = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":5,\"ymin\":0,\"xmax\":5,\"ymax\":5}") + .getGeometry()); + wiggleGeometry(env1, 0.00000001, 1982); + wiggleGeometry(env2, 0.00000001, 511); + assertTrue(!equals.execute(env1, env2, sr, null)); + assertTrue(!contains.execute(env1, env2, sr, null)); + assertTrue(!contains.execute(env2, env1, sr, null)); + assertTrue(!disjoint.execute(env1, env2, sr, null)); + assertTrue(touches.execute(env1, env2, sr, null)); + assertTrue(touches.execute(env2, env1, sr, null)); + assertTrue(!overlaps.execute(env1, env2, sr, null)); + assertTrue(!overlaps.execute(env2, env1, sr, null)); + assertTrue(!crosses.execute(env1, env2, sr, null)); + assertTrue(!crosses.execute(env2, env1, sr, null)); + } + + { + Envelope env1 = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":0,\"ymax\":0}") + .getGeometry()); + Envelope env2 = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":10}") + .getGeometry()); + wiggleGeometry(env1, 0.00000001, 1982); + wiggleGeometry(env2, 0.00000001, 511); + assertTrue(!equals.execute(env1, env2, sr, null)); + assertTrue(!contains.execute(env1, env2, sr, null)); + assertTrue(!contains.execute(env2, env1, sr, null)); + assertTrue(!disjoint.execute(env1, env2, sr, null)); + assertTrue(touches.execute(env1, env2, sr, null)); + assertTrue(touches.execute(env2, env1, sr, null)); + assertTrue(!overlaps.execute(env1, env2, sr, null)); + assertTrue(!overlaps.execute(env2, env1, sr, null)); + assertTrue(!crosses.execute(env1, env2, sr, null)); + assertTrue(!crosses.execute(env2, env1, sr, null)); + } + + { + Envelope env1 = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":5,\"ymin\":0,\"xmax\":5,\"ymax\":0}") + .getGeometry()); + Envelope env2 = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":10}") + .getGeometry()); + wiggleGeometry(env1, 0.00000001, 1982); + wiggleGeometry(env2, 0.00000001, 511); + assertTrue(!equals.execute(env1, env2, sr, null)); + assertTrue(!contains.execute(env1, env2, sr, null)); + assertTrue(!contains.execute(env2, env1, sr, null)); + assertTrue(!disjoint.execute(env1, env2, sr, null)); + assertTrue(touches.execute(env1, env2, sr, null)); + assertTrue(touches.execute(env2, env1, sr, null)); + assertTrue(!overlaps.execute(env1, env2, sr, null)); + assertTrue(!overlaps.execute(env2, env1, sr, null)); + assertTrue(!crosses.execute(env1, env2, sr, null)); + assertTrue(!crosses.execute(env2, env1, sr, null)); + } + + { + Envelope env1 = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":5,\"ymin\":5,\"xmax\":5,\"ymax\":5}") + .getGeometry()); + Envelope env2 = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":10}") + .getGeometry()); + wiggleGeometry(env1, 0.00000001, 1982); + wiggleGeometry(env2, 0.00000001, 511); + assertTrue(!equals.execute(env1, env2, sr, null)); + assertTrue(!contains.execute(env1, env2, sr, null)); + assertTrue(contains.execute(env2, env1, sr, null)); + assertTrue(!disjoint.execute(env1, env2, sr, null)); + assertTrue(!touches.execute(env1, env2, sr, null)); + assertTrue(!touches.execute(env2, env1, sr, null)); + assertTrue(!overlaps.execute(env1, env2, sr, null)); + assertTrue(!overlaps.execute(env2, env1, sr, null)); + assertTrue(!crosses.execute(env1, env2, sr, null)); + assertTrue(!crosses.execute(env2, env1, sr, null)); + } + + { + Envelope env1 = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":0,\"ymax\":0}") + .getGeometry()); + Envelope env2 = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":0}") + .getGeometry()); + wiggleGeometry(env1, 0.00000001, 1982); + wiggleGeometry(env2, 0.00000001, 511); + assertTrue(!equals.execute(env1, env2, sr, null)); + assertTrue(!contains.execute(env1, env2, sr, null)); + assertTrue(!contains.execute(env2, env1, sr, null)); + assertTrue(!disjoint.execute(env1, env2, sr, null)); + assertTrue(touches.execute(env1, env2, sr, null)); + assertTrue(touches.execute(env2, env1, sr, null)); + assertTrue(!overlaps.execute(env1, env2, sr, null)); + assertTrue(!overlaps.execute(env2, env1, sr, null)); + assertTrue(!crosses.execute(env1, env2, sr, null)); + assertTrue(!crosses.execute(env2, env1, sr, null)); + } + + { + Envelope env1 = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":5,\"ymin\":0,\"xmax\":5,\"ymax\":0}") + .getGeometry()); + Envelope env2 = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":0,\"ymin\":0,\"xmax\":10,\"ymax\":0}") + .getGeometry()); + wiggleGeometry(env1, 0.00000001, 1982); + wiggleGeometry(env2, 0.00000001, 511); + assertTrue(!equals.execute(env1, env2, sr, null)); + assertTrue(!contains.execute(env1, env2, sr, null)); + assertTrue(contains.execute(env2, env1, sr, null)); + assertTrue(!disjoint.execute(env1, env2, sr, null)); + assertTrue(!touches.execute(env1, env2, sr, null)); + assertTrue(!touches.execute(env2, env1, sr, null)); + assertTrue(!overlaps.execute(env1, env2, sr, null)); + assertTrue(!overlaps.execute(env2, env1, sr, null)); + assertTrue(!crosses.execute(env1, env2, sr, null)); + assertTrue(!crosses.execute(env2, env1, sr, null)); + } + + { + Envelope env1 = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":5,\"ymin\":0,\"xmax\":5,\"ymax\":0}") + .getGeometry()); + Envelope env2 = (Envelope) (TestCommonMethods + .fromJson("{\"xmin\":5,\"ymin\":0,\"xmax\":5,\"ymax\":0}") + .getGeometry()); + wiggleGeometry(env1, 0.00000001, 1982); + wiggleGeometry(env2, 0.00000001, 511); + assertTrue(equals.execute(env1, env2, sr, null)); + assertTrue(contains.execute(env1, env2, sr, null)); + assertTrue(contains.execute(env2, env1, sr, null)); + assertTrue(!disjoint.execute(env1, env2, sr, null)); + assertTrue(!touches.execute(env1, env2, sr, null)); + assertTrue(!touches.execute(env2, env1, sr, null)); + assertTrue(!overlaps.execute(env1, env2, sr, null)); + assertTrue(!overlaps.execute(env2, env1, sr, null)); + assertTrue(!crosses.execute(env1, env2, sr, null)); + assertTrue(!crosses.execute(env2, env1, sr, null)); + } + } + + static void wiggleGeometry(Geometry geometry, double tolerance, int rand) { + int type = geometry.getType().value(); + + if (type == Geometry.GeometryType.Polygon + || type == Geometry.GeometryType.Polyline + || type == Geometry.GeometryType.MultiPoint) { + MultiVertexGeometry mvGeom = (MultiVertexGeometry) geometry; + for (int i = 0; i < mvGeom.getPointCount(); i++) { + Point2D pt = mvGeom.getXY(i); + + // create random vector and normalize it to 0.49 * tolerance + Point2D randomV = new Point2D(); + rand = NumberUtils.nextRand(rand); + randomV.x = 1.0 * rand / NumberUtils.intMax() - 0.5; + rand = NumberUtils.nextRand(rand); + randomV.y = 1.0 * rand / NumberUtils.intMax() - 0.5; + randomV.normalize(); + randomV.scale(0.45 * tolerance); + pt.add(randomV); + mvGeom.setXY(i, pt); + } + } else if (type == Geometry.GeometryType.Point) { + Point ptGeom = (Point) (geometry); + Point2D pt = ptGeom.getXY(); + // create random vector and normalize it to 0.49 * tolerance + Point2D randomV = new Point2D(); + rand = NumberUtils.nextRand(rand); + randomV.x = 1.0 * rand / NumberUtils.intMax() - 0.5; + rand = NumberUtils.nextRand(rand); + randomV.y = 1.0 * rand / NumberUtils.intMax() - 0.5; + randomV.normalize(); + randomV.scale(0.45 * tolerance); + pt.add(randomV); + ptGeom.setXY(pt); + } else if (type == Geometry.GeometryType.Envelope) { + Envelope envGeom = (Envelope) (geometry); + Envelope2D env = new Envelope2D(); + envGeom.queryEnvelope2D(env); + double xmin, xmax, ymin, ymax; + Point2D pt = new Point2D(); + env.queryLowerLeft(pt); + // create random vector and normalize it to 0.49 * tolerance + Point2D randomV = new Point2D(); + rand = NumberUtils.nextRand(rand); + randomV.x = 1.0 * rand / NumberUtils.intMax() - 0.5; + rand = NumberUtils.nextRand(rand); + randomV.y = 1.0 * rand / NumberUtils.intMax() - 0.5; + randomV.normalize(); + randomV.scale(0.45 * tolerance); + xmin = (pt.x + randomV.x); + ymin = (pt.y + randomV.y); + + env.queryUpperRight(pt); + // create random vector and normalize it to 0.49 * tolerance + rand = NumberUtils.nextRand(rand); + randomV.x = 1.0 * rand / NumberUtils.intMax() - 0.5; + rand = NumberUtils.nextRand(rand); + randomV.y = 1.0 * rand / NumberUtils.intMax() - 0.5; + randomV.normalize(); + randomV.scale(0.45 * tolerance); + xmax = (pt.x + randomV.x); + ymax = (pt.y + randomV.y); + + if (xmin > xmax) { + double swap = xmin; + xmin = xmax; + xmax = swap; + } + + if (ymin > ymax) { + double swap = ymin; + ymin = ymax; + ymax = swap; + } + + envGeom.setCoords(xmin, ymin, xmax, ymax); + } + + } + + @Test + public void testDisjointRelationFalse() { + { + OperatorDisjoint op = (OperatorDisjoint) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Disjoint)); + Envelope env1 = new Envelope(50, 50, 150, 150); + Envelope env2 = new Envelope(25, 25, 175, 175); + boolean result = op.execute(env1, env2, + SpatialReference.create(4326), null); + assertTrue(!result); + } + { + OperatorIntersects op = (OperatorIntersects) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Intersects)); + Envelope env1 = new Envelope(50, 50, 150, 150); + Envelope env2 = new Envelope(25, 25, 175, 175); + boolean result = op.execute(env1, env2, + SpatialReference.create(4326), null); + assertTrue(result); + } + { + OperatorContains op = (OperatorContains) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Contains)); + Envelope env1 = new Envelope(100, 175, 200, 225); + Polyline polyline = new Polyline(); + polyline.startPath(200, 175); + polyline.lineTo(200, 225); + polyline.lineTo(125, 200); + boolean result = op.execute(env1, polyline, + SpatialReference.create(4326), null); + assertTrue(result); + } + { + OperatorTouches op = (OperatorTouches) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Touches)); + Envelope env1 = new Envelope(100, 200, 400, 400); + Polyline polyline = new Polyline(); + polyline.startPath(300, 60); + polyline.lineTo(300, 200); + polyline.lineTo(400, 50); + boolean result = op.execute(env1, polyline, + SpatialReference.create(4326), null); + assertTrue(result); + } + + { + OperatorTouches op = (OperatorTouches) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Touches)); + Envelope env1 = new Envelope(50, 50, 150, 150); + Polyline polyline = new Polyline(); + polyline.startPath(100, 20); + polyline.lineTo(100, 50); + polyline.lineTo(150, 10); + boolean result = op.execute(polyline, env1, + SpatialReference.create(4326), null); + assertTrue(result); + } + + { + OperatorDisjoint op = (OperatorDisjoint) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Disjoint)); + Polygon polygon = new Polygon(); + Polyline polyline = new Polyline(); + polygon.startPath(0, 0); + polygon.lineTo(0, 10); + polygon.lineTo(10, 10); + polygon.lineTo(10, 0); + polyline.startPath(-5, 4); + polyline.lineTo(5, -6); + boolean result = op.execute(polyline, polygon, + SpatialReference.create(4326), null); + assertTrue(result); + } + } + + @Test + public void testPolylinePolylineRelate() { + OperatorRelate op = OperatorRelate.local(); + SpatialReference sr = SpatialReference.create(4326); + boolean res; + String scl; + + Polyline polyline1 = new Polyline(); + Polyline polyline2 = new Polyline(); + + polyline1.startPath(0, 0); + polyline1.lineTo(1, 1); + + polyline2.startPath(1, 1); + polyline2.lineTo(2, 0); + + scl = "FF1FT01T2"; + res = op.execute(polyline1, polyline2, sr, scl, null); + assertTrue(res); + + scl = "****TF*T*"; + res = op.execute(polyline1, polyline2, sr, scl, null); + assertTrue(!res); + + scl = "****F****"; + res = op.execute(polyline1, polyline2, sr, scl, null); + assertTrue(!res); + + scl = "**1*0*T**"; + res = op.execute(polyline1, polyline2, sr, scl, null); + assertTrue(res); + + scl = "****1****"; + res = op.execute(polyline1, polyline2, sr, scl, null); + assertTrue(!res); + + scl = "**T*001*T"; + res = op.execute(polyline1, polyline2, sr, scl, null); + assertTrue(res); + + scl = "T********"; + res = op.execute(polyline1, polyline2, sr, scl, null); + assertTrue(!res); + + scl = "F********"; + res = op.execute(polyline1, polyline2, sr, scl, null); + assertTrue(res); + + polyline1.setEmpty(); + polyline2.setEmpty(); + + polyline1.startPath(0, 0); + polyline1.lineTo(1, 0); + + polyline2.startPath(0, 0); + polyline2.lineTo(1, 0); + + scl = "1FFFTFFFT"; + res = op.execute(polyline1, polyline2, sr, scl, null); + assertTrue(res); + + scl = "1*T*T****"; + res = op.execute(polyline1, polyline2, sr, scl, null); + assertTrue(!res); + + scl = "1T**T****"; + res = op.execute(polyline1, polyline2, sr, scl, null); + assertTrue(!res); + + polyline1.setEmpty(); + polyline2.setEmpty(); + + polyline1.startPath(0, 0); + polyline1.lineTo(0.5, 0.5); + polyline1.lineTo(1, 1); + + polyline2.startPath(1, 0); + polyline2.lineTo(0.5, 0.5); + polyline2.lineTo(0, 1); + + scl = "0F1FFTT0T"; + res = op.execute(polyline1, polyline2, sr, scl, null); + assertTrue(res); + + scl = "*T*******"; + res = op.execute(polyline1, polyline2, sr, scl, null); + assertTrue(!res); + + scl = "*F*F*****"; + res = op.execute(polyline1, polyline2, sr, scl, null); + assertTrue(res); + + polyline1.setEmpty(); + polyline2.setEmpty(); + + polyline1.startPath(0, 0); + polyline1.lineTo(1, 0); - polyline2.startPath(1, -1); - polyline2.lineTo(1, 1); + polyline2.startPath(1, -1); + polyline2.lineTo(1, 1); - scl = "FT1TF01TT"; - res = op.execute(polyline1, polyline2, sr, scl, null); - assertTrue(!res); + scl = "FT1TF01TT"; + res = op.execute(polyline1, polyline2, sr, scl, null); + assertTrue(!res); - scl = "***T*****"; - res = op.execute(polyline1, polyline2, sr, scl, null); - assertTrue(res); + scl = "***T*****"; + res = op.execute(polyline1, polyline2, sr, scl, null); + assertTrue(res); - polyline1.setEmpty(); - polyline2.setEmpty(); - - polyline1.startPath(0, 0); - polyline1.lineTo(0, 20); - polyline1.lineTo(20, 20); - polyline1.lineTo(20, 0); - polyline1.lineTo(0, 0); // has no boundary - - polyline2.startPath(3, 3); - polyline2.lineTo(5, 5); - - op.accelerateGeometry(polyline1, sr, Geometry.GeometryAccelerationDegree.enumHot); - - scl = "FF1FFF102"; - res = op.execute(polyline1, polyline2, sr, scl, null); - assertTrue(res); - - polyline1.setEmpty(); - polyline2.setEmpty(); - - polyline1.startPath(4, 0); - polyline1.lineTo(0, 4); - polyline1.lineTo(4, 8); - polyline1.lineTo(8, 4); - - polyline2.startPath(8, 1); - polyline2.lineTo(8, 2); - - op.accelerateGeometry(polyline1, sr, GeometryAccelerationDegree.enumHot); + polyline1.setEmpty(); + polyline2.setEmpty(); + + polyline1.startPath(0, 0); + polyline1.lineTo(0, 20); + polyline1.lineTo(20, 20); + polyline1.lineTo(20, 0); + polyline1.lineTo(0, 0); // has no boundary + + polyline2.startPath(3, 3); + polyline2.lineTo(5, 5); + + op.accelerateGeometry(polyline1, sr, Geometry.GeometryAccelerationDegree.enumHot); + + scl = "FF1FFF102"; + res = op.execute(polyline1, polyline2, sr, scl, null); + assertTrue(res); + + polyline1.setEmpty(); + polyline2.setEmpty(); + + polyline1.startPath(4, 0); + polyline1.lineTo(0, 4); + polyline1.lineTo(4, 8); + polyline1.lineTo(8, 4); + + polyline2.startPath(8, 1); + polyline2.lineTo(8, 2); + + op.accelerateGeometry(polyline1, sr, GeometryAccelerationDegree.enumHot); - scl = "FF1FF0102"; - res = op.execute(polyline1, polyline2, sr, scl, null); - assertTrue(res); + scl = "FF1FF0102"; + res = op.execute(polyline1, polyline2, sr, scl, null); + assertTrue(res); - polyline1.setEmpty(); - polyline2.setEmpty(); - polyline1.startPath(4, 0); - polyline1.lineTo(0, 4); - polyline2.startPath(3, 2); - polyline2.lineTo(3, 2); - assertTrue(polyline2.getBoundary().isEmpty()); - - scl = "******0F*"; - res = op.execute(polyline1, polyline2, sr, scl, null); - assertTrue(res); - - polyline2.lineTo(3, 2); - assertTrue(polyline2.getBoundary().isEmpty()); - - scl = "******0F*"; - res = op.execute(polyline1, polyline2, sr, scl, null); - assertTrue(res); - scl = "******0F*"; - - polyline2.lineTo(3, 2); - assertTrue(polyline2.getBoundary().isEmpty()); - - res = op.execute(polyline1, polyline2, sr, scl, null); - assertTrue(res); - - polyline1.setEmpty(); - polyline2.setEmpty(); - polyline1.startPath(3, 3); - polyline1.lineTo(3, 4); - polyline1.lineTo(3, 3); - polyline2.startPath(1, 1); - polyline2.lineTo(1, 1); - - scl = "FF1FFF0F2"; - res = op.execute(polyline1, polyline2, sr, scl, null); - assertTrue(res); - scl = "FF0FFF1F2"; - res = op.execute(polyline2, polyline1, sr, scl, null); - assertTrue(res); - - polyline1.setEmpty(); - polyline2.setEmpty(); - polyline1.startPath(4, 0); - polyline1.lineTo(0, 4); - polyline2.startPath(2, 2); - polyline2.lineTo(2, 2); - - scl = "0F*******"; - res = op.execute(polyline1, polyline2, sr, scl, null); - assertTrue(res); - - polyline2.lineTo(2, 2); - - scl = "0F*******"; - res = op.execute(polyline1, polyline2, sr, scl, null); - assertTrue(res); - scl = "0F*******"; - res = op.execute(polyline1, polyline2, sr, scl, null); - assertTrue(res); - } - - @Test - public void testPolygonPolylineRelate() { - OperatorRelate op = OperatorRelate.local(); - SpatialReference sr = SpatialReference.create(4326); - boolean res; - String scl; - - Polygon polygon1 = new Polygon(); - Polyline polyline2 = new Polyline(); - - polygon1.startPath(0, 0); - polygon1.lineTo(0, 10); - polygon1.lineTo(10, 10); - polygon1.lineTo(10, 0); - - polyline2.startPath(-10, 0); - polyline2.lineTo(0, 0); - - scl = "FF2F01102"; - res = op.execute(polygon1, polyline2, sr, scl, null); - assertTrue(res); - - scl = "**1*0110*"; - res = op.execute(polygon1, polyline2, sr, scl, null); - assertTrue(!res); - - scl = "T***T****"; - res = op.execute(polygon1, polyline2, sr, scl, null); - assertTrue(!res); - - scl = "FF2FT****"; - res = op.execute(polygon1, polyline2, sr, scl, null); - assertTrue(res); - - polyline2.setEmpty(); - polyline2.startPath(0, 0); - polyline2.lineTo(10, 0); - - scl = "**21*1FF*"; - res = op.execute(polygon1, polyline2, sr, scl, null); - assertTrue(res); - - scl = "F*21*1FF*"; - res = op.execute(polygon1, polyline2, sr, scl, null); - assertTrue(res); - - scl = "0**1*1FF*"; - res = op.execute(polygon1, polyline2, sr, scl, null); - assertTrue(!res); - - scl = "F**1*1TF*"; - res = op.execute(polygon1, polyline2, sr, scl, null); - assertTrue(!res); - - polyline2.setEmpty(); - polyline2.startPath(1, 1); - polyline2.lineTo(5, 5); - - scl = "TT2******"; - res = op.execute(polygon1, polyline2, sr, scl, null); - assertTrue(res); - - scl = "1T2FF1FF*"; - res = op.execute(polygon1, polyline2, sr, scl, null); - assertTrue(res); - - scl = "1T1FF1FF*"; - res = op.execute(polygon1, polyline2, sr, scl, null); - assertTrue(!res); - - polyline2.setEmpty(); - polyline2.startPath(5, 5); - polyline2.lineTo(15, 5); - - scl = "1T20F*T0T"; - res = op.execute(polygon1, polyline2, sr, scl, null); - assertTrue(res); - - polygon1.setEmpty(); - polyline2.setEmpty(); - - polygon1.startPath(2, 0); - polygon1.lineTo(0, 2); - polygon1.lineTo(2, 4); - polygon1.lineTo(4, 2); - - polyline2.startPath(1, 2); - polyline2.lineTo(3, 2); - - op.accelerateGeometry(polygon1, sr, GeometryAccelerationDegree.enumHot); - scl = "TTTFF****"; - res = op.execute(polygon1, polyline2, sr, scl, null); - assertTrue(res); - - polyline2.setEmpty(); - polyline2.startPath(5, 2); - polyline2.lineTo(7, 2); - scl = "FF2FFT***"; - res = op.execute(polygon1, polyline2, sr, scl, null); - assertTrue(res); - - polygon1.setEmpty(); - polyline2.setEmpty(); - polygon1.startPath(0, 0); - polygon1.lineTo(0, 1); - polygon1.lineTo(1, 0); - polyline2.startPath(0, 10); - polyline2.lineTo(0, 9); - polyline2.startPath(10, 0); - polyline2.lineTo(9, 0); - polyline2.startPath(0, -10); - polyline2.lineTo(0, -9); - scl = "**2******"; - res = op.execute(polygon1, polyline2, sr, scl, null); - assertTrue(res); - - polygon1.setEmpty(); - polyline2.setEmpty(); - polygon1.startPath(0, 0); - polygon1.lineTo(0, 1); - polygon1.lineTo(0, 0); - polyline2.startPath(0, 10); - polyline2.lineTo(0, 9); - scl = "**1******"; - res = op.execute(polygon1, polyline2, sr, scl, null); - assertTrue(res); - } - - @Test - public void testPolygonPolygonRelate() { - OperatorRelate op = (OperatorRelate) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Relate)); - SpatialReference sr = SpatialReference.create(4326); - boolean res; - String scl; - - Polygon polygon1 = new Polygon(); - Polygon polygon2 = new Polygon(); - - polygon1.startPath(0, 0); - polygon1.lineTo(0, 10); - polygon1.lineTo(10, 10); - polygon1.lineTo(10, 0); - - polygon2.startPath(15, 0); - polygon2.lineTo(15, 10); - polygon2.lineTo(25, 10); - polygon2.lineTo(25, 0); - - scl = "FFTFFT21T"; - res = op.execute(polygon1, polygon2, sr, scl, null); - assertTrue(res); - - scl = "FFTFFT11T"; - res = op.execute(polygon1, polygon2, sr, scl, null); - assertTrue(!res); - - polygon2.setEmpty(); - polygon2.startPath(5, 0); - polygon2.lineTo(5, 10); - polygon2.lineTo(15, 10); - polygon2.lineTo(15, 0); - - scl = "21TT1121T"; - res = op.execute(polygon1, polygon2, sr, scl, null); - assertTrue(res); - - polygon2.setEmpty(); - polygon2.startPath(1, 1); - polygon2.lineTo(1, 9); - polygon2.lineTo(9, 9); - polygon2.lineTo(9, 1); - - scl = "212FF1FFT"; - res = op.execute(polygon1, polygon2, sr, scl, null); - assertTrue(res); - - polygon1.setEmpty(); - polygon2.setEmpty(); - polygon1.startPath(3, 3); - polygon1.lineTo(3, 4); - polygon1.lineTo(3, 3); - polygon2.startPath(1, 1); - polygon2.lineTo(1, 1); - - scl = "FF1FFF0F2"; - res = op.execute(polygon1, polygon2, sr, scl, null); - assertTrue(res); - scl = "FF0FFF1F2"; - res = op.execute(polygon2, polygon1, sr, scl, null); - assertTrue(res); - - polygon1.setEmpty(); - polygon2.setEmpty(); - polygon1.startPath(0, 0); - polygon1.lineTo(0, 100); - polygon1.lineTo(100, 100); - polygon1.lineTo(100, 0); - polygon2.startPath(50, 50); - polygon2.lineTo(50, 50); - polygon2.lineTo(50, 50); - - op.accelerateGeometry(polygon1, sr, GeometryAccelerationDegree.enumHot); - - scl = "0F2FF1FF2"; - res = op.execute(polygon1, polygon2, sr, scl, null); - assertTrue(res); - - polygon2.lineTo(51, 50); - scl = "1F2FF1FF2"; - res = op.execute(polygon1, polygon2, sr, scl, null); - assertTrue(res); - } - - @Test - public void testMultiPointPointRelate() { - OperatorRelate op = (OperatorRelate) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Relate)); - SpatialReference sr = SpatialReference.create(4326); - boolean res; - String scl; - - MultiPoint m1 = new MultiPoint(); - Point p2 = new Point(); - - m1.add(0, 0); - p2.setXY(0, 0); - - scl = "T*F***F**"; - res = op.execute(m1, p2, sr, scl, null); - assertTrue(res); - - scl = "T*T***F**"; - res = op.execute(m1, p2, sr, scl, null); - assertTrue(!res); - - m1.add(1, 1); - res = op.execute(m1, p2, sr, scl, null); - assertTrue(res); - - m1.setEmpty(); - - m1.add(1, 1); - m1.add(2, 2); - - scl = "FF0FFFTF2"; - res = op.execute(m1, p2, sr, scl, null); - assertTrue(res); - } - - @Test - public void testPointPointRelate() { - OperatorRelate op = (OperatorRelate) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Relate)); - SpatialReference sr = SpatialReference.create(4326); - boolean res; - String scl; - - Point p1 = new Point(); - Point p2 = new Point(); - - p1.setXY(0, 0); - p2.setXY(0, 0); - - scl = "T********"; - res = op.execute(p1, p2, sr, scl, null); - assertTrue(res); - - p1.setXY(0, 0); - p2.setXY(1, 0); - res = op.execute(p1, p2, null, scl, null); - assertTrue(!res); - - p1.setEmpty(); - p2.setEmpty(); - scl = "*********"; - res = op.execute(p1, p2, null, scl, null); - assertTrue(res); - scl = "FFFFFFFFF"; - res = op.execute(p1, p2, null, scl, null); - assertTrue(res); - scl = "FFFFFFFFT"; - res = op.execute(p1, p2, null, scl, null); - assertTrue(!res); - } - - @Test - public void testPolygonMultiPointRelate() { - OperatorRelate op = (OperatorRelate) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Relate)); - SpatialReference sr = SpatialReference.create(4326); - boolean res; - String scl; - - Polygon polygon1 = new Polygon(); - MultiPoint multipoint2 = new MultiPoint(); - - polygon1.startPath(0, 0); - polygon1.lineTo(0, 10); - polygon1.lineTo(10, 10); - polygon1.lineTo(10, 0); - - multipoint2.add(0, 0); - multipoint2.add(5, 5); - - scl = "TFT0F1FFT"; - res = op.execute(polygon1, multipoint2, sr, scl, null); - assertTrue(res); - - scl = "T0FFFFT1T"; // transpose of above - res = op.execute(multipoint2, polygon1, sr, scl, null); - assertTrue(res); - - multipoint2.add(11, 11); - - scl = "TFT0F10FT"; - res = op.execute(polygon1, multipoint2, sr, scl, null); - assertTrue(res); - - multipoint2.add(0, 5); - - scl = "TFT0F10FT"; - res = op.execute(polygon1, multipoint2, sr, scl, null); - assertTrue(res); - - scl = "TFF0F10FT"; - res = op.execute(polygon1, multipoint2, sr, scl, null); - assertTrue(!res); - - polygon1.setEmpty(); - multipoint2.setEmpty(); - - polygon1.startPath(0, 0); - polygon1.lineTo(0, 20); - polygon1.lineTo(20, 20); - polygon1.lineTo(20, 0); - - multipoint2.add(3, 3); - multipoint2.add(5, 5); - - op.accelerateGeometry(polygon1, sr, - Geometry.GeometryAccelerationDegree.enumHot); - - scl = "TF2FF****"; - res = op.execute(polygon1, multipoint2, sr, scl, null); - assertTrue(res); - - polygon1.setEmpty(); - multipoint2.setEmpty(); - - polygon1.startPath(4, 0); - polygon1.lineTo(0, 4); - polygon1.lineTo(4, 8); - polygon1.lineTo(8, 4); - - multipoint2.add(8, 1); - multipoint2.add(8, 2); - - op.accelerateGeometry(polygon1, sr, - Geometry.GeometryAccelerationDegree.enumHot); - - scl = "FF2FF10F2"; - res = op.execute(polygon1, multipoint2, sr, scl, null); - assertTrue(res); - } - - @Test - public void testPolygonPointRelate() { - OperatorRelate op = (OperatorRelate) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Relate)); - SpatialReference sr = SpatialReference.create(4326); - boolean res; - String scl; - - Polygon polygon = new Polygon(); - Point point = new Point(); - - polygon.startPath(0, 0); - polygon.lineTo(0, 10); - polygon.lineTo(10, 10); - polygon.lineTo(10, 0); - - point.setXY(0, 0); - - scl = "FF20FTFFT"; - res = op.execute(polygon, point, sr, scl, null); - assertTrue(res); - - polygon.setEmpty(); - polygon.startPath(0, 0); - polygon.lineTo(0, 0); - polygon.lineTo(0, 0); - scl = "0FFFFFFF2"; - res = op.execute(polygon, point, sr, scl, null); - assertTrue(res); + polyline1.setEmpty(); + polyline2.setEmpty(); + polyline1.startPath(4, 0); + polyline1.lineTo(0, 4); + polyline2.startPath(3, 2); + polyline2.lineTo(3, 2); + assertTrue(polyline2.getBoundary().isEmpty()); + + scl = "******0F*"; + res = op.execute(polyline1, polyline2, sr, scl, null); + assertTrue(res); + + polyline2.lineTo(3, 2); + assertTrue(polyline2.getBoundary().isEmpty()); + + scl = "******0F*"; + res = op.execute(polyline1, polyline2, sr, scl, null); + assertTrue(res); + scl = "******0F*"; + + polyline2.lineTo(3, 2); + assertTrue(polyline2.getBoundary().isEmpty()); + + res = op.execute(polyline1, polyline2, sr, scl, null); + assertTrue(res); + + polyline1.setEmpty(); + polyline2.setEmpty(); + polyline1.startPath(3, 3); + polyline1.lineTo(3, 4); + polyline1.lineTo(3, 3); + polyline2.startPath(1, 1); + polyline2.lineTo(1, 1); + + scl = "FF1FFF0F2"; + res = op.execute(polyline1, polyline2, sr, scl, null); + assertTrue(res); + scl = "FF0FFF1F2"; + res = op.execute(polyline2, polyline1, sr, scl, null); + assertTrue(res); + + polyline1.setEmpty(); + polyline2.setEmpty(); + polyline1.startPath(4, 0); + polyline1.lineTo(0, 4); + polyline2.startPath(2, 2); + polyline2.lineTo(2, 2); + + scl = "0F*******"; + res = op.execute(polyline1, polyline2, sr, scl, null); + assertTrue(res); + + polyline2.lineTo(2, 2); + + scl = "0F*******"; + res = op.execute(polyline1, polyline2, sr, scl, null); + assertTrue(res); + scl = "0F*******"; + res = op.execute(polyline1, polyline2, sr, scl, null); + assertTrue(res); + } + + @Test + public void testPolygonPolylineRelate() { + OperatorRelate op = OperatorRelate.local(); + SpatialReference sr = SpatialReference.create(4326); + boolean res; + String scl; + + Polygon polygon1 = new Polygon(); + Polyline polyline2 = new Polyline(); + + polygon1.startPath(0, 0); + polygon1.lineTo(0, 10); + polygon1.lineTo(10, 10); + polygon1.lineTo(10, 0); + + polyline2.startPath(-10, 0); + polyline2.lineTo(0, 0); + + scl = "FF2F01102"; + res = op.execute(polygon1, polyline2, sr, scl, null); + assertTrue(res); + + scl = "**1*0110*"; + res = op.execute(polygon1, polyline2, sr, scl, null); + assertTrue(!res); + + scl = "T***T****"; + res = op.execute(polygon1, polyline2, sr, scl, null); + assertTrue(!res); + + scl = "FF2FT****"; + res = op.execute(polygon1, polyline2, sr, scl, null); + assertTrue(res); + + polyline2.setEmpty(); + polyline2.startPath(0, 0); + polyline2.lineTo(10, 0); + + scl = "**21*1FF*"; + res = op.execute(polygon1, polyline2, sr, scl, null); + assertTrue(res); + + scl = "F*21*1FF*"; + res = op.execute(polygon1, polyline2, sr, scl, null); + assertTrue(res); + + scl = "0**1*1FF*"; + res = op.execute(polygon1, polyline2, sr, scl, null); + assertTrue(!res); + + scl = "F**1*1TF*"; + res = op.execute(polygon1, polyline2, sr, scl, null); + assertTrue(!res); + + polyline2.setEmpty(); + polyline2.startPath(1, 1); + polyline2.lineTo(5, 5); + + scl = "TT2******"; + res = op.execute(polygon1, polyline2, sr, scl, null); + assertTrue(res); + + scl = "1T2FF1FF*"; + res = op.execute(polygon1, polyline2, sr, scl, null); + assertTrue(res); + + scl = "1T1FF1FF*"; + res = op.execute(polygon1, polyline2, sr, scl, null); + assertTrue(!res); + + polyline2.setEmpty(); + polyline2.startPath(5, 5); + polyline2.lineTo(15, 5); + + scl = "1T20F*T0T"; + res = op.execute(polygon1, polyline2, sr, scl, null); + assertTrue(res); + + polygon1.setEmpty(); + polyline2.setEmpty(); + + polygon1.startPath(2, 0); + polygon1.lineTo(0, 2); + polygon1.lineTo(2, 4); + polygon1.lineTo(4, 2); + + polyline2.startPath(1, 2); + polyline2.lineTo(3, 2); + + op.accelerateGeometry(polygon1, sr, GeometryAccelerationDegree.enumHot); + scl = "TTTFF****"; + res = op.execute(polygon1, polyline2, sr, scl, null); + assertTrue(res); + + polyline2.setEmpty(); + polyline2.startPath(5, 2); + polyline2.lineTo(7, 2); + scl = "FF2FFT***"; + res = op.execute(polygon1, polyline2, sr, scl, null); + assertTrue(res); + + polygon1.setEmpty(); + polyline2.setEmpty(); + polygon1.startPath(0, 0); + polygon1.lineTo(0, 1); + polygon1.lineTo(1, 0); + polyline2.startPath(0, 10); + polyline2.lineTo(0, 9); + polyline2.startPath(10, 0); + polyline2.lineTo(9, 0); + polyline2.startPath(0, -10); + polyline2.lineTo(0, -9); + scl = "**2******"; + res = op.execute(polygon1, polyline2, sr, scl, null); + assertTrue(res); + + polygon1.setEmpty(); + polyline2.setEmpty(); + polygon1.startPath(0, 0); + polygon1.lineTo(0, 1); + polygon1.lineTo(0, 0); + polyline2.startPath(0, 10); + polyline2.lineTo(0, 9); + scl = "**1******"; + res = op.execute(polygon1, polyline2, sr, scl, null); + assertTrue(res); + } + + @Test + public void testPolygonPolygonRelate() { + OperatorRelate op = (OperatorRelate) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Relate)); + SpatialReference sr = SpatialReference.create(4326); + boolean res; + String scl; + + Polygon polygon1 = new Polygon(); + Polygon polygon2 = new Polygon(); + + polygon1.startPath(0, 0); + polygon1.lineTo(0, 10); + polygon1.lineTo(10, 10); + polygon1.lineTo(10, 0); + + polygon2.startPath(15, 0); + polygon2.lineTo(15, 10); + polygon2.lineTo(25, 10); + polygon2.lineTo(25, 0); + + scl = "FFTFFT21T"; + res = op.execute(polygon1, polygon2, sr, scl, null); + assertTrue(res); + + scl = "FFTFFT11T"; + res = op.execute(polygon1, polygon2, sr, scl, null); + assertTrue(!res); + + polygon2.setEmpty(); + polygon2.startPath(5, 0); + polygon2.lineTo(5, 10); + polygon2.lineTo(15, 10); + polygon2.lineTo(15, 0); + + scl = "21TT1121T"; + res = op.execute(polygon1, polygon2, sr, scl, null); + assertTrue(res); + + polygon2.setEmpty(); + polygon2.startPath(1, 1); + polygon2.lineTo(1, 9); + polygon2.lineTo(9, 9); + polygon2.lineTo(9, 1); + + scl = "212FF1FFT"; + res = op.execute(polygon1, polygon2, sr, scl, null); + assertTrue(res); + + polygon1.setEmpty(); + polygon2.setEmpty(); + polygon1.startPath(3, 3); + polygon1.lineTo(3, 4); + polygon1.lineTo(3, 3); + polygon2.startPath(1, 1); + polygon2.lineTo(1, 1); + + scl = "FF1FFF0F2"; + res = op.execute(polygon1, polygon2, sr, scl, null); + assertTrue(res); + scl = "FF0FFF1F2"; + res = op.execute(polygon2, polygon1, sr, scl, null); + assertTrue(res); + + polygon1.setEmpty(); + polygon2.setEmpty(); + polygon1.startPath(0, 0); + polygon1.lineTo(0, 100); + polygon1.lineTo(100, 100); + polygon1.lineTo(100, 0); + polygon2.startPath(50, 50); + polygon2.lineTo(50, 50); + polygon2.lineTo(50, 50); + + op.accelerateGeometry(polygon1, sr, GeometryAccelerationDegree.enumHot); + + scl = "0F2FF1FF2"; + res = op.execute(polygon1, polygon2, sr, scl, null); + assertTrue(res); + + polygon2.lineTo(51, 50); + scl = "1F2FF1FF2"; + res = op.execute(polygon1, polygon2, sr, scl, null); + assertTrue(res); + } + + @Test + public void testMultiPointPointRelate() { + OperatorRelate op = (OperatorRelate) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Relate)); + SpatialReference sr = SpatialReference.create(4326); + boolean res; + String scl; + + MultiPoint m1 = new MultiPoint(); + Point p2 = new Point(); + + m1.add(0, 0); + p2.setXY(0, 0); + + scl = "T*F***F**"; + res = op.execute(m1, p2, sr, scl, null); + assertTrue(res); + + scl = "T*T***F**"; + res = op.execute(m1, p2, sr, scl, null); + assertTrue(!res); + + m1.add(1, 1); + res = op.execute(m1, p2, sr, scl, null); + assertTrue(res); + + m1.setEmpty(); + + m1.add(1, 1); + m1.add(2, 2); + + scl = "FF0FFFTF2"; + res = op.execute(m1, p2, sr, scl, null); + assertTrue(res); + } + + @Test + public void testPointPointRelate() { + OperatorRelate op = (OperatorRelate) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Relate)); + SpatialReference sr = SpatialReference.create(4326); + boolean res; + String scl; + + Point p1 = new Point(); + Point p2 = new Point(); + + p1.setXY(0, 0); + p2.setXY(0, 0); + + scl = "T********"; + res = op.execute(p1, p2, sr, scl, null); + assertTrue(res); + + p1.setXY(0, 0); + p2.setXY(1, 0); + res = op.execute(p1, p2, null, scl, null); + assertTrue(!res); + + p1.setEmpty(); + p2.setEmpty(); + scl = "*********"; + res = op.execute(p1, p2, null, scl, null); + assertTrue(res); + scl = "FFFFFFFFF"; + res = op.execute(p1, p2, null, scl, null); + assertTrue(res); + scl = "FFFFFFFFT"; + res = op.execute(p1, p2, null, scl, null); + assertTrue(!res); + } + + @Test + public void testPolygonMultiPointRelate() { + OperatorRelate op = (OperatorRelate) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Relate)); + SpatialReference sr = SpatialReference.create(4326); + boolean res; + String scl; + + Polygon polygon1 = new Polygon(); + MultiPoint multipoint2 = new MultiPoint(); + + polygon1.startPath(0, 0); + polygon1.lineTo(0, 10); + polygon1.lineTo(10, 10); + polygon1.lineTo(10, 0); + + multipoint2.add(0, 0); + multipoint2.add(5, 5); + + scl = "TFT0F1FFT"; + res = op.execute(polygon1, multipoint2, sr, scl, null); + assertTrue(res); + + scl = "T0FFFFT1T"; // transpose of above + res = op.execute(multipoint2, polygon1, sr, scl, null); + assertTrue(res); + + multipoint2.add(11, 11); + + scl = "TFT0F10FT"; + res = op.execute(polygon1, multipoint2, sr, scl, null); + assertTrue(res); + + multipoint2.add(0, 5); + + scl = "TFT0F10FT"; + res = op.execute(polygon1, multipoint2, sr, scl, null); + assertTrue(res); + + scl = "TFF0F10FT"; + res = op.execute(polygon1, multipoint2, sr, scl, null); + assertTrue(!res); + + polygon1.setEmpty(); + multipoint2.setEmpty(); + + polygon1.startPath(0, 0); + polygon1.lineTo(0, 20); + polygon1.lineTo(20, 20); + polygon1.lineTo(20, 0); + + multipoint2.add(3, 3); + multipoint2.add(5, 5); + + op.accelerateGeometry(polygon1, sr, + Geometry.GeometryAccelerationDegree.enumHot); + + scl = "TF2FF****"; + res = op.execute(polygon1, multipoint2, sr, scl, null); + assertTrue(res); + + polygon1.setEmpty(); + multipoint2.setEmpty(); + + polygon1.startPath(4, 0); + polygon1.lineTo(0, 4); + polygon1.lineTo(4, 8); + polygon1.lineTo(8, 4); + + multipoint2.add(8, 1); + multipoint2.add(8, 2); + + op.accelerateGeometry(polygon1, sr, + Geometry.GeometryAccelerationDegree.enumHot); + + scl = "FF2FF10F2"; + res = op.execute(polygon1, multipoint2, sr, scl, null); + assertTrue(res); + } + + @Test + public void testPolygonPointRelate() { + OperatorRelate op = (OperatorRelate) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Relate)); + SpatialReference sr = SpatialReference.create(4326); + boolean res; + String scl; + + Polygon polygon = new Polygon(); + Point point = new Point(); + + polygon.startPath(0, 0); + polygon.lineTo(0, 10); + polygon.lineTo(10, 10); + polygon.lineTo(10, 0); + + point.setXY(0, 0); + + scl = "FF20FTFFT"; + res = op.execute(polygon, point, sr, scl, null); + assertTrue(res); + + polygon.setEmpty(); + polygon.startPath(0, 0); + polygon.lineTo(0, 0); + polygon.lineTo(0, 0); + scl = "0FFFFFFF2"; + res = op.execute(polygon, point, sr, scl, null); + assertTrue(res); - polygon.setEmpty(); - polygon.startPath(0, 0); - polygon.lineTo(0, 1); - polygon.lineTo(0, 0); - scl = "0F1FFFFF2"; - res = op.execute(polygon, point, sr, scl, null); - assertTrue(res); + polygon.setEmpty(); + polygon.startPath(0, 0); + polygon.lineTo(0, 1); + polygon.lineTo(0, 0); + scl = "0F1FFFFF2"; + res = op.execute(polygon, point, sr, scl, null); + assertTrue(res); - point.setXY(-1, 0); - - scl = "FF1FFF0F2"; - res = op.execute(polygon, point, sr, scl, null); - assertTrue(res); + point.setXY(-1, 0); + + scl = "FF1FFF0F2"; + res = op.execute(polygon, point, sr, scl, null); + assertTrue(res); - polygon.setEmpty(); - polygon.startPath(0, 0); - polygon.lineTo(0, 10); - polygon.lineTo(0, 0); - scl = "FF1FFFTFT"; - res = op.execute(polygon, point, sr, scl, null); - assertTrue(res); + polygon.setEmpty(); + polygon.startPath(0, 0); + polygon.lineTo(0, 10); + polygon.lineTo(0, 0); + scl = "FF1FFFTFT"; + res = op.execute(polygon, point, sr, scl, null); + assertTrue(res); - polygon.setEmpty(); - polygon.startPath(0, 0); - polygon.lineTo(0, 0); - polygon.lineTo(0, 0); - scl = "FF0FFF0F2"; - res = op.execute(polygon, point, sr, scl, null); - assertTrue(res); - } - - @Test - public void testPolylineMultiPointRelate() { - OperatorRelate op = OperatorRelate.local(); - SpatialReference sr = SpatialReference.create(4326); - boolean res; - String scl; - - Polyline polyline1 = new Polyline(); - MultiPoint multipoint2 = new MultiPoint(); - - polyline1.startPath(0, 0); - polyline1.lineTo(10, 0); - - multipoint2.add(0, 0); - multipoint2.add(5, 5); - - scl = "FF10F00F2"; - res = op.execute(polyline1, multipoint2, sr, scl, null); - assertTrue(res); + polygon.setEmpty(); + polygon.startPath(0, 0); + polygon.lineTo(0, 0); + polygon.lineTo(0, 0); + scl = "FF0FFF0F2"; + res = op.execute(polygon, point, sr, scl, null); + assertTrue(res); + } + + @Test + public void testPolylineMultiPointRelate() { + OperatorRelate op = OperatorRelate.local(); + SpatialReference sr = SpatialReference.create(4326); + boolean res; + String scl; + + Polyline polyline1 = new Polyline(); + MultiPoint multipoint2 = new MultiPoint(); + + polyline1.startPath(0, 0); + polyline1.lineTo(10, 0); + + multipoint2.add(0, 0); + multipoint2.add(5, 5); + + scl = "FF10F00F2"; + res = op.execute(polyline1, multipoint2, sr, scl, null); + assertTrue(res); - multipoint2.add(5, 0); - - scl = "0F10F00F2"; - res = op.execute(polyline1, multipoint2, sr, scl, null); - assertTrue(res); + multipoint2.add(5, 0); + + scl = "0F10F00F2"; + res = op.execute(polyline1, multipoint2, sr, scl, null); + assertTrue(res); - scl = "0F11F00F2"; - res = op.execute(polyline1, multipoint2, sr, scl, null); - assertTrue(!res); + scl = "0F11F00F2"; + res = op.execute(polyline1, multipoint2, sr, scl, null); + assertTrue(!res); - polyline1.setEmpty(); - multipoint2.setEmpty(); + polyline1.setEmpty(); + multipoint2.setEmpty(); - polyline1.startPath(4, 0); - polyline1.lineTo(0, 4); - polyline1.lineTo(4, 8); - polyline1.lineTo(8, 4); - polyline1.lineTo(4, 0); // has no boundary + polyline1.startPath(4, 0); + polyline1.lineTo(0, 4); + polyline1.lineTo(4, 8); + polyline1.lineTo(8, 4); + polyline1.lineTo(4, 0); // has no boundary - multipoint2.add(8, 1); - multipoint2.add(8, 2); + multipoint2.add(8, 1); + multipoint2.add(8, 2); - op.accelerateGeometry(polyline1, sr, GeometryAccelerationDegree.enumHot); + op.accelerateGeometry(polyline1, sr, GeometryAccelerationDegree.enumHot); - scl = "FF1FFF0F2"; - res = op.execute(polyline1, multipoint2, sr, scl, null); - assertTrue(res); + scl = "FF1FFF0F2"; + res = op.execute(polyline1, multipoint2, sr, scl, null); + assertTrue(res); - polyline1.setEmpty(); - multipoint2.setEmpty(); + polyline1.setEmpty(); + multipoint2.setEmpty(); - polyline1.startPath(4, 0); - polyline1.lineTo(4, 0); + polyline1.startPath(4, 0); + polyline1.lineTo(4, 0); - multipoint2.add(8, 1); - multipoint2.add(8, 2); + multipoint2.add(8, 1); + multipoint2.add(8, 2); - scl = "FF0FFF0F2"; - res = op.execute(polyline1, multipoint2, sr, scl, null); - assertTrue(res); + scl = "FF0FFF0F2"; + res = op.execute(polyline1, multipoint2, sr, scl, null); + assertTrue(res); - multipoint2.add(-2, 0); - res = op.execute(polyline1, multipoint2, sr, scl, null); - assertTrue(res); + multipoint2.add(-2, 0); + res = op.execute(polyline1, multipoint2, sr, scl, null); + assertTrue(res); - op.accelerateGeometry(polyline1, sr, GeometryAccelerationDegree.enumHot); - res = op.execute(polyline1, multipoint2, sr, scl, null); - assertTrue(res); + op.accelerateGeometry(polyline1, sr, GeometryAccelerationDegree.enumHot); + res = op.execute(polyline1, multipoint2, sr, scl, null); + assertTrue(res); - polyline1.setEmpty(); - multipoint2.setEmpty(); + polyline1.setEmpty(); + multipoint2.setEmpty(); - polyline1.startPath(10, 10); - polyline1.lineTo(10, 10); - multipoint2.add(10, 10); + polyline1.startPath(10, 10); + polyline1.lineTo(10, 10); + multipoint2.add(10, 10); - scl = "0FFFFFFF2"; - res = op.execute(polyline1, multipoint2, sr, scl, null); - assertTrue(res); + scl = "0FFFFFFF2"; + res = op.execute(polyline1, multipoint2, sr, scl, null); + assertTrue(res); - polyline1.startPath(12, 12); - polyline1.lineTo(12, 12); + polyline1.startPath(12, 12); + polyline1.lineTo(12, 12); - scl = "0F0FFFFF2"; - res = op.execute(polyline1, multipoint2, sr, scl, null); - assertTrue(res); + scl = "0F0FFFFF2"; + res = op.execute(polyline1, multipoint2, sr, scl, null); + assertTrue(res); - polyline1.setEmpty(); - multipoint2.setEmpty(); + polyline1.setEmpty(); + multipoint2.setEmpty(); - polyline1.startPath(10, 10); - polyline1.lineTo(10, 10); - multipoint2.add(0, 0); + polyline1.startPath(10, 10); + polyline1.lineTo(10, 10); + multipoint2.add(0, 0); - scl = "FF0FFF0F2"; - res = op.execute(polyline1, multipoint2, sr, scl, null); - assertTrue(res); - } + scl = "FF0FFF0F2"; + res = op.execute(polyline1, multipoint2, sr, scl, null); + assertTrue(res); + } - @Test - public void testMultiPointMultipointRelate() { - OperatorRelate op = (OperatorRelate) (OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Relate)); - SpatialReference sr = SpatialReference.create(4326); - boolean res; - String scl; + @Test + public void testMultiPointMultipointRelate() { + OperatorRelate op = (OperatorRelate) (OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Relate)); + SpatialReference sr = SpatialReference.create(4326); + boolean res; + String scl; - MultiPoint multipoint1 = new MultiPoint(); - MultiPoint multipoint2 = new MultiPoint(); + MultiPoint multipoint1 = new MultiPoint(); + MultiPoint multipoint2 = new MultiPoint(); - multipoint1.add(0, 0); + multipoint1.add(0, 0); - multipoint2.add(0, 0); + multipoint2.add(0, 0); - scl = "TFFFFFFF2"; - res = op.execute(multipoint1, multipoint2, sr, scl, null); - assertTrue(res); + scl = "TFFFFFFF2"; + res = op.execute(multipoint1, multipoint2, sr, scl, null); + assertTrue(res); - multipoint2.add(5, 5); + multipoint2.add(5, 5); - scl = "TFFFFFTF2"; - res = op.execute(multipoint1, multipoint2, sr, scl, null); - assertTrue(res); + scl = "TFFFFFTF2"; + res = op.execute(multipoint1, multipoint2, sr, scl, null); + assertTrue(res); - multipoint1.add(-5, 0); + multipoint1.add(-5, 0); - scl = "0FTFFFTF2"; - res = op.execute(multipoint1, multipoint2, sr, scl, null); - assertTrue(res); + scl = "0FTFFFTF2"; + res = op.execute(multipoint1, multipoint2, sr, scl, null); + assertTrue(res); - res = GeometryEngine.relate(multipoint1, multipoint2, sr, scl); - assertTrue(res); + res = GeometryEngine.relate(multipoint1, multipoint2, sr, scl); + assertTrue(res); - multipoint1.setEmpty(); - multipoint2.setEmpty(); + multipoint1.setEmpty(); + multipoint2.setEmpty(); - multipoint1.add(0, 0); - multipoint2.add(1, 1); + multipoint1.add(0, 0); + multipoint2.add(1, 1); - scl = "FFTFFF0FT"; - res = op.execute(multipoint1, multipoint2, sr, scl, null); - assertTrue(res); - } + scl = "FFTFFF0FT"; + res = op.execute(multipoint1, multipoint2, sr, scl, null); + assertTrue(res); + } - @Test - public void testPolylinePointRelate() { - OperatorRelate op = OperatorRelate.local(); - SpatialReference sr = SpatialReference.create(4326); - boolean res; - String scl; + @Test + public void testPolylinePointRelate() { + OperatorRelate op = OperatorRelate.local(); + SpatialReference sr = SpatialReference.create(4326); + boolean res; + String scl; - Polyline polyline = new Polyline(); - Point point = new Point(); - - polyline.startPath(0, 2); - polyline.lineTo(0, 4); - - point.setXY(0, 3); - - scl = "0F1FF0FF2"; - res = op.execute(polyline, point, sr, scl, null); - assertTrue(res); - - point.setXY(1, 3); - - scl = "FF1FF00F2"; - res = op.execute(polyline, point, sr, scl, null); - assertTrue(res); - - polyline.lineTo(4, 4); - polyline.lineTo(4, 2); - polyline.lineTo(0, 2); // no bounadry - point.setXY(0, 3); - - scl = "0F1FFFFF2"; - res = op.execute(polyline, point, sr, scl, null); - assertTrue(res); - - scl = "0F1FFFFF2"; - res = op.execute(polyline, point, sr, scl, null); - assertTrue(res); - - point.setXY(1, 3); - - scl = "FF1FFF0F2"; - res = op.execute(polyline, point, sr, scl, null); - assertTrue(res); - - point.setXY(10, 10); - - scl = "FF1FFF0F2"; - res = op.execute(polyline, point, sr, scl, null); - assertTrue(res); - - polyline.setEmpty(); - point.setEmpty(); - - polyline.startPath(10, 10); - polyline.lineTo(10, 10); - point.setXY(10, 10); - - scl = "0FFFFFFF2"; - res = op.execute(polyline, point, sr, scl, null); - assertTrue(res); - - polyline.startPath(12, 12); - polyline.lineTo(12, 12); - - scl = "0F0FFFFF2"; - res = op.execute(polyline, point, sr, scl, null); - assertTrue(res); - - polyline.setEmpty(); - point.setEmpty(); - - polyline.startPath(10, 10); - polyline.lineTo(10, 10); - point.setXY(0, 0); - - scl = "FF0FFF0F2"; - res = op.execute(polyline, point, sr, scl, null); - assertTrue(res); - } - - @Test - public void testCrosses_github_issue_40() { - // Issue 40: Acceleration without a spatial reference changes the result - // of relation operators - Geometry geom1 = OperatorImportFromWkt.local().execute(0, - Geometry.Type.Unknown, "LINESTRING (2 0, 2 3)", null); - Geometry geom2 = OperatorImportFromWkt.local().execute(0, - Geometry.Type.Unknown, "POLYGON ((1 1, 4 1, 4 4, 1 4, 1 1))", - null); - boolean answer1 = OperatorCrosses.local().execute(geom1, geom2, null, - null); - assertTrue(answer1); - OperatorCrosses.local().accelerateGeometry(geom1, null, - GeometryAccelerationDegree.enumHot); - boolean answer2 = OperatorCrosses.local().execute(geom1, geom2, null, - null); - assertTrue(answer2); - } - - @Test - public void testDisjointCrash() { - Polygon g1 = new Polygon(); - g1.addEnvelope(Envelope2D.construct(0, 0, 10, 10), false); - Polygon g2 = new Polygon(); - g2.addEnvelope(Envelope2D.construct(10, 1, 21, 21), false); - g1 = (Polygon) OperatorDensifyByLength.local().execute(g1, 0.1, null); - OperatorDisjoint.local().accelerateGeometry(g1, SpatialReference.create(4267), GeometryAccelerationDegree.enumHot); - boolean res = OperatorDisjoint.local().execute(g1, g2, SpatialReference.create(4267), null); - assertTrue(!res); - } - - @Test - public void testDisjointFail() { - MapGeometry geometry1 = OperatorImportFromJson.local().execute(Geometry.Type.Unknown, "{\"paths\":[[[3,3],[3,3]]],\"spatialReference\":{\"wkid\":4326}}"); - MapGeometry geometry2 = OperatorImportFromJson.local().execute(Geometry.Type.Unknown, "{\"rings\":[[[2,2],[2,4],[4,4],[4,2],[2,2]]],\"spatialReference\":{\"wkid\":4326}}"); - OperatorDisjoint.local().accelerateGeometry(geometry1.getGeometry(), geometry1.getSpatialReference(), GeometryAccelerationDegree.enumMedium); - boolean res = OperatorDisjoint.local().execute(geometry1.getGeometry(), geometry2.getGeometry(), geometry1.getSpatialReference(), null); - assertTrue(!res); - } + Polyline polyline = new Polyline(); + Point point = new Point(); + + polyline.startPath(0, 2); + polyline.lineTo(0, 4); + + point.setXY(0, 3); + + scl = "0F1FF0FF2"; + res = op.execute(polyline, point, sr, scl, null); + assertTrue(res); + + point.setXY(1, 3); + + scl = "FF1FF00F2"; + res = op.execute(polyline, point, sr, scl, null); + assertTrue(res); + + polyline.lineTo(4, 4); + polyline.lineTo(4, 2); + polyline.lineTo(0, 2); // no bounadry + point.setXY(0, 3); + + scl = "0F1FFFFF2"; + res = op.execute(polyline, point, sr, scl, null); + assertTrue(res); + + scl = "0F1FFFFF2"; + res = op.execute(polyline, point, sr, scl, null); + assertTrue(res); + + point.setXY(1, 3); + + scl = "FF1FFF0F2"; + res = op.execute(polyline, point, sr, scl, null); + assertTrue(res); + + point.setXY(10, 10); + + scl = "FF1FFF0F2"; + res = op.execute(polyline, point, sr, scl, null); + assertTrue(res); + + polyline.setEmpty(); + point.setEmpty(); + + polyline.startPath(10, 10); + polyline.lineTo(10, 10); + point.setXY(10, 10); + + scl = "0FFFFFFF2"; + res = op.execute(polyline, point, sr, scl, null); + assertTrue(res); + + polyline.startPath(12, 12); + polyline.lineTo(12, 12); + + scl = "0F0FFFFF2"; + res = op.execute(polyline, point, sr, scl, null); + assertTrue(res); + + polyline.setEmpty(); + point.setEmpty(); + + polyline.startPath(10, 10); + polyline.lineTo(10, 10); + point.setXY(0, 0); + + scl = "FF0FFF0F2"; + res = op.execute(polyline, point, sr, scl, null); + assertTrue(res); + } + + @Test + public void testCrosses_github_issue_40() { + // Issue 40: Acceleration without a spatial reference changes the result + // of relation operators + Geometry geom1 = OperatorImportFromWkt.local().execute(0, + Geometry.Type.Unknown, "LINESTRING (2 0, 2 3)", null); + Geometry geom2 = OperatorImportFromWkt.local().execute(0, + Geometry.Type.Unknown, "POLYGON ((1 1, 4 1, 4 4, 1 4, 1 1))", + null); + boolean answer1 = OperatorCrosses.local().execute(geom1, geom2, null, + null); + assertTrue(answer1); + OperatorCrosses.local().accelerateGeometry(geom1, null, + GeometryAccelerationDegree.enumHot); + boolean answer2 = OperatorCrosses.local().execute(geom1, geom2, null, + null); + assertTrue(answer2); + } + + @Test + public void testDisjointCrash() { + Polygon g1 = new Polygon(); + g1.addEnvelope(Envelope2D.construct(0, 0, 10, 10), false); + Polygon g2 = new Polygon(); + g2.addEnvelope(Envelope2D.construct(10, 1, 21, 21), false); + g1 = (Polygon) OperatorDensifyByLength.local().execute(g1, 0.1, null); + OperatorDisjoint.local().accelerateGeometry(g1, SpatialReference.create(4267), GeometryAccelerationDegree.enumHot); + boolean res = OperatorDisjoint.local().execute(g1, g2, SpatialReference.create(4267), null); + assertTrue(!res); + } + + @Test + public void testDisjointFail() { + MapGeometry geometry1 = OperatorImportFromJson.local().execute(Geometry.Type.Unknown, "{\"paths\":[[[3,3],[3,3]]],\"spatialReference\":{\"wkid\":4326}}"); + MapGeometry geometry2 = OperatorImportFromJson.local().execute(Geometry.Type.Unknown, "{\"rings\":[[[2,2],[2,4],[4,4],[4,2],[2,2]]],\"spatialReference\":{\"wkid\":4326}}"); + OperatorDisjoint.local().accelerateGeometry(geometry1.getGeometry(), geometry1.getSpatialReference(), GeometryAccelerationDegree.enumMedium); + boolean res = OperatorDisjoint.local().execute(geometry1.getGeometry(), geometry2.getGeometry(), geometry1.getSpatialReference(), null); + assertTrue(!res); + } } diff --git a/src/test/java/com/esri/core/geometry/TestSerialization.java b/src/test/java/com/esri/core/geometry/TestSerialization.java index 80a673f8..5f3796a1 100644 --- a/src/test/java/com/esri/core/geometry/TestSerialization.java +++ b/src/test/java/com/esri/core/geometry/TestSerialization.java @@ -1,5 +1,5 @@ /* - Copyright 1995-2017 Esri + Copyright 1995-2018 Esri Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -24,352 +24,355 @@ package com.esri.core.geometry; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; import junit.framework.TestCase; import org.junit.Test; -import java.io.*; - public class TestSerialization extends TestCase { - @Override - protected void setUp() throws Exception { - super.setUp(); - } - - @Override - protected void tearDown() throws Exception { - super.tearDown(); - } - - @Test - public void testSerializePoint() { - try { - ByteArrayOutputStream streamOut = new ByteArrayOutputStream(); - ObjectOutputStream oo = new ObjectOutputStream(streamOut); - Point pt = new Point(10, 40); - oo.writeObject(pt); - ByteArrayInputStream streamIn = new ByteArrayInputStream( - streamOut.toByteArray()); - ObjectInputStream ii = new ObjectInputStream(streamIn); - Point ptRes = (Point) ii.readObject(); - assertTrue(ptRes.equals(pt)); - } catch (Exception ex) { - fail("Point serialization failure"); - - } - - //try - //{ - //FileOutputStream streamOut = new FileOutputStream("c:/temp/savedPoint1.txt"); - //ObjectOutputStream oo = new ObjectOutputStream(streamOut); - //Point pt = new Point(10, 40, 2); - //oo.writeObject(pt); - //} - //catch(Exception ex) - //{ - //fail("Point serialization failure"); - //} - - try { - InputStream s = TestSerialization.class - .getResourceAsStream("savedPoint.txt"); - ObjectInputStream ii = new ObjectInputStream(s); - Point ptRes = (Point) ii.readObject(); - assertTrue(ptRes.getX() == 10 && ptRes.getY() == 40); - } catch (Exception ex) { - fail("Point serialization failure"); - } - - try { - InputStream s = TestSerialization.class - .getResourceAsStream("savedPoint1.txt"); - ObjectInputStream ii = new ObjectInputStream(s); - Point ptRes = (Point) ii.readObject(); - assertTrue(ptRes.getX() == 10 && ptRes.getY() == 40 && ptRes.getZ() == 2); - } catch (Exception ex) { - fail("Point serialization failure"); - } - - } - - @Test - public void testSerializePolygon() { - try { - ByteArrayOutputStream streamOut = new ByteArrayOutputStream(); - ObjectOutputStream oo = new ObjectOutputStream(streamOut); - Polygon pt = new Polygon(); - pt.startPath(10, 10); - pt.lineTo(100, 100); - pt.lineTo(200, 100); - oo.writeObject(pt); - ByteArrayInputStream streamIn = new ByteArrayInputStream( - streamOut.toByteArray()); - ObjectInputStream ii = new ObjectInputStream(streamIn); - Polygon ptRes = (Polygon) ii.readObject(); - assertTrue(ptRes.equals(pt)); - } catch (Exception ex) { - fail("Polygon serialization failure"); - } - - try { - ByteArrayOutputStream streamOut = new ByteArrayOutputStream(); - ObjectOutputStream oo = new ObjectOutputStream(streamOut); - Polygon pt = new Polygon(); - pt.startPath(10, 10); - pt.lineTo(100, 100); - pt.lineTo(200, 100); - pt = (Polygon) GeometryEngine.simplify(pt, null); - oo.writeObject(pt); - ByteArrayInputStream streamIn = new ByteArrayInputStream( - streamOut.toByteArray()); - ObjectInputStream ii = new ObjectInputStream(streamIn); - Polygon ptRes = (Polygon) ii.readObject(); - assertTrue(ptRes.equals(pt)); - } catch (Exception ex) { - fail("Polygon serialization failure"); - } - - //try - //{ - //FileOutputStream streamOut = new FileOutputStream("c:/temp/savedPolygon1.txt"); - //ObjectOutputStream oo = new ObjectOutputStream(streamOut); - //Polygon pt = new Polygon(); - //pt.startPath(10, 10); - //pt.lineTo(100, 100); - //pt.lineTo(200, 100); - //pt = (Polygon)GeometryEngine.simplify(pt, null); - //oo.writeObject(pt); - //} - //catch(Exception ex) - //{ - //fail("Polygon serialization failure"); - //} - - try { - InputStream s = TestSerialization.class - .getResourceAsStream("savedPolygon.txt"); - ObjectInputStream ii = new ObjectInputStream(s); - Polygon ptRes = (Polygon) ii.readObject(); - assertTrue(ptRes != null); - } catch (Exception ex) { - fail("Polygon serialization failure"); - } - try { - InputStream s = TestSerialization.class - .getResourceAsStream("savedPolygon1.txt"); - ObjectInputStream ii = new ObjectInputStream(s); - Polygon ptRes = (Polygon) ii.readObject(); - assertTrue(ptRes != null); - } catch (Exception ex) { - fail("Polygon serialization failure"); - } - } - - @Test - public void testSerializePolyline() { - try { - ByteArrayOutputStream streamOut = new ByteArrayOutputStream(); - ObjectOutputStream oo = new ObjectOutputStream(streamOut); - Polyline pt = new Polyline(); - pt.startPath(10, 10); - pt.lineTo(100, 100); - pt.lineTo(200, 100); - oo.writeObject(pt); - ByteArrayInputStream streamIn = new ByteArrayInputStream( - streamOut.toByteArray()); - ObjectInputStream ii = new ObjectInputStream(streamIn); - Polyline ptRes = (Polyline) ii.readObject(); - assertTrue(ptRes.equals(pt)); - } catch (Exception ex) { - fail("Polyline serialization failure"); - } - - //try - //{ - //FileOutputStream streamOut = new FileOutputStream("c:/temp/savedPolyline1.txt"); - //ObjectOutputStream oo = new ObjectOutputStream(streamOut); - //Polyline pt = new Polyline(); - //pt.startPath(10, 10); - //pt.lineTo(100, 100); - //pt.lineTo(200, 100); - //oo.writeObject(pt); - //} - //catch(Exception ex) - //{ - //fail("Polyline serialization failure"); - //} - - try { - InputStream s = TestSerialization.class - .getResourceAsStream("savedPolyline.txt"); - ObjectInputStream ii = new ObjectInputStream(s); - Polyline ptRes = (Polyline) ii.readObject(); - assertTrue(ptRes != null); - } catch (Exception ex) { - fail("Polyline serialization failure"); - } - try { - InputStream s = TestSerialization.class - .getResourceAsStream("savedPolyline1.txt"); - ObjectInputStream ii = new ObjectInputStream(s); - Polyline ptRes = (Polyline) ii.readObject(); - assertTrue(ptRes != null); - } catch (Exception ex) { - fail("Polyline serialization failure"); - } - } - - @Test - public void testSerializeEnvelope() { - try { - ByteArrayOutputStream streamOut = new ByteArrayOutputStream(); - ObjectOutputStream oo = new ObjectOutputStream(streamOut); - Envelope pt = new Envelope(10, 10, 400, 300); - oo.writeObject(pt); - ByteArrayInputStream streamIn = new ByteArrayInputStream( - streamOut.toByteArray()); - ObjectInputStream ii = new ObjectInputStream(streamIn); - Envelope ptRes = (Envelope) ii.readObject(); - assertTrue(ptRes.equals(pt)); - } catch (Exception ex) { - fail("Envelope serialization failure"); - } - - //try - //{ - //FileOutputStream streamOut = new FileOutputStream("c:/temp/savedEnvelope1.txt"); - //ObjectOutputStream oo = new ObjectOutputStream(streamOut); - //Envelope pt = new Envelope(10, 10, 400, 300); - //oo.writeObject(pt); - //} - //catch(Exception ex) - //{ - //fail("Envelope serialization failure"); - //} - - try { - InputStream s = TestSerialization.class - .getResourceAsStream("savedEnvelope.txt"); - ObjectInputStream ii = new ObjectInputStream(s); - Envelope ptRes = (Envelope) ii.readObject(); - assertTrue(ptRes.getXMax() == 400); - } catch (Exception ex) { - fail("Envelope serialization failure"); - } - try { - InputStream s = TestSerialization.class - .getResourceAsStream("savedEnvelope1.txt"); - ObjectInputStream ii = new ObjectInputStream(s); - Envelope ptRes = (Envelope) ii.readObject(); - assertTrue(ptRes.getXMax() == 400); - } catch (Exception ex) { - fail("Envelope serialization failure"); - } - } - - @Test - public void testSerializeMultiPoint() { - try { - ByteArrayOutputStream streamOut = new ByteArrayOutputStream(); - ObjectOutputStream oo = new ObjectOutputStream(streamOut); - MultiPoint pt = new MultiPoint(); - pt.add(10, 30); - pt.add(120, 40); - oo.writeObject(pt); - ByteArrayInputStream streamIn = new ByteArrayInputStream( - streamOut.toByteArray()); - ObjectInputStream ii = new ObjectInputStream(streamIn); - MultiPoint ptRes = (MultiPoint) ii.readObject(); - assertTrue(ptRes.equals(pt)); - } catch (Exception ex) { - fail("MultiPoint serialization failure"); - } - - //try - //{ - //FileOutputStream streamOut = new FileOutputStream("c:/temp/savedMultiPoint1.txt"); - //ObjectOutputStream oo = new ObjectOutputStream(streamOut); - //MultiPoint pt = new MultiPoint(); - //pt.add(10, 30); - //pt.add(120, 40); - //oo.writeObject(pt); - //} - //catch(Exception ex) - //{ - //fail("MultiPoint serialization failure"); - //} - - try { - InputStream s = TestSerialization.class - .getResourceAsStream("savedMultiPoint.txt"); - ObjectInputStream ii = new ObjectInputStream(s); - MultiPoint ptRes = (MultiPoint) ii.readObject(); - assertTrue(ptRes.getPoint(1).getY() == 40); - } catch (Exception ex) { - fail("MultiPoint serialization failure"); - } - try { - InputStream s = TestSerialization.class - .getResourceAsStream("savedMultiPoint1.txt"); - ObjectInputStream ii = new ObjectInputStream(s); - MultiPoint ptRes = (MultiPoint) ii.readObject(); - assertTrue(ptRes.getPoint(1).getY() == 40); - } catch (Exception ex) { - fail("MultiPoint serialization failure"); - } - } - - @Test - public void testSerializeLine() { - try { - ByteArrayOutputStream streamOut = new ByteArrayOutputStream(); - ObjectOutputStream oo = new ObjectOutputStream(streamOut); - Line pt = new Line(); - pt.setStart(new Point(10, 30)); - pt.setEnd(new Point(120, 40)); - oo.writeObject(pt); - ByteArrayInputStream streamIn = new ByteArrayInputStream( - streamOut.toByteArray()); - ObjectInputStream ii = new ObjectInputStream(streamIn); - Line ptRes = (Line) ii.readObject(); - assertTrue(ptRes.equals(pt)); - } catch (Exception ex) { - // fail("Line serialization failure"); - assertEquals(ex.getMessage(), "Cannot serialize this geometry"); - } - } - - @Test - public void testSerializeSR() { - try { - ByteArrayOutputStream streamOut = new ByteArrayOutputStream(); - ObjectOutputStream oo = new ObjectOutputStream(streamOut); - SpatialReference sr = SpatialReference.create(102100); - oo.writeObject(sr); - ByteArrayInputStream streamIn = new ByteArrayInputStream( - streamOut.toByteArray()); - ObjectInputStream ii = new ObjectInputStream(streamIn); - SpatialReference ptRes = (SpatialReference) ii.readObject(); - assertTrue(ptRes.equals(sr)); - } catch (Exception ex) { - fail("Spatial Reference serialization failure"); - } - } - - @Test - public void testSerializeEnvelope2D() { - try { - ByteArrayOutputStream streamOut = new ByteArrayOutputStream(); - ObjectOutputStream oo = new ObjectOutputStream(streamOut); - Envelope2D env = new Envelope2D(1.213948734, 2.213948734, 11.213948734, 12.213948734); - oo.writeObject(env); - ByteArrayInputStream streamIn = new ByteArrayInputStream( - streamOut.toByteArray()); - ObjectInputStream ii = new ObjectInputStream(streamIn); - Envelope2D envRes = (Envelope2D) ii.readObject(); - assertTrue(envRes.equals(env)); - } catch (Exception ex) { - fail("Envelope2D serialization failure"); - } + @Override + protected void setUp() throws Exception { + super.setUp(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + } + + @Test + public void testSerializePoint() { + try { + ByteArrayOutputStream streamOut = new ByteArrayOutputStream(); + ObjectOutputStream oo = new ObjectOutputStream(streamOut); + Point pt = new Point(10, 40); + oo.writeObject(pt); + ByteArrayInputStream streamIn = new ByteArrayInputStream( + streamOut.toByteArray()); + ObjectInputStream ii = new ObjectInputStream(streamIn); + Point ptRes = (Point) ii.readObject(); + assertTrue(ptRes.equals(pt)); + } catch (Exception ex) { + fail("Point serialization failure"); + + } + + //try + //{ + //FileOutputStream streamOut = new FileOutputStream("c:/temp/savedPoint1.txt"); + //ObjectOutputStream oo = new ObjectOutputStream(streamOut); + //Point pt = new Point(10, 40, 2); + //oo.writeObject(pt); + //} + //catch(Exception ex) + //{ + //fail("Point serialization failure"); + //} + + try { + InputStream s = TestSerialization.class + .getResourceAsStream("savedPoint.txt"); + ObjectInputStream ii = new ObjectInputStream(s); + Point ptRes = (Point) ii.readObject(); + assertTrue(ptRes.getX() == 10 && ptRes.getY() == 40); + } catch (Exception ex) { + fail("Point serialization failure"); + } + + try { + InputStream s = TestSerialization.class + .getResourceAsStream("savedPoint1.txt"); + ObjectInputStream ii = new ObjectInputStream(s); + Point ptRes = (Point) ii.readObject(); + assertTrue(ptRes.getX() == 10 && ptRes.getY() == 40 && ptRes.getZ() == 2); + } catch (Exception ex) { + fail("Point serialization failure"); + } + + } + + @Test + public void testSerializePolygon() { + try { + ByteArrayOutputStream streamOut = new ByteArrayOutputStream(); + ObjectOutputStream oo = new ObjectOutputStream(streamOut); + Polygon pt = new Polygon(); + pt.startPath(10, 10); + pt.lineTo(100, 100); + pt.lineTo(200, 100); + oo.writeObject(pt); + ByteArrayInputStream streamIn = new ByteArrayInputStream( + streamOut.toByteArray()); + ObjectInputStream ii = new ObjectInputStream(streamIn); + Polygon ptRes = (Polygon) ii.readObject(); + assertTrue(ptRes.equals(pt)); + } catch (Exception ex) { + fail("Polygon serialization failure"); + } + + try { + ByteArrayOutputStream streamOut = new ByteArrayOutputStream(); + ObjectOutputStream oo = new ObjectOutputStream(streamOut); + Polygon pt = new Polygon(); + pt.startPath(10, 10); + pt.lineTo(100, 100); + pt.lineTo(200, 100); + pt = (Polygon) GeometryEngine.simplify(pt, null); + oo.writeObject(pt); + ByteArrayInputStream streamIn = new ByteArrayInputStream( + streamOut.toByteArray()); + ObjectInputStream ii = new ObjectInputStream(streamIn); + Polygon ptRes = (Polygon) ii.readObject(); + assertTrue(ptRes.equals(pt)); + } catch (Exception ex) { + fail("Polygon serialization failure"); + } + + //try + //{ + //FileOutputStream streamOut = new FileOutputStream("c:/temp/savedPolygon1.txt"); + //ObjectOutputStream oo = new ObjectOutputStream(streamOut); + //Polygon pt = new Polygon(); + //pt.startPath(10, 10); + //pt.lineTo(100, 100); + //pt.lineTo(200, 100); + //pt = (Polygon)GeometryEngine.simplify(pt, null); + //oo.writeObject(pt); + //} + //catch(Exception ex) + //{ + //fail("Polygon serialization failure"); + //} + + try { + InputStream s = TestSerialization.class + .getResourceAsStream("savedPolygon.txt"); + ObjectInputStream ii = new ObjectInputStream(s); + Polygon ptRes = (Polygon) ii.readObject(); + assertTrue(ptRes != null); + } catch (Exception ex) { + fail("Polygon serialization failure"); + } + try { + InputStream s = TestSerialization.class + .getResourceAsStream("savedPolygon1.txt"); + ObjectInputStream ii = new ObjectInputStream(s); + Polygon ptRes = (Polygon) ii.readObject(); + assertTrue(ptRes != null); + } catch (Exception ex) { + fail("Polygon serialization failure"); + } + } + + @Test + public void testSerializePolyline() { + try { + ByteArrayOutputStream streamOut = new ByteArrayOutputStream(); + ObjectOutputStream oo = new ObjectOutputStream(streamOut); + Polyline pt = new Polyline(); + pt.startPath(10, 10); + pt.lineTo(100, 100); + pt.lineTo(200, 100); + oo.writeObject(pt); + ByteArrayInputStream streamIn = new ByteArrayInputStream( + streamOut.toByteArray()); + ObjectInputStream ii = new ObjectInputStream(streamIn); + Polyline ptRes = (Polyline) ii.readObject(); + assertTrue(ptRes.equals(pt)); + } catch (Exception ex) { + fail("Polyline serialization failure"); + } + + //try + //{ + //FileOutputStream streamOut = new FileOutputStream("c:/temp/savedPolyline1.txt"); + //ObjectOutputStream oo = new ObjectOutputStream(streamOut); + //Polyline pt = new Polyline(); + //pt.startPath(10, 10); + //pt.lineTo(100, 100); + //pt.lineTo(200, 100); + //oo.writeObject(pt); + //} + //catch(Exception ex) + //{ + //fail("Polyline serialization failure"); + //} + + try { + InputStream s = TestSerialization.class + .getResourceAsStream("savedPolyline.txt"); + ObjectInputStream ii = new ObjectInputStream(s); + Polyline ptRes = (Polyline) ii.readObject(); + assertTrue(ptRes != null); + } catch (Exception ex) { + fail("Polyline serialization failure"); + } + try { + InputStream s = TestSerialization.class + .getResourceAsStream("savedPolyline1.txt"); + ObjectInputStream ii = new ObjectInputStream(s); + Polyline ptRes = (Polyline) ii.readObject(); + assertTrue(ptRes != null); + } catch (Exception ex) { + fail("Polyline serialization failure"); + } + } + + @Test + public void testSerializeEnvelope() { + try { + ByteArrayOutputStream streamOut = new ByteArrayOutputStream(); + ObjectOutputStream oo = new ObjectOutputStream(streamOut); + Envelope pt = new Envelope(10, 10, 400, 300); + oo.writeObject(pt); + ByteArrayInputStream streamIn = new ByteArrayInputStream( + streamOut.toByteArray()); + ObjectInputStream ii = new ObjectInputStream(streamIn); + Envelope ptRes = (Envelope) ii.readObject(); + assertTrue(ptRes.equals(pt)); + } catch (Exception ex) { + fail("Envelope serialization failure"); + } + + //try + //{ + //FileOutputStream streamOut = new FileOutputStream("c:/temp/savedEnvelope1.txt"); + //ObjectOutputStream oo = new ObjectOutputStream(streamOut); + //Envelope pt = new Envelope(10, 10, 400, 300); + //oo.writeObject(pt); + //} + //catch(Exception ex) + //{ + //fail("Envelope serialization failure"); + //} + + try { + InputStream s = TestSerialization.class + .getResourceAsStream("savedEnvelope.txt"); + ObjectInputStream ii = new ObjectInputStream(s); + Envelope ptRes = (Envelope) ii.readObject(); + assertTrue(ptRes.getXMax() == 400); + } catch (Exception ex) { + fail("Envelope serialization failure"); + } + try { + InputStream s = TestSerialization.class + .getResourceAsStream("savedEnvelope1.txt"); + ObjectInputStream ii = new ObjectInputStream(s); + Envelope ptRes = (Envelope) ii.readObject(); + assertTrue(ptRes.getXMax() == 400); + } catch (Exception ex) { + fail("Envelope serialization failure"); + } + } + + @Test + public void testSerializeMultiPoint() { + try { + ByteArrayOutputStream streamOut = new ByteArrayOutputStream(); + ObjectOutputStream oo = new ObjectOutputStream(streamOut); + MultiPoint pt = new MultiPoint(); + pt.add(10, 30); + pt.add(120, 40); + oo.writeObject(pt); + ByteArrayInputStream streamIn = new ByteArrayInputStream( + streamOut.toByteArray()); + ObjectInputStream ii = new ObjectInputStream(streamIn); + MultiPoint ptRes = (MultiPoint) ii.readObject(); + assertTrue(ptRes.equals(pt)); + } catch (Exception ex) { + fail("MultiPoint serialization failure"); + } + + //try + //{ + //FileOutputStream streamOut = new FileOutputStream("c:/temp/savedMultiPoint1.txt"); + //ObjectOutputStream oo = new ObjectOutputStream(streamOut); + //MultiPoint pt = new MultiPoint(); + //pt.add(10, 30); + //pt.add(120, 40); + //oo.writeObject(pt); + //} + //catch(Exception ex) + //{ + //fail("MultiPoint serialization failure"); + //} + + try { + InputStream s = TestSerialization.class + .getResourceAsStream("savedMultiPoint.txt"); + ObjectInputStream ii = new ObjectInputStream(s); + MultiPoint ptRes = (MultiPoint) ii.readObject(); + assertTrue(ptRes.getPoint(1).getY() == 40); + } catch (Exception ex) { + fail("MultiPoint serialization failure"); + } + try { + InputStream s = TestSerialization.class + .getResourceAsStream("savedMultiPoint1.txt"); + ObjectInputStream ii = new ObjectInputStream(s); + MultiPoint ptRes = (MultiPoint) ii.readObject(); + assertTrue(ptRes.getPoint(1).getY() == 40); + } catch (Exception ex) { + fail("MultiPoint serialization failure"); + } + } + + @Test + public void testSerializeLine() { + try { + ByteArrayOutputStream streamOut = new ByteArrayOutputStream(); + ObjectOutputStream oo = new ObjectOutputStream(streamOut); + Line pt = new Line(); + pt.setStart(new Point(10, 30)); + pt.setEnd(new Point(120, 40)); + oo.writeObject(pt); + ByteArrayInputStream streamIn = new ByteArrayInputStream( + streamOut.toByteArray()); + ObjectInputStream ii = new ObjectInputStream(streamIn); + Line ptRes = (Line) ii.readObject(); + assertTrue(ptRes.equals(pt)); + } catch (Exception ex) { + // fail("Line serialization failure"); + assertEquals(ex.getMessage(), "Cannot serialize this geometry"); + } + } + + @Test + public void testSerializeSR() { + try { + ByteArrayOutputStream streamOut = new ByteArrayOutputStream(); + ObjectOutputStream oo = new ObjectOutputStream(streamOut); + SpatialReference sr = SpatialReference.create(102100); + oo.writeObject(sr); + ByteArrayInputStream streamIn = new ByteArrayInputStream( + streamOut.toByteArray()); + ObjectInputStream ii = new ObjectInputStream(streamIn); + SpatialReference ptRes = (SpatialReference) ii.readObject(); + assertTrue(ptRes.equals(sr)); + } catch (Exception ex) { + fail("Spatial Reference serialization failure"); + } + } + + @Test + public void testSerializeEnvelope2D() { + try { + ByteArrayOutputStream streamOut = new ByteArrayOutputStream(); + ObjectOutputStream oo = new ObjectOutputStream(streamOut); + Envelope2D env = new Envelope2D(1.213948734, 2.213948734, 11.213948734, 12.213948734); + oo.writeObject(env); + ByteArrayInputStream streamIn = new ByteArrayInputStream( + streamOut.toByteArray()); + ObjectInputStream ii = new ObjectInputStream(streamIn); + Envelope2D envRes = (Envelope2D)ii.readObject(); + assertTrue(envRes.equals(env)); + } catch (Exception ex) { + fail("Envelope2D serialization failure"); + } // try // { @@ -384,17 +387,110 @@ public void testSerializeEnvelope2D() { // fail("Envelope2D serialization failure"); // } - try { - InputStream s = TestSerialization.class - .getResourceAsStream("savedEnvelope2D.txt"); - ObjectInputStream ii = new ObjectInputStream(s); - Envelope2D e = (Envelope2D) ii - .readObject(); - assertTrue(e != null); - assertTrue(e.equals(new Envelope2D(177.123, 188.234, 999.122, 888.999))); - } catch (Exception ex) { - fail("Envelope2D serialization failure"); - } - } - + try { + InputStream s = TestSerialization.class + .getResourceAsStream("savedEnvelope2D.txt"); + ObjectInputStream ii = new ObjectInputStream(s); + Envelope2D e = (Envelope2D) ii + .readObject(); + assertTrue(e != null); + assertTrue(e.equals(new Envelope2D(177.123, 188.234, 999.122, 888.999))); + } catch (Exception ex) { + fail("Envelope2D serialization failure"); + } + } + + public void testAttributeStreamOfInt32() { + AttributeStreamOfInt32 a = new AttributeStreamOfInt32(0); + for (int i = 0; i < 100; i++) + a.add(i); + + try { + // serialize + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream os = new ObjectOutputStream(baos); + os.writeObject(a); + os.close(); + baos.close(); + + // deserialize + ByteArrayInputStream bais = new ByteArrayInputStream( + baos.toByteArray()); + ObjectInputStream in = new ObjectInputStream(bais); + AttributeStreamOfInt32 aOut = (AttributeStreamOfInt32) in.readObject(); + in.close(); + bais.close(); + + assertTrue(aOut.size() == a.size()); + for (int i = 0; i < 100; i++) + assertTrue(aOut.get(i) == a.get(i)); + + } catch (Exception e) { + fail("AttributeStreamOfInt32 serialization failure"); + } + + } + + @Test + public void testQuadTree() { + MultiPoint mp = new MultiPoint(); + int r = 124124; + for (int i = 0; i < 100; ++i) { + r = NumberUtils.nextRand(r); + int x = r; + r = NumberUtils.nextRand(r); + int y = r; + mp.add(x, y); + } + + Envelope2D extent = new Envelope2D(); + mp.queryEnvelope2D(extent); + QuadTree quadTree = new QuadTree(extent, 8); + Envelope2D boundingbox = new Envelope2D(); + Point2D pt; + + for (int i = 0; i < mp.getPointCount(); i++) { + pt = mp.getXY(i); + boundingbox.setCoords(pt.x, pt.y, pt.x, pt.y); + quadTree.insert(i, boundingbox, -1); + } + + try { + // serialize + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream os = new ObjectOutputStream(baos); + os.writeObject(quadTree); + os.close(); + baos.close(); + + // deserialize + ByteArrayInputStream bais = new ByteArrayInputStream( + baos.toByteArray()); + ObjectInputStream in = new ObjectInputStream(bais); + QuadTree qOut = (QuadTree) in.readObject(); + in.close(); + bais.close(); + + assertTrue(quadTree.getElementCount() == qOut.getElementCount()); + QuadTree.QuadTreeIterator iter1 = quadTree.getIterator(); + QuadTree.QuadTreeIterator iter2 = qOut.getIterator(); + int h1 = iter1.next(); + int h2 = iter2.next(); + for (; h1 != -1 && h2 != -1; h1 = iter1.next(), h2 = iter2.next()) { + assertTrue(quadTree.getElement(h1) == qOut.getElement(h2)); + assertTrue(quadTree.getElementExtent(h1).equals(qOut.getElementExtent(h2))); + assertTrue(quadTree.getExtent(quadTree.getQuad(h1)).equals(qOut.getExtent(qOut.getQuad(h2)))); + int c1 = quadTree.getSubTreeElementCount(quadTree.getQuad(h1)); + int c2 = qOut.getSubTreeElementCount(qOut.getQuad(h2)); + assertTrue(c1 == c2); + } + + assertTrue(h1 == -1 && h2 == -1); + + assertTrue(quadTree.getDataExtent().equals(qOut.getDataExtent())); + } catch (Exception e) { + fail("QuadTree serialization failure"); + } + + } } diff --git a/src/test/java/com/esri/core/geometry/TestSimplify.java b/src/test/java/com/esri/core/geometry/TestSimplify.java index 980f30c7..acad1ce4 100644 --- a/src/test/java/com/esri/core/geometry/TestSimplify.java +++ b/src/test/java/com/esri/core/geometry/TestSimplify.java @@ -34,479 +34,479 @@ import org.junit.Test; public class TestSimplify extends TestCase { - OperatorFactoryLocal factory = null; - OperatorSimplify simplifyOp = null; - OperatorSimplifyOGC simplifyOpOGC = null; - SpatialReference sr102100 = null; - SpatialReference sr4326 = null; - SpatialReference sr3857 = null; - - @Override - protected void setUp() throws Exception { - super.setUp(); - factory = OperatorFactoryLocal.getInstance(); - simplifyOp = (OperatorSimplify) factory - .getOperator(Operator.Type.Simplify); - simplifyOpOGC = (OperatorSimplifyOGC) factory - .getOperator(Operator.Type.SimplifyOGC); - sr102100 = SpatialReference.create(102100); - sr3857 = SpatialReference.create(3857);// PE_PCS_WGS_1984_WEB_MERCATOR_AUXSPHERE); - sr4326 = SpatialReference.create(4326);// enum_value2(SpatialReference, - // Code, GCS_WGS_1984)); - } - - @Override - protected void tearDown() throws Exception { - super.tearDown(); - } - - public Polygon makeNonSimplePolygon2() { - //MapGeometry mg = OperatorFactoryLocal.loadGeometryFromJSONFileDbg("c:/temp/simplify_polygon_gnomonic.txt"); - //Geometry res = OperatorSimplify.local().execute(mg.getGeometry(), mg.getSpatialReference(), true, null); - - - Polygon poly = new Polygon(); - poly.startPath(0, 0); - poly.lineTo(0, 15); - poly.lineTo(15, 15); - poly.lineTo(15, 0); - - // This is an interior ring but it is clockwise - poly.startPath(5, 5); - poly.lineTo(5, 6); - poly.lineTo(6, 6); - poly.lineTo(6, 5); - - return poly; - }// done + OperatorFactoryLocal factory = null; + OperatorSimplify simplifyOp = null; + OperatorSimplifyOGC simplifyOpOGC = null; + SpatialReference sr102100 = null; + SpatialReference sr4326 = null; + SpatialReference sr3857 = null; + + @Override + protected void setUp() throws Exception { + super.setUp(); + factory = OperatorFactoryLocal.getInstance(); + simplifyOp = (OperatorSimplify) factory + .getOperator(Operator.Type.Simplify); + simplifyOpOGC = (OperatorSimplifyOGC) factory + .getOperator(Operator.Type.SimplifyOGC); + sr102100 = SpatialReference.create(102100); + sr3857 = SpatialReference.create(3857);// PE_PCS_WGS_1984_WEB_MERCATOR_AUXSPHERE); + sr4326 = SpatialReference.create(4326);// enum_value2(SpatialReference, + // Code, GCS_WGS_1984)); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + } + + public Polygon makeNonSimplePolygon2() { + //MapGeometry mg = OperatorFactoryLocal.loadGeometryFromJSONFileDbg("c:/temp/simplify_polygon_gnomonic.txt"); + //Geometry res = OperatorSimplify.local().execute(mg.getGeometry(), mg.getSpatialReference(), true, null); + + + Polygon poly = new Polygon(); + poly.startPath(0, 0); + poly.lineTo(0, 15); + poly.lineTo(15, 15); + poly.lineTo(15, 0); + + // This is an interior ring but it is clockwise + poly.startPath(5, 5); + poly.lineTo(5, 6); + poly.lineTo(6, 6); + poly.lineTo(6, 5); + + return poly; + }// done /* - * ------------>---------------->--------------- | | | (1) | | | | --->--- + * ------------>---------------->--------------- | | | (1) | | | | --->--- * ------->------- | | | | | (5) | | | | | | --<-- | | | | (2) | | | | | | | * | | | | (4) | | | | | | | -->-- | | --<-- | ---<--- | | | | | | * -------<------- | | (3) | -------------<---------------<--------------- * -->-- */ - // Bowtie case with vertices at intersection - - public Polygon makeNonSimplePolygon5() { - Polygon poly = new Polygon(); - poly.startPath(10, 0); - poly.lineTo(0, 0); - poly.lineTo(5, 5); - poly.lineTo(10, 10); - poly.lineTo(0, 10); - poly.lineTo(5, 5); - - return poly; - }// done - - @Test - public void test0() { - Polygon poly1 = new Polygon(); - poly1.addEnvelope(new Envelope(10, 10, 40, 20), false); - Polygon poly2 = (Polygon) simplifyOp.execute(poly1, null, false, null); - boolean res = simplifyOp.isSimpleAsFeature(poly2, null, true, null, - null); - assertTrue(res); - // assertTrue(poly1.equals(poly2)); - }// done - - @Test - public void test0Poly() {// simple - Polygon poly1 = new Polygon(); - poly1.addEnvelope(new Envelope(10, 10, 40, 20), false); - poly1.addEnvelope(new Envelope(50, 10, 100, 20), false); - Polygon poly2 = (Polygon) simplifyOp.execute(poly1, null, false, null); - boolean res = simplifyOp.isSimpleAsFeature(poly2, null, true, null, - null); - assertTrue(res); - // assertTrue(poly1.equals(poly2)); - }// done - - @Test - public void test0Polygon_Spike1() {// non-simple (spike) - Polygon poly1 = new Polygon(); - poly1.startPath(10, 10); - poly1.lineTo(10, 20); - poly1.lineTo(40, 20); - poly1.lineTo(40, 10); - poly1.lineTo(60, 10); - poly1.lineTo(70, 10); - - boolean res = simplifyOp.isSimpleAsFeature(poly1, null, true, null, - null); - assertTrue(!res); - Polygon poly2 = (Polygon) simplifyOp.execute(poly1, null, false, null); - res = simplifyOp.isSimpleAsFeature(poly2, null, true, null, null); - assertTrue(res); - assertTrue(poly2.getPointCount() == 4); - }// done - - @Test - public void test0Polygon_Spike2() {// non-simple (spikes) - Polygon poly1 = new Polygon(); - // rectangle with a spike - poly1.startPath(10, 10); - poly1.lineTo(10, 20); - poly1.lineTo(40, 20); - poly1.lineTo(40, 10); - poly1.lineTo(60, 10); - poly1.lineTo(70, 10); - - // degenerate - poly1.startPath(100, 100); - poly1.lineTo(100, 120); - poly1.lineTo(100, 130); - - boolean res = simplifyOp.isSimpleAsFeature(poly1, null, true, null, - null); - assertTrue(!res); - Polygon poly2 = (Polygon) simplifyOp.execute(poly1, null, false, null); - res = simplifyOp.isSimpleAsFeature(poly2, null, true, null, null); - assertTrue(res); - assertTrue(poly2.getPointCount() == 4); - }// done - - @Test - public void test0Polygon_Spike3() {// non-simple (spikes) - Polygon poly1 = new Polygon(); - // degenerate - poly1.startPath(100, 100); - poly1.lineTo(100, 120); - poly1.lineTo(100, 130); - - boolean res = simplifyOp.isSimpleAsFeature(poly1, null, true, null, - null); - assertTrue(!res); - Polygon poly2 = (Polygon) simplifyOp.execute(poly1, null, false, null); - res = simplifyOp.isSimpleAsFeature(poly2, null, true, null, null); - assertTrue(res); - assertTrue(poly2.isEmpty()); - }// done - - @Test - public void test0PolygonSelfIntersect1() {// non-simple (self-intersection) - Polygon poly1 = new Polygon(); - // touch uncracked - poly1.startPath(0, 0); - poly1.lineTo(0, 100); - poly1.lineTo(100, 100); - poly1.lineTo(0, 50); - poly1.lineTo(100, 0); - - boolean res = simplifyOp.isSimpleAsFeature(poly1, null, true, null, - null); - assertTrue(!res); - Polygon poly2 = (Polygon) simplifyOp.execute(poly1, null, false, null); - res = simplifyOp.isSimpleAsFeature(poly2, null, true, null, null); - assertTrue(res); - assertTrue(!poly2.isEmpty()); - }// done - - @Test - public void test0PolygonSelfIntersect2() {// non-simple (self-intersection) - Polygon poly1 = new Polygon(); - poly1.startPath(0, 0); - poly1.lineTo(0, 100); - poly1.lineTo(100, 100); - poly1.lineTo(-100, 0); - // poly1.lineTo(100, 0); - - boolean res = simplifyOp.isSimpleAsFeature(poly1, null, true, null, - null); - assertTrue(!res); - Polygon poly2 = (Polygon) simplifyOp.execute(poly1, null, false, null); - res = simplifyOp.isSimpleAsFeature(poly2, null, true, null, null); - assertTrue(res); - assertTrue(!poly2.isEmpty()); - }// done - - @Test - public void test0PolygonSelfIntersect3() { - Polygon poly = new Polygon(); - poly.startPath(0, 0); - poly.lineTo(0, 15); - poly.lineTo(15, 15); - poly.lineTo(15, 0); - - // This part intersects with the first part - poly.startPath(10, 10); - poly.lineTo(10, 20); - poly.lineTo(20, 20); - poly.lineTo(20, 10); - - boolean res = simplifyOp - .isSimpleAsFeature(poly, null, true, null, null); - assertTrue(!res); - Polygon poly2 = (Polygon) simplifyOp.execute(poly, null, false, null); - res = simplifyOp.isSimpleAsFeature(poly2, null, true, null, null); - assertTrue(res); - assertTrue(!poly2.isEmpty()); - }// done - - @Test - public void test0PolygonInteriorRing1() { - Polygon poly = new Polygon(); - poly.startPath(0, 0); - poly.lineTo(0, 15); - poly.lineTo(15, 15); - poly.lineTo(15, 0); - - // This is an interior ring but it is clockwise - poly.startPath(5, 5); - poly.lineTo(5, 6); - poly.lineTo(6, 6); - poly.lineTo(6, 5); - - boolean res = simplifyOp - .isSimpleAsFeature(poly, null, true, null, null); - assertTrue(!res); - Polygon poly2 = (Polygon) simplifyOp.execute(poly, null, false, null); - res = simplifyOp.isSimpleAsFeature(poly2, null, true, null, null); - assertTrue(res); - assertTrue(!poly2.isEmpty()); - }// done - - @Test - public void test0PolygonInteriorRing2() { - Polygon poly = new Polygon(); - poly.startPath(0, 0); - poly.lineTo(0, 15); - poly.lineTo(15, 15); - poly.lineTo(15, 0); - - // This is an interior ring but it is clockwise - poly.startPath(5, 5); - poly.lineTo(5, 6); - poly.lineTo(6, 6); - poly.lineTo(6, 5); - - // This part intersects with the first part - poly.startPath(10, 10); - poly.lineTo(10, 20); - poly.lineTo(20, 20); - poly.lineTo(20, 10); - - boolean res = simplifyOp - .isSimpleAsFeature(poly, null, true, null, null); - assertTrue(!res); - Polygon poly2 = (Polygon) simplifyOp.execute(poly, null, false, null); - res = simplifyOp.isSimpleAsFeature(poly2, null, true, null, null); - assertTrue(res); - assertTrue(!poly2.isEmpty()); - }// done - - @Test - public void test0PolygonInteriorRingWithCommonBoundary1() { - // Two rings have common boundary - Polygon poly = new Polygon(); - poly.startPath(0, 0); - poly.lineTo(0, 10); - poly.lineTo(10, 10); - poly.lineTo(10, 0); - - poly.startPath(10, 0); - poly.lineTo(10, 10); - poly.lineTo(20, 10); - poly.lineTo(20, 0); - - boolean res = simplifyOp - .isSimpleAsFeature(poly, null, true, null, null); - assertTrue(!res); - Polygon poly2 = (Polygon) simplifyOp.execute(poly, null, false, null); - res = simplifyOp.isSimpleAsFeature(poly2, null, true, null, null); - assertTrue(res); - assertTrue(!poly2.isEmpty()); - }// done - - @Test - public void test0PolygonInteriorRingWithCommonBoundary2() { - // Two rings have common boundary - Polygon poly = new Polygon(); - poly.startPath(0, 0); - poly.lineTo(0, 10); - poly.lineTo(10, 10); - poly.lineTo(10, 0); - - poly.startPath(10, 5); - poly.lineTo(10, 6); - poly.lineTo(20, 6); - poly.lineTo(20, 5); - - boolean res = simplifyOp - .isSimpleAsFeature(poly, null, true, null, null); - assertTrue(!res); - Polygon poly2 = (Polygon) simplifyOp.execute(poly, null, false, null); - res = simplifyOp.isSimpleAsFeature(poly2, null, true, null, null); - assertTrue(res); - assertTrue(!poly2.isEmpty()); - }// done - - @Test - public void testPolygon() { - Polygon nonSimplePolygon = makeNonSimplePolygon(); - Polygon simplePolygon = (Polygon) simplifyOp.execute(nonSimplePolygon, - sr3857, false, null); - - boolean res = simplifyOp.isSimpleAsFeature(simplePolygon, sr3857, true, - null, null); - assertTrue(res); - - @SuppressWarnings("unused") - int partCount = simplePolygon.getPathCount(); - // assertTrue(partCount == 2); - - double area = simplePolygon.calculateRingArea2D(0); - assertTrue(Math.abs(area - 300) <= 0.0001); - - area = simplePolygon.calculateRingArea2D(1); - assertTrue(Math.abs(area - (-25.0)) <= 0.0001); - }// done - - @Test - public void testPolygon2() { - Polygon nonSimplePolygon2 = makeNonSimplePolygon2(); - double area = nonSimplePolygon2.calculateRingArea2D(1); - assertTrue(Math.abs(area - 1.0) <= 0.0001); - - Polygon simplePolygon2 = (Polygon) simplifyOp.execute( - nonSimplePolygon2, sr3857, false, null); - - boolean res = simplifyOp.isSimpleAsFeature(simplePolygon2, sr3857, - true, null, null); - assertTrue(res); - - area = simplePolygon2.calculateRingArea2D(0); - assertTrue(Math.abs(area - 225) <= 0.0001); - - area = simplePolygon2.calculateRingArea2D(1); - assertTrue(Math.abs(area - (-1.0)) <= 0.0001); - }// done - - @Test - public void testPolygon3() { - Polygon nonSimplePolygon3 = makeNonSimplePolygon3(); - Polygon simplePolygon3 = (Polygon) simplifyOp.execute( - nonSimplePolygon3, sr3857, false, null); - - boolean res = simplifyOp.isSimpleAsFeature(simplePolygon3, sr3857, - true, null, null); - assertTrue(res); - - double area = simplePolygon3.calculateRingArea2D(0); - assertTrue(Math.abs(area - 875) <= 0.0001); - - area = simplePolygon3.calculateRingArea2D(1); - assertTrue(Math.abs(area - (-225)) <= 0.0001 - || Math.abs(area - (-50.0)) <= 0.0001); - - area = simplePolygon3.calculateRingArea2D(2); - assertTrue(Math.abs(area - (-225)) <= 0.0001 - || Math.abs(area - (-50.0)) <= 0.0001); - - area = simplePolygon3.calculateRingArea2D(3); - assertTrue(Math.abs(area - 25) <= 0.0001); - - area = simplePolygon3.calculateRingArea2D(4); - assertTrue(Math.abs(area - 25) <= 0.0001); - }// done - - @Test - public void testPolyline() { - Polyline nonSimplePolyline = makeNonSimplePolyline(); - Polyline simplePolyline = (Polyline) simplifyOp.execute( - nonSimplePolyline, sr3857, false, null); - - int segmentCount = simplePolyline.getSegmentCount(); - assertTrue(segmentCount == 4); - }// done - - @Test - public void testPolygon4() { - Polygon nonSimplePolygon4 = makeNonSimplePolygon4(); - Polygon simplePolygon4 = (Polygon) simplifyOp.execute( - nonSimplePolygon4, sr3857, false, null); - boolean res = simplifyOp.isSimpleAsFeature(simplePolygon4, sr3857, - true, null, null); - assertTrue(res); - - assertTrue(simplePolygon4.getPointCount() == 5); - Point point = nonSimplePolygon4.getPoint(0); - assertTrue(point.getX() == 0.0 && point.getY() == 0.0); - point = nonSimplePolygon4.getPoint(1); - assertTrue(point.getX() == 0.0 && point.getY() == 10.0); - point = nonSimplePolygon4.getPoint(2); - assertTrue(point.getX() == 10.0 && point.getY() == 10.0); - point = nonSimplePolygon4.getPoint(3); - assertTrue(point.getX() == 10.0 && point.getY() == 0.0); - point = nonSimplePolygon4.getPoint(4); - assertTrue(point.getX() == 5.0 && point.getY() == 0.0); - }// done - - @Test - public void testPolygon5() { - Polygon nonSimplePolygon5 = makeNonSimplePolygon5(); - Polygon simplePolygon5 = (Polygon) simplifyOp.execute( - nonSimplePolygon5, sr3857, false, null); - assertTrue(simplePolygon5 != null); - - boolean res = simplifyOp.isSimpleAsFeature(simplePolygon5, sr3857, - true, null, null); - assertTrue(res); - - int pointCount = simplePolygon5.getPointCount(); - assertTrue(pointCount == 6); - - double area = simplePolygon5.calculateArea2D(); - assertTrue(Math.abs(area - 50.0) <= 0.001); - - }// done - - @Test - public void testPolygon6() { - Polygon nonSimplePolygon6 = makeNonSimplePolygon6(); - Polygon simplePolygon6 = (Polygon) simplifyOp.execute( - nonSimplePolygon6, sr3857, false, null); - - boolean res = simplifyOp.isSimpleAsFeature(simplePolygon6, sr3857, - true, null, null); - assertTrue(res); - } - - @Test - public void testPolygon7() { - Polygon nonSimplePolygon7 = makeNonSimplePolygon7(); - Polygon simplePolygon7 = (Polygon) simplifyOp.execute( - nonSimplePolygon7, sr3857, false, null); - - boolean res = simplifyOp.isSimpleAsFeature(simplePolygon7, sr3857, - true, null, null); - assertTrue(res); - } - - public Polygon makeNonSimplePolygon() { - Polygon poly = new Polygon(); - poly.startPath(0, 0); - poly.lineTo(0, 15); - poly.lineTo(15, 15); - poly.lineTo(15, 0); - - // This is an interior ring but it is clockwise - poly.startPath(5, 5); - poly.lineTo(5, 6); - poly.lineTo(6, 6); - poly.lineTo(6, 5); - - // This part intersects with the first part - poly.startPath(10, 10); - poly.lineTo(10, 20); - poly.lineTo(20, 20); - poly.lineTo(20, 10); - - return poly; - }// done + // Bowtie case with vertices at intersection + + public Polygon makeNonSimplePolygon5() { + Polygon poly = new Polygon(); + poly.startPath(10, 0); + poly.lineTo(0, 0); + poly.lineTo(5, 5); + poly.lineTo(10, 10); + poly.lineTo(0, 10); + poly.lineTo(5, 5); + + return poly; + }// done + + @Test + public void test0() { + Polygon poly1 = new Polygon(); + poly1.addEnvelope(new Envelope(10, 10, 40, 20), false); + Polygon poly2 = (Polygon) simplifyOp.execute(poly1, null, false, null); + boolean res = simplifyOp.isSimpleAsFeature(poly2, null, true, null, + null); + assertTrue(res); + // assertTrue(poly1.equals(poly2)); + }// done + + @Test + public void test0Poly() {// simple + Polygon poly1 = new Polygon(); + poly1.addEnvelope(new Envelope(10, 10, 40, 20), false); + poly1.addEnvelope(new Envelope(50, 10, 100, 20), false); + Polygon poly2 = (Polygon) simplifyOp.execute(poly1, null, false, null); + boolean res = simplifyOp.isSimpleAsFeature(poly2, null, true, null, + null); + assertTrue(res); + // assertTrue(poly1.equals(poly2)); + }// done + + @Test + public void test0Polygon_Spike1() {// non-simple (spike) + Polygon poly1 = new Polygon(); + poly1.startPath(10, 10); + poly1.lineTo(10, 20); + poly1.lineTo(40, 20); + poly1.lineTo(40, 10); + poly1.lineTo(60, 10); + poly1.lineTo(70, 10); + + boolean res = simplifyOp.isSimpleAsFeature(poly1, null, true, null, + null); + assertTrue(!res); + Polygon poly2 = (Polygon) simplifyOp.execute(poly1, null, false, null); + res = simplifyOp.isSimpleAsFeature(poly2, null, true, null, null); + assertTrue(res); + assertTrue(poly2.getPointCount() == 4); + }// done + + @Test + public void test0Polygon_Spike2() {// non-simple (spikes) + Polygon poly1 = new Polygon(); + // rectangle with a spike + poly1.startPath(10, 10); + poly1.lineTo(10, 20); + poly1.lineTo(40, 20); + poly1.lineTo(40, 10); + poly1.lineTo(60, 10); + poly1.lineTo(70, 10); + + // degenerate + poly1.startPath(100, 100); + poly1.lineTo(100, 120); + poly1.lineTo(100, 130); + + boolean res = simplifyOp.isSimpleAsFeature(poly1, null, true, null, + null); + assertTrue(!res); + Polygon poly2 = (Polygon) simplifyOp.execute(poly1, null, false, null); + res = simplifyOp.isSimpleAsFeature(poly2, null, true, null, null); + assertTrue(res); + assertTrue(poly2.getPointCount() == 4); + }// done + + @Test + public void test0Polygon_Spike3() {// non-simple (spikes) + Polygon poly1 = new Polygon(); + // degenerate + poly1.startPath(100, 100); + poly1.lineTo(100, 120); + poly1.lineTo(100, 130); + + boolean res = simplifyOp.isSimpleAsFeature(poly1, null, true, null, + null); + assertTrue(!res); + Polygon poly2 = (Polygon) simplifyOp.execute(poly1, null, false, null); + res = simplifyOp.isSimpleAsFeature(poly2, null, true, null, null); + assertTrue(res); + assertTrue(poly2.isEmpty()); + }// done + + @Test + public void test0PolygonSelfIntersect1() {// non-simple (self-intersection) + Polygon poly1 = new Polygon(); + // touch uncracked + poly1.startPath(0, 0); + poly1.lineTo(0, 100); + poly1.lineTo(100, 100); + poly1.lineTo(0, 50); + poly1.lineTo(100, 0); + + boolean res = simplifyOp.isSimpleAsFeature(poly1, null, true, null, + null); + assertTrue(!res); + Polygon poly2 = (Polygon) simplifyOp.execute(poly1, null, false, null); + res = simplifyOp.isSimpleAsFeature(poly2, null, true, null, null); + assertTrue(res); + assertTrue(!poly2.isEmpty()); + }// done + + @Test + public void test0PolygonSelfIntersect2() {// non-simple (self-intersection) + Polygon poly1 = new Polygon(); + poly1.startPath(0, 0); + poly1.lineTo(0, 100); + poly1.lineTo(100, 100); + poly1.lineTo(-100, 0); + // poly1.lineTo(100, 0); + + boolean res = simplifyOp.isSimpleAsFeature(poly1, null, true, null, + null); + assertTrue(!res); + Polygon poly2 = (Polygon) simplifyOp.execute(poly1, null, false, null); + res = simplifyOp.isSimpleAsFeature(poly2, null, true, null, null); + assertTrue(res); + assertTrue(!poly2.isEmpty()); + }// done + + @Test + public void test0PolygonSelfIntersect3() { + Polygon poly = new Polygon(); + poly.startPath(0, 0); + poly.lineTo(0, 15); + poly.lineTo(15, 15); + poly.lineTo(15, 0); + + // This part intersects with the first part + poly.startPath(10, 10); + poly.lineTo(10, 20); + poly.lineTo(20, 20); + poly.lineTo(20, 10); + + boolean res = simplifyOp + .isSimpleAsFeature(poly, null, true, null, null); + assertTrue(!res); + Polygon poly2 = (Polygon) simplifyOp.execute(poly, null, false, null); + res = simplifyOp.isSimpleAsFeature(poly2, null, true, null, null); + assertTrue(res); + assertTrue(!poly2.isEmpty()); + }// done + + @Test + public void test0PolygonInteriorRing1() { + Polygon poly = new Polygon(); + poly.startPath(0, 0); + poly.lineTo(0, 15); + poly.lineTo(15, 15); + poly.lineTo(15, 0); + + // This is an interior ring but it is clockwise + poly.startPath(5, 5); + poly.lineTo(5, 6); + poly.lineTo(6, 6); + poly.lineTo(6, 5); + + boolean res = simplifyOp + .isSimpleAsFeature(poly, null, true, null, null); + assertTrue(!res); + Polygon poly2 = (Polygon) simplifyOp.execute(poly, null, false, null); + res = simplifyOp.isSimpleAsFeature(poly2, null, true, null, null); + assertTrue(res); + assertTrue(!poly2.isEmpty()); + }// done + + @Test + public void test0PolygonInteriorRing2() { + Polygon poly = new Polygon(); + poly.startPath(0, 0); + poly.lineTo(0, 15); + poly.lineTo(15, 15); + poly.lineTo(15, 0); + + // This is an interior ring but it is clockwise + poly.startPath(5, 5); + poly.lineTo(5, 6); + poly.lineTo(6, 6); + poly.lineTo(6, 5); + + // This part intersects with the first part + poly.startPath(10, 10); + poly.lineTo(10, 20); + poly.lineTo(20, 20); + poly.lineTo(20, 10); + + boolean res = simplifyOp + .isSimpleAsFeature(poly, null, true, null, null); + assertTrue(!res); + Polygon poly2 = (Polygon) simplifyOp.execute(poly, null, false, null); + res = simplifyOp.isSimpleAsFeature(poly2, null, true, null, null); + assertTrue(res); + assertTrue(!poly2.isEmpty()); + }// done + + @Test + public void test0PolygonInteriorRingWithCommonBoundary1() { + // Two rings have common boundary + Polygon poly = new Polygon(); + poly.startPath(0, 0); + poly.lineTo(0, 10); + poly.lineTo(10, 10); + poly.lineTo(10, 0); + + poly.startPath(10, 0); + poly.lineTo(10, 10); + poly.lineTo(20, 10); + poly.lineTo(20, 0); + + boolean res = simplifyOp + .isSimpleAsFeature(poly, null, true, null, null); + assertTrue(!res); + Polygon poly2 = (Polygon) simplifyOp.execute(poly, null, false, null); + res = simplifyOp.isSimpleAsFeature(poly2, null, true, null, null); + assertTrue(res); + assertTrue(!poly2.isEmpty()); + }// done + + @Test + public void test0PolygonInteriorRingWithCommonBoundary2() { + // Two rings have common boundary + Polygon poly = new Polygon(); + poly.startPath(0, 0); + poly.lineTo(0, 10); + poly.lineTo(10, 10); + poly.lineTo(10, 0); + + poly.startPath(10, 5); + poly.lineTo(10, 6); + poly.lineTo(20, 6); + poly.lineTo(20, 5); + + boolean res = simplifyOp + .isSimpleAsFeature(poly, null, true, null, null); + assertTrue(!res); + Polygon poly2 = (Polygon) simplifyOp.execute(poly, null, false, null); + res = simplifyOp.isSimpleAsFeature(poly2, null, true, null, null); + assertTrue(res); + assertTrue(!poly2.isEmpty()); + }// done + + @Test + public void testPolygon() { + Polygon nonSimplePolygon = makeNonSimplePolygon(); + Polygon simplePolygon = (Polygon) simplifyOp.execute(nonSimplePolygon, + sr3857, false, null); + + boolean res = simplifyOp.isSimpleAsFeature(simplePolygon, sr3857, true, + null, null); + assertTrue(res); + + @SuppressWarnings("unused") + int partCount = simplePolygon.getPathCount(); + // assertTrue(partCount == 2); + + double area = simplePolygon.calculateRingArea2D(0); + assertTrue(Math.abs(area - 300) <= 0.0001); + + area = simplePolygon.calculateRingArea2D(1); + assertTrue(Math.abs(area - (-25.0)) <= 0.0001); + }// done + + @Test + public void testPolygon2() { + Polygon nonSimplePolygon2 = makeNonSimplePolygon2(); + double area = nonSimplePolygon2.calculateRingArea2D(1); + assertTrue(Math.abs(area - 1.0) <= 0.0001); + + Polygon simplePolygon2 = (Polygon) simplifyOp.execute( + nonSimplePolygon2, sr3857, false, null); + + boolean res = simplifyOp.isSimpleAsFeature(simplePolygon2, sr3857, + true, null, null); + assertTrue(res); + + area = simplePolygon2.calculateRingArea2D(0); + assertTrue(Math.abs(area - 225) <= 0.0001); + + area = simplePolygon2.calculateRingArea2D(1); + assertTrue(Math.abs(area - (-1.0)) <= 0.0001); + }// done + + @Test + public void testPolygon3() { + Polygon nonSimplePolygon3 = makeNonSimplePolygon3(); + Polygon simplePolygon3 = (Polygon) simplifyOp.execute( + nonSimplePolygon3, sr3857, false, null); + + boolean res = simplifyOp.isSimpleAsFeature(simplePolygon3, sr3857, + true, null, null); + assertTrue(res); + + double area = simplePolygon3.calculateRingArea2D(0); + assertTrue(Math.abs(area - 875) <= 0.0001); + + area = simplePolygon3.calculateRingArea2D(1); + assertTrue(Math.abs(area - (-225)) <= 0.0001 + || Math.abs(area - (-50.0)) <= 0.0001); + + area = simplePolygon3.calculateRingArea2D(2); + assertTrue(Math.abs(area - (-225)) <= 0.0001 + || Math.abs(area - (-50.0)) <= 0.0001); + + area = simplePolygon3.calculateRingArea2D(3); + assertTrue(Math.abs(area - 25) <= 0.0001); + + area = simplePolygon3.calculateRingArea2D(4); + assertTrue(Math.abs(area - 25) <= 0.0001); + }// done + + @Test + public void testPolyline() { + Polyline nonSimplePolyline = makeNonSimplePolyline(); + Polyline simplePolyline = (Polyline) simplifyOp.execute( + nonSimplePolyline, sr3857, false, null); + + int segmentCount = simplePolyline.getSegmentCount(); + assertTrue(segmentCount == 4); + }// done + + @Test + public void testPolygon4() { + Polygon nonSimplePolygon4 = makeNonSimplePolygon4(); + Polygon simplePolygon4 = (Polygon) simplifyOp.execute( + nonSimplePolygon4, sr3857, false, null); + boolean res = simplifyOp.isSimpleAsFeature(simplePolygon4, sr3857, + true, null, null); + assertTrue(res); + + assertTrue(simplePolygon4.getPointCount() == 5); + Point point = nonSimplePolygon4.getPoint(0); + assertTrue(point.getX() == 0.0 && point.getY() == 0.0); + point = nonSimplePolygon4.getPoint(1); + assertTrue(point.getX() == 0.0 && point.getY() == 10.0); + point = nonSimplePolygon4.getPoint(2); + assertTrue(point.getX() == 10.0 && point.getY() == 10.0); + point = nonSimplePolygon4.getPoint(3); + assertTrue(point.getX() == 10.0 && point.getY() == 0.0); + point = nonSimplePolygon4.getPoint(4); + assertTrue(point.getX() == 5.0 && point.getY() == 0.0); + }// done + + @Test + public void testPolygon5() { + Polygon nonSimplePolygon5 = makeNonSimplePolygon5(); + Polygon simplePolygon5 = (Polygon) simplifyOp.execute( + nonSimplePolygon5, sr3857, false, null); + assertTrue(simplePolygon5 != null); + + boolean res = simplifyOp.isSimpleAsFeature(simplePolygon5, sr3857, + true, null, null); + assertTrue(res); + + int pointCount = simplePolygon5.getPointCount(); + assertTrue(pointCount == 6); + + double area = simplePolygon5.calculateArea2D(); + assertTrue(Math.abs(area - 50.0) <= 0.001); + + }// done + + @Test + public void testPolygon6() { + Polygon nonSimplePolygon6 = makeNonSimplePolygon6(); + Polygon simplePolygon6 = (Polygon) simplifyOp.execute( + nonSimplePolygon6, sr3857, false, null); + + boolean res = simplifyOp.isSimpleAsFeature(simplePolygon6, sr3857, + true, null, null); + assertTrue(res); + } + + @Test + public void testPolygon7() { + Polygon nonSimplePolygon7 = makeNonSimplePolygon7(); + Polygon simplePolygon7 = (Polygon) simplifyOp.execute( + nonSimplePolygon7, sr3857, false, null); + + boolean res = simplifyOp.isSimpleAsFeature(simplePolygon7, sr3857, + true, null, null); + assertTrue(res); + } + + public Polygon makeNonSimplePolygon() { + Polygon poly = new Polygon(); + poly.startPath(0, 0); + poly.lineTo(0, 15); + poly.lineTo(15, 15); + poly.lineTo(15, 0); + + // This is an interior ring but it is clockwise + poly.startPath(5, 5); + poly.lineTo(5, 6); + poly.lineTo(6, 6); + poly.lineTo(6, 5); + + // This part intersects with the first part + poly.startPath(10, 10); + poly.lineTo(10, 20); + poly.lineTo(20, 20); + poly.lineTo(20, 10); + + return poly; + }// done /* * ------------>---------------->--------------- | | | (1) | | | | --->--- @@ -516,849 +516,849 @@ public Polygon makeNonSimplePolygon() { * -->-- */ - public Polygon makeNonSimplePolygon3() { - Polygon poly = new Polygon(); - poly.startPath(0, 0); - poly.lineTo(0, 25); - poly.lineTo(35, 25); - poly.lineTo(35, 0); - - poly.startPath(5, 5); - poly.lineTo(5, 15); - poly.lineTo(10, 15); - poly.lineTo(10, 5); - - poly.startPath(40, 0); - poly.lineTo(45, 0); - poly.lineTo(45, 5); - poly.lineTo(40, 5); - - poly.startPath(20, 10); - poly.lineTo(25, 10); - poly.lineTo(25, 15); - poly.lineTo(20, 15); - - poly.startPath(15, 5); - poly.lineTo(15, 20); - poly.lineTo(30, 20); - poly.lineTo(30, 5); - - return poly; - }// done - - public Polygon makeNonSimplePolygon4() { - Polygon poly = new Polygon(); - poly.startPath(0, 0); - poly.lineTo(0, 10); - poly.lineTo(10, 10); - poly.lineTo(10, 0); - poly.lineTo(5, 0); - poly.lineTo(5, 5); - poly.lineTo(5, 0); - - return poly; - }// done - - public Polygon makeNonSimplePolygon6() { - Polygon poly = new Polygon(); - poly.startPath(35.34407570857744, 54.00551247713412); - poly.lineTo(41.07663499357954, 20.0); - poly.lineTo(40.66372033705177, 26.217432321849017); - - poly.startPath(42.81936574509338, 20.0); - poly.lineTo(43.58226670584747, 20.0); - poly.lineTo(39.29611825817084, 22.64634933678729); - poly.lineTo(44.369873312241346, 25.81893670527215); - poly.lineTo(42.68845660737179, 20.0); - poly.lineTo(38.569549792944244, 56.47456192829393); - poly.lineTo(42.79274114188401, 45.45117792578003); - poly.lineTo(41.09512147544657, 70.0); - - return poly; - } - - public Polygon makeNonSimplePolygon7() { - Polygon poly = new Polygon(); - - poly.startPath(41.987895433319686, 53.75822619011542); - poly.lineTo(41.98789542535497, 53.75822618803151); - poly.lineTo(40.15120412113667, 68.12604154722113); - poly.lineTo(37.72272697311022, 67.92767094118877); - poly.lineTo(37.147347454283086, 49.497473094145505); - poly.lineTo(38.636627026664385, 51.036687142232736); - - poly.startPath(39.00920080789793, 62.063425518369016); - poly.lineTo(38.604912643136885, 70.0); - poly.lineTo(40.71826863485308, 43.60337143116787); - poly.lineTo(35.34407570857744, 54.005512477134126); - poly.lineTo(39.29611825817084, 22.64634933678729); - - return poly; - } - - public Polyline makeNonSimplePolyline() { - // This polyline has a short segment - Polyline poly = new Polyline(); - poly.startPath(0, 0); - poly.lineTo(10, 0); - poly.lineTo(10, 10); - poly.lineTo(10, 5); - poly.lineTo(-5, 5); - - return poly; - }// done - - @Test - public void testIsSimpleBasicsPoint() { - boolean result; - // point is always simple - Point pt = new Point(); - result = simplifyOp.isSimpleAsFeature(pt, sr4326, false, null, null); - assertTrue(result); - pt.setXY(0, 0); - result = simplifyOp.isSimpleAsFeature(pt, sr4326, false, null, null); - assertTrue(result); - pt.setXY(100000, 10000); - result = simplifyOp.isSimpleAsFeature(pt, sr4326, false, null, null); - assertTrue(result); - }// done - - @Test - public void testIsSimpleBasicsEnvelope() { - // Envelope is simple, when it's width and height are not degenerate - Envelope env = new Envelope(); - boolean result = simplifyOp.isSimpleAsFeature(env, sr4326, false, null, - null); // Empty is simple - assertTrue(result); - env.setCoords(0, 0, 10, 10); - result = simplifyOp.isSimpleAsFeature(env, sr4326, false, null, null); - assertTrue(result); - // sliver but still simple - env.setCoords(0, 0, 0 + sr4326.getTolerance() * 2, 10); - result = simplifyOp.isSimpleAsFeature(env, sr4326, false, null, null); - assertTrue(result); - // sliver and not simple - env.setCoords(0, 0, 0 + sr4326.getTolerance() * 0.5, 10); - result = simplifyOp.isSimpleAsFeature(env, sr4326, false, null, null); - assertTrue(!result); - }// done - - @Test - public void testIsSimpleBasicsLine() { - Line line = new Line(); - boolean result = simplifyOp.isSimpleAsFeature(line, sr4326, false, - null, null); - assertTrue(!result); - - line.setStart(new Point(0, 0)); - // line.setEndXY(0, 0); - result = simplifyOp.isSimpleAsFeature(line, sr4326, false, null, null); - assertTrue(!result); - line.setEnd(new Point(1, 0)); - result = simplifyOp.isSimpleAsFeature(line, sr4326, false, null, null); - assertTrue(result); - }// done - - @Test - public void testIsSimpleMultiPoint1() { - MultiPoint mp = new MultiPoint(); - boolean result = simplifyOp.isSimpleAsFeature(mp, sr4326, false, null, - null); - assertTrue(result);// empty is simple - result = simplifyOp.isSimpleAsFeature( - simplifyOp.execute(mp, sr4326, false, null), sr4326, false, - null, null); - assertTrue(result); - }// done - - @Test - public void testIsSimpleMultiPoint2FarApart() { - // Two point test: far apart - MultiPoint mp = new MultiPoint(); - mp.add(20, 10); - mp.add(100, 100); - boolean result = simplifyOp.isSimpleAsFeature(mp, sr4326, false, null, - null); - assertTrue(result); - result = simplifyOp.isSimpleAsFeature( - simplifyOp.execute(mp, sr4326, false, null), sr4326, false, - null, null); - assertTrue(result); - assertTrue(mp.getPointCount() == 2); - }// done - - @Test - public void testIsSimpleMultiPointCoincident() { - // Two point test: coincident - MultiPoint mp = new MultiPoint(); - mp.add(100, 100); - mp.add(100, 100); - boolean result = simplifyOp.isSimpleAsFeature(mp, sr4326, false, null, - null); - assertTrue(!result); - MultiPoint mpS; - result = simplifyOp.isSimpleAsFeature( - mpS = (MultiPoint) simplifyOp.execute(mp, sr4326, false, null), - sr4326, false, null, null); - assertTrue(result); - assertTrue(mpS.getPointCount() == 1); - }// done - - @Test - public void testMultiPointSR4326_CR184439() { - OperatorFactoryLocal engine = OperatorFactoryLocal.getInstance(); - OperatorSimplify simpOp = (OperatorSimplify) engine - .getOperator(Operator.Type.Simplify); - NonSimpleResult nonSimpResult = new NonSimpleResult(); - nonSimpResult.m_reason = NonSimpleResult.Reason.NotDetermined; - MultiPoint multiPoint = new MultiPoint(); - multiPoint.add(0, 0); - multiPoint.add(0, 1); - multiPoint.add(0, 0); - Boolean multiPointIsSimple = simpOp.isSimpleAsFeature(multiPoint, - SpatialReference.create(4326), true, nonSimpResult, null); - assertFalse(multiPointIsSimple); - assertTrue(nonSimpResult.m_reason == NonSimpleResult.Reason.Clustering); - assertTrue(nonSimpResult.m_vertexIndex1 == 0); - assertTrue(nonSimpResult.m_vertexIndex2 == 2); - } - - @Test - public void testIsSimpleMultiPointCloserThanTolerance() { - // Two point test: closer than tolerance - MultiPoint mp = new MultiPoint(); - MultiPoint mpS; - mp.add(100, 100); - mp.add(100, 100 + sr4326.getTolerance() * .5); - boolean result = simplifyOp.isSimpleAsFeature(mp, sr4326, false, null, - null); - assertTrue(result); - result = simplifyOp.isSimpleAsFeature( - mpS = (MultiPoint) simplifyOp.execute(mp, sr4326, false, null), - sr4326, false, null, null); - assertTrue(result); - assertTrue(mpS.getPointCount() == 2); - }// done - - @Test - public void testIsSimpleMultiPointFarApart2() { - // 5 point test: far apart - MultiPoint mp = new MultiPoint(); - mp.add(100, 100); - mp.add(100, 101); - mp.add(101, 101); - mp.add(11, 1); - mp.add(11, 14); - MultiPoint mpS; - boolean result = simplifyOp.isSimpleAsFeature(mp, sr4326, false, null, - null); - assertTrue(result); - result = simplifyOp.isSimpleAsFeature( - mpS = (MultiPoint) simplifyOp.execute(mp, sr4326, false, null), - sr4326, false, null, null); - assertTrue(result); - assertTrue(mpS.getPointCount() == 5); - }// done - - @Test - public void testIsSimpleMultiPoint_coincident2() { - // 5 point test: coincident - MultiPoint mp = new MultiPoint(); - mp.add(100, 100); - mp.add(100, 101); - mp.add(100, 100); - mp.add(11, 1); - mp.add(11, 14); - boolean result = simplifyOp.isSimpleAsFeature(mp, sr4326, false, null, - null); - assertTrue(!result); - MultiPoint mpS; - result = simplifyOp.isSimpleAsFeature( - mpS = (MultiPoint) simplifyOp.execute(mp, sr4326, false, null), - sr4326, false, null, null); - assertTrue(result); - assertTrue(mpS.getPointCount() == 4); - assertEquals(mpS.getPoint(0).getX(), 100, 1e-7); - assertEquals(mpS.getPoint(0).getY(), 100, 1e-7); - assertEquals(mpS.getPoint(1).getX(), 100, 1e-7); - assertEquals(mpS.getPoint(1).getY(), 101, 1e-7); - assertEquals(mpS.getPoint(2).getX(), 11, 1e-7); - assertEquals(mpS.getPoint(2).getY(), 1, 1e-7); - assertEquals(mpS.getPoint(3).getX(), 11, 1e-7); - assertEquals(mpS.getPoint(3).getY(), 14, 1e-7); - }// done - - @Test - public void testIsSimpleMultiPointCloserThanTolerance2() { - // 5 point test: closer than tolerance - MultiPoint mp = new MultiPoint(); - mp.add(100, 100); - mp.add(100, 101); - mp.add(100, 100 + sr4326.getTolerance() / 2); - mp.add(11, 1); - mp.add(11, 14); - MultiPoint mpS; - boolean result = simplifyOp.isSimpleAsFeature(mp, sr4326, false, null, - null); - assertTrue(result); - result = simplifyOp.isSimpleAsFeature( - mpS = (MultiPoint) simplifyOp.execute(mp, sr4326, false, null), - sr4326, false, null, null); - assertTrue(result); - assertTrue(mpS.getPointCount() == 5); - }// done - - @Test - public void testIsSimplePolyline() { - Polyline poly = new Polyline(); - boolean result = simplifyOp.isSimpleAsFeature(poly, sr4326, false, - null, null); - assertTrue(result);// empty is simple - } - - @Test - public void testIsSimplePolylineFarApart() { - // Two point test: far apart - Polyline poly = new Polyline(); - poly.startPath(20, 10); - poly.lineTo(100, 100); - boolean result = simplifyOp.isSimpleAsFeature(poly, sr4326, false, - null, null); - assertTrue(result); - } - - @Test - public void testIsSimplePolylineCoincident() { - // Two point test: coincident - Polyline poly = new Polyline(); - poly.startPath(100, 100); - poly.lineTo(100, 100); - boolean result = simplifyOp.isSimpleAsFeature(poly, sr4326, false, - null, null); - assertTrue(!result); - @SuppressWarnings("unused") - Polyline polyS; - result = simplifyOp.isSimpleAsFeature( - polyS = (Polyline) simplifyOp - .execute(poly, sr4326, false, null), sr4326, false, - null, null); - assertTrue(result); - } - - @Test - public void testIsSimplePolylineCloserThanTolerance() { - // Two point test: closer than tolerance - Polyline poly = new Polyline(); - poly.startPath(100, 100); - poly.lineTo(100, 100 + sr4326.getTolerance() / 2); - boolean result = simplifyOp.isSimpleAsFeature(poly, sr4326, false, - null, null); - assertTrue(!result); - @SuppressWarnings("unused") - Polyline polyS; - result = simplifyOp.isSimpleAsFeature( - polyS = (Polyline) simplifyOp - .execute(poly, sr4326, false, null), sr4326, false, - null, null); - assertTrue(result); - } - - @Test - public void testIsSimplePolylineFarApartSelfOverlap0() { - // 3 point test: far apart, self overlapping - Polyline poly = new Polyline(); - poly.startPath(0, 0); - poly.lineTo(100, 100); - poly.lineTo(0, 0); - boolean result = simplifyOp.isSimpleAsFeature(poly, sr4326, false, - null, null); - assertTrue(result);// TO CONFIRM should be false - } - - @Test - public void testIsSimplePolylineSelfIntersect() { - // 4 point test: far apart, self intersecting - Polyline poly = new Polyline(); - poly.startPath(0, 0); - poly.lineTo(100, 100); - poly.lineTo(0, 100); - poly.lineTo(100, 0); - boolean result = simplifyOp.isSimpleAsFeature(poly, sr4326, false, - null, null); - assertTrue(result);// TO CONFIRM should be false - } - - @Test - public void testIsSimplePolylineDegenerateSegment() { - // 4 point test: degenerate segment - Polyline poly = new Polyline(); - poly.startPath(0, 0); - poly.lineTo(100, 100); - poly.lineTo(100, 100 + sr4326.getTolerance() / 2); - poly.lineTo(100, 0); - boolean result = simplifyOp.isSimpleAsFeature(poly, sr4326, false, - null, null); - assertTrue(!result); - @SuppressWarnings("unused") - Polyline polyS; - result = simplifyOp.isSimpleAsFeature( - polyS = (Polyline) simplifyOp - .execute(poly, sr4326, false, null), sr4326, false, - null, null); - assertTrue(result); - { - Polyline other = new Polyline(); - other.startPath(0, 0); - other.lineTo(100, 100); - other.lineTo(100, 0); - other.equals(poly); - } - } - - @Test - public void testIsSimplePolylineFarApartSelfOverlap() { - // 3 point test: far apart, self overlapping - Polyline poly = new Polyline(); - poly.startPath(0, 0); - poly.lineTo(100, 100); - poly.lineTo(0, 0); - boolean result = simplifyOp.isSimpleAsFeature(poly, sr4326, false, - null, null); - assertTrue(result);// TO CONFIRM should be false - } - - @Test - public void testIsSimplePolylineFarApartIntersect() { - // 4 point 2 parts test: far apart, intersecting parts - Polyline poly = new Polyline(); - poly.startPath(0, 0); - poly.lineTo(100, 100); - poly.startPath(100, 0); - poly.lineTo(0, 100); - - boolean result = simplifyOp.isSimpleAsFeature(poly, sr4326, false, - null, null); - assertTrue(result);// TO CONFIRM should be false - } - - @Test - public void testIsSimplePolylineFarApartOverlap2() { - // 4 point 2 parts test: far apart, overlapping parts. second part - // starts where first one ends - Polyline poly = new Polyline(); - poly.startPath(0, 0); - poly.lineTo(100, 100); - poly.startPath(100, 100); - poly.lineTo(0, 100); - - boolean result = simplifyOp.isSimpleAsFeature(poly, sr4326, false, - null, null); - assertTrue(result);// TO CONFIRM should be false - } - - @Test - public void testIsSimplePolylineDegenerateVertical() { - // 3 point test: degenerate vertical line - Polyline poly = new Polyline(); - poly.startPath(0, 0); - poly.lineTo(new Point(100, 100)); - poly.lineTo(new Point(100, 100)); - boolean result = simplifyOp.isSimpleAsFeature(poly, sr4326, false, - null, null); - assertTrue(!result); - Polyline polyS; - result = simplifyOp.isSimpleAsFeature( - polyS = (Polyline) simplifyOp - .execute(poly, sr4326, false, null), sr4326, false, - null, null); - assertTrue(result); - assertTrue(polyS.getPointCount() == 2); - } - - @Test - public void testIsSimplePolylineEmptyPath() { - // TODO: any way to test this? - // Empty path - // Polyline poly = new Polyline(); - // assertTrue(poly.isEmpty()); - // poly.addPath(new Polyline(), 0, true); - // assertTrue(poly.isEmpty()); - // boolean result = simplifyOp.isSimpleAsFeature(poly, sr4326, false, - // null, null); - // assertTrue(result); - } - - @Test - public void testIsSimplePolylineSinglePointInPath() { - // Single point in path - Polyline poly = new Polyline(); - poly.startPath(0, 0); - poly.lineTo(100, 100); - poly.removePoint(0, 1); - boolean result = simplifyOp.isSimpleAsFeature(poly, sr4326, false, - null, null); - assertTrue(!result); - Polyline polyS; - result = simplifyOp.isSimpleAsFeature( - polyS = (Polyline) simplifyOp - .execute(poly, sr4326, false, null), sr4326, false, - null, null); - assertTrue(result); - assertTrue(polyS.isEmpty()); - } - - @Test - public void testIsSimplePolygon() { - Polygon poly = new Polygon(); - boolean result = simplifyOp.isSimpleAsFeature(poly, sr4326, false, - null, null); - assertTrue(result);// empty is simple - result = simplifyOp.isSimpleAsFeature( - simplifyOp.execute(poly, sr4326, false, null), sr4326, false, - null, null); - assertTrue(result);// empty is simple - } - - @Test - public void testIsSimplePolygonEmptyPath() { - // TODO: - // Empty path - // Polygon poly = new Polygon(); - // poly.addPath(new Polyline(), 0, true); - // assertTrue(poly.getPathCount() == 1); - // boolean result = simplifyOp.isSimpleAsFeature(poly, sr4326, false, - // null, - // null); - // assertTrue(result); - // result = simplifyOp.isSimpleAsFeature(simplifyOp.execute(poly, - // sr4326, false, null), sr4326, false, null, null); - // assertTrue(result);// empty is simple - // assertTrue(poly.getPathCount() == 1); - } - - @Test - public void testIsSimplePolygonIncomplete1() { - // Incomplete polygon 1 - Polygon poly = new Polygon(); - poly.startPath(0, 0); - poly.lineTo(100, 100); - // poly.removePoint(0, 1);//TO CONFIRM no removePoint method in Java - boolean result = simplifyOp.isSimpleAsFeature(poly, sr4326, false, - null, null); - assertTrue(!result); - } - - @Test - public void testIsSimplePolygonIncomplete2() { - // Incomplete polygon 2 - Polygon poly = new Polygon(); - poly.startPath(0, 0); - poly.lineTo(100, 100); - boolean result = simplifyOp.isSimpleAsFeature(poly, sr4326, false, - null, null); - assertTrue(!result); - } - - @Test - public void testIsSimplePolygonDegenerateTriangle() { - // Degenerate triangle (self overlap) - Polygon poly = new Polygon(); - poly.startPath(0, 0); - poly.lineTo(100, 100); - poly.lineTo(0, 0); - boolean result = simplifyOp.isSimpleAsFeature(poly, sr4326, false, - null, null); - assertTrue(!result); - } - - @Test - public void testIsSimplePolygonSelfIntersect() { - // Self intersection - cracking is needed - Polygon poly = new Polygon(); - poly.startPath(0, 0); - poly.lineTo(100, 100); - poly.lineTo(0, 100); - poly.lineTo(100, 0); - boolean result = simplifyOp.isSimpleAsFeature(poly, sr4326, false, - null, null); - assertTrue(!result); - } - - @Test - public void testIsSimplePolygonRectangleHole() { - // Rectangle and rectangular hole that has one segment overlapping - // with the with the exterior ring. Cracking is needed. - Polygon poly = new Polygon(); - poly.addEnvelope(new Envelope(-200, -100, 200, 100), false); - poly.addEnvelope(new Envelope(-100, -100, 100, 50), true); - boolean result = simplifyOp.isSimpleAsFeature(poly, sr4326, false, - null, null); - assertTrue(!result); - poly.reverseAllPaths(); - result = simplifyOp.isSimpleAsFeature(poly, sr4326, false, null, null); - assertTrue(!result); - } - - @Test - public void testIsSimplePolygonRectangleHole2() { - // Rectangle and rectangular hole - Polygon poly = new Polygon(); - poly.addEnvelope(new Envelope(-200, -100, 200, 100), false); - poly.addEnvelope(new Envelope(-100, -50, 100, 50), true); - boolean result = simplifyOp.isSimpleAsFeature(poly, sr4326, false, - null, null); - assertTrue(result); - poly.reverseAllPaths(); - result = simplifyOp.isSimpleAsFeature(poly, sr4326, false, null, null); - assertTrue(!result); - } - - @Test - public void testIsSimplePolygonSelfIntersectAtVertex() { - // Self intersection at vertex - Polygon poly = new Polygon(); - poly.startPath(0, 0); - poly.lineTo(50, 50); - poly.lineTo(100, 100); - poly.lineTo(0, 100); - poly.lineTo(50, 50); - poly.lineTo(100, 0); - boolean result = simplifyOp.isSimpleAsFeature(poly, sr4326, false, - null, null); - assertTrue(!result); - result = simplifyOp.isSimpleAsFeature( - simplifyOp.execute(poly, sr4326, false, null), sr4326, false, - null, null); - assertTrue(result); - } - - @Test - public void testIsSimplePolygon_2EdgesTouchAtVertex() { - // No self-intersection, but more than two edges touch at the same - // vertex. Simple for ArcGIS, not simple for OGC - Polygon poly = new Polygon(); - poly.startPath(0, 0); - poly.lineTo(50, 50); - poly.lineTo(0, 100); - poly.lineTo(100, 100); - poly.lineTo(50, 50); - poly.lineTo(100, 0); - boolean result = simplifyOp.isSimpleAsFeature(poly, sr4326, false, - null, null); - assertTrue(result); - } - - @Test - public void testIsSimplePolygonTriangle() { - // Triangle - Polygon poly = new Polygon(); - poly.startPath(0, 0); - poly.lineTo(100, 100); - poly.lineTo(100, 0); - boolean result = simplifyOp.isSimpleAsFeature(poly, sr4326, false, - null, null); - assertTrue(result); - poly.reverseAllPaths(); - result = simplifyOp.isSimpleAsFeature(poly, sr4326, false, null, null); - assertTrue(!result); - } - - @Test - public void testIsSimplePolygonRectangle() { - // Rectangle - Polygon poly = new Polygon(); - poly.addEnvelope(new Envelope(-200, -100, 100, 200), false); - boolean result = simplifyOp.isSimpleAsFeature(poly, sr4326, false, - null, null); - assertTrue(result); - poly.reverseAllPaths(); - result = simplifyOp.isSimpleAsFeature(poly, sr4326, false, null, null); - assertTrue(!result); - } - - @Test - public void testIsSimplePolygonRectangleHoleWrongDirection() { - // Rectangle and rectangular hole that has wrong direction - Polygon poly = new Polygon(); - poly.addEnvelope(new Envelope(-200, -100, 200, 100), false); - poly.addEnvelope(new Envelope(-100, -50, 100, 50), false); - boolean result = simplifyOp.isSimpleAsFeature(poly, sr4326, false, - null, null); - assertTrue(!result); - poly.reverseAllPaths(); - result = simplifyOp.isSimpleAsFeature(poly, sr4326, false, null, null); - assertTrue(!result); - } - - @Test - public void testIsSimplePolygon_2RectanglesSideBySide() { - // Two rectangles side by side, simple - Polygon poly = new Polygon(); - poly.addEnvelope(new Envelope(-200, -100, 200, 100), false); - poly.addEnvelope(new Envelope(220, -50, 300, 50), false); - boolean result = simplifyOp.isSimpleAsFeature(poly, sr4326, false, - null, null); - assertTrue(result); - poly.reverseAllPaths(); - result = simplifyOp.isSimpleAsFeature(poly, sr4326, false, null, null); - assertTrue(!result); - } - - @Test - public void testIsSimplePolygonRectangleOneBelow() { - // Two rectangles one below another, simple - Polygon poly = new Polygon(); - poly.addEnvelope(new Envelope(50, 50, 100, 100), false); - poly.addEnvelope(new Envelope(50, 200, 100, 250), false); - boolean result = simplifyOp.isSimpleAsFeature(poly, sr4326, false, - null, null); - assertTrue(result); - poly.reverseAllPaths(); - result = simplifyOp.isSimpleAsFeature(poly, sr4326, false, null, null); - assertTrue(!result); - } - - @Test - public void testisSimpleOGC() { - Polyline poly = new Polyline(); - poly.startPath(0, 0); - poly.lineTo(10, 0); - boolean result = simplifyOpOGC.isSimpleOGC(poly, sr4326, true, null, - null); - assertTrue(result); - - poly = new Polyline(); - poly.startPath(0, 0); - poly.lineTo(10, 10); - poly.lineTo(0, 10); - poly.lineTo(10, 0); - NonSimpleResult nsr = new NonSimpleResult(); - result = simplifyOpOGC.isSimpleOGC(poly, sr4326, true, nsr, null); - assertTrue(!result); - assertTrue(nsr.m_reason == NonSimpleResult.Reason.Cracking); - - MultiPoint mp = new MultiPoint(); - mp.add(0, 0); - mp.add(10, 0); - result = simplifyOpOGC.isSimpleOGC(mp, sr4326, true, null, null); - assertTrue(result); - - mp = new MultiPoint(); - mp.add(10, 0); - mp.add(10, 0); - nsr = new NonSimpleResult(); - result = simplifyOpOGC.isSimpleOGC(mp, sr4326, true, nsr, null); - assertTrue(!result); - assertTrue(nsr.m_reason == NonSimpleResult.Reason.Clustering); - } - - @Test - public void testPolylineIsSimpleForOGC() { - OperatorImportFromJson importerJson = (OperatorImportFromJson) factory - .getOperator(Operator.Type.ImportFromJson); - OperatorSimplify simplify = (OperatorSimplify) factory - .getOperator(Operator.Type.Simplify); - - { - String s = "{\"paths\":[[[0, 10], [8, 5], [5, 2], [6, 0]]]}"; - Geometry g = importerJson.execute(Geometry.Type.Unknown, - JsonParserReader.createFromString(s)).getGeometry(); - boolean res = simplifyOpOGC.isSimpleOGC(g, null, true, null, null); - assertTrue(res); - } - { - String s = "{\"paths\":[[[0, 10], [6, 0], [7, 5], [0, 3]]]}";// self - // intersection - Geometry g = importerJson.execute(Geometry.Type.Unknown, - JsonParserReader.createFromString(s)).getGeometry(); - boolean res = simplifyOpOGC.isSimpleOGC(g, null, true, null, null); - assertTrue(!res); - } - - { - String s = "{\"paths\":[[[0, 10], [6, 0], [0, 3], [0, 10]]]}"; // closed - Geometry g = importerJson.execute(Geometry.Type.Unknown, - JsonParserReader.createFromString(s)).getGeometry(); - boolean res = simplifyOpOGC.isSimpleOGC(g, null, true, null, null); - assertTrue(res); - } - - { - String s = "{\"paths\":[[[0, 10], [5, 5], [6, 0], [0, 3], [5, 5], [0, 9], [0, 10]]]}"; // closed - // with - // self - // tangent - Geometry g = importerJson.execute(Geometry.Type.Unknown, - JsonParserReader.createFromString(s)).getGeometry(); - boolean res = simplifyOpOGC.isSimpleOGC(g, null, true, null, null); - assertTrue(!res); - } - - { - String s = "{\"paths\":[[[0, 10], [5, 2]], [[5, 2], [6, 0]]]}";// two - // paths - // connected - // at - // a - // point - Geometry g = importerJson.execute(Geometry.Type.Unknown, - JsonParserReader.createFromString(s)).getGeometry(); - boolean res = simplifyOpOGC.isSimpleOGC(g, null, true, null, null); - assertTrue(res); - } - - { - String s = "{\"paths\":[[[0, 0], [3, 3], [5, 0], [0, 0]], [[0, 10], [3, 3], [10, 10], [0, 10]]]}";// two - // closed - // rings - // touch - // at - // one - // point - Geometry g = importerJson.execute(Geometry.Type.Unknown, - JsonParserReader.createFromString(s)).getGeometry(); - boolean res = simplifyOpOGC.isSimpleOGC(g, null, true, null, null); - assertTrue(!res); - } - - { - String s = "{\"paths\":[[[0, 0], [10, 10]], [[0, 10], [10, 0]]]}";// two - // lines - // intersect - Geometry g = importerJson.execute(Geometry.Type.Unknown, - JsonParserReader.createFromString(s)).getGeometry(); - boolean res = simplifyOpOGC.isSimpleOGC(g, null, true, null, null); - assertTrue(!res); - } - - { - String s = "{\"paths\":[[[0, 0], [5, 5], [0, 10]], [[10, 10], [5, 5], [10, 0]]]}";// two - // paths - // share - // mid - // point. - Geometry g = importerJson.execute(Geometry.Type.Unknown, - JsonParserReader.createFromString(s)).getGeometry(); - boolean res = simplifyOpOGC.isSimpleOGC(g, null, true, null, null); - assertTrue(!res); - } - - } - - @Test - public void testFillRule() { - //self intersecting star shape - MapGeometry mg = OperatorImportFromJson.local().execute(Geometry.Type.Unknown, "{\"rings\":[[[0,0], [5,10], [10, 0], [0, 7], [10, 7], [0, 0]]]}"); - Polygon poly = (Polygon) mg.getGeometry(); - assertTrue(poly.getFillRule() == Polygon.FillRule.enumFillRuleOddEven); - poly.setFillRule(Polygon.FillRule.enumFillRuleWinding); - assertTrue(poly.getFillRule() == Polygon.FillRule.enumFillRuleWinding); - Geometry simpleResult = OperatorSimplify.local().execute(poly, null, true, null); - assertTrue(((Polygon) simpleResult).getFillRule() == Polygon.FillRule.enumFillRuleOddEven); - //solid start without holes: - MapGeometry mg1 = OperatorImportFromJson.local().execute(Geometry.Type.Unknown, "{\"rings\":[[[0,0],[2.5925925925925926,5.185185185185185],[0,7],[3.5,7],[5,10],[6.5,7],[10,7],[7.407407407407407,5.185185185185185],[10,0],[5,3.5],[0,0]]]}"); - boolean equals = OperatorEquals.local().execute(mg1.getGeometry(), simpleResult, null, null); - assertTrue(equals); - } + public Polygon makeNonSimplePolygon3() { + Polygon poly = new Polygon(); + poly.startPath(0, 0); + poly.lineTo(0, 25); + poly.lineTo(35, 25); + poly.lineTo(35, 0); + + poly.startPath(5, 5); + poly.lineTo(5, 15); + poly.lineTo(10, 15); + poly.lineTo(10, 5); + + poly.startPath(40, 0); + poly.lineTo(45, 0); + poly.lineTo(45, 5); + poly.lineTo(40, 5); + + poly.startPath(20, 10); + poly.lineTo(25, 10); + poly.lineTo(25, 15); + poly.lineTo(20, 15); + + poly.startPath(15, 5); + poly.lineTo(15, 20); + poly.lineTo(30, 20); + poly.lineTo(30, 5); + + return poly; + }// done + + public Polygon makeNonSimplePolygon4() { + Polygon poly = new Polygon(); + poly.startPath(0, 0); + poly.lineTo(0, 10); + poly.lineTo(10, 10); + poly.lineTo(10, 0); + poly.lineTo(5, 0); + poly.lineTo(5, 5); + poly.lineTo(5, 0); + + return poly; + }// done + + public Polygon makeNonSimplePolygon6() { + Polygon poly = new Polygon(); + poly.startPath(35.34407570857744, 54.00551247713412); + poly.lineTo(41.07663499357954, 20.0); + poly.lineTo(40.66372033705177, 26.217432321849017); + + poly.startPath(42.81936574509338, 20.0); + poly.lineTo(43.58226670584747, 20.0); + poly.lineTo(39.29611825817084, 22.64634933678729); + poly.lineTo(44.369873312241346, 25.81893670527215); + poly.lineTo(42.68845660737179, 20.0); + poly.lineTo(38.569549792944244, 56.47456192829393); + poly.lineTo(42.79274114188401, 45.45117792578003); + poly.lineTo(41.09512147544657, 70.0); + + return poly; + } + + public Polygon makeNonSimplePolygon7() { + Polygon poly = new Polygon(); + + poly.startPath(41.987895433319686, 53.75822619011542); + poly.lineTo(41.98789542535497, 53.75822618803151); + poly.lineTo(40.15120412113667, 68.12604154722113); + poly.lineTo(37.72272697311022, 67.92767094118877); + poly.lineTo(37.147347454283086, 49.497473094145505); + poly.lineTo(38.636627026664385, 51.036687142232736); + + poly.startPath(39.00920080789793, 62.063425518369016); + poly.lineTo(38.604912643136885, 70.0); + poly.lineTo(40.71826863485308, 43.60337143116787); + poly.lineTo(35.34407570857744, 54.005512477134126); + poly.lineTo(39.29611825817084, 22.64634933678729); + + return poly; + } + + public Polyline makeNonSimplePolyline() { + // This polyline has a short segment + Polyline poly = new Polyline(); + poly.startPath(0, 0); + poly.lineTo(10, 0); + poly.lineTo(10, 10); + poly.lineTo(10, 5); + poly.lineTo(-5, 5); + + return poly; + }// done + + @Test + public void testIsSimpleBasicsPoint() { + boolean result; + // point is always simple + Point pt = new Point(); + result = simplifyOp.isSimpleAsFeature(pt, sr4326, false, null, null); + assertTrue(result); + pt.setXY(0, 0); + result = simplifyOp.isSimpleAsFeature(pt, sr4326, false, null, null); + assertTrue(result); + pt.setXY(100000, 10000); + result = simplifyOp.isSimpleAsFeature(pt, sr4326, false, null, null); + assertTrue(result); + }// done + + @Test + public void testIsSimpleBasicsEnvelope() { + // Envelope is simple, when it's width and height are not degenerate + Envelope env = new Envelope(); + boolean result = simplifyOp.isSimpleAsFeature(env, sr4326, false, null, + null); // Empty is simple + assertTrue(result); + env.setCoords(0, 0, 10, 10); + result = simplifyOp.isSimpleAsFeature(env, sr4326, false, null, null); + assertTrue(result); + // sliver but still simple + env.setCoords(0, 0, 0 + sr4326.getTolerance() * 2, 10); + result = simplifyOp.isSimpleAsFeature(env, sr4326, false, null, null); + assertTrue(result); + // sliver and not simple + env.setCoords(0, 0, 0 + sr4326.getTolerance() * 0.5, 10); + result = simplifyOp.isSimpleAsFeature(env, sr4326, false, null, null); + assertTrue(!result); + }// done + + @Test + public void testIsSimpleBasicsLine() { + Line line = new Line(); + boolean result = simplifyOp.isSimpleAsFeature(line, sr4326, false, + null, null); + assertTrue(!result); + + line.setStart(new Point(0, 0)); + // line.setEndXY(0, 0); + result = simplifyOp.isSimpleAsFeature(line, sr4326, false, null, null); + assertTrue(!result); + line.setEnd(new Point(1, 0)); + result = simplifyOp.isSimpleAsFeature(line, sr4326, false, null, null); + assertTrue(result); + }// done + + @Test + public void testIsSimpleMultiPoint1() { + MultiPoint mp = new MultiPoint(); + boolean result = simplifyOp.isSimpleAsFeature(mp, sr4326, false, null, + null); + assertTrue(result);// empty is simple + result = simplifyOp.isSimpleAsFeature( + simplifyOp.execute(mp, sr4326, false, null), sr4326, false, + null, null); + assertTrue(result); + }// done + + @Test + public void testIsSimpleMultiPoint2FarApart() { + // Two point test: far apart + MultiPoint mp = new MultiPoint(); + mp.add(20, 10); + mp.add(100, 100); + boolean result = simplifyOp.isSimpleAsFeature(mp, sr4326, false, null, + null); + assertTrue(result); + result = simplifyOp.isSimpleAsFeature( + simplifyOp.execute(mp, sr4326, false, null), sr4326, false, + null, null); + assertTrue(result); + assertTrue(mp.getPointCount() == 2); + }// done + + @Test + public void testIsSimpleMultiPointCoincident() { + // Two point test: coincident + MultiPoint mp = new MultiPoint(); + mp.add(100, 100); + mp.add(100, 100); + boolean result = simplifyOp.isSimpleAsFeature(mp, sr4326, false, null, + null); + assertTrue(!result); + MultiPoint mpS; + result = simplifyOp.isSimpleAsFeature( + mpS = (MultiPoint) simplifyOp.execute(mp, sr4326, false, null), + sr4326, false, null, null); + assertTrue(result); + assertTrue(mpS.getPointCount() == 1); + }// done + + @Test + public void testMultiPointSR4326_CR184439() { + OperatorFactoryLocal engine = OperatorFactoryLocal.getInstance(); + OperatorSimplify simpOp = (OperatorSimplify) engine + .getOperator(Operator.Type.Simplify); + NonSimpleResult nonSimpResult = new NonSimpleResult(); + nonSimpResult.m_reason = NonSimpleResult.Reason.NotDetermined; + MultiPoint multiPoint = new MultiPoint(); + multiPoint.add(0, 0); + multiPoint.add(0, 1); + multiPoint.add(0, 0); + Boolean multiPointIsSimple = simpOp.isSimpleAsFeature(multiPoint, + SpatialReference.create(4326), true, nonSimpResult, null); + assertFalse(multiPointIsSimple); + assertTrue(nonSimpResult.m_reason == NonSimpleResult.Reason.Clustering); + assertTrue(nonSimpResult.m_vertexIndex1 == 0); + assertTrue(nonSimpResult.m_vertexIndex2 == 2); + } + + @Test + public void testIsSimpleMultiPointCloserThanTolerance() { + // Two point test: closer than tolerance + MultiPoint mp = new MultiPoint(); + MultiPoint mpS; + mp.add(100, 100); + mp.add(100, 100 + sr4326.getTolerance() * .5); + boolean result = simplifyOp.isSimpleAsFeature(mp, sr4326, false, null, + null); + assertTrue(result); + result = simplifyOp.isSimpleAsFeature( + mpS = (MultiPoint) simplifyOp.execute(mp, sr4326, false, null), + sr4326, false, null, null); + assertTrue(result); + assertTrue(mpS.getPointCount() == 2); + }// done + + @Test + public void testIsSimpleMultiPointFarApart2() { + // 5 point test: far apart + MultiPoint mp = new MultiPoint(); + mp.add(100, 100); + mp.add(100, 101); + mp.add(101, 101); + mp.add(11, 1); + mp.add(11, 14); + MultiPoint mpS; + boolean result = simplifyOp.isSimpleAsFeature(mp, sr4326, false, null, + null); + assertTrue(result); + result = simplifyOp.isSimpleAsFeature( + mpS = (MultiPoint) simplifyOp.execute(mp, sr4326, false, null), + sr4326, false, null, null); + assertTrue(result); + assertTrue(mpS.getPointCount() == 5); + }// done + + @Test + public void testIsSimpleMultiPoint_coincident2() { + // 5 point test: coincident + MultiPoint mp = new MultiPoint(); + mp.add(100, 100); + mp.add(100, 101); + mp.add(100, 100); + mp.add(11, 1); + mp.add(11, 14); + boolean result = simplifyOp.isSimpleAsFeature(mp, sr4326, false, null, + null); + assertTrue(!result); + MultiPoint mpS; + result = simplifyOp.isSimpleAsFeature( + mpS = (MultiPoint) simplifyOp.execute(mp, sr4326, false, null), + sr4326, false, null, null); + assertTrue(result); + assertTrue(mpS.getPointCount() == 4); + assertEquals(mpS.getPoint(0).getX(), 100, 1e-7); + assertEquals(mpS.getPoint(0).getY(), 100, 1e-7); + assertEquals(mpS.getPoint(1).getX(), 100, 1e-7); + assertEquals(mpS.getPoint(1).getY(), 101, 1e-7); + assertEquals(mpS.getPoint(2).getX(), 11, 1e-7); + assertEquals(mpS.getPoint(2).getY(), 1, 1e-7); + assertEquals(mpS.getPoint(3).getX(), 11, 1e-7); + assertEquals(mpS.getPoint(3).getY(), 14, 1e-7); + }// done + + @Test + public void testIsSimpleMultiPointCloserThanTolerance2() { + // 5 point test: closer than tolerance + MultiPoint mp = new MultiPoint(); + mp.add(100, 100); + mp.add(100, 101); + mp.add(100, 100 + sr4326.getTolerance() / 2); + mp.add(11, 1); + mp.add(11, 14); + MultiPoint mpS; + boolean result = simplifyOp.isSimpleAsFeature(mp, sr4326, false, null, + null); + assertTrue(result); + result = simplifyOp.isSimpleAsFeature( + mpS = (MultiPoint) simplifyOp.execute(mp, sr4326, false, null), + sr4326, false, null, null); + assertTrue(result); + assertTrue(mpS.getPointCount() == 5); + }// done + + @Test + public void testIsSimplePolyline() { + Polyline poly = new Polyline(); + boolean result = simplifyOp.isSimpleAsFeature(poly, sr4326, false, + null, null); + assertTrue(result);// empty is simple + } + + @Test + public void testIsSimplePolylineFarApart() { + // Two point test: far apart + Polyline poly = new Polyline(); + poly.startPath(20, 10); + poly.lineTo(100, 100); + boolean result = simplifyOp.isSimpleAsFeature(poly, sr4326, false, + null, null); + assertTrue(result); + } + + @Test + public void testIsSimplePolylineCoincident() { + // Two point test: coincident + Polyline poly = new Polyline(); + poly.startPath(100, 100); + poly.lineTo(100, 100); + boolean result = simplifyOp.isSimpleAsFeature(poly, sr4326, false, + null, null); + assertTrue(!result); + @SuppressWarnings("unused") + Polyline polyS; + result = simplifyOp.isSimpleAsFeature( + polyS = (Polyline) simplifyOp + .execute(poly, sr4326, false, null), sr4326, false, + null, null); + assertTrue(result); + } + + @Test + public void testIsSimplePolylineCloserThanTolerance() { + // Two point test: closer than tolerance + Polyline poly = new Polyline(); + poly.startPath(100, 100); + poly.lineTo(100, 100 + sr4326.getTolerance() / 2); + boolean result = simplifyOp.isSimpleAsFeature(poly, sr4326, false, + null, null); + assertTrue(!result); + @SuppressWarnings("unused") + Polyline polyS; + result = simplifyOp.isSimpleAsFeature( + polyS = (Polyline) simplifyOp + .execute(poly, sr4326, false, null), sr4326, false, + null, null); + assertTrue(result); + } + + @Test + public void testIsSimplePolylineFarApartSelfOverlap0() { + // 3 point test: far apart, self overlapping + Polyline poly = new Polyline(); + poly.startPath(0, 0); + poly.lineTo(100, 100); + poly.lineTo(0, 0); + boolean result = simplifyOp.isSimpleAsFeature(poly, sr4326, false, + null, null); + assertTrue(result);// TO CONFIRM should be false + } + + @Test + public void testIsSimplePolylineSelfIntersect() { + // 4 point test: far apart, self intersecting + Polyline poly = new Polyline(); + poly.startPath(0, 0); + poly.lineTo(100, 100); + poly.lineTo(0, 100); + poly.lineTo(100, 0); + boolean result = simplifyOp.isSimpleAsFeature(poly, sr4326, false, + null, null); + assertTrue(result);// TO CONFIRM should be false + } + + @Test + public void testIsSimplePolylineDegenerateSegment() { + // 4 point test: degenerate segment + Polyline poly = new Polyline(); + poly.startPath(0, 0); + poly.lineTo(100, 100); + poly.lineTo(100, 100 + sr4326.getTolerance() / 2); + poly.lineTo(100, 0); + boolean result = simplifyOp.isSimpleAsFeature(poly, sr4326, false, + null, null); + assertTrue(!result); + @SuppressWarnings("unused") + Polyline polyS; + result = simplifyOp.isSimpleAsFeature( + polyS = (Polyline) simplifyOp + .execute(poly, sr4326, false, null), sr4326, false, + null, null); + assertTrue(result); + { + Polyline other = new Polyline(); + other.startPath(0, 0); + other.lineTo(100, 100); + other.lineTo(100, 0); + other.equals(poly); + } + } + + @Test + public void testIsSimplePolylineFarApartSelfOverlap() { + // 3 point test: far apart, self overlapping + Polyline poly = new Polyline(); + poly.startPath(0, 0); + poly.lineTo(100, 100); + poly.lineTo(0, 0); + boolean result = simplifyOp.isSimpleAsFeature(poly, sr4326, false, + null, null); + assertTrue(result);// TO CONFIRM should be false + } + + @Test + public void testIsSimplePolylineFarApartIntersect() { + // 4 point 2 parts test: far apart, intersecting parts + Polyline poly = new Polyline(); + poly.startPath(0, 0); + poly.lineTo(100, 100); + poly.startPath(100, 0); + poly.lineTo(0, 100); + + boolean result = simplifyOp.isSimpleAsFeature(poly, sr4326, false, + null, null); + assertTrue(result);// TO CONFIRM should be false + } + + @Test + public void testIsSimplePolylineFarApartOverlap2() { + // 4 point 2 parts test: far apart, overlapping parts. second part + // starts where first one ends + Polyline poly = new Polyline(); + poly.startPath(0, 0); + poly.lineTo(100, 100); + poly.startPath(100, 100); + poly.lineTo(0, 100); + + boolean result = simplifyOp.isSimpleAsFeature(poly, sr4326, false, + null, null); + assertTrue(result);// TO CONFIRM should be false + } + + @Test + public void testIsSimplePolylineDegenerateVertical() { + // 3 point test: degenerate vertical line + Polyline poly = new Polyline(); + poly.startPath(0, 0); + poly.lineTo(new Point(100, 100)); + poly.lineTo(new Point(100, 100)); + boolean result = simplifyOp.isSimpleAsFeature(poly, sr4326, false, + null, null); + assertTrue(!result); + Polyline polyS; + result = simplifyOp.isSimpleAsFeature( + polyS = (Polyline) simplifyOp + .execute(poly, sr4326, false, null), sr4326, false, + null, null); + assertTrue(result); + assertTrue(polyS.getPointCount() == 2); + } + + @Test + public void testIsSimplePolylineEmptyPath() { + // TODO: any way to test this? + // Empty path + // Polyline poly = new Polyline(); + // assertTrue(poly.isEmpty()); + // poly.addPath(new Polyline(), 0, true); + // assertTrue(poly.isEmpty()); + // boolean result = simplifyOp.isSimpleAsFeature(poly, sr4326, false, + // null, null); + // assertTrue(result); + } + + @Test + public void testIsSimplePolylineSinglePointInPath() { + // Single point in path + Polyline poly = new Polyline(); + poly.startPath(0, 0); + poly.lineTo(100, 100); + poly.removePoint(0, 1); + boolean result = simplifyOp.isSimpleAsFeature(poly, sr4326, false, + null, null); + assertTrue(!result); + Polyline polyS; + result = simplifyOp.isSimpleAsFeature( + polyS = (Polyline) simplifyOp + .execute(poly, sr4326, false, null), sr4326, false, + null, null); + assertTrue(result); + assertTrue(polyS.isEmpty()); + } + + @Test + public void testIsSimplePolygon() { + Polygon poly = new Polygon(); + boolean result = simplifyOp.isSimpleAsFeature(poly, sr4326, false, + null, null); + assertTrue(result);// empty is simple + result = simplifyOp.isSimpleAsFeature( + simplifyOp.execute(poly, sr4326, false, null), sr4326, false, + null, null); + assertTrue(result);// empty is simple + } + + @Test + public void testIsSimplePolygonEmptyPath() { + // TODO: + // Empty path + // Polygon poly = new Polygon(); + // poly.addPath(new Polyline(), 0, true); + // assertTrue(poly.getPathCount() == 1); + // boolean result = simplifyOp.isSimpleAsFeature(poly, sr4326, false, + // null, + // null); + // assertTrue(result); + // result = simplifyOp.isSimpleAsFeature(simplifyOp.execute(poly, + // sr4326, false, null), sr4326, false, null, null); + // assertTrue(result);// empty is simple + // assertTrue(poly.getPathCount() == 1); + } + + @Test + public void testIsSimplePolygonIncomplete1() { + // Incomplete polygon 1 + Polygon poly = new Polygon(); + poly.startPath(0, 0); + poly.lineTo(100, 100); + // poly.removePoint(0, 1);//TO CONFIRM no removePoint method in Java + boolean result = simplifyOp.isSimpleAsFeature(poly, sr4326, false, + null, null); + assertTrue(!result); + } + + @Test + public void testIsSimplePolygonIncomplete2() { + // Incomplete polygon 2 + Polygon poly = new Polygon(); + poly.startPath(0, 0); + poly.lineTo(100, 100); + boolean result = simplifyOp.isSimpleAsFeature(poly, sr4326, false, + null, null); + assertTrue(!result); + } + + @Test + public void testIsSimplePolygonDegenerateTriangle() { + // Degenerate triangle (self overlap) + Polygon poly = new Polygon(); + poly.startPath(0, 0); + poly.lineTo(100, 100); + poly.lineTo(0, 0); + boolean result = simplifyOp.isSimpleAsFeature(poly, sr4326, false, + null, null); + assertTrue(!result); + } + + @Test + public void testIsSimplePolygonSelfIntersect() { + // Self intersection - cracking is needed + Polygon poly = new Polygon(); + poly.startPath(0, 0); + poly.lineTo(100, 100); + poly.lineTo(0, 100); + poly.lineTo(100, 0); + boolean result = simplifyOp.isSimpleAsFeature(poly, sr4326, false, + null, null); + assertTrue(!result); + } + + @Test + public void testIsSimplePolygonRectangleHole() { + // Rectangle and rectangular hole that has one segment overlapping + // with the with the exterior ring. Cracking is needed. + Polygon poly = new Polygon(); + poly.addEnvelope(new Envelope(-200, -100, 200, 100), false); + poly.addEnvelope(new Envelope(-100, -100, 100, 50), true); + boolean result = simplifyOp.isSimpleAsFeature(poly, sr4326, false, + null, null); + assertTrue(!result); + poly.reverseAllPaths(); + result = simplifyOp.isSimpleAsFeature(poly, sr4326, false, null, null); + assertTrue(!result); + } + + @Test + public void testIsSimplePolygonRectangleHole2() { + // Rectangle and rectangular hole + Polygon poly = new Polygon(); + poly.addEnvelope(new Envelope(-200, -100, 200, 100), false); + poly.addEnvelope(new Envelope(-100, -50, 100, 50), true); + boolean result = simplifyOp.isSimpleAsFeature(poly, sr4326, false, + null, null); + assertTrue(result); + poly.reverseAllPaths(); + result = simplifyOp.isSimpleAsFeature(poly, sr4326, false, null, null); + assertTrue(!result); + } + + @Test + public void testIsSimplePolygonSelfIntersectAtVertex() { + // Self intersection at vertex + Polygon poly = new Polygon(); + poly.startPath(0, 0); + poly.lineTo(50, 50); + poly.lineTo(100, 100); + poly.lineTo(0, 100); + poly.lineTo(50, 50); + poly.lineTo(100, 0); + boolean result = simplifyOp.isSimpleAsFeature(poly, sr4326, false, + null, null); + assertTrue(!result); + result = simplifyOp.isSimpleAsFeature( + simplifyOp.execute(poly, sr4326, false, null), sr4326, false, + null, null); + assertTrue(result); + } + + @Test + public void testIsSimplePolygon_2EdgesTouchAtVertex() { + // No self-intersection, but more than two edges touch at the same + // vertex. Simple for ArcGIS, not simple for OGC + Polygon poly = new Polygon(); + poly.startPath(0, 0); + poly.lineTo(50, 50); + poly.lineTo(0, 100); + poly.lineTo(100, 100); + poly.lineTo(50, 50); + poly.lineTo(100, 0); + boolean result = simplifyOp.isSimpleAsFeature(poly, sr4326, false, + null, null); + assertTrue(result); + } + + @Test + public void testIsSimplePolygonTriangle() { + // Triangle + Polygon poly = new Polygon(); + poly.startPath(0, 0); + poly.lineTo(100, 100); + poly.lineTo(100, 0); + boolean result = simplifyOp.isSimpleAsFeature(poly, sr4326, false, + null, null); + assertTrue(result); + poly.reverseAllPaths(); + result = simplifyOp.isSimpleAsFeature(poly, sr4326, false, null, null); + assertTrue(!result); + } + + @Test + public void testIsSimplePolygonRectangle() { + // Rectangle + Polygon poly = new Polygon(); + poly.addEnvelope(new Envelope(-200, -100, 100, 200), false); + boolean result = simplifyOp.isSimpleAsFeature(poly, sr4326, false, + null, null); + assertTrue(result); + poly.reverseAllPaths(); + result = simplifyOp.isSimpleAsFeature(poly, sr4326, false, null, null); + assertTrue(!result); + } + + @Test + public void testIsSimplePolygonRectangleHoleWrongDirection() { + // Rectangle and rectangular hole that has wrong direction + Polygon poly = new Polygon(); + poly.addEnvelope(new Envelope(-200, -100, 200, 100), false); + poly.addEnvelope(new Envelope(-100, -50, 100, 50), false); + boolean result = simplifyOp.isSimpleAsFeature(poly, sr4326, false, + null, null); + assertTrue(!result); + poly.reverseAllPaths(); + result = simplifyOp.isSimpleAsFeature(poly, sr4326, false, null, null); + assertTrue(!result); + } + + @Test + public void testIsSimplePolygon_2RectanglesSideBySide() { + // Two rectangles side by side, simple + Polygon poly = new Polygon(); + poly.addEnvelope(new Envelope(-200, -100, 200, 100), false); + poly.addEnvelope(new Envelope(220, -50, 300, 50), false); + boolean result = simplifyOp.isSimpleAsFeature(poly, sr4326, false, + null, null); + assertTrue(result); + poly.reverseAllPaths(); + result = simplifyOp.isSimpleAsFeature(poly, sr4326, false, null, null); + assertTrue(!result); + } + + @Test + public void testIsSimplePolygonRectangleOneBelow() { + // Two rectangles one below another, simple + Polygon poly = new Polygon(); + poly.addEnvelope(new Envelope(50, 50, 100, 100), false); + poly.addEnvelope(new Envelope(50, 200, 100, 250), false); + boolean result = simplifyOp.isSimpleAsFeature(poly, sr4326, false, + null, null); + assertTrue(result); + poly.reverseAllPaths(); + result = simplifyOp.isSimpleAsFeature(poly, sr4326, false, null, null); + assertTrue(!result); + } + + @Test + public void testisSimpleOGC() { + Polyline poly = new Polyline(); + poly.startPath(0, 0); + poly.lineTo(10, 0); + boolean result = simplifyOpOGC.isSimpleOGC(poly, sr4326, true, null, + null); + assertTrue(result); + + poly = new Polyline(); + poly.startPath(0, 0); + poly.lineTo(10, 10); + poly.lineTo(0, 10); + poly.lineTo(10, 0); + NonSimpleResult nsr = new NonSimpleResult(); + result = simplifyOpOGC.isSimpleOGC(poly, sr4326, true, nsr, null); + assertTrue(!result); + assertTrue(nsr.m_reason == NonSimpleResult.Reason.Cracking); + + MultiPoint mp = new MultiPoint(); + mp.add(0, 0); + mp.add(10, 0); + result = simplifyOpOGC.isSimpleOGC(mp, sr4326, true, null, null); + assertTrue(result); + + mp = new MultiPoint(); + mp.add(10, 0); + mp.add(10, 0); + nsr = new NonSimpleResult(); + result = simplifyOpOGC.isSimpleOGC(mp, sr4326, true, nsr, null); + assertTrue(!result); + assertTrue(nsr.m_reason == NonSimpleResult.Reason.Clustering); + } + + @Test + public void testPolylineIsSimpleForOGC() { + OperatorImportFromJson importerJson = (OperatorImportFromJson) factory + .getOperator(Operator.Type.ImportFromJson); + OperatorSimplify simplify = (OperatorSimplify) factory + .getOperator(Operator.Type.Simplify); + + { + String s = "{\"paths\":[[[0, 10], [8, 5], [5, 2], [6, 0]]]}"; + Geometry g = importerJson.execute(Geometry.Type.Unknown, + JsonParserReader.createFromString(s)).getGeometry(); + boolean res = simplifyOpOGC.isSimpleOGC(g, null, true, null, null); + assertTrue(res); + } + { + String s = "{\"paths\":[[[0, 10], [6, 0], [7, 5], [0, 3]]]}";// self + // intersection + Geometry g = importerJson.execute(Geometry.Type.Unknown, + JsonParserReader.createFromString(s)).getGeometry(); + boolean res = simplifyOpOGC.isSimpleOGC(g, null, true, null, null); + assertTrue(!res); + } + + { + String s = "{\"paths\":[[[0, 10], [6, 0], [0, 3], [0, 10]]]}"; // closed + Geometry g = importerJson.execute(Geometry.Type.Unknown, + JsonParserReader.createFromString(s)).getGeometry(); + boolean res = simplifyOpOGC.isSimpleOGC(g, null, true, null, null); + assertTrue(res); + } + + { + String s = "{\"paths\":[[[0, 10], [5, 5], [6, 0], [0, 3], [5, 5], [0, 9], [0, 10]]]}"; // closed + // with + // self + // tangent + Geometry g = importerJson.execute(Geometry.Type.Unknown, + JsonParserReader.createFromString(s)).getGeometry(); + boolean res = simplifyOpOGC.isSimpleOGC(g, null, true, null, null); + assertTrue(!res); + } + + { + String s = "{\"paths\":[[[0, 10], [5, 2]], [[5, 2], [6, 0]]]}";// two + // paths + // connected + // at + // a + // point + Geometry g = importerJson.execute(Geometry.Type.Unknown, + JsonParserReader.createFromString(s)).getGeometry(); + boolean res = simplifyOpOGC.isSimpleOGC(g, null, true, null, null); + assertTrue(res); + } + + { + String s = "{\"paths\":[[[0, 0], [3, 3], [5, 0], [0, 0]], [[0, 10], [3, 3], [10, 10], [0, 10]]]}";// two + // closed + // rings + // touch + // at + // one + // point + Geometry g = importerJson.execute(Geometry.Type.Unknown, + JsonParserReader.createFromString(s)).getGeometry(); + boolean res = simplifyOpOGC.isSimpleOGC(g, null, true, null, null); + assertTrue(!res); + } + + { + String s = "{\"paths\":[[[0, 0], [10, 10]], [[0, 10], [10, 0]]]}";// two + // lines + // intersect + Geometry g = importerJson.execute(Geometry.Type.Unknown, + JsonParserReader.createFromString(s)).getGeometry(); + boolean res = simplifyOpOGC.isSimpleOGC(g, null, true, null, null); + assertTrue(!res); + } + + { + String s = "{\"paths\":[[[0, 0], [5, 5], [0, 10]], [[10, 10], [5, 5], [10, 0]]]}";// two + // paths + // share + // mid + // point. + Geometry g = importerJson.execute(Geometry.Type.Unknown, + JsonParserReader.createFromString(s)).getGeometry(); + boolean res = simplifyOpOGC.isSimpleOGC(g, null, true, null, null); + assertTrue(!res); + } + + } + + @Test + public void testFillRule() { + //self intersecting star shape + MapGeometry mg = OperatorImportFromJson.local().execute(Geometry.Type.Unknown, "{\"rings\":[[[0,0], [5,10], [10, 0], [0, 7], [10, 7], [0, 0]]]}"); + Polygon poly = (Polygon) mg.getGeometry(); + assertTrue(poly.getFillRule() == Polygon.FillRule.enumFillRuleOddEven); + poly.setFillRule(Polygon.FillRule.enumFillRuleWinding); + assertTrue(poly.getFillRule() == Polygon.FillRule.enumFillRuleWinding); + Geometry simpleResult = OperatorSimplify.local().execute(poly, null, true, null); + assertTrue(((Polygon) simpleResult).getFillRule() == Polygon.FillRule.enumFillRuleOddEven); + //solid start without holes: + MapGeometry mg1 = OperatorImportFromJson.local().execute(Geometry.Type.Unknown, "{\"rings\":[[[0,0],[2.5925925925925926,5.185185185185185],[0,7],[3.5,7],[5,10],[6.5,7],[10,7],[7.407407407407407,5.185185185185185],[10,0],[5,3.5],[0,0]]]}"); + boolean equals = OperatorEquals.local().execute(mg1.getGeometry(), simpleResult, null, null); + assertTrue(equals); + } } diff --git a/src/test/java/com/esri/core/geometry/TestSpatialReference.java b/src/test/java/com/esri/core/geometry/TestSpatialReference.java index 8dbf13ea..a4170c00 100644 --- a/src/test/java/com/esri/core/geometry/TestSpatialReference.java +++ b/src/test/java/com/esri/core/geometry/TestSpatialReference.java @@ -31,201 +31,201 @@ import java.util.regex.Pattern; public class TestSpatialReference extends TestCase { - @Test - public void testEquals() { - String wktext1 = "GEOGCS[\"GCS_WGS_1984\",DATUM[\"D_WGS_1984\",SPHEROID[\"WGS_1984\",6378137.0,298.257223563]],PRIMEM[\"Greenwich\",0.0],UNIT[\"Degree\",0.0174532925199433]]"; - String wktext2 = "PROJCS[\"WGS_1984_Web_Mercator_Auxiliary_Sphere\",GEOGCS[\"GCS_WGS_1984\",DATUM[\"D_WGS_1984\",SPHEROID[\"WGS_1984\",6378137.0,298.257223563]],PRIMEM[\"Greenwich\",0.0],UNIT[\"Degree\",0.0174532925199433]],PROJECTION[\"Mercator_Auxiliary_Sphere\"],PARAMETER[\"False_Easting\",0.0],PARAMETER[\"False_Northing\",0.0],PARAMETER[\"Central_Meridian\",0.0],PARAMETER[\"Standard_Parallel_1\",0.0],PARAMETER[\"Auxiliary_Sphere_Type\",0.0],UNIT[\"Meter\",1.0]]"; - String proj4 = "+proj=utm +zone=30 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs "; - SpatialReference a1 = SpatialReference.create(wktext1); - SpatialReference b = SpatialReference.create(wktext2); - SpatialReference a2 = SpatialReference.create(wktext1); - SpatialReference c = SpatialReference.createFromProj4(proj4); - - assertTrue(a1.equals(a1)); - assertTrue(b.equals(b)); - - assertTrue(a1.equals(a2)); - - assertFalse(a1.equals(b)); - assertFalse(b.equals(a1)); - - assertFalse(c.equals(a1)); - assertFalse(c.equals(b)); - } - - @Test - public void testTolerance() { - String wktWGS84 = "GEOGCS[\"WGS 84\",DATUM[\"WGS_1984\",SPHEROID[\"WGS 84\",6378137,298.257223563,AUTHORITY[\"EPSG\",\"7030\"]],AUTHORITY[\"EPSG\",\"6326\"]],PRIMEM[\"Greenwich\",0,AUTHORITY[\"EPSG\",\"8901\"]],UNIT[\"degree\",0.0174532925199433,AUTHORITY[\"EPSG\",\"9122\"]],AUTHORITY[\"EPSG\",\"4326\"]]"; - SpatialReference a1 = SpatialReference.create(wktWGS84); - SpatialReference a2 = SpatialReference.create(4326); - assertEquals(a1.getTolerance(), a2.getTolerance()); - } - - @Test - public void prjCreateFromProj4() { - double longitude = 0.0; - double latitude = 0.0; - String proj4 = String.format( - "+proj=laea +lat_0=%f +lon_0=%f +x_0=0.0 +y_0=0.0 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs", - longitude, latitude); - - SpatialReference spatialReference = SpatialReference.createFromProj4(proj4); - assertNotNull(spatialReference); - assertEquals(spatialReference.getProj4(), proj4); - } - - @Test - public void testWKTToWkid() { - String test1 = "GEOGCS[\"WGS 84\",DATUM[\"WGS_1984\",SPHEROID[\"WGS 84\",6378137,298.257223563,AUTHORITY[\"EPSG\",\"7030\"]],AUTHORITY[\"EPSG\",\"6326\"]],PRIMEM[\"Greenwich\",0,AUTHORITY[\"EPSG\",\"8901\"]],UNIT[\"degree\",0.0174532925199433,AUTHORITY[\"EPSG\",\"9122\"]],AUTHORITY[\"EPSG\",\"4326\"]]"; - Pattern pattern = Pattern.compile("^([\\w\\W]+AUTHORITY[\\s]*\\[[\\s]*\"EPSG\"[\\s]*,[\\s]*[\"]*([\\d]+)[\"]*]])$"); - Matcher matcher = pattern.matcher(test1); - - assertTrue(matcher.find()); - assertTrue(matcher.group(2).equals("4326")); - - SpatialReference spatialReference = SpatialReference.create(test1); - assertEquals(spatialReference.getID(), 4326); - assertNotNull(spatialReference.getProj4()); - assertNull(spatialReference.getText()); - - String test2 = "GEOGCS[\n" + - "\t\"WGS 84\",\n" + - "\tDATUM[\n" + - "\t\t\"WGS_1984\",\n" + - "\t\tSPHEROID[\n" + - "\t\t\t\"WGS 84\",\n" + - "\t\t\t6378137,\n" + - "\t\t\t298.257223563,\n" + - "\t\t\tAUTHORITY[\"EPSG\",\"7030\"]\n" + - "\t\t\t],\n" + - "\t\t\tAUTHORITY[\"EPSG\",\"6326\"]\n" + - "\t\t],\n" + - "\t\tPRIMEM[\n" + - "\t\t\t\"Greenwich\",\n" + - "\t\t\t0,\n" + - "\t\t\tAUTHORITY[\"EPSG\",\"8901\"]\n" + - "\t\t],\n" + - "\t\tUNIT[\n" + - "\t\t\t\"degree\",\n" + - "\t\t\t0.0174532925199433,\n" + - "\t\t\tAUTHORITY[\"EPSG\",\"9122\"]\n" + - "\t\t],\n" + - "\t\t\n" + - "\t\tAUTHORITY\n" + - "\n" + - "\t\t[\n" + - "\n" + - "\t\t\t\"EPSG\" ,\n" + - "\t\t\t\"4326\"\n" + - "\t\t\n" + - "\t\t]\n" + - "\n" + - "\t]"; - SpatialReference spatialReference2 = SpatialReference.create(test2); - assertEquals(spatialReference2.getID(), 4326); - assertNotNull(spatialReference2.getProj4()); - assertNull(spatialReference2.getText()); - - String test3 = "GEOGCS[\"WGS 84\",DATUM[\"WGS_1984\",SPHEROID[\"WGS 84\",6378137,298.257223563,AUTHORITY[\"EPSG\",\"7030\"]],AUTHORITY[\"EPSG\",\"6326\"]],PRIMEM[\"Greenwich\",0,AUTHORITY[\"EPSG\",\"8901\"]],UNIT[\"degree\",0.01745329251994328,AUTHORITY[\"EPSG\",\"9122\"]],AUTHORITY[\"EPSG\",\"4326\"]]"; - SpatialReference spatialReference3 = SpatialReference.create(test3); - assertEquals(spatialReference3.getID(), 4326); - assertNotNull(spatialReference3.getProj4()); - assertNull(spatialReference3.getText()); - - String test4 = "PROJCS[\"WGS 84 / UTM zone 17N\",\n" + - " GEOGCS[\"WGS 84\",\n" + - " DATUM[\"WGS_1984\",\n" + - " SPHEROID[\"WGS 84\",6378137,298.257223563,\n" + - " AUTHORITY[\"EPSG\",\"7030\"]],\n" + - " AUTHORITY[\"EPSG\",\"6326\"]],\n" + - " PRIMEM[\"Greenwich\",0,\n" + - " AUTHORITY[\"EPSG\",\"8901\"]],\n" + - " UNIT[\"degree\",0.0174532925199433,\n" + - " AUTHORITY[\"EPSG\",\"9122\"]],\n" + - " AUTHORITY[\"EPSG\",\"4326\"]],\n" + - " PROJECTION[\"Transverse_Mercator\"],\n" + - " PARAMETER[\"latitude_of_origin\",0],\n" + - " PARAMETER[\"central_meridian\",-81],\n" + - " PARAMETER[\"scale_factor\",0.9996],\n" + - " PARAMETER[\"false_easting\",500000],\n" + - " PARAMETER[\"false_northing\",0],\n" + - " UNIT[\"metre\",1,\n" + - " AUTHORITY[\"EPSG\",\"9001\"]],\n" + - " AXIS[\"Easting\",EAST],\n" + - " AXIS[\"Northing\",NORTH],\n" + - " AUTHORITY[\"EPSG\",\"32617\"]]\n" + - " "; - SpatialReference spatialReference4 = SpatialReference.create(test4); - assertEquals(spatialReference4.getID(), 32617); - assertNotNull(spatialReference4.getProj4()); - assertNull(spatialReference4.getText()); - - String customWKT = "PROJCS[\"Lo27_Cape\",GEOGCS[\"GCS_Cape\",DATUM[\"D_Cape\",SPHEROID[\"Clarke_1880_Arc\",6378249.145,293.466307656]],PRIMEM[\"Greenwich\",0.0],UNIT[\"Degree\",0.0174532925199433]],PROJECTION[\"Transverse_Mercator\"],PARAMETER[\"False_Easting\",0.0],PARAMETER[\"False_Northing\",0.0],PARAMETER[\"Central_Meridian\",27.0],PARAMETER[\"Scale_Factor\",1.0],PARAMETER[\"Latitude_Of_Origin\",0.0],UNIT[\"Meter\",1.0]]"; - SpatialReference spatialReference5 = SpatialReference.create(customWKT); - assertEquals(spatialReference5.getID(), 0); - assertNull(spatialReference5.getProj4()); - assertNotNull(spatialReference5.getText()); - } - - @Test - public void testProj4EPSG() { - String epsg = "+init=epsg:26711"; - SpatialReference spatialReference = SpatialReference.createFromProj4(epsg); - assertEquals(26711, spatialReference.getID()); - assertEquals(SpatialReference.CoordinateSystemType.PROJECTED, spatialReference.getCoordinateSystemType()); - - epsg = "+init=epsg:4326"; - spatialReference = SpatialReference.createFromProj4(epsg); - assertEquals(4326, spatialReference.getID()); - assertEquals(SpatialReference.CoordinateSystemType.GEOGRAPHIC, spatialReference.getCoordinateSystemType()); - - String test4 = "PROJCS[\"WGS 84 / UTM zone 17N\",\n" + - " GEOGCS[\"WGS 84\",\n" + - " DATUM[\"WGS_1984\",\n" + - " SPHEROID[\"WGS 84\",6378137,298.257223563,\n" + - " AUTHORITY[\"EPSG\",\"7030\"]],\n" + - " AUTHORITY[\"EPSG\",\"6326\"]],\n" + - " PRIMEM[\"Greenwich\",0,\n" + - " AUTHORITY[\"EPSG\",\"8901\"]],\n" + - " UNIT[\"degree\",0.0174532925199433,\n" + - " AUTHORITY[\"EPSG\",\"9122\"]],\n" + - " AUTHORITY[\"EPSG\",\"4326\"]],\n" + - " PROJECTION[\"Transverse_Mercator\"],\n" + - " PARAMETER[\"latitude_of_origin\",0],\n" + - " PARAMETER[\"central_meridian\",-81],\n" + - " PARAMETER[\"scale_factor\",0.9996],\n" + - " PARAMETER[\"false_easting\",500000],\n" + - " PARAMETER[\"false_northing\",0],\n" + - " UNIT[\"metre\",1,\n" + - " AUTHORITY[\"EPSG\",\"9001\"]],\n" + - " AXIS[\"Easting\",EAST],\n" + - " AXIS[\"Northing\",NORTH]]]\n" + - " "; - SpatialReference spatialReference4 = SpatialReference.create(test4); - assertEquals(SpatialReference.CoordinateSystemType.PROJECTED, spatialReference4.getCoordinateSystemType()); - - spatialReference = SpatialReference.createFromProj4("+proj=longlat +datum=WGS84 +no_defs "); - assertEquals(SpatialReference.CoordinateSystemType.GEOGRAPHIC, spatialReference.getCoordinateSystemType()); - } - - @Test - public void testProj9001() { - String tet5 = "PROJCS[\"NUTM30\",GEOGCS[\"ETRS89\",DATUM[\"European_Terrestrial_Reference_System_1989\",SPHEROID[\"GRS 1980\",6378137,298.2572221010042,AUTHORITY[\"EPSG\",\"7019\"]],AUTHORITY[\"EPSG\",\"6258\"]],PRIMEM[\"Greenwich\",0],UNIT[\"degree\",0.0174532925199433],AUTHORITY[\"EPSG\",\"4258\"]],PROJECTION[\"Transverse_Mercator\"],PARAMETER[\"latitude_of_origin\",0],PARAMETER[\"central_meridian\",-3],PARAMETER[\"scale_factor\",0.9996],PARAMETER[\"false_easting\",500000],PARAMETER[\"false_northing\",0],UNIT[\"metre\",1,AUTHORITY[\"EPSG\",\"9001\"]]]"; - String epsg = "+init=epsg:4326"; - SpatialReference spatialReference = SpatialReference.createFromProj4(epsg); - assertEquals(4326, spatialReference.getID()); - assertEquals(SpatialReference.CoordinateSystemType.GEOGRAPHIC, spatialReference.getCoordinateSystemType()); - - SpatialReference spatialReference1 = SpatialReference.create(tet5); - assertEquals(9001, spatialReference1.getID()); - assertEquals("+init=epsg:9001", spatialReference1.getProj4()); - } - - @Test - public void testProjEquality() { - SpatialReference spatialReference = SpatialReference.createFromProj4("+proj=utm +zone=30 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs "); - SpatialReference spatialReference2 = SpatialReference.createFromProj4("+proj=utm +zone=30 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs "); - assertEquals(spatialReference, spatialReference2); - } + @Test + public void testEquals() { + String wktext1 = "GEOGCS[\"GCS_WGS_1984\",DATUM[\"D_WGS_1984\",SPHEROID[\"WGS_1984\",6378137.0,298.257223563]],PRIMEM[\"Greenwich\",0.0],UNIT[\"Degree\",0.0174532925199433]]"; + String wktext2 = "PROJCS[\"WGS_1984_Web_Mercator_Auxiliary_Sphere\",GEOGCS[\"GCS_WGS_1984\",DATUM[\"D_WGS_1984\",SPHEROID[\"WGS_1984\",6378137.0,298.257223563]],PRIMEM[\"Greenwich\",0.0],UNIT[\"Degree\",0.0174532925199433]],PROJECTION[\"Mercator_Auxiliary_Sphere\"],PARAMETER[\"False_Easting\",0.0],PARAMETER[\"False_Northing\",0.0],PARAMETER[\"Central_Meridian\",0.0],PARAMETER[\"Standard_Parallel_1\",0.0],PARAMETER[\"Auxiliary_Sphere_Type\",0.0],UNIT[\"Meter\",1.0]]"; + String proj4 = "+proj=utm +zone=30 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs "; + SpatialReference a1 = SpatialReference.create(wktext1); + SpatialReference b = SpatialReference.create(wktext2); + SpatialReference a2 = SpatialReference.create(wktext1); + SpatialReference c = SpatialReference.createFromProj4(proj4); + + assertTrue(a1.equals(a1)); + assertTrue(b.equals(b)); + + assertTrue(a1.equals(a2)); + + assertFalse(a1.equals(b)); + assertFalse(b.equals(a1)); + + assertFalse(c.equals(a1)); + assertFalse(c.equals(b)); + } + + @Test + public void testTolerance() { + String wktWGS84 = "GEOGCS[\"WGS 84\",DATUM[\"WGS_1984\",SPHEROID[\"WGS 84\",6378137,298.257223563,AUTHORITY[\"EPSG\",\"7030\"]],AUTHORITY[\"EPSG\",\"6326\"]],PRIMEM[\"Greenwich\",0,AUTHORITY[\"EPSG\",\"8901\"]],UNIT[\"degree\",0.0174532925199433,AUTHORITY[\"EPSG\",\"9122\"]],AUTHORITY[\"EPSG\",\"4326\"]]"; + SpatialReference a1 = SpatialReference.create(wktWGS84); + SpatialReference a2 = SpatialReference.create(4326); + assertEquals(a1.getTolerance(), a2.getTolerance()); + } + + @Test + public void prjCreateFromProj4() { + double longitude = 0.0; + double latitude = 0.0; + String proj4 = String.format( + "+proj=laea +lat_0=%f +lon_0=%f +x_0=0.0 +y_0=0.0 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs", + longitude, latitude); + + SpatialReference spatialReference = SpatialReference.createFromProj4(proj4); + assertNotNull(spatialReference); + assertEquals(spatialReference.getProj4(), proj4); + } + + @Test + public void testWKTToWkid() { + String test1 = "GEOGCS[\"WGS 84\",DATUM[\"WGS_1984\",SPHEROID[\"WGS 84\",6378137,298.257223563,AUTHORITY[\"EPSG\",\"7030\"]],AUTHORITY[\"EPSG\",\"6326\"]],PRIMEM[\"Greenwich\",0,AUTHORITY[\"EPSG\",\"8901\"]],UNIT[\"degree\",0.0174532925199433,AUTHORITY[\"EPSG\",\"9122\"]],AUTHORITY[\"EPSG\",\"4326\"]]"; + Pattern pattern = Pattern.compile("^([\\w\\W]+AUTHORITY[\\s]*\\[[\\s]*\"EPSG\"[\\s]*,[\\s]*[\"]*([\\d]+)[\"]*]])$"); + Matcher matcher = pattern.matcher(test1); + + assertTrue(matcher.find()); + assertTrue(matcher.group(2).equals("4326")); + + SpatialReference spatialReference = SpatialReference.create(test1); + assertEquals(spatialReference.getID(), 4326); + assertNotNull(spatialReference.getProj4()); + assertNull(spatialReference.getText()); + + String test2 = "GEOGCS[\n" + + "\t\"WGS 84\",\n" + + "\tDATUM[\n" + + "\t\t\"WGS_1984\",\n" + + "\t\tSPHEROID[\n" + + "\t\t\t\"WGS 84\",\n" + + "\t\t\t6378137,\n" + + "\t\t\t298.257223563,\n" + + "\t\t\tAUTHORITY[\"EPSG\",\"7030\"]\n" + + "\t\t\t],\n" + + "\t\t\tAUTHORITY[\"EPSG\",\"6326\"]\n" + + "\t\t],\n" + + "\t\tPRIMEM[\n" + + "\t\t\t\"Greenwich\",\n" + + "\t\t\t0,\n" + + "\t\t\tAUTHORITY[\"EPSG\",\"8901\"]\n" + + "\t\t],\n" + + "\t\tUNIT[\n" + + "\t\t\t\"degree\",\n" + + "\t\t\t0.0174532925199433,\n" + + "\t\t\tAUTHORITY[\"EPSG\",\"9122\"]\n" + + "\t\t],\n" + + "\t\t\n" + + "\t\tAUTHORITY\n" + + "\n" + + "\t\t[\n" + + "\n" + + "\t\t\t\"EPSG\" ,\n" + + "\t\t\t\"4326\"\n" + + "\t\t\n" + + "\t\t]\n" + + "\n" + + "\t]"; + SpatialReference spatialReference2 = SpatialReference.create(test2); + assertEquals(spatialReference2.getID(), 4326); + assertNotNull(spatialReference2.getProj4()); + assertNull(spatialReference2.getText()); + + String test3 = "GEOGCS[\"WGS 84\",DATUM[\"WGS_1984\",SPHEROID[\"WGS 84\",6378137,298.257223563,AUTHORITY[\"EPSG\",\"7030\"]],AUTHORITY[\"EPSG\",\"6326\"]],PRIMEM[\"Greenwich\",0,AUTHORITY[\"EPSG\",\"8901\"]],UNIT[\"degree\",0.01745329251994328,AUTHORITY[\"EPSG\",\"9122\"]],AUTHORITY[\"EPSG\",\"4326\"]]"; + SpatialReference spatialReference3 = SpatialReference.create(test3); + assertEquals(spatialReference3.getID(), 4326); + assertNotNull(spatialReference3.getProj4()); + assertNull(spatialReference3.getText()); + + String test4 = "PROJCS[\"WGS 84 / UTM zone 17N\",\n" + + " GEOGCS[\"WGS 84\",\n" + + " DATUM[\"WGS_1984\",\n" + + " SPHEROID[\"WGS 84\",6378137,298.257223563,\n" + + " AUTHORITY[\"EPSG\",\"7030\"]],\n" + + " AUTHORITY[\"EPSG\",\"6326\"]],\n" + + " PRIMEM[\"Greenwich\",0,\n" + + " AUTHORITY[\"EPSG\",\"8901\"]],\n" + + " UNIT[\"degree\",0.0174532925199433,\n" + + " AUTHORITY[\"EPSG\",\"9122\"]],\n" + + " AUTHORITY[\"EPSG\",\"4326\"]],\n" + + " PROJECTION[\"Transverse_Mercator\"],\n" + + " PARAMETER[\"latitude_of_origin\",0],\n" + + " PARAMETER[\"central_meridian\",-81],\n" + + " PARAMETER[\"scale_factor\",0.9996],\n" + + " PARAMETER[\"false_easting\",500000],\n" + + " PARAMETER[\"false_northing\",0],\n" + + " UNIT[\"metre\",1,\n" + + " AUTHORITY[\"EPSG\",\"9001\"]],\n" + + " AXIS[\"Easting\",EAST],\n" + + " AXIS[\"Northing\",NORTH],\n" + + " AUTHORITY[\"EPSG\",\"32617\"]]\n" + + " "; + SpatialReference spatialReference4 = SpatialReference.create(test4); + assertEquals(spatialReference4.getID(), 32617); + assertNotNull(spatialReference4.getProj4()); + assertNull(spatialReference4.getText()); + + String customWKT = "PROJCS[\"Lo27_Cape\",GEOGCS[\"GCS_Cape\",DATUM[\"D_Cape\",SPHEROID[\"Clarke_1880_Arc\",6378249.145,293.466307656]],PRIMEM[\"Greenwich\",0.0],UNIT[\"Degree\",0.0174532925199433]],PROJECTION[\"Transverse_Mercator\"],PARAMETER[\"False_Easting\",0.0],PARAMETER[\"False_Northing\",0.0],PARAMETER[\"Central_Meridian\",27.0],PARAMETER[\"Scale_Factor\",1.0],PARAMETER[\"Latitude_Of_Origin\",0.0],UNIT[\"Meter\",1.0]]"; + SpatialReference spatialReference5 = SpatialReference.create(customWKT); + assertEquals(spatialReference5.getID(), 0); + assertNull(spatialReference5.getProj4()); + assertNotNull(spatialReference5.getText()); + } + + @Test + public void testProj4EPSG() { + String epsg = "+init=epsg:26711"; + SpatialReference spatialReference = SpatialReference.createFromProj4(epsg); + assertEquals(26711, spatialReference.getID()); + assertEquals(SpatialReference.CoordinateSystemType.PROJECTED, spatialReference.getCoordinateSystemType()); + + epsg = "+init=epsg:4326"; + spatialReference = SpatialReference.createFromProj4(epsg); + assertEquals(4326, spatialReference.getID()); + assertEquals(SpatialReference.CoordinateSystemType.GEOGRAPHIC, spatialReference.getCoordinateSystemType()); + + String test4 = "PROJCS[\"WGS 84 / UTM zone 17N\",\n" + + " GEOGCS[\"WGS 84\",\n" + + " DATUM[\"WGS_1984\",\n" + + " SPHEROID[\"WGS 84\",6378137,298.257223563,\n" + + " AUTHORITY[\"EPSG\",\"7030\"]],\n" + + " AUTHORITY[\"EPSG\",\"6326\"]],\n" + + " PRIMEM[\"Greenwich\",0,\n" + + " AUTHORITY[\"EPSG\",\"8901\"]],\n" + + " UNIT[\"degree\",0.0174532925199433,\n" + + " AUTHORITY[\"EPSG\",\"9122\"]],\n" + + " AUTHORITY[\"EPSG\",\"4326\"]],\n" + + " PROJECTION[\"Transverse_Mercator\"],\n" + + " PARAMETER[\"latitude_of_origin\",0],\n" + + " PARAMETER[\"central_meridian\",-81],\n" + + " PARAMETER[\"scale_factor\",0.9996],\n" + + " PARAMETER[\"false_easting\",500000],\n" + + " PARAMETER[\"false_northing\",0],\n" + + " UNIT[\"metre\",1,\n" + + " AUTHORITY[\"EPSG\",\"9001\"]],\n" + + " AXIS[\"Easting\",EAST],\n" + + " AXIS[\"Northing\",NORTH]]]\n" + + " "; + SpatialReference spatialReference4 = SpatialReference.create(test4); + assertEquals(SpatialReference.CoordinateSystemType.PROJECTED, spatialReference4.getCoordinateSystemType()); + + spatialReference = SpatialReference.createFromProj4("+proj=longlat +datum=WGS84 +no_defs "); + assertEquals(SpatialReference.CoordinateSystemType.GEOGRAPHIC, spatialReference.getCoordinateSystemType()); + } + + @Test + public void testProj9001() { + String tet5 = "PROJCS[\"NUTM30\",GEOGCS[\"ETRS89\",DATUM[\"European_Terrestrial_Reference_System_1989\",SPHEROID[\"GRS 1980\",6378137,298.2572221010042,AUTHORITY[\"EPSG\",\"7019\"]],AUTHORITY[\"EPSG\",\"6258\"]],PRIMEM[\"Greenwich\",0],UNIT[\"degree\",0.0174532925199433],AUTHORITY[\"EPSG\",\"4258\"]],PROJECTION[\"Transverse_Mercator\"],PARAMETER[\"latitude_of_origin\",0],PARAMETER[\"central_meridian\",-3],PARAMETER[\"scale_factor\",0.9996],PARAMETER[\"false_easting\",500000],PARAMETER[\"false_northing\",0],UNIT[\"metre\",1,AUTHORITY[\"EPSG\",\"9001\"]]]"; + String epsg = "+init=epsg:4326"; + SpatialReference spatialReference = SpatialReference.createFromProj4(epsg); + assertEquals(4326, spatialReference.getID()); + assertEquals(SpatialReference.CoordinateSystemType.GEOGRAPHIC, spatialReference.getCoordinateSystemType()); + + SpatialReference spatialReference1 = SpatialReference.create(tet5); + assertEquals(9001, spatialReference1.getID()); + assertEquals("+init=epsg:9001", spatialReference1.getProj4()); + } + + @Test + public void testProjEquality() { + SpatialReference spatialReference = SpatialReference.createFromProj4("+proj=utm +zone=30 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs "); + SpatialReference spatialReference2 = SpatialReference.createFromProj4("+proj=utm +zone=30 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs "); + assertEquals(spatialReference, spatialReference2); + } } diff --git a/src/test/java/com/esri/core/geometry/TestTouch.java b/src/test/java/com/esri/core/geometry/TestTouch.java index 69ed3d08..f7761836 100644 --- a/src/test/java/com/esri/core/geometry/TestTouch.java +++ b/src/test/java/com/esri/core/geometry/TestTouch.java @@ -28,434 +28,434 @@ import org.junit.Test; public class TestTouch extends TestCase { - @Override - protected void setUp() throws Exception { - super.setUp(); - } - - @Override - protected void tearDown() throws Exception { - super.tearDown(); - } - - @Test - public void testTouchOnPointAndPolyline() { - Geometry baseGeom = new Point(-130, 10); - Polyline pl = new Polyline(); - pl.startPath(new Point(-130, 10)); - pl.lineTo(-131, 15); - pl.lineTo(-140, 20); - - SpatialReference sr = SpatialReference.create(4326); - - boolean isTouched; - boolean isTouched2; - try { - isTouched = GeometryEngine.touches(baseGeom, pl, sr); - isTouched2 = GeometryEngine.touches(pl, baseGeom, sr); - - } catch (IllegalArgumentException ex) { - isTouched = false; - isTouched2 = false; - } - assertEquals(isTouched && isTouched2, true); - } - - @Test - public void testTouchOnPointAndPolygon() { - Geometry baseGeom = new Point(-130, 10); - Polygon pg = new Polygon(); - pg.startPath(new Point(-130, 10)); - pg.lineTo(-131, 15); - pg.lineTo(-140, 20); - - SpatialReference sr = SpatialReference.create(4326); - - boolean isTouched; - boolean isTouched2; - try { - isTouched = GeometryEngine.touches(baseGeom, pg, sr); - isTouched2 = GeometryEngine.touches(pg, baseGeom, sr); - - } catch (IllegalArgumentException ex) { - isTouched = false; - isTouched2 = false; - } - assertEquals(isTouched && isTouched2, true); - } - - @Test - public void testTouchOnPolygons() { - Polygon pg = new Polygon(); - pg.startPath(new Point(-130, 10)); - pg.lineTo(-131, 15); - pg.lineTo(-140, 20); - - Polygon pg2 = new Polygon(); - pg2.startPath(new Point(-130, 10)); - pg2.lineTo(-131, 15); - pg2.lineTo(-120, 20); - - SpatialReference sr = SpatialReference.create(4326); - - boolean isTouched; - boolean isTouched2; - try { - isTouched = GeometryEngine.touches(pg, pg2, sr); - isTouched2 = GeometryEngine.touches(pg2, pg, sr); - - } catch (IllegalArgumentException ex) { - isTouched = false; - isTouched2 = false; - } - assertEquals(isTouched && isTouched2, true); - - // boolean isTouchedFromRest = GeometryUtils.isRelationTrue(pg2, pg, sr, - // GeometryUtils.SpatialRelationType.esriGeometryRelationTouch, ""); - // assertTrue(isTouchedFromRest==isTouched); - } - - @Test - public void testTouchesOnPolylines() { - SpatialReference sr = SpatialReference.create(4326); - - Polyline basePl = new Polyline(); - basePl.startPath(new Point(-117, 20)); - basePl.lineTo(new Point(-100, 20)); - - basePl.lineTo(new Point(-100, 10)); - basePl.lineTo(new Point(-117, 10)); - basePl.lineTo(new Point(-117, 20)); - - Polyline compPl = new Polyline(); - compPl.startPath(new Point(-104, 20)); - - compPl.lineTo(new Point(-108, 25)); - - compPl.lineTo(new Point(-100, 20)); - // compPl.lineTo(new Point(-100, 30)); - // compPl.lineTo(new Point(-117, 30)); - // compPl.lineTo(new Point(-117, 20)); - - boolean isTouched; - try { - isTouched = GeometryEngine.touches(basePl, compPl, sr); - - } catch (IllegalArgumentException ex) { - isTouched = false; - } - assertEquals(isTouched, true); - } - - @Test - public void testTouchesOnPolylineAndPolygon() { - SpatialReference sr = SpatialReference.create(4326); - - Polygon basePl = new Polygon(); - basePl.startPath(new Point(-117, 20)); - basePl.lineTo(new Point(-100, 20)); - - basePl.lineTo(new Point(-100, 10)); - basePl.lineTo(new Point(-117, 10)); - - Polyline compPl = new Polyline(); - - compPl.startPath(new Point(-117, 20)); - compPl.lineTo(new Point(-108, 25)); - compPl.lineTo(new Point(-100, 20)); - compPl.lineTo(new Point(-100, 30)); - - boolean isTouched; - try { - isTouched = GeometryEngine.touches(basePl, compPl, sr); - } catch (IllegalArgumentException ex) { - isTouched = false; - } - assertEquals(isTouched, true); - - } - - @Test - public void testTouchOnEnvelopes() { - // case1, not touched - // Envelope env = new Envelope(new Point(-117,20), 12, 12); - // Envelope env2 = new Envelope(-100,20,-80,30); - - // case2 touched - Envelope env = new Envelope(new Point(-117, 20), 12, 12); - Envelope env2 = new Envelope(-117, 26, -80, 30); - - SpatialReference sr = SpatialReference.create(4326); - - boolean isTouched; - try { - isTouched = GeometryEngine.touches(env, env2, sr); - } catch (IllegalArgumentException ex) { - isTouched = false; - } - assertEquals(isTouched, true); - - } - - @Test - public void testTouchesOnPolylineAndEnvelope() { - SpatialReference sr = SpatialReference.create(4326); - - Polyline basePl = new Polyline(); - basePl.startPath(new Point(-117, 20)); - basePl.lineTo(new Point(-100, 20)); - - basePl.lineTo(new Point(-100, 10)); - basePl.lineTo(new Point(-117, 10)); - basePl.lineTo(new Point(-117, 20)); - - // Envelope env = new Envelope(new Point(-117,20), 12, 12);//not touched - Envelope env = new Envelope(-100, 20, -80, 30);// touched - - boolean isTouched; - try { - isTouched = GeometryEngine.touches(basePl, env, sr); - } catch (IllegalArgumentException ex) { - isTouched = false; - } - assertEquals(isTouched, true); - - } - - @Test - public void testTouchesOnPolygonAndEnvelope() { - SpatialReference sr = SpatialReference.create(4326); - - Polygon basePl = new Polygon(); - basePl.startPath(new Point(-117, 20)); - basePl.lineTo(new Point(-100, 20)); - - basePl.lineTo(new Point(-100, 10)); - basePl.lineTo(new Point(-117, 10)); - - // Envelope env = new Envelope(new Point(-117,20), 12, 12);//not touched - Envelope env = new Envelope(-100, 20, -80, 30);// touched - - boolean isTouched; - try { - isTouched = GeometryEngine.touches(basePl, env, sr); - } catch (IllegalArgumentException ex) { - isTouched = false; - } - assertEquals(isTouched, true); - - } - - @Test - public void testTouchesOnPointAndEnvelope() { - SpatialReference sr = SpatialReference.create(4326); - - Point p = new Point(-130, 10); - - // Envelope env = new Envelope(p, 12, 12);//not touched - Envelope env = new Envelope(-130, 10, -110, 20);// touched - - boolean isTouched; - try { - isTouched = GeometryEngine.touches(p, env, sr); - } catch (IllegalArgumentException ex) { - isTouched = false; - } - assertEquals(isTouched, true); - - } - - @Test - public void testRelationTouch() { - SpatialReference sr = SpatialReference.create(4326); - Polyline basePl = new Polyline(); - basePl.startPath(2, 2); - basePl.lineTo(2, 10); - - Polyline compPl = new Polyline(); - compPl.startPath(2, 4); - compPl.lineTo(9, 4); - compPl.lineTo(9, 9); - compPl.lineTo(2, 9); - compPl.lineTo(2, 4); - - boolean isTouched = false;// GeometryEngine.relation(basePl, compPl, sr, - // "G1 TOUCH G2"); - assertEquals(isTouched, false); - - } - - @Test - /** - * test touches between point and polyline - * a point touches a polyline only if the point is - * coincident with one of the polyline end points - * */ - public void testTouchesBetweenPointAndLine() { - SpatialReference sr = SpatialReference.create(4326); - Point p = new Point(2, 4); - - Polyline compPl = new Polyline(); - compPl.startPath(2, 4); - - compPl.lineTo(9, 4); - compPl.lineTo(9, 9); - compPl.lineTo(2, 9); - compPl.lineTo(2, 4); - - boolean isTouched = GeometryEngine.touches(p, compPl, sr); - assertTrue(!isTouched); - - } - - @Test - /** - * test touches between polyline and polyline - * a polyline touches another polyline only if the end point(s) is - * coincident with the end points of another polyline - * In this test case, the end points of the first polyline are concident - * with two end points of the second polyline - * */ - public void testTouchesBetweenPolylines() { - SpatialReference sr = SpatialReference.create(4326); - Polyline pl = new Polyline(); - pl.startPath(2, 4); - pl.lineTo(9, 9); - - Polyline compPl = new Polyline(); - compPl.startPath(2, 4); - - compPl.lineTo(9, 4); - compPl.lineTo(9, 9); - compPl.lineTo(2, 9); - compPl.lineTo(2, 4); - - boolean isTouched = GeometryEngine.touches(pl, compPl, sr); - assertEquals(isTouched, true); - - } - - @Test - /** - * test touches between polyline and polygon - * a polyline touches polygon only if the end point(s) is - * coincident with the vertices of polygon - * In this test case, the end points of the polyline are co-incident - * with two vertices of the polygon which consists of two parts - * */ - public void testTouchesBetweenPolylineAndPolygon() { - SpatialReference sr = SpatialReference.create(4326); - Polyline pl = new Polyline(); - pl.startPath(2, 4); - pl.lineTo(1, 10); - pl.lineTo(6, 12); - - Polygon compPg = new Polygon(); - compPg.startPath(2, 4); - - compPg.lineTo(2, 9); - compPg.lineTo(9, 9); - compPg.lineTo(9, 4); - - compPg.startPath(2, 9); - compPg.lineTo(6, 12); - compPg.lineTo(9, 10); - - boolean isTouched = GeometryEngine.touches(pl, compPg, sr); - assertEquals(isTouched, true); - - } - - @Test - /** - * test touches between polylines who consists of two parts - * */ - public void testTouchesBetweenMultipartPolylines() { - SpatialReference sr = SpatialReference.create(4326); - Polyline pl = new Polyline(); - pl.startPath(2, 4); - pl.lineTo(1, 10); - pl.lineTo(6, 12); - - pl.startPath(6, 12); - pl.lineTo(12, 12); - pl.lineTo(9, 9); - - Polyline compPl = new Polyline(); - compPl.startPath(2, 4); - - compPl.lineTo(2, 9); - compPl.lineTo(9, 9); - compPl.lineTo(9, 4); - - compPl.startPath(2, 9); - compPl.lineTo(6, 12); - compPl.lineTo(9, 10); - - boolean isTouched = GeometryEngine.touches(pl, compPl, sr); - assertTrue(!isTouched); - - // boolean isTouchedFromRest = GeometryUtils.isRelationTrue(compPl, pl, - // sr, - // GeometryUtils.SpatialRelationType.esriGeometryRelationTouch, ""); - // assertTrue(isTouchedFromRest == isTouched); - } - - @Test - /** - * test touches between polygons who consists of two parts - * */ - public void testTouchesBetweenMultipartPolygons2() { - SpatialReference sr = SpatialReference.create(4326); - Polygon pl = new Polygon(); - pl.startPath(2, 4); - pl.lineTo(1, 9); - pl.lineTo(2, 6); - - pl.startPath(2, 9); - pl.lineTo(6, 14); - pl.lineTo(6, 12); - - Polygon compPl = new Polygon(); - compPl.startPath(2, 4); - - compPl.lineTo(2, 9); - compPl.lineTo(9, 9); - compPl.lineTo(9, 4); - - compPl.startPath(2, 9); - compPl.lineTo(6, 12); - compPl.lineTo(9, 10); - - boolean isTouched = GeometryEngine.touches(pl, compPl, sr); - assertEquals(isTouched, true); - - } - - @Test - public void testTouchPointLineCR183227() { - // Tests CR 183227 - Geometry baseGeom = new Point(-130, 10); - Polyline pl = new Polyline(); - // pl.startPath(new Point(-130, 10)); - pl.startPath(-130, 10); - pl.lineTo(-131, 15); - pl.lineTo(-140, 20); - - SpatialReference sr = SpatialReference.create(4326); - - boolean isTouched; - boolean isTouched2; - isTouched = GeometryEngine.touches(baseGeom, pl, sr); - isTouched2 = GeometryEngine.touches(pl, baseGeom, sr); - assertTrue(isTouched && isTouched2); - { - Geometry baseGeom2 = (Geometry) new Point(-131, 15); - boolean bIsTouched; - boolean bIsTouched2; - bIsTouched = GeometryEngine.touches(baseGeom2, pl, sr); - bIsTouched2 = GeometryEngine.touches(pl, baseGeom2, sr); - assertTrue(!bIsTouched && !bIsTouched2); - } - } + @Override + protected void setUp() throws Exception { + super.setUp(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + } + + @Test + public void testTouchOnPointAndPolyline() { + Geometry baseGeom = new Point(-130, 10); + Polyline pl = new Polyline(); + pl.startPath(new Point(-130, 10)); + pl.lineTo(-131, 15); + pl.lineTo(-140, 20); + + SpatialReference sr = SpatialReference.create(4326); + + boolean isTouched; + boolean isTouched2; + try { + isTouched = GeometryEngine.touches(baseGeom, pl, sr); + isTouched2 = GeometryEngine.touches(pl, baseGeom, sr); + + } catch (IllegalArgumentException ex) { + isTouched = false; + isTouched2 = false; + } + assertEquals(isTouched && isTouched2, true); + } + + @Test + public void testTouchOnPointAndPolygon() { + Geometry baseGeom = new Point(-130, 10); + Polygon pg = new Polygon(); + pg.startPath(new Point(-130, 10)); + pg.lineTo(-131, 15); + pg.lineTo(-140, 20); + + SpatialReference sr = SpatialReference.create(4326); + + boolean isTouched; + boolean isTouched2; + try { + isTouched = GeometryEngine.touches(baseGeom, pg, sr); + isTouched2 = GeometryEngine.touches(pg, baseGeom, sr); + + } catch (IllegalArgumentException ex) { + isTouched = false; + isTouched2 = false; + } + assertEquals(isTouched && isTouched2, true); + } + + @Test + public void testTouchOnPolygons() { + Polygon pg = new Polygon(); + pg.startPath(new Point(-130, 10)); + pg.lineTo(-131, 15); + pg.lineTo(-140, 20); + + Polygon pg2 = new Polygon(); + pg2.startPath(new Point(-130, 10)); + pg2.lineTo(-131, 15); + pg2.lineTo(-120, 20); + + SpatialReference sr = SpatialReference.create(4326); + + boolean isTouched; + boolean isTouched2; + try { + isTouched = GeometryEngine.touches(pg, pg2, sr); + isTouched2 = GeometryEngine.touches(pg2, pg, sr); + + } catch (IllegalArgumentException ex) { + isTouched = false; + isTouched2 = false; + } + assertEquals(isTouched && isTouched2, true); + + // boolean isTouchedFromRest = GeometryUtils.isRelationTrue(pg2, pg, sr, + // GeometryUtils.SpatialRelationType.esriGeometryRelationTouch, ""); + // assertTrue(isTouchedFromRest==isTouched); + } + + @Test + public void testTouchesOnPolylines() { + SpatialReference sr = SpatialReference.create(4326); + + Polyline basePl = new Polyline(); + basePl.startPath(new Point(-117, 20)); + basePl.lineTo(new Point(-100, 20)); + + basePl.lineTo(new Point(-100, 10)); + basePl.lineTo(new Point(-117, 10)); + basePl.lineTo(new Point(-117, 20)); + + Polyline compPl = new Polyline(); + compPl.startPath(new Point(-104, 20)); + + compPl.lineTo(new Point(-108, 25)); + + compPl.lineTo(new Point(-100, 20)); + // compPl.lineTo(new Point(-100, 30)); + // compPl.lineTo(new Point(-117, 30)); + // compPl.lineTo(new Point(-117, 20)); + + boolean isTouched; + try { + isTouched = GeometryEngine.touches(basePl, compPl, sr); + + } catch (IllegalArgumentException ex) { + isTouched = false; + } + assertEquals(isTouched, true); + } + + @Test + public void testTouchesOnPolylineAndPolygon() { + SpatialReference sr = SpatialReference.create(4326); + + Polygon basePl = new Polygon(); + basePl.startPath(new Point(-117, 20)); + basePl.lineTo(new Point(-100, 20)); + + basePl.lineTo(new Point(-100, 10)); + basePl.lineTo(new Point(-117, 10)); + + Polyline compPl = new Polyline(); + + compPl.startPath(new Point(-117, 20)); + compPl.lineTo(new Point(-108, 25)); + compPl.lineTo(new Point(-100, 20)); + compPl.lineTo(new Point(-100, 30)); + + boolean isTouched; + try { + isTouched = GeometryEngine.touches(basePl, compPl, sr); + } catch (IllegalArgumentException ex) { + isTouched = false; + } + assertEquals(isTouched, true); + + } + + @Test + public void testTouchOnEnvelopes() { + // case1, not touched + // Envelope env = new Envelope(new Point(-117,20), 12, 12); + // Envelope env2 = new Envelope(-100,20,-80,30); + + // case2 touched + Envelope env = new Envelope(new Point(-117, 20), 12, 12); + Envelope env2 = new Envelope(-117, 26, -80, 30); + + SpatialReference sr = SpatialReference.create(4326); + + boolean isTouched; + try { + isTouched = GeometryEngine.touches(env, env2, sr); + } catch (IllegalArgumentException ex) { + isTouched = false; + } + assertEquals(isTouched, true); + + } + + @Test + public void testTouchesOnPolylineAndEnvelope() { + SpatialReference sr = SpatialReference.create(4326); + + Polyline basePl = new Polyline(); + basePl.startPath(new Point(-117, 20)); + basePl.lineTo(new Point(-100, 20)); + + basePl.lineTo(new Point(-100, 10)); + basePl.lineTo(new Point(-117, 10)); + basePl.lineTo(new Point(-117, 20)); + + // Envelope env = new Envelope(new Point(-117,20), 12, 12);//not touched + Envelope env = new Envelope(-100, 20, -80, 30);// touched + + boolean isTouched; + try { + isTouched = GeometryEngine.touches(basePl, env, sr); + } catch (IllegalArgumentException ex) { + isTouched = false; + } + assertEquals(isTouched, true); + + } + + @Test + public void testTouchesOnPolygonAndEnvelope() { + SpatialReference sr = SpatialReference.create(4326); + + Polygon basePl = new Polygon(); + basePl.startPath(new Point(-117, 20)); + basePl.lineTo(new Point(-100, 20)); + + basePl.lineTo(new Point(-100, 10)); + basePl.lineTo(new Point(-117, 10)); + + // Envelope env = new Envelope(new Point(-117,20), 12, 12);//not touched + Envelope env = new Envelope(-100, 20, -80, 30);// touched + + boolean isTouched; + try { + isTouched = GeometryEngine.touches(basePl, env, sr); + } catch (IllegalArgumentException ex) { + isTouched = false; + } + assertEquals(isTouched, true); + + } + + @Test + public void testTouchesOnPointAndEnvelope() { + SpatialReference sr = SpatialReference.create(4326); + + Point p = new Point(-130, 10); + + // Envelope env = new Envelope(p, 12, 12);//not touched + Envelope env = new Envelope(-130, 10, -110, 20);// touched + + boolean isTouched; + try { + isTouched = GeometryEngine.touches(p, env, sr); + } catch (IllegalArgumentException ex) { + isTouched = false; + } + assertEquals(isTouched, true); + + } + + @Test + public void testRelationTouch() { + SpatialReference sr = SpatialReference.create(4326); + Polyline basePl = new Polyline(); + basePl.startPath(2, 2); + basePl.lineTo(2, 10); + + Polyline compPl = new Polyline(); + compPl.startPath(2, 4); + compPl.lineTo(9, 4); + compPl.lineTo(9, 9); + compPl.lineTo(2, 9); + compPl.lineTo(2, 4); + + boolean isTouched = false;// GeometryEngine.relation(basePl, compPl, sr, + // "G1 TOUCH G2"); + assertEquals(isTouched, false); + + } + + @Test + /** + * test touches between point and polyline + * a point touches a polyline only if the point is + * coincident with one of the polyline end points + * */ + public void testTouchesBetweenPointAndLine() { + SpatialReference sr = SpatialReference.create(4326); + Point p = new Point(2, 4); + + Polyline compPl = new Polyline(); + compPl.startPath(2, 4); + + compPl.lineTo(9, 4); + compPl.lineTo(9, 9); + compPl.lineTo(2, 9); + compPl.lineTo(2, 4); + + boolean isTouched = GeometryEngine.touches(p, compPl, sr); + assertTrue(!isTouched); + + } + + @Test + /** + * test touches between polyline and polyline + * a polyline touches another polyline only if the end point(s) is + * coincident with the end points of another polyline + * In this test case, the end points of the first polyline are concident + * with two end points of the second polyline + * */ + public void testTouchesBetweenPolylines() { + SpatialReference sr = SpatialReference.create(4326); + Polyline pl = new Polyline(); + pl.startPath(2, 4); + pl.lineTo(9, 9); + + Polyline compPl = new Polyline(); + compPl.startPath(2, 4); + + compPl.lineTo(9, 4); + compPl.lineTo(9, 9); + compPl.lineTo(2, 9); + compPl.lineTo(2, 4); + + boolean isTouched = GeometryEngine.touches(pl, compPl, sr); + assertEquals(isTouched, true); + + } + + @Test + /** + * test touches between polyline and polygon + * a polyline touches polygon only if the end point(s) is + * coincident with the vertices of polygon + * In this test case, the end points of the polyline are co-incident + * with two vertices of the polygon which consists of two parts + * */ + public void testTouchesBetweenPolylineAndPolygon() { + SpatialReference sr = SpatialReference.create(4326); + Polyline pl = new Polyline(); + pl.startPath(2, 4); + pl.lineTo(1, 10); + pl.lineTo(6, 12); + + Polygon compPg = new Polygon(); + compPg.startPath(2, 4); + + compPg.lineTo(2, 9); + compPg.lineTo(9, 9); + compPg.lineTo(9, 4); + + compPg.startPath(2, 9); + compPg.lineTo(6, 12); + compPg.lineTo(9, 10); + + boolean isTouched = GeometryEngine.touches(pl, compPg, sr); + assertEquals(isTouched, true); + + } + + @Test + /** + * test touches between polylines who consists of two parts + * */ + public void testTouchesBetweenMultipartPolylines() { + SpatialReference sr = SpatialReference.create(4326); + Polyline pl = new Polyline(); + pl.startPath(2, 4); + pl.lineTo(1, 10); + pl.lineTo(6, 12); + + pl.startPath(6, 12); + pl.lineTo(12, 12); + pl.lineTo(9, 9); + + Polyline compPl = new Polyline(); + compPl.startPath(2, 4); + + compPl.lineTo(2, 9); + compPl.lineTo(9, 9); + compPl.lineTo(9, 4); + + compPl.startPath(2, 9); + compPl.lineTo(6, 12); + compPl.lineTo(9, 10); + + boolean isTouched = GeometryEngine.touches(pl, compPl, sr); + assertTrue(!isTouched); + + // boolean isTouchedFromRest = GeometryUtils.isRelationTrue(compPl, pl, + // sr, + // GeometryUtils.SpatialRelationType.esriGeometryRelationTouch, ""); + // assertTrue(isTouchedFromRest == isTouched); + } + + @Test + /** + * test touches between polygons who consists of two parts + * */ + public void testTouchesBetweenMultipartPolygons2() { + SpatialReference sr = SpatialReference.create(4326); + Polygon pl = new Polygon(); + pl.startPath(2, 4); + pl.lineTo(1, 9); + pl.lineTo(2, 6); + + pl.startPath(2, 9); + pl.lineTo(6, 14); + pl.lineTo(6, 12); + + Polygon compPl = new Polygon(); + compPl.startPath(2, 4); + + compPl.lineTo(2, 9); + compPl.lineTo(9, 9); + compPl.lineTo(9, 4); + + compPl.startPath(2, 9); + compPl.lineTo(6, 12); + compPl.lineTo(9, 10); + + boolean isTouched = GeometryEngine.touches(pl, compPl, sr); + assertEquals(isTouched, true); + + } + + @Test + public void testTouchPointLineCR183227() { + // Tests CR 183227 + Geometry baseGeom = new Point(-130, 10); + Polyline pl = new Polyline(); + // pl.startPath(new Point(-130, 10)); + pl.startPath(-130, 10); + pl.lineTo(-131, 15); + pl.lineTo(-140, 20); + + SpatialReference sr = SpatialReference.create(4326); + + boolean isTouched; + boolean isTouched2; + isTouched = GeometryEngine.touches(baseGeom, pl, sr); + isTouched2 = GeometryEngine.touches(pl, baseGeom, sr); + assertTrue(isTouched && isTouched2); + { + Geometry baseGeom2 = (Geometry) new Point(-131, 15); + boolean bIsTouched; + boolean bIsTouched2; + bIsTouched = GeometryEngine.touches(baseGeom2, pl, sr); + bIsTouched2 = GeometryEngine.touches(pl, baseGeom2, sr); + assertTrue(!bIsTouched && !bIsTouched2); + } + } } diff --git a/src/test/java/com/esri/core/geometry/TestTreap.java b/src/test/java/com/esri/core/geometry/TestTreap.java index 38eb5349..e1f2b5b5 100644 --- a/src/test/java/com/esri/core/geometry/TestTreap.java +++ b/src/test/java/com/esri/core/geometry/TestTreap.java @@ -28,78 +28,78 @@ import org.junit.Test; public class TestTreap extends TestCase { - @Override - protected void setUp() throws Exception { - super.setUp(); - } - - @Override - protected void tearDown() throws Exception { - super.tearDown(); - } - - @Test - public static void test1() { - Point2D[] pts = new Point2D[10]; - - for (int i = 0; i < 10; i++) { - Point2D pt = new Point2D(); - pt.x = i; - pt.y = 0; - - pts[i] = pt; - } - - TreapComparatorForTesting c = new TreapComparatorForTesting(pts); - Treap treap = new Treap(); - treap.setComparator(c); - - int[] nodes = new int[10]; - for (int i = 0; i < 10; i++) - nodes[i] = treap.addElement(i, -1); - - for (int i = 1; i < 10; i++) { - assertTrue(treap.getPrev(nodes[i]) == nodes[i - 1]); - } - - for (int i = 0; i < 9; i++) { - assertTrue(treap.getNext(nodes[i]) == nodes[i + 1]); - } - - treap.deleteNode(nodes[0], -1); - treap.deleteNode(nodes[2], -1); - treap.deleteNode(nodes[4], -1); - treap.deleteNode(nodes[6], -1); - treap.deleteNode(nodes[8], -1); - - assertTrue(treap.getPrev(nodes[3]) == nodes[1]); - assertTrue(treap.getPrev(nodes[5]) == nodes[3]); - assertTrue(treap.getPrev(nodes[7]) == nodes[5]); - assertTrue(treap.getPrev(nodes[9]) == nodes[7]); - - assertTrue(treap.getNext(nodes[1]) == nodes[3]); - assertTrue(treap.getNext(nodes[3]) == nodes[5]); - assertTrue(treap.getNext(nodes[5]) == nodes[7]); - assertTrue(treap.getNext(nodes[7]) == nodes[9]); - } + @Override + protected void setUp() throws Exception { + super.setUp(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + } + + @Test + public static void test1() { + Point2D[] pts = new Point2D[10]; + + for (int i = 0; i < 10; i++) { + Point2D pt = new Point2D(); + pt.x = i; + pt.y = 0; + + pts[i] = pt; + } + + TreapComparatorForTesting c = new TreapComparatorForTesting(pts); + Treap treap = new Treap(); + treap.setComparator(c); + + int[] nodes = new int[10]; + for (int i = 0; i < 10; i++) + nodes[i] = treap.addElement(i, -1); + + for (int i = 1; i < 10; i++) { + assertTrue(treap.getPrev(nodes[i]) == nodes[i - 1]); + } + + for (int i = 0; i < 9; i++) { + assertTrue(treap.getNext(nodes[i]) == nodes[i + 1]); + } + + treap.deleteNode(nodes[0], -1); + treap.deleteNode(nodes[2], -1); + treap.deleteNode(nodes[4], -1); + treap.deleteNode(nodes[6], -1); + treap.deleteNode(nodes[8], -1); + + assertTrue(treap.getPrev(nodes[3]) == nodes[1]); + assertTrue(treap.getPrev(nodes[5]) == nodes[3]); + assertTrue(treap.getPrev(nodes[7]) == nodes[5]); + assertTrue(treap.getPrev(nodes[9]) == nodes[7]); + + assertTrue(treap.getNext(nodes[1]) == nodes[3]); + assertTrue(treap.getNext(nodes[3]) == nodes[5]); + assertTrue(treap.getNext(nodes[5]) == nodes[7]); + assertTrue(treap.getNext(nodes[7]) == nodes[9]); + } } final class TreapComparatorForTesting extends Treap.Comparator { - Point2D[] m_pts; + Point2D[] m_pts; - TreapComparatorForTesting(Point2D[] pts) { - m_pts = pts; - } + TreapComparatorForTesting(Point2D[] pts) { + m_pts = pts; + } - @Override - int compare(Treap treap, int elm, int node) { - int elm2 = treap.getElement(node); - Point2D pt1 = m_pts[elm]; - Point2D pt2 = m_pts[elm2]; + @Override + int compare(Treap treap, int elm, int node) { + int elm2 = treap.getElement(node); + Point2D pt1 = m_pts[elm]; + Point2D pt2 = m_pts[elm2]; - if (pt1.x < pt2.x) - return -1; + if (pt1.x < pt2.x) + return -1; - return 1; - } + return 1; + } } diff --git a/src/test/java/com/esri/core/geometry/TestUnion.java b/src/test/java/com/esri/core/geometry/TestUnion.java index b7ac6bea..bab2e0a1 100644 --- a/src/test/java/com/esri/core/geometry/TestUnion.java +++ b/src/test/java/com/esri/core/geometry/TestUnion.java @@ -32,56 +32,180 @@ import java.util.stream.Collectors; public class TestUnion extends TestCase { - public ArrayDeque pointList = null; - public ArrayDeque bufferedPointList = null; - - @Override - protected void setUp() throws Exception { - Random random = new Random(1977); - int max_size = 10000; - pointList = new ArrayDeque<>(max_size); - bufferedPointList = new ArrayDeque<>(max_size); - for (int i = 0; i < max_size; i++) { - double x = randomWithRange(-20, 20, random); - double y = randomWithRange(-20, 20, random); - Geometry point = new Point(x, y); - pointList.add(point); - bufferedPointList.add(OperatorBufferLocal.local().execute(point, null, 2.5, null)); - } - - super.setUp(); - } - - @Override - protected void tearDown() throws Exception { - super.tearDown(); - } - - @Test - public void testUnion() { - Point pt = new Point(10, 20); - - Point pt2 = new Point(); - pt2.setXY(10, 10); - - Envelope env1 = new Envelope(10, 10, 30, 50); - Envelope env2 = new Envelope(30, 10, 60, 50); - Geometry[] geomArray = new Geometry[]{env1, env2}; - SimpleGeometryCursor inputGeometries = new SimpleGeometryCursor( - geomArray); - OperatorUnion union = (OperatorUnion) OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Union); - - SpatialReference sr = SpatialReference.create(4326); - - GeometryCursor outputCursor = union.execute(inputGeometries, sr, null); - Geometry result = outputCursor.next(); - } - - static double randomWithRange(double min, double max, Random random) { - double range = Math.abs(max - min); - return (random.nextDouble() * range) + (min <= max ? min : max); - } + public ArrayDeque pointList = null; + public ArrayDeque bufferedPointList = null; + + @Override + protected void setUp() throws Exception { + Random random = new Random(1977); + int max_size = 10000; + pointList = new ArrayDeque<>(max_size); + bufferedPointList = new ArrayDeque<>(max_size); + for (int i = 0; i < max_size; i++) { + double x = randomWithRange(-20, 20, random); + double y = randomWithRange(-20, 20, random); + Geometry point = new Point(x, y); + pointList.add(point); + bufferedPointList.add(OperatorBufferLocal.local().execute(point, null, 2.5, null)); + } + + super.setUp(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + } + + @Test + public void testUnion() { + Point pt = new Point(10, 20); + + Point pt2 = new Point(); + pt2.setXY(10, 10); + + Envelope env1 = new Envelope(10, 10, 30, 50); + Envelope env2 = new Envelope(30, 10, 60, 50); + Geometry[] geomArray = new Geometry[]{env1, env2}; + SimpleGeometryCursor inputGeometries = new SimpleGeometryCursor( + geomArray); + OperatorUnion union = (OperatorUnion) OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Union); + + SpatialReference sr = SpatialReference.create(4326); + + GeometryCursor outputCursor = union.execute(inputGeometries, sr, null); + Geometry result = outputCursor.next(); + + MultiPath path = (MultiPath)result; + assertEquals(1, path.getPathCount()); + assertEquals(6, path.getPathEnd(0)); + assertEquals(new Point2D(10, 10), path.getXY(0)); + assertEquals(new Point2D(10, 50), path.getXY(1)); + assertEquals(new Point2D(30, 50), path.getXY(2)); + assertEquals(new Point2D(60, 50), path.getXY(3)); + assertEquals(new Point2D(60, 10), path.getXY(4)); + assertEquals(new Point2D(30, 10), path.getXY(5)); + } + + @Test + public static void testUnionDistinctGeometries() { + Envelope env = new Envelope(1, 5, 3, 10); + + Polygon polygon = new Polygon(); + polygon.startPath(new Point(4, 3)); + polygon.lineTo(new Point(7, 6)); + polygon.lineTo(new Point(6, 8)); + polygon.lineTo(new Point(4, 3)); + + Geometry[] geomArray = new Geometry[] { env, polygon }; + SimpleGeometryCursor inputGeometries = new SimpleGeometryCursor( + geomArray); + OperatorUnion union = (OperatorUnion) OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Union); + SpatialReference sr = SpatialReference.create(4326); + + GeometryCursor outputCursor = union.execute(inputGeometries, sr, null); + Geometry result = outputCursor.next(); + + MultiPath path = (MultiPath)result; + assertEquals(2, path.getPathCount()); + + assertEquals(3, path.getPathEnd(0)); + assertEquals(7, path.getPathEnd(1)); + // from polygon + assertEquals(new Point2D(4, 3), path.getXY(0)); + assertEquals(new Point2D(6, 8), path.getXY(1)); + assertEquals(new Point2D(7, 6), path.getXY(2)); + // from envelope + assertEquals(new Point2D(1, 5), path.getXY(3)); + assertEquals(new Point2D(1, 10), path.getXY(4)); + assertEquals(new Point2D(3, 10), path.getXY(5)); + assertEquals(new Point2D(3, 5), path.getXY(6)); + } + + @Test + public static void testUnionCoincidentPolygons() { + Polygon polygon1 = new Polygon(); + polygon1.startPath(new Point(3, 2)); + polygon1.lineTo(new Point(1, 2)); + polygon1.lineTo(new Point(1, 4)); + polygon1.lineTo(new Point(3, 4)); + polygon1.lineTo(new Point(3, 2)); + + Polygon polygon2 = new Polygon(); + polygon2.startPath(new Point(1, 2)); + polygon2.lineTo(new Point(1, 4)); + polygon2.lineTo(new Point(3, 4)); + polygon2.lineTo(new Point(3, 2)); + polygon2.lineTo(new Point(1, 2)); + + Geometry[] geomArray = new Geometry[] { polygon1, polygon2 }; + SimpleGeometryCursor inputGeometries = new SimpleGeometryCursor( + geomArray); + OperatorUnion union = (OperatorUnion) OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Union); + SpatialReference sr = SpatialReference.create(4326); + + GeometryCursor outputCursor = union.execute(inputGeometries, sr, null); + Geometry result = outputCursor.next(); + + MultiPath path = (MultiPath)result; + assertEquals(1, path.getPathCount()); + assertEquals(4, path.getPathEnd(0)); + assertEquals(new Point2D(1, 2), path.getXY(0)); + assertEquals(new Point2D(1, 4), path.getXY(1)); + assertEquals(new Point2D(3, 4), path.getXY(2)); + assertEquals(new Point2D(3, 2), path.getXY(3)); + } + + @Test + public static void testUnionCoincidentPolygonsWithReverseWinding() { + // Input polygons have CCW winding, result is always CW + Polygon polygon1 = new Polygon(); + polygon1.startPath(new Point(3, 2)); + polygon1.lineTo(new Point(3, 4)); + polygon1.lineTo(new Point(1, 4)); + polygon1.lineTo(new Point(1, 2)); + polygon1.lineTo(new Point(3, 2)); + + Polygon polygon2 = new Polygon(); + polygon2.startPath(new Point(1, 2)); + polygon2.lineTo(new Point(3, 2)); + polygon2.lineTo(new Point(3, 4)); + polygon2.lineTo(new Point(1, 4)); + polygon2.lineTo(new Point(1, 2)); + + Polygon expectedPolygon = new Polygon(); + expectedPolygon.startPath(new Point(1, 2)); + expectedPolygon.lineTo(new Point(1, 4)); + expectedPolygon.lineTo(new Point(3, 4)); + expectedPolygon.lineTo(new Point(3, 2)); + expectedPolygon.lineTo(new Point(1, 2)); + + Geometry[] geomArray = new Geometry[] { polygon1, polygon2 }; + SimpleGeometryCursor inputGeometries = new SimpleGeometryCursor( + geomArray); + OperatorUnion union = (OperatorUnion) OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Union); + SpatialReference sr = SpatialReference.create(4326); + + GeometryCursor outputCursor = union.execute(inputGeometries, sr, null); + Geometry result = outputCursor.next(); + + MultiPath path = (MultiPath)result; + assertEquals(1, path.getPathCount()); + assertEquals(4, path.getPathEnd(0)); + assertEquals(new Point2D(1, 2), path.getXY(0)); + assertEquals(new Point2D(1, 4), path.getXY(1)); + assertEquals(new Point2D(3, 4), path.getXY(2)); + assertEquals(new Point2D(3, 2), path.getXY(3)); + } + + static double randomWithRange(double min, double max, Random random) { + double range = Math.abs(max - min); + return (random.nextDouble() * range) + (min <= max ? min : max); + } // @Test @@ -123,106 +247,106 @@ static double randomWithRange(double min, double max, Random random) { // assertTrue(result.calculateArea2D() > 40 * 40); // } - @Test - public void testQuadTreeIterator() { - int size = 1000; - ArrayDeque bufferedArrayDequ = new ArrayDeque<>(new ArrayList<>(bufferedPointList).subList(0, size)); - SimpleGeometryCursor simpleGeometryCursor = new SimpleGeometryCursor(bufferedArrayDequ); - - HashMap m_quadTreeMap = new HashMap<>(); - Envelope2D quad_envelope2D = new Envelope2D(); - Geometry geometry = null; - Envelope2D geometry_env = new Envelope2D(); - int count_index = 0; - while ((geometry = simpleGeometryCursor.next()) != null) { - geometry.queryEnvelope2D(geometry_env); - quad_envelope2D.merge(geometry_env); - m_quadTreeMap.put(count_index++, geometry); - } - QuadTree quadTree = new QuadTree(quad_envelope2D, 16); - for (Integer element_id : m_quadTreeMap.keySet()) { - m_quadTreeMap.get(element_id).queryEnvelope2D(geometry_env); - quadTree.insert(element_id, geometry_env); - } - - QuadTree.QuadTreeIterator quadTreeIterator = quadTree.getIterator(true); - quadTreeIterator.resetIterator(quad_envelope2D, 0.0); - int element_handle = -1; - List geometryList = new ArrayList<>(); - assertFalse(geometryList.containsAll(m_quadTreeMap.values())); - - int max_height = 0; - while ((element_handle = quadTreeIterator.next()) != -1) { - int element_id = quadTree.getElement(element_handle); - int quad_handle = quadTree.getQuad(element_handle); - - int sub_count = quadTree.getContainedSubTreeElementCount(quad_handle); - int sub_count_2 = quadTree.getSubTreeElementCount(quad_handle); - - int quad_height = quadTree.getHeight(quad_handle); - max_height = quad_height > max_height ? quad_height : max_height; - Envelope2D envelope2D = quadTree.getExtent(quad_handle); - assertTrue(quadTree.hasData(envelope2D, 0.0)); - geometryList.add(m_quadTreeMap.get(element_id)); - } - assertTrue(max_height == 3); - assertEquals(16, quadTree.getMaxHeight()); - - assertTrue(geometryList.containsAll(m_quadTreeMap.values())); - } - - - @Test - public static void testFailedUnionDifferenceTest() { - // shapely result for union - String shapelyWKT = "POLYGON ((-14.50430349127707 -22.07059031842225, -14.51281964335354 -22.0769063272619, -14.72325338383755 -22.20303545737643, -14.94503664498982 -22.30793112778376, -15.17603353276639 -22.39058313583606, -15.41401942086222 -22.45019549751362, -15.65670237507864 -22.48619411318603, -15.90174522590254 -22.49823229650554, -16.14678807672644 -22.48619411318603, -16.38947103094286 -22.45019549751362, -16.4990865892769 -22.42273822951685, -16.65632769437413 -22.44606274412307, -16.90137054519803 -22.45810092744258, -17.14641339602193 -22.44606274412307, -17.38909635023835 -22.41006412845066, -17.62708223833419 -22.35045176677311, -17.85807912611075 -22.2677997587208, -17.86833950280889 -22.2629469619552, -17.93163213536989 -22.26605632960654, -18.15038036764053 -22.25530991806244, -18.32212283929288 -22.31676035701235, -18.56010872738872 -22.37637271868991, -18.80279168160514 -22.41237133436232, -19.04783453242904 -22.42440951768183, -19.29287738325294 -22.41237133436232, -19.53556033746936 -22.37637271868991, -19.63541513605011 -22.3513603937329, -19.66115167971507 -22.35009603841869, -19.90383463393149 -22.31409742274627, -20.14182052202732 -22.25448506106872, -20.37281740980389 -22.17183305301641, -20.42744614576441 -22.14599558515562, -20.45917099079353 -22.14128964893872, -20.69715687888937 -22.08167728726117, -20.92815376666594 -21.99902527920887, -21.14993702781821 -21.89412960880153, -21.36037076830222 -21.76800047868701, -21.55742839616233 -21.62185258133749, -21.73921213871958 -21.45709340089702, -21.90397131916006 -21.27530965833976, -22.05011921650958 -21.07825203047966, -22.1762483466241 -20.86781828999564, -22.28114401703143 -20.64603502884338, -22.36379602508374 -20.41503814106681, -22.4234083867613 -20.17705225297097, -22.45940700243371 -19.93436929875455, -22.47144518575322 -19.68932644793065, -22.46272989236197 -19.51192257546279, -22.48179191062821 -19.38341688656973, -22.49383009394772 -19.13837403574583, -22.48179191062821 -18.89333118492193, -22.4457932949558 -18.65064823070551, -22.38618093327824 -18.41266234260967, -22.3612750894556 -18.34305517218451, -22.39279909447611 -18.21720428958194, -22.42879771014853 -17.97452133536552, -22.44083589346804 -17.72947848454162, -22.42879771014853 -17.48443563371772, -22.39279909447611 -17.2417526795013, -22.33318673279856 -17.00376679140546, -22.29704609402757 -16.90276047256235, -22.3734870679685 -16.68912226225063, -22.43309942964606 -16.4511363741548, -22.46909804531847 -16.20845341993838, -22.48113622863798 -15.96341056911447, -22.46909804531847 -15.71836771829057, -22.43309942964606 -15.47568476407415, -22.40572505302204 -15.36640012664985, -22.42770850858644 -15.21819970725584, -22.43543587636467 -15.18735032582566, -22.47143449203709 -14.94466737160924, -22.48347267535659 -14.69962452078534, -22.47143449203709 -14.45458166996143, -22.43543587636467 -14.21189871574502, -22.37582351468712 -13.97391282764918, -22.29317150663481 -13.74291593987261, -22.29056292959623 -13.73740056711855, -22.29289905870317 -13.68984756671441, -22.29252178711778 -13.68216802717211, -22.31377473535278 -13.62277001599185, -22.37338709703034 -13.38478412789601, -22.40938571270275 -13.14210117367959, -22.42142389602226 -12.89705832285569, -22.40938571270275 -12.65201547203179, -22.37338709703034 -12.40933251781537, -22.31377473535278 -12.17134662971954, -22.23112272730048 -11.94034974194297, -22.19817821472779 -11.87069442245198, -22.19792766193782 -11.8655943032475, -22.16192904626541 -11.62291134903108, -22.10231668458785 -11.38492546093525, -22.01966467653555 -11.15392857315868, -21.99191048529292 -11.09524726609872, -21.92842458012701 -10.91781604746789, -21.8468060799781 -10.74524822781346, -21.92173834994376 -10.5868172541232, -22.00439035799606 -10.35582036634663, -22.01967276381155 -10.29480958237682, -22.06069364785215 -10.23949932305483, -22.18682277796667 -10.02906558257082, -22.291718448374 -9.807282321418555, -22.37437045642631 -9.576285433641985, -22.43398281810386 -9.33829954554615, -22.46998143377628 -9.09561659132973, -22.48201961709579 -8.850573740505828, -22.46998143377628 -8.605530889681926, -22.4573686685416 -8.520502533151651, -22.45836137069585 -8.500295616589442, -22.44973433808717 -8.324688333623628, -22.46112672765752 -8.24788708155117, -22.47316491097703 -8.002844230727268, -22.46112672765752 -7.757801379903367, -22.4251281119851 -7.515118425686947, -22.36551575030755 -7.277132537591112, -22.28286374225524 -7.046135649814543, -22.27337292135948 -7.026068995003135, -22.26191986068643 -6.792936589265861, -22.23700130787304 -6.624949351462579, -22.27702191722613 -6.465178122962197, -22.31302053289855 -6.222495168745778, -22.32505871621806 -5.977452317921876, -22.31302053289855 -5.732409467097974, -22.29913718581248 -5.638815543489387, -22.30871515529535 -5.443851495767794, -22.29667697197584 -5.198808644943893, -22.29060748755867 -5.157891504620128, -22.33815811338089 -5.024996408232262, -22.39777047505845 -4.787010520136427, -22.41659300653852 -4.660119320014077, -22.42566673888573 -4.623894949929971, -22.46166535455815 -4.381211995713552, -22.47370353787766 -4.13616914488965, -22.46166535455815 -3.891126294065749, -22.42631024597718 -3.652781512278879, -22.4441467206235 -3.532537767370365, -22.456184903943 -3.287494916546463, -22.4441467206235 -3.042452065722562, -22.40814810495108 -2.799769111506142, -22.40429375712431 -2.784381692441201, -22.4058295706438 -2.753119490067372, -22.42652472864004 -2.613604067413182, -22.43856291195954 -2.36856121658928, -22.42889752836875 -2.171817813823874, -22.46220332702011 -1.947288357391422, -22.47424151033962 -1.702245506567521, -22.46220332702011 -1.457202655743619, -22.42620471134769 -1.214519701527199, -22.36718807520162 -0.9789120830667674, -22.35689086573897 -0.7693075692219906, -22.32089225006656 -0.5266246150055711, -22.261279888389 -0.2886387269097357, -22.20425046928654 -0.1292521779944437, -22.23865998358758 -0.03308402793069509, -22.29827234526513 0.2049018601651402, -22.33427096093755 0.4475848143815596, -22.34532001016119 0.6724933781402493, -22.35146943767771 0.7139494510634626, -22.36350762099722 0.9589923018873644, -22.3592771699918 1.045105110367362, -22.38658792514858 1.154135756656995, -22.422586540821 1.396818710873414, -22.43462472414051 1.641861561697316, -22.422586540821 1.886904412521218, -22.38658792514858 2.129587366737637, -22.37396184882762 2.1799934889219, -22.38695198811661 2.216298496123226, -22.44656434979417 2.454284384219061, -22.48256296546658 2.69696733843548, -22.49460114878609 2.942010189259382, -22.48256296546658 3.187053040083284, -22.44656434979417 3.429735994299703, -22.38695198811661 3.667721882395539, -22.38282310228573 3.679261345251841, -22.40482289476282 3.827571899165153, -22.41686107808233 4.072614749989055, -22.40482289476282 4.317657600812956, -22.36882427909041 4.560340555029376, -22.30921191741285 4.798326443125212, -22.30467603942607 4.811003372857128, -22.36363753509564 4.975789714039571, -22.42324989677319 5.213775602135406, -22.45924851244561 5.456458556351826, -22.47128669576512 5.701501407175727, -22.45924851244561 5.946544257999629, -22.42520472119385 6.176048856423258, -22.43263431641783 6.22613511901725, -22.44467249973734 6.471177969841151, -22.43263431641783 6.716220820665053, -22.39663570074542 6.958903774881473, -22.39454427325957 6.967253221432506, -22.394861026681 6.969388599547307, -22.4068992100005 7.214431450371209, -22.394861026681 7.459474301195111, -22.36111420259841 7.686976909581786, -22.37179943577599 7.904479827593563, -22.35976125245649 8.149522678417465, -22.32376263678407 8.392205632633884, -22.26415027510652 8.630191520729721, -22.2200347057179 8.75348627752272, -22.21708918363268 8.813443756967004, -22.18109056796027 9.056126711183422, -22.12147820628271 9.294112599279259, -22.03882619823041 9.525109487055827, -22.00373838951193 9.599296425506701, -22.04396671166407 9.711727054073364, -22.05359014051572 9.732074084850684, -22.13624214856803 9.963070972627253, -22.19585451024558 10.20105686072309, -22.231853125918 10.44373981493951, -22.2438913092375 10.68878266576341, -22.231853125918 10.93382551658731, -22.19678075951196 11.1702642054589, -22.25477895783326 11.29289109286717, -22.33743096588557 11.52388798064374, -22.39704332756312 11.76187386873957, -22.43304194323554 12.00455682295599, -22.44508012655504 12.2495996737799, -22.43304194323554 12.4946425246038, -22.39704332756312 12.73732547882022, -22.33743096588557 12.97531136691605, -22.25477895783326 13.20630825469262, -22.14988328742593 13.42809151584489, -22.10462297699719 13.50360378180867, -22.16716011951175 13.67838338646343, -22.22677248118931 13.91636927455927, -22.26277109686172 14.15905222877569, -22.26462335331059 14.19675577495375, -22.29302006696381 14.31012181058106, -22.32901868263623 14.55280476479748, -22.34105686595574 14.79784761562138, -22.33192658845886 14.98369868361621, -22.39050818812954 15.21756953911278, -22.42650680380195 15.4602524933292, -22.43547952265877 15.64289638152731, -22.44403823256925 15.6770646667903, -22.48003684824166 15.91974762100672, -22.49207503156117 16.16479047183062, -22.48003684824166 16.40983332265453, -22.44403823256925 16.65251627687095, -22.40636946919279 16.80289840992767, -22.41197150930309 16.84066429670454, -22.4240096926226 17.08570714752844, -22.41197150930309 17.33074999835235, -22.38181414347826 17.53405444473314, -22.38305833385616 17.55938052168966, -22.37260135853582 17.7722371442781, -22.37766358477907 17.80636390156245, -22.38970176809858 18.05140675238635, -22.37766358477907 18.29644960321025, -22.35761020545555 18.4316385054875, -22.35423385062678 18.50036578689496, -22.37025623714802 18.60837994304902, -22.38229442046752 18.85342279387292, -22.37025623714802 19.09846564469682, -22.3342576214756 19.34114859891324, -22.30537123841755 19.45646950438467, -22.32604178702352 19.5958190240056, -22.33807997034302 19.8408618748295, -22.32604178702352 20.0859047256534, -22.2900431713511 20.32858767986982, -22.23043080967355 20.56657356796565, -22.14777880162124 20.79757045574222, -22.04288313121391 21.01935371689449, -21.91675400109939 21.22978745737851, -21.77060610374987 21.42684508523861, -21.60584692330939 21.60862882779587, -21.42406318075214 21.77338800823634, -21.22700555289203 21.91953590558586, -21.01657181240802 22.04566503570039, -20.79478855125575 22.15056070610771, -20.56379166347918 22.23321271416002, -20.4307583865337 22.26653581530638, -20.41830449611981 22.27242606679497, -20.18730760834324 22.35507807484727, -19.9493217202474 22.41469043652483, -19.70663876603098 22.45068905219724, -19.46159591520708 22.46272723551675, -19.21655306438318 22.45068905219724, -18.97387011016676 22.41469043652483, -18.73588422207093 22.35507807484728, -18.64505406713305 22.32257852574262, -18.40782727181207 22.3820007445785, -18.16514431759565 22.41799936025091, -17.92010146677175 22.43003754357042, -17.67505861594785 22.41799936025091, -17.5503671284345 22.399503125313, -17.43587274407975 22.41648676288385, -17.19082989325585 22.42852494620336, -16.94578704243195 22.41648676288385, -16.89031477907391 22.40825822991765, -16.82115409860222 22.41851724775424, -16.57611124777833 22.43055543107375, -16.39788303796649 22.42179964058564, -16.35038438081903 22.43369743482768, -16.10770142660261 22.46969605050009, -15.86265857577871 22.4817342338196, -15.61761572495481 22.46969605050009, -15.37493277073839 22.43369743482768, -15.13694688264255 22.37408507315013, -14.90594999486599 22.29143306509782, -14.8206581025195 22.25109300434882, -14.71557451981399 22.22477093715091, -14.65976147368973 22.20480070992366, -14.48458465159365 22.1788156830242, -14.45234634580798 22.17074040780624, -14.29831807419653 22.20932248134571, -14.05563511998011 22.24532109701812, -14.02162334345316 22.24699198845396, -13.99875298466096 22.2527207151063, -13.86995584245114 22.27182596638811, -13.81075298923094 22.29300908598844, -13.57276710113511 22.352621447666, -13.33008414691869 22.38862006333841, -13.08504129609479 22.40065824665792, -12.83999844527089 22.38862006333841, -12.60371436525269 22.35357063098932, -12.54382727719349 22.37499857372977, -12.30584138909765 22.43461093540733, -12.06315843488124 22.47060955107974, -11.81811558405734 22.48264773439925, -11.57307273323344 22.47060955107974, -11.33038977901702 22.43461093540733, -11.29538315086152 22.42584223153411, -11.23826008938479 22.42864850759365, -10.99321723856089 22.41661032427414, -10.75053428434447 22.38061170860173, -10.51254839624864 22.32099934692418, -10.33580272181398 22.25775873339386, -10.18534084118114 22.31159485512403, -9.947354953085307 22.37120721680159, -9.704671998868889 22.407205832474, -9.459629148044989 22.41924401579351, -9.214586297221089 22.407205832474, -9.04471806358278 22.38200826028587, -9.005397594027519 22.38393995108657, -8.793185646901277 22.43709627663851, -8.550502692684859 22.47309489231092, -8.305459841860959 22.48513307563043, -8.060416991037059 22.47309489231092, -7.81773403682064 22.43709627663851, -7.624786122499572 22.38876534010497, -7.42410576579648 22.39862413384041, -7.179062914972579 22.3865859505209, -6.93637996075616 22.35058733484848, -6.698394072660326 22.29097497317093, -6.541298596980119 22.23476531317993, -6.535699926618456 22.2350403582177, -6.290657075794555 22.22300217489819, -6.047974121578137 22.18700355922577, -6.045368531132135 22.18635089279545, -5.849769324545464 22.23534594346918, -5.740285956380461 22.25158626700496, -5.519323966714309 22.30693436411426, -5.276641012497891 22.34293297978667, -5.03159816167399 22.35497116310618, -4.78655531085009 22.34293297978667, -4.543872356633671 22.30693436411426, -4.462919229365399 22.28665666134685, -4.385824222448885 22.30596795527529, -4.143141268232466 22.34196657094771, -3.898098417408566 22.35400475426722, -3.653055566584665 22.34196657094771, -3.410372612368247 22.30596795527529, -3.383074108523836 22.29913003602953, -3.198321286899955 22.32653552827561, -2.953278436076054 22.33857371159512, -2.765340328481469 22.32934090441736, -2.64678250665151 22.37176157137471, -2.408796618555676 22.43137393305226, -2.166113664339258 22.46737254872468, -1.921070813515357 22.47941073204419, -1.676027962691456 22.46737254872468, -1.433345008475038 22.43137393305226, -1.195359120379203 22.37176157137471, -1.142651755126477 22.35290257453187, -0.9413867209710468 22.32304772693349, -0.7244596559357803 22.26871032582958, -0.5518773903080429 22.27718874886595, -0.3068345394841422 22.26515056554645, -0.0641515852677238 22.22915194987403, -0.03697761262200187 22.22234522406968, 0.0234066550944344 22.23747069573335, 0.2660896093108527 22.27346931140577, 0.5111324601347533 22.28550749472527, 0.756175310958654 22.27346931140577, 0.9988582651750725 22.23747069573335, 1.124606770200215 22.205972334961, 1.299512951183388 22.28869679765171, 1.530509838959956 22.37134880570402, 1.540541675798155 22.37386165001876, 1.580150144942097 22.38803378689097, 1.818136033037931 22.44764614856852, 2.06081898725435 22.48364476424094, 2.305861838078251 22.49568294756045, 2.550904688902151 22.48364476424094, 2.585818149549957 22.47846584157736, 2.636750143146877 22.48096796997526, 2.881792993970778 22.46892978665575, 3.124475948187196 22.43293117098334, 3.362461836283031 22.37331880930579, 3.405605077979647 22.35788191059068, 3.646083997305915 22.36969588233315, 3.891126848129816 22.35765769901364, 4.133809802346234 22.32165908334122, 4.371795690442069 22.26204672166367, 4.602792578218637 22.17939471361137, 4.74349612212289 22.11284689350158, 4.862426595900769 22.16909681837858, 5.093423483677336 22.25174882643089, 5.33140937177317 22.31136118810844, 5.574092325989588 22.34735980378086, 5.71264440274838 22.35416643084103, 5.788609578672952 22.38134720540751, 6.026595466768787 22.44095956708507, 6.269278420985205 22.47695818275748, 6.514321271809106 22.48899636607699, 6.759364122633007 22.47695818275748, 7.002047076849425 22.44095956708507, 7.045062493122757 22.43018476622139, 7.172998475183696 22.44916227646209, 7.418041326007597 22.4612004597816, 7.663084176831497 22.44916227646209, 7.905767131047916 22.41316366078968, 8.14375301914375 22.35355129911213, 8.374749906920318 22.27089929105982, 8.502525895102208 22.21046574944508, 8.674222684091824 22.14903165601327, 8.730173203256816 22.12256903125539, 8.755476828124921 22.12890725933043, 8.928144125486533 22.15452003340014, 9.056924723896049 22.21542872026604, 9.287921611672617 22.29808072831835, 9.525907499768453 22.35769308999591, 9.768590453984871 22.39369170566832, 10.01363330480877 22.40572988898783, 10.25867615563267 22.39369170566832, 10.38434897519156 22.37504990387232, 10.54562876847384 22.38297307204775, 10.79067161929774 22.37093488872825, 11.03335457351416 22.33493627305583, 11.27134046160999 22.27532391137828, 11.50233734938656 22.19267190332598, 11.5620735362037 22.1644187911154, 11.62238858930415 22.1614557025629, 11.65303800255386 22.15690929158103, 11.69067400012796 22.15875822957978, 11.93571685095186 22.14672004626027, 12.17839980516828 22.11072143058786, 12.41638569326412 22.05110906891031, 12.60921408285645 21.98211396788231, 12.61413707018288 21.98444236747987, 12.84513395795945 22.06709437553218, 13.08311984605528 22.12670673720973, 13.3258028002717 22.16270535288215, 13.5708456510956 22.17474353620165, 13.8158885019195 22.16270535288215, 14.0115966916425 22.13367478529024, 14.24606942960151 22.19240714866933, 14.48875238381793 22.22840576434175, 14.73379523464183 22.24044394766126, 14.83509011495141 22.23546764929387, 14.84302222492603 22.23830580362489, 15.08100811302187 22.29791816530244, 15.32369106723829 22.33391678097486, 15.56873391806219 22.34595496429436, 15.81377676888609 22.33391678097486, 16.05645972310251 22.29791816530244, 16.19915562030759 22.26217470377977, 16.35886794836413 22.31932068852286, 16.59685383645996 22.37893305020042, 16.83953679067638 22.41493166587283, 17.08457964150028 22.42696984919234, 17.32962249232418 22.41493166587283, 17.35406316190014 22.41130623501518, 17.36686412505037 22.41193510600877, 17.61190697587427 22.39989692268926, 17.85458993009069 22.36389830701685, 18.01708231883724 22.3231960825055, 18.18753309746713 22.38418434630179, 18.42551898556296 22.44379670797935, 18.66820193977938 22.47979532365176, 18.91324479060328 22.49183350697127, 19.15828764142718 22.47979532365176, 19.4009705956436 22.44379670797935, 19.63895648373943 22.38418434630179, 19.869953371516 22.30153233824949, 19.96551028205333 22.25633728547234, 19.9853426039062 22.24924116724643, 20.20712586505847 22.1443454968391, 20.41755960554248 22.01821636672458, 20.61461723340259 21.87206846937505, 20.79640097595984 21.70730928893459, 20.96116015640032 21.52552554637733, 20.97836787083578 21.50232362935326, 21.02993804195481 21.46407658377149, 21.1524925145701 21.35299968446598, 21.17995449857986 21.3365396046974, 21.37701212643996 21.19039170734787, 21.55879586899722 21.0256325269074, 21.72355504943769 20.84384878435015, 21.86970294678721 20.64679115649004, 21.99583207690174 20.43635741600603, 22.10072774730907 20.21457415485376, 22.18337975536138 19.9835772670772, 22.24299211703893 19.74559137898136, 22.27899073271135 19.50290842476495, 22.29102891603086 19.25786557394105, 22.29102891603086 19.25786557394103, 22.27899073271135 19.01282272311713, 22.25965275264398 18.88245665087605, 22.30806847593428 18.68917024884808, 22.3440670916067 18.44648729463166, 22.35610527492621 18.20144444380776, 22.35610527492621 18.20144444380774, 22.3440670916067 17.95640159298384, 22.32364979959007 17.81875939060629, 22.32637898934617 17.8111318162174, 22.38599135102372 17.57314592812157, 22.42198996669614 17.33046297390515, 22.43402815001565 17.08542012308125, 22.43402815001565 17.08542012308123, 22.42198996669614 16.84037727225733, 22.38599135102373 16.59769431804091, 22.32637898934617 16.35970842994507, 22.24372698129387 16.1287115421685, 22.13883131088654 15.90692828101623, 22.06904229209649 15.79049233750846, 22.10726844121714 15.70966993577967, 22.18992044926945 15.47867304800311, 22.24953281094701 15.24068715990727, 22.28553142661942 14.99800420569085, 22.29756960993893 14.75296135486695, 22.29756960993893 14.75296135486693, 22.28553142661942 14.50791850404303, 22.25769045232944 14.3202299009467, 22.29909198906613 14.15494570130185, 22.33509060473855 13.91226274708543, 22.34712878805806 13.66721989626153, 22.34712878805806 13.66721989626151, 22.33509060473855 13.42217704543761, 22.29909198906613 13.17949409122119, 22.23947962738858 12.94150820312535, 22.15682761933628 12.71051131534878, 22.1439806270021 12.68334863222938, 22.19843347304785 12.46596068515155, 22.23443208872027 12.22327773093513, 22.24647027203978 11.97823488011123, 22.24647027203978 11.97823488011121, 22.23443208872027 11.73319202928731, 22.22014157634299 11.63685322024689, 22.29170552965104 11.48554395377313, 22.37435753770335 11.25454706599656, 22.4339698993809 11.01656117790073, 22.46996851505332 10.77387822368431, 22.48200669837283 10.52883537286041, 22.48200669837283 10.52883537286039, 22.46996851505332 10.28379252203649, 22.43396989938091 10.04110956782007, 22.37435753770335 9.803123679724234, 22.34931049101803 9.733121873734932, 22.34643056114344 9.674499554410479, 22.31043194547102 9.431816600194061, 22.29103373003705 9.354374583175842, 22.30688482479567 9.310073741086473, 22.36649718647323 9.07208785299064, 22.40249580214564 8.829404898774222, 22.41453398546516 8.584362047950322, 22.41453398546516 8.5843620479503, 22.41010307540168 8.494168801603886, 22.43814828827776 8.382206035739104, 22.47414690395017 8.139523081522686, 22.48618508726968 7.894480230698785, 22.48618508726968 7.894480230698765, 22.47414690395017 7.649437379874864, 22.43814828827776 7.406754425658445, 22.3785359266002 7.16876853756261, 22.36084912120376 7.119337227936076, 22.36638055208554 7.082047349912735, 22.37841873540505 6.837004499088834, 22.37841873540505 6.837004499088813, 22.36638055208554 6.591961648264912, 22.35609034175698 6.522590685093183, 22.36222582230357 6.397700109463268, 22.36222582230357 6.397700109463248, 22.35018763898406 6.152657258639347, 22.31418902331165 5.909974304422928, 22.25457666163409 5.671988416327093, 22.17192465358179 5.440991528550525, 22.14187238184646 5.377451338525399, 22.13631459835018 5.264320056500067, 22.11639472283721 5.130031163807564, 22.14119387758969 5.060722169358346, 22.20080623926725 4.822736281262513, 22.20182312370297 4.815881003237257, 22.28678781110266 4.636238265065981, 22.36943981915496 4.405241377289414, 22.42905218083252 4.167255489193581, 22.46505079650493 3.924572534977163, 22.47708897982444 3.679529684153262, 22.47708897982444 3.679529684153241, 22.46505079650494 3.43448683332934, 22.42905218083252 3.191803879112921, 22.42622722872951 3.18052603813927, 22.41556802494946 2.963552960686345, 22.37956940927705 2.720870006469926, 22.37655704668347 2.708843980878516, 22.37665731548945 2.70816802349524, 22.38869549880896 2.463125172671339, 22.38869549880896 2.463125172671319, 22.37665731548946 2.218082321847417, 22.34065869981704 1.975399367630999, 22.31304697431726 1.86516718037985, 22.32294718632245 1.837497941417382, 22.38255954800001 1.599512053321549, 22.41855816367242 1.356829099105131, 22.43059634699193 1.11178624828123, 22.43059634699193 1.111786248281209, 22.41855816367243 0.866743397457308, 22.38255954800001 0.6240604432408892, 22.37015764437406 0.5745492686213595, 22.37034038738471 0.5740385361211262, 22.42995274906226 0.3360526480252923, 22.46595136473468 0.09336969380887428, 22.46983284362373 0.0143603759458221, 22.47762299880658 -0.03815658445019221, 22.48966118212609 -0.2831994352740928, 22.48966118212609 -0.2831994352741134, 22.47762299880658 -0.5282422860980147, 22.44162438313417 -0.7709252403144335, 22.38201202145661 -1.008911128410269, 22.33733720919316 -1.1337688643328, 22.35960416230565 -1.222663524140609, 22.39560277797807 -1.465346478357027, 22.40764096129758 -1.710389329180928, 22.40764096129758 -1.710389329180948, 22.39560277797807 -1.95543218000485, 22.35960416230566 -2.198115134221269, 22.2999918006281 -2.436101022317104, 22.2173397925758 -2.667097910093672, 22.12083454788258 -2.871141106569248, 22.10890457508578 -3.113981281601384, 22.09753928949359 -3.190599813495125, 22.11425511370344 -3.225942454346874, 22.19690712175575 -3.456939342123441, 22.2565194834333 -3.694925230219274, 22.27796733187449 -3.83951487968404, 22.30329211813286 -3.893059641470262, 22.38594412618517 -4.124056529246829, 22.44555648786272 -4.362042417342662, 22.48155510353514 -4.604725371559081, 22.49359328685465 -4.849768222382981, 22.49359328685465 -4.849768222383002, 22.48155510353514 -5.094811073206903, 22.46639370225972 -5.197020938304527, 22.4742428718067 -5.35679445490105, 22.4742428718067 -5.35679445490107, 22.47305251707211 -5.381024682163306, 22.47387421054751 -5.386564089619583, 22.48591239386703 -5.631606940443484, 22.48591239386703 -5.631606940443504, 22.47387421054752 -5.876649791267405, 22.4378755948751 -6.119332745483824, 22.37826323319755 -6.357318633579659, 22.37581970840857 -6.364147827869776, 22.33416054986185 -6.530460511431846, 22.25150854180955 -6.761457399208414, 22.14661287140222 -6.983240660360684, 22.14070790264234 -6.993092505548669, 22.14375134269476 -7.001598350679505, 22.20336370437232 -7.239584238775338, 22.23936232004473 -7.482267192991756, 22.25140050336424 -7.727310043815657, 22.25140050336424 -7.727310043815677, 22.23936232004474 -7.972352894639578, 22.20336370437232 -8.215035848855997, 22.17904866103241 -8.312106943180988, 22.25649042501777 -8.528542174291447, 22.31610278669532 -8.76652806238728, 22.32621521933611 -8.834700545738135, 22.32751997111001 -8.838347082660768, 22.38713233278757 -9.076332970756601, 22.42313094845998 -9.319015924973019, 22.4351691317795 -9.564058775796919, 22.4351691317795 -9.564058775796941, 22.42313094845999 -9.809101626620842, 22.38713233278757 -10.05178458083726, 22.32751997111002 -10.2897704689331, 22.24486796305771 -10.52076735670966, 22.13997229265038 -10.74255061786193, 22.04314691805991 -10.90409399590901, 22.03406561057082 -10.96531519812561, 22.06337928494946 -11.16293193877699, 22.06660106476485 -11.22851277350407, 22.08298043995721 -11.27429006049709, 22.14259280163477 -11.51227594859293, 22.17739333308725 -11.74688207506299, 22.23461413935799 -11.90680351528065, 22.29422650103554 -12.14478940337648, 22.33022511670796 -12.3874723575929, 22.34226330002747 -12.6325152084168, 22.34226330002747 -12.63251520841682, 22.33022511670796 -12.87755805924072, 22.30844502746572 -13.02438749425295, 22.34721627930011 -13.13274588408515, 22.40682864097767 -13.37073177218098, 22.44282725665008 -13.6134147263974, 22.45486543996959 -13.8584575772213, 22.45486543996959 -13.85845757722132, 22.44282725665009 -14.10350042804522, 22.40682864097767 -14.34618338226164, 22.40667909943321 -14.3467803855721, 22.41507202806971 -14.3802868348902, 22.45107064374212 -14.62296978910662, 22.46310882706163 -14.86801263993052, 22.46310882706163 -14.86801263993054, 22.45107064374212 -15.11305549075445, 22.41507202806971 -15.35573844497086, 22.37320910548004 -15.52286460019147, 22.36618663574583 -15.66581025551359, 22.33018802007341 -15.90849320973001, 22.30832089851852 -15.99579165248403, 22.31582939514044 -16.01677649474516, 22.375441756818 -16.254762382841, 22.41144037249041 -16.49744533705741, 22.42347855580992 -16.74248818788131, 22.42347855580992 -16.74248818788134, 22.41144037249041 -16.98753103870524, 22.375441756818 -17.23021399292166, 22.31582939514044 -17.46819988101749, 22.311953937675 -17.47903105904116, 22.3018715319233 -17.68426314290183, 22.26587291625088 -17.92694609711825, 22.20998447691467 -18.15006525387409, 22.19944723477361 -18.36455574513298, 22.1634486191012 -18.6072386993494, 22.10383625742364 -18.84522458744524, 22.04941193378315 -18.99733038228982, 22.04364672206227 -19.11468396282544, 22.00764810638986 -19.35736691704186, 21.97709163753492 -19.47935517875256, 21.97514755279599 -19.51892793271611, 21.93914893712358 -19.76161088693253, 21.87953657544602 -19.99959677502837, 21.79688456739372 -20.23059366280494, 21.69198889698639 -20.45237692395721, 21.64536097446595 -20.53017091284831, 21.58631018238545 -20.69520682078059, 21.48141451197812 -20.91699008193286, 21.35528538186359 -21.12742382241687, 21.20913748451407 -21.32448145027698, 21.0443783040736 -21.50626519283423, 20.86259456151634 -21.67102437327471, 20.66553693365623 -21.81717227062423, 20.45510319317222 -21.94330140073875, 20.23331993201996 -22.04819707114608, 20.00232304424339 -22.13084907919839, 19.76433715614755 -22.19046144087594, 19.52165420193113 -22.22646005654836, 19.27661135110723 -22.23849823986787, 19.03156850028333 -22.22646005654836, 18.78888554606691 -22.19046144087594, 18.73887089664221 -22.17793342337652, 18.4973901430078 -22.18979661208253, 18.41784477514719 -22.18588879874579, 18.41349373531924 -22.18697867748596, 18.17081078110282 -22.22297729315838, 17.98787095563432 -22.23196455048102, 17.79768532119148 -22.27960357192466, 17.55500236697506 -22.31560218759708, 17.30995951615116 -22.32764037091659, 17.06491666532726 -22.31560218759708, 16.82223371111084 -22.27960357192466, 16.584247823015 -22.21999121024711, 16.4666967485392 -22.177930763253, 16.4099384081795 -22.1695114587847, 16.28838315841296 -22.13906345377539, 16.17480211986003 -22.19278328422008, 15.94380523208346 -22.27543529227239, 15.70581934398762 -22.33504765394994, 15.46313638977121 -22.37104626962236, 15.2180935389473 -22.38308445294187, 14.9730506881234 -22.37104626962236, 14.73036773390698 -22.33504765394994, 14.65305301275748 -22.31568132447116, 14.45362419243909 -22.3452637954767, 14.20858134161519 -22.35730197879621, 13.96353849079129 -22.3452637954767, 13.73523415567763 -22.31139804646833, 13.59984162375042 -22.33148163139707, 13.35479877292652 -22.34351981471658, 13.10975592210262 -22.33148163139707, 12.8670729678862 -22.29548301572466, 12.62908707979036 -22.2358706540471, 12.61296722408551 -22.23010287744914, 12.51509107260605 -22.26512352442874, 12.27710518451022 -22.3247358861063, 12.0344222302938 -22.36073450177871, 11.7893793794699 -22.37277268509822, 11.544336528646 -22.36073450177871, 11.42614034228609 -22.34320175375175, 11.41367609013224 -22.34505065090392, 11.17312139811863 -22.35686834511981, 11.0505742524468 -22.38756480711927, 10.96704756934117 -22.39995482014355, 10.89076207090825 -22.41906334275269, 10.64807911669183 -22.4550619584251, 10.40303626586793 -22.46710014174461, 10.15799341504403 -22.4550619584251, 9.915310460827609 -22.41906334275269, 9.678390165997076 -22.35971789829296, 9.461434530251323 -22.39190022677332, 9.216391679427421 -22.40393841009282, 8.971348828603521 -22.39190022677332, 8.859745401813472 -22.37534542224775, 8.640809946866888 -22.43018589883542, 8.39812699265047 -22.46618451450784, 8.153084141826568 -22.47822269782734, 7.908041291002667 -22.46618451450784, 7.665358336786248 -22.43018589883542, 7.654227093690167 -22.42739766758913, 7.631127550771891 -22.42853247536382, 7.386084699947989 -22.41649429204432, 7.14340174573157 -22.3804956763719, 6.961547070081421 -22.33494345147172, 6.84664652751557 -22.31789956602152, 6.757417223308805 -22.33113548297839, 6.512374372484904 -22.3431736662979, 6.267331521661002 -22.33113548297839, 6.024648567444583 -22.29513686730598, 5.786662679348748 -22.23552450562843, 5.679434149468312 -22.19715752414906, 5.639137942656076 -22.19517789845072, 5.527756450060979 -22.2116997821483, 5.309290253954825 -22.22243233814412, 5.171949898293681 -22.28738948868023, 4.940953010517113 -22.37004149673253, 4.702967122421279 -22.42965385841009, 4.46028416820486 -22.4656524740825, 4.215241317380959 -22.47769065740201, 3.970198466557057 -22.4656524740825, 3.750904670430335 -22.43312331227301, 3.67246061444501 -22.44475938878411, 3.427417763621108 -22.45679757210362, 3.182374912797207 -22.44475938878411, 2.939691958580788 -22.40876077311169, 2.701706070484953 -22.34914841143414, 2.470709182708385 -22.26649640338184, 2.400539054657536 -22.233308404494, 2.382213028549373 -22.23058999531359, 2.144227140453538 -22.17097763363604, 1.91323025267697 -22.08832562558374, 1.772685063718212 -22.02185270178525, 1.740138581807164 -22.04599081787381, 1.529704841323152 -22.17211994798834, 1.307921580170883 -22.27701561839567, 1.076924692394315 -22.35966762644798, 0.8389388042984798 -22.41927998812553, 0.5962558500820608 -22.45527860379795, 0.3512129992581597 -22.46731678711745, 0.1061701484342584 -22.45527860379795, -0.04851836590371944 -22.43233273026278, -0.2461837018222049 -22.42262205500048, -0.4888666560386239 -22.38662343932807, -0.726852544134459 -22.32701107765052, -0.9578494319110273 -22.24435906959821, -1.125708636819748 -22.16496757836726, -1.139764547714639 -22.17161552911361, -1.370761435491207 -22.25426753716592, -1.608747323587042 -22.31387989884347, -1.851430277803461 -22.34987851451589, -2.096473128627362 -22.3619166978354, -2.341515979451263 -22.34987851451589, -2.455727455302357 -22.33293684245731, -2.55442301821249 -22.34757694624723, -2.617898317366901 -22.37028877144683, -2.855884205462736 -22.42990113312439, -3.098567159679154 -22.4658997487968, -3.343610010503056 -22.47793793211631, -3.588652861326957 -22.4658997487968, -3.831335815543376 -22.42990113312439, -3.907954521318272 -22.41070914642104, -3.975896008872092 -22.41404689767321, -4.183715500617316 -22.44487400721096, -4.428758351441217 -22.45691219053047, -4.673801202265119 -22.44487400721096, -4.916484156481538 -22.40887539153854, -5.020084557130864 -22.38292484210529, -5.020419078409338 -22.38304453573263, -5.258404966505172 -22.44265689741019, -5.501087920721591 -22.4786555130826, -5.746130771545492 -22.49069369640211, -5.991173622369394 -22.4786555130826, -6.123693431593027 -22.45899805631302, -6.264189488772653 -22.46590018500729, -6.509232339596555 -22.45386200168778, -6.751915293812974 -22.41786338601537, -6.989901181908809 -22.35825102433781, -7.220898069685378 -22.27559901628551, -7.347294079158904 -22.2158181559913, -7.532152849094219 -22.18839694779783, -7.598927497924632 -22.17167076899446, -7.804850114037394 -22.22325169913918, -8.047533068253813 -22.2592503148116, -8.292575919077715 -22.27128849813111, -8.537618769901615 -22.2592503148116, -8.565029213837116 -22.25518435954156, -8.633110179045801 -22.27954411840584, -8.871096067141636 -22.3391564800834, -9.113779021358054 -22.37515509575582, -9.358821872181956 -22.38719327907532, -9.603864723005856 -22.37515509575582, -9.846547677222276 -22.3391564800834, -10.08453356531811 -22.27954411840584, -10.09791748181934 -22.27475527650811, -10.14016295582498 -22.29473589765361, -10.37115984360155 -22.37738790570592, -10.60914573169738 -22.43700026738347, -10.8518286859138 -22.47299888305589, -11.0968715367377 -22.48503706637539, -11.3419143875616 -22.47299888305589, -11.58459734177802 -22.43700026738347, -11.75310292370707 -22.3947918163908, -11.90532691377749 -22.43292194093173, -12.1480098679939 -22.46892055660414, -12.39305271881781 -22.48095873992365, -12.63809556964171 -22.46892055660414, -12.88077852385813 -22.43292194093173, -13.11876441195396 -22.37330957925418, -13.20218180754802 -22.34346235785346, -13.35693885800207 -22.35106508422189, -13.60198170882597 -22.33902690090238, -13.84466466304239 -22.30302828522996, -14.08265055113823 -22.24341592355241, -14.31364743891479 -22.16076391550011, -14.50430349127707 -22.07059031842225))"; - - // epl result for union - String eplWKT = "MULTIPOLYGON (((-15.90174522590254 -22.49823229650554, -15.65670237507864 -22.48619411318603, -15.41401942086222 -22.45019549751362, -15.17603353276639 -22.39058313583606, -14.94503664498982 -22.30793112778376, -14.72325338383755 -22.20303545737643, -14.51281964335354 -22.0769063272619, -14.50430349127707 -22.07059031842225, -14.31364743891479 -22.16076391550011, -14.08265055113823 -22.24341592355241, -13.84466466304239 -22.30302828522996, -13.60198170882597 -22.33902690090238, -13.35693885800207 -22.35106508422189, -13.20218180754802 -22.34346235785346, -13.11876441195396 -22.37330957925418, -12.88077852385813 -22.43292194093173, -12.63809556964171 -22.46892055660414, -12.39305271881781 -22.48095873992365, -12.1480098679939 -22.46892055660414, -11.90532691377749 -22.43292194093173, -11.75310292370707 -22.3947918163908, -11.58459734177802 -22.43700026738347, -11.3419143875616 -22.47299888305589, -11.0968715367377 -22.48503706637539, -10.8518286859138 -22.47299888305589, -10.60914573169738 -22.43700026738347, -10.37115984360155 -22.37738790570592, -10.14016295582498 -22.29473589765361, -10.09791748181934 -22.27475527650811, -10.08453356531811 -22.27954411840584, -9.846547677222276 -22.3391564800834, -9.603864723005856 -22.37515509575582, -9.358821872181956 -22.38719327907532, -9.113779021358054 -22.37515509575582, -8.871096067141636 -22.3391564800834, -8.633110179045801 -22.27954411840584, -8.565029213837116 -22.25518435954156, -8.537618769901615 -22.2592503148116, -8.292575919077715 -22.27128849813111, -8.047533068253813 -22.2592503148116, -7.804850114037394 -22.22325169913918, -7.598927497924632 -22.17167076899446, -7.532152849094219 -22.18839694779783, -7.347294079158904 -22.2158181559913, -7.220898069685378 -22.27559901628551, -6.989901181908809 -22.35825102433781, -6.751915293812974 -22.41786338601537, -6.509232339596555 -22.45386200168778, -6.264189488772653 -22.46590018500729, -6.123693431593027 -22.45899805631302, -5.991173622369394 -22.4786555130826, -5.746130771545492 -22.49069369640211, -5.501087920721591 -22.4786555130826, -5.258404966505172 -22.44265689741019, -5.020419078409338 -22.38304453573263, -5.020084557130864 -22.38292484210529, -4.916484156481538 -22.40887539153854, -4.673801202265119 -22.44487400721096, -4.428758351441217 -22.45691219053047, -4.183715500617316 -22.44487400721096, -3.975896008872092 -22.41404689767321, -3.907954521318273 -22.41070914642104, -3.831335815543376 -22.42990113312439, -3.588652861326957 -22.4658997487968, -3.343610010503056 -22.47793793211631, -3.098567159679154 -22.4658997487968, -2.855884205462736 -22.42990113312439, -2.617898317366901 -22.37028877144683, -2.55442301821249 -22.34757694624723, -2.455727455302357 -22.33293684245731, -2.341515979451263 -22.34987851451589, -2.096473128627362 -22.3619166978354, -1.851430277803461 -22.34987851451589, -1.608747323587042 -22.31387989884347, -1.370761435491207 -22.25426753716592, -1.139764547714639 -22.17161552911361, -1.125708636819748 -22.16496757836726, -0.9578494319110273 -22.24435906959821, -0.726852544134459 -22.32701107765052, -0.4888666560386239 -22.38662343932807, -0.2461837018222049 -22.42262205500048, -0.04851836590371948 -22.43233273026278, 0.1061701484342584 -22.45527860379795, 0.3512129992581597 -22.46731678711745, 0.5962558500820608 -22.45527860379795, 0.8389388042984798 -22.41927998812553, 1.076924692394315 -22.35966762644798, 1.307921580170883 -22.27701561839567, 1.529704841323152 -22.17211994798834, 1.740138581807164 -22.04599081787381, 1.772685063718212 -22.02185270178525, 1.91323025267697 -22.08832562558374, 2.144227140453538 -22.17097763363604, 2.382213028549373 -22.23058999531359, 2.400539054657536 -22.233308404494, 2.470709182708385 -22.26649640338184, 2.701706070484953 -22.34914841143414, 2.939691958580788 -22.40876077311169, 3.182374912797207 -22.44475938878411, 3.427417763621108 -22.45679757210362, 3.67246061444501 -22.44475938878411, 3.750904670430335 -22.43312331227301, 3.970198466557057 -22.4656524740825, 4.215241317380959 -22.47769065740201, 4.46028416820486 -22.4656524740825, 4.702967122421279 -22.42965385841009, 4.940953010517113 -22.37004149673253, 5.171949898293681 -22.28738948868023, 5.309290253954825 -22.22243233814412, 5.527756450060979 -22.2116997821483, 5.63913794265608 -22.19517789845072, 5.679434149468313 -22.19715752414906, 5.786662679348748 -22.23552450562843, 6.024648567444583 -22.29513686730598, 6.267331521661002 -22.33113548297839, 6.512374372484904 -22.3431736662979, 6.757417223308805 -22.33113548297839, 6.846646527515573 -22.31789956602152, 6.961547070081421 -22.33494345147172, 7.14340174573157 -22.3804956763719, 7.386084699947989 -22.41649429204432, 7.631127550771891 -22.42853247536382, 7.654227093690167 -22.42739766758913, 7.665358336786248 -22.43018589883542, 7.908041291002667 -22.46618451450784, 8.153084141826568 -22.47822269782734, 8.39812699265047 -22.46618451450784, 8.640809946866888 -22.43018589883542, 8.859745401813472 -22.37534542224775, 8.971348828603521 -22.39190022677332, 9.216391679427421 -22.40393841009282, 9.461434530251323 -22.39190022677332, 9.678390165997076 -22.35971789829296, 9.915310460827609 -22.41906334275269, 10.15799341504403 -22.4550619584251, 10.40303626586793 -22.46710014174461, 10.64807911669183 -22.4550619584251, 10.89076207090825 -22.41906334275269, 10.96704756934117 -22.39995482014355, 11.0505742524468 -22.38756480711927, 11.17312139811863 -22.35686834511981, 11.41367609013224 -22.34505065090392, 11.42614034228609 -22.34320175375175, 11.544336528646 -22.36073450177871, 11.7893793794699 -22.37277268509822, 12.0344222302938 -22.36073450177871, 12.27710518451022 -22.3247358861063, 12.51509107260605 -22.26512352442874, 12.61296722408551 -22.23010287744914, 12.62908707979036 -22.2358706540471, 12.8670729678862 -22.29548301572466, 13.10975592210262 -22.33148163139707, 13.35479877292652 -22.34351981471658, 13.59984162375042 -22.33148163139707, 13.73523415567763 -22.31139804646833, 13.96353849079129 -22.3452637954767, 14.20858134161519 -22.35730197879621, 14.45362419243909 -22.3452637954767, 14.65305301275748 -22.31568132447116, 14.73036773390698 -22.33504765394994, 14.9730506881234 -22.37104626962236, 15.2180935389473 -22.38308445294187, 15.46313638977121 -22.37104626962236, 15.70581934398762 -22.33504765394994, 15.94380523208346 -22.27543529227239, 16.17480211986003 -22.19278328422008, 16.28838315841296 -22.13906345377539, 16.4099384081795 -22.1695114587847, 16.4666967485392 -22.177930763253, 16.584247823015 -22.21999121024711, 16.82223371111084 -22.27960357192466, 17.06491666532726 -22.31560218759708, 17.30995951615116 -22.32764037091659, 17.55500236697506 -22.31560218759708, 17.79768532119148 -22.27960357192466, 17.98787095563432 -22.23196455048102, 18.17081078110282 -22.22297729315838, 18.41349373531924 -22.18697867748596, 18.41784477514719 -22.18588879874579, 18.4973901430078 -22.18979661208253, 18.73887089664221 -22.17793342337652, 18.78888554606691 -22.19046144087594, 19.03156850028333 -22.22646005654836, 19.27661135110723 -22.23849823986787, 19.52165420193113 -22.22646005654836, 19.76433715614755 -22.19046144087594, 20.00232304424339 -22.13084907919839, 20.23331993201996 -22.04819707114608, 20.45510319317222 -21.94330140073875, 20.66553693365623 -21.81717227062423, 20.86259456151634 -21.67102437327471, 21.0443783040736 -21.50626519283423, 21.20913748451407 -21.32448145027698, 21.35528538186359 -21.12742382241687, 21.48141451197812 -20.91699008193286, 21.58631018238545 -20.69520682078059, 21.64536097446595 -20.53017091284831, 21.69198889698639 -20.45237692395721, 21.79688456739372 -20.23059366280494, 21.87953657544602 -19.99959677502837, 21.93914893712358 -19.76161088693253, 21.97514755279599 -19.51892793271611, 21.97709163753492 -19.47935517875256, 22.00764810638986 -19.35736691704186, 22.04364672206227 -19.11468396282544, 22.04941193378315 -18.99733038228982, 22.10383625742364 -18.84522458744524, 22.1634486191012 -18.6072386993494, 22.19944723477361 -18.36455574513298, 22.20998447691467 -18.15006525387409, 22.26587291625088 -17.92694609711825, 22.3018715319233 -17.68426314290183, 22.311953937675 -17.47903105904117, 22.31582939514044 -17.46819988101749, 22.375441756818 -17.23021399292166, 22.41144037249041 -16.98753103870524, 22.42347855580992 -16.74248818788132, 22.41144037249041 -16.49744533705741, 22.375441756818 -16.254762382841, 22.31582939514044 -16.01677649474516, 22.30832089851852 -15.99579165248403, 22.33018802007341 -15.90849320973001, 22.36618663574583 -15.66581025551359, 22.37320910548004 -15.52286460019147, 22.41507202806971 -15.35573844497086, 22.45107064374212 -15.11305549075445, 22.46310882706163 -14.86801263993053, 22.45107064374212 -14.62296978910662, 22.41507202806971 -14.3802868348902, 22.40667909943321 -14.3467803855721, 22.40682864097767 -14.34618338226164, 22.44282725665009 -14.10350042804522, 22.45486543996959 -13.85845757722131, 22.44282725665008 -13.6134147263974, 22.40682864097767 -13.37073177218098, 22.34721627930011 -13.13274588408515, 22.30844502746573 -13.02438749425295, 22.33022511670796 -12.87755805924072, 22.34226330002747 -12.63251520841681, 22.33022511670796 -12.3874723575929, 22.29422650103554 -12.14478940337648, 22.23461413935799 -11.90680351528065, 22.17739333308725 -11.74688207506299, 22.14259280163477 -11.51227594859293, 22.08298043995721 -11.27429006049709, 22.06660106476485 -11.22851277350407, 22.06337928494946 -11.16293193877699, 22.03406561057082 -10.96531519812561, 22.04314691805991 -10.90409399590901, 22.13997229265038 -10.74255061786193, 22.24486796305771 -10.52076735670966, 22.32751997111002 -10.2897704689331, 22.38713233278757 -10.05178458083726, 22.42313094845999 -9.809101626620842, 22.4351691317795 -9.56405877579693, 22.42313094845998 -9.319015924973019, 22.38713233278757 -9.076332970756601, 22.32751997111001 -8.838347082660768, 22.32621521933611 -8.834700545738135, 22.31610278669532 -8.76652806238728, 22.25649042501777 -8.528542174291447, 22.17904866103241 -8.312106943180988, 22.20336370437232 -8.215035848855997, 22.23936232004474 -7.972352894639578, 22.25140050336424 -7.727310043815667, 22.23936232004473 -7.482267192991756, 22.20336370437232 -7.239584238775338, 22.14375134269476 -7.001598350679505, 22.14070790264234 -6.993092505548669, 22.14661287140222 -6.983240660360684, 22.25150854180955 -6.761457399208414, 22.33416054986185 -6.530460511431846, 22.37581970840857 -6.364147827869776, 22.37826323319755 -6.357318633579659, 22.4378755948751 -6.119332745483824, 22.47387421054752 -5.876649791267405, 22.48591239386703 -5.631606940443493, 22.47387421054751 -5.386564089619583, 22.47305251707211 -5.381024682163304, 22.4742428718067 -5.35679445490106, 22.46639370225972 -5.197020938304531, 22.48155510353514 -5.094811073206903, 22.49359328685465 -4.849768222382991, 22.48155510353514 -4.604725371559081, 22.44555648786272 -4.362042417342662, 22.38594412618517 -4.124056529246829, 22.30329211813286 -3.893059641470262, 22.27796733187449 -3.83951487968404, 22.2565194834333 -3.694925230219274, 22.19690712175575 -3.456939342123441, 22.11425511370344 -3.225942454346874, 22.09753928949359 -3.190599813495125, 22.10890457508578 -3.113981281601384, 22.12083454788258 -2.87114110656925, 22.2173397925758 -2.667097910093672, 22.2999918006281 -2.436101022317104, 22.35960416230566 -2.198115134221269, 22.39560277797807 -1.95543218000485, 22.40764096129758 -1.710389329180938, 22.39560277797807 -1.465346478357027, 22.35960416230565 -1.222663524140609, 22.33733720919316 -1.1337688643328, 22.38201202145661 -1.008911128410269, 22.44162438313417 -0.7709252403144335, 22.47762299880658 -0.5282422860980147, 22.48966118212609 -0.2831994352741031, 22.47762299880658 -0.03815658445019221, 22.46983284362372 0.01436037594582373, 22.46595136473468 0.09336969380887428, 22.42995274906226 0.3360526480252923, 22.37034038738471 0.5740385361211262, 22.37015764437406 0.5745492686213597, 22.38255954800001 0.6240604432408892, 22.41855816367243 0.866743397457308, 22.43059634699193 1.11178624828122, 22.41855816367242 1.356829099105131, 22.38255954800001 1.599512053321549, 22.32294718632245 1.837497941417382, 22.31304697431726 1.86516718037985, 22.34065869981704 1.975399367630999, 22.37665731548946 2.218082321847417, 22.38869549880896 2.463125172671329, 22.37665731548945 2.70816802349524, 22.37655704668347 2.708843980878516, 22.37956940927705 2.720870006469926, 22.41556802494946 2.963552960686345, 22.42622722872951 3.180526038139268, 22.42905218083252 3.191803879112921, 22.46505079650494 3.43448683332934, 22.47708897982444 3.679529684153251, 22.46505079650493 3.924572534977163, 22.42905218083252 4.167255489193581, 22.36943981915496 4.405241377289414, 22.28678781110266 4.636238265065981, 22.20182312370297 4.815881003237257, 22.20080623926725 4.822736281262513, 22.14119387758969 5.060722169358346, 22.11639472283721 5.130031163807564, 22.13631459835018 5.264320056500067, 22.14187238184646 5.377451338525397, 22.17192465358179 5.440991528550525, 22.25457666163409 5.671988416327093, 22.31418902331165 5.909974304422928, 22.35018763898406 6.152657258639347, 22.36222582230357 6.397700109463258, 22.35609034175698 6.522590685093183, 22.36638055208554 6.591961648264912, 22.37841873540505 6.837004499088824, 22.36638055208554 7.082047349912735, 22.36084912120376 7.119337227936076, 22.3785359266002 7.16876853756261, 22.43814828827776 7.406754425658445, 22.47414690395017 7.649437379874864, 22.48618508726968 7.894480230698775, 22.47414690395017 8.139523081522686, 22.43814828827776 8.382206035739104, 22.41010307540168 8.494168801603886, 22.41453398546516 8.584362047950311, 22.40249580214564 8.829404898774222, 22.36649718647323 9.07208785299064, 22.30688482479567 9.310073741086473, 22.29103373003705 9.354374583175842, 22.31043194547102 9.431816600194061, 22.34643056114344 9.674499554410479, 22.34931049101803 9.73312187373493, 22.37435753770335 9.803123679724234, 22.43396989938091 10.04110956782007, 22.46996851505332 10.28379252203649, 22.48200669837283 10.5288353728604, 22.46996851505332 10.77387822368431, 22.4339698993809 11.01656117790073, 22.37435753770335 11.25454706599656, 22.29170552965104 11.48554395377313, 22.22014157634299 11.63685322024689, 22.23443208872027 11.73319202928731, 22.24647027203978 11.97823488011122, 22.23443208872027 12.22327773093513, 22.19843347304785 12.46596068515155, 22.1439806270021 12.68334863222938, 22.15682761933628 12.71051131534878, 22.23947962738858 12.94150820312535, 22.29909198906613 13.17949409122119, 22.33509060473855 13.42217704543761, 22.34712878805806 13.66721989626152, 22.33509060473855 13.91226274708543, 22.29909198906613 14.15494570130185, 22.25769045232944 14.3202299009467, 22.28553142661942 14.50791850404303, 22.29756960993893 14.75296135486694, 22.28553142661942 14.99800420569085, 22.24953281094701 15.24068715990727, 22.18992044926945 15.47867304800311, 22.10726844121714 15.70966993577967, 22.06904229209649 15.79049233750846, 22.13883131088654 15.90692828101623, 22.24372698129387 16.1287115421685, 22.32637898934617 16.35970842994507, 22.38599135102373 16.59769431804091, 22.42198996669614 16.84037727225733, 22.43402815001565 17.08542012308124, 22.42198996669614 17.33046297390515, 22.38599135102372 17.57314592812157, 22.32637898934617 17.8111318162174, 22.32364979959007 17.81875939060629, 22.3440670916067 17.95640159298384, 22.35610527492621 18.20144444380775, 22.3440670916067 18.44648729463166, 22.30806847593428 18.68917024884808, 22.25965275264398 18.88245665087605, 22.27899073271135 19.01282272311713, 22.29102891603086 19.25786557394104, 22.27899073271135 19.50290842476495, 22.24299211703893 19.74559137898136, 22.18337975536138 19.9835772670772, 22.10072774730907 20.21457415485376, 21.99583207690174 20.43635741600603, 21.86970294678721 20.64679115649004, 21.72355504943769 20.84384878435015, 21.55879586899722 21.0256325269074, 21.37701212643996 21.19039170734787, 21.17995449857986 21.3365396046974, 21.1524925145701 21.35299968446598, 21.02993804195481 21.46407658377149, 20.97836787083578 21.50232362935326, 20.96116015640032 21.52552554637733, 20.79640097595984 21.70730928893459, 20.61461723340259 21.87206846937505, 20.41755960554248 22.01821636672458, 20.20712586505847 22.1443454968391, 19.9853426039062 22.24924116724643, 19.96551028205333 22.25633728547234, 19.869953371516 22.30153233824949, 19.63895648373943 22.38418434630179, 19.4009705956436 22.44379670797935, 19.15828764142718 22.47979532365176, 18.91324479060328 22.49183350697127, 18.66820193977938 22.47979532365176, 18.42551898556296 22.44379670797935, 18.18753309746713 22.38418434630179, 18.01708231883724 22.3231960825055, 17.85458993009069 22.36389830701685, 17.61190697587427 22.39989692268926, 17.36686412505037 22.41193510600877, 17.35406316190014 22.41130623501518, 17.32962249232418 22.41493166587283, 17.08457964150028 22.42696984919234, 16.83953679067638 22.41493166587283, 16.59685383645996 22.37893305020042, 16.35886794836413 22.31932068852286, 16.19915562030759 22.26217470377977, 16.05645972310251 22.29791816530244, 15.81377676888609 22.33391678097486, 15.56873391806219 22.34595496429436, 15.32369106723829 22.33391678097486, 15.08100811302187 22.29791816530244, 14.84302222492603 22.23830580362489, 14.83509011495141 22.23546764929387, 14.73379523464183 22.24044394766126, 14.48875238381793 22.22840576434175, 14.24606942960151 22.19240714866933, 14.0115966916425 22.13367478529024, 13.8158885019195 22.16270535288215, 13.5708456510956 22.17474353620165, 13.3258028002717 22.16270535288215, 13.08311984605528 22.12670673720973, 12.84513395795945 22.06709437553218, 12.61413707018288 21.98444236747987, 12.60921408285645 21.98211396788231, 12.41638569326412 22.05110906891031, 12.17839980516828 22.11072143058786, 11.93571685095186 22.14672004626027, 11.69067400012796 22.15875822957978, 11.65303800255386 22.15690929158103, 11.62238858930415 22.1614557025629, 11.5620735362037 22.1644187911154, 11.50233734938656 22.19267190332598, 11.27134046160999 22.27532391137828, 11.03335457351416 22.33493627305583, 10.79067161929774 22.37093488872825, 10.54562876847384 22.38297307204775, 10.38434897519156 22.37504990387232, 10.25867615563267 22.39369170566832, 10.01363330480877 22.40572988898783, 9.768590453984871 22.39369170566832, 9.525907499768453 22.35769308999591, 9.287921611672617 22.29808072831835, 9.056924723896049 22.21542872026604, 8.928144125486533 22.15452003340014, 8.755476828124921 22.12890725933043, 8.730173203256818 22.12256903125539, 8.674222684091824 22.14903165601327, 8.502525895102208 22.21046574944508, 8.374749906920318 22.27089929105982, 8.14375301914375 22.35355129911213, 7.905767131047916 22.41316366078968, 7.663084176831497 22.44916227646209, 7.418041326007597 22.4612004597816, 7.172998475183696 22.44916227646209, 7.045062493122757 22.43018476622139, 7.002047076849425 22.44095956708507, 6.759364122633007 22.47695818275748, 6.514321271809106 22.48899636607699, 6.269278420985205 22.47695818275748, 6.026595466768787 22.44095956708507, 5.788609578672952 22.38134720540751, 5.71264440274838 22.35416643084103, 5.574092325989588 22.34735980378086, 5.33140937177317 22.31136118810844, 5.093423483677336 22.25174882643089, 4.862426595900769 22.16909681837858, 4.743496122122889 22.11284689350158, 4.602792578218637 22.17939471361137, 4.371795690442069 22.26204672166367, 4.133809802346234 22.32165908334122, 3.891126848129816 22.35765769901364, 3.646083997305915 22.36969588233315, 3.405605077979647 22.35788191059068, 3.362461836283031 22.37331880930579, 3.124475948187196 22.43293117098334, 2.881792993970778 22.46892978665575, 2.636750143146877 22.48096796997526, 2.585818149549957 22.47846584157736, 2.550904688902151 22.48364476424094, 2.305861838078251 22.49568294756045, 2.06081898725435 22.48364476424094, 1.818136033037931 22.44764614856852, 1.580150144942097 22.38803378689097, 1.540541675798155 22.37386165001876, 1.530509838959956 22.37134880570402, 1.299512951183388 22.28869679765171, 1.124606770200216 22.205972334961, 0.9988582651750725 22.23747069573335, 0.756175310958654 22.27346931140577, 0.5111324601347533 22.28550749472527, 0.2660896093108527 22.27346931140577, 0.0234066550944344 22.23747069573335, -0.03697761262200187 22.22234522406968, -0.0641515852677238 22.22915194987403, -0.3068345394841422 22.26515056554645, -0.5518773903080429 22.27718874886595, -0.7244596559357803 22.26871032582958, -0.9413867209710468 22.32304772693349, -1.142651755126477 22.35290257453187, -1.195359120379203 22.37176157137471, -1.433345008475038 22.43137393305226, -1.676027962691456 22.46737254872468, -1.921070813515357 22.47941073204419, -2.166113664339258 22.46737254872468, -2.408796618555676 22.43137393305226, -2.64678250665151 22.37176157137471, -2.765340328481469 22.32934090441736, -2.953278436076054 22.33857371159512, -3.198321286899955 22.32653552827561, -3.383074108523836 22.29913003602953, -3.410372612368247 22.30596795527529, -3.653055566584665 22.34196657094771, -3.898098417408566 22.35400475426722, -4.143141268232466 22.34196657094771, -4.385824222448885 22.30596795527529, -4.462919229365399 22.28665666134685, -4.543872356633671 22.30693436411426, -4.78655531085009 22.34293297978667, -5.03159816167399 22.35497116310618, -5.276641012497891 22.34293297978667, -5.519323966714309 22.30693436411426, -5.740285956380461 22.25158626700496, -5.849769324545464 22.23534594346918, -6.045368531132135 22.18635089279545, -6.047974121578137 22.18700355922577, -6.290657075794555 22.22300217489819, -6.535699926618456 22.2350403582177, -6.541298596980119 22.23476531317993, -6.698394072660326 22.29097497317093, -6.93637996075616 22.35058733484848, -7.179062914972579 22.3865859505209, -7.42410576579648 22.39862413384041, -7.624786122499572 22.38876534010497, -7.81773403682064 22.43709627663851, -8.060416991037059 22.47309489231092, -8.305459841860959 22.48513307563043, -8.550502692684859 22.47309489231092, -8.793185646901277 22.43709627663851, -9.005397594027517 22.38393995108657, -9.044718063582776 22.38200826028587, -9.214586297221089 22.407205832474, -9.459629148044989 22.41924401579351, -9.704671998868889 22.407205832474, -9.947354953085307 22.37120721680159, -10.18534084118114 22.31159485512403, -10.33580272181398 22.25775873339386, -10.51254839624864 22.32099934692418, -10.75053428434447 22.38061170860173, -10.99321723856089 22.41661032427414, -11.23826008938479 22.42864850759365, -11.29538315086152 22.42584223153411, -11.33038977901702 22.43461093540733, -11.57307273323344 22.47060955107974, -11.81811558405734 22.48264773439925, -12.06315843488124 22.47060955107974, -12.30584138909765 22.43461093540733, -12.54382727719349 22.37499857372977, -12.60371436525269 22.35357063098932, -12.83999844527089 22.38862006333841, -13.08504129609479 22.40065824665792, -13.33008414691869 22.38862006333841, -13.57276710113511 22.352621447666, -13.81075298923094 22.29300908598844, -13.86995584245114 22.27182596638811, -13.99875298466096 22.2527207151063, -14.02162334345316 22.24699198845396, -14.05563511998011 22.24532109701812, -14.29831807419653 22.20932248134571, -14.45234634580798 22.17074040780624, -14.48458465159365 22.1788156830242, -14.65976147368973 22.20480070992366, -14.71557451981399 22.22477093715091, -14.8206581025195 22.25109300434882, -14.90594999486599 22.29143306509782, -15.13694688264255 22.37408507315013, -15.37493277073839 22.43369743482768, -15.61761572495481 22.46969605050009, -15.86265857577871 22.4817342338196, -16.10770142660261 22.46969605050009, -16.35038438081903 22.43369743482768, -16.39788303796649 22.42179964058564, -16.57611124777833 22.43055543107375, -16.82115409860222 22.41851724775424, -16.89031477907391 22.40825822991765, -16.94578704243195 22.41648676288385, -17.19082989325585 22.42852494620336, -17.43587274407975 22.41648676288385, -17.5503671284345 22.399503125313, -17.67505861594785 22.41799936025091, -17.92010146677175 22.43003754357042, -18.16514431759565 22.41799936025091, -18.40782727181207 22.3820007445785, -18.64505406713305 22.32257852574262, -18.73588422207093 22.35507807484728, -18.97387011016676 22.41469043652483, -19.21655306438318 22.45068905219724, -19.46159591520708 22.46272723551675, -19.70663876603098 22.45068905219724, -19.9493217202474 22.41469043652483, -20.18730760834324 22.35507807484727, -20.41830449611981 22.27242606679497, -20.4307583865337 22.26653581530638, -20.56379166347918 22.23321271416002, -20.79478855125575 22.15056070610771, -21.01657181240802 22.04566503570039, -21.22700555289203 21.91953590558586, -21.42406318075214 21.77338800823634, -21.60584692330939 21.60862882779587, -21.77060610374987 21.42684508523861, -21.91675400109939 21.22978745737851, -22.04288313121391 21.01935371689449, -22.14777880162124 20.79757045574222, -22.23043080967355 20.56657356796565, -22.2900431713511 20.32858767986982, -22.32604178702352 20.0859047256534, -22.33807997034302 19.8408618748295, -22.32604178702352 19.5958190240056, -22.30537123841755 19.45646950438467, -22.3342576214756 19.34114859891324, -22.37025623714802 19.09846564469682, -22.38229442046752 18.85342279387292, -22.37025623714802 18.60837994304902, -22.35423385062678 18.50036578689495, -22.35761020545555 18.43163850548751, -22.37766358477907 18.29644960321025, -22.38970176809858 18.05140675238635, -22.37766358477907 17.80636390156245, -22.37260135853582 17.7722371442781, -22.38305833385616 17.55938052168966, -22.38181414347826 17.53405444473314, -22.41197150930309 17.33074999835235, -22.4240096926226 17.08570714752844, -22.41197150930309 16.84066429670454, -22.40636946919279 16.80289840992767, -22.44403823256925 16.65251627687095, -22.48003684824166 16.40983332265453, -22.49207503156117 16.16479047183062, -22.48003684824166 15.91974762100672, -22.44403823256925 15.6770646667903, -22.43547952265877 15.64289638152731, -22.42650680380195 15.4602524933292, -22.39050818812954 15.21756953911278, -22.33192658845886 14.98369868361621, -22.34105686595574 14.79784761562138, -22.32901868263623 14.55280476479748, -22.29302006696381 14.31012181058106, -22.26462335331059 14.19675577495375, -22.26277109686172 14.15905222877569, -22.22677248118931 13.91636927455927, -22.16716011951175 13.67838338646343, -22.10462297699719 13.50360378180867, -22.14988328742593 13.42809151584489, -22.25477895783326 13.20630825469262, -22.33743096588557 12.97531136691605, -22.39704332756312 12.73732547882022, -22.43304194323554 12.4946425246038, -22.44508012655504 12.2495996737799, -22.43304194323554 12.00455682295599, -22.39704332756312 11.76187386873957, -22.33743096588557 11.52388798064374, -22.25477895783326 11.29289109286717, -22.19678075951196 11.1702642054589, -22.231853125918 10.93382551658731, -22.2438913092375 10.68878266576341, -22.231853125918 10.44373981493951, -22.19585451024558 10.20105686072309, -22.13624214856803 9.963070972627253, -22.05359014051572 9.732074084850684, -22.04396671166407 9.711727054073368, -22.00373838951193 9.599296425506699, -22.03882619823041 9.525109487055827, -22.12147820628271 9.294112599279259, -22.18109056796027 9.056126711183422, -22.21708918363268 8.813443756967004, -22.2200347057179 8.75348627752272, -22.26415027510652 8.630191520729721, -22.32376263678407 8.392205632633884, -22.35976125245649 8.149522678417465, -22.37179943577599 7.904479827593563, -22.36111420259841 7.686976909581786, -22.394861026681 7.459474301195111, -22.4068992100005 7.214431450371209, -22.394861026681 6.969388599547307, -22.39454427325957 6.967253221432506, -22.39663570074542 6.958903774881473, -22.43263431641783 6.716220820665053, -22.44467249973734 6.471177969841151, -22.43263431641783 6.22613511901725, -22.42520472119385 6.176048856423258, -22.45924851244561 5.946544257999629, -22.47128669576512 5.701501407175727, -22.45924851244561 5.456458556351826, -22.42324989677319 5.213775602135406, -22.36363753509564 4.975789714039571, -22.30467603942607 4.811003372857127, -22.30921191741285 4.798326443125212, -22.36882427909041 4.560340555029376, -22.40482289476282 4.317657600812956, -22.41686107808233 4.072614749989055, -22.40482289476282 3.827571899165153, -22.38282310228573 3.679261345251841, -22.38695198811661 3.667721882395539, -22.44656434979417 3.429735994299703, -22.48256296546658 3.187053040083284, -22.49460114878609 2.942010189259382, -22.48256296546658 2.69696733843548, -22.44656434979417 2.454284384219061, -22.38695198811661 2.216298496123226, -22.37396184882762 2.1799934889219, -22.38658792514858 2.129587366737637, -22.422586540821 1.886904412521218, -22.43462472414051 1.641861561697316, -22.422586540821 1.396818710873414, -22.38658792514858 1.154135756656995, -22.3592771699918 1.045105110367365, -22.36350762099722 0.9589923018873644, -22.35146943767771 0.7139494510634626, -22.34532001016119 0.6724933781402493, -22.33427096093755 0.4475848143815596, -22.29827234526513 0.2049018601651402, -22.23865998358758 -0.03308402793069509, -22.20425046928654 -0.1292521779944436, -22.261279888389 -0.2886387269097357, -22.32089225006656 -0.5266246150055711, -22.35689086573897 -0.7693075692219906, -22.36718807520162 -0.9789120830667672, -22.42620471134769 -1.214519701527199, -22.46220332702011 -1.457202655743619, -22.47424151033962 -1.702245506567521, -22.46220332702011 -1.947288357391422, -22.42889752836875 -2.171817813823874, -22.43856291195954 -2.36856121658928, -22.42652472864004 -2.613604067413182, -22.4058295706438 -2.753119490067378, -22.40429375712431 -2.784381692441204, -22.40814810495108 -2.799769111506142, -22.4441467206235 -3.042452065722562, -22.456184903943 -3.287494916546463, -22.4441467206235 -3.532537767370365, -22.42631024597718 -3.652781512278879, -22.46166535455815 -3.891126294065749, -22.47370353787766 -4.13616914488965, -22.46166535455815 -4.381211995713552, -22.42566673888573 -4.623894949929971, -22.41659300653852 -4.660119320014077, -22.39777047505845 -4.787010520136427, -22.33815811338089 -5.024996408232262, -22.29060748755867 -5.157891504620128, -22.29667697197584 -5.198808644943893, -22.30871515529535 -5.443851495767794, -22.29913718581248 -5.638815543489387, -22.31302053289855 -5.732409467097974, -22.32505871621806 -5.977452317921876, -22.31302053289855 -6.222495168745778, -22.27702191722613 -6.465178122962197, -22.23700130787304 -6.624949351462579, -22.26191986068643 -6.792936589265861, -22.27337292135948 -7.026068995003135, -22.28286374225524 -7.046135649814543, -22.36551575030755 -7.277132537591112, -22.4251281119851 -7.515118425686947, -22.46112672765752 -7.757801379903367, -22.47316491097703 -8.002844230727268, -22.46112672765752 -8.24788708155117, -22.44973433808717 -8.324688333623625, -22.45836137069585 -8.500295616589442, -22.4573686685416 -8.520502533151651, -22.46998143377628 -8.605530889681926, -22.48201961709579 -8.850573740505828, -22.46998143377628 -9.09561659132973, -22.43398281810386 -9.33829954554615, -22.37437045642631 -9.576285433641985, -22.291718448374 -9.807282321418555, -22.18682277796667 -10.02906558257082, -22.06069364785215 -10.23949932305483, -22.01967276381155 -10.29480958237682, -22.00439035799606 -10.35582036634663, -21.92173834994376 -10.5868172541232, -21.8468060799781 -10.74524822781346, -21.92842458012701 -10.91781604746789, -21.99191048529292 -11.09524726609872, -22.01966467653555 -11.15392857315868, -22.10231668458785 -11.38492546093525, -22.16192904626541 -11.62291134903108, -22.19792766193782 -11.8655943032475, -22.19817821472779 -11.87069442245198, -22.23112272730048 -11.94034974194297, -22.31377473535278 -12.17134662971954, -22.37338709703034 -12.40933251781537, -22.40938571270275 -12.65201547203179, -22.42142389602226 -12.89705832285569, -22.40938571270275 -13.14210117367959, -22.37338709703034 -13.38478412789601, -22.31377473535278 -13.62277001599185, -22.29252178711778 -13.68216802717211, -22.29289905870317 -13.68984756671441, -22.29056292959623 -13.73740056711855, -22.29317150663481 -13.74291593987261, -22.37582351468712 -13.97391282764918, -22.43543587636467 -14.21189871574502, -22.47143449203709 -14.45458166996143, -22.48347267535659 -14.69962452078534, -22.47143449203709 -14.94466737160924, -22.43543587636467 -15.18735032582566, -22.42770850858644 -15.21819970725584, -22.40572505302204 -15.36640012664985, -22.43309942964606 -15.47568476407415, -22.46909804531847 -15.71836771829057, -22.48113622863798 -15.96341056911447, -22.46909804531847 -16.20845341993838, -22.43309942964606 -16.4511363741548, -22.3734870679685 -16.68912226225063, -22.29704609402757 -16.90276047256235, -22.33318673279856 -17.00376679140546, -22.39279909447611 -17.2417526795013, -22.42879771014853 -17.48443563371772, -22.44083589346804 -17.72947848454162, -22.42879771014853 -17.97452133536552, -22.39279909447611 -18.21720428958194, -22.3612750894556 -18.34305517218451, -22.38618093327824 -18.41266234260967, -22.4457932949558 -18.65064823070551, -22.48179191062821 -18.89333118492193, -22.49383009394772 -19.13837403574583, -22.48179191062821 -19.38341688656973, -22.46272989236197 -19.51192257546279, -22.47144518575322 -19.68932644793065, -22.45940700243371 -19.93436929875455, -22.4234083867613 -20.17705225297097, -22.36379602508374 -20.41503814106681, -22.28114401703143 -20.64603502884338, -22.1762483466241 -20.86781828999564, -22.05011921650958 -21.07825203047966, -21.90397131916006 -21.27530965833976, -21.73921213871958 -21.45709340089702, -21.55742839616233 -21.62185258133749, -21.36037076830222 -21.76800047868701, -21.14993702781821 -21.89412960880153, -20.92815376666594 -21.99902527920887, -20.69715687888937 -22.08167728726117, -20.45917099079353 -22.14128964893872, -20.42744614576441 -22.14599558515562, -20.37281740980389 -22.17183305301641, -20.14182052202732 -22.25448506106872, -19.90383463393149 -22.31409742274627, -19.66115167971507 -22.35009603841869, -19.63541513605011 -22.3513603937329, -19.53556033746936 -22.37637271868991, -19.29287738325294 -22.41237133436232, -19.04783453242904 -22.42440951768183, -18.80279168160514 -22.41237133436232, -18.56010872738872 -22.37637271868991, -18.32212283929288 -22.31676035701235, -18.15038036764053 -22.25530991806244, -17.93163213536989 -22.26605632960654, -17.86833950280889 -22.2629469619552, -17.85807912611075 -22.2677997587208, -17.62708223833419 -22.35045176677311, -17.38909635023835 -22.41006412845066, -17.14641339602193 -22.44606274412307, -16.90137054519803 -22.45810092744258, -16.65632769437413 -22.44606274412307, -16.4990865892769 -22.42273822951685, -16.38947103094286 -22.45019549751362, -16.14678807672644 -22.48619411318603, -15.90174522590254 -22.49823229650554)))"; - Geometry shapelyGeom = OperatorImportFromWkt.local().execute(0, Geometry.Type.Unknown, shapelyWKT, null); - Geometry eplGeom = OperatorImportFromWkt.local().execute(0, Geometry.Type.Unknown, eplWKT, null); - NonSimpleResult nonSimpleResult = new NonSimpleResult(); - boolean is_simple = OperatorSimplify.local().isSimpleAsFeature(shapelyGeom, null, true, nonSimpleResult, null); - assertFalse(is_simple); - assertTrue(OperatorSimplify.local().isSimpleAsFeature(eplGeom, null, true, nonSimpleResult, null)); - } - - @Test - public void testIDPass() { - int size = 1000; - List points = new ArrayList<>(size); - List pointList = new ArrayList<>(size); - for (int i = 0; i < size; i++) { - double x = randomWithRange(-20, 20); - double y = randomWithRange(-20, 20); - points.add(String.format("Point(%f %f)", x, y)); - pointList.add(new Point(x, y)); - } - - SimpleStringCursor simpleStringCursor = new SimpleStringCursor(points); - OperatorImportFromWktCursor operatorImportFromWktCursor = new OperatorImportFromWktCursor(0, simpleStringCursor); - double [] distances = new double[]{2.5}; - - GeometryCursor operatorBufferCursor = OperatorBuffer.local().execute(operatorImportFromWktCursor, - null, - distances, - Double.NaN, - 0, - true, - null); - - OperatorExportToWkbCursor operatorExportToGeoJsonCursor = new OperatorExportToWkbCursor(0, operatorBufferCursor); - - while (operatorExportToGeoJsonCursor.hasNext()) { - ByteBuffer wkb = operatorExportToGeoJsonCursor.next(); - long id = operatorExportToGeoJsonCursor.getByteBufferID(); - } - } - - static double randomWithRange(double min, double max) { - double range = Math.abs(max - min); - return (Math.random() * range) + (min <= max ? min : max); - } + @Test + public void testQuadTreeIterator() { + int size = 1000; + ArrayDeque bufferedArrayDequ = new ArrayDeque<>(new ArrayList<>(bufferedPointList).subList(0, size)); + SimpleGeometryCursor simpleGeometryCursor = new SimpleGeometryCursor(bufferedArrayDequ); + + HashMap m_quadTreeMap = new HashMap<>(); + Envelope2D quad_envelope2D = new Envelope2D(); + Geometry geometry = null; + Envelope2D geometry_env = new Envelope2D(); + int count_index = 0; + while ((geometry = simpleGeometryCursor.next()) != null) { + geometry.queryEnvelope2D(geometry_env); + quad_envelope2D.merge(geometry_env); + m_quadTreeMap.put(count_index++, geometry); + } + QuadTree quadTree = new QuadTree(quad_envelope2D, 16); + for (Integer element_id : m_quadTreeMap.keySet()) { + m_quadTreeMap.get(element_id).queryEnvelope2D(geometry_env); + quadTree.insert(element_id, geometry_env); + } + + QuadTree.QuadTreeIterator quadTreeIterator = quadTree.getIterator(true); + quadTreeIterator.resetIterator(quad_envelope2D, 0.0); + int element_handle = -1; + List geometryList = new ArrayList<>(); + assertFalse(geometryList.containsAll(m_quadTreeMap.values())); + + int max_height = 0; + while ((element_handle = quadTreeIterator.next()) != -1) { + int element_id = quadTree.getElement(element_handle); + int quad_handle = quadTree.getQuad(element_handle); + + int sub_count = quadTree.getContainedSubTreeElementCount(quad_handle); + int sub_count_2 = quadTree.getSubTreeElementCount(quad_handle); + + int quad_height = quadTree.getHeight(quad_handle); + max_height = quad_height > max_height ? quad_height : max_height; + Envelope2D envelope2D = quadTree.getExtent(quad_handle); + assertTrue(quadTree.hasData(envelope2D, 0.0)); + geometryList.add(m_quadTreeMap.get(element_id)); + } + assertTrue(max_height == 3); + assertEquals(16, quadTree.getMaxHeight()); + + assertTrue(geometryList.containsAll(m_quadTreeMap.values())); + } + + + @Test + public static void testFailedUnionDifferenceTest() { + // shapely result for union + String shapelyWKT = "POLYGON ((-14.50430349127707 -22.07059031842225, -14.51281964335354 -22.0769063272619, -14.72325338383755 -22.20303545737643, -14.94503664498982 -22.30793112778376, -15.17603353276639 -22.39058313583606, -15.41401942086222 -22.45019549751362, -15.65670237507864 -22.48619411318603, -15.90174522590254 -22.49823229650554, -16.14678807672644 -22.48619411318603, -16.38947103094286 -22.45019549751362, -16.4990865892769 -22.42273822951685, -16.65632769437413 -22.44606274412307, -16.90137054519803 -22.45810092744258, -17.14641339602193 -22.44606274412307, -17.38909635023835 -22.41006412845066, -17.62708223833419 -22.35045176677311, -17.85807912611075 -22.2677997587208, -17.86833950280889 -22.2629469619552, -17.93163213536989 -22.26605632960654, -18.15038036764053 -22.25530991806244, -18.32212283929288 -22.31676035701235, -18.56010872738872 -22.37637271868991, -18.80279168160514 -22.41237133436232, -19.04783453242904 -22.42440951768183, -19.29287738325294 -22.41237133436232, -19.53556033746936 -22.37637271868991, -19.63541513605011 -22.3513603937329, -19.66115167971507 -22.35009603841869, -19.90383463393149 -22.31409742274627, -20.14182052202732 -22.25448506106872, -20.37281740980389 -22.17183305301641, -20.42744614576441 -22.14599558515562, -20.45917099079353 -22.14128964893872, -20.69715687888937 -22.08167728726117, -20.92815376666594 -21.99902527920887, -21.14993702781821 -21.89412960880153, -21.36037076830222 -21.76800047868701, -21.55742839616233 -21.62185258133749, -21.73921213871958 -21.45709340089702, -21.90397131916006 -21.27530965833976, -22.05011921650958 -21.07825203047966, -22.1762483466241 -20.86781828999564, -22.28114401703143 -20.64603502884338, -22.36379602508374 -20.41503814106681, -22.4234083867613 -20.17705225297097, -22.45940700243371 -19.93436929875455, -22.47144518575322 -19.68932644793065, -22.46272989236197 -19.51192257546279, -22.48179191062821 -19.38341688656973, -22.49383009394772 -19.13837403574583, -22.48179191062821 -18.89333118492193, -22.4457932949558 -18.65064823070551, -22.38618093327824 -18.41266234260967, -22.3612750894556 -18.34305517218451, -22.39279909447611 -18.21720428958194, -22.42879771014853 -17.97452133536552, -22.44083589346804 -17.72947848454162, -22.42879771014853 -17.48443563371772, -22.39279909447611 -17.2417526795013, -22.33318673279856 -17.00376679140546, -22.29704609402757 -16.90276047256235, -22.3734870679685 -16.68912226225063, -22.43309942964606 -16.4511363741548, -22.46909804531847 -16.20845341993838, -22.48113622863798 -15.96341056911447, -22.46909804531847 -15.71836771829057, -22.43309942964606 -15.47568476407415, -22.40572505302204 -15.36640012664985, -22.42770850858644 -15.21819970725584, -22.43543587636467 -15.18735032582566, -22.47143449203709 -14.94466737160924, -22.48347267535659 -14.69962452078534, -22.47143449203709 -14.45458166996143, -22.43543587636467 -14.21189871574502, -22.37582351468712 -13.97391282764918, -22.29317150663481 -13.74291593987261, -22.29056292959623 -13.73740056711855, -22.29289905870317 -13.68984756671441, -22.29252178711778 -13.68216802717211, -22.31377473535278 -13.62277001599185, -22.37338709703034 -13.38478412789601, -22.40938571270275 -13.14210117367959, -22.42142389602226 -12.89705832285569, -22.40938571270275 -12.65201547203179, -22.37338709703034 -12.40933251781537, -22.31377473535278 -12.17134662971954, -22.23112272730048 -11.94034974194297, -22.19817821472779 -11.87069442245198, -22.19792766193782 -11.8655943032475, -22.16192904626541 -11.62291134903108, -22.10231668458785 -11.38492546093525, -22.01966467653555 -11.15392857315868, -21.99191048529292 -11.09524726609872, -21.92842458012701 -10.91781604746789, -21.8468060799781 -10.74524822781346, -21.92173834994376 -10.5868172541232, -22.00439035799606 -10.35582036634663, -22.01967276381155 -10.29480958237682, -22.06069364785215 -10.23949932305483, -22.18682277796667 -10.02906558257082, -22.291718448374 -9.807282321418555, -22.37437045642631 -9.576285433641985, -22.43398281810386 -9.33829954554615, -22.46998143377628 -9.09561659132973, -22.48201961709579 -8.850573740505828, -22.46998143377628 -8.605530889681926, -22.4573686685416 -8.520502533151651, -22.45836137069585 -8.500295616589442, -22.44973433808717 -8.324688333623628, -22.46112672765752 -8.24788708155117, -22.47316491097703 -8.002844230727268, -22.46112672765752 -7.757801379903367, -22.4251281119851 -7.515118425686947, -22.36551575030755 -7.277132537591112, -22.28286374225524 -7.046135649814543, -22.27337292135948 -7.026068995003135, -22.26191986068643 -6.792936589265861, -22.23700130787304 -6.624949351462579, -22.27702191722613 -6.465178122962197, -22.31302053289855 -6.222495168745778, -22.32505871621806 -5.977452317921876, -22.31302053289855 -5.732409467097974, -22.29913718581248 -5.638815543489387, -22.30871515529535 -5.443851495767794, -22.29667697197584 -5.198808644943893, -22.29060748755867 -5.157891504620128, -22.33815811338089 -5.024996408232262, -22.39777047505845 -4.787010520136427, -22.41659300653852 -4.660119320014077, -22.42566673888573 -4.623894949929971, -22.46166535455815 -4.381211995713552, -22.47370353787766 -4.13616914488965, -22.46166535455815 -3.891126294065749, -22.42631024597718 -3.652781512278879, -22.4441467206235 -3.532537767370365, -22.456184903943 -3.287494916546463, -22.4441467206235 -3.042452065722562, -22.40814810495108 -2.799769111506142, -22.40429375712431 -2.784381692441201, -22.4058295706438 -2.753119490067372, -22.42652472864004 -2.613604067413182, -22.43856291195954 -2.36856121658928, -22.42889752836875 -2.171817813823874, -22.46220332702011 -1.947288357391422, -22.47424151033962 -1.702245506567521, -22.46220332702011 -1.457202655743619, -22.42620471134769 -1.214519701527199, -22.36718807520162 -0.9789120830667674, -22.35689086573897 -0.7693075692219906, -22.32089225006656 -0.5266246150055711, -22.261279888389 -0.2886387269097357, -22.20425046928654 -0.1292521779944437, -22.23865998358758 -0.03308402793069509, -22.29827234526513 0.2049018601651402, -22.33427096093755 0.4475848143815596, -22.34532001016119 0.6724933781402493, -22.35146943767771 0.7139494510634626, -22.36350762099722 0.9589923018873644, -22.3592771699918 1.045105110367362, -22.38658792514858 1.154135756656995, -22.422586540821 1.396818710873414, -22.43462472414051 1.641861561697316, -22.422586540821 1.886904412521218, -22.38658792514858 2.129587366737637, -22.37396184882762 2.1799934889219, -22.38695198811661 2.216298496123226, -22.44656434979417 2.454284384219061, -22.48256296546658 2.69696733843548, -22.49460114878609 2.942010189259382, -22.48256296546658 3.187053040083284, -22.44656434979417 3.429735994299703, -22.38695198811661 3.667721882395539, -22.38282310228573 3.679261345251841, -22.40482289476282 3.827571899165153, -22.41686107808233 4.072614749989055, -22.40482289476282 4.317657600812956, -22.36882427909041 4.560340555029376, -22.30921191741285 4.798326443125212, -22.30467603942607 4.811003372857128, -22.36363753509564 4.975789714039571, -22.42324989677319 5.213775602135406, -22.45924851244561 5.456458556351826, -22.47128669576512 5.701501407175727, -22.45924851244561 5.946544257999629, -22.42520472119385 6.176048856423258, -22.43263431641783 6.22613511901725, -22.44467249973734 6.471177969841151, -22.43263431641783 6.716220820665053, -22.39663570074542 6.958903774881473, -22.39454427325957 6.967253221432506, -22.394861026681 6.969388599547307, -22.4068992100005 7.214431450371209, -22.394861026681 7.459474301195111, -22.36111420259841 7.686976909581786, -22.37179943577599 7.904479827593563, -22.35976125245649 8.149522678417465, -22.32376263678407 8.392205632633884, -22.26415027510652 8.630191520729721, -22.2200347057179 8.75348627752272, -22.21708918363268 8.813443756967004, -22.18109056796027 9.056126711183422, -22.12147820628271 9.294112599279259, -22.03882619823041 9.525109487055827, -22.00373838951193 9.599296425506701, -22.04396671166407 9.711727054073364, -22.05359014051572 9.732074084850684, -22.13624214856803 9.963070972627253, -22.19585451024558 10.20105686072309, -22.231853125918 10.44373981493951, -22.2438913092375 10.68878266576341, -22.231853125918 10.93382551658731, -22.19678075951196 11.1702642054589, -22.25477895783326 11.29289109286717, -22.33743096588557 11.52388798064374, -22.39704332756312 11.76187386873957, -22.43304194323554 12.00455682295599, -22.44508012655504 12.2495996737799, -22.43304194323554 12.4946425246038, -22.39704332756312 12.73732547882022, -22.33743096588557 12.97531136691605, -22.25477895783326 13.20630825469262, -22.14988328742593 13.42809151584489, -22.10462297699719 13.50360378180867, -22.16716011951175 13.67838338646343, -22.22677248118931 13.91636927455927, -22.26277109686172 14.15905222877569, -22.26462335331059 14.19675577495375, -22.29302006696381 14.31012181058106, -22.32901868263623 14.55280476479748, -22.34105686595574 14.79784761562138, -22.33192658845886 14.98369868361621, -22.39050818812954 15.21756953911278, -22.42650680380195 15.4602524933292, -22.43547952265877 15.64289638152731, -22.44403823256925 15.6770646667903, -22.48003684824166 15.91974762100672, -22.49207503156117 16.16479047183062, -22.48003684824166 16.40983332265453, -22.44403823256925 16.65251627687095, -22.40636946919279 16.80289840992767, -22.41197150930309 16.84066429670454, -22.4240096926226 17.08570714752844, -22.41197150930309 17.33074999835235, -22.38181414347826 17.53405444473314, -22.38305833385616 17.55938052168966, -22.37260135853582 17.7722371442781, -22.37766358477907 17.80636390156245, -22.38970176809858 18.05140675238635, -22.37766358477907 18.29644960321025, -22.35761020545555 18.4316385054875, -22.35423385062678 18.50036578689496, -22.37025623714802 18.60837994304902, -22.38229442046752 18.85342279387292, -22.37025623714802 19.09846564469682, -22.3342576214756 19.34114859891324, -22.30537123841755 19.45646950438467, -22.32604178702352 19.5958190240056, -22.33807997034302 19.8408618748295, -22.32604178702352 20.0859047256534, -22.2900431713511 20.32858767986982, -22.23043080967355 20.56657356796565, -22.14777880162124 20.79757045574222, -22.04288313121391 21.01935371689449, -21.91675400109939 21.22978745737851, -21.77060610374987 21.42684508523861, -21.60584692330939 21.60862882779587, -21.42406318075214 21.77338800823634, -21.22700555289203 21.91953590558586, -21.01657181240802 22.04566503570039, -20.79478855125575 22.15056070610771, -20.56379166347918 22.23321271416002, -20.4307583865337 22.26653581530638, -20.41830449611981 22.27242606679497, -20.18730760834324 22.35507807484727, -19.9493217202474 22.41469043652483, -19.70663876603098 22.45068905219724, -19.46159591520708 22.46272723551675, -19.21655306438318 22.45068905219724, -18.97387011016676 22.41469043652483, -18.73588422207093 22.35507807484728, -18.64505406713305 22.32257852574262, -18.40782727181207 22.3820007445785, -18.16514431759565 22.41799936025091, -17.92010146677175 22.43003754357042, -17.67505861594785 22.41799936025091, -17.5503671284345 22.399503125313, -17.43587274407975 22.41648676288385, -17.19082989325585 22.42852494620336, -16.94578704243195 22.41648676288385, -16.89031477907391 22.40825822991765, -16.82115409860222 22.41851724775424, -16.57611124777833 22.43055543107375, -16.39788303796649 22.42179964058564, -16.35038438081903 22.43369743482768, -16.10770142660261 22.46969605050009, -15.86265857577871 22.4817342338196, -15.61761572495481 22.46969605050009, -15.37493277073839 22.43369743482768, -15.13694688264255 22.37408507315013, -14.90594999486599 22.29143306509782, -14.8206581025195 22.25109300434882, -14.71557451981399 22.22477093715091, -14.65976147368973 22.20480070992366, -14.48458465159365 22.1788156830242, -14.45234634580798 22.17074040780624, -14.29831807419653 22.20932248134571, -14.05563511998011 22.24532109701812, -14.02162334345316 22.24699198845396, -13.99875298466096 22.2527207151063, -13.86995584245114 22.27182596638811, -13.81075298923094 22.29300908598844, -13.57276710113511 22.352621447666, -13.33008414691869 22.38862006333841, -13.08504129609479 22.40065824665792, -12.83999844527089 22.38862006333841, -12.60371436525269 22.35357063098932, -12.54382727719349 22.37499857372977, -12.30584138909765 22.43461093540733, -12.06315843488124 22.47060955107974, -11.81811558405734 22.48264773439925, -11.57307273323344 22.47060955107974, -11.33038977901702 22.43461093540733, -11.29538315086152 22.42584223153411, -11.23826008938479 22.42864850759365, -10.99321723856089 22.41661032427414, -10.75053428434447 22.38061170860173, -10.51254839624864 22.32099934692418, -10.33580272181398 22.25775873339386, -10.18534084118114 22.31159485512403, -9.947354953085307 22.37120721680159, -9.704671998868889 22.407205832474, -9.459629148044989 22.41924401579351, -9.214586297221089 22.407205832474, -9.04471806358278 22.38200826028587, -9.005397594027519 22.38393995108657, -8.793185646901277 22.43709627663851, -8.550502692684859 22.47309489231092, -8.305459841860959 22.48513307563043, -8.060416991037059 22.47309489231092, -7.81773403682064 22.43709627663851, -7.624786122499572 22.38876534010497, -7.42410576579648 22.39862413384041, -7.179062914972579 22.3865859505209, -6.93637996075616 22.35058733484848, -6.698394072660326 22.29097497317093, -6.541298596980119 22.23476531317993, -6.535699926618456 22.2350403582177, -6.290657075794555 22.22300217489819, -6.047974121578137 22.18700355922577, -6.045368531132135 22.18635089279545, -5.849769324545464 22.23534594346918, -5.740285956380461 22.25158626700496, -5.519323966714309 22.30693436411426, -5.276641012497891 22.34293297978667, -5.03159816167399 22.35497116310618, -4.78655531085009 22.34293297978667, -4.543872356633671 22.30693436411426, -4.462919229365399 22.28665666134685, -4.385824222448885 22.30596795527529, -4.143141268232466 22.34196657094771, -3.898098417408566 22.35400475426722, -3.653055566584665 22.34196657094771, -3.410372612368247 22.30596795527529, -3.383074108523836 22.29913003602953, -3.198321286899955 22.32653552827561, -2.953278436076054 22.33857371159512, -2.765340328481469 22.32934090441736, -2.64678250665151 22.37176157137471, -2.408796618555676 22.43137393305226, -2.166113664339258 22.46737254872468, -1.921070813515357 22.47941073204419, -1.676027962691456 22.46737254872468, -1.433345008475038 22.43137393305226, -1.195359120379203 22.37176157137471, -1.142651755126477 22.35290257453187, -0.9413867209710468 22.32304772693349, -0.7244596559357803 22.26871032582958, -0.5518773903080429 22.27718874886595, -0.3068345394841422 22.26515056554645, -0.0641515852677238 22.22915194987403, -0.03697761262200187 22.22234522406968, 0.0234066550944344 22.23747069573335, 0.2660896093108527 22.27346931140577, 0.5111324601347533 22.28550749472527, 0.756175310958654 22.27346931140577, 0.9988582651750725 22.23747069573335, 1.124606770200215 22.205972334961, 1.299512951183388 22.28869679765171, 1.530509838959956 22.37134880570402, 1.540541675798155 22.37386165001876, 1.580150144942097 22.38803378689097, 1.818136033037931 22.44764614856852, 2.06081898725435 22.48364476424094, 2.305861838078251 22.49568294756045, 2.550904688902151 22.48364476424094, 2.585818149549957 22.47846584157736, 2.636750143146877 22.48096796997526, 2.881792993970778 22.46892978665575, 3.124475948187196 22.43293117098334, 3.362461836283031 22.37331880930579, 3.405605077979647 22.35788191059068, 3.646083997305915 22.36969588233315, 3.891126848129816 22.35765769901364, 4.133809802346234 22.32165908334122, 4.371795690442069 22.26204672166367, 4.602792578218637 22.17939471361137, 4.74349612212289 22.11284689350158, 4.862426595900769 22.16909681837858, 5.093423483677336 22.25174882643089, 5.33140937177317 22.31136118810844, 5.574092325989588 22.34735980378086, 5.71264440274838 22.35416643084103, 5.788609578672952 22.38134720540751, 6.026595466768787 22.44095956708507, 6.269278420985205 22.47695818275748, 6.514321271809106 22.48899636607699, 6.759364122633007 22.47695818275748, 7.002047076849425 22.44095956708507, 7.045062493122757 22.43018476622139, 7.172998475183696 22.44916227646209, 7.418041326007597 22.4612004597816, 7.663084176831497 22.44916227646209, 7.905767131047916 22.41316366078968, 8.14375301914375 22.35355129911213, 8.374749906920318 22.27089929105982, 8.502525895102208 22.21046574944508, 8.674222684091824 22.14903165601327, 8.730173203256816 22.12256903125539, 8.755476828124921 22.12890725933043, 8.928144125486533 22.15452003340014, 9.056924723896049 22.21542872026604, 9.287921611672617 22.29808072831835, 9.525907499768453 22.35769308999591, 9.768590453984871 22.39369170566832, 10.01363330480877 22.40572988898783, 10.25867615563267 22.39369170566832, 10.38434897519156 22.37504990387232, 10.54562876847384 22.38297307204775, 10.79067161929774 22.37093488872825, 11.03335457351416 22.33493627305583, 11.27134046160999 22.27532391137828, 11.50233734938656 22.19267190332598, 11.5620735362037 22.1644187911154, 11.62238858930415 22.1614557025629, 11.65303800255386 22.15690929158103, 11.69067400012796 22.15875822957978, 11.93571685095186 22.14672004626027, 12.17839980516828 22.11072143058786, 12.41638569326412 22.05110906891031, 12.60921408285645 21.98211396788231, 12.61413707018288 21.98444236747987, 12.84513395795945 22.06709437553218, 13.08311984605528 22.12670673720973, 13.3258028002717 22.16270535288215, 13.5708456510956 22.17474353620165, 13.8158885019195 22.16270535288215, 14.0115966916425 22.13367478529024, 14.24606942960151 22.19240714866933, 14.48875238381793 22.22840576434175, 14.73379523464183 22.24044394766126, 14.83509011495141 22.23546764929387, 14.84302222492603 22.23830580362489, 15.08100811302187 22.29791816530244, 15.32369106723829 22.33391678097486, 15.56873391806219 22.34595496429436, 15.81377676888609 22.33391678097486, 16.05645972310251 22.29791816530244, 16.19915562030759 22.26217470377977, 16.35886794836413 22.31932068852286, 16.59685383645996 22.37893305020042, 16.83953679067638 22.41493166587283, 17.08457964150028 22.42696984919234, 17.32962249232418 22.41493166587283, 17.35406316190014 22.41130623501518, 17.36686412505037 22.41193510600877, 17.61190697587427 22.39989692268926, 17.85458993009069 22.36389830701685, 18.01708231883724 22.3231960825055, 18.18753309746713 22.38418434630179, 18.42551898556296 22.44379670797935, 18.66820193977938 22.47979532365176, 18.91324479060328 22.49183350697127, 19.15828764142718 22.47979532365176, 19.4009705956436 22.44379670797935, 19.63895648373943 22.38418434630179, 19.869953371516 22.30153233824949, 19.96551028205333 22.25633728547234, 19.9853426039062 22.24924116724643, 20.20712586505847 22.1443454968391, 20.41755960554248 22.01821636672458, 20.61461723340259 21.87206846937505, 20.79640097595984 21.70730928893459, 20.96116015640032 21.52552554637733, 20.97836787083578 21.50232362935326, 21.02993804195481 21.46407658377149, 21.1524925145701 21.35299968446598, 21.17995449857986 21.3365396046974, 21.37701212643996 21.19039170734787, 21.55879586899722 21.0256325269074, 21.72355504943769 20.84384878435015, 21.86970294678721 20.64679115649004, 21.99583207690174 20.43635741600603, 22.10072774730907 20.21457415485376, 22.18337975536138 19.9835772670772, 22.24299211703893 19.74559137898136, 22.27899073271135 19.50290842476495, 22.29102891603086 19.25786557394105, 22.29102891603086 19.25786557394103, 22.27899073271135 19.01282272311713, 22.25965275264398 18.88245665087605, 22.30806847593428 18.68917024884808, 22.3440670916067 18.44648729463166, 22.35610527492621 18.20144444380776, 22.35610527492621 18.20144444380774, 22.3440670916067 17.95640159298384, 22.32364979959007 17.81875939060629, 22.32637898934617 17.8111318162174, 22.38599135102372 17.57314592812157, 22.42198996669614 17.33046297390515, 22.43402815001565 17.08542012308125, 22.43402815001565 17.08542012308123, 22.42198996669614 16.84037727225733, 22.38599135102373 16.59769431804091, 22.32637898934617 16.35970842994507, 22.24372698129387 16.1287115421685, 22.13883131088654 15.90692828101623, 22.06904229209649 15.79049233750846, 22.10726844121714 15.70966993577967, 22.18992044926945 15.47867304800311, 22.24953281094701 15.24068715990727, 22.28553142661942 14.99800420569085, 22.29756960993893 14.75296135486695, 22.29756960993893 14.75296135486693, 22.28553142661942 14.50791850404303, 22.25769045232944 14.3202299009467, 22.29909198906613 14.15494570130185, 22.33509060473855 13.91226274708543, 22.34712878805806 13.66721989626153, 22.34712878805806 13.66721989626151, 22.33509060473855 13.42217704543761, 22.29909198906613 13.17949409122119, 22.23947962738858 12.94150820312535, 22.15682761933628 12.71051131534878, 22.1439806270021 12.68334863222938, 22.19843347304785 12.46596068515155, 22.23443208872027 12.22327773093513, 22.24647027203978 11.97823488011123, 22.24647027203978 11.97823488011121, 22.23443208872027 11.73319202928731, 22.22014157634299 11.63685322024689, 22.29170552965104 11.48554395377313, 22.37435753770335 11.25454706599656, 22.4339698993809 11.01656117790073, 22.46996851505332 10.77387822368431, 22.48200669837283 10.52883537286041, 22.48200669837283 10.52883537286039, 22.46996851505332 10.28379252203649, 22.43396989938091 10.04110956782007, 22.37435753770335 9.803123679724234, 22.34931049101803 9.733121873734932, 22.34643056114344 9.674499554410479, 22.31043194547102 9.431816600194061, 22.29103373003705 9.354374583175842, 22.30688482479567 9.310073741086473, 22.36649718647323 9.07208785299064, 22.40249580214564 8.829404898774222, 22.41453398546516 8.584362047950322, 22.41453398546516 8.5843620479503, 22.41010307540168 8.494168801603886, 22.43814828827776 8.382206035739104, 22.47414690395017 8.139523081522686, 22.48618508726968 7.894480230698785, 22.48618508726968 7.894480230698765, 22.47414690395017 7.649437379874864, 22.43814828827776 7.406754425658445, 22.3785359266002 7.16876853756261, 22.36084912120376 7.119337227936076, 22.36638055208554 7.082047349912735, 22.37841873540505 6.837004499088834, 22.37841873540505 6.837004499088813, 22.36638055208554 6.591961648264912, 22.35609034175698 6.522590685093183, 22.36222582230357 6.397700109463268, 22.36222582230357 6.397700109463248, 22.35018763898406 6.152657258639347, 22.31418902331165 5.909974304422928, 22.25457666163409 5.671988416327093, 22.17192465358179 5.440991528550525, 22.14187238184646 5.377451338525399, 22.13631459835018 5.264320056500067, 22.11639472283721 5.130031163807564, 22.14119387758969 5.060722169358346, 22.20080623926725 4.822736281262513, 22.20182312370297 4.815881003237257, 22.28678781110266 4.636238265065981, 22.36943981915496 4.405241377289414, 22.42905218083252 4.167255489193581, 22.46505079650493 3.924572534977163, 22.47708897982444 3.679529684153262, 22.47708897982444 3.679529684153241, 22.46505079650494 3.43448683332934, 22.42905218083252 3.191803879112921, 22.42622722872951 3.18052603813927, 22.41556802494946 2.963552960686345, 22.37956940927705 2.720870006469926, 22.37655704668347 2.708843980878516, 22.37665731548945 2.70816802349524, 22.38869549880896 2.463125172671339, 22.38869549880896 2.463125172671319, 22.37665731548946 2.218082321847417, 22.34065869981704 1.975399367630999, 22.31304697431726 1.86516718037985, 22.32294718632245 1.837497941417382, 22.38255954800001 1.599512053321549, 22.41855816367242 1.356829099105131, 22.43059634699193 1.11178624828123, 22.43059634699193 1.111786248281209, 22.41855816367243 0.866743397457308, 22.38255954800001 0.6240604432408892, 22.37015764437406 0.5745492686213595, 22.37034038738471 0.5740385361211262, 22.42995274906226 0.3360526480252923, 22.46595136473468 0.09336969380887428, 22.46983284362373 0.0143603759458221, 22.47762299880658 -0.03815658445019221, 22.48966118212609 -0.2831994352740928, 22.48966118212609 -0.2831994352741134, 22.47762299880658 -0.5282422860980147, 22.44162438313417 -0.7709252403144335, 22.38201202145661 -1.008911128410269, 22.33733720919316 -1.1337688643328, 22.35960416230565 -1.222663524140609, 22.39560277797807 -1.465346478357027, 22.40764096129758 -1.710389329180928, 22.40764096129758 -1.710389329180948, 22.39560277797807 -1.95543218000485, 22.35960416230566 -2.198115134221269, 22.2999918006281 -2.436101022317104, 22.2173397925758 -2.667097910093672, 22.12083454788258 -2.871141106569248, 22.10890457508578 -3.113981281601384, 22.09753928949359 -3.190599813495125, 22.11425511370344 -3.225942454346874, 22.19690712175575 -3.456939342123441, 22.2565194834333 -3.694925230219274, 22.27796733187449 -3.83951487968404, 22.30329211813286 -3.893059641470262, 22.38594412618517 -4.124056529246829, 22.44555648786272 -4.362042417342662, 22.48155510353514 -4.604725371559081, 22.49359328685465 -4.849768222382981, 22.49359328685465 -4.849768222383002, 22.48155510353514 -5.094811073206903, 22.46639370225972 -5.197020938304527, 22.4742428718067 -5.35679445490105, 22.4742428718067 -5.35679445490107, 22.47305251707211 -5.381024682163306, 22.47387421054751 -5.386564089619583, 22.48591239386703 -5.631606940443484, 22.48591239386703 -5.631606940443504, 22.47387421054752 -5.876649791267405, 22.4378755948751 -6.119332745483824, 22.37826323319755 -6.357318633579659, 22.37581970840857 -6.364147827869776, 22.33416054986185 -6.530460511431846, 22.25150854180955 -6.761457399208414, 22.14661287140222 -6.983240660360684, 22.14070790264234 -6.993092505548669, 22.14375134269476 -7.001598350679505, 22.20336370437232 -7.239584238775338, 22.23936232004473 -7.482267192991756, 22.25140050336424 -7.727310043815657, 22.25140050336424 -7.727310043815677, 22.23936232004474 -7.972352894639578, 22.20336370437232 -8.215035848855997, 22.17904866103241 -8.312106943180988, 22.25649042501777 -8.528542174291447, 22.31610278669532 -8.76652806238728, 22.32621521933611 -8.834700545738135, 22.32751997111001 -8.838347082660768, 22.38713233278757 -9.076332970756601, 22.42313094845998 -9.319015924973019, 22.4351691317795 -9.564058775796919, 22.4351691317795 -9.564058775796941, 22.42313094845999 -9.809101626620842, 22.38713233278757 -10.05178458083726, 22.32751997111002 -10.2897704689331, 22.24486796305771 -10.52076735670966, 22.13997229265038 -10.74255061786193, 22.04314691805991 -10.90409399590901, 22.03406561057082 -10.96531519812561, 22.06337928494946 -11.16293193877699, 22.06660106476485 -11.22851277350407, 22.08298043995721 -11.27429006049709, 22.14259280163477 -11.51227594859293, 22.17739333308725 -11.74688207506299, 22.23461413935799 -11.90680351528065, 22.29422650103554 -12.14478940337648, 22.33022511670796 -12.3874723575929, 22.34226330002747 -12.6325152084168, 22.34226330002747 -12.63251520841682, 22.33022511670796 -12.87755805924072, 22.30844502746572 -13.02438749425295, 22.34721627930011 -13.13274588408515, 22.40682864097767 -13.37073177218098, 22.44282725665008 -13.6134147263974, 22.45486543996959 -13.8584575772213, 22.45486543996959 -13.85845757722132, 22.44282725665009 -14.10350042804522, 22.40682864097767 -14.34618338226164, 22.40667909943321 -14.3467803855721, 22.41507202806971 -14.3802868348902, 22.45107064374212 -14.62296978910662, 22.46310882706163 -14.86801263993052, 22.46310882706163 -14.86801263993054, 22.45107064374212 -15.11305549075445, 22.41507202806971 -15.35573844497086, 22.37320910548004 -15.52286460019147, 22.36618663574583 -15.66581025551359, 22.33018802007341 -15.90849320973001, 22.30832089851852 -15.99579165248403, 22.31582939514044 -16.01677649474516, 22.375441756818 -16.254762382841, 22.41144037249041 -16.49744533705741, 22.42347855580992 -16.74248818788131, 22.42347855580992 -16.74248818788134, 22.41144037249041 -16.98753103870524, 22.375441756818 -17.23021399292166, 22.31582939514044 -17.46819988101749, 22.311953937675 -17.47903105904116, 22.3018715319233 -17.68426314290183, 22.26587291625088 -17.92694609711825, 22.20998447691467 -18.15006525387409, 22.19944723477361 -18.36455574513298, 22.1634486191012 -18.6072386993494, 22.10383625742364 -18.84522458744524, 22.04941193378315 -18.99733038228982, 22.04364672206227 -19.11468396282544, 22.00764810638986 -19.35736691704186, 21.97709163753492 -19.47935517875256, 21.97514755279599 -19.51892793271611, 21.93914893712358 -19.76161088693253, 21.87953657544602 -19.99959677502837, 21.79688456739372 -20.23059366280494, 21.69198889698639 -20.45237692395721, 21.64536097446595 -20.53017091284831, 21.58631018238545 -20.69520682078059, 21.48141451197812 -20.91699008193286, 21.35528538186359 -21.12742382241687, 21.20913748451407 -21.32448145027698, 21.0443783040736 -21.50626519283423, 20.86259456151634 -21.67102437327471, 20.66553693365623 -21.81717227062423, 20.45510319317222 -21.94330140073875, 20.23331993201996 -22.04819707114608, 20.00232304424339 -22.13084907919839, 19.76433715614755 -22.19046144087594, 19.52165420193113 -22.22646005654836, 19.27661135110723 -22.23849823986787, 19.03156850028333 -22.22646005654836, 18.78888554606691 -22.19046144087594, 18.73887089664221 -22.17793342337652, 18.4973901430078 -22.18979661208253, 18.41784477514719 -22.18588879874579, 18.41349373531924 -22.18697867748596, 18.17081078110282 -22.22297729315838, 17.98787095563432 -22.23196455048102, 17.79768532119148 -22.27960357192466, 17.55500236697506 -22.31560218759708, 17.30995951615116 -22.32764037091659, 17.06491666532726 -22.31560218759708, 16.82223371111084 -22.27960357192466, 16.584247823015 -22.21999121024711, 16.4666967485392 -22.177930763253, 16.4099384081795 -22.1695114587847, 16.28838315841296 -22.13906345377539, 16.17480211986003 -22.19278328422008, 15.94380523208346 -22.27543529227239, 15.70581934398762 -22.33504765394994, 15.46313638977121 -22.37104626962236, 15.2180935389473 -22.38308445294187, 14.9730506881234 -22.37104626962236, 14.73036773390698 -22.33504765394994, 14.65305301275748 -22.31568132447116, 14.45362419243909 -22.3452637954767, 14.20858134161519 -22.35730197879621, 13.96353849079129 -22.3452637954767, 13.73523415567763 -22.31139804646833, 13.59984162375042 -22.33148163139707, 13.35479877292652 -22.34351981471658, 13.10975592210262 -22.33148163139707, 12.8670729678862 -22.29548301572466, 12.62908707979036 -22.2358706540471, 12.61296722408551 -22.23010287744914, 12.51509107260605 -22.26512352442874, 12.27710518451022 -22.3247358861063, 12.0344222302938 -22.36073450177871, 11.7893793794699 -22.37277268509822, 11.544336528646 -22.36073450177871, 11.42614034228609 -22.34320175375175, 11.41367609013224 -22.34505065090392, 11.17312139811863 -22.35686834511981, 11.0505742524468 -22.38756480711927, 10.96704756934117 -22.39995482014355, 10.89076207090825 -22.41906334275269, 10.64807911669183 -22.4550619584251, 10.40303626586793 -22.46710014174461, 10.15799341504403 -22.4550619584251, 9.915310460827609 -22.41906334275269, 9.678390165997076 -22.35971789829296, 9.461434530251323 -22.39190022677332, 9.216391679427421 -22.40393841009282, 8.971348828603521 -22.39190022677332, 8.859745401813472 -22.37534542224775, 8.640809946866888 -22.43018589883542, 8.39812699265047 -22.46618451450784, 8.153084141826568 -22.47822269782734, 7.908041291002667 -22.46618451450784, 7.665358336786248 -22.43018589883542, 7.654227093690167 -22.42739766758913, 7.631127550771891 -22.42853247536382, 7.386084699947989 -22.41649429204432, 7.14340174573157 -22.3804956763719, 6.961547070081421 -22.33494345147172, 6.84664652751557 -22.31789956602152, 6.757417223308805 -22.33113548297839, 6.512374372484904 -22.3431736662979, 6.267331521661002 -22.33113548297839, 6.024648567444583 -22.29513686730598, 5.786662679348748 -22.23552450562843, 5.679434149468312 -22.19715752414906, 5.639137942656076 -22.19517789845072, 5.527756450060979 -22.2116997821483, 5.309290253954825 -22.22243233814412, 5.171949898293681 -22.28738948868023, 4.940953010517113 -22.37004149673253, 4.702967122421279 -22.42965385841009, 4.46028416820486 -22.4656524740825, 4.215241317380959 -22.47769065740201, 3.970198466557057 -22.4656524740825, 3.750904670430335 -22.43312331227301, 3.67246061444501 -22.44475938878411, 3.427417763621108 -22.45679757210362, 3.182374912797207 -22.44475938878411, 2.939691958580788 -22.40876077311169, 2.701706070484953 -22.34914841143414, 2.470709182708385 -22.26649640338184, 2.400539054657536 -22.233308404494, 2.382213028549373 -22.23058999531359, 2.144227140453538 -22.17097763363604, 1.91323025267697 -22.08832562558374, 1.772685063718212 -22.02185270178525, 1.740138581807164 -22.04599081787381, 1.529704841323152 -22.17211994798834, 1.307921580170883 -22.27701561839567, 1.076924692394315 -22.35966762644798, 0.8389388042984798 -22.41927998812553, 0.5962558500820608 -22.45527860379795, 0.3512129992581597 -22.46731678711745, 0.1061701484342584 -22.45527860379795, -0.04851836590371944 -22.43233273026278, -0.2461837018222049 -22.42262205500048, -0.4888666560386239 -22.38662343932807, -0.726852544134459 -22.32701107765052, -0.9578494319110273 -22.24435906959821, -1.125708636819748 -22.16496757836726, -1.139764547714639 -22.17161552911361, -1.370761435491207 -22.25426753716592, -1.608747323587042 -22.31387989884347, -1.851430277803461 -22.34987851451589, -2.096473128627362 -22.3619166978354, -2.341515979451263 -22.34987851451589, -2.455727455302357 -22.33293684245731, -2.55442301821249 -22.34757694624723, -2.617898317366901 -22.37028877144683, -2.855884205462736 -22.42990113312439, -3.098567159679154 -22.4658997487968, -3.343610010503056 -22.47793793211631, -3.588652861326957 -22.4658997487968, -3.831335815543376 -22.42990113312439, -3.907954521318272 -22.41070914642104, -3.975896008872092 -22.41404689767321, -4.183715500617316 -22.44487400721096, -4.428758351441217 -22.45691219053047, -4.673801202265119 -22.44487400721096, -4.916484156481538 -22.40887539153854, -5.020084557130864 -22.38292484210529, -5.020419078409338 -22.38304453573263, -5.258404966505172 -22.44265689741019, -5.501087920721591 -22.4786555130826, -5.746130771545492 -22.49069369640211, -5.991173622369394 -22.4786555130826, -6.123693431593027 -22.45899805631302, -6.264189488772653 -22.46590018500729, -6.509232339596555 -22.45386200168778, -6.751915293812974 -22.41786338601537, -6.989901181908809 -22.35825102433781, -7.220898069685378 -22.27559901628551, -7.347294079158904 -22.2158181559913, -7.532152849094219 -22.18839694779783, -7.598927497924632 -22.17167076899446, -7.804850114037394 -22.22325169913918, -8.047533068253813 -22.2592503148116, -8.292575919077715 -22.27128849813111, -8.537618769901615 -22.2592503148116, -8.565029213837116 -22.25518435954156, -8.633110179045801 -22.27954411840584, -8.871096067141636 -22.3391564800834, -9.113779021358054 -22.37515509575582, -9.358821872181956 -22.38719327907532, -9.603864723005856 -22.37515509575582, -9.846547677222276 -22.3391564800834, -10.08453356531811 -22.27954411840584, -10.09791748181934 -22.27475527650811, -10.14016295582498 -22.29473589765361, -10.37115984360155 -22.37738790570592, -10.60914573169738 -22.43700026738347, -10.8518286859138 -22.47299888305589, -11.0968715367377 -22.48503706637539, -11.3419143875616 -22.47299888305589, -11.58459734177802 -22.43700026738347, -11.75310292370707 -22.3947918163908, -11.90532691377749 -22.43292194093173, -12.1480098679939 -22.46892055660414, -12.39305271881781 -22.48095873992365, -12.63809556964171 -22.46892055660414, -12.88077852385813 -22.43292194093173, -13.11876441195396 -22.37330957925418, -13.20218180754802 -22.34346235785346, -13.35693885800207 -22.35106508422189, -13.60198170882597 -22.33902690090238, -13.84466466304239 -22.30302828522996, -14.08265055113823 -22.24341592355241, -14.31364743891479 -22.16076391550011, -14.50430349127707 -22.07059031842225))"; + + // epl result for union + String eplWKT = "MULTIPOLYGON (((-15.90174522590254 -22.49823229650554, -15.65670237507864 -22.48619411318603, -15.41401942086222 -22.45019549751362, -15.17603353276639 -22.39058313583606, -14.94503664498982 -22.30793112778376, -14.72325338383755 -22.20303545737643, -14.51281964335354 -22.0769063272619, -14.50430349127707 -22.07059031842225, -14.31364743891479 -22.16076391550011, -14.08265055113823 -22.24341592355241, -13.84466466304239 -22.30302828522996, -13.60198170882597 -22.33902690090238, -13.35693885800207 -22.35106508422189, -13.20218180754802 -22.34346235785346, -13.11876441195396 -22.37330957925418, -12.88077852385813 -22.43292194093173, -12.63809556964171 -22.46892055660414, -12.39305271881781 -22.48095873992365, -12.1480098679939 -22.46892055660414, -11.90532691377749 -22.43292194093173, -11.75310292370707 -22.3947918163908, -11.58459734177802 -22.43700026738347, -11.3419143875616 -22.47299888305589, -11.0968715367377 -22.48503706637539, -10.8518286859138 -22.47299888305589, -10.60914573169738 -22.43700026738347, -10.37115984360155 -22.37738790570592, -10.14016295582498 -22.29473589765361, -10.09791748181934 -22.27475527650811, -10.08453356531811 -22.27954411840584, -9.846547677222276 -22.3391564800834, -9.603864723005856 -22.37515509575582, -9.358821872181956 -22.38719327907532, -9.113779021358054 -22.37515509575582, -8.871096067141636 -22.3391564800834, -8.633110179045801 -22.27954411840584, -8.565029213837116 -22.25518435954156, -8.537618769901615 -22.2592503148116, -8.292575919077715 -22.27128849813111, -8.047533068253813 -22.2592503148116, -7.804850114037394 -22.22325169913918, -7.598927497924632 -22.17167076899446, -7.532152849094219 -22.18839694779783, -7.347294079158904 -22.2158181559913, -7.220898069685378 -22.27559901628551, -6.989901181908809 -22.35825102433781, -6.751915293812974 -22.41786338601537, -6.509232339596555 -22.45386200168778, -6.264189488772653 -22.46590018500729, -6.123693431593027 -22.45899805631302, -5.991173622369394 -22.4786555130826, -5.746130771545492 -22.49069369640211, -5.501087920721591 -22.4786555130826, -5.258404966505172 -22.44265689741019, -5.020419078409338 -22.38304453573263, -5.020084557130864 -22.38292484210529, -4.916484156481538 -22.40887539153854, -4.673801202265119 -22.44487400721096, -4.428758351441217 -22.45691219053047, -4.183715500617316 -22.44487400721096, -3.975896008872092 -22.41404689767321, -3.907954521318273 -22.41070914642104, -3.831335815543376 -22.42990113312439, -3.588652861326957 -22.4658997487968, -3.343610010503056 -22.47793793211631, -3.098567159679154 -22.4658997487968, -2.855884205462736 -22.42990113312439, -2.617898317366901 -22.37028877144683, -2.55442301821249 -22.34757694624723, -2.455727455302357 -22.33293684245731, -2.341515979451263 -22.34987851451589, -2.096473128627362 -22.3619166978354, -1.851430277803461 -22.34987851451589, -1.608747323587042 -22.31387989884347, -1.370761435491207 -22.25426753716592, -1.139764547714639 -22.17161552911361, -1.125708636819748 -22.16496757836726, -0.9578494319110273 -22.24435906959821, -0.726852544134459 -22.32701107765052, -0.4888666560386239 -22.38662343932807, -0.2461837018222049 -22.42262205500048, -0.04851836590371948 -22.43233273026278, 0.1061701484342584 -22.45527860379795, 0.3512129992581597 -22.46731678711745, 0.5962558500820608 -22.45527860379795, 0.8389388042984798 -22.41927998812553, 1.076924692394315 -22.35966762644798, 1.307921580170883 -22.27701561839567, 1.529704841323152 -22.17211994798834, 1.740138581807164 -22.04599081787381, 1.772685063718212 -22.02185270178525, 1.91323025267697 -22.08832562558374, 2.144227140453538 -22.17097763363604, 2.382213028549373 -22.23058999531359, 2.400539054657536 -22.233308404494, 2.470709182708385 -22.26649640338184, 2.701706070484953 -22.34914841143414, 2.939691958580788 -22.40876077311169, 3.182374912797207 -22.44475938878411, 3.427417763621108 -22.45679757210362, 3.67246061444501 -22.44475938878411, 3.750904670430335 -22.43312331227301, 3.970198466557057 -22.4656524740825, 4.215241317380959 -22.47769065740201, 4.46028416820486 -22.4656524740825, 4.702967122421279 -22.42965385841009, 4.940953010517113 -22.37004149673253, 5.171949898293681 -22.28738948868023, 5.309290253954825 -22.22243233814412, 5.527756450060979 -22.2116997821483, 5.63913794265608 -22.19517789845072, 5.679434149468313 -22.19715752414906, 5.786662679348748 -22.23552450562843, 6.024648567444583 -22.29513686730598, 6.267331521661002 -22.33113548297839, 6.512374372484904 -22.3431736662979, 6.757417223308805 -22.33113548297839, 6.846646527515573 -22.31789956602152, 6.961547070081421 -22.33494345147172, 7.14340174573157 -22.3804956763719, 7.386084699947989 -22.41649429204432, 7.631127550771891 -22.42853247536382, 7.654227093690167 -22.42739766758913, 7.665358336786248 -22.43018589883542, 7.908041291002667 -22.46618451450784, 8.153084141826568 -22.47822269782734, 8.39812699265047 -22.46618451450784, 8.640809946866888 -22.43018589883542, 8.859745401813472 -22.37534542224775, 8.971348828603521 -22.39190022677332, 9.216391679427421 -22.40393841009282, 9.461434530251323 -22.39190022677332, 9.678390165997076 -22.35971789829296, 9.915310460827609 -22.41906334275269, 10.15799341504403 -22.4550619584251, 10.40303626586793 -22.46710014174461, 10.64807911669183 -22.4550619584251, 10.89076207090825 -22.41906334275269, 10.96704756934117 -22.39995482014355, 11.0505742524468 -22.38756480711927, 11.17312139811863 -22.35686834511981, 11.41367609013224 -22.34505065090392, 11.42614034228609 -22.34320175375175, 11.544336528646 -22.36073450177871, 11.7893793794699 -22.37277268509822, 12.0344222302938 -22.36073450177871, 12.27710518451022 -22.3247358861063, 12.51509107260605 -22.26512352442874, 12.61296722408551 -22.23010287744914, 12.62908707979036 -22.2358706540471, 12.8670729678862 -22.29548301572466, 13.10975592210262 -22.33148163139707, 13.35479877292652 -22.34351981471658, 13.59984162375042 -22.33148163139707, 13.73523415567763 -22.31139804646833, 13.96353849079129 -22.3452637954767, 14.20858134161519 -22.35730197879621, 14.45362419243909 -22.3452637954767, 14.65305301275748 -22.31568132447116, 14.73036773390698 -22.33504765394994, 14.9730506881234 -22.37104626962236, 15.2180935389473 -22.38308445294187, 15.46313638977121 -22.37104626962236, 15.70581934398762 -22.33504765394994, 15.94380523208346 -22.27543529227239, 16.17480211986003 -22.19278328422008, 16.28838315841296 -22.13906345377539, 16.4099384081795 -22.1695114587847, 16.4666967485392 -22.177930763253, 16.584247823015 -22.21999121024711, 16.82223371111084 -22.27960357192466, 17.06491666532726 -22.31560218759708, 17.30995951615116 -22.32764037091659, 17.55500236697506 -22.31560218759708, 17.79768532119148 -22.27960357192466, 17.98787095563432 -22.23196455048102, 18.17081078110282 -22.22297729315838, 18.41349373531924 -22.18697867748596, 18.41784477514719 -22.18588879874579, 18.4973901430078 -22.18979661208253, 18.73887089664221 -22.17793342337652, 18.78888554606691 -22.19046144087594, 19.03156850028333 -22.22646005654836, 19.27661135110723 -22.23849823986787, 19.52165420193113 -22.22646005654836, 19.76433715614755 -22.19046144087594, 20.00232304424339 -22.13084907919839, 20.23331993201996 -22.04819707114608, 20.45510319317222 -21.94330140073875, 20.66553693365623 -21.81717227062423, 20.86259456151634 -21.67102437327471, 21.0443783040736 -21.50626519283423, 21.20913748451407 -21.32448145027698, 21.35528538186359 -21.12742382241687, 21.48141451197812 -20.91699008193286, 21.58631018238545 -20.69520682078059, 21.64536097446595 -20.53017091284831, 21.69198889698639 -20.45237692395721, 21.79688456739372 -20.23059366280494, 21.87953657544602 -19.99959677502837, 21.93914893712358 -19.76161088693253, 21.97514755279599 -19.51892793271611, 21.97709163753492 -19.47935517875256, 22.00764810638986 -19.35736691704186, 22.04364672206227 -19.11468396282544, 22.04941193378315 -18.99733038228982, 22.10383625742364 -18.84522458744524, 22.1634486191012 -18.6072386993494, 22.19944723477361 -18.36455574513298, 22.20998447691467 -18.15006525387409, 22.26587291625088 -17.92694609711825, 22.3018715319233 -17.68426314290183, 22.311953937675 -17.47903105904117, 22.31582939514044 -17.46819988101749, 22.375441756818 -17.23021399292166, 22.41144037249041 -16.98753103870524, 22.42347855580992 -16.74248818788132, 22.41144037249041 -16.49744533705741, 22.375441756818 -16.254762382841, 22.31582939514044 -16.01677649474516, 22.30832089851852 -15.99579165248403, 22.33018802007341 -15.90849320973001, 22.36618663574583 -15.66581025551359, 22.37320910548004 -15.52286460019147, 22.41507202806971 -15.35573844497086, 22.45107064374212 -15.11305549075445, 22.46310882706163 -14.86801263993053, 22.45107064374212 -14.62296978910662, 22.41507202806971 -14.3802868348902, 22.40667909943321 -14.3467803855721, 22.40682864097767 -14.34618338226164, 22.44282725665009 -14.10350042804522, 22.45486543996959 -13.85845757722131, 22.44282725665008 -13.6134147263974, 22.40682864097767 -13.37073177218098, 22.34721627930011 -13.13274588408515, 22.30844502746573 -13.02438749425295, 22.33022511670796 -12.87755805924072, 22.34226330002747 -12.63251520841681, 22.33022511670796 -12.3874723575929, 22.29422650103554 -12.14478940337648, 22.23461413935799 -11.90680351528065, 22.17739333308725 -11.74688207506299, 22.14259280163477 -11.51227594859293, 22.08298043995721 -11.27429006049709, 22.06660106476485 -11.22851277350407, 22.06337928494946 -11.16293193877699, 22.03406561057082 -10.96531519812561, 22.04314691805991 -10.90409399590901, 22.13997229265038 -10.74255061786193, 22.24486796305771 -10.52076735670966, 22.32751997111002 -10.2897704689331, 22.38713233278757 -10.05178458083726, 22.42313094845999 -9.809101626620842, 22.4351691317795 -9.56405877579693, 22.42313094845998 -9.319015924973019, 22.38713233278757 -9.076332970756601, 22.32751997111001 -8.838347082660768, 22.32621521933611 -8.834700545738135, 22.31610278669532 -8.76652806238728, 22.25649042501777 -8.528542174291447, 22.17904866103241 -8.312106943180988, 22.20336370437232 -8.215035848855997, 22.23936232004474 -7.972352894639578, 22.25140050336424 -7.727310043815667, 22.23936232004473 -7.482267192991756, 22.20336370437232 -7.239584238775338, 22.14375134269476 -7.001598350679505, 22.14070790264234 -6.993092505548669, 22.14661287140222 -6.983240660360684, 22.25150854180955 -6.761457399208414, 22.33416054986185 -6.530460511431846, 22.37581970840857 -6.364147827869776, 22.37826323319755 -6.357318633579659, 22.4378755948751 -6.119332745483824, 22.47387421054752 -5.876649791267405, 22.48591239386703 -5.631606940443493, 22.47387421054751 -5.386564089619583, 22.47305251707211 -5.381024682163304, 22.4742428718067 -5.35679445490106, 22.46639370225972 -5.197020938304531, 22.48155510353514 -5.094811073206903, 22.49359328685465 -4.849768222382991, 22.48155510353514 -4.604725371559081, 22.44555648786272 -4.362042417342662, 22.38594412618517 -4.124056529246829, 22.30329211813286 -3.893059641470262, 22.27796733187449 -3.83951487968404, 22.2565194834333 -3.694925230219274, 22.19690712175575 -3.456939342123441, 22.11425511370344 -3.225942454346874, 22.09753928949359 -3.190599813495125, 22.10890457508578 -3.113981281601384, 22.12083454788258 -2.87114110656925, 22.2173397925758 -2.667097910093672, 22.2999918006281 -2.436101022317104, 22.35960416230566 -2.198115134221269, 22.39560277797807 -1.95543218000485, 22.40764096129758 -1.710389329180938, 22.39560277797807 -1.465346478357027, 22.35960416230565 -1.222663524140609, 22.33733720919316 -1.1337688643328, 22.38201202145661 -1.008911128410269, 22.44162438313417 -0.7709252403144335, 22.47762299880658 -0.5282422860980147, 22.48966118212609 -0.2831994352741031, 22.47762299880658 -0.03815658445019221, 22.46983284362372 0.01436037594582373, 22.46595136473468 0.09336969380887428, 22.42995274906226 0.3360526480252923, 22.37034038738471 0.5740385361211262, 22.37015764437406 0.5745492686213597, 22.38255954800001 0.6240604432408892, 22.41855816367243 0.866743397457308, 22.43059634699193 1.11178624828122, 22.41855816367242 1.356829099105131, 22.38255954800001 1.599512053321549, 22.32294718632245 1.837497941417382, 22.31304697431726 1.86516718037985, 22.34065869981704 1.975399367630999, 22.37665731548946 2.218082321847417, 22.38869549880896 2.463125172671329, 22.37665731548945 2.70816802349524, 22.37655704668347 2.708843980878516, 22.37956940927705 2.720870006469926, 22.41556802494946 2.963552960686345, 22.42622722872951 3.180526038139268, 22.42905218083252 3.191803879112921, 22.46505079650494 3.43448683332934, 22.47708897982444 3.679529684153251, 22.46505079650493 3.924572534977163, 22.42905218083252 4.167255489193581, 22.36943981915496 4.405241377289414, 22.28678781110266 4.636238265065981, 22.20182312370297 4.815881003237257, 22.20080623926725 4.822736281262513, 22.14119387758969 5.060722169358346, 22.11639472283721 5.130031163807564, 22.13631459835018 5.264320056500067, 22.14187238184646 5.377451338525397, 22.17192465358179 5.440991528550525, 22.25457666163409 5.671988416327093, 22.31418902331165 5.909974304422928, 22.35018763898406 6.152657258639347, 22.36222582230357 6.397700109463258, 22.35609034175698 6.522590685093183, 22.36638055208554 6.591961648264912, 22.37841873540505 6.837004499088824, 22.36638055208554 7.082047349912735, 22.36084912120376 7.119337227936076, 22.3785359266002 7.16876853756261, 22.43814828827776 7.406754425658445, 22.47414690395017 7.649437379874864, 22.48618508726968 7.894480230698775, 22.47414690395017 8.139523081522686, 22.43814828827776 8.382206035739104, 22.41010307540168 8.494168801603886, 22.41453398546516 8.584362047950311, 22.40249580214564 8.829404898774222, 22.36649718647323 9.07208785299064, 22.30688482479567 9.310073741086473, 22.29103373003705 9.354374583175842, 22.31043194547102 9.431816600194061, 22.34643056114344 9.674499554410479, 22.34931049101803 9.73312187373493, 22.37435753770335 9.803123679724234, 22.43396989938091 10.04110956782007, 22.46996851505332 10.28379252203649, 22.48200669837283 10.5288353728604, 22.46996851505332 10.77387822368431, 22.4339698993809 11.01656117790073, 22.37435753770335 11.25454706599656, 22.29170552965104 11.48554395377313, 22.22014157634299 11.63685322024689, 22.23443208872027 11.73319202928731, 22.24647027203978 11.97823488011122, 22.23443208872027 12.22327773093513, 22.19843347304785 12.46596068515155, 22.1439806270021 12.68334863222938, 22.15682761933628 12.71051131534878, 22.23947962738858 12.94150820312535, 22.29909198906613 13.17949409122119, 22.33509060473855 13.42217704543761, 22.34712878805806 13.66721989626152, 22.33509060473855 13.91226274708543, 22.29909198906613 14.15494570130185, 22.25769045232944 14.3202299009467, 22.28553142661942 14.50791850404303, 22.29756960993893 14.75296135486694, 22.28553142661942 14.99800420569085, 22.24953281094701 15.24068715990727, 22.18992044926945 15.47867304800311, 22.10726844121714 15.70966993577967, 22.06904229209649 15.79049233750846, 22.13883131088654 15.90692828101623, 22.24372698129387 16.1287115421685, 22.32637898934617 16.35970842994507, 22.38599135102373 16.59769431804091, 22.42198996669614 16.84037727225733, 22.43402815001565 17.08542012308124, 22.42198996669614 17.33046297390515, 22.38599135102372 17.57314592812157, 22.32637898934617 17.8111318162174, 22.32364979959007 17.81875939060629, 22.3440670916067 17.95640159298384, 22.35610527492621 18.20144444380775, 22.3440670916067 18.44648729463166, 22.30806847593428 18.68917024884808, 22.25965275264398 18.88245665087605, 22.27899073271135 19.01282272311713, 22.29102891603086 19.25786557394104, 22.27899073271135 19.50290842476495, 22.24299211703893 19.74559137898136, 22.18337975536138 19.9835772670772, 22.10072774730907 20.21457415485376, 21.99583207690174 20.43635741600603, 21.86970294678721 20.64679115649004, 21.72355504943769 20.84384878435015, 21.55879586899722 21.0256325269074, 21.37701212643996 21.19039170734787, 21.17995449857986 21.3365396046974, 21.1524925145701 21.35299968446598, 21.02993804195481 21.46407658377149, 20.97836787083578 21.50232362935326, 20.96116015640032 21.52552554637733, 20.79640097595984 21.70730928893459, 20.61461723340259 21.87206846937505, 20.41755960554248 22.01821636672458, 20.20712586505847 22.1443454968391, 19.9853426039062 22.24924116724643, 19.96551028205333 22.25633728547234, 19.869953371516 22.30153233824949, 19.63895648373943 22.38418434630179, 19.4009705956436 22.44379670797935, 19.15828764142718 22.47979532365176, 18.91324479060328 22.49183350697127, 18.66820193977938 22.47979532365176, 18.42551898556296 22.44379670797935, 18.18753309746713 22.38418434630179, 18.01708231883724 22.3231960825055, 17.85458993009069 22.36389830701685, 17.61190697587427 22.39989692268926, 17.36686412505037 22.41193510600877, 17.35406316190014 22.41130623501518, 17.32962249232418 22.41493166587283, 17.08457964150028 22.42696984919234, 16.83953679067638 22.41493166587283, 16.59685383645996 22.37893305020042, 16.35886794836413 22.31932068852286, 16.19915562030759 22.26217470377977, 16.05645972310251 22.29791816530244, 15.81377676888609 22.33391678097486, 15.56873391806219 22.34595496429436, 15.32369106723829 22.33391678097486, 15.08100811302187 22.29791816530244, 14.84302222492603 22.23830580362489, 14.83509011495141 22.23546764929387, 14.73379523464183 22.24044394766126, 14.48875238381793 22.22840576434175, 14.24606942960151 22.19240714866933, 14.0115966916425 22.13367478529024, 13.8158885019195 22.16270535288215, 13.5708456510956 22.17474353620165, 13.3258028002717 22.16270535288215, 13.08311984605528 22.12670673720973, 12.84513395795945 22.06709437553218, 12.61413707018288 21.98444236747987, 12.60921408285645 21.98211396788231, 12.41638569326412 22.05110906891031, 12.17839980516828 22.11072143058786, 11.93571685095186 22.14672004626027, 11.69067400012796 22.15875822957978, 11.65303800255386 22.15690929158103, 11.62238858930415 22.1614557025629, 11.5620735362037 22.1644187911154, 11.50233734938656 22.19267190332598, 11.27134046160999 22.27532391137828, 11.03335457351416 22.33493627305583, 10.79067161929774 22.37093488872825, 10.54562876847384 22.38297307204775, 10.38434897519156 22.37504990387232, 10.25867615563267 22.39369170566832, 10.01363330480877 22.40572988898783, 9.768590453984871 22.39369170566832, 9.525907499768453 22.35769308999591, 9.287921611672617 22.29808072831835, 9.056924723896049 22.21542872026604, 8.928144125486533 22.15452003340014, 8.755476828124921 22.12890725933043, 8.730173203256818 22.12256903125539, 8.674222684091824 22.14903165601327, 8.502525895102208 22.21046574944508, 8.374749906920318 22.27089929105982, 8.14375301914375 22.35355129911213, 7.905767131047916 22.41316366078968, 7.663084176831497 22.44916227646209, 7.418041326007597 22.4612004597816, 7.172998475183696 22.44916227646209, 7.045062493122757 22.43018476622139, 7.002047076849425 22.44095956708507, 6.759364122633007 22.47695818275748, 6.514321271809106 22.48899636607699, 6.269278420985205 22.47695818275748, 6.026595466768787 22.44095956708507, 5.788609578672952 22.38134720540751, 5.71264440274838 22.35416643084103, 5.574092325989588 22.34735980378086, 5.33140937177317 22.31136118810844, 5.093423483677336 22.25174882643089, 4.862426595900769 22.16909681837858, 4.743496122122889 22.11284689350158, 4.602792578218637 22.17939471361137, 4.371795690442069 22.26204672166367, 4.133809802346234 22.32165908334122, 3.891126848129816 22.35765769901364, 3.646083997305915 22.36969588233315, 3.405605077979647 22.35788191059068, 3.362461836283031 22.37331880930579, 3.124475948187196 22.43293117098334, 2.881792993970778 22.46892978665575, 2.636750143146877 22.48096796997526, 2.585818149549957 22.47846584157736, 2.550904688902151 22.48364476424094, 2.305861838078251 22.49568294756045, 2.06081898725435 22.48364476424094, 1.818136033037931 22.44764614856852, 1.580150144942097 22.38803378689097, 1.540541675798155 22.37386165001876, 1.530509838959956 22.37134880570402, 1.299512951183388 22.28869679765171, 1.124606770200216 22.205972334961, 0.9988582651750725 22.23747069573335, 0.756175310958654 22.27346931140577, 0.5111324601347533 22.28550749472527, 0.2660896093108527 22.27346931140577, 0.0234066550944344 22.23747069573335, -0.03697761262200187 22.22234522406968, -0.0641515852677238 22.22915194987403, -0.3068345394841422 22.26515056554645, -0.5518773903080429 22.27718874886595, -0.7244596559357803 22.26871032582958, -0.9413867209710468 22.32304772693349, -1.142651755126477 22.35290257453187, -1.195359120379203 22.37176157137471, -1.433345008475038 22.43137393305226, -1.676027962691456 22.46737254872468, -1.921070813515357 22.47941073204419, -2.166113664339258 22.46737254872468, -2.408796618555676 22.43137393305226, -2.64678250665151 22.37176157137471, -2.765340328481469 22.32934090441736, -2.953278436076054 22.33857371159512, -3.198321286899955 22.32653552827561, -3.383074108523836 22.29913003602953, -3.410372612368247 22.30596795527529, -3.653055566584665 22.34196657094771, -3.898098417408566 22.35400475426722, -4.143141268232466 22.34196657094771, -4.385824222448885 22.30596795527529, -4.462919229365399 22.28665666134685, -4.543872356633671 22.30693436411426, -4.78655531085009 22.34293297978667, -5.03159816167399 22.35497116310618, -5.276641012497891 22.34293297978667, -5.519323966714309 22.30693436411426, -5.740285956380461 22.25158626700496, -5.849769324545464 22.23534594346918, -6.045368531132135 22.18635089279545, -6.047974121578137 22.18700355922577, -6.290657075794555 22.22300217489819, -6.535699926618456 22.2350403582177, -6.541298596980119 22.23476531317993, -6.698394072660326 22.29097497317093, -6.93637996075616 22.35058733484848, -7.179062914972579 22.3865859505209, -7.42410576579648 22.39862413384041, -7.624786122499572 22.38876534010497, -7.81773403682064 22.43709627663851, -8.060416991037059 22.47309489231092, -8.305459841860959 22.48513307563043, -8.550502692684859 22.47309489231092, -8.793185646901277 22.43709627663851, -9.005397594027517 22.38393995108657, -9.044718063582776 22.38200826028587, -9.214586297221089 22.407205832474, -9.459629148044989 22.41924401579351, -9.704671998868889 22.407205832474, -9.947354953085307 22.37120721680159, -10.18534084118114 22.31159485512403, -10.33580272181398 22.25775873339386, -10.51254839624864 22.32099934692418, -10.75053428434447 22.38061170860173, -10.99321723856089 22.41661032427414, -11.23826008938479 22.42864850759365, -11.29538315086152 22.42584223153411, -11.33038977901702 22.43461093540733, -11.57307273323344 22.47060955107974, -11.81811558405734 22.48264773439925, -12.06315843488124 22.47060955107974, -12.30584138909765 22.43461093540733, -12.54382727719349 22.37499857372977, -12.60371436525269 22.35357063098932, -12.83999844527089 22.38862006333841, -13.08504129609479 22.40065824665792, -13.33008414691869 22.38862006333841, -13.57276710113511 22.352621447666, -13.81075298923094 22.29300908598844, -13.86995584245114 22.27182596638811, -13.99875298466096 22.2527207151063, -14.02162334345316 22.24699198845396, -14.05563511998011 22.24532109701812, -14.29831807419653 22.20932248134571, -14.45234634580798 22.17074040780624, -14.48458465159365 22.1788156830242, -14.65976147368973 22.20480070992366, -14.71557451981399 22.22477093715091, -14.8206581025195 22.25109300434882, -14.90594999486599 22.29143306509782, -15.13694688264255 22.37408507315013, -15.37493277073839 22.43369743482768, -15.61761572495481 22.46969605050009, -15.86265857577871 22.4817342338196, -16.10770142660261 22.46969605050009, -16.35038438081903 22.43369743482768, -16.39788303796649 22.42179964058564, -16.57611124777833 22.43055543107375, -16.82115409860222 22.41851724775424, -16.89031477907391 22.40825822991765, -16.94578704243195 22.41648676288385, -17.19082989325585 22.42852494620336, -17.43587274407975 22.41648676288385, -17.5503671284345 22.399503125313, -17.67505861594785 22.41799936025091, -17.92010146677175 22.43003754357042, -18.16514431759565 22.41799936025091, -18.40782727181207 22.3820007445785, -18.64505406713305 22.32257852574262, -18.73588422207093 22.35507807484728, -18.97387011016676 22.41469043652483, -19.21655306438318 22.45068905219724, -19.46159591520708 22.46272723551675, -19.70663876603098 22.45068905219724, -19.9493217202474 22.41469043652483, -20.18730760834324 22.35507807484727, -20.41830449611981 22.27242606679497, -20.4307583865337 22.26653581530638, -20.56379166347918 22.23321271416002, -20.79478855125575 22.15056070610771, -21.01657181240802 22.04566503570039, -21.22700555289203 21.91953590558586, -21.42406318075214 21.77338800823634, -21.60584692330939 21.60862882779587, -21.77060610374987 21.42684508523861, -21.91675400109939 21.22978745737851, -22.04288313121391 21.01935371689449, -22.14777880162124 20.79757045574222, -22.23043080967355 20.56657356796565, -22.2900431713511 20.32858767986982, -22.32604178702352 20.0859047256534, -22.33807997034302 19.8408618748295, -22.32604178702352 19.5958190240056, -22.30537123841755 19.45646950438467, -22.3342576214756 19.34114859891324, -22.37025623714802 19.09846564469682, -22.38229442046752 18.85342279387292, -22.37025623714802 18.60837994304902, -22.35423385062678 18.50036578689495, -22.35761020545555 18.43163850548751, -22.37766358477907 18.29644960321025, -22.38970176809858 18.05140675238635, -22.37766358477907 17.80636390156245, -22.37260135853582 17.7722371442781, -22.38305833385616 17.55938052168966, -22.38181414347826 17.53405444473314, -22.41197150930309 17.33074999835235, -22.4240096926226 17.08570714752844, -22.41197150930309 16.84066429670454, -22.40636946919279 16.80289840992767, -22.44403823256925 16.65251627687095, -22.48003684824166 16.40983332265453, -22.49207503156117 16.16479047183062, -22.48003684824166 15.91974762100672, -22.44403823256925 15.6770646667903, -22.43547952265877 15.64289638152731, -22.42650680380195 15.4602524933292, -22.39050818812954 15.21756953911278, -22.33192658845886 14.98369868361621, -22.34105686595574 14.79784761562138, -22.32901868263623 14.55280476479748, -22.29302006696381 14.31012181058106, -22.26462335331059 14.19675577495375, -22.26277109686172 14.15905222877569, -22.22677248118931 13.91636927455927, -22.16716011951175 13.67838338646343, -22.10462297699719 13.50360378180867, -22.14988328742593 13.42809151584489, -22.25477895783326 13.20630825469262, -22.33743096588557 12.97531136691605, -22.39704332756312 12.73732547882022, -22.43304194323554 12.4946425246038, -22.44508012655504 12.2495996737799, -22.43304194323554 12.00455682295599, -22.39704332756312 11.76187386873957, -22.33743096588557 11.52388798064374, -22.25477895783326 11.29289109286717, -22.19678075951196 11.1702642054589, -22.231853125918 10.93382551658731, -22.2438913092375 10.68878266576341, -22.231853125918 10.44373981493951, -22.19585451024558 10.20105686072309, -22.13624214856803 9.963070972627253, -22.05359014051572 9.732074084850684, -22.04396671166407 9.711727054073368, -22.00373838951193 9.599296425506699, -22.03882619823041 9.525109487055827, -22.12147820628271 9.294112599279259, -22.18109056796027 9.056126711183422, -22.21708918363268 8.813443756967004, -22.2200347057179 8.75348627752272, -22.26415027510652 8.630191520729721, -22.32376263678407 8.392205632633884, -22.35976125245649 8.149522678417465, -22.37179943577599 7.904479827593563, -22.36111420259841 7.686976909581786, -22.394861026681 7.459474301195111, -22.4068992100005 7.214431450371209, -22.394861026681 6.969388599547307, -22.39454427325957 6.967253221432506, -22.39663570074542 6.958903774881473, -22.43263431641783 6.716220820665053, -22.44467249973734 6.471177969841151, -22.43263431641783 6.22613511901725, -22.42520472119385 6.176048856423258, -22.45924851244561 5.946544257999629, -22.47128669576512 5.701501407175727, -22.45924851244561 5.456458556351826, -22.42324989677319 5.213775602135406, -22.36363753509564 4.975789714039571, -22.30467603942607 4.811003372857127, -22.30921191741285 4.798326443125212, -22.36882427909041 4.560340555029376, -22.40482289476282 4.317657600812956, -22.41686107808233 4.072614749989055, -22.40482289476282 3.827571899165153, -22.38282310228573 3.679261345251841, -22.38695198811661 3.667721882395539, -22.44656434979417 3.429735994299703, -22.48256296546658 3.187053040083284, -22.49460114878609 2.942010189259382, -22.48256296546658 2.69696733843548, -22.44656434979417 2.454284384219061, -22.38695198811661 2.216298496123226, -22.37396184882762 2.1799934889219, -22.38658792514858 2.129587366737637, -22.422586540821 1.886904412521218, -22.43462472414051 1.641861561697316, -22.422586540821 1.396818710873414, -22.38658792514858 1.154135756656995, -22.3592771699918 1.045105110367365, -22.36350762099722 0.9589923018873644, -22.35146943767771 0.7139494510634626, -22.34532001016119 0.6724933781402493, -22.33427096093755 0.4475848143815596, -22.29827234526513 0.2049018601651402, -22.23865998358758 -0.03308402793069509, -22.20425046928654 -0.1292521779944436, -22.261279888389 -0.2886387269097357, -22.32089225006656 -0.5266246150055711, -22.35689086573897 -0.7693075692219906, -22.36718807520162 -0.9789120830667672, -22.42620471134769 -1.214519701527199, -22.46220332702011 -1.457202655743619, -22.47424151033962 -1.702245506567521, -22.46220332702011 -1.947288357391422, -22.42889752836875 -2.171817813823874, -22.43856291195954 -2.36856121658928, -22.42652472864004 -2.613604067413182, -22.4058295706438 -2.753119490067378, -22.40429375712431 -2.784381692441204, -22.40814810495108 -2.799769111506142, -22.4441467206235 -3.042452065722562, -22.456184903943 -3.287494916546463, -22.4441467206235 -3.532537767370365, -22.42631024597718 -3.652781512278879, -22.46166535455815 -3.891126294065749, -22.47370353787766 -4.13616914488965, -22.46166535455815 -4.381211995713552, -22.42566673888573 -4.623894949929971, -22.41659300653852 -4.660119320014077, -22.39777047505845 -4.787010520136427, -22.33815811338089 -5.024996408232262, -22.29060748755867 -5.157891504620128, -22.29667697197584 -5.198808644943893, -22.30871515529535 -5.443851495767794, -22.29913718581248 -5.638815543489387, -22.31302053289855 -5.732409467097974, -22.32505871621806 -5.977452317921876, -22.31302053289855 -6.222495168745778, -22.27702191722613 -6.465178122962197, -22.23700130787304 -6.624949351462579, -22.26191986068643 -6.792936589265861, -22.27337292135948 -7.026068995003135, -22.28286374225524 -7.046135649814543, -22.36551575030755 -7.277132537591112, -22.4251281119851 -7.515118425686947, -22.46112672765752 -7.757801379903367, -22.47316491097703 -8.002844230727268, -22.46112672765752 -8.24788708155117, -22.44973433808717 -8.324688333623625, -22.45836137069585 -8.500295616589442, -22.4573686685416 -8.520502533151651, -22.46998143377628 -8.605530889681926, -22.48201961709579 -8.850573740505828, -22.46998143377628 -9.09561659132973, -22.43398281810386 -9.33829954554615, -22.37437045642631 -9.576285433641985, -22.291718448374 -9.807282321418555, -22.18682277796667 -10.02906558257082, -22.06069364785215 -10.23949932305483, -22.01967276381155 -10.29480958237682, -22.00439035799606 -10.35582036634663, -21.92173834994376 -10.5868172541232, -21.8468060799781 -10.74524822781346, -21.92842458012701 -10.91781604746789, -21.99191048529292 -11.09524726609872, -22.01966467653555 -11.15392857315868, -22.10231668458785 -11.38492546093525, -22.16192904626541 -11.62291134903108, -22.19792766193782 -11.8655943032475, -22.19817821472779 -11.87069442245198, -22.23112272730048 -11.94034974194297, -22.31377473535278 -12.17134662971954, -22.37338709703034 -12.40933251781537, -22.40938571270275 -12.65201547203179, -22.42142389602226 -12.89705832285569, -22.40938571270275 -13.14210117367959, -22.37338709703034 -13.38478412789601, -22.31377473535278 -13.62277001599185, -22.29252178711778 -13.68216802717211, -22.29289905870317 -13.68984756671441, -22.29056292959623 -13.73740056711855, -22.29317150663481 -13.74291593987261, -22.37582351468712 -13.97391282764918, -22.43543587636467 -14.21189871574502, -22.47143449203709 -14.45458166996143, -22.48347267535659 -14.69962452078534, -22.47143449203709 -14.94466737160924, -22.43543587636467 -15.18735032582566, -22.42770850858644 -15.21819970725584, -22.40572505302204 -15.36640012664985, -22.43309942964606 -15.47568476407415, -22.46909804531847 -15.71836771829057, -22.48113622863798 -15.96341056911447, -22.46909804531847 -16.20845341993838, -22.43309942964606 -16.4511363741548, -22.3734870679685 -16.68912226225063, -22.29704609402757 -16.90276047256235, -22.33318673279856 -17.00376679140546, -22.39279909447611 -17.2417526795013, -22.42879771014853 -17.48443563371772, -22.44083589346804 -17.72947848454162, -22.42879771014853 -17.97452133536552, -22.39279909447611 -18.21720428958194, -22.3612750894556 -18.34305517218451, -22.38618093327824 -18.41266234260967, -22.4457932949558 -18.65064823070551, -22.48179191062821 -18.89333118492193, -22.49383009394772 -19.13837403574583, -22.48179191062821 -19.38341688656973, -22.46272989236197 -19.51192257546279, -22.47144518575322 -19.68932644793065, -22.45940700243371 -19.93436929875455, -22.4234083867613 -20.17705225297097, -22.36379602508374 -20.41503814106681, -22.28114401703143 -20.64603502884338, -22.1762483466241 -20.86781828999564, -22.05011921650958 -21.07825203047966, -21.90397131916006 -21.27530965833976, -21.73921213871958 -21.45709340089702, -21.55742839616233 -21.62185258133749, -21.36037076830222 -21.76800047868701, -21.14993702781821 -21.89412960880153, -20.92815376666594 -21.99902527920887, -20.69715687888937 -22.08167728726117, -20.45917099079353 -22.14128964893872, -20.42744614576441 -22.14599558515562, -20.37281740980389 -22.17183305301641, -20.14182052202732 -22.25448506106872, -19.90383463393149 -22.31409742274627, -19.66115167971507 -22.35009603841869, -19.63541513605011 -22.3513603937329, -19.53556033746936 -22.37637271868991, -19.29287738325294 -22.41237133436232, -19.04783453242904 -22.42440951768183, -18.80279168160514 -22.41237133436232, -18.56010872738872 -22.37637271868991, -18.32212283929288 -22.31676035701235, -18.15038036764053 -22.25530991806244, -17.93163213536989 -22.26605632960654, -17.86833950280889 -22.2629469619552, -17.85807912611075 -22.2677997587208, -17.62708223833419 -22.35045176677311, -17.38909635023835 -22.41006412845066, -17.14641339602193 -22.44606274412307, -16.90137054519803 -22.45810092744258, -16.65632769437413 -22.44606274412307, -16.4990865892769 -22.42273822951685, -16.38947103094286 -22.45019549751362, -16.14678807672644 -22.48619411318603, -15.90174522590254 -22.49823229650554)))"; + Geometry shapelyGeom = OperatorImportFromWkt.local().execute(0, Geometry.Type.Unknown, shapelyWKT, null); + Geometry eplGeom = OperatorImportFromWkt.local().execute(0, Geometry.Type.Unknown, eplWKT, null); + NonSimpleResult nonSimpleResult = new NonSimpleResult(); + boolean is_simple = OperatorSimplify.local().isSimpleAsFeature(shapelyGeom, null, true, nonSimpleResult, null); + assertFalse(is_simple); + assertTrue(OperatorSimplify.local().isSimpleAsFeature(eplGeom, null, true, nonSimpleResult, null)); + } + + @Test + public void testIDPass() { + int size = 1000; + List points = new ArrayList<>(size); + List pointList = new ArrayList<>(size); + for (int i = 0; i < size; i++) { + double x = randomWithRange(-20, 20); + double y = randomWithRange(-20, 20); + points.add(String.format("Point(%f %f)", x, y)); + pointList.add(new Point(x, y)); + } + + SimpleStringCursor simpleStringCursor = new SimpleStringCursor(points); + OperatorImportFromWktCursor operatorImportFromWktCursor = new OperatorImportFromWktCursor(0, simpleStringCursor); + double[] distances = new double[]{2.5}; + + GeometryCursor operatorBufferCursor = OperatorBuffer.local().execute(operatorImportFromWktCursor, + null, + distances, + Double.NaN, + 0, + true, + null); + + OperatorExportToWkbCursor operatorExportToGeoJsonCursor = new OperatorExportToWkbCursor(0, operatorBufferCursor); + + while (operatorExportToGeoJsonCursor.hasNext()) { + ByteBuffer wkb = operatorExportToGeoJsonCursor.next(); + long id = operatorExportToGeoJsonCursor.getByteBufferID(); + } + } + + static double randomWithRange(double min, double max) { + double range = Math.abs(max - min); + return (Math.random() * range) + (min <= max ? min : max); + } // @Test // @Ignore // public void testGeodesicBufferUnionPoint() { diff --git a/src/test/java/com/esri/core/geometry/TestWKBSupport.java b/src/test/java/com/esri/core/geometry/TestWKBSupport.java index 01861b08..1525a3b9 100644 --- a/src/test/java/com/esri/core/geometry/TestWKBSupport.java +++ b/src/test/java/com/esri/core/geometry/TestWKBSupport.java @@ -32,79 +32,79 @@ //import com.vividsolutions.jts.io.WKBReader; public class TestWKBSupport extends TestCase { - @Override - protected void setUp() throws Exception { - super.setUp(); - } - - @Override - protected void tearDown() throws Exception { - super.tearDown(); - } - - @Test - public void testWKB() { - // JSON -> GEOM -> WKB - - String strPolygon1 = "{\"xmin\":-1.1663479012889031E7,\"ymin\":4919777.494405342,\"xmax\":-1.1658587043078788E7,\"ymax\":4924669.464215587,\"spatialReference\":{\"wkid\":102100}}"; - // String strPolygon1 = - // "{\"rings\":[[[-119.152450421001,38.4118009590513],[-119.318825070203,38.5271086243914],[-119.575687062955,38.7029101298904],[-119.889341639399,38.9222515603984],[-119.995254694357,38.9941061536377],[-119.995150114198,39.0634913594691],[-119.994541258334,39.1061318056708],[-119.995527335641,39.1587132866355],[-119.995304181493,39.3115454332125],[-119.996011479298,39.4435009764511],[-119.996165311172,39.7206108077274],[-119.996324660047,41.1775662656441],[-119.993459369715,41.9892049531992],[-119.351692186077,41.9888529749781],[-119.3109421304,41.9891353872811],[-118.185316829038,41.9966370981387],[-117.018864363596,41.9947941808341],[-116.992313337997,41.9947945094663],[-115.947544658193,41.9945994628997],[-115.024862911148,41.996506455953],[-114.269471632824,41.9959242345073],[-114.039072662345,41.9953908974688],[-114.038151248682,40.9976868405942],[-114.038108189376,40.1110466529553],[-114.039844684228,39.9087788600023],[-114.040105338584,39.5386849268845],[-114.044267501155,38.6789958815881],[-114.045090206153,38.5710950539539],[-114.047272999176,38.1376524399918],[-114.047260595159,37.5984784866001],[-114.043939384154,36.9965379371421],[-114.043716435713,36.8418489458647],[-114.037392074194,36.2160228969702],[-114.045105557286,36.1939778840226],[-114.107775185788,36.1210907070504],[-114.12902308363,36.041730493896],[-114.206768869568,36.0172554164834],[-114.233472615347,36.0183310595897],[-114.307587598189,36.0622330993643],[-114.303857056018,36.0871084040611],[-114.316095374696,36.1114380366653],[-114.344233941709,36.1374802520568],[-114.380803116644,36.1509912717765],[-114.443945697733,36.1210532841897],[-114.466613475422,36.1247112590539],[-114.530573568745,36.1550902046725],[-114.598935242024,36.1383354528834],[-114.621610747198,36.1419666834504],[-114.712761724737,36.1051810523675],[-114.728150311069,36.0859627711604],[-114.728966012834,36.0587530361083],[-114.717673567756,36.0367580437018],[-114.736212493583,35.9876483502758],[-114.699275906446,35.9116119537412],[-114.661600122152,35.8804735854242],[-114.662462095522,35.8709599070091],[-114.689867343369,35.8474424944766],[-114.682739704595,35.7647034175617],[-114.688820027649,35.7325957399896],[-114.665091345861,35.6930994107107],[-114.668486064922,35.6563989882404],[-114.654065925137,35.6465840800053],[-114.6398667219,35.6113485698329],[-114.653134321223,35.5848331056108],[-114.649792053474,35.5466373866597],[-114.672215155693,35.5157541647721],[-114.645396168451,35.4507608261463],[-114.589584275424,35.3583787306827],[-114.587889840369,35.30476812919],[-114.559583045727,35.2201828714608],[-114.561039964054,35.1743461616313],[-114.572255261053,35.1400677445931],[-114.582616239058,35.1325604694085],[-114.626440825485,35.1339067529872],[-114.6359090842,35.1186557767895],[-114.595631971944,35.0760579746697],[-114.633779872695,35.0418633504303],[-114.621068606189,34.9989144286133],[-115.626197382816,35.7956983148418],[-115.88576934392,36.0012259572723],[-117.160423771838,36.9595941441767],[-117.838686423167,37.457298239715],[-118.417419755966,37.8866767486211],[-119.152450421001,38.4118009590513]]], \"spatialReference\":{\"wkid\":4326}}"; - - MapGeometry mapGeom = GeometryEngine.jsonToGeometry(strPolygon1); - Geometry geom = mapGeom.getGeometry(); - OperatorExportToWkb operatorExport = (OperatorExportToWkb) OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.ExportToWkb); - ByteBuffer byteBuffer = operatorExport.execute(0, geom, null); - byte[] wkb = byteBuffer.array(); - - // WKB -> GEOM -> JSON - OperatorImportFromWkb operatorImport = (OperatorImportFromWkb) OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.ImportFromWkb); - geom = operatorImport.execute(0, Geometry.Type.Polygon, - ByteBuffer.wrap(wkb), null); - // geom = operatorImport.execute(0, Geometry.Type.Polygon, - // byteBuffer); - String outputPolygon1 = GeometryEngine.geometryToJson(-1, geom); - } - - @Test - public void testWKB2() throws Exception { - // JSON -> GEOM -> WKB - - // String strPolygon1 = - // "{\"xmin\":-1.16605115291E7,\"ymin\":4925189.941699997,\"xmax\":-1.16567772126E7,\"ymax\":4928658.771399997,\"spatialReference\":{\"wkid\":102100}}"; - String strPolygon1 = "{\"rings\" : [ [ [-1.16605115291E7,4925189.941699997], [-1.16567772126E7,4925189.941699997], [-1.16567772126E7,4928658.771399997], [-1.16605115291E7,4928658.771399997], [-1.16605115291E7,4925189.941699997] ] ], \"spatialReference\" : {\"wkid\" : 102100}}"; - - MapGeometry mapGeom = GeometryEngine.jsonToGeometry(strPolygon1); - Geometry geom = mapGeom.getGeometry(); - - // simplifying geom - OperatorSimplify operatorSimplify = (OperatorSimplify) OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.Simplify); - SpatialReference sr = SpatialReference.create(102100); - geom = operatorSimplify.execute(geom, sr, true, null); - - OperatorExportToWkb operatorExport = (OperatorExportToWkb) OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.ExportToWkb); - ByteBuffer byteBuffer = operatorExport.execute(0, geom, null); - byte[] wkb = byteBuffer.array(); - - // // checking WKB correctness - // WKBReader jtsReader = new WKBReader(); - // com.vividsolutions.jts.geom.Geometry jtsGeom = jtsReader.read(wkb); - // System.out.println("jtsGeom = " + jtsGeom); - - // WKB -> GEOM -> JSON - OperatorImportFromWkb operatorImport = (OperatorImportFromWkb) OperatorFactoryLocal - .getInstance().getOperator(Operator.Type.ImportFromWkb); - geom = operatorImport.execute(0, Geometry.Type.Polygon, - ByteBuffer.wrap(wkb), null); - assertTrue(!geom.isEmpty()); - // geom = operatorImport.execute(0, Geometry.Type.Polygon, byteBuffer); - // String outputPolygon1 = GeometryEngine.geometryToJson(-1, geom); - // System.out.println(strPolygon1); - // System.out.println(outputPolygon1); - - } + @Override + protected void setUp() throws Exception { + super.setUp(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + } + + @Test + public void testWKB() { + // JSON -> GEOM -> WKB + + String strPolygon1 = "{\"xmin\":-1.1663479012889031E7,\"ymin\":4919777.494405342,\"xmax\":-1.1658587043078788E7,\"ymax\":4924669.464215587,\"spatialReference\":{\"wkid\":102100}}"; + // String strPolygon1 = + // "{\"rings\":[[[-119.152450421001,38.4118009590513],[-119.318825070203,38.5271086243914],[-119.575687062955,38.7029101298904],[-119.889341639399,38.9222515603984],[-119.995254694357,38.9941061536377],[-119.995150114198,39.0634913594691],[-119.994541258334,39.1061318056708],[-119.995527335641,39.1587132866355],[-119.995304181493,39.3115454332125],[-119.996011479298,39.4435009764511],[-119.996165311172,39.7206108077274],[-119.996324660047,41.1775662656441],[-119.993459369715,41.9892049531992],[-119.351692186077,41.9888529749781],[-119.3109421304,41.9891353872811],[-118.185316829038,41.9966370981387],[-117.018864363596,41.9947941808341],[-116.992313337997,41.9947945094663],[-115.947544658193,41.9945994628997],[-115.024862911148,41.996506455953],[-114.269471632824,41.9959242345073],[-114.039072662345,41.9953908974688],[-114.038151248682,40.9976868405942],[-114.038108189376,40.1110466529553],[-114.039844684228,39.9087788600023],[-114.040105338584,39.5386849268845],[-114.044267501155,38.6789958815881],[-114.045090206153,38.5710950539539],[-114.047272999176,38.1376524399918],[-114.047260595159,37.5984784866001],[-114.043939384154,36.9965379371421],[-114.043716435713,36.8418489458647],[-114.037392074194,36.2160228969702],[-114.045105557286,36.1939778840226],[-114.107775185788,36.1210907070504],[-114.12902308363,36.041730493896],[-114.206768869568,36.0172554164834],[-114.233472615347,36.0183310595897],[-114.307587598189,36.0622330993643],[-114.303857056018,36.0871084040611],[-114.316095374696,36.1114380366653],[-114.344233941709,36.1374802520568],[-114.380803116644,36.1509912717765],[-114.443945697733,36.1210532841897],[-114.466613475422,36.1247112590539],[-114.530573568745,36.1550902046725],[-114.598935242024,36.1383354528834],[-114.621610747198,36.1419666834504],[-114.712761724737,36.1051810523675],[-114.728150311069,36.0859627711604],[-114.728966012834,36.0587530361083],[-114.717673567756,36.0367580437018],[-114.736212493583,35.9876483502758],[-114.699275906446,35.9116119537412],[-114.661600122152,35.8804735854242],[-114.662462095522,35.8709599070091],[-114.689867343369,35.8474424944766],[-114.682739704595,35.7647034175617],[-114.688820027649,35.7325957399896],[-114.665091345861,35.6930994107107],[-114.668486064922,35.6563989882404],[-114.654065925137,35.6465840800053],[-114.6398667219,35.6113485698329],[-114.653134321223,35.5848331056108],[-114.649792053474,35.5466373866597],[-114.672215155693,35.5157541647721],[-114.645396168451,35.4507608261463],[-114.589584275424,35.3583787306827],[-114.587889840369,35.30476812919],[-114.559583045727,35.2201828714608],[-114.561039964054,35.1743461616313],[-114.572255261053,35.1400677445931],[-114.582616239058,35.1325604694085],[-114.626440825485,35.1339067529872],[-114.6359090842,35.1186557767895],[-114.595631971944,35.0760579746697],[-114.633779872695,35.0418633504303],[-114.621068606189,34.9989144286133],[-115.626197382816,35.7956983148418],[-115.88576934392,36.0012259572723],[-117.160423771838,36.9595941441767],[-117.838686423167,37.457298239715],[-118.417419755966,37.8866767486211],[-119.152450421001,38.4118009590513]]], \"spatialReference\":{\"wkid\":4326}}"; + + MapGeometry mapGeom = GeometryEngine.jsonToGeometry(strPolygon1); + Geometry geom = mapGeom.getGeometry(); + OperatorExportToWkb operatorExport = (OperatorExportToWkb) OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.ExportToWkb); + ByteBuffer byteBuffer = operatorExport.execute(0, geom, null); + byte[] wkb = byteBuffer.array(); + + // WKB -> GEOM -> JSON + OperatorImportFromWkb operatorImport = (OperatorImportFromWkb) OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.ImportFromWkb); + geom = operatorImport.execute(0, Geometry.Type.Polygon, + ByteBuffer.wrap(wkb), null); + // geom = operatorImport.execute(0, Geometry.Type.Polygon, + // byteBuffer); + String outputPolygon1 = GeometryEngine.geometryToJson(-1, geom); + } + + @Test + public void testWKB2() throws Exception { + // JSON -> GEOM -> WKB + + // String strPolygon1 = + // "{\"xmin\":-1.16605115291E7,\"ymin\":4925189.941699997,\"xmax\":-1.16567772126E7,\"ymax\":4928658.771399997,\"spatialReference\":{\"wkid\":102100}}"; + String strPolygon1 = "{\"rings\" : [ [ [-1.16605115291E7,4925189.941699997], [-1.16567772126E7,4925189.941699997], [-1.16567772126E7,4928658.771399997], [-1.16605115291E7,4928658.771399997], [-1.16605115291E7,4925189.941699997] ] ], \"spatialReference\" : {\"wkid\" : 102100}}"; + + MapGeometry mapGeom = GeometryEngine.jsonToGeometry(strPolygon1); + Geometry geom = mapGeom.getGeometry(); + + // simplifying geom + OperatorSimplify operatorSimplify = (OperatorSimplify) OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.Simplify); + SpatialReference sr = SpatialReference.create(102100); + geom = operatorSimplify.execute(geom, sr, true, null); + + OperatorExportToWkb operatorExport = (OperatorExportToWkb) OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.ExportToWkb); + ByteBuffer byteBuffer = operatorExport.execute(0, geom, null); + byte[] wkb = byteBuffer.array(); + + // // checking WKB correctness + // WKBReader jtsReader = new WKBReader(); + // com.vividsolutions.jts.geom.Geometry jtsGeom = jtsReader.read(wkb); + // System.out.println("jtsGeom = " + jtsGeom); + + // WKB -> GEOM -> JSON + OperatorImportFromWkb operatorImport = (OperatorImportFromWkb) OperatorFactoryLocal + .getInstance().getOperator(Operator.Type.ImportFromWkb); + geom = operatorImport.execute(0, Geometry.Type.Polygon, + ByteBuffer.wrap(wkb), null); + assertTrue(!geom.isEmpty()); + // geom = operatorImport.execute(0, Geometry.Type.Polygon, byteBuffer); + // String outputPolygon1 = GeometryEngine.geometryToJson(-1, geom); + // System.out.println(strPolygon1); + // System.out.println(outputPolygon1); + + } } diff --git a/src/test/java/com/esri/core/geometry/TestWkbImportOnPostgresST.java b/src/test/java/com/esri/core/geometry/TestWkbImportOnPostgresST.java index 59691c18..56b59d56 100644 --- a/src/test/java/com/esri/core/geometry/TestWkbImportOnPostgresST.java +++ b/src/test/java/com/esri/core/geometry/TestWkbImportOnPostgresST.java @@ -34,40 +34,40 @@ import java.sql.ResultSet; public class TestWkbImportOnPostgresST extends TestCase { - @Override - protected void setUp() throws Exception { - super.setUp(); - } + @Override + protected void setUp() throws Exception { + super.setUp(); + } - @Override - protected void tearDown() throws Exception { - super.tearDown(); - } + @Override + protected void tearDown() throws Exception { + super.tearDown(); + } - @Test - public static void testWkbImportOnPostgresST() throws Exception { - try { - Connection con = DriverManager.getConnection( - "jdbc:postgresql://tb.esri.com:5432/new_gdb", "tb", "tb"); - OperatorFactoryLocal factory = OperatorFactoryLocal.getInstance(); - OperatorImportFromWkb operatorImport = (OperatorImportFromWkb) factory - .getOperator(Operator.Type.ImportFromWkb); - String stmt = "SELECT objectid,sde.st_asbinary(shape) FROM new_gdb.tb.interstates a WHERE objectid IN (2) AND (a.shape IS NULL OR sde.st_geometrytype(shape)::text IN ('ST_MULTILINESTRING','ST_LINESTRING')) LIMIT 1000"; - PreparedStatement ps = con.prepareStatement(stmt); - ResultSet rs = ps.executeQuery(); - while (rs.next()) { - byte[] rsWkbGeom = rs.getBytes(2); - @SuppressWarnings("unused") - Geometry geomBorg = null; - if (rsWkbGeom != null) { - geomBorg = operatorImport.execute(0, Geometry.Type.Unknown, - ByteBuffer.wrap(rsWkbGeom), null); - } - } + @Test + public static void testWkbImportOnPostgresST() throws Exception { + try { + Connection con = DriverManager.getConnection( + "jdbc:postgresql://tb.esri.com:5432/new_gdb", "tb", "tb"); + OperatorFactoryLocal factory = OperatorFactoryLocal.getInstance(); + OperatorImportFromWkb operatorImport = (OperatorImportFromWkb) factory + .getOperator(Operator.Type.ImportFromWkb); + String stmt = "SELECT objectid,sde.st_asbinary(shape) FROM new_gdb.tb.interstates a WHERE objectid IN (2) AND (a.shape IS NULL OR sde.st_geometrytype(shape)::text IN ('ST_MULTILINESTRING','ST_LINESTRING')) LIMIT 1000"; + PreparedStatement ps = con.prepareStatement(stmt); + ResultSet rs = ps.executeQuery(); + while (rs.next()) { + byte[] rsWkbGeom = rs.getBytes(2); + @SuppressWarnings("unused") + Geometry geomBorg = null; + if (rsWkbGeom != null) { + geomBorg = operatorImport.execute(0, Geometry.Type.Unknown, + ByteBuffer.wrap(rsWkbGeom), null); + } + } - ps.close(); - con.close(); - } catch (Exception e) { - } - } + ps.close(); + con.close(); + } catch (Exception e) { + } + } } diff --git a/src/test/java/com/esri/core/geometry/TestWkid.java b/src/test/java/com/esri/core/geometry/TestWkid.java index a50dfca5..08154143 100644 --- a/src/test/java/com/esri/core/geometry/TestWkid.java +++ b/src/test/java/com/esri/core/geometry/TestWkid.java @@ -28,27 +28,27 @@ import org.junit.Test; public class TestWkid extends TestCase { - @Test - public void test() { - SpatialReference sr = SpatialReference.create(102100); - assertTrue(sr.getID() == 102100); - assertTrue(sr.getLatestID() == 3857); - assertTrue(sr.getOldID() == 102100); - assertTrue(sr.getTolerance() == 0.001); - - SpatialReference sr84 = SpatialReference.create(4326); - double tol84 = sr84.getTolerance(); - assertTrue(Math.abs(tol84 - 8.983152841195213E-9) < 8.983152841195213E-9 * 8.983152841195213E-9); - } - - - @Test - public void test_80() { - SpatialReference sr = SpatialReference.create(3857); - assertTrue(sr.getID() == 3857); - assertTrue(sr.getLatestID() == 3857); - assertTrue(sr.getOldID() == 102100); - assertTrue(sr.getTolerance() == 0.001); - } + @Test + public void test() { + SpatialReference sr = SpatialReference.create(102100); + assertTrue(sr.getID() == 102100); + assertTrue(sr.getLatestID() == 3857); + assertTrue(sr.getOldID() == 102100); + assertTrue(sr.getTolerance() == 0.001); + + SpatialReference sr84 = SpatialReference.create(4326); + double tol84 = sr84.getTolerance(); + assertTrue(Math.abs(tol84 - 8.983152841195213E-9) < 8.983152841195213E-9 * 8.983152841195213E-9); + } + + + @Test + public void test_80() { + SpatialReference sr = SpatialReference.create(3857); + assertTrue(sr.getID() == 3857); + assertTrue(sr.getLatestID() == 3857); + assertTrue(sr.getOldID() == 102100); + assertTrue(sr.getTolerance() == 0.001); + } } diff --git a/src/test/java/com/esri/core/geometry/TestWktParser.java b/src/test/java/com/esri/core/geometry/TestWktParser.java index cde7b98d..a534333c 100644 --- a/src/test/java/com/esri/core/geometry/TestWktParser.java +++ b/src/test/java/com/esri/core/geometry/TestWktParser.java @@ -29,1088 +29,1088 @@ public class TestWktParser extends TestCase { - @Test - public void testGeometryCollection() { - String s = " geometrycollection emPty "; - WktParser wktParser = new WktParser(); - wktParser.resetParser(s); + @Test + public void testGeometryCollection() { + String s = " geometrycollection emPty "; + WktParser wktParser = new WktParser(); + wktParser.resetParser(s); - int currentToken; - double value; + int currentToken; + double value; - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.geometrycollection); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.geometrycollection); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.empty); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.empty); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.not_available); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.not_available); - s = " geometrycollection zm ( geometrycollection zm ( POINT ZM ( 5. +1.e+0004 13 17) ), LineString zm emPty, MULTIpolyGON zM (((1 1 1 1))) ) "; - wktParser.resetParser(s); + s = " geometrycollection zm ( geometrycollection zm ( POINT ZM ( 5. +1.e+0004 13 17) ), LineString zm emPty, MULTIpolyGON zM (((1 1 1 1))) ) "; + wktParser.resetParser(s); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.geometrycollection); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.geometrycollection); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.attribute_zm); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.attribute_zm); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.left_paren); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.left_paren); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.geometrycollection); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.geometrycollection); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.attribute_zm); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.attribute_zm); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.left_paren); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.left_paren); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.point); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.point); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.attribute_zm); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.attribute_zm); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.left_paren); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.left_paren); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.x_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.x_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 5.0); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 5.0); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.y_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.y_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 1.0e4); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 1.0e4); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.z_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.z_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 13); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 13); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.m_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.m_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 17); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 17); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.right_paren); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.right_paren); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.right_paren); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.right_paren); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.linestring); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.linestring); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.attribute_zm); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.attribute_zm); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.empty); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.empty); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.multipolygon); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.multipolygon); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.attribute_zm); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.attribute_zm); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.left_paren); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.left_paren); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.left_paren); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.left_paren); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.left_paren); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.left_paren); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.x_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.x_literal); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.y_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.y_literal); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.z_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.z_literal); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.m_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.m_literal); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.right_paren); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.right_paren); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.right_paren); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.right_paren); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.right_paren); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.right_paren); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.right_paren); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.right_paren); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.not_available); - } + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.not_available); + } - @Test - public void testMultiPolygon() { - String s = " MultIPolYgOn emPty "; - WktParser wktParser = new WktParser(); - wktParser.resetParser(s); + @Test + public void testMultiPolygon() { + String s = " MultIPolYgOn emPty "; + WktParser wktParser = new WktParser(); + wktParser.resetParser(s); - int currentToken; - double value; + int currentToken; + double value; - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.multipolygon); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.multipolygon); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.empty); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.empty); - s = " MULTIpolyGON zM ( empty , ( empty, ( 5. +1.e+0004 13 17, -.1e07 .006 13 17 ) , empty , (4 003. 13 17, 02E-3 .3e2 13 17) ) , empty, ( ( 5. +1.e+0004 13 17, -.1e07 .006 13 17) , (4 003. 13 17 , 02E-3 .3e2 13 17) ) ) "; - wktParser.resetParser(s); + s = " MULTIpolyGON zM ( empty , ( empty, ( 5. +1.e+0004 13 17, -.1e07 .006 13 17 ) , empty , (4 003. 13 17, 02E-3 .3e2 13 17) ) , empty, ( ( 5. +1.e+0004 13 17, -.1e07 .006 13 17) , (4 003. 13 17 , 02E-3 .3e2 13 17) ) ) "; + wktParser.resetParser(s); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.multipolygon); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.multipolygon); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.attribute_zm); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.attribute_zm); - // Start first polygon - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.left_paren); + // Start first polygon + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.left_paren); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.empty); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.empty); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.left_paren); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.left_paren); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.empty); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.empty); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.left_paren); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.left_paren); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.x_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.x_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 5.0); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 5.0); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.y_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.y_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 1.0e4); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 1.0e4); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.z_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.z_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 13); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 13); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.m_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.m_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 17); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 17); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.x_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.x_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == -0.1e7); + value = wktParser.currentNumericLiteral(); + assertTrue(value == -0.1e7); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.y_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.y_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 0.006); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 0.006); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.z_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.z_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 13); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 13); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.m_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.m_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 17); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 17); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.right_paren); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.right_paren); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.empty); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.empty); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.left_paren); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.left_paren); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.x_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.x_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 4.0); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 4.0); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.y_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.y_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 3.0); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 3.0); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.z_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.z_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 13); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 13); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.m_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.m_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 17); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 17); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.x_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.x_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 2.0e-3); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 2.0e-3); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.y_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.y_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 0.3e2); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 0.3e2); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.z_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.z_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 13); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 13); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.m_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.m_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 17); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 17); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.right_paren); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.right_paren); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.right_paren); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.right_paren); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.empty); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.empty); - // End of First polygon + // End of First polygon - // Start Second Polygon - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.left_paren); + // Start Second Polygon + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.left_paren); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.left_paren); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.left_paren); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.x_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.x_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 5.0); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 5.0); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.y_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.y_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 1.0e4); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 1.0e4); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.z_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.z_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 13); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 13); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.m_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.m_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 17); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 17); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.x_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.x_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == -0.1e7); + value = wktParser.currentNumericLiteral(); + assertTrue(value == -0.1e7); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.y_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.y_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 0.006); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 0.006); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.z_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.z_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 13); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 13); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.m_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.m_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 17); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 17); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.right_paren); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.right_paren); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.left_paren); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.left_paren); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.x_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.x_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 4.0); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 4.0); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.y_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.y_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 3.0); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 3.0); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.z_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.z_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 13); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 13); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.m_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.m_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 17); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 17); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.x_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.x_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 2.0e-3); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 2.0e-3); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.y_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.y_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 0.3e2); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 0.3e2); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.z_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.z_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 13); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 13); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.m_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.m_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 17); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 17); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.right_paren); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.right_paren); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.right_paren); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.right_paren); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.right_paren); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.right_paren); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.not_available); - } + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.not_available); + } - @Test - public void testMultiLineString() { - String s = " MultiLineString emPty "; - WktParser wktParser = new WktParser(); - wktParser.resetParser(s); + @Test + public void testMultiLineString() { + String s = " MultiLineString emPty "; + WktParser wktParser = new WktParser(); + wktParser.resetParser(s); - int currentToken; - double value; + int currentToken; + double value; - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.multilinestring); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.multilinestring); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.empty); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.empty); - s = " MultiLineString Z ( empty, ( 5. +1.e+0004 13, -.1e07 .006 13 ) , empty , (4 003. 13 , 02E-3 .3e2 13 ) , empty, ( 5. +1.e+0004 13 , -.1e07 .006 13) , (4 003. 13 , 02E-3 .3e2 13 ) ) "; - wktParser.resetParser(s); + s = " MultiLineString Z ( empty, ( 5. +1.e+0004 13, -.1e07 .006 13 ) , empty , (4 003. 13 , 02E-3 .3e2 13 ) , empty, ( 5. +1.e+0004 13 , -.1e07 .006 13) , (4 003. 13 , 02E-3 .3e2 13 ) ) "; + wktParser.resetParser(s); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.multilinestring); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.multilinestring); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.attribute_z); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.attribute_z); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.left_paren); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.left_paren); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.empty); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.empty); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.left_paren); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.left_paren); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.x_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.x_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 5.0); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 5.0); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.y_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.y_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 1.0e4); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 1.0e4); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.z_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.z_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 13); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 13); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.x_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.x_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == -0.1e7); + value = wktParser.currentNumericLiteral(); + assertTrue(value == -0.1e7); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.y_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.y_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 0.006); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 0.006); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.z_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.z_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 13); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 13); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.right_paren); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.right_paren); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.empty); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.empty); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.left_paren); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.left_paren); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.x_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.x_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 4.0); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 4.0); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.y_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.y_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 3.0); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 3.0); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.z_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.z_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 13); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 13); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.x_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.x_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 2.0e-3); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 2.0e-3); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.y_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.y_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 0.3e2); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 0.3e2); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.z_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.z_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 13); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 13); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.right_paren); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.right_paren); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.empty); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.empty); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.left_paren); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.left_paren); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.x_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.x_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 5.0); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 5.0); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.y_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.y_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 1.0e4); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 1.0e4); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.z_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.z_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 13); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 13); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.x_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.x_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == -0.1e7); + value = wktParser.currentNumericLiteral(); + assertTrue(value == -0.1e7); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.y_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.y_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 0.006); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 0.006); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.z_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.z_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 13); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 13); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.right_paren); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.right_paren); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.left_paren); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.left_paren); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.x_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.x_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 4.0); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 4.0); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.y_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.y_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 3.0); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 3.0); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.z_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.z_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 13); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 13); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.x_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.x_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 2.0e-3); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 2.0e-3); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.y_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.y_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 0.3e2); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 0.3e2); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.z_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.z_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 13); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 13); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.right_paren); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.right_paren); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.right_paren); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.right_paren); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.not_available); - } + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.not_available); + } - @Test - public void testMultiPoint() { - String s = " MultipoInt emPty "; - WktParser wktParser = new WktParser(); - wktParser.resetParser(s); + @Test + public void testMultiPoint() { + String s = " MultipoInt emPty "; + WktParser wktParser = new WktParser(); + wktParser.resetParser(s); - int currentToken; - double value; + int currentToken; + double value; - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.multipoint); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.multipoint); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.empty); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.empty); - s = " Multipoint Z ( empty, ( 5. +1.e+0004 13 ), (-.1e07 .006 13 ) , empty , (4 003. 13 ), (02E-3 .3e2 13 ) ) "; - wktParser.resetParser(s); + s = " Multipoint Z ( empty, ( 5. +1.e+0004 13 ), (-.1e07 .006 13 ) , empty , (4 003. 13 ), (02E-3 .3e2 13 ) ) "; + wktParser.resetParser(s); - currentToken = wktParser.nextToken(); // bug here - assertTrue(currentToken == WktParser.WktToken.multipoint); + currentToken = wktParser.nextToken(); // bug here + assertTrue(currentToken == WktParser.WktToken.multipoint); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.attribute_z); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.attribute_z); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.left_paren); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.left_paren); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.empty); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.empty); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.left_paren); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.left_paren); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.x_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.x_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 5.0); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 5.0); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.y_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.y_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 1.0e4); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 1.0e4); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.z_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.z_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 13); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 13); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.right_paren); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.right_paren); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.left_paren); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.left_paren); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.x_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.x_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == -0.1e7); + value = wktParser.currentNumericLiteral(); + assertTrue(value == -0.1e7); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.y_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.y_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 0.006); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 0.006); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.z_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.z_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 13); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 13); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.right_paren); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.right_paren); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.empty); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.empty); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.left_paren); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.left_paren); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.x_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.x_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 4.0); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 4.0); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.y_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.y_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 3.0); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 3.0); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.z_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.z_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 13); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 13); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.right_paren); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.right_paren); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.left_paren); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.left_paren); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.x_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.x_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 2.0e-3); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 2.0e-3); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.y_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.y_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 0.3e2); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 0.3e2); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.z_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.z_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 13); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 13); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.right_paren); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.right_paren); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.right_paren); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.right_paren); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.not_available); - } + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.not_available); + } - @Test - public void testPolygon() { - String s = " Polygon emPty "; - WktParser wktParser = new WktParser(); - wktParser.resetParser(s); + @Test + public void testPolygon() { + String s = " Polygon emPty "; + WktParser wktParser = new WktParser(); + wktParser.resetParser(s); - int currentToken; - double value; + int currentToken; + double value; - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.polygon); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.polygon); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.empty); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.empty); - s = " polyGON M ( empty, ( 5. +1.e+0004 13, -.1e07 .006 13 ) , empty , (4 003. 13 , 02E-3 .3e2 13 ) , empty, ( 5. +1.e+0004 13 , -.1e07 .006 13) , (4 003. 13 , 02E-3 .3e2 13 ) ) "; - wktParser.resetParser(s); + s = " polyGON M ( empty, ( 5. +1.e+0004 13, -.1e07 .006 13 ) , empty , (4 003. 13 , 02E-3 .3e2 13 ) , empty, ( 5. +1.e+0004 13 , -.1e07 .006 13) , (4 003. 13 , 02E-3 .3e2 13 ) ) "; + wktParser.resetParser(s); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.polygon); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.polygon); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.attribute_m); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.attribute_m); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.left_paren); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.left_paren); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.empty); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.empty); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.left_paren); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.left_paren); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.x_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.x_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 5.0); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 5.0); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.y_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.y_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 1.0e4); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 1.0e4); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.m_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.m_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 13); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 13); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.x_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.x_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == -0.1e7); + value = wktParser.currentNumericLiteral(); + assertTrue(value == -0.1e7); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.y_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.y_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 0.006); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 0.006); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.m_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.m_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 13); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 13); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.right_paren); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.right_paren); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.empty); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.empty); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.left_paren); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.left_paren); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.x_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.x_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 4.0); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 4.0); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.y_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.y_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 3.0); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 3.0); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.m_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.m_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 13); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 13); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.x_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.x_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 2.0e-3); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 2.0e-3); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.y_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.y_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 0.3e2); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 0.3e2); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.m_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.m_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 13); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 13); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.right_paren); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.right_paren); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.empty); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.empty); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.left_paren); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.left_paren); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.x_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.x_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 5.0); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 5.0); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.y_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.y_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 1.0e4); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 1.0e4); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.m_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.m_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 13); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 13); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.x_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.x_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == -0.1e7); + value = wktParser.currentNumericLiteral(); + assertTrue(value == -0.1e7); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.y_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.y_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 0.006); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 0.006); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.m_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.m_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 13); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 13); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.right_paren); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.right_paren); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.left_paren); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.left_paren); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.x_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.x_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 4.0); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 4.0); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.y_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.y_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 3.0); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 3.0); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.m_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.m_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 13); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 13); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.x_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.x_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 2.0e-3); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 2.0e-3); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.y_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.y_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 0.3e2); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 0.3e2); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.m_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.m_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 13); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 13); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.right_paren); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.right_paren); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.right_paren); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.right_paren); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.not_available); - } + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.not_available); + } - @Test - public void testLineString() { - String s = " LineString emPty "; - WktParser wktParser = new WktParser(); - wktParser.resetParser(s); + @Test + public void testLineString() { + String s = " LineString emPty "; + WktParser wktParser = new WktParser(); + wktParser.resetParser(s); - int currentToken; - double value; + int currentToken; + double value; - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.linestring); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.linestring); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.empty); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.empty); - s = " LineString ( 5. +1.e+0004 , -.1e07 .006 ) "; - wktParser.resetParser(s); + s = " LineString ( 5. +1.e+0004 , -.1e07 .006 ) "; + wktParser.resetParser(s); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.linestring); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.linestring); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.left_paren); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.left_paren); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.x_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.x_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 5.0); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 5.0); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.y_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.y_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 1.0e4); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 1.0e4); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.x_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.x_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == -0.1e7); + value = wktParser.currentNumericLiteral(); + assertTrue(value == -0.1e7); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.y_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.y_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 0.006); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 0.006); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.right_paren); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.right_paren); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.not_available); - } + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.not_available); + } - @Test - public void testPoint() { - String s = " PoInT emPty "; - WktParser wktParser = new WktParser(); - wktParser.resetParser(s); + @Test + public void testPoint() { + String s = " PoInT emPty "; + WktParser wktParser = new WktParser(); + wktParser.resetParser(s); - int currentToken; - double value; + int currentToken; + double value; - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.point); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.point); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.empty); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.empty); - s = " POINT ZM ( 5. +1.e+0004 13 17) "; - wktParser.resetParser(s); + s = " POINT ZM ( 5. +1.e+0004 13 17) "; + wktParser.resetParser(s); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.point); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.point); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.attribute_zm); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.attribute_zm); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.left_paren); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.left_paren); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.x_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.x_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 5.0); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 5.0); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.y_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.y_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 1.0e4); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 1.0e4); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.z_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.z_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 13); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 13); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.m_literal); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.m_literal); - value = wktParser.currentNumericLiteral(); - assertTrue(value == 17); + value = wktParser.currentNumericLiteral(); + assertTrue(value == 17); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.right_paren); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.right_paren); - currentToken = wktParser.nextToken(); - assertTrue(currentToken == WktParser.WktToken.not_available); + currentToken = wktParser.nextToken(); + assertTrue(currentToken == WktParser.WktToken.not_available); - s = " PoInt "; - wktParser.resetParser(s); + s = " PoInt "; + wktParser.resetParser(s); - wktParser.nextToken(); - } + wktParser.nextToken(); + } } diff --git a/src/test/java/com/esri/core/geometry/Utils.java b/src/test/java/com/esri/core/geometry/Utils.java index 309deb1c..e1e1c4c5 100644 --- a/src/test/java/com/esri/core/geometry/Utils.java +++ b/src/test/java/com/esri/core/geometry/Utils.java @@ -25,8 +25,8 @@ package com.esri.core.geometry; public class Utils { - static void showProjectedGeometryInfo(MapGeometry mapGeom) { - return; + static void showProjectedGeometryInfo(MapGeometry mapGeom) { + return; /* System.out.println("\n"); MapGeometry geom = mapGeom; @@ -94,6 +94,6 @@ static void showProjectedGeometryInfo(MapGeometry mapGeom) { System.out.println("wkid: " + wkid); }*/ - } + } }