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 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968
|
// Copyright (c) 2005 INRIA (France).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org); you may redistribute it under
// the terms of the Q Public License version 1.0.
// See the file LICENSE.QPL distributed with CGAL.
//
// Licensees holding a valid commercial license may use this file in
// accordance with the commercial license agreement provided with the software.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
//
// $URL: svn+ssh://scm.gforge.inria.fr/svn/cgal/branches/CGAL-3.2-branch/Surface_mesh_parameterization/include/CGAL/Parameterization_mesh_patch_3.h $
// $Id: Parameterization_mesh_patch_3.h 29301 2006-03-09 17:15:04Z lsaboret $
//
//
// Author(s) : Laurent Saboret, Pierre Alliez, Bruno Levy
#ifndef CGAL_PARAMETERIZATION_MESH_PATCH_3_H
#define CGAL_PARAMETERIZATION_MESH_PATCH_3_H
#include <CGAL/iterator.h>
#include <CGAL/circulator.h>
#include <CGAL/Convertible_iterator_project.h>
#include <CGAL/Convertible_circulator_project.h>
#include <CGAL/Convertible_filter_iterator.h>
#include <CGAL/Param_mesh_patch_vertex.h>
#include <CGAL/Param_mesh_patch_iterators.h>
#include <CGAL/Param_mesh_patch_circulators.h>
#include <CGAL/surface_mesh_parameterization_assertions.h>
CGAL_BEGIN_NAMESPACE
/// Parameterization_mesh_patch_3 is a Decorator class to "virtually" cut a patch
/// in a ParameterizationPatchableMesh_3 3D surface. Only the patch is exported,
/// making the 3D surface look like a topological disk.
///
/// The input mesh can be of any genus, but it has to come with a "seam" that
/// describes the border of a topological disc. This border may be an actual
/// border of the mesh or a virtual border.
///
/// Concept:
/// Model of ParameterizationMesh_3 concept, whose purpose is to allow
/// the Surface_mesh_parameterization package to access meshes in a uniform manner.
///
/// Design Pattern:
/// Parameterization_mesh_patch_3 is a Decorator [GHJV95]: it changes the behavior
/// of a ParameterizationPatchableMesh_3 3D surface while keeping its
/// ParameterizationMesh_3 interface.
template<class ParameterizationPatchableMesh_3>
class Parameterization_mesh_patch_3
{
// Private types
private:
// Forward references
struct Inner_facets_filter;
/// Seaming flag.
enum Seaming_status { OUTER, INNER, BORDER };
public:
//*******************************************************************
/// @name INTERFACE SPECIFIC TO Parameterization_mesh_patch_3
//*******************************************************************
//@{
/// Export template parameter.
typedef ParameterizationPatchableMesh_3 Adaptor;
//@} // end of INTERFACE SPECIFIC TO Parameterization_mesh_patch_3
//*******************************************************************
/// @name ParameterizationMesh_3 INTERFACE
//*******************************************************************
//@{
/// Number type to represent coordinates.
typedef typename Adaptor::NT NT;
/// 2D point that represents (u,v) coordinates computed
/// by parameterization methods. Must provide X() and Y() methods.
typedef typename Adaptor::Point_2 Point_2;
/// 3D point that represents vertices coordinates. Must provide X() and Y() methods.
typedef typename Adaptor::Point_3 Point_3;
/// 2D vector. Must provide X() and Y() methods.
typedef typename Adaptor::Vector_2 Vector_2;
/// 3D vector. Must provide X() and Y() methods.
typedef typename Adaptor::Vector_3 Vector_3;
/// Opaque type representing a facet of the 3D mesh. No methods are expected.
typedef typename Adaptor::Facet Facet;
/// Handle to a facet. Model of the Handle concept.
typedef typename Adaptor::Facet_handle Facet_handle;
typedef typename Adaptor::Facet_const_handle
Facet_const_handle;
/// Iterator over all mesh facets. Model of the ForwardIterator concept.
typedef Convertible_filter_iterator<typename Adaptor::Facet_iterator,
Inner_facets_filter,
Facet_const_handle,
Facet_handle>
Facet_iterator;
typedef Convertible_filter_iterator<typename Adaptor::Facet_const_iterator,
Inner_facets_filter,
Facet_const_handle>
Facet_const_iterator;
/// Opaque type representing a vertex of the 3D mesh. No methods are expected.
typedef Param_mesh_patch_vertex<Adaptor> Vertex;
/// Handle to a vertex. Model of the Handle concept.
typedef Param_mesh_patch_vertex_handle<Adaptor>
Vertex_handle;
typedef Param_mesh_patch_vertex_const_handle<Adaptor>
Vertex_const_handle;
/// Iterator over all vertices of a mesh. Model of the ForwardIterator concept.
typedef Param_mesh_patch_vertex_list_iterator<Adaptor>
Vertex_iterator;
typedef Param_mesh_patch_vertex_list_const_iterator<Adaptor>
Vertex_const_iterator;
/// Iterator over vertices of the mesh "main border".
/// Model of the ForwardIterator concept.
typedef Vertex_iterator Border_vertex_iterator;
typedef Vertex_const_iterator Border_vertex_const_iterator;
/// Counter-clockwise circulator over a facet's vertices.
/// Model of the BidirectionalCirculator concept.
typedef Mesh_patch_vertex_around_facet_cir<Parameterization_mesh_patch_3,
Vertex_handle,
typename Adaptor::Vertex_around_facet_circulator>
Vertex_around_facet_circulator;
typedef Mesh_patch_vertex_around_facet_cir<const Parameterization_mesh_patch_3,
Vertex_const_handle,
typename Adaptor::Vertex_around_facet_const_circulator>
Vertex_around_facet_const_circulator;
/// Clockwise circulator over the vertices incident to a vertex.
/// Model of the BidirectionalCirculator concept.
typedef Mesh_patch_vertex_around_vertex_cir<Parameterization_mesh_patch_3,
Vertex_handle,
typename Adaptor::Vertex_around_vertex_circulator,
typename Adaptor::Vertex_handle>
Vertex_around_vertex_circulator;
typedef Mesh_patch_vertex_around_vertex_cir<const Parameterization_mesh_patch_3,
Vertex_const_handle,
typename Adaptor::Vertex_around_vertex_const_circulator,
typename Adaptor::Vertex_const_handle>
Vertex_around_vertex_const_circulator;
//@} // end of ParameterizationMesh_3 INTERFACE
// Public operations
public:
///******************************************************************
/// @name INTERFACE SPECIFIC TO Parameterization_mesh_patch_3
///******************************************************************
//@{
/// Create a Decorator for an existing ParameterizationPatchableMesh_3 mesh.
/// The input mesh can be of any genus, but it has to come with a "seam" that
/// describes the border of a topological disc. This border may be an actual
/// border of the mesh or a virtual border.
///
/// Preconditions:
/// - first_seam_vertex -> end_seam_vertex defines the outer seam,
/// ie Parameterization_mesh_patch_3 will export the "right" of the seam.
/// - the "seam" is given as a container of Adaptor::Vertex_handle elements.
template<class InputIterator>
Parameterization_mesh_patch_3(Adaptor& mesh,
InputIterator first_seam_vertex,
InputIterator end_seam_vertex)
// Store reference to adapted mesh
: m_mesh_adaptor(mesh)
{
// Set seaming flag of all vertices and edges to INNER, BORDER or OUTER
// wrt the first_seam_vertex -> end_seam_vertex border
set_mesh_seaming(first_seam_vertex, end_seam_vertex);
// Construct the list of all exported vertices, ie INNER and BORDER vertices
//
// 1) add inner vertices
for (typename Adaptor::Vertex_iterator it = mesh.mesh_vertices_begin();
it != mesh.mesh_vertices_end();
it++)
{
if (m_mesh_adaptor.get_vertex_seaming(it) == INNER)
m_inner_and_border_vertices.push_back( Vertex(it) );
}
// 2) add seam vertices, wrt outer seam/border order
InputIterator border_it = first_seam_vertex;
InputIterator prev_border_it = end_seam_vertex; prev_border_it--;;
InputIterator next_border_it = first_seam_vertex; next_border_it++;
while (border_it != end_seam_vertex)
{
// Get outer border vertex
Vertex v;
// if border vertex
if (m_mesh_adaptor.get_halfedge_seaming(*border_it, *prev_border_it) != BORDER)
v = Vertex(*border_it, *prev_border_it, *next_border_it);
else // if seam vertex
v = Vertex(*border_it, *next_border_it, *prev_border_it); // order inverted!
// Add vertex
m_inner_and_border_vertices.push_back(v);
// Increment iterators
border_it++;
//
prev_border_it++;
if (prev_border_it == end_seam_vertex)
prev_border_it = first_seam_vertex;
//
next_border_it++;
if (next_border_it == end_seam_vertex)
next_border_it = first_seam_vertex;
}
// Initialize m_seam_begin = iterator to beginning of seam/main border
// inside m_inner_and_border_vertices
m_seam_begin = mesh_vertices_end();
for (Vertex_iterator it=mesh_vertices_begin(); it!=mesh_vertices_end(); it++) {
if (get_vertex_seaming(it) == BORDER) {
m_seam_begin = it;
break;
}
}
#ifndef NDEBUG
// Index vertices right away to ease debugging
index_mesh_vertices();
#endif
}
/// Get the decorated mesh.
Adaptor& get_decorated_mesh() { return *m_mesh_adaptor; }
const Adaptor& get_decorated_mesh() const { return *m_mesh_adaptor; }
//@} // end of INTERFACE SPECIFIC TO Parameterization_mesh_patch_3
//*******************************************************************
/// @name ParameterizationMesh_3 INTERFACE
//*******************************************************************
//@{
// MESH INTERFACE
/// Get iterator over first vertex of mesh.
Vertex_iterator mesh_vertices_begin() {
return m_inner_and_border_vertices.begin();
}
Vertex_const_iterator mesh_vertices_begin() const {
return m_inner_and_border_vertices.begin();
}
/// Get iterator over past-the-end vertex of mesh.
Vertex_iterator mesh_vertices_end() {
return m_inner_and_border_vertices.end();
}
Vertex_const_iterator mesh_vertices_end() const {
return m_inner_and_border_vertices.end();
}
/// Count the number of vertices of the mesh.
int count_mesh_vertices() const {
int index = 0;
for (Vertex_const_iterator it=mesh_vertices_begin(); it!=mesh_vertices_end(); it++)
index++;
return index;
}
/// Index vertices of the mesh from 0 to count_mesh_vertices()-1.
void index_mesh_vertices ()
{
//fprintf(stderr," index Parameterization_mesh_patch_3 vertices:\n");
int index = 0;
for (Vertex_iterator it=mesh_vertices_begin(); it!=mesh_vertices_end(); it++)
{
//fprintf(stderr, " #%d = {%s,%s,%s}\n",
// index,
// get_vertex_index_as_string(it->vertex()).c_str(),
// get_vertex_index_as_string(it->last_cw_neighbor()).c_str(),
// get_vertex_index_as_string(it->first_cw_neighbor()).c_str());
set_vertex_index(it, index++);
}
//fprintf(stderr," ok\n");
}
/// Get iterator over first vertex of mesh's main border (aka "seam").
Border_vertex_iterator mesh_main_border_vertices_begin() {
return m_seam_begin;
}
Border_vertex_const_iterator mesh_main_border_vertices_begin() const {
return (Border_vertex_const_iterator) m_seam_begin;
}
/// Get iterator over past-the-end vertex of mesh's main border (aka "seam").
Border_vertex_iterator mesh_main_border_vertices_end() {
return mesh_vertices_end();
}
Border_vertex_const_iterator mesh_main_border_vertices_end() const {
return mesh_vertices_end();
}
/// Return the border containing seed_vertex.
/// Return an empty list if not found.
std::list<Vertex_handle> get_border(Vertex_handle seed_vertex)
{
std::list<Vertex_handle> border; // returned list
// If seam vertex, return the seam
if (is_vertex_on_main_border(seed_vertex))
{
for (Border_vertex_iterator it = mesh_main_border_vertices_begin();
it != mesh_main_border_vertices_end();
it++)
{
border.push_back(it);
}
}
else // if vertex on the border of a hole
{
// Get list of vertices on this border
std::list<typename Adaptor::Vertex_handle> adaptor_border =
m_mesh_adaptor.get_border(seed_vertex->vertex());
// Copy them into 'border'
for (typename std::list<typename Adaptor::Vertex_handle>::iterator it = adaptor_border.begin();
it != adaptor_border.end();
it++)
{
// Check that vertex is inner
assert(m_mesh_adaptor.get_vertex_seaming(*it) == INNER);
border.push_back( Vertex_handle(*it) );
}
}
return border;
}
/// Get iterator over first facet of mesh.
Facet_iterator mesh_facets_begin() {
return Facet_iterator(m_mesh_adaptor.mesh_facets_end(),
Inner_facets_filter(*this),
m_mesh_adaptor.mesh_facets_begin());
}
Facet_const_iterator mesh_facets_begin() const {
return Facet_const_iterator(m_mesh_adaptor.mesh_facets_end(),
Inner_facets_filter(*this),
m_mesh_adaptor.mesh_facets_begin());
}
/// Get iterator over past-the-end facet of mesh.
Facet_iterator mesh_facets_end() {
return Facet_iterator(m_mesh_adaptor.mesh_facets_end(),
Inner_facets_filter(*this));
}
Facet_const_iterator mesh_facets_end() const {
return Facet_const_iterator(m_mesh_adaptor.mesh_facets_end(),
Inner_facets_filter(*this));
}
/// Count the number of facets of the mesh.
int count_mesh_facets() const {
int index = 0;
for (Facet_const_iterator it=mesh_facets_begin(); it!=mesh_facets_end(); it++)
index++;
return index;
}
/// Return true of all mesh's facets are triangles.
bool is_mesh_triangular() const {
for (Facet_const_iterator it = mesh_facets_begin(); it != mesh_facets_end(); it++)
if (count_facet_vertices(it) != 3)
return false;
return true; // mesh is triangular if we reach this point
}
/// Count the number of halfedges of the mesh.
int count_mesh_halfedges() const {
int index = 0;
for (Vertex_const_iterator it=mesh_vertices_begin(); it!=mesh_vertices_end(); it++)
{
// Count each neighbor vertex
Vertex_around_vertex_const_circulator cir = vertices_around_vertex_begin(it);
Vertex_around_vertex_const_circulator cir_end = cir;
CGAL_For_all(cir, cir_end)
index++;
}
return index;
}
// FACET INTERFACE
/// Get circulator over facet's vertices.
Vertex_around_facet_circulator facet_vertices_begin(Facet_handle facet) {
CGAL_surface_mesh_parameterization_assertion(is_valid(facet));
return Vertex_around_facet_circulator(*this, m_mesh_adaptor.facet_vertices_begin(facet));
}
Vertex_around_facet_const_circulator facet_vertices_begin(Facet_const_handle facet) const {
CGAL_surface_mesh_parameterization_assertion(is_valid(facet));
return Vertex_around_facet_const_circulator(*this, m_mesh_adaptor.facet_vertices_begin(facet));
}
/// Count the number of vertices of a facet.
int count_facet_vertices(Facet_const_handle facet) const {
CGAL_surface_mesh_parameterization_assertion(is_valid(facet));
int index = 0;
Vertex_around_facet_const_circulator cir = facet_vertices_begin(facet),
cir_end = cir;
CGAL_For_all(cir, cir_end)
index++;
return index;
}
// VERTEX INTERFACE
/// Get the 3D position of a vertex.
Point_3 get_vertex_position(Vertex_const_handle vertex) const {
CGAL_surface_mesh_parameterization_assertion(is_valid(vertex));
return m_mesh_adaptor.get_vertex_position(vertex->vertex());
}
/// Get/set the 2D position (u/v pair) of a vertex. Default value is undefined.
Point_2 get_vertex_uv(Vertex_const_handle vertex) const {
CGAL_surface_mesh_parameterization_assertion(is_valid(vertex));
return m_mesh_adaptor.get_corners_uv(vertex->vertex(),
vertex->last_cw_neighbor(),
vertex->first_cw_neighbor());
}
void set_vertex_uv(Vertex_handle vertex, const Point_2& uv)
{
CGAL_surface_mesh_parameterization_assertion(is_valid(vertex));
return m_mesh_adaptor.set_corners_uv(vertex->vertex(),
vertex->last_cw_neighbor(),
vertex->first_cw_neighbor(),
uv);
}
/// Get/set "is parameterized" field of vertex. Default value is undefined.
bool is_vertex_parameterized(Vertex_const_handle vertex) const {
CGAL_surface_mesh_parameterization_assertion(is_valid(vertex));
return m_mesh_adaptor.are_corners_parameterized(vertex->vertex(),
vertex->last_cw_neighbor(),
vertex->first_cw_neighbor());
}
void set_vertex_parameterized(Vertex_handle vertex, bool parameterized)
{
CGAL_surface_mesh_parameterization_assertion(is_valid(vertex));
return m_mesh_adaptor.set_corners_parameterized(vertex->vertex(),
vertex->last_cw_neighbor(),
vertex->first_cw_neighbor(),
parameterized);
}
/// Get/set vertex index. Default value is undefined.
int get_vertex_index(Vertex_const_handle vertex) const {
CGAL_surface_mesh_parameterization_assertion(is_valid(vertex));
return m_mesh_adaptor.get_corners_index(vertex->vertex(),
vertex->last_cw_neighbor(),
vertex->first_cw_neighbor());
}
void set_vertex_index(Vertex_handle vertex, int index) {
CGAL_surface_mesh_parameterization_assertion(is_valid(vertex));
return m_mesh_adaptor.set_corners_index(vertex->vertex(),
vertex->last_cw_neighbor(),
vertex->first_cw_neighbor(),
index);
}
/// Get/set vertex' all purpose tag. Default value is undefined.
int get_vertex_tag(Vertex_const_handle vertex) const {
CGAL_surface_mesh_parameterization_assertion(is_valid(vertex));
return m_mesh_adaptor.get_corners_tag(vertex->vertex(),
vertex->last_cw_neighbor(),
vertex->first_cw_neighbor());
}
void set_vertex_tag(Vertex_handle vertex, int tag) {
return m_mesh_adaptor.set_corners_tag(vertex->vertex(),
vertex->last_cw_neighbor(),
vertex->first_cw_neighbor(),
tag);
}
/// Return true if a vertex belongs to ANY mesh's border.
bool is_vertex_on_border(Vertex_const_handle vertex) const {
CGAL_surface_mesh_parameterization_assertion(is_valid(vertex));
return is_vertex_on_main_border(vertex) ||
m_mesh_adaptor.is_vertex_on_border(vertex->vertex());
}
/// Return true if a vertex belongs to the UNIQUE mesh's main border
/// set by the constructor.
bool is_vertex_on_main_border(Vertex_const_handle vertex) const {
CGAL_surface_mesh_parameterization_assertion(is_valid(vertex));
return get_vertex_seaming(vertex) == BORDER;
}
/// Get circulator over the vertices incident to 'vertex'.
/// 'start_position' defines the optional initial position of the circulator.
Vertex_around_vertex_circulator vertices_around_vertex_begin(
Vertex_handle vertex,
Vertex_handle start_position = Vertex_handle())
{
CGAL_surface_mesh_parameterization_assertion(is_valid(vertex));
CGAL_surface_mesh_parameterization_assertion(start_position == NULL ||
is_valid(start_position));
// If no start position provided, pick one
if (start_position == NULL)
{
// If 'vertex' is an inner vertex, pick any neighbor
if (vertex->last_cw_neighbor() == NULL)
{
typename Adaptor::Vertex_around_vertex_circulator adaptor_circulator
= m_mesh_adaptor.vertices_around_vertex_begin(vertex->vertex());
start_position = get_decorated_inner_vertex(adaptor_circulator,
vertex->vertex());
}
else // If 'vertex' is a seam vertex, pick its last clockwise neighbor
{
start_position = get_decorated_border_vertex(vertex->last_cw_neighbor(),
NULL,
vertex->vertex());
}
}
return Vertex_around_vertex_circulator(*this, vertex, start_position);
}
Vertex_around_vertex_const_circulator vertices_around_vertex_begin(
Vertex_const_handle vertex,
Vertex_const_handle start_position = Vertex_const_handle()) const
{
CGAL_surface_mesh_parameterization_assertion(is_valid(vertex));
CGAL_surface_mesh_parameterization_assertion(start_position == NULL ||
is_valid(start_position));
// If no start position provided, pick one
if (start_position == NULL)
{
// If 'vertex' is an inner vertex, pick any neighbor
if (vertex->last_cw_neighbor() == NULL)
{
typename Adaptor::Vertex_around_vertex_const_circulator adaptor_circulator
= m_mesh_adaptor.vertices_around_vertex_begin(vertex->vertex());
start_position = get_decorated_inner_vertex(adaptor_circulator,
vertex->vertex());
}
else // If 'vertex' is a seam vertex, pick its last clockwise neighbor
{
start_position = get_decorated_border_vertex(vertex->last_cw_neighbor(),
NULL,
vertex->vertex());
}
}
return Vertex_around_vertex_const_circulator(*this, vertex, start_position);
}
//@} // end of ParameterizationMesh_3 INTERFACE
// Private operations
private:
/// Default copy constructor and operator =() are not (yet) implemented.
Parameterization_mesh_patch_3(const Parameterization_mesh_patch_3& toCopy);
Parameterization_mesh_patch_3& operator =(const Parameterization_mesh_patch_3& toCopy);
/// Set seaming flag of all vertices and edges to INNER, BORDER or OUTER
/// wrt the first_seam_vertex -> end_seam_vertex border
/// (outer seam edges are marked BORDER).
///
/// Preconditions:
/// - first_seam_vertex -> end_seam_vertex defines the outer seam,
/// ie Parameterization_mesh_patch_3 will export the "right" of the seam.
/// - the "seam" is given as a container of Adaptor::Vertex_handle elements.
template<class InputIterator>
void set_mesh_seaming(InputIterator first_seam_vertex,
InputIterator end_seam_vertex)
{
// Initialize the seaming flag of all vertices to OUTER
for (typename Adaptor::Vertex_iterator it = m_mesh_adaptor.mesh_vertices_begin();
it != m_mesh_adaptor.mesh_vertices_end();
it++)
{
m_mesh_adaptor.set_vertex_seaming(it, OUTER);
}
// Initialize the seaming flag of all halfedges to OUTER
for (typename Adaptor::Vertex_iterator it = m_mesh_adaptor.mesh_vertices_begin();
it != m_mesh_adaptor.mesh_vertices_end();
it++)
{
// For each neighbor vertex
typename Adaptor::Vertex_around_vertex_circulator cir, cir_end;
cir = m_mesh_adaptor.vertices_around_vertex_begin(it);
cir_end = cir;
CGAL_For_all(cir, cir_end)
m_mesh_adaptor.set_halfedge_seaming(it, cir, OUTER);
}
// Set seaming flag of seam vertices to BORDER.
// Set seaming flag of outer seam edges to BORDER
// and inner seam vertices to INNER.
for (InputIterator border_it = first_seam_vertex;
border_it != end_seam_vertex;
border_it++)
{
// Set vertex seaming flag
m_mesh_adaptor.set_vertex_seaming(*border_it, BORDER);
// Get next iterator (looping)
InputIterator next_border_it = border_it;
next_border_it++;
if (next_border_it == end_seam_vertex)
next_border_it = first_seam_vertex;
// Set outer seam edge to BORDER
m_mesh_adaptor.set_halfedge_seaming(*border_it, *next_border_it,
BORDER);
// Set inner seam edge to INNER (except if also BORDER)
if (m_mesh_adaptor.get_halfedge_seaming(*next_border_it,
*border_it) != BORDER) {
m_mesh_adaptor.set_halfedge_seaming(*next_border_it, *border_it,
INNER);
}
}
// Set the seaming flag of inner vertices and edges to INNER
for (InputIterator border_it = first_seam_vertex;
border_it != end_seam_vertex;
border_it++)
{
// Get next iterator (looping)
InputIterator next_border_it = border_it;
next_border_it++;
if (next_border_it == end_seam_vertex)
next_border_it = first_seam_vertex;
// Get inner point at the "right" of *border_it
// by a counter-clockwise rotation around the next seam vertex
typename Adaptor::Vertex_around_vertex_circulator cir =
m_mesh_adaptor.vertices_around_vertex_begin(*next_border_it,
*border_it);
cir--;
// Fill topological disk
if (m_mesh_adaptor.get_vertex_seaming(cir) != BORDER)
set_inner_region_seaming(cir);
}
}
/// Set the seaming flag of inner vertices and edges to INNER
/// by filling the topological disk.
///
/// Preconditions:
/// - Inner vertices are marked as OUTER, seam vertices as BORDER.
/// - Inner edges are marked as OUTER,
/// outer seam edges as BORDER, inner seam edges as INNER.
/// - pSeedVertex is in the inner region.
/// - pSeedVertex != NULL.
///
/// Implementation note:
/// The seaming status of inner edges is unused, thus this part is not tested.
///
void set_inner_region_seaming(typename Adaptor::Vertex_handle pSeedVertex)
{
if (pSeedVertex == NULL)
return; // Gloups... topological disc is empty!
// List of vertices to flag = pSeedVertex initially
std::list<typename Adaptor::Vertex_handle> vertices;
vertices.push_front(pSeedVertex);
// For each vertex in the list: pop it out, flag it as INNER and
// add its surrounding vertices to the list
while (!vertices.empty())
{
typename Adaptor::Vertex_handle pVertex = vertices.front();
vertices.pop_front();
CGAL_surface_mesh_parameterization_assertion(pVertex != NULL);
// Flag this vertex as INNER
if (m_mesh_adaptor.get_vertex_seaming(pVertex) == OUTER)
m_mesh_adaptor.set_vertex_seaming(pVertex, INNER);
else
continue; // Skip this vertex if it is already done
// For each neighbor vertex
typename Adaptor::Vertex_around_vertex_circulator cir, cir_end;
cir = m_mesh_adaptor.vertices_around_vertex_begin(pVertex);
cir_end = cir;
CGAL_For_all(cir, cir_end)
{
// Flag both oriented edges pVertex <-> cir
m_mesh_adaptor.set_halfedge_seaming(pVertex, cir, INNER);
m_mesh_adaptor.set_halfedge_seaming(cir, pVertex, INNER);
// Add surrounding vertices to list without crossing the border
if (m_mesh_adaptor.get_vertex_seaming(cir) == OUTER)
vertices.push_front(cir);
}
}
}
/// Get facet' seaming status (INNER or OUTER).
Seaming_status get_facet_seaming(typename Adaptor::Facet_const_handle facet) const
{
// do not call is_valid() to avoid an infinite loop
CGAL_surface_mesh_parameterization_assertion(facet != NULL);
typename Adaptor::Vertex_around_facet_const_circulator
cir = m_mesh_adaptor.facet_vertices_begin(facet);
CGAL_surface_mesh_parameterization_assertion(cir != NULL);
return (m_mesh_adaptor.get_vertex_seaming(cir) == OUTER) ?
OUTER :
INNER;
}
/// Get/set vertex seaming flag,
/// ie position of the vertex wrt to the UNIQUE main border.
Seaming_status get_vertex_seaming(Vertex_const_handle vertex) const {
CGAL_surface_mesh_parameterization_assertion(is_valid(vertex));
return (Seaming_status) m_mesh_adaptor.get_vertex_seaming(
vertex->vertex());
}
void set_vertex_seaming(Vertex_handle vertex, Seaming_status seaming) {
m_mesh_adaptor.set_vertex_seaming(vertex->vertex(), seaming);
}
/// Create a patch vertex from an adaptor vertex + one of its neighbors.
///
/// Preconditions:
/// - adaptor_neighbor is a neighbor of adaptor_vertex.
/// - (adaptor_vertex, adaptor_neighbor) must NOT be a seam (non-oriented) edge.
Vertex_const_handle get_decorated_inner_vertex(
typename Adaptor::Vertex_const_handle adaptor_vertex,
typename Adaptor::Vertex_const_handle adaptor_neighbor) const
{
// We need at least an inner neighbor as input
assert(m_mesh_adaptor.get_halfedge_seaming(adaptor_vertex,
adaptor_neighbor) != BORDER
|| m_mesh_adaptor.get_halfedge_seaming(adaptor_neighbor,
adaptor_vertex) != BORDER);
// if inner vertex
if (m_mesh_adaptor.get_vertex_seaming(adaptor_vertex) != BORDER)
{
// No extra information needed if inner vertex
return Vertex_const_handle(adaptor_vertex);
}
else // if seam vertex
{
// find last neighbor (on seam) for a clockwise rotation
typename Adaptor::Vertex_around_vertex_const_circulator last_cw_neighbor_cir
= m_mesh_adaptor.vertices_around_vertex_begin(adaptor_vertex,
adaptor_neighbor);
while (m_mesh_adaptor.get_halfedge_seaming(last_cw_neighbor_cir,
adaptor_vertex) != BORDER)
{
last_cw_neighbor_cir++;
}
// find first clockwise neighbor (on seam) by a counter-clockwise rotation
typename Adaptor::Vertex_around_vertex_const_circulator first_cw_neighbor_cir
= m_mesh_adaptor.vertices_around_vertex_begin(adaptor_vertex,
adaptor_neighbor);
while (m_mesh_adaptor.get_halfedge_seaming(adaptor_vertex,
first_cw_neighbor_cir) != BORDER)
{
first_cw_neighbor_cir--;
}
// The decorated vertex is then:
return Vertex_const_handle(adaptor_vertex,
last_cw_neighbor_cir,
first_cw_neighbor_cir);
}
}
Vertex_handle get_decorated_inner_vertex(
typename Adaptor::Vertex_handle adaptor_vertex,
typename Adaptor::Vertex_handle adaptor_neighbor)
{
// Call the const version of get_decorated_inner_vertex()
Vertex_const_handle vertex_hdl = get_decorated_inner_vertex(
(typename Adaptor::Vertex_const_handle)adaptor_vertex,
(typename Adaptor::Vertex_const_handle)adaptor_neighbor);
return const_cast<Vertex*>(&*vertex_hdl);
}
/// Create a patch vertex from a border/seam adaptor vertex
/// + one of its neighbors on the seam.
///
/// Preconditions:
/// - adaptor_vertex is a border/seam vertex.
/// - [first_cw_neighbor, last_cw_neighbor] defines the range
/// of the valid neighbors of adaptor_vertex (included) or are NULL.
/// - either first_cw_neighbor or last_cw_neighbor are not NULL.
Vertex_const_handle get_decorated_border_vertex(
typename Adaptor::Vertex_const_handle adaptor_vertex,
typename Adaptor::Vertex_const_handle last_cw_neighbor,
typename Adaptor::Vertex_const_handle first_cw_neighbor) const
{
assert(adaptor_vertex != NULL);
assert(last_cw_neighbor != NULL || first_cw_neighbor != NULL);
assert(last_cw_neighbor == NULL
|| m_mesh_adaptor.get_halfedge_seaming(adaptor_vertex,
last_cw_neighbor) == BORDER
|| m_mesh_adaptor.get_halfedge_seaming(last_cw_neighbor,
adaptor_vertex) == BORDER);
assert(first_cw_neighbor == NULL
|| m_mesh_adaptor.get_halfedge_seaming(adaptor_vertex,
first_cw_neighbor) == BORDER
|| m_mesh_adaptor.get_halfedge_seaming(first_cw_neighbor,
adaptor_vertex) == BORDER);
// If both first_cw_neighbor and last_cw_neighbor are provided
if (last_cw_neighbor != NULL && first_cw_neighbor != NULL)
{
// we're done (quick)
return Vertex_const_handle(adaptor_vertex,
last_cw_neighbor,
first_cw_neighbor);
}
else // if either first_cw_neighbor or last_cw_neighbor is missing
{
// search in border vertices list (slow)
for (Border_vertex_const_iterator it = mesh_main_border_vertices_begin();
it != mesh_main_border_vertices_end();
it++)
{
if (it->vertex() == adaptor_vertex
&& (last_cw_neighbor == NULL || it->last_cw_neighbor() == last_cw_neighbor)
&& (first_cw_neighbor == NULL || it->first_cw_neighbor() == first_cw_neighbor))
{
return it;
}
}
// we should not get here
assert(false);
return NULL;
}
}
Vertex_handle get_decorated_border_vertex(
typename Adaptor::Vertex_handle adaptor_vertex,
typename Adaptor::Vertex_handle last_cw_neighbor,
typename Adaptor::Vertex_handle first_cw_neighbor)
{
// Call the const version of get_decorated_border_vertex()
Vertex_const_handle vertex_hdl = get_decorated_border_vertex(
(typename Adaptor::Vertex_const_handle)adaptor_vertex,
(typename Adaptor::Vertex_const_handle)last_cw_neighbor,
(typename Adaptor::Vertex_const_handle)first_cw_neighbor);
return const_cast<Vertex*>(&*vertex_hdl);
}
/// Debug utility: Check if a Parameterization_mesh_patch_3 facet is valid.
bool is_valid(Facet_const_handle facet) const
{
if (facet == NULL)
return false;
// outer facets are not exported
if (get_facet_seaming(facet) != INNER)
return false;
// eventually: ok
return true;
}
/// Debug utility: Check if a Parameterization_mesh_patch_3 vertex is valid.
bool is_valid(Vertex_const_handle vertex) const
{
if (vertex == NULL)
return false;
// outer vertices are not exported
if (m_mesh_adaptor.get_vertex_seaming(vertex->vertex()) == OUTER)
return false;
// prev/next vertices must be on the main border
if (vertex->last_cw_neighbor() != NULL &&
m_mesh_adaptor.get_vertex_seaming(vertex->last_cw_neighbor()) != BORDER)
return false;
if (vertex->first_cw_neighbor() != NULL &&
m_mesh_adaptor.get_vertex_seaming(vertex->first_cw_neighbor()) != BORDER)
return false;
// eventually: ok
return true;
}
/// Debug utility: get vertex index as string ("-" if NULL vertex).
std::string get_vertex_index_as_string(typename Adaptor::Vertex_const_handle vertex) const
{
if (vertex == NULL) {
return std::string("-");
} else {
char index_as_string[64];
CGAL_CLIB_STD::sprintf(index_as_string, "%d", (int)m_mesh_adaptor.get_vertex_index(vertex));
return std::string(index_as_string);
}
}
// Fields
private:
/// The decorated mesh.
Adaptor& m_mesh_adaptor;
/// List of all exported vertices.
/// Order is: inner vertices, then seam/main border ones.
Param_mesh_patch_vertex_list<Adaptor> m_inner_and_border_vertices;
/// Iterator to first seam vertex inside m_inner_and_border_vertices.
Border_vertex_iterator m_seam_begin;
// Private types
private:
/// Utility class to generate the Facet_iterator type.
struct Inner_facets_filter
{
Inner_facets_filter(const Parameterization_mesh_patch_3& mesh) : m_mesh_patch(mesh) {}
/// Return TRUE <=> the facet IS NOT EXPORTED by Parameterization_mesh_patch_3,
/// ie is out of the topological disc.
bool operator()(const typename Adaptor::Facet_iterator& f) const {
return m_mesh_patch.get_facet_seaming(f) == OUTER;
}
bool operator()(const typename Adaptor::Facet_const_iterator& f) const {
return m_mesh_patch.get_facet_seaming(f) == OUTER;
}
private:
const Parameterization_mesh_patch_3& m_mesh_patch;
};
// Friends
friend class Param_mesh_patch_vertex<Adaptor>;
friend class Param_mesh_patch_vertex_handle<Adaptor>;
friend class Param_mesh_patch_vertex_const_handle<Adaptor>;
friend class Param_mesh_patch_vertex_list_iterator<Adaptor>;
friend class Param_mesh_patch_vertex_list_const_iterator<Adaptor>;
friend class Mesh_patch_vertex_around_facet_cir<Parameterization_mesh_patch_3,
Vertex_handle,
typename Adaptor::Vertex_around_facet_circulator>;
friend class Mesh_patch_vertex_around_facet_cir<const Parameterization_mesh_patch_3,
Vertex_const_handle,
typename Adaptor::Vertex_around_facet_const_circulator>;
friend class Mesh_patch_vertex_around_vertex_cir<Parameterization_mesh_patch_3,
Vertex_handle,
typename Adaptor::Vertex_around_vertex_circulator,
typename Adaptor::Vertex_handle>;
friend class Mesh_patch_vertex_around_vertex_cir<const Parameterization_mesh_patch_3,
Vertex_const_handle,
typename Adaptor::Vertex_around_vertex_const_circulator,
typename Adaptor::Vertex_const_handle>;
}; // Parameterization_mesh_patch_3
CGAL_END_NAMESPACE
#endif //CGAL_SURFACE_MESH_PARAMETERIZATION_MESH_PATCH_3_H
|