All Downloads are FREE. Search and download functionalities are using the official Maven repository.

ij.gui.PolygonRoi Maven / Gradle / Ivy

Go to download

ImageJ is an open source Java image processing program inspired by NIH Image for the Macintosh.

There is a newer version: 1.54p
Show newest version
package ij.gui;
import ij.*;
import ij.process.*;
import ij.measure.*;
import ij.plugin.frame.*;
import java.awt.*;
import java.awt.image.*;
import java.awt.geom.*;
import java.awt.event.*;

/** This class represents a polygon region of interest or polyline of interest. */
public class PolygonRoi extends Roi {

	protected int maxPoints = 1000; // will be increased if necessary
	protected int[] xp, yp;		// image coordinates relative to origin of roi bounding box
	protected float[] xpf, ypf;		// or alternative sub-pixel coordinates
	protected int[] xp2, yp2;	// absolute screen coordinates
	protected int nPoints;
	protected float[] xSpline,ySpline; // relative image coordinates
	protected int splinePoints = 200;
	Rectangle clip;
	
	private double angle1, degrees=Double.NaN;
	private int xClipMin, yClipMin, xClipMax, yClipMax;
	private boolean userCreated;
	private boolean subPixel;
	private boolean drawOffset;

	long mouseUpTime = 0;

