1 #ifndef __CPM__ALGORITHMS__QUADEDGE__MESHEULEROPERATORJOINVERTEXFUNCTION__HXX__
2 #define __CPM__ALGORITHMS__QUADEDGE__MESHEULEROPERATORJOINVERTEXFUNCTION__HXX__
4 #include <cpm/Algorithms/QuadEdge/MeshZipFunction.h>
6 // -------------------------------------------------------------------------
9 cpm::Algorithms::QuadEdge::MeshEulerOperatorJoinVertexFunction< M >::
11 cpm::Algorithms::QuadEdge::MeshEulerOperatorJoinVertexFunction< M >::
12 Evaluate( const TInput& e )
15 this->m_EdgeStatus = this->CheckStatus( e, del_edges );
18 switch( this->m_EdgeStatus )
20 case Self::STANDARD_CONFIG: out = this->Process( e ); break;
21 case Self::QUADEDGE_ISOLATED: out = this->ProcessQuadEdge( e ); break;
22 case Self::FACE_ISOLATED: out = this->ProcessFace( e, del_edges ); break;
23 default: out = NULL; break;
28 // e->IsIsolated( ) && e_sym->IsIsolated( )
29 case Self::EDGE_ISOLATED:
30 // more than 2 common vertices in 0-ring of org and dest respectively
31 case Self::TOO_MANY_COMMON_VERTICES:
33 case Self::TETRAHEDRON_CONFIG:
35 case Self::SAMOSA_CONFIG:
37 case Self::EYE_CONFIG:
39 case Self::EDGE_JOINING_DIFFERENT_BORDERS:
46 // -------------------------------------------------------------------------
48 cpm::Algorithms::QuadEdge::MeshEulerOperatorJoinVertexFunction< M >::
49 MeshEulerOperatorJoinVertexFunction( )
52 m_EdgeStatus( Self::STANDARD_CONFIG )
56 // -------------------------------------------------------------------------
58 cpm::Algorithms::QuadEdge::MeshEulerOperatorJoinVertexFunction< M >::
59 ~MeshEulerOperatorJoinVertexFunction( )
63 // -------------------------------------------------------------------------
66 cpm::Algorithms::QuadEdge::MeshEulerOperatorJoinVertexFunction< M >::
68 cpm::Algorithms::QuadEdge::MeshEulerOperatorJoinVertexFunction< M >::
69 CommonVertexNeighboor( TEdge* e )
72 TEdge* e_it = qe->GetOnext( );
74 typedef std::list< TPointId > TPointIdList;
75 TPointIdList dir_list;
76 TPointIdList sym_list;
77 TPointIdList intersection_list;
82 id = e_it->GetDestination( );
83 dir_list.push_back( id );
84 e_it = e_it->GetOnext( );
93 id = e_it->GetDestination( );
94 sym_list.push_back( id );
95 e_it = e_it->GetOnext( );
102 std::set_intersection(
103 dir_list.begin( ), dir_list.end( ),
104 sym_list.begin( ), sym_list.end( ),
105 std::back_inserter( intersection_list )
108 return( static_cast< TPointId >( intersection_list.size( ) ) );
111 // -------------------------------------------------------------------------
114 cpm::Algorithms::QuadEdge::MeshEulerOperatorJoinVertexFunction< M >::
115 IsTetrahedron( TEdge* e )
117 typedef typename M::CellIdentifier _TCellId;
118 if( true /* TODO: e->GetOrder( ) == 3 */ )
120 TEdge* e_sym = e->GetSym( );
121 if( true /* TODO e_sym->GetOrder( ) == 3 */ )
123 if( true /* TODO e->GetLprev( )->GetOrder( ) == 3 */ )
125 if( true /* TODO e_sym->GetLprev( )->GetOrder( ) == 3 */ )
127 bool left_triangle; // TODO: = e->IsLnextOfTriangle( );
128 bool right_triangle; // TODO: = e_sym->IsLnextOfTriangle( );
130 if( left_triangle && right_triangle )
132 _TCellId id_left_right_triangle;
133 if( e->GetLprev( )->IsRightSet( ) )
134 id_left_right_triangle = e->GetLprev( )->GetRight( );
138 _TCellId id_left_left_triangle;
139 if( e->GetLnext( )->IsRightSet( ) )
140 id_left_left_triangle = e->GetLnext( )->GetRight( );
144 _TCellId id_right_left_triangle;
145 if( e_sym->GetLnext( )->IsRightSet( ) )
146 id_right_left_triangle = e_sym->GetLnext( )->GetRight( );
150 _TCellId id_right_right_triangle;
151 if( e_sym->GetLprev( )->IsRightSet( ) )
152 id_right_right_triangle = e_sym->GetLprev( )->GetRight( );
157 ( id_left_right_triangle == id_right_left_triangle ) &&
158 ( id_left_left_triangle == id_right_right_triangle )
173 // -------------------------------------------------------------------------
176 cpm::Algorithms::QuadEdge::MeshEulerOperatorJoinVertexFunction< M >::
177 IsFaceIsolated( TEdge* e, bool iWasLeftFace, TStack& oToBeDeleted )
180 TEdge* e_sym = e->GetSym( );
182 // turn around the face( left or right one ) while edges are on the border
183 // and push them into a stack( which will be used to delete properly all
185 TEdge* temp =( iWasLeftFace == true )? e: e_sym;
188 oToBeDeleted.push( e_it );
189 e_it = e_it->GetLnext( );
192 oToBeDeleted.push( e_it );
193 border = e_it->IsAtBorder( );
194 e_it = e_it->GetLnext( );
196 while( ( e_it != temp ) && border );
201 // -------------------------------------------------------------------------
204 cpm::Algorithms::QuadEdge::MeshEulerOperatorJoinVertexFunction< M >::
207 // TODO return( ( e->GetOrder( ) == 2 ) && ( e->GetSym( )->GetOrder( ) == 2 ) );
211 // -------------------------------------------------------------------------
214 cpm::Algorithms::QuadEdge::MeshEulerOperatorJoinVertexFunction< M >::
217 bool OriginOrderIsTwo; // TODO =( e->GetOrder( ) == 2 );
218 bool DestinationOrderIsTwo; // TODO =( e->GetSym( )->GetOrder( ) == 2 );
221 ( OriginOrderIsTwo && !DestinationOrderIsTwo ) ||
222 ( !OriginOrderIsTwo && DestinationOrderIsTwo )
226 // -------------------------------------------------------------------------
229 cpm::Algorithms::QuadEdge::MeshEulerOperatorJoinVertexFunction< M >::
230 IsEdgeLinkingTwoDifferentBorders( TEdge* e )
238 org_border = e_it->IsAtBorder( );
239 e_it = e_it->GetOnext( );
241 while( ( e_it != t ) &&( !org_border ) );
249 dest_border = e_it->IsAtBorder( );
250 e_it = e_it->GetOnext( );
252 while( ( e_it != t ) &&( !dest_border ) );
254 return( dest_border );
260 // -------------------------------------------------------------------------
263 cpm::Algorithms::QuadEdge::MeshEulerOperatorJoinVertexFunction< M >::
265 cpm::Algorithms::QuadEdge::MeshEulerOperatorJoinVertexFunction< M >::
266 CheckStatus( TEdge* e, TStack& oToBeDeleted )
268 TEdge* e_sym = e->GetSym( );
270 bool IsEdgeIsolated = e->IsIsolated( );
271 bool IsSymEdgeIsolated = e_sym->IsIsolated( );
272 if( IsEdgeIsolated || IsSymEdgeIsolated )
274 if( IsEdgeIsolated && IsSymEdgeIsolated )
276 // We could shrink the edge to a point,
277 // But we consider this case to be degenerated.
278 itkDebugMacro( "Argument edge isolated." );
279 return( Self::EDGE_ISOLATED );
283 // One the endpoints( and only one ) of the incoming edge is isolated.
284 // Instead of "shrinking" the edge it suffice to delete it. Note that
285 // this also avoids trouble since the definition of leftZip or rightZip
286 // would be improper in this case( in fact leftZip or rightZip would
287 // in fact be e or e->GetSym( )...
289 // When e is adjacent to a face, we must retrieve the edge [ a, b ]
290 // in order to rebuild the face after edge deletion. If the left face
291 // of e is set then the right face is also set... since it is the same
292 // face ! Here is the situation:
301 // We are not yet sure of the orientation of e and which endpoint
302 // of e is attached in a.
303 return( Self::QUADEDGE_ISOLATED );
306 TPointId number_common_vertices = this->CommonVertexNeighboor( e );
307 if( number_common_vertices > 2 )
310 "The 2 vertices have more than 2 common neighboor vertices."
312 return( Self::TOO_MANY_COMMON_VERTICES );
316 if( number_common_vertices == 2 )
318 if( this->IsTetrahedron( e ) )
320 itkDebugMacro( "It forms a tetrahedron." );
321 return( Self::TETRAHEDRON_CONFIG );
328 bool wasLeftFace = e->IsLeftSet( );
329 bool wasRightFace = e->IsRightSet( );
331 if( wasLeftFace && wasRightFace )
333 if( this->IsSamosa( e ) )
335 itkDebugMacro( "Self::SAMOSA_CONFIG." );
336 return( Self::SAMOSA_CONFIG );
339 if( this->IsEye( e ) )
341 itkDebugMacro( "Self::EYE_CONFIG." );
342 return( Self::EYE_CONFIG );
345 if( this->IsEdgeLinkingTwoDifferentBorders( e ) )
347 itkDebugMacro( "Self::EDGE_JOINING_DIFFERENT_BORDERS." );
348 return( Self::EDGE_JOINING_DIFFERENT_BORDERS );
354 if( wasLeftFace || wasRightFace )
356 if( this->IsFaceIsolated( e, wasLeftFace, oToBeDeleted ) )
358 itkDebugMacro( "Self::FACE_ISOLATED." );
359 return( Self::FACE_ISOLATED );
366 return( Self::STANDARD_CONFIG );
369 // -------------------------------------------------------------------------
372 cpm::Algorithms::QuadEdge::MeshEulerOperatorJoinVertexFunction< M >::
374 cpm::Algorithms::QuadEdge::MeshEulerOperatorJoinVertexFunction< M >::
377 TEdge* e_sym = e->GetSym( );
380 bool wasLeftFace = e->IsLeftSet( );
381 bool wasRightFace = e->IsRightSet( );
382 bool wasLeftTriangle; // TODO = e->IsLnextOfTriangle( );
383 bool wasRightTriangle; // TODO = e_sym->IsLnextOfTriangle( );
385 TPointId NewDest = e->GetDestination( );
386 TPointId NewOrg = e->GetOrigin( );
387 TEdge* leftZip = e->GetLnext( );
388 TEdge* rightZip = e->GetOprev( );
394 // ------------------ b ------------- Y //
396 // _<_leftZip__/ | | //
398 // X left e right | //
399 // \____________ | | //
402 // ------------------ a -rightZip->-- Y //
407 // TODO: this->m_Mesh->LightWeightDeleteEdge( e );
408 // TODO: this->m_OldPointID = this->m_Mesh->Splice( leftZip, rightZip );
413 // __<_leftZip___ | / __/ | //
416 // X NOFACE __ [a = b] NOFACE | //
417 // \ / / / | \ \__ | //
418 // \______________/ _/ / | \ \__ | //
419 // __/ / | \ rightZip | //
423 // When the Lnext and/or the Rnext ring of the argument edge was originally
424 // the one[s] of a triangle, the above edge deletion created the odd
425 // situation of having two different edges adjacent to the same two
426 // vertices( which is quite a bad thing ). This is was is depicted on
427 // the above ascii-graph, the original left face was a triangle and
428 // the resulting situation has two different edges adjacent to the
429 // two vertices X and a. In order to clean up things, we can call the
430 // Zip( MeshFunction ) algorithm which handles this case.
431 // Once things are back to normal, we recreate faces when they were
432 // originally present.
435 typedef MeshZipFunction< M > _TZip;
436 if( wasLeftTriangle )
438 typename _TZip::Pointer zip = _TZip::New( );
439 zip->SetMesh( this->m_Mesh );
440 if( TEdge::NoGeometry != zip->Evaluate( leftZip ) )
442 itkDebugMacro( "Zip must return NoPoint( left )." );
451 this->m_Mesh->AddFace( leftZip );
455 // NewOrg = rightZip->GetOprev( )->GetDestination( );
456 if( wasRightTriangle )
458 NewOrg = rightZip->GetDestination( );
459 typename _TZip::Pointer zip = _TZip::New( );
460 zip->SetMesh( this->m_Mesh );
461 if( TEdge::NoGeometry != zip->Evaluate( rightZip ) )
463 itkDebugMacro( "Zip must return NoPoint( right )." );
470 NewOrg = rightZip->GetLprev( )->GetOrigin( );
473 this->m_Mesh->AddFace( rightZip );
477 TOutput result = this->m_Mesh->FindEdge( NewOrg, NewDest );
479 result = this->m_Mesh->FindEdge( NewDest )->GetSym( );
483 // -------------------------------------------------------------------------
486 cpm::Algorithms::QuadEdge::MeshEulerOperatorJoinVertexFunction< M >::
488 cpm::Algorithms::QuadEdge::MeshEulerOperatorJoinVertexFunction< M >::
489 ProcessQuadEdge( TEdge* e )
491 TEdge* temp = ( e->IsIsolated( ) == true )? e->GetSym( ): e;
492 TEdge* rebuildEdge = temp->GetOprev( );
494 this->m_OldPointID = temp->GetSym( )->GetOrigin( );
496 bool e_leftset = e->IsLeftSet( );
497 // TODO: this->m_Mesh->LightWeightDeleteEdge( e );
500 this->m_Mesh->AddFace( rebuildEdge );
503 // this case has no symetric case in SPlitVertex
504 // i.e. it is impossible to reconstruct such a pathological
505 // case using SplitVertex. Thus the return value is
507 // We return an edge whose dest is a, whichever.
508 return( rebuildEdge );
511 // -------------------------------------------------------------------------
514 cpm::Algorithms::QuadEdge::MeshEulerOperatorJoinVertexFunction< M >::
516 cpm::Algorithms::QuadEdge::MeshEulerOperatorJoinVertexFunction< M >::
517 ProcessFace( TEdge* e, TStack& EdgesToBeDeleted )
519 TPointId org = e->GetOrigin( );
520 TPointId dest = e->GetDestination( );
522 // delete all elements
523 while( !EdgesToBeDeleted.empty( ) )
525 // TODO: this->m_Mesh->LightWeightDeleteEdge( EdgesToBeDeleted.top( ) );
526 EdgesToBeDeleted.pop( );
529 // it now retuns one edge from NewDest or NewOrg if there are any
531 TEdge* temp = this->m_Mesh->FindEdge( dest );
535 return( this->m_Mesh->FindEdge( org ) );
539 // __CPM__ALGORITHMS__QUADEDGE__MESHEULEROPERATORJOINVERTEXFUNCTION__HXX__