/**
* Copyright (c) 2009, iPlant Collaborative, Texas Advanced Computing Center This software is licensed
* under the CC-GNU GPL version 2.0 or later. License: http://creativecommons.org/licenses/GPL/2.0/
*/
package org.iplantc.phyloviewer.shared.scene.intersect;
import java.util.ArrayList;
import org.iplantc.phyloviewer.shared.layout.ILayoutData;
import org.iplantc.phyloviewer.shared.math.Box2D;
import org.iplantc.phyloviewer.shared.math.Vector2;
import org.iplantc.phyloviewer.shared.model.IDocument;
import org.iplantc.phyloviewer.shared.model.INode;
import org.iplantc.phyloviewer.shared.model.ITree;
import org.iplantc.phyloviewer.shared.scene.Drawable;
import org.iplantc.phyloviewer.shared.scene.DrawableContainer;
public class IntersectTree
{
public class Hit
{
private INode node;
private Drawable drawable;
Hit(INode node, Drawable drawable)
{
this.node = node;
this.drawable = drawable;
}
public INode getNode()
{
return node;
}
public int getNodeId()
{
return node != null ? node.getId() : -1;
}
public Drawable getDrawable()
{
return drawable;
}
}
private ITree tree;
private Vector2 position;
private double distanceForHitSquared;
private ILayoutData layout;
private DrawableContainer drawableContainer;
private ArrayList<Hit> hitList = new ArrayList<Hit>();
public IntersectTree(IDocument document, DrawableContainer drawableContainer, Vector2 position,
double pixelSize)
{
if(document != null)
{
this.tree = document.getTree();
this.layout = document.getLayout();
}
this.drawableContainer = drawableContainer;
this.position = position;
distanceForHitSquared = pixelSize * pixelSize;
}
/**
* Get the hit object that was closest to the position.
*
* @return
*/
public Hit getClosestHit()
{
Hit closest = null;
double minDistance = Double.MAX_VALUE;
for(Hit hit : hitList)
{
Box2D box = hit.drawable.getBoundingBox();
Vector2 center = box.getCenter();
double distance = center.distance(position);
if(distance < minDistance)
{
minDistance = distance;
closest = hit;
}
}
return closest;
}
/**
* Perform the intersection test.
*/
public void intersect()
{
if(tree != null && tree.getRootNode() != null && layout != null && drawableContainer != null)
{
this.visit(tree.getRootNode());
}
}
private void visit(INode node)
{
if(node == null || this.position == null)
{
return;
}
if(layout.containsNode(node))
{
intersectNode(node);
// If the position is contained in the boundingbox, continue the traversal.
Box2D bbox = layout.getBoundingBox(node).clone();
bbox.expandBy(0.2);
if(bbox.contains(position))
{
this.traverse(node);
}
}
}
private void intersectNode(INode node)
{
Drawable[] drawables = drawableContainer.getNodeDrawables(node);
this.testIntersection(node, drawables);
Drawable drawable = drawableContainer.getTextDrawable(node);
this.testIntersection(node, drawable);
}
private void testIntersection(INode node, Drawable[] drawables)
{
if(drawables != null)
{
for(Drawable drawable : drawables)
{
testIntersection(node, drawable);
}
}
}
private void testIntersection(INode node, Drawable drawable)
{
if(drawable != null && drawable.intersect(position, distanceForHitSquared))
{
Hit hit = new Hit(node, drawable);
hitList.add(hit);
}
}
private void traverse(INode node)
{
INode[] children = node.getChildren();
if(children != null)
{
for(int i = 0;i < children.length;++i)
{
INode child = children[i];
Drawable[] drawables = drawableContainer.getBranchDrawables(child);
this.testIntersection(child, drawables);
this.visit(child);
}
}
}
}