/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2006-2008, Open Source Geospatial Foundation (OSGeo) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. */ package org.geotools.geometry.iso.util.algorithm2D; import java.awt.geom.AffineTransform; import java.awt.geom.GeneralPath; import java.awt.geom.Line2D; import java.awt.geom.PathIterator; import java.awt.geom.Point2D; import java.util.ArrayList; import java.util.Stack; /** * @author roehrig * * TODO To change the template for this generated type comment go to * Window - Preferences - Java - Code Style - Code Templates * * * * @source $URL$ */ public class AlgoLine2D { public static final int EQUALSEGMENT = 1; public static final int OPPOSITESEGMENT = -1; public static final int DIFFERENTSEGMENT = 0; public static double length(Line2D line) { return line.getP1().distance(line.getP2()); } public static ArrayList<Line2D> splitLines(double maxLength, ArrayList<Line2D> lines) { if (maxLength<=0.0) return lines; ArrayList<Line2D> result = new ArrayList<Line2D>(lines.size()); for (int i = 0; i<lines.size();++i) { Line2D line = (Line2D)lines.get(i); if (AlgoLine2D.length(line) > maxLength) { result.addAll(AlgoLine2D.split(line,maxLength)); } else { result.add(line); } } return result; } /** * @param maxLength */ public static ArrayList<Line2D> split(Line2D line, double maxSpacing) { ArrayList<Line2D> result = new ArrayList<Line2D>(); int n = (int) Math.ceil(AlgoLine2D.length(line) / maxSpacing); double x1 = line.getX1(); double y1 = line.getY1(); double x2 = line.getX2(); double y2 = line.getY2(); double deltaX = (x2-x1) / n; double deltaY = (y2-y1) / n; Point2D p1 = line.getP1(); for (int j = 1; j < n; ++j) { Point2D p2 = new Point2D.Double(x1 + deltaX * j, y1 + deltaY * j); result.add(new Line2D.Double(p1,p2)); p1 = p2; } /** add the last node*/ result.add(new Line2D.Double(p1,line.getP2())); return result; } // // first lines which are shorter as minLength will be merged // public static ArrayList mergeLines(double minLength, ArrayList lines) { // ArrayList result = new ArrayList(lines.size()); // int i = 0; // int j = 0; // while(i < lines.size()){ // Line2D line = (Line2D)lines.get(i); // if (line == lines.get(lines.size()-1)&& (AlgoLine.length(line) < minLength)&& (line.getP1().lineSize()< 3)){ // //line= line.merge(result.get(result.size()-1)); // line= (result.get(result.size()-1)).merge(line); // result.remove(result.size()-1); // result.add(line); // i++; // } // else if(AlgoLine.length(line) < minLength && (line.getP2().lineSize()< 3)){ // j=i+1; // while((AlgoLine.length(line) < minLength) && (j<=(lines.size()-1))&& (((AlgoLine)lines.get(j)).getP1().lineSize()< 3)){ // line = line.merge((AlgoLine)lines.get(j)); // j++; // } // i = j; // result.add(line); // }else { // result.add(line); // i += 1; // } // } // return result; // } // Ziethen 23.02.05 param minlengh // first lines witch are shorter as minLength will be merged public static Line2D merge(Line2D line, Line2D other) { Line2D.Double result = new Line2D.Double(line.getP1(),other.getP2()); return result; } public static boolean isParallel(Line2D l0, Line2D l1){ return AlgoLine2D.isParallel(l0.getP1(), l0.getP2(), l1.getP1(), l1.getP2()); } public static boolean isParallel(Point2D p0, Point2D p1, Point2D q0, Point2D q1) { return Math.abs((double)AlgoPoint2D.cross(AlgoPoint2D.subtract(p1,p0),AlgoPoint2D.subtract(q1,q0))) <= AlgoPoint2D.EPSILON; } public static double constrParamForPoint(Point2D p0 , Point2D p1 , Point2D dp) { // return the construction parametric coordinate (0.0 <= result <= 1.0) of // dp on the line (p0,p1) // if p0.equals(p1) then: if dp.equals(p0) return 0.0, else Double.NaN // if dp is close to p0 then result = 0.0 // if dp is close to p1 then result = 1.0 // if the line (p0,p1) does not contain dp then return Double.NaN double eps = AlgoPoint2D.EPSILON; double result = java.lang.Double.NaN; // return nothing if dp is not on the same line as (p0,p1): colinear if (!AlgoLine2D.isParallel(p0, p1, p0, dp)) return java.lang.Double.NaN; if (p0.equals(p1)) { if (AlgoPoint2D.equals(p0,dp,eps)) return 0.0; else return java.lang.Double.NaN; } if (Math.abs(p0.getX() - p1.getX()) > Math.abs(p0.getY() - p1.getY())) result = (dp.getX() - p0.getX()) / (p1.getX() - p0.getX()); else result = (dp.getY() - p0.getY()) / (p1.getY() - p0.getY()); if (Math.abs(result) <= eps) result = 0.0; if (Math.abs(1.0 - result) <= eps) result = 1.0; if (result < 0.0 || result > 1.0) return java.lang.Double.NaN; return result; } public static double orientation(Line2D line,Point2D point) { //(ZA)21.12.04 returns a Value about a Curve-Orientation (clockwise or counterclockwise) return AlgoPoint2D.cross((AlgoPoint2D.subtract(point,line.getP1())), AlgoPoint2D.subtract((line.getP2()),line.getP1())); } /** * @param dp * @return */ public static boolean rightSide(Line2D line, Point2D p) { /** * A return value of 1 relativeCCW indicates that the line segment must * turn in the direction that takes the positive X axis towards the * negative Y axis. In the default coordinate system used by Java 2D, * this direction is counterclockwise, in our coordinate system it is * clockwise (right side) * */ return rightSide(line.getP1(),line.getP2(),p); } public static boolean rightSide(Point2D p0, Point2D p1, Point2D p) { /** * A return value of 1 relativeCCW indicates that the line segment must * turn in the direction that takes the positive X axis towards the * negative Y axis. In the default coordinate system used by Java 2D, * this direction is counterclockwise, in our coordinate system it is * clockwise (right side) * */ return AlgoPoint2D.cross(AlgoPoint2D.subtract(p,p0),AlgoPoint2D.subtract(p1,p0)) > 0.0; } public static boolean leftSide(Line2D line, Point2D p) { return leftSide(line.getP1(),line.getP2(),p); //return this.relativeCCW(p) == -1; } public static boolean leftSide(Point2D p0, Point2D p1, Point2D p) { return AlgoPoint2D.cross(AlgoPoint2D.subtract(p,p0),AlgoPoint2D.subtract(p1,p0)) < 0.0; //return this.relativeCCW(p) == -1; } /** * Returns: * 0 if it is not the same segment, i.e !equal AND !inverted * 1 if it is equal, i.e. pa0.equals(pb0) && pa1.equals(pb1) * 2 if it is inverted, i.e. pa0.equals(pb1) && pa1.equals(pb0) * @return */ public static int sameSegment(Line2D lineA, Line2D lineB) { return sameSegment(lineA.getP1(), lineA.getP2(), lineB.getP1(), lineB.getP2()); } /** * Returns: * 0 if it is not the same segment, i.e !equal AND !inverted * 1 if it is equal, i.e. pa0.equals(pb0) && pa1.equals(pb1) * 2 if it is inverted, i.e. pa0.equals(pb1) && pa1.equals(pb0) * @return */ public static int sameSegment(Line2D line,Point2D pb0, Point2D pb1) { return sameSegment(line.getP1(), line.getP2(), pb0, pb1); } /** * Returns: * 0 if it is not the same segment, i.e !equal AND !inverted * 1 if it is equal, i.e. pa0.equals(pb0) && pa1.equals(pb1) * 2 if it is inverted, i.e. pa0.equals(pb1) && pa1.equals(pb0) * @param pa0 * @param pa1 * @param pb0 * @param pb1 * @return */ public static int sameSegment(Point2D pa0, Point2D pa1, Point2D pb0, Point2D pb1) { return (pa0.equals(pb0) && pa1.equals(pb1)) ? EQUALSEGMENT : (pa0.equals(pb1) && pa1.equals(pb0) ? OPPOSITESEGMENT : DIFFERENTSEGMENT); } public static Point2D evaluate( Line2D line, double r) { return AlgoPoint2D.evaluate(line.getP1(),line.getP2(),r); } public static GeneralPath reverse(GeneralPath path) { // JR uncomplete PathIterator pi = path.getPathIterator(new AffineTransform()); double[] coords = new double[6]; Stack<Point2D> ps = new Stack<Point2D>(); while (!pi.isDone()) { int type = pi.currentSegment(coords); if ((type == PathIterator.SEG_MOVETO) || (type == PathIterator.SEG_LINETO)) { ps.push(new Point2D.Double(coords[0], coords[1])); } pi.next(); } GeneralPath revPath = new GeneralPath(); Point2D.Double p = (Point2D.Double)ps.pop(); revPath.moveTo((float) p.x, (float) p.y); while (!ps.empty()) { revPath.lineTo((float) p.x, (float) p.y); } return revPath; } public static double getAngle2D(Line2D line, Point2D point) { // * p1 // / // / // / // *------>* // (0,0) this return AlgoPoint2D.getAngle2D(AlgoPoint2D.subtract(line.getP2(),line.getP1()), point); } }