/*- ******************************************************************************* * 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; /** * Class for ring region of interest */ public class RingROI extends ROIBase implements Serializable { protected double rad[]; // radii protected boolean clippingCompensation; // compensate for clipping private boolean averageArea = true; protected double dpp; // Sampling rate used for profile calculations in dots per pixel /** * */ public RingROI() { this(30., 120.); } /** * Create an annulus centred on origin * @param sr * @param er */ public RingROI(double sr, double er) { this(0, 0, sr, er); } /** * Create an annulus * @param ptx * @param pty * @param sr * @param er */ public RingROI(double ptx, double pty, double sr, double er) { this(ptx, pty, sr, er, 1.0, true); } /** * @param ptx * @param pty * @param sr * @param er * @param dpp * @param clip */ public RingROI(double ptx, double pty, double sr, double er, double dpp, boolean clip) { spt = new double[] {ptx, pty}; rad = new double[] {sr, er}; this.dpp = dpp; clippingCompensation = clip; checkRadii(); } /** * @return Returns reference to the radii */ public double[] getRadii() { return rad; } /** * @param index * @return Returns the radius */ public double getRadius(int index) { return rad[index]; } /** * @return Returns the radii */ public int[] getIntRadii() { return new int[] { (int) rad[0], (int) rad[1] }; } /** * @param index * @return Returns the radius */ public int getIntRadius(int index) { return (int) rad[index]; } /** * @param radius The radii to set */ public void setRadii(double radius[]) { setRadii(radius[0], radius[1]); } /** * @param startRadius * @param endRadius */ public void setRadii(double startRadius, double endRadius) { rad[0] = startRadius; rad[1] = endRadius; checkRadii(); setDirty(); } /** * Add an offset to radii * @param radius */ public void addRadii(double radius) { if (rad[0] + radius < 0) radius = -rad[0]; if (rad[1] + radius < 0) radius = -rad[1]; rad[0] += radius; rad[1] += radius; setDirty(); } /** * Add an offset to a radius * @param index * @param radius */ public void addRadius(int index, double radius) { rad[index] += radius; checkRadii(); setDirty(); } /** * Make sure radii lie in permitted range: * 0 <= rad0, rad1 * rad0 <= rad1 */ private void checkRadii() { if (rad[0] < 0) rad[0] = 0; if (rad[1] < 0) rad[1] = 0; if (rad[0] > rad[1]) { rad[0] = rad[1]; } } /** * @param clippingCompensation The clippingCompensation to set. */ public void setClippingCompensation(boolean clippingCompensation) { this.clippingCompensation = clippingCompensation; } /** * @return Returns the clippingCompensation. */ public boolean isClippingCompensation() { return clippingCompensation; } /** * Return sampling rate used in profile calculations * * @return * sampling rate in dots per pixel */ public double getDpp() { return dpp; } /** * Set sampling rate used in profile calculations * * @param dpp * sampling rate in dots per pixel; */ public void setDpp(double dpp) { this.dpp = dpp; } /** * Whether the pixel average value shall be calculated instead of integrating * @return averageArea */ public boolean isAverageArea() { return averageArea; } /** * Set true to not strictly integrate but average over the pixels * @param averageArea */ public void setAverageArea(boolean averageArea) { this.averageArea = averageArea; } @Override public RectangularROI getBounds() { if (bounds == null) { bounds = new RectangularROI(); bounds.setPoint(spt[0] - rad[1], spt[1] - rad[1]); bounds.setLengths(2*rad[1], 2*rad[1]); } return bounds; } @Override public void downsample(double subFactor) { super.downsample(subFactor); rad[0] /= subFactor; rad[1] /= subFactor; setDirty(); } @Override public RingROI copy() { RingROI c = new RingROI(spt[0], spt[1], rad[0], rad[1], dpp, clippingCompensation); c.setAverageArea(averageArea); c.name = name; c.plot = plot; return c; } @Override public boolean containsPoint(double x, double y) { x -= spt[0]; y -= spt[1]; double r = Math.hypot(x, y); return r >= rad[0] && r <= rad[1]; } @Override public boolean isNearOutline(double x, double y, double distance) { x -= spt[0]; y -= spt[1]; double r = Math.hypot(x, y); return Math.abs(r - rad[0]) <= distance || Math.abs(r - rad[1]) <= distance; } @Override public String toString() { return super.toString() + String.format("Centre %s Radii %s", Arrays.toString(spt), Arrays.toString(rad)); } @Override public double[] findHorizontalIntersections(double y) { y -= spt[1]; if (y < -rad[1] || y > rad[1]) { return null; } double x = spt[0]; if (y == -rad[1] || y == rad[1]) { // outer touching case return new double[]{x}; } double xo = Math.sqrt(rad[1]*rad[1] - y*y); if (y < -rad[0] || y > rad[0]) { return new double[] {x - xo, x + xo}; } if (y == -rad[0] || y == rad[0]) { // inner touching case return new double[]{x - xo, x, x + xo}; } double xi = Math.sqrt(rad[0]*rad[0] - y*y); return new double[]{x - xo, x - xi, x + xi, x + xo}; } @Override public int hashCode() { final int prime = 31; int result = super.hashCode(); result = prime * result + (averageArea ? 1231 : 1237); result = prime * result + (clippingCompensation ? 1231 : 1237); long temp; temp = Double.doubleToLongBits(dpp); result = prime * result + (int) (temp ^ (temp >>> 32)); result = prime * result + Arrays.hashCode(rad); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (!super.equals(obj)) return false; RingROI other = (RingROI) obj; if (averageArea != other.averageArea) return false; if (clippingCompensation != other.clippingCompensation) return false; if (Double.doubleToLongBits(dpp) != Double.doubleToLongBits(other.dpp)) return false; if (!Arrays.equals(rad, other.rad)) return false; return true; } }