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.RectAnchor2D; 024import icy.util.XMLUtil; 025 026import java.awt.Color; 027import java.awt.geom.Point2D; 028import java.awt.geom.Rectangle2D; 029import java.awt.geom.RectangularShape; 030 031import org.w3c.dom.Node; 032 033/** 034 * Base class for rectangular shape ROI. 035 * 036 * @author Stephane 037 */ 038public abstract class ROI2DRectShape extends ROI2DShape 039{ 040 protected class ROI2DRectAnchor2D extends RectAnchor2D 041 { 042 public ROI2DRectAnchor2D(Point2D position, Color color, Color selectedColor) 043 { 044 super(position, color, selectedColor); 045 } 046 047 @Override 048 protected Anchor2D getOppositePoint() 049 { 050 if (this == topLeft) 051 return bottomRight; 052 if (this == topRight) 053 return bottomLeft; 054 if (this == bottomLeft) 055 return topRight; 056 057 return topLeft; 058 }; 059 } 060 061 public static final String ID_TOPLEFT = "top_left"; 062 public static final String ID_BOTTOMRIGHT = "bottom_right"; 063 064 protected final Anchor2D topLeft; 065 protected final Anchor2D topRight; 066 protected final Anchor2D bottomLeft; 067 protected final Anchor2D bottomRight; 068 069 protected boolean internalPositionSet; 070 071 /** 072 * 073 */ 074 public ROI2DRectShape(RectangularShape shape, Point2D topLeft, Point2D bottomRight) 075 { 076 super(shape); 077 078 this.topLeft = createAnchor(topLeft); 079 this.topRight = createAnchor(new Point2D.Double(bottomRight.getX(), topLeft.getY())); 080 this.bottomLeft = createAnchor(new Point2D.Double(topLeft.getX(), bottomRight.getY())); 081 this.bottomRight = createAnchor(bottomRight); 082 // select the bottom right point by default for interactive mode 083 this.bottomRight.setSelected(true); 084 085 internalPositionSet = false; 086 087 // order is important as we compute distance from connected points 088 addPoint(this.topLeft); 089 addPoint(this.topRight); 090 addPoint(this.bottomRight); 091 addPoint(this.bottomLeft); 092 } 093 094 @Override 095 protected Anchor2D createAnchor(Point2D pos) 096 { 097 return new ROI2DRectAnchor2D(pos, getColor(), getFocusedColor()); 098 } 099 100 protected RectangularShape getRectangularShape() 101 { 102 return (RectangularShape) shape; 103 } 104 105 @Override 106 public boolean canSetBounds() 107 { 108 return true; 109 } 110 111 @Override 112 public void setBounds2D(Rectangle2D bounds) 113 { 114 beginUpdate(); 115 try 116 { 117 // set anchors (only 2 significants anchors need to be adjusted) 118 topLeft.setPosition(bounds.getMinX(), bounds.getMinY()); 119 bottomRight.setPosition(bounds.getMaxX(), bounds.getMaxY()); 120 } 121 finally 122 { 123 endUpdate(); 124 } 125 } 126 127 @Override 128 protected void updateShape() 129 { 130 getRectangularShape().setFrameFromDiagonal(topLeft.getPosition(), bottomRight.getPosition()); 131 132 // call super method after shape has been updated 133 super.updateShape(); 134 } 135 136 @Override 137 public boolean canAddPoint() 138 { 139 // this ROI doesn't support point add 140 return false; 141 } 142 143 @Override 144 public boolean canRemovePoint() 145 { 146 // this ROI doesn't support point remove 147 return false; 148 } 149 150 @Override 151 protected boolean removePoint(IcyCanvas canvas, Anchor2D pt) 152 { 153 // this ROI doesn't support point remove 154 return false; 155 } 156 157 @Override 158 public void controlPointPositionChanged(Anchor2D source) 159 { 160 // we are modifying internally the position --> exit 161 if (internalPositionSet) 162 return; 163 164 internalPositionSet = true; 165 try 166 { 167 // adjust dependents anchors 168 if (source == topLeft) 169 { 170 bottomLeft.setX(topLeft.getX()); 171 topRight.setY(topLeft.getY()); 172 } 173 else if (source == topRight) 174 { 175 bottomRight.setX(topRight.getX()); 176 topLeft.setY(topRight.getY()); 177 } 178 else if (source == bottomLeft) 179 { 180 topLeft.setX(bottomLeft.getX()); 181 bottomRight.setY(bottomLeft.getY()); 182 } 183 else if (source == bottomRight) 184 { 185 topRight.setX(bottomRight.getX()); 186 bottomLeft.setY(bottomRight.getY()); 187 } 188 } 189 finally 190 { 191 internalPositionSet = false; 192 } 193 194 super.controlPointPositionChanged(source); 195 } 196 197 @Override 198 public void translate(double dx, double dy) 199 { 200 beginUpdate(); 201 try 202 { 203 // translate (only 2 significants anchors need to be adjusted) 204 topLeft.translate(dx, dy); 205 bottomRight.translate(dx, dy); 206 } 207 finally 208 { 209 endUpdate(); 210 } 211 } 212 213 @Override 214 public boolean loadFromXML(Node node) 215 { 216 beginUpdate(); 217 try 218 { 219 if (!super.loadFromXML(node)) 220 return false; 221 222 topLeft.loadPositionFromXML(XMLUtil.getElement(node, ID_TOPLEFT)); 223 bottomRight.loadPositionFromXML(XMLUtil.getElement(node, ID_BOTTOMRIGHT)); 224 } 225 finally 226 { 227 endUpdate(); 228 } 229 230 return true; 231 } 232 233 @Override 234 public boolean saveToXML(Node node) 235 { 236 if (!super.saveToXML(node)) 237 return false; 238 239 topLeft.savePositionToXML(XMLUtil.setElement(node, ID_TOPLEFT)); 240 bottomRight.savePositionToXML(XMLUtil.setElement(node, ID_BOTTOMRIGHT)); 241 242 return true; 243 } 244 245}