/* * 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.fitting.ellipse; import georegression.geometry.UtilEllipse_F64; import georegression.misc.GrlConstants; import georegression.struct.point.Point2D_F64; import georegression.struct.shapes.EllipseQuadratic_F64; import georegression.struct.shapes.EllipseRotated_F64; import org.junit.Test; import java.util.ArrayList; import java.util.List; import java.util.Random; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; /** * @author Peter Abeles */ public class TestFitEllipseAlgebraic { Random rand = new Random(234); @Test public void checkCircle() { checkEllipse(0, 0, 3, 3, 0); } /** * Give it points which perfectly describe an ellipse. This isn't actually an easy case. See comments * in random section. */ @Test public void checkEllipse() { checkEllipse(0,0,3,1.5,0); checkEllipse(1,2,3,1.5,0); checkEllipse(1,2,3,1.5,0.25); } public void checkEllipse( double x0 , double y0, double a, double b, double phi ) { EllipseRotated_F64 rotated = new EllipseRotated_F64(x0,y0,a,b,phi); List<Point2D_F64> points = new ArrayList<Point2D_F64>(); for( int i = 0; i < 20; i++ ) { double theta = 2.0*(double)Math.PI*i/20; points.add(UtilEllipse_F64.computePoint(theta, rotated, null)); // System.out.println(points.get(i).x+" "+points.get(i).y); } EllipseQuadratic_F64 expected = UtilEllipse_F64.convert(rotated,null); FitEllipseAlgebraic alg = new FitEllipseAlgebraic(); assertTrue(alg.process(points)); EllipseQuadratic_F64 found = alg.getEllipse(); normalize(expected); normalize(found); assertEquals(expected.a,found.a, GrlConstants.DOUBLE_TEST_TOL); assertEquals(expected.b,found.b, GrlConstants.DOUBLE_TEST_TOL); assertEquals(expected.c,found.c, GrlConstants.DOUBLE_TEST_TOL); assertEquals(expected.d,found.d, GrlConstants.DOUBLE_TEST_TOL); assertEquals(expected.e,found.e, GrlConstants.DOUBLE_TEST_TOL); assertEquals(expected.f,found.f, GrlConstants.DOUBLE_TEST_TOL); } /** * Randomly generate points and see if it produces a valid ellipse * * The paper mentions that the case of perfect data is actually numerically unstable. The random test * below has been commented out since even the original algorithm run in octave can't pass that test. */ @Test public void checkRandom() { // for( int i = 0; i < 100; i++ ) { // System.out.println("i = "+i); // double x0 = (rand.nextDouble()-0.5)*2; // double y0 = (rand.nextDouble()-0.5)*2; // double b = rand.nextDouble(); // double a = b+rand.nextDouble()*2+0.1; // double theta = (rand.nextDouble()-0.5)*Math.PI; // // checkEllipse(x0,y0,a,b,theta); // } } private void normalize( EllipseQuadratic_F64 ellipse ) { ellipse.a /= ellipse.f; ellipse.b /= ellipse.f; ellipse.c /= ellipse.f; ellipse.d /= ellipse.f; ellipse.e /= ellipse.f; ellipse.f /= ellipse.f; } }