// Copyright (c) 2005 Stanford University (USA). // All rights reserved. // // This file is part of CGAL (www.cgal.org); you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public License as // published by the Free Software Foundation; version 2.1 of the License. // See the file LICENSE.LGPL 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. // // $URL$ // $Id$ // // // Author(s) : Daniel Russel #ifndef CGAL_KINETIC_KINETIC_DELAUNAY_2_H #define CGAL_KINETIC_KINETIC_DELAUNAY_2_H #include #include #include #include #include #include #include #include #include #include #include #include #include CGAL_KINETIC_BEGIN_NAMESPACE #define CGAL_DELAUNAY_2_DEBUG(x) template struct Delaunay_edge_failure_event: public Event_base { typedef Event_base P; Delaunay_edge_failure_event(const typename KDel::Certificate_data &c, const typename KDel::Edge &e, KDel *kdel): P(kdel), c_(c), e_(e) {} typename KDel::Certificate_data &certificate() const { return c_; } const typename KDel::Edge edge() const { return e_; } KDel* kdel() { return P::kds(); } KDel* kdel() const { return P::kds(); } void process() { kdel()->flip(e_, c_); } CGAL::Comparison_result compare_concurrent(typename KDel::Event_key a, typename KDel::Event_key b) const { return kdel()->compare_concurrent(a, b); } std::ostream& write(std::ostream &out) const { out << "Flip " << KDel::TDS_helper::origin(edge())->point() << "," << KDel::TDS_helper::destination(edge())->point() << " to " << KDel::TDS_helper::third_vertex(edge())->point() << ", " << KDel::TDS_helper::mirror_vertex(edge())->point() ; return out; } typename KDel::Certificate_data c_; const typename KDel::Edge e_; }; //! A 2D kinetic Delaunay triangulation. /*! Points are added via the Moving_point_table, so the public interface is very limited. See kinetic_Delaunay_2.cc for a useage example. */ template , CGAL::Kinetic::Delaunay_triangulation_face_base_2 > >, class Delaunay_traits_t= Delaunay_triangulation_default_traits_2 > class Delaunay_triangulation_2: public Ref_counted > { typedef CGAL::Delaunay_triangulation_2, CGAL::Kinetic::Delaunay_triangulation_face_base_2 > > Basic_Delaunay; public: typedef Delaunay_traits_t Traits; typedef Simulation_traits_t Simulation_traits; typedef Delaunay_triangulation_2 This; typedef typename Simulation_traits::Kinetic_kernel Kinetic_kernel; typedef typename Simulation_traits::Simulator Simulator; typedef typename Simulation_traits::Active_points_2_table Moving_point_table; typedef typename Moving_point_table::Key Point_key; typedef typename Simulator::Event_key Event_key; //typedef typename Simulator::Root_stack Root_stack; typedef typename Traits::Triangulation Triangulation; typedef typename Triangulation::Edge_circulator Edge_circulator; typedef typename Triangulation::Face_circulator Face_circulator; typedef typename Triangulation::Finite_edges_iterator Finite_edges_iterator; //typedef typename Triangulation::Edge_iterator Edge_iterator; typedef typename Triangulation::Geom_traits::Point_2 Del_point; typedef typename Triangulation::Vertex_handle Vertex_handle; typedef typename Triangulation::Face_handle Face_handle; typedef typename Triangulation::Edge Edge; typedef typename Triangulation::All_faces_iterator Face_iterator; typedef typename Triangulation::All_edges_iterator Edge_iterator; typedef typename Traits::Certificate_data Certificate_data; typedef typename Traits::Time Time; typedef internal::Triangulation_data_structure_helper_2 TDS_helper; typedef Delaunay_edge_failure_event Event; //friend class Delaunay_edge_failure_event; //friend class Delaunay_hull_edge_failure_event; typedef typename CGAL::Kinetic::Simulator_kds_listener Simulator_listener; friend class CGAL::Kinetic::Simulator_kds_listener; typedef typename CGAL::Kinetic::Active_objects_batch_listener_helper Moving_point_table_listener; friend class CGAL::Kinetic::Active_objects_batch_listener_helper; struct Compare_edges{ bool operator()(const Edge &a, const Edge &b) const { Point_key a0, a1, b0, b1; a0= a.first->vertex((a.second+1)%3)->point(); a1= a.first->vertex((a.second+2)%3)->point(); b0= b.first->vertex((b.second+1)%3)->point(); b1= b.first->vertex((b.second+2)%3)->point(); if (a0 > a1) std::swap(a0, a1); if (b0 > b1) std::swap(b0, b1); if (a0 < b0) return true; else if (a0 > b0) return false; else return a1 < b1; } }; void init_data() { siml_ = Simulator_listener(traits_.simulator_handle(), this); motl_= Moving_point_table_listener(traits_.active_points_2_table_handle(), this); has_certificates_=false; clear_stats(); batching_=false; } public: Delaunay_triangulation_2(Traits st, Triangulation del, Visitor w= Visitor()): traits_(st), watcher_(w), del_(del) { vhs_.resize(del_.number_of_vertices()); for (typename Triangulation::Vertex_iterator vit = del_.vertices_begin(); vit != del_.vertices_end(); ++vit) { CGAL_assertion(vit->point().to_index() < del_.number_of_vertices()); vhs_[vit->point().to_index()]=vit; } init_data(); set_has_certificates(true); } Delaunay_triangulation_2(Simulation_traits st, Visitor w= Visitor()): traits_(st), watcher_(w), del_(traits_.instantaneous_kernel_object()) { init_data(); set_has_certificates(true); } //! Just write the objects in order; void write(std::ostream &out) const { out << del_; } void clear_stats() { num_events_=0; // num_single_certificates_=0; } void write_stats(std::ostream &out) const { out << "Num events is " << num_events_ << std::endl; } const Triangulation &triangulation(const typename Simulator::NT &t) const { //update_instantaneous_kernel_time(); del_.geom_traits().set_time(t); return del_; } const Triangulation &triangulation() const { return del_; } // for Qt_triangulation /*Event_key null_event() const { return traits_.simulator_handle()->null_event(); }*/ /*const Simulation_traits& simulation_traits_object() const { return traits_; }*/ typedef typename Triangulation::Triangulation_data_structure Triangulation_data_structure; const Triangulation_data_structure &triangulation_data_structure() const { return del_.tds(); } bool is_batch_editing() const { return batching_; } void set_is_batch_editing(bool tf) { if (tf== batching_) return; else if (tf) { batching_=true; } else { //unsigned int num_certs= num_certificates_; // this is important that it be before update batching_=false; std::sort(batched_certs_.begin(), batched_certs_.end(), Compare_edges()); //std::cout << "Batch has " << batched_certs_.size() << " non-unique edges to compute." << std::endl; batched_certs_.erase(std::unique(batched_certs_.begin(), batched_certs_.end()), batched_certs_.end()); //std::cout << "Batch has " << batched_certs_.size() << " edges to compute." << std::endl; for (unsigned int i=0; i< batched_certs_.size(); ++i){ /*Point_key s=TDS_helper::origin(batched_certs_[i])->point(); Point_key t=TDS_helper::destination(batched_certs_[i])->point(); std::cout << std::min(s,t) << "--" << std::max(s,t) << std::endl;*/ update_edge(batched_certs_[i]); } batched_certs_.clear(); //int dnum= num_certificates_-num_certs; //std::cout << "Edit had " << dnum << " certificate computations" << std::endl; //audit(); } } /*const std::set& recent_edges() const { return new_edges_; }*/ //! Verify that the current state of the void audit() const { if (!has_certificates_) return; CGAL_KINETIC_LOG(CGAL::Kinetic::LOG_SOME, "Auditing delaunay" << std::endl); if (del_.number_of_vertices() < 50) { CGAL_KINETIC_LOG(CGAL::Kinetic::LOG_LOTS, *this); } if (del_.dimension() != 2) return; Basic_Delaunay sdel(traits_.instantaneous_kernel_object()); sdel.geom_traits().set_time(traits_.rational_current_time()); for (typename Triangulation::Finite_vertices_iterator cit= del_.finite_vertices_begin(); cit != del_.finite_vertices_end(); ++cit){ sdel.insert(cit->point()); } /* sdel.insert(traits_.active_points_2_table_handle()->keys_begin(), traits_.active_points_2_table_handle()->keys_end());*/ //CGAL_KINETIC_LOG(CGAL::Kinetic::LOG_LOTS, sdel << std::endl); if (del_.dimension() != sdel.dimension()) { CGAL_KINETIC_LOG(CGAL::Kinetic::LOG_NONE, "AUDIT FAILURE Dimensions don't match in audit" << std::endl); return; } CGAL_exactness_assertion(del_.dimension() == sdel.dimension()); for (typename Triangulation::All_vertices_iterator vit = del_.all_vertices_begin(); vit != del_.all_vertices_end(); ++vit) { if (vit->point() != Point_key()) { if (vit->neighbors_is_changed()) { CGAL_KINETIC_LOG(CGAL::Kinetic::LOG_NONE, "AUDIT FAILURE neighbors is changed " << vit->point() << std::endl); CGAL_exactness_assertion(!vit->neighbors_is_changed()); } if (vit->neighbors() != vit->degree()) { CGAL_KINETIC_LOG(CGAL::Kinetic::LOG_NONE, "AUDIT FAILURE stored degree is " << vit->neighbors() << " and actual is " << vit->degree() << " for " << vit->point() << std::endl); CGAL_exactness_assertion(vit->neighbors() == vit->degree()); } } } for (typename Basic_Delaunay::All_vertices_iterator vit = sdel.all_vertices_begin(); vit != sdel.all_vertices_end(); ++vit) { bool found=false; //Object_key k= vit->point(); for (typename Triangulation::All_vertices_iterator vit2= del_.all_vertices_begin(); vit2 != del_.all_vertices_end(); ++vit2) { //Object_key k2= vit2->point(); if (vit->point() == vit2->point()) { found=true; //int d= vit->degree(); //int d2= vit2->degree(); if (vit->degree() != vit2->degree()) { CGAL_KINETIC_LOG(CGAL::Kinetic::LOG_NONE, "AUDIT FAILURE Degrees don't match in: " << vit->point() << std::endl); } CGAL_exactness_assertion(vit->degree() == vit2->degree()); } } if (!found) { CGAL_KINETIC_LOG(CGAL::Kinetic::LOG_NONE, "AUDIT FAILURE Matching vertex not found: " << vit->point() << std::endl); } CGAL_exactness_assertion(found); } typename Simulation_traits::Instantaneous_kernel ik= traits_.instantaneous_kernel_object(); ik.set_time(traits_.rational_current_time()); typename Simulation_traits::Instantaneous_kernel::Side_of_oriented_circle_2 ic2 = ik.side_of_oriented_circle_2_object(); for (typename Triangulation::Finite_edges_iterator fit = del_.finite_edges_begin(); fit != del_.finite_edges_end(); ++fit){ Point_key k0= fit->first->vertex((fit->second+1)%3)->point(); Point_key k2= fit->first->vertex((fit->second+2)%3)->point(); Point_key k3= TDS_helper::mirror_vertex(*fit)->point(); Point_key k1= TDS_helper::third_vertex(*fit)->point(); if (k1== Point_key() || k3== Point_key()) continue; typename Triangulation::Geom_traits::Current_coordinates cc= del_.geom_traits().current_coordinates_object(); typedef typename Triangulation::Geom_traits::Current_coordinates::result_type P2; P2 p0= cc(k0); P2 p1= cc(k1); P2 p2= cc(k2); P2 p3= cc(k3); if (ic2(k0, k1, k2, k3) != CGAL::ON_POSITIVE_SIDE) { CGAL_KINETIC_LOG(CGAL::Kinetic::LOG_NONE, "AUDIT FAILURE Failed certificate: " << k0 << " " << k1 << " " << k2 << " " << k3 << std::endl); CGAL_KINETIC_LOG(CGAL::Kinetic::LOG_NONE, "AUDIT FAILURE Points are: " << p0 << ": " << p1 << ": " << p2 << ": " << p3 << std::endl); } CGAL_exactness_assertion(ic2(k0, k1, k2, k3) == CGAL::ON_POSITIVE_SIDE); } for (typename Triangulation::Edge_iterator fit = del_.edges_begin(); fit != del_.edges_end(); ++fit){ if (TDS_helper::origin(*fit)->degree()==3 || TDS_helper::destination(*fit)->degree()==3) { if (TDS_helper::get_undirected_edge_label(*fit) != Event_key()) { CGAL_KINETIC_LOG(CGAL::Kinetic::LOG_NONE, "AUDIT FAILURE certificate on degree 3 edge: " << TDS_helper::origin(*fit)->point() << " " << TDS_helper::destination(*fit)->point() << TDS_helper::origin(*fit)->degree() << " " << TDS_helper::destination(*fit)->degree() << std::endl); } CGAL_exactness_assertion(TDS_helper::get_undirected_edge_label(*fit) == Event_key()); } else { if (TDS_helper::get_undirected_edge_label(*fit) == Event_key()) { CGAL_KINETIC_LOG(CGAL::Kinetic::LOG_NONE, "AUDIT FAILURE no certificate on edge: " << TDS_helper::origin(*fit)->point() << " " << TDS_helper::destination(*fit)->point() << std::endl); CGAL_KINETIC_LOG(CGAL::Kinetic::LOG_NONE, "AUDIT FAILURE degrees are: " << TDS_helper::origin(*fit)->degree() << " " << TDS_helper::destination(*fit)->degree() << std::endl); } CGAL_exactness_assertion(TDS_helper::get_undirected_edge_label(*fit) != Event_key()); } } } void set_has_certificates(bool tf) { if (tf == has_certificates_){ } else { if (tf==true && del_.dimension()==2) { CGAL_KINETIC_LOG(CGAL::Kinetic::LOG_SOME, "DELAUNAY2: Creating certificates."<< std::endl); for (typename Triangulation::All_vertices_iterator vit = del_.all_vertices_begin(); vit != del_.all_vertices_end(); ++vit) { int deg=vit->degree(); CGAL_assertion(deg >=3); Vertex_handle vh= vit; vh->set_neighbors(deg); CGAL_DELAUNAY_2_DEBUG(std::cout << "Set degree of " << vit->point() << " to " << deg << std::endl); //vit->set_neighbors_is_changed(false); } for (Edge_iterator eit = del_.all_edges_begin(); eit != del_.all_edges_end(); ++eit) { TDS_helper::set_undirected_edge_label(*eit, Event_key()); update_edge(*eit); } watcher_.create_faces(del_.all_faces_begin(), del_.all_faces_end()); } else if (tf==false) { for (typename Triangulation::Edge_iterator it = del_.edges_begin(); it != del_.edges_end(); ++it){ if (TDS_helper::get_undirected_edge_label(*it) != Event_key()){ delete_certificate(*it); } } } has_certificates_=tf; } } bool has_certificates() { return has_certificates_; } void erase(Point_key k) { // erase all incident certificates Vertex_handle vh= vertex_handle(k); if (vh == Vertex_handle()) { CGAL_KINETIC_LOG(CGAL::Kinetic::LOG_SOME, "Point " << k << " is not in triangulation on removal."<< std::endl); return; } watcher_.remove_vertex(vh); if (has_certificates_) { Face_circulator fc= vh->incident_faces(), fe=fc; if (fc != NULL) { do { for (unsigned int j=0; j<3; ++j) { Edge e(fc, j); Event_key k= TDS_helper::get_undirected_edge_label(e); if (k.is_valid()) { delete_certificate(e); } fc->vertex(j)->set_neighbors_is_changed(true); } ++fc; } while (fc != fe); } } // remove from triangulation del_.geom_traits().set_time(traits_.rational_current_time()); del_.remove(vh); //new_edges_.clear(); if (del_.dimension()==2 && has_certificates_) { std::vector faces; del_.get_conflicts(k,std::back_inserter(faces)); for (unsigned int i=0; i< faces.size(); ++i) { for (unsigned int j=0; j<3; ++j) { Edge e(faces[i],j); //Event_key k= TDS_helper::get_undirected_edge_label(e); // a bit redundant for certificates which don't fail update_edge(e); //new_edges_.insert(e); } } watcher_.create_faces(faces.begin(), faces.end()); } } //! The assertion will catch that the object is in the same sorted order void set(Point_key k) { //std::cout << "Object changed " << k << std::endl; //new_edges_.clear(); if (del_.dimension() != 2) { CGAL_KINETIC_LOG(CGAL::Kinetic::LOG_SOME,"Triangulation is still 1D.\n"); return; } Vertex_handle vh=vertex_handle(k); if (vh == Vertex_handle()) { CGAL_KINETIC_LOG(CGAL::Kinetic::LOG_SOME, "Point " << k << " is not in triangulation on set."<< std::endl); return; } if (has_certificates_) { Edge_circulator ec= vh->incident_edges(), ef=ec; if (ec != NULL) { do { if (TDS_helper::get_undirected_edge_label(*ec) != Event_key()) { delete_certificate(*ec); } ++ec; } while (ec != ef); } Face_circulator fc= vh->incident_faces(), fe= fc; if (fc != NULL) { do { int i= fc->index(vh); Edge e(fc, i); if (TDS_helper::get_undirected_edge_label(e) != Event_key()) { delete_certificate(e); } ++fc; } while (fc != fe); } } watcher_.modify_vertex(vh); if (has_certificates_) { Edge_circulator ec= vh->incident_edges(), ef=ec; if (ec != NULL) { do { update_edge(*ec); ++ec; } while (ec != ef); } Face_circulator fc= vh->incident_faces(), fe= fc; if (fc != NULL) { do { int i= fc->index(vh); update_edge(Edge(fc, i)); ++fc; } while (fc != fe); } } //write(std::cout); } //! /*! Some old certificate edges will be lost, have to find all conflicts first */ void insert(Point_key k) { // evil hack if (vertex_handle(k) != Vertex_handle()) return; CGAL_DELAUNAY_2_DEBUG(std::cout << "Inserting " << k << std::endl); bool was_2d= (del_.dimension()==2); del_.geom_traits().set_time(traits_.rational_current_time()); if (was_2d && has_certificates_) { //std::cout << "removing extra certificates.\n"; std::vector faces; del_.get_conflicts(k, std::back_inserter(faces)); for (unsigned int i=0; i< faces.size(); ++i) { Face_handle f= faces[i]; for (unsigned int j=0; j<3; ++j) { f->vertex(j)->set_neighbors_is_changed(true); Edge e(f, j); Event_key k= TDS_helper::get_undirected_edge_label(e); if (k != Event_key()) { delete_certificate(e); } } } watcher_.remove_faces(faces.begin(), faces.end()); if (faces.empty()) { CGAL_KINETIC_LOG(CGAL::Kinetic::LOG_SOME, "DELAUNAY vertex not successfully inserted " << k << std::endl); return; } } set_vertex_handle(k, del_.insert(k)); CGAL_assertion(vertex_handle(k) != Vertex_handle()); vertex_handle(k)->set_neighbors(vertex_handle(k)->degree()); CGAL_DELAUNAY_2_DEBUG(std::cout << "Vertex " << vertex_handle(k)->point() << " has " << vertex_handle(k)->neighbors() << std::endl); watcher_.create_vertex(vertex_handle(k)); // now have to update if (!was_2d && del_.dimension()==2) { //std::cout << "Creating certificates from scratch.\n"; if (has_certificates_) { has_certificates_=false; set_has_certificates(true); } } else if (del_.dimension() == 2 && has_certificates_) { Vertex_handle vh= vertex_handle(k); Edge_circulator ec= vh->incident_edges(), ef=ec; do { if (TDS_helper::get_undirected_edge_label(*ec) == Event_key()) { update_edge(*ec); } ++ec; } while (ec != ef); Face_circulator fc= vh->incident_faces(), fe= fc; do { int i= fc->index(vh); Edge e(fc, i); if (TDS_helper::get_undirected_edge_label(e) == Event_key()) { update_edge(e); } ++fc; } while (fc != fe); } //write(std::cout); //if (del_.dimension()==2) audit(); } Comparison_result compare_concurrent(Event_key a, Event_key b) const { Edge ea= traits_.simulator_handle()->template event(a).edge(); Edge eb= traits_.simulator_handle()->template event(b).edge(); return traits_.compare_concurrent(a, ea, b, eb); } Edge flip(const Edge &e, Certificate_data cert) { ++num_events_; CGAL_precondition(!batching_); CGAL_KINETIC_LOG(CGAL::Kinetic::LOG_SOME, "DELAUNAY Flipping edge " << TDS_helper::origin(e)->point() << TDS_helper::destination(e)->point() << std::endl); //CGAL_KINETIC_LOG(CGAL::Kinetic::LOG_NONE, TDS_helper::destination(e)->point() << std::endl); //CGAL_KINETIC_LOG(CGAL::Kinetic::LOG_SOME, " at " << traits_.simulator()->current_time() << std::endl); Face_handle face= e.first; int index= e.second; int mirror_index = face->mirror_index(index); Face_handle mirror_face = face->neighbor(index); if (del_.is_edge(TDS_helper::third_vertex(e), TDS_helper::mirror_vertex(e))) { // we have a numeric error, lets try to rebuild the neighboring certificates CGAL_KINETIC_LOG(CGAL::Kinetic::LOG_SOME, "DELAUNAY ERROR not flipping unflippable edge" << std::endl); //make this better double ub=to_interval(traits_.simulator_handle()->next_event_time()).second; ub= (std::max)(ub+.0000001, nextafter(ub, (std::numeric_limits::max)())); Time t=ub; //cert.pop_failure_time(); Event_key k =traits_.simulator_handle()->new_event(t, Event(cert, e, this)); TDS_helper::set_undirected_edge_label(e, k); return e; } for (unsigned int i=0; i<3; ++i) { Edge e0(face, i); if (e0.second != index && TDS_helper::get_undirected_edge_label(e0) != Event_key()) { delete_certificate(e0); } face->vertex(i)->set_neighbors_is_changed(true); Edge e1(mirror_face, i); if (e1.second != mirror_index && TDS_helper::get_undirected_edge_label(e1) != Event_key()) { delete_certificate(e1); } mirror_face->vertex(i)->set_neighbors_is_changed(true); } TDS_helper::set_undirected_edge_label(e, Event_key()); watcher_.before_flip(e); del_.tds().flip(face,index); // we also know that CGAL preserves the edge index of the flipped edge mirror_index = mirror_face->index(face); index= face->index(mirror_face); Edge flipped_edge(face,index); //CGAL_postcondition(del_.is_face(face)); { std::pair sp= traits_.certificate_failure_time(e,cert); Event_key k =traits_.simulator_handle()->new_event(sp.first, Event(sp.second, flipped_edge, this)); TDS_helper::set_undirected_edge_label(flipped_edge, k); } mirror_index = face->mirror_index(index); mirror_face = face->neighbor(index); for (unsigned int i=0; i<3; ++i) { Edge e0(face, i); update_edge(e0); Edge e1(mirror_face, i); update_edge(e1); } //write(std::cout); //new_edges_.clear(); //new_edges_.insert(flipped_edge); CGAL_KINETIC_LOG(CGAL::Kinetic::LOG_SOME, "Created " << TDS_helper::origin(flipped_edge)->point()); CGAL_KINETIC_LOG(CGAL::Kinetic::LOG_SOME, TDS_helper::destination(flipped_edge)->point() << std::endl); watcher_.after_flip(flipped_edge); return flipped_edge; } Visitor &visitor() { return watcher_; } const Visitor &visitor() const { return watcher_; } protected: Traits traits_; Visitor watcher_; Triangulation del_; Simulator_listener siml_; Moving_point_table_listener motl_; std::vector vhs_; bool has_certificates_; bool batching_; std::vector batched_certs_; mutable unsigned int num_events_; //mutable unsigned int num_single_certificates_; const typename Traits::Point_2& point(Point_key k) const { return traits_.point(k); } Vertex_handle vertex_handle(Point_key k) const { if (k.to_index() >= vhs_.size()) return Vertex_handle(); CGAL_precondition(k.to_index() < vhs_.size()); return vhs_[k.to_index()]; } void set_vertex_handle(Point_key k, Vertex_handle vh) { vhs_.resize(std::max(k.to_index()+1, vhs_.size())); vhs_[k.to_index()]=vh; } void update_vertex(Vertex_handle vh) { if (!vh->neighbors_is_changed()) { } else { int deg= vh->degree(); if (deg ==3 && vh->neighbors() != 3) { CGAL_DELAUNAY_2_DEBUG(std::cout << "Degree 3 for " << vh->point() << std::endl); vh->set_neighbors(deg); typename Triangulation::Edge_circulator ec= del_.incident_edges(vh); do { if (TDS_helper::get_undirected_edge_label(*ec) != Event_key()) { delete_certificate(*ec); } ++ec; } while (ec != del_.incident_edges(vh)); } else if (vh->neighbors()==3 && deg != 3) { CGAL_DELAUNAY_2_DEBUG(std::cout << "Degree 4 for " << vh->point() << std::endl); vh->set_neighbors(deg); typename Triangulation::Edge_circulator ec= del_.incident_edges(vh); do { if (TDS_helper::get_undirected_edge_label(*ec) == Event_key()) { // check other vertex, it it is not changed and not 3, build Vertex_handle ov= ec->first->vertex((ec->second+1)%3); if (ov== vh) { ov= ec->first->vertex((ec->second+2)%3); } if (!ov->neighbors_is_changed() && ov->neighbors() != 3){ new_certificate(*ec); CGAL_DELAUNAY_2_DEBUG(std::cout << "New cert for " << TDS_helper::origin(*ec)->point() << " " << TDS_helper::destination(*ec)->point() << std::endl); } else { CGAL_DELAUNAY_2_DEBUG(std::cout << "Not creating cert for " << TDS_helper::origin(*ec)->point() << " " << TDS_helper::destination(*ec)->point() << std::endl); } } ++ec; } while (ec != del_.incident_edges(vh)); } else { vh->set_neighbors(deg); } CGAL_DELAUNAY_2_DEBUG( std::cout << "Vertex " << vh->point() << " has " << vh->neighbors() << std::endl); } } void update_edge(const Edge &e) { if (batching_) { batched_certs_.push_back(e); } else { CGAL_DELAUNAY_2_DEBUG(std::cout << "Updating edge " << TDS_helper::origin(e)->point() << " " << TDS_helper::destination(e)->point() << std::endl); Vertex_handle ov=TDS_helper::origin(e); Vertex_handle dv=TDS_helper::destination(e); update_vertex(ov); update_vertex(dv); CGAL_assertion(!ov->neighbors_is_changed()); CGAL_assertion(!dv->neighbors_is_changed()); if (TDS_helper::get_undirected_edge_label(e) != Event_key()) { CGAL_DELAUNAY_2_DEBUG(std::cout << "Already has event " << std::endl); } else if (ov->neighbors() ==3 || dv->neighbors() ==3) { CGAL_DELAUNAY_2_DEBUG(std::cout << "One end has 3 " << std::endl); } else { CGAL_DELAUNAY_2_DEBUG(std::cout << "New certificate" << std::endl); new_certificate(e); } } } void new_certificate(Edge e) { CGAL_precondition(TDS_helper::get_undirected_edge_label(e) == Event_key()); CGAL_DELAUNAY_2_DEBUG(std::cout << "Making certificate for " << TDS_helper::origin(e)->point() << " " << TDS_helper::destination(e)->point() << " which would make " << TDS_helper::mirror_vertex(e)->point() << " " << TDS_helper::third_vertex(e)->point() << std::endl); std::pair sp= traits_.certificate_failure_time(e); Event_key k= traits_.simulator_handle()->new_event(sp.first, Event(sp.second, e, this)); TDS_helper::set_undirected_edge_label(e, k); } void delete_certificate(Edge e) { Event_key k= TDS_helper::get_undirected_edge_label(e); traits_.simulator_handle()->delete_event(k); TDS_helper::set_undirected_edge_label(e, Event_key()); } }; template std::ostream &operator<<(std::ostream &out, const Delaunay_triangulation_2 &kd) { kd.write(out); return out; } CGAL_KINETIC_END_NAMESPACE #endif