Salome HOME
Merge from V6_3_BR 06/06/2011
[modules/smesh.git] / src / SMDS / SMDS_VtkVolume.cxx
1 // Copyright (C) 2010-2011  CEA/DEN, EDF R&D, OPEN CASCADE
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/ or email : webmaster.salome@opencascade.com
18 //
19
20 #include "SMDS_VtkVolume.hxx"
21 #include "SMDS_MeshNode.hxx"
22 #include "SMDS_Mesh.hxx"
23 #include "SMDS_VtkCellIterator.hxx"
24
25 #include "utilities.h"
26
27 #include <vector>
28
29 SMDS_VtkVolume::SMDS_VtkVolume()
30 {
31 }
32
33 SMDS_VtkVolume::SMDS_VtkVolume(std::vector<vtkIdType> nodeIds, SMDS_Mesh* mesh)
34 {
35   init(nodeIds, mesh);
36 }
37 /*!
38  * typed used are vtk types (@see vtkCellType.h)
39  * see GetEntityType() for conversion in SMDS type (@see SMDSAbs_ElementType.hxx)
40  */
41 void SMDS_VtkVolume::init(std::vector<vtkIdType> nodeIds, SMDS_Mesh* mesh)
42 {
43   SMDS_MeshVolume::init();
44   vtkUnstructuredGrid* grid = mesh->getGrid();
45   myMeshId = mesh->getMeshId();
46   vtkIdType aType = VTK_TETRA;
47   switch (nodeIds.size())
48   {
49     case 4:
50       aType = VTK_TETRA;
51       break;
52     case 5:
53       aType = VTK_PYRAMID;
54       break;
55     case 6:
56       aType = VTK_WEDGE;
57       break;
58     case 8:
59       aType = VTK_HEXAHEDRON;
60       break;
61     case 10:
62       aType = VTK_QUADRATIC_TETRA;
63       break;
64     case 13:
65       aType = VTK_QUADRATIC_PYRAMID;
66       break;
67     case 15:
68       aType = VTK_QUADRATIC_WEDGE;
69       break;
70     case 20:
71       aType = VTK_QUADRATIC_HEXAHEDRON;
72       break;
73     default:
74       aType = VTK_HEXAHEDRON;
75       break;
76   }
77   myVtkID = grid->InsertNextLinkedCell(aType, nodeIds.size(), &nodeIds[0]);
78   mesh->setMyModified();
79   //MESSAGE("SMDS_VtkVolume::init myVtkID " << myVtkID);
80 }
81
82 //#ifdef VTK_HAVE_POLYHEDRON
83 void SMDS_VtkVolume::initPoly(std::vector<vtkIdType> nodeIds, std::vector<int> nbNodesPerFace, SMDS_Mesh* mesh)
84 {
85   SMDS_MeshVolume::init();
86   //MESSAGE("SMDS_VtkVolume::initPoly");
87   SMDS_UnstructuredGrid* grid = mesh->getGrid();
88   double center[3];
89   this->gravityCenter(grid, &nodeIds[0], nodeIds.size(), &center[0]);
90   vector<vtkIdType> ptIds;
91   ptIds.clear();
92   vtkIdType nbFaces = nbNodesPerFace.size();
93   int k = 0;
94   for (int i = 0; i < nbFaces; i++)
95     {
96       int nf = nbNodesPerFace[i];
97       ptIds.push_back(nf);
98       double a[3];
99       double b[3];
100       double c[3];
101       grid->GetPoints()->GetPoint(nodeIds[k], a);
102       grid->GetPoints()->GetPoint(nodeIds[k + 1], b);
103       grid->GetPoints()->GetPoint(nodeIds[k + 2], c);
104       bool isFaceForward = this->isForward(a, b, c, center);
105       //MESSAGE("isFaceForward " << i << " " << isFaceForward);
106       vtkIdType *facePts = &nodeIds[k];
107       if (isFaceForward)
108         for (int n = 0; n < nf; n++)
109           ptIds.push_back(facePts[n]);
110       else
111         for (int n = nf - 1; n >= 0; n--)
112           ptIds.push_back(facePts[n]);
113       k += nf;
114     }
115   myVtkID = grid->InsertNextLinkedCell(VTK_POLYHEDRON, nbFaces, &ptIds[0]);
116   mesh->setMyModified();
117 }
118 //#endif
119
120 bool SMDS_VtkVolume::ChangeNodes(const SMDS_MeshNode* nodes[], const int nbNodes)
121 {
122   vtkUnstructuredGrid* grid = SMDS_Mesh::_meshList[myMeshId]->getGrid();
123   vtkIdType npts = 0;
124   vtkIdType* pts = 0;
125   grid->GetCellPoints(myVtkID, npts, pts);
126   if (nbNodes != npts)
127     {
128       MESSAGE("ChangeNodes problem: not the same number of nodes " << npts << " -> " << nbNodes);
129       return false;
130     }
131   for (int i = 0; i < nbNodes; i++)
132     {
133       pts[i] = nodes[i]->getVtkId();
134     }
135   SMDS_Mesh::_meshList[myMeshId]->setMyModified();
136   return true;
137 }
138
139 /*!
140  * Reorder in VTK order a list of nodes given in SMDS order.
141  * To be used before ChangeNodes: lists are given or computed in SMDS order.
142  */
143 bool SMDS_VtkVolume::vtkOrder(const SMDS_MeshNode* nodes[], const int nbNodes)
144 {
145   if (nbNodes != this->NbNodes())
146     {
147       MESSAGE("vtkOrder, wrong number of nodes " << nbNodes << " instead of "<< this->NbNodes());
148       return false;
149     }
150   vtkUnstructuredGrid* grid = SMDS_Mesh::_meshList[myMeshId]->getGrid();
151   vtkIdType aVtkType = grid->GetCellType(this->myVtkID);
152   switch (aVtkType)
153   {
154     case VTK_TETRA:
155       this->exchange(nodes, 1, 2);
156       break;
157     case VTK_QUADRATIC_TETRA:
158       this->exchange(nodes, 1, 2);
159       this->exchange(nodes, 4, 6);
160       this->exchange(nodes, 8, 9);
161       break;
162     case VTK_PYRAMID:
163       this->exchange(nodes, 1, 3);
164       break;
165     case VTK_WEDGE:
166       break;
167     case VTK_QUADRATIC_PYRAMID:
168       this->exchange(nodes, 1, 3);
169       this->exchange(nodes, 5, 8);
170       this->exchange(nodes, 6, 7);
171       this->exchange(nodes, 10, 12);
172       break;
173     case VTK_QUADRATIC_WEDGE:
174       break;
175     case VTK_HEXAHEDRON:
176       this->exchange(nodes, 1, 3);
177       this->exchange(nodes, 5, 7);
178       break;
179     case VTK_QUADRATIC_HEXAHEDRON:
180       this->exchange(nodes, 1, 3);
181       this->exchange(nodes, 5, 7);
182       this->exchange(nodes, 8, 11);
183       this->exchange(nodes, 9, 10);
184       this->exchange(nodes, 12, 15);
185       this->exchange(nodes, 13, 14);
186       this->exchange(nodes, 17, 19);
187       break;
188     case VTK_POLYHEDRON:
189     default:
190       break;
191   }
192   return true;
193 }
194
195 SMDS_VtkVolume::~SMDS_VtkVolume()
196 {
197 }
198
199 void SMDS_VtkVolume::Print(ostream & OS) const
200 {
201   OS << "volume <" << GetID() << "> : ";
202 }
203
204 int SMDS_VtkVolume::NbFaces() const
205 {
206   vtkUnstructuredGrid* grid = SMDS_Mesh::_meshList[myMeshId]->getGrid();
207   vtkIdType aVtkType = grid->GetCellType(this->myVtkID);
208   int nbFaces = 4;
209   switch (aVtkType)
210   {
211     case VTK_TETRA:
212     case VTK_QUADRATIC_TETRA:
213       nbFaces = 4;
214       break;
215     case VTK_PYRAMID:
216     case VTK_WEDGE:
217     case VTK_QUADRATIC_PYRAMID:
218     case VTK_QUADRATIC_WEDGE:
219       nbFaces = 5;
220       break;
221     case VTK_HEXAHEDRON:
222     case VTK_QUADRATIC_HEXAHEDRON:
223       nbFaces = 6;
224       break;
225     case VTK_POLYHEDRON:
226       {
227         vtkIdType nFaces = 0;
228         vtkIdType* ptIds = 0;
229         grid->GetFaceStream(this->myVtkID, nFaces, ptIds);
230         nbFaces = nFaces;
231         break;
232       }
233     default:
234       MESSAGE("invalid volume type")
235       ;
236       nbFaces = 0;
237       break;
238   }
239   return nbFaces;
240 }
241
242 int SMDS_VtkVolume::NbNodes() const
243 {
244   vtkUnstructuredGrid* grid = SMDS_Mesh::_meshList[myMeshId]->getGrid();
245   vtkIdType aVtkType = grid->GetCellType(this->myVtkID);
246   int nbPoints = 0;
247   if (aVtkType != VTK_POLYHEDRON)
248     {
249       nbPoints = grid->GetCell(myVtkID)->GetNumberOfPoints();
250     }
251   else
252     {
253       vtkIdType nFaces = 0;
254       vtkIdType* ptIds = 0;
255       grid->GetFaceStream(this->myVtkID, nFaces, ptIds);
256       int id = 0;
257       for (int i = 0; i < nFaces; i++)
258         {
259           int nodesInFace = ptIds[id];
260           nbPoints += nodesInFace;
261           id += (nodesInFace + 1);
262         }
263     }
264   return nbPoints;
265 }
266
267 int SMDS_VtkVolume::NbEdges() const
268 {
269   vtkUnstructuredGrid* grid = SMDS_Mesh::_meshList[myMeshId]->getGrid();
270   vtkIdType aVtkType = grid->GetCellType(this->myVtkID);
271   int nbEdges = 6;
272   switch (aVtkType)
273   {
274     case VTK_TETRA:
275     case VTK_QUADRATIC_TETRA:
276       nbEdges = 6;
277       break;
278     case VTK_PYRAMID:
279     case VTK_QUADRATIC_PYRAMID:
280       nbEdges = 8;
281       break;
282     case VTK_WEDGE:
283     case VTK_QUADRATIC_WEDGE:
284       nbEdges = 9;
285       break;
286     case VTK_HEXAHEDRON:
287     case VTK_QUADRATIC_HEXAHEDRON:
288       nbEdges = 12;
289       break;
290     case VTK_POLYHEDRON:
291       {
292         vtkIdType nFaces = 0;
293         vtkIdType* ptIds = 0;
294         grid->GetFaceStream(this->myVtkID, nFaces, ptIds);
295         nbEdges = 0;
296         int id = 0;
297         for (int i = 0; i < nFaces; i++)
298           {
299             int edgesInFace = ptIds[id];
300             id += (edgesInFace + 1);
301             nbEdges += edgesInFace;
302           }
303         nbEdges = nbEdges / 2;
304         break;
305       }
306     default:
307       MESSAGE("invalid volume type")
308       ;
309       nbEdges = 0;
310       break;
311   }
312   return nbEdges;
313 }
314
315 /*! polyhedron only,
316  *  1 <= face_ind <= NbFaces()
317  */
318 int SMDS_VtkVolume::NbFaceNodes(const int face_ind) const
319 {
320   vtkUnstructuredGrid* grid = SMDS_Mesh::_meshList[myMeshId]->getGrid();
321   vtkIdType aVtkType = grid->GetCellType(this->myVtkID);
322   int nbNodes = 0;
323   if (aVtkType == VTK_POLYHEDRON)
324     {
325       vtkIdType nFaces = 0;
326       vtkIdType* ptIds = 0;
327       grid->GetFaceStream(this->myVtkID, nFaces, ptIds);
328       int id = 0;
329       for (int i = 0; i < nFaces; i++)
330         {
331           int nodesInFace = ptIds[id];
332           id += (nodesInFace + 1);
333           if (i == face_ind - 1)
334             {
335               nbNodes = nodesInFace;
336               break;
337             }
338         }
339     }
340   return nbNodes;
341 }
342
343 /*! polyhedron only,
344  *  1 <= face_ind <= NbFaces()
345  *  1 <= node_ind <= NbFaceNodes()
346  */
347 const SMDS_MeshNode* SMDS_VtkVolume::GetFaceNode(const int face_ind, const int node_ind) const
348 {
349   SMDS_Mesh *mesh = SMDS_Mesh::_meshList[myMeshId];
350   vtkUnstructuredGrid* grid = mesh->getGrid();
351   vtkIdType aVtkType = grid->GetCellType(this->myVtkID);
352   const SMDS_MeshNode* node = 0;
353   if (aVtkType == VTK_POLYHEDRON)
354     {
355       vtkIdType nFaces = 0;
356       vtkIdType* ptIds = 0;
357       grid->GetFaceStream(this->myVtkID, nFaces, ptIds);
358       int id = 0;
359       for (int i = 0; i < nFaces; i++)
360         {
361           int nodesInFace = ptIds[id]; // nodeIds in ptIds[id+1 .. id+nodesInFace]
362           if (i == face_ind - 1) // first face is number 1
363             {
364               if ((node_ind > 0) && (node_ind <= nodesInFace))
365                 node = mesh->FindNodeVtk(ptIds[id + node_ind]); // ptIds[id+1] : first node
366               break;
367             }
368           id += (nodesInFace + 1);
369         }
370     }
371   return node;
372 }
373
374 /*! polyhedron only,
375  *  return number of nodes for each face
376  */
377 const std::vector<int> SMDS_VtkVolume::GetQuantities() const
378 {
379   vector<int> quantities;
380   quantities.clear();
381   SMDS_Mesh *mesh = SMDS_Mesh::_meshList[myMeshId];
382   vtkUnstructuredGrid* grid = mesh->getGrid();
383   vtkIdType aVtkType = grid->GetCellType(this->myVtkID);
384   if (aVtkType == VTK_POLYHEDRON)
385     {
386       vtkIdType nFaces = 0;
387       vtkIdType* ptIds = 0;
388       grid->GetFaceStream(this->myVtkID, nFaces, ptIds);
389       int id = 0;
390       for (int i = 0; i < nFaces; i++)
391         {
392           int nodesInFace = ptIds[id]; // nodeIds in ptIds[id+1 .. id+nodesInFace]
393           quantities.push_back(nodesInFace);
394           id += (nodesInFace + 1);
395         }
396     }
397   return quantities;
398 }
399
400 SMDS_ElemIteratorPtr SMDS_VtkVolume::elementsIterator(SMDSAbs_ElementType type) const
401 {
402   switch (type)
403   {
404     case SMDSAbs_Node:
405       {
406         SMDSAbs_EntityType aType = this->GetEntityType();
407         if (aType == SMDSEntity_Polyhedra)
408           return SMDS_ElemIteratorPtr(new SMDS_VtkCellIteratorPolyH(SMDS_Mesh::_meshList[myMeshId], myVtkID, aType));
409         else
410           return SMDS_ElemIteratorPtr(new SMDS_VtkCellIterator(SMDS_Mesh::_meshList[myMeshId], myVtkID, aType));
411       }
412     default:
413       MESSAGE("ERROR : Iterator not implemented");
414       return SMDS_ElemIteratorPtr((SMDS_ElemIterator*) NULL);
415   }
416 }
417
418 SMDS_ElemIteratorPtr SMDS_VtkVolume::nodesIteratorToUNV() const
419 {
420   return SMDS_ElemIteratorPtr(new SMDS_VtkCellIteratorToUNV(SMDS_Mesh::_meshList[myMeshId], myVtkID, GetEntityType()));
421 }
422
423 SMDS_ElemIteratorPtr SMDS_VtkVolume::interlacedNodesElemIterator() const
424 {
425   return SMDS_ElemIteratorPtr(new SMDS_VtkCellIteratorToUNV(SMDS_Mesh::_meshList[myMeshId], myVtkID, GetEntityType()));
426 }
427
428 SMDSAbs_ElementType SMDS_VtkVolume::GetType() const
429 {
430   return SMDSAbs_Volume;
431 }
432
433 /*!
434  * \brief Return node by its index
435  * \param ind - node index
436  * \retval const SMDS_MeshNode* - the node
437  */
438 const SMDS_MeshNode* SMDS_VtkVolume::GetNode(const int ind) const
439 {
440   // TODO optimize if possible (vtkCellIterator)
441   return SMDS_MeshElement::GetNode(ind);
442 }
443
444 bool SMDS_VtkVolume::IsQuadratic() const
445 {
446   vtkUnstructuredGrid* grid = SMDS_Mesh::_meshList[myMeshId]->getGrid();
447   vtkIdType aVtkType = grid->GetCellType(this->myVtkID);
448   // TODO quadratic polyhedrons ?
449   switch (aVtkType)
450   {
451     case VTK_QUADRATIC_TETRA:
452     case VTK_QUADRATIC_PYRAMID:
453     case VTK_QUADRATIC_WEDGE:
454     case VTK_QUADRATIC_HEXAHEDRON:
455       return true;
456       break;
457     default:
458       return false;
459   }
460 }
461
462 bool SMDS_VtkVolume::IsPoly() const
463 {
464   vtkUnstructuredGrid* grid = SMDS_Mesh::_meshList[myMeshId]->getGrid();
465   vtkIdType aVtkType = grid->GetCellType(this->myVtkID);
466   return (aVtkType == VTK_POLYHEDRON);
467 }
468
469 bool SMDS_VtkVolume::IsMediumNode(const SMDS_MeshNode* node) const
470 {
471   vtkUnstructuredGrid* grid = SMDS_Mesh::_meshList[myMeshId]->getGrid();
472   vtkIdType aVtkType = grid->GetCellType(this->myVtkID);
473   int rankFirstMedium = 0;
474   switch (aVtkType)
475   {
476     case VTK_QUADRATIC_TETRA:
477       rankFirstMedium = 4; // medium nodes are of rank 4 to 9
478       break;
479     case VTK_QUADRATIC_PYRAMID:
480       rankFirstMedium = 5; // medium nodes are of rank 5 to 12
481       break;
482     case VTK_QUADRATIC_WEDGE:
483       rankFirstMedium = 6; // medium nodes are of rank 6 to 14
484       break;
485     case VTK_QUADRATIC_HEXAHEDRON:
486       rankFirstMedium = 8; // medium nodes are of rank 8 to 19
487       break;
488     default:
489       return false;
490   }
491   vtkIdType npts = 0;
492   vtkIdType* pts = 0;
493   grid->GetCellPoints(myVtkID, npts, pts);
494   vtkIdType nodeId = node->getVtkId();
495   for (int rank = 0; rank < npts; rank++)
496     {
497       if (pts[rank] == nodeId)
498         {
499           if (rank < rankFirstMedium)
500             return false;
501           else
502             return true;
503         }
504     }
505   //throw SALOME_Exception(LOCALIZED("node does not belong to this element"));
506   MESSAGE("======================================================");
507   MESSAGE("= IsMediumNode: node does not belong to this element =");
508   MESSAGE("======================================================");
509   return false;
510 }
511
512 SMDSAbs_EntityType SMDS_VtkVolume::GetEntityType() const
513 {
514   vtkUnstructuredGrid* grid = SMDS_Mesh::_meshList[myMeshId]->getGrid();
515   vtkIdType aVtkType = grid->GetCellType(this->myVtkID);
516
517   SMDSAbs_EntityType aType = SMDSEntity_Tetra;
518   switch (aVtkType)
519   {
520     case VTK_TETRA:
521       aType = SMDSEntity_Tetra;
522       break;
523     case VTK_PYRAMID:
524       aType = SMDSEntity_Pyramid;
525       break;
526     case VTK_WEDGE:
527       aType = SMDSEntity_Penta;
528       break;
529     case VTK_HEXAHEDRON:
530       aType = SMDSEntity_Hexa;
531       break;
532     case VTK_QUADRATIC_TETRA:
533       aType = SMDSEntity_Quad_Tetra;
534       break;
535     case VTK_QUADRATIC_PYRAMID:
536       aType = SMDSEntity_Quad_Pyramid;
537       break;
538     case VTK_QUADRATIC_WEDGE:
539       aType = SMDSEntity_Quad_Penta;
540       break;
541     case VTK_QUADRATIC_HEXAHEDRON:
542       aType = SMDSEntity_Quad_Hexa;
543       break;
544 //#ifdef VTK_HAVE_POLYHEDRON
545     case VTK_POLYHEDRON:
546       aType = SMDSEntity_Polyhedra;
547       break;
548 //#endif
549     default:
550       aType = SMDSEntity_Polyhedra;
551       break;
552   }
553   return aType;
554 }
555
556 vtkIdType SMDS_VtkVolume::GetVtkType() const
557 {
558   vtkUnstructuredGrid* grid = SMDS_Mesh::_meshList[myMeshId]->getGrid();
559   vtkIdType aType = grid->GetCellType(myVtkID);
560   return aType;
561 }
562
563 void SMDS_VtkVolume::gravityCenter(SMDS_UnstructuredGrid* grid, vtkIdType *nodeIds, int nbNodes, double* result)
564 {
565   for (int j = 0; j < 3; j++)
566     result[j] = 0;
567   if (nbNodes <= 0)
568     return;
569   for (int i = 0; i < nbNodes; i++)
570     {
571       double *coords = grid->GetPoint(nodeIds[i]);
572       for (int j = 0; j < 3; j++)
573         result[j] += coords[j];
574     }
575   for (int j = 0; j < 3; j++)
576     result[j] = result[j] / nbNodes;
577   //MESSAGE("center " << result[0] << " " << result[1] << " "  << result[2]);
578   return;
579 }
580
581 bool SMDS_VtkVolume::isForward(double* a, double* b, double* c, double* d)
582 {
583   double u[3], v[3], w[3];
584   for (int j = 0; j < 3; j++)
585     {
586       //MESSAGE("a,b,c,d " << a[j] << " " << b[j] << " " << c[j] << " " << d[j]);
587       u[j] = b[j] - a[j];
588       v[j] = c[j] - a[j];
589       w[j] = d[j] - a[j];
590       //MESSAGE("u,v,w " << u[j] << " " << v[j] << " " << w[j]);
591     }
592   double prodmixte = (u[1]*v[2] - u[2]*v[1]) * w[0]
593                    + (u[2]*v[0] - u[0]*v[2]) * w[1]
594                    + (u[0]*v[1] - u[1]*v[0]) * w[2];
595   return (prodmixte < 0);
596 }
597
598 /*! For polyhedron only
599  *  @return actual number of nodes (not the sum of nodes of all faces)
600  */
601 int SMDS_VtkVolume::NbUniqueNodes() const
602 {
603   vtkUnstructuredGrid* grid = SMDS_Mesh::_meshList[myMeshId]->getGrid();
604   return grid->GetCell(myVtkID)->GetNumberOfPoints();
605 }
606
607 /*! For polyhedron use only
608  *  @return iterator on actual nodes (not through the faces)
609  */
610 SMDS_ElemIteratorPtr SMDS_VtkVolume::uniqueNodesIterator() const
611 {
612   MESSAGE("uniqueNodesIterator");
613   return SMDS_ElemIteratorPtr(new SMDS_VtkCellIterator(SMDS_Mesh::_meshList[myMeshId], myVtkID, GetEntityType()));
614 }