Removed or untracked irrelevant files

Also fixed some data paths.
This commit is contained in:
Mael Rouxel-Labbé 2017-02-21 13:41:52 +01:00
parent 4570ab4320
commit c2bc4082e7
9 changed files with 2 additions and 3296 deletions

View File

@ -56,7 +56,6 @@ if ( CGAL_FOUND )
create_single_source_cgal_program( "discrete_authalic.cpp" )
create_single_source_cgal_program( "lscm.cpp" )
create_single_source_cgal_program( "orbifold.cpp" )
create_single_source_cgal_program( "orbifold_mapping.cpp" )
create_single_source_cgal_program( "seam_Polyhedron_3.cpp" )
create_single_source_cgal_program( "simple_parameterization.cpp" )
create_single_source_cgal_program( "square_border_parameterizer.cpp" )

View File

@ -1,269 +0,0 @@
/***************************************************************************
begin : jan 02
copyright : (C) 2002 by Pierre Alliez
email : pierre.alliez@sophia.inria.fr
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#ifndef MESH_CUTTER_H
#define MESH_CUTTER_H
#include "Polyhedron_ex.h"
#include <list>
#include <cassert>
class Mesh_cutter
{
// Public types
public:
typedef std::list<Polyhedron_ex::Halfedge_handle>
Backbone;
// Private types
private:
typedef My_kernel::Vector_3 Vector_3;
typedef My_kernel::Point_3 Point_3;
enum {FREE,DONE,FIXED};
// Public operations
public:
// life cycle
Mesh_cutter(Polyhedron_ex& polyhedron)
{
m_pPolyhedron = &polyhedron;
m_pBackbone = NULL;
}
~Mesh_cutter() {}
void cut(Backbone& backbone);
void cut_genus(Backbone& backbone);
// Private operations
private:
// genus > 0
bool init();
bool simplify();
bool extend();
void precompute_distances();
Polyhedron_ex::Halfedge_handle pick_best_halfedge(
std::list<Polyhedron_ex::Halfedge_handle>::iterator &pos);
void recursive_tag(Polyhedron_ex::Facet_handle pFacet,int index);
// Fields
private:
Polyhedron_ex* m_pPolyhedron; // the model to cut
Backbone* m_pBackbone; // the backbone to fill
Polyhedron_ex::Facet_handle m_pSeedFacet;
Polyhedron_ex::Vertex_handle m_pSeedVertex;
};
//***************************************************
// simple cut for genus 0 mesh
//***************************************************
inline void Mesh_cutter::cut(Backbone& backbone)
{
m_pBackbone = &backbone;
// special init -> tag all vertices, but two
m_pPolyhedron->tag_vertices(FREE);
Polyhedron_ex::Vertex_handle pVertexMin,pVertexMax;
m_pPolyhedron->farthest_point_aligned(pVertexMin,pVertexMax);
pVertexMin->tag(FIXED);
pVertexMax->tag(FIXED);
init();
// cutting
while(extend()) {}
}
/////////////////////////////////////////////////////
// GENUS > 0
/////////////////////////////////////////////////////
//***************************************************
// cut for genus>0 mesh
//***************************************************
inline void Mesh_cutter::cut_genus(Backbone& backbone)
{
m_pBackbone = &backbone;
// init
m_pPolyhedron->tag_vertices(FREE); // all free
init();
// cutting
while(extend()) {}
}
//***************************************************
// init
//***************************************************
inline bool Mesh_cutter::init()
{
// tag facets
m_pPolyhedron->tag_facets(FREE);
// compute bounding box and center
double xmin = m_pPolyhedron->minimum(0);
double ymin = m_pPolyhedron->minimum(1);
double zmin = m_pPolyhedron->minimum(2);
double xmax = m_pPolyhedron->maximum(0);
double ymax = m_pPolyhedron->maximum(1);
double zmax = m_pPolyhedron->maximum(2);
double xcenter = 0.5*(xmin+xmax);
double ycenter = 0.5*(ymin+ymax);
double zcenter = 0.5*(zmin+zmax);
Point_3 center(xcenter,ycenter,zcenter);
// get closest facet
m_pSeedFacet = m_pPolyhedron->get_closest_inner_facet(center);
assert(m_pSeedFacet != NULL);
Polyhedron_ex::Halfedge_handle he = m_pSeedFacet->halfedge();
assert(he != NULL);
assert(m_pBackbone != NULL);
m_pBackbone->push_back(he);
m_pBackbone->push_back(he->next());
m_pBackbone->push_back(he->next()->next());
precompute_distances();
m_pSeedFacet->tag(DONE);
return true;
}
//***************************************************
// extend
//***************************************************
inline bool Mesh_cutter::extend()
{
std::list<Polyhedron_ex::Halfedge_handle>::iterator pos;
Polyhedron_ex::Halfedge_handle pHalfedge = pick_best_halfedge(pos);
if(pHalfedge == NULL)
return false;
// flag facet
pHalfedge->opposite()->facet()->tag(DONE);
// insert halfedge
std::list<Polyhedron_ex::Halfedge_handle>::iterator tmp =
m_pBackbone->insert(pos,pHalfedge->opposite()->next()->next());
m_pBackbone->insert(tmp,pHalfedge->opposite()->next());
// remove this one
m_pBackbone->remove(pHalfedge);
// simplify current backbone
while(simplify()) {}
return true;
}
//***************************************************
// simplify
//***************************************************
inline bool Mesh_cutter::simplify()
{
// cleanup
std::list<Polyhedron_ex::Halfedge_handle>::iterator iter;
for(iter = m_pBackbone->begin();
iter != m_pBackbone->end();
iter++)
{
Polyhedron_ex::Halfedge_handle pHalfedge = (*iter);
Polyhedron_ex::Halfedge_handle opposite = pHalfedge->opposite();
// get next halfedge in the list
iter++;
Polyhedron_ex::Halfedge_handle pNext = NULL;
if(iter == m_pBackbone->end()) // loop
pNext = (*m_pBackbone->begin());
else
pNext = (*iter);
if(pNext == opposite &&
pHalfedge->vertex()->tag() == FREE)
{
m_pBackbone->remove(pHalfedge);
m_pBackbone->remove(opposite);
return true;
}
iter--; // restore
}
return false;
}
//***************************************************
// precompute_distances
//***************************************************
inline void Mesh_cutter::precompute_distances()
{
Polyhedron_ex::Halfedge_iterator pHalfedge;
for(pHalfedge = m_pPolyhedron->halfedges_begin();
pHalfedge != m_pPolyhedron->halfedges_end();
pHalfedge++)
pHalfedge->distance(m_pPolyhedron->distance(m_pSeedFacet,pHalfedge));
}
//***************************************************
// pick_best_halfedge
//***************************************************
inline Polyhedron_ex::Halfedge_handle Mesh_cutter::pick_best_halfedge(
std::list<Polyhedron_ex::Halfedge_handle>::iterator &pos)
{
Polyhedron_ex::Halfedge_handle pBest = NULL;
double min_distance = 1e308; //
// cleanup
std::list<Polyhedron_ex::Halfedge_handle>::iterator iter;
for(iter = m_pBackbone->begin();
iter != m_pBackbone->end();
iter++)
{
Polyhedron_ex::Halfedge_handle pHalfedge = (*iter);
Polyhedron_ex::Halfedge_handle opposite = pHalfedge->opposite();
Polyhedron_ex::Facet_handle pFacet = opposite->facet();
// check
if(pHalfedge->is_border() ||
pFacet == NULL)
continue;
if(pFacet->tag() == DONE)
continue;
// no border vertex
Polyhedron_ex::Vertex_handle pVertex = opposite->next()->vertex();
if(m_pPolyhedron->is_border(pVertex))
continue;
// precomputed distance
double distance = pHalfedge->distance();
if(distance < min_distance)
{
pos = iter;
pBest = pHalfedge;
min_distance = distance;
}
}
return pBest;
}
#endif // MESH_CUTTER_H

View File

@ -1,596 +0,0 @@
#ifndef POLYHEDRON_EX_H_INCLUDED
#define POLYHEDRON_EX_H_INCLUDED
#include <CGAL/Simple_cartesian.h>
#include <CGAL/Polyhedron_3.h>
#include <CGAL/IO/Polyhedron_iostream.h>
#include <algorithm>
#include <vector>
#include <list>
#include <fstream>
#include <cassert>
// CGAL kernel
typedef CGAL::Simple_cartesian<double> My_kernel;
// compute facet center
struct Facet_center
{
typedef My_kernel::Vector_3 Vector_3;
typedef My_kernel::Point_3 Point_3;
template<class Facet>
void operator()(Facet& f)
{
Vector_3 vec(0.0,0.0,0.0);
int degree = 0;
typedef typename Facet::Halfedge_around_facet_const_circulator circ;
circ h = f.facet_begin();
do
{
vec = vec + (h->vertex()->point()-CGAL::ORIGIN);
degree++;
}
while (++h != f.facet_begin());
f.center() = CGAL::ORIGIN + (vec/degree);
}
};
template<class Refs, class T>
class My_facet : public CGAL::HalfedgeDS_face_base<Refs, T>
{
public:
typedef My_kernel::Vector_3 Vector_3;
typedef My_kernel::Point_3 Point_3;
// life cycle
// no constructors to repeat, since only
// default constructor mandatory
My_facet()
{
m_tag = -1; // uninitialized
}
// center
Point_3& center() { return m_center; }
const Point_3& center() const { return m_center; }
// tag
int tag() const { return m_tag; }
void tag(int tag) { m_tag = tag; }
// distance
double distance(Point_3& point) const
{
Vector_3 vec = (point-m_center);
return std::sqrt(vec*vec);
}
// Fields
private:
// facet data
int m_tag;
Point_3 m_center;
};
template<class Refs, class Tprev, class Tvertex, class Tface>
class My_halfedge
: public CGAL::HalfedgeDS_halfedge_base<Refs,Tprev,Tvertex,Tface>
{
private:
int m_tag;
// parameterization
bool m_is_parameterized;
int m_seaming; // seaming status
double m_u; // texture coordinates
double m_v;
int m_index; // for parameterization
// surface cutting
double m_distance;
public:
// life cycle
// no constructors to repeat, since only
// default constructor mandatory
My_halfedge()
{
m_tag = -1; // uninitialized
m_u = 0.0;
m_v = 0.0;
m_index = -1; // uninitialized
m_seaming = -1; // uninitialized
m_is_parameterized = false;
}
// tag
int tag() const { return m_tag; }
void tag(int tag) { m_tag = tag; }
// seaming status
int seaming() const { return m_seaming; }
void seaming(int seaming) { m_seaming = seaming; }
// precomputed distance
double distance() const { return m_distance; }
void distance(double distance) { m_distance = distance; }
// texture coordinates
double u() const { return m_u; }
double v() const { return m_v; }
void uv(double u, double v) { m_u = u; m_v = v; }
// param.
bool is_parameterized() const { return m_is_parameterized; }
void is_parameterized(bool is) { m_is_parameterized = is; }
// index
int index() const { return m_index; }
void index(int i) { m_index = i; }
};
// A redefined vertex class for the Polyhedron_3
template<class Refs, class T, class P>
class My_vertex : public CGAL::HalfedgeDS_vertex_base<Refs, T, P>
{
// index
int m_index;
// misc
int m_tag;
// seaming status
int m_seaming;
public:
// life cycle
My_vertex() { init(); }
// repeat mandatory constructors
My_vertex(const P& pt)
: CGAL::HalfedgeDS_vertex_base<Refs, T, P>(pt)
{
init();
}
void init()
{
m_index = -1; // uninitialized
m_tag = -1; // uninitialized
m_seaming = -1; // uninitialized
}
// index
int index() const { return m_index; }
void index(int i) { m_index = i; }
// tag
int tag() const { return m_tag; }
void tag(int tag) { m_tag = tag; }
// seaming status
int seaming() const { return m_seaming; }
void seaming(int seaming) { m_seaming = seaming; }
};
// A redefined items class for the Polyhedron_3 with a refined vertex, facet and halfedge classes
struct My_items : public CGAL::Polyhedron_items_3
{
typedef My_kernel::Vector_3 Vector_3;
typedef My_kernel::Point_3 Point_3;
// wrap vertex
template<class Refs, class Traits>
struct Vertex_wrapper
{
typedef typename Traits::Point_3 Point_3;
typedef My_vertex<Refs,
CGAL::Tag_true,
Point_3> Vertex;
};
// wrap facet
template<class Refs, class Traits>
struct Face_wrapper
{
typedef My_facet<Refs,
CGAL::Tag_true> Face;
};
// wrap halfedge
template<class Refs, class Traits>
struct Halfedge_wrapper
{
typedef My_halfedge<Refs,
CGAL::Tag_true,
CGAL::Tag_true,
CGAL::Tag_true> Halfedge;
};
};
class Polyhedron_ex : public CGAL::Polyhedron_3<My_kernel,My_items>
{
public:
typedef My_kernel::Vector_3 Vector_3;
typedef My_kernel::Point_3 Point_3;
public:
// life cycle
Polyhedron_ex() {}
virtual ~Polyhedron_ex() {}
// facet centers
void compute_facet_centers()
{
std::for_each(facets_begin(),facets_end(),Facet_center());
}
// tag all facets
void tag_facets(const int tag)
{
Facet_iterator pFace;
for(pFace = facets_begin();
pFace != facets_end();
pFace++)
pFace->tag(tag);
}
// get closest inner facet
Facet_handle get_closest_inner_facet(Point_3& point)
{
Facet_iterator pFace = facets_begin();
Facet_handle pClosest = pFace;
double minimum = pFace->distance(point);
for(;pFace != facets_end();
pFace++)
{
if(is_inner(pFace))
{
double distance = pFace->distance(point);
if(distance < minimum)
{
pClosest = pFace;
minimum = distance;
}
}
}
return pClosest;
}
bool is_inner(Facet_handle pFace)
{
typedef Halfedge_around_facet_const_circulator circ;
circ h = pFace->facet_begin();
do
{
if(h->opposite()->is_border())
return false;
}
while(++h != pFace->facet_begin());
return true;
}
// tag all vertices
void tag_vertices(const int tag)
{
Vertex_iterator iter;
for(iter = vertices_begin(); iter != vertices_end(); iter++)
iter->tag(tag);
}
// tag all halfedges
void tag_halfedges(const int tag)
{
Halfedge_iterator iter;
for(iter = halfedges_begin(); iter != halfedges_end(); iter++)
iter->tag(tag);
}
// compute bounding interval
double minimum (int coord)
{
assert(size_of_vertices() > 0);
Vertex_iterator pVertex = vertices_begin();
double minimum = pVertex->point()[coord];
for(;pVertex != vertices_end();pVertex++)
minimum = (std::min)(minimum,pVertex->point()[coord]);
return minimum;
}
double maximum (int coord)
{
assert(size_of_vertices() > 0);
Vertex_iterator pVertex = vertices_begin();
double maximum = pVertex->point()[coord];
for(;pVertex != vertices_end();pVertex++)
maximum = (std::max)(maximum,pVertex->point()[coord]);
return maximum;
}
Vertex_handle vertex_min(int coord,
double &minimum)
{
assert(size_of_vertices() > 0);
Vertex_iterator pVertex = vertices_begin();
Vertex_handle pBest = pVertex;
minimum = pVertex->point()[coord];
for(;pVertex != vertices_end();pVertex++)
{
double value = pVertex->point()[coord];
if(value < minimum)
{
minimum = (std::min)(minimum,value);
pBest = pVertex;
}
}
return pBest;
}
Vertex_handle vertex_max(int coord,
double &maximum)
{
assert(size_of_vertices() > 0);
Vertex_iterator pVertex = vertices_begin();
Vertex_handle pBest = pVertex;
maximum = pVertex->point()[coord];
for(;pVertex != vertices_end();pVertex++)
{
double value = pVertex->point()[coord];
if(value > maximum)
{
maximum = (std::max)(maximum,value);
pBest = pVertex;
}
}
return pBest;
}
// Index all mesh vertices following the order of the vertices_begin() iterator
void precompute_vertex_indices()
{
Vertex_iterator pVertex;
unsigned int i = 0;
for(pVertex = vertices_begin();
pVertex != vertices_end();
pVertex++)
pVertex->index(i++);
}
// Index all mesh half edges following the order of the halfedges_begin() iterator
void precompute_halfedge_indices()
{
Halfedge_iterator pHalfedge;
unsigned int i = 0;
for(pHalfedge = halfedges_begin();
pHalfedge != halfedges_end();
pHalfedge++)
pHalfedge->index(i++);
}
#ifdef DEBUG_TRUNCATE_OUTPUT
// Debug: write coordinates with 2 digits precision
#define FORMAT_EPS_COORD(x) (int(x/10.0+0.5)*10)
#else
#define FORMAT_EPS_COORD(x) (x)
#endif
// Dump parameterized mesh to an eps file
bool write_file_eps(const char *pFilename,
double scale = 500.0)
{
assert(pFilename != NULL);
std::ofstream out(pFilename);
if(!out)
return false;
CGAL::set_ascii_mode(out);
// compute bounding box
double xmin,xmax,ymin,ymax;
xmin = ymin = xmax = ymax = 0;
Halfedge_iterator pHalfedge;
for(pHalfedge = halfedges_begin();
pHalfedge != halfedges_end();
pHalfedge++)
{
double x1 = scale * pHalfedge->prev()->u();
double y1 = scale * pHalfedge->prev()->v();
double x2 = scale * pHalfedge->u();
double y2 = scale * pHalfedge->v();
xmin = (std::min)(xmin,x1);
xmin = (std::min)(xmin,x2);
xmax = (std::max)(xmax,x1);
xmax = (std::max)(xmax,x2);
ymax = (std::max)(ymax,y1);
ymax = (std::max)(ymax,y2);
ymin = (std::min)(ymin,y1);
ymin = (std::min)(ymin,y2);
}
out << "%!PS-Adobe-2.0 EPSF-2.0" << std::endl;
out << "%%BoundingBox: " << int(xmin+0.5) << " "
<< int(ymin+0.5) << " "
<< int(xmax+0.5) << " "
<< int(ymax+0.5) << std::endl;
out << "%%HiResBoundingBox: " << xmin << " "
<< ymin << " "
<< xmax << " "
<< ymax << std::endl;
out << "%%EndComments" << std::endl;
out << "gsave" << std::endl;
out << "0.1 setlinewidth" << std::endl;
// color macros
out << std::endl;
out << "% RGB color command - r g b C" << std::endl;
out << "/C { setrgbcolor } bind def" << std::endl;
out << "/white { 1 1 1 C } bind def" << std::endl;
out << "/black { 0 0 0 C } bind def" << std::endl;
// edge macro -> E
out << std::endl;
out << "% Black stroke - x1 y1 x2 y2 E" << std::endl;
out << "/E {moveto lineto stroke} bind def" << std::endl;
out << "black" << std::endl << std::endl;
// output edge coordinates
for(pHalfedge = halfedges_begin();
pHalfedge != halfedges_end();
pHalfedge++)
{
double x1 = scale * pHalfedge->prev()->u();
double y1 = scale * pHalfedge->prev()->v();
double x2 = scale * pHalfedge->u();
double y2 = scale * pHalfedge->v();
out << FORMAT_EPS_COORD(x1) << " "
<< FORMAT_EPS_COORD(y1) << " "
<< FORMAT_EPS_COORD(x2) << " "
<< FORMAT_EPS_COORD(y2) << " E" << std::endl;
}
/* Emit EPS trailer. */
out << "grestore" << std::endl;
out << std::endl;
out << "showpage" << std::endl;
return true;
}
#ifdef DEBUG_TRUNCATE_OUTPUT
// Debug: write coordinates with 2 digits precision
#define FORMAT_UV(x) (float(int(x*100.0+0.5))/100.0)
#else
#define FORMAT_UV(x) (x)
#endif
// Dump parameterized mesh to a Wavefront OBJ file
// v x y z
// f 1 2 3 4 (1-based)
//
// Implementation note: the UV is meaningless for a NON parameterized halfedge
bool write_file_obj(const char *pFilename)
{
assert(pFilename != NULL);
std::ofstream out(pFilename);
if(!out)
return false;
CGAL::set_ascii_mode(out);
// Index all mesh vertices following the order of vertices_begin() iterator
precompute_vertex_indices();
// Index all mesh half edges following the order of halfedges_begin() iterator
precompute_halfedge_indices();
// write the name of material file
out << "mtllib parameterization.mtl" << std::endl ;
// output coordinates
out << "# vertices" << std::endl ;
Vertex_iterator pVertex;
for(pVertex = vertices_begin(); pVertex != vertices_end(); pVertex++)
out << "v " << pVertex->point().x() << " "
<< pVertex->point().y() << " "
<< pVertex->point().z() << std::endl;
// Write UVs (1 UV / halfedge)
out << "# uv coordinates" << std::endl ;
Halfedge_iterator pHalfedge;
for(pHalfedge = halfedges_begin(); pHalfedge != halfedges_end(); pHalfedge++)
{
if (pHalfedge->is_parameterized())
out << "vt " << FORMAT_UV(pHalfedge->u()) << " " << FORMAT_UV(pHalfedge->v()) << std::endl;
else
out << "vt " << 0.0 << " " << 0.0 << std::endl;
}
// Write facets using the unique material # 1
out << "# facets" << std::endl;
out << "usemtl Mat_1" << std::endl;
Facet_const_iterator pFacet;
for(pFacet = facets_begin(); pFacet != facets_end(); pFacet++)
{
Halfedge_around_facet_const_circulator h = pFacet->facet_begin();
out << "f";
do {
out << " " << h->vertex()->index()+1;
if (h->is_parameterized())
out << "/" << h->index()+1;
}
while(++h != pFacet->facet_begin());
out << std::endl;
}
return true;
}
// is vertex on border ?
static bool is_border(Vertex_const_handle pVertex)
{
Halfedge_around_vertex_const_circulator pHalfedge = pVertex->vertex_begin();
Halfedge_around_vertex_const_circulator end = pHalfedge;
if(pHalfedge == NULL) // isolated vertex
return true;
CGAL_For_all(pHalfedge,end)
if(pHalfedge->is_border())
return true;
return false;
}
// compute distance from facet center to halfedge center
double distance(Facet_handle pFacet,
Halfedge_handle pHalfedge)
{
// we assume
Point_3 center_facet = pFacet->center();
Vector_3 v = (pHalfedge->opposite()->vertex()->point()
- pHalfedge->vertex()->point());
Point_3 center_halfedge = pHalfedge->vertex()->point() + (v/2);
Vector_3 d = center_facet-center_halfedge;
return std::sqrt(d*d);
}
void farthest_point_aligned(Vertex_handle &pVertexMin,
Vertex_handle &pVertexMax)
{
double xmin,xmax,ymin,ymax,zmin,zmax;
Vertex_handle pVertex_xMin = vertex_min(0,xmin);
Vertex_handle pVertex_xMax = vertex_max(0,xmax);
Vertex_handle pVertex_yMin = vertex_min(1,ymin);
Vertex_handle pVertex_yMax = vertex_max(1,ymax);
Vertex_handle pVertex_zMin = vertex_min(2,zmin);
Vertex_handle pVertex_zMax = vertex_max(2,zmax);
double xdiff = xmax-xmin;
double ydiff = ymax-ymin;
double zdiff = zmax-zmin;
if (xdiff >= (std::max)(ydiff,zdiff))
{
pVertexMin = pVertex_xMin;
pVertexMax = pVertex_xMax;
}
else if (ydiff >= (std::max)(xdiff,zdiff))
{
pVertexMin = pVertex_yMin;
pVertexMax = pVertex_yMax;
}
else
{
pVertexMin = pVertex_zMin;
pVertexMax = pVertex_zMax;
}
}
}; // end class PolyhedronEx
#endif // POLYHEDRON_EX_H_INCLUDED

