EntityOwner is moving at different pace than AIS_Object when dragged?

eue

Active CAD practitioner
I call UpdateTransformation() to set the global position of the object after drag within the overridden ProcessDragging(), but strange is that its attached EntityOwner seems to move at different pace than the AIS_Object.

C++:
Standard_Boolean BIM_InteractiveObject::ProcessDragging(const Handle(AIS_InteractiveContext)& theCtx, const Handle(V3d_View)& theView, const Handle(SelectMgr_EntityOwner)& theOwner, const Graphic3d_Vec2i & theDragFrom, const Graphic3d_Vec2i & theDragTo, const AIS_DragAction theAction)
{
    if (theAction == AIS_DragAction_Update)
    {
        Handle(StdSelect_ViewerSelector3d) aSelector = this->InteractiveContext()->MainSelector();
        SelectMgr_SortCriterion aPickPnt;
        for (int aPickIter = 1; aPickIter <= aSelector->NbPicked(); ++aPickIter)
        {
            if (aSelector->Picked(aPickIter) == theOwner) // filter out other SelectMgr_EntityOwner
            {
                aPickPnt = aSelector->PickedData(aPickIter);
                break;
            }
        }
        gp_Trsf DirTrans;
        DirTrans.SetTranslation(gp_Pnt(aPickPnt.Point.X(), aPickPnt.Point.Y(), aPickPnt.Point.Z()), gp_Pnt(position_in_view.x(), position_in_view.y(), position_in_view.z()));

        this->SetLocalTransformation(DirTrans);
       
    }
    else if (theAction == AIS_DragAction_Stop)
    {
    this->UpdateTransformation(); // should update the absolute transformation of the object    
    }
    return true;
}


What happens is after the object dragged, it stops interacting with my mouse.

Only after placing a new object (maybe triggering refreshment of entity owners), the highlighted entity appears in random/different position when hovering mouse over the AIS object. [see picture one]

But clicking it transport the object to where entity owner is at. [see picture two]

My guess at this problem is maybe the entity owner is moving at a different pace than the dragged AIS object, this cause the object to separate from entity?
but I can't figure out why it is so and how to fix this?

1655106829114.png
1655106852188.png
 

JSlyadne

Administrator
Staff member
I call UpdateTransformation() to set the global position of the object after drag within the overridden ProcessDragging(), but strange is that its attached EntityOwner seems to move at different pace than the AIS_Object.

C++:
Standard_Boolean BIM_InteractiveObject::ProcessDragging(const Handle(AIS_InteractiveContext)& theCtx, const Handle(V3d_View)& theView, const Handle(SelectMgr_EntityOwner)& theOwner, const Graphic3d_Vec2i & theDragFrom, const Graphic3d_Vec2i & theDragTo, const AIS_DragAction theAction)
{
    if (theAction == AIS_DragAction_Update)
    {
        Handle(StdSelect_ViewerSelector3d) aSelector = this->InteractiveContext()->MainSelector();
        SelectMgr_SortCriterion aPickPnt;
        for (int aPickIter = 1; aPickIter <= aSelector->NbPicked(); ++aPickIter)
        {
            if (aSelector->Picked(aPickIter) == theOwner) // filter out other SelectMgr_EntityOwner
            {
                aPickPnt = aSelector->PickedData(aPickIter);
                break;
            }
        }
        gp_Trsf DirTrans;
        DirTrans.SetTranslation(gp_Pnt(aPickPnt.Point.X(), aPickPnt.Point.Y(), aPickPnt.Point.Z()), gp_Pnt(position_in_view.x(), position_in_view.y(), position_in_view.z()));

        this->SetLocalTransformation(DirTrans);
      
    }
    else if (theAction == AIS_DragAction_Stop)
    {
    this->UpdateTransformation(); // should update the absolute transformation of the object   
    }
    return true;
}


What happens is after the object dragged, it stops interacting with my mouse.

Only after placing a new object (maybe triggering refreshment of entity owners), the highlighted entity appears in random/different position when hovering mouse over the AIS object. [see picture one]

But clicking it transport the object to where entity owner is at. [see picture two]

My guess at this problem is maybe the entity owner is moving at a different pace than the dragged AIS object, this cause the object to separate from entity?
but I can't figure out why it is so and how to fix this?

View attachment 289
View attachment 290
In OCCT the presentations and the presentations for interactivity such as a pointer moving assuming dynamic highlighting and a pointer clicking assuming selection are built independently. That's why if a form and/or transformation of AIS object is changed, we should also take care about highlighting and selection entities.

