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>
50 //----------------------------------------------------------------------------
53 //----------------------------------------------------------------------------
61 return theZPtr[theDX - theSelection[0] + (theDY - theSelection[1])*(theSelection[2] - theSelection[0] + 1)];
65 //----------------------------------------------------------------------------
77 if(theDX >= theSelection[0] && theDX <= theSelection[2] &&
78 theDY >= theSelection[1] && theDY <= theSelection[3])
80 // Access the value from the captured zbuffer. Note, we only
81 // captured a portion of the zbuffer, so we need to offset dx by
82 // the selection window.
83 aZ = GetZ(theZPtr,theSelection,theDX,theDY);
84 if(aZ > theTolerance && aZ < 1.0 - theTolerance){
85 aRet = fabs(aZ - theDZ) <= theTolerance;
89 //cout<<"\tCheck = {"<<theDX<<", "<<theDY<<", "<<theDZ<<", "<<aZ<<"} = "<<aRet<<"\n";
94 //----------------------------------------------------------------------------
96 SelectVisiblePoints(int theSelection[4],
97 vtkRenderer *theRenderer,
99 SVTK_RectPicker::TVectorIds& theVisibleIds,
100 SVTK_RectPicker::TVectorIds& theInVisibleIds,
103 theVisibleIds.clear();
104 theInVisibleIds.clear();
106 vtkIdType aNumPts = theInput->GetNumberOfPoints();
110 theVisibleIds.reserve(aNumPts/2 + 1);
111 theInVisibleIds.reserve(aNumPts/2 + 1);
113 // Grab the composite perspective transform. This matrix is used to convert
114 // each point to view coordinates. vtkRenderer provides a WorldToView()
115 // method but it computes the composite perspective transform each time
116 // WorldToView() is called. This is expensive, so we get the matrix once
117 // and handle the transformation ourselves.
118 vtkMatrix4x4 *aMatrix = vtkMatrix4x4::New();
119 aMatrix->DeepCopy(theRenderer->GetActiveCamera()->
120 GetCompositePerspectiveTransformMatrix(1,0,1));
122 // We grab the z-buffer for the selection region all at once and probe the resulting array.
123 float *aZPtr = theRenderer->GetRenderWindow()->
124 GetZbufferData(theSelection[0], theSelection[1], theSelection[2], theSelection[3]);
126 //cout<<"theSelection = {"<<theSelection[0]<<", "<<theSelection[1]<<", "<<theSelection[2]<<", "<<theSelection[3]<<"}\n";
128 for(int iY = theSelection[1]; iY <= theSelection[3]; iY++){
129 for(int iX = theSelection[0]; iX <= theSelection[2]; iX++){
130 cout<<GetZ(aZPtr,theSelection,iX,iY)<<" ";
135 for(vtkIdType aPntId = 0; aPntId < aNumPts; aPntId++){
136 // perform conversion
137 float aX[4] = {1.0, 1.0, 1.0, 1.0};
138 theInput->GetPoint(aPntId,aX);
141 aMatrix->MultiplyPoint(aX,aView);
144 theRenderer->SetViewPoint(aView[0]/aView[3],
147 theRenderer->ViewToDisplay();
150 theRenderer->GetDisplayPoint(aDX);
152 // check whether visible and in selection window
153 if(aDX[0] >= theSelection[0] && aDX[0] <= theSelection[2] &&
154 aDX[1] >= theSelection[1] && aDX[1] <= theSelection[3])
156 //cout<<"aPntId "<<aPntId<<"; aDX = {"<<aDX[0]<<", "<<aDX[1]<<", "<<aDX[2]<<"}\n";
157 int aDX0 = int(aDX[0]);
158 int aDX1 = int(aDX[1]);
160 int aRet = Check(aZPtr,theSelection,theTolerance,aDX[2],aDX0,aDX1);
166 static int aMaxRadius = 5;
167 for(int aRadius = 1; aRadius < aMaxRadius; aRadius++){
168 int aStartDX[2] = {aDX0 - aRadius, aDX1 - aRadius};
169 for(int i = 0; i <= aRadius; i++){
170 int aRet = Check(aZPtr,theSelection,theTolerance,aDX[2],aStartDX[0]++,aStartDX[1]);
176 for(int i = 0; i <= aRadius; i++){
177 int aRet = Check(aZPtr,theSelection,theTolerance,aDX[2],aStartDX[0],aStartDX[1]++);
183 for(int i = 0; i <= aRadius; i++){
184 int aRet = Check(aZPtr,theSelection,theTolerance,aDX[2],aStartDX[0]--,aStartDX[1]);
190 for(int i = 0; i <= aRadius; i++){
191 int aRet = Check(aZPtr,theSelection,theTolerance,aDX[2],aStartDX[0],aStartDX[1]--);
199 ADD_VISIBLE : theVisibleIds.push_back(aPntId);
201 ADD_INVISIBLE : theInVisibleIds.push_back(aPntId);
212 //----------------------------------------------------------------------------
215 GetCenter(const float theBounds[6],
218 theCenter[0] = (theBounds[1] + theBounds[0]) / 2.0;
219 theCenter[1] = (theBounds[3] + theBounds[2]) / 2.0;
220 theCenter[2] = (theBounds[5] + theBounds[4]) / 2.0;
224 SelectVisibleCells(int theSelection[4],
225 vtkRenderer *theRenderer,
226 vtkDataSet *theInput,
227 SVTK_RectPicker::TVectorIds& theVectorIds,
230 theVectorIds.clear();
232 vtkIdType aNumCells = theInput->GetNumberOfCells();
236 theVectorIds.reserve(aNumCells/2 + 1);
238 SVTK_RectPicker::TVectorIds aVisiblePntIds;
239 SVTK_RectPicker::TVectorIds anInVisiblePntIds;
240 SelectVisiblePoints(theSelection,
247 typedef std::set<vtkIdType> TIdsSet;
248 TIdsSet aVisibleIds(aVisiblePntIds.begin(),aVisiblePntIds.end());
249 TIdsSet anInVisibleIds(anInVisiblePntIds.begin(),anInVisiblePntIds.end());
251 // Grab the composite perspective transform. This matrix is used to convert
252 // each point to view coordinates. vtkRenderer provides a WorldToView()
253 // method but it computes the composite perspective transform each time
254 // WorldToView() is called. This is expensive, so we get the matrix once
255 // and handle the transformation ourselves.
256 vtkMatrix4x4 *aMatrix = vtkMatrix4x4::New();
257 aMatrix->DeepCopy(theRenderer->GetActiveCamera()->
258 GetCompositePerspectiveTransformMatrix(1,0,1));
260 for(vtkIdType aCellId = 0; aCellId < aNumCells; aCellId++){
261 vtkCell* aCell = theInput->GetCell(aCellId);
264 aCell->GetBounds(aBounds);
267 GetCenter(aBounds,aCenter);
270 float aX[4] = {aCenter[0], aCenter[1], aCenter[2], 1.0};
271 aMatrix->MultiplyPoint(aX,aView);
276 theRenderer->SetViewPoint(aView[0]/aView[3],
279 theRenderer->ViewToDisplay();
282 theRenderer->GetDisplayPoint(aDX);
284 // check whether visible and in selection window
285 if(aDX[0] >= theSelection[0] && aDX[0] <= theSelection[2] &&
286 aDX[1] >= theSelection[1] && aDX[1] <= theSelection[3])
289 //cout<<"aCellId = "<<aCellId<<": ";
290 vtkIdType aNumPts = aCell->GetNumberOfPoints();
291 bool anIsVisible = true;
292 for(vtkIdType anId = 0; anId < aNumPts; anId++){
293 vtkIdType aPntId = aCell->GetPointId(anId);
294 //cout<<aPntId<<"; ";
295 anIsVisible = aVisibleIds.find(aPntId) != aVisibleIds.end();
299 //cout<<"\t"<<anIsVisible<<"\n";
301 theVectorIds.push_back(aCellId);
306 //----------------------------------------------------------------------------
308 CalculatePickPosition(vtkRenderer *theRenderer,
312 float thePickPosition[3])
314 // Convert the selection point into world coordinates.
316 theRenderer->SetDisplayPoint(theSelectionX, theSelectionY, theSelectionZ);
317 theRenderer->DisplayToWorld();
318 float* aWorldCoords = theRenderer->GetWorldPoint();
319 if ( aWorldCoords[3] != 0.0 ) {
320 for (int i=0; i < 3; i++) {
321 thePickPosition[i] = aWorldCoords[i] / aWorldCoords[3];
327 //----------------------------------------------------------------------------
328 vtkStandardNewMacro(SVTK_RectPicker);
330 //----------------------------------------------------------------------------
334 this->Tolerance = 0.005;
335 this->PickPoints = 1;
344 ::Pick(float, float, float, vtkRenderer*)
349 //----------------------------------------------------------------------------
352 ::Pick(float theSelection[3], float theSelection2[3], vtkRenderer *theRenderer)
354 return Pick(theSelection[0], theSelection[1], theSelection[2],
355 theSelection2[0], theSelection2[1], theSelection2[2],
359 //----------------------------------------------------------------------------
362 ::Pick(float theSelectionX, float theSelectionY, float theSelectionZ,
363 float theSelectionX2, float theSelectionY2, float theSelectionZ2,
364 vtkRenderer *theRenderer)
366 // Initialize picking process
368 myCellIdsMap.clear();
369 myPointIdsMap.clear();
370 this->Renderer = theRenderer;
372 // Get camera focal point and position. Convert to display (screen)
373 // coordinates. We need a depth value for z-buffer.
375 vtkCamera* aCamera = theRenderer->GetActiveCamera();
378 aCamera->GetFocalPoint(aCameraFP);
381 theRenderer->SetWorldPoint(aCameraFP);
382 theRenderer->WorldToDisplay();
383 float* aDisplayCoords = theRenderer->GetDisplayPoint();
384 float aSelectionZ = aDisplayCoords[2];
386 this->SelectionPoint[0] = theSelectionX;
387 this->SelectionPoint[1] = theSelectionY;
388 this->SelectionPoint[2] = theSelectionZ;
390 // Convert the selection point into world coordinates.
392 CalculatePickPosition(theRenderer,
398 this->SelectionPoint2[0] = theSelectionX2;
399 this->SelectionPoint2[1] = theSelectionY2;
400 this->SelectionPoint2[2] = theSelectionZ2;
402 // Convert the selection point into world coordinates.
404 CalculatePickPosition(theRenderer,
408 this->PickPosition2);
410 // Invoke start pick method if defined
411 this->InvokeEvent(vtkCommand::StartPickEvent,NULL);
413 vtkPropCollection *aProps;
414 if ( this->PickFromList )
415 aProps = this->GetPickList();
417 aProps = theRenderer->GetProps();
419 aProps->InitTraversal();
420 while ( vtkProp* aProp = aProps->GetNextProp() ) {
421 aProp->InitPathTraversal();
422 while ( vtkAssemblyPath* aPath = aProp->GetNextPath() ) {
423 vtkMapper *aMapper = NULL;
424 bool anIsPickable = false;
425 vtkActor* anActor = NULL;
426 vtkProp *aPropCandidate = aPath->GetLastNode()->GetProp();
427 if ( aPropCandidate->GetPickable() && aPropCandidate->GetVisibility() ) {
429 anActor = vtkActor::SafeDownCast(aPropCandidate);
431 aMapper = anActor->GetMapper();
432 if ( anActor->GetProperty()->GetOpacity() <= 0.0 )
433 anIsPickable = false;
436 if ( anIsPickable && aMapper && aMapper->GetInput()) {
437 int aSelectionPoint[4] = {int(theSelectionX),
440 int(theSelectionY2)};
441 if ( this->PickPoints ) {
442 TVectorIds& aVisibleIds = myPointIdsMap[anActor];
443 TVectorIds anInVisibleIds;
444 SelectVisiblePoints(aSelectionPoint,
450 if ( aVisibleIds.empty() ) {
451 myPointIdsMap.erase(myPointIdsMap.find(anActor));
454 TVectorIds& aVectorIds = myCellIdsMap[anActor];
455 SelectVisibleCells(aSelectionPoint,
460 if ( aVectorIds.empty() ) {
461 myCellIdsMap.erase(myCellIdsMap.find(anActor));
468 // Invoke end pick method if defined
469 this->InvokeEvent(vtkCommand::EndPickEvent,NULL);
471 return myPointIdsMap.empty() || myCellIdsMap.empty();
475 //----------------------------------------------------------------------------
476 const SVTK_RectPicker::TVectorIdsMap&
478 ::GetPointIdsMap() const
480 return myPointIdsMap;
483 const SVTK_RectPicker::TVectorIdsMap&
485 ::GetCellIdsMap() const