1 #ifndef __CPM__ALGORITHMS__QUADEDGE__EDGEDECIMATIONFILTER__HXX__
2 #define __CPM__ALGORITHMS__QUADEDGE__EDGEDECIMATIONFILTER__HXX__
4 #include <itkTriangleHelper.h>
6 // -------------------------------------------------------------------------
7 template< class I, class O, class C >
8 cpm::Algorithms::QuadEdge::EdgeDecimationFilter< I, O, C >::
9 EdgeDecimationFilter( )
12 m_CheckOrientation( false ),
15 this->m_JoinVertexFunction = TOperator::New( );
16 this->m_PriorityQueue = TPriorityQueue::New( );
19 // -------------------------------------------------------------------------
20 template< class I, class O, class C >
21 cpm::Algorithms::QuadEdge::EdgeDecimationFilter< I, O, C >::
22 ~EdgeDecimationFilter( )
26 while( !( this->m_PriorityQueue->Empty( ) ) )
28 edge = this->m_PriorityQueue->Peek( )->m_Element;
29 this->m_PriorityQueue->Pop( );
31 typename TQueueMap::iterator it = this->m_QueueMapper.find( edge );
33 this->m_QueueMapper.erase( it );
38 // -------------------------------------------------------------------------
39 template< class I, class O, class C >
40 void cpm::Algorithms::QuadEdge::EdgeDecimationFilter< I, O, C >::
43 typename O::Pointer output = this->GetOutput( );
45 this->m_JoinVertexFunction->SetMesh( output );
47 /* TODO: fill queue with qedges
48 typename O::CellsContainerIterator it = output->GetEdgeCells( )->Begin( );
49 typename O::CellsContainerIterator end = output->GetEdgeCells( )->End( );
51 OutputEdgeCellType* edge;
53 // cache for use in MeasureEdge
54 this->GetOutput( ) = this->GetOutput( );
58 edge = dynamic_cast< OutputEdgeCellType* >( it.Value( ) );
62 PushElement( edge->GetQEGeom( ) );
69 // -------------------------------------------------------------------------
70 template< class I, class O, class C >
71 void cpm::Algorithms::QuadEdge::EdgeDecimationFilter< I, O, C >::
72 PushElement( TOutPrimalEdge* iEdge )
74 TOutPointIdentifier id_org = iEdge->GetOrigin( );
75 TOutPointIdentifier id_dest = iEdge->GetDestination( );
77 TOutPrimalEdge* temp =( id_org < id_dest ) ? iEdge : iEdge->GetSym( );
78 TScalar measure = MeasureEdge( temp );
80 TPriorityQueueItem* qi = new TPriorityQueueItem( temp,
81 TPriority( false, measure ) );
83 this->m_QueueMapper[ temp ] = qi;
84 this->m_PriorityQueue->Push( qi );
87 // -------------------------------------------------------------------------
88 template< class I, class O, class C >
89 bool cpm::Algorithms::QuadEdge::EdgeDecimationFilter< I, O, C >::
90 IsEdgeOKToBeProcessed( TOutPrimalEdge* iEdge )
95 // -------------------------------------------------------------------------
96 template< class I, class O, class C >
97 void cpm::Algorithms::QuadEdge::EdgeDecimationFilter< I, O, C >::
100 typename O::Pointer output = this->GetOutput( );
104 this->m_Element = this->m_PriorityQueue->Peek( )->m_Element;
105 this->m_Priority = this->m_PriorityQueue->Peek( )->m_Priority;
107 this->m_PriorityQueue->Pop( );
108 typename TQueueMap::iterator it = this->m_QueueMapper.find( this->m_Element );
110 this->m_QueueMapper.erase( it );
112 while( !IsEdgeOKToBeProcessed( this->m_Element ) );
115 // -------------------------------------------------------------------------
116 template< class I, class O, class C >
117 void cpm::Algorithms::QuadEdge::EdgeDecimationFilter< I, O, C >::
118 DeleteElement( TOutPrimalEdge* iEdge )
120 if( iEdge ) // this test can be removed
122 TOutPrimalEdge* temp =( iEdge->GetOrigin( ) < iEdge->GetDestination( ) ) ?
123 iEdge : iEdge->GetSym( );
125 typename TQueueMap::iterator map_it = this->m_QueueMapper.find( temp );
126 if( map_it != this->m_QueueMapper.end( ) )
128 if( !map_it->second->m_Priority.first )
130 TPriorityQueueItem* e( map_it->second );
131 this->m_PriorityQueue->DeleteElement( e );
132 delete map_it->second;
133 this->m_QueueMapper.erase( map_it );
139 // -------------------------------------------------------------------------
140 template< class I, class O, class C >
141 void cpm::Algorithms::QuadEdge::EdgeDecimationFilter< I, O, C >::
143 const TOutPointIdentifier& iIdToBeDeleted,
144 const TOutPointIdentifier& iRemaining
149 this->GetOutput( )->DeletePoint( iIdToBeDeleted );
153 // -------------------------------------------------------------------------
154 template< class I, class O, class C >
155 void cpm::Algorithms::QuadEdge::EdgeDecimationFilter< I, O, C >::
156 PushOrUpdateElement( TOutPrimalEdge* iEdge )
158 TOutPrimalEdge* temp = iEdge;
160 if( temp->GetOrigin( ) > temp->GetDestination( ) )
162 temp = temp->GetSym( );
165 typename TQueueMap::iterator map_it = this->m_QueueMapper.find( temp );
167 TScalar measure = MeasureEdge( temp );
168 if( map_it != this->m_QueueMapper.end( ) )
170 if( !map_it->second->m_Priority.first )
172 map_it->second->m_Priority.second = measure;
173 this->m_PriorityQueue->Update( map_it->second );
178 TPriorityQueueItem* qi = new TPriorityQueueItem( temp,
179 TPriority( false, measure ) );
180 this->m_QueueMapper[ temp ] = qi;
181 this->m_PriorityQueue->Push( qi );
185 // -------------------------------------------------------------------------
186 template< class I, class O, class C >
187 void cpm::Algorithms::QuadEdge::EdgeDecimationFilter< I, O, C >::
190 typename TOperator::TEdgeStatus
191 status = this->m_JoinVertexFunction->GetEdgeStatus( );
195 case TOperator::EDGE_NULL:
196 case TOperator::MESH_NULL:
197 case TOperator::FACE_ISOLATED:
199 case TOperator::EDGE_ISOLATED:
200 itkDebugMacro( "EDGE_ISOLATED, at iteration: " << this->m_Iteration );
201 TagElementOut( this->m_Element );
203 // more than 2 common vertices in 0-ring of org and dest respectively
204 case TOperator::TOO_MANY_COMMON_VERTICES:
205 itkDebugMacro( "TOO_MANY_COMMON_VERTICES, at iteration "
206 << this->m_Iteration );
207 itkDebugMacro( << this->m_Element->GetOrigin( ) << " -> "
208 << this->m_Element->GetDestination( ) );
209 this->TagElementOut( this->m_Element );
211 // ******************************************************************
213 case TOperator::TETRAHEDRON_CONFIG:
214 itkDebugMacro( "TETRAHEDRON_CONFIG, at iteration " << this->m_Iteration );
216 this->TagElementOut( this->m_Element );
217 this->TagElementOut( this->m_Element->GetOnext( ) );
218 this->TagElementOut( this->m_Element->GetOprev( ) );
219 this->TagElementOut( this->m_Element->GetSym( ) );
220 this->TagElementOut( this->m_Element->GetSym( )->GetOnext( ) );
221 this->TagElementOut( this->m_Element->GetSym( )->GetOprev( ) );
222 this->TagElementOut( this->m_Element->GetOnext( )->GetLnext( ) );
224 // ******************************************************************
226 case TOperator::SAMOSA_CONFIG:
227 itkDebugMacro( "SAMOSA_CONFIG, at iteration " << this->m_Iteration );
228 this->RemoveSamosa( );
230 // ******************************************************************
232 case TOperator::EYE_CONFIG:
233 itkDebugMacro( "EYE_CONFIG, at iteration " << this->m_Iteration );
236 case TOperator::EDGE_JOINING_DIFFERENT_BORDERS:
237 itkDebugMacro( "EDGE_JOINING_DIFFERENT_BORDERS, at iteration "
238 << this->m_Iteration );
239 this->TagElementOut( this->m_Element );
244 // -------------------------------------------------------------------------
245 template< class I, class O, class C >
246 bool cpm::Algorithms::QuadEdge::EdgeDecimationFilter< I, O, C >::
247 ProcessWithoutAnyTopologicalGuarantee( )
251 TOutPointIdentifier id_org = this->m_Element->GetOrigin( );
252 TOutPointIdentifier id_dest = this->m_Element->GetDestination( );
253 TOutPointIdentifier idx =( id_org < id_dest ) ? id_org : id_dest;
255 bool to_be_processed( true );
257 if( this->m_Relocate )
259 pt = Relocate( this->m_Element );
263 pt = this->GetOutput( )->GetPoint( idx );
266 ///TODO use CheckOrientation!!!
267 // if( this->m_CheckOrientation )
268 // to_be_processed = CheckOrientation( this->m_Element, idx, pt );
270 if( !to_be_processed )
275 std::list< TOutPrimalEdge* > list_qe_to_be_deleted;
276 TOutPrimalEdge* temp = this->m_Element->GetOnext( );
278 while( temp != this->m_Element )
280 list_qe_to_be_deleted.push_back( temp );
281 temp = temp->GetOnext( );
284 temp = this->m_Element->GetSym( )->GetOnext( );
285 while( temp != this->m_Element->GetSym( ) )
287 list_qe_to_be_deleted.push_back( temp );
288 temp = temp->GetOnext( );
291 typename std::list< TOutPrimalEdge* >::iterator
292 it = list_qe_to_be_deleted.begin( );
294 while( it != list_qe_to_be_deleted.end( ) )
296 DeleteElement( *it );
300 if( !this->m_JoinVertexFunction->Evaluate( this->m_Element ) )
302 it = list_qe_to_be_deleted.begin( );
304 while( it != list_qe_to_be_deleted.end( ) )
306 PushOrUpdateElement( *it );
314 TOutPointIdentifier old_id = this->m_JoinVertexFunction->GetOldPointID( );
316 TOutPointIdentifier new_id =( old_id == id_dest ) ? id_org : id_dest;
317 DeletePoint( old_id, new_id );
319 TOutPrimalEdge* edge = this->GetOutput( )->FindEdge( new_id );
320 if( edge == ITK_NULLPTR )
322 itkDebugMacro( "edge == 0, at iteration " << this->m_Iteration );
326 if( this->m_Relocate )
328 this->GetOutput( )->SetPoint( new_id, pt );
335 PushOrUpdateElement( temp );
336 temp = temp->GetOnext( );
338 while( temp != edge );
343 // -------------------------------------------------------------------------
344 template< class I, class O, class C >
345 unsigned int cpm::Algorithms::QuadEdge::EdgeDecimationFilter< I, O, C >::
346 CheckQEProcessingStatus( )
348 TOutPrimalEdge* qe = this->m_Element;
349 TOutPrimalEdge* qe_sym = qe->GetSym( );
352 bool LeftIsTriangle = qe->IsLnextOfTriangle( );
353 bool RightIsTriangle = qe->GetSym( )->IsLnextOfTriangle( );
355 bool LeftIsTriangle = false;
356 bool RightIsTriangle = false;
358 if( LeftIsTriangle || RightIsTriangle )
360 if( LeftIsTriangle && RightIsTriangle )
363 bool OriginOrderIsTwo;// TODO: =( qe->GetOrder( ) == 2 );
364 bool DestinationOrderIsTwo;// TODO: =( qe_sym->GetOrder( ) == 2 );
366 if( OriginOrderIsTwo || DestinationOrderIsTwo )
368 if( OriginOrderIsTwo && DestinationOrderIsTwo )
370 // isolated component made of two triangles
371 // sharing same points but with opposite orientation
372 // looks like a samosa
373 itkDebugMacro( "RemoveSamosa" );
375 } // end if( OriginOrderIsTwo && DestinationOrderIsTwo )
378 // two triangles share three points and two edges
379 // the last edge is duplicated = two edge cells
380 // having the same points. It is a valid manifold case
381 // but you have to decimate it the right way.
382 // from the top the drawing of that case looks like an Eye
383 itkDebugMacro( "RemoveEye" );
385 } // end else if( OriginOrderIsTwo && DestinationOrderIsTwo )
386 } // end if( OriginOrderIsTwo || DestinationOrderIsTwo )
387 else // if( OriginOrderIsTwo || DestinationOrderIsTwo )
389 if( NumberOfCommonVerticesIn0Ring( ) > 2 )
391 // both points have more than 2 edges on their O-ring
392 itkDebugMacro( "NumberOfCommonVerticesIn0Ring( ) > 2" );
394 } //end if( NumberOfCommonVerticesIn0Ring( ) > 2 )
399 } // end else if( OriginOrderIsTwo || DestinationOrderIsTwo )
400 } // end if( LeftIsTriangle && RightIsTriangle )
401 else // if( LeftIsTriangle && RightIsTriangle )
403 if( NumberOfCommonVerticesIn0Ring( ) > 1 )
405 itkDebugMacro( "NumberOfCommonVerticesIn0Ring( ) > 1" );
407 } // end if( NumberOfCommonVerticesIn0Ring( ) > 1 )
408 else // if( NumberOfCommonVerticesIn0Ring( ) > 1 )
410 if( RightIsTriangle )
418 } // end else if( NumberOfCommonVerticesIn0Ring( ) > 1 )
419 } // end else if( LeftIsTriangle && RightIsTriangle )
420 } // end if( LeftIsTriangle || RightIsTriangle )
421 else // if( LeftIsTriangle || RightIsTriangle )
423 if( NumberOfCommonVerticesIn0Ring( ) > 0 )
431 } // end if( LeftIsTriangle || RightIsTriangle )
436 // -------------------------------------------------------------------------
437 template< class I, class O, class C >
438 bool cpm::Algorithms::QuadEdge::EdgeDecimationFilter< I, O, C >::
439 ProcessWithTopologicalGuarantee( )
441 if( this->m_Priority.first )
446 ProcessWithoutAnyTopologicalGuarantee( );
450 // -------------------------------------------------------------------------
451 template< class I, class O, class C >
452 unsigned long cpm::Algorithms::QuadEdge::EdgeDecimationFilter< I, O, C >::
453 NumberOfCommonVerticesIn0Ring( ) const
455 TOutPrimalEdge* qe = this->m_Element;
456 TOutPrimalEdge* e_it = qe->GetOnext( );
458 std::list< TOutPointIdentifier > dir_list, sym_list, intersection_list;
461 dir_list.push_back( e_it->GetDestination( ) );
462 e_it = e_it->GetOnext( );
471 sym_list.push_back( e_it->GetDestination( ) );
472 e_it = e_it->GetOnext( );
479 std::set_intersection( dir_list.begin( ), dir_list.end( ),
480 sym_list.begin( ), sym_list.end( ),
481 std::back_inserter( intersection_list ) );
483 return( static_cast< unsigned long >( intersection_list.size( ) ) );
486 // -------------------------------------------------------------------------
487 template< class I, class O, class C >
488 void cpm::Algorithms::QuadEdge::EdgeDecimationFilter< I, O, C >::
491 DeleteElement( this->m_Element->GetLnext( ) );
492 DeleteElement( this->m_Element->GetLprev( ) );
493 DeleteElement( this->m_Element->GetRnext( ) );
494 DeleteElement( this->m_Element->GetRprev( ) );
497 // -------------------------------------------------------------------------
498 template< class I, class O, class C >
499 void cpm::Algorithms::QuadEdge::EdgeDecimationFilter< I, O, C >::
500 TagElementOut( TOutPrimalEdge* iEdge )
502 typename TQueueMap::iterator map_it = this->m_QueueMapper.find( iEdge );
504 if( map_it != this->m_QueueMapper.end( ) )
506 map_it->second->m_Priority.first = true;
507 map_it->second->m_Priority.second = static_cast< TScalar >( 0. );
508 this->m_PriorityQueue->Update( map_it->second );
512 TPriorityQueueItem* qi = new TPriorityQueueItem( iEdge,
513 TPriority( true, static_cast< TScalar >( 0. ) ) );
515 this->m_QueueMapper[ iEdge ] = qi;
516 this->m_PriorityQueue->Push( qi );
520 // -------------------------------------------------------------------------
521 template< class I, class O, class C >
522 void cpm::Algorithms::QuadEdge::EdgeDecimationFilter< I, O, C >::
525 TOutPrimalEdge* qe = this->m_Element;
526 TOutPrimalEdge* qe_sym = this->m_Element->GetSym( );
529 if( qe->GetSym( )->GetOrder( ) == 2 )
536 TagElementOut( qe->GetOnext( ) );
537 TagElementOut( qe->GetSym( )->GetOnext( ) );
538 TagElementOut( qe->GetSym( )->GetOprev( ) );
541 // -------------------------------------------------------------------------
542 template< class I, class O, class C >
543 bool cpm::Algorithms::QuadEdge::EdgeDecimationFilter< I, O, C >::
544 CheckOrientation( TOutPrimalEdge* iEdge,
545 const TOutPointIdentifier& iId,
546 const TOutPoint& iPt )
548 typename O::Pointer output = this->GetOutput( );
549 typename O::CellsContainerPointer cells = output->GetCells( );
551 std::list< typename O::CellIdentifier > r1, r2, elements_to_be_tested;
552 TOutPrimalEdge* qe = iEdge;
553 TOutPrimalEdge* qe_it = qe->GetOnext( );
557 r1.push_back( qe_it->GetLeft( ) );
558 qe_it = qe_it->GetOnext( );
560 while( qe_it != qe );
562 qe = iEdge->GetSym( );
563 qe_it = qe->GetOnext( );
567 r2.push_back( qe_it->GetLeft( ) );
568 qe_it = qe_it->GetOnext( );
570 while( qe_it != qe );
575 std::set_symmetric_difference( r1.begin( ), r1.end( ),
576 r2.begin( ), r2.end( ),
577 std::back_inserter( elements_to_be_tested ) );
579 typename std::list< typename O::CellIdentifier >::iterator
580 it = elements_to_be_tested.begin( );
582 typedef itk::TriangleHelper< TOutPoint > TTriangle;
584 bool orientation_ok( true );
585 typename O::CellIdentifier c_id( 0 );
587 /* TODO: iterate over polygons
588 OutputPolygonType* poly;
589 TOutPointIdentifier p_id;
591 int k( 0 ), replace_k( 0 );
594 OutputVectorType n_bef, n_aft;
596 while( ( it != elements_to_be_tested.end( ) ) && orientation_ok )
599 poly = dynamic_cast< OutputPolygonType* >( cells->GetElement( c_id ) );
600 qe = poly->GetEdgeRingEntry( );
605 p_id = qe_it->GetOrigin( );
610 pt[ k++ ] = output->GetPoint( p_id );
611 qe_it = qe_it->GetLnext( );
613 while( qe_it != qe );
615 n_bef = TTriangle::ComputeNormal( pt[ 0 ], pt[ 1 ], pt[ 2 ] );
620 n_aft = TTriangle::ComputeNormal( iPt, pt[ 1 ], pt[ 2 ] );
623 n_aft = TTriangle::ComputeNormal( pt[ 0 ], iPt, pt[ 2 ] );
626 n_aft = TTriangle::ComputeNormal( pt[ 0 ], pt[ 1 ], iPt );
630 orientation_ok =( n_bef * n_aft ) < 0.;
634 return( orientation_ok );
637 // -------------------------------------------------------------------------
638 template< class I, class O, class C >
639 bool cpm::Algorithms::QuadEdge::EdgeDecimationFilter< I, O, C >::
640 IsCriterionSatisfied( )
642 if( this->m_PriorityQueue->Empty( ) )
648 return( this->m_Criterion->is_satisfied( this->GetOutput( ), 0, this->m_Priority.second ) );
652 #endif // __CPM__ALGORITHMS__QUADEDGE__EDGEDECIMATIONFILTER__HXX__