/* * Copyright 2010-2015 Institut Pasteur. * * This file is part of Icy. * * Icy is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Icy is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Icy. If not, see <http://www.gnu.org/licenses/>. */ package plugins.kernel.roi.roi2d; import icy.canvas.IcyCanvas; import icy.painter.Anchor2D; import icy.painter.RectAnchor2D; import icy.util.XMLUtil; import java.awt.Color; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import java.awt.geom.RectangularShape; import org.w3c.dom.Node; /** * Base class for rectangular shape ROI. * * @author Stephane */ public abstract class ROI2DRectShape extends ROI2DShape { protected class ROI2DRectAnchor2D extends RectAnchor2D { public ROI2DRectAnchor2D(Point2D position, Color color, Color selectedColor) { super(position, color, selectedColor); } @Override protected Anchor2D getOppositePoint() { if (this == topLeft) return bottomRight; if (this == topRight) return bottomLeft; if (this == bottomLeft) return topRight; return topLeft; }; } public static final String ID_TOPLEFT = "top_left"; public static final String ID_BOTTOMRIGHT = "bottom_right"; protected final Anchor2D topLeft; protected final Anchor2D topRight; protected final Anchor2D bottomLeft; protected final Anchor2D bottomRight; protected boolean internalPositionSet; /** * */ public ROI2DRectShape(RectangularShape shape, Point2D topLeft, Point2D bottomRight) { super(shape); this.topLeft = createAnchor(topLeft); this.topRight = createAnchor(new Point2D.Double(bottomRight.getX(), topLeft.getY())); this.bottomLeft = createAnchor(new Point2D.Double(topLeft.getX(), bottomRight.getY())); this.bottomRight = createAnchor(bottomRight); // select the bottom right point by default for interactive mode this.bottomRight.setSelected(true); internalPositionSet = false; // order is important as we compute distance from connected points addPoint(this.topLeft); addPoint(this.topRight); addPoint(this.bottomRight); addPoint(this.bottomLeft); } @Override protected Anchor2D createAnchor(Point2D pos) { return new ROI2DRectAnchor2D(pos, getColor(), getFocusedColor()); } protected RectangularShape getRectangularShape() { return (RectangularShape) shape; } @Override public boolean canSetBounds() { return true; } @Override public void setBounds2D(Rectangle2D bounds) { beginUpdate(); try { // set anchors (only 2 significants anchors need to be adjusted) topLeft.setPosition(bounds.getMinX(), bounds.getMinY()); bottomRight.setPosition(bounds.getMaxX(), bounds.getMaxY()); } finally { endUpdate(); } } @Override protected void updateShape() { getRectangularShape().setFrameFromDiagonal(topLeft.getPosition(), bottomRight.getPosition()); // call super method after shape has been updated super.updateShape(); } @Override public boolean canAddPoint() { // this ROI doesn't support point add return false; } @Override public boolean canRemovePoint() { // this ROI doesn't support point remove return false; } @Override protected boolean removePoint(IcyCanvas canvas, Anchor2D pt) { // this ROI doesn't support point remove return false; } @Override public void controlPointPositionChanged(Anchor2D source) { // we are modifying internally the position --> exit if (internalPositionSet) return; internalPositionSet = true; try { // adjust dependents anchors if (source == topLeft) { bottomLeft.setX(topLeft.getX()); topRight.setY(topLeft.getY()); } else if (source == topRight) { bottomRight.setX(topRight.getX()); topLeft.setY(topRight.getY()); } else if (source == bottomLeft) { topLeft.setX(bottomLeft.getX()); bottomRight.setY(bottomLeft.getY()); } else if (source == bottomRight) { topRight.setX(bottomRight.getX()); bottomLeft.setY(bottomRight.getY()); } } finally { internalPositionSet = false; } super.controlPointPositionChanged(source); } @Override public void translate(double dx, double dy) { beginUpdate(); try { // translate (only 2 significants anchors need to be adjusted) topLeft.translate(dx, dy); bottomRight.translate(dx, dy); } finally { endUpdate(); } } @Override public boolean loadFromXML(Node node) { beginUpdate(); try { if (!super.loadFromXML(node)) return false; topLeft.loadPositionFromXML(XMLUtil.getElement(node, ID_TOPLEFT)); bottomRight.loadPositionFromXML(XMLUtil.getElement(node, ID_BOTTOMRIGHT)); } finally { endUpdate(); } return true; } @Override public boolean saveToXML(Node node) { if (!super.saveToXML(node)) return false; topLeft.savePositionToXML(XMLUtil.setElement(node, ID_TOPLEFT)); bottomRight.savePositionToXML(XMLUtil.setElement(node, ID_BOTTOMRIGHT)); return true; } }