/******************************************************************************* * 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 ******************************************************************************/ /* * @(#)TriangleFigure.java 1.0 2006-03-27 * * 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.awt.*; import java.awt.geom.*; import java.io.*; import java.util.*; import javax.swing.*; import static org.jhotdraw.draw.AttributeKeys.*; import org.jhotdraw.geom.*; /** * A triangle with same dimensions as its enclosing rectangle, * and apex at any of 8 places * * * @author Werner Randelshofer * @version 1.0 2006-03-27 Created. */ public class TriangleFigure extends AbstractAttributedFigure { /** * The bounds of the triangle figure. */ private Rectangle2D.Double rectangle; /** Creates a new instance. */ public TriangleFigure() { this(0, 0, 0, 0); } public TriangleFigure(Orientation direction) { this(0, 0, 0, 0, direction); } public TriangleFigure(double x, double y, double width, double height) { this(x, y, width, height, Orientation.NORTH); } public TriangleFigure(double x, double y, double width, double height, Orientation direction) { rectangle = new Rectangle2D.Double(x, y, width, height); /* setFillColor(Color.white); setStrokeColor(Color.black); */ ORIENTATION.basicSet(this, direction); } // DRAWING // SHAPE AND BOUNDS // ATTRIBUTES // EDITING // CONNECTING public Connector findConnector(Point2D.Double p, ConnectionFigure prototype) { return new ChopTriangleConnector(this); } public Connector findCompatibleConnector(Connector c, boolean isStartConnector) { return new ChopTriangleConnector(this); } /** * Returns the Figures connector for the specified location. * By default a ChopDiamondConnector is returned. * @see ChopDiamondConnector *//* public Connector findConnector(Point2D.Double p, ConnectionFigure prototype) { return new ChopTriangleConnector(this); } public Connector findCompatibleConnector(Connector c, boolean isStart) { return new ChopTriangleConnector(this); }*/ // COMPOSITE FIGURES // CLONING // EVENT HANDLING public Rectangle2D.Double getBounds() { Rectangle2D.Double bounds = (Rectangle2D.Double) rectangle.clone(); return bounds; } protected void drawFill(Graphics2D g) { Rectangle2D.Double r = (Rectangle2D.Double) rectangle.clone(); Shape triangle = getBezierPath(); double grow = AttributeKeys.getPerpendicularFillGrowth(this); if (grow != 0d) { GrowStroke gs = new GrowStroke((float) grow, (float) (AttributeKeys.getStrokeTotalWidth(this) * STROKE_MITER_LIMIT.get(this)) ); triangle = gs.createStrokedShape(triangle); } g.fill(triangle); } protected void drawStroke(Graphics2D g) { Shape triangle = getBezierPath(); double grow = AttributeKeys.getPerpendicularDrawGrowth(this); if (grow != 0d) { GrowStroke gs = new GrowStroke((float) grow, (float) (AttributeKeys.getStrokeTotalWidth(this) * STROKE_MITER_LIMIT.get(this)) ); triangle = gs.createStrokedShape(triangle); } g.draw(triangle); } public Collection<Handle> createHandles(int detailLevel) { LinkedList<Handle> handles = (LinkedList<Handle>) super.createHandles(detailLevel); if (detailLevel == 0) { handles.add(new TriangleRotationHandler(this)); } return handles; } public BezierPath getBezierPath() { Rectangle2D.Double r = (Rectangle2D.Double) rectangle.clone(); BezierPath triangle = new BezierPath(); switch (ORIENTATION.get(this)) { case NORTH : default : triangle.moveTo((float) (r.x + r.width / 2), (float) r.y); triangle.lineTo((float) (r.x + r.width), (float) (r.y + r.height)); triangle.lineTo((float) r.x, (float) (r.y + r.height)); break; case NORTH_EAST : triangle.moveTo((float) (r.x), (float) r.y); triangle.lineTo((float) (r.x + r.width), (float) (r.y)); triangle.lineTo((float) (r.x + r.width), (float) (r.y + r.height)); break; case EAST : triangle.moveTo((float) (r.x), (float) (r.y)); triangle.lineTo((float) (r.x + r.width), (float) (r.y + r.height / 2d)); triangle.lineTo((float) r.x, (float) (r.y + r.height)); break; case SOUTH_EAST : triangle.moveTo((float) (r.x + r.width), (float) (r.y)); triangle.lineTo((float) (r.x + r.width), (float) (r.y + r.height)); triangle.lineTo((float) (r.x), (float) (r.y + r.height)); break; case SOUTH : triangle.moveTo((float) (r.x + r.width / 2), (float) (r.y + r.height)); triangle.lineTo((float) r.x, (float) r.y); triangle.lineTo((float) (r.x + r.width), (float) r.y); break; case SOUTH_WEST : triangle.moveTo((float) (r.x + r.width), (float) (r.y + r.height)); triangle.lineTo((float) (r.x), (float) (r.y + r.height)); triangle.lineTo((float) (r.x), (float) (r.y)); break; case WEST : triangle.moveTo((float) (r.x), (float) (r.y + r.height / 2)); triangle.lineTo((float) (r.x + r.width), (float) (r.y )); triangle.lineTo((float) (r.x + r.width), (float) (r.y + r.height)); break; case NORTH_WEST : triangle.moveTo((float) (r.x), (float) (r.y + r.height)); triangle.lineTo((float) (r.x), (float) (r.y)); triangle.lineTo((float) (r.x + r.width), (float) (r.y)); break; } triangle.setClosed(true); return triangle; } /** * Checks if a Point2D.Double is inside the figure. */ public boolean contains(Point2D.Double p) { Shape triangle = getBezierPath(); double grow = AttributeKeys.getPerpendicularHitGrowth(this); if (grow != 0d) { GrowStroke gs = new GrowStroke((float) grow, (float) (AttributeKeys.getStrokeTotalWidth(this) * STROKE_MITER_LIMIT.get(this)) ); triangle =gs.createStrokedShape(triangle); } return triangle.contains(p); } public void setBounds(Point2D.Double anchor, Point2D.Double lead) { rectangle.x = Math.min(anchor.x, lead.x); rectangle.y = Math.min(anchor.y , lead.y); rectangle.width = Math.max(0.1, Math.abs(lead.x - anchor.x)); rectangle.height = Math.max(0.1, Math.abs(lead.y - anchor.y)); } public Rectangle2D.Double getDrawingArea() { double totalStrokeWidth = AttributeKeys.getStrokeTotalWidth(this); double width = 0d; if (STROKE_COLOR.get(this) != null) { switch (STROKE_PLACEMENT.get(this)) { case INSIDE : width = 0d; break; case OUTSIDE : if (STROKE_JOIN.get(this) == BasicStroke.JOIN_MITER) { width = totalStrokeWidth * STROKE_MITER_LIMIT.get(this); } else { width = totalStrokeWidth; } break; case CENTER : if (STROKE_JOIN.get(this) == BasicStroke.JOIN_MITER) { width = totalStrokeWidth / 2d * STROKE_MITER_LIMIT.get(this); } else { width = totalStrokeWidth / 2d; } break; } } width++; Rectangle2D.Double r = getBounds(); Geom.grow(r, width, width); return r; } public Point2D.Double chop(Point2D.Double p) { Shape triangle = getBezierPath(); double grow = AttributeKeys.getPerpendicularHitGrowth(this); if (grow != 0d) { GrowStroke gs = new GrowStroke((float) grow, (float) (AttributeKeys.getStrokeTotalWidth(this) * STROKE_MITER_LIMIT.get(this)) ); triangle =gs.createStrokedShape(triangle); } return Geom.chop(triangle, p); } /** * Moves the Figure to a new location. * @param tx the transformation matrix. */ public void transform(AffineTransform tx) { Point2D.Double anchor = getStartPoint(); Point2D.Double lead = getEndPoint(); setBounds( (Point2D.Double) tx.transform(anchor, anchor), (Point2D.Double) tx.transform(lead, lead) ); } public TriangleFigure clone() { TriangleFigure that = (TriangleFigure) super.clone(); that.rectangle = (Rectangle2D.Double) this.rectangle.clone(); return that; } public void restoreTransformTo(Object geometry) { Rectangle2D.Double r = (Rectangle2D.Double) geometry; rectangle.x = r.x; rectangle.y = r.y; rectangle.width = r.width; rectangle.height = r.height; } public Object getTransformRestoreData() { return rectangle.clone(); } }