this->UpdateTransformation();

In contrast to UpdateTransformation(...) that transforms the caller object only and doing nothing for the selection entities, you might look at AIS_InteractiveContext::SetLocation(...) method - it will give you an idea how to update the selection entities as well.
 

natalia

Moderator
Staff member
Hello, @eue

The missed functionality in attached implementation is:
  • saving some presentation values on drag start (the most important is the current local transformation),
  • it’s better using parameter of the ProcessDragging method instead of pick,
  • adding the current local transformation to the presentation start transformation during update,
  • update selection on the presentation on drag stop.
UpdateTransformation on Stop didn’t help because it’s already called inside SetLocalTransfomration. We may check it at PrsMgr_PresentableObject::setLocalTransformation.

The proposed implementation for described case is:
C++:
Standard_Boolean viewerDrag_presentation::ProcessDragging (const Handle(AIS_InteractiveContext)& context,
                                                            const Handle(V3d_View)&              view,
                                                            const Handle(SelectMgr_EntityOwner)& owner,
                                                            const Graphic3d_Vec2i&               dragFrom,
                                                            const Graphic3d_Vec2i&               dragTo,
                                                            const AIS_DragAction                 action)
{
  if (action == AIS_DragAction_Start)
  {
    m_startPosition = dragFrom;
    m_startTrsf = Transformation();
    m_startAttributes = Attributes();

    // hide detected presentation in the viewer as it will be changed on drag
    InteractiveContext()->ClearDetected();

    // set visual parameters into presentation as it's highlighted and recompute presentation
    SetAttributes(this->InteractiveContext()->HighlightStyle());
    InteractiveContext()->RecomputePrsOnly (this, false);
  }
  if (action == AIS_DragAction_Update)
  {
      gp_Trsf DirTrans;
      const Handle(V3d_View) view = this->InteractiveContext()->LastActiveView();
      gp_Vec translationVec = GetTranslationVector(view, m_startPosition.x(), m_startPosition.y(), dragTo.x(), dragTo.y());
      DirTrans.SetTranslation(translationVec);

      // unites the previuos and the current transformations
      gp_Trsf trsf = DirTrans * m_startTrsf;

      SetLocalTransformation(trsf);
  }
  else if (action == AIS_DragAction_Stop)
  {
    // recompute selection on the presentation
    InteractiveContext()->SelectionManager()->Update(this);

    // restore initial visual attributes and recompute presentation
    SetAttributes(m_startAttributes);
    InteractiveContext()->RecomputePrsOnly (this, false);

    // restore highlight in the viewer
    const Handle(V3d_View) view = this->InteractiveContext()->LastActiveView();
    InteractiveContext()->MoveTo(dragTo.x(), dragTo.y(), view, true);
  }
  return true;
}

(The whole example is available in Git repository: https://gitlab.com/ssv/lessons/-/tree/viewerDrag, package is extras_viewerDrag)

This sample is preparing in the same way as AIS_Manipulator processes the dragging. Manipulator also unites the previous local transformations of parameter objects with the new one.

Additionally this code has some rows for styling change of the current object. We set style of highlight on start and restore the basic one on stop. This seems to be a way for having better performance than updating highlighted presentation on each drag.

One more remark about the proposed piece of code. It’s better to call MoveTo and ClearDetected in the class that calls ProcessDragging (outside of the presentation). These methods are here for better understanding where we need them.
 

eue

Active CAD practitioner
thank you so much, I implemented the code you gave, the selection entity now moves with AIS_object and always interactable with the mouse, so this is one problem solved.

However, AIS_Shape when dragged always starts at the position where it is first placed.

here is the code I implemented after studying yours.

Code:
Standard_Boolean BIM_InteractiveObject::ProcessDragging(const Handle(AIS_InteractiveContext)& theCtx, const Handle(V3d_View)& theView, const Handle(SelectMgr_EntityOwner)& theOwner, const Graphic3d_Vec2i & theDragFrom, const Graphic3d_Vec2i & theDragTo, const AIS_DragAction theAction)
{
    if (theAction == AIS_DragAction_Update && this->DisplayMode() != BIM_InteractiveObject::MyDispMode_ReShape)
    {
        Handle(StdSelect_ViewerSelector3d) aSelector = this->InteractiveContext()->MainSelector();
        SelectMgr_SortCriterion aPickPnt;
        for (int aPickIter = 1; aPickIter <= aSelector->NbPicked(); ++aPickIter)
        {
            if (aSelector->Picked(aPickIter) == theOwner) // filter out other SelectMgr_EntityOwner
            {
                aPickPnt = aSelector->PickedData(aPickIter);
                break;
            }
        }
        gp_Trsf DirTrans;
        DirTrans.SetTranslation(gp_Pnt(aPickPnt.Point.X(), aPickPnt.Point.Y(), aPickPnt.Point.Z()), gp_Pnt(position_in_view.x(), position_in_view.y(), position_in_view.z()));

        this->SetLocalTransformation(DirTrans);
        
    }
    else if (theAction == AIS_DragAction_Stop)
    {
        wprintf(L"stopping AIS_DragAction\n");

        InteractiveContext()->SelectionManager()->Update(this);

    }
    else if (theAction == AIS_DragAction_Abort)
    {
        wprintf(L"aborting AIS_DragAction\n");
        this->ResetTransformation();
    }
    return true;
}

so the InteractiveContext()->SelectionManager()->Update(this) allows the selection entity to be re-placed onto AIS_Object. However, the AIS_Object seems to not be moved to the end position. The bypass to this problem is reimplementing a different myshape. But it isn't really a solution.

Could you kindly tell me the solution?
 
Last edited:

natalia

Moderator
Staff member
However, AIS_Shape when dragged always starts at the position where it is first placed.
You should store the previous local transformation value and add it to the new one, have a look at variable m_startTrsf in the code above. Good luck)
 
  • Like
