added to project

This commit is contained in:
Michael Seel 2001-11-20 12:40:20 +00:00
parent 41a65c4f8a
commit 685c90d5aa
37 changed files with 8291 additions and 0 deletions

4
Packages/Nef_S2/TODO Normal file
View File

@ -0,0 +1,4 @@
Possible Improvements for future releases are
1) introduce clean spherical kernel trais

View File

@ -0,0 +1,6 @@
Nef_S2 Package: Release changes
----------------------------------------------------------------------
0.9 (20 Nov 2001)
initial release

View File

@ -0,0 +1,4 @@
nef-demo -n 4 -r 3
nef-demo -n 8 -r 1
nef-demo

View File

@ -0,0 +1,95 @@
#include <CGAL/basic.h>
#include <CGAL/Homogeneous.h>
#include <CGAL/leda_integer.h>
#include <CGAL/random_selection.h>
#include <CGAL/point_generators_3.h>
#include <CGAL/Nef_polyhedron_S2.h>
#include <CGAL/IO/Nef_polyhedron_S2_OGLUT_stream.h>
#include <LEDA/param_handler.h>
typedef leda_integer NT;
typedef CGAL::Homogeneous<NT> Kernel;
typedef Kernel::Point_3 Point_3;
typedef Kernel::Plane_3 Plane_3;
typedef CGAL::Nef_polyhedron_S2<Kernel> Nef_polyhedron_S2;
typedef Nef_polyhedron_S2::Sphere_point Sphere_point;
typedef Nef_polyhedron_S2::Sphere_segment Sphere_segment;
typedef Nef_polyhedron_S2::Sphere_circle Sphere_circle;
typedef Nef_polyhedron_S2::Explorer Explorer;
typedef CGAL::Creator_uniform_3<NT,Point_3> Creator;
typedef CGAL::Random_points_in_cube_3<Point_3,Creator> Point_source;
int main(int argc, char **argv)
{
CGAL::set_pretty_mode ( std::cerr );
SETDTHREAD(911);
// Sphere_geometry 11
// Sphere_geometry_OGL 13
// Segment_overlay 23
// SM_overlayer 53
Point_3 p(0,0,0);
int seed;
int n;
leda_string input_file;
leda_param_handler H(argc,argv,".nd",false);
H.add_parameter("random_seed:-r:int:0");
H.add_parameter("number_of_lines:-n:int:10");
H.add_parameter("file_of_segments:-i:string:");
leda_param_handler::init_all();
H.get_parameter("-r",seed);
H.get_parameter("-n",n);
H.get_parameter("-i",input_file);
CGAL_assertion_msg(n>0,"-n value must be postive.");
srand(seed);
std::list<Sphere_circle> L;
if ( input_file == "" ) { // create random input:
Point_source S(5);
Point_3 ph;
Point_3 o(0,0,0);
while ( n-- > 0 ) {
do { ph = *S++; } while ( ph == o );
Plane_3 h(o,(ph-CGAL::ORIGIN).direction());
L.push_back( Sphere_circle(h) );
}
} else { // read input from file:
std::ifstream input(input_file);
CGAL_assertion_msg(input,"no input log.");
Sphere_circle c;
while ( input >> c ) L.push_back(c);
}
// output log:
std::ofstream output("nef-demo.log");
std::list<Sphere_circle>::iterator it;
CGAL_forall_iterators(it,L) output << *it << ' ';
output << std::endl;
output.close();
// partition input into two lists
std::list<Sphere_circle> L1,L2;
int b=0;
CGAL_forall_iterators(it,L) {
if ( b == 0 ) L1.push_back(*it);
else L2.push_back(*it);
b = 1-b;
}
Nef_polyhedron_S2 N1(L1.begin(), L1.end(), 0.5);
Nef_polyhedron_S2 N2(L2.begin(), L2.end(), 0.5);
Nef_polyhedron_S2 N3 = N1 * N2;
Nef_polyhedron_S2 N4 = N1 ^ N2;
//std::cerr << N1 << N2 << N3 << N4 << std::endl;
CGAL::ogl << N1 << N2 << N3 << N4;
CGAL::ogl << "Nef Polyhedron 1" << "Nef Polyhedron 2"
<< "Intersection" << "Symmetric Difference";
CGAL::ogl.display();
return 0;
}

View File

@ -0,0 +1,80 @@
#include <LOCAL/CGALH3.h>
#include <CGAL/random_selection.h>
#include <CGAL/point_generators_3.h>
#include "Nef_polyhedron_S2.h"
#include "Nef_S2/Nef_polyhedron_S2_OGLUT_stream.h"
#include <LEDA/param_handler.h>
//#define TRACEV(t) std::cerr << #t << " = " << t <<std::endl
typedef CGAL::Nef_polyhedron_S2<HKernel> Nef_polyhedron_S2;
typedef Nef_polyhedron_S2::Sphere_point Sphere_point;
typedef Nef_polyhedron_S2::Sphere_segment Sphere_segment;
typedef Nef_polyhedron_S2::Sphere_circle Sphere_circle;
typedef Nef_polyhedron_S2::Explorer Explorer;
typedef CGAL::Creator_uniform_3<RT,Point_3> Creator;
typedef CGAL::Random_points_in_cube_3<Point_3,Creator> Point_source;
int main(int argc, char **argv)
{
CGAL::set_pretty_mode ( std::cerr );
SETDTHREAD(911);
// Sphere_geometry 11
// Sphere_geometry_OGL 13
// Segment_overlay 23
// SM_overlayer 53
Point_3 p(0,0,0);
leda_string input_file;
leda_param_handler H(argc,argv,".nd",false);
H.add_parameter("file_of_circles:-i:string:");
leda_param_handler::init_all();
H.get_parameter("-i",input_file);
std::list<Sphere_circle> L;
if ( input_file == "" ) { // create random input:
L.push_back( Sphere_circle(1,0,0) );
L.push_back( Sphere_circle(0,1,0) );
L.push_back( Sphere_circle(0,0,1) );
L.push_back( Sphere_circle(1,1,1) );
L.push_back( Sphere_circle(-1,1,1) );
L.push_back( Sphere_circle(1,-1,1) );
L.push_back( Sphere_circle(1,1,-1) );
} else { // read input from file:
std::ifstream input(input_file);
CGAL_assertion_msg(input,"no input log.");
Sphere_circle c;
while ( input >> c ) L.push_back(c);
}
// output log:
std::ofstream output("nef2.log");
std::list<Sphere_circle>::iterator it;
CGAL_forall_iterators(it,L) output << *it << ' ';
output << std::endl;
output.close();
// partition input into two lists
Nef_polyhedron_S2 Ni, N;
bool first(false);
CGAL_forall_iterators(it,L) {
if ( first ) {
N = Nef_polyhedron_S2(*it);
first = false;
} else {
Ni = Nef_polyhedron_S2(*it);
N = N ^ Ni;
}
}
//std::cerr << Ni << N std::endl;
CGAL::ogl << N;
CGAL::ogl << "Symmetric Difference";
CGAL::ogl.display();
return 0;
}

View File

@ -0,0 +1,109 @@
#include <LOCAL/CGALH3.h>
#include <CGAL/copy_n.h>
#include <CGAL/random_selection.h>
#include <CGAL/point_generators_3.h>
#include <LEDA/param_handler.h>
#include <CGAL/Nef_S2/Sphere_map.h>
#include <CGAL/Nef_S2/SM_decorator.h>
#include <CGAL/Nef_S2/SM_io_parser.h>
#include "SM_overlayer.h"
typedef CGAL::Sphere_geometry<HKernel> SKernel;
typedef CGAL::Sphere_map<SKernel> Sphere_map;
typedef Sphere_map::Vertex_handle Vertex_handle;
typedef Sphere_map::Halfedge_handle Halfedge_handle;
typedef Sphere_map::Face_handle Face_handle;
typedef CGAL::SM_decorator<Sphere_map,SKernel> SM_decorator;
typedef CGAL::SM_overlayer<SM_decorator> SM_overlayer;
typedef CGAL::Creator_uniform_3<RT,Point_3> Creator;
typedef CGAL::Random_points_in_cube_3<Point_3,Creator> Point_source;
typedef SKernel::Sphere_point SPoint;
typedef SKernel::Sphere_segment SSegment;
struct OR {
bool operator()(bool b1, bool b2) const
{ return b1||b2; }
};
int main(int argc, char **argv)
{
CGAL::set_pretty_mode ( std::cerr );
SETDTHREAD(911);
// Sphere_geometry 11
// Sphere_geometry_OGL 13
// Segment_overlay 23
// SM_overlayer 53
Point_3 p(0,0,0);
Sphere_map E1,E2,E3;
SM_decorator D1(E1),D2(E2),D3(E3);
SM_overlayer O1(D1),O2(D2),O3(D3);
int n;
leda_string input_file;
leda_param_handler H(argc,argv,".sg",false);
H.add_parameter("number_of_lines:-n:int:10");
H.add_parameter("file_of_segments:-i:string:");
leda_param_handler::init_all();
H.get_parameter("-n",n);
H.get_parameter("-i",input_file);
CGAL_assertion_msg(n>0,"-n value must be postive.");
std::list<SSegment> L;
if ( input_file == "" ) {
Point_source S(5);
Point_3 p1,p2,ph;
Point_3 o(0,0,0);
while ( n-- > 0 ) {
do { ph = *S++; } while ( ph == o );
Plane_3 h(o,(ph-CGAL::ORIGIN).direction());
do { p1 = *S++; }
while ( p1 == o || h.projection(p1) == o );
do { p2 = *S++; }
while ( p2 == o || h.projection(p2) == o );
SPoint p3(h.projection(p1)),p4(h.projection(p2));
int which = CGAL::default_random.get_int(0,3);
if ( p3 == p4 ) which = 3;
if ( p3 == p4.opposite() ) which = 2;
switch ( which ) {
case 0: // short
L.push_back( SSegment(p3,p4,true) ); break;
case 1: // long
L.push_back( SSegment(p3,p4,false) ); break;
case 2: // halfcircle
L.push_back( SSegment(p3,p3.opposite(),h) ); break;
case 3: // trivial
L.push_back( SSegment(p3,p3,h) ); break;
}
}
} else {
std::ifstream input(input_file);
CGAL_assertion_msg(input,"no input log.");
SSegment s;
while ( input >> s ) L.push_back(s);
}
std::ofstream output("smo-demo.log");
std::list<SSegment>::iterator it;
forall_iterators(it,L) output << *it;
output << std::endl;
output.close();
std::list<SSegment> L1,L2;
int b=0;
forall_iterators(it,L) {
if ( b == 0 ) L1.push_back(*it);
else L2.push_back(*it);
b = 1-b;
}
O1.create_from_segments(L1.begin(),L1.end());
O1.simplify(); // O1.dump(std::cerr);
O2.create_from_segments(L2.begin(),L2.end());
O2.simplify(); // O2.dump(std::cerr);
O3.subdivide(E1,E2);
O3.select(OR());
O3.simplify(); // O3.dump(std::cerr);
return 0;
}

View File

@ -0,0 +1,114 @@
#include <CGAL/leda_integer.h>
#include <CGAL/Homogeneous.h>
#include <CGAL/copy_n.h>
#include <CGAL/random_selection.h>
#include <CGAL/point_generators_3.h>
#include <LEDA/param_handler.h>
#include <LEDA/random.h>
#include <CGAL/Nef_S2/leda_sphere_map.h>
#include <CGAL/Nef_S2/Sphere_geometry_OGL.h>
typedef leda_integer RT;
typedef CGAL::Homogeneous<RT> HKernel;
typedef CGAL::Sphere_point<HKernel> SPoint;
typedef CGAL::Sphere_segment<HKernel> SSegment;
typedef CGAL::Plane_3<HKernel> Plane;
typedef CGAL::Point_3<HKernel> Point;
typedef CGAL::Direction_3<HKernel> Direction;
typedef CGAL::Creator_uniform_3<leda_integer,Point> Creator;
typedef CGAL::Random_points_in_cube_3<Point,Creator> Point_source;
int main(int argc, char **argv)
{
CGAL::set_pretty_mode ( std::cerr );
SETDTHREAD(101); //(11*23*31);
// Sphere_geometry 11
// Sphere_geometry_OGL 13
// PM_segment_overlay 23
// leda_sphere_map 31
int n;
leda_string input_file;
leda_param_handler H(argc,argv,".sg",false);
H.add_parameter("number_of_lines:-n:int:10");
H.add_parameter("file_of_segments:-i:string:");
leda_param_handler::init_all();
H.get_parameter("-n",n);
H.get_parameter("-i",input_file);
CGAL_assertion_msg(n>0,"-n value must be postive.");
std::list<SSegment> L;
if ( input_file == "" ) {
Point_source S(5);
Point p1,p2,ph;
Point o(0,0,0);
while ( n-->0 ) {
do { ph = *S++; } while ( ph == o );
Plane h(o,(ph-CGAL::ORIGIN).direction());
do { p1 = *S++; }
while ( p1 == o || h.projection(p1) == o );
do { p2 = *S++; }
while ( p2 == o || h.projection(p2) == o );
SPoint p3(h.projection(p1)),p4(h.projection(p2));
int which = CGAL::default_random.get_int(0,3);
if ( p3 == p4 ) which = 3;
if ( p3 == p4.opposite() ) which = 2;
switch ( which ) {
case 0: // short
L.push_back( SSegment(p3,p4,true) ); break;
case 1: // long
L.push_back( SSegment(p3,p4,false) ); break;
case 2: // halfcircle
L.push_back( SSegment(p3,p3.opposite(),h) ); break;
case 3: // trivial
L.push_back( SSegment(p3,p3,h) ); break;
}
}
} else {
std::ifstream input(input_file);
CGAL_assertion_msg(input,"no input log.");
SSegment s;
while ( input >> s ) L.push_back(s);
}
std::ofstream output("sg-demo.log");
std::list<SSegment>::iterator it;
CGAL_forall_iterators(it,L) output << *it;
output << std::endl;
output.close();
leda_sphere_map_overlayer<HKernel> SMO;
SMO.subdivide(L.begin(),L.end());
//SMO.dump(std::cerr);
CGAL::OGL::add_sphere();
CGAL::OGL::add_sphere();
CGAL::OGL::Unit_sphere& S1(*CGAL::OGL::spheres_.begin());
CGAL::OGL::Unit_sphere& S2(CGAL::OGL::spheres_.back());
CGAL_forall_iterators(it,L) {
S1.push_back(*it);
S1.push_back(it->source(),CGAL::BLUE);
S1.push_back(it->target(),CGAL::BLUE);
}
leda_edge e;
forall_edges(e,SMO.sphere_map()) {
SSegment s(SMO.sphere_map()[source(e)],
SMO.sphere_map()[target(e)]);
S2.push_back(s);
}
leda_node v;
forall_nodes(v,SMO.sphere_map()) {
SPoint p(SMO.sphere_map()[v]);
S2.push_back(p);
}
CGAL::OGL::titles_.push_back(std::string("Input segments"));
CGAL::OGL::titles_.push_back(std::string("Output map"));
CGAL::OGL::start_viewer();
return 0;
}

View File

@ -0,0 +1,74 @@
# Created by the script create_makefile
# This is the makefile for compiling a CGAL application.
#---------------------------------------------------------------------#
# OpenGL und GLUT settings
# one needs the root directories for the extended X libs and
# the OpenGL package including a GLUT extension
#
# Please adapt the following paths:
#---------------------------------------------------------------------#
X_DIR = /opt/xfree86-4.0.1
X_GLUTDIR = /HPS/opt/pckg/glut
TESTSUITE_LDFLAGS = \
-L$(X_DIR)/lib -L$(X_GLUTDIR)/lib \
-R$(X_DIR)/lib -R$(X_GLUTDIR)/lib \
-lGL -lGLU -lglut -lXext -lXmu
#---------------------------------------------------------------------#
# include platform specific settings
#---------------------------------------------------------------------#
# Choose the right include file from the <cgalroot>/make directory.
# CGAL_MAKEFILE = ENTER_YOUR_INCLUDE_MAKEFILE_HERE
include $(CGAL_MAKEFILE)
#---------------------------------------------------------------------#
# compiler flags
#---------------------------------------------------------------------#
CXXFLAGS = \
$(TESTSUITE_CXXFLAGS) \
$(EXTRA_FLAGS) \
-Iinclude -I$(X_DIR)/include -I$(X_GLUTDIR)/include\
$(CGAL_CXXFLAGS) \
$(LONG_NAME_PROBLEM_CXXFLAGS) \
$(DEBUG_OPT)
#---------------------------------------------------------------------#
# linker flags
#---------------------------------------------------------------------#
LIBPATH = \
$(TESTSUITE_LIBPATH) \
$(CGAL_LIBPATH)
LDFLAGS = \
$(TESTSUITE_LDFLAGS) \
$(LONG_NAME_PROBLEM_LDFLAGS) \
$(CGAL_WINDOW_LDFLAGS)
#---------------------------------------------------------------------#
# target entries
#---------------------------------------------------------------------#
all: \
Nef_polyhedron_S2-demo Sphere_geometry-demo
Nef_polyhedron_S2-demo$(EXE_EXT): Nef_polyhedron_S2-demo$(OBJ_EXT)
$(CGAL_CXX) $(LIBPATH) $(EXE_OPT)Nef_polyhedron_S2-demo Nef_polyhedron_S2-demo$(OBJ_EXT) $(LDFLAGS)
Sphere_geometry-demo$(EXE_EXT): Sphere_geometry-demo$(OBJ_EXT)
$(CGAL_CXX) $(LIBPATH) $(EXE_OPT)Sphere_geometry-demo Sphere_geometry-demo$(OBJ_EXT) $(LDFLAGS)
clean: \
Nef_polyhedron_S2-demo.clean Sphere_geometry-demo.clean
#---------------------------------------------------------------------#
# suffix rules
#---------------------------------------------------------------------#
.C$(OBJ_EXT):
$(CGAL_CXX) $(CXXFLAGS) $(OBJ_OPT) $<

View File

@ -0,0 +1 @@
Nef polyhedra in the plane

View File

@ -0,0 +1,2 @@
TODO
noweb

View File

@ -0,0 +1,69 @@
// ============================================================================
//
// Copyright (c) 1997-2000 The CGAL Consortium
//
// This software and related documentation is part of an INTERNAL release
// of the Computational Geometry Algorithms Library (CGAL). It is not
// intended for general use.
//
// ----------------------------------------------------------------------------
//
// release : $CGAL_Revision$
// release_date : $CGAL_Date$
//
// file : include/CGAL/IO/Nef_polyhedron_S2_OGLUT_stream.h
// package : Nef_S2
// chapter : Nef Polyhedra
//
// revision : $Revision$
// revision_date : $Date$
//
// author(s) : Michael Seel <seel@mpi-sb.mpg.de>
// maintainer : Michael Seel <seel@mpi-sb.mpg.de>
// coordinator : Michael Seel <seel@mpi-sb.mpg.de>
//
// ============================================================================
#ifndef NEF_POLYHEDRON_S2_OGLUT_STREAM_H
#define NEF_POLYHEDRON_S2_OGLUT_STREAM_H
#include <CGAL/Nef_polyhedron_S2.h>
#include <CGAL/Nef_S2/SM_visualizor.h>
#include <string>
CGAL_BEGIN_NAMESPACE
struct OGLUT_stream { // dummy class
OGLUT_stream() {}
void display() { CGAL::OGL::start_viewer(); }
};
static OGLUT_stream ogl;
template <typename T>
CGAL::OGLUT_stream& operator<<(CGAL::OGLUT_stream& ogls,
const Nef_polyhedron_S2<T>& P)
{
typedef Nef_polyhedron_S2<T> Polyhedron;
typedef typename Polyhedron::Sphere_map Sphere_map;
typedef typename Polyhedron::Sphere_kernel Sphere_kernel;
typedef CGAL::SM_visualizor<Sphere_map,Sphere_kernel> Visualizor;
CGAL::OGL::add_sphere();
Visualizor V(P.sphere_map(),CGAL::OGL::spheres_.back()); V.draw_map();
// CGAL::OGL::spheres_.back().print();
return ogls;
}
static CGAL::OGLUT_stream& operator<<(CGAL::OGLUT_stream& ogls,
const char* s)
{
CGAL::OGL::titles_.push_back(std::string(s));
return ogls;
}
CGAL_END_NAMESPACE
#endif // NEF_POLYHEDRON_S2_OGLUT_STREAM_H

View File

@ -0,0 +1,34 @@
#ifndef CGAL_GENERIC_HANDLE_MAP_H
#define CGAL_GENERIC_HANDLE_MAP_H
#include <CGAL/Unique_hash_map.h>
CGAL_BEGIN_NAMESPACE
struct Void_handle_hash_function {
std::size_t operator() (void* h) const {
return std::size_t(h);
}
};
template <class I>
class Generic_handle_map : public
Unique_hash_map<void*,I,Void_handle_hash_function>
{ typedef Unique_hash_map<void*,I,Void_handle_hash_function> Base;
public:
Generic_handle_map() : Base() {}
Generic_handle_map(I i) : Base(i) {}
template <class H>
const I& operator[](H h) const
{ return Base::operator[](&*h); }
template <class H>
I& operator[](H h)
{ return Base::operator[](&*h); }
};
CGAL_END_NAMESPACE
#endif //CGAL_GENERIC_HANDLE_MAP_H

View File

@ -0,0 +1,238 @@
#ifndef CGAL_SM_CHECKER_H
#define CGAL_SM_CHECKER_H
#include <CGAL/basic.h>
#include <CGAL/Nef_S2/SM_const_decorator.h>
#define USING(t) typedef typename Base::t t
CGAL_BEGIN_NAMESPACE
/*{\Moptions outfile=SM_checker.man }*/
/*{\Manpage {SM_checker}{PMCDEC,GEOM}{Plane map checking}{}}*/
/*{\Mdefinition An instance |\Mvar| of the data type |\Mname| is a
decorator to check the structure of a plane map. It is generic with
respect to two template concepts. |PMCDEC| has to be a decorator
model of our |SM_const_decorator| concept. |GEOM| has to be a model of
our geometry kernel concept.}*/
/*{\Mgeneralization SM_const_decorator}*/
template <typename PMCDEC, typename GEOM>
class SM_checker : public PMCDEC
{ typedef PMCDEC Base;
const GEOM& K;
public:
/*{\Mtypes 3}*/
typedef PMCDEC SM_const_decorator;
/*{\Mtypemember equals |PMCDEC|. Add link to PMCDEC concept.}*/
typedef typename PMCDEC::Plane_map Plane_map;
/*{\Mtypemember equals |PMCDEC::Plane_map|, the underlying plane map type.}*/
typedef GEOM Geometry;
/*{\Mtypemember equals |GEOM|. Add link to GEOM concept.\\
\precond |Geometry::Point_2| equals |Plane_map::Point|. }*/
typedef typename GEOM::Point_2 Point;
typedef typename GEOM::Direction_2 Direction;
USING(Vertex_const_handle);
USING(SEdge_handle);
USING(Vertex_const_iterator);
USING(Halfedge_const_iterator);
USING(Halfedge_around_vertex_const_circulator);
USING(Halfedge_around_face_const_circulator);
/*{\Mtext Iterators, handles, and circulators are inherited from
|SM_const_decorator|.}*/
/*{\Mcreation 3}*/
SM_checker(Plane_map& P, const Geometry& k = Geometry()) :
Base(P), K(k) {}
/*{\Mcreate constructs a plane map checker working on |P| with
geometric predicates used from |k|.}*/
SM_checker(const Base& D, const Geometry& k = Geometry()) :
Base(D), K(k) {}
/*{\Moperations 2 }*/
Direction direction(Halfedge_const_handle e) const
{ return K.construct_direction(
point(source(e)),point(target(e))); }
bool is_forward(Halfedge_const_handle e) const
{ return K.compare_xy(point(source(e)),point(target(e)))<0; }
void check_order_preserving_embedding(Vertex_const_handle v) const;
/*{\Mop checks if the embedding of the targets of the edges in
the adjacency list |A(v)| is counter-clockwise order-preserving with
respect to the order of the edges in |A(v)|.}*/
void check_order_preserving_embedding() const;
/*{\Mop checks if the embedding of all vertices of |P| is
counter-clockwise order-preserving with respect to the adjacency
list ordering of all vertices.}*/
void check_forward_prefix_condition(Vertex_const_handle v) const;
/*{\Mop checks the forward prefix property of the adjacency
list of |v|.}*/
Halfedge_const_iterator
check_boundary_is_clockwise_weakly_polygon() const;
/*{\Mop checks if the outer face cycle of |P| is a clockwise weakly polygon and
returns a halfedge on the boundary. \precond |P| is a connected graph.
}*/
void check_is_triangulation() const;
/*{\Mop checks if |P| is a triangulation.}*/
}; // SM_checker<PMCDEC,GEOM>
template <typename PMCDEC, typename GEOM>
void SM_checker<PMCDEC,GEOM>::
check_order_preserving_embedding(Vertex_const_handle v) const
{
std::ostrstream error_status;
CGAL::set_pretty_mode ( error_status );
Halfedge_const_handle ef = first_out_edge(v) ,e=ef,en,enn;
error_status << "check_order_preserving_embedding\n";
error_status << "vertex " << PV(v) << endl;
if ( e != Halfedge_const_handle() ) {
while ( true ) {
en = cyclic_adj_succ(e);
enn = cyclic_adj_succ(en);
if (en == ef) break;
error_status << " -> " << point(target(e));
error_status << " " << point(target(en)) << " ";
error_status << " " << point(target(enn)) << endl;
if ( !K.strictly_ordered_ccw(direction(e),direction(en),
direction(enn)) ||
!K.strictly_ordered_ccw(direction(e),direction(en),
direction(ef)) ) {
error_status << "ccw order violate!" << endl << '\0';
CGAL_assertion_msg(0,error_status.str());
}
e = en;
}
}
error_status.freeze(0);
}
template <typename PMCDEC, typename GEOM>
void SM_checker<PMCDEC,GEOM>::
check_forward_prefix_condition(Vertex_const_handle v) const
{ Halfedge_const_handle ef = first_out_edge(v);
if ( ef == Halfedge_const_handle() ) return;
Halfedge_const_handle el = cyclic_adj_pred(ef);
bool is_leftturn = K.leftturn(point(v),
point(target(ef)),
point(target(el)));
bool el_forward = is_forward(el);
bool ef_forward = is_forward(ef);
CGAL_assertion_msg( (ef == el ||
ef_forward && !el_forward ||
ef_forward && el_forward && is_leftturn ||
!ef_forward && !el_forward && is_leftturn) ,
"check_forward_prefix_condition: first backward, last forward\n");
}
template <typename PMCDEC, typename GEOM>
void SM_checker<PMCDEC,GEOM>::
check_order_preserving_embedding() const
{
Vertex_const_iterator vit;
for (vit = vertices_begin(); vit != vertices_end(); ++vit) {
check_order_preserving_embedding(vit);
check_forward_prefix_condition(vit);
}
}
template <typename PMCDEC, typename GEOM>
typename SM_checker<PMCDEC,GEOM>::Halfedge_const_iterator
SM_checker<PMCDEC,GEOM>::
check_boundary_is_clockwise_weakly_polygon() const
{
Vertex_const_iterator vit, v_min;
for (vit = v_min = vertices_begin() ; vit != vertices_end(); ++vit)
if ( K.compare_xy(point(vit), point(v_min))<0 ) v_min = vit;
CGAL_assertion_msg(!is_isolated(v_min),"Minimal vertex not connected.");
Sphere_point p_min = point(v_min);
// determine boundary edge incident to v_min:
Halfedge_const_handle e_boundary_at_v_min = first_out_edge(v_min);
// all out edges are forward oriented due to minimality
Halfedge_around_vertex_const_circulator
hvit(e_boundary_at_v_min), hend(hvit);
do {
--hvit;
Sphere_point p1 = point(target(e_boundary_at_v_min));
Sphere_point p2 = point(target(hvit));
if ( K.orientation(p_min,p1,p2) > 0 ) { // leftturn
e_boundary_at_v_min = hvit;
break;
}
} while (hvit != hend);
// now e_boundary_at_v_min is highest starting edge in bundle!!
int winding_around_globally=0;
Halfedge_around_face_const_circulator
hfit(e_boundary_at_v_min),hstart(hfit);
Halfedge_const_handle e_prev = next(e_boundary_at_v_min);
/* we run counterclockwise around the outer face cycle and allow only
position where the direction vector of an edge gets smaller again */
Direction d_prev = direction(e_prev);
CGAL_For_all_backwards(hstart,hfit) {
Direction d_curr = direction(hfit);
if ( d_curr < d_prev ) ++winding_around_globally;
d_prev = d_curr;
}
CGAL_assertion(winding_around_globally == 1);
return e_boundary_at_v_min;
}
template <typename PMCDEC, typename GEOM>
void SM_checker<PMCDEC,GEOM>::
check_is_triangulation() const
{
Halfedge_const_iterator eb;
check_integrity_and_topological_planarity(false);
CGAL_assertion(number_of_connected_components() == 1);
check_order_preserving_embedding();
eb = check_boundary_is_clockwise_weakly_polygon();
CGAL::Hash_map< Halfedge_const_iterator, bool> on_boundary(false);
Halfedge_around_face_const_circulator hit(eb), hend(hit);
std::ostrstream error_status;
CGAL::set_pretty_mode ( error_status );
error_status << "check_is_triangulation\n";
error_status << "on boundary:\n";
CGAL_For_all(hit,hend) {
error_status << " " << PE(hit) << endl;
on_boundary[hit]=true;
}
Halfedge_const_iterator eit;
for( eit = halfedges_begin(); eit != halfedges_end(); ++eit) {
if (on_boundary[eit]) continue;
hit = hend = eit;
int edges_in_face_cycle=0;
CGAL_For_all(hit,hend) {
error_status << PE(hit);
++edges_in_face_cycle;
}
CGAL_assertion_msg(edges_in_face_cycle==3,error_status.str());
}
error_status.freeze(0);
}
\subsection{Plane map input and output}
The input and output is mainly triggered by an IO Decorator which
has the control over the IO format and does some basic parsing when
reading input.
CGAL_END_NAMESPACE
#undef USING
#endif // CGAL_SM_CHECKER_H

View File