View File

@ -53,7 +53,7 @@ int main(int argc, char * argv[])
CGAL::Timer task_timer;
task_timer.start();
const char* mesh_filename = (argc>1) ? argv[1] : "../data/bear.off";
const char* mesh_filename = (argc>1) ? argv[1] : "data/bear.off";
std::ifstream in_mesh(mesh_filename);
if(!in_mesh) {
std::cerr << "Error: problem loading the input data" << std::endl;
@ -67,7 +67,7 @@ int main(int argc, char * argv[])
// -- the first line for the cones indices
// -- the second line must be empty
// -- the third line optionally provides the seam edges indices as 'e11 e12 e21 e22 e31 e32' etc.
const char* cone_filename = (argc>2) ? argv[2] : "../data/bear.selection.txt";
const char* cone_filename = (argc>2) ? argv[2] : "data/bear.selection.txt";
// Read the cones and find the corresponding vertex_descriptor in the underlying mesh 'sm'
typedef std::vector<SM_vertex_descriptor> Cones_in_smesh_container;

View File

@ -1,240 +0,0 @@
#include <CGAL/Simple_cartesian.h>
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
#include <CGAL/Surface_mesh.h>
#include <CGAL/boost/graph/graph_traits_Surface_mesh.h>
#include <CGAL/boost/graph/Seam_mesh.h>
#include <CGAL/boost/graph/graph_traits_Seam_mesh.h>
#include <CGAL/Surface_mesh_parameterization/internal/Containers_filler.h>
#include <CGAL/Surface_mesh_parameterization/internal/kernel_traits.h>
#include <CGAL/Surface_mesh_parameterization/internal/shortest_path.h>
#include <CGAL/Surface_mesh_parameterization/Orbifold_Tutte_parameterizer_3.h>
#include <CGAL/Surface_mesh_parameterization/Orbifold_Tutte_sphere_mapping.h>
#include <CGAL/Arr_non_caching_segment_traits_2.h>
#include <CGAL/Arr_segment_traits_2.h>
#include <CGAL/Arrangement_2.h>
#include <CGAL/Polygon_mesh_processing/connected_components.h>
#include <CGAL/Polygon_mesh_processing/measure.h>
#include <CGAL/boost/graph/properties.h>
#include <CGAL/Timer.h>
#include <boost/foreach.hpp>
#include <boost/unordered_map.hpp>
#include <fstream>
#include <iostream>
#include <list>
#include <string>
#include <utility>
#include <vector>
typedef CGAL::Simple_cartesian<double> Kernel;
typedef Kernel::Point_2 Point_2;
typedef Kernel::Point_3 Point_3;
typedef CGAL::Surface_mesh<Kernel::Point_3> SurfaceMesh;
typedef boost::graph_traits<SurfaceMesh>::vertex_descriptor SM_vertex_descriptor;
typedef boost::graph_traits<SurfaceMesh>::halfedge_descriptor SM_halfedge_descriptor;
typedef boost::graph_traits<SurfaceMesh>::edge_descriptor SM_edge_descriptor;
typedef SurfaceMesh::Property_map<SM_edge_descriptor, bool> Seam_edge_pmap;
typedef SurfaceMesh::Property_map<SM_vertex_descriptor, bool> Seam_vertex_pmap;
typedef CGAL::Seam_mesh<SurfaceMesh, Seam_edge_pmap, Seam_vertex_pmap> Mesh;
typedef boost::graph_traits<Mesh>::vertex_descriptor vertex_descriptor;
typedef boost::graph_traits<Mesh>::halfedge_descriptor halfedge_descriptor;
namespace SMP = CGAL::Surface_mesh_parameterization;
// Cones
typedef boost::unordered_map<vertex_descriptor, SMP::Cone_type> ConeMap;
// VertexIndexMap
typedef boost::unordered_map<vertex_descriptor, int> Indices;
typedef boost::associative_property_map<Indices> VertexIndexMap;
// VertexUVMap
typedef SurfaceMesh::Property_map<SM_halfedge_descriptor, Point_2> VertexUVMap;
// Embedded_mesh type to regroup all the info in one class
typedef SMP::internal::Embedded_mesh<Mesh, ConeMap,
VertexIndexMap, VertexUVMap> Embedded_mesh;
int main(int argc, char * argv[])
{
CGAL::Timer task_timer;
task_timer.start();
// Selection file that contains the cones and possibly the path between cones
// -- the first line for the cones indices
// -- the second line must be empty
// -- the third line optionally provides the seam edges indices as 'e11 e12 e21 e22 e31 e32' etc.
const char* mesh_filename_A = (argc>1) ? argv[1] : "../data/bear.off";
const char* cone_filename_A = (argc>2) ? argv[2] : "../data/bear.selection.txt";
const char* mesh_filename_B = (argc>3) ? argv[3] : "../data/sphere.off";
const char* cone_filename_B = (argc>4) ? argv[4] : "../data/sphere2.selection.txt";
const SMP::Orbifold_type orb_type = SMP::Triangle;
// Parameterizer
typedef SMP::Orbifold_Tutte_parameterizer_3<Mesh> Parameterizer;
Parameterizer parameterizer(orb_type, SMP::Cotangent);
// *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
// Parameterization of the first domain
// *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
SurfaceMesh sm_A; // underlying mesh of the seam mesh
std::ifstream in_mesh_A(mesh_filename_A);
if(!in_mesh_A) {
std::cerr << "Error: problem loading the input data" << std::endl;
}
in_mesh_A >> sm_A;
// Read the cones and find the corresponding vertex_descriptor in the underlying mesh 'sm'
typedef std::vector<SM_vertex_descriptor> Cones_in_smesh_container;
Cones_in_smesh_container cone_vds_in_sm_A;
SMP::internal::read_cones<SurfaceMesh>(sm_A, cone_filename_A, cone_vds_in_sm_A);
// Two property maps to store the seam edges and vertices
Seam_edge_pmap seam_edge_pm_A = sm_A.add_property_map<SM_edge_descriptor, bool>("e:on_seam", false).first;
Seam_vertex_pmap seam_vertex_pm_A = sm_A.add_property_map<SM_vertex_descriptor, bool>("v:on_seam",false).first;
// The seam mesh
Mesh mesh_A(sm_A, seam_edge_pm_A, seam_vertex_pm_A);
// Use the path provided between cones to create a seam mesh
SM_halfedge_descriptor smhd_A = mesh_A.add_seams(cone_filename_A);
if(smhd_A == SM_halfedge_descriptor() ) {
std::cout << "No seams were given in input, computing shortest paths between cones" << std::endl;
std::list<SM_edge_descriptor> seam_edges_A;
SMP::internal::compute_shortest_paths_between_cones(sm_A, cone_vds_in_sm_A, seam_edges_A);
// Add the seams to the seam mesh
BOOST_FOREACH(SM_edge_descriptor e, seam_edges_A) {
mesh_A.add_seam(source(e, sm_A), target(e, sm_A));
}
}
std::cout << mesh_A.number_of_seam_edges() << " seam edges" << std::endl;
// Index map of the seam mesh (assuming a single connected component so far)
Indices indices_A;
VertexIndexMap vimap_A(indices_A);
int counter_A = 0;
BOOST_FOREACH(vertex_descriptor vd, vertices(mesh_A)) {
put(vimap_A, vd, counter_A++);
}
// Mark the cones in the seam mesh
ConeMap cmap_A;
SMP::internal::locate_cones<Mesh,
Cones_in_smesh_container,
ConeMap>(mesh_A, cone_vds_in_sm_A, cmap_A);
// The 2D points of the uv parametrisation will be written into this map
// Note that this is a halfedge property map, and that uv values
// are only stored for the canonical halfedges representing a vertex
VertexUVMap uvmap_A = sm_A.add_property_map<SM_halfedge_descriptor, Point_2>("h:uv").first;
// a halfedge on the (possibly virtual) border
// only used in output (will also be used to handle multiple connected components in the future)
halfedge_descriptor bhd_A = CGAL::Polygon_mesh_processing::longest_border(mesh_A,
CGAL::Polygon_mesh_processing::parameters::all_default()).first;
parameterizer.parameterize(mesh_A, bhd_A, cmap_A, uvmap_A, vimap_A);
std::cout << "Parameterized the first domain in " << task_timer.time() << " seconds" << std::endl;
std::ofstream out_A("orbifold_source.off");
SMP::IO::output_uvmap_to_off(mesh_A, bhd_A, uvmap_A, out_A);
Embedded_mesh emesh_A(mesh_A, cmap_A, vimap_A, uvmap_A, orb_type);
// *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
// Parameterization of the second domain
// *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
SurfaceMesh sm_B; // underlying mesh of the seam mesh
std::ifstream in_mesh_B(mesh_filename_B);
if(!in_mesh_B) {
std::cerr << "Error: problem loading the input data" << std::endl;
}
in_mesh_B >> sm_B;
// Read the cones and find the corresponding vertex_descriptor in the underlying mesh 'sm'
typedef std::vector<SM_vertex_descriptor> Cones_in_smesh_container;
Cones_in_smesh_container cone_vds_in_sm_B;
SMP::internal::read_cones<SurfaceMesh>(sm_B, cone_filename_B, cone_vds_in_sm_B);
// Two property maps to store the seam edges and vertices
Seam_edge_pmap seam_edge_pm_B = sm_B.add_property_map<SM_edge_descriptor, bool>("e:on_seam", false).first;
Seam_vertex_pmap seam_vertex_pm_B = sm_B.add_property_map<SM_vertex_descriptor, bool>("v:on_seam",false).first;
// The seam mesh
Mesh mesh_B(sm_B, seam_edge_pm_B, seam_vertex_pm_B);
// Use the path provided between cones to create a seam mesh
SM_halfedge_descriptor smhd_B = mesh_B.add_seams(cone_filename_B);
if(smhd_B == SM_halfedge_descriptor() ) {
std::cout << "No seams were given in input, computing shortest paths between cones" << std::endl;
std::list<SM_edge_descriptor> seam_edges_B;
SMP::internal::compute_shortest_paths_between_cones(sm_B, cone_vds_in_sm_B, seam_edges_B);
// Add the seams to the seam mesh
BOOST_FOREACH(SM_edge_descriptor e, seam_edges_B) {
mesh_B.add_seam(source(e, sm_B), target(e, sm_B));
}
}
std::cout << mesh_B.number_of_seam_edges() << " seam edges" << std::endl;
// Index map of the seam mesh (assuming a single connected component so far)
Indices indices_B;
VertexIndexMap vimap_B(indices_B);
int counter_B = 0;
BOOST_FOREACH(vertex_descriptor vd, vertices(mesh_B)) {
put(vimap_B, vd, counter_B++);
}
// Mark the cones in the seam mesh
ConeMap cmap_B;
SMP::internal::locate_cones<Mesh,
Cones_in_smesh_container,
ConeMap>(mesh_B, cone_vds_in_sm_B, cmap_B);
// The 2D points of the uv parametrisation will be written into this map
// Note that this is a halfedge property map, and that uv values
// are only stored for the canonical halfedges representing a vertex
VertexUVMap uvmap_B = sm_B.add_property_map<SM_halfedge_descriptor, Point_2>("h:uv").first;
// a halfedge on the (possibly virtual) border
// only used in output (will also be used to handle multiple connected components in the future)
halfedge_descriptor bhd_B = CGAL::Polygon_mesh_processing::longest_border(mesh_B,
CGAL::Polygon_mesh_processing::parameters::all_default()).first;
parameterizer.parameterize(mesh_B, bhd_B, cmap_B, uvmap_B, vimap_B);
std::cout << "Parameterized the second domain in " << task_timer.time() << " seconds" << std::endl;
std::ofstream out_B("orbifold_target.off");
SMP::IO::output_uvmap_to_off(mesh_B, bhd_B, uvmap_B, out_B);
Embedded_mesh emesh_B(mesh_B, cmap_B, vimap_B, uvmap_B, orb_type);
// *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
// Mapping
// *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
typedef CGAL::Exact_predicates_exact_constructions_kernel Exact_kernel;
// typedef CGAL::Arr_segment_traits_2<Exact_kernel> Traits_2;
typedef CGAL::Arr_non_caching_segment_traits_2<Exact_kernel> Traits_2;
typedef CGAL::Arrangement_2<Traits_2> Arrangement_2;
typedef SMP::Orbifold_sphere_mapper<Arrangement_2, Embedded_mesh> Orb_sphere_mapper;
Orb_sphere_mapper mapper;
mapper.compute_map_from_sphere_embeddings(emesh_A, emesh_B);
std::cout << "Finished mapping in " << task_timer.time() << " seconds" << std::endl;
}

View File

@ -1,401 +0,0 @@
#define CGAL_CHECK_EXPENSIVE
#include <CGAL/Simple_cartesian.h>
#include <CGAL/Surface_mesh.h>
#include <CGAL/boost/graph/graph_traits_Surface_mesh.h>
#include <CGAL/Polyhedron_3.h>
#include <CGAL/boost/graph/graph_traits_Polyhedron_3.h>
#include <CGAL/boost/graph/Seam_mesh.h>
#include <CGAL/boost/graph/graph_traits_Seam_mesh.h>
#include <CGAL/Surface_mesh_parameterization/Error_code.h>
#include <CGAL/surface_mesh_parameterization.h>
#include <CGAL/Polygon_mesh_processing/measure.h>
#include <boost/foreach.hpp>
#include <boost/functional/hash.hpp>
#include <iostream>
#include <fstream>
namespace SMP = CGAL::Surface_mesh_parameterization;
typedef CGAL::Simple_cartesian<double> Kernel;
typedef Kernel::Point_2 Point_2;
typedef Kernel::Point_3 Point_3;
#define POLY_MESH // Polyhedron mesh
#ifdef POLY_MESH
#define MVC_POLY_MESH
#define BARY_POLY_MESH
#define ARAP_POLY_MESH
#endif
#define SURF_MESH // Surface_mesh
#ifdef SURF_MESH
#define ARAP_SURF_MESH
#endif
#define PM_SEAM_MESH // Polyhedron-based seam mesh
#ifdef PM_SEAM_MESH
#define POLY_MESH
#define ARAP_PM_SEAM_MESH
#endif
#define SM_SEAM_MESH // Surface_mesh-based seam mesh
#ifdef SM_SEAM_MESH
#define SURF_MESH
#define ARAP_SM_SEAM_MESH
#endif
// #define REDIRECT_OUTPUT
#ifdef POLY_MESH
typedef CGAL::Polyhedron_3<Kernel> PMesh;
typedef boost::graph_traits<PMesh>::vertex_descriptor PM_vertex_descriptor;
typedef boost::graph_traits<PMesh>::halfedge_descriptor PM_halfedge_descriptor;
typedef CGAL::Unique_hash_map<PM_halfedge_descriptor, Point_2> PM_UV_hmap;
typedef boost::associative_property_map<PM_UV_hmap> PM_UV_pmap;
#endif
#ifdef SURF_MESH
typedef CGAL::Surface_mesh<Point_3> SMesh;
typedef boost::graph_traits<SMesh>::vertex_descriptor SM_vertex_descriptor;
typedef boost::graph_traits<SMesh>::halfedge_descriptor SM_halfedge_descriptor;
typedef SMesh::Property_map<SM_halfedge_descriptor, Point_2> SM_UV_pmap;
#endif
#ifdef SM_SEAM_MESH
typedef boost::graph_traits<SMesh>::edge_descriptor SM_edge_descriptor;
typedef SMesh::Property_map<SM_edge_descriptor, bool> SM_seam_edge_pmap;
typedef SMesh::Property_map<SM_vertex_descriptor, bool> SM_seam_vertex_pmap;
typedef CGAL::Seam_mesh<SMesh, SM_seam_edge_pmap, SM_seam_vertex_pmap>
SM_Seam_mesh;
typedef boost::graph_traits<SM_Seam_mesh>::vertex_descriptor SM_SE_vertex_descriptor;
typedef boost::graph_traits<SM_Seam_mesh>::halfedge_descriptor SM_SE_halfedge_descriptor;
#endif
#ifdef PM_SEAM_MESH
typedef boost::graph_traits<PMesh>::edge_descriptor PM_edge_descriptor;
typedef CGAL::Unique_hash_map<PM_edge_descriptor, bool> PM_seam_edge_hmap;
typedef boost::associative_property_map<PM_seam_edge_hmap> PM_seam_edge_pmap;
typedef CGAL::Unique_hash_map<PM_vertex_descriptor, bool> PM_seam_vertex_hmap;
typedef boost::associative_property_map<PM_seam_vertex_hmap> PM_seam_vertex_pmap;
typedef CGAL::Seam_mesh<PMesh, PM_seam_edge_pmap, PM_seam_vertex_pmap>
PM_Seam_mesh;
typedef boost::graph_traits<PM_Seam_mesh>::vertex_descriptor PM_SE_vertex_descriptor;
typedef boost::graph_traits<PM_Seam_mesh>::halfedge_descriptor PM_SE_halfedge_descriptor;
#endif
int main(int argc, char * argv[])
{
std::cout.precision(17);
CGAL::set_pretty_mode(std::cout);
#ifdef REDIRECT_OUTPUT
std::freopen("/home/mrouxell/POLY_MESH.txt", "w", stdout);
#endif
// std::ifstream in((argc>1)?argv[1]:"../data/tiny_nef.off");
// std::ifstream in((argc>1)?argv[1]:"../data/nefertiti.off");
// std::ifstream in((argc>1)?argv[1]:"../data/lion.off");
// std::ifstream in((argc>1)?argv[1]:"../data/blob.off");
std::ifstream in((argc>1)?argv[1]:"/home/mrouxell/Data/OFF/mushroom.off");
// std::ifstream in((argc>1)?argv[1]:"/home/mrouxell/Data/OFF/lion-head.off");
// std::ifstream in((argc>1)?argv[1]:"../data/three_peaks.off");
// std::ifstream in((argc>1)?argv[1]:"/home/mrouxell/Data/OFF/three_peaks_dense.off");
// std::ifstream in((argc>1)?argv[1]:"../data/cow_with_hole.off");
// std::ifstream in((argc>1)?argv[1]:"../data/cow_dense.off");
// std::ifstream in((argc>1)?argv[1]:"../data/cow_densified.off");
// std::ifstream in((argc>1)?argv[1]:"../data/mushroom_big_hole.off");
// std::ifstream in((argc>1)?argv[1]:"../data/mushroom_hole_1.off");
// const char* selection = "../data/lion.selection.txt";
const char* selection = "/home/mrouxell/mushroom.selection.txt";
if(!in) {
std::cerr << "Problem loading the input data" << std::endl;
return 1;
}
// ***************************************************************************
// Default case
// ***************************************************************************
#ifdef MVC_POLY_MESH
{
std::cout << "MVC POLY MESH" << std::endl;
PMesh pm;
in >> pm;
PM_halfedge_descriptor hd = CGAL::Polygon_mesh_processing::longest_border(pm).first;
CGAL::Unique_hash_map<PM_vertex_descriptor, Point_2,
boost::hash<PM_vertex_descriptor> > uvhm;
boost::associative_property_map<
CGAL::Unique_hash_map<PM_vertex_descriptor, Point_2,
boost::hash<PM_vertex_descriptor> > > uvpm(uvhm);
// Go to default (aka Mean values)
SMP::parameterize(pm, hd, uvpm);
std::cout << "Parameterized with Default (Mean Values)!" << std::endl;
}
#endif
// ***************************************************************************
// Barycentric mapping
// ***************************************************************************
#ifdef BARY_POLY_MESH
{
std::cout << "BARY POLY MESH" << std::endl;
PMesh pm;
in.clear();
in.seekg(0, std::ios::beg);
in >> pm;
PM_halfedge_descriptor hd = CGAL::Polygon_mesh_processing::longest_border(pm).first;
assert(hd != PM_halfedge_descriptor());
// UV map
CGAL::Unique_hash_map<PM_vertex_descriptor, Point_2,
boost::hash<PM_vertex_descriptor> > uvhm;
boost::associative_property_map<
CGAL::Unique_hash_map<PM_vertex_descriptor, Point_2,
boost::hash<PM_vertex_descriptor> > > uvpm(uvhm);
// Indices map
typedef boost::unordered_map<PM_vertex_descriptor, int> Indices;
Indices indices;
CGAL::Polygon_mesh_processing::connected_component(
face(opposite(hd, pm), pm),
pm,
boost::make_function_output_iterator(
SMP::internal::Index_map_filler<PMesh, Indices>(pm, indices)));
// Vertex parameterized map
boost::unordered_set<PM_vertex_descriptor> vs;
SMP::internal::Bool_property_map<boost::unordered_set<PM_vertex_descriptor> > vpm(vs);
typename SMP::Barycentric_mapping_parameterizer_3<PMesh> parameterizer;
parameterizer.parameterize(pm, hd, uvpm, boost::make_assoc_property_map(indices), vpm);
std::cout << "Parameterized with Barycentric!" << std::endl;
}
#endif
// ***************************************************************************
// ARAP WITH POLY_MESH
// ***************************************************************************
#ifdef ARAP_POLY_MESH
{
std::cout << "ARAP POLY MESH" << std::endl;
PMesh pm;
in.clear();
in.seekg(0, std::ios::beg);
in >> pm;
PM_halfedge_descriptor hd = CGAL::Polygon_mesh_processing::longest_border(pm).first;
// UV map
CGAL::Unique_hash_map<PM_vertex_descriptor, Point_2,
boost::hash<PM_vertex_descriptor> > uvhm;
boost::associative_property_map<
CGAL::Unique_hash_map<PM_vertex_descriptor, Point_2,
boost::hash<PM_vertex_descriptor> > > uvpm(uvhm);
// Indices map
typedef boost::unordered_map<PM_vertex_descriptor, int> Indices;
Indices indices;
CGAL::Polygon_mesh_processing::connected_component(
face(opposite(hd, pm), pm),
pm,
boost::make_function_output_iterator(
SMP::internal::Index_map_filler<PMesh, Indices>(pm, indices)));
boost::associative_property_map<Indices> vipm(indices);
// Vertex parameterized map
boost::unordered_set<PM_vertex_descriptor> vs;
SMP::internal::Bool_property_map<boost::unordered_set<PM_vertex_descriptor> > vpm(vs);
// Parameterizer
typename SMP::ARAP_parameterizer_3<PMesh> parameterizer;
SMP::Error_code status = parameterizer.parameterize(pm, hd, uvpm, vipm, vpm);
if(status != SMP::OK)
std::cout << "Encountered a problem: " << status << std::endl;
else
std::cout << "Parameterized with ARAP!" << std::endl;
}
#endif
// ***************************************************************************
// ARAP WITH SURF_MESH
// ***************************************************************************
#ifdef REDIRECT_OUTPUT
std::freopen("/home/mrouxell/SURF_MESH.txt", "w", stdout);
#endif
#ifdef ARAP_SURF_MESH
{
std::cout << "ARAP SURF MESH" << std::endl;
SMesh sm;
in.clear();
in.seekg(0, std::ios::beg);
in >> sm;
SM_halfedge_descriptor bhd =
CGAL::Polygon_mesh_processing::longest_border(sm).first;
CGAL::Unique_hash_map<SM_vertex_descriptor, Point_2,
boost::hash<SM_vertex_descriptor> > uvhm;
boost::associative_property_map<
CGAL::Unique_hash_map<SM_vertex_descriptor,
Point_2,
boost::hash<SM_vertex_descriptor> > > uv_pm(uvhm);
// Indices map
typedef boost::unordered_map<SM_vertex_descriptor, int> Indices;
Indices indices;
CGAL::Polygon_mesh_processing::connected_component(
face(opposite(bhd, sm), sm),
sm,
boost::make_function_output_iterator(
SMP::internal::Index_map_filler<SMesh, Indices>(sm, indices)));
boost::associative_property_map<Indices> vipm(indices);
boost::unordered_set<SM_vertex_descriptor> vs;
SMP::internal::Bool_property_map< boost::unordered_set<SM_vertex_descriptor> > vpm(vs);
typename SMP::ARAP_parameterizer_3<SMesh> parameterizer;
parameterizer.parameterize(sm, bhd, uv_pm, vipm, vpm);
}
#endif
// ***************************************************************************
// ARAP WITH SEAM_MESH (SM)
// ***************************************************************************
#ifdef ARAP_SM_SEAM_MESH
{
std::cout << "ARAP SURF SEAM MESH" << std::endl;
SMesh sm;
in.clear();
in.seekg(0, std::ios::beg);
in >> sm;
SM_seam_edge_pmap seam_edge_pm =
sm.add_property_map<SM_edge_descriptor,bool>("e:on_seam", false).first;
SM_seam_vertex_pmap seam_vertex_pm =
sm.add_property_map<SM_vertex_descriptor,bool>("v:on_seam", false).first;
SM_Seam_mesh mesh(sm, seam_edge_pm, seam_vertex_pm);
SM_halfedge_descriptor smhd = mesh.add_seams(selection);
if(smhd == SM_halfedge_descriptor() ) {
std::cerr << "Warning: No seams in input" << std::endl;
}
// The 2D points of the uv parametrisation will be written into this map
// Note that this is a halfedge property map, and that the uv
// is only stored for the canonical halfedges representing a vertex
SM_UV_pmap uv_pm = sm.add_property_map<SM_halfedge_descriptor,
Point_2>("h:uv").first;
// a halfedge on the (possibly virtual) border
SM_SE_halfedge_descriptor bhd = CGAL::Polygon_mesh_processing::longest_border(mesh).first;
// Indices
typedef boost::unordered_map<SM_SE_vertex_descriptor, int> Indices;
Indices indices;
CGAL::Polygon_mesh_processing::connected_component(
face(opposite(bhd, mesh), mesh),
mesh,
boost::make_function_output_iterator(
SMP::internal::Index_map_filler<SM_Seam_mesh, Indices>(mesh, indices)));
boost::associative_property_map<Indices> vipm(indices);
// Parameterized
boost::unordered_set<SM_SE_vertex_descriptor> vs;
SMP::internal::Bool_property_map<boost::unordered_set<SM_SE_vertex_descriptor> > vpm(vs);
typename SMP::ARAP_parameterizer_3<SM_Seam_mesh> parameterizer;
parameterizer.parameterize(mesh, bhd, uv_pm, vipm, vpm);
}
#endif
// ***************************************************************************
// ARAP WITH SEAM_MESH (POLY)
// ***************************************************************************
#ifdef ARAP_PM_SEAM_MESH
{
std::cout << "ARAP POLY SEAM MESH" << std::endl;
PMesh pm;
in.clear();
in.seekg(0, std::ios::beg);
in >> pm;
PM_seam_edge_hmap seam_edge_hm(false);
PM_seam_edge_pmap seam_edge_pm(seam_edge_hm);
PM_seam_vertex_hmap seam_vertex_hm(false);
PM_seam_vertex_pmap seam_vertex_pm(seam_vertex_hm);
PM_Seam_mesh mesh(pm, seam_edge_pm, seam_vertex_pm);
PM_halfedge_descriptor pmhd = mesh.add_seams(selection);
if(pmhd == PM_halfedge_descriptor() ) {
std::cerr << "Warning: No seams in input" << std::endl;
}
// The 2D points of the uv parametrisation will be written into this map
// Note that this is a halfedge property map, and that the uv
// is only stored for the canonical halfedges representing a vertex
PM_UV_hmap uv_hm;
PM_UV_pmap uv_pm(uv_hm);
// a halfedge on the (possibly virtual) border
PM_SE_halfedge_descriptor bhd = CGAL::Polygon_mesh_processing::longest_border(mesh).first;
// Indices
typedef boost::unordered_map<PM_SE_vertex_descriptor, int> Indices;
Indices indices;
CGAL::Polygon_mesh_processing::connected_component(
face(opposite(bhd, mesh), mesh),
mesh,
boost::make_function_output_iterator(
SMP::internal::Index_map_filler<PM_Seam_mesh, Indices>(mesh, indices)));
boost::associative_property_map<Indices> vipm(indices);
// Parameterized
boost::unordered_set<PM_SE_vertex_descriptor> vs;
SMP::internal::Bool_property_map<boost::unordered_set<PM_SE_vertex_descriptor> > vpm(vs);
typename SMP::ARAP_parameterizer_3<PM_Seam_mesh> parameterizer;
parameterizer.parameterize(mesh, bhd, uv_pm, vipm, vpm);
}
#endif
return 0;
}

View File

@ -1,920 +0,0 @@
// Copyright (c) 2016 GeometryFactory (France).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org).
// You can redistribute it and/or modify it under the terms of the GNU
// General Public License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any later version.
//
// Licensees holding a valid commercial license may use this file in
// accordance with the commercial license agreement provided with the software.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
//
// $URL$
// $Id$
//
//
// Author(s) : Mael Rouxel-Labbé
#ifndef CGAL_SURFACE_MESH_PARAMETERIZATION_ORBIFOLD_TUTTE_SPHERE_MAPPING_H
#define CGAL_SURFACE_MESH_PARAMETERIZATION_ORBIFOLD_TUTTE_SPHERE_MAPPING_H
#include <CGAL/license/Surface_mesh_parameterization.h>
#include <CGAL/Surface_mesh_parameterization/internal/orbifold_cone_helper.h>
#include <CGAL/Surface_mesh_parameterization/internal/kernel_traits.h>
#include <CGAL/Arr_default_overlay_traits.h>
#include <CGAL/Arrangement_2.h>
#include <CGAL/Arr_overlay_2.h>
#include <CGAL/Cartesian_converter.h>
#include <CGAL/convex_hull_2.h>
#include <CGAL/intersection_2.h>
#include <CGAL/Triangulation_2.h>
#include <CGAL/Timer.h>
#include <Eigen/Dense>
#include <boost/iterator/transform_iterator.hpp>
#include <boost/graph/graph_traits.hpp>
#include <boost/unordered_map.hpp>
#include <cmath>
#include <iostream>
#include <map>
#include <set>
#include <sstream>
#include <vector>
namespace CGAL {
namespace Surface_mesh_parameterization {
namespace internal {
/// Output a container of triangles as a .off file.
template<typename Triangle_container>
void output_triangle_set(Triangle_container& triangles,
const char* filename)
{
typedef typename Triangle_container::value_type Triangle_2;
typedef typename Triangle_2::R Kernel;
typedef typename Kernel::Point_2 Point_2;
const std::size_t triangles_n = triangles.size();
std::map<Point_2, int> points_to_indices;
std::vector<Point_2> ids_to_print;
ids_to_print.reserve(3 * triangles_n);
std::ofstream out(filename);
std::ostringstream faces_ss;
int counter = 0;
typename Triangle_container::const_iterator trit = triangles.begin(),
trend = triangles.end();
for(; trit!=trend; ++trit) {
const Triangle_2& tr = *trit;
std::vector<int> ids(3);
for(std::size_t i=0; i<3; ++i) {
std::pair<typename std::map<Point_2, int>::iterator, bool> is_insert_successful =
points_to_indices.insert(std::make_pair(tr[i], counter));
if(!is_insert_successful.second) {
ids[i] = is_insert_successful.first->second;
} else {
ids[i] = counter;
ids_to_print.push_back(tr[i]);
++counter;
}
}
faces_ss << "3 " << ids[0] << " "<< ids[1] << " " << ids[2] << '\n';
}
// OFF header
out << "OFF" << '\n';
out << points_to_indices.size() << " " << triangles_n << " 0" << '\n';
// outputs points
typename std::vector<Point_2>::iterator it = ids_to_print.begin(),
end = ids_to_print.end();
for(; it!=end; ++it) {
out << *it << " 0" << '\n';
}
// outputs faces
out << faces_ss.str() << std::endl;
}
/// Outputs an arrangement as a .off file.
template<typename Arrangement>
void output_arrangement_to_off(const Arrangement& arr,
std::ofstream& out)
{
typedef typename Arrangement::Vertex_const_iterator Vertex_const_iterator;
typedef typename Arrangement::Edge_const_iterator Edge_const_iterator;
typedef typename Arrangement::Point_2 Exact_point_2;
std::cout << "Arrangement with " << arr.number_of_vertices() << " vertices and "
<< arr.number_of_edges() << " edges" << std::endl;
std::map<Exact_point_2, int> indices;
std::ostringstream out_vertices;
std::size_t vertices_counter = 0;
// arrangement vertices
Vertex_const_iterator vit = arr.vertices_begin(), vend = arr.vertices_end();
for(; vit!=vend; ++vit) {
std::pair<typename std::map<Exact_point_2, int>::iterator, bool> is_insert_successful =
indices.insert(std::make_pair(vit->point(), vertices_counter));
if(is_insert_successful.second) {
out_vertices << vit->point() << " 0" << '\n';
++vertices_counter;
}
}
CGAL_assertion(arr.number_of_vertices() == vertices_counter);
out << "OFF" << "\n" << std::endl;
out << vertices_counter << " " << arr.number_of_edges() << " 0" << '\n';
out << out_vertices.str();
// arrangement edges
Edge_const_iterator eit = arr.edges_begin(), eend = arr.edges_end();
for(; eit!=eend; ++eit) {
out << "3 " << indices[eit->curve().source()] << " "
<< indices[eit->curve().target()] << " "
<< indices[eit->curve().source()] << '\n';
}
out << std::endl;
}
// A type to regroup all the info and avoid having to pass it all in each function.
template<typename SeamMesh_,
typename ConeMap_,
typename VertexIndexMap_,
typename VertexUVMap_>
class Embedded_mesh
{
public:
typedef SeamMesh_ SeamMesh;
typedef ConeMap_ ConeMap;
typedef VertexIndexMap_ VertexIndexMap;
typedef VertexUVMap_ VertexUVMap;
const SeamMesh& mesh;
const ConeMap& cmap;
const VertexIndexMap vimap;
const VertexUVMap uvmap;
const Orbifold_type orb_type;
Embedded_mesh(const SeamMesh& mesh,
const ConeMap& cmap,
const VertexIndexMap vimap,
const VertexUVMap uvmap,
const Orbifold_type orb_type)
:
mesh(mesh),
cmap(cmap),
vimap(vimap),
uvmap(uvmap),
orb_type(orb_type)
{ }
};
// Affine transformation to express A = T*B + V
// @fixme transf needs a translation component too (for orb type IV)
template<typename Kernel>
class Affine_transformation
{
public:
typedef typename Kernel::FT NT;
typedef typename Kernel::Point_2 Point_2;
// rotation of 'angle' around 'center'
Eigen::Matrix3d transformation_matrix;
public:
/// Apply the affine transformation to the point `p`.
Point_2 transform(const Point_2& p) const
{
Eigen::Vector3d v, res;
v(0) = p.x(); v(1) = p.y(); v(2) = 1;
res = transformation_matrix * v;
Point_2 newp(res(0), res(1));
// std::cout << "------------------------------ transformed " << p << " in " << newp << std::endl;
return newp;
}
const Eigen::Matrix3d& get_tr() const
{
return transformation_matrix;
}
/// Multiply the current transformation by `new_rot` to get a single transformation matrix.
void combine_transformations(const Eigen::Matrix3d& new_transf)
{
transformation_matrix = transformation_matrix * new_transf;
}
/// Create a transformation matrix based on the translation [tx, ty].
Affine_transformation(const NT tx, const NT& ty)
{
transformation_matrix << 1, 0, tx,
0, 1, ty,
0, 0, 1;
std::cout << "built (translation) matrix for " << tx << " and " << ty << std::endl;
std::cout << transformation_matrix << std::endl;
}
/// Create a transformation matrix based on the rotation around `center` of `angle`.
Affine_transformation(const NT angle, const Point_2& center)
{
const NT c = std::cos(angle);
const NT s = std::sin(angle);
const NT center_x = center.x();
const NT center_y = center.y();
transformation_matrix << c, -s, center_x - c * center_x + s * center_y,
s, c, center_y - s * center_x - c * center_y,
0, 0, 1;
std::cout << "built matrix for " << center << " and angle: " << angle << std::endl;
std::cout << transformation_matrix << std::endl;
}
Affine_transformation()
{
transformation_matrix << 1, 0, 0,
0, 1, 0,
0, 0, 1;
}
};
// halfedge that carries a transformation that is used to compute the coordinates
// of the incident faces in the tiled space.
template<typename SeamMesh>
class halfedge_with_transformation
{
typedef halfedge_with_transformation<SeamMesh> Self;
public:
typedef SeamMesh Seam_mesh;
typedef typename internal::Kernel_traits<Seam_mesh>::Kernel Kernel;
typedef Affine_transformation<Kernel> Transformation;
typedef typename Seam_mesh::TriangleMesh TriangleMesh;
typedef typename boost::graph_traits<TriangleMesh>::halfedge_descriptor TM_halfedge_descriptor;
TM_halfedge_descriptor tmhd;
Transformation transformation;
halfedge_with_transformation(TM_halfedge_descriptor tmhd,
const Transformation& transformation)
:
tmhd(tmhd), transformation(transformation)
{ }
};
} // namespace internal
template<typename Arrangement,
typename EmbeddedMesh>
class Orbifold_sphere_mapper
{
// Types related to the embedded mesh
typedef typename EmbeddedMesh::ConeMap ConeMap;
typedef typename EmbeddedMesh::SeamMesh Seam_mesh;
typedef typename EmbeddedMesh::VertexIndexMap VertexIndexMap;
typedef typename EmbeddedMesh::VertexUVMap VertexUVMap;
// Graph types for the seam mesh
typedef typename boost::graph_traits<Seam_mesh>::vertex_descriptor vertex_descriptor;
typedef typename boost::graph_traits<Seam_mesh>::halfedge_descriptor halfedge_descriptor;
typedef typename boost::graph_traits<Seam_mesh>::edge_descriptor edge_descriptor;
typedef typename boost::graph_traits<Seam_mesh>::face_descriptor face_descriptor;
typedef typename boost::graph_traits<Seam_mesh>::vertex_iterator vertex_iterator;
// Graph types for the underlying mesh
typedef typename Seam_mesh::TriangleMesh TriangleMesh;
typedef typename boost::graph_traits<TriangleMesh>::vertex_descriptor TM_vertex_descriptor;
typedef typename boost::graph_traits<TriangleMesh>::halfedge_descriptor TM_halfedge_descriptor;
// Kernel types
typedef typename internal::Kernel_traits<Seam_mesh>::Kernel Kernel;
typedef typename Kernel::FT NT;
typedef typename Kernel::Point_2 Point_2;
typedef typename Kernel::Segment_2 Segment_2;
typedef typename Kernel::Vector_2 Vector_2;
typedef typename Kernel::Triangle_2 Triangle_2;
// Arrangement types
typedef typename Arrangement::Geometry_traits_2 Arr_traits;
typedef CGAL::Arr_default_overlay_traits<Arrangement> Overlay_traits;
// Exact kernel types
typedef typename Arr_traits::Kernel Exact_kernel;
typedef typename Arr_traits::X_monotone_curve_2 Arr_segment_2;
typedef typename Exact_kernel::FT Exact_NT;
typedef typename Exact_kernel::Point_2 Exact_point_2;
typedef typename Exact_kernel::Segment_2 Exact_segment_2;
typedef CGAL::Cartesian_converter<Kernel, Exact_kernel> IK_to_EK;
// Transformation types
typedef internal::Affine_transformation<Kernel> Aff_tr;
typedef internal::halfedge_with_transformation<Seam_mesh> halfedge_w_tr;
// Triangulation type
typedef CGAL::Triangulation_2<Kernel> Triangulation;
const IK_to_EK to_exact;
/// For all seam edges, mark both halfedges with the transformation to apply
/// to obtain the next tile's coordinates from the previous tile.
template<typename Seam_halfedges_segment,
typename SeamTransformationMap,
typename BorderHalfedges>
void tag_seam_segment(const EmbeddedMesh& emesh,
const Seam_halfedges_segment& seam_segment,
SeamTransformationMap& seam_transformations,
BorderHalfedges& border_halfedges,
NT ang) const
{
std::cout << "Segment of length " << seam_segment.size() << std::endl;
const Seam_mesh& mesh = emesh.mesh;
const VertexIndexMap vimap = emesh.vimap;
const VertexUVMap uvmap = emesh.uvmap;
// s and t are the two sides of the seam
vertex_descriptor vf_s = target(seam_segment.front().first, mesh);
vertex_descriptor vf_t = source(seam_segment.front().second, mesh);
vertex_descriptor ve_s = source(seam_segment.back().first, mesh);
vertex_descriptor ve_t = target(seam_segment.back().second, mesh);
const bool is_reversed = (get(vimap, ve_s) == get(vimap, ve_t));
if(is_reversed) {
ang *= -1;
}
const Aff_tr identity;
Aff_tr trs, trt;
if(ang == 1) { // translation
trs = Aff_tr(-2., 0.);
trt = Aff_tr( 2., 0.);
}
else {
const Point_2& pb = is_reversed ? get(uvmap, ve_s) : get(uvmap, vf_s);
const Point_2& pe = is_reversed ? get(uvmap, ve_t) : get(uvmap, vf_t);
trs = Aff_tr(+ 2 * CGAL_PI / ang /*angle*/, pb /*center*/);
trt = Aff_tr(- 2 * CGAL_PI / ang /*angle*/, pe /*center*/);
}
typename Seam_halfedges_segment::const_iterator it = seam_segment.begin(),
end = seam_segment.end();
for(; it!=end; ++it) {
// Associate to the halfedges on the seam a transformation that can be
// thought of as:
// "if I cross this border, which affine transformation must I apply to
// a triangle of the initial mesh to obtain the coordinates of this triangle
// in the next tile"
const halfedge_descriptor hd1 = it->first;
const TM_halfedge_descriptor base_hd1 = hd1.tmhd;
seam_transformations[base_hd1] = trs;
const halfedge_descriptor hd2 = it->second;
const TM_halfedge_descriptor base_hd2 = hd2.tmhd;
seam_transformations[base_hd2] = trt;
// The initial border edges are by definition in the initial mesh so they
// do not have a transformation at the beginning
const halfedge_w_tr hdt1(base_hd1, identity);
const halfedge_w_tr hdt2(base_hd2, identity);
border_halfedges.push_back(hdt1);
border_halfedges.push_back(hdt2);
}
}
/// Go through the seam edges to collect the initial border halfedges and mark the
/// transformations on the seam.
template<typename SeamTransformationMap,
typename BorderHalfedges>
void compute_initial_border(const EmbeddedMesh& emesh,
SeamTransformationMap& seam_transformations,
BorderHalfedges& border_halfedges) const
{
const Seam_mesh& mesh = emesh.mesh;
// the angles at the cones
typedef std::vector<NT> Angle_container;
const Angle_container& angs = get_angles_at_cones<Angle_container>(emesh.orb_type);
// Find the cone tagged 'First_unique_cone'
int start_cone_index = -1; // index of the beginning of the seam (useless here)
vertex_descriptor start_cone;
internal::find_start_cone(emesh.cmap, emesh.vimap, start_cone, start_cone_index);
// By property of the seam mesh, the canonical halfedge that points to start_cone
// is on the seam, and is not on the border
const halfedge_descriptor hd = halfedge(start_cone, mesh);
CGAL_precondition(mesh.has_on_seam(hd));
halfedge_descriptor bhd = opposite(hd, mesh);
CGAL_precondition(is_border(bhd, mesh));
// To count the segments of the seam (a segment is a set of edges between two cones)
// there are 3 segment max in orb types I, II, III and IV
std::size_t segment_index = 0;
// The segments between cones
typedef std::vector<std::pair<halfedge_descriptor, halfedge_descriptor> > Seam_halfedges_segment;
Seam_halfedges_segment seam_segment;
// Walk the border till we find the first cone again, while tagging the seam edges
// with the correct transformation (such that if we go over the seam, we unfold
// properly in the plane
while(true) { // breaking at the last cone
// get the two halfedges that are not on the border
const halfedge_descriptor hd1 = opposite(bhd, mesh);
// The non-border halfedge with same vertices (in the underlying mesh of the seam
// mesh) as bhd is simply bhd with the 'seam' boolean set to false
const halfedge_descriptor hd2(bhd, false /*not on seam*/);
CGAL_assertion(segment_index < angs.size());
NT ang = angs[segment_index];
seam_segment.push_back(std::make_pair(hd1, hd2));
// Check if we have reached the end of the seam
vertex_descriptor bhd_target = target(bhd, mesh);
typename ConeMap::const_iterator is_in_map = emesh.cmap.find(bhd_target);
if(is_in_map != emesh.cmap.end()) {
tag_seam_segment<Seam_halfedges_segment,
SeamTransformationMap,
BorderHalfedges>(emesh,
seam_segment,
seam_transformations,
border_halfedges,
ang);
// reached the end of the seam
if(is_in_map->second == Second_unique_cone) {
break;
}
std::cout << "-------------------------" << std::endl;
seam_segment.clear();
++segment_index;
}
// move to the next halfedge couple (walking on the border of the seam)
bhd = next(bhd, mesh);
CGAL_postcondition(mesh.has_on_seam(bhd) && is_border(bhd, mesh));
}
std::cout << "built border & tags" << std::endl;
std::cout << border_halfedges.size() << " border halfedges" << std::endl;
CGAL_postcondition(border_halfedges.size() == 2 * mesh.number_of_seam_edges());
}
/// Insert all the base faces in the set of unique faces.
template<typename Face_set,
typename Face_container>
void mark_base_mesh_faces(const EmbeddedMesh& emesh,
Face_set& inserted_faces,
Face_container& faces_to_draw) const
{
const Seam_mesh& mesh = emesh.mesh;
const VertexUVMap uvmap = emesh.uvmap;
BOOST_FOREACH(face_descriptor fd, faces(mesh)) {
const halfedge_descriptor hd = halfedge(fd, mesh);
const vertex_descriptor vda = source(hd, mesh);
const vertex_descriptor vdb = target(hd, mesh);
const vertex_descriptor vdc = target(next(hd, mesh), mesh);
const Point_2& tpa = get(uvmap, vda);
const Point_2& tpb = get(uvmap, vdb);
const Point_2& tpc = get(uvmap, vdc);
// std::cout << "add " << tpa << " " << tpb << " " << tpc << std::endl;
const Triangle_2 tr(tpa, tpb, tpc);
faces_to_draw.push_back(tr);
const Point_2 bar = CGAL::barycenter(tpa, 1., tpb, 1., tpc, 1.);
// ugly hack to get rid of imprecisions @fixme
// uv values are close to 1 so *1e7 is not too dangerous
NT barx = 1e7 * bar.x();
NT bary = 1e7 * bar.y();
barx = static_cast<int>(barx >= 0 ? barx + 0.5 : barx - 0.5);
bary = static_cast<int>(bary >= 0 ? bary + 0.5 : bary - 0.5);
inserted_faces.insert(std::make_pair(barx, bary));
}
}
template<typename BorderHalfedges,
typename SeamTransformationMap,
typename Face_container,
typename Barycenter_set,
typename Arr_segments>
void expand_border(const EmbeddedMesh& source_embedded_mesh,
const Triangulation& tr,
const SeamTransformationMap& seam_transformations,
const BorderHalfedges& current_border_halfedges,
BorderHalfedges& next_border_halfedges,
Face_container& faces_to_draw,
Barycenter_set& inserted_faces,
Arr_segments& arr_segments) const
{
const Seam_mesh& mesh = source_embedded_mesh.mesh;
const VertexUVMap uvmap = source_embedded_mesh.uvmap;
const TriangleMesh& tm = mesh.mesh();
typename BorderHalfedges::const_iterator bhit = current_border_halfedges.begin(),
bhend = current_border_halfedges.end();
for(; bhit!=bhend; ++bhit) {
// Get the next border edge
const halfedge_w_tr hdt = *bhit;
const TM_halfedge_descriptor hd = hdt.tmhd;
// std::cout << "at halfedge " << source(hd, tm) << " " << target(hd, tm) << std::endl;
// halfedge_descriptor shd(hd);
// std::cout << "that is " << get(uvmap, (source(shd, mesh))) << " || "
// << get(uvmap, (target(shd, mesh))) << std::endl;
// the transformation stocked in the halfedge
Aff_tr hd_transformation = hdt.transformation;
// std::cout << "base transformation: " << std::endl;
// std::cout << hd_transformation.get_tr() << std::endl;
// check if [ab] with the current transformation intersects, otherwise stops
const Point_2& tpa = hd_transformation.transform(get(uvmap, target(hd, mesh)));
const Point_2& tpb = hd_transformation.transform(get(uvmap, source(hd, mesh)));
const Segment_2 es_ab(tpa, tpb);
if(!is_intersecting(tr, es_ab)) {
// std::cout << "no intersection" << std::endl;
continue;
}
// There is an intersection and we must insert the face incident to ohd.
// Get the opposite halfedge, which is incident to the triangle that we will add
// (with transformed coordinates)
const TM_halfedge_descriptor ohd = opposite(hd, tm);
// TM_vertex_descriptor tmvdc = target(next(ohd, tm), tm); // third point
// std::cout << "third " << tmvdc;
// std::cout<< " with pos: " << get(uvmap, target(halfedge_descriptor(next(ohd, tm)), mesh)) << std::endl;
// if the edge is on a seam, we combine the current transformation
// with the transformation assigned to the seam halfedge to obtain the transformation
if(mesh.has_on_seam(hd)) {
typename SeamTransformationMap::const_iterator it = seam_transformations.find(hd);
CGAL_assertion(it != seam_transformations.end());
Aff_tr seam_transf = it->second;
hd_transformation.combine_transformations(seam_transf.get_tr());
}
const TM_halfedge_descriptor hd_bc = next(ohd, tm);
const vertex_descriptor vdc = target(halfedge_descriptor(hd_bc), mesh);
const Point_2& tpc = hd_transformation.transform(get(uvmap, vdc));
const Exact_point_2& etpa = to_exact(tpa);
const Exact_point_2& etpb = to_exact(tpb);
const Exact_point_2& etpc = to_exact(tpc);
// Check if we have already inserted the face incident to ohd in the arrangement
const Point_2& bar = CGAL::barycenter(tpa, 1., tpb, 1., tpc, 1.);
// ugly hack to get rid of imprecisions @fixme
NT barx = 1e7 * bar.x();
NT bary = 1e7 * bar.y();
barx = static_cast<int>(barx >= 0 ? barx + 0.5 : barx - 0.5);
bary = static_cast<int>(bary >= 0 ? bary + 0.5 : bary - 0.5);
std::pair<typename Barycenter_set::iterator, bool> is_insert_successful =
inserted_faces.insert(std::make_pair(barx, bary));
if(!is_insert_successful.second) // triangle has already been considered
continue;
// std::cout.precision(20);
// std::cout << "new triangle with bar: " << barx << " || " << bary << std::endl;
// std::cout << "tps: " << tpa << " " << tpb << " " << tpc << std::endl;
const Triangle_2 tr(tpa, tpb, tpc);
faces_to_draw.push_back(tr);
// Add the new segments
const Exact_segment_2 es_ac(etpa, etpc);
const Exact_segment_2 es_bc(etpb, etpc);
// There is no need to insert ab because we have already inserted it
// at previous steps. Leaving it here for clarity.
// arr_segments.push_back(Exact_segment_2(etpa, etpb))
arr_segments.push_back(es_ac);
arr_segments.push_back(es_bc);
// Insert the (other) edges of the face incident to ohd
// there are two "new" border edges: ac and bc
const TM_halfedge_descriptor hd_ac = prev(ohd, tm);
const halfedge_w_tr hdt_ac(hd_ac, hd_transformation);
next_border_halfedges.push_back(hdt_ac);
const halfedge_w_tr hdt_bc(hd_bc, hd_transformation);
next_border_halfedges.push_back(hdt_bc);
}
}
/// Check if a given segment intersects the target mesh (actually, a triangulation
/// of the -- slightly grown -- convex hull of the target mesh)
bool is_intersecting(const Triangulation& tr,
const Segment_2& segment) const
{
typename Kernel::Construct_triangle_2 triangle_functor;
typename Kernel::Do_intersect_2 do_intersect_2_functor;
// Brute force, but the triangulation _should_ have very few faces
typedef typename Triangulation::Finite_faces_iterator Finite_faces_iterator;
Finite_faces_iterator fit = tr.finite_faces_begin(), end = tr.finite_faces_end();
for(; fit!=end; fit++) {
const Triangle_2 tr = triangle_functor(fit->vertex(0)->point(),
fit->vertex(1)->point(),
fit->vertex(2)->point());
if(do_intersect_2_functor(segment, tr))
return true;
}
return false;
}
/// Functor used to offer dereferencing vertex_iterator to UV values
struct Vd_to_uv
{
typedef vertex_iterator argument_type;
typedef Point_2 result_type;
const VertexUVMap uvmap;
result_type operator()(vertex_iterator vit) const
{
vertex_descriptor vd = *vit;
return get(uvmap, vd);
}
result_type operator()(vertex_descriptor vd) const
{
return get(uvmap, vd);
}
Vd_to_uv(const VertexUVMap uvmap) : uvmap(uvmap) { }
};
/// Compute the convex hull of a mesh, and triangulate the convex hull.
void triangulate_convex_hull(const EmbeddedMesh& emesh,
Triangulation& tr) const
{
const Seam_mesh& mesh = emesh.mesh;
const VertexUVMap uvmap = emesh.uvmap;
// compute the convex hull of the mesh
std::vector<Point_2> convex_hull_pts;
const Vd_to_uv vd_to_uv(uvmap);
CGAL::convex_hull_2(boost::make_transform_iterator(mesh.vertices_begin(), vd_to_uv),
boost::make_transform_iterator(mesh.vertices_end(), vd_to_uv),
std::back_inserter(convex_hull_pts));
std::cout << convex_hull_pts.size() << " pts on the convex hull" << std::endl;
/// Trick: slightly grow the convex hull so that the source mesh will completely
/// englobe the target mesh
// compute the center point (ish)
const NT weight = 1. / convex_hull_pts.size();
NT bx = 0., by = 0.;
for(std::size_t i=0; i<convex_hull_pts.size(); ++i) {
bx += convex_hull_pts[i].x();
by += convex_hull_pts[i].y();
}
bx *= weight;
by *= weight;
Point_2 bp(bx, by);
// move points on the convex hull away from that center point
for(std::size_t i=0; i<convex_hull_pts.size(); ++i) {
Point_2& pci = convex_hull_pts[i];
// 0.01 is arbitrary but is enough to grow a bit farther than the cones
pci = pci + 0.01 * Vector_2(bp, pci);
}
// triangulate the (grown) convex hull
tr.insert(convex_hull_pts.begin(), convex_hull_pts.end());
CGAL_postcondition(tr.number_of_vertices() == convex_hull_pts.size());
std::cout << tr.number_of_faces() << " faces in the triangulation" << std::endl;
}
/// Grow the source mesh until it covers the target mesh.
Arrangement grow_source_embedding(const EmbeddedMesh& source_embedded_mesh,
const EmbeddedMesh& target_embedded_mesh) const
{
CGAL::Timer task_timer;
task_timer.start();
const Seam_mesh& mesh = source_embedded_mesh.mesh;
const VertexUVMap uvmap = source_embedded_mesh.uvmap;
// Seam tags (on the source mesh) indicate the transformation that must
// be applied to the UV coordinates to obtain the coordinates of
// the adjacent triangle in the tiled space when going over the seam edge
typedef boost::unordered_map<TM_halfedge_descriptor, Aff_tr> SeamTransformationMap;
SeamTransformationMap seam_transformations;
// Border_halfedes is the border of the expending border of the source mesh.
// We grow it until the border does not intersect the target mesh anymore.
// note: ideally, it'd be a set, but I don't have a good hash function for it
// and in practice it's not slower to use a vector.
typedef std::vector<halfedge_w_tr> BorderHalfedges;
BorderHalfedges current_border_halfedges, next_border_halfedges;
current_border_halfedges.reserve(2 * mesh.number_of_seam_edges());
compute_initial_border(source_embedded_mesh, seam_transformations, current_border_halfedges);
CGAL_postcondition(seam_transformations.size() == 2 * mesh.number_of_seam_edges());
CGAL_postcondition(current_border_halfedges.size() == 2 * mesh.number_of_seam_edges());
// Segments that will form the arrangement obtained by growing the source mesh
std::vector<Arr_segment_2> arr_segments;
arr_segments.reserve(num_edges(mesh));
// Fill the arrangement with the edges of the source mesh
BOOST_FOREACH(edge_descriptor ed, edges(mesh)) {
const vertex_descriptor vds = source(ed, mesh);
const vertex_descriptor vdt = target(ed, mesh);
arr_segments.push_back(Exact_segment_2(to_exact(get(uvmap, vds)),
to_exact(get(uvmap, vdt))));
}
// -------------- INFO & OUTPUT
std::cout << num_edges(mesh.mesh()) << " edges in the base mesh" << std::endl;
std::cout << mesh.number_of_seam_edges() << " seams" << std::endl;
std::cout << num_edges(mesh) << " edges in the source seam mesh" << std::endl;
std::cout << arr_segments.size() << " segments in the base arrangement" << std::endl;
CGAL_postcondition(arr_segments.size() == num_edges(mesh));
Arrangement source_arrangement;
CGAL::insert(source_arrangement, arr_segments.begin(), arr_segments.end());
// Write the arrangement to a file.
std::ofstream arr_out("arr_source.off");
internal::output_arrangement_to_off(source_arrangement, arr_out);
// --------------------
// Keep a set of faces. Can't sort by IDs, so using a set of barycenters instead...
// Problem is that rotations introduce imprecisions so we can't just get a point
// Some (super) ugly hack is to only consider part of the mantissa
typedef std::set<std::pair<int, int> > Barycenter_set;
Barycenter_set inserted_faces;
std::vector<Triangle_2> faces_to_draw; // just for output
mark_base_mesh_faces(source_embedded_mesh, inserted_faces, faces_to_draw);
// The target mesh is a dense mesh, which makes it expensive to check for intersections.
// Instead, build a triangulation of the convex hull, which is "close enough"
// since the parameterisations give somewhat convex results
Triangulation tr;
triangulate_convex_hull(target_embedded_mesh, tr);
// Expand the border until it doesn't intersect the target mesh
std::cout << "initial border of length: " << current_border_halfedges.size() << std::endl;
int counter = 0;
while(true) {
// For all halfedges in the current border (non-continuous), add the incident
// triangle if the shared edge intersects the target mesh
expand_border(source_embedded_mesh, tr, seam_transformations,
current_border_halfedges, next_border_halfedges,
faces_to_draw, inserted_faces, arr_segments);
++counter;
std::cout << "iteration: " << counter << std::endl;
std::cout << arr_segments.size() << " segments in the arrangement" << std::endl;
std::cout << next_border_halfedges.size() << " in the next loop" << std::endl;
if(next_border_halfedges.empty())
break;
current_border_halfedges = next_border_halfedges;
next_border_halfedges.clear();
}
std::cout << "Finished growing in " << task_timer.time() << " seconds" << std::endl;
// visualize the grown mesh
internal::output_triangle_set<std::vector<Triangle_2> >(faces_to_draw, "arr_grown.off");
Arrangement grown_arrangement;
std::cout << "building grown arrangement with " << arr_segments.size() << " segments" << std::endl;
CGAL::insert(grown_arrangement, arr_segments.begin(), arr_segments.end());
// Write the arrangement to a file.
std::ofstream arr_grown_out("arr_grown_old.off");
internal::output_arrangement_to_off(grown_arrangement, arr_grown_out);
return grown_arrangement;
}
/// Build an arrangement from a two-dimensional mesh.
Arrangement get_arrangement_from_embedded_mesh(const EmbeddedMesh& emesh) const
{
const Seam_mesh& mesh = emesh.mesh;
const VertexUVMap uvmap = emesh.uvmap;
std::vector<Exact_segment_2> arr_segments;
arr_segments.reserve(num_edges(mesh));
BOOST_FOREACH(edge_descriptor ed, edges(mesh)) {
vertex_descriptor vds = source(ed, mesh);
vertex_descriptor vdt = target(ed, mesh);
arr_segments.push_back(Exact_segment_2(to_exact(get(uvmap, vds)),
to_exact(get(uvmap, vdt))));
}
// Build the arrangement
Arrangement arrangement;
CGAL::insert(arrangement, arr_segments.begin(), arr_segments.end());
// Write the arrangement to a file.
std::ofstream arr_out("arr_target.off");
internal::output_arrangement_to_off(arrangement, arr_out);
return arrangement;
}
/// Overlay the source and target arrangements.
void overlay_arrangements(const Arrangement& source_arrangement,
const Arrangement& target_arrangement) const
{
std::cout << "The source arrangement size:" << std::endl
<< " V = " << source_arrangement.number_of_vertices()
<< ", E = " << source_arrangement.number_of_edges()
<< ", F = " << source_arrangement.number_of_faces() << std::endl;
std::cout << "The target arrangement size:" << std::endl
<< " V = " << target_arrangement.number_of_vertices()
<< ", E = " << target_arrangement.number_of_edges()
<< ", F = " << target_arrangement.number_of_faces() << std::endl;
Arrangement overlay_arrangement;
Overlay_traits overlay_traits;
CGAL::overlay(source_arrangement, target_arrangement,
overlay_arrangement, overlay_traits);
// Write the arrangement to a file
std::ofstream arr_out("arr_overlay.off");
internal::output_arrangement_to_off(overlay_arrangement, arr_out);
std::cout << "The overlaid arrangement size:" << std::endl
<< " V = " << overlay_arrangement.number_of_vertices()
<< ", E = " << overlay_arrangement.number_of_edges()
<< ", F = " << overlay_arrangement.number_of_faces() << std::endl;
}
public:
/// Compute the map between the source and the target mesh.
void compute_map_from_sphere_embeddings(const EmbeddedMesh& source_embedded_mesh,
const EmbeddedMesh& target_embedded_mesh) const
{
// Grow the source mesh until it covers the target mesh and convert it to arrangement
const Arrangement& source_arrangement =
grow_source_embedding(source_embedded_mesh, target_embedded_mesh);
const Arrangement& target_arrangement =
get_arrangement_from_embedded_mesh(target_embedded_mesh);
// Overlay the two arrangements
overlay_arrangements(source_arrangement, target_arrangement);
// Compute the one-to-one mapping
// @todo
}
/// Constructor.
Orbifold_sphere_mapper() : to_exact() { }
};
} // namespace Surface_mesh_parameterization
} // namespace CGAL
#endif // CGAL_SURFACE_MESH_PARAMETERIZATION_ORBIFOLD_TUTTE_SPHERE_MAPPING_H

View File

@ -1,271 +0,0 @@
/***************************************************************************
begin : jan 02
copyright : (C) 2002 by Pierre Alliez
email : pierre.alliez@sophia.inria.fr
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#ifndef MESH_CUTTER_H
#define MESH_CUTTER_H
#include <CGAL/Cartesian.h>
#include "Polyhedron_ex.h"
#include <list>
#include <cassert>
class Mesh_cutter
{
// Public types
public:
typedef std::list<Polyhedron_ex::Halfedge_handle>
Backbone;
// Private types
private:
typedef My_kernel::Vector_3 Vector_3;
typedef My_kernel::Point_3 Point_3;
enum {FREE,DONE,FIXED};
// Public operations
public:
// life cycle
Mesh_cutter(Polyhedron_ex& polyhedron)
{
m_pPolyhedron = &polyhedron;
m_pBackbone = NULL;
}
~Mesh_cutter() {}
void cut(Backbone& backbone);
void cut_genus(Backbone& backbone);
// Private operations
private:
// genus > 0
bool init();
bool simplify();
bool extend();
void precompute_distances();
Polyhedron_ex::Halfedge_handle pick_best_halfedge(
std::list<Polyhedron_ex::Halfedge_handle>::iterator &pos);
void recursive_tag(Polyhedron_ex::Facet_handle pFacet,int index);
// Fields
private:
Polyhedron_ex* m_pPolyhedron; // the model to cut
Backbone* m_pBackbone; // the backbone to fill
Polyhedron_ex::Facet_handle m_pSeedFacet;
Polyhedron_ex::Vertex_handle m_pSeedVertex;
};
//***************************************************
// simple cut for genus 0 mesh
//***************************************************
inline void Mesh_cutter::cut(Backbone& backbone)
{
m_pBackbone = &backbone;
// special init -> tag all vertices, but two
m_pPolyhedron->tag_vertices(FREE);
Polyhedron_ex::Vertex_handle pVertexMin,pVertexMax;
m_pPolyhedron->farthest_point_aligned(pVertexMin,pVertexMax);
pVertexMin->tag(FIXED);
pVertexMax->tag(FIXED);
init();
// cutting
while(extend()) {}
}
/////////////////////////////////////////////////////
// GENUS > 0
/////////////////////////////////////////////////////
//***************************************************
// cut for genus>0 mesh
//***************************************************
inline void Mesh_cutter::cut_genus(Backbone& backbone)
{
m_pBackbone = &backbone;
// init
m_pPolyhedron->tag_vertices(FREE); // all free
init();
// cutting
while(extend()) {}
}
//***************************************************
// init
//***************************************************
inline bool Mesh_cutter::init()
{
// tag facets
m_pPolyhedron->tag_facets(FREE);
// compute bounding box and center
double xmin = m_pPolyhedron->minimum(0);
double ymin = m_pPolyhedron->minimum(1);
double zmin = m_pPolyhedron->minimum(2);
double xmax = m_pPolyhedron->maximum(0);
double ymax = m_pPolyhedron->maximum(1);
double zmax = m_pPolyhedron->maximum(2);
double xcenter = 0.5*(xmin+xmax);
double ycenter = 0.5*(ymin+ymax);
double zcenter = 0.5*(zmin+zmax);
Point_3 center(xcenter,ycenter,zcenter);
// get closest facet
m_pSeedFacet = m_pPolyhedron->get_closest_inner_facet(center);
assert(m_pSeedFacet != NULL);
Polyhedron_ex::Halfedge_handle he = m_pSeedFacet->halfedge();
assert(he != NULL);
assert(m_pBackbone != NULL);
m_pBackbone->push_back(he);
m_pBackbone->push_back(he->next());
m_pBackbone->push_back(he->next()->next());
precompute_distances();
m_pSeedFacet->tag(DONE);
return true;
}
//***************************************************
// extend
//***************************************************
inline bool Mesh_cutter::extend()
{
std::list<Polyhedron_ex::Halfedge_handle>::iterator pos;
Polyhedron_ex::Halfedge_handle pHalfedge = pick_best_halfedge(pos);
if(pHalfedge == NULL)
return false;
// flag facet
pHalfedge->opposite()->facet()->tag(DONE);
// insert halfedge
std::list<Polyhedron_ex::Halfedge_handle>::iterator tmp =
m_pBackbone->insert(pos,pHalfedge->opposite()->next()->next());
m_pBackbone->insert(tmp,pHalfedge->opposite()->next());
// remove this one
m_pBackbone->remove(pHalfedge);
// simplify current backbone
while(simplify()) {}
return true;
}
//***************************************************
// simplify
//***************************************************
inline bool Mesh_cutter::simplify()
{
// cleanup
std::list<Polyhedron_ex::Halfedge_handle>::iterator iter;
for(iter = m_pBackbone->begin();
iter != m_pBackbone->end();
iter++)
{
Polyhedron_ex::Halfedge_handle pHalfedge = (*iter);
Polyhedron_ex::Halfedge_handle opposite = pHalfedge->opposite();
// get next halfedge in the list
iter++;
Polyhedron_ex::Halfedge_handle pNext = NULL;
if(iter == m_pBackbone->end()) // loop
pNext = (*m_pBackbone->begin());
else
pNext = (*iter);
if(pNext == opposite &&
pHalfedge->vertex()->tag() == FREE)
{
m_pBackbone->remove(pHalfedge);
m_pBackbone->remove(opposite);
return true;
}
iter--; // restore
}
return false;
}
//***************************************************
// precompute_distances
//***************************************************
inline void Mesh_cutter::precompute_distances()
{
Polyhedron_ex::Halfedge_iterator pHalfedge;
for(pHalfedge = m_pPolyhedron->halfedges_begin();
pHalfedge != m_pPolyhedron->halfedges_end();
pHalfedge++)
pHalfedge->distance(m_pPolyhedron->distance(m_pSeedFacet,pHalfedge));
}
//***************************************************
// pick_best_halfedge
//***************************************************
inline Polyhedron_ex::Halfedge_handle Mesh_cutter::pick_best_halfedge(
std::list<Polyhedron_ex::Halfedge_handle>::iterator &pos)
{
Polyhedron_ex::Halfedge_handle pBest = NULL;
double min_distance = 1e308; //
// cleanup
std::list<Polyhedron_ex::Halfedge_handle>::iterator iter;
for(iter = m_pBackbone->begin();
iter != m_pBackbone->end();
iter++)
{
Polyhedron_ex::Halfedge_handle pHalfedge = (*iter);
Polyhedron_ex::Halfedge_handle opposite = pHalfedge->opposite();
Polyhedron_ex::Facet_handle pFacet = opposite->facet();
// check
if(pHalfedge->is_border() ||
pFacet == NULL)
continue;
if(pFacet->tag() == DONE)
continue;
// no border vertex
Polyhedron_ex::Vertex_handle pVertex = opposite->next()->vertex();
if(m_pPolyhedron->is_border(pVertex))
continue;
// precomputed distance
double distance = pHalfedge->distance();
if(distance < min_distance)
{
pos = iter;
pBest = pHalfedge;
min_distance = distance;
}
}
return pBest;
}
#endif // MESH_CUTTER_H

View File

@ -1,596 +0,0 @@
#ifndef POLYHEDRON_EX_H_INCLUDED
#define POLYHEDRON_EX_H_INCLUDED
#include <CGAL/Cartesian.h>
#include <CGAL/Polyhedron_3.h>
#include <CGAL/IO/Polyhedron_iostream.h>
#include <algorithm>
#include <vector>
#include <list>
#include <fstream>
#include <cassert>
// CGAL kernel
typedef CGAL::Cartesian<double> My_kernel;
// compute facet center
struct Facet_center
{
typedef My_kernel::Vector_3 Vector_3;
typedef My_kernel::Point_3 Point_3;
template<class Facet>
void operator()(Facet& f)
{
Vector_3 vec(0.0,0.0,0.0);
int degree = 0;
typedef typename Facet::Halfedge_around_facet_const_circulator circ;
circ h = f.facet_begin();
do
{
vec = vec + (h->vertex()->point()-CGAL::ORIGIN);
degree++;
}
while (++h != f.facet_begin());
f.center() = CGAL::ORIGIN + (vec/degree);
}
};
template<class Refs, class T>
class My_facet : public CGAL::HalfedgeDS_face_base<Refs, T>
{
public:
typedef My_kernel::Vector_3 Vector_3;
typedef My_kernel::Point_3 Point_3;
// life cycle
// no constructors to repeat, since only
// default constructor mandatory
My_facet()
{
m_tag = -1; // uninitialized
}
// center
Point_3& center() { return m_center; }
const Point_3& center() const { return m_center; }
// tag
int tag() const { return m_tag; }
void tag(int tag) { m_tag = tag; }
// distance
double distance(Point_3& point) const
{
Vector_3 vec = (point-m_center);
return std::sqrt(vec*vec);
}
// Fields
private:
// facet data
int m_tag;
Point_3 m_center;
};
template<class Refs, class Tprev, class Tvertex, class Tface>
class My_halfedge
: public CGAL::HalfedgeDS_halfedge_base<Refs,Tprev,Tvertex,Tface>
{
private:
int m_tag;
// parameterization
bool m_is_parameterized;
int m_seaming; // seaming status
double m_u; // texture coordinates
double m_v;
int m_index; // for parameterization
// surface cutting
double m_distance;
public:
// life cycle
// no constructors to repeat, since only
// default constructor mandatory
My_halfedge()
{
m_tag = -1; // uninitialized
m_u = 0.0;
m_v = 0.0;
m_index = -1; // uninitialized
m_seaming = -1; // uninitialized
m_is_parameterized = false;
}
// tag
int tag() const { return m_tag; }
void tag(int tag) { m_tag = tag; }
// seaming status
int seaming() const { return m_seaming; }
void seaming(int seaming) { m_seaming = seaming; }
// precomputed distance
double distance() const { return m_distance; }
void distance(double distance) { m_distance = distance; }
// texture coordinates
double u() const { return m_u; }
double v() const { return m_v; }
void uv(double u, double v) { m_u = u; m_v = v; }
// param.
bool is_parameterized() const { return m_is_parameterized; }
void is_parameterized(bool is) { m_is_parameterized = is; }
// index
int index() const { return m_index; }
void index(int i) { m_index = i; }
};
// A redefined vertex class for the Polyhedron_3
template<class Refs, class T, class P>
class My_vertex : public CGAL::HalfedgeDS_vertex_base<Refs, T, P>
{
// index
int m_index;
// misc
int m_tag;
// seaming status
int m_seaming;
public:
// life cycle
My_vertex() { init(); }
// repeat mandatory constructors
My_vertex(const P& pt)
: CGAL::HalfedgeDS_vertex_base<Refs, T, P>(pt)
{
init();
}
void init()
{
m_index = -1; // uninitialized
m_tag = -1; // uninitialized
m_seaming = -1; // uninitialized
}
// index
int index() const { return m_index; }
void index(int i) { m_index = i; }
// tag
int tag() const { return m_tag; }
void tag(int tag) { m_tag = tag; }
// seaming status
int seaming() const { return m_seaming; }
void seaming(int seaming) { m_seaming = seaming; }
};
// A redefined items class for the Polyhedron_3 with a refined vertex, facet and halfedge classes
struct My_items : public CGAL::Polyhedron_items_3
{
typedef My_kernel::Vector_3 Vector_3;
typedef My_kernel::Point_3 Point_3;
// wrap vertex
template<class Refs, class Traits>
struct Vertex_wrapper
{
typedef typename Traits::Point_3 Point_3;
typedef My_vertex<Refs,
CGAL::Tag_true,
Point_3> Vertex;
};
// wrap facet
template<class Refs, class Traits>
struct Face_wrapper
{
typedef My_facet<Refs,
CGAL::Tag_true> Face;
};
// wrap halfedge
template<class Refs, class Traits>
struct Halfedge_wrapper
{
typedef My_halfedge<Refs,
CGAL::Tag_true,
CGAL::Tag_true,
CGAL::Tag_true> Halfedge;
};
};
class Polyhedron_ex : public CGAL::Polyhedron_3<My_kernel,My_items>
{
public:
typedef My_kernel::Vector_3 Vector_3;
typedef My_kernel::Point_3 Point_3;
public:
// life cycle
Polyhedron_ex() {}
virtual ~Polyhedron_ex() {}
// facet centers
void compute_facet_centers()
{
std::for_each(facets_begin(),facets_end(),Facet_center());
}
// tag all facets
void tag_facets(const int tag)
{
Facet_iterator pFace;
for(pFace = facets_begin();
pFace != facets_end();
pFace++)
pFace->tag(tag);
}
// get closest inner facet
Facet_handle get_closest_inner_facet(Point_3& point)
{
Facet_iterator pFace = facets_begin();
Facet_handle pClosest = pFace;
double minimum = pFace->distance(point);
for(;pFace != facets_end();
pFace++)
{
if(is_inner(pFace))
{
double distance = pFace->distance(point);
if(distance < minimum)
{
pClosest = pFace;
minimum = distance;
}
}
}
return pClosest;
}
bool is_inner(Facet_handle pFace)
{
typedef Halfedge_around_facet_const_circulator circ;
circ h = pFace->facet_begin();
do
{
if(h->opposite()->is_border())
return false;
}
while(++h != pFace->facet_begin());
return true;
}
// tag all vertices
void tag_vertices(const int tag)
{
Vertex_iterator iter;
for(iter = vertices_begin(); iter != vertices_end(); iter++)
iter->tag(tag);
}
// tag all halfedges
void tag_halfedges(const int tag)
{
Halfedge_iterator iter;
for(iter = halfedges_begin(); iter != halfedges_end(); iter++)
iter->tag(tag);
}
// compute bounding interval
double minimum (int coord)
{
assert(size_of_vertices() > 0);
Vertex_iterator pVertex = vertices_begin();
double minimum = pVertex->point()[coord];
for(;pVertex != vertices_end();pVertex++)
minimum = (std::min)(minimum,pVertex->point()[coord]);
return minimum;
}
double maximum (int coord)
{
assert(size_of_vertices() > 0);
Vertex_iterator pVertex = vertices_begin();
double maximum = pVertex->point()[coord];
for(;pVertex != vertices_end();pVertex++)
maximum = (std::max)(maximum,pVertex->point()[coord]);
return maximum;
}
Vertex_handle vertex_min(int coord,
double &minimum)
{
assert(size_of_vertices() > 0);
Vertex_iterator pVertex = vertices_begin();
Vertex_handle pBest = pVertex;
minimum = pVertex->point()[coord];
for(;pVertex != vertices_end();pVertex++)
{
double value = pVertex->point()[coord];
if(value < minimum)
{
minimum = (std::min)(minimum,value);
pBest = pVertex;
}
}
return pBest;
}
Vertex_handle vertex_max(int coord,
double &maximum)
{
assert(size_of_vertices() > 0);
Vertex_iterator pVertex = vertices_begin();
Vertex_handle pBest = pVertex;
maximum = pVertex->point()[coord];
for(;pVertex != vertices_end();pVertex++)
{
double value = pVertex->point()[coord];
if(value > maximum)
{
maximum = (std::max)(maximum,value);
pBest = pVertex;
}
}
return pBest;
}
// Index all mesh vertices following the order of the vertices_begin() iterator
void precompute_vertex_indices()
{
Vertex_iterator pVertex;
unsigned int i = 0;
for(pVertex = vertices_begin();
pVertex != vertices_end();
pVertex++)
pVertex->index(i++);
}
// Index all mesh half edges following the order of the halfedges_begin() iterator
void precompute_halfedge_indices()
{
Halfedge_iterator pHalfedge;
unsigned int i = 0;
for(pHalfedge = halfedges_begin();
pHalfedge != halfedges_end();
pHalfedge++)
pHalfedge->index(i++);
}
#ifdef DEBUG_TRUNCATE_OUTPUT
// Debug: write coordinates with 2 digits precision
#define FORMAT_EPS_COORD(x) (int(x/10.0+0.5)*10)
#else
#define FORMAT_EPS_COORD(x) (x)
#endif
// Dump parameterized mesh to an eps file
bool write_file_eps(const char *pFilename,
double scale = 500.0)
{
assert(pFilename != NULL);
std::ofstream out(pFilename);
if(!out)
return false;
CGAL::set_ascii_mode(out);
// compute bounding box
double xmin,xmax,ymin,ymax;
xmin = ymin = xmax = ymax = 0;
Halfedge_iterator pHalfedge;
for(pHalfedge = halfedges_begin();
pHalfedge != halfedges_end();
pHalfedge++)
{
double x1 = scale * pHalfedge->prev()->u();
double y1 = scale * pHalfedge->prev()->v();
double x2 = scale * pHalfedge->u();
double y2 = scale * pHalfedge->v();
xmin = (std::min)(xmin,x1);
xmin = (std::min)(xmin,x2);
xmax = (std::max)(xmax,x1);
xmax = (std::max)(xmax,x2);
ymax = (std::max)(ymax,y1);
ymax = (std::max)(ymax,y2);
ymin = (std::min)(ymin,y1);
ymin = (std::min)(ymin,y2);
}
out << "%!PS-Adobe-2.0 EPSF-2.0" << std::endl;
out << "%%BoundingBox: " << int(xmin+0.5) << " "
<< int(ymin+0.5) << " "
<< int(xmax+0.5) << " "
<< int(ymax+0.5) << std::endl;
out << "%%HiResBoundingBox: " << xmin << " "
<< ymin << " "
<< xmax << " "
<< ymax << std::endl;
out << "%%EndComments" << std::endl;
out << "gsave" << std::endl;
out << "0.1 setlinewidth" << std::endl;
// color macros
out << std::endl;
out << "% RGB color command - r g b C" << std::endl;
out << "/C { setrgbcolor } bind def" << std::endl;
out << "/white { 1 1 1 C } bind def" << std::endl;
out << "/black { 0 0 0 C } bind def" << std::endl;
// edge macro -> E
out << std::endl;
out << "% Black stroke - x1 y1 x2 y2 E" << std::endl;
out << "/E {moveto lineto stroke} bind def" << std::endl;
out << "black" << std::endl << std::endl;
// output edge coordinates
for(pHalfedge = halfedges_begin();
pHalfedge != halfedges_end();
pHalfedge++)
{
double x1 = scale * pHalfedge->prev()->u();
double y1 = scale * pHalfedge->prev()->v();
double x2 = scale * pHalfedge->u();
double y2 = scale * pHalfedge->v();
out << FORMAT_EPS_COORD(x1) << " "
<< FORMAT_EPS_COORD(y1) << " "
<< FORMAT_EPS_COORD(x2) << " "
<< FORMAT_EPS_COORD(y2) << " E" << std::endl;
}
/* Emit EPS trailer. */
out << "grestore" << std::endl;
out << std::endl;
out << "showpage" << std::endl;
return true;
}
#ifdef DEBUG_TRUNCATE_OUTPUT
// Debug: write coordinates with 2 digits precision
#define FORMAT_UV(x) (float(int(x*100.0+0.5))/100.0)
#else
#define FORMAT_UV(x) (x)
#endif
// Dump parameterized mesh to a Wavefront OBJ file
// v x y z
// f 1 2 3 4 (1-based)
//
// Implementation note: the UV is meaningless for a NON parameterized halfedge
bool write_file_obj(const char *pFilename)
{
assert(pFilename != NULL);
std::ofstream out(pFilename);
if(!out)
return false;
CGAL::set_ascii_mode(out);
// Index all mesh vertices following the order of vertices_begin() iterator
precompute_vertex_indices();
// Index all mesh half edges following the order of halfedges_begin() iterator
precompute_halfedge_indices();
// write the name of material file
out << "mtllib parameterization.mtl" << std::endl ;
// output coordinates
out << "# vertices" << std::endl ;
Vertex_iterator pVertex;
for(pVertex = vertices_begin(); pVertex != vertices_end(); pVertex++)
out << "v " << pVertex->point().x() << " "
<< pVertex->point().y() << " "
<< pVertex->point().z() << std::endl;
// Write UVs (1 UV / halfedge)
out << "# uv coordinates" << std::endl ;
Halfedge_iterator pHalfedge;
for(pHalfedge = halfedges_begin(); pHalfedge != halfedges_end(); pHalfedge++)
{
if (pHalfedge->is_parameterized())
out << "vt " << FORMAT_UV(pHalfedge->u()) << " " << FORMAT_UV(pHalfedge->v()) << std::endl;
else
out << "vt " << 0.0 << " " << 0.0 << std::endl;
}
// Write facets using the unique material # 1
out << "# facets" << std::endl;
out << "usemtl Mat_1" << std::endl;
Facet_const_iterator pFacet;
for(pFacet = facets_begin(); pFacet != facets_end(); pFacet++)
{
Halfedge_around_facet_const_circulator h = pFacet->facet_begin();
out << "f";
do {
out << " " << h->vertex()->index()+1;
if (h->is_parameterized())
out << "/" << h->index()+1;
}
while(++h != pFacet->facet_begin());
out << std::endl;
}
return true;
}
// is vertex on border ?
static bool is_border(Vertex_const_handle pVertex)
{
Halfedge_around_vertex_const_circulator pHalfedge = pVertex->vertex_begin();
Halfedge_around_vertex_const_circulator end = pHalfedge;
if(pHalfedge == NULL) // isolated vertex
return true;
CGAL_For_all(pHalfedge,end)
if(pHalfedge->is_border())
return true;
return false;
}
// compute distance from facet center to halfedge center
double distance(Facet_handle pFacet,
Halfedge_handle pHalfedge)
{
// we assume
Point_3 center_facet = pFacet->center();
Vector_3 v = (pHalfedge->opposite()->vertex()->point()
- pHalfedge->vertex()->point());
Point_3 center_halfedge = pHalfedge->vertex()->point() + (v/2);
Vector_3 d = center_facet-center_halfedge;
return std::sqrt(d*d);
}
void farthest_point_aligned(Vertex_handle &pVertexMin,
Vertex_handle &pVertexMax)
{
double xmin,xmax,ymin,ymax,zmin,zmax;
Vertex_handle pVertex_xMin = vertex_min(0,xmin);
Vertex_handle pVertex_xMax = vertex_max(0,xmax);
Vertex_handle pVertex_yMin = vertex_min(1,ymin);
Vertex_handle pVertex_yMax = vertex_max(1,ymax);
Vertex_handle pVertex_zMin = vertex_min(2,zmin);
Vertex_handle pVertex_zMax = vertex_max(2,zmax);
double xdiff = xmax-xmin;
double ydiff = ymax-ymin;
double zdiff = zmax-zmin;
if (xdiff >= (std::max)(ydiff,zdiff))
{
pVertexMin = pVertex_xMin;
pVertexMax = pVertex_xMax;
}
else if (ydiff >= (std::max)(xdiff,zdiff))
{
pVertexMin = pVertex_yMin;
pVertexMax = pVertex_yMax;
}
else
{
pVertexMin = pVertex_zMin;
pVertexMax = pVertex_zMax;
}
}
}; // end class PolyhedronEx
#endif // POLYHEDRON_EX_H_INCLUDED