001/* 002 * Copyright 2010-2015 Institut Pasteur. 003 * 004 * This file is part of Icy. 005 * 006 * Icy is free software: you can redistribute it and/or modify 007 * it under the terms of the GNU General Public License as published by 008 * the Free Software Foundation, either version 3 of the License, or 009 * (at your option) any later version. 010 * 011 * Icy is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 014 * GNU General Public License for more details. 015 * 016 * You should have received a copy of the GNU General Public License 017 * along with Icy. If not, see <http://www.gnu.org/licenses/>. 018 */ 019package plugins.kernel.roi.roi2d; 020 021import icy.painter.Anchor2D; 022import icy.painter.LineAnchor2D; 023import icy.resource.ResourceUtil; 024import icy.roi.ROI; 025import icy.type.geom.Polyline2D; 026import icy.type.point.Point2DUtil; 027import icy.type.point.Point5D; 028import icy.util.XMLUtil; 029 030import java.awt.Color; 031import java.awt.Graphics2D; 032import java.awt.Polygon; 033import java.awt.geom.Path2D; 034import java.awt.geom.Point2D; 035import java.awt.geom.Rectangle2D; 036import java.awt.image.BufferedImage; 037import java.awt.image.DataBufferByte; 038import java.util.ArrayList; 039import java.util.List; 040 041import org.w3c.dom.Element; 042import org.w3c.dom.Node; 043 044/** 045 * @author Stephane 046 */ 047public class ROI2DPolyLine extends ROI2DShape 048{ 049 protected class ROI2DPolyLineAnchor2D extends LineAnchor2D 050 { 051 public ROI2DPolyLineAnchor2D(Point2D position, Color color, Color selectedColor) 052 { 053 super(position, color, selectedColor); 054 } 055 056 @Override 057 protected Anchor2D getPreviousPoint() 058 { 059 final int ind = controlPoints.indexOf(this); 060 061 if (ind == 0) 062 { 063 if (controlPoints.size() > 1) 064 return controlPoints.get(1); 065 066 return null; 067 } 068 069 if (ind != -1) 070 return controlPoints.get(ind - 1); 071 072 return null; 073 } 074 } 075 076 public static final String ID_POINTS = "points"; 077 public static final String ID_POINT = "point"; 078 079 080 081 /** 082 * @deprecated 083 */ 084 @Deprecated 085 public ROI2DPolyLine(Point2D pt, boolean cm) 086 { 087 this(pt); 088 } 089 090 /** 091 * 092 */ 093 public ROI2DPolyLine(Point2D pt) 094 { 095 super(new Polyline2D()); 096 097 final Anchor2D point = createAnchor(pt); 098 point.setSelected(true); 099 addPoint(point); 100 101 // set icon (default name is defined by getDefaultName()) 102 setIcon(ResourceUtil.ICON_ROI_POLYLINE); 103 } 104 105 /** 106 * Generic constructor for interactive mode 107 */ 108 public ROI2DPolyLine(Point5D pt) 109 { 110 this(pt.toPoint2D()); 111 // getOverlay().setMousePos(pt); 112 } 113 114 public ROI2DPolyLine(Polygon polygon) 115 { 116 this(new Point2D.Double()); 117 118 setPolygon(polygon); 119 } 120 121 public ROI2DPolyLine(Polyline2D polyline) 122 { 123 this(new Point2D.Double()); 124 125 setPolyline2D(polyline); 126 } 127 128 public ROI2DPolyLine(List<Point2D> points) 129 { 130 this(new Point2D.Double()); 131 132 setPoints(points); 133 } 134 135 public ROI2DPolyLine() 136 { 137 this(new Point2D.Double()); 138 } 139 140 @Override 141 public String getDefaultName() 142 { 143 return "PolyLine2D"; 144 } 145 146 @Override 147 protected Anchor2D createAnchor(Point2D pos) 148 { 149 return new ROI2DPolyLineAnchor2D(pos, getColor(), getFocusedColor()); 150 } 151 152 // @Override 153 // protected ROI2DPolyLinePainter createPainter() 154 // { 155 // return new ROI2DPolyLinePainter(); 156 // } 157 158 /** 159 * @deprecated Use {@link #getPolyline2D()} instead 160 */ 161 @Deprecated 162 protected Path2D getPath() 163 { 164 return new Path2D.Double(shape); 165 } 166 167 public void setPoints(List<Point2D> pts) 168 { 169 beginUpdate(); 170 try 171 { 172 removeAllPoint(); 173 for (Point2D pt : pts) 174 addNewPoint(pt, false); 175 } 176 finally 177 { 178 endUpdate(); 179 } 180 } 181 182 /** 183 * @deprecated Use {@link #setPoints(List)} instead. 184 */ 185 @Deprecated 186 public void setPoints(ArrayList<Point2D> pts) 187 { 188 setPoints((List<Point2D>) pts); 189 } 190 191 public Polyline2D getPolyline2D() 192 { 193 return (Polyline2D) shape; 194 } 195 196 public void setPolyline2D(Polyline2D polyline2D) 197 { 198 beginUpdate(); 199 try 200 { 201 removeAllPoint(); 202 for (int i = 0; i < polyline2D.npoints; i++) 203 addNewPoint(new Point2D.Double(polyline2D.xpoints[i], polyline2D.ypoints[i]), false); 204 } 205 finally 206 { 207 endUpdate(); 208 } 209 } 210 211 public Polygon getPolygon() 212 { 213 return getPolyline2D().getPolygon2D().getPolygon(); 214 } 215 216 public void setPolygon(Polygon polygon) 217 { 218 beginUpdate(); 219 try 220 { 221 removeAllPoint(); 222 for (int i = 0; i < polygon.npoints; i++) 223 addNewPoint(new Point2D.Double(polygon.xpoints[i], polygon.ypoints[i]), false); 224 } 225 finally 226 { 227 endUpdate(); 228 } 229 } 230 231 @Override 232 public boolean contains(double x, double y) 233 { 234 return false; 235 } 236 237 @Override 238 public boolean contains(Point2D p) 239 { 240 return false; 241 } 242 243 @Override 244 public boolean contains(double x, double y, double w, double h) 245 { 246 return false; 247 } 248 249 @Override 250 public boolean contains(Rectangle2D r) 251 { 252 return false; 253 } 254 255 @Override 256 public boolean contains(ROI roi) 257 { 258 return false; 259 } 260 261 @Override 262 protected double getTotalDistance(List<Point2D> points, double factorX, double factorY) 263 { 264 // for polyline the total length don't need last point connection 265 return Point2DUtil.getTotalDistance(points, factorX, factorY, false); 266 } 267 268 @Override 269 public double computeNumberOfPoints() 270 { 271 return 0d; 272 } 273 274 @Override 275 protected void updateShape() 276 { 277 final int len; 278 final double[] ptsX; 279 final double[] ptsY; 280 281 synchronized (controlPoints) 282 { 283 len = controlPoints.size(); 284 ptsX = new double[len]; 285 ptsY = new double[len]; 286 287 for (int i = 0; i < len; i++) 288 { 289 final Anchor2D pt = controlPoints.get(i); 290 291 ptsX[i] = pt.getX(); 292 ptsY[i] = pt.getY(); 293 } 294 } 295 296 final Polyline2D polyline2d = getPolyline2D(); 297 298 // we can have a problem here if we try to redraw while we are modifying the polygon points 299 synchronized (polyline2d) 300 { 301 polyline2d.npoints = len; 302 polyline2d.xpoints = ptsX; 303 polyline2d.ypoints = ptsY; 304 polyline2d.calculatePath(); 305 } 306 307 // call super method after shape has been updated 308 super.updateShape(); 309 } 310 311 @Override 312 public boolean[] getBooleanMask(int x, int y, int w, int h, boolean inclusive) 313 { 314 if ((w <= 0) || (h <= 0)) 315 return new boolean[0]; 316 317 // this ROI doesn't contains area 318 if (!inclusive) 319 return new boolean[w * h]; 320 321 final BufferedImage maskImg = new BufferedImage(w, h, BufferedImage.TYPE_BYTE_GRAY); 322 final Graphics2D g = maskImg.createGraphics(); 323 324 // draw shape in image 325 g.setColor(Color.white); 326 g.translate(-x, -y); 327 g.draw(shape); 328 g.dispose(); 329 330 // use the image to define the mask 331 final byte[] maskData = ((DataBufferByte) maskImg.getRaster().getDataBuffer()).getData(); 332 final boolean[] result = new boolean[w * h]; 333 334 for (int i = 0; i < result.length; i++) 335 result[i] = (maskData[i] != 0); 336 337 return result; 338 } 339 340 @Override 341 public boolean loadFromXML(Node node) 342 { 343 beginUpdate(); 344 try 345 { 346 if (!super.loadFromXML(node)) 347 return false; 348 349 removeAllPoint(); 350 351 final List<Node> pointsNode = XMLUtil.getChildren(XMLUtil.getElement(node, ID_POINTS), ID_POINT); 352 if (pointsNode != null) 353 { 354 for (Node n : pointsNode) 355 { 356 final Anchor2D pt = createAnchor(new Point2D.Double()); 357 pt.loadPositionFromXML(n); 358 addPoint(pt); 359 } 360 } 361 } 362 finally 363 { 364 endUpdate(); 365 } 366 367 return true; 368 } 369 370 @Override 371 public boolean saveToXML(Node node) 372 { 373 if (!super.saveToXML(node)) 374 return false; 375 376 final Element pointsNode = XMLUtil.setElement(node, ID_POINTS); 377 synchronized (controlPoints) 378 { 379 for (Anchor2D pt : controlPoints) 380 pt.savePositionToXML(XMLUtil.addElement(pointsNode, ID_POINT)); 381 } 382 383 return true; 384 } 385}