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.type.geom.Polygon2D;
025import icy.type.point.Point5D;
026import icy.util.XMLUtil;
027
028import java.awt.Color;
029import java.awt.Polygon;
030import java.awt.geom.Path2D;
031import java.awt.geom.Point2D;
032import java.util.ArrayList;
033import java.util.List;
034
035import org.w3c.dom.Element;
036import org.w3c.dom.Node;
037
038/**
039 * ROI 2D polygon class.
040 * 
041 * @author Stephane
042 */
043public class ROI2DPolygon extends ROI2DShape
044{
045    protected class ROI2DPolygonAnchor2D extends LineAnchor2D
046    {
047        public ROI2DPolygonAnchor2D(Point2D position, Color color, Color selectedColor)
048        {
049            super(position, color, selectedColor);
050        }
051
052        @Override
053        protected Anchor2D getPreviousPoint()
054        {
055            final int ind = controlPoints.indexOf(this);
056
057            if (ind == 0)
058            {
059                if (controlPoints.size() > 1)
060                    return controlPoints.get(1);
061
062                return null;
063            }
064
065            if (ind != -1)
066                return controlPoints.get(ind - 1);
067
068            return null;
069        }
070    }
071
072    public static final String ID_POINTS = "points";
073    public static final String ID_POINT = "point";
074
075    /**
076     * @deprecated
077     */
078    @Deprecated
079    public ROI2DPolygon(Point2D pt, boolean cm)
080    {
081        this(pt);
082    }
083
084    public ROI2DPolygon(Point2D pt)
085    {
086        super(new Polygon2D());
087
088        final Anchor2D point = createAnchor(pt);
089        point.setSelected(true);
090        addPoint(point);
091
092        // set icon (default name is defined by getDefaultName())
093        setIcon(ResourceUtil.ICON_ROI_POLYGON);
094    }
095
096    /**
097     * Generic constructor for interactive mode
098     */
099    public ROI2DPolygon(Point5D pt)
100    {
101        this(pt.toPoint2D());
102        // getOverlay().setMousePos(pt);
103    }
104
105    public ROI2DPolygon(List<Point2D> points)
106    {
107        this(new Point2D.Double());
108
109        setPoints(points);
110        unselectAllPoints();
111    }
112
113    /**
114     * @deprecated Better to use {@link #ROI2DPolygon(Polygon2D)} instead to have double point precision
115     */
116    @Deprecated
117    public ROI2DPolygon(Polygon polygon)
118    {
119        this(new Point2D.Double());
120
121        setPolygon(polygon);
122        unselectAllPoints();
123    }
124
125    public ROI2DPolygon(Polygon2D polygon)
126    {
127        this(new Point2D.Double());
128
129        setPolygon2D(polygon);
130        unselectAllPoints();
131    }
132
133    public ROI2DPolygon()
134    {
135        this(new Point2D.Double());
136    }
137
138    @Override
139    public String getDefaultName()
140    {
141        return "Polygon2D";
142    }
143
144    @Override
145    protected Anchor2D createAnchor(Point2D pos)
146    {
147        return new ROI2DPolygonAnchor2D(pos, getColor(), getFocusedColor());
148    }
149
150    /**
151     * @deprecated Use {@link #getPolygon2D()} instead
152     */
153    @Deprecated
154    protected Path2D getPath()
155    {
156        return new Path2D.Double(shape);
157    }
158
159    public void setPoints(List<Point2D> pts)
160    {
161        beginUpdate();
162        try
163        {
164            removeAllPoint();
165            for (Point2D pt : pts)
166                addNewPoint(pt, false);
167        }
168        finally
169        {
170            endUpdate();
171        }
172    }
173
174    /**
175     * @deprecated Use {@link #setPoints(List)} instead.
176     */
177    @Deprecated
178    public void setPoints(ArrayList<Point2D> pts)
179    {
180        setPoints((List<Point2D>) pts);
181    }
182
183    public Polygon2D getPolygon2D()
184    {
185        return (Polygon2D) shape;
186    }
187
188    public void setPolygon2D(Polygon2D polygon2D)
189    {
190        beginUpdate();
191        try
192        {
193            removeAllPoint();
194            for (int i = 0; i < polygon2D.npoints; i++)
195                addNewPoint(new Point2D.Double(polygon2D.xpoints[i], polygon2D.ypoints[i]), false);
196        }
197        finally
198        {
199            endUpdate();
200        }
201    }
202
203    public Polygon getPolygon()
204    {
205        return getPolygon2D().getPolygon();
206    }
207
208    public void setPolygon(Polygon polygon)
209    {
210        beginUpdate();
211        try
212        {
213            removeAllPoint();
214            for (int i = 0; i < polygon.npoints; i++)
215                addNewPoint(new Point2D.Double(polygon.xpoints[i], polygon.ypoints[i]), false);
216        }
217        finally
218        {
219            endUpdate();
220        }
221    }
222
223    @Override
224    protected void updateShape()
225    {
226        final int len;
227        final double[] ptsX;
228        final double[] ptsY;
229
230        synchronized (controlPoints)
231        {
232            len = controlPoints.size();
233            ptsX = new double[len];
234            ptsY = new double[len];
235
236            for (int i = 0; i < len; i++)
237            {
238                final Anchor2D pt = controlPoints.get(i);
239
240                ptsX[i] = pt.getX();
241                ptsY[i] = pt.getY();
242            }
243        }
244
245        final Polygon2D polygon2d = getPolygon2D();
246
247        // we can have a problem here if we try to redraw while we are modifying the polygon points
248        synchronized (polygon2d)
249        {
250            polygon2d.npoints = len;
251            polygon2d.xpoints = ptsX;
252            polygon2d.ypoints = ptsY;
253            polygon2d.calculatePath();
254        }
255
256        // call super method after shape has been updated
257        super.updateShape();
258    }
259
260    @Override
261    public boolean loadFromXML(Node node)
262    {
263        beginUpdate();
264        try
265        {
266            if (!super.loadFromXML(node))
267                return false;
268
269            removeAllPoint();
270
271            final List<Node> nodesPoint = XMLUtil.getChildren(XMLUtil.getElement(node, ID_POINTS), ID_POINT);
272            if (nodesPoint != null)
273            {
274                for (Node n : nodesPoint)
275                {
276                    final Anchor2D pt = createAnchor(new Point2D.Double());
277                    pt.loadPositionFromXML(n);
278                    addPoint(pt);
279                }
280            }
281        }
282        finally
283        {
284            endUpdate();
285        }
286
287        return true;
288    }
289
290    @Override
291    public boolean saveToXML(Node node)
292    {
293        if (!super.saveToXML(node))
294            return false;
295
296        final Element nodePoints = XMLUtil.setElement(node, ID_POINTS);
297        synchronized (controlPoints)
298        {
299            for (Anchor2D pt : controlPoints)
300                pt.savePositionToXML(XMLUtil.addElement(nodePoints, ID_POINT));
301        }
302        return true;
303    }
304}