@ -0,0 +1,546 @@
#ifndef CGAL_SM_CONST_DECORATOR_H
#define CGAL_SM_CONST_DECORATOR_H
#include <CGAL/basic.h>
#include <CGAL/circulator.h>
#include <CGAL/Unique_hash_map.h>
#include <CGAL/Nef_2/Object_index.h>
#include <CGAL/Nef_S2/SM_iteration.h>
#include <string>
#include <list>
#include <strstream>
#undef _DEBUG
#define _DEBUG 127
#include <CGAL/Nef_S2/debug.h>
CGAL_BEGIN_NAMESPACE
template <typename Iter, typename Move>
class CircFromIt : public Iter {
// Ptr node; // The internal node ptr inherited from It.
typedef CircFromIt<Iter,Move> ThisClass;
public:
CircFromIt() : Iter(0) {}
CircFromIt(Iter i) : Iter(i) {}
// OPERATIONS Forward Category
// ---------------------------
bool operator==( CGAL_NULL_TYPE p ) const {
CGAL_assertion( p == NULL );
return Iter::operator==( Iter(NULL) );
}
bool operator!=( CGAL_NULL_TYPE p ) const {
return !(*this == p);
}
bool operator==( const ThisClass& i ) const {
return Iter::operator==(i);
}
bool operator!=( const ThisClass& i) const {
return !(*this == i);
}
ThisClass& operator++() {
Move move;
move.forward(*this);
return *this;
}
ThisClass operator++(int) {
CircFromIt tmp = *this;
++*this;
return tmp;
}
// OPERATIONS Bidirectional Category
// ---------------------------------
ThisClass& operator--() {
Move move;
move.backward(*this);
return *this;
}
ThisClass operator--(int) {
CircFromIt tmp = *this;
--*this;
return tmp;
}
};
template <typename Iter, typename Move>
inline CGAL::Circulator_tag
query_circulator_or_iterator(const CircFromIt<Iter,Move>& )
{ return CGAL::Circulator_tag(); }
template <typename HE>
class move_edge_around_vertex {
public:
void forward(HE& e) const { e = (e->prev_->twin_); }
void backward(HE& e) const { e = (e->twin_->next_); }
};
template <typename HE>
struct move_edge_around_face {
void forward(HE& e) const { e = (e->next_); }
void backward(HE& e) const { e = (e->prev_); }
};
template <typename Iter, typename Pnt>
class PntItFromVertIt : public Iter {
public:
typedef PntItFromVertIt<Iter,Pnt> Self;
typedef Iter Base;
typedef Pnt value_type;
typedef const Pnt* pointer;
typedef const Pnt& reference;
PntItFromVertIt() : Base() {}
PntItFromVertIt(Iter it) : Base(it) {}
PntItFromVertIt(const Self& it) : Base(it) {}
reference operator*() const
{ return Base::operator*().point(); }
pointer operator->() const
{ return &(operator*()); }
Self& operator++() { return (Self&)Base::operator++(); }
Self operator++(int) { Self tmp=*this; ++*this; return tmp; }
};
/*{\Moptions print_title=yes }*/
/*{\Moptions outfile=SM_decorator.man }*/
/*{\Manpage {SM_decorator}{HDS,Kernel}{Topological sphere map decorator}{D}}*/
template <typename Sphere_map_, typename Kernel_>
class SM_const_decorator
{ typedef SM_const_decorator<Sphere_map_,Kernel_> Self;
public:
/*{\Mdefinition ...}*/
/*{\Mtypes 5}*/
typedef Kernel_ Kernel;
typedef typename Kernel_::Sphere_point Sphere_point;
/*{\Mtypemember embedding vertices.}*/
typedef typename Kernel_::Sphere_segment Sphere_segment;
/*{\Mtypemember embedding edges.}*/
typedef typename Kernel_::Sphere_circle Sphere_circle;
/*{\Mtypemember embedding loops.}*/
typedef typename Sphere_map_::Mark Mark;
/*{\Mtypemember attributes of objects (vertices, edges, faces).}*/
typedef size_t Size_type;
/*{\Mtypemember size type.}*/
typedef void* GenPtr;
#define USING(t) typedef typename Sphere_map_::t t
USING(Vertex_const_handle);
USING(Vertex_const_iterator);
USING(Vertex);
USING(Halfedge);
USING(Halfedge_const_handle);
USING(Halfedge_const_iterator);
USING(Face);
USING(Face_const_handle);
USING(Face_const_iterator);
USING(Halfloop);
USING(Halfloop_const_handle);
USING(Halfloop_const_iterator);
#undef USING
/*{\Mtext Local types are handles, iterators and circulators of the
following kind: |Vertex_handle|, |Vertex_iterator|, |Halfedge_handle|,
|Halfedge_iterator|, |Halfloop_handle|, |Halfloop_iterator|,
|Face_handle|, |Face_iterator|. Additionally the following
circulators are defined.}*/
typedef CircFromIt<
Halfedge_const_iterator,
move_edge_around_vertex<Halfedge_const_iterator> >
Halfedge_around_vertex_const_circulator;
/*{\Mtypemember circulating the adjacency list of an vertex |v|.}*/
typedef CircFromIt<
Halfedge_const_iterator,
move_edge_around_face<Halfedge_const_iterator> >
Halfedge_around_face_const_circulator;
/*{\Mtypemember circulating the face cycle of an face |f|.}*/
typedef typename Sphere_map_::Face_cycle_const_iterator
Face_cycle_const_iterator;
/*{\Mtypemember iterating all face cycles of an face |f|.
The iterator has method |bool is_vertex()|, |bool is_halfedge()|,
|bool is_halfloop()|, and can be converted to the corresponding
handles |Vertex_const_handle|, |Halfedge_const_handle|, or
|Halfloop_const_handle|.}*/
protected:
Sphere_map_* psm_;
friend class SM_decorator<Sphere_map_,Kernel_>;
public:
/*{\Mcreation 3}*/
SM_const_decorator() : psm_(0) {}
SM_const_decorator(const Self& D) : psm_(D.psm_) {}
Self& operator=(const Self& D) { psm_=D.psm_; return *this; }
SM_const_decorator(const Sphere_map_& M) :
psm_(const_cast<Sphere_map_*>(&M)) {}
/*{\Mcreate constructs a plane map decorator exploring |M|.}*/
/*{\Moperations 4 4}*/
Vertex_const_handle source(Halfedge_const_handle e) const
/*{\Mop returns the source of |e|.}*/
{ return e->source_; }
Vertex_const_handle target(Halfedge_const_handle e) const
/*{\Mop returns the target of |e|.}*/
{ return e->twin_->source_; }
Halfedge_const_handle twin(Halfedge_const_handle e) const
/*{\Mop returns the twin of |e|.}*/
{ return e->twin_; }
Halfloop_const_handle twin(Halfloop_const_handle l) const
/*{\Mop returns the twin of |l|.}*/
{ return l->twin_; }
bool is_isolated(Vertex_const_handle v) const
/*{\Mop returns |true| when |v| is linked to the interior of a face.}*/
{ return (Halfedge_const_handle(v->edge_) == Halfedge_const_handle()); }
Halfedge_const_handle first_out_edge(Vertex_const_handle v) const
/*{\Mop returns one edge with source |v|. It's the starting point for
the circular iteration over the edges with source |v|.
\precond |!is_isolated(v)|.}*/
{ return v->edge_; }
Halfedge_const_handle last_out_edge(Vertex_const_handle v) const
/*{\Mop returns one edge with source |v|. \precond |!is_isolated(v)|.}*/
{ return cap(v->edge_); }
Halfedge_const_handle cyclic_adj_succ(Halfedge_const_handle e) const
/*{\Mop returns the edge after |e| in the cyclic ordered adjacency list of
|source(e)|.}*/
{ return e->prev_->twin_; }
Halfedge_const_handle cyclic_adj_pred(Halfedge_const_handle e) const
/*{\Mop returns the edge before |e| in the cyclic ordered adjacency list of
|source(e)|.}*/
{ return e->twin_->next_; }
Halfedge_const_handle next(Halfedge_const_handle e) const
/*{\Mop returns the next edge in the face cycle containing |e|.}*/
{ return e->next_; }
Halfedge_const_handle previous(Halfedge_const_handle e) const
/*{\Mop returns the previous edge in the face cycle containing |e|.}*/
{ return e->prev_; }
Face_const_handle face(Halfedge_const_handle e) const
/*{\Mop returns the face incident to |e|.}*/
{ return e->face_; }
Face_const_handle face(Halfloop_const_handle l) const
/*{\Mop returns the face incident to |l|.}*/
{ return l->face_; }
Face_const_handle face(Vertex_const_handle v) const
/*{\Mop returns the face incident to |v|.
\precond |is_isolated(v)|.}*/
{ return v->face_; }
/*{\Mtext \headerline{Iteration} \setopdims{3.3cm}{0cm}}*/
Vertex_const_iterator vertices_begin() const
{ return psm_->vertices_begin(); }
Vertex_const_iterator vertices_end() const
{ return psm_->vertices_end(); }
Halfedge_const_iterator halfedges_begin() const
{ return psm_->halfedges_begin(); }
Halfedge_const_iterator halfedges_end() const
{ return psm_->halfedges_end(); }
Face_const_iterator faces_begin() const
{ return psm_->faces_begin(); }
Face_const_iterator faces_end() const
{ return psm_->faces_end(); }
Halfloop_const_iterator halfloops_begin() const
{ return psm_->halfloops_begin(); }
Halfloop_const_iterator halfloops_end() const
{ return psm_->halfloops_end(); }
Halfloop_const_handle halfloop() const
/*{\Mop returns access to the loop.}*/
{ return psm_->loops_; }
bool has_loop() const
/*{\Mop returns true iff there is a loop.}*/
{ return halfloop() != 0; }
Halfedge_around_vertex_const_circulator
out_edges(Vertex_const_handle v) const
/*{\Mop returns a circulator for the cyclic adjacency list of |v|.
\precond the adjacency list is not empty.}*/
{ return Halfedge_around_vertex_const_circulator(first_out_edge(v)); }
Face_cycle_const_iterator face_cycles_begin(Face_const_handle f) const
/*{\Mop returns an iterator for all bounding face cycles of |f|.
The iterator is is convertable to |Vertex_const_handle|,
|Halfloop_const_handle|, or |Halfedge_const_handle|.}*/
{ return f->bounday_.begin(); }
Face_cycle_const_iterator face_cycles_end(Face_const_handle f) const
/*{\Mop returns the past the end iterator of |f|.}*/
{ return f->boundary_.end(); }
/*{\Mtext \headerline{Statistics and Integrity}}*/
Size_type number_of_vertices() const
/*{\Mop returns the number of vertices.}*/
{ return psm_->number_of_vertices(); }
Size_type number_of_halfedges() const
/*{\Mop returns the number of halfedges.}*/
{ return psm_->number_of_halfedges(); }
Size_type number_of_edges() const
/*{\Mop returns the number of edges.}*/
{ return number_of_halfedges()/2; }
Size_type number_of_halfloops() const
/*{\Mop returns the number of halfloops.}*/
{ return psm_->number_of_halfloops(); }
Size_type number_of_loops() const
/*{\Mop returns the number of loops.}*/
{ return psm_->number_of_halfloops()/2; }
Size_type number_of_faces() const
/*{\Mop returns the number of faces.}*/
{ return psm_->number_of_faces(); }
Size_type number_of_face_cycles() const;
/*{\Mop returns the number of face cycles.}*/
Size_type number_of_connected_components() const;
/*{\Mop calculates the number of connected components of |P|.}*/
void print_statistics(std::ostream& os = std::cout) const
/*{\Mop print the statistics of |P|: the number of vertices, edges,
and faces.}*/
{
os << "Sphere Map - Statistics\n";
os << "|V| = " << number_of_vertices() << std::endl;
os << "|E| = " << number_of_edges() << std::endl;
os << "|L| = " << number_of_halfloops()/2 << std::endl;
os << "|F| = " << number_of_faces() << std::endl;
os << "|Fcs| = " << number_of_face_cycles() << std::endl << std::endl;
}
void check_integrity_and_topological_planarity(bool faces=true) const;
/*{\Mop checks the link structure and the genus of |P|.}*/
Halfedge_const_handle cas(Halfedge_const_handle e) const
{ return cyclic_adj_succ(e); }
Halfedge_const_handle cap(Halfedge_const_handle e) const
{ return cyclic_adj_pred(e); }
template <typename H>
bool is_boundary_object(H h) const
{ return psm_->is_boundary_object(h); }
/*{\Mtext \headerline{Associated Information}\restoreopdims}*/
const Sphere_point& point(Vertex_const_handle v) const
/*{\Mop returns the embedding of |v|.}*/
{ return v->point_; }
const Sphere_circle& circle(Halfedge_const_handle e) const
/*{\Mop returns the circle supporting |e|.}*/
{ return e->circle_; }
const Sphere_circle& circle(Halfloop_const_handle l) const
/*{\Mop returns the circle supporting |l|.}*/
{ return l->circle_; }
Mark mark(Vertex_const_handle v) const
/*{\Mop returns the mark of |v|.}*/
{ return v->mark_; }
Mark mark(Halfedge_const_handle e) const
/*{\Mop returns the mark of |e|.}*/
{ return ( &*e < &*twin(e) ) ? e->mark_ : twin(e)->mark_; }
Mark mark(Halfloop_const_handle l) const
/*{\Mop returns the mark of |l|.}*/
{ return ( &*l < &*twin(l) ) ? l->mark_ : twin(l)->mark_; }
Mark mark(Face_const_handle f) const
/*{\Mop returns the mark of |f|.}*/
{ return f->mark_; }
Mark mark_of_halfsphere(int i) const
{ CGAL_assertion(i);
if (i<0) return psm_->m_neg_;
return psm_->m_pos_; }
/*{\Mtext \headerline{Iteration}}*/
/*{\Mtext The list of all objects can be accessed via iterator ranges.
For comfortable iteration we also provide iterations macros.
The iterator range access operations are of the following kind:\\
|Vertex_iterator vertices_begin()/vertices_end()|\\
|Halfedge_iterator halfedges_begin()/halfedges_end()|\\
|Halfloop_iterator halfloops_begin()/halfloops_end()|\\
|Face_iterator faces_begin()/faces_end()|
The macros are then |CGAL_forall_vertices(v,M)|, |CGAL_forall_halfedges(e,M)|,
|CGAL_forall_faces(f,M)|, |CGAL_forall_face_cycles_of(fc,F)| where |M| is
a sphere map and |F| is a face.}*/
}; // SM_const_decorator
template <class H>
std::string PH(H h)
{ if (h == H()) return "nil"; return h->debug(); }
template <typename SM_, typename K_>
void SM_const_decorator<SM_,K_>::
check_integrity_and_topological_planarity(bool faces) const
{
TRACEN("check_integrity_and_topological_planarity:");
using CGAL::Object_index;
Object_index<Vertex_const_iterator>
VI(vertices_begin(),vertices_end(),'v');
Object_index<Halfedge_const_iterator>
EI(halfedges_begin(),halfedges_end(),'e');
Object_index<Face_const_iterator>
FI(faces_begin(),faces_end(),'f');
typedef Halfedge_around_vertex_const_circulator hvc_circulator;
typedef Halfedge_around_face_const_circulator hfc_circulator;
Vertex_const_handle v;
int iso_vert_num=0;
/* check the source links of out edges and count isolated vertices */
CGAL_forall_vertices(v,*this) {
if ( is_isolated(v) ) {
if ( faces )
CGAL_assertion_msg( face(v) != Face_const_handle(), VI(v).c_str());
++iso_vert_num;
} else {
CGAL_assertion_msg( first_out_edge(v) != Halfedge_const_handle(),
VI(v).c_str());
TRACEN(point(v)<<" "<<EI(first_out_edge(v)));
CGAL_assertion_msg( source(first_out_edge(v)) == v ,
VI(v).c_str());
}
}
/* check the bidirected links and the face pointer init */
Halfedge_const_iterator e;
CGAL_forall_halfedges(e,*this) {
CGAL_assertion( twin(twin(e)) == e );
CGAL_assertion( source(e) != Vertex_const_handle() );
CGAL_assertion( next(e) != Halfedge_const_handle() );
CGAL_assertion( previous(next(e)) == e );
CGAL_assertion( target(e) == source(next(e)) );
CGAL_assertion( previous(e) != Halfedge_const_handle() );
CGAL_assertion( next(previous(e)) == e );
CGAL_assertion( target(previous(e)) == source(e) );
if ( !faces ) continue;
CGAL_assertion( face(e) != Face_const_handle() );
CGAL_assertion( face(next(e)) == face(e) );
CGAL_assertion( face(previous(e)) == face(e) );
}
int fc_num(0),iv_num(0);
Face_const_iterator f;
Face_cycle_const_iterator fci;
CGAL_forall_faces(f,*this) {
CGAL_forall_face_cycles_of(fci,f) {
if ( fci.is_halfedge() ) {
CGAL_assertion( face(Halfedge_const_handle(fci)) == f ); ++fc_num;
} else if ( fci.is_vertex() ) {
CGAL_assertion( face(Vertex_const_handle(fci)) == f ); ++iv_num;
}
else CGAL_assertion(0);
}
}
int v_num = number_of_vertices() - iso_vert_num;
int e_num = number_of_edges();
int c_num = number_of_connected_components() - iso_vert_num;
int f_num = number_of_face_cycles() - c_num + 1;
TRACEV(fc_num);TRACEV(iv_num);TRACEV(iso_vert_num);
TRACEV(v_num);TRACEV(e_num);TRACEV(c_num);TRACEV(f_num);
/* this means all face cycles and all isolated vertices are
indeed referenced from a face */
/* every isolated vertex increases the component count
one face cycle per component is redundent except one
finally check the Euler formula: */
CGAL_assertion( v_num - e_num + f_num == 1 + c_num );
}
template <typename SM_, typename K_>
typename SM_const_decorator<SM_,K_>::Size_type
SM_const_decorator<SM_,K_>::
number_of_face_cycles() const
{
unsigned int fc_num=0;
CGAL::Unique_hash_map<Halfedge_const_handle,bool> visited;
// init with bool() == false
Halfedge_const_iterator e;
CGAL_forall_halfedges(e,*this) {
if (visited[e]) continue;
Halfedge_around_face_const_circulator hfc(e), hend(hfc);
CGAL_For_all(hfc,hend) visited[hfc]=true;
++fc_num;
}
if ( has_loop() ) fc_num += 2;
return fc_num;
}
template <typename SM_, typename K_>
typename SM_const_decorator<SM_,K_>::Size_type
SM_const_decorator<SM_,K_>::
number_of_connected_components() const
{
int comp_num=0;
CGAL::Unique_hash_map<Vertex_const_iterator,bool> visited(false);
Vertex_const_iterator v;
CGAL_forall_vertices(v,*this) {
if (visited[v]) continue;
std::list<Vertex_const_iterator> L;
L.push_back(v); visited[v]=true;
/* we keep the invariant that all nodes which have been stacked
are marked visited */
while (!L.empty()) {
Vertex_const_iterator vc = L.front(); L.pop_front();
if ( is_isolated(vc) ) continue;
Halfedge_around_vertex_const_circulator
havc(first_out_edge(vc)), hend(havc);
CGAL_For_all(havc,hend) {
if (!visited[target(havc)]) {
L.push_back(target(havc)); visited[target(havc)]=true;
}
}
}
++comp_num;
}
return comp_num;
}
CGAL_END_NAMESPACE
#endif // CGAL_SM_CONST_DECORATOR_H

View File

@ -0,0 +1,412 @@
// ============================================================================
//
// Copyright (c) 1997-2000 The CGAL Consortium
//
// This software and related documentation is part of an INTERNAL release
// of the Computational Geometry Algorithms Library (CGAL). It is not
// intended for general use.
//
// ----------------------------------------------------------------------------
//
// release : $CGAL_Revision$
// release_date : $CGAL_Date$
//
// file : include/CGAL/Nef_S2/SM_constrained_triang_traits.h
// package : Nef_S2
// chapter : Nef Polyhedra
//
// revision : $Revision$
// revision_date : $Date$
//
// author(s) : Michael Seel <seel@mpi-sb.mpg.de>
// maintainer : Michael Seel <seel@mpi-sb.mpg.de>
// coordinator : Michael Seel <seel@mpi-sb.mpg.de>
//
// implementation: Constrained triangulation of a sphere map
// ============================================================================
#ifndef CGAL_SM_CONSTRAINED_TRIANG_TRAITS_H
#define CGAL_SM_CONSTRAINED_TRIANG_TRAITS_H
#include <CGAL/basic.h>
#include <CGAL/Unique_hash_map.h>
#include <CGAL/generic_sweep.h>
//#include <CGAL/Nef_S2/SM_checker.h>
#include <string>
#include <map>
#include <set>
#undef _DEBUG
#define _DEBUG 139
#include <CGAL/Nef_S2/debug.h>
CGAL_BEGIN_NAMESPACE
/* For a detailed documentation see the MPI research report 2001-1-003
which documents the planar flavor of this baby; only minor deviations
are included in this code */
template <typename Decorator_, typename Kernel_>
class SM_constrained_triang_traits : public Decorator_ {
public:
typedef SM_constrained_triang_traits<Decorator_,Kernel_> Self;
typedef Decorator_ Base;
typedef typename Kernel_::Point_2 Point;
typedef typename Kernel_::Segment_2 Segment;
typedef typename Base::Halfedge_handle Halfedge_handle;
typedef typename Base::Vertex_handle Vertex_handle;
typedef typename Base::Face_handle Face_handle;
typedef typename Base::Halfedge_iterator Halfedge_iterator;
typedef typename Base::Vertex_iterator Vertex_iterator;
typedef typename Base::Face_iterator Face_iterator;
typedef typename Base::Halfedge_around_vertex_circulator
Halfedge_around_vertex_circulator;
// the types interfacing the sweep:
typedef std::pair<Vertex_iterator,Vertex_iterator> INPUT;
typedef Decorator_ OUTPUT;
typedef Kernel_ GEOMETRY;
class lt_edges_in_sweepline : public Decorator_
{ const Point& p;
const Halfedge_handle& e_bottom;
const Halfedge_handle& e_top;
const Kernel_& K;
public:
lt_edges_in_sweepline(const Point& pi,
const Halfedge_handle& e1, const Halfedge_handle& e2,
const Decorator_& D, const Kernel_& k) :
Decorator_(D), p(pi), e_bottom(e1), e_top(e2), K(k) {}
lt_edges_in_sweepline(const lt_edges_in_sweepline& lt) :
Decorator_(lt), p(lt.p),
e_bottom(lt.e_bottom), e_top(lt.e_top), K(lt.K) {}
Segment seg(const Halfedge_handle& e) const
{ return K.construct_segment(point(source(e)),point(target(e))); }
int orientation(Halfedge_handle e, const Point& p) const
{ return K.orientation(point(source(e)),point(target(e)),p); }
bool operator()(const Halfedge_handle& e1, const Halfedge_handle& e2) const
{ // Precondition:
// [[p]] is identical to the source of either [[e1]] or [[e2]].
if (e1 == e_bottom || e2 == e_top) return true;
if (e2 == e_bottom || e1 == e_top) return false;
if ( e1 == e2 ) return 0;
int s = 0;
if ( p == point(source(e1)) ) s = orientation(e2,p);
else if ( p == point(source(e2)) ) s = - orientation(e1,p);
else CGAL_assertion_msg(0,"compare error in sweep.");
if ( s || source(e1) == target(e1) || source(e2) == target(e2) )
return ( s < 0 );
s = orientation(e2,point(target(e1)));
if (s==0) CGAL_assertion_msg(0,"parallel edges not allowed.");
return ( s < 0 );
}
}; // lt_edges_in_sweepline
class lt_pnts_xy : public Decorator_
{ const Kernel_& K;
public:
lt_pnts_xy(const Decorator_& D, const Kernel_& k) : Decorator_(D), K(k) {}
lt_pnts_xy(const lt_pnts_xy& lt) : Decorator_(lt), K(lt.K) {}
int operator()(const Vertex_handle& v1, const Vertex_handle& v2) const
{ return K.compare_xy(point(v1),point(v2)) < 0; }
}; // lt_pnts_xy
typedef std::map<Halfedge_handle, Halfedge_handle, lt_edges_in_sweepline>
Sweep_status_structure;
typedef typename Sweep_status_structure::iterator ss_iterator;
typedef typename Sweep_status_structure::value_type ss_pair;
typedef std::set<Vertex_iterator,lt_pnts_xy> Event_Q;
typedef typename Event_Q::const_iterator event_iterator;
const GEOMETRY& K;
Event_Q event_Q;
event_iterator event_it;
Vertex_handle event;
Point p_sweep;
Sweep_status_structure SL;
CGAL::Unique_hash_map<Halfedge_handle,ss_iterator> SLItem;
Halfedge_handle e_low,e_high; // framing edges !
Halfedge_handle e_search;
Vertex_iterator v_first, v_beyond;
SM_constrained_triang_traits(const INPUT& in, OUTPUT& out,
const GEOMETRY& k)
: Base(out), K(k), event_Q(lt_pnts_xy(*this,K)),
SL(lt_edges_in_sweepline(p_sweep,e_low,e_high,*this,K)),
SLItem(SL.end()), v_first(in.first), v_beyond(in.second)
{ TRACEN("Constrained Triangulation Sweep"); }
/* |treat_new_edge| is used to forward information that exists
at input edges of the triangulation as such it spreads input
information to the newly created edges of the triangulation;
the used operation incident_mark refers to the base class of
|*this| */
void treat_new_edge(Halfedge_handle e)
{ assoc_info(e);
mark(e) = incident_mark(e) = incident_mark(twin(e)) =
incident_mark(next(e));
TRACEN(" treat_new_edge "<<PH(e));
}
Halfedge_handle new_bi_edge(Vertex_handle v1, Vertex_handle v2)
{ // appended at v1 and v2 adj list
Halfedge_handle e = Base::new_edge_pair(v1,v2);
treat_new_edge(e);
return e;
}
Halfedge_handle new_bi_edge(Halfedge_handle e_bf, Halfedge_handle e_af)
{ // ccw before e_bf and after e_af
Halfedge_handle e =
Base::new_edge_pair(e_bf,e_af,Base::BEFORE, Base::AFTER);
treat_new_edge(e);
return e;
}
Halfedge_handle new_bi_edge(Vertex_handle v, Halfedge_handle e_bf)
{ // appended at v's adj list and before e_bf
Halfedge_handle e = Base::new_edge_pair(v,e_bf,Base::BEFORE);
treat_new_edge(e);
return e;
}
Segment segment(Halfedge_handle e) const
{ return K.construct_segment(point(source(e)),point(target(e))); }
bool is_forward(Halfedge_handle e) const
{ return K.compare_xy(point(source(e)),point(target(e))) < 0; }
bool edge_is_visible_from(Vertex_handle v, Halfedge_handle e)
{
Point p = point(v);
Point p1 = point(source(e));
Point p2 = point(target(e));
return ( K.orientation(p1,p2,p) > 0 ); // leftturn
}
void triangulate_up(Halfedge_handle& e_apex)
{
TRACEN("triangulate_up "<<segment(e_apex));
Vertex_handle v_apex = source(e_apex);
while (true) {
Halfedge_handle e_vis = previous(twin(e_apex));
bool in_sweep_line = (SLItem[e_vis] != SL.end());
bool not_visible = !edge_is_visible_from(v_apex,e_vis);
TRACEN(" checking "<<in_sweep_line<<not_visible<<" "<<segment(e_vis));
if ( in_sweep_line || not_visible) {
TRACEN(" STOP"); return;
}
Halfedge_handle e_back = new_bi_edge(e_apex,e_vis);
e_apex = e_back;
TRACEN(" produced " << segment(e_apex));
}
}
void triangulate_down(Halfedge_handle& e_apex)
{
TRACEN("triangulate_down "<<segment(e_apex));
Vertex_handle v_apex = source(e_apex);
while (true) {
Halfedge_handle e_vis = next(e_apex);
bool in_sweep_line = (SLItem[e_vis] != SL.end());
bool not_visible = !edge_is_visible_from(v_apex,e_vis);
TRACEN(" checking "<<in_sweep_line<<not_visible<<" "<<segment(e_vis));
if ( in_sweep_line || not_visible) {
TRACEN(" STOP"); return;
}
Halfedge_handle e_vis_rev = twin(e_vis);
Halfedge_handle e_forw = new_bi_edge(e_vis_rev,e_apex);
e_apex = twin(e_forw);
TRACEN(" produced " << segment(e_apex));
}
}
void triangulate_between(Halfedge_handle e_upper, Halfedge_handle e_lower)
{
// we triangulate the interior of the whole chain between
// target(e_upper) and target(e_lower)
assert(source(e_upper)==source(e_lower));
TRACE("triangulate_between\n "<<segment(e_upper));
TRACEN("\n "<<segment(e_lower));
Halfedge_handle e_end = twin(e_lower);
while (true) {
Halfedge_handle e_vis = next(e_upper);
Halfedge_handle en_vis = next(e_vis);
TRACEN(" working on base e_vis " << segment(e_vis));
TRACEN(" next is " << segment(en_vis));
if (en_vis == e_end) return;
e_upper = twin(new_bi_edge(twin(e_vis),e_upper));
TRACEN(" produced " << segment(e_upper));
}
}
void process_event()
{
TRACEN("\nPROCESS_EVENT " << p_sweep);
Halfedge_handle e, ep, eb_low, eb_high, e_end;
if ( !is_isolated(event) ) {
e = last_out_edge(event);
ep = first_out_edge(event);
}
ss_iterator sit_pred, sit;
/* PRECONDITION:
only ingoing => e is lowest in ingoing bundle
only outgoing => e is highest in outgoing bundle
ingoing and outgoing => e is lowest in ingoing bundle */
eb_high = e_end = ep;
eb_low = e;
TRACEN("determining handle in SL");
if ( e != Halfedge_handle() ) {
point(target(e_search)) = p_sweep; // degenerate loop edge
sit_pred = SLItem[e];
if ( sit_pred != SL.end()) sit = --sit_pred;
else sit = sit_pred = --SL.upper_bound(e_search);
} else { // event is isolated vertex
point(target(e_search)) = p_sweep; // degenerate loop edge
sit_pred = --SL.upper_bound(e_search);
}
bool ending_edges(0), starting_edges(0);
while ( e != Halfedge_handle() ) { // walk adjacency list clockwise
if ( SLItem[e] != SL.end() )
{
TRACEN("ending " << segment(e));
if (ending_edges) triangulate_between(e,cyclic_adj_succ(e));
ending_edges = true;
SL.erase(SLItem[e]);
link_bi_edge_to(e,SL.end());
// not in SL anymore
}
else
{
TRACEN("starting "<<segment(e));
sit = SL.insert(sit,ss_pair(e,e));
link_bi_edge_to(e,sit);
if ( !starting_edges ) eb_high = cyclic_adj_succ(e);
starting_edges = true;
}
if (e == e_end) break;
e = cyclic_adj_pred(e);
}
if (!ending_edges)
{
Halfedge_handle e_vis = sit_pred->second;
Halfedge_handle e_vis_n = cyclic_adj_succ(e_vis);
eb_low = eb_high = new_bi_edge(event,e_vis_n);
TRACEN(" producing link "<<segment(eb_low)<<
"\n before "<<segment(e_vis_n));
}
triangulate_up(eb_high);
triangulate_down(eb_low);
sit_pred->second = eb_low;
}
bool event_exists()
{ if ( event_it != event_Q.end() ) {
// event is set at end of loop and in init
event = *event_it;
p_sweep = point(event);
return true;
}
return false;
}
void procede_to_next_event()
{ ++event_it; }
void link_bi_edge_to(Halfedge_handle e, ss_iterator sit) {
SLItem[e] = SLItem[twin(e)] = sit;
}
void initialize_structures()
{
TRACEN("initialize_structures ");
for ( event = v_first; event != v_beyond; ++event )
event_Q.insert(event); // sorted order of vertices
event_it = event_Q.begin();
if ( event_Q.empty() ) return;
event = *event_it;
p_sweep = point(event);
if ( !is_isolated(event) ) {
Halfedge_around_vertex_circulator
e(first_out_edge(event)), eend(e);
CGAL_For_all(e,eend) {
TRACEN("init with "<<PH(e));
ss_iterator sit = SL.insert(ss_pair(e,e)).first;
link_bi_edge_to(e,sit);
}
}
Vertex_handle v_tmp = new_vertex(Point());
e_high = Base::new_edge_pair(event,v_tmp);
e_low = Base::new_edge_pair(event,v_tmp);
// this are two symbolic edges just accessed as sentinels
// they carry no geometric information
e_search = Base::new_edge_pair(v_tmp,v_tmp);
// this is just a loop used for searches in SL
ss_iterator sit_high = SL.insert(ss_pair(e_high,e_high)).first;
ss_iterator sit_low = SL.insert(ss_pair(e_low,e_low)).first;
// inserting sentinels into SL
link_bi_edge_to(e_high, sit_high);
link_bi_edge_to(e_low , sit_low);
// we mark them being in the sweepline, which they will never leave
// we move to the second vertex:
procede_to_next_event();
event_exists(); // sets p_sweep for check invariants
TRACEN("EOF initialization");
}
void complete_structures()
{
if (e_low != Halfedge_handle()) {
delete_vertex(target(e_search));
} // removing sentinels and e_search
}
void check_ccw_local_embedding() const
{
#ifdef CGAL_CHECK_EXPENSIVEXXX
PM_checker<Decorator_,Kernel_> C(*this,K);
C.check_order_preserving_embedding(event);
#endif
}
void check_invariants()
{
#ifdef CGAL_CHECK_EXPENSIVEXXX
if ( event_it == event_Q.end() ) return;
check_ccw_local_embedding();
#endif
}
void check_final()
{
#ifdef CGAL_CHECK_EXPENSIVEXXX
PM_checker<Decorator_,Kernel_> C(*this,K); C.check_is_triangulation();
#endif
}
}; // SM_constrained_triang_traits<Decorator_,Kernel_,New_edge_>
CGAL_END_NAMESPACE
#endif // CGAL_SM_CONSTRAINED_TRIANG_TRAITS_H

View File

