mirror of https://github.com/CGAL/cgal
836 lines
25 KiB
C++
836 lines
25 KiB
C++
// Copyright (c) 1997-2002 Max-Planck-Institute Saarbruecken (Germany).
|
|
// All rights reserved.
|
|
//
|
|
// This file is part of CGAL (www.cgal.org).
|
|
//
|
|
// $URL$
|
|
// $Id$
|
|
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
|
|
//
|
|
//
|
|
// Author(s) : Michael Seel <seel@mpi-sb.mpg.de>
|
|
|
|
#ifndef CGAL_SPHERE_GEOMETRY_OGL_H
|
|
#define CGAL_SPHERE_GEOMETRY_OGL_H
|
|
|
|
#include <CGAL/license/Nef_S2.h>
|
|
|
|
|
|
#include <CGAL/Nef_S2/OGL_base_object.h>
|
|
#include <CGAL/Simple_cartesian.h>
|
|
#include <CGAL/Nef_S2/Sphere_geometry.h>
|
|
#include <CGAL/Nef_S2/SM_triangulator.h>
|
|
#include <CGAL/IO/Color.h>
|
|
#include <qgl.h>
|
|
#include <CGAL/glu.h>
|
|
#include <cmath>
|
|
#include <cstdlib>
|
|
#include <cstdio>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#undef CGAL_NEF_DEBUG
|
|
#define CGAL_NEF_DEBUG 151
|
|
#include <CGAL/Nef_2/debug.h>
|
|
|
|
#define CGAL_NEF_LGREY CGAL::IO::Color(170,170,200)
|
|
#define CGAL_NEF_DGREY CGAL::IO::Color(30,30,50)
|
|
|
|
namespace CGAL {
|
|
namespace OGL {
|
|
|
|
struct Gen_object {
|
|
Gen_object() {}
|
|
virtual ~Gen_object() {}
|
|
virtual void draw() const {}
|
|
virtual Gen_object* clone() const { return 0; }
|
|
virtual void print() const {}
|
|
};
|
|
|
|
typedef CGAL::Simple_cartesian<double> VKernel;
|
|
typedef VKernel::Vector_3 VVector;
|
|
typedef VKernel::Point_3 VPoint;
|
|
typedef VKernel::Aff_transformation_3 VTrafo;
|
|
typedef VKernel::Aff_transformation_3 Affine_3;
|
|
typedef std::vector<VPoint> VSegment;
|
|
typedef VKernel::Triangle_3 DTriangle;
|
|
typedef std::vector<DTriangle> VTriangle;
|
|
|
|
template <typename R>
|
|
VVector convert(const CGAL::Vector_3<R>& v)
|
|
{ return VVector(CGAL::to_double(v.x()),
|
|
CGAL::to_double(v.y()),
|
|
CGAL::to_double(v.z())); }
|
|
|
|
template <typename R>
|
|
VVector normalize_and_convert(const CGAL::Vector_3<R>& v)
|
|
{
|
|
typename R::FT xa = CGAL::abs(v.x());
|
|
typename R::FT ya = CGAL::abs(v.y());
|
|
typename R::FT za = CGAL::abs(v.z());
|
|
typename R::FT m = (std::max)((std::max)(xa,ya),za);
|
|
if (m==0) {
|
|
return VVector(0,0,0);
|
|
} else {
|
|
double xd = CGAL::to_double(v.x()/m);
|
|
double yd = CGAL::to_double(v.y()/m);
|
|
double zd = CGAL::to_double(v.z()/m);
|
|
VVector u(xd,yd,zd);
|
|
return u / CGAL_NTS sqrt(u*u) ; // normalize
|
|
}
|
|
}
|
|
|
|
const double refinement_angle = 0.1;
|
|
const double shrink_fac = 0.995;
|
|
|
|
template <typename R>
|
|
class Approximator {
|
|
|
|
public:
|
|
static VPoint approximate(const CGAL::Sphere_point<R>& p) {
|
|
VVector v = normalize_and_convert(p-CGAL::ORIGIN);
|
|
return CGAL::ORIGIN+v;
|
|
}
|
|
|
|
static VSegment approximate(const CGAL::Sphere_segment<R>& s) {
|
|
|
|
/* we construct the rotation matrix that transfers the x-axis
|
|
into |ps_|, the z-axis into h_.orthogonal_vector() and the
|
|
y-axix into the corresponding crossproduct of the two.*/
|
|
if ( s.is_degenerate() ) {
|
|
VSegment S(1);
|
|
S[0] = approximate(s.source());
|
|
return S;
|
|
}
|
|
|
|
VVector v0 = convert(s.source()-CGAL::ORIGIN);
|
|
VVector v2 = convert(s.sphere_circle().orthogonal_vector());
|
|
VVector v1(-cross_product(v0,v2));
|
|
VVector v3 = convert(s.target()-CGAL::ORIGIN);
|
|
double v0l = CGAL_NTS sqrt(v0*v0);
|
|
double v1l = CGAL_NTS sqrt(v1*v1);
|
|
double v2l = CGAL_NTS sqrt(v2*v2);
|
|
double v3l = CGAL_NTS sqrt(v3*v3);
|
|
double cosalpha = v0*v3 / v0l / v3l;
|
|
double alpha = std::acos(cosalpha);
|
|
const int units_per_halfcircle = 50;
|
|
int units = int(units_per_halfcircle/CGAL_PI * alpha);
|
|
if (units == 0) ++units;
|
|
bool seg_is_short = s.is_short();
|
|
bool seg_is_halfcircle = s.is_halfcircle();
|
|
if ( seg_is_halfcircle ) units = units_per_halfcircle;
|
|
else if ( !seg_is_short ) {
|
|
units = 2*units_per_halfcircle - (units+1);
|
|
} CGAL_NEF_TRACEV(units); CGAL_NEF_TRACEV(cosalpha); CGAL_NEF_TRACEV(alpha);
|
|
|
|
v0 = v0 / v0l;
|
|
v1 = v1 / v1l;
|
|
v2 = v2 / v2l;
|
|
v3 = v3 / v3l;
|
|
VTrafo T(v0.x(),v1.x(),v2.x(),
|
|
v0.y(),v1.y(),v2.y(),
|
|
v0.z(),v1.z(),v2.z());
|
|
VSegment S(units+1);
|
|
for (int i=0; i<units; ++i)
|
|
S[i] = VPoint(std::cos(CGAL_PI*i/double(units_per_halfcircle)),
|
|
std::sin(CGAL_PI*i/double(units_per_halfcircle)),
|
|
0.0);
|
|
double sinalpha = 1 - cosalpha*cosalpha;
|
|
if (sinalpha <0) sinalpha = 0;
|
|
else sinalpha = CGAL_NTS sqrt(sinalpha);
|
|
if ( seg_is_short )
|
|
S[units] = VPoint(cosalpha, sinalpha, 0);
|
|
else
|
|
S[units] = VPoint(cosalpha, -sinalpha, 0);
|
|
VSegment::iterator it;
|
|
for(it = S.begin(); it != S.end(); ++it) { CGAL_NEF_TRACEN(*it<<" "<<T(*it));
|
|
*it = T(*it);
|
|
} CGAL_NEF_TRACEN("");
|
|
return S;
|
|
}
|
|
|
|
static VSegment approximate(const CGAL::Sphere_circle<R>& s) {
|
|
|
|
/* we construct the rotation matrix that transfers the x-axis
|
|
into |ps_|, the z-axis into h_.orthogonal_vector() and the
|
|
y-axix into the corresponding crossproduct of the two.*/
|
|
|
|
VVector v0 = convert(s.base1());
|
|
VVector v1 = convert(s.base2());
|
|
VVector v2 = convert(s.orthogonal_vector());
|
|
double v0l = CGAL_NTS sqrt(v0*v0);
|
|
double v1l = CGAL_NTS sqrt(v1*v1);
|
|
double v2l = CGAL_NTS sqrt(v2*v2);
|
|
const int units = 100;
|
|
v0 = v0 / v0l;
|
|
v1 = v1 / v1l;
|
|
v2 = v2 / v2l;
|
|
VTrafo T(v0.x(),v1.x(),v2.x(),
|
|
v0.y(),v1.y(),v2.y(),
|
|
v0.z(),v1.z(),v2.z());
|
|
VSegment S(units);
|
|
for (int i=0; i<units; ++i) {
|
|
S[i] = VPoint(std::cos(2.0*CGAL_PI*i/double(units)),
|
|
std::sin(2.0*CGAL_PI*i/double(units)),
|
|
0.0);
|
|
}
|
|
VSegment::iterator it;
|
|
for(it = S.begin(); it != S.end(); ++it) *it = T(*it);
|
|
return S;
|
|
}
|
|
|
|
|
|
/* the following operation refines a sphere triangle as a list of flat
|
|
triangles in 3d. The refinement only works for triangles that are
|
|
contained in a perfect hemisphere (no long sphere segments are
|
|
allowed as triangle segments). We split triangles along at the
|
|
midpoint of their longest side into two. */
|
|
|
|
static void refine(const DTriangle& t, VTriangle& T) {
|
|
double angle[3]; int i(0);
|
|
angle[0] = std::acos((t[0]-CGAL::ORIGIN)*(t[1]-CGAL::ORIGIN));
|
|
angle[1] = std::acos((t[1]-CGAL::ORIGIN)*(t[2]-CGAL::ORIGIN));
|
|
angle[2] = std::acos((t[2]-CGAL::ORIGIN)*(t[0]-CGAL::ORIGIN));
|
|
CGAL_NEF_TRACEN("refine "<<angle[0]<<" "<<angle[1]<<" "<<angle[2]);
|
|
if ( angle[1] > angle[0] ) {
|
|
if ( angle[2] > angle[1] ) i=2;
|
|
else i=1;
|
|
} else { // angle[0] >= angle[1]
|
|
if ( angle[2] > angle[0] ) i=2;
|
|
else i=0;
|
|
}
|
|
// now i references the side of maximal angle
|
|
if ( angle[i] < refinement_angle ) // refinement threshold
|
|
{ T.push_back(t); return; }
|
|
VVector v;
|
|
switch (i) {
|
|
case 0: v = (t[0]-CGAL::ORIGIN)+(t[1]-CGAL::ORIGIN); break;
|
|
case 1: v = (t[1]-CGAL::ORIGIN)+(t[2]-CGAL::ORIGIN); break;
|
|
case 2: v = (t[2]-CGAL::ORIGIN)+(t[0]-CGAL::ORIGIN); break;
|
|
}
|
|
v = v / CGAL_NTS sqrt(v*v) ; // normalize
|
|
VPoint p = CGAL::ORIGIN+v;
|
|
DTriangle t1,t2;
|
|
switch (i) {
|
|
case 0: t1=DTriangle(t[0],p,t[2]); t2=DTriangle(p,t[1],t[2]); break;
|
|
case 1: t1=DTriangle(t[1],p,t[0]); t2=DTriangle(p,t[2],t[0]); break;
|
|
case 2: t1=DTriangle(t[2],p,t[1]); t2=DTriangle(p,t[0],t[1]); break;
|
|
}
|
|
refine(t1,T);
|
|
refine(t2,T);
|
|
}
|
|
|
|
static VTriangle approximate(const CGAL::Sphere_triangle<R>& t) {
|
|
// we subdivide the triangle into a list of triangles until
|
|
// we reach a fine resolution on the surface.
|
|
|
|
VTriangle T;
|
|
DTriangle td(approximate(t.point(0)),
|
|
approximate(t.point(1)),
|
|
approximate(t.point(2)));
|
|
CGAL_NEF_TRACEN("approximate " << td);
|
|
refine(td,T);
|
|
return T;
|
|
}
|
|
|
|
};
|
|
|
|
|
|
template <class R_>
|
|
class Sphere_point : public VPoint, public Gen_object {
|
|
typedef R_ R;
|
|
CGAL::Sphere_point<R> p_;
|
|
CGAL::IO::Color c_;
|
|
unsigned w_;
|
|
public:
|
|
Sphere_point() {}
|
|
Sphere_point(const CGAL::Sphere_point<R>& p,
|
|
CGAL::IO::Color c = CGAL::black(), unsigned w = 10) :
|
|
VPoint(Approximator<R>::approximate(p)), p_(p), c_(c), w_(w) {}
|
|
Sphere_point(const Sphere_point<R>& p) : VPoint(p), Gen_object()
|
|
{ p_ = p.p_; c_ = p.c_; w_ = p.w_; }
|
|
Sphere_point<R>& operator=(const Sphere_point<R>& p)
|
|
{ VPoint::operator=(p); p_ = p.p_; c_ = p.c_; w_ = p.w_;
|
|
return *this; }
|
|
|
|
virtual ~Sphere_point() {}
|
|
|
|
const CGAL::Sphere_point<R>& original() const
|
|
{ return p_; }
|
|
|
|
virtual Gen_object* clone() const
|
|
{ return new Sphere_point<R>(*this); }
|
|
|
|
virtual void draw() const {
|
|
glPointSize(w_);
|
|
glColor3ub(c_.red(),c_.green(),c_.blue());
|
|
glBegin(GL_POINTS);
|
|
glNormal3d(x(),y(),z());
|
|
glVertex3d(x(),y(),z());
|
|
glEnd();
|
|
}
|
|
|
|
virtual void print() const
|
|
{ std::cerr << "point " << p_; }
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
template <class R_>
|
|
class Sphere_segment : public VSegment, public Gen_object {
|
|
typedef R_ R;
|
|
CGAL::Sphere_segment<R> s_;
|
|
CGAL::IO::Color c_;
|
|
unsigned w_;
|
|
public:
|
|
Sphere_segment() {}
|
|
Sphere_segment(const CGAL::Sphere_segment<R>& s,
|
|
CGAL::IO::Color c = CGAL::black(), unsigned w = 2)
|
|
: VSegment(Approximator<R>::approximate(s)), s_(s), c_(c), w_(w) {}
|
|
Sphere_segment(const Sphere_segment<R>& s) : VSegment(s), Gen_object()
|
|
{ s_ = s.s_; c_ = s.c_; w_ = s.w_; }
|
|
Sphere_segment<R>& operator=(const Sphere_segment<R>& s)
|
|
{ VSegment::operator=(s); s_ = s.s_; c_ = s.c_; w_ = s.w_;
|
|
return *this; }
|
|
virtual ~Sphere_segment() {}
|
|
|
|
const CGAL::Sphere_segment<R>& original() const
|
|
{ return s_; }
|
|
|
|
virtual Gen_object* clone() const
|
|
{ return new Sphere_segment<R>(*this); }
|
|
|
|
virtual void draw() const
|
|
{ CGAL_NEF_TRACEN("draw "<<s_);
|
|
if ( size() == 1 ) {
|
|
glPointSize(5*w_);
|
|
glColor3ub(c_.red(),c_.green(),c_.blue());
|
|
glBegin(GL_POINTS);
|
|
glNormal3d(begin()->x(),begin()->y(),begin()->z());
|
|
glVertex3d(begin()->x(),begin()->y(),begin()->z());
|
|
glEnd();
|
|
} else {
|
|
glLineWidth(w_);
|
|
glColor3ub(c_.red(),c_.green(),c_.blue());
|
|
glBegin(GL_LINE_STRIP);
|
|
VSegment::const_iterator it;
|
|
for(it = begin(); it != end(); ++it) {
|
|
glNormal3d(it->x(),it->y(),it->z());
|
|
glVertex3d(it->x(),it->y(),it->z());
|
|
}
|
|
glEnd();
|
|
}
|
|
}
|
|
|
|
virtual void print() const
|
|
{ std::cerr << "segment " << s_; }
|
|
|
|
};
|
|
|
|
|
|
|
|
template <class R_>
|
|
class Sphere_circle : public VSegment, public Gen_object {
|
|
typedef R_ R;
|
|
CGAL::Sphere_circle<R> s_;
|
|
CGAL::IO::Color c_;
|
|
unsigned w_;
|
|
public:
|
|
Sphere_circle() {}
|
|
Sphere_circle(const CGAL::Sphere_circle<R>& s,
|
|
CGAL::IO::Color c = CGAL::black(), unsigned w = 2)
|
|
: VSegment(Approximator<R>::approximate(s)), s_(s), c_(c), w_(w) {}
|
|
Sphere_circle(const Sphere_circle<R>& s) : VSegment(s), Gen_object()
|
|
{ s_ = s.s_; c_ = s.c_; w_ = s.w_; }
|
|
Sphere_circle<R>& operator=(const Sphere_circle<R>& s)
|
|
{ VSegment::operator=(s); s_ = s.s_; c_ = s.c_; w_ = s.w_;
|
|
return *this; }
|
|
virtual ~Sphere_circle() {}
|
|
|
|
const CGAL::Sphere_circle<R>& original() const
|
|
{ return s_; }
|
|
|
|
virtual Gen_object* clone() const
|
|
{ return new Sphere_circle<R>(*this); }
|
|
|
|
virtual void draw() const
|
|
{ CGAL_NEF_TRACEN("draw "<<s_);
|
|
glLineWidth(w_);
|
|
glColor3ub(c_.red(),c_.green(),c_.blue());
|
|
glBegin(GL_LINE_LOOP);
|
|
VSegment::const_iterator it;
|
|
for(it = begin(); it != end(); ++it) {
|
|
glNormal3d(it->x(),it->y(),it->z());
|
|
glVertex3d(it->x(),it->y(),it->z());
|
|
}
|
|
glEnd();
|
|
}
|
|
|
|
virtual void print() const
|
|
{ std::cerr << "circle " << s_; }
|
|
|
|
};
|
|
|
|
|
|
/* The following class approximates a spherical triangle by a list
|
|
of flat triangles */
|
|
|
|
template <class R_>
|
|
class Sphere_triangle : public VTriangle, public Gen_object {
|
|
typedef R_ R;
|
|
CGAL::Sphere_triangle<R> t_;
|
|
CGAL::IO::Color c_;
|
|
public:
|
|
Sphere_triangle() {}
|
|
|
|
Sphere_triangle(const CGAL::Sphere_triangle<R>& t,
|
|
CGAL::IO::Color c = CGAL::IO::Color(100,100,120))
|
|
: VTriangle(Approximator<R>::approximate(t)), t_(t), c_(c) {}
|
|
|
|
Sphere_triangle(const Sphere_triangle<R>& t) : VTriangle(t), Gen_object()
|
|
{ t_ = t.t_; c_ = t.c_; }
|
|
|
|
Sphere_triangle<R>& operator=(const Sphere_triangle<R>& t)
|
|
{ VTriangle::operator=(t); t_ = t.t_; c_ = t.c_; return *this; }
|
|
|
|
virtual ~Sphere_triangle() {}
|
|
|
|
const CGAL::Sphere_triangle<R>& original() const
|
|
{ return t_; }
|
|
|
|
virtual Gen_object* clone() const
|
|
{ return new Sphere_triangle<R>(*this); }
|
|
|
|
virtual void draw() const {
|
|
CGAL_NEF_TRACEN("draw "<<t_ << " in " << c_);
|
|
VTriangle::const_iterator it;
|
|
VPoint p;
|
|
glColorMaterial(GL_FRONT, GL_DIFFUSE);
|
|
glEnable(GL_COLOR_MATERIAL);
|
|
glColor3ub(c_.red(),c_.green(),c_.blue());
|
|
glBegin(GL_TRIANGLES);
|
|
for(it = begin(); it != end(); ++it) {
|
|
p = it->vertex(0);
|
|
glNormal3d(p.x(),p.y(),p.z()); //glVertex3d(p.x(),p.y(),p.z());
|
|
glVertex3d(shrink_fac*p.x(),shrink_fac*p.y(),shrink_fac*p.z());
|
|
p = it->vertex(1);
|
|
glNormal3d(p.x(),p.y(),p.z());
|
|
glVertex3d(shrink_fac*p.x(),shrink_fac*p.y(),shrink_fac*p.z());
|
|
p = it->vertex(2);
|
|
glNormal3d(p.x(),p.y(),p.z());
|
|
glVertex3d(shrink_fac*p.x(),shrink_fac*p.y(),shrink_fac*p.z());
|
|
}
|
|
glEnd();
|
|
glDisable(GL_COLOR_MATERIAL);
|
|
}
|
|
|
|
virtual void print() const
|
|
{ std::cerr << "triangle " << t_; }
|
|
|
|
};
|
|
|
|
//----------------------------------------------------------------------------
|
|
// the sphere:
|
|
//----------------------------------------------------------------------------
|
|
|
|
enum { SM_FACES, SM_SKELETON, SM_TRIANGULATION };
|
|
enum { SM_AXES, SM_CUBE };
|
|
|
|
class Unit_sphere : public OGL_base_object {
|
|
typedef std::list<Gen_object*> Object_list;
|
|
typedef Object_list::const_iterator Object_const_iterator;
|
|
typedef Object_list::iterator Object_iterator;
|
|
|
|
GLUquadricObj* sphere_;
|
|
int style_;
|
|
bool initialized_;
|
|
Object_list objects_,triangles_,triangle_edges_;
|
|
GLuint sphere_list_;
|
|
std::vector<bool> switches;
|
|
|
|
public:
|
|
void init() {
|
|
style_ = SM_FACES;
|
|
switches[0] = true;
|
|
switches[1] = false;
|
|
gluQuadricNormals(sphere_,GLenum(GLU_SMOOTH));
|
|
}
|
|
|
|
Unit_sphere() : switches(2) {
|
|
sphere_ = gluNewQuadric();
|
|
initialized_ = false;
|
|
init();
|
|
}
|
|
|
|
void clear_list()
|
|
{ while ( objects_.begin() != objects_.end() ) {
|
|
delete (*objects_.begin());
|
|
objects_.pop_front();
|
|
}
|
|
while ( triangles_.begin() != triangles_.end() ) {
|
|
delete (*triangles_.begin());
|
|
triangles_.pop_front();
|
|
}
|
|
while ( triangle_edges_.begin() != triangle_edges_.end() ) {
|
|
delete (*triangle_edges_.begin());
|
|
triangle_edges_.pop_front();
|
|
}
|
|
}
|
|
|
|
void copy_list(const Unit_sphere& S)
|
|
{ Object_const_iterator it;
|
|
CGAL_forall_iterators (it,S.objects_)
|
|
objects_.push_back( (*it)->clone() );
|
|
CGAL_forall_iterators (it,S.triangles_)
|
|
triangles_.push_back( (*it)->clone() );
|
|
CGAL_forall_iterators (it,S.triangle_edges_)
|
|
triangle_edges_.push_back( (*it)->clone() );
|
|
}
|
|
|
|
void print() const
|
|
{ std::cerr << "Dumping Unit_sphere:\n";
|
|
for (Object_const_iterator it = objects_.begin();
|
|
it != objects_.end(); ++it)
|
|
(*it)->print();
|
|
std::cerr << std::endl;
|
|
for (Object_const_iterator it = triangles_.begin();
|
|
it != triangles_.end(); ++it)
|
|
(*it)->print();
|
|
std::cerr << std::endl;
|
|
}
|
|
|
|
Unit_sphere(const Unit_sphere& S) : OGL_base_object(), switches(2)
|
|
{ CGAL_NEF_TRACEN("copyconstruction");
|
|
sphere_ = gluNewQuadric();
|
|
initialized_ = S.initialized_;
|
|
style_ = S.style_;
|
|
switches[0] = S.switches[0];
|
|
switches[1] = S.switches[1];
|
|
copy_list(S);
|
|
}
|
|
|
|
|
|
Unit_sphere& operator=(const Unit_sphere& S)
|
|
{ CGAL_NEF_TRACEN("assignment");
|
|
initialized_ = S.initialized_;
|
|
style_ = S.style_;
|
|
switches[0] = S.switches[0];
|
|
switches[1] = S.switches[1];
|
|
clear_list(); copy_list(S);
|
|
return *this;
|
|
}
|
|
|
|
~Unit_sphere() {
|
|
clear_list();
|
|
gluDeleteQuadric(sphere_);
|
|
}
|
|
|
|
template <typename R>
|
|
void push_back(const CGAL::Sphere_point<R>& p,
|
|
CGAL::IO::Color c = CGAL::IO::yellow(), unsigned w = 5)
|
|
{ objects_.push_back(new Sphere_point<R>(p,c,w)); }
|
|
|
|
template <typename R>
|
|
void push_back(const CGAL::Sphere_segment<R>& s,
|
|
CGAL::IO::Color c = CGAL::IO::black(), unsigned w = 1)
|
|
{ objects_.push_back(new Sphere_segment<R>(s,c,w)); }
|
|
|
|
template <typename R>
|
|
void push_back(const CGAL::Sphere_circle<R>& s,
|
|
CGAL::IO::Color c = CGAL::IO::black(), unsigned w = 1)
|
|
{ objects_.push_back(new Sphere_circle<R>(s,c,w)); }
|
|
|
|
template <typename R>
|
|
void push_back(const CGAL::Sphere_triangle<R>& t,
|
|
CGAL::IO::Color c = CGAL::IO::white())
|
|
{ triangles_.push_back(new Sphere_triangle<R>(t,c)); }
|
|
|
|
template <typename R>
|
|
void push_back_triangle_edge(const CGAL::Sphere_segment<R>& s,
|
|
CGAL::IO::Color c = CGAL::IO::blue(), unsigned w = 1)
|
|
{ triangle_edges_.push_back(new Sphere_segment<R>(s,c,w)); }
|
|
|
|
void set_style(int style) {
|
|
style_ = style;
|
|
}
|
|
|
|
void toggle(int index) {
|
|
switches[index] = !switches[index];
|
|
}
|
|
private:
|
|
|
|
void construct_axes() const
|
|
{ int i;
|
|
double f(1.02);
|
|
glNewList(sphere_list_+3, GL_COMPILE);
|
|
glLineWidth(2.0);
|
|
// red x-axis and equator
|
|
glColor3f(1.0,0.0,0.0);
|
|
glBegin(GL_LINES);
|
|
glVertex3d(0.0,0.0,0.0);
|
|
glVertex3d(1.2,0.0,0.0);
|
|
glEnd();
|
|
glBegin(GL_LINE_LOOP);
|
|
for(i=0;i<100;i++)
|
|
glVertex3d(f*std::cos(2.0*CGAL_PI*i/100.0),f*std::sin(2.0*CGAL_PI*i/100.0),0.0);
|
|
glEnd();
|
|
// green y-axis and equator
|
|
glColor3f(0.0,1.0,0.0);
|
|
glBegin(GL_LINES);
|
|
glVertex3d(0.0,0.0,0.0);
|
|
glVertex3d(0.0,1.2,0.0);
|
|
glEnd();
|
|
glBegin(GL_LINE_LOOP);
|
|
for(i=0;i<100;i++)
|
|
glVertex3d(0.0,f*std::cos(2.0*CGAL_PI*i/100.0),f*std::sin(2.0*CGAL_PI*i/100.0));
|
|
glEnd();
|
|
// blue z-axis and equator
|
|
glColor3f(0.0,0.0,1.0);
|
|
glBegin(GL_LINES);
|
|
glVertex3d(0.0,0.0,0.0);
|
|
glVertex3d(0.0,0.0,1.2);
|
|
glEnd();
|
|
glBegin(GL_LINE_LOOP);
|
|
for(i=0;i<100;i++)
|
|
glVertex3d(f*std::cos(2.0*CGAL_PI*i/100.0),0.0,f*std::sin(2.0*CGAL_PI*i/100.0));
|
|
glEnd();
|
|
// six coordinate points in pink:
|
|
glPointSize(10);
|
|
glColor3f(1,0,1);
|
|
glBegin(GL_POINTS);
|
|
glVertex3d(1,0,0);
|
|
glVertex3d(0,1,0);
|
|
glVertex3d(0,0,1);
|
|
glVertex3d(-1,0,0);
|
|
glVertex3d(0,-1,0);
|
|
glVertex3d(0,0,-1);
|
|
glEnd(); glEndList();
|
|
}
|
|
|
|
void construct_cube() const
|
|
{
|
|
glNewList(sphere_list_+4, GL_COMPILE);
|
|
glColor3f(1,1,0); // yellow
|
|
glLineWidth(2.0);
|
|
glBegin(GL_LINE_LOOP);
|
|
glVertex3d(-1.0,-1.0,-1.0);
|
|
glVertex3d( 1.0,-1.0,-1.0);
|
|
glVertex3d( 1.0, 1.0,-1.0);
|
|
glVertex3d(-1.0, 1.0,-1.0);
|
|
glEnd();
|
|
glBegin(GL_LINE_LOOP);
|
|
glVertex3d(-1.0,-1.0, 1.0);
|
|
glVertex3d( 1.0,-1.0, 1.0);
|
|
glVertex3d( 1.0, 1.0, 1.0);
|
|
glVertex3d(-1.0, 1.0, 1.0);
|
|
glEnd();
|
|
glBegin(GL_LINES);
|
|
glVertex3d(-1.0,-1.0,-1.0);
|
|
glVertex3d(-1.0,-1.0, 1.0);
|
|
glVertex3d( 1.0,-1.0,-1.0);
|
|
glVertex3d( 1.0,-1.0, 1.0);
|
|
glVertex3d( 1.0, 1.0,-1.0);
|
|
glVertex3d( 1.0, 1.0, 1.0);
|
|
glVertex3d(-1.0, 1.0,-1.0);
|
|
glVertex3d(-1.0, 1.0, 1.0);
|
|
glEnd(); glEndList();
|
|
}
|
|
|
|
void construct()
|
|
{ initialized_=true;
|
|
sphere_list_ = glGenLists(5);
|
|
CGAL_assertion_msg(sphere_list_!=0,"no display list.");
|
|
// skeleton:
|
|
glNewList(sphere_list_, GL_COMPILE);
|
|
for (Object_const_iterator it = objects_.begin();
|
|
it != objects_.end(); ++it)
|
|
(*it)->draw();
|
|
glEndList();
|
|
// triangles:
|
|
glNewList(sphere_list_+1, GL_COMPILE);
|
|
for (Object_const_iterator it = triangles_.begin();
|
|
it != triangles_.end(); ++it)
|
|
(*it)->draw();
|
|
glEndList();
|
|
glNewList(sphere_list_+2, GL_COMPILE);
|
|
for (Object_const_iterator it = triangle_edges_.begin();
|
|
it != triangle_edges_.end(); ++it)
|
|
(*it)->draw();
|
|
glEndList();
|
|
// orientation features:
|
|
construct_axes();
|
|
construct_cube();
|
|
}
|
|
|
|
public:
|
|
|
|
//void draw(GLdouble z_vec[3]) const
|
|
void draw() const
|
|
{
|
|
gluQuadricDrawStyle(sphere_,GLenum(GLU_FILL));
|
|
glEnable(GL_LIGHTING);
|
|
if ( style_ == SM_SKELETON ) {
|
|
glEnable(GL_COLOR_MATERIAL);
|
|
glColor3f(0.7f,0.7f,0.7f);
|
|
gluSphere(sphere_,shrink_fac,50,50);
|
|
glDisable(GL_COLOR_MATERIAL);
|
|
}
|
|
glDisable(GL_LIGHTING);
|
|
if ( !initialized_ ) const_cast<Unit_sphere*>(this)->construct();
|
|
if ( style_ == SM_FACES || style_ == SM_TRIANGULATION ) {
|
|
glEnable(GL_LIGHTING);
|
|
glCallList(sphere_list_+1); // triangle list
|
|
glDisable(GL_LIGHTING);
|
|
}
|
|
if ( style_ == SM_TRIANGULATION ) {
|
|
glCallList(sphere_list_+2); // triangle edge list
|
|
}
|
|
|
|
if ( style_ != SM_TRIANGULATION ) {
|
|
glCallList(sphere_list_);
|
|
}
|
|
if ( switches[0] ) glCallList(sphere_list_+3);
|
|
if ( switches[1] ) glCallList(sphere_list_+4);
|
|
}
|
|
|
|
|
|
};
|
|
|
|
template <typename Map_>
|
|
class SM_BooleColor
|
|
{
|
|
typedef typename Map_::SVertex_const_handle SVertex_const_handle;
|
|
typedef typename Map_::SHalfedge_const_handle SHalfedge_const_handle;
|
|
typedef typename Map_::SHalfloop_const_handle SHalfloop_const_handle;
|
|
typedef typename Map_::SFace_const_handle SFace_const_handle;
|
|
typedef typename Map_::Mark Mark;
|
|
public:
|
|
Color color(SVertex_const_handle, Mark m) const
|
|
{ return ( m ? CGAL::black() : CGAL::white() ); }
|
|
Color color(SHalfedge_const_handle, Mark m) const
|
|
{ return ( m ? CGAL::black() : CGAL::white() ); }
|
|
Color color(SHalfloop_const_handle, Mark m) const
|
|
{ return ( m ? CGAL::black() : CGAL::white() ); }
|
|
Color color(SFace_const_handle, Mark m) const
|
|
{ return ( m ? CGAL_NEF_DGREY : CGAL_NEF_LGREY ); }
|
|
};
|
|
|
|
template <typename Nef_polyhedron>
|
|
class NefS2_to_UnitSphere
|
|
{
|
|
typedef typename Nef_polyhedron::Sphere_map Sphere_map;
|
|
typedef typename Nef_polyhedron::Const_decorator SM_const_decorator;
|
|
typedef CGAL::OGL::SM_BooleColor<Sphere_map> Color_;
|
|
typedef typename Sphere_map::Sphere_kernel Sphere_kernel;
|
|
typedef SM_decorator<Sphere_map> Decorator;
|
|
typedef CGAL::SM_triangulator<Decorator> Base;
|
|
|
|
typedef typename Sphere_map::SVertex_const_handle SVertex_const_handle;
|
|
typedef typename Sphere_map::SHalfedge_const_handle SHalfedge_const_handle;
|
|
typedef typename Sphere_map::SFace_const_handle SFace_const_handle;
|
|
typedef typename Sphere_map::SVertex_const_iterator SVertex_const_iterator;
|
|
typedef typename Sphere_map::SHalfedge_const_iterator SHalfedge_const_iterator;
|
|
typedef typename Sphere_map::SFace_const_iterator SFace_const_iterator;
|
|
typedef typename Sphere_map::Mark Mark;
|
|
|
|
typedef typename Sphere_kernel::Sphere_point Sphere_point;
|
|
typedef typename Sphere_kernel::Sphere_segment Sphere_segment;
|
|
typedef typename Sphere_kernel::Sphere_circle Sphere_circle;
|
|
typedef typename Sphere_kernel::Sphere_triangle Sphere_triangle;
|
|
|
|
typedef Color_ Color_objects;
|
|
|
|
public:
|
|
static CGAL::OGL::Unit_sphere convert(const SM_const_decorator& E_,
|
|
const Color_objects& CO_ = Color_objects()) {
|
|
Sphere_map MT_(true);
|
|
Base T_(&MT_, &E_);
|
|
CGAL::OGL::Unit_sphere S_;
|
|
|
|
T_.triangulate();
|
|
|
|
SHalfedge_const_iterator e;
|
|
CGAL_forall_sedges(e,E_) {
|
|
if ( e->source() == e->twin()->source() ) {
|
|
S_.push_back(e->circle(), CO_.color(e,e->mark()));} else {
|
|
S_.push_back(Sphere_segment(e->source()->point(),
|
|
e->twin()->source()->point(),
|
|
e->circle()),CO_.color(e,e->mark()));
|
|
}
|
|
}
|
|
// draw sphere circles underlying loops of E_:
|
|
|
|
if ( E_.has_shalfloop() )
|
|
S_.push_back(
|
|
E_.shalfloop()->circle(),
|
|
CO_.color(E_.shalfloop(),E_.shalfloop()->mark()));
|
|
|
|
// draw points underlying vertices of E_:
|
|
SVertex_const_iterator v;
|
|
CGAL_forall_svertices(v,E_)
|
|
S_.push_back(v->point(),CO_.color(v,v->mark()));
|
|
|
|
Unique_hash_map<SHalfedge_const_iterator,bool> Done(false);
|
|
CGAL_forall_shalfedges(e,T_) {
|
|
if ( Done[e] ) continue;
|
|
SHalfedge_const_handle en(e->snext()),enn(en->snext());
|
|
CGAL_NEF_TRACEV(T_.incident_triangle(e));
|
|
CGAL_NEF_TRACEN(T_.incident_mark(e)<<T_.incident_mark(en)<<T_.incident_mark(enn));
|
|
CGAL_assertion(T_.incident_mark(e)==T_.incident_mark(en) &&
|
|
T_.incident_mark(en)==T_.incident_mark(enn));
|
|
Mark m = T_.incident_mark(e);
|
|
Sphere_triangle t = T_.incident_triangle(e);
|
|
S_.push_back(t, (m ? CGAL_NEF_DGREY : CGAL_NEF_LGREY) );
|
|
Done[e]=Done[en]=Done[enn]=true;
|
|
}
|
|
|
|
Done.clear(false);
|
|
CGAL_forall_shalfedges(e,T_) {
|
|
if ( Done[e] ) continue;
|
|
S_.push_back_triangle_edge(Sphere_segment(e->source()->point(),
|
|
e->twin()->source()->point(),
|
|
e->circle()));
|
|
Done[e]=Done[e->twin()]=true;
|
|
}
|
|
return S_;
|
|
}
|
|
};
|
|
|
|
} // OGL
|
|
} //namespace CGAL
|
|
|
|
|
|
|
|
template <class R>
|
|
std::ostream& operator<<(std::ostream& os,
|
|
const CGAL::OGL::Sphere_segment<R>& s)
|
|
{ CGAL::OGL::VSegment::const_iterator it;
|
|
os << s.original() << " ";
|
|
for (it = s.begin(); it != s.end(); ++it)
|
|
os << *it;
|
|
return os;
|
|
}
|
|
|
|
template <class R>
|
|
std::ostream& operator<<(std::ostream& os,
|
|
const CGAL::OGL::Sphere_circle<R>& s)
|
|
{ CGAL::OGL::VSegment::const_iterator it;
|
|
os << s.original() << " ";
|
|
for (it = s.begin(); it != s.end(); ++it)
|
|
os << *it;
|
|
return os;
|
|
}
|
|
|
|
|
|
|
|
template <class R>
|
|
std::ostream& operator<<(std::ostream& os,
|
|
const CGAL::OGL::Sphere_point<R>& p)
|
|
{ os << p.original() << CGAL::OGL::VPoint(p); return os; }
|
|
|
|
|
|
#endif //CGAL_SPHERE_GEOMETRY_OGL_H
|