1   /****************************************************************************
2    * This demo file is part of yFiles for Java 2.14.
3    * Copyright (c) 2000-2017 by yWorks GmbH, Vor dem Kreuzberg 28,
4    * 72070 Tuebingen, Germany. All rights reserved.
5    * 
6    * yFiles demo files exhibit yFiles for Java functionalities. Any redistribution
7    * of demo files in source code or binary form, with or without
8    * modification, is not permitted.
9    * 
10   * Owners of a valid software license for a yFiles for Java version that this
11   * demo is shipped with are allowed to use the demo source code as basis
12   * for their own yFiles for Java powered applications. Use of such programs is
13   * governed by the rights and conditions as set out in the yFiles for Java
14   * license agreement.
15   * 
16   * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESS OR IMPLIED
17   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18   * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
19   * NO EVENT SHALL yWorks BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
21   * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22   * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
23   * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24   * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25   * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26   *
27   ***************************************************************************/
28  package demo.view.entityrelationship.painters;
29  
30  import demo.view.flowchart.painters.FlowchartDecisionPainter;
31  import y.view.GenericNodeRealizer;
32  import y.view.LineType;
33  import y.view.NodeRealizer;
34  
35  import java.awt.Shape;
36  import java.awt.geom.GeneralPath;
37  
38  /**
39   * This is a painter to display a relationship node for entity relationship diagrams (ERD).
40   *
41   * A relationship is represented by a diamond shape. It is possible to display a weak
42   * relationship by drawing a double border.
43   */
44  public class ErdRelationshipNodePainter extends FlowchartDecisionPainter {
45    private static final double EPSILON = 1.0e-12;
46  
47    /**
48     * Calculates the interior shape for the specified node.
49     * @param context The node context
50     */
51    protected Shape newDecoration( final NodeRealizer context ) {
52      if (!hasDoubleBorder(context)) {
53        return null;
54      }
55  
56      final double width = context.getWidth();
57      final double height = context.getHeight();
58      if (Math.abs(width) < EPSILON || Math.abs(height) < EPSILON) {
59        return null;
60      }
61  
62      final double x = context.getX();
63      final double y = context.getY();
64  
65      final LineType lineType = context.getLineType();
66      final float lw = lineType.getLineWidth();
67  
68      final double offset = 2 + lw;
69  
70      final double w2 = width * 0.5;
71      final double h2 = height * 0.5;
72  
73      // slope vector  s = (w / 2,   h / 2)
74      // normal vector n = (h / 2, - w / 2)
75      // length of normal vector
76      final double nl = Math.sqrt(w2 * w2 + h2 * h2);
77  
78      // origin of line parallel to 0 + t*s with distance offset
79      final double ox =  offset * h2 / nl;
80      final double oy = -offset * w2 / nl;
81  
82      // intersection of line o + t*s with y == 0
83      final double ix = ox + (-oy / h2) * w2;
84      // intersection of line o + t*s with x == w / 2
85      final double iy = oy + (1 -ox / w2) * h2;
86  
87      final double offsetX = ix;
88      final double offsetY = h2 - iy;
89  
90      if (offsetX + lw < w2 && offsetY + lw < h2) {
91        final GeneralPath shapePath = new GeneralPath();
92        shapePath.moveTo((float)(x + w2), (float)(y + offsetY));
93        shapePath.lineTo((float)(x + width - offsetX), (float)(y + h2));
94        shapePath.lineTo((float)(x + w2), (float)(y + height - offsetY));
95        shapePath.lineTo((float)(x + offsetX) , (float)(y + h2));
96        shapePath.closePath();
97        return shapePath;
98      } else {
99        return null;
100     }
101   }
102 
103   /**
104    * Tests if the style property {@link ErdRealizerFactory#DOUBLE_BORDER} is set for the context realizer.
105    * @param context The context node
106    * @return <code>true</code>, if style property border is set, <code>false</code> otherwise
107    */
108   protected boolean hasDoubleBorder(NodeRealizer context) {
109     return Boolean.TRUE.equals(((GenericNodeRealizer) context).getStyleProperty(ErdRealizerFactory.DOUBLE_BORDER));
110   }
111 }
112