view gnv-artifacts/src/main/java/de/intevation/gnv/raster/JTSMultiPolygonProducer.java @ 778:9a828e5a2390

Removed trailing whitespace gnv-artifacts/trunk@851 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author Sascha L. Teichmann <sascha.teichmann@intevation.de>
date Mon, 29 Mar 2010 07:58:51 +0000
parents 70adafe2b9d5
children c4156275c1e1
line wrap: on
line source
package de.intevation.gnv.raster;

import com.vividsolutions.jts.algorithm.CGAlgorithms;

import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.LinearRing;
import com.vividsolutions.jts.geom.MultiPolygon;
import com.vividsolutions.jts.geom.Polygon;
import com.vividsolutions.jts.geom.PrecisionModel;
import com.vividsolutions.jts.geom.TopologyException;

import com.vividsolutions.jts.geom.impl.PackedCoordinateSequenceFactory;

import de.intevation.gnv.raster.Vectorizer.Edge;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import org.apache.log4j.Logger;

/**
 * @author Sascha L. Teichmann (sascha.teichmann@intevation.de)
 */
public class JTSMultiPolygonProducer
extends      AbstractProducer
{
    private static Logger log = Logger.getLogger(
        JTSMultiPolygonProducer.class);

    public static final int SRID_WGS84 = 4326;

    public interface ValueConverter {

        Integer convert(Integer value);

    } // interface ValueConverter

    protected GeometryFactory geometryFactory;

    protected Polygon clip;

    protected HashMap<Integer, ArrayList<Polygon>> valueToPolygons;

    public JTSMultiPolygonProducer() {
    }

    public JTSMultiPolygonProducer(
        Polygon clip,
        double minX, double minY,
        double maxX, double maxY
    ) {
        this(
            clip,
            createDefaultGeometryFactory(),
            minX, minY,
            maxX, maxY);
    }

    public JTSMultiPolygonProducer(
        Polygon clip,
        GeometryFactory geometryFactory,
        double minX, double minY,
        double maxX, double maxY
    ) {
        super(minX, minY, maxX, maxY);
        this.clip = clip;
        this.geometryFactory = geometryFactory;
        valueToPolygons = new HashMap<Integer, ArrayList<Polygon>>();
    }

    public static GeometryFactory createDefaultGeometryFactory() {
        return createDefaultGeometryFactory(3);
    }

    public static GeometryFactory createDefaultGeometryFactory(int dim) {
        return new GeometryFactory(
            new PrecisionModel(
                PrecisionModel.FLOATING),
            SRID_WGS84,
            new PackedCoordinateSequenceFactory(
                PackedCoordinateSequenceFactory.DOUBLE,
                dim));
    }

    public void handleRings(
        List<Edge> rings,
        int        value,
        int        width,
        int        height
    ) {
        if (value == -1) {
            return;
        }

        double b1 = minX;
        double m1 = width != 1
           ? (maxX - minX)/(width-1)
           : 0d;

        double b2 = minY;
        double m2 = height != 1
           ? (maxY - minY)/(height-1)
           : 0d;

        ArrayList<Coordinate> vertices = new ArrayList<Coordinate>();

        LinearRing shell = null;
        ArrayList<LinearRing> holes = new ArrayList<LinearRing>();

        for (Edge head: rings) {
            Edge current = head;
            do {
                vertices.add(new Coordinate(
                    m1*(current.a % width) + b1,
                    m2*(current.a / width) + b2));
            }
            while ((current = current.prev) != head);
            vertices.add(new Coordinate(
                m1*(head.a % width) + b1,
                m2*(head.a / width) + b2));

            Coordinate [] coordinates =
                vertices.toArray(new Coordinate[vertices.size()]);

            vertices.clear();

            LinearRing ring = geometryFactory.createLinearRing(
                coordinates);

            if (CGAlgorithms.isCCW(coordinates)) {
                shell = ring;
            }
            else {
                holes.add(ring);
            }
        }

        if (shell == null) {
            log.error("polygon has no shell");
            return;
        }

        Polygon polygon = geometryFactory.createPolygon(
            shell,
            holes.toArray(new LinearRing[holes.size()]));

        if (clip == null || clip.intersects(polygon)) {
            Integer v = Integer.valueOf(value);

            ArrayList<Polygon> polygons = valueToPolygons.get(v);

            if (polygons == null) {
                valueToPolygons.put(v, polygons = new ArrayList<Polygon>());
            }

            polygons.add(polygon);
        }
    }

    public Map<Integer, MultiPolygon> getMultiPolygons() {
        return getMultiPolygons(null);
    }

    protected MultiPolygon flattenCollection(Geometry result) {

        if (result instanceof MultiPolygon) {
            return (MultiPolygon)result;
        }

        if (result instanceof Polygon) {
            return geometryFactory.createMultiPolygon(
                new Polygon[] { (Polygon)result });
        }

        log.warn("cannot handle " + result.getClass());

        return null;
    }

    public Map<Integer, MultiPolygon> getMultiPolygons(
        ValueConverter valueConverter
    ) {
        TreeMap<Integer, MultiPolygon> multiPolygons =
            new TreeMap<Integer, MultiPolygon>();

        for (Map.Entry<Integer, ArrayList<Polygon>> entry:
            valueToPolygons.entrySet()
        ) {
            ArrayList<Polygon> polygons = entry.getValue();

            Integer value = valueConverter != null
                ? valueConverter.convert(entry.getKey())
                : entry.getKey();

            MultiPolygon mp = geometryFactory.createMultiPolygon(
                polygons.toArray(new Polygon[polygons.size()]));

            if (clip != null) {
                try {
                    Geometry result = mp.intersection(clip);

                    MultiPolygon mp2 = flattenCollection(result);

                    if (mp2 != null) { mp = mp2; }
                }
                catch (TopologyException te) {
                    log.error(te.getLocalizedMessage(), te);
                }
            }
            multiPolygons.put(value, mp);
        }

        return multiPolygons;
    }

    public void clear() {
        valueToPolygons.clear();
    }
}
// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :

http://dive4elements.wald.intevation.org