@ -0,0 +1,796 @@
#ifndef CGAL_SM_DECORATOR_H
#define CGAL_SM_DECORATOR_H
#include <CGAL/basic.h>
#include <CGAL/Nef_S2/SM_const_decorator.h>
CGAL_BEGIN_NAMESPACE
/*{\Moptions print_title=yes }*/
/*{\Moptions outfile=SM_decorator.man }*/
/*{\Manpage {SM_decorator}{Sphere_map,Kernel}
{Topological sphere map decorator}{D}}*/
template <typename Sphere_map_, typename Kernel_>
class SM_decorator : public SM_const_decorator<Sphere_map_,Kernel_>
{
public:
typedef SM_const_decorator<Sphere_map_,Kernel_> Base;
typedef SM_decorator<Sphere_map_,Kernel_> Self;
/*{\Mdefinition ...}*/
/*{\Mtypes 5}*/
typedef Sphere_map_ Sphere_map;
typedef Kernel_ Kernel;
typedef typename Kernel_::Sphere_point Sphere_point;
/*{\Mtypemember embedding vertices.}*/
typedef typename Kernel_::Sphere_segment Sphere_segment;
/*{\Mtypemember embedding edges.}*/
typedef typename Kernel_::Sphere_circle Sphere_circle;
/*{\Mtypemember embedding loops.}*/
typedef typename Sphere_map_::Mark Mark;
/*{\Mtypemember attributes of objects (vertices, edges, faces).}*/
typedef size_t Size_type;
/*{\Mtypemember size type.}*/
enum { BEFORE = -1, AFTER = 1 };
/*{\Menum insertion order labels.}*/
typedef void* GenPtr;
#define USING(t) typedef typename Sphere_map_::t t
USING(Vertex);
USING(Vertex_const_handle);
USING(Vertex_const_iterator);
USING(Halfedge);
USING(Halfedge_const_handle);
USING(Halfedge_const_iterator);
USING(Face);
USING(Face_const_handle);
USING(Face_const_iterator);
USING(Halfloop);
USING(Halfloop_const_handle);
USING(Halfloop_const_iterator);
USING(Vertex_handle);
USING(Vertex_iterator);
USING(Halfedge_handle);
USING(Halfedge_iterator);
USING(Face_handle);
USING(Face_iterator);
USING(Halfloop_handle);
USING(Halfloop_iterator);
USING(Object_handle);
#undef USING
#define USING(t) typedef typename Base::t t
USING(Halfedge_around_vertex_const_circulator);
USING(Halfedge_around_face_const_circulator);
USING(Face_cycle_const_iterator);
#undef USING
/*{\Mtext Local types are handles, iterators and circulators of the
following kind: |Vertex_handle|, |Vertex_iterator|, |Halfedge_handle|,
|Halfedge_iterator|, |Halfloop_handle|, |Halfloop_iterator|,
|Face_handle|, |Face_iterator|. Additionally the following
circulators are defined.}*/
typedef CircFromIt<
Halfedge_iterator,
move_edge_around_vertex<Halfedge_iterator> >
Halfedge_around_vertex_circulator;
/*{\Mtypemember circulating the adjacency list of an vertex |v|.}*/
typedef CircFromIt<
Halfedge_iterator,
move_edge_around_face<Halfedge_iterator> >
Halfedge_around_face_circulator;
/*{\Mtypemember circulating the face cycle of an face |f|.}*/
typedef typename Sphere_map_::Face_cycle_iterator
Face_cycle_iterator;
/*{\Mtypemember iterating all face cycles of an face |f|.
The iterator has method |bool is_vertex()|, |bool is_halfedge()|,
|bool is_halfloop()|, and can be converted to the corresponding
handles |Vertex_handle|, |Halfedge_handle|, or
|Halfloop_handle|.}*/
public:
/*{\Mcreation 3}*/
SM_decorator() : Base() {}
SM_decorator(const Self& D) : Base(D) {}
SM_decorator(Sphere_map_& M) : Base(M) {}
/*{\Mcreate constructs a plane map decorator exploring |M|.}*/
/*{\Moperations 4 4}*/
Sphere_map& sm() { return *psm_; }
Vertex_const_handle source(Halfedge_const_handle e) const
{ return e->source_; }
Vertex_const_handle target(Halfedge_const_handle e) const
{ return e->twin_->source_; }
Halfedge_const_handle twin(Halfedge_const_handle e) const
{ return e->twin_; }
Halfloop_const_handle twin(Halfloop_const_handle l) const
{ return l->twin_; }
Vertex_handle source(Halfedge_handle e) const
/*{\Mop returns the source of |e|.}*/
{ return e->source_; }
Vertex_handle target(Halfedge_handle e) const
/*{\Mop returns the target of |e|.}*/
{ return e->twin_->source_; }
Halfedge_handle twin(Halfedge_handle e) const
/*{\Mop returns the twin of |e|.}*/
{ return e->twin_; }
Halfloop_handle twin(Halfloop_handle l) const
/*{\Mop returns the twin of |l|.}*/
{ return l->twin_; }
bool is_isolated(Vertex_const_handle v) const
{ return (v->edge_ == Halfedge_handle()); }
bool is_isolated(Vertex_handle v) const
/*{\Mop returns |true| when |v| is linked to the interior of a face.}*/
{ return (v->edge_ == Halfedge_handle()); }
Halfedge_const_handle first_out_edge(Vertex_const_handle v) const
{ return v->edge_; }
Halfedge_const_handle last_out_edge(Vertex_const_handle v) const
{ return cap(v->edge_); }
Halfedge_handle first_out_edge(Vertex_handle v) const
/*{\Mop returns one edge with source |v|. It's the starting point for
the circular iteration over the edges with source |v|.
\precond |!is_isolated(v)|.}*/
{ return v->edge_; }
Halfedge_handle last_out_edge(Vertex_handle v) const
/*{\Mop returns one edge with source |v|. \precond |!is_isolated(v)|.}*/
{ return cap(v->edge_); }
Halfedge_const_handle cyclic_adj_succ(Halfedge_const_handle e) const
{ return e->prev_->twin_; }
Halfedge_const_handle cyclic_adj_pred(Halfedge_const_handle e) const
{ return e->twin_->next_; }
Halfedge_handle cyclic_adj_succ(Halfedge_handle e) const
/*{\Mop returns the edge after |e| in the cyclic ordered adjacency list of
|source(e)|.}*/
{ return e->prev_->twin_; }
Halfedge_handle cyclic_adj_pred(Halfedge_handle e) const
/*{\Mop returns the edge before |e| in the cyclic ordered adjacency list of
|source(e)|.}*/
{ return e->twin_->next_; }
Halfedge_const_handle next(Halfedge_const_handle e) const
{ return e->next_; }
Halfedge_const_handle previous(Halfedge_const_handle e) const
{ return e->prev_; }
Halfedge_handle next(Halfedge_handle e) const
/*{\Mop returns the next edge in the face cycle containing |e|.}*/
{ return e->next_; }
Halfedge_handle previous(Halfedge_handle e) const
/*{\Mop returns the previous edge in the face cycle containing |e|.}*/
{ return e->prev_; }
Face_const_handle face(Halfedge_const_handle e) const
{ return e->face_; }
Face_const_handle face(Halfloop_const_handle l) const
{ return l->face_; }
Face_const_handle face(Vertex_const_handle v) const
{ return v->face_; }
Face_handle face(Halfedge_handle e) const
/*{\Mop returns the face incident to |e|.}*/
{ return e->face_; }
Face_handle face(Halfloop_handle l) const
/*{\Mop returns the face incident to |l|.}*/
{ return l->face_; }
Face_handle face(Vertex_handle v) const
/*{\Mop returns the face incident to |v|. \precond |is_isolated(v)|.}*/
{ return v->face_; }
/*{\Mtext \headerline{Iteration} \setopdims{3.3cm}{0cm}}*/
Vertex_iterator vertices_begin() const
{ return psm_->vertices_begin(); }
Vertex_iterator vertices_end() const
{ return psm_->vertices_end(); }
Halfedge_iterator halfedges_begin() const
{ return psm_->halfedges_begin(); }
Halfedge_iterator halfedges_end() const
{ return psm_->halfedges_end(); }
Face_iterator faces_begin() const
{ return psm_->faces_begin(); }
Face_iterator faces_end() const
{ return psm_->faces_end(); }
Halfloop_iterator halfloops_begin() const
{ return psm_->halfloops_begin(); }
Halfloop_iterator halfloops_end() const
{ return psm_->halfloops_end(); }
Halfloop_handle halfloop() const
{ return psm_->loops_; }
Halfedge_around_vertex_const_circulator
out_edges(Vertex_const_handle v) const
{ return Halfedge_around_vertex_circulator(first_out_edge(v)); }
Face_cycle_const_iterator face_cycles_begin(Face_const_handle f) const
{ return f->bounday_.begin(); }
Face_cycle_const_iterator face_cycles_end(Face_const_handle f) const
{ return f->boundary_.end(); }
Face_cycle_iterator face_cycles_begin(Face_handle f) const
/*{\Mop returns an iterator for all bounding face cycles of |f|.
The iterator is is convertable to |Vertex_handle|,
|Halfloop_handle|, or |Halfedge_handle|.}*/
{ return f->boundary_.begin(); }
Face_cycle_iterator face_cycles_end(Face_handle f) const
/*{\Mop returns the past the end iterator of |f|.}*/
{ return f->boundary_.end(); }
Halfedge_around_vertex_circulator
out_edges(Vertex_handle v) const
/*{\Mop returns a circulator for the cyclic adjacency list of |v|.
\precond the adjacency list is not empty.}*/
{ return Halfedge_around_vertex_circulator(first_out_edge(v)); }
/*{\Mtext \headerline{Update Operations}}*/
void clear() const
/*{\Mop reintializes |P| to the empty map.}*/
{ psm_->clear(); }
bool is_closed_at_source(Halfedge_handle e) const
/*{\Mop returns |true| when |prev(e) == twin(e)|.}*/
{ return previous(e) == twin(e); }
bool is_closed_at_target(Halfedge_handle e) const
/*{\Mop returns |true| when |next(e) == twin(e)|.}*/
{ return next(e) == twin(e); }
Halfedge_handle cas(Halfedge_handle e) const
{ return cyclic_adj_succ(e); }
Halfedge_handle cap(Halfedge_handle e) const
{ return cyclic_adj_pred(e); }
template <class H>
void make_twins(H h1, H h2) const
{ h1->twin_ = h2; h2->twin_ = h1; }
Vertex_handle new_vertex(const Sphere_point& p) const
/*{\Mop creates a new vertex.}*/
{ return psm_->new_vertex(p); }
Halfedge_handle new_edge_pair() const
/*{\Xop creates a new edge pair. No connectivity is provided.}*/
{ return psm_->new_halfedge_pair(); }
Halfloop_handle new_loop_pair() const
/*{\Mop creates a new loop pair.
\precond No sloop pair exists in the local graph.}*/
{ CGAL_assertion(!has_loop());
return psm_->new_halfloop_pair(); }
Face_handle new_face() const
/*{\Mop creates a new face.}*/
{ return psm_->new_face(); }
void delete_vertex_only(Vertex_handle v) const
/*{\Mop deletes |v| without any connectivity update.}*/
{ return psm_->delete_vertex(v); }
void delete_edge_pair_only(Halfedge_handle e) const
/*{\Mop deletes |e| and its twin without any connectivity update.}*/
{ psm_->delete_halfedge_pair(e); }
void delete_halfedge_only(Halfedge_handle e) const
/*{\Mop deletes |e| without its twin and without any connectivity update.}*/
{ psm_->delete_halfedge(e); }
void delete_face_only(Face_handle f) const
/*{\Mop deletes |f| without any connectivity update.}*/
{ return psm_->delete_face(f); }
void delete_loop_only() const
/*{\Mop deletes the loop and its twin without any connectivity update.}*/
{ CGAL_assertion(psm_->loops_);
psm_->delete_halfloop_pair(psm_->loops_); }
template <typename H>
bool is_boundary_object(H h) const
{ return psm_->is_boundary_object(h); }
template <typename H>
void store_boundary_object(H h, Face_handle f) const
{ f->boundary_.push_back(make_object(h));
psm_->store_boundary_item(h, --(psm_->face_cycles_end(f)));
}
template <typename H>
void undo_boundary_object(H h, Face_handle f) const
{ CGAL_assertion(psm_->is_boundary_object(h));
Face_cycle_iterator it = psm_->boundary_item(h);
psm_->undef_boundary_item(h);
f->boundary_.erase(it);
}
void link_as_face_cycle(Halfedge_handle e, Face_handle f) const
/*{\Mop creates a new face cycle of |f| and
makes |e| the entry point of it.}*/
{
Halfedge_around_face_circulator hfc(e), hend(hfc);
CGAL_For_all(hfc,hend) hfc->face_ = f;
store_boundary_object(e,f);
}
void link_as_loop(Halfloop_handle l, Face_handle f) const
/*{\Mop creates a new trivial face cycle of |f| and
makes |l| the singular object of it.}*/
{ store_boundary_object(l,f); l->face_ = f; }
void link_as_isolated_vertex(Vertex_handle v, Face_handle f) const
/*{\Mop creates a new trivial face cycle of |f|.
(makes |v| an isolated vertex within |f|).}*/
{ store_boundary_object(v,f); v->face_ = f; }
void unlink_as_face_cycle(Halfedge_handle e) const
/*{\Mop removes the face cycle defined by |e| from |face(e)|.
Does not update the face links of the corresponding face cycle
edges. \precond |e| is the entry object of the face cycle.}*/
{ undo_boundary_object(e,face(e)); }
void unlink_as_loop(Halfloop_handle l) const
/*{\Mop removes the trivial face cycle defined by |l| from
|face(l)|. Does not update |l|'s face link.}*/
{ undo_boundary_object(l,face(l)); }
void unlink_as_isolated_vertex(Vertex_handle v) const
/*{\Mop removes the trivial face cycle defined by |v| from
|face(v)|. Does not update |v|'s face link.
\precond |v| is a trivial face cycle of |face(v)|.}*/
{ undo_boundary_object(v,face(v)); }
void clear_face_cycle_entries(Face_handle f) const
{ psm_->reset_object_list(f->boundary_);
// removes entries of list and the hashed membership
}
Halfedge_handle new_edge_pair(Vertex_handle v1,
Vertex_handle v2) const
/*{\Mop creates a new pair of edges |(e1,e2)| representing |(v1,v2)|
by appending the |ei| to |A(vi)| $(i=1,2)$.}*/
{ Halfedge_handle e1 = new_edge_pair();
Halfedge_handle e2 = twin(e1);
if ( ! is_isolated(v1) )
set_adjacency_at_source_between(cap(first_out_edge(v1)),e1,
first_out_edge(v1));
else
close_tip_at_source(e1,v1);
if ( ! is_isolated(v2) )
set_adjacency_at_source_between(cap(first_out_edge(v2)),e2,
first_out_edge(v2));
else
close_tip_at_source(e2,v2);
return e1;
}
Halfedge_handle new_edge_pair(Halfedge_handle e1,
Halfedge_handle e2,
int pos1 = AFTER, int pos2 = AFTER) const
/*{\Mop creates a new pair of edges |(es1,es2)| representing the uedge
|\{source(e1),source(e2)\}| by inserting the |esi| before or after |ei|
into the cyclic adjacency list of |source(ei)| depending on |posi|
$(i=1,2)$ from |\Mname::BEFORE|, |\Mname::AFTER|.}*/
{
Halfedge_handle er = new_edge_pair();
Halfedge_handle ero = twin(er);
if (pos1 < 0) { // before e1
set_adjacency_at_source_between(cap(e1),er,e1);
if ( e1 == first_out_edge(source(e1)) )
set_first_out_edge(source(e1),er);
} else { // after e1
set_adjacency_at_source_between(e1,er,cas(e1));
}
if (pos2 < 0) { // before e2
set_adjacency_at_source_between(cap(e2),ero,e2);
if ( e2 == first_out_edge(source(e2)) )
set_first_out_edge(source(e2),ero);
} else { // after e2
set_adjacency_at_source_between(e2,ero,cas(e2));
}
return er;
}
Halfedge_handle new_edge_pair(Halfedge_handle e, Vertex_handle v,
int pos = AFTER) const
/*{\Mop creates a new pair of edges |(e1,e2)| representing the uedge
|\{source(e),v\}| by inserting |e1| before or after |e| into cyclic
adjacency list of |source(e)| depending on |pos| from |\Mname::BEFORE|,
|\Mname::AFTER| and appending |e2| at |A(v)|.}*/
{
Halfedge_handle e_new = new_edge_pair();
Halfedge_handle e_opp = twin(e_new);
if (pos < 0) { // before e
set_adjacency_at_source_between(cap(e),e_new,e);
if ( e == first_out_edge(source(e)) )
set_first_out_edge(source(e),e_new);
} else // after e
set_adjacency_at_source_between(e,e_new,cas(e));
if ( ! is_isolated(v) ) {
Halfedge_handle e_first = first_out_edge(v);
set_adjacency_at_source_between(cap(e_first),e_opp,e_first);
} else
close_tip_at_source(e_opp,v);
return e_new;
}
Halfedge_handle new_edge_pair(Vertex_handle v, Halfedge_handle e,
int pos = AFTER) const
/*{\Mop symmetric to the previous one.}*/
{ return twin(new_edge_pair(e,v,pos)); }
void delete_edge_pair(Halfedge_handle e) const
/*{\Mop deletes |e| and its twin and maintains the adjacency at its source
and its target.}*/
{ remove_from_adj_list_at_source(e);
remove_from_adj_list_at_source(twin(e));
delete_edge_pair_only(e);
}
void delete_vertex(Vertex_handle v) const
/*{\Mop deletes |v| and all outgoing edges |A(v)| as well as their twins.
Updates the adjacency at the targets of the edges in |A(v)|.}*/
{
if ( ! is_isolated(v) ) {
Halfedge_handle e = first_out_edge(v);
while ( e != cap(e) )
delete_edge_pair(cap(e));
delete_edge_pair(e);
}
delete_vertex_only(v);
}
void delete_face(Face_handle f) const
/*{\Mop deletes the face |f| without consideration of topological
linkage.}*/
{ clear_face_cycle_entries(f); delete_face_only(f); }
bool has_outdeg_two(Vertex_handle v) const
/*{\Mop return true when |v| has outdegree two.}*/
// does this work for looping edges?
{ if (is_isolated(v)) return false;
Halfedge_handle e1 = first_out_edge(v);
Halfedge_handle e2 = last_out_edge(v);
return (e1!=e2 && e2==cas(e1));
}
void link_as_prev_next_pair(Halfedge_handle e1, Halfedge_handle e2) const
/*{\Xop makes |e1| and |e2| adjacent in the face cycle
$\ldots-|e1-e2|-\ldots$.
Afterwards |e1 = previous(e2)| and |e2 = next(e1)|.}*/
{ e1->next_ = e2; e2->prev_ = e1; }
void merge_edge_pairs_at_target(Halfedge_handle e) const
/*{\Mop merges the edge pairs at |v = target(e)|. |e| and |twin(e)|
are preserved, |next(e)|, |twin(next(e))| and |v| are deleted
in the merger. \precond |v| has outdegree two. The adjacency at
|source(e)| and |target(next(e))| is kept consistent.
If |next(e)| was entry point of |face(e)| then |e| takes this role.
The same holds for |twin(next(e))| and |face(twin(e))|.}*/
{
TRACEN("merge_edge_pairs_at_target "<<PH(e));
Halfedge_handle en = next(e), eno = twin(en), enn, enno,
eo = twin(e) ;
if ( is_closed_at_target(en) ) { enn = eo; enno=e; }
else { enn = next(en), enno = previous(eno); }
Vertex_handle v = target(e), vn = target(en);
CGAL_assertion(has_outdeg_two(v));
Face_handle f1 = face(en), f2 = face(eno);
// transfer the opposite face cycles e-en-enn to e-enn
if ( enn != eno ) {
link_as_prev_next_pair(e,enn);
link_as_prev_next_pair(enno,eo);
} else {
link_as_prev_next_pair(e,eo);
}
// set vertex of e and deal with vertex-halfedge incidence
eo->source_ = vn;
if ( first_out_edge(vn) == eno ) set_first_out_edge(vn,eo);
if ( is_boundary_object(en) )
{ undo_boundary_object(en,f1); store_boundary_object(e,f1); }
if ( is_boundary_object(eno) )
{ undo_boundary_object(eno,f2); store_boundary_object(eo,f2); }
delete_vertex_only(v);
delete_edge_pair_only(en);
TRACEN("END "<<PH(previous(e))<<PH(e)<<PH(next(e)));
}
void convert_edge_to_loop(Halfedge_handle e) const
/*{\Mop converts the edge at |v = target(e)| to the unique
loop |l| of |\Mvar|. |e|, |twin(e)| and |v| are deleted
in the conversion. \precond there was no loop in |\Mvar|.
As |e| was entry point of |face(e)| then |l| takes this role.}*/
{ TRACEN("convert_edge_to_loop "<<PH(e));
CGAL_assertion( !has_loop() );
Halfloop_handle l = new_loop_pair();
Vertex_handle v = target(e);
Face_handle f1 = face(e), f2 = face(twin(e));
CGAL_assertion( is_boundary_object(e) &&
is_boundary_object(twin(e)) );
undo_boundary_object(e,f1); undo_boundary_object(twin(e),f2);
link_as_loop(l,f1), link_as_loop(twin(l),f2);
circle(l) = circle(e); circle(twin(l)) = circle(twin(e));
mark(l) = mark(e);
delete_vertex_only(v);
delete_edge_pair_only(e);
}
void flip_diagonal(Halfedge_handle e) const
{ Halfedge_handle r = twin(e);
Halfedge_handle en = next(e), enn= next(en);
Halfedge_handle rn = next(r), rnn= next(rn);
TRACEN(PH(e)<<PH(en)<<PH(enn));
TRACEN(PH(r)<<PH(rn)<<PH(rnn));
CGAL_assertion( next(enn)==e && next(rnn)==r );
remove_from_adj_list_at_source(e);
remove_from_adj_list_at_source(r);
set_adjacency_at_source_between(enn,e,twin(en));
set_adjacency_at_source_between(rnn,r,twin(rn));
}
/*{\Mtext \headerline{Incomplete topological update primitives}}*/
Halfedge_handle new_edge_pair_at_source
(Halfedge_handle e, int pos = AFTER) const
/*{\Xop creates a new pair of edges |(e1,e2)| representing |(source(e),())|
by inserting |e1| before or after |e| into cyclic adjacency list of
|source(e)| depending on |pos| from |\Mname::BEFORE, \Mname::AFTER|.}*/
{ Halfedge_handle e_new = new_edge_pair();
if (pos < 0) set_adjacency_at_source_between(cap(e),e_new,e);
else set_adjacency_at_source_between(e,e_new,cas(e));
return e_new;
}
Halfedge_handle new_edge_pair_at_source
(Vertex_handle v, int pos = AFTER) const
/*{\Mop creates a new pair of edges |(e1,e2)| representing |(v,())|
by inserting |e1| at the beginning (BEFORE) or end (AFTER)
of adjacency list of |v|.}*/
{ Halfedge_handle e1 = new_edge_pair();
if ( ! is_isolated(v) ) {
Halfedge_handle ef = first_out_edge(v);
if (pos < 0) { // before e1
set_adjacency_at_source_between(cap(ef),e1,ef);
set_first_out_edge(v,e1);
} else {
set_adjacency_at_source_between(ef,e1,cas(ef));
}
} else
close_tip_at_source(e1,v);
return e1;
}
void delete_edge_pair_at_source(Halfedge_handle e) const
/*{\Mop deletes |e| and its twin and maintains the adjacency at its
source.}*/
{ remove_from_adj_list_at_source(e);
delete_edge_pair_only(e);
}
void link_as_target_and_append(Vertex_handle v, Halfedge_handle e) const
/*{\Mop makes |v| the target of |e| appends |twin(e)| to the adjacency list
of |v|.}*/
{ if ( !is_isolated(v) )
set_adjacency_at_source_between(cap(first_out_edge(v)),twin(e),
first_out_edge(v));
else
close_tip_at_target(e,v);
}
void link_as_source_of(Halfedge_handle e, Vertex_handle v) const
/*{\Mop makes |source(e) = v| and sets |e| as the first
out edge if |v| was isolated before.}*/
{ e->source_ = v;
if (v->edge_ == Halfedge_handle()) v->edge_ = e; }
void link_as_target_of(Halfedge_handle e, Vertex_handle v) const
/*{\Mop makes |target(e) = v| and sets |e| as the first
in edge if |v| was isolated before.}*/
{ link_as_source_of(twin(e),v); }
void set_adjacency_at_source_between(Halfedge_handle e, Halfedge_handle en)
const
/*{\Mop makes |e| and |en| neigbors in the cyclic ordered adjacency list
around |v=source(e)|. \precond |source(e)==source(en)|.}*/
{ CGAL_assertion(source(e)==source(en));
link_as_prev_next_pair(twin(en),e);
}
void set_adjacency_at_source_between(Halfedge_handle e1,
Halfedge_handle e_between,
Halfedge_handle e2) const
/*{\Mop inserts |e_between| into the adjacency list around |source(e1)|
between |e1| and |e2| and makes |source(e1)| the source of |e_between|.
\precond |source(e1)==source(e2)|.}*/
{
e_between->source_ = source(e1);
set_adjacency_at_source_between(e1,e_between);
set_adjacency_at_source_between(e_between,e2);
}
void close_tip_at_source(Halfedge_handle e, Vertex_handle v) const
/*{\Mop sets |v| as source of |e| and closes the tip by setting the
corresponding pointers such that |prev(e) == twin(e)| and
|next(twin(e)) == e|.}*/
{ link_as_source_of(e,v);
link_as_prev_next_pair(twin(e),e); }
void close_tip_at_target(Halfedge_handle e, Vertex_handle v) const
/*{\Mop sets |v| as target of |e| and closes the tip by setting the
corresponding pointers such that |prev(twin(e)) == e| and
|next(e) == twin(e)|.}*/
{ link_as_target_of(e,v);
link_as_prev_next_pair(e,twin(e)); }
void remove_from_adj_list_at_source(Halfedge_handle e) const
/*{\Mop removes a halfedge pair |(e,twin(e)| from the adjacency list
of |source(e)|. Afterwards |next(prev(e))==next(twin(e))| and
|first_out_edge(source(e))| is valid if |degree(source(v))>1| before
the operation.}*/
{
Vertex_handle v = source(e);
if ( is_closed_at_source(e) ) { // last outgoing
v->edge_ = Halfedge_handle();
} else {
if (e == first_out_edge(v)) v->edge_ = cap(e);
set_adjacency_at_source_between(cap(e),cas(e));
}
}
void set_face(Halfedge_handle e, Face_handle f) const
{ e->face_ = f; }
void set_face(Vertex_handle v, Face_handle f) const
{ v->face_ = f; }
void set_first_out_edge(Vertex_handle v, Halfedge_handle e) const
{ v->edge_ = e; }
void set_prev(Halfedge_handle e, Halfedge_handle ep) const
{ e->prev_ = ep; }
void set_next(Halfedge_handle e, Halfedge_handle en) const
{ e->next_ = en; }
void set_source(Halfedge_handle e, Vertex_handle v) const
{ e->source_ = v; }
/*{\Mtext \headerline{Associated Information}\restoreopdims}*/
Sphere_point& point(Vertex_handle v) const
/*{\Mop returns the embedding of |v|.}*/
{ return v->point_; }
Sphere_circle& circle(Halfedge_handle e) const
/*{\Mop returns the plane supporting |e|.}*/
{ return e->circle_; }
Sphere_circle& circle(Halfloop_handle l) const
/*{\Mop returns the plane supporting |e|.}*/
{ return l->circle_; }
Mark& mark(Vertex_handle v) const
/*{\Mop returns the mark of |v|.}*/
{ return v->mark_; }
Mark& mark(Halfedge_handle e) const
/*{\Mop returns the mark of |e|.}*/
{ return ( &*e < &*twin(e) ) ? e->mark_ : twin(e)->mark_; }
Mark& mark(Halfloop_handle l) const
/*{\Mop returns the mark of |l|.}*/
{ return ( &*l < &*twin(l) ) ? l->mark_ : twin(l)->mark_; }
Mark& mark(Face_handle f) const
/*{\Mop returns the mark of |f|.}*/
{ return f->mark_; }
void unify_marks(Halfedge_handle e) const
{ if ( &*e < &*twin(e) ) twin(e)->mark_ = e->mark_;
else e->mark_ = twin(e)->mark_;
}
const Sphere_point& point(Vertex_const_handle v) const
{ return v->point_; }
const Sphere_circle& circle(Halfedge_const_handle e) const
{ return e->circle_; }
const Sphere_circle& circle(Halfloop_const_handle l) const
{ return l->circle_; }
const Mark& mark(Vertex_const_handle v) const
{ return v->mark_; }
const Mark& mark(Halfedge_const_handle e) const
{ return ( &*e < &*twin(e) ) ? e->mark_ : twin(e)->mark_; }
const Mark& mark(Halfloop_const_handle l) const
{ return ( &*l < &*twin(l) ) ? l->mark_ : twin(l)->mark_; }
const Mark& mark(Face_const_handle f) const
{ return f->mark_; }
void unify_tmp_marks(Halfedge_handle e) const
{ if (&*e < &*twin(e)) twin(e)->mark_ = e->mark_;
else e->mark_ = twin(e)->mark_; }
void set_marks_in_face_cycle(Halfedge_handle e, Mark m) const
{ Halfedge_around_face_circulator hfc(e), hend(hfc);
CGAL_For_all(hfc,hend) mark(hfc) = mark(target(hfc)) = m;
}
Mark& mark_of_halfsphere(int i) const
{ CGAL_assertion(i);
if (i<0) return psm_->m_neg_;
return psm_->m_pos_; }
GenPtr& info(Vertex_handle v) const
{ return v->info_; }
GenPtr& info(Halfedge_handle e) const
{ return e->info_; }
GenPtr& info(Halfloop_handle l) const
{ return l->info_; }
GenPtr& info(Face_handle f) const
{ return f->info_; }
const GenPtr& info(Vertex_const_handle v) const
{ return v->info_; }
const GenPtr& info(Halfedge_const_handle e) const
{ return e->info_; }
const GenPtr& info(Halfloop_const_handle l) const
{ return l->info_; }
const GenPtr& info(Face_const_handle f) const
{ return f->info_; }
/*{\Mtext \headerline{Iteration}}*/
/*{\Mtext The list of all objects can be accessed via iterator ranges.
For comfortable iteration we also provide iterations macros.
The iterator range access operations are of the following kind:\\
|Vertex_iterator vertices_begin()/vertices_end()|\\
|Halfedge_iterator edges_begin()/edges_end()|\\
|Face_iterator faces_begin()/faces_end()|
The macros are then |CGAL_forall_vertices_of(v,V)|,
|CGAL_forall_edges_of(e,V)|, |CGAL_forall_faces_of(f,V)|,
|CGAL_forall_face_cycles_of(fc,F)| where |V| is the center vertex of
the local graph and |F| any face.}*/
}; // SM_decorator
CGAL_END_NAMESPACE
#endif // CGAL_SM_DECORATOR_H

View File

@ -0,0 +1,466 @@
#ifndef CGAL_SM_IO_PARSER_H
#define CGAL_SM_IO_PARSER_H
#include <CGAL/Nef_S2/SM_decorator.h>
#include <CGAL/Nef_2/Object_index.h>
#include <vector>
CGAL_BEGIN_NAMESPACE
/*{\Moptions outfile=SM_io_parser.man }*/
/*{\Manpage {SM_io_parser}{Decorator_}{IO of embedded maps}{IO}}*/
/*{\Mdefinition An instance |\Mvar| of the data type |\Mname| is a
decorator to provide input and output of a embedded map. |\Mtype| is
generic with respect to the |Decorator_| parameter. |Decorator_| has
to be a decorator model of our |SM_decorator| concept.}*/
/*{\Mgeneralization SM_decorator}*/
template <typename Decorator_>
class SM_io_parser : public Decorator_
{
typedef Decorator_ Base;
typedef typename Decorator_::Sphere_point Sphere_point;
typedef typename Decorator_::Sphere_circle Sphere_circle;
typedef typename Decorator_::Mark Mark;
typedef typename Decorator_::Vertex_iterator Vertex_iterator;
typedef typename Decorator_::Halfedge_iterator Halfedge_iterator;
typedef typename Decorator_::Face_iterator Face_iterator;
typedef typename Decorator_::Vertex_handle Vertex_handle;
typedef typename Decorator_::Halfedge_handle Halfedge_handle;
typedef typename Decorator_::Face_handle Face_handle;
typedef typename Decorator_::Halfloop_handle Halfloop_handle;
typedef typename Decorator_::Face_cycle_iterator Face_cycle_iterator;
std::istream& in; std::ostream& out;
bool verbose;
// a reference to the IO object
CGAL::Object_index<Vertex_handle> VI;
CGAL::Object_index<Halfedge_handle> EI;
CGAL::Object_index<Face_handle> FI;
std::vector<Vertex_handle> Vertex_of;
std::vector<Halfedge_handle> Edge_of;
std::vector<Face_handle> Face_of;
Halfloop_handle Loop_of[2];
// object mapping for input
int vn,en,ln,fn,i;
// the number of objects
bool check_sep(char* sep);
void print_vertex(Vertex_handle) const;
void print_edge(Halfedge_handle) const;
void print_loop(Halfloop_handle) const;
void print_face(Face_handle) const;
void print_init_points() const;
bool read_vertex(Vertex_handle);
bool read_edge(Halfedge_handle);
bool read_loop(Halfloop_handle);
bool read_face(Face_handle);
bool read_init_points() const;
void debug_vertex(Vertex_handle) const;
void debug_edge(Halfedge_handle) const;
void debug_loop(Halfloop_handle) const;
public:
/*{\Mcreation 3}*/
SM_io_parser(istream& is, const Base& D);
/*{\Mcreate creates an instance |\Mvar| of type |\Mname|
to input |H| from |is|.}*/
SM_io_parser(ostream& os, const Base& D);
/*{\Mcreate creates an instance |\Mvar| of type |\Mname|
to output |H| to |os|.}*/
/*{\Moperations 2 3}*/
void print() const;
/*{\Mop prints |H| to |os|.}*/
void read();
/*{\Mop reads |H| from |is|.}*/
void debug() const;
void print_faces() const;
std::string index(Vertex_handle v) const
{ return VI(v,verbose); }
std::string index(Halfedge_handle e) const
{ return EI(e,verbose); }
std::string index(Halfloop_handle l) const
{ if (verbose) return (l==halfloop()? "l0" : "l1");
else return (l==halfloop()? "0" : "1");
}
std::string index(Face_handle f) const
{ return FI(f,verbose); }
static void dump(const Decorator_& D, std::ostream& os = cerr);
/*{\Mstatic prints the plane map decorated by |D| to |os|.}*/
}; // SM_io_parser<Decorator_>
template <typename Decorator_>
SM_io_parser<Decorator_>::
SM_io_parser(istream& iin, const Decorator_& H) :
Base(H), in(iin), out(std::cout), verbose(0),
vn(0), en(0), fn(0), ln(0)
{ clear(); }
template <typename Decorator_>
SM_io_parser<Decorator_>::
SM_io_parser(std::ostream& iout, const Decorator_& D)
: Base(D), in(std::cin), out(iout),
VI(vertices_begin(),vertices_end(),'v'),
EI(halfedges_begin(),halfedges_end(),'e'),
FI(faces_begin(),faces_end(),'f'),
vn(number_of_vertices()),
en(number_of_halfedges()),
ln(number_of_halfloops()),
fn(number_of_faces())
{ verbose = (out.iword(CGAL::IO::mode) != CGAL::IO::ASCII &&
out.iword(CGAL::IO::mode) != CGAL::IO::BINARY);
}
//-----------------------------------------------------------------------------
// OUTPUT AND INPUT:
//-----------------------------------------------------------------------------
template <typename Decorator_>
bool SM_io_parser<Decorator_>::check_sep(char* sep)
{
char c;
do in.get(c); while (isspace(c));
while (*sep != '\0') {
if (*sep != c) {
in.putback(c);
return false;
}
++sep; in.get(c);
}
in.putback(c);
return true;
}
template <typename Decorator_>
void SM_io_parser<Decorator_>::print_vertex(Vertex_handle v) const
{
// syntax: index { isolated incident_object, mark, point }
out << index(v) << " { ";
if ( is_isolated(v) ) out << "1 " << index(face(v));
else out << "0 " << index(first_out_edge(v));
out << ", " << mark(v) << ", " << point(v) << "}\n";
}
template <typename Decorator_>
bool SM_io_parser<Decorator_>::read_vertex(Vertex_handle v)
{
// precondition: nodes exist
// syntax: index { isolated incident_object, mark, point}
int n; bool iso; int f; Mark m; Sphere_point p;
if ( !(in >> n) ||
!check_sep("{") ||
!(in >> iso) ||
!(in >> f) ||
!check_sep(",") ||
!(in >> m) ||
!check_sep(",") ||
!(in >> p) ||
!check_sep("}") ) return false;
if (iso) set_face(v,Face_of[f]);
else set_first_out_edge(v,Edge_of[f]);
mark(v) = m; point(v) = p;
return true;
}
template <typename Decorator_>
void SM_io_parser<Decorator_>::print_edge(Halfedge_handle e) const
{ // syntax: index { twin, prev, next, source, face, mark, circle }
out << index(e) << " { "
<< index(twin(e)) << ", "
<< index(previous(e)) << ", " << index(next(e)) << ", "
<< index(source(e)) << ", " << index(face(e)) << ", "
<< mark(e) << ", " << circle(e) << " }\n";
}
template <typename Decorator_>
bool SM_io_parser<Decorator_>::read_edge(Halfedge_handle e)
{ // syntax: index { twin, prev, next, source, face, mark }
int n, eo, epr, ene, v, f; bool m; Sphere_circle k;
if ( !(in >> n) ||
!check_sep("{") ||
!(in >> eo) || !check_sep(",") ||
!(in >> epr) || !check_sep(",") ||
!(in >> ene) || !check_sep(",") ||
!(in >> v) || !check_sep(",") ||
!(in >> f) || !check_sep(",") ||
!(in >> m) || !check_sep(",") ||
!(in >> k) || !check_sep("}") )
return false;
CGAL_assertion_msg
(eo >= 0 && eo < en && epr >= 0 && epr < en && ene >= 0 && ene < en &&
v >= 0 && v < vn && f >= 0 && f < fn ,
"wrong index in read_edge");
// precond: features exist!
CGAL_assertion(EI[twin(e)]);
set_prev(e,Edge_of[epr]);
set_next(e,Edge_of[ene]);
set_source(e,Vertex_of[v]);
set_face(e,Face_of[f]);
mark(e) = m;
circle(e) = k;
return true;
}
template <typename Decorator_>
void SM_io_parser<Decorator_>::print_loop(Halfloop_handle l) const
{ // syntax: index { twin, face, mark }
out << index(l) << " { "
<< index(twin(l)) << ", "
<< index(face(l)) << ", "
<< mark(l) << ", " << circle(l) << " }\n";
}
template <typename Decorator_>
bool SM_io_parser<Decorator_>::read_loop(Halfloop_handle l)
{ // syntax: index { twin, face, mark }
int n, lo, f; bool m; Sphere_circle k;
if ( !(in >> n) ||
!check_sep("{") ||
!(in >> lo) || !check_sep(",") ||
!(in >> f) || !check_sep(",") ||
!(in >> m) || !check_sep(",") ||
!(in >> k) || !check_sep("}") )
return false;
CGAL_assertion_msg(
(lo >= 0 && lo < 2 && f >= 0 && f < fn),"wrong index in read_edge");
set_face(l,Face_of[f]);
mark(l) = m;
circle(l) = k;
return true;
}
template <typename Decorator_>
void SM_io_parser<Decorator_>::print_face(Face_handle f) const
{ // syntax: index { fclist, ivlist, loop, mark }
out << index(f) << " { ";
Face_cycle_iterator it;
Halfedge_handle e; Vertex_handle v; Halfloop_handle l;
CGAL_forall_face_cycles_of(it,f)
if ( assign(e,it) ) out << index(e) << ' ';
out << ", ";
CGAL_forall_face_cycles_of(it,f)
if ( assign(v,it) ) out << index(v) << ' ';
out << ", ";
CGAL_forall_face_cycles_of(it,f)
if ( assign(l,it) ) out << index(l);
out << ", " << mark(f) << " }\n";
}
template <typename Decorator_>
void SM_io_parser<Decorator_>::print_init_points() const
{
out << mark_of_halfsphere(-1) << " "
<< mark_of_halfsphere(+1) << "\n";
}
template <typename Decorator_>
bool SM_io_parser<Decorator_>::read_face(Face_handle f)
{ // syntax: index { fclist, ivlist, loop, mark }
int n, ei, vi, li; Mark m;
if ( !(in >> n) || !check_sep("{") ) return false;
while (in >> ei) {
CGAL_assertion_msg(ei >= 0 && ei < en, "wrong index in face cycle list.");
store_boundary_object(Edge_of[ei],f);
} in.clear();
if (!check_sep(",")) { return false; }
while (in >> vi) {
CGAL_assertion_msg(vi >= 0 && vi < vn, "wrong index in iso vertex list.");
store_boundary_object(Vertex_of[vi],f);
} in.clear();
if (!check_sep(",")) { return false; }
while (in >> li) {
CGAL_assertion_msg(li >= 0 && li < 2, "wrong index in iso vertex list.");
store_boundary_object(Loop_of[li],f);
} in.clear();
if (!check_sep(",") || !(in >> m) || !check_sep("}") )
return false;
mark(f) = m;
return true;
}
template <typename Decorator_>
bool SM_io_parser<Decorator_>::read_init_points() const
{ Mark m_neg, m_pos;
if ( ! (in >> m_neg >> m_pos) ) return false;
mark_of_halfsphere(-1) = m_neg;
mark_of_halfsphere(+1) = m_pos;
return true;
}
template <typename Decorator_>
void SM_io_parser<Decorator_>::print() const
{
out << "Sphere_map_2" << endl;
out << "vertices " << vn << endl;
out << "edges " << en << endl;
out << "loops " << ln << endl;
out << "faces " << fn << endl;
if (verbose)
out << "/* index { isolated ? face : edge, mark, point } */" << endl;
Vertex_iterator vit;
CGAL_forall_vertices(vit,*this) print_vertex(vit);
if (verbose)
out << "/* index { twin, prev, next, source, face, mark } */" << endl;
Halfedge_iterator eit;
CGAL_forall_halfedges(eit,*this) print_edge(eit);
if (verbose)
out << "/* index { twin, face, mark } */" << endl;
if ( has_loop() )
{ print_loop(halfloop()); print_loop(twin(halfloop())); }
if (verbose)
out << "/* index { fclist, ivlist, loop, mark } */" << endl;
Face_iterator fit;
CGAL_forall_faces(fit,*this) print_face(fit);
if (verbose)
out << "/* mark at y-/y+ */" << endl;
print_init_points();
out.flush();
if (verbose) debug();
}
template <typename Decorator_>
void SM_io_parser<Decorator_>::read()
{
if ( !check_sep("Plane_map_2") )
CGAL_assertion_msg(0,"SM_io_parser::read: no embedded_PM header.");
if ( !(check_sep("vertices") && (in >> vn)) )
CGAL_assertion_msg(0,"SM_io_parser::read: wrong vertex line.");
if ( !(check_sep("edges") && (in >> en) && (en%2==0)) )
CGAL_assertion_msg(0,"SM_io_parser::read: wrong edge line.");
if ( !(check_sep("loops") && (in >> ln)) )
CGAL_assertion_msg(0,"SM_io_parser::read: wrong loop line.");
if ( !(check_sep("faces") && (in >> fn)) )
CGAL_assertion_msg(0,"SM_io_parser::read: wrong face line.");
Vertex_of.reserve(vn);
Edge_of.reserve(en);
Face_of.reserve(fn);
for(i=0; i<vn; i++) Vertex_of[i] = new_vertex();
for(i=0; i<en; i++)
if (i%2==0) Edge_of[i] = new_edge_pair_without_vertices();
else Edge_of[i] = twin(Edge_of[i-1]);
for(i=0; i<fn; i++) Face_of[i] = new_face();
if ( ln == 2 )
{ Loop_of[0] = new_loop(); Loop_of[1] = twin(loop()); }
for(i=0; i<vn; i++) {
if (!read_vertex(Vertex_of[i]))
CGAL_assertion_msg(0,"SM_io_parser::read: error in node line");
}
for(i=0; i<en; i++) {
if (!read_edge(Edge_of[i]))
CGAL_assertion_msg(0,"SM_io_parser::read: error in edge line");
}
if ( ln == 2 ) {
read_loop(Loop_of[0]); read_loop(Loop_of[1]);
}
for(i=0; i<fn; i++) {
if (!read_face(Face_of[i]))
CGAL_assertion_msg(0,"SM_io_parser::read: error in face line");
}
if (!read_init_points())
CGAL_assertion_msg(0,"SM_io_parser::read: error in init point line");
}
//-----------------------------------------------------------------------------
// VERBOSE OUTPUT:
// note that we output the index of the objects which is stored in them
// this is NOT the member index as produced by the forall loops
//-----------------------------------------------------------------------------
template <typename Decorator_>
void SM_io_parser<Decorator_>::debug_vertex(Vertex_handle v) const
{
out << index(v) << "[" << mark(v) << "," << point(v) << "]" << endl;
}
template <typename Decorator_>
void SM_io_parser<Decorator_>::debug_edge(Halfedge_handle e) const
{
out << index(e)
<< "(" << index(source(e)) << "," << index(target(e)) << ") "
<< index(twin(e)) << " " << index(face(e))
<< " ["<< mark(e) << "," << circle(e) << "] " << endl;
}
template <typename Decorator_>
void SM_io_parser<Decorator_>::debug_loop(Halfloop_handle l) const
{
out << index(l) << " "
<< index(twin(l)) << " " << index(face(l))
<< " ["<< mark(l) << "] " << circle(l) << endl;
}
template <typename Decorator_>
void SM_io_parser<Decorator_>::debug() const
{
out << "\nDEBUG Plane_map\n";
out << "Vertices: " << number_of_vertices() << "\n";
out << "Halfedges: " << number_of_halfedges() << "\n";
out << "Loop: " << number_of_halfloops() << "\n";
Vertex_iterator vit;
CGAL_forall_vertices(vit,*this) {
if ( is_isolated(vit) ) continue;
typename Base::Halfedge_around_vertex_circulator
hcirc = out_edges(vit), hend = hcirc;
debug_vertex(vit);
CGAL_For_all(hcirc,hend) { out << " "; debug_edge(hcirc); }
}
if ( has_loop() )
{ debug_loop(halfloop()); debug_loop(twin(halfloop())); }
out << std::endl;
}
template <typename Decorator_>
void SM_io_parser<Decorator_>::print_faces() const
{
out << "\nFACES\n";
out << "Vertices: " << number_of_vertices() << "\n";
out << "Halfedges: " << number_of_halfedges() << "\n";
out << "Loop: " << number_of_halfloops() << "\n";
Halfedge_iterator e;
Unique_hash_map<Halfedge_iterator,bool> Done(false);
CGAL_forall_halfedges(e,*this) {
if ( Done[e] ) continue;
typename Base::Halfedge_around_face_circulator c(e), ce = c;
out << "face cycle\n";
CGAL_For_all(c,ce)
{ Done[c]=true; out << " "; debug_vertex(source(c)); }
}
if ( has_loop() )
{ debug_loop(halfloop()); debug_loop(twin(halfloop())); }
out << std::endl;
}
template <typename Decorator_>
void SM_io_parser<Decorator_>::dump(const Decorator_& D, std::ostream& os)
{ SM_io_parser<Decorator_> Out(os,D);
Out.print();
Out.print_faces();
}
CGAL_END_NAMESPACE
#endif //CGAL_SM_IO_PARSER_H

