small changes over the last months … :-|
[engrid-github.git] / src / libengrid / meshpartition.h
bloba39d0695af005ef633a4e22570bec6a2bd1b2a7c
1 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 // + +
3 // + This file is part of enGrid. +
4 // + +
5 // + Copyright 2008-2014 enGits GmbH +
6 // + +
7 // + enGrid is free software: you can redistribute it and/or modify +
8 // + it under the terms of the GNU General Public License as published by +
9 // + the Free Software Foundation, either version 3 of the License, or +
10 // + (at your option) any later version. +
11 // + +
12 // + enGrid is distributed in the hope that it will be useful, +
13 // + but WITHOUT ANY WARRANTY; without even the implied warranty of +
14 // + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +
15 // + GNU General Public License for more details. +
16 // + +
17 // + You should have received a copy of the GNU General Public License +
18 // + along with enGrid. If not, see <http://www.gnu.org/licenses/>. +
19 // + +
20 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
22 #ifndef MESHPARTITION_H
23 #define MESHPARTITION_H
25 class MeshPartition;
27 #include "egvtkobject.h"
29 class MeshPartition : public EgVtkObject
32 private: // attributes
35 vtkUnstructuredGrid* m_Grid; ///< the grid underlying this mesh partition
36 QVector<vtkIdType> m_Cells; ///< all cells of the mesh partition
37 QVector<int> m_LCells; ///< inverse indexing for the cells
38 QVector<vtkIdType> m_Nodes; ///< all nodes of the mesh partition
39 QVector<int> m_LNodes; ///< inverse indexing for the nodes
40 QVector<QVector<int> > m_N2C; ///< node to cell information
41 QVector<QVector<int> > m_N2BC; ///< node to boundary code information
42 QVector<QVector<int> > m_N2N; ///< node to node information
43 QVector<QVector<int> > m_C2C; ///< cell to cell information
45 int m_CellsStamp; ///< "time"-stamp
46 int m_LCellsStamp; ///< "time"-stamp
47 int m_NodesStamp; ///< "time"-stamp
48 int m_LNodesStamp; ///< "time"-stamp
49 int m_N2NStamp; ///< "time"-stamp
50 int m_N2CStamp; ///< "time"-stamp
51 int m_N2BCStamp; ///< "time"-stamp
52 int m_C2CStamp; ///< "time"-stamp
54 bool m_TrackGrid; ///< flag to determine if grid should be tracked (make sure that all cells are always included)
55 unsigned long int m_GridMTime; ///< VTK's modification time of the underlying grid
57 private: // methods
59 void createNodeToBC();
61 void resetTimeStamps();
62 void checkCells();
63 void checkNodes();
64 void checkLCells();
65 void checkLNodes();
66 void checkN2N();
67 void checkN2C();
68 void checkN2BC();
69 void checkC2C();
71 public: // methods
73 /// Create an empty (undefined) mesh partition
74 MeshPartition();
76 /**
77 * Create a mesh partition with the grid set. Optionally all cells can be selected.
78 * @param grid the grid to use
79 * @param use_all_cells if set to true all cells will be selected;
81 MeshPartition(vtkUnstructuredGrid *grid, bool use_all_cells = false);
83 /**
84 * Create a mesh partition from a global volume definition
85 * @param volume_name the name of the volume
87 MeshPartition(QString volume_name);
89 /**
90 * Set the grid.
91 * @param a pointer to the grid
92 * @param use_all_cells if set to true all cells will be selected;
94 void setGrid(vtkUnstructuredGrid *grid, bool use_all_cells = false);
96 /**
97 * Set the grid and make sure all cells are always included (automatic tracking).
98 * @param a pointer to the grid
100 void trackGrid(vtkUnstructuredGrid *grid);
103 * Access to the grid.
104 * @return a pointer to the grid
106 vtkUnstructuredGrid* getGrid() const { return m_Grid; }
109 * Define the mesh partition by defining its cells.
110 * @param cls the cells of the subset
112 template <class C>
113 void setCells(const C& cls);
116 * Define the mesh partition by defining its nodes.
117 * @param nds the nodes of the subset
119 template <class C>
120 void setNodes(const C& nds);
123 * Define the mesh partition by defining boundary codes.
124 * @param bcs the boundary codes of the subset
126 template <class C>
127 void setBCs(const C& bcs);
130 * Define the mesh partition by defining a boundary code.
131 * @param bc the boundary code of the subset
133 void setBC(int bc);
136 * @brief reset all surface cells to a new boundary condition
137 * @param bc_name name of teh boundary condition
138 * @param bc_type type of the boundary condition
140 void resetBC(QString bc_name, QString bc_type);
143 * Define the mesh partition by defining all its cells.
145 void setAllCells();
148 * Define the mesh partition by giving a symbolic volume name.
149 * The grid will be changed to the default (main) grid that is currently loaded into ENGRID.
150 * @param volume_name the symbolic volume name
152 void setVolume(QString volume_name);
155 * Define the mesh partition as the remainder of an existing partition.
156 * @param part the existing partition
158 void setRemainder(const MeshPartition& part);
160 const QVector<vtkIdType>& getCells() const; ///< Access to the cell indices
161 const QVector<int>& getLocalCells(); ///< Access to the local cell indices
162 const QVector<vtkIdType>& getNodes(); ///< Access to the node indices
163 const QVector<int>& getLocalNodes(); ///< Access to the local node indices
164 const QVector<QVector<int> >& getN2N(); ///< Access to the local node to node structure
165 const QVector<QVector<int> >& getN2C(); ///< Access to the local node to cell structure
166 const QVector<QVector<int> >& getC2C(); ///< Access to the local cell to cell structure
168 void setVolumeOrientation(); ///< change the face orientation to match the volume definition
169 void setOriginalOrientation(); ///< change the orientation to match the original orientation
172 * Copy the partition to a VTK grid.
173 * @param new_grid the grid to copy the partition to (will be resized accordingly).
175 void extractToVtkGrid(vtkUnstructuredGrid *new_grid);
178 * Add another partition to this one.
179 * At the moment overlapping partitions on two different grids will not be handled well.
180 * If both partitions do not have the same underlying grid the grid will be extended in order
181 * to add the other partition.
182 * @param part the partition to add
183 * @param tol the tolerance to identify duplicate nodes
184 * (negative values denote a relative tolerance -- relative to the smallest edge length)
186 void addPartition(const MeshPartition& part, double tol = -1e-3);
189 * Concatenate another partition to this one (duplicate nodes will not be merged).
190 * If both partitions do not have the same underlying grid the grid will be extended in order
191 * to add the other partition.
192 * @param part the partition to add
194 void concatenatePartition(const MeshPartition& part);
197 * compute the smallest edge length of the partition
198 * @return the smallest edge length
200 double getSmallestEdgeLength() const;
203 * Get the number of nodes in the partition.
204 * @return the number of nodes
206 int getNumberOfNodes();
209 * Get the number of cells in the partition.
210 * @return the number of cells
212 int getNumberOfCells();
215 * Get the average length of all surface edges connected to this node.
216 * @param id_node the node ID of the node in question
217 * @return the average length of all connected surface edges
219 double getAverageSurfaceEdgeLength(vtkIdType id_node);
222 * @brief compute the minimal and maximal edge length of a surface stencil
223 * A surface stencil consists of all surface elements which have a single node in common.
224 * @param id_node the node in common
225 * @param l_min on return this will hold the minimal edge length
226 * @param l_max on return this will hold the maximal edge length
228 void computeMinAndMaxSurfaceStencilEdgeLengths(vtkIdType id_node, double &l_min, double &l_max);
231 * @brief get the minimal edge length of a surface stencil
232 * A surface stencil consists of all surface elements which have a single node in common.
233 * @param id_node the node in common
234 * @return the minimal edge length
236 double getMinSurfaceStencilEdgeLength(vtkIdType id_node);
239 * @brief get the maximal edge length of a surface stencil
240 * A surface stencil consists of all surface elements which have a single node in common.
241 * @param id_node the node in common
242 * @return the maximal edge length
244 double getMaxSurfaceStencilEdgeLength(vtkIdType id_node);
246 vtkIdType getVolumeCell(vtkIdType id_face);
248 int localNode(vtkIdType id_node);
249 vtkIdType globalNode(int i);
250 int localCell(vtkIdType id_cell);
251 vtkIdType globalCell(int i);
254 int n2nLSize(int i_nodes);
255 int n2nLL(int i_nodes, int j);
256 vtkIdType n2nLG(int i_nodes, int j);
257 int n2nGSize(vtkIdType id_node);
258 int n2nGL(vtkIdType id_node, int j);
259 vtkIdType n2nGG(vtkIdType id_node, int j);
260 int n2cLSize(int i_nodes);
261 int n2cLL(int i_nodes, int j);
262 vtkIdType n2cLG(int i_nodes, int j);
263 int n2cGSize(vtkIdType id_node);
264 int n2cGL(vtkIdType id_node, int j);
265 vtkIdType n2cGG(vtkIdType id_node, int j);
266 int c2cLSize(int i_cells);
267 int c2cLL(int i_cells, int j);
268 vtkIdType c2cLG(int i_cells, int j);
269 int c2cGSize(vtkIdType id_cell);
270 int c2cGL(vtkIdType id_cell, int j);
271 vtkIdType c2cGG(vtkIdType id_cell, int j);
272 int n2bcLSize(int i_nodes);
273 int n2bcL(int i_nodes, int j);
274 int n2bcGSize(vtkIdType id_node);
275 int n2bcG(vtkIdType id_node, int j);
277 bool hasNeighNode(vtkIdType id_node, vtkIdType id_neigh);
278 bool hasBC(vtkIdType id_node, int bc);
281 * Compute the normal vector of a node.
282 * @param id_node the global ID of the node
283 * @return the normalised normal vector
285 vec3_t globalNormal(vtkIdType id_node);
287 template <typename C>
288 void getGlobalN2N(vtkIdType id_node, C& cont);
290 int getNumberOfFeatureNeighbours(vtkIdType id_node);
292 template <typename C>
293 void getEdgeFaces(vtkIdType id_node1, vtkIdType id_node2, C &edge_faces);
295 int getEdgeType(vtkIdType id_node1, vtkIdType id_node2);
298 * @brief compute topological distance between two nodes
299 * @param id_node1 index of the first node
300 * @param id_node2 index of the second node
301 * @param max_dist maximal search distance
302 * @param restriction_type (0: no restriction, 1: only surface nodes, 2: only edge nodes)
303 * @return the number of edges for the shortest connection between the two nodes
305 int computeTopoDistance(vtkIdType id_node1, vtkIdType id_node2, int max_dist, int restriction_type);
308 * @brief get common nodes of two cells
309 * @param id_cell1 id of the first cell
310 * @param id_cell2 id of the second cell
311 * @param common_nodes holds the common node ids on return
313 void getCommonNodes(vtkIdType id_cell1, vtkIdType id_cell2, QVector<vtkIdType> &common_nodes);
316 * @brief get common boundary codes of a set of nodes
317 * @param nodes Qt container holding the nodes to investigate
318 * @param common_bcs holds the common boundary codes on return
320 template <typename C>
321 void getCommonBcs(const C &common_nodes, QVector<int> &common_bcs);
324 * @brief get common boundary codes of a set of nodes
325 * @param nodes Qt container holding the nodes to investigate
326 * @return a set with the common boundary codes
328 template <typename C>
329 QSet<int> getCommonBcs(const C &common_nodes);
332 * @brief check if an edge is a feature edge
333 * The check is done by trying to snap to the edge geometry of the CAD interface.
334 * Depending on the distance of the snapped locations this will a feature edge or not.
335 * @param id_node1 first node of the edge
336 * @param id_node2 second node of the edge
337 * @param feature_angle the feature angle threshold
338 * @return true if id_node1 -> id_node2 is a feature edge
340 bool isFeatureEdge(vtkIdType id_node1, vtkIdType id_node2, double feature_angle);
341 bool isConvexNode(vtkIdType id_node);
342 bool isConvexNode(vtkIdType id_node, QVector<int> bl_codes);
345 * @brief compute hyraulic diameter, perimeter, area, and normal of all surface cells in the partition.
346 * @param Dh on return Dh will contain the hydraulic diameter
347 * @param A on return A will contain the area
348 * @param P on return P will contain the perimeter
349 * @param x on return n will contain the centre of gravity of the surface
350 * @param n on return n will contain the surface normal (|n| = 1)
352 void calcPlanarSurfaceMetrics(double &Dh, double &A, double &P, vec3_t &x, vec3_t &n);
355 * @brief duplicate the sub-mesh.
356 * This methods duplicates all nodes and cells which are in the mesh partition.
357 * Afterwards the mesh partition will contain the duplicated and detached mesh.
358 * The original set of nodes and cells will not be part of the mesh partition anymore.
360 void duplicate();
363 * @brief scale the whole partition
364 * @param factor the scale factor
365 * @param centre (optional) the centre of the transformation
367 void scale(double factor, vec3_t centre = vec3_t(0,0,0));
370 * @brief translate the whole partition
371 * @param v the translation vector
373 void translate(vec3_t v);
376 * @brief extrude the whole partition (only surface cells allowed)
377 * @param dir the direction of the extrusion (vector length has no influence)
378 * @param h a list of layer heights
380 void extrude(vec3_t dir, QList<double> h, BoundaryCondition extrude_bc,
381 bool force_bottom_bc = false, bool force_side_bc = false, bool force_top_bc = false,
382 BoundaryCondition bottom_bc = BoundaryCondition(), BoundaryCondition side_bc = BoundaryCondition(), BoundaryCondition top_bc = BoundaryCondition());
385 * @brief check if the partition only consists of surface cells
386 * @return true if the partition only consists of surface cells
388 bool onlySurfaceCells();
391 * @brief Write the mesh partition to an STL file (only surface cells allowed).
392 * @param file_name the file name of the STL file ('.stl'will be appended if it is lot part of the file name)
394 void writeSTL(QString file_name);
397 * @brief Check if the mesh partition represents a planar surface.
398 * @param tolerance_angle the maximally allowed angle between a face normal and the mean normal
399 * @return true if it is planar
401 bool isPlanar(double tolerance_angle = 0.0017453);
406 template <class C>
407 inline void MeshPartition::setCells(const C& cls)
409 m_Cells.resize(cls.size());
410 qCopy(cls.begin(), cls.end(), m_Cells.begin());
411 ++m_CellsStamp;
414 template <class C>
415 inline void MeshPartition::setNodes(const C& nds)
417 QList<vtkIdType> cls;
418 QVector<bool> node_inside(m_Grid->GetNumberOfPoints(), false);
419 foreach (vtkIdType id_node, nds) {
420 node_inside[id_node] = true;
422 for (vtkIdType id_cell = 0; id_cell < m_Grid->GetNumberOfCells(); ++id_cell) {
423 vtkIdType N_pts, *pts;
424 m_Grid->GetCellPoints(id_cell, N_pts, pts);
425 bool append_cell = true;
426 for (int i = 0; i < N_pts; ++i) {
427 if (!node_inside[pts[i]]) {
428 append_cell = false;
429 break;
432 if (append_cell) {
433 cls.append(id_cell);
436 setCells(cls);
439 template <class C>
440 inline void MeshPartition::setBCs(const C& bcs)
442 QList<vtkIdType> cls;
443 EG_VTKDCC(vtkIntArray, cell_code, m_Grid, "cell_code");
444 for (vtkIdType id_cell = 0; id_cell < m_Grid->GetNumberOfCells(); ++id_cell) {
445 foreach (int bc, bcs) {
446 if (cell_code->GetValue(id_cell) == bc) {
447 cls.append(id_cell);
448 break;
452 setCells(cls);
455 inline void MeshPartition::setAllCells()
457 QVector <vtkIdType> all_cells;
458 getAllCells(all_cells, m_Grid);
459 this->setCells(all_cells);
462 inline void MeshPartition::checkCells()
464 if (m_Grid->GetMTime() > m_GridMTime) {
465 setAllCells();
466 m_GridMTime = m_Grid->GetMTime();
470 inline void MeshPartition::checkNodes()
472 if (m_TrackGrid) {
473 checkCells();
475 if (m_CellsStamp > m_NodesStamp) {
476 getNodesFromCells(m_Cells, m_Nodes, m_Grid);
477 m_NodesStamp = m_CellsStamp;
481 inline void MeshPartition::checkLCells()
483 if (m_TrackGrid) {
484 checkCells();
486 if (m_CellsStamp > m_LCellsStamp) {
487 createCellMapping(m_Cells, m_LCells, m_Grid);
488 m_LCellsStamp = m_CellsStamp;
492 inline void MeshPartition::checkLNodes()
494 checkNodes();
495 if (m_NodesStamp > m_LNodesStamp) {
496 createNodeMapping(m_Nodes, m_LNodes, m_Grid);
497 m_LNodesStamp = m_NodesStamp;
501 inline void MeshPartition::checkN2N()
503 checkLNodes();
504 if (m_LNodesStamp > m_N2NStamp) {
505 createNodeToNode(m_Cells, m_Nodes, m_LNodes, m_N2N, m_Grid);
506 m_N2NStamp = m_LNodesStamp;
510 inline void MeshPartition::checkN2C()
512 checkLNodes();
513 if (m_LNodesStamp > m_N2CStamp) {
514 createNodeToCell(m_Cells, m_Nodes, m_LNodes, m_N2C, m_Grid);
515 m_N2CStamp = m_LNodesStamp;
519 inline void MeshPartition::checkN2BC()
521 checkN2C();
522 if (m_N2CStamp > m_N2BCStamp) {
523 createNodeToBC();
524 m_N2BCStamp = m_N2CStamp;
528 inline void MeshPartition::checkC2C()
530 checkLCells();
531 if (m_CellsStamp > m_C2CStamp) {
532 createCellToCell(m_Cells, m_C2C, m_Grid);
533 m_C2CStamp = m_CellsStamp;
537 inline const QVector<vtkIdType>& MeshPartition::getCells() const
539 return m_Cells;
542 inline const QVector<int>& MeshPartition::getLocalCells()
544 checkLCells();
545 return m_LCells;
548 inline const QVector<vtkIdType>& MeshPartition::getNodes()
550 checkNodes();
551 return m_Nodes;
554 inline const QVector<int>& MeshPartition::getLocalNodes()
556 checkLNodes();
557 return m_LNodes;
560 inline const QVector<QVector<int> >& MeshPartition::getN2N()
562 checkN2N();
563 return m_N2N;
566 inline const QVector<QVector<int> >& MeshPartition::getN2C()
568 checkN2C();
569 return m_N2C;
572 inline const QVector<QVector<int> >& MeshPartition::getC2C()
574 checkC2C();
575 return m_C2C;
578 inline int MeshPartition::n2nLSize(int i_nodes)
580 checkN2N();
581 return m_N2N[i_nodes].size();
584 inline int MeshPartition::n2nLL(int i_nodes, int j)
586 checkN2N();
587 return m_N2N[i_nodes][j];
590 inline vtkIdType MeshPartition::n2nLG(int i_nodes, int j)
592 checkN2N();
593 return m_Nodes[m_N2N[i_nodes][j]];
596 inline int MeshPartition::n2nGSize(vtkIdType id_node)
598 checkN2N();
599 return m_N2N[m_LNodes[id_node]].size();
602 inline int MeshPartition::n2nGL(vtkIdType id_node, int j)
604 checkN2N();
605 return m_N2N[m_LNodes[id_node]][j];
608 inline vtkIdType MeshPartition::n2nGG(vtkIdType id_node, int j)
610 checkN2N();
611 return m_Nodes[m_N2N[m_LNodes[id_node]][j]];
614 inline int MeshPartition::n2cLSize(int i_nodes)
616 checkN2C();
617 return m_N2C[i_nodes].size();
620 inline int MeshPartition::n2cLL(int i_nodes, int j)
622 checkN2C();
623 return m_N2C[i_nodes][j];
626 inline vtkIdType MeshPartition::n2cLG(int i_nodes, int j)
628 checkN2C();
629 int i_cell = m_N2C[i_nodes][j];
630 if(i_cell<0) return(-1);
631 else return m_Cells[i_cell];
634 inline int MeshPartition::n2cGSize(vtkIdType id_node)
636 checkN2C();
637 return m_N2C[m_LNodes[id_node]].size();
640 inline int MeshPartition::n2cGL(vtkIdType id_node, int j)
642 checkN2C();
643 return m_N2C[m_LNodes[id_node]][j];
646 inline vtkIdType MeshPartition::n2cGG(vtkIdType id_node, int j)
648 checkN2C();
649 int i_cell = m_N2C[m_LNodes[id_node]][j];
650 if(i_cell<0) return(-1);
651 else return m_Cells[i_cell];
654 inline int MeshPartition::c2cLSize(int i_cells)
656 checkC2C();
657 return m_C2C[i_cells].size();
660 inline int MeshPartition::c2cLL(int i_cells, int j)
662 checkC2C();
663 return m_C2C[i_cells][j];
666 inline vtkIdType MeshPartition::c2cLG(int i_cells, int j)
668 checkC2C();
669 int i_cell = m_C2C[i_cells][j];
670 if(i_cell<0) return(-1);
671 else return m_Cells[i_cell];
674 inline int MeshPartition::c2cGSize(vtkIdType id_cell)
676 checkC2C();
677 checkLCells();
678 return m_C2C[m_LCells[id_cell]].size();
681 inline int MeshPartition::c2cGL(vtkIdType id_cell, int j)
683 checkC2C();
684 checkLCells();
685 return m_C2C[m_LCells[id_cell]][j];
688 inline vtkIdType MeshPartition::c2cGG(vtkIdType id_cell, int j)
690 checkC2C();
691 checkLCells();
692 int i_cell = m_C2C[m_LCells[id_cell]][j];
693 if(i_cell<0) return(-1);
694 else return m_Cells[i_cell];
697 inline int MeshPartition::getNumberOfCells()
699 return m_Cells.size();
702 inline int MeshPartition::getNumberOfNodes()
704 checkNodes();
705 return m_Nodes.size();
708 inline int MeshPartition::localNode(vtkIdType id_node)
710 checkLNodes();
711 return m_LNodes[id_node];
714 inline vtkIdType MeshPartition::globalNode(int i)
716 checkNodes();
717 return m_Nodes[i];
720 inline int MeshPartition::localCell(vtkIdType id_cell)
722 checkLCells();
723 return m_LCells[id_cell];
726 inline vtkIdType MeshPartition::globalCell(int i)
728 if(i<0) return(-1);
729 else return m_Cells[i];
732 inline int MeshPartition::n2bcLSize(int i_nodes)
734 checkN2BC();
735 return m_N2BC[i_nodes].size();
738 inline int MeshPartition::n2bcL(int i_nodes, int j)
740 checkN2BC();
741 return m_N2BC[i_nodes][j];
744 inline int MeshPartition::n2bcGSize(vtkIdType id_node)
746 checkN2BC();
747 return m_N2BC[m_LNodes[id_node]].size();
750 inline int MeshPartition::n2bcG(vtkIdType id_node, int j)
752 checkN2BC();
753 return m_N2BC[m_LNodes[id_node]][j];
756 template <typename C>
757 void MeshPartition::getGlobalN2N(vtkIdType id_node, C& cont)
759 cont.clear();
760 for (int i = 0; i < n2nGSize(id_node); ++i) {
761 cont << n2nGG(id_node, i);
765 template <typename C>
766 void MeshPartition::getEdgeFaces(vtkIdType id_node1, vtkIdType id_node2, C &edge_faces)
768 edge_faces.clear();
769 for (int i = 0; i < n2cGSize(id_node1); ++i) {
770 vtkIdType id_cell = n2cGG(id_node1, i);
771 if (isSurface(id_cell, m_Grid)) {
772 vtkIdType num_pts, *pts;
773 m_Grid->GetCellPoints(id_cell, num_pts, pts);
774 for (int j = 0; j < num_pts; ++j) {
775 if (pts[j] == id_node2) {
776 edge_faces << id_cell;
777 break;
784 template <typename C>
785 void MeshPartition::getCommonBcs(const C &nodes, QVector<int> &common_bcs)
787 QSet<int> bcs;
788 bool first = true;
789 foreach (vtkIdType id_node, nodes) {
790 QSet<int> node_bcs;
791 for (int i = 0; i < n2bcGSize(id_node); ++i) {
792 node_bcs.insert(n2bcG(id_node, i));
794 if (first) {
795 first = false;
796 bcs = node_bcs;
797 } else {
798 bcs.intersect(node_bcs);
801 common_bcs.resize(bcs.size());
802 qCopy(bcs.begin(), bcs.end(), common_bcs.begin());
805 template <typename C>
806 QSet<int> MeshPartition::getCommonBcs(const C &nodes)
808 QSet<int> common_bcs;
809 bool first = true;
810 foreach (vtkIdType id_node, nodes) {
811 QSet<int> node_bcs;
812 for (int i = 0; i < n2bcGSize(id_node); ++i) {
813 node_bcs.insert(n2bcG(id_node, i));
815 if (first) {
816 first = false;
817 common_bcs = node_bcs;
818 } else {
819 common_bcs.intersect(node_bcs);
822 return common_bcs;
825 #endif // MESHPARTITION_H