sascha@465: package de.intevation.gnv.raster; sascha@465: sascha@465: import com.vividsolutions.jts.algorithm.CGAlgorithms; sascha@465: sascha@499: import com.vividsolutions.jts.geom.Coordinate; sascha@499: import com.vividsolutions.jts.geom.Geometry; sascha@499: import com.vividsolutions.jts.geom.GeometryFactory; sascha@499: import com.vividsolutions.jts.geom.LinearRing; sascha@499: import com.vividsolutions.jts.geom.MultiPolygon; sascha@499: import com.vividsolutions.jts.geom.Polygon; sascha@499: import com.vividsolutions.jts.geom.PrecisionModel; sascha@499: import com.vividsolutions.jts.geom.TopologyException; sascha@499: sascha@465: import com.vividsolutions.jts.geom.impl.PackedCoordinateSequenceFactory; sascha@465: sascha@499: import de.intevation.gnv.raster.Vectorizer.Edge; sascha@499: sascha@499: import java.util.ArrayList; sascha@499: import java.util.HashMap; sascha@499: import java.util.List; sascha@499: import java.util.Map; sascha@499: import java.util.TreeMap; sascha@499: sascha@465: import org.apache.log4j.Logger; sascha@465: sascha@465: /** sascha@465: * @author Sascha L. Teichmann (sascha.teichmann@intevation.de) sascha@465: */ sascha@465: public class JTSMultiPolygonProducer sascha@465: extends AbstractProducer sascha@465: { sascha@465: private static Logger log = Logger.getLogger( sascha@465: JTSMultiPolygonProducer.class); sascha@465: sascha@465: public static final int SRID_WGS84 = 4326; sascha@465: sascha@465: public interface ValueConverter { sascha@465: sascha@465: Integer convert(Integer value); sascha@465: sascha@465: } // interface ValueConverter sascha@465: sascha@465: protected GeometryFactory geometryFactory; sascha@465: sascha@499: protected Polygon clip; sascha@499: sascha@465: protected HashMap> valueToPolygons; sascha@465: sascha@465: public JTSMultiPolygonProducer() { sascha@465: } sascha@465: sascha@465: public JTSMultiPolygonProducer( sascha@499: Polygon clip, sascha@465: double minX, double minY, sascha@465: double maxX, double maxY sascha@465: ) { sascha@465: this( sascha@499: clip, sascha@465: createDefaultGeometryFactory(), sascha@465: minX, minY, sascha@465: maxX, maxY); sascha@465: } sascha@465: sascha@465: public JTSMultiPolygonProducer( sascha@499: Polygon clip, sascha@465: GeometryFactory geometryFactory, sascha@465: double minX, double minY, sascha@465: double maxX, double maxY sascha@465: ) { sascha@465: super(minX, minY, maxX, maxY); sascha@499: this.clip = clip; sascha@465: this.geometryFactory = geometryFactory; sascha@465: valueToPolygons = new HashMap>(); sascha@465: } sascha@465: sascha@465: public static GeometryFactory createDefaultGeometryFactory() { sascha@499: return createDefaultGeometryFactory(3); sascha@498: } sascha@498: sascha@498: public static GeometryFactory createDefaultGeometryFactory(int dim) { sascha@465: return new GeometryFactory( sascha@465: new PrecisionModel( sascha@465: PrecisionModel.FLOATING), sascha@465: SRID_WGS84, sascha@465: new PackedCoordinateSequenceFactory( sascha@465: PackedCoordinateSequenceFactory.DOUBLE, sascha@498: dim)); sascha@465: } sascha@465: sascha@465: public void handleRings( sascha@778: List rings, sascha@778: int value, sascha@465: int width, sascha@465: int height sascha@465: ) { sascha@465: if (value == -1) { sascha@465: return; sascha@465: } sascha@465: sascha@465: double b1 = minX; sascha@465: double m1 = width != 1 sascha@465: ? (maxX - minX)/(width-1) sascha@465: : 0d; sascha@465: sascha@465: double b2 = minY; sascha@465: double m2 = height != 1 sascha@465: ? (maxY - minY)/(height-1) sascha@465: : 0d; sascha@465: sascha@465: ArrayList vertices = new ArrayList(); sascha@465: sascha@465: LinearRing shell = null; sascha@465: ArrayList holes = new ArrayList(); sascha@465: sascha@465: for (Edge head: rings) { sascha@465: Edge current = head; sascha@465: do { sascha@465: vertices.add(new Coordinate( sascha@465: m1*(current.a % width) + b1, sascha@465: m2*(current.a / width) + b2)); sascha@465: } sascha@495: while ((current = current.prev) != head); sascha@465: vertices.add(new Coordinate( sascha@465: m1*(head.a % width) + b1, sascha@465: m2*(head.a / width) + b2)); sascha@465: sascha@465: Coordinate [] coordinates = sascha@465: vertices.toArray(new Coordinate[vertices.size()]); sascha@465: sascha@465: vertices.clear(); sascha@465: sascha@465: LinearRing ring = geometryFactory.createLinearRing( sascha@465: coordinates); sascha@465: sascha@465: if (CGAlgorithms.isCCW(coordinates)) { sascha@465: shell = ring; sascha@465: } sascha@465: else { sascha@465: holes.add(ring); sascha@465: } sascha@465: } sascha@465: sascha@465: if (shell == null) { sascha@465: log.error("polygon has no shell"); sascha@465: return; sascha@465: } sascha@465: sascha@465: Polygon polygon = geometryFactory.createPolygon( sascha@465: shell, sascha@465: holes.toArray(new LinearRing[holes.size()])); sascha@465: sascha@499: if (clip == null || clip.intersects(polygon)) { sascha@499: Integer v = Integer.valueOf(value); sascha@499: sascha@499: ArrayList polygons = valueToPolygons.get(v); sascha@499: sascha@499: if (polygons == null) { sascha@499: valueToPolygons.put(v, polygons = new ArrayList()); sascha@499: } sascha@499: sascha@499: polygons.add(polygon); sascha@499: } sascha@465: } sascha@465: sascha@465: public Map getMultiPolygons() { sascha@465: return getMultiPolygons(null); sascha@465: } sascha@465: sascha@499: protected MultiPolygon flattenCollection(Geometry result) { sascha@499: sascha@499: if (result instanceof MultiPolygon) { sascha@499: return (MultiPolygon)result; sascha@499: } sascha@499: sascha@499: if (result instanceof Polygon) { sascha@499: return geometryFactory.createMultiPolygon( sascha@499: new Polygon[] { (Polygon)result }); sascha@499: } sascha@499: sascha@499: log.warn("cannot handle " + result.getClass()); sascha@499: sascha@499: return null; sascha@499: } sascha@499: sascha@465: public Map getMultiPolygons( sascha@465: ValueConverter valueConverter sascha@465: ) { sascha@465: TreeMap multiPolygons = sascha@465: new TreeMap(); sascha@465: sascha@465: for (Map.Entry> entry: sascha@465: valueToPolygons.entrySet() sascha@465: ) { sascha@465: ArrayList polygons = entry.getValue(); sascha@465: sascha@465: Integer value = valueConverter != null sascha@465: ? valueConverter.convert(entry.getKey()) sascha@465: : entry.getKey(); sascha@465: sascha@499: MultiPolygon mp = geometryFactory.createMultiPolygon( sascha@499: polygons.toArray(new Polygon[polygons.size()])); sascha@499: sascha@499: if (clip != null) { sascha@499: try { sascha@499: Geometry result = mp.intersection(clip); sascha@499: sascha@499: MultiPolygon mp2 = flattenCollection(result); sascha@499: sascha@499: if (mp2 != null) { mp = mp2; } sascha@499: } sascha@499: catch (TopologyException te) { sascha@499: log.error(te.getLocalizedMessage(), te); sascha@499: } sascha@499: } sascha@499: multiPolygons.put(value, mp); sascha@465: } sascha@465: sascha@465: return multiPolygons; sascha@465: } sascha@465: sascha@465: public void clear() { sascha@465: valueToPolygons.clear(); sascha@465: } sascha@465: } sascha@465: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :