/*
* org.openmicroscopy.shoola.util.math.geom2D.Line
*
*------------------------------------------------------------------------------
* Copyright (C) 2006 University of Dundee. All rights reserved.
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*------------------------------------------------------------------------------
*/
package org.openmicroscopy.shoola.util.math.geom2D;
//Java imports
//Third-party libraries
//Application-internal dependencies
import org.openmicroscopy.shoola.util.ui.UIUtilities;
/**
* An oriented 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$)
* </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 Math.abs(k1-k2) < UIUtilities.EPSILON;
}
/**
* 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)
*/
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()
*/
public int hashCode() { return origin.hashCode(); }
}