View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  
20  package org.apache.myfaces.tobago.example.demo;
21  
22  import javax.swing.tree.DefaultMutableTreeNode;
23  import javax.swing.tree.TreeNode;
24  import java.io.Serializable;
25  import java.math.BigInteger;
26  import java.util.Enumeration;
27  
28  /**
29   * Builds a tree with the iterations of the <a href="http://en.wikipedia.org/wiki/Cantor_set">Cantor set</a>. The tree
30   * is infinitive, so it will be created on the fly.
31   */
32  public class CantorInterval extends DefaultMutableTreeNode {
33  
34    private final Fraction begin;
35    private final Fraction end;
36    private boolean initialized;
37  
38    public CantorInterval() {
39      begin = Fraction.ZERO;
40      end = Fraction.ONE;
41    }
42  
43    private CantorInterval(final Fraction begin, final Fraction end) {
44      this.begin = begin;
45      this.end = end;
46    }
47  
48    // init must be lazy, because the tree is infinite
49    private void init() {
50      if (!initialized) {
51        initialized = true; // add() will call getChildCount()!
52        final Fraction subtract = end.subtract(begin);
53        final Fraction multiply = subtract.multiply(Fraction.ONE_THIRD);
54        final Fraction oneThird = multiply.add(begin);
55        add(new CantorInterval(begin, oneThird));
56  
57        final Fraction twoThird = end.subtract(begin).multiply(Fraction.TWO_THIRDS).add(begin);
58        add(new CantorInterval(twoThird, end));
59      }
60    }
61  
62    @Override
63    public int getChildCount() {
64      init();
65      return super.getChildCount();
66    }
67  
68    @Override
69    public TreeNode getChildAt(final int i) {
70      init();
71      return super.getChildAt(i);
72    }
73  
74    @Override
75    public Enumeration<TreeNode> children() {
76      init();
77      return super.children();
78    }
79  
80    public String getLabel() {
81      return "[" + begin + ", " + end + "]";
82    }
83  
84    public String toString() {
85      return getLabel();
86    }
87  
88    public static final class Fraction implements Serializable {
89  
90      private final BigInteger numerator;
91      private final BigInteger denominator;
92  
93      public static final Fraction ZERO = new Fraction(0);
94      public static final Fraction ONE = new Fraction(1);
95      public static final BigInteger THREE = BigInteger.valueOf(3);
96      public static final Fraction ONE_THIRD = new Fraction(BigInteger.ONE, THREE);
97      public static final Fraction TWO_THIRDS = new Fraction(BigInteger.valueOf(2), THREE);
98  
99      private Fraction(final long i) {
100       numerator = BigInteger.valueOf(i);
101       denominator = BigInteger.ONE;
102     }
103 
104     private Fraction(final BigInteger numerator, final BigInteger denominator) {
105       BigInteger n = numerator;
106       BigInteger d = denominator;
107       while (n.remainder(THREE).equals(BigInteger.ZERO)
108           && d.remainder(THREE).equals(BigInteger.ZERO)) {
109         n = n.divide(THREE);
110         d = d.divide(THREE);
111       }
112       this.numerator = n;
113       this.denominator = d;
114     }
115 
116     public Fraction add(final Fraction value) {
117       return new Fraction(
118           numerator.multiply(value.denominator).add(denominator.multiply(value.numerator)),
119           denominator.multiply(value.denominator));
120     }
121 
122     public Fraction subtract(final Fraction value) {
123       return new Fraction(
124           numerator.multiply(value.denominator).subtract(denominator.multiply(value.numerator)),
125           denominator.multiply(value.denominator));
126     }
127 
128     public Fraction multiply(final Fraction value) {
129       return new Fraction(
130           numerator.multiply(value.numerator),
131           denominator.multiply(value.denominator));
132     }
133 
134     @Override
135     public String toString() {
136       final StringBuilder builder = new StringBuilder();
137       if (denominator.equals(BigInteger.ONE)) {
138         builder.append(numerator);
139       } else {
140         builder.append(numerator);
141         builder.append("/");
142         builder.append(denominator);
143       }
144       return builder.toString();
145     }
146   }
147 }