/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2007-2008, Open Source Geospatial Foundation (OSGeo)
*
* This library 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;
* version 2.1 of the License.
*
* This library 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.
*/
package org.geotools.renderer3d.utils.quadtree;
import org.geotools.renderer3d.utils.BoundingRectangle;
import org.geotools.renderer3d.utils.ParameterChecker;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
/**
* @author Hans H�ggstr�m
*/
public class QuadTreeImpl<N>
implements QuadTree<N>
{
//======================================================================
// Private Fields
private final double myStartRadius;
private final NodeDataFactory<N> myNodeDataFactory;
private final List<QuadTreeListener<N>> myListeners = new ArrayList<QuadTreeListener<N>>( 3 );
private QuadTreeNode<N> myRootNode;
//======================================================================
// Private Constants
private static final NodeDataFactory NULL_NODE_DATA_FACTORY = new NodeDataFactory()
{
public Object createNodeDataObject( final QuadTreeNode node )
{
return null;
}
public Object reuseNodeDataObject( final QuadTreeNode node, final Object nodeData )
{
return null;
}
public void onDataObjectUnused( final Object nodeData )
{
}
};
//======================================================================
// Public Methods
//----------------------------------------------------------------------
// Constructors
/**
* @param startRadius
* @param nodeDataFactory a factory for creating data objects for nodes. May be null (in that case all node data objects will be null by default).
*/
public QuadTreeImpl( final double startRadius,
NodeDataFactory<N> nodeDataFactory )
{
ParameterChecker.checkPositiveNonZeroNormalNumber( startRadius, "startRadius" );
myStartRadius = startRadius;
if ( nodeDataFactory == null )
{
myNodeDataFactory = NULL_NODE_DATA_FACTORY;
}
else
{
myNodeDataFactory = nodeDataFactory;
}
}
//----------------------------------------------------------------------
// QuadTree Implementation
public QuadTreeNode<N> getRootNode()
{
buildRootNodeIfNeeded( 0, 0 );
return myRootNode;
}
public void setRootNode( QuadTreeNode<N> newRootNode )
{
ParameterChecker.checkNotNull( newRootNode, "newRootNode" );
myRootNode = newRootNode;
for ( QuadTreeListener<N> listener : myListeners )
{
listener.onRootChanged( myRootNode );
}
}
public NodeDataFactory<N> getNodeDataFactory()
{
return myNodeDataFactory;
}
public void addQuadTreeListener( QuadTreeListener<N> addedQuadTreeListener )
{
ParameterChecker.checkNotNull( addedQuadTreeListener, "addedQuadTreeListener" );
ParameterChecker.checkNotAlreadyContained( addedQuadTreeListener, myListeners, "myListeners" );
myListeners.add( addedQuadTreeListener );
}
public void removeQuadTreeListener( QuadTreeListener<N> removedQuadTreeListener )
{
ParameterChecker.checkNotNull( removedQuadTreeListener, "removedQuadTreeListener" );
ParameterChecker.checkContained( removedQuadTreeListener, myListeners, "myListeners" );
myListeners.remove( removedQuadTreeListener );
}
private final LinkedList<QuadTreeNode<N>> myQuadTreeNodePool = new LinkedList<QuadTreeNode<N>>();
public QuadTreeNode<N> createQuadTreeNode( final BoundingRectangle bounds,
final QuadTreeNode<N> parentNode )
{
final QuadTreeNode<N> quadTreeNode;
if ( myQuadTreeNodePool.isEmpty() )
{
quadTreeNode = new QuadTreeNodeImpl<N>( this, bounds, parentNode );
}
else
{
quadTreeNode = myQuadTreeNodePool.removeLast();
quadTreeNode.attach( bounds, parentNode );
}
return quadTreeNode;
}
public void initnodedata( final QuadTreeNode<N> quadTreeNode )
{
final N nodeData;
if ( quadTreeNode.hasNodeData() )
{
nodeData = myNodeDataFactory.reuseNodeDataObject( quadTreeNode, quadTreeNode.getNodeData() );
}
else
{
nodeData = myNodeDataFactory.createNodeDataObject( quadTreeNode );
}
quadTreeNode.setNodeData( nodeData );
}
public void releaseQuadTreeNode( final QuadTreeNode<N> node )
{
final N nodeData = node.getNodeData();
myNodeDataFactory.onDataObjectUnused( nodeData );
node.detach();
myQuadTreeNodePool.addLast( node );
}
//======================================================================
// Private Methods
private void buildRootNodeIfNeeded( final double startCenterX, final double startCenterY )
{
if ( myRootNode == null )
{
myRootNode = new QuadTreeNodeImpl<N>( this, startCenterX, startCenterY, myStartRadius );
}
}
}