Hi again, 

Forgot to attach the last two files with fixes to the virtual inheritance 
warnings...

I have also attached the fix to the type shadowing problem in 
ConvexPolyhedron.cpp

With this I think that the OSG Core group of projects compiles without warnings 
on Visual Studio 2015.

Regards
Björn

>-----Original Message-----
>From: osg-users [mailto:[email protected]] On
>Behalf Of Björn Blissing
>Sent: Friday, June 3, 2016 3:35 PM
>To: OpenSceneGraph Users <[email protected]>
>Subject: Re: [osg-users] Preparing to make 3.5.3 dev release, please test
>
>Hi again,
>
>This is the fix for the rest of the virtual inheritance warnings. Same as for
>issues as for the Operation class.
>
>Regards
>Björn
>
>>-----Original Message-----
>>From: osg-users [mailto:[email protected]] On
>>Behalf Of Björn Blissing
>>Sent: Friday, June 3, 2016 2:39 PM
>>To: OpenSceneGraph Users <[email protected]>
>>Subject: Re: [osg-users] Preparing to make 3.5.3 dev release, please test
>>
>>Hi Robert,
>>
>>The warnings relating the Operation class comes from the two protected
>>constructors. Since the class uses virtual inheritance it is initialized by 
>>the
>most
>>derived class. So the initializer for the virtual base class is ignored.
>>
>>So just removing the base class initializer for Operation will remove this
>>warning. I do not think this will have any negative side effects, since base
>class
>>initializer should be ignored by all compliant compilers anyway.
>>
>>I have attached the changed file.
>>
>>Regards
>>Björn
>>
>>>-----Original Message-----
>>>From: osg-users [mailto:[email protected]] On
>>>Behalf Of Robert Osfield
>>>Sent: Friday, June 3, 2016 1:46 PM
>>>To: OpenSceneGraph Users <[email protected]>
>>>Subject: Re: [osg-users] Preparing to make 3.5.3 dev release, please test
>>>
>>>Hi Bjorn,
>>>
>>>On 3 June 2016 at 09:48, Björn Blissing <[email protected]> wrote:
>>>>
>>>> I compiled the latest master with Visual Studio 2015.
>>>>
>>>> I got a couple of warnings.  First of all I got a ton of these, which all
>>originates
>>>from the same origin:
>>>>
>>>>
>>>> Code:
>>>>
>>>> ...
>>>> OpenSceneGraph\include\osg/OperationThread(80): warning C4589:
>>>Constructor of abstract class 'osg::Operation' ignores initializer for 
>>>virtual
>>base
>>>class 'osg::Referenced' (compiling source file
>>>D:\github\OpenSceneGraph\src\osg\AnimationPath.cpp)
>>>>   OpenSceneGraph\include\osg/OperationThread(80): note: virtual base
>>>classes are only initialized by the most-derived type (compiling source file
>>>D:\github\OpenSceneGraph\src\osg\AnimationPath.cpp)
>>>> ...
>>>>
>>>>
>>>>
>>>>
>>>> And the same warnings for the following classes:
>>>>
>>>>
>>>> Code:
>>>>
>>>> OpenSceneGraph\src\osgGA\CameraManipulator.cpp(24): warning
>C4589:
>>>Constructor of abstract class 'osgGA::CameraManipulator' ignores initializer
>>for
>>>virtual base class 'osg::Callback'
>>>>   OpenSceneGraph\src\osgGA\CameraManipulator.cpp(24): note: virtual
>>>base classes are only initialized by the most-derived type
>>>> OpenSceneGraph\src\osgGA\StandardManipulator.cpp(51): warning
>>C4589:
>>>Constructor of abstract class 'osgGA::StandardManipulator' ignores
>initializer
>>>for virtual base class 'osg::Callback'
>>>>   OpenSceneGraph\src\osgGA\StandardManipulator.cpp(51): note:
>virtual
>>>base classes are only initialized by the most-derived type
>>>> OpenSceneGraph\src\osgViewer\ViewerBase.cpp(44): warning C4589:
>>>Constructor of abstract class 'osgViewer::ViewerBase' ignores initializer for
>>>virtual base class 'osg::Object'
>>>>   OpenSceneGraph\src\osgViewer\ViewerBase.cpp(44): note: virtual
>base
>>>classes are only initialized by the most-derived type
>>>> OpenSceneGraph\src\osgViewer\ViewerBase.cpp(50): warning C4589:
>>>Constructor of abstract class 'osgViewer::ViewerBase' ignores initializer for
>>>virtual base class 'osg::Object'
>>>>   OpenSceneGraph\src\osgViewer\ViewerBase.cpp(50): note: virtual
>base
>>>classes are only initialized by the most-derived type
>>>> OpenSceneGraph\src\osgAnimation\AnimationManagerBase.cpp(65):
>>>warning C4589: Constructor of abstract class
>>>'osgAnimation::AnimationManagerBase' ignores initializer for virtual base
>>class
>>>'osg::Callback'
>>>>   OpenSceneGraph\src\osgAnimation\AnimationManagerBase.cpp(65):
>>>note: virtual base classes are only initialized by the most-derived type
>>>
>>>Unfortunately I don't see these warnings with the compiler I have
>>>available with the settings that are currently available.  Do you know
>>>of what to enable these warnings in gcc or Clang?
>>>
>>>The nature of these warnings are such that I really need to be able to
>>>see the warning first hand and attempt a local fix to see the affect.
>>>
>>>Cheers,
>>>Robert.
>>>_______________________________________________
>>>osg-users mailing list
>>>[email protected]
>>>http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org
/*  -*-c++-*-
 *  Copyright (C) 2008 Cedric Pinson <[email protected]>
 *
 * This library is open source and may be redistributed and/or modified under
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 *
 * 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
 * OpenSceneGraph Public License for more details.
*/

#include <osgAnimation/AnimationManagerBase>
#include <osgAnimation/LinkVisitor>
#include <algorithm>

using namespace osgAnimation;

AnimationManagerBase::~AnimationManagerBase() {}

AnimationManagerBase::AnimationManagerBase()
{
    _needToLink = false;
    _automaticLink = true;
}

void AnimationManagerBase::clearTargets()
{
    for (TargetSet::iterator it = _targets.begin(); it != _targets.end(); ++it)
        (*it).get()->reset();
}

void AnimationManagerBase::dirty()
{
    _needToLink = true;
}

void AnimationManagerBase::setAutomaticLink(bool state) { _automaticLink = 
state; }
bool AnimationManagerBase::getAutomaticLink() const { return _automaticLink; }

void AnimationManagerBase::operator()(osg::Node* node, osg::NodeVisitor* nv)
{
    if (nv && nv->getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR)
    {
        if (needToLink())
        {
            /** manager need to link, it means that an animation has been added
                so we need to relink all item animated with all animations.
                We apply the linker visitor on the manager node to affect
                all its children.
                But it should not be done here, it should be done in the
                update of AnimationManager
            */
            link(node);
        }
        const osg::FrameStamp* fs = nv->getFrameStamp();
        update(fs->getSimulationTime());
    }
    traverse(node,nv);
}


AnimationManagerBase::AnimationManagerBase(const AnimationManagerBase& b, const 
osg::CopyOp& copyop) : osg::NodeCallback(b,copyop) // TODO check this
{
    const AnimationList& animationList = b.getAnimationList();
    for (AnimationList::const_iterator it = animationList.begin();
         it != animationList.end();
         ++it)
    {
        Animation* animation = 
dynamic_cast<osgAnimation::Animation*>(it->get()->clone(copyop));
        _animations.push_back(animation);
    }
    _needToLink = true;
    _automaticLink = b._automaticLink;
    buildTargetReference();
}

void AnimationManagerBase::buildTargetReference()
{
    _targets.clear();
    for( AnimationList::iterator iterAnim = _animations.begin(); iterAnim != 
_animations.end(); ++iterAnim )
    {
        Animation* anim = (*iterAnim).get();
        for (ChannelList::iterator it = anim->getChannels().begin();
             it != anim->getChannels().end();
             ++it)
            _targets.insert((*it)->getTarget());
    }
}


void AnimationManagerBase::registerAnimation (Animation* animation)
{
    _needToLink = true;
    _animations.push_back(animation);
    buildTargetReference();
}

void AnimationManagerBase::unregisterAnimation (Animation* animation)
{
    AnimationList::iterator it = std::find(_animations.begin(), 
_animations.end(), animation);
    if (it != _animations.end())
    {
        _animations.erase(it);
    }
    buildTargetReference();
}

bool AnimationManagerBase::needToLink() const { return _needToLink && 
getAutomaticLink(); }


void AnimationManagerBase::setLinkVisitor(LinkVisitor* visitor)
{
    _linker = visitor;
}

LinkVisitor* AnimationManagerBase::getOrCreateLinkVisitor()
{
    if (!_linker.valid())
        _linker = new LinkVisitor;
    return _linker.get();
}

void AnimationManagerBase::link(osg::Node* subgraph)
{
    LinkVisitor* linker = getOrCreateLinkVisitor();
    linker->getAnimationList().clear();
    linker->getAnimationList() = _animations;

    subgraph->accept(*linker);
    _needToLink = false;
    buildTargetReference();
}
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
 *
 * This library is open source and may be redistributed and/or modified under
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 *
 * 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
 * OpenSceneGraph Public License for more details.
*/

#include <stdlib.h>
#include <string.h>

#include <osgViewer/ViewerBase>
#include <osgViewer/View>
#include <osgViewer/Renderer>

#include <osg/io_utils>

#include <osg/TextureCubeMap>
#include <osg/TextureRectangle>
#include <osg/TexMat>
#include <osg/DeleteHandler>

#include <osgDB/Registry>

#include <osgUtil/Optimizer>
#include <osgUtil/IntersectionVisitor>
#include <osgUtil/Statistics>