Reactions: eue

JSlyadne

Administrator
Staff member
thank you so much, I implemented the code you gave, the selection entity now moves with AIS_object and always interactable with the mouse, so this is one problem solved.

However, AIS_Shape when dragged always starts at the position where it is first placed.

here is the code I implemented after studying yours.

Code:
Standard_Boolean BIM_InteractiveObject::ProcessDragging(const Handle(AIS_InteractiveContext)& theCtx, const Handle(V3d_View)& theView, const Handle(SelectMgr_EntityOwner)& theOwner, const Graphic3d_Vec2i & theDragFrom, const Graphic3d_Vec2i & theDragTo, const AIS_DragAction theAction)
{
    if (theAction == AIS_DragAction_Update && this->DisplayMode() != BIM_InteractiveObject::MyDispMode_ReShape)
    {
        Handle(StdSelect_ViewerSelector3d) aSelector = this->InteractiveContext()->MainSelector();
        SelectMgr_SortCriterion aPickPnt;
        for (int aPickIter = 1; aPickIter <= aSelector->NbPicked(); ++aPickIter)
        {
            if (aSelector->Picked(aPickIter) == theOwner) // filter out other SelectMgr_EntityOwner
            {
                aPickPnt = aSelector->PickedData(aPickIter);
                break;
            }
        }
        gp_Trsf DirTrans;
        DirTrans.SetTranslation(gp_Pnt(aPickPnt.Point.X(), aPickPnt.Point.Y(), aPickPnt.Point.Z()), gp_Pnt(position_in_view.x(), position_in_view.y(), position_in_view.z()));

        this->SetLocalTransformation(DirTrans);
      
    }
    else if (theAction == AIS_DragAction_Stop)
    {
        wprintf(L"stopping AIS_DragAction\n");

        InteractiveContext()->SelectionManager()->Update(this);

    }
    else if (theAction == AIS_DragAction_Abort)
    {
        wprintf(L"aborting AIS_DragAction\n");
        this->ResetTransformation();
    }
    return true;
}

so the InteractiveContext()->SelectionManager()->Update(this) allows the selection entity to be re-placed onto AIS_Object. However, the AIS_Object seems to not be moved to the end position. The bypass to this problem is reimplementing a different myshape. But it isn't really a solution.

Could you kindly tell me the solution?
@eue What is the intention of getting a picked point? Why not just to apply a translation stored in "dragTo" parameter of ProcessDraging(...) method?
 

eue

Active CAD practitioner
You should store the previous local transformation value and add it to the new one, have a look at variable m_startTrsf in the code above. Good luck)
I am sorry for asking the wrong question.

You are right that I should save the final transformation (local + global) of the object and that is what I intent to do.

What I do not know is which function applies the final transformation on the object at AIS_DragAction_Stop that would pin the object to the final position?
The UpdateTransformation() don't really work as you said, and I am at a lose of finding the correct function or way to apply the final transformation to the object at end of drag.
 

eue

Active CAD practitioner
@eue What is the intention of getting a picked point? Why not just to apply a translation stored in "dragTo" parameter of ProcessDraging(...) method?

