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}