// Copyright (c) 1997-2002 Max-Planck-Institute Saarbruecken (Germany). // All rights reserved. // // This file is part of CGAL (www.cgal.org). // You can redistribute it and/or modify it under the terms of the GNU // General Public License as published by the Free Software Foundation, // either version 3 of the License, or (at your option) any later version. // // Licensees holding a valid commercial license may use this file in // accordance with the commercial license agreement provided with the software. // // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE // WARRANTY OF DESISGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. // // $URL$ // $Id$ // SPDX-License-Identifier: GPL-3.0+ // // // Author(s) : Michael Seel // Miguel Granados // Susan Hert // Lutz Kettner // Peter Hachenberger #ifndef CGAL_NEF3_BINARY_OPERATION_H #define CGAL_NEF3_BINARY_OPERATION_H #include #include #include #include #include #include #include #include #include #include #include #include #include //#include #undef CGAL_NEF_DEBUG #define CGAL_NEF_DEBUG 19 #include namespace CGAL { #if defined (CGAL_NEF3_TIMER_OVERLAY) || defined(CGAL_NEF3_TIMER_INTERSECTION) CGAL::Timer timer_overlay; #endif #ifdef CGAL_NEF3_TIMER_POINT_LOCATION int number_of_point_location_queries; int number_of_ray_shooting_queries; CGAL::Timer timer_point_location; CGAL::Timer timer_ray_shooting; #endif #ifdef CGAL_NEF3_TIMER_SPHERE_SWEEPS int number_of_edge_facet_overlays=0; int number_of_clones=0; int number_of_sphere_sweeps=0; CGAL::Timer timer_sphere_sweeps; #endif #ifdef CGAL_NEF3_TIMER_PLANE_SWEEPS int number_of_plane_sweeps=0; CGAL::Timer timer_plane_sweeps; #endif #ifdef CGAL_NEF3_DUMP_STATISTICS int number_of_intersections; int number_of_intersection_candidates; #endif template class Binary_operation : public CGAL::SNC_decorator { public: typedef Map SNC_structure; typedef typename SNC_structure::Items Items; typedef typename Map::Sphere_map Sphere_map; typedef CGAL::SNC_decorator SNC_decorator; typedef SNC_decorator Base; typedef CGAL::SNC_constructor SNC_constructor; typedef CGAL::SNC_external_structure SNC_external_structure; typedef CGAL::SM_decorator SM_decorator; typedef CGAL::SNC_SM_overlayer SM_overlayer; typedef CGAL::SM_point_locator SM_point_locator; typedef CGAL::SNC_point_locator SNC_point_locator; typedef typename SNC_structure::Vertex_handle Vertex_handle; typedef typename SNC_structure::Halfedge_handle Halfedge_handle; typedef typename SNC_structure::Halffacet_handle Halffacet_handle; typedef typename SNC_structure::Volume_handle Volume_handle; typedef typename SNC_structure::SVertex_handle SVertex_handle; typedef typename SNC_structure::SHalfedge_handle SHalfedge_handle; typedef typename SNC_structure::SHalfloop_handle SHalfloop_handle; typedef typename SNC_structure::SFace_handle SFace_handle; typedef typename SNC_structure::Vertex_iterator Vertex_iterator; typedef typename SNC_structure::Halfedge_iterator Halfedge_iterator; typedef typename SNC_structure::Halffacet_iterator Halffacet_iterator; typedef typename SNC_structure::Volume_iterator Volume_iterator; typedef typename SNC_structure::SVertex_iterator SVertex_iterator; typedef typename SNC_structure::SHalfedge_iterator SHalfedge_iterator; typedef typename SNC_structure::SHalfloop_iterator SHalfloop_iterator; typedef typename SNC_structure::SFace_iterator SFace_iterator; typedef typename SNC_structure::SFace_cycle_iterator SFace_cycle_iterator; typedef typename SNC_structure::Halffacet_cycle_iterator Halffacet_cycle_iterator; typedef typename SNC_structure::Shell_entry_iterator Shell_entry_iterator; typedef typename SNC_structure::Object_handle Object_handle; typedef typename Base::Vertex_const_handle Vertex_const_handle; typedef typename Base::Volume_const_handle Volume_const_handle; typedef typename Base::Vertex_const_iterator Vertex_const_iterator; typedef typename Base::SHalfedge_const_iterator SHalfedge_const_iterator; typedef typename Base::SHalfloop_const_iterator SHalfloop_const_iterator; typedef typename Base::Point_3 Point_3; typedef typename Base::Plane_3 Plane_3; typedef typename Base::Mark Mark; typedef CGAL::ID_support_handler Association; public: Binary_operation(SNC_structure& W) : Base(W) {} template Vertex_handle binop_local_views( Vertex_const_handle v0, Vertex_const_handle v1, const Selection& BOP, SNC_structure& rsnc ,Association& A) /*{\opOverlays two spheres maps.}*/ { // CGAL_NEF_SETDTHREAD(19*43*131); CGAL_assertion( v0->point() == v1->point()); Vertex_handle v01 = rsnc.new_vertex( v0->point(), BOP( v0->mark(),v1->mark())); // std::cerr <<"BOP Vertex "<< v0->point() << ":" // << v0->mark()<<" "<mark()<sncp())); SM_overlayer O(&*v01); O.subdivide( &*v0, &*v1, A); O.select( BOP); O.simplify(A); return v01; } Vertex_handle create_local_view_on( const Point_3& p, Halfedge_handle e) { SNC_constructor C(*this->sncp()); return C.create_from_edge( e, p); } Vertex_handle create_local_view_on( const Point_3& p, Halffacet_handle f) { SNC_constructor C(*this->sncp()); return C.create_from_facet( f, p); } Vertex_handle create_local_view_on( const Point_3& p, Volume_const_handle c) { Vertex_handle v = this->sncp()->new_vertex( p, c->mark()); SM_decorator SD(&*v); SFace_handle f = SD.new_sface(); f->mark() = c->mark(); CGAL_NEF_TRACEN("volume "<<&*c<<" marked as "<mark()); return v; } template class Intersection_call_back : public SNC_point_locator::Intersection_call_back { typedef typename SNC_decorator::Decorator_traits Decorator_traits; typedef typename Decorator_traits::Halfedge_handle Halfedge_handle; typedef typename Decorator_traits::Halffacet_handle Halffacet_handle; public: Intersection_call_back( SNC_structure& s0, SNC_structure& s1, const Selection& _bop, SNC_structure& r, bool invert_order, Association& Ain) : snc0(s0), snc1(s1), bop(_bop), result(r), inverse_order(invert_order), A(Ain) {} void operator()(Halfedge_handle e0, Object_handle o1, const Point_3& ip) const { #ifdef CGAL_NEF3_DUMP_STATISTICS ++number_of_intersections; #endif Halfedge_handle e; Halffacet_handle f; Point_3 p(normalized(ip)); CGAL_NEF_TRACEN("Intersection_call_back: intersection reported on " << p << " (normalized: " << normalized(p) << " )"); #ifdef CGAL_NEF_DEBUG CGAL_NEF_TRACEN("edge 0 has source " << e0->source()->point() << " and direction " << e0->vector()); if( CGAL::assign( e, o1)) { CGAL_NEF_TRACEN("edge 1 has source " << e->source()->point() << " and direction " << e->vector()); } else if( CGAL::assign( f, o1)) { CGAL_NEF_TRACEN("face 1 has plane equation " << f->plane()); } else CGAL_error_msg( "wrong handle"); #endif #if defined (CGAL_NEF3_TIMER_OVERLAY) || (CGAL_NEF3_TIMER_INTERSECTION) timer_overlay.start(); #endif if( CGAL::assign( e, o1)) { // std::cerr << "inverse order " << inverse_order << std::endl; #ifdef CGAL_NEF_EXPERIMENTAL_CODE typename CGAL::Edge_edge_overlay eeo(result, e0, e); Sphere_map* M0 = eeo.create_edge_edge_overlay(p, bop, inverse_order, A); SM_overlayer O(M0); O.simplify(A); #else Binary_operation D(result); Vertex_handle v0, v1; v0 = D.create_local_view_on( p, e0); v1 = D.create_local_view_on( p, e); if( inverse_order) std::swap( v0, v1); D.binop_local_views( v0, v1, bop, result,A); result.delete_vertex(v0); result.delete_vertex(v1); #endif } else if( CGAL::assign( f, o1)) { #ifdef CGAL_NEF3_OVERLAY_BY_HAND_OFF Binary_operation D(result); Vertex_handle v0, v1; v0 = D.create_local_view_on( p, e0); v1 = D.create_local_view_on( p, f); if( inverse_order) std::swap( v0, v1); D.binop_local_views( v0, v1, bop, result,A); result.delete_vertex(v0); result.delete_vertex(v1); #else // CGAL_NEF3_OVERLAY_BY_HAND_OFF SNC_constructor C(result); Sphere_map* M0 = C.create_edge_facet_overlay(e0, f, p, bop, inverse_order, A); SM_overlayer O(M0); O.simplify(A); #endif // CGAL_NEF3_OVERLAY_BY_HAND_OFF } else CGAL_error_msg( "wrong handle"); #if defined (CGAL_NEF3_TIMER_OVERLAY) || (CGAL_NEF3_TIMER_INTERSECTION) timer_overlay.stop(); #endif } private: const SNC_structure& snc0; const SNC_structure& snc1; const Selection& bop; SNC_structure& result; bool inverse_order; Association& A; }; template void operator()( SNC_point_locator* pl0, const SNC_structure& snc1, const SNC_point_locator* pl1, const SNC_structure& snc2, const SNC_point_locator* pl2, const Selection& BOP) /*{\opPerforms a binary operation defined on |BOP| between two SNC structures. The input structures are not modified and the result of the operation is stored in |result|. \precondition: the structure |result| is empty.}*/ { // CGAL_NEF_SETDTHREAD(23); CGAL_assertion( this->sncp()->is_empty()); CGAL_assertion( pl1 != NULL && pl2 != NULL); // CGAL_NEF_SETDTHREAD(19*13*43*37); #ifdef CGAL_NEF3_TIMER_BINARY_OPERATION CGAL::Timer timer_binary_operation; timer_binary_operation.start(); #endif #ifdef CGAL_NEF3_TIMER_SPHERE_SWEEPS timer_sphere_sweeps.reset(); number_of_sphere_sweeps=0; number_of_edge_facet_overlays=0; number_of_clones=0; #endif #ifdef CGAL_NEF3_TIMER_POINT_LOCATION timer_point_location.reset(); number_of_point_location_queries=0; #endif #ifdef CGAL_NEF3_TIMER_OVERLAY timer_overlay.reset(); #endif #ifdef CGAL_NEF3_DUMP_STATISTICS number_of_intersections=0; number_of_intersection_candidates=0; #endif Unique_hash_map ignore(false); Vertex_const_iterator v0; // CGAL_NEF_SETDTHREAD(19*43*131); CGAL_NEF_TRACEN("=> binary operation"); #ifdef CGAL_NEF3_FACET_WITH_BOX SNC_constructor C1(snc1); C1.create_box(); SNC_constructor C2(snc2); C2.create_box(); #endif CGAL_NEF_TRACEN("\nnumber of vertices (so far...) = " << this->sncp()->number_of_vertices()); CGAL_NEF_TRACEN("=> for all v0 in snc1, qualify v0 with respect snc2"); // int i=2; Association A; SHalfedge_const_iterator sei; CGAL_forall_shalfedges(sei, snc1) A.initialize_hash(sei); CGAL_forall_shalfedges(sei, snc2) A.initialize_hash(sei); SHalfloop_const_iterator sli; CGAL_forall_shalfloops(sli, snc1) A.initialize_hash(sli); CGAL_forall_shalfloops(sli, snc2) A.initialize_hash(sli); CGAL_forall_vertices( v0, snc1) { CGAL_assertion(!ignore[v0]); Point_3 p0(v0->point()); Vertex_handle v; Halfedge_handle e; Halffacet_handle f; Volume_handle c; CGAL_NEF_TRACEN("Locating point " << p0); #ifdef CGAL_NEF3_TIMER_POINT_LOCATION ++number_of_point_location_queries; timer_point_location.start(); #endif Object_handle o = pl2->locate(p0); #ifdef CGAL_NEF3_TIMER_POINT_LOCATION timer_point_location.stop(); #endif #if defined(CGAL_NEF3_TIMER_OVERLAY) timer_overlay.start(); #endif if( CGAL::assign( v, o)) { CGAL_NEF_TRACEN("p0 found on vertex"); binop_local_views( v0, v, BOP, *this->sncp(),A); ignore[v] = true; } else if( CGAL::assign( e, o)) { CGAL_NEF_TRACEN("p0 found on edge"); Vertex_handle v1 = create_local_view_on( p0, e); binop_local_views( v0, v1, BOP, *this->sncp(),A); this->sncp()->delete_vertex(v1); } else if( CGAL::assign( f, o)) { CGAL_NEF_TRACEN("p0 found on facet" << f->plane()); Vertex_handle v1 = create_local_view_on( p0, f); binop_local_views( v0, v1, BOP, *this->sncp(),A); this->sncp()->delete_vertex(v1); } else if( CGAL::assign( c, o)) { CGAL_NEF_TRACEN("p0 found on volume with mark " << c->mark()); #ifdef CGAL_NEF3_OVERLAY_IF_NEEDED_OFF if(true) { #else if( BOP( true, c->mark()) != BOP( false, c->mark())) { #endif #ifdef CGAL_NEF3_OVERLAY_BY_HAND_OFF Vertex_handle v1 = create_local_view_on( p0, c); binop_local_views( v0, v1, BOP, *this->sncp(),A); this->sncp()->delete_vertex(v1); #else SNC_constructor C(*this->sncp()); Vertex_handle v1 = C.clone_SM(v0); SM_decorator SM(&*v1); SM.change_marks(BOP, c->mark()); SM_overlayer O(&*v1); O.simplify(A); #endif } else { CGAL_NEF_TRACEN("vertex in volume deleted " << std::endl << " vertex: " << v0->point() << std::endl << " mark of volume: " << c->mark()); } } else CGAL_error_msg( "wrong handle"); #if defined(CGAL_NEF3_TIMER_OVERLAY) timer_overlay.stop(); #endif } CGAL_NEF_TRACEN("\nnumber of vertices (so far...) = " << this->sncp()->number_of_vertices()); CGAL_NEF_TRACEN("=> for all v1 in snc1, qualify v1 with respect snc0"); CGAL_forall_vertices( v0, snc2) { if(ignore[v0]) continue; Point_3 p1(v0->point()); Halfedge_handle e; Halffacet_handle f; Volume_handle c; CGAL_NEF_TRACEN("Locating point " << p1); #ifdef CGAL_NEF3_TIMER_POINT_LOCATION number_of_point_location_queries++; timer_point_location.start(); #endif Object_handle o = pl1->locate(p1); #ifdef CGAL_NEF3_TIMER_POINT_LOCATION timer_point_location.stop(); #endif CGAL_assertion_code(Vertex_handle v); CGAL_assertion( !CGAL::assign( v, o)); #if defined(CGAL_NEF3_TIMER_OVERLAY) timer_overlay.start(); #endif if( CGAL::assign( e, o)) { CGAL_NEF_TRACEN("p1 found on edge"); Vertex_handle v1 = create_local_view_on( p1, e); binop_local_views( v1, v0, BOP, *this->sncp(),A); this->sncp()->delete_vertex(v1); } else if( CGAL::assign( f, o)) { CGAL_NEF_TRACEN("p1 found on facet"); Vertex_handle v1 = create_local_view_on( p1, f); binop_local_views( v1, v0, BOP, *this->sncp(),A); this->sncp()->delete_vertex(v1); } else if( CGAL::assign( c, o)) { CGAL_NEF_TRACEN("p1 found on volume with mark " << c->mark()); #ifdef CGAL_NEF3_OVERLAY_IF_NEEDED_OFF if(true) #else if( BOP( c->mark(), true) != BOP( c->mark(), false)) #endif { #ifdef CGAL_NEF3_OVERLAY_BY_HAND_OFF Vertex_handle v1 = create_local_view_on( p1, c); binop_local_views( v1, v0, BOP, *this->sncp(),A); this->sncp()->delete_vertex(v1); #else SNC_constructor C(*this->sncp()); Vertex_handle v1 = C.clone_SM(v0); SM_decorator SM(&*v1); SM.change_marks(c->mark(), BOP); SM_overlayer O(&*v1); O.simplify(A); #endif } else { CGAL_NEF_TRACEN("vertex in volume deleted " << std::endl << " vertex: " << v0->point() << std::endl << " mark of volume: " << c->mark()); } } else CGAL_error_msg( "wrong handle"); #if defined(CGAL_NEF3_TIMER_OVERLAY) timer_overlay.stop(); #endif } CGAL_NEF_TRACEN("\nnumber of vertices (so far...) = "<< this->sncp()->number_of_vertices()); // Each time the intersect method of the point locator for the // SNC structure finds an intersection between the segment defined // by an edge on the other SNC structure, the call back method is // called with the intersecting objects and the intersection point. // The responsability of the call back functor is to construct the // local view on the intersection point on both SNC structures, // overlay them and add the resulting sphere map to the result. // CGAL_NEF_SETDTHREAD(19*509*43*131); Intersection_call_back call_back0 ( const_cast(snc1), const_cast(snc2), BOP, *this->sncp(), false, A); Intersection_call_back call_back1 ( const_cast(snc2), const_cast(snc2), BOP, *this->sncp(), true, A); #ifdef CGAL_NEF3_TIMER_INTERSECTION double split_intersection = timer_overlay.time(); CGAL::Timer timer_intersection; timer_intersection.start(); #endif // choose between intersection algorithms #ifdef CGAL_NEF3_INTERSECTION_BY_KDTREE Halfedge_iterator e0, e1; /* CGAL_NEF_TRACEN("=> finding edge-edge intersections..."); CGAL_forall_edges( e0, snc1) { // ee_intersections++; pl2->intersect_with_edges( e0, call_back0); } CGAL_NEF_TRACEN("number of vertices (so far...) = " << this->sncp()->number_of_vertices()); CGAL_NEF_TRACEN("=> finding edge0-facet1 intersections..."); CGAL_forall_edges( e0, snc1) { // ef_intersections++; pl2->intersect_with_facets( e0, call_back0); } CGAL_NEF_TRACEN("\nnumber of vertices (so far...) = " << this->sncp()->number_of_vertices()); */ CGAL_forall_edges(e0,const_cast(snc1)) pl2->intersect_with_edges_and_facets(e0,call_back0); CGAL_NEF_TRACEN("=> finding edge1-facet0 intersections..."); CGAL_forall_edges( e1,const_cast(snc2)) { // ef_intersections++; pl1->intersect_with_facets( e1, call_back1); } CGAL_NEF_TRACEN("\nnumber of vertices (so far...) = " << this->sncp()->number_of_vertices()); #elif defined CGAL_NEF3_INTERSECTION_NAIVE CGAL::SNC_point_locator_naive pln1; CGAL::SNC_point_locator_naive pln2; pln1.initialize(const_cast(&snc1)); pln2.initialize(const_cast(&snc2)); Halfedge_iterator e0; CGAL_forall_edges(e0,const_cast(snc1)) pln2.intersect_with_edges_and_facets(e0,call_back0); CGAL_forall_edges(e0,const_cast(snc2)) pln1.intersect_with_facets( e0, call_back1); #else CGAL_NEF_TRACEN("intersection by fast box intersection"); binop_intersection_test_segment_tree binop_box_intersection; binop_box_intersection(call_back0, call_back1, const_cast(snc1), const_cast(snc2)); #endif #ifdef CGAL_NEF3_TIMER_INTERSECTION timer_intersection.stop(); if(cgal_nef3_timer_on) std::cout << "Runtime_intersection: " << timer_intersection.time()-timer_overlay.time()+split_intersection << std::endl; #endif CGAL_NEF_TRACEN("=> resultant vertices (before simplification): "); CGAL_assertion_code(CGAL_forall_vertices( v0, *this->sncp()) CGAL_NEF_TRACEN(&*v0<<" "<point())); SNC_external_structure es(*this->sncp(), pl0); es.build_after_binary_operation(A); #ifdef CGAL_NEF3_TIMER_PLANE_SWEEPS if(cgal_nef3_timer_on) { std::cout << "Number_of_plane_sweeps: " << number_of_plane_sweeps << std::endl; std::cout << "Runtime_plane_sweeps: " << timer_plane_sweeps.time() << std::endl; } #endif #ifdef CGAL_NEF3_DUMP_STATISTICS if(cgal_nef3_timer_on) { std::cout << "Vertices_in_object_A: " << snc1.number_of_vertices() << std::endl; std::cout << "Vertices_in_object_B: " << snc2.number_of_vertices() << std::endl; std::cout << "Number_of_intersections: " << number_of_intersections << std::endl; std::cout << "Number_of_intersection_candidates: " << number_of_intersection_candidates << std::endl; std::cout << "Vertices_in_Result: " << this->sncp()->number_of_vertices() << std::endl; } #endif #ifdef CGAL_NEF3_TIMER_SPHERE_SWEEPS if(cgal_nef3_timer_on) { std::cout << "Number_of_edge_facet_overlays: " << number_of_edge_facet_overlays << std::endl; std::cout << "Number_of_clones: " << number_of_clones << std::endl; std::cout << "Number_of_sphere_sweeps: " << number_of_sphere_sweeps << std::endl; std::cout << "Runtime_sphere_sweeps: " << timer_sphere_sweeps.time() << std::endl; } #endif #if defined (CGAL_NEF3_TIMER_SPHERE_SWEEPS) && defined (CGAL_NEF3_TIMER_PLANE_SWEEPS) if(cgal_nef3_timer_on) { std::cout << "Runtime_all_sweeps: " << timer_sphere_sweeps.time()+timer_plane_sweeps.time() << std::endl; } #endif #ifdef CGAL_NEF3_TIMER_OVERLAY if(cgal_nef3_timer_on) { std::cout << "Runtime_overlay: " << timer_overlay.time() << std::endl; } #endif #ifdef CGAL_NEF3_TIMER_POINT_LOCATION if(cgal_nef3_timer_on) { std::cout << "Number_of_ray_shooting_queries: " << number_of_ray_shooting_queries << std::endl; std::cout << "Runtime_ray_shooting: " << timer_ray_shooting.time() << std::endl; std::cout << "Number_of_point_location_queries: " << number_of_point_location_queries << std::endl; std::cout << "Runtime_point_location: " << timer_point_location.time() << std::endl; std::cout << "Number_of_kd_tree_queries: " << number_of_point_location_queries + number_of_ray_shooting_queries << std::endl; std::cout << "Runtime_kd_tree_queries: " << timer_point_location.time() + timer_ray_shooting.time() << std::endl; } #endif #ifdef CGAL_NEF3_TIMER_BINARY_OPERATION if(cgal_nef3_timer_on) { timer_binary_operation.stop(); std::cout << "Runtime_binary_operation: " << timer_binary_operation.time() << std::endl; } #endif } }; } //namespace CGAL #endif //CGAL_NEF_BINARY_OPERATION_H