/* File Line2D.java 
 *
 * Project : Java Geometry Library
 *
 * ===========================================
 * 
 * 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, either version 2.1 of the License, or (at
 * your option) any later version.
 *
 * 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.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library. if not, write to :
 * The Free Software Foundation, Inc., 59 Temple Place, Suite 330,
 * Boston, MA 02111-1307, USA.
 */

// package

package math.geom2d.line;

import java.util.Collection;

import math.geom2d.*;
import math.geom2d.circulinear.CirculinearDomain2D;
import math.geom2d.circulinear.CirculinearElement2D;
import math.geom2d.circulinear.buffer.BufferCalculator;
import math.geom2d.conic.CircleArc2D;
import math.geom2d.curve.*;
import math.geom2d.transform.CircleInversion2D;

// Imports

/**
 * Line object defined from 2 points. This object keep points reference in
 * memory, and recomputes properties directly from points. Line2D is
 * mutable.
 * 

* Example : *

* * // Create an Edge2D
* Line2D line = new Line2D(new Point2D(0, 0), new Point2D(1, 2));
* // Change direction of line, by changing second point :
* line.setPoint2(new Point2D(4, 5));
* // Change position and direction of the line, by changing first point.
* // 'line' is now the edge (2,3)-(4,5)
* line.setPoint1(new Point2D(2, 3));
*
*

*

* This class may be slower than Edge2D or StraightLine2D, because parameters * are updated each time a computation is made, causing lot of additional * processing. Moreover, as inner point fields are public, it is not as safe * as {@link math.geom2d.line.LineSegment2D}. */ public class Line2D extends AbstractSmoothCurve2D implements LinearElement2D, Cloneable { // =================================================================== // constants // =================================================================== // class variables /** * The origin point. */ public Point2D p1; /** * The destination point. */ public Point2D p2; // =================================================================== // constructors /** * Checks if two line intersect. Uses the * {@link math.geom2d.Point2D#ccw(Point2D, Point2D, Point2D) Point2D.ccw} * method, which is based on Sedgewick algorithm. * * @param line1 a Line2D object * @param line2 a Line2D object * @return true if the 2 lines intersect */ public static boolean intersects(Line2D line1, Line2D line2) { Point2D e1p1 = line1.firstPoint(); Point2D e1p2 = line1.lastPoint(); Point2D e2p1 = line2.firstPoint(); Point2D e2p2 = line2.lastPoint(); boolean b1 = Point2D.ccw(e1p1, e1p2, e2p1) * Point2D.ccw(e1p1, e1p2, e2p2) <= 0; boolean b2 = Point2D.ccw(e2p1, e2p2, e1p1) * Point2D.ccw(e2p1, e2p2, e1p2) <= 0; return b1 && b2; } // =================================================================== // constructors /** Define a new Line2D with two extremities. */ public Line2D(Point2D point1, Point2D point2) { this.p1 = point1; this.p2 = point2; } /** Define a new Line2D with two extremities. */ public Line2D(double x1, double y1, double x2, double y2) { p1 = new Point2D(x1, y1); p2 = new Point2D(x2, y2); } /** * Copy constructor. */ public Line2D(Line2D line) { this(line.getPoint1(), line.getPoint2()); } // =================================================================== // Static factory /** * Static factory for creating a new Line2D, starting from p1 * and finishing at p2. * @deprecated since 0.11.1 */ @Deprecated public static Line2D create(Point2D p1, Point2D p2) { return new Line2D(p1, p2); } // =================================================================== // Methods specific to Line2D /** * Return the first point of the edge. It corresponds to getPoint(0). * * @return the first point. */ public Point2D getPoint1() { return p1; } /** * Return the last point of the edge. It corresponds to getPoint(1). * * @return the last point. */ public Point2D getPoint2() { return p2; } public double getX1() { return p1.x(); } public double getY1() { return p1.y(); } public double getX2() { return p2.x(); } public double getY2() { return p2.y(); } /** * Return the opposite vertex of the edge. * * @param point : one of the vertices of the edge * @return the other vertex */ public Point2D getOtherPoint(Point2D point) { if (point.equals(p1)) return p2; if (point.equals(p2)) return p1; return null; } public void setPoint1(Point2D point) { p1 = point; } public void setPoint2(Point2D point) { p2 = point; } // =================================================================== // methods implementing the LinearShape2D interface public boolean isColinear(LinearShape2D line) { return new LineSegment2D(p1, p2).isColinear(line); } /** * Test if the this object is parallel to the given one. This method is * overloaded to update parameters before computation. */ public boolean isParallel(LinearShape2D line) { return new LineSegment2D(p1, p2).isParallel(line); } // =================================================================== // methods implementing the CirculinearCurve2D interface /* (non-Javadoc) * @see math.geom2d.circulinear.CirculinearShape2D#buffer(double) */ public CirculinearDomain2D buffer(double dist) { BufferCalculator bc = BufferCalculator.getDefaultInstance(); return bc.computeBuffer(this, dist); } /* (non-Javadoc) * @see math.geom2d.circulinear.CirculinearCurve2D#parallel(double) */ public Line2D parallel(double d) { double x0 = getX1(); double y0 = getY1(); double dx = getX2()-x0; double dy = getY2()-y0; double d2 = d / Math.hypot(dx, dy); return new Line2D( x0 + dy * d2, y0 - dx * d2, x0 + dx + dy * d2, y0 + dy - dx * d2); } /* (non-Javadoc) * @see math.geom2d.circulinear.CirculinearCurve2D#length() */ public double length() { return p1.distance(p2); } /* (non-Javadoc) * @see math.geom2d.circulinear.CirculinearCurve2D#length(double) */ public double length(double pos) { double dx = p2.x() - p1.x(); double dy = p2.y() - p1.y(); return pos * Math.hypot(dx, dy); } /* (non-Javadoc) * @see math.geom2d.circulinear.CirculinearCurve2D#position(double) */ public double position(double length) { double dx = p2.x() - p1.x(); double dy = p2.y() - p1.y(); return length / Math.hypot(dx, dy); } /* (non-Javadoc) * @see math.geom2d.circulinear.CirculinearCurve2D#transform(math.geom2d.transform.CircleInversion2D) */ public CirculinearElement2D transform(CircleInversion2D inv) { // Extract inversion parameters Point2D center = inv.center(); double r = inv.radius(); // compute distance of line to inversion center Point2D po = new StraightLine2D(this).projectedPoint(center); double d = this.distance(po); // Degenerate case of a line passing through the center. // returns the line itself. if (Math.abs(d) < Shape2D.ACCURACY){ Point2D p1 = this.firstPoint().transform(inv); Point2D p2 = this.lastPoint().transform(inv); return new LineSegment2D(p1, p2); } // angle from center to line double angle = Angle2D.horizontalAngle(center, po); // center of transformed circle double r2 = r * r / d / 2; Point2D c2 = Point2D.createPolar(center, r2, angle); // choose direction of circle arc boolean direct = !this.isInside(center); // compute angle between center of transformed circle and end points double theta1 = Angle2D.horizontalAngle(c2, p1); double theta2 = Angle2D.horizontalAngle(c2, p2); // create the new circle arc return new CircleArc2D(c2, r2, theta1, theta2, direct); } // =================================================================== // methods implementing the LinearShape2D interface /* (non-Javadoc) */ public double[][] parametric() { return new LineSegment2D(p1, p2).parametric(); } public double[] cartesianEquation() { return new LineSegment2D(p1, p2).cartesianEquation(); } public double[] polarCoefficients() { return new LineSegment2D(p1, p2).polarCoefficients(); } public double[] polarCoefficientsSigned() { return new LineSegment2D(p1, p2).polarCoefficientsSigned(); } // =================================================================== // methods implementing the LinearShape2D interface public double horizontalAngle() { return new LineSegment2D(p1, p2).horizontalAngle(); } /* (non-Javadoc) * @see math.geom2d.line.LinearShape2D#intersection(math.geom2d.line.LinearShape2D) */ public Point2D intersection(LinearShape2D line) { return new LineSegment2D(p1, p2).intersection(line); } /* (non-Javadoc) * @see math.geom2d.line.LinearShape2D#origin() */ public Point2D origin() { return p1; } /* (non-Javadoc) * @see math.geom2d.line.LinearShape2D#supportingLine() */ public StraightLine2D supportingLine() { return new StraightLine2D(p1, p2); } /* (non-Javadoc) * @see math.geom2d.line.LinearShape2D#direction() */ public Vector2D direction() { return new Vector2D(p1, p2); } // =================================================================== // methods implementing the OrientedCurve2D interface public double signedDistance(Point2D p) { return signedDistance(p.x(), p.y()); } public double signedDistance(double x, double y) { return new LineSegment2D(p1, p2).signedDistance(x, y); } // =================================================================== // methods implementing the ContinuousCurve2D interface /* (non-Javadoc) * @see math.geom2d.curve.ContinuousCurve2D#smoothPieces() */ @Override public Collection smoothPieces() { return wrapCurve(this); } /** * Returns false. * @see math.geom2d.curve.ContinuousCurve2D#isClosed() */ public boolean isClosed() { return false; } // =================================================================== // methods implementing the Shape2D interface /** * Returns the distance of the point p to this edge. */ public double distance(Point2D p) { return distance(p.x(), p.y()); } /** * Returns the distance of the point (x, y) to this edge. */ public double distance(double x, double y) { // project the point on the support line StraightLine2D support = new StraightLine2D(p1, p2); Point2D proj = support.projectedPoint(x, y); // if this line contains the projection, return orthogonal distance if (contains(proj)) return proj.distance(x, y); // return distance to closest extremity double d1 = Math.hypot(p1.x() - x, p1.y() - y); double d2 = Math.hypot(p2.x() - x, p2.y() - y); return Math.min(d1, d2); } /** * Creates a straight line parallel to this object, and passing through * the given point. * * @param point the point to go through * @return the parallel through the point */ public StraightLine2D parallel(Point2D point) { return new LineSegment2D(p1, p2).parallel(point); } /** * Creates a straight line perpendicular to this object, and passing * through the given point. * * @param point the point to go through * @return the perpendicular through point */ public StraightLine2D perpendicular(Point2D point) { return new LineSegment2D(p1, p2).perpendicular(point); } /** * Clips the line object by a box. The result is an instance of CurveSet2D, * which contains only instances of LineArc2D. If the line object is not * clipped, the result is an instance of CurveSet2D which * contains 0 curves. */ public CurveSet2D clip(Box2D box) { // Clip the curve CurveSet2D set = Curves2D.clipCurve(this, box); // Stores the result in appropriate structure CurveArray2D result = new CurveArray2D(set.size()); // convert the result for (Curve2D curve : set.curves()) { if (curve instanceof Line2D) result.add((Line2D) curve); } return result; } /** * Returns the bounding box of the Line2D. */ public Box2D boundingBox() { return new Box2D(p1, p2); } // =================================================================== // methods inherited from SmoothCurve2D interface public Vector2D tangent(double t) { return new Vector2D(p1, p2); } /** * Returns 0 as every linear shape. */ public double curvature(double t) { return 0.0; } // =================================================================== // methods inherited from OrientedCurve2D interface public double windingAngle(Point2D point) { return new LineSegment2D(p1, p2).windingAngle(point); } public boolean isInside(Point2D point) { return new LineSegment2D(p1, p2).signedDistance(point)<0; } // =================================================================== // methods inherited from Curve2D interface /** * Returns 0. */ public double t0() { return 0.0; } /** * @deprecated replaced by t0() (since 0.11.1). */ @Deprecated public double getT0() { return t0(); } /** * Returns 1. */ public double t1() { return 1.0; } /** * @deprecated replaced by t1() (since 0.11.1). */ @Deprecated public double getT1() { return t1(); } public Point2D point(double t) { t = Math.min(Math.max(t, 0), 1); double x = p1.x() * (1 - t) + p2.x() * t; double y = p1.y() * (1 - t) + p2.y() * t; return new Point2D(x, y); } /** * Get the first point of the curve. * * @return the first point of the curve */ @Override public Point2D firstPoint() { return p1; } /** * Get the last point of the curve. * * @return the last point of the curve. */ @Override public Point2D lastPoint() { return p2; } /** * Returns the position of the point on the line. If point belongs to the * line, this position is defined by the ratio: *

* t = (xp - x0)/dx <\code>, or equivalently :

* t = (yp - y0)/dy <\code>.

* If point does not belong to edge, return Double.NaN. The current implementation * uses the direction with the biggest derivative, in order to avoid divisions * by zero. */ public double position(Point2D point) { return new LineSegment2D(p1, p2).position(point); } public double project(Point2D point) { return new LineSegment2D(p1, p2).project(point); } /** * Returns the Line2D object which starts at point2 and ends at * point1. */ public Line2D reverse() { return new Line2D(p2, p1); } @Override public Collection continuousCurves() { return wrapCurve(this); } /** * Returns a new Line2D, which is the portion of the line delimited by * parameters t0 and t1. */ public Line2D subCurve(double t0, double t1) { if(t0 > t1) return null; t0 = Math.max(t0, t0()); t1 = Math.min(t1, t1()); return new Line2D(this.point(t0), this.point(t1)); } /* (non-Javadoc) * @see math.geom2d.curve.Curve2D#intersections(math.geom2d.line.LinearShape2D) */ public Collection intersections(LinearShape2D line) { return new LineSegment2D(p1, p2).intersections(line); } // =================================================================== // methods inherited from Shape2D interface public Line2D transform(AffineTransform2D trans) { return new Line2D( p1.transform(trans), p2.transform(trans)); } // =================================================================== // methods inherited from Shape interface /** * Returns true if the point (x, y) lies on the line, with precision given * by Shape2D.ACCURACY. */ public boolean contains(double x, double y) { return new LineSegment2D(p1, p2).contains(x, y); } /** * Returns true if the point p lies on the line, with precision given by * Shape2D.ACCURACY. */ public boolean contains(Point2D p) { return contains(p.x(), p.y()); } /** * Returns true */ public boolean isBounded() { return true; } /** * Returns false */ public boolean isEmpty() { return false; } public java.awt.geom.GeneralPath getGeneralPath() { java.awt.geom.GeneralPath path = new java.awt.geom.GeneralPath(); path.moveTo((float) p1.x(), (float) p1.y()); path.lineTo((float) p2.x(), (float) p2.y()); return path; } public java.awt.geom.GeneralPath appendPath(java.awt.geom.GeneralPath path) { path.lineTo((float) p2.x(), (float) p2.y()); return path; } // =================================================================== // methods implementing the GeometricObject2D interface /* (non-Javadoc) * @see math.geom2d.GeometricObject2D#almostEquals(math.geom2d.GeometricObject2D, double) */ public boolean almostEquals(GeometricObject2D obj, double eps) { if (this==obj) return true; // check class if(!(obj instanceof Line2D)) return false; // cast class, and compare members Line2D edge = (Line2D) obj; return p1.almostEquals(edge.p1, eps) && p2.almostEquals(edge.p2, eps); } // =================================================================== // methods inherited from Object interface @Override public String toString() { return "Line2D(" + p1 + ")-(" + p2 + ")"; } /** * Two Line2D are equals if the share the two same points, * in the same order. * * @param obj the edge to compare to. * @return true if extremities of both edges are the same. */ @Override public boolean equals(Object obj) { if (this == obj) return true; if(!(obj instanceof Line2D)) return false; // cast class, and compare members Line2D edge = (Line2D) obj; return p1.equals(edge.p1) && p2.equals(edge.p2); } /** * @deprecated use copy constructor instead (0.11.2) */ @Deprecated @Override public Line2D clone() { return new Line2D(p1, p2); } }

Ads help maintain this website.