Skip to Content.
Sympa Menu

cgal-discuss - Re: [cgal-discuss] fix border edges for mesh simplification

Subject: CGAL users discussion list

List archive

Re: [cgal-discuss] fix border edges for mesh simplification


Chronological Thread 
  • From: "Qianqian Fang" <>
  • To:
  • Subject: Re: [cgal-discuss] fix border edges for mesh simplification
  • Date: Tue, 1 Apr 2008 13:37:09 -0400
  • Domainkey-signature: a=rsa-sha1; c=nofws; d=gmail.com; s=beta; h=message-id:date:from:to:subject:in-reply-to:mime-version:content-type:references; b=sf4R2inzk0Uli+KdpdpGrHoPipNVVY+SQfS9V/RCD413WFzBZxMdU6bstaHQk3xhzBhHHUz4N+cI18POdrkFaHT32jrdICnI+vU20lRGPw6aYzqzx1M4v/3CxUGikdMjlr+XT1VakH9rUk6X6bPp8oInwoaE9+y8fODoabau/uw=

thank you Fernando

Now the code compiles normally. Unfortunately, the simplified surface mesh is similar to the
old one:some of the border edges were collapsed.

My test dataset (testoff.off) and my modified code (including your class) are attached.
There are 348 border nodes and edges in the mesh. The command line to run the test is

./edge_collapse_enriched_polyhedron testoff.off 0.05


the output info is :

Edges collected: 164574
822622

Edges collected: 164574
Edges proccessed: 52708
Edges collapsed: 51576

Edges not collapsed due to topological constrians: 591
Edge not collapsed due to cost computation constrians: 0
Edge not collapsed due to placement computation constrians: 540

Finished...
156348 edges removed.
8226 final edges.

There are 540 edges were not collapsed due to placement constrains, seems the
wrapper class is functioning. This number is greater than 348, I guess it is the
total edges connect to border nodes? (a little smaller than I expected though)

do you think there could be an indexing problem while removing the edges from
the surface?

I don't want to spend too much of your time on this, but if you have some quick
thoughts or ideas where to look at, that would be great help.

thank you again

Qianqian


On Tue, Apr 1, 2008 at 11:33 AM, Fernando Cacciola <> wrote:
Hi Qianqian,

> Fernando Cacciola wrote:
>> Hi Qianqian,
>>
>>> typedef typename Profile::const_in_edge_iterator
>>> const_in_edge_iterator ;
>>
> Replacing the above line to
> typedef typename Profile::ConstGraphTraits::const_in_edge_iterator
> const_in_edge_iterator ;
>
> the error message became:
>
> edge_collapse_enriched_polyhedron.cpp:142: error: no type named
> 'const_in_edge_iterator' in 'struct boost::graph_traits<const
> CGAL::Polyhedron_3<CGAL::Simple_cartesian<double>,
> CGAL::Polyhedron_items_with_id_3, CGAL::HalfedgeDS_default,
> std::allocator<int> > >'
>
> seems something still not quite right.
>
OK...
I couldn't compile the warpper myself because the development version of the
package was broken and I had been postponing fixing it until I finish something
else.
But now I just fixed it, so I was able to try the wrapper myself...
There were some additional errors, but the attached version works AFAICT.

Best

Fernando Cacciola
GeometryFactory
--
You are currently subscribed to cgal-discuss.
To unsubscribe or access the archives, go to
https://lists-sop.inria.fr/wws/info/cgal-discuss

#include <iostream>
#include <fstream>

#include <CGAL/Simple_cartesian.h>
#include <CGAL/Polyhedron_3.h>
#include <CGAL/IO/Polyhedron_iostream.h>

// Adaptor for Polyhedron_3
#include <CGAL/Surface_mesh_simplification/HalfedgeGraph_Polyhedron_3.h>

// Simplification function
#include <CGAL/Surface_mesh_simplification/edge_collapse.h>

// Extended polyhedron items which include an id() field
#include <CGAL/Polyhedron_items_with_id_3.h>

// Stop-condition policy
#include <CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Count_ratio_stop_predicate.h>

// Non-default cost and placement policies
#include <CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Midpoint_and_length.h> 

typedef CGAL::Simple_cartesian<double> Kernel;

typedef Kernel::Point_3 Point ;

//
// Setup an enriched polyhedron type which stores an id() field in the items
//
typedef CGAL::Polyhedron_3<Kernel,CGAL::Polyhedron_items_with_id_3> Surface; 

typedef Surface::Halfedge_handle Halfedge_handle ;

namespace SMS = CGAL::Surface_mesh_simplification ;

typedef SMS::Edge_profile<Surface> Profile ;


// The following is a Visitor that keeps track of the simplification process.
// In this example the progress is printed real-time and a few statistics are
// recorded (and printed in the end).
//
struct Visitor
{
  Visitor() 
    : collected(0)
    , processed(0)
    , collapsed(0)
    , non_collapsable(0)
    , cost_uncomputable(0) 
    , placement_uncomputable(0) 
  {} 

  // Called on algorithm entry  
  void OnStarted( Surface& ) {} 
  
  // Called on algorithm exit  
  void OnFinished ( Surface& ) { std::cerr << "\n" << std::flush ; } 
  
  // Called when the stop condition returned true
  void OnStopConditionReached( Profile const& ) {} 
  
