Package utils

Source Code of utils.SpacialQuadTree$Node

/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/

package utils;

import factories.Boxes;
import graphics.common.Box;
import graphics.common.GraphicsObject;
import java.awt.Color;
import java.awt.Graphics2D;
import java.util.LinkedList;
import java.util.List;

/**
*
* @author frozen
*/
public class SpacialQuadTree < T extends GraphicsObject > implements TrieTree< T > {

    private int mMaxDepth;
    private int mItemsToSplit;
    private int mItemsToPrune;

    private Node< T > mHead;

     private class Node< T > {
        public List< T > mStoredItems;
        public Node< T > mTopLeft, mTopRight;
        public Node< T > mBottomLeft, mBottomRight;
        public Box mNodeLoc;

        public Node( double x, double y, double width, double height ) {
            mStoredItems = new LinkedList< T >();
            mTopLeft = null;
            mTopRight = null;
            mBottomLeft = null;
            mBottomRight = null;
            mNodeLoc = Boxes.get( x, y, 0,
                                  width, height, 0 );
        }
    }

    public SpacialQuadTree( int maxDepth, int itemsToSplit, int itemsToPrune,
                            double width, double height ) {
        mHead = new Node( 0, 0, width, height );
        mMaxDepth = maxDepth;
        mItemsToSplit = itemsToSplit;
        mItemsToPrune = itemsToPrune < itemsToSplit ? itemsToPrune : itemsToSplit - 1;
    }

    // TEMPORARY METHOD FOR DEBUGGING
    public void drawTree( Graphics2D g ) {
        g.setColor( Color.BLUE );
        drawTreeRecursive( g, mHead );
        g.setColor( Color.WHITE );
    }

        // TEMPORARY METHOD FOR DEBUGGING
    private void drawTreeRecursive( Graphics2D g, Node< T > node ) {
        if( node == null )
            return;

        drawTreeRecursive( g, node.mTopLeft );
        drawTreeRecursive( g, node.mTopRight );
        drawTreeRecursive( g, node.mBottomLeft );
        drawTreeRecursive( g, node.mBottomRight );

        Box loc = node.mNodeLoc;
        //top
        g.drawLine( loc.getX(), loc.getY(),
                loc.getX() + loc.getWidth(), loc.getY() );
        //bottom
        g.drawLine( loc.getX(), loc.getY() + loc.getHeight(),
                loc.getX() + loc.getWidth(), loc.getY() + loc.getHeight() );
        //left
        g.drawLine( loc.getX(), loc.getY(), loc.getX(),
                loc.getY() + loc.getHeight() );
        //right
        g.drawLine( loc.getX() + loc.getWidth(), loc.getY(),
                loc.getX() + loc.getWidth(), loc.getY() + loc.getHeight() );
        loc = null;
    }

    @Override
    public void insert( T thing ) {
        insertRecursive( thing, mHead, 0 );
    }

    private void insertRecursive( T thing, Node< T > node, int depth ) {
        if( node.mTopLeft != null ) {
            Box thingBox = thing.getBox()[ 0 ];
            if( thingBox.intersectingWith( node.mTopLeft.mNodeLoc ) )
                insertRecursive( thing, node.mTopLeft, depth + 1 );
            if( thingBox.intersectingWith( node.mTopRight.mNodeLoc ) )
                insertRecursive( thing, node.mTopRight, depth + 1 );
            if( thingBox.intersectingWith( node.mBottomLeft.mNodeLoc ) )
                insertRecursive( thing, node.mBottomLeft, depth + 1 );
            if( thingBox.intersectingWith( node.mBottomRight.mNodeLoc ) )
                insertRecursive( thing, node.mBottomRight, depth + 1 );
        }
        else {
            node.mStoredItems.add( thing );
            if( node.mStoredItems.size() >= mItemsToSplit && depth < mMaxDepth ) {
                split( node, depth );
            }
        }
    }

    private void split( Node< T > node, int depth ) {
        double width = node.mNodeLoc.getRealWidth() / 2.0;
        double height = node.mNodeLoc.getRealHeight() / 2.0;
        node.mTopLeft = new Node< T >( node.mNodeLoc.getRealX(), node.mNodeLoc.getRealY(),
                                    width, height );
        node.mTopRight = new Node< T >( node.mNodeLoc.getRealX() + width, node.mNodeLoc.getRealY(),
                                    width, height );
        node.mBottomLeft = new Node< T >( node.mNodeLoc.getRealX(), node.mNodeLoc.getRealY() + height,
                                    width, height );
        node.mBottomRight = new Node< T >( node.mNodeLoc.getRealX() + width, node.mNodeLoc.getRealY() + height,
                                    width, height );
        for( T thing : node.mStoredItems ) {
            insertRecursive( thing, node, depth );
        }
        node.mStoredItems.clear();
        //node.mStoredItems = null;
    }