View File

@ -0,0 +1,251 @@
#ifndef CGAL_SM_ITEMS_H
#define CGAL_SM_ITEMS_H
#include <CGAL/basic.h>
#include <CGAL/In_place_list.h>
#include <CGAL/Object.h>
#include <string>
#include <strstream>
CGAL_BEGIN_NAMESPACE
template <typename K, typename M> class SM_items;
template <typename K> class Sphere_map;
template <typename SM, typename K> class SM_const_decorator;
template <typename SM, typename K> class SM_decorator;
template <typename EH> struct move_edge_around_vertex;
template <typename EH> struct move_edge_around_face;
template <typename Kernel_, typename Mark_>
struct SM_items {
public:
typedef Kernel_ Kernel;
typedef typename Kernel::Sphere_point Sphere_point;
typedef typename Kernel::Sphere_segment Sphere_segment;
typedef typename Kernel::Sphere_circle Sphere_circle;
typedef Mark_ Mark;
typedef SM_items<Kernel_,Mark_> Self;
typedef void* GenPtr;
template <typename Refs>
class Vertex : public CGAL::In_place_list_base< Vertex<Refs> >
{
typedef typename Refs::Items Items;
friend class Sphere_map<Kernel_>;
friend class SM_const_decorator<Refs,Kernel_>;
friend class SM_decorator<Refs,Kernel_>;
typedef typename Refs::Vertex_handle Vertex_handle;
typedef typename Refs::Halfedge_handle Halfedge_handle;
typedef typename Refs::Face_handle Face_handle;
Sphere_point point_;
Mark mark_;
Halfedge_handle edge_;
Face_handle face_;
GenPtr info_;
// temporary information:
public:
Vertex() :
point_(), mark_(), edge_(), face_(), info_() {}
Vertex(const Mark& m) :
point_(), mark_(m), edge_(), face_(), info_() {}
Vertex(const Sphere_point& p) :
point_(p), mark_(), edge_(), face_(), info_() {}
~Vertex() {}
Vertex(const Vertex<Refs>& v)
{ point_ = v.point_;
mark_ = v.mark_;
edge_ = v.edge_;
face_ = v.face_;
info_ = 0;
}
Vertex<Refs>& operator=(const Vertex<Refs>& v)
{ point_ = v.point_;
mark_ = v.mark_;
edge_ = v.edge_;
face_ = v.face_;
info_ = 0;
return *this;
}
public:
std::string debug() const
{ std::ostrstream os; set_pretty_mode(os);
os<<"V"<<point_<<' '<<info_<<'\0';
std::string res(os.str()); os.freeze(0); return res;
}
}; // Vertex
template <typename Refs>
class Halfedge : public CGAL::In_place_list_base< Halfedge<Refs> >
{
typedef typename Refs::Items Items;
typedef typename Refs::Vertex_handle Vertex_handle;
typedef typename Refs::Halfedge_handle Halfedge_handle;
typedef typename Refs::Halfedge_const_handle Halfedge_const_handle;
typedef typename Refs::Face_handle Face_handle;
friend class Sphere_map<Kernel_>;
friend class SM_const_decorator<Refs,Kernel_>;
friend class SM_decorator<Refs,Kernel_>;
friend class move_edge_around_vertex<Halfedge_handle>;
friend class move_edge_around_face<Halfedge_handle>;
friend class move_edge_around_vertex<Halfedge_const_handle>;
friend class move_edge_around_face<Halfedge_const_handle>;
// Role within local graph:
Sphere_circle circle_;
Mark mark_;
Halfedge_handle twin_, prev_, next_;
Vertex_handle source_;
Face_handle face_;
GenPtr info_;
public:
Halfedge() : circle_(), mark_(), twin_(), prev_(), next_(),
source_(), face_(), info_() {}
~Halfedge() {}
Halfedge(const Halfedge<Refs>& e)
{
circle_ = e.circle_;
mark_ = e.mark_;
twin_ = e.twin_;
prev_ = e.prev_;
next_ = e.next_;
source_ = e.source_;
face_ = e.face_;
info_ = 0;
}
Halfedge<Refs>& operator=(const Halfedge<Refs>& e)
{
circle_ = e.circle_;
mark_ = e.mark_;
twin_ = e.twin_;
prev_ = e.prev_;
next_ = e.next_;
source_ = e.source_;
face_ = e.face_;
info_ = 0;
return *this;
}
std::string debug() const
{ std::ostrstream os; set_pretty_mode(os);
os <<"e["<<source_->debug()<<", "
<<twin_->source_->debug()<<" "<<info_<<"]"<<'\0';
std::string res(os.str()); os.freeze(0); return res;
}
}; // Halfedge
template <typename Refs>
class Halfloop : public CGAL::In_place_list_base< Halfloop<Refs> >
{
typedef typename Refs::Halfloop_handle Halfloop_handle;
typedef typename Refs::Face_handle Face_handle;
typedef typename Refs::Items Items;
friend class Sphere_map<Kernel_>;
friend class SM_const_decorator<Refs,Kernel_>;
friend class SM_decorator<Refs,Kernel_>;
friend class Self::Vertex<Refs>;
Sphere_circle circle_;
Mark mark_;
Halfloop_handle twin_;
Face_handle face_;
GenPtr info_;
// temporary needed:
public:
Halfloop() : circle_(), mark_(), twin_(), face_(), info_() {}
~Halfloop() {}
Halfloop(const Halfloop<Refs>& l)
{
circle_ = l.circle_;
mark_ = l.mark_;
twin_ = l.twin_;
face_ = l.face_;
info_ = 0;
}
Halfloop<Refs>& operator=(const Halfloop<Refs>& l)
{
circle_ = l.circle_;
mark_ = l.mark_;
twin_ = l.twin_;
face_ = l.face_;
info_ = 0;
return *this;
}
std::string debug() const
{ std::ostrstream os; set_pretty_mode(os);
os<<"l"<<circle_<<' '<<info_<<'\0';
std::string res(os.str()); os.freeze(0); return res;
}
}; // Halfloop
template <typename Refs>
class Face : public CGAL::In_place_list_base< Face<Refs> >
{
typedef typename Refs::Items Items;
friend class Sphere_map<Kernel_>;
friend class SM_const_decorator<Refs,Kernel_>;
friend class SM_decorator<Refs,Kernel_>;
typedef typename Refs::Object_handle Object_handle;
typedef typename Refs::Object_list Object_list;
typedef typename Refs::Face_cycle_iterator Face_cycle_iterator;
typedef typename Refs::Face_cycle_const_iterator
Face_cycle_const_iterator;
Mark mark_;
Object_list boundary_; // Halfedges, Halfloops, Vertices
GenPtr info_;
// temporary needed:
public:
Face() : mark_(), info_() {}
~Face() {}
Face(const Face<Refs>& f)
{ mark_ = f.mark_;
boundary_ = f.boundary_;
info_ = 0;
}
Face<Refs>& operator=(const Face<Refs>& f)
{ if (this == &f) return *this;
mark_ = f.mark_;
boundary_ = f.boundary_;
info_ = 0;
return *this;
}
Face_cycle_iterator face_cycles_begin()
{ return boundary_.begin(); }
Face_cycle_iterator face_cycles_end()
{ return boundary_.end(); }
Face_cycle_const_iterator face_cycles_begin() const
{ return boundary_.begin(); }
Face_cycle_const_iterator face_cycles_end() const
{ return boundary_.end(); }
}; // Face
}; // SM_items
CGAL_END_NAMESPACE
#endif // CGAL_SM_ITEMS_H

View File

@ -0,0 +1,23 @@
#ifndef CGAL_SM_ITERATION_H
#define CGAL_SM_ITERATION_H
#define CGAL_forall_iterators(x,S)\
for(x = S.begin(); x != S.end(); ++x)
#define CGAL_forall_vertices(x,SM)\
for(x = (SM).vertices_begin(); x != (SM).vertices_end(); ++x)
#define CGAL_forall_halfedges(x,SM)\
for(x = (SM).halfedges_begin(); x != (SM).halfedges_end(); ++x)
#define CGAL_forall_halfloops(x,SM)\
for(x = (SM).halfloops_begin(); x != (SM).halfloops_end(); ++x)
#define CGAL_forall_faces(x,SM)\
for(x = (SM).faces_begin(); x != (SM).faces_end(); ++x)
#define CGAL_forall_face_cycles_of(x,F)\
for(x = (F)->face_cycles_begin(); x != (F)->face_cycles_end(); ++x)
#endif //CGAL_SM_ITERATION_H

View File

@ -0,0 +1,453 @@
// ============================================================================
//
// Copyright (c) 1997-2000 The CGAL Consortium
//
// This software and related documentation is part of an INTERNAL release
// of the Computational Geometry Algorithms Library (CGAL). It is not
// intended for general use.
//
// ----------------------------------------------------------------------------
//
// release : $CGAL_Revision$
// release_date : $CGAL_Date$
//
// file : include/CGAL/Nef_S2/SM_point_locator.h
// package : Nef_S2
// chapter : Nef Polyhedra
//
// revision : $Revision$
// revision_date : $Date$
//
// author(s) : Michael Seel <seel@mpi-sb.mpg.de>
// maintainer : Michael Seel <seel@mpi-sb.mpg.de>
// coordinator : Michael Seel <seel@mpi-sb.mpg.de>
//
// implementation: Point location module
// ============================================================================
#ifndef CGAL_SM_POINT_LOCATOR_H
#define CGAL_SM_POINT_LOCATOR_H
#include <CGAL/basic.h>
#include <CGAL/Unique_hash_map.h>
#include <CGAL/Object.h>
#include <CGAL/Nef_2/geninfo.h>
#undef _DEBUG
#define _DEBUG 143
#include <CGAL/Nef_S2/debug.h>
CGAL_BEGIN_NAMESPACE
/*{\Moptions print_title=yes }*/
/*{\Manpage {SM_point_locator}{Decorator}
{Naive point location in plane maps}{PL}}*/
/*{\Mdefinition An instance |\Mvar| of data type |\Mname|
encapsulates naive point location queries within a sphere map |M|. The
two template parameters are specified via concepts. |PM_decorator_|
must be a model of the concept |PMDecorator| as described in the
appendix. |Geometry_| must be a model of the concept
|AffineGeometryTraits_2| as described in the appendix. For a
specification of plane maps see also the concept of
|PMConstDecorator|.}*/
/*{\Mgeneralization Decorator}*/
template <typename Decorator_>
class SM_point_locator : public Decorator_ {
protected:
typedef Decorator_ Base;
typedef SM_point_locator<Decorator_> Self;
public:
/*{\Mtypes 5}*/
typedef Decorator_ Decorator;
/*{\Mtypemember equals |Decorator_|.}*/
typedef typename Decorator::Sphere_map Sphere_map;
/*{\Mtypemember the sphere map type decorated by |Decorator|.}*/
typedef typename Decorator::Mark Mark;
/*{\Mtypemember the attribute of all objects (vertices, edges, loops,
faces).}*/
typedef typename Decorator::Kernel Kernel;
/*{\Mtypemember the sphere kernel.}*/
typedef typename Kernel::Sphere_point Sphere_point;
/*{\Mtypemember points.}*/
typedef typename Kernel::Sphere_segment Sphere_segment;
/*{\Mtypemember segments.}*/
typedef typename Kernel::Sphere_circle Sphere_circle;
/*{\Mtypemember circles.}*/
typedef typename Kernel::Sphere_direction Sphere_direction;
/*{\Mtypemember directions.}*/
/*{\Mtext Local types are handles, iterators and circulators of the
following kind: |Vertex_const_handle|, |Vertex_const_iterator|,
|Halfedge_const_handle|, |Halfedge_const_iterator|,
|Halfloop_const_handle|, |Halfloop_const_iterator|,
|Face_const_handle|, |Face_const_iterator|.}*/
typedef typename Sphere_map::Object_handle Object_handle;
/*{\Mtypemember a generic handle to an object of the underlying plane
map. The kind of the object |(vertex, halfedge,face)| can be determined and
the object assigned by the three functions:\\
|bool assign(Vertex_const_handle& h, Object_handle o)|\\
|bool assign(Halfedge_const_handle& h, Object_handle o)|\\
|bool assign(Face_const_handle& h, Object_handle o)|\\ where each
function returns |true| iff the assignment of |o| to |h| was valid.}*/
#define USING(t) typedef typename Decorator_::t t
USING(Vertex_handle);
USING(Halfedge_handle);
USING(Halfloop_handle);
USING(Face_handle);
USING(Vertex_const_handle);
USING(Halfedge_const_handle);
USING(Halfloop_const_handle);
USING(Face_const_handle);
USING(Vertex_iterator);
USING(Halfedge_iterator);
USING(Halfloop_iterator);
USING(Face_iterator);
USING(Vertex_const_iterator);
USING(Halfedge_const_iterator);
USING(Halfloop_const_iterator);
USING(Face_const_iterator);
USING(Halfedge_around_vertex_circulator);
USING(Halfedge_around_vertex_const_circulator);
USING(Halfedge_around_face_circulator);
USING(Halfedge_around_face_const_circulator);
#undef USING
Sphere_segment segment(Halfedge_const_handle e) const
{ return Sphere_segment(point(source(e)), point(target(e)), circle(e)); }
Sphere_direction direction(Halfedge_const_handle e) const
{ return Sphere_direction(circle(e)); }
Halfedge_const_handle out_wedge(Vertex_const_handle v,
const Sphere_direction& d, bool& collinear) const
/*{\Xop returns a halfedge |e| bounding a wedge in between two
neighbored edges in the adjacency list of |v| which contains |d|.
If |d| extends along a edge then |e| is this edge. If |d| extends
into the interior of such a wedge then |e| is the first edge hit
when |d| is rotated clockwise. \precond |v| is not isolated.}*/
{ TRACEN("out_wedge "<<PH(v));
assert(!is_isolated(v));
collinear=false;
Sphere_point p = point(v);
Halfedge_const_handle e_res = first_out_edge(v);
Sphere_direction d_res = direction(e_res);
Halfedge_around_vertex_const_circulator el(e_res),ee(el);
CGAL_For_all(el,ee) {
if ( strictly_ordered_ccw_at(p,d_res, direction(el), d) )
e_res = el; d_res = direction(e_res);
}
TRACEN(" determined "<<PH(e_res)<<" "<<d_res);
if ( direction(cyclic_adj_succ(e_res)) == d ) {
e_res = cyclic_adj_succ(e_res);
collinear=true;
}
TRACEN(" wedge = "<<PH(e_res)<<" "<<collinear);
return e_res;
}
template <class Handle>
Object_handle make_object(Handle h) const
{ return CGAL::make_object(h); }
/*{\Mcreation 3}*/
SM_point_locator() : Base() {}
/*{\Moptions constref=yes}*/
SM_point_locator(const Sphere_map& M) :
Base(const_cast<Sphere_map&>(M)) {}
/*{\Mcreate constructs a point locator working on |P|.}*/
/*{\Moptions constref=no}*/
/*{\Moperations 2.5 0.5}*/
const Mark& mark(Object_handle h) const
/*{\Mop returns the mark associated to the object |h|.}*/
{ Vertex_const_handle v;
Halfedge_const_handle e;
Face_const_handle f;
if ( assign(v,h) ) return mark(v);
if ( assign(e,h) ) return mark(e);
if ( assign(f,h) ) return mark(f);
CGAL_assertion_msg(0,
"PM_point_locator::mark: Object_handle holds no object.");
}
enum SOLUTION { is_vertex_, is_edge_, is_loop_ };
// enumeration for internal use
Object_handle locate(const Sphere_point& p) const
/*{\Mop returns a generic handle |h| to an object (vertex, halfedge,
face) of the underlying plane map |P| which contains the point |p =
s.source()| in its relative interior. |s.target()| must be a point
such that |s| intersects the $1$-skeleton of |P|.}*/
{ TRACEN("locate naivly "<<p);
Vertex_const_iterator v;
CGAL_forall_vertices(v,*this) {
if ( p == point(v) ) return make_object(v);
}
Halfedge_const_iterator e;
CGAL::Unique_hash_map<Halfedge_const_handle,bool> visited(false);
CGAL_forall_halfedges(e,*this) {
if ( visited[e] ) continue;
if ( segment(e).has_on(p) ) return make_object(e);
visited[e]=visited[twin(e)]=true;
}
if ( has_loop() && circle(halfloop()).has_on(p) )
return make_object(Halfloop_const_handle(halfloop()));
// now in face:
if ( number_of_vertices() == 0 && ! has_loop() )
return make_object(faces_begin());
Vertex_const_handle v_res;
Halfedge_const_handle e_res;
Halfloop_const_handle l_res;
SOLUTION solution;
Sphere_segment s; // we shorten the segment iteratively
if ( has_loop() ) {
Sphere_circle c(circle(halfloop()),p); // orthogonal through p
s = Sphere_segment(p,intersection(c,circle(halfloop())));
l_res = circle(halfloop()).has_on_positive_side(p) ?
halfloop() : twin(halfloop());
solution = is_loop_;
} else { // has vertices !
CGAL_assertion( number_of_vertices()!=0 );
Vertex_const_handle vt = vertices_begin();
Sphere_point pvt = point(vt);
if ( p != pvt.opposite() ) s = Sphere_segment(p,pvt);
else s = Sphere_segment(p,pvt,Sphere_circle(p,pvt));
v_res = vt;
solution = is_vertex_;
}
// s now initialized
Sphere_direction dso(s.sphere_circle().opposite()), d_res;
visited.clear(false);
CGAL_forall_vertices(v,*this) {
Sphere_point p_res, vp = point(v);
if ( s.has_on(vp) ) {
TRACEN(" location via vertex at "<<vp);
s = Sphere_segment(p,vp,s.sphere_circle()); // we shrink the segment
if ( is_isolated(v) ) {
v_res = v; solution = is_vertex_;
} else { // not isolated
bool dummy;
e_res = out_wedge(v,dso,dummy);
Halfedge_around_vertex_const_circulator el(e_res),ee(el);
CGAL_For_all(el,ee)
visited[el] = visited[twin(el)] = true;
/* e_res is now the counterclockwise maximal halfedge out
of v just before s */
if ( circle(e_res).has_on_negative_side(p) )
e_res = previous(e_res);
// correction to make e_res visible from p
solution = is_edge_;
TRACEN(" determined "<<PH(e_res));
}
}
}
CGAL_forall_halfedges(e,*this) {
if ( visited[e] ) continue;
Sphere_segment se = segment(e);
Sphere_point p_res;
if ( do_intersect_internally(se,s,p_res) ) {
TRACEN(" location via halfedge "<<se);
s = Sphere_segment(p,p_res,s.sphere_circle());
e_res = ( circle(e).has_on_positive_side(p) ? e : twin(e) );
visited[e] = visited[twin(e)] = true;
solution = is_edge_;
TRACEN(" determined "<<PH(e_res)<<" "<<mark(face(e_res)));
}
}
switch ( solution ) {
case is_edge_:
return make_object((Face_const_handle)(face(e_res)));
case is_loop_:
return make_object((Face_const_handle)(face(l_res)));
case is_vertex_:
return make_object((Face_const_handle)(face(v_res)));
default: CGAL_assertion_msg(0,"missing solution.");
}
return Object_handle(); // never reached!
}
template <typename Object_predicate>
Object_handle ray_shoot(const Sphere_point& p,
const Sphere_direction& d,
const Object_predicate& M) const
/*{\Mop returns an |Object_handle o| which can be converted to a
|Vertex_const_handle|, |Halfedge_const_handle|, |Face_const_handle|
|h| as described above. The object predicate |M| has to have
function operators \\ |bool operator() (const
Vertex_/Halfedge_/Halfloop_/Face_const_handle&)|.\\ The object
returned is intersected by |d.circle()|, has minimal distance to
|p|, and |M(h)| holds on the converted object. The operation returns
the null handle |NULL| if the ray shoot along |s| does not hit any
object |h| of |M| with |M(h)|.}*/
{
Sphere_circle c(d.circle());
Sphere_segment s;
bool s_init(false);
Object_handle h = locate(p);
Vertex_const_handle v;
Halfedge_const_handle e;
Halfloop_const_handle l;
Face_const_handle f;
if ( assign(v,h) && M(v) ||
assign(e,h) && M(e) ||
assign(l,h) && M(l) ||
assign(f,h) && M(f) ) return h;
h = Object_handle();
TRACEN("not contained");
#if 0
HASEN: s am anfang circle, ab wann segment ?
wo loop ?
CGAL_forall_vertices (v,*this) {
Point pv = point(v);
if ( !(s_init && s.has_on(pv) ||
!s_init && c.has_on(pv)) ) continue;
TRACEN("candidate "<<pv);
if ( M(v) ) {
h = make_object(v); // store vertex
s = Sphere_segment(p,pv,c); // shorten
continue;
}
// now we know that v is not marked but on s
bool collinear;
Halfedge_const_handle e = out_wedge(v,d,collinear);
if ( collinear ) {
if ( M(e) ) {
h = make_object(e);
s = Sphere_segment(p,pv,c);
}
continue;
}
if ( M(face(e)) ) {
h = make_object(face(e));
s = Sphere_segment(p,pv,c);
}
} // all vertices
CGAL::Unique_hash_map<Halfedge_const_handle,bool> visited(false);
Halfedge_const_iterator e_res;
CGAL_forall_halfedges(e,*this) {
Sphere_segment se = segment(e);
Sphere_point p_res;
if ( do_intersect_internally(se,s,p_res) ) {
// internal intersection
TRACEN("candidate "<<se);
e_res = e;
Sphere_segment s_cand = Sphere_segment(p,p_res,c);
if ( s_cand.is_short() && circle(e).has_on_negative_side(p) ||
s_cand.is_long() && circle(e).has_on_positive_side(p) ||
s_cand.is_halfcircle() &&
strictly_ordered_ccw_at(p.opposite(),
direction(e),d,direction(twin(e))) )
e_res = twin(e);
if ( M(e_res) ) {
h = make_object(e_res); s = s_cand;
} else if ( M(face(twin(e_res))) ) {
h = make_object(face(twin(e_res))); s = s_cand;
}
}
}
#endif
CGAL_assertion_msg(0,"not yet correct");
return h;
}
void init_marks_of_halfspheres();
// C++ is really friendly:
#define USECMARK(t) const Mark& mark(t h) const { return Base::mark(h); }
#define USEMARK(t) Mark& mark(t h) const { return Base::mark(h); }
USEMARK(Vertex_handle)
USEMARK(Halfedge_handle)
USEMARK(Face_handle)
USECMARK(Vertex_const_handle)
USECMARK(Halfedge_const_handle)
USECMARK(Face_const_handle)
#undef USEMARK
#undef USECMARK
/*{\Mimplementation Naive query operations are realized by checking
the intersection points of the $1$-skeleton of the plane map |P| with
the query segments $s$. This method takes time linear in the size $n$
of the underlying plane map without any preprocessing.}*/
}; // SM_point_locator<Decorator_>
template <typename D>
void SM_point_locator<D>::init_marks_of_halfspheres()
{ TRACEN("init_marks_of_halfspheres");
Sphere_point y_minus(0,-1,0);
Object_handle h = locate(y_minus);
Face_const_handle f;
if ( CGAL::assign(f,h) ) {
mark_of_halfsphere(-1) = mark_of_halfsphere(+1) = mark(f);
return;
}
Halfedge_const_handle e;
if ( CGAL::assign(e,h) ) {
CGAL_assertion(circle(e).has_on(y_minus));
Sphere_point op(CGAL::ORIGIN+circle(e).orthogonal_vector());
TRACEN("on edge "<<op);
if ( (op.x() > 0) || (op.x() == 0) && (op.z() < 0) ) e = twin(e);
// if ( (op.z() < 0) || (op.z() == 0) && (op.x() > 0) ) e = twin(e);
mark_of_halfsphere(+1) = mark(face(e));
mark_of_halfsphere(-1) = mark(face(twin(e)));
return;
}
Halfloop_const_handle l;
if ( CGAL::assign(l,h) ) {
CGAL_assertion(circle(l).has_on(y_minus));
Sphere_point op(CGAL::ORIGIN+circle(l).orthogonal_vector());
TRACEN("on loop "<<op);
if ( (op.x() > 0) || (op.x() == 0) && (op.z() < 0) ) l = twin(l);
// if ( (op.z() < 0) || (op.z() == 0) && (op.x() > 0) ) l = twin(l);
mark_of_halfsphere(+1) = mark(face(l));
mark_of_halfsphere(-1) = mark(face(twin(l)));
return;
}
//Sphere_circle c(-1,0,0);
//Sphere_direction up(c),down(c.opposite());
Sphere_circle c(0,0,1);
Sphere_direction right(c),left(c.opposite());
bool collinear(false);
Vertex_const_handle v;
if ( CGAL::assign(v,h) ) {
CGAL_assertion(point(v)==y_minus);
e = out_wedge(v,left,collinear);
if ( collinear ) mark_of_halfsphere(+1) = mark(face(twin(e)));
else mark_of_halfsphere(+1) = mark(face(e));
e = out_wedge(v,right,collinear);
if ( collinear ) mark_of_halfsphere(-1) = mark(face(twin(e)));
else mark_of_halfsphere(-1) = mark(face(e));
return;
}
CGAL_assertion_msg(0,"damn wrong type.");
}
CGAL_END_NAMESPACE
#endif // CGAL_SM_POINT_LOCATOR_H

View File

