/* VisualReferenceArrow.java created 2007-11-30 * */ package org.signalml.app.view.montage.visualreference; import java.awt.Color; import java.awt.Point; import java.awt.Shape; import java.awt.geom.AffineTransform; import java.awt.geom.Path2D; import org.signalml.util.Util; /** VisualReferenceArrow * * * @author Michal Dobaczewski © 2007-2008 CC Otwarte Systemy Komputerowe Sp. z o.o. */ public class VisualReferenceArrow { public static final int FULL_SHAFT_WIDTH = 3; public static final int FULL_SHAFT_WIDTH_AT_POINT = 5; public static final int FULL_POINT_WIDTH = 8; public static final int POINT_LENGTH = 12; public static final double HALF_SHAFT_WIDTH = FULL_SHAFT_WIDTH / 2.; public static final double HALF_SHAFT_WIDTH_AT_POINT = FULL_SHAFT_WIDTH_AT_POINT / 2.; public static final double HALF_POINT_WIDTH = FULL_POINT_WIDTH / 2.; private int sourceChannel; private int targetChannel; private Point fromPoint; private Point toPoint; private Color color; private Shape cachedShape; private boolean positioned = false; public VisualReferenceArrow(int sourceChannel, int targetChannel) { this.sourceChannel = sourceChannel; this.targetChannel = targetChannel; } public int getSourceChannel() { return sourceChannel; } public int getTargetChannel() { return targetChannel; } public Point getFromPoint() { return fromPoint; } public void setFromPoint(Point fromPoint) { if (!Util.equalsWithNulls(this.fromPoint, fromPoint)) { this.fromPoint = fromPoint; cachedShape = null; } } public Point getToPoint() { return toPoint; } public void setToPoint(Point toPoint) { if (!Util.equalsWithNulls(this.toPoint, toPoint)) { this.toPoint = toPoint; cachedShape = null; } } public Color getColor() { return color; } public void setColor(Color color) { this.color = color; } public Shape getShape() { if (cachedShape == null) { if (fromPoint == null || toPoint == null) { return null; } else { cachedShape = createArrowShape(); } } return cachedShape; } private Shape createArrowShape() { double distance = fromPoint.distance(toPoint); double fixedPointLength = Math.min(distance, POINT_LENGTH); double shaftLength = distance - fixedPointLength; Path2D.Double path = new Path2D.Double(); path.moveTo(fromPoint.x, fromPoint.y); if (shaftLength > 0) { path.lineTo(fromPoint.x, fromPoint.y-HALF_SHAFT_WIDTH); path.lineTo(fromPoint.x+shaftLength, fromPoint.y-HALF_SHAFT_WIDTH_AT_POINT); path.lineTo(fromPoint.x+shaftLength, fromPoint.y-HALF_POINT_WIDTH); path.lineTo(fromPoint.x+distance, fromPoint.y); path.lineTo(fromPoint.x+shaftLength, fromPoint.y+HALF_POINT_WIDTH); path.lineTo(fromPoint.x+shaftLength, fromPoint.y+HALF_SHAFT_WIDTH_AT_POINT); path.lineTo(fromPoint.x, fromPoint.y+HALF_SHAFT_WIDTH); } else { // short triangular shaft-less arrow to be used for very shor distances path.lineTo(fromPoint.x, fromPoint.y-HALF_POINT_WIDTH); path.lineTo(fromPoint.x+distance, fromPoint.y); path.lineTo(fromPoint.x, fromPoint.y+HALF_POINT_WIDTH); } path.lineTo(fromPoint.x, fromPoint.y); // calculate angle and rotate the arrow double dx = toPoint.x - fromPoint.x; double dy = toPoint.y - fromPoint.y; double theta = Math.atan2(dy, dx); return AffineTransform.getRotateInstance(theta, fromPoint.x, fromPoint.y).createTransformedShape(path); } public boolean isPositioned() { return positioned; } public void setPositioned(boolean positioned) { this.positioned = positioned; } }