1 // Copyright (c) 1999-2004,2006-2009, 2017 INRIA Sophia-Antipolis (France).
2 // All rights reserved.
3 //
4 // This file is part of CGAL (www.cgal.org).
5 //
6 // $URL: https://github.com/CGAL/cgal/blob/v5.3/Periodic_3_triangulation_3/include/CGAL/Periodic_3_Delaunay_triangulation_3.h $
7 // $Id: Periodic_3_Delaunay_triangulation_3.h 0779373 2020-03-26T13:31:46+01:00 Sébastien Loriot
8 // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
9 //
10 // Author(s) : Monique Teillaud <Monique.Teillaud@sophia.inria.fr>
11 // Sylvain Pion <Sylvain.Pion@sophia.inria.fr>
12 // Andreas Fabri <Andreas.Fabri@sophia.inria.fr>
13 // Nico Kruithof <Nico.Kruithof@sophia.inria.fr>
14 // Manuel Caroli <Manuel.Caroli@sophia.inria.fr>
15
16 #ifndef CGAL_PERIODIC_3_DELAUNAY_TRIANGULATION_3_H
17 #define CGAL_PERIODIC_3_DELAUNAY_TRIANGULATION_3_H
18
19 #include <CGAL/license/Periodic_3_triangulation_3.h>
20
21 #include <CGAL/Periodic_3_triangulation_3.h>
22 #include <CGAL/spatial_sort.h>
23
24 // Needed by remove to fill the hole.
25 #include <CGAL/internal/Periodic_3_Delaunay_triangulation_remove_traits_3.h>
26 #include <CGAL/Delaunay_triangulation_3.h>
27
28 #include <iostream>
29 #include <vector>
30 #include <utility>
31
32 namespace CGAL {
33
34 template < class GT, class TDS > class Periodic_3_Delaunay_triangulation_3;
35 template < class GT, class TDS > std::istream& operator>>
36 (std::istream& is, Periodic_3_Delaunay_triangulation_3<GT,TDS> &tr);
37
38 template < class Gt,
39 class Tds = Triangulation_data_structure_3 <
40 Triangulation_vertex_base_3<
41 Gt, Periodic_3_triangulation_ds_vertex_base_3<>
42 >,
43 Triangulation_cell_base_3<
44 Gt, Periodic_3_triangulation_ds_cell_base_3<>
45 >
46 >
47 >
48 class Periodic_3_Delaunay_triangulation_3 :
49 public Periodic_3_triangulation_3<Gt, Tds>
50 {
51 friend std::istream& operator>> <>
52 (std::istream& is, Periodic_3_Delaunay_triangulation_3<Gt, Tds> &tr);
53
54 typedef Periodic_3_Delaunay_triangulation_3<Gt,Tds> Self;
55 public:
56 typedef Periodic_3_triangulation_3<Gt,Tds> Base;
57
58 public:
59 /** @name Template parameter types */
60 typedef Gt Geometric_traits;
61 typedef Tds Triangulation_data_structure;
62
63
64 ///Compatibility typedef:
65 typedef Geometric_traits Geom_traits;
66 typedef typename Gt::FT FT;
67
68 typedef typename Gt::Point_3 Point;
69 typedef typename Gt::Segment_3 Segment;
70 typedef typename Gt::Triangle_3 Triangle;
71 typedef typename Gt::Tetrahedron_3 Tetrahedron;
72
73 typedef typename Base::Periodic_point Periodic_point;
74 typedef typename Base::Periodic_segment Periodic_segment;
75 typedef typename Base::Periodic_triangle Periodic_triangle;
76 typedef typename Base::Periodic_tetrahedron Periodic_tetrahedron;
77
78 typedef typename Base::Cell_handle Cell_handle;
79 typedef typename Base::Vertex_handle Vertex_handle;
80
81 typedef typename Base::Cell Cell;
82 typedef typename Base::Vertex Vertex;
83 typedef typename Base::Facet Facet;
84 typedef typename Base::Edge Edge;
85
86 typedef typename Base::Cell_circulator Cell_circulator;
87 typedef typename Base::Facet_circulator Facet_circulator;
88 typedef typename Base::Cell_iterator Cell_iterator;
89 typedef typename Base::Facet_iterator Facet_iterator;
90 typedef typename Base::Edge_iterator Edge_iterator;
91 typedef typename Base::Vertex_iterator Vertex_iterator;
92
93 typedef typename Base::All_cells_iterator All_cells_iterator;
94 typedef typename Base::All_facets_iterator All_facets_iterator;
95 typedef typename Base::All_edges_iterator All_edges_iterator;
96 typedef typename Base::All_vertices_iterator All_vertices_iterator;
97
98 typedef typename Base::size_type size_type;
99 typedef typename Base::difference_type difference_type;
100
101 typedef typename Base::Locate_type Locate_type;
102 typedef typename Base::Iterator_type Iterator_type;
103
104 typedef typename Base::Offset Offset;
105 typedef typename Base::Iso_cuboid Iso_cuboid;
106 typedef typename Base::Covering_sheets Covering_sheets;
107 typedef typename Base::Periodic_segment_iterator Periodic_segment_iterator;
108 typedef typename Base::Periodic_tetrahedron_iterator Periodic_tetrahedron_iterator;
109
110 //Tag to distinguish Delaunay from Regular triangulations
111 typedef Tag_false Weighted_tag;
112
113 // Tag to distinguish periodic triangulations from others
114 typedef Tag_true Periodic_tag;
115
116 #ifndef CGAL_CFG_USING_BASE_MEMBER_BUG_2
117 using Base::cw;
118 using Base::ccw;
119 using Base::domain;
120 using Base::geom_traits;
121 using Base::insert_dummy_points;
122 using Base::int_to_off;
123 using Base::is_1_cover;
124 using Base::is_virtual;
125 using Base::number_of_sheets;
126 using Base::number_of_vertices;
127 using Base::number_of_edges;
128 using Base::number_of_facets;
129 using Base::number_of_cells;
130 using Base::next_around_edge;
131 using Base::vertex_triple_index;
132 using Base::mirror_vertex;
133 using Base::orientation;
134 using Base::point;
135 using Base::swap;
136 using Base::tds;
137 using Base::vertices_begin;
138 using Base::vertices_end;
139 using Base::edges_begin;
140 using Base::edges_end;
141 using Base::facets_begin;
142 using Base::facets_end;
143 using Base::cells_begin;
144 using Base::cells_end;
145 #endif
146
147 // For strict-ansi compliance
148 using Base::adjacent_vertices;
149 using Base::combine_offsets;
150 using Base::construct_point;
151 using Base::convert_to_27_sheeted_covering;
152 using Base::draw_dual;
153 using Base::incident_edges;
154 using Base::incident_facets;
155 using Base::incident_cells;
156 using Base::is_valid_conflict;
157 using Base::get_offset;
158 using Base::get_original_vertex;
159 using Base::get_location_offset;
160 using Base::locate;
161 using Base::neighbor_offset;
162 using Base::periodic_point;
163
164 private:
165 /// This threshold should be chosen such that if all edges are shorter,
166 /// we can be sure that there are no self-edges anymore.
167 FT edge_length_threshold;
168
169 /// This adjacency list stores all edges that are longer than
170 /// edge_length_threshold.
171 std::map< Vertex_handle, std::list<Vertex_handle> > too_long_edges;
172 unsigned int too_long_edge_counter;
173
174 class Cover_manager
175 {
176 Periodic_3_Delaunay_triangulation_3& tr;
177
178 public:
Cover_manager(Periodic_3_Delaunay_triangulation_3 & tr)179 Cover_manager (Periodic_3_Delaunay_triangulation_3& tr)
180 : tr(tr)
181 {}
182
create_initial_triangulation()183 void create_initial_triangulation()
184 {
185 tr.create_initial_triangulation();
186 }
187
188 template <class CellIt>
delete_unsatisfying_elements(const CellIt begin,const CellIt end)189 void delete_unsatisfying_elements(const CellIt begin, const CellIt end)
190 {
191 tr.delete_too_long_edges(begin, end);
192 }
193
194 template <class CellIt>
insert_unsatisfying_elements(Vertex_handle v,const CellIt begin,const CellIt end)195 void insert_unsatisfying_elements(Vertex_handle v, const CellIt begin, const CellIt end)
196 {
197 tr.insert_too_long_edges(v, begin, end);
198 }
199
can_be_converted_to_1_sheet()200 bool can_be_converted_to_1_sheet () const
201 {
202 return tr.can_be_converted_to_1_sheet();
203 }
204
update_cover_data_during_management(Cell_handle new_ch,const std::vector<Cell_handle> & new_cells,const bool abort_if_cover_change)205 bool update_cover_data_during_management(Cell_handle new_ch,
206 const std::vector<Cell_handle>& new_cells,
207 const bool abort_if_cover_change)
208 {
209 return tr.update_cover_data_during_management(new_ch, new_cells, abort_if_cover_change);
210 }
211 };
212
213 public:
214 /** @name Creation */
215 Periodic_3_Delaunay_triangulation_3(const Iso_cuboid& domain = Iso_cuboid(0,0,0,1,1,1),
216 const Geometric_traits& gt = Geometric_traits())
Base(domain,gt)217 : Base(domain, gt), too_long_edge_counter(0)
218 {
219 edge_length_threshold = FT(0.166) * (domain.xmax()-domain.xmin())
220 * (domain.xmax()-domain.xmin());
221 }
222
223 template < typename InputIterator >
224 Periodic_3_Delaunay_triangulation_3(InputIterator first, InputIterator last,
225 const Iso_cuboid& domain = Iso_cuboid(0,0,0,1,1,1),
226 const Geometric_traits& gt = Geometric_traits())
Base(domain,gt)227 : Base(domain, gt), too_long_edge_counter(0)
228 {
229 edge_length_threshold = FT(0.166) * (domain.xmax()-domain.xmin())
230 * (domain.xmax()-domain.xmin());
231 insert(first, last);
232 }
233
234 // copy constructor duplicates vertices and cells
Periodic_3_Delaunay_triangulation_3(const Periodic_3_Delaunay_triangulation_3 & tr)235 Periodic_3_Delaunay_triangulation_3(const Periodic_3_Delaunay_triangulation_3& tr)
236 : Base(static_cast<const Base&>(tr)),
237 edge_length_threshold(tr.edge_length_threshold), too_long_edge_counter(0)
238 {
239 if(!is_1_cover())
240 compute_too_long_edges();
241
242 CGAL_triangulation_expensive_postcondition(*this == tr);
243 CGAL_triangulation_expensive_postcondition(is_valid());
244 }
245
246 Periodic_3_Delaunay_triangulation_3 operator=(Periodic_3_Delaunay_triangulation_3 tr)
247 {
248 tr.swap(*this);
249 return *this;
250 }
251
swap(Periodic_3_Delaunay_triangulation_3 & tr)252 void swap(Periodic_3_Delaunay_triangulation_3&tr)
253 {
254 std::swap(edge_length_threshold,tr.edge_length_threshold);
255 std::swap(too_long_edges,tr.too_long_edges);
256 std::swap(too_long_edge_counter,tr.too_long_edge_counter);
257 Base::swap(tr);
258 }
259
clear_covering_data()260 virtual void clear_covering_data()
261 {
262 too_long_edges.clear();
263 too_long_edge_counter = 0;
264 }
265
update_cover_data_after_setting_domain()266 virtual void update_cover_data_after_setting_domain ()
267 {
268 edge_length_threshold = FT(0.166) * (domain().xmax()-domain().xmin())
269 * (domain().xmax()-domain().xmin());
270 }
271
update_cover_data_after_converting_to_27_sheeted_covering()272 virtual void update_cover_data_after_converting_to_27_sheeted_covering()
273 {
274 compute_too_long_edges();
275 }
276
277 bool is_extensible_triangulation_in_1_sheet_h1() const;
278 bool is_extensible_triangulation_in_1_sheet_h2() const;
279
280 // iterates over all edges and store the ones that are longer than 'edge_length_threshold'
compute_too_long_edges()281 void compute_too_long_edges()
282 {
283 too_long_edge_counter = 0;
284 too_long_edges.clear();
285
286 for(Vertex_iterator vit = vertices_begin(); vit != vertices_end(); ++vit)
287 too_long_edges[vit] = std::list<Vertex_handle>();
288
289 std::pair<Vertex_handle, Vertex_handle> edge_to_add;
290 Point p1, p2;
291 int i, j;
292
293 for(Edge_iterator eit = edges_begin(); eit != edges_end(); ++eit)
294 {
295 if(&*(eit->first->vertex(eit->second)) < &*(eit->first->vertex(eit->third))) {
296 i = eit->second; j = eit->third;
297 } else {
298 i = eit->third; j = eit->second;
299 }
300
301 edge_to_add = std::make_pair(eit->first->vertex(i), eit->first->vertex(j));
302 p1 = construct_point(eit->first->vertex(i)->point(), get_offset(eit->first, i));
303 p2 = construct_point(eit->first->vertex(j)->point(), get_offset(eit->first, j));
304 Vertex_handle v_no = eit->first->vertex(i);
305 if(squared_distance(p1,p2) > edge_length_threshold)
306 {
307 CGAL_triangulation_assertion(find(too_long_edges[v_no].begin(),
308 too_long_edges[v_no].end(),
309 edge_to_add.second) == too_long_edges[v_no].end());
310 too_long_edges[v_no].push_back(edge_to_add.second);
311 ++too_long_edge_counter;
312 }
313 }
314 }
315
create_initial_triangulation()316 void create_initial_triangulation()
317 {
318 // create the base for too_long_edges;
319 CGAL_triangulation_assertion( too_long_edges.empty() );
320 CGAL_triangulation_assertion(too_long_edge_counter == 0);
321
322 for(Vertex_iterator vit = vertices_begin(); vit !=vertices_end(); ++vit )
323 too_long_edges[vit] = std::list<Vertex_handle>();;
324
325 std::vector<Cell_handle> temp_inc_cells;
326 for(Vertex_iterator vit = vertices_begin(); vit !=vertices_end(); ++vit ) {
327 temp_inc_cells.clear();
328 incident_cells(vit, std::back_inserter(temp_inc_cells));
329 for(unsigned int i=0; i<temp_inc_cells.size(); i++) {
330 int k = temp_inc_cells[i]->index(vit);
331 for(int j=0; j<4; j++) {
332 if(j==k) continue;
333 if(&*vit > &*(temp_inc_cells[i]->vertex(j))) continue;
334 if((find(too_long_edges[vit].begin(),
335 too_long_edges[vit].end(),
336 temp_inc_cells[i]->vertex(j)) ==
337 too_long_edges[vit].end())) {
338 too_long_edges[vit].push_back(temp_inc_cells[i]->vertex(j));
339 too_long_edge_counter++;
340 }
341 }
342 }
343 }
344 }
345
346 template <class CellIt>
delete_too_long_edges(const CellIt begin,const CellIt end)347 void delete_too_long_edges(const CellIt begin, const CellIt end)
348 {
349 std::pair< Vertex_handle, Vertex_handle > edge_to_delete, edge_to_delete2;
350 typename std::list< Vertex_handle >::iterator sit;
351 // Iterate over all cells that are in the star. That means that those cells
352 // are going to be deleted. Therefore, all of them have to be deleted from
353 // too_long_edges, if they are contained in it.
354 for(CellIt it = begin; it != end; ++it) {
355 for(int j=0; j<4; j++) {
356 for(int k=0; k<4; k++) {
357 if(&*((*it)->vertex(j)) < &*((*it)->vertex(k))) {
358 edge_to_delete = std::make_pair((*it)->vertex(j),(*it)->vertex(k));
359 } else {
360 edge_to_delete = std::make_pair((*it)->vertex(k),(*it)->vertex(j));
361 }
362 Vertex_handle v_no = edge_to_delete.first;
363 std::list<Vertex_handle>& vl = too_long_edges[v_no];
364 sit = std::find(vl.begin(), vl.end(), edge_to_delete.second);
365 if(sit != vl.end()) {
366 vl.erase(sit);
367 too_long_edge_counter--;
368 }
369 }
370 }
371 }
372 }
373
374 template <class CellIt>
insert_too_long_edges(Vertex_handle v,const CellIt begin,const CellIt end)375 void insert_too_long_edges(Vertex_handle v, const CellIt begin, const CellIt end)
376 {
377 CGAL_triangulation_precondition(number_of_vertices() != 0);
378 // add newly added edges to too_long_edges, if necessary.
379 Point p1,p2;
380 std::pair< Vertex_handle, Vertex_handle > edge_to_add;
381 std::list<Vertex_handle> empty_list;
382 too_long_edges[v] = empty_list;
383 // Iterate over all cells of the new star.
384 for(CellIt it = begin; it != end; ++it) {
385 // Consider all possible vertex pairs.
386 for(int k=0; k<4; k++) {
387 for(int j=0; j<4; j++) {
388 if(j==k) continue;
389 if(&*((*it)->vertex(j)) > &*((*it)->vertex(k))) continue;
390 // make the offsets canonical (wrt. to some notion)
391 // add to too_long_edges, if not yet added and if "too long"
392 CGAL_triangulation_precondition(
393 &*((*it)->vertex(j))< &*((*it)->vertex(k)));
394
395 edge_to_add = std::make_pair((*it)->vertex(j), (*it)->vertex(k));
396
397 p1 = construct_point((*it)->vertex(j)->point(), get_offset(*it, j));
398 p2 = construct_point((*it)->vertex(k)->point(), get_offset(*it, k));
399
400 std::list<Vertex_handle>& vl = too_long_edges[(*it)->vertex(j)];
401
402 if((squared_distance(p1,p2) > edge_length_threshold)
403 && (find(vl.begin(), vl.end(), edge_to_add.second)
404 == vl.end())) {
405 vl.push_back(edge_to_add.second);
406 too_long_edge_counter++;
407 }
408 }
409 }
410 }
411 }
412
can_be_converted_to_1_sheet()413 bool can_be_converted_to_1_sheet() const
414 {
415 return too_long_edge_counter == 0;
416 }
417
update_cover_data_during_management(Cell_handle new_ch,const std::vector<Cell_handle> & new_cells,const bool abort_if_cover_change)418 bool update_cover_data_during_management(Cell_handle new_ch,
419 const std::vector<Cell_handle>& new_cells,
420 const bool abort_if_cover_change)
421 {
422 for(int i=0; i < 4; i++)
423 {
424 for(int j=0; j < 4; j++)
425 {
426 if(j==i)
427 continue;
428
429 if(&*(new_ch->vertex(i)) > &*(new_ch->vertex(j)))
430 continue;
431
432 Point p1 = construct_point(new_ch->vertex(i)->point(),
433 get_offset(new_ch, i));
434 Point p2 = construct_point(new_ch->vertex(j)->point(),
435 get_offset(new_ch, j));
436 Vertex_handle v_no = new_ch->vertex(i);
437
438 if(squared_distance(p1, p2) > edge_length_threshold)
439 {
440 // If the cell does not fulfill the edge-length criterion
441 // revert all changes to the triangulation and transform it
442 // to a triangulation in the needed covering space.
443 if(is_1_cover())
444 {
445 if(abort_if_cover_change)
446 return true;
447
448 tds().delete_cells(new_cells.begin(), new_cells.end());
449 convert_to_27_sheeted_covering();
450 return true;
451 }
452 else if(find(too_long_edges[v_no].begin(),
453 too_long_edges[v_no].end(),
454 new_ch->vertex(j)) == too_long_edges[v_no].end())
455 {
456 too_long_edges[v_no].push_back(new_ch->vertex(j));
457 too_long_edge_counter++;
458 }
459 }
460 }
461 }
462 return false;
463 }
464
465 /** @name Insertion */
466 Vertex_handle insert(const Point& p, Cell_handle start = Cell_handle())
467 {
468 Conflict_tester tester(p, this);
469 Point_hider hider;
470 Cover_manager cover_manager(*this);
471 return Base::insert_in_conflict(p, start, tester, hider, cover_manager);
472 }
473
insert(const Point & p,Locate_type lt,Cell_handle c,int li,int lj)474 Vertex_handle insert(const Point& p, Locate_type lt, Cell_handle c,
475 int li, int lj)
476 {
477 Conflict_tester tester(p, this);
478 Point_hider hider;
479 Cover_manager cover_manager(*this);
480 return Base::insert_in_conflict(p,lt,c,li,lj, tester,hider, cover_manager);
481 }
482
483 template < class InputIterator >
484 std::ptrdiff_t insert(InputIterator first, InputIterator last,
485 bool is_large_point_set = false)
486 {
487 if(first == last) return 0;
488 size_type n = number_of_vertices();
489 // The heuristic discards the existing triangulation so it can only be
490 // applied to empty triangulations.
491 if(n!=0)
492 is_large_point_set = false;
493
494 std::vector<Point> points(first, last);
495 std::vector<Vertex_handle> dummy_points, double_vertices;
496 typename std::vector<Point>::iterator pbegin = points.begin();
497 if(is_large_point_set)
498 {
499 dummy_points = insert_dummy_points();
500 } else {
501 CGAL::cpp98::random_shuffle(points.begin(), points.end());
502 pbegin = points.begin();
503 while(!is_1_cover()) {
504 insert(*pbegin);
505 ++pbegin;
506 if(pbegin == points.end())
507 return number_of_vertices() - n;
508 }
509 }
510
511 CGAL_postcondition(is_1_cover());
512
513 spatial_sort (pbegin, points.end(), this->geom_traits());
514
515 Cell_handle hint;
516 Conflict_tester tester(*pbegin,this);
517 Point_hider hider;
518 Cover_manager cover_manager(*this);
519 double_vertices = Base::insert_in_conflict(
520 points.begin(), points.end(), hint, tester, hider, cover_manager);
521
522 if(is_large_point_set) {
523 typedef CGAL::Periodic_3_Delaunay_triangulation_remove_traits_3<Gt> P3removeT;
524 typedef CGAL::Delaunay_triangulation_3< P3removeT > DT;
525 typedef Vertex_remover< DT > Remover;
526 P3removeT remove_traits(domain());
527 DT dt(remove_traits);
528 Remover remover(this,dt);
529 Conflict_tester t(this);
530 for(unsigned int i=0; i<dummy_points.size(); i++) {
531 if(std::find(double_vertices.begin(), double_vertices.end(),
532 dummy_points[i]) == double_vertices.end())
533 Base::remove(dummy_points[i],remover,t, cover_manager);
534 }
535 }
536
537 return number_of_vertices() - n;
538 }
539
540 /** @name Point moving */
541 // @todo should be deprecated and a function move() should be introduced
542 // see what is done in /Triangulation_3
543 // Also need to introduce move() for periodic regular triangulations
544 Vertex_handle move_point(Vertex_handle v, const Point& p);
545
546
547 public:
548 /** @name Removal */
549 void remove(Vertex_handle v);
550
551 // Undocumented function that tries to remove 'v' but only does so if removal
552 // does not make the triangulation become 27-sheeted. Useful for P3M3.
553 // \pre the triangulation is 1-sheeted
554 bool remove_if_no_cover_change(Vertex_handle v);
555
556 template < typename InputIterator >
remove(InputIterator first,InputIterator beyond)557 std::ptrdiff_t remove(InputIterator first, InputIterator beyond)
558 {
559 std::size_t n = number_of_vertices();
560 while(first != beyond) {
561 remove(*first);
562 ++first;
563 }
564 return n - number_of_vertices();
565 }
566
567 public:
568 /** @name Wrapping the traits */
side_of_oriented_sphere(const Point & p,const Point & q,const Point & r,const Point & s,const Point & t)569 Oriented_side side_of_oriented_sphere(const Point& p, const Point& q,
570 const Point& r, const Point& s,
571 const Point& t) const {
572 return geom_traits().side_of_oriented_sphere_3_object()(p,q,r,s,t);
573 }
side_of_oriented_sphere(const Point & p,const Point & q,const Point & r,const Point & s,const Point & t,const Offset & o_p,const Offset & o_q,const Offset & o_r,const Offset & o_s,const Offset & o_t)574 Oriented_side side_of_oriented_sphere(const Point& p, const Point& q,
575 const Point& r, const Point& s,
576 const Point& t,
577 const Offset& o_p, const Offset& o_q,
578 const Offset& o_r, const Offset& o_s,
579 const Offset& o_t) const {
580 return geom_traits().side_of_oriented_sphere_3_object()(
581 p,q,r,s,t,o_p,o_q,o_r,o_s,o_t);
582 }
compare_distance(const Point & p,const Point & q,const Point & r)583 Comparison_result compare_distance(const Point& p, const Point& q,
584 const Point& r) const {
585 return geom_traits().compare_distance_3_object()(p, q, r);
586 }
compare_distance(const Point & p,const Point & q,const Point & r,const Offset & o_p,const Offset & o_q,const Offset & o_r)587 Comparison_result compare_distance(const Point& p, const Point& q,
588 const Point& r,
589 const Offset& o_p, const Offset& o_q,
590 const Offset& o_r) const {
591 return geom_traits().compare_distance_3_object()(p, q, r, o_p, o_q, o_r);
592 }
593
594 private:
595 /** @name Query helpers */
596 Bounded_side _side_of_sphere(const Cell_handle& c, const Point& p,
597 const Offset & offset = Offset(), bool perturb = false) const;
598
599 Offset get_min_dist_offset(const Point& p, const Offset& o,
600 const Vertex_handle vh) const;
601
602 public:
603 /** @name Queries */
604 Bounded_side side_of_sphere(const Cell_handle& c, const Point& p,
605 const Offset & offset = Offset(), bool perturb = false) const{
606 Bounded_side bs = ON_UNBOUNDED_SIDE;
607 int i=0;
608 // TODO: optimize which copies to check depending on the offsets in
609 // the cell.
610 while(bs == ON_UNBOUNDED_SIDE && i<8) {
611 bs= _side_of_sphere(c,p,combine_offsets(offset,int_to_off(i)),perturb);
612 i++;
613 }
614 return bs;
615 }
616
617 Vertex_handle nearest_vertex(const Point& p, Cell_handle c = Cell_handle()) const;
618 Vertex_handle nearest_vertex_in_cell(const Cell_handle& c, const Point & p,
619 const Offset & offset = Offset()) const;
620
621 /// Undocumented wrapper for find_conflicts.
622 template <class OutputIteratorBoundaryFacets, class OutputIteratorCells>
623 std::pair<OutputIteratorBoundaryFacets, OutputIteratorCells>
find_conflicts(const Point & p,Cell_handle c,OutputIteratorBoundaryFacets bfit,OutputIteratorCells cit)624 find_conflicts(const Point &p, Cell_handle c,
625 OutputIteratorBoundaryFacets bfit,
626 OutputIteratorCells cit) const
627 {
628 Triple<OutputIteratorBoundaryFacets,OutputIteratorCells,Emptyset_iterator>
629 t = find_conflicts(p, c, bfit, cit, Emptyset_iterator());
630 return std::make_pair(t.first, t.second);
631 }
632
633 template <class OutputIteratorBoundaryFacets, class OutputIteratorCells,
634 class OutputIteratorInternalFacets>
635 Triple<OutputIteratorBoundaryFacets, OutputIteratorCells,
636 OutputIteratorInternalFacets>
637 find_conflicts(const Point &p, Cell_handle c,
638 OutputIteratorBoundaryFacets bfit, OutputIteratorCells cit,
639 OutputIteratorInternalFacets ifit) const;
640
641 /// Returns the vertices on the boundary of the conflict hole.
642 template <class OutputIterator>
643 OutputIterator vertices_in_conflict(const Point&p, Cell_handle c,
644 OutputIterator res) const;
645
646 bool is_Gabriel(const Cell_handle c, int i) const;
647 bool is_Gabriel(const Cell_handle c, int i, int j) const;
is_Gabriel(const Facet & f)648 bool is_Gabriel(const Facet& f)const {
649 return is_Gabriel(f.first, f.second);
650 }
is_Gabriel(const Edge & e)651 bool is_Gabriel(const Edge& e) const {
652 return is_Gabriel(e.first, e.second, e.third);
653 }
654
655 private:
656 /** @name Voronoi diagram helpers */
is_canonical(const Periodic_segment & ps)657 bool is_canonical(const Periodic_segment &ps) const
658 {
659 if(number_of_sheets() == make_array(1,1,1)) return true;
660 Offset o0 = ps.at(0).second;
661 Offset o1 = ps.at(1).second;
662 Offset cumm_off((std::min)(o0.x(),o1.x()),(std::min)(o0.y(),o1.y()),
663 (std::min)(o0.z(),o1.z()));
664 return (cumm_off == Offset(0,0,0));
665 }
666
667 public:
668 /** @name Geometric access functions */
669
point(const Periodic_point & pp)670 Point point(const Periodic_point& pp) const
671 {
672 return point(pp, geom_traits().construct_point_3_object());
673 }
674
675 // The following functions return the "real" position in space (unrestrained
676 // to the fundamental domain) of the vertices v and c->vertex(idx),
677 // respectively
678
point(Vertex_handle v)679 Point point(Vertex_handle v) const
680 {
681 return point(v, geom_traits().construct_point_3_object());
682 }
683
point(Cell_handle c,int idx)684 Point point(Cell_handle c, int idx) const
685 {
686 return point(c, idx, geom_traits().construct_point_3_object());
687 }
688
689 // end of geometric functions
690
periodic_circumcenter(Cell_handle c)691 Periodic_point periodic_circumcenter(Cell_handle c) const {
692 return Base::periodic_circumcenter(c, geom_traits().construct_circumcenter_3_object());
693 }
694
695 public:
696 /** @name Voronoi diagram */
697 // cell dual
dual(Cell_handle c)698 Point dual(Cell_handle c) const {
699 return Base::construct_point(periodic_circumcenter(c).first);
700 }
701
canonical_dual(Cell_handle c)702 Point canonical_dual(Cell_handle c) const {
703 return point(periodic_circumcenter(c));
704 }
705
706 // facet dual
canonical_dual_segment(Cell_handle c,int i,Periodic_segment & ps)707 bool canonical_dual_segment(Cell_handle c, int i, Periodic_segment& ps) const {
708 return Base::canonical_dual_segment(c, i, ps, geom_traits().construct_circumcenter_3_object());
709 }
710
dual(Cell_handle c,int i)711 Periodic_segment dual(Cell_handle c, int i) const
712 {
713 Periodic_segment ps;
714 canonical_dual_segment(c,i,ps);
715 return ps;
716 }
717
dual(const Facet & f)718 Periodic_segment dual(const Facet & f) const {
719 return dual( f.first, f.second );
720 }
721
722 // edge dual
723 template <class OutputIterator>
dual(Cell_handle c,int i,int j,OutputIterator points)724 OutputIterator dual(Cell_handle c, int i, int j, OutputIterator points) const {
725 Base::dual(c, i, j, points, geom_traits().construct_circumcenter_3_object());
726 return points;
727 }
728
729 template <class OutputIterator>
dual(const Edge & e,OutputIterator points)730 OutputIterator dual(const Edge & e, OutputIterator points) const {
731 return dual(e.first, e.second, e.third, points);
732 }
733
734 // vertex dual
735 template <class OutputIterator>
dual(Vertex_handle v,OutputIterator points)736 OutputIterator dual(Vertex_handle v, OutputIterator points) const {
737 Base::dual(v, points, geom_traits().construct_circumcenter_3_object());
738 return points;
739 }
740
741 template <class Stream>
draw_dual(Stream & os)742 Stream& draw_dual(Stream& os) const {
743 return Base::draw_dual(os, geom_traits().construct_circumcenter_3_object());
744 }
745
746 /// Volume computations
dual_volume(Vertex_handle v)747 FT dual_volume(Vertex_handle v) const {
748 return Base::dual_volume(v, geom_traits().construct_circumcenter_3_object());
749 }
750
751 /// Centroid computations
dual_centroid(Vertex_handle v)752 Point dual_centroid(Vertex_handle v) const {
753 return Base::dual_centroid(v, geom_traits().construct_circumcenter_3_object());
754 }
755
756 /** @name Checking */
757 bool is_valid(bool verbose = false, int level = 0) const;
758 bool is_valid(Cell_handle c, bool verbose = false, int level = 0) const;
759
760 protected:
761 // Protected, because inheritors(e.g. periodic triangulation for meshing)
762 // of the class Periodic_3_Delaunay_triangulation_3 use this class
763 class Conflict_tester;
764 private:
765 class Point_hider;
766
767 #ifndef CGAL_CFG_OUTOFLINE_TEMPLATE_MEMBER_DEFINITION_BUG
768 template <class TriangulationR3> struct Vertex_remover;
769 #else
770 template <class TriangulationR3>
771 struct Vertex_remover
772 {
773 typedef TriangulationR3 Triangulation_R3;
774
775 typedef typename std::vector<Point>::iterator Hidden_points_iterator;
776
777 typedef Triple < Vertex_handle, Vertex_handle, Vertex_handle > Vertex_triple;
778
779 typedef typename Triangulation_R3::Triangulation_data_structure TDSE;
780 typedef typename Triangulation_R3::Cell_handle CellE_handle;
781 typedef typename Triangulation_R3::Vertex_handle VertexE_handle;
782 typedef typename Triangulation_R3::Facet FacetE;
783 typedef typename Triangulation_R3::Finite_cells_iterator Finite_cellsE_iterator;
784
785 typedef Triple< VertexE_handle, VertexE_handle, VertexE_handle >
786 VertexE_triple;
787
788 typedef std::map<Vertex_triple,Facet> Vertex_triple_Facet_map;
789 typedef std::map<Vertex_triple, FacetE> Vertex_triple_FacetE_map;
790 typedef typename Vertex_triple_FacetE_map::iterator
791 Vertex_triple_FacetE_map_it;
792
Vertex_removerVertex_remover793 Vertex_remover(const Self *t, Triangulation_R3 &tmp_) : _t(t),tmp(tmp_) {}
794
795 const Self *_t;
796 Triangulation_R3 &tmp;
797
add_hidden_pointsVertex_remover798 void add_hidden_points(Cell_handle) {
799 std::copy (hidden_points_begin(), hidden_points_end(),
800 std::back_inserter(hidden));
801 }
802
hidden_points_beginVertex_remover803 Hidden_points_iterator hidden_points_begin() {
804 return hidden.begin();
805 }
hidden_points_endVertex_remover806 Hidden_points_iterator hidden_points_end() {
807 return hidden.end();
808 }
809 //private:
810 // The removal of v may un-hide some points,
811 // Space functions output them.
812 std::vector<Point> hidden;
813 };
814 #endif //CGAL_CFG_OUTOFLINE_TEMPLATE_MEMBER_DEFINITION_BUG
815 };
816
817 template < class GT, class Tds >
818 typename Periodic_3_Delaunay_triangulation_3<GT,Tds>::Vertex_handle
nearest_vertex(const Point & p,Cell_handle start)819 Periodic_3_Delaunay_triangulation_3<GT,Tds>::nearest_vertex(const Point& p,
820 Cell_handle start) const
821 {
822 if(number_of_vertices() == 0)
823 return Vertex_handle();
824
825 Locate_type lt;
826 int li, lj;
827 Offset query_offset;
828 Cell_handle c = locate(p, query_offset, lt, li, lj, start);
829
830 if(lt == Base::VERTEX)
831 return c->vertex(li);
832
833 // Take the opposite because periodic_locate() returns the offset such that
834 // cell + offset contains 'p' but here we need to move 'p'
835 query_offset = this->combine_offsets(Offset(), -query_offset);
836
837 // - start with the closest vertex from the located cell.
838 // - repeatedly take the nearest of its incident vertices if any
839 // - if not, we're done.
840 Vertex_handle nearest = nearest_vertex_in_cell(c, p, query_offset);
841 Offset offset_of_nearest = get_min_dist_offset(p, query_offset, nearest);
842
843 std::vector<Vertex_handle> vs;
844 vs.reserve(32);
845 while(true)
846 {
847 Vertex_handle tmp = nearest;
848 adjacent_vertices(nearest, std::back_inserter(vs));
849 for(typename std::vector<Vertex_handle>::const_iterator
850 vsit = vs.begin(); vsit != vs.end(); ++vsit)
851 {
852 // Can happen in 27-sheeted triangulations composed of few points
853 if((*vsit)->point() == nearest->point())
854 continue;
855
856 const Offset min_dist_offset = get_min_dist_offset(p, query_offset, *vsit);
857 if(compare_distance(p, (*vsit)->point(), tmp->point(),
858 query_offset, min_dist_offset, offset_of_nearest) == SMALLER)
859 {
860 tmp = *vsit;
861 offset_of_nearest = min_dist_offset;
862 }
863 }
864
865 if(tmp == nearest)
866 break;
867
868 vs.clear();
869 nearest = tmp;
870 }
871
872 return get_original_vertex(nearest);
873 }
874
875 // To use the function below, the offset 'o' must be appropriately chosen
876 // because we then only consider positive offsets from 'vh'. See example
877 // of use in nearest_power_vertex()
878 template < class GT, class Tds >
879 typename Periodic_3_Delaunay_triangulation_3<GT,Tds>::Offset
get_min_dist_offset(const Point & p,const Offset & o,const Vertex_handle vh)880 Periodic_3_Delaunay_triangulation_3<GT,Tds>::get_min_dist_offset(
881 const Point& p, const Offset& o, const Vertex_handle vh) const
882 {
883 Offset mdo = get_offset(vh);
884 Offset min = combine_offsets(mdo, Offset(0, 0, 0));
885
886 for(int i=0; i<=1; ++i) {
887 for(int j=0; j<=1; ++j) {
888 for(int k=0; k<=1; ++k)
889 {
890 if(i==0 && j==0 && k==0)
891 continue;
892
893 Offset loc_off = combine_offsets(mdo, Offset(i, j, k));
894 if(compare_distance(p, vh->point(), vh->point(), o, min, loc_off) == LARGER)
895 min = loc_off;
896 }
897 }
898 }
899
900 return min;
901 }
902
903 /// Returns the finite vertex of the cell c which is the closest to p.
904 template < class GT, class Tds >
905 typename Periodic_3_Delaunay_triangulation_3<GT,Tds>::Vertex_handle
nearest_vertex_in_cell(const Cell_handle & c,const Point & p,const Offset & o)906 Periodic_3_Delaunay_triangulation_3<GT,Tds>::nearest_vertex_in_cell(
907 const Cell_handle& c, const Point& p, const Offset& o) const
908 {
909 CGAL_triangulation_precondition(number_of_vertices() != 0);
910 Vertex_handle nearest = c->vertex(0);
911 for(int i=1; i<4; i++) {
912 nearest = (compare_distance(p,nearest->point(),c->vertex(i)->point(),
913 o, get_offset(c,c->index(nearest)),
914 get_offset(c,i)) == SMALLER) ?
915 nearest : c->vertex(i);
916 }
917 return nearest;
918 }
919
920 // ############################################################################
921
922 // TODO: reintroduce the commented lines.
923 template < class Gt, class Tds >
924 typename Periodic_3_Delaunay_triangulation_3<Gt,Tds>::Vertex_handle
925 Periodic_3_Delaunay_triangulation_3<Gt,Tds>::
move_point(Vertex_handle v,const Point & p)926 move_point(Vertex_handle v, const Point& p)
927 {
928 CGAL_triangulation_expensive_precondition(is_vertex(v));
929 // Remember an incident vertex to restart
930 // the point location after the removal.
931 // Cell_handle c = v->cell();
932 //Vertex_handle old_neighbor = c->vertex(c->index(v) == 0 ? 1 : 0);
933 // CGAL_triangulation_assertion(old_neighbor != v);
934
935 remove(v);
936
937 if(number_of_vertices() == 0)
938 return insert(p);
939 return insert(p);//, old_neighbor->cell());
940 }
941
942 template < class Gt, class Tds >
remove(Vertex_handle v)943 void Periodic_3_Delaunay_triangulation_3<Gt,Tds>::remove(Vertex_handle v)
944 {
945 typedef CGAL::Periodic_3_Delaunay_triangulation_remove_traits_3<Gt> P3removeT;
946 typedef CGAL::Delaunay_triangulation_3< P3removeT >
947 Euclidean_triangulation;
948 typedef Vertex_remover< Euclidean_triangulation > Remover;
949 P3removeT remove_traits(domain());
950 Euclidean_triangulation tmp(remove_traits);
951 Remover remover(this, tmp);
952 Conflict_tester ct(this);
953 Cover_manager cover_manager(*this);
954
955 Base::remove(v, remover, ct, cover_manager);
956 CGAL_triangulation_expensive_assertion(is_valid());
957 }
958
959 // Undocumented function that tries to remove 'v' but only does so if removal
960 // does not make the triangulation become 27-sheeted. Useful for P3M3.
961 // \pre the triangulation is 1-sheeted
962 template < class Gt, class Tds >
963 bool
964 Periodic_3_Delaunay_triangulation_3<Gt,Tds>::
remove_if_no_cover_change(Vertex_handle v)965 remove_if_no_cover_change(Vertex_handle v)
966 {
967 CGAL_triangulation_precondition(this->is_1_cover());
968
969 // Since we are in a 1-sheet configuration, we can call directly periodic_remove()
970 // and don't need the conflict tester. The rest is copied from above.
971
972 typedef CGAL::Periodic_3_Delaunay_triangulation_remove_traits_3< Gt > P3removeT;
973 typedef CGAL::Delaunay_triangulation_3< P3removeT > Euclidean_triangulation;
974 typedef Vertex_remover< Euclidean_triangulation > Remover;
975
976 P3removeT remove_traits(domain());
977 Euclidean_triangulation tmp(remove_traits);
978 Remover remover(this, tmp);
979 Cover_manager cover_manager(*this);
980
981 if(!Base::periodic_remove(v, remover, cover_manager, true /*abort if cover change*/))
982 {
983 // std::cerr << "Warning: removing " << &*v << " (" << v->point() << ") would change cover" << std::endl;
984 // std::cerr << "Aborted removal." << std::endl;
985 return false; // removing would cause a cover change
986 }
987
988 CGAL_triangulation_expensive_postcondition(is_valid());
989 CGAL_triangulation_postcondition(this->is_1_cover());
990 return true; // successfully removed the vertex
991 }
992
993 template < class Gt, class Tds >
994 template <class OutputIteratorBoundaryFacets, class OutputIteratorCells,
995 class OutputIteratorInternalFacets>
996 Triple<OutputIteratorBoundaryFacets, OutputIteratorCells,
997 OutputIteratorInternalFacets>
find_conflicts(const Point & p,Cell_handle c,OutputIteratorBoundaryFacets bfit,OutputIteratorCells cit,OutputIteratorInternalFacets ifit)998 Periodic_3_Delaunay_triangulation_3<Gt,Tds>::find_conflicts(
999 const Point& p, Cell_handle c, OutputIteratorBoundaryFacets bfit,
1000 OutputIteratorCells cit, OutputIteratorInternalFacets ifit) const
1001 {
1002 CGAL_triangulation_precondition(number_of_vertices() != 0);
1003
1004 std::vector<Facet> facets;
1005 facets.reserve(64);
1006 std::vector<Cell_handle> cells;
1007 cells.reserve(32);
1008
1009 Conflict_tester tester(p, this);
1010 Triple<typename std::back_insert_iterator<std::vector<Facet> >,
1011 typename std::back_insert_iterator<std::vector<Cell_handle> >,
1012 OutputIteratorInternalFacets> tit = Base::find_conflicts(c, tester,
1013 make_triple(std::back_inserter(facets),
1014 std::back_inserter(cells), ifit));
1015 ifit = tit.third;
1016
1017 // Reset the conflict flag on the boundary.
1018 for(typename std::vector<Facet>::iterator fit=facets.begin();
1019 fit != facets.end(); ++fit) {
1020 fit->first->neighbor(fit->second)->tds_data().clear();
1021 *bfit++ = *fit;
1022 }
1023
1024 // Reset the conflict flag in the conflict cells.
1025 for(typename std::vector<Cell_handle>::iterator ccit=cells.begin();
1026 ccit != cells.end(); ++ccit) {
1027 (*ccit)->tds_data().clear();
1028 *cit++ = *ccit;
1029 }
1030
1031 for(typename std::vector<Vertex_handle>::iterator
1032 voit = this->v_offsets.begin();
1033 voit != this->v_offsets.end(); ++voit) {
1034 (*voit)->clear_offset();
1035 }
1036 this->v_offsets.clear();
1037
1038 return make_triple(bfit, cit, ifit);
1039 }
1040
1041 template < class Gt, class Tds >
1042 template <class OutputIterator>
1043 OutputIterator
vertices_in_conflict(const Point & p,Cell_handle c,OutputIterator res)1044 Periodic_3_Delaunay_triangulation_3<Gt,Tds>::vertices_in_conflict(
1045 const Point& p, Cell_handle c, OutputIterator res) const
1046 {
1047 if(number_of_vertices() == 0) return res;
1048
1049 // Get the facets on the boundary of the hole.
1050 std::vector<Facet> facets;
1051 find_conflicts(p, c, std::back_inserter(facets), Emptyset_iterator());
1052
1053 // Then extract uniquely the vertices.
1054 std::set<Vertex_handle> vertices;
1055 for(typename std::vector<Facet>::const_iterator i = facets.begin();
1056 i != facets.end(); ++i) {
1057 vertices.insert(i->first->vertex((i->second+1)&3));
1058 vertices.insert(i->first->vertex((i->second+2)&3));
1059 vertices.insert(i->first->vertex((i->second+3)&3));
1060 }
1061
1062 return std::copy(vertices.begin(), vertices.end(), res);
1063 }
1064
1065 template < class Gt, class Tds >
1066 Bounded_side Periodic_3_Delaunay_triangulation_3<Gt,Tds>::
_side_of_sphere(const Cell_handle & c,const Point & q,const Offset & offset,bool perturb)1067 _side_of_sphere(const Cell_handle& c, const Point& q,
1068 const Offset& offset, bool perturb ) const
1069 {
1070 Point p0 = c->vertex(0)->point(),
1071 p1 = c->vertex(1)->point(),
1072 p2 = c->vertex(2)->point(),
1073 p3 = c->vertex(3)->point();
1074 Offset o0 = this->get_offset(c,0),
1075 o1 = this->get_offset(c,1),
1076 o2 = this->get_offset(c,2),
1077 o3 = this->get_offset(c,3),
1078 oq = offset;
1079
1080 Oriented_side os = ON_NEGATIVE_SIDE;
1081 os= side_of_oriented_sphere(p0, p1, p2, p3, q, o0, o1, o2, o3, oq);
1082
1083 if(os != ON_ORIENTED_BOUNDARY || !perturb)
1084 return enum_cast<Bounded_side>(os);
1085
1086 //We are now in a degenerate case => we do a symbolic perturbation.
1087 // We sort the points lexicographically.
1088 Periodic_point pts[5] = {std::make_pair(p0,o0), std::make_pair(p1,o1),
1089 std::make_pair(p2,o2), std::make_pair(p3,o3),
1090 std::make_pair(q,oq)};
1091 const Periodic_point *points[5] = {&pts[0],&pts[1],&pts[2],&pts[3],&pts[4]};
1092
1093 std::sort(points, points+5, typename Base::Perturbation_order(this));
1094
1095 // We successively look whether the leading monomial, then 2nd monomial
1096 // of the determinant has non null coefficient.
1097 // 2 iterations are enough (cf paper)
1098 for(int i=4; i>2; --i) {
1099 if(points[i] == &pts[4]) {
1100 CGAL_triangulation_assertion(orientation(p0, p1, p2, p3, o0, o1, o2, o3)
1101 == POSITIVE);
1102 // since p0 p1 p2 p3 are non coplanar and positively oriented
1103 return ON_UNBOUNDED_SIDE;
1104 }
1105 Orientation o;
1106 if(points[i] == &pts[3] &&
1107 (o = orientation(p0, p1, p2, q, o0, o1, o2, oq)) != COPLANAR ) {
1108 return enum_cast<Bounded_side>(o);
1109 }
1110 if(points[i] == &pts[2] &&
1111 (o = orientation(p0, p1, q, p3, o0, o1, oq, o3)) != COPLANAR ) {
1112 return enum_cast<Bounded_side>(o);
1113 }
1114 if(points[i] == &pts[1] &&
1115 (o = orientation(p0, q, p2, p3, o0, oq, o2, o3)) != COPLANAR ) {
1116 return enum_cast<Bounded_side>(o);
1117 }
1118 if(points[i] == &pts[0] &&
1119 (o = orientation(q, p1, p2 ,p3, oq, o1, o2, o3)) != COPLANAR ) {
1120 return enum_cast<Bounded_side>(o);
1121 }
1122 }
1123
1124 CGAL_triangulation_assertion(false);
1125 return ON_UNBOUNDED_SIDE;
1126 }
1127
1128 template < class Gt, class Tds >
1129 bool Periodic_3_Delaunay_triangulation_3<Gt,Tds>::
is_Gabriel(const Cell_handle c,int i)1130 is_Gabriel(const Cell_handle c, int i) const
1131 {
1132 CGAL_triangulation_precondition(number_of_vertices() != 0);
1133 typename Geom_traits::Side_of_bounded_sphere_3
1134 side_of_bounded_sphere =
1135 geom_traits().side_of_bounded_sphere_3_object();
1136
1137 if(side_of_bounded_sphere (
1138 c->vertex(vertex_triple_index(i,0))->point(),
1139 c->vertex(vertex_triple_index(i,1))->point(),
1140 c->vertex(vertex_triple_index(i,2))->point(),
1141 c->vertex(i)->point(),
1142 get_offset(c,vertex_triple_index(i,0)),
1143 get_offset(c,vertex_triple_index(i,1)),
1144 get_offset(c,vertex_triple_index(i,2)),
1145 get_offset(c,i) ) == ON_BOUNDED_SIDE )
1146 return false;
1147
1148 Cell_handle neighbor = c->neighbor(i);
1149 int in = neighbor->index(c);
1150
1151 if(side_of_bounded_sphere(
1152 neighbor->vertex(vertex_triple_index(in,0))->point(),
1153 neighbor->vertex(vertex_triple_index(in,1))->point(),
1154 neighbor->vertex(vertex_triple_index(in,2))->point(),
1155 neighbor->vertex(in)->point(),
1156 get_offset(neighbor,vertex_triple_index(in,0)),
1157 get_offset(neighbor,vertex_triple_index(in,1)),
1158 get_offset(neighbor,vertex_triple_index(in,2)),
1159 get_offset(neighbor, in) ) == ON_BOUNDED_SIDE )
1160 return false;
1161
1162 return true;
1163 }
1164
1165 template < class Gt, class Tds >
1166 bool Periodic_3_Delaunay_triangulation_3<Gt,Tds>::
is_Gabriel(const Cell_handle c,int i,int j)1167 is_Gabriel(const Cell_handle c, int i, int j) const
1168 {
1169 typename Geom_traits::Side_of_bounded_sphere_3
1170 side_of_bounded_sphere =
1171 geom_traits().side_of_bounded_sphere_3_object();
1172
1173 Facet_circulator fcirc = incident_facets(c,i,j), fdone(fcirc);
1174 Vertex_handle v1 = c->vertex(i);
1175 Vertex_handle v2 = c->vertex(j);
1176 do {
1177 // test whether the vertex of cc opposite to *fcirc
1178 // is inside the sphere defined by the edge e = (s, i,j)
1179 // It is necessary to fetch the offsets from the current cell.
1180 Cell_handle cc = fcirc->first;
1181 int i1 = cc->index(v1);
1182 int i2 = cc->index(v2);
1183 int i3 = fcirc->second;
1184 Offset off1 = get_offset(cc, i1);
1185 Offset off2 = get_offset(cc, i2);
1186 Offset off3 = get_offset(cc, i3);
1187 if(side_of_bounded_sphere(
1188 v1->point(), v2->point(), cc->vertex(fcirc->second)->point(),
1189 off1, off2, off3) == ON_BOUNDED_SIDE ) return false;
1190 } while(++fcirc != fdone);
1191 return true;
1192 }
1193
1194 template < class Gt, class Tds >
1195 bool
1196 Periodic_3_Delaunay_triangulation_3<Gt,Tds>::
is_valid(bool verbose,int level)1197 is_valid(bool verbose, int level) const
1198 {
1199 if(!Base::is_valid(verbose, level)) {
1200 if(verbose)
1201 std::cerr << "Delaunay: invalid base" << std::endl;
1202 return false;
1203 }
1204
1205 Conflict_tester tester(this);
1206 if(!is_valid_conflict(tester, verbose, level)) {
1207 if(verbose)
1208 std::cerr << "Delaunay: conflict problems" << std::endl;
1209 return false;
1210 }
1211
1212 if(verbose)
1213 std::cerr << "Delaunay valid triangulation" << std::endl;
1214 return true;
1215 }
1216
1217 template < class GT, class TDS >
1218 bool
1219 Periodic_3_Delaunay_triangulation_3<GT,TDS>::
is_valid(Cell_handle ch,bool verbose,int level)1220 is_valid(Cell_handle ch, bool verbose, int level) const
1221 {
1222 bool error = false;
1223 if(!Base::is_valid(ch, verbose, level)) {
1224 error = true;
1225 if(verbose) {
1226 std::cerr << "geometrically invalid cell" << std::endl;
1227 for(int i=0; i<4; i++)
1228 std::cerr << ch->vertex(i)->point() << ", ";
1229 std::cerr << std::endl;
1230 }
1231 }
1232
1233 for(Vertex_iterator vit = vertices_begin(); vit != vertices_end(); ++ vit) {
1234 for(int i=-1; i<=1; i++) {
1235 for(int j=-1; j<=1; j++) {
1236 for(int k=-1; k<=1; k++) {
1237 if(periodic_point(ch,0) == std::make_pair(periodic_point(vit).first,
1238 periodic_point(vit).second+Offset(i,j,k))
1239 || periodic_point(ch,1) == std::make_pair(periodic_point(vit).first,
1240 periodic_point(vit).second+Offset(i,j,k))
1241 || periodic_point(ch,2) == std::make_pair(periodic_point(vit).first,
1242 periodic_point(vit).second+Offset(i,j,k))
1243 || periodic_point(ch,3) == std::make_pair(periodic_point(vit).first,
1244 periodic_point(vit).second+Offset(i,j,k)) )
1245 continue;
1246 if(_side_of_sphere(ch, periodic_point(vit).first,
1247 periodic_point(vit).second+Offset(i,j,k),true)
1248 != ON_UNBOUNDED_SIDE) {
1249 error = true;
1250 if(verbose) {
1251 std::cerr << "Delaunay invalid cell" << std::endl;
1252 for(int i=0; i<4; i++) {
1253 Periodic_point pp = periodic_point(ch,i);
1254 std::cerr <<"("<<pp.first <<","<<pp.second<< "), ";
1255 }
1256 std::cerr << std::endl;
1257 }
1258 }
1259 }
1260 }
1261 }
1262 }
1263 return !error;
1264 }
1265
1266 template < class GT, class Tds >
1267 class Periodic_3_Delaunay_triangulation_3<GT,Tds>::Conflict_tester
1268 {
1269 // stores a pointer to the triangulation,
1270 // a point, and an offset
1271 const Self *t;
1272 Point p;
1273 // stores the offset of a point in 27-cover
1274 mutable Offset o;
1275
1276 public:
1277 /// Constructor
Conflict_tester(const Self * _t)1278 Conflict_tester(const Self *_t) : t(_t), p(Point()) {}
Conflict_tester(const Point & pt,const Self * _t)1279 Conflict_tester(const Point &pt, const Self *_t) : t(_t), p(pt) { }
1280
1281 /** The functor
1282 *
1283 * gives true if the circumcircle of c contains p
1284 */
operator()1285 bool operator()(const Cell_handle c, const Offset &off) const {
1286 return (t->_side_of_sphere(c, p, t->combine_offsets(o, off), true)
1287 == ON_BOUNDED_SIDE);
1288 }
1289
operator()1290 bool operator()(const Cell_handle c, const Point& pt,
1291 const Offset &off) const {
1292 return (t->_side_of_sphere(c, pt, o + off, true) == ON_BOUNDED_SIDE);
1293 }
1294
compare_weight(Point,Point)1295 int compare_weight(Point, Point) const
1296 {
1297 return 0;
1298 }
1299
test_initial_cell(Cell_handle c,const Offset & off)1300 bool test_initial_cell(Cell_handle c, const Offset &off) const
1301 {
1302 if(!(operator()(c, off)))
1303 CGAL_triangulation_assertion(false);
1304 return true;
1305 }
1306
set_point(const Point & _p)1307 void set_point(const Point &_p) {
1308 p = _p;
1309 }
1310
set_offset(const Offset & off)1311 void set_offset(const Offset &off) const {
1312 o = off;
1313 }
1314
get_offset()1315 const Offset &get_offset() const {
1316 return o;
1317 }
1318
point()1319 const Point &point() const {
1320 return p;
1321 }
1322
1323 };
1324
1325 template < class GT, class Tds>
1326 class Periodic_3_Delaunay_triangulation_3<GT,Tds>::Point_hider
1327 {
1328 public:
Point_hider()1329 Point_hider() { }
1330
set_original_cube(bool)1331 void set_original_cube (bool) const { }
1332
1333 template <class InputIterator>
set_vertices(InputIterator,InputIterator)1334 inline void set_vertices(InputIterator, InputIterator) const { }
reinsert_vertices(Vertex_handle)1335 inline void reinsert_vertices(Vertex_handle ) { }
replace_vertex(Cell_handle c,int index,const Point &)1336 inline Vertex_handle replace_vertex(Cell_handle c, int index, const Point &) {
1337 return c->vertex(index);
1338 }
hide_point(Cell_handle,const Point &)1339 inline void hide_point(Cell_handle, const Point &) { }
1340
hide(Point &,Cell_handle)1341 inline void hide(Point &, Cell_handle ) const {
1342 CGAL_triangulation_assertion(false);
1343 }
1344
do_hide(const Point &,Cell_handle)1345 inline void do_hide(const Point &, Cell_handle ) const {
1346 CGAL_triangulation_assertion(false);
1347 }
1348 template < class Tester >
replace_vertex(const Point &,Vertex_handle,const Tester &)1349 inline bool replace_vertex(const Point &, Vertex_handle ,
1350 const Tester &) const {
1351 return true;
1352 }
1353 template <class Conflict_tester>
hide_points(Vertex_handle,const Conflict_tester &)1354 inline void hide_points(Vertex_handle, const Conflict_tester &) {
1355 // No points to hide in the Delaunay triangulation.
1356 }
1357 };
1358
1359 #ifndef CGAL_CFG_OUTOFLINE_TEMPLATE_MEMBER_DEFINITION_BUG
1360 template <class GT, class Tds>
1361 template <class TriangulationR3>
1362 struct Periodic_3_Delaunay_triangulation_3<GT,Tds>::Vertex_remover
1363 {
1364 typedef TriangulationR3 Triangulation_R3;
1365
1366 typedef typename std::vector<Point>::iterator Hidden_points_iterator;
1367
1368 typedef Triple < Vertex_handle, Vertex_handle, Vertex_handle > Vertex_triple;
1369
1370 typedef typename Triangulation_R3::Triangulation_data_structure TDSE;
1371 typedef typename Triangulation_R3::Cell_handle CellE_handle;
1372 typedef typename Triangulation_R3::Vertex_handle VertexE_handle;
1373 typedef typename Triangulation_R3::Facet FacetE;
1374 typedef typename Triangulation_R3::Finite_cells_iterator Finite_cellsE_iterator;
1375
1376 typedef Triple< VertexE_handle, VertexE_handle, VertexE_handle > VertexE_triple;
1377
1378 typedef std::map<Vertex_triple, Facet> Vertex_triple_Facet_map;
1379 typedef std::map<Vertex_triple, FacetE> Vertex_triple_FacetE_map;
1380 typedef typename Vertex_triple_FacetE_map::iterator Vertex_triple_FacetE_map_it;
1381
1382 Vertex_remover(const Self *t, Triangulation_R3 &tmp_) : _t(t),tmp(tmp_) {}
1383
1384 const Self *_t;
1385 Triangulation_R3 &tmp;
1386
1387 void add_hidden_points(Cell_handle) {
1388 std::copy(hidden_points_begin(), hidden_points_end(),
1389 std::back_inserter(hidden));
1390 }
1391
1392 Hidden_points_iterator hidden_points_begin() {
1393 return hidden.begin();
1394 }
1395 Hidden_points_iterator hidden_points_end() {
1396 return hidden.end();
1397 }
1398 //private:
1399 // The removal of v may un-hide some points,
1400 // Space functions output them.
1401 std::vector<Point> hidden;
1402 };
1403 #endif //CGAL_CFG_OUTOFLINE_TEMPLATE_MEMBER_DEFINITION_BUG
1404
1405 template < class GT, class TDS >
1406 inline bool
1407 Periodic_3_Delaunay_triangulation_3<GT,TDS>::
1408 is_extensible_triangulation_in_1_sheet_h1() const
1409 {
1410 if(!is_1_cover()) {
1411 if(too_long_edge_counter == 0) return true;
1412 else return false;
1413 } else {
1414 typename Geometric_traits::FT longest_edge_squared_length(0);
1415 Segment s;
1416 for(Periodic_segment_iterator psit = this->periodic_segments_begin(Base::UNIQUE);
1417 psit != this->periodic_segments_end(Base::UNIQUE); ++psit) {
1418 s = this->construct_segment(*psit);
1419 longest_edge_squared_length = (std::max)(longest_edge_squared_length,
1420 s.squared_length());
1421 }
1422 return (longest_edge_squared_length < edge_length_threshold);
1423 }
1424 }
1425
1426 template < class GT, class TDS >
1427 inline bool
1428 Periodic_3_Delaunay_triangulation_3<GT,TDS>::
1429 is_extensible_triangulation_in_1_sheet_h2() const
1430 {
1431 typedef typename Geometric_traits::Construct_circumcenter_3
1432 Construct_circumcenter;
1433 typedef typename Geometric_traits::FT FT;
1434 Construct_circumcenter construct_circumcenter
1435 = geom_traits().construct_circumcenter_3_object();
1436 for(Periodic_tetrahedron_iterator tit = this->periodic_tetrahedra_begin(Base::UNIQUE);
1437 tit != this->periodic_tetrahedra_end(Base::UNIQUE); ++tit) {
1438 Point cc = construct_circumcenter(
1439 tit->at(0).first, tit->at(1).first,
1440 tit->at(2).first, tit->at(3).first,
1441 tit->at(0).second, tit->at(1).second,
1442 tit->at(2).second, tit->at(3).second);
1443
1444 if( !(FT(16)*squared_distance(cc,point(tit->at(0)))
1445 < (domain().xmax()-domain().xmin())*(domain().xmax()-domain().xmin())) )
1446 return false;
1447 }
1448 return true;
1449 }
1450
1451 template < class GT, class TDS >
1452 std::istream &
1453 operator>> (std::istream& is, Periodic_3_Delaunay_triangulation_3<GT,TDS> &tr)
1454 {
1455 typedef Periodic_3_Delaunay_triangulation_3<GT,TDS> P3DT3;
1456 typedef typename P3DT3::Base Base;
1457 typedef typename GT::FT FT;
1458
1459 is >> static_cast<Base&>(tr);
1460
1461 tr.edge_length_threshold = FT(0.166) * (tr.domain().xmax()-tr.domain().xmin())
1462 * (tr.domain().xmax()-tr.domain().xmin());
1463
1464 tr.compute_too_long_edges();
1465
1466 CGAL_triangulation_expensive_assertion( tr.is_valid() );
1467 return is;
1468 }
1469
1470 } // namespace CGAL
1471
1472 #endif // CGAL_PERIODIC_3_DELAUNAY_TRIANGULATION_3_H
1473