/******************************************************************************* * Copyright (c) 2006-2012 * Software Technology Group, Dresden University of Technology * DevBoost GmbH, Berlin, Amtsgericht Charlottenburg, HRB 140026 * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Software Technology Group - TU Dresden, Germany; * DevBoost GmbH - Berlin, Germany * - initial API and implementation ******************************************************************************/ /* * @(#)AbstractLineDecoration.java 2.0 2006-01-14 * * Copyright (c) 1996-2006 by the original authors of JHotDraw * and all its contributors. * All rights reserved. * * The copyright of this software is owned by the authors and * contributors of the JHotDraw project ("the copyright holders"). * You may not use, copy or modify this software, except in * accordance with the license agreement you entered into with * the copyright holders. For details see accompanying license terms. * */ package org.jhotdraw.draw; import java.io.*; import java.awt.*; import java.awt.geom.*; import org.jhotdraw.geom.Geom; import org.jhotdraw.util.*; import static org.jhotdraw.draw.AttributeKeys.*; /** * An standard implementation of a line decoration. It draws a shape which * is rotated and moved to the end of the line. The shape is scaled by the * stroke width. * * @author Werner Randelshofer * @version 2.0 2006-01-14 Changed to support double precison coordinates. * <br>1.0 2003-12-01 Derived from JHotDraw 5.4b1. */ public abstract class AbstractLineDecoration implements LineDecoration { /** * If this is true, the decoration is filled. */ private boolean isFilled; /** * If this is true, the decoration is stroked. */ private boolean isStroked; /** * If this is true, the stroke color is used to fill the decoration. */ private boolean isSolid; /** * Constructs an arrow tip with the given angle and radius. */ public AbstractLineDecoration(boolean isFilled, boolean isStroked, boolean isSolid) { this.isFilled = isFilled; this.isStroked = isStroked; this.isSolid = isSolid; } protected boolean isFilled() { return isFilled; } protected boolean isStroked() { return isStroked; } protected boolean isSolid() { return isSolid; } /** * Draws the arrow tip in the direction specified by the given two * Points.. (template method) */ public void draw(Graphics2D g, Figure f, Point2D.Double p1, Point2D.Double p2) { GeneralPath path = getTransformedDecoratorPath(f, p1, p2); Color color; if (isFilled) { if (isSolid) { color = STROKE_COLOR.get(f); } else { color = FILL_COLOR.get(f); } if (color != null) { g.setColor(color); g.fill(path); } } if (isStroked) { color = STROKE_COLOR.get(f); if (color != null) { g.setColor(color); g.setStroke(AttributeKeys.getStroke(f)); g.draw(path); } } } /** * Returns the drawing area of the decorator. */ public Rectangle2D.Double getDrawingArea(Figure f, Point2D.Double p1, Point2D.Double p2) { GeneralPath path = getTransformedDecoratorPath(f, p1, p2); Rectangle2D b = path.getBounds2D(); Rectangle2D.Double area = new Rectangle2D.Double(b.getX(), b.getY(), b.getWidth(), b.getHeight()); if (isStroked) { double strokeWidth = STROKE_WIDTH.get(f); int strokeJoin = STROKE_JOIN.get(f); double miterLimit = (STROKE_MITER_LIMIT.get(f) * strokeWidth); double grow; if (strokeJoin == BasicStroke.JOIN_MITER) { grow = (int) (1 + strokeWidth / 2 * miterLimit); } else { grow = (int) (1 + strokeWidth / 2); } Geom.grow(area, grow, grow); } else { Geom.grow(area, 1, 1); // grow due to antialiasing } return area; } public double getDecorationRadius(Figure f) { double strokeWidth = STROKE_WIDTH.get(f); double scaleFactor; if (strokeWidth > 1f) { scaleFactor = 1d + (strokeWidth - 1d) / 2d; } else { scaleFactor = 1d; } return getDecoratorPathRadius(f) * scaleFactor; } private GeneralPath getTransformedDecoratorPath(Figure f, Point2D.Double p1, Point2D.Double p2) { GeneralPath path = getDecoratorPath(f); double strokeWidth = STROKE_WIDTH.get(f); AffineTransform transform = new AffineTransform(); transform.translate(p1.x, p1.y); transform.rotate(Math.atan2(p1.x - p2.x, p2.y - p1.y)); // transform.rotate(Math.PI / 2); if (strokeWidth > 1f) { transform.scale(1d + (strokeWidth - 1d) / 2d, 1d + (strokeWidth - 1d) / 2d); } path.transform(transform); return path; } protected void setFilled(boolean b) { isFilled = b; } protected void setStroked(boolean b) { isStroked = b; } protected void setSolid(boolean b) { isSolid = b; } /** * Hook method to calculates the path of the decorator. */ protected abstract GeneralPath getDecoratorPath(Figure f); /** * Hook method to calculates the radius of the decorator path. */ protected abstract double getDecoratorPathRadius(Figure f); }