Squiz Matrix  4.12.2
 All Data Structures Namespaces Functions Variables Pages
PolygonRoi.java
1 package ij.gui;
2 import java.awt.*;
3 import java.awt.image.*;
4 import ij.*;
5 import ij.process.*;
6 import ij.measure.*;
7 
9 public class PolygonRoi extends Roi {
10 
11  protected int maxPoints = 1000; // will be increased if necessary
12  protected int[] xp, yp; // image coordinates relative to origin of roi bounding box
13  protected int[] xp2, yp2; // absolute screen coordinates
14  protected int nPoints;
15  protected int[] xSpline,ySpline; // relative image coordinates
16  protected int[] xScreenSpline,yScreenSpline; // absolute screen coordinates
17  protected int splinePoints = 200;
18  Rectangle clip;
19 
20  private double angle1=-1.0, degrees=-1.0;
21  private int xClipMin, yClipMin, xClipMax, yClipMax;
22 
23  long mouseUpTime = 0;
24 
27  public PolygonRoi(int[] xPoints, int[] yPoints, int nPoints, int type) {
28  super(0, 0, null);
29  if (type==POLYGON)
30  this.type = POLYGON;
31  else if (type==FREEROI)
32  this.type = FREEROI;
33  else if (type==TRACED_ROI)
34  this.type = TRACED_ROI;
35  else if (type==POLYLINE)
36  this.type = POLYLINE;
37  else if (type==FREELINE)
38  this.type = FREELINE;
39  else if (type==ANGLE)
40  this.type = ANGLE;
41  else
42  throw new IllegalArgumentException("Invalid type");
43  maxPoints = nPoints;
44  this.nPoints = nPoints;
45  xp = xPoints;
46  yp = yPoints;
47  if (type!=TRACED_ROI) {
48  xp = new int[nPoints];
49  yp = new int[nPoints];
50  for (int i=0; i<nPoints; i++) {
51  xp[i] = xPoints[i];
52  yp[i] = yPoints[i];
53  }
54  }
55  xp2 = new int[nPoints];
56  yp2 = new int[nPoints];
57  if (type==ANGLE && nPoints==3)
58  getAngleAsString();
59  finishPolygon();
60  }
61 
64  public PolygonRoi(Polygon p, int type) {
65  this(p.xpoints, p.ypoints, p.npoints, type);
66  }
67 
69  public PolygonRoi(int[] xPoints, int[] yPoints, int nPoints, ImagePlus imp, int type) {
70  this(xPoints, yPoints, nPoints, type);
71  setImage(imp);
72  }
73 
75  public PolygonRoi(int ox, int oy, ImagePlus imp) {
76  super(ox, oy, imp);
77  int tool = Toolbar.getToolId();
78  if (tool==Toolbar.POLYGON)
79  type = POLYGON;
80  else if (tool==Toolbar.ANGLE)
81  type = ANGLE;
82  else
83  type = POLYLINE;
84  xp = new int[maxPoints];
85  yp = new int[maxPoints];
86  xp2 = new int[maxPoints];
87  yp2 = new int[maxPoints];
88  nPoints = 2;
89  x = ox;
90  y = oy;
91  width=1;
92  height=1;
93  clipX = ox;
94  clipY = oy;
95  clipWidth = 1;
96  clipHeight = 1;
97  state = CONSTRUCTING;
98  }
99 
100  private void drawStartBox(Graphics g) {
101  if (type!=ANGLE)
102  g.drawRect(ic.screenX(startX)-4, ic.screenY(startY)-4, 8, 8);
103  }
104 
105  public void draw(Graphics g) {
106  updatePolygon();
107  g.setColor(ROIColor);
108  if (xSpline!=null) {
109  if (type==POLYLINE || type==FREELINE)
110  g.drawPolyline(xScreenSpline, yScreenSpline, splinePoints);
111  else
112  g.drawPolygon(xScreenSpline, yScreenSpline, splinePoints);
113  } else {
114  if (type==POLYLINE || type==FREELINE || type==ANGLE || state==CONSTRUCTING)
115  g.drawPolyline(xp2, yp2, nPoints);
116  else
117  g.drawPolygon(xp2, yp2, nPoints);
118  if (state==CONSTRUCTING && type!=FREEROI && type!=FREELINE)
119  drawStartBox(g);
120  }
121  //g.drawRect(clip.x, clip.y, clip.width, clip.height);
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;
126  if (activeHandle>0)
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);
132  }
133  drawPreviousRoi(g);
134  if (!(state==MOVING_HANDLE||state==CONSTRUCTING||state==NORMAL))
135  showStatus();
136  if (updateFullWindow)
137  {updateFullWindow = false; imp.draw();}
138  }
139 
140  public void drawPixels() {
141  ImageProcessor ip = imp.getProcessor();
142  if (xSpline!=null) {
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]);
148  } else {
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]);
154  }
155  if (xSpline!=null || Line.getWidth()>1)
156  updateFullWindow = true;
157  }
158 
159  protected void grow(int x, int y) {
160  // Overrides grow() in Roi class
161  }
162 
163 
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++) {
168  xp2[i] = xp[i]+x;
169  yp2[i] = yp[i]+y;
170  }
171  } else {
172  for (int i=0; i<nPoints; i++) {
173  xp2[i] = ic.screenX(xp[i]+x);
174  yp2[i] = ic.screenY(yp[i]+y);
175  }
176  }
177  if (xSpline!=null) {
178  for (int i=0; i<splinePoints; i++) {
179  xScreenSpline[i] = ic.screenX(xSpline[i]+x);
180  yScreenSpline[i] = ic.screenY(ySpline[i]+y);
181  }
182  }
183  }
184 
185  void handleMouseMove(int ox, int oy) {
186  // Do rubber banding
187  int tool = Toolbar.getToolId();
188  if (!(tool==Toolbar.POLYGON || tool==Toolbar.POLYLINE || tool==Toolbar.ANGLE)) {
189  imp.killRoi();
190  imp.draw();
191  return;
192  }
193  drawRubberBand(ox, oy);
194  degrees = -1;
195  double len = -1;
196  if (nPoints>1) {
197  int x1 = xp[nPoints-2];
198  int y1 = yp[nPoints-2];
199  int x2 = xp[nPoints-1];
200  int y2 = yp[nPoints-1];
201  degrees = getAngle(x1, y1, x2, y2);
202  if (tool!=Toolbar.ANGLE) {
203  Calibration cal = imp.getCalibration();
204  len = Math.sqrt((x2-x1)*cal.pixelWidth*(x2-x1)*cal.pixelWidth
205  + (y2-y1)*cal.pixelHeight*(y2-y1)*cal.pixelHeight);
206  }
207  }
208  if (tool==Toolbar.ANGLE) {
209  if (nPoints==2)
210  angle1 = degrees;
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));
214  if (degrees>180.0)
215  degrees = 360.0-degrees;
216  }
217  }
218  String length = len!=-1?", length=" + IJ.d2s(len):"";
219  String angle = degrees!=-1?", angle=" + IJ.d2s(degrees):"";
220  IJ.showStatus(imp.getLocationAsString(ox,oy) + length + angle);
221  }
222 
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;
241  //clip = new Rectangle(xmin, ymin, xmax-xmin, ymax-ymin);
242  int margin = 4;
243  if (ic!=null) {
244  double mag = ic.getMagnification();
245  if (mag<1.0) margin = (int)(margin/mag);
246  }
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);
250  }
251 
252  void finishPolygon() {
253  Polygon poly = new Polygon(xp, yp, nPoints);
254  Rectangle r = poly.getBounds();
255  x = r.x;
256  y = r.y;
257  width = r.width;
258  height = r.height;
259  if ((nPoints<2) || (!(type==FREELINE||type==POLYLINE||type==ANGLE) && (nPoints<3||width==0||height==0))) {
260  if (imp!=null) imp.killRoi();
261  return;
262  }
263  for (int i=0; i<nPoints; i++) {
264  xp[i] = xp[i]-x;
265  yp[i] = yp[i]-y;
266  }
267  state = NORMAL;
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;
271  modifyRoi();
272  }
273 
274  protected void moveHandle(int ox, int oy) {
275  if (clipboard!=null)
276  return;
277  xp[activeHandle] = ox-x;
278  yp[activeHandle] = oy-y;
279  if (xSpline!=null) {
280  fitSpline(splinePoints);
281  updateClipRect();
282  imp.draw(clipX, clipY, clipWidth, clipHeight);
283  oldX = x; oldY = y;
284  oldWidth = width; oldHeight = height;
285  } else {
286  resetBoundingRect();
287  updateClipRectAndDraw();
288  }
289  String angle = type==ANGLE?getAngleAsString():"";
290  IJ.showStatus(imp.getLocationAsString(ox,oy) + angle);
291  }
292 
294  void updateClipRectAndDraw() {
295  int xmin=Integer.MAX_VALUE, ymin=Integer.MAX_VALUE, xmax=0, ymax=0;
296  int x2, y2;
297  if (activeHandle>0)
298  {x2=x+xp[activeHandle-1]; y2=y+yp[activeHandle-1];}
299  else
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];}
312  else
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);
327  }
328 
329  void resetBoundingRect() {
330  int xmin=Integer.MAX_VALUE, xmax=-xmin, ymin=xmin, ymax=xmax;
331  int xx, yy;
332  for(int i=0; i<nPoints; i++) {
333  xx = xp[i];
334  if (xx<xmin) xmin=xx;
335  if (xx>xmax) xmax=xx;
336  yy = yp[i];
337  if (yy<ymin) ymin=yy;
338  if (yy>ymax) ymax=yy;
339  }
340  if (xmin!=0)
341  for (int i=0; i<nPoints; i++)
342  xp[i] -= xmin;
343  if (ymin!=0)
344  for (int i=0; i<nPoints; i++)
345  yp[i] -= ymin;
346  //IJ.log("reset: "+ymin+" "+before+" "+yp[0]);
347  x+=xmin; y+=ymin;
348  width=xmax-xmin; height=ymax-ymin;
349  }
350 
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));
355  if (degrees>180.0)
356  degrees = 360.0-degrees;
357  return ", angle=" + IJ.d2s(degrees);
358  }
359 
360  protected void mouseDownInHandle(int handle, int sx, int sy) {
361  if (state==CONSTRUCTING)
362  return;
363  state = MOVING_HANDLE;
364  activeHandle = handle;
365  int ox=ic.offScreenX(sx), oy=ic.offScreenY(sy);
366  int m = (int)(10.0/ic.getMagnification());
367  xClipMin=ox-m; yClipMin=oy-m; xClipMax=ox+m; yClipMax=oy+m;
368  }
369 
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];
377  }
378  int nNodes = nPoints;
379  if (type==POLYGON) {
380  nNodes++;
381  if (nNodes>=xp.length)
382  enlargeArrays();
383  xp[nNodes-1] = xp[0];
384  yp[nNodes-1] = yp[0];
385  }
386  int[] xindex = new int[nNodes];
387  for(int i=0; i<nNodes; i++)
388  xindex[i] = i;
389  SplineFitter sfx = new SplineFitter(xindex, xp, nNodes);
390  SplineFitter sfy = new SplineFitter(xindex, yp, nNodes);
391 
392  // Evaluate the splines at all points
393  double scale = (double)(nNodes-1)/(splinePoints-1);
394  int xs=0, ys=0;
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;
401  xSpline[i] = 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;
405  ySpline[i] = ys;
406  }
407  if (xmin!=0) {
408  for (int i=0; i<nPoints; i++)
409  xp[i] -= xmin;
410  for (int i=0; i<splinePoints; i++)
411  xSpline[i] -= xmin;
412  }
413  if (ymin!=0) {
414  for (int i=0; i<nPoints; i++)
415  yp[i] -= ymin;
416  for (int i=0; i<splinePoints; i++)
417  ySpline[i] -= ymin;
418  }
419  //IJ.log("reset: "+ymin+" "+before+" "+yp[0]);
420  x+=xmin; y+=ymin;
421  width=xmax-xmin; height=ymax-ymin;
422  }
423 
424  /*
425  double getSplineLength() {
426  int nNodes = nPoints;
427  if (type==POLYGON) {
428  nNodes++;
429  if (nNodes==xp.length)
430  enlargeArrays();
431  xp[nNodes-1] = xp[0];
432  yp[nNodes-1] = yp[0];
433  }
434  int[] xindex = new int[nNodes];
435  for(int i=0; i<nNodes; i++)
436  xindex[i] = i;
437  SplineFitter sfx = new SplineFitter(xindex, xp, nNodes);
438  SplineFitter sfy = new SplineFitter(xindex, yp, nNodes);
439 
440  double scale = (double)(nNodes-1)/(splinePoints-1);
441  double xs=0.0, ys=0.0;
442  double length = 0.0;
443  for(int i=0; i<splinePoints; i++) {
444  double xvalue = i*scale;
445  xs = sfx.evalSpline(xindex, xp, nNodes, xvalue);
446  ys = sfy.evalSpline(xindex, yp, nNodes, xvalue);
447  length += Math.sqrt(xs*xs + ys*ys);
448  }
449  //if (type==POLYGON)
450  return length;
451  }
452  */
453 
454  protected void handleMouseUp(int sx, int sy) {
455  if (state==MOVING)
456  {state = NORMAL; return;}
457  if (state==MOVING_HANDLE) {
458  cachedMask = null; //mask is no longer valid
459  state = NORMAL;
460  updateClipRect();
461  oldX=x; oldY=y;
462  oldWidth=width; oldHeight=height;
463  return;
464  }
465  if (state!=CONSTRUCTING)
466  return;
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)
470  || (ic.offScreenX(sx)==startX && ic.offScreenY(sy)==startY)
471  || (samePoint && (System.currentTimeMillis()-mouseUpTime)<=500))) {
472  nPoints--;
473  addOffset();
474  finishPolygon();
475  return;
476  } else if (!samePoint) {
477  mouseUpTime = System.currentTimeMillis();
478  if (type==ANGLE && nPoints==3) {
479  addOffset();
480  finishPolygon();
481  return;
482  }
483  //add point to polygon
484  xp[nPoints] = xp[nPoints-1];
485  yp[nPoints] = yp[nPoints-1];
486  nPoints++;
487  if (nPoints==xp.length)
488  enlargeArrays();
489  }
490  }
491 
492  protected void addOffset() {
493  for (int i=0; i<nPoints; i++) {
494  xp[i] = xp[i]+x;
495  yp[i] = yp[i]+y;
496  }
497  }
498 
499  public boolean contains(int x, int y) {
500  if (!super.contains(x, y))
501  return false;
502  else if (xScreenSpline!=null) {
503  Polygon poly = new Polygon(xScreenSpline, yScreenSpline, splinePoints);
504  return poly.contains(ic.screenX(x), ic.screenY(y));
505  } else {
506  Polygon poly = new Polygon(xp2, yp2, nPoints);
507  return poly.contains(ic.screenX(x), ic.screenY(y));
508  }
509  }
510 
513  public int isHandle(int sx, int sy) {
514  if (!(xSpline!=null||type==POLYGON||type==POLYLINE||type==ANGLE)||clipboard!=null)
515  return -1;
516  int size = HANDLE_SIZE+5;
517  int halfSize = size/2;
518  int handle = -1;
519  int sx2, sy2;
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) {
523  handle = i;
524  break;
525  }
526  }
527  return handle;
528  }
529 
531  //public void nudge(int key) {
532  // super.nudge(key);
533  // if (xSpline!=null) {
534  // fitSpline();
535  // updateFullWindow = true;
536  // imp.draw();
537  // }
538  //}
539 
541  if (cachedMask!=null)
542  return cachedMask;
543  PolygonFiller pf = new PolygonFiller();
544  if (xSpline!=null)
545  pf.setPolygon(xSpline, ySpline, splinePoints);
546  else
547  pf.setPolygon(xp, yp, nPoints);
548  cachedMask = pf.getMask(width, height);
549  return cachedMask;
550  }
551 
552  /*
553  public int[] getMask() {
554  if (type==POLYLINE || type==FREELINE || type==ANGLE || width==0 || height==0)
555  return null;
556  Image img = GUI.createBlankImage(width, height);
557  Graphics g = img.getGraphics();
558  //g.setColor(Color.white);
559  //g.fillRect(0, 0, width, height);
560  g.setColor(Color.black);
561  if (xSpline!=null)
562  g.fillPolygon(xSpline, ySpline, splinePoints);
563  else
564  g.fillPolygon(xp, yp, nPoints);
565  //new ImagePlus("Mask", img).show();
566  ColorProcessor cp = new ColorProcessor(img);
567  img.flush();
568  img = null;
569  g.dispose();
570  return (int[])cp.getPixels();
571  }
572  */
573 
576  double getSmoothedLineLength() {
577  double length = 0.0;
578  double w2 = 1.0;
579  double h2 = 1.0;
580  double dx, dy;
581  if (imp!=null) {
582  Calibration cal = imp.getCalibration();
583  w2 = cal.pixelWidth*cal.pixelWidth;
584  h2 = cal.pixelHeight*cal.pixelHeight;
585  }
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++) {
590  x1=x2; x2=x3; x3=x4;
591  y1=y2; y2=y3; y3=y4;;
592  if ((i+2)<nPoints) {
593  x4=xp[i+2];
594  y4=yp[i+2];
595  }
596  dx = (x4-x1)/3.0; // = (x2+x3+x4)/3-(x1+x2+x3)/3
597  dy = (y4-y1)/3.0; // = (y2+y3+y4)/3-(y1+y2+y3)/3
598  length += Math.sqrt(dx*dx*w2+dy*dy*h2);
599  }
600  return length;
601  }
602 
605  double getSmoothedPerimeter() {
606  double length = 0.0;
607  double w2 = 1.0;
608  double h2 = 1.0;
609  double dx, dy;
610  if (imp!=null) {
611  Calibration cal = imp.getCalibration();
612  w2 = cal.pixelWidth*cal.pixelWidth;
613  h2 = cal.pixelHeight*cal.pixelHeight;
614  }
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++) {
619  x1=x2; x2=x3; x3=x4;
620  y1=y2; y2=y3; y3=y4;;
621  if ((i+2)<nPoints) {
622  x4=xp[i+2];
623  y4=yp[i+2];
624  } else {
625  x4=xp[0];
626  y4=yp[0];
627  }
628  dx = (x4-x1)/3.0; // = (x2+x3+x4)/3-(x1+x2+x3)/3
629  dy = (y4-y1)/3.0; // = (y2+y3+y4)/3-(y1+y2+y3)/3
630  length += Math.sqrt(dx*dx*w2+dy*dy*h2);
631  }
632  x1=x2; x2=x3; x3=x4; x4=xp[1];
633  y1=y2; y2=y3; y3=y4; y4=yp[1];
634  dx = (x4-x1)/3.0;
635  dy = (y4-y1)/3.0;
636  length += Math.sqrt(dx*dx*w2+dy*dy*h2);
637  return length;
638  }
639 
643  double getTracedPerimeter() {
644  int sumdx = 0;
645  int sumdy = 0;
646  int nCorners = 0;
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); //one of these is 0
650  boolean corner = false;
651  int nexti, dx2, dy2, side2;
652  for (int i=0; i<nPoints; i++) {
653  nexti = i+1;
654  if (nexti==nPoints)
655  nexti = 0;
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) {
662  corner = true;
663  nCorners++;
664  } else
665  corner = false;
666  dx1 = dx2;
667  dy1 = dy2;
668  side1 = side2;
669  }
670  double w=1.0,h=1.0;
671  if (imp!=null) {
672  Calibration cal = imp.getCalibration();
673  w = cal.pixelWidth;
674  h = cal.pixelHeight;
675  }
676  return sumdx*w+sumdy*h-(nCorners*((w+h)-Math.sqrt(w*w+h*h)));
677  }
678 
680  public double getLength() {
681  if (type==TRACED_ROI)
682  return getTracedPerimeter();
683 
684  if (nPoints>2) {
685  if (type==FREEROI)
686  return getSmoothedPerimeter();
687  else if (type==FREELINE && !(width==0 || height==0))
688  return getSmoothedLineLength();
689  }
690 
691  double length = 0.0;
692  int dx, dy;
693  Calibration cal = imp.getCalibration();
694  double w2 = cal.pixelWidth*cal.pixelWidth;
695  double h2 = cal.pixelHeight*cal.pixelHeight;
696  if (xSpline!=null) {
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);
701  }
702  if (type==POLYGON) {
703  dx = xSpline[0]-xSpline[splinePoints-1];
704  dy = ySpline[0]-ySpline[splinePoints-1];
705  length += Math.sqrt(dx*dx*w2+dy*dy*h2);
706  }
707  } else {
708  for (int i=0; i<(nPoints-1); i++) {
709  dx = xp[i+1]-xp[i];
710  dy = yp[i+1]-yp[i];
711  length += Math.sqrt(dx*dx*w2+dy*dy*h2);
712  }
713  if (type==POLYGON) {
714  dx = xp[0]-xp[nPoints-1];
715  dy = yp[0]-yp[nPoints-1];
716  length += Math.sqrt(dx*dx*w2+dy*dy*h2);
717  }
718  }
719  return length;
720  }
721 
724  public double getFeretsDiameter() {
725  double w2=1.0, h2=1.0;
726  if (imp!=null) {
727  Calibration cal = imp.getCalibration();
728  w2 = cal.pixelWidth*cal.pixelWidth;
729  h2 = cal.pixelHeight*cal.pixelHeight;
730  }
731  double diameter = 0.0, dx, dy, d;
732  for (int i=0; i<nPoints; i++) {
733  for (int j=i; j<nPoints; j++) {
734  dx = xp[i] - xp[j];
735  dy = yp[i] - yp[j];
736  d = Math.sqrt(dx*dx*w2 + dy*dy*h2);
737  if (d>diameter)
738  diameter = d;
739  }
740  }
741  return diameter;
742  }
743 
745  public double getAngle() {
746  return degrees;
747  }
748 
750  public int getNCoordinates() {
751  if (xSpline!=null)
752  return splinePoints;
753  else
754  return nPoints;
755  }
756 
759  public int[] getXCoordinates() {
760  if (xSpline!=null)
761  return xSpline;
762  else
763  return xp;
764  }
765 
768  public int[] getYCoordinates() {
769  if (xSpline!=null)
770  return ySpline;
771  else
772  return yp;
773  }
774 
780  public Polygon getPolygon() {
781  int n;
782  int[] xpoints1, ypoints1;
783  if (xSpline!=null) {
784  n = splinePoints;
785  xpoints1 = xSpline;
786  ypoints1 = ySpline;
787  } else {
788  n = nPoints;
789  xpoints1 = xp;
790  ypoints1 = yp;
791  }
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;
797  }
798  return new Polygon(xpoints2, ypoints2, n);
799  }
800 
802  public synchronized Object clone() {
803  PolygonRoi r = (PolygonRoi)super.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++) {
809  r.xp[i] = xp[i];
810  r.yp[i] = yp[i];
811  r.xp2[i] = xp2[i];
812  r.yp2[i] = yp2[i];
813  }
814  if (xSpline!=null) {
815  r.xSpline = null;
816  r.fitSpline(splinePoints);
817  }
818  return r;
819  }
820 
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");
833  maxPoints *= 2;
834  }
835 
836 }