Hi,

today I ask for some guidance with the following problem:

I have written a pick framework which allows fast frustum picking of polygons, 
lines and points. In principle this works fine until recently. Problems show up 
the moment I have introduced the first 'InverseTransform' core into the scene 
graph. After some debugging I found that I have made a terrible mistake in my 
"SimpleSelectionFunctor" class. Eliminating this error did reveal a weakness, 
at least IMHO, of the OpenSG framework, which I  would like to remove. But 
maybe I did it all completely wrong and should take another route. So allow me 
to lay done my design and implementation so that you can understand the core of 
my problem.

User code: frustum picking
=================
void View::pick(NodePtr root, UInt32 x0, UInt32 y0, UInt32 x1, UInt32 y1)
{
    graphic::Frustum frustum = calcViewFrustum(x0, y0, x1, y1);

    SelectionAction* action = SelectionAction::create(frustum);
    SimpleSelectionFunctor selFunc(action, SimpleSelectionFunctor::FACE);

    action->apply(root);

    BOOST_FOREACH(const SimpleSelectionFunctor::HitT& hit, selFunc.hits()) 
    {
        ...
    }
}

Implementation details
===============

// Basically the same as Action (could be improved, but is not the point here)
class SelectionAction : public Action
{
public:
    static void registerEnterDefault(const FieldContainerType& type, 
                                     const Action::Functor&    func);
    
    static void registerLeaveDefault(const FieldContainerType& type, 
                                     const Action::Functor&    func);
private:
    std::stack<RenderEngine::graphic::Frustum>  _frustums;
    std::stack<NodePtr>                         _nodes;
    std::stack<Matrix>                          _matrices;
    FrustumVolume                               _frustumVolume;
    SelectionFunctor*                           _actor;

    static std::vector<Functor>* _defaultEnterFunctors;
    static std::vector<Functor>* _defaultLeaveFunctors;
};

// Base class functor
class SelectionFunctor : boost::noncopyable
{
public:
    enum SelectionType {
        FACE   = 0x0001,
        EDGE   = 0x0002,
        VERTEX = 0x0004,
        ALL    = FACE | EDGE | VERTEX
    };

    enum HitType {
        PRIMITIVE,
        OBJECT_IN_VIEW_DIR,
        OBJECT_AGAINST_VIEW_DIR
    };

    struct HitT {...}

    typedef std::deque<HitT> DequeHitsT;

public:
    void                setAction(SelectionAction* action);

    void                start();
    void                stop();

    const DequeHitsT&   hits(HitType hitType = OBJECT_IN_VIEW_DIR) const;

protected:
    SelectionAction* _action;
    SelectionType    _selectionType;
    DequeHitsT       _dequeHits;
};

// Functor with terrible wrong implementation
class SimpleSelectionFunctor : public SelectionFunctor
{
public:
                SimpleSelectionFunctor();

private:
    virtual void    init();

    Action::ResultE enterTransform(CNodePtr& node, Action* action);
    Action::ResultE leaveTransform(CNodePtr& node, Action* action);

    Action::ResultE enterAccumulateTransform(CNodePtr& node, Action* action);
    Action::ResultE leaveAccumulateTransform(CNodePtr& node, Action* action);

    Action::ResultE enterGeometry(CNodePtr& node, Action* action);
    Action::ResultE leaveGeometry(CNodePtr& node, Action* action);

    Action::ResultE enterMultiSwitch(CNodePtr& node, Action* action);
    Action::ResultE leaveMultiSwitch(CNodePtr& node, Action* action);

    void            triangles   (const Plane& plane, const GeometryPtr& geo);
    void            lines       (const Plane& plane, const GeometryPtr& geo);
    void            points      (const Plane& plane, const GeometryPtr& geo);
};

