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 java.awt.geom.Rectangle2D;
31  
32  /**
33   * The class stores the height, width and depth of a solid figure. This data is used to get its bounds in the view space
34   * and the bounds of its base area used in the layout space.
35   */
36  public class IsometryData implements Cloneable {
37    // Matrix to transform points from the layout space into the view space.
38    public static final double M_TO_VIEW_11 = Math.sqrt(3) * 0.5;
39    public static final double M_TO_VIEW_12 = M_TO_VIEW_11;
40    public static final double M_TO_VIEW_21 = -0.5;
41    public static final double M_TO_VIEW_22 = 0.5;
42  
43    // Matrix to transform points from the view space into the layout space.
44    public static final double M_TO_LAYOUT_11 = 1 / Math.sqrt(3);
45    public static final double M_TO_LAYOUT_12 = -1;
46    public static final double M_TO_LAYOUT_21 = M_TO_LAYOUT_11;
47    public static final double M_TO_LAYOUT_22 = -M_TO_LAYOUT_12;
48  
49    // Indices for the corners of the bounding box.
50    public static final int C0_X = 0; // lower left
51    public static final int C0_Y = 1;
52    public static final int C1_X = 2; // lower front
53    public static final int C1_Y = 3;
54    public static final int C2_X = 4; // lower right
55    public static final int C2_Y = 5;
56    public static final int C3_X = 6; // lower back
57    public static final int C3_Y = 7;
58    public static final int C4_X = 8; // upper left
59    public static final int C4_Y = 9;
60    public static final int C5_X = 10; // upper front
61    public static final int C5_Y = 11;
62    public static final int C6_X = 12; // upper right
63    public static final int C6_Y = 13;
64    public static final int C7_X = 14; // upper back
65    public static final int C7_Y = 15;
66  
67    private double width;
68    private double height;
69    private double depth;
70  
71    private boolean isHorizontal;
72  
73    /**
74     * Creates an instance with the given dimensions.
75     */
76    public IsometryData(final double width, final double depth, final double height, final boolean isHorizontal) {
77      this.width = width;
78      this.depth = depth;
79      this.height = height;
80      this.isHorizontal = isHorizontal;
81    }
82  
83    /**
84     * Returns the width of the solid figure.
85     */
86    public double getWidth() {
87      return width;
88    }
89  
90    /**
91     * Sets the width of the solid figure.
92     */
93    public void setWidth(final double width) {
94      this.width = width;
95    }
96  
97    /**
98     * Returns the depth of the solid figure.
99     */
100   public double getDepth() {
101     return depth;
102   }
103 
104   /**
105    * Sets the depth of the solid figure.
106    */
107   public void setDepth(final double depth) {
108     this.depth = depth;
109   }
110 
111   /**
112    * Returns the height of the solid figure.
113    */
114   public double getHeight() {
115     return height;
116   }
117 
118   /**
119    * Sets the height of the solid figure.
120    */
121   public void setHeight(final double height) {
122     this.height = height;
123   }
124 
125   /**
126    * Determines whether or no the base of the solid figure is horizontal in layout space.
127    * This is important for labels that may be rotated during layout.
128    */
129   public boolean isHorizontal() {
130     return isHorizontal;
131   }
132 
133   /**
134    * Specifies whether or no the base of the solid figure is horizontal in layout space.
135    * This is important for labels that may be rotated during layout.
136    */
137   public void setHorizontal(boolean horizontal) {
138     isHorizontal = horizontal;
139   }
140 
141   /**
142    * Calculates the bounds of the solid figure in the view space.
143    *
144    * @param bounds the calculated bounds
145    */
146   public void calculateViewBounds(final Rectangle2D bounds) {
147     final double[] corners = new double[16];
148     calculateCorners(corners);
149     calculateViewBounds(corners, bounds);
150   }
151 
152   /**
153    * Calculates the bounds of the solid figure in the view space.
154    *
155    * @param corners the corners of the projection of the bounds of solid figure into the view space
156    * @param bounds  the calculated bounds
157    */
158   public static void calculateViewBounds(final double[] corners, final Rectangle2D bounds) {
159     double minX = corners[C0_X];
160     double minY = corners[C0_Y];
161     double maxX = corners[C0_X];
162     double maxY = corners[C0_Y];
163     for (int i = 2; i < corners.length; i += 2) {
164       minX = Math.min(minX, corners[i]);
165       minY = Math.min(minY, corners[i + 1]);
166       maxX = Math.max(maxX, corners[i]);
167       maxY = Math.max(maxY, corners[i + 1]);
168     }
169     bounds.setFrame(minX, minY, maxX - minX, maxY - minY);
170   }
171 
172   /**
173    * Calculates the corners of the projection of the bounds of solid figure into the view space.
174    *
175    * @param corners the calculated corners.
176    */
177   public void calculateCorners(final double[] corners) {
178     corners[C0_X] = 0;
179     corners[C0_Y] = 0;
180 
181     corners[C1_X] = toViewX(getWidth(), 0);
182     corners[C1_Y] = toViewY(getWidth(), 0);
183 
184     corners[C2_X] = toViewX(getWidth(), getDepth());
185     corners[C2_Y] = toViewY(getWidth(), getDepth());
186 
187     corners[C3_X] = toViewX(0, getDepth());
188     corners[C3_Y] = toViewY(0, getDepth());
189 
190     for (int i = 0; i < 8; i += 2) {
191       corners[i + 8] = corners[i];
192       corners[i + 9] = corners[i + 1] - getHeight();
193     }
194   }
195 
196   /**
197    * Transforms the given point from the layout space into the view space.
198    *
199    * @param layoutX x-coordinate in layout space
200    * @param layoutY y-coordinate in layout space
201    * @return x-coordinate in view space
202    */
203   static double toViewX(final double layoutX, final double layoutY) {
204     return M_TO_VIEW_11 * layoutX + M_TO_VIEW_12 * layoutY;
205   }
206 
207   /**
208    * Transforms the given point from the layout space into the view space.
209    *
210    * @param layoutX x-coordinate in layout space
211    * @param layoutY y-coordinate in layout space
212    * @return y-coordinate in view space
213    */
214   static double toViewY(final double layoutX, final double layoutY) {
215     return M_TO_VIEW_21 * layoutX + M_TO_VIEW_22 * layoutY;
216   }
217 
218   /**
219    * Transforms the given point from the view space into the layout space.
220    *
221    * @param viewX x-coordinate in view space
222    * @param viewY y-coordinate in view space
223    * @return x-coordinate in layout space
224    */
225   static double toLayoutX(final double viewX, final double viewY) {
226     return M_TO_LAYOUT_11 * viewX + M_TO_LAYOUT_12 * viewY;
227   }
228 
229   /**
230    * Transforms the given point from the view space into the layout space.
231    *
232    * @param viewX x-coordinate in view space
233    * @param viewY y-coordinate in view space
234    * @return y-coordinate in layout space
235    */
236   static double toLayoutY(final double viewX, final double viewY) {
237     return M_TO_LAYOUT_21 * viewX + M_TO_LAYOUT_22 * viewY;
238   }
239 
240   /**
241    * Translates the given corner to the given location, so that the upper left location of the bounds of the given
242    * corners is on the given location.
243    *
244    * @param x       x-coordinate of the location where the corners should be moved to
245    * @param y       y-coordinate of the location where the corners should be moved to
246    * @param corners corners to be moved
247    */
248   public static void moveTo(final double x, final double y, final double[] corners) {
249     // Calculate the upper left location of the bounds of the given corners.
250     double minX = corners[C0_X];
251     double minY = corners[C0_Y];
252     for (int i = 2; i < corners.length; i += 2) {
253       minX = Math.min(minX, corners[i]);
254       minY = Math.min(minY, corners[i + 1]);
255     }
256 
257     // Move the corners to the given location.
258     final double dx = x - minX;
259     final double dy = y - minY;
260     for (int i = 0; i < corners.length; i += 2) {
261       corners[i] += dx;
262       corners[i + 1] += dy;
263     }
264   }
265 
266   public Object clone () throws CloneNotSupportedException {
267     return super.clone();
268   }
269 }
270