package ij.gui;
import java.awt.*;
import java.awt.image.*;
import java.awt.geom.*;
import java.awt.event.KeyEvent;
import java.util.*;
import ij.*;
import ij.process.*;
import ij.measure.*;
import ij.plugin.frame.Recorder;
import ij.plugin.filter.Analyzer;
import ij.util.Tools;
public class ShapeRoi extends Roi {
static final int NO_TYPE = 128;
static final double MAXERROR = 1.0e-3;
static final double FLATNESS = 0.1;
private static final int MAXPOLY = 10;
private static final int OR=0, AND=1, XOR=2, NOT=3;
private static final double SHAPE_TO_ROI=-1.0;
private Shape shape;
private double maxerror = ShapeRoi.MAXERROR;
private double flatness = ShapeRoi.FLATNESS;
private int maxPoly = ShapeRoi.MAXPOLY;
private boolean flatten;
private boolean forceTrace = false;
private boolean forceAngle = false;
private Vector savedRois;
private static Stroke defaultStroke = new BasicStroke();
public ShapeRoi(Roi r) {
this(r, ShapeRoi.FLATNESS, ShapeRoi.MAXERROR, false, false, false, ShapeRoi.MAXPOLY);
}
public ShapeRoi(Shape s) {
super(s.getBounds());
AffineTransform at = new AffineTransform();
at.translate(-x, -y);
shape = new GeneralPath(at.createTransformedShape(s));
type = COMPOSITE;
}
public ShapeRoi(int x, int y, Shape s) {
super(x, y, s.getBounds().width, s.getBounds().height);
shape = new GeneralPath(s);
type = COMPOSITE;
}
ShapeRoi(Roi r, double flatness, double maxerror, boolean forceAngle, boolean forceTrace, boolean flatten, int maxPoly) {
super(r.startX, r.startY, r.width, r.height);
this.type = COMPOSITE;
this.flatness = flatness;
this.maxerror = maxerror;
this.forceAngle = forceAngle;
this.forceTrace = forceTrace;
this.maxPoly= maxPoly;
this.flatten = flatten;
shape = roiToShape((Roi)r.clone());
}
public ShapeRoi(float[] shapeArray) {
super(0,0,null);
shape = makeShapeFromArray(shapeArray);
Rectangle r = shape.getBounds();
x = r.x;
y = r.y;
width = r.width;
height = r.height;
state = NORMAL;
oldX=x; oldY=y; oldWidth=width; oldHeight=height;
AffineTransform at = new AffineTransform();
at.translate(-x, -y);
shape = new GeneralPath(at.createTransformedShape(shape));
flatness = ShapeRoi.FLATNESS;
maxerror = ShapeRoi.MAXERROR;
maxPoly = ShapeRoi.MAXPOLY;
flatten = false;
type = COMPOSITE;
}
public synchronized Object clone() { ShapeRoi sr = (ShapeRoi)super.clone();
sr.type = COMPOSITE;
sr.flatness = flatness;
sr.maxerror = maxerror;
sr.forceAngle = forceAngle;
sr.forceTrace = forceTrace;
sr.setShape(ShapeRoi.cloneShape(shape));
return sr;
}
static Shape cloneShape(Shape rhs) {
if(rhs==null) return null;
if(rhs instanceof Rectangle2D.Double) { return (Rectangle2D.Double)((Rectangle2D.Double)rhs).clone(); }
else if(rhs instanceof Ellipse2D.Double) { return (Ellipse2D.Double)((Ellipse2D.Double)rhs).clone(); }
else if(rhs instanceof Line2D.Double) { return (Line2D.Double)((Line2D.Double)rhs).clone(); }
else if(rhs instanceof Polygon) { return new Polygon(((Polygon)rhs).xpoints, ((Polygon)rhs).ypoints, ((Polygon)rhs).npoints); }
else if(rhs instanceof GeneralPath) { return (GeneralPath)((GeneralPath)rhs).clone(); }
return new GeneralPath(); }
public ShapeRoi or(ShapeRoi sr) {return unaryOp(sr, OR);}
public ShapeRoi and(ShapeRoi sr) {return unaryOp(sr, AND);}
public ShapeRoi xor(ShapeRoi sr) {return unaryOp(sr, XOR);}
public ShapeRoi not(ShapeRoi sr) {return unaryOp(sr, NOT);}
ShapeRoi unaryOp(ShapeRoi sr, int op) {
AffineTransform at = new AffineTransform();
at.translate(x, y);
Area a1 = new Area(at.createTransformedShape(getShape()));
at = new AffineTransform();
at.translate(sr.x, sr.y);
Area a2 = new Area(at.createTransformedShape(sr.getShape()));
try {
switch (op) {
case OR: a1.add(a2); break;
case AND: a1.intersect(a2); break;
case XOR: a1.exclusiveOr(a2); break;
case NOT: a1.subtract(a2); break;
}
} catch(Exception e) {}
Rectangle r = a1.getBounds();
at = new AffineTransform();
at.translate(-r.x, -r.y);
setShape(new GeneralPath(at.createTransformedShape(a1)));
x = r.x;
y = r.y;
cachedMask = null;
return this;
}
private Shape roiToShape(Roi roi) {
Shape shape = null;
Rectangle r = roi.getBounds();
int[] xCoords = null;
int[] yCoords = null;
int nCoords = 0;
switch(roi.getType()) {
case Roi.LINE:
Line line = (Line)roi;
shape = new Line2D.Double ((double)(line.x1-r.x), (double)(line.y1-r.y), (double)(line.x2-r.x), (double)(line.y2-r.y) );
break;
case Roi.RECTANGLE:
int arcSize = roi.getCornerDiameter();
if (arcSize>0)
shape = new RoundRectangle2D.Float(0, 0, r.width, r.height, arcSize, arcSize);
else
shape = new Rectangle2D.Double(0.0, 0.0, (double)r.width, (double)r.height);
break;
case Roi.OVAL:
Polygon p = roi.getPolygon();
for (int i=0; i<p.npoints; i++) {
p.xpoints[i] -= r.x;
p.ypoints[i] -= r.y;
}
shape = new Polygon(p.xpoints, p.ypoints, p.npoints);
break;
case Roi.POLYGON:
nCoords =((PolygonRoi)roi).getNCoordinates();
xCoords = ((PolygonRoi)roi).getXCoordinates();
yCoords = ((PolygonRoi)roi).getYCoordinates();
shape = new Polygon(xCoords,yCoords,nCoords);
break;
case Roi.FREEROI: case Roi.TRACED_ROI:
nCoords =((PolygonRoi)roi).getNCoordinates();
xCoords = ((PolygonRoi)roi).getXCoordinates();
yCoords = ((PolygonRoi)roi).getYCoordinates();
shape = new GeneralPath(GeneralPath.WIND_EVEN_ODD,nCoords);
((GeneralPath)shape).moveTo((float)xCoords[0], (float)yCoords[0]);
for (int i=1; i<nCoords; i++)
((GeneralPath)shape).lineTo((float)xCoords[i],(float)yCoords[i]);
((GeneralPath)shape).closePath();
break;
case Roi.POLYLINE: case Roi.FREELINE: case Roi.ANGLE:
nCoords =((PolygonRoi)roi).getNCoordinates();
xCoords = ((PolygonRoi)roi).getXCoordinates();
yCoords = ((PolygonRoi)roi).getYCoordinates();
shape = new GeneralPath(GeneralPath.WIND_NON_ZERO,nCoords);
((GeneralPath)shape).moveTo((float)xCoords[0], (float)yCoords[0]);
for (int i=1; i<nCoords; i++)
((GeneralPath)shape).lineTo((float)xCoords[i],(float)yCoords[i]);
break;
case Roi.POINT:
ImageProcessor mask = roi.getMask();
byte[] maskPixels = (byte[])mask.getPixels();
Rectangle maskBounds = roi.getBounds();
int maskWidth = mask.getWidth();
Area area = new Area();
for (int y=0; y<mask.getHeight(); y++) {
int yOffset = y*maskWidth;
for (int x=0; x<maskWidth; x++) {
if (maskPixels[x+yOffset]!=0)
area.add(new Area(new Rectangle(x+maskBounds.x, y+maskBounds.y, 1, 1)));
}
}
shape = area;
break;
case Roi.COMPOSITE: shape = ShapeRoi.cloneShape(((ShapeRoi)roi).getShape());
break;
default:
throw new IllegalArgumentException("Roi type not supported");
}
if(shape!=null) {
this.x = roi.x;
this.y = roi.y;
Rectangle bounds = shape.getBounds();
this.width = bounds.width;
this.height = bounds.height;
this.startX = x;
this.startY = y;
}
return shape;
}
Shape makeShapeFromArray(float[] array) {
if(array==null) return null;
Shape s = new GeneralPath(GeneralPath.WIND_EVEN_ODD);
int index=0, type, len;
float[] seg = new float[7];
while (true) {
len = getSegment(array, seg, index);
if (len<0) break;
index += len;
type = (int)seg[0];
switch(type) {
case PathIterator.SEG_MOVETO:
((GeneralPath)s).moveTo(seg[1], seg[2]);
break;
case PathIterator.SEG_LINETO:
((GeneralPath)s).lineTo(seg[1], seg[2]);
break;
case PathIterator.SEG_QUADTO:
((GeneralPath)s).quadTo(seg[1], seg[2],seg[3], seg[4]);
break;
case PathIterator.SEG_CUBICTO:
((GeneralPath)s).curveTo(seg[1], seg[2], seg[3], seg[4], seg[5], seg[6]);
break;
case PathIterator.SEG_CLOSE:
((GeneralPath)s).closePath();
break;
default: break;
}
}
return s;
}
private int getSegment(float[] array, float[] seg, int index) {
int len = array.length;
if (index>=len) return -1; seg[0]=array[index++];
int type = (int)seg[0];
if (type==PathIterator.SEG_CLOSE) return 1;
if (index>=len) return -1; seg[1]=array[index++];
if (index>=len) return -1; seg[2]=array[index++];
if (type==PathIterator.SEG_MOVETO||type==PathIterator.SEG_LINETO) return 3;
if (index>=len) return -1; seg[3]=array[index++];
if (index>=len) return -1; seg[4]=array[index++];
if (type==PathIterator.SEG_QUADTO) return 5;
if (index>=len) return -1; seg[5]=array[index++];
if (index>=len) return -1; seg[6]=array[index++];
if (type==PathIterator.SEG_CUBICTO) return 7;
return -1;
}
void saveRoi(Roi roi) {
if (savedRois==null)
savedRois = new Vector();
savedRois.addElement(roi);
}
public Roi[] getRois () {
if (shape==null)
return new Roi[0];
if (savedRois!=null)
return getSavedRois();
Vector rois = new Vector();
if (shape instanceof Rectangle2D.Double) {
Roi r = new Roi((int)((Rectangle2D.Double)shape).getX(), (int)((Rectangle2D.Double)shape).getY(), (int)((Rectangle2D.Double)shape).getWidth(), (int)((Rectangle2D.Double)shape).getHeight());
rois.addElement(r);
} else if (shape instanceof Ellipse2D.Double) {
Roi r = new OvalRoi((int)((Ellipse2D.Double)shape).getX(), (int)((Ellipse2D.Double)shape).getY(), (int)((Ellipse2D.Double)shape).getWidth(), (int)((Ellipse2D.Double)shape).getHeight());
rois.addElement(r);
} else if (shape instanceof Line2D.Double) {
Roi r = new ij.gui.Line((int)((Line2D.Double)shape).getX1(), (int)((Line2D.Double)shape).getY1(), (int)((Line2D.Double)shape).getX2(), (int)((Line2D.Double)shape).getY2());
rois.addElement(r);
} else if (shape instanceof Polygon) {
Roi r = new PolygonRoi(((Polygon)shape).xpoints, ((Polygon)shape).ypoints, ((Polygon)shape).npoints, Roi.POLYGON);
rois.addElement(r);
} else if (shape instanceof GeneralPath) {
PathIterator pIter;
if (flatten)
pIter = getFlatteningPathIterator(shape,flatness);
else
pIter = shape.getPathIterator(new AffineTransform());
parsePath(pIter, null, null, rois, null);
}
Roi[] array = new Roi[rois.size()];
rois.copyInto((Roi[])array);
return array;
}
Roi[] getSavedRois () {
Roi[] array = new Roi[savedRois.size()];
savedRois.copyInto((Roi[])array);
return array;
}
public Roi shapeToRoi() {
if (shape==null || !(shape instanceof GeneralPath))
return null;
PathIterator pIter = shape.getPathIterator(new AffineTransform());
Vector rois = new Vector();
double[] params = {SHAPE_TO_ROI};
if (!parsePath(pIter, params, null, rois, null))
return null;
if (rois.size()==1)
return (Roi)rois.elementAt(0);
else
return null;
}
private int guessType(int segments, boolean linesOnly, boolean curvesOnly, boolean closed) {
closed = true; int roiType = Roi.RECTANGLE;
if (linesOnly) {
switch(segments) {
case 0: roiType = NO_TYPE; break;
case 1: roiType = NO_TYPE; break;
case 2: roiType = (closed ? NO_TYPE : Roi.LINE); break;
case 3: roiType = (closed ? Roi.POLYGON : (forceAngle ? Roi.ANGLE: Roi.POLYLINE)); break;
case 4: roiType = (closed ? Roi.RECTANGLE : Roi.POLYLINE); break;
default:
if (segments <= MAXPOLY)
roiType = closed ? Roi.POLYGON : Roi.POLYLINE;
else
roiType = closed ? (forceTrace ? Roi.TRACED_ROI: Roi.FREEROI): Roi.FREELINE;
break;
}
}
else roiType = segments >=2 ? Roi.COMPOSITE : NO_TYPE;
return roiType;
}
private Roi createRoi(Vector xCoords, Vector yCoords, int roiType) {
if (roiType==NO_TYPE) return null;
Roi roi = null;
if(xCoords.size() != yCoords.size() || xCoords.size()==0) { return null; }
int[] xPoints = new int[xCoords.size()];
int[] yPoints = new int[yCoords.size()];
for (int i=0; i<xPoints.length; i++) {
xPoints[i] = ((Integer)xCoords.elementAt(i)).intValue() + x;
yPoints[i] = ((Integer)yCoords.elementAt(i)).intValue() + y;
}
int startX = 0;
int startY = 0;
int width = 0;
int height = 0;
switch(roiType) {
case Roi.COMPOSITE: roi = this; break; case Roi.OVAL:
startX = xPoints[xPoints.length-4];
startY = yPoints[yPoints.length-3];
width = max(xPoints)-min(xPoints);
height = max(yPoints)-min(yPoints);
roi = new OvalRoi(startX, startY, width, height);
break;
case Roi.RECTANGLE:
startX = xPoints[0];
startY = yPoints[0];
width = max(xPoints)-min(xPoints);
height = max(yPoints)-min(yPoints);
roi = new Roi(startX, startY, width, height);
break;
case Roi.LINE: roi = new ij.gui.Line(xPoints[0],yPoints[0],xPoints[1],yPoints[1]); break;
default:
int n = xPoints.length;
roi = new PolygonRoi(xPoints, yPoints, n, roiType);
if (roiType==FREEROI) {
double length = roi.getLength();
double mag = ic!=null?ic.getMagnification():1.0;
length *= mag;
if (length/n>=15.0) {
roi = new PolygonRoi(xPoints, yPoints, n, POLYGON);
}
}
break;
}
return roi;
}
public boolean contains(int x, int y) {
if(shape==null) return false;
return shape.contains(x-this.x, y-this.y);
}
public double[] getFeretValues() {
Roi[] rois = getRois();
if (rois!=null && rois.length==1) {
rois[0].setImage(imp);
return rois[0].getFeretValues();
}
double min=Double.MAX_VALUE, diameter=0.0, angle=0.0;
int p1=0, p2=0;
double pw=1.0, ph=1.0;
if (imp!=null) {
Calibration cal = imp.getCalibration();
pw = cal.pixelWidth;
ph = cal.pixelHeight;
}
Shape shape = getShape();
Shape s = null;
Rectangle2D r = shape.getBounds2D();
double cx = r.getX() + r.getWidth()/2;
double cy = r.getY() + r.getHeight()/2;
AffineTransform at = new AffineTransform();
at.translate(cx, cy);
for (int i=0; i<181; i++) {
at.rotate(Math.PI/180.0);
s = at.createTransformedShape(shape);
r = s.getBounds2D();
double max2 = Math.max(r.getWidth(), r.getHeight());
if (max2>diameter) {
diameter = max2*pw;
}
double min2 = Math.min(r.getWidth(), r.getHeight());
min = Math.min(min, min2);
}
if (pw!=ph) {
diameter = 0.0;
angle = 0.0;
}
if (pw==ph)
min *= pw;
else {
min = 0.0;
angle = 0.0;
}
double[] a = new double[5];
a[0] = diameter;
a[1] = angle;
a[2] = min;
a[3] = 0.0; a[4] = 0.0; return a;
}
public double getLength() {
if (width==0 && height==0)
return 0.0;
double length = 0.0;
Roi[] rois = getRois();
ImagePlus imp2 = getImage();
if (rois!=null) {
for (int i=0; i<rois.length; i++) {
Roi roi = rois[i];
if (roi instanceof ShapeRoi)
return 0.0;
roi.setImage(imp2);
length += roi.getLength();
roi.setImage(null);
}
}
return length;
}
FlatteningPathIterator getFlatteningPathIterator(Shape s, double fl) {
return (FlatteningPathIterator)s.getPathIterator(new AffineTransform(),fl);
}
double cplength(CubicCurve2D.Double c) {
double result = Math.sqrt(Math.pow((c.ctrlx1-c.x1),2.0)+Math.pow((c.ctrly1-c.y1),2.0));
result += Math.sqrt(Math.pow((c.ctrlx2-c.ctrlx1),2.0)+Math.pow((c.ctrly2-c.ctrly1),2.0));
result += Math.sqrt(Math.pow((c.x2-c.ctrlx2),2.0)+Math.pow((c.y2-c.ctrly2),2.0));
return result;
}
double qplength(QuadCurve2D.Double c) {
double result = Math.sqrt(Math.pow((c.ctrlx-c.x1),2.0)+Math.pow((c.ctrly-c.y1),2.0));
result += Math.sqrt(Math.pow((c.x2-c.ctrlx),2.0)+Math.pow((c.y2-c.ctrly),2.0));
return result;
}
double cclength(CubicCurve2D.Double c)
{ return Math.sqrt(Math.pow((c.x2-c.x1),2.0) + Math.pow((c.y2-c.y1),2.0)); }
double qclength(QuadCurve2D.Double c)
{ return Math.sqrt(Math.pow((c.x2-c.x1),2.0) + Math.pow((c.y2-c.y1),2.0)); }
double cBezLength(CubicCurve2D.Double c) {
double l = 0.0;
double cl = cclength(c);
double pl = cplength(c);
if((pl-cl)/2.0 > maxerror)
{
CubicCurve2D.Double[] cc = cBezSplit(c);
for(int i=0; i<2; i++) l+=cBezLength(cc[i]);
return l;
}
l = 0.5*pl+0.5*cl;
return l;
}
double qBezLength(QuadCurve2D.Double c) {
double l = 0.0;
double cl = qclength(c);
double pl = qplength(c);
if((pl-cl)/2.0 > maxerror)
{
QuadCurve2D.Double[] cc = qBezSplit(c);
for(int i=0; i<2; i++) l+=qBezLength(cc[i]);
return l;
}
l = (2.0*pl+cl)/3.0;
return l;
}
CubicCurve2D.Double[] cBezSplit(CubicCurve2D.Double c) {
CubicCurve2D.Double[] cc = new CubicCurve2D.Double[2];
for (int i=0; i<2 ; i++) cc[i] = new CubicCurve2D.Double();
c.subdivide(cc[0],cc[1]);
return cc;
}
QuadCurve2D.Double[] qBezSplit(QuadCurve2D.Double c) {
QuadCurve2D.Double[] cc = new QuadCurve2D.Double[2];
for(int i=0; i<2; i++) cc[i] = new QuadCurve2D.Double();
c.subdivide(cc[0],cc[1]);
return cc;
}
void scaleCoords(double[] c, double pw, double ph) {
int k = c.length/2;
if (2*k!=c.length) return; for(int i=0; i<c.length; i+=2)
{
c[i]*=pw;
c[i+1]*=ph;
}
}
Vector parseSegments(PathIterator pI) {
Vector v = new Vector();
if (parsePath(pI, null, v, null, null)) return v;
return null;
}
public float[] getShapeAsArray() {
if(shape==null) return null;
PathIterator pIt = shape.getPathIterator(new AffineTransform());
Vector h = new Vector(); Vector s = new Vector(); if (!(parsePath(pIt, null, s, null, h))) return null;
float[] result = new float[7*s.size()];
Point2D.Double p;
int segType;
int k=0, j=0;
int index = 0;
for (int i=0; i<s.size(); i++) {
segType = ((Integer)s.elementAt(i)).intValue();
switch(segType) {
case PathIterator.SEG_MOVETO: case PathIterator.SEG_LINETO:
result[index++] = segType;
p = (Point2D.Double)h.elementAt(j++);
result[index++]=(float)p.getX()+x; result[index++]=(float)p.getY()+y;
break;
case PathIterator.SEG_QUADTO:
result[index++] = segType;
p = (Point2D.Double)h.elementAt(j++);
result[index++]=(float)p.getX()+x; result[index++]=(float)p.getY()+y;
p = (Point2D.Double)h.elementAt(j++);
result[index++]=(float)p.getX()+x; result[index++]=(float)p.getY()+y;
break;
case PathIterator.SEG_CUBICTO:
result[index++] = segType;
p = (Point2D.Double)h.elementAt(j++);
result[index++]=(float)p.getX()+x; result[index++]=(float)p.getY()+y;
p = (Point2D.Double)h.elementAt(j++);
result[index++]=(float)p.getX()+x; result[index++]=(float)p.getY()+y;
p = (Point2D.Double)h.elementAt(j++);
result[index++]=(float)p.getX()+x; result[index++]=(float)p.getY()+y;
break;
case PathIterator.SEG_CLOSE:
result[index++] = segType;
break;
default: break;
}
}
float[] result2 = new float[index];
System.arraycopy(result, 0, result2, 0, result2.length);
return result2;
}
boolean parsePath(PathIterator pIter, double[] params, Vector segments, Vector rois, Vector handles) {
if (pIter==null || pIter.isDone())
return false;
boolean result = true;
double pw = 1.0, ph = 1.0;
if (imp!=null) {
Calibration cal = imp.getCalibration();
pw = cal.pixelWidth;
ph = cal.pixelHeight;
}
Vector xCoords = new Vector();
Vector yCoords = new Vector();
if (segments==null) segments = new Vector();
if (handles==null) handles = new Vector();
if (params == null) params = new double[1];
boolean shapeToRoi = params[0]==SHAPE_TO_ROI;
int subPaths = 0; int count = 0; int roiType = Roi.RECTANGLE;
int segType;
boolean closed = false;
boolean linesOnly = true;
boolean curvesOnly = true;
double[] coords; double[] ucoords; double sX = Double.NaN; double sY = Double.NaN; double x0 = Double.NaN; double y0 = Double.NaN; double usX = Double.NaN; double usY = Double.NaN;
double ux0 = Double.NaN;
double uy0 = Double.NaN;
double pathLength = 0.0;
Shape curve; boolean done = false;
while (!done) {
coords = new double[6];
ucoords = new double[6];
segType = pIter.currentSegment(coords);
segments.add(new Integer(segType));
count++;
System.arraycopy(coords,0,ucoords,0,coords.length);
scaleCoords(coords,pw,ph);
switch(segType) {
case PathIterator.SEG_MOVETO:
if (subPaths>0) {
closed = ((int)ux0==(int)usX && (int)uy0==(int)usY);
if (closed && (int)ux0!=(int)usX && (int)uy0!=(int)usY) { xCoords.add(new Integer(((Integer)xCoords.elementAt(0)).intValue()));
yCoords.add(new Integer(((Integer)yCoords.elementAt(0)).intValue()));
}
if (rois!=null) {
roiType = guessType(count, linesOnly, curvesOnly, closed);
Roi r = createRoi(xCoords, yCoords, roiType);
if (r!=null)
rois.addElement(r);
}
xCoords = new Vector();
yCoords = new Vector();
count = 1;
}
subPaths++;
usX = ucoords[0];
usY = ucoords[1];
ux0 = ucoords[0];
uy0 = ucoords[1];
sX = coords[0];
sY = coords[1];
x0 = coords[0];
y0 = coords[1];
handles.add(new Point2D.Double(ucoords[0],ucoords[1]));
xCoords.add(new Integer((int)ucoords[0]));
yCoords.add(new Integer((int)ucoords[1]));
closed = false;
break;
case PathIterator.SEG_LINETO:
linesOnly = linesOnly & true;
curvesOnly = curvesOnly & false;
pathLength += Math.sqrt(Math.pow((y0-coords[1]),2.0)+Math.pow((x0-coords[0]),2.0));
ux0 = ucoords[0];
uy0 = ucoords[1];
x0 = coords[0];
y0 = coords[1];
handles.add(new Point2D.Double(ucoords[0],ucoords[1]));
xCoords.add(new Integer((int)ucoords[0]));
yCoords.add(new Integer((int)ucoords[1]));
closed = ((int)ux0==(int)usX && (int)uy0==(int)usY);
break;
case PathIterator.SEG_QUADTO:
linesOnly = linesOnly & false;
curvesOnly = curvesOnly & true;
curve = new QuadCurve2D.Double(x0,y0,coords[0],coords[2],coords[2],coords[3]);
pathLength += qBezLength((QuadCurve2D.Double)curve);
ux0 = ucoords[2];
uy0 = ucoords[3];
x0 = coords[2];
y0 = coords[3];
handles.add(new Point2D.Double(ucoords[0],ucoords[1]));
handles.add(new Point2D.Double(ucoords[2],ucoords[3]));
xCoords.add(new Integer((int)ucoords[2]));
yCoords.add(new Integer((int)ucoords[3]));
closed = ((int)ux0==(int)usX && (int)uy0==(int)usY);
break;
case PathIterator.SEG_CUBICTO:
linesOnly = linesOnly & false;
curvesOnly = curvesOnly & true;
curve = new CubicCurve2D.Double(x0,y0,coords[0],coords[1],coords[2],coords[3],coords[4],coords[5]);
pathLength += cBezLength((CubicCurve2D.Double)curve);
ux0 = ucoords[4];
uy0 = ucoords[5];
x0 = coords[4];
y0 = coords[5];
handles.add(new Point2D.Double(ucoords[0],ucoords[1]));
handles.add(new Point2D.Double(ucoords[2],ucoords[3]));
handles.add(new Point2D.Double(ucoords[4],ucoords[5]));
xCoords.add(new Integer((int)ucoords[4]));
yCoords.add(new Integer((int)ucoords[5]));
closed = ((int)ux0==(int)usX && (int)uy0==(int)usY);
break;
case PathIterator.SEG_CLOSE:
if((int)ux0 != (int)usX && (int)uy0 != (int)usY) pathLength += Math.sqrt(Math.pow((x0-sX),2.0) + Math.pow((y0-sY),2.0));
closed = true;
break;
default:
break;
}
pIter.next();
done = pIter.isDone() || (shapeToRoi&&rois!=null&&rois.size()==1);
if (done) {
if(closed && (int)x0!=(int)sX && (int)y0!=(int)sY) { xCoords.add(new Integer(((Integer)xCoords.elementAt(0)).intValue()));
yCoords.add(new Integer(((Integer)yCoords.elementAt(0)).intValue()));
}
if (rois!=null) {
roiType = shapeToRoi?TRACED_ROI:guessType(count+1, linesOnly, curvesOnly, closed);
Roi r = createRoi(xCoords, yCoords, roiType);
if (r!=null)
rois.addElement(r);
}
}
}
params[0] = pathLength;
return result;
}
public void draw(Graphics g) {
Color color = strokeColor!=null? strokeColor:ROIColor;
boolean isActiveOverlayRoi = !overlay && isActiveOverlayRoi();
if (isActiveOverlayRoi)
color = Color.cyan;
if (fillColor!=null) color = fillColor;
g.setColor(color);
AffineTransform aTx = (((Graphics2D)g).getDeviceConfiguration()).getDefaultTransform();
Graphics2D g2d = (Graphics2D)g;
if (stroke!=null && !isActiveOverlayRoi)
g2d.setStroke((ic!=null&&ic.getCustomRoi())||isCursor()?stroke:getScaledStroke());
mag = getMagnification();
int basex=0, basey=0;
if (ic!=null) {
Rectangle r = ic.getSrcRect();
basex=r.x; basey=r.y;
}
aTx.setTransform(mag, 0.0, 0.0, mag, -basex*mag, -basey*mag);
aTx.translate(x, y);
if (fillColor!=null) {
if (isActiveOverlayRoi) {
g2d.setColor(Color.cyan);
g2d.draw(aTx.createTransformedShape(shape));
} else
g2d.fill(aTx.createTransformedShape(shape));
} else
g2d.draw(aTx.createTransformedShape(shape));
if (stroke!=null) g2d.setStroke(defaultStroke);
if (Toolbar.getToolId()==Toolbar.OVAL)
drawRoiBrush(g);
if (state!=NORMAL && imp!=null && imp.getRoi()!=null)
showStatus();
if (updateFullWindow)
{updateFullWindow = false; imp.draw();}
}
public void drawRoiBrush(Graphics g) {
g.setColor(ROIColor);
int size = Toolbar.getBrushSize();
if (size==0 || ic==null)
return;
int flags = ic.getModifiers();
if ((flags&16)==0) return; size = (int)(size*mag);
Point p = ic.getCursorLoc();
int sx = ic.screenX(p.x);
int sy = ic.screenY(p.y);
g.drawOval(sx-size/2, sy-size/2, size, size);
}
public void drawPixels(ImageProcessor ip) {
PathIterator pIter = shape.getPathIterator(new AffineTransform(), flatness);
float[] coords = new float[6];
float sx=0f, sy=0f;
while (!pIter.isDone()) {
int segType = pIter.currentSegment(coords);
switch(segType) {
case PathIterator.SEG_MOVETO:
sx = coords[0];
sy = coords[1];
ip.moveTo(x+(int)sx, y+(int)sy);
break;
case PathIterator.SEG_LINETO:
ip.lineTo(x+(int)coords[0], y+(int)coords[1]);
break;
case PathIterator.SEG_CLOSE:
ip.lineTo(x+(int)sx, y+(int)sy);
break;
default: break;
}
pIter.next();
}
}
public ImageProcessor getMask() {
if (shape==null)
return null;
if (cachedMask!=null && cachedMask.getPixels()!=null)
return cachedMask;
BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY);
Graphics2D g2d = bi.createGraphics();
g2d.setColor(Color.white);
g2d.fill(shape);
Raster raster = bi.getRaster();
DataBufferByte buffer = (DataBufferByte)raster.getDataBuffer();
byte[] mask = buffer.getData();
cachedMask = new ByteProcessor(width, height, mask, null);
cachedMask.setThreshold(255,255,ImageProcessor.NO_LUT_UPDATE);
return cachedMask;
}
public Shape getShape() {
return shape;
}
boolean setShape(Shape rhs) {
boolean result = true;
if (rhs==null) return false;
if (shape.equals(rhs)) return false;
shape = rhs;
type = Roi.COMPOSITE;
Rectangle rect = shape.getBounds();
width = rect.width;
height = rect.height;
return true;
}
private int min(int[] array) {
int val = array[0];
for (int i=1; i<array.length; i++) val = Math.min(val,array[i]);
return val;
}
private int max(int[] array) {
int val = array[0];
for (int i=1; i<array.length; i++) val = Math.max(val,array[i]);
return val;
}
static ShapeRoi getCircularRoi(int x, int y, int width) {
return new ShapeRoi(new OvalRoi(x - width / 2, y - width / 2, width, width));
}
public int isHandle(int sx, int sy) {
return -1;
}
public Polygon getConvexHull() {
Roi[] rois = getRois();
if (rois!=null && rois.length==1)
return rois[0].getConvexHull();
else
return null;
}
public Polygon getPolygon() {
Roi[] rois = getRois();
if (rois!=null && rois.length==1)
return rois[0].getPolygon();
else
return super.getPolygon();
}
public FloatPolygon getFloatPolygon() {
Roi[] rois = getRois();
if (rois!=null && rois.length==1)
return rois[0].getFloatPolygon();
else
return super.getFloatPolygon();
}
}