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@465: /**
sascha@465:  * @author Sascha L. Teichmann (sascha.teichmann@intevation.de)
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@465:     protected GeometryFactory geometryFactory;
sascha@465: 
sascha@499:     protected Polygon clip;
sascha@499: 
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@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@499:     protected void clipLineString(
sascha@499:         LineString            lineString,
sascha@499:         ArrayList<LineString> 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@465:     public List<Pair<Object, MultiLineString>> getMultiLineStrings(
sascha@465:         AttributeGenerator attributeGenerator
sascha@465:     ) {
sascha@465:         ArrayList<Pair<Object, MultiLineString>> multiLineStrings =
sascha@465:             new ArrayList<Pair<Object, MultiLineString>>();
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<Coordinate> coordinates = new ArrayList<Coordinate>();
sascha@465: 
sascha@465:         for (IJKey key: joinPairs()) {
sascha@465:             ArrayList<LineString> lineStrings = new ArrayList<LineString>();
sascha@465: 
sascha@465:             // process complete
sascha@465:             ArrayList<Edge> 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<Object, MultiLineString>(
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 :