  // Called during the collecting phase for each edge collected.
  void OnCollected( Profile const&, boost::optional<double> const& )
  {
    ++ collected ;
    std::cerr << "\rEdges collected: " << collected << std::flush ;
  }                
  
  // Called during the processing phase for each edge selected.
  // If cost is absent the edge won't be collapsed.
  void OnSelected(Profile const&          
                 ,boost::optional<double> cost
                 ,std::size_t             initial
                 ,std::size_t             current
                 )
  {
    ++ processed ;
    if ( !cost )
      ++ cost_uncomputable ;
      
    if ( current == initial )
      std::cerr << "\n" << std::flush ;
    std::cerr << "\r" << current << std::flush ;
  }                
  
  // Called during the processing phase for each edge being collapsed.
  // If placement is absent the edge is left uncollapsed.
  void OnCollapsing(Profile const&          
                   ,boost::optional<Point>  placement
                   )
  {
    if ( placement )
         ++ collapsed;
    else ++ placement_uncomputable ;
  }                
  
  // Called for each edge which failed the so called link-condition,
  // that is, which cannot be collapsed because doing so would
  // turn the surface into a non-manifold.
  void OnNonCollapsable( Profile const& )
  {
    ++ non_collapsable;
  }                
  
  std::size_t  collected
             , processed
             , collapsed
             , non_collapsable
             , cost_uncomputable  
             , placement_uncomputable ; 
} ;

template<class GetPlacement_>
struct Placement_with_fixed_border_vertices : GetPlacement_
{
  typedef GetPlacement_ GetPlacement ;

  typedef typename GetPlacement::Profile Profile ;

  typedef typename GetPlacement::result_type result_type ;

  typedef typename Profile::ECM                     ECM ;
  typedef typename Profile::const_vertex_descriptor const_vertex_descriptor ;
  typedef typename Profile::const_edge_descriptor   const_edge_descriptor ;
  
  typedef typename Profile::ConstGraphTraits::in_edge_iterator const_in_edge_iterator ;
  
  result_type operator()( Profile const& aProfile ) const
  {
     if ( is_border_vertex(aProfile.v0(), aProfile.surface()) || is_border_vertex(aProfile.v1(), aProfile.surface()) )
           return boost::none ;
     else
          return this->GetPlacement::operator()(aProfile);
  }

  bool is_border_vertex( const_vertex_descriptor v, ECM& aSurface ) const
  {
    bool rR = false ;

    const_in_edge_iterator eb, ee ; 
    for ( boost::tie(eb,ee) = boost::in_edges(v,aSurface) ; eb != ee ; ++ eb )
    {
      const_edge_descriptor lEdge = *eb ;
      if ( lEdge->is_border() || lEdge->opposite()->is_border() )
      {
        rR = true ;
        break ;
      }
    }  
 
    return rR ;  
  }
} ;



typedef Placement_with_fixed_border_vertices< SMS::Midpoint_placement<Surface> > My_placement ;

int main( int argc, char** argv ) 
{
  Surface surface; 
  float maxface=0.1;

  std::ifstream is(argv[1]) ; is >> surface ;
  if(argc>2) maxface=atof(argv[2]);

  printf("max face ratio=%f\n",maxface);
   
   
  // The items in this polyhedron have an "id()" field 
  // which the default index maps used in the algorithm
  // need to get the index of a vertex/edge.
  // However, the Polyhedron_3 class doesn't assign any value to
  // this id(), so we must do it here:
  int index = 0 ;
  
  for( Surface::Halfedge_iterator eb = surface.halfedges_begin()
     , ee = surface.halfedges_end()
     ; eb != ee
     ; ++ eb
     ) 
    eb->id() = index++;

  index = 0 ;
  for( Surface::Vertex_iterator vb = surface.vertices_begin()
     , ve = surface.vertices_end()
     ; vb != ve
     ; ++ vb
     ) 
    vb->id() = index++;
    
  // In this example, the simplification stops when the number of undirected edges
  // drops below 10% of the initial count
  SMS::Count_ratio_stop_predicate<Surface> stop(maxface);
     
  Visitor vis ;
  
  // The index maps are not explicitelty passed as in the previous
  // example because the surface items have a proper id() field.
  // On the other hand, we pass here explicit cost and placement
  // function which differ from the default policies, ommited in
  // the previous example.
  int r = SMS::edge_collapse
           (surface
           ,stop
           ,CGAL::get_cost     (SMS::Edge_length_cost  <Surface>())
                 .get_placement( My_placement() )
                 .visitor(&vis)
           );
  
  std::cout << "\nEdges collected: " << vis.collected
            << "\nEdges proccessed: " << vis.processed
            << "\nEdges collapsed: " << vis.collapsed
            << std::endl
            << "\nEdges not collapsed due to topological constrians: " 
            << vis.non_collapsable
            << "\nEdge not collapsed due to cost computation constrians: " 
            << vis.cost_uncomputable 
            << "\nEdge not collapsed due to placement computation constrians: " 
            << vis.placement_uncomputable 
            << std::endl ; 
            
  std::cout << "\nFinished...\n" << r << " edges removed.\n" 
            << (surface.size_of_halfedges()/2) << " final edges.\n" ;
        
  std::ofstream os( argc > 3 ? argv[3] : "out.off" ) ; os << surface ;
  
  return 0 ;      
}



// EOF //

Attachment: testoff.off.gz
Description: GNU Zip compressed data




Archive powered by MHonArc 2.6.16.

Top of Page