Package org.geotools.renderer3d.utils.quadtree

Source Code of org.geotools.renderer3d.utils.quadtree.QuadTreeNodeImpl

/*
*    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.BoundingRectangleImpl;
import org.geotools.renderer3d.utils.ParameterChecker;

import java.util.ArrayList;
import java.util.List;

/**
* @author Hans H�ggstr�m
*/
public final class QuadTreeNodeImpl<N>
        implements QuadTreeNode<N>
{

    //======================================================================
    // Private Fields

    private final QuadTree<N> myQuadTree;
    private final List<NodeListener<N>> myNodeListeners = new ArrayList<NodeListener<N>>( 3 );

    private QuadTreeNode<N> myParent = null;
    private BoundingRectangle myBoundingRectangle;
    private QuadTreeNode<N>[] myChildren = null;
    private N myNodeData = null;
    private boolean myExpanded = false;
    private boolean myAttached = true;

    //======================================================================
    // Private Constants

    private static final int NUMBER_OF_SUBNODES = 4;
    private static final BoundingRectangleImpl ORIGO_BOUNDING_RECTANGLE = new BoundingRectangleImpl( 0, 0, 10 );

    //======================================================================
    // Public Methods

    //----------------------------------------------------------------------
    // Constructors

    public QuadTreeNodeImpl( final QuadTree<N> quadTree,
                             BoundingRectangle boundingRectangle )
    {
        this( quadTree, boundingRectangle, null );
    }


    public QuadTreeNodeImpl( final QuadTree<N> quadTree,
                             final BoundingRectangle boundingRectangle,
                             final QuadTreeNode<N> parentNode )
    {
        ParameterChecker.checkNotNull( quadTree, "quadTree" );

        setBounds( boundingRectangle );

        myQuadTree = quadTree;
        myParent = parentNode;
    }


    public QuadTreeNodeImpl( QuadTree<N> quadTree, double centerX, double centerY, double radius )
    {
        this( quadTree,
              centerX - radius,
              centerY - radius,
              centerX + radius,
              centerY + radius );

        ParameterChecker.checkPositiveNonZeroNormalNumber( radius, "radius" );
        ParameterChecker.checkNormalNumber( centerX, "centerX" );
        ParameterChecker.checkNormalNumber( centerY, "centerY" );
    }


    public QuadTreeNodeImpl( final QuadTree<N> quadTree,
                             final double x1,
                             final double y1,
                             final double x2,
                             final double y2 )
    {
        this( quadTree, new BoundingRectangleImpl( x1, y1, x2, y2 ) );
    }

    //----------------------------------------------------------------------
    // QuadTreeNode Implementation

    public BoundingRectangle getBounds()
    {
        checkNodeIsAttached();

        return myBoundingRectangle;
    }


    public QuadTreeNode<N> getRootNode()
    {
        checkNodeIsAttached();

        if ( myParent != null )
        {
            return myParent.getRootNode();
        }
        else
        {
            return this;
        }
    }

    public boolean hasNodeData()
    {
        return myNodeData != null;
    }

    public N getNodeData()
    {
        checkNodeIsAttached();

        // Lazy creation
        if ( myNodeData == null )
        {
            myNodeData = myQuadTree.getNodeDataFactory().createNodeDataObject( this );
        }

        return myNodeData;
    }


    public void setNodeData( final N nodeData )
    {
        checkNodeIsAttached();

        myNodeData = nodeData;
    }


    public boolean visitChildren( final NodeVisitor<N> visitor )
    {
        checkNodeIsAttached();

        if ( myChildren != null )
        {
            for ( QuadTreeNode<N> child : myChildren )
            {
                if ( !visitor.visitNode( child ) )
                {
                    return false;
                }
            }
        }

        return true;
    }


    public boolean visitDecendants( final NodeVisitor<N> visitor )
    {
        checkNodeIsAttached();

        if ( myChildren != null )
        {
            for ( QuadTreeNode<N> child : myChildren )
            {
                if ( !child.visitSelfAndDecendants( visitor ) )
                {
                    return false;
                }
            }
        }

        return true;
    }


    public boolean visitSelfAndDecendants( final NodeVisitor<N> visitor )
    {
        checkNodeIsAttached();

        if ( visitor.visitNode( this ) )
        {
            return visitDecendants( visitor );
        }
        else
        {
            return false;
        }
    }


    public int getNumberOfChildren()
    {
        checkNodeIsAttached();

        return NUMBER_OF_SUBNODES;
    }


    public QuadTreeNode<N> getChild( final int index )
    {
        checkNodeIsAttached();

        if ( myChildren == null )
        {
            return null;
        }
        else
        {
            return myChildren[ index ];
        }
    }


    public void setExpanded( final boolean expanded )
    {
        checkNodeIsAttached();

        if ( expanded )
        {
            expand();
        }
        else
        {
            collapse();
        }
    }


    public boolean isExpanded()
    {
        checkNodeIsAttached();

        return myExpanded;
    }


    public boolean covers( final double x, final double y, final double radius )
    {
        checkNodeIsAttached();

        return getBounds().isInside( x, y, radius );
    }


    public void grow( double x, double y )
    {
        checkNodeIsAttached();

        if ( isRootNode() )
        {
            // Calcualte which direction the new parent should expand into
            final int parentSubsector = myBoundingRectangle.getSubsectorAt( x, y );

            // Create a new parent
            final BoundingRectangle parentBounds = myBoundingRectangle.createParentBoundingRectangle( parentSubsector );
            final QuadTreeNode<N> parentNode = myQuadTree.createQuadTreeNode( parentBounds, null );
            myQuadTree.initnodedata( parentNode );

            // Add this node as a child of the parent node (in the opposite corner of where we expanded)
            final int childSubquadrant = myBoundingRectangle.getOppositeSubquadrant( parentSubsector );
            parentNode.expandWithChild( childSubquadrant, this );

            myParent = parentNode;

            // Notify model that we have a new root node
            myQuadTree.setRootNode( parentNode );

        }
        else
        {
            getRootNode().grow( x, y );
        }
    }


    public void growToInclude( double x, double y, final double radius )
    {
        checkNodeIsAttached();

        while ( !getRootNode().covers( x, y, radius ) )
        {
            grow( x, y );
        }
    }


    public boolean isRootNode()
    {
        checkNodeIsAttached();

        return myParent == null;
    }


    public void addNodeListener( NodeListener<N> addedNodeListener )

    {
        checkNodeIsAttached();

        ParameterChecker.checkNotNull( addedNodeListener, "addedNodeListener" );
        ParameterChecker.checkNotAlreadyContained( addedNodeListener, myNodeListeners, "myNodeListeners" );

        myNodeListeners.add( addedNodeListener );
    }


    public void removeNodeListener(
            NodeListener<N> removedNodeListener )

    {
        checkNodeIsAttached();

        ParameterChecker.checkNotNull( removedNodeListener, "removedNodeListener" );
        ParameterChecker.checkContained( removedNodeListener, myNodeListeners, "myNodeListeners" );

        myNodeListeners.remove( removedNodeListener );
    }


    public void detach()
    {
        checkNodeIsAttached();

        myParent = null;
        myAttached = false;
        myChildren = null;
        myBoundingRectangle = ORIGO_BOUNDING_RECTANGLE;
    }


    public void attach( final BoundingRectangle bounds, QuadTreeNode<N> parent )
    {
        if ( myAttached )
        {
            throw new IllegalStateException( "A node that was already attached to '" + myParent + "' was attempted to be attached to '" + parent + "' " );
        }

        myParent = parent;
        myAttached = true;

        setBounds( bounds );
    }


    public boolean isAttached()
    {
        return myAttached;
    }


    public void expandWithChild( final int childSubquadrant, final QuadTreeNode<N> childNode )
    {
        checkNodeIsAttached();

        if ( !myExpanded )
        {
            myExpanded = true;

            // Create the child array if needed
            if ( myChildren == null )
            {
                //noinspection unchecked
                myChildren = new QuadTreeNode[NUMBER_OF_SUBNODES];
            }

            // Create child nodes
            for ( int i = 0; i < NUMBER_OF_SUBNODES; i++ )
            {
                if ( myChildren[ i ] != null )
                {
                    throw new IllegalStateException( "A newly expanded node should not have any children" );
                }

                if ( i == childSubquadrant )
                {
                    myChildren[ i ] = childNode;
                }
                else
                {
                    final BoundingRectangle rectangle = myBoundingRectangle.createSubquadrantBoundingRectangle( i );
                    myChildren[ i ] = myQuadTree.createQuadTreeNode( rectangle, this );
                }
            }

            // Init node data for the other children
            for ( int i = 0; i < myChildren.length; i++ )
            {
                if ( i != childSubquadrant )
                {
                    myQuadTree.initnodedata( myChildren[ i ] );
                }
            }

            for ( NodeListener<N> nodeListener : myNodeListeners )
            {
                nodeListener.onExpanded( this );
            }
        }
    }


    public QuadTreeNode<N> getParent()
    {
        return myParent;
    }


    public int getIndexOfChild( final QuadTreeNode<N> childNode )
    {
        for ( int i = 0; i < myChildren.length; i++ )
        {
            if ( childNode == myChildren[ i ] )
            {
                return i;
            }
        }

        return -1;
    }

    //======================================================================
    // Private Methods

    private void setBounds( final BoundingRectangle boundingRectangle )
    {
        checkNodeIsAttached();

        ParameterChecker.checkNotNull( boundingRectangle, "boundingRectangle" );
        if ( boundingRectangle.isEmpty() )
        {
            throw new IllegalArgumentException( "The bounding rectangle '" + boundingRectangle +
                                                "' specified for the QuadTreeNode should not be empty." );
        }

        myBoundingRectangle = boundingRectangle;
    }


    private void checkNodeIsAttached()
    {
        if ( !isAttached() )
        {
            throw new IllegalStateException( "Can not do any operations to a detached node." );
        }
    }


    private void expand()
    {
        checkNodeIsAttached();

        expandWithChild( -1, null );
    }


    private void collapse()
    {
        checkNodeIsAttached();

        if ( myExpanded )
        {
            myExpanded = false;

            if ( myChildren != null )
            {
                // Delete all child nodes
                for ( int i = 0; i < NUMBER_OF_SUBNODES; i++ )
                {
                    final QuadTreeNode<N> child = myChildren[ i ];
                    if ( child != null )
                    {
                        child.setExpanded( false );

                        myQuadTree.releaseQuadTreeNode( child );
                    }
                    myChildren[ i ] = null;
                }
            }

            myChildren = null;

            for ( NodeListener<N> nodeListener : myNodeListeners )
            {
                nodeListener.onCollapsed( this );
            }
        }
    }

}
TOP

Related Classes of org.geotools.renderer3d.utils.quadtree.QuadTreeNodeImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.