Well, embarrassed to say. I just don't know how to use the View to convert the 2D position "dragto" to a 3D position in view-world with certain depth from view screen and back.

I understand what natalia means with below function is to make a vector from start position to drag position across screen.
Code:
gp_Vec translationVec = GetTranslationVector(view, m_startPosition.x(), m_startPosition.y(), dragTo.x(), dragTo.y());

so to answer your question, this is my work around, which is just getting picked point (3D point) and position_in_view (another 3D point at mouse point) directly to do translation.

Could you be kind to show me how GetTranslationVector() function could be implemented? or show me how to convert 2D screen point to 3D position point in certain depth from screen? The 3D vector across would be parallel and equal length to the 2D vector on the computer screen.

1655368273984.png
 

JSlyadne

Administrator
Staff member
or show me how to convert 2D screen point to 3D position point in certain depth from screen? The 3D vector across would be parallel and equal length to the 2D vector on the computer screen.

I believe Convert() and ConvertWithProj() methods of V3d_View class is what you're looking for:

C++:
//! Converts the projected point into a point
  //! in the reference frame of the view corresponding
  //! to the intersection with the projection plane
  //! of the eye/view point vector.
  Standard_EXPORT void Convert (const Standard_Integer Xp, const Standard_Integer Yp,
                                Standard_Real& X, Standard_Real& Y, Standard_Real& Z) const;

  //! Converts the projected point into a point
  //! in the reference frame of the view corresponding
  //! to the intersection with the projection plane
  //! of the eye/view point vector and returns the
  //! projection ray for further computations.
  Standard_EXPORT void ConvertWithProj (const Standard_Integer Xp, const Standard_Integer Yp,
                                        Standard_Real& X,  Standard_Real& Y,  Standard_Real& Z,
                                        Standard_Real& Vx, Standard_Real& Vy, Standard_Real& Vz) const;

The instance of V3d_View is the input parameter of ProcessDragging(...) method. So, just call the appropriate method through this instance.

Could you be kind to show me how GetTranslationVector() function could be implemented?
Natalia left a link in the message above to the sources, https://gitlab.com/ssv/lessons/-/tree/viewerDrag. You might look the implementation details there. Or do you have access issue? If yes, let us know.
 

eue

Active CAD practitioner
I believe Convert() and ConvertWithProj() methods of V3d_View class is what you're looking for:

C++:
//! Converts the projected point into a point
  //! in the reference frame of the view corresponding
  //! to the intersection with the projection plane
  //! of the eye/view point vector.
  Standard_EXPORT void Convert (const Standard_Integer Xp, const Standard_Integer Yp,
                                Standard_Real& X, Standard_Real& Y, Standard_Real& Z) const;

  //! Converts the projected point into a point
  //! in the reference frame of the view corresponding
  //! to the intersection with the projection plane
  //! of the eye/view point vector and returns the
  //! projection ray for further computations.
  Standard_EXPORT void ConvertWithProj (const Standard_Integer Xp, const Standard_Integer Yp,
                                        Standard_Real& X,  Standard_Real& Y,  Standard_Real& Z,
                                        Standard_Real& Vx, Standard_Real& Vy, Standard_Real& Vz) const;

The instance of V3d_View is the input parameter of ProcessDragging(...) method. So, just call the appropriate method through this instance.


Natalia left a link in the message above to the sources, https://gitlab.com/ssv/lessons/-/tree/viewerDrag. You might look the implementation details there. Or do you have access issue? If yes, let us know.
yes, I can access it. thank you!

In the link's code, it is the RecomputePrsOnly(...) that recomputes new object at place of end drag to replace the old one. +

This solves my problem, but it is computationally expensive for a complex object.

Is there any lighter way to simply orient and translate the object?
 

natalia

Moderator
Staff member
Hi @eue,

It’s the correct practice using ‘RecomputePrsOnly’ when you need update presentations of the object in the scene (something like calling Redisplay but without recompute for selection, the lighter only). The alternative for recompute is setting a local transformation for the object, which is appropriate if only position/orientation of the object changed, not the object’s geometry/structure.

So the advice is to brainstorm about your Compute implementation as what ‘RecomputePrsOnly’ do is calling Compute of your presentation. It is not worth moving into this method too expensive computation. If it’s possible, just moving out of it some logic, it’s encouragingly.

By the way, in the sample code we have the ‘RecomputePrsOnly’ call by Start and Stop only, not Update! During the update, we just change the local transformation and usually that is enough. Do you really have the performance problem using this approach?
 
  • Like
Reactions: eue
Top