NodeTransitPtr createTorus(void)
{
    // Make Object Nodes
    NodeRecPtr ExampleTorusGeo = makeTorus(90, 270, 16, 16);

    // Preform transformations on them
    Matrix mat;

    // On Torus    
    mat.setTranslate(0.0,100.0,-200.0);
    TransformRecPtr TorusTranCore = Transform::create();
    TorusTranCore->setMatrix(mat);

    NodeRecPtr ExampleTorus = Node::create();
    ExampleTorus->setCore(TorusTranCore);
    ExampleTorus->addChild(ExampleTorusGeo);
    ExampleTorus->setTravMask(0);

    return NodeTransitPtr(ExampleTorus);
}
NodeTransitPtr createBox(void)
{
    // Make Object Nodes
    NodeRecPtr ExampleBoxGeo = makeBox(100, 100, 100, 1, 1, 1);

    MaterialRecPtr GreenMaterial = createMaterial(Color4f(0.0f,1.0f,0.0f,1.0f));
    dynamic_cast<Geometry*>(ExampleBoxGeo->getCore())->setMaterial(GreenMaterial);

    Matrix mat;
    mat.setTranslate(250.0,250.0,0.0);

    TransformRecPtr ExampleBoxTranCore = Transform::create();
    ExampleBoxTranCore->setMatrix(mat);

    NodeRecPtr ExampleBox = Node::create();
    ExampleBox->setCore(ExampleBoxTranCore);
    ExampleBox->addChild(ExampleBoxGeo);
    ExampleBox->setTravMask(0);

    return NodeTransitPtr(ExampleBox);
}
NodeTransitPtr createSphere(void)
{
    // Make Object Nodes
    NodeRecPtr ExampleSphereGeo = makeSphere(4, 100);

    MaterialRecPtr RedMaterial = createMaterial(Color4f(1.0f,0.0f,0.0f,1.0f));
    dynamic_cast<Geometry*>(ExampleSphereGeo->getCore())->setMaterial(RedMaterial);

    Matrix mat;
    mat.setTranslate(250.0,0.0,0.0);

    TransformRecPtr SphereTranCore = Transform::create();
    SphereTranCore->setMatrix(mat);

    NodeRecPtr ExampleSphere = Node::create();
    ExampleSphere->setCore(SphereTranCore);
    ExampleSphere->addChild(ExampleSphereGeo);
    ExampleSphere->setTravMask(0);

    return NodeTransitPtr(ExampleSphere);
}
NodeTransitPtr createCone(void)
{
    // Make Object Nodes
    NodeRecPtr ExampleConeGeo = makeCone(150, 50, 16, true, true);

    MaterialRecPtr BlueMaterial = createMaterial(Color4f(0.0f,0.0f,1.0f,1.0f));
    dynamic_cast<Geometry*>(ExampleConeGeo->getCore())->setMaterial(BlueMaterial);

    // Preform transformations on them
    Matrix mat;

    // On Cone
    mat.setTranslate(0.0,0.0,-250.0);

    TransformRecPtr ConeTranCore = Transform::create();
    ConeTranCore->setMatrix(mat);

    NodeRecPtr ExampleCone = Node::create();
    ExampleCone->setCore(ConeTranCore);
    ExampleCone->addChild(ExampleConeGeo);
    ExampleCone->setTravMask(0);

    return NodeTransitPtr(ExampleCone);
}
// Initialize GLUT & OpenSG and set up the rootNode
int main(int argc, char **argv)
{
    // OSG init
    osgInit(argc,argv);

    {
        // Set up Window
        WindowEventProducerRecPtr TutorialWindow = createNativeWindow();
        TutorialWindow->initWindow();

        SimpleSceneManager sceneManager;
        TutorialWindow->setDisplayCallback(boost::bind(display, &sceneManager));
        TutorialWindow->setReshapeCallback(boost::bind(reshape, _1, &sceneManager));

        //Attach to events
        TutorialWindow->connectMousePressed(boost::bind(mousePressed, _1, &sceneManager));
        TutorialWindow->connectMouseReleased(boost::bind(mouseReleased, _1, &sceneManager));
        TutorialWindow->connectMouseMoved(boost::bind(mouseMoved, _1, &sceneManager));
        TutorialWindow->connectMouseDragged(boost::bind(mouseDragged, _1, &sceneManager));

        // Tell the Manager what to manage
        sceneManager.setWindow(TutorialWindow);

        UInt32 SceneMask(1),
               NanobotMask(2),
               PathMask(4);

        BoostPath SceneFilePath(".//Data//CellParts.osb");

        if(argc >= 2)
        {
            SceneFilePath = BoostPath(argv[1]);
            if(!boost::filesystem::exists(SceneFilePath))
            {
                SceneFilePath = BoostPath(".//Data//CellParts.osb");
            }
        }

        //Make Base Geometry Node
        NodeRecPtr SceneGeometryNode =
            SceneFileHandler::the()->read(SceneFilePath.string().c_str());
        SceneGeometryNode->setTravMask(SceneMask);
        if(SceneGeometryNode == NULL)
        {
            SceneGeometryNode = makeTorus(1.0, 10.0, 24, 24);
        }
        //Construct the Root Node
        NodeRecPtr RootNode = makeCoredNode<Group>();
        RootNode->addChild(SceneGeometryNode);

        commitChanges();

        //Create the Octree

        SLOG << "Started Building Octree" << std::endl;
        SLOG << "This may take some time ..." << std::endl;
        Time StartTime;
        StartTime = getSystemTime();
		OctreePtr TheOctree =
            Octree::buildTree(RootNode,SceneMask,6,0.5,true);

        SLOG << "Building Octree: " << getSystemTime() - StartTime << " s" << std::endl;
        Pnt3f Min,Max;
        TheOctree->getRoot()->getVolume();
        SLOG << "Octree: "<< std::endl
             << "    Depth: " << TheOctree->getDepth() << std::endl
             << "    Bounds: " << TheOctree->getRoot()->getVolume().getMin() << "  :  " << TheOctree->getRoot()->getVolume().getMax() << std::endl
             << "    NodeCount: " << TheOctree->getNodeCount() << std::endl
             << "    LeafNodeCount: " << TheOctree->getLeafNodeCount() << std::endl
             << "    BranchNodeCount: " << TheOctree->getBranchNodeCount() << std::endl
             << "    IntersectingNodeCount: " << TheOctree->getIntersectingNodeCount() << std::endl
             << "    IntersectingLeafNodeCount: " << TheOctree->getIntersectingLeafNodeCount() << std::endl;

        //Make the Nanobot Nodes
        BoostPath NanobotFilePath(".//Data//Nanobot.osb");
        NodeRecPtr NanobotGeoNode =
            SceneFileHandler::the()->read(NanobotFilePath.string().c_str());

        NanobotVector Nanobots;

        UInt32 NumNanobots(3);
        for(UInt32 i(0) ; i<NumNanobots ; ++i)
        {
            NanobotDetails TheDetails;

            //Get the Transform node for the Nanobot
            TheDetails._Transform = Transform::create();
            Matrix NanobotMatrix;
            
            Pnt3f Min,Max;
            SceneGeometryNode->getVolume().getBounds(Min,Max);
            Min = Min + ShrinkFactor;
            Max = Max - ShrinkFactor;
            NanobotMatrix.setTranslate(randomOpenPosition(Min,Max,TheOctree).subZero());
            NanobotMatrix.setScale(0.06f);
            TheDetails._Transform->setMatrix(NanobotMatrix);

            TheDetails._Node = makeNodeFor(TheDetails._Transform);
            TheDetails._Node->addChild(cloneTree(NanobotGeoNode));
            TheDetails._Node->setTravMask(NanobotMask);
            
            TheDetails._PathVisNode = Node::create();

            Nanobots.push_back(TheDetails);

            makeNanobotPath(Nanobots.back(), TheOctree, TutorialWindow, Min,Max);
        }

        for(UInt32 i(0) ; i<Nanobots.size() ; ++i)
        {
            RootNode->addChild(Nanobots[i]._Node);
            RootNode->addChild(Nanobots[i]._PathVisNode);
        }
        commitChanges();


        //NodeRecPtr StartNode = makeSphere(1.0, 2);
        //TransformRecPtr StartNodeTransform = Transform::create();
        //Matrix StartNodeMatrix;
        //StartNodeMatrix.setTranslate(Start);
        //StartNodeMatrix.setScale(0.1f);
        //StartNodeTransform->setMatrix(StartNodeMatrix);
        //NodeRecPtr StartNodeTransformNode = makeNodeFor(StartNodeTransform);
        //StartNodeTransformNode->addChild(StartNode);
        //StartNodeTransformNode->setTravMask(PathMask);
        //RootNode->addChild(StartNodeTransformNode);

        //NodeRecPtr GoalNode = makeSphere(1.0, 2);
        //TransformRecPtr GoalNodeTransform = Transform::create();
        //Matrix GoalNodeMatrix;
        //GoalNodeMatrix.setScale(0.1f);
        //GoalNodeMatrix.setTranslate(Goal);
        //GoalNodeTransform->setMatrix(GoalNodeMatrix);
        //NodeRecPtr GoalNodeTransformNode = makeNodeFor(GoalNodeTransform);
        //GoalNodeTransformNode->addChild(GoalNode);
        //GoalNodeTransformNode->setTravMask(PathMask);
        //RootNode->addChild(GoalNodeTransformNode);

        TutorialWindow->connectKeyPressed(boost::bind(keyPressed, _1,
                                                      TutorialWindow.get(),
                                                      SceneGeometryNode.get(),
                                                      TheOctree,
                                                      Nanobots));


        //Set the background
        SolidBackgroundRecPtr TheBackground = SolidBackground::create();
        TheBackground->setColor(Color3f(0.0f,0.0f,0.0f));

        // tell the manager what to manage
        sceneManager.setRoot  (RootNode);
        sceneManager.getWindow()->getPort(0)->setBackground(TheBackground);

        // show the whole RootNode
        sceneManager.showAll();

        Vec2f WinSize(TutorialWindow->getDesktopSize() * 0.85f);
        Pnt2f WinPos((TutorialWindow->getDesktopSize() - WinSize) *0.5);
        TutorialWindow->openWindow(WinPos,
                                   WinSize,
                                   "01AStarPathing");

        //Enter main Loop
        TutorialWindow->mainLoop();
    }

    osgExit();

    return 0;
}
// Initialize GLUT & OpenSG and set up the rootNode
int main(int argc, char **argv)
{
    // OSG init
    osgInit(argc,argv);

    {
        // Set up Window
        WindowEventProducerRecPtr TutorialWindow = createNativeWindow();
        TutorialWindow->initWindow();

        SimpleSceneManager sceneManager;
        TutorialWindow->setDisplayCallback(boost::bind(display, &sceneManager));
        TutorialWindow->setReshapeCallback(boost::bind(reshape, _1, &sceneManager));

        //Attach to events
        TutorialWindow->connectMousePressed(boost::bind(mousePressed, _1, &sceneManager));
        TutorialWindow->connectMouseReleased(boost::bind(mouseReleased, _1, &sceneManager));
        TutorialWindow->connectMouseMoved(boost::bind(mouseMoved, _1, &sceneManager));
        TutorialWindow->connectMouseDragged(boost::bind(mouseDragged, _1, &sceneManager));
        TutorialWindow->connectMouseWheelMoved(boost::bind(mouseWheelMoved, _1, &sceneManager));

        // Tell the Manager what to manage
        sceneManager.setWindow(TutorialWindow);

        //Make Base Geometry Node
        NodeRecPtr TriGeometryBase = makeTorus(0.5, 1.0, 24, 24);

        //Make Main Scene Node
        NodeRecPtr scene = makeCoredNode<Group>();
        setName(scene, "scene");
        NodeRecPtr rootNode = Node::create();
        setName(rootNode, "rootNode");
        ComponentTransformRecPtr Trans;
        Trans = ComponentTransform::create();
        rootNode->setCore(Trans);

        // add the torus as a child
        rootNode->addChild(scene);

        //Make The Physics Characteristics Node
        PhysicsCharacteristicsDrawableRecPtr PhysDrawable = PhysicsCharacteristicsDrawable::create();
        PhysDrawable->setRoot(rootNode);

        NodeRecPtr PhysDrawableNode = Node::create();
        PhysDrawableNode->setCore(PhysDrawable);
        PhysDrawableNode->setTravMask(TypeTraits<UInt32>::getMin());

        rootNode->addChild(PhysDrawableNode);


        //Setup Physics Scene
        PhysicsWorldRecPtr physicsWorld = PhysicsWorld::create();
        physicsWorld->setWorldContactSurfaceLayer(0.005);
        physicsWorld->setAutoDisableFlag(1);
        physicsWorld->setAutoDisableTime(0.75);
        physicsWorld->setWorldContactMaxCorrectingVel(100.0);
        physicsWorld->setGravity(Vec3f(0.0, 0.0, -9.81));

        PhysicsHashSpaceRecPtr physicsSpace = PhysicsHashSpace::create();

        PhysicsHandlerRecPtr physHandler = PhysicsHandler::create();
        physHandler->setWorld(physicsWorld);
        physHandler->pushToSpaces(physicsSpace);
        physHandler->setUpdateNode(rootNode);

        physHandler->attachUpdateProducer(TutorialWindow);


        /************************************************************************/
        /* create spaces, geoms and bodys                                       */
        /************************************************************************/
        //create a group for our space
        GroupRecPtr spaceGroup;
        NodeRecPtr spaceGroupNode = makeCoredNode<Group>(&spaceGroup);
        //create the ground plane
        GeometryRecPtr plane;
        NodeRecPtr planeNode = makeBox(30.0, 30.0, 1.0, 1, 1, 1);
        plane = dynamic_cast<Geometry*>(planeNode->getCore());
        //and its Material
        SimpleMaterialRecPtr plane_mat = SimpleMaterial::create();
        plane_mat->setAmbient(Color3f(0.7,0.7,0.7));
        plane_mat->setDiffuse(Color3f(0.9,0.6,1.0));

        plane->setMaterial(plane_mat);



        //create Physical Attachments
        PhysicsBoxGeomRecPtr planeGeom = PhysicsBoxGeom::create();
        planeGeom->setLengths(Vec3f(30.0, 30.0, 1.0));
        //add geoms to space for collision
        planeGeom->setSpace(physicsSpace);


        //add Attachments to nodes...
        spaceGroupNode->addAttachment(physicsSpace);
        spaceGroupNode->addAttachment(physHandler);    
        spaceGroupNode->addAttachment(physicsWorld);
        spaceGroupNode->addChild(planeNode);


        planeNode->addAttachment(planeGeom);


        scene->addChild(spaceGroupNode);


        //Create Statistics Foreground
        SimpleStatisticsForegroundRecPtr PhysicsStatForeground = SimpleStatisticsForeground::create();
        PhysicsStatForeground->setSize(25);
        PhysicsStatForeground->setColor(Color4f(0,1,0,0.7));
        PhysicsStatForeground->addElement(WindowEventProducer::statWindowLoopTime, "Draw FPS: %r.3f");
        PhysicsStatForeground->getCollector()->getElem(WindowEventProducer::statWindowLoopTime, true);
        PhysicsStatForeground->addElement(RenderAction::statNGeometries, 
                                         "%d Nodes drawn");
        PhysicsStatForeground->getCollector()->getElem(RenderAction::statNGeometries, true);
        PhysicsStatForeground->addElement(PhysicsHandler::statPhysicsTime, 
                                          "Physics time: %.3f s");
        PhysicsStatForeground->getCollector()->getElem(PhysicsHandler::statPhysicsTime, true);
        PhysicsStatForeground->addElement(PhysicsHandler::statCollisionTime, 
                                          "Collision time: %.3f s");
        PhysicsStatForeground->getCollector()->getElem(PhysicsHandler::statCollisionTime, true);
        PhysicsStatForeground->addElement(PhysicsHandler::statSimulationTime, 
                                          "Simulation time: %.3f s");
        PhysicsStatForeground->getCollector()->getElem(PhysicsHandler::statSimulationTime, true);
        PhysicsStatForeground->addElement(PhysicsHandler::statNCollisions, 
                                          "%d collisions");
        PhysicsStatForeground->getCollector()->getElem(PhysicsHandler::statNCollisions, true);
        PhysicsStatForeground->addElement(PhysicsHandler::statNCollisionTests, 
                                          "%d collision tests");
        PhysicsStatForeground->getCollector()->getElem(PhysicsHandler::statNCollisionTests, true);
        PhysicsStatForeground->addElement(PhysicsHandler::statNPhysicsSteps, 
                                          "%d simulation steps per frame");
        PhysicsStatForeground->getCollector()->getElem(PhysicsHandler::statNPhysicsSteps, true);
        TutorialWindow->connectUpdate(boost::bind(handleStatisticsReset, _1), boost::signals2::at_front);
        StatCollector::setGlobalCollector(PhysicsStatForeground->getCollector());


        SimpleStatisticsForegroundRecPtr RenderStatForeground = SimpleStatisticsForeground::create();
        RenderStatForeground->setSize(25);
        RenderStatForeground->setColor(Color4f(0,1,0,0.7));





        // tell the manager what to manage
        sceneManager.setRoot  (rootNode);

        sceneManager.getWindow()->getPort(0)->addForeground(PhysicsStatForeground);
        sceneManager.getWindow()->getPort(0)->addForeground(RenderStatForeground);

        
        TutorialWindow->connectKeyPressed(boost::bind(keyPressed, _1,
            TriGeometryBase.get(),
            spaceGroupNode.get(),
            PhysDrawableNode.get(),
            physicsWorld.get(),
            physicsSpace.get()));

        // show the whole rootNode
        sceneManager.getNavigator()->set(Pnt3f(20.0,20.0,10.0), Pnt3f(0.0,0.0,0.0), Vec3f(0.0,0.0,1.0));
        sceneManager.getNavigator()->setMotionFactor(1.0f);
        sceneManager.getCamera()->setFar(10000.0f);
        sceneManager.getCamera()->setNear(0.1f);

        Vec2f WinSize(TutorialWindow->getDesktopSize() * 0.85f);
        Pnt2f WinPos((TutorialWindow->getDesktopSize() - WinSize) *0.5);
        TutorialWindow->openWindow(WinPos,
                                   WinSize,
                                   "01SimplePhysics");

        //Enter main Loop
        TutorialWindow->mainLoop();
    }

    osgExit();

    return 0;
}
// Initialize GLUT & OpenSG and set up the rootNode
int main(int argc, char **argv)
{
    // OSG init
    osgInit(argc,argv);

    {
        // Set up Window
        WindowEventProducerRecPtr TutorialWindow = createNativeWindow();
        TutorialWindow->initWindow();

        SimpleSceneManager sceneManager;
        TutorialWindow->setDisplayCallback(boost::bind(display, &sceneManager));
        TutorialWindow->setReshapeCallback(boost::bind(reshape, _1, &sceneManager));

        //Attach to events
        TutorialWindow->connectMousePressed(boost::bind(mousePressed, _1, &sceneManager));
        TutorialWindow->connectMouseReleased(boost::bind(mouseReleased, _1, &sceneManager));
        TutorialWindow->connectMouseMoved(boost::bind(mouseMoved, _1, &sceneManager));
        TutorialWindow->connectMouseDragged(boost::bind(mouseDragged, _1, &sceneManager));
        TutorialWindow->connectKeyPressed(boost::bind(keyPressed,_1));

        // Tell the Manager what to manage
        sceneManager.setWindow(TutorialWindow);

        UInt32 SceneMask(1),
               PathMask(4);

        BoostPath SceneFilePath(".//Data//CellParts.osb");

        if(argc >= 2)
        {
            SceneFilePath = BoostPath(argv[1]);
            if(!boost::filesystem::exists(SceneFilePath))
            {
                SceneFilePath = BoostPath(".//Data//CellParts.osb");
            }
        }

        //Make Base Geometry Node
        NodeRecPtr SceneGeometryNode =
            SceneFileHandler::the()->read(SceneFilePath.string().c_str());
        SceneGeometryNode->setTravMask(SceneMask);
        if(SceneGeometryNode == NULL)
        {
            SceneGeometryNode = makeTorus(1.0, 10.0, 24, 24);
        }

        //Construct the Root Node
        NodeRecPtr RootNode = makeCoredNode<Group>();
        RootNode->addChild(SceneGeometryNode);
        commitChanges();

        //Create the Octree

        SLOG << "Started Building Octree" << std::endl;
        SLOG << "This may take some time ..." << std::endl;
        Time StartTime;
        StartTime = getSystemTime();
		OctreePtr TheOctree =
            Octree::buildTree(RootNode,SceneMask,6,1.5,true);

        SLOG << "Building Octree: " << getSystemTime() - StartTime << " s" << std::endl;
        Pnt3f Min,Max;
        TheOctree->getRoot()->getVolume();
        SLOG << "Octree: "<< std::endl
             << "    Depth: " << TheOctree->getDepth() << std::endl
             << "    Bounds: " << TheOctree->getRoot()->getVolume().getMin() << "  :  " << TheOctree->getRoot()->getVolume().getMax() << std::endl
             << "    NodeCount: " << TheOctree->getNodeCount() << std::endl
             << "    LeafNodeCount: " << TheOctree->getLeafNodeCount() << std::endl
             << "    BranchNodeCount: " << TheOctree->getBranchNodeCount() << std::endl
             << "    IntersectingNodeCount: " << TheOctree->getIntersectingNodeCount() << std::endl
             << "    IntersectingLeafNodeCount: " << TheOctree->getIntersectingLeafNodeCount() << std::endl;

        //Create the Path Geometry
        //Generate the Path
        OctreeAStarAlgorithm AlgorithmObj;
        SLOG << "Started AStar Search" << std::endl;
        StartTime = getSystemTime();
        Pnt3f Start(-4.01f,1.01f,10.01f),Goal(-4.01f,-0.01f,-7.01f);
        std::vector<Pnt3f> Path =
            AlgorithmObj.search(TheOctree,Start,Goal);
        Path.front() = Start;
        Path.back() = Goal;
        SLOG << "Finished AStar Search: " << getSystemTime() - StartTime << " s" << std::endl;

        NodeRecPtr PathNode = createPathGeometry(Path);
        PathNode->setTravMask(PathMask);
        RootNode->addChild(PathNode);

        NodeRecPtr StartNode = makeSphere(1.0, 2);
        TransformRecPtr StartNodeTransform = Transform::create();
        Matrix StartNodeMatrix;
        StartNodeMatrix.setTranslate(Start);
        StartNodeMatrix.setScale(0.1f);
        StartNodeTransform->setMatrix(StartNodeMatrix);
        NodeRecPtr StartNodeTransformNode = makeNodeFor(StartNodeTransform);
        StartNodeTransformNode->addChild(StartNode);
        StartNodeTransformNode->setTravMask(PathMask);
        RootNode->addChild(StartNodeTransformNode);

        NodeRecPtr GoalNode = makeSphere(1.0, 2);
        TransformRecPtr GoalNodeTransform = Transform::create();
        Matrix GoalNodeMatrix;
        GoalNodeMatrix.setScale(0.1f);
        GoalNodeMatrix.setTranslate(Goal);
        GoalNodeTransform->setMatrix(GoalNodeMatrix);
        NodeRecPtr GoalNodeTransformNode = makeNodeFor(GoalNodeTransform);
        GoalNodeTransformNode->addChild(GoalNode);
        GoalNodeTransformNode->setTravMask(PathMask);
        RootNode->addChild(GoalNodeTransformNode);


        //Set the background
        SolidBackgroundRecPtr TheBackground = SolidBackground::create();
        TheBackground->setColor(Color3f(0.0f,0.0f,0.0f));

        // tell the manager what to manage
        sceneManager.setRoot  (RootNode);
        sceneManager.getWindow()->getPort(0)->setBackground(TheBackground);

        // show the whole RootNode
        sceneManager.showAll();

        Vec2f WinSize(TutorialWindow->getDesktopSize() * 0.85f);
        Pnt2f WinPos((TutorialWindow->getDesktopSize() - WinSize) *0.5);
        TutorialWindow->openWindow(WinPos,
                                   WinSize,
                                   "01AStarPathing");

        //Enter main Loop
        TutorialWindow->mainLoop();
    }

    osgExit();

    return 0;
}