Author: [log in to unmask] Date: Wed Oct 19 13:10:51 2016 New Revision: 4516 Log: Circle fitting utilities Added: java/trunk/tracking/src/main/java/org/hps/recon/tracking/circlefit/ java/trunk/tracking/src/main/java/org/hps/recon/tracking/circlefit/CircleFit.java java/trunk/tracking/src/main/java/org/hps/recon/tracking/circlefit/TwoPointRadiusCircleFitter.java Added: java/trunk/tracking/src/main/java/org/hps/recon/tracking/circlefit/CircleFit.java ============================================================================= --- java/trunk/tracking/src/main/java/org/hps/recon/tracking/circlefit/CircleFit.java (added) +++ java/trunk/tracking/src/main/java/org/hps/recon/tracking/circlefit/CircleFit.java Wed Oct 19 13:10:51 2016 @@ -0,0 +1,85 @@ +package org.hps.recon.tracking.circlefit; + +/** + * A class which encapsulates the result of a circle fit. + * + * @author Norman A Graf + * + * @version $Id: + */ +public class CircleFit +{ + + private double _x0; + private double _y0; + private double _r; + + /** + * Creates a new instance of CircleFit + * + * @param x0 the x coordinate of the center of the circle + * @param y0 the y coordinate of the center of the circle + * @param r the radius of the circle + */ + public CircleFit(double x0, double y0, double r) + { + _x0 = x0; + _y0 = y0; + _r = r; + } + + /** + * The x coordinate of the center of the circle. + * + * @return the x coordinate of the center of the circle + */ + public double x0() + { + return _x0; + } + + /** + * The y coordinate of the center of the circle + * + * @return + */ + public double y0() + { + return _y0; + } + + /** + * The radius of the circle + * + * @return the radius of the circle + */ + public double radius() + { + return _r; + } + + /** + * Return the slope of the tangent (dy/dx) at a point on this circle (does + * not check if point is on circle) + * + * @param p double array assumed to be (x, y) + * @return the slope of the tangent to this circle at the point p + */ + public double tangentAtPoint(double[] p) + { + double tangent; + tangent = -(p[0] - _x0) / (p[1] - _y0); + return tangent; + } + + /** + * String representation of this object + * + * @return String representation of this object + */ + public String toString() + { + return "CircleFit: x0= " + _x0 + " y0= " + _y0 + " r= " + _r; + } + +} Added: java/trunk/tracking/src/main/java/org/hps/recon/tracking/circlefit/TwoPointRadiusCircleFitter.java ============================================================================= --- java/trunk/tracking/src/main/java/org/hps/recon/tracking/circlefit/TwoPointRadiusCircleFitter.java (added) +++ java/trunk/tracking/src/main/java/org/hps/recon/tracking/circlefit/TwoPointRadiusCircleFitter.java Wed Oct 19 13:10:51 2016 @@ -0,0 +1,71 @@ +package org.hps.recon.tracking.circlefit; + +import static java.lang.Math.hypot; +import static java.lang.Math.pow; +import static java.lang.Math.sqrt; + +/** + * Fits a circle to two points and a radius + * @author Norman A Graf + * + * @version $Id: + */ +public class TwoPointRadiusCircleFitter +{ + + private static boolean _debug = false; + + static double distance(double[] p1, double[] p2) + { + return hypot((p1[0] - p2[0]), p1[1] - p2[1]); + } + + /** + * Returns two circles which can be fit to two points and a radius + * @param p1 A point on the cricle + * @param p2 Another point on the circle + * @param radius The radius of the circle + * @return The two circles which can be fit, or null + */ + public static CircleFit[] findCircles(double[] p1, double[] p2, double radius) + { + CircleFit[] results = null; + double separation = distance(p1, p2); + double mirrorDistance; + + if (separation == 0.0) { + if (radius == 0.0) { + if (_debug) { + System.out.printf("\nNo circles can be drawn through (%.4f,%.4f)", p1[0], p1[1]); + } + } else { + if (_debug) { + System.out.printf("\nInfinitely many circles can be drawn through (%.4f,%.4f)", p1[0], p1[1]); + } + } + } else if (separation == 2 * radius) { + results = new CircleFit[1]; + results[0] = new CircleFit((p1[0] + p2[0]) / 2, (p1[1] + p2[1]) / 2, radius); + if (_debug) { + System.out.printf("\nGiven points are opposite ends of a diameter of the circle with center (%.4f,%.4f) and radius %.4f", (p1[0] + p2[0]) / 2, (p1[1] + p2[1]) / 2, radius); + } + } else if (separation > 2 * radius) { + if (_debug) { + System.out.printf("\nGiven points are farther away from each other than a diameter of a circle with radius %.4f", radius); + } + } else { + mirrorDistance = sqrt(pow(radius, 2) - pow(separation / 2, 2)); + results = new CircleFit[2]; + results[0] = new CircleFit((p1[0] + p2[0]) / 2 + mirrorDistance * (p1[1] - p2[1]) / separation, (p1[1] + p2[1]) / 2 + mirrorDistance * (p2[0] - p1[0]) / separation, radius); + results[1] = new CircleFit((p1[0] + p2[0]) / 2 - mirrorDistance * (p1[1] - p2[1]) / separation, (p1[1] + p2[1]) / 2 - mirrorDistance * (p2[0] - p1[0]) / separation, radius); + if (_debug) { + System.out.printf("\nTwo circles are possible."); + } + if (_debug) { + System.out.printf("\nCircle C1 with center (%.4f,%.4f), radius %.4f and Circle C2 with center (%.4f,%.4f), radius %.4f", (p1[0] + p2[0]) / 2 + mirrorDistance * (p1[1] - p2[1]) / separation, (p1[1] + p2[1]) / 2 + mirrorDistance * (p2[0] - p1[0]) / separation, radius, (p1[0] + p2[0]) / 2 - mirrorDistance * (p1[1] - p2[1]) / separation, (p1[1] + p2[1]) / 2 - mirrorDistance * (p2[0] - p1[0]) / separation, radius); + } + } + return results; + } + +}