3 import java.awt.image.*;
11 protected int maxPoints = 1000;
12 protected int[] xp, yp;
13 protected int[] xp2, yp2;
14 protected int nPoints;
15 protected int[] xSpline,ySpline;
16 protected int[] xScreenSpline,yScreenSpline;
17 protected int splinePoints = 200;
20 private double angle1=-1.0, degrees=-1.0;
21 private int xClipMin, yClipMin, xClipMax, yClipMax;
27 public PolygonRoi(
int[] xPoints,
int[] yPoints,
int nPoints,
int type) {
31 else if (type==FREEROI)
33 else if (type==TRACED_ROI)
34 this.type = TRACED_ROI;
35 else if (type==POLYLINE)
37 else if (type==FREELINE)
42 throw new IllegalArgumentException(
"Invalid type");
44 this.nPoints = nPoints;
47 if (type!=TRACED_ROI) {
48 xp =
new int[nPoints];
49 yp =
new int[nPoints];
50 for (
int i=0; i<nPoints; i++) {
55 xp2 =
new int[nPoints];
56 yp2 =
new int[nPoints];
57 if (type==ANGLE && nPoints==3)
65 this(p.xpoints, p.ypoints, p.npoints, type);
70 this(xPoints, yPoints, nPoints, type);
84 xp =
new int[maxPoints];
85 yp =
new int[maxPoints];
86 xp2 =
new int[maxPoints];
87 yp2 =
new int[maxPoints];
100 private void drawStartBox(Graphics g) {
105 public void draw(Graphics g) {
107 g.setColor(ROIColor);
109 if (type==POLYLINE || type==FREELINE)
110 g.drawPolyline(xScreenSpline, yScreenSpline, splinePoints);
112 g.drawPolygon(xScreenSpline, yScreenSpline, splinePoints);
114 if (type==POLYLINE || type==FREELINE || type==ANGLE || state==CONSTRUCTING)
115 g.drawPolyline(xp2, yp2, nPoints);
117 g.drawPolygon(xp2, yp2, nPoints);
118 if (state==CONSTRUCTING && type!=FREEROI && type!=FREELINE)
122 if ((xSpline!=null||type==POLYGON||type==POLYLINE||type==ANGLE)
123 && state!=CONSTRUCTING && clipboard==null) {
124 if (ic!=null) mag = ic.getMagnification();
125 int size2 = HANDLE_SIZE/2;
127 drawHandle(g, xp2[activeHandle-1]-size2, yp2[activeHandle-1]-size2);
128 if (activeHandle<nPoints-1)
129 drawHandle(g, xp2[activeHandle+1]-size2, yp2[activeHandle+1]-size2);
130 for (
int i=0; i<nPoints; i++)
131 drawHandle(g, xp2[i]-size2, yp2[i]-size2);
134 if (!(state==MOVING_HANDLE||state==CONSTRUCTING||state==NORMAL))
136 if (updateFullWindow)
137 {updateFullWindow =
false; imp.
draw();}
140 public void drawPixels() {
143 ip.moveTo(x+xSpline[0], y+ySpline[0]);
144 for (
int i=1; i<splinePoints; i++)
145 ip.lineTo(x+xSpline[i], y+ySpline[i]);
146 if (type==POLYGON || type==FREEROI || type==TRACED_ROI)
147 ip.lineTo(x+xSpline[0], y+ySpline[0]);
149 ip.moveTo(x+xp[0], y+yp[0]);
150 for (
int i=1; i<nPoints; i++)
151 ip.lineTo(x+xp[i], y+yp[i]);
152 if (type==POLYGON || type==FREEROI || type==TRACED_ROI)
153 ip.lineTo(x+xp[0], y+yp[0]);
155 if (xSpline!=null || Line.getWidth()>1)
156 updateFullWindow =
true;
159 protected void grow(
int x,
int y) {
164 protected void updatePolygon() {
165 Rectangle srcRect = ic.getSrcRect();
166 if (ic.getMagnification()==1.0 && srcRect.x==0 && srcRect.y==0) {
167 for (
int i=0; i<nPoints; i++) {
172 for (
int i=0; i<nPoints; i++) {
178 for (
int i=0; i<splinePoints; i++) {
179 xScreenSpline[i] = ic.
screenX(xSpline[i]+x);
180 yScreenSpline[i] = ic.
screenY(ySpline[i]+y);
185 void handleMouseMove(
int ox,
int oy) {
187 int tool = Toolbar.getToolId();
188 if (!(tool==Toolbar.POLYGON || tool==Toolbar.POLYLINE || tool==Toolbar.ANGLE)) {
193 drawRubberBand(ox, oy);
197 int x1 = xp[nPoints-2];
198 int y1 = yp[nPoints-2];
199 int x2 = xp[nPoints-1];
200 int y2 = yp[nPoints-1];
202 if (tool!=Toolbar.ANGLE) {
204 len = Math.sqrt((x2-x1)*cal.pixelWidth*(x2-x1)*cal.pixelWidth
205 + (y2-y1)*cal.pixelHeight*(y2-y1)*cal.pixelHeight);
208 if (tool==Toolbar.ANGLE) {
211 else if (nPoints==3) {
212 double angle2 =
getAngle(xp[1], yp[1], xp[2], yp[2]);
213 degrees = Math.abs(180-Math.abs(angle1-angle2));
215 degrees = 360.0-degrees;
218 String length = len!=-1?
", length=" + IJ.d2s(len):
"";
219 String angle = degrees!=-1?
", angle=" + IJ.d2s(degrees):
"";
223 void drawRubberBand(
int ox,
int oy) {
224 int x1 = xp[nPoints-2]+x;
225 int y1 = yp[nPoints-2]+y;
226 int x2 = xp[nPoints-1]+x;
227 int y2 = yp[nPoints-1]+y;
228 int xmin=9999, ymin=9999, xmax=0, ymax=0;
229 if (x1<xmin) xmin=x1;
230 if (x2<xmin) xmin=x2;
231 if (ox<xmin) xmin=ox;
232 if (x1>xmax) xmax=x1;
233 if (x2>xmax) xmax=x2;
234 if (ox>xmax) xmax=ox;
235 if (y1<ymin) ymin=y1;
236 if (y2<ymin) ymin=y2;
237 if (oy<ymin) ymin=oy;
238 if (y1>ymax) ymax=y1;
239 if (y2>ymax) ymax=y2;
240 if (oy>ymax) ymax=oy;
244 double mag = ic.getMagnification();
245 if (mag<1.0) margin = (int)(margin/mag);
247 xp[nPoints-1] = ox-x;
248 yp[nPoints-1] = oy-y;
249 imp.
draw(xmin-margin, ymin-margin, (xmax-xmin)+margin*2, (ymax-ymin)+margin*2);
252 void finishPolygon() {
253 Polygon poly =
new Polygon(xp, yp, nPoints);
254 Rectangle r = poly.getBounds();
259 if ((nPoints<2) || (!(type==FREELINE||type==POLYLINE||type==ANGLE) && (nPoints<3||width==0||height==0))) {
263 for (
int i=0; i<nPoints; i++) {
268 if (imp!=null && !(type==TRACED_ROI))
269 imp.
draw(x-5, y-5, width+10, height+10);
270 oldX=x; oldY=y; oldWidth=width; oldHeight=height;
274 protected void moveHandle(
int ox,
int oy) {
277 xp[activeHandle] = ox-x;
278 yp[activeHandle] = oy-y;
280 fitSpline(splinePoints);
282 imp.
draw(clipX, clipY, clipWidth, clipHeight);
284 oldWidth = width; oldHeight = height;
287 updateClipRectAndDraw();
289 String angle = type==ANGLE?getAngleAsString():
"";
294 void updateClipRectAndDraw() {
295 int xmin=Integer.MAX_VALUE, ymin=Integer.MAX_VALUE, xmax=0, ymax=0;
298 {x2=x+xp[activeHandle-1]; y2=y+yp[activeHandle-1];}
300 {x2=x+xp[nPoints-1]; y2=y+yp[nPoints-1];}
301 if (x2<xmin) xmin = x2;
302 if (y2<ymin) ymin = y2;
303 if (x2>xmax) xmax = x2;
304 if (y2>ymax) ymax = y2;
305 x2=x+xp[activeHandle]; y2=y+yp[activeHandle];
306 if (x2<xmin) xmin = x2;
307 if (y2<ymin) ymin = y2;
308 if (x2>xmax) xmax = x2;
309 if (y2>ymax) ymax = y2;
310 if (activeHandle<nPoints-1)
311 {x2=x+xp[activeHandle+1]; y2=y+yp[activeHandle+1];}
313 {x2=x+xp[0]; y2=y+yp[0];}
314 if (x2<xmin) xmin = x2;
315 if (y2<ymin) ymin = y2;
316 if (x2>xmax) xmax = x2;
317 if (y2>ymax) ymax = y2;
318 int xmin2=xmin, ymin2=ymin, xmax2=xmax, ymax2=ymax;
319 if (xClipMin<xmin2) xmin2 = xClipMin;
320 if (yClipMin<ymin2) ymin2 = yClipMin;
321 if (xClipMax>xmax2) xmax2 = xClipMax;
322 if (yClipMax>ymax2) ymax2 = yClipMax;
323 xClipMin=xmin; yClipMin=ymin; xClipMax=xmax; yClipMax=ymax;
324 double mag = ic.getMagnification();
325 int m = mag<1.0?(int)(HANDLE_SIZE/mag):HANDLE_SIZE;
326 imp.
draw(xmin2-m, ymin2-m, xmax2-xmin2+m*2, ymax2-ymin2+m*2);
329 void resetBoundingRect() {
330 int xmin=Integer.MAX_VALUE, xmax=-xmin, ymin=xmin, ymax=xmax;
332 for(
int i=0; i<nPoints; i++) {
334 if (xx<xmin) xmin=xx;
335 if (xx>xmax) xmax=xx;
337 if (yy<ymin) ymin=yy;
338 if (yy>ymax) ymax=yy;
341 for (
int i=0; i<nPoints; i++)
344 for (
int i=0; i<nPoints; i++)
348 width=xmax-xmin; height=ymax-ymin;
351 String getAngleAsString() {
352 double angle1 =
getAngle(xp[0], yp[0], xp[1], yp[1]);
353 double angle2 =
getAngle(xp[1], yp[1], xp[2], yp[2]);
354 degrees = Math.abs(180-Math.abs(angle1-angle2));
356 degrees = 360.0-degrees;
357 return ", angle=" + IJ.d2s(degrees);
360 protected void mouseDownInHandle(
int handle,
int sx,
int sy) {
361 if (state==CONSTRUCTING)
363 state = MOVING_HANDLE;
364 activeHandle = handle;
366 int m = (int)(10.0/ic.getMagnification());
367 xClipMin=ox-m; yClipMin=oy-m; xClipMax=ox+m; yClipMax=oy+m;
370 public void fitSpline(
int evaluationPoints) {
371 if (xSpline==null || splinePoints!=evaluationPoints) {
372 splinePoints = evaluationPoints;
373 xSpline =
new int[splinePoints];
374 ySpline =
new int[splinePoints];
375 xScreenSpline =
new int[splinePoints];
376 yScreenSpline =
new int[splinePoints];
378 int nNodes = nPoints;
381 if (nNodes>=xp.length)
383 xp[nNodes-1] = xp[0];
384 yp[nNodes-1] = yp[0];
386 int[] xindex =
new int[nNodes];
387 for(
int i=0; i<nNodes; i++)
389 SplineFitter sfx =
new SplineFitter(xindex, xp, nNodes);
390 SplineFitter sfy =
new SplineFitter(xindex, yp, nNodes);
393 double scale = (double)(nNodes-1)/(splinePoints-1);
395 int xmin=Integer.MAX_VALUE, xmax=-xmin, ymin=xmin, ymax=xmax;
396 for(
int i=0; i<splinePoints; i++) {
397 double xvalue = i*scale;
398 xs = (int) Math.floor(sfx.evalSpline(xindex, xp, nNodes, xvalue) + 0.5);
399 if (xs<xmin) xmin=xs;
400 if (xs>xmax) xmax=xs;
402 ys = (int) Math.floor(sfy.evalSpline(xindex, yp, nNodes, xvalue) + 0.5);
403 if (ys<ymin) ymin=ys;
404 if (ys>ymax) ymax=ys;
408 for (
int i=0; i<nPoints; i++)
410 for (
int i=0; i<splinePoints; i++)
414 for (
int i=0; i<nPoints; i++)
416 for (
int i=0; i<splinePoints; i++)
421 width=xmax-xmin; height=ymax-ymin;
454 protected void handleMouseUp(
int sx,
int sy) {
456 {state = NORMAL;
return;}
457 if (state==MOVING_HANDLE) {
462 oldWidth=width; oldHeight=height;
465 if (state!=CONSTRUCTING)
467 boolean samePoint = (xp[nPoints-2]==xp[nPoints-1] && yp[nPoints-2]==yp[nPoints-1]);
468 Rectangle biggerStartBox =
new Rectangle(ic.
screenX(startX)-5, ic.
screenY(startY)-5, 10, 10);
469 if (nPoints>2 && (biggerStartBox.contains(sx, sy)
471 || (samePoint && (System.currentTimeMillis()-mouseUpTime)<=500))) {
476 }
else if (!samePoint) {
477 mouseUpTime = System.currentTimeMillis();
478 if (type==ANGLE && nPoints==3) {
484 xp[nPoints] = xp[nPoints-1];
485 yp[nPoints] = yp[nPoints-1];
487 if (nPoints==xp.length)
492 protected void addOffset() {
493 for (
int i=0; i<nPoints; i++) {
499 public boolean contains(
int x,
int y) {
500 if (!super.contains(x, y))
502 else if (xScreenSpline!=null) {
503 Polygon poly =
new Polygon(xScreenSpline, yScreenSpline, splinePoints);
506 Polygon poly =
new Polygon(xp2, yp2, nPoints);
514 if (!(xSpline!=null||type==POLYGON||type==POLYLINE||type==ANGLE)||clipboard!=null)
516 int size = HANDLE_SIZE+5;
517 int halfSize = size/2;
520 for (
int i=0; i<nPoints; i++) {
521 sx2 = xp2[i]-halfSize; sy2=yp2[i]-halfSize;
522 if (sx>=sx2 && sx<=sx2+size && sy>=sy2 && sy<=sy2+size) {
541 if (cachedMask!=null)
543 PolygonFiller pf =
new PolygonFiller();
545 pf.setPolygon(xSpline, ySpline, splinePoints);
547 pf.setPolygon(xp, yp, nPoints);
548 cachedMask = pf.
getMask(width, height);
576 double getSmoothedLineLength() {
586 double x1,x2,x3,x4,y1,y2,y3,y4;
587 x2=xp[0]; x3=xp[0]; x4=xp[1];
588 y2=yp[0]; y3=yp[0]; y4=yp[1];
589 for (
int i=0; i<(nPoints-1); i++) {
591 y1=y2; y2=y3; y3=y4;;
598 length += Math.sqrt(dx*dx*w2+dy*dy*h2);
605 double getSmoothedPerimeter() {
612 w2 = cal.pixelWidth*cal.pixelWidth;
613 h2 = cal.pixelHeight*cal.pixelHeight;
615 double x1,x2,x3,x4,y1,y2,y3,y4;
616 x2=xp[nPoints-1]; x3=xp[0]; x4=xp[1];
617 y2=yp[nPoints-1]; y3=yp[0]; y4=yp[1];
618 for (
int i=0; i<(nPoints-1); i++) {
620 y1=y2; y2=y3; y3=y4;;
630 length += Math.sqrt(dx*dx*w2+dy*dy*h2);
632 x1=x2; x2=x3; x3=x4; x4=xp[1];
633 y1=y2; y2=y3; y3=y4; y4=yp[1];
636 length += Math.sqrt(dx*dx*w2+dy*dy*h2);
643 double getTracedPerimeter() {
647 int dx1 = xp[0] - xp[nPoints-1];
648 int dy1 = yp[0] - yp[nPoints-1];
649 int side1 = Math.abs(dx1) + Math.abs(dy1);
650 boolean corner =
false;
651 int nexti, dx2, dy2, side2;
652 for (
int i=0; i<nPoints; i++) {
656 dx2 = xp[nexti] - xp[i];
657 dy2 = yp[nexti] - yp[i];
658 sumdx += Math.abs(dx1);
659 sumdy += Math.abs(dy1);
660 side2 = Math.abs(dx2) + Math.abs(dy2);
661 if (side1>1 || !corner) {
676 return sumdx*w+sumdy*h-(nCorners*((w+h)-Math.sqrt(w*w+h*h)));
681 if (type==TRACED_ROI)
682 return getTracedPerimeter();
686 return getSmoothedPerimeter();
687 else if (type==FREELINE && !(width==0 || height==0))
688 return getSmoothedLineLength();
697 for (
int i=0; i<(splinePoints-1); i++) {
698 dx = xSpline[i+1]-xSpline[i];
699 dy = ySpline[i+1]-ySpline[i];
700 length += Math.sqrt(dx*dx*w2+dy*dy*h2);
703 dx = xSpline[0]-xSpline[splinePoints-1];
704 dy = ySpline[0]-ySpline[splinePoints-1];
705 length += Math.sqrt(dx*dx*w2+dy*dy*h2);
708 for (
int i=0; i<(nPoints-1); i++) {
711 length += Math.sqrt(dx*dx*w2+dy*dy*h2);
714 dx = xp[0]-xp[nPoints-1];
715 dy = yp[0]-yp[nPoints-1];
716 length += Math.sqrt(dx*dx*w2+dy*dy*h2);
725 double w2=1.0, h2=1.0;
731 double diameter = 0.0, dx, dy, d;
732 for (
int i=0; i<nPoints; i++) {
733 for (
int j=i; j<nPoints; j++) {
736 d = Math.sqrt(dx*dx*w2 + dy*dy*h2);
782 int[] xpoints1, ypoints1;
792 int[] xpoints2 =
new int[n];
793 int[] ypoints2 =
new int[n];
794 for (
int i=0; i<n; i++) {
795 xpoints2[i] = xpoints1[i] + x;
796 ypoints2[i] = ypoints1[i] + y;
798 return new Polygon(xpoints2, ypoints2, n);
802 public synchronized Object
clone() {
804 r.xp =
new int[maxPoints];
805 r.yp =
new int[maxPoints];
806 r.xp2 =
new int[maxPoints];
807 r.yp2 =
new int[maxPoints];
808 for (
int i=0; i<nPoints; i++) {
816 r.fitSpline(splinePoints);
821 void enlargeArrays() {
822 int[] xptemp =
new int[maxPoints*2];
823 int[] yptemp =
new int[maxPoints*2];
824 int[] xp2temp =
new int[maxPoints*2];
825 int[] yp2temp =
new int[maxPoints*2];
826 System.arraycopy(xp, 0, xptemp, 0, maxPoints);
827 System.arraycopy(yp, 0, yptemp, 0, maxPoints);
828 System.arraycopy(xp2, 0, xp2temp, 0, maxPoints);
829 System.arraycopy(yp2, 0, yp2temp, 0, maxPoints);
830 xp=xptemp; yp=yptemp;
831 xp2=xp2temp; yp2=yp2temp;
832 if (
IJ.debugMode)
IJ.
log(
"PolygonRoi: "+maxPoints+
" points");