mirror of https://github.com/CGAL/cgal
added to project
This commit is contained in:
parent
41a65c4f8a
commit
685c90d5aa
|
|
@ -0,0 +1,4 @@
|
|||
Possible Improvements for future releases are
|
||||
|
||||
1) introduce clean spherical kernel trais
|
||||
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
Nef_S2 Package: Release changes
|
||||
----------------------------------------------------------------------
|
||||
|
||||
0.9 (20 Nov 2001)
|
||||
|
||||
initial release
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
nef-demo -n 4 -r 3
|
||||
nef-demo -n 8 -r 1
|
||||
nef-demo
|
||||
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
#include <CGAL/basic.h>
|
||||
#include <CGAL/Homogeneous.h>
|
||||
#include <CGAL/leda_integer.h>
|
||||
#include <CGAL/random_selection.h>
|
||||
#include <CGAL/point_generators_3.h>
|
||||
#include <CGAL/Nef_polyhedron_S2.h>
|
||||
#include <CGAL/IO/Nef_polyhedron_S2_OGLUT_stream.h>
|
||||
#include <LEDA/param_handler.h>
|
||||
|
||||
typedef leda_integer NT;
|
||||
typedef CGAL::Homogeneous<NT> Kernel;
|
||||
typedef Kernel::Point_3 Point_3;
|
||||
typedef Kernel::Plane_3 Plane_3;
|
||||
|
||||
typedef CGAL::Nef_polyhedron_S2<Kernel> Nef_polyhedron_S2;
|
||||
typedef Nef_polyhedron_S2::Sphere_point Sphere_point;
|
||||
typedef Nef_polyhedron_S2::Sphere_segment Sphere_segment;
|
||||
typedef Nef_polyhedron_S2::Sphere_circle Sphere_circle;
|
||||
typedef Nef_polyhedron_S2::Explorer Explorer;
|
||||
|
||||
typedef CGAL::Creator_uniform_3<NT,Point_3> Creator;
|
||||
typedef CGAL::Random_points_in_cube_3<Point_3,Creator> Point_source;
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
CGAL::set_pretty_mode ( std::cerr );
|
||||
SETDTHREAD(911);
|
||||
// Sphere_geometry 11
|
||||
// Sphere_geometry_OGL 13
|
||||
// Segment_overlay 23
|
||||
// SM_overlayer 53
|
||||
Point_3 p(0,0,0);
|
||||
|
||||
int seed;
|
||||
int n;
|
||||
leda_string input_file;
|
||||
leda_param_handler H(argc,argv,".nd",false);
|
||||
H.add_parameter("random_seed:-r:int:0");
|
||||
H.add_parameter("number_of_lines:-n:int:10");
|
||||
H.add_parameter("file_of_segments:-i:string:");
|
||||
leda_param_handler::init_all();
|
||||
H.get_parameter("-r",seed);
|
||||
H.get_parameter("-n",n);
|
||||
H.get_parameter("-i",input_file);
|
||||
CGAL_assertion_msg(n>0,"-n value must be postive.");
|
||||
srand(seed);
|
||||
|
||||
std::list<Sphere_circle> L;
|
||||
if ( input_file == "" ) { // create random input:
|
||||
Point_source S(5);
|
||||
Point_3 ph;
|
||||
Point_3 o(0,0,0);
|
||||
while ( n-- > 0 ) {
|
||||
do { ph = *S++; } while ( ph == o );
|
||||
Plane_3 h(o,(ph-CGAL::ORIGIN).direction());
|
||||
L.push_back( Sphere_circle(h) );
|
||||
}
|
||||
} else { // read input from file:
|
||||
std::ifstream input(input_file);
|
||||
CGAL_assertion_msg(input,"no input log.");
|
||||
Sphere_circle c;
|
||||
while ( input >> c ) L.push_back(c);
|
||||
}
|
||||
|
||||
// output log:
|
||||
std::ofstream output("nef-demo.log");
|
||||
std::list<Sphere_circle>::iterator it;
|
||||
CGAL_forall_iterators(it,L) output << *it << ' ';
|
||||
output << std::endl;
|
||||
output.close();
|
||||
|
||||
// partition input into two lists
|
||||
std::list<Sphere_circle> L1,L2;
|
||||
int b=0;
|
||||
CGAL_forall_iterators(it,L) {
|
||||
if ( b == 0 ) L1.push_back(*it);
|
||||
else L2.push_back(*it);
|
||||
b = 1-b;
|
||||
}
|
||||
|
||||
Nef_polyhedron_S2 N1(L1.begin(), L1.end(), 0.5);
|
||||
Nef_polyhedron_S2 N2(L2.begin(), L2.end(), 0.5);
|
||||
Nef_polyhedron_S2 N3 = N1 * N2;
|
||||
Nef_polyhedron_S2 N4 = N1 ^ N2;
|
||||
//std::cerr << N1 << N2 << N3 << N4 << std::endl;
|
||||
CGAL::ogl << N1 << N2 << N3 << N4;
|
||||
CGAL::ogl << "Nef Polyhedron 1" << "Nef Polyhedron 2"
|
||||
<< "Intersection" << "Symmetric Difference";
|
||||
CGAL::ogl.display();
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
#include <LOCAL/CGALH3.h>
|
||||
#include <CGAL/random_selection.h>
|
||||
#include <CGAL/point_generators_3.h>
|
||||
#include "Nef_polyhedron_S2.h"
|
||||
#include "Nef_S2/Nef_polyhedron_S2_OGLUT_stream.h"
|
||||
#include <LEDA/param_handler.h>
|
||||
|
||||
//#define TRACEV(t) std::cerr << #t << " = " << t <<std::endl
|
||||
|
||||
typedef CGAL::Nef_polyhedron_S2<HKernel> Nef_polyhedron_S2;
|
||||
typedef Nef_polyhedron_S2::Sphere_point Sphere_point;
|
||||
typedef Nef_polyhedron_S2::Sphere_segment Sphere_segment;
|
||||
typedef Nef_polyhedron_S2::Sphere_circle Sphere_circle;
|
||||
typedef Nef_polyhedron_S2::Explorer Explorer;
|
||||
|
||||
typedef CGAL::Creator_uniform_3<RT,Point_3> Creator;
|
||||
typedef CGAL::Random_points_in_cube_3<Point_3,Creator> Point_source;
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
CGAL::set_pretty_mode ( std::cerr );
|
||||
SETDTHREAD(911);
|
||||
// Sphere_geometry 11
|
||||
// Sphere_geometry_OGL 13
|
||||
// Segment_overlay 23
|
||||
// SM_overlayer 53
|
||||
Point_3 p(0,0,0);
|
||||
|
||||
leda_string input_file;
|
||||
leda_param_handler H(argc,argv,".nd",false);
|
||||
H.add_parameter("file_of_circles:-i:string:");
|
||||
leda_param_handler::init_all();
|
||||
H.get_parameter("-i",input_file);
|
||||
|
||||
std::list<Sphere_circle> L;
|
||||
if ( input_file == "" ) { // create random input:
|
||||
L.push_back( Sphere_circle(1,0,0) );
|
||||
L.push_back( Sphere_circle(0,1,0) );
|
||||
L.push_back( Sphere_circle(0,0,1) );
|
||||
L.push_back( Sphere_circle(1,1,1) );
|
||||
L.push_back( Sphere_circle(-1,1,1) );
|
||||
L.push_back( Sphere_circle(1,-1,1) );
|
||||
L.push_back( Sphere_circle(1,1,-1) );
|
||||
} else { // read input from file:
|
||||
std::ifstream input(input_file);
|
||||
CGAL_assertion_msg(input,"no input log.");
|
||||
Sphere_circle c;
|
||||
while ( input >> c ) L.push_back(c);
|
||||
}
|
||||
|
||||
// output log:
|
||||
std::ofstream output("nef2.log");
|
||||
std::list<Sphere_circle>::iterator it;
|
||||
CGAL_forall_iterators(it,L) output << *it << ' ';
|
||||
output << std::endl;
|
||||
output.close();
|
||||
|
||||
// partition input into two lists
|
||||
Nef_polyhedron_S2 Ni, N;
|
||||
bool first(false);
|
||||
CGAL_forall_iterators(it,L) {
|
||||
if ( first ) {
|
||||
N = Nef_polyhedron_S2(*it);
|
||||
first = false;
|
||||
} else {
|
||||
Ni = Nef_polyhedron_S2(*it);
|
||||
N = N ^ Ni;
|
||||
}
|
||||
}
|
||||
|
||||
//std::cerr << Ni << N std::endl;
|
||||
CGAL::ogl << N;
|
||||
CGAL::ogl << "Symmetric Difference";
|
||||
CGAL::ogl.display();
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
#include <LOCAL/CGALH3.h>
|
||||
#include <CGAL/copy_n.h>
|
||||
#include <CGAL/random_selection.h>
|
||||
#include <CGAL/point_generators_3.h>
|
||||
#include <LEDA/param_handler.h>
|
||||
#include <CGAL/Nef_S2/Sphere_map.h>
|
||||
#include <CGAL/Nef_S2/SM_decorator.h>
|
||||
#include <CGAL/Nef_S2/SM_io_parser.h>
|
||||
#include "SM_overlayer.h"
|
||||
|
||||
typedef CGAL::Sphere_geometry<HKernel> SKernel;
|
||||
typedef CGAL::Sphere_map<SKernel> Sphere_map;
|
||||
|
||||
typedef Sphere_map::Vertex_handle Vertex_handle;
|
||||
typedef Sphere_map::Halfedge_handle Halfedge_handle;
|
||||
typedef Sphere_map::Face_handle Face_handle;
|
||||
typedef CGAL::SM_decorator<Sphere_map,SKernel> SM_decorator;
|
||||
typedef CGAL::SM_overlayer<SM_decorator> SM_overlayer;
|
||||
|
||||
typedef CGAL::Creator_uniform_3<RT,Point_3> Creator;
|
||||
typedef CGAL::Random_points_in_cube_3<Point_3,Creator> Point_source;
|
||||
typedef SKernel::Sphere_point SPoint;
|
||||
typedef SKernel::Sphere_segment SSegment;
|
||||
|
||||
struct OR {
|
||||
bool operator()(bool b1, bool b2) const
|
||||
{ return b1||b2; }
|
||||
};
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
CGAL::set_pretty_mode ( std::cerr );
|
||||
SETDTHREAD(911);
|
||||
// Sphere_geometry 11
|
||||
// Sphere_geometry_OGL 13
|
||||
// Segment_overlay 23
|
||||
// SM_overlayer 53
|
||||
Point_3 p(0,0,0);
|
||||
Sphere_map E1,E2,E3;
|
||||
SM_decorator D1(E1),D2(E2),D3(E3);
|
||||
SM_overlayer O1(D1),O2(D2),O3(D3);
|
||||
|
||||
int n;
|
||||
leda_string input_file;
|
||||
leda_param_handler H(argc,argv,".sg",false);
|
||||
H.add_parameter("number_of_lines:-n:int:10");
|
||||
H.add_parameter("file_of_segments:-i:string:");
|
||||
leda_param_handler::init_all();
|
||||
H.get_parameter("-n",n);
|
||||
H.get_parameter("-i",input_file);
|
||||
|
||||
CGAL_assertion_msg(n>0,"-n value must be postive.");
|
||||
|
||||
std::list<SSegment> L;
|
||||
if ( input_file == "" ) {
|
||||
Point_source S(5);
|
||||
Point_3 p1,p2,ph;
|
||||
Point_3 o(0,0,0);
|
||||
while ( n-- > 0 ) {
|
||||
do { ph = *S++; } while ( ph == o );
|
||||
Plane_3 h(o,(ph-CGAL::ORIGIN).direction());
|
||||
do { p1 = *S++; }
|
||||
while ( p1 == o || h.projection(p1) == o );
|
||||
do { p2 = *S++; }
|
||||
while ( p2 == o || h.projection(p2) == o );
|
||||
SPoint p3(h.projection(p1)),p4(h.projection(p2));
|
||||
int which = CGAL::default_random.get_int(0,3);
|
||||
if ( p3 == p4 ) which = 3;
|
||||
if ( p3 == p4.opposite() ) which = 2;
|
||||
switch ( which ) {
|
||||
case 0: // short
|
||||
L.push_back( SSegment(p3,p4,true) ); break;
|
||||
case 1: // long
|
||||
L.push_back( SSegment(p3,p4,false) ); break;
|
||||
case 2: // halfcircle
|
||||
L.push_back( SSegment(p3,p3.opposite(),h) ); break;
|
||||
case 3: // trivial
|
||||
L.push_back( SSegment(p3,p3,h) ); break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
std::ifstream input(input_file);
|
||||
CGAL_assertion_msg(input,"no input log.");
|
||||
SSegment s;
|
||||
while ( input >> s ) L.push_back(s);
|
||||
}
|
||||
std::ofstream output("smo-demo.log");
|
||||
std::list<SSegment>::iterator it;
|
||||
forall_iterators(it,L) output << *it;
|
||||
output << std::endl;
|
||||
output.close();
|
||||
std::list<SSegment> L1,L2;
|
||||
int b=0;
|
||||
forall_iterators(it,L) {
|
||||
if ( b == 0 ) L1.push_back(*it);
|
||||
else L2.push_back(*it);
|
||||
b = 1-b;
|
||||
}
|
||||
O1.create_from_segments(L1.begin(),L1.end());
|
||||
O1.simplify(); // O1.dump(std::cerr);
|
||||
O2.create_from_segments(L2.begin(),L2.end());
|
||||
O2.simplify(); // O2.dump(std::cerr);
|
||||
O3.subdivide(E1,E2);
|
||||
O3.select(OR());
|
||||
O3.simplify(); // O3.dump(std::cerr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,114 @@
|
|||
#include <CGAL/leda_integer.h>
|
||||
#include <CGAL/Homogeneous.h>
|
||||
#include <CGAL/copy_n.h>
|
||||
#include <CGAL/random_selection.h>
|
||||
#include <CGAL/point_generators_3.h>
|
||||
#include <LEDA/param_handler.h>
|
||||
#include <LEDA/random.h>
|
||||
#include <CGAL/Nef_S2/leda_sphere_map.h>
|
||||
#include <CGAL/Nef_S2/Sphere_geometry_OGL.h>
|
||||
|
||||
typedef leda_integer RT;
|
||||
typedef CGAL::Homogeneous<RT> HKernel;
|
||||
typedef CGAL::Sphere_point<HKernel> SPoint;
|
||||
typedef CGAL::Sphere_segment<HKernel> SSegment;
|
||||
typedef CGAL::Plane_3<HKernel> Plane;
|
||||
typedef CGAL::Point_3<HKernel> Point;
|
||||
typedef CGAL::Direction_3<HKernel> Direction;
|
||||
|
||||
typedef CGAL::Creator_uniform_3<leda_integer,Point> Creator;
|
||||
typedef CGAL::Random_points_in_cube_3<Point,Creator> Point_source;
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
CGAL::set_pretty_mode ( std::cerr );
|
||||
SETDTHREAD(101); //(11*23*31);
|
||||
// Sphere_geometry 11
|
||||
// Sphere_geometry_OGL 13
|
||||
// PM_segment_overlay 23
|
||||
// leda_sphere_map 31
|
||||
|
||||
int n;
|
||||
leda_string input_file;
|
||||
leda_param_handler H(argc,argv,".sg",false);
|
||||
H.add_parameter("number_of_lines:-n:int:10");
|
||||
H.add_parameter("file_of_segments:-i:string:");
|
||||
leda_param_handler::init_all();
|
||||
H.get_parameter("-n",n);
|
||||
H.get_parameter("-i",input_file);
|
||||
CGAL_assertion_msg(n>0,"-n value must be postive.");
|
||||
|
||||
std::list<SSegment> L;
|
||||
if ( input_file == "" ) {
|
||||
Point_source S(5);
|
||||
Point p1,p2,ph;
|
||||
Point o(0,0,0);
|
||||
while ( n-->0 ) {
|
||||
do { ph = *S++; } while ( ph == o );
|
||||
Plane h(o,(ph-CGAL::ORIGIN).direction());
|
||||
do { p1 = *S++; }
|
||||
while ( p1 == o || h.projection(p1) == o );
|
||||
do { p2 = *S++; }
|
||||
while ( p2 == o || h.projection(p2) == o );
|
||||
SPoint p3(h.projection(p1)),p4(h.projection(p2));
|
||||
int which = CGAL::default_random.get_int(0,3);
|
||||
if ( p3 == p4 ) which = 3;
|
||||
if ( p3 == p4.opposite() ) which = 2;
|
||||
switch ( which ) {
|
||||
case 0: // short
|
||||
L.push_back( SSegment(p3,p4,true) ); break;
|
||||
case 1: // long
|
||||
L.push_back( SSegment(p3,p4,false) ); break;
|
||||
case 2: // halfcircle
|
||||
L.push_back( SSegment(p3,p3.opposite(),h) ); break;
|
||||
case 3: // trivial
|
||||
L.push_back( SSegment(p3,p3,h) ); break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
std::ifstream input(input_file);
|
||||
CGAL_assertion_msg(input,"no input log.");
|
||||
SSegment s;
|
||||
while ( input >> s ) L.push_back(s);
|
||||
}
|
||||
std::ofstream output("sg-demo.log");
|
||||
std::list<SSegment>::iterator it;
|
||||
CGAL_forall_iterators(it,L) output << *it;
|
||||
output << std::endl;
|
||||
output.close();
|
||||
leda_sphere_map_overlayer<HKernel> SMO;
|
||||
SMO.subdivide(L.begin(),L.end());
|
||||
//SMO.dump(std::cerr);
|
||||
|
||||
CGAL::OGL::add_sphere();
|
||||
CGAL::OGL::add_sphere();
|
||||
CGAL::OGL::Unit_sphere& S1(*CGAL::OGL::spheres_.begin());
|
||||
CGAL::OGL::Unit_sphere& S2(CGAL::OGL::spheres_.back());
|
||||
|
||||
CGAL_forall_iterators(it,L) {
|
||||
S1.push_back(*it);
|
||||
S1.push_back(it->source(),CGAL::BLUE);
|
||||
S1.push_back(it->target(),CGAL::BLUE);
|
||||
}
|
||||
|
||||
leda_edge e;
|
||||
forall_edges(e,SMO.sphere_map()) {
|
||||
SSegment s(SMO.sphere_map()[source(e)],
|
||||
SMO.sphere_map()[target(e)]);
|
||||
S2.push_back(s);
|
||||
}
|
||||
leda_node v;
|
||||
forall_nodes(v,SMO.sphere_map()) {
|
||||
SPoint p(SMO.sphere_map()[v]);
|
||||
S2.push_back(p);
|
||||
}
|
||||
CGAL::OGL::titles_.push_back(std::string("Input segments"));
|
||||
CGAL::OGL::titles_.push_back(std::string("Output map"));
|
||||
CGAL::OGL::start_viewer();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
# Created by the script create_makefile
|
||||
# This is the makefile for compiling a CGAL application.
|
||||
|
||||
#---------------------------------------------------------------------#
|
||||
# OpenGL und GLUT settings
|
||||
# one needs the root directories for the extended X libs and
|
||||
# the OpenGL package including a GLUT extension
|
||||
#
|
||||
# Please adapt the following paths:
|
||||
#---------------------------------------------------------------------#
|
||||
|
||||
X_DIR = /opt/xfree86-4.0.1
|
||||
X_GLUTDIR = /HPS/opt/pckg/glut
|
||||
TESTSUITE_LDFLAGS = \
|
||||
-L$(X_DIR)/lib -L$(X_GLUTDIR)/lib \
|
||||
-R$(X_DIR)/lib -R$(X_GLUTDIR)/lib \
|
||||
-lGL -lGLU -lglut -lXext -lXmu
|
||||
|
||||
#---------------------------------------------------------------------#
|
||||
# include platform specific settings
|
||||
#---------------------------------------------------------------------#
|
||||
# Choose the right include file from the <cgalroot>/make directory.
|
||||
|
||||
# CGAL_MAKEFILE = ENTER_YOUR_INCLUDE_MAKEFILE_HERE
|
||||
include $(CGAL_MAKEFILE)
|
||||
|
||||
#---------------------------------------------------------------------#
|
||||
# compiler flags
|
||||
#---------------------------------------------------------------------#
|
||||
|
||||
CXXFLAGS = \
|
||||
$(TESTSUITE_CXXFLAGS) \
|
||||
$(EXTRA_FLAGS) \
|
||||
-Iinclude -I$(X_DIR)/include -I$(X_GLUTDIR)/include\
|
||||
$(CGAL_CXXFLAGS) \
|
||||
$(LONG_NAME_PROBLEM_CXXFLAGS) \
|
||||
$(DEBUG_OPT)
|
||||
|
||||
#---------------------------------------------------------------------#
|
||||
# linker flags
|
||||
#---------------------------------------------------------------------#
|
||||
|
||||
LIBPATH = \
|
||||
$(TESTSUITE_LIBPATH) \
|
||||
$(CGAL_LIBPATH)
|
||||
|
||||
LDFLAGS = \
|
||||
$(TESTSUITE_LDFLAGS) \
|
||||
$(LONG_NAME_PROBLEM_LDFLAGS) \
|
||||
$(CGAL_WINDOW_LDFLAGS)
|
||||
|
||||
#---------------------------------------------------------------------#
|
||||
# target entries
|
||||
#---------------------------------------------------------------------#
|
||||
|
||||
all: \
|
||||
Nef_polyhedron_S2-demo Sphere_geometry-demo
|
||||
|
||||
Nef_polyhedron_S2-demo$(EXE_EXT): Nef_polyhedron_S2-demo$(OBJ_EXT)
|
||||
$(CGAL_CXX) $(LIBPATH) $(EXE_OPT)Nef_polyhedron_S2-demo Nef_polyhedron_S2-demo$(OBJ_EXT) $(LDFLAGS)
|
||||
|
||||
Sphere_geometry-demo$(EXE_EXT): Sphere_geometry-demo$(OBJ_EXT)
|
||||
$(CGAL_CXX) $(LIBPATH) $(EXE_OPT)Sphere_geometry-demo Sphere_geometry-demo$(OBJ_EXT) $(LDFLAGS)
|
||||
|
||||
clean: \
|
||||
Nef_polyhedron_S2-demo.clean Sphere_geometry-demo.clean
|
||||
|
||||
#---------------------------------------------------------------------#
|
||||
# suffix rules
|
||||
#---------------------------------------------------------------------#
|
||||
|
||||
.C$(OBJ_EXT):
|
||||
$(CGAL_CXX) $(CXXFLAGS) $(OBJ_OPT) $<
|
||||
|
||||
|
|
@ -0,0 +1 @@
|
|||
Nef polyhedra in the plane
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
TODO
|
||||
noweb
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
// ============================================================================
|
||||
//
|
||||
// Copyright (c) 1997-2000 The CGAL Consortium
|
||||
//
|
||||
// This software and related documentation is part of an INTERNAL release
|
||||
// of the Computational Geometry Algorithms Library (CGAL). It is not
|
||||
// intended for general use.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// release : $CGAL_Revision$
|
||||
// release_date : $CGAL_Date$
|
||||
//
|
||||
// file : include/CGAL/IO/Nef_polyhedron_S2_OGLUT_stream.h
|
||||
// package : Nef_S2
|
||||
// chapter : Nef Polyhedra
|
||||
//
|
||||
// revision : $Revision$
|
||||
// revision_date : $Date$
|
||||
//
|
||||
// author(s) : Michael Seel <seel@mpi-sb.mpg.de>
|
||||
// maintainer : Michael Seel <seel@mpi-sb.mpg.de>
|
||||
// coordinator : Michael Seel <seel@mpi-sb.mpg.de>
|
||||
//
|
||||
// ============================================================================
|
||||
|
||||
#ifndef NEF_POLYHEDRON_S2_OGLUT_STREAM_H
|
||||
#define NEF_POLYHEDRON_S2_OGLUT_STREAM_H
|
||||
|
||||
#include <CGAL/Nef_polyhedron_S2.h>
|
||||
#include <CGAL/Nef_S2/SM_visualizor.h>
|
||||
#include <string>
|
||||
|
||||
CGAL_BEGIN_NAMESPACE
|
||||
|
||||
|
||||
struct OGLUT_stream { // dummy class
|
||||
OGLUT_stream() {}
|
||||
void display() { CGAL::OGL::start_viewer(); }
|
||||
};
|
||||
|
||||
static OGLUT_stream ogl;
|
||||
|
||||
template <typename T>
|
||||
CGAL::OGLUT_stream& operator<<(CGAL::OGLUT_stream& ogls,
|
||||
const Nef_polyhedron_S2<T>& P)
|
||||
{
|
||||
typedef Nef_polyhedron_S2<T> Polyhedron;
|
||||
typedef typename Polyhedron::Sphere_map Sphere_map;
|
||||
typedef typename Polyhedron::Sphere_kernel Sphere_kernel;
|
||||
typedef CGAL::SM_visualizor<Sphere_map,Sphere_kernel> Visualizor;
|
||||
CGAL::OGL::add_sphere();
|
||||
Visualizor V(P.sphere_map(),CGAL::OGL::spheres_.back()); V.draw_map();
|
||||
// CGAL::OGL::spheres_.back().print();
|
||||
return ogls;
|
||||
}
|
||||
|
||||
static CGAL::OGLUT_stream& operator<<(CGAL::OGLUT_stream& ogls,
|
||||
const char* s)
|
||||
{
|
||||
CGAL::OGL::titles_.push_back(std::string(s));
|
||||
return ogls;
|
||||
}
|
||||
|
||||
CGAL_END_NAMESPACE
|
||||
|
||||
#endif // NEF_POLYHEDRON_S2_OGLUT_STREAM_H
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
#ifndef CGAL_GENERIC_HANDLE_MAP_H
|
||||
#define CGAL_GENERIC_HANDLE_MAP_H
|
||||
|
||||
#include <CGAL/Unique_hash_map.h>
|
||||
|
||||
CGAL_BEGIN_NAMESPACE
|
||||
|
||||
struct Void_handle_hash_function {
|
||||
std::size_t operator() (void* h) const {
|
||||
return std::size_t(h);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <class I>
|
||||
class Generic_handle_map : public
|
||||
Unique_hash_map<void*,I,Void_handle_hash_function>
|
||||
{ typedef Unique_hash_map<void*,I,Void_handle_hash_function> Base;
|
||||
public:
|
||||
Generic_handle_map() : Base() {}
|
||||
Generic_handle_map(I i) : Base(i) {}
|
||||
|
||||
template <class H>
|
||||
const I& operator[](H h) const
|
||||
{ return Base::operator[](&*h); }
|
||||
|
||||
template <class H>
|
||||
I& operator[](H h)
|
||||
{ return Base::operator[](&*h); }
|
||||
|
||||
};
|
||||
|
||||
CGAL_END_NAMESPACE
|
||||
#endif //CGAL_GENERIC_HANDLE_MAP_H
|
||||
|
|
@ -0,0 +1,238 @@
|
|||
#ifndef CGAL_SM_CHECKER_H
|
||||
#define CGAL_SM_CHECKER_H
|
||||
|
||||
#include <CGAL/basic.h>
|
||||
#include <CGAL/Nef_S2/SM_const_decorator.h>
|
||||
|
||||
#define USING(t) typedef typename Base::t t
|
||||
CGAL_BEGIN_NAMESPACE
|
||||
|
||||
/*{\Moptions outfile=SM_checker.man }*/
|
||||
/*{\Manpage {SM_checker}{PMCDEC,GEOM}{Plane map checking}{}}*/
|
||||
|
||||
/*{\Mdefinition An instance |\Mvar| of the data type |\Mname| is a
|
||||
decorator to check the structure of a plane map. It is generic with
|
||||
respect to two template concepts. |PMCDEC| has to be a decorator
|
||||
model of our |SM_const_decorator| concept. |GEOM| has to be a model of
|
||||
our geometry kernel concept.}*/
|
||||
|
||||
/*{\Mgeneralization SM_const_decorator}*/
|
||||
|
||||
template <typename PMCDEC, typename GEOM>
|
||||
class SM_checker : public PMCDEC
|
||||
{ typedef PMCDEC Base;
|
||||
const GEOM& K;
|
||||
public:
|
||||
/*{\Mtypes 3}*/
|
||||
typedef PMCDEC SM_const_decorator;
|
||||
/*{\Mtypemember equals |PMCDEC|. Add link to PMCDEC concept.}*/
|
||||
typedef typename PMCDEC::Plane_map Plane_map;
|
||||
/*{\Mtypemember equals |PMCDEC::Plane_map|, the underlying plane map type.}*/
|
||||
typedef GEOM Geometry;
|
||||
/*{\Mtypemember equals |GEOM|. Add link to GEOM concept.\\
|
||||
\precond |Geometry::Point_2| equals |Plane_map::Point|. }*/
|
||||
|
||||
typedef typename GEOM::Point_2 Point;
|
||||
typedef typename GEOM::Direction_2 Direction;
|
||||
|
||||
USING(Vertex_const_handle);
|
||||
USING(SEdge_handle);
|
||||
USING(Vertex_const_iterator);
|
||||
USING(Halfedge_const_iterator);
|
||||
USING(Halfedge_around_vertex_const_circulator);
|
||||
USING(Halfedge_around_face_const_circulator);
|
||||
/*{\Mtext Iterators, handles, and circulators are inherited from
|
||||
|SM_const_decorator|.}*/
|
||||
|
||||
/*{\Mcreation 3}*/
|
||||
SM_checker(Plane_map& P, const Geometry& k = Geometry()) :
|
||||
Base(P), K(k) {}
|
||||
/*{\Mcreate constructs a plane map checker working on |P| with
|
||||
geometric predicates used from |k|.}*/
|
||||
|
||||
SM_checker(const Base& D, const Geometry& k = Geometry()) :
|
||||
Base(D), K(k) {}
|
||||
|
||||
|
||||
/*{\Moperations 2 }*/
|
||||
Direction direction(Halfedge_const_handle e) const
|
||||
{ return K.construct_direction(
|
||||
point(source(e)),point(target(e))); }
|
||||
|
||||
bool is_forward(Halfedge_const_handle e) const
|
||||
{ return K.compare_xy(point(source(e)),point(target(e)))<0; }
|
||||
|
||||
void check_order_preserving_embedding(Vertex_const_handle v) const;
|
||||
/*{\Mop checks if the embedding of the targets of the edges in
|
||||
the adjacency list |A(v)| is counter-clockwise order-preserving with
|
||||
respect to the order of the edges in |A(v)|.}*/
|
||||
|
||||
void check_order_preserving_embedding() const;
|
||||
/*{\Mop checks if the embedding of all vertices of |P| is
|
||||
counter-clockwise order-preserving with respect to the adjacency
|
||||
list ordering of all vertices.}*/
|
||||
|
||||
void check_forward_prefix_condition(Vertex_const_handle v) const;
|
||||
/*{\Mop checks the forward prefix property of the adjacency
|
||||
list of |v|.}*/
|
||||
|
||||
Halfedge_const_iterator
|
||||
check_boundary_is_clockwise_weakly_polygon() const;
|
||||
/*{\Mop checks if the outer face cycle of |P| is a clockwise weakly polygon and
|
||||
returns a halfedge on the boundary. \precond |P| is a connected graph.
|
||||
}*/
|
||||
|
||||
void check_is_triangulation() const;
|
||||
/*{\Mop checks if |P| is a triangulation.}*/
|
||||
|
||||
}; // SM_checker<PMCDEC,GEOM>
|
||||
|
||||
|
||||
template <typename PMCDEC, typename GEOM>
|
||||
void SM_checker<PMCDEC,GEOM>::
|
||||
check_order_preserving_embedding(Vertex_const_handle v) const
|
||||
{
|
||||
std::ostrstream error_status;
|
||||
CGAL::set_pretty_mode ( error_status );
|
||||
Halfedge_const_handle ef = first_out_edge(v) ,e=ef,en,enn;
|
||||
error_status << "check_order_preserving_embedding\n";
|
||||
error_status << "vertex " << PV(v) << endl;
|
||||
if ( e != Halfedge_const_handle() ) {
|
||||
while ( true ) {
|
||||
en = cyclic_adj_succ(e);
|
||||
enn = cyclic_adj_succ(en);
|
||||
if (en == ef) break;
|
||||
error_status << " -> " << point(target(e));
|
||||
error_status << " " << point(target(en)) << " ";
|
||||
error_status << " " << point(target(enn)) << endl;
|
||||
if ( !K.strictly_ordered_ccw(direction(e),direction(en),
|
||||
direction(enn)) ||
|
||||
!K.strictly_ordered_ccw(direction(e),direction(en),
|
||||
direction(ef)) ) {
|
||||
error_status << "ccw order violate!" << endl << '\0';
|
||||
CGAL_assertion_msg(0,error_status.str());
|
||||
}
|
||||
e = en;
|
||||
}
|
||||
}
|
||||
error_status.freeze(0);
|
||||
}
|
||||
|
||||
template <typename PMCDEC, typename GEOM>
|
||||
void SM_checker<PMCDEC,GEOM>::
|
||||
check_forward_prefix_condition(Vertex_const_handle v) const
|
||||
{ Halfedge_const_handle ef = first_out_edge(v);
|
||||
if ( ef == Halfedge_const_handle() ) return;
|
||||
Halfedge_const_handle el = cyclic_adj_pred(ef);
|
||||
bool is_leftturn = K.leftturn(point(v),
|
||||
point(target(ef)),
|
||||
point(target(el)));
|
||||
bool el_forward = is_forward(el);
|
||||
bool ef_forward = is_forward(ef);
|
||||
CGAL_assertion_msg( (ef == el ||
|
||||
ef_forward && !el_forward ||
|
||||
ef_forward && el_forward && is_leftturn ||
|
||||
!ef_forward && !el_forward && is_leftturn) ,
|
||||
"check_forward_prefix_condition: first backward, last forward\n");
|
||||
}
|
||||
|
||||
template <typename PMCDEC, typename GEOM>
|
||||
void SM_checker<PMCDEC,GEOM>::
|
||||
check_order_preserving_embedding() const
|
||||
{
|
||||
Vertex_const_iterator vit;
|
||||
for (vit = vertices_begin(); vit != vertices_end(); ++vit) {
|
||||
check_order_preserving_embedding(vit);
|
||||
check_forward_prefix_condition(vit);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <typename PMCDEC, typename GEOM>
|
||||
typename SM_checker<PMCDEC,GEOM>::Halfedge_const_iterator
|
||||
SM_checker<PMCDEC,GEOM>::
|
||||
check_boundary_is_clockwise_weakly_polygon() const
|
||||
{
|
||||
Vertex_const_iterator vit, v_min;
|
||||
for (vit = v_min = vertices_begin() ; vit != vertices_end(); ++vit)
|
||||
if ( K.compare_xy(point(vit), point(v_min))<0 ) v_min = vit;
|
||||
CGAL_assertion_msg(!is_isolated(v_min),"Minimal vertex not connected.");
|
||||
Sphere_point p_min = point(v_min);
|
||||
|
||||
// determine boundary edge incident to v_min:
|
||||
Halfedge_const_handle e_boundary_at_v_min = first_out_edge(v_min);
|
||||
// all out edges are forward oriented due to minimality
|
||||
Halfedge_around_vertex_const_circulator
|
||||
hvit(e_boundary_at_v_min), hend(hvit);
|
||||
do {
|
||||
--hvit;
|
||||
Sphere_point p1 = point(target(e_boundary_at_v_min));
|
||||
Sphere_point p2 = point(target(hvit));
|
||||
if ( K.orientation(p_min,p1,p2) > 0 ) { // leftturn
|
||||
e_boundary_at_v_min = hvit;
|
||||
break;
|
||||
}
|
||||
} while (hvit != hend);
|
||||
// now e_boundary_at_v_min is highest starting edge in bundle!!
|
||||
|
||||
int winding_around_globally=0;
|
||||
Halfedge_around_face_const_circulator
|
||||
hfit(e_boundary_at_v_min),hstart(hfit);
|
||||
Halfedge_const_handle e_prev = next(e_boundary_at_v_min);
|
||||
/* we run counterclockwise around the outer face cycle and allow only
|
||||
position where the direction vector of an edge gets smaller again */
|
||||
Direction d_prev = direction(e_prev);
|
||||
CGAL_For_all_backwards(hstart,hfit) {
|
||||
Direction d_curr = direction(hfit);
|
||||
if ( d_curr < d_prev ) ++winding_around_globally;
|
||||
d_prev = d_curr;
|
||||
}
|
||||
CGAL_assertion(winding_around_globally == 1);
|
||||
return e_boundary_at_v_min;
|
||||
}
|
||||
|
||||
template <typename PMCDEC, typename GEOM>
|
||||
void SM_checker<PMCDEC,GEOM>::
|
||||
check_is_triangulation() const
|
||||
{
|
||||
Halfedge_const_iterator eb;
|
||||
check_integrity_and_topological_planarity(false);
|
||||
CGAL_assertion(number_of_connected_components() == 1);
|
||||
check_order_preserving_embedding();
|
||||
eb = check_boundary_is_clockwise_weakly_polygon();
|
||||
|
||||
CGAL::Hash_map< Halfedge_const_iterator, bool> on_boundary(false);
|
||||
Halfedge_around_face_const_circulator hit(eb), hend(hit);
|
||||
std::ostrstream error_status;
|
||||
CGAL::set_pretty_mode ( error_status );
|
||||
error_status << "check_is_triangulation\n";
|
||||
error_status << "on boundary:\n";
|
||||
CGAL_For_all(hit,hend) {
|
||||
error_status << " " << PE(hit) << endl;
|
||||
on_boundary[hit]=true;
|
||||
}
|
||||
Halfedge_const_iterator eit;
|
||||
for( eit = halfedges_begin(); eit != halfedges_end(); ++eit) {
|
||||
if (on_boundary[eit]) continue;
|
||||
hit = hend = eit;
|
||||
int edges_in_face_cycle=0;
|
||||
CGAL_For_all(hit,hend) {
|
||||
error_status << PE(hit);
|
||||
++edges_in_face_cycle;
|
||||
}
|
||||
CGAL_assertion_msg(edges_in_face_cycle==3,error_status.str());
|
||||
}
|
||||
error_status.freeze(0);
|
||||
}
|
||||
|
||||
|
||||
\subsection{Plane map input and output}
|
||||
The input and output is mainly triggered by an IO Decorator which
|
||||
has the control over the IO format and does some basic parsing when
|
||||
reading input.
|
||||
|
||||
CGAL_END_NAMESPACE
|
||||
|
||||
#undef USING
|
||||
#endif // CGAL_SM_CHECKER_H
|
||||
|
||||
|
|
@ -0,0 +1,546 @@
|
|||
#ifndef CGAL_SM_CONST_DECORATOR_H
|
||||
#define CGAL_SM_CONST_DECORATOR_H
|
||||
|
||||
#include <CGAL/basic.h>
|
||||
#include <CGAL/circulator.h>
|
||||
#include <CGAL/Unique_hash_map.h>
|
||||
#include <CGAL/Nef_2/Object_index.h>
|
||||
#include <CGAL/Nef_S2/SM_iteration.h>
|
||||
#include <string>
|
||||
#include <list>
|
||||
#include <strstream>
|
||||
#undef _DEBUG
|
||||
#define _DEBUG 127
|
||||
#include <CGAL/Nef_S2/debug.h>
|
||||
|
||||
CGAL_BEGIN_NAMESPACE
|
||||
|
||||
template <typename Iter, typename Move>
|
||||
class CircFromIt : public Iter {
|
||||
// Ptr node; // The internal node ptr inherited from It.
|
||||
typedef CircFromIt<Iter,Move> ThisClass;
|
||||
public:
|
||||
|
||||
CircFromIt() : Iter(0) {}
|
||||
CircFromIt(Iter i) : Iter(i) {}
|
||||
|
||||
// OPERATIONS Forward Category
|
||||
// ---------------------------
|
||||
|
||||
bool operator==( CGAL_NULL_TYPE p ) const {
|
||||
CGAL_assertion( p == NULL );
|
||||
return Iter::operator==( Iter(NULL) );
|
||||
}
|
||||
bool operator!=( CGAL_NULL_TYPE p ) const {
|
||||
return !(*this == p);
|
||||
}
|
||||
bool operator==( const ThisClass& i ) const {
|
||||
return Iter::operator==(i);
|
||||
}
|
||||
bool operator!=( const ThisClass& i) const {
|
||||
return !(*this == i);
|
||||
}
|
||||
|
||||
ThisClass& operator++() {
|
||||
Move move;
|
||||
move.forward(*this);
|
||||
return *this;
|
||||
}
|
||||
ThisClass operator++(int) {
|
||||
CircFromIt tmp = *this;
|
||||
++*this;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
// OPERATIONS Bidirectional Category
|
||||
// ---------------------------------
|
||||
|
||||
ThisClass& operator--() {
|
||||
Move move;
|
||||
move.backward(*this);
|
||||
return *this;
|
||||
}
|
||||
ThisClass operator--(int) {
|
||||
CircFromIt tmp = *this;
|
||||
--*this;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template <typename Iter, typename Move>
|
||||
inline CGAL::Circulator_tag
|
||||
query_circulator_or_iterator(const CircFromIt<Iter,Move>& )
|
||||
{ return CGAL::Circulator_tag(); }
|
||||
|
||||
template <typename HE>
|
||||
class move_edge_around_vertex {
|
||||
public:
|
||||
void forward(HE& e) const { e = (e->prev_->twin_); }
|
||||
void backward(HE& e) const { e = (e->twin_->next_); }
|
||||
};
|
||||
|
||||
template <typename HE>
|
||||
struct move_edge_around_face {
|
||||
void forward(HE& e) const { e = (e->next_); }
|
||||
void backward(HE& e) const { e = (e->prev_); }
|
||||
};
|
||||
|
||||
template <typename Iter, typename Pnt>
|
||||
class PntItFromVertIt : public Iter {
|
||||
public:
|
||||
typedef PntItFromVertIt<Iter,Pnt> Self;
|
||||
typedef Iter Base;
|
||||
typedef Pnt value_type;
|
||||
typedef const Pnt* pointer;
|
||||
typedef const Pnt& reference;
|
||||
|
||||
PntItFromVertIt() : Base() {}
|
||||
PntItFromVertIt(Iter it) : Base(it) {}
|
||||
PntItFromVertIt(const Self& it) : Base(it) {}
|
||||
|
||||
reference operator*() const
|
||||
{ return Base::operator*().point(); }
|
||||
pointer operator->() const
|
||||
{ return &(operator*()); }
|
||||
Self& operator++() { return (Self&)Base::operator++(); }
|
||||
Self operator++(int) { Self tmp=*this; ++*this; return tmp; }
|
||||
|
||||
};
|
||||
|
||||
|
||||
/*{\Moptions print_title=yes }*/
|
||||
/*{\Moptions outfile=SM_decorator.man }*/
|
||||
/*{\Manpage {SM_decorator}{HDS,Kernel}{Topological sphere map decorator}{D}}*/
|
||||
|
||||
template <typename Sphere_map_, typename Kernel_>
|
||||
class SM_const_decorator
|
||||
{ typedef SM_const_decorator<Sphere_map_,Kernel_> Self;
|
||||
public:
|
||||
|
||||
/*{\Mdefinition ...}*/
|
||||
|
||||
/*{\Mtypes 5}*/
|
||||
|
||||
typedef Kernel_ Kernel;
|
||||
|
||||
typedef typename Kernel_::Sphere_point Sphere_point;
|
||||
/*{\Mtypemember embedding vertices.}*/
|
||||
|
||||
typedef typename Kernel_::Sphere_segment Sphere_segment;
|
||||
/*{\Mtypemember embedding edges.}*/
|
||||
|
||||
typedef typename Kernel_::Sphere_circle Sphere_circle;
|
||||
/*{\Mtypemember embedding loops.}*/
|
||||
|
||||
typedef typename Sphere_map_::Mark Mark;
|
||||
/*{\Mtypemember attributes of objects (vertices, edges, faces).}*/
|
||||
|
||||
typedef size_t Size_type;
|
||||
/*{\Mtypemember size type.}*/
|
||||
|
||||
typedef void* GenPtr;
|
||||
|
||||
#define USING(t) typedef typename Sphere_map_::t t
|
||||
USING(Vertex_const_handle);
|
||||
USING(Vertex_const_iterator);
|
||||
USING(Vertex);
|
||||
USING(Halfedge);
|
||||
USING(Halfedge_const_handle);
|
||||
USING(Halfedge_const_iterator);
|
||||
USING(Face);
|
||||
USING(Face_const_handle);
|
||||
USING(Face_const_iterator);
|
||||
USING(Halfloop);
|
||||
USING(Halfloop_const_handle);
|
||||
USING(Halfloop_const_iterator);
|
||||
#undef USING
|
||||
|
||||
/*{\Mtext Local types are handles, iterators and circulators of the
|
||||
following kind: |Vertex_handle|, |Vertex_iterator|, |Halfedge_handle|,
|
||||
|Halfedge_iterator|, |Halfloop_handle|, |Halfloop_iterator|,
|
||||
|Face_handle|, |Face_iterator|. Additionally the following
|
||||
circulators are defined.}*/
|
||||
|
||||
typedef CircFromIt<
|
||||
Halfedge_const_iterator,
|
||||
move_edge_around_vertex<Halfedge_const_iterator> >
|
||||
Halfedge_around_vertex_const_circulator;
|
||||
/*{\Mtypemember circulating the adjacency list of an vertex |v|.}*/
|
||||
|
||||
typedef CircFromIt<
|
||||
Halfedge_const_iterator,
|
||||
move_edge_around_face<Halfedge_const_iterator> >
|
||||
Halfedge_around_face_const_circulator;
|
||||
/*{\Mtypemember circulating the face cycle of an face |f|.}*/
|
||||
|
||||
typedef typename Sphere_map_::Face_cycle_const_iterator
|
||||
Face_cycle_const_iterator;
|
||||
/*{\Mtypemember iterating all face cycles of an face |f|.
|
||||
The iterator has method |bool is_vertex()|, |bool is_halfedge()|,
|
||||
|bool is_halfloop()|, and can be converted to the corresponding
|
||||
handles |Vertex_const_handle|, |Halfedge_const_handle|, or
|
||||
|Halfloop_const_handle|.}*/
|
||||
|
||||
protected:
|
||||
Sphere_map_* psm_;
|
||||
friend class SM_decorator<Sphere_map_,Kernel_>;
|
||||
public:
|
||||
|
||||
/*{\Mcreation 3}*/
|
||||
SM_const_decorator() : psm_(0) {}
|
||||
SM_const_decorator(const Self& D) : psm_(D.psm_) {}
|
||||
Self& operator=(const Self& D) { psm_=D.psm_; return *this; }
|
||||
|
||||
SM_const_decorator(const Sphere_map_& M) :
|
||||
psm_(const_cast<Sphere_map_*>(&M)) {}
|
||||
/*{\Mcreate constructs a plane map decorator exploring |M|.}*/
|
||||
|
||||
/*{\Moperations 4 4}*/
|
||||
|
||||
Vertex_const_handle source(Halfedge_const_handle e) const
|
||||
/*{\Mop returns the source of |e|.}*/
|
||||
{ return e->source_; }
|
||||
|
||||
Vertex_const_handle target(Halfedge_const_handle e) const
|
||||
/*{\Mop returns the target of |e|.}*/
|
||||
{ return e->twin_->source_; }
|
||||
|
||||
Halfedge_const_handle twin(Halfedge_const_handle e) const
|
||||
/*{\Mop returns the twin of |e|.}*/
|
||||
{ return e->twin_; }
|
||||
|
||||
Halfloop_const_handle twin(Halfloop_const_handle l) const
|
||||
/*{\Mop returns the twin of |l|.}*/
|
||||
{ return l->twin_; }
|
||||
|
||||
bool is_isolated(Vertex_const_handle v) const
|
||||
/*{\Mop returns |true| when |v| is linked to the interior of a face.}*/
|
||||
{ return (Halfedge_const_handle(v->edge_) == Halfedge_const_handle()); }
|
||||
|
||||
Halfedge_const_handle first_out_edge(Vertex_const_handle v) const
|
||||
/*{\Mop returns one edge with source |v|. It's the starting point for
|
||||
the circular iteration over the edges with source |v|.
|
||||
\precond |!is_isolated(v)|.}*/
|
||||
{ return v->edge_; }
|
||||
|
||||
Halfedge_const_handle last_out_edge(Vertex_const_handle v) const
|
||||
/*{\Mop returns one edge with source |v|. \precond |!is_isolated(v)|.}*/
|
||||
{ return cap(v->edge_); }
|
||||
|
||||
Halfedge_const_handle cyclic_adj_succ(Halfedge_const_handle e) const
|
||||
/*{\Mop returns the edge after |e| in the cyclic ordered adjacency list of
|
||||
|source(e)|.}*/
|
||||
{ return e->prev_->twin_; }
|
||||
|
||||
Halfedge_const_handle cyclic_adj_pred(Halfedge_const_handle e) const
|
||||
/*{\Mop returns the edge before |e| in the cyclic ordered adjacency list of
|
||||
|source(e)|.}*/
|
||||
{ return e->twin_->next_; }
|
||||
|
||||
|
||||
Halfedge_const_handle next(Halfedge_const_handle e) const
|
||||
/*{\Mop returns the next edge in the face cycle containing |e|.}*/
|
||||
{ return e->next_; }
|
||||
|
||||
Halfedge_const_handle previous(Halfedge_const_handle e) const
|
||||
/*{\Mop returns the previous edge in the face cycle containing |e|.}*/
|
||||
{ return e->prev_; }
|
||||
|
||||
Face_const_handle face(Halfedge_const_handle e) const
|
||||
/*{\Mop returns the face incident to |e|.}*/
|
||||
{ return e->face_; }
|
||||
|
||||
Face_const_handle face(Halfloop_const_handle l) const
|
||||
/*{\Mop returns the face incident to |l|.}*/
|
||||
{ return l->face_; }
|
||||
|
||||
Face_const_handle face(Vertex_const_handle v) const
|
||||
/*{\Mop returns the face incident to |v|.
|
||||
\precond |is_isolated(v)|.}*/
|
||||
{ return v->face_; }
|
||||
|
||||
/*{\Mtext \headerline{Iteration} \setopdims{3.3cm}{0cm}}*/
|
||||
|
||||
Vertex_const_iterator vertices_begin() const
|
||||
{ return psm_->vertices_begin(); }
|
||||
Vertex_const_iterator vertices_end() const
|
||||
{ return psm_->vertices_end(); }
|
||||
Halfedge_const_iterator halfedges_begin() const
|
||||
{ return psm_->halfedges_begin(); }
|
||||
Halfedge_const_iterator halfedges_end() const
|
||||
{ return psm_->halfedges_end(); }
|
||||
Face_const_iterator faces_begin() const
|
||||
{ return psm_->faces_begin(); }
|
||||
Face_const_iterator faces_end() const
|
||||
{ return psm_->faces_end(); }
|
||||
Halfloop_const_iterator halfloops_begin() const
|
||||
{ return psm_->halfloops_begin(); }
|
||||
Halfloop_const_iterator halfloops_end() const
|
||||
{ return psm_->halfloops_end(); }
|
||||
|
||||
Halfloop_const_handle halfloop() const
|
||||
/*{\Mop returns access to the loop.}*/
|
||||
{ return psm_->loops_; }
|
||||
|
||||
bool has_loop() const
|
||||
/*{\Mop returns true iff there is a loop.}*/
|
||||
{ return halfloop() != 0; }
|
||||
|
||||
Halfedge_around_vertex_const_circulator
|
||||
out_edges(Vertex_const_handle v) const
|
||||
/*{\Mop returns a circulator for the cyclic adjacency list of |v|.
|
||||
\precond the adjacency list is not empty.}*/
|
||||
{ return Halfedge_around_vertex_const_circulator(first_out_edge(v)); }
|
||||
|
||||
Face_cycle_const_iterator face_cycles_begin(Face_const_handle f) const
|
||||
/*{\Mop returns an iterator for all bounding face cycles of |f|.
|
||||
The iterator is is convertable to |Vertex_const_handle|,
|
||||
|Halfloop_const_handle|, or |Halfedge_const_handle|.}*/
|
||||
{ return f->bounday_.begin(); }
|
||||
|
||||
Face_cycle_const_iterator face_cycles_end(Face_const_handle f) const
|
||||
/*{\Mop returns the past the end iterator of |f|.}*/
|
||||
{ return f->boundary_.end(); }
|
||||
|
||||
/*{\Mtext \headerline{Statistics and Integrity}}*/
|
||||
|
||||
Size_type number_of_vertices() const
|
||||
/*{\Mop returns the number of vertices.}*/
|
||||
{ return psm_->number_of_vertices(); }
|
||||
|
||||
Size_type number_of_halfedges() const
|
||||
/*{\Mop returns the number of halfedges.}*/
|
||||
{ return psm_->number_of_halfedges(); }
|
||||
|
||||
Size_type number_of_edges() const
|
||||
/*{\Mop returns the number of edges.}*/
|
||||
{ return number_of_halfedges()/2; }
|
||||
|
||||
Size_type number_of_halfloops() const
|
||||
/*{\Mop returns the number of halfloops.}*/
|
||||
{ return psm_->number_of_halfloops(); }
|
||||
|
||||
Size_type number_of_loops() const
|
||||
/*{\Mop returns the number of loops.}*/
|
||||
{ return psm_->number_of_halfloops()/2; }
|
||||
|
||||
Size_type number_of_faces() const
|
||||
/*{\Mop returns the number of faces.}*/
|
||||
{ return psm_->number_of_faces(); }
|
||||
|
||||
Size_type number_of_face_cycles() const;
|
||||
/*{\Mop returns the number of face cycles.}*/
|
||||
|
||||
Size_type number_of_connected_components() const;
|
||||
/*{\Mop calculates the number of connected components of |P|.}*/
|
||||
|
||||
void print_statistics(std::ostream& os = std::cout) const
|
||||
/*{\Mop print the statistics of |P|: the number of vertices, edges,
|
||||
and faces.}*/
|
||||
{
|
||||
os << "Sphere Map - Statistics\n";
|
||||
os << "|V| = " << number_of_vertices() << std::endl;
|
||||
os << "|E| = " << number_of_edges() << std::endl;
|
||||
os << "|L| = " << number_of_halfloops()/2 << std::endl;
|
||||
os << "|F| = " << number_of_faces() << std::endl;
|
||||
os << "|Fcs| = " << number_of_face_cycles() << std::endl << std::endl;
|
||||
}
|
||||
|
||||
void check_integrity_and_topological_planarity(bool faces=true) const;
|
||||
/*{\Mop checks the link structure and the genus of |P|.}*/
|
||||
|
||||
Halfedge_const_handle cas(Halfedge_const_handle e) const
|
||||
{ return cyclic_adj_succ(e); }
|
||||
|
||||
Halfedge_const_handle cap(Halfedge_const_handle e) const
|
||||
{ return cyclic_adj_pred(e); }
|
||||
|
||||
template <typename H>
|
||||
bool is_boundary_object(H h) const
|
||||
{ return psm_->is_boundary_object(h); }
|
||||
|
||||
/*{\Mtext \headerline{Associated Information}\restoreopdims}*/
|
||||
|
||||
const Sphere_point& point(Vertex_const_handle v) const
|
||||
/*{\Mop returns the embedding of |v|.}*/
|
||||
{ return v->point_; }
|
||||
|
||||
const Sphere_circle& circle(Halfedge_const_handle e) const
|
||||
/*{\Mop returns the circle supporting |e|.}*/
|
||||
{ return e->circle_; }
|
||||
|
||||
const Sphere_circle& circle(Halfloop_const_handle l) const
|
||||
/*{\Mop returns the circle supporting |l|.}*/
|
||||
{ return l->circle_; }
|
||||
|
||||
Mark mark(Vertex_const_handle v) const
|
||||
/*{\Mop returns the mark of |v|.}*/
|
||||
{ return v->mark_; }
|
||||
|
||||
Mark mark(Halfedge_const_handle e) const
|
||||
/*{\Mop returns the mark of |e|.}*/
|
||||
{ return ( &*e < &*twin(e) ) ? e->mark_ : twin(e)->mark_; }
|
||||
|
||||
Mark mark(Halfloop_const_handle l) const
|
||||
/*{\Mop returns the mark of |l|.}*/
|
||||
{ return ( &*l < &*twin(l) ) ? l->mark_ : twin(l)->mark_; }
|
||||
|
||||
Mark mark(Face_const_handle f) const
|
||||
/*{\Mop returns the mark of |f|.}*/
|
||||
{ return f->mark_; }
|
||||
|
||||
Mark mark_of_halfsphere(int i) const
|
||||
{ CGAL_assertion(i);
|
||||
if (i<0) return psm_->m_neg_;
|
||||
return psm_->m_pos_; }
|
||||
|
||||
/*{\Mtext \headerline{Iteration}}*/
|
||||
/*{\Mtext The list of all objects can be accessed via iterator ranges.
|
||||
For comfortable iteration we also provide iterations macros.
|
||||
The iterator range access operations are of the following kind:\\
|
||||
|Vertex_iterator vertices_begin()/vertices_end()|\\
|
||||
|Halfedge_iterator halfedges_begin()/halfedges_end()|\\
|
||||
|Halfloop_iterator halfloops_begin()/halfloops_end()|\\
|
||||
|Face_iterator faces_begin()/faces_end()|
|
||||
|
||||
The macros are then |CGAL_forall_vertices(v,M)|, |CGAL_forall_halfedges(e,M)|,
|
||||
|CGAL_forall_faces(f,M)|, |CGAL_forall_face_cycles_of(fc,F)| where |M| is
|
||||
a sphere map and |F| is a face.}*/
|
||||
|
||||
}; // SM_const_decorator
|
||||
|
||||
|
||||
template <class H>
|
||||
std::string PH(H h)
|
||||
{ if (h == H()) return "nil"; return h->debug(); }
|
||||
|
||||
|
||||
template <typename SM_, typename K_>
|
||||
void SM_const_decorator<SM_,K_>::
|
||||
check_integrity_and_topological_planarity(bool faces) const
|
||||
{
|
||||
TRACEN("check_integrity_and_topological_planarity:");
|
||||
using CGAL::Object_index;
|
||||
Object_index<Vertex_const_iterator>
|
||||
VI(vertices_begin(),vertices_end(),'v');
|
||||
Object_index<Halfedge_const_iterator>
|
||||
EI(halfedges_begin(),halfedges_end(),'e');
|
||||
Object_index<Face_const_iterator>
|
||||
FI(faces_begin(),faces_end(),'f');
|
||||
typedef Halfedge_around_vertex_const_circulator hvc_circulator;
|
||||
typedef Halfedge_around_face_const_circulator hfc_circulator;
|
||||
Vertex_const_handle v;
|
||||
int iso_vert_num=0;
|
||||
/* check the source links of out edges and count isolated vertices */
|
||||
CGAL_forall_vertices(v,*this) {
|
||||
if ( is_isolated(v) ) {
|
||||
if ( faces )
|
||||
CGAL_assertion_msg( face(v) != Face_const_handle(), VI(v).c_str());
|
||||
++iso_vert_num;
|
||||
} else {
|
||||
CGAL_assertion_msg( first_out_edge(v) != Halfedge_const_handle(),
|
||||
VI(v).c_str());
|
||||
TRACEN(point(v)<<" "<<EI(first_out_edge(v)));
|
||||
CGAL_assertion_msg( source(first_out_edge(v)) == v ,
|
||||
VI(v).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
/* check the bidirected links and the face pointer init */
|
||||
Halfedge_const_iterator e;
|
||||
CGAL_forall_halfedges(e,*this) {
|
||||
CGAL_assertion( twin(twin(e)) == e );
|
||||
CGAL_assertion( source(e) != Vertex_const_handle() );
|
||||
CGAL_assertion( next(e) != Halfedge_const_handle() );
|
||||
CGAL_assertion( previous(next(e)) == e );
|
||||
CGAL_assertion( target(e) == source(next(e)) );
|
||||
CGAL_assertion( previous(e) != Halfedge_const_handle() );
|
||||
CGAL_assertion( next(previous(e)) == e );
|
||||
CGAL_assertion( target(previous(e)) == source(e) );
|
||||
if ( !faces ) continue;
|
||||
CGAL_assertion( face(e) != Face_const_handle() );
|
||||
CGAL_assertion( face(next(e)) == face(e) );
|
||||
CGAL_assertion( face(previous(e)) == face(e) );
|
||||
}
|
||||
|
||||
int fc_num(0),iv_num(0);
|
||||
Face_const_iterator f;
|
||||
Face_cycle_const_iterator fci;
|
||||
CGAL_forall_faces(f,*this) {
|
||||
CGAL_forall_face_cycles_of(fci,f) {
|
||||
if ( fci.is_halfedge() ) {
|
||||
CGAL_assertion( face(Halfedge_const_handle(fci)) == f ); ++fc_num;
|
||||
} else if ( fci.is_vertex() ) {
|
||||
CGAL_assertion( face(Vertex_const_handle(fci)) == f ); ++iv_num;
|
||||
}
|
||||
else CGAL_assertion(0);
|
||||
}
|
||||
}
|
||||
|
||||
int v_num = number_of_vertices() - iso_vert_num;
|
||||
int e_num = number_of_edges();
|
||||
int c_num = number_of_connected_components() - iso_vert_num;
|
||||
int f_num = number_of_face_cycles() - c_num + 1;
|
||||
TRACEV(fc_num);TRACEV(iv_num);TRACEV(iso_vert_num);
|
||||
TRACEV(v_num);TRACEV(e_num);TRACEV(c_num);TRACEV(f_num);
|
||||
/* this means all face cycles and all isolated vertices are
|
||||
indeed referenced from a face */
|
||||
/* every isolated vertex increases the component count
|
||||
one face cycle per component is redundent except one
|
||||
finally check the Euler formula: */
|
||||
CGAL_assertion( v_num - e_num + f_num == 1 + c_num );
|
||||
}
|
||||
|
||||
template <typename SM_, typename K_>
|
||||
typename SM_const_decorator<SM_,K_>::Size_type
|
||||
SM_const_decorator<SM_,K_>::
|
||||
number_of_face_cycles() const
|
||||
{
|
||||
unsigned int fc_num=0;
|
||||
CGAL::Unique_hash_map<Halfedge_const_handle,bool> visited;
|
||||
// init with bool() == false
|
||||
Halfedge_const_iterator e;
|
||||
CGAL_forall_halfedges(e,*this) {
|
||||
if (visited[e]) continue;
|
||||
Halfedge_around_face_const_circulator hfc(e), hend(hfc);
|
||||
CGAL_For_all(hfc,hend) visited[hfc]=true;
|
||||
++fc_num;
|
||||
}
|
||||
if ( has_loop() ) fc_num += 2;
|
||||
return fc_num;
|
||||
}
|
||||
|
||||
template <typename SM_, typename K_>
|
||||
typename SM_const_decorator<SM_,K_>::Size_type
|
||||
SM_const_decorator<SM_,K_>::
|
||||
number_of_connected_components() const
|
||||
{
|
||||
int comp_num=0;
|
||||
CGAL::Unique_hash_map<Vertex_const_iterator,bool> visited(false);
|
||||
Vertex_const_iterator v;
|
||||
CGAL_forall_vertices(v,*this) {
|
||||
if (visited[v]) continue;
|
||||
std::list<Vertex_const_iterator> L;
|
||||
L.push_back(v); visited[v]=true;
|
||||
/* we keep the invariant that all nodes which have been stacked
|
||||
are marked visited */
|
||||
while (!L.empty()) {
|
||||
Vertex_const_iterator vc = L.front(); L.pop_front();
|
||||
if ( is_isolated(vc) ) continue;
|
||||
Halfedge_around_vertex_const_circulator
|
||||
havc(first_out_edge(vc)), hend(havc);
|
||||
CGAL_For_all(havc,hend) {
|
||||
if (!visited[target(havc)]) {
|
||||
L.push_back(target(havc)); visited[target(havc)]=true;
|
||||
}
|
||||
}
|
||||
}
|
||||
++comp_num;
|
||||
}
|
||||
return comp_num;
|
||||
}
|
||||
|
||||
CGAL_END_NAMESPACE
|
||||
#endif // CGAL_SM_CONST_DECORATOR_H
|
||||
|
||||
|
|
@ -0,0 +1,412 @@
|
|||
// ============================================================================
|
||||
//
|
||||
// Copyright (c) 1997-2000 The CGAL Consortium
|
||||
//
|
||||
// This software and related documentation is part of an INTERNAL release
|
||||
// of the Computational Geometry Algorithms Library (CGAL). It is not
|
||||
// intended for general use.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// release : $CGAL_Revision$
|
||||
// release_date : $CGAL_Date$
|
||||
//
|
||||
// file : include/CGAL/Nef_S2/SM_constrained_triang_traits.h
|
||||
// package : Nef_S2
|
||||
// chapter : Nef Polyhedra
|
||||
//
|
||||
// revision : $Revision$
|
||||
// revision_date : $Date$
|
||||
//
|
||||
// author(s) : Michael Seel <seel@mpi-sb.mpg.de>
|
||||
// maintainer : Michael Seel <seel@mpi-sb.mpg.de>
|
||||
// coordinator : Michael Seel <seel@mpi-sb.mpg.de>
|
||||
//
|
||||
// implementation: Constrained triangulation of a sphere map
|
||||
// ============================================================================
|
||||
#ifndef CGAL_SM_CONSTRAINED_TRIANG_TRAITS_H
|
||||
#define CGAL_SM_CONSTRAINED_TRIANG_TRAITS_H
|
||||
|
||||
#include <CGAL/basic.h>
|
||||
#include <CGAL/Unique_hash_map.h>
|
||||
#include <CGAL/generic_sweep.h>
|
||||
//#include <CGAL/Nef_S2/SM_checker.h>
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#undef _DEBUG
|
||||
#define _DEBUG 139
|
||||
#include <CGAL/Nef_S2/debug.h>
|
||||
|
||||
CGAL_BEGIN_NAMESPACE
|
||||
|
||||
/* For a detailed documentation see the MPI research report 2001-1-003
|
||||
which documents the planar flavor of this baby; only minor deviations
|
||||
are included in this code */
|
||||
|
||||
template <typename Decorator_, typename Kernel_>
|
||||
class SM_constrained_triang_traits : public Decorator_ {
|
||||
public:
|
||||
typedef SM_constrained_triang_traits<Decorator_,Kernel_> Self;
|
||||
typedef Decorator_ Base;
|
||||
|
||||
|
||||
typedef typename Kernel_::Point_2 Point;
|
||||
typedef typename Kernel_::Segment_2 Segment;
|
||||
|
||||
typedef typename Base::Halfedge_handle Halfedge_handle;
|
||||
typedef typename Base::Vertex_handle Vertex_handle;
|
||||
typedef typename Base::Face_handle Face_handle;
|
||||
typedef typename Base::Halfedge_iterator Halfedge_iterator;
|
||||
typedef typename Base::Vertex_iterator Vertex_iterator;
|
||||
typedef typename Base::Face_iterator Face_iterator;
|
||||
typedef typename Base::Halfedge_around_vertex_circulator
|
||||
Halfedge_around_vertex_circulator;
|
||||
|
||||
// the types interfacing the sweep:
|
||||
typedef std::pair<Vertex_iterator,Vertex_iterator> INPUT;
|
||||
typedef Decorator_ OUTPUT;
|
||||
typedef Kernel_ GEOMETRY;
|
||||
|
||||
|
||||
class lt_edges_in_sweepline : public Decorator_
|
||||
{ const Point& p;
|
||||
const Halfedge_handle& e_bottom;
|
||||
const Halfedge_handle& e_top;
|
||||
const Kernel_& K;
|
||||
public:
|
||||
lt_edges_in_sweepline(const Point& pi,
|
||||
const Halfedge_handle& e1, const Halfedge_handle& e2,
|
||||
const Decorator_& D, const Kernel_& k) :
|
||||
Decorator_(D), p(pi), e_bottom(e1), e_top(e2), K(k) {}
|
||||
|
||||
lt_edges_in_sweepline(const lt_edges_in_sweepline& lt) :
|
||||
Decorator_(lt), p(lt.p),
|
||||
e_bottom(lt.e_bottom), e_top(lt.e_top), K(lt.K) {}
|
||||
|
||||
Segment seg(const Halfedge_handle& e) const
|
||||
{ return K.construct_segment(point(source(e)),point(target(e))); }
|
||||
|
||||
int orientation(Halfedge_handle e, const Point& p) const
|
||||
{ return K.orientation(point(source(e)),point(target(e)),p); }
|
||||
|
||||
bool operator()(const Halfedge_handle& e1, const Halfedge_handle& e2) const
|
||||
{ // Precondition:
|
||||
// [[p]] is identical to the source of either [[e1]] or [[e2]].
|
||||
if (e1 == e_bottom || e2 == e_top) return true;
|
||||
if (e2 == e_bottom || e1 == e_top) return false;
|
||||
if ( e1 == e2 ) return 0;
|
||||
int s = 0;
|
||||
if ( p == point(source(e1)) ) s = orientation(e2,p);
|
||||
else if ( p == point(source(e2)) ) s = - orientation(e1,p);
|
||||
else CGAL_assertion_msg(0,"compare error in sweep.");
|
||||
if ( s || source(e1) == target(e1) || source(e2) == target(e2) )
|
||||
return ( s < 0 );
|
||||
s = orientation(e2,point(target(e1)));
|
||||
if (s==0) CGAL_assertion_msg(0,"parallel edges not allowed.");
|
||||
return ( s < 0 );
|
||||
}
|
||||
|
||||
|
||||
}; // lt_edges_in_sweepline
|
||||
|
||||
class lt_pnts_xy : public Decorator_
|
||||
{ const Kernel_& K;
|
||||
public:
|
||||
lt_pnts_xy(const Decorator_& D, const Kernel_& k) : Decorator_(D), K(k) {}
|
||||
lt_pnts_xy(const lt_pnts_xy& lt) : Decorator_(lt), K(lt.K) {}
|
||||
int operator()(const Vertex_handle& v1, const Vertex_handle& v2) const
|
||||
{ return K.compare_xy(point(v1),point(v2)) < 0; }
|
||||
}; // lt_pnts_xy
|
||||
|
||||
|
||||
typedef std::map<Halfedge_handle, Halfedge_handle, lt_edges_in_sweepline>
|
||||
Sweep_status_structure;
|
||||
typedef typename Sweep_status_structure::iterator ss_iterator;
|
||||
typedef typename Sweep_status_structure::value_type ss_pair;
|
||||
typedef std::set<Vertex_iterator,lt_pnts_xy> Event_Q;
|
||||
typedef typename Event_Q::const_iterator event_iterator;
|
||||
|
||||
const GEOMETRY& K;
|
||||
Event_Q event_Q;
|
||||
event_iterator event_it;
|
||||
Vertex_handle event;
|
||||
Point p_sweep;
|
||||
Sweep_status_structure SL;
|
||||
CGAL::Unique_hash_map<Halfedge_handle,ss_iterator> SLItem;
|
||||
Halfedge_handle e_low,e_high; // framing edges !
|
||||
Halfedge_handle e_search;
|
||||
Vertex_iterator v_first, v_beyond;
|
||||
|
||||
SM_constrained_triang_traits(const INPUT& in, OUTPUT& out,
|
||||
const GEOMETRY& k)
|
||||
: Base(out), K(k), event_Q(lt_pnts_xy(*this,K)),
|
||||
SL(lt_edges_in_sweepline(p_sweep,e_low,e_high,*this,K)),
|
||||
SLItem(SL.end()), v_first(in.first), v_beyond(in.second)
|
||||
{ TRACEN("Constrained Triangulation Sweep"); }
|
||||
|
||||
/* |treat_new_edge| is used to forward information that exists
|
||||
at input edges of the triangulation as such it spreads input
|
||||
information to the newly created edges of the triangulation;
|
||||
the used operation incident_mark refers to the base class of
|
||||
|*this| */
|
||||
void treat_new_edge(Halfedge_handle e)
|
||||
{ assoc_info(e);
|
||||
mark(e) = incident_mark(e) = incident_mark(twin(e)) =
|
||||
incident_mark(next(e));
|
||||
TRACEN(" treat_new_edge "<<PH(e));
|
||||
}
|
||||
|
||||
Halfedge_handle new_bi_edge(Vertex_handle v1, Vertex_handle v2)
|
||||
{ // appended at v1 and v2 adj list
|
||||
Halfedge_handle e = Base::new_edge_pair(v1,v2);
|
||||
treat_new_edge(e);
|
||||
return e;
|
||||
}
|
||||
|
||||
Halfedge_handle new_bi_edge(Halfedge_handle e_bf, Halfedge_handle e_af)
|
||||
{ // ccw before e_bf and after e_af
|
||||
Halfedge_handle e =
|
||||
Base::new_edge_pair(e_bf,e_af,Base::BEFORE, Base::AFTER);
|
||||
treat_new_edge(e);
|
||||
return e;
|
||||
}
|
||||
|
||||
Halfedge_handle new_bi_edge(Vertex_handle v, Halfedge_handle e_bf)
|
||||
{ // appended at v's adj list and before e_bf
|
||||
Halfedge_handle e = Base::new_edge_pair(v,e_bf,Base::BEFORE);
|
||||
treat_new_edge(e);
|
||||
return e;
|
||||
}
|
||||
|
||||
Segment segment(Halfedge_handle e) const
|
||||
{ return K.construct_segment(point(source(e)),point(target(e))); }
|
||||
|
||||
bool is_forward(Halfedge_handle e) const
|
||||
{ return K.compare_xy(point(source(e)),point(target(e))) < 0; }
|
||||
|
||||
bool edge_is_visible_from(Vertex_handle v, Halfedge_handle e)
|
||||
{
|
||||
Point p = point(v);
|
||||
Point p1 = point(source(e));
|
||||
Point p2 = point(target(e));
|
||||
return ( K.orientation(p1,p2,p) > 0 ); // leftturn
|
||||
}
|
||||
|
||||
void triangulate_up(Halfedge_handle& e_apex)
|
||||
{
|
||||
TRACEN("triangulate_up "<<segment(e_apex));
|
||||
Vertex_handle v_apex = source(e_apex);
|
||||
while (true) {
|
||||
Halfedge_handle e_vis = previous(twin(e_apex));
|
||||
bool in_sweep_line = (SLItem[e_vis] != SL.end());
|
||||
bool not_visible = !edge_is_visible_from(v_apex,e_vis);
|
||||
TRACEN(" checking "<<in_sweep_line<<not_visible<<" "<<segment(e_vis));
|
||||
if ( in_sweep_line || not_visible) {
|
||||
TRACEN(" STOP"); return;
|
||||
}
|
||||
Halfedge_handle e_back = new_bi_edge(e_apex,e_vis);
|
||||
e_apex = e_back;
|
||||
TRACEN(" produced " << segment(e_apex));
|
||||
}
|
||||
}
|
||||
|
||||
void triangulate_down(Halfedge_handle& e_apex)
|
||||
{
|
||||
TRACEN("triangulate_down "<<segment(e_apex));
|
||||
Vertex_handle v_apex = source(e_apex);
|
||||
while (true) {
|
||||
Halfedge_handle e_vis = next(e_apex);
|
||||
bool in_sweep_line = (SLItem[e_vis] != SL.end());
|
||||
bool not_visible = !edge_is_visible_from(v_apex,e_vis);
|
||||
TRACEN(" checking "<<in_sweep_line<<not_visible<<" "<<segment(e_vis));
|
||||
if ( in_sweep_line || not_visible) {
|
||||
TRACEN(" STOP"); return;
|
||||
}
|
||||
Halfedge_handle e_vis_rev = twin(e_vis);
|
||||
Halfedge_handle e_forw = new_bi_edge(e_vis_rev,e_apex);
|
||||
e_apex = twin(e_forw);
|
||||
TRACEN(" produced " << segment(e_apex));
|
||||
}
|
||||
}
|
||||
|
||||
void triangulate_between(Halfedge_handle e_upper, Halfedge_handle e_lower)
|
||||
{
|
||||
// we triangulate the interior of the whole chain between
|
||||
// target(e_upper) and target(e_lower)
|
||||
assert(source(e_upper)==source(e_lower));
|
||||
TRACE("triangulate_between\n "<<segment(e_upper));
|
||||
TRACEN("\n "<<segment(e_lower));
|
||||
Halfedge_handle e_end = twin(e_lower);
|
||||
while (true) {
|
||||
Halfedge_handle e_vis = next(e_upper);
|
||||
Halfedge_handle en_vis = next(e_vis);
|
||||
TRACEN(" working on base e_vis " << segment(e_vis));
|
||||
TRACEN(" next is " << segment(en_vis));
|
||||
if (en_vis == e_end) return;
|
||||
e_upper = twin(new_bi_edge(twin(e_vis),e_upper));
|
||||
TRACEN(" produced " << segment(e_upper));
|
||||
}
|
||||
}
|
||||
|
||||
void process_event()
|
||||
{
|
||||
TRACEN("\nPROCESS_EVENT " << p_sweep);
|
||||
Halfedge_handle e, ep, eb_low, eb_high, e_end;
|
||||
if ( !is_isolated(event) ) {
|
||||
e = last_out_edge(event);
|
||||
ep = first_out_edge(event);
|
||||
}
|
||||
ss_iterator sit_pred, sit;
|
||||
/* PRECONDITION:
|
||||
only ingoing => e is lowest in ingoing bundle
|
||||
only outgoing => e is highest in outgoing bundle
|
||||
ingoing and outgoing => e is lowest in ingoing bundle */
|
||||
eb_high = e_end = ep;
|
||||
eb_low = e;
|
||||
TRACEN("determining handle in SL");
|
||||
if ( e != Halfedge_handle() ) {
|
||||
point(target(e_search)) = p_sweep; // degenerate loop edge
|
||||
sit_pred = SLItem[e];
|
||||
if ( sit_pred != SL.end()) sit = --sit_pred;
|
||||
else sit = sit_pred = --SL.upper_bound(e_search);
|
||||
} else { // event is isolated vertex
|
||||
point(target(e_search)) = p_sweep; // degenerate loop edge
|
||||
sit_pred = --SL.upper_bound(e_search);
|
||||
}
|
||||
|
||||
bool ending_edges(0), starting_edges(0);
|
||||
while ( e != Halfedge_handle() ) { // walk adjacency list clockwise
|
||||
if ( SLItem[e] != SL.end() )
|
||||
{
|
||||
TRACEN("ending " << segment(e));
|
||||
if (ending_edges) triangulate_between(e,cyclic_adj_succ(e));
|
||||
ending_edges = true;
|
||||
SL.erase(SLItem[e]);
|
||||
link_bi_edge_to(e,SL.end());
|
||||
// not in SL anymore
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACEN("starting "<<segment(e));
|
||||
sit = SL.insert(sit,ss_pair(e,e));
|
||||
link_bi_edge_to(e,sit);
|
||||
if ( !starting_edges ) eb_high = cyclic_adj_succ(e);
|
||||
starting_edges = true;
|
||||
}
|
||||
|
||||
if (e == e_end) break;
|
||||
e = cyclic_adj_pred(e);
|
||||
}
|
||||
if (!ending_edges)
|
||||
{
|
||||
Halfedge_handle e_vis = sit_pred->second;
|
||||
Halfedge_handle e_vis_n = cyclic_adj_succ(e_vis);
|
||||
eb_low = eb_high = new_bi_edge(event,e_vis_n);
|
||||
TRACEN(" producing link "<<segment(eb_low)<<
|
||||
"\n before "<<segment(e_vis_n));
|
||||
}
|
||||
|
||||
triangulate_up(eb_high);
|
||||
triangulate_down(eb_low);
|
||||
sit_pred->second = eb_low;
|
||||
}
|
||||
|
||||
bool event_exists()
|
||||
{ if ( event_it != event_Q.end() ) {
|
||||
// event is set at end of loop and in init
|
||||
event = *event_it;
|
||||
p_sweep = point(event);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void procede_to_next_event()
|
||||
{ ++event_it; }
|
||||
|
||||
void link_bi_edge_to(Halfedge_handle e, ss_iterator sit) {
|
||||
SLItem[e] = SLItem[twin(e)] = sit;
|
||||
}
|
||||
|
||||
void initialize_structures()
|
||||
{
|
||||
TRACEN("initialize_structures ");
|
||||
|
||||
for ( event = v_first; event != v_beyond; ++event )
|
||||
event_Q.insert(event); // sorted order of vertices
|
||||
|
||||
event_it = event_Q.begin();
|
||||
if ( event_Q.empty() ) return;
|
||||
event = *event_it;
|
||||
p_sweep = point(event);
|
||||
if ( !is_isolated(event) ) {
|
||||
Halfedge_around_vertex_circulator
|
||||
e(first_out_edge(event)), eend(e);
|
||||
CGAL_For_all(e,eend) {
|
||||
TRACEN("init with "<<PH(e));
|
||||
ss_iterator sit = SL.insert(ss_pair(e,e)).first;
|
||||
link_bi_edge_to(e,sit);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Vertex_handle v_tmp = new_vertex(Point());
|
||||
e_high = Base::new_edge_pair(event,v_tmp);
|
||||
e_low = Base::new_edge_pair(event,v_tmp);
|
||||
// this are two symbolic edges just accessed as sentinels
|
||||
// they carry no geometric information
|
||||
e_search = Base::new_edge_pair(v_tmp,v_tmp);
|
||||
// this is just a loop used for searches in SL
|
||||
|
||||
ss_iterator sit_high = SL.insert(ss_pair(e_high,e_high)).first;
|
||||
ss_iterator sit_low = SL.insert(ss_pair(e_low,e_low)).first;
|
||||
// inserting sentinels into SL
|
||||
link_bi_edge_to(e_high, sit_high);
|
||||
link_bi_edge_to(e_low , sit_low);
|
||||
// we mark them being in the sweepline, which they will never leave
|
||||
|
||||
|
||||
// we move to the second vertex:
|
||||
procede_to_next_event();
|
||||
event_exists(); // sets p_sweep for check invariants
|
||||
TRACEN("EOF initialization");
|
||||
}
|
||||
|
||||
void complete_structures()
|
||||
{
|
||||
if (e_low != Halfedge_handle()) {
|
||||
delete_vertex(target(e_search));
|
||||
} // removing sentinels and e_search
|
||||
}
|
||||
|
||||
|
||||
void check_ccw_local_embedding() const
|
||||
{
|
||||
#ifdef CGAL_CHECK_EXPENSIVEXXX
|
||||
PM_checker<Decorator_,Kernel_> C(*this,K);
|
||||
C.check_order_preserving_embedding(event);
|
||||
#endif
|
||||
}
|
||||
|
||||
void check_invariants()
|
||||
{
|
||||
#ifdef CGAL_CHECK_EXPENSIVEXXX
|
||||
if ( event_it == event_Q.end() ) return;
|
||||
check_ccw_local_embedding();
|
||||
#endif
|
||||
}
|
||||
|
||||
void check_final()
|
||||
{
|
||||
#ifdef CGAL_CHECK_EXPENSIVEXXX
|
||||
PM_checker<Decorator_,Kernel_> C(*this,K); C.check_is_triangulation();
|
||||
#endif
|
||||
}
|
||||
|
||||
}; // SM_constrained_triang_traits<Decorator_,Kernel_,New_edge_>
|
||||
|
||||
|
||||
CGAL_END_NAMESPACE
|
||||
#endif // CGAL_SM_CONSTRAINED_TRIANG_TRAITS_H
|
||||
|
||||
|
|
@ -0,0 +1,796 @@
|
|||
#ifndef CGAL_SM_DECORATOR_H
|
||||
#define CGAL_SM_DECORATOR_H
|
||||
|
||||
#include <CGAL/basic.h>
|
||||
#include <CGAL/Nef_S2/SM_const_decorator.h>
|
||||
|
||||
CGAL_BEGIN_NAMESPACE
|
||||
|
||||
/*{\Moptions print_title=yes }*/
|
||||
/*{\Moptions outfile=SM_decorator.man }*/
|
||||
/*{\Manpage {SM_decorator}{Sphere_map,Kernel}
|
||||
{Topological sphere map decorator}{D}}*/
|
||||
|
||||
template <typename Sphere_map_, typename Kernel_>
|
||||
class SM_decorator : public SM_const_decorator<Sphere_map_,Kernel_>
|
||||
{
|
||||
public:
|
||||
typedef SM_const_decorator<Sphere_map_,Kernel_> Base;
|
||||
typedef SM_decorator<Sphere_map_,Kernel_> Self;
|
||||
|
||||
/*{\Mdefinition ...}*/
|
||||
|
||||
/*{\Mtypes 5}*/
|
||||
|
||||
typedef Sphere_map_ Sphere_map;
|
||||
typedef Kernel_ Kernel;
|
||||
|
||||
typedef typename Kernel_::Sphere_point Sphere_point;
|
||||
/*{\Mtypemember embedding vertices.}*/
|
||||
|
||||
typedef typename Kernel_::Sphere_segment Sphere_segment;
|
||||
/*{\Mtypemember embedding edges.}*/
|
||||
|
||||
typedef typename Kernel_::Sphere_circle Sphere_circle;
|
||||
/*{\Mtypemember embedding loops.}*/
|
||||
|
||||
typedef typename Sphere_map_::Mark Mark;
|
||||
/*{\Mtypemember attributes of objects (vertices, edges, faces).}*/
|
||||
|
||||
typedef size_t Size_type;
|
||||
/*{\Mtypemember size type.}*/
|
||||
|
||||
enum { BEFORE = -1, AFTER = 1 };
|
||||
/*{\Menum insertion order labels.}*/
|
||||
|
||||
typedef void* GenPtr;
|
||||
|
||||
#define USING(t) typedef typename Sphere_map_::t t
|
||||
USING(Vertex);
|
||||
USING(Vertex_const_handle);
|
||||
USING(Vertex_const_iterator);
|
||||
USING(Halfedge);
|
||||
USING(Halfedge_const_handle);
|
||||
USING(Halfedge_const_iterator);
|
||||
USING(Face);
|
||||
USING(Face_const_handle);
|
||||
USING(Face_const_iterator);
|
||||
USING(Halfloop);
|
||||
USING(Halfloop_const_handle);
|
||||
USING(Halfloop_const_iterator);
|
||||
USING(Vertex_handle);
|
||||
USING(Vertex_iterator);
|
||||
USING(Halfedge_handle);
|
||||
USING(Halfedge_iterator);
|
||||
USING(Face_handle);
|
||||
USING(Face_iterator);
|
||||
USING(Halfloop_handle);
|
||||
USING(Halfloop_iterator);
|
||||
USING(Object_handle);
|
||||
#undef USING
|
||||
#define USING(t) typedef typename Base::t t
|
||||
USING(Halfedge_around_vertex_const_circulator);
|
||||
USING(Halfedge_around_face_const_circulator);
|
||||
USING(Face_cycle_const_iterator);
|
||||
#undef USING
|
||||
|
||||
|
||||
/*{\Mtext Local types are handles, iterators and circulators of the
|
||||
following kind: |Vertex_handle|, |Vertex_iterator|, |Halfedge_handle|,
|
||||
|Halfedge_iterator|, |Halfloop_handle|, |Halfloop_iterator|,
|
||||
|Face_handle|, |Face_iterator|. Additionally the following
|
||||
circulators are defined.}*/
|
||||
|
||||
typedef CircFromIt<
|
||||
Halfedge_iterator,
|
||||
move_edge_around_vertex<Halfedge_iterator> >
|
||||
Halfedge_around_vertex_circulator;
|
||||
/*{\Mtypemember circulating the adjacency list of an vertex |v|.}*/
|
||||
|
||||
typedef CircFromIt<
|
||||
Halfedge_iterator,
|
||||
move_edge_around_face<Halfedge_iterator> >
|
||||
Halfedge_around_face_circulator;
|
||||
/*{\Mtypemember circulating the face cycle of an face |f|.}*/
|
||||
|
||||
typedef typename Sphere_map_::Face_cycle_iterator
|
||||
Face_cycle_iterator;
|
||||
/*{\Mtypemember iterating all face cycles of an face |f|.
|
||||
The iterator has method |bool is_vertex()|, |bool is_halfedge()|,
|
||||
|bool is_halfloop()|, and can be converted to the corresponding
|
||||
handles |Vertex_handle|, |Halfedge_handle|, or
|
||||
|Halfloop_handle|.}*/
|
||||
|
||||
public:
|
||||
|
||||
/*{\Mcreation 3}*/
|
||||
SM_decorator() : Base() {}
|
||||
SM_decorator(const Self& D) : Base(D) {}
|
||||
|
||||
SM_decorator(Sphere_map_& M) : Base(M) {}
|
||||
/*{\Mcreate constructs a plane map decorator exploring |M|.}*/
|
||||
|
||||
|
||||
/*{\Moperations 4 4}*/
|
||||
|
||||
Sphere_map& sm() { return *psm_; }
|
||||
|
||||
Vertex_const_handle source(Halfedge_const_handle e) const
|
||||
{ return e->source_; }
|
||||
Vertex_const_handle target(Halfedge_const_handle e) const
|
||||
{ return e->twin_->source_; }
|
||||
Halfedge_const_handle twin(Halfedge_const_handle e) const
|
||||
{ return e->twin_; }
|
||||
Halfloop_const_handle twin(Halfloop_const_handle l) const
|
||||
{ return l->twin_; }
|
||||
|
||||
Vertex_handle source(Halfedge_handle e) const
|
||||
/*{\Mop returns the source of |e|.}*/
|
||||
{ return e->source_; }
|
||||
|
||||
Vertex_handle target(Halfedge_handle e) const
|
||||
/*{\Mop returns the target of |e|.}*/
|
||||
{ return e->twin_->source_; }
|
||||
|
||||
Halfedge_handle twin(Halfedge_handle e) const
|
||||
/*{\Mop returns the twin of |e|.}*/
|
||||
{ return e->twin_; }
|
||||
|
||||
Halfloop_handle twin(Halfloop_handle l) const
|
||||
/*{\Mop returns the twin of |l|.}*/
|
||||
{ return l->twin_; }
|
||||
|
||||
bool is_isolated(Vertex_const_handle v) const
|
||||
{ return (v->edge_ == Halfedge_handle()); }
|
||||
|
||||
bool is_isolated(Vertex_handle v) const
|
||||
/*{\Mop returns |true| when |v| is linked to the interior of a face.}*/
|
||||
{ return (v->edge_ == Halfedge_handle()); }
|
||||
|
||||
Halfedge_const_handle first_out_edge(Vertex_const_handle v) const
|
||||
{ return v->edge_; }
|
||||
Halfedge_const_handle last_out_edge(Vertex_const_handle v) const
|
||||
{ return cap(v->edge_); }
|
||||
|
||||
Halfedge_handle first_out_edge(Vertex_handle v) const
|
||||
/*{\Mop returns one edge with source |v|. It's the starting point for
|
||||
the circular iteration over the edges with source |v|.
|
||||
\precond |!is_isolated(v)|.}*/
|
||||
{ return v->edge_; }
|
||||
|
||||
Halfedge_handle last_out_edge(Vertex_handle v) const
|
||||
/*{\Mop returns one edge with source |v|. \precond |!is_isolated(v)|.}*/
|
||||
{ return cap(v->edge_); }
|
||||
|
||||
Halfedge_const_handle cyclic_adj_succ(Halfedge_const_handle e) const
|
||||
{ return e->prev_->twin_; }
|
||||
Halfedge_const_handle cyclic_adj_pred(Halfedge_const_handle e) const
|
||||
{ return e->twin_->next_; }
|
||||
|
||||
Halfedge_handle cyclic_adj_succ(Halfedge_handle e) const
|
||||
/*{\Mop returns the edge after |e| in the cyclic ordered adjacency list of
|
||||
|source(e)|.}*/
|
||||
{ return e->prev_->twin_; }
|
||||
|
||||
Halfedge_handle cyclic_adj_pred(Halfedge_handle e) const
|
||||
/*{\Mop returns the edge before |e| in the cyclic ordered adjacency list of
|
||||
|source(e)|.}*/
|
||||
{ return e->twin_->next_; }
|
||||
|
||||
Halfedge_const_handle next(Halfedge_const_handle e) const
|
||||
{ return e->next_; }
|
||||
Halfedge_const_handle previous(Halfedge_const_handle e) const
|
||||
{ return e->prev_; }
|
||||
|
||||
Halfedge_handle next(Halfedge_handle e) const
|
||||
/*{\Mop returns the next edge in the face cycle containing |e|.}*/
|
||||
{ return e->next_; }
|
||||
|
||||
Halfedge_handle previous(Halfedge_handle e) const
|
||||
/*{\Mop returns the previous edge in the face cycle containing |e|.}*/
|
||||
{ return e->prev_; }
|
||||
|
||||
Face_const_handle face(Halfedge_const_handle e) const
|
||||
{ return e->face_; }
|
||||
Face_const_handle face(Halfloop_const_handle l) const
|
||||
{ return l->face_; }
|
||||
Face_const_handle face(Vertex_const_handle v) const
|
||||
{ return v->face_; }
|
||||
|
||||
Face_handle face(Halfedge_handle e) const
|
||||
/*{\Mop returns the face incident to |e|.}*/
|
||||
{ return e->face_; }
|
||||
|
||||
Face_handle face(Halfloop_handle l) const
|
||||
/*{\Mop returns the face incident to |l|.}*/
|
||||
{ return l->face_; }
|
||||
|
||||
Face_handle face(Vertex_handle v) const
|
||||
/*{\Mop returns the face incident to |v|. \precond |is_isolated(v)|.}*/
|
||||
{ return v->face_; }
|
||||
|
||||
/*{\Mtext \headerline{Iteration} \setopdims{3.3cm}{0cm}}*/
|
||||
|
||||
Vertex_iterator vertices_begin() const
|
||||
{ return psm_->vertices_begin(); }
|
||||
Vertex_iterator vertices_end() const
|
||||
{ return psm_->vertices_end(); }
|
||||
Halfedge_iterator halfedges_begin() const
|
||||
{ return psm_->halfedges_begin(); }
|
||||
Halfedge_iterator halfedges_end() const
|
||||
{ return psm_->halfedges_end(); }
|
||||
Face_iterator faces_begin() const
|
||||
{ return psm_->faces_begin(); }
|
||||
Face_iterator faces_end() const
|
||||
{ return psm_->faces_end(); }
|
||||
Halfloop_iterator halfloops_begin() const
|
||||
{ return psm_->halfloops_begin(); }
|
||||
Halfloop_iterator halfloops_end() const
|
||||
{ return psm_->halfloops_end(); }
|
||||
|
||||
Halfloop_handle halfloop() const
|
||||
{ return psm_->loops_; }
|
||||
|
||||
Halfedge_around_vertex_const_circulator
|
||||
out_edges(Vertex_const_handle v) const
|
||||
{ return Halfedge_around_vertex_circulator(first_out_edge(v)); }
|
||||
Face_cycle_const_iterator face_cycles_begin(Face_const_handle f) const
|
||||
{ return f->bounday_.begin(); }
|
||||
Face_cycle_const_iterator face_cycles_end(Face_const_handle f) const
|
||||
{ return f->boundary_.end(); }
|
||||
|
||||
Face_cycle_iterator face_cycles_begin(Face_handle f) const
|
||||
/*{\Mop returns an iterator for all bounding face cycles of |f|.
|
||||
The iterator is is convertable to |Vertex_handle|,
|
||||
|Halfloop_handle|, or |Halfedge_handle|.}*/
|
||||
{ return f->boundary_.begin(); }
|
||||
|
||||
Face_cycle_iterator face_cycles_end(Face_handle f) const
|
||||
/*{\Mop returns the past the end iterator of |f|.}*/
|
||||
{ return f->boundary_.end(); }
|
||||
|
||||
Halfedge_around_vertex_circulator
|
||||
out_edges(Vertex_handle v) const
|
||||
/*{\Mop returns a circulator for the cyclic adjacency list of |v|.
|
||||
\precond the adjacency list is not empty.}*/
|
||||
{ return Halfedge_around_vertex_circulator(first_out_edge(v)); }
|
||||
|
||||
/*{\Mtext \headerline{Update Operations}}*/
|
||||
|
||||
void clear() const
|
||||
/*{\Mop reintializes |P| to the empty map.}*/
|
||||
{ psm_->clear(); }
|
||||
|
||||
bool is_closed_at_source(Halfedge_handle e) const
|
||||
/*{\Mop returns |true| when |prev(e) == twin(e)|.}*/
|
||||
{ return previous(e) == twin(e); }
|
||||
|
||||
bool is_closed_at_target(Halfedge_handle e) const
|
||||
/*{\Mop returns |true| when |next(e) == twin(e)|.}*/
|
||||
{ return next(e) == twin(e); }
|
||||
|
||||
Halfedge_handle cas(Halfedge_handle e) const
|
||||
{ return cyclic_adj_succ(e); }
|
||||
Halfedge_handle cap(Halfedge_handle e) const
|
||||
{ return cyclic_adj_pred(e); }
|
||||
|
||||
template <class H>
|
||||
void make_twins(H h1, H h2) const
|
||||
{ h1->twin_ = h2; h2->twin_ = h1; }
|
||||
|
||||
Vertex_handle new_vertex(const Sphere_point& p) const
|
||||
/*{\Mop creates a new vertex.}*/
|
||||
{ return psm_->new_vertex(p); }
|
||||
|
||||
Halfedge_handle new_edge_pair() const
|
||||
/*{\Xop creates a new edge pair. No connectivity is provided.}*/
|
||||
{ return psm_->new_halfedge_pair(); }
|
||||
|
||||
Halfloop_handle new_loop_pair() const
|
||||
/*{\Mop creates a new loop pair.
|
||||
\precond No sloop pair exists in the local graph.}*/
|
||||
{ CGAL_assertion(!has_loop());
|
||||
return psm_->new_halfloop_pair(); }
|
||||
|
||||
Face_handle new_face() const
|
||||
/*{\Mop creates a new face.}*/
|
||||
{ return psm_->new_face(); }
|
||||
|
||||
void delete_vertex_only(Vertex_handle v) const
|
||||
/*{\Mop deletes |v| without any connectivity update.}*/
|
||||
{ return psm_->delete_vertex(v); }
|
||||
|
||||
void delete_edge_pair_only(Halfedge_handle e) const
|
||||
/*{\Mop deletes |e| and its twin without any connectivity update.}*/
|
||||
{ psm_->delete_halfedge_pair(e); }
|
||||
|
||||
void delete_halfedge_only(Halfedge_handle e) const
|
||||
/*{\Mop deletes |e| without its twin and without any connectivity update.}*/
|
||||
{ psm_->delete_halfedge(e); }
|
||||
|
||||
void delete_face_only(Face_handle f) const
|
||||
/*{\Mop deletes |f| without any connectivity update.}*/
|
||||
{ return psm_->delete_face(f); }
|
||||
|
||||
void delete_loop_only() const
|
||||
/*{\Mop deletes the loop and its twin without any connectivity update.}*/
|
||||
{ CGAL_assertion(psm_->loops_);
|
||||
psm_->delete_halfloop_pair(psm_->loops_); }
|
||||
|
||||
template <typename H>
|
||||
bool is_boundary_object(H h) const
|
||||
{ return psm_->is_boundary_object(h); }
|
||||
|
||||
template <typename H>
|
||||
void store_boundary_object(H h, Face_handle f) const
|
||||
{ f->boundary_.push_back(make_object(h));
|
||||
psm_->store_boundary_item(h, --(psm_->face_cycles_end(f)));
|
||||
}
|
||||
|
||||
template <typename H>
|
||||
void undo_boundary_object(H h, Face_handle f) const
|
||||
{ CGAL_assertion(psm_->is_boundary_object(h));
|
||||
Face_cycle_iterator it = psm_->boundary_item(h);
|
||||
psm_->undef_boundary_item(h);
|
||||
f->boundary_.erase(it);
|
||||
}
|
||||
|
||||
void link_as_face_cycle(Halfedge_handle e, Face_handle f) const
|
||||
/*{\Mop creates a new face cycle of |f| and
|
||||
makes |e| the entry point of it.}*/
|
||||
{
|
||||
Halfedge_around_face_circulator hfc(e), hend(hfc);
|
||||
CGAL_For_all(hfc,hend) hfc->face_ = f;
|
||||
store_boundary_object(e,f);
|
||||
}
|
||||
|
||||
void link_as_loop(Halfloop_handle l, Face_handle f) const
|
||||
/*{\Mop creates a new trivial face cycle of |f| and
|
||||
makes |l| the singular object of it.}*/
|
||||
{ store_boundary_object(l,f); l->face_ = f; }
|
||||
|
||||
void link_as_isolated_vertex(Vertex_handle v, Face_handle f) const
|
||||
/*{\Mop creates a new trivial face cycle of |f|.
|
||||
(makes |v| an isolated vertex within |f|).}*/
|
||||
{ store_boundary_object(v,f); v->face_ = f; }
|
||||
|
||||
void unlink_as_face_cycle(Halfedge_handle e) const
|
||||
/*{\Mop removes the face cycle defined by |e| from |face(e)|.
|
||||
Does not update the face links of the corresponding face cycle
|
||||
edges. \precond |e| is the entry object of the face cycle.}*/
|
||||
{ undo_boundary_object(e,face(e)); }
|
||||
|
||||
void unlink_as_loop(Halfloop_handle l) const
|
||||
/*{\Mop removes the trivial face cycle defined by |l| from
|
||||
|face(l)|. Does not update |l|'s face link.}*/
|
||||
{ undo_boundary_object(l,face(l)); }
|
||||
|
||||
void unlink_as_isolated_vertex(Vertex_handle v) const
|
||||
/*{\Mop removes the trivial face cycle defined by |v| from
|
||||
|face(v)|. Does not update |v|'s face link.
|
||||
\precond |v| is a trivial face cycle of |face(v)|.}*/
|
||||
{ undo_boundary_object(v,face(v)); }
|
||||
|
||||
void clear_face_cycle_entries(Face_handle f) const
|
||||
{ psm_->reset_object_list(f->boundary_);
|
||||
// removes entries of list and the hashed membership
|
||||
}
|
||||
|
||||
Halfedge_handle new_edge_pair(Vertex_handle v1,
|
||||
Vertex_handle v2) const
|
||||
/*{\Mop creates a new pair of edges |(e1,e2)| representing |(v1,v2)|
|
||||
by appending the |ei| to |A(vi)| $(i=1,2)$.}*/
|
||||
{ Halfedge_handle e1 = new_edge_pair();
|
||||
Halfedge_handle e2 = twin(e1);
|
||||
if ( ! is_isolated(v1) )
|
||||
set_adjacency_at_source_between(cap(first_out_edge(v1)),e1,
|
||||
first_out_edge(v1));
|
||||
else
|
||||
close_tip_at_source(e1,v1);
|
||||
if ( ! is_isolated(v2) )
|
||||
set_adjacency_at_source_between(cap(first_out_edge(v2)),e2,
|
||||
first_out_edge(v2));
|
||||
else
|
||||
close_tip_at_source(e2,v2);
|
||||
return e1;
|
||||
}
|
||||
|
||||
|
||||
Halfedge_handle new_edge_pair(Halfedge_handle e1,
|
||||
Halfedge_handle e2,
|
||||
int pos1 = AFTER, int pos2 = AFTER) const
|
||||
/*{\Mop creates a new pair of edges |(es1,es2)| representing the uedge
|
||||
|\{source(e1),source(e2)\}| by inserting the |esi| before or after |ei|
|
||||
into the cyclic adjacency list of |source(ei)| depending on |posi|
|
||||
$(i=1,2)$ from |\Mname::BEFORE|, |\Mname::AFTER|.}*/
|
||||
{
|
||||
Halfedge_handle er = new_edge_pair();
|
||||
Halfedge_handle ero = twin(er);
|
||||
if (pos1 < 0) { // before e1
|
||||
set_adjacency_at_source_between(cap(e1),er,e1);
|
||||
if ( e1 == first_out_edge(source(e1)) )
|
||||
set_first_out_edge(source(e1),er);
|
||||
} else { // after e1
|
||||
set_adjacency_at_source_between(e1,er,cas(e1));
|
||||
}
|
||||
if (pos2 < 0) { // before e2
|
||||
set_adjacency_at_source_between(cap(e2),ero,e2);
|
||||
if ( e2 == first_out_edge(source(e2)) )
|
||||
set_first_out_edge(source(e2),ero);
|
||||
} else { // after e2
|
||||
set_adjacency_at_source_between(e2,ero,cas(e2));
|
||||
}
|
||||
return er;
|
||||
}
|
||||
|
||||
Halfedge_handle new_edge_pair(Halfedge_handle e, Vertex_handle v,
|
||||
int pos = AFTER) const
|
||||
/*{\Mop creates a new pair of edges |(e1,e2)| representing the uedge
|
||||
|\{source(e),v\}| by inserting |e1| before or after |e| into cyclic
|
||||
adjacency list of |source(e)| depending on |pos| from |\Mname::BEFORE|,
|
||||
|\Mname::AFTER| and appending |e2| at |A(v)|.}*/
|
||||
{
|
||||
Halfedge_handle e_new = new_edge_pair();
|
||||
Halfedge_handle e_opp = twin(e_new);
|
||||
if (pos < 0) { // before e
|
||||
set_adjacency_at_source_between(cap(e),e_new,e);
|
||||
if ( e == first_out_edge(source(e)) )
|
||||
set_first_out_edge(source(e),e_new);
|
||||
} else // after e
|
||||
set_adjacency_at_source_between(e,e_new,cas(e));
|
||||
|
||||
if ( ! is_isolated(v) ) {
|
||||
Halfedge_handle e_first = first_out_edge(v);
|
||||
set_adjacency_at_source_between(cap(e_first),e_opp,e_first);
|
||||
} else
|
||||
close_tip_at_source(e_opp,v);
|
||||
return e_new;
|
||||
}
|
||||
|
||||
|
||||
Halfedge_handle new_edge_pair(Vertex_handle v, Halfedge_handle e,
|
||||
int pos = AFTER) const
|
||||
/*{\Mop symmetric to the previous one.}*/
|
||||
{ return twin(new_edge_pair(e,v,pos)); }
|
||||
|
||||
void delete_edge_pair(Halfedge_handle e) const
|
||||
/*{\Mop deletes |e| and its twin and maintains the adjacency at its source
|
||||
and its target.}*/
|
||||
{ remove_from_adj_list_at_source(e);
|
||||
remove_from_adj_list_at_source(twin(e));
|
||||
delete_edge_pair_only(e);
|
||||
}
|
||||
|
||||
void delete_vertex(Vertex_handle v) const
|
||||
/*{\Mop deletes |v| and all outgoing edges |A(v)| as well as their twins.
|
||||
Updates the adjacency at the targets of the edges in |A(v)|.}*/
|
||||
{
|
||||
if ( ! is_isolated(v) ) {
|
||||
Halfedge_handle e = first_out_edge(v);
|
||||
while ( e != cap(e) )
|
||||
delete_edge_pair(cap(e));
|
||||
delete_edge_pair(e);
|
||||
}
|
||||
delete_vertex_only(v);
|
||||
}
|
||||
|
||||
void delete_face(Face_handle f) const
|
||||
/*{\Mop deletes the face |f| without consideration of topological
|
||||
linkage.}*/
|
||||
{ clear_face_cycle_entries(f); delete_face_only(f); }
|
||||
|
||||
bool has_outdeg_two(Vertex_handle v) const
|
||||
/*{\Mop return true when |v| has outdegree two.}*/
|
||||
// does this work for looping edges?
|
||||
{ if (is_isolated(v)) return false;
|
||||
Halfedge_handle e1 = first_out_edge(v);
|
||||
Halfedge_handle e2 = last_out_edge(v);
|
||||
return (e1!=e2 && e2==cas(e1));
|
||||
}
|
||||
|
||||
void link_as_prev_next_pair(Halfedge_handle e1, Halfedge_handle e2) const
|
||||
/*{\Xop makes |e1| and |e2| adjacent in the face cycle
|
||||
$\ldots-|e1-e2|-\ldots$.
|
||||
Afterwards |e1 = previous(e2)| and |e2 = next(e1)|.}*/
|
||||
{ e1->next_ = e2; e2->prev_ = e1; }
|
||||
|
||||
void merge_edge_pairs_at_target(Halfedge_handle e) const
|
||||
/*{\Mop merges the edge pairs at |v = target(e)|. |e| and |twin(e)|
|
||||
are preserved, |next(e)|, |twin(next(e))| and |v| are deleted
|
||||
in the merger. \precond |v| has outdegree two. The adjacency at
|
||||
|source(e)| and |target(next(e))| is kept consistent.
|
||||
If |next(e)| was entry point of |face(e)| then |e| takes this role.
|
||||
The same holds for |twin(next(e))| and |face(twin(e))|.}*/
|
||||
{
|
||||
TRACEN("merge_edge_pairs_at_target "<<PH(e));
|
||||
Halfedge_handle en = next(e), eno = twin(en), enn, enno,
|
||||
eo = twin(e) ;
|
||||
if ( is_closed_at_target(en) ) { enn = eo; enno=e; }
|
||||
else { enn = next(en), enno = previous(eno); }
|
||||
Vertex_handle v = target(e), vn = target(en);
|
||||
CGAL_assertion(has_outdeg_two(v));
|
||||
Face_handle f1 = face(en), f2 = face(eno);
|
||||
// transfer the opposite face cycles e-en-enn to e-enn
|
||||
if ( enn != eno ) {
|
||||
link_as_prev_next_pair(e,enn);
|
||||
link_as_prev_next_pair(enno,eo);
|
||||
} else {
|
||||
link_as_prev_next_pair(e,eo);
|
||||
}
|
||||
// set vertex of e and deal with vertex-halfedge incidence
|
||||
eo->source_ = vn;
|
||||
|
||||
if ( first_out_edge(vn) == eno ) set_first_out_edge(vn,eo);
|
||||
if ( is_boundary_object(en) )
|
||||
{ undo_boundary_object(en,f1); store_boundary_object(e,f1); }
|
||||
if ( is_boundary_object(eno) )
|
||||
{ undo_boundary_object(eno,f2); store_boundary_object(eo,f2); }
|
||||
delete_vertex_only(v);
|
||||
delete_edge_pair_only(en);
|
||||
TRACEN("END "<<PH(previous(e))<<PH(e)<<PH(next(e)));
|
||||
}
|
||||
|
||||
void convert_edge_to_loop(Halfedge_handle e) const
|
||||
/*{\Mop converts the edge at |v = target(e)| to the unique
|
||||
loop |l| of |\Mvar|. |e|, |twin(e)| and |v| are deleted
|
||||
in the conversion. \precond there was no loop in |\Mvar|.
|
||||
As |e| was entry point of |face(e)| then |l| takes this role.}*/
|
||||
{ TRACEN("convert_edge_to_loop "<<PH(e));
|
||||
CGAL_assertion( !has_loop() );
|
||||
Halfloop_handle l = new_loop_pair();
|
||||
Vertex_handle v = target(e);
|
||||
Face_handle f1 = face(e), f2 = face(twin(e));
|
||||
CGAL_assertion( is_boundary_object(e) &&
|
||||
is_boundary_object(twin(e)) );
|
||||
undo_boundary_object(e,f1); undo_boundary_object(twin(e),f2);
|
||||
link_as_loop(l,f1), link_as_loop(twin(l),f2);
|
||||
circle(l) = circle(e); circle(twin(l)) = circle(twin(e));
|
||||
mark(l) = mark(e);
|
||||
delete_vertex_only(v);
|
||||
delete_edge_pair_only(e);
|
||||
}
|
||||
|
||||
void flip_diagonal(Halfedge_handle e) const
|
||||
{ Halfedge_handle r = twin(e);
|
||||
Halfedge_handle en = next(e), enn= next(en);
|
||||
Halfedge_handle rn = next(r), rnn= next(rn);
|
||||
TRACEN(PH(e)<<PH(en)<<PH(enn));
|
||||
TRACEN(PH(r)<<PH(rn)<<PH(rnn));
|
||||
CGAL_assertion( next(enn)==e && next(rnn)==r );
|
||||
remove_from_adj_list_at_source(e);
|
||||
remove_from_adj_list_at_source(r);
|
||||
set_adjacency_at_source_between(enn,e,twin(en));
|
||||
set_adjacency_at_source_between(rnn,r,twin(rn));
|
||||
}
|
||||
|
||||
|
||||
/*{\Mtext \headerline{Incomplete topological update primitives}}*/
|
||||
|
||||
Halfedge_handle new_edge_pair_at_source
|
||||
(Halfedge_handle e, int pos = AFTER) const
|
||||
/*{\Xop creates a new pair of edges |(e1,e2)| representing |(source(e),())|
|
||||
by inserting |e1| before or after |e| into cyclic adjacency list of
|
||||
|source(e)| depending on |pos| from |\Mname::BEFORE, \Mname::AFTER|.}*/
|
||||
{ Halfedge_handle e_new = new_edge_pair();
|
||||
if (pos < 0) set_adjacency_at_source_between(cap(e),e_new,e);
|
||||
else set_adjacency_at_source_between(e,e_new,cas(e));
|
||||
return e_new;
|
||||
}
|
||||
|
||||
Halfedge_handle new_edge_pair_at_source
|
||||
(Vertex_handle v, int pos = AFTER) const
|
||||
/*{\Mop creates a new pair of edges |(e1,e2)| representing |(v,())|
|
||||
by inserting |e1| at the beginning (BEFORE) or end (AFTER)
|
||||
of adjacency list of |v|.}*/
|
||||
{ Halfedge_handle e1 = new_edge_pair();
|
||||
if ( ! is_isolated(v) ) {
|
||||
Halfedge_handle ef = first_out_edge(v);
|
||||
if (pos < 0) { // before e1
|
||||
set_adjacency_at_source_between(cap(ef),e1,ef);
|
||||
set_first_out_edge(v,e1);
|
||||
} else {
|
||||
set_adjacency_at_source_between(ef,e1,cas(ef));
|
||||
}
|
||||
} else
|
||||
close_tip_at_source(e1,v);
|
||||
return e1;
|
||||
}
|
||||
|
||||
void delete_edge_pair_at_source(Halfedge_handle e) const
|
||||
/*{\Mop deletes |e| and its twin and maintains the adjacency at its
|
||||
source.}*/
|
||||
{ remove_from_adj_list_at_source(e);
|
||||
delete_edge_pair_only(e);
|
||||
}
|
||||
|
||||
void link_as_target_and_append(Vertex_handle v, Halfedge_handle e) const
|
||||
/*{\Mop makes |v| the target of |e| appends |twin(e)| to the adjacency list
|
||||
of |v|.}*/
|
||||
{ if ( !is_isolated(v) )
|
||||
set_adjacency_at_source_between(cap(first_out_edge(v)),twin(e),
|
||||
first_out_edge(v));
|
||||
else
|
||||
close_tip_at_target(e,v);
|
||||
}
|
||||
|
||||
void link_as_source_of(Halfedge_handle e, Vertex_handle v) const
|
||||
/*{\Mop makes |source(e) = v| and sets |e| as the first
|
||||
out edge if |v| was isolated before.}*/
|
||||
{ e->source_ = v;
|
||||
if (v->edge_ == Halfedge_handle()) v->edge_ = e; }
|
||||
|
||||
void link_as_target_of(Halfedge_handle e, Vertex_handle v) const
|
||||
/*{\Mop makes |target(e) = v| and sets |e| as the first
|
||||
in edge if |v| was isolated before.}*/
|
||||
{ link_as_source_of(twin(e),v); }
|
||||
|
||||
void set_adjacency_at_source_between(Halfedge_handle e, Halfedge_handle en)
|
||||
const
|
||||
/*{\Mop makes |e| and |en| neigbors in the cyclic ordered adjacency list
|
||||
around |v=source(e)|. \precond |source(e)==source(en)|.}*/
|
||||
{ CGAL_assertion(source(e)==source(en));
|
||||
link_as_prev_next_pair(twin(en),e);
|
||||
}
|
||||
|
||||
void set_adjacency_at_source_between(Halfedge_handle e1,
|
||||
Halfedge_handle e_between,
|
||||
Halfedge_handle e2) const
|
||||
/*{\Mop inserts |e_between| into the adjacency list around |source(e1)|
|
||||
between |e1| and |e2| and makes |source(e1)| the source of |e_between|.
|
||||
\precond |source(e1)==source(e2)|.}*/
|
||||
{
|
||||
e_between->source_ = source(e1);
|
||||
set_adjacency_at_source_between(e1,e_between);
|
||||
set_adjacency_at_source_between(e_between,e2);
|
||||
}
|
||||
|
||||
void close_tip_at_source(Halfedge_handle e, Vertex_handle v) const
|
||||
/*{\Mop sets |v| as source of |e| and closes the tip by setting the
|
||||
corresponding pointers such that |prev(e) == twin(e)| and
|
||||
|next(twin(e)) == e|.}*/
|
||||
{ link_as_source_of(e,v);
|
||||
link_as_prev_next_pair(twin(e),e); }
|
||||
|
||||
void close_tip_at_target(Halfedge_handle e, Vertex_handle v) const
|
||||
/*{\Mop sets |v| as target of |e| and closes the tip by setting the
|
||||
corresponding pointers such that |prev(twin(e)) == e| and
|
||||
|next(e) == twin(e)|.}*/
|
||||
{ link_as_target_of(e,v);
|
||||
link_as_prev_next_pair(e,twin(e)); }
|
||||
|
||||
|
||||
void remove_from_adj_list_at_source(Halfedge_handle e) const
|
||||
/*{\Mop removes a halfedge pair |(e,twin(e)| from the adjacency list
|
||||
of |source(e)|. Afterwards |next(prev(e))==next(twin(e))| and
|
||||
|first_out_edge(source(e))| is valid if |degree(source(v))>1| before
|
||||
the operation.}*/
|
||||
{
|
||||
Vertex_handle v = source(e);
|
||||
if ( is_closed_at_source(e) ) { // last outgoing
|
||||
v->edge_ = Halfedge_handle();
|
||||
} else {
|
||||
if (e == first_out_edge(v)) v->edge_ = cap(e);
|
||||
set_adjacency_at_source_between(cap(e),cas(e));
|
||||
}
|
||||
}
|
||||
|
||||
void set_face(Halfedge_handle e, Face_handle f) const
|
||||
{ e->face_ = f; }
|
||||
void set_face(Vertex_handle v, Face_handle f) const
|
||||
{ v->face_ = f; }
|
||||
void set_first_out_edge(Vertex_handle v, Halfedge_handle e) const
|
||||
{ v->edge_ = e; }
|
||||
void set_prev(Halfedge_handle e, Halfedge_handle ep) const
|
||||
{ e->prev_ = ep; }
|
||||
void set_next(Halfedge_handle e, Halfedge_handle en) const
|
||||
{ e->next_ = en; }
|
||||
void set_source(Halfedge_handle e, Vertex_handle v) const
|
||||
{ e->source_ = v; }
|
||||
|
||||
|
||||
|
||||
/*{\Mtext \headerline{Associated Information}\restoreopdims}*/
|
||||
|
||||
Sphere_point& point(Vertex_handle v) const
|
||||
/*{\Mop returns the embedding of |v|.}*/
|
||||
{ return v->point_; }
|
||||
|
||||
Sphere_circle& circle(Halfedge_handle e) const
|
||||
/*{\Mop returns the plane supporting |e|.}*/
|
||||
{ return e->circle_; }
|
||||
|
||||
Sphere_circle& circle(Halfloop_handle l) const
|
||||
/*{\Mop returns the plane supporting |e|.}*/
|
||||
{ return l->circle_; }
|
||||
|
||||
Mark& mark(Vertex_handle v) const
|
||||
/*{\Mop returns the mark of |v|.}*/
|
||||
{ return v->mark_; }
|
||||
|
||||
Mark& mark(Halfedge_handle e) const
|
||||
/*{\Mop returns the mark of |e|.}*/
|
||||
{ return ( &*e < &*twin(e) ) ? e->mark_ : twin(e)->mark_; }
|
||||
|
||||
Mark& mark(Halfloop_handle l) const
|
||||
/*{\Mop returns the mark of |l|.}*/
|
||||
{ return ( &*l < &*twin(l) ) ? l->mark_ : twin(l)->mark_; }
|
||||
|
||||
Mark& mark(Face_handle f) const
|
||||
/*{\Mop returns the mark of |f|.}*/
|
||||
{ return f->mark_; }
|
||||
|
||||
void unify_marks(Halfedge_handle e) const
|
||||
{ if ( &*e < &*twin(e) ) twin(e)->mark_ = e->mark_;
|
||||
else e->mark_ = twin(e)->mark_;
|
||||
}
|
||||
|
||||
const Sphere_point& point(Vertex_const_handle v) const
|
||||
{ return v->point_; }
|
||||
const Sphere_circle& circle(Halfedge_const_handle e) const
|
||||
{ return e->circle_; }
|
||||
const Sphere_circle& circle(Halfloop_const_handle l) const
|
||||
{ return l->circle_; }
|
||||
|
||||
const Mark& mark(Vertex_const_handle v) const
|
||||
{ return v->mark_; }
|
||||
const Mark& mark(Halfedge_const_handle e) const
|
||||
{ return ( &*e < &*twin(e) ) ? e->mark_ : twin(e)->mark_; }
|
||||
const Mark& mark(Halfloop_const_handle l) const
|
||||
{ return ( &*l < &*twin(l) ) ? l->mark_ : twin(l)->mark_; }
|
||||
const Mark& mark(Face_const_handle f) const
|
||||
{ return f->mark_; }
|
||||
|
||||
void unify_tmp_marks(Halfedge_handle e) const
|
||||
{ if (&*e < &*twin(e)) twin(e)->mark_ = e->mark_;
|
||||
else e->mark_ = twin(e)->mark_; }
|
||||
|
||||
void set_marks_in_face_cycle(Halfedge_handle e, Mark m) const
|
||||
{ Halfedge_around_face_circulator hfc(e), hend(hfc);
|
||||
CGAL_For_all(hfc,hend) mark(hfc) = mark(target(hfc)) = m;
|
||||
}
|
||||
|
||||
Mark& mark_of_halfsphere(int i) const
|
||||
{ CGAL_assertion(i);
|
||||
if (i<0) return psm_->m_neg_;
|
||||
return psm_->m_pos_; }
|
||||
|
||||
GenPtr& info(Vertex_handle v) const
|
||||
{ return v->info_; }
|
||||
GenPtr& info(Halfedge_handle e) const
|
||||
{ return e->info_; }
|
||||
GenPtr& info(Halfloop_handle l) const
|
||||
{ return l->info_; }
|
||||
GenPtr& info(Face_handle f) const
|
||||
{ return f->info_; }
|
||||
|
||||
const GenPtr& info(Vertex_const_handle v) const
|
||||
{ return v->info_; }
|
||||
const GenPtr& info(Halfedge_const_handle e) const
|
||||
{ return e->info_; }
|
||||
const GenPtr& info(Halfloop_const_handle l) const
|
||||
{ return l->info_; }
|
||||
const GenPtr& info(Face_const_handle f) const
|
||||
{ return f->info_; }
|
||||
|
||||
|
||||
/*{\Mtext \headerline{Iteration}}*/
|
||||
/*{\Mtext The list of all objects can be accessed via iterator ranges.
|
||||
For comfortable iteration we also provide iterations macros.
|
||||
The iterator range access operations are of the following kind:\\
|
||||
|Vertex_iterator vertices_begin()/vertices_end()|\\
|
||||
|Halfedge_iterator edges_begin()/edges_end()|\\
|
||||
|Face_iterator faces_begin()/faces_end()|
|
||||
|
||||
The macros are then |CGAL_forall_vertices_of(v,V)|,
|
||||
|CGAL_forall_edges_of(e,V)|, |CGAL_forall_faces_of(f,V)|,
|
||||
|CGAL_forall_face_cycles_of(fc,F)| where |V| is the center vertex of
|
||||
the local graph and |F| any face.}*/
|
||||
|
||||
|
||||
}; // SM_decorator
|
||||
|
||||
|
||||
CGAL_END_NAMESPACE
|
||||
#endif // CGAL_SM_DECORATOR_H
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,466 @@
|
|||
#ifndef CGAL_SM_IO_PARSER_H
|
||||
#define CGAL_SM_IO_PARSER_H
|
||||
|
||||
#include <CGAL/Nef_S2/SM_decorator.h>
|
||||
#include <CGAL/Nef_2/Object_index.h>
|
||||
#include <vector>
|
||||
|
||||
CGAL_BEGIN_NAMESPACE
|
||||
|
||||
/*{\Moptions outfile=SM_io_parser.man }*/
|
||||
/*{\Manpage {SM_io_parser}{Decorator_}{IO of embedded maps}{IO}}*/
|
||||
|
||||
/*{\Mdefinition An instance |\Mvar| of the data type |\Mname| is a
|
||||
decorator to provide input and output of a embedded map. |\Mtype| is
|
||||
generic with respect to the |Decorator_| parameter. |Decorator_| has
|
||||
to be a decorator model of our |SM_decorator| concept.}*/
|
||||
|
||||
/*{\Mgeneralization SM_decorator}*/
|
||||
|
||||
template <typename Decorator_>
|
||||
class SM_io_parser : public Decorator_
|
||||
{
|
||||
typedef Decorator_ Base;
|
||||
typedef typename Decorator_::Sphere_point Sphere_point;
|
||||
typedef typename Decorator_::Sphere_circle Sphere_circle;
|
||||
typedef typename Decorator_::Mark Mark;
|
||||
|
||||
typedef typename Decorator_::Vertex_iterator Vertex_iterator;
|
||||
typedef typename Decorator_::Halfedge_iterator Halfedge_iterator;
|
||||
typedef typename Decorator_::Face_iterator Face_iterator;
|
||||
typedef typename Decorator_::Vertex_handle Vertex_handle;
|
||||
typedef typename Decorator_::Halfedge_handle Halfedge_handle;
|
||||
typedef typename Decorator_::Face_handle Face_handle;
|
||||
typedef typename Decorator_::Halfloop_handle Halfloop_handle;
|
||||
typedef typename Decorator_::Face_cycle_iterator Face_cycle_iterator;
|
||||
std::istream& in; std::ostream& out;
|
||||
bool verbose;
|
||||
// a reference to the IO object
|
||||
CGAL::Object_index<Vertex_handle> VI;
|
||||
CGAL::Object_index<Halfedge_handle> EI;
|
||||
CGAL::Object_index<Face_handle> FI;
|
||||
std::vector<Vertex_handle> Vertex_of;
|
||||
std::vector<Halfedge_handle> Edge_of;
|
||||
std::vector<Face_handle> Face_of;
|
||||
Halfloop_handle Loop_of[2];
|
||||
// object mapping for input
|
||||
int vn,en,ln,fn,i;
|
||||
// the number of objects
|
||||
|
||||
bool check_sep(char* sep);
|
||||
void print_vertex(Vertex_handle) const;
|
||||
void print_edge(Halfedge_handle) const;
|
||||
void print_loop(Halfloop_handle) const;
|
||||
void print_face(Face_handle) const;
|
||||
void print_init_points() const;
|
||||
|
||||
bool read_vertex(Vertex_handle);
|
||||
bool read_edge(Halfedge_handle);
|
||||
bool read_loop(Halfloop_handle);
|
||||
bool read_face(Face_handle);
|
||||
bool read_init_points() const;
|
||||
|
||||
void debug_vertex(Vertex_handle) const;
|
||||
void debug_edge(Halfedge_handle) const;
|
||||
void debug_loop(Halfloop_handle) const;
|
||||
|
||||
public:
|
||||
/*{\Mcreation 3}*/
|
||||
SM_io_parser(istream& is, const Base& D);
|
||||
/*{\Mcreate creates an instance |\Mvar| of type |\Mname|
|
||||
to input |H| from |is|.}*/
|
||||
|
||||
SM_io_parser(ostream& os, const Base& D);
|
||||
/*{\Mcreate creates an instance |\Mvar| of type |\Mname|
|
||||
to output |H| to |os|.}*/
|
||||
|
||||
/*{\Moperations 2 3}*/
|
||||
void print() const;
|
||||
/*{\Mop prints |H| to |os|.}*/
|
||||
void read();
|
||||
/*{\Mop reads |H| from |is|.}*/
|
||||
void debug() const;
|
||||
void print_faces() const;
|
||||
|
||||
std::string index(Vertex_handle v) const
|
||||
{ return VI(v,verbose); }
|
||||
std::string index(Halfedge_handle e) const
|
||||
{ return EI(e,verbose); }
|
||||
std::string index(Halfloop_handle l) const
|
||||
{ if (verbose) return (l==halfloop()? "l0" : "l1");
|
||||
else return (l==halfloop()? "0" : "1");
|
||||
}
|
||||
std::string index(Face_handle f) const
|
||||
{ return FI(f,verbose); }
|
||||
|
||||
static void dump(const Decorator_& D, std::ostream& os = cerr);
|
||||
/*{\Mstatic prints the plane map decorated by |D| to |os|.}*/
|
||||
|
||||
}; // SM_io_parser<Decorator_>
|
||||
|
||||
|
||||
template <typename Decorator_>
|
||||
SM_io_parser<Decorator_>::
|
||||
SM_io_parser(istream& iin, const Decorator_& H) :
|
||||
Base(H), in(iin), out(std::cout), verbose(0),
|
||||
vn(0), en(0), fn(0), ln(0)
|
||||
{ clear(); }
|
||||
|
||||
template <typename Decorator_>
|
||||
SM_io_parser<Decorator_>::
|
||||
SM_io_parser(std::ostream& iout, const Decorator_& D)
|
||||
: Base(D), in(std::cin), out(iout),
|
||||
VI(vertices_begin(),vertices_end(),'v'),
|
||||
EI(halfedges_begin(),halfedges_end(),'e'),
|
||||
FI(faces_begin(),faces_end(),'f'),
|
||||
vn(number_of_vertices()),
|
||||
en(number_of_halfedges()),
|
||||
ln(number_of_halfloops()),
|
||||
fn(number_of_faces())
|
||||
{ verbose = (out.iword(CGAL::IO::mode) != CGAL::IO::ASCII &&
|
||||
out.iword(CGAL::IO::mode) != CGAL::IO::BINARY);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// OUTPUT AND INPUT:
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
template <typename Decorator_>
|
||||
bool SM_io_parser<Decorator_>::check_sep(char* sep)
|
||||
{
|
||||
char c;
|
||||
do in.get(c); while (isspace(c));
|
||||
while (*sep != '\0') {
|
||||
if (*sep != c) {
|
||||
in.putback(c);
|
||||
return false;
|
||||
}
|
||||
++sep; in.get(c);
|
||||
}
|
||||
in.putback(c);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Decorator_>
|
||||
void SM_io_parser<Decorator_>::print_vertex(Vertex_handle v) const
|
||||
{
|
||||
// syntax: index { isolated incident_object, mark, point }
|
||||
out << index(v) << " { ";
|
||||
if ( is_isolated(v) ) out << "1 " << index(face(v));
|
||||
else out << "0 " << index(first_out_edge(v));
|
||||
out << ", " << mark(v) << ", " << point(v) << "}\n";
|
||||
}
|
||||
|
||||
template <typename Decorator_>
|
||||
bool SM_io_parser<Decorator_>::read_vertex(Vertex_handle v)
|
||||
{
|
||||
// precondition: nodes exist
|
||||
// syntax: index { isolated incident_object, mark, point}
|
||||
int n; bool iso; int f; Mark m; Sphere_point p;
|
||||
if ( !(in >> n) ||
|
||||
!check_sep("{") ||
|
||||
!(in >> iso) ||
|
||||
!(in >> f) ||
|
||||
!check_sep(",") ||
|
||||
!(in >> m) ||
|
||||
!check_sep(",") ||
|
||||
!(in >> p) ||
|
||||
!check_sep("}") ) return false;
|
||||
|
||||
if (iso) set_face(v,Face_of[f]);
|
||||
else set_first_out_edge(v,Edge_of[f]);
|
||||
mark(v) = m; point(v) = p;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Decorator_>
|
||||
void SM_io_parser<Decorator_>::print_edge(Halfedge_handle e) const
|
||||
{ // syntax: index { twin, prev, next, source, face, mark, circle }
|
||||
out << index(e) << " { "
|
||||
<< index(twin(e)) << ", "
|
||||
<< index(previous(e)) << ", " << index(next(e)) << ", "
|
||||
<< index(source(e)) << ", " << index(face(e)) << ", "
|
||||
<< mark(e) << ", " << circle(e) << " }\n";
|
||||
}
|
||||
|
||||
template <typename Decorator_>
|
||||
bool SM_io_parser<Decorator_>::read_edge(Halfedge_handle e)
|
||||
{ // syntax: index { twin, prev, next, source, face, mark }
|
||||
int n, eo, epr, ene, v, f; bool m; Sphere_circle k;
|
||||
if ( !(in >> n) ||
|
||||
!check_sep("{") ||
|
||||
!(in >> eo) || !check_sep(",") ||
|
||||
!(in >> epr) || !check_sep(",") ||
|
||||
!(in >> ene) || !check_sep(",") ||
|
||||
!(in >> v) || !check_sep(",") ||
|
||||
!(in >> f) || !check_sep(",") ||
|
||||
!(in >> m) || !check_sep(",") ||
|
||||
!(in >> k) || !check_sep("}") )
|
||||
return false;
|
||||
CGAL_assertion_msg
|
||||
(eo >= 0 && eo < en && epr >= 0 && epr < en && ene >= 0 && ene < en &&
|
||||
v >= 0 && v < vn && f >= 0 && f < fn ,
|
||||
"wrong index in read_edge");
|
||||
|
||||
// precond: features exist!
|
||||
CGAL_assertion(EI[twin(e)]);
|
||||
set_prev(e,Edge_of[epr]);
|
||||
set_next(e,Edge_of[ene]);
|
||||
set_source(e,Vertex_of[v]);
|
||||
set_face(e,Face_of[f]);
|
||||
mark(e) = m;
|
||||
circle(e) = k;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Decorator_>
|
||||
void SM_io_parser<Decorator_>::print_loop(Halfloop_handle l) const
|
||||
{ // syntax: index { twin, face, mark }
|
||||
out << index(l) << " { "
|
||||
<< index(twin(l)) << ", "
|
||||
<< index(face(l)) << ", "
|
||||
<< mark(l) << ", " << circle(l) << " }\n";
|
||||
}
|
||||
|
||||
template <typename Decorator_>
|
||||
bool SM_io_parser<Decorator_>::read_loop(Halfloop_handle l)
|
||||
{ // syntax: index { twin, face, mark }
|
||||
int n, lo, f; bool m; Sphere_circle k;
|
||||
if ( !(in >> n) ||
|
||||
!check_sep("{") ||
|
||||
!(in >> lo) || !check_sep(",") ||
|
||||
!(in >> f) || !check_sep(",") ||
|
||||
!(in >> m) || !check_sep(",") ||
|
||||
!(in >> k) || !check_sep("}") )
|
||||
return false;
|
||||
CGAL_assertion_msg(
|
||||
(lo >= 0 && lo < 2 && f >= 0 && f < fn),"wrong index in read_edge");
|
||||
|
||||
set_face(l,Face_of[f]);
|
||||
mark(l) = m;
|
||||
circle(l) = k;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
template <typename Decorator_>
|
||||
void SM_io_parser<Decorator_>::print_face(Face_handle f) const
|
||||
{ // syntax: index { fclist, ivlist, loop, mark }
|
||||
out << index(f) << " { ";
|
||||
Face_cycle_iterator it;
|
||||
Halfedge_handle e; Vertex_handle v; Halfloop_handle l;
|
||||
CGAL_forall_face_cycles_of(it,f)
|
||||
if ( assign(e,it) ) out << index(e) << ' ';
|
||||
out << ", ";
|
||||
CGAL_forall_face_cycles_of(it,f)
|
||||
if ( assign(v,it) ) out << index(v) << ' ';
|
||||
out << ", ";
|
||||
CGAL_forall_face_cycles_of(it,f)
|
||||
if ( assign(l,it) ) out << index(l);
|
||||
out << ", " << mark(f) << " }\n";
|
||||
}
|
||||
|
||||
template <typename Decorator_>
|
||||
void SM_io_parser<Decorator_>::print_init_points() const
|
||||
{
|
||||
out << mark_of_halfsphere(-1) << " "
|
||||
<< mark_of_halfsphere(+1) << "\n";
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <typename Decorator_>
|
||||
bool SM_io_parser<Decorator_>::read_face(Face_handle f)
|
||||
{ // syntax: index { fclist, ivlist, loop, mark }
|
||||
int n, ei, vi, li; Mark m;
|
||||
if ( !(in >> n) || !check_sep("{") ) return false;
|
||||
while (in >> ei) {
|
||||
CGAL_assertion_msg(ei >= 0 && ei < en, "wrong index in face cycle list.");
|
||||
store_boundary_object(Edge_of[ei],f);
|
||||
} in.clear();
|
||||
if (!check_sep(",")) { return false; }
|
||||
while (in >> vi) {
|
||||
CGAL_assertion_msg(vi >= 0 && vi < vn, "wrong index in iso vertex list.");
|
||||
store_boundary_object(Vertex_of[vi],f);
|
||||
} in.clear();
|
||||
if (!check_sep(",")) { return false; }
|
||||
while (in >> li) {
|
||||
CGAL_assertion_msg(li >= 0 && li < 2, "wrong index in iso vertex list.");
|
||||
store_boundary_object(Loop_of[li],f);
|
||||
} in.clear();
|
||||
if (!check_sep(",") || !(in >> m) || !check_sep("}") )
|
||||
return false;
|
||||
mark(f) = m;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Decorator_>
|
||||
bool SM_io_parser<Decorator_>::read_init_points() const
|
||||
{ Mark m_neg, m_pos;
|
||||
if ( ! (in >> m_neg >> m_pos) ) return false;
|
||||
mark_of_halfsphere(-1) = m_neg;
|
||||
mark_of_halfsphere(+1) = m_pos;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <typename Decorator_>
|
||||
void SM_io_parser<Decorator_>::print() const
|
||||
{
|
||||
out << "Sphere_map_2" << endl;
|
||||
out << "vertices " << vn << endl;
|
||||
out << "edges " << en << endl;
|
||||
out << "loops " << ln << endl;
|
||||
out << "faces " << fn << endl;
|
||||
if (verbose)
|
||||
out << "/* index { isolated ? face : edge, mark, point } */" << endl;
|
||||
Vertex_iterator vit;
|
||||
CGAL_forall_vertices(vit,*this) print_vertex(vit);
|
||||
if (verbose)
|
||||
out << "/* index { twin, prev, next, source, face, mark } */" << endl;
|
||||
Halfedge_iterator eit;
|
||||
CGAL_forall_halfedges(eit,*this) print_edge(eit);
|
||||
if (verbose)
|
||||
out << "/* index { twin, face, mark } */" << endl;
|
||||
if ( has_loop() )
|
||||
{ print_loop(halfloop()); print_loop(twin(halfloop())); }
|
||||
if (verbose)
|
||||
out << "/* index { fclist, ivlist, loop, mark } */" << endl;
|
||||
Face_iterator fit;
|
||||
CGAL_forall_faces(fit,*this) print_face(fit);
|
||||
if (verbose)
|
||||
out << "/* mark at y-/y+ */" << endl;
|
||||
print_init_points();
|
||||
out.flush();
|
||||
if (verbose) debug();
|
||||
}
|
||||
|
||||
template <typename Decorator_>
|
||||
void SM_io_parser<Decorator_>::read()
|
||||
{
|
||||
if ( !check_sep("Plane_map_2") )
|
||||
CGAL_assertion_msg(0,"SM_io_parser::read: no embedded_PM header.");
|
||||
if ( !(check_sep("vertices") && (in >> vn)) )
|
||||
CGAL_assertion_msg(0,"SM_io_parser::read: wrong vertex line.");
|
||||
if ( !(check_sep("edges") && (in >> en) && (en%2==0)) )
|
||||
CGAL_assertion_msg(0,"SM_io_parser::read: wrong edge line.");
|
||||
if ( !(check_sep("loops") && (in >> ln)) )
|
||||
CGAL_assertion_msg(0,"SM_io_parser::read: wrong loop line.");
|
||||
if ( !(check_sep("faces") && (in >> fn)) )
|
||||
CGAL_assertion_msg(0,"SM_io_parser::read: wrong face line.");
|
||||
|
||||
Vertex_of.reserve(vn);
|
||||
Edge_of.reserve(en);
|
||||
Face_of.reserve(fn);
|
||||
for(i=0; i<vn; i++) Vertex_of[i] = new_vertex();
|
||||
for(i=0; i<en; i++)
|
||||
if (i%2==0) Edge_of[i] = new_edge_pair_without_vertices();
|
||||
else Edge_of[i] = twin(Edge_of[i-1]);
|
||||
for(i=0; i<fn; i++) Face_of[i] = new_face();
|
||||
if ( ln == 2 )
|
||||
{ Loop_of[0] = new_loop(); Loop_of[1] = twin(loop()); }
|
||||
|
||||
for(i=0; i<vn; i++) {
|
||||
if (!read_vertex(Vertex_of[i]))
|
||||
CGAL_assertion_msg(0,"SM_io_parser::read: error in node line");
|
||||
}
|
||||
for(i=0; i<en; i++) {
|
||||
if (!read_edge(Edge_of[i]))
|
||||
CGAL_assertion_msg(0,"SM_io_parser::read: error in edge line");
|
||||
}
|
||||
if ( ln == 2 ) {
|
||||
read_loop(Loop_of[0]); read_loop(Loop_of[1]);
|
||||
}
|
||||
for(i=0; i<fn; i++) {
|
||||
if (!read_face(Face_of[i]))
|
||||
CGAL_assertion_msg(0,"SM_io_parser::read: error in face line");
|
||||
}
|
||||
if (!read_init_points())
|
||||
CGAL_assertion_msg(0,"SM_io_parser::read: error in init point line");
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// VERBOSE OUTPUT:
|
||||
// note that we output the index of the objects which is stored in them
|
||||
// this is NOT the member index as produced by the forall loops
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
template <typename Decorator_>
|
||||
void SM_io_parser<Decorator_>::debug_vertex(Vertex_handle v) const
|
||||
{
|
||||
out << index(v) << "[" << mark(v) << "," << point(v) << "]" << endl;
|
||||
}
|
||||
|
||||
template <typename Decorator_>
|
||||
void SM_io_parser<Decorator_>::debug_edge(Halfedge_handle e) const
|
||||
{
|
||||
out << index(e)
|
||||
<< "(" << index(source(e)) << "," << index(target(e)) << ") "
|
||||
<< index(twin(e)) << " " << index(face(e))
|
||||
<< " ["<< mark(e) << "," << circle(e) << "] " << endl;
|
||||
}
|
||||
|
||||
template <typename Decorator_>
|
||||
void SM_io_parser<Decorator_>::debug_loop(Halfloop_handle l) const
|
||||
{
|
||||
out << index(l) << " "
|
||||
<< index(twin(l)) << " " << index(face(l))
|
||||
<< " ["<< mark(l) << "] " << circle(l) << endl;
|
||||
}
|
||||
|
||||
|
||||
template <typename Decorator_>
|
||||
void SM_io_parser<Decorator_>::debug() const
|
||||
{
|
||||
out << "\nDEBUG Plane_map\n";
|
||||
out << "Vertices: " << number_of_vertices() << "\n";
|
||||
out << "Halfedges: " << number_of_halfedges() << "\n";
|
||||
out << "Loop: " << number_of_halfloops() << "\n";
|
||||
Vertex_iterator vit;
|
||||
CGAL_forall_vertices(vit,*this) {
|
||||
if ( is_isolated(vit) ) continue;
|
||||
typename Base::Halfedge_around_vertex_circulator
|
||||
hcirc = out_edges(vit), hend = hcirc;
|
||||
debug_vertex(vit);
|
||||
CGAL_For_all(hcirc,hend) { out << " "; debug_edge(hcirc); }
|
||||
}
|
||||
if ( has_loop() )
|
||||
{ debug_loop(halfloop()); debug_loop(twin(halfloop())); }
|
||||
out << std::endl;
|
||||
}
|
||||
|
||||
template <typename Decorator_>
|
||||
void SM_io_parser<Decorator_>::print_faces() const
|
||||
{
|
||||
out << "\nFACES\n";
|
||||
out << "Vertices: " << number_of_vertices() << "\n";
|
||||
out << "Halfedges: " << number_of_halfedges() << "\n";
|
||||
out << "Loop: " << number_of_halfloops() << "\n";
|
||||
Halfedge_iterator e;
|
||||
Unique_hash_map<Halfedge_iterator,bool> Done(false);
|
||||
CGAL_forall_halfedges(e,*this) {
|
||||
if ( Done[e] ) continue;
|
||||
typename Base::Halfedge_around_face_circulator c(e), ce = c;
|
||||
out << "face cycle\n";
|
||||
CGAL_For_all(c,ce)
|
||||
{ Done[c]=true; out << " "; debug_vertex(source(c)); }
|
||||
}
|
||||
if ( has_loop() )
|
||||
{ debug_loop(halfloop()); debug_loop(twin(halfloop())); }
|
||||
out << std::endl;
|
||||
}
|
||||
|
||||
template <typename Decorator_>
|
||||
void SM_io_parser<Decorator_>::dump(const Decorator_& D, std::ostream& os)
|
||||
{ SM_io_parser<Decorator_> Out(os,D);
|
||||
Out.print();
|
||||
Out.print_faces();
|
||||
}
|
||||
|
||||
|
||||
|
||||
CGAL_END_NAMESPACE
|
||||
#endif //CGAL_SM_IO_PARSER_H
|
||||
|
||||
|
|
@ -0,0 +1,251 @@
|
|||
#ifndef CGAL_SM_ITEMS_H
|
||||
#define CGAL_SM_ITEMS_H
|
||||
|
||||
#include <CGAL/basic.h>
|
||||
#include <CGAL/In_place_list.h>
|
||||
#include <CGAL/Object.h>
|
||||
#include <string>
|
||||
#include <strstream>
|
||||
|
||||
CGAL_BEGIN_NAMESPACE
|
||||
|
||||
template <typename K, typename M> class SM_items;
|
||||
template <typename K> class Sphere_map;
|
||||
template <typename SM, typename K> class SM_const_decorator;
|
||||
template <typename SM, typename K> class SM_decorator;
|
||||
template <typename EH> struct move_edge_around_vertex;
|
||||
template <typename EH> struct move_edge_around_face;
|
||||
|
||||
template <typename Kernel_, typename Mark_>
|
||||
struct SM_items {
|
||||
public:
|
||||
typedef Kernel_ Kernel;
|
||||
typedef typename Kernel::Sphere_point Sphere_point;
|
||||
typedef typename Kernel::Sphere_segment Sphere_segment;
|
||||
typedef typename Kernel::Sphere_circle Sphere_circle;
|
||||
typedef Mark_ Mark;
|
||||
typedef SM_items<Kernel_,Mark_> Self;
|
||||
typedef void* GenPtr;
|
||||
|
||||
template <typename Refs>
|
||||
class Vertex : public CGAL::In_place_list_base< Vertex<Refs> >
|
||||
{
|
||||
typedef typename Refs::Items Items;
|
||||
friend class Sphere_map<Kernel_>;
|
||||
friend class SM_const_decorator<Refs,Kernel_>;
|
||||
friend class SM_decorator<Refs,Kernel_>;
|
||||
|
||||
typedef typename Refs::Vertex_handle Vertex_handle;
|
||||
typedef typename Refs::Halfedge_handle Halfedge_handle;
|
||||
typedef typename Refs::Face_handle Face_handle;
|
||||
|
||||
Sphere_point point_;
|
||||
Mark mark_;
|
||||
Halfedge_handle edge_;
|
||||
Face_handle face_;
|
||||
GenPtr info_;
|
||||
// temporary information:
|
||||
|
||||
public:
|
||||
Vertex() :
|
||||
point_(), mark_(), edge_(), face_(), info_() {}
|
||||
Vertex(const Mark& m) :
|
||||
point_(), mark_(m), edge_(), face_(), info_() {}
|
||||
Vertex(const Sphere_point& p) :
|
||||
point_(p), mark_(), edge_(), face_(), info_() {}
|
||||
|
||||
~Vertex() {}
|
||||
|
||||
Vertex(const Vertex<Refs>& v)
|
||||
{ point_ = v.point_;
|
||||
mark_ = v.mark_;
|
||||
edge_ = v.edge_;
|
||||
face_ = v.face_;
|
||||
info_ = 0;
|
||||
}
|
||||
|
||||
Vertex<Refs>& operator=(const Vertex<Refs>& v)
|
||||
{ point_ = v.point_;
|
||||
mark_ = v.mark_;
|
||||
edge_ = v.edge_;
|
||||
face_ = v.face_;
|
||||
info_ = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
public:
|
||||
std::string debug() const
|
||||
{ std::ostrstream os; set_pretty_mode(os);
|
||||
os<<"V"<<point_<<' '<<info_<<'\0';
|
||||
std::string res(os.str()); os.freeze(0); return res;
|
||||
}
|
||||
|
||||
}; // Vertex
|
||||
|
||||
|
||||
template <typename Refs>
|
||||
class Halfedge : public CGAL::In_place_list_base< Halfedge<Refs> >
|
||||
{
|
||||
typedef typename Refs::Items Items;
|
||||
typedef typename Refs::Vertex_handle Vertex_handle;
|
||||
typedef typename Refs::Halfedge_handle Halfedge_handle;
|
||||
typedef typename Refs::Halfedge_const_handle Halfedge_const_handle;
|
||||
typedef typename Refs::Face_handle Face_handle;
|
||||
|
||||
friend class Sphere_map<Kernel_>;
|
||||
friend class SM_const_decorator<Refs,Kernel_>;
|
||||
friend class SM_decorator<Refs,Kernel_>;
|
||||
friend class move_edge_around_vertex<Halfedge_handle>;
|
||||
friend class move_edge_around_face<Halfedge_handle>;
|
||||
friend class move_edge_around_vertex<Halfedge_const_handle>;
|
||||
friend class move_edge_around_face<Halfedge_const_handle>;
|
||||
|
||||
// Role within local graph:
|
||||
Sphere_circle circle_;
|
||||
Mark mark_;
|
||||
Halfedge_handle twin_, prev_, next_;
|
||||
Vertex_handle source_;
|
||||
Face_handle face_;
|
||||
GenPtr info_;
|
||||
|
||||
public:
|
||||
Halfedge() : circle_(), mark_(), twin_(), prev_(), next_(),
|
||||
source_(), face_(), info_() {}
|
||||
|
||||
~Halfedge() {}
|
||||
|
||||
Halfedge(const Halfedge<Refs>& e)
|
||||
{
|
||||
circle_ = e.circle_;
|
||||
mark_ = e.mark_;
|
||||
twin_ = e.twin_;
|
||||
prev_ = e.prev_;
|
||||
next_ = e.next_;
|
||||
source_ = e.source_;
|
||||
face_ = e.face_;
|
||||
info_ = 0;
|
||||
}
|
||||
Halfedge<Refs>& operator=(const Halfedge<Refs>& e)
|
||||
{
|
||||
circle_ = e.circle_;
|
||||
mark_ = e.mark_;
|
||||
twin_ = e.twin_;
|
||||
prev_ = e.prev_;
|
||||
next_ = e.next_;
|
||||
source_ = e.source_;
|
||||
face_ = e.face_;
|
||||
info_ = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::string debug() const
|
||||
{ std::ostrstream os; set_pretty_mode(os);
|
||||
os <<"e["<<source_->debug()<<", "
|
||||
<<twin_->source_->debug()<<" "<<info_<<"]"<<'\0';
|
||||
std::string res(os.str()); os.freeze(0); return res;
|
||||
}
|
||||
|
||||
}; // Halfedge
|
||||
|
||||
template <typename Refs>
|
||||
class Halfloop : public CGAL::In_place_list_base< Halfloop<Refs> >
|
||||
{
|
||||
typedef typename Refs::Halfloop_handle Halfloop_handle;
|
||||
typedef typename Refs::Face_handle Face_handle;
|
||||
typedef typename Refs::Items Items;
|
||||
friend class Sphere_map<Kernel_>;
|
||||
friend class SM_const_decorator<Refs,Kernel_>;
|
||||
friend class SM_decorator<Refs,Kernel_>;
|
||||
friend class Self::Vertex<Refs>;
|
||||
|
||||
Sphere_circle circle_;
|
||||
Mark mark_;
|
||||
Halfloop_handle twin_;
|
||||
Face_handle face_;
|
||||
GenPtr info_;
|
||||
// temporary needed:
|
||||
|
||||
public:
|
||||
Halfloop() : circle_(), mark_(), twin_(), face_(), info_() {}
|
||||
~Halfloop() {}
|
||||
Halfloop(const Halfloop<Refs>& l)
|
||||
{
|
||||
circle_ = l.circle_;
|
||||
mark_ = l.mark_;
|
||||
twin_ = l.twin_;
|
||||
face_ = l.face_;
|
||||
info_ = 0;
|
||||
}
|
||||
Halfloop<Refs>& operator=(const Halfloop<Refs>& l)
|
||||
{
|
||||
circle_ = l.circle_;
|
||||
mark_ = l.mark_;
|
||||
twin_ = l.twin_;
|
||||
face_ = l.face_;
|
||||
info_ = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::string debug() const
|
||||
{ std::ostrstream os; set_pretty_mode(os);
|
||||
os<<"l"<<circle_<<' '<<info_<<'\0';
|
||||
std::string res(os.str()); os.freeze(0); return res;
|
||||
}
|
||||
|
||||
}; // Halfloop
|
||||
|
||||
template <typename Refs>
|
||||
class Face : public CGAL::In_place_list_base< Face<Refs> >
|
||||
{
|
||||
typedef typename Refs::Items Items;
|
||||
friend class Sphere_map<Kernel_>;
|
||||
friend class SM_const_decorator<Refs,Kernel_>;
|
||||
friend class SM_decorator<Refs,Kernel_>;
|
||||
|
||||
typedef typename Refs::Object_handle Object_handle;
|
||||
typedef typename Refs::Object_list Object_list;
|
||||
typedef typename Refs::Face_cycle_iterator Face_cycle_iterator;
|
||||
typedef typename Refs::Face_cycle_const_iterator
|
||||
Face_cycle_const_iterator;
|
||||
|
||||
Mark mark_;
|
||||
Object_list boundary_; // Halfedges, Halfloops, Vertices
|
||||
GenPtr info_;
|
||||
// temporary needed:
|
||||
|
||||
public:
|
||||
Face() : mark_(), info_() {}
|
||||
~Face() {}
|
||||
|
||||
Face(const Face<Refs>& f)
|
||||
{ mark_ = f.mark_;
|
||||
boundary_ = f.boundary_;
|
||||
info_ = 0;
|
||||
}
|
||||
Face<Refs>& operator=(const Face<Refs>& f)
|
||||
{ if (this == &f) return *this;
|
||||
mark_ = f.mark_;
|
||||
boundary_ = f.boundary_;
|
||||
info_ = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Face_cycle_iterator face_cycles_begin()
|
||||
{ return boundary_.begin(); }
|
||||
Face_cycle_iterator face_cycles_end()
|
||||
{ return boundary_.end(); }
|
||||
|
||||
Face_cycle_const_iterator face_cycles_begin() const
|
||||
{ return boundary_.begin(); }
|
||||
Face_cycle_const_iterator face_cycles_end() const
|
||||
{ return boundary_.end(); }
|
||||
|
||||
}; // Face
|
||||
|
||||
}; // SM_items
|
||||
|
||||
|
||||
CGAL_END_NAMESPACE
|
||||
#endif // CGAL_SM_ITEMS_H
|
||||
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -0,0 +1,453 @@
|
|||
// ============================================================================
|
||||
//
|
||||
// Copyright (c) 1997-2000 The CGAL Consortium
|
||||
//
|
||||
// This software and related documentation is part of an INTERNAL release
|
||||
// of the Computational Geometry Algorithms Library (CGAL). It is not
|
||||
// intended for general use.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// release : $CGAL_Revision$
|
||||
// release_date : $CGAL_Date$
|
||||
//
|
||||
// file : include/CGAL/Nef_S2/SM_point_locator.h
|
||||
// package : Nef_S2
|
||||
// chapter : Nef Polyhedra
|
||||
//
|
||||
// revision : $Revision$
|
||||
// revision_date : $Date$
|
||||
//
|
||||
// author(s) : Michael Seel <seel@mpi-sb.mpg.de>
|
||||
// maintainer : Michael Seel <seel@mpi-sb.mpg.de>
|
||||
// coordinator : Michael Seel <seel@mpi-sb.mpg.de>
|
||||
//
|
||||
// implementation: Point location module
|
||||
// ============================================================================
|
||||
#ifndef CGAL_SM_POINT_LOCATOR_H
|
||||
#define CGAL_SM_POINT_LOCATOR_H
|
||||
|
||||
#include <CGAL/basic.h>
|
||||
#include <CGAL/Unique_hash_map.h>
|
||||
#include <CGAL/Object.h>
|
||||
#include <CGAL/Nef_2/geninfo.h>
|
||||
|
||||
#undef _DEBUG
|
||||
#define _DEBUG 143
|
||||
#include <CGAL/Nef_S2/debug.h>
|
||||
|
||||
|
||||
CGAL_BEGIN_NAMESPACE
|
||||
|
||||
/*{\Moptions print_title=yes }*/
|
||||
|
||||
/*{\Manpage {SM_point_locator}{Decorator}
|
||||
{Naive point location in plane maps}{PL}}*/
|
||||
/*{\Mdefinition An instance |\Mvar| of data type |\Mname|
|
||||
encapsulates naive point location queries within a sphere map |M|. The
|
||||
two template parameters are specified via concepts. |PM_decorator_|
|
||||
must be a model of the concept |PMDecorator| as described in the
|
||||
appendix. |Geometry_| must be a model of the concept
|
||||
|AffineGeometryTraits_2| as described in the appendix. For a
|
||||
specification of plane maps see also the concept of
|
||||
|PMConstDecorator|.}*/
|
||||
|
||||
/*{\Mgeneralization Decorator}*/
|
||||
|
||||
template <typename Decorator_>
|
||||
class SM_point_locator : public Decorator_ {
|
||||
protected:
|
||||
typedef Decorator_ Base;
|
||||
typedef SM_point_locator<Decorator_> Self;
|
||||
|
||||
public:
|
||||
/*{\Mtypes 5}*/
|
||||
typedef Decorator_ Decorator;
|
||||
/*{\Mtypemember equals |Decorator_|.}*/
|
||||
typedef typename Decorator::Sphere_map Sphere_map;
|
||||
/*{\Mtypemember the sphere map type decorated by |Decorator|.}*/
|
||||
typedef typename Decorator::Mark Mark;
|
||||
/*{\Mtypemember the attribute of all objects (vertices, edges, loops,
|
||||
faces).}*/
|
||||
|
||||
typedef typename Decorator::Kernel Kernel;
|
||||
/*{\Mtypemember the sphere kernel.}*/
|
||||
typedef typename Kernel::Sphere_point Sphere_point;
|
||||
/*{\Mtypemember points.}*/
|
||||
typedef typename Kernel::Sphere_segment Sphere_segment;
|
||||
/*{\Mtypemember segments.}*/
|
||||
typedef typename Kernel::Sphere_circle Sphere_circle;
|
||||
/*{\Mtypemember circles.}*/
|
||||
typedef typename Kernel::Sphere_direction Sphere_direction;
|
||||
/*{\Mtypemember directions.}*/
|
||||
|
||||
/*{\Mtext Local types are handles, iterators and circulators of the
|
||||
following kind: |Vertex_const_handle|, |Vertex_const_iterator|,
|
||||
|Halfedge_const_handle|, |Halfedge_const_iterator|,
|
||||
|Halfloop_const_handle|, |Halfloop_const_iterator|,
|
||||
|Face_const_handle|, |Face_const_iterator|.}*/
|
||||
|
||||
typedef typename Sphere_map::Object_handle Object_handle;
|
||||
/*{\Mtypemember a generic handle to an object of the underlying plane
|
||||
map. The kind of the object |(vertex, halfedge,face)| can be determined and
|
||||
the object assigned by the three functions:\\
|
||||
|bool assign(Vertex_const_handle& h, Object_handle o)|\\
|
||||
|bool assign(Halfedge_const_handle& h, Object_handle o)|\\
|
||||
|bool assign(Face_const_handle& h, Object_handle o)|\\ where each
|
||||
function returns |true| iff the assignment of |o| to |h| was valid.}*/
|
||||
|
||||
#define USING(t) typedef typename Decorator_::t t
|
||||
USING(Vertex_handle);
|
||||
USING(Halfedge_handle);
|
||||
USING(Halfloop_handle);
|
||||
USING(Face_handle);
|
||||
USING(Vertex_const_handle);
|
||||
USING(Halfedge_const_handle);
|
||||
USING(Halfloop_const_handle);
|
||||
USING(Face_const_handle);
|
||||
USING(Vertex_iterator);
|
||||
USING(Halfedge_iterator);
|
||||
USING(Halfloop_iterator);
|
||||
USING(Face_iterator);
|
||||
USING(Vertex_const_iterator);
|
||||
USING(Halfedge_const_iterator);
|
||||
USING(Halfloop_const_iterator);
|
||||
USING(Face_const_iterator);
|
||||
USING(Halfedge_around_vertex_circulator);
|
||||
USING(Halfedge_around_vertex_const_circulator);
|
||||
USING(Halfedge_around_face_circulator);
|
||||
USING(Halfedge_around_face_const_circulator);
|
||||
#undef USING
|
||||
|
||||
Sphere_segment segment(Halfedge_const_handle e) const
|
||||
{ return Sphere_segment(point(source(e)), point(target(e)), circle(e)); }
|
||||
|
||||
Sphere_direction direction(Halfedge_const_handle e) const
|
||||
{ return Sphere_direction(circle(e)); }
|
||||
|
||||
Halfedge_const_handle out_wedge(Vertex_const_handle v,
|
||||
const Sphere_direction& d, bool& collinear) const
|
||||
/*{\Xop returns a halfedge |e| bounding a wedge in between two
|
||||
neighbored edges in the adjacency list of |v| which contains |d|.
|
||||
If |d| extends along a edge then |e| is this edge. If |d| extends
|
||||
into the interior of such a wedge then |e| is the first edge hit
|
||||
when |d| is rotated clockwise. \precond |v| is not isolated.}*/
|
||||
{ TRACEN("out_wedge "<<PH(v));
|
||||
assert(!is_isolated(v));
|
||||
collinear=false;
|
||||
Sphere_point p = point(v);
|
||||
Halfedge_const_handle e_res = first_out_edge(v);
|
||||
Sphere_direction d_res = direction(e_res);
|
||||
Halfedge_around_vertex_const_circulator el(e_res),ee(el);
|
||||
CGAL_For_all(el,ee) {
|
||||
if ( strictly_ordered_ccw_at(p,d_res, direction(el), d) )
|
||||
e_res = el; d_res = direction(e_res);
|
||||
}
|
||||
TRACEN(" determined "<<PH(e_res)<<" "<<d_res);
|
||||
if ( direction(cyclic_adj_succ(e_res)) == d ) {
|
||||
e_res = cyclic_adj_succ(e_res);
|
||||
collinear=true;
|
||||
}
|
||||
TRACEN(" wedge = "<<PH(e_res)<<" "<<collinear);
|
||||
return e_res;
|
||||
}
|
||||
|
||||
|
||||
template <class Handle>
|
||||
Object_handle make_object(Handle h) const
|
||||
{ return CGAL::make_object(h); }
|
||||
|
||||
/*{\Mcreation 3}*/
|
||||
|
||||
SM_point_locator() : Base() {}
|
||||
|
||||
/*{\Moptions constref=yes}*/
|
||||
SM_point_locator(const Sphere_map& M) :
|
||||
Base(const_cast<Sphere_map&>(M)) {}
|
||||
/*{\Mcreate constructs a point locator working on |P|.}*/
|
||||
/*{\Moptions constref=no}*/
|
||||
/*{\Moperations 2.5 0.5}*/
|
||||
|
||||
const Mark& mark(Object_handle h) const
|
||||
/*{\Mop returns the mark associated to the object |h|.}*/
|
||||
{ Vertex_const_handle v;
|
||||
Halfedge_const_handle e;
|
||||
Face_const_handle f;
|
||||
if ( assign(v,h) ) return mark(v);
|
||||
if ( assign(e,h) ) return mark(e);
|
||||
if ( assign(f,h) ) return mark(f);
|
||||
CGAL_assertion_msg(0,
|
||||
"PM_point_locator::mark: Object_handle holds no object.");
|
||||
}
|
||||
|
||||
|
||||
enum SOLUTION { is_vertex_, is_edge_, is_loop_ };
|
||||
// enumeration for internal use
|
||||
|
||||
Object_handle locate(const Sphere_point& p) const
|
||||
/*{\Mop returns a generic handle |h| to an object (vertex, halfedge,
|
||||
face) of the underlying plane map |P| which contains the point |p =
|
||||
s.source()| in its relative interior. |s.target()| must be a point
|
||||
such that |s| intersects the $1$-skeleton of |P|.}*/
|
||||
{ TRACEN("locate naivly "<<p);
|
||||
Vertex_const_iterator v;
|
||||
CGAL_forall_vertices(v,*this) {
|
||||
if ( p == point(v) ) return make_object(v);
|
||||
}
|
||||
|
||||
Halfedge_const_iterator e;
|
||||
CGAL::Unique_hash_map<Halfedge_const_handle,bool> visited(false);
|
||||
CGAL_forall_halfedges(e,*this) {
|
||||
if ( visited[e] ) continue;
|
||||
if ( segment(e).has_on(p) ) return make_object(e);
|
||||
visited[e]=visited[twin(e)]=true;
|
||||
}
|
||||
if ( has_loop() && circle(halfloop()).has_on(p) )
|
||||
return make_object(Halfloop_const_handle(halfloop()));
|
||||
|
||||
// now in face:
|
||||
|
||||
if ( number_of_vertices() == 0 && ! has_loop() )
|
||||
return make_object(faces_begin());
|
||||
|
||||
Vertex_const_handle v_res;
|
||||
Halfedge_const_handle e_res;
|
||||
Halfloop_const_handle l_res;
|
||||
SOLUTION solution;
|
||||
|
||||
Sphere_segment s; // we shorten the segment iteratively
|
||||
if ( has_loop() ) {
|
||||
Sphere_circle c(circle(halfloop()),p); // orthogonal through p
|
||||
s = Sphere_segment(p,intersection(c,circle(halfloop())));
|
||||
l_res = circle(halfloop()).has_on_positive_side(p) ?
|
||||
halfloop() : twin(halfloop());
|
||||
solution = is_loop_;
|
||||
} else { // has vertices !
|
||||
CGAL_assertion( number_of_vertices()!=0 );
|
||||
Vertex_const_handle vt = vertices_begin();
|
||||
Sphere_point pvt = point(vt);
|
||||
if ( p != pvt.opposite() ) s = Sphere_segment(p,pvt);
|
||||
else s = Sphere_segment(p,pvt,Sphere_circle(p,pvt));
|
||||
v_res = vt;
|
||||
solution = is_vertex_;
|
||||
}
|
||||
|
||||
// s now initialized
|
||||
|
||||
Sphere_direction dso(s.sphere_circle().opposite()), d_res;
|
||||
visited.clear(false);
|
||||
CGAL_forall_vertices(v,*this) {
|
||||
Sphere_point p_res, vp = point(v);
|
||||
if ( s.has_on(vp) ) {
|
||||
TRACEN(" location via vertex at "<<vp);
|
||||
s = Sphere_segment(p,vp,s.sphere_circle()); // we shrink the segment
|
||||
if ( is_isolated(v) ) {
|
||||
v_res = v; solution = is_vertex_;
|
||||
} else { // not isolated
|
||||
bool dummy;
|
||||
e_res = out_wedge(v,dso,dummy);
|
||||
Halfedge_around_vertex_const_circulator el(e_res),ee(el);
|
||||
CGAL_For_all(el,ee)
|
||||
visited[el] = visited[twin(el)] = true;
|
||||
/* e_res is now the counterclockwise maximal halfedge out
|
||||
of v just before s */
|
||||
if ( circle(e_res).has_on_negative_side(p) )
|
||||
e_res = previous(e_res);
|
||||
// correction to make e_res visible from p
|
||||
solution = is_edge_;
|
||||
TRACEN(" determined "<<PH(e_res));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CGAL_forall_halfedges(e,*this) {
|
||||
if ( visited[e] ) continue;
|
||||
Sphere_segment se = segment(e);
|
||||
Sphere_point p_res;
|
||||
if ( do_intersect_internally(se,s,p_res) ) {
|
||||
TRACEN(" location via halfedge "<<se);
|
||||
s = Sphere_segment(p,p_res,s.sphere_circle());
|
||||
e_res = ( circle(e).has_on_positive_side(p) ? e : twin(e) );
|
||||
visited[e] = visited[twin(e)] = true;
|
||||
solution = is_edge_;
|
||||
TRACEN(" determined "<<PH(e_res)<<" "<<mark(face(e_res)));
|
||||
}
|
||||
}
|
||||
|
||||
switch ( solution ) {
|
||||
case is_edge_:
|
||||
return make_object((Face_const_handle)(face(e_res)));
|
||||
case is_loop_:
|
||||
return make_object((Face_const_handle)(face(l_res)));
|
||||
case is_vertex_:
|
||||
return make_object((Face_const_handle)(face(v_res)));
|
||||
default: CGAL_assertion_msg(0,"missing solution.");
|
||||
}
|
||||
return Object_handle(); // never reached!
|
||||
}
|
||||
|
||||
|
||||
template <typename Object_predicate>
|
||||
Object_handle ray_shoot(const Sphere_point& p,
|
||||
const Sphere_direction& d,
|
||||
const Object_predicate& M) const
|
||||
/*{\Mop returns an |Object_handle o| which can be converted to a
|
||||
|Vertex_const_handle|, |Halfedge_const_handle|, |Face_const_handle|
|
||||
|h| as described above. The object predicate |M| has to have
|
||||
function operators \\ |bool operator() (const
|
||||
Vertex_/Halfedge_/Halfloop_/Face_const_handle&)|.\\ The object
|
||||
returned is intersected by |d.circle()|, has minimal distance to
|
||||
|p|, and |M(h)| holds on the converted object. The operation returns
|
||||
the null handle |NULL| if the ray shoot along |s| does not hit any
|
||||
object |h| of |M| with |M(h)|.}*/
|
||||
{
|
||||
Sphere_circle c(d.circle());
|
||||
Sphere_segment s;
|
||||
bool s_init(false);
|
||||
Object_handle h = locate(p);
|
||||
Vertex_const_handle v;
|
||||
Halfedge_const_handle e;
|
||||
Halfloop_const_handle l;
|
||||
Face_const_handle f;
|
||||
if ( assign(v,h) && M(v) ||
|
||||
assign(e,h) && M(e) ||
|
||||
assign(l,h) && M(l) ||
|
||||
assign(f,h) && M(f) ) return h;
|
||||
h = Object_handle();
|
||||
TRACEN("not contained");
|
||||
#if 0
|
||||
HASEN: s am anfang circle, ab wann segment ?
|
||||
wo loop ?
|
||||
|
||||
CGAL_forall_vertices (v,*this) {
|
||||
Point pv = point(v);
|
||||
if ( !(s_init && s.has_on(pv) ||
|
||||
!s_init && c.has_on(pv)) ) continue;
|
||||
TRACEN("candidate "<<pv);
|
||||
if ( M(v) ) {
|
||||
h = make_object(v); // store vertex
|
||||
s = Sphere_segment(p,pv,c); // shorten
|
||||
continue;
|
||||
}
|
||||
// now we know that v is not marked but on s
|
||||
bool collinear;
|
||||
Halfedge_const_handle e = out_wedge(v,d,collinear);
|
||||
if ( collinear ) {
|
||||
if ( M(e) ) {
|
||||
h = make_object(e);
|
||||
s = Sphere_segment(p,pv,c);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if ( M(face(e)) ) {
|
||||
h = make_object(face(e));
|
||||
s = Sphere_segment(p,pv,c);
|
||||
}
|
||||
} // all vertices
|
||||
|
||||
CGAL::Unique_hash_map<Halfedge_const_handle,bool> visited(false);
|
||||
Halfedge_const_iterator e_res;
|
||||
CGAL_forall_halfedges(e,*this) {
|
||||
Sphere_segment se = segment(e);
|
||||
Sphere_point p_res;
|
||||
if ( do_intersect_internally(se,s,p_res) ) {
|
||||
// internal intersection
|
||||
TRACEN("candidate "<<se);
|
||||
e_res = e;
|
||||
Sphere_segment s_cand = Sphere_segment(p,p_res,c);
|
||||
if ( s_cand.is_short() && circle(e).has_on_negative_side(p) ||
|
||||
s_cand.is_long() && circle(e).has_on_positive_side(p) ||
|
||||
s_cand.is_halfcircle() &&
|
||||
strictly_ordered_ccw_at(p.opposite(),
|
||||
direction(e),d,direction(twin(e))) )
|
||||
e_res = twin(e);
|
||||
if ( M(e_res) ) {
|
||||
h = make_object(e_res); s = s_cand;
|
||||
} else if ( M(face(twin(e_res))) ) {
|
||||
h = make_object(face(twin(e_res))); s = s_cand;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
CGAL_assertion_msg(0,"not yet correct");
|
||||
return h;
|
||||
}
|
||||
|
||||
void init_marks_of_halfspheres();
|
||||
|
||||
// C++ is really friendly:
|
||||
#define USECMARK(t) const Mark& mark(t h) const { return Base::mark(h); }
|
||||
#define USEMARK(t) Mark& mark(t h) const { return Base::mark(h); }
|
||||
USEMARK(Vertex_handle)
|
||||
USEMARK(Halfedge_handle)
|
||||
USEMARK(Face_handle)
|
||||
USECMARK(Vertex_const_handle)
|
||||
USECMARK(Halfedge_const_handle)
|
||||
USECMARK(Face_const_handle)
|
||||
#undef USEMARK
|
||||
#undef USECMARK
|
||||
/*{\Mimplementation Naive query operations are realized by checking
|
||||
the intersection points of the $1$-skeleton of the plane map |P| with
|
||||
the query segments $s$. This method takes time linear in the size $n$
|
||||
of the underlying plane map without any preprocessing.}*/
|
||||
}; // SM_point_locator<Decorator_>
|
||||
|
||||
template <typename D>
|
||||
void SM_point_locator<D>::init_marks_of_halfspheres()
|
||||
{ TRACEN("init_marks_of_halfspheres");
|
||||
Sphere_point y_minus(0,-1,0);
|
||||
Object_handle h = locate(y_minus);
|
||||
Face_const_handle f;
|
||||
if ( CGAL::assign(f,h) ) {
|
||||
mark_of_halfsphere(-1) = mark_of_halfsphere(+1) = mark(f);
|
||||
return;
|
||||
}
|
||||
|
||||
Halfedge_const_handle e;
|
||||
if ( CGAL::assign(e,h) ) {
|
||||
CGAL_assertion(circle(e).has_on(y_minus));
|
||||
Sphere_point op(CGAL::ORIGIN+circle(e).orthogonal_vector());
|
||||
TRACEN("on edge "<<op);
|
||||
if ( (op.x() > 0) || (op.x() == 0) && (op.z() < 0) ) e = twin(e);
|
||||
// if ( (op.z() < 0) || (op.z() == 0) && (op.x() > 0) ) e = twin(e);
|
||||
mark_of_halfsphere(+1) = mark(face(e));
|
||||
mark_of_halfsphere(-1) = mark(face(twin(e)));
|
||||
return;
|
||||
}
|
||||
|
||||
Halfloop_const_handle l;
|
||||
if ( CGAL::assign(l,h) ) {
|
||||
CGAL_assertion(circle(l).has_on(y_minus));
|
||||
Sphere_point op(CGAL::ORIGIN+circle(l).orthogonal_vector());
|
||||
TRACEN("on loop "<<op);
|
||||
if ( (op.x() > 0) || (op.x() == 0) && (op.z() < 0) ) l = twin(l);
|
||||
// if ( (op.z() < 0) || (op.z() == 0) && (op.x() > 0) ) l = twin(l);
|
||||
mark_of_halfsphere(+1) = mark(face(l));
|
||||
mark_of_halfsphere(-1) = mark(face(twin(l)));
|
||||
return;
|
||||
}
|
||||
|
||||
//Sphere_circle c(-1,0,0);
|
||||
//Sphere_direction up(c),down(c.opposite());
|
||||
Sphere_circle c(0,0,1);
|
||||
Sphere_direction right(c),left(c.opposite());
|
||||
bool collinear(false);
|
||||
Vertex_const_handle v;
|
||||
if ( CGAL::assign(v,h) ) {
|
||||
CGAL_assertion(point(v)==y_minus);
|
||||
e = out_wedge(v,left,collinear);
|
||||
if ( collinear ) mark_of_halfsphere(+1) = mark(face(twin(e)));
|
||||
else mark_of_halfsphere(+1) = mark(face(e));
|
||||
e = out_wedge(v,right,collinear);
|
||||
if ( collinear ) mark_of_halfsphere(-1) = mark(face(twin(e)));
|
||||
else mark_of_halfsphere(-1) = mark(face(e));
|
||||
return;
|
||||
}
|
||||
CGAL_assertion_msg(0,"damn wrong type.");
|
||||
}
|
||||
|
||||
CGAL_END_NAMESPACE
|
||||
#endif // CGAL_SM_POINT_LOCATOR_H
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,674 @@
|
|||
// ============================================================================
|
||||
//
|
||||
// Copyright (c) 1997-2000 The CGAL Consortium
|
||||
//
|
||||
// This software and related documentation is part of an INTERNAL release
|
||||
// of the Computational Geometry Algorithms Library (CGAL). It is not
|
||||
// intended for general use.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// release : $CGAL_Revision$
|
||||
// release_date : $CGAL_Date$
|
||||
//
|
||||
// file : include/CGAL/Nef_S2/SM_triagulator.h
|
||||
// package : Nef_S2
|
||||
// chapter : Nef Polyhedra
|
||||
//
|
||||
// revision : $Revision$
|
||||
// revision_date : $Date$
|
||||
//
|
||||
// author(s) : Michael Seel <seel@mpi-sb.mpg.de>
|
||||
// maintainer : Michael Seel <seel@mpi-sb.mpg.de>
|
||||
// coordinator : Michael Seel <seel@mpi-sb.mpg.de>
|
||||
//
|
||||
// implementation: Triangulation module for sphere maps
|
||||
// ============================================================================
|
||||
|
||||
#ifndef CGAL_SM_TRIANGULATOR_H
|
||||
#define CGAL_SM_TRIANGULATOR_H
|
||||
|
||||
#include <CGAL/basic.h>
|
||||
#include <CGAL/Partition.h>
|
||||
#include <CGAL/Unique_hash_map.h>
|
||||
#include <CGAL/Nef_2/Segment_overlay_traits.h>
|
||||
#include <CGAL/Nef_2/geninfo.h>
|
||||
#include <CGAL/Nef_S2/SM_decorator.h>
|
||||
#include <CGAL/Nef_S2/SM_io_parser.h>
|
||||
#include <CGAL/Nef_S2/SM_constrained_triang_traits.h>
|
||||
|
||||
#undef _DEBUG
|
||||
#define _DEBUG 137
|
||||
#include <CGAL/Nef_S2/debug.h>
|
||||
|
||||
#define USING(t) typedef typename Base::t t
|
||||
#ifndef CGAL_USE_LEDA
|
||||
#define LEDA_MEMORY(t)
|
||||
#endif
|
||||
CGAL_BEGIN_NAMESPACE
|
||||
|
||||
template <typename Decorator_, typename IT, typename INFO>
|
||||
struct SM_subdivision {
|
||||
typedef Decorator_ Triangulator;
|
||||
typedef typename Decorator_::Explorer Explorer;
|
||||
typedef typename Decorator_::Vertex_handle Vertex_handle;
|
||||
typedef typename Decorator_::Halfedge_handle Halfedge_handle;
|
||||
typedef typename Decorator_::Sphere_point Point;
|
||||
typedef typename Decorator_::Sphere_segment Segment;
|
||||
Triangulator T;
|
||||
Explorer E;
|
||||
CGAL::Unique_hash_map<IT,INFO>& M;
|
||||
/* M stores the object that supports the segment that
|
||||
is input object of the sweep */
|
||||
|
||||
SM_subdivision(Triangulator Ti, Explorer Ei,
|
||||
CGAL::Unique_hash_map<IT,INFO>& Mi) :
|
||||
T(Ti), E(Ei), M(Mi) {}
|
||||
|
||||
Vertex_handle new_vertex(const Point& p) const
|
||||
{ Vertex_handle v = T.new_vertex(p); T.assoc_info(v);
|
||||
return v;
|
||||
}
|
||||
|
||||
void link_as_target_and_append(Vertex_handle v, Halfedge_handle e) const
|
||||
{ T.link_as_target_and_append(v,e); }
|
||||
|
||||
Halfedge_handle new_halfedge_pair_at_source(Vertex_handle v) const
|
||||
{ Halfedge_handle e =
|
||||
T.new_edge_pair_at_source(v,Decorator_::BEFORE);
|
||||
T.assoc_info(e);
|
||||
return e;
|
||||
}
|
||||
|
||||
void halfedge_below(Vertex_handle v, Halfedge_handle e) const
|
||||
{ T.halfedge_below(v) = e; }
|
||||
|
||||
/* the following operation associates segment support with
|
||||
halfedges, we only update if non-NULL; this prevents
|
||||
artificial sphere subdivision segments that have NULL
|
||||
support to overwrite non-NULL support */
|
||||
|
||||
void supporting_segment(Halfedge_handle e, IT it) const
|
||||
{ T.is_forward(e) = true;
|
||||
if ( M[it] != NULL ) T.support(e) = M[it]; }
|
||||
|
||||
/* the following operation associate segment support with
|
||||
vertices, we only update if non-NULL; this prevents
|
||||
artificial segments that have NULL support to overwrite
|
||||
non-NULL support */
|
||||
|
||||
void trivial_segment(Vertex_handle v, IT it) const
|
||||
{ if ( M[it] != NULL ) T.support(v) = M[it]; }
|
||||
|
||||
void starting_segment(Vertex_handle v, IT it) const
|
||||
{ if ( M[it] != NULL ) T.support(v) = M[it]; }
|
||||
|
||||
void ending_segment(Vertex_handle v, IT it) const
|
||||
{ if ( M[it] != NULL ) T.support(v) = M[it]; }
|
||||
|
||||
void passing_segment(Vertex_handle v, IT it) const
|
||||
{ if ( M[it] != NULL ) T.support(v) = M[it]; }
|
||||
|
||||
|
||||
}; // SM_subdivision
|
||||
|
||||
|
||||
|
||||
/*{\Manpage {SM_triangulator}{Decorator_}{Overlay in the sphere}{O}}*/
|
||||
|
||||
template <typename Decorator_>
|
||||
class SM_triangulator : public Decorator_ {
|
||||
public:
|
||||
/*{\Mdefinition An instance |\Mvar| of data type |\Mname| is a
|
||||
decorator object offering sphere map triangulation calculation.}*/
|
||||
|
||||
typedef Decorator_ Base;
|
||||
typedef typename Decorator_::Base Explorer;
|
||||
typedef Decorator_ Decorator;
|
||||
typedef SM_triangulator<Decorator_> Self;
|
||||
USING(Vertex_handle);
|
||||
USING(Halfedge_handle);
|
||||
USING(Halfloop_handle);
|
||||
USING(Face_handle);
|
||||
USING(Vertex_iterator);
|
||||
USING(Halfedge_iterator);
|
||||
USING(Face_iterator);
|
||||
USING(Vertex_const_handle);
|
||||
USING(Halfedge_const_handle);
|
||||
USING(Halfloop_const_handle);
|
||||
USING(Face_const_handle);
|
||||
USING(Vertex_const_iterator);
|
||||
USING(Halfedge_const_iterator);
|
||||
USING(Face_const_iterator);
|
||||
USING(Object_handle);
|
||||
USING(Halfedge_around_vertex_circulator);
|
||||
USING(Halfedge_around_face_circulator);
|
||||
USING(Sphere_map);
|
||||
typedef std::pair<Halfedge_handle,Halfedge_handle> Halfedge_pair;
|
||||
|
||||
/*{\Mtypes 3}*/
|
||||
|
||||
typedef typename Base::Kernel Kernel;
|
||||
|
||||
typedef typename Kernel::Sphere_point Sphere_point;
|
||||
/*{\Mtypemember the point type of the sphere geometry.}*/
|
||||
typedef typename Kernel::Sphere_segment Sphere_segment;
|
||||
/*{\Mtypemember the segment type of the sphere geometry.}*/
|
||||
typedef typename Kernel::Sphere_circle Sphere_circle;
|
||||
/*{\Mtypemember the circle type of the sphere geometry.}*/
|
||||
typedef typename Kernel::Sphere_triangle Sphere_triangle;
|
||||
/*{\Mtypemember the triangle type of the sphere geometry.}*/
|
||||
|
||||
typedef typename Decorator::Mark Mark;
|
||||
/*{\Mtypemember the mark of sphere map objects.}*/
|
||||
|
||||
/*{\Mgeneralization Decorator_}*/
|
||||
|
||||
protected:
|
||||
Explorer E_;
|
||||
const Kernel& K;
|
||||
|
||||
public:
|
||||
|
||||
typedef std::list<Sphere_segment> Seg_list;
|
||||
typedef typename Seg_list::iterator Seg_iterator;
|
||||
typedef std::pair<Seg_iterator,Seg_iterator> Seg_it_pair;
|
||||
typedef std::pair<Sphere_segment,Sphere_segment> Seg_pair;
|
||||
typedef CGAL::Unique_hash_map<Seg_iterator,Object_handle> Seg_map;
|
||||
|
||||
// vertex_info stores the origin of vertices
|
||||
struct vertex_info {
|
||||
Object_handle o_;
|
||||
Halfedge_handle e_;
|
||||
vertex_info() : o_(),e_() {}
|
||||
LEDA_MEMORY(vertex_info)
|
||||
};
|
||||
|
||||
void assoc_info(Vertex_handle v) const
|
||||
{ geninfo<vertex_info>::create(info(v)); }
|
||||
|
||||
void discard_info(Vertex_handle v) const
|
||||
{ geninfo<vertex_info>::clear(info(v)); }
|
||||
|
||||
vertex_info& ginfo(Vertex_handle v) const
|
||||
{ return geninfo<vertex_info>::access(info(v)); }
|
||||
|
||||
Object_handle& support(Vertex_handle v) const
|
||||
{ return ginfo(v).o_; }
|
||||
|
||||
Halfedge_handle& halfedge_below(Vertex_handle v) const
|
||||
{ return ginfo(v).e_; }
|
||||
|
||||
// edge_info stores the origin of edges
|
||||
struct edge_info {
|
||||
Mark m_left_; Object_handle o_; bool forw_;
|
||||
|
||||
edge_info() { m_left_=Mark(); o_=Object_handle(); forw_=false; }
|
||||
LEDA_MEMORY(edge_info)
|
||||
};
|
||||
|
||||
void assoc_info(Halfedge_handle e) const
|
||||
{ geninfo<edge_info>::create(info(e));
|
||||
geninfo<edge_info>::create(info(twin(e))); }
|
||||
|
||||
void discard_info(Halfedge_handle e) const
|
||||
{ geninfo<edge_info>::clear(info(e));
|
||||
geninfo<edge_info>::clear(info(twin(e))); }
|
||||
|
||||
edge_info& ginfo(Halfedge_handle e) const
|
||||
{ return geninfo<edge_info>::access(info(e)); }
|
||||
|
||||
Object_handle& support(Halfedge_handle e) const
|
||||
// uedge information we store in the smaller one
|
||||
{ if (&*e < &*(twin(e))) return ginfo(e).o_;
|
||||
else return ginfo(twin(e)).o_; }
|
||||
|
||||
Mark& incident_mark(Halfedge_handle e) const
|
||||
// biedge information we store in the edge
|
||||
{ return ginfo(e).m_left_; }
|
||||
|
||||
const edge_info& ginfo(Halfedge_const_handle e) const
|
||||
{ return geninfo<edge_info>::const_access(info(e)); }
|
||||
const Mark& incident_mark(Halfedge_const_handle e) const
|
||||
{ return ginfo(e).m_left_; }
|
||||
|
||||
bool& is_forward(Halfedge_handle e) const
|
||||
// biedge information we store in the edge
|
||||
{ return ginfo(e).forw_; }
|
||||
|
||||
void assert_equal_marks(Vertex_handle v1, Vertex_handle v2) const
|
||||
{ CGAL_assertion(mark(v1)==mark(v2)); }
|
||||
|
||||
void assert_equal_marks(Halfedge_handle e1, Halfedge_handle e2) const
|
||||
{ CGAL_assertion(mark(e1)==mark(e2)); }
|
||||
|
||||
Sphere_segment segment(Explorer N,
|
||||
Halfedge_const_handle e) const
|
||||
{ return Sphere_segment(
|
||||
N.point(N.source(e)),N.point(N.target(e)),N.circle(e)); }
|
||||
|
||||
Sphere_segment trivial_segment(Explorer N,
|
||||
Vertex_const_handle v) const
|
||||
{ Sphere_point p = N.point(v);
|
||||
return Sphere_segment(p,p); }
|
||||
|
||||
Seg_pair two_segments(Explorer N,
|
||||
Halfedge_const_handle e) const
|
||||
// we know that source(e)==target(e)
|
||||
{ return N.circle(e).split_at(N.point(N.source(e))); }
|
||||
|
||||
Seg_pair two_segments(Explorer N,
|
||||
Halfloop_const_handle l) const
|
||||
{ return N.circle(l).split_at_xy_plane(); }
|
||||
|
||||
|
||||
Mark& mark(Vertex_handle h) const
|
||||
{ return Base::mark(h); }
|
||||
Mark& mark(Halfedge_handle h) const
|
||||
{ return Base::mark(h); }
|
||||
Mark& mark(Halfloop_handle h) const
|
||||
{ return Base::mark(h); }
|
||||
Mark& mark(Face_handle h) const
|
||||
{ return Base::mark(h); }
|
||||
const Mark& mark(Vertex_const_handle h) const
|
||||
{ return Base::mark(h); }
|
||||
const Mark& mark(Halfedge_const_handle h) const
|
||||
{ return Base::mark(h); }
|
||||
const Mark& mark(Halfloop_const_handle h) const
|
||||
{ return Base::mark(h); }
|
||||
const Mark& mark(Face_const_handle h) const
|
||||
{ return Base::mark(h); }
|
||||
|
||||
/*{\Mcreation 6}*/
|
||||
SM_triangulator(const Sphere_map& M, Sphere_map& MT,
|
||||
const Kernel& Kr = Kernel()) :
|
||||
Base(MT), E_(const_cast<Sphere_map&>(M)), K(Kr) {}
|
||||
/*{\Mcreate |\Mvar| is a triangulator object for the map |M|,
|
||||
stores the triangulation in |MT|.}*/
|
||||
|
||||
/*{\Moperations 1.1 1}*/
|
||||
|
||||
void triangulate();
|
||||
/*{\Mop produces a triangulated sphere map.}*/
|
||||
|
||||
void triangulate_per_hemisphere(Vertex_iterator start, Vertex_iterator end);
|
||||
|
||||
template <typename Iterator, typename T>
|
||||
void partition_to_halfsphere(Iterator start, Iterator end,
|
||||
Seg_list& L, CGAL::Unique_hash_map<Iterator,T>& M, int pos) const;
|
||||
|
||||
void merge_halfsphere_maps(Vertex_handle v1, Vertex_handle v2) const;
|
||||
void merge_nodes(Halfedge_handle e1, Halfedge_handle e2) const;
|
||||
void complete_support(Vertex_iterator v_start, Vertex_iterator v_end,
|
||||
int pos) const;
|
||||
|
||||
void correct_triangle_at(Vertex_handle v)
|
||||
{ TRACEN("correct_triangle_at "<<PH(v));
|
||||
if ( !has_outdeg_two(v) ) return;
|
||||
Halfedge_handle e = first_out_edge(v);
|
||||
CGAL_assertion(next(next(next(e)))==e);
|
||||
flip_diagonal(next(e));
|
||||
}
|
||||
|
||||
void dump(std::ostream& os = std::cerr) const
|
||||
{ SM_io_parser<Explorer>::dump(E_,os);
|
||||
SM_io_parser<Base>::dump(*this,os); }
|
||||
|
||||
Sphere_triangle incident_triangle(Halfedge_handle e) const
|
||||
{ Halfedge_handle en(next(e)), enn(next(en));
|
||||
CGAL_assertion(next(enn)==e);
|
||||
return Sphere_triangle(
|
||||
point(source(e)),point(source(en)),point(source(enn)),
|
||||
circle(e),circle(en),circle(enn));
|
||||
}
|
||||
|
||||
Sphere_triangle incident_triangle(Halfedge_const_handle e) const
|
||||
{ Halfedge_const_handle en(next(e)), enn(next(en));
|
||||
CGAL_assertion(next(enn)==e);
|
||||
return Sphere_triangle(
|
||||
point(source(e)),point(source(en)),point(source(enn)),
|
||||
circle(e),circle(en),circle(enn));
|
||||
}
|
||||
|
||||
void discard_info()
|
||||
{
|
||||
Vertex_iterator v;
|
||||
Halfedge_iterator e;
|
||||
CGAL_forall_vertices(v,*this) discard_info(v);
|
||||
CGAL_forall_halfedges(e,*this) discard_info(e);
|
||||
}
|
||||
|
||||
|
||||
}; // SM_triangulator<Decorator_>
|
||||
|
||||
|
||||
template <typename Decorator_>
|
||||
void SM_triangulator<Decorator_>::triangulate()
|
||||
{ TRACEN("triangulate");
|
||||
// first create sphere segments from isoverts, edges, loops
|
||||
Seg_list L;
|
||||
Seg_map From;
|
||||
CGAL::Unique_hash_map<Halfedge_const_iterator,bool> Done(false);
|
||||
Vertex_const_iterator v;
|
||||
CGAL_forall_vertices(v,E_) {
|
||||
if ( !E_.is_isolated(v) ) continue;
|
||||
L.push_back(trivial_segment(E_,v));
|
||||
From[--L.end()] = make_object(v);
|
||||
}
|
||||
Halfedge_const_iterator e;
|
||||
CGAL_forall_halfedges(e,E_) {
|
||||
if ( Done[e] ) continue;
|
||||
if ( source(e) == target(e) ) {
|
||||
Seg_pair p = two_segments(E_,e);
|
||||
L.push_back(p.first); L.push_back(p.second);
|
||||
From[--L.end()] = From[--(--L.end())] = make_object(e);
|
||||
} else {
|
||||
L.push_back(segment(E_,e));
|
||||
From[--L.end()] = make_object(e);
|
||||
}
|
||||
Done[e] = Done[twin(e)] = true;
|
||||
|
||||
}
|
||||
if ( E_.has_loop() ) {
|
||||
Seg_pair p = two_segments(E_,E_.halfloop());
|
||||
L.push_back(p.first); L.push_back(p.second);
|
||||
From[--L.end()] = From[--(--L.end())] = make_object(E_.halfloop());
|
||||
}
|
||||
|
||||
// partition segments from L to positive and negative hemisphere
|
||||
Seg_list L_pos,L_neg;
|
||||
partition_to_halfsphere(L.begin(), L.end(), L_pos, From, +1);
|
||||
partition_to_halfsphere(L.begin(), L.end(), L_neg, From, -1);
|
||||
|
||||
// sweep the hemispheres to create two half sphere maps
|
||||
typedef SM_subdivision<Self,Seg_iterator,Object_handle> SM_output;
|
||||
typedef typename Kernel::Positive_halfsphere_geometry PH_geometry;
|
||||
typedef CGAL::Segment_overlay_traits<
|
||||
Seg_iterator, SM_output, PH_geometry> PHS_traits;
|
||||
typedef CGAL::generic_sweep<PHS_traits> Positive_halfsphere_sweep;
|
||||
|
||||
typedef typename Kernel::Negative_halfsphere_geometry NH_geometry;
|
||||
typedef CGAL::Segment_overlay_traits<
|
||||
Seg_iterator, SM_output, NH_geometry> NHS_traits;
|
||||
typedef CGAL::generic_sweep<NHS_traits> Negative_halfsphere_sweep;
|
||||
|
||||
Vertex_handle v_sep;
|
||||
Halfedge_handle e_sep;
|
||||
SM_output O(*this,E_,From);
|
||||
|
||||
typedef typename PHS_traits::INPUT Input_range;
|
||||
Positive_halfsphere_sweep SP(
|
||||
Input_range(L_pos.begin(),L_pos.end()),O,
|
||||
K.get_positive_halfsphere_geometry());
|
||||
SP.sweep();
|
||||
v_sep=--vertices_end(); e_sep=--halfedges_end();
|
||||
|
||||
Negative_halfsphere_sweep SM(
|
||||
Input_range(L_neg.begin(),L_neg.end()),O,
|
||||
K.get_negative_halfsphere_geometry());
|
||||
SM.sweep();
|
||||
++v_sep; ++e_sep;
|
||||
// now two CCs of sphere graph are calculated
|
||||
// v_sep = first vertex of CC in negative x-sphere
|
||||
// e_sep = first edge of CC in negative x-sphere
|
||||
|
||||
// enrich the edges by circle information
|
||||
CGAL::Unique_hash_map<Halfedge_iterator,bool> Done2(false);
|
||||
for(Halfedge_iterator e = halfedges_begin(); e != halfedges_end(); ++e)
|
||||
{ if ( Done2[e] ) continue;
|
||||
Sphere_segment s(point(source(e)),point(target(e)));
|
||||
circle(e) = s.sphere_circle();
|
||||
circle(twin(e)) = s.sphere_circle().opposite();
|
||||
Done2[e] = Done2[twin(e)] = true;
|
||||
}
|
||||
|
||||
// complete the support of per hemisphere
|
||||
complete_support(vertices_begin(), v_sep, +1);
|
||||
complete_support(v_sep, vertices_end(), -1);
|
||||
|
||||
// triangulate per hemisphere
|
||||
typedef SM_constrained_triang_traits<Self,PH_geometry> PCT_traits;
|
||||
typedef CGAL::generic_sweep<PCT_traits> Positive_halfsphere_ct_sweep;
|
||||
typedef SM_constrained_triang_traits<Self,NH_geometry> NCT_traits;
|
||||
typedef CGAL::generic_sweep<NCT_traits> Negative_halfsphere_ct_sweep;
|
||||
typedef std::pair<Vertex_iterator,Vertex_iterator> Vertex_pair;
|
||||
|
||||
Vertex_pair vpp(vertices_begin(),v_sep);
|
||||
Positive_halfsphere_ct_sweep PCTS(vpp, *this,
|
||||
K.get_positive_halfsphere_geometry());
|
||||
PCTS.sweep();
|
||||
Vertex_pair vpn(v_sep,vertices_end());
|
||||
Negative_halfsphere_ct_sweep NCTS(vpn, *this,
|
||||
K.get_negative_halfsphere_geometry());
|
||||
NCTS.sweep();
|
||||
|
||||
/* Note the we divide the world along the xy equator and
|
||||
split the equator at y- and y+. We treat the halfcircle
|
||||
at x+ as if perturbed slightly up. This makes triangles
|
||||
that have y- or y+ as a vertex degenerate. if such triangles
|
||||
appear we repair it by flipping the edge opposite to the
|
||||
vertex y-(y+).
|
||||
*/
|
||||
correct_triangle_at(vertices_begin());
|
||||
correct_triangle_at(--Vertex_iterator(v_sep));
|
||||
correct_triangle_at(v_sep);
|
||||
correct_triangle_at(--vertices_end());
|
||||
|
||||
// enrigh triangulation edges by circle information
|
||||
for(Halfedge_iterator e = halfedges_begin(); e != halfedges_end(); ++e)
|
||||
{ if ( Done2[e] ) continue;
|
||||
Sphere_segment s(point(source(e)),point(target(e)));
|
||||
circle(e) = s.sphere_circle();
|
||||
circle(twin(e)) = s.sphere_circle().opposite();
|
||||
Done2[e] = Done2[twin(e)] = true;
|
||||
}
|
||||
|
||||
// merge the hemisphere maps into one sphere map
|
||||
merge_halfsphere_maps(vertices_begin(),v_sep);
|
||||
check_integrity_and_topological_planarity(false);
|
||||
}
|
||||
|
||||
|
||||
template <typename Decorator_>
|
||||
template <typename Iterator, typename T>
|
||||
void SM_triangulator<Decorator_>::
|
||||
partition_to_halfsphere(Iterator start, Iterator beyond, Seg_list& L,
|
||||
CGAL::Unique_hash_map<Iterator,T>& M, int pos) const
|
||||
{ TRACEN("partition_to_halfsphere ");
|
||||
CGAL_assertion(pos!=0);
|
||||
Sphere_segment s1,s2;
|
||||
Sphere_circle xycircle(0,0,pos);
|
||||
while ( start != beyond ) {
|
||||
int i = start->intersection(xycircle,s1,s2);
|
||||
if (i>1) { L.push_back(s2); M[--L.end()] = M[start]; }
|
||||
if (i>0) { L.push_back(s1); M[--L.end()] = M[start]; }
|
||||
++start;
|
||||
}
|
||||
// now all segments are split into halfspheres
|
||||
// we still have to:
|
||||
// - split segments containing our special poles y^-, y^+
|
||||
// - split halfcircles
|
||||
// - add four equator segments
|
||||
Sphere_point S(0,-1,0),N(0,1,0);
|
||||
Sphere_circle yzcircle(1,0,0);
|
||||
typename Seg_list::iterator it, itl;
|
||||
|
||||
bool part_in_hemisphere(false);
|
||||
CGAL_forall_iterators(it,L) { TRACEN(" "<<*it);
|
||||
if ( equal_as_sets(it->sphere_circle(),xycircle) ) {
|
||||
TRACEN(" splitting xy seg "<<*it);
|
||||
int n1 = it->intersection(yzcircle,s1,s2);
|
||||
if (n1 > 1 && !s2.is_degenerate())
|
||||
{ M[ L.insert(it,s2) ] = M[it]; }
|
||||
if (n1 > 0 && !s1.is_degenerate())
|
||||
{ M[ L.insert(it,s1) ] = M[it]; }
|
||||
int n2 = it->intersection(yzcircle.opposite(),s1,s2);
|
||||
if (n2 > 1 && !s2.is_degenerate())
|
||||
{ M[ L.insert(it,s2) ] = M[it]; }
|
||||
if (n2 > 0 && !s1.is_degenerate())
|
||||
{ M[ L.insert(it,s1) ] = M[it]; }
|
||||
itl = it; --it; L.erase(itl); M[itl] = T();
|
||||
// at least one item was appended
|
||||
} else {
|
||||
part_in_hemisphere = true;
|
||||
}
|
||||
}
|
||||
CGAL_forall_iterators(it,L) {
|
||||
if ( it->is_halfcircle() ) {
|
||||
TRACEN(" splitting halfcircle "<<*it);
|
||||
Sphere_segment s1,s2;
|
||||
it->split_halfcircle(s1,s2);
|
||||
*it = s2;
|
||||
M[ L.insert(it,s1) ] = M[it];
|
||||
}
|
||||
}
|
||||
// append 4 xy-equator segments:
|
||||
Sphere_segment sp(S,N,xycircle);
|
||||
Sphere_segment sm(S,N,xycircle.opposite());
|
||||
Sphere_segment s[4];
|
||||
sp.split_halfcircle(s[0],s[1]);
|
||||
sm.split_halfcircle(s[2],s[3]);
|
||||
L.insert(L.end(),s,s+4);
|
||||
/* if no segment is covering the interior of the hemisphere
|
||||
we have to add a trivial segment to allow for a correct
|
||||
triangulation */
|
||||
if ( !part_in_hemisphere ) {
|
||||
Sphere_point p(0,0,pos);
|
||||
Sphere_circle c(1,0,0);
|
||||
L.push_back(Sphere_segment(p,p,c));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <typename Decorator_>
|
||||
void SM_triangulator<Decorator_>::
|
||||
merge_nodes(Halfedge_handle e1, Halfedge_handle e2) const
|
||||
{
|
||||
Vertex_handle v1 = source(e1), v2 = target(e2);
|
||||
TRACEN("merge_nodes "<<PH(v1)<<PH(v2));
|
||||
CGAL_assertion(point(v1)==point(v2));
|
||||
Halfedge_handle ep1 = previous(e1), en2 = next(e2);
|
||||
Halfedge_around_vertex_circulator eav(out_edges(v2)),ee(eav);
|
||||
CGAL_For_all(eav,ee) { set_source(eav,v1); }
|
||||
link_as_prev_next_pair(e2,e1);
|
||||
link_as_prev_next_pair(ep1,en2);
|
||||
assert_equal_marks(v1,v2);
|
||||
discard_info(v2);
|
||||
delete_vertex_only(v2);
|
||||
}
|
||||
|
||||
template <typename Decorator_>
|
||||
void SM_triangulator<Decorator_>::
|
||||
merge_halfsphere_maps(Vertex_handle v1, Vertex_handle v2) const
|
||||
{ TRACEN("merging halfspheres "<<PH(v1)<<PH(v2));
|
||||
CGAL_assertion(point(v1)==point(v2));
|
||||
std::list<Halfedge_pair> L_equator;
|
||||
Halfedge_around_face_circulator
|
||||
ep(last_out_edge(v1)), en(twin(first_out_edge(v2)));
|
||||
do {
|
||||
L_equator.push_back(Halfedge_pair(ep,en));
|
||||
merge_nodes(ep,en); ++ep; --en;
|
||||
} while ( source(ep) != v1 );
|
||||
|
||||
typename std::list<Halfedge_pair>::iterator it;
|
||||
CGAL_forall_iterators(it,L_equator) {
|
||||
Halfedge_handle e1 = it->first, e2 = it->second;
|
||||
Halfedge_handle e1t = twin(e1), e2t = twin(e2);
|
||||
TRACEV(PH(e1));TRACEV(PH(e2));
|
||||
assert_equal_marks(e1,e2);
|
||||
unify_marks(e1); unify_marks(e2);
|
||||
make_twins(e1,e2); make_twins(e1t,e2t);
|
||||
if ( e1 == first_out_edge(source(e1)) )
|
||||
set_first_out_edge(source(e1),e2t);
|
||||
if ( e2 == first_out_edge(source(e2)) )
|
||||
set_first_out_edge(source(e2),e1t);
|
||||
discard_info(e1);
|
||||
delete_edge_pair_only(e1);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Decorator_>
|
||||
void SM_triangulator<Decorator_>::
|
||||
complete_support(Vertex_iterator v_start, Vertex_iterator v_end, int pos) const
|
||||
{
|
||||
TRACEN("complete_support");
|
||||
for (Vertex_iterator v = v_start; v != v_end; ++v) {
|
||||
TRACEN(" vertex = "<<PH(v));
|
||||
Mark m_buffer;
|
||||
Halfedge_handle e_below = halfedge_below(v);
|
||||
if ( v == v_start ) {
|
||||
m_buffer = E_.mark_of_halfsphere(-pos);
|
||||
} else if ( e_below != Halfedge_handle() ) {
|
||||
m_buffer = incident_mark(e_below);
|
||||
} else { // e_below does not exist
|
||||
/* this is only the case for a vertex v on the final equatorial
|
||||
halfcircle; there we take the mark from an inedge edge into v */
|
||||
CGAL_assertion( point(v).z() == 0 &&
|
||||
( pos > 0 ? (point(v).x() >= 0) : (point(v).x()<=0)) );
|
||||
m_buffer = incident_mark(previous(first_out_edge(v)));
|
||||
}
|
||||
TRACEN(" face mark below "<<m_buffer);
|
||||
|
||||
Object_handle o = support(v);
|
||||
Vertex_const_handle vs;
|
||||
Halfedge_const_handle es;
|
||||
Halfloop_const_handle ls;
|
||||
if ( o == NULL ) { mark(v) = m_buffer; }
|
||||
else if ( assign(vs,o) ) { mark(v) = E_.mark(vs); }
|
||||
else if ( assign(es,support(v)) ) {
|
||||
if ( point(source(es)) == point(v) )
|
||||
{ mark(v) = E_.mark(E_.source(es)); }
|
||||
else if ( point(target(es)) == point(v) )
|
||||
{ mark(v) = E_.mark(E_.target(es)); }
|
||||
else { mark(v) = E_.mark(es); }
|
||||
}
|
||||
else if ( assign(ls,o) ) { mark(v) = E_.mark(ls); }
|
||||
else CGAL_assertion_msg(0,"damn wrong support.");
|
||||
TRACEN(" face mark at "<<mark(v));
|
||||
|
||||
if ( is_isolated(v) ) continue;
|
||||
|
||||
Halfedge_around_vertex_circulator e(first_out_edge(v)), hend(e);
|
||||
CGAL_For_all(e,hend) {
|
||||
TRACEN(" edge "<<PH(e));
|
||||
if ( !is_forward(e) ) break;
|
||||
if ( support(e) != NULL ) {
|
||||
Halfedge_const_handle ei;
|
||||
if ( assign(ei,support(e)) ) {
|
||||
if ( E_.circle(ei) != circle(e) ) { ei = E_.twin(ei); }
|
||||
CGAL_assertion( E_.circle(ei) == circle(e) );
|
||||
TRACEN(" supporting edge "<<PH(ei));
|
||||
incident_mark(twin(e)) = E_.mark(E_.face(E_.twin(ei)));
|
||||
mark(e) = E_.mark(ei);
|
||||
incident_mark(e) = m_buffer = E_.mark(E_.face(ei));
|
||||
}
|
||||
Halfloop_const_handle li;
|
||||
if ( assign(li,support(e)) ) {
|
||||
if ( E_.circle(li) != circle(e) ) { li = E_.twin(li); }
|
||||
CGAL_assertion( E_.circle(li) == circle(e) );
|
||||
TRACEN(" supporting loop "<<PH(li));
|
||||
incident_mark(twin(e)) = E_.mark(E_.face(E_.twin(li)));
|
||||
mark(e) = E_.mark(li);
|
||||
incident_mark(e) = m_buffer = E_.mark(E_.face(li));
|
||||
}
|
||||
} else { TRACEN(" support from face below ");
|
||||
incident_mark(twin(e)) = mark(e) =
|
||||
incident_mark(e) = m_buffer;
|
||||
}
|
||||
TRACEN(" new face mark "<<m_buffer);
|
||||
|
||||
} // CGAL_For_all(e,hend)
|
||||
|
||||
TRACEN(" mark of "<<PH(v));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
CGAL_END_NAMESPACE
|
||||
#undef USING
|
||||
#endif //CGAL_SM_TRIANGULATOR_H
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,196 @@
|
|||
#ifndef SM_VISUALIZOR_H
|
||||
#define SM_VISUALIZOR_H
|
||||
|
||||
#include <CGAL/basic.h>
|
||||
#include <CGAL/Nef_S2/SM_decorator.h>
|
||||
#include <CGAL/Nef_S2/SM_triangulator.h>
|
||||
#include <CGAL/Nef_S2/Sphere_geometry_OGL.h>
|
||||
|
||||
#define USING(t) typedef typename Sphere_map_::t t
|
||||
//#define LGREY CGAL::Color(170,170,170)
|
||||
//#define DGREY CGAL::Color(30,30,30)
|
||||
#define LGREY CGAL::Color(170,170,200)
|
||||
#define DGREY CGAL::Color(30,30,50)
|
||||
CGAL_BEGIN_NAMESPACE
|
||||
|
||||
template <typename Sphere_map_>
|
||||
class SM_BooleColor
|
||||
{
|
||||
typedef typename Sphere_map_::Vertex_const_handle Vertex_const_handle;
|
||||
typedef typename Sphere_map_::Halfedge_const_handle Halfedge_const_handle;
|
||||
typedef typename Sphere_map_::Halfloop_const_handle Halfloop_const_handle;
|
||||
typedef typename Sphere_map_::Face_const_handle Face_const_handle;
|
||||
typedef typename Sphere_map_::Mark Mark;
|
||||
public:
|
||||
Color color(Vertex_const_handle, Mark m) const
|
||||
{ return ( m ? CGAL::BLACK : CGAL::WHITE ); }
|
||||
Color color(Halfedge_const_handle, Mark m) const
|
||||
{ return ( m ? CGAL::BLACK : CGAL::WHITE ); }
|
||||
Color color(Halfloop_const_handle, Mark m) const
|
||||
{ return ( m ? CGAL::BLACK : CGAL::WHITE ); }
|
||||
Color color(Face_const_handle, Mark m) const
|
||||
{ return ( m ? DGREY : LGREY ); }
|
||||
};
|
||||
|
||||
|
||||
/*{\Moptions outfile=SM_visualizor.man }*/
|
||||
/*{\Manpage {SM_visualizor}{Sphere_map_,Sphere_kernel_}
|
||||
{Drawing plane maps}{V}}*/
|
||||
|
||||
template <typename Sphere_map_, typename Sphere_kernel_,
|
||||
typename Color_ = SM_BooleColor<Sphere_map_> >
|
||||
class SM_visualizor : public
|
||||
SM_triangulator< SM_decorator<Sphere_map_,Sphere_kernel_> >
|
||||
{
|
||||
/*{\Mdefinition An instance |\Mvar| of the data type |\Mname| is a
|
||||
decorator to draw the structure of a sphere map into the surface
|
||||
of a OpenGL sphere. It is generic with respect to the template
|
||||
concept.}*/
|
||||
|
||||
/*{\Mgeneralization SM_decorator}*/
|
||||
/*{\Mtypes 3}*/
|
||||
public:
|
||||
typedef Sphere_map_ Sphere_map;
|
||||
typedef Sphere_kernel_ Sphere_kernel;
|
||||
typedef SM_visualizor<Sphere_map_,Sphere_kernel_,Color_> Self;
|
||||
typedef SM_const_decorator<Sphere_map_,Sphere_kernel_> Explorer;
|
||||
typedef SM_decorator<Sphere_map_,Sphere_kernel_> Decorator;
|
||||
typedef SM_triangulator<Decorator> Base;
|
||||
|
||||
USING(Vertex_const_handle);
|
||||
USING(Halfedge_const_handle);
|
||||
USING(Face_const_handle);
|
||||
USING(Vertex_const_iterator);
|
||||
USING(Halfedge_const_iterator);
|
||||
USING(Face_const_iterator);
|
||||
USING(Mark);
|
||||
|
||||
typedef typename Sphere_kernel::Sphere_point Sphere_point;
|
||||
typedef typename Sphere_kernel::Sphere_segment Sphere_segment;
|
||||
typedef typename Sphere_kernel::Sphere_circle Sphere_circle;
|
||||
typedef typename Sphere_kernel::Sphere_triangle Sphere_triangle;
|
||||
|
||||
typedef Color_ Color_objects;
|
||||
/*{\Mtypemember The color data accessor.}*/
|
||||
|
||||
protected:
|
||||
Explorer E_;
|
||||
const Color_objects& CO_;
|
||||
Sphere_map MT_;
|
||||
CGAL::OGL::Unit_sphere& S_;
|
||||
public:
|
||||
|
||||
/*{\Mcreation 4}*/
|
||||
SM_visualizor(const Sphere_map& M, CGAL::OGL::Unit_sphere& S,
|
||||
const Color_objects& C = Color_objects())
|
||||
/*{\Mcreate creates an instance |\Mvar| of type |\Mname| to visualize
|
||||
the vertices, edges, and faces of |D| in an open GL window.}*/
|
||||
: Base(M,MT_), E_(M), CO_(C), MT_(), S_(S)
|
||||
{ triangulate(); }
|
||||
|
||||
/*{\Moperations 2 1}*/
|
||||
|
||||
/* |draw_map| draws all object of the referenced sphere map:
|
||||
1) edges, loops, and vertices are taken from E_
|
||||
2) faces are drawn via the calculated triangulation in MT_ */
|
||||
|
||||
void draw_map() const
|
||||
/*{\Mop draw the whole plane map.}*/
|
||||
{
|
||||
// draw sphere segments underlying edges of E_:
|
||||
Halfedge_const_iterator e;
|
||||
CGAL::Unique_hash_map<Halfedge_const_iterator,bool> Done(false);
|
||||
CGAL_forall_halfedges(e,E_) {
|
||||
if ( Done[e] ) continue;
|
||||
if ( source(e) == target(e) ) {
|
||||
S_.push_back(E_.circle(e), CO_.color(e,E_.mark(e)));
|
||||
} else {
|
||||
S_.push_back(Sphere_segment(E_.point(E_.source(e)),
|
||||
E_.point(E_.target(e)),
|
||||
E_.circle(e)),CO_.color(e,E_.mark(e)));
|
||||
}
|
||||
Done[e]=Done[E_.twin(e)]=true;
|
||||
}
|
||||
// draw sphere circles underlying loops of E_:
|
||||
|
||||
if ( E_.has_loop() )
|
||||
S_.push_back(
|
||||
Sphere_circle(E_.circle(E_.halfloop())),
|
||||
CO_.color(E_.halfloop(),E_.mark(E_.halfloop())));
|
||||
|
||||
// draw points underlying vertices of E_:
|
||||
Vertex_const_iterator v;
|
||||
CGAL_forall_vertices(v,E_)
|
||||
S_.push_back(E_.point(v),CO_.color(v,E_.mark(v)));
|
||||
|
||||
CGAL_forall_halfedges(e,*this) {
|
||||
if ( Done[e] ) continue;
|
||||
Halfedge_const_handle en(next(e)),enn(next(en));
|
||||
TRACEV(Base::incident_triangle(e));
|
||||
TRACEN(incident_mark(e)<<incident_mark(en)<<incident_mark(enn));
|
||||
CGAL_assertion(Base::incident_mark(e)==Base::incident_mark(en) &&
|
||||
Base::incident_mark(en)==Base::incident_mark(enn));
|
||||
Mark m = Base::incident_mark(e);
|
||||
Sphere_triangle t = Base::incident_triangle(e);
|
||||
S_.push_back(t, (m ? DGREY : LGREY) );
|
||||
Done[e]=Done[en]=Done[enn]=true;
|
||||
}
|
||||
|
||||
Done.clear(false);
|
||||
CGAL_forall_halfedges(e,*this) {
|
||||
if ( Done[e] ) continue;
|
||||
S_.push_back_triangle_edge(Sphere_segment(E_.point(E_.source(e)),
|
||||
E_.point(E_.target(e)),
|
||||
E_.circle(e)));
|
||||
Done[e]=Done[twin(e)]=true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* |draw_triangulation| draws all object of the underlying triangulation:
|
||||
1) edges, loops, and vertices are taken from E_
|
||||
2) faces are drawn via the calculated triangulation in MT_ */
|
||||
|
||||
void draw_triangulation() const
|
||||
{
|
||||
CGAL::Unique_hash_map<Halfedge_const_iterator,bool> Done(false);
|
||||
// draw sphere segments underlying edges of triangulation:
|
||||
Halfedge_const_iterator e;
|
||||
CGAL_forall_halfedges(e,*this) {
|
||||
if ( Done[e] ) continue;
|
||||
S_.push_back(Sphere_segment(point(source(e)),point(target(e)),
|
||||
circle(e)),CO_.color(e,mark(e)));
|
||||
Done[e]=Done[twin(e)]=true;
|
||||
}
|
||||
|
||||
// draw points underlying vertices of triangulation:
|
||||
Vertex_const_iterator v;
|
||||
CGAL_forall_vertices(v,*this)
|
||||
S_.push_back(point(v),CO_.color(v,mark(v)));
|
||||
|
||||
Done.clear(false);
|
||||
CGAL_forall_halfedges(e,*this) {
|
||||
if ( Done[e] ) continue;
|
||||
Halfedge_const_handle en(next(e)),enn(next(en));
|
||||
CGAL_assertion(incident_mark(e)==incident_mark(en)&&
|
||||
incident_mark(en)==incident_mark(enn));
|
||||
Mark m = incident_mark(e);
|
||||
Sphere_triangle t = incident_triangle(e);
|
||||
S_.push_back(t, (m ? DGREY : LGREY) );
|
||||
Done[e]=Done[en]=Done[enn]=true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}; // end of SM_visualizor
|
||||
|
||||
|
||||
|
||||
|
||||
CGAL_END_NAMESPACE
|
||||
#undef USING
|
||||
//#undef LGREY
|
||||
//#undef DGREY
|
||||
#endif // SM_VISUALIZOR_H
|
||||
|
||||
|
|
@ -0,0 +1,130 @@
|
|||
#ifndef CGAL_SPHERE_CIRCLE_H
|
||||
#define CGAL_SPHERE_CIRCLE_H
|
||||
|
||||
#include <CGAL/basic.h>
|
||||
|
||||
CGAL_BEGIN_NAMESPACE
|
||||
|
||||
/*{\Manpage{Sphere_circle}{R}{Great circles on the unit sphere}{c}}*/
|
||||
|
||||
template <class R_> class Sphere_circle : public R_::Plane_3 {
|
||||
|
||||
/*{\Mdefinition An object |\Mvar| of type |\Mname| is an oriented
|
||||
great circle on the surface of a unit sphere. Such circles correspond
|
||||
to the intersection of an oriented plane (that contains the origin)
|
||||
and the surface of $S_2$. The orientation of the great circle is that
|
||||
of a counterclockwise walk along the circle as seen from the positive
|
||||
halfspace of the oriented plane.}*/
|
||||
|
||||
public:
|
||||
|
||||
/*{\Mtypes 5}*/
|
||||
typedef R_ R;
|
||||
/*{\Mtypemember representation class.}*/
|
||||
typedef typename R::RT RT;
|
||||
/*{\Mtypemember ring type.}*/
|
||||
typedef std::pair< Sphere_segment<R>,Sphere_segment<R> >
|
||||
Sphere_segment_pair;
|
||||
/*{\Mtypemember sphere segment pair.}*/
|
||||
|
||||
typedef typename R_::Plane_3 Plane_3;
|
||||
typedef typename R_::Point_3 Point_3;
|
||||
typedef Sphere_circle<R_> Self;
|
||||
typedef typename R_::Plane_3 Base;
|
||||
|
||||
/*{\Mcreation 5}*/
|
||||
Sphere_circle() : Base() {}
|
||||
/*{\Mcreate creates some great circle.}*/
|
||||
|
||||
Sphere_circle(const Sphere_point<R>& p, const Sphere_point<R>&q)
|
||||
: Base(Point_3(0,0,0),p,q)
|
||||
/*{\Mcreate creates a great circle through $p$ and $q$. If $p$ and
|
||||
$q$ are not opposite on $S_2$, then this circle is unique and oriented
|
||||
such that a walk along |\Mvar| meets $p$ just before the shorter segment
|
||||
between $p$ and $q$. If $p$ and $q$ are opposite of each other then we
|
||||
create any great circle that contains $p$ and $q$.}*/
|
||||
{ Point_3 p1(0,0,0), p4 = CGAL::ORIGIN + orthogonal_vector();
|
||||
if ( p != q.opposite() ) {
|
||||
if ( CGAL::orientation(p1,p,q,p4) != CGAL::POSITIVE )
|
||||
*this = Self(opposite());
|
||||
} else {
|
||||
*this = Self(Plane_3(p1,q-p));
|
||||
}
|
||||
}
|
||||
|
||||
Sphere_circle(const CGAL::Plane_3<R>& h)
|
||||
/*{\Mcreate creates the circle corresponding to the plane |h|.
|
||||
\precond |h| contains the origin.}*/
|
||||
: Base(h) { CGAL_assertion(h.d() == 0); }
|
||||
|
||||
Sphere_circle(const RT& x, const RT& y, const RT& z) : Base(x,y,z,0) {}
|
||||
/*{\Mcreate creates the circle orthogonal to the vector $(x,y,z)$.}*/
|
||||
|
||||
Sphere_circle(Sphere_circle<R> c, const Sphere_point<R>& p)
|
||||
/*{\Mcreate creates a great circle orthogonal to $c$ that contains $p$.
|
||||
\precond $p$ is not part of $c$.}*/
|
||||
{ CGAL_assertion(!c.has_on(p));
|
||||
if ( c.has_on_negative_side(p) ) c=c.opposite();
|
||||
if ( p == c.orthogonal_pole() )
|
||||
*this = Sphere_circle<R>(Base(Point_3(0,0,0),p,CGAL::ORIGIN+c.base1()));
|
||||
else
|
||||
*this = Sphere_circle<R>(Base(Point_3(0,0,0),p,c.orthogonal_pole()));
|
||||
}
|
||||
|
||||
/*{\Moperations 4 2}*/
|
||||
|
||||
Sphere_circle<R> opposite() const
|
||||
/*{\Mop returns the opposite of |\Mvar|.}*/
|
||||
{ return Base::opposite(); }
|
||||
|
||||
bool has_on(const Sphere_point<R>& p) const
|
||||
/*{\Mop returns true iff |\Mvar| contains |p|.}*/
|
||||
{ return Base::has_on(p); }
|
||||
|
||||
Plane_3 plane() const { return Base(*this); }
|
||||
/*{\Mop returns the plane supporting |\Mvar|.}*/
|
||||
|
||||
Sphere_point<R> orthogonal_pole() const
|
||||
/*{\Mop returns the point that is the pole of the
|
||||
hemisphere left of |\Mvar|.}*/
|
||||
{ return CGAL::ORIGIN+orthogonal_vector(); }
|
||||
|
||||
Sphere_segment_pair split_at(const Sphere_point<R>& p) const;
|
||||
/*{\Mop returns the pair of circle segments that is the result
|
||||
of splitting |\Mvar| at |p| and |p.opposite()|.}*/
|
||||
|
||||
Sphere_segment_pair split_at_xy_plane() const;
|
||||
/*{\Mop returns the pair of circle segments that is the result
|
||||
of splitting |\Mvar| at the $x$-$y$-coordinate plane if |\Mvar|
|
||||
is not part of it. Otherwise |\Mvar| is split at the
|
||||
$x$-$z$-coordinate plane.}*/
|
||||
|
||||
}; // Sphere_circle<R>
|
||||
|
||||
/*{\Mtext\headerline{Global functions}}*/
|
||||
|
||||
template <class R>
|
||||
bool equal_as_sets(const CGAL::Sphere_circle<R>& c1,
|
||||
const CGAL::Sphere_circle<R>& c2)
|
||||
/*{\Mfunc returns true iff |c1| and |c2| are equal as unoriented
|
||||
circles.}*/
|
||||
{ return c1==c2 || c1==c2.opposite(); }
|
||||
|
||||
template <typename R>
|
||||
Sphere_point<R> intersection(const Sphere_circle<R>& c1,
|
||||
const Sphere_circle<R>& c2)
|
||||
/*{\Mfunc returns one of the two intersection points of
|
||||
|c1| and |c2|. \precond |c1 != c2| as sets.}*/
|
||||
{
|
||||
CGAL_assertion(!equal_as_sets(c1,c2));
|
||||
typename R::Line_3 lres;
|
||||
TRACEN("circle_intersection "<<c1<<" "<<c2);
|
||||
CGAL::Object o = CGAL::intersection(c1.plane(),c2.plane());
|
||||
if ( !assign(lres,o) ) CGAL_assertion_msg(0,"damn id planes.");
|
||||
return CGAL::ORIGIN + lres.direction().vector();
|
||||
}
|
||||
|
||||
|
||||
|
||||
CGAL_END_NAMESPACE
|
||||
#endif //CGAL_SPHERE_CIRCLE_H
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
#ifndef CGAL_SPHERE_DIRECTION_H
|
||||
#define CGAL_SPHERE_DIRECTION_H
|
||||
|
||||
#include <CGAL/basic.h>
|
||||
|
||||
CGAL_BEGIN_NAMESPACE
|
||||
|
||||
/*{\Manpage{Sphere_direction}{R}{Directions on the unit sphere}{c}}*/
|
||||
|
||||
template <class R_> class Sphere_direction : public R_::Plane_3 {
|
||||
|
||||
/*{\Mdefinition An object |\Mvar| of type |\Mname| is a direction
|
||||
on the surface of the unit sphere. Such directions can be used to
|
||||
describe walks that are part of great circles.}*/
|
||||
|
||||
public:
|
||||
|
||||
/*{\Mtypes 5}*/
|
||||
typedef R_ R;
|
||||
/*{\Mtypemember representation class.}*/
|
||||
typedef typename R::RT RT;
|
||||
/*{\Mtypemember ring type.}*/
|
||||
|
||||
typedef typename R_::Point_3 Point_3;
|
||||
typedef typename R_::Plane_3 Plane_3;
|
||||
typedef typename R_::Plane_3 Base;
|
||||
typedef Sphere_direction<R_> Self;
|
||||
|
||||
/*{\Mcreation 5}*/
|
||||
Sphere_direction() : Base() {}
|
||||
/*{\Mcreate creates some direction.}*/
|
||||
|
||||
Sphere_direction(const Sphere_circle<R>& c)
|
||||
/*{\Mcreate creates the direction corresponding to the circle |c|.}*/
|
||||
: Base(c) {}
|
||||
|
||||
Sphere_direction(const Sphere_point<R>& p, const Sphere_point<R>&q)
|
||||
: Base(Point_3(0,0,0),p,q)
|
||||
/*{\Mcreate creates a direction that describes the orientation of
|
||||
the great circle through $p$ and $q$ (oriented such that the segment
|
||||
$pq$ is the shorter one of the two possible ones. \precond $p$ and $q$
|
||||
are not opposite on $S_2$.}*/
|
||||
{ CGAL_assertion(p!=q.opposite());
|
||||
Point_3 p1(0,0,0), p4 = CGAL::ORIGIN + orthogonal_vector();
|
||||
if ( CGAL::orientation(p1,p,q,p4) != CGAL::POSITIVE )
|
||||
*this = Sphere_direction(opposite());
|
||||
}
|
||||
|
||||
Sphere_direction(const CGAL::Plane_3<R>& h)
|
||||
/*{\Xcreate creates the direction corresponding to the plane |h|.
|
||||
\precond |h| contains the origin.}*/
|
||||
: Base(h) { CGAL_assertion(h.d() == 0); }
|
||||
|
||||
/*{\Moperations 4 2}*/
|
||||
|
||||
Sphere_direction<R> opposite() const
|
||||
/*{\Mop returns the opposite of |\Mvar|.}*/
|
||||
{ return Base::opposite(); }
|
||||
|
||||
Plane_3 plane() const { return Base(*this); }
|
||||
/*{\Xop returns the plane supporting |\Mvar|.}*/
|
||||
|
||||
}; // Sphere_direction<R>
|
||||
|
||||
|
||||
/* We have:
|
||||
1) all directions fixed at p
|
||||
2) d1==d3 possible
|
||||
return true iff d1,d2,d3 are stricly ccw ordered around p
|
||||
Note: Sphere_directions are Plane_3
|
||||
we therefore compare the normal vectors of the planes
|
||||
that underly the directions d1,d2,d3 in the plane
|
||||
through 0 and orthogonal to the vector p-0
|
||||
*/
|
||||
|
||||
template <typename R>
|
||||
bool strictly_ordered_ccw_at(const Sphere_point<R>& p,
|
||||
const Sphere_direction<R>& d1,
|
||||
const Sphere_direction<R>& d2,
|
||||
const Sphere_direction<R>& d3)
|
||||
{ CGAL_assertion(d1.has_on(p) && d2.has_on(p) && d3.has_on(p));
|
||||
typename R::Point_3 p0(0,0,0);
|
||||
typename R::Point_3 p1(CGAL::ORIGIN + d1.orthogonal_vector());
|
||||
typename R::Point_3 p2(CGAL::ORIGIN + d2.orthogonal_vector());
|
||||
typename R::Point_3 p3(CGAL::ORIGIN + d3.orthogonal_vector());
|
||||
|
||||
if ( d1 == d3 ) return false;
|
||||
if ( CGAL::orientation(p0,p,p1,p3) == CGAL::POSITIVE ) {
|
||||
return CGAL::orientation(p0,p,p1,p2) == CGAL::POSITIVE &&
|
||||
CGAL::orientation(p0,p,p3,p2) == CGAL::NEGATIVE;
|
||||
} else {
|
||||
return CGAL::orientation(p0,p,p1,p2) == CGAL::POSITIVE ||
|
||||
CGAL::orientation(p0,p,p3,p2) == CGAL::NEGATIVE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
CGAL_END_NAMESPACE
|
||||
#endif //CGAL_SPHERE_DIRECTION_H
|
||||
|
|
@ -0,0 +1,173 @@
|
|||
#ifndef CGAL_SPHERE_GEOMETRY_H
|
||||
#define CGAL_SPHERE_GEOMETRY_H
|
||||
|
||||
#include <CGAL/basic.h>
|
||||
#include <CGAL/intersection_3.h>
|
||||
#include <list>
|
||||
|
||||
#undef _DEBUG
|
||||
#define _DEBUG 113
|
||||
#include <CGAL/Nef_S2/debug.h>
|
||||
|
||||
CGAL_BEGIN_NAMESPACE
|
||||
|
||||
template <class R> class Sphere_point;
|
||||
template <class R> class Sphere_segment;
|
||||
template <class R> class Sphere_triangle;
|
||||
template <class R> class Sphere_circle;
|
||||
template <class R> class Sphere_direction;
|
||||
|
||||
CGAL_END_NAMESPACE
|
||||
|
||||
#include <CGAL/Nef_S2/Sphere_point.h>
|
||||
#include <CGAL/Nef_S2/Sphere_circle.h>
|
||||
#include <CGAL/Nef_S2/Sphere_direction.h>
|
||||
#include <CGAL/Nef_S2/Sphere_segment.h>
|
||||
#include <CGAL/Nef_S2/Sphere_triangle.h>
|
||||
#include <CGAL/Nef_S2/sphere_predicates.h>
|
||||
|
||||
CGAL_BEGIN_NAMESPACE
|
||||
|
||||
template <typename R_>
|
||||
struct Positive_halfsphere_geometry {
|
||||
|
||||
typedef R_ R;
|
||||
typedef CGAL::Sphere_point<R> Point_2;
|
||||
typedef CGAL::Sphere_segment<R> Segment_2;
|
||||
|
||||
Positive_halfsphere_geometry() {}
|
||||
|
||||
Point_2 source(const Segment_2& s) const
|
||||
{ return s.source(); }
|
||||
Point_2 target(const Segment_2& s) const
|
||||
{ return s.target(); }
|
||||
Segment_2 construct_segment(const Point_2& p, const Point_2& q) const
|
||||
{ return Segment_2(p,q); }
|
||||
|
||||
void xz_pi_half_rotate(Point_2& p) const
|
||||
{ p = Point_2(-p.hz(),p.hy(),p.hx()); }
|
||||
|
||||
int orientation(const Point_2& p1, const Point_2& p2,
|
||||
const Point_2& p3) const
|
||||
{ int or = CGAL::spherical_orientation(p1,p2,p3);
|
||||
if (or) return or;
|
||||
Point_2 pp1(p1), pp2(p2), pp3(p3);
|
||||
if ( !( p1.hz() == 0 && p2.hz() == 0 && p3.hz() == 0) ) return or;
|
||||
// or==0 we perturb any point in the xy-plane with x>0
|
||||
// by a negative rotation around the y-axis
|
||||
// our perturbation is big :-) we take PI/2 :
|
||||
if ( p1.hx()>0 ) xz_pi_half_rotate(pp1);
|
||||
if ( p2.hx()>0 ) xz_pi_half_rotate(pp2);
|
||||
if ( p3.hx()>0 ) xz_pi_half_rotate(pp3);
|
||||
return CGAL::spherical_orientation(pp1,pp2,pp3);
|
||||
}
|
||||
|
||||
int orientation(const Segment_2& s, const Point_2& p) const
|
||||
{ return orientation(s.source(),s.target(),p); }
|
||||
|
||||
bool is_degenerate(const Segment_2& s) const
|
||||
{ return s.is_degenerate(); }
|
||||
|
||||
int compare_xy(const Point_2& p1, const Point_2& p2) const
|
||||
{ return CGAL::spherical_compare(p1,p2,+1); }
|
||||
|
||||
Point_2 intersection(const Segment_2& s1, const Segment_2& s2) const
|
||||
{ if (s1.sphere_circle() != s2.sphere_circle().opposite())
|
||||
return s1.intersection(s2);
|
||||
CGAL_assertion(s1.target()==s2.target());
|
||||
return s1.target();
|
||||
}
|
||||
|
||||
}; // Positive_halfsphere_geometry<R>
|
||||
|
||||
template <typename R>
|
||||
struct Negative_halfsphere_geometry :
|
||||
public Positive_halfsphere_geometry<R> {
|
||||
|
||||
typedef Positive_halfsphere_geometry<R> Base;
|
||||
typedef typename Base::Point_2 Point_2;
|
||||
typedef typename Base::Segment_2 Segment_2;
|
||||
|
||||
Negative_halfsphere_geometry() {}
|
||||
|
||||
int orientation(const Point_2& p1, const Point_2& p2,
|
||||
const Point_2& p3) const
|
||||
{ int or = CGAL::spherical_orientation(p1,p2,p3);
|
||||
if (or) return or;
|
||||
Point_2 pp1(p1), pp2(p2), pp3(p3);
|
||||
if ( !( p1.hz() == 0 && p2.hz() == 0 && p3.hz() == 0) ) return or;
|
||||
// or==0 we perturb any point in the xy-plane with x>0
|
||||
// by a negative rotation around the y-axis
|
||||
// our perturbation is big :-) we take PI/2 :
|
||||
if ( p1.hx()<0 ) xz_pi_half_rotate(pp1);
|
||||
if ( p2.hx()<0 ) xz_pi_half_rotate(pp2);
|
||||
if ( p3.hx()<0 ) xz_pi_half_rotate(pp3);
|
||||
return CGAL::spherical_orientation(pp1,pp2,pp3);
|
||||
}
|
||||
|
||||
int orientation(const Segment_2& s, const Point_2& p) const
|
||||
{ return orientation(s.source(),s.target(),p); }
|
||||
|
||||
int compare_xy(const Point_2& p1, const Point_2& p2) const
|
||||
{ return CGAL::spherical_compare(p1,p2,-1); }
|
||||
|
||||
}; // Negative_halfsphere_geometry<R>
|
||||
|
||||
|
||||
template <typename R_>
|
||||
struct Sphere_geometry {
|
||||
|
||||
typedef R_ R;
|
||||
typedef typename R_::RT RT;
|
||||
typedef typename R_::FT FT;
|
||||
typedef CGAL::Sphere_point<R> Sphere_point;
|
||||
typedef CGAL::Sphere_segment<R> Sphere_segment;
|
||||
typedef CGAL::Sphere_circle<R> Sphere_circle;
|
||||
typedef CGAL::Sphere_direction<R> Sphere_direction;
|
||||
typedef CGAL::Sphere_triangle<R> Sphere_triangle;
|
||||
typedef CGAL::Point_3<R> Point_3;
|
||||
typedef CGAL::Plane_3<R> Plane_3;
|
||||
typedef Positive_halfsphere_geometry<R> Positive_halfsphere_geometry;
|
||||
typedef Negative_halfsphere_geometry<R> Negative_halfsphere_geometry;
|
||||
|
||||
Sphere_point source(const Sphere_segment& s) const
|
||||
{ return s.source(); }
|
||||
|
||||
Sphere_point target(const Sphere_segment& s) const
|
||||
{ return s.target(); }
|
||||
|
||||
Sphere_segment construct_segment(const Sphere_point& p,
|
||||
const Sphere_point& q) const
|
||||
{ return Sphere_segment(p,q); }
|
||||
|
||||
Sphere_segment construct_segment(const Sphere_point& p,
|
||||
const Sphere_point& q,
|
||||
const Plane_3& h) const
|
||||
{ return Sphere_segment(p,q,h); }
|
||||
|
||||
|
||||
Plane_3 affine_representation(const Plane_3& h, const Point_3& p) const
|
||||
{ RT wp = p.hw();
|
||||
return Plane_3(wp*h.a(),wp*h.b(),wp*h.c(),
|
||||
-(p.hx()*h.a() + p.hy()*h.b() + p.hz()*h.c())); }
|
||||
|
||||
Plane_3 linear_representation(const Plane_3& h) const
|
||||
{ return Plane_3(h.a(),h.b(),h.c(),0); }
|
||||
|
||||
Positive_halfsphere_geometry PHG;
|
||||
const Positive_halfsphere_geometry&
|
||||
get_positive_halfsphere_geometry() const
|
||||
{ return PHG; }
|
||||
|
||||
Negative_halfsphere_geometry NHG;
|
||||
const Negative_halfsphere_geometry&
|
||||
get_negative_halfsphere_geometry() const
|
||||
{ return NHG; }
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
CGAL_END_NAMESPACE
|
||||
#endif //CGAL_SPHERE_GEOMETRY_H
|
||||
|
||||
|
|
@ -0,0 +1,923 @@
|
|||
#ifndef CGAL_SPHERE_GEOMETRY_OGL_H
|
||||
#define CGAL_SPHERE_GEOMETRY_OGL_H
|
||||
|
||||
#include <CGAL/Simple_cartesian.h>
|
||||
#include <CGAL/Nef_S2/Sphere_geometry.h>
|
||||
#include <CGAL/IO/Color.h>
|
||||
#include <GL/glut.h>
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#undef _DEBUG
|
||||
#define _DEBUG 151
|
||||
#include <CGAL/Nef_S2/debug.h>
|
||||
|
||||
CGAL_BEGIN_NAMESPACE
|
||||
namespace OGL {
|
||||
|
||||
struct Gen_object {
|
||||
Gen_object() {}
|
||||
virtual ~Gen_object() {}
|
||||
virtual void draw() const {}
|
||||
virtual Gen_object* clone() const { return 0; }
|
||||
virtual void print() const {}
|
||||
};
|
||||
|
||||
typedef CGAL::Simple_cartesian<double> VKernel;
|
||||
typedef VKernel::Vector_3 VVector;
|
||||
typedef VKernel::Point_3 VPoint;
|
||||
typedef VKernel::Aff_transformation_3 VTrafo;
|
||||
typedef std::vector<VPoint> VSegment;
|
||||
typedef VKernel::Triangle_3 DTriangle;
|
||||
typedef std::vector<DTriangle> VTriangle;
|
||||
|
||||
const double refinement_angle = 0.1;
|
||||
const double shrink_fac = 0.995;
|
||||
|
||||
template <typename R>
|
||||
VVector convert(const CGAL::Vector_3<R>& v)
|
||||
{ return VVector(CGAL::to_double(v.x()),
|
||||
CGAL::to_double(v.y()),
|
||||
CGAL::to_double(v.z())); }
|
||||
|
||||
template <typename R>
|
||||
VPoint approximate(const CGAL::Sphere_point<R>& p)
|
||||
{
|
||||
VVector v = convert(p-CGAL::ORIGIN);
|
||||
v = v / CGAL_NTS sqrt(v*v) ; // normalize
|
||||
return CGAL::ORIGIN+v;
|
||||
}
|
||||
|
||||
template <class R_>
|
||||
class Sphere_point : public VPoint, public Gen_object {
|
||||
typedef R_ R;
|
||||
CGAL::Sphere_point<R> p_;
|
||||
CGAL::Color c_;
|
||||
unsigned w_;
|
||||
public:
|
||||
Sphere_point() {}
|
||||
Sphere_point(const CGAL::Sphere_point<R>& p,
|
||||
CGAL::Color c = CGAL::BLACK, unsigned w = 10) :
|
||||
VPoint(approximate(p)), p_(p), c_(c), w_(w) {}
|
||||
Sphere_point(const Sphere_point<R>& p) : VPoint(p)
|
||||
{ p_ = p.p_; c_ = p.c_; w_ = p.w_; }
|
||||
Sphere_point<R>& operator=(const Sphere_point<R>& p)
|
||||
{ VPoint::operator=(p); p_ = p.p_; c_ = p.c_; w_ = p.w_;
|
||||
return *this; }
|
||||
|
||||
virtual ~Sphere_point() {}
|
||||
|
||||
const CGAL::Sphere_point<R>& original() const
|
||||
{ return p_; }
|
||||
|
||||
virtual Gen_object* clone() const
|
||||
{ return new Sphere_point<R>(*this); }
|
||||
|
||||
virtual void draw() const
|
||||
{ glPointSize(w_);
|
||||
glColor3ub(c_.red(),c_.green(),c_.blue());
|
||||
glBegin(GL_POINTS);
|
||||
glNormal3d(x(),y(),z());
|
||||
glVertex3d(x(),y(),z());
|
||||
glEnd();
|
||||
}
|
||||
|
||||
virtual void print() const
|
||||
{ std::cerr << "point " << p_; }
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
template <typename R>
|
||||
VSegment approximate(const CGAL::Sphere_segment<R>& s)
|
||||
{
|
||||
/* we construct the rotation matrix that transfers the x-axis
|
||||
into |ps_|, the z-axis into h_.orthogonal_vector() and the
|
||||
y-axix into the corresponding crossproduct of the two.*/
|
||||
if ( s.is_degenerate() ) {
|
||||
VSegment S(1);
|
||||
S[0] = approximate(s.source());
|
||||
return S;
|
||||
}
|
||||
|
||||
VVector v0 = convert(s.source()-CGAL::ORIGIN);
|
||||
VVector v2 = convert(s.sphere_circle().orthogonal_vector());
|
||||
VVector v1(-cross_product(v0,v2));
|
||||
VVector v3 = convert(s.target()-CGAL::ORIGIN);
|
||||
double v0l = CGAL_NTS sqrt(v0*v0);
|
||||
double v1l = CGAL_NTS sqrt(v1*v1);
|
||||
double v2l = CGAL_NTS sqrt(v2*v2);
|
||||
double v3l = CGAL_NTS sqrt(v3*v3);
|
||||
double cosalpha = v0*v3 / v0l / v3l;
|
||||
double alpha = acos(cosalpha);
|
||||
const int units_per_halfcircle = 50;
|
||||
int units = int(units_per_halfcircle/M_PI * alpha);
|
||||
if (units == 0) ++units;
|
||||
bool seg_is_short = s.is_short();
|
||||
bool seg_is_halfcircle = s.is_halfcircle();
|
||||
if ( seg_is_halfcircle ) units = units_per_halfcircle;
|
||||
else if ( !seg_is_short ) {
|
||||
units = 2*units_per_halfcircle - (units+1);
|
||||
} TRACEV(units); TRACEV(cosalpha); TRACEV(alpha);
|
||||
|
||||
v0 = v0 / v0l;
|
||||
v1 = v1 / v1l;
|
||||
v2 = v2 / v2l;
|
||||
v3 = v3 / v3l;
|
||||
VTrafo T(v0.x(),v1.x(),v2.x(),
|
||||
v0.y(),v1.y(),v2.y(),
|
||||
v0.z(),v1.z(),v2.z());
|
||||
VSegment S(units+1);
|
||||
for (int i=0; i<units; ++i)
|
||||
S[i] = VPoint(cos(M_PI*i/double(units_per_halfcircle)),
|
||||
sin(M_PI*i/double(units_per_halfcircle)),
|
||||
0.0);
|
||||
double sinalpha = 1 - cosalpha*cosalpha;
|
||||
if (sinalpha <0) sinalpha = 0;
|
||||
else sinalpha = CGAL_NTS sqrt(sinalpha);
|
||||
if ( seg_is_short )
|
||||
S[units] = VPoint(cosalpha, sinalpha, 0);
|
||||
else
|
||||
S[units] = VPoint(cosalpha, -sinalpha, 0);
|
||||
VSegment::iterator it;
|
||||
for(it = S.begin(); it != S.end(); ++it) { TRACEN(*it<<" "<<T(*it));
|
||||
*it = T(*it);
|
||||
} TRACEN("");
|
||||
return S;
|
||||
}
|
||||
|
||||
|
||||
template <class R_>
|
||||
class Sphere_segment : public VSegment, public Gen_object {
|
||||
typedef R_ R;
|
||||
CGAL::Sphere_segment<R> s_;
|
||||
CGAL::Color c_;
|
||||
unsigned w_;
|
||||
public:
|
||||
Sphere_segment() {}
|
||||
Sphere_segment(const CGAL::Sphere_segment<R>& s,
|
||||
CGAL::Color c = CGAL::BLACK, unsigned w = 2)
|
||||
: VSegment(approximate(s)), s_(s), c_(c), w_(w) {}
|
||||
Sphere_segment(const Sphere_segment<R>& s) : VSegment(s)
|
||||
{ s_ = s.s_; c_ = s.c_; w_ = s.w_; }
|
||||
Sphere_segment<R>& operator=(const Sphere_segment<R>& s)
|
||||
{ VSegment::operator=(s); s_ = s.s_; c_ = s.c_; w_ = s.w_;
|
||||
return *this; }
|
||||
virtual ~Sphere_segment() {}
|
||||
|
||||
const CGAL::Sphere_segment<R>& original() const
|
||||
{ return s_; }
|
||||
|
||||
virtual Gen_object* clone() const
|
||||
{ return new Sphere_segment<R>(*this); }
|
||||
|
||||
virtual void draw() const
|
||||
{ TRACEN("draw "<<s_);
|
||||
if ( size() == 1 ) {
|
||||
glPointSize(5*w_);
|
||||
glColor3ub(c_.red(),c_.green(),c_.blue());
|
||||
glBegin(GL_POINTS);
|
||||
glNormal3d(begin()->x(),begin()->y(),begin()->z());
|
||||
glVertex3d(begin()->x(),begin()->y(),begin()->z());
|
||||
glEnd();
|
||||
} else {
|
||||
glLineWidth(w_);
|
||||
glColor3ub(c_.red(),c_.green(),c_.blue());
|
||||
glBegin(GL_LINE_STRIP);
|
||||
VSegment::const_iterator it;
|
||||
for(it = begin(); it != end(); ++it) {
|
||||
glNormal3d(it->x(),it->y(),it->z());
|
||||
glVertex3d(it->x(),it->y(),it->z());
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
}
|
||||
|
||||
virtual void print() const
|
||||
{ std::cerr << "segment " << s_; }
|
||||
|
||||
};
|
||||
|
||||
|
||||
template <typename R>
|
||||
VSegment approximate(const CGAL::Sphere_circle<R>& s)
|
||||
{
|
||||
/* we construct the rotation matrix that transfers the x-axis
|
||||
into |ps_|, the z-axis into h_.orthogonal_vector() and the
|
||||
y-axix into the corresponding crossproduct of the two.*/
|
||||
|
||||
VVector v0 = convert(s.base1());
|
||||
VVector v1 = convert(s.base2());
|
||||
VVector v2 = convert(s.orthogonal_vector());
|
||||
double v0l = CGAL_NTS sqrt(v0*v0);
|
||||
double v1l = CGAL_NTS sqrt(v1*v1);
|
||||
double v2l = CGAL_NTS sqrt(v2*v2);
|
||||
const int units = 100;
|
||||
v0 = v0 / v0l;
|
||||
v1 = v1 / v1l;
|
||||
v2 = v2 / v2l;
|
||||
VTrafo T(v0.x(),v1.x(),v2.x(),
|
||||
v0.y(),v1.y(),v2.y(),
|
||||
v0.z(),v1.z(),v2.z());
|
||||
VSegment S(units);
|
||||
for (int i=0; i<units; ++i)
|
||||
S[i] = VPoint(cos(2*M_PI*i/double(units)),
|
||||
sin(2*M_PI*i/double(units)),
|
||||
0.0);
|
||||
VSegment::iterator it;
|
||||
for(it = S.begin(); it != S.end(); ++it) *it = T(*it);
|
||||
return S;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <class R_>
|
||||
class Sphere_circle : public VSegment, public Gen_object {
|
||||
typedef R_ R;
|
||||
CGAL::Sphere_circle<R> s_;
|
||||
CGAL::Color c_;
|
||||
unsigned w_;
|
||||
public:
|
||||
Sphere_circle() {}
|
||||
Sphere_circle(const CGAL::Sphere_circle<R>& s,
|
||||
CGAL::Color c = CGAL::BLACK, unsigned w = 2)
|
||||
: VSegment(approximate(s)), s_(s), c_(c), w_(w) {}
|
||||
Sphere_circle(const Sphere_circle<R>& s) : VSegment(s)
|
||||
{ s_ = s.s_; c_ = s.c_; w_ = s.w_; }
|
||||
Sphere_circle<R>& operator=(const Sphere_circle<R>& s)
|
||||
{ VSegment::operator=(s); s_ = s.s_; c_ = s.c_; w_ = s.w_;
|
||||
return *this; }
|
||||
virtual ~Sphere_circle() {}
|
||||
|
||||
const CGAL::Sphere_circle<R>& original() const
|
||||
{ return s_; }
|
||||
|
||||
virtual Gen_object* clone() const
|
||||
{ return new Sphere_circle<R>(*this); }
|
||||
|
||||
virtual void draw() const
|
||||
{ TRACEN("draw "<<s_);
|
||||
glLineWidth(w_);
|
||||
glColor3ub(c_.red(),c_.green(),c_.blue());
|
||||
glBegin(GL_LINE_LOOP);
|
||||
VSegment::const_iterator it;
|
||||
for(it = begin(); it != end(); ++it)
|
||||
glNormal3d(it->x(),it->y(),it->z());
|
||||
glVertex3d(it->x(),it->y(),it->z());
|
||||
glEnd();
|
||||
}
|
||||
|
||||
virtual void print() const
|
||||
{ std::cerr << "circle " << s_; }
|
||||
|
||||
};
|
||||
|
||||
|
||||
/* The following class approximates a spherical triangle by a list
|
||||
of flat triangles */
|
||||
|
||||
template <class R_>
|
||||
class Sphere_triangle : public VTriangle, public Gen_object {
|
||||
typedef R_ R;
|
||||
CGAL::Sphere_triangle<R> t_;
|
||||
CGAL::Color c_;
|
||||
public:
|
||||
Sphere_triangle() {}
|
||||
|
||||
Sphere_triangle(const CGAL::Sphere_triangle<R>& t,
|
||||
CGAL::Color c = CGAL::GREY)
|
||||
: VTriangle(approximate(t)), t_(t), c_(c) {}
|
||||
|
||||
Sphere_triangle(const Sphere_triangle<R>& t) : VTriangle(t)
|
||||
{ t_ = t.t_; c_ = t.c_; }
|
||||
|
||||
Sphere_triangle<R>& operator=(const Sphere_triangle<R>& t)
|
||||
{ VTriangle::operator=(t); t_ = t.t_; c_ = s.c_; return *this; }
|
||||
|
||||
virtual ~Sphere_triangle() {}
|
||||
|
||||
const CGAL::Sphere_triangle<R>& original() const
|
||||
{ return t_; }
|
||||
|
||||
virtual Gen_object* clone() const
|
||||
{ return new Sphere_triangle<R>(*this); }
|
||||
|
||||
virtual void draw() const
|
||||
{ TRACEN("draw "<<t_);
|
||||
VTriangle::const_iterator it;
|
||||
VPoint p;
|
||||
glColorMaterial(GL_FRONT, GL_DIFFUSE);
|
||||
glEnable(GL_COLOR_MATERIAL);
|
||||
glColor3ub(c_.red(),c_.green(),c_.blue());
|
||||
glBegin(GL_TRIANGLES);
|
||||
for(it = begin(); it != end(); ++it) {
|
||||
p = it->vertex(0);
|
||||
glNormal3d(p.x(),p.y(),p.z()); //glVertex3d(p.x(),p.y(),p.z());
|
||||
glVertex3d(shrink_fac*p.x(),shrink_fac*p.y(),shrink_fac*p.z());
|
||||
p = it->vertex(1);
|
||||
glNormal3d(p.x(),p.y(),p.z());
|
||||
glVertex3d(shrink_fac*p.x(),shrink_fac*p.y(),shrink_fac*p.z());
|
||||
p = it->vertex(2);
|
||||
glNormal3d(p.x(),p.y(),p.z());
|
||||
glVertex3d(shrink_fac*p.x(),shrink_fac*p.y(),shrink_fac*p.z());
|
||||
}
|
||||
glEnd();
|
||||
glDisable(GL_COLOR_MATERIAL);
|
||||
}
|
||||
|
||||
virtual void print() const
|
||||
{ std::cerr << "triangle " << t_; }
|
||||
|
||||
};
|
||||
|
||||
/* the following operation refines a sphere triangle as a list of flat
|
||||
triangles in 3d. The refinement only works for triangles that are
|
||||
contained in a perfect hemisphere (no long sphere segments are
|
||||
allowed as triangle segments). We split triangles along at the
|
||||
midpoint of their longest side into two. */
|
||||
|
||||
void refine(const DTriangle& t, VTriangle& T)
|
||||
{
|
||||
double angle[3]; int i(0);
|
||||
angle[0] = acos((t[0]-CGAL::ORIGIN)*(t[1]-CGAL::ORIGIN));
|
||||
angle[1] = acos((t[1]-CGAL::ORIGIN)*(t[2]-CGAL::ORIGIN));
|
||||
angle[2] = acos((t[2]-CGAL::ORIGIN)*(t[0]-CGAL::ORIGIN));
|
||||
TRACEN("refine "<<angle[0]<<" "<<angle[1]<<" "<<angle[2]);
|
||||
if ( angle[1] > angle[0] ) {
|
||||
if ( angle[2] > angle[1] ) i=2;
|
||||
else i=1;
|
||||
} else { // angle[0] >= angle[1]
|
||||
if ( angle[2] > angle[0] ) i=2;
|
||||
else i=0;
|
||||
}
|
||||
// now i references the side of maximal angle
|
||||
if ( angle[i] < refinement_angle ) // refinement threshhold
|
||||
{ T.push_back(t); return; }
|
||||
VVector v;
|
||||
switch (i) {
|
||||
case 0: v = (t[0]-CGAL::ORIGIN)+(t[1]-CGAL::ORIGIN); break;
|
||||
case 1: v = (t[1]-CGAL::ORIGIN)+(t[2]-CGAL::ORIGIN); break;
|
||||
case 2: v = (t[2]-CGAL::ORIGIN)+(t[0]-CGAL::ORIGIN); break;
|
||||
}
|
||||
v = v / CGAL_NTS sqrt(v*v) ; // normalize
|
||||
VPoint p = CGAL::ORIGIN+v;
|
||||
DTriangle t1,t2;
|
||||
switch (i) {
|
||||
case 0: t1=DTriangle(t[0],p,t[2]); t2=DTriangle(p,t[1],t[2]); break;
|
||||
case 1: t1=DTriangle(t[1],p,t[0]); t2=DTriangle(p,t[2],t[0]); break;
|
||||
case 2: t1=DTriangle(t[2],p,t[1]); t2=DTriangle(p,t[0],t[1]); break;
|
||||
}
|
||||
refine(t1,T);
|
||||
refine(t2,T);
|
||||
}
|
||||
|
||||
template <typename R>
|
||||
VTriangle approximate(const CGAL::Sphere_triangle<R>& t)
|
||||
{
|
||||
/* we subdivide the triangle into a list of triangles until
|
||||
we reach a fine resolution on the surface.*/
|
||||
|
||||
VTriangle T;
|
||||
DTriangle td(approximate(t.point(0)),
|
||||
approximate(t.point(1)),
|
||||
approximate(t.point(2)));
|
||||
TRACEN("approximate " << td);
|
||||
refine(td,T);
|
||||
return T;
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// the sphere:
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
enum Sphere_map_mode {
|
||||
SM_FACES, SM_SKELETON, SM_TRIANGULATION
|
||||
};
|
||||
|
||||
class Unit_sphere {
|
||||
typedef std::list<Gen_object*> Object_list;
|
||||
typedef Object_list::const_iterator Object_const_iterator;
|
||||
typedef Object_list::iterator Object_iterator;
|
||||
|
||||
GLUquadricObj* sphere_;
|
||||
Sphere_map_mode style_;
|
||||
bool axes_, cube_, initialized_;
|
||||
Object_list objects_,triangles_,triangle_edges_;
|
||||
GLuint sphere_list_;
|
||||
|
||||
public:
|
||||
void init(Sphere_map_mode style = SM_FACES)
|
||||
{ style_ = style; axes_ = true; cube_ = false;
|
||||
gluQuadricNormals(sphere_,GLenum(GLU_SMOOTH));
|
||||
}
|
||||
|
||||
Unit_sphere(Sphere_map_mode style = SM_FACES)
|
||||
{ sphere_ = gluNewQuadric(); initialized_ = false; init(style); }
|
||||
|
||||
void clear_list()
|
||||
{ while ( objects_.begin() != objects_.end() ) {
|
||||
delete (*objects_.begin());
|
||||
objects_.pop_front();
|
||||
}
|
||||
while ( triangles_.begin() != triangles_.end() ) {
|
||||
delete (*triangles_.begin());
|
||||
triangles_.pop_front();
|
||||
}
|
||||
while ( triangle_edges_.begin() != triangle_edges_.end() ) {
|
||||
delete (*triangle_edges_.begin());
|
||||
triangle_edges_.pop_front();
|
||||
}
|
||||
}
|
||||
|
||||
void copy_list(const Unit_sphere& S)
|
||||
{ Object_const_iterator it;
|
||||
CGAL_forall_iterators (it,S.objects_)
|
||||
objects_.push_back( (*it)->clone() );
|
||||
CGAL_forall_iterators (it,S.triangles_)
|
||||
triangles_.push_back( (*it)->clone() );
|
||||
CGAL_forall_iterators (it,S.triangle_edges_)
|
||||
triangle_edges_.push_back( (*it)->clone() );
|
||||
}
|
||||
|
||||
void print() const
|
||||
{ std::cerr << "Dumping Unit_sphere:\n";
|
||||
for (Object_const_iterator it = objects_.begin();
|
||||
it != objects_.end(); ++it)
|
||||
(*it)->print();
|
||||
std::cerr << std::endl;
|
||||
for (Object_const_iterator it = triangles_.begin();
|
||||
it != triangles_.end(); ++it)
|
||||
(*it)->print();
|
||||
std::cerr << std::endl;
|
||||
}
|
||||
|
||||
Unit_sphere(const Unit_sphere& S)
|
||||
{ TRACEN("copyconstruction");
|
||||
sphere_ = gluNewQuadric();
|
||||
initialized_ = S.initialized_;
|
||||
style_ = S.style_;
|
||||
axes_ = S.axes_;
|
||||
cube_ = S.cube_;
|
||||
copy_list(S);
|
||||
}
|
||||
|
||||
|
||||
Unit_sphere& operator=(const Unit_sphere& S)
|
||||
{ TRACEN("assignment");
|
||||
initialized_ = S.initialized_;
|
||||
style_ = S.style_;
|
||||
axes_ = S.axes_;
|
||||
cube_ = S.cube_;
|
||||
clear_list(); copy_list(S);
|
||||
return *this;
|
||||
}
|
||||
|
||||
~Unit_sphere() { clear_list(); gluDeleteQuadric(sphere_); }
|
||||
|
||||
template <typename R>
|
||||
void push_back(const CGAL::Sphere_point<R>& p,
|
||||
CGAL::Color c = CGAL::YELLOW, unsigned w = 5)
|
||||
{ objects_.push_back(new Sphere_point<R>(p,c,w)); }
|
||||
|
||||
template <typename R>
|
||||
void push_back(const CGAL::Sphere_segment<R>& s,
|
||||
CGAL::Color c = CGAL::BLACK, unsigned w = 1)
|
||||
{ objects_.push_back(new Sphere_segment<R>(s,c,w)); }
|
||||
|
||||
template <typename R>
|
||||
void push_back(const CGAL::Sphere_circle<R>& s,
|
||||
CGAL::Color c = CGAL::BLACK, unsigned w = 1)
|
||||
{ objects_.push_back(new Sphere_circle<R>(s,c,w)); }
|
||||
|
||||
template <typename R>
|
||||
void push_back(const CGAL::Sphere_triangle<R>& t,
|
||||
CGAL::Color c = CGAL::WHITE)
|
||||
{ triangles_.push_back(new Sphere_triangle<R>(t,c)); }
|
||||
|
||||
template <typename R>
|
||||
void push_back_triangle_edge(const CGAL::Sphere_segment<R>& s,
|
||||
CGAL::Color c = CGAL::BLUE, unsigned w = 1)
|
||||
{ triangle_edges_.push_back(new Sphere_segment<R>(s,c,w)); }
|
||||
|
||||
void set_style(Sphere_map_mode style) { style_ = style; }
|
||||
void toggle_axes() { axes_ = !axes_; }
|
||||
void toggle_cube() { cube_ = !cube_; }
|
||||
|
||||
private:
|
||||
|
||||
void construct_axes() const
|
||||
{ int i;
|
||||
register double f(1.02);
|
||||
glNewList(sphere_list_+3, GL_COMPILE);
|
||||
glLineWidth(2.0);
|
||||
// red x-axis and equator
|
||||
glColor3f(1.0,0.0,0.0);
|
||||
glBegin(GL_LINES);
|
||||
glVertex3f(0.0,0.0,0.0);
|
||||
glVertex3f(1.2,0.0,0.0);
|
||||
glEnd();
|
||||
glBegin(GL_LINE_LOOP);
|
||||
for(i=0;i<100;i++)
|
||||
glVertex3d(f*cos(2.0*M_PI*i/100.0),f*sin(2.0*M_PI*i/100.0),0.0);
|
||||
glEnd();
|
||||
// green y-axis and equator
|
||||
glColor3f(0.0,1.0,0.0);
|
||||
glBegin(GL_LINES);
|
||||
glVertex3f(0.0,0.0,0.0);
|
||||
glVertex3f(0.0,1.2,0.0);
|
||||
glEnd();
|
||||
glBegin(GL_LINE_LOOP);
|
||||
for(i=0;i<100;i++)
|
||||
glVertex3d(0.0,f*cos(2.0*M_PI*i/100.0),f*sin(2.0*M_PI*i/100.0));
|
||||
glEnd();
|
||||
// blue z-axis and equator
|
||||
glColor3f(0.0,0.0,1.0);
|
||||
glBegin(GL_LINES);
|
||||
glVertex3f(0.0,0.0,0.0);
|
||||
glVertex3f(0.0,0.0,1.2);
|
||||
glEnd();
|
||||
glBegin(GL_LINE_LOOP);
|
||||
for(i=0;i<100;i++)
|
||||
glVertex3d(f*cos(2.0*M_PI*i/100.0),0.0,f*sin(2.0*M_PI*i/100.0));
|
||||
glEnd();
|
||||
// six coordinate points in pink:
|
||||
glPointSize(10);
|
||||
glColor3f(1,0,1);
|
||||
glBegin(GL_POINTS);
|
||||
glVertex3d(1,0,0);
|
||||
glVertex3d(0,1,0);
|
||||
glVertex3d(0,0,1);
|
||||
glVertex3d(-1,0,0);
|
||||
glVertex3d(0,-1,0);
|
||||
glVertex3d(0,0,-1);
|
||||
glEnd(); glEndList();
|
||||
}
|
||||
|
||||
void construct_cube() const
|
||||
{
|
||||
glNewList(sphere_list_+4, GL_COMPILE);
|
||||
glColor3f(1,1,0); // yellow
|
||||
glLineWidth(2.0);
|
||||
glBegin(GL_LINE_LOOP);
|
||||
glVertex3f(-1.0,-1.0,-1.0);
|
||||
glVertex3f( 1.0,-1.0,-1.0);
|
||||
glVertex3f( 1.0, 1.0,-1.0);
|
||||
glVertex3f(-1.0, 1.0,-1.0);
|
||||
glEnd();
|
||||
glBegin(GL_LINE_LOOP);
|
||||
glVertex3f(-1.0,-1.0, 1.0);
|
||||
glVertex3f( 1.0,-1.0, 1.0);
|
||||
glVertex3f( 1.0, 1.0, 1.0);
|
||||
glVertex3f(-1.0, 1.0, 1.0);
|
||||
glEnd();
|
||||
glBegin(GL_LINES);
|
||||
glVertex3f(-1.0,-1.0,-1.0);
|
||||
glVertex3f(-1.0,-1.0, 1.0);
|
||||
glVertex3f( 1.0,-1.0,-1.0);
|
||||
glVertex3f( 1.0,-1.0, 1.0);
|
||||
glVertex3f( 1.0, 1.0,-1.0);
|
||||
glVertex3f( 1.0, 1.0, 1.0);
|
||||
glVertex3f(-1.0, 1.0,-1.0);
|
||||
glVertex3f(-1.0, 1.0, 1.0);
|
||||
glEnd(); glEndList();
|
||||
}
|
||||
|
||||
void construct()
|
||||
{ initialized_=true;
|
||||
sphere_list_ = glGenLists(5);
|
||||
CGAL_assertion_msg(sphere_list_!=0,"no display list.");
|
||||
// skeleton:
|
||||
glNewList(sphere_list_, GL_COMPILE);
|
||||
for (Object_const_iterator it = objects_.begin();
|
||||
it != objects_.end(); ++it)
|
||||
(*it)->draw();
|
||||
glEndList();
|
||||
// triangles:
|
||||
glNewList(sphere_list_+1, GL_COMPILE);
|
||||
for (Object_const_iterator it = triangles_.begin();
|
||||
it != triangles_.end(); ++it)
|
||||
(*it)->draw();
|
||||
glEndList();
|
||||
glNewList(sphere_list_+2, GL_COMPILE);
|
||||
for (Object_const_iterator it = triangle_edges_.begin();
|
||||
it != triangle_edges_.end(); ++it)
|
||||
(*it)->draw();
|
||||
glEndList();
|
||||
// orientation features:
|
||||
construct_axes();
|
||||
construct_cube();
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
void draw() const
|
||||
{ gluQuadricDrawStyle(sphere_,style_);
|
||||
glEnable(GL_LIGHTING);
|
||||
if ( style_ == SM_SKELETON ) {
|
||||
glEnable(GL_COLOR_MATERIAL);
|
||||
glColor3f(0.7,0.7,0.7);
|
||||
gluSphere(sphere_,shrink_fac,50,50);
|
||||
glDisable(GL_COLOR_MATERIAL);
|
||||
}
|
||||
glDisable(GL_LIGHTING);
|
||||
if ( !initialized_ ) const_cast<Unit_sphere*>(this)->construct();
|
||||
if ( style_ == SM_FACES || style_ == SM_TRIANGULATION ) {
|
||||
glEnable(GL_LIGHTING);
|
||||
glCallList(sphere_list_+1); // triangle list
|
||||
glDisable(GL_LIGHTING);
|
||||
}
|
||||
if ( style_ == SM_TRIANGULATION ) {
|
||||
glCallList(sphere_list_+2); // triangle edge list
|
||||
}
|
||||
|
||||
if ( style_ != SM_TRIANGULATION ) {
|
||||
glCallList(sphere_list_);
|
||||
}
|
||||
if ( axes_ ) glCallList(sphere_list_+3);
|
||||
if ( cube_ ) glCallList(sphere_list_+4);
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
enum MenuEntries { ROTATE, SCALE, TRANSLATE, RESET_CONTROL,
|
||||
UNITY_CUBE, AXES,
|
||||
FACES, SKELETON, TRIANGULATION,
|
||||
QUIT };
|
||||
|
||||
int window_width = 300; // Breite und
|
||||
int window_height = 300; // Hoehe des Fensters
|
||||
|
||||
int mouse_x, mouse_y; // Mauskoordinaten linker button
|
||||
int mouse_left_button = false; // Mouse1 gedrueckt
|
||||
int motion_mode = ROTATE; // Bewegen der Maus bei Mouse1 gedrueckt
|
||||
int submenu1, submenu2;
|
||||
long double dx = 0; // Translation
|
||||
long double dy = 0; // Translation
|
||||
long double wx = 0; // Rotation
|
||||
long double wy = 0; // Rotation
|
||||
long double s = 1.5; // Skalierung
|
||||
|
||||
long double factor_d; // Umrechnungsfaktor fuer Translation
|
||||
long double factor_w; // Umrechnungsfaktor fuer Rotation
|
||||
long double factor_s; // Umrechnungsfaktor fuer Skalierung
|
||||
|
||||
// our draw object:
|
||||
static std::vector<Unit_sphere> spheres_;
|
||||
static std::vector<std::string> titles_;
|
||||
|
||||
void show (int mode)
|
||||
{
|
||||
std::vector<Unit_sphere>::iterator it;
|
||||
switch(mode)
|
||||
{
|
||||
case ROTATE:
|
||||
case SCALE:
|
||||
case TRANSLATE:
|
||||
motion_mode = mode;
|
||||
break;
|
||||
case RESET_CONTROL:
|
||||
dx = dy = wx = wy = 0.0;
|
||||
s = 1.5;
|
||||
motion_mode = ROTATE;
|
||||
CGAL_forall_iterators(it,spheres_) it->init();
|
||||
glutPostRedisplay();
|
||||
break;
|
||||
case UNITY_CUBE:
|
||||
CGAL_forall_iterators(it,spheres_) it->toggle_cube();
|
||||
glutPostRedisplay();
|
||||
break;
|
||||
case AXES:
|
||||
CGAL_forall_iterators(it,spheres_) it->toggle_axes();
|
||||
glutPostRedisplay();
|
||||
break;
|
||||
case FACES:
|
||||
CGAL_forall_iterators(it,spheres_) it->set_style(SM_FACES);
|
||||
glutPostRedisplay();
|
||||
break;
|
||||
case SKELETON:
|
||||
CGAL_forall_iterators(it,spheres_) it->set_style(SM_SKELETON);
|
||||
glutPostRedisplay();
|
||||
break;
|
||||
case TRIANGULATION:
|
||||
CGAL_forall_iterators(it,spheres_) it->set_style(SM_TRIANGULATION);
|
||||
glutPostRedisplay();
|
||||
break;
|
||||
case QUIT:
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Mausknopf gedrueckt
|
||||
void mouse (int button, int state, int x, int y)
|
||||
{
|
||||
if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
|
||||
{
|
||||
mouse_x = x;
|
||||
mouse_y = y;
|
||||
mouse_left_button = true;
|
||||
}
|
||||
else
|
||||
mouse_left_button = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Objekt rotieren, zoomen oder verschieben
|
||||
void motion (int x, int y)
|
||||
{
|
||||
if (mouse_left_button)
|
||||
{
|
||||
if (motion_mode == ROTATE)
|
||||
{
|
||||
wx += (y - mouse_y) * factor_w;
|
||||
// Mausbewegung in y-Richtung entspricht Rotation um die x-Achse
|
||||
wy += (x - mouse_x) * factor_w;
|
||||
// Mausbewegung in x-Richtung entspricht Rotation um die y-Achse
|
||||
}
|
||||
else if (motion_mode == SCALE)
|
||||
{
|
||||
s *= exp( (y - mouse_y) * factor_s );
|
||||
}
|
||||
else if (motion_mode == TRANSLATE)
|
||||
{
|
||||
dx += (x - mouse_x) * factor_d / s;
|
||||
dy -= (y - mouse_y) * factor_d / s;
|
||||
}
|
||||
mouse_x = x;
|
||||
mouse_y = y;
|
||||
glutPostRedisplay();
|
||||
}
|
||||
}
|
||||
|
||||
void init()
|
||||
{
|
||||
GLfloat mat_diffuse[4] = { 0.7, 0.7, 0.7, 1.0 };
|
||||
GLfloat mat_specular[4] = { 1.0, 1.0, 1.0, 1.0 };
|
||||
GLfloat mat_shininess[] = { 100.0 };
|
||||
GLfloat ambient_light[] = { 0.2, 0.2, 0.2, 1.0 };
|
||||
|
||||
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient_light);
|
||||
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mat_diffuse );
|
||||
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat_specular );
|
||||
glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, mat_shininess );
|
||||
//#define SCREENSHOTS
|
||||
#ifdef SCREENSHOTS
|
||||
GLfloat mat_emission[] = { 0.1, 0.1, 0.2, 0.0 };
|
||||
glMaterialfv(GL_FRONT, GL_EMISSION, mat_emission);
|
||||
//for screenshots enable this section
|
||||
#endif
|
||||
|
||||
GLfloat light0[4] = { 4.0, 4.0, 10.0, 1.0 };
|
||||
glLightfv (GL_LIGHT0, GL_POSITION, light0);
|
||||
glEnable (GL_LIGHT0);
|
||||
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glEnable(GL_AUTO_NORMAL);
|
||||
glEnable(GL_NORMALIZE);
|
||||
glEnable(GL_POINT_SMOOTH);
|
||||
}
|
||||
|
||||
void enter_leave(int state)
|
||||
{ glutPostRedisplay(); }
|
||||
|
||||
void draw()
|
||||
{
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
|
||||
glPushMatrix();
|
||||
glRotated(wy,0,1,0);
|
||||
glRotated(wx,1,0,0);
|
||||
glScaled(s,s,s);
|
||||
glTranslated(dx,dy,0.0);
|
||||
int win = glutGetWindow();
|
||||
//std::cerr << "WINDOW" << win << std::endl;
|
||||
spheres_[win-1].draw();
|
||||
glPopMatrix();
|
||||
glutSwapBuffers();
|
||||
}
|
||||
|
||||
void reshape(int width, int height)
|
||||
{
|
||||
window_width = width;
|
||||
window_height = height;
|
||||
|
||||
glViewport(0, 0, (GLint)width, (GLint)height);
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
|
||||
if (width>height)
|
||||
{
|
||||
long double w = (long double) width / (long double) height;
|
||||
glOrtho( -2*w, 2*w, -2.0, 2.0, -100.0, 100.0 );
|
||||
factor_d = 2.0 / (height/2.0);
|
||||
// halbe Fensterhoehe soll 2 LE entsprechen
|
||||
factor_w = 90.0 / (height/2.0);
|
||||
// halbe Fensterhoehe soll 90 Grad entsprechen
|
||||
factor_s = std::log(4.0) / (height/2.0);
|
||||
// halbe Fensterhoehe soll Faktor 4 entsprechen
|
||||
}
|
||||
else
|
||||
{
|
||||
long double h = (long double) height / (long double) width;
|
||||
glOrtho( -2.0, 2.0, -2*h, 2*h, -100.0, 100.0 );
|
||||
factor_d = 2.0 / (width/2.0);
|
||||
// halbe Fensterbreite soll 2 LE entsprechen
|
||||
factor_w = 90.0 / (width/2.0);
|
||||
// halbe Fensterbreite soll 90 Grad entsprechen
|
||||
factor_s = std::log(4.0) / (height/2.0);
|
||||
// halbe Fensterhoehe soll Faktor 4 entsprechen
|
||||
}
|
||||
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
}
|
||||
|
||||
void add_sphere()
|
||||
{ spheres_.push_back(Unit_sphere()); }
|
||||
|
||||
void start_viewer()
|
||||
{
|
||||
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
|
||||
glutInitWindowSize(window_width, window_height);
|
||||
glutInitWindowPosition(0,0);
|
||||
|
||||
int submenu1 = glutCreateMenu(show);
|
||||
glutAddMenuEntry("Reset",RESET_CONTROL);
|
||||
glutAddMenuEntry("Rotate",ROTATE);
|
||||
glutAddMenuEntry("Scale",SCALE);
|
||||
glutAddMenuEntry("Translate",TRANSLATE);
|
||||
|
||||
int submenu2 = glutCreateMenu(show);
|
||||
glutAddMenuEntry("Toggle Axes",AXES);
|
||||
glutAddMenuEntry("Toggle Unity Cube",UNITY_CUBE);
|
||||
|
||||
int submenu3 = glutCreateMenu(show);
|
||||
glutAddMenuEntry("Faces",FACES);
|
||||
glutAddMenuEntry("Skeleton",SKELETON);
|
||||
glutAddMenuEntry("Triangulation",TRIANGULATION);
|
||||
|
||||
//for (unsigned i = 0; i < spheres_.size(); ++i) spheres_[i].print();
|
||||
for (unsigned i = 0; i < spheres_.size(); ++i) {
|
||||
if (i > 0 ) glutInitWindowPosition(i*(window_width+12),0);
|
||||
if ( i < titles_.size() ) glutCreateWindow(titles_[i].c_str());
|
||||
else glutCreateWindow("Sphere Window");
|
||||
glutEntryFunc(enter_leave);
|
||||
init();
|
||||
glutDisplayFunc(draw);
|
||||
glutReshapeFunc(reshape);
|
||||
glutMouseFunc(mouse);
|
||||
glutMotionFunc(motion);
|
||||
glutCreateMenu(show);
|
||||
glutAddSubMenu("Control",submenu1);
|
||||
glutAddSubMenu("Render",submenu3);
|
||||
glutAddSubMenu("Options",submenu2);
|
||||
glutAddMenuEntry("Quit",QUIT);
|
||||
glutAttachMenu(GLUT_RIGHT_BUTTON);
|
||||
}
|
||||
|
||||
glutMainLoop();
|
||||
}
|
||||
|
||||
|
||||
} // OGL
|
||||
CGAL_END_NAMESPACE
|
||||
|
||||
|
||||
|
||||
template <class R>
|
||||
std::ostream& operator<<(std::ostream& os,
|
||||
const CGAL::OGL::Sphere_segment<R>& s)
|
||||
{ CGAL::OGL::VSegment::const_iterator it;
|
||||
os << s.original() << " ";
|
||||
for (it = s.begin(); it != s.end(); ++it)
|
||||
os << *it;
|
||||
return os;
|
||||
}
|
||||
|
||||
template <class R>
|
||||
std::ostream& operator<<(std::ostream& os,
|
||||
const CGAL::OGL::Sphere_circle<R>& s)
|
||||
{ CGAL::OGL::VSegment::const_iterator it;
|
||||
os << s.original() << " ";
|
||||
for (it = s.begin(); it != s.end(); ++it)
|
||||
os << *it;
|
||||
return os;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <class R>
|
||||
std::ostream& operator<<(std::ostream& os,
|
||||
const CGAL::OGL::Sphere_point<R>& p)
|
||||
{ os << p.original() << CGAL::OGL::VPoint(p); return os; }
|
||||
|
||||
|
||||
#endif //CGAL_SPHERE_GEOMETRY_OGL_H
|
||||
|
||||
|
|
@ -0,0 +1,463 @@
|
|||
// ============================================================================
|
||||
//
|
||||
// Copyright (c) 1997-2000 The CGAL Consortium
|
||||
//
|
||||
// This software and related documentation is part of an INTERNAL release
|
||||
// of the Computational Geometry Algorithms Library (CGAL). It is not
|
||||
// intended for general use.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// release : $CGAL_Revision$
|
||||
// release_date : $CGAL_Date$
|
||||
//
|
||||
// file : include/CGAL/Nef_S2/Sphere_map.h
|
||||
// package : Nef_S2
|
||||
// chapter : Nef Polyhedra on the sphere
|
||||
//
|
||||
// revision : $Revision$
|
||||
// revision_date : $Date$
|
||||
//
|
||||
// author(s) : Michael Seel <seel@mpi-sb.mpg.de>
|
||||
// maintainer : Michael Seel <seel@mpi-sb.mpg.de>
|
||||
// coordinator : Michael Seel <seel@mpi-sb.mpg.de>
|
||||
// ============================================================================
|
||||
|
||||
#ifndef CGAL_SPHERE_MAP_H
|
||||
#define CGAL_SPHERE_MAP_H
|
||||
|
||||
#include <CGAL/basic.h>
|
||||
#include <CGAL/Object.h>
|
||||
#include <CGAL/Unique_hash_map.h>
|
||||
#include <CGAL/Nef_S2/SM_items.h>
|
||||
#include <CGAL/Nef_S2/SM_iteration.h>
|
||||
#include <CGAL/Nef_S2/Generic_handle_map.h>
|
||||
#include <list>
|
||||
#undef _DEBUG
|
||||
#define _DEBUG 109
|
||||
#include <CGAL/Nef_S2/debug.h>
|
||||
|
||||
CGAL_BEGIN_NAMESPACE
|
||||
|
||||
/*{\Manpage {Sphere_map}{Kernel}{Sphere Maps}{M}}*/
|
||||
|
||||
template <typename Kernel_>
|
||||
class Sphere_map {
|
||||
|
||||
/*{\Mdefinition selective sphere map container based on
|
||||
the HDS design of Kettner.}*/
|
||||
|
||||
public:
|
||||
/*{\Mtypes 7}*/
|
||||
typedef Kernel_ Kernel;
|
||||
typedef Sphere_map<Kernel_> Self;
|
||||
typedef SM_items<Kernel_,bool> Items;
|
||||
|
||||
friend class SM_const_decorator<Self,Kernel>;
|
||||
friend class SM_decorator<Self,Kernel>;
|
||||
|
||||
typedef typename Kernel::Sphere_point Sphere_point;
|
||||
/*{\Mtypemember embedding vertices.}*/
|
||||
typedef typename Kernel::Sphere_circle Sphere_circle;
|
||||
/*{\Mtypemember embedding edges.}*/
|
||||
typedef bool Mark;
|
||||
/*{\Mtypemember selective attributes of all objects.}*/
|
||||
typedef size_t Size_type;
|
||||
/*{\Mtypemember size type.}*/
|
||||
|
||||
/*{\Mtext For all objects |Vertex|, |Halfedge|, |Halfloop|, |Face|
|
||||
there are handle and iterator types |xxx_handle|, |xxx_iterator|.
|
||||
There's no type |SLoop_iterator|, as there is
|
||||
at most one |SLoop| pair per sphere map.}*/
|
||||
|
||||
typedef typename Items::template Vertex<Self> Vertex;
|
||||
typedef CGAL::In_place_list<Vertex,false> Vertex_list;
|
||||
typedef typename Vertex_list::iterator Vertex_handle;
|
||||
typedef typename Vertex_list::const_iterator Vertex_const_handle;
|
||||
typedef typename Vertex_list::iterator Vertex_iterator;
|
||||
typedef typename Vertex_list::const_iterator Vertex_const_iterator;
|
||||
|
||||
typedef typename Items::template Halfedge<Self> Halfedge;
|
||||
typedef CGAL::In_place_list<Halfedge,false> Halfedge_list;
|
||||
typedef typename Halfedge_list::iterator Halfedge_handle;
|
||||
typedef typename Halfedge_list::const_iterator Halfedge_const_handle;
|
||||
typedef typename Halfedge_list::iterator Halfedge_iterator;
|
||||
typedef typename Halfedge_list::const_iterator Halfedge_const_iterator;
|
||||
|
||||
typedef typename Items::template Face<Self> Face;
|
||||
typedef CGAL::In_place_list<Face,false> Face_list;
|
||||
typedef typename Face_list::iterator Face_handle;
|
||||
typedef typename Face_list::const_iterator Face_const_handle;
|
||||
typedef typename Face_list::iterator Face_iterator;
|
||||
typedef typename Face_list::const_iterator Face_const_iterator;
|
||||
|
||||
typedef typename Items::template Halfloop<Self> Halfloop;
|
||||
typedef Halfloop* Halfloop_handle;
|
||||
typedef const Halfloop* Halfloop_const_handle;
|
||||
typedef Halfloop* Halfloop_iterator;
|
||||
typedef const Halfloop* Halfloop_const_iterator;
|
||||
|
||||
class Object_handle
|
||||
/*{\Mtypemember a generic handle to an object of |\Mvar|.
|
||||
The kind of the object can be determined and the object assigned
|
||||
by the function:\\
|
||||
|bool assign(xxx_handle& h, Object_handle o)|\\
|
||||
where the function returns |true| iff the assignment of |o| to
|
||||
|h| was valid.}*/
|
||||
: public CGAL::Object
|
||||
{
|
||||
typedef CGAL::Object Base;
|
||||
public:
|
||||
Object_handle() : Base() {}
|
||||
Object_handle(const CGAL::Object& o) : Base(o) {}
|
||||
Object_handle(const Object_handle& h) : Base(h) {}
|
||||
Object_handle& operator=(const Object_handle& h)
|
||||
{ Base::operator=(h); return *this; }
|
||||
bool operator==(CGAL_NULL_TYPE n) const
|
||||
{ assert(n == 0); return Base::is_empty(); }
|
||||
bool operator!=(CGAL_NULL_TYPE n) const
|
||||
{ assert(n == 0); return !Base::is_empty(); }
|
||||
}; // Object_handle
|
||||
|
||||
typedef std::list<Object_handle> Object_list;
|
||||
typedef typename Object_list::iterator Object_iterator;
|
||||
typedef typename Object_list::const_iterator Object_const_iterator;
|
||||
typedef Generic_handle_map<Object_iterator> Handle_to_iterator_map;
|
||||
|
||||
class Face_cycle_iterator : public Object_iterator
|
||||
/*{\Mtypemember a generic iterator to an object in the boundary
|
||||
of a facet. Convertible to |Object_handle|.}*/
|
||||
{ typedef Object_iterator Ibase;
|
||||
public:
|
||||
Face_cycle_iterator() : Ibase() {}
|
||||
Face_cycle_iterator(const Ibase& b) : Ibase(b) {}
|
||||
Face_cycle_iterator(const Face_cycle_iterator& i) : Ibase(i) {}
|
||||
bool is_vertex() const
|
||||
{ Vertex_handle v; return CGAL::assign(v,Ibase::operator*()); }
|
||||
bool is_halfedge() const
|
||||
{ Halfedge_handle e; return CGAL::assign(e,Ibase::operator*()); }
|
||||
bool is_halfloop() const
|
||||
{ Halfloop_handle l; return CGAL::assign(l,Ibase::operator*()); }
|
||||
operator Vertex_handle() const
|
||||
{ Vertex_handle v; CGAL::assign(v,Ibase::operator*()); return v; }
|
||||
operator Halfedge_handle() const
|
||||
{ Halfedge_handle e; CGAL::assign(e,Ibase::operator*()); return e; }
|
||||
operator Halfloop_handle() const
|
||||
{ Halfloop_handle l; CGAL::assign(l,Ibase::operator*()); return l; }
|
||||
|
||||
operator Object_handle() const { return Ibase::operator*(); }
|
||||
Object_handle& operator*() const { return Ibase::operator*(); }
|
||||
Object_handle operator->() const { CGAL_assertion_msg(0,"not impl."); }
|
||||
};
|
||||
|
||||
class Face_cycle_const_iterator : public Object_const_iterator
|
||||
/*{\Mtypemember a generic iterator to an object in the boundary
|
||||
of a facet. Convertible to |Object_handle|.}*/
|
||||
{ typedef Object_const_iterator Ibase;
|
||||
public:
|
||||
Face_cycle_const_iterator() : Ibase() {}
|
||||
Face_cycle_const_iterator(const Ibase& b) : Ibase(b) {}
|
||||
Face_cycle_const_iterator(const Face_cycle_const_iterator& i)
|
||||
: Ibase(i) {}
|
||||
bool is_vertex() const
|
||||
{ Vertex_handle v; return CGAL::assign(v,Ibase::operator*()); }
|
||||
bool is_halfedge() const
|
||||
{ Halfedge_handle e; return CGAL::assign(e,Ibase::operator*()); }
|
||||
bool is_halfloop() const
|
||||
{ Halfloop_handle l; return CGAL::assign(l,Ibase::operator*()); }
|
||||
operator Vertex_const_handle() const
|
||||
{ Vertex_handle v; CGAL::assign(v,Ibase::operator*());
|
||||
return Vertex_const_handle(v); }
|
||||
operator Halfedge_const_handle() const
|
||||
{ Halfedge_handle e; CGAL::assign(e,Ibase::operator*());
|
||||
return Halfedge_const_handle(e); }
|
||||
operator Halfloop_const_handle() const
|
||||
{ Halfloop_handle l; CGAL::assign(l,Ibase::operator*());
|
||||
return Halfloop_const_handle(l); }
|
||||
|
||||
operator Object_handle() const { return Ibase::operator*(); }
|
||||
const Object_handle& operator*() const { return Ibase::operator*(); }
|
||||
Object_handle operator->() const { CGAL_assertion_msg(0,"not impl."); }
|
||||
};
|
||||
|
||||
/*{\Mcreation 3}*/
|
||||
/*{\Mtext |\Mname| is default and copy constructible. Note that copy
|
||||
construction means cloning an isomorphic structure and is thus an
|
||||
expensive operation.}*/
|
||||
|
||||
Sphere_map() : boundary_item_(undef_),
|
||||
vertices_(), edges_(), faces_(), loops_(0)
|
||||
{ m_pos_ = m_neg_ = Mark(); }
|
||||
|
||||
~Sphere_map() { clear(); }
|
||||
|
||||
Sphere_map(const Self& D) : boundary_item_(undef_),
|
||||
vertices_(D.vertices_), edges_(D.edges_), faces_(D.faces_), loops_(0)
|
||||
{ if ( D.loops_ != 0 ) new_halfloop_pair(*(D.loops_),*(D.loops_->twin_));
|
||||
pointer_update(D);
|
||||
m_pos_ = D.m_pos_; m_neg_ = D.m_neg_; }
|
||||
|
||||
Self& operator=(const Self& D)
|
||||
{ if ( this == &D ) return *this;
|
||||
clear();
|
||||
vertices_ = D.vertices_; edges_ = D.edges_; faces_ = D.faces_;
|
||||
if ( D.loops_ != 0 ) new_halfloop_pair(*D.loops_,*(D.loops_->twin_));
|
||||
pointer_update(D);
|
||||
m_pos_ = D.m_pos_; m_neg_ = D.m_neg_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
boundary_item_.clear(undef_);
|
||||
vertices_.destroy(); edges_.destroy(); faces_.destroy();
|
||||
if ( loops_ != 0 ) { delete_halfloop_pair(loops_); loops_=0; }
|
||||
m_pos_ = m_neg_ = Mark();
|
||||
}
|
||||
|
||||
template <typename H>
|
||||
bool is_boundary_object(H h)
|
||||
{ return boundary_item_[h]!=undef_; }
|
||||
|
||||
template <typename H>
|
||||
Object_iterator& boundary_item(H h)
|
||||
{ return boundary_item_[h]; }
|
||||
|
||||
template <typename H>
|
||||
void store_boundary_item(H h, Object_iterator o)
|
||||
{ boundary_item_[h] = o; }
|
||||
|
||||
template <typename H>
|
||||
void undef_boundary_item(H h)
|
||||
{ CGAL_assertion(boundary_item_[h]!=undef_);
|
||||
boundary_item_[h] = undef_; }
|
||||
|
||||
void reset_iterator_hash(Object_iterator it)
|
||||
{ Vertex_handle sv;
|
||||
Halfedge_handle se;
|
||||
Halfloop_handle sl;
|
||||
if ( assign(se,*it) ) { undef_boundary_item(se); return; }
|
||||
if ( assign(sl,*it) ) { undef_boundary_item(sl); return; }
|
||||
if ( assign(sv,*it) ) { undef_boundary_item(sv); return; }
|
||||
}
|
||||
|
||||
void reset_object_list(Object_list& L)
|
||||
{ Object_iterator oit;
|
||||
CGAL_forall_iterators(oit,L) reset_iterator_hash(oit);
|
||||
L.clear();
|
||||
}
|
||||
|
||||
/*{\Moperations 2.5 3}*/
|
||||
|
||||
// The constant iterators and circulators.
|
||||
Vertex_const_iterator vertices_begin() const { return vertices_.begin();}
|
||||
Vertex_const_iterator vertices_end() const { return vertices_.end();}
|
||||
Halfedge_const_iterator halfedges_begin() const { return edges_.begin();}
|
||||
Halfedge_const_iterator halfedges_end() const { return edges_.end();}
|
||||
Halfloop_const_iterator halfloops_begin() const { return loops_; }
|
||||
Halfloop_const_iterator halfloops_end() const
|
||||
{ return loops_ != 0 ? loops_+2 : loops_; }
|
||||
Face_const_iterator faces_begin() const { return faces_.begin();}
|
||||
Face_const_iterator faces_end() const { return faces_.end();}
|
||||
|
||||
Vertex_iterator vertices_begin() { return vertices_.begin();}
|
||||
Vertex_iterator vertices_end() { return vertices_.end();}
|
||||
Halfedge_iterator halfedges_begin() { return edges_.begin();}
|
||||
Halfedge_iterator halfedges_end() { return edges_.end();}
|
||||
Halfloop_iterator halfloops_begin() { return loops_; }
|
||||
Halfloop_iterator halfloops_end()
|
||||
{ return loops_ != 0 ? loops_+2 : loops_; }
|
||||
Face_iterator faces_begin() { return faces_.begin();}
|
||||
Face_iterator faces_end() { return faces_.end();}
|
||||
|
||||
Face_cycle_const_iterator face_cycles_begin(Face_const_handle f) const
|
||||
{ return f->face_cycles_begin(); }
|
||||
Face_cycle_const_iterator face_cycles_end(Face_const_handle f) const
|
||||
{ return f->face_cycles_end(); }
|
||||
Face_cycle_iterator face_cycles_begin(Face_handle f) const
|
||||
{ return f->face_cycles_begin(); }
|
||||
Face_cycle_iterator face_cycles_end(Face_handle f) const
|
||||
{ return f->face_cycles_end(); }
|
||||
|
||||
/*{\Mtext The list of all objects can be accessed via iterator ranges.
|
||||
For comfortable iteration we also provide iterations macros.
|
||||
The iterator range access operations are of the following kind:\\
|
||||
|Vertex_iterator vertices_begin()/vertices_end()|\\
|
||||
|Halfedge_iterator halfedges_begin()/halfedges_end()|\\
|
||||
|Halfloop_iterator halfloops_begin()/halfloops_end()|\\
|
||||
|Face_iterator faces_begin()/faces_end()|
|
||||
|
||||
The macros are then |CGAL_forall_vertices(v,\Mvar)|,
|
||||
|CGAL_forall_halfedges(e,\Mvar)|,
|
||||
|CGAL_forall_halfloops(l,\Mvar)|,
|
||||
|CGAL_forall_faces(f,\Mvar)|.}*/
|
||||
|
||||
Size_type number_of_vertices() const { return vertices_.size();}
|
||||
/*{\Mop returns the number of vertices.}*/
|
||||
Size_type number_of_halfedges() const { return edges_.size();}
|
||||
/*{\Mop returns the number of (directed edges).}*/
|
||||
Size_type number_of_faces() const { return faces_.size();}
|
||||
/*{\Mop returns the number of facets.}*/
|
||||
Size_type number_of_halfloops() const
|
||||
{ return loops_!=Halfloop_handle() ? 2 : 0; }
|
||||
/*{\Mop returns the number of sloops.}*/
|
||||
|
||||
bool empty() const
|
||||
{ return number_of_vertices() == 0 &&
|
||||
number_of_halfedges() == 0 &&
|
||||
number_of_halfloops() == 0 &&
|
||||
number_of_faces() == 0;
|
||||
}
|
||||
|
||||
Vertex_handle new_vertex(const Sphere_point& p,
|
||||
Mark m = Mark())
|
||||
/*{\Mop returns a new vertex at point |p| marked by |m|.}*/
|
||||
{ Vertex_handle vh = new_vertex(); vh->point_ = p; vh->mark_ = m;
|
||||
TRACEN("new_vertex "<<&*vh);
|
||||
return vh;
|
||||
}
|
||||
|
||||
template <typename H>
|
||||
void make_twins(H h1, H h2) { h1->twin_ = h2; h2->twin_ = h1; }
|
||||
|
||||
Vertex_handle new_vertex()
|
||||
{ vertices_.push_back( * new Vertex); return --vertices_end(); }
|
||||
|
||||
Face_handle new_face()
|
||||
{ faces_.push_back( * new Face ); return --faces_end(); }
|
||||
|
||||
Halfedge_handle new_halfedge_pair()
|
||||
{ edges_.push_back( * new Halfedge );
|
||||
Halfedge_handle e1 = --halfedges_end();
|
||||
edges_.push_back( * new Halfedge );
|
||||
Halfedge_handle e2 = --halfedges_end();
|
||||
make_twins(e1,e2); return e1; }
|
||||
|
||||
Halfloop_handle new_halfloop_pair()
|
||||
{ Halfloop_handle ph = new Halfloop[2];
|
||||
Halfloop* pt(ph); ++pt;
|
||||
make_twins(ph,pt);
|
||||
loops_=ph; return ph; }
|
||||
|
||||
Halfloop_handle new_halfloop_pair(const Halfloop& l1,
|
||||
const Halfloop& l2)
|
||||
{ Halfloop* ph = new Halfloop[2];
|
||||
Halfloop* pt(ph); ++pt;
|
||||
*ph=l1; *pt=l2; make_twins(ph,pt);
|
||||
loops_=ph; return ph; }
|
||||
|
||||
void delete_vertex(Vertex_handle h)
|
||||
{ vertices_.erase(h); delete &* h; }
|
||||
|
||||
void delete_face(Face_handle h)
|
||||
{ faces_.erase(h); delete &* h; }
|
||||
|
||||
void delete_halfedge_pair(Halfedge_handle h)
|
||||
{ Halfedge_handle ht = h->twin_;
|
||||
edges_.erase(h); edges_.erase(ht);
|
||||
delete &*ht; delete &*h; }
|
||||
|
||||
void delete_halfloop_pair(Halfloop_handle h)
|
||||
{ Halfloop* ph = &*h;
|
||||
Halfloop* pt = &*(h->twin_);
|
||||
if ( ph > pt ) std::swap(ph,pt);
|
||||
loops_ = Halfloop_handle();
|
||||
delete [] ph; }
|
||||
|
||||
void delete_halfedge(Halfedge_handle h)
|
||||
{ edges_.erase(h); delete &* h; }
|
||||
|
||||
protected:
|
||||
void pointer_update(const Self& D);
|
||||
Handle_to_iterator_map boundary_item_;
|
||||
static Object_iterator undef_;
|
||||
|
||||
Vertex_list vertices_;
|
||||
Halfedge_list edges_;
|
||||
Face_list faces_;
|
||||
Halfloop_iterator loops_;
|
||||
Mark m_pos_, m_neg_;
|
||||
/* two default marks at y-
|
||||
m_neg_ just below the pos-xy-equator
|
||||
m_pos_ just above the neg-xy-equator */
|
||||
|
||||
}; // Sphere_map
|
||||
|
||||
|
||||
template <typename K>
|
||||
void Sphere_map<K>::
|
||||
pointer_update(const Sphere_map<K>& D)
|
||||
{
|
||||
CGAL::Unique_hash_map<Vertex_const_handle,Vertex_handle> VM;
|
||||
CGAL::Unique_hash_map<Halfedge_const_handle,Halfedge_handle> EM;
|
||||
CGAL::Unique_hash_map<Halfloop_const_handle,Halfloop_handle> LM;
|
||||
CGAL::Unique_hash_map<Face_const_handle,Face_handle> FM;
|
||||
|
||||
Vertex_const_iterator vc = D.vertices_begin();
|
||||
Vertex_iterator v = vertices_begin();
|
||||
for ( ; vc != D.vertices_end(); ++vc,++v) VM[vc] = v;
|
||||
VM[D.vertices_end()] = vertices_end();
|
||||
|
||||
Halfedge_const_iterator ec = D.halfedges_begin();
|
||||
Halfedge_iterator e = halfedges_begin();
|
||||
for ( ; ec != D.halfedges_end(); ++ec,++e) EM[ec] = e;
|
||||
EM[D.halfedges_end()] = halfedges_end();
|
||||
|
||||
Face_const_iterator fc = D.faces_begin();
|
||||
Face_iterator f = faces_begin();
|
||||
for ( ; fc != D.faces_end(); ++fc,++f) FM[fc] = f;
|
||||
FM[D.faces_end()] = faces_end();
|
||||
|
||||
Halfloop_iterator l;
|
||||
if ( D.loops_ != 0 ) {
|
||||
LM[D.loops_] = loops_;
|
||||
LM[D.loops_->twin_] = loops_->twin_;
|
||||
}
|
||||
|
||||
for (v = vertices_begin(); v != vertices_end(); ++v) {
|
||||
// Local Graph update: (SVertices are postponed/updated as Edges)
|
||||
v->edge_ = EM[v->edge_];
|
||||
v->face_ = FM[v->face_];
|
||||
}
|
||||
// Edge update:
|
||||
for (e = halfedges_begin(); e != halfedges_end(); ++e) {
|
||||
e->twin_ = EM[e->twin_];
|
||||
e->prev_ = EM[e->prev_];
|
||||
e->next_ = EM[e->next_];
|
||||
e->source_ = VM[e->source_];
|
||||
e->face_ = FM[e->face_];
|
||||
}
|
||||
|
||||
for (l = halfloops_begin(); l != halfloops_end(); ++l) {
|
||||
// l->twin_ = LM[l->twin_]; twin is set on construction
|
||||
l->face_ = FM[l->face_];
|
||||
}
|
||||
|
||||
for (f = faces_begin(); f != faces_end(); ++f) {
|
||||
Face_cycle_iterator fci;
|
||||
for(fci = f->boundary_.begin(); fci != f->boundary_.end(); ++fci) {
|
||||
if ( assign(v,Object_handle(fci)) )
|
||||
{ *fci = make_object(VM[v]); store_boundary_item(v,fci); }
|
||||
else if ( assign(e,Object_handle(fci)) )
|
||||
{ *fci = make_object(EM[e]); store_boundary_item(e,fci); }
|
||||
else if ( assign(l,Object_handle(fci)) )
|
||||
{ *fci = make_object(LM[l]); store_boundary_item(l,fci); }
|
||||
else CGAL_assertion_msg(0,"damn wrong boundary item in face.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Kernel_>
|
||||
typename Sphere_map<Kernel_>::Object_iterator
|
||||
Sphere_map<Kernel_>::undef_;
|
||||
|
||||
/* boundary item is member!
|
||||
template <typename Kernel_>
|
||||
typename Sphere_map<Kernel_>::Handle_to_iterator_map
|
||||
Sphere_map<Kernel_>::boundary_item_(Sphere_map<Kernel_>::undef_);
|
||||
*/
|
||||
|
||||
CGAL_END_NAMESPACE
|
||||
#endif // CGAL_SPHERE_MAP_H
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
#ifndef CGAL_SPHERE_POINT_H
|
||||
#define CGAL_SPHERE_POINT_H
|
||||
|
||||
#include <CGAL/basic.h>
|
||||
|
||||
CGAL_BEGIN_NAMESPACE
|
||||
|
||||
/*{\Mtext \headerline{Restricted Spherical Geometry}
|
||||
|
||||
We introduce geometric objects that are part of the
|
||||
spherical surface $S_2$ and operations on them. We define types
|
||||
|Sphere_point|, |Sphere_circle|, |Sphere_segment|, and
|
||||
|Sphere_direction|. |Sphere_point|s are points on $S_2$,
|
||||
|Sphere_circle|s are oriented great circles of $S_2$,
|
||||
|Sphere_segment|s are oriented parts of |Sphere_circles| bounded by a
|
||||
pair of |Sphere_point|s, and |Sphere_direction|s are directions that
|
||||
are part of great circles (a direction is usually defined to be a
|
||||
vector without length, that floats around in its underlying space and
|
||||
can be used to specify a movement at any point of the underlying
|
||||
space; in our case we use directions only at points that are part of
|
||||
the great circle that underlies also the direction.)
|
||||
|
||||
Note that we have to consider special geometric properties of the
|
||||
objects. For example two points that are part of a great circle define
|
||||
two |Sphere_segment|s, and two arbitrary |Sphere_segment|s can
|
||||
intersect in two points.
|
||||
|
||||
If we restrict our geometric objects to a so-called perfect hemisphere
|
||||
of $S_2$\footnote{A perfect hemisphere of $S_2$ is an open half-sphere
|
||||
plus an open half-circle in the boundary of the open half-sphere plus one
|
||||
endpoint of the half-circle.} then the restricted objects behave like
|
||||
in classical geometry, e.g., two points define exactly one segment,
|
||||
two segments intersect in at most one interior point
|
||||
(non-degenerately), or three non-cocircular sphere points can be
|
||||
qualified as being positively or negatively oriented.}*/
|
||||
|
||||
/*{\Moptions print_title=yes }*/
|
||||
/*{\Manpage{Sphere_point}{R}{Points on the unit sphere}{p}}*/
|
||||
|
||||
template <class R_>
|
||||
class Sphere_point : public R_::Point_3 {
|
||||
|
||||
/*{\Mdefinition An object |\Mvar| of type |\Mname| is a point on the
|
||||
surface of a unit sphere. Such points correspond to the nontrivial
|
||||
directions in space and similarly to the equivalence classes of all
|
||||
nontrivial vectors under normalization.}*/
|
||||
|
||||
public:
|
||||
/*{\Mtypes 5}*/
|
||||
typedef R_ R;
|
||||
/*{\Mtypemember representation class.}*/
|
||||
typedef typename R_::FT FT;
|
||||
/*{\Xtypemember ring number type.}*/
|
||||
typedef typename R_::RT RT;
|
||||
/*{\Mtypemember field number type.}*/
|
||||
typedef Sphere_point<R> Self;
|
||||
typedef typename R::Point_3 Base;
|
||||
typedef typename R::Direction_3 Direction_3;
|
||||
|
||||
/*{\Mcreation 5}*/
|
||||
Sphere_point() : Base() {}
|
||||
/*{\Mcreate creates some sphere point.}*/
|
||||
|
||||
Sphere_point(int x, int y, int z) :
|
||||
Base(x,y,z,1) { CGAL_assertion(x!=0 || y!=0 || z!=0); }
|
||||
|
||||
Sphere_point(const RT& x, const RT& y, const RT& z) :
|
||||
/*{\Mcreate creates a sphere point corresponding to the point of
|
||||
intersection of the ray starting at the origin in direction $(x,y,z)$
|
||||
and the surface of $S_2$.}*/
|
||||
Base(x,y,z,1) { CGAL_assertion(x!=0 || y!=0 || z!=0); }
|
||||
|
||||
Sphere_point(const Base& p) : Base(p) {}
|
||||
|
||||
/*{\Moperations 4 2}*/
|
||||
|
||||
/*{\Mtext Access to the coordinates is provided by the following
|
||||
operations. Note that the vector $(x,y,z)$ is not normalized.}*/
|
||||
|
||||
RT x() const { return hx(); }
|
||||
/*{\Mop the $x$-coordinate.}*/
|
||||
RT y() const { return hy(); }
|
||||
/*{\Mop the $y$-coordinate.}*/
|
||||
RT z() const { return hz(); }
|
||||
/*{\Mop the $z$-coordinate.}*/
|
||||
|
||||
bool operator==(const Sphere_point<R>& q) const
|
||||
/*{\Mbinop Equality.}*/
|
||||
{ return Direction_3(Base(*this)-ORIGIN)==
|
||||
Direction_3(q-ORIGIN); }
|
||||
|
||||
bool operator!=(const Sphere_point<R>& q) const
|
||||
/*{\Mbinop Inequality.}*/
|
||||
{ return !operator==(q); }
|
||||
|
||||
Sphere_point<R> opposite() const
|
||||
/*{\Mop returns the opposite of |\Mvar|.}*/
|
||||
{ return ORIGIN + -(Base(*this)-ORIGIN); }
|
||||
|
||||
}; // Sphere_point<R>
|
||||
|
||||
template <typename R>
|
||||
CGAL::Point_3<R> operator+(
|
||||
const CGAL::Point_3<R>& p, const Sphere_point<R>& q)
|
||||
{ return p + (q-CGAL::ORIGIN); }
|
||||
|
||||
CGAL_END_NAMESPACE
|
||||
#endif //CGAL_SPHERE_POINT_H
|
||||
|
|
@ -0,0 +1,344 @@
|
|||
#ifndef CGAL_SPHERE_SEGMENT_H
|
||||
#define CGAL_SPHERE_SEGMENT_H
|
||||
|
||||
#include <CGAL/basic.h>
|
||||
#include <CGAL/Handle_for.h>
|
||||
|
||||
CGAL_BEGIN_NAMESPACE
|
||||
|
||||
template <class R_> class Sphere_segment_rep : public Ref_counted
|
||||
{
|
||||
typedef typename R_::Point_3 Point_3;
|
||||
typedef typename R_::Plane_3 Plane_3;
|
||||
typedef Sphere_point<R_> Point;
|
||||
typedef Sphere_circle<R_> Circle;
|
||||
typedef Sphere_segment_rep<R_> Rep;
|
||||
friend class Sphere_segment<R_>;
|
||||
public:
|
||||
|
||||
Sphere_segment_rep(const Point& p1, const Point& p2,
|
||||
bool shorter_arc=true) :
|
||||
ps_(p1), pt_(p2), c_(Plane_3(p1,p2,Point_3(0,0,0)))
|
||||
{ CGAL_assertion(p1 != p2.opposite());
|
||||
if ( p1 == p2 ) {
|
||||
Plane_3 h(Point_3(0,0,0),(p1-CGAL::ORIGIN));
|
||||
c_ = Sphere_circle<R_>(Plane_3(Point_3(0,0,0),h.base1()));
|
||||
}
|
||||
if (!shorter_arc) c_ = c_.opposite();
|
||||
}
|
||||
|
||||
Sphere_segment_rep(const Point& p1, const Point& p2, const Circle& c) :
|
||||
ps_(p1), pt_(p2), c_(c)
|
||||
{ CGAL_assertion(c.has_on(p1)&&c.has_on(p2)); }
|
||||
|
||||
Sphere_segment_rep(const Circle& c1,
|
||||
const Circle& c2) : c_(c1)
|
||||
{ CGAL_assertion(!equal_as_sets(c1,c2));
|
||||
ps_ = intersection(c1,c2);
|
||||
pt_ = ps_.opposite();
|
||||
if ( orientation(Point_3(0,0,0),ps_,pt_,
|
||||
CGAL::ORIGIN + c_.orthogonal_vector()) !=
|
||||
CGAL::POSITIVE ) std::swap(ps_,pt_);
|
||||
}
|
||||
|
||||
Sphere_segment_rep(const Rep& r) :
|
||||
ps_(r.ps_), pt_(r.pt_), c_(r.c_) {}
|
||||
|
||||
Rep& operator=(const Rep& r)
|
||||
{ ps_=r.ps_; pt_=r.pt_; c_=r.c_; return *this; }
|
||||
|
||||
protected:
|
||||
Sphere_point<R_> ps_,pt_;
|
||||
Sphere_circle<R_> c_;
|
||||
};
|
||||
|
||||
|
||||
/*{\Moptions print_title=yes }*/
|
||||
/*{\Manpage{Sphere_segment}{R}{Segments on the unit sphere}{s}}*/
|
||||
|
||||
template <class R_>
|
||||
class Sphere_segment :
|
||||
public Handle_for< Sphere_segment_rep<R_> > {
|
||||
|
||||
/*{\Mdefinition An object |\Mvar| of type |\Mname| is a segment in the
|
||||
surface of a unit sphere that is part of a great circle trough the
|
||||
origin. Sphere segments are represented by two sphere points $p$ and
|
||||
$q$ plus an oriented plane $h$ that contains $p$ and $q$. The plane
|
||||
determines the sphere segment. Let $c$ be the circle in the
|
||||
intersection of $h$ and $S_2$. Then $s$ is that part of $c$ that is
|
||||
swept, when we rotate $p$ into $q$ in counterclockwise rotation around
|
||||
the normal vector of $h$ as seen from the positive halfspace.}*/
|
||||
|
||||
public:
|
||||
|
||||
/*{\Mtypes 6}*/
|
||||
|
||||
typedef R_ R;
|
||||
/*{\Mtypemember representation class.}*/
|
||||
typedef typename R_::RT RT;
|
||||
/*{\Mtypemember ring number type.}*/
|
||||
|
||||
typedef Sphere_segment_rep<R_> Rep;
|
||||
typedef Handle_for<Rep> Base;
|
||||
|
||||
typedef typename R_::Point_3 Point_3;
|
||||
typedef typename R_::Vector_3 Vector_3;
|
||||
typedef typename R_::Plane_3 Plane_3;
|
||||
typedef typename R_::Line_3 Line_3;
|
||||
typedef Sphere_segment<R_> Self;
|
||||
|
||||
/*{\Mcreation 4}*/
|
||||
|
||||
Sphere_segment() : Base() {}
|
||||
|
||||
Sphere_segment(const Sphere_point<R>& p1, const Sphere_point<R>& p2,
|
||||
bool shorter_arc=true) : Base(Rep(p1,p2,shorter_arc)) {}
|
||||
/*{\Mcreate creates a spherical segment spanning the shorter arc
|
||||
from |p1| to |p2| if |shorter_arc == true|. Otherwise the longer
|
||||
arc is created. \precond |p1 != p2| and |p1 != p2.opposite()|.}*/
|
||||
|
||||
|
||||
Sphere_segment(const Sphere_point<R>& p1, const Sphere_point<R>& p2,
|
||||
const Sphere_circle<R>& c) : Base(Rep(p1,p2,c)) {}
|
||||
/*{\Mcreate creates a spherical segment spanning the arc
|
||||
from |p1| to |p2| as part of the oriented circle |c|
|
||||
(|p1 == p2| or |p1 == p2.opposite()| are possible.)
|
||||
\precond |p1| and |p2| are contained in |c|.}*/
|
||||
|
||||
Sphere_segment(const Sphere_circle<R>& c1,
|
||||
const Sphere_circle<R>& c2) : Base(Rep(c1,c2)) {}
|
||||
/*{\Mcreate creates the spherical segment as part of |c1|
|
||||
that is part of the halfsphere left of the oriented circle |c2|.
|
||||
\precond |c1 != c2| as unoriented circles.}*/
|
||||
|
||||
Sphere_segment(const Self& s) : Base(s) {}
|
||||
|
||||
/*{\Moperations 4 2}*/
|
||||
|
||||
const Sphere_point<R>& source() const { return ptr->ps_; }
|
||||
/*{\Mop the source point of |\Mvar|.}*/
|
||||
const Sphere_point<R>& target() const { return ptr->pt_; }
|
||||
/*{\Mop the target point of |\Mvar|.}*/
|
||||
const Sphere_circle<R>& sphere_circle() const { return ptr->c_; }
|
||||
/*{\Mop the great circle supporting |\Mvar|.}*/
|
||||
|
||||
Sphere_segment<R> opposite() const
|
||||
/*{\Mop returns the sperical segment oriented from |target()|
|
||||
to |source()| with the same point set as |\Mvar|. }*/
|
||||
{ return Sphere_segment<R>(
|
||||
target(),source(),sphere_circle().opposite()); }
|
||||
|
||||
Sphere_segment<R> complement() const
|
||||
/*{\Mop returns the sperical segment oriented from |target()|
|
||||
to |source()| with the point set completing |\Mvar| to a
|
||||
full circle. }*/
|
||||
{ return Sphere_segment<R>(target(),source(),sphere_circle()); }
|
||||
|
||||
|
||||
int intersection(const Sphere_circle<R>& c,
|
||||
Sphere_segment<R>& s1, Sphere_segment<R>& s2) const;
|
||||
/*{\Mop returns the number of non-trivial connected components
|
||||
of the intersection of |\Mvar| and the closed halfsphere left of
|
||||
|c|.}*/
|
||||
|
||||
Sphere_point<R> intersection(const Sphere_segment<R>& so) const;
|
||||
/*{\Mop returns the point of intersection of |\Mvar| and
|
||||
|so|. \precond |\Mvar| and |so| do intersect.}*/
|
||||
|
||||
void split_halfcircle(Sphere_segment<R>& s1,
|
||||
Sphere_segment<R>& s2) const
|
||||
/*{\Mop splits a halfcircle into two equally sized segments.
|
||||
\precond |\Mvar| is a halfcircle.}*/
|
||||
{ CGAL_assertion( is_halfcircle() );
|
||||
Plane_3 h(Point_3(0,0,0),(target()-CGAL::ORIGIN));
|
||||
Sphere_point<R> p =
|
||||
CGAL::intersection(sphere_circle(),Sphere_circle<R>(h));
|
||||
if ( !has_on(p) ) p = p.opposite();
|
||||
s1 = Sphere_segment<R>(ptr->ps_,p,ptr->c_);
|
||||
s2 = Sphere_segment<R>(p,ptr->pt_,ptr->c_);
|
||||
}
|
||||
|
||||
bool is_short() const
|
||||
/*{\Mop a segment is short iff it is shorter than a halfcircle.}*/
|
||||
{ return CGAL::orientation(Point_3(0,0,0), source(), target(),
|
||||
CGAL::ORIGIN + ptr->c_.orthogonal_vector())
|
||||
== CGAL::POSITIVE; }
|
||||
|
||||
bool is_long() const
|
||||
/*{\Mop a segment is long iff it is longer than a halfcircle.}*/
|
||||
{ return CGAL::orientation(Point_3(0,0,0), source(), target(),
|
||||
CGAL::ORIGIN + ptr->c_.orthogonal_vector())
|
||||
== CGAL::NEGATIVE; }
|
||||
|
||||
bool is_degenerate() const { return source() == target(); }
|
||||
/*{\Mop return true iff |\Mvar| is degenerate.}*/
|
||||
|
||||
bool is_halfcircle() const { return source().opposite() == target(); }
|
||||
/*{\Mop return true iff |\Mvar| is a halfcircle.}*/
|
||||
|
||||
bool has_on(const Sphere_point<R>& p) const;
|
||||
/*{\Mop return true iff |\Mvar| contains |p|.}*/
|
||||
|
||||
bool has_in_relative_interior(const Sphere_point<R>& p) const;
|
||||
/*{\Mop return true iff |\Mvar| contains |p| in
|
||||
its relative interior.}*/
|
||||
|
||||
bool operator==(const Sphere_segment<R>& so) const
|
||||
{ return source() == so.source() && target() == so.target() &&
|
||||
(source() == target() ||
|
||||
sphere_circle() == so.sphere_circle()); }
|
||||
|
||||
bool operator!=(const Sphere_segment<R>& so) const
|
||||
{ return !operator==(so); }
|
||||
|
||||
};
|
||||
|
||||
template <typename R>
|
||||
bool do_intersect_internally(const Sphere_segment<R>& s1,
|
||||
const Sphere_segment<R>& s2,
|
||||
Sphere_point<R>& p);
|
||||
/*{\Mfunc return true iff |s1| and |s2| intersect internally
|
||||
(non-degenerately). If |true| the parameter |p| returns the point of
|
||||
intersection.}*/
|
||||
|
||||
|
||||
template <typename R>
|
||||
std::ostream& operator<<(std::ostream& os,
|
||||
const CGAL::Sphere_segment<R>& s)
|
||||
{ os << s.source()<<" "<<s.target()<<" "<<
|
||||
s.sphere_circle().plane()<<" "; return os; }
|
||||
|
||||
template <typename R>
|
||||
std::istream& operator>>(std::istream& is,
|
||||
CGAL::Sphere_segment<R>& s)
|
||||
{ CGAL::Sphere_point<R> p1,p2;
|
||||
CGAL::Sphere_circle<R> c;
|
||||
if ( !(is >> p1 >> p2 >> c) ) return is;
|
||||
s = CGAL::Sphere_segment<R>(p1,p2,c);
|
||||
return is; }
|
||||
|
||||
|
||||
template <typename R>
|
||||
std::pair< Sphere_segment<R>,Sphere_segment<R> >
|
||||
Sphere_circle<R>::split_at(const Sphere_point<R>& p) const
|
||||
{ CGAL_assertion(has_on(p));
|
||||
Sphere_point<R> q(p.opposite());
|
||||
return Sphere_segment_pair(
|
||||
Sphere_segment<R>(p,q,*this),
|
||||
Sphere_segment<R>(p,q,this->opposite()));
|
||||
}
|
||||
|
||||
template <typename R>
|
||||
std::pair< Sphere_segment<R>,Sphere_segment<R> >
|
||||
Sphere_circle<R>::split_at_xy_plane() const
|
||||
{ Self xycircle(0,0,1), yzcircle(1,0,0);
|
||||
if ( !equal_as_sets(xycircle,*this) )
|
||||
return split_at(intersection(*this,xycircle));
|
||||
else
|
||||
return split_at(intersection(*this,yzcircle));
|
||||
}
|
||||
|
||||
|
||||
/* Contains maps to two orientation checks with the wedge
|
||||
spanned by the source and the target with planes orthogonal
|
||||
to the supporting plane of $p$ and $q$. The logic depends on
|
||||
the segments length: long or short. */
|
||||
|
||||
template <typename R>
|
||||
bool Sphere_segment<R>::
|
||||
has_on(const CGAL::Sphere_point<R>& p) const
|
||||
{ if ( !sphere_circle().has_on(p) ) return false;
|
||||
if ( !is_long() ) {
|
||||
return orientation(Point_3(0,0,0),
|
||||
CGAL::ORIGIN + sphere_circle().orthogonal_vector(),
|
||||
source(),p) !=
|
||||
CGAL::NEGATIVE &&
|
||||
orientation(Point_3(0,0,0),target(),
|
||||
CGAL::ORIGIN +
|
||||
sphere_circle().orthogonal_vector(),p) !=
|
||||
CGAL::NEGATIVE;
|
||||
} else {
|
||||
return orientation(Point_3(0,0,0),
|
||||
CGAL::ORIGIN + sphere_circle().orthogonal_vector(),
|
||||
source(),p) !=
|
||||
CGAL::NEGATIVE ||
|
||||
orientation(Point_3(0,0,0),target(),
|
||||
CGAL::ORIGIN +
|
||||
sphere_circle().orthogonal_vector(),p) !=
|
||||
CGAL::NEGATIVE;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename R>
|
||||
bool Sphere_segment<R>::
|
||||
has_in_relative_interior(const CGAL::Sphere_point<R>& p) const
|
||||
{ if ( !sphere_circle().has_on(p) ) return false;
|
||||
if ( !is_long() ) {
|
||||
return orientation(Point_3(0,0,0),
|
||||
CGAL::ORIGIN + sphere_circle().orthogonal_vector(),
|
||||
source(),p) == CGAL::POSITIVE &&
|
||||
orientation(Point_3(0,0,0),target(),
|
||||
CGAL::ORIGIN +
|
||||
sphere_circle().orthogonal_vector(),p) ==
|
||||
CGAL::POSITIVE;
|
||||
} else {
|
||||
return orientation(Point_3(0,0,0),
|
||||
CGAL::ORIGIN + sphere_circle().orthogonal_vector(),
|
||||
source(),p) == CGAL::POSITIVE ||
|
||||
orientation(Point_3(0,0,0),target(),
|
||||
CGAL::ORIGIN +
|
||||
sphere_circle().orthogonal_vector(),p) ==
|
||||
CGAL::POSITIVE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Intersection of two sphere segments. It does not work if the two
|
||||
involved planes are equal as sets. */
|
||||
|
||||
template <typename R>
|
||||
Sphere_point<R> Sphere_segment<R>::
|
||||
intersection(const Sphere_segment<R>& s) const
|
||||
{
|
||||
CGAL_assertion(!equal_as_sets(sphere_circle(),s.sphere_circle()));
|
||||
Sphere_point<R> res =
|
||||
CGAL::intersection(sphere_circle(),s.sphere_circle());
|
||||
if ( has_on(res) && s.has_on(res) ) return res;
|
||||
return res.opposite();
|
||||
}
|
||||
|
||||
template <typename R>
|
||||
bool do_intersect_internally(const Sphere_segment<R>& s1,
|
||||
const Sphere_segment<R>& s2,
|
||||
Sphere_point<R>& p)
|
||||
{
|
||||
if ( equal_as_sets(s1.sphere_circle(),s2.sphere_circle()) )
|
||||
return false;
|
||||
p = CGAL::intersection(s1.sphere_circle(),s2.sphere_circle());
|
||||
if ( s1.has_in_relative_interior(p) &&
|
||||
s2.has_in_relative_interior(p) ) return true;
|
||||
p = p.opposite();
|
||||
if ( s1.has_in_relative_interior(p) &&
|
||||
s2.has_in_relative_interior(p) ) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
template <typename R>
|
||||
bool do_intersect_internally(const Sphere_circle<R>& c1,
|
||||
const Sphere_segment<R>& s2,
|
||||
Sphere_point<R>& p)
|
||||
{
|
||||
if ( equal_as_sets(c1,s2.sphere_circle()) )
|
||||
return false;
|
||||
p = CGAL::intersection(c1,s2.sphere_circle());
|
||||
if ( s2.has_in_relative_interior(p) ) return true;
|
||||
p = p.opposite();
|
||||
if ( s2.has_in_relative_interior(p) ) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
CGAL_END_NAMESPACE
|
||||
#endif //CGAL_SPHERE_SEGMENT_H
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
#ifndef CGAL_SPHERE_TRIANGLE_H
|
||||
#define CGAL_SPHERE_TRIANGLE_H
|
||||
|
||||
#include <CGAL/basic.h>
|
||||
#include <CGAL/Handle_for.h>
|
||||
#include <CGAL/Nef_S2/Tuple.h>
|
||||
|
||||
CGAL_BEGIN_NAMESPACE
|
||||
|
||||
template <class R_> class Sphere_triangle_rep : public Ref_counted
|
||||
{ typedef Sphere_point<R_> Point;
|
||||
typedef Sphere_circle<R_> Circle;
|
||||
typedef Sphere_triangle_rep<R_> Rep;
|
||||
|
||||
Tuple<Point,3> points_;
|
||||
Tuple<Circle,3> circles_;
|
||||
|
||||
friend class Sphere_triangle<R_>;
|
||||
|
||||
Sphere_triangle_rep(const Point& p1, const Point& p2, const Point& p3,
|
||||
const Circle& c1, const Circle& c2, const Circle& c3) :
|
||||
points_(p1,p2,p3), circles_(c1,c2,c3) {}
|
||||
public:
|
||||
Sphere_triangle_rep(const Rep& r) :
|
||||
points_(r.points_), circles_(r.circles_) {}
|
||||
|
||||
};
|
||||
|
||||
|
||||
/*{\Manpage{Sphere_triangle}{R}{Triangles on the unit sphere}{t}}*/
|
||||
template <class R_> class Sphere_triangle :
|
||||
public Handle_for< Sphere_triangle_rep<R_> > {
|
||||
/*{\Mdefinition An object |\Mvar| of type |\Mname| is a triangle
|
||||
on the surface of the unit sphere.}*/
|
||||
|
||||
public:
|
||||
/*{\Mtypes 5}*/
|
||||
typedef R_ R;
|
||||
/*{\Mtypemember representation class.}*/
|
||||
typedef typename R::RT RT;
|
||||
/*{\Mtypemember ring type.}*/
|
||||
|
||||
typedef Sphere_triangle_rep<R_> Rep;
|
||||
typedef Handle_for<Rep> Base;
|
||||
|
||||
/*{\Mcreation 5}*/
|
||||
Sphere_triangle() : Base() {}
|
||||
/*{\Mcreate creates some triangle.}*/
|
||||
|
||||
Sphere_triangle(
|
||||
const Sphere_point<R>& p0, const Sphere_point<R>& p1,
|
||||
const Sphere_point<R>& p2,
|
||||
const Sphere_circle<R>& c0, const Sphere_circle<R>& c1,
|
||||
const Sphere_circle<R>& c2) : Base(Rep(p0,p1,p2,c0,c1,c2))
|
||||
/*{\Mcreate creates a triangle spanned by the three points
|
||||
|p0|, |p1|, |p2|, where the triangle is left of the three circles
|
||||
|c0|, |c1|, |c2|. \precond $c_i$ contains $p_i$ and $p_{i+1}$ mod 3.}*/
|
||||
{ CGAL_assertion( c0.has_on(p0) && c0.has_on(p1) );
|
||||
CGAL_assertion( c1.has_on(p1) && c1.has_on(p2) );
|
||||
CGAL_assertion( c2.has_on(p2) && c0.has_on(p0) );
|
||||
}
|
||||
|
||||
Sphere_triangle(const Sphere_triangle<R>& t) : Base(t) {}
|
||||
|
||||
/*{\Moperations 4 2}*/
|
||||
|
||||
const Sphere_point<R>& point(unsigned i) const
|
||||
/*{\Mop returns the ith point of |\Mvar|.}*/
|
||||
{ return ptr->points_[i%3]; }
|
||||
|
||||
const Sphere_circle<R>& circle(unsigned i) const
|
||||
/*{\Mop returns the ith circle of |\Mvar|.}*/
|
||||
{ return ptr->circles_[i%3]; }
|
||||
|
||||
Sphere_triangle<R> opposite() const
|
||||
/*{\Mop returns the opposite of |\Mvar|.}*/
|
||||
{ return Sphere_triangle<R>(point(0), point(1), point(2),
|
||||
circle(0).opposite(), circle(1).opposite(), circle(2).opposite()); }
|
||||
|
||||
|
||||
}; // Sphere_triangle<R>
|
||||
|
||||
|
||||
template <typename R>
|
||||
std::ostream& operator<<(std::ostream& os,
|
||||
const CGAL::Sphere_triangle<R>& t)
|
||||
{ for (int i=0; i<3; ++i) os << t.point(i);
|
||||
for (int i=0; i<3; ++i) os << t.circle(i); return os; }
|
||||
|
||||
template <typename R>
|
||||
std::istream& operator>>(std::istream& is,
|
||||
CGAL::Sphere_triangle<R>& t)
|
||||
{ CGAL::Sphere_point<R> p1,p2,p3;
|
||||
CGAL::Sphere_circle<R> c1,c2,c3;
|
||||
if ( !(is >> p1 >> p2 >> p3 >> c1 >> c2 >> c3) ) return is;
|
||||
t = CGAL::Sphere_triangle<R>(p1,p2,p3,c1,c2,c3);
|
||||
return is; }
|
||||
|
||||
CGAL_END_NAMESPACE
|
||||
#endif //CGAL_SPHERE_TRIANGLE_H
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
#ifndef CGAL_TUPLE_H
|
||||
#define CGAL_TUPLE_H
|
||||
|
||||
#include <CGAL/basic.h>
|
||||
|
||||
CGAL_BEGIN_NAMESPACE
|
||||
|
||||
template <class T, unsigned n>
|
||||
class Tuple {
|
||||
typedef Tuple<T,n> Self;
|
||||
T object_[n];
|
||||
public:
|
||||
Tuple() { for (unsigned i=0; i<n; ++i) object_[i]=T(); }
|
||||
Tuple(const T& t1, const T& t2)
|
||||
{ CGAL_assertion(n>1); object_[0]=t1; object_[1]=t2; }
|
||||
Tuple(const T& t1, const T& t2, const T& t3)
|
||||
{ CGAL_assertion(n>2); object_[0]=t1; object_[1]=t2; object_[2]=t3; }
|
||||
|
||||
Tuple(const Self& t)
|
||||
{ for (unsigned i=0; i<n; ++i) object_[i] = t.object_[i]; }
|
||||
Self& operator=(const Self& t)
|
||||
{ for (unsigned i=0; i<n; ++i) object_[i] = t.object_[i];
|
||||
return *this; }
|
||||
|
||||
const T& operator[](unsigned i) const
|
||||
{ CGAL_assertion(i<n); return object_[i]; }
|
||||
T& operator[](unsigned i)
|
||||
{ CGAL_assertion(i<n); return object_[i]; }
|
||||
|
||||
};
|
||||
|
||||
CGAL_END_NAMESPACE
|
||||
#endif //CGAL_TUPLE_H
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
// ============================================================================
|
||||
//
|
||||
// Copyright (c) 1997-2000 The CGAL Consortium
|
||||
//
|
||||
// This software and related documentation is part of an INTERNAL release
|
||||
// of the Computational Geometry Algorithms Library (CGAL). It is not
|
||||
// intended for general use.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// release : $CGAL_Revision$
|
||||
// release_date : $CGAL_Date$
|
||||
//
|
||||
// file : include/CGAL/Nef_2/debug.h
|
||||
// package : Nef_2
|
||||
// chapter : Nef Polyhedra
|
||||
//
|
||||
// revision : $Revision$
|
||||
// revision_date : $Date$
|
||||
//
|
||||
// author(s) : Michael Seel <seel@mpi-sb.mpg.de>
|
||||
// maintainer : Michael Seel <seel@mpi-sb.mpg.de>
|
||||
// coordinator : Michael Seel <seel@mpi-sb.mpg.de>
|
||||
//
|
||||
// implementation: simple debugging macros
|
||||
// ============================================================================
|
||||
|
||||
#ifndef CGAL_DEBUG_H
|
||||
#define CGAL_DEBUG_H
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#undef TRACE
|
||||
#undef TRACEN
|
||||
#undef TRACEV
|
||||
#undef CTRACE
|
||||
#undef CTRACEN
|
||||
#undef ASSERT
|
||||
|
||||
static int debugthread=3141592;
|
||||
|
||||
#if _DEBUG>0
|
||||
#define SETDTHREAD(l) debugthread=l
|
||||
#else
|
||||
#define SETDTHREAD(l)
|
||||
#endif
|
||||
|
||||
#if _DEBUG>0
|
||||
#define TRACE(t) if((debugthread%_DEBUG)==0)\
|
||||
std::cerr<<" "<<t;std::cerr.flush()
|
||||
#else
|
||||
#define TRACE(t)
|
||||
#endif
|
||||
|
||||
#if _DEBUG>0
|
||||
#define TRACEV(t) if((debugthread%_DEBUG)==0)\
|
||||
std::cerr<<" "<<#t<<" = "<<(t)<<std::endl;std::cerr.flush()
|
||||
#else
|
||||
#define TRACEV(t)
|
||||
#endif
|
||||
|
||||
#if _DEBUG>0
|
||||
#define TRACEN(t) if((debugthread%_DEBUG)==0)\
|
||||
std::cerr<<" "<<t<<std::endl;std::cerr.flush()
|
||||
#else
|
||||
#define TRACEN(t)
|
||||
#endif
|
||||
|
||||
#if _DEBUG>0
|
||||
#define CTRACE(b,t) if(b) std::cerr<<" "<<t; else std::cerr<<" 0"
|
||||
#else
|
||||
#define CTRACE(b,t)
|
||||
#endif
|
||||
|
||||
#if _DEBUG>0
|
||||
#define CTRACEN(b,t) if(b) std::cerr<<" "<<t<<"\n"; else std::cerr<<" 0\n"
|
||||
#else
|
||||
#define CTRACEN(b,t)
|
||||
#endif
|
||||
|
||||
#ifndef _ASSERT
|
||||
#define ASSERT(cond,fstr)
|
||||
#else
|
||||
#define ASSERT(cond,fstr) \
|
||||
if (!(cond)) { \
|
||||
std::cerr<<" ASSERT: "<< #fstr << endl; \
|
||||
std::cerr<<" COND: "<< #cond << endl; \
|
||||
std::cerr<<" POSITION: "<<__FILE__<<" at line "<<__LINE__<<std::endl; \
|
||||
abort(); \
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif //CGAL_DEBUG_H
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,249 @@
|
|||
#ifndef LEDA_SPHERE_MAP_H
|
||||
#define LEDA_SPHERE_MAP_H
|
||||
|
||||
#include <CGAL/generic_sweep.h>
|
||||
#include <CGAL/Nef_2/Segment_overlay_traits.h>
|
||||
#include <CGAL/Nef_S2/Sphere_geometry.h>
|
||||
#include <LEDA/graph.h>
|
||||
#include <LEDA/graph_misc.h>
|
||||
|
||||
#undef _DEBUG
|
||||
#define _DEBUG 211
|
||||
#include <CGAL/Nef_S2/debug.h>
|
||||
|
||||
template <typename R, typename ITERATOR>
|
||||
class leda_graph_decorator {
|
||||
public:
|
||||
typedef leda_node Vertex_handle;
|
||||
typedef leda_edge Halfedge_handle;
|
||||
typedef CGAL::Sphere_point<R> Point_2;
|
||||
typedef CGAL::Sphere_segment<R> Segment_2;
|
||||
typedef GRAPH< Point_2, Segment_2 > Graph;
|
||||
typedef leda_node_map<Halfedge_handle> Below_map;
|
||||
|
||||
Graph& G;
|
||||
Below_map& M;
|
||||
|
||||
leda_graph_decorator(Graph& Gi, Below_map& Mi) : G(Gi), M(Mi) {}
|
||||
|
||||
Vertex_handle new_vertex(const Point_2& p)
|
||||
{ return G.new_node(p); }
|
||||
|
||||
void link_as_target_and_append(Vertex_handle v, Halfedge_handle e)
|
||||
{ Halfedge_handle erev = G.reversal(e);
|
||||
G.move_edge(e,G.cyclic_adj_pred(e,G.source(e)),v);
|
||||
G.move_edge(erev,v,G.target(erev));
|
||||
}
|
||||
|
||||
Halfedge_handle new_halfedge_pair_at_source(Vertex_handle v)
|
||||
{ Halfedge_handle e_res,e_rev, e_first = G.first_adj_edge(v);
|
||||
if ( e_first == nil ) {
|
||||
e_res = G.new_edge(v,v);
|
||||
e_rev = G.new_edge(v,v);
|
||||
} else {
|
||||
e_res = G.new_edge(e_first,v,LEDA::before);
|
||||
e_rev = G.new_edge(e_first,v,LEDA::before);
|
||||
}
|
||||
G.set_reversal(e_res,e_rev);
|
||||
return e_res;
|
||||
}
|
||||
|
||||
void supporting_segment(Halfedge_handle e, ITERATOR it)
|
||||
{ G[e] = *it; }
|
||||
|
||||
void halfedge_below(Vertex_handle v, Halfedge_handle e)
|
||||
{ M[v] = e; }
|
||||
|
||||
void trivial_segment(Vertex_handle v, ITERATOR it) {}
|
||||
void starting_segment(Vertex_handle v, ITERATOR it) {}
|
||||
void passing_segment(Vertex_handle v, ITERATOR it) {}
|
||||
void ending_segment(Vertex_handle v, ITERATOR it) {}
|
||||
|
||||
|
||||
}; // leda_graph_decorator
|
||||
|
||||
|
||||
template <typename R>
|
||||
class leda_sphere_map_overlayer {
|
||||
|
||||
typedef std::pair<leda_edge,leda_edge> edge_pair;
|
||||
typedef CGAL::Sphere_point<R> SPoint_2;
|
||||
typedef CGAL::Sphere_segment<R> SSegment_2;
|
||||
typedef CGAL::Plane_3<R> Plane_3;
|
||||
typedef GRAPH<SPoint_2,SSegment_2> Sphere_map;
|
||||
|
||||
Sphere_map G;
|
||||
leda_node_map<leda_edge> E;
|
||||
|
||||
public:
|
||||
|
||||
leda_sphere_map_overlayer() : G(),E(G) {}
|
||||
|
||||
const Sphere_map& sphere_map() const { return G; }
|
||||
|
||||
template <typename Iterator>
|
||||
void subdivide(Iterator start, Iterator end)
|
||||
/* subdivision is done in phases
|
||||
- first we partition all segments into the pieces in the
|
||||
closed postive xy-halfspace and into the pieces in the
|
||||
negative xy-halfspace
|
||||
- we sweep both halfspheres separate. Note that the boundary
|
||||
carries the same topology
|
||||
- we unify the graphs embedded into both halfspheres at
|
||||
the boundary.
|
||||
*/
|
||||
{
|
||||
typedef leda_graph_decorator<R,Iterator> leda_graph_output;
|
||||
typedef CGAL::Positive_halfsphere_geometry<R> PH_geometry;
|
||||
typedef CGAL::Segment_overlay_traits<
|
||||
Iterator, leda_graph_output, PH_geometry> PHS_traits;
|
||||
typedef CGAL::generic_sweep<PHS_traits> Positive_halfsphere_sweep;
|
||||
|
||||
typedef CGAL::Negative_halfsphere_geometry<R> NH_geometry;
|
||||
typedef CGAL::Segment_overlay_traits<
|
||||
Iterator, leda_graph_output, NH_geometry> NHS_traits;
|
||||
typedef CGAL::generic_sweep<NHS_traits> Negative_halfsphere_sweep;
|
||||
|
||||
std::list<SSegment_2> Lp,Lm;
|
||||
partition_xy( start, end, Lp , +1);
|
||||
partition_xy( start, end, Lm , -1);
|
||||
// both lists initialized with four quarter segments
|
||||
// supporting the xy-equator thereby separating the
|
||||
// two halfspheres
|
||||
// all other segments in the range are split into their
|
||||
// connected components with respect to the xy-plane.
|
||||
|
||||
leda_node v1,v2;
|
||||
leda_graph_output O(G,E);
|
||||
typedef typename PHS_traits::INPUT Input_range;
|
||||
Positive_halfsphere_sweep SP(Input_range(Lp.begin(),Lp.end()),O);
|
||||
SP.sweep();
|
||||
TRACEN("POS SWEEP\n"<<(dump(std::cerr),""));
|
||||
v1=G.first_node(); v2=G.last_node();
|
||||
Negative_halfsphere_sweep SM(Input_range(Lm.begin(),Lm.end()),O);
|
||||
SM.sweep();
|
||||
TRACEN("NEG SWEEP\n"<<(dump(std::cerr),""));
|
||||
v2 = G.succ_node(v2);
|
||||
// now two CCs of sphere graph calculated
|
||||
// v1 = first node of CC in positive xy-sphere
|
||||
// v2 = first node of CC in negative xy-sphere
|
||||
|
||||
merging_halfspheres(v1,v2);
|
||||
clean_trivial_face_cycles();
|
||||
if (!Is_Plane_Map(G)) error_handler(1,"Sphere map: embedding wrong.");
|
||||
compute_faces();
|
||||
}
|
||||
|
||||
void merge_nodes(leda_edge e1, leda_edge e2)
|
||||
// e1 and e2 are two edges of the xy equator such that
|
||||
// e1 is part of the positive xy-sphere bounding outer face
|
||||
// e2 is part of the negative xy-sphere bounding outer face
|
||||
// e1 and e2 are oppositely oriented
|
||||
// the outer faces are left of the edges
|
||||
// the edges are embedded orderpreserving ccw
|
||||
// then the following code merges the edges of A(target(e2))
|
||||
// to A(source(e1)) preserving the embedding
|
||||
// afterwards source(e1) carries all edges, target(e2) is isolated
|
||||
{
|
||||
leda_node v = source(e1);
|
||||
leda_edge e_pos = e1;
|
||||
leda_edge e = G.reversal(e2), er = e2;
|
||||
leda_edge e_end = e;
|
||||
do {
|
||||
leda_edge e_next = G.cyclic_adj_succ(e);
|
||||
G.move_edge(e,e_pos,target(e));
|
||||
G.move_edge(er,er,v);
|
||||
e_pos = e;
|
||||
e = e_next; er = G.reversal(e);
|
||||
} while ( e != e_end );
|
||||
}
|
||||
|
||||
void merging_halfspheres(leda_node v1, leda_node v2)
|
||||
// v1 and v2 are the definite nodes of both CCs
|
||||
// where the negative y-axis pierces the sphere.
|
||||
// the faces are left of edges
|
||||
// edges are embedded orderpreserving ccw
|
||||
{
|
||||
TRACEN("Merging Halfspheres");
|
||||
leda_edge e1,e2,e3,e4,e1n,e2n;
|
||||
forall_adj_edges(e1,v1)
|
||||
if ( G[target(e1)].hz()==0 && G[target(e1)].hx()<0 ) break;
|
||||
forall_adj_edges(e2,v2)
|
||||
if ( G[target(e2)].hz()==0 && G[target(e2)].hx()>0 ) break;
|
||||
e3 = G.face_cycle_pred(e1);
|
||||
e4 = e2; e2 = G.face_cycle_pred(e2);
|
||||
while ( e1 != e3 || e2 != e4 ) {
|
||||
TRACEN(G[source(e1)]<<" "<< G[target(e2)]);
|
||||
e1n = G.face_cycle_succ(e1); e2n = G.face_cycle_pred(e2);
|
||||
merge_nodes(e1,e2);
|
||||
e1 = e1n; e2 = e2n;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void clean_trivial_face_cycles()
|
||||
// removes trivial face cycles at equator
|
||||
// removes isolated vertices stemming from
|
||||
// equator unification
|
||||
{
|
||||
leda_edge_map<bool> known(G,false);
|
||||
leda_list<leda_edge> L;
|
||||
leda_list<edge_pair> Lr;
|
||||
leda_edge e;
|
||||
forall_edges(e,G) {
|
||||
if (known[e]) continue;
|
||||
leda_edge en = G.face_cycle_succ(e);
|
||||
if ( G.face_cycle_succ(en) != e )
|
||||
continue;
|
||||
// e in trivial face cycle
|
||||
L.append(e); L.append(en);
|
||||
TRACEN("tivial cycle "<<G[source(e)]<<G[target(e)]);
|
||||
known[e] = known[en] = true;
|
||||
leda_edge er = G.reversal(e);
|
||||
leda_edge enr = G.reversal(en);
|
||||
Lr.append(edge_pair(er,enr));
|
||||
}
|
||||
edge_pair ep;
|
||||
forall(ep,Lr) G.set_reversal(ep.first,ep.second);
|
||||
G.del_edges(L);
|
||||
leda_node v;
|
||||
forall_nodes(v,G) if ( G.outdeg(v)==0 ) G.del_node(v);
|
||||
}
|
||||
|
||||
void compute_faces()
|
||||
{
|
||||
G.compute_faces();
|
||||
leda_face f;
|
||||
leda_edge e;
|
||||
forall_faces(f,G) {
|
||||
TRACEN("FACE:");
|
||||
forall_face_edges(e,f)
|
||||
TRACEN(" "<<SSegment_2(G[source(e)],G[target(e)]));
|
||||
}
|
||||
}
|
||||
|
||||
void dump(std::ostream& os, leda_node v, bool nl=true) const
|
||||
{ os << " ["<<::index(v)<<"] "<<G[v];
|
||||
if (nl) os << std::endl; }
|
||||
|
||||
void dump(std::ostream& os) const
|
||||
{
|
||||
leda_node v;
|
||||
leda_edge e;
|
||||
forall_nodes(v,G) {
|
||||
dump(os,v);
|
||||
forall_adj_edges(e,v) {
|
||||
os << " ->";
|
||||
dump(os,target(e),false);
|
||||
os <<" ["<<G[e]<<" ]\n";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}; // leda_sphere_map_overlayer<R>
|
||||
|
||||
|
||||
#endif //LEDA_SPHERE_MAP_H
|
||||
|
||||
|
|
@ -0,0 +1,235 @@
|
|||
#ifndef CGAL_SPHERE_PREDICATES_H
|
||||
#define CGAL_SPHERE_PREDICATES_H
|
||||
|
||||
#include <CGAL/basic.h>
|
||||
#include <CGAL/Nef_S2/SM_iteration.h>
|
||||
|
||||
CGAL_BEGIN_NAMESPACE
|
||||
|
||||
/* |spherical_orientation| takes three points of one hemisphere and
|
||||
returns the orientation of $p_3$ with respect to the halfcircle
|
||||
through $p_1$ and $p_2$. We map this to the 3d orientation predicate
|
||||
of the origin, $p_1$, $p_2$, and $p_3$ */
|
||||
|
||||
template <class R>
|
||||
int spherical_orientation(const Sphere_point<R>& p1,
|
||||
const Sphere_point<R>& p2,
|
||||
const Sphere_point<R>& p3)
|
||||
{ return CGAL::orientation(CGAL::Point_3<R>(0,0,0),p1,p2,p3); }
|
||||
|
||||
|
||||
/* |spherical_compare| codes our order of points during the sweep. The
|
||||
south pole is the first point, the north pole is the last point, then
|
||||
we order lexicographically. We cover the special case where both
|
||||
points are part of the equator first. Otherwise we sort according to
|
||||
the angle of the halfcircle through $S$, $N$, and the points with
|
||||
respect to the xy-plane. If both lie on the same halfcircle then the
|
||||
angle with respect to $OS$ decides. The parameter $pos=1$ does
|
||||
everthing in the positive halfsphere. If $pos=-1$ then we rotate the
|
||||
whole scenery around the y-axis by $\pi$. Then the x-axis points left
|
||||
and the z-axis into the equatorial plane. */
|
||||
|
||||
template <class R>
|
||||
int spherical_compare(const Sphere_point<R>& p1,
|
||||
const Sphere_point<R>& p2,
|
||||
int pos)
|
||||
{
|
||||
Sphere_point<R> pS(0,-1,0),pN(0,1,0);
|
||||
CGAL::Direction_3<R> d1(p1-CGAL::ORIGIN), d2(p2-CGAL::ORIGIN),
|
||||
dS(pS-CGAL::ORIGIN), dN(pN-CGAL::ORIGIN);
|
||||
if (d1 == d2) return 0;
|
||||
if (d1 == dS || d2 == dN) return -1;
|
||||
if (d1 == dN || d2 == dS) return 1;
|
||||
// now no more special cases
|
||||
if ( (p1.hz()==static_cast<typename R::RT>(0)) &&
|
||||
(p2.hz()==static_cast<typename R::RT>(0)) ) {
|
||||
// both in xy-plane, pi.hx() can't be zero
|
||||
int s1 = CGAL_NTS sign(p1.hx());
|
||||
int s2 = CGAL_NTS sign(p2.hx());
|
||||
if ( s1 != s2 ) return pos * s1;
|
||||
// now s1 == s2
|
||||
return s1 * CGAL::spherical_orientation(p1,Sphere_point<R>(0,0,1),p2);
|
||||
|
||||
} else { // not in xy-plane
|
||||
int or = CGAL::spherical_orientation(pS,p1,p2);
|
||||
if ( or ) return or;
|
||||
else // or == 0 => on the same sweep line
|
||||
return CGAL::spherical_orientation(Sphere_point<R>(-pos,0,0),p2,p1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* the next two functions partition the segments in a list into a list
|
||||
that carries the segment parts that are only part of a halfspace.
|
||||
Halfcircles are again divided into two equally sized pieces. */
|
||||
|
||||
template <class R, class I>
|
||||
void partition(const Sphere_circle<R>& c, I start, I beyond,
|
||||
std::list< Sphere_segment<R> >& Lpos)
|
||||
{ TRACEN("partition ");
|
||||
Sphere_segment<R> s1,s2,s3;
|
||||
while ( start != beyond ) { TRACEN(" "<<*start);
|
||||
int i = start->intersection(c,s1,s2);
|
||||
if (i>1) Lpos.push_back(s2);
|
||||
if (i>0) Lpos.push_back(s1);
|
||||
++start;
|
||||
}
|
||||
}
|
||||
|
||||
template <class R, class I>
|
||||
void partition_xy(I start, I beyond,
|
||||
std::list< Sphere_segment<R> >& L, int pos)
|
||||
{
|
||||
Sphere_circle<R> xy_circle(0,0,1), yz_circle(1,0,0);
|
||||
Sphere_point<R> S(0,-1,0),N(0,1,0);
|
||||
Sphere_segment<R> s1,s2;
|
||||
if (pos > 0) partition(xy_circle,start,beyond,L);
|
||||
else partition(xy_circle.opposite(),start,beyond,L);
|
||||
typename std::list< Sphere_segment<R> >::iterator it,itl;
|
||||
TRACEN("partition_xy ");
|
||||
CGAL_forall_iterators(it,L) {
|
||||
TRACEN(" "<<*it);
|
||||
if ( equal_as_sets(it->sphere_circle(),xy_circle) ) {
|
||||
TRACEN(" splitting xy seg "<<*it);
|
||||
int n1 = it->intersection(yz_circle,s1,s2);
|
||||
if (n1 > 1 && !s2.is_degenerate()) L.insert(it,s2);
|
||||
if (n1 > 0 && !s1.is_degenerate()) L.insert(it,s1);
|
||||
int n2 = it->intersection(yz_circle.opposite(),s1,s2);
|
||||
if (n2 > 1 && !s2.is_degenerate()) L.insert(it,s2);
|
||||
if (n2 > 0 && !s1.is_degenerate()) L.insert(it,s1);
|
||||
itl = it; --it; L.erase(itl);
|
||||
// at least one item was appended
|
||||
}
|
||||
}
|
||||
CGAL_forall_iterators(it,L) {
|
||||
if ( it->is_halfcircle() ) {
|
||||
TRACEN(" splitting halfcircle "<<*it);
|
||||
Sphere_segment<R> s1,s2;
|
||||
it->split_halfcircle(s1,s2);
|
||||
*it = s2; L.insert(it,s1);
|
||||
}
|
||||
}
|
||||
// append 4 xy-equator segments:
|
||||
Sphere_segment<R> sp(S,N,xy_circle);
|
||||
Sphere_segment<R> sm(S,N,xy_circle.opposite());
|
||||
Sphere_segment<R> s[4];
|
||||
sp.split_halfcircle(s[0],s[1]);
|
||||
sm.split_halfcircle(s[2],s[3]);
|
||||
L.insert(L.end(),s,s+4);
|
||||
}
|
||||
|
||||
|
||||
/* |intersection| calculates the intersection of a halfspace $h$
|
||||
(defined via a great circle $c$) with a sphere segment
|
||||
$s$. Interesting are the boundary cases. If an endpoint is part of
|
||||
$h^0$, but the part of $s$ incident to the endpoint is not part of
|
||||
$h^{0+}$ then we return a trivial segment.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
template <typename R>
|
||||
int Sphere_segment<R>::
|
||||
intersection(const CGAL::Sphere_circle<R>& c,
|
||||
Sphere_segment<R>& s1, Sphere_segment<R>& s2) const
|
||||
{
|
||||
TRACEN(" intersection "<<*this<<" "<<c);
|
||||
if ( is_degenerate() ) { TRACEN(" degenerate");
|
||||
if ( !c.has_on_negative_side(source()) )
|
||||
{ s1 = *this; return 1; }
|
||||
return 0;
|
||||
}
|
||||
CGAL::Oriented_side or1 = c.oriented_side(source());
|
||||
CGAL::Oriented_side or2 = c.oriented_side(target());
|
||||
if ( or1 == CGAL::opposite(or2) && or1 != or2 ) {
|
||||
/* it is sure that $s$ intersects $h$ in its interior. the
|
||||
question is which part is in the halfspace $h^+$.*/
|
||||
TRACEN(" opposite");
|
||||
Sphere_point<R> i1 = CGAL::intersection(ptr->c_,c);
|
||||
if ( !has_on(i1) ) i1 = i1.opposite();
|
||||
if ( or1 == CGAL::ON_POSITIVE_SIDE )
|
||||
s1 = Sphere_segment<R>(source(),i1,sphere_circle());
|
||||
else if ( or2 == CGAL::ON_POSITIVE_SIDE )
|
||||
s1 = Sphere_segment<R>(i1,target(),sphere_circle());
|
||||
else CGAL_assertion_msg(0,"no intersection.");
|
||||
return 1;
|
||||
}
|
||||
else if ( or1 == CGAL::ON_ORIENTED_BOUNDARY &&
|
||||
or2 == CGAL::ON_ORIENTED_BOUNDARY ) {
|
||||
/* if both ends of $s$ are part of $h$ then $s$ is a halfcircle or
|
||||
$s$ is fully part of $h$. In this case we have to check if the
|
||||
halfcircle is not part of $h^-$. This can be formulated by an
|
||||
orientation test of the point $p$ at the tip of the normal of
|
||||
|s.sphere_circle()| with respect to the plane through the
|
||||
endpoints of $s$ and the tip of the normal of $h$. */
|
||||
TRACEN(" both in plane");
|
||||
if ( source() != target().opposite() ) {
|
||||
s1 = *this; return 1;
|
||||
}
|
||||
// now this is a halfcircle
|
||||
register bool halfcircle_notin_hminus =
|
||||
(CGAL::orientation(source(),target(),
|
||||
CGAL::ORIGIN + c.orthogonal_vector(),
|
||||
CGAL::ORIGIN + sphere_circle().orthogonal_vector())
|
||||
!= CGAL::POSITIVE);
|
||||
TRACE(" ");TRACEV(halfcircle_notin_hminus);
|
||||
if ( halfcircle_notin_hminus ) { s1 = *this; return 1; }
|
||||
else {
|
||||
s1 = Sphere_segment(source(),source(),sphere_circle());
|
||||
s2 = Sphere_segment(target(),target(),sphere_circle());
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
else if ( or1 != CGAL::ON_NEGATIVE_SIDE &&
|
||||
or2 != CGAL::ON_NEGATIVE_SIDE ) {
|
||||
/* this case covers the endpoints of $s$ as part of the closed
|
||||
oriented halfspace $h^{0+}$. At least one is part of
|
||||
$h^{+}$. If $s$ is not long then the segment must be fully part
|
||||
of $h^{0+}$. Otherwise if $s$ is long, then we at both ends
|
||||
there are subsegments as part of $h^{0+}$ (one might be
|
||||
degenerate). */
|
||||
if ( is_long() ) {
|
||||
Sphere_point<R> i1 = CGAL::intersection(ptr->c_,c);
|
||||
Sphere_point<R> i2 = i1.opposite();
|
||||
Sphere_segment<R> so(i1,i2,sphere_circle());
|
||||
if ( so.has_on(source()) && so.has_on(target()) )
|
||||
std::swap(i1,i2);
|
||||
// now source(),i1,i2,target() are circularly ordered
|
||||
s1 = Sphere_segment(source(),i1,sphere_circle());
|
||||
s2 = Sphere_segment(i2,target(),sphere_circle());
|
||||
TRACEN(" both >= plane, long "<<s1<<s2);
|
||||
return 2;
|
||||
} // now short:
|
||||
TRACEN(" both >= plane, short ");
|
||||
s1=*this; return 1;
|
||||
}
|
||||
else if ( or1 != CGAL::ON_POSITIVE_SIDE &&
|
||||
or2 != CGAL::ON_POSITIVE_SIDE ) {
|
||||
/* either both endpoints of $s$ are in $h^-$ or one is in $h^-$
|
||||
and one on $h^0$. */
|
||||
if ( is_long() ) {
|
||||
Sphere_point<R> i1 = CGAL::intersection(ptr->c_,c);
|
||||
Sphere_point<R> i2 = i1.opposite();
|
||||
Sphere_segment<R> so(i1,i2,sphere_circle());
|
||||
TRACEN(" both <= plane, long"<<so);
|
||||
if ( so.has_on(source()) && so.has_on(target()) )
|
||||
{ so = so.complement(); }
|
||||
TRACEN(" both <= plane, long"<<so);
|
||||
s1 = so; return 1;
|
||||
} // now short
|
||||
TRACEN(" both <= plane, short");
|
||||
if ( or1 == CGAL::ON_ORIENTED_BOUNDARY )
|
||||
{ s1 = Sphere_segment<R>(source(),source(),sphere_circle()); return 1; }
|
||||
if ( or2 == CGAL::ON_ORIENTED_BOUNDARY )
|
||||
{ s1 = Sphere_segment<R>(target(),target(),sphere_circle()); return 1; }
|
||||
return 0;
|
||||
}
|
||||
|
||||
CGAL_assertion_msg(0,"Oops, forgot some case.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
CGAL_END_NAMESPACE
|
||||
|
||||
#endif //CGAL_SPHERE_PREDICATES_H
|
||||
|
|
@ -0,0 +1,689 @@
|
|||
// ============================================================================
|
||||
//
|
||||
// Copyright (c) 1997-2000 The CGAL Consortium
|
||||
//
|
||||
// This software and related documentation is part of an INTERNAL release
|
||||
// of the Computational Geometry Algorithms Library (CGAL). It is not
|
||||
// intended for general use.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// release : $CGAL_Revision$
|
||||
// release_date : $CGAL_Date$
|
||||
//
|
||||
// file : include/CGAL/Nef_polyhedron_S2.h
|
||||
// package : Nef_S2
|
||||
// chapter : Nef Polyhedra
|
||||
//
|
||||
// revision : $Revision$
|
||||
// revision_date : $Date$
|
||||
//
|
||||
// author(s) : Michael Seel <seel@mpi-sb.mpg.de>
|
||||
// maintainer : Michael Seel <seel@mpi-sb.mpg.de>
|
||||
// coordinator : Michael Seel <seel@mpi-sb.mpg.de>
|
||||
//
|
||||
// implementation: Nef polyhedra in the sphere surface
|
||||
// ============================================================================
|
||||
|
||||
#ifndef CGAL_NEF_POLYHEDRON_S2_H
|
||||
#define CGAL_NEF_POLYHEDRON_S2_H
|
||||
|
||||
#include <CGAL/basic.h>
|
||||
#include <CGAL/Handle_for.h>
|
||||
#include <CGAL/Random.h>
|
||||
#include <CGAL/Nef_S2/Sphere_map.h>
|
||||
#include <CGAL/Nef_S2/SM_decorator.h>
|
||||
#include <CGAL/Nef_S2/SM_io_parser.h>
|
||||
#include <CGAL/Nef_S2/SM_point_locator.h>
|
||||
#include <CGAL/Nef_S2/SM_overlayer.h>
|
||||
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#undef _DEBUG
|
||||
#define _DEBUG 121
|
||||
#include <CGAL/Nef_S2/debug.h>
|
||||
|
||||
CGAL_BEGIN_NAMESPACE
|
||||
|
||||
template <typename K> class Nef_polyhedron_S2;
|
||||
template <typename K> class Nef_polyhedron_S2_rep;
|
||||
|
||||
template <typename K>
|
||||
std::ostream& operator<<(std::ostream&, const Nef_polyhedron_S2<K>&);
|
||||
template <typename K>
|
||||
std::istream& operator>>(std::istream&, Nef_polyhedron_S2<K>&);
|
||||
|
||||
|
||||
template <typename K>
|
||||
class Nef_polyhedron_S2_rep : public Ref_counted
|
||||
{ typedef Nef_polyhedron_S2_rep<K> Self;
|
||||
friend class Nef_polyhedron_S2<K>;
|
||||
|
||||
typedef K Kernel;
|
||||
typedef CGAL::Sphere_geometry<Kernel> Sphere_kernel;
|
||||
typedef CGAL::Sphere_map<Sphere_kernel> Sphere_map;
|
||||
typedef CGAL::SM_const_decorator<Sphere_map,Sphere_kernel>
|
||||
Const_decorator;
|
||||
typedef CGAL::SM_decorator<Sphere_map,Sphere_kernel> Decorator;
|
||||
typedef CGAL::SM_overlayer<Decorator> Overlayer;
|
||||
typedef CGAL::SM_point_locator<Decorator> Locator;
|
||||
|
||||
Sphere_map sm_;
|
||||
|
||||
public:
|
||||
Nef_polyhedron_S2_rep() : Ref_counted(), sm_() {}
|
||||
Nef_polyhedron_S2_rep(const Self& R) : Ref_counted(), sm_() {}
|
||||
~Nef_polyhedron_S2_rep() { sm_.clear(); }
|
||||
};
|
||||
|
||||
/*{\Moptions print_title=yes }*/
|
||||
/*{\Manpage {Nef_polyhedron_S2}{K}
|
||||
{Nef Polyhedra in the sphere surface}{N}}*/
|
||||
|
||||
/*{\Mdefinition An instance of data type |\Mname| is a subset of $S_2$
|
||||
that is the result of forming complements and intersections starting
|
||||
from a finite set |H| of half-spaces. |\Mtype| is closed under all
|
||||
binary set operations |intersection|, |union|, |difference|,
|
||||
|complement| and under the topological operations |boundary|,
|
||||
|closure|, and |interior|.
|
||||
|
||||
The template parameter |Kernel| is specified via a kernel concept.
|
||||
|Kernel| must be a model of the concept |NefSphereKernelTraits_2|.
|
||||
}*/
|
||||
|
||||
template <typename K>
|
||||
class Nef_polyhedron_S2 : public Handle_for< Nef_polyhedron_S2_rep<K> >
|
||||
{
|
||||
public:
|
||||
typedef K Kernel;
|
||||
|
||||
/*{\Mtypes 7}*/
|
||||
typedef Nef_polyhedron_S2<K> Self;
|
||||
typedef Nef_polyhedron_S2_rep<K> Rep;
|
||||
typedef Handle_for< Nef_polyhedron_S2_rep<K> > Base;
|
||||
typedef typename Rep::Sphere_kernel Sphere_kernel;
|
||||
typedef typename Rep::Sphere_map Sphere_map;
|
||||
|
||||
typedef typename Sphere_kernel::Sphere_point Sphere_point;
|
||||
/*{\Mtypemember points in the sphere surface.}*/
|
||||
|
||||
typedef typename Sphere_kernel::Sphere_segment Sphere_segment;
|
||||
/*{\Mtypemember segments in the sphere surface.}*/
|
||||
|
||||
typedef typename Sphere_kernel::Sphere_circle Sphere_circle;
|
||||
/*{\Mtypemember oriented great circles modeling spherical half-spaces}*/
|
||||
|
||||
typedef typename Sphere_kernel::Sphere_direction Sphere_direction;
|
||||
|
||||
typedef typename Sphere_map::Mark Mark;
|
||||
/*{\Xtypemember marking set membership or exclusion.}*/
|
||||
|
||||
enum Boundary { EXCLUDED=0, INCLUDED=1 };
|
||||
/*{\Menum construction selection.}*/
|
||||
|
||||
enum Content { EMPTY=0, COMPLETE=1 };
|
||||
/*{\Menum construction selection}*/
|
||||
|
||||
const Sphere_map& sphere_map() const { return ptr->sm_; }
|
||||
protected:
|
||||
Sphere_map& sphere_map() { return ptr->sm_; }
|
||||
|
||||
struct AND { bool operator()(bool b1, bool b2) const { return b1&&b2; } };
|
||||
struct OR { bool operator()(bool b1, bool b2) const { return b1||b2; } };
|
||||
struct DIFF { bool operator()(bool b1, bool b2) const { return b1&&!b2; } };
|
||||
struct XOR { bool operator()(bool b1, bool b2) const
|
||||
{ return (b1&&!b2)||(!b1&&b2); } };
|
||||
|
||||
typedef Nef_polyhedron_S2_rep<K> Nef_rep;
|
||||
typedef typename Nef_rep::Decorator Decorator;
|
||||
typedef typename Nef_rep::Const_decorator Const_decorator;
|
||||
typedef typename Nef_rep::Overlayer Overlayer;
|
||||
typedef typename Nef_rep::Locator Locator;
|
||||
|
||||
friend std::ostream& operator<< CGAL_NULL_TMPL_ARGS
|
||||
(std::ostream& os, const Nef_polyhedron_S2<K>& NP);
|
||||
friend std::istream& operator>> CGAL_NULL_TMPL_ARGS
|
||||
(std::istream& is, Nef_polyhedron_S2<K>& NP);
|
||||
|
||||
typedef typename Decorator::Vertex_handle Vertex_handle;
|
||||
typedef typename Decorator::Halfedge_handle Halfedge_handle;
|
||||
typedef typename Decorator::Halfloop_handle Halfloop_handle;
|
||||
typedef typename Decorator::Face_handle Face_handle;
|
||||
|
||||
typedef typename Decorator::Vertex_const_handle Vertex_const_handle;
|
||||
typedef typename Decorator::Halfedge_const_handle Halfedge_const_handle;
|
||||
typedef typename Decorator::Halfloop_const_handle Halfloop_const_handle;
|
||||
typedef typename Decorator::Face_const_handle Face_const_handle;
|
||||
|
||||
typedef typename Decorator::Vertex_iterator Vertex_iterator;
|
||||
typedef typename Decorator::Halfedge_iterator Halfedge_iterator;
|
||||
typedef typename Decorator::Halfloop_iterator Halfloop_iterator;
|
||||
typedef typename Decorator::Face_iterator Face_iterator;
|
||||
typedef typename Const_decorator::Vertex_const_iterator
|
||||
Vertex_const_iterator;
|
||||
typedef typename Const_decorator::Halfedge_const_iterator
|
||||
Halfedge_const_iterator;
|
||||
typedef typename Const_decorator::Halfloop_const_iterator
|
||||
Halfloop_const_iterator;
|
||||
typedef typename Const_decorator::Face_const_iterator
|
||||
Face_const_iterator;
|
||||
|
||||
typedef std::list<Sphere_segment> SS_list;
|
||||
typedef typename SS_list::const_iterator SS_iterator;
|
||||
|
||||
public:
|
||||
/*{\Mcreation 3}*/
|
||||
|
||||
Nef_polyhedron_S2(Content sphere = EMPTY) : Base(Nef_rep())
|
||||
/*{\Mcreate creates an instance |\Mvar| of type |\Mname|
|
||||
and initializes it to the empty set if |sphere == EMPTY|
|
||||
and to the whole sphere if |sphere == COMPLETE|.}*/
|
||||
{
|
||||
SS_list L;
|
||||
Decorator D(sphere_map());
|
||||
D.mark_of_halfsphere(-1) = D.mark_of_halfsphere(+1) = bool(sphere);
|
||||
}
|
||||
|
||||
|
||||
Nef_polyhedron_S2(const Sphere_circle& c,
|
||||
Boundary circle = INCLUDED) : Base(Nef_rep())
|
||||
/*{\Mcreate creates a Nef polyhedron |\Mvar| containing the half-sphere
|
||||
left of |c| including |c| if |circle==INCLUDED|, excluding |c| if
|
||||
|circle==EXCLUDED|.}*/
|
||||
{ TRACEN("Nef_polyhedron_S2(): construction from circle "<<c);
|
||||
Overlayer D(sphere_map()); D.create(c);
|
||||
Halfloop_handle h = D.halfloop();
|
||||
if ( D.circle(h) != c ) h = D.twin(h);
|
||||
D.mark(D.face(h)) = true;
|
||||
D.mark(h) = bool(circle);
|
||||
Locator L(sphere_map()); L.init_marks_of_halfspheres();
|
||||
}
|
||||
|
||||
|
||||
template <class Forward_iterator>
|
||||
Nef_polyhedron_S2(Forward_iterator first, Forward_iterator beyond,
|
||||
Boundary b = INCLUDED) : Base(Nef_rep())
|
||||
/*{\Mcreate creates a Nef polyhedron |\Mvar| from the set of sphere
|
||||
segments in the iterator range |[first,beyond)|. If the set of sphere
|
||||
segments is a simple polygon that separates the sphere surface
|
||||
into two regions, then the polygonal region that is left of the
|
||||
segment |*first| is selected. The polygonal region includes its
|
||||
boundary if |b = INCLUDED| and excludes the boundary
|
||||
otherwise. |Forward_iterator| has to be an iterator with value
|
||||
type |Sphere_segment|.}*/
|
||||
{ TRACEN("Nef_polyhedron_S2(): creation from segment range");
|
||||
CGAL_assertion(first!=beyond);
|
||||
Overlayer D(sphere_map());
|
||||
Sphere_segment s = *first;
|
||||
D.create_from_segments(first,beyond);
|
||||
Halfedge_iterator e;
|
||||
CGAL_forall_halfedges(e,D) {
|
||||
Sphere_circle c(D.circle(e));
|
||||
if ( c == s.sphere_circle() ) break;
|
||||
}
|
||||
if ( e != Halfedge_iterator() ) {
|
||||
if ( D.circle(e) != s.sphere_circle() ) e = D.twin(e);
|
||||
CGAL_assertion( D.circle(e) == s.sphere_circle() );
|
||||
D.set_marks_in_face_cycle(e,bool(b));
|
||||
if ( D.number_of_faces() > 2 ) D.mark(D.face(e)) = true;
|
||||
else D.mark(D.face(e)) = !bool(b);
|
||||
return;
|
||||
}
|
||||
D.simplify();
|
||||
Locator L(sphere_map()); L.init_marks_of_halfspheres();
|
||||
}
|
||||
|
||||
Nef_polyhedron_S2(const Nef_polyhedron_S2<K>& N1) : Base(N1) {}
|
||||
Nef_polyhedron_S2& operator=(const Nef_polyhedron_S2<K>& N1)
|
||||
{ Base::operator=(N1); return (*this); }
|
||||
~Nef_polyhedron_S2() {}
|
||||
|
||||
|
||||
template <class Forward_iterator>
|
||||
Nef_polyhedron_S2(Forward_iterator first, Forward_iterator beyond,
|
||||
double p) : Base(Nef_rep())
|
||||
/*{\Xcreate creates a random Nef polyhedron from the arrangement of
|
||||
the set of circles |S = set[first,beyond)|. The cells of the arrangement
|
||||
are selected uniformly at random with probability $p$. \precond $0 < p
|
||||
< 1$.}*/
|
||||
{ CGAL_assertion(0<p && p<1);
|
||||
CGAL_assertion(first!=beyond);
|
||||
Overlayer D(sphere_map());
|
||||
D.create_from_circles(first, beyond); D.simplify();
|
||||
Vertex_iterator v; Halfedge_iterator e; Face_iterator f;
|
||||
CGAL_forall_vertices(v,D)
|
||||
D.mark(v) = ( default_random.get_double() < p ? true : false );
|
||||
CGAL_forall_halfedges(e,D)
|
||||
D.mark(e) = ( default_random.get_double() < p ? true : false );
|
||||
CGAL_forall_faces(f,D)
|
||||
D.mark(f) = ( default_random.get_double() < p ? true : false );
|
||||
D.simplify();
|
||||
Locator L(sphere_map()); L.init_marks_of_halfspheres();
|
||||
}
|
||||
|
||||
protected:
|
||||
Nef_polyhedron_S2(const Sphere_map& H, bool clone=true) : Base(Nef_rep())
|
||||
/*{\Xcreate makes |\Mvar| a new object. If |clone==true| then the
|
||||
underlying structure of |H| is copied into |\Mvar|.}*/
|
||||
{ if (clone) ptr->sm_ = H; }
|
||||
|
||||
void clone_rep() { *this = Nef_polyhedron_S2<K>(sphere_map()); }
|
||||
|
||||
/*{\Moperations 4 3 }*/
|
||||
public:
|
||||
|
||||
void clear(Content plane = EMPTY)
|
||||
{ *this = Nef_polyhedron_S2(plane); }
|
||||
/*{\Mop makes |\Mvar| the empty set if |plane == EMPTY| and the
|
||||
full plane if |plane == COMPLETE|.}*/
|
||||
|
||||
bool is_empty() const
|
||||
/*{\Mop returns true if |\Mvar| is empty, false otherwise.}*/
|
||||
{ Const_decorator D(sphere_map());
|
||||
Face_const_iterator f = D.faces_begin();
|
||||
return (D.number_of_vertices()==0 &&
|
||||
D.number_of_edges()==0 &&
|
||||
D.number_of_loops()==0 &&
|
||||
D.number_of_faces()==1 &&
|
||||
D.mark(f) == false);
|
||||
}
|
||||
|
||||
bool is_plane() const
|
||||
/*{\Mop returns true if |\Mvar| is the whole plane, false otherwise.}*/
|
||||
{ Const_decorator D(sphere_map());
|
||||
Face_const_iterator f = D.faces_begin();
|
||||
return (D.number_of_vertices()==0 &&
|
||||
D.number_of_edges()==0 &&
|
||||
D.number_of_loops()==0 &&
|
||||
D.number_of_faces()==1 &&
|
||||
D.mark(f) == true);
|
||||
}
|
||||
|
||||
void extract_complement()
|
||||
{ TRACEN("extract complement");
|
||||
if ( ptr->is_shared() ) clone_rep();
|
||||
Overlayer D(sphere_map());
|
||||
Vertex_iterator v, vend = D.vertices_end();
|
||||
for(v = D.vertices_begin(); v != vend; ++v)
|
||||
D.mark(v) = !D.mark(v);
|
||||
|
||||
Unique_hash_map<Halfedge_iterator,bool> Done(false);
|
||||
Halfedge_iterator e, eend = D.halfedges_end();
|
||||
for(e = D.halfedges_begin(); e != eend; ++e) {
|
||||
if ( Done[e] ) continue;
|
||||
D.mark(e) = !D.mark(e);
|
||||
Done[e] = Done[D.twin(e)] = true;
|
||||
}
|
||||
|
||||
Face_iterator f, fend = D.faces_end();
|
||||
for(f = D.faces_begin(); f != fend; ++f)
|
||||
D.mark(f) = !D.mark(f);
|
||||
if ( D.has_loop() )
|
||||
D.mark(D.halfloop()) = !D.mark(D.halfloop());
|
||||
D.mark_of_halfsphere(-1) = !D.mark_of_halfsphere(-1);
|
||||
D.mark_of_halfsphere(+1) = !D.mark_of_halfsphere(+1);
|
||||
}
|
||||
|
||||
void extract_interior()
|
||||
{ TRACEN("extract interior");
|
||||
if ( ptr->is_shared() ) clone_rep();
|
||||
Overlayer D(sphere_map());
|
||||
Vertex_iterator v, vend = D.vertices_end();
|
||||
for(v = D.vertices_begin(); v != vend; ++v) D.mark(v) = false;
|
||||
Halfedge_iterator e, eend = D.halfedges_end();
|
||||
for(e = D.halfedges_begin(); e != eend; ++e) D.mark(e) = false;
|
||||
if ( D.has_loop() ) D.mark(D.halfloop()) = false;
|
||||
D.simplify();
|
||||
}
|
||||
|
||||
|
||||
void extract_boundary()
|
||||
{ TRACEN("extract boundary");
|
||||
if ( ptr->is_shared() ) clone_rep();
|
||||
Overlayer D(sphere_map());
|
||||
Vertex_iterator v, vend = D.vertices_end();
|
||||
for(v = D.vertices_begin(); v != vend; ++v) D.mark(v) = true;
|
||||
Halfedge_iterator e, eend = D.halfedges_end();
|
||||
for(e = D.halfedges_begin(); e != eend; ++e) D.mark(e) = true;
|
||||
if ( D.has_loop() ) D.mark(D.halfloop()) = true;
|
||||
Face_iterator f, fend = D.faces_end();
|
||||
for(f = D.faces_begin(); f != fend; ++f) D.mark(f) = false;
|
||||
D.mark_of_halfsphere(-1) = D.mark_of_halfsphere(+1) = false;
|
||||
D.simplify();
|
||||
}
|
||||
|
||||
void extract_closure()
|
||||
/*{\Xop converts |\Mvar| to its closure. }*/
|
||||
{ TRACEN("extract closure");
|
||||
extract_complement();
|
||||
extract_interior();
|
||||
extract_complement();
|
||||
}
|
||||
|
||||
void extract_regularization()
|
||||
/*{\Xop converts |\Mvar| to its regularization. }*/
|
||||
{ TRACEN("extract regularization");
|
||||
extract_interior();
|
||||
extract_closure();
|
||||
}
|
||||
|
||||
/*{\Mtext \headerline{Constructive Operations}}*/
|
||||
|
||||
Nef_polyhedron_S2<K> complement() const
|
||||
/*{\Mop returns the complement of |\Mvar| in the plane.}*/
|
||||
{ Nef_polyhedron_S2<K> res = *this;
|
||||
res.extract_complement();
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
Nef_polyhedron_S2<K> interior() const
|
||||
/*{\Mop returns the interior of |\Mvar|.}*/
|
||||
{ Nef_polyhedron_S2<K> res = *this;
|
||||
res.extract_interior();
|
||||
return res;
|
||||
}
|
||||
|
||||
Nef_polyhedron_S2<K> closure() const
|
||||
/*{\Mop returns the closure of |\Mvar|.}*/
|
||||
{ Nef_polyhedron_S2<K> res = *this;
|
||||
res.extract_closure();
|
||||
return res;
|
||||
}
|
||||
|
||||
Nef_polyhedron_S2<K> boundary() const
|
||||
/*{\Mop returns the boundary of |\Mvar|.}*/
|
||||
{ Nef_polyhedron_S2<K> res = *this;
|
||||
res.extract_boundary();
|
||||
return res;
|
||||
}
|
||||
|
||||
Nef_polyhedron_S2<K> regularization() const
|
||||
/*{\Mop returns the regularized polyhedron (closure of interior).}*/
|
||||
{ Nef_polyhedron_S2<K> res = *this;
|
||||
res.extract_regularization();
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
Nef_polyhedron_S2<K> intersection(const Nef_polyhedron_S2<K>& N1) const
|
||||
/*{\Mop returns |\Mvar| $\cap$ |N1|. }*/
|
||||
{ Nef_polyhedron_S2<K> res(sphere_map(),false); // empty
|
||||
Overlayer D(res.sphere_map());
|
||||
D.subdivide(sphere_map(),N1.sphere_map());
|
||||
AND _and; D.select(_and); D.simplify();
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
Nef_polyhedron_S2<K> join(const Nef_polyhedron_S2<K>& N1) const
|
||||
/*{\Mop returns |\Mvar| $\cup$ |N1|. }*/
|
||||
{ Nef_polyhedron_S2<K> res(sphere_map(),false); // empty
|
||||
Overlayer D(res.sphere_map());
|
||||
D.subdivide(sphere_map(),N1.sphere_map());
|
||||
OR _or; D.select(_or); D.simplify();
|
||||
return res;
|
||||
}
|
||||
|
||||
Nef_polyhedron_S2<K> difference(const Nef_polyhedron_S2<K>& N1) const
|
||||
/*{\Mop returns |\Mvar| $-$ |N1|. }*/
|
||||
{ Nef_polyhedron_S2<K> res(sphere_map(),false); // empty
|
||||
Overlayer D(res.sphere_map());
|
||||
D.subdivide(sphere_map(),N1.sphere_map());
|
||||
DIFF _diff; D.select(_diff); D.simplify();
|
||||
return res;
|
||||
}
|
||||
|
||||
Nef_polyhedron_S2<K> symmetric_difference(
|
||||
const Nef_polyhedron_S2<K>& N1) const
|
||||
/*{\Mop returns the symmectric difference |\Mvar - T| $\cup$
|
||||
|T - \Mvar|. }*/
|
||||
{ Nef_polyhedron_S2<K> res(sphere_map(),false); // empty
|
||||
Overlayer D(res.sphere_map());
|
||||
D.subdivide(sphere_map(),N1.sphere_map());
|
||||
XOR _xor; D.select(_xor); D.simplify();
|
||||
return res;
|
||||
}
|
||||
|
||||
/*{\Mtext Additionally there are operators |*,+,-,^,!| which
|
||||
implement the binary operations \emph{intersection}, \emph{union},
|
||||
\emph{difference}, \emph{symmetric difference}, and the unary
|
||||
operation \emph{complement} respectively. There are also the
|
||||
corresponding modification operations |*=,+=,-=,^=|.}*/
|
||||
|
||||
Nef_polyhedron_S2<K> operator*(const Nef_polyhedron_S2<K>& N1) const
|
||||
{ return intersection(N1); }
|
||||
|
||||
Nef_polyhedron_S2<K> operator+(const Nef_polyhedron_S2<K>& N1) const
|
||||
{ return join(N1); }
|
||||
|
||||
Nef_polyhedron_S2<K> operator-(const Nef_polyhedron_S2<K>& N1) const
|
||||
{ return difference(N1); }
|
||||
|
||||
Nef_polyhedron_S2<K> operator^(const Nef_polyhedron_S2<K>& N1) const
|
||||
{ return symmetric_difference(N1); }
|
||||
|
||||
Nef_polyhedron_S2<K> operator!() const
|
||||
{ return complement(); }
|
||||
|
||||
Nef_polyhedron_S2<K>& operator*=(const Nef_polyhedron_S2<K>& N1)
|
||||
{ this = intersection(N1); return *this; }
|
||||
|
||||
Nef_polyhedron_S2<K>& operator+=(const Nef_polyhedron_S2<K>& N1)
|
||||
{ this = join(N1); return *this; }
|
||||
|
||||
Nef_polyhedron_S2<K>& operator-=(const Nef_polyhedron_S2<K>& N1)
|
||||
{ this = difference(N1); return *this; }
|
||||
|
||||
Nef_polyhedron_S2<K>& operator^=(const Nef_polyhedron_S2<K>& N1)
|
||||
{ this = symmetric_difference(N1); return *this; }
|
||||
|
||||
/*{\Mtext There are also comparison operations like |<,<=,>,>=,==,!=|
|
||||
which implement the relations subset, subset or equal, superset, superset
|
||||
or equal, equality, inequality, respectively.}*/
|
||||
|
||||
bool operator==(const Nef_polyhedron_S2<K>& N1) const
|
||||
{ return symmetric_difference(N1).is_empty(); }
|
||||
|
||||
bool operator!=(const Nef_polyhedron_S2<K>& N1) const
|
||||
{ return !operator==(N1); }
|
||||
|
||||
bool operator<=(const Nef_polyhedron_S2<K>& N1) const
|
||||
{ return difference(N1).is_empty(); }
|
||||
|
||||
bool operator<(const Nef_polyhedron_S2<K>& N1) const
|
||||
{ return difference(N1).is_empty() && !N1.difference(*this).is_empty(); }
|
||||
|
||||
bool operator>=(const Nef_polyhedron_S2<K>& N1) const
|
||||
{ return N1.difference(*this).is_empty(); }
|
||||
|
||||
bool operator>(const Nef_polyhedron_S2<K>& N1) const
|
||||
{ return N1.difference(*this).is_empty() && !difference(N1).is_empty(); }
|
||||
|
||||
|
||||
/*{\Mtext \headerline{Exploration - Point location - Ray shooting}
|
||||
As Nef polyhedra are the result of forming complements
|
||||
and intersections starting from a set |H| of half-spaces that are
|
||||
defined by oriented lines in the plane, they can be represented by
|
||||
an attributed plane map $M = (V,E,F)$. For topological queries
|
||||
within |M| the following types and operations allow exploration
|
||||
access to this structure.}*/
|
||||
|
||||
/*{\Mtypes 3}*/
|
||||
typedef Const_decorator Topological_explorer;
|
||||
|
||||
//typedef CGAL::SM_explorer<Const_decorator,T> Explorer;
|
||||
|
||||
typedef Const_decorator Explorer;
|
||||
/*{\Mtypemember a decorator to examine the underlying plane map.
|
||||
See the manual page of |Explorer|.}*/
|
||||
|
||||
typedef typename Locator::Object_handle Object_handle;
|
||||
/*{\Mtypemember a generic handle to an object of the underlying
|
||||
plane map. The kind of object |(vertex, halfedge, face)| can
|
||||
be determined and the object can be assigned to a corresponding
|
||||
handle by the three functions:\\
|
||||
|bool assign(Vertex_const_handle& h, Object_handle)|\\
|
||||
|bool assign(Halfedge_const_handle& h, Object_handle)|\\
|
||||
|bool assign(Face_const_handle& h, Object_handle)|\\
|
||||
where each function returns |true| iff the assignment to
|
||||
|h| was done.}*/
|
||||
|
||||
|
||||
/*{\Moperations 3 1 }*/
|
||||
|
||||
bool contains(Object_handle h) const
|
||||
/*{\Mop returns true iff the object |h| is contained in the set
|
||||
represented by |\Mvar|.}*/
|
||||
{ Locator PL(sphere_map()); return PL.mark(h); }
|
||||
|
||||
bool contained_in_boundary(Object_handle h) const
|
||||
/*{\Mop returns true iff the object |h| is contained in the $1$-skeleton
|
||||
of |\Mvar|.}*/
|
||||
{ Vertex_const_handle v;
|
||||
Halfedge_const_handle e;
|
||||
return ( CGAL::assign(v,h) || CGAL::assign(e,h) );
|
||||
}
|
||||
|
||||
|
||||
Object_handle locate(const Sphere_point& p) const
|
||||
/*{\Mop returns a generic handle |h| to an object (face, halfedge, vertex)
|
||||
of the underlying plane map that contains the point |p| in its relative
|
||||
interior. The point |p| is contained in the set represented by |\Mvar| if
|
||||
|\Mvar.contains(h)| is true. The location mode flag |m| allows one to choose
|
||||
between different point location strategies.}*/
|
||||
{
|
||||
Locator PL(sphere_map());
|
||||
return PL.locate(p);
|
||||
}
|
||||
|
||||
struct INSET {
|
||||
const Const_decorator& D;
|
||||
INSET(const Const_decorator& Di) : D(Di) {}
|
||||
bool operator()(Vertex_const_handle v) const { return D.mark(v); }
|
||||
bool operator()(Halfedge_const_handle e) const { return D.mark(e); }
|
||||
bool operator()(Halfloop_const_handle l) const { return D.mark(l); }
|
||||
bool operator()(Face_const_handle f) const { return D.mark(f); }
|
||||
};
|
||||
|
||||
Object_handle ray_shoot(const Sphere_point& p,
|
||||
const Sphere_direction& d) const
|
||||
/*{\Mop returns a handle |h| with |\Mvar.contains(h)| that can be
|
||||
converted to a |Vertex_/Halfedge_/Face_const_handle| as described
|
||||
above. The object returned is intersected by the ray starting in |p|
|
||||
with direction |d| and has minimal distance to |p|. The operation
|
||||
returns the null handle |NULL| if the ray shoot along |d| does not hit
|
||||
any object |h| of |\Mvar| with |\Mvar.contains(h)|.}*/
|
||||
{
|
||||
Locator PL(sphere_map());
|
||||
return PL.ray_shoot(p,d,INSET(PL));
|
||||
}
|
||||
|
||||
struct INSKEL {
|
||||
bool operator()(Vertex_const_handle) const { return true; }
|
||||
bool operator()(Halfedge_const_handle) const { return true; }
|
||||
bool operator()(Halfloop_const_handle) const { return true; }
|
||||
bool operator()(Face_const_handle) const { return false; }
|
||||
};
|
||||
|
||||
Object_handle ray_shoot_to_boundary(const Sphere_point& p,
|
||||
const Sphere_direction& d) const
|
||||
/*{\Mop returns a handle |h| that can be converted to a
|
||||
|Vertex_/Halfedge_const_handle| as described above. The object
|
||||
returned is part of the $1$-skeleton of |\Mvar|, intersected by the
|
||||
ray starting in |p| with direction |d| and has minimal distance to
|
||||
|p|. The operation returns the null handle |NULL| if the ray shoot
|
||||
along |d| does not hit any $1$-skeleton object |h| of |\Mvar|. The
|
||||
location mode flag |m| allows one to choose between different point
|
||||
location strategies.}*/
|
||||
{
|
||||
Locator PL(sphere_map());
|
||||
return PL.ray_shoot(p,d,INSKEL());
|
||||
}
|
||||
|
||||
|
||||
Explorer explorer() const
|
||||
/*{\Mop returns a decorator object which allows read-only access of
|
||||
the underlying plane map. See the manual page |Explorer| for its
|
||||
usage.}*/
|
||||
{ return Explorer(const_cast<Sphere_map&>(sphere_map())); }
|
||||
|
||||
/*{\Mtext\headerline{Input and Output}
|
||||
A Nef polyhedron |\Mvar| can be visualized in an open GL window. The
|
||||
output operator is defined in the file
|
||||
|CGAL/IO/Nef_\-poly\-hedron_2_\-Win\-dow_\-stream.h|.
|
||||
}*/
|
||||
|
||||
/*{\Mimplementation Nef polyhedra are implemented on top of a halfedge
|
||||
data structure and use linear space in the number of vertices, edges
|
||||
and facets. Operations like |empty| take constant time. The
|
||||
operations |clear|, |complement|, |interior|, |closure|, |boundary|,
|
||||
|regularization|, input and output take linear time. All binary set
|
||||
operations and comparison operations take time $O(n \log n)$ where $n$
|
||||
is the size of the output plus the size of the input.
|
||||
|
||||
The point location and ray shooting operations are implemented in
|
||||
the naive way. The operations run in linear query time without
|
||||
any preprocessing.}*/
|
||||
|
||||
/*{\Mexample Nef polyhedra are parameterized by a standard CGAL
|
||||
kernel.
|
||||
|
||||
\begin{Mverb}
|
||||
#include <CGAL/Homogeneous.h>
|
||||
#include <CGAL/leda_integer.h>
|
||||
#include <CGAL/Nef_polyhedron_S2.h>
|
||||
|
||||
using namespace CGAL;
|
||||
typedef Homogeneous<leda_integer> Kernel;
|
||||
typedef Nef_polyhedron_S2<Kernel> Nef_polyhedron;
|
||||
typedef Nef_polyhedron::Sphere_circle Sphere_circle;
|
||||
|
||||
int main()
|
||||
{
|
||||
Nef_polyhedron N1(Sphere_circle(1,0,0));
|
||||
Nef_polyhedron N2(Sphere_circle(0,1,0), Nef_polyhedron::EXCLUDED);
|
||||
Nef_polyhedron N3 = N1 * N2; // line (*)
|
||||
return 0;
|
||||
}
|
||||
\end{Mverb}
|
||||
After line (*) |N3| is the intersection of |N1| and |N2|.}*/
|
||||
|
||||
|
||||
}; // end of Nef_polyhedron_S2
|
||||
|
||||
|
||||
template <typename K>
|
||||
std::ostream& operator<<
|
||||
(std::ostream& os, const Nef_polyhedron_S2<K>& NP)
|
||||
{
|
||||
os << "Nef_polyhedron_S2\n";
|
||||
typedef typename Nef_polyhedron_S2<K>::Decorator Decorator;
|
||||
typedef typename Nef_polyhedron_S2<K>::Sphere_map Sphere_map;
|
||||
CGAL::SM_io_parser<Decorator> O(os,
|
||||
const_cast<Sphere_map&>(NP.sphere_map()));
|
||||
O.print();
|
||||
return os;
|
||||
}
|
||||
|
||||
template <typename K>
|
||||
std::istream& operator>>
|
||||
(std::istream& is, Nef_polyhedron_S2<K>& NP)
|
||||
{
|
||||
typedef typename Nef_polyhedron_S2<K>::Decorator Decorator;
|
||||
CGAL::SM_io_parser<Decorator> I(is, NP.sphere_map());
|
||||
if ( I.check_sep("Nef_polyhedron_S2") ) I.read();
|
||||
else {
|
||||
std::cerr << "Nef_polyhedron_S2 input corrupted." << std::endl;
|
||||
NP = Nef_polyhedron_S2<K>();
|
||||
}
|
||||
typename Nef_polyhedron_S2<K>::Topological_explorer D(NP.explorer());
|
||||
D.check_integrity_and_topological_planarity();
|
||||
return is;
|
||||
}
|
||||
|
||||
|
||||
CGAL_END_NAMESPACE
|
||||
#endif //CGAL_NEF_POLYHEDRON_S2_H
|
||||
|
||||
|
||||
|
|
@ -0,0 +1 @@
|
|||
Michael Seel <seel@mpi-sb.mpg.de>
|
||||
|
|
@ -0,0 +1 @@
|
|||
0.9.0 ( 20 Nov 2001)
|
||||
Loading…
Reference in New Issue