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 "insertpoints.h"
23 #include "guimainwindow.h"
25 #include <vtkCharArray.h>
29 InsertPoints::InsertPoints() : SurfaceOperation()
32 getSet("surface meshing", "point insertion threshold", 1, m_Threshold
);
35 void InsertPoints::operate()
37 int N1
= m_Grid
->GetNumberOfPoints();
39 int N2
= m_Grid
->GetNumberOfPoints();
40 m_NumInserted
= N2
- N1
;
43 ///\todo Adapt this code for multiple volumes.
44 int InsertPoints::insertPoints()
47 l2g_t cells
= getPartCells();
48 g2l_t _cells
= getPartLocalCells();
52 EG_VTKDCC(vtkIntArray
, cell_code
, m_Grid
, "cell_code");
53 EG_VTKDCN(vtkDoubleArray
, characteristic_length_desired
, m_Grid
, "node_meshdensity_desired");
58 QVector
<int> marked_cells(cells
.size(), 0);
59 QVector
<stencil_t
> stencil_vector(cells
.size());
61 // find potential edges for splitting
63 for (int i
= 0; i
< cells
.size(); ++i
) {
64 vtkIdType id_cell
= cells
[i
];
66 // if cell is selected and a triangle
67 if (m_BoundaryCodes
.contains(cell_code
->GetValue(id_cell
)) && (m_Grid
->GetCellType(id_cell
) == VTK_TRIANGLE
)) {
70 vtkIdType N_pts
, *pts
;
71 m_Grid
->GetCellPoints(id_cell
, N_pts
, pts
);
73 //find best side to split (longest)
74 for (int j
= 0; j
< 3; ++j
) {
76 //check if neighbour cell on this side is also selected
77 stencil_t S
= getStencil(id_cell
, j
);
78 bool selected_edge
= true;
79 for (int i_cell_neighbour
=1;i_cell_neighbour
<S
.id_cell
.size();i_cell_neighbour
++) {
80 vtkIdType id_cell_neighbour
= S
.id_cell
[i_cell_neighbour
];
81 if (!m_BoundaryCodes
.contains(cell_code
->GetValue(id_cell_neighbour
)) || S
.type_cell
[i_cell_neighbour
] != VTK_TRIANGLE
) {
84 } // end of loop through neighbour cells
87 vtkIdType id_node1
= pts
[j
];
88 vtkIdType id_node2
= pts
[(j
+1)%N_pts
];
89 double L
= distance(m_Grid
, id_node1
, id_node2
);
90 double L1
= characteristic_length_desired
->GetValue(id_node1
);
91 double L2
= characteristic_length_desired
->GetValue(id_node2
);
92 if (L
> m_Threshold
*min(L1
,L2
)) {
99 } // end of loop through sides
101 stencil_t S
= getStencil(id_cell
, j_split
);
104 E
.L1
= characteristic_length_desired
->GetValue(S
.p1
);
105 E
.L2
= characteristic_length_desired
->GetValue(S
.p2
);
106 E
.L12
= distance(m_Grid
, S
.p1
, S
.p2
);
115 foreach (edge_t E
, edges
) {
116 int i_cells1
= _cells
[E
.S
.id_cell
[0]];
117 bool all_unmarked
= true;
118 for (int i
= 0; i
< E
.S
.id_cell
.size(); i
++) {
119 int i_cells
= _cells
[E
.S
.id_cell
[i
]];
120 if (marked_cells
[i_cells
]) {
125 stencil_vector
[i_cells1
] = E
.S
;
126 marked_cells
[i_cells1
] = 1;
127 for (int i
= 1; i
< E
.S
.id_cell
.size(); i
++) {
128 int i_cells
= _cells
[E
.S
.id_cell
[i
]];
129 marked_cells
[i_cells
] = 2;
132 num_newcells
+= E
.S
.id_cell
.size();
136 //initialize grid_tmp
137 int l_N_points
=m_Grid
->GetNumberOfPoints();
138 int l_N_cells
=m_Grid
->GetNumberOfCells();
139 EG_VTKSP(vtkUnstructuredGrid
,grid_tmp
);
140 allocateGrid(grid_tmp
, l_N_cells
+ num_newcells
, l_N_points
+ num_newpoints
);
141 makeCopyNoAlloc(m_Grid
, grid_tmp
);
143 //initialize new node counter
144 vtkIdType id_new_node
= l_N_points
;
147 for (int i
= 0; i
< cells
.size(); i
++) {
148 if (marked_cells
[i
] == 1) {
149 stencil_t S
= stencil_vector
[i
];
153 grid_tmp
->GetPoint(S
.p1
,A
.data());
154 grid_tmp
->GetPoint(S
.p2
,B
.data());
158 grid_tmp
->GetPoints()->SetPoint(id_new_node
, M
.data());
159 copyNodeData(grid_tmp
,S
.p1
,grid_tmp
,id_new_node
); ///\todo maybe trouble
161 // inserted edge point = type of the edge on which it is inserted
162 EG_VTKDCN(vtkCharArray
, node_type
, grid_tmp
, "node_type");
163 node_type
->SetValue(id_new_node
, getNewNodeType(S
) );
167 int N
= S
.id_cell
.size();
168 QVector
< QVector
<vtkIdType
> > pts_triangle(2*N
,QVector
<vtkIdType
>(3));
170 for(int i_triangle
= 0; i_triangle
< N
; i_triangle
++) {
171 vtkIdType
*pts
, N_pts
;
172 grid_tmp
->GetCellPoints(S
.id_cell
[i_triangle
], N_pts
, pts
);
175 for(int i_pts
= 0; i_pts
< N_pts
; i_pts
++) {
176 if (pts
[i_pts
] == S
.p1
) {
177 if (pts
[(i_pts
+1)%N_pts
] == S
.p2
) {
185 pts_triangle
[i_triangle
][0] = S
.p1
;
186 pts_triangle
[i_triangle
][1] = id_new_node
;
187 pts_triangle
[i_triangle
][2] = S
.id_node
[i_triangle
];
189 pts_triangle
[i_triangle
+N
][0] = id_new_node
;
190 pts_triangle
[i_triangle
+N
][1] = S
.p2
;
191 pts_triangle
[i_triangle
+N
][2] = S
.id_node
[i_triangle
];
193 pts_triangle
[i_triangle
][0] = S
.p2
;
194 pts_triangle
[i_triangle
][1] = id_new_node
;
195 pts_triangle
[i_triangle
][2] = S
.id_node
[i_triangle
];
197 pts_triangle
[i_triangle
+N
][0] = id_new_node
;
198 pts_triangle
[i_triangle
+N
][1] = S
.p1
;
199 pts_triangle
[i_triangle
+N
][2] = S
.id_node
[i_triangle
];
202 grid_tmp
->ReplaceCell(S
.id_cell
[i_triangle
] , 3, pts_triangle
[i_triangle
].data());
203 vtkIdType newCellId
= grid_tmp
->InsertNextCell(VTK_TRIANGLE
,3,pts_triangle
[i_triangle
+N
].data());
204 copyCellData(grid_tmp
,S
.id_cell
[i_triangle
],grid_tmp
,newCellId
);
213 makeCopy(grid_tmp
,m_Grid
);
218 char InsertPoints::getNewNodeType(stencil_t S
)
220 vtkIdType id_node1
= S
.p1
;
221 vtkIdType id_node2
= S
.p2
;
223 EG_VTKDCN(vtkCharArray
, node_type
, m_Grid
, "node_type");
224 EG_VTKDCC(vtkIntArray
, cell_code
, m_Grid
, "cell_code");
225 char type1
= node_type
->GetValue(id_node1
);
226 char type2
= node_type
->GetValue(id_node2
);
227 if (type1
== EG_SIMPLE_VERTEX
|| type2
== EG_SIMPLE_VERTEX
) {
228 return EG_SIMPLE_VERTEX
;
230 QVector
<vtkIdType
> PSP1
= getPotentialSnapPoints(id_node1
);
231 QVector
<vtkIdType
> PSP2
= getPotentialSnapPoints(id_node2
);
232 bool complex = false;
233 if (PSP1
.contains(id_node2
) || PSP2
.contains(id_node1
)) {
235 } else if (type1
>= EG_BOUNDARY_EDGE_VERTEX
&& type2
>= EG_BOUNDARY_EDGE_VERTEX
) {
236 if (!PSP1
.contains(id_node2
) && !PSP2
.contains(id_node1
) && S
.id_cell
.size() == 2) {
237 int bc1
= cell_code
->GetValue(S
.id_cell
[0]);
238 int bc2
= cell_code
->GetValue(S
.id_cell
[1]);
240 return EG_BOUNDARY_EDGE_VERTEX
;
242 vec3_t n1
= cellNormal(m_Grid
, S
.id_cell
[0]);
243 vec3_t n2
= cellNormal(m_Grid
, S
.id_cell
[1]);
244 if (GeometryTools::angle(n1
, n2
) > m_FeatureAngle
) {
245 return EG_FEATURE_EDGE_VERTEX
;
250 if (S
.id_cell
.size() < 1) {
251 return EG_BOUNDARY_EDGE_VERTEX
;
252 } else if (S
.id_cell
.size() == 1) {
253 EG_ERR_RETURN("Invalid surface mesh. Check this with 'Tools -> Check surface integrity'.");
255 if (cell_code
->GetValue(S
.id_cell
[0]) != cell_code
->GetValue(S
.id_cell
[1])) {
256 return EG_BOUNDARY_EDGE_VERTEX
;
258 if (isFeatureNode(id_node1
) || isFeatureNode(id_node2
)) {
259 return EG_FEATURE_EDGE_VERTEX
;
261 return EG_SIMPLE_VERTEX
;
266 return EG_SIMPLE_VERTEX
;