1   /****************************************************************************
2    **
3    ** This file is part of yFiles-2.9. 
4    ** 
5    ** yWorks proprietary/confidential. Use is subject to license terms.
6    **
7    ** Redistribution of this file or of an unauthorized byte-code version
8    ** of this file is strictly forbidden.
9    **
10   ** Copyright (c) 2000-2011 by yWorks GmbH, Vor dem Kreuzberg 28, 
11   ** 72070 Tuebingen, Germany. All rights reserved.
12   **
13   ***************************************************************************/
14  package demo.view.entityrelationship.painters;
15  
16  import demo.view.flowchart.painters.FlowchartDecisionPainter;
17  import y.view.GenericNodeRealizer;
18  import y.view.LineType;
19  import y.view.NodeRealizer;
20  
21  import java.awt.geom.GeneralPath;
22  
23  /**
24   * This is a painter to display a relationship node for entity relationship diagrams (ERD).
25   *
26   * A relationship is represented by a diamond shape. It is possible to display a weak
27   * relationship by drawing a double border.
28   */
29  public class ErdRelationshipNodePainter extends FlowchartDecisionPainter {
30    private static final double EPSILON = 1.0e-12;
31  
32    /** The border of the diamond shaped node */
33    private GeneralPath path;
34  
35    /**
36     * Calculates the interior shape for the specified node.
37     * @param context The node context
38     */
39    protected void updateInsideShape( final NodeRealizer context ) {
40      if (hasDoubleBorder(context)) {
41        if (path == null) {
42          path = new GeneralPath();
43        }
44        innerShape = path;
45        updateInsideShapeImpl(context);
46      } else {
47        if (path != null) {
48          path.reset();
49        }
50        innerShape = null;
51      }
52    }
53  
54    /**
55     * Calculates the path of the border segments for the interior shape.
56     * @param context The node context
57     */
58    private void updateInsideShapeImpl( final NodeRealizer context ) {
59      final GeneralPath shapePath = (GeneralPath) getInnerShape();
60      shapePath.reset();
61  
62      final double width = context.getWidth();
63      final double height = context.getHeight();
64      if (Math.abs(width) < EPSILON || Math.abs(height) < EPSILON) {
65        return;
66      }
67  
68      final double x = context.getX();
69      final double y = context.getY();
70  
71      final LineType lineType = context.getLineType();
72      final float lw = lineType.getLineWidth();
73  
74      final double offset = 2 + lw;
75  
76      final double w2 = width * 0.5;
77      final double h2 = height * 0.5;
78  
79      // slope vector  s = (w / 2,   h / 2)
80      // normal vector n = (h / 2, - w / 2)
81      // length of normal vector
82      final double nl = Math.sqrt(w2 * w2 + h2 * h2);
83  
84      // origin of line parallel to 0 + t*s with distance offset
85      final double ox =  offset * h2 / nl;
86      final double oy = -offset * w2 / nl;
87  
88      // intersection of line o + t*s with y == 0
89      final double ix = ox + (-oy / h2) * w2;
90      // intersection of line o + t*s with x == w / 2
91      final double iy = oy + (1 -ox / w2) * h2;
92  
93      final double offsetX = ix;
94      final double offsetY = h2 - iy;
95  
96      if (offsetX + lw < w2 && offsetY + lw < h2) {
97        shapePath.moveTo((float)(x + w2), (float)(y + offsetY));
98        shapePath.lineTo((float)(x + width - offsetX), (float)(y + h2));
99        shapePath.lineTo((float)(x + w2), (float)(y + height - offsetY));
100       shapePath.lineTo((float)(x + offsetX) , (float)(y + h2));
101       shapePath.closePath();
102     }
103   }
104 
105   /**
106    * Tests if the style property {@link ErdRealizerFactory#DOUBLE_BORDER} is set for the context realizer.
107    * @param context The context node
108    * @return <code>true</code>, if style property border is set, <code>false</code> otherwise
109    */
110   private boolean hasDoubleBorder(NodeRealizer context) {
111     return Boolean.TRUE.equals(((GenericNodeRealizer) context).getStyleProperty(ErdRealizerFactory.DOUBLE_BORDER));
112   }
113 
114 }
115