sascha@465: package de.intevation.gnv.raster; 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.LineString; sascha@499: import com.vividsolutions.jts.geom.MultiLineString; sascha@501: import com.vividsolutions.jts.geom.Polygon; sascha@499: import com.vividsolutions.jts.geom.TopologyException; sascha@465: sascha@499: import de.intevation.gnv.math.IJKey; sascha@465: sascha@465: import de.intevation.gnv.raster.Vectorizer.Edge; sascha@465: sascha@465: import de.intevation.gnv.utils.Pair; sascha@465: sascha@499: import gnu.trove.TIntObjectHashMap; sascha@465: sascha@499: import java.util.ArrayList; sascha@499: import java.util.List; sascha@499: sascha@499: import org.apache.log4j.Logger; sascha@779: sascha@465: /** sascha@802: * Vectorizer backend to generated iso lines in form of sascha@802: * JTS multi linestrings. sascha@802: * sascha@780: * @author Sascha L. Teichmann sascha@465: */ sascha@465: public class JTSMultiLineStringProducer sascha@465: extends IsoProducer sascha@465: { sascha@465: private static Logger log = Logger.getLogger( sascha@465: JTSMultiLineStringProducer.class); sascha@465: sascha@802: /** sascha@802: * The JTS geometry factory of this producer. sascha@802: */ sascha@465: protected GeometryFactory geometryFactory; sascha@465: sascha@802: /** sascha@802: * The polygon used to clip the produced multe line strings. sascha@802: */ sascha@499: protected Polygon clip; sascha@499: sascha@802: /** sascha@802: * Constructor to create a JTSMultiLineStringProducer with sascha@802: * a given clipping polygon and a world bounding box. sascha@802: * @param clip The clipping polygon. sascha@802: * @param minX Min x coord of the world. sascha@802: * @param minY Min y coord of the world. sascha@802: * @param maxX Max x coord of the world. sascha@802: * @param maxY Max y coord of the world. sascha@802: */ sascha@465: public JTSMultiLineStringProducer( 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@498: // XXX: Geotools crashes if only using a 2d packed data format! sascha@498: JTSMultiPolygonProducer.createDefaultGeometryFactory(3), sascha@465: minX, minY, sascha@465: maxX, maxY); sascha@465: } sascha@465: sascha@802: /** sascha@802: * Constructor to create a JTSMultiLineStringProducer with sascha@802: * a given clipping polygon, a geometry factory sascha@802: * and a world bounding box. sascha@802: * @param clip The clipping polygon. sascha@802: * @param geometryFactory The geometry factory. sascha@802: * @param minX Min x coord of the world. sascha@802: * @param minY Min y coord of the world. sascha@802: * @param maxX Max x coord of the world. sascha@802: * @param maxY Max y coord of the world. sascha@802: */ sascha@465: public JTSMultiLineStringProducer( 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: } sascha@465: sascha@802: /** sascha@802: * Clips a given line string against the clippin polygon. The sascha@802: * result is stored in the given list of line strings. sascha@802: * @param lineString The line string to be clipped. sascha@802: * @param lineStrings The result line string list. sascha@802: */ sascha@499: protected void clipLineString( sascha@499: LineString lineString, sascha@499: ArrayList lineStrings sascha@499: ) { sascha@499: if (clip == null) { sascha@499: lineStrings.add(lineString); sascha@499: return; sascha@499: } sascha@499: sascha@499: if (!lineString.intersects(clip)) { sascha@499: return; sascha@499: } sascha@499: sascha@499: try { sascha@499: Geometry result = lineString.intersection(clip); sascha@499: sascha@499: if (result instanceof LineString) { sascha@499: lineStrings.add((LineString)result); sascha@499: } sascha@499: else if (result instanceof MultiLineString) { sascha@499: MultiLineString mls = (MultiLineString)result; sascha@499: for (int i = 0, N = mls.getNumGeometries(); i < N; ++i) { sascha@499: Geometry g = mls.getGeometryN(i); sascha@499: if (g instanceof LineString) { sascha@499: lineStrings.add((LineString)g); sascha@499: } sascha@499: else { sascha@499: log.warn("cannot handle geometry " + g.getClass()); sascha@499: } sascha@499: } sascha@499: } sascha@499: else { sascha@499: log.warn("cannot handle " + result.getClass()); sascha@499: } sascha@499: } sascha@499: catch (TopologyException te) { sascha@499: log.error(te.getLocalizedMessage(), te); sascha@499: lineStrings.add(lineString); sascha@499: } sascha@499: } sascha@499: sascha@802: /** sascha@802: * Returns a list of pairs attribute -> multi line string. sascha@802: * All line strings produced are grouped by there attribute sascha@802: * which is generated with the given attribute generator. sascha@802: * @param attributeGenerator The attribute generator. sascha@802: * @return The list of attribute/multi line strings. sascha@802: */ sascha@465: public List> getMultiLineStrings( sascha@465: AttributeGenerator attributeGenerator sascha@465: ) { sascha@465: ArrayList> multiLineStrings = sascha@465: new ArrayList>(); 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 coordinates = new ArrayList(); sascha@465: sascha@465: for (IJKey key: joinPairs()) { sascha@465: ArrayList lineStrings = new ArrayList(); sascha@465: sascha@465: // process complete sascha@465: ArrayList completeList = complete.get(key); sascha@465: if (completeList != null) { sascha@465: for (Edge head: completeList) { sascha@465: Edge current = head; sascha@465: do { sascha@465: coordinates.add(new Coordinate( sascha@465: m1*(current.a % width) + b1, sascha@465: m2*(current.a / width) + b2)); sascha@465: } sascha@465: while ((current = current.next) != head); sascha@465: // add head again to close shape sascha@465: coordinates.add(new Coordinate( sascha@465: m1*(head.a % width) + b1, sascha@465: m2*(head.a / width) + b2)); sascha@499: sascha@499: clipLineString( sascha@465: geometryFactory.createLineString( sascha@465: coordinates.toArray( sascha@499: new Coordinate[coordinates.size()])), sascha@499: lineStrings); sascha@499: sascha@465: coordinates.clear(); sascha@465: } sascha@465: } sascha@465: sascha@465: // process open sascha@465: TIntObjectHashMap map = commonOpen.get(key); sascha@465: sascha@465: if (map != null) { sascha@465: for (Edge head: headList(map)) { sascha@465: sascha@465: head = Vectorizer.simplify(head, width); sascha@465: Edge current = head, last = head; sascha@465: do { sascha@465: coordinates.add(new Coordinate( sascha@465: m1*(current.a % width) + b1, sascha@465: m2*(current.a / width) + b2)); sascha@465: last = current; sascha@465: } sascha@465: while ((current = current.next) != null); sascha@465: // add b from tail sascha@465: coordinates.add(new Coordinate( sascha@465: m1*(last.b % width) + b1, sascha@465: m2*(last.b / width) + b2)); sascha@499: sascha@499: clipLineString( sascha@465: geometryFactory.createLineString( sascha@465: coordinates.toArray( sascha@499: new Coordinate[coordinates.size()])), sascha@499: lineStrings); sascha@499: sascha@465: coordinates.clear(); sascha@465: } // for all in common open sascha@465: } // if map defined for key sascha@465: sascha@465: if (!lineStrings.isEmpty()) { sascha@465: MultiLineString multiLineString = sascha@465: geometryFactory.createMultiLineString( sascha@465: lineStrings.toArray( sascha@465: new LineString[lineStrings.size()])); sascha@465: lineStrings.clear(); sascha@465: Object attribute = attributeGenerator != null sascha@465: ? attributeGenerator.generateAttribute(key.i, key.j) sascha@465: : key; sascha@465: multiLineStrings.add(new Pair( sascha@465: attribute, sascha@465: multiLineString)); sascha@465: } sascha@465: } // for all pairs sascha@465: sascha@465: return multiLineStrings; sascha@465: } sascha@465: } sascha@465: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :