/*-
*******************************************************************************
* 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.handler;
import org.eclipse.dawnsci.analysis.api.roi.IParametricROI;
import org.eclipse.dawnsci.analysis.dataset.roi.CircularROI;
import org.eclipse.dawnsci.analysis.dataset.roi.EllipticalROI;
import org.eclipse.dawnsci.analysis.dataset.roi.HyperbolicROI;
import org.eclipse.dawnsci.analysis.dataset.roi.OrientableROIBase;
import org.eclipse.dawnsci.analysis.dataset.roi.ParabolicROI;
/**
* Wrapper class for a IParametricROI that adds handles. If the ROI is closed then it has five handles
* otherwise it is open (i.e. unbounded) and has four handles (as one is considered to be at infinity).
* An open parametric ROI usually has its infinity at the parameter of its orientation angle.
*
* Handle 0 is focus (or centre), 1 is periapsis, 2 is c/w of 1 at the latus rectum or minor axis
* intersection points, 3 is a/c of 1 at the other intersection point, and 4 is apoapsis if closed.
*/
public class ParametricROIHandler<T extends IParametricROI> extends ROIHandler<T> {
/**
* Number of handle areas
*/
private final static int NHANDLE = 5;
private boolean closed;
/**
* Handler for RectangularROI
* @param roi
*/
public ParametricROIHandler(T roi, boolean isClosed) {
super();
this.roi = roi;
closed = isClosed;
for (int h = 0; h < NHANDLE; h++) {
add(-1);
}
if (!closed) {
remove(NHANDLE - 1);
}
}
@Override
public int getCentreHandle() {
return 0;
}
private static final double FAR = 1e3;
@Override
public double[] getHandlePoint(int handle, int size) {
double m = (roi.getStartParameter(FAR) + roi.getEndParameter(FAR)) * 0.5;
double[] pt = null;
switch (handle) {
case 0:
pt = roi.getPoint();
break;
case 1:
pt = roi.getPoint(m);
break;
case 2:
pt = roi.getPoint(m*0.5);
break;
case 3:
pt = roi.getPoint(m*1.5);
break;
case 4:
if (closed)
pt = roi.getPoint(0);
break;
}
return pt;
}
@Override
public double[] getAnchorPoint(int handle, int size) {
double m = (roi.getStartParameter(FAR) + roi.getEndParameter(FAR)) * 0.5;
double[] pt = null;
switch (handle) {
case 0:
pt = roi.getPoint();
break;
case 1:
pt = roi.getPoint(m);
break;
case 2:
pt = roi.getPoint(m*0.5);
break;
case 3:
pt = roi.getPoint(m*1.5);
break;
case 4:
if (closed)
pt = roi.getPoint(0);
break;
}
return pt;
}
/**
* @param spt starting point
* @param pt
* @return resized ROI
*/
@SuppressWarnings("unchecked")
public T resize(double[] spt, double[] pt) {
T rroi = null;
if (!closed && handle == 4)
return rroi;
rroi = (T) roi.copy();
pt[0] -= spt[0];
pt[1] -= spt[1];
switch (handle) {
case -1: // new definition
rroi.setPoint(spt);
break;
case 0: // focus/centre
rroi.addPoint(pt);
break;
case 1: // periapsis
if (rroi instanceof CircularROI) {
if (pt[0] == 0)
break;
CircularROI lroi = (CircularROI) rroi;
// work out perpendicular displacement
double r = lroi.getRadius();
r -= pt[0];
if (r < 0)
r = 0;
lroi.setRadius(r);
} else if (rroi instanceof OrientableROIBase) {
// work out perpendicular displacement
double a = rroi.getAngle();
double d = pt[0] * Math.cos(a) + pt[1] * Math.sin(a);
if (d == 0)
break;
if (rroi instanceof EllipticalROI) {
EllipticalROI lroi = (EllipticalROI) rroi;
double r = lroi.getSemiAxis(0) - d;
if (r < 0)
r = 0;
lroi.setSemiAxis(0, r);
} else if (rroi instanceof ParabolicROI) {
ParabolicROI lroi = (ParabolicROI) rroi;
double p = lroi.getFocalParameter() - d;
if (p < 0)
p = 0;
lroi.setFocalParameter(p);
} else if (rroi instanceof HyperbolicROI) {
HyperbolicROI lroi = (HyperbolicROI) rroi;
double l = lroi.getSemilatusRectum();
double e = lroi.getEccentricity();
double x = l / (1 + e) - d;
e = l / x - 1;
if (e < 1)
e = 1;
lroi.setEccentricity(e);
}
}
break;
case 2:
if (rroi instanceof CircularROI) {
if (pt[1] == 0)
break;
CircularROI lroi = (CircularROI) rroi;
double r = lroi.getRadius();
r += pt[1];
if (r < 0)
r = 0;
lroi.setRadius(r);
} else if (rroi instanceof OrientableROIBase) {
// work out perpendicular displacement
double a = rroi.getAngle();
double d = -pt[0] * Math.sin(a) + pt[1] * Math.cos(a);
if (d == 0)
break;
if (rroi instanceof EllipticalROI) {
EllipticalROI lroi = (EllipticalROI) rroi;
// work out perpendicular displacement
double r = lroi.getSemiAxis(1) + d;
if (r < 0)
r = 0;
lroi.setSemiAxis(1, r);
} else if (rroi instanceof ParabolicROI) {
ParabolicROI lroi = (ParabolicROI) rroi;
double p = lroi.getFocalParameter() + 0.5 * d;
if (p < 0)
p = 0;
lroi.setFocalParameter(p);
} else if (rroi instanceof HyperbolicROI) {
HyperbolicROI lroi = (HyperbolicROI) rroi;
double l = lroi.getSemilatusRectum() + d;
if (l < 0)
l = 0;
lroi.setSemilatusRectum(l);
}
}
break;
case 3:
if (rroi instanceof CircularROI) {
if (pt[1] == 0)
break;
CircularROI lroi = (CircularROI) rroi;
double r = lroi.getRadius();
r -= pt[1];
if (r < 0)
r = 0;
lroi.setRadius(r);
} else if (rroi instanceof OrientableROIBase) {
// work out perpendicular displacement
double a = rroi.getAngle();
double d = -pt[0] * Math.sin(a) + pt[1] * Math.cos(a);
if (d == 0)
break;
if (rroi instanceof EllipticalROI) {
EllipticalROI lroi = (EllipticalROI) rroi;
// work out perpendicular displacement
double r = lroi.getSemiAxis(1) - d;
if (r < 0)
r = 0;
lroi.setSemiAxis(1, r);
} else if (rroi instanceof ParabolicROI) {
ParabolicROI lroi = (ParabolicROI) rroi;
double p = lroi.getFocalParameter() - 0.5 * d;
if (p < 0)
p = 0;
lroi.setFocalParameter(p);
} else if (rroi instanceof HyperbolicROI) {
HyperbolicROI lroi = (HyperbolicROI) rroi;
double l = lroi.getSemilatusRectum() - d;
if (l < 0)
l = 0;
lroi.setSemilatusRectum(l);
}
}
break;
case 4:
if (closed) {
if (rroi instanceof CircularROI) {
if (pt[0] == 0)
break;
CircularROI lroi = (CircularROI) rroi;
double r = lroi.getRadius();
r += pt[0];
if (r < 0)
r = 0;
lroi.setRadius(r);
} else if (rroi instanceof EllipticalROI) {
EllipticalROI lroi = (EllipticalROI) rroi;
// work out perpendicular displacement
double a = lroi.getAngle();
double d = pt[0] * Math.cos(a) + pt[1] * Math.sin(a);
if (d == 0)
break;
double r = lroi.getSemiAxis(0) + d;
if (r < 0)
r = 0;
lroi.setSemiAxis(0, r);
}
}
break;
default:
break;
}
return rroi;
}
/**
* @param pt
* @return reoriented ROI
*/
public T reorient(@SuppressWarnings("unused") double[] pt) {
return null; // TODO
}
@SuppressWarnings("unchecked")
@Override
public T interpretMouseDragging(double[] spt, double[] ept) {
T croi = null; // return null if not a valid event
switch (status) {
case RMOVE:
croi = (T) roi.copy();
ept[0] -= spt[0];
ept[1] -= spt[1];
croi.addPoint(ept);
break;
case NONE:
croi = (T) roi.copy();
// croi.setEndPoint(ept);
break;
case REORIENT:
croi = reorient(ept);
break;
case RESIZE:
croi = resize(spt, ept);
break;
case ROTATE:
// croi = (T) roi.copy();
// double ang = croi.getAngleRelativeToMidPoint(ept);
// double[] mpt = croi.getMidPoint();
// croi.setAngle(ang);
// croi.setMidPoint(mpt);
break;
case CMOVE:
break;
case CRMOVE:
break;
}
if (croi == null) {
throw new UnsupportedOperationException("Not implemented yet");
}
return croi;
}
}