/*-
*******************************************************************************
* 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 java.util.Arrays;
import org.eclipse.dawnsci.analysis.api.roi.IParametricROI;
/**
* A circular region of interest
*/
public class CircularROI extends ROIBase implements IParametricROI, Serializable {
private double rad;
/**
* Create a unit circle centred on origin
*/
public CircularROI() {
this(1, 0, 0);
}
/**
* Create circle of given radius centred on origin
* @param radius
*/
public CircularROI(double radius) {
this(radius, 0, 0);
}
/**
* Create circle of given radius with specified centre
* @param radius
* @param ptx centre point x value
* @param pty centre point y value
*/
public CircularROI(double radius, double ptx, double pty) {
spt = new double[] { ptx, pty };
rad = Math.abs(radius);
}
@Override
public void downsample(double subFactor) {
super.downsample(subFactor);
rad /= subFactor;
setDirty();
}
@Override
public CircularROI copy() {
CircularROI c = new CircularROI(rad, spt[0], spt[1]);
c.name = name;
c.plot = plot;
return c;
}
/**
* @return radius
*/
public double getRadius() {
return rad;
}
/**
* Set radius
* @param radius
*/
public void setRadius(double radius) {
rad = radius;
setDirty();
}
/**
* Get point on circle at given angle
* @param angle in radians
* @return point
*/
@Override
public double[] getPoint(double angle) {
return new double[] { spt[0] + rad*Math.cos(angle),
spt[1] + rad*Math.sin(angle) };
}
/**
* Get point on circle at given angle
* @param angle in degrees
* @return point
*/
public double[] getPointDegrees(double angle) {
return getPoint(Math.toRadians(angle));
}
/**
* Get centre point
* @return x and y coordinates in double array
*/
public double[] getCentre() {
return getPoint();
}
/**
* Set centre point
* @param centre
*/
public void setCentre(double... centre) {
setPoint(centre);
}
@Override
public RectangularROI getBounds() {
if (bounds == null) {
bounds = new RectangularROI();
bounds.setPoint(spt[0] - rad, spt[1] - rad);
bounds.setLengths(2 * rad, 2 * rad);
}
return bounds;
}
@Override
public boolean containsPoint(double x, double y) {
return Math.hypot(x - spt[0], y - spt[1]) <= rad;
}
@Override
public boolean isNearOutline(double x, double y, double distance) {
double r = Math.hypot(x - spt[0], y - spt[1]);
return Math.abs(r - rad) <= distance;
}
@Override
public String toString() {
return super.toString() + String.format("point=%s, radius=%g", Arrays.toString(spt), rad);
}
/**
* Calculate values for angle at which circle will intersect vertical line of given x
* @param x
* @return possible angles
*/
@Override
public double[] getVerticalIntersectionParameters(double x) {
x -= spt[0];
if (x < -rad || x > rad) {
return null;
}
if (x == -rad || x == rad) { // touching case
return new double[]{x < 0 ? Math.PI : 0};
}
double ang = Math.acos(x/rad);
return new double[] {ang, (Math.PI*2)-ang};
}
/**
* Calculate values for angle at which circle will intersect horizontal line of given y
* @param y
* @return possible angles
*/
@Override
public double[] getHorizontalIntersectionParameters(double y) {
y -= spt[1];
if (y < -rad || y > rad) {
return null;
}
if (y == -rad || y == rad) { // touching case
return new double[]{y < 0 ? Math.PI : 0};
}
double ang = Math.acos(y/rad);
return new double[] {ang, (Math.PI*2)-ang};
}
/**
* Calculate x values at which circle will intersect horizontal line of given y
* @param y
* @return x values
*/
@Override
public double[] findHorizontalIntersections(double y) {
y -= spt[1];
if (y < -rad || y > rad) {
return null;
}
if (y == -rad || y == rad) { // touching case
return new double[]{spt[0]};
}
double x = Math.sqrt(rad*rad - y*y);
return new double[] {spt[0] - x, spt[0] + x};
}
@Override
public double getAngleDegrees() {
return 0;
}
@Override
public void setAngleDegrees(double degrees) {
}
@Override
public double getAngle() {
return 0;
}
@Override
public void setAngle(double angle) {
}
@Override
public double getStartParameter(double d) {
return 0;
}
@Override
public double getEndParameter(double d) {
return Math.PI * 2;
}
@Override
public int hashCode() {
final int prime = 31;
int result = super.hashCode();
long temp;
temp = Double.doubleToLongBits(rad);
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;
CircularROI other = (CircularROI) obj;
if (Double.doubleToLongBits(rad) != Double.doubleToLongBits(other.rad))
return false;
return true;
}
}