| /******************************************************************************* |
| * 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$ |
| } |
| |
| } |