Skip to content

Commit 7b94886

Browse files
committed
Merge pull request #17 from stolstov/geojson
Fix export to multilinestring
2 parents e8b83e8 + 4063920 commit 7b94886

14 files changed

Lines changed: 220 additions & 176 deletions
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/*
2+
Copyright 1995-2013 Esri
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
16+
For additional information, contact:
17+
Environmental Systems Research Institute, Inc.
18+
Attn: Contracts Dept
19+
380 New York Street
20+
Redlands, California, USA 92373
21+
22+
email: contracts@esri.com
23+
*/
24+
package com.esri.core.geometry;
25+
26+
public interface GeoJsonExportFlags {
27+
static final int geoJsonExportDefaults = 0;
28+
static final int geoJsonExportPreferMultiGeometry = 1;
29+
}

src/com/esri/core/geometry/GeometryEngine.java

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,7 @@ public class GeometryEngine {
3737

3838
private static OperatorFactoryLocal factory = OperatorFactoryLocal
3939
.getInstance();
40-
41-
42-
40+
4341
/**
4442
* Imports the MapGeometry from its JSON representation. M and Z values are
4543
* not imported from JSON representation.
@@ -600,8 +598,7 @@ public static Geometry[] cut(Geometry cuttee, Polyline cutter,
600598

601599
return cutsList.toArray(new Geometry[0]);
602600
}
603-
604-
601+
605602
/**
606603
* Calculates a buffer polygon for each geometry at each of the
607604
* corresponding specified distances. It is assumed that all geometries have
@@ -644,8 +641,7 @@ public static Polygon[] buffer(Geometry[] geometries,
644641
return buffers;
645642
}
646643
}
647-
648-
644+
649645
/**
650646
* Calculates a buffer polygon of the geometry as specified by the
651647
* distance input. The buffer is implemented in the xy-plane.
@@ -818,8 +814,7 @@ static boolean isSimple(Geometry geometry, SpatialReference spatialReference) {
818814
boolean result = op.isSimpleAsFeature(geometry, spatialReference, null);
819815
return result;
820816
}
821-
822-
817+
823818
/**
824819
* A geodesic distance is the shortest distance between any two points on the earth's surface when the earth's
825820
* surface is approximated by a spheroid. The function returns the shortest distance between two points on the

src/com/esri/core/geometry/MultiPathImpl.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2186,9 +2186,11 @@ protected void _updateOGCFlags() {
21862186
m_pathFlags = (AttributeStreamOfInt8) AttributeStreamBase
21872187
.createByteStream(pathCount + 1);
21882188

2189+
int firstSign = 1;
21892190
for (int ipath = 0; ipath < pathCount; ipath++) {
21902191
double area = m_cachedRingAreas2D.read(ipath);
2191-
if (area > 0.0)
2192+
if (ipath == 0) firstSign = area > 0 ? 1 : -1;
2193+
if (area * firstSign > 0.0)
21922194
m_pathFlags.setBits(ipath,
21932195
(byte) PathFlags.enumOGCStartPolygon);
21942196
else

src/com/esri/core/geometry/OperatorExportToGeoJson.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@
2424

2525
import com.esri.core.geometry.Operator.Type;
2626

27+
/**
28+
*Export to GeoJson format.
29+
*/
2730
public abstract class OperatorExportToGeoJson extends Operator {
2831
@Override
2932
public Type getType() {
@@ -34,6 +37,8 @@ public Type getType() {
3437

3538
public abstract String execute(SpatialReference spatialReference, Geometry geometry);
3639

40+
public abstract String execute(int exportFlags, SpatialReference spatialReference, Geometry geometry);
41+
3742
public abstract String execute(Geometry geometry);
3843

3944
public static OperatorExportToGeoJson local() {

src/com/esri/core/geometry/OperatorExportToGeoJsonCursor.java

Lines changed: 61 additions & 142 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,11 @@ class OperatorExportToGeoJsonCursor extends JsonCursor {
3535
int m_wkid = -1;
3636
int m_latest_wkid = -1;
3737
String m_wkt = null;
38+
boolean m_preferMulti = false;
3839

3940
private static JsonFactory factory = new JsonFactory();
4041

41-
public OperatorExportToGeoJsonCursor(SpatialReference spatialReference, GeometryCursor geometryCursor) {
42+
public OperatorExportToGeoJsonCursor(boolean preferMulti, SpatialReference spatialReference, GeometryCursor geometryCursor) {
4243
m_index = -1;
4344
if (geometryCursor == null)
4445
throw new IllegalArgumentException();
@@ -48,6 +49,7 @@ public OperatorExportToGeoJsonCursor(SpatialReference spatialReference, Geometry
4849
m_latest_wkid = spatialReference.getLatestID();
4950
}
5051
m_inputGeometryCursor = geometryCursor;
52+
m_preferMulti = preferMulti;
5153
}
5254

5355
public OperatorExportToGeoJsonCursor(GeometryCursor geometryCursor) {
@@ -90,10 +92,10 @@ private String exportToGeoJson(Geometry geometry) {
9092
exportMultiPointToGeoJson(g, (MultiPoint) geometry);
9193
break;
9294
case Geometry.GeometryType.Polyline:
93-
exportPolylineToGeoJson(g, (Polyline) geometry);
95+
exportMultiPathToGeoJson(g, (Polyline) geometry);
9496
break;
9597
case Geometry.GeometryType.Polygon:
96-
exportPolygonToGeoJson(g, (Polygon) geometry);
98+
exportMultiPathToGeoJson(g, (Polygon) geometry);
9799
break;
98100
case Geometry.GeometryType.Envelope:
99101
exportEnvelopeToGeoJson(g, (Envelope) geometry);
@@ -110,6 +112,13 @@ private String exportToGeoJson(Geometry geometry) {
110112
}
111113

112114
private void exportPointToGeoJson(JsonGenerator g, Point p) throws JsonGenerationException, IOException {
115+
if (m_preferMulti) {
116+
MultiPoint mp = new MultiPoint();
117+
mp.add(p);
118+
exportMultiPointToGeoJson(g, mp);
119+
return;
120+
}
121+
113122
g.writeStartObject();
114123

115124
g.writeFieldName("type");
@@ -176,118 +185,85 @@ private void exportMultiPointToGeoJson(JsonGenerator g, MultiPoint mp) throws Js
176185
g.close();
177186
}
178187

179-
private void exportPolylineToGeoJson(JsonGenerator g, Polyline p) throws JsonGenerationException, IOException {
180-
g.writeStartObject();
181-
182-
g.writeFieldName("type");
183-
g.writeString("LineString");
184-
185-
g.writeFieldName("coordinates");
186-
187-
if (p.isEmpty()) {
188-
g.writeNull();
189-
} else {
190-
g.writeStartArray();
191-
exportPathToGeoJson(g, p);
192-
g.writeEndArray();
193-
}
194-
195-
g.writeEndObject();
196-
g.close();
197-
}
198-
199-
private void exportPolygonToGeoJson(JsonGenerator g, Polygon p) throws JsonGenerationException, IOException {
188+
private void exportMultiPathToGeoJson(JsonGenerator g, MultiPath p) throws JsonGenerationException, IOException {
200189
MultiPathImpl pImpl = (MultiPathImpl) p._getImpl();
201190

202-
//int pointCount = pImpl.getPointCount();
203-
int polyCount = pImpl.getOGCPolygonCount();
191+
boolean isPolygon = pImpl.m_bPolygon;
192+
int polyCount = isPolygon ? pImpl.getOGCPolygonCount() : 0;
204193

205194
// check yo' polys playa
206195

207196
g.writeStartObject();
208197

209198
g.writeFieldName("type");
210199

211-
if (polyCount >= 2) { // single polys seem to have a polyCount of 0, multi polys seem to be >= 2
212-
g.writeString("MultiPolygon");
213-
} else {
214-
g.writeString("Polygon");
200+
boolean bCollection = false;
201+
if (isPolygon) {
202+
if (polyCount >= 2 || m_preferMulti) { // single polys seem to have a polyCount of 0, multi polys seem to be >= 2
203+
g.writeString("MultiPolygon");
204+
bCollection = true;
205+
} else {
206+
g.writeString("Polygon");
207+
}
208+
}
209+
else {
210+
if (p.getPathCount() > 1 || m_preferMulti) { // single polys seem to have a polyCount of 0, multi polys seem to be >= 2
211+
g.writeString("MultiLineString");
212+
bCollection = true;
213+
} else {
214+
g.writeString("LineString");
215+
}
215216
}
216217

217218
g.writeFieldName("coordinates");
218219

219220
if (p.isEmpty()) {
220221
g.writeNull();
221222
} else {
222-
g.writeStartArray();
223-
224-
if (polyCount >= 2) {
225-
g.writeStartArray();
226-
exportMultiPolygonToGeoJson(g, p, pImpl);
227-
g.writeEndArray();
228-
} else {
229-
exportPathToGeoJson(g, p);
230-
}
231-
232-
g.writeEndArray();
223+
exportMultiPathToGeoJson(g, pImpl, bCollection);
233224
}
234225

235226
g.writeEndObject();
236227
g.close();
237228
}
238229

239-
private void exportMultiPolygonToGeoJson(JsonGenerator g, Polygon p, MultiPathImpl pImpl) throws IOException {
230+
private void exportMultiPathToGeoJson(JsonGenerator g, MultiPathImpl pImpl, boolean bCollection) throws IOException {
240231
int startIndex;
241232
int vertices;
242233

234+
if (bCollection)
235+
g.writeStartArray();
236+
243237
//AttributeStreamOfDbl position = (AttributeStreamOfDbl) pImpl.getAttributeStreamRef(VertexDescription.Semantics.POSITION);
244238
//AttributeStreamOfInt8 pathFlags = pImpl.getPathFlagsStreamRef();
245239
//AttributeStreamOfInt32 paths = pImpl.getPathStreamRef();
246240
int pathCount = pImpl.getPathCount();
241+
boolean isPolygon = pImpl.m_bPolygon;
242+
AttributeStreamOfDbl zs = pImpl.hasAttribute(Semantics.Z) ? (AttributeStreamOfDbl) pImpl.getAttributeStreamRef(Semantics.Z) : null;
243+
244+
for (int path = 0; path < pathCount; path++) {
245+
startIndex = pImpl.getPathStart(path);
246+
vertices = pImpl.getPathSize(path);
247+
248+
boolean isExtRing = isPolygon && pImpl.isExteriorRing(path);
249+
if (isExtRing) {//only for polygons
250+
if (path > 0)
251+
g.writeEndArray();//end of OGC polygon
252+
253+
g.writeStartArray();//start of next OGC polygon
254+
}
247255

248-
AttributeStreamOfDbl zs = p.hasAttribute(Semantics.Z) ? (AttributeStreamOfDbl) pImpl.getAttributeStreamRef(Semantics.Z) : null;
249-
250-
Point2D pt = new Point2D();
251-
252-
g.writeStartArray();
253-
254-
startIndex = p.getPathStart(0);
255-
vertices = p.getPathSize(0);
256-
257-
for (int i = startIndex; i < startIndex + vertices; i++) {
258-
p.getXY(i, pt);
259-
g.writeStartArray();
260-
writeDouble(pt.x, g);
261-
writeDouble(pt.y, g);
262-
263-
if (zs != null)
264-
writeDouble(zs.get(i), g);
265-
266-
g.writeEndArray();
267-
}
268-
269-
p.getXY(startIndex, pt);
270-
g.writeStartArray();
271-
writeDouble(pt.x, g);
272-
writeDouble(pt.y, g);
273-
274-
if (zs != null)
275-
writeDouble(zs.get(startIndex), g);
276-
277-
g.writeEndArray();
278-
279-
g.writeEndArray();
280-
281-
for (int path = 1; path < pathCount; path++) {
282-
boolean isExtRing = p.isExteriorRing(path);
283-
startIndex = p.getPathStart(path);
284-
vertices = p.getPathSize(path);
285-
286-
writePath(p, g, startIndex, vertices, zs, isExtRing);
256+
writePath(pImpl, g, path, startIndex, vertices, zs);
287257
}
258+
259+
if (isPolygon)
260+
g.writeEndArray();//end of last OGC polygon
261+
262+
if (bCollection)
263+
g.writeEndArray();
288264
}
289265

290-
private void closePolygon(MultiPath mp, JsonGenerator g, int startIndex, AttributeStreamOfDbl zs) throws IOException {
266+
private void closePath(MultiPathImpl mp, JsonGenerator g, int startIndex, AttributeStreamOfDbl zs) throws IOException {
291267
Point2D pt = new Point2D();
292268

293269
// close ring
@@ -302,16 +278,9 @@ private void closePolygon(MultiPath mp, JsonGenerator g, int startIndex, Attribu
302278
g.writeEndArray();
303279
}
304280

305-
private void writePath(MultiPath mp, JsonGenerator g, int startIndex, int vertices, AttributeStreamOfDbl zs, boolean isExtRing) throws IOException {
281+
private void writePath(MultiPathImpl mp, JsonGenerator g, int pathIndex, int startIndex, int vertices, AttributeStreamOfDbl zs) throws IOException {
306282
Point2D pt = new Point2D();
307283

308-
boolean isPoly = mp instanceof Polygon;
309-
310-
if (isPoly && isExtRing) {
311-
g.writeEndArray();
312-
g.writeStartArray();
313-
}
314-
315284
g.writeStartArray();
316285

317286
for (int i = startIndex; i < startIndex + vertices; i++) {
@@ -326,62 +295,12 @@ private void writePath(MultiPath mp, JsonGenerator g, int startIndex, int vertic
326295
g.writeEndArray();
327296
}
328297

329-
if (isPoly)
330-
closePolygon(mp, g, startIndex, zs);
298+
if (mp.isClosedPath(pathIndex))
299+
closePath(mp, g, startIndex, zs);
331300

332301
g.writeEndArray();
333302
}
334303

335-
private void exportPathToGeoJson(JsonGenerator g, MultiPath mp) throws JsonGenerationException, IOException {
336-
boolean isPoly = mp instanceof Polygon;
337-
338-
MultiPathImpl mpImpl = (MultiPathImpl) mp._getImpl();
339-
AttributeStreamOfDbl zs = mp.hasAttribute(Semantics.Z) ? (AttributeStreamOfDbl) mpImpl.getAttributeStreamRef(Semantics.Z) : null;
340-
341-
Point2D p = new Point2D();
342-
343-
int n = mp.getPathCount();
344-
345-
for (int i = 0; i < n; i++) {
346-
if (isPoly)
347-
g.writeStartArray();
348-
349-
int startIndex = mp.getPathStart(i);
350-
int vertices = mp.getPathSize(i);
351-
352-
for (int j = startIndex; j < startIndex + vertices; j++) {
353-
mp.getXY(j, p);
354-
355-
g.writeStartArray();
356-
357-
writeDouble(p.x, g);
358-
writeDouble(p.y, g);
359-
360-
if (zs != null)
361-
writeDouble(zs.get(j), g);
362-
363-
g.writeEndArray();
364-
}
365-
366-
if (isPoly) {
367-
mp.getXY(startIndex, p);
368-
369-
g.writeStartArray();
370-
371-
writeDouble(p.x, g);
372-
writeDouble(p.y, g);
373-
374-
if (zs != null)
375-
writeDouble(zs.get(startIndex), g);
376-
377-
g.writeEndArray();
378-
}
379-
380-
if (isPoly)
381-
g.writeEndArray();
382-
}
383-
}
384-
385304
private void exportEnvelopeToGeoJson(JsonGenerator g, Envelope e) throws JsonGenerationException, IOException {
386305
boolean empty = e.isEmpty();
387306

0 commit comments

Comments
 (0)