Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stolstov/collection methods #178

Merged
merged 19 commits into from
Jun 21, 2018
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
a few fixes, added intersection and difference for collections
  • Loading branch information
satol committed May 30, 2018
commit 0618e303c9e3958c3dac68eb38706d6b664a2f9a
5 changes: 0 additions & 5 deletions src/main/java/com/esri/core/geometry/OGCStructure.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,8 @@
*/
package com.esri.core.geometry;

import java.util.ArrayList;
import java.util.List;

import com.esri.core.geometry.ogc.OGCConcreteGeometryCollection;
import com.esri.core.geometry.ogc.OGCGeometry;
import com.esri.core.geometry.ogc.OGCGeometryCollection;

public class OGCStructure {
public int m_type;
public List<OGCStructure> m_structures;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,6 @@
*/
package com.esri.core.geometry;

import java.util.ArrayList;
import java.util.List;

import com.esri.core.geometry.ogc.OGCConcreteGeometryCollection;
import com.esri.core.geometry.ogc.OGCGeometry;
import com.esri.core.geometry.ogc.OGCGeometryCollection;

//An internal helper class. Do not use.
public class OGCStructureInternal {
private static class EditShapeCursor extends GeometryCursor {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,11 @@ public OGCConcreteGeometryCollection(OGCGeometry geom, SpatialReference sr) {
esriSR = sr;
}

public OGCConcreteGeometryCollection(SpatialReference sr) {
geometries = new ArrayList<OGCGeometry>();
esriSR = sr;
}

@Override
public int dimension() {
int maxD = 0;
Expand Down Expand Up @@ -356,7 +361,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<OGCGeometry> m_geoms;
Expand Down Expand Up @@ -522,6 +527,9 @@ public int hashCode() {

@Override
public double distance(OGCGeometry another) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like this method returns 0 if another is an empty geometry. Is this correct? Should it throw or return -1 to distinguish between the case when another and this overlap vs. another is empty?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Distance returns NaN for empty input. I'll fix this for collection.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

if (this == another)
return isEmpty() ? Double.NaN : 0;

double minD = Double.NaN;
for (int i = 0, n = numGeometries(); i < n; ++i) {
double d = geometryN(i).distance(another);
Expand All @@ -535,6 +543,8 @@ public double distance(OGCGeometry another) {

return minD;
}

//
//Relational operations
@Override
public boolean disjoint(OGCGeometry another) {
Expand Down Expand Up @@ -569,7 +579,8 @@ public boolean disjoint(OGCGeometry another) {
@Override
public boolean contains(OGCGeometry another) {
if (isEmpty() || another.isEmpty())
return true;
return false;

if (this == another)
return false;

Expand Down Expand Up @@ -601,7 +612,79 @@ public boolean contains(OGCGeometry another) {
//each geometry of another is contained in a geometry from this.
return true;
}

//Topological
@Override
public OGCGeometry difference(OGCGeometry another) {
List<OGCConcreteGeometryCollection> list = wrapGeomsIntoList_(this, another);
list = prepare_for_ops_(list);
if (list.size() != 2) // this should not happen
throw new GeometryException("internal error");

List<OGCGeometry> result = new ArrayList<OGCGeometry>();
OGCConcreteGeometryCollection coll1 = list.get(0);
OGCConcreteGeometryCollection coll2 = list.get(1);
for (int i = 0, n = coll1.numGeometries(); i < n; ++i) {
OGCGeometry cur = coll1.geometryN(i);
for (int j = 0, n2 = coll2.numGeometries(); j < n2; ++j) {
OGCGeometry geom2 = coll2.geometryN(j);
if (cur.dimension() > geom2.dimension())
continue; //subtracting lower dimension has no effect.

cur = cur.difference(geom2);
if (cur.isEmpty())
break;
}

if (cur.isEmpty())
continue;

result.add(cur);
}

return new OGCConcreteGeometryCollection(result, esriSR);
}

@Override
public OGCGeometry intersection(OGCGeometry another) {
List<OGCConcreteGeometryCollection> list = wrapGeomsIntoList_(this, another);
list = prepare_for_ops_(list);
if (list.size() != 2) // this should not happen
throw new GeometryException("internal error");

List<OGCGeometry> result = new ArrayList<OGCGeometry>();
OGCConcreteGeometryCollection coll1 = list.get(0);
OGCConcreteGeometryCollection coll2 = list.get(1);
for (int i = 0, n = coll1.numGeometries(); i < n; ++i) {
OGCGeometry cur = coll1.geometryN(i);
for (int j = 0, n2 = coll2.numGeometries(); j < n2; ++j) {
OGCGeometry geom2 = coll2.geometryN(j);

OGCGeometry partialIntersection = cur.intersection(geom2);
if (partialIntersection.isEmpty())
continue;

result.add(partialIntersection);
}
}

return (new OGCConcreteGeometryCollection(result, esriSR)).flattenAndRemoveOverlaps();
}

//make a list of collections out of two geometries
private static List<OGCConcreteGeometryCollection> wrapGeomsIntoList_(OGCGeometry g1, OGCGeometry g2) {
List<OGCConcreteGeometryCollection> list = new ArrayList<OGCConcreteGeometryCollection>();
if (g1.geometryType() != OGCConcreteGeometryCollection.TYPE) {
g1 = new OGCConcreteGeometryCollection(g1, g1.getEsriSpatialReference());
}
if (g2.geometryType() != OGCConcreteGeometryCollection.TYPE) {
g2 = new OGCConcreteGeometryCollection(g2, g2.getEsriSpatialReference());
}

list.add((OGCConcreteGeometryCollection)g1);
list.add((OGCConcreteGeometryCollection)g2);

return list;
}
/**
* Checks if collection is flattened.
* @return True for the flattened collection. A flattened collection contains up to three non-empty geometries:
Expand Down Expand Up @@ -636,7 +719,7 @@ public boolean isFlattened() {
/**
* Flattens Geometry Collection.
* The result collection contains up to three geometries:
* an OGCMultiPoint, an OGCMultiPolygon, and an OGCMultilineString.
* an OGCMultiPoint, an OGCMultilineString, and an OGCMultiPolygon (in that order).
* @return A flattened Geometry Collection, or self if already flattened.
*/
public OGCConcreteGeometryCollection flatten() {
Expand Down Expand Up @@ -804,17 +887,23 @@ private List<OGCConcreteGeometryCollection> prepare_for_ops_(List<OGCConcreteGeo
assert(geoms != null && !geoms.isEmpty());
GeometryCursor prepared = OGCStructureInternal.prepare_for_ops_(new FlatteningCollectionCursor(geoms), esriSR);

ArrayList<OGCConcreteGeometryCollection> result = new ArrayList<OGCConcreteGeometryCollection>();
List<OGCConcreteGeometryCollection> result = new ArrayList<OGCConcreteGeometryCollection>();
int prevCollectionIndex = -1;
ArrayList<Geometry> list = null;
List<Geometry> list = null;
for (Geometry g = prepared.next(); g != null; g = prepared.next()) {
int c = prepared.getGeometryID();
if (c != prevCollectionIndex) {
//add empty collections for all skipped indices
for (int i = prevCollectionIndex; i < c - 1; i++) {
result.add(new OGCConcreteGeometryCollection(esriSR));
}

if (list != null) {
result.add(removeOverlapsHelper_(list));
}

list = new ArrayList<Geometry>();
prevCollectionIndex = c;
}

list.add(g);
Expand Down
13 changes: 12 additions & 1 deletion src/main/java/com/esri/core/geometry/ogc/OGCGeometry.java
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ public boolean isMeasured() {
*/
public boolean Equals(OGCGeometry another) {
if (this == another)
return true;
return true; //should return false for empty

if (another == null)
return false;
Expand Down Expand Up @@ -333,6 +333,9 @@ 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) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't the same logic apply to other methods, e.g. contains, overlaps, etc.?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes most need to be changed eventually.

return another.distance(this);
}
Expand Down Expand Up @@ -456,6 +459,10 @@ public OGCGeometry convexHull() {
}

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(
Expand Down Expand Up @@ -487,6 +494,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(
Expand Down
12 changes: 12 additions & 0 deletions src/test/java/com/esri/core/geometry/TestOGC.java
Original file line number Diff line number Diff line change
Expand Up @@ -983,6 +983,18 @@ public void testUnionGeometryCollectionWithGeometryCollection() {
"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());
Expand Down