4 import java.awt.image.*;
5 import java.awt.event.KeyEvent;
9 import ij.plugin.frame.Recorder;
10 import ij.plugin.filter.Analyzer;
13 public class Roi extends Object implements Cloneable, java.io.Serializable {
15 public static final int CONSTRUCTING=0, MOVING=1, RESIZING=2, NORMAL=3, MOVING_HANDLE=4;
16 public static final int RECTANGLE=0, OVAL=1, POLYGON=2, FREEROI=3, TRACED_ROI=4, LINE=5,
17 POLYLINE=6, FREELINE=7, ANGLE=8, COMPOSITE=9;
18 public static final int HANDLE_SIZE = 5;
19 public static final int NOT_PASTING = -1;
21 int startX, startY, x, y, width, height;
25 public static Roi previousRoi;
27 protected static int pasteMode = Blitter.COPY;
30 protected int xMax, yMax;
33 protected int oldX, oldY, oldWidth, oldHeight;
34 protected int clipX, clipY, clipWidth, clipHeight;
36 protected boolean constrain;
37 protected boolean center;
38 protected boolean updateFullWindow;
39 protected double mag = 1.0;
40 protected String name;
44 public Roi(
int x,
int y,
int width,
int height) {
46 if (width<1) width = 1;
47 if (height<1) height = 1;
48 if (width>xMax) width = xMax;
49 if (height>yMax) height = yMax;
53 startX = x; startY = y;
54 oldX = x; oldY = y; oldWidth=0; oldHeight=0;
66 Graphics g = ic.getGraphics();
84 this(x, y, width, height);
88 public void setLocation(
int x,
int y) {
91 if ((x+width)>xMax) x = xMax-width;
92 if ((y+height)>yMax) y = yMax-height;
96 startX = x; startY = y;
97 oldX = x; oldY = y; oldWidth=0; oldHeight=0;
109 ic = imp.getCanvas();
110 xMax = imp.getWidth();
111 yMax = imp.getHeight();
115 public int getType() {
119 public int getState() {
125 double pw=1.0, ph=1.0;
131 return 2.0*width*pw+2.0*height*ph;
137 double pw=1.0, ph=1.0;
143 return Math.sqrt(width*width*pw*pw+height*height*ph*ph);
148 return new Rectangle(x, y, width, height);
163 int[] xpoints =
new int[4];
164 int[] ypoints =
new int[4];
167 xpoints[1] = x+width;
169 xpoints[2] = x+width;
170 ypoints[2] = y+height;
172 ypoints[3] = y+height;
173 return new Polygon(xpoints, ypoints, 4);
178 public synchronized Object
clone() {
184 catch (CloneNotSupportedException e) {
return null;}
187 protected void grow(
int xNew,
int yNew) {
190 if (xNew < 0) xNew = 0;
191 if (yNew < 0) yNew = 0;
206 width = Math.abs(xNew - startX)*2;
207 height = Math.abs(yNew - startY)*2;
208 x = startX - width/2;
209 y = startY - height/2;
211 width = Math.abs(xNew - startX);
212 height = Math.abs(yNew - startY);
213 x = (xNew>=startX)?startX:startX - width;
214 y = (yNew>=startY)?startY:startY - height;
215 if ((x+width) > xMax)
217 if ((y+height) > yMax)
221 imp.
draw(clipX, clipY, clipWidth, clipHeight);
228 protected void moveHandle(
int ox,
int oy) {
231 if (ox<0) ox=0;
if (oy<0) oy=0;
232 if (ox>xMax) ox=xMax;
if (oy>yMax) oy=yMax;
234 int x1=x, y1=y, x2=x1+width, y2=y+height;
235 switch (activeHandle) {
236 case 0: x=ox; y=oy;
break;
238 case 2: x2=ox; y=oy;
break;
239 case 3: x2=ox;
break;
240 case 4: x2=ox; y2=oy;
break;
241 case 5: y2=oy;
break;
242 case 6: x=ox; y2=oy;
break;
256 imp.
draw(clipX, clipY, clipWidth, clipHeight);
258 oldWidth=width; oldHeight=height;
261 void move(
int xNew,
int yNew) {
264 if (type!=RECTANGLE || clipboard==null) {
265 if (x<0) x=0;
if (y<0) y=0;
266 if ((x+width)>xMax) x = xMax-width;
267 if ((y+height)>yMax) y = yMax-height;
272 imp.
draw(clipX, clipY, clipWidth, clipHeight);
284 if (y<0 && (type!=RECTANGLE||clipboard==null))
287 case KeyEvent.VK_DOWN:
289 if ((y+height)>=yMax && (type!=RECTANGLE||clipboard==null))
292 case KeyEvent.VK_LEFT:
294 if (x<0 && (type!=RECTANGLE||clipboard==null))
297 case KeyEvent.VK_RIGHT:
299 if ((x+width)>=xMax && (type!=RECTANGLE||clipboard==null))
304 imp.
draw(clipX, clipY, clipWidth, clipHeight);
312 if (type>OVAL || clipboard!=null)
317 if (height<1) height = 1;
319 case KeyEvent.VK_DOWN:
321 if ((y+height) > yMax) height = yMax-y;
323 case KeyEvent.VK_LEFT:
325 if (width<1) width = 1;
327 case KeyEvent.VK_RIGHT:
329 if ((x+width) > xMax) width = xMax-x;
333 imp.
draw(clipX, clipY, clipWidth, clipHeight);
339 protected void updateClipRect() {
341 clipX = (x<=oldX)?x:oldX;
342 clipY = (y<=oldY)?y:oldY;
343 clipWidth = ((x+width>=oldX+oldWidth)?x+width:oldX+oldWidth) - clipX + 1;
344 clipHeight = ((y+height>=oldY+oldHeight)?y+height:oldY+oldHeight) - clipY + 1;
347 double mag = ic.getMagnification();
352 clipWidth+=m*2; clipHeight+=m*2;
355 protected void handleMouseDrag(
int sx,
int sy,
int flags) {
356 if (ic==null)
return;
357 constrain = (flags&Event.SHIFT_MASK)!=0;
358 center = (flags&Event.CTRL_MASK)!=0 || (IJ.isMacintosh()&&(flags&Event.META_MASK)!=0);
376 int getHandleSize() {
377 double mag = ic!=null?ic.getMagnification():1.0;
378 double size = HANDLE_SIZE/mag;
379 return (
int)(size*mag);
382 public void draw(Graphics g) {
383 if (ic==null)
return;
384 g.setColor(ROIColor);
385 mag = ic.getMagnification();
386 int sw = (int)(width*mag);
387 int sh = (int)(height*mag);
394 g.drawRect(sx1, sy1, sw, sh);
395 if (state!=CONSTRUCTING && clipboard==null) {
396 int size2 = HANDLE_SIZE/2;
397 drawHandle(g, sx1-size2, sy1-size2);
398 drawHandle(g, sx2-size2, sy1-size2);
399 drawHandle(g, sx3-size2, sy1-size2);
400 drawHandle(g, sx3-size2, sy2-size2);
401 drawHandle(g, sx3-size2, sy3-size2);
402 drawHandle(g, sx2-size2, sy3-size2);
403 drawHandle(g, sx1-size2, sy3-size2);
404 drawHandle(g, sx1-size2, sy2-size2);
407 if (state!=NORMAL) showStatus();
408 if (updateFullWindow)
409 {updateFullWindow =
false; imp.
draw();}
412 void drawPreviousRoi(Graphics g) {
413 if (previousRoi!=null && previousRoi!=
this && ic.roiModState!=ImageCanvas.NO_MODS) {
414 previousRoi.setImage(imp);
419 void drawHandle(Graphics g,
int x,
int y) {
420 double size = (width*height)*mag;
422 size = Math.sqrt(width*width+height*height);
426 g.setColor(Color.black);
428 g.setColor(Color.white);
429 g.fillRect(x+1,y+1,3,3);
430 }
else if (size>1500.0) {
431 g.setColor(Color.black);
432 g.fillRect(x+1,y+1,4,4);
433 g.setColor(Color.white);
434 g.fillRect(x+2,y+2,2,2);
436 g.setColor(Color.black);
437 g.fillRect(x+1,y+1,3,3);
438 g.setColor(Color.white);
439 g.fillRect(x+2,y+2,1,1);
443 public void drawPixels() {
446 if (Line.getWidth()>1)
447 updateFullWindow =
true;
450 public boolean contains(
int x,
int y) {
451 Rectangle r =
new Rectangle(this.x, this.y, width, height);
452 return r.contains(x, y);
458 if (clipboard!=null)
return -1;
459 double mag = ic.getMagnification();
460 int size = HANDLE_SIZE+3;
461 int halfSize = size/2;
462 int sx1 = ic.
screenX(x) - halfSize;
463 int sy1 = ic.
screenY(y) - halfSize;
464 int sx3 = ic.
screenX(x+width) - halfSize;
465 int sy3 = ic.
screenY(y+height) - halfSize;
466 int sx2 = sx1 + (sx3 - sx1)/2;
467 int sy2 = sy1 + (sy3 - sy1)/2;
468 if (sx>=sx1&&sx<=sx1+size&&sy>=sy1&&sy<=sy1+size)
return 0;
469 if (sx>=sx2&&sx<=sx2+size&&sy>=sy1&&sy<=sy1+size)
return 1;
470 if (sx>=sx3&&sx<=sx3+size&&sy>=sy1&&sy<=sy1+size)
return 2;
471 if (sx>=sx3&&sx<=sx3+size&&sy>=sy2&&sy<=sy2+size)
return 3;
472 if (sx>=sx3&&sx<=sx3+size&&sy>=sy3&&sy<=sy3+size)
return 4;
473 if (sx>=sx2&&sx<=sx2+size&&sy>=sy3&&sy<=sy3+size)
return 5;
474 if (sx>=sx1&&sx<=sx1+size&&sy>=sy3&&sy<=sy3+size)
return 6;
475 if (sx>=sx1&&sx<=sx1+size&&sy>=sy2&&sy<=sy2+size)
return 7;
479 protected void mouseDownInHandle(
int handle,
int sx,
int sy) {
480 state = MOVING_HANDLE;
481 activeHandle = handle;
484 protected void handleMouseDown(
int sx,
int sy) {
493 protected void handleMouseUp(
int screenX,
int screenY) {
495 imp.
draw(clipX-5, clipY-5, clipWidth+10, clipHeight+10);
496 if (Recorder.record) {
499 if (imp==null)
return;
500 Line line = (Line)imp.getRoi();
501 Recorder.record(
"makeLine", line.x1, line.y1, line.x2, line.y2);
502 }
else if (type==OVAL)
503 Recorder.record(
"makeOval", x, y, width, height);
505 Recorder.record(
"makeRectangle", x, y, width, height);
510 public void modifyRoi() {
512 if (ic==null || ic.roiModState==ImageCanvas.NO_MODS || previousRoi==null)
516 if (previousRoi instanceof ShapeRoi)
517 s1 = (ShapeRoi)previousRoi;
519 s1 =
new ShapeRoi(previousRoi);
520 if (
this instanceof ShapeRoi)
523 s2 =
new ShapeRoi(
this);
524 if (ic.roiModState==ImageCanvas.ADD_TO_ROI)
528 ic.roiModState = ImageCanvas.NO_MODS;
529 Roi[] rois = s1.getRois();
530 int type2 = rois[0].getType();
532 if (rois.length==1 && (type2==POLYGON||type2==FREEROI))
538 protected void showStatus() {
540 if (state!=CONSTRUCTING && type==RECTANGLE && width<=25 && height<=25) {
542 double v = ip.getPixelValue(x,y);
543 int digits = (imp.
getType()==ImagePlus.GRAY8||imp.
getType()==ImagePlus.GRAY16)?0:2;
544 value =
", value="+IJ.d2s(v,digits);
549 if (cal.scaled() && !IJ.altKeyDown())
550 size =
", w="+IJ.d2s(width*cal.pixelWidth)+
", h="+IJ.d2s(height*cal.pixelHeight);
552 size =
", w="+width+
", h="+height;
556 public ImageProcessor getMask() {
560 void startPaste(ImagePlus clipboard) {
561 IJ.showStatus(
"Pasting...");
562 this.clipboard = clipboard;
565 if (IJ.debugMode) IJ.log(
"startPaste: "+clipX+
" "+clipY+
" "+clipWidth+
" "+clipHeight);
566 imp.
draw(clipX, clipY, clipWidth, clipHeight);
570 if (clipboard!=null) {
573 ip.copyBits(clipboard.getProcessor(), x, y, pasteMode);
580 public void endPaste() {
581 if (clipboard!=null) {
583 if (pasteMode!=Blitter.COPY) ip.reset();
584 ip.copyBits(clipboard.getProcessor(), x, y, pasteMode);
590 Undo.setup(Undo.FILTER, imp);
594 public void abortPaste() {
601 public double getAngle(
int x1,
int y1,
int x2,
int y2) {
602 final int q1=0, q2orq3=2, q4=3;
615 angle = Math.atan(dy/dx);
620 angle = -Math.PI/2.0;
622 angle = (180.0/Math.PI)*angle;
623 if (dx>=0.0 && dy>=0.0)
665 int previousMode = pasteMode;
666 pasteMode = transferMode;
670 if (previousMode!=Blitter.COPY) {
673 if (pasteMode!=Blitter.COPY) {
699 return (type>=RECTANGLE && type<=TRACED_ROI) || type==COMPOSITE;
704 return type>=LINE && type<=FREELINE;
711 case POLYGON: s=
"Polygon";
break;
712 case FREEROI: s=
"Freehand";
break;
713 case TRACED_ROI: s=
"Traced";
break;
714 case POLYLINE: s=
"Polyline";
break;
715 case FREELINE: s=
"Freeline";
break;
716 case ANGLE: s=
"Angle";
break;
717 case LINE: s=
"Straight Line";
break;
718 case OVAL: s=
"Oval";
break;
719 case COMPOSITE: s =
"Composite";
break;
720 default: s=
"Rectangle";
break;
725 public String toString() {
726 return (
"Roi: type="+type+
", x="+x+
", y="+y+
", width="+width+
", height="+height);