1 // SALOME VTKViewer : build VTK viewer into Salome desktop
3 // Copyright (C) 2003 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.opencascade.org/SALOME/ or email : webmaster.salome@opencascade.org
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 //----------------------------------------------------------------------------
69 vtkFloatingPointType theTolerance,
70 vtkFloatingPointType theDZ,
75 vtkFloatingPointType aZ = -1.0;
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,
100 vtkFloatingPointType theTolerance)
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 GetCompositePerspectiveTransformMatrix(1,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";
127 for(int iY = theSelection[1]; iY <= theSelection[3]; iY++){
128 for(int iX = theSelection[0]; iX <= theSelection[2]; iX++){
129 cout<<GetZ(aZPtr,theSelection,iX,iY)<<" ";
134 for(vtkIdType aPntId = 0; aPntId < aNumPts; aPntId++){
135 // perform conversion
136 vtkFloatingPointType aX[4] = {1.0, 1.0, 1.0, 1.0};
137 theInput->GetPoint(aPntId,aX);
139 vtkFloatingPointType aView[4];
140 aMatrix->MultiplyPoint(aX,aView);
143 theRenderer->SetViewPoint(aView[0]/aView[3],
146 theRenderer->ViewToDisplay();
148 vtkFloatingPointType aDX[3];
149 theRenderer->GetDisplayPoint(aDX);
151 // check whether visible and in selection window
152 if(aDX[0] >= theSelection[0] && aDX[0] <= theSelection[2] &&
153 aDX[1] >= theSelection[1] && aDX[1] <= theSelection[3])
155 //cout<<"aPntId "<<aPntId<<"; aDX = {"<<aDX[0]<<", "<<aDX[1]<<", "<<aDX[2]<<"}\n";
156 int aDX0 = int(aDX[0]);
157 int aDX1 = int(aDX[1]);
159 int aRet = Check(aZPtr,theSelection,theTolerance,aDX[2],aDX0,aDX1);
165 static int aMaxRadius = 5;
166 for(int aRadius = 1; aRadius < aMaxRadius; aRadius++){
167 int aStartDX[2] = {aDX0 - aRadius, aDX1 - aRadius};
168 for(int i = 0; i <= aRadius; i++){
169 int aRet = Check(aZPtr,theSelection,theTolerance,aDX[2],aStartDX[0]++,aStartDX[1]);
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]--);
198 ADD_VISIBLE : theVisibleIds.push_back(aPntId);
200 ADD_INVISIBLE : theInVisibleIds.push_back(aPntId);
211 //----------------------------------------------------------------------------
214 GetCenter(const vtkFloatingPointType theBounds[6],
215 vtkFloatingPointType theCenter[3])
217 theCenter[0] = (theBounds[1] + theBounds[0]) / 2.0;
218 theCenter[1] = (theBounds[3] + theBounds[2]) / 2.0;
219 theCenter[2] = (theBounds[5] + theBounds[4]) / 2.0;
223 SelectVisibleCells(int theSelection[4],
224 vtkRenderer *theRenderer,
225 vtkDataSet *theInput,
226 SVTK_RectPicker::TVectorIds& theVectorIds,
227 vtkFloatingPointType theTolerance)
229 theVectorIds.clear();
231 vtkIdType aNumCells = theInput->GetNumberOfCells();
235 theVectorIds.reserve(aNumCells/2 + 1);
237 SVTK_RectPicker::TVectorIds aVisiblePntIds;
238 SVTK_RectPicker::TVectorIds anInVisiblePntIds;
239 SelectVisiblePoints(theSelection,
246 typedef std::set<vtkIdType> TIdsSet;
247 TIdsSet aVisibleIds(aVisiblePntIds.begin(),aVisiblePntIds.end());
248 TIdsSet anInVisibleIds(anInVisiblePntIds.begin(),anInVisiblePntIds.end());
250 // Grab the composite perspective transform. This matrix is used to convert
251 // each point to view coordinates. vtkRenderer provides a WorldToView()
252 // method but it computes the composite perspective transform each time
253 // WorldToView() is called. This is expensive, so we get the matrix once
254 // and handle the transformation ourselves.
255 vtkMatrix4x4 *aMatrix = vtkMatrix4x4::New();
256 aMatrix->DeepCopy(theRenderer->GetActiveCamera()->
257 GetCompositePerspectiveTransformMatrix(1,0,1));
259 for(vtkIdType aCellId = 0; aCellId < aNumCells; aCellId++){
260 vtkCell* aCell = theInput->GetCell(aCellId);
262 vtkFloatingPointType aBounds[6];
263 aCell->GetBounds(aBounds);
265 vtkFloatingPointType aCenter[3];
266 GetCenter(aBounds,aCenter);
268 vtkFloatingPointType aView[4];
269 vtkFloatingPointType aX[4] = {aCenter[0], aCenter[1], aCenter[2], 1.0};
270 aMatrix->MultiplyPoint(aX,aView);
275 theRenderer->SetViewPoint(aView[0]/aView[3],
278 theRenderer->ViewToDisplay();
280 vtkFloatingPointType aDX[3];
281 theRenderer->GetDisplayPoint(aDX);
283 // check whether visible and in selection window
284 if(aDX[0] >= theSelection[0] && aDX[0] <= theSelection[2] &&
285 aDX[1] >= theSelection[1] && aDX[1] <= theSelection[3])
288 //cout<<"aCellId = "<<aCellId<<": ";
289 vtkIdType aNumPts = aCell->GetNumberOfPoints();
290 bool anIsVisible = true;
291 for(vtkIdType anId = 0; anId < aNumPts; anId++){
292 vtkIdType aPntId = aCell->GetPointId(anId);
293 //cout<<aPntId<<"; ";
294 anIsVisible = aVisibleIds.find(aPntId) != aVisibleIds.end();
298 //cout<<"\t"<<anIsVisible<<"\n";
300 theVectorIds.push_back(aCellId);
305 //----------------------------------------------------------------------------
307 CalculatePickPosition(vtkRenderer *theRenderer,
308 vtkFloatingPointType theSelectionX,
309 vtkFloatingPointType theSelectionY,
310 vtkFloatingPointType theSelectionZ,
311 vtkFloatingPointType thePickPosition[3])
313 // Convert the selection point into world coordinates.
315 theRenderer->SetDisplayPoint(theSelectionX, theSelectionY, theSelectionZ);
316 theRenderer->DisplayToWorld();
317 vtkFloatingPointType* aWorldCoords = theRenderer->GetWorldPoint();
318 if ( aWorldCoords[3] != 0.0 ) {
319 for (int i=0; i < 3; i++) {
320 thePickPosition[i] = aWorldCoords[i] / aWorldCoords[3];
326 vtkStandardNewMacro(SVTK_RectPicker);
331 this->Tolerance = 0.005;
332 this->PickPoints = 1;
341 ::Pick(vtkFloatingPointType,
342 vtkFloatingPointType,
343 vtkFloatingPointType,
351 ::Pick(vtkFloatingPointType theSelection[3],
352 vtkFloatingPointType theSelection2[3],
353 vtkRenderer *theRenderer)
355 return Pick(theSelection[0], theSelection[1], theSelection[2],
356 theSelection2[0], theSelection2[1], theSelection2[2],
362 ::Pick(vtkFloatingPointType theSelectionX,
363 vtkFloatingPointType theSelectionY,
364 vtkFloatingPointType theSelectionZ,
365 vtkFloatingPointType theSelectionX2,
366 vtkFloatingPointType theSelectionY2,
367 vtkFloatingPointType theSelectionZ2,
368 vtkRenderer *theRenderer)
370 // Initialize picking process
372 myCellIdsMap.clear();
373 myPointIdsMap.clear();
374 this->Renderer = theRenderer;
376 // Get camera focal point and position. Convert to display (screen)
377 // coordinates. We need a depth value for z-buffer.
379 vtkCamera* aCamera = theRenderer->GetActiveCamera();
381 vtkFloatingPointType aCameraFP[4];
382 aCamera->GetFocalPoint(aCameraFP);
385 theRenderer->SetWorldPoint(aCameraFP);
386 theRenderer->WorldToDisplay();
387 vtkFloatingPointType* aDisplayCoords = theRenderer->GetDisplayPoint();
388 vtkFloatingPointType aSelectionZ = aDisplayCoords[2];
390 this->SelectionPoint[0] = theSelectionX;
391 this->SelectionPoint[1] = theSelectionY;
392 this->SelectionPoint[2] = theSelectionZ;
394 // Convert the selection point into world coordinates.
396 CalculatePickPosition(theRenderer,
402 this->SelectionPoint2[0] = theSelectionX2;
403 this->SelectionPoint2[1] = theSelectionY2;
404 this->SelectionPoint2[2] = theSelectionZ2;
406 // Convert the selection point into world coordinates.
408 CalculatePickPosition(theRenderer,
412 this->PickPosition2);
414 // Invoke start pick method if defined
415 this->InvokeEvent(vtkCommand::StartPickEvent,NULL);
417 vtkPropCollection *aProps;
418 if ( this->PickFromList )
419 aProps = this->GetPickList();
421 aProps = theRenderer->GetProps();
423 aProps->InitTraversal();
424 while ( vtkProp* aProp = aProps->GetNextProp() ) {
425 aProp->InitPathTraversal();
426 while ( vtkAssemblyPath* aPath = aProp->GetNextPath() ) {
427 vtkMapper *aMapper = NULL;
428 bool anIsPickable = false;
429 vtkActor* anActor = NULL;
430 vtkProp *aPropCandidate = aPath->GetLastNode()->GetProp();
431 if ( aPropCandidate->GetPickable() && aPropCandidate->GetVisibility() ) {
433 anActor = vtkActor::SafeDownCast(aPropCandidate);
435 aMapper = anActor->GetMapper();
436 if ( anActor->GetProperty()->GetOpacity() <= 0.0 )
437 anIsPickable = false;
440 if ( anIsPickable && aMapper && aMapper->GetInput()) {
441 int aSelectionPoint[4] = {int(theSelectionX),
444 int(theSelectionY2)};
445 if ( this->PickPoints ) {
446 TVectorIds& aVisibleIds = myPointIdsMap[anActor];
447 TVectorIds anInVisibleIds;
448 SelectVisiblePoints(aSelectionPoint,
454 if ( aVisibleIds.empty() ) {
455 myPointIdsMap.erase(myPointIdsMap.find(anActor));
458 TVectorIds& aVectorIds = myCellIdsMap[anActor];
459 SelectVisibleCells(aSelectionPoint,
464 if ( aVectorIds.empty() ) {
465 myCellIdsMap.erase(myCellIdsMap.find(anActor));
472 // Invoke end pick method if defined
473 this->InvokeEvent(vtkCommand::EndPickEvent,NULL);
475 return myPointIdsMap.empty() || myCellIdsMap.empty();
479 const SVTK_RectPicker::TVectorIdsMap&
481 ::GetPointIdsMap() const
483 return myPointIdsMap;
486 const SVTK_RectPicker::TVectorIdsMap&
488 ::GetCellIdsMap() const