3D PLM Enterprise Architecture

3D Visualization

Viewer Feedback

How to retrieve information on interactions coming from viewers
Use Case

Abstract

This article shows how to retrieve and analyze information on interactions coming from viewers. These interactions can be mouse motion or press/release button.


What You Will Learn With This Use Case

This use case is intended to show you how to retrieve and analyze information on interactions coming from viewers. You will learn how to:

[Top]

The CAACafViewerFeedback Use Case

CAACafViewerFeedback is a use case of CAACATIAApplicationFrm.edu and CAAApplicationFrame.edu frameworks that illustrates Visualization framework capabilities.

[Top]

What Does CAACafViewerFeedback Do

CAACafViewerFeedback use case enables you to activate or deactivate the feedback mode on the current viewer. This switch is possible thanks to a command set in an add-in of the General workshop [1].

The Viewer Feedback demonstrator command, see pictures below, is represented by a check button. When the button is "ON" (right picture), the feedback mode is active. When the button is "OFF" (left picture), the feedback mode is not active.

When the feedback mode is active in the current viewer you can see:

[Top]

How to Launch CAACafViewerFeedback

To launch CAACafViewerFeedback, you will need to set up the build time environment, then compile CAACafViewerFeedback along with its prerequisites, set up the run time environment, and then execute the use case [2].

But just before launching the execution, edit the CAAApplicationFrame.edu.dico interface dictionary file in the dictionary directory of your runtime view:

InstallRootDirectory\OS\code\dictionary\

where InstallRootDirectory is the directory where the CAA CD-ROM is installed and OS is a directory the name of which depends on the operating system. Refer to [2] to get the list of the currently supported operating systems and their associated directory names..

In this file, remove the "#" character before the two following lines:

...
#CAAAfrGeneralWksAddin       CATIWorkbenchAddin          libCAAAfrGeneralWksAddin  
#CAAAfrGeneralWksAddin       CATIAfrGeneralWksAddin      libCAAAfrGeneralWksAddin
...

The two line deal with the General workshop add-in described in the CAAAfrGeneralWksAddin use case [1] located in the CAAAfrGeneralWksAddin.m module (CAAApplicationFrame.edu framework)

Then, in the window where you run the mkrun command, do not type the module name on the command line, but type CNEXT instead. When the application is ready, do the following:

[Top]

Where to Find the CAACafViewerFeedback Code

The CAACafViewerFeedback use case is made of several classes located:

where InstallRootDirectory is the directory where the CAA CD-ROM is installed.

[Top]

Step-by-Step

There are four logical steps in the CAACafViewerFeedback use case:

  1. Creating the CAACafViewerFeedbackManager Class Header
  2. Activating the Feedback Mode
  3. Deactivating the Feedback Mode
  4. Decoding the CATVisViewerFeedbackEvent Notification

[Top]

Creating the CAACafViewerFeedbackManager Class Header

// System Framework
#include "CATBaseUnknown.h"      // Needed to derive from 
#include "CATEventSubscriber.h"  // To set callback

class CAT2DBagRep ;              // The graphic representation of the feedback
class CATViewer ;                // The viewer with the visual feedback
class CATNotification ;          // for callback methods
class CATUnicodeString ;         // 
class CATPathElement ;           // 

class CAACafViewerFeedbackManager : public CATBaseUnknown
{
  public :

   CAACafViewerFeedbackManager ();

   virtual ~CAACafViewerFeedbackManager();  
	
   static void GetManager(CAACafViewerFeedbackManager ** opManager);

   void SetViewerFeedbackOn();

   void SetViewerFeedbackOff();

  private : 

   void ViewerFeedbackCB          (CATCallbackEvent  iEventAlarm,
                           void             *iAlarm,
                           CATNotification  *iNotifAlarm,
                           CATSubscriberData iBurglarData,
                           CATCallback       iCallBack );

   void WindowActivatedCB          (CATCallbackEvent  iEventAlarm,
                           void             *iAlarm,
                           CATNotification  *iNotifAlarm,
                           CATSubscriberData iBurglarData,
                           CATCallback       iCallBack );

   void WindowDeactivatedCB          (CATCallbackEvent  iEventAlarm,
                           void             *iAlarm,
                           CATNotification  *iNotifAlarm,
                           CATSubscriberData iBurglarData,
                           CATCallback       iCallBack );

 
   void PathElementString(CATPathElement   * ipPath, 
                           CATUnicodeString & oPathName) ;

