/* * Geotoolkit.org - An Open Source Java GIS Toolkit * http://www.geotoolkit.org * * (C) 1998-2012, Open Source Geospatial Foundation (OSGeo) * (C) 2009-2012, Geomatys * * 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; * version 2.1 of the License. * * 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. */ package org.geotoolkit.math; import java.awt.geom.Line2D; import java.awt.geom.Point2D; import static java.lang.Double.*; /** * Equation of a line in a two dimensional space (<var>x</var>,<var>y</var>). * * @author Martin Desruisseaux (MPO, IRD) * @version 3.00 * * @see Point2D * @see Line2D * @see Plane * * @since 1.0 * @module */ public class Line extends org.apache.sis.math.Line { /** * Small value for rounding errors. */ private static final double EPS = 1E-12; /** * Construct an initially uninitialized line. All methods will returns {@link Double#NaN}. */ public Line() { } /** * Construct a line with the specified slope and offset. * The linear equation will be <var>y</var>=<var>slope</var>*<var>x</var>+<var>y0</var>. * * @param slope The slope. * @param y0 The <var>y</var> value at <var>x</var>==0. * * @see #setLine(double, double) */ public Line(final double slope, final double y0) { super(slope, y0); } /** * Returns the intersection point between this line and the specified one. * If both lines are parallel, then this method returns {@code null}. * * @param line The line to intersect. * @return The intersection point, or {@code null}. */ public Point2D intersectionPoint(final Line line) { final double x, y; if (isInfinite(slope())) { if (isInfinite(line.slope())) { return null; } x = x0(); y = line.y(x); } else { if (isInfinite(line.slope())) { x = line.x0(); } else { x = (y0() - line.y0()) / (line.slope() - slope()); if (isInfinite(x)) { return null; } } y = y(x); } return new Point2D.Double(x,y); } /** * Returns the intersection point between this line and the specified bounded line. * If both lines are parallel or if the specified {@code line} doesn't reach * this line (since {@link Line2D} do not extends toward infinities), then this * method returns {@code null}. * * @param line The bounded line to intersect. * @return The intersection point, or {@code null}. */ public Point2D intersectionPoint(final Line2D line) { final double x1 = line.getX1(); final double y1 = line.getY1(); final double x2 = line.getX2(); final double y2 = line.getY2(); double x,y; double m = (y2-y1) / (x2-x1); if (isInfinite(slope())) { x = x0(); y = x*m + (y2 - m*x2); } else { if (!isInfinite(m)) { x = (y0() - (y2 - m*x2)) / (m - slope()); } else { x = 0.5 * (x1 + x2); } y = x*slope() + y0(); } double eps; /* * Ensures that the intersection is in the range of valid x values. */ eps = EPS * Math.abs(x); if (x1 <= x2) { if (!(x >= x1-eps && x <= x2+eps)) { return null; } } else { if (!(x <= x1+eps && x >= x2-eps)) { return null; } } /* * Ensures that the intersection is in the range of valid y values. */ eps = EPS * Math.abs(y); if (y1 <= y2) { if (!(y >= y1-eps && y <= y2+eps)) { return null; } } else { if (!(y <= y1-eps && y >= y2+eps)) { return null; } } return new Point2D.Double(x,y); } /** * Returns the nearest point on this line from the specified point. * * @param point An arbitrary point. * @return The point on this line which is the nearest of the specified {@code point}. */ public Point2D nearestColinearPoint(final Point2D point) { if (!isInfinite(slope())) { final double x = ((point.getY() - y0()) * slope() + point.getX()) / (slope() * slope() + 1); return new Point2D.Double(x, x*slope() + y0()); } else { return new Point2D.Double(x0(), point.getY()); } } /** * Computes the base of a isosceles triangle having the specified summit and side length. * The base will be colinear with this line. In other words, this method compute two * points (<var>x1</var>,<var>y1</var>) and (<var>x2</var>,<var>y2</var>) located in * such a way that: * <ul> * <li>Both points are on this line.</li> * <li>The distance between any of the two points and the specified {@code summit} * is exactly {@code sideLength}.</li> * </ul> * * @param summit The summit of the isosceles triangle. * @param sideLength The length for the two sides of the isosceles triangle. * @return The base of the isoscele triangle, colinear with this line, or {@code null} * if the base can't be computed. If non-null, then the triangle is the figure formed * by joining (<var>x1</var>,<var>y1</var>), (<var>x2</var>,<var>y2</var>) and * {@code summit}. */ public Line2D isoscelesTriangleBase(final Point2D summit, double sideLength) { sideLength *= sideLength; if (slope() == 0) { final double x = summit.getX(); final double dy = y0() - summit.getY(); final double dx = Math.sqrt(sideLength - dy*dy); if (isNaN(dx)) { return null; } return new Line2D.Double(x+dx, y0(), x-dx, y0()); } if (isInfinite(slope())) { final double y = summit.getY(); final double dx = x0() - summit.getX(); final double dy = Math.sqrt(sideLength - dx*dx); if (isNaN(dy)) { return null; } return new Line2D.Double(x0(), y+dy, x0(), y-dy); } final double x = summit.getX(); final double y = summit.getY(); final double dy = y0() - y + slope() * x; final double B = -slope() * dy; final double A = slope() * slope() + 1; final double C = Math.sqrt(B*B + A*(sideLength - dy*dy)); if (isNaN(C)) { return null; } final double x1 = (B+C)/A + x; final double x2 = (B-C)/A + x; return new Line2D.Double(x1, slope() * x1 + y0(), x2, slope() * x2 + y0()); } }