24
24
import java .util .List ;
25
25
import java .util .Map ;
26
26
27
- import com .vividsolutions .jts .geom .Point ;
28
- import vector_tile .VectorTile ;
29
-
30
27
import com .vividsolutions .jts .algorithm .CGAlgorithms ;
31
28
import com .vividsolutions .jts .geom .Coordinate ;
32
29
import com .vividsolutions .jts .geom .Geometry ;
33
- import com .vividsolutions .jts .geom .GeometryCollection ;
34
30
import com .vividsolutions .jts .geom .GeometryFactory ;
35
31
import com .vividsolutions .jts .geom .LineString ;
36
32
import com .vividsolutions .jts .geom .LinearRing ;
37
33
import com .vividsolutions .jts .geom .MultiLineString ;
38
34
import com .vividsolutions .jts .geom .MultiPoint ;
39
35
import com .vividsolutions .jts .geom .MultiPolygon ;
36
+ import com .vividsolutions .jts .geom .Point ;
40
37
import com .vividsolutions .jts .geom .Polygon ;
41
38
import com .vividsolutions .jts .geom .TopologyException ;
42
39
import com .vividsolutions .jts .io .ParseException ;
43
40
import com .vividsolutions .jts .io .WKTReader ;
44
41
42
+ import vector_tile .VectorTile ;
43
+
45
44
public class VectorTileEncoder {
46
45
47
46
private final Map <String , Layer > layers = new LinkedHashMap <String , Layer >();
@@ -136,13 +135,11 @@ public void addFeature(String layerName, Map<String, ?> attributes, Geometry geo
136
135
* @param id
137
136
*/
138
137
public void addFeature (String layerName , Map <String , ?> attributes , Geometry geometry , long id ) {
139
- // split up MultiPolygon and GeometryCollection (without subclasses)
140
- if ( geometry instanceof MultiPolygon || geometry . getClass (). equals ( GeometryCollection . class )) {
141
- splitAndAddFeatures ( layerName , attributes , ( GeometryCollection ) geometry );
138
+
139
+ // skip small Polygon/LineString.
140
+ if ( geometry instanceof MultiPolygon && geometry . getArea () < 1.0d ) {
142
141
return ;
143
142
}
144
-
145
- // skip small Polygon/LineString.
146
143
if (geometry instanceof Polygon && geometry .getArea () < 1.0d ) {
147
144
return ;
148
145
}
@@ -159,12 +156,6 @@ public void addFeature(String layerName, Map<String, ?> attributes, Geometry geo
159
156
geometry = clipGeometry (geometry );
160
157
}
161
158
162
- // if clipping result in MultiPolygon, then split once more
163
- if (geometry instanceof MultiPolygon || geometry .getClass ().equals (GeometryCollection .class )) {
164
- splitAndAddFeatures (layerName , attributes , (GeometryCollection ) geometry );
165
- return ;
166
- }
167
-
168
159
// no need to add empty geometry
169
160
if (geometry .isEmpty ()) {
170
161
return ;
@@ -239,13 +230,6 @@ protected Geometry clipGeometry(Geometry geometry) {
239
230
}
240
231
}
241
232
242
- private void splitAndAddFeatures (String layerName , Map <String , ?> attributes , GeometryCollection geometry ) {
243
- for (int i = 0 ; i < geometry .getNumGeometries (); i ++) {
244
- Geometry subGeometry = geometry .getGeometryN (i );
245
- addFeature (layerName , attributes , subGeometry );
246
- }
247
- }
248
-
249
233
/**
250
234
* @return a byte array with the vector tile
251
235
*/
@@ -296,6 +280,9 @@ public byte[] encode() {
296
280
}
297
281
298
282
featureBuilder .setType (toGeomType (geometry ));
283
+
284
+ x = 0 ;
285
+ y = 0 ;
299
286
featureBuilder .addAllGeometry (commands (geometry ));
300
287
301
288
tileLayer .addFeatures (featureBuilder .build ());
@@ -309,19 +296,22 @@ public byte[] encode() {
309
296
}
310
297
311
298
static VectorTile .Tile .GeomType toGeomType (Geometry geometry ) {
312
- if (geometry instanceof com . vividsolutions . jts . geom . Point ) {
299
+ if (geometry instanceof Point ) {
313
300
return VectorTile .Tile .GeomType .POINT ;
314
301
}
315
- if (geometry instanceof com . vividsolutions . jts . geom . MultiPoint ) {
302
+ if (geometry instanceof MultiPoint ) {
316
303
return VectorTile .Tile .GeomType .POINT ;
317
304
}
318
- if (geometry instanceof com . vividsolutions . jts . geom . LineString ) {
305
+ if (geometry instanceof LineString ) {
319
306
return VectorTile .Tile .GeomType .LINESTRING ;
320
307
}
321
- if (geometry instanceof com . vividsolutions . jts . geom . MultiLineString ) {
308
+ if (geometry instanceof MultiLineString ) {
322
309
return VectorTile .Tile .GeomType .LINESTRING ;
323
310
}
324
- if (geometry instanceof com .vividsolutions .jts .geom .Polygon ) {
311
+ if (geometry instanceof Polygon ) {
312
+ return VectorTile .Tile .GeomType .POLYGON ;
313
+ }
314
+ if (geometry instanceof MultiPolygon ) {
325
315
return VectorTile .Tile .GeomType .POLYGON ;
326
316
}
327
317
return VectorTile .Tile .GeomType .UNKNOWN ;
@@ -332,48 +322,62 @@ static boolean shouldClosePath(Geometry geometry) {
332
322
}
333
323
334
324
List <Integer > commands (Geometry geometry ) {
335
-
336
- x = 0 ;
337
- y = 0 ;
338
-
325
+
326
+ if ( geometry instanceof MultiLineString ) {
327
+ return commands (( MultiLineString ) geometry ) ;
328
+ }
339
329
if (geometry instanceof Polygon ) {
340
- Polygon polygon = (Polygon ) geometry ;
341
- List <Integer > commands = new ArrayList <Integer >();
342
-
343
- // According to the vector tile specification, the exterior ring of a polygon
344
- // must be in clockwise order, while the interior ring in counter-clockwise order.
345
- // In the tile coordinate system, Y axis is positive down.
346
- //
347
- // However, in geographic coordinate system, Y axis is positive up.
348
- // Therefore, we must reverse the coordinates.
349
- // So, the code below will make sure that exterior ring is in counter-clockwise order
350
- // and interior ring in clockwise order.
351
- LineString exteriorRing = polygon .getExteriorRing ();
352
- if (!CGAlgorithms .isCCW (exteriorRing .getCoordinates ())) {
353
- exteriorRing = (LineString ) exteriorRing .reverse ();
354
- }
355
- commands .addAll (commands (exteriorRing .getCoordinates (), true ));
356
-
357
- for (int i = 0 ; i < polygon .getNumInteriorRing (); i ++) {
358
- LineString interiorRing = polygon .getInteriorRingN (i );
359
- if (CGAlgorithms .isCCW (interiorRing .getCoordinates ())) {
360
- interiorRing = (LineString ) interiorRing .reverse ();
361
- }
362
- commands .addAll (commands (interiorRing .getCoordinates (), true ));
363
- }
364
- return commands ;
330
+ return commands ((Polygon ) geometry );
331
+ }
332
+ if (geometry instanceof MultiPolygon ) {
333
+ return commands ((MultiPolygon ) geometry );
334
+ }
335
+
336
+ return commands (geometry .getCoordinates (), shouldClosePath (geometry ), geometry instanceof MultiPoint );
337
+ }
338
+
339
+ List <Integer > commands (MultiLineString mls ) {
340
+ List <Integer > commands = new ArrayList <Integer >();
341
+ for (int i = 0 ; i < mls .getNumGeometries (); i ++) {
342
+ commands .addAll (commands (mls .getGeometryN (i ).getCoordinates (), false ));
343
+ }
344
+ return commands ;
345
+ }
346
+
347
+ List <Integer > commands (MultiPolygon mp ) {
348
+ List <Integer > commands = new ArrayList <Integer >();
349
+ for (int i = 0 ; i < mp .getNumGeometries (); i ++) {
350
+ Polygon polygon = (Polygon ) mp .getGeometryN (i );
351
+ commands .addAll (commands (polygon ));
365
352
}
353
+ return commands ;
354
+ }
355
+
356
+ List <Integer > commands (Polygon polygon ) {
357
+ List <Integer > commands = new ArrayList <Integer >();
358
+
359
+ // According to the vector tile specification, the exterior ring of a polygon
360
+ // must be in clockwise order, while the interior ring in counter-clockwise order.
361
+ // In the tile coordinate system, Y axis is positive down.
362
+ //
363
+ // However, in geographic coordinate system, Y axis is positive up.
364
+ // Therefore, we must reverse the coordinates.
365
+ // So, the code below will make sure that exterior ring is in counter-clockwise order
366
+ // and interior ring in clockwise order.
367
+ LineString exteriorRing = polygon .getExteriorRing ();
368
+ if (!CGAlgorithms .isCCW (exteriorRing .getCoordinates ())) {
369
+ exteriorRing = (LineString ) exteriorRing .reverse ();
370
+ }
371
+ commands .addAll (commands (exteriorRing .getCoordinates (), true ));
366
372
367
- if (geometry instanceof MultiLineString ) {
368
- List <Integer > commands = new ArrayList <Integer >();
369
- GeometryCollection gc = (GeometryCollection ) geometry ;
370
- for (int i = 0 ; i < gc .getNumGeometries (); i ++) {
371
- commands .addAll (commands (gc .getGeometryN (i ).getCoordinates (), false ));
373
+ for (int i = 0 ; i < polygon .getNumInteriorRing (); i ++) {
374
+ LineString interiorRing = polygon .getInteriorRingN (i );
375
+ if (CGAlgorithms .isCCW (interiorRing .getCoordinates ())) {
376
+ interiorRing = (LineString ) interiorRing .reverse ();
372
377
}
373
- return commands ;
378
+ commands . addAll ( commands ( interiorRing . getCoordinates (), true )) ;
374
379
}
375
-
376
- return commands (geometry .getCoordinates (), shouldClosePath (geometry ), geometry instanceof MultiPoint );
380
+ return commands ;
377
381
}
378
382
379
383
private int x = 0 ;
0 commit comments