= 0) {
return m_attributes[getEndPointOffset(m_description, end_point)
+ m_description.getPointAttributeOffset_(attribute_index)
@@ -637,7 +648,6 @@ void setAttributeAsDblImpl_(int end_point, int semantics, int ordinate,
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
@@ -647,32 +657,17 @@ void setAttributeAsDblImpl_(int end_point, int semantics, int ordinate,
void _ensureAttributes() {
_touch();
if (m_attributes == null && m_description.getTotalComponentCount() > 2) {
- m_attributes = new double[(m_description.getTotalComponentCount() - 2) * 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);
-
- 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++;
- }
- }
+ 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 (m_attributes == null) {
- m_description = newDescription;
- return;
- }
-
if (newDescription.getTotalComponentCount() > 2) {
int[] mapping = VertexDescriptionDesignerImpl.mapAttributes(newDescription, m_description);
@@ -726,8 +721,6 @@ protected void _assignVertexDescriptionImpl(VertexDescription newDescription) {
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;
@@ -742,7 +735,6 @@ protected void _assignVertexDescriptionImpl(VertexDescription newDescription) {
int attributeIndex = m_description.getAttributeIndex(semantics);
if (attributeIndex >= 0) {
- _ensureAttributes();
return m_attributes[_getEndPointOffset(m_description, endPoint)
+ m_description._getPointAttributeOffset(attributeIndex)
- 2 + ordinate];
@@ -776,14 +768,10 @@ void _setAttributeAsDbl(int endPoint, int semantics, int ordinate,
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;
@@ -1007,7 +995,7 @@ public boolean equals(Object _other) {
return false;
for (int i = 0, n = (m_description.getTotalComponentCount() - 2) * 2; i < n; i++)
- if (m_attributes[i] != other.m_attributes[i])
+ if (!NumberUtils.isEqualNonIEEE(m_attributes[i], other.m_attributes[i]))
return false;
return true;
@@ -1022,7 +1010,7 @@ public boolean equals(Object _other) {
public int hashCode() {
int hashCode = m_description.hashCode();
hashCode = NumberUtils.hash(hashCode, m_envelope.hashCode());
- if (!isEmpty() && m_attributes != null) {
+ if (!isEmpty()) {
for (int i = 0, n = (m_description.getTotalComponentCount() - 2) * 2; i < n; i++) {
hashCode = NumberUtils.hash(hashCode, m_attributes[i]);
}
@@ -1110,28 +1098,28 @@ public void setYMax(double y) {
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);
- }
- }
- }
-
+ @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.
*/
diff --git a/src/main/java/com/esri/core/geometry/Envelope1D.java b/src/main/java/com/esri/core/geometry/Envelope1D.java
index 96540895..e000ef0a 100644
--- a/src/main/java/com/esri/core/geometry/Envelope1D.java
+++ b/src/main/java/com/esri/core/geometry/Envelope1D.java
@@ -133,8 +133,10 @@ public boolean contains(double v) {
/**
* 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(/* const */Envelope1D other) /* const */
+ public boolean contains(Envelope1D other)
{
return other.vmin >= vmin && other.vmax <= vmax;
}
@@ -223,7 +225,13 @@ public boolean equals(Object _other)
@Override
public int hashCode() {
- return NumberUtils.hash(NumberUtils.hash(vmin), vmax);
+ 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 172619dd..5c8bebf5 100644
--- a/src/main/java/com/esri/core/geometry/Envelope2D.java
+++ b/src/main/java/com/esri/core/geometry/Envelope2D.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.
@@ -28,12 +28,14 @@
import java.io.ObjectStreamException;
import java.io.Serializable;
+import static com.esri.core.geometry.SizeOf.SIZE_OF_ENVELOPE2D;
+
/**
* 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;
@@ -79,6 +81,11 @@ public Envelope2D(double _xmin, double _ymin, double _xmax, double _ymax) {
public Envelope2D(Envelope2D other) {
setCoords(other);
}
+
+ public int estimateMemorySize()
+ {
+ return SIZE_OF_ENVELOPE2D;
+ }
public void setCoords(double _x, double _y) {
xmin = _x;
@@ -124,6 +131,7 @@ public Envelope2D getInflated(double dx, double dy) {
/**
* Sets the envelope from the array of points. The envelope will be set to
* empty if the array is null.
+ * @param points The points to set the envelope from. No element in the array can be null.
*/
public void setFromPoints(Point2D[] points) {
if (points == null || points.length == 0) {
@@ -191,6 +199,8 @@ else if (ymax < y)
/**
* Merges a point with this envelope without checking if the envelope is
* empty. Use with care.
+ * @param x The x coord of the point
+ * @param y the y coord in the point
*/
public void mergeNE(double x, double y) {
if (xmin > x)
@@ -251,6 +261,7 @@ public void zoom(double factorX, double factorY) {
/**
* Checks if this envelope intersects the other.
+ * @param other The other envelope.
* @return True if this envelope intersects the other.
*/
public boolean isIntersecting(Envelope2D other) {
@@ -267,6 +278,7 @@ public boolean isIntersecting(Envelope2D other) {
/**
* Checks if this envelope intersects the other assuming neither one is empty.
+ * @param other The other envelope.
* @return True if this envelope intersects the other. Assumes this and
* other envelopes are not empty.
*/
@@ -282,6 +294,10 @@ public boolean isIntersectingNE(Envelope2D other) {
/**
* Checks if this envelope intersects the other.
+ * @param xmin_
+ * @param ymin_
+ * @param xmax_
+ * @param ymax_
* @return True if this envelope intersects the other.
*/
public boolean isIntersecting(double xmin_, double ymin_, double xmax_, double ymax_) {
@@ -300,13 +316,15 @@ public boolean isIntersecting(double xmin_, double ymin_, double xmax_, double y
/**
* Intersects this envelope with the other and stores result in this
* envelope.
- *
+ * @param other The other envelope.
* @return True if this envelope intersects the other, otherwise sets this
* 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;
@@ -363,6 +381,7 @@ public Point2D queryCorner(int index) {
/**
* Queries corners into a given array. The array length must be at least
* 4. Starts from the lower left corner and goes clockwise.
+ * @param corners The array of four points.
*/
public void queryCorners(Point2D[] corners) {
if ((corners == null) || (corners.length < 4))
@@ -392,6 +411,7 @@ public void queryCorners(Point2D[] corners) {
* Queries corners into a given array in reversed order. The array length
* must be at least 4. Starts from the lower left corner and goes
* counterclockwise.
+ * @param corners The array of four points.
*/
public void queryCornersReversed(Point2D[] corners) {
if (corners == null || ((corners != null) && (corners.length < 4)))
@@ -493,6 +513,8 @@ public double getHeight() {
/**
* Moves the Envelope by given distance.
+ * @param dx
+ * @param dy
*/
public void move(double dx, double dy) {
if (isEmpty())
@@ -551,6 +573,7 @@ public void queryUpperRight(Point2D pt) {
/**
* Returns True if this envelope is valid (empty, or has xmin less or equal
* to xmax, or ymin less or equal to ymax).
+ * @return True if the envelope is valid.
*/
public boolean isValid() {
return isEmpty() || (xmin <= xmax && ymin <= ymax);
@@ -614,6 +637,8 @@ public boolean contains(double x, double y) {
/**
* Returns True if the envelope contains the other envelope (boundary
* inclusive).
+ * @param other The other envelope.
+ * @return True if this contains the other.
*/
public boolean contains(Envelope2D other) {// Note: Will return False, if
// either envelope is empty.
@@ -623,7 +648,10 @@ public boolean contains(Envelope2D other) {// Note: Will return False, if
/**
* Returns True if the envelope contains the point (boundary exclusive).
- */
+ * @param x
+ * @param y
+ * @return True if this contains the point.
+ * */
public boolean containsExclusive(double x, double y) {
// Note: This will return False, if envelope is empty, thus no need to
// call is_empty().
@@ -640,6 +668,8 @@ public boolean containsExclusive(Point2D pt) {
/**
* Returns True if the envelope contains the other envelope (boundary
* exclusive).
+ * @param other The other envelope
+ * @return True if this contains the other, boundary exclusive.
*/
boolean containsExclusive(Envelope2D other) {
// Note: This will return False, if either envelope is empty, thus no
@@ -669,23 +699,14 @@ public boolean equals(Object _other) {
@Override
public int hashCode() {
-
- long bits = Double.doubleToLongBits(xmin);
- int hc = (int) (bits ^ (bits >>> 32));
-
- int hash = NumberUtils.hash(hc);
-
- bits = Double.doubleToLongBits(xmax);
- hc = (int) (bits ^ (bits >>> 32));
- hash = NumberUtils.hash(hash, hc);
-
- bits = Double.doubleToLongBits(ymin);
- hc = (int) (bits ^ (bits >>> 32));
- hash = NumberUtils.hash(hash, hc);
-
- bits = Double.doubleToLongBits(ymax);
- hc = (int) (bits ^ (bits >>> 32));
- hash = NumberUtils.hash(hash, hc);
+ 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;
}
@@ -1068,8 +1089,10 @@ public boolean isPointOnBoundary(Point2D pt, double tolerance) {
/**
* Calculates minimum distance from this envelope to the other.
* Returns 0 for empty envelopes.
+ * @param other The other envelope.
+ * @return Returns the distance
*/
- public double distance(/* const */Envelope2D other)
+ public double distance(Envelope2D other)
{
return Math.sqrt(sqrDistance(other));
}
@@ -1077,6 +1100,8 @@ public double distance(/* const */Envelope2D other)
/**
* Calculates minimum distance from this envelope to the point.
* Returns 0 for empty envelopes.
+ * @param pt2D The other point.
+ * @return Returns the distance
*/
public double distance(Point2D pt2D)
{
@@ -1086,6 +1111,8 @@ public double distance(Point2D pt2D)
/**
* Calculates minimum squared distance from this envelope to the other.
* Returns 0 for empty envelopes.
+ * @param other The other envelope.
+ * @return Returns the squared distance
*/
public double sqrDistance(Envelope2D other)
{
@@ -1115,6 +1142,11 @@ public double sqrDistance(Envelope2D other)
/**
* Calculates minimum squared distance from this envelope to the other.
* Returns 0 for empty envelopes.
+ * @param xmin_
+ * @param ymin_
+ * @param xmax_
+ * @param ymax_
+ * @return Returns the squared distance.
*/
public double sqrDistance(double xmin_, double ymin_, double xmax_, double ymax_)
{
@@ -1171,6 +1203,8 @@ public double sqrMaxDistance(Envelope2D other) {
/**
* Calculates minimum squared distance from this envelope to the point.
* Returns 0 for empty envelopes.
+ * @param pt2D The point.
+ * @return Returns the squared distance
*/
public double sqrDistance(Point2D pt2D)
{
diff --git a/src/main/java/com/esri/core/geometry/Envelope3D.java b/src/main/java/com/esri/core/geometry/Envelope3D.java
index 3f64b053..6fa8b522 100644
--- a/src/main/java/com/esri/core/geometry/Envelope3D.java
+++ b/src/main/java/com/esri/core/geometry/Envelope3D.java
@@ -320,6 +320,22 @@ public boolean equals(Object _other) {
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()) {
diff --git a/src/main/java/com/esri/core/geometry/Geometry.java b/src/main/java/com/esri/core/geometry/Geometry.java
index 68e93671..d108d328 100644
--- a/src/main/java/com/esri/core/geometry/Geometry.java
+++ b/src/main/java/com/esri/core/geometry/Geometry.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,11 +25,11 @@
package com.esri.core.geometry;
-import com.esri.core.geometry.VertexDescription.Semantics;
-
import java.io.ObjectStreamException;
import java.io.Serializable;
+import static com.esri.core.geometry.SizeOf.sizeOfDoubleArray;
+
/**
* Common properties and methods shared by all geometric objects. Geometries are
* objects that define a spatial location and and associated geometric shape.
@@ -151,7 +151,24 @@ static public Geometry.Type intToType(int geometryType)
public abstract int getDimension();
/**
- * Returns the VertexDescription of this geomtry.
+ * Returns an estimate of this object size in bytes.
+ *
+ * This estimate doesn't include the size of the {@link VertexDescription} object
+ * because instances of {@link VertexDescription} are shared among
+ * geometry objects.
+ *
+ * @return Returns an estimate of this object size in bytes.
+ */
+ public abstract long estimateMemorySize();
+
+ protected static long estimateMemorySize(double[] attributes)
+ {
+ return attributes != null ? sizeOfDoubleArray(attributes.length) : 0;
+ }
+
+ /**
+ * Returns the VertexDescription of this geometry.
+ * @return VertexDescription
*/
public VertexDescription getDescription() {
return m_description;
@@ -160,6 +177,7 @@ public VertexDescription getDescription() {
/**
* Assigns the new VertexDescription by adding or dropping attributes. The
* Geometry will have the src description as a result.
+ * @param src VertexDescription to assign.
*/
public void assignVertexDescription(VertexDescription src) {
_touch();
@@ -175,6 +193,7 @@ public void assignVertexDescription(VertexDescription src) {
* Merges the new VertexDescription by adding missing attributes from the
* src. The Geometry will have a union of the current and the src
* descriptions.
+ * @param src VertexDescription to merge.
*/
public void mergeVertexDescription(VertexDescription src) {
_touch();
@@ -191,6 +210,8 @@ public void mergeVertexDescription(VertexDescription src) {
/**
* A shortcut for getDescription().hasAttribute()
+ * @param semantics The VertexDescription.Semantics to check.
+ * @return Return true if the attribute is present.
*/
public boolean hasAttribute(int semantics) {
return getDescription().hasAttribute(semantics);
@@ -199,7 +220,7 @@ public boolean hasAttribute(int semantics) {
/**
* Adds a new attribute to the Geometry.
*
- * @param semantics
+ * @param semantics The VertexDescription.Semantics to add.
*/
public void addAttribute(int semantics) {
_touch();
@@ -215,6 +236,7 @@ public void addAttribute(int semantics) {
* equivalent to setting the attribute to the default value for each vertex,
* However, it is faster and the result Geometry has smaller memory
* footprint and smaller size when persisted.
+ * @param semantics The VertexDescription.Semantics to drop.
*/
public void dropAttribute(int semantics) {
_touch();
@@ -234,7 +256,10 @@ public void dropAllAttributes() {
}
/**
- * Returns the min and max attribute values at the ordinate of the Geometry
+ * Returns the min and max attribute values at the ordinate of the Geometry.
+ * @param semantics The semantics of the interval.
+ * @param ordinate The ordinate of the interval.
+ * @return The interval.
*/
public abstract Envelope1D queryInterval(int semantics, int ordinate);
@@ -246,19 +271,17 @@ public void dropAllAttributes() {
*/
public abstract void queryEnvelope(Envelope env);
- // {
- // Envelope2D e2d = new Envelope2D();
- // queryEnvelope2D(e2d);
- // env.setEnvelope2D(e2d);
- // }
-
/**
* Returns tight bbox of the Geometry in X, Y plane.
+ * @param env
+ * The envelope to return the result in.
*/
public abstract void queryEnvelope2D(Envelope2D env);
/**
* Returns tight bbox of the Geometry in 3D.
+ * @param env
+ * The envelope to return the result in.
*/
abstract void queryEnvelope3D(Envelope3D env);
@@ -266,6 +289,8 @@ public void dropAllAttributes() {
* Returns the conservative bbox of the Geometry in X, Y plane. This is a
* faster method than QueryEnvelope2D. However, the bbox could be larger
* than the tight box.
+ * @param env
+ * The envelope to return the result in.
*/
public void queryLooseEnvelope2D(Envelope2D env) {
queryEnvelope2D(env);
@@ -275,6 +300,8 @@ public void queryLooseEnvelope2D(Envelope2D env) {
* Returns tight conservative box of the Geometry in 3D. This is a faster
* method than the QueryEnvelope3D. However, the box could be larger than
* the tight box.
+ * @param env
+ * The envelope to return the result in.
*/
void queryLooseEnvelope3D(Envelope3D env) {
queryEnvelope3D(env);
@@ -312,13 +339,14 @@ void queryLooseEnvelope3D(Envelope3D env) {
/**
* Creates an instance of an empty geometry of the same type.
+ * @return The new instance.
*/
public abstract Geometry createInstance();
/**
* Copies this geometry to another geometry of the same type. The result
* geometry is an exact copy.
- *
+ * @param dst The geometry instance to copy to.
* @exception GeometryException
* invalid_argument if the geometry is of different type.
*/
@@ -428,7 +456,7 @@ public static int getDimensionFromType(int type) {
* @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.
+ * @return TRUE if the geometry is a point (a Point or a Multipoint).
*/
public static boolean isPoint(int type) {
return (type & 0x20) != 0;
@@ -509,20 +537,22 @@ public Geometry copy() {
return geom;
}
- /**
- * Returns boundary of this geometry.
- *
- * Polygon and Envelope boundary is a Polyline. For Polyline and Line, the
- * boundary is a Multi_point consisting of path endpoints. For Multi_point
- * and Point NULL is returned.
- */
- public abstract Geometry getBoundary();
-
+ /**
+ * Returns boundary of this geometry.
+ *
+ * Polygon and Envelope boundary is a Polyline. For Polyline and Line, the
+ * boundary is a Multi_point consisting of path end points. For Multi_point and
+ * Point null is returned.
+ * @return The boundary geometry.
+ */
+ public abstract Geometry getBoundary();
+
/**
* Replaces NaNs in the attribute with the given value.
* If the geometry is not empty, it adds the attribute if geometry does not have it yet, and replaces the values.
* If the geometry is empty, it adds the attribute and does not set any values.
- *
+ * @param semantics The semantics for which to replace the NaNs.
+ * @param value The value to replace NaNs with.
*/
public abstract void replaceNaNs(int semantics, double value);
@@ -613,30 +643,31 @@ public String toString() {
}
}
- /**
- *Returns count of geometry vertices:
- *1 for Point, 4 for Envelope, get_point_count for MultiVertexGeometry types,
- *2 for segment types
- *Returns 0 if geometry is empty.
- */
- public static int vertex_count(Geometry geom) {
- Geometry.Type gt = geom.getType();
- if (Geometry.isMultiVertex(gt.value()))
- return ((MultiVertexGeometry)geom).getPointCount();
+ /**
+ * Returns count of geometry vertices: 1 for Point, 4 for Envelope,
+ * get_point_count for MultiVertexGeometry types, 2 for segment types Returns 0
+ * if geometry is empty.
+ * @param geom The geometry to get the vertex count for.
+ * @return The vertex count.
+ */
+ public static int vertex_count(Geometry geom) {
+ Geometry.Type gt = geom.getType();
+ 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");
- }
-
}
diff --git a/src/main/java/com/esri/core/geometry/GeometryAccelerators.java b/src/main/java/com/esri/core/geometry/GeometryAccelerators.java
index 2ccc84cc..90d699d0 100644
--- a/src/main/java/com/esri/core/geometry/GeometryAccelerators.java
+++ b/src/main/java/com/esri/core/geometry/GeometryAccelerators.java
@@ -23,8 +23,6 @@
*/
package com.esri.core.geometry;
-import java.util.ArrayList;
-
class GeometryAccelerators {
private RasterizedGeometry2D m_rasterizedGeometry;
@@ -84,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/GeometryEngine.java b/src/main/java/com/esri/core/geometry/GeometryEngine.java
index 6f729cea..2ba61cf4 100644
--- a/src/main/java/com/esri/core/geometry/GeometryEngine.java
+++ b/src/main/java/com/esri/core/geometry/GeometryEngine.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.
@@ -44,6 +44,7 @@ public class GeometryEngine {
/**
+ * @deprecated Use jsonToGeometry(String)
* Imports the MapGeometry from its JSON representation. M and Z values are
* not imported from JSON representation.
*
@@ -55,6 +56,7 @@ public class GeometryEngine {
* @return The MapGeometry instance containing the imported geometry and its
* spatial reference.
*/
+ @Deprecated
public static MapGeometry jsonToGeometry(JsonParser json) {
MapGeometry geom = OperatorImportFromJson.local().execute(Geometry.Type.Unknown, new JsonParserReader(json));
return geom;
@@ -88,8 +90,6 @@ public static MapGeometry jsonToGeometry(JsonReader json) {
* reference).
* @return The MapGeometry instance containing the imported geometry and its
* spatial reference.
- * @throws IOException
- * @throws JsonParseException
*/
public static MapGeometry jsonToGeometry(String json) {
MapGeometry geom = OperatorImportFromJson.local().execute(Geometry.Type.Unknown, json);
@@ -97,11 +97,11 @@ public static MapGeometry jsonToGeometry(String json) {
}
/**
- * Exports the specified geometry instance to it's JSON representation.
+ * Exports the specified geometry instance to its JSON representation.
*
* See OperatorExportToJson.
*
- * @see GeometryEngine#geometryToJson(SpatialReference spatialiReference,
+ * @see GeometryEngine#geometryToJson(SpatialReference spatialReference,
* Geometry geometry)
* @param wkid
* The spatial reference Well Known ID to be used for the JSON
@@ -116,7 +116,7 @@ public static String geometryToJson(int wkid, Geometry geometry) {
}
/**
- * Exports the specified geometry instance to it's JSON representation. M
+ * Exports the specified geometry instance to its JSON representation. M
* and Z values are not imported from JSON representation.
*
* See OperatorExportToJson.
@@ -153,8 +153,6 @@ public static String geometryToGeoJson(Geometry geometry) {
* reference).
* @return The MapGeometry instance containing the imported geometry and its
* spatial reference.
- * @throws IOException
- * @throws JsonParseException
*/
public static MapGeometry geoJsonToGeometry(String json, int importFlags, Geometry.Type type) {
MapGeometry geom = OperatorImportFromGeoJson.local().execute(importFlags, type, json, null);
@@ -181,7 +179,7 @@ public static String geometryToGeoJson(int wkid, Geometry geometry) {
}
/**
- * Exports the specified geometry instance to it's JSON representation.
+ * Exports the specified geometry instance to its JSON representation.
*
* See OperatorImportFromGeoJson.
*
@@ -254,7 +252,7 @@ public static byte[] geometryToEsriShape(Geometry geometry) {
* @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 IllegalArgument exception if an error is found while parsing the WKT string.
+ * @throws IllegalArgumentException if an error is found while parsing the WKT string.
*/
public static Geometry geometryFromWkt(String wkt, int importFlags,
Geometry.Type geometryType) {
diff --git a/src/main/java/com/esri/core/geometry/JsonParserReader.java b/src/main/java/com/esri/core/geometry/JsonParserReader.java
index 90427c63..5313c0ab 100644
--- a/src/main/java/com/esri/core/geometry/JsonParserReader.java
+++ b/src/main/java/com/esri/core/geometry/JsonParserReader.java
@@ -27,9 +27,10 @@
import com.fasterxml.jackson.core.*;
/**
- * A throw in JsonReader built around the Jackson JsonParser.
- *
+ * @deprecated Intended for internal use by geometry-api-java only.
+ * A throw-in JsonReader built around Jackson.
*/
+@Deprecated
public class JsonParserReader implements JsonReader {
private JsonParser m_jsonParser;
@@ -46,7 +47,7 @@ public static JsonReader createFromString(String str) {
try {
JsonFactory factory = new JsonFactory();
JsonParser jsonParser = factory.createParser(str);
-
+
jsonParser.nextToken();
return new JsonParserReader(jsonParser);
}
@@ -168,4 +169,3 @@ else if (t == Token.VALUE_FALSE)
throw new JsonGeometryException("Not a boolean");
}
}
-
diff --git a/src/main/java/com/esri/core/geometry/JsonReaderCursor.java b/src/main/java/com/esri/core/geometry/JsonReaderCursor.java
index 94f72a30..8e0f16de 100644
--- a/src/main/java/com/esri/core/geometry/JsonReaderCursor.java
+++ b/src/main/java/com/esri/core/geometry/JsonReaderCursor.java
@@ -19,21 +19,6 @@
380 New York Street
Redlands, California, USA 92373
- email: contracts@esri.com
- */
-/*
- COPYRIGHT 1995-2017 ESRI
-
- TRADE SECRETS: ESRI PROPRIETARY AND CONFIDENTIAL
- Unpublished material - all rights reserved under the
- Copyright Laws of the United States.
-
- For additional information, contact:
- Environmental Systems Research Institute, Inc.
- Attn: Contracts Dept
- 380 New York Street
- Redlands, California, USA 92373
-
email: contracts@esri.com
*/
diff --git a/src/main/java/com/esri/core/geometry/Line.java b/src/main/java/com/esri/core/geometry/Line.java
index 4eccd513..ce7b7b23 100644
--- a/src/main/java/com/esri/core/geometry/Line.java
+++ b/src/main/java/com/esri/core/geometry/Line.java
@@ -29,6 +29,8 @@
import java.io.Serializable;
+import static com.esri.core.geometry.SizeOf.SIZE_OF_LINE;
+
/**
* A straight line between a pair of points.
*
@@ -40,6 +42,12 @@ public Geometry.Type getType() {
return Type.Line;
}
+ @Override
+ public long estimateMemorySize()
+ {
+ return SIZE_OF_LINE + estimateMemorySize(m_attributes);
+ }
+
@Override
public double calculateLength2D() {
double dx = m_xStart - m_xEnd;
@@ -540,6 +548,11 @@ public boolean equals(Object other) {
return _equalsImpl((Segment)other);
}
+ @Override
+ public int hashCode() {
+ return super.hashCode();
+ }
+
boolean equals(Line other) {
if (other == this)
return true;
diff --git a/src/main/java/com/esri/core/geometry/MapGeometry.java b/src/main/java/com/esri/core/geometry/MapGeometry.java
index d7161d52..dbd90646 100644
--- a/src/main/java/com/esri/core/geometry/MapGeometry.java
+++ b/src/main/java/com/esri/core/geometry/MapGeometry.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,6 +25,8 @@
package com.esri.core.geometry;
+import static com.esri.core.geometry.SizeOf.SIZE_OF_MAPGEOMETRY;
+
import java.io.Serializable;
/**
@@ -132,6 +134,22 @@ public boolean equals(Object other) {
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();
diff --git a/src/main/java/com/esri/core/geometry/MgrsConversionMode.java b/src/main/java/com/esri/core/geometry/MgrsConversionMode.java
deleted file mode 100644
index b92ef646..00000000
--- a/src/main/java/com/esri/core/geometry/MgrsConversionMode.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- Copyright 1995-2015 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;
-
-/**
- * The modes for converting between military grid reference system (MGRS)
- * 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
-}
diff --git a/src/main/java/com/esri/core/geometry/MultiPathImpl.java b/src/main/java/com/esri/core/geometry/MultiPathImpl.java
index dce85615..d70e5c5d 100644
--- a/src/main/java/com/esri/core/geometry/MultiPathImpl.java
+++ b/src/main/java/com/esri/core/geometry/MultiPathImpl.java
@@ -25,10 +25,9 @@
package com.esri.core.geometry;
-import com.esri.core.geometry.MultiVertexGeometryImpl.DirtyFlags;
+import static com.esri.core.geometry.SizeOf.SIZE_OF_MULTI_PATH_IMPL;
final class MultiPathImpl extends MultiVertexGeometryImpl {
-
protected boolean m_bPolygon;
protected Point m_moveToPoint;
protected double m_cachedLength2D;
@@ -60,6 +59,32 @@ final class MultiPathImpl extends MultiVertexGeometryImpl {
// Bezier, XXX, Arc,
// XXX;
+ @Override
+ public long estimateMemorySize()
+ {
+ long size = SIZE_OF_MULTI_PATH_IMPL +
+ + (m_envelope != null ? m_envelope.estimateMemorySize() : 0)
+ + (m_moveToPoint != null ? m_moveToPoint.estimateMemorySize() : 0)
+ + (m_cachedRingAreas2D != null ? m_cachedRingAreas2D.estimateMemorySize() : 0)
+ + (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);
+
+ if (m_vertexAttributes != null) {
+ for (int i = 0; i < m_vertexAttributes.length; i++) {
+ size += m_vertexAttributes[i].estimateMemorySize();
+ }
+ }
+
+ if (m_accelerators != null) {
+ size += m_accelerators.estimateMemorySize();
+ }
+
+ return size;
+ }
+
public boolean hasNonLinearSegments() {
return m_curveParamwritePoint > 0;
}
@@ -2108,27 +2133,34 @@ int getOGCPolygonCount() {
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);
- }
+ _updateOGCFlagsHelper();
_setDirtyFlag(DirtyFlags.DirtyOGCFlags, false);
}
}
+
+ private void _updateOGCFlagsHelper() {
+ int pathCount = getPathCount();
+ if (pathCount > 0 && (m_pathFlags == null || m_pathFlags.size() < pathCount))
+ m_pathFlags = (AttributeStreamOfInt8) AttributeStreamBase.createByteStream(pathCount + 1);
+
+ // firstSign is the sign of first ring.
+ // a first ring with non zero area defines the
+ // value. First zero area rings are written out as enumOGCStartPolygon.
+ int firstSign = 0;
+ for (int ipath = 0; ipath < pathCount; ipath++) {
+ double area = m_cachedRingAreas2D.read(ipath);
+ if (firstSign == 0) {
+ // if the first ring is inverted we assume that the
+ // whole polygon is inverted.
+ firstSign = MathUtils.sign(area);
+ }
+
+ if (area * firstSign > 0.0 || firstSign == 0)
+ m_pathFlags.setBits(ipath, (byte) PathFlags.enumOGCStartPolygon);
+ else
+ m_pathFlags.clearBits(ipath, (byte) PathFlags.enumOGCStartPolygon);
+ }
+ }
public int getPathIndexFromPointIndex(int pointIndex) {
int positionHint = m_currentPathIndex;// in case of multithreading
diff --git a/src/main/java/com/esri/core/geometry/MultiPoint.java b/src/main/java/com/esri/core/geometry/MultiPoint.java
index 8a3f6f6a..4beca5b5 100644
--- a/src/main/java/com/esri/core/geometry/MultiPoint.java
+++ b/src/main/java/com/esri/core/geometry/MultiPoint.java
@@ -26,6 +26,8 @@
import java.io.Serializable;
+import static com.esri.core.geometry.SizeOf.SIZE_OF_MULTI_POINT;
+
/**
* A Multipoint is a collection of points. A multipoint is a one-dimensional
* geometry object. Multipoints can be used to store a collection of point-based
@@ -258,6 +260,12 @@ public int getDimension() {
return 0;
}
+ @Override
+ public long estimateMemorySize()
+ {
+ return SIZE_OF_MULTI_POINT + m_impl.estimateMemorySize();
+ }
+
@Override
public Geometry.Type getType() {
return Type.MultiPoint;
diff --git a/src/main/java/com/esri/core/geometry/MultiPointImpl.java b/src/main/java/com/esri/core/geometry/MultiPointImpl.java
index b3d0a4b7..bb16671f 100644
--- a/src/main/java/com/esri/core/geometry/MultiPointImpl.java
+++ b/src/main/java/com/esri/core/geometry/MultiPointImpl.java
@@ -26,11 +26,12 @@
import com.esri.core.geometry.VertexDescription.Semantics;
+import static com.esri.core.geometry.SizeOf.SIZE_OF_MULTI_POINT_IMPL;
+
/**
* The MultiPoint is a collection of points.
*/
final class MultiPointImpl extends MultiVertexGeometryImpl {
-
public MultiPointImpl() {
super();
m_description = VertexDescriptionDesignerImpl.getDefaultDescriptor2D();
@@ -247,6 +248,19 @@ 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) {
+ for (int i = 0; i < m_vertexAttributes.length; i++) {
+ size += m_vertexAttributes[i].estimateMemorySize();
+ }
+ }
+ return size;
+ }
+
@Override
public Geometry.Type getType() {
return Type.MultiPoint;
diff --git a/src/main/java/com/esri/core/geometry/MultiVertexGeometryImpl.java b/src/main/java/com/esri/core/geometry/MultiVertexGeometryImpl.java
index 6e2694c7..e045aa2a 100644
--- a/src/main/java/com/esri/core/geometry/MultiVertexGeometryImpl.java
+++ b/src/main/java/com/esri/core/geometry/MultiVertexGeometryImpl.java
@@ -63,52 +63,34 @@ public interface GeometryXSimple {
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; // ! 0) {
builder.append(buffer, 0, read);
}
- stream.close();
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;
@@ -275,20 +285,28 @@ public static Geometry loadGeometryFromWKTFileDbg(String file_name) {
}
String s = null;
+ Reader reader = null;
try {
FileInputStream stream = new FileInputStream(file_name);
- Reader reader = new BufferedReader(new InputStreamReader(stream));
+ 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) {
}
+ 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/OperatorImportFromGeoJson.java b/src/main/java/com/esri/core/geometry/OperatorImportFromGeoJson.java
index 87de2d4a..2a25215d 100644
--- a/src/main/java/com/esri/core/geometry/OperatorImportFromGeoJson.java
+++ b/src/main/java/com/esri/core/geometry/OperatorImportFromGeoJson.java
@@ -34,7 +34,7 @@ public Type getType() {
* Performs the ImportFromGeoJson operation.
*
* @param type Use the {@link Geometry.Type} enum.
- * @param jsonObject The JSONObject holding the geometry and spatial reference.
+ * @param jsonReader The JSONReader.
* @return Returns the imported MapGeometry.
* @throws JsonGeometryException
*/
@@ -49,7 +49,6 @@ public Type getType() {
* @param type Use the {@link Geometry.Type} enum.
* @param geoJsonString The string holding the Geometry in geoJson format.
* @return Returns the imported MapGeometry.
- * @throws JSONException
*
*/
public abstract MapGeometry execute(int import_flags, Geometry.Type type, String geoJsonString, ProgressTracker progress_tracker);
@@ -61,7 +60,6 @@ public Type getType() {
* @param import_flags Use the {@link GeoJsonImportFlags} interface.
* @param geoJsonString The string holding the Geometry in geoJson format.
* @return Returns the imported MapOGCStructure.
- * @throws JSONException
*/
public abstract MapOGCStructure executeOGC(int import_flags, String geoJsonString, ProgressTracker progress_tracker);
diff --git a/src/main/java/com/esri/core/geometry/OperatorIntersection.java b/src/main/java/com/esri/core/geometry/OperatorIntersection.java
index ee3b4833..5afc6e37 100644
--- a/src/main/java/com/esri/core/geometry/OperatorIntersection.java
+++ b/src/main/java/com/esri/core/geometry/OperatorIntersection.java
@@ -53,12 +53,12 @@ public abstract GeometryCursor execute(GeometryCursor inputGeometries,
*@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).
+ *@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
+ *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.
+ *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.
@@ -81,7 +81,7 @@ public abstract GeometryCursor execute(GeometryCursor input_geometries,
*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());
+ *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.
diff --git a/src/main/java/com/esri/core/geometry/OperatorOffset.java b/src/main/java/com/esri/core/geometry/OperatorOffset.java
index 7b4f3673..bdcf5005 100644
--- a/src/main/java/com/esri/core/geometry/OperatorOffset.java
+++ b/src/main/java/com/esri/core/geometry/OperatorOffset.java
@@ -43,7 +43,7 @@ public enum JoinType {
*
* 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 > 0, then the offset geometry is
+ * one sided result. If offsetDistance greater than 0, then the offset geometry is
* constructed to the right of the oriented input geometry, otherwise it is
* constructed to the left. For a simple polygon, the orientation of outer
* rings is clockwise and for inner rings it is counter clockwise. So the
@@ -82,7 +82,7 @@ public abstract GeometryCursor execute(GeometryCursor inputGeometries,
*
* 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 > 0, then the offset geometry is
+ * one sided result. If offsetDistance greater than 0, then the offset geometry is
* constructed to the right of the oriented input geometry, otherwise it is
* constructed to the left. For a simple polygon, the orientation of outer
* rings is clockwise and for inner rings it is counter clockwise. So the
diff --git a/src/main/java/com/esri/core/geometry/OperatorSimplifyLocalHelper.java b/src/main/java/com/esri/core/geometry/OperatorSimplifyLocalHelper.java
index b0bd4dd8..2513693e 100644
--- a/src/main/java/com/esri/core/geometry/OperatorSimplifyLocalHelper.java
+++ b/src/main/java/com/esri/core/geometry/OperatorSimplifyLocalHelper.java
@@ -476,10 +476,12 @@ boolean checkSelfIntersectionsPolylinePlanar_() {
|| (xyindex == path_last);
if (m_bOGCRestrictions)
vi_prev.boundary = !is_closed_path && vi_prev.end_point;
- else
+ 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;
@@ -506,11 +508,11 @@ boolean checkSelfIntersectionsPolylinePlanar_() {
boolean end_point = (xyindex == path_start)
|| (xyindex == path_last);
if (m_bOGCRestrictions)
- boundary = !is_closed_path && vi_prev.end_point;
+ boundary = !is_closed_path && end_point;
else
// for regular planar simplify, only the end points are allowed
// to coincide
- boundary = vi_prev.end_point;
+ boundary = end_point;
vi.x = pt.x;
vi.y = pt.y;
@@ -522,22 +524,12 @@ boolean checkSelfIntersectionsPolylinePlanar_() {
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))// check
- // that
- // this
- // is
- // not
- // the
- // endpoints
- // of
- // a
- // closed
- // path
- {
+ || (!vi.end_point && !vi_prev.end_point)) {
// one of coincident vertices is not on the boundary
- // this is either Non_simple_result::cross_over or
- // Non_simple_result::ogc_self_tangency.
+ // this is either NonSimpleResult.CrossOver or
+ // NonSimpleResult.OGCPolylineSelfTangency.
// too expensive to distinguish between the two.
m_nonSimpleResult = new NonSimpleResult(
NonSimpleResult.Reason.OGCPolylineSelfTangency,
@@ -546,12 +538,9 @@ boolean checkSelfIntersectionsPolylinePlanar_() {
}
}
} else {
- if (!vi.end_point || !vi_prev.end_point) {// one of
- // coincident
- // vertices is
- // not an
- // endpoint
- m_nonSimpleResult = new NonSimpleResult(
+ 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
diff --git a/src/main/java/com/esri/core/geometry/PlaneSweepCrackerHelper.java b/src/main/java/com/esri/core/geometry/PlaneSweepCrackerHelper.java
index 4bdf00cc..c84b4724 100644
--- a/src/main/java/com/esri/core/geometry/PlaneSweepCrackerHelper.java
+++ b/src/main/java/com/esri/core/geometry/PlaneSweepCrackerHelper.java
@@ -1212,9 +1212,14 @@ void splitEdge_(int edge1, int edge2, int intersectionCluster,
// Adjust the vertex coordinates and split the segments in the the edit
// shape.
applyIntersectorToEditShape_(edgeOrigins1, intersector, 0);
- if (edge2 != -1)
+ if (edgeOrigins2 != -1)
applyIntersectorToEditShape_(edgeOrigins2, intersector, 1);
-
+ else {
+ assert (intersectionCluster != -1);
+ Point2D pt = intersector.getResultPoint().getXY();
+ updateClusterXY(intersectionCluster, pt);
+ }
+
// Produce clusters, and new edges. The new edges are added to
// m_edges_to_insert_in_sweep_structure.
createEdgesAndClustersFromSplitEdge_(edge1, intersector, 0);
diff --git a/src/main/java/com/esri/core/geometry/Point.java b/src/main/java/com/esri/core/geometry/Point.java
index 2343c5df..cc5b7042 100644
--- a/src/main/java/com/esri/core/geometry/Point.java
+++ b/src/main/java/com/esri/core/geometry/Point.java
@@ -28,6 +28,8 @@
import java.io.Serializable;
+import static com.esri.core.geometry.SizeOf.SIZE_OF_POINT;
+
/**
* A Point is a zero-dimensional object that represents a specific (X,Y)
* location in a two-dimensional XY-Plane. In case of Geographic Coordinate
@@ -37,19 +39,24 @@ 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)
+ 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();
}
/**
@@ -66,6 +73,7 @@ public Point(double x, double y) {
m_description = VertexDescriptionDesignerImpl.getDefaultDescriptor2D();
setXY(x, y);
}
+
public Point(Point2D pt) {
m_description = VertexDescriptionDesignerImpl.getDefaultDescriptor2D();
setXY(pt);
@@ -89,19 +97,14 @@ public Point(double x, double y, double z) {
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]);
+ pt.setCoords(m_x, m_y);
return pt;
}
@@ -109,11 +112,7 @@ public final Point2D getXY() {
* 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]);
+ pt.setCoords(m_x, m_y);
}
/**
@@ -129,17 +128,10 @@ public final void setXY(Point2D pt) {
* 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);
+ pt.x = m_x;
+ pt.y = m_y;
+ pt.z = hasZ() ? m_attributes[0] : VertexDescription.getDefaultValue(VertexDescription.Semantics.Z);
return pt;
}
@@ -152,39 +144,17 @@ public Point3D getXYZ() {
*/
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;
+ 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() {
- if (isEmptyImpl())
- throw new GeometryException(
- "This operation should not be performed on an empty geometry.");
-
- return m_attributes[0];
+ return m_x;
}
/**
@@ -194,18 +164,14 @@ public final double getX() {
* The X coordinate to be set for this point.
*/
public void setX(double x) {
- setAttribute(Semantics.POSITION, 0, x);
+ m_x = 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];
+ return m_y;
}
/**
@@ -215,14 +181,14 @@ public final double getY() {
* The Y coordinate to be set for this point.
*/
public void setY(double y) {
- setAttribute(Semantics.POSITION, 1, y);
+ m_y = y;
}
/**
* Returns the Z coordinate of this point.
*/
public double getZ() {
- return getAttributeAsDbl(Semantics.Z, 0);
+ return hasZ() ? m_attributes[0] : VertexDescription.getDefaultValue(VertexDescription.Semantics.Z);
}
/**
@@ -280,10 +246,18 @@ public void setID(int id) {
* @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.");
-
+ 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();
@@ -291,7 +265,7 @@ public double getAttributeAsDbl(int semantics, int ordinate) {
int attributeIndex = m_description.getAttributeIndex(semantics);
if (attributeIndex >= 0)
return m_attributes[m_description
- ._getPointAttributeOffset(attributeIndex) + ordinate];
+ ._getPointAttributeOffset(attributeIndex) - 2 + ordinate];
else
return VertexDescription.getDefaultValue(semantics);
}
@@ -308,20 +282,7 @@ public double getAttributeAsDbl(int semantics, int ordinate) {
* @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);
+ return (int)getAttributeAsDbl(semantics, ordinate);
}
/**
@@ -338,6 +299,19 @@ public int getAttributeAsInt(int semantics, int ordinate) {
*/
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();
@@ -348,10 +322,7 @@ public void setAttribute(int semantics, int ordinate, double value) {
attributeIndex = m_description.getAttributeIndex(semantics);
}
- if (m_attributes == null)
- _setToDefault();
-
- m_attributes[m_description._getPointAttributeOffset(attributeIndex)
+ m_attributes[m_description._getPointAttributeOffset(attributeIndex) - 2
+ ordinate] = value;
}
@@ -369,65 +340,79 @@ public int getDimension() {
return 0;
}
+ @Override
+ public long estimateMemorySize()
+ {
+ return SIZE_OF_POINT + estimateMemorySize(m_attributes);
+ }
+
@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) {
- 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++)
+ 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)
{
- newAttributes[j] = d;
- j++;
+ 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++;
+ 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;
}
-
- m_attributes = newAttributes;
+ else {
+ m_attributes = null;
+ }
+
m_description = newDescription;
}
/**
- * Sets the Point to a default, non-empty state.
+ * Sets to a default 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();
+ 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
@@ -441,7 +426,7 @@ public void applyTransformation(Transformation2D transform) {
}
@Override
- void applyTransformation(Transformation3D transform) {
+ public void applyTransformation(Transformation3D transform) {
if (isEmptyImpl())
return;
@@ -454,20 +439,27 @@ void applyTransformation(Transformation3D transform) {
public void copyTo(Geometry dst) {
if (dst.getType() != Type.Point)
throw new IllegalArgumentException();
-
- Point pointDst = (Point) dst;
+
+ if (this == dst)
+ return;
+
dst._touch();
- if (m_attributes == null) {
- pointDst.setEmpty();
+ 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;
- pointDst.assignVertexDescription(m_description);
- } else {
- pointDst.assignVertexDescription(m_description);
- pointDst.resizeAttributes(m_description.getTotalComponentCount());
- attributeCopy(m_attributes, pointDst.m_attributes,
- m_description.getTotalComponentCount());
+ 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
@@ -482,30 +474,29 @@ public boolean isEmpty() {
}
final boolean isEmptyImpl() {
- return ((m_attributes == null) || NumberUtils.isNaN(m_attributes[0]) || NumberUtils
- .isNaN(m_attributes[1]));
+ return NumberUtils.isNaN(m_x) || NumberUtils.isNaN(m_y);
}
@Override
public void queryEnvelope(Envelope env) {
- env.setEmpty();
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_attributes[0];
- env.ymin = m_attributes[1];
- env.xmax = m_attributes[0];
- env.ymax = m_attributes[1];
+ env.xmin = m_x;
+ env.ymin = m_y;
+ env.xmax = m_x;
+ env.ymax = m_y;
}
@Override
@@ -515,13 +506,13 @@ void queryEnvelope3D(Envelope3D env) {
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;
+ 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
@@ -538,21 +529,6 @@ public Envelope1D queryInterval(int semantics, int ordinate) {
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.
*
@@ -564,11 +540,8 @@ static void attributeCopy(double[] src, double[] dst, int count) {
public void setXY(double x, double y) {
_touch();
- if (m_attributes == null)
- _setToDefault();
-
- m_attributes[0] = x;
- m_attributes[1] = y;
+ m_x = x;
+ m_y = y;
}
/**
@@ -588,15 +561,21 @@ public boolean equals(Object _other) {
if (m_description != otherPt.m_description)
return false;
- if (isEmptyImpl())
+ 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(); i < n; i++)
- if (m_attributes[i] != otherPt.m_attributes[i])
+ 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;
}
@@ -609,31 +588,34 @@ public boolean equals(Object _other) {
public int hashCode() {
int hashCode = m_description.hashCode();
if (!isEmptyImpl()) {
- for (int i = 0, n = m_description.getTotalComponentCount(); i < n; i++) {
+ 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() {
- return 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++) {
- double v = getAttributeAsDbl(semantics, i);
- if (Double.isNaN(v))
- setAttribute(semantics, i, value);
- }
- }
+ @Override
+ public Geometry getBoundary() {
+ return 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++) {
+ double v = getAttributeAsDbl(semantics, i);
+ if (Double.isNaN(v))
+ setAttribute(semantics, i, value);
+ }
+ }
}
diff --git a/src/main/java/com/esri/core/geometry/Point2D.java b/src/main/java/com/esri/core/geometry/Point2D.java
index 245b8156..95a46c66 100644
--- a/src/main/java/com/esri/core/geometry/Point2D.java
+++ b/src/main/java/com/esri/core/geometry/Point2D.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.
@@ -94,6 +94,12 @@ public boolean equals(Object 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;
@@ -435,7 +441,7 @@ public boolean isNaN() {
}
/**
- * Calculates the orientation of the triangle formed by p->q->r. Returns 1
+ * 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.
*/
@@ -751,11 +757,6 @@ static Point2D calculateCircleCenterFromThreePoints(Point2D from, Point2D mid_po
}
}
- @Override
- public int hashCode() {
- return NumberUtils.hash(NumberUtils.hash(x), y);
- }
-
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 849b00e1..71cbfdba 100644
--- a/src/main/java/com/esri/core/geometry/Point3D.java
+++ b/src/main/java/com/esri/core/geometry/Point3D.java
@@ -132,4 +132,31 @@ 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/Polygon.java b/src/main/java/com/esri/core/geometry/Polygon.java
index cb027357..949a3797 100644
--- a/src/main/java/com/esri/core/geometry/Polygon.java
+++ b/src/main/java/com/esri/core/geometry/Polygon.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.
@@ -27,11 +27,12 @@
import java.io.Serializable;
+import static com.esri.core.geometry.SizeOf.SIZE_OF_POLYGON;
+
/**
* A polygon is a collection of one or many interior or exterior rings.
*/
public class Polygon extends MultiPath implements Serializable {
-
private static final long serialVersionUID = 2L;// TODO:remove as we use
// writeReplace and
// GeometrySerializer
@@ -62,6 +63,11 @@ public Geometry.Type getType() {
return Type.Polygon;
}
+ @Override
+ public long estimateMemorySize() {
+ return SIZE_OF_POLYGON + m_impl.estimateMemorySize();
+ }
+
/**
* Calculates the ring area for this ring.
*
@@ -139,39 +145,41 @@ 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 interior if a ray
- * from this point to infinity crosses odd number of segments of the polygon.
- */
- public final static int enumFillRuleOddEven = 0;
- /**
- * winding fill rule (aka non-zero winding rule). A point is in the polygon interior if a winding number is not zero.
- * To compute a winding number for a point, draw a ray from this point to infinity. If N is the number of times the ray
- * crosses segments directed up and the M is the number of times it 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 polygon. It affects the Simplify operation.
- *Can be use by drawing code to pass around the fill rule of graphic path.
- *This property is not persisted in any format yet.
- *See also Polygon.FillRule.
- */
- public void setFillRule(int rule) {
- m_impl.setFillRule(rule);
- }
-
- /**
- *Fill rule for the polygon that defines the interior of the self intersecting polygon. It affects the Simplify operation.
- *Changing the fill rule on the polygon that has no self intersections has no physical effect.
- *Can be use by drawing code to pass around the fill rule of graphic path.
- *This property is not persisted in any format yet.
- *See also Polygon.FillRule.
- */
- public int getFillRule() {
- return m_impl.getFillRule();
- }
+ public interface FillRule {
+ /**
+ * odd-even fill rule. This is the default value. A point is in the polygon
+ * interior if a ray from this point to infinity crosses odd number of segments
+ * of the polygon.
+ */
+ public final static int enumFillRuleOddEven = 0;
+ /**
+ * winding fill rule (aka non-zero winding rule). A point is in the polygon
+ * interior if a winding number is not zero. To compute a winding number for a
+ * point, draw a ray from this point to infinity. If N is the number of times
+ * the ray crosses segments directed up and the M is the number of times it
+ * 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
+ * polygon. It affects the Simplify operation. Can be use by drawing code to
+ * pass around the fill rule of graphic path. This property is not persisted in
+ * any format yet. See also Polygon.FillRule.
+ */
+ public void setFillRule(int rule) {
+ m_impl.setFillRule(rule);
+ }
+
+ /**
+ * Fill rule for the polygon that defines the interior of the self intersecting
+ * polygon. It affects the Simplify operation. Changing the fill rule on the
+ * polygon that has no self intersections has no physical effect. Can be use by
+ * drawing code to pass around the fill rule of graphic path. This property is
+ * not persisted in any format yet. See also Polygon.FillRule.
+ */
+ public int getFillRule() {
+ return m_impl.getFillRule();
+ }
}
diff --git a/src/main/java/com/esri/core/geometry/Polyline.java b/src/main/java/com/esri/core/geometry/Polyline.java
index 4c83a147..9f45d7ea 100644
--- a/src/main/java/com/esri/core/geometry/Polyline.java
+++ b/src/main/java/com/esri/core/geometry/Polyline.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.
@@ -27,6 +27,8 @@
import java.io.Serializable;
+import static com.esri.core.geometry.SizeOf.SIZE_OF_POLYLINE;
+
/**
* A polyline is a collection of one or many paths.
*
@@ -72,6 +74,11 @@ public Geometry.Type getType() {
return Type.Polyline;
}
+ @Override
+ public long estimateMemorySize() {
+ return SIZE_OF_POLYLINE + m_impl.estimateMemorySize();
+ }
+
/**
* Returns TRUE when this geometry has exactly same type, properties, and
* coordinates as the other geometry.
diff --git a/src/main/java/com/esri/core/geometry/QuadTree.java b/src/main/java/com/esri/core/geometry/QuadTree.java
index 32d81c3c..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,7 +25,11 @@
package com.esri.core.geometry;
-public class QuadTree {
+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
diff --git a/src/main/java/com/esri/core/geometry/QuadTreeImpl.java b/src/main/java/com/esri/core/geometry/QuadTreeImpl.java
index fe48999a..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,9 +23,19 @@
*/
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 {
+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
@@ -771,6 +781,22 @@ 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");
@@ -1248,19 +1274,25 @@ private void set_data_values_(int data_handle, int element, Envelope2D bounding_
private Envelope2D m_data_extent;
private StridedIndexTypeCollection m_quad_tree_nodes;
private StridedIndexTypeCollection m_element_nodes;
- private ArrayList m_data;
+ transient 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;
+ 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_;
@@ -1269,6 +1301,57 @@ static final class Data {
}
}
+ 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
* 1: m_north_west_child
diff --git a/src/main/java/com/esri/core/geometry/RasterizedGeometry2D.java b/src/main/java/com/esri/core/geometry/RasterizedGeometry2D.java
index 46ccd5c6..ff1b8257 100644
--- a/src/main/java/com/esri/core/geometry/RasterizedGeometry2D.java
+++ b/src/main/java/com/esri/core/geometry/RasterizedGeometry2D.java
@@ -136,4 +136,10 @@ static boolean canUseAccelerator(Geometry geom) {
*/
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 ff21c8ec..c7def2d4 100644
--- a/src/main/java/com/esri/core/geometry/RasterizedGeometry2DImpl.java
+++ b/src/main/java/com/esri/core/geometry/RasterizedGeometry2DImpl.java
@@ -24,18 +24,14 @@
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;
@@ -89,6 +85,17 @@ public void drawScan(int[] scans, int scanCount3) {
}
}
}
+
+ /**
+ * 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) {
@@ -138,10 +145,6 @@ void strokeDrawPolyPath(SimpleRasterizer rasterizer,
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();
@@ -150,6 +153,7 @@ void strokeDrawPolyPath(SimpleRasterizer rasterizer,
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;
@@ -167,10 +171,11 @@ void strokeDrawPolyPath(SimpleRasterizer rasterizer,
if (hasFan) {
rasterizer.startAddingEdges();
rasterizer.addSegmentStroke(prev_start.x, prev_start.y,
- prev_end.x, prev_end.y, strokeHalfWidth, false,
+ 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;
@@ -192,19 +197,26 @@ void strokeDrawPolyPath(SimpleRasterizer rasterizer,
rasterizer.startAddingEdges();
hasFan = !rasterizer.addSegmentStroke(prev_start.x,
- prev_start.y, prev_end.x, prev_end.y, strokeHalfWidth,
+ prev_start.y, prev_end.x, prev_end.y, strokeHalfWidth + extraWidth,
true, helper_xy_10_elm);
rasterizer.renderEdges(SimpleRasterizer.EVEN_ODD);
- if (!hasFan)
+ 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,
+ prev_start.y, prev_end.x, prev_end.y, strokeHalfWidth + extraWidth,
false, helper_xy_10_elm);
rasterizer.renderEdges(SimpleRasterizer.EVEN_ODD);
+ extraWidth = 0.0;
}
}
}
@@ -305,12 +317,10 @@ void init(MultiVertexGeometryImpl geom, double 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);
+ fillPoints(m_rasterizer, (MultiPointImpl) geom, m_stroke_half_width);
break;
case Geometry.GeometryType.Polyline:
callback.setColor(m_rasterizer, 2);
@@ -542,7 +552,6 @@ public boolean dbgSaveToBitmap(String fileName) {
// 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;
@@ -559,4 +568,14 @@ public boolean dbgSaveToBitmap(String fileName) {
}
}
+
+ @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 0b73561a..34fdd216 100644
--- a/src/main/java/com/esri/core/geometry/RelationalOperations.java
+++ b/src/main/java/com/esri/core/geometry/RelationalOperations.java
@@ -1609,7 +1609,7 @@ private static boolean polylineDisjointPolyline_(Polyline polyline_a,
PairwiseIntersectorImpl intersector_paths = new PairwiseIntersectorImpl(multi_path_impl_a, multi_path_impl_b, tolerance, true);
if (!intersector_paths.next())
- return false;
+ return true;
return !linearPathIntersectsLinearPath_(polyline_a, polyline_b,
tolerance);
@@ -4142,9 +4142,6 @@ private static boolean linearPathIntersectsMultiPoint_(
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();
@@ -4152,10 +4149,6 @@ private static boolean linearPathIntersectsMultiPoint_(
multipoint_b.queryEnvelope2D(env_b);
env_a.inflate(tolerance, tolerance);
- if (!env_a.contains(env_b)) {
- bContained = false;
- }
-
env_b.inflate(tolerance, tolerance);
envInter.setCoords(env_a);
envInter.intersect(env_b);
@@ -4169,6 +4162,7 @@ private static boolean linearPathIntersectsMultiPoint_(
if (accel != null) {
quadTreeA = accel.getQuadTree();
+ quadTreePathsA = accel.getQuadTreeForPaths();
if (quadTreeA == null) {
qtA = InternalUtils.buildQuadTree(
(MultiPathImpl) multipathA._getImpl(), envInter);
@@ -4187,7 +4181,6 @@ private static boolean linearPathIntersectsMultiPoint_(
qtIterPathsA = quadTreePathsA.getIterator();
Point2D ptB = new Point2D(), closest = new Point2D();
- boolean b_intersects = false;
double toleranceSq = tolerance * tolerance;
for (int i = 0; i < multipoint_b.getPointCount(); i++) {
@@ -5153,9 +5146,9 @@ private static final class OverlapEvent {
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;
+// 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,
@@ -5166,9 +5159,9 @@ static OverlapEvent construct(int ivertex_a, int 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;
+// overlapEvent.m_ipath_b = ipath_b;
+// overlapEvent.m_scalar_b_0 = scalar_b_0;
+// overlapEvent.m_scalar_b_1 = scalar_b_1;
return overlapEvent;
}
}
diff --git a/src/main/java/com/esri/core/geometry/Segment.java b/src/main/java/com/esri/core/geometry/Segment.java
index ca2ea184..b15364a2 100644
--- a/src/main/java/com/esri/core/geometry/Segment.java
+++ b/src/main/java/com/esri/core/geometry/Segment.java
@@ -528,9 +528,6 @@ private void _get(int endPoint, Point outPoint) {
outPoint.assignVertexDescription(m_description);
- if (outPoint.isEmptyImpl())
- outPoint._setToDefault();
-
for (int attributeIndex = 0; attributeIndex < m_description
.getAttributeCount(); attributeIndex++) {
int semantics = m_description._getSemanticsImpl(attributeIndex);
@@ -689,12 +686,26 @@ boolean _equalsImpl(Segment other) {
|| 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])
+ 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).
diff --git a/src/main/java/com/esri/core/geometry/SimpleRasterizer.java b/src/main/java/com/esri/core/geometry/SimpleRasterizer.java
index de817443..8c6d7e46 100644
--- a/src/main/java/com/esri/core/geometry/SimpleRasterizer.java
+++ b/src/main/java/com/esri/core/geometry/SimpleRasterizer.java
@@ -24,11 +24,14 @@
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.
*
@@ -44,15 +47,15 @@ public class SimpleRasterizer {
* Winding fill rule
*/
public final static int WINDING = 1;
-
- public static interface ScanCallback {
+
+ 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.
*/
- public abstract void drawScan(int[] scans, int scanCount3);
+ void drawScan(int[] scans, int scanCount3);
}
public SimpleRasterizer() {
@@ -295,62 +298,96 @@ public final void fillEnvelope(Envelope2D envIn) {
}
}
- 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;
- }
-
+ 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
- private static class Edge {
+ 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_() {
diff --git a/src/main/java/com/esri/core/geometry/Simplificator.java b/src/main/java/com/esri/core/geometry/Simplificator.java
index e0401cfa..a5102528 100644
--- a/src/main/java/com/esri/core/geometry/Simplificator.java
+++ b/src/main/java/com/esri/core/geometry/Simplificator.java
@@ -33,16 +33,16 @@ class Simplificator {
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 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,
@@ -91,9 +91,15 @@ private void _beforeRemoveVertex(int vertex, boolean bChangePathFirst) {
}
}
- static class SimplificatorAngleComparer extends
+ static private class SimplificatorAngleComparer extends
AttributeStreamOfInt32.IntComparator {
- Simplificator m_parent;
+ 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;
@@ -101,19 +107,35 @@ public SimplificatorAngleComparer(Simplificator parent) {
@Override
public int compare(int v1, int v2) {
- return m_parent._compareAngles(v1, 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;
- 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);
@@ -129,25 +151,17 @@ private boolean _processBunch() {
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
@@ -165,7 +179,6 @@ private boolean _processBunch() {
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
@@ -189,8 +202,6 @@ private boolean _processBunch() {
// 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);
@@ -199,11 +210,6 @@ private boolean _processBunch() {
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
@@ -254,7 +260,6 @@ private boolean _processCrossOvers(Point2D ptCenter) {
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))
@@ -263,9 +268,6 @@ private boolean _processCrossOvers(Point2D ptCenter) {
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)
@@ -331,9 +333,6 @@ else if (_removeSpike(vertexC2))
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)
@@ -355,9 +354,11 @@ else if (_removeSpike(vertexC2))
return bFound;
}
- static class SimplificatorVertexComparer extends
+ static private class SimplificatorVertexComparer extends
AttributeStreamOfInt32.IntComparator {
- Simplificator m_parent;
+ private Simplificator m_parent;
+ private Point2D pt1 = new Point2D();
+ private Point2D pt2 = new Point2D();
SimplificatorVertexComparer(Simplificator parent) {
m_parent = parent;
@@ -365,9 +366,21 @@ static class SimplificatorVertexComparer extends
@Override
public int compare(int v1, int v2) {
- return m_parent._compareVerticesSimple(v1, 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() {
@@ -381,8 +394,6 @@ private boolean _simplify() {
assert (m_shape.getFillRule(m_geometry) == Polygon.FillRule.enumFillRuleOddEven);
}
boolean bChanged = false;
- boolean bNeedWindingRepeat = true;
- boolean bWinding = false;
m_userIndexSortedIndexToVertex = -1;
m_userIndexSortedAngleIndexToVertex = -1;
@@ -406,8 +417,6 @@ private boolean _simplify() {
// 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.
@@ -424,11 +433,6 @@ private boolean _simplify() {
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,
@@ -452,120 +456,100 @@ private boolean _simplify() {
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;
+ // Simplify polygon
+ int iRepeatNum = 0;
+ boolean bNeedRepeat = 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);
- }
+ // 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 {
+
+ vlistindex = m_nextVertexToProcess;
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;
+ } else {
+ m_firstCoincidentVertex = vlistindex;
+ m_shape.getXY(m_sortedVertices.getData(vlistindex),
+ ptFirst);
+ coincidentCount = 0;
}
- if (iRepeatNum++ > 10) {
- throw GeometryException.GeometryInternalError();
- }
+ if (vlistindex != -1)//vlistindex can be set to -1 after ProcessBunch call above
+ vlistindex = m_sortedVertices.getNext(vlistindex);
+ }
- if (bNeedRepeat)
- _fixOrphanVertices();// fix broken structure of the shape
+ m_nextVertexToProcess = -1;
- if (_cleanupSpikes())
+ if (coincidentCount > 0) {
+ boolean result = _processBunch();
+ if (result)
bNeedRepeat = true;
+ }
+
+ if (iRepeatNum++ > 10) {
+ throw GeometryException.GeometryInternalError();
+ }
- bNeedWindingRepeat |= bNeedRepeat && bWinding;
+ if (bNeedRepeat)
+ _fixOrphanVertices();// fix broken structure of the shape
- bChanged |= bNeedRepeat;
+ if (_cleanupSpikes())
+ bNeedRepeat = true;
- } while (bNeedRepeat);
+ bChanged |= bNeedRepeat;
- }// while (bNeedWindingRepeat)
+ } while (bNeedRepeat);
// Now process rings. Fix ring orientation and determine rings that need
// to be deleted.
@@ -581,11 +565,8 @@ private boolean _simplify() {
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;
}
}
@@ -593,8 +574,6 @@ private boolean _getDirection(int vert1, int vert2) {
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);
@@ -602,17 +581,6 @@ private boolean _detectAndResolveCrossOver(boolean bDirection1,
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);
@@ -622,44 +590,42 @@ private boolean _detectAndResolveCrossOver(boolean bDirection1,
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;
+
+ 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 = br[j];
- int data = ar[j];
+ int key = m_br[j];
+ int data = m_ar[j];
int i = j - 1;
- while (i >= 0 && br[i] > key) {
- br[i + 1] = br[i];
- ar[i + 1] = ar[i];
+ while (i >= 0 && m_br[i] > key) {
+ m_br[i + 1] = m_br[i];
+ m_ar[i + 1] = m_ar[i];
i--;
}
- br[i + 1] = key;
- ar[i + 1] = data;
+ m_br[i + 1] = key;
+ m_ar[i + 1] = data;
}
int detector = 0;
- if (ar[0] != 0)
+ if (m_ar[0] != 0)
detector |= 1;
- if (ar[1] != 0)
+ if (m_ar[1] != 0)
detector |= 2;
- if (ar[2] != 0)
+ if (m_ar[2] != 0)
detector |= 4;
- if (ar[3] != 0)
+ if (m_ar[3] != 0)
detector |= 8;
if (detector != 5 && detector != 10)// not an overlap
return false;
@@ -701,19 +667,8 @@ private boolean _detectAndResolveCrossOver(boolean bDirection1,
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.");
+ _resolveOverlapOddEven(bDirection1, bDirection2, vertexA1,
+ vertexB1, vertexA2, vertexB2);
}
private void _resolveOverlapOddEven(boolean bDirection1,
@@ -721,8 +676,6 @@ private void _resolveOverlapOddEven(boolean bDirection1,
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); // | |
@@ -753,15 +706,6 @@ private void _resolveOverlapOddEven(boolean bDirection1,
}
} 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;
@@ -861,7 +805,6 @@ 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) {
@@ -984,61 +927,16 @@ private void _removeAngleSortInfo(int vertex) {
}
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_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;
- }
}
diff --git a/src/main/java/com/esri/core/geometry/SizeOf.java b/src/main/java/com/esri/core/geometry/SizeOf.java
new file mode 100644
index 00000000..8d9f4c77
--- /dev/null
+++ b/src/main/java/com/esri/core/geometry/SizeOf.java
@@ -0,0 +1,144 @@
+/*
+ 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 static sun.misc.Unsafe.ARRAY_BYTE_BASE_OFFSET;
+import static sun.misc.Unsafe.ARRAY_BYTE_INDEX_SCALE;
+import static sun.misc.Unsafe.ARRAY_CHAR_BASE_OFFSET;
+import static sun.misc.Unsafe.ARRAY_CHAR_INDEX_SCALE;
+import static sun.misc.Unsafe.ARRAY_DOUBLE_BASE_OFFSET;
+import static sun.misc.Unsafe.ARRAY_DOUBLE_INDEX_SCALE;
+import static sun.misc.Unsafe.ARRAY_FLOAT_BASE_OFFSET;
+import static sun.misc.Unsafe.ARRAY_FLOAT_INDEX_SCALE;
+import static sun.misc.Unsafe.ARRAY_INT_BASE_OFFSET;
+import static sun.misc.Unsafe.ARRAY_INT_INDEX_SCALE;
+import static sun.misc.Unsafe.ARRAY_LONG_BASE_OFFSET;
+import static sun.misc.Unsafe.ARRAY_LONG_INDEX_SCALE;
+import static sun.misc.Unsafe.ARRAY_OBJECT_BASE_OFFSET;
+import static sun.misc.Unsafe.ARRAY_OBJECT_INDEX_SCALE;
+import static sun.misc.Unsafe.ARRAY_SHORT_BASE_OFFSET;
+import static sun.misc.Unsafe.ARRAY_SHORT_INDEX_SCALE;
+
+public final class SizeOf {
+ public static final int SIZE_OF_ATTRIBUTE_STREAM_OF_FLOAT = 24;
+
+ public static final int SIZE_OF_ATTRIBUTE_STREAM_OF_DBL = 24;
+
+ public static final int SIZE_OF_ATTRIBUTE_STREAM_OF_INT8 = 24;
+
+ public static final int SIZE_OF_ATTRIBUTE_STREAM_OF_INT16 = 24;
+
+ public static final int SIZE_OF_ATTRIBUTE_STREAM_OF_INT32 = 24;
+
+ public static final int SIZE_OF_ATTRIBUTE_STREAM_OF_INT64 = 24;
+
+ public static final int SIZE_OF_ENVELOPE = 32;
+
+ public static final int SIZE_OF_ENVELOPE2D = 48;
+
+ public static final int SIZE_OF_LINE = 56;
+
+ public static final int SIZE_OF_MULTI_PATH = 24;
+
+ public static final int SIZE_OF_MULTI_PATH_IMPL = 112;
+
+ public static final int SIZE_OF_MULTI_POINT = 24;
+
+ public static final int SIZE_OF_MULTI_POINT_IMPL = 56;
+
+ public static final int SIZE_OF_POINT = 40;
+
+ public static final int SIZE_OF_POLYGON = 24;
+
+ public static final int SIZE_OF_POLYLINE = 24;
+
+ public static final int SIZE_OF_OGC_CONCRETE_GEOMETRY_COLLECTION = 24;
+
+ public static final int SIZE_OF_OGC_LINE_STRING = 24;
+
+ public static final int SIZE_OF_OGC_MULTI_LINE_STRING = 24;
+
+ public static final int SIZE_OF_OGC_MULTI_POINT = 24;
+
+ public static final int SIZE_OF_OGC_MULTI_POLYGON = 24;
+
+ public static final int SIZE_OF_OGC_POINT = 24;
+
+ public static final int SIZE_OF_OGC_POLYGON = 24;
+
+ 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 ARRAY_BYTE_BASE_OFFSET + (((long) ARRAY_BYTE_INDEX_SCALE) * length);
+ }
+
+ public static long sizeOfShortArray(int length) {
+ return ARRAY_SHORT_BASE_OFFSET + (((long) ARRAY_SHORT_INDEX_SCALE) * length);
+ }
+
+ public static long sizeOfCharArray(int length) {
+ return ARRAY_CHAR_BASE_OFFSET + (((long) ARRAY_CHAR_INDEX_SCALE) * length);
+ }
+
+ public static long sizeOfIntArray(int length) {
+ return ARRAY_INT_BASE_OFFSET + (((long) ARRAY_INT_INDEX_SCALE) * length);
+ }
+
+ public static long sizeOfLongArray(int length) {
+ return ARRAY_LONG_BASE_OFFSET + (((long) ARRAY_LONG_INDEX_SCALE) * length);
+ }
+
+ public static long sizeOfFloatArray(int length) {
+ return ARRAY_FLOAT_BASE_OFFSET + (((long) ARRAY_FLOAT_INDEX_SCALE) * length);
+ }
+
+ public static long sizeOfDoubleArray(int length) {
+ return ARRAY_DOUBLE_BASE_OFFSET + (((long) ARRAY_DOUBLE_INDEX_SCALE) * length);
+ }
+
+ public static long sizeOfObjectArray(int length)
+ {
+ return ARRAY_OBJECT_BASE_OFFSET + (((long) 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 44fe3912..26e6c562 100644
--- a/src/main/java/com/esri/core/geometry/SpatialReference.java
+++ b/src/main/java/com/esri/core/geometry/SpatialReference.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,14 +24,11 @@
package com.esri.core.geometry;
+import com.fasterxml.jackson.core.JsonParser;
+
import java.io.ObjectStreamException;
import java.io.Serializable;
-import com.esri.core.geometry.SpatialReference;
-import com.esri.core.geometry.SpatialReferenceSerializer;
-import com.esri.core.geometry.VertexDescription;
-import com.fasterxml.jackson.core.JsonParser;
-
/**
* A class that represents the spatial reference for the geometry.
* This class provide tolerance value for the topological and relational operations.
@@ -77,6 +74,7 @@ boolean isLocal() {
}
/**
+ * @deprecated Use fromJson(String)
* Returns spatial reference from the JsonParser.
*
* @param parser
@@ -86,6 +84,7 @@ boolean isLocal() {
* @throws Exception
* if parsing has failed
*/
+ @Deprecated
public static SpatialReference fromJson(JsonParser parser) throws Exception {
return fromJson(new JsonParserReader(parser));
}
diff --git a/src/main/java/com/esri/core/geometry/SpatialReferenceImpl.java b/src/main/java/com/esri/core/geometry/SpatialReferenceImpl.java
index 618eb6b8..25158369 100644
--- a/src/main/java/com/esri/core/geometry/SpatialReferenceImpl.java
+++ b/src/main/java/com/esri/core/geometry/SpatialReferenceImpl.java
@@ -25,20 +25,7 @@
package com.esri.core.geometry;
import java.util.Arrays;
-import java.util.HashMap;
-import java.util.Map;
import java.util.concurrent.locks.ReentrantLock;
-import java.lang.ref.*;
-
-import com.esri.core.geometry.Envelope2D;
-import com.esri.core.geometry.GeoDist;
-import com.esri.core.geometry.GeometryException;
-import com.esri.core.geometry.PeDouble;
-import com.esri.core.geometry.Point;
-import com.esri.core.geometry.Polyline;
-import com.esri.core.geometry.SpatialReference;
-import com.esri.core.geometry.SpatialReferenceImpl;
-import com.esri.core.geometry.VertexDescription.Semantics;
class SpatialReferenceImpl extends SpatialReference {
static final boolean no_projection_engine = true;
diff --git a/src/main/java/com/esri/core/geometry/StridedIndexTypeCollection.java b/src/main/java/com/esri/core/geometry/StridedIndexTypeCollection.java
index c54cfe9a..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,13 +23,21 @@
*/
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 {
+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;
@@ -273,4 +281,18 @@ private void grow_(long newsize) {
}
}
}
+
+ 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/Transformation2D.java b/src/main/java/com/esri/core/geometry/Transformation2D.java
index 99ea7cde..1704628a 100644
--- a/src/main/java/com/esri/core/geometry/Transformation2D.java
+++ b/src/main/java/com/esri/core/geometry/Transformation2D.java
@@ -24,6 +24,8 @@
package com.esri.core.geometry;
+import static com.esri.core.geometry.SizeOf.SIZE_OF_TRANSFORMATION_2D;
+
/**
* The affine transformation class for 2D.
*
@@ -921,4 +923,8 @@ public void extractScaleTransform(Transformation2D scale,
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 99702706..cac98407 100644
--- a/src/main/java/com/esri/core/geometry/Transformation3D.java
+++ b/src/main/java/com/esri/core/geometry/Transformation3D.java
@@ -33,7 +33,7 @@
* are the matrices. This is equivalent to the following line of code:
* ResultVector = (M1.Mul(M2).Mul(M3)).Transform(Vector)
*/
-final class Transformation3D {
+final public class Transformation3D {
public double xx, yx, zx, xd, xy, yy, zy, yd, xz, yz, zz, zd;
@@ -112,7 +112,7 @@ public Envelope3D transform(Envelope3D env) {
return env;
}
- void transform(Point3D[] pointsIn, int count, Point3D[] pointsOut) {
+ public void transform(Point3D[] pointsIn, int count, Point3D[] pointsOut) {
for (int i = 0; i < count; i++) {
Point3D res = new Point3D();
Point3D src = pointsIn[i];
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 3560333c..66eb1310 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,24 +25,55 @@
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;
import java.util.ArrayList;
import java.util.List;
+import static com.esri.core.geometry.SizeOf.SIZE_OF_OGC_CONCRETE_GEOMETRY_COLLECTION;
+
public class OGCConcreteGeometryCollection extends OGCGeometryCollection {
+ 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);
@@ -50,6 +81,11 @@ public OGCConcreteGeometryCollection(OGCGeometry geom, SpatialReference sr) {
esriSR = sr;
}
+ public OGCConcreteGeometryCollection(SpatialReference sr) {
+ geometries = new ArrayList();
+ esriSR = sr;
+ }
+
@Override
public int dimension() {
int maxD = 0;
@@ -101,7 +137,19 @@ public OGCGeometry geometryN(int n) {
@Override
public String geometryType() {
- return "GeometryCollection";
+ return TYPE;
+ }
+
+ @Override
+ public long estimateMemorySize()
+ {
+ long size = SIZE_OF_OGC_CONCRETE_GEOMETRY_COLLECTION;
+ if (geometries != null) {
+ for (OGCGeometry geometry : geometries) {
+ size += geometry.estimateMemorySize();
+ }
+ }
+ return size;
}
@Override
@@ -252,6 +300,7 @@ public boolean isSimple() {
for (int i = 0, n = numGeometries(); i < n; i++)
if (!geometryN(i).isSimple())
return false;
+
return true;
}
@@ -313,7 +362,7 @@ protected boolean isConcreteGeometryCollection() {
return true;
}
- static class GeometryCursorOGC extends GeometryCursor {
+ private static class GeometryCursorOGC extends GeometryCursor {
private int m_index;
private int m_ind;
private List m_geoms;
@@ -362,8 +411,59 @@ public int getGeometryID() {
}
}
+
+ @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");
+ }
+ }
- List geometries;
+ 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_) {
@@ -378,6 +478,20 @@ public void setSpatialReference(SpatialReference esriSR_) {
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() {
@@ -425,4 +539,420 @@ public int 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 0755dc2e..dd229e5e 100644
--- a/src/main/java/com/esri/core/geometry/ogc/OGCCurve.java
+++ b/src/main/java/com/esri/core/geometry/ogc/OGCCurve.java
@@ -41,6 +41,9 @@ public boolean isRing() {
@Override
public OGCGeometry boundary() {
+ if (isEmpty())
+ return new OGCMultiPoint(this.getEsriSpatialReference());
+
if (isClosed())
return new OGCMultiPoint(new MultiPoint(getEsriGeometry()
.getDescription()), esriSR);// return empty multipoint;
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 7bcc17c8..a6fdeaa9 100644
--- a/src/main/java/com/esri/core/geometry/ogc/OGCGeometry.java
+++ b/src/main/java/com/esri/core/geometry/ogc/OGCGeometry.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,12 +24,45 @@
package com.esri.core.geometry.ogc;
+import com.esri.core.geometry.Envelope;
+import com.esri.core.geometry.Envelope1D;
+import com.esri.core.geometry.Geometry;
+import com.esri.core.geometry.GeometryCursor;
+import com.esri.core.geometry.GeometryCursorAppend;
+import com.esri.core.geometry.GeometryEngine;
+import com.esri.core.geometry.JsonParserReader;
+import com.esri.core.geometry.MapGeometry;
+import com.esri.core.geometry.MapOGCStructure;
+import com.esri.core.geometry.MultiPoint;
+import com.esri.core.geometry.NumberUtils;
+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;
+import com.esri.core.geometry.OperatorFactoryLocal;
+import com.esri.core.geometry.OperatorImportFromESRIShape;
+import com.esri.core.geometry.OperatorImportFromGeoJson;
+import com.esri.core.geometry.OperatorImportFromWkb;
+import com.esri.core.geometry.OperatorImportFromWkt;
+import com.esri.core.geometry.OperatorIntersection;
+import com.esri.core.geometry.OperatorSimplify;
+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;
+import com.esri.core.geometry.SpatialReference;
+import com.esri.core.geometry.VertexDescription;
+
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
-import com.esri.core.geometry.*;
-
/**
* OGC Simple Feature Access specification v.1.2.1
*
@@ -53,6 +86,17 @@ public int coordinateDimension() {
abstract public String geometryType();
+ /**
+ * 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 abstract long estimateMemorySize();
+
public int SRID() {
if (esriSR == null)
return 0;
@@ -209,23 +253,31 @@ public boolean isMeasured() {
*/
public boolean Equals(OGCGeometry another) {
if (this == another)
- return true;
+ 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,
@@ -237,6 +289,11 @@ public boolean intersects(OGCGeometry 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,
@@ -244,6 +301,11 @@ public boolean touches(OGCGeometry another) {
}
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,
@@ -251,13 +313,14 @@ public boolean crosses(OGCGeometry another) {
}
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());
+ 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,
@@ -265,6 +328,11 @@ public boolean contains(OGCGeometry another) {
}
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,
@@ -272,6 +340,11 @@ public boolean overlaps(OGCGeometry another) {
}
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,
@@ -284,6 +357,14 @@ public boolean relate(OGCGeometry another, String matrix) {
// 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,
@@ -385,15 +466,43 @@ public OGCGeometry buffer(double distance) {
return OGCGeometry.createFromEsriGeometry(cursor.next(), esriSR);
}
- public OGCGeometry convexHull() {
- com.esri.core.geometry.OperatorConvexHull op = (OperatorConvexHull) OperatorFactoryLocal
- .getInstance().getOperator(Operator.Type.ConvexHull);
+ public OGCGeometry buffer(double distance, int max_vertices_in_full_circle, double max_deviation) {
+ 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(), true, null);
+ getEsriGeometryCursor(), getEsriSpatialReference(), d, max_deviation, max_vertices_in_full_circle, 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(
@@ -403,6 +512,18 @@ public OGCGeometry intersection(OGCGeometry another) {
}
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(
@@ -413,6 +534,10 @@ public OGCGeometry union(OGCGeometry another) {
}
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(
@@ -421,6 +546,11 @@ public OGCGeometry difference(OGCGeometry another) {
}
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(
@@ -670,6 +800,17 @@ public void setSpatialReference(SpatialReference esriSR_) {
*/
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();
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 da51e2d9..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.
@@ -34,9 +34,14 @@
import com.esri.core.geometry.SpatialReference;
import com.esri.core.geometry.WkbExportFlags;
import com.esri.core.geometry.WktExportFlags;
+
import java.nio.ByteBuffer;
+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.
*/
@@ -78,6 +83,9 @@ public OGCPoint pointN(int n) {
@Override
public boolean isClosed() {
+ if (isEmpty())
+ return false;
+
return multiPath.isClosedPathInXYPlane(0);
}
@@ -113,7 +121,13 @@ public OGCPoint endPoint() {
@Override
public String geometryType() {
- return "LineString";
+ return TYPE;
+ }
+
+ @Override
+ public long estimateMemorySize()
+ {
+ return SIZE_OF_OGC_LINE_STRING + (multiPath != null ? multiPath.estimateMemorySize() : 0);
}
@Override
@@ -137,5 +151,10 @@ 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/OGCMultiLineString.java b/src/main/java/com/esri/core/geometry/ogc/OGCMultiLineString.java
index 37006a16..e0608f61 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.
@@ -36,26 +36,37 @@
import com.esri.core.geometry.SpatialReference;
import com.esri.core.geometry.WkbExportFlags;
import com.esri.core.geometry.WktExportFlags;
+
import java.nio.ByteBuffer;
-public class OGCMultiLineString extends OGCMultiCurve {
+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);
}
+
@Override
- public String asGeoJson() {
- OperatorExportToGeoJson op = (OperatorExportToGeoJson) OperatorFactoryLocal
- .getInstance().getOperator(Operator.Type.ExportToGeoJson);
- return op.execute(GeoJsonExportFlags.geoJsonExportPreferMultiGeometry, null, getEsriGeometry());
- }
+ public String asGeoJson() {
+ OperatorExportToGeoJson op = (OperatorExportToGeoJson) OperatorFactoryLocal.getInstance()
+ .getOperator(Operator.Type.ExportToGeoJson);
+ return op.execute(GeoJsonExportFlags.geoJsonExportPreferMultiGeometry, esriSR, getEsriGeometry());
+ }
+
@Override
public ByteBuffer asBinary() {
OperatorExportToWkb op = (OperatorExportToWkb) OperatorFactoryLocal
@@ -72,7 +83,13 @@ public OGCGeometry geometryN(int n) {
@Override
public String geometryType() {
- return "MultiLineString";
+ return TYPE;
+ }
+
+ @Override
+ public long estimateMemorySize()
+ {
+ return SIZE_OF_OGC_MULTI_LINE_STRING + (polyline != null ? polyline.estimateMemorySize() : 0);
}
@Override
@@ -106,5 +123,19 @@ 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 77258957..b1c70a02 100644
--- a/src/main/java/com/esri/core/geometry/ogc/OGCMultiPoint.java
+++ b/src/main/java/com/esri/core/geometry/ogc/OGCMultiPoint.java
@@ -24,8 +24,6 @@
package com.esri.core.geometry.ogc;
-import java.nio.ByteBuffer;
-
import com.esri.core.geometry.Geometry;
import com.esri.core.geometry.GeometryEngine;
import com.esri.core.geometry.MultiPoint;
@@ -37,7 +35,13 @@
import com.esri.core.geometry.WkbExportFlags;
import com.esri.core.geometry.WktExportFlags;
+import java.nio.ByteBuffer;
+
+import static com.esri.core.geometry.SizeOf.SIZE_OF_OGC_MULTI_POINT;
+
public class OGCMultiPoint extends OGCGeometryCollection {
+ public static String TYPE = "MultiPoint";
+
public int numGeometries() {
return multiPoint.getPointCount();
}
@@ -63,7 +67,13 @@ public OGCGeometry geometryN(int n) {
@Override
public String geometryType() {
- return "MultiPoint";
+ return TYPE;
+ }
+
+ @Override
+ public long estimateMemorySize()
+ {
+ return SIZE_OF_OGC_MULTI_POINT + (multiPoint != null ? multiPoint.estimateMemorySize() : 0);
}
/**
@@ -123,5 +133,19 @@ 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 944e88d5..941bc7c2 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.
@@ -36,15 +36,24 @@
import com.esri.core.geometry.SpatialReference;
import com.esri.core.geometry.WkbExportFlags;
import com.esri.core.geometry.WktExportFlags;
+
import java.nio.ByteBuffer;
-public class OGCMultiPolygon extends OGCMultiSurface {
+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(SpatialReference sr) {
+ polygon = new Polygon();
+ esriSR = sr;
+ }
+
@Override
public String asText() {
return GeometryEngine.geometryToWkt(getEsriGeometry(),
@@ -62,7 +71,7 @@ public ByteBuffer asBinary() {
public String asGeoJson() {
OperatorExportToGeoJson op = (OperatorExportToGeoJson) OperatorFactoryLocal
.getInstance().getOperator(Operator.Type.ExportToGeoJson);
- return op.execute(GeoJsonExportFlags.geoJsonExportPreferMultiGeometry, null, getEsriGeometry());
+ return op.execute(GeoJsonExportFlags.geoJsonExportPreferMultiGeometry, esriSR, getEsriGeometry());
}
@Override
public int numGeometries() {
@@ -86,7 +95,13 @@ public OGCGeometry geometryN(int n) {
@Override
public String geometryType() {
- return "MultiPolygon";
+ return TYPE;
+ }
+
+ @Override
+ public long estimateMemorySize()
+ {
+ return SIZE_OF_OGC_MULTI_POLYGON + (polygon != null ? polygon.estimateMemorySize() : 0);
}
@Override
@@ -120,5 +135,19 @@ 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 1c98be92..5a36dd0e 100644
--- a/src/main/java/com/esri/core/geometry/ogc/OGCMultiSurface.java
+++ b/src/main/java/com/esri/core/geometry/ogc/OGCMultiSurface.java
@@ -29,11 +29,6 @@ public double area() {
return getEsriGeometry().calculateArea2D();
}
- public OGCPoint centroid() {
- // TODO
- throw new UnsupportedOperationException();
- }
-
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 7e246a6e..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.
@@ -24,8 +24,6 @@
package com.esri.core.geometry.ogc;
-import java.nio.ByteBuffer;
-
import com.esri.core.geometry.GeometryEngine;
import com.esri.core.geometry.MultiPoint;
import com.esri.core.geometry.Operator;
@@ -36,7 +34,13 @@
import com.esri.core.geometry.WkbExportFlags;
import com.esri.core.geometry.WktExportFlags;
+import java.nio.ByteBuffer;
+
+import static com.esri.core.geometry.SizeOf.SIZE_OF_OGC_POINT;
+
public final class OGCPoint extends OGCGeometry {
+ public static String TYPE = "Point";
+
public OGCPoint(Point pt, SpatialReference sr) {
point = pt;
esriSR = sr;
@@ -74,7 +78,13 @@ public double M() {
@Override
public String geometryType() {
- return "Point";
+ return TYPE;
+ }
+
+ @Override
+ public long estimateMemorySize()
+ {
+ return SIZE_OF_OGC_POINT + (point != null ? point.estimateMemorySize() : 0);
}
@Override
@@ -105,6 +115,11 @@ 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 b27e4e48..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.
@@ -34,9 +34,14 @@
import com.esri.core.geometry.SpatialReference;
import com.esri.core.geometry.WkbExportFlags;
import com.esri.core.geometry.WktExportFlags;
+
import java.nio.ByteBuffer;
+import static com.esri.core.geometry.SizeOf.SIZE_OF_OGC_POLYGON;
+
public class OGCPolygon extends OGCSurface {
+ 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++) {
@@ -106,7 +111,13 @@ public OGCMultiCurve boundary() {
@Override
public String geometryType() {
- return "Polygon";
+ return TYPE;
+ }
+
+ @Override
+ public long estimateMemorySize()
+ {
+ return SIZE_OF_OGC_POLYGON + (polygon != null ? polygon.estimateMemorySize() : 0);
}
@Override
@@ -132,5 +143,10 @@ 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 43d192e6..989dfec8 100644
--- a/src/main/java/com/esri/core/geometry/ogc/OGCSurface.java
+++ b/src/main/java/com/esri/core/geometry/ogc/OGCSurface.java
@@ -29,11 +29,6 @@ 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();
diff --git a/src/main/java/com/esri/core/geometry/ogc/package-info.java b/src/main/java/com/esri/core/geometry/ogc/package-info.java
new file mode 100644
index 00000000..b6b69aa6
--- /dev/null
+++ b/src/main/java/com/esri/core/geometry/ogc/package-info.java
@@ -0,0 +1,19 @@
+/*
+ Copyright 2017-2023 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.
+ */
+
+@org.osgi.annotation.bundle.Export
+@org.osgi.annotation.versioning.Version("2.2.4")
+package com.esri.core.geometry.ogc;
diff --git a/src/main/java/com/esri/core/geometry/package-info.java b/src/main/java/com/esri/core/geometry/package-info.java
new file mode 100644
index 00000000..5a613f65
--- /dev/null
+++ b/src/main/java/com/esri/core/geometry/package-info.java
@@ -0,0 +1,19 @@
+/*
+ Copyright 2017-2023 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.
+ */
+
+@org.osgi.annotation.bundle.Export
+@org.osgi.annotation.versioning.Version("2.2.4")
+package com.esri.core.geometry;
diff --git a/src/test/java/com/esri/core/geometry/TestBuffer.java b/src/test/java/com/esri/core/geometry/TestBuffer.java
index 341751f5..e60145bb 100755
--- a/src/test/java/com/esri/core/geometry/TestBuffer.java
+++ b/src/test/java/com/esri/core/geometry/TestBuffer.java
@@ -27,6 +27,8 @@
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 {
@@ -389,4 +391,27 @@ public void testBufferPolygon() {
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/TestConvexHull.java b/src/test/java/com/esri/core/geometry/TestConvexHull.java
index b2e2d59e..ee9c764e 100644
--- a/src/test/java/com/esri/core/geometry/TestConvexHull.java
+++ b/src/test/java/com/esri/core/geometry/TestConvexHull.java
@@ -27,6 +27,8 @@
import junit.framework.TestCase;
import org.junit.Test;
+import com.esri.core.geometry.ogc.OGCGeometry;
+
public class TestConvexHull extends TestCase {
@Override
protected void setUp() throws Exception {
@@ -992,5 +994,79 @@ public void testHullTickTock() {
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 456973cd..a388ff01 100644
--- a/src/test/java/com/esri/core/geometry/TestCut.java
+++ b/src/test/java/com/esri/core/geometry/TestCut.java
@@ -51,7 +51,7 @@ public static void testCut4326() {
}
- public static void testConsiderTouch1(SpatialReference spatialReference) {
+ private static void testConsiderTouch1(SpatialReference spatialReference) {
OperatorFactoryLocal engine = OperatorFactoryLocal.getInstance();
OperatorCut opCut = (OperatorCut) engine.getOperator(Operator.Type.Cut);
@@ -101,7 +101,7 @@ public static void testConsiderTouch1(SpatialReference spatialReference) {
assertTrue(cut == null);
}
- public static void testConsiderTouch2(SpatialReference spatialReference) {
+ private static void testConsiderTouch2(SpatialReference spatialReference) {
OperatorFactoryLocal engine = OperatorFactoryLocal.getInstance();
OperatorCut opCut = (OperatorCut) engine.getOperator(Operator.Type.Cut);
@@ -167,7 +167,7 @@ public static void testConsiderTouch2(SpatialReference spatialReference) {
assertTrue(cut == null);
}
- public static void testPolygon5(SpatialReference spatialReference) {
+ private static void testPolygon5(SpatialReference spatialReference) {
OperatorFactoryLocal engine = OperatorFactoryLocal.getInstance();
OperatorCut opCut = (OperatorCut) engine.getOperator(Operator.Type.Cut);
@@ -201,7 +201,7 @@ public static void testPolygon5(SpatialReference spatialReference) {
assertTrue(cut == null);
}
- public static void testPolygon7(SpatialReference spatialReference) {
+ private static void testPolygon7(SpatialReference spatialReference) {
OperatorFactoryLocal engine = OperatorFactoryLocal.getInstance();
OperatorCut opCut = (OperatorCut) engine.getOperator(Operator.Type.Cut);
@@ -238,7 +238,7 @@ public static void testPolygon7(SpatialReference spatialReference) {
assertTrue(cut == null);
}
- public static void testPolygon8(SpatialReference spatialReference) {
+ private static void testPolygon8(SpatialReference spatialReference) {
OperatorFactoryLocal engine = OperatorFactoryLocal.getInstance();
OperatorCut opCut = (OperatorCut) engine.getOperator(Operator.Type.Cut);
@@ -275,7 +275,7 @@ public static void testPolygon8(SpatialReference spatialReference) {
assertTrue(cut == null);
}
- public static void testPolygon9(SpatialReference spatialReference) {
+ private static void testPolygon9(SpatialReference spatialReference) {
OperatorFactoryLocal engine = OperatorFactoryLocal.getInstance();
OperatorCut opCut = (OperatorCut) engine.getOperator(Operator.Type.Cut);
@@ -309,7 +309,7 @@ public static void testPolygon9(SpatialReference spatialReference) {
assertTrue(cut == null);
}
- public static void testEngine(SpatialReference spatialReference) {
+ private static void testEngine(SpatialReference spatialReference) {
Polygon polygon8 = makePolygon8();
Polyline cutter8 = makePolygonCutter8();
@@ -337,7 +337,7 @@ public static void testEngine(SpatialReference spatialReference) {
assertTrue(area == 800);
}
- public static Polyline makePolyline1() {
+ private static Polyline makePolyline1() {
Polyline poly = new Polyline();
poly.startPath(0, 0);
@@ -355,7 +355,7 @@ public static Polyline makePolyline1() {
return poly;
}
- public static Polyline makePolylineCutter1() {
+ private static Polyline makePolylineCutter1() {
Polyline poly = new Polyline();
poly.startPath(1, 0);
@@ -395,7 +395,7 @@ public static Polyline makePolylineCutter1() {
return poly;
}
- public static Polyline makePolyline2() {
+ private static Polyline makePolyline2() {
Polyline poly = new Polyline();
poly.startPath(-2, 0);
@@ -410,7 +410,7 @@ public static Polyline makePolyline2() {
return poly;
}
- public static Polyline makePolylineCutter2() {
+ private static Polyline makePolylineCutter2() {
Polyline poly = new Polyline();
poly.startPath(-1.5, 0);
@@ -443,7 +443,7 @@ public static Polyline makePolylineCutter2() {
return poly;
}
- public static Polygon makePolygon5() {
+ private static Polygon makePolygon5() {
Polygon poly = new Polygon();
poly.startPath(0, 0);
@@ -454,7 +454,7 @@ public static Polygon makePolygon5() {
return poly;
}
- public static Polyline makePolygonCutter5() {
+ private static Polyline makePolygonCutter5() {
Polyline poly = new Polyline();
poly.startPath(15, 0);
@@ -466,7 +466,7 @@ public static Polyline makePolygonCutter5() {
return poly;
}
- public static Polygon makePolygon7() {
+ private static Polygon makePolygon7() {
Polygon poly = new Polygon();
poly.startPath(0, 0);
@@ -477,7 +477,7 @@ public static Polygon makePolygon7() {
return poly;
}
- public static Polyline makePolygonCutter7() {
+ private static Polyline makePolygonCutter7() {
Polyline poly = new Polyline();
poly.startPath(10, 10);
@@ -489,7 +489,7 @@ public static Polyline makePolygonCutter7() {
return poly;
}
- public static Polygon makePolygon8() {
+ private static Polygon makePolygon8() {
Polygon poly = new Polygon();
poly.startPath(0, 0);
@@ -500,7 +500,7 @@ public static Polygon makePolygon8() {
return poly;
}
- public static Polyline makePolygonCutter8() {
+ private static Polyline makePolygonCutter8() {
Polyline poly = new Polyline();
poly.startPath(10, 10);
@@ -512,7 +512,7 @@ public static Polyline makePolygonCutter8() {
return poly;
}
- public static Polygon makePolygon9() {
+ private static Polygon makePolygon9() {
Polygon poly = new Polygon();
poly.startPath(0, 0);
@@ -533,7 +533,7 @@ public static Polygon makePolygon9() {
return poly;
}
- public static Polyline makePolygonCutter9() {
+ private static Polyline makePolygonCutter9() {
Polyline poly = new Polyline();
poly.startPath(5, -1);
@@ -541,4 +541,20 @@ public static Polyline makePolygonCutter9() {
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 c6f22321..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,8 +24,6 @@
package com.esri.core.geometry;
-import java.util.ArrayList;
-import java.util.List;
import junit.framework.TestCase;
@@ -504,6 +502,14 @@ public static void testDifferenceOnPolyline() {
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();
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..9ee34862
--- /dev/null
+++ b/src/test/java/com/esri/core/geometry/TestEnvelope.java
@@ -0,0 +1,179 @@
+/*
+ * 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
+ /**The function returns the x and y coordinates of the center of the envelope.
+ * If the envelope is empty the point is set to empty otherwise the point is set to the center of the envelope.
+ */
+ public void testGetCeneter(){
+ //xmin,ymin,xmax,ymax of envelope
+ Envelope env1 = new Envelope(1,1, 2, 4);
+ Envelope env2 = new Envelope();
+ Point p = new Point();
+ Point p1 = new Point(1,2);
+
+ /**Tests if the point is correctly set to the center of the envelope, */
+ env1.getCenter(p);
+ assertTrue(p.getX() == 1.5);
+
+ /** Tests if the point is empty because of the envelope is empty */
+ env2.getCenter(p1);
+ assertTrue(p1.isEmpty());
+ }
+ @Test
+ /* Merge takes a Point as input and increas the bouandary of the envelope to contain the point.
+ *If the point is empty the envelope remains the same or if the envelope is empty the coordinates
+ *of the point is assigned to the envelope */
+ public void testMerge(){
+
+ /* To increase the covarege the branch where the envelope is empty can be tested
+ * And that the envelope and the point is not empty */
+ Envelope env1 = new Envelope(1,1, 2, 4);
+ Envelope env2 = new Envelope(1,1, 2, 4);
+ Envelope env3 = new Envelope(1,1, 2, 4);
+ Point p = new Point(100,4);
+
+ /*This should be false since env1 should change depending on point p */
+ env1.merge(p);
+ assertFalse(env1.equals(env2));
+
+ /* This assert should be true since the point is empty and therefore env2 should not change */
+ Point p1 = new Point();
+ env2.merge(p1);
+ assertTrue(env2.equals(env3));
+ }
+
+
+ @Test
+ /** TESTEST ENVELOPE2D **
+ * ClipLine modify a line to be inside a envelope if possible */
+ public void TestClipLine(){
+
+ //checking if segPrama is 0 and the segment is outside of the clipping window
+ //covers first return
+ Envelope2D env0 = new Envelope2D(1, 1, 4, 4);
+ // Reaches the branch where the delta is 0
+ Point2D p1 = new Point2D(2,2);
+ Point2D p2 = new Point2D(2,2);
+
+ int lineExtension = 0;
+ double[] segParams = {3,4};
+ //reaches the branch where boundaryDistances is not 0
+ double[] boundaryDistances = {2.0, 3.0};
+
+ int a = env0.clipLine(p1, p2, lineExtension, segParams, boundaryDistances);
+ //should be true since the points are inside the envelope
+ assertTrue(a == 4);
+
+ // Changes p3 to fit the envelop, the line is on the edge of the envelope
+ Envelope2D env1 = new Envelope2D(1, 1, 4, 4);
+ Point2D p3 = new Point2D(1,10);
+ Point2D p4 = new Point2D(1,1);
+
+ int b = env1.clipLine(p3, p4, lineExtension, segParams, boundaryDistances);
+ assertTrue(b == 1);
+ // the second point is outside and therefore changed
+ Envelope2D env2 = new Envelope2D(1, 1, 4, 4);
+ Point2D p5 = new Point2D(2,2);
+ Point2D p6 = new Point2D(1,10);
+
+ int c = env2.clipLine(p5, p6, lineExtension, segParams, boundaryDistances);
+ assertTrue(c == 2);
+
+ //Both points is outside the envelope and therefore no line is possible to clip, and this should return 0
+ Envelope2D env3 = new Envelope2D(1, 1, 4, 4);
+ Point2D p7 = new Point2D(11,10);
+ Point2D p8 = new Point2D(5,5);
+
+ int d = env3.clipLine(p7, p8, lineExtension, segParams, boundaryDistances);
+ assertTrue(d == 0);
+ }
+
+ @Test
+ public void testSqrDistances(){
+ //the point is on the envelope, which means that the distance is 0
+ Envelope2D env0 = new Envelope2D(1, 1, 4, 4);
+ Point2D p0 = new Point2D(4,4);
+ assertTrue(env0.sqrDistance(p0) == 0.0);
+
+ Envelope2D env1 = new Envelope2D(1, 1, 4, 4);
+ Point2D p1 = new Point2D(1,0);
+
+ assertTrue(env0.sqrDistance(p1) == 1.0);
+
+ }
+ @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/TestEnvelope1D.java b/src/test/java/com/esri/core/geometry/TestEnvelope1D.java
new file mode 100644
index 00000000..4ecd8cbc
--- /dev/null
+++ b/src/test/java/com/esri/core/geometry/TestEnvelope1D.java
@@ -0,0 +1,22 @@
+package com.esri.core.geometry;
+
+import junit.framework.TestCase;
+import org.junit.Test;
+public class TestEnvelope1D extends TestCase{
+ @Test
+ public void testCalculateToleranceFromEnvelopeEmpty() {
+ Envelope1D envelope = new Envelope1D();
+ envelope.setEmpty();
+ double tolerance = envelope._calculateToleranceFromEnvelope();
+ assertEquals(100.0 * NumberUtils.doubleEps(), tolerance, 0.0001);
+ }
+
+ @Test
+ public void testCalculateToleranceFromEnvelopeNonEmpty() {
+ Envelope1D envelope = new Envelope1D(2.0, 4.0);
+ double tolerance = envelope._calculateToleranceFromEnvelope();
+ assertEquals(2.220446049250313e-14, tolerance, 1e-10);
+ }
+
+
+}
diff --git a/src/test/java/com/esri/core/geometry/TestEstimateMemorySize.java b/src/test/java/com/esri/core/geometry/TestEstimateMemorySize.java
new file mode 100644
index 00000000..b1b40b22
--- /dev/null
+++ b/src/test/java/com/esri/core/geometry/TestEstimateMemorySize.java
@@ -0,0 +1,193 @@
+/*
+ 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;
+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 org.junit.Test;
+// ClassLayout is GPL with Classpath exception, see http://openjdk.java.net/legal/gplv2+ce.html
+import org.openjdk.jol.info.ClassLayout;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+public class TestEstimateMemorySize {
+ @Test
+ public void testInstanceSizes() {
+ assertEquals(getInstanceSize(AttributeStreamOfFloat.class), SizeOf.SIZE_OF_ATTRIBUTE_STREAM_OF_FLOAT);
+ assertEquals(getInstanceSize(AttributeStreamOfDbl.class), SizeOf.SIZE_OF_ATTRIBUTE_STREAM_OF_DBL);
+ assertEquals(getInstanceSize(AttributeStreamOfInt8.class), SizeOf.SIZE_OF_ATTRIBUTE_STREAM_OF_INT8);
+ assertEquals(getInstanceSize(AttributeStreamOfInt16.class), SizeOf.SIZE_OF_ATTRIBUTE_STREAM_OF_INT16);
+ assertEquals(getInstanceSize(AttributeStreamOfInt32.class), SizeOf.SIZE_OF_ATTRIBUTE_STREAM_OF_INT32);
+ assertEquals(getInstanceSize(AttributeStreamOfInt64.class), SizeOf.SIZE_OF_ATTRIBUTE_STREAM_OF_INT64);
+ assertEquals(getInstanceSize(Envelope.class), SizeOf.SIZE_OF_ENVELOPE);
+ assertEquals(getInstanceSize(Envelope2D.class), SizeOf.SIZE_OF_ENVELOPE2D);
+ assertEquals(getInstanceSize(Line.class), SizeOf.SIZE_OF_LINE);
+ assertEquals(getInstanceSize(MultiPath.class), SizeOf.SIZE_OF_MULTI_PATH);
+ assertEquals(getInstanceSize(MultiPathImpl.class), SizeOf.SIZE_OF_MULTI_PATH_IMPL);
+ assertEquals(getInstanceSize(MultiPoint.class), SizeOf.SIZE_OF_MULTI_POINT);
+ assertEquals(getInstanceSize(MultiPointImpl.class), SizeOf.SIZE_OF_MULTI_POINT_IMPL);
+ assertEquals(getInstanceSize(Point.class), SizeOf.SIZE_OF_POINT);
+ assertEquals(getInstanceSize(Polygon.class), SizeOf.SIZE_OF_POLYGON);
+ assertEquals(getInstanceSize(Polyline.class), SizeOf.SIZE_OF_POLYLINE);
+ assertEquals(getInstanceSize(OGCConcreteGeometryCollection.class),
+ SizeOf.SIZE_OF_OGC_CONCRETE_GEOMETRY_COLLECTION);
+ assertEquals(getInstanceSize(OGCLineString.class), SizeOf.SIZE_OF_OGC_LINE_STRING);
+ assertEquals(getInstanceSize(OGCMultiLineString.class), SizeOf.SIZE_OF_OGC_MULTI_LINE_STRING);
+ assertEquals(getInstanceSize(OGCMultiPoint.class), SizeOf.SIZE_OF_OGC_MULTI_POINT);
+ 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) {
+ return ClassLayout.parseClass(clazz).instanceSize();
+ }
+
+ @Test
+ 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 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() {
+ 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() {
+ 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() {
+ 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
+ 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);
+ return geometry;
+ }
+}
diff --git a/src/test/java/com/esri/core/geometry/TestGeomToGeoJson.java b/src/test/java/com/esri/core/geometry/TestGeomToGeoJson.java
index aa480b26..83271d5b 100644
--- a/src/test/java/com/esri/core/geometry/TestGeomToGeoJson.java
+++ b/src/test/java/com/esri/core/geometry/TestGeomToGeoJson.java
@@ -22,14 +22,9 @@
package com.esri.core.geometry;
-import com.esri.core.geometry.ogc.OGCGeometry;
-import com.esri.core.geometry.ogc.OGCPoint;
-import com.esri.core.geometry.ogc.OGCMultiPoint;
-import com.esri.core.geometry.ogc.OGCLineString;
-import com.esri.core.geometry.ogc.OGCPolygon;
+import com.esri.core.geometry.ogc.*;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParser;
-import com.esri.core.geometry.ogc.OGCConcreteGeometryCollection;
import junit.framework.TestCase;
import org.junit.Test;
@@ -161,6 +156,20 @@ public void testOGCLineString() {
assertEquals("{\"type\":\"LineString\",\"coordinates\":[[100,0],[101,0],[101,1],[100,1]],\"crs\":null}", result);
}
+ @Test
+ public void testOGCMultiLineStringCRS() throws IOException {
+ 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);
+
+ OGCMultiLineString multiLineString = new OGCMultiLineString(p, SpatialReference.create(4326));
+
+ String result = multiLineString.asGeoJson();
+ assertEquals("{\"type\":\"MultiLineString\",\"coordinates\":[[[100,0],[101,0],[101,1],[100,1]]],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:4326\"}}}", result);
+ }
+
@Test
public void testPolygon() {
Polygon p = new Polygon();
@@ -241,6 +250,24 @@ public void testMultiPolygon() throws IOException {
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 testOGCMultiPolygonCRS() throws IOException {
+ JsonFactory jsonFactory = new JsonFactory();
+
+ 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);
+
+ parsedPoly.setSpatialReference(SpatialReference.create(4326));
+ Polygon poly = (Polygon) parsedPoly.getGeometry();
+ OGCMultiPolygon multiPolygon = new OGCMultiPolygon(poly, parsedPoly.getSpatialReference());
+
+
+ String result = multiPolygon.asGeoJson();
+ 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]]]],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:4326\"}}}", result);
+ }
+
@Test
public void testEmptyPolygon() {
@@ -334,6 +361,29 @@ public void testOGCPolygonWithHole() {
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 testOGCPolygonWithHoleCRS() {
+ 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();
+
+ SpatialReference sr = SpatialReference.create(4326);
+
+ OGCPolygon ogcPolygon = new OGCPolygon(p, sr);
+ 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\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:4326\"}}}", result);
+ }
+
@Test
public void testGeometryCollection() {
SpatialReference sr = SpatialReference.create(4326);
diff --git a/src/test/java/com/esri/core/geometry/TestImportExport.java b/src/test/java/com/esri/core/geometry/TestImportExport.java
index 0b9e2bc8..73faed01 100644
--- a/src/test/java/com/esri/core/geometry/TestImportExport.java
+++ b/src/test/java/com/esri/core/geometry/TestImportExport.java
@@ -44,15 +44,6 @@ protected void tearDown() throws Exception {
@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);
-// boolean result1 = OperatorSimplify.local().isSimpleAsFeature(g, null, null);
-// boolean result2 = OperatorSimplifyOGC.local().isSimpleOGC(g, null, true, null, null);
-// Geometry simple = OperatorSimplifyOGC.local().execute(g, null, true, null);
-// 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);
@@ -1754,6 +1745,20 @@ public static void testImportGeoJsonSpatialReference() throws Exception {
assertTrue(mapGeometry4326.getGeometry().equals(mapGeometry3857.getGeometry()));
}
+ @Test
+ public void testZeroRingWkb() {
+ //https://github.com/Esri/geometry-api-java/issues/275
+ Polygon poly = new Polygon();
+ poly.startPath(0, 0);
+ poly.lineTo(0, 10);
+ poly.lineTo(0, 10);
+ poly.addEnvelope(new Envelope(1, 1, 3, 3), false);
+
+ ByteBuffer bb = OperatorExportToWkb.local().execute(0, poly, null);
+ Geometry res = OperatorImportFromWkb.local().execute(0, Geometry.Type.Unknown, bb, null);
+ assertTrue(res.equals(poly));
+ }
+
public static Polygon makePolygon() {
Polygon poly = new Polygon();
poly.startPath(0, 0);
diff --git a/src/test/java/com/esri/core/geometry/TestIndexHashTable.java b/src/test/java/com/esri/core/geometry/TestIndexHashTable.java
new file mode 100644
index 00000000..36ec75ac
--- /dev/null
+++ b/src/test/java/com/esri/core/geometry/TestIndexHashTable.java
@@ -0,0 +1,72 @@
+package com.esri.core.geometry;
+import org.junit.Test;
+import junit.framework.TestCase;
+public class TestIndexHashTable extends TestCase{
+ @Test
+ public void testAddElement() {
+ IndexHashTable.HashFunction hashFunction = new IndexHashTable.HashFunction() {
+ @Override
+ public int getHash(int element) {
+ return element % 10; // A simple hash function for testing
+ }
+
+ @Override
+ public boolean equal(int element1, int element2) {
+ return element1 == element2;
+ }
+
+ @Override
+ public int getHash(Object elementDescriptor) {
+ return ((Integer) elementDescriptor) % 10;
+ }
+
+ @Override
+ public boolean equal(Object elementDescriptor, int element) {
+ return ((Integer) elementDescriptor) == element;
+ }
+ };
+
+ IndexHashTable hashTable = new IndexHashTable(10, hashFunction);
+
+ int element1 = 5;
+
+ int node1 = hashTable.addElement(element1);
+
+ assertEquals(node1, hashTable.findNode(element1));
+ }
+
+ @Test
+ public void testDeleteElement() {
+ IndexHashTable.HashFunction hashFunction = new IndexHashTable.HashFunction() {
+ @Override
+ public int getHash(int element) {
+ return element % 10; // A simple hash function for testing
+ }
+
+ @Override
+ public boolean equal(int element1, int element2) {
+ return element1 == element2;
+ }
+
+ @Override
+ public int getHash(Object elementDescriptor) {
+ return ((Integer) elementDescriptor) % 10;
+ }
+
+ @Override
+ public boolean equal(Object elementDescriptor, int element) {
+ return ((Integer) elementDescriptor) == element;
+ }
+ };
+
+ IndexHashTable hashTable = new IndexHashTable(10, hashFunction);
+
+ int element1 = 5;
+
+ int node1 = hashTable.addElement(element1);
+
+ hashTable.deleteElement(element1);
+ assertEquals(IndexHashTable.nullNode(), hashTable.findNode(element1));
+ }
+
+}
diff --git a/src/test/java/com/esri/core/geometry/TestIntersect2.java b/src/test/java/com/esri/core/geometry/TestIntersect2.java
index 36860635..0254dcb8 100644
--- a/src/test/java/com/esri/core/geometry/TestIntersect2.java
+++ b/src/test/java/com/esri/core/geometry/TestIntersect2.java
@@ -25,6 +25,7 @@
package com.esri.core.geometry;
import com.esri.core.geometry.Geometry.Type;
+import com.esri.core.geometry.ogc.OGCGeometry;
import junit.framework.TestCase;
import org.junit.Test;
@@ -39,6 +40,16 @@ protected void tearDown() throws Exception {
super.tearDown();
}
+ @Test
+ public void testIntersectsLinestringAndMultilinestring() {
+ // https://github.com/Esri/geometry-api-java/issues/326
+ OGCGeometry line = OGCGeometry.fromText("LINESTRING(1 0, 1 1)");
+ OGCGeometry multiLine = OGCGeometry.fromText("MULTILINESTRING((0 0, 0 1), (2 0, 2 1))");
+
+ assertFalse(line.intersects(multiLine));
+ assertFalse(multiLine.intersects(line));
+ }
+
@Test
/**
* Intersect
diff --git a/src/test/java/com/esri/core/geometry/TestJSONUtils.java b/src/test/java/com/esri/core/geometry/TestJSONUtils.java
new file mode 100644
index 00000000..86a29aff
--- /dev/null
+++ b/src/test/java/com/esri/core/geometry/TestJSONUtils.java
@@ -0,0 +1,47 @@
+package com.esri.core.geometry;
+
+import org.junit.Test;
+import junit.framework.TestCase;
+import org.mockito.Mockito;
+public class TestJSONUtils extends TestCase{
+
+ @Test
+ public void testReadDoubleWithFloatValue() {
+ JsonReader parser = Mockito.mock(JsonReader.class);
+ Mockito.when(parser.currentToken()).thenReturn(JsonReader.Token.VALUE_NUMBER_FLOAT);
+ Mockito.when(parser.currentDoubleValue()).thenReturn(3.14);
+
+ double result = JSONUtils.readDouble(parser);
+ assertEquals(3.14, result, 0.0001);
+ }
+
+ @Test
+ public void testReadDoubleWithIntValue() {
+ JsonReader parser = Mockito.mock(JsonReader.class);
+ Mockito.when(parser.currentToken()).thenReturn(JsonReader.Token.VALUE_NUMBER_INT);
+ Mockito.when(parser.currentIntValue()).thenReturn(42);
+
+ double result = JSONUtils.readDouble(parser);
+ assertEquals(42.0, result, 0.0001);
+ }
+
+ @Test
+ public void testReadDoubleWithNullValue() {
+ JsonReader parser = Mockito.mock(JsonReader.class);
+ Mockito.when(parser.currentToken()).thenReturn(JsonReader.Token.VALUE_NULL);
+
+ double result = JSONUtils.readDouble(parser);
+ assertTrue(Double.isNaN(result));
+ }
+
+ @Test
+ public void testReadDoubleWithNaNString() {
+ JsonReader parser = Mockito.mock(JsonReader.class);
+ Mockito.when(parser.currentToken()).thenReturn(JsonReader.Token.VALUE_STRING);
+ Mockito.when(parser.currentString()).thenReturn("NaN");
+
+ double result = JSONUtils.readDouble(parser);
+ assertTrue(Double.isNaN(result));
+ }
+
+}
diff --git a/src/test/java/com/esri/core/geometry/TestOGC.java b/src/test/java/com/esri/core/geometry/TestOGC.java
index ca2bcf6d..b68f2fcc 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.
@@ -35,7 +35,6 @@
import com.esri.core.geometry.ogc.OGCMultiPolygon;
import com.esri.core.geometry.ogc.OGCPoint;
import com.esri.core.geometry.ogc.OGCPolygon;
-import com.fasterxml.jackson.core.JsonParseException;
import com.esri.core.geometry.ogc.OGCConcreteGeometryCollection;
import org.junit.Test;
@@ -926,4 +925,135 @@ public void testPolylineSimplifyIssueGithub52() throws Exception {
}
}
+ @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);
+ }
+
+ @Test
+ public void testOGCUnionLinePoint() {
+ OGCGeometry point = OGCGeometry.fromText("POINT (-44.16176186699087 -19.943264803833348)");
+ OGCGeometry lineString = OGCGeometry.fromText(
+ "LINESTRING (-44.1247493 -19.9467657, -44.1247979 -19.9468385, -44.1249043 -19.946934, -44.1251096 -19.9470651, -44.1252609 -19.9471383, -44.1254992 -19.947204, -44.1257652 -19.947229, -44.1261292 -19.9471833, -44.1268946 -19.9470098, -44.1276847 -19.9468416, -44.127831 -19.9468143, -44.1282639 -19.9467366, -44.1284569 -19.9467237, -44.1287119 -19.9467261, -44.1289437 -19.9467665, -44.1291499 -19.9468221, -44.1293856 -19.9469396, -44.1298857 -19.9471497, -44.1300908 -19.9472071, -44.1302743 -19.9472331, -44.1305029 -19.9472364, -44.1306498 -19.9472275, -44.1308054 -19.947216, -44.1308553 -19.9472037, -44.1313206 -19.9471394, -44.1317889 -19.9470854, -44.1330422 -19.9468887, -44.1337465 -19.9467083, -44.1339922 -19.9466842, -44.1341506 -19.9466997, -44.1343621 -19.9467226, -44.1345134 -19.9467855, -44.1346494 -19.9468456, -44.1347295 -19.946881, -44.1347988 -19.9469299, -44.1350231 -19.9471131, -44.1355843 -19.9478307, -44.1357802 -19.9480557, -44.1366289 -19.949198, -44.1370384 -19.9497001, -44.137386 -19.9501921, -44.1374113 -19.9502263, -44.1380888 -19.9510925, -44.1381769 -19.9513526, -44.1382509 -19.9516202, -44.1383014 -19.9522136, -44.1383889 -19.9530931, -44.1384227 -19.9538784, -44.1384512 -19.9539653, -44.1384555 -19.9539807, -44.1384901 -19.9541928, -44.1385563 -19.9543859, -44.1386656 -19.9545781, -44.1387339 -19.9546889, -44.1389219 -19.9548661, -44.1391695 -19.9550384, -44.1393672 -19.9551414, -44.1397538 -19.9552208, -44.1401714 -19.9552332, -44.1405656 -19.9551143, -44.1406198 -19.9550853, -44.1407579 -19.9550224, -44.1409029 -19.9549201, -44.1410283 -19.9548257, -44.1413902 -19.9544132, -44.141835 -19.9539274, -44.142268 -19.953484, -44.1427036 -19.9531023, -44.1436229 -19.952259, -44.1437568 -19.9521565, -44.1441783 -19.9517273, -44.144644 -19.9512109, -44.1452538 -19.9505663, -44.1453541 -19.9504774, -44.1458653 -19.9500442, -44.1463563 -19.9496473, -44.1467534 -19.9492812, -44.1470553 -19.9490028, -44.1475804 -19.9485293, -44.1479838 -19.9482096, -44.1485003 -19.9478532, -44.1489451 -19.9477314, -44.1492225 -19.9477024, -44.149453 -19.9476684, -44.149694 -19.9476387, -44.1499556 -19.9475436, -44.1501398 -19.9474234, -44.1502723 -19.9473206, -44.150421 -19.9471473, -44.1505043 -19.9470004, -44.1507664 -19.9462594, -44.150867 -19.9459518, -44.1509225 -19.9457843, -44.1511168 -19.945466, -44.1513601 -19.9452272, -44.1516846 -19.944999, -44.15197 -19.9448738, -44.1525994 -19.9447263, -44.1536614 -19.9444791, -44.1544071 -19.9442671, -44.1548978 -19.9441275, -44.1556247 -19.9438304, -44.1565996 -19.9434083, -44.1570351 -19.9432556, -44.1573142 -19.9432091, -44.1575332 -19.9431645, -44.157931 -19.9431484, -44.1586408 -19.9431504, -44.1593575 -19.9431457, -44.1596498 -19.9431562, -44.1600991 -19.9431475, -44.1602331 -19.9431567, -44.1607926 -19.9432449, -44.1609723 -19.9432499, -44.1623815 -19.9432765, -44.1628299 -19.9433645, -44.1632475 -19.9435839, -44.1633456 -19.9436559, -44.1636261 -19.9439375, -44.1638186 -19.9442439, -44.1642535 -19.9451781, -44.165178 -19.947156, -44.1652928 -19.9474016, -44.1653074 -19.9474329, -44.1654026 -19.947766, -44.1654774 -19.9481718, -44.1655699 -19.9490241, -44.1656196 -19.9491538, -44.1659735 -19.9499097, -44.1662485 -19.9504925, -44.1662996 -19.9506347, -44.1663574 -19.9512961, -44.1664094 -19.9519273, -44.1664144 -19.9519881, -44.1664799 -19.9526399, -44.1666965 -19.9532586, -44.1671191 -19.9544126, -44.1672019 -19.9545869, -44.1673344 -19.9547603, -44.1675958 -19.9550466, -44.1692349 -19.9567775, -44.1694607 -19.9569284, -44.1718843 -19.9574147, -44.1719167 -19.9574206, -44.1721627 -19.9574748, -44.1723207 -19.9575386, -44.1724439 -19.9575883, -44.1742798 -19.9583293, -44.1748841 -19.9585688, -44.1751118 -19.9586796, -44.1752554 -19.9587769, -44.1752644 -19.9587881, -44.1756052 -19.9592143, -44.1766415 -19.9602689, -44.1774912 -19.9612387, -44.177663 -19.961364, -44.177856 -19.9614494, -44.178034 -19.9615125, -44.1782475 -19.9615423, -44.1785115 -19.9615155, -44.1795404 -19.9610879, -44.1796393 -19.9610759, -44.1798873 -19.9610459, -44.1802404 -19.961036, -44.1804714 -19.9609634, -44.181059 -19.9605365, -44.1815113 -19.9602333, -44.1826712 -19.9594067, -44.1829715 -19.9592551, -44.1837201 -19.9590611, -44.1839277 -19.9590073, -44.1853022 -19.9586512, -44.1856812 -19.9585316, -44.1862915 -19.9584212, -44.1866215 -19.9583494, -44.1867651 -19.9583391, -44.1868852 -19.9583372, -44.1872523 -19.9583313, -44.187823 -19.9583281, -44.1884457 -19.958351, -44.1889559 -19.958437, -44.1893825 -19.9585816, -44.1897582 -19.9587828, -44.1901186 -19.9590453, -44.1912457 -19.9602029, -44.1916575 -19.9606307, -44.1921624 -19.9611588, -44.1925367 -19.9615872, -44.1931832 -19.9622566, -44.1938468 -19.9629343, -44.194089 -19.9631996, -44.1943924 -19.9634141, -44.1946006 -19.9635104, -44.1948789 -19.963599, -44.1957402 -19.9637569, -44.1964094 -19.9638505, -44.1965875 -19.9639188, -44.1967865 -19.9640801, -44.197096 -19.9643572, -44.1972765 -19.964458, -44.1974407 -19.9644824, -44.1976234 -19.9644668, -44.1977654 -19.9644282, -44.1980715 -19.96417, -44.1984541 -19.9638069, -44.1986632 -19.9636002, -44.1988132 -19.9634172, -44.1989542 -19.9632962, -44.1991349 -19.9631081)");
+ OGCGeometry result12 = point.union(lineString);
+ String text12 = result12.asText();
+ assertEquals(text12, "LINESTRING (-44.1247493 -19.9467657, -44.1247979 -19.9468385, -44.1249043 -19.946934, -44.1251096 -19.9470651, -44.1252609 -19.9471383, -44.1254992 -19.947204, -44.1257652 -19.947229, -44.1261292 -19.9471833, -44.1268946 -19.9470098, -44.1276847 -19.9468416, -44.127831 -19.9468143, -44.1282639 -19.9467366, -44.1284569 -19.9467237, -44.1287119 -19.9467261, -44.1289437 -19.9467665, -44.1291499 -19.9468221, -44.1293856 -19.9469396, -44.1298857 -19.9471497, -44.1300908 -19.9472071, -44.1302743 -19.9472331, -44.1305029 -19.9472364, -44.1306498 -19.9472275, -44.1308054 -19.947216, -44.1308553 -19.9472037, -44.1313206 -19.9471394, -44.1317889 -19.9470854, -44.1330422 -19.9468887, -44.1337465 -19.9467083, -44.1339922 -19.9466842, -44.1341506 -19.9466997, -44.1343621 -19.9467226, -44.1345134 -19.9467855, -44.1346494 -19.9468456, -44.1347295 -19.946881, -44.1347988 -19.9469299, -44.1350231 -19.9471131, -44.1355843 -19.9478307, -44.1357802 -19.9480557, -44.1366289 -19.949198, -44.1370384 -19.9497001, -44.137386 -19.9501921, -44.1374113 -19.9502263, -44.1380888 -19.9510925, -44.1381769 -19.9513526, -44.1382509 -19.9516202, -44.1383014 -19.9522136, -44.1383889 -19.9530931, -44.1384227 -19.9538784, -44.1384512 -19.9539653, -44.1384555 -19.9539807, -44.1384901 -19.9541928, -44.1385563 -19.9543859, -44.1386656 -19.9545781, -44.1387339 -19.9546889, -44.1389219 -19.9548661, -44.1391695 -19.9550384, -44.1393672 -19.9551414, -44.1397538 -19.9552208, -44.1401714 -19.9552332, -44.1405656 -19.9551143, -44.1406198 -19.9550853, -44.1407579 -19.9550224, -44.1409029 -19.9549201, -44.1410283 -19.9548257, -44.1413902 -19.9544132, -44.141835 -19.9539274, -44.142268 -19.953484, -44.1427036 -19.9531023, -44.1436229 -19.952259, -44.1437568 -19.9521565, -44.1441783 -19.9517273, -44.144644 -19.9512109, -44.1452538 -19.9505663, -44.1453541 -19.9504774, -44.1458653 -19.9500442, -44.1463563 -19.9496473, -44.1467534 -19.9492812, -44.1470553 -19.9490028, -44.1475804 -19.9485293, -44.1479838 -19.9482096, -44.1485003 -19.9478532, -44.1489451 -19.9477314, -44.1492225 -19.9477024, -44.149453 -19.9476684, -44.149694 -19.9476387, -44.1499556 -19.9475436, -44.1501398 -19.9474234, -44.1502723 -19.9473206, -44.150421 -19.9471473, -44.1505043 -19.9470004, -44.1507664 -19.9462594, -44.150867 -19.9459518, -44.1509225 -19.9457843, -44.1511168 -19.945466, -44.1513601 -19.9452272, -44.1516846 -19.944999, -44.15197 -19.9448738, -44.1525994 -19.9447263, -44.1536614 -19.9444791, -44.1544071 -19.9442671, -44.1548978 -19.9441275, -44.1556247 -19.9438304, -44.1565996 -19.9434083, -44.1570351 -19.9432556, -44.1573142 -19.9432091, -44.1575332 -19.9431645, -44.157931 -19.9431484, -44.1586408 -19.9431504, -44.1593575 -19.9431457, -44.1596498 -19.9431562, -44.1600991 -19.9431475, -44.1602331 -19.9431567, -44.1607926 -19.9432449, -44.1609723 -19.9432499, -44.16176186699087 -19.94326480383335, -44.1623815 -19.9432765, -44.1628299 -19.9433645, -44.1632475 -19.9435839, -44.1633456 -19.9436559, -44.1636261 -19.9439375, -44.1638186 -19.9442439, -44.1642535 -19.9451781, -44.165178 -19.947156, -44.1652928 -19.9474016, -44.1653074 -19.9474329, -44.1654026 -19.947766, -44.1654774 -19.9481718, -44.1655699 -19.9490241, -44.1656196 -19.9491538, -44.1659735 -19.9499097, -44.1662485 -19.9504925, -44.1662996 -19.9506347, -44.1663574 -19.9512961, -44.1664094 -19.9519273, -44.1664144 -19.9519881, -44.1664799 -19.9526399, -44.1666965 -19.9532586, -44.1671191 -19.9544126, -44.1672019 -19.9545869, -44.1673344 -19.9547603, -44.1675958 -19.9550466, -44.1692349 -19.9567775, -44.1694607 -19.9569284, -44.1718843 -19.9574147, -44.1719167 -19.9574206, -44.1721627 -19.9574748, -44.1723207 -19.9575386, -44.1724439 -19.9575883, -44.1742798 -19.9583293, -44.1748841 -19.9585688, -44.1751118 -19.9586796, -44.1752554 -19.9587769, -44.1752644 -19.9587881, -44.1756052 -19.9592143, -44.1766415 -19.9602689, -44.1774912 -19.9612387, -44.177663 -19.961364, -44.177856 -19.9614494, -44.178034 -19.9615125, -44.1782475 -19.9615423, -44.1785115 -19.9615155, -44.1795404 -19.9610879, -44.1796393 -19.9610759, -44.1798873 -19.9610459, -44.1802404 -19.961036, -44.1804714 -19.9609634, -44.181059 -19.9605365, -44.1815113 -19.9602333, -44.1826712 -19.9594067, -44.1829715 -19.9592551, -44.1837201 -19.9590611, -44.1839277 -19.9590073, -44.1853022 -19.9586512, -44.1856812 -19.9585316, -44.1862915 -19.9584212, -44.1866215 -19.9583494, -44.1867651 -19.9583391, -44.1868852 -19.9583372, -44.1872523 -19.9583313, -44.187823 -19.9583281, -44.1884457 -19.958351, -44.1889559 -19.958437, -44.1893825 -19.9585816, -44.1897582 -19.9587828, -44.1901186 -19.9590453, -44.1912457 -19.9602029, -44.1916575 -19.9606307, -44.1921624 -19.9611588, -44.1925367 -19.9615872, -44.1931832 -19.9622566, -44.1938468 -19.9629343, -44.194089 -19.9631996, -44.1943924 -19.9634141, -44.1946006 -19.9635104, -44.1948789 -19.963599, -44.1957402 -19.9637569, -44.1964094 -19.9638505, -44.1965875 -19.9639188, -44.1967865 -19.9640801, -44.197096 -19.9643572, -44.1972765 -19.964458, -44.1974407 -19.9644824, -44.1976234 -19.9644668, -44.1977654 -19.9644282, -44.1980715 -19.96417, -44.1984541 -19.9638069, -44.1986632 -19.9636002, -44.1988132 -19.9634172, -44.1989542 -19.9632962, -44.1991349 -19.9631081)");
+ }
+
}
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/TestPoint.java b/src/test/java/com/esri/core/geometry/TestPoint.java
index c2e8bd2f..c30f612f 100644
--- a/src/test/java/com/esri/core/geometry/TestPoint.java
+++ b/src/test/java/com/esri/core/geometry/TestPoint.java
@@ -45,9 +45,35 @@ protected void tearDown() throws Exception {
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();
}
diff --git a/src/test/java/com/esri/core/geometry/TestSerialization.java b/src/test/java/com/esri/core/geometry/TestSerialization.java
index 8cdb4ad9..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.
@@ -26,7 +26,6 @@
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
-import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
@@ -401,4 +400,97 @@ public void testSerializeEnvelope2D() {
}
}
+ 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/TestUnion.java b/src/test/java/com/esri/core/geometry/TestUnion.java
index 55392e39..77032413 100644
--- a/src/test/java/com/esri/core/geometry/TestUnion.java
+++ b/src/test/java/com/esri/core/geometry/TestUnion.java
@@ -40,11 +40,6 @@ protected void tearDown() throws Exception {
@Test
public static 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 };
@@ -57,5 +52,129 @@ public static void testUnion() {
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));
}
}
diff --git a/src/test/java/com/esri/core/geometry/TestWKBSupport.java b/src/test/java/com/esri/core/geometry/TestWKBSupport.java
index a55252fb..dfbaba16 100644
--- a/src/test/java/com/esri/core/geometry/TestWKBSupport.java
+++ b/src/test/java/com/esri/core/geometry/TestWKBSupport.java
@@ -24,6 +24,7 @@
package com.esri.core.geometry;
+import com.esri.core.geometry.ogc.OGCGeometry;
import java.io.IOException;
import java.nio.ByteBuffer;
import junit.framework.TestCase;
@@ -107,4 +108,12 @@ public void testWKB2() throws Exception {
}
+ @Test
+ public void testWKB3() throws Exception {
+ String multiPointWKT = "MULTIPOINT ZM(10 40 1 23, 40 30 2 45)";
+ OGCGeometry geometry = OGCGeometry.fromText(multiPointWKT);
+ ByteBuffer byteBuffer = geometry.asBinary();
+ OGCGeometry geomFromBinary = OGCGeometry.fromBinary(byteBuffer);
+ assertTrue(geometry.Equals(geomFromBinary));
+ }
}