1 // Copyright (C) 2007-2012 CEA/DEN, EDF R&D, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License.
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // Lesser General Public License for more details.
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
23 // SALOME VTKViewer : build VTK viewer into Salome desktop
24 // File : SVTK_RectPicker.cxx
28 #include "SVTK_RectPicker.h"
32 #include <vtkObjectFactory.h>
33 #include <vtkCommand.h>
35 #include <vtkAbstractMapper3D.h>
36 #include <vtkMapper.h>
37 #include <vtkProperty.h>
39 #include <vtkAssemblyPath.h>
40 #include <vtkAssemblyNode.h>
42 #include <vtkRenderWindow.h>
43 #include <vtkMatrix4x4.h>
44 #include <vtkRenderer.h>
45 #include <vtkDataSet.h>
46 #include <vtkPoints.h>
47 #include <vtkCamera.h>
52 //----------------------------------------------------------------------------
60 return theZPtr[theDX - theSelection[0] + (theDY - theSelection[1])*(theSelection[2] - theSelection[0] + 1)];
64 //----------------------------------------------------------------------------
76 if(theDX >= theSelection[0] && theDX <= theSelection[2] &&
77 theDY >= theSelection[1] && theDY <= theSelection[3])
79 // Access the value from the captured zbuffer. Note, we only
80 // captured a portion of the zbuffer, so we need to offset dx by
81 // the selection window.
82 aZ = GetZ(theZPtr,theSelection,theDX,theDY);
83 if(aZ > theTolerance && aZ < 1.0 - theTolerance){
84 aRet = fabs(aZ - theDZ) <= theTolerance;
88 //cout<<"\tCheck = {"<<theDX<<", "<<theDY<<", "<<theDZ<<", "<<aZ<<"} = "<<aRet<<"\n";
93 //----------------------------------------------------------------------------
95 SelectVisiblePoints(int theSelection[4],
96 vtkRenderer *theRenderer,
98 SVTK_RectPicker::TVectorIds& theVisibleIds,
99 SVTK_RectPicker::TVectorIds& theInVisibleIds,
102 theVisibleIds.clear();
103 theInVisibleIds.clear();
105 vtkIdType aNumPts = theInput->GetNumberOfPoints();
109 theVisibleIds.reserve(aNumPts/2 + 1);
110 theInVisibleIds.reserve(aNumPts/2 + 1);
112 // Grab the composite perspective transform. This matrix is used to convert
113 // each point to view coordinates. vtkRenderer provides a WorldToView()
114 // method but it computes the composite perspective transform each time
115 // WorldToView() is called. This is expensive, so we get the matrix once
116 // and handle the transformation ourselves.
117 vtkMatrix4x4 *aMatrix = vtkMatrix4x4::New();
118 aMatrix->DeepCopy( theRenderer->GetActiveCamera()->
119 GetCompositeProjectionTransformMatrix( theRenderer->GetTiledAspectRatio(), 0, 1 ) );
121 // We grab the z-buffer for the selection region all at once and probe the resulting array.
122 float *aZPtr = theRenderer->GetRenderWindow()->
123 GetZbufferData(theSelection[0], theSelection[1], theSelection[2], theSelection[3]);
125 //cout<<"theSelection = {"<<theSelection[0]<<", "<<theSelection[1]<<", "<<theSelection[2]<<", "<<theSelection[3]<<"}\n";
128 for(int iX = theSelection[0]; iX <= theSelection[2]; iX++){
133 for(int iY = theSelection[1]; iY <= theSelection[3]; iY++){
135 for(int iX = theSelection[0]; iX <= theSelection[2]; iX++){
136 //cout<<std::setprecision(4)<<GetZ(aZPtr,theSelection,iX,iY)<<"\t";
141 for(vtkIdType aPntId = 0; aPntId < aNumPts; aPntId++){
142 // perform conversion
143 double aX[4] = {1.0, 1.0, 1.0, 1.0};
144 theInput->GetPoint(aPntId,aX);
147 aMatrix->MultiplyPoint(aX,aView);
150 theRenderer->SetViewPoint(aView[0]/aView[3],
153 theRenderer->ViewToDisplay();
156 theRenderer->GetDisplayPoint(aDX);
158 // check whether visible and in selection window
159 if(aDX[0] >= theSelection[0] && aDX[0] <= theSelection[2] &&
160 aDX[1] >= theSelection[1] && aDX[1] <= theSelection[3])
162 //cout<<"aPntId "<<aPntId<<"; aDX = {"<<aDX[0]<<", "<<aDX[1]<<", "<<aDX[2]<<"}\n";
163 int aDX0 = int(aDX[0]);
164 int aDX1 = int(aDX[1]);
166 int aRet = Check(aZPtr,theSelection,theTolerance,aDX[2],aDX0,aDX1);
172 static int aMaxRadius = 5;
173 for(int aRadius = 1; aRadius < aMaxRadius; aRadius++){
174 int aStartDX[2] = {aDX0 - aRadius, aDX1 - aRadius};
175 for(int i = 0; i <= aRadius; i++){
176 int aRet = Check(aZPtr,theSelection,theTolerance,aDX[2],aStartDX[0]++,aStartDX[1]);
182 for(int i = 0; i <= aRadius; i++){
183 int aRet = Check(aZPtr,theSelection,theTolerance,aDX[2],aStartDX[0],aStartDX[1]++);
189 for(int i = 0; i <= aRadius; i++){
190 int aRet = Check(aZPtr,theSelection,theTolerance,aDX[2],aStartDX[0]--,aStartDX[1]);
196 for(int i = 0; i <= aRadius; i++){
197 int aRet = Check(aZPtr,theSelection,theTolerance,aDX[2],aStartDX[0],aStartDX[1]--);
205 ADD_VISIBLE : theVisibleIds.push_back(aPntId);
207 ADD_INVISIBLE : theInVisibleIds.push_back(aPntId);
218 //----------------------------------------------------------------------------
221 GetCenter(const double theBounds[6],
224 theCenter[0] = (theBounds[1] + theBounds[0]) / 2.0;
225 theCenter[1] = (theBounds[3] + theBounds[2]) / 2.0;
226 theCenter[2] = (theBounds[5] + theBounds[4]) / 2.0;
230 SelectVisibleCells(int theSelection[4],
231 vtkRenderer *theRenderer,
232 vtkDataSet *theInput,
233 SVTK_RectPicker::TVectorIds& theVectorIds,
236 theVectorIds.clear();
238 vtkIdType aNumCells = theInput->GetNumberOfCells();
242 theVectorIds.reserve(aNumCells/2 + 1);
244 SVTK_RectPicker::TVectorIds aVisiblePntIds;
245 SVTK_RectPicker::TVectorIds anInVisiblePntIds;
246 SelectVisiblePoints(theSelection,
253 typedef std::set<vtkIdType> TIdsSet;
254 TIdsSet aVisibleIds(aVisiblePntIds.begin(),aVisiblePntIds.end());
255 TIdsSet anInVisibleIds(anInVisiblePntIds.begin(),anInVisiblePntIds.end());
257 // Grab the composite perspective transform. This matrix is used to convert
258 // each point to view coordinates. vtkRenderer provides a WorldToView()
259 // method but it computes the composite perspective transform each time
260 // WorldToView() is called. This is expensive, so we get the matrix once
261 // and handle the transformation ourselves.
262 vtkMatrix4x4 *aMatrix = vtkMatrix4x4::New();
263 aMatrix->DeepCopy(theRenderer->GetActiveCamera()->
264 GetCompositeProjectionTransformMatrix( theRenderer->GetTiledAspectRatio(), 0, 1 ) );
266 for(vtkIdType aCellId = 0; aCellId < aNumCells; aCellId++){
267 vtkCell* aCell = theInput->GetCell(aCellId);
270 aCell->GetBounds(aBounds);
273 GetCenter(aBounds,aCenter);
276 double aX[4] = {aCenter[0], aCenter[1], aCenter[2], 1.0};
277 aMatrix->MultiplyPoint(aX,aView);
282 theRenderer->SetViewPoint(aView[0]/aView[3],
285 theRenderer->ViewToDisplay();
288 theRenderer->GetDisplayPoint(aDX);
290 // check whether visible and in selection window
291 if(aDX[0] >= theSelection[0] && aDX[0] <= theSelection[2] &&
292 aDX[1] >= theSelection[1] && aDX[1] <= theSelection[3])
295 //cout<<"aCellId = "<<aCellId<<": ";
296 vtkIdType aNumPts = aCell->GetNumberOfPoints();
297 bool anIsVisible = true;
298 for(vtkIdType anId = 0; anId < aNumPts; anId++){
299 vtkIdType aPntId = aCell->GetPointId(anId);
300 //cout<<aPntId<<"; ";
301 anIsVisible = aVisibleIds.find(aPntId) != aVisibleIds.end();
305 //cout<<"\t"<<anIsVisible<<"\n";
307 theVectorIds.push_back(aCellId);
312 //----------------------------------------------------------------------------
314 CalculatePickPosition(vtkRenderer *theRenderer,
315 double theSelectionX,
316 double theSelectionY,
317 double theSelectionZ,
318 double thePickPosition[3])
320 // Convert the selection point into world coordinates.
322 theRenderer->SetDisplayPoint(theSelectionX, theSelectionY, theSelectionZ);
323 theRenderer->DisplayToWorld();
324 double* aWorldCoords = theRenderer->GetWorldPoint();
325 if ( aWorldCoords[3] != 0.0 ) {
326 for (int i=0; i < 3; i++) {
327 thePickPosition[i] = aWorldCoords[i] / aWorldCoords[3];
333 vtkStandardNewMacro(SVTK_RectPicker);
338 this->Tolerance = 0.005;
339 this->PickPoints = 1;
358 ::Pick(double theSelection[3],
359 double theSelection2[3],
360 vtkRenderer *theRenderer)
362 return Pick(theSelection[0], theSelection[1], theSelection[2],
363 theSelection2[0], theSelection2[1], theSelection2[2],
369 ::Pick(double theSelectionX,
370 double theSelectionY,
371 double theSelectionZ,
372 double theSelectionX2,
373 double theSelectionY2,
374 double theSelectionZ2,
375 vtkRenderer *theRenderer)
377 // Initialize picking process
379 myCellIdsMap.clear();
380 myPointIdsMap.clear();
381 this->Renderer = theRenderer;
383 // Get camera focal point and position. Convert to display (screen)
384 // coordinates. We need a depth value for z-buffer.
386 vtkCamera* aCamera = theRenderer->GetActiveCamera();
389 aCamera->GetFocalPoint(aCameraFP);
392 theRenderer->SetWorldPoint(aCameraFP);
393 theRenderer->WorldToDisplay();
394 double* aDisplayCoords = theRenderer->GetDisplayPoint();
395 double aSelectionZ = aDisplayCoords[2];
397 this->SelectionPoint[0] = theSelectionX;
398 this->SelectionPoint[1] = theSelectionY;
399 this->SelectionPoint[2] = theSelectionZ;
401 // Convert the selection point into world coordinates.
403 CalculatePickPosition(theRenderer,
409 this->SelectionPoint2[0] = theSelectionX2;
410 this->SelectionPoint2[1] = theSelectionY2;
411 this->SelectionPoint2[2] = theSelectionZ2;
413 // Convert the selection point into world coordinates.
415 CalculatePickPosition(theRenderer,
419 this->PickPosition2);
421 // Invoke start pick method if defined
422 this->InvokeEvent(vtkCommand::StartPickEvent,NULL);
424 vtkPropCollection *aProps;
425 if ( this->PickFromList )
426 aProps = this->GetPickList();
428 aProps = theRenderer->GetViewProps();
430 aProps->InitTraversal();
431 while ( vtkProp* aProp = aProps->GetNextProp() ) {
432 aProp->InitPathTraversal();
433 while ( vtkAssemblyPath* aPath = aProp->GetNextPath() ) {
434 vtkMapper *aMapper = NULL;
435 bool anIsPickable = false;
436 vtkActor* anActor = NULL;
437 vtkProp *aPropCandidate = aPath->GetLastNode()->GetViewProp();
438 if ( aPropCandidate->GetPickable() && aPropCandidate->GetVisibility() ) {
440 anActor = vtkActor::SafeDownCast(aPropCandidate);
442 aMapper = anActor->GetMapper();
443 if ( anActor->GetProperty()->GetOpacity() <= 0.0 )
444 anIsPickable = false;
447 if ( anIsPickable && aMapper && aMapper->GetInput()) {
448 int aSelectionPoint[4] = {int(theSelectionX),
451 int(theSelectionY2)};
452 if ( this->PickPoints ) {
453 TVectorIds& aVisibleIds = myPointIdsMap[anActor];
454 TVectorIds anInVisibleIds;
455 SelectVisiblePoints(aSelectionPoint,
461 if ( aVisibleIds.empty() ) {
462 myPointIdsMap.erase(myPointIdsMap.find(anActor));
465 TVectorIds& aVectorIds = myCellIdsMap[anActor];
466 SelectVisibleCells(aSelectionPoint,
471 if ( aVectorIds.empty() ) {
472 myCellIdsMap.erase(myCellIdsMap.find(anActor));
479 // Invoke end pick method if defined
480 this->InvokeEvent(vtkCommand::EndPickEvent,NULL);
482 return myPointIdsMap.empty() || myCellIdsMap.empty();
486 const SVTK_RectPicker::TVectorIdsMap&
488 ::GetPointIdsMap() const
490 return myPointIdsMap;
493 const SVTK_RectPicker::TVectorIdsMap&
495 ::GetCellIdsMap() const