/*- ******************************************************************************* * Copyright (c) 2011, 2014 Diamond Light Source Ltd. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Peter Chang - initial API and implementation and/or initial documentation *******************************************************************************/ package org.eclipse.dawnsci.analysis.dataset.roi; import java.io.Serializable; import org.eclipse.dawnsci.analysis.api.fitting.IConicSectionFitter; import org.eclipse.dawnsci.analysis.api.roi.IFitROI; import org.eclipse.dawnsci.analysis.api.roi.IPolylineROI; import org.eclipse.dawnsci.analysis.dataset.roi.fitting.CircleFitter; import org.eclipse.dawnsci.analysis.dataset.roi.fitting.EllipseFitter; import org.eclipse.january.dataset.IDataset; /** * An elliptical region of interest which fits the points in a polygonal region of interest */ public class EllipticalFitROI extends EllipticalROI implements IFitROI, Serializable { private IPolylineROI proi; private boolean circleOnly; private transient IConicSectionFitter fitter; // The fitter is not serializable, the EllipticalFitROI is. private double residual; private EllipticalFitROI(double major, double minor, double angle, double ptx, double pty) { super(major, minor, angle, ptx, pty); residual = 0; } public EllipticalFitROI(IPolylineROI points) { this(points, false); } public EllipticalFitROI(IPolylineROI points, boolean fitCircle) { super(1, 0, 0); circleOnly = fitCircle; setPoints(points); } @Override public void downsample(double subFactor) { super.downsample(subFactor); proi.downsample(subFactor); } @Override public EllipticalFitROI copy() { EllipticalFitROI c = new EllipticalFitROI(getSemiAxis(0), getSemiAxis(1), getAngle(), getPointX(), getPointY()); c.proi = proi.copy(); c.name = name; c.plot = plot; return c; } /** * Fit an ellipse to given polyline * @param polyline * @return fitter */ public static IConicSectionFitter fit(IPolylineROI polyline, final boolean fitCircle) { // IFittingAlgorithmService service = (IFittingAlgorithmService) Activator.getService(IFittingAlgorithmService.class); IDataset[] xy = polyline.makeCoordinateDatasets(); if (fitCircle) { IConicSectionFitter f = new CircleFitter(); f.geometricFit(xy[0], xy[1], null); return f; } IConicSectionFitter f = new EllipseFitter(); f.geometricFit(xy[0], xy[1], null); return f; } /** * Set points which are then used to fit ellipse * @param points */ @Override public void setPoints(IPolylineROI points) { proi = points; int n = points.getNumberOfPoints(); final double[] p; if (fitter == null) { fitter = fit(points, n < 5 || circleOnly); p = fitter.getParameters(); } else { IDataset[] xy = points.makeCoordinateDatasets(); p = fitter.getParameters(); if (p.length < 5) { p[0] = getSemiAxis(0); p[1] = getPointX(); p[2] = getPointY(); } else { p[0] = getSemiAxis(0); p[1] = getSemiAxis(1); p[2] = getAngle(); p[3] = getPointX(); p[4] = getPointY(); } fitter.geometricFit(xy[0], xy[1], p); } residual = fitter.getRMS(); if (p.length < 5) { setSemiAxis(0, p[0]); setSemiAxis(1, p[0]); setAngle(0); setPoint(p[1], p[2]); } else { setSemiAxis(0, p[0]); setSemiAxis(1, p[1]); setAngle(p[2]); setPoint(p[3], p[4]); } setDirty(); } /** * @return root mean squared of residuals */ @Override public double getRMS() { return residual; } /** * @return fitter used */ public IConicSectionFitter getFitter() { return fitter; } /** * @return points in polygon for fitting */ @Override public IPolylineROI getPoints() { return proi; } @Override public int hashCode() { final int prime = 31; int result = super.hashCode(); result = prime * result + (circleOnly ? 1231 : 1237); result = prime * result + ((proi == null) ? 0 : proi.hashCode()); long temp; temp = Double.doubleToLongBits(residual); result = prime * result + (int) (temp ^ (temp >>> 32)); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (!super.equals(obj)) return false; EllipticalFitROI other = (EllipticalFitROI) obj; if (circleOnly != other.circleOnly) return false; if (proi == null) { if (other.proi != null) return false; } else if (!proi.equals(other.proi)) return false; if (Double.doubleToLongBits(residual) != Double.doubleToLongBits(other.residual)) return false; return true; } }