mirror of https://github.com/CGAL/cgal
Removed or untracked irrelevant files
Also fixed some data paths.
This commit is contained in:
parent
4570ab4320
commit
c2bc4082e7
|
|
@ -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" )
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
||||
Loading…
Reference in New Issue