diff --git a/Packages/Nef_S2/TODO b/Packages/Nef_S2/TODO new file mode 100644 index 00000000000..1b00335f5e4 --- /dev/null +++ b/Packages/Nef_S2/TODO @@ -0,0 +1,4 @@ +Possible Improvements for future releases are + +1) introduce clean spherical kernel trais + diff --git a/Packages/Nef_S2/changes.txt b/Packages/Nef_S2/changes.txt new file mode 100644 index 00000000000..9c656f7323b --- /dev/null +++ b/Packages/Nef_S2/changes.txt @@ -0,0 +1,6 @@ +Nef_S2 Package: Release changes +---------------------------------------------------------------------- + +0.9 (20 Nov 2001) + + initial release diff --git a/Packages/Nef_S2/demo/Nef_S2/GoodCalls b/Packages/Nef_S2/demo/Nef_S2/GoodCalls new file mode 100644 index 00000000000..b408ad498f0 --- /dev/null +++ b/Packages/Nef_S2/demo/Nef_S2/GoodCalls @@ -0,0 +1,4 @@ +nef-demo -n 4 -r 3 +nef-demo -n 8 -r 1 +nef-demo + diff --git a/Packages/Nef_S2/demo/Nef_S2/Nef_polyhedron_S2-demo.C b/Packages/Nef_S2/demo/Nef_S2/Nef_polyhedron_S2-demo.C new file mode 100644 index 00000000000..64e7a4136da --- /dev/null +++ b/Packages/Nef_S2/demo/Nef_S2/Nef_polyhedron_S2-demo.C @@ -0,0 +1,95 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +typedef leda_integer NT; +typedef CGAL::Homogeneous Kernel; +typedef Kernel::Point_3 Point_3; +typedef Kernel::Plane_3 Plane_3; + +typedef CGAL::Nef_polyhedron_S2 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 Creator; +typedef CGAL::Random_points_in_cube_3 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 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::iterator it; + CGAL_forall_iterators(it,L) output << *it << ' '; + output << std::endl; + output.close(); + + // partition input into two lists + std::list 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; + +} + + diff --git a/Packages/Nef_S2/demo/Nef_S2/Nef_polyhedron_S2-demo2.C b/Packages/Nef_S2/demo/Nef_S2/Nef_polyhedron_S2-demo2.C new file mode 100644 index 00000000000..3c44f5ab1ce --- /dev/null +++ b/Packages/Nef_S2/demo/Nef_S2/Nef_polyhedron_S2-demo2.C @@ -0,0 +1,80 @@ +#include +#include +#include +#include "Nef_polyhedron_S2.h" +#include "Nef_S2/Nef_polyhedron_S2_OGLUT_stream.h" +#include + +//#define TRACEV(t) std::cerr << #t << " = " << t < 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 Creator; +typedef CGAL::Random_points_in_cube_3 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 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::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; + +} + + diff --git a/Packages/Nef_S2/demo/Nef_S2/SM_overlayer-demo.C b/Packages/Nef_S2/demo/Nef_S2/SM_overlayer-demo.C new file mode 100644 index 00000000000..c0fac1d4e3d --- /dev/null +++ b/Packages/Nef_S2/demo/Nef_S2/SM_overlayer-demo.C @@ -0,0 +1,109 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "SM_overlayer.h" + +typedef CGAL::Sphere_geometry SKernel; +typedef CGAL::Sphere_map 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 SM_decorator; +typedef CGAL::SM_overlayer SM_overlayer; + +typedef CGAL::Creator_uniform_3 Creator; +typedef CGAL::Random_points_in_cube_3 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 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::iterator it; + forall_iterators(it,L) output << *it; + output << std::endl; + output.close(); + std::list 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; +} + + diff --git a/Packages/Nef_S2/demo/Nef_S2/Sphere_geometry-demo.C b/Packages/Nef_S2/demo/Nef_S2/Sphere_geometry-demo.C new file mode 100644 index 00000000000..346fa0600b7 --- /dev/null +++ b/Packages/Nef_S2/demo/Nef_S2/Sphere_geometry-demo.C @@ -0,0 +1,114 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef leda_integer RT; +typedef CGAL::Homogeneous HKernel; +typedef CGAL::Sphere_point SPoint; +typedef CGAL::Sphere_segment SSegment; +typedef CGAL::Plane_3 Plane; +typedef CGAL::Point_3 Point; +typedef CGAL::Direction_3 Direction; + +typedef CGAL::Creator_uniform_3 Creator; +typedef CGAL::Random_points_in_cube_3 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 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::iterator it; + CGAL_forall_iterators(it,L) output << *it; + output << std::endl; + output.close(); + leda_sphere_map_overlayer 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; +} + + + + + diff --git a/Packages/Nef_S2/demo/Nef_S2/makefile b/Packages/Nef_S2/demo/Nef_S2/makefile new file mode 100644 index 00000000000..496f66371a0 --- /dev/null +++ b/Packages/Nef_S2/demo/Nef_S2/makefile @@ -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 /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) $< + diff --git a/Packages/Nef_S2/description.txt b/Packages/Nef_S2/description.txt new file mode 100644 index 00000000000..6f67e9697e2 --- /dev/null +++ b/Packages/Nef_S2/description.txt @@ -0,0 +1 @@ +Nef polyhedra in the plane diff --git a/Packages/Nef_S2/dont_submit b/Packages/Nef_S2/dont_submit new file mode 100644 index 00000000000..743eb210b5d --- /dev/null +++ b/Packages/Nef_S2/dont_submit @@ -0,0 +1,2 @@ +TODO +noweb diff --git a/Packages/Nef_S2/include/CGAL/IO/Nef_polyhedron_S2_OGLUT_stream.h b/Packages/Nef_S2/include/CGAL/IO/Nef_polyhedron_S2_OGLUT_stream.h new file mode 100644 index 00000000000..be9877771c5 --- /dev/null +++ b/Packages/Nef_S2/include/CGAL/IO/Nef_polyhedron_S2_OGLUT_stream.h @@ -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 +// maintainer : Michael Seel +// coordinator : Michael Seel +// +// ============================================================================ + +#ifndef NEF_POLYHEDRON_S2_OGLUT_STREAM_H +#define NEF_POLYHEDRON_S2_OGLUT_STREAM_H + +#include +#include +#include + +CGAL_BEGIN_NAMESPACE + + +struct OGLUT_stream { // dummy class + OGLUT_stream() {} + void display() { CGAL::OGL::start_viewer(); } +}; + +static OGLUT_stream ogl; + +template +CGAL::OGLUT_stream& operator<<(CGAL::OGLUT_stream& ogls, + const Nef_polyhedron_S2& P) +{ + typedef Nef_polyhedron_S2 Polyhedron; + typedef typename Polyhedron::Sphere_map Sphere_map; + typedef typename Polyhedron::Sphere_kernel Sphere_kernel; + typedef CGAL::SM_visualizor 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 + + diff --git a/Packages/Nef_S2/include/CGAL/Nef_S2/Generic_handle_map.h b/Packages/Nef_S2/include/CGAL/Nef_S2/Generic_handle_map.h new file mode 100644 index 00000000000..08a28eb3dfe --- /dev/null +++ b/Packages/Nef_S2/include/CGAL/Nef_S2/Generic_handle_map.h @@ -0,0 +1,34 @@ +#ifndef CGAL_GENERIC_HANDLE_MAP_H +#define CGAL_GENERIC_HANDLE_MAP_H + +#include + +CGAL_BEGIN_NAMESPACE + +struct Void_handle_hash_function { + std::size_t operator() (void* h) const { + return std::size_t(h); + } +}; + + +template +class Generic_handle_map : public + Unique_hash_map +{ typedef Unique_hash_map Base; +public: + Generic_handle_map() : Base() {} + Generic_handle_map(I i) : Base(i) {} + + template + const I& operator[](H h) const + { return Base::operator[](&*h); } + + template + I& operator[](H h) + { return Base::operator[](&*h); } + +}; + +CGAL_END_NAMESPACE +#endif //CGAL_GENERIC_HANDLE_MAP_H diff --git a/Packages/Nef_S2/include/CGAL/Nef_S2/SM_checker.h b/Packages/Nef_S2/include/CGAL/Nef_S2/SM_checker.h new file mode 100644 index 00000000000..a2b0e9a06e5 --- /dev/null +++ b/Packages/Nef_S2/include/CGAL/Nef_S2/SM_checker.h @@ -0,0 +1,238 @@ +#ifndef CGAL_SM_CHECKER_H +#define CGAL_SM_CHECKER_H + +#include +#include + +#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 +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 + + +template +void SM_checker:: +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 +void SM_checker:: +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 +void SM_checker:: +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 SM_checker::Halfedge_const_iterator +SM_checker:: +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 +void SM_checker:: +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 + diff --git a/Packages/Nef_S2/include/CGAL/Nef_S2/SM_const_decorator.h b/Packages/Nef_S2/include/CGAL/Nef_S2/SM_const_decorator.h new file mode 100644 index 00000000000..5eaf87e8b64 --- /dev/null +++ b/Packages/Nef_S2/include/CGAL/Nef_S2/SM_const_decorator.h @@ -0,0 +1,546 @@ +#ifndef CGAL_SM_CONST_DECORATOR_H +#define CGAL_SM_CONST_DECORATOR_H + +#include +#include +#include +#include +#include +#include +#include +#include +#undef _DEBUG +#define _DEBUG 127 +#include + +CGAL_BEGIN_NAMESPACE + +template +class CircFromIt : public Iter { + // Ptr node; // The internal node ptr inherited from It. + typedef CircFromIt 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 +inline CGAL::Circulator_tag +query_circulator_or_iterator(const CircFromIt& ) +{ return CGAL::Circulator_tag(); } + +template +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 +struct move_edge_around_face { + void forward(HE& e) const { e = (e->next_); } + void backward(HE& e) const { e = (e->prev_); } +}; + +template +class PntItFromVertIt : public Iter { +public: + typedef PntItFromVertIt 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 +class SM_const_decorator +{ typedef SM_const_decorator 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_around_vertex_const_circulator; +/*{\Mtypemember circulating the adjacency list of an vertex |v|.}*/ + +typedef CircFromIt< + Halfedge_const_iterator, + move_edge_around_face > + 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; +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(&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 +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 +std::string PH(H h) +{ if (h == H()) return "nil"; return h->debug(); } + + +template +void SM_const_decorator:: +check_integrity_and_topological_planarity(bool faces) const +{ + TRACEN("check_integrity_and_topological_planarity:"); + using CGAL::Object_index; + Object_index + VI(vertices_begin(),vertices_end(),'v'); + Object_index + EI(halfedges_begin(),halfedges_end(),'e'); + Object_index + 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)<<" "< +typename SM_const_decorator::Size_type +SM_const_decorator:: +number_of_face_cycles() const +{ + unsigned int fc_num=0; + CGAL::Unique_hash_map 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_const_decorator::Size_type +SM_const_decorator:: +number_of_connected_components() const +{ + int comp_num=0; + CGAL::Unique_hash_map visited(false); + Vertex_const_iterator v; + CGAL_forall_vertices(v,*this) { + if (visited[v]) continue; + std::list 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 + diff --git a/Packages/Nef_S2/include/CGAL/Nef_S2/SM_constrained_triang_traits.h b/Packages/Nef_S2/include/CGAL/Nef_S2/SM_constrained_triang_traits.h new file mode 100644 index 00000000000..cbcb711d50c --- /dev/null +++ b/Packages/Nef_S2/include/CGAL/Nef_S2/SM_constrained_triang_traits.h @@ -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 +// maintainer : Michael Seel +// coordinator : Michael Seel +// +// implementation: Constrained triangulation of a sphere map +// ============================================================================ +#ifndef CGAL_SM_CONSTRAINED_TRIANG_TRAITS_H +#define CGAL_SM_CONSTRAINED_TRIANG_TRAITS_H + +#include +#include +#include +//#include +#include +#include +#include +#undef _DEBUG +#define _DEBUG 139 +#include + +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 +class SM_constrained_triang_traits : public Decorator_ { +public: + typedef SM_constrained_triang_traits 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 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 + Sweep_status_structure; + typedef typename Sweep_status_structure::iterator ss_iterator; + typedef typename Sweep_status_structure::value_type ss_pair; + typedef std::set 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 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 "< 0 ); // leftturn + } + + void triangulate_up(Halfedge_handle& e_apex) + { + TRACEN("triangulate_up "< 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 "<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 "<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 "< 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 C(*this,K); C.check_is_triangulation(); +#endif + } + +}; // SM_constrained_triang_traits + + +CGAL_END_NAMESPACE +#endif // CGAL_SM_CONSTRAINED_TRIANG_TRAITS_H + diff --git a/Packages/Nef_S2/include/CGAL/Nef_S2/SM_decorator.h b/Packages/Nef_S2/include/CGAL/Nef_S2/SM_decorator.h new file mode 100644 index 00000000000..e08fba87b4e --- /dev/null +++ b/Packages/Nef_S2/include/CGAL/Nef_S2/SM_decorator.h @@ -0,0 +1,796 @@ +#ifndef CGAL_SM_DECORATOR_H +#define CGAL_SM_DECORATOR_H + +#include +#include + +CGAL_BEGIN_NAMESPACE + +/*{\Moptions print_title=yes }*/ +/*{\Moptions outfile=SM_decorator.man }*/ +/*{\Manpage {SM_decorator}{Sphere_map,Kernel} +{Topological sphere map decorator}{D}}*/ + +template +class SM_decorator : public SM_const_decorator +{ +public: +typedef SM_const_decorator Base; +typedef SM_decorator 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_around_vertex_circulator; +/*{\Mtypemember circulating the adjacency list of an vertex |v|.}*/ + +typedef CircFromIt< + Halfedge_iterator, + move_edge_around_face > + 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 +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 +bool is_boundary_object(H h) const +{ return psm_->is_boundary_object(h); } + +template +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 +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 "<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 "<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 + + diff --git a/Packages/Nef_S2/include/CGAL/Nef_S2/SM_io_parser.h b/Packages/Nef_S2/include/CGAL/Nef_S2/SM_io_parser.h new file mode 100644 index 00000000000..4e5b334c3cf --- /dev/null +++ b/Packages/Nef_S2/include/CGAL/Nef_S2/SM_io_parser.h @@ -0,0 +1,466 @@ +#ifndef CGAL_SM_IO_PARSER_H +#define CGAL_SM_IO_PARSER_H + +#include +#include +#include + +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 +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 VI; + CGAL::Object_index EI; + CGAL::Object_index FI; + std::vector Vertex_of; + std::vector Edge_of; + std::vector 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 + + +template +SM_io_parser:: +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 +SM_io_parser:: +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 +bool SM_io_parser::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 +void SM_io_parser::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 +bool SM_io_parser::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 +void SM_io_parser::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 +bool SM_io_parser::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 +void SM_io_parser::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 +bool SM_io_parser::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 +void SM_io_parser::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 +void SM_io_parser::print_init_points() const +{ + out << mark_of_halfsphere(-1) << " " + << mark_of_halfsphere(+1) << "\n"; +} + + + +template +bool SM_io_parser::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 +bool SM_io_parser::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 +void SM_io_parser::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 +void SM_io_parser::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 +void SM_io_parser::debug_vertex(Vertex_handle v) const +{ + out << index(v) << "[" << mark(v) << "," << point(v) << "]" << endl; +} + +template +void SM_io_parser::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 +void SM_io_parser::debug_loop(Halfloop_handle l) const +{ + out << index(l) << " " + << index(twin(l)) << " " << index(face(l)) + << " ["<< mark(l) << "] " << circle(l) << endl; +} + + +template +void SM_io_parser::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 +void SM_io_parser::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 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 +void SM_io_parser::dump(const Decorator_& D, std::ostream& os) +{ SM_io_parser Out(os,D); + Out.print(); + Out.print_faces(); +} + + + +CGAL_END_NAMESPACE +#endif //CGAL_SM_IO_PARSER_H + diff --git a/Packages/Nef_S2/include/CGAL/Nef_S2/SM_items.h b/Packages/Nef_S2/include/CGAL/Nef_S2/SM_items.h new file mode 100644 index 00000000000..e193721d84d --- /dev/null +++ b/Packages/Nef_S2/include/CGAL/Nef_S2/SM_items.h @@ -0,0 +1,251 @@ +#ifndef CGAL_SM_ITEMS_H +#define CGAL_SM_ITEMS_H + +#include +#include +#include +#include +#include + +CGAL_BEGIN_NAMESPACE + +template class SM_items; +template class Sphere_map; +template class SM_const_decorator; +template class SM_decorator; +template struct move_edge_around_vertex; +template struct move_edge_around_face; + +template +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 Self; + typedef void* GenPtr; + + template + class Vertex : public CGAL::In_place_list_base< Vertex > + { + typedef typename Refs::Items Items; + friend class Sphere_map; + friend class SM_const_decorator; + friend class SM_decorator; + + 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& v) + { point_ = v.point_; + mark_ = v.mark_; + edge_ = v.edge_; + face_ = v.face_; + info_ = 0; + } + + Vertex& operator=(const Vertex& 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"< + class Halfedge : public CGAL::In_place_list_base< Halfedge > + { + 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; + friend class SM_const_decorator; + friend class SM_decorator; + friend class move_edge_around_vertex; + friend class move_edge_around_face; + friend class move_edge_around_vertex; + friend class move_edge_around_face; + + // 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& 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& operator=(const Halfedge& 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["<debug()<<", " + <source_->debug()<<" "< + class Halfloop : public CGAL::In_place_list_base< Halfloop > + { + typedef typename Refs::Halfloop_handle Halfloop_handle; + typedef typename Refs::Face_handle Face_handle; + typedef typename Refs::Items Items; + friend class Sphere_map; + friend class SM_const_decorator; + friend class SM_decorator; + friend class Self::Vertex; + + 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& l) + { + circle_ = l.circle_; + mark_ = l.mark_; + twin_ = l.twin_; + face_ = l.face_; + info_ = 0; + } + Halfloop& operator=(const Halfloop& 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"< + class Face : public CGAL::In_place_list_base< Face > + { + typedef typename Refs::Items Items; + friend class Sphere_map; + friend class SM_const_decorator; + friend class SM_decorator; + + 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& f) + { mark_ = f.mark_; + boundary_ = f.boundary_; + info_ = 0; + } + Face& operator=(const Face& 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 + + diff --git a/Packages/Nef_S2/include/CGAL/Nef_S2/SM_iteration.h b/Packages/Nef_S2/include/CGAL/Nef_S2/SM_iteration.h new file mode 100644 index 00000000000..4d931b28cad --- /dev/null +++ b/Packages/Nef_S2/include/CGAL/Nef_S2/SM_iteration.h @@ -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 + diff --git a/Packages/Nef_S2/include/CGAL/Nef_S2/SM_point_locator.h b/Packages/Nef_S2/include/CGAL/Nef_S2/SM_point_locator.h new file mode 100644 index 00000000000..13e08109da0 --- /dev/null +++ b/Packages/Nef_S2/include/CGAL/Nef_S2/SM_point_locator.h @@ -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 +// maintainer : Michael Seel +// coordinator : Michael Seel +// +// implementation: Point location module +// ============================================================================ +#ifndef CGAL_SM_POINT_LOCATOR_H +#define CGAL_SM_POINT_LOCATOR_H + +#include +#include +#include +#include + +#undef _DEBUG +#define _DEBUG 143 +#include + + +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 +class SM_point_locator : public Decorator_ { +protected: + typedef Decorator_ Base; + typedef SM_point_locator 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 "< + 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(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 "< 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 "< + 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 "< 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 "< + +template +void SM_point_locator::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 "< 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 "< 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 + + + diff --git a/Packages/Nef_S2/include/CGAL/Nef_S2/SM_triangulator.h b/Packages/Nef_S2/include/CGAL/Nef_S2/SM_triangulator.h new file mode 100644 index 00000000000..c2d22afe4d9 --- /dev/null +++ b/Packages/Nef_S2/include/CGAL/Nef_S2/SM_triangulator.h @@ -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 +// maintainer : Michael Seel +// coordinator : Michael Seel +// +// implementation: Triangulation module for sphere maps +// ============================================================================ + +#ifndef CGAL_SM_TRIANGULATOR_H +#define CGAL_SM_TRIANGULATOR_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#undef _DEBUG +#define _DEBUG 137 +#include + +#define USING(t) typedef typename Base::t t +#ifndef CGAL_USE_LEDA +#define LEDA_MEMORY(t) +#endif +CGAL_BEGIN_NAMESPACE + +template +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& 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& 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 +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 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_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 Seg_list; + typedef typename Seg_list::iterator Seg_iterator; + typedef std::pair Seg_it_pair; + typedef std::pair Seg_pair; + typedef CGAL::Unique_hash_map 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::create(info(v)); } + + void discard_info(Vertex_handle v) const + { geninfo::clear(info(v)); } + + vertex_info& ginfo(Vertex_handle v) const + { return geninfo::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::create(info(e)); + geninfo::create(info(twin(e))); } + + void discard_info(Halfedge_handle e) const + { geninfo::clear(info(e)); + geninfo::clear(info(twin(e))); } + + edge_info& ginfo(Halfedge_handle e) const + { return geninfo::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::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(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 + void partition_to_halfsphere(Iterator start, Iterator end, + Seg_list& L, CGAL::Unique_hash_map& 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 "<::dump(E_,os); + SM_io_parser::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 + + +template +void SM_triangulator::triangulate() +{ TRACEN("triangulate"); + // first create sphere segments from isoverts, edges, loops + Seg_list L; + Seg_map From; + CGAL::Unique_hash_map 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 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 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 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 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 PCT_traits; + typedef CGAL::generic_sweep Positive_halfsphere_ct_sweep; + typedef SM_constrained_triang_traits NCT_traits; + typedef CGAL::generic_sweep Negative_halfsphere_ct_sweep; + typedef std::pair 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 +template +void SM_triangulator:: +partition_to_halfsphere(Iterator start, Iterator beyond, Seg_list& L, + CGAL::Unique_hash_map& 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 +void SM_triangulator:: +merge_nodes(Halfedge_handle e1, Halfedge_handle e2) const +{ + Vertex_handle v1 = source(e1), v2 = target(e2); + TRACEN("merge_nodes "< +void SM_triangulator:: +merge_halfsphere_maps(Vertex_handle v1, Vertex_handle v2) const +{ TRACEN("merging halfspheres "< 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::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 +void SM_triangulator:: +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 = "< 0 ? (point(v).x() >= 0) : (point(v).x()<=0)) ); + m_buffer = incident_mark(previous(first_out_edge(v))); + } + TRACEN(" face mark below "< +#include +#include +#include + +#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 +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 > +class SM_visualizor : public + SM_triangulator< SM_decorator > +{ +/*{\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 Self; + typedef SM_const_decorator Explorer; + typedef SM_decorator Decorator; + typedef SM_triangulator 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 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)< 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 + diff --git a/Packages/Nef_S2/include/CGAL/Nef_S2/Sphere_circle.h b/Packages/Nef_S2/include/CGAL/Nef_S2/Sphere_circle.h new file mode 100644 index 00000000000..7e87acdbf71 --- /dev/null +++ b/Packages/Nef_S2/include/CGAL/Nef_S2/Sphere_circle.h @@ -0,0 +1,130 @@ +#ifndef CGAL_SPHERE_CIRCLE_H +#define CGAL_SPHERE_CIRCLE_H + +#include + +CGAL_BEGIN_NAMESPACE + +/*{\Manpage{Sphere_circle}{R}{Great circles on the unit sphere}{c}}*/ + +template 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,Sphere_segment > + Sphere_segment_pair; +/*{\Mtypemember sphere segment pair.}*/ + +typedef typename R_::Plane_3 Plane_3; +typedef typename R_::Point_3 Point_3; +typedef Sphere_circle Self; +typedef typename R_::Plane_3 Base; + +/*{\Mcreation 5}*/ +Sphere_circle() : Base() {} +/*{\Mcreate creates some great circle.}*/ + +Sphere_circle(const Sphere_point& p, const Sphere_point&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& 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 c, const Sphere_point& 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(Base(Point_3(0,0,0),p,CGAL::ORIGIN+c.base1())); + else + *this = Sphere_circle(Base(Point_3(0,0,0),p,c.orthogonal_pole())); +} + +/*{\Moperations 4 2}*/ + +Sphere_circle opposite() const +/*{\Mop returns the opposite of |\Mvar|.}*/ +{ return Base::opposite(); } + +bool has_on(const Sphere_point& 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 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& 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 + +/*{\Mtext\headerline{Global functions}}*/ + +template +bool equal_as_sets(const CGAL::Sphere_circle& c1, + const CGAL::Sphere_circle& c2) +/*{\Mfunc returns true iff |c1| and |c2| are equal as unoriented +circles.}*/ +{ return c1==c2 || c1==c2.opposite(); } + +template +Sphere_point intersection(const Sphere_circle& c1, + const Sphere_circle& 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 "< + +CGAL_BEGIN_NAMESPACE + +/*{\Manpage{Sphere_direction}{R}{Directions on the unit sphere}{c}}*/ + +template 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 Self; + +/*{\Mcreation 5}*/ +Sphere_direction() : Base() {} +/*{\Mcreate creates some direction.}*/ + +Sphere_direction(const Sphere_circle& c) +/*{\Mcreate creates the direction corresponding to the circle |c|.}*/ + : Base(c) {} + +Sphere_direction(const Sphere_point& p, const Sphere_point&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& 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 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 + + +/* 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 +bool strictly_ordered_ccw_at(const Sphere_point& p, + const Sphere_direction& d1, + const Sphere_direction& d2, + const Sphere_direction& 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 diff --git a/Packages/Nef_S2/include/CGAL/Nef_S2/Sphere_geometry.h b/Packages/Nef_S2/include/CGAL/Nef_S2/Sphere_geometry.h new file mode 100644 index 00000000000..b3d6ee2eff6 --- /dev/null +++ b/Packages/Nef_S2/include/CGAL/Nef_S2/Sphere_geometry.h @@ -0,0 +1,173 @@ +#ifndef CGAL_SPHERE_GEOMETRY_H +#define CGAL_SPHERE_GEOMETRY_H + +#include +#include +#include + +#undef _DEBUG +#define _DEBUG 113 +#include + +CGAL_BEGIN_NAMESPACE + +template class Sphere_point; +template class Sphere_segment; +template class Sphere_triangle; +template class Sphere_circle; +template class Sphere_direction; + +CGAL_END_NAMESPACE + +#include +#include +#include +#include +#include +#include + +CGAL_BEGIN_NAMESPACE + +template +struct Positive_halfsphere_geometry { + +typedef R_ R; +typedef CGAL::Sphere_point Point_2; +typedef CGAL::Sphere_segment 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 + +template +struct Negative_halfsphere_geometry : + public Positive_halfsphere_geometry { + +typedef Positive_halfsphere_geometry 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 + + +template +struct Sphere_geometry { + +typedef R_ R; +typedef typename R_::RT RT; +typedef typename R_::FT FT; +typedef CGAL::Sphere_point Sphere_point; +typedef CGAL::Sphere_segment Sphere_segment; +typedef CGAL::Sphere_circle Sphere_circle; +typedef CGAL::Sphere_direction Sphere_direction; +typedef CGAL::Sphere_triangle Sphere_triangle; +typedef CGAL::Point_3 Point_3; +typedef CGAL::Plane_3 Plane_3; +typedef Positive_halfsphere_geometry Positive_halfsphere_geometry; +typedef Negative_halfsphere_geometry 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 + diff --git a/Packages/Nef_S2/include/CGAL/Nef_S2/Sphere_geometry_OGL.h b/Packages/Nef_S2/include/CGAL/Nef_S2/Sphere_geometry_OGL.h new file mode 100644 index 00000000000..0369d7a3793 --- /dev/null +++ b/Packages/Nef_S2/include/CGAL/Nef_S2/Sphere_geometry_OGL.h @@ -0,0 +1,923 @@ +#ifndef CGAL_SPHERE_GEOMETRY_OGL_H +#define CGAL_SPHERE_GEOMETRY_OGL_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#undef _DEBUG +#define _DEBUG 151 +#include + +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 VKernel; +typedef VKernel::Vector_3 VVector; +typedef VKernel::Point_3 VPoint; +typedef VKernel::Aff_transformation_3 VTrafo; +typedef std::vector VSegment; +typedef VKernel::Triangle_3 DTriangle; +typedef std::vector VTriangle; + +const double refinement_angle = 0.1; +const double shrink_fac = 0.995; + +template +VVector convert(const CGAL::Vector_3& v) +{ return VVector(CGAL::to_double(v.x()), + CGAL::to_double(v.y()), + CGAL::to_double(v.z())); } + +template +VPoint approximate(const CGAL::Sphere_point& p) +{ + VVector v = convert(p-CGAL::ORIGIN); + v = v / CGAL_NTS sqrt(v*v) ; // normalize + return CGAL::ORIGIN+v; +} + +template +class Sphere_point : public VPoint, public Gen_object { + typedef R_ R; + CGAL::Sphere_point p_; + CGAL::Color c_; + unsigned w_; +public: + Sphere_point() {} + Sphere_point(const CGAL::Sphere_point& p, + CGAL::Color c = CGAL::BLACK, unsigned w = 10) : + VPoint(approximate(p)), p_(p), c_(c), w_(w) {} + Sphere_point(const Sphere_point& p) : VPoint(p) + { p_ = p.p_; c_ = p.c_; w_ = p.w_; } + Sphere_point& operator=(const Sphere_point& p) + { VPoint::operator=(p); p_ = p.p_; c_ = p.c_; w_ = p.w_; + return *this; } + + virtual ~Sphere_point() {} + + const CGAL::Sphere_point& original() const + { return p_; } + + virtual Gen_object* clone() const + { return new Sphere_point(*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 +VSegment approximate(const CGAL::Sphere_segment& 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 +class Sphere_segment : public VSegment, public Gen_object { + typedef R_ R; + CGAL::Sphere_segment s_; + CGAL::Color c_; + unsigned w_; +public: + Sphere_segment() {} + Sphere_segment(const CGAL::Sphere_segment& s, + CGAL::Color c = CGAL::BLACK, unsigned w = 2) + : VSegment(approximate(s)), s_(s), c_(c), w_(w) {} + Sphere_segment(const Sphere_segment& s) : VSegment(s) + { s_ = s.s_; c_ = s.c_; w_ = s.w_; } + Sphere_segment& operator=(const Sphere_segment& s) + { VSegment::operator=(s); s_ = s.s_; c_ = s.c_; w_ = s.w_; + return *this; } + virtual ~Sphere_segment() {} + + const CGAL::Sphere_segment& original() const + { return s_; } + + virtual Gen_object* clone() const + { return new Sphere_segment(*this); } + + virtual void draw() const + { TRACEN("draw "<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 +VSegment approximate(const CGAL::Sphere_circle& 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 +class Sphere_circle : public VSegment, public Gen_object { + typedef R_ R; + CGAL::Sphere_circle s_; + CGAL::Color c_; + unsigned w_; +public: + Sphere_circle() {} + Sphere_circle(const CGAL::Sphere_circle& s, + CGAL::Color c = CGAL::BLACK, unsigned w = 2) + : VSegment(approximate(s)), s_(s), c_(c), w_(w) {} + Sphere_circle(const Sphere_circle& s) : VSegment(s) + { s_ = s.s_; c_ = s.c_; w_ = s.w_; } + Sphere_circle& operator=(const Sphere_circle& s) + { VSegment::operator=(s); s_ = s.s_; c_ = s.c_; w_ = s.w_; + return *this; } + virtual ~Sphere_circle() {} + + const CGAL::Sphere_circle& original() const + { return s_; } + + virtual Gen_object* clone() const + { return new Sphere_circle(*this); } + + virtual void draw() const + { TRACEN("draw "<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 Sphere_triangle : public VTriangle, public Gen_object { + typedef R_ R; + CGAL::Sphere_triangle t_; + CGAL::Color c_; +public: + Sphere_triangle() {} + + Sphere_triangle(const CGAL::Sphere_triangle& t, + CGAL::Color c = CGAL::GREY) + : VTriangle(approximate(t)), t_(t), c_(c) {} + + Sphere_triangle(const Sphere_triangle& t) : VTriangle(t) + { t_ = t.t_; c_ = t.c_; } + + Sphere_triangle& operator=(const Sphere_triangle& t) + { VTriangle::operator=(t); t_ = t.t_; c_ = s.c_; return *this; } + + virtual ~Sphere_triangle() {} + + const CGAL::Sphere_triangle& original() const + { return t_; } + + virtual Gen_object* clone() const + { return new Sphere_triangle(*this); } + + virtual void draw() const + { TRACEN("draw "<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] ) { + 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 +VTriangle approximate(const CGAL::Sphere_triangle& 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 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 +void push_back(const CGAL::Sphere_point& p, + CGAL::Color c = CGAL::YELLOW, unsigned w = 5) +{ objects_.push_back(new Sphere_point(p,c,w)); } + +template +void push_back(const CGAL::Sphere_segment& s, + CGAL::Color c = CGAL::BLACK, unsigned w = 1) +{ objects_.push_back(new Sphere_segment(s,c,w)); } + +template +void push_back(const CGAL::Sphere_circle& s, + CGAL::Color c = CGAL::BLACK, unsigned w = 1) +{ objects_.push_back(new Sphere_circle(s,c,w)); } + +template +void push_back(const CGAL::Sphere_triangle& t, + CGAL::Color c = CGAL::WHITE) +{ triangles_.push_back(new Sphere_triangle(t,c)); } + +template +void push_back_triangle_edge(const CGAL::Sphere_segment& s, + CGAL::Color c = CGAL::BLUE, unsigned w = 1) +{ triangle_edges_.push_back(new Sphere_segment(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(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 spheres_; + static std::vector titles_; + +void show (int mode) +{ + std::vector::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 +std::ostream& operator<<(std::ostream& os, + const CGAL::OGL::Sphere_segment& s) +{ CGAL::OGL::VSegment::const_iterator it; + os << s.original() << " "; + for (it = s.begin(); it != s.end(); ++it) + os << *it; + return os; +} + +template +std::ostream& operator<<(std::ostream& os, + const CGAL::OGL::Sphere_circle& s) +{ CGAL::OGL::VSegment::const_iterator it; + os << s.original() << " "; + for (it = s.begin(); it != s.end(); ++it) + os << *it; + return os; +} + + + +template +std::ostream& operator<<(std::ostream& os, + const CGAL::OGL::Sphere_point& p) +{ os << p.original() << CGAL::OGL::VPoint(p); return os; } + + +#endif //CGAL_SPHERE_GEOMETRY_OGL_H + diff --git a/Packages/Nef_S2/include/CGAL/Nef_S2/Sphere_map.h b/Packages/Nef_S2/include/CGAL/Nef_S2/Sphere_map.h new file mode 100644 index 00000000000..0d4ff694290 --- /dev/null +++ b/Packages/Nef_S2/include/CGAL/Nef_S2/Sphere_map.h @@ -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 +// maintainer : Michael Seel +// coordinator : Michael Seel +// ============================================================================ + +#ifndef CGAL_SPHERE_MAP_H +#define CGAL_SPHERE_MAP_H + +#include +#include +#include +#include +#include +#include +#include +#undef _DEBUG +#define _DEBUG 109 +#include + +CGAL_BEGIN_NAMESPACE + +/*{\Manpage {Sphere_map}{Kernel}{Sphere Maps}{M}}*/ + +template +class Sphere_map { + +/*{\Mdefinition selective sphere map container based on +the HDS design of Kettner.}*/ + +public: + /*{\Mtypes 7}*/ + typedef Kernel_ Kernel; + typedef Sphere_map Self; + typedef SM_items Items; + + friend class SM_const_decorator; + friend class SM_decorator; + + 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 Vertex; + typedef CGAL::In_place_list 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 Halfedge; + typedef CGAL::In_place_list 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 Face; + typedef CGAL::In_place_list 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 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_list; + typedef typename Object_list::iterator Object_iterator; + typedef typename Object_list::const_iterator Object_const_iterator; + typedef Generic_handle_map 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 + bool is_boundary_object(H h) + { return boundary_item_[h]!=undef_; } + + template + Object_iterator& boundary_item(H h) + { return boundary_item_[h]; } + + template + void store_boundary_item(H h, Object_iterator o) + { boundary_item_[h] = o; } + + template + 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 + 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 +void Sphere_map:: +pointer_update(const Sphere_map& D) +{ + CGAL::Unique_hash_map VM; + CGAL::Unique_hash_map EM; + CGAL::Unique_hash_map LM; + CGAL::Unique_hash_map 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 Sphere_map::Object_iterator +Sphere_map::undef_; + +/* boundary item is member! +template +typename Sphere_map::Handle_to_iterator_map +Sphere_map::boundary_item_(Sphere_map::undef_); +*/ + +CGAL_END_NAMESPACE +#endif // CGAL_SPHERE_MAP_H + + diff --git a/Packages/Nef_S2/include/CGAL/Nef_S2/Sphere_point.h b/Packages/Nef_S2/include/CGAL/Nef_S2/Sphere_point.h new file mode 100644 index 00000000000..c027d809430 --- /dev/null +++ b/Packages/Nef_S2/include/CGAL/Nef_S2/Sphere_point.h @@ -0,0 +1,108 @@ +#ifndef CGAL_SPHERE_POINT_H +#define CGAL_SPHERE_POINT_H + +#include + +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 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 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& q) const +/*{\Mbinop Equality.}*/ +{ return Direction_3(Base(*this)-ORIGIN)== + Direction_3(q-ORIGIN); } + +bool operator!=(const Sphere_point& q) const +/*{\Mbinop Inequality.}*/ +{ return !operator==(q); } + +Sphere_point opposite() const +/*{\Mop returns the opposite of |\Mvar|.}*/ +{ return ORIGIN + -(Base(*this)-ORIGIN); } + +}; // Sphere_point + +template +CGAL::Point_3 operator+( + const CGAL::Point_3& p, const Sphere_point& q) +{ return p + (q-CGAL::ORIGIN); } + +CGAL_END_NAMESPACE +#endif //CGAL_SPHERE_POINT_H diff --git a/Packages/Nef_S2/include/CGAL/Nef_S2/Sphere_segment.h b/Packages/Nef_S2/include/CGAL/Nef_S2/Sphere_segment.h new file mode 100644 index 00000000000..5d6df7171ba --- /dev/null +++ b/Packages/Nef_S2/include/CGAL/Nef_S2/Sphere_segment.h @@ -0,0 +1,344 @@ +#ifndef CGAL_SPHERE_SEGMENT_H +#define CGAL_SPHERE_SEGMENT_H + +#include +#include + +CGAL_BEGIN_NAMESPACE + +template class Sphere_segment_rep : public Ref_counted +{ + typedef typename R_::Point_3 Point_3; + typedef typename R_::Plane_3 Plane_3; + typedef Sphere_point Point; + typedef Sphere_circle Circle; + typedef Sphere_segment_rep Rep; + friend class Sphere_segment; +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(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 ps_,pt_; + Sphere_circle c_; +}; + + +/*{\Moptions print_title=yes }*/ +/*{\Manpage{Sphere_segment}{R}{Segments on the unit sphere}{s}}*/ + +template +class Sphere_segment : + public Handle_for< Sphere_segment_rep > { + +/*{\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 Rep; +typedef Handle_for 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 Self; + +/*{\Mcreation 4}*/ + +Sphere_segment() : Base() {} + +Sphere_segment(const Sphere_point& p1, const Sphere_point& 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& p1, const Sphere_point& p2, + const Sphere_circle& 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& c1, + const Sphere_circle& 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& source() const { return ptr->ps_; } +/*{\Mop the source point of |\Mvar|.}*/ +const Sphere_point& target() const { return ptr->pt_; } +/*{\Mop the target point of |\Mvar|.}*/ +const Sphere_circle& sphere_circle() const { return ptr->c_; } +/*{\Mop the great circle supporting |\Mvar|.}*/ + +Sphere_segment opposite() const +/*{\Mop returns the sperical segment oriented from |target()| + to |source()| with the same point set as |\Mvar|. }*/ +{ return Sphere_segment( + target(),source(),sphere_circle().opposite()); } + +Sphere_segment 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(target(),source(),sphere_circle()); } + + +int intersection(const Sphere_circle& c, + Sphere_segment& s1, Sphere_segment& 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 intersection(const Sphere_segment& so) const; +/*{\Mop returns the point of intersection of |\Mvar| and +|so|. \precond |\Mvar| and |so| do intersect.}*/ + +void split_halfcircle(Sphere_segment& s1, + Sphere_segment& 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 p = + CGAL::intersection(sphere_circle(),Sphere_circle(h)); + if ( !has_on(p) ) p = p.opposite(); + s1 = Sphere_segment(ptr->ps_,p,ptr->c_); + s2 = Sphere_segment(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& p) const; +/*{\Mop return true iff |\Mvar| contains |p|.}*/ + +bool has_in_relative_interior(const Sphere_point& p) const; +/*{\Mop return true iff |\Mvar| contains |p| in +its relative interior.}*/ + +bool operator==(const Sphere_segment& so) const +{ return source() == so.source() && target() == so.target() && + (source() == target() || + sphere_circle() == so.sphere_circle()); } + +bool operator!=(const Sphere_segment& so) const +{ return !operator==(so); } + +}; + +template +bool do_intersect_internally(const Sphere_segment& s1, + const Sphere_segment& s2, + Sphere_point& p); +/*{\Mfunc return true iff |s1| and |s2| intersect internally +(non-degenerately). If |true| the parameter |p| returns the point of +intersection.}*/ + + +template +std::ostream& operator<<(std::ostream& os, + const CGAL::Sphere_segment& s) +{ os << s.source()<<" "< +std::istream& operator>>(std::istream& is, + CGAL::Sphere_segment& s) +{ CGAL::Sphere_point p1,p2; + CGAL::Sphere_circle c; + if ( !(is >> p1 >> p2 >> c) ) return is; + s = CGAL::Sphere_segment(p1,p2,c); + return is; } + + +template +std::pair< Sphere_segment,Sphere_segment > +Sphere_circle::split_at(const Sphere_point& p) const +{ CGAL_assertion(has_on(p)); + Sphere_point q(p.opposite()); + return Sphere_segment_pair( + Sphere_segment(p,q,*this), + Sphere_segment(p,q,this->opposite())); +} + +template +std::pair< Sphere_segment,Sphere_segment > +Sphere_circle::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 +bool Sphere_segment:: +has_on(const CGAL::Sphere_point& 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 +bool Sphere_segment:: +has_in_relative_interior(const CGAL::Sphere_point& 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 +Sphere_point Sphere_segment:: +intersection(const Sphere_segment& s) const +{ + CGAL_assertion(!equal_as_sets(sphere_circle(),s.sphere_circle())); + Sphere_point res = + CGAL::intersection(sphere_circle(),s.sphere_circle()); + if ( has_on(res) && s.has_on(res) ) return res; + return res.opposite(); +} + +template +bool do_intersect_internally(const Sphere_segment& s1, + const Sphere_segment& s2, + Sphere_point& 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 +bool do_intersect_internally(const Sphere_circle& c1, + const Sphere_segment& s2, + Sphere_point& 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 diff --git a/Packages/Nef_S2/include/CGAL/Nef_S2/Sphere_triangle.h b/Packages/Nef_S2/include/CGAL/Nef_S2/Sphere_triangle.h new file mode 100644 index 00000000000..a032275d11f --- /dev/null +++ b/Packages/Nef_S2/include/CGAL/Nef_S2/Sphere_triangle.h @@ -0,0 +1,100 @@ +#ifndef CGAL_SPHERE_TRIANGLE_H +#define CGAL_SPHERE_TRIANGLE_H + +#include +#include +#include + +CGAL_BEGIN_NAMESPACE + +template class Sphere_triangle_rep : public Ref_counted +{ typedef Sphere_point Point; + typedef Sphere_circle Circle; + typedef Sphere_triangle_rep Rep; + + Tuple points_; + Tuple circles_; + + friend class Sphere_triangle; + + 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 Sphere_triangle : + public Handle_for< Sphere_triangle_rep > { +/*{\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 Rep; +typedef Handle_for Base; + +/*{\Mcreation 5}*/ +Sphere_triangle() : Base() {} +/*{\Mcreate creates some triangle.}*/ + +Sphere_triangle( + const Sphere_point& p0, const Sphere_point& p1, + const Sphere_point& p2, + const Sphere_circle& c0, const Sphere_circle& c1, + const Sphere_circle& 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& t) : Base(t) {} + +/*{\Moperations 4 2}*/ + +const Sphere_point& point(unsigned i) const +/*{\Mop returns the ith point of |\Mvar|.}*/ +{ return ptr->points_[i%3]; } + +const Sphere_circle& circle(unsigned i) const +/*{\Mop returns the ith circle of |\Mvar|.}*/ +{ return ptr->circles_[i%3]; } + +Sphere_triangle opposite() const +/*{\Mop returns the opposite of |\Mvar|.}*/ +{ return Sphere_triangle(point(0), point(1), point(2), + circle(0).opposite(), circle(1).opposite(), circle(2).opposite()); } + + +}; // Sphere_triangle + + +template +std::ostream& operator<<(std::ostream& os, + const CGAL::Sphere_triangle& 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 +std::istream& operator>>(std::istream& is, + CGAL::Sphere_triangle& t) +{ CGAL::Sphere_point p1,p2,p3; + CGAL::Sphere_circle c1,c2,c3; + if ( !(is >> p1 >> p2 >> p3 >> c1 >> c2 >> c3) ) return is; + t = CGAL::Sphere_triangle(p1,p2,p3,c1,c2,c3); + return is; } + +CGAL_END_NAMESPACE +#endif //CGAL_SPHERE_TRIANGLE_H diff --git a/Packages/Nef_S2/include/CGAL/Nef_S2/Tuple.h b/Packages/Nef_S2/include/CGAL/Nef_S2/Tuple.h new file mode 100644 index 00000000000..3482ecf4eba --- /dev/null +++ b/Packages/Nef_S2/include/CGAL/Nef_S2/Tuple.h @@ -0,0 +1,33 @@ +#ifndef CGAL_TUPLE_H +#define CGAL_TUPLE_H + +#include + +CGAL_BEGIN_NAMESPACE + +template +class Tuple { + typedef Tuple Self; + T object_[n]; +public: + Tuple() { for (unsigned i=0; i1); 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 +// maintainer : Michael Seel +// coordinator : Michael Seel +// +// implementation: simple debugging macros +// ============================================================================ + +#ifndef CGAL_DEBUG_H +#define CGAL_DEBUG_H + +#include + +#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<<" "<0 +#define TRACEV(t) if((debugthread%_DEBUG)==0)\ + std::cerr<<" "<<#t<<" = "<<(t)<0 +#define TRACEN(t) if((debugthread%_DEBUG)==0)\ + std::cerr<<" "<0 +#define CTRACE(b,t) if(b) std::cerr<<" "<0 +#define CTRACEN(b,t) if(b) std::cerr<<" "< +#include +#include +#include +#include + +#undef _DEBUG +#define _DEBUG 211 +#include + +template +class leda_graph_decorator { +public: + typedef leda_node Vertex_handle; + typedef leda_edge Halfedge_handle; + typedef CGAL::Sphere_point Point_2; + typedef CGAL::Sphere_segment Segment_2; + typedef GRAPH< Point_2, Segment_2 > Graph; + typedef leda_node_map 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 +class leda_sphere_map_overlayer { + + typedef std::pair edge_pair; + typedef CGAL::Sphere_point SPoint_2; + typedef CGAL::Sphere_segment SSegment_2; + typedef CGAL::Plane_3 Plane_3; + typedef GRAPH Sphere_map; + + Sphere_map G; + leda_node_map E; + +public: + +leda_sphere_map_overlayer() : G(),E(G) {} + +const Sphere_map& sphere_map() const { return G; } + +template +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 leda_graph_output; +typedef CGAL::Positive_halfsphere_geometry PH_geometry; +typedef CGAL::Segment_overlay_traits< + Iterator, leda_graph_output, PH_geometry> PHS_traits; +typedef CGAL::generic_sweep Positive_halfsphere_sweep; + +typedef CGAL::Negative_halfsphere_geometry NH_geometry; +typedef CGAL::Segment_overlay_traits< + Iterator, leda_graph_output, NH_geometry> NHS_traits; +typedef CGAL::generic_sweep Negative_halfsphere_sweep; + + std::list 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 known(G,false); + leda_list L; + leda_list 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 "<"; + dump(os,target(e),false); + os <<" ["< + + +#endif //LEDA_SPHERE_MAP_H + diff --git a/Packages/Nef_S2/include/CGAL/Nef_S2/sphere_predicates.h b/Packages/Nef_S2/include/CGAL/Nef_S2/sphere_predicates.h new file mode 100644 index 00000000000..7874533c757 --- /dev/null +++ b/Packages/Nef_S2/include/CGAL/Nef_S2/sphere_predicates.h @@ -0,0 +1,235 @@ +#ifndef CGAL_SPHERE_PREDICATES_H +#define CGAL_SPHERE_PREDICATES_H + +#include +#include + +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 +int spherical_orientation(const Sphere_point& p1, + const Sphere_point& p2, + const Sphere_point& p3) +{ return CGAL::orientation(CGAL::Point_3(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 +int spherical_compare(const Sphere_point& p1, + const Sphere_point& p2, + int pos) +{ + Sphere_point pS(0,-1,0),pN(0,1,0); + CGAL::Direction_3 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(0)) && + (p2.hz()==static_cast(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(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(-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 +void partition(const Sphere_circle& c, I start, I beyond, + std::list< Sphere_segment >& Lpos) +{ TRACEN("partition "); + Sphere_segment 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 +void partition_xy(I start, I beyond, + std::list< Sphere_segment >& L, int pos) +{ + Sphere_circle xy_circle(0,0,1), yz_circle(1,0,0); + Sphere_point S(0,-1,0),N(0,1,0); + Sphere_segment s1,s2; + if (pos > 0) partition(xy_circle,start,beyond,L); + else partition(xy_circle.opposite(),start,beyond,L); + typename std::list< Sphere_segment >::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 s1,s2; + it->split_halfcircle(s1,s2); + *it = s2; L.insert(it,s1); + } + } + // append 4 xy-equator segments: + Sphere_segment sp(S,N,xy_circle); + Sphere_segment sm(S,N,xy_circle.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); +} + + +/* |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 +int Sphere_segment:: +intersection(const CGAL::Sphere_circle& c, + Sphere_segment& s1, Sphere_segment& s2) const +{ + TRACEN(" intersection "<<*this<<" "< i1 = CGAL::intersection(ptr->c_,c); + if ( !has_on(i1) ) i1 = i1.opposite(); + if ( or1 == CGAL::ON_POSITIVE_SIDE ) + s1 = Sphere_segment(source(),i1,sphere_circle()); + else if ( or2 == CGAL::ON_POSITIVE_SIDE ) + s1 = Sphere_segment(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 i1 = CGAL::intersection(ptr->c_,c); + Sphere_point i2 = i1.opposite(); + Sphere_segment 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 "<= 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 i1 = CGAL::intersection(ptr->c_,c); + Sphere_point i2 = i1.opposite(); + Sphere_segment so(i1,i2,sphere_circle()); + TRACEN(" both <= plane, long"<(source(),source(),sphere_circle()); return 1; } + if ( or2 == CGAL::ON_ORIENTED_BOUNDARY ) + { s1 = Sphere_segment(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 diff --git a/Packages/Nef_S2/include/CGAL/Nef_polyhedron_S2.h b/Packages/Nef_S2/include/CGAL/Nef_polyhedron_S2.h new file mode 100644 index 00000000000..f23eaec338b --- /dev/null +++ b/Packages/Nef_S2/include/CGAL/Nef_polyhedron_S2.h @@ -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 +// maintainer : Michael Seel +// coordinator : Michael Seel +// +// implementation: Nef polyhedra in the sphere surface +// ============================================================================ + +#ifndef CGAL_NEF_POLYHEDRON_S2_H +#define CGAL_NEF_POLYHEDRON_S2_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#undef _DEBUG +#define _DEBUG 121 +#include + +CGAL_BEGIN_NAMESPACE + +template class Nef_polyhedron_S2; +template class Nef_polyhedron_S2_rep; + +template +std::ostream& operator<<(std::ostream&, const Nef_polyhedron_S2&); +template +std::istream& operator>>(std::istream&, Nef_polyhedron_S2&); + + +template +class Nef_polyhedron_S2_rep : public Ref_counted +{ typedef Nef_polyhedron_S2_rep Self; + friend class Nef_polyhedron_S2; + + typedef K Kernel; + typedef CGAL::Sphere_geometry Sphere_kernel; + typedef CGAL::Sphere_map Sphere_map; + typedef CGAL::SM_const_decorator + Const_decorator; + typedef CGAL::SM_decorator Decorator; + typedef CGAL::SM_overlayer Overlayer; + typedef CGAL::SM_point_locator 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 +class Nef_polyhedron_S2 : public Handle_for< Nef_polyhedron_S2_rep > +{ +public: + typedef K Kernel; + + /*{\Mtypes 7}*/ + typedef Nef_polyhedron_S2 Self; + typedef Nef_polyhedron_S2_rep Rep; + typedef Handle_for< Nef_polyhedron_S2_rep > 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 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& NP); + friend std::istream& operator>> CGAL_NULL_TMPL_ARGS + (std::istream& is, Nef_polyhedron_S2& 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 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 "< + 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& N1) : Base(N1) {} + Nef_polyhedron_S2& operator=(const Nef_polyhedron_S2& N1) + { Base::operator=(N1); return (*this); } + ~Nef_polyhedron_S2() {} + + + template + 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

