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