ingo@1115: /* ingo@1115: * Copyright (c) 2010 by Intevation GmbH ingo@1115: * ingo@1115: * This program is free software under the LGPL (>=v2.1) ingo@1115: * Read the file LGPL.txt coming with the software for details ingo@1115: * or visit http://www.gnu.org/licenses/ if it does not exist. ingo@1115: */ ingo@1115: sascha@349: package de.intevation.gnv.utils; sascha@349: sascha@779: import java.awt.Point; sascha@779: sascha@349: import java.awt.geom.Point2D; sascha@349: sascha@349: import java.util.List; sascha@349: sascha@349: /** sascha@349: * Create buffers around integer pairs (i_1..n), j_1..n). sascha@349: * sascha@780: * @author Sascha L. Teichmann sascha@349: */ sascha@349: public class IndexBuffer sascha@349: { sascha@349: public static final double EPSILON = 1e-6d; sascha@349: public static final double OFFSET = 1.0d; sascha@349: sascha@349: public static final String I_COLUMN = "IPOSITION"; sascha@349: public static final String J_COLUMN = "JPOSITION"; sascha@349: sascha@349: public static final class Segment { sascha@349: sascha@349: private Segment next; sascha@349: sascha@349: private Point2D.Double n; sascha@349: private double d1; sascha@349: private double d2; sascha@349: sascha@349: private int iMin; sascha@349: private int iMax; sascha@349: sascha@349: private int jMin; sascha@349: private int jMax; sascha@349: sascha@349: public Segment(Point a, Point b, Segment next) { sascha@349: sascha@349: this.next = next; sascha@349: sascha@349: iMin = Math.min(a.x, b.x)-1; sascha@349: iMax = Math.max(a.x, b.x)+1; sascha@349: sascha@349: jMin = Math.min(a.y, b.y)-1; sascha@349: jMax = Math.max(a.y, b.y)+1; sascha@349: sascha@349: if (a.x > b.x) { sascha@349: Point p = a; a = b; b = p; sascha@349: } sascha@349: sascha@349: Point2D.Double p1, p2, p3; sascha@349: sascha@349: if (a.y < b.y) { sascha@349: p1 = new Point2D.Double(a.x - OFFSET, a.y + 1 + OFFSET); sascha@349: p2 = new Point2D.Double(b.x - OFFSET, b.y + 1 + OFFSET); sascha@349: p3 = new Point2D.Double(a.x + 1 + OFFSET, a.y - OFFSET); sascha@349: } sascha@349: else { sascha@349: p1 = new Point2D.Double(a.x + 1 + OFFSET, a.y + 1 + OFFSET); sascha@349: p2 = new Point2D.Double(b.x + 1 + OFFSET, b.y + 1 + OFFSET); sascha@349: p3 = new Point2D.Double(b.x - OFFSET, b.y - OFFSET); sascha@349: } sascha@349: sascha@349: n = normalize(orthogonal(sub(p1, p2))); sascha@349: sascha@349: d1 = dot(n, p1); sascha@349: d2 = dot(n, p3); sascha@349: sascha@349: if (d1 > d2) { sascha@349: double d = d1; sascha@349: d1 = d2; sascha@349: d2 = d; sascha@349: } sascha@349: } sascha@349: sascha@349: public boolean check(int i, int j) { sascha@349: if (i < iMin || i > iMax || j < jMin || j > jMax) { sascha@349: return false; sascha@349: } sascha@349: double v = dot(n, i, j); sascha@349: return v >= d1 && v <= d2; sascha@349: } sascha@349: sascha@349: public void toWhereClause(StringBuilder sb, String iColumn, String jColumn) { sascha@349: sb.append('(') sascha@349: .append(iColumn).append(" >= ").append(iMin).append(" AND ") sascha@349: .append(iColumn).append(" <= ").append(iMax).append(" AND ") sascha@349: .append(jColumn).append(" >= ").append(jMin).append(" AND ") sascha@349: .append(jColumn).append(" <= ").append(jMax).append(" AND (") sascha@349: .append(n.x).append('*').append(iColumn).append(" + ") sascha@349: .append(n.y).append('*').append(jColumn) sascha@349: .append(") BETWEEN ").append(d1).append(" AND ").append(d2).append(')'); sascha@349: } sascha@349: } // class Segment sascha@349: sascha@349: protected Segment head; sascha@349: sascha@349: protected String iColumn; sascha@349: protected String jColumn; sascha@349: sascha@349: public IndexBuffer(List points) { sascha@349: this(points, I_COLUMN, J_COLUMN); sascha@349: } sascha@349: sascha@349: public IndexBuffer(List points, String iColumn, String jColumn) { sascha@349: this.iColumn = iColumn; sascha@349: this.jColumn = jColumn; sascha@349: sascha@349: for (int i = 1, N = points.size(); i < N; ++i) { sascha@349: Point p1 = (Point)points.get(i-1); sascha@349: Point p2 = (Point)points.get(i); sascha@349: head = new Segment(p1, p2, head); sascha@349: } sascha@349: } sascha@349: sascha@349: public boolean check(int i, int j) { sascha@349: sascha@349: Segment current = head; sascha@349: while (current != null) { sascha@349: if (current.check(i, j)) { sascha@349: return true; sascha@349: } sascha@349: current = current.next; sascha@349: } sascha@349: return false; sascha@349: } sascha@349: sascha@349: public String toWhereClause() { sascha@349: sascha@349: StringBuilder sb = new StringBuilder(); sascha@349: sascha@349: Segment current = head; sascha@349: sascha@349: while (current != null) { sascha@349: if (current != head) { sascha@349: sb.append(" OR "); sascha@349: } sascha@349: current.toWhereClause(sb, iColumn, jColumn); sascha@349: current = current.next; sascha@349: } sascha@349: sascha@349: return sb.toString(); sascha@349: } sascha@349: sascha@349: public static Point2D.Double sub(Point2D.Double p1, Point2D.Double p2) { sascha@349: return new Point2D.Double(p1.x - p2.x, p1.y - p2.y); sascha@349: } sascha@349: sascha@349: public static final double dot(Point2D.Double p1, Point2D.Double p2) { sascha@349: return p1.x*p2.x + p1.y*p2.y; sascha@349: } sascha@349: sascha@349: public static final double dot(Point2D.Double p1, double x, double y) { sascha@349: return p1.x*x + p1.y*y; sascha@349: } sascha@349: sascha@349: public static final Point2D.Double scale(Point2D.Double p, double s) { sascha@349: return new Point2D.Double(s*p.x, s*p.y); sascha@349: } sascha@349: sascha@349: public static final Point2D.Double normalize(Point2D.Double p) { sascha@349: double len2 = Math.sqrt(dot(p, p)); sascha@349: return len2 > EPSILON ? scale(p, 1d/len2) : p; sascha@349: } sascha@349: sascha@349: public static final Point2D.Double orthogonal(Point2D.Double p) { sascha@349: return new Point2D.Double(p.y, -p.x); sascha@349: } sascha@349: } sascha@798: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :