fw4spl
fwVtkCellPicker.cpp
1 /* ***** BEGIN LICENSE BLOCK *****
2  * FW4SPL - Copyright (C) IRCAD, 2009-2017.
3  * Distributed under the terms of the GNU Lesser General Public License (LGPL) as
4  * published by the Free Software Foundation.
5  * ****** END LICENSE BLOCK ****** */
6 
7 /*=========================================================================
8  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
9  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
10  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
11  fw version of vtkCellPicked : same a vtk5.4's cellpicker,
12  but inherits from fwVtkPicker.
13  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
14  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
15  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
16  =========================================================================*/
17 
18 /*=========================================================================
19 
20  Program: Visualization Toolkit
21  Module: $RCSfile: fwVtkCellPicker.cxx,v $
22 
23  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
24  All rights reserved.
25  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
26 
27  This software is distributed WITHOUT ANY WARRANTY; without even
28  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
29  PURPOSE. See the above copyright notice for more information.
30 
31  =========================================================================*/
32 
33 #include "fwRenderVTK/vtk/fwVtkCellPicker.hpp"
34 
35 #include <boost/assign.hpp>
36 
37 #include <vtkAbstractVolumeMapper.h>
38 #include <vtkGenericCell.h>
39 #include <vtkImageData.h>
40 #include <vtkInstantiator.h>
41 #include <vtkMapper.h>
42 #include <vtkMath.h>
43 #include <vtkObjectFactory.h>
44 #include <vtkPolyData.h>
45 
46 vtkStandardNewMacro(fwVtkCellPicker);
47 
48 //------------------------------------------------------------------------------
49 
50 fwVtkCellPicker::fwVtkCellPicker()
51 {
52  this->CellId = -1;
53  this->SubId = -1;
54  for (int i = 0; i < 3; i++)
55  {
56  this->PCoords[i] = 0.0;
57  }
58  this->Cell = vtkGenericCell::New();
59 }
60 
61 //------------------------------------------------------------------------------
62 
63 fwVtkCellPicker::~fwVtkCellPicker()
64 {
65  this->Cell->Delete();
66 }
67 
68 //------------------------------------------------------------------------------
69 
70 double fwVtkCellPicker::IntersectWithLine(double p1[3], double p2[3], double tol,
71  vtkAssemblyPath* path,
72  vtkProp3D* prop3D,
73  vtkAbstractMapper3D* m)
74 {
75  vtkIdType numCells, cellId, minCellId;
76  int i, minSubId, subId;
77  double x[3], tMin, t, pcoords[3], minXYZ[3], minPcoords[3];
78  vtkDataSet* input;
79  vtkMapper* mapper;
80  vtkAbstractVolumeMapper* volumeMapper;
81 
82  // Get the underlying dataset
83  if ( (mapper = vtkMapper::SafeDownCast(m)) != NULL )
84  {
85  input = mapper->GetInput();
86  }
87  else if ( (volumeMapper = vtkAbstractVolumeMapper::SafeDownCast(m)) != NULL )
88  {
89  input = volumeMapper->GetDataSetInput();
90  }
91  else
92  {
93  return VTK_DOUBLE_MAX;
94  }
95 
96  if ( (numCells = input->GetNumberOfCells()) < 1 )
97  {
98  return 2.0;
99  }
100 
101  // Intersect each cell with ray. Keep track of one closest to
102  // the eye (within the tolerance tol) and within the clipping range).
103  // Note that we fudge the "closest to" (tMin+this->Tolerance) a little and
104  // keep track of the cell with the best pick based on parametric
105  // coordinate (pick the minimum, maximum parametric distance). This
106  // breaks ties in a reasonable way when cells are the same distance
107  // from the eye (like cells lying on a 2D plane).
108  //
109  minCellId = -1;
110  minSubId = -1;
111  pcoords[0] = pcoords[1] = pcoords[2] = 0;
112  double pDistMin = VTK_DOUBLE_MAX, pDist;
113  for (tMin = VTK_DOUBLE_MAX, cellId = 0; cellId < numCells; cellId++)
114  {
115  input->GetCell(cellId, this->Cell);
116 
117  if ( this->Cell->IntersectWithLine(p1, p2, tol, t, x, pcoords, subId)
118  && t <= (tMin+this->Tolerance) )
119  {
120  pDist = this->Cell->GetParametricDistance(pcoords);
121  if ( pDist < pDistMin || (pDist == pDistMin && t < tMin) )
122  {
123  minCellId = cellId;
124  minSubId = subId;
125  for (i = 0; i < 3; i++)
126  {
127  minXYZ[i] = x[i];
128  minPcoords[i] = pcoords[i];
129  }
130  tMin = t;
131  pDistMin = pDist;
132  }//if minimum, maximum
133  }//if a close cell
134  }//for all cells
135 
136  // Now compare this against other actors.
137  if ( minCellId > (-1) && tMin < this->GlobalTMin )
138  {
139  this->MarkPicked(path, prop3D, m, tMin, minXYZ);
140  this->CellId = minCellId;
141  this->SubId = minSubId;
142  for (i = 0; i < 3; i++)
143  {
144  this->PCoords[i] = minPcoords[i];
145  }
146  vtkDebugMacro("Picked cell id= " << minCellId);
147  }
148  return tMin;
149 }
150 
151 //------------------------------------------------------------------------------
152 
153 void fwVtkCellPicker::Initialize()
154 {
155  this->CellId = (-1);
156  this->SubId = (-1);
157  for (int i = 0; i < 3; i++)
158  {
159  this->PCoords[i] = 0.0;
160  }
161  this->fwVtkPicker::Initialize();
162 }
163 
164 //------------------------------------------------------------------------------
165 
166 void fwVtkCellPicker::PrintSelf(ostream& os, vtkIndent indent)
167 {
168  this->Superclass::PrintSelf(os, indent);
169 
170  os << indent << "Cell Id: " << this->CellId << "\n";
171  os << indent << "SubId: " << this->SubId << "\n";
172  os << indent << "PCoords: (" << this->PCoords[0] << ", "
173  << this->PCoords[1] << ", " << this->PCoords[2] << ")\n";
174 }
175 
176 //------------------------------------------------------------------------------
177 
178 fwVtkCellPicker::PickedCellType fwVtkCellPicker::GetPickedCellIds( double p1[3], double p2[3], vtkPolyData* polydata)
179 {
180  PickedCellType res;
181 
182  if ( this->PickPolyData(p1, p2, polydata) )
183  {
184  double* intersec = this->GetPickPosition();
185  fwVec3d point;
186 
187  for(unsigned int i = 0; i < 3; i++)
188  {
189  point[i] = intersec[i];
190  }
191  res.push_back( std::make_pair( this->GetCellId(), point) );
192 
193  double ray[3];
194  double p3a[3];
195  double p3b[3];
196 
197  this->GetPickPosition(p3a);
198  this->GetPickPosition(p3b);
199 
200  for (int i = 0; i < 3; i++)
201  {
202  ray[i] = p2[i] - p1[i];
203  }
204 
205  vtkMath::Normalize(ray);
206 
207  for (int i = 0; i < 3; i++)
208  {
209  ray[i] *= 1e-5;
210  p3a[i] -= ray[i];
211  p3b[i] += ray[i];
212  }
213 
214  ::boost::assign::push_back(res).range( this->GetPickedCellIds(p1, p3a, polydata) );
215  ::boost::assign::push_back(res).range( this->GetPickedCellIds(p3b, p2, polydata) );
216 
217  }
218 
219  return res;
220 }