/*
 * 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.geometry;

import georegression.misc.GrlConstants;
import georegression.struct.point.Point2D_F32;
import georegression.struct.shapes.EllipseQuadratic_F32;
import georegression.struct.shapes.EllipseRotated_F32;

/**
 * Functions for extracting information from ellipses and converting between different ellipse formats.
 *
 * @author Peter Abeles
 */
public class UtilEllipse_F32 {

	/**
	 * 

* Convert from quadratic to rotated formats. Equations taken from [1]. *

* *

* [1] David Eberly "Information About Ellipses", Geometric Tools, LLC 2011 *

* * @param input Input in quadratic format. * @param output (Optional) Storage for converted format. Can be null. * @return Ellipse in rotated format. */ public static EllipseRotated_F32 convert( EllipseQuadratic_F32 input , EllipseRotated_F32 output ) { if( output == null ) output = new EllipseRotated_F32(); float a11 = input.a; float a12 = input.b; float a22 = input.c; float b1 = 2*input.d; float b2 = 2*input.e; float c = input.f; output.center.x = (a22*b1-a12*b2)/(2*(a12*a12 - a11*a22)); output.center.y = (a11*b2-a12*b1)/(2*(a12*a12 - a11*a22)); float k1 = output.center.x; float k2 = output.center.y; float mu = 1.0f/(a11*k1*k1 + 2*a12*k1*k2 + a22*k2*k2 - c); float m11 = mu*a11; float m12 = mu*a12; float m22 = mu*a22; float inner = (float)Math.sqrt((m11-m22)*(m11-m22) + 4*m12*m12); float l1 = ((m11+m22) + inner)/2.0f; float l2 = ((m11+m22) - inner)/2.0f; output.b = 1/(float)Math.sqrt(l1); output.a = 1/(float)Math.sqrt(l2); // direction of minor axis float dx,dy; if( m11 >= m22 ) { dx = l1-m22; dy = m12; } else { dx = m12; dy = l1-m11; } // direction of major axis output.phi = (float)Math.atan2(-dx,dy); if( output.phi < -GrlConstants.F_PId2 ) { output.phi += (float)Math.PI; } else if( output.phi > GrlConstants.F_PId2 ) { output.phi -= (float)Math.PI; } return output; } /** * Convert from rotated to quadratic. * * @param input Input rotated format. * @param output (Optional) Storage for quadratic format. Can be null. * @return Ellipse in quadratic format. */ public static EllipseQuadratic_F32 convert( EllipseRotated_F32 input , EllipseQuadratic_F32 output ) { if( output == null ) output = new EllipseQuadratic_F32(); float x0 = input.center.x; float y0 = input.center.y; float a = input.a; float b = input.b; float phi = input.phi; float cphi = (float)Math.cos(phi); float sphi = (float)Math.sin(phi); float cphi2 = cphi*cphi; float sphi2 = sphi*sphi; float a2 = a*a; float b2 = b*b; float x02 = x0*x0; float y02 = y0*y0; // TODO simplfy using more trig identities output.a = cphi2/a2 + sphi2/b2; output.b = sphi*cphi/a2 - sphi*cphi/b2; output.c = sphi2/a2 + cphi2/b2; output.d = -x0*cphi2/a2 - y0*sphi*cphi/a2 - x0*sphi2/b2 + y0*sphi*cphi/b2; output.e = -x0*sphi*cphi/a2 - y0*sphi2/a2 + x0*sphi*cphi/b2 - y0*cphi2/b2; output.f = x02*cphi2/a2 + 2*x0*y0*sphi*cphi/a2 + y02*sphi2/a2 + x02*sphi2/b2 - 2*x0*y0*sphi*cphi/b2 + y02*cphi2/b2 - 1; return output; } /** * Computes the value of the quadratic ellipse function at point (x,y). Should equal 0 if the point * is along the ellipse. * * @param x x-coordinate * @param y y-coordinate * @param ellipse Ellipse equation being evaluated. * @return value of ellipse equation at point (x,y) */ public static float evaluate( float x , float y , EllipseQuadratic_F32 ellipse ) { return ellipse.a*x*x + 2*ellipse.b*x*y + ellipse.c*y*y + 2*ellipse.d*x + 2*ellipse.e*y + ellipse.f; } /** * Computes the value of the quadratic ellipse function at point (x,y). Should equal 1 if the point is on the * ellipse. * @param x x-coordinate * @param y y-coordinate * @param ellipse Ellipse equation being evaluated. * @return value of ellipse equation at point (x,y) */ public static float evaluate( float x , float y , EllipseRotated_F32 ellipse ) { float cphi = (float)Math.cos(ellipse.phi); float sphi = (float)Math.sin(ellipse.phi); x -= ellipse.center.x; y -= ellipse.center.y; float left = (x*cphi + y*sphi); float right = (-x*sphi + y*cphi); return (left*left)/(ellipse.a*ellipse.a) + (right*right)/(ellipse.b*ellipse.b); } /** * Computes the point on the ellipse at location 't', where t is an angle in radians * * @param t An angle in radians from 0 to 2*PI * @param ellipse Ellipse * @param output (Optional) point on the ellipse . Can be null. * @return Point on the ellipse */ public static Point2D_F32 computePoint( float t , EllipseRotated_F32 ellipse , Point2D_F32 output ) { if( output == null ) output = new Point2D_F32(); float ct = (float)Math.cos(t); float st = (float)Math.sin(t); float cphi = (float)Math.cos(ellipse.phi); float sphi = (float)Math.sin(ellipse.phi); output.x = ellipse.center.x + ellipse.a*ct*cphi - ellipse.b*st*sphi; output.y = ellipse.center.y + ellipse.a*ct*sphi + ellipse.b*st*cphi; return output; } /** * Computes the value of 't' used to specify a point's location * * @param p Point on the ellipse * @param ellipse Ellipse * @return Angle from -pi to pi */ public static float computeAngle( Point2D_F32 p , EllipseRotated_F32 ellipse ) { // put point into ellipse's reference frame float ce = (float)Math.cos(ellipse.phi); float se = (float)Math.sin(ellipse.phi); float xc = p.x - ellipse.center.x; float yc = p.y - ellipse.center.y; float x = ce*xc + se*yc; float y = -se*xc + ce*yc; return (float)Math.atan2( y/ellipse.b , x/ellipse.a ); } }

Ads help maintain this website.