    @Override
    public void remove( T thing ) {
        removeRecursive( thing, mHead );
    }

    private void removeRecursive( T thing, Node< T > node ) {
        if( node == null )
            return;
        Box thingBox = thing.getBox()[ 0 ];
        if( thingBox.intersectingWith( node.mNodeLoc ) ) {
            if( node.mTopLeft == null ) {
                node.mStoredItems.remove( thing );
            }
            else {
                removeRecursive( thing, node.mTopLeft );
                removeRecursive( thing, node.mTopRight );
                removeRecursive( thing, node.mBottomLeft );
                removeRecursive( thing, node.mBottomRight );

                if( getTotalNumItems( node ) <= mItemsToPrune ) {
                    joinChildrenToParent( node );
                }
            }           
        }
    }

    private int getTotalNumItems( Node< T > node ) {
        if( node == null )
            return 0;
        return node.mStoredItems.size() +
                getTotalNumItems( node.mTopLeft ) +
                getTotalNumItems( node.mTopRight ) +
                getTotalNumItems( node.mBottomLeft ) +
                getTotalNumItems( node.mBottomRight );
    }

    private void joinChildrenToParent( Node< T > node ) {
        if( node.mTopLeft == null ) {
            return;
        }
        else {
            joinChildrenToParent( node.mTopLeft );
            joinChildrenToParent( node.mTopRight );
            joinChildrenToParent( node.mBottomLeft );
            joinChildrenToParent( node.mBottomRight );

            node.mStoredItems.addAll( node.mTopLeft.mStoredItems );
            node.mStoredItems.addAll( node.mTopRight.mStoredItems );
            node.mStoredItems.addAll( node.mBottomLeft.mStoredItems );
            node.mStoredItems.addAll( node.mBottomRight.mStoredItems );

            node.mTopLeft.mStoredItems.clear();
            node.mTopRight.mStoredItems.clear();
            node.mBottomLeft.mStoredItems.clear();
            node.mBottomRight.mStoredItems.clear();
            node.mTopLeft = null;
            node.mTopRight = null;
            node.mBottomLeft = null;
            node.mBottomRight = null;
        }
    }

    @Override
    public void update( T thing ) {
        updateRecursive( thing, mHead, 0 );
    }

    private boolean updateRecursive( T thing, Node< T > node, int depth ) {
        if( node == null )
            return true;
       
        //if( node.mStoredItems.contains( thing ) )
        //    return true;
       
        Box thingBox = thing.getBox()[ 0 ];
        boolean found = false;
        if( thingBox.intersectingWith( node.mNodeLoc ) ) {
            found = updateRecursive( thing, node.mTopLeft, depth + 1 ) || found ? true : false;
            found = updateRecursive( thing, node.mTopRight, depth + 1 ) || found ? true : false;
            found = updateRecursive( thing, node.mBottomLeft, depth + 1 ) || found ? true : false;
            found = updateRecursive( thing, node.mBottomRight, depth + 1 ) || found ? true : false;
        }

        if( found ) {          
            if( nodeContains( node, thing ) ) {
                removeRecursive( thing, node );
                insertRecursive( thing, node, depth );
                return false;
            }
            return true;
        }

        return false;
    }

    private boolean nodeContains( Node< T > node, T thing ) {
        Box thingBox = thing.getBox()[ 0 ];
        Box nodeLoc = node.mNodeLoc;
        if( thingBox.getRealX() < nodeLoc.getRealX() ||
                thingBox.getRealX() > nodeLoc.getRealX() + nodeLoc.getRealWidth() )
            return false;
        if( thingBox.getRealX() + thingBox.getRealWidth() < nodeLoc.getRealX() ||
                thingBox.getRealX() + thingBox.getRealWidth() > nodeLoc.getRealX() + nodeLoc.getRealWidth() )
            return false;
        if( thingBox.getRealY() < nodeLoc.getRealY() ||
                thingBox.getRealY() > nodeLoc.getRealY() + nodeLoc.getRealHeight() )
            return false;
        if( thingBox.getRealY() + thingBox.getRealHeight() < nodeLoc.getRealY() ||
                thingBox.getRealY() + thingBox.getRealHeight() > nodeLoc.getRealY() + nodeLoc.getRealHeight() )
            return false;

        return true;
    }

    @Override
    public List< T > findColliding( T thing ) {
        List< T > theList = new LinkedList< T >();
        findCollidingRecursive( thing.getBox()[ 0 ], mHead, theList );
        return theList;
    }
   
