001: /*
002: * Created on 23 juin 2005
003: *
004: * Olivier BEDEL
005: * Bassin Versant du Jaudy-Guindy-Bizien,
006: * Laboratoire RESO UMR ESO 6590 CNRS, Université de Rennes 2
007: *
008: */
009: package org.openjump.core.ui.style.decoration;
010:
011: import java.awt.Graphics2D;
012: import java.awt.Point;
013: import java.awt.geom.AffineTransform;
014: import java.awt.geom.GeneralPath;
015: import java.awt.geom.NoninvertibleTransformException;
016: import java.awt.geom.Point2D;
017:
018: import com.vividsolutions.jump.I18N;
019: import com.vividsolutions.jump.workbench.ui.GUIUtil;
020: import com.vividsolutions.jump.workbench.ui.Viewport;
021: import com.vividsolutions.jump.workbench.ui.images.IconLoader;
022: import com.vividsolutions.jump.workbench.ui.renderer.style.LineStringEndpointStyle;
023:
024: /**
025: * @author Olivier
026: *
027: */
028: public class ArrowLineStringMiddlepointStyle extends
029: LineStringEndpointStyle {
030:
031: private final static double SMALL_ANGLE = 10;
032: private final static double MEDIUM_ANGLE = 30;
033:
034: private final static double MEDIUM_LENGTH = 10;
035: private final static double LARGE_LENGTH = 15;
036: private boolean filled;
037: private double finAngle;
038: protected double finLength;
039:
040: public ArrowLineStringMiddlepointStyle(String name, boolean start,
041: String iconFile, double finAngle, double finLength,
042: boolean filled) {
043: super (name, IconLoader.icon(iconFile), start);
044: this .finAngle = finAngle;
045: this .finLength = finLength;
046: this .filled = filled;
047: }
048:
049: /**
050: * @param tail the tail of the whole arrow; just used to determine angle
051: * @param finLength required distance from the tip to each fin's tip
052: */
053: private GeneralPath arrowhead(Point2D shaftTip, Point2D shaftTail,
054: double finLength, double finAngle) {
055: GeneralPath arrowhead = new GeneralPath();
056: Point2D finTip1 = fin(shaftTip, shaftTail, finLength, finAngle);
057: Point2D finTip2 = fin(shaftTip, shaftTail, finLength, -finAngle);
058: arrowhead
059: .moveTo((float) finTip1.getX(), (float) finTip1.getY());
060: arrowhead.lineTo((float) shaftTip.getX(), (float) shaftTip
061: .getY());
062: arrowhead
063: .lineTo((float) finTip2.getX(), (float) finTip2.getY());
064:
065: return arrowhead;
066: }
067:
068: private Point2D fin(Point2D shaftTip, Point2D shaftTail,
069: double length, double angle) {
070: double shaftLength = shaftTip.distance(shaftTail);
071: Point2D finTail = shaftTip;
072: Point2D finTip = GUIUtil.add(GUIUtil.multiply(GUIUtil.subtract(
073: shaftTail, shaftTip), length / shaftLength), finTail);
074: AffineTransform affineTransform = new AffineTransform();
075: affineTransform.rotate((angle * Math.PI) / 180, finTail.getX(),
076: finTail.getY());
077:
078: return affineTransform.transform(finTip, null);
079: }
080:
081: protected void paint(Point2D terminal, Point2D next,
082: Viewport viewport, Graphics2D graphics)
083: throws NoninvertibleTransformException {
084: if (terminal.equals(next)) {
085: return;
086: }
087:
088: graphics.setColor(lineColorWithAlpha);
089: graphics.setStroke(stroke);
090: Point2D middle = new Point();
091:
092: middle.setLocation((terminal.getX() + next.getX()) / 2.0,
093: (terminal.getY() + next.getY()) / 2.0);
094: GeneralPath arrowhead = arrowhead(middle, next, finLength,
095: finAngle);
096:
097: if (filled) {
098: arrowhead.closePath();
099: graphics.fill(arrowhead);
100: }
101:
102: //#fill isn't affected by line width, but #draw is. Therefore, draw even
103: //if we've already filled. [Jon Aquino]
104: graphics.draw(arrowhead);
105: }
106:
107: public static class NarrowSolidMiddle extends
108: ArrowLineStringMiddlepointStyle {
109: public NarrowSolidMiddle() {
110: super (
111: I18N
112: .get("ui.renderer.style.ArrowLineStringMiddlepointStyle.Middle-Arrow-Solid-Narrow"), false, "ArrowEndSolidNarrow.gif", //$NON-NLS-1$ //$NON-NLS-2$
113: SMALL_ANGLE, LARGE_LENGTH, true);
114: }
115: }
116: }
|