|
Line |
|
package ij.gui; import java.awt.*; import java.awt.image.*; import ij.*; import ij.process.*; import ij.measure.*; import java.awt.event.KeyEvent; /** This class represents a straight line selection. */ public class Line extends Roi { public int x1, y1, x2, y2; // the line private int x1R, y1R, x2R, y2R; // the line, relative to base of bounding rect private static int lineWidth = 1; private int xHandleOffset, yHandleOffset; /** Creates a new straight line selection using the specified starting and ending offscreen coordinates. */ public Line(int ox1, int oy1, int ox2, int oy2) { this(ox1, oy1, null); grow(ox2, oy2); x1=x+x1R; y1=y+y1R; x2=x+x2R; y2=y+y2R; state = NORMAL; } /** Starts the process of creating a new user-generated straight line selection. 'ox' and 'oy' are offscreen coordinates that specify the start of the line. The user will determine the end of the line interactively using rubber banding. */ public Line(int ox, int oy, ImagePlus imp) { super(ox, oy, imp); x1R = 0; y1R = 0; type = LINE; } /** Obsolete */ public Line(int ox1, int oy1, int ox2, int oy2, ImagePlus imp) { this(ox1, oy1, ox2, oy2); setImage(imp); } protected void grow(int xend, int yend) { if (xend<0) xend=0; if (yend<0) yend=0; if (xend>xMax) xend=xMax; if (yend>yMax) yend=yMax; int xstart=x+x1R, ystart=y+y1R; if (constrain) { int dx = Math.abs(xend-xstart); int dy = Math.abs(yend-ystart); if (dx>=dy) yend = ystart; else xend = xstart; } x=Math.min(x+x1R,xend); y=Math.min(y+y1R,yend); x1R=xstart-x; y1R=ystart-y; x2R=xend-x; y2R=yend-y; width=Math.abs(x2R-x1R); height=Math.abs(y2R-y1R); if (width<1) width=1; if (height<1) height=1; updateClipRect(); if (imp!=null) { if (lineWidth==1) imp.draw(clipX, clipY, clipWidth, clipHeight); else imp.draw(); } oldX=x; oldY=y; oldWidth=width; oldHeight=height; } void move(int xNew, int yNew) { x += xNew - startX; y += yNew - startY; clipboard=null; startX = xNew; startY = yNew; if (lineWidth==1) { updateClipRect(); imp.draw(clipX, clipY, clipWidth, clipHeight); } else imp.draw(); oldX = x; oldY = y; oldWidth = width; oldHeight=height; } protected void moveHandle(int ox, int oy) { x1=x+x1R; y1=y+y1R; x2=x+x2R; y2=y+y2R; switch (activeHandle) { case 0: x1=ox; y1=oy; break; case 1: x2=ox; y2=oy; break; case 2: int dx = ox-(x1+(x2-x1)/2); int dy = oy-(y1+(y2-y1)/2); x1+=dx; y1+=dy; x2+=dx; y2+=dy; if (lineWidth>1) { x1+=xHandleOffset; y1+=yHandleOffset; x2+=xHandleOffset; y2+=yHandleOffset; } break; } if (constrain) { int dx = Math.abs(x1-x2); int dy = Math.abs(y1-y2); if (activeHandle==0) { if (dx>=dy) y1= y2; else x1 = x2; } else if (activeHandle==1) { if (dx>=dy) y2= y1; else x2 = x1; } } x=Math.min(x1,x2); y=Math.min(y1,y2); x1R=x1-x; y1R=y1-y; x2R=x2-x; y2R=y2-y; width=Math.abs(x2R-x1R); height=Math.abs(y2R-y1R); updateClipRect(); if (lineWidth==1) imp.draw(clipX, clipY, clipWidth, clipHeight); else imp.draw(); oldX = x; oldY = y; oldWidth = width; oldHeight = height; } protected void mouseDownInHandle(int handle, int sx, int sy) { state = MOVING_HANDLE; activeHandle = handle; if (lineWidth<=3) ic.setCursor(new Cursor(Cursor.CROSSHAIR_CURSOR)); } /** Draws this line in the image. */ public void draw(Graphics g) { g.setColor(ROIColor); x1=x+x1R; y1=y+y1R; x2=x+x2R; y2=y+y2R; int sx1 = ic.screenX(x1); int sy1 = ic.screenY(y1); int sx2 = ic.screenX(x2); int sy2 = ic.screenY(y2); int sx3 = sx1 + (sx2-sx1)/2; int sy3 = sy1 + (sy2-sy1)/2; if (lineWidth==1) g.drawLine(sx1, sy1, sx2, sy2); else { Polygon p = getPolygon(); g.drawLine(ic.screenX(p.xpoints[0]), ic.screenY(p.ypoints[0]), ic.screenX(p.xpoints[1]), ic.screenY(p.ypoints[1])); g.drawLine(ic.screenX(p.xpoints[1]), ic.screenY(p.ypoints[1]), ic.screenX(p.xpoints[2]), ic.screenY(p.ypoints[2])); g.drawLine(ic.screenX(p.xpoints[2]), ic.screenY(p.ypoints[2]), ic.screenX(p.xpoints[3]), ic.screenY(p.ypoints[3])); g.drawLine(ic.screenX(p.xpoints[3]), ic.screenY(p.ypoints[3]), ic.screenX(p.xpoints[0]), ic.screenY(p.ypoints[0])); //updateFullWindow = true; } if (state!=CONSTRUCTING) { int size2 = HANDLE_SIZE/2; if (ic!=null) mag = ic.getMagnification(); drawHandle(g, sx1-size2, sy1-size2); drawHandle(g, sx2-size2, sy2-size2); drawHandle(g, sx3-size2, sy3-size2); } if (state!=NORMAL) IJ.showStatus(imp.getLocationAsString(x2,y2)+", angle=" + IJ.d2s(getAngle(x1,y1,x2,y2)) + ", length=" + IJ.d2s(getLength())); if (updateFullWindow) {updateFullWindow = false; imp.draw();} } /** Returns the length of this line. */ public double getLength() { Calibration cal = imp.getCalibration(); return Math.sqrt((x2-x1)*cal.pixelWidth*(x2-x1)*cal.pixelWidth + (y2-y1)*cal.pixelHeight*(y2-y1)*cal.pixelHeight); } /** Returns the length of this line in pixels. */ public double getRawLength() { return Math.sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1)); } /** Returns the pixel values along this line. */ public double[] getPixels() { double[] profile; ImageProcessor ip = imp.getProcessor(); if (lineWidth==1) profile = ip.getLine(x1, y1, x2, y2); else { ImageProcessor ip2 = rotateWideLine(ip); int width = ip2.getWidth(); int height = ip2.getHeight(); profile = new double[width]; double[] aLine; ip2.setInterpolate(false); for (int y=0; y<height; y++) { aLine = ip2.getLine(0, y, width-1, y); for (int i=0; i<width; i++) profile[i] += aLine[i]; } for (int i=0; i<width; i++) profile[i] /= height; } return profile; } ImageProcessor rotateWideLine(ImageProcessor ip) { int width = (int)Math.round(getRawLength()); int height = lineWidth; ImageProcessor ip2 = new FloatProcessor(width, height); double angle = Math.atan2(y1-y2, x2-x1); double srcWidth = (double)ip.getWidth(); double srcHeight = (double)ip.getHeight(); Polygon p = getPolygon(); int sxbase = p.xpoints[1]; int sybase = p.ypoints[1]; double r, theta, sx, sy; for (int dy=0; dy<height; dy++) { for (int dx=0; dx<width; dx++) { r = Math.sqrt(dx*dx+dy*dy); theta = Math.atan2(dy, dx); theta += angle; sx = sxbase + r*Math.cos(theta); sy = sybase - r*Math.sin(theta); //if (dy==height/2 && dx==width/2) IJ.log(""+angle+" "+dx+" "+dy+" "+sx+" "+sy+" "+r +" "+" "+theta+" "+sy); if (sx>srcWidth || sy>srcHeight || sy<0.0 || sx<0.0 ) ip2.putPixelValue(dx, dy, 0.0); else ip2.putPixelValue(dx, dy, ip.getInterpolatedValue(sx, sy)); } } if (IJ.altKeyDown()) { ip2.resetMinAndMax(); new ImagePlus("Rotated Line", ip2).show(); } return ip2; } public Polygon getPolygon() { Polygon p = new Polygon(); if (lineWidth==1) { p.addPoint(x1, y1); p.addPoint(x2, y2); } else { double angle = Math.atan2(y1-y2, x2-x1); double width2 = lineWidth/2.0; double p1x = x1 + Math.cos(angle+Math.PI/2d)*width2; double p1y = y1 - Math.sin(angle+Math.PI/2d)*width2; double p2x = x1 + Math.cos(angle-Math.PI/2d)*width2; double p2y = y1 - Math.sin(angle-Math.PI/2d)*width2; double p3x = x2 + Math.cos(angle-Math.PI/2d)*width2; double p3y = y2 - Math.sin(angle-Math.PI/2d)*width2; double p4x = x2 + Math.cos(angle+Math.PI/2d)*width2; double p4y = y2 - Math.sin(angle+Math.PI/2d)*width2; p.addPoint((int)Math.round(p1x), (int)Math.round(p1y)); p.addPoint((int)Math.round(p2x), (int)Math.round(p2y)); p.addPoint((int)Math.round(p3x), (int)Math.round(p3y)); p.addPoint((int)Math.round(p4x), (int)Math.round(p4y)); } return p; } public void drawPixels(ImageProcessor ip) { ip.setLineWidth(1); if (lineWidth==1) { ip.moveTo(x1, y1); ip.lineTo(x2, y2); } else { ip.drawPolygon(getPolygon()); updateFullWindow = true; } } public boolean contains(int x, int y) { if (lineWidth>1) return getPolygon().contains(x, y); else return false; } /** Returns a handle number if the specified screen coordinates are inside or near a handle, otherwise returns -1. */ public int isHandle(int sx, int sy) { int size = HANDLE_SIZE+5; if (lineWidth>1) size += (int)Math.log(lineWidth); int halfSize = size/2; int sx1 = ic.screenX(x+x1R) - halfSize; int sy1 = ic.screenY(y+y1R) - halfSize; int sx2 = ic.screenX(x+x2R) - halfSize; int sy2 = ic.screenY(y+y2R) - halfSize; int sx3 = sx1 + (sx2-sx1)/2-1; int sy3 = sy1 + (sy2-sy1)/2-1; if (sx>=sx1&&sx<=sx1+size&&sy>=sy1&&sy<=sy1+size) return 0; if (sx>=sx2&&sx<=sx2+size&&sy>=sy2&&sy<=sy2+size) return 1; if (sx>=sx3&&sx<=sx3+size+2&&sy>=sy3&&sy<=sy3+size+2) return 2; return -1; } public static int getWidth() { return lineWidth; } public static void setWidth(int w) { if (w<1) w = 1; if (w>200) w = 200; lineWidth = w; } /** Nudge end point of line by one pixel. */ public void nudgeCorner(int key) { switch(key) { case KeyEvent.VK_UP: y2R--; break; case KeyEvent.VK_DOWN: y2R++; break; case KeyEvent.VK_LEFT: x2R--; break; case KeyEvent.VK_RIGHT: x2R++; break; } grow(x+x2R,y+y2R); } }
|
Line |
|