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