   void ChangeBagPosition(float Xpos, float Ypos) ;
   
   CAACafViewerFeedbackManager(const CAACafViewerFeedbackManager &iObjectToCopy);
   CAACafViewerFeedbackManager & operator = (const CAACafViewerFeedbackManager &iObjectToCopy);

  private :
   CATViewer     * _pCurrentViewer ;
   CAT2DBagRep   * _pInformationsToDisplay;

   CATCallback     _ViewerFeedbackCB ;
   CATCallback     _WindowActivatedCB ;
   CATCallback     _WindowDeactivatedCB ;
   CATCallback     _WindowDeletedCB ;
};

This class contains the following methods:

and contains the following data:

[Top]

Activating the Feedback Mode

The SetViewerFeedbackOn method consists in first to retrieve a viewer:

void CAACafViewerFeedbackManager::SetViewerFeedbackOn()
{
    if ( NULL == _pCurrentViewer )
    {
       CATFrmLayout * pCurrentLayout= CATFrmLayout::GetCurrentLayout();
       if ( NULL != pCurrentLayout )
       {
          CATFrmWindow * pCurrentWindow = pCurrentLayout->GetCurrentWindow();

          if ( NULL != pCurrentWindow )
          {
              _pCurrentViewer = pCurrentWindow->GetViewer();
...

This viewer is one of the current window (it is the choice of this command). The CATFrmLayout [4] is the class which manages all the windows all the session.

Then, once you have a viewer, you can activate the feedback mode:

 ...
       if ( NULL != _pCurrentViewer )
       {         
          _pCurrentViewer->SetFeedbackMode(TRUE);
          if (0 == _ViewerFeedbackCB)
          {
             _ViewerFeedbackCB = ::AddCallback(this,
                            _pCurrentViewer, 
                            CATViewer::VIEWER_FEEDBACK_UPDATE(), 
                            (CATSubscriberMethod) & CAACafViewerFeedbackManager::ViewerFeedbackCB, NULL);
          }
       }

The SetFeedbackMode method with TRUE actives the feedback mode. It means that now the viewer sends notifications when an interaction occurs. To receive these notifications, the command sets a callback.

_ViewerFeedbackCB is an identifier of the callback, it is important to keep it for the callback deletion. See the SetViewerFeedbackOn method

[Top]

Deactivating the Feedback Mode

The SetViewerFeedbackOn method consists in to cancel the feedback mode on the current viewer.

void CAACafViewerFeedbackManager::SetViewerFeedbackOff()
{
    if ( NULL != _pCurrentViewer)
    {
       _pCurrentViewer->SetFeedbackMode(FALSE);

       if (NULL != _pInformationsToDisplay)
       {
          _pCurrentViewer->RemoveRep(_pInformationsToDisplay);

          _pInformationsToDisplay->Destroy();
          _pInformationsToDisplay = NULL;
       }
       _pCurrentViewer->Draw();

       if (0 != _ViewerFeedbackCB)
       {
          ::RemoveCallback(this,_pCurrentViewer,_ViewerFeedbackCB) ;
          _ViewerFeedbackCB = 0 ;
       }
       _pCurrentViewer = NULL ; 
    }
}

There are four steps:

  1. Deactivate the feedback mode: It is done with the SetFeedbackMode method with FALSE as argument. It means that now the viewer will do not send notifications when an interaction will occurs.
  2. Remove the graphic representation created in the ViewerFeedbackCB method. _pInformationsToDisplay is first removed from the viewer and then deleted. The Destroy method deletes the graphic representation and its contents, if it is a bag.
  3. Refresh the viewer: It is the role of the Draw method
  4. Removes the callback coming from the viewer: _ViewerFeedbackCB is the identifier returns by the AddCallback method. See the SetViewerFeedbackOn method.
  5. _pCurrentViewer, returned by the GetViewer method of CATFrmWindow, is not "AddReffed" by this method, so you have just to reset the pointer.

[Top]

Decoding the CATVisViewerFeedbackEvent Notification

The ViewerFeedbackCB method consists in to decode the notification contained in the callback event, and to display in the main 2D viewpoint of the viewer, the information of the notification.

void CAACafViewerFeedbackManager::ViewerFeedbackCB( CATCallbackEvent   event,
                                              void             * client,
                                              CATNotification  * iNotification,
                                              CATSubscriberData  data,
                                              CATCallback        callback)
{
  if ( NULL != _pCurrentViewer )
  {
     if (NULL != _pInformationsToDisplay)
     {
        _pCurrentViewer->RemoveRep(_pInformationsToDisplay);

        _pInformationsToDisplay->Destroy();
        _pInformationsToDisplay = NULL;
     }
...

The ViewerFeedbackCB method is called each time the viewer sends an event. So the graphic representation, _pInformationsToDisplay, previously created, should be first removed from the viewer and deleted.

     CATVisViewerFeedbackEvent * pFeedbackEvent = NULL ;
     if ( NULL != iNotification )
     {
        pFeedbackEvent = (CATVisViewerFeedbackEvent*) iNotification;
     }

     if (NULL != pFeedbackEvent)
     {
         CATViewer * pViewerPublisher = pFeedbackEvent->GetViewer();
         if ( (NULL != pViewerPublisher) && ( pViewerPublisher == _pCurrentViewer) )
         {
            _pInformationsToDisplay = new CAT2DBagRep();
            _pCurrentViewer->AddRep(_pInformationsToDisplay);
            ...

The third argument of the ViewerFeedbackCB method is the notification containing the information. This notification, iNotification, is a CATVisViewerFeedbackEvent class. This class instance contains the viewer which has published the event. GetViewer retrieves it, it is pViewerPublisher. This viewer should be released at this end of the method. This value enables you to check that the current viewer, _pCurrentViewer, kept by the manager, is the same as the notification's sender. Once the check is validated, a new graphic representation can be built.

_pInformationsToDisplay is a 2D bag added to the viewer thanks to the AddRep method. This method adds the 2D representation to the main 2D viewpoint. _pInformationsToDisplay will have several children depending on the notification's contents. The ViewerFeedbackCB method analyses and displays a text for :

  1. The mouse position in screen coordinates
  2. The intersection point with the selected geometry
  3. The elements under the mouse

These three steps are described below.

  1. The mouse position in screen coordinates
  2. Before to detail the code, a picture to explain the screen coordinates:

    If (Xpos,Ypos) are the screen coordinates of the mouse,
    • Xpos ranges from 0 to width-1
    • Ypos ranges from 0 to height-1

    where width and height are the support (CATSupport) dimensions.

               int XPos, YPos;
               pFeedbackEvent->GetMousePosition(&XPos, &YPos);
    
               ChangeBagPosition(XPos,YPos);
    
               float points[2];
               points[0] = 8.0f;
               points[1] = 8.0f;
    
    ...

    GetMousePosition returns the mouse position in screen coordinates. This position serves to locate the 2D bag. The ChangeBagPosition method locates _pInformationsToDisplay near the mouse. points is an array of two floats which is used to locate the child representations in the 2D bag.

    The position of a child is a position in the bag axis system as shown in the picture below:

    (u,v) is the bag axis system

    (Xpos,Ypos) is the mouse position in screen coordinates

    The ChangeBagPosition method transforms (Xpos,Ypos) is model coordinates.

    Here is the code of the ChangeBagPosition method:

    ...
    void CAACafViewerFeedbackManager::ChangeBagPosition(float Xpos, float Ypos)
    {
            CATSupport & Support = _pCurrentViewer->GetSupport();
    
            float width, height, MMInSupportUnit, RatioWH ;
    
            Support.GetWidthAndHeight(width,height);
    
            MMInSupportUnit = Support.GetMMInSupportUnit();
            RatioWH = Support.GetRatioWH();
    
            CAT2DViewpoint & VP2D = _pCurrentViewer->GetMain2DViewpoint() ;
    
            CATMathPoint2Df ModelPos;
            VP2D.ComputeModelFromPixel( Xpos,Ypos, 
                                        ModelPos.x, ModelPos.y, 
                                        width, height, 
                                        MMInSupportUnit, 
                                        RatioWH);
           
            CATMathVector2Df U,V ;
            CAT3x3Matrix Matrix(U,V,ModelPos);
           _pInformationsToDisplay->SetMatrix(Matrix);
        }
    }
    ...

    (ModelPos.x, ModelPos.y) is the mouse position in model coordinates. The ComputeModelFromPixel method transforms a 2D point from screen coordinates to model coordinates.

    Come back to the ViewerFeedbackCB method:

    ...
               char MousePositionBuffer[200];
               sprintf(MousePositionBuffer, "Mouse Coordinates : X=%d Y=%d", XPos, YPos);
    
               CAT2DAnnotationTextRep * pMousePositionTextRep = NULL ;
               pMousePositionTextRep = new CAT2DAnnotationTextRep( points, 
                                                                 MousePositionBuffer, 
                                                                 BASE_LEFT);
    
               if (NULL != pMousePositionTextRep)
               {
                  _pInformationsToDisplay->AddChild(*pMousePositionTextRep);
               }
    ...

    pMousePositionTextRep is a CAT2DAnnotationTextRep class instance to display the mouse position screen coordinates.

  3. The intersection point with the selected geometry
  4. Before to detail the code, a picture to explain the intersection point.

    The point symbolized by a bold circle is the intersection point of the line and the nearest selected geometry. This point is in model coordinates.

    GetIntersection returns a CATGraphicElementIntersection class instance pointer. This class contains as public data a CATMathPoint . point is the intersection point. If there is nothing under the mouse, GetIntersection returns NULL.

    ...
               CATGraphicElementIntersection* pIntersection = pFeedbackEvent->GetIntersection();
    
               if (NULL != pIntersection)
               {
                  points[1] += 8.0f;
    
                  char IntersectionBuffer[200];
    
                  sprintf(IntersectionBuffer, 
                     "Intersection Coordinates : X=%.2f Y=%.2f Z=%.2f", 
                      pIntersection->point.GetX(), 
                      pIntersection->point.GetY(), 
                      pIntersection->point.GetZ());
    
                  CAT2DAnnotationTextRep * pIntersectionTextRep = NULL ;
                  pIntersectionTextRep = new CAT2DAnnotationTextRep( points, 
                                                      IntersectionBuffer, BASE_LEFT);
    
                  if (NULL != pIntersectionTextRep)
                  {
                     _pInformationsToDisplay->AddChild(*pIntersectionTextRep);
                  }
    
                  pIntersection->Release();
                  pIntersection = NULL;
               }
    ...

    pMousePositionTextRep is a CAT2DAnnotationTextRep class instance which contains the intersection point coordinates.

  5. The elements under the mouse
  6. GetElementsUnder returns the list of elements under the mouse. This list can be empty. The elements in this list are sorted, the first (0 index) being the nearest, and the last ( n-1) the further. Each element is a CATPathElement from the geometry to the root.

    ...
               CATSO* SO = pFeedbackEvent->GetElementsUnder();
    
               if (NULL != SO)
               {
                  int SOSize = SO->GetSize() ;
                  for ( int i= 0 ; i < SOSize ; i++)
                  {
                     CATPathElement * pPathElement = (CATPathElement*) ((*SO)[i]) ;
    
                     CATUnicodeString PathElementName = "";
                     PathElementString(pPathElement,PathElementName);
    
                     char Buffer[200];
                     sprintf(Buffer, "   : %d / %d", i+1,SO->GetSize());
              
                     CATUnicodeString Count(Buffer);
                     PathElementName.Append(Buffer) ;
    
                     points[1] += 8.0f;
    
                     CAT2DAnnotationTextRep* pElementTextRep = NULL ;
                     pElementTextRep = new CAT2DAnnotationTextRep( points, 
                                                              PathElementName.CastToCharPtr(), 
                                                              BASE_LEFT);
    
                     if (NULL != pElementTextRep)
                     {
                        _pInformationsToDisplay->AddChild(*pElementTextRep);
                     }
                  }
                  SO->Release();
                  SO = NULL;
    ...

    This piece of code is a loop from the first element to the last. For each path, PathElementString converts a path in a string. This string is the input of a new CAT2DAnnotationTextRep class instance.

[Top]


In Short

This use case explains how to receive information from a viewer when interactions occur. These information are inside a CATVisViewerFeebackEvent notification class.

[Top]


References

[1] Making Your Document Independent Command Available in All Workbenches
[2] Building and Launching a CAA V5 Use Case
[3] Creating a Command with Options in the "Tools Palette" Toolbar
[4] Understanding the Application Frame Layout
[5] The Callback Mechanism
[Top]

History

Version: 1 [Aug 2003] Document created
[Top]

Copyright © 2001, Dassault Systèmes. All rights reserved.