view gnv-artifacts/src/main/java/de/intevation/gnv/math/GridCell.java @ 605:e8ebdbc7f1e3

First step of removing the cache blob. The static part of the describe document will be created by using the input data stored at each state. Some TODOs left (see ChangeLog). gnv-artifacts/trunk@671 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author Ingo Weinzierl <ingo.weinzierl@intevation.de>
date Tue, 09 Feb 2010 14:27:55 +0000
parents b248531fa20b
children c4156275c1e1
line wrap: on
line source
package de.intevation.gnv.math;

import com.vividsolutions.jts.algorithm.CGAlgorithms;

import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Envelope;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.LinearRing;
import com.vividsolutions.jts.geom.Point;
import com.vividsolutions.jts.geom.Polygon;

import com.vividsolutions.jts.index.ItemVisitor;

import java.io.Serializable;

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

import org.apache.log4j.Logger;

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

    public static final class CellFinder
    implements                ItemVisitor
    {
        public    GridCell found;

        protected Point    point;

        public CellFinder() {
        }

        public void prepare(Coordinate center) {
            found = null;
            point = GEOMETRY_FACTORY.createPoint(center);
        }

        public void visitItem(Object item) {
            if (found == null) {
                GridCell cell = (GridCell)item;
                if (cell.contains(point)) {
                    found = cell;
                }
            }
        }
    } // class CellFinder

    public Point2d p1;
    public Point2d p2;
    public Point2d p3;
    public Point2d p4;

    protected Polygon polygon;

    public static final GeometryFactory GEOMETRY_FACTORY
        = new GeometryFactory();

    public GridCell() {
    }

    public GridCell(Point2d p1, Point2d p2, Point2d p3, Point2d p4) {
        this.p1 = p1;
        this.p2 = p2;
        this.p3 = p3;
        this.p4 = p4;
        createPolygon();
    }

    protected void createPolygon() {
        Coordinate [] coords = new Coordinate [] { p1, p2, p3, p4, p1 };
        if (!CGAlgorithms.isCCW(coords)) {
            for (int i = 0, j = coords.length-1; i < j; ++i, --j) {
                Coordinate c = coords[i];
                coords[i] = coords[j];
                coords[j] = c;
            }
        }
        LinearRing shell = GEOMETRY_FACTORY
            .createLinearRing(coords);

        if (!shell.isValid()) {
            log.warn("linear ring is not valid");
        }

        polygon = GEOMETRY_FACTORY.createPolygon(shell, null);
    }

    public Envelope getEnvelope() {
        return polygon.getEnvelopeInternal();
    }

    public boolean contains(Geometry coord) {
        return polygon.contains(coord);
    }

    public static List<GridCell> pointsToGridCells(
        List<? extends Point2d> points
    ) {
        return pointsToGridCells(points, null);
    }

    public static List<GridCell> pointsToGridCells(
        List<? extends Point2d> points,
        Envelope                relevantArea
    ) {
        return pointsToGridCells(points, relevantArea, 0);
    }

    private static final int NEIGHBORS [][] = {
        { -1, -1 }, // 0
        { -1,  0 }, // 1
        { -1, +1 }, // 2
        {  0, +1 }, // 3
        { +1, +1 }, // 4
        { +1,  0 }, // 5
        { +1, -1 }, // 6
        {  0, -1 }  // 7
    };

    public static int extrapolate(
        HashMap<Integer, HashMap<Integer, Point2d>> rows,
        int minI, int maxI,
        int minJ, int maxJ,
        int rounds,
        Envelope relevantArea
    ) {
        Point2d [] neighbors = new Point2d[NEIGHBORS.length];
        Point2d [] positions = new Point2d[NEIGHBORS.length];

        int total = 0;

        ArrayList<ArrayList<IJKey>> prio =
            new ArrayList<ArrayList<IJKey>>(NEIGHBORS.length);

        for (int i = 0; i < NEIGHBORS.length; ++i) {
            prio.add(new ArrayList<IJKey>());
        }

        while (rounds-- > 0) {
            for (int i = minI; i <= maxI; ++i) {
                for (int j = minJ; j <= maxJ; ++j) {
                    Point2d p = get(rows, i, j);
                    if (p != null) {
                        continue;
                    }

                    int count = 0;

                    for (int k = 0; k < neighbors.length; ++k) {
                        neighbors[k] = positions[k] = null;
                        int dij [] = NEIGHBORS[k];
                        Point2d n1 = get(rows, i+  dij[0], j+  dij[1]);
                        Point2d n2 = get(rows, i+2*dij[0], j+2*dij[1]);
                        if (n1 != null && n2 != null) {
                            ++count;
                        }
                    }

                    if (count > 0) {
                        prio.get(count-1).add(new IJKey(i, j));
                    }
                } // for all columns
            } // for all rows

            int N = 0;

            for (int l = NEIGHBORS.length-1; l >= 0; --l) {
                ArrayList<IJKey> list = prio.get(l);
                for (IJKey ij: list) {
                    int i = ij.i;
                    int j = ij.j;
                    for (int k = 0; k < neighbors.length; ++k) {
                        neighbors[k] = positions[k] = null;
                        int dij [] = NEIGHBORS[k];
                        Point2d n1 = get(rows, i+  dij[0], j+  dij[1]);
                        Point2d n2 = get(rows, i+2*dij[0], j+2*dij[1]);
                        if (n1 != null && n2 != null) {
                            neighbors[k] = n1;
                            positions[k] = n1.extrapolate(-1d, n2);
                        }
                    }

                    Point2d avg = Point2d.average(positions);

                    if (avg != null && avg.near(positions)
                    && (relevantArea == null || relevantArea.contains(avg.x, avg.y))) {
                        avg.i = i;
                        avg.j = j;
                        avg.inverseDistanceWeighting(neighbors);
                        put(rows, avg, i, j);
                    }
                }
                N += list.size();
                list.clear();
            }

            if (N == 0) {
                break;
            }
            total += N;
        } // for all rounds

        return total;
    }

    public static List<GridCell> pointsToGridCells(
        List<? extends Point2d> points,
        Envelope                relevantArea,
        int                     extrapolationRounds
    ) {
        int minI = Integer.MAX_VALUE;
        int maxI = Integer.MIN_VALUE;
        int minJ = Integer.MAX_VALUE;
        int maxJ = Integer.MIN_VALUE;

        HashMap<Integer, HashMap<Integer, Point2d>> rows =
            new HashMap<Integer, HashMap<Integer, Point2d>>();

        int culled = 0;

        for (Point2d p: points) {

            if (relevantArea != null && !relevantArea.contains(p.x, p.y)) {
                ++culled;
                continue;
            }

            if (p.i < minI) minI = p.i;
            if (p.i > maxI) maxI = p.i;
            if (p.j < minJ) minJ = p.j;
            if (p.j > maxJ) maxJ = p.j;

            HashMap<Integer, Point2d> row = rows.get(p.i);

            if (row == null) {
                rows.put(p.i, row = new HashMap<Integer, Point2d>());
            }

            row.put(p.j, p);
        }

        ArrayList<GridCell> cells = new ArrayList<GridCell>(points.size());

        int extrapolated = extrapolate(
            rows,
            minI, maxI,
            minJ, maxJ,
            extrapolationRounds,
            relevantArea);

        for (int i = minI + 1; i <= maxI; ++i) {
            HashMap<Integer, Point2d> row1 = rows.get(i-1);
            HashMap<Integer, Point2d> row2 = rows.get(i);

            if (row1 == null || row2 == null) {
                continue;
            }

            for (int j = minJ + 1; j < maxJ; ++j) {
                Point2d p1 = row1.get(j-1);
                Point2d p2 = row1.get(j);
                Point2d p3 = row2.get(j);
                Point2d p4 = row2.get(j-1);

                if (p1 != null && p2 != null && p3 != null && p4 != null) {
                    cells.add(new GridCell(p1, p2, p3, p4));
                }
            }
        } // for all rows

        if (log.isDebugEnabled()) {
            log.debug("culled points: " + culled);
            log.debug("extrapolated points: " + extrapolated);
            log.debug("min/max i: " + minI + " / " + maxI);
            log.debug("min/max j: " + minJ + " / " + maxJ);
            log.debug("cells found: " + cells.size());
        }

        return cells;
    }

    private static Point2d get(
        HashMap<Integer, HashMap<Integer, Point2d>> rows,
        int i, int j
    ) {
        HashMap<Integer, Point2d> row = rows.get(i);
        return row != null ? row.get(j) : null;
    }

    private static void put(
        HashMap<Integer, HashMap<Integer, Point2d>> rows,
        Point2d point,
        int i, int j
    ) {
        Integer I = Integer.valueOf(i);
        HashMap<Integer, Point2d> row = rows.get(I);
        if (row == null) {
            rows.put(I, row = new HashMap<Integer, Point2d>());
        }
        row.put(j, point);
    }
}
// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :

http://dive4elements.wald.intevation.org