/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package com.cloudsoft.utils;
import java.awt.Point;
import java.util.Vector;
// **************************************************************************************************
/** Stores a one-dimensional ordered list of objects that can represent a two-dimensional arrangement
* using Morton ordering. The order of objects stored in this collection is assumed to be Morton.
* Ordering can be VERTICAL (mirror 'N' shaped) or HORIZONTAL ('Z' shaped).
* @author Jo Wood, giCentre.
* @version 3.0, 24th February, 2011.
* @param Type of object stored in the Morton ordered collection.
*/
// **************************************************************************************************
/* This file is part of the giCentre treeMappa library. treeMappa is free software: you can
* redistribute it and/or modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* treeMappa is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* source code (see COPYING.LESSER included with this source code). If not, see
* http://www.gnu.org/licenses/.
*/
public class MortonList extends Vector
{
// -------------------- Object and class variables -------------------
private static final long serialVersionUID = 1464385625231719807L;
/** Indicates that Morton ordering is mirror 'N' shaped. */
public static final int VERTICAL = 1;
/** Indicates that Morton ordering is 'Z' shaped. */
public static final int HORIZONTAL = 2;
private int direction;
// --------------------------- Constructor ---------------------------
/** Creates the collection assuming a vertical Morton layout.
*/
public MortonList()
{
this(VERTICAL);
}
/** Creates the collection with a Morton layout in the given direction.
* @param direction Direction of layout. Should be one of VERTICAL
* (mirrored 'N' shaped) or HORIZONTAL ('Z' shaped).
*/
public MortonList(int direction)
{
super();
this.direction = direction;
}
// ----------------------------- Methods -----------------------------
/** Clears this collection and sets the given direction for Morton ordering.
* @param mDirection New direction for Morton ordering. Should be one of VERTICAL
* (mirrored 'N' shaped) or HORIZONTAL ('Z' shaped).
*/
public void resetDirection(int mDirection)
{
clear();
this.direction = mDirection;
}
/** Returns the x,y position of the first occurrence of the given object in this collection,
* or null if the collection does not contain the object.
* @param obj Object whose position will be reported.
* @return 2-dimensional position of the object.
*/
public Point positionOf(Object obj)
{
int index = indexOf(obj);
if (index < 0)
{
return null;
}
return new Point(getX(index),getY(index));
}
/** Returns the object at the given x,y position or null if no object at the given position.
* Note that it is not possible to distinguish between a null object at a given position
* and position that it out of bounds of the current collection.
* @param x x coordinate of the position from which to retrieve the object.
* @param y x coordinate of the position from which to retrieve the object.
* @return Object at the given position or null if out of bounds or no object.
*/
public E get(int x, int y)
{
int morton = getMorton(x, y);
if (morton >= size())
{
//System.err.println("Position out of bounds: Morton number for "+x+","+y+" is "+morton+" but collection only has "+size()+" elements.");
return null;
}
return get(morton);
}
/** Returns the object that is to the 'right' (x+1) of the first instance of the given reference object
* or null if no object to the right or if the given reference object not found.
* @param obj Reference object from which to find its neighbour.
* @return Object to the right of the given reference object.
*/
public E getNextX(Object obj)
{
Point position = positionOf(obj);
if (position == null)
{
//System.err.println("getNextX(): Object "+obj+" not found in collection.");
return null;
}
return get(position.x+1,position.y);
}
/** Returns the object that is 'below' (y+1) the first instance of the given reference object
* or null if no object below or if the given reference object not found.
* @param obj Reference object from which to find its neighbour.
* @return Object below the given reference object.
*/
public E getNextY(Object obj)
{
Point position = positionOf(obj);
if (position == null)
{
//System.err.println("getNextY(): Object "+obj+" not found in collection.");
return null;
}
return get(position.x,position.y+1);
}
/** Reports the x coordinate of the position represented by the given Morton number.
* @param mortonNumber Number to process.
* @return x coordinate represented by the Morton number.
*/
public int getX(int mortonNumber)
{
int x=0;
if (direction == HORIZONTAL)
{
for (int i=0; i<32; i+=2)
{
int mask = 1 << (i);
x += (mortonNumber&mask)>>(i/2);
}
}
else
{
for (int i=1; i<32; i+=2)
{
int mask = 1 << (i);
x += (mortonNumber&mask)>>((i+1)/2);
}
}
return x;
}
/** Reports the y coordinate of the position represented by the given Morton number.
* @param mortonNumber Number to process.
* @return y coordinate represented by the Morton number.
*/
public int getY(int mortonNumber)
{
int y=0;
if (direction == HORIZONTAL)
{
for (int i=1; i<32; i+=2)
{
int mask = 1 << (i);
y += (mortonNumber&mask)>>((i+1)/2);
}
}
else
{
for (int i=0; i<32; i+=2)
{
int mask = 1 << (i);
y += (mortonNumber&mask)>>(i/2);
}
}
return y;
}
/** Reports the Morton number representing the given x,y coordinate pair.
* @param x x coordinate of position to calculate.
* @param y y coordinate of position to calculate.
* @return Morton number representing the given position.
*/
public int getMorton(int x, int y)
{
int newX = x;
int newY = y;
int morton = 0;
if (direction == HORIZONTAL)
{
// Swap x and y coordinates for horizontal ordering.
newX = y;
newY = x;
}
for (int i=0; i<16; i++)
{
int mask = 1 << (i);
morton += (newX&mask)<<(i+1);
morton += (newY&mask)<