/*
* Copyright (C) 2011-2015, Peter Abeles. All Rights Reserved.
*
* This file is part of Geometric Regression Library (GeoRegression).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package georegression.metric;
import georegression.geometry.UtilPoint2D_F64;
import georegression.struct.line.LineGeneral2D_F64;
import georegression.struct.line.LineParametric2D_F64;
import georegression.struct.line.LineSegment2D_F64;
import georegression.struct.point.Point2D_F64;
import georegression.struct.shapes.EllipseRotated_F64;
import georegression.struct.shapes.Polygon2D_F64;
import georegression.struct.shapes.Quadrilateral_F64;
/**
* Functions related to finding the distance of one shape from another shape. This is often
* closely related to finding the {@link ClosestPoint3D_F64 closest point}.
*
* @author Peter Abeles
*/
// TODO distance between two line segments, line lines
// handle parallel overlapping cases by returning zero
public class Distance2D_F64 {
/**
* <p>
* Returns the Euclidean distance of the closest point on the line from a point.
* </p>
*
* @param line A line segment. Not modified.
* @param p The point. Not modified.
* @return Distance the closest point on the line is away from the point.
*/
public static double distance( LineParametric2D_F64 line, Point2D_F64 p ) {
return Math.sqrt(distanceSq(line, p));
}
/**
* <p>
* Returns the Euclidean distance squared of the closest point on the line from a point.
* </p>
*
* @param line A line segment. Not modified.
* @param p The point. Not modified.
* @return Euclidean distance squared to the closest point on the line is away from the point.
*/
public static double distanceSq( LineParametric2D_F64 line, Point2D_F64 p ) {
double t = ClosestPoint2D_F64.closestPointT( line, p );
double a = line.slope.x * t + line.p.x;
double b = line.slope.y * t + line.p.y;
double dx = p.x - a;
double dy = p.y - b;
return dx * dx + dy * dy;
}
/**
* <p>
* Returns the Euclidean distance of the closest point on a line segment to the specified point.
* </p>
*
* @param line A line segment. Not modified.
* @param p The point. Not modified.
* @return Euclidean distance of the closest point on a line is away from a point.
*/
public static double distance( LineSegment2D_F64 line, Point2D_F64 p ) {
return Math.sqrt(distanceSq(line, p));
}
/**
* <p>
* Returns the Euclidean distance squared of the closest point on a line segment to the specified point.
* </p>
*
* @param line A line segment. Not modified.
* @param p The point. Not modified.
* @return Euclidean distance squared of the closest point on a line is away from a point.
*/
public static double distanceSq( LineSegment2D_F64 line, Point2D_F64 p ) {
double a = line.b.x - line.a.x;
double b = line.b.y - line.a.y;
double t = a * ( p.x - line.a.x ) + b * ( p.y - line.a.y );
t /= ( a * a + b * b );
// if the point of intersection is past the end points return the distance
// from the closest end point
if( t < 0 ) {
return UtilPoint2D_F64.distanceSq(line.a.x, line.a.y, p.x, p.y);
} else if( t > 1.0 )
return UtilPoint2D_F64.distanceSq(line.b.x, line.b.y, p.x, p.y);
// return the distance of the closest point on the line
return UtilPoint2D_F64.distanceSq(line.a.x + t * a, line.a.y + t * b, p.x, p.y);
}
/**
* Finds the distance between the two line segments
* @param segmentA Line segment. Not modified.
* @param segmentB Line segment. Not modified.
* @return Euclidean distance of the closest point between the two line segments.
*/
public static double distance( LineSegment2D_F64 segmentA , LineSegment2D_F64 segmentB ) {
return Math.sqrt(distanceSq(segmentA, segmentB));
}
/**
* Finds the distance squared between the two line segments
* @param segmentA Line segment. Not modified.
* @param segmentB Line segment. Not modified.
* @return Euclidean distance squared of the closest point between the two line segments.
*/
public static double distanceSq( LineSegment2D_F64 segmentA , LineSegment2D_F64 segmentB ) {
// intersection of the two lines relative to A
double slopeAX = segmentA.slopeX();
double slopeAY = segmentA.slopeY();
double slopeBX = segmentB.slopeX();
double slopeBY = segmentB.slopeY();
double ta = slopeBX*( segmentA.a.y - segmentB.a.y ) - slopeBY*( segmentA.a.x - segmentB.a.x );
double bottom = slopeBY*slopeAX - slopeAY*slopeBX;
// see they intersect
if( bottom != 0 ) {
// see if the intersection is inside of lineA
ta /= bottom;
if( ta >= 0 && ta <= 1.0 ) {
// see if the intersection is inside of lineB
double tb = slopeAX*( segmentB.a.y - segmentA.a.y ) - slopeAY*( segmentB.a.x - segmentA.a.x );
tb /= slopeAY*slopeBX - slopeBY*slopeAX;
if( tb >= 0 && tb <= 1.0 )
return 0;
}
}
double closest = Double.MAX_VALUE;
closest = Math.min(closest,distanceSq(segmentA, segmentB.a));
closest = Math.min(closest,distanceSq(segmentA, segmentB.b));
closest = Math.min(closest,distanceSq(segmentB, segmentA.a));
closest = Math.min(closest,distanceSq(segmentB, segmentA.b));
return closest;
}
/**
* Returns the Euclidean distance of the closest point on the quadrilateral to the provided point.
*
* @param quad Quadrilateral
* @param p Point
* @return Distance apart
*/
public static double distance( Quadrilateral_F64 quad , Point2D_F64 p ) {
return Math.sqrt(distanceSq(quad,p));
}
/**
* Returns the Euclidean distance squared of the closest point on the quadrilateral to the provided point.
*
* @param quad Quadrilateral
* @param p Point
* @return Distance squared apart
*/
public static double distanceSq( Quadrilateral_F64 quad , Point2D_F64 p ) {
LineSegment2D_F64 seg = LineSegment2D_F64.wrap(quad.a, quad.b);
double a = distanceSq(seg, p);
seg.a = quad.b;seg.b = quad.c;
a = Math.min(a,distanceSq(seg,p));
seg.a = quad.c;seg.b = quad.d;
a = Math.min(a,distanceSq(seg,p));
seg.a = quad.d;seg.b = quad.a;
return Math.min(a, distanceSq(seg, p));
}
/**
* Returns the Euclidean distance of the closest point on the Polygon to the provided point.
*
* @param poly Polygon2D
* @param p Point
* @return Distance squared apart
*/
public static double distance( Polygon2D_F64 poly , Point2D_F64 p ) {
return Math.sqrt(distanceSq(poly, p, null));
}
/**
* Returns the Euclidean distance squared of the closest point on the Polygon to the provided point.
*
* @param poly Polygon2D
* @param p Point
* @param storage Optional storage for linesegment which is used internally to compute the distance
* @return Distance squared apart
*/
public static double distanceSq( Polygon2D_F64 poly , Point2D_F64 p , LineSegment2D_F64 storage ) {
if( storage == null )
storage = LineSegment2D_F64.wrap(null,null);
double minimum = Double.MAX_VALUE;
for (int i = 0; i < poly.size(); i++) {
int j = (i+1)%poly.size();
storage.a = poly.vertexes.data[i];
storage.b = poly.vertexes.data[j];
double d = distanceSq(storage, p);
if( d < minimum )
minimum = d;
}
return minimum;
}
/**
* <p>
* Returns the Euclidean distance of the closest point on the line to the specified point.
* </p>
*
* @param line A line. Not modified.
* @param p The point. Not modified.
* @return Euclidean distance of the closest point on the line to the specified point.
*/
public static double distance( LineGeneral2D_F64 line , Point2D_F64 p ) {
return Math.abs(line.A*p.x + line.B*p.y + line.C) / Math.sqrt( line.A*line.A + line.B*line.B );
}
/**
* <p>
* Returns the signed Euclidean distance of the closest point on the line to the specified point.
* The line is assumed be normalized. See {@link LineGeneral2D_F64} for details on normalization.
* </p>
*
* @param line A normalized line. Not modified.
* @param p The point. Not modified.
* @return Euclidean distance of the closest point on the line to the specified point.
*/
public static double distanceNorm(LineGeneral2D_F64 line, Point2D_F64 p) {
return Math.abs(line.A*p.x + line.B*p.y + line.C);
}
/**
* Returns the distance of the closest point on the line from the origin
* @param line Line
* @return Euclidean distance
*/
public static double distanceOrigin( LineParametric2D_F64 line ) {
double top = line.slope.y*line.p.x - line.slope.x*line.p.y;
return Math.abs(top)/line.slope.norm();
}
/**
* Euclidean distance of closest point on ellipse to point 'p'.
*
* @param ellipse Ellipse
* @param p Point
* @return Euclidean distance
*/
public static double distance(EllipseRotated_F64 ellipse , Point2D_F64 p ) {
return Math.sqrt(distance2(ellipse, p));
}
/**
* Euclidean distance squared of closest point on ellipse to point 'p'.
*
* @param ellipse Ellipse
* @param p Point
* @return Euclidean distance squared
*/
public static double distance2(EllipseRotated_F64 ellipse , Point2D_F64 p ) {
// put point into ellipse's reference frame
double cphi = Math.cos(ellipse.phi);
double sphi = Math.sin(ellipse.phi);
double xc = p.x - ellipse.center.x;
double yc = p.y - ellipse.center.y;
double r = Math.sqrt(xc*xc + yc*yc);
double x = cphi*xc + sphi*yc;
double y = -sphi*xc + cphi*yc;
double ct = x/r;
double st = y/r;
x = ellipse.center.x + ellipse.a*ct*cphi - ellipse.b*st*sphi;
y = ellipse.center.y + ellipse.a*ct*sphi + ellipse.b*st*cphi;
return p.distance2(x,y);
}
}