001: //THIS SOFTWARE IS PROVIDED BY SOFTARIS PTY.LTD. AND OTHER METABOSS
002: //CONTRIBUTORS ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
003: //BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
004: //FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SOFTARIS PTY.LTD.
005: //OR OTHER METABOSS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
006: //INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
007: //LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
008: //OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
009: //LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
010: //NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
011: //EVEN IF SOFTARIS PTY.LTD. OR OTHER METABOSS CONTRIBUTORS ARE ADVISED OF THE
012: //POSSIBILITY OF SUCH DAMAGE.
013: //
014: //Copyright 2000-2005 © Softaris Pty.Ltd. All Rights Reserved.
015: package com.metaboss.applications.designstudio.dependencyview;
016:
017: import java.awt.Graphics2D;
018: import java.awt.Polygon;
019: import java.awt.Shape;
020: import java.awt.geom.AffineTransform;
021: import java.awt.geom.Point2D;
022: import java.awt.geom.Rectangle2D;
023:
024: import edu.berkeley.guir.prefuse.EdgeItem;
025: import edu.berkeley.guir.prefuse.VisualItem;
026: import edu.berkeley.guir.prefuse.render.DefaultEdgeRenderer;
027: import edu.berkeley.guir.prefuse.util.GeometryLib;
028:
029: /**
030: * Default edge renderer that draws edges as lines connecting nodes. Both
031: * straight and curved (Bezier) lines are supported.
032: *
033: * @version 1.0
034: * @author <a href="http://jheer.org">Jeffrey Heer</a> prefuse(AT)jheer.org
035: */
036: public class SpecialEdgeRenderer extends DefaultEdgeRenderer {
037: // The Polygon defining diamond used in UML diagrams
038: private Polygon mUmlDiamond = new Polygon(new int[] { 0, -4, 0, 4,
039: 0 }, new int[] { 16, 8, 0, 8, 16 }, 5);
040: protected AffineTransform mUmlDiamondTransform = new AffineTransform();
041:
042: /**
043: * @see edu.berkeley.guir.prefuse.render.Renderer#render(java.awt.Graphics2D, edu.berkeley.guir.prefuse.VisualItem)
044: */
045: public void render(Graphics2D g, VisualItem item) {
046: super .render(g, item);
047: // Draw arrow always
048: EdgeItem lEdgeItem = (EdgeItem) item;
049: SpecialEdge lEdge = (SpecialEdge) lEdgeItem.getEntity();
050: int width;
051:
052: String stype = (String) item.getVizAttribute(EDGE_TYPE);
053: int type = m_edgeType;
054: if (stype != null) {
055: try {
056: type = Integer.parseInt(stype);
057: } catch (Exception ex) {
058: ex.printStackTrace();
059: }
060: }
061: Point2D pLineStart = null;
062: Point2D pLineEnd = null;
063: switch (type) {
064: case EDGE_TYPE_LINE:
065: pLineStart = m_tmpPoints[0];
066: pLineEnd = m_tmpPoints[1];
067: width = m_width;
068: break;
069: case EDGE_TYPE_CURVE:
070: pLineStart = m_ctrlPoints[1];
071: pLineEnd = m_tmpPoints[1];
072: width = 1;
073: break;
074: default:
075: throw new IllegalStateException("Unknown edge type.");
076: }
077: VisualItem lFromNode = (VisualItem) lEdgeItem.getFirstNode();
078: Rectangle2D lFromNodeBounds = lFromNode.getBounds();
079:
080: VisualItem lToNode = (VisualItem) lEdgeItem.getSecondNode();
081: Rectangle2D lToNodeBounds = lToNode.getBounds();
082:
083: // Always draw the head
084: {
085: int lIntersectsWithToNode = GeometryLib
086: .intersectLineRectangle(pLineStart, pLineEnd,
087: lToNodeBounds, m_isctPoints);
088: Point2D pActualLineEnd = (lIntersectsWithToNode == 0) ? pLineEnd
089: : m_isctPoints[0];
090:
091: AffineTransform at = getArrowTrans(pLineStart,
092: pActualLineEnd, width);
093: Shape arrowHead = at.createTransformedShape(m_arrowHead);
094: g.setPaint(item.getFillColor());
095: g.fill(arrowHead);
096: }
097: // We also may need to draw containment
098: if (lEdge.isContainment()) {
099: int lIntersectsWithFromNode = GeometryLib
100: .intersectLineRectangle(pLineStart, pLineEnd,
101: lFromNodeBounds, m_isctPoints);
102: Point2D pActualLineStart = (lIntersectsWithFromNode == 0) ? pLineStart
103: : m_isctPoints[0];
104:
105: AffineTransform dt = getUmlDiamondTrans(pActualLineStart,
106: pLineEnd, width);
107: Shape lUmlDiamond = dt.createTransformedShape(mUmlDiamond);
108: g.setPaint(item.getFillColor());
109: g.fill(lUmlDiamond);
110: }
111: }
112:
113: /**
114: * Returns an affine transformation that maps the diamond shape
115: * to the position and orientation specified by the provided
116: * line segment end points.
117: */
118: protected AffineTransform getUmlDiamondTrans(Point2D pPoint1,
119: Point2D pPoint2, int width) {
120: mUmlDiamondTransform.setToTranslation(pPoint1.getX(), pPoint1
121: .getY());
122: mUmlDiamondTransform.rotate(-HALF_PI
123: + Math.atan2(pPoint2.getY() - pPoint1.getY(), pPoint2
124: .getX()
125: - pPoint1.getX()));
126: if (width > 1) {
127: double scalar = (2.0 * (width - 1)) / 4 + 1;
128: mUmlDiamondTransform.scale(scalar, scalar);
129: }
130: return mUmlDiamondTransform;
131: }
132: }
|