/*
* 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.fitting.ellipse.ClosestPointEllipseAngle_F32;
import georegression.misc.GrlConstants;
import georegression.struct.line.LineGeneral2D_F32;
import georegression.struct.line.LineParametric2D_F32;
import georegression.struct.line.LineSegment2D_F32;
import georegression.struct.point.Point2D_F32;
import georegression.struct.shapes.EllipseRotated_F32;
/**
* Functions related to finding the closest point(s) on one shape from another shape.
*
* @author Peter Abeles
*/
public class ClosestPoint2D_F32 {
/**
* <p>
* Finds the closest point on 'line' to the specified point.
* </p>
*
* @param line Line along which the closest point is to be found.
* @param p Point.
* @param output Where the solution is stored. If null a new instance is created. Modified.
* @return Closest point on the line.
*/
public static Point2D_F32 closestPoint( LineGeneral2D_F32 line,
Point2D_F32 p,
Point2D_F32 output ) {
if( output == null )
output = new Point2D_F32();
float AA = line.A*line.A;
float AB = line.A*line.B;
float BB = line.B*line.B;
output.y = AA*p.y - AB*p.x - line.B*line.C;
output.y /= AA+BB;
output.x = BB*p.x - AB*p.y - line.A*line.C;
output.x /= AA+BB;
return output;
}
/**
* <p>
* Finds the closest point on 'line' to the specified point.
* </p>
*
* @param line Line along which the closest point is being found.
* @param p Point.
* @param output Where the solution is stored. If null a new instance is created. Modified.
* @return Closest point on the line.
*/
public static Point2D_F32 closestPoint( LineParametric2D_F32 line,
Point2D_F32 p,
Point2D_F32 output ) {
if( output == null )
output = new Point2D_F32();
float t = closestPointT( line, p );
output.x = line.p.x + line.slope.x * t;
output.y = line.p.y + line.slope.y * t;
return output;
}
/**
* <p>
* Computes the closest point along the line as a function of 't':<br>
* [x, y] = [x_0, y_0] + t·[slopeX, slopeY]
* </p>
*
* @param line The line along which the closest point is being found. Not modified.
* @param p A point. Not modified.
* @return Distance as a function of 't'
*/
public static float closestPointT( LineParametric2D_F32 line,
Point2D_F32 p ) {
float t = line.slope.x * ( p.x - line.p.x ) + line.slope.y * ( p.y - line.p.y );
t /= line.slope.x * line.slope.x + line.slope.y * line.slope.y;
return t;
}
/**
* Finds the closest point on the line segment to the provided point 'p'.
*
* @param line Line segment
* @param p Point`
* @param output Optional storage for the closet point on the line to p. If null a new instance is created.
* @return Closest point on the line to the point
*/
public static Point2D_F32 closestPoint( LineSegment2D_F32 line,
Point2D_F32 p,
Point2D_F32 output ) {
if( output == null )
output = new Point2D_F32();
float slopeX = line.b.x - line.a.x;
float slopeY = line.b.y - line.a.y;
float t = slopeX * ( p.x - line.a.x ) + slopeY * ( p.y - line.a.y );
t /= slopeX*slopeX + slopeY*slopeY;
if( t < 0 )
t = 0;
else if( t > 1 )
t = 1;
output.x = line.a.x + slopeX * t;
output.y = line.a.y + slopeY * t;
return output;
}
/**
* Computes the closest point on an ellipse to the provided point. If there are multiple solutions then one
* is arbitrarily chosen.
*
* NOTE: When optimizing consider calling {@link georegression.fitting.ellipse.ClosestPointEllipseAngle_F32} directly instead.
*
* @param ellipse Ellipse
* @param p Point
* @return Closest point on the ellipse
*/
public static Point2D_F32 closestPoint( EllipseRotated_F32 ellipse , Point2D_F32 p ) {
ClosestPointEllipseAngle_F32 alg = new ClosestPointEllipseAngle_F32(GrlConstants.FLOAT_TEST_TOL,30);
alg.setEllipse(ellipse);
alg.process(p);
return alg.getClosest();
}
}