package ij.gui;
import java.awt.*;
import java.awt.image.*;
import java.awt.geom.*;
import ij.*;
import ij.process.*;
import ij.measure.Calibration;
public class OvalRoi extends Roi {
public OvalRoi(int x, int y, int width, int height) {
super(x, y, width, height);
type = OVAL;
}
public OvalRoi(double x, double y, double width, double height) {
super(x, y, width, height);
type = OVAL;
}
public static OvalRoi create(double x, double y, double width, double height) {
return new OvalRoi(x, y, width, height);
}
public OvalRoi(int x, int y, ImagePlus imp) {
super(x, y, imp);
type = OVAL;
}
public OvalRoi(int x, int y, int width, int height, ImagePlus imp) {
this(x, y, width, height);
setImage(imp);
}
public double[] getFeretValues() {
double[] a = new double[FERET_ARRAYSIZE];
double pw=1.0, ph=1.0;
if (imp!=null) {
Calibration cal = imp.getCalibration();
pw = cal.pixelWidth;
ph = cal.pixelHeight;
}
boolean highAspect = ph*height > pw*width;
a[0] = highAspect ? height*ph : width*pw; a[1] = highAspect ? 90.0 : 0.0; a[2] = highAspect ? width*pw : height*ph; a[3] = (x + (highAspect ? 0.5*width : 0)) * pw; a[4] = (y + (highAspect ? height : 0.5*height)) * ph; int i = FERET_ARRAY_POINTOFFSET;
a[i++] = x + (highAspect ? 0.5*width : 0); a[i++] = y + (highAspect ? height : 0.5*height);
a[i++] = x + (highAspect ? 0.5*width : width); a[i++] = y + (highAspect ? 0 : 0.5*height);
a[i++] = x + (highAspect ? 0 : 0.5*width); a[i++] = y + (highAspect ? 0.5*height : height);
a[i++] = x + (highAspect ? width : 0.5*width); a[i++] = y + (highAspect ? 0.5*height : 0);
return a;
}
protected void moveHandle(int sx, int sy) {
double asp;
if (clipboard!=null) return;
int ox = offScreenX(sx);
int oy = offScreenY(sy);
int x1=x, y1=y, x2=x+width, y2=y+height, xc=x+width/2, yc=y+height/2;
int w2 = (int)(0.14645*width);
int h2 = (int)(0.14645*height);
if (width > 7 && height > 7) {
asp = (double)width/(double)height;
asp_bk = asp;
} else
asp = asp_bk;
switch (activeHandle) {
case 0: x=ox-w2; y=oy-h2; break;
case 1: y=oy; break;
case 2: x2=ox+w2; y=oy-h2; break;
case 3: x2=ox; break;
case 4: x2=ox+w2; y2=oy+h2; break;
case 5: y2=oy; break;
case 6: x=ox-w2; y2=oy+h2; break;
case 7: x=ox; break;
}
if (x<x2)
width=x2-x;
else
{width=1; x=x2;}
if (y<y2)
height = y2-y;
else
{height=1; y=y2;}
if (center) {
switch(activeHandle){
case 0:
width=(xc-x)*2;
height=(yc-y)*2;
break;
case 1:
height=(yc-y)*2;
break;
case 2:
width=(x2-xc)*2;
x=x2-width;
height=(yc-y)*2;
break;
case 3:
width=(x2-xc)*2;
x=x2-width;
break;
case 4:
width=(x2-xc)*2;
x=x2-width;
height=(y2-yc)*2;
y=y2-height;
break;
case 5:
height=(y2-yc)*2;
y=y2-height;
break;
case 6:
width=(xc-x)*2;
height=(y2-yc)*2;
y=y2-height;
break;
case 7:
width=(xc-x)*2;
break;
}
if (x>=x2) {
width=1;
x=x2=xc;
}
if (y>=y2) {
height=1;
y=y2=yc;
}
}
if (constrain) {
if (activeHandle==1 || activeHandle==5) width=height;
else height=width;
if (x>=x2) {
width=1;
x=x2=xc;
}
if (y>=y2) {
height=1;
y=y2=yc;
}
switch(activeHandle){
case 0:
x=x2-width;
y=y2-height;
break;
case 1:
x=xc-width/2;
y=y2-height;
break;
case 2:
y=y2-height;
break;
case 3:
y=yc-height/2;
break;
case 5:
x=xc-width/2;
break;
case 6:
x=x2-width;
break;
case 7:
y=yc-height/2;
x=x2-width;
break;
}
if (center){
x=xc-width/2;
y=yc-height/2;
}
}
if (aspect && !constrain) {
if (activeHandle==1 || activeHandle==5) width=(int)Math.rint((double)height*asp);
else height=(int)Math.rint((double)width/asp);
switch (activeHandle) {
case 0:
x=x2-width;
y=y2-height;
break;
case 1:
x=xc-width/2;
y=y2-height;
break;
case 2:
y=y2-height;
break;
case 3:
y=yc-height/2;
break;
case 5:
x=xc-width/2;
break;
case 6:
x=x2-width;
break;
case 7:
y=yc-height/2;
x=x2-width;
break;
}
if (center) {
x=xc-width/2;
y=yc-height/2;
}
if (width<8) {
if (width<1) width = 1;
height=(int)Math.rint((double)width/asp_bk);
}
if (height<8) {
if (height<1) height =1;
width=(int)Math.rint((double)height*asp_bk);
}
}
updateClipRect();
imp.draw(clipX, clipY, clipWidth, clipHeight);
oldX=x; oldY=y;
oldWidth=width; oldHeight=height;
cachedMask = null;
bounds = null;
}
public void draw(Graphics g) {
Color color = strokeColor!=null? strokeColor:ROIColor;
if (fillColor!=null) color = fillColor;
g.setColor(color);
mag = getMagnification();
int sw = (int)(width*mag);
int sh = (int)(height*mag);
int sx1 = screenX(x);
int sy1 = screenY(y);
if (subPixelResolution() && bounds!=null) {
sw = (int)(bounds.width*mag);
sh = (int)(bounds.height*mag);
sx1 = screenXD(bounds.x);
sy1 = screenYD(bounds.y);
}
int sw2 = (int)(0.14645*width*mag);
int sh2 = (int)(0.14645*height*mag);
int sx2 = sx1+sw/2;
int sy2 = sy1+sh/2;
int sx3 = sx1+sw;
int sy3 = sy1+sh;
Graphics2D g2d = (Graphics2D)g;
if (stroke!=null)
g2d.setStroke(getScaledStroke());
setRenderingHint(g2d);
if (fillColor!=null) {
if (!overlay && isActiveOverlayRoi()) {
g.setColor(Color.cyan);
g.drawOval(sx1, sy1, sw, sh);
} else
g.fillOval(sx1, sy1, sw, sh);
} else
g.drawOval(sx1, sy1, sw, sh);
if (clipboard==null && !overlay) {
drawHandle(g, sx1+sw2, sy1+sh2);
drawHandle(g, sx3-sw2, sy1+sh2);
drawHandle(g, sx3-sw2, sy3-sh2);
drawHandle(g, sx1+sw2, sy3-sh2);
drawHandle(g, sx2, sy1);
drawHandle(g, sx3, sy2);
drawHandle(g, sx2, sy3);
drawHandle(g, sx1, sy2);
}
drawPreviousRoi(g);
if (updateFullWindow)
{updateFullWindow = false; imp.draw();}
if (state!=NORMAL) showStatus();
}
public void drawPixels(ImageProcessor ip) {
Polygon p = getPolygon();
if (p.npoints>0) {
int saveWidth = ip.getLineWidth();
if (getStrokeWidth()>1f)
ip.setLineWidth((int)Math.round(getStrokeWidth()));
ip.drawPolygon(p);
ip.setLineWidth(saveWidth);
}
if (Line.getWidth()>1 || getStrokeWidth()>1)
updateFullWindow = true;
}
public Polygon getPolygon() {
return getPolygon(true);
}
Polygon getPolygon(boolean absoluteCoordinates) {
ImageProcessor mask = getMask();
Wand wand = new Wand(mask);
wand.autoOutline(width/2,height/2, 255, 255);
if (absoluteCoordinates)
for (int i=0; i<wand.npoints; i++) {
wand.xpoints[i] += x;
wand.ypoints[i] += y;
}
return new Polygon(wand.xpoints, wand.ypoints, wand.npoints);
}
public FloatPolygon getFloatPolygon() {
ShapeRoi sr = new ShapeRoi(new java.awt.geom.Ellipse2D.Double(x-0.0004, y-0.0004, width+0.0008, height+0.0008)); return sr.getFloatPolygon();
}
public FloatPolygon getFloatPolygon4() {
return super.getFloatPolygon();
}
public int size() {
return getPolygon().npoints;
}
public boolean contains(int ox, int oy) {
double a = width*0.5;
double b = height*0.5;
double cx = x + a - 0.5;
double cy = y + b - 0.5;
double dx = ox - cx;
double dy = oy - cy;
return ((dx*dx)/(a*a) + (dy*dy)/(b*b)) <= 1.0;
}
public boolean containsPoint(double x, double y) {
if (!super.containsPoint(x, y))
return false;
Ellipse2D.Double e = new Ellipse2D.Double(this.x, this.y, width, height);
return e.contains(x, y);
}
public int isHandle(int sx, int sy) {
if (clipboard!=null || ic==null) return -1;
double mag = ic.getMagnification();
int size = getHandleSize()+3;
int halfSize = size/2;
int sx1 = screenX(x) - halfSize;
int sy1 = screenY(y) - halfSize;
int sx3 = screenX(x+width) - halfSize;
int sy3 = screenY(y+height) - halfSize;
int sx2 = sx1 + (sx3 - sx1)/2;
int sy2 = sy1 + (sy3 - sy1)/2;
int sw2 = (int)(0.14645*(sx3-sx1));
int sh2 = (int)(0.14645*(sy3-sy1));
if (sx>=sx1+sw2&&sx<=sx1+sw2+size&&sy>=sy1+sh2&&sy<=sy1+sh2+size) return 0;
if (sx>=sx2&&sx<=sx2+size&&sy>=sy1&&sy<=sy1+size) return 1;
if (sx>=sx3-sw2&&sx<=sx3-sw2+size&&sy>=sy1+sh2&&sy<=sy1+sh2+size) return 2;
if (sx>=sx3&&sx<=sx3+size&&sy>=sy2&&sy<=sy2+size) return 3;
if (sx>=sx3-sw2&&sx<=sx3-sw2+size&&sy>=sy3-sh2&&sy<=sy3-sh2+size) return 4;
if (sx>=sx2&&sx<=sx2+size&&sy>=sy3&&sy<=sy3+size) return 5;
if (sx>=sx1+sw2&&sx<=sx1+sw2+size&&sy>=sy3-sh2&&sy<=sy3-sh2+size) return 6;
if (sx>=sx1&&sx<=sx1+size&&sy>=sy2&&sy<=sy2+size) return 7;
return -1;
}
public ImageProcessor getMask() {
ImageProcessor mask = cachedMask;
if (mask!=null && mask.getPixels()!=null && mask.getWidth()==width && mask.getHeight()==height)
return mask;
mask = new ByteProcessor(width, height);
double a=width/2.0, b=height/2.0;
double a2=a*a, b2=b*b;
a -= 0.5; b -= 0.5;
double xx, yy;
int offset;
byte[] pixels = (byte[])mask.getPixels();
for (int y=0; y<height; y++) {
offset = y*width;
for (int x=0; x<width; x++) {
xx = x - a;
yy = y - b;
if ((xx*xx/a2+yy*yy/b2)<=1.0)
pixels[offset+x] = -1;
}
}
cachedMask = mask;
return mask;
}
public double getLength() {
double pw=1.0, ph=1.0;
if (imp!=null) {
Calibration cal = imp.getCalibration();
pw = cal.pixelWidth;
ph = cal.pixelHeight;
}
double a = 0.5*width*pw;
double b = 0.5*height*ph;
return Math.PI*(3*(a + b) - Math.sqrt((3*a + b)*(a + 3*b)));
}
}