1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941
|
// Copyright (c) 2006 Tel-Aviv University (Israel).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org).
// You can redistribute it and/or modify it under the terms of the GNU
// General Public License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any later version.
//
// Licensees holding a valid commercial license may use this file in
// accordance with the commercial license agreement provided with the software.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
//
// $URL: svn+ssh://scm.gforge.inria.fr/svn/cgal/branches/next/Minkowski_sum_2/include/CGAL/Small_side_angle_bisector_decomposition_2.h $
// $Id: Small_side_angle_bisector_decomposition_2.h 67117 2012-01-13 18:14:48Z lrineau $
//
// Author(s) : Ron Wein <wein@post.tau.ac.il>
// (based on an old version by Eyal Flato)
#ifndef CGAL_SMALL_SIDE_ANGLE_BISECTOR_DECOMPOSITION_2_H
#define CGAL_SMALL_SIDE_ANGLE_BISECTOR_DECOMPOSITION_2_H
#include <CGAL/Polygon_2.h>
#include <vector>
#include <list>
namespace CGAL {
/*!
* \class
* Small-side angle-bisector decomposition strategy.
*/
template <class Kernel_,
class Container_ = std::vector<typename Kernel_::Point_2> >
class Small_side_angle_bisector_decomposition_2
{
public:
typedef Kernel_ Kernel;
typedef CGAL::Polygon_2<Kernel, Container_> Polygon_2;
typedef typename Kernel::Point_2 Point_2;
private:
typedef typename Kernel::Direction_2 Direction_2;
typedef typename Kernel::Segment_2 Segment_2;
typedef typename Polygon_2::Vertex_circulator Vertex_circulator;
// Kernel functors:
typedef typename Kernel::Equal_2 Equal_2;
typedef typename Kernel::Construct_translated_point_2 Translate_point_2;
typedef typename Kernel::Construct_vector_2 Construct_vector_2;
typedef typename Kernel::Construct_direction_2 Construct_direction_2;
typedef typename Kernel::Orientation_2 Compute_orientation_2;
typedef typename Kernel::Do_intersect_2 Do_intersect_2;
typedef typename Kernel::Counterclockwise_in_between_2 Ccw_in_between_2;
typedef std::list<unsigned int> Indices_list;
typedef typename Indices_list::const_iterator Indices_iterator;
// Point with additional infomaration.
struct Point_info_2
{
Point_2 point;
bool is_reflex;
unsigned int reflex_count;
Indices_list visible;
Indices_list non_visible;
// Default constructor.
Point_info_2 () :
is_reflex (false),
reflex_count (0),
visible (),
non_visible ()
{}
// Check if the given vertex is visible.
bool is_visible (unsigned int index) const
{
Indices_iterator it;
for (it = visible.begin(); it != visible.end(); ++it)
{
if (*it == index)
return (true);
}
return (false);
}
// Check if the given vertex is non-visible.
bool is_non_visible (unsigned int index) const
{
Indices_iterator it;
for (it = non_visible.begin(); it != non_visible.end(); ++it)
{
if (*it == index)
return (true);
}
return (false);
}
};
typedef std::vector<Point_info_2> Point_vector_2;
// Data members:
Equal_2 f_equal;
Translate_point_2 f_add;
Construct_vector_2 f_vector;
Construct_direction_2 f_direction;
Compute_orientation_2 f_orientation;
Do_intersect_2 f_do_intersect;
Ccw_in_between_2 f_ccw_in_between;
public:
/*! Default constructor. */
Small_side_angle_bisector_decomposition_2 ()
{
// Obtain kernel functors.
Kernel ker;
f_equal = ker.equal_2_object();
f_add = ker.construct_translated_point_2_object();
f_vector = ker.construct_vector_2_object();
f_direction = ker.construct_direction_2_object();
f_orientation = ker.orientation_2_object();
f_do_intersect = ker.do_intersect_2_object();
f_ccw_in_between = ker.counterclockwise_in_between_2_object();
}
/*!
* Decompose a simple polygon to convex sub-polygons.
* \param pgn The input polygon.
* \param oi An output iterator of convex polygons.
* \return A past-the-end iterator for the sub-polygons.
*/
template <class OutputIterator>
OutputIterator operator() (const Polygon_2& pgn,
OutputIterator oi) const
{
// Construct a point-info vector that represents the input polygon.
Point_vector_2 vec;
if (_construct_point_vector (pgn, vec))
{
// The input polygon is convex - just return it as is (we use the
// auxiliary function to make sure the returned polygon is oriented
// counterclockwise).
oi = _output_polygon (vec, oi);
return (oi);
}
// Prepare a queue of polygons, represented as point vectors, to decompose.
// We first try the small-side decomposition, and if we fail we turn to
// the normal angle-bisector decomposition.
std::list<Point_vector_2> ss_queue;
std::list<Point_vector_2> ab_queue;
unsigned int ind1, ind2;
Point_vector_2 vec1, vec2;
ind1 = ind2 = static_cast<unsigned int>(-1); // Pacify some compiler
ss_queue.push_back (vec);
// Use the small-side decomposition as long as possible.
while (! ss_queue.empty())
{
// Extract the first polygon from the queue.
vec = ss_queue.front();
ss_queue.pop_front();
// Try computing a minimal diagonal eliminating two reflex vertices.
if (_compute_min_diagonal (vec, ind1, ind2))
{
// We have found a minimal diagonal - use it to split the polygon.
_split_by_diagonal (vec, ind1, ind2,
false,
vec1, vec2);
// For either of the resulting sub-polygons: Report them if they are
// convex, otherwise decompose them recursively.
if (vec1[vec1.size() - 1].reflex_count == 0)
oi = _output_polygon (vec1, oi);
else
ss_queue.push_back (vec1);
if (vec2[vec2.size() - 1].reflex_count == 0)
oi = _output_polygon (vec2, oi);
else
ss_queue.push_back (vec2);
}
else
{
// We have failed to find a minimal diagonal eliminating two reflex
// vertices - use the simple angle bisector method for this polygon.
ab_queue.push_back (vec);
}
}
// Decompose the remaining polygons.
while (! ab_queue.empty())
{
// Extract the first polygon from the queue.
vec = ab_queue.front();
ab_queue.pop_front();
// Compute the best angle bisector and split the polygon accordingly.
_approximate_angle_bisector (vec, ind1, ind2);
_split_by_diagonal (vec, ind1, ind2,
true,
vec1, vec2);
// For either of the resulting sub-polygons: Report them if they are
// convex, otherwise decompose them recursively.
if (vec1[vec1.size() - 1].reflex_count == 0)
oi = _output_polygon (vec1, oi);
else
ab_queue.push_back (vec1);
if (vec2[vec2.size() - 1].reflex_count == 0)
oi = _output_polygon (vec2, oi);
else
ab_queue.push_back (vec2);
}
return (oi);
}
private:
/*! Return the succesive index of a 'point info' vector. */
inline unsigned int _vec_succ (const Point_vector_2& vec,
unsigned int i) const
{
return ((i + 1) % vec.size());
}
/*! Return the previous index of a 'point info' vector. */
inline unsigned int _vec_pred (const Point_vector_2& vec,
unsigned int i) const
{
if (i == 0)
return (vec.size() - 1);
return (i - 1);
}
/*!
* Reflect the point b around the point a.
* \return The result of: a + vec('a'-'b').
*/
Point_2 _opposite_from_vertex (const Point_2& a, const Point_2& b) const
{
return (f_add (a, f_vector(b, a)));
}
// The "reflex zone" of a vertex v is the slice created by continuing the
// edges incident to this vertex, from v to infinity. This enumeration
// describes the location of a point with respect to this zone.
enum Reflex_zone_position
{
LEFT_OF_ZONE = -1,
INSIDE_ZONE = 0,
RIGHT_OF_ZONE = 1,
ON_ZONE_BOUNDARY = 3,
OPPOSITE_OF_ZONE = 9
};
/*!
* Get the position of a query point with respect to the reflex zone of a
* given vertex.
* \param vec A vector defining counterclockwise-oriented polygon.
* \param v_ind The index of the vertex v.
* \param q_pt A query point.
* \return The location of the query point with respect to the zone.
*/
Reflex_zone_position _query_reflex_zone (const Point_vector_2& vec,
unsigned int v_ind,
const Point_2& q_pt) const
{
// Initialize q, the reflex vertex, and it previous and next vertices
// and incident edges.
const Point_2& v_pt = vec[v_ind].point;
const Point_2& pred_pt = vec[_vec_pred(vec, v_ind)].point;
const Point_2& succ_pt = vec[_vec_succ(vec, v_ind)].point;
Direction_2 pred_dir = f_direction (f_vector (v_pt, pred_pt));
Direction_2 succ_dir = f_direction (f_vector (v_pt, succ_pt));
Point_2 opp_pred_pt = _opposite_from_vertex (v_pt, pred_pt);
Point_2 opp_succ_pt = _opposite_from_vertex (v_pt, succ_pt);
Direction_2 opp_pred_dir = f_direction (f_vector (v_pt, opp_pred_pt));
Direction_2 opp_succ_dir = f_direction (f_vector (v_pt, opp_succ_pt));
Direction_2 q_dir = f_direction (f_vector (v_pt, q_pt));
if (f_ccw_in_between (q_dir, opp_pred_dir, opp_succ_dir))
{
// The point is contained between the continuation of the edges around v,
// so it is inside the reflex zone.
return (INSIDE_ZONE);
}
if (f_equal (q_dir, opp_pred_dir) || f_equal (q_dir, opp_succ_dir))
{
// The point lies on the boundary of the reflex zone.
return (ON_ZONE_BOUNDARY);
}
if (f_ccw_in_between (q_dir, opp_succ_dir, pred_dir))
{
// The point lies to the left of the reflex zone.
return (LEFT_OF_ZONE);
}
if (f_ccw_in_between (q_dir, succ_dir, opp_pred_dir))
{
// The point lies to the right of the reflex zone.
return (RIGHT_OF_ZONE);
}
// If we reached here, the query point lies on the opposite side of the
// reflex zone.
CGAL_assertion (f_ccw_in_between (q_dir, pred_dir, succ_dir) ||
f_equal (q_dir, pred_dir) || f_equal (q_dir, succ_dir));
return (OPPOSITE_OF_ZONE);
}
/*!
* Check whether a given vertex u is visible from a reflex vertex v.
* \param vec A vector defining counterclockwise-oriented polygon.
* \param v_ind The index of the reflex vertex v.
* \param u_ind The index of the vertex u.
* \return Whether the vertices are visible.
*/
bool _is_visible (Point_vector_2& vec,
unsigned int v_ind, unsigned int u_ind) const
{
CGAL_precondition (vec[v_ind].is_reflex);
// Check whether the visiblity status is already known.
if (vec[v_ind].is_visible (u_ind))
return (true);
if (vec[v_ind].is_non_visible (u_ind))
return (false);
// Check whether the diagonal (v_ind, u_ind) does not intersect any of
// the polygn edges.
bool result;
if (u_ind == v_ind ||
u_ind == _vec_pred(vec, v_ind) ||
u_ind == _vec_succ(vec, v_ind))
{
// A polygon edge (or a degenerate diagonal) is not considered as a legal
// visibility diagonal.
result = false;
}
else if (_query_reflex_zone (vec, v_ind,
vec[u_ind].point) == OPPOSITE_OF_ZONE)
{
// In this case the diagonal between u and v lies outside the polygon,
// so the two vertices are not visible.
result = false;
}
else
{
// Perform an exhaustive search on the polygon edges and check if any of
// them intersects the diagonal segment uv.
Segment_2 diag (vec[u_ind].point, vec[v_ind].point);
unsigned int curr = _vec_succ(vec, v_ind);
unsigned int next = _vec_succ(vec, curr);
result = true;
while (result && next != v_ind)
{
if (curr != u_ind && next != u_ind)
{
if (do_intersect (diag,
Segment_2 (vec[curr].point, vec[next].point)))
result = false;
}
curr = next;
next = _vec_succ(vec, curr);
}
}
// Update the visibility status.
if (result)
{
vec[v_ind].visible.push_back (u_ind);
}
else
{
vec[v_ind].non_visible.push_back (u_ind);
}
return (result);
}
/*!
* Construct a Point_info_2 vector from the given polygon.
* \param poly The input polygon.
* \param vec Output: The point vector.
* \return Whether the polygon is convex.
*/
bool _construct_point_vector (const Polygon_2& pgn,
Point_vector_2& vec) const
{
// Resize the vector to fit the polygon.
const unsigned int n = pgn.size();
const bool forward = (pgn.orientation() == COUNTERCLOCKWISE);
Vertex_circulator prev, curr, next;
unsigned int reflex_count = 0;
unsigned int k;
vec.resize (n);
// Initialize the vertex circulators.
next = curr = prev = pgn.vertices_circulator();
if (forward)
--prev;
else
++prev;
// Traverse the polygon's vertices in a counterclockwise order and prepare
// the output vector.
for (k = 0; k < n; k++)
{
// Set the next vertex.
if (forward)
++next;
else
--next;
// Set the current point.
vec[k].point = *curr;
// Check if the current vertex is reflex by checking the orientation of
// the polygon around it.
vec[k].is_reflex = (f_orientation (*prev, *curr, *next) == RIGHT_TURN);
// Set the number of reflex vertices from the beginning of the vector
// until the k'th (including itself).
if (vec[k].is_reflex)
reflex_count++;
vec[k].reflex_count = reflex_count;
// Proceed to the next vertex.
prev = curr;
curr = next;
}
// The polygon is convex if there are not reflex vertices:
return (reflex_count == 0);
}
/*!
* Given a polygon and to of its vertices u and v, count the number of reflex
* vertices between u and v, and between v and u (not including u and v
* themselves), and return the lesser quantity.
* \param vec A vector defining counterclockwise-oriented polygon.
* \param v_ind The index of the vertex v.
* \param u_ind The index of the vertex u.
* \return The minimal number of reflex vertices between u and v.
*/
unsigned int _count_reflex_vertices (const Point_vector_2& vec,
unsigned int u_ind,
unsigned int v_ind) const
{
if (u_ind == v_ind)
return (0);
unsigned int count1 = 0, count2 = 0;
unsigned int k;
// Make sure that v_ind > u_ind (if necessary, swap indices).
if (u_ind > v_ind)
{
k = u_ind;
u_ind = v_ind;
v_ind = k;
}
// Compute how many reflex vertices there are between u and v (not
// including v itself).
count1 = (vec[v_ind].reflex_count - vec[u_ind].reflex_count);
if (vec[v_ind].is_reflex)
count1--;
// Compute how many reflex vertices there are between v and u (not
// including u itself).
count2 = (vec[vec.size() - 1].reflex_count - vec[v_ind].reflex_count) +
vec[u_ind].reflex_count;
if (vec[u_ind].is_reflex)
count2--;
// Return the smaller value.
if (count1 < count2)
return count1;
else
return count2;
}
/*!
* Given a non-convex polygon, try to find a diagonal connecting to mutually
* visible reflex vertices u and v such that the number of reflex vertices
* between u and v is minimized.
* \param vec A vector defining counterclockwise-oriented polygon.
* \param v_ind Output: The index of the vertex v.
* \param u_ind Output: The index of the vertex u.
* \return Whether a diagonal was found.
*/
bool _compute_min_diagonal (Point_vector_2& vec,
unsigned int& u_ind, unsigned int& v_ind) const
{
unsigned int ind1, ind2;
Reflex_zone_position zone_pos;
unsigned int curr_count;
unsigned int min_count = 0;
bool found = false;
unsigned int dist;
// Let the distance between pairs of vertices we try vary between 2 and
// half the size of the polygon.
for (dist = 2; dist < (vec.size() + 1) / 2; dist++)
{
// Traverse the polygon vertices.
for (ind1 = 0; ind1 < vec.size(); ind1++)
{
if (! vec[ind1].is_reflex)
// Ignore convex vertices.
continue;
ind2 = (ind1 + dist) % vec.size();
if (! vec[ind2].is_reflex)
// Ignore convex vertices.
continue;
// Count the number of reflex vertices between the current pair of
// reflex vertices.
curr_count = _count_reflex_vertices (vec, ind1, ind2);
// If we are not below the minimal, stop checking.
if (found && min_count < curr_count)
continue;
// Check whether the two vertices lie in the reflex zone of one
// another. If so, the diagonal between them splits each of the angles
// of u and v into two angles than are not greater than 180 degrees.
zone_pos = _query_reflex_zone (vec, ind1, vec[ind2].point);
if ((zone_pos != INSIDE_ZONE) && (zone_pos != ON_ZONE_BOUNDARY))
continue;
zone_pos = _query_reflex_zone (vec, ind2, vec[ind1].point);
if ((zone_pos != INSIDE_ZONE) && (zone_pos != ON_ZONE_BOUNDARY))
continue;
// Check whether the two vertices are mutually visible.
if (! _is_visible (vec, ind1, ind2))
continue;
// If we passed all the various tests and reached here, we can update
// the minimal count.
min_count = curr_count;
u_ind = ind1;
v_ind = ind2;
found = true;
}
}
// Return whether a diagonal has been found.
return (found);
}
/*!
* Split the given polygon by the given diagonal.
* \param vec A vector defining counterclockwise-oriented polygon.
* \param ind1 The index of the first diagonal end-vertex.
* \param ind2 The index of the second diagonal end-vertex.
* \param check_ends Should we check for convexity near ind1 and ind2.
* \param vec1 Output: The first output polygon.
* \param vec2 Output: The second output polygon.
*/
void _split_by_diagonal (const Point_vector_2& vec,
unsigned int ind1, unsigned int ind2,
bool check_ends,
Point_vector_2& vec1,
Point_vector_2& vec2) const
{
unsigned int i1, i2;
Indices_iterator iter;
unsigned int reflex_count;
// Make sure that the index ind2 is greater than ind1.
if (ind1 > ind2)
{
i1 = ind1;
ind1 = ind2;
ind2 = i1;
}
// Resize the output vectors.
vec1.resize (ind2 - ind1 + 1);
vec2.resize (vec.size() - (ind2 - ind1 - 1));
// Construct the first output polygon. Notice we traverse the polygon in
// a counterclockwise direction from ind1 to ind2 and back.
reflex_count = 0;
for (i1 = ind1; i1 <= ind2; i1++)
{
// Copy the point.
vec1[i1 - ind1].point = vec[i1].point;
// Clear the visible vertices list.
vec1[i1-ind1].visible.clear();
vec1[i1-ind1].non_visible.clear();
if (i1 == ind1)
{
if (check_ends)
{
// Check the turn around ind1.
vec1[i1-ind1].is_reflex =
(f_orientation (vec[ind2].point,
vec[ind1].point,
vec[_vec_succ(vec, ind1)].point) == RIGHT_TURN);
}
else
{
// The two diagonal end-vertices are not reflex any more.
vec1[i1-ind1].is_reflex = false;
}
}
else if (i1 == ind2)
{
if (check_ends)
{
// Check the turn around ind2.
vec1[i1-ind1].is_reflex =
(f_orientation (vec[_vec_pred(vec, ind2)].point,
vec[ind2].point,
vec[ind1].point) == RIGHT_TURN);
}
else
{
// The two diagonal end-vertices are not reflex any more.
vec1[i1-ind1].is_reflex = false;
}
}
else
{
// Copy the reflexity flag.
vec1[i1-ind1].is_reflex = vec[i1].is_reflex;
// Set the visible vertices list.
for (iter = vec[i1].visible.begin();
iter != vec[i1].visible.end(); ++iter)
{
if ((*iter > ind1) && (*iter < ind2))
vec1[i1-ind1].visible.push_back(*iter - ind1);
}
// Set the non-visible vertices list.
for (iter = vec[i1].non_visible.begin();
iter != vec[i1].non_visible.end(); ++iter)
{
if ((*iter > ind1) && (*iter < ind2))
vec1[i1-ind1].non_visible.push_back(*iter - ind1);
}
}
// Set the reflex count.
if (vec1[i1-ind1].is_reflex)
reflex_count++;
vec1[i1-ind1].reflex_count = reflex_count;
}
// Construct the second output polygon. Notice we traverse the polygon in
// a counterclockwise direction from ind2 to ind1 and back.
reflex_count = 0;
i2 = 0;
i1 = ind2;
// go ccw on all the vertices from 'ind2' to 'ind1'.
while (i1 != (ind1+1))
{
// Copy the point.
vec2[i2].point = vec[i1].point;
// Clear the visible vertices list.
vec2[i2].visible.clear();
vec2[i2].non_visible.clear();
if (i1 == ind1)
{
if (check_ends)
{
// Check the turn around ind1.
vec2[i2].is_reflex =
(f_orientation (vec[_vec_pred(vec, ind1)].point,
vec[ind1].point,
vec[ind2].point) == RIGHT_TURN);
}
else
{
// The two diagonal end-vertices are not reflex any more.
vec2[i2].is_reflex = false;
}
}
else if (i1 == ind2)
{
if (check_ends)
{
// Check the turn around ind2.
vec2[i2].is_reflex =
(f_orientation (vec[ind1].point,
vec[ind2].point,
vec[_vec_succ(vec, ind2)].point) == RIGHT_TURN);
}
else
{
// The two diagonal end-vertices are not reflex any more.
vec2[i2].is_reflex = false;
}
}
else
{
// Copy the reflexity flag.
vec2[i2].is_reflex = vec[i1].is_reflex;
// Set the visible vertices list.
for (iter = vec[i1].visible.begin();
iter != vec[i1].visible.end(); ++iter)
{
if (*iter > ind2)
{
vec2[i2].visible.push_back (*iter - ind2);
}
else if (*iter < ind1)
{
vec2[i2].visible.push_back (*iter + vec.size() - ind2);
}
}
// Set the non-visible vertices list.
for (iter = vec[i1].non_visible.begin();
iter != vec[i1].non_visible.end(); ++iter)
{
if (*iter > ind2)
{
vec2[i2].non_visible.push_back (*iter - ind2);
}
else if (*iter < ind1)
{
vec2[i2].non_visible.push_back (*iter + vec.size() - ind2);
}
}
}
// Set the reflex count.
if (vec2[i2].is_reflex)
reflex_count++;
vec2[i2].reflex_count = reflex_count;
// advance the indices.
i1 = _vec_succ(vec, i1);
i2++;
}
return;
}
/*!
* Get the angle ratio created by the the bisection of the angle at the
* reflex vertex v by the diagonal uv.
* \param vec A vector defining counterclockwise-oriented polygon.
* \param v_ind The index of the vertex v.
* \param u_ind The index of the vertex u.
* \return The ratio between the bisected angles.
*/
double _angle_bisection_ratio (Point_vector_2 &vec,
unsigned int v_ind,
unsigned int u_ind) const
{
const double _2_PI = 6.2831853;
// Get the points at u and v, as well as v's adjacencies and approximate
// their coordinates.
const Point_2& u_pt = vec[u_ind].point;
const Point_2& v_pt = vec[v_ind].point;
const Point_2& pred_pt = vec[_vec_pred(vec, v_ind)].point;
const Point_2& succ_pt = vec[_vec_succ(vec, v_ind)].point;
const double ux = CGAL::to_double (u_pt.x());
const double uy = CGAL::to_double (u_pt.y());
const double vx = CGAL::to_double (v_pt.x());
const double vy = CGAL::to_double (v_pt.y());
const double pred_x = CGAL::to_double (pred_pt.x());
const double pred_y = CGAL::to_double (pred_pt.y());
const double succ_x = CGAL::to_double (succ_pt.x());
const double succ_y = CGAL::to_double (succ_pt.y());
// Compute the edge length and the diagonal length.
const double len_uv = ::sqrt((ux - vx) * (ux - vx) +
(uy - vy) * (uy - vy));
const double len_pred = ::sqrt((pred_x - vx) * (pred_x - vx) +
(pred_y - vy) * (pred_y - vy));
const double len_succ = ::sqrt((succ_x - vx) * (succ_x - vx) +
(succ_y - vy) * (succ_y - vy));
// Compute the angle a1 = <) (pred_pt, v_pt, u_pt):
const double cos_a1 = ((ux - vx) * (pred_x - vx) +
(uy - vy) * (pred_y - vy)) / (len_uv * len_pred);
double a1 = ::acos (cos_a1);
if (f_orientation (pred_pt, v_pt, u_pt) == RIGHT_TURN)
// The angle a1 is larger than 180 degree:
a1 = _2_PI - a1;
// Compute the angle a2 = <) (u_pt, v_pt, succ_pt):
const double cos_a2 = ((ux - vx) * (succ_x - vx) +
(uy - vy) * (succ_y - vy)) / (len_uv * len_succ);
double a2 = ::acos (cos_a2);
if (f_orientation (u_pt, v_pt, succ_pt) == RIGHT_TURN)
// The angle a1 is larger than 180 degree:
a2 = _2_PI - a2;
// Return the ratio of max(a1,a2)/min(a1,a2).
if (a1 == 0 || a2 == 0)
return (10000);
if (a1 > a2)
return (a1 / a2);
else
return (a2 / a1);
}
/*!
* Perform an approximate angle-bisector decomposition, by locating a reflex
* vertex and another vertex such that the diagonal between them is not
* blocked, and such that it approximates the angle bisector of the reflex
* vertex.
* \param vec A vector defining counterclockwise-oriented polygon.
* \param reflex_ind Output: The index of the reflex vertex whose angle we
* wish to bisect.
* \param other_ind Output: The index of the other polygon vertex.
*/
void _approximate_angle_bisector (Point_vector_2& vec,
unsigned int& reflex_ind,
unsigned int& other_ind) const
{
unsigned int ind1, ind2;
double curr_ratio;
double min_ratio = 0;
bool found = false;
unsigned int dist;
// Let the distance between pairs of vertices we try vary between 2 and
// the size of the polygon - 2.
for (dist = 2; dist <= vec.size() - 2; dist++)
{
// Traverse the polygon vertices.
for (ind1 = 0; ind1 < vec.size(); ind1++)
{
if (! vec[ind1].is_reflex)
// Ignore convex vertices.
continue;
ind2 = (ind1 + dist) % vec.size();
// Get the current ratio between the two angles the current
// diagonal splits around vec[ind1].
curr_ratio = _angle_bisection_ratio (vec, ind1, ind2);
// If we are not below the minimal, stop checking.
if (found && min_ratio < curr_ratio)
continue;
// Check whether the two vertices are mutually visible.
if (! _is_visible (vec, ind1, ind2))
continue;
// If we passed all the various tests and reached here, we can update
// the minimal angle difference.
min_ratio = curr_ratio;
reflex_ind = ind1;
other_ind = ind2;
found = true;
}
}
// Return whether a diagonal has been found.
CGAL_assertion (found);
return;
}
/*!
* Convert the point-info vector into a polygon and send it as an output.
* \param vec A vector defining counterclockwise-oriented convex polygon.
* \param oi The output iterator.
* \return A past-the-end iterator for the sub-polygons.
*/
template <class OutputIterator>
OutputIterator _output_polygon (const Point_vector_2& vec,
OutputIterator oi) const
{
const unsigned int n = vec.size();
Polygon_2 pgn;
unsigned int k;
for (k = 0; k < n; k++)
pgn.push_back (vec[k].point);
*oi = pgn;
++oi;
return (oi);
}
};
} //namespace CGAL
#endif
|