// Copyright (c) 2005 Tel-Aviv University (Israel). // All rights reserved. // // This file is part of CGAL (www.cgal.org); you may redistribute it under // the terms of the Q Public License version 1.0. // See the file LICENSE.QPL distributed with CGAL. // // 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 DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. // // $Source: /CVSROOT/CGAL/Packages/Envelope_3/include/CGAL/Envelope_element_visitor_3.h,v $ // $Revision$ $Date$ // $Name: $ // // Author(s) : Michal Meyerovitch #ifndef CGAL_ENVELOPE_ELEMENT_VISITOR_3_H #define CGAL_ENVELOPE_ELEMENT_VISITOR_3_H #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include CGAL_BEGIN_NAMESPACE // this class does the resolving of edge and face in the divide & conquer algorithm // it should handle all faces (it supports holes in the face) template class Envelope_element_visitor_3 { public: typedef EnvelopeTraits_3 Traits; typedef typename Traits::Surface_3 Surface_3; typedef typename Traits::Xy_monotone_surface_3 Xy_monotone_surface_3; typedef MinimizationDiagram_2 Minimization_diagram_2; typedef typename Traits::Point_2 Point_2; typedef typename Traits::X_monotone_curve_2 X_monotone_curve_2; typedef typename Traits::Curve_2 Curve_2; protected: typedef Envelope_element_visitor_3 Self; typedef typename Minimization_diagram_2::Halfedge_const_iterator Halfedge_const_iterator; typedef typename Minimization_diagram_2::Halfedge_handle Halfedge_handle; typedef typename Minimization_diagram_2::Halfedge_iterator Halfedge_iterator; typedef typename Minimization_diagram_2::Face_handle Face_handle; typedef typename Minimization_diagram_2::Face_iterator Face_iterator; typedef typename Minimization_diagram_2::Vertex_handle Vertex_handle; typedef typename Minimization_diagram_2::Vertex_iterator Vertex_iterator; typedef typename Minimization_diagram_2::Ccb_halfedge_circulator Ccb_halfedge_circulator; typedef typename Minimization_diagram_2::Hole_iterator Hole_iterator; typedef typename Minimization_diagram_2::Isolated_vertex_iterator Isolated_vertex_iterator; typedef typename Minimization_diagram_2::Dcel Dcel; typedef typename Minimization_diagram_2::Dcel::Dcel_data_iterator Envelope_data_iterator; typedef Arr_observer Md_observer; typedef Arr_accessor Md_accessor; typedef Arr_walk_along_line_point_location Md_point_location; typedef Arr_inc_insertion_zone_visitor Md_insert_zone_visitor; typedef std::list Halfedges_list; typedef typename std::list::iterator Halfedges_list_iterator; typedef std::pair Halfedge_w_type; typedef std::list Halfedges_w_type_list; typedef std::list Vertices_list; typedef typename std::list::iterator Vertices_list_iterator; typedef std::list Faces_list; typedef typename std::list::iterator Faces_list_iterator; typedef Unique_hash_map Vertices_hash; typedef Unique_hash_map Halfedges_hash; typedef Unique_hash_map Halfedges_hash_w_type; typedef Unique_hash_map Faces_hash; typedef Unique_hash_map Vertices_map; typedef Unique_hash_map Halfedges_map; typedef Unique_hash_map Faces_map; typedef Unique_hash_map Vertices_to_edges_map; typedef std::pair Intersection_curve; typedef std::list Intersections_list; // this is used in the resolve edge process typedef Triple Point_2_with_info; struct Points_compare { protected: Traits* p_traits; public: Points_compare(Traits& tr) : p_traits(&tr) {} bool operator() (const Point_2_with_info& p1, const Point_2_with_info& p2) const { Comparison_result res = p_traits->compare_xy_2_object()(p1.first, p2.first); if (res == SMALLER) return true; if (res == LARGER) return false; return (p1.second == true || p2.third == true); } }; public: // c'tor Envelope_element_visitor_3() { // Allocate the traits. traits = new Traits; own_traits = true; reset_statistics(); } Envelope_element_visitor_3(Traits* tr) { // Set the traits. traits = tr; own_traits = false; reset_statistics(); } // virtual destructor. virtual ~Envelope_element_visitor_3() { // Free the traits object, if necessary. if (own_traits) delete traits; } // get a face with 2 surfaces defined over it, and compute the arrangement of the // envelope of these surfaces over the face void resolve(Face_handle face, Minimization_diagram_2& result) { #ifdef CGAL_DEBUG_ENVELOPE_DEQ_3 std::cout << "in general resolve face" << std::endl; #endif CGAL_assertion(face->get_aux_is_set(0)); CGAL_assertion(face->get_aux_is_set(1)); intersection_timer.start(); // we are interested with the envelope's shape over the current face, // so we only need to check the first surface from each group, since // all the surfaces in a group overlap over the current face. Xy_monotone_surface_3 surf1 = get_aux_surface(face, 0); Xy_monotone_surface_3 surf2 = get_aux_surface(face, 1); #ifdef CGAL_DEBUG_ENVELOPE_DEQ_3 std::cout << "compared surfaces are:" << surf1 << std::endl << surf2 << std::endl; #endif // find the projected intersections of the surfaces. if none - we have a simple case: // need only resolve non-intersecting and return std::list inter_objs; get_projected_intersections(surf1, surf2, std::back_inserter(inter_objs)); intersection_timer.stop(); if (inter_objs.size() == 0) { minimal_face_timer.start(); // here for resolve we can compare the surfaces over the edges only (no need for left/right versions) Comparison_result cur_res = resolve_minimal_face(face); copy_data_by_comparison_result(face, face, cur_res); // check face boundary for "data from face" features #ifdef CGAL_ENVELOPE_SAVE_COMPARISONS copy_data_to_face_boundary(face); #endif minimal_face_timer.stop(); return; } copied_arr_timer.start(); // we insert all projected intersections into a temporary arrangement, // with only the current face's curves, to find the arrangement of the lower envelope // of the 2 surfaces over the current face Minimization_diagram_2 copied_face_arr(traits); // here we maintain a mapping between edges in the copied arrangement and // their original generating edge from result Halfedges_map map_copied_to_orig_halfedges; // here we maintain a mapping between vertices in the copied arrangement and // their original generating vertex from result Vertices_map map_copied_to_orig_vertices; // here we maintain a mapping between faces in the copied arrangement and // their corresponding face from result Faces_map map_copied_to_orig_faces; // now, insert the face's boundary into the temporary minimization diagram // the face is assumed to have outer boundary, and may also have holes, // and isolated vertices // we need to keep track of the original halfedges in the inserted halfedges // we also need to have the face handle of the copied face in copied_face_arr bool fakes_exist = false; Face_handle copied_face = copy_face(face, result, copied_face_arr, map_copied_to_orig_halfedges, map_copied_to_orig_vertices, fakes_exist); CGAL_assertion(is_valid(copied_face_arr)); map_copied_to_orig_faces[copied_face] = face; copied_arr_timer.stop(); #ifdef CGAL_DEBUG_ENVELOPE_DEQ_3 std::cout << "number of face's edges: " << copied_face_arr.number_of_edges() << std::endl; #endif // insert the projected intersections into the temporary minimization diagram zone_timer.start(); Point_2 point; Intersection_curve curve; Object cur_obj; #ifdef CGAL_DEBUG_ENVELOPE_DEQ_3 std::cout << "resolve face: need to deal with " << inter_objs.size() << " intersection objects" << std::endl; #endif #ifdef CGAL_DEBUG_ENVELOPE_DEQ_3 // print all edges of result std::cout << "from general resolve face: all edges before insert " << std::endl; for (Halfedge_iterator hhit = result.halfedges_begin(); hhit != result.halfedges_end(); ++hhit, ++hhit) std::cout << hhit->curve() << std::endl; #endif // we use our zone visitor, which only inserts into the arrangement the // points and curves which are inside the copied face // it updates the result arrangement at the same time (action after action // using observer to the copied arrangement and accessor to result) // the visitor is responsible for updating: // 1. the collection of special edges. (these are (parts of) edges of the // original face's boundary that overlap with projected intersections Halfedges_list result_special_edges; // 2. the collection of newly added edges, each with the type of the // projected intersection that created it. Halfedges_w_type_list result_new_edges; // 3. the collection of faces that form the face before any insertion Faces_list result_face_parts; // 4. the collection of special vertices, which contains: // - new vertices that were created inside the original face // (both isolated and not isolated) // - new vertices created by a split of a boundary edge which has // the property "data from face" // - original vertices of the boundary that consolidate with projected // intersections, and have common aux data with the face // all these vertices should have their data set as "EQUAL" Vertices_list result_special_vertices; New_faces_observer new_faces_obs(result); Copied_face_zone_visitor zone_visitor(result, copied_face_arr, face, copied_face, map_copied_to_orig_halfedges, map_copied_to_orig_vertices, map_copied_to_orig_faces, result_special_edges, result_new_edges, result_face_parts, result_special_vertices, this); Md_point_location pl(copied_face_arr); std::list::iterator inter_objs_it = inter_objs.begin(); for(; inter_objs_it != inter_objs.end(); ++inter_objs_it) { cur_obj = *inter_objs_it; CGAL_assertion(!cur_obj.is_empty()); if (assign(point, cur_obj)) { // intersection can be a point when the surfaces only touch each other. // we are only interested in the points that are inside the face or on its // boundary. // we insert the point into the planar map as a vertex, with both surfaces // over it. #ifdef CGAL_DEBUG_ENVELOPE_DEQ_3 std::cout << "found intersection point: " << point << std::endl; #endif // should use observer for split_edge // if not in a sub-face of "face", shouldn't insert it // the above information is available in zone_visitor insert_point(copied_face_arr, point, pl, zone_visitor); } else if (assign(curve, cur_obj)) { #ifdef CGAL_DEBUG_ENVELOPE_DEQ_3 std::cout << "found intersection curve: " << curve.first << std::endl; #endif zone_visitor.set_current_intersection_type(curve.second); insert_curve(copied_face_arr, curve.first, pl, zone_visitor); } else CGAL_assertion_msg(false, "wrong projected intersection type"); } zone_visitor.finish(); zone_timer.stop(); #ifdef CGAL_DEBUG_ENVELOPE_DEQ_3 std::cout << "number of new edges: " << result_new_edges.size() << std::endl; #endif #ifdef CGAL_DEBUG_ENVELOPE_DEQ_3 std::cout << "number of edges on face boundary that overlap projected intersections is " << result_special_edges.size() << std::endl; #endif // now determine the envelope data in result over the new faces minimal_face_timer.start(); // first, we try to copy information from incident faces, thru fake edges if (fakes_exist) { typename std::list::iterator fit; for(fit = result_face_parts.begin(); fit != result_face_parts.end(); ++fit) { Face_handle new_f = *fit; // we didn't set envelope data yet CGAL_assertion(!new_f->is_decision_set()); // try to find a fake edge on the outer boundary // (if we have fake edges, we don't have holes) Ccb_halfedge_circulator hec = new_f->outer_ccb(); Ccb_halfedge_circulator hec_begin = hec; do { Halfedge_handle hh = hec; if (hh->get_is_fake() && hh->twin()->face()->is_decision_set()) { Face_handle twin_f = hh->twin()->face(); new_f->set_decision(twin_f->get_decision()); hh->set_decision(twin_f->get_decision()); hh->twin()->set_decision(hh->get_decision()); } ++hec; } while (hec != hec_begin); } } // in order to use resolve_minimal_face with intersection halfedge, we go over // the new edges, and set data over their faces #ifdef CGAL_DEBUG_ENVELOPE_DEQ_3 std::cout << "number of new edges: " << result_new_edges.size() << std::endl; #endif typename Halfedges_w_type_list::iterator new_edge_it; for(new_edge_it = result_new_edges.begin(); new_edge_it != result_new_edges.end(); ++new_edge_it) { Halfedge_handle new_he = (*new_edge_it).first; Halfedge_handle new_he_twin = new_he->twin(); Intersection_type itype = (*new_edge_it).second; // set sources of the new edge new_he->set_aux_source(0, face->get_aux_source(0)); new_he->set_aux_source(1, face->get_aux_source(1)); new_he_twin->set_aux_source(0, face->get_aux_source(0)); new_he_twin->set_aux_source(1, face->get_aux_source(1)); // set data on new edges new_he->set_decision(EQUAL); new_he_twin->set_decision(EQUAL); // set data on the faces // could be that the data is set for f2, and can use itype to conclude // to f1, not only the opposite Face_handle f1 = new_he->face(), f2 = new_he_twin->face(); Comparison_result res; if (!f1->is_decision_set() && !f2->is_decision_set()) { res = resolve_minimal_face(f1, &new_he); copy_data_by_comparison_result(face, f1, res); } // now at least one of the faces f1,f2 has its decision set. // if the other face doesn't have its data, we resolve it using // the former result and the intersection type (if exists) if (!f2->is_decision_set()) { #ifdef CGAL_ENVELOPE_SAVE_COMPARISONS if (itype != UNKNOWN) { res = convert_decision_to_comparison_result(f1->get_decision()); res = resolve_by_intersection_type(res, itype); CGAL_expensive_assertion_code( Comparison_result tmp_res = resolve_minimal_face(f2, &new_he_twin); ); CGAL_expensive_assertion(tmp_res == res); } else res = resolve_minimal_face(f2, &new_he_twin); #else res = resolve_minimal_face(f2, &new_he_twin); #endif copy_data_by_comparison_result(face, f2, res); } if (!f1->is_decision_set()) { #ifdef CGAL_ENVELOPE_SAVE_COMPARISONS if (itype != UNKNOWN) { res = convert_decision_to_comparison_result(f2->get_decision()); res = resolve_by_intersection_type(res, itype); CGAL_expensive_assertion_code( Comparison_result tmp_res = resolve_minimal_face(f1, &new_he); ); CGAL_expensive_assertion(tmp_res == res); } else res = resolve_minimal_face(f1, &new_he); #else res = resolve_minimal_face(f1, &new_he); #endif copy_data_by_comparison_result(face, f1, res); } } // we also need to check the faces incident to the halfedges in special_edges // since the envelope data over them should be computed using compare_left/right versions #ifdef CGAL_DEBUG_ENVELOPE_DEQ_3 std::cout << "number of special edges: " << result_special_edges.size() << std::endl; #endif Halfedges_list_iterator special_edge_it; for(special_edge_it = result_special_edges.begin(); special_edge_it != result_special_edges.end(); ++special_edge_it) { // we assume that the halfedge given points to the correct face (which is inside the original face) Halfedge_handle special_he = *special_edge_it; Face_handle f = special_he->face(); if (!f->is_decision_set()) { Comparison_result res = resolve_minimal_face(f, &special_he); copy_data_by_comparison_result(face, f, res); } // take care for the edge, if necessary if (!special_he->is_decision_set() && can_copy_decision_from_face_to_edge(special_he)) { if (!special_he->get_aux_is_set(0) || !special_he->get_aux_is_set(1)) { // this can only happen when the edge is fake, since the edge is on // the face's boundary CGAL_assertion(special_he->get_is_fake()); special_he->set_aux_source(0, face->get_aux_source(0)); special_he->set_aux_source(1, face->get_aux_source(1)); special_he->twin()->set_aux_source(0, face->get_aux_source(0)); special_he->twin()->set_aux_source(1, face->get_aux_source(1)); } if (special_he->get_is_fake()) { // this edge is not fake anymore, as it coincides with a projected // intersection special_he->set_is_fake(false); special_he->twin()->set_is_fake(false); } special_he->set_decision(EQUAL); special_he->twin()->set_decision(EQUAL); } } // update data on special vertices #ifdef CGAL_DEBUG_ENVELOPE_DEQ_3 std::cout << "number of special vertices: " << result_special_vertices.size() << std::endl; #endif Vertices_list_iterator special_vertex_it; for(special_vertex_it = result_special_vertices.begin(); special_vertex_it != result_special_vertices.end(); ++special_vertex_it) { Vertex_handle special_v = *special_vertex_it; if (!special_v->is_decision_set()) { #ifdef CGAL_DEBUG_ENVELOPE_DEQ_3 std::cout << "special vertex " << special_v->point() << std::endl; #endif if (special_v->get_aux_is_set(0) && special_v->get_aux_is_set(1)) set_data_by_comparison_result(special_v, EQUAL); else // this is a new vertex inside the face, so we need to update its // aux source information from face also (done in method) copy_all_data_to_vertex(face, special_v); } else CGAL_assertion(special_v->get_aux_is_set(0) && special_v->get_aux_is_set(1)); } // assert all new faces got data set, if not, then maybe no curve cuts the face, // and should use regular resolve_minimal_face #ifdef CGAL_DEBUG_ENVELOPE_DEQ_3 std::cout << "check all face parts: " << result_face_parts.size() << std::endl; #endif typename std::list::iterator new_face_it; for(new_face_it = result_face_parts.begin(); new_face_it != result_face_parts.end(); ++new_face_it) { Face_handle new_face = *new_face_it; if (!new_face->is_decision_set()) { Comparison_result res = resolve_minimal_face(new_face); copy_data_by_comparison_result(face, new_face, res); } // check face boundary for "data from face" features #ifdef CGAL_ENVELOPE_SAVE_COMPARISONS copy_data_to_face_boundary(new_face); #endif } minimal_face_timer.stop(); #ifdef CGAL_DEBUG_ENVELOPE_DEQ_3 std::cout << "finish resolve face " << std::endl; #endif } // get an edge with 2 surfaces defined over it, and split it to get the shape // of the envelope of these surfaces over the edge void resolve(Halfedge_handle edge, Minimization_diagram_2& result) { #ifdef CGAL_DEBUG_ENVELOPE_DEQ_3 std::cout << "in resolve edge" << std::endl; #endif Xy_monotone_surface_3 surf1 = get_aux_surface(edge, 0); Xy_monotone_surface_3 surf2 = get_aux_surface(edge, 1); #ifdef CGAL_DEBUG_ENVELOPE_DEQ_3 std::cout << "resolve edge: compared surfaces are:" << surf1 << std::endl << surf2 << std::endl; #endif // find the projected intersections std::list inter_objs; edge_intersection_timer.start(); get_projected_intersections(surf1, surf2, std::back_inserter(inter_objs)); edge_intersection_timer.stop(); if (inter_objs.size() == 0) { resolve_minimal_edge(edge, edge); #ifdef CGAL_ENVELOPE_SAVE_COMPARISONS copy_data_to_edge_endpoints(edge); #endif return; } edge_2d_inter_timer.start(); const X_monotone_curve_2& original_cv = edge->curve(); const Point_2& original_left = traits->construct_min_vertex_2_object()(original_cv); const Point_2& original_right = traits->construct_max_vertex_2_object()(original_cv); // we want to work on the halfedge going from left to right if (original_left != edge->source()->point()) edge = edge->twin(); Vertex_handle original_src = edge->source(); Vertex_handle original_trg = edge->target(); // we should have a list of points where we should split the edge's curve // we then will sort the list, and split the curve // we should pay a special attension for overlaps, since we can get special // edges // we associate with every point 2 flags: // 1. is the point a left endpoint of an overlapping segment // 2. is the point a right endpoint of an overlapping segment typedef std::vector Points_vec; Points_vec split_points; Point_2 point; Intersection_curve icurve; Object cur_obj; #ifdef CGAL_DEBUG_ENVELOPE_DEQ_3 std::cout << "resolve edge: need to deal with " << inter_objs.size() << " intersection objects" << std::endl; #endif std::list::iterator inter_objs_it = inter_objs.begin(); for(; inter_objs_it != inter_objs.end(); ++inter_objs_it) { cur_obj = *inter_objs_it; CGAL_assertion(!cur_obj.is_empty()); if (assign(point, cur_obj)) { #ifdef CGAL_DEBUG_ENVELOPE_DEQ_3 std::cout << "found intersection point: " << point << std::endl; #endif // if the point is on the curve, should add it the the split points // list, otherwise, it is irrelevant and should be ignored if (is_point_on_curve(point, original_cv, original_left, original_right)) split_points.push_back(Point_2_with_info(point, false, false)); } else if (assign(icurve, cur_obj)) { Curve_2 curve = icurve.first; #ifdef CGAL_DEBUG_ENVELOPE_DEQ_3 std::cout << "found intersection curve: " << curve << std::endl; #endif // find the intersection points and overlapping segments with the // original curve and insert them to the list of split points // first, get x_monotone parts std::list x_objects; std::list::const_iterator obj_it; const X_monotone_curve_2 *x_curve; const Point_2 *iso_p; traits->make_x_monotone_2_object()(curve, std::back_inserter(x_objects)); for (obj_it = x_objects.begin(); obj_it != x_objects.end(); ++obj_it) { x_curve = object_cast (&(*obj_it)); if (x_curve != NULL) { // intersect the x-monotone curve with the edge's curve typedef std::pair Intersect_point_2; std::list intersections_list; const Intersect_point_2 *ip; const X_monotone_curve_2 *icv; traits->intersect_2_object()(*x_curve, original_cv, std::back_inserter(intersections_list)); std::list::iterator inter_it = intersections_list.begin(); for(; inter_it != intersections_list.end(); ++inter_it) { ip = object_cast (&(*inter_it)); if (ip != NULL) { split_points.push_back(Point_2_with_info(ip->first, false, false)); } else { icv = object_cast (&(*inter_it)); CGAL_assertion (icv != NULL); split_points.push_back(Point_2_with_info( traits->construct_min_vertex_2_object()(*icv), true, false)); split_points.push_back(Point_2_with_info( traits->construct_max_vertex_2_object()(*icv), false, true)); } } } else { iso_p = object_cast (&(*obj_it)); CGAL_assertion (iso_p != NULL); // if the point is on the curve, should add it the the split points // list, otherwise, it is irrelevant and should be ignored if (is_point_on_curve(*iso_p, original_cv, original_left, original_right)) split_points.push_back(Point_2_with_info(*iso_p, false, false)); } } } else CGAL_assertion_msg(false, "wrong projected intersection type"); } edge_2d_inter_timer.stop(); // if there aren't any split points, we can finish if (split_points.size() == 0) { resolve_minimal_edge(edge, edge); #ifdef CGAL_ENVELOPE_SAVE_COMPARISONS copy_data_to_edge_endpoints(edge); #endif return; } edge_split_timer.start(); // sort the split points from left to right // and split the original edge in these points Points_compare comp(*traits); std::sort(split_points.begin(), split_points.end(), comp); // find if vertical surfaces are involved here, since if not, we can save // calls to traits methods (we know that over projected intersection the // surfaces are equal on the envelope, which is not neccessarily true if // vertical surfaces are involved) bool are_verticals_involved = false; // if (traits->is_vertical_3_object()(surf1) || // traits->is_vertical_3_object()(surf2)) // are_verticals_involved = true; // check if source is a special vertex (i.e. also a projected intersection) // by checking the first point in the list bool source_is_special = false; CGAL_assertion(split_points.size() >= 1); if (split_points[0].first == original_src->point()) source_is_special = true; // check if target is a special vertex, by checking the last point in the list bool target_is_special = false; if (split_points[split_points.size()-1].first == original_trg->point()) target_is_special = true; // if overlaps > 0 it will indicate that we are inside an overlapping segment // meaning, we have a special edge int overlaps = 0; // remember the envelope decision over the first & last parts, to // be able to copy it to the original endpoints // TODO: the initial value is only needed to shut up the compiler // TODO: is this realy needed, or we can use the decision made on "edge" // (is "edge" always the first part? ) Comparison_result first_part_res = EQUAL; // cur_part is the part of the original edge that might be split Halfedge_handle cur_part = edge; for(unsigned int i=0; ipoint()) break; Vertex_handle cur_src_vertex = cur_part->source(); // check that the current split point is not already a vertex if (cur_p.first != cur_src_vertex->point()) { // split the edge in this point X_monotone_curve_2 a,b; #ifdef CGAL_DEBUG_ENVELOPE_DEQ_3 std::cout << "before edge_split, curve=" << cur_part->curve() << std::endl << " point= " << cur_p.first << std::endl; #endif traits->split_2_object()(cur_part->curve(), cur_p.first, a, b); // todo: can we use the internal split? Halfedge_handle split_he = result.split_edge(cur_part, a, b); // split always returns the halfedge with source = cur_part.source CGAL_assertion(split_he->source() == cur_src_vertex); // the new vertex is split_he->target(), we set envelope data on it if (!are_verticals_involved) copy_all_data_to_vertex(edge, split_he->target()); else //resolve(split_he->target()); deal_with_new_vertex(edge, split_he->target()); // identify the part of the split edge that we are finished with // (this is the one with cur_src_vertex), // and the part that might be split again Halfedge_handle finished_part = split_he; cur_part = split_he->next(); // set the envelope data over the finished part // if the finished part is a special edge, and no verticals are involved // we can set both aux data on it. otherwise we should use the traits // compare method. Comparison_result finished_part_res; if (overlaps > 0 && !are_verticals_involved) finished_part_res = EQUAL; else finished_part_res = resolve_minimal_edge(edge, finished_part); finished_part->set_decision(finished_part_res); finished_part->twin()->set_decision(finished_part_res); if (finished_part == edge) first_part_res = finished_part_res; } // check the overlaps indications if (cur_p.second == true) ++overlaps; // we start a new overlapping segment at this point if (cur_p.third == true) --overlaps; // we end an overlapping segment at this point } // set envelope data on the last part (cur_part) // if the last part is a special edge, and no verticals are involved // we can set both aux data on it. otherwise we should use the traits // compare method. Comparison_result cur_part_res; if (overlaps > 0 && !are_verticals_involved) cur_part_res = EQUAL; else cur_part_res = resolve_minimal_edge(edge, cur_part); cur_part->set_decision(cur_part_res); cur_part->twin()->set_decision(cur_part_res); if (cur_part == edge) first_part_res = cur_part_res; // if the original source and target have same aux data as the edge // we can set envelope data over them also // if they are special vertices, we set both aux data. otherwise we copy // from the incident edge part. // the incident edge part to source should be edge (the first part) CGAL_assertion(original_src == edge->source()); if (!original_src->is_decision_set() && !are_verticals_involved && can_copy_decision_from_edge_to_vertex(edge->twin())) { if (source_is_special) set_data_by_comparison_result(original_src, EQUAL); #ifdef CGAL_ENVELOPE_SAVE_COMPARISONS else set_data_by_comparison_result(original_src, first_part_res); #endif } // the incident edge part to target should be cur_part (the last part) CGAL_assertion(original_trg == cur_part->target()); if (!original_trg->is_decision_set() && !are_verticals_involved && can_copy_decision_from_edge_to_vertex(cur_part)) { if (target_is_special) set_data_by_comparison_result(original_trg, EQUAL); #ifdef CGAL_ENVELOPE_SAVE_COMPARISONS else set_data_by_comparison_result(original_trg, cur_part_res); #endif } edge_split_timer.stop(); } // get a vertex with 2 surfaces defined over it and decide the envelope data // on it between them void resolve(Vertex_handle vertex) { // it is enough to compare only one surface from each group (because they // all overlap over the vertex), but set all the group Xy_monotone_surface_3 surf1 = get_aux_surface(vertex, 0); Xy_monotone_surface_3 surf2 = get_aux_surface(vertex, 1); Point_2 point_2 = vertex->point(); Comparison_result cur_res = compare_distance_to_envelope(point_2,surf1,surf2); vertex->set_decision(cur_res); } /*! Access the traits object (const version). */ const Traits* get_traits () const { return (traits); } /*! Access the traits object (non-const version). */ Traits* get_traits () { return (traits); } void reset() { reset_statistics(); } void reset_statistics() { if (intersection_timer.is_running()) intersection_timer.stop(); if (copied_arr_timer.is_running()) copied_arr_timer.stop(); if (zone_timer.is_running()) zone_timer.stop(); if (minimal_face_timer.is_running()) minimal_face_timer.stop(); if (edge_intersection_timer.is_running()) edge_intersection_timer.stop(); if (edge_2d_inter_timer.is_running()) edge_2d_inter_timer.stop(); if (edge_split_timer.is_running()) edge_split_timer.stop(); intersection_timer.reset(); copied_arr_timer.reset(); zone_timer.reset(); minimal_face_timer.reset(); edge_intersection_timer.reset(); edge_2d_inter_timer.reset(); edge_split_timer.reset(); } void print_times() { #ifdef CGAL_BENCH_ENVELOPE_DAC std::cout << "resolve face times: " << std::endl; std::cout << "intersections: " << intersection_timer.time() << " seconds" << std::endl; std::cout << "copied_arr: " << copied_arr_timer.time() << " seconds" << std::endl; std::cout << "zone calculation: " << zone_timer.time() << " seconds" << std::endl; std::cout << "envelope data: " << minimal_face_timer.time() << " seconds" << std::endl; std::cout << std::endl; std::cout << "resolve edge times: " << std::endl; std::cout << "intersections: " << edge_intersection_timer.time() << " seconds" << std::endl; std::cout << "2d intersections: " << edge_2d_inter_timer.time() << " seconds" << std::endl; std::cout << "split & compare: " << edge_split_timer.time() << " seconds" << std::endl; std::cout << std::endl << "determine a feature's shape took: " << intersection_timer.time() + copied_arr_timer.time() + zone_timer.time() << "seconds " << std::endl << "labelling took: " << minimal_face_timer.time() <face() == face); CGAL_assertion(!face->is_unbounded()); Comparison_result res; bool success = false; #ifdef CGAL_ENVELOPE_SAVE_COMPARISONS success = can_copy_decision_from_boundary_edge(face, res); #endif if (success) return res; Xy_monotone_surface_3 surf1 = get_aux_surface(face, 0); Xy_monotone_surface_3 surf2 = get_aux_surface(face, 1); if (he == NULL) { // compare the surfaces over arbitrary edge Ccb_halfedge_circulator hec = face->outer_ccb(); X_monotone_curve_2 cv = hec->curve(); res = compare_distance_to_envelope(cv,surf1,surf2); #ifdef CGAL_DEBUG_ENVELOPE_DEQ_3 std::cout << "in resolve_minimal_face, with no halfedge, got " << res << std::endl; #endif // check that result is equal on all edges CGAL_assertion_code( Ccb_halfedge_circulator hec_begin = hec; ++hec; while (hec != hec_begin) { Comparison_result tmp = compare_distance_to_envelope(hec->curve(),surf1,surf2); ) CGAL_assertion_msg(tmp == res, "compare over curve returns non-consistent results"); CGAL_assertion_code( ++hec; } ) } else { #ifdef CGAL_DEBUG_ENVELOPE_DEQ_3 std::cout << "in resolve_minimal_face, with halfedge " << std::endl; #endif // compare the surfaces over the halfedge's curve X_monotone_curve_2 cv = (*he)->curve(); CGAL_assertion_code( bool same_dir = (traits->construct_min_vertex_2_object()(cv) == (*he)->source()->point()); bool left_to_right = ((*he)->direction() == SMALLER); ); CGAL_assertion(same_dir == left_to_right); // a face is always to the left of its halfedge if ((*he)->direction() == SMALLER) res = traits->compare_distance_to_envelope_above_3_object() (cv,surf1,surf2); else res = traits->compare_distance_to_envelope_below_3_object() (cv,surf1,surf2); #ifdef CGAL_DEBUG_ENVELOPE_DEQ_3 std::cout << "resolve_minimal_face check " << (same_dir ? "left " : "right ") << "of curve " << cv << std::endl << "got " << res << std::endl; #endif } return res; } // use the Intersection type (Transversal/Tangent) and return the appropriate // comparison result of the other side of the intersection curve, // if the first side has result "res" Comparison_result resolve_by_intersection_type(Comparison_result res, Intersection_type itype) { #ifdef CGAL_DEBUG_ENVELOPE_DEQ_3 std::cout << "resolve_by_intersection_type called" << std::endl; #endif if (itype == TRANSVERSAL) { if (res == LARGER) return SMALLER; else if (res == SMALLER) return LARGER; else return res; } else { CGAL_assertion(itype == TANGENT); return res; } } // find intersections between 2 xy-monotone surfaces // use caching for repeating questions of same pair of surfaces template OutputIterator get_projected_intersections(Xy_monotone_surface_3& s1, Xy_monotone_surface_3& s2, OutputIterator o) { return traits->construct_projected_intersections_2_object()(s1, s2, o); } // Geometry can be a Point_2 or a X_monotone_curve_2 template Comparison_result compare_distance_to_envelope(Geometry& g, Xy_monotone_surface_3& s1, Xy_monotone_surface_3& s2) { #ifdef CGAL_DEBUG_ENVELOPE_DEQ_3 std::cout << "compare distance on " << g << std::endl; #endif return traits->compare_distance_to_envelope_3_object()(g, s1, s2); } // helper method to get the surfaces we need to work on template Xy_monotone_surface_3 get_aux_surface(FeatureHandle fh, unsigned int id) { Object o = fh->get_aux_source(id); CGAL_assertion(!o.is_empty()); Xy_monotone_surface_3 data; Halfedge_handle h; Vertex_handle v; Face_handle f; // aux source of a face must be a face! // aux source of a halfedge can be face or halfedge // aux source of a vertex can be face, halfedge or vertex // this is why we start with a check for a face, then halfedge // and last vertex if (assign(f, o)) data = f->get_data(); else if (assign(h, o)) data = h->get_data(); else { CGAL_assertion_code(bool b =) assign(v, o); CGAL_assertion(b); data = v->get_data(); } return data; } bool can_copy_decision_from_face_to_edge(Halfedge_handle h) { // can copy decision from face to its incident edge if the aux // envelopes are continous over the face and edge return (h->get_has_equal_aux_data_in_face(0) && h->get_has_equal_aux_data_in_face(1)); } bool can_copy_decision_from_edge_to_vertex(Halfedge_handle h) { // can copy decision from face to its incident edge if the aux // envelopes are continous over the face and edge return (h->get_has_equal_aux_data_in_target(0) && h->get_has_equal_aux_data_in_target(1)); } /* template OutputIterator find_ccb_unique_edges(Ccb_halfedge_circulator hec, OutputIterator o) { // when having "antena" in the ccb, edge might appear twice // (with its 2 halfedges) on the boundary // we keep here those halfedges that its twin is also on this face's boundary // as a stack std::deque antena; Ccb_halfedge_circulator hec_begin = hec; do { Halfedge_handle hh = hec; if (hh->twin()->face() == hh->face() && antena.size() > 0 && antena.back() == hh->twin()) { antena.pop_back(); } else { if (hh->twin()->face() == hh->face()) antena.push_back(hh); *o++ = hh; } hec++; } while(hec != hec_begin); CGAL_assertion(antena.size() == 0); return o; } */ // void print_ccb(Ccb_halfedge_circulator hec) // { // std::cout << "print ccb: " << std::endl; // Ccb_halfedge_circulator hec_begin = hec; // do { // Halfedge_handle h = hec; // std::cout << h->source()->point() << " --> " << h->target()->point() << std::endl; // hec++; // } while(hec != hec_begin); // } // check the aux data on the edges & vertices of the boundary of the face, // and if it equals the aux data on the face, copy it, to save calculations for // these features later // also consider isolated vertices // "res" is the decision made on the face void copy_data_to_face_boundary(Face_handle face) { Ccb_halfedge_circulator ccb = face->outer_ccb(); copy_data_to_face_boundary(face, ccb); Hole_iterator inner_iter = face->holes_begin(); for (; inner_iter != face->holes_end(); ++inner_iter) { ccb = (*inner_iter); copy_data_to_face_boundary(face, ccb); } Isolated_vertex_iterator iso_iter = face->isolated_vertices_begin(); for (; iso_iter != face->isolated_vertices_end(); ++iso_iter) { Vertex_handle vh = iso_iter; if (!vh->is_decision_set() && has_equal_aux_data_with_face(vh)) // can copy the data from the face, since we already took care of // the vertices of projected intersections vh->set_decision(face->get_decision()); } } void copy_data_to_face_boundary(Face_handle face, Ccb_halfedge_circulator hec) { Ccb_halfedge_circulator hec_begin = hec; do { Halfedge_handle hh = hec; CGAL_assertion(face == hh->face()); // if it is a vertical decomposition edge, copy data from face if (!hh->is_decision_set() && hh->get_is_fake()) { hh->set_decision(face->get_decision()); hh->twin()->set_decision(face->get_decision()); } else if (!hh->is_decision_set() && can_copy_decision_from_face_to_edge(hh)) { // copy the decision from face to the edge #ifdef CGAL_DEBUG_ENVELOPE_DEQ_3 std::cout << "copy from face to edge " << hh->curve() << std::endl; #endif hh->set_decision(face->get_decision()); hh->twin()->set_decision(hh->get_decision()); } // TODO: is this correct? shouldn't we split the edge first? // I think it is correct, because there is no intersection (of // the edges aux sources) over the edge, as if there was such // intersection, there would also be intersection between the surfaces // over the face, and we know now that there isn't. // if the first map is continous, but the second isn't (i.e. when we move // from the face to the edge, the envelope goes closer), then if the // second map wins on the face, it wins on the edge also else if (!hh->is_decision_set() && face->get_decision() == SECOND && hh->get_has_equal_aux_data_in_face(0) && !hh->get_has_equal_aux_data_in_face(1)) { hh->set_decision(SECOND); hh->twin()->set_decision(SECOND); } // if the second map is continous, but the first isn't, then if the // first map wins on the face, it wins on the edge also else if (!hh->is_decision_set() && face->get_decision() == FIRST && !hh->get_has_equal_aux_data_in_face(0) && hh->get_has_equal_aux_data_in_face(1)) { hh->set_decision(FIRST); hh->twin()->set_decision(FIRST); } // conclude to the vertices // we check both endpoints, since it can be possible that we cannot // conclude from one edge, bt can conclude from the other conclude_decision_to_vertex(hh->source(), hh->twin(), face, false); conclude_decision_to_vertex(hh->target(), hh, face, true); hec++; } while(hec != hec_begin); } // try to conclude the decision from the halfedge or the face to the vertex // the method assumes that the vertex is an endpoint of the edge represented // by "hh", which lies on the boundary of "fh" // the last bool indicates whether to check if possible to conclude from // face to vertex. it is only possible when hh->face == fh void conclude_decision_to_vertex(Vertex_handle vh, Halfedge_handle hh, Face_handle fh, bool try_vertex_face) { if (vh->is_decision_set()) return; // first, we try to copy decision from edge, then from face if (hh->is_decision_set() && can_copy_decision_from_edge_to_vertex(hh)) { vh->set_decision(hh->get_decision()); } // if the first map is continous, but the second isn't (i.e. when we move // from the edge to the vertex, the envelope goes closer), then if the // second map wins on the edge, it wins on the vertex also else if (hh->get_decision() == SECOND && hh->get_has_equal_aux_data_in_target(0) && !hh->get_has_equal_aux_data_in_target(1)) { vh->set_decision(SECOND); } // if the second map is continous, but the first isn't, then if the // first map wins on the edge, it wins on the vertex also else if (hh->get_decision() == FIRST && !hh->get_has_equal_aux_data_in_target(0) && hh->get_has_equal_aux_data_in_target(1)) { vh->set_decision(FIRST); } // check if we can copy from the face // todo: what if has_equal has 3 possible values? (and projected intersection // vertices have unknown flags) else if (try_vertex_face) { CGAL_assertion(has_equal_aux_data_in_target_and_face(hh) == has_equal_aux_data(vh, fh)); if (has_equal_aux_data_in_target_and_face(hh)) { #ifdef CGAL_DEBUG_ENVELOPE_DEQ_3 //std::cout << "check edge->vertex " << hh->curve() << " --> " << vh->point() << std::endl; std::cout << "copy from face to vertex " << vh->point() << std::endl; #endif // can copy the data from the face, since we already took care of // the vertices of projected intersections vh->set_decision(fh->get_decision()); } } } // todo: this is for checking template bool has_equal_data(const InputIterator & begin1, const InputIterator & end1, const InputIterator & begin2, const InputIterator & end2) { // insert the input data objects into a set std::set first(begin1, end1); std::set second(begin2, end2); std::list intersection; std::set_intersection(first.begin(), first.end(), second.begin(), second.end(), std::back_inserter(intersection)); return (intersection.size() > 0); } // todo: this is for checking template void get_aux_data_iterators(unsigned int id, FeatureHandle fh, Envelope_data_iterator& begin, Envelope_data_iterator& end) { Halfedge_handle h; Vertex_handle v; Face_handle f; Object o = fh->get_aux_source(id); CGAL_assertion(!o.is_empty()); if (assign(v, o)) { begin = v->begin_data(); end = v->end_data(); } else if (assign(h, o)) { begin = h->begin_data(); end = h->end_data(); } else { CGAL_assertion(assign(f, o)); assign(f, o); begin = f->begin_data(); end = f->end_data(); } } // todo: this is for checking template bool has_equal_aux_data(unsigned int id, FeatureHandle1 fh1, FeatureHandle2 fh2) { Envelope_data_iterator begin1, end1, begin2, end2; get_aux_data_iterators(id, fh1, begin1, end1); get_aux_data_iterators(id, fh2, begin2, end2); bool has_eq = has_equal_data(begin1, end1, begin2, end2); return has_eq; } // todo: this is for checking template bool has_equal_aux_data(FeatureHandle1 fh1, FeatureHandle2 fh2) { return (has_equal_aux_data(0, fh1, fh2) && has_equal_aux_data(1, fh1, fh2)); } // // check if we can copy the decision made on an incident face to the current // // face (by using the edge between the faces) // // this is an old version for saving comparisons over a face, and should be replaced // // with can_copy_decision_from_boundary // bool can_copy_decision_from_incident_face(Face_handle face, Comparison_result& res) // { // bool result = false; // Ccb_halfedge_circulator hec = face->outer_ccb(); // Ccb_halfedge_circulator hec_begin = hec; // do { // Halfedge_handle hh = hec; // // check the incident face // if (hh->twin()->face()->is_decision_set() && // can_copy_decision_from_face_to_edge(hh->twin()) && // can_copy_decision_from_face_to_edge(hh) && // hh->is_decision_set() && // hh->get_decision() != BOTH) // { // res = convert_decision_to_comparison_result(hh->get_decision()); // result = true; // } // // hec++; // } while(hec != hec_begin && !result); // return result; // } // check if we can copy the decision made on a boundary edge to the face // if so, res will contain this decision's comparison result bool can_copy_decision_from_boundary_edge(Face_handle face, Comparison_result& res) { bool result = false; // check outer boundary Ccb_halfedge_circulator hec = face->outer_ccb(); Ccb_halfedge_circulator hec_begin = hec; do { Halfedge_handle hh = hec; if (can_copy_decision_from_face_to_edge(hh) && hh->is_decision_set() && hh->get_decision() != BOTH) { res = convert_decision_to_comparison_result(hh->get_decision()); result = true; } // if the first map is continous, but the second isn't (i.e. when we move // from the edge to the face, the envelope goes farther), then if the // first map wins on the edge, it wins on the face also else if (hh->is_decision_set() && hh->get_decision() == FIRST && hh->get_has_equal_aux_data_in_face(0) && !hh->get_has_equal_aux_data_in_face(1)) { res = convert_decision_to_comparison_result(FIRST); result = true; } // if the second map is continous, but the first isn't, then if the // second map wins on the edge, it wins on the face also else if (hh->is_decision_set() && hh->get_decision() == SECOND && !hh->get_has_equal_aux_data_in_face(0) && hh->get_has_equal_aux_data_in_face(1)) { res = convert_decision_to_comparison_result(SECOND); result = true; } hec++; } while(hec != hec_begin && !result); if (result) return true; // check inner boundaries Hole_iterator hole_iter = face->holes_begin(); for (; hole_iter != face->holes_end(); ++hole_iter) { hec = (*hole_iter); hec_begin = hec; do { Halfedge_handle hh = hec; if (can_copy_decision_from_face_to_edge(hh) && hh->is_decision_set() && hh->get_decision() != BOTH) { res = convert_decision_to_comparison_result(hh->get_decision()); result = true; } // if the first map is continous, but the second isn't (i.e. when we move // from the edge to the face, the envelope goes farther), then if the // first map wins on the edge, it wins on the face also else if (hh->is_decision_set() && hh->get_decision() == FIRST && hh->get_has_equal_aux_data_in_face(0) && !hh->get_has_equal_aux_data_in_face(1)) { res = convert_decision_to_comparison_result(FIRST); result = true; } // if the second map is continous, but the first isn't, then if the // second map wins on the edge, it wins on the face also else if (hh->is_decision_set() && hh->get_decision() == SECOND && !hh->get_has_equal_aux_data_in_face(0) && hh->get_has_equal_aux_data_in_face(1)) { res = convert_decision_to_comparison_result(SECOND); result = true; } hec++; } while(hec != hec_begin && !result); if (result) return true; } return result; } Comparison_result convert_decision_to_comparison_result(CGAL::Dac_decision d) { if (d == FIRST) return SMALLER; else if (d == SECOND) return LARGER; else return EQUAL; } bool has_equal_aux_data_with_face(Vertex_handle v) { CGAL_assertion(v->is_isolated()); return (v->get_has_equal_aux_data_in_face(0) && v->get_has_equal_aux_data_in_face(1)); } bool has_equal_aux_data_in_target_and_face(Halfedge_handle h) { return (h->get_has_equal_aux_data_in_target_and_face(0) && h->get_has_equal_aux_data_in_target_and_face(1)); } // check the aux data on the endpoint vertices of the edge // and if it equals the aux data on the edge, copy it, to save calculations for // these features later void copy_data_to_edge_endpoints(Halfedge_handle edge) { // take care for source if (!edge->source()->is_decision_set() && can_copy_decision_from_edge_to_vertex(edge->twin())) // can copy the data from the edge, since we already took care of // the vertices of projected intersections edge->source()->set_decision(edge->get_decision()); // if the first map is continous, but the second isn't (i.e. when we move // from the edge to the vertex, the envelope goes closer), then if the // second map wins on the edge, it wins on the vertex also else if (edge->get_decision() == SECOND && edge->twin()->get_has_equal_aux_data_in_target(0) && !edge->twin()->get_has_equal_aux_data_in_target(1)) { edge->source()->set_decision(SECOND); } // if the second map is continous, but the first isn't, then if the // first map wins on the edge, it wins on the vertex also else if (edge->get_decision() == FIRST && !edge->twin()->get_has_equal_aux_data_in_target(0) && edge->twin()->get_has_equal_aux_data_in_target(1)) { edge->source()->set_decision(FIRST); } // take care for target if (!edge->target()->is_decision_set() && can_copy_decision_from_edge_to_vertex(edge)) // can copy the data from the edge, since we already took care of // the vertices of projected intersections edge->target()->set_decision(edge->get_decision()); // if the first map is continous, but the second isn't (i.e. when we move // from the edge to the vertex, the envelope goes closer), then if the // second map wins on the edge, it wins on the vertex also else if (edge->get_decision() == SECOND && edge->get_has_equal_aux_data_in_target(0) && !edge->get_has_equal_aux_data_in_target(1)) { edge->target()->set_decision(SECOND); } // if the second map is continous, but the first isn't, then if the // first map wins on the edge, it wins on the vertex also else if (edge->get_decision() == FIRST && !edge->get_has_equal_aux_data_in_target(0) && edge->get_has_equal_aux_data_in_target(1)) { edge->target()->set_decision(FIRST); } } // copy the halfedges of a ccb (in from) to the md "to" inside the face inside_face void copy_ccb(Ccb_halfedge_circulator hec, // the circulator to insert Minimization_diagram_2 &from,// the original arrangement Face_handle inside_face, // the face in which we insert it Minimization_diagram_2 &to, // the arrangement to which we insert Halfedges_map& map_copied_to_orig_halfedges, Vertices_map& map_copied_to_orig_vertices, Halfedges_map& map_orig_to_copied_halfedges, Vertices_map& map_orig_to_copied_vertices, bool is_outer_ccb, // do we copy an outer (or inner) ccb bool& fakes_exist) // this bool is assumed to be initialized already { Md_accessor to_accessor(to); // count the number of faces that are closed by this ccb // (it can be more than 1 in degenerate cases, when closed area hangs // on a boundary vertex) int n_faces_closed = 0; Ccb_halfedge_circulator hec_begin = hec; bool first_he = true; Halfedge_handle copied_prev_he; do { Halfedge_handle hh = hec; // update fakes_exist if (hh->get_is_fake()) fakes_exist = true; if (hh->twin()->face() == hh->face() && map_orig_to_copied_halfedges.is_defined(hh)) { // this can happen in the case of antennas, when we get to the same // antena halfedge from the other side copied_prev_he = map_orig_to_copied_halfedges[hh]; } else { X_monotone_curve_2 current_cv = hh->curve(); #ifdef CGAL_DEBUG_ENVELOPE_DEQ_3 //std::cout << "original halfedge: " << std::endl; //std::cout << hh->source()->point() << " --> " << hh->target()->point() // << std::endl; #endif if (first_he) { first_he = false; // create the 2 vertices and connect them with the edge // copied_prev_he should be directed from copied_source to copied_target Vertex_handle copied_source = to_accessor.create_vertex(hh->source()->point()); Vertex_handle copied_target = to_accessor.create_vertex(hh->target()->point()); copied_prev_he = to_accessor.insert_in_face_interior_ex(current_cv, inside_face, copied_source, copied_target, hh->direction()); map_copied_to_orig_halfedges[copied_prev_he] = hh; map_orig_to_copied_halfedges[hh] = copied_prev_he; map_copied_to_orig_halfedges[copied_prev_he->twin()] = hh->twin(); map_orig_to_copied_halfedges[hh->twin()] = copied_prev_he->twin(); map_copied_to_orig_vertices[copied_prev_he->source()] = hh->source(); map_orig_to_copied_vertices[hh->source()] = copied_prev_he->source(); map_copied_to_orig_vertices[copied_prev_he->target()] = hh->target(); map_orig_to_copied_vertices[hh->target()] = copied_prev_he->target(); } else { CGAL_assertion(map_copied_to_orig_halfedges[copied_prev_he]->target() == hh->source()); // insert from vertex: prev_he->target() // should check if hh->target is already a vertex in the copied face // in which case we should use insert at vertices bool use_2_vertices = false; Vertex_handle copied_v2; if (map_orig_to_copied_vertices.is_defined(hh->target())) { use_2_vertices = true; copied_v2 = map_orig_to_copied_vertices[hh->target()]; } Halfedge_handle copied_new_he; if (!use_2_vertices) { // create vertex for the new target, and insert the new edge Vertex_handle copied_target = to_accessor.create_vertex(hh->target()->point()); copied_new_he = to_accessor.insert_from_vertex_ex(current_cv, copied_prev_he, copied_target, hh->direction()); // the target of copied_new_he is the new vertex, so it is directed // the same way as hh in "from" // update the vertices maps: map_copied_to_orig_vertices[copied_new_he->target()] = hh->target(); map_orig_to_copied_vertices[hh->target()] = copied_new_he->target(); } else { #ifdef CGAL_DEBUG_ENVELOPE_DEQ_3 std::cout << "use 2 vertices: " << copied_prev_he->target()->point() << " and " << copied_v2->point() << std::endl; #endif ++n_faces_closed; // in order to insert the new edge we should determine the prev // halfedge of copied_v2 - this is done be going backwards on the // ccb (in the copied arrangement) until finding the first halfedge // with target copied_v2 // (note that going on twin()->next() is problematic in case that // the inner boundary we traverse is made of several faces) Halfedge_handle copied_prev_v2 = copied_prev_he; while(copied_prev_v2->source() != copied_v2) copied_prev_v2 = copied_prev_v2->prev(); copied_prev_v2 = copied_prev_v2->twin(); CGAL_assertion_code( Halfedge_handle tmp = to_accessor.locate_around_vertex(copied_v2, current_cv); ); CGAL_assertion(tmp == copied_prev_v2); bool new_face; if (is_outer_ccb) { // if it is the first face created, and the last halfedge to // insert, this is a regular outer ccb, with no special // degeneracies (around the current vertices, at least) // so we can use the accessor method if (n_faces_closed == 1 && map_orig_to_copied_halfedges.is_defined(hh->next())) { copied_new_he = to_accessor.insert_at_vertices_ex (current_cv, copied_prev_he, copied_prev_v2, hh->direction(), new_face); CGAL_assertion(new_face); } else { // TODO:can we use accessor method? copied_new_he = to.insert_at_vertices(current_cv, copied_prev_he, copied_prev_v2); } // in order to use the accessor version, we need to identify // the order in which to pass the halfedges // (we should be careful in cases where more than one face is // created by the outer ccb } else // copy inner boundary { // should always flip the side of the edge, because the face // that we close is never the copied face, even in strane // situations like this: (two faces thouch in vertex) // ------ |\ /| // | |\ | | \/ | // | | \| | /\ | // --- |/ \| // // copied_new_he = to_accessor.insert_at_vertices_ex(current_cv, copied_prev_v2, copied_prev_he, hh->twin()->direction(), new_face); CGAL_assertion(new_face); copied_new_he = copied_new_he->twin(); } CGAL_assertion(copied_new_he->target() == copied_v2); } // update the halfedges maps: map_copied_to_orig_halfedges[copied_new_he] = hh; map_copied_to_orig_halfedges[copied_new_he->twin()] = hh->twin(); map_orig_to_copied_halfedges[hh] = copied_new_he; map_orig_to_copied_halfedges[hh->twin()] = copied_new_he->twin(); // update the previous he copied_prev_he = copied_new_he; } #ifdef CGAL_DEBUG_ENVELOPE_DEQ_3 //std::cout << "copied halfedge: " << std::endl; //std::cout << copied_prev_he->source()->point() << " --> " << copied_prev_he->target()->point() // << std::endl; #endif } hec++; } while(hec != hec_begin); } // copy the halfedges of the boundary of face (in from) to the md "to" // return a handle to the copied face in "to" // precondition: "to" is empty Face_handle copy_face(Face_handle face, Minimization_diagram_2& from, Minimization_diagram_2& to, Halfedges_map& map_copied_to_orig_halfedges, Vertices_map& map_copied_to_orig_vertices, bool& fakes_exist) { CGAL_precondition(to.number_of_vertices() == 0); CGAL_precondition(!face->is_unbounded()); #ifdef CGAL_DEBUG_ENVELOPE_DEQ_3 std::cout << "copying the original face - outer boundary" << std::endl; #endif fakes_exist = false; Vertices_map map_orig_to_copied_vertices; Halfedges_map map_orig_to_copied_halfedges; Face_handle to_uf = to.unbounded_face(); // first deal with outer boundary Ccb_halfedge_circulator hec = face->outer_ccb(); copy_ccb(hec, from, to_uf, to, map_copied_to_orig_halfedges, map_copied_to_orig_vertices, map_orig_to_copied_halfedges, map_orig_to_copied_vertices, true, fakes_exist); CGAL_assertion(is_valid(to)); // we need to find the copied face Hole_iterator to_uf_hi = to_uf->holes_begin(); Ccb_halfedge_circulator to_uf_hec = (*to_uf_hi); CGAL_assertion(to_uf->number_of_holes() == 1); Halfedge_handle to_f_he = to_uf_hec->twin(); // second, deal with inner boundaries #ifdef CGAL_DEBUG_ENVELOPE_DEQ_3 std::cout << "copying the original face - inner boundaries" << std::endl; #endif Hole_iterator hole_iter = face->holes_begin(); for (; hole_iter != face->holes_end(); ++hole_iter) { #ifdef CGAL_DEBUG_ENVELOPE_DEQ_3 std::cout << "copying hole" << std::endl; #endif Ccb_halfedge_circulator he = (*hole_iter); copy_ccb(he, from, to_f_he->face(), to, map_copied_to_orig_halfedges, map_copied_to_orig_vertices, map_orig_to_copied_halfedges, map_orig_to_copied_vertices, false, fakes_exist); CGAL_assertion(is_valid(to)); } // find the face in "to" Face_handle copied_face = to_f_he->face(); // copy the isolated vertices inside the given face, if any // and save them in map_copied_to_orig_vertices #ifdef CGAL_DEBUG_ENVELOPE_DEQ_3 std::cout << "copying the original face - isolated vertices" << std::endl; #endif Isolated_vertex_iterator isolated_iter = face->isolated_vertices_begin(); for(; isolated_iter != face->isolated_vertices_end(); ++isolated_iter) { Vertex_handle copied_iso = to.insert_in_face_interior(isolated_iter->point(), copied_face); map_copied_to_orig_vertices[copied_iso] = isolated_iter; map_orig_to_copied_vertices[isolated_iter] = copied_iso; } return copied_face; } // set envelope data in face "to" according to the comparison result of the // aux data of face "from" void copy_data_by_comparison_result(Face_handle from, Face_handle to, Comparison_result res) { CGAL_assertion_msg(from->get_aux_is_set(0), "aux_data(0) is not set"); CGAL_assertion_msg(from->get_aux_is_set(1), "aux_data(1) is not set"); to->set_aux_source(0, from->get_aux_source(0)); to->set_aux_source(1, from->get_aux_source(1)); to->set_decision(res); } // set envelope data in vertex "v" according to the comparison result of the // aux data of "v" void set_data_by_comparison_result(Vertex_handle v, Comparison_result res) { CGAL_assertion_msg(v->get_aux_is_set(0), "aux_data(0) is not set"); CGAL_assertion_msg(v->get_aux_is_set(1), "aux_data(1) is not set"); v->set_decision(res); } // set envelope data in halfedge "h" according to the comparison result of the // aux data of "h" void set_data_by_comparison_result(Halfedge_handle h, Comparison_result res) { CGAL_assertion_msg(h->get_aux_is_set(0), "aux_data(0) is not set"); CGAL_assertion_msg(h->get_aux_is_set(1), "aux_data(1) is not set"); h->set_decision(res); } // set envelope data in vertex "to" according to the union of both // aux data of the feature "from" // FeatureHabdle should be a Face_handle, Halfedge_handle or // Vertex_handle template void copy_all_data_to_vertex(FeatureHabdle from, Vertex_handle to) { CGAL_assertion_msg(from->get_aux_is_set(0), "aux_data(0) is not set"); CGAL_assertion_msg(from->get_aux_is_set(1), "aux_data(1) is not set"); CGAL_assertion_msg(!to->is_decision_set(), "data is set in new vertex"); to->set_aux_source(0, from->get_aux_source(0)); to->set_aux_source(1, from->get_aux_source(1)); to->set_decision(EQUAL); } void deal_with_new_vertex(Halfedge_handle orig_he, Vertex_handle new_v) { Xy_monotone_surface_3 surf1 = get_aux_surface(orig_he, 0); Xy_monotone_surface_3 surf2 = get_aux_surface(orig_he, 1); Point_2 p = new_v->point(); Comparison_result res = compare_distance_to_envelope(p, surf1, surf2); new_v->set_aux_source(0, orig_he->get_aux_source(0)); new_v->set_aux_source(1, orig_he->get_aux_source(1)); new_v->set_decision(res); } Comparison_result resolve_minimal_edge(Halfedge_handle orig_he, Halfedge_handle new_he) { // find and set the envelope data on the new edge Xy_monotone_surface_3 surf1 = get_aux_surface(orig_he, 0); Xy_monotone_surface_3 surf2 = get_aux_surface(orig_he, 1); Comparison_result res = compare_distance_to_envelope(new_he->curve(), surf1, surf2); // new_he->set_aux_source(0, orig_he->get_aux_source(0)); // new_he->set_aux_source(1, orig_he->get_aux_source(1)); // new_he->twin()->set_aux_source(0, orig_he->get_aux_source(0)); // new_he->twin()->set_aux_source(1, orig_he->get_aux_source(1)); // the observer keeps this information when splitting an edge CGAL_assertion(new_he->get_aux_is_set(0) && new_he->get_aux_is_set(1)); CGAL_assertion(new_he->twin()->get_aux_is_set(0) && new_he->twin()->get_aux_is_set(1)); new_he->set_decision(res); new_he->twin()->set_decision(res); return res; } // check if the point is on the curve // left and right should be the left and right endpoints of the curve cv bool is_point_on_curve(const Point_2& p, const X_monotone_curve_2& cv, const Point_2& left, const Point_2& right) { CGAL_precondition(traits->equal_2_object() (left, traits->construct_min_vertex_2_object()(cv))); CGAL_precondition(traits->equal_2_object() (right, traits->construct_max_vertex_2_object()(cv))); // we should check if the point is in the x range of the curve, // and if so, if it lies on it if ((traits->compare_x_2_object()(p, left) != SMALLER) && (traits->compare_x_2_object()(p, right) != LARGER) && (traits->compare_y_at_x_2_object()(p, cv) == EQUAL)) return true; return false; } // this observer is used in the process of resolving a face // this observer should copy the faces' indication when a face is split // so we can later identify all the faces that form the original given face // it also should remember the edges of the face, that are also projected intersections class Copied_face_observer : public Md_observer { public: typedef typename Minimization_diagram_2::Face_handle Face_handle; typedef typename Minimization_diagram_2::Halfedge_handle Halfedge_handle; typedef typename Minimization_diagram_2::X_monotone_curve_2 X_monotone_curve_2; Copied_face_observer(Halfedges_map &map_h) : map_halfedges(map_h) { } virtual ~Copied_face_observer() {} void set_elements_collections(Halfedges_hash& boundary, Halfedges_hash& specialh, Halfedges_hash_w_type& newh, Faces_hash& parts, Vertices_hash& boundaryv, Vertices_hash& specialv, Vertices_to_edges_map& v_to_h) { boundary_halfedges = &boundary; special_edges = &specialh; new_edges = &newh; face_parts = &parts; boundary_vertices = &boundaryv; special_vertices = &specialv; vertices_to_halfedges = &v_to_h; } virtual void after_split_face(Face_handle org_f, Face_handle new_f, bool) { #ifdef CGAL_DEBUG_ENVELOPE_DEQ_3 std::cout << "in Copied_face_observer after_split_face" << std::endl; #endif // keep track of the face parts if (face_parts->is_defined(org_f)) (*face_parts)[new_f] = face_parts->default_value(); } virtual void after_split_edge(Halfedge_handle org_he, Halfedge_handle new_he) { #ifdef CGAL_DEBUG_ENVELOPE_DEQ_3 std::cout << "in Copied_face_observer after_split_edge" << std::endl; #endif // take care of special edges that were split if (special_edges->is_defined(org_he)) { // if original edge was in the set, then now both split parts should // be in the set (*special_edges)[new_he] = special_edges->default_value(); (*special_edges)[new_he->twin()] = special_edges->default_value(); } // take care of new edges that were split if (new_edges->is_defined(org_he)) { (*new_edges)[new_he] = (*new_edges)[org_he]; (*new_edges)[new_he->twin()] = (*new_edges)[org_he]; } // take care for boundary edges if (boundary_halfedges->is_defined(org_he)) { #ifdef CGAL_DEBUG_ENVELOPE_DEQ_3 std::cout << "original boundary edge was split" << std::endl; #endif (*boundary_halfedges)[new_he] = boundary_halfedges->default_value(); (*boundary_halfedges)[new_he->twin()] = boundary_halfedges->default_value(); // the new created vertex is a special vertex since it lies on the boundary // of the face, and it is of a projected intersection // we are interested in it only if the split halfedge is "data from face" CGAL_assertion(map_halfedges.is_defined(org_he)); CGAL_assertion(org_he->target() == new_he->source()); if ((map_halfedges[org_he])->get_has_equal_aux_data_in_face(0) && (map_halfedges[org_he])->get_has_equal_aux_data_in_face(1)) (*special_vertices)[org_he->target()] = special_vertices->default_value(); // update the boundary vertices collection (*boundary_vertices)[org_he->target()] = boundary_vertices->default_value(); // update the vertices to halfedges collection Halfedge_handle correct_side_he; if (face_parts->is_defined(org_he->face())) correct_side_he = org_he; else { CGAL_assertion(face_parts->is_defined(new_he->twin()->face())); // new_he->twin() is directed as org_he, so on the boundary pointing // inside the face, and has the new vertex as target CGAL_assertion(org_he->target() == new_he->twin()->target()); correct_side_he = new_he->twin(); } // set the new vertex (*vertices_to_halfedges)[org_he->target()] = correct_side_he; // update the old vertices (only one needs update, unless it is antenna) CGAL_assertion(vertices_to_halfedges->is_defined(correct_side_he->source()) && vertices_to_halfedges->is_defined(correct_side_he->next()->target())); (*vertices_to_halfedges)[correct_side_he->next()->target()] = correct_side_he->next(); if (correct_side_he == org_he && face_parts->is_defined(org_he->twin()->face())) (*vertices_to_halfedges)[org_he->source()] = org_he->twin(); } } protected: Halfedges_hash *boundary_halfedges; Halfedges_hash *special_edges; Halfedges_hash_w_type *new_edges; Faces_hash *face_parts; Vertices_hash *boundary_vertices; Vertices_hash *special_vertices; Vertices_to_edges_map *vertices_to_halfedges; Halfedges_map &map_halfedges; }; // this observer is used in the process of resolving a face // it listens to what happpens in the copied arrangement, and copies back // the actions to result arrangements very efficiently class Copy_observer : public Md_observer { public: typedef typename Minimization_diagram_2::Face_handle Face_handle; typedef typename Minimization_diagram_2::Halfedge_handle Halfedge_handle; typedef typename Minimization_diagram_2::Vertex_handle Vertex_handle; typedef typename Minimization_diagram_2::Point_2 Point_2; typedef typename Minimization_diagram_2::X_monotone_curve_2 X_monotone_curve_2; typedef typename Minimization_diagram_2::Ccb_halfedge_circulator Ccb_halfedge_circulator; Copy_observer(Minimization_diagram_2& small, Minimization_diagram_2& big, Halfedges_map& map_h, Vertices_map& map_v, Faces_map& map_f) : small_arr(small), big_arr(big), big_arr_accessor(big_arr), map_halfedges(map_h), map_vertices(map_v), map_faces(map_f) { } virtual ~Copy_observer() {} virtual void before_create_vertex (const Point_2& /* p */) {} virtual void after_create_vertex (Vertex_handle v) { #ifdef CGAL_DEBUG_ENVELOPE_DEQ_3 std::cout << "in Copy_observer after_create_vertex" << std::endl; #endif // should create a new vertex with v->point() inside Vertex_handle new_v = big_arr_accessor.create_vertex(v->point()); // save a mapping between the 2 vertices map_vertices[v] = new_v; // add indication of a new vertex (that is not connected to anything, // and is also no isolated) new_vertices.push_back(v); } virtual void before_create_edge (const X_monotone_curve_2& /* c */, Vertex_handle v1, Vertex_handle v2) { // save state for after_create_edge event create_edge_v1 = v1; create_edge_v2 = v2; is_in_relocate = false; } virtual void after_create_edge (Halfedge_handle e) { #ifdef CGAL_DEBUG_ENVELOPE_DEQ_3 std::cout << "in Copy_observer after_create_edge" << std::endl; #endif // a new edge e was created in small_arr, we should create a corresponing // edge in big_arr CGAL_assertion(map_vertices.is_defined(create_edge_v1)); CGAL_assertion(map_vertices.is_defined(create_edge_v2)); CGAL_assertion(new_vertices.size() <= 2); Vertex_handle big_v1 = map_vertices[create_edge_v1]; Vertex_handle big_v2 = map_vertices[create_edge_v2]; // should check if v1 and v2 are new or old // if we have 2 new vertices, they must be new. // if we have only one, we should check which is new bool v1_is_new = false, v2_is_new = false; if (new_vertices.size() == 1) { if (new_vertices.back() == create_edge_v1) v1_is_new = true; else { CGAL_assertion(new_vertices.back() == create_edge_v2); v2_is_new = true; } } if (new_vertices.size() == 2) { v1_is_new = true; v2_is_new = true; } new_vertices.clear(); // just to make sure we have the halfedge in the same direction as // we got in the before event CGAL_assertion(e->source() == create_edge_v1); Halfedge_handle he = ((e->source() == create_edge_v1) ? e : e->twin()); // if an endpoint is not new, but is isolated, we should remove it from // its face's isolated vertices list, and treat it as new if (!v1_is_new && big_v1->is_isolated()) { //Face_handle f = big_v1->face(); //big_arr.incident_face(big_v1); //big_arr_accessor.find_and_erase_isolated_vertex(f, big_v1); big_arr_accessor.remove_isolated_vertex_ex(big_v1); v1_is_new = true; } if (!v2_is_new && big_v2->is_isolated()) { //Face_handle f = big_v2->face(); //big_arr.incident_face(big_v2); //big_arr_accessor.find_and_erase_isolated_vertex(f, big_v2); big_arr_accessor.remove_isolated_vertex_ex(big_v2); v2_is_new = true; } // now use the approppriate method to insert the new edge if (v1_is_new && v2_is_new) { // if both vertices are new - use the O(1) operation // _insert_in_face_interior (in the face mapped to by he->face()) CGAL_assertion(map_faces.is_defined(he->face())); Face_handle big_face = map_faces[he->face()]; Halfedge_handle new_he = big_arr_accessor.insert_in_face_interior_ex(he->curve(), big_face, big_v1, big_v2, he->direction()); // update mapping of new edge // new_he is directed from big_v1 to big_v2, and he is directed from // create_edge_v1 to create_edge_v2, so he is mapped to new_he map_halfedges[he] = new_he; map_halfedges[he->twin()] = new_he->twin(); } else if (!v1_is_new && !v2_is_new) { // if both vertices are old - use _insert_at_vertices // this is a linear action by the size of the faces involved // we can get relevant prev halfedges from he Halfedge_handle prev1 = he->prev(); Halfedge_handle prev2 = he->twin()->prev(); CGAL_assertion(map_halfedges.is_defined(prev1)); CGAL_assertion(map_halfedges.is_defined(prev2)); Halfedge_handle big_prev1 = map_halfedges[prev1]; Halfedge_handle big_prev2 = map_halfedges[prev2]; bool new_face; Halfedge_handle new_he = big_arr_accessor.insert_at_vertices_ex(he->curve(), big_prev1, big_prev2, he->direction(), new_face); #ifdef CGAL_DEBUG_ENVELOPE_DEQ_3 std::cout << "in copy_observer, use insert at vertices" << std::endl; std::cout << (!new_face ? "no " : "") << "new face created" << std::endl; #endif // new_he should be directed as he CGAL_assertion(map_vertices.is_defined(he->source()) && map_vertices[he->source()] == new_he->source() && map_vertices.is_defined(he->target()) && map_vertices[he->target()] == new_he->target()); // update mapping of new edge map_halfedges[he] = new_he; map_halfedges[he->twin()] = new_he->twin(); // make sure that the old face is mapped already CGAL_assertion(map_faces.is_defined(he->twin()->face()) && map_faces[he->twin()->face()] == new_he->twin()->face()); // if a new face was created update its mapping too // the new face is the incident face of he if (new_face) { map_faces[he->face()] = new_he->face(); // save state for move_hole/move_isolated_vertex events is_in_relocate = true; } // make sure the face is correctly mapped CGAL_assertion(map_faces.is_defined(he->face()) && map_faces[he->face()] == new_he->face()); } else { // only one vertex is new - use the O(1) operation _insert_from_vertex // we can get the relevant prev halfedge from e Halfedge_handle prev = he->prev(); CGAL_assertion(map_halfedges.is_defined(prev)); Halfedge_handle big_prev = map_halfedges[prev]; Halfedge_handle new_he; if (!v1_is_new) { new_he = big_arr_accessor.insert_from_vertex_ex(he->curve(), big_prev, big_v2, he->direction()); // update mapping of new edge // new_he is directed from big_v1 to big_v2 as he map_halfedges[he] = new_he; map_halfedges[he->twin()] = new_he->twin(); } else { new_he = big_arr_accessor.insert_from_vertex_ex(he->curve(), big_prev, big_v1, he->direction()); // update mapping of new edge // new_he is directed from big_v2 to big_v1 opposite of he map_halfedges[he] = new_he->twin(); map_halfedges[he->twin()] = new_he; } } } virtual void before_split_edge (Halfedge_handle e, Vertex_handle v, const X_monotone_curve_2& /* c1 */, const X_monotone_curve_2& /* c2 */) { // save state info for using _split_edge in after event split_v = v; split_e = e; } virtual void after_split_edge (Halfedge_handle e1, Halfedge_handle e2) { #ifdef CGAL_DEBUG_ENVELOPE_DEQ_3 std::cout << "in Copy_observer after_split_edge" << std::endl; #endif // find the corresponding split vertex in big_arr CGAL_assertion(map_vertices.is_defined(split_v)); Vertex_handle big_v = map_vertices[split_v]; // make sure it is the only new vertex right now CGAL_assertion(new_vertices.size() == 1 && new_vertices.back() == split_v); new_vertices.pop_back(); // find the edge to split in big_arr CGAL_assertion(map_halfedges.is_defined(split_e)); Halfedge_handle big_e = map_halfedges[split_e]; // use the O(1) operation _split_edge Halfedge_handle big_e1 = big_arr_accessor.split_edge_ex(big_e, big_v, e1->curve(), e2->curve()); Halfedge_handle big_e2 = big_e1->next(); // update mapping of new halfedges // big_e1 is directed at big_v, as e1 is directed at split_v - // these are supposed to be mapped CGAL_assertion(map_halfedges.is_defined(e1) && map_halfedges[e1] == big_e1); // should update the mapping of the second halfedge map_halfedges[e2] = big_e2; map_halfedges[e2->twin()] = big_e2->twin(); } virtual void before_add_isolated_vertex (Face_handle f, Vertex_handle /* v */) { saved_face = f; } virtual void after_add_isolated_vertex (Vertex_handle v) { // make sure it is the only new vertex right now CGAL_assertion(new_vertices.size() == 1 && new_vertices.back() == v); new_vertices.pop_back(); CGAL_assertion(map_vertices.is_defined(v)); CGAL_assertion(map_faces.is_defined(saved_face)); // find features in big_arr Vertex_handle big_v = map_vertices[v]; Face_handle big_face = map_faces[saved_face]; // can use O(1) operation _insert_isolated_vertex big_arr_accessor.insert_isolated_vertex(big_face, big_v); } virtual void before_move_hole (Face_handle from_f, Face_handle to_f, Ccb_halfedge_circulator h) { // should be used after insert_at_vertices which creates a new face CGAL_assertion(is_in_relocate); move_from = from_f; move_to = to_f; } virtual void after_move_hole (Ccb_halfedge_circulator h) { #ifdef CGAL_DEBUG_ENVELOPE_DEQ_3 std::cout << "in Copy_observer after_move_hole" << std::endl; #endif CGAL_assertion(map_faces.is_defined(move_from)); CGAL_assertion(map_faces.is_defined(move_to)); CGAL_assertion(map_halfedges.is_defined(h)); Face_handle big_from_f = map_faces[move_from]; Face_handle big_to_f = map_faces[move_to]; Ccb_halfedge_circulator big_h = (map_halfedges[h])->ccb(); Ccb_halfedge_circulator big_ccb = big_h; big_arr_accessor.move_hole(big_from_f, big_to_f, big_ccb); } virtual void before_move_isolated_vertex (Face_handle from_f, Face_handle to_f, Vertex_handle v) { // should be used after insert_at_vertices which creates a new face CGAL_assertion(is_in_relocate); move_from = from_f; move_to = to_f; } virtual void after_move_isolated_vertex (Vertex_handle v) { CGAL_assertion(map_faces.is_defined(move_from)); CGAL_assertion(map_faces.is_defined(move_to)); CGAL_assertion(map_vertices.is_defined(v)); Face_handle big_from_f = map_faces[move_from]; Face_handle big_to_f = map_faces[move_to]; Vertex_handle big_v = map_vertices[v]; big_arr_accessor.move_isolated_vertex(big_from_f, big_to_f, big_v); } protected: Minimization_diagram_2& small_arr; Minimization_diagram_2& big_arr; Md_accessor big_arr_accessor; // mappings between small_arr features to big_arr features Halfedges_map& map_halfedges; Vertices_map& map_vertices; Faces_map& map_faces; std::deque new_vertices; // state for actions Vertex_handle create_edge_v1; Vertex_handle create_edge_v2; Vertex_handle split_v; Halfedge_handle split_e; Face_handle saved_face; Face_handle move_from; Face_handle move_to; bool is_in_relocate; }; // A zone visitor for the Minimization Diagram which only inserts // parts of the curve which are inside a given face // it also remembers those parts which overlap the boundary of the original face class Copied_face_zone_visitor { public: typedef typename Minimization_diagram_2::Vertex_handle Vertex_handle; typedef typename Minimization_diagram_2::Halfedge_handle Halfedge_handle; typedef typename Minimization_diagram_2::Face_handle Face_handle; typedef typename Minimization_diagram_2::Point_2 Point_2; typedef typename Minimization_diagram_2::X_monotone_curve_2 X_monotone_curve_2; typedef std::pair Result; Copied_face_zone_visitor(Minimization_diagram_2& result, Minimization_diagram_2& copied, Face_handle orig_face, Face_handle copied_face, Halfedges_map &map_h, Vertices_map &map_v, Faces_map &map_f, Halfedges_list &se, // special edges Halfedges_w_type_list &new_edges, Faces_list &face_parts, Vertices_list &sv, // special vertices Self* p) : copied_arr(copied), result_arr(result), result_original_face(orig_face), map_halfedges(map_h), map_vertices(map_v), map_faces(map_f), result_special_edges(se), result_new_edges(new_edges), result_face_parts(face_parts), result_special_vertices(sv), md_copy_observer(copied, result, map_h, map_v, map_f), md_observer(map_h), parent(p) { // init maps copied_face_parts[copied_face] = copied_face_parts.default_value(); Halfedge_iterator hi = copied_arr.halfedges_begin(); for(; hi != copied_arr.halfedges_end(); ++hi) { copied_arr_boundary_halfedges[hi] = copied_arr_boundary_halfedges.default_value(); if (hi->face() == copied_face) copied_vertices_to_halfedges[hi->target()] = hi; } Vertex_iterator vi = copied_arr.vertices_begin(); for(; vi != copied_arr.vertices_end(); ++vi) { copied_arr_orig_vertices[vi] = copied_arr_orig_vertices.default_value(); if (vi->is_isolated()) { CGAL_assertion(vi->face() == copied_face); copied_vertices_to_halfedges[vi] = Halfedge_handle(NULL); } else CGAL_assertion(copied_vertices_to_halfedges.is_defined(vi)); } // init observers md_copy_observer.attach(copied_arr); md_observer.set_elements_collections(copied_arr_boundary_halfedges, copied_arr_special_edges, copied_arr_new_edges, copied_face_parts, copied_arr_new_boundary_vertices, copied_arr_special_vertices, copied_vertices_to_halfedges); md_observer.attach(copied_arr); } virtual ~Copied_face_zone_visitor() { } // the zone visitor functions /*! Initialize the visitor with an arrangement object. */ void init (Minimization_diagram_2 *arr) { CGAL_assertion(&copied_arr == arr); insert_visitor.init(arr); } /*! * Handle the a subcurve located in the interior of a given face. * \param cv The subcurve. * \param face The face containing cv's interior. * \param left_v The vertex that corresponds to the left endpoint of cv * (or an invalid handle if no such arrangement vertex exists). * \param left_he The halfedge that contains the left endpoint of cv * (or an invalid handle if no such halfedge exists). * \param right_v The vertex that corresponds to the right endpoint of cv * (or an invalid handle if no such arrangement vertex exists). * \param right_he The halfedge that contains the right endpoint of cv * (or an invalid handle if no such halfedge exists). * \return A handle to the halfedge obtained from the insertion of the * subcurve into the arrangement. */ Result found_subcurve (const X_monotone_curve_2& cv, Face_handle face, Vertex_handle left_v, Halfedge_handle left_he, Vertex_handle right_v, Halfedge_handle right_he) { // insert the curve only if the face is ok if (is_face_ok(face)) { Result base_result = insert_visitor.found_subcurve(cv, face, left_v, left_he, right_v, right_he); // update the collection of newly added edges Halfedge_handle new_he = base_result.first; #ifdef CGAL_DEBUG_ENVELOPE_DEQ_3 std::cout << "found a new edge " << new_he->curve() << std::endl; std::cout << "from " << new_he->source()->point() << std::endl; #endif copied_arr_new_edges[new_he] = itype; copied_arr_new_edges[new_he->twin()] = itype; // take care for special vertices. the split vertices are always special, // and this is taken care of in the after_split event. // here we should update the original vertices that consolidate with the // new subcurve if (copied_arr_orig_vertices.is_defined(new_he->source())) copied_arr_special_vertices[new_he->source()] = copied_arr_special_vertices.default_value(); if (copied_arr_orig_vertices.is_defined(new_he->target())) copied_arr_special_vertices[new_he->target()] = copied_arr_special_vertices.default_value(); // we should set the halfedge-face, halfedge-target // and target-face aux flags on the new edge (of result) Halfedge_handle result_new_he = map_halfedges[new_he]; // it is clear that the halfedge-face are all true result_new_he->set_is_equal_aux_data_in_face(0, true); result_new_he->set_is_equal_aux_data_in_face(1, true); result_new_he->twin()->set_is_equal_aux_data_in_face(0, true); result_new_he->twin()->set_is_equal_aux_data_in_face(1, true); result_new_he->set_has_equal_aux_data_in_face(0, true); result_new_he->set_has_equal_aux_data_in_face(1, true); result_new_he->twin()->set_has_equal_aux_data_in_face(0, true); result_new_he->twin()->set_has_equal_aux_data_in_face(1, true); // for the halfedge-target flags, if the vertex is a boundary vertex // we should use its boundary halfedge as intermediary between the face // and the vertex (or the vertex info if it was isolated) // otherwise, we set flags to true since it is a new vertex inside the // original face, and have same aux data as all face parts if (is_boundary_vertex(new_he->target())) { Vertex_handle cur_t = new_he->target(); CGAL_assertion(copied_vertices_to_halfedges.is_defined(cur_t)); Halfedge_handle copied_b_he = copied_vertices_to_halfedges[cur_t]; if (copied_b_he == Halfedge_handle(NULL)) { // this was an isolated vertex, which we touch // since we have in the new edge aux sources as in the face, // we can copy the vertex-face flags from the vertex result_new_he->set_is_equal_aux_data_in_target (0, cur_t->get_is_equal_aux_data_in_face(0)); result_new_he->set_is_equal_aux_data_in_target (1, cur_t->get_is_equal_aux_data_in_face(1)); result_new_he->set_has_equal_aux_data_in_target (0, cur_t->get_has_equal_aux_data_in_face(0)); result_new_he->set_has_equal_aux_data_in_target (1, cur_t->get_has_equal_aux_data_in_face(1)); result_new_he->set_has_equal_aux_data_in_target_and_face (0, cur_t->get_has_equal_aux_data_in_face(0)); result_new_he->set_has_equal_aux_data_in_target_and_face (1, cur_t->get_has_equal_aux_data_in_face(1)); } else { CGAL_assertion(copied_b_he->target() == cur_t); CGAL_assertion(is_boundary_edge(copied_b_he)); Halfedge_handle b_he = map_halfedges[copied_b_he]; #ifdef CGAL_DEBUG_ENVELOPE_DEQ_3 std::cout << "b_he=" << b_he->source()->point() << " --> " << b_he->target()->point(); #endif bool flag; flag = (b_he->get_is_equal_aux_data_in_face(0) && b_he->get_is_equal_aux_data_in_target(0)); result_new_he->set_is_equal_aux_data_in_target(0, flag); flag = (b_he->get_is_equal_aux_data_in_face(1) && b_he->get_is_equal_aux_data_in_target(1)); result_new_he->set_is_equal_aux_data_in_target(1, flag); flag = b_he->get_has_equal_aux_data_in_target_and_face(0); CGAL_assertion(flag == parent->has_equal_aux_data(0, b_he->face(), b_he->target())); result_new_he->set_has_equal_aux_data_in_target(0, flag); result_new_he->set_has_equal_aux_data_in_target_and_face(0, flag); flag = b_he->get_has_equal_aux_data_in_target_and_face(1); CGAL_assertion(flag == parent->has_equal_aux_data(1, b_he->face(), b_he->target())); result_new_he->set_has_equal_aux_data_in_target(1, flag); result_new_he->set_has_equal_aux_data_in_target_and_face(1, flag); } } else // not a boundary vertex { result_new_he->set_is_equal_aux_data_in_target(0, true); result_new_he->set_is_equal_aux_data_in_target(1, true); // the face's data is not empty - so it is ok to set "true" here result_new_he->set_has_equal_aux_data_in_target(0, true); result_new_he->set_has_equal_aux_data_in_target(1, true); result_new_he->set_has_equal_aux_data_in_target_and_face(0, true); result_new_he->set_has_equal_aux_data_in_target_and_face(1, true); } if (is_boundary_vertex(new_he->source())) { Vertex_handle cur_t = new_he->source(); CGAL_assertion(copied_vertices_to_halfedges.is_defined(cur_t)); Halfedge_handle copied_b_he = copied_vertices_to_halfedges[cur_t]; if (copied_b_he == Halfedge_handle(NULL)) { // this was an isolated vertex, which we touch // since we have in the new edge aux sources as in the face, // we can copy the vertex-face flags from the vertex result_new_he->twin()->set_is_equal_aux_data_in_target (0, cur_t->get_is_equal_aux_data_in_face(0)); result_new_he->twin()->set_is_equal_aux_data_in_target (1, cur_t->get_is_equal_aux_data_in_face(1)); result_new_he->twin()->set_has_equal_aux_data_in_target (0, cur_t->get_has_equal_aux_data_in_face(0)); result_new_he->twin()->set_has_equal_aux_data_in_target (1, cur_t->get_has_equal_aux_data_in_face(1)); result_new_he->twin()->set_has_equal_aux_data_in_target_and_face (0, cur_t->get_has_equal_aux_data_in_face(0)); result_new_he->twin()->set_has_equal_aux_data_in_target_and_face (1, cur_t->get_has_equal_aux_data_in_face(1)); } else { CGAL_assertion(copied_b_he->target() == cur_t); CGAL_assertion(is_boundary_edge(copied_b_he)); Halfedge_handle b_he = map_halfedges[copied_b_he]; #ifdef CGAL_DEBUG_ENVELOPE_DEQ_3 std::cout << "b_he=" << b_he->source()->point() << " --> " << b_he->target()->point(); #endif bool flag; flag = (b_he->get_is_equal_aux_data_in_face(0) && b_he->get_is_equal_aux_data_in_target(0)); result_new_he->twin()->set_is_equal_aux_data_in_target(0, flag); flag = (b_he->get_is_equal_aux_data_in_face(1) && b_he->get_is_equal_aux_data_in_target(1)); result_new_he->twin()->set_is_equal_aux_data_in_target(1, flag); flag = b_he->get_has_equal_aux_data_in_target_and_face(0); CGAL_assertion(flag == parent->has_equal_aux_data(0, b_he->face(), b_he->target())); result_new_he->twin()->set_has_equal_aux_data_in_target(0, flag); result_new_he->twin()->set_has_equal_aux_data_in_target_and_face(0, flag); flag = b_he->get_has_equal_aux_data_in_target_and_face(1); CGAL_assertion(flag == parent->has_equal_aux_data(1, b_he->face(), b_he->target())); result_new_he->twin()->set_has_equal_aux_data_in_target(1, flag); result_new_he->twin()->set_has_equal_aux_data_in_target_and_face(1, flag); } } else { result_new_he->twin()->set_is_equal_aux_data_in_target(0, true); result_new_he->twin()->set_is_equal_aux_data_in_target(1, true); result_new_he->twin()->set_has_equal_aux_data_in_target(0, true); result_new_he->twin()->set_has_equal_aux_data_in_target(1, true); result_new_he->twin()->set_has_equal_aux_data_in_target_and_face(0, true); result_new_he->twin()->set_has_equal_aux_data_in_target_and_face(1, true); } #ifdef CGAL_DEBUG_ENVELOPE_DEQ_3 std::cout << "set halfedge-vertex flags:" << std::endl; std::cout << "is equal(0) = " << result_new_he->get_is_equal_aux_data_in_target(0) << " is_equal(1) = " << result_new_he->get_is_equal_aux_data_in_target(1) << " has_equal(0) = " << result_new_he->get_has_equal_aux_data_in_target(0) << " has_equal(1) = " << result_new_he->get_has_equal_aux_data_in_target(1) << std::endl; std::cout << "for twin: " << std::endl; std::cout << "is equal(0) = " << result_new_he->twin()->get_is_equal_aux_data_in_target(0) << " is_equal(1) = " << result_new_he->twin()->get_is_equal_aux_data_in_target(1) << " has_equal(0) = " << result_new_he->twin()->get_has_equal_aux_data_in_target(0) << " has_equal(1) = " << result_new_he->twin()->get_has_equal_aux_data_in_target(1) << std::endl; #endif return base_result; } else { // we don't insert the subcurve, but it might touch a vertex of the // face's boundary - we need to check it and identify special vertices if (left_v != Vertex_handle(NULL) && copied_arr_orig_vertices.is_defined(left_v)) copied_arr_special_vertices[left_v] = copied_arr_special_vertices.default_value(); if (right_v != Vertex_handle(NULL) && copied_arr_orig_vertices.is_defined(right_v)) copied_arr_special_vertices[right_v] = copied_arr_special_vertices.default_value(); Halfedge_handle invalid_hh; return Result (invalid_hh, false); } } /*! * Handle the a subcurve that overlaps a given edge. * \param cv The overlapping subcurve. * \param he The overlapped halfedge (directed from left to right). * \param left_v The vertex that corresponds to the left endpoint of cv * (or an invalid handle if no such arrangement vertex exists). * \param right_v The vertex that corresponds to the right endpoint of cv * (or an invalid handle if no such arrangement vertex exists). * \return A handle to the halfedge obtained from the insertion of the * overlapping subcurve into the arrangement. */ Result found_overlap (const X_monotone_curve_2& cv, Halfedge_handle he, Vertex_handle left_v, Vertex_handle right_v) { // check if the halfedge is the boundary of the original face // (here we assume that this indication is dealt with in an observer // attached to the md, and implements split_edge) bool is_boundary = is_boundary_edge(he); // use insert_visitor to get the halfedge with the overlap Result base_res = insert_visitor.found_overlap(cv, he, left_v, right_v); Halfedge_handle overlap_he = base_res.first; #ifdef CGAL_DEBUG_ENVELOPE_DEQ_3 std::cout << "In copied face zone visitor: found an overlap" << overlap_he->curve() << std::endl; #endif // take care for special vertices. the split vertices are always special, // and this is taken care of in the after_split event. // here we should update the original vertices that consolidate with the // new subcurve if (copied_arr_orig_vertices.is_defined(overlap_he->source())) copied_arr_special_vertices[overlap_he->source()] = copied_arr_special_vertices.default_value(); if (copied_arr_orig_vertices.is_defined(overlap_he->target())) copied_arr_special_vertices[overlap_he->target()] = copied_arr_special_vertices.default_value(); if (!is_boundary) return base_res; // if he is a boundary edge, it is a special edge if (is_boundary) { #ifdef CGAL_DEBUG_ENVELOPE_DEQ_3 std::cout << "In copied face zone visitor: found a special edge" << std::endl; #endif copied_arr_special_edges[overlap_he] = copied_arr_special_edges.default_value(); copied_arr_special_edges[overlap_he->twin()] = copied_arr_special_edges.default_value(); } return base_res; } /*! * Handle point that lies inside a given face. * \param p The point. * \param face The face inside which the point lies. * \return A handle to the new vertex obtained from the insertion of the * point into the face, or invalid handle if the point wasn't * inserted to the arrangement. */ Vertex_handle found_point_in_face(const Point_2& p, Face_handle face) { // p lies inside a face: Insert it as an isolated vertex it the interior of // this face. Vertex_handle vh_for_p; if (is_face_ok(face)) { vh_for_p = copied_arr.insert_in_face_interior(p, face); // now should set the is_equal and has_equal flags CGAL_assertion(map_vertices.is_defined(vh_for_p)); Vertex_handle result_new_v = map_vertices[vh_for_p]; result_new_v->set_is_equal_aux_data_in_face(0, true); result_new_v->set_is_equal_aux_data_in_face(1, true); result_new_v->set_has_equal_aux_data_in_face(0, true); result_new_v->set_has_equal_aux_data_in_face(1, true); } return vh_for_p; } /*! * Handle point that lies on a given edge. * \param p The point. * \param he The edge on which the point lies. * \return A handle to the new vertex obtained from the insertion of the * point into the edge, or invalid handle if the point wasn't * inserted to the arrangement. */ Vertex_handle found_point_on_edge(const Point_2& p, Halfedge_handle he) { // p lies in the interior of an edge: Split this edge to create a new // vertex associated with p. X_monotone_curve_2 sub_cv1, sub_cv2; Halfedge_handle split_he; copied_arr.get_traits()->split_2_object() (he->curve(), p, sub_cv1, sub_cv2); split_he = copied_arr.split_edge (he, sub_cv1, sub_cv2); // if the edge is a boundary edge, then the new vertex is a special vertex // and this is taken care of in the after_split event // TODO: should we update some is_equal / has_equal flags? // I think that no, because it is handled in the after_split event // The new vertex is the target of the returned halfedge. return split_he->target(); } /*! * Handle point that lies on a given vertex. * \param p The point. * \param v The vertex on which the point lies. * \return A handle to the new vertex obtained from the modifying * the existing vertex. */ Vertex_handle found_point_on_vertex(const Point_2& p, Vertex_handle v) { // if the vertex is a boundary vertex, then it is a special vertex // if it was created by split of a boundary edge, then it is already // marked as special. we need to mark it as special if it is an original // vertex if (copied_arr_orig_vertices.is_defined(v)) copied_arr_special_vertices[v] = copied_arr_special_vertices.default_value(); return copied_arr.modify_vertex (v, p); } /*! * Update all the output collections using the internal data saved during * the previous inserts. * Should be called after all inserts have finished. */ void finish() { // result_special_edges // result_new_edges Halfedge_iterator hi = copied_arr.halfedges_begin(); for(; hi != copied_arr.halfedges_end(); ++hi, ++hi) { Halfedge_handle h = hi; CGAL_assertion(map_halfedges.is_defined(h) && map_halfedges.is_defined(h->twin())); // we need only one of the twin halfedges to represent the new edge if (copied_arr_new_edges.is_defined(h)) result_new_edges.push_back(std::make_pair(map_halfedges[h], copied_arr_new_edges[h])); if (copied_arr_special_edges.is_defined(h)) { // we need the halfedge that its incident face is inside the original // face Face_handle f1 = h->face(), f2 = h->twin()->face(); if (copied_face_parts.is_defined(f1)) result_special_edges.push_back(map_halfedges[h]); else { CGAL_assertion(copied_face_parts.is_defined(f2)); result_special_edges.push_back(map_halfedges[h->twin()]); } } } // result_face_parts Face_iterator fi = copied_arr.faces_begin(); for(; fi != copied_arr.faces_end(); ++fi) { Face_handle f = fi; if (copied_face_parts.is_defined(f)) { CGAL_assertion(map_faces.is_defined(f)); result_face_parts.push_back(map_faces[f]); } } // result_special_vertices Vertex_iterator vi = copied_arr.vertices_begin(); for(; vi != copied_arr.vertices_end(); ++vi) { Vertex_handle v = vi; CGAL_assertion(map_vertices.is_defined(v)); Vertex_handle result_v = map_vertices[v]; if (copied_arr_orig_vertices.is_defined(v)) { // original vertex should be mapped to a boundary halfedge whose // target is the vertex CGAL_assertion(copied_vertices_to_halfedges.is_defined(v)); Halfedge_handle inc_he = copied_vertices_to_halfedges[v]; CGAL_assertion(copied_face_parts.is_defined(inc_he->face())); Halfedge_handle result_inc_he = map_halfedges[inc_he]; CGAL_assertion(result_inc_he->target() == result_v); CGAL_assertion(map_faces[inc_he->face()] == result_inc_he->face()); // original vertex is special if it appears in the special collection // and its aux data share equal surfaces with the faces aux data if (copied_arr_special_vertices.is_defined(v) && ((result_v->is_isolated() && parent->has_equal_aux_data_with_face(result_v)) || (!result_v->is_isolated() && parent->has_equal_aux_data_in_target_and_face(result_inc_he)))) { CGAL_assertion(parent->has_equal_aux_data(result_v, result_original_face)); result_special_vertices.push_back(result_v); } } else { if (!copied_arr_new_boundary_vertices.is_defined(v)) // new vertex inside the face result_special_vertices.push_back(result_v); else if (copied_arr_special_vertices.is_defined(v)) result_special_vertices.push_back(result_v); } } } void set_current_intersection_type(Intersection_type t) { itype = t; } protected: bool is_face_ok(Face_handle face) { // is this face a part of the original face? // check in the copied_face_parts map return (copied_face_parts.is_defined(face)); } bool is_boundary_edge(Halfedge_handle he) { return (copied_arr_boundary_halfedges.is_defined(he)); } bool is_original_boundary_vertex(Vertex_handle v) { return (copied_arr_orig_vertices.is_defined(v)); } bool is_boundary_vertex(Vertex_handle v) { return (copied_arr_orig_vertices.is_defined(v) || copied_arr_new_boundary_vertices.is_defined(v)); } protected: // this zone visitor knows how to insert the given subcurves into the // minimization diagram. we use it to insert the subcurves we want (which // are in the given original face) Md_insert_zone_visitor insert_visitor; Minimization_diagram_2 &copied_arr; Minimization_diagram_2 &result_arr; Face_handle result_original_face; // mappings between features in the 2 arrangements Halfedges_map &map_halfedges; Vertices_map &map_vertices; Faces_map &map_faces; // output lists Halfedges_list &result_special_edges; Halfedges_w_type_list &result_new_edges; Faces_list &result_face_parts; Vertices_list &result_special_vertices; // helper collections (for copied_arr features) Halfedges_hash copied_arr_boundary_halfedges; Vertices_hash copied_arr_orig_vertices; Vertices_hash copied_arr_new_boundary_vertices; Vertices_to_edges_map copied_vertices_to_halfedges; Halfedges_hash copied_arr_special_edges; Halfedges_hash_w_type copied_arr_new_edges; Faces_hash copied_face_parts; Vertices_hash copied_arr_special_vertices; // this observer will take care of the result arrangegment Copy_observer md_copy_observer; // this observer will keep all our information in the helper collections // during the insert process // (the special features info, boundary info, new_edges) Copied_face_observer md_observer; // for using its methods Self* parent; // current type of interection curve that is inserted Intersection_type itype; }; // this minimization diagram observer updates data in new faces created class New_faces_observer : public Md_observer { public: typedef typename Minimization_diagram_2::Face_handle Face_handle; New_faces_observer(Minimization_diagram_2& arr) : Md_observer(arr) {} virtual ~New_faces_observer() {} virtual void after_split_face(Face_handle org_f, Face_handle new_f, bool) { #ifdef CGAL_DEBUG_ENVELOPE_DEQ_3 std::cout << "in New_faces_observer::after_split_face" << std::endl; #endif // update the new face's aux_data from original face if (org_f->get_aux_is_set(0)) new_f->set_aux_source(0, org_f->get_aux_source(0)); if (org_f->get_aux_is_set(1)) new_f->set_aux_source(1, org_f->get_aux_source(1)); } }; Traits *traits; bool own_traits; // Should we eventually free the traits object. // measure times for resolve face mutable Timer intersection_timer; mutable Timer copied_arr_timer; mutable Timer zone_timer; mutable Timer minimal_face_timer; // measure times for resolve edge mutable Timer edge_intersection_timer; mutable Timer edge_2d_inter_timer; mutable Timer edge_split_timer; }; CGAL_END_NAMESPACE #endif