/* * ome.util.math.geom2D.Line * * Copyright 2006 University of Dundee. All rights reserved. * Use is subject to license terms supplied in LICENSE.txt */ package ome.util.math.geom2D; /** * An orientated line in the Euclidean space <b>R</b><sup>2</sup>. * * @author Jean-Marie Burel      <a * href="mailto:j.burel@dundee.ac.uk">j.burel@dundee.ac.uk</a> * @author <br> * Andrea Falconi      <a * href="mailto:a.falconi@dundee.ac.uk"> a.falconi@dundee.ac.uk</a> * @version 2.2 <small> (<b>Internal version:</b> $Revision$ $Date: * 2005/06/09 15:01:32 $) </small> * @since OME2.2 */ public class Line { /** * The origin point of the line. Any point (within the line) that falls on * the half line that has the same orientation as the {@link #direction} * unit vector is said to have positive orientation — this also * includes the {@link #origin} point. All other points of the line are said * to have (strictly) negative orientation. */ public final PlanePoint origin; /** * The unit vector that, given the {@link #origin} point, identifies this * line. */ public final PlanePoint direction; /** * Creates a new object to represent the line passing through the * <code>o</code> and <code>p</code> points. The <code>o</code> point * is taken to define the origin of the line and the direction is defined by * the <i>op</i> vector. * * @param o * The origin of the line. Mustn't be <code>null</code>. * @param p * A point of the line. Mustn't be <code>null</code> nor the * same as <code>o</code>. */ public Line(PlanePoint o, PlanePoint p) { if (o == null) { throw new NullPointerException("No origin."); } if (p == null) { throw new NullPointerException("No point p."); } if (o.equals(p)) { throw new IllegalArgumentException("Need two different points."); } origin = o; direction = origin.vec(p).normalize(); } /** * Creates a new object to represent the line passing through <code>o</code> * and having direction <i>pq</i>. The <code>p</code> and <code>q</code> * points are, respectively, the tail and head of the vector <i>pq</i> that * is taken to define the direction of the line. * * @param p * Tail of a vector. Mustn't be <code>null</code>. * @param q * Head of a vector. Mustn't be <code>null</code> nor the same * as <code>q</code>. * @param o * The origin of the line. Mustn't be <code>null</code>. */ public Line(PlanePoint p, PlanePoint q, PlanePoint o) { if (p == null) { throw new NullPointerException("No point p."); } if (q == null) { throw new NullPointerException("No point q."); } if (o == null) { throw new NullPointerException("No origin."); } if (p.equals(q)) { throw new IllegalArgumentException("Need two different points."); } origin = o; direction = p.vec(q).normalize(); } /** * Returns the point of this line defined by <code>k</code>. More * precisely, this method returns the * <code>{@link #origin}+k{@link #direction}</code> point. * * @param k * The coefficient to select the point. * @return See above. */ public PlanePoint getPoint(double k) { return new PlanePoint(origin.x1 + k * direction.x1, origin.x2 + k * direction.x2); } /** * Tells whether the specified point lies on this line. * * @param p * The point to test. Mustn't be <code>null</code>. * @return <code>true</code> if <code>p</code> lies on this line, * <code>false</code> otherwise. */ public boolean lies(PlanePoint p) { if (p == null) { throw new NullPointerException("No point."); } if (direction.x1 == 0) { return p.x1 == origin.x1; } if (direction.x2 == 0) { return p.x2 == origin.x2; } double k1 = (p.x1 - origin.x1) / direction.x1, k2 = (p.x2 - origin.x2) / direction.x2; return k1 == k2; } /** * Tells whether the specified point lies on this line and within the * specified orientation. The <code>positiveOrientation</code> parameter * is used to specify which side (with respect to the {@link #origin}) of * the line to check. If <code>true</code>, then we check to see whether * <code>p</code> falls on the half line that has the same orientation as * the {@link #direction} unit vector — this also includes the * {@link #origin}. If <code>false</code>, we check to see whether * <code>p</code> falls on the opposite half line. * * @param p * The point to test. Mustn't be <code>null</code>. * @param positiveOrientation * <code>true</code> for the positive orientation, * <code>false</code> for the strictly negative orientation. * @return <code>true</code> if <code>p</code> lies on this line, * <code>false</code> otherwise. */ public boolean lies(PlanePoint p, boolean positiveOrientation) { if (!lies(p)) { return false; } double k; if (direction.x1 != 0) { k = (p.x1 - origin.x1) / direction.x1; } else { k = (p.x2 - origin.x2) / direction.x2; // direction.x2 can't be 0 } // too. if (positiveOrientation) { return 0 <= k; } return k < 0; } /** * Overridden to reflect equality of abstract values (data object) as * opposite to object identity. * * @see Object#equals(Object) */ @Override public boolean equals(Object o) { boolean isEqual = false; if (o != null && o instanceof Line) { Line other = (Line) o; isEqual = origin == other.origin && direction == other.direction; } return isEqual; } /** * Overridden to reflect equality of abstract values (data object) as * opposite to object identity. * * @see Object#hashCode() */ @Override public int hashCode() { return origin.hashCode(); } }