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.isometry;
29  
30  import y.view.AbstractCustomNodePainter;
31  import y.view.GenericNodeRealizer;
32  import y.view.NodeRealizer;
33  
34  import java.awt.Color;
35  import java.awt.Graphics2D;
36  import java.awt.Shape;
37  import java.awt.geom.GeneralPath;
38  import java.awt.geom.Line2D;
39  
40  /**
41   * A painter that paints a node as block in an isometric fashion.
42   */
43  class IsometryNodePainter extends AbstractCustomNodePainter implements GenericNodeRealizer.ContainsTest {
44  
45    protected void paintNode(final NodeRealizer context, final Graphics2D graphics, final boolean sloppy) {
46      final IsometryData data = (IsometryData) ((GenericNodeRealizer) context).getUserData();
47      final double[] corners = new double[16];
48      calculateCorners(context, corners);
49  
50      // fill faces
51      if (initializeFill(context, graphics)) {
52        final GeneralPath path = new GeneralPath();
53        path.moveTo((float) corners[IsometryData.C4_X], (float) corners[IsometryData.C4_Y]);
54        path.lineTo((float) corners[IsometryData.C5_X], (float) corners[IsometryData.C5_Y]);
55        path.lineTo((float) corners[IsometryData.C6_X], (float) corners[IsometryData.C6_Y]);
56        path.lineTo((float) corners[IsometryData.C7_X], (float) corners[IsometryData.C7_Y]);
57        path.closePath();
58        graphics.fill(path);
59        path.reset();
60  
61        if (data.getHeight() > 0) {
62          path.moveTo((float) corners[IsometryData.C0_X], (float) corners[IsometryData.C0_Y]);
63          path.lineTo((float) corners[IsometryData.C4_X], (float) corners[IsometryData.C4_Y]);
64          path.lineTo((float) corners[IsometryData.C7_X], (float) corners[IsometryData.C7_Y]);
65          path.lineTo((float) corners[IsometryData.C3_X], (float) corners[IsometryData.C3_Y]);
66          path.closePath();
67          Color color = getFillColor(context, false).darker();
68          graphics.setColor(color);
69          graphics.fill(path);
70          path.reset();
71  
72          path.moveTo((float) corners[IsometryData.C3_X], (float) corners[IsometryData.C3_Y]);
73          path.lineTo((float) corners[IsometryData.C7_X], (float) corners[IsometryData.C7_Y]);
74          path.lineTo((float) corners[IsometryData.C6_X], (float) corners[IsometryData.C6_Y]);
75          path.lineTo((float) corners[IsometryData.C2_X], (float) corners[IsometryData.C2_Y]);
76          path.closePath();
77          graphics.setColor(color.darker());
78          graphics.fill(path);
79        }
80      }
81  
82      // draw lines
83      if (initializeLine(context, graphics)) {
84        final Shape outline = createOutline(corners);
85        graphics.draw(outline);
86        if (data.getHeight() > 0) {
87          final Line2D line = new Line2D.Double();
88          line.setLine(corners[IsometryData.C7_X], corners[IsometryData.C7_Y],
89              corners[IsometryData.C4_X], corners[IsometryData.C4_Y]);
90          graphics.draw(line);
91          line.setLine(corners[IsometryData.C7_X], corners[IsometryData.C7_Y],
92              corners[IsometryData.C3_X], corners[IsometryData.C3_Y]);
93          graphics.draw(line);
94          line.setLine(corners[IsometryData.C7_X], corners[IsometryData.C7_Y],
95              corners[IsometryData.C6_X], corners[IsometryData.C6_Y]);
96          graphics.draw(line);
97        }
98      }
99    }
100 
101   public boolean contains(final NodeRealizer context, final double x, final double y) {
102     final double[] corners = new double[16];
103     calculateCorners(context, corners);
104     final Shape outline = createOutline(corners);
105     return outline.contains(x, y);
106   }
107 
108   /**
109    * Created the outline shape out of the corners of the node in the view space.
110    *
111    * @see #calculateCorners(y.view.NodeRealizer, double[])
112    */
113   private Shape createOutline(final double[] corners) {
114     final GeneralPath outline = new GeneralPath();
115     outline.moveTo((float) corners[IsometryData.C0_X], (float) corners[IsometryData.C0_Y]);
116     outline.lineTo((float) corners[IsometryData.C3_X], (float) corners[IsometryData.C3_Y]);
117     outline.lineTo((float) corners[IsometryData.C2_X], (float) corners[IsometryData.C2_Y]);
118     outline.lineTo((float) corners[IsometryData.C6_X], (float) corners[IsometryData.C6_Y]);
119     outline.lineTo((float) corners[IsometryData.C5_X], (float) corners[IsometryData.C5_Y]);
120     outline.lineTo((float) corners[IsometryData.C4_X], (float) corners[IsometryData.C4_Y]);
121     outline.closePath();
122     return outline;
123   }
124 
125   /**
126    * Calculates the corners of the node in the view space. The size of the node is stored in its {@link IsometryData
127    * user data}. This method transforms the corners into the view space and moves them to the location of the realizer.
128    */
129   private void calculateCorners(final NodeRealizer context, final double[] corners) {
130     if (context instanceof GenericNodeRealizer) {
131       final IsometryData data = (IsometryData) ((GenericNodeRealizer) context).getUserData();
132       data.calculateCorners(corners);
133       IsometryData.moveTo(context.getX(), context.getY(), corners);
134     }
135   }
136 }
137