small changes over the last months … :-|
[engrid-github.git] / src / libengrid / meshpartition.cpp
blob615aa026587932d3e3d0e8790148ddffd072e860
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 #include "meshpartition.h"
23 #include "guimainwindow.h"
25 #include <vtkKdTreePointLocator.h>
26 #include <vtkClipDataSet.h>
27 #include <vtkTriangleFilter.h>
28 #include <vtkGeometryFilter.h>
29 #include <vtkSTLWriter.h>
31 #include <vtkEgNormalExtrusion.h>
33 MeshPartition::MeshPartition()
35 m_Grid = NULL;
36 m_TrackGrid = false;
37 resetTimeStamps();
40 MeshPartition::MeshPartition(vtkUnstructuredGrid *grid, bool use_all_cells)
42 setGrid(grid, use_all_cells);
45 MeshPartition::MeshPartition(QString volume_name)
47 m_TrackGrid = false;
48 resetTimeStamps();
49 setVolume(volume_name);
52 void MeshPartition::setGrid(vtkUnstructuredGrid *grid, bool use_all_cells)
54 m_TrackGrid = false;
55 resetTimeStamps();
56 m_Grid = grid;
57 if (use_all_cells) {
58 QVector<vtkIdType> cls(grid->GetNumberOfCells());
59 for (vtkIdType id_cell = 0; id_cell < cls.size(); ++id_cell) {
60 cls[id_cell] = id_cell;
62 setCells(cls);
67 void MeshPartition::resetTimeStamps()
69 m_CellsStamp = 0;
70 m_LCellsStamp = 0;
71 m_NodesStamp = 0;
72 m_LNodesStamp = 0;
73 m_N2NStamp = 0;
74 m_N2CStamp = 0;
75 m_N2BCStamp = 0;
76 m_C2CStamp = 0;
79 void MeshPartition::trackGrid(vtkUnstructuredGrid *grid)
81 setGrid(grid);
82 setAllCells();
83 m_GridMTime = m_Grid->GetMTime();
84 m_TrackGrid = true;
87 void MeshPartition::setVolume(QString volume_name)
89 m_Grid = GuiMainWindow::pointer()->getGrid();
90 resetOrientation(m_Grid);
91 VolumeDefinition V = GuiMainWindow::pointer()->getVol(volume_name);
92 QList<vtkIdType> cls;
93 EG_VTKDCC(vtkIntArray, cell_code, m_Grid, "cell_code");
94 EG_VTKDCC(vtkIntArray, cell_orgdir, m_Grid, "cell_orgdir");
95 EG_VTKDCC(vtkIntArray, cell_curdir, m_Grid, "cell_curdir");
96 EG_VTKDCC(vtkIntArray, cell_voldir, m_Grid, "cell_voldir");
97 for (vtkIdType id_cell = 0; id_cell < m_Grid->GetNumberOfCells(); ++id_cell) {
98 if (isSurface(id_cell, m_Grid)) {
99 int bc = cell_code->GetValue(id_cell);
100 cell_voldir->SetValue(id_cell, 0);
101 if (V.getSign(bc) != 0) {
102 cls.append(id_cell);
103 if (V.getSign(bc) == -1) {
104 cell_voldir->SetValue(id_cell, 1);
107 } else {
108 if (cell_code->GetValue(id_cell) == V.getVC()) {
109 cls.append(id_cell);
113 setCells(cls);
116 void MeshPartition::setVolumeOrientation()
118 EG_VTKDCC(vtkIntArray, cell_curdir, m_Grid, "cell_curdir");
119 EG_VTKDCC(vtkIntArray, cell_voldir, m_Grid, "cell_voldir");
120 foreach (vtkIdType id_cell, m_Cells) {
121 if (isSurface(id_cell, m_Grid)) {
122 if (cell_curdir->GetValue(id_cell) != cell_voldir->GetValue(id_cell)) {
123 reorientateFace(m_Grid, id_cell);
129 void MeshPartition::setOriginalOrientation()
131 EG_VTKDCC(vtkIntArray, cell_curdir, m_Grid, "cell_curdir");
132 EG_VTKDCC(vtkIntArray, cell_orgdir, m_Grid, "cell_orgdir");
133 foreach (vtkIdType id_cell, m_Cells) {
134 if (isSurface(id_cell, m_Grid)) {
135 if (cell_curdir->GetValue(id_cell) != cell_orgdir->GetValue(id_cell)) {
136 reorientateFace(m_Grid, id_cell);
142 void MeshPartition::setRemainder(const MeshPartition& part)
144 setGrid(part.getGrid());
145 QVector<vtkIdType> rcells;
146 getRestCells(m_Grid, part.m_Cells, rcells);
147 setCells(rcells);
150 void MeshPartition::extractToVtkGrid(vtkUnstructuredGrid *new_grid)
152 checkLNodes();
153 allocateGrid(new_grid, m_Cells.size(), m_Nodes.size());
154 for (int i_nodes = 0; i_nodes < m_Nodes.size(); ++i_nodes) {
155 vec3_t x;
156 m_Grid->GetPoints()->GetPoint(m_Nodes[i_nodes], x.data());
157 new_grid->GetPoints()->SetPoint(i_nodes, x.data());
158 copyNodeData(m_Grid, m_Nodes[i_nodes], new_grid, i_nodes);
160 foreach (vtkIdType id_cell, m_Cells) {
162 vtkIdType N_pts, *pts;
163 vtkIdType type_cell = m_Grid->GetCellType(id_cell);
164 m_Grid->GetCellPoints(id_cell, N_pts, pts);
165 QVector<vtkIdType> new_pts(N_pts);
166 for (int i = 0; i < N_pts; ++i) {
167 new_pts[i] = m_LNodes[pts[i]];
169 // update for polyhedral cells here
170 vtkIdType id_new_cell = new_grid->InsertNextCell(type_cell, N_pts, new_pts.data());
172 vtkIdType id_new_cell = copyCell(m_Grid, id_cell, new_grid, m_LNodes);
173 copyCellData(m_Grid, id_cell, new_grid, id_new_cell);
177 void MeshPartition::addPartition(const MeshPartition& part, double tol)
179 if (m_Grid == part.m_Grid) {
180 QVector<bool> cell_marked(m_Grid->GetNumberOfCells(), false);
181 foreach (vtkIdType id_cell, m_Cells) {
182 cell_marked[id_cell] = true;
184 foreach (vtkIdType id_cell, part.m_Cells) {
185 cell_marked[id_cell] = true;
187 QList<vtkIdType> new_cells;
188 for (vtkIdType id_cell = 0; id_cell < m_Grid->GetNumberOfCells(); ++id_cell) {
189 if (cell_marked[id_cell]) {
190 new_cells.append(id_cell);
193 setCells(new_cells);
194 } else {
195 if (tol < 0) {
196 tol *= -min(getSmallestEdgeLength(), part.getSmallestEdgeLength());
198 tol = max(tol, 1e-30);
199 EG_VTKSP(vtkUnstructuredGrid, new_grid);
200 EG_VTKSP(vtkKdTreePointLocator,loc);
201 loc->SetDataSet(m_Grid);
202 loc->BuildLocator();
203 QVector<vtkIdType> pnode2node(part.m_Grid->GetNumberOfPoints());
204 vtkIdType N = m_Grid->GetNumberOfPoints();
205 Timer T(10);
206 for (vtkIdType id_pnode = 0; id_pnode < part.m_Grid->GetNumberOfPoints(); ++id_pnode) {
207 vec3_t xp, x;
208 part.m_Grid->GetPoint(id_pnode, xp.data());
209 vtkIdType id_node = loc->FindClosestPoint(xp.data());
210 m_Grid->GetPoint(id_node, x.data());
211 if ((x - xp).abs() < tol) {
212 pnode2node[id_pnode] = id_node;
213 } else {
214 pnode2node[id_pnode] = N;
215 ++N;
218 allocateGrid(new_grid, m_Grid->GetNumberOfCells() + part.m_Cells.size(), N);
219 for (vtkIdType id_node = 0; id_node < m_Grid->GetNumberOfPoints(); ++id_node) {
220 vec3_t x;
221 m_Grid->GetPoint(id_node, x.data());
222 new_grid->GetPoints()->SetPoint(id_node, x.data());
223 copyNodeData(m_Grid, id_node, new_grid, id_node);
225 QVector<vtkIdType> part_nodes;
226 getNodesFromCells(part.m_Cells, part_nodes, part.m_Grid);
227 foreach (vtkIdType id_pnode, part_nodes) {
228 vec3_t x;
229 part.m_Grid->GetPoint(id_pnode, x.data());
230 new_grid->GetPoints()->SetPoint(pnode2node[id_pnode], x.data());
231 copyNodeData(part.m_Grid, id_pnode, new_grid, pnode2node[id_pnode]);
233 QList<vtkIdType> new_cells;
234 for (vtkIdType id_cell = 0; id_cell < m_Grid->GetNumberOfCells(); ++id_cell) {
235 vtkIdType id_new_cell = copyCell(m_Grid, id_cell, new_grid);
236 copyCellData(m_Grid, id_cell, new_grid, id_new_cell);
237 new_cells.append(id_new_cell);
239 foreach (vtkIdType id_pcell, part.m_Cells) {
240 vtkIdType id_new_cell = copyCell(part.m_Grid, id_pcell, new_grid, pnode2node);
241 copyCellData(part.m_Grid, id_pcell, new_grid, id_new_cell);
242 new_cells.append(id_new_cell);
244 makeCopy(new_grid, m_Grid);
248 void MeshPartition::concatenatePartition(const MeshPartition& part)
250 if (m_Grid == part.m_Grid) {
251 QVector<bool> cell_marked(m_Grid->GetNumberOfCells(), false);
252 foreach (vtkIdType id_cell, m_Cells) {
253 cell_marked[id_cell] = true;
255 foreach (vtkIdType id_cell, part.m_Cells) {
256 cell_marked[id_cell] = true;
258 QList<vtkIdType> new_cells;
259 for (vtkIdType id_cell = 0; id_cell < m_Grid->GetNumberOfCells(); ++id_cell) {
260 if (cell_marked[id_cell]) {
261 new_cells.append(id_cell);
264 setCells(new_cells);
265 } else {
266 EG_VTKSP(vtkUnstructuredGrid, new_grid);
267 QVector<vtkIdType> pnode2node(part.m_Grid->GetNumberOfPoints());
268 vtkIdType N = m_Grid->GetNumberOfPoints();
269 for (vtkIdType id_pnode = 0; id_pnode < part.m_Grid->GetNumberOfPoints(); ++id_pnode) {
270 pnode2node[id_pnode] = N;
271 ++N;
273 allocateGrid(new_grid, m_Grid->GetNumberOfCells() + part.m_Cells.size(), N);
274 for (vtkIdType id_node = 0; id_node < m_Grid->GetNumberOfPoints(); ++id_node) {
275 vec3_t x;
276 m_Grid->GetPoint(id_node, x.data());
277 new_grid->GetPoints()->SetPoint(id_node, x.data());
278 copyNodeData(m_Grid, id_node, new_grid, id_node);
280 QVector<vtkIdType> part_nodes;
281 getNodesFromCells(part.m_Cells, part_nodes, part.m_Grid);
282 foreach (vtkIdType id_pnode, part_nodes) {
283 vec3_t x;
284 part.m_Grid->GetPoint(id_pnode, x.data());
285 new_grid->GetPoints()->SetPoint(pnode2node[id_pnode], x.data());
286 copyNodeData(part.m_Grid, id_pnode, new_grid, pnode2node[id_pnode]);
288 QList<vtkIdType> new_cells;
289 for (vtkIdType id_cell = 0; id_cell < m_Grid->GetNumberOfCells(); ++id_cell) {
290 vtkIdType id_new_cell = copyCell(m_Grid, id_cell, new_grid);
291 copyCellData(m_Grid, id_cell, new_grid, id_new_cell);
292 new_cells.append(id_new_cell);
294 foreach (vtkIdType id_pcell, part.m_Cells) {
295 vtkIdType id_new_cell = copyCell(part.m_Grid, id_pcell, new_grid, pnode2node);
296 copyCellData(part.m_Grid, id_pcell, new_grid, id_new_cell);
297 new_cells.append(id_new_cell);
299 makeCopy(new_grid, m_Grid);
303 double MeshPartition::getSmallestEdgeLength() const
305 double L = 1e99;
306 foreach (vtkIdType id_cell, m_Cells) {
307 vtkIdType type_cell = m_Grid->GetCellType(id_cell);
308 vtkIdType N_pts, *pts;
309 m_Grid->GetCellPoints(id_cell, N_pts, pts);
310 QVector<vec3_t> x(N_pts);
311 for (int i = 0; i < N_pts; ++i) {
312 m_Grid->GetPoint(pts[i], x[i].data());
314 if (type_cell == VTK_TRIANGLE) {
315 L = min(L, (x[0] - x[1]).abs());
316 L = min(L, (x[1] - x[2]).abs());
317 L = min(L, (x[2] - x[0]).abs());
318 } else if (type_cell == VTK_QUAD) {
319 L = min(L, (x[0] - x[1]).abs());
320 L = min(L, (x[1] - x[2]).abs());
321 L = min(L, (x[2] - x[3]).abs());
322 L = min(L, (x[3] - x[0]).abs());
323 } else if (type_cell == VTK_TETRA) {
324 L = min(L, (x[0] - x[1]).abs());
325 L = min(L, (x[1] - x[2]).abs());
326 L = min(L, (x[2] - x[0]).abs());
327 L = min(L, (x[3] - x[0]).abs());
328 L = min(L, (x[3] - x[1]).abs());
329 L = min(L, (x[3] - x[2]).abs());
330 } else if (type_cell == VTK_PYRAMID) {
331 L = min(L, (x[0] - x[1]).abs());
332 L = min(L, (x[1] - x[2]).abs());
333 L = min(L, (x[2] - x[3]).abs());
334 L = min(L, (x[3] - x[0]).abs());
335 L = min(L, (x[4] - x[0]).abs());
336 L = min(L, (x[4] - x[1]).abs());
337 L = min(L, (x[4] - x[2]).abs());
338 L = min(L, (x[4] - x[3]).abs());
339 } else if (type_cell == VTK_WEDGE) {
340 L = min(L, (x[0] - x[1]).abs());
341 L = min(L, (x[1] - x[2]).abs());
342 L = min(L, (x[2] - x[0]).abs());
343 L = min(L, (x[3] - x[4]).abs());
344 L = min(L, (x[4] - x[5]).abs());
345 L = min(L, (x[5] - x[3]).abs());
346 L = min(L, (x[0] - x[3]).abs());
347 L = min(L, (x[1] - x[4]).abs());
348 L = min(L, (x[2] - x[5]).abs());
349 } else if (type_cell == VTK_HEXAHEDRON) {
350 L = min(L, (x[0] - x[1]).abs());
351 L = min(L, (x[1] - x[2]).abs());
352 L = min(L, (x[2] - x[3]).abs());
353 L = min(L, (x[3] - x[0]).abs());
354 L = min(L, (x[4] - x[5]).abs());
355 L = min(L, (x[5] - x[6]).abs());
356 L = min(L, (x[6] - x[7]).abs());
357 L = min(L, (x[7] - x[4]).abs());
358 L = min(L, (x[0] - x[4]).abs());
359 L = min(L, (x[1] - x[5]).abs());
360 L = min(L, (x[2] - x[6]).abs());
361 L = min(L, (x[3] - x[7]).abs());
364 return L;
367 bool MeshPartition::hasNeighNode(vtkIdType id_node, vtkIdType id_neigh)
369 for (int i = 0; i < n2nGSize(id_node); ++i) {
370 if (n2nGG(id_node, i) == id_neigh) {
371 return true;
374 return false;
377 void MeshPartition::createNodeToBC()
379 EG_VTKDCC(vtkIntArray, cell_code, m_Grid, "cell_code");
380 m_N2BC.resize(m_Nodes.size());
381 for (int i_node = 0; i_node < m_Nodes.size(); ++i_node) {
382 QSet<int> bcs;
383 for (int j = 0; j < n2cLSize(i_node); ++j) {
384 vtkIdType id_cell = n2cLG(i_node, j);
385 if (isSurface(id_cell, m_Grid)) {
386 int bc = cell_code->GetValue(n2cLG(i_node, j));
387 if (bc != 0) {
388 bcs.insert(cell_code->GetValue(n2cLG(i_node, j)));
392 m_N2BC[i_node].resize(bcs.size());
393 int i = 0;
394 foreach (int bc, bcs) {
395 m_N2BC[i_node][i++] = bc;
400 bool MeshPartition::hasBC(vtkIdType id_node, int bc)
402 bool found = false;
403 for (int j = 0; j < n2bcGSize(id_node); ++j) {
404 if (n2bcG(id_node, j) == bc) {
405 found = true;
406 break;
409 return found;
412 vtkIdType MeshPartition::getVolumeCell(vtkIdType id_face)
414 checkLNodes();
415 checkLCells();
416 checkN2C();
417 return findVolumeCell(m_Grid, id_face, m_LNodes, m_Cells, m_LCells, m_N2C);
420 vec3_t MeshPartition::globalNormal(vtkIdType id_node)
422 vec3_t normal(0,0,0);
423 for (int i = 0; i < n2cGSize(id_node); ++i) {
424 vtkIdType id_cell = n2cGG(id_node, i);
425 if (isSurface(id_cell, m_Grid)) {
426 vtkIdType N_pts, *pts;
427 m_Grid->GetCellPoints(id_cell, N_pts, pts);
428 vec3_t a, b, c;
429 for (int j = 0; j < N_pts; ++j) {
430 if (pts[j] == id_node) {
431 m_Grid->GetPoint(pts[j], a.data());
432 if (j > 0) {
433 m_Grid->GetPoint(pts[j-1], b.data());
434 } else {
435 m_Grid->GetPoint(pts[N_pts-1], b.data());
437 if (j < N_pts - 1) {
438 m_Grid->GetPoint(pts[j+1], c.data());
439 } else {
440 m_Grid->GetPoint(pts[0], c.data());
444 vec3_t u = b - a;
445 vec3_t v = c - a;
446 double alpha = GeometryTools::angle(u, v);
447 vec3_t n = u.cross(v);
448 n.normalise();
449 if (checkVector(n)) {
450 normal -= alpha*n;
454 normal.normalise();
455 return normal;
458 double MeshPartition::getAverageSurfaceEdgeLength(vtkIdType id_node)
460 QSet<vtkIdType> surface_neighbours;
461 for (int i = 0; i < n2cGSize(id_node); ++i) {
462 vtkIdType id_cell = n2cGG(id_node, i);
463 if (isSurface(id_cell, m_Grid)) {
464 EG_GET_CELL(id_cell, m_Grid);
465 for (int j = 0; j < num_pts; ++j) {
466 if (pts[j] != id_node) {
467 surface_neighbours.insert(pts[j]);
472 double L = 0;
473 if (surface_neighbours.size() > 0) {
474 vec3_t x, xn;
475 m_Grid->GetPoint(id_node, x.data());
476 foreach (vtkIdType id_neigh, surface_neighbours) {
477 m_Grid->GetPoint(id_neigh, xn.data());
478 L += (x - xn).abs();
480 L /= surface_neighbours.size();
482 return L;
485 void MeshPartition::computeMinAndMaxSurfaceStencilEdgeLengths(vtkIdType id_node, double &l_min, double &l_max)
487 l_min = 1e99;
488 l_max = 0;
489 for (int i = 0; i < n2cGSize(id_node); ++i) {
490 vtkIdType id_cell = n2cGG(id_node, i);
491 if (isSurface(id_cell, m_Grid)) {
492 vtkIdType *pts, num_pts;
493 m_Grid->GetCellPoints(id_cell, num_pts, pts);
494 vec3_t x1, x2;
495 m_Grid->GetPoint(pts[num_pts - 1], x1.data());
496 for (int j = 0; j < num_pts; ++j) {
497 m_Grid->GetPoint(pts[j], x2.data());
498 double L = (x1 - x2).abs();
499 l_min = min(L, l_min);
500 l_max = max(L, l_max);
501 x1 = x2;
507 double MeshPartition::getMinSurfaceStencilEdgeLength(vtkIdType id_node)
509 double l_min, l_max;
510 computeMinAndMaxSurfaceStencilEdgeLengths(id_node, l_min, l_max);
511 return l_min;
514 double MeshPartition::getMaxSurfaceStencilEdgeLength(vtkIdType id_node)
516 double l_min, l_max;
517 computeMinAndMaxSurfaceStencilEdgeLengths(id_node, l_min, l_max);
518 return l_max;
521 int MeshPartition::getNumberOfFeatureNeighbours(vtkIdType id_node)
523 EG_VTKDCN(vtkCharArray, node_type, m_Grid, "node_type");
524 int N = 0;
525 for (int i = 0; i < n2nGSize(id_node); ++i) {
526 char type = node_type->GetValue(n2nGG(id_node, i));
527 if (type == EG_FEATURE_EDGE_VERTEX || type == EG_FEATURE_CORNER_VERTEX) {
528 ++N;
531 return N;
534 int MeshPartition::getEdgeType(vtkIdType id_node1, vtkIdType id_node2)
536 QList <vtkIdType> edge_faces;
537 getEdgeFaces(id_node1, id_node2, edge_faces);
538 int edge = 0;
539 if (edge_faces.size() == 1) {
540 edge = 2;
541 } else if (edge_faces.size() >= 2) {
542 EG_VTKDCC(vtkIntArray, cell_code, m_Grid, "cell_code");
543 QSet<int> bcs;
544 foreach (vtkIdType id_face, edge_faces) {
545 bcs.insert(cell_code->GetValue(id_face));
547 if (bcs.size() > 1) {
548 edge = 2;
549 } else {
550 edge = 1;
553 return edge;
556 int MeshPartition::computeTopoDistance(vtkIdType id_node1, vtkIdType id_node2, int max_dist, int restriction_type)
558 int dist = 0;
559 QSet<vtkIdType> candidates;
560 candidates.insert(id_node1);
561 while (dist < max_dist && !candidates.contains(id_node2)) {
562 foreach (vtkIdType id_node, candidates) {
563 for (int i = 0; i < n2nGSize(id_node); ++i) {
564 vtkIdType id_neigh = n2nGG(id_node,i);
565 if (!candidates.contains(id_neigh)) {
566 bool insert = true;
567 if (restriction_type > 0) {
568 insert = getEdgeType(id_node, id_neigh) >= restriction_type;
570 if (insert) {
571 candidates.insert(id_neigh);
576 ++dist;
578 return dist;
581 void MeshPartition::getCommonNodes(vtkIdType id_cell1, vtkIdType id_cell2, QVector<vtkIdType> &common_nodes)
583 common_nodes.clear();
584 QSet<vtkIdType> nodes1, nodes2;
585 vtkIdType num_pts, *pts;
586 m_Grid->GetCellPoints(id_cell1, num_pts, pts);
587 for (int i = 0; i < num_pts; ++i) {
588 nodes1.insert(pts[i]);
590 m_Grid->GetCellPoints(id_cell2, num_pts, pts);
591 for (int i = 0; i < num_pts; ++i) {
592 nodes2.insert(pts[i]);
594 nodes1.intersect(nodes2);
595 common_nodes.resize(nodes1.size());
596 qCopy(nodes1.begin(), nodes1.end(), common_nodes.begin());
599 bool MeshPartition::isFeatureEdge(vtkIdType id_node1, vtkIdType id_node2, double feature_angle)
601 bool is_feature_edge = false;
602 QVector<int> bcs;
603 QVector<vtkIdType> nodes(2);
604 nodes[0] = id_node1;
605 nodes[1] = id_node2;
606 getCommonBcs(nodes, bcs);
607 if (bcs.size() == 1) {
608 QList<vtkIdType> faces;
609 getEdgeFaces(id_node1, id_node2, faces);
610 if (faces.size() == 2) {
611 vec3_t n1 = cellNormal(m_Grid, faces[0]);
612 vec3_t n2 = cellNormal(m_Grid, faces[1]);
613 if (GeometryTools::angle(n1, n2) > feature_angle) {
614 EG_VTKDCN(vtkDoubleArray, cl, m_Grid, "node_meshdensity_desired");
615 CadInterface *cad = GuiMainWindow::pointer()->getCadInterface(bcs.first());
616 vec3_t x1, x2;
617 m_Grid->GetPoint(id_node1, x1.data());
618 m_Grid->GetPoint(id_node2, x2.data());
619 vec3_t x = 0.5*(x1 + x2);
620 double h = min(cl->GetValue(id_node1), cl->GetValue(id_node2));
621 vec3_t xs = cad->snapToEdge(x);
622 if ((xs - x).abs() < 0.2*h) {
623 is_feature_edge = true;
628 return is_feature_edge;
631 bool MeshPartition::isConvexNode(vtkIdType id_node)
633 int n_faces = n2cGSize(id_node);
634 if (n_faces <= 1) {
635 return false;
638 vec3_t x1, cell_centers(0,0,0), cell_normals(0,0,0);
639 m_Grid->GetPoint(id_node, x1.data());
640 for (int i = 0; i < n_faces; ++i) {
641 vtkIdType id_cell = n2cGG(id_node, i);
642 cell_centers += cellCentre(m_Grid, id_cell);
643 cell_normals += cellNormal(m_Grid, id_cell);
645 cell_centers *= 1.0/n_faces;
646 if ((x1 - cell_centers)*cell_normals.normalise() > 0) {
647 return true;
649 return false;
653 bool MeshPartition::isConvexNode(vtkIdType id_node, QVector<int> bl_codes)
655 EG_VTKDCC(vtkIntArray, cell_code, m_Grid, "cell_code");
656 int n_faces = n2cGSize(id_node);
657 if (n_faces <= 1) {
658 return false;
661 vec3_t x1, cell_centers(0,0,0), cell_normals(0,0,0);
662 m_Grid->GetPoint(id_node, x1.data());
663 int n_used = 0;
664 for (int i = 0; i < n_faces; ++i) {
665 vtkIdType id_cell = n2cGG(id_node, i);
666 if (bl_codes.contains(cell_code->GetValue(id_cell))) {
667 cell_centers += cellCentre(m_Grid, id_cell);
668 cell_normals += cellNormal(m_Grid, id_cell);
669 ++n_used;
672 if (n_used > 0) {
673 cell_centers *= 1.0/n_used;
674 if ((x1 - cell_centers)*cell_normals.normalise() > 0) {
675 return true;
678 return false;
681 void MeshPartition::calcPlanarSurfaceMetrics(double &Dh, double &A, double &P, vec3_t &x, vec3_t &n)
683 A = 0;
684 n = vec3_t(0, 0, 0);
685 x = vec3_t(0, 0, 0);
686 P = 0;
687 foreach (vtkIdType id_cell, m_Cells) {
688 if (isSurface(id_cell, m_Grid)) {
689 vtkIdType num_pts, *pts;
690 m_Grid->GetCellPoints(id_cell, num_pts, pts);
691 QVector<vec3_t> x_pt(num_pts + 1);
692 for (int i = 0; i < num_pts; ++i) {
693 m_Grid->GetPoint(pts[i], x_pt[i].data());
695 x_pt[num_pts] = x_pt[0];
696 double a = cellVA(m_Grid, id_cell);
697 A += a;
698 x += a*cellCentre(m_Grid, id_cell);
699 n += cellNormal(m_Grid, id_cell);
700 for (int i = 0; i < num_pts; ++i) {
701 if (c2cGG(id_cell, i) == -1) {
702 P += (x_pt[i+1] - x_pt[i]).abs();
707 n.normalise();
708 x *= 1.0/A;
709 Dh = 4*A/P;
712 bool MeshPartition::isPlanar(double tolerance_angle)
714 foreach (vtkIdType id_cell, m_Cells) {
715 if (!isSurface(id_cell, m_Grid)) {
716 return false;
719 double Dh, A, P;
720 vec3_t x, n0;
721 calcPlanarSurfaceMetrics(Dh, A, P, n0, x);
722 foreach (vtkIdType id_cell, m_Cells) {
723 vec3_t n = cellNormal(m_Grid, id_cell);
724 if (angle(n, n0) > tolerance_angle) {
725 return false;
728 return true;
731 void MeshPartition::setBC(int bc)
733 QList<vtkIdType> cls;
734 EG_VTKDCC(vtkIntArray, cell_code, m_Grid, "cell_code");
735 for (vtkIdType id_cell = 0; id_cell < m_Grid->GetNumberOfCells(); ++id_cell) {
736 if (cell_code->GetValue(id_cell) == bc) {
737 cls.append(id_cell);
740 setCells(cls);
743 void MeshPartition::duplicate()
745 vtkIdType old_num_cells = m_Grid->GetNumberOfCells();
746 EG_VTKSP(vtkUnstructuredGrid, new_grid);
747 extractToVtkGrid(new_grid);
748 MeshPartition new_part(new_grid, true);
749 concatenatePartition(new_part);
750 QList<vtkIdType> cells;
751 for (vtkIdType id_cell = old_num_cells; id_cell < m_Grid->GetNumberOfCells(); ++id_cell) {
752 cells << id_cell;
754 setCells(cells);
757 void MeshPartition::scale(double factor, vec3_t centre)
759 checkNodes();
760 foreach (vtkIdType id_node, m_Nodes) {
761 vec3_t x;
762 m_Grid->GetPoint(id_node, x.data());
763 x -= centre;
764 x *= factor;
765 x += centre;
766 m_Grid->GetPoints()->SetPoint(id_node, x.data());
770 void MeshPartition::translate(vec3_t v)
772 checkNodes();
773 foreach (vtkIdType id_node, m_Nodes) {
774 vec3_t x;
775 m_Grid->GetPoint(id_node, x.data());
776 x += v;
777 m_Grid->GetPoints()->SetPoint(id_node, x.data());
781 void MeshPartition::extrude(vec3_t dir, QList<double> h, BoundaryCondition extrude_bc,
782 bool force_bottom_bc, bool force_side_bc, bool force_top_bc,
783 BoundaryCondition bottom_bc, BoundaryCondition side_bc, BoundaryCondition top_bc)
785 checkNodes();
786 if (onlySurfaceCells()) {
787 QList<vtkIdType> new_cells;
788 foreach (vtkIdType id_cell, m_Cells) {
789 new_cells << id_cell;
791 vtkIdType old_num_cells = m_Grid->GetNumberOfCells();
792 extrude_bc = GuiMainWindow::pointer()->getBC(extrude_bc);
793 EG_VTKDCC(vtkIntArray, cell_code, m_Grid, "cell_code");
794 foreach (vtkIdType id_cell, m_Cells) {
795 cell_code->SetValue(id_cell, extrude_bc.getCode());
797 QSet<int> bcs;
798 bcs.insert(extrude_bc.getCode());
799 EG_VTKSP(vtkEgNormalExtrusion, extr);
800 QVector<double> y(h.size() + 1);
802 y[0] = 0;
803 int i = 1;
804 foreach (double dy, h) {
805 y[i] = y[i-1] + dy;
806 ++i;
809 extr->SetLayers(y);
810 extr->SetBoundaryCodes(bcs);
811 if (force_bottom_bc) extr->SetCustomBottomBc (bottom_bc.getCode());
812 if (force_side_bc) extr->SetCustomSideBc (side_bc.getCode());
813 if (force_top_bc) extr->SetCustomTopBc (top_bc.getCode());
814 dir.normalise();
815 extr->SetNormal(dir);
816 extr->SetFixed();
817 EG_VTKSP(vtkUnstructuredGrid,ug);
818 makeCopy(m_Grid, ug);
819 extr->SetInputData(ug);
820 extr->Update();
821 makeCopy(extr->GetOutput(), m_Grid);
822 setBC(extrude_bc.getCode());
826 bool MeshPartition::onlySurfaceCells()
828 foreach (vtkIdType id_cell, m_Cells) {
829 if (!isSurface(id_cell, m_Grid)) {
830 return false;
833 return true;
836 void MeshPartition::resetBC(QString bc_name, QString bc_type)
838 BoundaryCondition bc = GuiMainWindow::pointer()->getBC(BoundaryCondition(bc_name, bc_type));
839 EG_VTKDCC(vtkIntArray, cell_code, m_Grid, "cell_code");
840 foreach (vtkIdType id_cell, m_Cells) {
841 cell_code->SetValue(id_cell, bc.getCode());
845 void MeshPartition::writeSTL(QString file_name)
847 if (file_name.right(4).toLower() != ".stl") {
848 file_name += ".stl";
850 EG_VTKSP(vtkUnstructuredGrid, grid);
851 extractToVtkGrid(grid);
852 EG_VTKSP(vtkGeometryFilter, geometry);
853 geometry->SetInputData(grid);
854 EG_VTKSP(vtkTriangleFilter, triangle);
855 triangle->SetInputConnection(geometry->GetOutputPort());
856 EG_VTKSP(vtkSTLWriter, stl);
857 stl->SetInputConnection( triangle->GetOutputPort());
858 stl->SetFileName(qPrintable(file_name));
859 stl->SetFileTypeToBinary();
860 stl->Write();