/* * Copyright (C) 2014 Alec Dhuse * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package co.foldingmap.map.vector; import co.foldingmap.map.vector.Coordinate; import java.awt.Point; import java.awt.geom.FlatteningPathIterator; import java.awt.geom.GeneralPath; import java.awt.geom.Line2D; import java.awt.geom.PathIterator; /** * The Intersection class provides methods for determining * the intersection point of two lines and the intersection * point of a line and a GeneralPath object. * * @author Jesus M. Salvo Jr. */ public class Intersection { /** * Returns the intersection point of two lines. * * @param line1 First line * @param line2 Second line * @return The Point object where the two lines intersect. This method * returns null if the two lines do not intersect. * @throws <tt>MultipleIntersectionException</tt> when the two lines * have more than one intersection point. */ static public Point getIntersection( Line2D line1, Line2D line2 ) throws Exception { double dyline1, dxline1; double dyline2, dxline2, e, f; double x1line1, y1line1, x2line1, y2line1; double x1line2, y1line2, x2line2, y2line2; if ( !line1.intersectsLine( line2 ) ) return null; /* first, check to see if the segments intersect by parameterization on s and t; if s and t are both between [0,1], then the segments intersect */ x1line1 = (double)line1.getX1(); y1line1 = (double)line1.getY1(); x2line1 = (double)line1.getX2(); y2line1 = (double)line1.getY2(); x1line2 = (double)line2.getX1(); y1line2 = (double)line2.getY1(); x2line2 = (double)line2.getX2(); y2line2 = (double)line2.getY2(); /* check to see if the segments have any endpoints in common. If they do, then return the endpoints as the intersection point */ if ((x1line1==x1line2) && (y1line1==y1line2)) { return (new Point( (int) x1line1, (int) y1line1)); } if ((x1line1==x2line2) && (y1line1==y2line2)) { return (new Point( (int) x1line1, (int) y1line1)); } if ((x2line1==x1line2) && (y2line1==y1line2)) { return (new Point( (int) x2line1, (int) y2line1)); } if ((x2line1==x2line2) && (y2line1==y2line2)) { return (new Point( (int) x2line1, (int) y2line1)); } dyline1 = -( y2line1 - y1line1 ); dxline1 = x2line1 - x1line1; dyline2 = -( y2line2 - y1line2 ); dxline2 = x2line2 - x1line2; e = -(dyline1 * x1line1) - (dxline1 * y1line1); f = -(dyline2 * x1line2) - (dxline2 * y1line2); /* compute the intersection point using ax+by+e = 0 and cx+dy+f = 0 If there is more than 1 intersection point between two lines, */ if( (dyline1 * dxline2 - dyline2 * dxline1) == 0 ) throw new Exception(); return (new Point( (int) (-(e * dxline2 - dxline1 * f)/(dyline1 * dxline2 - dyline2 * dxline1)), (int) (-(dyline1 * f - dyline2 * e)/(dyline1 * dxline2 - dyline2 * dxline1)))); } /** * Returns the intersection point of a line and a GeneralPath. Given that * a line can intersect more than one segment of a GeneralPath, this method * will return the intersection point of the first segment, returned by * a PathIterator, and the line. No consideration is taken if the line * intersects more than one segment of the GeneralPath since this is internally * used by salvo.jesus.graph.VisualEdge wherein the edge of a line * will intersect only one segment of the VisualVertex's GeneralPath. * * @param line1 First line * @param path GeneralPath representing line segments * @return The Point object where the line and the GeneralPath object intersect. * This method returns null if they do not intersect. */ static public boolean getIntersection( Line2D line, GeneralPath path ){ boolean intersects = false; Line2D.Double rectline = new Line2D.Double(); Point intersectpoint = null; Point testintersectpoint = null; Point previousintersectpoint; Point lineorigin = new Point( (int) line.getX1(), (int) line.getY1() ); FlatteningPathIterator pathiterator; double coords[] = new double[6]; int segmenttype; double prevx = -1, prevy = -1; // Iterate through the segments pathiterator = new FlatteningPathIterator( path.getPathIterator( null ), 1.0 ); while( !pathiterator.isDone() ){ segmenttype = pathiterator.currentSegment( coords ); // Since we are are iterating through a GeneralPath, all segments // are guaranteed to be a line. switch (segmenttype){ case PathIterator.SEG_MOVETO: prevx = coords[0]; prevy = coords[1]; break; case PathIterator.SEG_QUADTO: case PathIterator.SEG_CUBICTO: case PathIterator.SEG_LINETO: // If prevx or prev = -1, then we do not have an initial SEG_MOVETO yet. // Therefore, the if block does not get executed and the coordinates // are treated as if it were a SEG_MOVETO. if( prevx != -1 && prevy != 1 ){ // Check if the line segment intersects with the line in the argument rectline.setLine( prevx, prevy, coords[0], coords[1] ); // Workaround at the moment try { testintersectpoint = getIntersection( line, rectline ); } catch( Exception ex ) { intersects = true; } if (testintersectpoint != null) intersects = true; } prevx = coords[0]; prevy = coords[1]; break; } pathiterator.next(); } return intersects; } /** * * @param c1 First coordinate in the first line * @param c2 Second coordinate in the first line * @param c3 First coordinate in the second line * @param c4 Second coordinate in the second line * @return */ static public Coordinate getIntersection(Coordinate c1, Coordinate c2, Coordinate c3, Coordinate c4) { Coordinate intersectionCoordinate; Line2D line1, line2; Point intersectionPoint; intersectionCoordinate = Coordinate.UNKNOWN_COORDINATE; try { line1 = new Line2D.Double(c1.getAsPoint2D(), c2.getAsPoint2D()); line2 = new Line2D.Double(c3.getAsPoint2D(), c4.getAsPoint2D()); intersectionPoint = getIntersection(line1, line2); intersectionCoordinate = new Coordinate(0, intersectionPoint.y, intersectionPoint.x); } catch (Exception e) { System.err.println("Error in Intersection.getIntersection - " + e); } return intersectionCoordinate; } }