	/** Creates a new polygon or polyline ROI from x and y coordinate arrays.
		Type must be Roi.POLYGON, Roi.FREEROI, Roi.TRACED_ROI, Roi.POLYLINE, Roi.FREELINE or Roi.ANGLE.*/
	public PolygonRoi(int[] xPoints, int[] yPoints, int nPoints, int type) {
		super(0, 0, null);
		init1(nPoints, type);
		xp = xPoints;
		yp = yPoints;
		if (type!=TRACED_ROI) {
			xp = new int[nPoints];
			yp = new int[nPoints];
			for (int i=0; i1 && isLine())
			updateWideLine(lineWidth);
		finishPolygon();
	}
	
	/** Creates a new polygon or polyline ROI from a Polygon. Type must be Roi.POLYGON, 
		Roi.FREEROI, Roi.TRACED_ROI, Roi.POLYLINE, Roi.FREELINE or Roi.ANGLE.*/
	public PolygonRoi(Polygon p, int type) {
		this(p.xpoints, p.ypoints, p.npoints, type);
	}

	/** Creates a new polygon or polyline ROI from a FloatPolygon. Type must be Roi.POLYGON, 
		Roi.FREEROI, Roi.TRACED_ROI, Roi.POLYLINE, Roi.FREELINE or Roi.ANGLE.*/
	public PolygonRoi(FloatPolygon p, int type) {
		this(p.xpoints, p.ypoints, p.npoints, type);
	}

	/** @deprecated */
	public PolygonRoi(int[] xPoints, int[] yPoints, int nPoints, ImagePlus imp, int type) {
		this(xPoints, yPoints, nPoints, type);
		setImage(imp);
	}

	/** Starts the process of creating a new user-generated polygon or polyline ROI. */
	public PolygonRoi(int sx, int sy, ImagePlus imp) {
		super(sx, sy, imp);
		int tool = Toolbar.getToolId();
		switch (tool) {
			case Toolbar.POLYGON:
				type = POLYGON;
				break;
			case Toolbar.FREEROI:
				type = FREEROI;
				break;
			case Toolbar.FREELINE:
				type = FREELINE;
				if (Prefs.subPixelResolution)
					subPixel = true;
				break;
			case Toolbar.ANGLE:
				type = ANGLE;
				break;
			default:
				type = POLYLINE;
				if (Prefs.subPixelResolution)
					subPixel = true;
				break;
		}
		if (this instanceof EllipseRoi)
			subPixel = true;
		x = ic.offScreenX(sx);
		y = ic.offScreenY(sy);
		startXD = subPixelResolution()?ic.offScreenXD(sx):x;
		startYD = subPixelResolution()?ic.offScreenYD(sy):y;
		if (subPixelResolution()) {
			setLocation(ic.offScreenXD(sx), ic.offScreenYD(sy));
			xpf = new float[maxPoints];
			ypf = new float[maxPoints];
			double xbase = getXBase();
			double ybase = getYBase();
			xpf[0] = (float)(startXD-xbase);
			ypf[0] = (float)(startYD-ybase);
			xpf[1] = xpf[0];
			ypf[1] = ypf[0];
		} else {
			xp = new int[maxPoints];
			yp = new int[maxPoints];
		}
		xp2 = new int[maxPoints];
		yp2 = new int[maxPoints];
		nPoints = 2;
		width=1;
		height=1;
		clipX = x;
		clipY = y;
		clipWidth = 1;
		clipHeight = 1;
		state = CONSTRUCTING;
		userCreated = true;
		if (lineWidth>1 && isLine())
			updateWideLine(lineWidth);
		drawOffset = subPixelResolution();
	}

	private void drawStartBox(Graphics g) {
		if (type!=ANGLE) {
			double offset = getOffset(0.5);
			g.drawRect(ic.screenXD(startXD+offset)-4, ic.screenYD(startYD+offset)-4, 8, 8);
		}
	}
	
	public void draw(Graphics g) {
		updatePolygon();
		Color color =  strokeColor!=null?strokeColor:ROIColor;
		boolean hasHandles = xSpline!=null||type==POLYGON||type==POLYLINE||type==ANGLE;
		boolean isActiveOverlayRoi = !overlay && isActiveOverlayRoi();
		if (isActiveOverlayRoi && !hasHandles) {
			if (color==Color.cyan)
				color = Color.magenta;
			else
				color = Color.cyan;
		}
		boolean fill = false;
		mag = getMagnification();
		if (fillColor!=null && !isLine() && state!=CONSTRUCTING) {
			color = fillColor;
			fill = true;
		}
		g.setColor(color);
		Graphics2D g2d = (Graphics2D)g;
		if (stroke!=null && !isActiveOverlayRoi)
			g2d.setStroke(getScaledStroke());
		if (xSpline!=null) {
			if (type==POLYLINE || type==FREELINE) {
				drawSpline(g, xSpline, ySpline, splinePoints, false, fill, isActiveOverlayRoi);
				if (wideLine && !overlay) {
					g2d.setStroke(onePixelWide);
					g.setColor(getColor());
					drawSpline(g, xSpline, ySpline, splinePoints, false, fill, isActiveOverlayRoi);
				}
			} else
				drawSpline(g, xSpline, ySpline, splinePoints, true, fill, isActiveOverlayRoi);
		} else {
			if (type==POLYLINE || type==FREELINE || type==ANGLE || state==CONSTRUCTING) {
				g.drawPolyline(xp2, yp2, nPoints);
				if (wideLine && !overlay) {
					g2d.setStroke(onePixelWide);
					g.setColor(getColor());
					g.drawPolyline(xp2, yp2, nPoints);
				}
			} else {
				if (fill) {
					if (isActiveOverlayRoi) {
						g.setColor(Color.cyan);
						g.drawPolygon(xp2, yp2, nPoints);
					} else
						g.fillPolygon(xp2, yp2, nPoints);
				} else
					g.drawPolygon(xp2, yp2, nPoints);
			 }
			if (state==CONSTRUCTING && type!=FREEROI && type!=FREELINE)
				drawStartBox(g);
		}
		if (hasHandles	&& clipboard==null && !overlay) {
			int size2 = HANDLE_SIZE/2;
			if (activeHandle>0)
				drawHandle(g, xp2[activeHandle-1]-size2, yp2[activeHandle-1]-size2);
			if (activeHandle1f)
			ip.setLineWidth((int)Math.round(getStrokeWidth()));
		double xbase = getXBase();
		double ybase = getYBase();
		if (xSpline!=null) {
			ip.moveTo((int)Math.round(xbase+xSpline[0]), (int)Math.round(ybase+ySpline[0]));
			for (int i=1; i1) {
			double x1, y1, x2, y2;
			if (xpf!=null) {
				x1 = xpf[nPoints-2];
				y1 = ypf[nPoints-2];
				x2 = xpf[nPoints-1];
				y2 = ypf[nPoints-1];
			} else {
				x1 = xp[nPoints-2];
				y1 = yp[nPoints-2];
				x2 = xp[nPoints-1];
				y2 = yp[nPoints-1];
			}
			degrees = getAngle((int)Math.round(x1), (int)Math.round(y1), (int)Math.round(x2), (int)Math.round(y2));
			if (tool!=Toolbar.ANGLE) {
				Calibration cal = imp.getCalibration();
				double pw=cal.pixelWidth, ph=cal.pixelHeight;
				if (IJ.altKeyDown()) {pw=1.0; ph=1.0;}
				len = Math.sqrt((x2-x1)*pw*(x2-x1)*pw + (y2-y1)*ph*(y2-y1)*ph);
			}
		}
		if (tool==Toolbar.ANGLE) {
			if (nPoints==2)
				angle1 = degrees;
			else if (nPoints==3) {
				double angle2 = getAngle(xp[1], yp[1], xp[2], yp[2]);
				degrees = Math.abs(180-Math.abs(angle1-angle2));
				if (degrees>180.0)
					degrees = 360.0-degrees;
			}
		}
		String length = len!=-1?", length=" + IJ.d2s(len):"";
		double degrees2 = tool==Toolbar.ANGLE&&nPoints==3&&Prefs.reflexAngle?360.0-degrees:degrees;
		String angle = !Double.isNaN(degrees)?", angle=" + IJ.d2s(degrees2):"";
		int ox = ic!=null?ic.offScreenX(sx):sx;
		int oy = ic!=null?ic.offScreenY(sy):sy;
		IJ.showStatus(imp.getLocationAsString(ox,oy) + length + angle);
	}

	void drawRubberBand(int sx, int sy) {
		double oxd = ic!=null?ic.offScreenXD(sx):sx;
		double oyd = ic!=null?ic.offScreenYD(sy):sy;
		int ox = (int)oxd;
		int oy = (int)oyd;
		int x1, y1, x2, y2;
		if (xpf!=null) {
			x1 = (int)xpf[nPoints-2]+x;
			y1 = (int)ypf[nPoints-2]+y;
			x2 = (int)xpf[nPoints-1]+x;
			y2 = (int)ypf[nPoints-1]+y;
		} else {
			x1 = xp[nPoints-2]+x;
			y1 = yp[nPoints-2]+y;
			x2 = xp[nPoints-1]+x;
			y2 = yp[nPoints-1]+y;
		}
		int xmin=Integer.MAX_VALUE, ymin=Integer.MAX_VALUE, xmax=0, ymax=0;
		if (x1xmax) xmax=x1;
		if (x2>xmax) xmax=x2;
		if (ox>xmax) xmax=ox;
		if (y1ymax) ymax=y1;
		if (y2>ymax) ymax=y2;
		if (oy>ymax) ymax=oy;
		//clip = new Rectangle(xmin, ymin, xmax-xmin, ymax-ymin);
		int margin = 4;
		if (ic!=null) {
			double mag = ic.getMagnification();
			if (mag<1.0) margin = (int)(margin/mag);
		}
		margin = (int)(margin+getStrokeWidth());
		if (xpf!=null) {
			xpf[nPoints-1] = (float)(oxd-getXBase());
			ypf[nPoints-1] = (float)(oyd-getYBase());
		} else {
			xp[nPoints-1] = ox-x;
			yp[nPoints-1] = oy-y;
		}
		if (type==POLYLINE && subPixelResolution()) {
			fitSpline();
			imp.draw();
		} else
			imp.draw(xmin-margin, ymin-margin, (xmax-xmin)+margin*2, (ymax-ymin)+margin*2);
	}
	
	void finishPolygon() {
		if (xpf!=null) {
			float xbase0 = (float)getXBase();
			float ybase0 = (float)getYBase();
			FloatPolygon poly = new FloatPolygon(xpf, ypf, nPoints);
			Rectangle r = poly.getBounds();
			x = r.x;
			y = r.y;
			width = r.width;
			height = r.height;
			bounds = poly.getFloatBounds();
			float xbase = (float)bounds.getX();
			float ybase = (float)bounds.getY();
			for (int i=0; i1 && isLine()) || ignoreClipRect)
			imp.draw();
		else
			imp.draw(clipX, clipY, clipWidth, clipHeight);
		oldX = x;
		oldY = y;
		oldWidth = width;
		oldHeight=height;
	}
	*/

	protected void moveHandle(int sx, int sy) {
		if (clipboard!=null) return;
		int ox = ic.offScreenX(sx);
		int oy = ic.offScreenY(sy);
		if (xpf!=null) {
			double offset = getOffset(-0.5);
			double xbase = getXBase();
			double ybase = getYBase();
			xpf[activeHandle] = (float)(ic.offScreenXD(sx)-xbase+offset);
			ypf[activeHandle] = (float)(ic.offScreenYD(sy)-ybase+offset);
		} else {
			xp[activeHandle] = ox-x;
			yp[activeHandle] = oy-y;
		}
		if (xSpline!=null) {
			fitSpline(splinePoints);
			imp.draw();
		} else {
			if (!subPixelResolution())
				resetBoundingRect();
			if (type==POINT && width==0 && height==0)
				{width=1; height=1;}
			updateClipRectAndDraw();
		}
		String angle = type==ANGLE?getAngleAsString():"";
		IJ.showStatus(imp.getLocationAsString(ox,oy) + angle);
	}

   /** After handle is moved, find clip rect and repaint. */
   void updateClipRectAndDraw() {
		if (xpf!=null) {
			xp = toInt(xpf, xp, nPoints);
			yp = toInt(ypf, yp, nPoints);
		}
		int xmin=Integer.MAX_VALUE, ymin=Integer.MAX_VALUE, xmax=0, ymax=0;
		int x2, y2;
		if (activeHandle>0)
		   {x2=x+xp[activeHandle-1]; y2=y+yp[activeHandle-1];}
		else
		   {x2=x+xp[nPoints-1]; y2=y+yp[nPoints-1];}
		if (x2xmax) xmax = x2;
		if (y2>ymax) ymax = y2;
		x2=x+xp[activeHandle]; y2=y+yp[activeHandle];
		if (x2xmax) xmax = x2;
		if (y2>ymax) ymax = y2;
		if (activeHandlexmax) xmax = x2;
		if (y2>ymax) ymax = y2;
		int xmin2=xmin, ymin2=ymin, xmax2=xmax, ymax2=ymax;
		if (xClipMinxmax2) xmax2 = xClipMax;
		if (yClipMax>ymax2) ymax2 = yClipMax;
		xClipMin=xmin; yClipMin=ymin; xClipMax=xmax; yClipMax=ymax;
		double mag = ic.getMagnification();
		int handleSize = type==POINT?HANDLE_SIZE+12:HANDLE_SIZE;
		double strokeWidth = getStrokeWidth();
		if (strokeWidth<1.0) strokeWidth=1.0;
		if (handleSizexmax) xmax=xx;
			yy = yp[i];
			if (yyymax) ymax=yy;
		}
		if (xmin!=0) {
			for (int i=0; i180.0)
			degrees = 360.0-degrees;
		double degrees2 = Prefs.reflexAngle&&type==ANGLE?360.0-degrees:degrees;
		return ", angle=" + IJ.d2s(degrees2);
	}
   
   protected void mouseDownInHandle(int handle, int sx, int sy) {
		if (state==CONSTRUCTING)
			return;
		int ox=ic.offScreenX(sx), oy=ic.offScreenY(sy);
		double oxd=ic.offScreenXD(sx), oyd=ic.offScreenYD(sy);
		if (IJ.altKeyDown() && !(nPoints<=3 && type!=POINT)) {
			deleteHandle(oxd, oyd); 
			return;
		} else if (IJ.shiftKeyDown() && type!=POINT) {
			addHandle(oxd, oyd); 
			return;
		}
		state = MOVING_HANDLE;
		activeHandle = handle;
		int m = (int)(10.0/ic.getMagnification());
		xClipMin=ox-m; yClipMin=oy-m; xClipMax=ox+m; yClipMax=oy+m;
	}

	public void deleteHandle(double ox, double oy) {
		if (imp==null) return;
		if (nPoints<=1)
			{imp.deleteRoi(); return;}
		boolean splineFit = xSpline != null;
		xSpline = null;
		FloatPolygon points = getFloatPolygon();
		modState = NO_MODS;
		if (previousRoi!=null) previousRoi.modState = NO_MODS;
		int pointToDelete = getClosestPoint(ox, oy, points);
		FloatPolygon points2 = new FloatPolygon();
		for (int i=0; ixmax) xmax=xs;
			xSpline[i] = xs;
			ys = (float)sfy.evalSpline(xvalue);
			if (ysymax) ymax=ys;
			ySpline[i] = ys;
		}
		cachedMask = null;
		// update protected xp and yp arrays for backward compatibility
		xp = toInt(xpf, xp, nPoints);
		yp = toInt(ypf, yp, nPoints);
		if (state==NORMAL)
			resetBoundingRect();
	}

	public void fitSpline() {
		double length = getUncalibratedLength();
		int evaluationPoints = (int)(length/2.0);
		if (ic!=null) {
			double mag = ic.getMagnification();
			if (mag<1.0)
				evaluationPoints *= mag;;
		}
		if (evaluationPoints<100)
			evaluationPoints = 100;
		fitSpline(evaluationPoints);
	}
	
	public void removeSplineFit() {
		xSpline = null;
		ySpline = null;
	}
	
	/** Returns 'true' if this selection has been fitted with a spline. */
	public boolean isSplineFit() {
		return xSpline!=null;
	}

	/* Creates a spline fitted polygon with one pixel segment lengths 
		that can be retrieved using the getFloatPolygon() method. */
	public void fitSplineForStraightening() {
		fitSpline((int)getUncalibratedLength()*2);
		if (xSpline==null || splinePoints==0) return;
		float[] xpoints = new float[splinePoints*2];
		float[] ypoints = new float[splinePoints*2];
		xpoints[0] = xSpline[0];
		ypoints[0] = ySpline[0];
		int n=1, n2;
		double inc = 0.01;
		double distance=0.0, distance2=0.0, dx=0.0, dy=0.0, xinc, yinc;
		double x, y, lastx, lasty, x1, y1, x2=xSpline[0], y2=ySpline[0];
		for (int i=1; i=1.0-inc/2.0 && n0);
		}
		xSpline = xpoints;
		ySpline = ypoints;
		splinePoints = n;
		//IJ.log("xSpline="+xSpline+" splinePoints="+splinePoints);
	}

	public double getUncalibratedLength() {
		ImagePlus saveImp = imp;
		imp = null;
		double length = getLength();
		imp = saveImp;
		return length;
	}
	
	/** With segmented selections, ignore first mouse up and finalize
		when user double-clicks, control-clicks or clicks in start box. */
	protected void handleMouseUp(int sx, int sy) {
		if (state==MOVING) {
			state = NORMAL;
			return;
		}				
		if (state==MOVING_HANDLE) {
			cachedMask = null; //mask is no longer valid
			state = NORMAL;
			updateClipRect();
			oldX=x; oldY=y;
			oldWidth=width; oldHeight=height;
			if (subPixelResolution())
				resetBoundingRect();
			return;
		}		
		if (state!=CONSTRUCTING)
			return;
		if (IJ.spaceBarDown()) // is user scrolling image?
			return;
		boolean samePoint = false;
		if (xpf!=null) 
			samePoint = (xpf[nPoints-2]==xpf[nPoints-1] && ypf[nPoints-2]==ypf[nPoints-1]);
		else
			samePoint = (xp[nPoints-2]==xp[nPoints-1] && yp[nPoints-2]==yp[nPoints-1]);
		Rectangle biggerStartBox = new Rectangle(ic.screenXD(startXD)-5, ic.screenYD(startYD)-5, 10, 10);
		if (nPoints>2 && (biggerStartBox.contains(sx, sy)
		|| (ic.offScreenXD(sx)==startXD && ic.offScreenYD(sy)==startYD)
		|| (samePoint && (System.currentTimeMillis()-mouseUpTime)<=500))) {
			nPoints--;
			addOffset();
			finishPolygon();
			return;
		} else if (!samePoint) {
			mouseUpTime = System.currentTimeMillis();
			if (type==ANGLE && nPoints==3) {
				addOffset();
				finishPolygon();
				return;
			}
			//add point to polygon
			if (xpf!=null) {
				xpf[nPoints] = xpf[nPoints-1];
				ypf[nPoints] = ypf[nPoints-1];
				nPoints++;
				if (nPoints==xpf.length)
					enlargeArrays();
			} else {
				xp[nPoints] = xp[nPoints-1];
				yp[nPoints] = yp[nPoints-1];
				nPoints++;
				if (nPoints==xp.length)
					enlargeArrays();
			}
			//if (lineWidth>1) fitSpline();
		}
	}

	protected void addOffset() {
		if (xpf!=null) {
			double xbase = getXBase();
			double ybase = getYBase();
			for (int i=0; i=sx2 && sx<=sx2+size && sy>=sy2 && sy<=sy2+size) {
				handle = i;
				break;
			}
		}
		return handle;
	}

	/** Override Roi.nudge() to support splines. */
	//public void nudge(int key) {
	//	super.nudge(key);
	//	if (xSpline!=null) {
	//		fitSpline();
	//		updateFullWindow = true;
	//		imp.draw();
	//	}
	//}

	public ImageProcessor getMask() {
		if (cachedMask!=null && cachedMask.getPixels()!=null
		&& cachedMask.getWidth()==width && cachedMask.getHeight()==height)
			return cachedMask;
		PolygonFiller pf = new PolygonFiller();
		if (xSpline!=null)
			pf.setPolygon(toIntR(xSpline), toIntR(ySpline), splinePoints);
		else if (xpf!=null)
			pf.setPolygon(toIntR(xpf), toIntR(ypf), nPoints);
		else
			pf.setPolygon(xp, yp, nPoints);
		cachedMask = pf.getMask(width, height);
		return cachedMask;
	}

	/** Returns the length of this line selection after
		smoothing using a 3-point running average.*/
	double getSmoothedLineLength() {
		if (subPixelResolution() && xpf!=null)
			return getFloatSmoothedLineLength();
		double length = 0.0;
		double w2 = 1.0;
		double h2 = 1.0;
		double dx, dy;
		if (imp!=null) {
			Calibration cal = imp.getCalibration();
			w2 = cal.pixelWidth*cal.pixelWidth;
			h2 = cal.pixelHeight*cal.pixelHeight;
		}
		dx = (xp[0]+xp[1]+xp[2])/3.0-xp[0];
		dy = (yp[0]+yp[1]+yp[2])/3.0-yp[0];
		length += Math.sqrt(dx*dx*w2+dy*dy*h2);
		for (int i=1; i1 || !corner) {
			  corner = true;
			  nCorners++;
			} else
			  corner = false;
			dx1 = dx2;
			dy1 = dy2;
			side1 = side2;
		}
		double w=1.0,h=1.0;
		if (imp!=null) {
			Calibration cal = imp.getCalibration();
			w = cal.pixelWidth;
			h = cal.pixelHeight;
		}
		return sumdx*w+sumdy*h-(nCorners*((w+h)-Math.sqrt(w*w+h*h)));
	}

