001package plugins.kernel.roi.tool;
002
003import icy.canvas.IcyCanvas;
004import icy.roi.ROI;
005import icy.roi.ROIUtil;
006import icy.sequence.Sequence;
007import icy.sequence.edit.ROIReplacesSequenceEdit;
008import icy.system.thread.ThreadUtil;
009import icy.type.point.Point5D;
010import icy.type.point.Point5D.Double;
011import icy.type.rectangle.Rectangle2DUtil;
012
013import java.awt.BasicStroke;
014import java.awt.Graphics2D;
015import java.awt.event.MouseEvent;
016import java.awt.geom.Line2D;
017import java.util.ArrayList;
018import java.util.List;
019
020import plugins.kernel.roi.roi2d.ROI2DLine;
021
022/**
023 * ROI Helper class for ROI cutting action
024 * 
025 * @author Stephane
026 */
027public class ROILineCutter extends ROI2DLine
028{
029    public class ROILineCutterPainter extends ROI2DLinePainter
030    {
031        @Override
032        public void mouseReleased(MouseEvent e, Double imagePoint, IcyCanvas canvas)
033        {
034            super.mouseReleased(e, imagePoint, canvas);
035
036            // do that in background as it can take sometime
037            ThreadUtil.bgRun(new Runnable()
038            {
039                @Override
040                public void run()
041                {
042                    // get sequences where we are attached first
043                    final List<Sequence> sequences = getSequences();
044
045                    // remove the ROI, we don't need it anymore...
046                    ROILineCutter.this.remove(false);
047
048                    // and do cutting now
049                    splitOverlappedROIs(sequences);
050                }
051            });
052        }
053
054        @Override
055        protected void drawShape(Graphics2D g, Sequence sequence, IcyCanvas canvas, boolean simplified)
056        {
057            final Line2D extendedLine = getExtendedLine(sequence);
058
059            if (extendedLine != null)
060            {
061                final Graphics2D g2 = (Graphics2D) g.create();
062
063                // draw extended line
064                g2.setStroke(new BasicStroke((float) (ROI.getAdjustedStroke(canvas, stroke) / 2f)));
065                g2.setColor(getDisplayColor());
066                g2.draw(extendedLine);
067
068                g2.dispose();
069            }
070
071            super.drawShape(g, sequence, canvas, getLine(), simplified);
072        }
073    }
074
075    public ROILineCutter(Point5D pt)
076    {
077        super(pt);
078    }
079
080    public ROILineCutter()
081    {
082        super();
083    }
084
085    @Override
086    protected ROI2DShapePainter createPainter()
087    {
088        return new ROILineCutterPainter();
089    }
090
091    protected Line2D getExtendedLine(Sequence sequence)
092    {
093        return Rectangle2DUtil.getIntersectionLine(sequence.getBounds2D(), getLine());
094    }
095
096    /**
097     * This is a special function of this ROI, it cuts all overlapped ROI from given Sequences based on the current ROI
098     * shape (line).
099     * 
100     * @return <code>true</code> if some ROIS were cuts
101     */
102    public boolean splitOverlappedROIs(List<Sequence> sequences)
103    {
104        boolean result = false;
105
106        for (Sequence sequence : sequences)
107        {
108            final List<ROI> removedROI = new ArrayList<ROI>();
109            final List<ROI> addedROI = new ArrayList<ROI>();
110
111            sequence.beginUpdate();
112            try
113            {
114                for (ROI roi : sequence.getROIs())
115                {
116                    final List<ROI> resultRois = ROIUtil.split(roi, getLine());
117
118                    // ROI was cut ?
119                    if (resultRois != null)
120                    {
121                        removedROI.add(roi);
122                        addedROI.addAll(resultRois);
123                        result = true;
124                    }
125                }
126
127                if (!removedROI.isEmpty())
128                {
129                    sequence.removeROIs(removedROI, false);
130                    sequence.addROIs(addedROI, false);
131
132                    // add undo operation
133                    sequence.addUndoableEdit(new ROIReplacesSequenceEdit(sequence, removedROI, addedROI));
134                }
135            }
136            finally
137            {
138                sequence.endUpdate();
139            }
140        }
141
142        return result;
143    }
144}