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 <a href="mailto:sascha.teichmann@intevation.de">Sascha L. Teichmann</a>
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<? extends Point> points) {
sascha@349:         this(points, I_COLUMN, J_COLUMN);
sascha@349:     }
sascha@349: 
sascha@349:     public IndexBuffer(List<? extends Point> 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 :