	/** Returns the perimeter (for ROIs) or length (for lines).*/
	public double getLength() {
		if (type==TRACED_ROI)
			return getTracedPerimeter();
			
		if (nPoints>2) {
			if (type==FREEROI)
				return getSmoothedPerimeter();
			else if (type==FREELINE && !(width==0 || height==0))
				return getSmoothedLineLength();
		}
		
		double length = 0.0;
		int dx, dy;
		double w2=1.0, h2=1.0;
		if (imp!=null) {
			Calibration cal = imp.getCalibration();
			w2 = cal.pixelWidth*cal.pixelWidth;
			h2 = cal.pixelHeight*cal.pixelHeight;
		}
		if (xSpline!=null) {
			double fdx, fdy;
			for (int i=0; i<(splinePoints-1); i++) {
				fdx = xSpline[i+1]-xSpline[i];
				fdy = ySpline[i+1]-ySpline[i];
				length += Math.sqrt(fdx*fdx*w2+fdy*fdy*h2);
			}
			if (type==POLYGON) {
				fdx = xSpline[0]-xSpline[splinePoints-1];
				fdy = ySpline[0]-ySpline[splinePoints-1];
				length += Math.sqrt(fdx*fdx*w2+fdy*fdy*h2);
			}
		} else if (xpf!=null) {
			double fdx, fdy;
			for (int i=0; i<(nPoints-1); i++) {
				fdx = xpf[i+1]-xpf[i];
				fdy = ypf[i+1]-ypf[i];
				length += Math.sqrt(fdx*fdx*w2+fdy*fdy*h2);
			}
			if (type==POLYGON) {
				fdx = xpf[0]-xpf[nPoints-1];
				fdy = ypf[0]-ypf[nPoints-1];
				length += Math.sqrt(fdx*fdx*w2+fdy*fdy*h2);
			}
		} else {
			for (int i=0; i<(nPoints-1); i++) {
				dx = xp[i+1]-xp[i];
				dy = yp[i+1]-yp[i];
				length += Math.sqrt(dx*dx*w2+dy*dy*h2);
			}
			if (type==POLYGON) {
				dx = xp[0]-xp[nPoints-1];
				dy = yp[0]-yp[nPoints-1];
				length += Math.sqrt(dx*dx*w2+dy*dy*h2);
			}
		}
		return length;
	}
	
