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 cout
<< " tol=" << tol
<< endl
;
195 EG_VTKSP(vtkUnstructuredGrid
, new_grid
);
196 EG_VTKSP(vtkKdTreePointLocator
,loc
);
197 loc
->SetDataSet(m_Grid
);
199 QVector
<vtkIdType
> pnode2node(part
.m_Grid
->GetNumberOfPoints());
200 vtkIdType N
= m_Grid
->GetNumberOfPoints();
202 for (vtkIdType id_pnode
= 0; id_pnode
< part
.m_Grid
->GetNumberOfPoints(); ++id_pnode
) {
204 part
.m_Grid
->GetPoint(id_pnode
, xp
.data());
205 vtkIdType id_node
= loc
->FindClosestPoint(xp
.data());
206 m_Grid
->GetPoint(id_node
, x
.data());
207 if ((x
- xp
).abs() < tol
) {
208 pnode2node
[id_pnode
] = id_node
;
210 pnode2node
[id_pnode
] = N
;
214 allocateGrid(new_grid
, m_Grid
->GetNumberOfCells() + part
.m_Cells
.size(), N
);
215 for (vtkIdType id_node
= 0; id_node
< m_Grid
->GetNumberOfPoints(); ++id_node
) {
217 m_Grid
->GetPoint(id_node
, x
.data());
218 new_grid
->GetPoints()->SetPoint(id_node
, x
.data());
219 copyNodeData(m_Grid
, id_node
, new_grid
, id_node
);
221 QVector
<vtkIdType
> part_nodes
;
222 getNodesFromCells(part
.m_Cells
, part_nodes
, part
.m_Grid
);
223 foreach (vtkIdType id_pnode
, part_nodes
) {
225 part
.m_Grid
->GetPoint(id_pnode
, x
.data());
226 new_grid
->GetPoints()->SetPoint(pnode2node
[id_pnode
], x
.data());
227 copyNodeData(part
.m_Grid
, id_pnode
, new_grid
, pnode2node
[id_pnode
]);
229 QList
<vtkIdType
> new_cells
;
230 for (vtkIdType id_cell
= 0; id_cell
< m_Grid
->GetNumberOfCells(); ++id_cell
) {
231 vtkIdType id_new_cell
= copyCell(m_Grid
, id_cell
, new_grid
);
232 copyCellData(m_Grid
, id_cell
, new_grid
, id_new_cell
);
233 new_cells
.append(id_new_cell
);
235 foreach (vtkIdType id_pcell
, part
.m_Cells
) {
236 vtkIdType id_new_cell
= copyCell(part
.m_Grid
, id_pcell
, new_grid
, pnode2node
);
237 copyCellData(part
.m_Grid
, id_pcell
, new_grid
, id_new_cell
);
238 new_cells
.append(id_new_cell
);
240 makeCopy(new_grid
, m_Grid
);
244 double MeshPartition::getSmallestEdgeLength() const
247 foreach (vtkIdType id_cell
, m_Cells
) {
248 vtkIdType type_cell
= m_Grid
->GetCellType(id_cell
);
249 vtkIdType N_pts
, *pts
;
250 m_Grid
->GetCellPoints(id_cell
, N_pts
, pts
);
251 QVector
<vec3_t
> x(N_pts
);
252 for (int i
= 0; i
< N_pts
; ++i
) {
253 m_Grid
->GetPoint(pts
[i
], x
[i
].data());
255 if (type_cell
== VTK_TRIANGLE
) {
256 L
= min(L
, (x
[0] - x
[1]).abs());
257 L
= min(L
, (x
[1] - x
[2]).abs());
258 L
= min(L
, (x
[2] - x
[0]).abs());
259 } else if (type_cell
== VTK_QUAD
) {
260 L
= min(L
, (x
[0] - x
[1]).abs());
261 L
= min(L
, (x
[1] - x
[2]).abs());
262 L
= min(L
, (x
[2] - x
[3]).abs());
263 L
= min(L
, (x
[3] - x
[0]).abs());
264 } else if (type_cell
== VTK_TETRA
) {
265 L
= min(L
, (x
[0] - x
[1]).abs());
266 L
= min(L
, (x
[1] - x
[2]).abs());
267 L
= min(L
, (x
[2] - x
[0]).abs());
268 L
= min(L
, (x
[3] - x
[0]).abs());
269 L
= min(L
, (x
[3] - x
[1]).abs());
270 L
= min(L
, (x
[3] - x
[2]).abs());
271 } else if (type_cell
== VTK_PYRAMID
) {
272 L
= min(L
, (x
[0] - x
[1]).abs());
273 L
= min(L
, (x
[1] - x
[2]).abs());
274 L
= min(L
, (x
[2] - x
[3]).abs());
275 L
= min(L
, (x
[3] - x
[0]).abs());
276 L
= min(L
, (x
[4] - x
[0]).abs());
277 L
= min(L
, (x
[4] - x
[1]).abs());
278 L
= min(L
, (x
[4] - x
[2]).abs());
279 L
= min(L
, (x
[4] - x
[3]).abs());
280 } else if (type_cell
== VTK_WEDGE
) {
281 L
= min(L
, (x
[0] - x
[1]).abs());
282 L
= min(L
, (x
[1] - x
[2]).abs());
283 L
= min(L
, (x
[2] - x
[0]).abs());
284 L
= min(L
, (x
[3] - x
[4]).abs());
285 L
= min(L
, (x
[4] - x
[5]).abs());
286 L
= min(L
, (x
[5] - x
[3]).abs());
287 L
= min(L
, (x
[0] - x
[3]).abs());
288 L
= min(L
, (x
[1] - x
[4]).abs());
289 L
= min(L
, (x
[2] - x
[5]).abs());
290 } else if (type_cell
== VTK_HEXAHEDRON
) {
291 L
= min(L
, (x
[0] - x
[1]).abs());
292 L
= min(L
, (x
[1] - x
[2]).abs());
293 L
= min(L
, (x
[2] - x
[3]).abs());
294 L
= min(L
, (x
[3] - x
[0]).abs());
295 L
= min(L
, (x
[4] - x
[5]).abs());
296 L
= min(L
, (x
[5] - x
[6]).abs());
297 L
= min(L
, (x
[6] - x
[7]).abs());
298 L
= min(L
, (x
[7] - x
[4]).abs());
299 L
= min(L
, (x
[0] - x
[4]).abs());
300 L
= min(L
, (x
[1] - x
[5]).abs());
301 L
= min(L
, (x
[2] - x
[6]).abs());
302 L
= min(L
, (x
[3] - x
[7]).abs());
308 bool MeshPartition::hasNeighNode(vtkIdType id_node
, vtkIdType id_neigh
)
310 for (int i
= 0; i
< n2nGSize(id_node
); ++i
) {
311 if (n2nGG(id_node
, i
) == id_neigh
) {
318 void MeshPartition::createNodeToBC()
320 EG_VTKDCC(vtkIntArray
, cell_code
, m_Grid
, "cell_code");
321 m_N2BC
.resize(m_Nodes
.size());
322 for (int i_node
= 0; i_node
< m_Nodes
.size(); ++i_node
) {
324 for (int j
= 0; j
< n2cLSize(i_node
); ++j
) {
325 vtkIdType id_cell
= n2cLG(i_node
, j
);
326 if (isSurface(id_cell
, m_Grid
)) {
327 int bc
= cell_code
->GetValue(n2cLG(i_node
, j
));
329 bcs
.insert(cell_code
->GetValue(n2cLG(i_node
, j
)));
333 m_N2BC
[i_node
].resize(bcs
.size());
335 foreach (int bc
, bcs
) {
336 m_N2BC
[i_node
][i
++] = bc
;
341 bool MeshPartition::hasBC(vtkIdType id_node
, int bc
)
344 for (int j
= 0; j
< n2bcGSize(id_node
); ++j
) {
345 if (n2bcG(id_node
, j
) == bc
) {
353 vtkIdType
MeshPartition::getVolumeCell(vtkIdType id_face
)
358 return findVolumeCell(m_Grid
, id_face
, m_LNodes
, m_Cells
, m_LCells
, m_N2C
);
361 vec3_t
MeshPartition::globalNormal(vtkIdType id_node
)
363 vec3_t
normal(0,0,0);
364 for (int i
= 0; i
< n2cGSize(id_node
); ++i
) {
365 vtkIdType id_cell
= n2cGG(id_node
, i
);
366 if (isSurface(id_cell
, m_Grid
)) {
367 vtkIdType N_pts
, *pts
;
368 m_Grid
->GetCellPoints(id_cell
, N_pts
, pts
);
370 for (int j
= 0; j
< N_pts
; ++j
) {
371 if (pts
[j
] == id_node
) {
372 m_Grid
->GetPoint(pts
[j
], a
.data());
374 m_Grid
->GetPoint(pts
[j
-1], b
.data());
376 m_Grid
->GetPoint(pts
[N_pts
-1], b
.data());
379 m_Grid
->GetPoint(pts
[j
+1], c
.data());
381 m_Grid
->GetPoint(pts
[0], c
.data());
387 double alpha
= GeometryTools::angle(u
, v
);
388 vec3_t n
= u
.cross(v
);
390 if (checkVector(n
)) {
399 double MeshPartition::getAverageSurfaceEdgeLength(vtkIdType id_node
)
401 QSet
<vtkIdType
> surface_neighbours
;
402 for (int i
= 0; i
< n2cGSize(id_node
); ++i
) {
403 vtkIdType id_cell
= n2cGG(id_node
, i
);
404 if (isSurface(id_cell
, m_Grid
)) {
405 EG_GET_CELL(id_cell
, m_Grid
);
406 for (int j
= 0; j
< num_pts
; ++j
) {
407 if (pts
[j
] != id_node
) {
408 surface_neighbours
.insert(pts
[j
]);
414 if (surface_neighbours
.size() > 0) {
416 m_Grid
->GetPoint(id_node
, x
.data());
417 foreach (vtkIdType id_neigh
, surface_neighbours
) {
418 m_Grid
->GetPoint(id_neigh
, xn
.data());
421 L
/= surface_neighbours
.size();
426 void MeshPartition::computeMinAndMaxSurfaceStencilEdgeLengths(vtkIdType id_node
, double &l_min
, double &l_max
)
430 for (int i
= 0; i
< n2cGSize(id_node
); ++i
) {
431 vtkIdType id_cell
= n2cGG(id_node
, i
);
432 if (isSurface(id_cell
, m_Grid
)) {
433 vtkIdType
*pts
, num_pts
;
434 m_Grid
->GetCellPoints(id_cell
, num_pts
, pts
);
436 m_Grid
->GetPoint(pts
[num_pts
- 1], x1
.data());
437 for (int j
= 0; j
< num_pts
; ++j
) {
438 m_Grid
->GetPoint(pts
[j
], x2
.data());
439 double L
= (x1
- x2
).abs();
440 l_min
= min(L
, l_min
);
441 l_max
= max(L
, l_max
);
448 double MeshPartition::getMinSurfaceStencilEdgeLength(vtkIdType id_node
)
451 computeMinAndMaxSurfaceStencilEdgeLengths(id_node
, l_min
, l_max
);
455 double MeshPartition::getMaxSurfaceStencilEdgeLength(vtkIdType id_node
)
458 computeMinAndMaxSurfaceStencilEdgeLengths(id_node
, l_min
, l_max
);
462 int MeshPartition::getNumberOfFeatureNeighbours(vtkIdType id_node
)
464 EG_VTKDCN(vtkCharArray
, node_type
, m_Grid
, "node_type");
466 for (int i
= 0; i
< n2nGSize(id_node
); ++i
) {
467 char type
= node_type
->GetValue(n2nGG(id_node
, i
));
468 if (type
== EG_FEATURE_EDGE_VERTEX
|| type
== EG_FEATURE_CORNER_VERTEX
) {
475 int MeshPartition::getEdgeType(vtkIdType id_node1
, vtkIdType id_node2
)
477 QList
<vtkIdType
> edge_faces
;
478 getEdgeFaces(id_node1
, id_node2
, edge_faces
);
480 if (edge_faces
.size() == 1) {
482 } else if (edge_faces
.size() >= 2) {
483 EG_VTKDCC(vtkIntArray
, cell_code
, m_Grid
, "cell_code");
485 foreach (vtkIdType id_face
, edge_faces
) {
486 bcs
.insert(cell_code
->GetValue(id_face
));
488 if (bcs
.size() > 1) {
497 int MeshPartition::computeTopoDistance(vtkIdType id_node1
, vtkIdType id_node2
, int max_dist
, int restriction_type
)
500 QSet
<vtkIdType
> candidates
;
501 candidates
.insert(id_node1
);
502 while (dist
< max_dist
&& !candidates
.contains(id_node2
)) {
503 foreach (vtkIdType id_node
, candidates
) {
504 for (int i
= 0; i
< n2nGSize(id_node
); ++i
) {
505 vtkIdType id_neigh
= n2nGG(id_node
,i
);
506 if (!candidates
.contains(id_neigh
)) {
507 if (getEdgeType(id_node
, id_neigh
) >= restriction_type
) {
508 candidates
.insert(id_neigh
);
518 void MeshPartition::getCommonNodes(vtkIdType id_cell1
, vtkIdType id_cell2
, QVector
<vtkIdType
> &common_nodes
)
520 common_nodes
.clear();
521 QSet
<vtkIdType
> nodes1
, nodes2
;
522 vtkIdType num_pts
, *pts
;
523 m_Grid
->GetCellPoints(id_cell1
, num_pts
, pts
);
524 for (int i
= 0; i
< num_pts
; ++i
) {
525 nodes1
.insert(pts
[i
]);
527 m_Grid
->GetCellPoints(id_cell2
, num_pts
, pts
);
528 for (int i
= 0; i
< num_pts
; ++i
) {
529 nodes2
.insert(pts
[i
]);
531 nodes1
.intersect(nodes2
);
532 common_nodes
.resize(nodes1
.size());
533 qCopy(nodes1
.begin(), nodes1
.end(), common_nodes
.begin());
536 bool MeshPartition::isFeatureEdge(vtkIdType id_node1
, vtkIdType id_node2
, double feature_angle
)
538 bool is_feature_edge
= false;
540 QVector
<vtkIdType
> nodes(2);
543 getCommonBcs(nodes
, bcs
);
544 if (bcs
.size() == 1) {
545 QList
<vtkIdType
> faces
;
546 getEdgeFaces(id_node1
, id_node2
, faces
);
547 if (faces
.size() == 2) {
548 vec3_t n1
= cellNormal(m_Grid
, faces
[0]);
549 vec3_t n2
= cellNormal(m_Grid
, faces
[1]);
550 if (GeometryTools::angle(n1
, n2
) > feature_angle
) {
551 EG_VTKDCN(vtkDoubleArray
, cl
, m_Grid
, "node_meshdensity_desired");
552 CadInterface
*cad
= GuiMainWindow::pointer()->getCadInterface(bcs
.first());
554 m_Grid
->GetPoint(id_node1
, x1
.data());
555 m_Grid
->GetPoint(id_node2
, x2
.data());
556 vec3_t x
= 0.5*(x1
+ x2
);
557 double h
= min(cl
->GetValue(id_node1
), cl
->GetValue(id_node2
));
558 vec3_t xs
= cad
->snapToEdge(x
);
559 if ((xs
- x
).abs() < 0.2*h
) {
560 is_feature_edge
= true;
565 return is_feature_edge
;