static osg::ApplicationUsageProxy 
ViewerBase_e0(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_CONFIG_FILE 
<filename>","Specify a viewer configuration file to load by default.");
static osg::ApplicationUsageProxy 
ViewerBase_e1(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_THREADING 
<value>","Set the threading model using by Viewer, <value> can be 
SingleThreaded, CullDrawThreadPerContext, DrawThreadPerContext or 
CullThreadPerCameraDrawThreadPerContext.");
static osg::ApplicationUsageProxy 
ViewerBase_e2(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_SCREEN 
<value>","Set the default screen that windows should open up on.");
static osg::ApplicationUsageProxy 
ViewerBase_e3(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_WINDOW x y 
width height","Set the default window dimensions that windows should open up 
on.");
static osg::ApplicationUsageProxy 
ViewerBase_e4(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_RUN_FRAME_SCHEME","Frame
 rate manage scheme that viewer run should use,  ON_DEMAND or CONTINUOUS 
(default).");
static osg::ApplicationUsageProxy 
ViewerBase_e5(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_RUN_MAX_FRAME_RATE","Set
 the maximum number of frame as second that viewer run. 0.0 is default and 
disables an frame rate capping.");

using namespace osgViewer;

ViewerBase::ViewerBase()
{
    viewerBaseInit();
}

ViewerBase::ViewerBase(const ViewerBase&)
{
    viewerBaseInit();
}

void ViewerBase::viewerBaseInit()
{
    _firstFrame = true;
    _done = false;
    _keyEventSetsDone = osgGA::GUIEventAdapter::KEY_Escape;
    _quitEventSetsDone = true;
    _releaseContextAtEndOfFrameHint = true;
    _threadingModel = AutomaticSelection;
    _threadsRunning = false;
    _endBarrierPosition = AfterSwapBuffers;
    _endBarrierOperation = osg::BarrierOperation::NO_OPERATION;
    _requestRedraw = true;
    _requestContinousUpdate = false;

    _runFrameScheme = CONTINUOUS;
    _runMaxFrameRate = 0.0f;

    const char* str = getenv("OSG_RUN_FRAME_SCHEME");
    if (str)
    {
        if      (strcmp(str, "ON_DEMAND")==0) _runFrameScheme = ON_DEMAND;
        else if (strcmp(str, "CONTINUOUS")==0) _runFrameScheme = CONTINUOUS;
    }

    str = getenv("OSG_RUN_MAX_FRAME_RATE");
    if (str)
    {
        _runMaxFrameRate = osg::asciiToDouble(str);
    }
}

void ViewerBase::setThreadingModel(ThreadingModel threadingModel)
{
    if (_threadingModel == threadingModel) return;

    if (_threadsRunning) stopThreading();

    _threadingModel = threadingModel;

    if (isRealized() && _threadingModel!=SingleThreaded) startThreading();
}

ViewerBase::ThreadingModel ViewerBase::suggestBestThreadingModel()
{
    const char* str = getenv("OSG_THREADING");
    if (str)
    {
        if (strcmp(str,"SingleThreaded")==0) return SingleThreaded;
        else if (strcmp(str,"CullDrawThreadPerContext")==0) return 
CullDrawThreadPerContext;
        else if (strcmp(str,"DrawThreadPerContext")==0) return 
DrawThreadPerContext;
        else if (strcmp(str,"CullThreadPerCameraDrawThreadPerContext")==0) 
return CullThreadPerCameraDrawThreadPerContext;
    }

    Contexts contexts;
    getContexts(contexts);

    if (contexts.empty()) return SingleThreaded;

#if 0
    // temporary hack to disable multi-threading under Windows till we find 
good solutions for
    // crashes that users are seeing.
    return SingleThreaded;
#endif

    Cameras cameras;
    getCameras(cameras);

    if (cameras.empty()) return SingleThreaded;


    int numProcessors = OpenThreads::GetNumberOfProcessors();

    if (contexts.size()==1)
    {
        if (numProcessors==1) return SingleThreaded;
        else return DrawThreadPerContext;
    }

#if 1
    if (numProcessors >= static_cast<int>(cameras.size()+contexts.size()))
    {
        return CullThreadPerCameraDrawThreadPerContext;
    }
#endif

    return DrawThreadPerContext;
}

void ViewerBase::setUpThreading()
{
    Contexts contexts;
    getContexts(contexts);

    if (_threadingModel==SingleThreaded)
    {
        if (_threadsRunning) stopThreading();
        else
        {
            // we'll set processor affinity here to help single threaded apps
            // with multiple processor cores, and using the database pager.
            int numProcessors = OpenThreads::GetNumberOfProcessors();
            bool affinity = numProcessors>1;
            if (affinity)
            {
                OpenThreads::SetProcessorAffinityOfCurrentThread(0);

                Scenes scenes;
                getScenes(scenes);

                for(Scenes::iterator scitr = scenes.begin();
                    scitr != scenes.end();
                    ++scitr)
                {
                    if ((*scitr)->getSceneData())
                    {
                        // update the scene graph so that it has enough GL 
object buffer memory for the graphics contexts that will be using it.
                        
(*scitr)->getSceneData()->resizeGLObjectBuffers(osg::DisplaySettings::instance()->getMaxNumberOfGraphicsContexts());
                    }
                }
            }
        }
    }
    else
    {
        if (!_threadsRunning) startThreading();
    }

}

void ViewerBase::setEndBarrierPosition(BarrierPosition bp)
{
    if (_endBarrierPosition == bp) return;

    if (_threadsRunning) stopThreading();

    _endBarrierPosition = bp;

    if (_threadingModel!=SingleThreaded) startThreading();
}

void ViewerBase::setEndBarrierOperation(osg::BarrierOperation::PreBlockOp op)
{
    if (_endBarrierOperation == op) return;

    if (_threadsRunning) stopThreading();

    _endBarrierOperation = op;

    if (_threadingModel!=SingleThreaded) startThreading();
}

void ViewerBase::stopThreading()
{
    if (!_threadsRunning) return;

    OSG_INFO<<"ViewerBase::stopThreading() - stopping threading"<<std::endl;

    Contexts contexts;
    getContexts(contexts);

    Cameras cameras;
    getCameras(cameras);

    Contexts::iterator gcitr;
    Cameras::iterator citr;

    for(Cameras::iterator camItr = cameras.begin();
        camItr != cameras.end();
        ++camItr)
    {
        osg::Camera* camera = *camItr;
        Renderer* renderer = dynamic_cast<Renderer*>(camera->getRenderer());
        if (renderer) renderer->release();
    }

    // delete all the graphics threads.
    for(gcitr = contexts.begin();
        gcitr != contexts.end();
        ++gcitr)
    {
        (*gcitr)->setGraphicsThread(0);
    }

    // delete all the camera threads.
    for(citr = cameras.begin();
        citr != cameras.end();
        ++citr)
    {
        (*citr)->setCameraThread(0);
    }

    for(Cameras::iterator camItr = cameras.begin();
        camItr != cameras.end();
        ++camItr)
    {
        osg::Camera* camera = *camItr;
        Renderer* renderer = dynamic_cast<Renderer*>(camera->getRenderer());
        if (renderer)
        {
            renderer->setGraphicsThreadDoesCull( true );
            renderer->setDone(false);
        }
    }


    _threadsRunning = false;
    _startRenderingBarrier = 0;
    _endRenderingDispatchBarrier = 0;
    _endDynamicDrawBlock = 0;

    OSG_INFO<<"Viewer::stopThreading() - stopped threading."<<std::endl;
}

void ViewerBase::startThreading()
{
    if (_threadsRunning) return;

    OSG_INFO<<"Viewer::startThreading() - starting threading"<<std::endl;

    // release any context held by the main thread.
    releaseContext();

    _threadingModel = _threadingModel==AutomaticSelection ? 
suggestBestThreadingModel() : _threadingModel;

    Contexts contexts;
    getContexts(contexts);

    OSG_INFO<<"Viewer::startThreading() - 
contexts.size()="<<contexts.size()<<std::endl;

    Cameras cameras;
    getCameras(cameras);

    unsigned int numThreadsOnStartBarrier = 0;
    unsigned int numThreadsOnEndBarrier = 0;
    switch(_threadingModel)
    {
        case(SingleThreaded):
            numThreadsOnStartBarrier = 1;
            numThreadsOnEndBarrier = 1;
            return;
        case(CullDrawThreadPerContext):
            numThreadsOnStartBarrier = contexts.size()+1;
            numThreadsOnEndBarrier = contexts.size()+1;
            break;
        case(DrawThreadPerContext):
            numThreadsOnStartBarrier = 1;
            numThreadsOnEndBarrier = 1;
            break;
        case(CullThreadPerCameraDrawThreadPerContext):
            numThreadsOnStartBarrier = cameras.size()+1;
            numThreadsOnEndBarrier = 1;
            break;
        default:
            OSG_NOTICE<<"Error: Threading model not selected"<<std::endl;
            return;
    }

    // using multi-threading so make sure that new objects are allocated with 
thread safe ref/unref
    osg::Referenced::setThreadSafeReferenceCounting(true);

    Scenes scenes;
    getScenes(scenes);
    for(Scenes::iterator scitr = scenes.begin();
        scitr != scenes.end();
        ++scitr)
    {
        if ((*scitr)->getSceneData())
        {
            OSG_INFO<<"Making scene thread safe"<<std::endl;

            // make sure that existing scene graph objects are allocated with 
thread safe ref/unref
            (*scitr)->getSceneData()->setThreadSafeRefUnref(true);

            // update the scene graph so that it has enough GL object buffer 
memory for the graphics contexts that will be using it.
            
(*scitr)->getSceneData()->resizeGLObjectBuffers(osg::DisplaySettings::instance()->getMaxNumberOfGraphicsContexts());
        }
    }

    int numProcessors = OpenThreads::GetNumberOfProcessors();
    bool affinity = numProcessors>1;

    Contexts::iterator citr;

    unsigned int numViewerDoubleBufferedRenderingOperation = 0;

    bool graphicsThreadsDoesCull = _threadingModel == CullDrawThreadPerContext 
|| _threadingModel==SingleThreaded;

    for(Cameras::iterator camItr = cameras.begin();
        camItr != cameras.end();
        ++camItr)
    {
        osg::Camera* camera = *camItr;
        Renderer* renderer = dynamic_cast<Renderer*>(camera->getRenderer());
        if (renderer)
        {
            renderer->setGraphicsThreadDoesCull(graphicsThreadsDoesCull);
            renderer->setDone(false);
            renderer->reset();
            ++numViewerDoubleBufferedRenderingOperation;
        }
    }

    if (_threadingModel==CullDrawThreadPerContext)
    {
        _startRenderingBarrier = 0;
        _endRenderingDispatchBarrier = 0;
        _endDynamicDrawBlock = 0;
    }
    else if (_threadingModel==DrawThreadPerContext ||
             _threadingModel==CullThreadPerCameraDrawThreadPerContext)
    {
        _startRenderingBarrier = 0;
        _endRenderingDispatchBarrier = 0;
        _endDynamicDrawBlock = new 
osg::EndOfDynamicDrawBlock(numViewerDoubleBufferedRenderingOperation);

#ifndef OSGUTIL_RENDERBACKEND_USE_REF_PTR
        if (!osg::Referenced::getDeleteHandler()) 
osg::Referenced::setDeleteHandler(new osg::DeleteHandler(2));
        else 
osg::Referenced::getDeleteHandler()->setNumFramesToRetainObjects(2);
#endif
    }

    if (numThreadsOnStartBarrier>1)
    {
        _startRenderingBarrier = new 
osg::BarrierOperation(numThreadsOnStartBarrier, 
osg::BarrierOperation::NO_OPERATION);
    }

    if (numThreadsOnEndBarrier>1)
    {
        _endRenderingDispatchBarrier = new 
osg::BarrierOperation(numThreadsOnEndBarrier, _endBarrierOperation);
    }


    osg::ref_ptr<osg::BarrierOperation> swapReadyBarrier = contexts.empty() ? 0 
: new osg::BarrierOperation(contexts.size(), 
osg::BarrierOperation::NO_OPERATION);

    osg::ref_ptr<osg::SwapBuffersOperation> swapOp = new 
osg::SwapBuffersOperation();

    typedef std::map<OpenThreads::Thread*, int> ThreadAffinityMap;
    ThreadAffinityMap threadAffinityMap;

    unsigned int processNum = 1;
    for(citr = contexts.begin();
        citr != contexts.end();
        ++citr, ++processNum)
    {
        osg::GraphicsContext* gc = (*citr);

        if (!gc->isRealized())
        {
            OSG_INFO<<"ViewerBase::startThreading() : Realizng window 
"<<gc<<std::endl;
            gc->realize();
        }

        
gc->getState()->setDynamicObjectRenderingCompletedCallback(_endDynamicDrawBlock.get());

        // create the a graphics thread for this context
        gc->createGraphicsThread();

        if (affinity) gc->getGraphicsThread()->setProcessorAffinity(processNum 
% numProcessors);
        threadAffinityMap[gc->getGraphicsThread()] = processNum % numProcessors;

        // add the startRenderingBarrier
        if (_threadingModel==CullDrawThreadPerContext && 
_startRenderingBarrier.valid()) 
gc->getGraphicsThread()->add(_startRenderingBarrier.get());

        // add the rendering operation itself.
        gc->getGraphicsThread()->add(new osg::RunOperations());

        if (_threadingModel==CullDrawThreadPerContext && 
_endBarrierPosition==BeforeSwapBuffers && _endRenderingDispatchBarrier.valid())
        {
            // add the endRenderingDispatchBarrier
            gc->getGraphicsThread()->add(_endRenderingDispatchBarrier.get());
        }

        if (swapReadyBarrier.valid()) 
gc->getGraphicsThread()->add(swapReadyBarrier.get());

        // add the swap buffers
        gc->getGraphicsThread()->add(swapOp.get());

        if (_threadingModel==CullDrawThreadPerContext && 
_endBarrierPosition==AfterSwapBuffers && _endRenderingDispatchBarrier.valid())
        {
            // add the endRenderingDispatchBarrier
            gc->getGraphicsThread()->add(_endRenderingDispatchBarrier.get());
        }

    }

    if (_threadingModel==CullThreadPerCameraDrawThreadPerContext && 
numThreadsOnStartBarrier>1)
    {
        Cameras::iterator camItr;

        for(camItr = cameras.begin();
            camItr != cameras.end();
            ++camItr, ++processNum)
        {
            osg::Camera* camera = *camItr;
            camera->createCameraThread();

            if (affinity) 
camera->getCameraThread()->setProcessorAffinity(processNum % numProcessors);
            threadAffinityMap[camera->getCameraThread()] = processNum % 
numProcessors;

            osg::GraphicsContext* gc = camera->getGraphicsContext();

            // add the startRenderingBarrier
            if (_startRenderingBarrier.valid()) 
camera->getCameraThread()->add(_startRenderingBarrier.get());

            Renderer* renderer = dynamic_cast<Renderer*>(camera->getRenderer());
            renderer->setGraphicsThreadDoesCull(false);
            camera->getCameraThread()->add(renderer);

            if (_endRenderingDispatchBarrier.valid())
            {
                // add the endRenderingDispatchBarrier
                
gc->getGraphicsThread()->add(_endRenderingDispatchBarrier.get());
            }

        }

        for(camItr = cameras.begin();
            camItr != cameras.end();
            ++camItr)
        {
            osg::Camera* camera = *camItr;
            if (camera->getCameraThread() && 
!camera->getCameraThread()->isRunning())
            {
                OSG_INFO<<"  camera->getCameraThread()-> 
"<<camera->getCameraThread()<<std::endl;
                camera->getCameraThread()->startThread();
            }
        }
    }

#if 0
    if (affinity)
    {
        OpenThreads::SetProcessorAffinityOfCurrentThread(0);
        if (_scene.valid() && _scene->getDatabasePager())
        {
#if 0
            _scene->getDatabasePager()->setProcessorAffinity(1);
#else
            _scene->getDatabasePager()->setProcessorAffinity(0);
#endif
        }
    }
#endif

#if 0
    if (affinity)
    {
        for(ThreadAffinityMap::iterator titr = threadAffinityMap.begin();
            titr != threadAffinityMap.end();
            ++titr)
        {
            titr->first->setProcessorAffinity(titr->second);
        }
    }
#endif


    for(citr = contexts.begin();
        citr != contexts.end();
        ++citr)
    {
        osg::GraphicsContext* gc = (*citr);
        if (gc->getGraphicsThread() && !gc->getGraphicsThread()->isRunning())
        {
            OSG_INFO<<"  gc->getGraphicsThread()->startThread() 
"<<gc->getGraphicsThread()<<std::endl;
            gc->getGraphicsThread()->startThread();
            // OpenThreads::Thread::YieldCurrentThread();
        }
    }

    _threadsRunning = true;

    OSG_INFO<<"Set up threading"<<std::endl;
}

void ViewerBase::getWindows(Windows& windows, bool onlyValid)
{
    windows.clear();

    Contexts contexts;
    getContexts(contexts, onlyValid);

    for(Contexts::iterator itr = contexts.begin();
        itr != contexts.end();
        ++itr)
    {
        osgViewer::GraphicsWindow* gw = 
dynamic_cast<osgViewer::GraphicsWindow*>(*itr);
        if (gw) windows.push_back(gw);
    }
}

void ViewerBase::checkWindowStatus()
{
    Contexts contexts;
    getContexts(contexts);
    checkWindowStatus(contexts);
}

void ViewerBase::checkWindowStatus(const Contexts& contexts)
{
    if (contexts.size()==0)
    {
        _done = true;
        if (areThreadsRunning()) stopThreading();
    }
}

void ViewerBase::addUpdateOperation(osg::Operation* operation)
{
    if (!operation) return;

    if (!_updateOperations) _updateOperations = new osg::OperationQueue;

    _updateOperations->add(operation);
}

void ViewerBase::removeUpdateOperation(osg::Operation* operation)
{
    if (!operation) return;

    if (_updateOperations.valid())
    {
        _updateOperations->remove(operation);
    }
}

void 
ViewerBase::setIncrementalCompileOperation(osgUtil::IncrementalCompileOperation*
 ico)
{
    if (_incrementalCompileOperation == ico) return;

    Contexts contexts;
    getContexts(contexts, false);

    if (_incrementalCompileOperation.valid()) 
_incrementalCompileOperation->removeContexts(contexts);

    // assign new operation
    _incrementalCompileOperation = ico;

    Scenes scenes;
    getScenes(scenes,false);
    for(Scenes::iterator itr = scenes.begin();
        itr != scenes.end();
        ++itr)
    {
        osgDB::DatabasePager* dp = (*itr)->getDatabasePager();
        dp->setIncrementalCompileOperation(ico);
    }


    if (_incrementalCompileOperation) 
_incrementalCompileOperation->assignContexts(contexts);
}

int ViewerBase::run()
{
    if (!isRealized())
    {
        realize();
    }

    const char* run_frame_count_str = getenv("OSG_RUN_FRAME_COUNT");
    unsigned int runTillFrameNumber = run_frame_count_str==0 ? 
osg::UNINITIALIZED_FRAME_NUMBER : atoi(run_frame_count_str);

    while(!done() && (run_frame_count_str==0 || 
getViewerFrameStamp()->getFrameNumber()<runTillFrameNumber))
    {
        double minFrameTime = _runMaxFrameRate>0.0 ? 1.0/_runMaxFrameRate : 0.0;
        osg::Timer_t startFrameTick = osg::Timer::instance()->tick();
        if (_runFrameScheme==ON_DEMAND)
        {
            if (checkNeedToDoFrame())
            {
                frame();
            }
            else
            {
                // we don't need to render a frame but we don't want to spin 
the run loop so make sure the minimum
                // loop time is 1/100th of second, if not otherwise set, so 
enabling the frame microSleep below to
                // avoid consume excessive CPU resources.
                if (minFrameTime==0.0) minFrameTime=0.01;
            }
        }
        else
        {
            frame();
        }

        // work out if we need to force a sleep to hold back the frame rate
        osg::Timer_t endFrameTick = osg::Timer::instance()->tick();
        double frameTime = osg::Timer::instance()->delta_s(startFrameTick, 
endFrameTick);
        if (frameTime < minFrameTime) 
OpenThreads::Thread::microSleep(static_cast<unsigned 
int>(1000000.0*(minFrameTime-frameTime)));
    }

    return 0;
}

void ViewerBase::frame(double simulationTime)
{
    if (_done) return;

    // OSG_NOTICE<<std::endl<<"CompositeViewer::frame()"<<std::endl<<std::endl;

    if (_firstFrame)
    {
        viewerInit();

        if (!isRealized())
        {
            realize();
        }

        _firstFrame = false;
    }
    advance(simulationTime);

    eventTraversal();
    updateTraversal();
    renderingTraversals();
}


void ViewerBase::renderingTraversals()
{
    bool _outputMasterCameraLocation = false;
    if (_outputMasterCameraLocation)
    {
        Views views;
        getViews(views);

        for(Views::iterator itr = views.begin();
            itr != views.end();
            ++itr)
        {
            osgViewer::View* view = *itr;
            if (view)
            {
                const osg::Matrixd& m = 
view->getCamera()->getInverseViewMatrix();
                OSG_NOTICE<<"View "<<view<<", Master Camera 
position("<<m.getTrans()<<"), rotation("<<m.getRotate()<<")"<<std::endl;
            }
        }
    }

    Contexts contexts;
    getContexts(contexts);

    // check to see if windows are still valid
    checkWindowStatus(contexts);
    if (_done) return;

    double beginRenderingTraversals = elapsedTime();

    osg::FrameStamp* frameStamp = getViewerFrameStamp();

    if (getViewerStats() && getViewerStats()->collectStats("scene"))
    {
        unsigned int frameNumber = frameStamp ? frameStamp->getFrameNumber() : 
0;

        Views views;
        getViews(views);
        for(Views::iterator vitr = views.begin();
            vitr != views.end();
            ++vitr)
        {
            View* view = *vitr;
            osg::Stats* stats = view->getStats();
            osg::Node* sceneRoot = view->getSceneData();
            if (sceneRoot && stats)
            {
                osgUtil::StatsVisitor statsVisitor;
                sceneRoot->accept(statsVisitor);
                statsVisitor.totalUpStats();

                unsigned int unique_primitives = 0;
                osgUtil::Statistics::PrimitiveCountMap::iterator pcmitr;
                for(pcmitr = statsVisitor._uniqueStats.GetPrimitivesBegin();
                    pcmitr != statsVisitor._uniqueStats.GetPrimitivesEnd();
                    ++pcmitr)
                {
                    unique_primitives += pcmitr->second;
                }

                stats->setAttribute(frameNumber, "Number of unique StateSet", 
static_cast<double>(statsVisitor._statesetSet.size()));
                stats->setAttribute(frameNumber, "Number of unique Group", 
static_cast<double>(statsVisitor._groupSet.size()));
                stats->setAttribute(frameNumber, "Number of unique Transform", 
static_cast<double>(statsVisitor._transformSet.size()));
                stats->setAttribute(frameNumber, "Number of unique LOD", 
static_cast<double>(statsVisitor._lodSet.size()));
                stats->setAttribute(frameNumber, "Number of unique Switch", 
static_cast<double>(statsVisitor._switchSet.size()));
                stats->setAttribute(frameNumber, "Number of unique Geode", 
static_cast<double>(statsVisitor._geodeSet.size()));
                stats->setAttribute(frameNumber, "Number of unique Drawable", 
static_cast<double>(statsVisitor._drawableSet.size()));
                stats->setAttribute(frameNumber, "Number of unique Geometry", 
static_cast<double>(statsVisitor._geometrySet.size()));
                stats->setAttribute(frameNumber, "Number of unique Vertices", 
static_cast<double>(statsVisitor._uniqueStats._vertexCount));
                stats->setAttribute(frameNumber, "Number of unique Primitives", 
static_cast<double>(unique_primitives));

                unsigned int instanced_primitives = 0;
                for(pcmitr = statsVisitor._instancedStats.GetPrimitivesBegin();
                    pcmitr != statsVisitor._instancedStats.GetPrimitivesEnd();
                    ++pcmitr)
                {
                    instanced_primitives += pcmitr->second;
                }

                stats->setAttribute(frameNumber, "Number of instanced 
Stateset", static_cast<double>(statsVisitor._numInstancedStateSet));
                stats->setAttribute(frameNumber, "Number of instanced Group", 
static_cast<double>(statsVisitor._numInstancedGroup));
                stats->setAttribute(frameNumber, "Number of instanced 
Transform", static_cast<double>(statsVisitor._numInstancedTransform));
                stats->setAttribute(frameNumber, "Number of instanced LOD", 
static_cast<double>(statsVisitor._numInstancedLOD));
                stats->setAttribute(frameNumber, "Number of instanced Switch", 
static_cast<double>(statsVisitor._numInstancedSwitch));
                stats->setAttribute(frameNumber, "Number of instanced Geode", 
static_cast<double>(statsVisitor._numInstancedGeode));
                stats->setAttribute(frameNumber, "Number of instanced 
Drawable", static_cast<double>(statsVisitor._numInstancedDrawable));
                stats->setAttribute(frameNumber, "Number of instanced 
Geometry", static_cast<double>(statsVisitor._numInstancedGeometry));
                stats->setAttribute(frameNumber, "Number of instanced 
Vertices", static_cast<double>(statsVisitor._instancedStats._vertexCount));
                stats->setAttribute(frameNumber, "Number of instanced 
Primitives", static_cast<double>(instanced_primitives));
           }
        }
    }

    Scenes scenes;
    getScenes(scenes);

    for(Scenes::iterator sitr = scenes.begin();
        sitr != scenes.end();
        ++sitr)
    {
        Scene* scene = *sitr;
        osgDB::DatabasePager* dp = scene ? scene->getDatabasePager() : 0;
        if (dp) dp->signalBeginFrame(frameStamp);

        osgDB::ImagePager* ip = scene ? scene->getImagePager() : 0;
        if (ip) ip->signalBeginFrame(frameStamp);

        if (scene->getSceneData())
        {
            // fire off a build of the bounding volumes while we
            // are still running single threaded.
            scene->getSceneData()->getBound();
        }
    }

    // OSG_NOTICE<<std::endl<<"Start frame"<<std::endl;


    Cameras cameras;
    getCameras(cameras);

    Contexts::iterator itr;

    bool doneMakeCurrentInThisThread = false;

    if (_endDynamicDrawBlock.valid())
    {
        _endDynamicDrawBlock->reset();
    }

    // dispatch the rendering threads
    if (_startRenderingBarrier.valid()) _startRenderingBarrier->block();

    // reset any double buffer graphics objects
    for(Cameras::iterator camItr = cameras.begin();
        camItr != cameras.end();
        ++camItr)
    {
        osg::Camera* camera = *camItr;
        Renderer* renderer = dynamic_cast<Renderer*>(camera->getRenderer());
        if (renderer)
        {
            if (!renderer->getGraphicsThreadDoesCull() && 
!(camera->getCameraThread()))
            {
                renderer->cull();
            }
        }
    }

    for(itr = contexts.begin();
        itr != contexts.end() && !_done;
        ++itr)
    {
        if (!((*itr)->getGraphicsThread()) && (*itr)->valid())
        {
            doneMakeCurrentInThisThread = true;
            makeCurrent(*itr);
            (*itr)->runOperations();
        }
    }

    // OSG_NOTICE<<"Joing _endRenderingDispatchBarrier block 
"<<_endRenderingDispatchBarrier.get()<<std::endl;

    // wait till the rendering dispatch is done.
    if (_endRenderingDispatchBarrier.valid()) 
_endRenderingDispatchBarrier->block();

    for(itr = contexts.begin();
        itr != contexts.end() && !_done;
        ++itr)
    {
        if (!((*itr)->getGraphicsThread()) && (*itr)->valid())
        {
            doneMakeCurrentInThisThread = true;
            makeCurrent(*itr);
            (*itr)->swapBuffers();
        }
    }

    for(Scenes::iterator sitr = scenes.begin();
        sitr != scenes.end();
        ++sitr)
    {
        Scene* scene = *sitr;
        osgDB::DatabasePager* dp = scene ? scene->getDatabasePager() : 0;
        if (dp) dp->signalEndFrame();

        osgDB::ImagePager* ip = scene ? scene->getImagePager() : 0;
        if (ip) ip->signalEndFrame();
    }

    // wait till the dynamic draw is complete.
    if (_endDynamicDrawBlock.valid())
    {
        // osg::Timer_t startTick = osg::Timer::instance()->tick();
        _endDynamicDrawBlock->block();
        // OSG_NOTICE<<"Time waiting 
"<<osg::Timer::instance()->delta_m(startTick, 
osg::Timer::instance()->tick())<<std::endl;;
    }

    if (_releaseContextAtEndOfFrameHint && doneMakeCurrentInThisThread)
    {
        //OSG_NOTICE<<"Doing release context"<<std::endl;
        releaseContext();
    }

    if (getViewerStats() && getViewerStats()->collectStats("update"))
    {
        double endRenderingTraversals = elapsedTime();

        // update current frames stats
        getViewerStats()->setAttribute(frameStamp->getFrameNumber(), "Rendering 
traversals begin time ", beginRenderingTraversals);
        getViewerStats()->setAttribute(frameStamp->getFrameNumber(), "Rendering 
traversals end time ", endRenderingTraversals);
        getViewerStats()->setAttribute(frameStamp->getFrameNumber(), "Rendering 
traversals time taken", endRenderingTraversals-beginRenderingTraversals);
    }

    _requestRedraw = false;
}

/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
 *
 * This library is open source and may be redistributed and/or modified under
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 *
 * 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
 * OpenSceneGraph Public License for more details.
 *
 * ViewDependentShadow codes Copyright (C) 2008 Wojciech Lewandowski
 * Thanks to to my company http://www.ai.com.pl for allowing me free this work.
*/

#include<osgShadow/ConvexPolyhedron>
#include<osg/Group>
#include<osg/Geode>
#include<osgDB/WriteFile>

#include<cassert>
#include<deque>
#include<algorithm>
#include<iterator>

#include <stdio.h>
#include <string.h>

using namespace osgShadow;


#if defined( DEBUG ) || defined( _DEBUG ) || defined( _DEBUG_ )
// ConvexPolyhedron may produce tons of warnings when it becomes non convex.
// Unfortuantely this condition often happens in daily routine of shadow usage
// due precision errors mixed with repeating frustum cuts performed by 
MinimalShadowClasses.
// However, in most of above cases this condition is not fatal
// because polyhedron becomes concave by very small margin (mesuring deep the 
hole).
// Unfortunately warnings are produced even for such small margin cases and can
// easily flood the console.
// So I leave MAKE_CHECKS commented out. Its really useful only for a guy who 
debugs
// larger concaveness issues which means most developers will want to keep it 
commented.
//    #define MAKE_CHECKS 1
#endif

#if MAKE_CHECKS

#define WARN  OSG_WARN

#define CONVEX_POLYHEDRON_CHECK_COHERENCY             1
#define CONVEX_POLYHEDRON_WARN_ON_INCOHERENT_DATA     2
#define CONVEX_POLYHEDRON_DUMP_ON_INCOHERENT_DATA     2
#define CONVEX_POLYHEDRON_WARN_ON_BAD_POLYGON         1
#define CONVEX_POLYHEDRON_DUMP_ON_BAD_POLYGON         1
#define CONVEX_POLYHEDRON_WARN_ON_CONCAVE_POLYGON     1
#define CONVEX_POLYHEDRON_DUMP_ON_CONCAVE_POLYGON     1
#define CONVEX_POLYHEDRON_WARN_ON_INCORRECT_FACE_CUT  1
#define CONVEX_POLYHEDRON_DUMP_ON_INCORRECT_FACE_CUT  1


#else

#define WARN OSG_WARN

#define CONVEX_POLYHEDRON_CHECK_COHERENCY             0
#define CONVEX_POLYHEDRON_WARN_ON_INCOHERENT_DATA     0
#define CONVEX_POLYHEDRON_DUMP_ON_INCOHERENT_DATA     0
#define CONVEX_POLYHEDRON_WARN_ON_BAD_POLYGON         0
#define CONVEX_POLYHEDRON_DUMP_ON_BAD_POLYGON         0
#define CONVEX_POLYHEDRON_WARN_ON_CONCAVE_POLYGON     0
#define CONVEX_POLYHEDRON_DUMP_ON_CONCAVE_POLYGON     0
#define CONVEX_POLYHEDRON_WARN_ON_INCORRECT_FACE_CUT  0
#define CONVEX_POLYHEDRON_DUMP_ON_INCORRECT_FACE_CUT  0

#endif

const osg::Matrix & ConvexPolyhedron::defaultMatrix = *(osg::Matrix*)NULL;
static const double epsi = pow( 2.0, -20.0 ); //circa 8 times float prec(~2^-23)
static const double plane_hull_tolerance    = 1.0e-5;
static const double point_plane_tolerance   = 0.0;
static const double point_point_equivalence = 0.;

// Tim Moore modifications for GCC 4.3 August 15, 2008
// they correspond to Adrian Egli tweaks for VS 7.3 on August 19, 2008
namespace
{
typedef std::vector< double > Distances;
typedef std::vector< osg::Vec4d > Points;

// Auxiliary params continued per face
struct FaceDistances
{
    ConvexPolyhedron::Faces::iterator itr;
    Points points;
    Distances distances;
    int below, above, on;
};
} // namespace

ConvexPolyhedron::ConvexPolyhedron( const osg::Matrix& matrix,
                        const osg::Matrix& inverse,
                        const osg::BoundingBox& bb )
{
    setToBoundingBox( bb );

    if( &matrix != &defaultMatrix && &inverse != &defaultMatrix )
        transform( matrix, inverse );
    else if( &matrix != &defaultMatrix && &inverse == &defaultMatrix )
        transform( matrix, osg::Matrix::inverse( matrix ) );
    else if( &matrix == &defaultMatrix && &inverse != &defaultMatrix )
        transform( osg::Matrix::inverse( inverse ), matrix );
}

void ConvexPolyhedron::setToUnitFrustum(bool withNear, bool withFar)
{
    const osg::Vec3d v000(-1.0,-1.0,-1.0);
    const osg::Vec3d v010(-1.0,1.0,-1.0);
    const osg::Vec3d v001(-1.0,-1.0,1.0);
    const osg::Vec3d v011(-1.0,1.0,1.0);
    const osg::Vec3d v100(1.0,-1.0,-1.0);
    const osg::Vec3d v110(1.0,1.0,-1.0);
    const osg::Vec3d v101(1.0,-1.0,1.0);
    const osg::Vec3d v111(1.0,1.0,1.0);

    _faces.clear();

    {   // left plane.
        Face& face = createFace();
        face.name = "left";
        face.plane.set(1.0,0.0,0.0,1.0);
        face.vertices.push_back(v000);
        face.vertices.push_back(v001);
        face.vertices.push_back(v011);
        face.vertices.push_back(v010);
    }

    {   // right plane.
        Face& face = createFace();
        face.name = "right";
        face.plane.set(-1.0,0.0,0.0,1.0);
        face.vertices.push_back(v100);
        face.vertices.push_back(v110);
        face.vertices.push_back(v111);
        face.vertices.push_back(v101);
    }

    {   // bottom plane.
        Face& face = createFace();
        face.name = "bottom";
        face.plane.set(0.0,1.0,0.0,1.0);
        face.vertices.push_back(v000);
        face.vertices.push_back(v100);
        face.vertices.push_back(v101);
        face.vertices.push_back(v001);
    }

    {   // top plane.
        Face& face = createFace();
        face.name = "top";
        face.plane.set(0.0,-1.0,0.0,1.0);
        face.vertices.push_back(v010);
        face.vertices.push_back(v011);
        face.vertices.push_back(v111);
        face.vertices.push_back(v110);
    }

    if (withNear)
    {   // near plane
        Face& face = createFace();
        face.name = "near";
        face.plane.set(0.0,0.0,1.0,1.0);
        face.vertices.push_back(v000);
        face.vertices.push_back(v010);
        face.vertices.push_back(v110);
        face.vertices.push_back(v100);
    }

    if (withFar)
    {   // far plane
        Face& face = createFace();
        face.name = "far";
        face.plane.set(0.0,0.0,-1.0,1.0);
        face.vertices.push_back(v001);
        face.vertices.push_back(v101);
        face.vertices.push_back(v111);
        face.vertices.push_back(v011);
    }
}

void ConvexPolyhedron::setToBoundingBox(const osg::BoundingBox& bb)
{
    _faces.clear();

    // Ignore invalid and one dimensional boxes
    if( bb._min[0] >= bb._max[0] ||
        bb._min[1] >= bb._max[1] ||
        bb._min[2] >= bb._max[2] ) return;

    const osg::Vec3d v000(bb.xMin(),bb.yMin(), bb.zMin());
    const osg::Vec3d v010(bb.xMin(),bb.yMax(), bb.zMin());
    const osg::Vec3d v001(bb.xMin(),bb.yMin(), bb.zMax());
    const osg::Vec3d v011(bb.xMin(),bb.yMax(), bb.zMax());
    const osg::Vec3d v100(bb.xMax(),bb.yMin(), bb.zMin());
    const osg::Vec3d v110(bb.xMax(),bb.yMax(), bb.zMin());
    const osg::Vec3d v101(bb.xMax(),bb.yMin(), bb.zMax());
    const osg::Vec3d v111(bb.xMax(),bb.yMax(), bb.zMax());



    {   // x min plane
        Face& face = createFace();
        face.name = "xMin";
        face.plane.set(1.0,0.0,0.0,-bb.xMin());
        face.vertices.push_back(v000);
        face.vertices.push_back(v001);
        face.vertices.push_back(v011);
        face.vertices.push_back(v010);
    }

    {   // x max plane.
        Face& face = createFace();
        face.name = "xMax";
        face.plane.set(-1.0,0.0,0.0,bb.xMax());
        face.vertices.push_back(v100);
        face.vertices.push_back(v110);
        face.vertices.push_back(v111);
        face.vertices.push_back(v101);
    }

    {   // y min plane.
        Face& face = createFace();
        face.name = "yMin";
        face.plane.set(0.0,1.0,0.0,-bb.yMin());
        face.vertices.push_back(v000);
        face.vertices.push_back(v100);
        face.vertices.push_back(v101);
        face.vertices.push_back(v001);
    }

    {   // y max plane.
        Face& face = createFace();
        face.name = "yMax";
        face.plane.set(0.0,-1.0,0.0,bb.yMax());
        face.vertices.push_back(v010);
        face.vertices.push_back(v011);
        face.vertices.push_back(v111);
        face.vertices.push_back(v110);
    }
    {   // z min plane
        Face& face = createFace();
        face.name = "zMin";
        face.plane.set(0.0,0.0,1.0,-bb.zMin());
        face.vertices.push_back(v000);
        face.vertices.push_back(v010);
        face.vertices.push_back(v110);
        face.vertices.push_back(v100);
    }

    {   // z max plane
        Face& face = createFace();
        face.name = "zMax";
        face.plane.set(0.0,0.0,-1.0,bb.zMax());
        face.vertices.push_back(v001);
        face.vertices.push_back(v101);
        face.vertices.push_back(v111);
        face.vertices.push_back(v011);
    }
}

void ConvexPolyhedron::transform(const osg::Matrix& matrix, const osg::Matrix& 
inverse)
{
    bool requires_infinite_plane_clip = false;

    ConvexPolyhedron cp = *this;
    for(Faces::iterator itr = _faces.begin();
        itr != _faces.end() && !requires_infinite_plane_clip;
        ++itr)
    {
        Face& face = *itr;
        face.plane.transformProvidingInverse(inverse);
        for(Vertices::iterator vitr = face.vertices.begin();
            vitr != face.vertices.end();
            ++vitr)
        {
            osg::Vec4d v( *vitr, 1.0 );
            v = v * matrix;

            if( v[3] <= 0 ) {
                requires_infinite_plane_clip = true;
                break;
            }

            vitr->set( v[0]/v[3], v[1]/v[3], v[2]/v[3] );
        }
    }

    if( requires_infinite_plane_clip ) {
        *this = cp;
        transformClip( matrix, inverse );
//        cp.dumpGeometry(&cp._faces.back(),&cp._faces.back().plane,this);
    }

    // Perpective transforms and lack of precision
    // occasionaly cause removal of some points

    removeDuplicateVertices( );

    checkCoherency( true, "ConvexPolyhedron::transform" );
}

void ConvexPolyhedron::transformClip(const osg::Matrix& matrix, const 
osg::Matrix& inverse)
{
    double tolerance = 0.00001;

    if( _faces.empty() ) return;


    ConvexPolyhedron cp( *this );

    typedef std::vector< FaceDistances > FaceDistancesList;
    FaceDistancesList faceDistances;
    faceDistances.resize( _faces.size() );

    double min = FLT_MAX, max = -FLT_MAX; //Hull max & min point distances

    // First step compute each face points distances to cutting plane
    Faces::iterator faces_itr = _faces.begin();
    for(FaceDistancesList::iterator fd = faceDistances.begin();
        faces_itr != _faces.end();
        ++faces_itr, ++fd)
    {
        fd->itr = faces_itr;
        fd->distances.reserve( faces_itr->vertices.size() );
        fd->on = 0;
        fd->above = 0;
        fd->below = 0;

        faces_itr->plane.transformProvidingInverse(inverse);

        for( Vertices::iterator vitr = faces_itr->vertices.begin();
            vitr != faces_itr->vertices.end();
            ++vitr)
        {
            osg::Vec4d p( *vitr, 1.0 );
            p = p * matrix;
            vitr->set( p[0]/p[3], p[1]/p[3], p[2]/p[3] );

            double d = p[3]-tolerance;

            fd->points.push_back( p );
            fd->distances.push_back( d );
            if ( d>point_plane_tolerance )       ++fd->above;
            else if ( d<-point_plane_tolerance ) ++fd->below;
            else                                 ++fd->on;
            min = osg::minimum( min, d );
            max = osg::maximum( max, d );
        }
    }

    if( max <= plane_hull_tolerance ) { // All points on or below cutting plane
        _faces.clear();
        return;
    }

    if( min >= -plane_hull_tolerance ) { // All points on or above cutting plane
        return;
    }

    typedef std::pair<osg::Vec3d, osg::Vec3d> Edge;
    typedef std::set< Edge > Edges;
    Edges edges;

    for( FaceDistancesList::iterator fd = faceDistances.begin();
        fd != faceDistances.end();
        ++fd )
    {
        if ( fd->below == 0 )
        {  // skip face if all points on or above cutting plane ( below == 0 )
            continue;
        }

        if ( /* fd->below > 0 && */ fd->above == 0 && fd->on == 0 )
        {
            _faces.erase( fd->itr ); // remove face if points below or on
            continue;
        }

        // cut the face if some points above and below plane
        // assert( fd->below > 0 && fd->above > 0 );

        Face& face = *(fd->itr);
        Points& vertices = fd->points;
        Distances& distances = fd->distances;
        Vertices newFaceVertices;
        Vertices newVertices;

        for(unsigned int i=0; i < vertices.size(); ++i)
        {
            osg::Vec4d &va = vertices[i];
            osg::Vec4d &vb = vertices[(i+1)%vertices.size()];
            double &distance_a = distances[i];
            double &distance_b = distances[(i+1)%vertices.size()];

            // Is first edge point above or on the plane?
            if ( -point_plane_tolerance <= distance_a ) {

                osg::Vec3d v( vertices[i][0], vertices[i][1], vertices[i][2] );
                v /= vertices[i][3];

                if( newVertices.empty() || v != newVertices.back() )
                    newVertices.push_back( v );

                if ( distance_a <= point_plane_tolerance ) {
                    if( newFaceVertices.empty() || v != newFaceVertices.back() )
                        newFaceVertices.push_back( v );
                }
            }

            // Does edge intersect plane ?
            if ( ( distance_a < -point_plane_tolerance && distance_b > 
point_plane_tolerance ) ||
                 ( distance_b < -point_plane_tolerance && distance_a > 
point_plane_tolerance ) )
            {
                osg::Vec4d intersection; // Inserting vertex
                double da = fabs( distance_a ), db = fabs( distance_b );

                // tweaks to improve coherency of polytope after cut
                if( da <= point_point_equivalence && da <= db ) {
                    intersection = va;
                } else if( db <= point_point_equivalence && db <= da ) {
                    intersection = vb;
                } else {
                    double dab4 = 0.25 * ( da + db );
                    if( dab4 < da && dab4 < db ) {
                        intersection = (vb*distance_a - 
va*distance_b)/(distance_a-distance_b);
                    } else {
                        osg::Vec4d v = (vb - va)/(distance_a-distance_b);
                        if( da < db )
                            intersection = va + v * distance_a;
                        else
                            intersection = vb + v * distance_b;
                    }
                }


                osg::Vec3d v( intersection[0], intersection[1], intersection[2] 
);
                v /= intersection[3];

                if( newVertices.empty() || v != newVertices.back() )
                    newVertices.push_back( v );

                if( newFaceVertices.empty() || v != newFaceVertices.back() )
                    newFaceVertices.push_back( v );
            }
        }

        if( newVertices.size() && newVertices.front() == newVertices.back() )
            newVertices.pop_back();

        if( newFaceVertices.size() && newFaceVertices.front() == 
newFaceVertices.back() )
            newFaceVertices.pop_back();

        if( newFaceVertices.size() == 1 ) {  // This is very rare but correct
            WARN
                << "ConvexPolyhedron::transformClip - Slicing face polygon 
returns "
                << newFaceVertices.size()
                << " points. Should be 2 (usually) or 1 (rarely)."
                << std::endl;

        } else if( newFaceVertices.size() == 2 ) {
            if( newFaceVertices[0] < newFaceVertices[1] ) {
                edges.insert( Edge( newFaceVertices[0], newFaceVertices[1] ) );
            } else {
                edges.insert( Edge( newFaceVertices[1], newFaceVertices[0] ) );
            }
        } else if( newFaceVertices.size() > 2 ) {

#if CONVEX_POLYHEDRON_WARN_ON_INCORRECT_FACE_CUT

            // This may happen if face polygon is not planar or convex.
            // It may happen when face was distorted by projection transform
            // or when some polygon vertices land in incorrect positions after
            // some transformation by badly conditioned matrix (weak precison)

            WARN
                << "ConvexPolyhedron::transformClip - Slicing face polygon 
returns "
                << newFaceVertices.size()
                << " points. Should be 2 (usually) or 1 (rarely)."
                << std::endl;
#endif

#if CONVEX_POLYHEDRON_DUMP_ON_INCORRECT_FACE_CUT
            dumpGeometry( &face, NULL, &cp );
#endif

            // Lets try to recover from this uneasy situation
            // by comparing current face polygon edges cut by new plane
            // with edges selected for new plane

            unsigned i0 = 0, i1 = newFaceVertices.size() - 1;
            unsigned j0 = 0, j1 = newVertices.size() - 1;

            for( ; i0 < newFaceVertices.size(); i1 = i0++, j1 = j0++ ) {
                while( newFaceVertices[i0] != newVertices[j0] ) j1 = j0++;
                if( newFaceVertices[i1] == newVertices[j1] )
                {
                    if( newFaceVertices[i0] < newFaceVertices[i1] ) {
                        edges.insert( Edge( newFaceVertices[i0], 
newFaceVertices[i1] ) );
                    } else {
                        edges.insert( Edge( newFaceVertices[i1], 
newFaceVertices[i0] ) );
                    }
                }
            }
        }

        if( newVertices.size() >= 3 ) { //Add faces with at least 3 points

#if ( CONVEX_POLYHEDRON_WARN_ON_CONCAVE_POLYGON || 
CONVEX_POLYHEDRON_DUMP_ON_CONCAVE_POLYGON )
            int convex = isFacePolygonConvex( face );
            face.vertices.swap( newVertices );
            if( convex && !isFacePolygonConvex( face ) ) {
#if CONVEX_POLYHEDRON_WARN_ON_CONCAVE_POLYGON
                WARN << "ConvexPolyhedron::transformClip - polygon output non 
convex."
                << " This may lead to other issues in ConvexPolyhedron math" << 
std::endl;
#endif
#if CONVEX_POLYHEDRON_DUMP_ON_CONCAVE_POLYGON
                dumpGeometry( &face, NULL, &cp );
#endif
            }
#else
            face.vertices.swap( newVertices );
#endif
        } else //Remove face reduced to 0, 1, 2 points
            _faces.erase( fd->itr );
    }

    osg::Vec3d center( 0, 0, 0 );
    unsigned count = 0;
    for( Faces::iterator itr = _faces.begin();
        itr != _faces.end();
        ++itr )
    {
        for( Vertices::iterator vitr = itr->vertices.begin();
            vitr != itr->vertices.end();
            ++vitr )
        {
            center += *vitr;
            count ++;
        }
    }

    center /= count;


    if ( edges.size() > 1 ) //Ignore faces reduced to 0, 1, 2 points
    {
        Face face;
        face.name = "Almost infinite plane";

        std::deque< osg::Vec3d > vertices;

        Edges::iterator itr = edges.begin();
        vertices.push_back( itr->first );
        vertices.push_back( itr->second );
        edges.erase( itr++ );

        for( unsigned int vertices_size = 0;
            vertices_size < vertices.size(); )
        {
            vertices_size = vertices.size();
            for( itr = edges.begin(); itr != edges.end(); )
            {
                bool not_added = false;

                if( itr->first == vertices.back() )
                    vertices.push_back( itr->second );
                else if ( itr->first == vertices.front() )
                    vertices.push_front( itr->second );
                else if ( itr->second == vertices.back() )
                    vertices.push_back( itr->first );
                else if ( itr->second == vertices.front() )
                    vertices.push_front( itr->first );
                else
                    not_added = true;

                if( not_added )
                    ++itr;
                else
                    edges.erase( itr++ );
            }
        }

#if CONVEX_POLYHEDRON_WARN_ON_BAD_POLYGON
        if( !edges.empty() ) {
            WARN
                << "ConvexPolyhedron::transformClip - Building new face polygon 
- "
                << "Found edges not matching former polygon ends"
                << std::endl;
        }
#endif

        std::copy(vertices.begin(), vertices.end(), 
std::back_inserter(face.vertices));

        face.plane.set( vertices[0], vertices[1], vertices[2] );

        if( face.plane.distance( center ) < 0.0 ) face.plane.flip();

        _faces.push_back(face);

        // Last vertex is duplicated - remove one instance
        if( face.vertices.front() == face.vertices.back() )
            face.vertices.pop_back();
        else {// If not duplicated then it may mean we have open polygon ;-(
#if CONVEX_POLYHEDRON_WARN_ON_BAD_POLYGON
            WARN
            << "ConvexPolyhedron::transformClip - Building new face polygon - "
            << " Polygon not properly closed."
            << std::endl;
#endif
#if CONVEX_POLYHEDRON_DUMP_ON_BAD_POLYGON
            dumpGeometry( &_faces.back(), NULL, &cp );
#endif
        }

#if ( CONVEX_POLYHEDRON_WARN_ON_CONCAVE_POLYGON || 
CONVEX_POLYHEDRON_DUMP_ON_CONCAVE_POLYGON )
        if( !isFacePolygonConvex( face ) ) {
#if CONVEX_POLYHEDRON_WARN_ON_CONCAVE_POLYGON
            WARN << "ConvexPolyhedron::transformClip - new face polygon non 
convex."
                << " This may lead to other issues in ConvexPolyhedron math" << 
std::endl;
#endif
#if CONVEX_POLYHEDRON_DUMP_ON_CONCAVE_POLYGON
            ConvexPolyhedron cp;
            cp.createFace() = face;
            cp.dumpGeometry( );
#endif
        }
#endif
    }

    // Perpective transforms and lack of precision
    // occasionaly cause removal of some points

    removeDuplicateVertices( );

    checkCoherency( true, "ConvexPolyhedron::transformClip" );
}

bool ConvexPolyhedron::mergeFaces
    ( const Face & face0, const Face & face1, Face & face )
{
    typedef std::pair< osg::Vec3d, osg::Vec3d >  Edge;
    typedef std::set<Edge> Edges;
    Edges edges;

    for(unsigned int i=0; i<face0.vertices.size(); ++i)
    {
        const osg::Vec3d* va = &face0.vertices[i];
        const osg::Vec3d* vb = &face0.vertices[(i+1)%face0.vertices.size()];
        if( *vb == *va ) continue; // ignore duplicated point edges
        if( *vb < *va ) std::swap( va, vb );
        edges.insert( Edge( *va, *vb ) );
    }

    bool intersection = false;
    for(unsigned int i=0; i<face1.vertices.size(); ++i)
    {
        const osg::Vec3d* va = &face1.vertices[i];
        const osg::Vec3d* vb = &face1.vertices[(i+1)%face1.vertices.size()];
        if( *vb == *va ) continue; // ignore duplicated point edges
        if( *vb < *va ) std::swap( va, vb );
        Edge edge( *va, *vb );
        Edges::iterator itr = edges.find( edge );
        if( itr == edges.end() )
            edges.insert( edge );
        else {
            edges.erase( itr );
            intersection = true;
        }
    }

    if( intersection )
        face.vertices.clear();

    if( intersection && edges.size() > 1 ) //Ignore faces reduced to 0, 1, 2 
points
    {
        std::deque< osg::Vec3d > vertices;

        Edges::iterator itr = edges.begin();
        vertices.push_back( itr->first );
        vertices.push_back( itr->second );
        edges.erase( itr++ );

        for( unsigned int vertices_size = 0;
            vertices_size < vertices.size(); )
        {
            vertices_size = vertices.size();
            for( itr = edges.begin(); itr != edges.end(); )
            {
                bool not_added = false;

                if( itr->first == vertices.back() )
                    vertices.push_back( itr->second );
                else if ( itr->first == vertices.front() )
                    vertices.push_front( itr->second );
                else if ( itr->second == vertices.back() )
                    vertices.push_back( itr->first );
                else if ( itr->second == vertices.front() )
                    vertices.push_front( itr->first );
                else
                    not_added = true;

                if( not_added )
                    ++itr;
                else
                    edges.erase( itr++ );
            }
        }

#if CONVEX_POLYHEDRON_WARN_ON_BAD_POLYGON
        if( !edges.empty() ) {
            WARN
                << "ConvexPolyhedron::mergeFaces - Building new face polygon - "
                << "Found edges not matching former polygon ends."
                << std::endl;
        }
#endif

        // Last vertex is duplicated - remove one instance
        if( vertices.front() == vertices.back() )
            vertices.pop_back();
        else {// If not duplicated then it may mean we have open polygon ;-(
#if CONVEX_POLYHEDRON_WARN_ON_BAD_POLYGON
            WARN
            << "ConvexPolyhedron::mergeFaces - Building new face polygon - "
            << " Polygon not properly closed."
            << std::endl;
#endif
#if CONVEX_POLYHEDRON_DUMP_ON_BAD_POLYGON
#endif
        }

#if 1 // Resulting plane will be the same as face0
        face.plane = face0.plane;

        std::copy(vertices.begin(), vertices.end(), 
std::back_inserter(face.vertices));

#else // Compute resulting plane as average of faces (not a good idea)
        osg::Vec3d normal = face0.plane.getNormal() + face1.plane.getNormal();
        normal.normalize();

        osg::Vec3d center;
        for( unsigned int i = 0; i < vertices.size(); ++i )
        {
            center += vertices[i];
            face.vertices.push_back( vertices[i] );
        }
        center /= vertices.size();

        face.plane.set( normal, center );
#endif

        face.name = face0.name + " + "  + face1.name;

        // No testing for concave polys
        // Its possible to build concave polygon from two merged faces
        // But after all coplanar faces are merged final result should be 
convex.
    }
    return intersection;
}

void ConvexPolyhedron::mergeCoplanarFaces
    ( const double & dot_tolerance, const double & delta_tolerance )
{
    for(Faces::iterator itr0 = _faces.begin();
        itr0 != _faces.end();
        ++itr0 )
    {
        double tolerance = delta_tolerance;
        for( unsigned i = 0; i < itr0->vertices.size(); ++i ) {
            tolerance = osg::maximum( tolerance,
                fabs( itr0->plane.distance( itr0->vertices[i] ) ) );
        }

        for(Faces::iterator itr1 = _faces.begin();
            itr1 != _faces.end();
            )
        {
            if( itr1 == itr0 ) {
                ++itr1;
                continue;
            }

            bool attempt_merge = true;
            for( unsigned i = 0; i < itr1->vertices.size(); ++i ) {
                if( fabs( itr0->plane.distance( itr1->vertices[i] ) ) > 
tolerance )
                {
                    attempt_merge = false;
                    break;
                }
            }

            if( !attempt_merge &&
                1.0 - itr0->plane.getNormal() * itr1->plane.getNormal() < 
dot_tolerance &&
                fabs( itr0->plane.ptr()[3] - itr1->plane.ptr()[3] ) < 
delta_tolerance )
                    attempt_merge = true;

            if( attempt_merge && mergeFaces( *itr0, *itr1, *itr0 ) )
                itr1 = _faces.erase( itr1 );
            else
                ++itr1;
        }
    }
}

void ConvexPolyhedron::removeDuplicateVertices( void )
{
#if 1
    // Aggressive removal, find very close points and replace them
    // with their average. Second step wil do the rest.

    typedef std::map< osg::Vec3f, osg::Vec4d > PointMap;
    typedef std::set< osg::Vec3d > VertexSet;

    VertexSet  vertexSet;
        PointMap     points;

    for( Faces::iterator itr = _faces.begin();
         itr != _faces.end();
         ++itr )
    {
        for( Vertices::iterator vitr = itr->vertices.begin();
             vitr != itr->vertices.end();
             ++vitr )
        {
            vertexSet.insert( *vitr );
        }
    }

    for( VertexSet::iterator vitr = vertexSet.begin();
         vitr != vertexSet.end();
         ++vitr )
    {
        points[ *vitr ] += osg::Vec4d( *vitr, 1.0 );
    }

    for(PointMap::iterator itr = points.begin();
         itr != points.end();
         ++itr )
    {
        if( itr->second[3] > 1.0 )
            itr->second /= itr->second[3];
    }

    for( Faces::iterator itr = _faces.begin();
         itr != _faces.end();
         ++itr )
    {
        for( Vertices::iterator vitr = itr->vertices.begin();
             vitr != itr->vertices.end();
             ++vitr )
        {
            osg::Vec4d &v = points[ *vitr ];
            *vitr = osg::Vec3d( v[0], v[1], v[2] );
        }
    }
#endif

    for( Faces::iterator itr = _faces.begin();
         itr != _faces.end();
        )
    {
        assert( itr->vertices.size() > 0 );

        osg::Vec3d prev = itr->vertices.back();

        for( Vertices::iterator vitr = itr->vertices.begin();
            vitr != itr->vertices.end();
            )
        {
            if( *vitr == prev ) {
                vitr = itr->vertices.erase( vitr );
            } else {
                prev = *vitr;
                ++vitr;
            }
        }

        if( itr->vertices.size() < 3 )
            itr = _faces.erase( itr );
        else
            ++itr;
    }

    mergeCoplanarFaces();

#if 1
    // Experimentally remove vertices on colinear edge chains
    // effectivelyy replacing them with one edge
    typedef std::map<osg::Vec3d,int> VertexCounter;
    VertexCounter vertexCounter;

    for( Faces::iterator itr = _faces.begin();
        itr != _faces.end();
        ++itr)
    {
        for( Vertices::iterator vitr = itr->vertices.begin();
             vitr != itr->vertices.end();
             ++vitr )
        {
            ++vertexCounter[ *vitr ];
        }
    }

    for( Faces::iterator itr = _faces.begin();
        itr != _faces.end();
        )
    {
        for( Vertices::iterator vitr = itr->vertices.begin();
             vitr != itr->vertices.end();
             )
        {
            if( vertexCounter[ *vitr ] == 2 ) {
#if 0 // Sanity check if we could remove this point without changing poly shape

                Vertices::iterator next = ( vitr + 1 == itr->vertices.end() ?
                                            itr->vertices.begin() :
                                            vitr + 1 );

                Vertices::iterator prev = ( vitr == itr->vertices.begin() ?
                                            itr->vertices.end() - 1 :
                                            vitr - 1 );


                osg::Vec3d va = *vitr - *prev;
                osg::Vec3d vb = *next - *vitr;

                double da = va.normalize();
                double db = vb.normalize();

                if( 0.001 < da && 0.001 < db )
                {
                    double dot = va * vb, limit = cos( 0.01 );
                    if( dot < limit ) {
                        WARN << "ConvexPolyhedron::removeDuplicateVertices"
                            << " - removed mid point connecting two non 
colinear edges."
                            << " Angle(deg): " << osg::RadiansToDegrees( acos( 
dot ) )
                            << " Length1: " << da
                            << " Length2: " << db
                            << std::endl;
                    }
                } else {
                    if( da == 0.0 || db == 0.0 )
                        WARN << "ConvexPolyhedron::removeDuplicateVertices"
                             << " - removed degenerated mid point connecting 
two edges"
                            << std::endl;

                }
#endif
                vitr = itr->vertices.erase( vitr );
            } else {
                ++vitr;
            }
        }

        if( itr->vertices.size() < 3 )
            itr = _faces.erase( itr );
        else
            ++itr;
    }
#endif

    checkCoherency( false, "Leave ConvexPolyhedron::removeDuplicateVertices" );
}

int ConvexPolyhedron::pointsColinear
    ( const osg::Vec3d & a, const osg::Vec3d & b, const osg::Vec3d & c,
      const double & dot_tolerance, const double & delta_tolerance )
{
    osg::Vec3d va = b - a;
    osg::Vec3d vb = c - b;

    double da = va.normalize();
    double db = vb.normalize();

    if( delta_tolerance >= da || delta_tolerance >= db )
        return -1; // assume collinearity if one of the edges is zero length

    if( 1.0 - fabs( va * vb ) <= dot_tolerance )
        return 1; // edge normals match collinearity condition

    return 0; // nope. not collinear
}

int ConvexPolyhedron::isFacePolygonConvex( Face & face, bool 
ignoreColinearVertices )
{
    int positive = 0, negative = 0, colinear = 0;
    for( unsigned int i = 0; i < face.vertices.size(); ++i )
    {
        osg::Vec3d va = face.vertices[i];
        osg::Vec3d vb = face.vertices[(i+1)%face.vertices.size()];
        osg::Vec3d vc = face.vertices[(i+2)%face.vertices.size()];


#if ( CONVEX_POLYHEDRON_WARN_ON_INCOHERENT_DATA  > 1 || 
CONVEX_POLYHEDRON_WARN_ON_CONCAVE_POLYGON )
        double dist = fabs( face.plane.distance( va ) );
        if( dist > 0.0001 )
        {
            WARN << "ConvexPolyhedron::isFacePolygonConvex - plane point too 
far from plane (" << dist <<")" << std::endl;
        }
#endif

        // cast points on a plane
        va -= face.plane.getNormal() * face.plane.distance( va );
        vb -= face.plane.getNormal() * face.plane.distance( vb );
        vc -= face.plane.getNormal() * face.plane.distance( vc );

        if( pointsColinear( va, vb, vc ) ) {
            colinear++;
        } else {
            double side =( ( vc  - vb ) ^ ( vb - va ) ) * 
face.plane.getNormal();

            if( side < 0 ) negative++;
            if( side > 0 ) positive++;
        }
    }

    if( !ignoreColinearVertices && colinear > 0 )
        return 0;

    if( !negative && !positive )
        return 0;

    if( (negative + colinear) == static_cast<int>(face.vertices.size()) )
        return -( negative + colinear );

    if( (positive + colinear) == static_cast<int>(face.vertices.size()) )
        return +( positive + colinear );

    return 0;
}

bool ConvexPolyhedron::checkCoherency
    ( bool checkForNonConvexPolys, const char * errorPrefix )
{
    bool result = true;
    bool convex = true;

#if CONVEX_POLYHEDRON_CHECK_COHERENCY

    if( !errorPrefix ) errorPrefix = "ConvexPolyhedron";

    typedef std::pair<osg::Vec3d, osg::Vec3d> Edge;
    typedef std::map<Edge,int> EdgeCounter;
    typedef std::map<osg::Vec3d,int> VertexCounter;

    EdgeCounter edgeCounter;
    VertexCounter vertexCounter;

    for( Faces::iterator itr = _faces.begin();
        itr != _faces.end();
        ++itr)
    {
        Face& face = *itr;

        if( checkForNonConvexPolys && !isFacePolygonConvex( face ) ) {
            convex = false;
#if ( 1 < CONVEX_POLYHEDRON_WARN_ON_INCOHERENT_DATA || 
CONVEX_POLYHEDRON_WARN_ON_CONCAVE_POLYGON )
            WARN << errorPrefix <<
                " - coherency fail - face polygon concave" << std::endl;
#endif
#if ( 1 < CONVEX_POLYHEDRON_DUMP_ON_INCOHERENT_DATA || 
CONVEX_POLYHEDRON_DUMP_ON_CONCAVE_POLYGON )
            dumpGeometry( &face );
#endif
        }

        Vertices& vertices = face.vertices;
        for(unsigned int i=0; i<vertices.size(); ++i)
        {
            osg::Vec3d& a = vertices[ i ];
            osg::Vec3d& b = vertices[ (i+1) % vertices.size()];
            ++vertexCounter[ a ];
            if (a<b)
                ++edgeCounter[Edge(a,b)];
            else
                ++edgeCounter[Edge(b,a)];
        }
    }


    for( EdgeCounter::iterator itr = edgeCounter.begin();
        itr != edgeCounter.end();
        ++itr)
    {
        const Edge &e = itr->first;

        if( e.first.isNaN() ) {
            result = false;
#if ( 1 < CONVEX_POLYHEDRON_WARN_ON_INCOHERENT_DATA )
            WARN << errorPrefix <<
                " - coherency fail - Vertex is NaN." << std::endl;
#endif
        }

        if( e.second.isNaN() ) {
            result = false;
#if ( 1 < CONVEX_POLYHEDRON_WARN_ON_INCOHERENT_DATA )
            WARN << errorPrefix <<
                " - coherency fail - Vertex is NaN." << std::endl;
#endif
        }

        if( e.first == e.second ) {
            result = false;
#if ( 1 < CONVEX_POLYHEDRON_WARN_ON_INCOHERENT_DATA )
            WARN << errorPrefix <<
                " - coherency fail - Edge with identical vertices." << 
std::endl;
#endif
        }

        if( vertexCounter[ e.first ] < 3 ) {
            result = false;
#if ( 1 < CONVEX_POLYHEDRON_WARN_ON_INCOHERENT_DATA )
            WARN << errorPrefix <<
                " - coherency fail - Vertex present " << vertexCounter[ e.first 
] << " times" << std::endl;
#endif
        }

        if( vertexCounter[ e.second ] < 3 ) {
            result = false;
#if ( 1 < CONVEX_POLYHEDRON_WARN_ON_INCOHERENT_DATA )
            WARN << errorPrefix <<
                " - coherency fail - Vertex present " << vertexCounter[ 
e.second ] << " times" << std::endl;
#endif
        }

        if( itr->second != 2 ) {
            result = false;
#if ( 1 < CONVEX_POLYHEDRON_WARN_ON_INCOHERENT_DATA )
            WARN << errorPrefix <<
                " - coherency fail - Edge present " << itr->second << " times" 
<< std::endl;
#endif
        }
    }

#if ( 1 == CONVEX_POLYHEDRON_WARN_ON_INCOHERENT_DATA )
    if( !convex )
        WARN << errorPrefix
            << " - coherency fail - non convex output" << std::endl;

    if ( !result )
        WARN << errorPrefix
            << " - coherency fail - incoherent output" << std::endl;
#endif

#if ( 1 == CONVEX_POLYHEDRON_DUMP_ON_INCOHERENT_DATA )
    if( !result || !convex )
        dumpGeometry( );
#endif

#if ( 1 < CONVEX_POLYHEDRON_DUMP_ON_INCOHERENT_DATA )
    if( !result )
        dumpGeometry( );
#endif


#endif // CONVEX_POLYHEDRON_CHECK_COHERENCY
    return result && convex;
}

osg::BoundingBox ConvexPolyhedron::computeBoundingBox( const osg::Matrix & m ) 
const
{
    osg::BoundingBox bb;

    if( &m != &defaultMatrix ) {
        for( Faces::const_iterator itr = _faces.begin(); itr != _faces.end(); 
++itr )
            for( Vertices::const_iterator vitr = itr->vertices.begin();
                 vitr != itr->vertices.end();
                 ++vitr )
                    bb.expandBy( *vitr * m );
    } else {
        for( Faces::const_iterator itr = _faces.begin(); itr != _faces.end(); 
++itr )
            for( Vertices::const_iterator vitr = itr->vertices.begin();
                 vitr != itr->vertices.end();
                 ++vitr )
                    bb.expandBy( *vitr );
    }

    return bb;
}

void ConvexPolyhedron::cut(const osg::Polytope & polytope)
{
    const char * apc[6] = { "left", "right", "bottom", "top", "near", "far" };
    char ac[16];
    int i = 0;

    for(osg::Polytope::PlaneList::const_iterator itr = 
polytope.getPlaneList().begin();
        itr != polytope.getPlaneList().end();
        ++itr)
    {
        const char* arg;
        if (i < 6) {
            arg = apc[i];
        } else {
            sprintf(ac, "%d", i);
            arg = ac;
        }
        cut(*itr, std::string( arg ) );

        i++;
    }

    removeDuplicateVertices();
}

void ConvexPolyhedron::cut(const ConvexPolyhedron& polytope)
{
    for(Faces::const_iterator itr = polytope._faces.begin();
        itr != polytope._faces.end();
        ++itr)
    {
        cut(itr->plane, itr->name);
    }

    removeDuplicateVertices();
}

void ConvexPolyhedron::cut(const osg::Plane& plane, const std::string& name)
{
    if( _faces.empty() ) return;

    ConvexPolyhedron cp( *this );

    typedef std::vector< FaceDistances > FaceDistancesList;
    FaceDistancesList faceDistances;
    faceDistances.resize( _faces.size() );

    double min = FLT_MAX, max = -FLT_MAX; //Hull max & min point distances


    // First step compute each face points distances to cutting plane
    Faces::iterator faces_itr = _faces.begin();
    for(FaceDistancesList::iterator fd = faceDistances.begin();
        faces_itr != _faces.end();
        ++faces_itr, ++fd )
    {
        fd->itr = faces_itr;
        fd->distances.reserve( faces_itr->vertices.size() );
        fd->on = 0;
        fd->above = 0;
        fd->below = 0;

#if 0 //  Skip if cutting plane the same as one of faces
        if( plane.ptr()[0] == faces_itr->plane.ptr()[0] &&
            plane.ptr()[1] == faces_itr->plane.ptr()[1] &&
            plane.ptr()[2] == faces_itr->plane.ptr()[2] &&
#else    // check plane using less precise float values
        if( float( plane.ptr()[0] ) == float( faces_itr->plane.ptr()[0] ) &&
            float( plane.ptr()[1] ) == float( faces_itr->plane.ptr()[1] ) &&
            float( plane.ptr()[2] ) == float( faces_itr->plane.ptr()[2] ) &&
#endif
            plane_hull_tolerance >= fabs( float( plane.ptr()[3] )-  float( 
faces_itr->plane.ptr()[3] ) ) )
            return;

        for(Vertices::iterator vitr = faces_itr->vertices.begin();
            vitr != faces_itr->vertices.end();
            ++vitr)
        {
            double d = plane.distance( *vitr );

            fd->distances.push_back( d );
            if ( d>point_plane_tolerance )       ++fd->above;
            else if ( d<-point_plane_tolerance ) ++fd->below;
            else                                 ++fd->on;
            min = osg::minimum( min, d );
            max = osg::maximum( max, d );
        }
    }

    if( max <= plane_hull_tolerance ) { // All points on or below cutting plane
        _faces.clear();
        return;
    }

    if( min >= -plane_hull_tolerance ) { // All points on or above cutting plane
        return;
    }

    typedef std::pair<osg::Vec3d, osg::Vec3d> Edge;
    typedef std::set< Edge > Edges;
    Edges edges;

    for( FaceDistancesList::iterator fd = faceDistances.begin();
        fd != faceDistances.end();
        ++fd )
    {
        if ( fd->below == 0 )
        {  // skip face if all points on or above cutting plane ( below == 0 )
            continue;
        }

        if ( /* fd->below > 0 && */ fd->above == 0 && fd->on == 0 )
        {
            _faces.erase( fd->itr ); // remove face if points below or on
            continue;
        }

        // cut the face if some points above and below plane
        // assert( fd->below > 0 && fd->above > 0 );

        Face& face = *(fd->itr);
        Vertices& vertices = face.vertices;
        Distances& distances = fd->distances;
        Vertices newFaceVertices;
        Vertices newVertices;


        for(unsigned int i=0; i < vertices.size(); ++i)
        {
            osg::Vec3d &va = vertices[i];
            osg::Vec3d &vb = vertices[(i+1)%vertices.size()];
            double &distance_a = distances[i];
            double &distance_b = distances[(i+1)%vertices.size()];

            // Is first edge point above or on the plane?
            if ( -point_plane_tolerance <= distance_a ) {

                if( newVertices.empty() || vertices[i] != newVertices.back() )
                    newVertices.push_back( vertices[i] );

                if ( distance_a <= point_plane_tolerance ) {
                    if( newFaceVertices.empty() || vertices[i] != 
newFaceVertices.back() )
                        newFaceVertices.push_back( vertices[i] );
                }
            }

            // Does edge intersect plane ?
            if ( ( distance_a < -point_plane_tolerance && distance_b > 
point_plane_tolerance ) ||
                 ( distance_b < -point_plane_tolerance && distance_a > 
point_plane_tolerance ) )
            {
                osg::Vec3d intersection; // Inserting vertex
                double da = fabs( distance_a ), db = fabs( distance_b );

                // tweaks to improve coherency of polytope after cut
                if( da <= point_point_equivalence && da <= db ) {
                    intersection = va;
                } else if( db <= point_point_equivalence && db <= da ) {
                    intersection = vb;
                } else {
                    double dab4 = 0.25 * ( da + db );
                    if( dab4 < da && dab4 < db ) {
                        intersection = (vb*distance_a - 
va*distance_b)/(distance_a-distance_b);
                    } else {
                        osg::Vec3d v = (vb - va)/(distance_a-distance_b);
                        if( da < db )
                            intersection = va + v * distance_a;
                        else
                            intersection = vb + v * distance_b;
                    }
                }

                if( newVertices.empty() || intersection != newVertices.back() )
                    newVertices.push_back( intersection );

                if( newFaceVertices.empty() || intersection != 
newFaceVertices.back() )
                    newFaceVertices.push_back( intersection );
            }
        }

        if( newVertices.size() && newVertices.front() == newVertices.back() )
            newVertices.pop_back();

        if( newFaceVertices.size() && newFaceVertices.front() == 
newFaceVertices.back() )
            newFaceVertices.pop_back();

        if( newFaceVertices.size() == 1 ) {  // This is very rare but correct
            WARN
                << "ConvexPolyhedron::cut - Slicing face polygon returns "
                << newFaceVertices.size()
                << " points. Should be 2 (usually) or 1 (rarely)."
                << std::endl;

        } else if( newFaceVertices.size() == 2 ) {
            if( newFaceVertices[0] < newFaceVertices[1] ) {
                edges.insert( Edge( newFaceVertices[0], newFaceVertices[1] ) );
            } else {
                edges.insert( Edge( newFaceVertices[1], newFaceVertices[0] ) );
            }
        } else if( newFaceVertices.size() > 2 ) {

#if CONVEX_POLYHEDRON_WARN_ON_INCORRECT_FACE_CUT

            // This may happen if face polygon is not planar or convex.
            // It may happen when face was distorted by projection transform
            // or when some polygon vertices land in incorrect positions after
            // some transformation by badly conditioned matrix (weak precison)

            WARN
                << "ConvexPolyhedron::cut - Slicing face polygon returns "
                << newFaceVertices.size()
                << " points. Should be 2 (usually) or 1 (rarely)."
                << std::endl;
#endif

#if CONVEX_POLYHEDRON_DUMP_ON_INCORRECT_FACE_CUT
            dumpGeometry( &face, &plane );
#endif

            // Let try to recover from this uneasy situation
            // by comparing current face polygon edges cut by new plane
            // with edges selected for new plane

            unsigned i0 = 0, i1 = newFaceVertices.size() - 1;
            unsigned j0 = 0, j1 = newVertices.size() - 1;

            for( ; i0 < newFaceVertices.size(); i1 = i0++, j1 = j0++ ) {
                while( newFaceVertices[i0] != newVertices[j0] ) j1 = j0++;
                if( newFaceVertices[i1] == newVertices[j1] )
                {
                    if( newFaceVertices[i0] < newFaceVertices[i1] ) {
                        edges.insert( Edge( newFaceVertices[i0], 
newFaceVertices[i1] ) );
                    } else {
                        edges.insert( Edge( newFaceVertices[i1], 
newFaceVertices[i0] ) );
                    }
                }
            }
        }

        if( newVertices.size() >= 3 ) { //Add faces with at least 3 points
#if ( CONVEX_POLYHEDRON_WARN_ON_CONCAVE_POLYGON || 
CONVEX_POLYHEDRON_DUMP_ON_CONCAVE_POLYGON )
            int convex = isFacePolygonConvex( face );
            vertices.swap( newVertices );
            if( convex && !isFacePolygonConvex( face ) ) {
#if CONVEX_POLYHEDRON_WARN_ON_CONCAVE_POLYGON
                WARN << "ConvexPolyhedron::cut - polygon output non convex."
                << " This may lead to other issues in ConvexPolyhedron math" << 
std::endl;
#endif
#if CONVEX_POLYHEDRON_DUMP_ON_CONCAVE_POLYGON
                dumpGeometry( &face, &plane, &cp );
#endif
            }
#else
            vertices.swap( newVertices );
#endif
        } else //Remove face reduced to 0, 1, 2 points
            _faces.erase( fd->itr );
    }

    if ( edges.size() > 1 ) //Ignore faces reduced to 0, 1, 2 points
    {
        Face face;
        face.name = name;
        face.plane = plane;

        std::deque< osg::Vec3d > vertices;

        Edges::iterator itr = edges.begin();
        vertices.push_back( itr->first );
        vertices.push_back( itr->second );
        edges.erase( itr++ );

        for( unsigned int vertices_size = 0;
            vertices_size < vertices.size(); )
        {
            vertices_size = vertices.size();
            for( itr = edges.begin(); itr != edges.end(); )
            {
                bool not_added = false;

                if( itr->first == vertices.back() )
                    vertices.push_back( itr->second );
                else if ( itr->first == vertices.front() )
                    vertices.push_front( itr->second );
                else if ( itr->second == vertices.back() )
                    vertices.push_back( itr->first );
                else if ( itr->second == vertices.front() )
                    vertices.push_front( itr->first );
                else
                    not_added = true;

                if( not_added )
                    ++itr;
                else
                    edges.erase( itr++ );
            }
        }

#if CONVEX_POLYHEDRON_WARN_ON_BAD_POLYGON
        if( !edges.empty() ) {
            WARN
                << "ConvexPolyhedron::cut - Building new face polygon - "
                << "Found edges not matching former polygon ends"
                << std::endl;
        }
#endif

        std::copy(vertices.begin(), vertices.end(), 
std::back_inserter(face.vertices));

        _faces.push_back(face);

        // Last vertex is duplicated - remove one instance
        if( face.vertices.front() == face.vertices.back() )
            face.vertices.pop_back();
        else {// If not duplicated then it may mean we have open polygon ;-(
#if CONVEX_POLYHEDRON_WARN_ON_BAD_POLYGON
            WARN
            << "ConvexPolyhedron::cut - Building new face polygon - "
            << " Polygon not properly closed."
            << std::endl;
#endif
#if CONVEX_POLYHEDRON_DUMP_ON_BAD_POLYGON
            dumpGeometry( &_faces.back(), &plane, &cp );
#endif
        }

#if ( CONVEX_POLYHEDRON_WARN_ON_CONCAVE_POLYGON || 
CONVEX_POLYHEDRON_DUMP_ON_CONCAVE_POLYGON )
        if( !isFacePolygonConvex( face ) ) {
#if CONVEX_POLYHEDRON_DUMP_ON_CONCAVE_POLYGON
            ConvexPolyhedron cp;
            cp.createFace() = face;
            cp.dumpGeometry( );
#endif
#if CONVEX_POLYHEDRON_WARN_ON_CONCAVE_POLYGON
            WARN << "ConvexPolyhedron::cut - new face polygon non convex."
                << " This may lead to other issues in ConvexPolyhedron math" << 
std::endl;
#endif
        }
#endif
    }

//    removeDuplicateVertices( );
}
////////////////////////////////////////////////////////////////////////////
void ConvexPolyhedron::extrude( const osg::Vec3d & offset )
{
    if( offset.length2() == 0 ) return;

    typedef std::pair<osg::Vec3d, osg::Vec3d> Edge;
    typedef std::vector<Face*> EdgeFaces;
    typedef std::map<Edge, EdgeFaces> EdgeMap;

    EdgeMap edgeMap;

    // Build edge maps
    for(Faces::iterator itr = _faces.begin();
        itr != _faces.end();
        ++itr)
    {
        Face& face = *itr;
        for(unsigned int i=0; i<face.vertices.size(); ++i)
        {
            osg::Vec3d& va = face.vertices[i];
            osg::Vec3d& vb = face.vertices[(i+1)%face.vertices.size()];
            if (va < vb) edgeMap[Edge(va,vb)].push_back(&face);
            else edgeMap[Edge(vb,va)].push_back(&face);
        }
    }

    // Offset faces
    for(Faces::iterator itr = _faces.begin();
        itr != _faces.end();
        ++itr)
    {
        Face& face = *itr;

        double dotOffset = face.plane.dotProductNormal( offset );

        if( dotOffset >= 0 ) continue;

        face.plane.ptr()[3] -= dotOffset;
        for(unsigned int i=0; i<face.vertices.size(); ++i)
        {
            face.vertices[i] += offset;
        }
    }

    typedef std::set< Edge > SilhouetteEdges;
    typedef std::map< Face*, SilhouetteEdges > SilhouetteFaces;
    SilhouetteFaces silhouetteFaces;

    int new_face_counter = 0;

    // Now add new faces from slhouette edges extrusion
    for(EdgeMap::iterator eitr = edgeMap.begin();
        eitr != edgeMap.end();
        ++eitr)
    {
        const Edge& edge = eitr->first;
        const EdgeFaces& edgeFaces = eitr->second;

        if ( edgeFaces.size()==1 )
        {
            // WL: Execution should not reach this line.
            // If you got here let me know: [email protected]
            assert( 0 );
        }
        else if ( edgeFaces.size()==2 )
        {
#if 0 // Use float normal computations
            osg::Vec3f vf( offset );
            double dotOffset0 = osg::Vec3f( edgeFaces[0]->plane.getNormal() ) * 
vf;
            double dotOffset1 = osg::Vec3f( edgeFaces[1]->plane.getNormal() ) * 
vf;
#else
            double dotOffset0 = edgeFaces[0]->plane.getNormal() * offset;
            double dotOffset1 = edgeFaces[1]->plane.getNormal() * offset;
#endif
            //Select orthogonal faces and vertices appropriate for offsetting
            if( (dotOffset0 == 0.0 && dotOffset1 < 0.0) ||
                (dotOffset1 == 0.0 && dotOffset0 < 0.0) )
            {
                Face * face = ( dotOffset0 == 0 ? edgeFaces[0] : edgeFaces[1] );
                silhouetteFaces[ face ].insert( edge );
            }

            if( (dotOffset0 < 0.0 && dotOffset1 > 0.0) ||
                (dotOffset1 < 0.0 && dotOffset0 > 0.0) )
            {
                Face & face = createFace();
                char ac[40] = "Side plane from edge extrude ";
                sprintf(ac + strlen(ac), "%d", new_face_counter++);
                face.name = ac;

                // Compute face plane
                face.vertices.push_back( edge.first );
                face.vertices.push_back( edge.second );

                osg::Vec3d n = face.vertices[0] - face.vertices[1];
                n.normalize();
                n = ( n ^ offset );
                n.normalize();

                if( n * ( edgeFaces[1]->plane.getNormal() + 
edgeFaces[0]->plane.getNormal() ) < 0 )
                {
                    n = -n;
                    std::swap( face.vertices[1], face.vertices[0] );
                }

                face.vertices.push_back( face.vertices[1] + offset );
                face.vertices.push_back( face.vertices[0] + offset );

                face.plane.set( n,(face.vertices[0] + face.vertices[1] +
                    face.vertices[2] + face.vertices[3]) * .25 );
            }
        }
        else if( edgeFaces.size() > 2 )
        {
            assert( 0 );
            // WL: Execution should not reach this line.
            // If you got here let me know: [email protected]
        }
    }

    // Finally update faces which are orthogonal to our normal
    for(SilhouetteFaces::iterator itr = silhouetteFaces.begin();
        itr != silhouetteFaces.end();
        ++itr)
    {
        SilhouetteEdges & edges = itr->second;
        Vertices & vertices =  itr->first->vertices;
        Vertices newVertices;

        for( unsigned int i = 0; i < vertices.size(); i++ )
        {
            osg::Vec3d
                &va = vertices[ ( i + vertices.size() - 1 ) % vertices.size() ],
                &vb = vertices[  i  ],
                &vc = vertices[ ( i +  1 ) % vertices.size() ];

            Edge eab =  va < vb ? Edge( va, vb ) : Edge( vb, va );
            Edge ebc =  vb < vc ? Edge( vb, vc ) : Edge( vc, vb );

            bool abFound = edges.find( eab ) != edges.end();
            bool bcFound = edges.find( ebc ) != edges.end();

            if( abFound && bcFound ) {
                newVertices.push_back( vb + offset );
            } else if( !abFound && !bcFound ) {
                newVertices.push_back( vb );
            } else if( !abFound && bcFound ) {
                newVertices.push_back( vb );
                newVertices.push_back( vb + offset );
            } else if( abFound && !bcFound ) {
                newVertices.push_back( vb + offset );
                newVertices.push_back( vb );
            }
        }

        vertices.swap( newVertices );
    }

    removeDuplicateVertices( );
    checkCoherency( true, "ConvexPolyhedron::extrude" );
}
////////////////////////////////////////////////////////////////////////////
void ConvexPolyhedron::translate( const osg::Vec3d & offset )
{
    for( Faces::iterator itr = _faces.begin(); itr != _faces.end(); ++itr )
    {
        itr->plane.ptr()[3] -= itr->plane.dotProductNormal( offset );

        for( Vertices::iterator vitr = itr->vertices.begin();
             vitr != itr->vertices.end();
             ++vitr )
        {
            *vitr += offset;
        }
    }
}
////////////////////////////////////////////////////////////////////////////
void ConvexPolyhedron::getPolytope(osg::Polytope& polytope) const
{
    for(Faces::const_iterator itr = _faces.begin();
        itr != _faces.end();
        ++itr)
    {
        polytope.add(itr->plane);
    }
}
////////////////////////////////////////////////////////////////////////////
void ConvexPolyhedron::getPoints(Vertices& vertices) const
{
    typedef std::set<osg::Vec3d> VerticesSet;
    VerticesSet verticesSet;
    for(Faces::const_iterator itr = _faces.begin();
        itr != _faces.end();
        ++itr)
    {
        const Face& face = *itr;
        for(Vertices::const_iterator vitr = face.vertices.begin();
            vitr != face.vertices.end();
            ++vitr)
        {
            verticesSet.insert(*vitr);
        }
    }

    for(VerticesSet::iterator sitr = verticesSet.begin();
        sitr != verticesSet.end();
        ++sitr)
    {
        vertices.push_back(*sitr);
    }
}
////////////////////////////////////////////////////////////////////////////
osg::Geometry* ConvexPolyhedron::buildGeometry( const osg::Vec4d& colorOutline,
                                         const osg::Vec4d& colorInside,
                                         osg::Geometry* geometry ) const
{
    if( !geometry ) {
        geometry = new osg::Geometry;
    } else {
        geometry->getPrimitiveSetList( ).clear();
    }

    osg::Vec3dArray* vertices = new osg::Vec3dArray;
    geometry->setVertexArray(vertices);

    osg::Vec4Array* colors = new osg::Vec4Array;
    geometry->setColorArray(colors, osg::Array::BIND_PER_PRIMITIVE_SET);

    for(Faces::const_iterator itr = _faces.begin();
        itr != _faces.end();
        ++itr)
    {
        if( colorInside[3] > 0 ) {
            geometry->addPrimitiveSet( new osg::DrawArrays( GL_TRIANGLE_FAN,
                vertices->size(), itr->vertices.size() ) );

            colors->push_back( colorInside );
        }

        if( colorOutline[3] > 0 ) {
            geometry->addPrimitiveSet( new osg::DrawArrays( GL_LINE_LOOP,
                vertices->size(), itr->vertices.size() ) );

            colors->push_back( colorOutline );
        }

        vertices->insert
            ( vertices->end(), itr->vertices.begin(), itr->vertices.end() );
    }

    osg::StateSet* stateset = geometry->getOrCreateStateSet();
    stateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
    stateset->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::OFF);
    stateset->setTextureMode(1, GL_TEXTURE_2D, osg::StateAttribute::OFF);

    return geometry;
}
////////////////////////////////////////////////////////////////////////////
bool ConvexPolyhedron::dumpGeometry
( const Face * face,
  const osg::Plane * plane,
  ConvexPolyhedron * base,
  const char * filename,
  const osg::Vec4d& colorOutline,
  const osg::Vec4d& colorInside,
  const osg::Vec4d& faceColorOutline,
  const osg::Vec4d& faceColorInside,
  const osg::Vec4d& planeColorOutline,
  const osg::Vec4d& planeColorInside,
  const osg::Vec4d& baseColorOutline,
  const osg::Vec4d& baseColorInside ) const
{
    osg::Group * group = new osg::Group();
    osg::Geode * geode = new osg::Geode();
    geode->getOrCreateStateSet()->setMode( GL_BLEND, osg::StateAttribute::ON );
    geode->getOrCreateStateSet()->setMode( GL_CULL_FACE, 
osg::StateAttribute::OFF );
    geode->getOrCreateStateSet()->setMode( GL_DEPTH_TEST, 
osg::StateAttribute::OFF );

    group->addChild( geode );

    Vertices vertices;
    getPoints( vertices );

    osg::BoundingBox bb;
    for( unsigned int i = 0; i < vertices.size(); i++ )
        bb.expandBy( vertices[i] );

    ConvexPolyhedron cph( *this ), cpFace;

    for( Faces::iterator itr = cph._faces.begin(); itr != cph._faces.end(); )
    {
        bool found = ( face &&
                       itr->name == face->name &&
                       itr->plane == face->plane &&
                       itr->vertices == face->vertices );
#if 1
        if( cph.isFacePolygonConvex( *itr ) < 0 )
            std::reverse( itr->vertices.begin(), itr->vertices.end() );
#endif

        if( found ) {
            cpFace.createFace() = *face;
            itr = cph._faces.erase( itr );
        } else {
            ++itr;
        }
    }

    osg::Geometry * geometry = cph.buildGeometry( colorOutline, colorInside );
    geometry->getOrCreateStateSet()->setMode( GL_CULL_FACE, 
osg::StateAttribute::ON );

    geode->addDrawable( geometry );

    if( face )
        geode->addDrawable( cpFace.buildGeometry( faceColorOutline, 
faceColorInside ) );

    if( plane )
    {
        ConvexPolyhedron cp;
        Face & cp_face = cp.createFace();
        cp_face.plane = *plane;

        osg::Vec3d normal = cp_face.plane.getNormal();
        osg::Vec3d side = fabs(normal.x()) < fabs(normal.y()) ?
                            osg::Vec3d(1.0, 0.0, 0.0) :
                            osg::Vec3d(0.0, 1.0, 0.0);

        osg::Vec3d v = normal ^ side;
        v.normalize();
        v *= bb.radius();

        osg::Vec3d u = v ^ normal;
        u.normalize();
        u *= bb.radius();

        osg::Vec3d c = bb.center();
        c -= cp_face.plane.getNormal() * cp_face.plane.distance( c );

        cp_face.vertices.push_back( c - u - v );
        cp_face.vertices.push_back( c - u + v );
        cp_face.vertices.push_back( c + u + v );
        cp_face.vertices.push_back( c + u - v );

        geode->addDrawable( cp.buildGeometry( planeColorOutline, 
planeColorInside ) );
    }

    if( base )
        geode->addDrawable( base->buildGeometry( baseColorOutline, 
baseColorInside ) );

    return osgDB::writeNodeFile( *group, std::string( filename ) );
}
////////////////////////////////////////////////////////////////////////////
_______________________________________________
osg-users mailing list
[email protected]
http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org

Reply via email to