View Javadoc
1   /*
2    * ObjectLab, http://www.objectlab.co.uk/open is supporting JTreeMap.
3    *
4    * Based in London, we are world leaders in the design and development
5    * of bespoke applications for the securities financing markets.
6    *
7    * <a href="http://www.objectlab.co.uk/open">Click here to learn more</a>
8    *           ___  _     _           _   _          _
9    *          / _ \| |__ (_) ___  ___| |_| |    __ _| |__
10   *         | | | | '_ \| |/ _ \/ __| __| |   / _` | '_ \
11   *         | |_| | |_) | |  __/ (__| |_| |__| (_| | |_) |
12   *          \___/|_.__// |\___|\___|\__|_____\__,_|_.__/
13   *                   |__/
14   *
15   *                     www.ObjectLab.co.uk
16   *
17   * $Id$
18   *
19   * Copyright 2006 the original author or authors.
20   *
21   * Licensed under the Apache License, Version 2.0 (the "License"); you may not
22   * use this file except in compliance with the License. You may obtain a copy of
23   * the License at
24   *
25   * http://www.apache.org/licenses/LICENSE-2.0
26   *
27   * Unless required by applicable law or agreed to in writing, software
28   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
29   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
30   * License for the specific language governing permissions and limitations under
31   * the License.
32   */
33  package net.sf.jtreemap.swing;
34  
35  import java.util.ArrayList;
36  import java.util.List;
37  
38  /**
39   * The Squarified split strategy
40   *
41   * @author Laurent DUTHEIL
42   */
43  public class SplitSquarified extends SplitStrategy {
44      private static final long serialVersionUID = 1711898915283018450L;
45      private int w1;
46      private int h1;
47      private int x;
48      private int y;
49      private int w;
50      private int h;
51      private int x2;
52      private int y2;
53      private int w2;
54      private int h2;
55  
56      @Override
57      public void splitElements(final List<TreeMapNode> v, final List<TreeMapNode> v1, final List<TreeMapNode> v2) {
58          int mid = 0;
59          final double weight0 = sumWeight(v);
60          final double a = v.get(mid).getWeight() / weight0;
61          double b = a;
62  
63          if (this.w < this.h) {
64              // height/width
65              while (mid < v.size()) {
66                  final double aspect = normAspect(this.h, this.w, a, b);
67                  final double q = v.get(mid).getWeight() / weight0;
68                  if (normAspect(this.h, this.w, a, b + q) > aspect) {
69                      break;
70                  }
71                  mid++;
72                  b += q;
73              }
74              int i = 0;
75              for (; i <= mid && i < v.size(); i++) {
76                  v1.add(v.get(i));
77              }
78              for (; i < v.size(); i++) {
79                  v2.add(v.get(i));
80              }
81              this.h1 = (int) Math.round(this.h * b);
82              this.w1 = this.w;
83              this.x2 = this.x;
84              this.y2 = (int) Math.round(this.y + this.h * b);
85              this.w2 = this.w;
86              this.h2 = this.h - this.h1;
87          } else {
88              widthSameOrBiggerThanHeight(v, v1, v2, mid, weight0, a, b);
89          }
90      }
91  
92      private void widthSameOrBiggerThanHeight(final List<TreeMapNode> v, final List<TreeMapNode> v1, final List<TreeMapNode> v2, int mid,
93              final double weight0, final double a, double b) {
94          // width/height
95          while (mid < v.size()) {
96              final double aspect = normAspect(this.w, this.h, a, b);
97              final double q = v.get(mid).getWeight() / weight0;
98              if (normAspect(this.w, this.h, a, b + q) > aspect) {
99                  break;
100             }
101             mid++;
102             b += q;
103         }
104         int i = 0;
105         for (; i <= mid && i < v.size(); i++) {
106             v1.add(v.get(i));
107         }
108         for (; i < v.size(); i++) {
109             v2.add(v.get(i));
110         }
111         this.h1 = this.h;
112         this.w1 = (int) Math.round(this.w * b);
113         this.x2 = (int) Math.round(this.x + this.w * b);
114         this.y2 = this.y;
115         this.w2 = this.w - this.w1;
116         this.h2 = this.h;
117     }
118 
119     /*
120      * (non-Javadoc)
121      *
122      * @see net.sf.jtreemap.swing.SplitStrategy#calculatePositionsRec(int, int,
123      *      int, int, double, java.util.List)
124      */
125     @Override
126     protected void calculatePositionsRec(final int x0, final int y0, final int w0, final int h0, final double weight0, final List<TreeMapNode> v) {
127         // 1. don't calculate if the area is too small,
128         if (w0 * h0 < 20) {
129             return;
130         }
131 
132         // 2. don't calculate if the candidates are too many to display
133         if (w0 * h0 < v.size()) {
134             return;
135         }
136 
137         final List<TreeMapNode> vClone = new ArrayList<>(v);
138 
139         sortList(vClone);
140 
141         if (vClone.size() <= 2) {
142             SplitBySlice.splitInSlice(x0, y0, w0, h0, vClone, sumWeight(vClone));
143             calculateChildren(vClone);
144         } else {
145             final List<TreeMapNode> v1 = new ArrayList<>();
146             final List<TreeMapNode> v2 = new ArrayList<>();
147             this.x = x0;
148             this.y = y0;
149             this.w = w0;
150             this.h = h0;
151             splitElements(vClone, v1, v2);
152             // before the recurence, we have to "save" the values for the 2nd
153             // list
154             final int prevX2 = this.x2;
155             final int prevY2 = this.y2;
156             final int prevW2 = this.w2;
157             final int prevH2 = this.h2;
158             SplitBySlice.splitInSlice(x0, y0, this.w1, this.h1, v1, sumWeight(v1));
159             calculateChildren(v1);
160             calculatePositionsRec(prevX2, prevY2, prevW2, prevH2, sumWeight(v2), v2);
161         }
162 
163     }
164 
165     private double aspect(final double big, final double small, final double a, final double b) {
166         return big * b / (small * a / b);
167     }
168 
169     /**
170      * Execute the recurence for the children of the elements of the list.<BR>
171      * Add also the borders if necessary
172      *
173      * @param v
174      *            List with the elements to calculate
175      */
176     private void calculateChildren(final List<TreeMapNode> v) {
177         for (final TreeMapNode node : v) {
178             if (node.isLeaf()) {
179                 node.setX(node.getX() + TreeMapNode.getBorder());
180                 node.setY(node.getY() + TreeMapNode.getBorder());
181                 int width = node.getWidth() - TreeMapNode.getBorder();
182                 if (width < 0) {
183                     width = 0;
184                 }
185                 int height = node.getHeight() - TreeMapNode.getBorder();
186                 if (height < 0) {
187                     height = 0;
188                 }
189                 node.setHeight(height);
190                 node.setWidth(width);
191             } else {
192                 calculateNonLeaf(node);
193             }
194         }
195     }
196 
197     private void calculateNonLeaf(final TreeMapNode node) {
198         // if this is not a leaf, calculation for the children
199         int bSub;
200         if (TreeMapNode.getBorder() > 1) {
201             bSub = 2;
202         } else if (TreeMapNode.getBorder() == 1) {
203             bSub = 1;
204         } else {
205             bSub = 0;
206         }
207 
208         int width = node.getWidth() - bSub;
209         if (width < 0) {
210             width = 0;
211         }
212         int height = node.getHeight() - bSub;
213         if (height < 0) {
214             height = 0;
215         }
216 
217         TreeMapNode.setBorder(TreeMapNode.getBorder() - bSub);
218         calculatePositionsRec(node.getX() + bSub, node.getY() + bSub, width, height, node.getWeight(), node.getChildren());
219         TreeMapNode.setBorder(TreeMapNode.getBorder() + bSub);
220     }
221 
222     private double normAspect(final double big, final double small, final double a, final double b) {
223         final double xCalc = aspect(big, small, a, b);
224         if (xCalc < 1) {
225             return 1 / xCalc;
226         }
227         return xCalc;
228     }
229 }
230 /*
231  *                 ObjectLab is supporing JTreeMap
232  *
233  * Based in London, we are world leaders in the design and development
234  * of bespoke applications for the securities financing markets.
235  *
236  * <a href="http://www.objectlab.co.uk/open">Click here to learn more about us</a>
237  *           ___  _     _           _   _          _
238  *          / _ \| |__ (_) ___  ___| |_| |    __ _| |__
239  *         | | | | '_ \| |/ _ \/ __| __| |   / _` | '_ \
240  *         | |_| | |_) | |  __/ (__| |_| |__| (_| | |_) |
241  *          \___/|_.__// |\___|\___|\__|_____\__,_|_.__/
242  *                   |__/
243  *
244  *                     www.ObjectLab.co.uk
245  */