lcsim/test/org/lcsim/fit/twopointcircle
diff -N TwoPointCircleFitterTest.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ TwoPointCircleFitterTest.java 3 Nov 2009 23:53:40 -0000 1.1
@@ -0,0 +1,160 @@
+/*
+ * Test case for the TwoPointCircleFitter.
+ */
+
+package org.lcsim.fit.twopointcircle;
+
+import java.util.List;
+import java.util.Random;
+import junit.framework.TestCase;
+
+/**
+ * @author Richard Partridge
+ */
+public class TwoPointCircleFitterTest extends TestCase {
+
+ public void testTwoPointCircleFitter() {
+ TwoPointCircleFitter fitter = new TwoPointCircleFitter();
+ fitter.setDebug(true);
+ double epsilon = 1.0e-6;
+ Random r = new Random();
+ // generate a set of random circles
+ double xmax = 1000.;
+ double ymax = 1000.;
+ double dmax = 10.;
+ for(int i=0; i<1000000; ++i)
+ {
+ // Pick the center of the circle and the impact parameter
+ double xc = (2 * r.nextDouble() - 1.) * xmax;
+ double yc = (2 * r.nextDouble() - 1.) * ymax;
+ double d0 = r.nextDouble()*dmax;
+
+ // If the center of the circle is inside the impact parameter, skip
+ double rcent = Math.sqrt(xc*xc + yc*yc);
+ if (rcent <= d0) continue;
+
+ // Loop over the two possible circle radii for this test
+ for (int j=0; j<2; j++) {
+ double radius = rcent + (2*j - 1) * d0;
+
+ // Generate the two hits
+ double [] hit1 = nextPoint(xc, yc, radius, d0);
+ double [] hit2 = nextPoint(xc, yc, radius, d0);
+
+ // Set the minimum radius
+ double rmin = 0.;
+ if (r.nextBoolean()) rmin = xmax * r.nextDouble();
+ fitter.setRMin(rmin);
+
+ // Do the fit
+ boolean success = fitter.FitCircle(hit1[0], hit1[1], hit2[0], hit2[1], d0);
+
+ // If the circle radius is larger than the min radius, we should have found a solution
+ if (radius >= rmin) assertTrue(success);
+
+ // Check the circle fits go through hits 1 & 2
+ List<TwoPointCircleFit> cfits = fitter.getCircleFits();
+ for (TwoPointCircleFit fit : cfits) {
+
+ // Calculate the locations of hits 1 & 2 from the circle parameters
+ double rcfit = fit.rc();
+ double xcfit = fit.xc();
+ double ycfit = fit.yc();
+ double phi0 = Math.atan2(-ycfit, -xcfit);
+ double dphi1 = fit.s1() / rcfit;
+ double dphi2 = fit.s2() / rcfit;
+ double phi1;
+ double phi2;
+ if (fit.cw()) {
+ phi1 = phi0 - dphi1;
+ phi2 = phi0 - dphi2;
+ } else {
+ phi1 = phi0 + dphi1;
+ phi2 = phi0 + dphi2;
+ }
+ double x1 = xcfit + rcfit * Math.cos(phi1);
+ double y1 = ycfit + rcfit * Math.sin(phi1);
+ double x2 = xcfit + rcfit * Math.cos(phi2);
+ double y2 = ycfit + rcfit * Math.sin(phi2);
+
+ // Check that the hit positions match
+ assertEquals(x1, hit1[0], epsilon);
+ assertEquals(y1, hit1[1], epsilon);
+ assertEquals(x2, hit2[0], epsilon);
+ assertEquals(y2, hit2[1], epsilon);
+
+ // Check that the circle radius exceeds the minimum value
+ assertTrue(rcfit+epsilon >= rmin);
+
+ // Check that the IP matches the specified value if the circle radius is above the minimum
+ if (rcfit > rmin) {
+ double dcent = Math.sqrt(xcfit*xcfit + ycfit*ycfit);
+ assertEquals(Math.abs(dcent - rcfit), d0, epsilon);
+ }
+ }
+
+ // If we have a line fit, make sure it goes through the hits
+ TwoPointLineFit lfit = fitter.getLineFit();
+ if (lfit != null) {
+
+ // Calculate the hit positions
+ double x0fit = lfit.x0();
+ double y0fit = lfit.y0();
+ double phi0fit = lfit.phi0();
+ double x1fit = x0fit + lfit.s1() * Math.cos(phi0fit);
+ double y1fit = y0fit + lfit.s1() * Math.sin(phi0fit);
+ double x2fit = x0fit + lfit.s2() * Math.cos(phi0fit);
+ double y2fit = y0fit + lfit.s2() * Math.sin(phi0fit);
+
+ // Check that the hit positions match
+ assertEquals(x1fit, hit1[0], epsilon);
+ assertEquals(y1fit, hit1[1], epsilon);
+ assertEquals(x2fit, hit2[0], epsilon);
+ assertEquals(y2fit, hit2[1], epsilon);
+ }
+
+ // If we have a line fit with two circle fits, check that the circle fits have opposite sign
+ if (cfits.size() == 2 && lfit != null) {
+ assertEquals(cfits.get(0).cw(), !cfits.get(1).cw());
+ }
+
+ // If the generate circle has a radius above the minimum, check that one
+ // of the two solutions matches the generated circle
+ if (radius > rmin) {
+
+ // Find the best match to the generated circle center
+ double dbest = 1.0e99;
+ TwoPointCircleFit bestfit = null;
+ for (TwoPointCircleFit fit : fitter.getCircleFits()) {
+ double xcfit = fit.xc();
+ double ycfit = fit.yc();
+ double dist = (xcfit - xc)*(xcfit - xc) + (ycfit - yc)*(ycfit - yc);
+ if (dist < dbest) {
+ bestfit = fit;
+ dbest = dist;
+ }
+ }
+
+ // Check that the best fit matches the generated circle
+ assertEquals(bestfit.xc(), xc, epsilon);
+ assertEquals(bestfit.yc(), yc, epsilon);
+ assertEquals(bestfit.rc(), radius, epsilon);
+ }
+ }
+ }
+ }
+ private double[] nextPoint( double xc, double yc, double rc, double d0)
+ {
+ Random rn = new Random();
+ double[] p = new double[2];
+ double r = -1.;
+ while (r < d0) {
+ double phi = rn.nextDouble()*2.*Math.PI;
+ p[0] = rc*Math.cos(phi)+xc;
+ p[1] = rc*Math.sin(phi)+yc;
+ r = Math.sqrt(p[0]*p[0]+p[1]*p[1]);
+ }
+ return p;
+ }
+
+}