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 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
21 #include "fixcadgeometry.h"
23 #include "surfacemesher.h"
24 #include "vertexmeshdensity.h"
25 #include "guimainwindow.h"
26 #include "deletestraynodes.h"
27 #include "correctsurfaceorientation.h"
28 #include "swaptriangles.h"
32 #include "geometrytools.h"
33 using namespace GeometryTools
;
39 FixCadGeometry::FixCadGeometry()
42 m_PerformGeometricTests
= true;
43 m_UseProjectionForSmoothing
= false;
44 m_UseNormalCorrectionForSmoothing
= true;
45 m_OriginalFeatureAngle
= m_FeatureAngle
;
46 m_FeatureAngle
= GeometryTools::deg2rad(0.5);
47 m_AllowFeatureEdgeSwapping
= false;
48 m_AllowSmallAreaSwapping
= true;
49 m_NumDelaunaySweeps
= 1;
52 void FixCadGeometry::callMesher()
55 if (m_BoundaryCodes
.size() == 0) {
58 EG_VTKDCN(vtkDoubleArray
, characteristic_length_desired
, m_Grid
, "node_meshdensity_desired");
59 for (vtkIdType id_node
= 0; id_node
< m_Grid
->GetNumberOfPoints(); ++id_node
) {
60 characteristic_length_desired
->SetValue(id_node
, 1e-6);
69 swap
.setRespectBC(true);
70 swap
.setFeatureSwap(m_AllowFeatureEdgeSwapping
);
71 swap
.setFeatureAngle(m_FeatureAngle
);
72 swap
.setMaxNumLoops(1);
73 swap
.setSmallAreaSwap(m_AllowSmallAreaSwapping
);
74 swap
.setDelaunayThreshold(1e6
);
76 QSet
<int> rest_bcs
= GuiMainWindow::pointer()->getAllBoundaryCodes();
77 rest_bcs
-= m_BoundaryCodes
;
78 swap
.setBoundaryCodes(rest_bcs
);
81 if (swap
.getNumSwaps() == 0 || count
>= 100) {
89 cout << "CAD fix iteration " << iter << ":" << endl;
91 customUpdateNodeInfo();
93 int num_deleted = deleteNodes();
94 cout << " deleted nodes : " << num_deleted << endl;
97 done = (iter >= 20) || (num_deleted == 0);
98 cout << " total nodes : " << m_Grid->GetNumberOfPoints() << endl;
99 cout << " total cells : " << m_Grid->GetNumberOfCells() << endl;
102 createIndices(m_Grid
);
103 customUpdateNodeInfo();
107 void FixCadGeometry::setDesiredLength(double L
)
109 setAllSurfaceCells();
110 l2g_t nodes
= getPartNodes();
112 EG_VTKDCN(vtkDoubleArray
, characteristic_length_desired
, m_Grid
, "node_meshdensity_desired");
113 EG_VTKDCN(vtkIntArray
, characteristic_length_specified
, m_Grid
, "node_specified_density");
115 for (int i_nodes
= 0; i_nodes
< nodes
.size(); ++i_nodes
) {
116 vtkIdType id_node
= nodes
[i_nodes
];
117 characteristic_length_specified
->SetValue(id_node
, 0);
118 characteristic_length_desired
->SetValue(id_node
, L
);
122 void FixCadGeometry::customUpdateNodeInfo()
124 cout
<< "updating node information ..." << endl
;
126 EG_VTKDCN(vtkCharArray_t
, node_type
, m_Grid
, "node_type");
127 l2g_t cells
= getPartCells();
128 for (vtkIdType id_node
= 0; id_node
< m_Grid
->GetNumberOfPoints(); ++id_node
) {
129 node_type
->SetValue(id_node
, EG_FIXED_VERTEX
);
131 foreach (vtkIdType id_cell
, cells
) {
132 if (isSurface(id_cell
, m_Grid
)) {
133 EG_GET_CELL(id_cell
, m_Grid
);
135 vec3_t n1
= cellNormal(m_Grid
, id_cell
);
136 QVector
<int> num_bad_edges(3, 0);
137 for (int i
= 0; i
< num_pts
; ++i
) {
140 if (i
< num_pts
- 1) {
144 m_Grid
->GetPoint(pts
[i1
], x1
.data());
145 m_Grid
->GetPoint(pts
[i2
], x2
.data());
146 double L
= (x1
- x2
).abs();
147 vtkIdType id_neigh_cell
= m_Part
.c2cGG(id_cell
, i
);
148 if (id_neigh_cell
!= -1) {
149 bool bad_edge
= false;
150 vec3_t n2
= cellNormal(m_Grid
, id_neigh_cell
);
151 if (angle(n1
, n2
) > deg2rad(179.5)) {
160 for (int i
= 0; i
< num_pts
; ++i
) {
161 if (num_bad_edges
[i
] >= 2) {
162 node_type
->SetValue(pts
[i
], EG_SIMPLE_VERTEX
);
168 cout
<< "done." << endl
;
171 void FixCadGeometry::copyFaces(const QVector
<bool> ©_face
)
174 for (vtkIdType id_cell
= 0; id_cell
< m_Grid
->GetNumberOfCells(); ++id_cell
) {
175 if (!copy_face
[id_cell
]) {
179 int N_cells
= m_Grid
->GetNumberOfCells() - N_del
;
181 QVector
<bool> copy_node(m_Grid
->GetNumberOfPoints(), false);
182 for (vtkIdType id_node
= 0; id_node
< m_Grid
->GetNumberOfPoints(); ++id_node
) {
183 for (int i
= 0; i
< m_Part
.n2cGSize(id_node
); ++i
) {
184 if (copy_face
[m_Part
.n2cGG(id_node
, i
)]) {
185 copy_node
[id_node
] = true;
191 EG_VTKSP(vtkUnstructuredGrid
, new_grid
);
192 allocateGrid(new_grid
, N_cells
, N_nodes
);
193 QVector
<vtkIdType
> old2new(m_Grid
->GetNumberOfPoints(), -1);
194 vtkIdType id_new_node
= 0;
195 for (vtkIdType id_node
= 0; id_node
< m_Grid
->GetNumberOfPoints(); ++id_node
) {
196 if (copy_node
[id_node
]) {
197 old2new
[id_node
] = id_new_node
;
199 m_Grid
->GetPoint(id_node
, x
.data());
200 new_grid
->GetPoints()->SetPoint(id_new_node
, x
.data());
201 copyNodeData(m_Grid
, id_node
, new_grid
, id_new_node
);
205 for (vtkIdType id_cell
= 0; id_cell
< m_Grid
->GetNumberOfCells(); ++id_cell
) {
206 if (copy_face
[id_cell
]) {
207 EG_GET_CELL(id_cell
, m_Grid
);
208 vtkIdType id_new_cell
= new_grid
->InsertNextCell(m_Grid
->GetCellType(id_cell
), ptIds
);
209 copyCellData(m_Grid
, id_cell
, new_grid
, id_new_cell
);
212 makeCopy(new_grid
, m_Grid
);
213 cout
<< " deleted " << N_del
<< " faces" << endl
;
216 void FixCadGeometry::fixNonManifold1()
218 cout
<< "fixing non-manifold edges\n (pass 1) ..." << endl
;
219 QVector
<bool> copy_face(m_Grid
->GetNumberOfCells(), true);
220 for (vtkIdType id_cell
= 0; id_cell
< m_Grid
->GetNumberOfCells(); ++id_cell
) {
221 for (int i
= 0; i
< m_Part
.c2cGSize(id_cell
); ++i
) {
222 if (m_Part
.c2cGG(id_cell
, i
) == -1) {
223 copy_face
[id_cell
] = false;
228 copyFaces(copy_face
);
229 cout
<< "done." << endl
;
232 void FixCadGeometry::fixNonManifold2()
234 cout
<< "fixing non-manifold edges\n (pass 2) ..." << endl
;
235 QVector
<bool> copy_face(m_Grid
->GetNumberOfCells(), true);
236 for (vtkIdType id_cell
= 0; id_cell
< m_Grid
->GetNumberOfCells(); ++id_cell
) {
237 EG_GET_CELL(id_cell
, m_Grid
);
239 copy_face
[id_cell
] = false;
242 QVector
<QSet
<vtkIdType
> > n2c(num_pts
);
243 for (int i
= 0; i
< num_pts
; ++i
) {
244 for (int j
= 0; j
< m_Part
.n2cGSize(pts
[i
]); ++j
) {
245 n2c
[i
].insert(m_Part
.n2cGG(pts
[i
], j
));
248 QSet
<vtkIdType
> faces
= n2c
[0];
249 for (int i
= 1; i
< num_pts
; ++i
) {
250 faces
= faces
.intersect(n2c
[i
]);
252 if (faces
.size() > 1) {
253 vtkIdType id_del
= id_cell
;
254 foreach (vtkIdType id
, faces
) {
255 id_del
= min(id_del
, id
);
257 copy_face
[id_del
] = false;
260 copyFaces(copy_face
);
261 cout
<< "done." << endl
;
264 void FixCadGeometry::markNonManifold()
266 cout
<< "marking non-manifold edges\n" << endl
;
268 m_NumNonManifold
= 0;
269 EG_VTKDCC(vtkIntArray
, cell_code
, m_Grid
, "cell_code");
270 QVector
<bool> nm_face(m_Grid
->GetNumberOfCells(), false);
271 for (vtkIdType id_cell
= 0; id_cell
< m_Grid
->GetNumberOfCells(); ++id_cell
) {
272 if (isSurface(id_cell
, m_Grid
)) {
273 new_bc
= max(new_bc
, cell_code
->GetValue(id_cell
));
274 EG_GET_CELL(id_cell
, m_Grid
);
275 for (int i
= 0; i
< num_pts
; ++i
) {
276 QSet
<vtkIdType
> edge_cells
;
278 if (i
< num_pts
- 1) {
279 N
= getEdgeCells(pts
[i
], pts
[i
+1], edge_cells
);
281 N
= getEdgeCells(pts
[i
], pts
[0], edge_cells
);
284 nm_face
[id_cell
] = true;
291 m_BoundaryCodes
= GuiMainWindow::pointer()->getAllBoundaryCodes();
292 foreach (int bc
, m_BoundaryCodes
) {
294 QString bc_name
= "NM_" + GuiMainWindow::pointer()->getBC(bc
).getName();
295 for (int level
= 0; level
< 2; ++level
) {
296 QVector
<bool> new_nm_face
= nm_face
;
297 for (vtkIdType id_cell
= 0; id_cell
< m_Grid
->GetNumberOfCells(); ++id_cell
) {
298 if (isSurface(id_cell
, m_Grid
)) {
299 if ((cell_code
->GetValue(id_cell
)) == bc
&& nm_face
[id_cell
]) {
300 EG_GET_CELL(id_cell
, m_Grid
);
301 for (int i
= 0; i
< num_pts
; ++i
) {
302 for (int j
= 0; j
< m_Part
.n2cGSize(pts
[i
]); ++j
) {
303 vtkIdType id_neigh
= m_Part
.n2cGG(pts
[i
], j
);
304 if (cell_code
->GetValue(id_neigh
) == bc
) {
305 new_nm_face
[id_neigh
] = true;
312 nm_face
= new_nm_face
;
314 GuiMainWindow::pointer()->setBC(new_bc
, BoundaryCondition(bc_name
, "patch", new_bc
));
315 for (vtkIdType id_cell
= 0; id_cell
< m_Grid
->GetNumberOfCells(); ++id_cell
) {
316 if (isSurface(id_cell
, m_Grid
)) {
317 if (cell_code
->GetValue(id_cell
) == bc
&& nm_face
[id_cell
]) {
318 cell_code
->SetValue(id_cell
, new_bc
);
323 GuiMainWindow::pointer()->updateBoundaryCodes(true);
324 cout
<< "done." << endl
;
327 void FixCadGeometry::operate()
330 DeleteStrayNodes del
;
337 if (m_NumNonManifold
== 0) {
340 EG_VTKDCC(vtkIntArray
, bc
, m_Grid
, "cell_code");
342 l2g_t cells
= m_Part
.getCells();
343 foreach (vtkIdType id_cell
, cells
) {
344 if (isSurface(id_cell
, m_Grid
)) {
345 bcs
.insert(bc
->GetValue(id_cell
));
348 QMap
<int,int> BCmap
;
349 foreach(int bc
, bcs
) {
353 //set density infinite
354 VertexMeshDensity VMD
;
357 qWarning()<<"VMD.BCmap="<<VMD
.BCmap
;
358 m_VMDvector
.push_back(VMD
);
360 customUpdateNodeInfo();
362 // fix non manifold edges
366 //call surface mesher
368 setBoundaryCodes(bcs
);
369 setVertexMeshDensityVector(m_VMDvector
);
375 // correct surface orientation
376 CorrectSurfaceOrientation correct;
377 correct.setGrid(m_Grid);
378 correct.setAllCells();
384 m_FeatureAngle
= m_OriginalFeatureAngle
;
385 createIndices(m_Grid
);
386 EG_VTKDCN(vtkCharArray_t
, node_type
, m_Grid
, "node_type");
387 for (vtkIdType id_node
= 0; id_node
< m_Grid
->GetNumberOfPoints(); ++id_node
) {
388 node_type
->SetValue(id_node
, EG_SIMPLE_VERTEX
);