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 #include "meshpartition.h"
23 #include "guimainwindow.h"
25 #include <vtkKdTreePointLocator.h>
26 #include <vtkClipDataSet.h>
28 MeshPartition::MeshPartition()
35 MeshPartition::MeshPartition(vtkUnstructuredGrid
*grid
, bool use_all_cells
)
37 setGrid(grid
, use_all_cells
);
40 MeshPartition::MeshPartition(QString volume_name
)
44 setVolume(volume_name
);
47 void MeshPartition::setGrid(vtkUnstructuredGrid
*grid
, bool use_all_cells
)
53 QVector
<vtkIdType
> cls(grid
->GetNumberOfCells());
54 for (vtkIdType id_cell
= 0; id_cell
< cls
.size(); ++id_cell
) {
55 cls
[id_cell
] = id_cell
;
62 void MeshPartition::resetTimeStamps()
74 void MeshPartition::trackGrid(vtkUnstructuredGrid
*grid
)
78 m_GridMTime
= m_Grid
->GetMTime();
82 void MeshPartition::setVolume(QString volume_name
)
84 m_Grid
= GuiMainWindow::pointer()->getGrid();
85 resetOrientation(m_Grid
);
86 VolumeDefinition V
= GuiMainWindow::pointer()->getVol(volume_name
);
88 EG_VTKDCC(vtkIntArray
, cell_code
, m_Grid
, "cell_code");
89 EG_VTKDCC(vtkIntArray
, cell_orgdir
, m_Grid
, "cell_orgdir");
90 EG_VTKDCC(vtkIntArray
, cell_curdir
, m_Grid
, "cell_curdir");
91 EG_VTKDCC(vtkIntArray
, cell_voldir
, m_Grid
, "cell_voldir");
92 for (vtkIdType id_cell
= 0; id_cell
< m_Grid
->GetNumberOfCells(); ++id_cell
) {
93 if (isSurface(id_cell
, m_Grid
)) {
94 int bc
= cell_code
->GetValue(id_cell
);
95 cell_voldir
->SetValue(id_cell
, 0);
96 if (V
.getSign(bc
) != 0) {
98 if (V
.getSign(bc
) == -1) {
99 cell_voldir
->SetValue(id_cell
, 1);
103 if (cell_code
->GetValue(id_cell
) == V
.getVC()) {
111 void MeshPartition::setVolumeOrientation()
113 EG_VTKDCC(vtkIntArray
, cell_curdir
, m_Grid
, "cell_curdir");
114 EG_VTKDCC(vtkIntArray
, cell_voldir
, m_Grid
, "cell_voldir");
115 foreach (vtkIdType id_cell
, m_Cells
) {
116 if (isSurface(id_cell
, m_Grid
)) {
117 if (cell_curdir
->GetValue(id_cell
) != cell_voldir
->GetValue(id_cell
)) {
118 reorientateFace(m_Grid
, id_cell
);
124 void MeshPartition::setOriginalOrientation()
126 EG_VTKDCC(vtkIntArray
, cell_curdir
, m_Grid
, "cell_curdir");
127 EG_VTKDCC(vtkIntArray
, cell_orgdir
, m_Grid
, "cell_orgdir");
128 foreach (vtkIdType id_cell
, m_Cells
) {
129 if (isSurface(id_cell
, m_Grid
)) {
130 if (cell_curdir
->GetValue(id_cell
) != cell_orgdir
->GetValue(id_cell
)) {
131 reorientateFace(m_Grid
, id_cell
);
137 void MeshPartition::setRemainder(const MeshPartition
& part
)
139 setGrid(part
.getGrid());
140 QVector
<vtkIdType
> rcells
;
141 getRestCells(m_Grid
, part
.m_Cells
, rcells
);
145 void MeshPartition::extractToVtkGrid(vtkUnstructuredGrid
*new_grid
)
148 allocateGrid(new_grid
, m_Cells
.size(), m_Nodes
.size());
149 for (int i_nodes
= 0; i_nodes
< m_Nodes
.size(); ++i_nodes
) {
151 m_Grid
->GetPoints()->GetPoint(m_Nodes
[i_nodes
], x
.data());
152 new_grid
->GetPoints()->SetPoint(i_nodes
, x
.data());
153 copyNodeData(m_Grid
, m_Nodes
[i_nodes
], new_grid
, i_nodes
);
155 foreach (vtkIdType id_cell
, m_Cells
) {
157 vtkIdType N_pts, *pts;
158 vtkIdType type_cell = m_Grid->GetCellType(id_cell);
159 m_Grid->GetCellPoints(id_cell, N_pts, pts);
160 QVector<vtkIdType> new_pts(N_pts);
161 for (int i = 0; i < N_pts; ++i) {
162 new_pts[i] = m_LNodes[pts[i]];
164 // update for polyhedral cells here
165 vtkIdType id_new_cell = new_grid->InsertNextCell(type_cell, N_pts, new_pts.data());
167 vtkIdType id_new_cell
= copyCell(m_Grid
, id_cell
, new_grid
, m_LNodes
);
168 copyCellData(m_Grid
, id_cell
, new_grid
, id_new_cell
);
172 void MeshPartition::addPartition(const MeshPartition
& part
, double tol
)
174 if (m_Grid
== part
.m_Grid
) {
175 QVector
<bool> cell_marked(m_Grid
->GetNumberOfCells(), false);
176 foreach (vtkIdType id_cell
, m_Cells
) {
177 cell_marked
[id_cell
] = true;
179 foreach (vtkIdType id_cell
, part
.m_Cells
) {
180 cell_marked
[id_cell
] = true;
182 QList
<vtkIdType
> new_cells
;
183 for (vtkIdType id_cell
= 0; id_cell
< m_Grid
->GetNumberOfCells(); ++id_cell
) {
184 if (cell_marked
[id_cell
]) {
185 new_cells
.append(id_cell
);
191 tol
*= -min(getSmallestEdgeLength(), part
.getSmallestEdgeLength());
193 tol
= max(tol
, 1e-30);
194 EG_VTKSP(vtkUnstructuredGrid
, new_grid
);
195 EG_VTKSP(vtkKdTreePointLocator
,loc
);
196 loc
->SetDataSet(m_Grid
);
198 QVector
<vtkIdType
> pnode2node(part
.m_Grid
->GetNumberOfPoints());
199 vtkIdType N
= m_Grid
->GetNumberOfPoints();
201 for (vtkIdType id_pnode
= 0; id_pnode
< part
.m_Grid
->GetNumberOfPoints(); ++id_pnode
) {
203 part
.m_Grid
->GetPoint(id_pnode
, xp
.data());
204 vtkIdType id_node
= loc
->FindClosestPoint(xp
.data());
205 m_Grid
->GetPoint(id_node
, x
.data());
206 if ((x
- xp
).abs() < tol
) {
207 pnode2node
[id_pnode
] = id_node
;
209 pnode2node
[id_pnode
] = N
;
213 allocateGrid(new_grid
, m_Grid
->GetNumberOfCells() + part
.m_Cells
.size(), N
);
214 for (vtkIdType id_node
= 0; id_node
< m_Grid
->GetNumberOfPoints(); ++id_node
) {
216 m_Grid
->GetPoint(id_node
, x
.data());
217 new_grid
->GetPoints()->SetPoint(id_node
, x
.data());
218 copyNodeData(m_Grid
, id_node
, new_grid
, id_node
);
220 QVector
<vtkIdType
> part_nodes
;
221 getNodesFromCells(part
.m_Cells
, part_nodes
, part
.m_Grid
);
222 foreach (vtkIdType id_pnode
, part_nodes
) {
224 part
.m_Grid
->GetPoint(id_pnode
, x
.data());
225 new_grid
->GetPoints()->SetPoint(pnode2node
[id_pnode
], x
.data());
226 copyNodeData(part
.m_Grid
, id_pnode
, new_grid
, pnode2node
[id_pnode
]);
228 QList
<vtkIdType
> new_cells
;
229 for (vtkIdType id_cell
= 0; id_cell
< m_Grid
->GetNumberOfCells(); ++id_cell
) {
230 vtkIdType id_new_cell
= copyCell(m_Grid
, id_cell
, new_grid
);
231 copyCellData(m_Grid
, id_cell
, new_grid
, id_new_cell
);
232 new_cells
.append(id_new_cell
);
234 foreach (vtkIdType id_pcell
, part
.m_Cells
) {
235 vtkIdType id_new_cell
= copyCell(part
.m_Grid
, id_pcell
, new_grid
, pnode2node
);
236 copyCellData(part
.m_Grid
, id_pcell
, new_grid
, id_new_cell
);
237 new_cells
.append(id_new_cell
);
239 makeCopy(new_grid
, m_Grid
);
243 double MeshPartition::getSmallestEdgeLength() const
246 foreach (vtkIdType id_cell
, m_Cells
) {
247 vtkIdType type_cell
= m_Grid
->GetCellType(id_cell
);
248 vtkIdType N_pts
, *pts
;
249 m_Grid
->GetCellPoints(id_cell
, N_pts
, pts
);
250 QVector
<vec3_t
> x(N_pts
);
251 for (int i
= 0; i
< N_pts
; ++i
) {
252 m_Grid
->GetPoint(pts
[i
], x
[i
].data());
254 if (type_cell
== VTK_TRIANGLE
) {
255 L
= min(L
, (x
[0] - x
[1]).abs());
256 L
= min(L
, (x
[1] - x
[2]).abs());
257 L
= min(L
, (x
[2] - x
[0]).abs());
258 } else if (type_cell
== VTK_QUAD
) {
259 L
= min(L
, (x
[0] - x
[1]).abs());
260 L
= min(L
, (x
[1] - x
[2]).abs());
261 L
= min(L
, (x
[2] - x
[3]).abs());
262 L
= min(L
, (x
[3] - x
[0]).abs());
263 } else if (type_cell
== VTK_TETRA
) {
264 L
= min(L
, (x
[0] - x
[1]).abs());
265 L
= min(L
, (x
[1] - x
[2]).abs());
266 L
= min(L
, (x
[2] - x
[0]).abs());
267 L
= min(L
, (x
[3] - x
[0]).abs());
268 L
= min(L
, (x
[3] - x
[1]).abs());
269 L
= min(L
, (x
[3] - x
[2]).abs());
270 } else if (type_cell
== VTK_PYRAMID
) {
271 L
= min(L
, (x
[0] - x
[1]).abs());
272 L
= min(L
, (x
[1] - x
[2]).abs());
273 L
= min(L
, (x
[2] - x
[3]).abs());
274 L
= min(L
, (x
[3] - x
[0]).abs());
275 L
= min(L
, (x
[4] - x
[0]).abs());
276 L
= min(L
, (x
[4] - x
[1]).abs());
277 L
= min(L
, (x
[4] - x
[2]).abs());
278 L
= min(L
, (x
[4] - x
[3]).abs());
279 } else if (type_cell
== VTK_WEDGE
) {
280 L
= min(L
, (x
[0] - x
[1]).abs());
281 L
= min(L
, (x
[1] - x
[2]).abs());
282 L
= min(L
, (x
[2] - x
[0]).abs());
283 L
= min(L
, (x
[3] - x
[4]).abs());
284 L
= min(L
, (x
[4] - x
[5]).abs());
285 L
= min(L
, (x
[5] - x
[3]).abs());
286 L
= min(L
, (x
[0] - x
[3]).abs());
287 L
= min(L
, (x
[1] - x
[4]).abs());
288 L
= min(L
, (x
[2] - x
[5]).abs());
289 } else if (type_cell
== VTK_HEXAHEDRON
) {
290 L
= min(L
, (x
[0] - x
[1]).abs());
291 L
= min(L
, (x
[1] - x
[2]).abs());
292 L
= min(L
, (x
[2] - x
[3]).abs());
293 L
= min(L
, (x
[3] - x
[0]).abs());
294 L
= min(L
, (x
[4] - x
[5]).abs());
295 L
= min(L
, (x
[5] - x
[6]).abs());
296 L
= min(L
, (x
[6] - x
[7]).abs());
297 L
= min(L
, (x
[7] - x
[4]).abs());
298 L
= min(L
, (x
[0] - x
[4]).abs());
299 L
= min(L
, (x
[1] - x
[5]).abs());
300 L
= min(L
, (x
[2] - x
[6]).abs());
301 L
= min(L
, (x
[3] - x
[7]).abs());
307 bool MeshPartition::hasNeighNode(vtkIdType id_node
, vtkIdType id_neigh
)
309 for (int i
= 0; i
< n2nGSize(id_node
); ++i
) {
310 if (n2nGG(id_node
, i
) == id_neigh
) {
317 void MeshPartition::createNodeToBC()
319 EG_VTKDCC(vtkIntArray
, cell_code
, m_Grid
, "cell_code");
320 m_N2BC
.resize(m_Nodes
.size());
321 for (int i_node
= 0; i_node
< m_Nodes
.size(); ++i_node
) {
323 for (int j
= 0; j
< n2cLSize(i_node
); ++j
) {
324 vtkIdType id_cell
= n2cLG(i_node
, j
);
325 if (isSurface(id_cell
, m_Grid
)) {
326 int bc
= cell_code
->GetValue(n2cLG(i_node
, j
));
328 bcs
.insert(cell_code
->GetValue(n2cLG(i_node
, j
)));
332 m_N2BC
[i_node
].resize(bcs
.size());
334 foreach (int bc
, bcs
) {
335 m_N2BC
[i_node
][i
++] = bc
;
340 bool MeshPartition::hasBC(vtkIdType id_node
, int bc
)
343 for (int j
= 0; j
< n2bcGSize(id_node
); ++j
) {
344 if (n2bcG(id_node
, j
) == bc
) {
352 vtkIdType
MeshPartition::getVolumeCell(vtkIdType id_face
)
357 return findVolumeCell(m_Grid
, id_face
, m_LNodes
, m_Cells
, m_LCells
, m_N2C
);
360 vec3_t
MeshPartition::globalNormal(vtkIdType id_node
)
362 vec3_t
normal(0,0,0);
363 for (int i
= 0; i
< n2cGSize(id_node
); ++i
) {
364 vtkIdType id_cell
= n2cGG(id_node
, i
);
365 if (isSurface(id_cell
, m_Grid
)) {
366 vtkIdType N_pts
, *pts
;
367 m_Grid
->GetCellPoints(id_cell
, N_pts
, pts
);
369 for (int j
= 0; j
< N_pts
; ++j
) {
370 if (pts
[j
] == id_node
) {
371 m_Grid
->GetPoint(pts
[j
], a
.data());
373 m_Grid
->GetPoint(pts
[j
-1], b
.data());
375 m_Grid
->GetPoint(pts
[N_pts
-1], b
.data());
378 m_Grid
->GetPoint(pts
[j
+1], c
.data());
380 m_Grid
->GetPoint(pts
[0], c
.data());
386 double alpha
= GeometryTools::angle(u
, v
);
387 vec3_t n
= u
.cross(v
);
389 if (checkVector(n
)) {
398 double MeshPartition::getAverageSurfaceEdgeLength(vtkIdType id_node
)
400 QSet
<vtkIdType
> surface_neighbours
;
401 for (int i
= 0; i
< n2cGSize(id_node
); ++i
) {
402 vtkIdType id_cell
= n2cGG(id_node
, i
);
403 if (isSurface(id_cell
, m_Grid
)) {
404 EG_GET_CELL(id_cell
, m_Grid
);
405 for (int j
= 0; j
< num_pts
; ++j
) {
406 if (pts
[j
] != id_node
) {
407 surface_neighbours
.insert(pts
[j
]);
413 if (surface_neighbours
.size() > 0) {
415 m_Grid
->GetPoint(id_node
, x
.data());
416 foreach (vtkIdType id_neigh
, surface_neighbours
) {
417 m_Grid
->GetPoint(id_neigh
, xn
.data());
420 L
/= surface_neighbours
.size();
425 void MeshPartition::computeMinAndMaxSurfaceStencilEdgeLengths(vtkIdType id_node
, double &l_min
, double &l_max
)
429 for (int i
= 0; i
< n2cGSize(id_node
); ++i
) {
430 vtkIdType id_cell
= n2cGG(id_node
, i
);
431 if (isSurface(id_cell
, m_Grid
)) {
432 vtkIdType
*pts
, num_pts
;
433 m_Grid
->GetCellPoints(id_cell
, num_pts
, pts
);
435 m_Grid
->GetPoint(pts
[num_pts
- 1], x1
.data());
436 for (int j
= 0; j
< num_pts
; ++j
) {
437 m_Grid
->GetPoint(pts
[j
], x2
.data());
438 double L
= (x1
- x2
).abs();
439 l_min
= min(L
, l_min
);
440 l_max
= max(L
, l_max
);
447 double MeshPartition::getMinSurfaceStencilEdgeLength(vtkIdType id_node
)
450 computeMinAndMaxSurfaceStencilEdgeLengths(id_node
, l_min
, l_max
);
454 double MeshPartition::getMaxSurfaceStencilEdgeLength(vtkIdType id_node
)
457 computeMinAndMaxSurfaceStencilEdgeLengths(id_node
, l_min
, l_max
);
461 int MeshPartition::getNumberOfFeatureNeighbours(vtkIdType id_node
)
463 EG_VTKDCN(vtkCharArray
, node_type
, m_Grid
, "node_type");
465 for (int i
= 0; i
< n2nGSize(id_node
); ++i
) {
466 char type
= node_type
->GetValue(n2nGG(id_node
, i
));
467 if (type
== EG_FEATURE_EDGE_VERTEX
|| type
== EG_FEATURE_CORNER_VERTEX
) {
474 int MeshPartition::getEdgeType(vtkIdType id_node1
, vtkIdType id_node2
)
476 QList
<vtkIdType
> edge_faces
;
477 getEdgeFaces(id_node1
, id_node2
, edge_faces
);
479 if (edge_faces
.size() == 1) {
481 } else if (edge_faces
.size() >= 2) {
482 EG_VTKDCC(vtkIntArray
, cell_code
, m_Grid
, "cell_code");
484 foreach (vtkIdType id_face
, edge_faces
) {
485 bcs
.insert(cell_code
->GetValue(id_face
));
487 if (bcs
.size() > 1) {
496 int MeshPartition::computeTopoDistance(vtkIdType id_node1
, vtkIdType id_node2
, int max_dist
, int restriction_type
)
499 QSet
<vtkIdType
> candidates
;
500 candidates
.insert(id_node1
);
501 while (dist
< max_dist
&& !candidates
.contains(id_node2
)) {
502 foreach (vtkIdType id_node
, candidates
) {
503 for (int i
= 0; i
< n2nGSize(id_node
); ++i
) {
504 vtkIdType id_neigh
= n2nGG(id_node
,i
);
505 if (!candidates
.contains(id_neigh
)) {
507 if (restriction_type
> 0) {
508 insert
= getEdgeType(id_node
, id_neigh
) >= restriction_type
;
511 candidates
.insert(id_neigh
);
521 void MeshPartition::getCommonNodes(vtkIdType id_cell1
, vtkIdType id_cell2
, QVector
<vtkIdType
> &common_nodes
)
523 common_nodes
.clear();
524 QSet
<vtkIdType
> nodes1
, nodes2
;
525 vtkIdType num_pts
, *pts
;
526 m_Grid
->GetCellPoints(id_cell1
, num_pts
, pts
);
527 for (int i
= 0; i
< num_pts
; ++i
) {
528 nodes1
.insert(pts
[i
]);
530 m_Grid
->GetCellPoints(id_cell2
, num_pts
, pts
);
531 for (int i
= 0; i
< num_pts
; ++i
) {
532 nodes2
.insert(pts
[i
]);
534 nodes1
.intersect(nodes2
);
535 common_nodes
.resize(nodes1
.size());
536 qCopy(nodes1
.begin(), nodes1
.end(), common_nodes
.begin());
539 bool MeshPartition::isFeatureEdge(vtkIdType id_node1
, vtkIdType id_node2
, double feature_angle
)
541 bool is_feature_edge
= false;
543 QVector
<vtkIdType
> nodes(2);
546 getCommonBcs(nodes
, bcs
);
547 if (bcs
.size() == 1) {
548 QList
<vtkIdType
> faces
;
549 getEdgeFaces(id_node1
, id_node2
, faces
);
550 if (faces
.size() == 2) {
551 vec3_t n1
= cellNormal(m_Grid
, faces
[0]);
552 vec3_t n2
= cellNormal(m_Grid
, faces
[1]);
553 if (GeometryTools::angle(n1
, n2
) > feature_angle
) {
554 EG_VTKDCN(vtkDoubleArray
, cl
, m_Grid
, "node_meshdensity_desired");
555 CadInterface
*cad
= GuiMainWindow::pointer()->getCadInterface(bcs
.first());
557 m_Grid
->GetPoint(id_node1
, x1
.data());
558 m_Grid
->GetPoint(id_node2
, x2
.data());
559 vec3_t x
= 0.5*(x1
+ x2
);
560 double h
= min(cl
->GetValue(id_node1
), cl
->GetValue(id_node2
));
561 vec3_t xs
= cad
->snapToEdge(x
);
562 if ((xs
- x
).abs() < 0.2*h
) {
563 is_feature_edge
= true;
568 return is_feature_edge
;
571 bool MeshPartition::isConvexNode(vtkIdType id_node
)
573 int n_faces
= n2cGSize(id_node
);
578 vec3_t x1
, cell_centers(0,0,0), cell_normals(0,0,0);
579 m_Grid
->GetPoint(id_node
, x1
.data());
580 for (int i
= 0; i
< n_faces
; ++i
) {
581 vtkIdType id_cell
= n2cGG(id_node
, i
);
582 cell_centers
+= cellCentre(m_Grid
, id_cell
);
583 cell_normals
+= cellNormal(m_Grid
, id_cell
);
585 cell_centers
*= 1.0/n_faces
;
586 if ((x1
- cell_centers
)*cell_normals
.normalise() > 0) {
593 bool MeshPartition::isConvexNode(vtkIdType id_node
, QVector
<int> bl_codes
)
595 EG_VTKDCC(vtkIntArray
, cell_code
, m_Grid
, "cell_code");
596 int n_faces
= n2cGSize(id_node
);
601 vec3_t x1
, cell_centers(0,0,0), cell_normals(0,0,0);
602 m_Grid
->GetPoint(id_node
, x1
.data());
604 for (int i
= 0; i
< n_faces
; ++i
) {
605 vtkIdType id_cell
= n2cGG(id_node
, i
);
606 if (bl_codes
.contains(cell_code
->GetValue(id_cell
))) {
607 cell_centers
+= cellCentre(m_Grid
, id_cell
);
608 cell_normals
+= cellNormal(m_Grid
, id_cell
);
613 cell_centers
*= 1.0/n_used
;
614 if ((x1
- cell_centers
)*cell_normals
.normalise() > 0) {