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.canvas.IcyCanvas;
022import icy.painter.Anchor2D;
023import icy.painter.LineAnchor2D;
024import icy.resource.ResourceUtil;
025import icy.roi.ROI;
026import icy.type.point.Point2DUtil;
027import icy.type.point.Point5D;
028import icy.util.XMLUtil;
029
030import java.awt.Graphics2D;
031import java.awt.geom.Line2D;
032import java.awt.geom.Point2D;
033import java.awt.geom.Rectangle2D;
034import java.util.List;
035
036import org.w3c.dom.Node;
037
038/**
039 * ROI 2D Line.
040 * 
041 * @author Stephane
042 */
043public class ROI2DLine extends ROI2DShape
044{
045    protected class ROI2DLineAnchor2D extends LineAnchor2D
046    {
047        public ROI2DLineAnchor2D(Point2D position)
048        {
049            super(position, getOverlay().getColor(), getOverlay().getFocusedColor());
050        }
051
052        @Override
053        protected Anchor2D getPreviousPoint()
054        {
055            if (this == pt1)
056                return pt2;
057            return pt1;
058        }
059    }
060
061    public class ROI2DLinePainter extends ROI2DShapePainter
062    {
063        @Override
064        protected boolean isTiny(Rectangle2D bounds, Graphics2D g, IcyCanvas canvas)
065        {
066            if (isSelected())
067                return false;
068
069            return super.isTiny(bounds, g, canvas);
070        }
071    }
072
073    public static final String ID_PT1 = "pt1";
074    public static final String ID_PT2 = "pt2";
075
076    protected final Anchor2D pt1;
077    protected final Anchor2D pt2;
078
079    public ROI2DLine(Point2D pt1, Point2D pt2)
080    {
081        super(new Line2D.Double());
082
083        this.pt1 = createAnchor(pt1);
084        this.pt2 = createAnchor(pt2);
085        // keep pt2 selected to size the line for "interactive mode"
086        this.pt2.setSelected(true);
087
088        addPoint(this.pt1);
089        addPoint(this.pt2);
090
091        // set icon (default name is defined by getDefaultName()) 
092        setIcon(ResourceUtil.ICON_ROI_LINE);
093    }
094
095    public ROI2DLine(Line2D line)
096    {
097        this(line.getP1(), line.getP2());
098    }
099
100    /**
101     * @deprecated
102     */
103    @SuppressWarnings("unused")
104    @Deprecated
105    public ROI2DLine(Point2D pt, boolean cm)
106    {
107        this(pt);
108    }
109
110    public ROI2DLine(Point2D pt)
111    {
112        this(new Point2D.Double(pt.getX(), pt.getY()), pt);
113    }
114
115    /**
116     * Generic constructor for interactive mode
117     */
118    public ROI2DLine(Point5D pt)
119    {
120        this(pt.toPoint2D());
121        // getOverlay().setMousePos(pt);
122    }
123
124    public ROI2DLine(double x1, double y1, double x2, double y2)
125    {
126        this(new Point2D.Double(x1, y1), new Point2D.Double(x2, y2));
127    }
128
129    public ROI2DLine()
130    {
131        this(new Point2D.Double(), new Point2D.Double());
132    }
133    
134    @Override
135    public String getDefaultName()
136    {
137        return "Line2D";
138    }
139
140    @Override
141    protected ROI2DShapePainter createPainter()
142    {
143        return new ROI2DLinePainter();
144    }
145
146    @Override
147    protected Anchor2D createAnchor(Point2D pos)
148    {
149        return new ROI2DLineAnchor2D(pos);
150    }
151
152    public Line2D getLine()
153    {
154        return (Line2D) shape;
155    }
156
157    @Override
158    public boolean canSetBounds()
159    {
160        return true;
161    }
162
163    @Override
164    public void setBounds2D(Rectangle2D bounds)
165    {
166        beginUpdate();
167        try
168        {
169            pt1.setPosition(bounds.getMinX(), bounds.getMinY());
170            pt2.setPosition(bounds.getMaxX(), bounds.getMaxY());
171        }
172        finally
173        {
174            endUpdate();
175        }
176    }
177
178    public void setLine(Line2D line)
179    {
180        beginUpdate();
181        try
182        {
183            pt1.setPosition(line.getP1());
184            pt2.setPosition(line.getP2());
185        }
186        finally
187        {
188            endUpdate();
189        }
190    }
191
192    @Override
193    protected void updateShape()
194    {
195        getLine().setLine(pt1.getPosition(), pt2.getPosition());
196
197        // call super method after shape has been updated
198        super.updateShape();
199    }
200
201    @Override
202    public boolean canAddPoint()
203    {
204        // this ROI doesn't support point add
205        return false;
206    }
207
208    @Override
209    public boolean canRemovePoint()
210    {
211        // this ROI doesn't support point remove
212        return false;
213    }
214
215    @Override
216    protected boolean removePoint(IcyCanvas canvas, Anchor2D pt)
217    {
218        // this ROI doesn't support point remove
219        return false;
220    }
221
222    @Override
223    protected double getTotalDistance(List<Point2D> points, double factorX, double factorY)
224    {
225        // for ROI2DLine the total length don't need last point connection
226        return Point2DUtil.getTotalDistance(points, factorX, factorY, false);
227    }
228
229    @Override
230    public double computeNumberOfPoints()
231    {
232        return 0d;
233    }
234
235    @Override
236    public boolean contains(double x, double y)
237    {
238        return false;
239    }
240
241    @Override
242    public boolean contains(Point2D p)
243    {
244        return false;
245    }
246
247    @Override
248    public boolean contains(double x, double y, double w, double h)
249    {
250        return false;
251    }
252
253    @Override
254    public boolean contains(Rectangle2D r)
255    {
256        return false;
257    }
258
259    @Override
260    public boolean contains(ROI roi)
261    {
262        return false;
263    }
264
265    @Override
266    public boolean intersects(ROI r)
267    {
268        // special case of ROI2DLine
269        if (r instanceof ROI2DLine)
270            return onSamePos(((ROI2DLine) r), false) && ((ROI2DLine) r).getLine().intersectsLine(getLine());
271        // special case of ROI2DRectangle
272        if (r instanceof ROI2DRectangle)
273            return onSamePos(((ROI2DRectangle) r), false)
274                    && ((ROI2DRectangle) r).getRectangle().intersectsLine(getLine());
275
276        return super.intersects(r);
277    }
278
279    @Override
280    public boolean loadFromXML(Node node)
281    {
282        beginUpdate();
283        try
284        {
285            if (!super.loadFromXML(node))
286                return false;
287
288            pt1.loadPositionFromXML(XMLUtil.getElement(node, ID_PT1));
289            pt2.loadPositionFromXML(XMLUtil.getElement(node, ID_PT2));
290        }
291        finally
292        {
293            endUpdate();
294        }
295
296        return true;
297    }
298
299    @Override
300    public boolean saveToXML(Node node)
301    {
302        if (!super.saveToXML(node))
303            return false;
304
305        pt1.savePositionToXML(XMLUtil.setElement(node, ID_PT1));
306        pt2.savePositionToXML(XMLUtil.setElement(node, ID_PT2));
307
308        return true;
309    }
310}