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"
22 #include "surfacemesher.h"
23 #include "vertexmeshdensity.h"
24 #include "guimainwindow.h"
25 #include "deletestraynodes.h"
26 #include "correctsurfaceorientation.h"
27 #include "swaptriangles.h"
31 #include "geometrytools.h"
32 using namespace GeometryTools
;
38 FixCadGeometry::FixCadGeometry()
41 m_PerformGeometricTests
= true;
42 m_UseProjectionForSmoothing
= false;
43 m_UseNormalCorrectionForSmoothing
= true;
44 m_OriginalFeatureAngle
= m_FeatureAngle
;
45 m_FeatureAngle
= GeometryTools::deg2rad(0.5);
46 m_AllowFeatureEdgeSwapping
= false;
47 m_AllowSmallAreaSwapping
= true;
48 m_NumDelaunaySweeps
= 1;
51 void FixCadGeometry::callMesher()
54 if (m_BoundaryCodes
.size() == 0) {
57 EG_VTKDCN(vtkDoubleArray
, characteristic_length_desired
, m_Grid
, "node_meshdensity_desired");
58 for (vtkIdType id_node
= 0; id_node
< m_Grid
->GetNumberOfPoints(); ++id_node
) {
59 characteristic_length_desired
->SetValue(id_node
, 1e-6);
68 swap
.setRespectBC(true);
69 swap
.setFeatureSwap(m_AllowFeatureEdgeSwapping
);
70 swap
.setFeatureAngle(m_FeatureAngle
);
71 swap
.setMaxNumLoops(1);
72 swap
.setSmallAreaSwap(m_AllowSmallAreaSwapping
);
73 swap
.setDelaunayThreshold(1e6
);
75 QSet
<int> rest_bcs
= GuiMainWindow::pointer()->getAllBoundaryCodes();
76 rest_bcs
-= m_BoundaryCodes
;
77 swap
.setBoundaryCodes(rest_bcs
);
80 if (swap
.getNumSwaps() == 0 || count
>= 100) {
88 cout << "CAD fix iteration " << iter << ":" << endl;
90 customUpdateNodeInfo();
92 int num_deleted = deleteNodes();
93 cout << " deleted nodes : " << num_deleted << endl;
96 done = (iter >= 20) || (num_deleted == 0);
97 cout << " total nodes : " << m_Grid->GetNumberOfPoints() << endl;
98 cout << " total cells : " << m_Grid->GetNumberOfCells() << endl;
101 createIndices(m_Grid
);
102 customUpdateNodeInfo();
106 void FixCadGeometry::setDesiredLength(double L
)
108 setAllSurfaceCells();
109 l2g_t nodes
= getPartNodes();
111 EG_VTKDCN(vtkDoubleArray
, characteristic_length_desired
, m_Grid
, "node_meshdensity_desired");
112 EG_VTKDCN(vtkIntArray
, characteristic_length_specified
, m_Grid
, "node_specified_density");
114 for (int i_nodes
= 0; i_nodes
< nodes
.size(); ++i_nodes
) {
115 vtkIdType id_node
= nodes
[i_nodes
];
116 characteristic_length_specified
->SetValue(id_node
, 0);
117 characteristic_length_desired
->SetValue(id_node
, L
);
121 void FixCadGeometry::customUpdateNodeInfo()
123 cout
<< "updating node information ..." << endl
;
125 EG_VTKDCN(vtkCharArray
, node_type
, m_Grid
, "node_type");
126 l2g_t cells
= getPartCells();
127 for (vtkIdType id_node
= 0; id_node
< m_Grid
->GetNumberOfPoints(); ++id_node
) {
128 node_type
->SetValue(id_node
, EG_FIXED_VERTEX
);
130 foreach (vtkIdType id_cell
, cells
) {
131 if (isSurface(id_cell
, m_Grid
)) {
132 vtkIdType N_pts
, *pts
;
133 m_Grid
->GetCellPoints(id_cell
, N_pts
, pts
);
135 vec3_t n1
= cellNormal(m_Grid
, id_cell
);
136 QVector
<int> num_bad_edges(3, 0);
137 for (int i
= 0; i
< N_pts
; ++i
) {
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
< N_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 vtkIdType N_pts
, *pts
;
208 m_Grid
->GetCellPoints(id_cell
, N_pts
, pts
);
209 vtkIdType id_new_cell
= new_grid
->InsertNextCell(m_Grid
->GetCellType(id_cell
), N_pts
, pts
);
210 copyCellData(m_Grid
, id_cell
, new_grid
, id_new_cell
);
213 makeCopy(new_grid
, m_Grid
);
214 cout
<< " deleted " << N_del
<< " faces" << endl
;
217 void FixCadGeometry::fixNonManifold1()
219 cout
<< "fixing non-manifold edges\n (pass 1) ..." << endl
;
220 QVector
<bool> copy_face(m_Grid
->GetNumberOfCells(), true);
221 for (vtkIdType id_cell
= 0; id_cell
< m_Grid
->GetNumberOfCells(); ++id_cell
) {
222 for (int i
= 0; i
< m_Part
.c2cGSize(id_cell
); ++i
) {
223 if (m_Part
.c2cGG(id_cell
, i
) == -1) {
224 copy_face
[id_cell
] = false;
229 copyFaces(copy_face
);
230 cout
<< "done." << endl
;
233 void FixCadGeometry::fixNonManifold2()
235 cout
<< "fixing non-manifold edges\n (pass 2) ..." << endl
;
236 QVector
<bool> copy_face(m_Grid
->GetNumberOfCells(), true);
237 for (vtkIdType id_cell
= 0; id_cell
< m_Grid
->GetNumberOfCells(); ++id_cell
) {
238 vtkIdType N_pts
, *pts
;
239 m_Grid
->GetCellPoints(id_cell
, N_pts
, pts
);
241 copy_face
[id_cell
] = false;
244 QVector
<QSet
<vtkIdType
> > n2c(N_pts
);
245 for (int i
= 0; i
< N_pts
; ++i
) {
246 for (int j
= 0; j
< m_Part
.n2cGSize(pts
[i
]); ++j
) {
247 n2c
[i
].insert(m_Part
.n2cGG(pts
[i
], j
));
250 QSet
<vtkIdType
> faces
= n2c
[0];
251 for (int i
= 1; i
< N_pts
; ++i
) {
252 faces
= faces
.intersect(n2c
[i
]);
254 if (faces
.size() > 1) {
255 vtkIdType id_del
= id_cell
;
256 foreach (vtkIdType id
, faces
) {
257 id_del
= min(id_del
, id
);
259 copy_face
[id_del
] = false;
262 copyFaces(copy_face
);
263 cout
<< "done." << endl
;
266 void FixCadGeometry::markNonManifold()
268 cout
<< "marking non-manifold edges\n" << endl
;
270 m_NumNonManifold
= 0;
271 EG_VTKDCC(vtkIntArray
, cell_code
, m_Grid
, "cell_code");
272 QVector
<bool> nm_face(m_Grid
->GetNumberOfCells(), false);
273 for (vtkIdType id_cell
= 0; id_cell
< m_Grid
->GetNumberOfCells(); ++id_cell
) {
274 if (isSurface(id_cell
, m_Grid
)) {
275 new_bc
= max(new_bc
, cell_code
->GetValue(id_cell
));
276 vtkIdType N_pts
, *pts
;
277 m_Grid
->GetCellPoints(id_cell
, N_pts
, pts
);
278 for (int i
= 0; i
< N_pts
; ++i
) {
279 QSet
<vtkIdType
> edge_cells
;
282 N
= getEdgeCells(pts
[i
], pts
[i
+1], edge_cells
);
284 N
= getEdgeCells(pts
[i
], pts
[0], edge_cells
);
287 nm_face
[id_cell
] = true;
294 m_BoundaryCodes
= GuiMainWindow::pointer()->getAllBoundaryCodes();
295 foreach (int bc
, m_BoundaryCodes
) {
297 QString bc_name
= "NM_" + GuiMainWindow::pointer()->getBC(bc
).getName();
298 for (int level
= 0; level
< 2; ++level
) {
299 QVector
<bool> new_nm_face
= nm_face
;
300 for (vtkIdType id_cell
= 0; id_cell
< m_Grid
->GetNumberOfCells(); ++id_cell
) {
301 if (isSurface(id_cell
, m_Grid
)) {
302 if ((cell_code
->GetValue(id_cell
)) == bc
&& nm_face
[id_cell
]) {
303 vtkIdType N_pts
, *pts
;
304 m_Grid
->GetCellPoints(id_cell
, N_pts
, pts
);
305 for (int i
= 0; i
< N_pts
; ++i
) {
306 for (int j
= 0; j
< m_Part
.n2cGSize(pts
[i
]); ++j
) {
307 vtkIdType id_neigh
= m_Part
.n2cGG(pts
[i
], j
);
308 if (cell_code
->GetValue(id_neigh
) == bc
) {
309 new_nm_face
[id_neigh
] = true;
316 nm_face
= new_nm_face
;
318 GuiMainWindow::pointer()->setBC(new_bc
, BoundaryCondition(bc_name
, "patch", new_bc
));
319 for (vtkIdType id_cell
= 0; id_cell
< m_Grid
->GetNumberOfCells(); ++id_cell
) {
320 if (isSurface(id_cell
, m_Grid
)) {
321 if (cell_code
->GetValue(id_cell
) == bc
&& nm_face
[id_cell
]) {
322 cell_code
->SetValue(id_cell
, new_bc
);
327 GuiMainWindow::pointer()->updateBoundaryCodes(true);
328 cout
<< "done." << endl
;
331 void FixCadGeometry::operate()
334 DeleteStrayNodes del
;
341 if (m_NumNonManifold
== 0) {
344 EG_VTKDCC(vtkIntArray
, bc
, m_Grid
, "cell_code");
346 l2g_t cells
= m_Part
.getCells();
347 foreach (vtkIdType id_cell
, cells
) {
348 if (isSurface(id_cell
, m_Grid
)) {
349 bcs
.insert(bc
->GetValue(id_cell
));
352 QMap
<int,int> BCmap
;
353 foreach(int bc
, bcs
) {
357 //set density infinite
358 VertexMeshDensity VMD
;
361 qWarning()<<"VMD.BCmap="<<VMD
.BCmap
;
362 m_VMDvector
.push_back(VMD
);
364 customUpdateNodeInfo();
366 // fix non manifold edges
370 //call surface mesher
372 setBoundaryCodes(bcs
);
373 setVertexMeshDensityVector(m_VMDvector
);
379 // correct surface orientation
380 CorrectSurfaceOrientation correct;
381 correct.setGrid(m_Grid);
382 correct.setAllCells();
388 m_FeatureAngle
= m_OriginalFeatureAngle
;
389 createIndices(m_Grid
);
390 EG_VTKDCN(vtkCharArray
, node_type
, m_Grid
, "node_type");
391 for (vtkIdType id_node
= 0; id_node
< m_Grid
->GetNumberOfPoints(); ++id_node
) {
392 node_type
->SetValue(id_node
, EG_SIMPLE_VERTEX
);