@ -0,0 +1,674 @@
// ============================================================================
//
// Copyright (c) 1997-2000 The CGAL Consortium
//
// This software and related documentation is part of an INTERNAL release
// of the Computational Geometry Algorithms Library (CGAL). It is not
// intended for general use.
//
// ----------------------------------------------------------------------------
//
// release : $CGAL_Revision$
// release_date : $CGAL_Date$
//
// file : include/CGAL/Nef_S2/SM_triagulator.h
// package : Nef_S2
// chapter : Nef Polyhedra
//
// revision : $Revision$
// revision_date : $Date$
//
// author(s) : Michael Seel <seel@mpi-sb.mpg.de>
// maintainer : Michael Seel <seel@mpi-sb.mpg.de>
// coordinator : Michael Seel <seel@mpi-sb.mpg.de>
//
// implementation: Triangulation module for sphere maps
// ============================================================================
#ifndef CGAL_SM_TRIANGULATOR_H
#define CGAL_SM_TRIANGULATOR_H
#include <CGAL/basic.h>
#include <CGAL/Partition.h>
#include <CGAL/Unique_hash_map.h>
#include <CGAL/Nef_2/Segment_overlay_traits.h>
#include <CGAL/Nef_2/geninfo.h>
#include <CGAL/Nef_S2/SM_decorator.h>
#include <CGAL/Nef_S2/SM_io_parser.h>
#include <CGAL/Nef_S2/SM_constrained_triang_traits.h>
#undef _DEBUG
#define _DEBUG 137
#include <CGAL/Nef_S2/debug.h>
#define USING(t) typedef typename Base::t t
#ifndef CGAL_USE_LEDA
#define LEDA_MEMORY(t)
#endif
CGAL_BEGIN_NAMESPACE
template <typename Decorator_, typename IT, typename INFO>
struct SM_subdivision {
typedef Decorator_ Triangulator;
typedef typename Decorator_::Explorer Explorer;
typedef typename Decorator_::Vertex_handle Vertex_handle;
typedef typename Decorator_::Halfedge_handle Halfedge_handle;
typedef typename Decorator_::Sphere_point Point;
typedef typename Decorator_::Sphere_segment Segment;
Triangulator T;
Explorer E;
CGAL::Unique_hash_map<IT,INFO>& M;
/* M stores the object that supports the segment that
is input object of the sweep */
SM_subdivision(Triangulator Ti, Explorer Ei,
CGAL::Unique_hash_map<IT,INFO>& Mi) :
T(Ti), E(Ei), M(Mi) {}
Vertex_handle new_vertex(const Point& p) const
{ Vertex_handle v = T.new_vertex(p); T.assoc_info(v);
return v;
}
void link_as_target_and_append(Vertex_handle v, Halfedge_handle e) const
{ T.link_as_target_and_append(v,e); }
Halfedge_handle new_halfedge_pair_at_source(Vertex_handle v) const
{ Halfedge_handle e =
T.new_edge_pair_at_source(v,Decorator_::BEFORE);
T.assoc_info(e);
return e;
}
void halfedge_below(Vertex_handle v, Halfedge_handle e) const
{ T.halfedge_below(v) = e; }
/* the following operation associates segment support with
halfedges, we only update if non-NULL; this prevents
artificial sphere subdivision segments that have NULL
support to overwrite non-NULL support */
void supporting_segment(Halfedge_handle e, IT it) const
{ T.is_forward(e) = true;
if ( M[it] != NULL ) T.support(e) = M[it]; }
/* the following operation associate segment support with
vertices, we only update if non-NULL; this prevents
artificial segments that have NULL support to overwrite
non-NULL support */
void trivial_segment(Vertex_handle v, IT it) const
{ if ( M[it] != NULL ) T.support(v) = M[it]; }
void starting_segment(Vertex_handle v, IT it) const
{ if ( M[it] != NULL ) T.support(v) = M[it]; }
void ending_segment(Vertex_handle v, IT it) const
{ if ( M[it] != NULL ) T.support(v) = M[it]; }
void passing_segment(Vertex_handle v, IT it) const
{ if ( M[it] != NULL ) T.support(v) = M[it]; }
}; // SM_subdivision
/*{\Manpage {SM_triangulator}{Decorator_}{Overlay in the sphere}{O}}*/
template <typename Decorator_>
class SM_triangulator : public Decorator_ {
public:
/*{\Mdefinition An instance |\Mvar| of data type |\Mname| is a
decorator object offering sphere map triangulation calculation.}*/
typedef Decorator_ Base;
typedef typename Decorator_::Base Explorer;
typedef Decorator_ Decorator;
typedef SM_triangulator<Decorator_> Self;
USING(Vertex_handle);
USING(Halfedge_handle);
USING(Halfloop_handle);
USING(Face_handle);
USING(Vertex_iterator);
USING(Halfedge_iterator);
USING(Face_iterator);
USING(Vertex_const_handle);
USING(Halfedge_const_handle);
USING(Halfloop_const_handle);
USING(Face_const_handle);
USING(Vertex_const_iterator);
USING(Halfedge_const_iterator);
USING(Face_const_iterator);
USING(Object_handle);
USING(Halfedge_around_vertex_circulator);
USING(Halfedge_around_face_circulator);
USING(Sphere_map);
typedef std::pair<Halfedge_handle,Halfedge_handle> Halfedge_pair;
/*{\Mtypes 3}*/
typedef typename Base::Kernel Kernel;
typedef typename Kernel::Sphere_point Sphere_point;
/*{\Mtypemember the point type of the sphere geometry.}*/
typedef typename Kernel::Sphere_segment Sphere_segment;
/*{\Mtypemember the segment type of the sphere geometry.}*/
typedef typename Kernel::Sphere_circle Sphere_circle;
/*{\Mtypemember the circle type of the sphere geometry.}*/
typedef typename Kernel::Sphere_triangle Sphere_triangle;
/*{\Mtypemember the triangle type of the sphere geometry.}*/
typedef typename Decorator::Mark Mark;
/*{\Mtypemember the mark of sphere map objects.}*/
/*{\Mgeneralization Decorator_}*/
protected:
Explorer E_;
const Kernel& K;
public:
typedef std::list<Sphere_segment> Seg_list;
typedef typename Seg_list::iterator Seg_iterator;
typedef std::pair<Seg_iterator,Seg_iterator> Seg_it_pair;
typedef std::pair<Sphere_segment,Sphere_segment> Seg_pair;
typedef CGAL::Unique_hash_map<Seg_iterator,Object_handle> Seg_map;
// vertex_info stores the origin of vertices
struct vertex_info {
Object_handle o_;
Halfedge_handle e_;
vertex_info() : o_(),e_() {}
LEDA_MEMORY(vertex_info)
};
void assoc_info(Vertex_handle v) const
{ geninfo<vertex_info>::create(info(v)); }
void discard_info(Vertex_handle v) const
{ geninfo<vertex_info>::clear(info(v)); }
vertex_info& ginfo(Vertex_handle v) const
{ return geninfo<vertex_info>::access(info(v)); }
Object_handle& support(Vertex_handle v) const
{ return ginfo(v).o_; }
Halfedge_handle& halfedge_below(Vertex_handle v) const
{ return ginfo(v).e_; }
// edge_info stores the origin of edges
struct edge_info {
Mark m_left_; Object_handle o_; bool forw_;
edge_info() { m_left_=Mark(); o_=Object_handle(); forw_=false; }
LEDA_MEMORY(edge_info)
};
void assoc_info(Halfedge_handle e) const
{ geninfo<edge_info>::create(info(e));
geninfo<edge_info>::create(info(twin(e))); }
void discard_info(Halfedge_handle e) const
{ geninfo<edge_info>::clear(info(e));
geninfo<edge_info>::clear(info(twin(e))); }
edge_info& ginfo(Halfedge_handle e) const
{ return geninfo<edge_info>::access(info(e)); }
Object_handle& support(Halfedge_handle e) const
// uedge information we store in the smaller one
{ if (&*e < &*(twin(e))) return ginfo(e).o_;
else return ginfo(twin(e)).o_; }
Mark& incident_mark(Halfedge_handle e) const
// biedge information we store in the edge
{ return ginfo(e).m_left_; }
const edge_info& ginfo(Halfedge_const_handle e) const
{ return geninfo<edge_info>::const_access(info(e)); }
const Mark& incident_mark(Halfedge_const_handle e) const
{ return ginfo(e).m_left_; }
bool& is_forward(Halfedge_handle e) const
// biedge information we store in the edge
{ return ginfo(e).forw_; }
void assert_equal_marks(Vertex_handle v1, Vertex_handle v2) const
{ CGAL_assertion(mark(v1)==mark(v2)); }
void assert_equal_marks(Halfedge_handle e1, Halfedge_handle e2) const
{ CGAL_assertion(mark(e1)==mark(e2)); }
Sphere_segment segment(Explorer N,
Halfedge_const_handle e) const
{ return Sphere_segment(
N.point(N.source(e)),N.point(N.target(e)),N.circle(e)); }
Sphere_segment trivial_segment(Explorer N,
Vertex_const_handle v) const
{ Sphere_point p = N.point(v);
return Sphere_segment(p,p); }
Seg_pair two_segments(Explorer N,
Halfedge_const_handle e) const
// we know that source(e)==target(e)
{ return N.circle(e).split_at(N.point(N.source(e))); }
Seg_pair two_segments(Explorer N,
Halfloop_const_handle l) const
{ return N.circle(l).split_at_xy_plane(); }
Mark& mark(Vertex_handle h) const
{ return Base::mark(h); }
Mark& mark(Halfedge_handle h) const
{ return Base::mark(h); }
Mark& mark(Halfloop_handle h) const
{ return Base::mark(h); }
Mark& mark(Face_handle h) const
{ return Base::mark(h); }
const Mark& mark(Vertex_const_handle h) const
{ return Base::mark(h); }
const Mark& mark(Halfedge_const_handle h) const
{ return Base::mark(h); }
const Mark& mark(Halfloop_const_handle h) const
{ return Base::mark(h); }
const Mark& mark(Face_const_handle h) const
{ return Base::mark(h); }
/*{\Mcreation 6}*/
SM_triangulator(const Sphere_map& M, Sphere_map& MT,
const Kernel& Kr = Kernel()) :
Base(MT), E_(const_cast<Sphere_map&>(M)), K(Kr) {}
/*{\Mcreate |\Mvar| is a triangulator object for the map |M|,
stores the triangulation in |MT|.}*/
/*{\Moperations 1.1 1}*/
void triangulate();
/*{\Mop produces a triangulated sphere map.}*/
void triangulate_per_hemisphere(Vertex_iterator start, Vertex_iterator end);
template <typename Iterator, typename T>
void partition_to_halfsphere(Iterator start, Iterator end,
Seg_list& L, CGAL::Unique_hash_map<Iterator,T>& M, int pos) const;
void merge_halfsphere_maps(Vertex_handle v1, Vertex_handle v2) const;
void merge_nodes(Halfedge_handle e1, Halfedge_handle e2) const;
void complete_support(Vertex_iterator v_start, Vertex_iterator v_end,
int pos) const;
void correct_triangle_at(Vertex_handle v)
{ TRACEN("correct_triangle_at "<<PH(v));
if ( !has_outdeg_two(v) ) return;
Halfedge_handle e = first_out_edge(v);
CGAL_assertion(next(next(next(e)))==e);
flip_diagonal(next(e));
}
void dump(std::ostream& os = std::cerr) const
{ SM_io_parser<Explorer>::dump(E_,os);
SM_io_parser<Base>::dump(*this,os); }
Sphere_triangle incident_triangle(Halfedge_handle e) const
{ Halfedge_handle en(next(e)), enn(next(en));
CGAL_assertion(next(enn)==e);
return Sphere_triangle(
point(source(e)),point(source(en)),point(source(enn)),
circle(e),circle(en),circle(enn));
}
Sphere_triangle incident_triangle(Halfedge_const_handle e) const
{ Halfedge_const_handle en(next(e)), enn(next(en));
CGAL_assertion(next(enn)==e);
return Sphere_triangle(
point(source(e)),point(source(en)),point(source(enn)),
circle(e),circle(en),circle(enn));
}
void discard_info()
{
Vertex_iterator v;
Halfedge_iterator e;
CGAL_forall_vertices(v,*this) discard_info(v);
CGAL_forall_halfedges(e,*this) discard_info(e);
}
}; // SM_triangulator<Decorator_>
template <typename Decorator_>
void SM_triangulator<Decorator_>::triangulate()
{ TRACEN("triangulate");
// first create sphere segments from isoverts, edges, loops
Seg_list L;
Seg_map From;
CGAL::Unique_hash_map<Halfedge_const_iterator,bool> Done(false);
Vertex_const_iterator v;
CGAL_forall_vertices(v,E_) {
if ( !E_.is_isolated(v) ) continue;
L.push_back(trivial_segment(E_,v));
From[--L.end()] = make_object(v);
}
Halfedge_const_iterator e;
CGAL_forall_halfedges(e,E_) {
if ( Done[e] ) continue;
if ( source(e) == target(e) ) {
Seg_pair p = two_segments(E_,e);
L.push_back(p.first); L.push_back(p.second);
From[--L.end()] = From[--(--L.end())] = make_object(e);
} else {
L.push_back(segment(E_,e));
From[--L.end()] = make_object(e);
}
Done[e] = Done[twin(e)] = true;
}
if ( E_.has_loop() ) {
Seg_pair p = two_segments(E_,E_.halfloop());
L.push_back(p.first); L.push_back(p.second);
From[--L.end()] = From[--(--L.end())] = make_object(E_.halfloop());
}
// partition segments from L to positive and negative hemisphere
Seg_list L_pos,L_neg;
partition_to_halfsphere(L.begin(), L.end(), L_pos, From, +1);
partition_to_halfsphere(L.begin(), L.end(), L_neg, From, -1);
// sweep the hemispheres to create two half sphere maps
typedef SM_subdivision<Self,Seg_iterator,Object_handle> SM_output;
typedef typename Kernel::Positive_halfsphere_geometry PH_geometry;
typedef CGAL::Segment_overlay_traits<
Seg_iterator, SM_output, PH_geometry> PHS_traits;
typedef CGAL::generic_sweep<PHS_traits> Positive_halfsphere_sweep;
typedef typename Kernel::Negative_halfsphere_geometry NH_geometry;
typedef CGAL::Segment_overlay_traits<
Seg_iterator, SM_output, NH_geometry> NHS_traits;
typedef CGAL::generic_sweep<NHS_traits> Negative_halfsphere_sweep;
Vertex_handle v_sep;
Halfedge_handle e_sep;
SM_output O(*this,E_,From);
typedef typename PHS_traits::INPUT Input_range;
Positive_halfsphere_sweep SP(
Input_range(L_pos.begin(),L_pos.end()),O,
K.get_positive_halfsphere_geometry());
SP.sweep();
v_sep=--vertices_end(); e_sep=--halfedges_end();
Negative_halfsphere_sweep SM(
Input_range(L_neg.begin(),L_neg.end()),O,
K.get_negative_halfsphere_geometry());
SM.sweep();
++v_sep; ++e_sep;
// now two CCs of sphere graph are calculated
// v_sep = first vertex of CC in negative x-sphere
// e_sep = first edge of CC in negative x-sphere
// enrich the edges by circle information
CGAL::Unique_hash_map<Halfedge_iterator,bool> Done2(false);
for(Halfedge_iterator e = halfedges_begin(); e != halfedges_end(); ++e)
{ if ( Done2[e] ) continue;
Sphere_segment s(point(source(e)),point(target(e)));
circle(e) = s.sphere_circle();
circle(twin(e)) = s.sphere_circle().opposite();
Done2[e] = Done2[twin(e)] = true;
}
// complete the support of per hemisphere
complete_support(vertices_begin(), v_sep, +1);
complete_support(v_sep, vertices_end(), -1);
// triangulate per hemisphere
typedef SM_constrained_triang_traits<Self,PH_geometry> PCT_traits;
typedef CGAL::generic_sweep<PCT_traits> Positive_halfsphere_ct_sweep;
typedef SM_constrained_triang_traits<Self,NH_geometry> NCT_traits;
typedef CGAL::generic_sweep<NCT_traits> Negative_halfsphere_ct_sweep;
typedef std::pair<Vertex_iterator,Vertex_iterator> Vertex_pair;
Vertex_pair vpp(vertices_begin(),v_sep);
Positive_halfsphere_ct_sweep PCTS(vpp, *this,
K.get_positive_halfsphere_geometry());
PCTS.sweep();
Vertex_pair vpn(v_sep,vertices_end());
Negative_halfsphere_ct_sweep NCTS(vpn, *this,
K.get_negative_halfsphere_geometry());
NCTS.sweep();
/* Note the we divide the world along the xy equator and
split the equator at y- and y+. We treat the halfcircle
at x+ as if perturbed slightly up. This makes triangles
that have y- or y+ as a vertex degenerate. if such triangles
appear we repair it by flipping the edge opposite to the
vertex y-(y+).
*/
correct_triangle_at(vertices_begin());
correct_triangle_at(--Vertex_iterator(v_sep));
correct_triangle_at(v_sep);
correct_triangle_at(--vertices_end());
// enrigh triangulation edges by circle information
for(Halfedge_iterator e = halfedges_begin(); e != halfedges_end(); ++e)
{ if ( Done2[e] ) continue;
Sphere_segment s(point(source(e)),point(target(e)));
circle(e) = s.sphere_circle();
circle(twin(e)) = s.sphere_circle().opposite();
Done2[e] = Done2[twin(e)] = true;
}
// merge the hemisphere maps into one sphere map
merge_halfsphere_maps(vertices_begin(),v_sep);
check_integrity_and_topological_planarity(false);
}
template <typename Decorator_>
template <typename Iterator, typename T>
void SM_triangulator<Decorator_>::
partition_to_halfsphere(Iterator start, Iterator beyond, Seg_list& L,
CGAL::Unique_hash_map<Iterator,T>& M, int pos) const
{ TRACEN("partition_to_halfsphere ");
CGAL_assertion(pos!=0);
Sphere_segment s1,s2;
Sphere_circle xycircle(0,0,pos);
while ( start != beyond ) {
int i = start->intersection(xycircle,s1,s2);
if (i>1) { L.push_back(s2); M[--L.end()] = M[start]; }
if (i>0) { L.push_back(s1); M[--L.end()] = M[start]; }
++start;
}
// now all segments are split into halfspheres
// we still have to:
// - split segments containing our special poles y^-, y^+
// - split halfcircles
// - add four equator segments
Sphere_point S(0,-1,0),N(0,1,0);
Sphere_circle yzcircle(1,0,0);
typename Seg_list::iterator it, itl;
bool part_in_hemisphere(false);
CGAL_forall_iterators(it,L) { TRACEN(" "<<*it);
if ( equal_as_sets(it->sphere_circle(),xycircle) ) {
TRACEN(" splitting xy seg "<<*it);
int n1 = it->intersection(yzcircle,s1,s2);
if (n1 > 1 && !s2.is_degenerate())
{ M[ L.insert(it,s2) ] = M[it]; }
if (n1 > 0 && !s1.is_degenerate())
{ M[ L.insert(it,s1) ] = M[it]; }
int n2 = it->intersection(yzcircle.opposite(),s1,s2);
if (n2 > 1 && !s2.is_degenerate())
{ M[ L.insert(it,s2) ] = M[it]; }
if (n2 > 0 && !s1.is_degenerate())
{ M[ L.insert(it,s1) ] = M[it]; }
itl = it; --it; L.erase(itl); M[itl] = T();
// at least one item was appended
} else {
part_in_hemisphere = true;
}
}
CGAL_forall_iterators(it,L) {
if ( it->is_halfcircle() ) {
TRACEN(" splitting halfcircle "<<*it);
Sphere_segment s1,s2;
it->split_halfcircle(s1,s2);
*it = s2;
M[ L.insert(it,s1) ] = M[it];
}
}
// append 4 xy-equator segments:
Sphere_segment sp(S,N,xycircle);
Sphere_segment sm(S,N,xycircle.opposite());
Sphere_segment s[4];
sp.split_halfcircle(s[0],s[1]);
sm.split_halfcircle(s[2],s[3]);
L.insert(L.end(),s,s+4);
/* if no segment is covering the interior of the hemisphere
we have to add a trivial segment to allow for a correct
triangulation */
if ( !part_in_hemisphere ) {
Sphere_point p(0,0,pos);
Sphere_circle c(1,0,0);
L.push_back(Sphere_segment(p,p,c));
}
}
template <typename Decorator_>
void SM_triangulator<Decorator_>::
merge_nodes(Halfedge_handle e1, Halfedge_handle e2) const
{
Vertex_handle v1 = source(e1), v2 = target(e2);
TRACEN("merge_nodes "<<PH(v1)<<PH(v2));
CGAL_assertion(point(v1)==point(v2));
Halfedge_handle ep1 = previous(e1), en2 = next(e2);
Halfedge_around_vertex_circulator eav(out_edges(v2)),ee(eav);
CGAL_For_all(eav,ee) { set_source(eav,v1); }
link_as_prev_next_pair(e2,e1);
link_as_prev_next_pair(ep1,en2);
assert_equal_marks(v1,v2);
discard_info(v2);
delete_vertex_only(v2);
}
template <typename Decorator_>
void SM_triangulator<Decorator_>::
merge_halfsphere_maps(Vertex_handle v1, Vertex_handle v2) const
{ TRACEN("merging halfspheres "<<PH(v1)<<PH(v2));
CGAL_assertion(point(v1)==point(v2));
std::list<Halfedge_pair> L_equator;
Halfedge_around_face_circulator
ep(last_out_edge(v1)), en(twin(first_out_edge(v2)));
do {
L_equator.push_back(Halfedge_pair(ep,en));
merge_nodes(ep,en); ++ep; --en;
} while ( source(ep) != v1 );
typename std::list<Halfedge_pair>::iterator it;
CGAL_forall_iterators(it,L_equator) {
Halfedge_handle e1 = it->first, e2 = it->second;
Halfedge_handle e1t = twin(e1), e2t = twin(e2);
TRACEV(PH(e1));TRACEV(PH(e2));
assert_equal_marks(e1,e2);
unify_marks(e1); unify_marks(e2);
make_twins(e1,e2); make_twins(e1t,e2t);
if ( e1 == first_out_edge(source(e1)) )
set_first_out_edge(source(e1),e2t);
if ( e2 == first_out_edge(source(e2)) )
set_first_out_edge(source(e2),e1t);
discard_info(e1);
delete_edge_pair_only(e1);
}
}
template <typename Decorator_>
void SM_triangulator<Decorator_>::
complete_support(Vertex_iterator v_start, Vertex_iterator v_end, int pos) const
{
TRACEN("complete_support");
for (Vertex_iterator v = v_start; v != v_end; ++v) {
TRACEN(" vertex = "<<PH(v));
Mark m_buffer;
Halfedge_handle e_below = halfedge_below(v);
if ( v == v_start ) {
m_buffer = E_.mark_of_halfsphere(-pos);
} else if ( e_below != Halfedge_handle() ) {
m_buffer = incident_mark(e_below);
} else { // e_below does not exist
/* this is only the case for a vertex v on the final equatorial
halfcircle; there we take the mark from an inedge edge into v */
CGAL_assertion( point(v).z() == 0 &&
( pos > 0 ? (point(v).x() >= 0) : (point(v).x()<=0)) );
m_buffer = incident_mark(previous(first_out_edge(v)));
}
TRACEN(" face mark below "<<m_buffer);
Object_handle o = support(v);
Vertex_const_handle vs;
Halfedge_const_handle es;
Halfloop_const_handle ls;
if ( o == NULL ) { mark(v) = m_buffer; }
else if ( assign(vs,o) ) { mark(v) = E_.mark(vs); }
else if ( assign(es,support(v)) ) {
if ( point(source(es)) == point(v) )
{ mark(v) = E_.mark(E_.source(es)); }
else if ( point(target(es)) == point(v) )
{ mark(v) = E_.mark(E_.target(es)); }
else { mark(v) = E_.mark(es); }
}
else if ( assign(ls,o) ) { mark(v) = E_.mark(ls); }
else CGAL_assertion_msg(0,"damn wrong support.");
TRACEN(" face mark at "<<mark(v));
if ( is_isolated(v) ) continue;
Halfedge_around_vertex_circulator e(first_out_edge(v)), hend(e);
CGAL_For_all(e,hend) {
TRACEN(" edge "<<PH(e));
if ( !is_forward(e) ) break;
if ( support(e) != NULL ) {
Halfedge_const_handle ei;
if ( assign(ei,support(e)) ) {
if ( E_.circle(ei) != circle(e) ) { ei = E_.twin(ei); }
CGAL_assertion( E_.circle(ei) == circle(e) );
TRACEN(" supporting edge "<<PH(ei));
incident_mark(twin(e)) = E_.mark(E_.face(E_.twin(ei)));
mark(e) = E_.mark(ei);
incident_mark(e) = m_buffer = E_.mark(E_.face(ei));
}
Halfloop_const_handle li;
if ( assign(li,support(e)) ) {
if ( E_.circle(li) != circle(e) ) { li = E_.twin(li); }
CGAL_assertion( E_.circle(li) == circle(e) );
TRACEN(" supporting loop "<<PH(li));
incident_mark(twin(e)) = E_.mark(E_.face(E_.twin(li)));
mark(e) = E_.mark(li);
incident_mark(e) = m_buffer = E_.mark(E_.face(li));
}
} else { TRACEN(" support from face below ");
incident_mark(twin(e)) = mark(e) =
incident_mark(e) = m_buffer;
}
TRACEN(" new face mark "<<m_buffer);
} // CGAL_For_all(e,hend)
TRACEN(" mark of "<<PH(v));
}
}
CGAL_END_NAMESPACE
#undef USING
#endif //CGAL_SM_TRIANGULATOR_H

View File

