/* File LineSegment2D.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 math.geom2d.*;
import math.geom2d.circulinear.CirculinearElement2D;
import math.utils.EqualUtils;


/**
 * Line segment, defined as the set of points located between the two end
 * points.
 */
public class LineSegment2D extends AbstractLine2D
implements Cloneable, CirculinearElement2D {

    // ===================================================================
    // static constructors

    /**
     * Static factory for creating a new line segment between two points.
	 * @deprecated since 0.11.1
	 */
	@Deprecated
    public static LineSegment2D create(Point2D p1, Point2D p2) {
    	return new LineSegment2D(p1, p2);
    }

    /**
     * Returns the straight line that is the median of the edge extremities.
     */
	public static StraightLine2D getMedian(LineSegment2D edge) {
		return new StraightLine2D(
				edge.x0 + edge.dx * .5, 
				edge.y0 + edge.dy * .5, 
				-edge.dy, edge.dx);
    }
    
    /**
     * Returns angle between two edges sharing one vertex.
     */
	public static double getEdgeAngle(LineSegment2D edge1, LineSegment2D edge2) {
		double x0, y0, x1, y1, x2, y2;

		if (Math.abs(edge1.x0 - edge2.x0) < Shape2D.ACCURACY
				&& Math.abs(edge1.y0 - edge2.y0) < Shape2D.ACCURACY) {
			x0 = edge1.x0;
			y0 = edge1.y0;
			x1 = edge1.x0 + edge1.dx;
			y1 = edge1.y0 + edge1.dy;
			x2 = edge2.x0 + edge2.dx;
			y2 = edge2.y0 + edge2.dy;
		} else if (Math.abs(edge1.x0 + edge1.dx - edge2.x0) < Shape2D.ACCURACY
				&& Math.abs(edge1.y0 + edge1.dy - edge2.y0) < Shape2D.ACCURACY) {
			x0 = edge1.x0 + edge1.dx;
			y0 = edge1.y0 + edge1.dy;
			x1 = edge1.x0;
			y1 = edge1.y0;
			x2 = edge2.x0 + edge2.dx;
			y2 = edge2.y0 + edge2.dy;
		} else if (Math.abs(edge1.x0 + edge1.dx - edge2.x0 - edge2.dx) < Shape2D.ACCURACY
				&& Math.abs(edge1.y0 + edge1.dy - edge2.y0 - edge2.dy) < Shape2D.ACCURACY) {
			x0 = edge1.x0 + edge1.dx;
			y0 = edge1.y0 + edge1.dy;
			x1 = edge1.x0;
			y1 = edge1.y0;
			x2 = edge2.x0;
			y2 = edge2.y0;
		} else if (Math.abs(edge1.x0 - edge2.x0 - edge2.dx) < Shape2D.ACCURACY
				&& Math.abs(edge1.y0 - edge2.y0 - edge2.dy) < Shape2D.ACCURACY) {
			x0 = edge1.x0;
			y0 = edge1.y0;
			x1 = edge1.x0 + edge1.dx;
			y1 = edge1.y0 + edge1.dy;
			x2 = edge2.x0;
			y2 = edge2.y0;
		} else {// no common vertex -> return NaN
			return Double.NaN;
		}

		return Angle2D.angle(new Vector2D(x1 - x0, y1 - y0), new Vector2D(x2
				- x0, y2 - y0));
	}

    /**
     * Checks if two line segment intersect. Uses the Point2D.ccw() method,
     * which is based on Sedgewick algorithm.
     * 
     * @param edge1 a line segment
     * @param edge2 a line segment
     * @return true if the 2 line segments intersect
     */
	public static boolean intersects(LineSegment2D edge1, LineSegment2D edge2) {
		Point2D e1p1 = edge1.firstPoint();
		Point2D e1p2 = edge1.lastPoint();
		Point2D e2p1 = edge2.firstPoint();
		Point2D e2p2 = edge2.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

    /** Defines a new Edge with two extremities. */
    public LineSegment2D(Point2D point1, Point2D point2) {
        this(point1.x(), point1.y(), point2.x(), point2.y());
    }

    /** Defines a new Edge with two extremities. */
    public LineSegment2D(double x1, double y1, double x2, double y2) {
        super(x1, y1, x2-x1, y2-y1);
    }
    
    // ===================================================================
    // Methods specific to LineSegment2D

    /**
     * Returns the opposite vertex of the edge.
     * 
     * @param point one of the vertices of the edge
     * @return the other vertex, or null if point is nor a vertex of the edge
     */
	public Point2D opposite(Point2D point) {
		if (point.equals(new Point2D(x0, y0)))
			return new Point2D(x0 + dx, y0 + dy);
		if (point.equals(new Point2D(x0 + dx, y0 + dy)))
			return new Point2D(x0, y0);
		return null;
	}

	/**
	 * Returns the median of the edge, that is the locus of points located at
	 * equal distance of each vertex.
	 */
	public StraightLine2D getMedian() {
		// initial point is the middle of the edge -> x = x0+.5*dx
		// direction vector is the initial direction vector rotated by pi/2.
		return new StraightLine2D(x0 + dx * .5, y0 + dy * .5, -dy, dx);
	}


    // ===================================================================
    // methods implementing the CirculinearCurve2D interface

    /**
     * Returns the length of the line segment.
     */
	@Override
    public double length() {
        return Math.hypot(dx, dy);
    }

	/* (non-Javadoc)
	 * @see math.geom2d.circulinear.CirculinearCurve2D#parallel(double)
	 */
	public LineSegment2D parallel(double d) {
		double d2 = Math.hypot(dx, dy);
		if (Math.abs(d2) < Shape2D.ACCURACY)
			throw new DegeneratedLine2DException(
					"Can not compute parallel of degnerated edge", this);
		d2 = d / d2;
		return new LineSegment2D(
				x0 + dy * d2, y0 - dx * d2, 
				x0 + dx + dy * d2, y0 + dy - dx * d2);
	}

	
    // ===================================================================
    // Methods implementing the OrientedCurve2D interface

	/* (non-Javadoc)
	 * @see math.geom2d.domain.OrientedCurve2D#signedDistance(math.geom2d.Point2D)
	 */
	@Override
    public double signedDistance(double x, double y) {
        Point2D proj = super.projectedPoint(x, y);
        if (contains(proj))
            return super.signedDistance(x, y);

		double d = this.distance(x, y);
		return super.signedDistance(x, y) > 0 ? d : -d;
	}
    
    

    // ===================================================================
    // Methods implementing the Curve2D interface

    /**
     * Returns the first point of the edge.
     * 
     * @return the first point of the edge
     */
	@Override
    public Point2D firstPoint() {
        return new Point2D(x0, y0);
    }

    /**
     * Returns the last point of the edge.
     * 
     * @return the last point of the edge
     */
	@Override
	public Point2D lastPoint() {
		return new Point2D(x0 + dx, y0 + dy);
	}

    /**
     * Returns the parameter of the first point of the edge, equals to 0.
     */
    public double t0() {
        return 0.0;
    }

    /**
     * @deprecated replaced by t0() (since 0.11.1).
     */
    @Deprecated
    public double getT0() {
    	return t0();
    }

    /**
     * Returns the parameter of the last point of the edge, equals to 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);
		return new Point2D(x0 + dx * t, y0 + dy * t);
	}

    /**
     * Returns the LineSegment which start from last point of this line segment,
     * and which ends at the fist point of this last segment.
     */
	public LineSegment2D reverse() {
		return new LineSegment2D(x0 + dx, y0 + dy, x0, y0);
	}

    // ===================================================================
    // Methods implementing the Shape2D interface

    /**
     * Returns true
     */
    public boolean isBounded() {
        return true;
    }

    public boolean contains(double xp, double yp) {
        if (!super.supportContains(xp, yp))
            return false;

        // compute position on the line
        double t = positionOnLine(xp, yp);

		if (t < -ACCURACY)
			return false;
		if (t - 1 > ACCURACY)
			return false;

        return true;
    }

    /**
     * Get the distance of the point (x, y) to this edge.
     */
    @Override
	public double distance(double x, double y) {
		Point2D proj = super.projectedPoint(x, y);
		if (contains(proj))
			return proj.distance(x, y);
		double d1 = Math.hypot(x0 - x, y0 - y);
		double d2 = Math.hypot(x0 + dx - x, y0 + dy - y);
		return Math.min(d1, d2);
    }

    @Override
	public LineSegment2D transform(AffineTransform2D trans) {
		double[] tab = trans.coefficients();
		double x1 = x0 * tab[0] + y0 * tab[1] + tab[2];
		double y1 = x0 * tab[3] + y0 * tab[4] + tab[5];
		double x2 = (x0 + dx) * tab[0] + (y0 + dy) * tab[1] + tab[2];
		double y2 = (x0 + dx) * tab[3] + (y0 + dy) * tab[4] + tab[5];
		return new LineSegment2D(x1, y1, x2, y2);
	}

    /**
     * Returns the bounding box of this line segment.
     */
    public Box2D boundingBox() {
        return new Box2D(x0, x0+dx, y0, y0+dy);
    }

    // =================================
    // Methods implementing the Shape interface

    /**
     * Appends a line to the current path.
     * 
     * @param path the path to modify
     * @return the modified path
     */
	public java.awt.geom.GeneralPath appendPath(java.awt.geom.GeneralPath path) {
		path.lineTo((float) x0 + dx, (float) y0 + dy);
		return path;
	}

	/**
	 * deprecated
	 */
	public java.awt.geom.GeneralPath getGeneralPath() {
		java.awt.geom.GeneralPath path = new java.awt.geom.GeneralPath();
		path.moveTo((float) x0, (float) y0);
		path.lineTo((float) (x0 + dx), (float) (y0 + dy));
		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;

		if (!(obj instanceof LineSegment2D))
			return false;
		LineSegment2D edge = (LineSegment2D) obj;

		if (Math.abs(x0 - edge.x0) > eps)
			return false;
		if (Math.abs(y0 - edge.y0) > eps)
			return false;
		if (Math.abs(dx - edge.dx) > eps)
			return false;
		if (Math.abs(dy - edge.dy) > eps)
			return false;

		return true;
	}

    // ===================================================================
    // Methods implementing the Object interface

	@Override
	public String toString() {
		return new String("LineSegment2D[(" + x0 + "," + y0 + ")-(" + (x0 + dx)
				+ "," + (y0 + dy) + ")]");
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (!(obj instanceof LineSegment2D))
			return false;
		LineSegment2D that = (LineSegment2D) obj;

        // Compare each field
		if (!EqualUtils.areEqual(this.x0, that.x0)) 
			return false;
		if (!EqualUtils.areEqual(this.y0, that.y0)) 
			return false;
		if (!EqualUtils.areEqual(this.dx, that.dx)) 
			return false;
		if (!EqualUtils.areEqual(this.dy, that.dy)) 
			return false;

		return true;
	}

	/**
	 * @deprecated use copy constructor instead (0.11.2)
	 */
	@Deprecated
	@Override
	public LineSegment2D clone() {
		return new LineSegment2D(x0, y0, x0 + dx, y0 + dy);
	}
}

 

Ads help maintain this website.