Salome HOME
Copyrights update
[modules/gui.git] / src / VTKViewer / VTKViewer_CellRectPicker.cxx
1 // Copyright (C) 2005  OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D
2 // 
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either 
6 // version 2.1 of the License.
7 // 
8 // This library is distributed in the hope that it will be useful 
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of 
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public  
14 // License along with this library; if not, write to the Free Software 
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/
18 //
19 #include <VTKViewer_CellRectPicker.h>
20
21 #include "vtkGenericCell.h"
22 #include "vtkAssemblyNode.h"
23 #include "vtkAssemblyPath.h"
24 #include "vtkObjectFactory.h"
25 #include "vtkImageData.h"
26 #include "vtkMapper.h"
27 #include "vtkVolumeMapper.h"
28 #include "vtkMath.h"
29 #include "vtkLine.h"
30 #include "vtkQuad.h"
31 #include "vtkPoints.h"
32 #include "vtkPlane.h"
33 #include "vtkActor.h"
34
35 vtkStandardNewMacro(VTKViewer_CellRectPicker);
36
37 /*!Constructor.\n
38  * \li create instance of generic cell
39  * \li create two instances of Quad.
40  */
41 VTKViewer_CellRectPicker::VTKViewer_CellRectPicker()
42 {
43   this->Cell = vtkGenericCell::New();
44   this->Quad1 = vtkQuad::New();
45   this->Quad2 = vtkQuad::New();
46 }
47
48 /*!Destructor.
49  * \li Delete generic cell
50  * \li Delete two quads.
51  */
52 VTKViewer_CellRectPicker::~VTKViewer_CellRectPicker()
53 {
54   this->Cell->Delete();
55   this->Quad1->Delete();
56   this->Quad2->Delete();
57 }
58
59 /*!Clear \a ActorData and call VTKViewer_RectPicker::Initialize() method*/
60 void VTKViewer_CellRectPicker::Initialize()
61 {
62   ActorData.clear();
63   this->VTKViewer_RectPicker::Initialize();
64 }
65
66 /*!*/
67 float VTKViewer_CellRectPicker::IntersectWithHex(float p1[4][4], float p2[4][4], float tol, 
68                                                  vtkAssemblyPath *path, vtkProp3D *prop3D, 
69                                                  vtkAbstractMapper3D *m)
70 {
71   vtkDataSet *input;
72   vtkMapper *mapper;
73   vtkVolumeMapper *volumeMapper;
74   
75   // Get the underlying dataset
76   if ( (mapper=vtkMapper::SafeDownCast(m)) != NULL ) {
77     input = mapper->GetInput();
78   }
79   else if ( (volumeMapper=vtkVolumeMapper::SafeDownCast(m)) != NULL ) {
80     input = volumeMapper->GetInput();
81   }
82   else {
83     return VTK_LARGE_FLOAT;
84   }
85   
86   vtkIdType numCells;
87   if ( (numCells = input->GetNumberOfCells()) < 1 ) {
88     return 2.0;
89   }
90   
91   int i, k, subId;
92   float bounds[6], center[3], cp1[3], cp2[3];
93   float pcoord[3], weight[4], dist;
94   float t1[2], t2[2], x[3], t;
95   
96   for (k = 0; k < 4; k++) {
97     this->Quad1->PointIds->SetId(k, k);
98     this->Quad1->Points->SetPoint(k, p1[k]);
99     this->Quad2->PointIds->SetId(k, k);
100     this->Quad2->Points->SetPoint(k, p2[k]);
101   }
102   
103   /*
104   cout << "---> Selection area:"   << endl;
105   for (k = 0; k < 4; k++)
106   cout << "\t(" << p1[k][0] << ", " << p1[k][1] << ", " << p1[k][2] << ")";
107   cout << endl;
108   for (k = 0; k < 4; k++)
109   cout << "\t(" << p2[k][0] << ", " << p2[k][1] << ", " << p2[k][2] << ")";
110   cout << endl;
111   */
112   
113   vtkIdType cellId;
114   VTKViewer_CellData cellData;
115   VTKViewer_CellDataSet dataList;
116   
117   char inside; int n; float *point;
118   float tMin = VTK_LARGE_FLOAT, xMin[3];
119   for (cellId = 0; cellId < numCells; cellId++) {
120     input->GetCell(cellId, this->Cell);
121     
122     this->Cell->GetBounds(bounds);
123     for (i = 0; i < 3; i++)
124       center[i] = (bounds[2*i]+bounds[2*i+1])/2;
125     
126       /*
127       if (!VTKViewer_RectPicker::PointInside(center, p1, p2, 0.01))
128       continue;
129     */
130     
131     inside = 1;
132     n = this->Cell->Points->GetNumberOfPoints();
133     //cout << "---> Info cell " << cellId << " (" << n << "): " << endl;
134     for (k = 0; k < n; k++) {
135       point = this->Cell->Points->GetPoint(k);
136       //cout << "  P (" << point[0] << ", " << point[1] << ", " << point[2] << ")";
137       if (!VTKViewer_RectPicker::PointInside(point, p1, p2)) {
138         inside = 0; break;
139       }
140     }
141     //cout << endl;
142     if (!inside) continue;
143     
144     //cout << "---> Inside cell " << cellId << endl;
145     
146     this->Quad1->EvaluatePosition(center, 0, subId, pcoord, dist, weight);
147     t1[0] = pcoord[0]; t1[1] = pcoord[1];
148     this->Quad2->EvaluatePosition(center, 0, subId, pcoord, dist, weight);
149     t2[0] = pcoord[0]; t2[1] = pcoord[1];
150     
151     pcoord[0] = (t1[0]+t2[0])/2; pcoord[1] = (t1[1]+t2[1])/2; pcoord[2] = 0;
152     
153     this->Quad1->EvaluateLocation(subId, pcoord, cp1, weight);
154     this->Quad2->EvaluateLocation(subId, pcoord, cp2, weight);
155     
156     if (this->Cell->IntersectWithLine(cp1, cp2, tol, t, x, pcoord, subId)) {
157       cellData.cellId = cellId;
158       cellData.subId = subId;
159       cellData.depth = t;
160       for (i = 0; i < 3; i++) {
161         cellData.p1[i] = cp1[i];
162         cellData.p2[i] = cp2[i];
163       }
164       /*
165       cout << "---> Include cell " << cellId << ", depth = " << t   << endl;
166       cout << "     P1 = (" << cp1[0] << ", " << cp1[1] << ", " << cp1[2] << ")"  << endl;
167       cout << "     P2 = (" << cp2[0] << ", " << cp2[1] << ", " << cp2[2] << ")"  << endl;
168       */
169       IncludeCell(input, cellData, dataList);
170       if (t < tMin) {
171         tMin = t;
172         for (i = 0; i < 3; i++)
173           xMin[i] = x[i];
174       }
175     }
176   }
177   
178   if (!dataList.empty()) {
179     // compare against other actors
180     IncludeActor(prop3D, input, dataList);
181     if (tMin < this->GlobalTMin) {
182       this->MarkPicked(path, prop3D, m, tMin, xMin);
183     }
184   }
185   
186   return tMin;
187 }
188
189 /*!*/
190 void VTKViewer_CellRectPicker::IncludeCell(vtkDataSet* input, 
191                                            VTKViewer_CellData cellData, 
192                                            VTKViewer_CellDataSet& dataList)
193 {
194   vtkGenericCell* cell1 = vtkGenericCell::New();
195   vtkGenericCell* cell2 = vtkGenericCell::New();
196   vtkCell* sub1 = 0;
197   vtkCell* sub2 = 0;
198   
199   input->GetCell(cellData.cellId, cell1);
200   if (cell1->GetNumberOfFaces() > 0)
201     sub1 = cell1->GetFace(cellData.subId);
202   
203   int i, result;
204   float p1[3], p2[3], dir[3];
205   char add = 1;
206   
207   VTKViewer_CellData curData;
208   VTKViewer_CellDataSet::iterator it;
209   for (it = dataList.begin(); it != dataList.end();) {
210     curData = *it;
211     for (i = 0; i < 3; i++) {
212       p1[i] = (cellData.p1[i]+curData.p1[i])/2;
213       p2[i] = (cellData.p2[i]+curData.p2[i])/2;
214       dir[i] = p2[i] - p1[i];
215     }
216     
217     input->GetCell(curData.cellId, cell2);
218     sub2 = 0;
219     if (cell2->GetNumberOfFaces() > 0)
220       sub2 = cell2->GetFace(curData.subId);
221     
222     if (sub1) {
223       if (sub2)
224         result = IntersectCells(sub1, cellData.depth, 
225         sub2, curData.depth, dir);
226       else 
227         result = IntersectCells(sub1, cellData.depth, 
228         cell2, curData.depth, dir);
229     }
230     else {
231       if (sub2)
232         result = IntersectCells(cell1, cellData.depth, 
233         sub2, curData.depth, dir);
234       else
235         result = IntersectCells(cell1, cellData.depth, 
236         cell2, curData.depth, dir);
237     }
238     /*
239     cout << "     Direction = (" << dir[0] << ", " << dir[1] << ", " << dir[2] << ")";
240     cout << "     depth = " << cellData.depth << ", " << curData.depth << ", " << result << endl;
241     */
242     if (result > 0) {
243       if (result == 1) {
244         it = dataList.erase(it);
245         continue;
246       } 
247       else {
248         add = 0;
249         break;
250       }
251     }
252     ++it;
253   }
254   if (add) {
255     //cout << "     add "   << endl;
256     dataList.push_back(cellData);
257   }
258   
259   cell1->Delete();
260   cell2->Delete();
261 }
262
263 /*!*/
264 void VTKViewer_CellRectPicker::IncludeActor(vtkProp3D* prop, 
265                                             vtkDataSet* input, 
266                                             VTKViewer_CellDataSet& dataList)
267 {
268   vtkGenericCell* cell1 = vtkGenericCell::New();
269   vtkGenericCell* cell2 = vtkGenericCell::New();
270   
271   int i, result;
272   float p1[3], p2[3], dir[3];
273   char removed;
274   
275   VTKViewer_CellDataSet actorData;
276   VTKViewer_CellData curData, cellData;
277   VTKViewer_CellDataSet::iterator it1, it2;
278   VTKViewer_ActorDataMap::iterator it;
279   
280   for (it1 = dataList.begin(); it1 != dataList.end();) {
281     cellData = *it1;
282     input->GetCell(cellData.cellId, cell1);
283     removed = 0;
284     
285     for (it = ActorData.begin(); it != ActorData.end(); ++it) {
286       //vtkActor* actor = (*it).first;
287       actorData = (*it).second;
288       
289       for (it2 = actorData.begin(); it2 != actorData.end();) {
290         curData = *it2;
291         for (i = 0; i < 3; i++) {
292           p1[i] = (cellData.p1[i]+curData.p1[i])/2;
293           p2[i] = (cellData.p2[i]+curData.p2[i])/2;
294           dir[i] = p2[i] - p1[i];
295         }
296         
297         input->GetCell(curData.cellId, cell2);
298         result = IntersectCells(cell1, cellData.depth,
299           cell2, curData.depth, dir);
300         if (result > 0) {
301           if (result == 1) {
302             it2 = actorData.erase(it2);
303             continue;
304           }
305           else {
306             removed = 1;
307             it1 = dataList.erase(it1);
308             break;
309           }
310           break;
311         }
312         ++it2;
313       }
314       if (removed) break;
315     } // by actors
316     if (!removed) ++it1;
317   }
318   
319   if (!dataList.empty()) {
320     vtkActor* actor;
321     if ((actor = vtkActor::SafeDownCast(prop)) != NULL)
322       ActorData[actor] = dataList;
323   }
324   
325   cell1->Delete();
326   cell2->Delete();
327 }
328
329 /*! The method returns a non-zero value, if the cells intersect each other 
330  * in the direction dir[3].
331  * \param c1 - first vtkCell pointer
332  * \param d1 - 
333  * \param c2 - second vtkCell pointer
334  * \param d2 - 
335  * \param dir[3] - direction
336  * \retval integer - Returned value is 1 if the first cell is top of 
337  * the second one according to direction and 2 if the second cell is top.
338  */
339 int VTKViewer_CellRectPicker::IntersectCells(vtkCell* c1, float d1, vtkCell* c2, float d2, float dir[3])
340 {
341   int i, k;
342   float *orig, cp[3], bounds[6];
343   vtkCell* cell = 0;
344   vtkCell* tcell = 0;
345   
346   // define the central point and cell for projection
347   if (fabs(d1-d2) < 1.e-7) return 0;
348   
349   if (d1 < d2) {
350     orig = c1->Points->GetPoint(0);
351     cell = c1;
352     tcell = c2;
353     c2->GetBounds(bounds);
354     for (i = 0; i < 3; i++)
355       cp[i] = (bounds[2*i] + bounds[2*i+1])/2;
356   }
357   else if (d1 > d2) {
358     orig = c2->Points->GetPoint(0);
359     cell = c2;
360     tcell = c1;
361     c1->GetBounds(bounds);
362     for (i = 0; i < 3; i++)
363       cp[i] = (bounds[2*i] + bounds[2*i+1])/2;
364   }
365   
366   float proj[3];
367   vtkPlane::GeneralizedProjectPoint(cp, orig, dir, proj);
368   
369   float *p, pp[3];
370   vtkPoints* aPoints = vtkPoints::New();
371   for (k = 0; k < cell->Points->GetNumberOfPoints(); k++) {
372     p = cell->Points->GetPoint(k);
373     vtkPlane::GeneralizedProjectPoint(p, orig, dir, pp);
374     aPoints->InsertNextPoint(pp[0], pp[1], pp[2]);
375   }
376   
377   int result = 0;
378   if (PointInside(proj, aPoints)) {
379     result = (d1<d2) ? 1 : 2;
380   }
381   
382   if (result == 0) {
383     // test for boundary cells
384     for (k = 0; k < tcell->Points->GetNumberOfPoints(); k++) {
385       p = tcell->Points->GetPoint(k);
386       vtkPlane::GeneralizedProjectPoint(p, orig, dir, pp);
387       if (PointInside(pp, aPoints)) {
388         result = 1; break;
389       }
390     }
391     if (result && d2<d1) result = 2;
392   }
393   
394   aPoints->Delete();
395   return result;
396 }
397
398 /*! Check point position.
399  * \param point[3] - point
400  * \param list - point data set
401  * \retval 0 or 1 - The method returns a non-zero value, if the point is inlide point data set
402  */
403 char VTKViewer_CellRectPicker::PointInside(float point[3], vtkPoints* list)
404 {
405   int i, k, l, n;
406   float x[3], *a1, *a2, v[3], p[3], q[3];
407   
408   n = list->GetNumberOfPoints();
409   if (n < 3) return 0;
410   
411   for (k = 0; k < n; k++) {
412     l = k+1; if (l == n) l = 0;
413     a1 = list->GetPoint(k);
414     a2 = list->GetPoint(l);
415     
416     // compute vectors
417     for (i = 0; i < 3; i++) {
418       x[i] = point[i] - a1[i];
419       v[i] = a2[i]-a1[i];
420     }
421     
422     // check if point coincides with vertex
423     if (x[0]*x[0] + x[1]*x[1] + x[2]*x[2] < 1.e-7) return 0;
424     
425     // compute normal
426     vtkMath::Cross(x, v, p);
427     
428     // check if point lays on edge
429     if (p[0]*p[0] + p[1]*p[1] + p[2]*p[2] < 1.e-7) return 0;
430     
431     // check if normals are in the same direction
432     if (k > 0) {
433       if (vtkMath::Dot(p, q) < 0.0) return 0;
434     }
435     
436     // remember normal direction
437     for (i = 0; i < 3; i++) {
438       q[i] = p[i];
439     }
440   }
441   
442   return 1;
443 }