//
// Init: Register the handler functions
//
void SimpleSelectionFunctor::init()
{
    if (!_action) return;

    Base::init();

    typedef Action::ResultE T1;
    typedef SimpleSelectionFunctor T2;
    typedef CNodePtr T3;
    typedef Action* T4;

    _action->registerEnterFunction(Transform::getClassType(),           
osgTypedMethodFunctor2ObjPtrCPtrRef<T1, T2, T3, T4>(this, 
&SimpleSelectionFunctor::enterTransform));
    _action->registerLeaveFunction(Transform::getClassType(),           
osgTypedMethodFunctor2ObjPtrCPtrRef<T1, T2, T3, T4>(this, 
&SimpleSelectionFunctor::leaveTransform));
    _action->registerEnterFunction(ComponentTransform::getClassType(),  
osgTypedMethodFunctor2ObjPtrCPtrRef<T1, T2, T3, T4>(this, 
&SimpleSelectionFunctor::enterTransform));
...
    _action->registerEnterFunction(InverseTransform::getClassType(),    
osgTypedMethodFunctor2ObjPtrCPtrRef<T1, T2, T3, T4>(this, 
&SimpleSelectionFunctor::enterAccumulateTransform));
    _action->registerLeaveFunction(InverseTransform::getClassType(),    
osgTypedMethodFunctor2ObjPtrCPtrRef<T1, T2, T3, T4>(this, 
&SimpleSelectionFunctor::leaveAccumulateTransform));
    _action->registerEnterFunction(Billboard::getClassType(),           
osgTypedMethodFunctor2ObjPtrCPtrRef<T1, T2, T3, T4>(this, 
&SimpleSelectionFunctor::enterAccumulateTransform));
...
    _action->registerEnterFunction(Geometry::getClassType(),            
osgTypedMethodFunctor2ObjPtrCPtrRef<T1, T2, T3, T4>(this, 
&SimpleSelectionFunctor::enterGeometry));
    _action->registerLeaveFunction(Geometry::getClassType(),            
osgTypedMethodFunctor2ObjPtrCPtrRef<T1, T2, T3, T4>(this, 
&SimpleSelectionFunctor::leaveGeometry));

...
}

//
// My mistake the terrible wrong handler implementation for InverseTransform 
and the like
//
Action::ResultE SimpleSelectionFunctor::enterAccumulateTransform(CNodePtr& cp, 
Action* action)
{
    NodePtr trans_node = _action->getActNode();
    DynamicVolume volume = trans_node->getVolume();
    if (volume.isValid() && !volume.intersect(_action->frustumVolume()))
        return Action::Skip;

    NodeCorePtr  core  = trans_node->getCore();
    TransformPtr trans = TransformPtr::dcast(core); 

// Hue, that is plainly wrong and will later crash! InverseTransform
// does not inherit from Transform but from Group and NodeCore.

    Matrix mat;
    mat.setIdentity();
    trans->accumulateMatrix(mat); // crash...
    mat.invert();

    RenderEngine::graphic::Frustum frustum = _action->topFrustum();
    frustum.multFullMatrix(mat);

    mat = _action->topMatrix();
    trans->accumulateMatrix(mat);

    _action->pushMatrix(mat);
    _action->pushFrustum(frustum);
    _action->pushNode(trans_node);

    return Action::Continue; 
}

//
// So I tried to repair the code above with the following code
//
Action::ResultE SimpleSelectionFunctor::enterAccumulateTransform(CNodePtr& cp, 
Action* action)
{
    NodePtr trans_node = _action->getActNode();
    DynamicVolume volume = trans_node->getVolume();
    if (volume.isValid() && !volume.intersect(_action->frustumVolume()))
        return Action::Skip;

    NodeCorePtr  core  = trans_node->getCore();

    Matrix mat;
    mat.setIdentity();
    core->accumulateMatrix(mat); // Does not compile NodeCore::accumulateMatrix 
is protected
    mat.invert();

    RenderEngine::graphic::Frustum frustum = _action->topFrustum();
    frustum.multFullMatrix(mat);

    mat = _action->topMatrix();
    core->accumulateMatrix(mat);

    _action->pushMatrix(mat);
    _action->pushFrustum(frustum);
    _action->pushNode(trans_node);

    return Action::Continue; 
}

Now, I'm at the core of my problem. 'NodeCore' base class function 
'accumulateMatrix' is protected, therefore preventing polymorphic dispatching 
to the correct implementation in my client code. Of course, I could write 
different handler functions for each class, like 
'enterAccumulateInverseTransform', but that is cumbersome and does not scale 
very well. 

So my point is that NodeCore::accumulateMatrix and NodeCore::adjustVolume 
should be public instead.

If there is a more elegant way to write custom actions I would be glad to learn 
about them. However, until now my solution did work quite fine.

Any help and suggestions are appreciated.

With best regards,
Johannes






------------------------------------------------------------------------------
This SF.net email is sponsored by:
SourcForge Community
SourceForge wants to tell your story.
http://p.sf.net/sfu/sf-spreadtheword
_______________________________________________
Opensg-users mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/opensg-users

Reply via email to