    private void findCollidingRecursive( Box thingBox, Node< T > node, List< T > list ) {
        if( node == null )
            return;

        if( node.mTopLeft != null ) {           
            if( thingBox.intersectingWith( node.mTopLeft.mNodeLoc ) )
                findCollidingRecursive( thingBox, node.mTopLeft, list );
            if( thingBox.intersectingWith( node.mTopRight.mNodeLoc ) )
                findCollidingRecursive( thingBox, node.mTopRight, list );
            if( thingBox.intersectingWith( node.mBottomLeft.mNodeLoc ) )
                findCollidingRecursive( thingBox, node.mBottomLeft, list );
            if( thingBox.intersectingWith( node.mBottomRight.mNodeLoc ) )
                findCollidingRecursive( thingBox, node.mBottomRight, list );
        }
        else {
            for( T storedThing : node.mStoredItems ) {
                Box otherBox = storedThing.getBox()[ 0 ];
                if( thingBox.intersectingWith( otherBox ) ) {
                    list.add( storedThing );
                }
            }
        }
    }

    @Override
    public List< T > findCollidingBetween( T thing1, T thing2 ) {
        List< T > theList = new LinkedList< T >();
        Box box1 = thing1.getBox()[ 0 ];
        Box box2 = thing2.getBox()[ 0 ];
        Box totalBox = null;
        if( box1.getRealY() < box2.getRealY() ) {
            if( box1.getRealX() < box2.getRealX() ) {
                totalBox = Boxes.get( box1.getRealX(), box1.getRealY(), 0,
                        box2.getRealX() + box2.getRealWidth() - box1.getRealX(),
                        box2.getRealY() + box2.getRealHeight() - box1.getRealY(),
                        0 );
            }
            else {
                totalBox = Boxes.get( box1.getRealX() + box1.getRealWidth(), box1.getRealY(), 0,
                        box2.getRealX() - ( box1.getRealX() + box1.getRealWidth() ),
                        box2.getRealY() + box2.getRealHeight() - box1.getRealY(),
                        0 );
            }
        }
        else {
            if( box2.getRealX() < box1.getRealX() ) {
                Boxes.get( box2.getRealX(), box2.getRealY(), 0,
                        box1.getRealX() + box1.getRealWidth() - box2.getRealX(),
                        box1.getRealY() + box1.getRealHeight() - box2.getRealY(),
                        0 );
            }
            else {
                Boxes.get( box2.getRealX() + box2.getRealWidth(), box2.getRealY(), 0,
                        box1.getRealX() - ( box2.getRealX() + box2.getRealWidth() ),
                        box1.getRealY() + box1.getRealHeight() - box2.getRealY(),
                        0 );
            }
        }
        findCollidingRecursive( totalBox, mHead, theList );
        return theList;
    }

    @Override
    public void setNumItemsBeforeSplit( int num ) {
        mItemsToSplit = num;
    }

    @Override
    public int getNumItemsBeforeSplit() {
        return mItemsToSplit;
    }

    @Override
    public void setNumItemsBeforePrune( int num ) {
        mItemsToPrune = num;
    }

    @Override
    public int getNumItemsBeforePrune() {
        return mItemsToPrune;
    }

    @Override
    public void setMaxDepth( int depth ) {
        mMaxDepth = depth;
    }

    @Override
    public int getMaxDepth() {
        return mMaxDepth;
    }

    @Override
    public void buildTreeToDepth( int depth ) {
        depth = depth <= mMaxDepth ? depth : mMaxDepth;
        buildTreeToDepthRecursive( 0, depth, mHead );
    }

    private void buildTreeToDepthRecursive( int curDepth, int maxDepth, Node< T > node ) {
        if( curDepth == maxDepth )
            return;

        split( node, curDepth );
        buildTreeToDepthRecursive( curDepth + 1, maxDepth, node.mTopLeft );
        buildTreeToDepthRecursive( curDepth + 1, maxDepth, node.mTopRight );
        buildTreeToDepthRecursive( curDepth + 1, maxDepth, node.mBottomLeft );
        buildTreeToDepthRecursive( curDepth + 1, maxDepth, node.mBottomRight );
    }

    @Override
    public void resetTree( int maxDepth, int itemsToSplit, int itemsToPrune,
                            double width, double height ) {
        resetTreeRecursive( mHead );
        mHead = null;
        mHead = new Node< T >( 0, 0, width, height );
        mMaxDepth = maxDepth;
        mItemsToSplit = itemsToSplit;
        mItemsToPrune = itemsToPrune;
    }

    private void resetTreeRecursive( Node< T > node ) {
        if( node == null )
            return;

        resetTreeRecursive( node.mTopLeft );
        resetTreeRecursive( node.mTopRight );
        resetTreeRecursive( node.mBottomLeft );
        resetTreeRecursive( node.mBottomRight );
        node.mTopLeft = null;
        node.mTopRight = null;
        node.mBottomLeft = null;
        node.mBottomRight = null;
        node.mStoredItems.clear();
        node.mStoredItems = null;
        node.mNodeLoc = null;
    }
}
TOP

Related Classes of utils.SpacialQuadTree$Node

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.