in baremaps-core/src/main/java/org/apache/baremaps/storage/shapefile/internal/ShapefileByteReader.java [332:380]
private Geometry readMultiplePolygon(int numParts, int numPoints) {
/**
* From ESRI Specification : Parts : 0 5 (meaning : 0 designs the first v1, 5 designs the first
* v5 on the points list below). Points : v1 v2 v3 v4 v1 v5 v8 v7 v6 v5
*
* <p>
* POSITION FIELD VALUE TYPE NUMBER ORDER Byte 0 Shape Type 5 Integer 1 Little Byte 4 Box Box
* Double 4 Little Byte 36 NumParts NumParts Integer 1 Little Byte 40 NumPoints NumPoints
* Integer 1 Little Byte 44 Parts Parts Integer NumParts Little Byte X Points Points Point
* NumPoints Little
*/
// Read all the parts indexes (starting at byte 44).
var partsIndexes = new int[numParts];
for (int index = 0; index < numParts; index++) {
partsIndexes[index] = getByteBuffer().getInt();
}
// Read all the coordinates.
var coordinates = new Coordinate[numPoints];
for (var i = 0; i < numPoints; i++) {
var x = getByteBuffer().getDouble();
var y = getByteBuffer().getDouble();
var coordinate = new Coordinate(x, y);
coordinates[i] = coordinate;
}
// Create the shells and holes.
var shells = new ArrayList<Polygon>();
var holes = new LinkedList<Polygon>();
for (var i = 0; i < partsIndexes.length; i++) {
var from = partsIndexes[i];
var to = i < partsIndexes.length - 1 ? partsIndexes[i + 1] : coordinates.length;
var array = Arrays.copyOfRange(coordinates, from, to);
var linearRing = geometryFactory.createPolygon(array);
if (!Orientation.isCCW(linearRing.getCoordinates())) {
shells.add(linearRing);
} else {
holes.add(linearRing);
}
}
// Compute the difference between shells and holes
var shellsMultiPolygon =
geometryFactory.createMultiPolygon(shells.toArray(size -> new Polygon[size]));
var holesMultiPolygon =
geometryFactory.createMultiPolygon(holes.toArray(size -> new Polygon[size]));
return shellsMultiPolygon.difference(holesMultiPolygon);
}