sm_ = H; } + + void clone_rep() { *this = Nef_polyhedron_S2(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 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 complement() const + /*{\Mop returns the complement of |\Mvar| in the plane.}*/ + { Nef_polyhedron_S2 res = *this; + res.extract_complement(); + return res; + } + + + Nef_polyhedron_S2 interior() const + /*{\Mop returns the interior of |\Mvar|.}*/ + { Nef_polyhedron_S2 res = *this; + res.extract_interior(); + return res; + } + + Nef_polyhedron_S2 closure() const + /*{\Mop returns the closure of |\Mvar|.}*/ + { Nef_polyhedron_S2 res = *this; + res.extract_closure(); + return res; + } + + Nef_polyhedron_S2 boundary() const + /*{\Mop returns the boundary of |\Mvar|.}*/ + { Nef_polyhedron_S2 res = *this; + res.extract_boundary(); + return res; + } + + Nef_polyhedron_S2 regularization() const + /*{\Mop returns the regularized polyhedron (closure of interior).}*/ + { Nef_polyhedron_S2 res = *this; + res.extract_regularization(); + return res; + } + + + Nef_polyhedron_S2 intersection(const Nef_polyhedron_S2& N1) const + /*{\Mop returns |\Mvar| $\cap$ |N1|. }*/ + { Nef_polyhedron_S2 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 join(const Nef_polyhedron_S2& N1) const + /*{\Mop returns |\Mvar| $\cup$ |N1|. }*/ + { Nef_polyhedron_S2 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 difference(const Nef_polyhedron_S2& N1) const + /*{\Mop returns |\Mvar| $-$ |N1|. }*/ + { Nef_polyhedron_S2 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 symmetric_difference( + const Nef_polyhedron_S2& N1) const + /*{\Mop returns the symmectric difference |\Mvar - T| $\cup$ + |T - \Mvar|. }*/ + { Nef_polyhedron_S2 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 operator*(const Nef_polyhedron_S2& N1) const + { return intersection(N1); } + + Nef_polyhedron_S2 operator+(const Nef_polyhedron_S2& N1) const + { return join(N1); } + + Nef_polyhedron_S2 operator-(const Nef_polyhedron_S2& N1) const + { return difference(N1); } + + Nef_polyhedron_S2 operator^(const Nef_polyhedron_S2& N1) const + { return symmetric_difference(N1); } + + Nef_polyhedron_S2 operator!() const + { return complement(); } + + Nef_polyhedron_S2& operator*=(const Nef_polyhedron_S2& N1) + { this = intersection(N1); return *this; } + + Nef_polyhedron_S2& operator+=(const Nef_polyhedron_S2& N1) + { this = join(N1); return *this; } + + Nef_polyhedron_S2& operator-=(const Nef_polyhedron_S2& N1) + { this = difference(N1); return *this; } + + Nef_polyhedron_S2& operator^=(const Nef_polyhedron_S2& 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& N1) const + { return symmetric_difference(N1).is_empty(); } + + bool operator!=(const Nef_polyhedron_S2& N1) const + { return !operator==(N1); } + + bool operator<=(const Nef_polyhedron_S2& N1) const + { return difference(N1).is_empty(); } + + bool operator<(const Nef_polyhedron_S2& N1) const + { return difference(N1).is_empty() && !N1.difference(*this).is_empty(); } + + bool operator>=(const Nef_polyhedron_S2& N1) const + { return N1.difference(*this).is_empty(); } + + bool operator>(const Nef_polyhedron_S2& 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 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())); } + + /*{\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 + #include + #include + + using namespace CGAL; + typedef Homogeneous Kernel; + typedef Nef_polyhedron_S2 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 +std::ostream& operator<< + (std::ostream& os, const Nef_polyhedron_S2& NP) +{ + os << "Nef_polyhedron_S2\n"; + typedef typename Nef_polyhedron_S2::Decorator Decorator; + typedef typename Nef_polyhedron_S2::Sphere_map Sphere_map; + CGAL::SM_io_parser O(os, + const_cast(NP.sphere_map())); + O.print(); + return os; +} + +template +std::istream& operator>> + (std::istream& is, Nef_polyhedron_S2& NP) +{ + typedef typename Nef_polyhedron_S2::Decorator Decorator; + CGAL::SM_io_parser 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(); + } + typename Nef_polyhedron_S2::Topological_explorer D(NP.explorer()); + D.check_integrity_and_topological_planarity(); + return is; +} + + +CGAL_END_NAMESPACE +#endif //CGAL_NEF_POLYHEDRON_S2_H + + diff --git a/Packages/Nef_S2/maintainer b/Packages/Nef_S2/maintainer new file mode 100644 index 00000000000..a259e773d92 --- /dev/null +++ b/Packages/Nef_S2/maintainer @@ -0,0 +1 @@ +Michael Seel diff --git a/Packages/Nef_S2/version b/Packages/Nef_S2/version new file mode 100644 index 00000000000..569ce95acf0 --- /dev/null +++ b/Packages/Nef_S2/version @@ -0,0 +1 @@ +0.9.0 ( 20 Nov 2001)