View Javadoc

1   /*
2    * @(#)$Id: Grid.java 689 2009-07-22 00:10:27Z bsigner $
3    *
4    * Author       :   Ueli Kurmann, igesture@uelikurmann.ch
5    *
6    * Purpose      : 	Implementation of the grid that is used to create the
7    *                  signature.
8    *
9    * -----------------------------------------------------------------------
10   *
11   * Revision Information:
12   *
13   * Date             Who         Reason
14   *
15   * Dec 26, 2006     ukurmann    Initial Release
16   * Mar 18, 2007     bsigner     Cleanup
17   *
18   * -----------------------------------------------------------------------
19   *
20   * Copyright 1999-2009 ETH Zurich. All Rights Reserved.
21   *
22   * This software is the proprietary information of ETH Zurich.
23   * Use is subject to license terms.
24   * 
25   */
26  
27  
28  package org.ximtec.igesture.algorithm.signature;
29  
30  import java.util.BitSet;
31  import java.util.HashMap;
32  
33  import org.sigtec.util.Constant;
34  
35  
36  /**
37   * Implementation of the grid that is used to create the signature.
38   * 
39   * @version 1.0 Dec 11, 2006
40   * @author Ueli Kurmann, igesture@uelikurmann.ch
41   * @author Beat Signer, signer@inf.ethz.ch
42   */
43  public class Grid {
44  
45     /**
46      * Directions to populate the signatures.
47      */
48     private enum Direction {
49        RIGHT, UP
50     }
51  
52     /**
53      * The lenght of the bit string (signature representation).
54      */
55     private int bitStringLength;
56  
57     /**
58      * The size of the grid.
59      */
60     private int size;
61  
62     /**
63      * the grid
64      */
65     private BitSet[][] grid;
66  
67     private static HashMap<Integer, Grid> gridCache;
68  
69     static {
70        gridCache = new HashMap<Integer, Grid>();
71     }
72  
73  
74     /**
75      * Constructs a new grid.
76      * 
77      * @param size the size of the grid (size*size).
78      */
79     public Grid(int size) {
80        this.size = computeGridSize(size);
81        bitStringLength = (int)Math.ceil(Math.log(this.size * this.size)
82              / Math.log(2));
83        grid = new BitSet[this.size][this.size];
84        init();
85     }
86  
87  
88     /**
89      * Computes the position of the bit.
90      * 
91      * @param width the width of the "subgrid" after mirroring.
92      * @param height the height of the "subgrid" after mirroring.
93      * @return the bit position.
94      */
95     private int getBitPosition(int width, int height) {
96        final double pow = Math.log(width * height) / Math.log(2);
97        return this.bitStringLength - (int)(Math.ceil(pow));
98     } // getBitPosition
99  
100 
101    public int getBitStringLength() {
102       return bitStringLength;
103    } // getBitStringLength
104 
105 
106    /**
107     * Computes the "mirror" position of the given field.
108     * 
109     * @param x the x coordinate of the field to mirror.
110     * @param y the y coordinate of the field to mirror.
111     * @param width total width of the current "subgrid".
112     * @param height total height of the current "subgrid".
113     * @param direction the direction to be mirrored.
114     * @return the coordinates 0=x, 1=y).
115     */
116    private int[] getMirrorPosition(int x, int y, int width, int height,
117          Direction direction) {
118       final int[] coordinate = new int[2];
119 
120       if (direction.equals(Direction.UP)) {
121          final int newHeight = 2 * height;
122          coordinate[0] = x;
123          coordinate[1] = newHeight - (y + 1);
124       }
125       else {
126          final int newWidth = 2 * width;
127          coordinate[0] = newWidth - (x + 1);
128          coordinate[1] = y;
129       }
130 
131       return coordinate;
132    } // getMirrorPosition
133 
134 
135    /**
136     * Returns the signature of a given field of the grid.
137     * 
138     * @param x the x coordinate.
139     * @param y the y coordinate.
140     * @return the signature.
141     */
142    public BitSet getSignature(int x, int y) {
143       if (!(x >= 0 && x < size && y >= 0 && y < size)) {
144          throw new RuntimeException("size not allowed");
145       }
146 
147       return grid[x][y];
148    } // getSignature
149 
150 
151    /**
152     * Initialises the grid.
153     */
154    private void init() {
155       final BitSet bitSet = new BitSet(size);
156       bitSet.clear();
157       grid[0][0] = bitSet;
158       recursive(1, 1, Direction.UP);
159    } // init
160 
161 
162    /**
163     * Pretty print for a given bit set.
164     * 
165     * @param bitSet the bit set to be formatted.
166     * @return formatted bit set.
167     */
168    private String prettyPrint(BitSet bitSet) {
169       final StringBuilder sb = new StringBuilder();
170 
171       for (int i = 0; i < this.bitStringLength; i++) {
172 
173          if (bitSet.get(i)) {
174             sb.append(Constant.ONE);
175          }
176          else {
177             sb.append(Constant.ZERO);
178          }
179 
180       }
181 
182       return sb.toString();
183    } // prettyPrint
184 
185 
186    /**
187     * Recursive method to populate the values in the grid.
188     * 
189     * @param x the x coordinate.
190     * @param y the y coordinate.
191     * @param direction the direction.
192     */
193    private void recursive(int x, int y, Direction direction) {
194       if (x >= this.size && y >= this.size) {
195          return;
196       }
197 
198       int newX;
199       int newY;
200       Direction newDirection;
201 
202       if (direction.equals(Direction.RIGHT)) {
203          newX = x * 2;
204          newY = y;
205          newDirection = Direction.UP;
206       }
207       else {
208          newX = x;
209          newY = y * 2;
210          newDirection = Direction.RIGHT;
211       }
212 
213       for (int i = 0; i < x; i++) {
214 
215          for (int j = 0; j < y; j++) {
216             final int[] coord = getMirrorPosition(i, j, x, y, direction);
217             final BitSet b = (BitSet)grid[i][j].clone();
218             b.set(getBitPosition(newX, newY));
219             this.setCell(coord[0], coord[1], b);
220          }
221 
222       }
223 
224       recursive(newX, newY, newDirection);
225    } // recursive
226 
227 
228    /**
229     * Sets the signature of a field.
230     * 
231     * @param x the x coordinate.
232     * @param y the y coordinate.
233     * @param bitSet the signature of the field.
234     */
235    public void setCell(int x, int y, BitSet bitSet) {
236       if (!(x >= 0 && x < size && y >= 0 && y < size)) {
237          throw new IndexOutOfBoundsException();
238       }
239 
240       grid[x][y] = bitSet;
241    } // setCell
242 
243 
244    private static int computeGridSize(int gridSize) {
245       return (int)Math
246             .pow(2, (int)Math.ceil((Math.log(gridSize) / Math.log(2))));
247    } // computeGridSize
248 
249 
250    /**
251     * Returns the grid with the desired size. If the grid is available in the
252     * cache, the cached instance is returned. Otherwise a new grid instance is
253     * created and added to the cache.
254     * 
255     * @param size the size of the grid to be returned.
256     * @return grid with the specified size.
257     */
258    public static Grid createInstance(int size) {
259       final int gridSize = computeGridSize(size);
260       Grid result = gridCache.get(gridSize);
261 
262       if (result == null) {
263          result = new Grid(gridSize);
264          gridCache.put(gridSize, result);
265       }
266 
267       return result;
268    } // createInstance
269 
270 
271    @Override
272    public String toString() {
273       final StringBuilder sb = new StringBuilder();
274 
275       for (int i = 0; i < size; i++) {
276 
277          for (int j = 0; j < size; j++) {
278             sb.append(prettyPrint(grid[i][j]) + Constant.DOUBLE_BLANK);
279          }
280 
281          sb.append(Constant.LF_STRING);
282       }
283 
284       return sb.toString();
285    } // toString
286 
287 }