Back to index

salome-gui  6.5.0
SVTK_RectPicker.cxx
Go to the documentation of this file.
00001 // Copyright (C) 2007-2012  CEA/DEN, EDF R&D, OPEN CASCADE
00002 //
00003 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
00004 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
00005 //
00006 // This library is free software; you can redistribute it and/or
00007 // modify it under the terms of the GNU Lesser General Public
00008 // License as published by the Free Software Foundation; either
00009 // version 2.1 of the License.
00010 //
00011 // This library is distributed in the hope that it will be useful,
00012 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014 // Lesser General Public License for more details.
00015 //
00016 // You should have received a copy of the GNU Lesser General Public
00017 // License along with this library; if not, write to the Free Software
00018 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
00019 //
00020 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
00021 //
00022 
00023 //  SALOME VTKViewer : build VTK viewer into Salome desktop
00024 //  File   : SVTK_RectPicker.cxx
00025 //  Author : 
00026 //  Module : SALOME
00027 //
00028 #include "SVTK_RectPicker.h"
00029 
00030 #include <set>
00031 
00032 #include <vtkObjectFactory.h>
00033 #include <vtkCommand.h>
00034 
00035 #include <vtkAbstractMapper3D.h>
00036 #include <vtkMapper.h>
00037 #include <vtkProperty.h>
00038 
00039 #include <vtkAssemblyPath.h>
00040 #include <vtkAssemblyNode.h>
00041 
00042 #include <vtkRenderWindow.h>
00043 #include <vtkMatrix4x4.h>
00044 #include <vtkRenderer.h>
00045 #include <vtkDataSet.h>
00046 #include <vtkPoints.h>
00047 #include <vtkCamera.h>
00048 #include <vtkCell.h>
00049 
00050 namespace
00051 {
00052   //----------------------------------------------------------------------------
00053   inline
00054   vtkFloatingPointType
00055   GetZ(float* theZPtr,
00056        int theSelection[4],
00057        int theDX,
00058        int theDY)
00059   {
00060     return theZPtr[theDX - theSelection[0] + (theDY - theSelection[1])*(theSelection[2] - theSelection[0] + 1)];
00061   }
00062 
00063 
00064   //----------------------------------------------------------------------------
00065   inline
00066   int
00067   Check(float* theZPtr,
00068         int theSelection[4],
00069         vtkFloatingPointType theTolerance,
00070         vtkFloatingPointType theDZ,
00071         int theDX,
00072         int theDY)
00073   {
00074     int aRet = 0;
00075     vtkFloatingPointType aZ = -1.0;
00076     if(theDX >= theSelection[0] && theDX <= theSelection[2] &&
00077        theDY >= theSelection[1] && theDY <= theSelection[3])
00078     {
00079       // Access the value from the captured zbuffer.  Note, we only
00080       // captured a portion of the zbuffer, so we need to offset dx by
00081       // the selection window.
00082       aZ = GetZ(theZPtr,theSelection,theDX,theDY);
00083       if(aZ > theTolerance && aZ < 1.0 - theTolerance){
00084         aRet = fabs(aZ - theDZ) <= theTolerance;
00085       }
00086     }
00087 
00088     //cout<<"\tCheck = {"<<theDX<<", "<<theDY<<", "<<theDZ<<", "<<aZ<<"} = "<<aRet<<"\n";
00089     return aRet;
00090   }
00091 
00092 
00093   //----------------------------------------------------------------------------
00094   void
00095   SelectVisiblePoints(int theSelection[4],
00096                       vtkRenderer *theRenderer,
00097                       vtkDataSet *theInput,
00098                       SVTK_RectPicker::TVectorIds& theVisibleIds,
00099                       SVTK_RectPicker::TVectorIds& theInVisibleIds,
00100                       vtkFloatingPointType theTolerance)
00101   {
00102     theVisibleIds.clear();
00103     theInVisibleIds.clear();
00104 
00105     vtkIdType aNumPts = theInput->GetNumberOfPoints();
00106     if(aNumPts < 1)
00107       return;
00108     
00109     theVisibleIds.reserve(aNumPts/2 + 1);
00110     theInVisibleIds.reserve(aNumPts/2 + 1);
00111 
00112     // Grab the composite perspective transform.  This matrix is used to convert
00113     // each point to view coordinates.  vtkRenderer provides a WorldToView()
00114     // method but it computes the composite perspective transform each time
00115     // WorldToView() is called.  This is expensive, so we get the matrix once
00116     // and handle the transformation ourselves.
00117     vtkMatrix4x4 *aMatrix = vtkMatrix4x4::New();
00118     aMatrix->DeepCopy( theRenderer->GetActiveCamera()->
00119                        GetCompositeProjectionTransformMatrix( theRenderer->GetTiledAspectRatio(), 0, 1 ) );
00120 
00121     // We grab the z-buffer for the selection region all at once and probe the resulting array.
00122     float *aZPtr = theRenderer->GetRenderWindow()->
00123       GetZbufferData(theSelection[0], theSelection[1], theSelection[2], theSelection[3]);
00124 
00125     //cout<<"theSelection = {"<<theSelection[0]<<", "<<theSelection[1]<<", "<<theSelection[2]<<", "<<theSelection[3]<<"}\n";
00126 
00127     //cout<<"\t";
00128     for(int iX = theSelection[0]; iX <= theSelection[2];  iX++){
00129       //cout<<iX<<"\t";
00130     }
00131     //cout<<endl;
00132 
00133     for(int iY = theSelection[1]; iY <= theSelection[3];  iY++){
00134       //cout<<iY<<"\t";
00135       for(int iX = theSelection[0]; iX <= theSelection[2];  iX++){
00136         //cout<<std::setprecision(4)<<GetZ(aZPtr,theSelection,iX,iY)<<"\t";
00137       }
00138       //cout<<endl;
00139     }
00140 
00141     for(vtkIdType aPntId = 0; aPntId < aNumPts; aPntId++){
00142       // perform conversion
00143       vtkFloatingPointType aX[4] = {1.0, 1.0, 1.0, 1.0};
00144       theInput->GetPoint(aPntId,aX);
00145 
00146       vtkFloatingPointType aView[4];
00147       aMatrix->MultiplyPoint(aX,aView);
00148       if(aView[3] == 0.0)
00149         continue;
00150       theRenderer->SetViewPoint(aView[0]/aView[3], 
00151                                 aView[1]/aView[3],
00152                                 aView[2]/aView[3]);
00153       theRenderer->ViewToDisplay();
00154 
00155       vtkFloatingPointType aDX[3];
00156       theRenderer->GetDisplayPoint(aDX);
00157       
00158       // check whether visible and in selection window 
00159       if(aDX[0] >= theSelection[0] && aDX[0] <= theSelection[2] &&
00160          aDX[1] >= theSelection[1] && aDX[1] <= theSelection[3])
00161       {
00162         //cout<<"aPntId "<<aPntId<<"; aDX = {"<<aDX[0]<<", "<<aDX[1]<<", "<<aDX[2]<<"}\n";
00163         int aDX0 = int(aDX[0]);
00164         int aDX1 = int(aDX[1]);
00165 
00166         int aRet = Check(aZPtr,theSelection,theTolerance,aDX[2],aDX0,aDX1);
00167         if(aRet > 0)
00168           goto ADD_VISIBLE;
00169         if(aRet < 0)
00170           goto ADD_INVISIBLE;
00171 
00172         static int aMaxRadius = 5;
00173         for(int aRadius = 1; aRadius < aMaxRadius; aRadius++){
00174           int aStartDX[2] = {aDX0 - aRadius, aDX1 - aRadius};
00175           for(int i = 0; i <= aRadius; i++){
00176             int aRet = Check(aZPtr,theSelection,theTolerance,aDX[2],aStartDX[0]++,aStartDX[1]);
00177             if(aRet > 0)
00178               goto ADD_VISIBLE;
00179             if(aRet < 0)
00180               goto ADD_INVISIBLE;
00181           }
00182           for(int i = 0; i <= aRadius; i++){
00183             int aRet = Check(aZPtr,theSelection,theTolerance,aDX[2],aStartDX[0],aStartDX[1]++);
00184             if(aRet > 0)
00185               goto ADD_VISIBLE;
00186             if(aRet < 0)
00187               goto ADD_INVISIBLE;
00188           }
00189           for(int i = 0; i <= aRadius; i++){
00190             int aRet = Check(aZPtr,theSelection,theTolerance,aDX[2],aStartDX[0]--,aStartDX[1]);
00191             if(aRet > 0)
00192               goto ADD_VISIBLE;
00193             if(aRet < 0)
00194               goto ADD_INVISIBLE;
00195           }
00196           for(int i = 0; i <= aRadius; i++){
00197             int aRet = Check(aZPtr,theSelection,theTolerance,aDX[2],aStartDX[0],aStartDX[1]--);
00198             if(aRet > 0)
00199               goto ADD_VISIBLE;
00200             if(aRet < 0)
00201               goto ADD_INVISIBLE;
00202           }
00203         }
00204         if(false)
00205           ADD_VISIBLE : theVisibleIds.push_back(aPntId);
00206         if(false)
00207           ADD_INVISIBLE : theInVisibleIds.push_back(aPntId);
00208       }
00209     }//for all points
00210 
00211     aMatrix->Delete();
00212 
00213     if(aZPtr)
00214       delete [] aZPtr;
00215   }
00216 
00217 
00218   //----------------------------------------------------------------------------
00219   inline
00220   void
00221   GetCenter(const vtkFloatingPointType theBounds[6],
00222             vtkFloatingPointType theCenter[3])
00223   {
00224     theCenter[0] = (theBounds[1] + theBounds[0]) / 2.0;
00225     theCenter[1] = (theBounds[3] + theBounds[2]) / 2.0;
00226     theCenter[2] = (theBounds[5] + theBounds[4]) / 2.0;
00227   }
00228 
00229   void
00230   SelectVisibleCells(int theSelection[4],
00231                      vtkRenderer *theRenderer,
00232                      vtkDataSet *theInput,
00233                      SVTK_RectPicker::TVectorIds& theVectorIds,
00234                      vtkFloatingPointType theTolerance)
00235   {
00236     theVectorIds.clear();
00237 
00238     vtkIdType aNumCells = theInput->GetNumberOfCells();
00239     if(aNumCells < 1)
00240       return;
00241     
00242     theVectorIds.reserve(aNumCells/2 + 1);
00243 
00244     SVTK_RectPicker::TVectorIds aVisiblePntIds;
00245     SVTK_RectPicker::TVectorIds anInVisiblePntIds;
00246     SelectVisiblePoints(theSelection,
00247                         theRenderer,
00248                         theInput,
00249                         aVisiblePntIds,
00250                         anInVisiblePntIds,
00251                         theTolerance);
00252 
00253     typedef std::set<vtkIdType> TIdsSet;
00254     TIdsSet aVisibleIds(aVisiblePntIds.begin(),aVisiblePntIds.end());
00255     TIdsSet anInVisibleIds(anInVisiblePntIds.begin(),anInVisiblePntIds.end());
00256 
00257     // Grab the composite perspective transform.  This matrix is used to convert
00258     // each point to view coordinates.  vtkRenderer provides a WorldToView()
00259     // method but it computes the composite perspective transform each time
00260     // WorldToView() is called.  This is expensive, so we get the matrix once
00261     // and handle the transformation ourselves.
00262     vtkMatrix4x4 *aMatrix = vtkMatrix4x4::New();
00263     aMatrix->DeepCopy(theRenderer->GetActiveCamera()->
00264                       GetCompositeProjectionTransformMatrix( theRenderer->GetTiledAspectRatio(), 0, 1 ) );
00265 
00266     for(vtkIdType aCellId = 0; aCellId < aNumCells; aCellId++){
00267       vtkCell* aCell = theInput->GetCell(aCellId);
00268 
00269       vtkFloatingPointType aBounds[6];
00270       aCell->GetBounds(aBounds);
00271 
00272       vtkFloatingPointType aCenter[3];
00273       GetCenter(aBounds,aCenter);
00274 
00275       vtkFloatingPointType aView[4];
00276       vtkFloatingPointType aX[4] = {aCenter[0], aCenter[1], aCenter[2], 1.0};
00277       aMatrix->MultiplyPoint(aX,aView);
00278 
00279       if(aView[3] == 0.0)
00280         continue;
00281 
00282       theRenderer->SetViewPoint(aView[0]/aView[3], 
00283                                 aView[1]/aView[3],
00284                                 aView[2]/aView[3]);
00285       theRenderer->ViewToDisplay();
00286 
00287       vtkFloatingPointType aDX[3];
00288       theRenderer->GetDisplayPoint(aDX);
00289       
00290       // check whether visible and in selection window 
00291       if(aDX[0] >= theSelection[0] && aDX[0] <= theSelection[2] &&
00292          aDX[1] >= theSelection[1] && aDX[1] <= theSelection[3])
00293       {
00294 
00295         //cout<<"aCellId = "<<aCellId<<": ";
00296         vtkIdType aNumPts = aCell->GetNumberOfPoints();
00297         bool anIsVisible = true;
00298         for(vtkIdType anId = 0; anId < aNumPts; anId++){
00299           vtkIdType aPntId = aCell->GetPointId(anId);
00300           //cout<<aPntId<<"; ";
00301           anIsVisible = aVisibleIds.find(aPntId) != aVisibleIds.end();
00302           if(!anIsVisible)
00303             break;
00304         }
00305         //cout<<"\t"<<anIsVisible<<"\n";
00306         if(anIsVisible)
00307           theVectorIds.push_back(aCellId);
00308       }
00309     }//for all parts
00310   }
00311 
00312   //----------------------------------------------------------------------------
00313   void
00314   CalculatePickPosition(vtkRenderer *theRenderer,
00315                         vtkFloatingPointType theSelectionX, 
00316                         vtkFloatingPointType theSelectionY, 
00317                         vtkFloatingPointType theSelectionZ,
00318                         vtkFloatingPointType thePickPosition[3])
00319   {
00320     // Convert the selection point into world coordinates.
00321     //
00322     theRenderer->SetDisplayPoint(theSelectionX, theSelectionY, theSelectionZ);
00323     theRenderer->DisplayToWorld();
00324     vtkFloatingPointType* aWorldCoords = theRenderer->GetWorldPoint();
00325     if ( aWorldCoords[3] != 0.0 ) {
00326       for (int i=0; i < 3; i++) {
00327         thePickPosition[i] = aWorldCoords[i] / aWorldCoords[3];
00328       }
00329     }
00330   }
00331 }
00332 
00333 vtkStandardNewMacro(SVTK_RectPicker);
00334 
00335 SVTK_RectPicker
00336 ::SVTK_RectPicker()
00337 {
00338   this->Tolerance = 0.005;
00339   this->PickPoints = 1;
00340 }
00341 
00342 SVTK_RectPicker
00343 ::~SVTK_RectPicker()
00344 {}
00345 
00346 int
00347 SVTK_RectPicker
00348 ::Pick(vtkFloatingPointType, 
00349        vtkFloatingPointType, 
00350        vtkFloatingPointType, 
00351        vtkRenderer*)
00352 {
00353   return 0;
00354 }
00355 
00356 int
00357 SVTK_RectPicker
00358 ::Pick(vtkFloatingPointType theSelection[3], 
00359        vtkFloatingPointType theSelection2[3], 
00360        vtkRenderer *theRenderer)
00361 {
00362   return Pick(theSelection[0], theSelection[1], theSelection[2], 
00363               theSelection2[0], theSelection2[1], theSelection2[2],
00364               theRenderer);
00365 }
00366 
00367 int 
00368 SVTK_RectPicker
00369 ::Pick(vtkFloatingPointType theSelectionX, 
00370        vtkFloatingPointType theSelectionY, 
00371        vtkFloatingPointType theSelectionZ, 
00372        vtkFloatingPointType theSelectionX2, 
00373        vtkFloatingPointType theSelectionY2, 
00374        vtkFloatingPointType theSelectionZ2,
00375        vtkRenderer *theRenderer)
00376 {
00377   //  Initialize picking process
00378   this->Initialize();
00379   myCellIdsMap.clear();
00380   myPointIdsMap.clear();
00381   this->Renderer = theRenderer;
00382 
00383   // Get camera focal point and position. Convert to display (screen) 
00384   // coordinates. We need a depth value for z-buffer.
00385   //
00386   vtkCamera* aCamera = theRenderer->GetActiveCamera();
00387 
00388   vtkFloatingPointType aCameraFP[4];
00389   aCamera->GetFocalPoint(aCameraFP); 
00390   aCameraFP[3] = 1.0;
00391 
00392   theRenderer->SetWorldPoint(aCameraFP);
00393   theRenderer->WorldToDisplay();
00394   vtkFloatingPointType* aDisplayCoords = theRenderer->GetDisplayPoint();
00395   vtkFloatingPointType aSelectionZ = aDisplayCoords[2];
00396 
00397   this->SelectionPoint[0] = theSelectionX;
00398   this->SelectionPoint[1] = theSelectionY;
00399   this->SelectionPoint[2] = theSelectionZ;
00400 
00401   // Convert the selection point into world coordinates.
00402   //
00403   CalculatePickPosition(theRenderer,
00404                         theSelectionX,
00405                         theSelectionY,
00406                         aSelectionZ,
00407                         this->PickPosition);
00408 
00409   this->SelectionPoint2[0] = theSelectionX2;
00410   this->SelectionPoint2[1] = theSelectionY2;
00411   this->SelectionPoint2[2] = theSelectionZ2;
00412 
00413   // Convert the selection point into world coordinates.
00414   //
00415   CalculatePickPosition(theRenderer,
00416                         theSelectionX2,
00417                         theSelectionY2,
00418                         aSelectionZ,
00419                         this->PickPosition2);
00420 
00421   // Invoke start pick method if defined
00422   this->InvokeEvent(vtkCommand::StartPickEvent,NULL);
00423 
00424   vtkPropCollection *aProps;
00425   if ( this->PickFromList ) 
00426     aProps = this->GetPickList();
00427   else 
00428     aProps = theRenderer->GetViewProps();
00429 
00430   aProps->InitTraversal();
00431   while ( vtkProp* aProp = aProps->GetNextProp() ) {
00432     aProp->InitPathTraversal();
00433     while ( vtkAssemblyPath* aPath = aProp->GetNextPath() ) {
00434       vtkMapper *aMapper = NULL;
00435       bool anIsPickable = false;
00436       vtkActor* anActor = NULL;
00437       vtkProp *aPropCandidate = aPath->GetLastNode()->GetViewProp();
00438       if ( aPropCandidate->GetPickable() && aPropCandidate->GetVisibility() ) {
00439         anIsPickable = true;
00440         anActor = vtkActor::SafeDownCast(aPropCandidate);
00441         if ( anActor ) {
00442           aMapper = anActor->GetMapper();
00443           if ( anActor->GetProperty()->GetOpacity() <= 0.0 )
00444             anIsPickable = false;
00445         }
00446       }
00447       if ( anIsPickable  &&  aMapper && aMapper->GetInput()) {
00448         int aSelectionPoint[4] = {int(theSelectionX),
00449                                   int(theSelectionY),
00450                                   int(theSelectionX2),
00451                                   int(theSelectionY2)};
00452         if ( this->PickPoints ) {
00453           TVectorIds& aVisibleIds = myPointIdsMap[anActor];
00454           TVectorIds anInVisibleIds;
00455           SelectVisiblePoints(aSelectionPoint,
00456                               theRenderer,
00457                               aMapper->GetInput(),
00458                               aVisibleIds,
00459                               anInVisibleIds,
00460                               this->Tolerance);
00461           if ( aVisibleIds.empty() ) {
00462             myPointIdsMap.erase(myPointIdsMap.find(anActor));
00463           }
00464         } else {
00465           TVectorIds& aVectorIds = myCellIdsMap[anActor];
00466           SelectVisibleCells(aSelectionPoint,
00467                              theRenderer,
00468                              aMapper->GetInput(),
00469                              aVectorIds,
00470                              this->Tolerance);
00471           if ( aVectorIds.empty() ) {
00472             myCellIdsMap.erase(myCellIdsMap.find(anActor));
00473           }
00474         }
00475       }
00476     }
00477   }
00478 
00479   // Invoke end pick method if defined
00480   this->InvokeEvent(vtkCommand::EndPickEvent,NULL);
00481 
00482   return myPointIdsMap.empty() || myCellIdsMap.empty();
00483 }
00484 
00485 
00486 const SVTK_RectPicker::TVectorIdsMap& 
00487 SVTK_RectPicker
00488 ::GetPointIdsMap() const
00489 {
00490   return myPointIdsMap;
00491 }
00492 
00493 const SVTK_RectPicker::TVectorIdsMap& 
00494 SVTK_RectPicker
00495 ::GetCellIdsMap() const
00496 {
00497   return myCellIdsMap;
00498 }