blob: aa09482b35806db09334a28a251bca9dcc84690c [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2010 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Research Group Software Construction,
* RWTH Aachen University, Germany - initial API and implementation
*
*******************************************************************************/
package org.eclipse.draw2d.geometry;
/**
* Represents a straight line within 2-dimensional Euclidean space.
*
* @author Alexander Nyssen
* @since 3.6
*/
public class Straight {
/** position vector of this straight */
public Vector position;
/** direction vector of this straight */
public Vector direction;
/**
* Constructs a new Straight with the given position and direction.
*
* @param position
* @param direction
*/
public Straight(Vector position, Vector direction) {
if (direction.isNull()) {
throw new IllegalArgumentException(
"direction has to be unequal to (0,0)"); //$NON-NLS-1$
}
this.position = position;
this.direction = direction;
}
/**
* Constructs a new Straight between the two given Points.
*
* @param point1
* a first waypoint of the Straight to be constructed
* @param point2
* a second waypoint of the Straight to be constructed
*/
public Straight(PrecisionPoint point1, PrecisionPoint point2) {
this(new Vector(point1), new Vector(point1, point2));
}
/**
* Checks whether this Straight and the provided one have an intersection
* point.
*
* @param other
* The Straight to use for the calculation.
* @return true if the two Straights intersect, false otherwise.
*/
public boolean intersects(Straight other) {
return direction.getDotProduct(other.direction
.getOrthogonalComplement()) != 0;
}
/**
* Checks whether this Straight and the provided one have an intersection
* point, which is inside the specified segment between segmentStart and
* segmentEnd.
*
* segmentStart a Vector indicating the start point of the segment. Has to
* be a point on the straight.
*
* @param segmentEnd
* a Vector indicating the end point of the segment. Has to be a
* point on the straight.
* @param other
* the Straight to test
* @return true if the true straights intersect and the intersection point
* is contained within the specified segment, false otherwise.
* @since 3.2
*/
public boolean intersectsWithinSegment(Vector segmentStart,
Vector segmentEnd, Straight other) {
// precondition: segment start and end have to be points on this
// straight.
if (!contains(segmentStart) || !contains(segmentEnd)) {
throw new IllegalArgumentException(
"segment points have to be contained"); //$NON-NLS-1$
}
// check if segmentStart->segmentEnd is a legal segment or a single
// point
Vector segmentDirection = segmentEnd.getSubtracted(segmentStart);
if (segmentDirection.isNull()) {
return other.contains(segmentStart);
}
// legal segment, check if there is an intersection within the segment
if (intersects(other)) {
Vector intersection = getIntersection(other);
return containsWithinSegment(segmentStart, segmentEnd, intersection);
}
return false;
}
/**
* Computes the intersection point of this Straight and the provided one, if
* it exists.
*
* @param other
* The Straight to use for calculations.
* @return A Vector pointing to the intersection point, if it exists, null
* if no intersection point exists (or the Straights are equal).
*/
public Vector getIntersection(Straight other) {
// first check if there is a single intersection point
if (!intersects(other)) {
return null;
}
// calculate intersection point
Vector s1 = direction.getMultiplied(other.position
.getDotProduct(other.direction.getOrthogonalComplement()));
Vector s2 = other.direction.getMultiplied(position
.getDotProduct(direction.getOrthogonalComplement()));
return s1.getSubtracted(s2).getDivided(
direction.getDotProduct(other.direction
.getOrthogonalComplement()));
}
/**
* Returns the (smallest) angle between this Straight and the provided one.
*
* @param other
* The Straight to be used for the calculation.
* @return The angle spanned between the two Straights.
*/
public double getAngle(Straight other) {
return direction.getAngle(other.direction);
}
/**
* Returns the projection of the given Vector onto this Straight, which is
* the point on this Straight with the minimal distance to the point,
* denoted by the provided Vector.
*
* @param vector
* The Vector whose projection should be determined.
* @return A new Vector representing the projection of the provided Vector
* onto this Straight.
*/
public Vector getProjection(Vector vector) {
return getIntersection(new Straight(vector,
direction.getOrthogonalComplement()));
}
/**
* Returns the distance of the provided Vector to this Straight, which is
* the distance between the provided Vector and its projection onto this
* Straight.
*
* @param vector
* The Vector whose distance is to be calculated.
* @return the distance between this Straight and the provided Vector.
*/
public double getDistance(Vector vector) {
return getProjection(vector).getSubtracted(vector).getLength();
}
/**
* Calculates whether the point indicated by the provided Vector is a point
* on this Straight.
*
* @param vector
* the Vector who has to be checked.
* @return true if the point indicated by the given Vector is a point of
* this Straight, false otherwise.
*/
public boolean contains(Vector vector) {
return getDistance(vector) == 0;
}
/**
* Calculates whether the point indicated by the provided Vector is a point
* on the straight segment between the given start and end points.
*
* @param segmentStart
* a Vector indicating the start point of the segment. Has to be
* a point on the straight.
* @param segmentEnd
* a Vector indicating the end point of the segment. Has to be a
* point on the straight.
* @param vector
* the Vector who has to be checked.
* @return true if point indicated by the given Vector is a point on this
* straight, within the specified segment, false otherwise.
*/
public boolean containsWithinSegment(Vector segmentStart,
Vector segmentEnd, Vector vector) {
// precondition: segment start and end have to be points on this
// straight.
if (!contains(segmentStart) || !contains(segmentEnd)) {
throw new IllegalArgumentException(
"segment points have to be contained"); //$NON-NLS-1$
}
// check if segmentStart->segmentEnd is a legal segment or a single
// point
Vector segmentDirection = segmentEnd.getSubtracted(segmentStart);
if (segmentDirection.isNull()) {
return segmentStart.equals(vector);
}
// legal segment
if (new Straight(segmentStart, segmentDirection).contains(vector)) {
// compute parameter s, so that vector = segmentStart + s *
// (segmentEnd - segmentStart).
double s = segmentDirection.isVertical() ? (vector.y - segmentDirection.y)
/ segmentDirection.y
: (vector.x - segmentStart.x) / segmentDirection.x;
// if s is between 0 and 1, intersection point lies within
// segment
if (0 <= s && s <= 1) {
return true;
}
}
return false;
}
/**
* Checks whether this Straight and the provided one are parallel to each
* other.
*
* @param other
* The Straight to test for parallelism.
* @return true if the direction vectors of this Straight and the provided
* one are parallel, false otherwise.
*/
public boolean isParallelTo(Straight other) {
return direction.isParallelTo(other.direction);
}
/**
* Checks whether this Straight is equal to the provided Straight. Two
* Straights s1 and s2 are equal, if the position vector of s2 is a point on
* s1 and the direction vectors of s1 and s2 are parallel.
*
* @see java.lang.Object#equals(java.lang.Object)
*/
public boolean equals(Object other) {
if (!(other instanceof Straight)) {
return false;
} else {
Straight otherStraight = (Straight) other;
return contains(otherStraight.position)
&& isParallelTo(otherStraight);
}
}
/**
* @see java.lang.Object#hashCode()
*/
public int hashCode() {
return position.hashCode() + direction.hashCode();
}
/**
* @see java.lang.Object#toString()
*/
public String toString() {
return position.toString() + " + s * " + direction.toString(); //$NON-NLS-1$
}
}