001: /*
002: * The Unified Mapping Platform (JUMP) is an extensible, interactive GUI
003: * for visualizing and manipulating spatial features with geometry and attributes.
004: *
005: * Copyright (C) 2003 Vivid Solutions
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License
009: * as published by the Free Software Foundation; either version 2
010: * of the License, or (at your option) any later version.
011: *
012: * This program is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
015: * GNU General Public License for more details.
016: *
017: * You should have received a copy of the GNU General Public License
018: * along with this program; if not, write to the Free Software
019: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
020: *
021: * For more information, contact:
022: *
023: * Vivid Solutions
024: * Suite #1A
025: * 2328 Government Street
026: * Victoria BC V8T 5G5
027: * Canada
028: *
029: * (250)385-6040
030: * www.vividsolutions.com
031: */
032:
033: package com.vividsolutions.jump.workbench.ui.renderer.style;
034:
035: import java.awt.BasicStroke;
036: import java.awt.Graphics2D;
037: import java.awt.geom.AffineTransform;
038: import java.awt.geom.GeneralPath;
039: import java.awt.geom.NoninvertibleTransformException;
040: import java.awt.geom.Point2D;
041:
042: import com.vividsolutions.jump.I18N;
043: import com.vividsolutions.jump.workbench.model.Layer;
044: import com.vividsolutions.jump.workbench.ui.GUIUtil;
045: import com.vividsolutions.jump.workbench.ui.Viewport;
046: import com.vividsolutions.jump.workbench.ui.images.IconLoader;
047:
048: public class ArrowLineStringSegmentStyle extends LineStringSegmentStyle {
049: private final static double SMALL_ANGLE = 10;
050: private final static double MEDIUM_ANGLE = 30;
051:
052: private final static double MEDIUM_LENGTH = 10;
053: private final static double LARGE_LENGTH = 15;
054: private boolean filled;
055: private double finAngle;
056: protected double finLength;
057:
058: /**
059: * @param finAngle degrees
060: * @param finLength pixels
061: */
062: public ArrowLineStringSegmentStyle(String name, String iconFile,
063: double finAngle, double finLength, boolean filled) {
064: super (name, IconLoader.icon(iconFile));
065: this .finAngle = finAngle;
066: this .finLength = finLength;
067: this .filled = filled;
068: }
069:
070: protected void paint(Point2D p0, Point2D p1, Viewport viewport,
071: Graphics2D graphics) throws NoninvertibleTransformException {
072: if (p0.equals(p1)) {
073: return;
074: }
075:
076: graphics.setColor(lineColorWithAlpha);
077: graphics.setStroke(stroke);
078:
079: GeneralPath arrowhead = arrowhead(p0, p1, finLength, finAngle);
080:
081: if (filled) {
082: arrowhead.closePath();
083: graphics.fill(arrowhead);
084: }
085:
086: //#fill isn't affected by line width, but #draw is. Therefore, draw even
087: //if we've already filled. [Jon Aquino]
088: graphics.draw(arrowhead);
089: }
090:
091: /**
092: * @param tail the tail of the whole arrow; just used to determine angle
093: * @param finLength required distance from the tip to each fin's tip
094: */
095: private GeneralPath arrowhead(Point2D p0, Point2D p1,
096: double finLength, double finAngle) {
097: Point2D mid = new Point2D.Float(
098: (float) ((p0.getX() + p1.getX()) / 2), (float) ((p0
099: .getY() + p1.getY()) / 2));
100: GeneralPath arrowhead = new GeneralPath();
101: Point2D finTip1 = fin(mid, p0, finLength, finAngle);
102: Point2D finTip2 = fin(mid, p0, finLength, -finAngle);
103: arrowhead
104: .moveTo((float) finTip1.getX(), (float) finTip1.getY());
105: arrowhead.lineTo((float) mid.getX(), (float) mid.getY());
106: arrowhead
107: .lineTo((float) finTip2.getX(), (float) finTip2.getY());
108:
109: return arrowhead;
110: }
111:
112: private Point2D fin(Point2D shaftTip, Point2D shaftTail,
113: double length, double angle) {
114: double shaftLength = shaftTip.distance(shaftTail);
115: Point2D finTail = shaftTip;
116: Point2D finTip = GUIUtil.add(GUIUtil.multiply(GUIUtil.subtract(
117: shaftTail, shaftTip), length / shaftLength), finTail);
118: AffineTransform affineTransform = new AffineTransform();
119: affineTransform.rotate((angle * Math.PI) / 180, finTail.getX(),
120: finTail.getY());
121:
122: return affineTransform.transform(finTip, null);
123: }
124:
125: public static class Open extends ArrowLineStringSegmentStyle {
126: public Open() {
127: super (
128: I18N
129: .get("ui.renderer.style.ArrowLineStringSegmentStyle.Segment-Mid-Arrow-Open"),
130: "ArrowMidOpen.gif", MEDIUM_ANGLE, MEDIUM_LENGTH,
131: false);
132: }
133: }
134:
135: public static class Solid extends ArrowLineStringSegmentStyle {
136: public Solid() {
137: super (
138: I18N
139: .get("ui.renderer.style.ArrowLineStringSegmentStyle.Segment-Mid-Arrow-Solid"),
140: "ArrowMidSolid.gif", MEDIUM_ANGLE, MEDIUM_LENGTH,
141: true);
142: }
143: }
144:
145: public static class NarrowSolid extends ArrowLineStringSegmentStyle {
146: public NarrowSolid() {
147: super (
148: I18N
149: .get("ui.renderer.style.ArrowLineStringSegmentStyle.Segment-Mid-Arrow-Solid-Narrow"),
150: "ArrowMidSolidNarrow.gif", SMALL_ANGLE,
151: LARGE_LENGTH, true);
152: }
153: }
154:
155: }
|