/* Copyright 2013 The jeo project. All rights reserved. * * 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 org.oscim.utils.geom; import org.locationtech.jts.geom.Coordinate; import org.locationtech.jts.geom.Geometry; import org.locationtech.jts.geom.GeometryCollection; import org.locationtech.jts.geom.GeometryFactory; import org.locationtech.jts.geom.LineString; import org.locationtech.jts.geom.LinearRing; import org.locationtech.jts.geom.MultiLineString; import org.locationtech.jts.geom.MultiPoint; import org.locationtech.jts.geom.MultiPolygon; import org.locationtech.jts.geom.Point; import org.locationtech.jts.geom.Polygon; import org.locationtech.jts.geom.PrecisionModel; import java.lang.reflect.Array; import java.util.ArrayDeque; import java.util.Arrays; import java.util.Deque; import java.util.Iterator; /** * Builder for geometry objects. *
* Example usage: *
*
*
* GeometryBuilder gb = new GeometryBuilder();
*
* // create array two 2d points and turn into a line string
* gb.points(1,2,3,4,5,6).toLineString();
*
* // build a polygon with holes
* gb.points(0,0,10,0,10,10,0,10,0,0).ring()
* .points(4,4,6,4,6,6,4,6,4,4).ring()
* .toPolygon();
*
*
*
*
*
*
* @author Justin Deoliveira, OpenGeo
*/
public class GeomBuilder {
GeometryFactory factory;
Deque* If the first and last coordinate on the point stack are not equal an * additional point will be added. *
*/ public GeomBuilder ring() { Coordinate[] coords = cpopAll(); if (coords.length > 1 && !coords[0].equals(coords[coords.length - 1])) { Coordinate[] tmp = new Coordinate[coords.length + 1]; System.arraycopy(coords, 0, tmp, 0, coords.length); tmp[tmp.length - 1] = new Coordinate(tmp[0]); coords = tmp; } gstack.push(factory.createLinearRing(coords)); return this; } /** * Creates a Polygon from all LinearRings on the geometry stack and places * the result back * on the geometry stack. */ public GeomBuilder polygon() { if (gstack.isEmpty() || !(gstack.peek() instanceof LinearRing)) { ring(); } LinearRing[] rings = gpopAll(LinearRing.class); LinearRing outer = rings[0]; LinearRing[] inner = null; if (rings.length > 1) { inner = Arrays.copyOfRange(rings, 1, rings.length); } gstack.push(factory.createPolygon(outer, inner)); return this; } /** * Creates a MultiPoint from all coordinates on the coordinate stack, * plaching the result * back on the geometry stack. ** If the coordinate stack is empty this method will consume all Point * geometries on the geometry stack. *
*/ public GeomBuilder multiPoint() { if (!cstack.isEmpty()) { gstack.push(factory.createMultiPoint(cpopAll())); } else { gstack.push(factory.createMultiPoint(gpopAll(Point.class))); } return this; } /** * Creates a MultiLineString from all LineStrings on the geometry stack and * places the result * back on the geometry stack. */ public GeomBuilder multiLineString() { gstack.push(factory.createMultiLineString(gpopAll(LineString.class))); return this; } /** * Creates a MultiPolygon from all Polygons on the geometry stack and places * the result * back on the geometry stack. */ public GeomBuilder multiPolygon() { gstack.push(factory.createMultiPolygon(gpopAll(Polygon.class))); return this; } /** * Creates a GeometryCollection from all Geometries on the geometry stack * and places the result * back on the geometry stack. */ public GeomBuilder collection() { gstack.push(factory.createGeometryCollection(gpopAll(Geometry.class))); return this; } /** * Buffers the geometry at the top of the geometry stack, and places the * result back on the * geometry stack. */ public GeomBuilder buffer(double amt) { gstack.push(gpop(Geometry.class).buffer(amt)); return this; } /** * Consumes the top of the geometry stack. */ public Geometry get() { return gpop(Geometry.class); } /** * Builds and returns a Point. ** This method is equivalent to: *
*
* (Point) point().get();
*
*
*
*/
public Point toPoint() {
return point().gpop(Point.class);
}
/**
* Builds and returns a LineString.
* * This method is equivalent to: *
*
* (LineString) lineString().get();
*
*
*
*/
public LineString toLineString() {
return lineString().gpop(LineString.class);
}
/**
* Builds and returns a LineString.
* * This method is equivalent to: *
*
* (LinearRing) ring().get();
*
*
*
*/
public LinearRing toLinearRing() {
return ring().gpop(LinearRing.class);
}
/**
* Builds and returns a Polygon.
* * This method is equivalent to: *
*
* (Polygon) polygon().get();
*
*
*
*/
public Polygon toPolygon() {
return polygon().gpop(Polygon.class);
}
/**
* Builds and returns a MultiPoint.
* * This method is equivalent to: *
*
* (MultiPoint) multiPoint().get();
*
*
*
*/
public MultiPoint toMultiPoint() {
return multiPoint().gpop(MultiPoint.class);
}
/**
* Builds and returns a MultiLineString.
* * This method is equivalent to: *
*
* (MultiLineString) multiLineString().get();
*
*
*
*/
public MultiLineString toMultiLineString() {
return multiLineString().gpop(MultiLineString.class);
}
/**
* Builds and returns a MultiPolygon.
* * This method is equivalent to: *
*
* (MultiPolygon) multiPolygon().get();
*
*
*
*/
public MultiPolygon toMultiPolygon() {
return multiPolygon().gpop(MultiPolygon.class);
}
/**
* Builds and returns a GEometryCollection.
* * This method is equivalent to: *
*
* (GeometryCollection) collection().get();
*
*
*
*/
public GeometryCollection toCollection() {
return collection().gpop(GeometryCollection.class);
}
Coordinate cpop() {
return cpop(1)[0];
}
Coordinate[] cpop(int n) {
if (cstack.size() < n) {
throw new IllegalStateException(String.format("Expected %d values on coordinate stack, "
+ "but found %d",
n,
cstack.size()));
}
Coordinate[] c = new Coordinate[n];
for (int i = 0; i < n; i++) {
c[n - i - 1] = cstack.pop();
}
return c;
}
Coordinate[] cpopAll() {
if (cstack.isEmpty()) {
throw new IllegalStateException("Coordinate stack is empty");
}
return cpop(cstack.size());
}