1 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 // + This file is part of enGrid. +
5 // + Copyright 2008-2014 enGits GmbH +
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. +
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. +
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/>. +
20 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
22 #ifndef MESHPARTITION_H
23 #define MESHPARTITION_H
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
59 void createNodeToBC();
61 void resetTimeStamps();
73 /// Create an empty (undefined) mesh partition
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);
84 * Create a mesh partition from a global volume definition
85 * @param volume_name the name of the volume
87 MeshPartition(QString volume_name
);
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);
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
113 void setCells(const C
& cls
);
116 * Define the mesh partition by defining its nodes.
117 * @param nds the nodes of the subset
120 void setNodes(const C
& nds
);
123 * Define the mesh partition by defining boundary codes.
124 * @param bcs the boundary codes of the subset
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
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.
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.
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);
407 inline void MeshPartition::setCells(const C
& cls
)
409 m_Cells
.resize(cls
.size());
410 qCopy(cls
.begin(), cls
.end(), m_Cells
.begin());
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 EG_GET_CELL(id_cell
, m_Grid
);
424 bool append_cell
= true;
425 for (int i
= 0; i
< num_pts
; ++i
) {
426 if (!node_inside
[pts
[i
]]) {
439 inline void MeshPartition::setBCs(const C
& bcs
)
441 QList
<vtkIdType
> cls
;
442 EG_VTKDCC(vtkIntArray
, cell_code
, m_Grid
, "cell_code");
443 for (vtkIdType id_cell
= 0; id_cell
< m_Grid
->GetNumberOfCells(); ++id_cell
) {
444 foreach (int bc
, bcs
) {
445 if (cell_code
->GetValue(id_cell
) == bc
) {
454 inline void MeshPartition::setAllCells()
456 QVector
<vtkIdType
> all_cells
;
457 getAllCells(all_cells
, m_Grid
);
458 this->setCells(all_cells
);
461 inline void MeshPartition::checkCells()
463 if (m_Grid
->GetMTime() > m_GridMTime
) {
465 m_GridMTime
= m_Grid
->GetMTime();
469 inline void MeshPartition::checkNodes()
474 if (m_CellsStamp
> m_NodesStamp
) {
475 getNodesFromCells(m_Cells
, m_Nodes
, m_Grid
);
476 m_NodesStamp
= m_CellsStamp
;
480 inline void MeshPartition::checkLCells()
485 if (m_CellsStamp
> m_LCellsStamp
) {
486 createCellMapping(m_Cells
, m_LCells
, m_Grid
);
487 m_LCellsStamp
= m_CellsStamp
;
491 inline void MeshPartition::checkLNodes()
494 if (m_NodesStamp
> m_LNodesStamp
) {
495 createNodeMapping(m_Nodes
, m_LNodes
, m_Grid
);
496 m_LNodesStamp
= m_NodesStamp
;
500 inline void MeshPartition::checkN2N()
503 if (m_LNodesStamp
> m_N2NStamp
) {
504 createNodeToNode(m_Cells
, m_Nodes
, m_LNodes
, m_N2N
, m_Grid
);
505 m_N2NStamp
= m_LNodesStamp
;
509 inline void MeshPartition::checkN2C()
512 if (m_LNodesStamp
> m_N2CStamp
) {
513 createNodeToCell(m_Cells
, m_Nodes
, m_LNodes
, m_N2C
, m_Grid
);
514 m_N2CStamp
= m_LNodesStamp
;
518 inline void MeshPartition::checkN2BC()
521 if (m_N2CStamp
> m_N2BCStamp
) {
523 m_N2BCStamp
= m_N2CStamp
;
527 inline void MeshPartition::checkC2C()
530 if (m_CellsStamp
> m_C2CStamp
) {
531 createCellToCell(m_Cells
, m_C2C
, m_Grid
);
532 m_C2CStamp
= m_CellsStamp
;
536 inline const QVector
<vtkIdType
>& MeshPartition::getCells() const
541 inline const QVector
<int>& MeshPartition::getLocalCells()
547 inline const QVector
<vtkIdType
>& MeshPartition::getNodes()
553 inline const QVector
<int>& MeshPartition::getLocalNodes()
559 inline const QVector
<QVector
<int> >& MeshPartition::getN2N()
565 inline const QVector
<QVector
<int> >& MeshPartition::getN2C()
571 inline const QVector
<QVector
<int> >& MeshPartition::getC2C()
577 inline int MeshPartition::n2nLSize(int i_nodes
)
580 return m_N2N
[i_nodes
].size();
583 inline int MeshPartition::n2nLL(int i_nodes
, int j
)
586 return m_N2N
[i_nodes
][j
];
589 inline vtkIdType
MeshPartition::n2nLG(int i_nodes
, int j
)
592 return m_Nodes
[m_N2N
[i_nodes
][j
]];
595 inline int MeshPartition::n2nGSize(vtkIdType id_node
)
598 return m_N2N
[m_LNodes
[id_node
]].size();
601 inline int MeshPartition::n2nGL(vtkIdType id_node
, int j
)
604 return m_N2N
[m_LNodes
[id_node
]][j
];
607 inline vtkIdType
MeshPartition::n2nGG(vtkIdType id_node
, int j
)
610 return m_Nodes
[m_N2N
[m_LNodes
[id_node
]][j
]];
613 inline int MeshPartition::n2cLSize(int i_nodes
)
616 return m_N2C
[i_nodes
].size();
619 inline int MeshPartition::n2cLL(int i_nodes
, int j
)
622 return m_N2C
[i_nodes
][j
];
625 inline vtkIdType
MeshPartition::n2cLG(int i_nodes
, int j
)
628 int i_cell
= m_N2C
[i_nodes
][j
];
629 if(i_cell
<0) return(-1);
630 else return m_Cells
[i_cell
];
633 inline int MeshPartition::n2cGSize(vtkIdType id_node
)
636 return m_N2C
[m_LNodes
[id_node
]].size();
639 inline int MeshPartition::n2cGL(vtkIdType id_node
, int j
)
642 return m_N2C
[m_LNodes
[id_node
]][j
];
645 inline vtkIdType
MeshPartition::n2cGG(vtkIdType id_node
, int j
)
648 int i_cell
= m_N2C
[m_LNodes
[id_node
]][j
];
649 if(i_cell
<0) return(-1);
650 else return m_Cells
[i_cell
];
653 inline int MeshPartition::c2cLSize(int i_cells
)
656 return m_C2C
[i_cells
].size();
659 inline int MeshPartition::c2cLL(int i_cells
, int j
)
662 return m_C2C
[i_cells
][j
];
665 inline vtkIdType
MeshPartition::c2cLG(int i_cells
, int j
)
668 int i_cell
= m_C2C
[i_cells
][j
];
669 if(i_cell
<0) return(-1);
670 else return m_Cells
[i_cell
];
673 inline int MeshPartition::c2cGSize(vtkIdType id_cell
)
677 return m_C2C
[m_LCells
[id_cell
]].size();
680 inline int MeshPartition::c2cGL(vtkIdType id_cell
, int j
)
684 return m_C2C
[m_LCells
[id_cell
]][j
];
687 inline vtkIdType
MeshPartition::c2cGG(vtkIdType id_cell
, int j
)
691 int i_cell
= m_C2C
[m_LCells
[id_cell
]][j
];
692 if(i_cell
<0) return(-1);
693 else return m_Cells
[i_cell
];
696 inline int MeshPartition::getNumberOfCells()
698 return m_Cells
.size();
701 inline int MeshPartition::getNumberOfNodes()
704 return m_Nodes
.size();
707 inline int MeshPartition::localNode(vtkIdType id_node
)
710 return m_LNodes
[id_node
];
713 inline vtkIdType
MeshPartition::globalNode(int i
)
719 inline int MeshPartition::localCell(vtkIdType id_cell
)
722 return m_LCells
[id_cell
];
725 inline vtkIdType
MeshPartition::globalCell(int i
)
728 else return m_Cells
[i
];
731 inline int MeshPartition::n2bcLSize(int i_nodes
)
734 return m_N2BC
[i_nodes
].size();
737 inline int MeshPartition::n2bcL(int i_nodes
, int j
)
740 return m_N2BC
[i_nodes
][j
];
743 inline int MeshPartition::n2bcGSize(vtkIdType id_node
)
746 return m_N2BC
[m_LNodes
[id_node
]].size();
749 inline int MeshPartition::n2bcG(vtkIdType id_node
, int j
)
752 return m_N2BC
[m_LNodes
[id_node
]][j
];
755 template <typename C
>
756 void MeshPartition::getGlobalN2N(vtkIdType id_node
, C
& cont
)
759 for (int i
= 0; i
< n2nGSize(id_node
); ++i
) {
760 cont
<< n2nGG(id_node
, i
);
764 template <typename C
>
765 void MeshPartition::getEdgeFaces(vtkIdType id_node1
, vtkIdType id_node2
, C
&edge_faces
)
768 for (int i
= 0; i
< n2cGSize(id_node1
); ++i
) {
769 vtkIdType id_cell
= n2cGG(id_node1
, i
);
770 if (isSurface(id_cell
, m_Grid
)) {
771 EG_GET_CELL(id_cell
, m_Grid
);
772 for (int j
= 0; j
< num_pts
; ++j
) {
773 if (pts
[j
] == id_node2
) {
774 edge_faces
<< id_cell
;
782 template <typename C
>
783 void MeshPartition::getCommonBcs(const C
&nodes
, QVector
<int> &common_bcs
)
787 foreach (vtkIdType id_node
, nodes
) {
789 for (int i
= 0; i
< n2bcGSize(id_node
); ++i
) {
790 node_bcs
.insert(n2bcG(id_node
, i
));
796 bcs
.intersect(node_bcs
);
799 common_bcs
.resize(bcs
.size());
800 qCopy(bcs
.begin(), bcs
.end(), common_bcs
.begin());
803 template <typename C
>
804 QSet
<int> MeshPartition::getCommonBcs(const C
&nodes
)
806 QSet
<int> common_bcs
;
808 foreach (vtkIdType id_node
, nodes
) {
810 for (int i
= 0; i
< n2bcGSize(id_node
); ++i
) {
811 node_bcs
.insert(n2bcG(id_node
, i
));
815 common_bcs
= node_bcs
;
817 common_bcs
.intersect(node_bcs
);
823 #endif // MESHPARTITION_H