	/** Returns the angle in degrees between the first two segments of this polyline.*/
	public double getAngle() {
		return degrees;
	}
	
	/** Returns the number of XY coordinates. */
	public int getNCoordinates() {
		if (xSpline!=null)
			return splinePoints;
		else
			return nPoints;
	}
	
	/** Obsolete; replaced by either getPolygon() or getFloatPolygon(). */
	public int[] getXCoordinates() {
		if (xSpline!=null)
			return toIntR(xSpline);
		else if (xpf!=null)
			return toIntR(xpf);
		else
			return xp;
	}

	/** Obsolete; replaced by either getPolygon() or getFloatPolygon(). */
	public int[] getYCoordinates() {
		if (xSpline!=null)
			return toIntR(ySpline);
		else if (ypf!=null)
			return toIntR(ypf);
		else
			return yp;
	}
	
	public Polygon getNonSplineCoordinates() {
		if (xpf!=null)
			return new Polygon(toIntR(xpf), toIntR(ypf), nPoints);
		else
			return new Polygon(xp, yp, nPoints);
	}
		
	public FloatPolygon getNonSplineFloatPolygon() {
		if (xpf!=null) {
			FloatPolygon p = (new FloatPolygon(xpf, ypf, nPoints)).duplicate();
			float xbase = (float)getXBase();
			float ybase = (float)getYBase();
			for (int i=0; i0)
					{x2=x3; y2=y3; p2=p3;}
				p3 += 1;
				if (p3==n) p3 = 0;
			} while (p3!=p1);
			if (n210) return null;
			}
			p1 = p2;
		} while (p1!=pstart);
		return new Polygon(xx, yy, n2);
	}
		
	public FloatPolygon getInterpolatedPolygon(double interval, boolean smooth) {
		FloatPolygon p = getFloatPolygon();
		if (smooth && (type==TRACED_ROI || type==FREEROI || type==FREELINE)) {
			for (int i=1; i "+newSize);
		maxPoints = newSize;
	}
	
	private double getOffset(double value) {
		return getDrawOffset()&&getMagnification()>1.0?value:0.0;
	}
	
	public boolean getDrawOffset() {
		return drawOffset;
	}
	
	public void setDrawOffset(boolean drawOffset) {
		this.drawOffset = drawOffset && subPixelResolution();
	}
		
	public void setLocation(double x, double y) {
		super.setLocation(x, y);
		if ((int)x!=x || (int)y!=y) {
			subPixel = true;
			if (xpf==null && xp!=null) {
				xpf = toFloat(xp);
				ypf = toFloat(yp);
			}
		}
	}

	public void enableSubPixelResolution() {
		super.enableSubPixelResolution();
		if (xpf==null) {
			xpf = toFloat(xp);
			ypf = toFloat(yp);
		}
	}

	public String getDebugInfo() {
		String s = "ROI Debug Properties\n";
		s += "	bounds: "+bounds+"\n";
		s += "	x,y,w,h: "+x+","+y+","+width+","+height+"\n";
		if (xpf!=null && xpf.length>0)
			s += "	xpf[0],ypf[0]: "+xpf[0]+","+ypf[0]+"\n";
		return s;
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy