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( "discrete_authalic.cpp" )
|
||||||
create_single_source_cgal_program( "lscm.cpp" )
|
create_single_source_cgal_program( "lscm.cpp" )
|
||||||
create_single_source_cgal_program( "orbifold.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( "seam_Polyhedron_3.cpp" )
|
||||||
create_single_source_cgal_program( "simple_parameterization.cpp" )
|
create_single_source_cgal_program( "simple_parameterization.cpp" )
|
||||||
create_single_source_cgal_program( "square_border_parameterizer.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;
|
CGAL::Timer task_timer;
|
||||||
task_timer.start();
|
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);
|
std::ifstream in_mesh(mesh_filename);
|
||||||
if(!in_mesh) {
|
if(!in_mesh) {
|
||||||
std::cerr << "Error: problem loading the input data" << std::endl;
|
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 first line for the cones indices
|
||||||
// -- the second line must be empty
|
// -- the second line must be empty
|
||||||
// -- the third line optionally provides the seam edges indices as 'e11 e12 e21 e22 e31 e32' etc.
|
// -- 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'
|
// Read the cones and find the corresponding vertex_descriptor in the underlying mesh 'sm'
|
||||||
typedef std::vector<SM_vertex_descriptor> Cones_in_smesh_container;
|
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