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 "polymolecule.h"
23 #include "guimainwindow.h"
25 #include <vtkUnstructuredGridWriter.h>
26 #include <vtkGeometryFilter.h>
27 #include <vtkXMLPolyDataWriter.h>
28 #include <vtkDelaunay3D.h>
30 #include <vtkTriangleFilter.h>
32 PolyMolecule::PolyMolecule()
34 m_AllPositive
= false;
40 PolyMolecule::PolyMolecule(PolyMesh
*poly_mesh
, int i_pcell
)
43 QVector
<QList
<int> > faces(poly_mesh
->numFacesOfPCell(i_pcell
));
44 for (int i
= 0; i
< poly_mesh
->numFacesOfPCell(i_pcell
); ++i
) {
45 int i_face
= poly_mesh
->pcell2Face(i_pcell
, i
);
46 m_FacesInPMesh
.append(i_face
);
47 int num_nodes
= poly_mesh
->numNodes(i_face
);
48 for (int j
= 0; j
< num_nodes
; ++j
) {
49 int node
= poly_mesh
->nodeIndex(i_face
, j
);
50 if (poly_mesh
->owner(i_face
) == i_pcell
) {
51 faces
[i
].append(node
);
53 faces
[i
].prepend(node
);
57 m_AllPositive
= false;
60 init(poly_mesh
, faces
);
63 void PolyMolecule::writeVtkFile(QString file_name
)
65 EG_VTKSP(vtkUnstructuredGrid
, grid
);
66 allocateGrid(grid
, m_Faces
.size(), m_Nodes
.size());
68 EG_VTKSP(vtkDoubleArray
, normals
);
69 normals
->SetNumberOfComponents(3);
70 normals
->SetNumberOfTuples(m_Nodes
.size());
71 normals
->SetName("N");
73 EG_VTKSP(vtkDoubleArray
, badness
);
74 badness
->SetNumberOfComponents(1);
75 badness
->SetNumberOfTuples(m_Nodes
.size());
76 badness
->SetName("badness");
78 for (int i
= 0; i
< m_Nodes
.size(); ++i
) {
79 vec3_t x
= getXNode(i
);
80 grid
->GetPoints()->SetPoint(i
, x
.data());
81 normals
->SetTuple(i
, m_NodeNormals
[i
].data());
82 badness
->SetValue(i
, double(m_N2BadFaces
[i
].size()));
84 grid
->GetPointData()->AddArray(normals
);
85 grid
->GetPointData()->AddArray(badness
);
87 for (int i
= 0; i
< m_Faces
.size(); ++i
) {
88 QVector
<vtkIdType
> pts(m_Faces
[i
].size());
89 for (int j
= 0; j
< m_Faces
[i
].size(); ++j
) {
90 pts
[j
] = m_Faces
[i
][j
];
92 grid
->InsertNextCell(VTK_POLYGON
, m_Faces
[i
].size(), pts
.data());
94 EG_VTKSP(vtkXMLUnstructuredGridWriter
, vtu
);
95 file_name
= GuiMainWindow::pointer()->getCwd() + "/" + file_name
+ ".vtu";
96 vtu
->SetFileName(qPrintable(file_name
));
97 vtu
->SetDataModeToBinary();
98 vtu
->SetInputData(grid
);
102 void PolyMolecule::createPolyData(vtkPolyData
*poly_data
)
104 int N
= m_Nodes
.size();
105 EG_VTKSP(vtkPoints
, points
);
106 points
->SetNumberOfPoints(N
);
107 for (int i
= 0; i
< N
; ++i
) {
108 vec3_t x
= getXNode(i
);
109 points
->SetPoint(i
, x
.data());
111 poly_data
->Allocate(m_Faces
.size());
112 poly_data
->SetPoints(points
);
113 for (int i
= 0; i
< m_Faces
.size(); ++i
) {
114 QVector
<vtkIdType
> pts(m_Faces
[i
].size());
115 for (int j
= 0; j
< m_Faces
[i
].size(); ++j
) {
116 pts
[j
] = m_Faces
[i
][j
];
118 if (pts
.size() == 3) {
119 poly_data
->InsertNextCell(VTK_TRIANGLE
, pts
.size(), pts
.data());
120 } else if (pts
.size() == 4) {
121 poly_data
->InsertNextCell(VTK_QUAD
, pts
.size(), pts
.data());
123 poly_data
->InsertNextCell(VTK_POLYGON
, pts
.size(), pts
.data());
128 void PolyMolecule::computeCentreOfGravity()
130 m_AllPositive
= true;
131 // first guess of centre of gravity
132 vec3_t
x_centre(0,0,0);
133 for (int i
= 0; i
< m_Faces
.size(); ++i
) {
134 x_centre
+= getXFace(i
);
136 m_N2BadFaces
.resize(m_Nodes
.size());
137 for (int i
= 0; i
< m_Nodes
.size(); ++i
) {
138 m_N2BadFaces
[i
].clear();
140 x_centre
*= 1.0/m_Faces
.size();
141 for (int iter
= 0; iter
< 2; ++iter
) {
143 m_CentreOfGravity
= vec3_t(0,0,0);
144 m_MaxPyramidVolume
= -1e99
;
145 m_MinPyramidVolume
= 1e99
;
146 for (int i
= 0; i
< m_Faces
.size(); ++i
) {
147 double V_pyramid
= 0;
148 vec3_t x_face
= getXFace(i
);
149 QVector
<vec3_t
> x(m_Faces
[i
].size() + 1);
150 for (int j
= 0; j
< m_Faces
[i
].size(); ++j
) {
151 x
[j
] = getXNode(m_Faces
[i
][j
]);
153 x
.last() = x
.first();
154 for (int j
= 0; j
< m_Faces
[i
].size(); ++j
) {
155 double V
= GeometryTools::tetraVol(x_face
, x
[j
+1], x
[j
], x_centre
, true);
157 m_AllPositive
= false;
161 m_CentreOfGravity
+= 0.25*V
*(x_face
+ x
[j
+1] + x
[j
] + x_centre
);
163 if (V_pyramid
<= 0) {
164 for (int j
= 0; j
< m_Faces
[i
].size(); ++j
) {
165 m_N2BadFaces
[m_Faces
[i
][j
]].insert(i
);
168 m_MaxPyramidVolume
= max(V_pyramid
, m_MaxPyramidVolume
);
169 m_MinPyramidVolume
= min(V_pyramid
, m_MinPyramidVolume
);
171 m_CentreOfGravity
*= 1.0/V_total
;
172 x_centre
= m_CentreOfGravity
;
176 void PolyMolecule::buildNode2Node()
179 m_N2N
.resize(m_Nodes
.size());
180 for (int i
= 0; i
< m_Faces
.size(); ++i
) {
181 for (int j
= 0; j
< m_Faces
[i
].size() - 1; ++j
) {
182 m_N2N
[m_Faces
[i
][j
]].insert(m_Faces
[i
][j
+1]);
183 m_N2N
[m_Faces
[i
][j
+1]].insert(m_Faces
[i
][j
]);
188 void PolyMolecule::buildFace2Face()
191 m_F2F
.resize(m_Faces
.size());
192 for (int face
= 0; face
< m_Faces
.size(); ++face
) {
193 for (int i
= 0; i
< m_Faces
[face
].size(); ++i
) {
195 if (j
>= m_Faces
[face
].size()) {
198 edge_t e
= getEdge(m_Faces
[face
][i
], m_Faces
[face
][j
]);
199 if (e
.face1
!= face
) {
200 m_F2F
[face
].insert(e
.face1
);
202 if (e
.face2
!= face
) {
203 m_F2F
[face
].insert(e
.face2
);
209 void PolyMolecule::computeNormals()
211 m_FaceNormals
.fill(vec3_t(0,0,0), m_Faces
.size());
212 m_NodeNormals
.fill(vec3_t(0,0,0), m_Nodes
.size());
213 for (int i
= 0; i
< m_Faces
.size(); ++i
) {
214 QVector
<vec3_t
> x(m_Faces
[i
].size() + 1);
215 vec3_t
x_face(0,0,0);
216 for (int j
= 0; j
< m_Faces
[i
].size(); ++j
) {
217 x
[j
] = getXNode(m_Faces
[i
][j
]);
220 x
.last() = x
.first();
221 x_face
*= 1.0/m_Faces
[i
].size();
222 m_FaceNormals
[i
] = vec3_t(0,0,0);
223 for (int j
= 0; j
< m_Faces
[i
].size(); ++j
) {
224 m_FaceNormals
[i
] += triNormal(x_face
, x
[j
], x
[j
+1]);
226 for (int j
= 0; j
< m_Faces
[i
].size(); ++j
) {
227 vec3_t n
= m_FaceNormals
[i
];
229 m_NodeNormals
[m_Faces
[i
][j
]] += n
;
232 for (int i
= 0; i
< m_Nodes
.size(); ++i
) {
233 m_NodeNormals
[i
].normalise();
237 vec3_t
PolyMolecule::getXFace(int face
)
240 foreach (int i
, m_Faces
[face
]) {
243 if (m_Nodes
.size() == 0) {
246 return (1.0/m_Faces
[face
].size())*x
;
249 void PolyMolecule::smooth(bool delaunay
, bool write
)
253 writeVtkFile("bad_cell");
256 // collect all "healthy" cells in the neighbourhood
257 // they will be checked for volume inversion caused by the smoothing of this cell
259 QSet
<int> check_cells
;
260 check_cells
.insert(m_PCell
);
261 for (int i
= 0; i
< m_PolyMesh
->numFacesOfPCell(m_PCell
); ++i
) {
262 int i_face
= m_PolyMesh
->pcell2Face(m_PCell
, i
);
263 int i_cell
= m_PolyMesh
->owner(i_face
);
264 PolyMolecule
pm(m_PolyMesh
, i_cell
);
265 if (pm
.minPyramidVolume() > 0) {
266 check_cells
.insert(i_cell
);
268 i_cell
= m_PolyMesh
->neighbour(i_face
);
270 PolyMolecule
pm(m_PolyMesh
, i_cell
);
271 if (pm
.minPyramidVolume() > 0) {
272 check_cells
.insert(i_cell
);
277 // VTK pipeline to get convex hull
278 // The cell will be "inflated" into this convex hull.
280 QVector
<QVector
<vec3_t
> > convex_hull
;
282 EG_VTKSP(vtkPolyData
, poly_data
);
283 EG_VTKSP(vtkPoints
, points
);
284 points
->SetNumberOfPoints(m_Nodes
.size());
285 for (vtkIdType id_node
= 0; id_node
< m_Nodes
.size(); ++id_node
) {
286 vec3_t x
= getXNode(id_node
);
287 points
->SetPoint(id_node
, x
.data());
289 poly_data
->Allocate(m_Faces
.size());
290 poly_data
->SetPoints(points
);
291 for (int i
= 0; i
< m_Faces
.size(); ++i
) {
292 QVector
<vtkIdType
> pts(m_Faces
[i
].size());
293 for (int j
= 0; j
< m_Faces
[i
].size(); ++j
) {
294 pts
[j
] = m_Faces
[i
][j
];
296 poly_data
->InsertNextCell(VTK_POLYGON
, pts
.size(), pts
.data());
298 EG_VTKSP(vtkGeometryFilter
, surface
);
300 EG_VTKSP(vtkDelaunay3D
, delaunay
);
301 delaunay
->SetOffset(100);
302 delaunay
->SetInputData(poly_data
);
303 surface
->SetInputConnection(delaunay
->GetOutputPort());
305 EG_VTKSP(vtkHull
, hull
);
306 hull
->SetInputData(poly_data
);
307 hull
->AddRecursiveSpherePlanes(5);
308 EG_VTKSP(vtkTriangleFilter
, tri
);
309 tri
->SetInputConnection(hull
->GetOutputPort());
310 surface
->SetInputConnection(tri
->GetOutputPort());
313 if (surface
->GetOutput()->GetNumberOfCells() < 4) {
316 EG_VTKSP(vtkXMLPolyDataWriter
, vtp
);
318 QString file_name
= GuiMainWindow::pointer()->getCwd() + "/" + "convex_hull.vtp";
319 vtp
->SetFileName(qPrintable(file_name
));
320 vtp
->SetDataModeToAscii();
321 vtp
->SetInputConnection(surface
->GetOutputPort());
324 convex_hull
.fill(QVector
<vec3_t
>(3), surface
->GetOutput()->GetNumberOfCells());
325 for (vtkIdType id_tri
= 0; id_tri
< surface
->GetOutput()->GetNumberOfCells(); ++id_tri
) {
326 EG_GET_CELL(id_tri
, surface
->GetOutput());
327 if (type_cell
!= VTK_TRIANGLE
) {
330 for (int i
= 0; i
< 3; ++i
) {
332 surface
->GetOutput()->GetPoint(pts
[i
], x
.data());
333 convex_hull
[id_tri
][i
] = x
;
338 // Save old nodes for under-relaxations
340 QVector
<vec3_t
> x_old(m_Nodes
.size());
341 for (int i
= 0; i
< m_Nodes
.size(); ++i
) {
342 x_old
[i
] = getXNode(i
);
347 for (int iter
= 1; iter
<= 100; ++iter
) {
348 for (int i
= 0; i
< m_Nodes
.size(); ++i
) {
349 vec3_t x
= getXNode(i
);
350 double L
= (x
- m_CentreOfGravity
).abs();
352 vec3_t Dx_n
= 0.1*L
*m_NodeNormals
[i
];
354 foreach (int neigh
, m_N2N
[i
]) {
355 Dx_lp
+= 0.1*(getXNode(neigh
) - x
);
357 //Dx_lp -= (Dx_lp * m_NodeNormals[i])*m_NodeNormals[i];
358 vec3_t Dx
= Dx_n
+ Dx_lp
;
360 for (int j
= 0; j
< convex_hull
.size(); ++j
) {
361 vec3_t np
= triNormal(convex_hull
[j
][0], convex_hull
[j
][1], convex_hull
[j
][2]);
363 double d
= GeometryTools::intersection(x
, Dx
, convex_hull
[j
][0], np
);
364 if (d
> -1e-3 && d
< 1) {
369 for (int j
= 0; j
< convex_hull
.size(); ++j
) {
370 vec3_t np
= triNormal(convex_hull
[j
][0], convex_hull
[j
][1], convex_hull
[j
][2]);
372 double d
= GeometryTools::intersection(x
, Dx
, convex_hull
[j
][0], np
);
373 if (d
> -1e-3 && d
< 1) {
379 m_PolyMesh
->setNodeVector(m_Nodes
[i
], x
);
382 file_name
.setNum(iter
);
383 file_name
= file_name
.rightJustified(4, '0');
384 file_name
= "improved_cell." + file_name
;
385 if (write
) writeVtkFile(file_name
);
386 computeCentreOfGravity();
390 // get new state of the cell for under relaxation
392 QVector
<vec3_t
> x_new(m_Nodes
.size());
393 for (int i
= 0; i
< m_Nodes
.size(); ++i
) {
394 x_new
[i
] = getXNode(i
);
397 // check all formerly "healthy" cells and under relax as rquired
403 foreach (int i_pcell
, check_cells
) {
404 PolyMolecule
pm(m_PolyMesh
, i_pcell
);
405 if (!pm
.allPositive()) {
416 for (int i
= 0; i
< m_Nodes
.size(); ++i
) {
417 m_PolyMesh
->setNodeVector(m_Nodes
[i
], x_old
[i
] + relax
*(x_new
[i
] - x_old
[i
]));
423 if (write
) writeVtkFile("improved_cell");
426 PolyMolecule::edge_t
PolyMolecule::getEdge(int node1
, int node2
)
433 for (int i
= 0; i
< m_Faces
.size(); ++i
) {
434 for (int j
= 0; j
< m_Faces
[i
].size(); ++j
) {
435 int n1
= m_Faces
[i
][j
];
436 int n2
= m_Faces
[i
][0];
437 if (j
< m_Faces
[i
].size() - 1) {
438 n2
= m_Faces
[i
][j
+1];
440 if (n1
== node1
&& n2
== node2
) {
443 if (n1
== node2
&& n2
== node1
) {
448 if (e
.face1
== -1 || e
.face2
== -1) {
454 QList
<PolyMolecule::edge_t
> PolyMolecule::findConcaveEdges()
457 cout
<< "break" << endl
;
459 QList
<edge_t
> concave_edges
;
460 for (int node1
= 0; node1
< m_Nodes
.size(); ++node1
) {
461 foreach (int node2
, m_N2N
[node1
]) {
463 edge_t e
= getEdge(node1
, node2
);
464 vec3_t x1
= getXNode(node1
);
465 vec3_t x2
= getXNode(node2
);
466 vec3_t xe
= 0.5*(getXNode(node1
) + getXNode(node2
));
467 vec3_t xf1
= getXFace(e
.face1
);
468 vec3_t xf2
= getXFace(e
.face2
);
469 vec3_t xc
= m_CentreOfGravity
;
470 vec3_t xn
= 0.5*(xf1
+ xf2
);
471 double Lnorm
= (xf2
- xf1
).abs();
472 double L
= ((xn
- xc
).abs() - (xe
- xc
).abs())/Lnorm
;
474 concave_edges
.append(e
);
479 return concave_edges
;
482 void PolyMolecule::split(bool write
)
485 writeVtkFile("concave_cell");
489 QList
<edge_t
> concave_edges
= findConcaveEdges();
490 if (concave_edges
.size() == 0) {
493 QList
<int> seed_faces
;
494 foreach (edge_t e
, concave_edges
) {
495 if (!seed_faces
.contains(e
.face1
)) {
496 seed_faces
.append(e
.face1
);
498 if (!seed_faces
.contains(e
.face2
)) {
499 seed_faces
.append(e
.face2
);
502 if (seed_faces
.size() != concave_edges
.size() + 1) {
505 QVector
<int> old2new(m_Faces
.size());
506 int num_faces
= m_Faces
.size();
507 for (int face
= 0; face
< m_Faces
.size(); ++face
) {
508 old2new
[face
] = seed_faces
.indexOf(face
);
509 if (old2new
[face
] != -1) {
513 while (num_faces
> 0) {
514 for (int face1
= 0; face1
< m_Faces
.size(); ++face1
) {
515 if (old2new
[face1
] != -1) {
516 foreach (int face2
, m_F2F
[face1
]) {
517 if (old2new
[face2
] == -1) {
518 old2new
[face2
] = old2new
[face1
];
525 QVector
<int> new_pcell_index(seed_faces
.size());
526 new_pcell_index
[0] = m_PCell
;
527 for (int i
= 1; i
< seed_faces
.size(); ++i
) {
528 new_pcell_index
[i
] = m_PolyMesh
->numCells() + i
- 1;
530 QVector
<PolyMesh::face_t
> new_faces(concave_edges
.size());
531 QVector
<vec3_t
> new_cell_centre(seed_faces
.size(), vec3_t(0,0,0));
533 QVector
<int> count(seed_faces
.size(), 0);
534 for (int face
= 0; face
< m_Faces
.size(); ++face
) {
535 new_cell_centre
[old2new
[face
]] += getXFace(face
);
536 ++count
[old2new
[face
]];
538 for (int i
= 0; i
< new_cell_centre
.size(); ++i
) {
542 new_cell_centre
[i
] *= 1.0/count
[i
];
545 for (int i
= 0; i
< concave_edges
.size(); ++i
) {
546 edge_t e
= concave_edges
[i
];
549 new_faces
[i
].node
.append(m_Nodes
[e
.node1
]);
550 int o2n1
= old2new
[e
.face1
];
551 int o2n2
= old2new
[e
.face2
];
552 new_faces
[i
].ref_vec
= new_cell_centre
[o2n2
] - new_cell_centre
[o2n1
];
553 new_faces
[i
].owner
= new_pcell_index
[o2n1
];
554 new_faces
[i
].neighbour
= new_pcell_index
[o2n2
];
556 bool reversed
= false;
557 while (e
.node2
!= start
) {
559 new_faces
[i
].node
.prepend(m_Nodes
[e
.node2
]);
561 new_faces
[i
].node
.append(m_Nodes
[e
.node2
]);
564 foreach (int n
, m_N2N
[e
.node2
]) {
566 edge_t ne
= getEdge(e
.node2
, n
);
567 if (old2new
[ne
.face1
] == o2n1
&& old2new
[ne
.face2
] == o2n2
) {
575 // reached a dead-end here ...
576 if (!found
&& !reversed
) {
580 foreach (int n
, m_N2N
[first
]) {
582 edge_t ne
= getEdge(first
, n
);
583 if (old2new
[ne
.face1
] == o2n1
&& old2new
[ne
.face2
] == o2n2
) {
595 if (new_faces
[i
].owner
> new_faces
[i
].neighbour
&& new_faces
[i
].neighbour
!= -1) {
596 swap(new_faces
[i
].owner
, new_faces
[i
].neighbour
);
597 new_faces
[i
].ref_vec
*= -1;
598 invertQContainer(new_faces
[i
].node
);
601 for (int face
= 0; face
< m_Faces
.size(); ++face
) {
602 int pface
= m_FacesInPMesh
[face
];
603 //m_PolyMesh->m_Faces[pface].bc = 1;
604 if (m_PolyMesh
->m_Faces
[pface
].owner
== m_PCell
) {
605 m_PolyMesh
->m_Faces
[pface
].owner
= new_pcell_index
[old2new
[face
]];
607 if (m_PolyMesh
->m_Faces
[pface
].neighbour
== m_PCell
) {
608 m_PolyMesh
->m_Faces
[pface
].neighbour
= new_pcell_index
[old2new
[face
]];
610 if (m_PolyMesh
->m_Faces
[pface
].owner
> m_PolyMesh
->m_Faces
[pface
].neighbour
&& m_PolyMesh
->m_Faces
[pface
].neighbour
!= -1) {
611 swap(m_PolyMesh
->m_Faces
[pface
].owner
, m_PolyMesh
->m_Faces
[pface
].neighbour
);
612 m_PolyMesh
->m_Faces
[pface
].ref_vec
*= -1;
613 invertQContainer(m_PolyMesh
->m_Faces
[pface
].node
);
616 foreach (PolyMesh::face_t f
, new_faces
) {
620 if (f
.neighbour
== -1) {
623 if (f
.owner
> f
.neighbour
) {
624 swap(f
.owner
, f
.neighbour
);
625 invertQContainer(f
.node
);
628 m_PolyMesh
->m_Faces
.append(f
);
630 m_PolyMesh
->m_NumPolyCells
+= seed_faces
.size() - 1;
633 void PolyMolecule::updatePMesh()
636 foreach (int face
, m_FacesInPMesh
) {
637 m_PolyMesh
->m_Faces
.removeAt(face
- offset
);
642 void PolyMolecule::optimise(bool write
)
645 if (m_MinPyramidVolume
<= 0) {
646 smooth(false, write
);
650 void PolyMolecule::updateFace(int face
, int new_cell_index
)
652 PolyMesh::face_t f
= m_PolyMesh
->m_Faces
[m_FacesInPMesh
[face
]];
653 if (f
.owner
== m_PCell
) {
654 f
.owner
= new_cell_index
;
656 if (f
.neighbour
== m_PCell
) {
657 f
.neighbour
= new_cell_index
;
659 if (f
.owner
> f
.neighbour
&& f
.neighbour
!= -1) {
660 swap(f
.owner
, f
.neighbour
);
661 invertQContainer(f
.node
);
664 m_PolyMesh
->m_Faces
[m_FacesInPMesh
[face
]] = f
;
667 void PolyMolecule::centreSplit()
671 QList
<edge_t
> concave_edges
= findConcaveEdges();
672 if (concave_edges
.size() == 0) {
676 // find common nodes in all edges and return if none exists
677 QSet
<int> common_nodes
;
678 common_nodes
.insert(concave_edges
.first().node1
);
679 common_nodes
.insert(concave_edges
.first().node2
);
680 foreach (edge_t e
, concave_edges
) {
681 QSet
<int> edge_nodes
;
682 edge_nodes
.insert(e
.node1
);
683 edge_nodes
.insert(e
.node2
);
684 common_nodes
.intersect(edge_nodes
);
686 if (common_nodes
.size() == 0) {
690 // start point of straight for divide point computation
694 foreach(int node
, common_nodes
) {
695 x1
+= getXNode(node
);
701 // end point of straight for divide point computation
706 QList
<int> adjacent_faces
;
707 foreach (edge_t e
, concave_edges
) {
708 if (!adjacent_faces
.contains(e
.face1
)) {
709 adjacent_faces
.append(e
.face1
);
711 if (!adjacent_faces
.contains(e
.face2
)) {
712 adjacent_faces
.append(e
.face2
);
715 foreach (int face
, adjacent_faces
) {
716 n
+= m_FaceNormals
[face
];
721 for (int node
= 0; node
< m_Nodes
.size(); ++node
) {
722 vec3_t x
= getXNode(node
);
723 double dist
= (x1
- x
)*n
;
724 if (dist
> max_dist
) {
735 // tip point for all polygonial pyramids
736 vec3_t x_tip
= 0.5*(x1
+ x2
);
738 // vector with new cell indices
739 QVector
<int> cell_index(m_Faces
.size());
740 cell_index
[0] = m_PCell
;
741 for (int i
= 1; i
< cell_index
.size(); ++i
) {
742 cell_index
[i
] = m_PolyMesh
->m_NumPolyCells
++;
746 int new_node
= m_PolyMesh
->m_Points
.size();
747 m_PolyMesh
->m_Points
.append(x_tip
);
749 // re-map existing faces
750 for (int face
= 0; face
< m_FacesInPMesh
.size(); ++face
) {
751 updateFace(face
, cell_index
[face
]);
755 for (int face
= 0; face
< m_Faces
.size(); ++face
) {
756 QList
<int> nodes
= m_Faces
[face
];
757 nodes
.append(nodes
.first());
758 for (int i_node
= 0; i_node
< nodes
.size() - 1; ++i_node
) {
759 int node1
= nodes
[i_node
];
760 int node2
= nodes
[i_node
+ 1];
761 edge_t e
= getEdge(node1
, node2
);
763 if (e
.face1
== face
) {
764 f
.neighbour
= cell_index
[e
.face2
];
766 f
.neighbour
= cell_index
[e
.face1
];
768 if (f
.owner
< f
.neighbour
) {
770 f
.node
.append(m_Nodes
[node2
]);
771 f
.node
.append(m_Nodes
[node1
]);
772 f
.node
.append(new_node
);
773 f
.owner
= cell_index
[face
];
774 vec3_t x1
= m_PolyMesh
->m_Points
[f
.node
[0]];
775 vec3_t x2
= m_PolyMesh
->m_Points
[f
.node
[1]];
776 vec3_t x3
= m_PolyMesh
->m_Points
[f
.node
[2]];
777 f
.ref_vec
= GeometryTools::triNormal(x1
, x2
, x3
);
779 if (f.owner > f.neighbour) {
780 swap(f.owner, f.neighbour);
782 invertQContainer(f.node);
785 m_PolyMesh
->m_Faces
.append(f
);