/*
* Copyright (C) 2014 Alfons Wirtz
* website www.freerouting.net
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License at <http://www.gnu.org/licenses/>
* for more details.
*
* ShapeTree.java
*
* Created on 1. September 2004, 10:50
*/
package datastructures;
import geometry.planar.ShapeBoundingDirections;
import geometry.planar.RegularTileShape;
import geometry.planar.Shape;
import geometry.planar.TileShape;
/**
* Abstract binary search tree for shapes in the plane.
* The shapes are stored in the leafs of the tree.
* Objects to be stored in the tree must implement the interface ShapeTree.Storable.
*
* @author Alfons Wirtz
*/
public abstract class ShapeTree
{
/** Creates a new instance of ShapeTree */
public ShapeTree(ShapeBoundingDirections p_directions)
{
bounding_directions = p_directions ;
root = null ;
leaf_count = 0;
}
/**
* Inserts all shapes of p_obj into the tree
*/
public void insert(ShapeTree.Storable p_obj)
{
int shape_count = p_obj.tree_shape_count(this);
if (shape_count <= 0)
{
return;
}
Leaf [] leaf_arr = new Leaf [shape_count];
for (int i = 0; i < shape_count; ++i)
{
leaf_arr [i] = insert(p_obj, i);
}
p_obj.set_search_tree_entries(leaf_arr, this);
}
/**
* Insert a shape - creates a new node with a bounding shape
*/
protected Leaf insert(ShapeTree.Storable p_object, int p_index)
{
Shape object_shape = p_object.get_tree_shape(this, p_index);
if (object_shape == null)
{
return null;
}
RegularTileShape bounding_shape = object_shape.bounding_shape(bounding_directions) ;
if ( bounding_shape == null )
{
System.out.println("ShapeTree.insert: bounding shape of TreeObject is null");
return null;
}
// Construct a new KdLeaf and set it up
Leaf new_leaf = new Leaf(p_object, p_index, null, bounding_shape) ;
this.insert(new_leaf);
return new_leaf;
}
/** Inserts the leaves of this tree into an array. */
public Leaf[] to_array()
{
Leaf [] result = new Leaf[this.leaf_count];
if (result.length == 0)
{
return result;
}
TreeNode curr_node = this.root;
int curr_index = 0;
for (;;)
{
// go down from curr_node to the left most leaf
while (curr_node instanceof InnerNode)
{
curr_node = ((InnerNode) curr_node).first_child;
}
result[curr_index] = (Leaf) curr_node;
++curr_index;
// go up until parent.second_child != curr_node, which means we came from first_child
InnerNode curr_parent = curr_node.parent;
while (curr_parent != null && curr_parent.second_child == curr_node)
{
curr_node = curr_parent;
curr_parent = curr_node.parent;
}
if (curr_parent == null)
{
break;
}
curr_node = curr_parent.second_child;
}
return result;
}
abstract void insert(Leaf p_leaf);
abstract void remove_leaf(Leaf p_leaf);
/**
* removes all entries of p_obj in the tree.
*/
public void remove(Leaf [] p_entries)
{
if (p_entries == null)
{
return;
}
for (int i = 0; i < p_entries.length; ++i)
{
remove_leaf(p_entries[i]);
}
}
/** Returns the number of entries stored in the tree. */
public int size()
{
return leaf_count;
}
/** Outputs some statistic information about the tree. */
public void statistics(String p_message)
{
Leaf[] leaf_arr = this.to_array();
double cumulative_depth = 0;
int maximum_depth = 0;
for (int i = 0; i < leaf_arr.length; ++ i)
{
if (leaf_arr[i] != null)
{
int distance_to_root = leaf_arr[i].distance_to_root();
cumulative_depth += distance_to_root;
maximum_depth = Math.max(maximum_depth, distance_to_root);
}
}
double everage_depth = cumulative_depth / leaf_arr.length;
System.out.print("MinAreaTree: Entry count: ");
System.out.print(leaf_arr.length);
System.out.print(" log: ");
System.out.print(Math.round(Math.log(leaf_arr.length)));
System.out.print(" Everage depth: ");
System.out.print(Math.round(everage_depth));
System.out.print(" ");
System.out.print(" Maximum depth: ");
System.out.print(maximum_depth);
System.out.print(" ");
System.out.println(p_message);
}
/**
* the fixed directions for calculating bounding RegularTileShapes
* of shapes to store in this tree.
*/
final protected ShapeBoundingDirections bounding_directions ;
/** Root node - initially null */
protected TreeNode root ;
/** The number of entries stored in the tree */
protected int leaf_count;
/**
* Interface, which must be implemented by objects to be stored
* in a ShapeTree.
*/
public interface Storable extends Comparable<Object>
{
/**
* Number of shapes of an object to store in p_shape_tree
*/
int tree_shape_count(ShapeTree p_shape_tree) ;
/**
* Get the Shape of this object with index p_index stored in the ShapeTree with index identification number p_tree_id_no
*/
TileShape get_tree_shape(ShapeTree p_tree, int p_index) ;
/**
* Stores the entries in the ShapeTrees of this object for
* better performance while for example deleting tree entries.
* Called only by insert methods of class ShapeTree.
*/
void set_search_tree_entries(Leaf [] p_entries, ShapeTree p_tree);
}
/**
* Information of a single object stored in a tree
*/
public static class TreeEntry
{
public TreeEntry(ShapeTree.Storable p_object, int p_shape_index_in_object)
{
object = p_object;
shape_index_in_object = p_shape_index_in_object;
}
public final ShapeTree.Storable object;
public final int shape_index_in_object;
}
//////////////////////////////////////////////////////////
/** Common functionality of inner nodes and leaf nodes. */
protected static class TreeNode
{
public RegularTileShape bounding_shape ;
InnerNode parent;
}
//////////////////////////////////////////////////////////
/**
* Desscription of an inner node of the tree,
* which implements a fork to its two children.
*/
public static class InnerNode extends TreeNode
{
public InnerNode( RegularTileShape p_bounding_shape, InnerNode p_parent )
{
bounding_shape = p_bounding_shape;
parent = p_parent;
first_child = null ;
second_child = null ;
}
public TreeNode first_child ;
public TreeNode second_child ;
}
//////////////////////////////////////////////////////////
/**
* Description of a leaf of the Tree, where the geometric
* information is stored.
*/
public static class Leaf extends TreeNode implements Comparable<Leaf>
{
public Leaf( ShapeTree.Storable p_object, int p_index, InnerNode p_parent, RegularTileShape p_bounding_shape)
{
bounding_shape = p_bounding_shape;
parent = p_parent;
object = p_object ;
shape_index_in_object = p_index ;
}
public int compareTo(Leaf p_other)
{
int result = this.object.compareTo(p_other.object);
if (result == 0)
{
result = shape_index_in_object - p_other.shape_index_in_object;
}
return result;
}
/** Returns the number of nodes between this leaf and the croot of the tree. */
public int distance_to_root()
{
int result = 1;
InnerNode curr_parent = this.parent;
while (curr_parent.parent != null)
{
curr_parent = curr_parent.parent;
++result;
}
return result;
}
/** Actual object stored */
public ShapeTree.Storable object ;
/** index of the shape in the object */
public int shape_index_in_object;
}
}