package org.openjump.core.ui.style.decoration;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import java.awt.geom.NoninvertibleTransformException;
import java.awt.geom.Point2D;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jump.I18N;
import com.vividsolutions.jump.workbench.ui.GUIUtil;
import com.vividsolutions.jump.workbench.ui.Viewport;
import com.vividsolutions.jump.workbench.ui.images.IconLoader;
import com.vividsolutions.jump.workbench.ui.renderer.style.LineStringSegmentStyle;
/**
* @author Paul Austin
*/
public abstract class SegmentDownhillArrowStyle extends LineStringSegmentStyle {
private final static double SMALL_ANGLE = 10;
private final static double MEDIUM_ANGLE = 30;
private final static double MEDIUM_LENGTH = 10;
private final static double LARGE_LENGTH = 15;
private boolean filled;
private double finAngle;
protected double finLength;
public SegmentDownhillArrowStyle(String name, String iconFile,
double finAngle, double finLength, boolean filled) {
super(I18N.get(SegmentDownhillArrowStyle.class.getName()
+ "." + name), IconLoader.icon(iconFile));
this.finAngle = finAngle;
this.finLength = finLength;
this.filled = filled;
}
/**
* @param tail the tail of the whole arrow; just used to determine angle
* @param finLength required distance from the tip to each fin's tip
*/
private GeneralPath arrowhead(Point2D shaftTip, Point2D shaftTail,
double finLength, double finAngle) {
GeneralPath arrowhead = new GeneralPath();
Point2D finTip1 = fin(shaftTip, shaftTail, finLength, finAngle);
Point2D finTip2 = fin(shaftTip, shaftTail, finLength, -finAngle);
arrowhead.moveTo((float)finTip1.getX(), (float)finTip1.getY());
arrowhead.lineTo((float)shaftTip.getX(), (float)shaftTip.getY());
arrowhead.lineTo((float)finTip2.getX(), (float)finTip2.getY());
return arrowhead;
}
private Point2D fin(Point2D shaftTip, Point2D shaftTail, double length,
double angle) {
double shaftLength = shaftTip.distance(shaftTail);
Point2D finTail = shaftTip;
Point2D finTip = GUIUtil.add(GUIUtil.multiply(GUIUtil.subtract(shaftTail,
shaftTip), length / shaftLength), finTail);
AffineTransform affineTransform = new AffineTransform();
affineTransform.rotate((angle * Math.PI) / 180, finTail.getX(),
finTail.getY());
return affineTransform.transform(finTip, null);
}
protected void paint(Coordinate terminal, Coordinate next, Viewport viewport,
Graphics2D graphics) throws Exception {
Point2D startPoint = viewport.toViewPoint(new Point2D.Double(terminal.x,
terminal.y));
Point2D endPoint = viewport.toViewPoint(new Point2D.Double(next.x, next.y));
if (terminal.z != next.z && !Double.isNaN(terminal.z)
&& !Double.isNaN(next.z)) {
if (terminal.z < next.z) {
paint(startPoint, endPoint, viewport, graphics);
} else {
paint(endPoint, startPoint, viewport, graphics);
}
}
}
protected void paint(Point2D terminal, Point2D next, Viewport viewport,
Graphics2D graphics) throws NoninvertibleTransformException {
if (terminal.equals(next)) {
return;
}
graphics.setColor(lineColorWithAlpha);
graphics.setStroke(stroke);
Point2D middle = new Point();
middle.setLocation((terminal.getX() + next.getX()) / 2.0,
(terminal.getY() + next.getY()) / 2.0);
GeneralPath arrowhead = arrowhead(middle, next, finLength, finAngle);
if (filled) {
arrowhead.closePath();
graphics.fill(arrowhead);
}
graphics.draw(arrowhead);
}
public static class Open extends SegmentDownhillArrowStyle {
public Open() {
super("Open", "ArrowMidOpen.gif", MEDIUM_ANGLE, MEDIUM_LENGTH, false);
}
}
public static class Solid extends SegmentDownhillArrowStyle {
public Solid() {
super("Solid", "ArrowMidSolid.gif", MEDIUM_ANGLE, MEDIUM_LENGTH, true);
}
}
public static class NarrowSolidMiddle extends SegmentDownhillArrowStyle {
public NarrowSolidMiddle() {
super("SolidNarrow", "ArrowMidSolidNarrow.gif", SMALL_ANGLE, LARGE_LENGTH,
true);
}
}
}