Salome HOME
PR: doubleNodesOnGroupBoundaries in progress
[modules/smesh.git] / src / SMDS / SMDS_UnstructuredGrid.cxx
1 #define CHRONODEF
2 #include "SMDS_UnstructuredGrid.hxx"
3 #include "SMDS_Mesh.hxx"
4 #include "SMDS_MeshInfo.hxx"
5 #include "SMDS_Downward.hxx"
6
7 #include "utilities.h"
8
9 #include <vtkCellArray.h>
10 #include <vtkCellLinks.h>
11 #include <vtkIdTypeArray.h>
12 #include <vtkUnsignedCharArray.h>
13
14 #include <list>
15
16 using namespace std;
17
18 SMDS_CellLinks* SMDS_CellLinks::New()
19 {
20   MESSAGE("SMDS_CellLinks::New");
21   return new SMDS_CellLinks();
22 }
23
24 vtkCellLinks::Link* SMDS_CellLinks::ResizeL(vtkIdType sz)
25 {
26   return vtkCellLinks::Resize(sz);
27 }
28
29 vtkIdType SMDS_CellLinks::GetLinksSize()
30 {
31   return this->Size;
32 }
33
34 SMDS_CellLinks::SMDS_CellLinks() :
35   vtkCellLinks()
36 {
37 }
38
39 SMDS_CellLinks::~SMDS_CellLinks()
40 {
41 }
42
43 SMDS_UnstructuredGrid* SMDS_UnstructuredGrid::New()
44 {
45   MESSAGE("SMDS_UnstructuredGrid::New");
46   return new SMDS_UnstructuredGrid();
47 }
48
49 SMDS_UnstructuredGrid::SMDS_UnstructuredGrid() :
50   vtkUnstructuredGrid()
51 {
52   _cellIdToDownId.clear();
53   _downTypes.clear();
54   _downArray.clear();
55   _mesh = 0;
56 }
57
58 SMDS_UnstructuredGrid::~SMDS_UnstructuredGrid()
59 {
60 }
61
62 unsigned long SMDS_UnstructuredGrid::GetMTime()
63 {
64   unsigned long mtime = vtkUnstructuredGrid::GetMTime();
65   MESSAGE("vtkUnstructuredGrid::GetMTime: " << mtime);
66   return mtime;
67 }
68
69 void SMDS_UnstructuredGrid::Update()
70 {
71   MESSAGE("SMDS_UnstructuredGrid::Update");
72   return vtkUnstructuredGrid::Update();
73 }
74
75 void SMDS_UnstructuredGrid::UpdateInformation()
76 {
77   MESSAGE("SMDS_UnstructuredGrid::UpdateInformation");
78   return vtkUnstructuredGrid::UpdateInformation();
79 }
80
81 vtkPoints* SMDS_UnstructuredGrid::GetPoints()
82 {
83   // TODO erreur incomprehensible de la macro vtk GetPoints apparue avec la version paraview de fin aout 2010
84   //MESSAGE("*********************** SMDS_UnstructuredGrid::GetPoints " << this->Points << " " << vtkUnstructuredGrid::GetPoints());
85   return this->Points;
86 }
87
88 //#ifdef VTK_HAVE_POLYHEDRON
89 int SMDS_UnstructuredGrid::InsertNextLinkedCell(int type, int npts, vtkIdType *pts)
90 {
91   if (type != VTK_POLYHEDRON)
92     return vtkUnstructuredGrid::InsertNextLinkedCell(type, npts, pts);
93
94   // --- type = VTK_POLYHEDRON
95   //MESSAGE("InsertNextLinkedCell VTK_POLYHEDRON");
96   int cellid = this->InsertNextCell(type, npts, pts);
97
98   set<vtkIdType> setOfNodes;
99   setOfNodes.clear();
100   int nbfaces = npts;
101   int i = 0;
102   for (int nf = 0; nf < nbfaces; nf++)
103     {
104       int nbnodes = pts[i];
105       i++;
106       for (int k = 0; k < nbnodes; k++)
107         {
108           //MESSAGE(" cell " << cellid << " face " << nf << " node " << pts[i]);
109           setOfNodes.insert(pts[i]);
110           i++;
111         }
112     }
113
114   set<vtkIdType>::iterator it = setOfNodes.begin();
115   for (; it != setOfNodes.end(); ++it)
116     {
117       //MESSAGE("reverse link for node " << *it << " cell " << cellid);
118       this->Links->ResizeCellList(*it, 1);
119       this->Links->AddCellReference(cellid, *it);
120     }
121
122   return cellid;
123 }
124 //#endif
125
126 void SMDS_UnstructuredGrid::setSMDS_mesh(SMDS_Mesh *mesh)
127 {
128   _mesh = mesh;
129 }
130
131 void SMDS_UnstructuredGrid::compactGrid(std::vector<int>& idNodesOldToNew, int newNodeSize,
132                                         std::vector<int>& idCellsOldToNew, int newCellSize)
133 {
134   // TODO utiliser mieux vtk pour faire plus simple (plus couteux ?)
135
136   MESSAGE("------------------------- SMDS_UnstructuredGrid::compactGrid " << newNodeSize << " " << newCellSize);CHRONO(1);
137   int alreadyCopied = 0;
138
139   //    if (this->Links)
140   //    {
141   //            this->Links->UnRegister(this);
142   //            this->Links = 0;
143   //    }
144
145   // --- if newNodeSize, create a new compacted vtkPoints
146
147   vtkPoints *newPoints = vtkPoints::New();
148   newPoints->SetDataType(VTK_DOUBLE);
149   newPoints->SetNumberOfPoints(newNodeSize);
150   if (newNodeSize)
151     {
152       MESSAGE("-------------- compactGrid, newNodeSize " << newNodeSize);
153       // rnv: to fix bug "21125: EDF 1233 SMESH: Degrardation of precision in a test case for quadratic conversion"
154       // using double type for storing coordinates of nodes instead float.
155       int oldNodeSize = idNodesOldToNew.size();
156
157       int i = 0;
158       while ( i < oldNodeSize )
159       {
160         // skip a hole if any
161         while ( i < oldNodeSize && idNodesOldToNew[i] < 0 )
162           ++i;
163         int startBloc = i;
164         // look for a block end
165         while ( i < oldNodeSize && idNodesOldToNew[i] >= 0 )
166           ++i;
167         int endBloc = i;
168         copyNodes(newPoints, idNodesOldToNew, alreadyCopied, startBloc, endBloc);
169       }
170 //       for (int i = 0; i < oldNodeSize; i++)
171 //         {
172 //           //MESSAGE("                                    " << i << " " << idNodesOldToNew[i]);
173 //           switch (compactState)
174 //           {
175 //             case lookHoleStart:
176 //               if (idNodesOldToNew[i] < 0)
177 //                 {
178 //                   MESSAGE("-------------- newNodeSize, startHole " << i << " " << oldNodeSize);
179 //                   startHole = i;
180 //                   if (!alreadyCopied) // copy the first bloc
181 //                     {
182 //                       MESSAGE("--------- copy first nodes before hole " << i << " " << oldNodeSize);
183 //                       copyNodes(newPoints, idNodesOldToNew, alreadyCopied, 0, startHole);
184 //                     }
185 //                   compactState = lookHoleEnd;
186 //                 }
187 //               break;
188 //             case lookHoleEnd:
189 //               if (idNodesOldToNew[i] >= 0)
190 //                 {
191 //                   MESSAGE("-------------- newNodeSize, endHole " << i << " " << oldNodeSize);
192 //                   endHole = i;
193 //                   startBloc = i;
194 //                   compactState = lookBlocEnd;
195 //                 }
196 //               break;
197 //             case lookBlocEnd:
198 //               if (idNodesOldToNew[i] < 0)
199 //                 endBloc = i; // see nbPoints below
200 //               else if (i == (oldNodeSize - 1))
201 //                 endBloc = i + 1;
202 //               if (endBloc)
203 //                 {
204 //                   MESSAGE("-------------- newNodeSize, endbloc " << endBloc << " " << oldNodeSize);
205 //                   copyNodes(newPoints, idNodesOldToNew, alreadyCopied, startBloc, endBloc);
206 //                   compactState = lookHoleEnd;
207 //                   startHole = i;
208 //                   endHole = 0;
209 //                   startBloc = 0;
210 //                   endBloc = 0;
211 //                 }
212 //               break;
213 //           }
214 //         }
215 //       if (!alreadyCopied) // no hole, but shorter, no need to modify idNodesOldToNew
216 //         {
217 //           MESSAGE("------------- newNodeSize, shorter " << oldNodeSize);
218 //           copyNodes(newPoints, idNodesOldToNew, alreadyCopied, 0, newNodeSize);
219 //         }
220       newPoints->Squeeze();
221     }
222
223   // --- create new compacted Connectivity, Locations and Types
224
225   int oldCellSize = this->Types->GetNumberOfTuples();
226
227   vtkCellArray *newConnectivity = vtkCellArray::New();
228   newConnectivity->Initialize();
229   int oldCellDataSize = this->Connectivity->GetData()->GetSize();
230   newConnectivity->Allocate(oldCellDataSize);
231   MESSAGE("oldCellSize="<< oldCellSize << " oldCellDataSize=" << oldCellDataSize);
232
233   vtkUnsignedCharArray *newTypes = vtkUnsignedCharArray::New();
234   newTypes->Initialize();
235   newTypes->SetNumberOfValues(newCellSize);
236
237   vtkIdTypeArray *newLocations = vtkIdTypeArray::New();
238   newLocations->Initialize();
239   newLocations->SetNumberOfValues(newCellSize);
240
241   // TODO some polyhedron may be huge (only in some tests)
242   vtkIdType tmpid[NBMAXNODESINCELL];
243   vtkIdType *pointsCell = &tmpid[0]; // --- points id to fill a new cell
244
245   alreadyCopied = 0;
246   int i = 0;
247   while ( i < oldCellSize )
248   {
249     // skip a hole if any
250     while ( i < oldCellSize && this->Types->GetValue(i) == VTK_EMPTY_CELL )
251       ++i;
252     int startBloc = i;
253     // look for a block end
254     while ( i < oldCellSize && this->Types->GetValue(i) != VTK_EMPTY_CELL )
255       ++i;
256     int endBloc = i;
257     if ( endBloc > startBloc )
258       copyBloc(newTypes, idCellsOldToNew, idNodesOldToNew, newConnectivity, newLocations, pointsCell,
259                alreadyCopied, startBloc, endBloc);
260   }
261 //   for (int i = 0; i < oldCellSize; i++)
262 //     {
263 //       switch (compactState)
264 //       {
265 //         case lookHoleStart:
266 //           if (this->Types->GetValue(i) == VTK_EMPTY_CELL)
267 //             {
268 //               MESSAGE(" -------- newCellSize, startHole " << i << " " << oldCellSize);
269 //               startHole = i;
270 //               compactState = lookHoleEnd;
271 //               if (!alreadyCopied) // copy the first bloc
272 //                 {
273 //                   MESSAGE("--------- copy first bloc before hole " << i << " " << oldCellSize);
274 //                   copyBloc(newTypes, idCellsOldToNew, idNodesOldToNew, newConnectivity, newLocations, pointsCell,
275 //                            alreadyCopied, 0, startHole);
276 //                 }
277 //             }
278 //           break;
279 //         case lookHoleEnd:
280 //           if (this->Types->GetValue(i) != VTK_EMPTY_CELL)
281 //             {
282 //               MESSAGE(" -------- newCellSize, EndHole " << i << " " << oldCellSize);
283 //               endHole = i;
284 //               startBloc = i;
285 //               compactState = lookBlocEnd;
286 //               holes += endHole - startHole;
287 //             }
288 //           break;
289 //         case lookBlocEnd:
290 //           endBloc = 0;
291 //           if (this->Types->GetValue(i) == VTK_EMPTY_CELL)
292 //             endBloc = i;
293 //           else if (i == (oldCellSize - 1))
294 //             endBloc = i + 1;
295 //           if (endBloc)
296 //             {
297 //               MESSAGE(" -------- newCellSize, endBloc " << endBloc << " " << oldCellSize);
298 //               copyBloc(newTypes, idCellsOldToNew, idNodesOldToNew, newConnectivity, newLocations, pointsCell,
299 //                        alreadyCopied, startBloc, endBloc);
300 //               compactState = lookHoleEnd;
301 //             }
302 //           break;
303 //       }
304 //     }
305 //   if (!alreadyCopied) // no hole, but shorter
306 //     {
307 //       MESSAGE(" -------- newCellSize, shorter " << oldCellSize);
308 //       copyBloc(newTypes, idCellsOldToNew, idNodesOldToNew, newConnectivity, newLocations, pointsCell, alreadyCopied, 0,
309 //                oldCellSize);
310 //     }
311
312   newConnectivity->Squeeze();
313   //newTypes->Squeeze();
314   //newLocations->Squeeze();
315
316   if (1/*newNodeSize*/)
317     {
318       MESSAGE("------- newNodeSize, setPoints");
319       this->SetPoints(newPoints);
320       MESSAGE("NumberOfPoints: " << this->GetNumberOfPoints());
321     }
322
323   if (this->FaceLocations)
324     {
325       vtkIdTypeArray *newFaceLocations = vtkIdTypeArray::New();
326       newFaceLocations->Initialize();
327       newFaceLocations->Allocate(newTypes->GetSize());
328       vtkIdTypeArray *newFaces = vtkIdTypeArray::New();
329       newFaces->Initialize();
330       newFaces->Allocate(this->Faces->GetSize());
331       for (int i = 0; i < oldCellSize; i++)
332         {
333           if (this->Types->GetValue(i) == VTK_EMPTY_CELL)
334             continue;
335           int newCellId = idCellsOldToNew[i];
336           if (newTypes->GetValue(newCellId) == VTK_POLYHEDRON)
337             {
338                newFaceLocations->InsertNextValue(newFaces->GetMaxId()+1);
339                int oldFaceLoc = this->FaceLocations->GetValue(i);
340                int nCellFaces = this->Faces->GetValue(oldFaceLoc++);
341                newFaces->InsertNextValue(nCellFaces);
342                for (int n=0; n<nCellFaces; n++)
343                  {
344                    int nptsInFace = this->Faces->GetValue(oldFaceLoc++);
345                    newFaces->InsertNextValue(nptsInFace);
346                    for (int k=0; k<nptsInFace; k++)
347                      {
348                        int oldpt = this->Faces->GetValue(oldFaceLoc++);
349                        newFaces->InsertNextValue(idNodesOldToNew[oldpt]);
350                      }
351                  }
352             }
353           else
354             {
355                newFaceLocations->InsertNextValue(-1);
356             }
357         }
358       newFaceLocations->Squeeze();
359       newFaces->Squeeze();
360       newFaceLocations->Register(this);
361       newFaces->Register(this);
362       this->SetCells(newTypes, newLocations, newConnectivity, newFaceLocations, newFaces);
363       newFaceLocations->Delete();
364       newFaces->Delete();
365     }
366   else
367     this->SetCells(newTypes, newLocations, newConnectivity, FaceLocations, Faces);
368
369   newPoints->Delete();
370   newTypes->Delete();
371   newLocations->Delete();
372   newConnectivity->Delete();
373   this->BuildLinks();
374 }
375
376 void SMDS_UnstructuredGrid::copyNodes(vtkPoints *newPoints, std::vector<int>& idNodesOldToNew, int& alreadyCopied,
377                                       int start, int end)
378 {
379   MESSAGE("copyNodes " << alreadyCopied << " " << start << " " << end << " size: " << end - start << " total: " << alreadyCopied + end - start);
380   void *target = newPoints->GetVoidPointer(3 * alreadyCopied);
381   void *source = this->Points->GetVoidPointer(3 * start);
382   int nbPoints = end - start;
383   if (nbPoints > 0)
384     {
385       memcpy(target, source, 3 * sizeof(double) * nbPoints);
386       for (int j = start; j < end; j++)
387         idNodesOldToNew[j] = alreadyCopied++; // old vtkId --> new vtkId
388         //idNodesOldToNew[alreadyCopied++] = idNodesOldToNew[j]; // new vtkId --> old SMDS id
389     }
390 }
391
392 void SMDS_UnstructuredGrid::copyBloc(vtkUnsignedCharArray *newTypes, std::vector<int>& idCellsOldToNew,
393                                      std::vector<int>& idNodesOldToNew, vtkCellArray* newConnectivity,
394                                      vtkIdTypeArray* newLocations, vtkIdType* pointsCell, int& alreadyCopied,
395                                      int start, int end)
396 {
397   MESSAGE("copyBloc " << alreadyCopied << " " << start << " " << end << " size: " << end - start << " total: " << alreadyCopied + end - start);
398   for (int j = start; j < end; j++)
399     {
400       newTypes->SetValue(alreadyCopied, this->Types->GetValue(j));
401       idCellsOldToNew[j] = alreadyCopied; // old vtkId --> new vtkId
402       vtkIdType oldLoc = this->Locations->GetValue(j);
403       vtkIdType nbpts;
404       vtkIdType *oldPtsCell = 0;
405       this->Connectivity->GetCell(oldLoc, nbpts, oldPtsCell);
406       assert(nbpts < NBMAXNODESINCELL);
407       //MESSAGE(j << " " << alreadyCopied << " " << (int)this->Types->GetValue(j) << " " << oldLoc << " " << nbpts );
408       for (int l = 0; l < nbpts; l++)
409         {
410           int oldval = oldPtsCell[l];
411           pointsCell[l] = idNodesOldToNew[oldval];
412           //MESSAGE("   " << oldval << " " << pointsCell[l]);
413         }
414       /*int newcnt = */newConnectivity->InsertNextCell(nbpts, pointsCell);
415       int newLoc = newConnectivity->GetInsertLocation(nbpts);
416       //MESSAGE(newcnt << " " << newLoc);
417       newLocations->SetValue(alreadyCopied, newLoc);
418       alreadyCopied++;
419     }
420 }
421
422 int SMDS_UnstructuredGrid::CellIdToDownId(int vtkCellId)
423 {
424   // ASSERT((vtkCellId >= 0) && (vtkCellId < _cellIdToDownId.size()));
425   return _cellIdToDownId[vtkCellId];
426 }
427
428 void SMDS_UnstructuredGrid::setCellIdToDownId(int vtkCellId, int downId)
429 {
430   // ASSERT((vtkCellId >= 0) && (vtkCellId < _cellIdToDownId.size()));
431   _cellIdToDownId[vtkCellId] = downId;
432 }
433
434 /*! Build downward connectivity: to do only when needed because heavy memory load.
435  *  Downward connectivity is no more valid if vtkUnstructuredGrid is modified.
436  *
437  */
438 void SMDS_UnstructuredGrid::BuildDownwardConnectivity(bool withEdges)
439 {
440   MESSAGE("SMDS_UnstructuredGrid::BuildDownwardConnectivity");CHRONO(2);
441   // TODO calcul partiel sans edges
442
443   // --- erase previous data if any
444
445   for (int i = 0; i < _downArray.size(); i++)
446     {
447       if (_downArray[i])
448         delete _downArray[i];
449       _downArray[i] = 0;
450     }
451   _cellIdToDownId.clear();
452
453   // --- create SMDS_Downward structures (in _downArray vector[vtkCellType])
454
455   _downArray.resize(VTK_MAXTYPE + 1, 0); // --- max. type value = VTK_QUADRATIC_PYRAMID
456
457   _downArray[VTK_LINE] = new SMDS_DownEdge(this);
458   _downArray[VTK_QUADRATIC_EDGE] = new SMDS_DownQuadEdge(this);
459   _downArray[VTK_TRIANGLE] = new SMDS_DownTriangle(this);
460   _downArray[VTK_QUADRATIC_TRIANGLE] = new SMDS_DownQuadTriangle(this);
461   _downArray[VTK_QUAD] = new SMDS_DownQuadrangle(this);
462   _downArray[VTK_QUADRATIC_QUAD] = new SMDS_DownQuadQuadrangle(this);
463   _downArray[VTK_TETRA] = new SMDS_DownTetra(this);
464   _downArray[VTK_QUADRATIC_TETRA] = new SMDS_DownQuadTetra(this);
465   _downArray[VTK_PYRAMID] = new SMDS_DownPyramid(this);
466   _downArray[VTK_QUADRATIC_PYRAMID] = new SMDS_DownQuadPyramid(this);
467   _downArray[VTK_WEDGE] = new SMDS_DownPenta(this);
468   _downArray[VTK_QUADRATIC_WEDGE] = new SMDS_DownQuadPenta(this);
469   _downArray[VTK_HEXAHEDRON] = new SMDS_DownHexa(this);
470   _downArray[VTK_QUADRATIC_HEXAHEDRON] = new SMDS_DownQuadHexa(this);
471
472   // --- get detailed info of number of cells of each type, allocate SMDS_downward structures
473
474   const SMDS_MeshInfo &meshInfo = _mesh->GetMeshInfo();
475
476   int nbLinTetra = meshInfo.NbTetras(ORDER_LINEAR);
477   int nbQuadTetra = meshInfo.NbTetras(ORDER_QUADRATIC);
478   int nbLinPyra = meshInfo.NbPyramids(ORDER_LINEAR);
479   int nbQuadPyra = meshInfo.NbPyramids(ORDER_QUADRATIC);
480   int nbLinPrism = meshInfo.NbPrisms(ORDER_LINEAR);
481   int nbQuadPrism = meshInfo.NbPrisms(ORDER_QUADRATIC);
482   int nbLinHexa = meshInfo.NbHexas(ORDER_LINEAR);
483   int nbQuadHexa = meshInfo.NbHexas(ORDER_QUADRATIC);
484
485   int nbLineGuess = int((4.0 / 3.0) * nbLinTetra + 2 * nbLinPrism + 2.5 * nbLinPyra + 3 * nbLinHexa);
486   int nbQuadEdgeGuess = int((4.0 / 3.0) * nbQuadTetra + 2 * nbQuadPrism + 2.5 * nbQuadPyra + 3 * nbQuadHexa);
487   int nbLinTriaGuess = 2 * nbLinTetra + nbLinPrism + 2 * nbLinPyra;
488   int nbQuadTriaGuess = 2 * nbQuadTetra + nbQuadPrism + 2 * nbQuadPyra;
489   int nbLinQuadGuess = int((2.0 / 3.0) * nbLinPrism + (1.0 / 2.0) * nbLinPyra + 3 * nbLinHexa);
490   int nbQuadQuadGuess = int((2.0 / 3.0) * nbQuadPrism + (1.0 / 2.0) * nbQuadPyra + 3 * nbQuadHexa);
491
492   int GuessSize[VTK_QUADRATIC_TETRA];
493   GuessSize[VTK_LINE] = nbLineGuess;
494   GuessSize[VTK_QUADRATIC_EDGE] = nbQuadEdgeGuess;
495   GuessSize[VTK_TRIANGLE] = nbLinTriaGuess;
496   GuessSize[VTK_QUADRATIC_TRIANGLE] = nbQuadTriaGuess;
497   GuessSize[VTK_QUAD] = nbLinQuadGuess;
498   GuessSize[VTK_QUADRATIC_QUAD] = nbQuadQuadGuess;
499   GuessSize[VTK_TETRA] = nbLinTetra;
500   GuessSize[VTK_QUADRATIC_TETRA] = nbQuadTetra;
501   GuessSize[VTK_PYRAMID] = nbLinPyra;
502   GuessSize[VTK_QUADRATIC_PYRAMID] = nbQuadPyra;
503   GuessSize[VTK_WEDGE] = nbLinPrism;
504   GuessSize[VTK_QUADRATIC_WEDGE] = nbQuadPrism;
505   GuessSize[VTK_HEXAHEDRON] = nbLinHexa;
506   GuessSize[VTK_QUADRATIC_HEXAHEDRON] = nbQuadHexa;
507
508   _downArray[VTK_LINE]->allocate(nbLineGuess);
509   _downArray[VTK_QUADRATIC_EDGE]->allocate(nbQuadEdgeGuess);
510   _downArray[VTK_TRIANGLE]->allocate(nbLinTriaGuess);
511   _downArray[VTK_QUADRATIC_TRIANGLE]->allocate(nbQuadTriaGuess);
512   _downArray[VTK_QUAD]->allocate(nbLinQuadGuess);
513   _downArray[VTK_QUADRATIC_QUAD]->allocate(nbQuadQuadGuess);
514   _downArray[VTK_TETRA]->allocate(nbLinTetra);
515   _downArray[VTK_QUADRATIC_TETRA]->allocate(nbQuadTetra);
516   _downArray[VTK_PYRAMID]->allocate(nbLinPyra);
517   _downArray[VTK_QUADRATIC_PYRAMID]->allocate(nbQuadPyra);
518   _downArray[VTK_WEDGE]->allocate(nbLinPrism);
519   _downArray[VTK_QUADRATIC_WEDGE]->allocate(nbQuadPrism);
520   _downArray[VTK_HEXAHEDRON]->allocate(nbLinHexa);
521   _downArray[VTK_QUADRATIC_HEXAHEDRON]->allocate(nbQuadHexa);
522
523   // --- iteration on vtkUnstructuredGrid cells, only faces
524   //     for each vtk face:
525   //       create a downward face entry with its downward id.
526   //       compute vtk volumes, create downward volumes entry.
527   //       mark face in downward volumes
528   //       mark volumes in downward face
529
530   MESSAGE("--- iteration on vtkUnstructuredGrid cells, only faces");CHRONO(20);
531   int cellSize = this->Types->GetNumberOfTuples();
532   _cellIdToDownId.resize(cellSize, -1);
533
534   for (int i = 0; i < cellSize; i++)
535     {
536       int vtkFaceType = this->GetCellType(i);
537       if (SMDS_Downward::getCellDimension(vtkFaceType) == 2)
538         {
539           int vtkFaceId = i;
540           //ASSERT(_downArray[vtkFaceType]);
541           int connFaceId = _downArray[vtkFaceType]->addCell(vtkFaceId);
542           SMDS_Down2D* downFace = static_cast<SMDS_Down2D*> (_downArray[vtkFaceType]);
543           downFace->setTempNodes(connFaceId, vtkFaceId);
544           int vols[2] = { -1, -1 };
545           int nbVolumes = downFace->computeVolumeIds(vtkFaceId, vols);
546           //MESSAGE("nbVolumes="<< nbVolumes);
547           for (int ivol = 0; ivol < nbVolumes; ivol++)
548             {
549               int vtkVolId = vols[ivol];
550               int vtkVolType = this->GetCellType(vtkVolId);
551               //ASSERT(_downArray[vtkVolType]);
552               int connVolId = _downArray[vtkVolType]->addCell(vtkVolId);
553               _downArray[vtkVolType]->addDownCell(connVolId, connFaceId, vtkFaceType);
554               _downArray[vtkFaceType]->addUpCell(connFaceId, connVolId, vtkVolType);
555               // MESSAGE("Face " << vtkFaceId << " belongs to volume " << vtkVolId);
556             }
557         }
558     }
559
560   // --- iteration on vtkUnstructuredGrid cells, only volumes
561   //     for each vtk volume:
562   //       create downward volumes entry if not already done
563   //       build a temporary list of faces described with their nodes
564   //       for each face
565   //         compute the vtk volumes containing this face
566   //         check if the face is already listed in the volumes (comparison of ordered list of nodes)
567   //         if not, create a downward face entry (resizing of structure required)
568   //         (the downward faces store a temporary list of nodes to ease the comparison)
569   //         create downward volumes entry if not already done
570   //         mark volumes in downward face
571   //         mark face in downward volumes
572
573   CHRONOSTOP(20);
574   MESSAGE("--- iteration on vtkUnstructuredGrid cells, only volumes");CHRONO(21);
575
576   for (int i = 0; i < cellSize; i++)
577     {
578       int vtkType = this->GetCellType(i);
579       if (SMDS_Downward::getCellDimension(vtkType) == 3)
580         {
581           //CHRONO(31);
582           int vtkVolId = i;
583           // MESSAGE("vtk volume " << vtkVolId);
584           //ASSERT(_downArray[vtkType]);
585           /*int connVolId = */_downArray[vtkType]->addCell(vtkVolId);
586
587           // --- find all the faces of the volume, describe the faces by their nodes
588
589           SMDS_Down3D* downVol = static_cast<SMDS_Down3D*> (_downArray[vtkType]);
590           ListElemByNodesType facesWithNodes;
591           downVol->computeFacesWithNodes(vtkVolId, facesWithNodes);
592           // MESSAGE("vtk volume " << vtkVolId << " contains " << facesWithNodes.nbElems << " faces");
593           //CHRONOSTOP(31);
594           for (int iface = 0; iface < facesWithNodes.nbElems; iface++)
595             {
596               // --- find the volumes containing the face
597
598               //CHRONO(32);
599               int vtkFaceType = facesWithNodes.elems[iface].vtkType;
600               SMDS_Down2D* downFace = static_cast<SMDS_Down2D*> (_downArray[vtkFaceType]);
601               int vols[2] = { -1, -1 };
602               int *nodes = &facesWithNodes.elems[iface].nodeIds[0];
603               int lg = facesWithNodes.elems[iface].nbNodes;
604               int nbVolumes = downFace->computeVolumeIdsFromNodesFace(nodes, lg, vols);
605               // MESSAGE("vtk volume " << vtkVolId << " face " << iface << " belongs to " << nbVolumes << " volumes");
606
607               // --- check if face is registered in the volumes
608               //CHRONOSTOP(32);
609
610               //CHRONO(33);
611               int connFaceId = -1;
612               for (int ivol = 0; ivol < nbVolumes; ivol++)
613                 {
614                   int vtkVolId2 = vols[ivol];
615                   int vtkVolType = this->GetCellType(vtkVolId2);
616                   //ASSERT(_downArray[vtkVolType]);
617                   int connVolId2 = _downArray[vtkVolType]->addCell(vtkVolId2);
618                   SMDS_Down3D* downVol2 = static_cast<SMDS_Down3D*> (_downArray[vtkVolType]);
619                   connFaceId = downVol2->FindFaceByNodes(connVolId2, facesWithNodes.elems[iface]);
620                   if (connFaceId >= 0)
621                     break; // --- face already created
622                 }//CHRONOSTOP(33);
623
624               // --- if face is not registered in the volumes, create face
625
626               //CHRONO(34);
627               if (connFaceId < 0)
628                 {
629                   connFaceId = _downArray[vtkFaceType]->addCell();
630                   downFace->setTempNodes(connFaceId, facesWithNodes.elems[iface]);
631                 }//CHRONOSTOP(34);
632
633               // --- mark volumes in downward face and mark face in downward volumes
634
635               //CHRONO(35);
636               for (int ivol = 0; ivol < nbVolumes; ivol++)
637                 {
638                   int vtkVolId2 = vols[ivol];
639                   int vtkVolType = this->GetCellType(vtkVolId2);
640                   //ASSERT(_downArray[vtkVolType]);
641                   int connVolId2 = _downArray[vtkVolType]->addCell(vtkVolId2);
642                   _downArray[vtkVolType]->addDownCell(connVolId2, connFaceId, vtkFaceType);
643                   _downArray[vtkFaceType]->addUpCell(connFaceId, connVolId2, vtkVolType);
644                   // MESSAGE(" From volume " << vtkVolId << " face " << connFaceId << " belongs to volume " << vtkVolId2);
645                 }//CHRONOSTOP(35);
646             }
647         }
648     }
649
650   // --- iteration on vtkUnstructuredGrid cells, only edges
651   //     for each vtk edge:
652   //       create downward edge entry
653   //       store the nodes id's in downward edge (redundant with vtkUnstructuredGrid)
654   //       find downward faces
655   //       (from vtk faces or volumes, get downward faces, they have a temporary list of nodes)
656   //       mark edge in downward faces
657   //       mark faces in downward edge
658
659   CHRONOSTOP(21);
660   MESSAGE("--- iteration on vtkUnstructuredGrid cells, only edges");CHRONO(22);
661
662   for (int i = 0; i < cellSize; i++)
663     {
664       int vtkEdgeType = this->GetCellType(i);
665       if (SMDS_Downward::getCellDimension(vtkEdgeType) == 1)
666         {
667           int vtkEdgeId = i;
668           //ASSERT(_downArray[vtkEdgeType]);
669           int connEdgeId = _downArray[vtkEdgeType]->addCell(vtkEdgeId);
670           SMDS_Down1D* downEdge = static_cast<SMDS_Down1D*> (_downArray[vtkEdgeType]);
671           downEdge->setNodes(connEdgeId, vtkEdgeId);
672           vector<int> vtkIds;
673           int nbVtkCells = downEdge->computeVtkCells(connEdgeId, vtkIds);
674           int downFaces[1000];
675           unsigned char downTypes[1000];
676           int nbDownFaces = downEdge->computeFaces(connEdgeId, &vtkIds[0], nbVtkCells, downFaces, downTypes);
677           for (int n = 0; n < nbDownFaces; n++)
678             {
679               _downArray[downTypes[n]]->addDownCell(downFaces[n], connEdgeId, vtkEdgeType);
680               _downArray[vtkEdgeType]->addUpCell(connEdgeId, downFaces[n], downTypes[n]);
681             }
682         }
683     }
684
685   // --- iteration on downward faces (they are all listed now)
686   //     for each downward face:
687   //       build a temporary list of edges with their ordered list of nodes
688   //       for each edge:
689   //         find all the vtk cells containing this edge
690   //         then identify all the downward faces containing the edge, from the vtk cells
691   //         check if the edge is already listed in the faces (comparison of ordered list of nodes)
692   //         if not, create a downward edge entry with the node id's
693   //         mark edge in downward faces
694   //         mark downward faces in edge (size of list unknown, to be allocated)
695
696   CHRONOSTOP(22);CHRONO(23);
697
698   for (int vtkFaceType = 0; vtkFaceType < VTK_QUADRATIC_PYRAMID; vtkFaceType++)
699     {
700       if (SMDS_Downward::getCellDimension(vtkFaceType) != 2)
701         continue;
702
703       // --- find all the edges of the face, describe the edges by their nodes
704
705       SMDS_Down2D* downFace = static_cast<SMDS_Down2D*> (_downArray[vtkFaceType]);
706       int maxId = downFace->getMaxId();
707       for (int faceId = 0; faceId < maxId; faceId++)
708         {
709           //CHRONO(40);
710           ListElemByNodesType edgesWithNodes;
711           downFace->computeEdgesWithNodes(faceId, edgesWithNodes);
712           // MESSAGE("downward face type " << vtkFaceType << " num " << faceId << " contains " << edgesWithNodes.nbElems << " edges");
713
714           //CHRONOSTOP(40);
715           for (int iedge = 0; iedge < edgesWithNodes.nbElems; iedge++)
716             {
717
718               // --- check if the edge is already registered by exploration of the faces
719
720               //CHRONO(41);
721               vector<int> vtkIds;
722               unsigned char vtkEdgeType = edgesWithNodes.elems[iedge].vtkType;
723               int *pts = &edgesWithNodes.elems[iedge].nodeIds[0];
724               SMDS_Down1D* downEdge = static_cast<SMDS_Down1D*> (_downArray[vtkEdgeType]);
725               int nbVtkCells = downEdge->computeVtkCells(pts, vtkIds);
726               //CHRONOSTOP(41);CHRONO(42);
727               int downFaces[1000];
728               unsigned char downTypes[1000];
729               int nbDownFaces = downEdge->computeFaces(pts, &vtkIds[0], nbVtkCells, downFaces, downTypes);
730               //CHRONOSTOP(42);
731
732               //CHRONO(43);
733               int connEdgeId = -1;
734               for (int idf = 0; idf < nbDownFaces; idf++)
735                 {
736                   int faceId2 = downFaces[idf];
737                   int faceType = downTypes[idf];
738                   //ASSERT(_downArray[faceType]);
739                   SMDS_Down2D* downFace2 = static_cast<SMDS_Down2D*> (_downArray[faceType]);
740                   connEdgeId = downFace2->FindEdgeByNodes(faceId2, edgesWithNodes.elems[iedge]);
741                   if (connEdgeId >= 0)
742                     break; // --- edge already created
743                 }//CHRONOSTOP(43);
744
745               // --- if edge is not registered in the faces, create edge
746
747               if (connEdgeId < 0)
748                 {
749                   //CHRONO(44);
750                   connEdgeId = _downArray[vtkEdgeType]->addCell();
751                   downEdge->setNodes(connEdgeId, edgesWithNodes.elems[iedge].nodeIds);
752                   //CHRONOSTOP(44);
753                 }
754
755               // --- mark faces in downward edge and mark edge in downward faces
756
757               //CHRONO(45);
758               for (int idf = 0; idf < nbDownFaces; idf++)
759                 {
760                   int faceId2 = downFaces[idf];
761                   int faceType = downTypes[idf];
762                   //ASSERT(_downArray[faceType]);
763                   //SMDS_Down2D* downFace2 = static_cast<SMDS_Down2D*> (_downArray[faceType]);
764                   _downArray[vtkEdgeType]->addUpCell(connEdgeId, faceId2, faceType);
765                   _downArray[faceType]->addDownCell(faceId2, connEdgeId, vtkEdgeType);
766                   // MESSAGE(" From face t:" << vtkFaceType << " " << faceId <<
767                   //  " edge " << connEdgeId << " belongs to face t:" << faceType << " " << faceId2);
768                 }//CHRONOSTOP(45);
769             }
770         }
771     }
772
773   CHRONOSTOP(23);CHRONO(24);
774
775   // compact downward connectivity structure: adjust downward arrays size, replace vector<vector int>> by a single vector<int>
776   // 3D first then 2D and last 1D to release memory before edge upCells reorganization, (temporary memory use)
777
778   for (int vtkType = VTK_QUADRATIC_PYRAMID; vtkType >= 0; vtkType--)
779     {
780       if (SMDS_Downward *down = _downArray[vtkType])
781         {
782           down->compactStorage();
783         }
784     }
785
786   // --- Statistics
787
788   for (int vtkType = 0; vtkType <= VTK_QUADRATIC_PYRAMID; vtkType++)
789     {
790       if (SMDS_Downward *down = _downArray[vtkType])
791         {
792           if (down->getMaxId())
793             {
794               MESSAGE("Cells of Type " << vtkType << " : number of entities, est: "
795                   << GuessSize[vtkType] << " real: " << down->getMaxId());
796             }
797         }
798     }CHRONOSTOP(24);CHRONOSTOP(2);
799   counters::stats();
800 }
801
802 /*! Get the neighbors of a cell.
803  * Only the neighbors having the dimension of the cell are taken into account
804  * (neighbors of a volume are the volumes sharing a face with this volume,
805  *  neighbors of a face are the faces sharing an edge with this face...).
806  * @param neighborsVtkIds vector of neighbors vtk id's to fill (reserve enough space).
807  * @param downIds downward id's of cells of dimension n-1, to fill (reserve enough space).
808  * @param downTypes vtk types of cells of dimension n-1, to fill (reserve enough space).
809  * @param vtkId the vtk id of the cell
810  * @return number of neighbors
811  */
812 int SMDS_UnstructuredGrid::GetNeighbors(int* neighborsVtkIds, int* downIds, unsigned char* downTypes, int vtkId)
813 {
814   int vtkType = this->GetCellType(vtkId);
815   int cellDim = SMDS_Downward::getCellDimension(vtkType);
816   if (cellDim <2)
817     return 0; // TODO voisins des edges = edges connectees
818   int cellId = this->_cellIdToDownId[vtkId];
819
820   int nbCells = _downArray[vtkType]->getNumberOfDownCells(cellId);
821   const int *downCells = _downArray[vtkType]->getDownCells(cellId);
822   const unsigned char* downTyp = _downArray[vtkType]->getDownTypes(cellId);
823
824   // --- iteration on faces of the 3D cell (or edges on the 2D cell).
825
826   int nb = 0;
827   for (int i = 0; i < nbCells; i++)
828     {
829       int downId = downCells[i];
830       int cellType = downTyp[i];
831       int nbUp = _downArray[cellType]->getNumberOfUpCells(downId);
832       const int *upCells = _downArray[cellType]->getUpCells(downId);
833       const unsigned char* upTypes = _downArray[cellType]->getUpTypes(downId);
834
835       // ---for a volume, max 2 upCells, one is this cell, the other is a neighbor
836       //    for a face, number of neighbors (connected faces) not known
837
838       for (int j = 0; j < nbUp; j++)
839         {
840           if ((upCells[j] == cellId) && (upTypes[j] == vtkType))
841             continue;
842           int vtkNeighbor = _downArray[upTypes[j]]->getVtkCellId(upCells[j]);
843           neighborsVtkIds[nb] = vtkNeighbor;
844           downIds[nb] = downId;
845           downTypes[nb] = cellType;
846           nb++;
847         }
848       if (nb >= NBMAXNEIGHBORS)
849         assert(0);
850     }
851   return nb;
852 }
853
854 /*! get the node id's of a cell.
855  * The cell is defined by it's downward connectivity id and type.
856  * @param nodeSet set of of vtk node id's to fill.
857  * @param downId downward connectivity id of the cell.
858  * @param downType type of cell.
859  */
860 void SMDS_UnstructuredGrid::GetNodeIds(std::set<int>& nodeSet, int downId, unsigned char downType)
861 {
862   _downArray[downType]->getNodeIds(downId, nodeSet);
863 }
864
865 /*! change some nodes in cell without modifying type or internal connectivity.
866  * Nodes inverse connectivity is maintained up to date.
867  * @param vtkVolId vtk id of the cell
868  * @param localClonedNodeIds map old node id to new node id.
869  */
870 void SMDS_UnstructuredGrid::ModifyCellNodes(int vtkVolId, std::map<int, int> localClonedNodeIds)
871 {
872   vtkIdType npts = 0;
873   vtkIdType *pts; // will refer to the point id's of the face
874   this->GetCellPoints(vtkVolId, npts, pts);
875   for (int i = 0; i < npts; i++)
876     {
877       if (localClonedNodeIds.count(pts[i]))
878         {
879           vtkIdType oldpt = pts[i];
880           pts[i] = localClonedNodeIds[oldpt];
881           //MESSAGE(oldpt << " --> " << pts[i]);
882           //this->RemoveReferenceToCell(oldpt, vtkVolId);
883           //this->AddReferenceToCell(pts[i], vtkVolId);
884         }
885     }
886 }
887
888 /*! reorder the nodes of a face
889  * @param vtkVolId vtk id of a volume containing the face, to get an orientation for the face.
890  * @param orderedNodes list of nodes to reorder (in out)
891  * @return size of the list
892  */
893 int SMDS_UnstructuredGrid::getOrderedNodesOfFace(int vtkVolId, std::vector<vtkIdType>& orderedNodes)
894 {
895   int vtkType = this->GetCellType(vtkVolId);
896   int cellDim = SMDS_Downward::getCellDimension(vtkType);
897   if (cellDim != 3)
898     return 0;
899   SMDS_Down3D *downvol = static_cast<SMDS_Down3D*> (_downArray[vtkType]);
900   int downVolId = this->_cellIdToDownId[vtkVolId];
901   downvol->getOrderedNodesOfFace(downVolId, orderedNodes);
902   return orderedNodes.size();
903 }
904
905 void SMDS_UnstructuredGrid::BuildLinks()
906 {
907   // Remove the old links if they are already built
908   if (this->Links)
909     {
910     this->Links->UnRegister(this);
911     }
912
913   this->Links = SMDS_CellLinks::New();
914   this->Links->Allocate(this->GetNumberOfPoints());
915   this->Links->Register(this);
916   this->Links->BuildLinks(this, this->Connectivity);
917   this->Links->Delete();
918 }