@ -0,0 +1,196 @@
#ifndef SM_VISUALIZOR_H
#define SM_VISUALIZOR_H
#include <CGAL/basic.h>
#include <CGAL/Nef_S2/SM_decorator.h>
#include <CGAL/Nef_S2/SM_triangulator.h>
#include <CGAL/Nef_S2/Sphere_geometry_OGL.h>
#define USING(t) typedef typename Sphere_map_::t t
//#define LGREY CGAL::Color(170,170,170)
//#define DGREY CGAL::Color(30,30,30)
#define LGREY CGAL::Color(170,170,200)
#define DGREY CGAL::Color(30,30,50)
CGAL_BEGIN_NAMESPACE
template <typename Sphere_map_>
class SM_BooleColor
{
typedef typename Sphere_map_::Vertex_const_handle Vertex_const_handle;
typedef typename Sphere_map_::Halfedge_const_handle Halfedge_const_handle;
typedef typename Sphere_map_::Halfloop_const_handle Halfloop_const_handle;
typedef typename Sphere_map_::Face_const_handle Face_const_handle;
typedef typename Sphere_map_::Mark Mark;
public:
Color color(Vertex_const_handle, Mark m) const
{ return ( m ? CGAL::BLACK : CGAL::WHITE ); }
Color color(Halfedge_const_handle, Mark m) const
{ return ( m ? CGAL::BLACK : CGAL::WHITE ); }
Color color(Halfloop_const_handle, Mark m) const
{ return ( m ? CGAL::BLACK : CGAL::WHITE ); }
Color color(Face_const_handle, Mark m) const
{ return ( m ? DGREY : LGREY ); }
};
/*{\Moptions outfile=SM_visualizor.man }*/
/*{\Manpage {SM_visualizor}{Sphere_map_,Sphere_kernel_}
{Drawing plane maps}{V}}*/
template <typename Sphere_map_, typename Sphere_kernel_,
typename Color_ = SM_BooleColor<Sphere_map_> >
class SM_visualizor : public
SM_triangulator< SM_decorator<Sphere_map_,Sphere_kernel_> >
{
/*{\Mdefinition An instance |\Mvar| of the data type |\Mname| is a
decorator to draw the structure of a sphere map into the surface
of a OpenGL sphere. It is generic with respect to the template
concept.}*/
/*{\Mgeneralization SM_decorator}*/
/*{\Mtypes 3}*/
public:
typedef Sphere_map_ Sphere_map;
typedef Sphere_kernel_ Sphere_kernel;
typedef SM_visualizor<Sphere_map_,Sphere_kernel_,Color_> Self;
typedef SM_const_decorator<Sphere_map_,Sphere_kernel_> Explorer;
typedef SM_decorator<Sphere_map_,Sphere_kernel_> Decorator;
typedef SM_triangulator<Decorator> Base;
USING(Vertex_const_handle);
USING(Halfedge_const_handle);
USING(Face_const_handle);
USING(Vertex_const_iterator);
USING(Halfedge_const_iterator);
USING(Face_const_iterator);
USING(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;
/*{\Mtypemember The color data accessor.}*/
protected:
Explorer E_;
const Color_objects& CO_;
Sphere_map MT_;
CGAL::OGL::Unit_sphere& S_;
public:
/*{\Mcreation 4}*/
SM_visualizor(const Sphere_map& M, CGAL::OGL::Unit_sphere& S,
const Color_objects& C = Color_objects())
/*{\Mcreate creates an instance |\Mvar| of type |\Mname| to visualize
the vertices, edges, and faces of |D| in an open GL window.}*/
: Base(M,MT_), E_(M), CO_(C), MT_(), S_(S)
{ triangulate(); }
/*{\Moperations 2 1}*/
/* |draw_map| draws all object of the referenced sphere map:
1) edges, loops, and vertices are taken from E_
2) faces are drawn via the calculated triangulation in MT_ */
void draw_map() const
/*{\Mop draw the whole plane map.}*/
{
// draw sphere segments underlying edges of E_:
Halfedge_const_iterator e;
CGAL::Unique_hash_map<Halfedge_const_iterator,bool> Done(false);
CGAL_forall_halfedges(e,E_) {
if ( Done[e] ) continue;
if ( source(e) == target(e) ) {
S_.push_back(E_.circle(e), CO_.color(e,E_.mark(e)));
} else {
S_.push_back(Sphere_segment(E_.point(E_.source(e)),
E_.point(E_.target(e)),
E_.circle(e)),CO_.color(e,E_.mark(e)));
}
Done[e]=Done[E_.twin(e)]=true;
}
// draw sphere circles underlying loops of E_:
if ( E_.has_loop() )
S_.push_back(
Sphere_circle(E_.circle(E_.halfloop())),
CO_.color(E_.halfloop(),E_.mark(E_.halfloop())));
// draw points underlying vertices of E_:
Vertex_const_iterator v;
CGAL_forall_vertices(v,E_)
S_.push_back(E_.point(v),CO_.color(v,E_.mark(v)));
CGAL_forall_halfedges(e,*this) {
if ( Done[e] ) continue;
Halfedge_const_handle en(next(e)),enn(next(en));
TRACEV(Base::incident_triangle(e));
TRACEN(incident_mark(e)<<incident_mark(en)<<incident_mark(enn));
CGAL_assertion(Base::incident_mark(e)==Base::incident_mark(en) &&
Base::incident_mark(en)==Base::incident_mark(enn));
Mark m = Base::incident_mark(e);
Sphere_triangle t = Base::incident_triangle(e);
S_.push_back(t, (m ? DGREY : LGREY) );
Done[e]=Done[en]=Done[enn]=true;
}
Done.clear(false);
CGAL_forall_halfedges(e,*this) {
if ( Done[e] ) continue;
S_.push_back_triangle_edge(Sphere_segment(E_.point(E_.source(e)),
E_.point(E_.target(e)),
E_.circle(e)));
Done[e]=Done[twin(e)]=true;
}
}
/* |draw_triangulation| draws all object of the underlying triangulation:
1) edges, loops, and vertices are taken from E_
2) faces are drawn via the calculated triangulation in MT_ */
void draw_triangulation() const
{
CGAL::Unique_hash_map<Halfedge_const_iterator,bool> Done(false);
// draw sphere segments underlying edges of triangulation:
Halfedge_const_iterator e;
CGAL_forall_halfedges(e,*this) {
if ( Done[e] ) continue;
S_.push_back(Sphere_segment(point(source(e)),point(target(e)),
circle(e)),CO_.color(e,mark(e)));
Done[e]=Done[twin(e)]=true;
}
// draw points underlying vertices of triangulation:
Vertex_const_iterator v;
CGAL_forall_vertices(v,*this)
S_.push_back(point(v),CO_.color(v,mark(v)));
Done.clear(false);
CGAL_forall_halfedges(e,*this) {
if ( Done[e] ) continue;
Halfedge_const_handle en(next(e)),enn(next(en));
CGAL_assertion(incident_mark(e)==incident_mark(en)&&
incident_mark(en)==incident_mark(enn));
Mark m = incident_mark(e);
Sphere_triangle t = incident_triangle(e);
S_.push_back(t, (m ? DGREY : LGREY) );
Done[e]=Done[en]=Done[enn]=true;
}
}
}; // end of SM_visualizor
CGAL_END_NAMESPACE
#undef USING
//#undef LGREY
//#undef DGREY
#endif // SM_VISUALIZOR_H

View File

@ -0,0 +1,130 @@
#ifndef CGAL_SPHERE_CIRCLE_H
#define CGAL_SPHERE_CIRCLE_H
#include <CGAL/basic.h>
CGAL_BEGIN_NAMESPACE
/*{\Manpage{Sphere_circle}{R}{Great circles on the unit sphere}{c}}*/
template <class R_> class Sphere_circle : public R_::Plane_3 {
/*{\Mdefinition An object |\Mvar| of type |\Mname| is an oriented
great circle on the surface of a unit sphere. Such circles correspond
to the intersection of an oriented plane (that contains the origin)
and the surface of $S_2$. The orientation of the great circle is that
of a counterclockwise walk along the circle as seen from the positive
halfspace of the oriented plane.}*/
public:
/*{\Mtypes 5}*/
typedef R_ R;
/*{\Mtypemember representation class.}*/
typedef typename R::RT RT;
/*{\Mtypemember ring type.}*/
typedef std::pair< Sphere_segment<R>,Sphere_segment<R> >
Sphere_segment_pair;
/*{\Mtypemember sphere segment pair.}*/
typedef typename R_::Plane_3 Plane_3;
typedef typename R_::Point_3 Point_3;
typedef Sphere_circle<R_> Self;
typedef typename R_::Plane_3 Base;
/*{\Mcreation 5}*/
Sphere_circle() : Base() {}
/*{\Mcreate creates some great circle.}*/
Sphere_circle(const Sphere_point<R>& p, const Sphere_point<R>&q)
: Base(Point_3(0,0,0),p,q)
/*{\Mcreate creates a great circle through $p$ and $q$. If $p$ and
$q$ are not opposite on $S_2$, then this circle is unique and oriented
such that a walk along |\Mvar| meets $p$ just before the shorter segment
between $p$ and $q$. If $p$ and $q$ are opposite of each other then we
create any great circle that contains $p$ and $q$.}*/
{ Point_3 p1(0,0,0), p4 = CGAL::ORIGIN + orthogonal_vector();
if ( p != q.opposite() ) {
if ( CGAL::orientation(p1,p,q,p4) != CGAL::POSITIVE )
*this = Self(opposite());
} else {
*this = Self(Plane_3(p1,q-p));
}
}
Sphere_circle(const CGAL::Plane_3<R>& h)
/*{\Mcreate creates the circle corresponding to the plane |h|.
\precond |h| contains the origin.}*/
: Base(h) { CGAL_assertion(h.d() == 0); }
Sphere_circle(const RT& x, const RT& y, const RT& z) : Base(x,y,z,0) {}
/*{\Mcreate creates the circle orthogonal to the vector $(x,y,z)$.}*/
Sphere_circle(Sphere_circle<R> c, const Sphere_point<R>& p)
/*{\Mcreate creates a great circle orthogonal to $c$ that contains $p$.
\precond $p$ is not part of $c$.}*/
{ CGAL_assertion(!c.has_on(p));
if ( c.has_on_negative_side(p) ) c=c.opposite();
if ( p == c.orthogonal_pole() )
*this = Sphere_circle<R>(Base(Point_3(0,0,0),p,CGAL::ORIGIN+c.base1()));
else
*this = Sphere_circle<R>(Base(Point_3(0,0,0),p,c.orthogonal_pole()));
}
/*{\Moperations 4 2}*/
Sphere_circle<R> opposite() const
/*{\Mop returns the opposite of |\Mvar|.}*/
{ return Base::opposite(); }
bool has_on(const Sphere_point<R>& p) const
/*{\Mop returns true iff |\Mvar| contains |p|.}*/
{ return Base::has_on(p); }
Plane_3 plane() const { return Base(*this); }
/*{\Mop returns the plane supporting |\Mvar|.}*/
Sphere_point<R> orthogonal_pole() const
/*{\Mop returns the point that is the pole of the
hemisphere left of |\Mvar|.}*/
{ return CGAL::ORIGIN+orthogonal_vector(); }
Sphere_segment_pair split_at(const Sphere_point<R>& p) const;
/*{\Mop returns the pair of circle segments that is the result
of splitting |\Mvar| at |p| and |p.opposite()|.}*/
Sphere_segment_pair split_at_xy_plane() const;
/*{\Mop returns the pair of circle segments that is the result
of splitting |\Mvar| at the $x$-$y$-coordinate plane if |\Mvar|
is not part of it. Otherwise |\Mvar| is split at the
$x$-$z$-coordinate plane.}*/
}; // Sphere_circle<R>
/*{\Mtext\headerline{Global functions}}*/
template <class R>
bool equal_as_sets(const CGAL::Sphere_circle<R>& c1,
const CGAL::Sphere_circle<R>& c2)
/*{\Mfunc returns true iff |c1| and |c2| are equal as unoriented
circles.}*/
{ return c1==c2 || c1==c2.opposite(); }
template <typename R>
Sphere_point<R> intersection(const Sphere_circle<R>& c1,
const Sphere_circle<R>& c2)
/*{\Mfunc returns one of the two intersection points of
|c1| and |c2|. \precond |c1 != c2| as sets.}*/
{
CGAL_assertion(!equal_as_sets(c1,c2));
typename R::Line_3 lres;
TRACEN("circle_intersection "<<c1<<" "<<c2);
CGAL::Object o = CGAL::intersection(c1.plane(),c2.plane());
if ( !assign(lres,o) ) CGAL_assertion_msg(0,"damn id planes.");
return CGAL::ORIGIN + lres.direction().vector();
}
CGAL_END_NAMESPACE
#endif //CGAL_SPHERE_CIRCLE_H

View File

@ -0,0 +1,99 @@
#ifndef CGAL_SPHERE_DIRECTION_H
#define CGAL_SPHERE_DIRECTION_H
#include <CGAL/basic.h>
CGAL_BEGIN_NAMESPACE
/*{\Manpage{Sphere_direction}{R}{Directions on the unit sphere}{c}}*/
template <class R_> class Sphere_direction : public R_::Plane_3 {
/*{\Mdefinition An object |\Mvar| of type |\Mname| is a direction
on the surface of the unit sphere. Such directions can be used to
describe walks that are part of great circles.}*/
public:
/*{\Mtypes 5}*/
typedef R_ R;
/*{\Mtypemember representation class.}*/
typedef typename R::RT RT;
/*{\Mtypemember ring type.}*/
typedef typename R_::Point_3 Point_3;
typedef typename R_::Plane_3 Plane_3;
typedef typename R_::Plane_3 Base;
typedef Sphere_direction<R_> Self;
/*{\Mcreation 5}*/
Sphere_direction() : Base() {}
/*{\Mcreate creates some direction.}*/
Sphere_direction(const Sphere_circle<R>& c)
/*{\Mcreate creates the direction corresponding to the circle |c|.}*/
: Base(c) {}
Sphere_direction(const Sphere_point<R>& p, const Sphere_point<R>&q)
: Base(Point_3(0,0,0),p,q)
/*{\Mcreate creates a direction that describes the orientation of
the great circle through $p$ and $q$ (oriented such that the segment
$pq$ is the shorter one of the two possible ones. \precond $p$ and $q$
are not opposite on $S_2$.}*/
{ CGAL_assertion(p!=q.opposite());
Point_3 p1(0,0,0), p4 = CGAL::ORIGIN + orthogonal_vector();
if ( CGAL::orientation(p1,p,q,p4) != CGAL::POSITIVE )
*this = Sphere_direction(opposite());
}
Sphere_direction(const CGAL::Plane_3<R>& h)
/*{\Xcreate creates the direction corresponding to the plane |h|.
\precond |h| contains the origin.}*/
: Base(h) { CGAL_assertion(h.d() == 0); }
/*{\Moperations 4 2}*/
Sphere_direction<R> opposite() const
/*{\Mop returns the opposite of |\Mvar|.}*/
{ return Base::opposite(); }
Plane_3 plane() const { return Base(*this); }
/*{\Xop returns the plane supporting |\Mvar|.}*/
}; // Sphere_direction<R>
/* We have:
1) all directions fixed at p
2) d1==d3 possible
return true iff d1,d2,d3 are stricly ccw ordered around p
Note: Sphere_directions are Plane_3
we therefore compare the normal vectors of the planes
that underly the directions d1,d2,d3 in the plane
through 0 and orthogonal to the vector p-0
*/
template <typename R>
bool strictly_ordered_ccw_at(const Sphere_point<R>& p,
const Sphere_direction<R>& d1,
const Sphere_direction<R>& d2,
const Sphere_direction<R>& d3)
{ CGAL_assertion(d1.has_on(p) && d2.has_on(p) && d3.has_on(p));
typename R::Point_3 p0(0,0,0);
typename R::Point_3 p1(CGAL::ORIGIN + d1.orthogonal_vector());
typename R::Point_3 p2(CGAL::ORIGIN + d2.orthogonal_vector());
typename R::Point_3 p3(CGAL::ORIGIN + d3.orthogonal_vector());
if ( d1 == d3 ) return false;
if ( CGAL::orientation(p0,p,p1,p3) == CGAL::POSITIVE ) {
return CGAL::orientation(p0,p,p1,p2) == CGAL::POSITIVE &&
CGAL::orientation(p0,p,p3,p2) == CGAL::NEGATIVE;
} else {
return CGAL::orientation(p0,p,p1,p2) == CGAL::POSITIVE ||
CGAL::orientation(p0,p,p3,p2) == CGAL::NEGATIVE;
}
}
CGAL_END_NAMESPACE
#endif //CGAL_SPHERE_DIRECTION_H

View File

@ -0,0 +1,173 @@
#ifndef CGAL_SPHERE_GEOMETRY_H
#define CGAL_SPHERE_GEOMETRY_H
#include <CGAL/basic.h>
#include <CGAL/intersection_3.h>
#include <list>
#undef _DEBUG
#define _DEBUG 113
#include <CGAL/Nef_S2/debug.h>
CGAL_BEGIN_NAMESPACE
template <class R> class Sphere_point;
template <class R> class Sphere_segment;
template <class R> class Sphere_triangle;
template <class R> class Sphere_circle;
template <class R> class Sphere_direction;
CGAL_END_NAMESPACE
#include <CGAL/Nef_S2/Sphere_point.h>
#include <CGAL/Nef_S2/Sphere_circle.h>
#include <CGAL/Nef_S2/Sphere_direction.h>
#include <CGAL/Nef_S2/Sphere_segment.h>
#include <CGAL/Nef_S2/Sphere_triangle.h>
#include <CGAL/Nef_S2/sphere_predicates.h>
CGAL_BEGIN_NAMESPACE
template <typename R_>
struct Positive_halfsphere_geometry {
typedef R_ R;
typedef CGAL::Sphere_point<R> Point_2;
typedef CGAL::Sphere_segment<R> Segment_2;
Positive_halfsphere_geometry() {}
Point_2 source(const Segment_2& s) const
{ return s.source(); }
Point_2 target(const Segment_2& s) const
{ return s.target(); }
Segment_2 construct_segment(const Point_2& p, const Point_2& q) const
{ return Segment_2(p,q); }
void xz_pi_half_rotate(Point_2& p) const
{ p = Point_2(-p.hz(),p.hy(),p.hx()); }
int orientation(const Point_2& p1, const Point_2& p2,
const Point_2& p3) const
{ int or = CGAL::spherical_orientation(p1,p2,p3);
if (or) return or;
Point_2 pp1(p1), pp2(p2), pp3(p3);
if ( !( p1.hz() == 0 && p2.hz() == 0 && p3.hz() == 0) ) return or;
// or==0 we perturb any point in the xy-plane with x>0
// by a negative rotation around the y-axis
// our perturbation is big :-) we take PI/2 :
if ( p1.hx()>0 ) xz_pi_half_rotate(pp1);
if ( p2.hx()>0 ) xz_pi_half_rotate(pp2);
if ( p3.hx()>0 ) xz_pi_half_rotate(pp3);
return CGAL::spherical_orientation(pp1,pp2,pp3);
}
int orientation(const Segment_2& s, const Point_2& p) const
{ return orientation(s.source(),s.target(),p); }
bool is_degenerate(const Segment_2& s) const
{ return s.is_degenerate(); }
int compare_xy(const Point_2& p1, const Point_2& p2) const
{ return CGAL::spherical_compare(p1,p2,+1); }
Point_2 intersection(const Segment_2& s1, const Segment_2& s2) const
{ if (s1.sphere_circle() != s2.sphere_circle().opposite())
return s1.intersection(s2);
CGAL_assertion(s1.target()==s2.target());
return s1.target();
}
}; // Positive_halfsphere_geometry<R>
template <typename R>
struct Negative_halfsphere_geometry :
public Positive_halfsphere_geometry<R> {
typedef Positive_halfsphere_geometry<R> Base;
typedef typename Base::Point_2 Point_2;
typedef typename Base::Segment_2 Segment_2;
Negative_halfsphere_geometry() {}
int orientation(const Point_2& p1, const Point_2& p2,
const Point_2& p3) const
{ int or = CGAL::spherical_orientation(p1,p2,p3);
if (or) return or;
Point_2 pp1(p1), pp2(p2), pp3(p3);
if ( !( p1.hz() == 0 && p2.hz() == 0 && p3.hz() == 0) ) return or;
// or==0 we perturb any point in the xy-plane with x>0
// by a negative rotation around the y-axis
// our perturbation is big :-) we take PI/2 :
if ( p1.hx()<0 ) xz_pi_half_rotate(pp1);
if ( p2.hx()<0 ) xz_pi_half_rotate(pp2);
if ( p3.hx()<0 ) xz_pi_half_rotate(pp3);
return CGAL::spherical_orientation(pp1,pp2,pp3);
}
int orientation(const Segment_2& s, const Point_2& p) const
{ return orientation(s.source(),s.target(),p); }
int compare_xy(const Point_2& p1, const Point_2& p2) const
{ return CGAL::spherical_compare(p1,p2,-1); }
}; // Negative_halfsphere_geometry<R>
template <typename R_>
struct Sphere_geometry {
typedef R_ R;
typedef typename R_::RT RT;
typedef typename R_::FT FT;
typedef CGAL::Sphere_point<R> Sphere_point;
typedef CGAL::Sphere_segment<R> Sphere_segment;
typedef CGAL::Sphere_circle<R> Sphere_circle;
typedef CGAL::Sphere_direction<R> Sphere_direction;
typedef CGAL::Sphere_triangle<R> Sphere_triangle;
typedef CGAL::Point_3<R> Point_3;
typedef CGAL::Plane_3<R> Plane_3;
typedef Positive_halfsphere_geometry<R> Positive_halfsphere_geometry;
typedef Negative_halfsphere_geometry<R> Negative_halfsphere_geometry;
Sphere_point source(const Sphere_segment& s) const
{ return s.source(); }
Sphere_point target(const Sphere_segment& s) const
{ return s.target(); }
Sphere_segment construct_segment(const Sphere_point& p,
const Sphere_point& q) const
{ return Sphere_segment(p,q); }
Sphere_segment construct_segment(const Sphere_point& p,
const Sphere_point& q,
const Plane_3& h) const
{ return Sphere_segment(p,q,h); }
Plane_3 affine_representation(const Plane_3& h, const Point_3& p) const
{ RT wp = p.hw();
return Plane_3(wp*h.a(),wp*h.b(),wp*h.c(),
-(p.hx()*h.a() + p.hy()*h.b() + p.hz()*h.c())); }
Plane_3 linear_representation(const Plane_3& h) const
{ return Plane_3(h.a(),h.b(),h.c(),0); }
Positive_halfsphere_geometry PHG;
const Positive_halfsphere_geometry&
get_positive_halfsphere_geometry() const
{ return PHG; }
Negative_halfsphere_geometry NHG;
const Negative_halfsphere_geometry&
get_negative_halfsphere_geometry() const
{ return NHG; }
};
CGAL_END_NAMESPACE
#endif //CGAL_SPHERE_GEOMETRY_H

View File

@ -0,0 +1,923 @@
#ifndef CGAL_SPHERE_GEOMETRY_OGL_H
#define CGAL_SPHERE_GEOMETRY_OGL_H
#include <CGAL/Simple_cartesian.h>
#include <CGAL/Nef_S2/Sphere_geometry.h>
#include <CGAL/IO/Color.h>
#include <GL/glut.h>
#include <cmath>
#include <cstdlib>
#include <cstdio>
#include <string>
#include <vector>
#undef _DEBUG
#define _DEBUG 151
#include <CGAL/Nef_S2/debug.h>
CGAL_BEGIN_NAMESPACE
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 std::vector<VPoint> VSegment;
typedef VKernel::Triangle_3 DTriangle;
typedef std::vector<DTriangle> VTriangle;
const double refinement_angle = 0.1;
const double shrink_fac = 0.995;
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>
VPoint approximate(const CGAL::Sphere_point<R>& p)
{
VVector v = convert(p-CGAL::ORIGIN);
v = v / CGAL_NTS sqrt(v*v) ; // normalize
return CGAL::ORIGIN+v;
}
template <class R_>
class Sphere_point : public VPoint, public Gen_object {
typedef R_ R;
CGAL::Sphere_point<R> p_;
CGAL::Color c_;
unsigned w_;
public:
Sphere_point() {}
Sphere_point(const CGAL::Sphere_point<R>& p,
CGAL::Color c = CGAL::BLACK, unsigned w = 10) :
VPoint(approximate(p)), p_(p), c_(c), w_(w) {}
Sphere_point(const Sphere_point<R>& p) : VPoint(p)
{ 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 <typename R>
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 = acos(cosalpha);
const int units_per_halfcircle = 50;
int units = int(units_per_halfcircle/M_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);
} TRACEV(units); TRACEV(cosalpha); 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(cos(M_PI*i/double(units_per_halfcircle)),
sin(M_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) { TRACEN(*it<<" "<<T(*it));
*it = T(*it);
} TRACEN("");
return S;
}
template <class R_>
class Sphere_segment : public VSegment, public Gen_object {
typedef R_ R;
CGAL::Sphere_segment<R> s_;
CGAL::Color c_;
unsigned w_;
public:
Sphere_segment() {}
Sphere_segment(const CGAL::Sphere_segment<R>& s,
CGAL::Color c = CGAL::BLACK, unsigned w = 2)
: VSegment(approximate(s)), s_(s), c_(c), w_(w) {}
Sphere_segment(const Sphere_segment<R>& s) : VSegment(s)
{ 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
{ 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 <typename R>
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(cos(2*M_PI*i/double(units)),
sin(2*M_PI*i/double(units)),
0.0);
VSegment::iterator it;
for(it = S.begin(); it != S.end(); ++it) *it = T(*it);
return S;
}
template <class R_>
class Sphere_circle : public VSegment, public Gen_object {
typedef R_ R;
CGAL::Sphere_circle<R> s_;
CGAL::Color c_;
unsigned w_;
public:
Sphere_circle() {}
Sphere_circle(const CGAL::Sphere_circle<R>& s,
CGAL::Color c = CGAL::BLACK, unsigned w = 2)
: VSegment(approximate(s)), s_(s), c_(c), w_(w) {}
Sphere_circle(const Sphere_circle<R>& s) : VSegment(s)
{ 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
{ 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::Color c_;
public:
Sphere_triangle() {}
Sphere_triangle(const CGAL::Sphere_triangle<R>& t,
CGAL::Color c = CGAL::GREY)
: VTriangle(approximate(t)), t_(t), c_(c) {}
Sphere_triangle(const Sphere_triangle<R>& t) : VTriangle(t)
{ t_ = t.t_; c_ = t.c_; }
Sphere_triangle<R>& operator=(const Sphere_triangle<R>& t)
{ VTriangle::operator=(t); t_ = t.t_; c_ = s.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
{ TRACEN("draw "<<t_);
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 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. */
void refine(const DTriangle& t, VTriangle& T)
{
double angle[3]; int i(0);
angle[0] = acos((t[0]-CGAL::ORIGIN)*(t[1]-CGAL::ORIGIN));
angle[1] = acos((t[1]-CGAL::ORIGIN)*(t[2]-CGAL::ORIGIN));
angle[2] = acos((t[2]-CGAL::ORIGIN)*(t[0]-CGAL::ORIGIN));
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 threshhold
{ 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);
}
template <typename R>
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)));
TRACEN("approximate " << td);
refine(td,T);
return T;
}
//----------------------------------------------------------------------------
// the sphere:
//----------------------------------------------------------------------------
enum Sphere_map_mode {
SM_FACES, SM_SKELETON, SM_TRIANGULATION
};
class Unit_sphere {
typedef std::list<Gen_object*> Object_list;
typedef Object_list::const_iterator Object_const_iterator;
typedef Object_list::iterator Object_iterator;
GLUquadricObj* sphere_;
Sphere_map_mode style_;
bool axes_, cube_, initialized_;
Object_list objects_,triangles_,triangle_edges_;
GLuint sphere_list_;
public:
void init(Sphere_map_mode style = SM_FACES)
{ style_ = style; axes_ = true; cube_ = false;
gluQuadricNormals(sphere_,GLenum(GLU_SMOOTH));
}
Unit_sphere(Sphere_map_mode style = SM_FACES)
{ sphere_ = gluNewQuadric(); initialized_ = false; init(style); }
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)
{ TRACEN("copyconstruction");
sphere_ = gluNewQuadric();
initialized_ = S.initialized_;
style_ = S.style_;
axes_ = S.axes_;
cube_ = S.cube_;
copy_list(S);
}
Unit_sphere& operator=(const Unit_sphere& S)
{ TRACEN("assignment");
initialized_ = S.initialized_;
style_ = S.style_;
axes_ = S.axes_;
cube_ = S.cube_;
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::Color c = CGAL::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::Color c = CGAL::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::Color c = CGAL::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::Color c = CGAL::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::Color c = CGAL::BLUE, unsigned w = 1)
{ triangle_edges_.push_back(new Sphere_segment<R>(s,c,w)); }
void set_style(Sphere_map_mode style) { style_ = style; }
void toggle_axes() { axes_ = !axes_; }
void toggle_cube() { cube_ = !cube_; }
private:
void construct_axes() const
{ int i;
register 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);
glVertex3f(0.0,0.0,0.0);
glVertex3f(1.2,0.0,0.0);
glEnd();
glBegin(GL_LINE_LOOP);
for(i=0;i<100;i++)
glVertex3d(f*cos(2.0*M_PI*i/100.0),f*sin(2.0*M_PI*i/100.0),0.0);
glEnd();
// green y-axis and equator
glColor3f(0.0,1.0,0.0);
glBegin(GL_LINES);
glVertex3f(0.0,0.0,0.0);
glVertex3f(0.0,1.2,0.0);
glEnd();
glBegin(GL_LINE_LOOP);
for(i=0;i<100;i++)
glVertex3d(0.0,f*cos(2.0*M_PI*i/100.0),f*sin(2.0*M_PI*i/100.0));
glEnd();
// blue z-axis and equator
glColor3f(0.0,0.0,1.0);
glBegin(GL_LINES);
glVertex3f(0.0,0.0,0.0);
glVertex3f(0.0,0.0,1.2);
glEnd();
glBegin(GL_LINE_LOOP);
for(i=0;i<100;i++)
glVertex3d(f*cos(2.0*M_PI*i/100.0),0.0,f*sin(2.0*M_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);
glVertex3f(-1.0,-1.0,-1.0);
glVertex3f( 1.0,-1.0,-1.0);
glVertex3f( 1.0, 1.0,-1.0);
glVertex3f(-1.0, 1.0,-1.0);
glEnd();
glBegin(GL_LINE_LOOP);
glVertex3f(-1.0,-1.0, 1.0);
glVertex3f( 1.0,-1.0, 1.0);
glVertex3f( 1.0, 1.0, 1.0);
glVertex3f(-1.0, 1.0, 1.0);
glEnd();
glBegin(GL_LINES);
glVertex3f(-1.0,-1.0,-1.0);
glVertex3f(-1.0,-1.0, 1.0);
glVertex3f( 1.0,-1.0,-1.0);
glVertex3f( 1.0,-1.0, 1.0);
glVertex3f( 1.0, 1.0,-1.0);
glVertex3f( 1.0, 1.0, 1.0);
glVertex3f(-1.0, 1.0,-1.0);
glVertex3f(-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() const
{ gluQuadricDrawStyle(sphere_,style_);
glEnable(GL_LIGHTING);
if ( style_ == SM_SKELETON ) {
glEnable(GL_COLOR_MATERIAL);
glColor3f(0.7,0.7,0.7);
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 ( axes_ ) glCallList(sphere_list_+3);
if ( cube_ ) glCallList(sphere_list_+4);
}
};
enum MenuEntries { ROTATE, SCALE, TRANSLATE, RESET_CONTROL,
UNITY_CUBE, AXES,
FACES, SKELETON, TRIANGULATION,
QUIT };
int window_width = 300; // Breite und
int window_height = 300; // Hoehe des Fensters
int mouse_x, mouse_y; // Mauskoordinaten linker button
int mouse_left_button = false; // Mouse1 gedrueckt
int motion_mode = ROTATE; // Bewegen der Maus bei Mouse1 gedrueckt
int submenu1, submenu2;
long double dx = 0; // Translation
long double dy = 0; // Translation
long double wx = 0; // Rotation
long double wy = 0; // Rotation
long double s = 1.5; // Skalierung
long double factor_d; // Umrechnungsfaktor fuer Translation
long double factor_w; // Umrechnungsfaktor fuer Rotation
long double factor_s; // Umrechnungsfaktor fuer Skalierung
// our draw object:
static std::vector<Unit_sphere> spheres_;
static std::vector<std::string> titles_;
void show (int mode)
{
std::vector<Unit_sphere>::iterator it;
switch(mode)
{
case ROTATE:
case SCALE:
case TRANSLATE:
motion_mode = mode;
break;
case RESET_CONTROL:
dx = dy = wx = wy = 0.0;
s = 1.5;
motion_mode = ROTATE;
CGAL_forall_iterators(it,spheres_) it->init();
glutPostRedisplay();
break;
case UNITY_CUBE:
CGAL_forall_iterators(it,spheres_) it->toggle_cube();
glutPostRedisplay();
break;
case AXES:
CGAL_forall_iterators(it,spheres_) it->toggle_axes();
glutPostRedisplay();
break;
case FACES:
CGAL_forall_iterators(it,spheres_) it->set_style(SM_FACES);
glutPostRedisplay();
break;
case SKELETON:
CGAL_forall_iterators(it,spheres_) it->set_style(SM_SKELETON);
glutPostRedisplay();
break;
case TRIANGULATION:
CGAL_forall_iterators(it,spheres_) it->set_style(SM_TRIANGULATION);
glutPostRedisplay();
break;
case QUIT:
exit(0);
}
}
// Mausknopf gedrueckt
void mouse (int button, int state, int x, int y)
{
if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
{
mouse_x = x;
mouse_y = y;
mouse_left_button = true;
}
else
mouse_left_button = false;
}
// Objekt rotieren, zoomen oder verschieben
void motion (int x, int y)
{
if (mouse_left_button)
{
if (motion_mode == ROTATE)
{
wx += (y - mouse_y) * factor_w;
// Mausbewegung in y-Richtung entspricht Rotation um die x-Achse
wy += (x - mouse_x) * factor_w;
// Mausbewegung in x-Richtung entspricht Rotation um die y-Achse
}
else if (motion_mode == SCALE)
{
s *= exp( (y - mouse_y) * factor_s );
}
else if (motion_mode == TRANSLATE)
{
dx += (x - mouse_x) * factor_d / s;
dy -= (y - mouse_y) * factor_d / s;
}
mouse_x = x;
mouse_y = y;
glutPostRedisplay();
}
}
void init()
{
GLfloat mat_diffuse[4] = { 0.7, 0.7, 0.7, 1.0 };
GLfloat mat_specular[4] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat mat_shininess[] = { 100.0 };
GLfloat ambient_light[] = { 0.2, 0.2, 0.2, 1.0 };
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient_light);
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mat_diffuse );
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat_specular );
glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, mat_shininess );
//#define SCREENSHOTS
#ifdef SCREENSHOTS
GLfloat mat_emission[] = { 0.1, 0.1, 0.2, 0.0 };
glMaterialfv(GL_FRONT, GL_EMISSION, mat_emission);
//for screenshots enable this section
#endif
GLfloat light0[4] = { 4.0, 4.0, 10.0, 1.0 };
glLightfv (GL_LIGHT0, GL_POSITION, light0);
glEnable (GL_LIGHT0);
glEnable(GL_DEPTH_TEST);
glEnable(GL_AUTO_NORMAL);
glEnable(GL_NORMALIZE);
glEnable(GL_POINT_SMOOTH);
}
void enter_leave(int state)
{ glutPostRedisplay(); }
void draw()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glPushMatrix();
glRotated(wy,0,1,0);
glRotated(wx,1,0,0);
glScaled(s,s,s);
glTranslated(dx,dy,0.0);
int win = glutGetWindow();
//std::cerr << "WINDOW" << win << std::endl;
spheres_[win-1].draw();
glPopMatrix();
glutSwapBuffers();
}
void reshape(int width, int height)
{
window_width = width;
window_height = height;
glViewport(0, 0, (GLint)width, (GLint)height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (width>height)
{
long double w = (long double) width / (long double) height;
glOrtho( -2*w, 2*w, -2.0, 2.0, -100.0, 100.0 );
factor_d = 2.0 / (height/2.0);
// halbe Fensterhoehe soll 2 LE entsprechen
factor_w = 90.0 / (height/2.0);
// halbe Fensterhoehe soll 90 Grad entsprechen
factor_s = std::log(4.0) / (height/2.0);
// halbe Fensterhoehe soll Faktor 4 entsprechen
}
else
{
long double h = (long double) height / (long double) width;
glOrtho( -2.0, 2.0, -2*h, 2*h, -100.0, 100.0 );
factor_d = 2.0 / (width/2.0);
// halbe Fensterbreite soll 2 LE entsprechen
factor_w = 90.0 / (width/2.0);
// halbe Fensterbreite soll 90 Grad entsprechen
factor_s = std::log(4.0) / (height/2.0);
// halbe Fensterhoehe soll Faktor 4 entsprechen
}
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void add_sphere()
{ spheres_.push_back(Unit_sphere()); }
void start_viewer()
{
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
glutInitWindowSize(window_width, window_height);
glutInitWindowPosition(0,0);
int submenu1 = glutCreateMenu(show);
glutAddMenuEntry("Reset",RESET_CONTROL);
glutAddMenuEntry("Rotate",ROTATE);
glutAddMenuEntry("Scale",SCALE);
glutAddMenuEntry("Translate",TRANSLATE);
int submenu2 = glutCreateMenu(show);
glutAddMenuEntry("Toggle Axes",AXES);
glutAddMenuEntry("Toggle Unity Cube",UNITY_CUBE);
int submenu3 = glutCreateMenu(show);
glutAddMenuEntry("Faces",FACES);
glutAddMenuEntry("Skeleton",SKELETON);
glutAddMenuEntry("Triangulation",TRIANGULATION);
//for (unsigned i = 0; i < spheres_.size(); ++i) spheres_[i].print();
for (unsigned i = 0; i < spheres_.size(); ++i) {
if (i > 0 ) glutInitWindowPosition(i*(window_width+12),0);
if ( i < titles_.size() ) glutCreateWindow(titles_[i].c_str());
else glutCreateWindow("Sphere Window");
glutEntryFunc(enter_leave);
init();
glutDisplayFunc(draw);
glutReshapeFunc(reshape);
glutMouseFunc(mouse);
glutMotionFunc(motion);
glutCreateMenu(show);
glutAddSubMenu("Control",submenu1);
glutAddSubMenu("Render",submenu3);
glutAddSubMenu("Options",submenu2);
glutAddMenuEntry("Quit",QUIT);
glutAttachMenu(GLUT_RIGHT_BUTTON);
}
glutMainLoop();
}
} // OGL
CGAL_END_NAMESPACE
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

View File

@ -0,0 +1,463 @@
// ============================================================================
//
// Copyright (c) 1997-2000 The CGAL Consortium
//
// This software and related documentation is part of an INTERNAL release
// of the Computational Geometry Algorithms Library (CGAL). It is not
// intended for general use.
//
// ----------------------------------------------------------------------------
//
// release : $CGAL_Revision$
// release_date : $CGAL_Date$
//
// file : include/CGAL/Nef_S2/Sphere_map.h
// package : Nef_S2
// chapter : Nef Polyhedra on the sphere
//
// revision : $Revision$
// revision_date : $Date$
//
// author(s) : Michael Seel <seel@mpi-sb.mpg.de>
// maintainer : Michael Seel <seel@mpi-sb.mpg.de>
// coordinator : Michael Seel <seel@mpi-sb.mpg.de>
// ============================================================================
#ifndef CGAL_SPHERE_MAP_H
#define CGAL_SPHERE_MAP_H
#include <CGAL/basic.h>
#include <CGAL/Object.h>
#include <CGAL/Unique_hash_map.h>
#include <CGAL/Nef_S2/SM_items.h>
#include <CGAL/Nef_S2/SM_iteration.h>
#include <CGAL/Nef_S2/Generic_handle_map.h>
#include <list>
#undef _DEBUG
#define _DEBUG 109
#include <CGAL/Nef_S2/debug.h>
CGAL_BEGIN_NAMESPACE
/*{\Manpage {Sphere_map}{Kernel}{Sphere Maps}{M}}*/
template <typename Kernel_>
class Sphere_map {
/*{\Mdefinition selective sphere map container based on
the HDS design of Kettner.}*/
public:
/*{\Mtypes 7}*/
typedef Kernel_ Kernel;
typedef Sphere_map<Kernel_> Self;
typedef SM_items<Kernel_,bool> Items;
friend class SM_const_decorator<Self,Kernel>;
friend class SM_decorator<Self,Kernel>;
typedef typename Kernel::Sphere_point Sphere_point;
/*{\Mtypemember embedding vertices.}*/
typedef typename Kernel::Sphere_circle Sphere_circle;
/*{\Mtypemember embedding edges.}*/
typedef bool Mark;
/*{\Mtypemember selective attributes of all objects.}*/
typedef size_t Size_type;
/*{\Mtypemember size type.}*/
/*{\Mtext For all objects |Vertex|, |Halfedge|, |Halfloop|, |Face|
there are handle and iterator types |xxx_handle|, |xxx_iterator|.
There's no type |SLoop_iterator|, as there is
at most one |SLoop| pair per sphere map.}*/
typedef typename Items::template Vertex<Self> Vertex;
typedef CGAL::In_place_list<Vertex,false> Vertex_list;
typedef typename Vertex_list::iterator Vertex_handle;
typedef typename Vertex_list::const_iterator Vertex_const_handle;
typedef typename Vertex_list::iterator Vertex_iterator;
typedef typename Vertex_list::const_iterator Vertex_const_iterator;
typedef typename Items::template Halfedge<Self> Halfedge;
typedef CGAL::In_place_list<Halfedge,false> Halfedge_list;
typedef typename Halfedge_list::iterator Halfedge_handle;
typedef typename Halfedge_list::const_iterator Halfedge_const_handle;
typedef typename Halfedge_list::iterator Halfedge_iterator;
typedef typename Halfedge_list::const_iterator Halfedge_const_iterator;
typedef typename Items::template Face<Self> Face;
typedef CGAL::In_place_list<Face,false> Face_list;
typedef typename Face_list::iterator Face_handle;
typedef typename Face_list::const_iterator Face_const_handle;
typedef typename Face_list::iterator Face_iterator;
typedef typename Face_list::const_iterator Face_const_iterator;
typedef typename Items::template Halfloop<Self> Halfloop;
typedef Halfloop* Halfloop_handle;
typedef const Halfloop* Halfloop_const_handle;
typedef Halfloop* Halfloop_iterator;
typedef const Halfloop* Halfloop_const_iterator;
class Object_handle
/*{\Mtypemember a generic handle to an object of |\Mvar|.
The kind of the object can be determined and the object assigned
by the function:\\
|bool assign(xxx_handle& h, Object_handle o)|\\
where the function returns |true| iff the assignment of |o| to
|h| was valid.}*/
: public CGAL::Object
{
typedef CGAL::Object Base;
public:
Object_handle() : Base() {}
Object_handle(const CGAL::Object& o) : Base(o) {}
Object_handle(const Object_handle& h) : Base(h) {}
Object_handle& operator=(const Object_handle& h)
{ Base::operator=(h); return *this; }
bool operator==(CGAL_NULL_TYPE n) const
{ assert(n == 0); return Base::is_empty(); }
bool operator!=(CGAL_NULL_TYPE n) const
{ assert(n == 0); return !Base::is_empty(); }
}; // Object_handle
typedef std::list<Object_handle> Object_list;
typedef typename Object_list::iterator Object_iterator;
typedef typename Object_list::const_iterator Object_const_iterator;
typedef Generic_handle_map<Object_iterator> Handle_to_iterator_map;
class Face_cycle_iterator : public Object_iterator
/*{\Mtypemember a generic iterator to an object in the boundary
of a facet. Convertible to |Object_handle|.}*/
{ typedef Object_iterator Ibase;
public:
Face_cycle_iterator() : Ibase() {}
Face_cycle_iterator(const Ibase& b) : Ibase(b) {}
Face_cycle_iterator(const Face_cycle_iterator& i) : Ibase(i) {}
bool is_vertex() const
{ Vertex_handle v; return CGAL::assign(v,Ibase::operator*()); }
bool is_halfedge() const
{ Halfedge_handle e; return CGAL::assign(e,Ibase::operator*()); }
bool is_halfloop() const
{ Halfloop_handle l; return CGAL::assign(l,Ibase::operator*()); }
operator Vertex_handle() const
{ Vertex_handle v; CGAL::assign(v,Ibase::operator*()); return v; }
operator Halfedge_handle() const
{ Halfedge_handle e; CGAL::assign(e,Ibase::operator*()); return e; }
operator Halfloop_handle() const
{ Halfloop_handle l; CGAL::assign(l,Ibase::operator*()); return l; }
operator Object_handle() const { return Ibase::operator*(); }
Object_handle& operator*() const { return Ibase::operator*(); }
Object_handle operator->() const { CGAL_assertion_msg(0,"not impl."); }
};
class Face_cycle_const_iterator : public Object_const_iterator
/*{\Mtypemember a generic iterator to an object in the boundary
of a facet. Convertible to |Object_handle|.}*/
{ typedef Object_const_iterator Ibase;
public:
Face_cycle_const_iterator() : Ibase() {}
Face_cycle_const_iterator(const Ibase& b) : Ibase(b) {}
Face_cycle_const_iterator(const Face_cycle_const_iterator& i)
: Ibase(i) {}
bool is_vertex() const
{ Vertex_handle v; return CGAL::assign(v,Ibase::operator*()); }
bool is_halfedge() const
{ Halfedge_handle e; return CGAL::assign(e,Ibase::operator*()); }
bool is_halfloop() const
{ Halfloop_handle l; return CGAL::assign(l,Ibase::operator*()); }
operator Vertex_const_handle() const
{ Vertex_handle v; CGAL::assign(v,Ibase::operator*());
return Vertex_const_handle(v); }
operator Halfedge_const_handle() const
{ Halfedge_handle e; CGAL::assign(e,Ibase::operator*());
return Halfedge_const_handle(e); }
operator Halfloop_const_handle() const
{ Halfloop_handle l; CGAL::assign(l,Ibase::operator*());
return Halfloop_const_handle(l); }
operator Object_handle() const { return Ibase::operator*(); }
const Object_handle& operator*() const { return Ibase::operator*(); }
Object_handle operator->() const { CGAL_assertion_msg(0,"not impl."); }
};
/*{\Mcreation 3}*/
/*{\Mtext |\Mname| is default and copy constructible. Note that copy
construction means cloning an isomorphic structure and is thus an
expensive operation.}*/
Sphere_map() : boundary_item_(undef_),
vertices_(), edges_(), faces_(), loops_(0)
{ m_pos_ = m_neg_ = Mark(); }
~Sphere_map() { clear(); }
Sphere_map(const Self& D) : boundary_item_(undef_),
vertices_(D.vertices_), edges_(D.edges_), faces_(D.faces_), loops_(0)
{ if ( D.loops_ != 0 ) new_halfloop_pair(*(D.loops_),*(D.loops_->twin_));
pointer_update(D);
m_pos_ = D.m_pos_; m_neg_ = D.m_neg_; }
Self& operator=(const Self& D)
{ if ( this == &D ) return *this;
clear();
vertices_ = D.vertices_; edges_ = D.edges_; faces_ = D.faces_;
if ( D.loops_ != 0 ) new_halfloop_pair(*D.loops_,*(D.loops_->twin_));
pointer_update(D);
m_pos_ = D.m_pos_; m_neg_ = D.m_neg_;
return *this;
}
void clear()
{
boundary_item_.clear(undef_);
vertices_.destroy(); edges_.destroy(); faces_.destroy();
if ( loops_ != 0 ) { delete_halfloop_pair(loops_); loops_=0; }
m_pos_ = m_neg_ = Mark();
}
template <typename H>
bool is_boundary_object(H h)
{ return boundary_item_[h]!=undef_; }
template <typename H>
Object_iterator& boundary_item(H h)
{ return boundary_item_[h]; }
template <typename H>
void store_boundary_item(H h, Object_iterator o)
{ boundary_item_[h] = o; }
template <typename H>
void undef_boundary_item(H h)
{ CGAL_assertion(boundary_item_[h]!=undef_);
boundary_item_[h] = undef_; }
void reset_iterator_hash(Object_iterator it)
{ Vertex_handle sv;
Halfedge_handle se;
Halfloop_handle sl;
if ( assign(se,*it) ) { undef_boundary_item(se); return; }
if ( assign(sl,*it) ) { undef_boundary_item(sl); return; }
if ( assign(sv,*it) ) { undef_boundary_item(sv); return; }
}
void reset_object_list(Object_list& L)
{ Object_iterator oit;
CGAL_forall_iterators(oit,L) reset_iterator_hash(oit);
L.clear();
}
/*{\Moperations 2.5 3}*/
// The constant iterators and circulators.
Vertex_const_iterator vertices_begin() const { return vertices_.begin();}
Vertex_const_iterator vertices_end() const { return vertices_.end();}
Halfedge_const_iterator halfedges_begin() const { return edges_.begin();}
Halfedge_const_iterator halfedges_end() const { return edges_.end();}
Halfloop_const_iterator halfloops_begin() const { return loops_; }
Halfloop_const_iterator halfloops_end() const
{ return loops_ != 0 ? loops_+2 : loops_; }
Face_const_iterator faces_begin() const { return faces_.begin();}
Face_const_iterator faces_end() const { return faces_.end();}
Vertex_iterator vertices_begin() { return vertices_.begin();}
Vertex_iterator vertices_end() { return vertices_.end();}
Halfedge_iterator halfedges_begin() { return edges_.begin();}
Halfedge_iterator halfedges_end() { return edges_.end();}
Halfloop_iterator halfloops_begin() { return loops_; }
Halfloop_iterator halfloops_end()
{ return loops_ != 0 ? loops_+2 : loops_; }
Face_iterator faces_begin() { return faces_.begin();}
Face_iterator faces_end() { return faces_.end();}
Face_cycle_const_iterator face_cycles_begin(Face_const_handle f) const
{ return f->face_cycles_begin(); }
Face_cycle_const_iterator face_cycles_end(Face_const_handle f) const
{ return f->face_cycles_end(); }
Face_cycle_iterator face_cycles_begin(Face_handle f) const
{ return f->face_cycles_begin(); }
Face_cycle_iterator face_cycles_end(Face_handle f) const
{ return f->face_cycles_end(); }
/*{\Mtext The list of all objects can be accessed via iterator ranges.
For comfortable iteration we also provide iterations macros.
The iterator range access operations are of the following kind:\\
|Vertex_iterator vertices_begin()/vertices_end()|\\
|Halfedge_iterator halfedges_begin()/halfedges_end()|\\
|Halfloop_iterator halfloops_begin()/halfloops_end()|\\
|Face_iterator faces_begin()/faces_end()|
The macros are then |CGAL_forall_vertices(v,\Mvar)|,
|CGAL_forall_halfedges(e,\Mvar)|,
|CGAL_forall_halfloops(l,\Mvar)|,
|CGAL_forall_faces(f,\Mvar)|.}*/
Size_type number_of_vertices() const { return vertices_.size();}
/*{\Mop returns the number of vertices.}*/
Size_type number_of_halfedges() const { return edges_.size();}
/*{\Mop returns the number of (directed edges).}*/
Size_type number_of_faces() const { return faces_.size();}
/*{\Mop returns the number of facets.}*/
Size_type number_of_halfloops() const
{ return loops_!=Halfloop_handle() ? 2 : 0; }
/*{\Mop returns the number of sloops.}*/
bool empty() const
{ return number_of_vertices() == 0 &&
number_of_halfedges() == 0 &&
number_of_halfloops() == 0 &&
number_of_faces() == 0;
}
Vertex_handle new_vertex(const Sphere_point& p,
Mark m = Mark())
/*{\Mop returns a new vertex at point |p| marked by |m|.}*/
{ Vertex_handle vh = new_vertex(); vh->point_ = p; vh->mark_ = m;
TRACEN("new_vertex "<<&*vh);
return vh;
}
template <typename H>
void make_twins(H h1, H h2) { h1->twin_ = h2; h2->twin_ = h1; }
Vertex_handle new_vertex()
{ vertices_.push_back( * new Vertex); return --vertices_end(); }
Face_handle new_face()
{ faces_.push_back( * new Face ); return --faces_end(); }
Halfedge_handle new_halfedge_pair()
{ edges_.push_back( * new Halfedge );
Halfedge_handle e1 = --halfedges_end();
edges_.push_back( * new Halfedge );
Halfedge_handle e2 = --halfedges_end();
make_twins(e1,e2); return e1; }
Halfloop_handle new_halfloop_pair()
{ Halfloop_handle ph = new Halfloop[2];
Halfloop* pt(ph); ++pt;
make_twins(ph,pt);
loops_=ph; return ph; }
Halfloop_handle new_halfloop_pair(const Halfloop& l1,
const Halfloop& l2)
{ Halfloop* ph = new Halfloop[2];
Halfloop* pt(ph); ++pt;
*ph=l1; *pt=l2; make_twins(ph,pt);
loops_=ph; return ph; }
void delete_vertex(Vertex_handle h)
{ vertices_.erase(h); delete &* h; }
void delete_face(Face_handle h)
{ faces_.erase(h); delete &* h; }
void delete_halfedge_pair(Halfedge_handle h)
{ Halfedge_handle ht = h->twin_;
edges_.erase(h); edges_.erase(ht);
delete &*ht; delete &*h; }
void delete_halfloop_pair(Halfloop_handle h)
{ Halfloop* ph = &*h;
Halfloop* pt = &*(h->twin_);
if ( ph > pt ) std::swap(ph,pt);
loops_ = Halfloop_handle();
delete [] ph; }
void delete_halfedge(Halfedge_handle h)
{ edges_.erase(h); delete &* h; }
protected:
void pointer_update(const Self& D);
Handle_to_iterator_map boundary_item_;
static Object_iterator undef_;
Vertex_list vertices_;
Halfedge_list edges_;
Face_list faces_;
Halfloop_iterator loops_;
Mark m_pos_, m_neg_;
/* two default marks at y-
m_neg_ just below the pos-xy-equator
m_pos_ just above the neg-xy-equator */
}; // Sphere_map
template <typename K>
void Sphere_map<K>::
pointer_update(const Sphere_map<K>& D)
{
CGAL::Unique_hash_map<Vertex_const_handle,Vertex_handle> VM;
CGAL::Unique_hash_map<Halfedge_const_handle,Halfedge_handle> EM;
CGAL::Unique_hash_map<Halfloop_const_handle,Halfloop_handle> LM;
CGAL::Unique_hash_map<Face_const_handle,Face_handle> FM;
Vertex_const_iterator vc = D.vertices_begin();
Vertex_iterator v = vertices_begin();
for ( ; vc != D.vertices_end(); ++vc,++v) VM[vc] = v;
VM[D.vertices_end()] = vertices_end();
Halfedge_const_iterator ec = D.halfedges_begin();
Halfedge_iterator e = halfedges_begin();
for ( ; ec != D.halfedges_end(); ++ec,++e) EM[ec] = e;
EM[D.halfedges_end()] = halfedges_end();
Face_const_iterator fc = D.faces_begin();
Face_iterator f = faces_begin();
for ( ; fc != D.faces_end(); ++fc,++f) FM[fc] = f;
FM[D.faces_end()] = faces_end();
Halfloop_iterator l;
if ( D.loops_ != 0 ) {
LM[D.loops_] = loops_;
LM[D.loops_->twin_] = loops_->twin_;
}
for (v = vertices_begin(); v != vertices_end(); ++v) {
// Local Graph update: (SVertices are postponed/updated as Edges)
v->edge_ = EM[v->edge_];
v->face_ = FM[v->face_];
}
// Edge update:
for (e = halfedges_begin(); e != halfedges_end(); ++e) {
e->twin_ = EM[e->twin_];
e->prev_ = EM[e->prev_];
e->next_ = EM[e->next_];
e->source_ = VM[e->source_];
e->face_ = FM[e->face_];
}
for (l = halfloops_begin(); l != halfloops_end(); ++l) {
// l->twin_ = LM[l->twin_]; twin is set on construction
l->face_ = FM[l->face_];
}
for (f = faces_begin(); f != faces_end(); ++f) {
Face_cycle_iterator fci;
for(fci = f->boundary_.begin(); fci != f->boundary_.end(); ++fci) {
if ( assign(v,Object_handle(fci)) )
{ *fci = make_object(VM[v]); store_boundary_item(v,fci); }
else if ( assign(e,Object_handle(fci)) )
{ *fci = make_object(EM[e]); store_boundary_item(e,fci); }
else if ( assign(l,Object_handle(fci)) )
{ *fci = make_object(LM[l]); store_boundary_item(l,fci); }
else CGAL_assertion_msg(0,"damn wrong boundary item in face.");
}
}
}
template <typename Kernel_>
typename Sphere_map<Kernel_>::Object_iterator
Sphere_map<Kernel_>::undef_;
/* boundary item is member!
template <typename Kernel_>
typename Sphere_map<Kernel_>::Handle_to_iterator_map
Sphere_map<Kernel_>::boundary_item_(Sphere_map<Kernel_>::undef_);
*/
CGAL_END_NAMESPACE
#endif // CGAL_SPHERE_MAP_H

View File

@ -0,0 +1,108 @@
#ifndef CGAL_SPHERE_POINT_H
#define CGAL_SPHERE_POINT_H
#include <CGAL/basic.h>
CGAL_BEGIN_NAMESPACE
/*{\Mtext \headerline{Restricted Spherical Geometry}
We introduce geometric objects that are part of the
spherical surface $S_2$ and operations on them. We define types
|Sphere_point|, |Sphere_circle|, |Sphere_segment|, and
|Sphere_direction|. |Sphere_point|s are points on $S_2$,
|Sphere_circle|s are oriented great circles of $S_2$,
|Sphere_segment|s are oriented parts of |Sphere_circles| bounded by a
pair of |Sphere_point|s, and |Sphere_direction|s are directions that
are part of great circles (a direction is usually defined to be a
vector without length, that floats around in its underlying space and
can be used to specify a movement at any point of the underlying
space; in our case we use directions only at points that are part of
the great circle that underlies also the direction.)
Note that we have to consider special geometric properties of the
objects. For example two points that are part of a great circle define
two |Sphere_segment|s, and two arbitrary |Sphere_segment|s can
intersect in two points.
If we restrict our geometric objects to a so-called perfect hemisphere
of $S_2$\footnote{A perfect hemisphere of $S_2$ is an open half-sphere
plus an open half-circle in the boundary of the open half-sphere plus one
endpoint of the half-circle.} then the restricted objects behave like
in classical geometry, e.g., two points define exactly one segment,
two segments intersect in at most one interior point
(non-degenerately), or three non-cocircular sphere points can be
qualified as being positively or negatively oriented.}*/
/*{\Moptions print_title=yes }*/
/*{\Manpage{Sphere_point}{R}{Points on the unit sphere}{p}}*/
template <class R_>
class Sphere_point : public R_::Point_3 {
/*{\Mdefinition An object |\Mvar| of type |\Mname| is a point on the
surface of a unit sphere. Such points correspond to the nontrivial
directions in space and similarly to the equivalence classes of all
nontrivial vectors under normalization.}*/
public:
/*{\Mtypes 5}*/
typedef R_ R;
/*{\Mtypemember representation class.}*/
typedef typename R_::FT FT;
/*{\Xtypemember ring number type.}*/
typedef typename R_::RT RT;
/*{\Mtypemember field number type.}*/
typedef Sphere_point<R> Self;
typedef typename R::Point_3 Base;
typedef typename R::Direction_3 Direction_3;
/*{\Mcreation 5}*/
Sphere_point() : Base() {}
/*{\Mcreate creates some sphere point.}*/
Sphere_point(int x, int y, int z) :
Base(x,y,z,1) { CGAL_assertion(x!=0 || y!=0 || z!=0); }
Sphere_point(const RT& x, const RT& y, const RT& z) :
/*{\Mcreate creates a sphere point corresponding to the point of
intersection of the ray starting at the origin in direction $(x,y,z)$
and the surface of $S_2$.}*/
Base(x,y,z,1) { CGAL_assertion(x!=0 || y!=0 || z!=0); }
Sphere_point(const Base& p) : Base(p) {}
/*{\Moperations 4 2}*/
/*{\Mtext Access to the coordinates is provided by the following
operations. Note that the vector $(x,y,z)$ is not normalized.}*/
RT x() const { return hx(); }
/*{\Mop the $x$-coordinate.}*/
RT y() const { return hy(); }
/*{\Mop the $y$-coordinate.}*/
RT z() const { return hz(); }
/*{\Mop the $z$-coordinate.}*/
bool operator==(const Sphere_point<R>& q) const
/*{\Mbinop Equality.}*/
{ return Direction_3(Base(*this)-ORIGIN)==
Direction_3(q-ORIGIN); }
bool operator!=(const Sphere_point<R>& q) const
/*{\Mbinop Inequality.}*/
{ return !operator==(q); }
Sphere_point<R> opposite() const
/*{\Mop returns the opposite of |\Mvar|.}*/
{ return ORIGIN + -(Base(*this)-ORIGIN); }
}; // Sphere_point<R>
template <typename R>
CGAL::Point_3<R> operator+(
const CGAL::Point_3<R>& p, const Sphere_point<R>& q)
{ return p + (q-CGAL::ORIGIN); }
CGAL_END_NAMESPACE
#endif //CGAL_SPHERE_POINT_H

View File

@ -0,0 +1,344 @@
#ifndef CGAL_SPHERE_SEGMENT_H
#define CGAL_SPHERE_SEGMENT_H
#include <CGAL/basic.h>
#include <CGAL/Handle_for.h>
CGAL_BEGIN_NAMESPACE
template <class R_> class Sphere_segment_rep : public Ref_counted
{
typedef typename R_::Point_3 Point_3;
typedef typename R_::Plane_3 Plane_3;
typedef Sphere_point<R_> Point;
typedef Sphere_circle<R_> Circle;
typedef Sphere_segment_rep<R_> Rep;
friend class Sphere_segment<R_>;
public:
Sphere_segment_rep(const Point& p1, const Point& p2,
bool shorter_arc=true) :
ps_(p1), pt_(p2), c_(Plane_3(p1,p2,Point_3(0,0,0)))
{ CGAL_assertion(p1 != p2.opposite());
if ( p1 == p2 ) {
Plane_3 h(Point_3(0,0,0),(p1-CGAL::ORIGIN));
c_ = Sphere_circle<R_>(Plane_3(Point_3(0,0,0),h.base1()));
}
if (!shorter_arc) c_ = c_.opposite();
}
Sphere_segment_rep(const Point& p1, const Point& p2, const Circle& c) :
ps_(p1), pt_(p2), c_(c)
{ CGAL_assertion(c.has_on(p1)&&c.has_on(p2)); }
Sphere_segment_rep(const Circle& c1,
const Circle& c2) : c_(c1)
{ CGAL_assertion(!equal_as_sets(c1,c2));
ps_ = intersection(c1,c2);
pt_ = ps_.opposite();
if ( orientation(Point_3(0,0,0),ps_,pt_,
CGAL::ORIGIN + c_.orthogonal_vector()) !=
CGAL::POSITIVE ) std::swap(ps_,pt_);
}
Sphere_segment_rep(const Rep& r) :
ps_(r.ps_), pt_(r.pt_), c_(r.c_) {}
Rep& operator=(const Rep& r)
{ ps_=r.ps_; pt_=r.pt_; c_=r.c_; return *this; }
protected:
Sphere_point<R_> ps_,pt_;
Sphere_circle<R_> c_;
};
/*{\Moptions print_title=yes }*/
/*{\Manpage{Sphere_segment}{R}{Segments on the unit sphere}{s}}*/
template <class R_>
class Sphere_segment :
public Handle_for< Sphere_segment_rep<R_> > {
/*{\Mdefinition An object |\Mvar| of type |\Mname| is a segment in the
surface of a unit sphere that is part of a great circle trough the
origin. Sphere segments are represented by two sphere points $p$ and
$q$ plus an oriented plane $h$ that contains $p$ and $q$. The plane
determines the sphere segment. Let $c$ be the circle in the
intersection of $h$ and $S_2$. Then $s$ is that part of $c$ that is
swept, when we rotate $p$ into $q$ in counterclockwise rotation around
the normal vector of $h$ as seen from the positive halfspace.}*/
public:
/*{\Mtypes 6}*/
typedef R_ R;
/*{\Mtypemember representation class.}*/
typedef typename R_::RT RT;
/*{\Mtypemember ring number type.}*/
typedef Sphere_segment_rep<R_> Rep;
typedef Handle_for<Rep> Base;
typedef typename R_::Point_3 Point_3;
typedef typename R_::Vector_3 Vector_3;
typedef typename R_::Plane_3 Plane_3;
typedef typename R_::Line_3 Line_3;
typedef Sphere_segment<R_> Self;
/*{\Mcreation 4}*/
Sphere_segment() : Base() {}
Sphere_segment(const Sphere_point<R>& p1, const Sphere_point<R>& p2,
bool shorter_arc=true) : Base(Rep(p1,p2,shorter_arc)) {}
/*{\Mcreate creates a spherical segment spanning the shorter arc
from |p1| to |p2| if |shorter_arc == true|. Otherwise the longer
arc is created. \precond |p1 != p2| and |p1 != p2.opposite()|.}*/
Sphere_segment(const Sphere_point<R>& p1, const Sphere_point<R>& p2,
const Sphere_circle<R>& c) : Base(Rep(p1,p2,c)) {}
/*{\Mcreate creates a spherical segment spanning the arc
from |p1| to |p2| as part of the oriented circle |c|
(|p1 == p2| or |p1 == p2.opposite()| are possible.)
\precond |p1| and |p2| are contained in |c|.}*/
Sphere_segment(const Sphere_circle<R>& c1,
const Sphere_circle<R>& c2) : Base(Rep(c1,c2)) {}
/*{\Mcreate creates the spherical segment as part of |c1|
that is part of the halfsphere left of the oriented circle |c2|.
\precond |c1 != c2| as unoriented circles.}*/
Sphere_segment(const Self& s) : Base(s) {}
/*{\Moperations 4 2}*/
const Sphere_point<R>& source() const { return ptr->ps_; }
/*{\Mop the source point of |\Mvar|.}*/
const Sphere_point<R>& target() const { return ptr->pt_; }
/*{\Mop the target point of |\Mvar|.}*/
const Sphere_circle<R>& sphere_circle() const { return ptr->c_; }
/*{\Mop the great circle supporting |\Mvar|.}*/
Sphere_segment<R> opposite() const
/*{\Mop returns the sperical segment oriented from |target()|
to |source()| with the same point set as |\Mvar|. }*/
{ return Sphere_segment<R>(
target(),source(),sphere_circle().opposite()); }
Sphere_segment<R> complement() const
/*{\Mop returns the sperical segment oriented from |target()|
to |source()| with the point set completing |\Mvar| to a
full circle. }*/
{ return Sphere_segment<R>(target(),source(),sphere_circle()); }
int intersection(const Sphere_circle<R>& c,
Sphere_segment<R>& s1, Sphere_segment<R>& s2) const;
/*{\Mop returns the number of non-trivial connected components
of the intersection of |\Mvar| and the closed halfsphere left of
|c|.}*/
Sphere_point<R> intersection(const Sphere_segment<R>& so) const;
/*{\Mop returns the point of intersection of |\Mvar| and
|so|. \precond |\Mvar| and |so| do intersect.}*/
void split_halfcircle(Sphere_segment<R>& s1,
Sphere_segment<R>& s2) const
/*{\Mop splits a halfcircle into two equally sized segments.
\precond |\Mvar| is a halfcircle.}*/
{ CGAL_assertion( is_halfcircle() );
Plane_3 h(Point_3(0,0,0),(target()-CGAL::ORIGIN));
Sphere_point<R> p =
CGAL::intersection(sphere_circle(),Sphere_circle<R>(h));
if ( !has_on(p) ) p = p.opposite();
s1 = Sphere_segment<R>(ptr->ps_,p,ptr->c_);
s2 = Sphere_segment<R>(p,ptr->pt_,ptr->c_);
}
bool is_short() const
/*{\Mop a segment is short iff it is shorter than a halfcircle.}*/
{ return CGAL::orientation(Point_3(0,0,0), source(), target(),
CGAL::ORIGIN + ptr->c_.orthogonal_vector())
== CGAL::POSITIVE; }
bool is_long() const
/*{\Mop a segment is long iff it is longer than a halfcircle.}*/
{ return CGAL::orientation(Point_3(0,0,0), source(), target(),
CGAL::ORIGIN + ptr->c_.orthogonal_vector())
== CGAL::NEGATIVE; }
bool is_degenerate() const { return source() == target(); }
/*{\Mop return true iff |\Mvar| is degenerate.}*/
bool is_halfcircle() const { return source().opposite() == target(); }
/*{\Mop return true iff |\Mvar| is a halfcircle.}*/
bool has_on(const Sphere_point<R>& p) const;
/*{\Mop return true iff |\Mvar| contains |p|.}*/
bool has_in_relative_interior(const Sphere_point<R>& p) const;
/*{\Mop return true iff |\Mvar| contains |p| in
its relative interior.}*/
bool operator==(const Sphere_segment<R>& so) const
{ return source() == so.source() && target() == so.target() &&
(source() == target() ||
sphere_circle() == so.sphere_circle()); }
bool operator!=(const Sphere_segment<R>& so) const
{ return !operator==(so); }
};
template <typename R>
bool do_intersect_internally(const Sphere_segment<R>& s1,
const Sphere_segment<R>& s2,
Sphere_point<R>& p);
/*{\Mfunc return true iff |s1| and |s2| intersect internally
(non-degenerately). If |true| the parameter |p| returns the point of
intersection.}*/
template <typename R>
std::ostream& operator<<(std::ostream& os,
const CGAL::Sphere_segment<R>& s)
{ os << s.source()<<" "<<s.target()<<" "<<
s.sphere_circle().plane()<<" "; return os; }
template <typename R>
std::istream& operator>>(std::istream& is,
CGAL::Sphere_segment<R>& s)
{ CGAL::Sphere_point<R> p1,p2;
CGAL::Sphere_circle<R> c;
if ( !(is >> p1 >> p2 >> c) ) return is;
s = CGAL::Sphere_segment<R>(p1,p2,c);
return is; }
template <typename R>
std::pair< Sphere_segment<R>,Sphere_segment<R> >
Sphere_circle<R>::split_at(const Sphere_point<R>& p) const
{ CGAL_assertion(has_on(p));
Sphere_point<R> q(p.opposite());
return Sphere_segment_pair(
Sphere_segment<R>(p,q,*this),
Sphere_segment<R>(p,q,this->opposite()));
}
template <typename R>
std::pair< Sphere_segment<R>,Sphere_segment<R> >
Sphere_circle<R>::split_at_xy_plane() const
{ Self xycircle(0,0,1), yzcircle(1,0,0);
if ( !equal_as_sets(xycircle,*this) )
return split_at(intersection(*this,xycircle));
else
return split_at(intersection(*this,yzcircle));
}
/* Contains maps to two orientation checks with the wedge
spanned by the source and the target with planes orthogonal
to the supporting plane of $p$ and $q$. The logic depends on
the segments length: long or short. */
template <typename R>
bool Sphere_segment<R>::
has_on(const CGAL::Sphere_point<R>& p) const
{ if ( !sphere_circle().has_on(p) ) return false;
if ( !is_long() ) {
return orientation(Point_3(0,0,0),
CGAL::ORIGIN + sphere_circle().orthogonal_vector(),
source(),p) !=
CGAL::NEGATIVE &&
orientation(Point_3(0,0,0),target(),
CGAL::ORIGIN +
sphere_circle().orthogonal_vector(),p) !=
CGAL::NEGATIVE;
} else {
return orientation(Point_3(0,0,0),
CGAL::ORIGIN + sphere_circle().orthogonal_vector(),
source(),p) !=
CGAL::NEGATIVE ||
orientation(Point_3(0,0,0),target(),
CGAL::ORIGIN +
sphere_circle().orthogonal_vector(),p) !=
CGAL::NEGATIVE;
}
}
template <typename R>
bool Sphere_segment<R>::
has_in_relative_interior(const CGAL::Sphere_point<R>& p) const
{ if ( !sphere_circle().has_on(p) ) return false;
if ( !is_long() ) {
return orientation(Point_3(0,0,0),
CGAL::ORIGIN + sphere_circle().orthogonal_vector(),
source(),p) == CGAL::POSITIVE &&
orientation(Point_3(0,0,0),target(),
CGAL::ORIGIN +
sphere_circle().orthogonal_vector(),p) ==
CGAL::POSITIVE;
} else {
return orientation(Point_3(0,0,0),
CGAL::ORIGIN + sphere_circle().orthogonal_vector(),
source(),p) == CGAL::POSITIVE ||
orientation(Point_3(0,0,0),target(),
CGAL::ORIGIN +
sphere_circle().orthogonal_vector(),p) ==
CGAL::POSITIVE;
}
}
/* Intersection of two sphere segments. It does not work if the two
involved planes are equal as sets. */
template <typename R>
Sphere_point<R> Sphere_segment<R>::
intersection(const Sphere_segment<R>& s) const
{
CGAL_assertion(!equal_as_sets(sphere_circle(),s.sphere_circle()));
Sphere_point<R> res =
CGAL::intersection(sphere_circle(),s.sphere_circle());
if ( has_on(res) && s.has_on(res) ) return res;
return res.opposite();
}
template <typename R>
bool do_intersect_internally(const Sphere_segment<R>& s1,
const Sphere_segment<R>& s2,
Sphere_point<R>& p)
{
if ( equal_as_sets(s1.sphere_circle(),s2.sphere_circle()) )
return false;
p = CGAL::intersection(s1.sphere_circle(),s2.sphere_circle());
if ( s1.has_in_relative_interior(p) &&
s2.has_in_relative_interior(p) ) return true;
p = p.opposite();
if ( s1.has_in_relative_interior(p) &&
s2.has_in_relative_interior(p) ) return true;
return false;
}
template <typename R>
bool do_intersect_internally(const Sphere_circle<R>& c1,
const Sphere_segment<R>& s2,
Sphere_point<R>& p)
{
if ( equal_as_sets(c1,s2.sphere_circle()) )
return false;
p = CGAL::intersection(c1,s2.sphere_circle());
if ( s2.has_in_relative_interior(p) ) return true;
p = p.opposite();
if ( s2.has_in_relative_interior(p) ) return true;
return false;
}
CGAL_END_NAMESPACE
#endif //CGAL_SPHERE_SEGMENT_H

View File

@ -0,0 +1,100 @@
#ifndef CGAL_SPHERE_TRIANGLE_H
#define CGAL_SPHERE_TRIANGLE_H
#include <CGAL/basic.h>
#include <CGAL/Handle_for.h>
#include <CGAL/Nef_S2/Tuple.h>
CGAL_BEGIN_NAMESPACE
template <class R_> class Sphere_triangle_rep : public Ref_counted
{ typedef Sphere_point<R_> Point;
typedef Sphere_circle<R_> Circle;
typedef Sphere_triangle_rep<R_> Rep;
Tuple<Point,3> points_;
Tuple<Circle,3> circles_;
friend class Sphere_triangle<R_>;
Sphere_triangle_rep(const Point& p1, const Point& p2, const Point& p3,
const Circle& c1, const Circle& c2, const Circle& c3) :
points_(p1,p2,p3), circles_(c1,c2,c3) {}
public:
Sphere_triangle_rep(const Rep& r) :
points_(r.points_), circles_(r.circles_) {}
};
/*{\Manpage{Sphere_triangle}{R}{Triangles on the unit sphere}{t}}*/
template <class R_> class Sphere_triangle :
public Handle_for< Sphere_triangle_rep<R_> > {
/*{\Mdefinition An object |\Mvar| of type |\Mname| is a triangle
on the surface of the unit sphere.}*/
public:
/*{\Mtypes 5}*/
typedef R_ R;
/*{\Mtypemember representation class.}*/
typedef typename R::RT RT;
/*{\Mtypemember ring type.}*/
typedef Sphere_triangle_rep<R_> Rep;
typedef Handle_for<Rep> Base;
/*{\Mcreation 5}*/
Sphere_triangle() : Base() {}
/*{\Mcreate creates some triangle.}*/
Sphere_triangle(
const Sphere_point<R>& p0, const Sphere_point<R>& p1,
const Sphere_point<R>& p2,
const Sphere_circle<R>& c0, const Sphere_circle<R>& c1,
const Sphere_circle<R>& c2) : Base(Rep(p0,p1,p2,c0,c1,c2))
/*{\Mcreate creates a triangle spanned by the three points
|p0|, |p1|, |p2|, where the triangle is left of the three circles
|c0|, |c1|, |c2|. \precond $c_i$ contains $p_i$ and $p_{i+1}$ mod 3.}*/
{ CGAL_assertion( c0.has_on(p0) && c0.has_on(p1) );
CGAL_assertion( c1.has_on(p1) && c1.has_on(p2) );
CGAL_assertion( c2.has_on(p2) && c0.has_on(p0) );
}
Sphere_triangle(const Sphere_triangle<R>& t) : Base(t) {}
/*{\Moperations 4 2}*/
const Sphere_point<R>& point(unsigned i) const
/*{\Mop returns the ith point of |\Mvar|.}*/
{ return ptr->points_[i%3]; }
const Sphere_circle<R>& circle(unsigned i) const
/*{\Mop returns the ith circle of |\Mvar|.}*/
{ return ptr->circles_[i%3]; }
Sphere_triangle<R> opposite() const
/*{\Mop returns the opposite of |\Mvar|.}*/
{ return Sphere_triangle<R>(point(0), point(1), point(2),
circle(0).opposite(), circle(1).opposite(), circle(2).opposite()); }
}; // Sphere_triangle<R>
template <typename R>
std::ostream& operator<<(std::ostream& os,
const CGAL::Sphere_triangle<R>& t)
{ for (int i=0; i<3; ++i) os << t.point(i);
for (int i=0; i<3; ++i) os << t.circle(i); return os; }
template <typename R>
std::istream& operator>>(std::istream& is,
CGAL::Sphere_triangle<R>& t)
{ CGAL::Sphere_point<R> p1,p2,p3;
CGAL::Sphere_circle<R> c1,c2,c3;
if ( !(is >> p1 >> p2 >> p3 >> c1 >> c2 >> c3) ) return is;
t = CGAL::Sphere_triangle<R>(p1,p2,p3,c1,c2,c3);
return is; }
CGAL_END_NAMESPACE
#endif //CGAL_SPHERE_TRIANGLE_H

View File

@ -0,0 +1,33 @@
#ifndef CGAL_TUPLE_H
#define CGAL_TUPLE_H
#include <CGAL/basic.h>
CGAL_BEGIN_NAMESPACE
template <class T, unsigned n>
class Tuple {
typedef Tuple<T,n> Self;
T object_[n];
public:
Tuple() { for (unsigned i=0; i<n; ++i) object_[i]=T(); }
Tuple(const T& t1, const T& t2)
{ CGAL_assertion(n>1); object_[0]=t1; object_[1]=t2; }
Tuple(const T& t1, const T& t2, const T& t3)
{ CGAL_assertion(n>2); object_[0]=t1; object_[1]=t2; object_[2]=t3; }
Tuple(const Self& t)
{ for (unsigned i=0; i<n; ++i) object_[i] = t.object_[i]; }
Self& operator=(const Self& t)
{ for (unsigned i=0; i<n; ++i) object_[i] = t.object_[i];
return *this; }
const T& operator[](unsigned i) const
{ CGAL_assertion(i<n); return object_[i]; }
T& operator[](unsigned i)
{ CGAL_assertion(i<n); return object_[i]; }
};
CGAL_END_NAMESPACE
#endif //CGAL_TUPLE_H

View File

@ -0,0 +1,96 @@
// ============================================================================
//
// Copyright (c) 1997-2000 The CGAL Consortium
//
// This software and related documentation is part of an INTERNAL release
// of the Computational Geometry Algorithms Library (CGAL). It is not
// intended for general use.
//
// ----------------------------------------------------------------------------
//
// release : $CGAL_Revision$
// release_date : $CGAL_Date$
//
// file : include/CGAL/Nef_2/debug.h
// package : Nef_2
// chapter : Nef Polyhedra
//
// revision : $Revision$
// revision_date : $Date$
//
// author(s) : Michael Seel <seel@mpi-sb.mpg.de>
// maintainer : Michael Seel <seel@mpi-sb.mpg.de>
// coordinator : Michael Seel <seel@mpi-sb.mpg.de>
//
// implementation: simple debugging macros
// ============================================================================
#ifndef CGAL_DEBUG_H
#define CGAL_DEBUG_H
#include <iostream>
#undef TRACE
#undef TRACEN
#undef TRACEV
#undef CTRACE
#undef CTRACEN
#undef ASSERT
static int debugthread=3141592;
#if _DEBUG>0
#define SETDTHREAD(l) debugthread=l
#else
#define SETDTHREAD(l)
#endif
#if _DEBUG>0
#define TRACE(t) if((debugthread%_DEBUG)==0)\
std::cerr<<" "<<t;std::cerr.flush()
#else
#define TRACE(t)
#endif
#if _DEBUG>0
#define TRACEV(t) if((debugthread%_DEBUG)==0)\
std::cerr<<" "<<#t<<" = "<<(t)<<std::endl;std::cerr.flush()
#else
#define TRACEV(t)
#endif
#if _DEBUG>0
#define TRACEN(t) if((debugthread%_DEBUG)==0)\
std::cerr<<" "<<t<<std::endl;std::cerr.flush()
#else
#define TRACEN(t)
#endif
#if _DEBUG>0
#define CTRACE(b,t) if(b) std::cerr<<" "<<t; else std::cerr<<" 0"
#else
#define CTRACE(b,t)
#endif
#if _DEBUG>0
#define CTRACEN(b,t) if(b) std::cerr<<" "<<t<<"\n"; else std::cerr<<" 0\n"
#else
#define CTRACEN(b,t)
#endif
#ifndef _ASSERT
#define ASSERT(cond,fstr)
#else
#define ASSERT(cond,fstr) \
if (!(cond)) { \
std::cerr<<" ASSERT: "<< #fstr << endl; \
std::cerr<<" COND: "<< #cond << endl; \
std::cerr<<" POSITION: "<<__FILE__<<" at line "<<__LINE__<<std::endl; \
abort(); \
}
#endif
#endif //CGAL_DEBUG_H

View File

@ -0,0 +1,249 @@
#ifndef LEDA_SPHERE_MAP_H
#define LEDA_SPHERE_MAP_H
#include <CGAL/generic_sweep.h>
#include <CGAL/Nef_2/Segment_overlay_traits.h>
#include <CGAL/Nef_S2/Sphere_geometry.h>
#include <LEDA/graph.h>
#include <LEDA/graph_misc.h>
#undef _DEBUG
#define _DEBUG 211
#include <CGAL/Nef_S2/debug.h>
template <typename R, typename ITERATOR>
class leda_graph_decorator {
public:
typedef leda_node Vertex_handle;
typedef leda_edge Halfedge_handle;
typedef CGAL::Sphere_point<R> Point_2;
typedef CGAL::Sphere_segment<R> Segment_2;
typedef GRAPH< Point_2, Segment_2 > Graph;
typedef leda_node_map<Halfedge_handle> Below_map;
Graph& G;
Below_map& M;
leda_graph_decorator(Graph& Gi, Below_map& Mi) : G(Gi), M(Mi) {}
Vertex_handle new_vertex(const Point_2& p)
{ return G.new_node(p); }
void link_as_target_and_append(Vertex_handle v, Halfedge_handle e)
{ Halfedge_handle erev = G.reversal(e);
G.move_edge(e,G.cyclic_adj_pred(e,G.source(e)),v);
G.move_edge(erev,v,G.target(erev));
}
Halfedge_handle new_halfedge_pair_at_source(Vertex_handle v)
{ Halfedge_handle e_res,e_rev, e_first = G.first_adj_edge(v);
if ( e_first == nil ) {
e_res = G.new_edge(v,v);
e_rev = G.new_edge(v,v);
} else {
e_res = G.new_edge(e_first,v,LEDA::before);
e_rev = G.new_edge(e_first,v,LEDA::before);
}
G.set_reversal(e_res,e_rev);
return e_res;
}
void supporting_segment(Halfedge_handle e, ITERATOR it)
{ G[e] = *it; }
void halfedge_below(Vertex_handle v, Halfedge_handle e)
{ M[v] = e; }
void trivial_segment(Vertex_handle v, ITERATOR it) {}
void starting_segment(Vertex_handle v, ITERATOR it) {}
void passing_segment(Vertex_handle v, ITERATOR it) {}
void ending_segment(Vertex_handle v, ITERATOR it) {}
}; // leda_graph_decorator
template <typename R>
class leda_sphere_map_overlayer {
typedef std::pair<leda_edge,leda_edge> edge_pair;
typedef CGAL::Sphere_point<R> SPoint_2;
typedef CGAL::Sphere_segment<R> SSegment_2;
typedef CGAL::Plane_3<R> Plane_3;
typedef GRAPH<SPoint_2,SSegment_2> Sphere_map;
Sphere_map G;
leda_node_map<leda_edge> E;
public:
leda_sphere_map_overlayer() : G(),E(G) {}
const Sphere_map& sphere_map() const { return G; }
template <typename Iterator>
void subdivide(Iterator start, Iterator end)
/* subdivision is done in phases
- first we partition all segments into the pieces in the
closed postive xy-halfspace and into the pieces in the
negative xy-halfspace
- we sweep both halfspheres separate. Note that the boundary
carries the same topology
- we unify the graphs embedded into both halfspheres at
the boundary.
*/
{
typedef leda_graph_decorator<R,Iterator> leda_graph_output;
typedef CGAL::Positive_halfsphere_geometry<R> PH_geometry;
typedef CGAL::Segment_overlay_traits<
Iterator, leda_graph_output, PH_geometry> PHS_traits;
typedef CGAL::generic_sweep<PHS_traits> Positive_halfsphere_sweep;
typedef CGAL::Negative_halfsphere_geometry<R> NH_geometry;
typedef CGAL::Segment_overlay_traits<
Iterator, leda_graph_output, NH_geometry> NHS_traits;
typedef CGAL::generic_sweep<NHS_traits> Negative_halfsphere_sweep;
std::list<SSegment_2> Lp,Lm;
partition_xy( start, end, Lp , +1);
partition_xy( start, end, Lm , -1);
// both lists initialized with four quarter segments
// supporting the xy-equator thereby separating the
// two halfspheres
// all other segments in the range are split into their
// connected components with respect to the xy-plane.
leda_node v1,v2;
leda_graph_output O(G,E);
typedef typename PHS_traits::INPUT Input_range;
Positive_halfsphere_sweep SP(Input_range(Lp.begin(),Lp.end()),O);
SP.sweep();
TRACEN("POS SWEEP\n"<<(dump(std::cerr),""));
v1=G.first_node(); v2=G.last_node();
Negative_halfsphere_sweep SM(Input_range(Lm.begin(),Lm.end()),O);
SM.sweep();
TRACEN("NEG SWEEP\n"<<(dump(std::cerr),""));
v2 = G.succ_node(v2);
// now two CCs of sphere graph calculated
// v1 = first node of CC in positive xy-sphere
// v2 = first node of CC in negative xy-sphere
merging_halfspheres(v1,v2);
clean_trivial_face_cycles();
if (!Is_Plane_Map(G)) error_handler(1,"Sphere map: embedding wrong.");
compute_faces();
}
void merge_nodes(leda_edge e1, leda_edge e2)
// e1 and e2 are two edges of the xy equator such that
// e1 is part of the positive xy-sphere bounding outer face
// e2 is part of the negative xy-sphere bounding outer face
// e1 and e2 are oppositely oriented
// the outer faces are left of the edges
// the edges are embedded orderpreserving ccw
// then the following code merges the edges of A(target(e2))
// to A(source(e1)) preserving the embedding
// afterwards source(e1) carries all edges, target(e2) is isolated
{
leda_node v = source(e1);
leda_edge e_pos = e1;
leda_edge e = G.reversal(e2), er = e2;
leda_edge e_end = e;
do {
leda_edge e_next = G.cyclic_adj_succ(e);
G.move_edge(e,e_pos,target(e));
G.move_edge(er,er,v);
e_pos = e;
e = e_next; er = G.reversal(e);
} while ( e != e_end );
}
void merging_halfspheres(leda_node v1, leda_node v2)
// v1 and v2 are the definite nodes of both CCs
// where the negative y-axis pierces the sphere.
// the faces are left of edges
// edges are embedded orderpreserving ccw
{
TRACEN("Merging Halfspheres");
leda_edge e1,e2,e3,e4,e1n,e2n;
forall_adj_edges(e1,v1)
if ( G[target(e1)].hz()==0 && G[target(e1)].hx()<0 ) break;
forall_adj_edges(e2,v2)
if ( G[target(e2)].hz()==0 && G[target(e2)].hx()>0 ) break;
e3 = G.face_cycle_pred(e1);
e4 = e2; e2 = G.face_cycle_pred(e2);
while ( e1 != e3 || e2 != e4 ) {
TRACEN(G[source(e1)]<<" "<< G[target(e2)]);
e1n = G.face_cycle_succ(e1); e2n = G.face_cycle_pred(e2);
merge_nodes(e1,e2);
e1 = e1n; e2 = e2n;
}
}
void clean_trivial_face_cycles()
// removes trivial face cycles at equator
// removes isolated vertices stemming from
// equator unification
{
leda_edge_map<bool> known(G,false);
leda_list<leda_edge> L;
leda_list<edge_pair> Lr;
leda_edge e;
forall_edges(e,G) {
if (known[e]) continue;
leda_edge en = G.face_cycle_succ(e);
if ( G.face_cycle_succ(en) != e )
continue;
// e in trivial face cycle
L.append(e); L.append(en);
TRACEN("tivial cycle "<<G[source(e)]<<G[target(e)]);
known[e] = known[en] = true;
leda_edge er = G.reversal(e);
leda_edge enr = G.reversal(en);
Lr.append(edge_pair(er,enr));
}
edge_pair ep;
forall(ep,Lr) G.set_reversal(ep.first,ep.second);
G.del_edges(L);
leda_node v;
forall_nodes(v,G) if ( G.outdeg(v)==0 ) G.del_node(v);
}
void compute_faces()
{
G.compute_faces();
leda_face f;
leda_edge e;
forall_faces(f,G) {
TRACEN("FACE:");
forall_face_edges(e,f)
TRACEN(" "<<SSegment_2(G[source(e)],G[target(e)]));
}
}
void dump(std::ostream& os, leda_node v, bool nl=true) const
{ os << " ["<<::index(v)<<"] "<<G[v];
if (nl) os << std::endl; }
void dump(std::ostream& os) const
{
leda_node v;
leda_edge e;
forall_nodes(v,G) {
dump(os,v);
forall_adj_edges(e,v) {
os << " ->";
dump(os,target(e),false);
os <<" ["<<G[e]<<" ]\n";
}
}
}
}; // leda_sphere_map_overlayer<R>
#endif //LEDA_SPHERE_MAP_H

View File

@ -0,0 +1,235 @@
#ifndef CGAL_SPHERE_PREDICATES_H
#define CGAL_SPHERE_PREDICATES_H
#include <CGAL/basic.h>
#include <CGAL/Nef_S2/SM_iteration.h>
CGAL_BEGIN_NAMESPACE
/* |spherical_orientation| takes three points of one hemisphere and
returns the orientation of $p_3$ with respect to the halfcircle
through $p_1$ and $p_2$. We map this to the 3d orientation predicate
of the origin, $p_1$, $p_2$, and $p_3$ */
template <class R>
int spherical_orientation(const Sphere_point<R>& p1,
const Sphere_point<R>& p2,
const Sphere_point<R>& p3)
{ return CGAL::orientation(CGAL::Point_3<R>(0,0,0),p1,p2,p3); }
/* |spherical_compare| codes our order of points during the sweep. The
south pole is the first point, the north pole is the last point, then
we order lexicographically. We cover the special case where both
points are part of the equator first. Otherwise we sort according to
the angle of the halfcircle through $S$, $N$, and the points with
respect to the xy-plane. If both lie on the same halfcircle then the
angle with respect to $OS$ decides. The parameter $pos=1$ does
everthing in the positive halfsphere. If $pos=-1$ then we rotate the
whole scenery around the y-axis by $\pi$. Then the x-axis points left
and the z-axis into the equatorial plane. */
template <class R>
int spherical_compare(const Sphere_point<R>& p1,
const Sphere_point<R>& p2,
int pos)
{
Sphere_point<R> pS(0,-1,0),pN(0,1,0);
CGAL::Direction_3<R> d1(p1-CGAL::ORIGIN), d2(p2-CGAL::ORIGIN),
dS(pS-CGAL::ORIGIN), dN(pN-CGAL::ORIGIN);
if (d1 == d2) return 0;
if (d1 == dS || d2 == dN) return -1;
if (d1 == dN || d2 == dS) return 1;
// now no more special cases
if ( (p1.hz()==static_cast<typename R::RT>(0)) &&
(p2.hz()==static_cast<typename R::RT>(0)) ) {
// both in xy-plane, pi.hx() can't be zero
int s1 = CGAL_NTS sign(p1.hx());
int s2 = CGAL_NTS sign(p2.hx());
if ( s1 != s2 ) return pos * s1;
// now s1 == s2
return s1 * CGAL::spherical_orientation(p1,Sphere_point<R>(0,0,1),p2);
} else { // not in xy-plane
int or = CGAL::spherical_orientation(pS,p1,p2);
if ( or ) return or;
else // or == 0 => on the same sweep line
return CGAL::spherical_orientation(Sphere_point<R>(-pos,0,0),p2,p1);
}
}
/* the next two functions partition the segments in a list into a list
that carries the segment parts that are only part of a halfspace.
Halfcircles are again divided into two equally sized pieces. */
template <class R, class I>
void partition(const Sphere_circle<R>& c, I start, I beyond,
std::list< Sphere_segment<R> >& Lpos)
{ TRACEN("partition ");
Sphere_segment<R> s1,s2,s3;
while ( start != beyond ) { TRACEN(" "<<*start);
int i = start->intersection(c,s1,s2);
if (i>1) Lpos.push_back(s2);
if (i>0) Lpos.push_back(s1);
++start;
}
}
template <class R, class I>
void partition_xy(I start, I beyond,
std::list< Sphere_segment<R> >& L, int pos)
{
Sphere_circle<R> xy_circle(0,0,1), yz_circle(1,0,0);
Sphere_point<R> S(0,-1,0),N(0,1,0);
Sphere_segment<R> s1,s2;
if (pos > 0) partition(xy_circle,start,beyond,L);
else partition(xy_circle.opposite(),start,beyond,L);
typename std::list< Sphere_segment<R> >::iterator it,itl;
TRACEN("partition_xy ");
CGAL_forall_iterators(it,L) {
TRACEN(" "<<*it);
if ( equal_as_sets(it->sphere_circle(),xy_circle) ) {
TRACEN(" splitting xy seg "<<*it);
int n1 = it->intersection(yz_circle,s1,s2);
if (n1 > 1 && !s2.is_degenerate()) L.insert(it,s2);
if (n1 > 0 && !s1.is_degenerate()) L.insert(it,s1);
int n2 = it->intersection(yz_circle.opposite(),s1,s2);
if (n2 > 1 && !s2.is_degenerate()) L.insert(it,s2);
if (n2 > 0 && !s1.is_degenerate()) L.insert(it,s1);
itl = it; --it; L.erase(itl);
// at least one item was appended
}
}
CGAL_forall_iterators(it,L) {
if ( it->is_halfcircle() ) {
TRACEN(" splitting halfcircle "<<*it);
Sphere_segment<R> s1,s2;
it->split_halfcircle(s1,s2);
*it = s2; L.insert(it,s1);
}
}
// append 4 xy-equator segments:
Sphere_segment<R> sp(S,N,xy_circle);
Sphere_segment<R> sm(S,N,xy_circle.opposite());
Sphere_segment<R> s[4];
sp.split_halfcircle(s[0],s[1]);
sm.split_halfcircle(s[2],s[3]);
L.insert(L.end(),s,s+4);
}
/* |intersection| calculates the intersection of a halfspace $h$
(defined via a great circle $c$) with a sphere segment
$s$. Interesting are the boundary cases. If an endpoint is part of
$h^0$, but the part of $s$ incident to the endpoint is not part of
$h^{0+}$ then we return a trivial segment.
*/
template <typename R>
int Sphere_segment<R>::
intersection(const CGAL::Sphere_circle<R>& c,
Sphere_segment<R>& s1, Sphere_segment<R>& s2) const
{
TRACEN(" intersection "<<*this<<" "<<c);
if ( is_degenerate() ) { TRACEN(" degenerate");
if ( !c.has_on_negative_side(source()) )
{ s1 = *this; return 1; }
return 0;
}
CGAL::Oriented_side or1 = c.oriented_side(source());
CGAL::Oriented_side or2 = c.oriented_side(target());
if ( or1 == CGAL::opposite(or2) && or1 != or2 ) {
/* it is sure that $s$ intersects $h$ in its interior. the
question is which part is in the halfspace $h^+$.*/
TRACEN(" opposite");
Sphere_point<R> i1 = CGAL::intersection(ptr->c_,c);
if ( !has_on(i1) ) i1 = i1.opposite();
if ( or1 == CGAL::ON_POSITIVE_SIDE )
s1 = Sphere_segment<R>(source(),i1,sphere_circle());
else if ( or2 == CGAL::ON_POSITIVE_SIDE )
s1 = Sphere_segment<R>(i1,target(),sphere_circle());
else CGAL_assertion_msg(0,"no intersection.");
return 1;
}
else if ( or1 == CGAL::ON_ORIENTED_BOUNDARY &&
or2 == CGAL::ON_ORIENTED_BOUNDARY ) {
/* if both ends of $s$ are part of $h$ then $s$ is a halfcircle or
$s$ is fully part of $h$. In this case we have to check if the
halfcircle is not part of $h^-$. This can be formulated by an
orientation test of the point $p$ at the tip of the normal of
|s.sphere_circle()| with respect to the plane through the
endpoints of $s$ and the tip of the normal of $h$. */
TRACEN(" both in plane");
if ( source() != target().opposite() ) {
s1 = *this; return 1;
}
// now this is a halfcircle
register bool halfcircle_notin_hminus =
(CGAL::orientation(source(),target(),
CGAL::ORIGIN + c.orthogonal_vector(),
CGAL::ORIGIN + sphere_circle().orthogonal_vector())
!= CGAL::POSITIVE);
TRACE(" ");TRACEV(halfcircle_notin_hminus);
if ( halfcircle_notin_hminus ) { s1 = *this; return 1; }
else {
s1 = Sphere_segment(source(),source(),sphere_circle());
s2 = Sphere_segment(target(),target(),sphere_circle());
return 2;
}
}
else if ( or1 != CGAL::ON_NEGATIVE_SIDE &&
or2 != CGAL::ON_NEGATIVE_SIDE ) {
/* this case covers the endpoints of $s$ as part of the closed
oriented halfspace $h^{0+}$. At least one is part of
$h^{+}$. If $s$ is not long then the segment must be fully part
of $h^{0+}$. Otherwise if $s$ is long, then we at both ends
there are subsegments as part of $h^{0+}$ (one might be
degenerate). */
if ( is_long() ) {
Sphere_point<R> i1 = CGAL::intersection(ptr->c_,c);
Sphere_point<R> i2 = i1.opposite();
Sphere_segment<R> so(i1,i2,sphere_circle());
if ( so.has_on(source()) && so.has_on(target()) )
std::swap(i1,i2);
// now source(),i1,i2,target() are circularly ordered
s1 = Sphere_segment(source(),i1,sphere_circle());
s2 = Sphere_segment(i2,target(),sphere_circle());
TRACEN(" both >= plane, long "<<s1<<s2);
return 2;
} // now short:
TRACEN(" both >= plane, short ");
s1=*this; return 1;
}
else if ( or1 != CGAL::ON_POSITIVE_SIDE &&
or2 != CGAL::ON_POSITIVE_SIDE ) {
/* either both endpoints of $s$ are in $h^-$ or one is in $h^-$
and one on $h^0$. */
if ( is_long() ) {
Sphere_point<R> i1 = CGAL::intersection(ptr->c_,c);
Sphere_point<R> i2 = i1.opposite();
Sphere_segment<R> so(i1,i2,sphere_circle());
TRACEN(" both <= plane, long"<<so);
if ( so.has_on(source()) && so.has_on(target()) )
{ so = so.complement(); }
TRACEN(" both <= plane, long"<<so);
s1 = so; return 1;
} // now short
TRACEN(" both <= plane, short");
if ( or1 == CGAL::ON_ORIENTED_BOUNDARY )
{ s1 = Sphere_segment<R>(source(),source(),sphere_circle()); return 1; }
if ( or2 == CGAL::ON_ORIENTED_BOUNDARY )
{ s1 = Sphere_segment<R>(target(),target(),sphere_circle()); return 1; }
return 0;
}
CGAL_assertion_msg(0,"Oops, forgot some case.");
return -1;
}
CGAL_END_NAMESPACE
#endif //CGAL_SPHERE_PREDICATES_H

View File

@ -0,0 +1,689 @@
// ============================================================================
//
// Copyright (c) 1997-2000 The CGAL Consortium
//
// This software and related documentation is part of an INTERNAL release
// of the Computational Geometry Algorithms Library (CGAL). It is not
// intended for general use.
//
// ----------------------------------------------------------------------------
//
// release : $CGAL_Revision$
// release_date : $CGAL_Date$
//
// file : include/CGAL/Nef_polyhedron_S2.h
// package : Nef_S2
// chapter : Nef Polyhedra
//
// revision : $Revision$
// revision_date : $Date$
//
// author(s) : Michael Seel <seel@mpi-sb.mpg.de>
// maintainer : Michael Seel <seel@mpi-sb.mpg.de>
// coordinator : Michael Seel <seel@mpi-sb.mpg.de>
//
// implementation: Nef polyhedra in the sphere surface
// ============================================================================
#ifndef CGAL_NEF_POLYHEDRON_S2_H
#define CGAL_NEF_POLYHEDRON_S2_H
#include <CGAL/basic.h>
#include <CGAL/Handle_for.h>
#include <CGAL/Random.h>
#include <CGAL/Nef_S2/Sphere_map.h>
#include <CGAL/Nef_S2/SM_decorator.h>
#include <CGAL/Nef_S2/SM_io_parser.h>
#include <CGAL/Nef_S2/SM_point_locator.h>
#include <CGAL/Nef_S2/SM_overlayer.h>
#include <vector>
#include <list>
#undef _DEBUG
#define _DEBUG 121
#include <CGAL/Nef_S2/debug.h>
CGAL_BEGIN_NAMESPACE
template <typename K> class Nef_polyhedron_S2;
template <typename K> class Nef_polyhedron_S2_rep;
template <typename K>
std::ostream& operator<<(std::ostream&, const Nef_polyhedron_S2<K>&);
template <typename K>
std::istream& operator>>(std::istream&, Nef_polyhedron_S2<K>&);
template <typename K>
class Nef_polyhedron_S2_rep : public Ref_counted
{ typedef Nef_polyhedron_S2_rep<K> Self;
friend class Nef_polyhedron_S2<K>;
typedef K Kernel;
typedef CGAL::Sphere_geometry<Kernel> Sphere_kernel;
typedef CGAL::Sphere_map<Sphere_kernel> Sphere_map;
typedef CGAL::SM_const_decorator<Sphere_map,Sphere_kernel>
Const_decorator;
typedef CGAL::SM_decorator<Sphere_map,Sphere_kernel> Decorator;
typedef CGAL::SM_overlayer<Decorator> Overlayer;
typedef CGAL::SM_point_locator<Decorator> Locator;
Sphere_map sm_;
public:
Nef_polyhedron_S2_rep() : Ref_counted(), sm_() {}
Nef_polyhedron_S2_rep(const Self& R) : Ref_counted(), sm_() {}
~Nef_polyhedron_S2_rep() { sm_.clear(); }
};
/*{\Moptions print_title=yes }*/
/*{\Manpage {Nef_polyhedron_S2}{K}
{Nef Polyhedra in the sphere surface}{N}}*/
/*{\Mdefinition An instance of data type |\Mname| is a subset of $S_2$
that is the result of forming complements and intersections starting
from a finite set |H| of half-spaces. |\Mtype| is closed under all
binary set operations |intersection|, |union|, |difference|,
|complement| and under the topological operations |boundary|,
|closure|, and |interior|.
The template parameter |Kernel| is specified via a kernel concept.
|Kernel| must be a model of the concept |NefSphereKernelTraits_2|.
}*/
template <typename K>
class Nef_polyhedron_S2 : public Handle_for< Nef_polyhedron_S2_rep<K> >
{
public:
typedef K Kernel;
/*{\Mtypes 7}*/
typedef Nef_polyhedron_S2<K> Self;
typedef Nef_polyhedron_S2_rep<K> Rep;
typedef Handle_for< Nef_polyhedron_S2_rep<K> > Base;
typedef typename Rep::Sphere_kernel Sphere_kernel;
typedef typename Rep::Sphere_map Sphere_map;
typedef typename Sphere_kernel::Sphere_point Sphere_point;
/*{\Mtypemember points in the sphere surface.}*/
typedef typename Sphere_kernel::Sphere_segment Sphere_segment;
/*{\Mtypemember segments in the sphere surface.}*/
typedef typename Sphere_kernel::Sphere_circle Sphere_circle;
/*{\Mtypemember oriented great circles modeling spherical half-spaces}*/
typedef typename Sphere_kernel::Sphere_direction Sphere_direction;
typedef typename Sphere_map::Mark Mark;
/*{\Xtypemember marking set membership or exclusion.}*/
enum Boundary { EXCLUDED=0, INCLUDED=1 };
/*{\Menum construction selection.}*/
enum Content { EMPTY=0, COMPLETE=1 };
/*{\Menum construction selection}*/
const Sphere_map& sphere_map() const { return ptr->sm_; }
protected:
Sphere_map& sphere_map() { return ptr->sm_; }
struct AND { bool operator()(bool b1, bool b2) const { return b1&&b2; } };
struct OR { bool operator()(bool b1, bool b2) const { return b1||b2; } };
struct DIFF { bool operator()(bool b1, bool b2) const { return b1&&!b2; } };
struct XOR { bool operator()(bool b1, bool b2) const
{ return (b1&&!b2)||(!b1&&b2); } };
typedef Nef_polyhedron_S2_rep<K> Nef_rep;
typedef typename Nef_rep::Decorator Decorator;
typedef typename Nef_rep::Const_decorator Const_decorator;
typedef typename Nef_rep::Overlayer Overlayer;
typedef typename Nef_rep::Locator Locator;
friend std::ostream& operator<< CGAL_NULL_TMPL_ARGS
(std::ostream& os, const Nef_polyhedron_S2<K>& NP);
friend std::istream& operator>> CGAL_NULL_TMPL_ARGS
(std::istream& is, Nef_polyhedron_S2<K>& NP);
typedef typename Decorator::Vertex_handle Vertex_handle;
typedef typename Decorator::Halfedge_handle Halfedge_handle;
typedef typename Decorator::Halfloop_handle Halfloop_handle;
typedef typename Decorator::Face_handle Face_handle;
typedef typename Decorator::Vertex_const_handle Vertex_const_handle;
typedef typename Decorator::Halfedge_const_handle Halfedge_const_handle;
typedef typename Decorator::Halfloop_const_handle Halfloop_const_handle;
typedef typename Decorator::Face_const_handle Face_const_handle;
typedef typename Decorator::Vertex_iterator Vertex_iterator;
typedef typename Decorator::Halfedge_iterator Halfedge_iterator;
typedef typename Decorator::Halfloop_iterator Halfloop_iterator;
typedef typename Decorator::Face_iterator Face_iterator;
typedef typename Const_decorator::Vertex_const_iterator
Vertex_const_iterator;
typedef typename Const_decorator::Halfedge_const_iterator
Halfedge_const_iterator;
typedef typename Const_decorator::Halfloop_const_iterator
Halfloop_const_iterator;
typedef typename Const_decorator::Face_const_iterator
Face_const_iterator;
typedef std::list<Sphere_segment> SS_list;
typedef typename SS_list::const_iterator SS_iterator;
public:
/*{\Mcreation 3}*/
Nef_polyhedron_S2(Content sphere = EMPTY) : Base(Nef_rep())
/*{\Mcreate creates an instance |\Mvar| of type |\Mname|
and initializes it to the empty set if |sphere == EMPTY|
and to the whole sphere if |sphere == COMPLETE|.}*/
{
SS_list L;
Decorator D(sphere_map());
D.mark_of_halfsphere(-1) = D.mark_of_halfsphere(+1) = bool(sphere);
}
Nef_polyhedron_S2(const Sphere_circle& c,
Boundary circle = INCLUDED) : Base(Nef_rep())
/*{\Mcreate creates a Nef polyhedron |\Mvar| containing the half-sphere
left of |c| including |c| if |circle==INCLUDED|, excluding |c| if
|circle==EXCLUDED|.}*/
{ TRACEN("Nef_polyhedron_S2(): construction from circle "<<c);
Overlayer D(sphere_map()); D.create(c);
Halfloop_handle h = D.halfloop();
if ( D.circle(h) != c ) h = D.twin(h);
D.mark(D.face(h)) = true;
D.mark(h) = bool(circle);
Locator L(sphere_map()); L.init_marks_of_halfspheres();
}
template <class Forward_iterator>
Nef_polyhedron_S2(Forward_iterator first, Forward_iterator beyond,
Boundary b = INCLUDED) : Base(Nef_rep())
/*{\Mcreate creates a Nef polyhedron |\Mvar| from the set of sphere
segments in the iterator range |[first,beyond)|. If the set of sphere
segments is a simple polygon that separates the sphere surface
into two regions, then the polygonal region that is left of the
segment |*first| is selected. The polygonal region includes its
boundary if |b = INCLUDED| and excludes the boundary
otherwise. |Forward_iterator| has to be an iterator with value
type |Sphere_segment|.}*/
{ TRACEN("Nef_polyhedron_S2(): creation from segment range");
CGAL_assertion(first!=beyond);
Overlayer D(sphere_map());
Sphere_segment s = *first;
D.create_from_segments(first,beyond);
Halfedge_iterator e;
CGAL_forall_halfedges(e,D) {
Sphere_circle c(D.circle(e));
if ( c == s.sphere_circle() ) break;
}
if ( e != Halfedge_iterator() ) {
if ( D.circle(e) != s.sphere_circle() ) e = D.twin(e);
CGAL_assertion( D.circle(e) == s.sphere_circle() );
D.set_marks_in_face_cycle(e,bool(b));
if ( D.number_of_faces() > 2 ) D.mark(D.face(e)) = true;
else D.mark(D.face(e)) = !bool(b);
return;
}
D.simplify();
Locator L(sphere_map()); L.init_marks_of_halfspheres();
}
Nef_polyhedron_S2(const Nef_polyhedron_S2<K>& N1) : Base(N1) {}
Nef_polyhedron_S2& operator=(const Nef_polyhedron_S2<K>& N1)
{ Base::operator=(N1); return (*this); }
~Nef_polyhedron_S2() {}
template <class Forward_iterator>
Nef_polyhedron_S2(Forward_iterator first, Forward_iterator beyond,
double p) : Base(Nef_rep())
/*{\Xcreate creates a random Nef polyhedron from the arrangement of
the set of circles |S = set[first,beyond)|. The cells of the arrangement
are selected uniformly at random with probability $p$. \precond $0 < p
< 1$.}*/
{ CGAL_assertion(0<p && p<1);
CGAL_assertion(first!=beyond);
Overlayer D(sphere_map());
D.create_from_circles(first, beyond); D.simplify();
Vertex_iterator v; Halfedge_iterator e; Face_iterator f;
CGAL_forall_vertices(v,D)
D.mark(v) = ( default_random.get_double() < p ? true : false );
CGAL_forall_halfedges(e,D)
D.mark(e) = ( default_random.get_double() < p ? true : false );
CGAL_forall_faces(f,D)
D.mark(f) = ( default_random.get_double() < p ? true : false );
D.simplify();
Locator L(sphere_map()); L.init_marks_of_halfspheres();
}
protected:
Nef_polyhedron_S2(const Sphere_map& H, bool clone=true) : Base(Nef_rep())
/*{\Xcreate makes |\Mvar| a new object. If |clone==true| then the
underlying structure of |H| is copied into |\Mvar|.}*/
{ if (clone) ptr->sm_ = H; }
void clone_rep() { *this = Nef_polyhedron_S2<K>(sphere_map()); }
/*{\Moperations 4 3 }*/
public:
void clear(Content plane = EMPTY)
{ *this = Nef_polyhedron_S2(plane); }
/*{\Mop makes |\Mvar| the empty set if |plane == EMPTY| and the
full plane if |plane == COMPLETE|.}*/
bool is_empty() const
/*{\Mop returns true if |\Mvar| is empty, false otherwise.}*/
{ Const_decorator D(sphere_map());
Face_const_iterator f = D.faces_begin();
return (D.number_of_vertices()==0 &&
D.number_of_edges()==0 &&
D.number_of_loops()==0 &&
D.number_of_faces()==1 &&
D.mark(f) == false);
}
bool is_plane() const
/*{\Mop returns true if |\Mvar| is the whole plane, false otherwise.}*/
{ Const_decorator D(sphere_map());
Face_const_iterator f = D.faces_begin();
return (D.number_of_vertices()==0 &&
D.number_of_edges()==0 &&
D.number_of_loops()==0 &&
D.number_of_faces()==1 &&
D.mark(f) == true);
}
void extract_complement()
{ TRACEN("extract complement");
if ( ptr->is_shared() ) clone_rep();
Overlayer D(sphere_map());
Vertex_iterator v, vend = D.vertices_end();
for(v = D.vertices_begin(); v != vend; ++v)
D.mark(v) = !D.mark(v);
Unique_hash_map<Halfedge_iterator,bool> Done(false);
Halfedge_iterator e, eend = D.halfedges_end();
for(e = D.halfedges_begin(); e != eend; ++e) {
if ( Done[e] ) continue;
D.mark(e) = !D.mark(e);
Done[e] = Done[D.twin(e)] = true;
}
Face_iterator f, fend = D.faces_end();
for(f = D.faces_begin(); f != fend; ++f)
D.mark(f) = !D.mark(f);
if ( D.has_loop() )
D.mark(D.halfloop()) = !D.mark(D.halfloop());
D.mark_of_halfsphere(-1) = !D.mark_of_halfsphere(-1);
D.mark_of_halfsphere(+1) = !D.mark_of_halfsphere(+1);
}
void extract_interior()
{ TRACEN("extract interior");
if ( ptr->is_shared() ) clone_rep();
Overlayer D(sphere_map());
Vertex_iterator v, vend = D.vertices_end();
for(v = D.vertices_begin(); v != vend; ++v) D.mark(v) = false;
Halfedge_iterator e, eend = D.halfedges_end();
for(e = D.halfedges_begin(); e != eend; ++e) D.mark(e) = false;
if ( D.has_loop() ) D.mark(D.halfloop()) = false;
D.simplify();
}
void extract_boundary()
{ TRACEN("extract boundary");
if ( ptr->is_shared() ) clone_rep();
Overlayer D(sphere_map());
Vertex_iterator v, vend = D.vertices_end();
for(v = D.vertices_begin(); v != vend; ++v) D.mark(v) = true;
Halfedge_iterator e, eend = D.halfedges_end();
for(e = D.halfedges_begin(); e != eend; ++e) D.mark(e) = true;
if ( D.has_loop() ) D.mark(D.halfloop()) = true;
Face_iterator f, fend = D.faces_end();
for(f = D.faces_begin(); f != fend; ++f) D.mark(f) = false;
D.mark_of_halfsphere(-1) = D.mark_of_halfsphere(+1) = false;
D.simplify();
}
void extract_closure()
/*{\Xop converts |\Mvar| to its closure. }*/
{ TRACEN("extract closure");
extract_complement();
extract_interior();
extract_complement();
}
void extract_regularization()
/*{\Xop converts |\Mvar| to its regularization. }*/
{ TRACEN("extract regularization");
extract_interior();
extract_closure();
}
/*{\Mtext \headerline{Constructive Operations}}*/
Nef_polyhedron_S2<K> complement() const
/*{\Mop returns the complement of |\Mvar| in the plane.}*/
{ Nef_polyhedron_S2<K> res = *this;
res.extract_complement();
return res;
}
Nef_polyhedron_S2<K> interior() const
/*{\Mop returns the interior of |\Mvar|.}*/
{ Nef_polyhedron_S2<K> res = *this;
res.extract_interior();
return res;
}
Nef_polyhedron_S2<K> closure() const
/*{\Mop returns the closure of |\Mvar|.}*/
{ Nef_polyhedron_S2<K> res = *this;
res.extract_closure();
return res;
}
Nef_polyhedron_S2<K> boundary() const
/*{\Mop returns the boundary of |\Mvar|.}*/
{ Nef_polyhedron_S2<K> res = *this;
res.extract_boundary();
return res;
}
Nef_polyhedron_S2<K> regularization() const
/*{\Mop returns the regularized polyhedron (closure of interior).}*/
{ Nef_polyhedron_S2<K> res = *this;
res.extract_regularization();
return res;
}
Nef_polyhedron_S2<K> intersection(const Nef_polyhedron_S2<K>& N1) const
/*{\Mop returns |\Mvar| $\cap$ |N1|. }*/
{ Nef_polyhedron_S2<K> res(sphere_map(),false); // empty
Overlayer D(res.sphere_map());
D.subdivide(sphere_map(),N1.sphere_map());
AND _and; D.select(_and); D.simplify();
return res;
}
Nef_polyhedron_S2<K> join(const Nef_polyhedron_S2<K>& N1) const
/*{\Mop returns |\Mvar| $\cup$ |N1|. }*/
{ Nef_polyhedron_S2<K> res(sphere_map(),false); // empty
Overlayer D(res.sphere_map());
D.subdivide(sphere_map(),N1.sphere_map());
OR _or; D.select(_or); D.simplify();
return res;
}
Nef_polyhedron_S2<K> difference(const Nef_polyhedron_S2<K>& N1) const
/*{\Mop returns |\Mvar| $-$ |N1|. }*/
{ Nef_polyhedron_S2<K> res(sphere_map(),false); // empty
Overlayer D(res.sphere_map());
D.subdivide(sphere_map(),N1.sphere_map());
DIFF _diff; D.select(_diff); D.simplify();
return res;
}
Nef_polyhedron_S2<K> symmetric_difference(
const Nef_polyhedron_S2<K>& N1) const
/*{\Mop returns the symmectric difference |\Mvar - T| $\cup$
|T - \Mvar|. }*/
{ Nef_polyhedron_S2<K> res(sphere_map(),false); // empty
Overlayer D(res.sphere_map());
D.subdivide(sphere_map(),N1.sphere_map());
XOR _xor; D.select(_xor); D.simplify();
return res;
}
/*{\Mtext Additionally there are operators |*,+,-,^,!| which
implement the binary operations \emph{intersection}, \emph{union},
\emph{difference}, \emph{symmetric difference}, and the unary
operation \emph{complement} respectively. There are also the
corresponding modification operations |*=,+=,-=,^=|.}*/
Nef_polyhedron_S2<K> operator*(const Nef_polyhedron_S2<K>& N1) const
{ return intersection(N1); }
Nef_polyhedron_S2<K> operator+(const Nef_polyhedron_S2<K>& N1) const
{ return join(N1); }
Nef_polyhedron_S2<K> operator-(const Nef_polyhedron_S2<K>& N1) const
{ return difference(N1); }
Nef_polyhedron_S2<K> operator^(const Nef_polyhedron_S2<K>& N1) const
{ return symmetric_difference(N1); }
Nef_polyhedron_S2<K> operator!() const
{ return complement(); }
Nef_polyhedron_S2<K>& operator*=(const Nef_polyhedron_S2<K>& N1)
{ this = intersection(N1); return *this; }
Nef_polyhedron_S2<K>& operator+=(const Nef_polyhedron_S2<K>& N1)
{ this = join(N1); return *this; }
Nef_polyhedron_S2<K>& operator-=(const Nef_polyhedron_S2<K>& N1)
{ this = difference(N1); return *this; }
Nef_polyhedron_S2<K>& operator^=(const Nef_polyhedron_S2<K>& N1)
{ this = symmetric_difference(N1); return *this; }
/*{\Mtext There are also comparison operations like |<,<=,>,>=,==,!=|
which implement the relations subset, subset or equal, superset, superset
or equal, equality, inequality, respectively.}*/
bool operator==(const Nef_polyhedron_S2<K>& N1) const
{ return symmetric_difference(N1).is_empty(); }
bool operator!=(const Nef_polyhedron_S2<K>& N1) const
{ return !operator==(N1); }
bool operator<=(const Nef_polyhedron_S2<K>& N1) const
{ return difference(N1).is_empty(); }
bool operator<(const Nef_polyhedron_S2<K>& N1) const
{ return difference(N1).is_empty() && !N1.difference(*this).is_empty(); }
bool operator>=(const Nef_polyhedron_S2<K>& N1) const
{ return N1.difference(*this).is_empty(); }
bool operator>(const Nef_polyhedron_S2<K>& N1) const
{ return N1.difference(*this).is_empty() && !difference(N1).is_empty(); }
/*{\Mtext \headerline{Exploration - Point location - Ray shooting}
As Nef polyhedra are the result of forming complements
and intersections starting from a set |H| of half-spaces that are
defined by oriented lines in the plane, they can be represented by
an attributed plane map $M = (V,E,F)$. For topological queries
within |M| the following types and operations allow exploration
access to this structure.}*/
/*{\Mtypes 3}*/
typedef Const_decorator Topological_explorer;
//typedef CGAL::SM_explorer<Const_decorator,T> Explorer;
typedef Const_decorator Explorer;
/*{\Mtypemember a decorator to examine the underlying plane map.
See the manual page of |Explorer|.}*/
typedef typename Locator::Object_handle Object_handle;
/*{\Mtypemember a generic handle to an object of the underlying
plane map. The kind of object |(vertex, halfedge, face)| can
be determined and the object can be assigned to a corresponding
handle by the three functions:\\
|bool assign(Vertex_const_handle& h, Object_handle)|\\
|bool assign(Halfedge_const_handle& h, Object_handle)|\\
|bool assign(Face_const_handle& h, Object_handle)|\\
where each function returns |true| iff the assignment to
|h| was done.}*/
/*{\Moperations 3 1 }*/
bool contains(Object_handle h) const
/*{\Mop returns true iff the object |h| is contained in the set
represented by |\Mvar|.}*/
{ Locator PL(sphere_map()); return PL.mark(h); }
bool contained_in_boundary(Object_handle h) const
/*{\Mop returns true iff the object |h| is contained in the $1$-skeleton
of |\Mvar|.}*/
{ Vertex_const_handle v;
Halfedge_const_handle e;
return ( CGAL::assign(v,h) || CGAL::assign(e,h) );
}
Object_handle locate(const Sphere_point& p) const
/*{\Mop returns a generic handle |h| to an object (face, halfedge, vertex)
of the underlying plane map that contains the point |p| in its relative
interior. The point |p| is contained in the set represented by |\Mvar| if
|\Mvar.contains(h)| is true. The location mode flag |m| allows one to choose
between different point location strategies.}*/
{
Locator PL(sphere_map());
return PL.locate(p);
}
struct INSET {
const Const_decorator& D;
INSET(const Const_decorator& Di) : D(Di) {}
bool operator()(Vertex_const_handle v) const { return D.mark(v); }
bool operator()(Halfedge_const_handle e) const { return D.mark(e); }
bool operator()(Halfloop_const_handle l) const { return D.mark(l); }
bool operator()(Face_const_handle f) const { return D.mark(f); }
};
Object_handle ray_shoot(const Sphere_point& p,
const Sphere_direction& d) const
/*{\Mop returns a handle |h| with |\Mvar.contains(h)| that can be
converted to a |Vertex_/Halfedge_/Face_const_handle| as described
above. The object returned is intersected by the ray starting in |p|
with direction |d| and has minimal distance to |p|. The operation
returns the null handle |NULL| if the ray shoot along |d| does not hit
any object |h| of |\Mvar| with |\Mvar.contains(h)|.}*/
{
Locator PL(sphere_map());
return PL.ray_shoot(p,d,INSET(PL));
}
struct INSKEL {
bool operator()(Vertex_const_handle) const { return true; }
bool operator()(Halfedge_const_handle) const { return true; }
bool operator()(Halfloop_const_handle) const { return true; }
bool operator()(Face_const_handle) const { return false; }
};
Object_handle ray_shoot_to_boundary(const Sphere_point& p,
const Sphere_direction& d) const
/*{\Mop returns a handle |h| that can be converted to a
|Vertex_/Halfedge_const_handle| as described above. The object
returned is part of the $1$-skeleton of |\Mvar|, intersected by the
ray starting in |p| with direction |d| and has minimal distance to
|p|. The operation returns the null handle |NULL| if the ray shoot
along |d| does not hit any $1$-skeleton object |h| of |\Mvar|. The
location mode flag |m| allows one to choose between different point
location strategies.}*/
{
Locator PL(sphere_map());
return PL.ray_shoot(p,d,INSKEL());
}
Explorer explorer() const
/*{\Mop returns a decorator object which allows read-only access of
the underlying plane map. See the manual page |Explorer| for its
usage.}*/
{ return Explorer(const_cast<Sphere_map&>(sphere_map())); }
/*{\Mtext\headerline{Input and Output}
A Nef polyhedron |\Mvar| can be visualized in an open GL window. The
output operator is defined in the file
|CGAL/IO/Nef_\-poly\-hedron_2_\-Win\-dow_\-stream.h|.
}*/
/*{\Mimplementation Nef polyhedra are implemented on top of a halfedge
data structure and use linear space in the number of vertices, edges
and facets. Operations like |empty| take constant time. The
operations |clear|, |complement|, |interior|, |closure|, |boundary|,
|regularization|, input and output take linear time. All binary set
operations and comparison operations take time $O(n \log n)$ where $n$
is the size of the output plus the size of the input.
The point location and ray shooting operations are implemented in
the naive way. The operations run in linear query time without
any preprocessing.}*/
/*{\Mexample Nef polyhedra are parameterized by a standard CGAL
kernel.
\begin{Mverb}
#include <CGAL/Homogeneous.h>
#include <CGAL/leda_integer.h>
#include <CGAL/Nef_polyhedron_S2.h>
using namespace CGAL;
typedef Homogeneous<leda_integer> Kernel;
typedef Nef_polyhedron_S2<Kernel> Nef_polyhedron;
typedef Nef_polyhedron::Sphere_circle Sphere_circle;
int main()
{
Nef_polyhedron N1(Sphere_circle(1,0,0));
Nef_polyhedron N2(Sphere_circle(0,1,0), Nef_polyhedron::EXCLUDED);
Nef_polyhedron N3 = N1 * N2; // line (*)
return 0;
}
\end{Mverb}
After line (*) |N3| is the intersection of |N1| and |N2|.}*/
}; // end of Nef_polyhedron_S2
template <typename K>
std::ostream& operator<<
(std::ostream& os, const Nef_polyhedron_S2<K>& NP)
{
os << "Nef_polyhedron_S2\n";
typedef typename Nef_polyhedron_S2<K>::Decorator Decorator;
typedef typename Nef_polyhedron_S2<K>::Sphere_map Sphere_map;
CGAL::SM_io_parser<Decorator> O(os,
const_cast<Sphere_map&>(NP.sphere_map()));
O.print();
return os;
}
template <typename K>
std::istream& operator>>
(std::istream& is, Nef_polyhedron_S2<K>& NP)
{
typedef typename Nef_polyhedron_S2<K>::Decorator Decorator;
CGAL::SM_io_parser<Decorator> I(is, NP.sphere_map());
if ( I.check_sep("Nef_polyhedron_S2") ) I.read();
else {
std::cerr << "Nef_polyhedron_S2 input corrupted." << std::endl;
NP = Nef_polyhedron_S2<K>();
}
typename Nef_polyhedron_S2<K>::Topological_explorer D(NP.explorer());
D.check_integrity_and_topological_planarity();
return is;
}
CGAL_END_NAMESPACE
#endif //CGAL_NEF_POLYHEDRON_S2_H

View File

@ -0,0 +1 @@
Michael Seel <seel@mpi-sb.mpg.de>

1
Packages/Nef_S2/version Normal file
View File

@ -0,0 +1 @@
0.9.0 ( 20 Nov 2001)