2 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 // + This file is part of enGrid. +
6 // + Copyright 2008,2009 Oliver Gloth +
8 // + enGrid is free software: you can redistribute it and/or modify +
9 // + it under the terms of the GNU General Public License as published by +
10 // + the Free Software Foundation, either version 3 of the License, or +
11 // + (at your option) any later version. +
13 // + enGrid is distributed in the hope that it will be useful, +
14 // + but WITHOUT ANY WARRANTY; without even the implied warranty of +
15 // + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +
16 // + GNU General Public License for more details. +
18 // + You should have received a copy of the GNU General Public License +
19 // + along with enGrid. If not, see <http://www.gnu.org/licenses/>. +
21 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
23 #include "surfaceoperation.h"
25 #include "guimainwindow.h"
27 #include <vtkCharArray.h>
29 #include <vtkCellArray.h>
30 #include <vtkPolygon.h>
32 #include "geometrytools.h"
33 using namespace GeometryTools
;
35 SurfaceOperation::SurfaceOperation()
38 //default values for determining node types and for smoothing operations
40 NumberOfIterations
= 20;
41 RelaxationFactor
= 0.01;
42 m_AllowFeatureEdgeVertices
= 1;//0 by default in VTK, but we need 1 to avoid the "potatoe effect" ^^
45 BoundarySmoothing
= 1;
48 void SurfaceOperation::operate()
53 ostream
& operator<<( ostream
&out
, stencil_t S
)
55 out
<< "S.id_cell1=" << S
.id_cell1
<< " ";
56 out
<< "S.id_cell2=" << S
.id_cell2
<< " ";
57 out
<< "S.sameBC=" << S
.sameBC
<< " ";
58 out
<< "S.twocells=" << S
.twocells
<< " ";
59 out
<< "S.neighbour_type=" << S
.neighbour_type
<< " ";
61 for ( int i
= 0; i
< 4; i
++ ) {
63 if ( i
!= 3 ) out
<< ",";
69 stencil_t
SurfaceOperation::getStencil( vtkIdType id_cell1
, int j1
)
71 l2g_t cells
= getPartCells();
72 g2l_t _cells
= getPartLocalCells();
73 l2l_t c2c
= getPartC2C();
75 if ( grid
->GetCellType( id_cell1
) != VTK_TRIANGLE
) {
76 cout
<< "CELL IS NOT A TRIANGLE" << endl
;
86 S
.neighbour_type
= -1;
88 //initialize first cell
89 S
.id_cell1
= id_cell1
;
91 grid
->GetCellPoints( S
.id_cell1
, N1
, pts1
);
93 if ( j1
== 0 ) { S
.p
[0] = pts1
[2]; S
.p
[1] = pts1
[0]; S
.p
[3] = pts1
[1]; }
94 else if ( j1
== 1 ) { S
.p
[0] = pts1
[0]; S
.p
[1] = pts1
[1]; S
.p
[3] = pts1
[2]; }
95 else if ( j1
== 2 ) { S
.p
[0] = pts1
[1]; S
.p
[1] = pts1
[2]; S
.p
[3] = pts1
[0]; };
97 //initialize second cell
102 if ( c2c
[_cells
[id_cell1
]][j1
] != -1 ) { //if neighbour cell
106 S
.id_cell2
= cells
[c2c
[_cells
[id_cell1
]][j1
]];
109 EG_VTKDCC( vtkIntArray
, cell_code
, grid
, "cell_code" );
110 if ( cell_code
->GetValue( S
.id_cell1
) == cell_code
->GetValue( S
.id_cell2
) ) S
.sameBC
= true;
113 S
.neighbour_type
= grid
->GetCellType( S
.id_cell2
);
114 if ( S
.neighbour_type
== VTK_TRIANGLE
) {//if neighbour cell is a triangle
116 grid
->GetCellPoints( S
.id_cell2
, N2
, pts2
);
120 if ( c2c
[_cells
[S
.id_cell2
]][0] != -1 ) {
121 if ( cells
[c2c
[_cells
[S
.id_cell2
]][0]] == S
.id_cell1
) {
126 if ( c2c
[_cells
[S
.id_cell2
]][1] != -1 ) {
127 if ( cells
[c2c
[_cells
[S
.id_cell2
]][1]] == S
.id_cell1
) {
132 if ( c2c
[_cells
[S
.id_cell2
]][2] != -1 ) {
133 if ( cells
[c2c
[_cells
[S
.id_cell2
]][2]] == S
.id_cell1
) {
139 if ( !p2
) {//failed to place point 2, appears when cell1 is linked to cell2, but cell2 not to cell1
140 cout
<< "S.id_cell1=" << S
.id_cell1
<< endl
;
141 cout
<< "S.id_cell2=" << S
.id_cell2
<< endl
;
142 GuiMainWindow::pointer()->saveAs( GuiMainWindow::pointer()->getFilePath() + "abort.egc", false );
146 }//end of if neighbour cell
150 int SurfaceOperation::UpdateCurrentMeshDensity()
152 if ( DebugLevel
> 0 ) {
153 cout
<< "===UpdateMeshDensity START===" << endl
;
155 QVector
<vtkIdType
> cells
;
156 getAllSurfaceCells( cells
, grid
);
157 EG_VTKDCC( vtkIntArray
, cell_code
, grid
, "cell_code" );
158 EG_VTKDCN( vtkDoubleArray
, node_meshdensity_desired
, grid
, "node_meshdensity_desired" );
161 if ( DebugLevel
> 5 ) {
162 cout
<< "cells.size()=" << cells
.size() << endl
;
164 EG_VTKDCN( vtkDoubleArray
, node_meshdensity_current
, grid
, "node_meshdensity_current" );
165 l2g_t nodes
= getPartNodes();
166 foreach( vtkIdType node
, nodes
) {
167 node_meshdensity_current
->SetValue( node
, CurrentMeshDensity( node
) );
169 if ( DebugLevel
> 0 ) {
170 cout
<< "===UpdateMeshDensity END===" << endl
;
172 return( 0 ); ///@@@ what for???
175 int SurfaceOperation::UpdatePotentialSnapPoints( bool update_node_types
, bool allow_feature_edge_vertices
)
177 l2g_t nodes
= getPartNodes();
178 l2g_t cells
= getPartCells();
179 g2l_t _cells
= getPartLocalCells();
180 l2l_t c2c
= getPartC2C();
182 //cout<<"=== UpdatePotentialSnapPoints START ==="<<endl;
184 setAllSurfaceCells();
186 m_PotentialSnapPoints
.resize( nodes
.size() );
188 //initialize default values
189 EG_VTKDCN( vtkCharArray
, node_type
, grid
, "node_type" );
190 foreach( vtkIdType id_node
, nodes
) {
191 if ( update_node_types
) node_type
->SetValue( id_node
, VTK_SIMPLE_VERTEX
);
192 m_PotentialSnapPoints
[id_node
].clear();
195 //cout<<"===pre-processing==="<<endl;
197 //We loop through edges
198 foreach( vtkIdType id_cell
, cells
) {
199 vtkIdType
*pts
, Npts
;
200 grid
->GetCellPoints( id_cell
, Npts
, pts
);
201 for ( int i
= 0; i
< Npts
; i
++ ) {
203 int i_neighbour_cell
= c2c
[_cells
[id_cell
]][i
];
204 if ( i_neighbour_cell
>= 0 && cells
[i_neighbour_cell
] < id_cell
) continue;//already visited edge
207 vtkIdType id_node1
= pts
[i
];
208 vtkIdType id_node2
= pts
[( i
+1 )%Npts
];
210 //-----------------------
211 //determine edge type
212 char edge
= getEdgeType( id_node2
, id_node1
, allow_feature_edge_vertices
);
213 //-----------------------
214 //determine node type pre-processing (count nb of complex edges if the node is complex, otherwise, just count the nb of edges)
215 if ( edge
&& node_type
->GetValue( id_node1
) == VTK_SIMPLE_VERTEX
) {
216 m_PotentialSnapPoints
[id_node1
].clear();
217 m_PotentialSnapPoints
[id_node1
].push_back( id_node2
);
218 if ( update_node_types
) node_type
->SetValue( id_node1
, edge
);
220 else if (( edge
&& node_type
->GetValue( id_node1
) == VTK_BOUNDARY_EDGE_VERTEX
) ||
221 ( edge
&& node_type
->GetValue( id_node1
) == VTK_FEATURE_EDGE_VERTEX
) ||
222 ( !edge
&& node_type
->GetValue( id_node1
) == VTK_SIMPLE_VERTEX
) ) {
223 m_PotentialSnapPoints
[id_node1
].push_back( id_node2
);
224 if ( node_type
->GetValue( id_node1
) && edge
== VTK_BOUNDARY_EDGE_VERTEX
) {
225 if ( update_node_types
) node_type
->SetValue( id_node1
, VTK_BOUNDARY_EDGE_VERTEX
);//VTK_BOUNDARY_EDGE_VERTEX has priority over VTK_FEATURE_EDGE_VERTEX
229 if ( edge
&& node_type
->GetValue( id_node2
) == VTK_SIMPLE_VERTEX
) {
230 m_PotentialSnapPoints
[id_node2
].clear();
231 m_PotentialSnapPoints
[id_node2
].push_back( id_node1
);
232 if ( update_node_types
) node_type
->SetValue( id_node2
, edge
);
234 else if (( edge
&& node_type
->GetValue( id_node2
) == VTK_BOUNDARY_EDGE_VERTEX
) ||
235 ( edge
&& node_type
->GetValue( id_node2
) == VTK_FEATURE_EDGE_VERTEX
) ||
236 ( !edge
&& node_type
->GetValue( id_node2
) == VTK_SIMPLE_VERTEX
) ) {
237 m_PotentialSnapPoints
[id_node2
].push_back( id_node1
);
238 if ( node_type
->GetValue( id_node2
) && edge
== VTK_BOUNDARY_EDGE_VERTEX
) {
239 if ( update_node_types
) node_type
->SetValue( id_node2
, VTK_BOUNDARY_EDGE_VERTEX
);//VTK_BOUNDARY_EDGE_VERTEX has priority over VTK_FEATURE_EDGE_VERTEX
245 //cout<<"num_edges="<<num_edges<<endl;
247 //-----------------------
248 //determine node type post-processing
249 double CosEdgeAngle
= cos(( double ) vtkMath::RadiansFromDegrees( this->EdgeAngle
) );
250 //cout<<"===post-processing==="<<endl;
251 //This time, we loop through nodes
252 foreach( vtkIdType id_node
, nodes
) {
253 if ( node_type
->GetValue( id_node
) == VTK_FEATURE_EDGE_VERTEX
|| node_type
->GetValue( id_node
) == VTK_BOUNDARY_EDGE_VERTEX
) { //see how many edges; if two, what the angle is
255 if ( !this->BoundarySmoothing
&&
256 node_type
->GetValue( id_node
) == VTK_BOUNDARY_EDGE_VERTEX
) {
257 if ( update_node_types
) node_type
->SetValue( id_node
, VTK_FIXED_VERTEX
);
259 else if ( m_PotentialSnapPoints
[id_node
].size() != 2 ) {
260 if ( update_node_types
) node_type
->SetValue( id_node
, VTK_FIXED_VERTEX
);
262 else { //check angle between edges
263 double x1
[3], x2
[3], x3
[3], l1
[3], l2
[3];
264 grid
->GetPoint( m_PotentialSnapPoints
[id_node
][0], x1
);
265 grid
->GetPoint( id_node
, x2
);
266 grid
->GetPoint( m_PotentialSnapPoints
[id_node
][1], x3
);
267 for ( int k
= 0; k
< 3; k
++ ) {
268 l1
[k
] = x2
[k
] - x1
[k
];
269 l2
[k
] = x3
[k
] - x2
[k
];
271 if ( vtkMath::Normalize( l1
) >= 0.0 &&
272 vtkMath::Normalize( l2
) >= 0.0 &&
273 vtkMath::Dot( l1
, l2
) < CosEdgeAngle
) {
274 if ( update_node_types
) node_type
->SetValue( id_node
, VTK_FIXED_VERTEX
);
279 //cout<<"m_PotentialSnapPoints.size()="<<m_PotentialSnapPoints.size()<<endl;
280 //cout<<"=== UpdatePotentialSnapPoints END ==="<<endl;
284 char SurfaceOperation::getNodeType( vtkIdType id_node
, bool allow_feature_edge_vertices
)
286 l2g_t nodes
= getPartNodes();
287 g2l_t _nodes
= getPartLocalNodes();
288 l2l_t n2n
= getPartN2N();
290 //initialize default value
291 char type
= VTK_SIMPLE_VERTEX
;
293 //loop through edges around id_node
295 QVector
<vtkIdType
> edges
;
297 double CosEdgeAngle
= cos(( double ) vtkMath::RadiansFromDegrees( this->EdgeAngle
) );
299 foreach( int i_node2
, n2n
[_nodes
[id_node
]] ) {
300 vtkIdType id_node2
= nodes
[i_node2
];
301 //-----------------------
302 //determine edge type
303 char edge
= getEdgeType( id_node2
, id_node
, allow_feature_edge_vertices
);
305 //-----------------------
306 //determine node type pre-processing (count nb of complex edges if the node is complex, otherwise, just count the nb of edges)
307 if ( edge
&& type
== VTK_SIMPLE_VERTEX
) {
309 edges
.push_back( id_node2
);
312 else if (( edge
&& type
== VTK_BOUNDARY_EDGE_VERTEX
) ||
313 ( edge
&& type
== VTK_FEATURE_EDGE_VERTEX
) ||
314 ( !edge
&& type
== VTK_SIMPLE_VERTEX
) ) {
315 edges
.push_back( id_node2
);
316 if ( type
&& edge
== VTK_BOUNDARY_EDGE_VERTEX
) {
317 type
= VTK_BOUNDARY_EDGE_VERTEX
;//VTK_BOUNDARY_EDGE_VERTEX has priority over VTK_FEATURE_EDGE_VERTEX
321 //-----------------------
322 //determine node type post-processing
323 if ( type
== VTK_FEATURE_EDGE_VERTEX
|| type
== VTK_BOUNDARY_EDGE_VERTEX
) { //see how many edges; if two, what the angle is
325 if ( !this->BoundarySmoothing
&&
326 type
== VTK_BOUNDARY_EDGE_VERTEX
) {
327 type
= VTK_FIXED_VERTEX
;
329 else if ( edges
.size() != 2 ) {
330 type
= VTK_FIXED_VERTEX
;
332 else { //check angle between edges
333 double x1
[3], x2
[3], x3
[3], l1
[3], l2
[3];
334 grid
->GetPoint( edges
[0], x1
);
335 grid
->GetPoint( id_node
, x2
);
336 grid
->GetPoint( edges
[1], x3
);
337 for ( int k
= 0; k
< 3; k
++ ) {
338 l1
[k
] = x2
[k
] - x1
[k
];
339 l2
[k
] = x3
[k
] - x2
[k
];
341 if ( vtkMath::Normalize( l1
) >= 0.0 &&
342 vtkMath::Normalize( l2
) >= 0.0 &&
343 vtkMath::Dot( l1
, l2
) < CosEdgeAngle
) {
344 type
= VTK_FIXED_VERTEX
;
349 if ( !allow_feature_edge_vertices
&& type
== VTK_FEATURE_EDGE_VERTEX
) EG_BUG
;
353 int SurfaceOperation::getEdgeCells( vtkIdType id_node1
, vtkIdType id_node2
, QVector
<vtkIdType
> &EdgeCells
)
355 g2l_t _nodes
= getPartLocalNodes();
356 l2g_t cells
= getPartCells();
357 l2l_t n2c
= getPartN2C();
360 foreach( int i
, n2c
[_nodes
[id_node1
]] ) {
361 S1
.insert( cells
[i
] );
365 foreach( int i
, n2c
[_nodes
[id_node2
]] ) {
366 S2
.insert( cells
[i
] );
370 EdgeCells
= Set2Vector( S2
, false );
371 return EdgeCells
.size();
374 int SurfaceOperation::getEdgeCells( vtkIdType id_node1
, vtkIdType id_node2
, QSet
<vtkIdType
> &EdgeCells
)
376 g2l_t _nodes
= getPartLocalNodes();
377 l2g_t cells
= getPartCells();
378 l2l_t n2c
= getPartN2C();
381 foreach( int i
, n2c
[_nodes
[id_node1
]] ) {
382 S1
.insert( cells
[i
] );
386 foreach( int i
, n2c
[_nodes
[id_node2
]] ) {
387 S2
.insert( cells
[i
] );
390 EdgeCells
= S2
.intersect( S1
);
391 return EdgeCells
.size();
394 char SurfaceOperation::getEdgeType( vtkIdType a_node1
, vtkIdType a_node2
, bool allow_feature_edge_vertices
)
396 double CosFeatureAngle
= cos(( double ) vtkMath::RadiansFromDegrees( this->FeatureAngle
) );
398 //compute number of cells around edge [a_node,p2] and put them into neighbour_cells
399 QVector
<vtkIdType
> neighbour_cells
;
400 int numNei
= getEdgeCells( a_node1
, a_node2
, neighbour_cells
) - 1;
403 char edge
= VTK_SIMPLE_VERTEX
;
406 edge
= VTK_BOUNDARY_EDGE_VERTEX
;
408 else if ( numNei
>= 2 ) {
409 qWarning() << "FATAL ERROR: edge belongs to more than 2 cells! This is not supported yet.";
411 edge
= VTK_FEATURE_EDGE_VERTEX
;
413 else if ( numNei
== 1 ) {
414 //check angle between cell1 and cell2 against FeatureAngle
415 if ( allow_feature_edge_vertices
&& this->m_AllowFeatureEdgeVertices
&& CosAngle( grid
, neighbour_cells
[0], neighbour_cells
[1] ) <= CosFeatureAngle
) {
416 edge
= VTK_FEATURE_EDGE_VERTEX
;
418 //check the boundary codes
419 EG_VTKDCC( vtkIntArray
, cell_code
, grid
, "cell_code" );
420 if ( cell_code
->GetValue( neighbour_cells
[0] ) != cell_code
->GetValue( neighbour_cells
[1] ) ) {
421 edge
= VTK_BOUNDARY_EDGE_VERTEX
;
428 QSet
<int> SurfaceOperation::getBCset( vtkIdType id_node
)
430 g2l_t _nodes
= getPartLocalNodes();
431 l2g_t cells
= getPartCells();
432 l2l_t n2c
= getPartN2C();
434 EG_VTKDCC( vtkIntArray
, cell_code
, grid
, "cell_code" );
436 foreach( int i_cell
, n2c
[_nodes
[id_node
]] ) {
437 vtkIdType id_cell
= cells
[i_cell
];
438 bc
.insert( cell_code
->GetValue( id_cell
) );
443 VertexMeshDensity
SurfaceOperation::getVMD( vtkIdType id_node
)
445 g2l_t _nodes
= getPartLocalNodes();
446 l2g_t cells
= getPartCells();
447 l2l_t n2c
= getPartN2C();
449 EG_VTKDCN( vtkCharArray
, node_type
, grid
, "node_type" );
450 EG_VTKDCC( vtkIntArray
, cell_code
, grid
, "cell_code" );
452 VertexMeshDensity VMD
;
453 VMD
.type
= node_type
->GetValue( id_node
);
455 VMD
.CurrentNode
= id_node
;
457 foreach( int i_cell
, n2c
[_nodes
[id_node
]] ) {
458 vtkIdType id_cell
= cells
[i_cell
];
459 VMD
.BCmap
[cell_code
->GetValue( id_cell
)] = 2;
464 //////////////////////////////////////////////
465 double SurfaceOperation::CurrentVertexAvgDist( vtkIdType id_node
)
467 l2g_t nodes
= getPartNodes();
468 g2l_t _nodes
= getPartLocalNodes();
469 l2l_t n2n
= getPartN2N();
471 double total_dist
= 0;
473 int N
= n2n
[_nodes
[id_node
]].size();
475 grid
->GetPoint( id_node
, C
.data() );
476 foreach( int i_node_neighbour
, n2n
[_nodes
[id_node
]] ) {
477 vtkIdType id_node_neighbour
= nodes
[i_node_neighbour
];
479 grid
->GetPoint( id_node_neighbour
, M
.data() );
480 total_dist
+= ( M
- C
).abs();
482 avg_dist
= total_dist
/ ( double )N
;
486 double SurfaceOperation::CurrentMeshDensity( vtkIdType id_node
)
488 return 1.0 / CurrentVertexAvgDist( id_node
);
491 double SurfaceOperation::DesiredVertexAvgDist( vtkIdType id_node
)
493 l2g_t nodes
= getPartNodes();
494 g2l_t _nodes
= getPartLocalNodes();
495 l2l_t n2n
= getPartN2N();
497 double total_dist
= 0;
499 EG_VTKDCN( vtkDoubleArray
, node_meshdensity_desired
, grid
, "node_meshdensity_desired" );
500 int N
= n2n
[_nodes
[id_node
]].size();
501 foreach( int i_node_neighbour
, n2n
[_nodes
[id_node
]] ) {
502 vtkIdType id_node_neighbour
= nodes
[i_node_neighbour
];
503 total_dist
+= 1. / node_meshdensity_desired
->GetValue( id_node_neighbour
);
505 avg_dist
= total_dist
/ ( double )N
;
509 double SurfaceOperation::DesiredMeshDensity( vtkIdType id_node
)
511 l2g_t nodes
= getPartNodes();
512 g2l_t _nodes
= getPartLocalNodes();
513 l2l_t n2n
= getPartN2N();
515 double total_density
= 0;
516 double avg_density
= 0;
517 EG_VTKDCN( vtkDoubleArray
, node_meshdensity_desired
, grid
, "node_meshdensity_desired" );
518 int N
= n2n
[_nodes
[id_node
]].size();
519 foreach( int i_node_neighbour
, n2n
[_nodes
[id_node
]] ) {
520 vtkIdType id_node_neighbour
= nodes
[i_node_neighbour
];
521 total_density
+= node_meshdensity_desired
->GetValue( id_node_neighbour
);
523 avg_density
= total_density
/ ( double )N
;
524 return( avg_density
);
527 ///////////////////////////////////////////
529 //---------------------------------------------------
530 //Utility functions used in Roland's formulas
532 ///@@@ TODO: change meshdensity fields to edgelength fields since this is what is mostly used?
534 /// desired edge length for id_node
535 double SurfaceOperation::desiredEdgeLength( vtkIdType id_node
)
537 EG_VTKDCN( vtkDoubleArray
, node_meshdensity_desired
, grid
, "node_meshdensity_desired" );
538 return( 1.0 / node_meshdensity_desired
->GetValue( id_node
) );
543 double SurfaceOperation::perimeter( vtkIdType id_cell
)
546 vtkIdType num_pts
, *pts
;
547 grid
->GetCellPoints( id_cell
, num_pts
, pts
);
548 for ( int i
= 0; i
< num_pts
; i
++ ) {
550 grid
->GetPoints()->GetPoint( pts
[i
], A
.data() );
551 grid
->GetPoints()->GetPoint( pts
[( i
+1 )%num_pts
], B
.data() );
552 ret
+= ( B
- A
).abs();
557 /// mean desired edge length for id_cell
558 double SurfaceOperation::meanDesiredEdgeLength( vtkIdType id_cell
)
560 vtkIdType num_pts
, *pts
;
561 grid
->GetCellPoints( id_cell
, num_pts
, pts
);
563 for ( int i
= 0; i
< num_pts
; i
++ ) {
564 total
+= desiredEdgeLength( pts
[i
] );
566 return total
/ ( double )num_pts
;
569 ///@@@ TODO: Should be renamed to be more explicit if possible
571 /// perimeter / sum of the desired edge lengths
572 double SurfaceOperation::Q_L( vtkIdType id_cell
)
574 double denom_sum
= 0;
575 vtkIdType num_pts
, *pts
;
576 grid
->GetCellPoints( id_cell
, num_pts
, pts
);
577 for ( int i
= 0; i
< num_pts
; i
++ ) {
578 denom_sum
+= desiredEdgeLength( pts
[i
] );
580 return( perimeter( id_cell
) / denom_sum
);
583 /// sum(2*edgelength,edges(id_node))/sum(desired edgelengths of each edgepoint,edges(id_node))
584 double SurfaceOperation::Q_L1( vtkIdType id_node
)
586 l2l_t n2n
= getPartN2N();
587 g2l_t _nodes
= getPartLocalNodes();
588 l2g_t nodes
= getPartNodes();
591 double denom_sum
= 0;
592 foreach( int i_node_neighbour
, n2n
[_nodes
[id_node
]] ) {
593 vtkIdType id_node_neighbour
= nodes
[i_node_neighbour
];
594 num_sum
+= 2 * distance( grid
, id_node_neighbour
, id_node
);
595 denom_sum
+= desiredEdgeLength( id_node
) + desiredEdgeLength( id_node_neighbour
);
597 return( num_sum
/ denom_sum
);
600 /// minimum of sum(2*edgelength)/sum(desired edgelengths of each edgepoint) for each edge of id_node
601 double SurfaceOperation::Q_L2( vtkIdType id_node
)
603 l2l_t n2n
= getPartN2N();
604 g2l_t _nodes
= getPartLocalNodes();
605 l2g_t nodes
= getPartNodes();
609 foreach( int i_node_neighbour
, n2n
[_nodes
[id_node
]] ) {
610 vtkIdType id_node_neighbour
= nodes
[i_node_neighbour
];
611 num
= 2 * distance( grid
, id_node_neighbour
, id_node
);
612 denom
= desiredEdgeLength( id_node
) + desiredEdgeLength( id_node_neighbour
);
613 V
.push_back( num
/ denom
);
615 qSort( V
.begin(), V
.end() );
619 /// Value to minimize for mesh smoothing. w allows putting more weight on the form or the area of triangles.
620 double SurfaceOperation::T_min( int w
)
622 l2g_t cells
= getPartCells();
624 foreach( vtkIdType id_cell
, cells
) {
625 T
+= areaOfCircumscribedCircle( grid
, id_cell
) / pow( cellVA( grid
, id_cell
), w
) * pow( meanDesiredEdgeLength( id_cell
), 2 * ( w
- 1 ) );
630 //---------------------------------------------------
632 vtkIdType
SurfaceOperation::getClosestNode( vtkIdType id_node
)
634 l2l_t n2n
= getPartN2N();
635 g2l_t _nodes
= getPartLocalNodes();
636 l2g_t nodes
= getPartNodes();
639 grid
->GetPoint( id_node
, C
.data() );
640 vtkIdType id_minlen
= -1;
642 foreach( int i_node_neighbour
, n2n
[_nodes
[id_node
]] ) {
643 vtkIdType id_node_neighbour
= nodes
[i_node_neighbour
];
645 grid
->GetPoint( id_node_neighbour
, M
.data() );
646 double len
= ( M
- C
).abs();
647 if ( minlen
< 0 or len
< minlen
) {
649 id_minlen
= id_node_neighbour
;
655 vtkIdType
SurfaceOperation::getFarthestNode( vtkIdType id_node
)
657 l2l_t n2n
= getPartN2N();
658 g2l_t _nodes
= getPartLocalNodes();
659 l2g_t nodes
= getPartNodes();
662 grid
->GetPoint( id_node
, C
.data() );
663 vtkIdType id_maxlen
= -1;
665 foreach( int i_node_neighbour
, n2n
[_nodes
[id_node
]] ) {
666 vtkIdType id_node_neighbour
= nodes
[i_node_neighbour
];
668 grid
->GetPoint( id_node_neighbour
, M
.data() );
669 double len
= ( M
- C
).abs();
670 if ( maxlen
< 0 or len
> maxlen
) {
672 id_maxlen
= id_node_neighbour
;
678 QVector
<vtkIdType
> SurfaceOperation::getPotentialSnapPoints( vtkIdType id_node
)
680 if ( id_node
< 0 || id_node
>= m_PotentialSnapPoints
.size() ) EG_BUG
;
681 return m_PotentialSnapPoints
[id_node
];
684 // bool SurfaceOperation::DeletePoint( vtkIdType DeadNode, int& num_newpoints, int& num_newcells )
686 // QSet <vtkIdType> DeadNodes;
687 // DeadNodes.insert( DeadNode );
688 // bool ret = DeleteSetOfPoints( DeadNodes, num_newpoints, num_newcells );
691 // //End of DeletePoint