Developer Documentation
PolyLineT_impl.hh
1 /*===========================================================================*\
2  * *
3  * OpenFlipper *
4  * Copyright (c) 2001-2015, RWTH-Aachen University *
5  * Department of Computer Graphics and Multimedia *
6  * All rights reserved. *
7  * www.openflipper.org *
8  * *
9  *---------------------------------------------------------------------------*
10  * This file is part of OpenFlipper. *
11  *---------------------------------------------------------------------------*
12  * *
13  * Redistribution and use in source and binary forms, with or without *
14  * modification, are permitted provided that the following conditions *
15  * are met: *
16  * *
17  * 1. Redistributions of source code must retain the above copyright notice, *
18  * this list of conditions and the following disclaimer. *
19  * *
20  * 2. Redistributions in binary form must reproduce the above copyright *
21  * notice, this list of conditions and the following disclaimer in the *
22  * documentation and/or other materials provided with the distribution. *
23  * *
24  * 3. Neither the name of the copyright holder nor the names of its *
25  * contributors may be used to endorse or promote products derived from *
26  * this software without specific prior written permission. *
27  * *
28  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
29  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
30  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
31  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
32  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
33  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
34  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
35  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
36  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
37  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
38  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
39  * *
40 \*===========================================================================*/
41 
42 
43 
44 
45 
46 //=============================================================================
47 //
48 // CLASS PolyLineT - IMPLEMENTATION
49 //
50 //=============================================================================
51 
52 #define ACG_POLYLINET_C
53 
54 //== INCLUDES =================================================================
55 
56 #include <OpenMesh/Core/Geometry/VectorT.hh>
57 
58 #include <iostream>
59 #include <fstream>
60 #include <map>
61 #include <stack>
62 
63 #include "PolyLineT.hh"
64 
65 #include <cfloat>
66 #include <ACG/Geometry/Algorithms.hh>
67 #include <ACG/Utils/VSToolsT.hh>
68 
69 #ifndef WIN32
70 #include <cstdlib>
71 #endif
72 
73 #include <cstring>
74 
75 #ifdef USE_OPENMP
76 #include <omp.h>
77 #endif
78 
79 //== NAMESPACES ===============================================================
80 
81 namespace ACG {
82 
83 //== IMPLEMENTATION ==========================================================
84 
85 //-----------------------------------------------------------------------------
86 
87 
89 template <class PointT>
91  PolyLineT( bool _closed )
92  : closed_(_closed),
93  vertex_radius_(0.01),
94  edge_radius_(0.01),
95  ref_count_vnormals_(0),
96  ref_count_vbinormals_(0),
97  ref_count_vcolors_(0),
98  ref_count_vscalars_(0),
99  ref_count_vselections_(0),
100  ref_count_vvhandles_(0),
101  ref_count_vehandles_(0),
102  ref_count_vfhandles_(0),
103  ref_count_enormals_(0),
104  ref_count_ecolors_(0),
105  ref_count_escalars_(0),
106  ref_count_eselections_(0),
107  ref_count_epreimage_direction_(0)
108 {
109 }
110 
111 //-----------------------------------------------------------------------------
112 
114 template <class PointT>
116  PolyLineT( const PolyLineT& _line ) :
117 
118  //copy points
119  points_(_line.points_),
120 
121  closed_(_line.closed_),
122 
123  //copy vertex properties
124  vnormals_(_line.vnormals_),
125  vbinormals_(_line.vbinormals_),
126  vcolors_(_line.vcolors_),
127  vscalars_(_line.vscalars_),
128  vselections_(_line.vselections_),
129  vvhandles_(_line.vvhandles_),
130  vehandles_(_line.vehandles_),
131  vfhandles_(_line.vfhandles_),
132 
133  //copy edge properties
134  enormals_(_line.enormals_),
135  ecolors_(_line.ecolors_),
136  escalars_(_line.escalars_),
137  eselections_(_line.eselections_),
138  epreimage_direction_(_line.epreimage_direction_),
139 
140  // property reference counter
141  ref_count_vnormals_(_line.ref_count_vnormals_),
142  ref_count_vbinormals_(_line.ref_count_vbinormals_),
143  ref_count_vcolors_(_line.ref_count_vcolors_),
144  ref_count_vscalars_(_line.ref_count_vscalars_),
145  ref_count_vselections_(_line.ref_count_vselections_),
146  ref_count_vvhandles_(_line.ref_count_vvhandles_),
147  ref_count_vehandles_(_line.ref_count_vehandles_),
148  ref_count_vfhandles_(_line.ref_count_vfhandles_),
149 
150  ref_count_enormals_(_line.ref_count_enormals_),
151  ref_count_ecolors_(_line.ref_count_ecolors_),
152  ref_count_escalars_(_line.ref_count_escalars_),
153  ref_count_eselections_(_line.ref_count_eselections_),
154  ref_count_epreimage_direction_(_line.ref_count_epreimage_direction_)
155 
156 {
157 
158  // copy custom properties
159  for (typename CustomPropertyMap::const_iterator it = _line.custom_properties.begin(); it != _line.custom_properties.end(); ++it) {
160 
161  const CustomProperty* src = it->second;
162  CustomProperty* dst = new CustomProperty;
163 
164  dst->name = src->name;
165  dst->ref_count = src->ref_count;
166  dst->prop_size = src->prop_size;
167  dst->prop_data = src->prop_data;
168 
169  dst->datatype = src->datatype;
170  dst->shader_binding = src->shader_binding;
171 
172  custom_properties[it->first] = dst;
173  }
174 }
175 
176 //-----------------------------------------------------------------------------
177 
178 
179 template <class PointT>
180 void
183 {
184  points_.clear();
185 
186  // clear propertiy vectors
187  vnormals_.clear();
188  vbinormals_.clear();
189  vcolors_.clear();
190  vscalars_.clear();
191  vselections_.clear();
192  vvhandles_.clear();
193  vehandles_.clear();
194  vfhandles_.clear();
195 
196  enormals_.clear();
197  ecolors_.clear();
198  escalars_.clear();
199  eselections_.clear();
200  epreimage_direction_.clear();
201 
202  for (typename CustomPropertyMap::iterator it = custom_properties.begin(); it != custom_properties.end(); ++it)
203  delete it->second;
204  custom_properties.clear();
205 }
206 
207 //-----------------------------------------------------------------------------
208 
209 template <class PointT>
210 size_t
212 {
213  if (n_vertices() <= 1)
214  return 0;
215  else
216  return n_vertices() - 1 + (unsigned int) closed_;
217 }
218 
219 
220 //-----------------------------------------------------------------------------
221 
222 
223 template <class PointT>
224 void
226 resize( unsigned int _n)
227 {
228  if( _n < n_vertices())
229  {
230 
231  points_.resize( _n);
232 
233  // clear propertiy vectors
234  if( vertex_normals_available() )
235  vnormals_.resize( _n);
236  if( vertex_binormals_available() )
237  vbinormals_.resize( _n);
238  if( vertex_colors_available())
239  vcolors_.resize( _n);
240  if( vertex_scalars_available())
241  vscalars_.resize( _n);
242  if( vertex_selections_available())
243  vselections_.resize( _n);
244  if( vertex_vhandles_available())
245  vvhandles_.resize( _n);
246  if( vertex_ehandles_available())
247  vehandles_.resize( _n);
248  if( vertex_fhandles_available())
249  vfhandles_.resize( _n);
250 
251  if( edge_normals_available())
252  enormals_.resize( _n);
253  if( edge_colors_available())
254  ecolors_.resize( _n);
255  if( edge_scalars_available())
256  escalars_.resize( _n);
257  if( edge_preimage_directions_available())
258  epreimage_direction_.resize( _n);
259 
260 
261  for (typename CustomPropertyMap::iterator it = custom_properties.begin(); it != custom_properties.end(); ++it) {
262 
263  CustomProperty* p = it->second;
264 
265  p->prop_data.resize(p->prop_size * _n);
266  }
267 
268  }
269  else
270  {
271  while( n_vertices() < _n)
272  add_point( Point());
273  }
274 }
275 
276 
277 //-----------------------------------------------------------------------------
278 
279 
280 template <class PointT>
281 void
283 add_point(const Point& _p)
284 {
285  // add new point
286  points_.push_back( _p );
287 
288  // add available properties
289  if( vertex_normals_available() )
290  vnormals_.push_back( Point(0,0,0));
291 
292  if( vertex_binormals_available() )
293  vbinormals_.push_back( Point(0,0,0));
294 
295  if( vertex_colors_available())
296  vcolors_.push_back( Point(1,0,1));
297 
298  if( vertex_scalars_available())
299  vscalars_.push_back( 0.0 );
300 
301  if( vertex_selections_available())
302  vselections_.push_back( false);
303 
304  if( vertex_vhandles_available())
305  vvhandles_.push_back(-1);
306 
307  if( vertex_ehandles_available())
308  vehandles_.push_back(-1);
309 
310  if( vertex_fhandles_available())
311  vfhandles_.push_back(-1);
312 
313  if( edge_normals_available())
314  enormals_.push_back( Point(0,0,0));
315 
316  if( edge_colors_available())
317  ecolors_.push_back( Point(1,0,1));
318 
319  if( edge_scalars_available())
320  escalars_.push_back( 0.0);
321 
322  if( edge_selections_available())
323  eselections_.push_back(false);
324 
325  if( edge_preimage_directions_available())
326  epreimage_direction_.push_back(Point(0,0,0));
327 
328 
329  for (typename CustomPropertyMap::iterator it = custom_properties.begin(); it != custom_properties.end(); ++it) {
330 
331  CustomProperty* p = it->second;
332 
333  size_t cur_size = p->prop_data.size();
334 
335  p->prop_data.resize(cur_size + p->prop_size);
336 
337  if (p->buffer())
338  memset(p->buffer() + cur_size, 0, p->prop_size);
339  }
340 }
341 
342 //-----------------------------------------------------------------------------
343 
344 template <class PointT>
345 void
347 insert_point(int _idx, const Point& _p)
348 {
349  assert(_idx < (int)n_vertices() );
350 
351  // insert new point
352  points_.insert(points_.begin()+_idx, _p);
353 
354  // insert available properties
355  if( vertex_normals_available() )
356  vnormals_.insert(vnormals_.begin()+_idx, Point(0,0,0));
357 
358  if( vertex_binormals_available() )
359  vbinormals_.insert(vbinormals_.begin()+_idx, Point(0,0,0));
360 
361  if( vertex_colors_available())
362  vcolors_.insert(vcolors_.begin()+_idx, Point(1,0,1));
363 
364  if( vertex_scalars_available())
365  vscalars_.insert(vscalars_.begin()+_idx, 0.0 );
366 
367  if( vertex_selections_available())
368  vselections_.insert(vselections_.begin()+_idx, false);
369 
370  if( vertex_vhandles_available())
371  vvhandles_.insert(vvhandles_.begin()+_idx, -1);
372 
373  if( vertex_ehandles_available())
374  vehandles_.insert(vehandles_.begin()+_idx, -1);
375 
376  if( vertex_fhandles_available())
377  vfhandles_.insert(vfhandles_.begin()+_idx, -1);
378 
379  if( edge_normals_available())
380  enormals_.insert(enormals_.begin()+_idx, Point(0,0,0));
381 
382  if( edge_colors_available())
383  ecolors_.insert(ecolors_.begin()+_idx, Point(1,0,1));
384 
385  if( edge_scalars_available())
386  escalars_.insert(escalars_.begin()+_idx, 0.0);
387 
388  if( edge_selections_available())
389  eselections_.insert(eselections_.begin()+_idx, false);
390 
391  if( edge_preimage_directions_available())
392  epreimage_direction_.insert(epreimage_direction_.begin()+_idx, Point(0,0,0));
393 
394  // custom properties: insert byte-wise
395  for (typename CustomPropertyMap::iterator it = custom_properties.begin(); it != custom_properties.end(); ++it) {
396 
397  CustomProperty* p = it->second;
398  unsigned int offset = p->prop_size * _idx;
399 
400  for (unsigned int i = 0; i < p->prop_size; ++i)
401  p->prop_data.insert(p->prop_data.begin() + offset, 0);
402  }
403 }
404 
405 
406 //-----------------------------------------------------------------------------
407 
408 
409 template <class PointT>
410 void
412 delete_point(int _idx)
413 {
414  assert(_idx < (int)n_vertices() );
415 
416  // delete point at given index
417  points_.erase(points_.begin()+_idx);
418 
419 
420  // delete available properties
421  if( vertex_normals_available() )
422  vnormals_.erase(vnormals_.begin()+_idx);
423 
424  if( vertex_binormals_available() )
425  vbinormals_.erase(vbinormals_.begin()+_idx);
426 
427  if( vertex_colors_available())
428  vcolors_.erase(vcolors_.begin()+_idx);
429 
430  if( vertex_scalars_available())
431  vscalars_.erase(vscalars_.begin()+_idx);
432 
433  if( vertex_selections_available())
434  vselections_.erase(vselections_.begin()+_idx);
435 
436  if( vertex_vhandles_available())
437  vvhandles_.erase(vvhandles_.begin()+_idx);
438 
439  if( vertex_ehandles_available())
440  vehandles_.erase(vehandles_.begin()+_idx);
441 
442  if( vertex_fhandles_available())
443  vfhandles_.erase(vfhandles_.begin()+_idx);
444 
445  if( edge_normals_available())
446  enormals_.erase(enormals_.begin()+_idx);
447 
448  if( edge_colors_available())
449  ecolors_.erase(ecolors_.begin()+_idx);
450 
451  if( edge_scalars_available())
452  escalars_.erase(escalars_.begin()+_idx);
453 
454  if( edge_selections_available())
455  eselections_.erase(eselections_.begin()+_idx);
456 
457  if( edge_preimage_directions_available())
458  epreimage_direction_.erase(epreimage_direction_.begin()+_idx);
459 
460 
461  // custom properties: delete byte-wise
462  for (typename CustomPropertyMap::iterator it = custom_properties.begin(); it != custom_properties.end(); ++it) {
463 
464  CustomProperty* p = it->second;
465  unsigned int offset = p->prop_size * _idx;
466 
467  for (unsigned int i = 0; i < p->prop_size; ++i)
468  p->prop_data.erase(p->prop_data.begin() + offset);
469  }
470 }
471 
472 
473 //-----------------------------------------------------------------------------
474 
475 
476 template <class PointT>
477 typename PolyLineT<PointT>::Scalar
479 length() const
480 {
481  Scalar l = 0;
482 
483  unsigned int n = points_.size();
484 
485  if(!closed_)
486  {
487  for(unsigned int i=0; i<n-1; ++i)
488  {
489  l += (points_[(i+1)]-points_[i]).norm();
490  }
491  }
492  else
493  {
494  for(unsigned int i=0; i<n; ++i)
495  {
496  l += (points_[(i+1)%n]-points_[i]).norm();
497  }
498  }
499 
500  return l;
501 }
502 
503 
504 //-----------------------------------------------------------------------------
505 
506 
507 template <class PointT>
508 typename PolyLineT<PointT>::Point
510 position(const Scalar _t) const
511 {
512  assert(_t >=0.0 && _t<=1.0);
513  return position_arclength(_t*this->length());
514 }
515 
516 
517 //-----------------------------------------------------------------------------
518 
519 
520 template <class PointT>
521 typename PolyLineT<PointT>::Point
523 position_arclength(const Scalar _t) const
524 {
525  // handle degenerate polyline cases
526  if(this->n_vertices() < 2)
527  {
528  if(this->n_vertices() == 1)
529  return this->front();
530  else
531  {
532  std::cerr << "Warning: called position_arclength on emptu PolyLine!!!" << std::endl;
533  return Point(0,0,0);
534  }
535  }
536 
537  // return beginning of curve for negative parameter value
538  if(_t < 0.0)
539  return this->front();
540 
541  unsigned int nv = this->n_vertices();
542  unsigned int ne = this->n_edges();
543 
544  Scalar l = 0;
545 
546  for(unsigned int i=0; i<ne; ++i)
547  {
548  Scalar dl = (points_[(i+1)%nv]-points_[i]).norm();
549 
550  if(l <= _t && _t <= (l+dl))
551  {
552  Scalar tl = (_t-l)/dl;
553  if(!std::isfinite(tl))
554  tl = 0.0;
555  return (tl*points_[(i+1)%nv] + (1.0-tl)*points_[i]);
556  }
557 
558  l += dl;
559  }
560 
561  // return end of curve for too large parameter values
562  if(!closed_)
563  return this->back();
564  else
565  return this->front();
566 }
567 
568 
569 //-----------------------------------------------------------------------------
570 
571 
572 template <class PointT>
573 void
575 resample_arclength_uniform(const unsigned int _n)
576 {
577  unsigned int n = std::max((unsigned int)(2),_n);
578  Scalar l = this->length();
579 
580  // add new polyline with similar properties
581  PolyLineT<PointT> new_pl = *this;
582  // copy first point
583  new_pl.resize(n);
584  new_pl.copy_vertex_complete(*this, 0, 0);
585 
586  if(!closed_)
587  {
588  Scalar s = l/Scalar(n-1);
589  for(unsigned int i=1; i<n-1; ++i)
590  new_pl.point(i) = this->position_arclength(i*s);
591  }
592  else
593  {
594  Scalar s = l/Scalar(n);
595  for(unsigned int i=1; i<n; ++i)
596  new_pl.point(i) = this->position_arclength(i*s);
597  }
598 
599  // copy last point
600  if(!closed_)
601  new_pl.copy_vertex_complete(*this, std::max(int(0),int(this->n_vertices())-1), std::max(int(0),int(new_pl.n_vertices())-1));
602 
603  // update polyline
604  *this = new_pl;
605 }
606 
607 
608 //-----------------------------------------------------------------------------
609 
610 
611 template <class PointT>
612 void
614 subdivide(Scalar _largest)
615 {
616  // check validity
617  if (!n_vertices())
618  return;
619 
620  unsigned int n_subdivisions = 1;
621 
622  while (n_subdivisions != 0) {
623 
624  n_subdivisions = 0;
625 
626  // add new polyline and add first point
627  PolyLineT<PointT> new_pl = *this;
628  new_pl.resize(1);
629  new_pl.copy_vertex_complete(*this, 0, 0);
630 
631  // squared maximal length
632  Scalar l2 = _largest * _largest;
633 
634  for (unsigned int i = 1; i < points_.size(); ++i) {
635  if ((new_pl.point(new_pl.n_vertices() - 1) - points_[i]).sqrnorm() > l2) {
636  Point mid_point = (new_pl.point(new_pl.n_vertices() - 1) + points_[i]) * 0.5;
637 
638  new_pl.add_point(mid_point);
639  ++n_subdivisions;
640  }
641 
642  // copy vertex
643  new_pl.resize(new_pl.n_vertices() + 1);
644  new_pl.copy_vertex_complete(*this, i, new_pl.n_vertices() - 1);
645  }
646 
647  // last interval for closed polyline
648  if (closed_) {
649  if ((new_pl.point(new_pl.n_vertices() - 1) - points_[0]).sqrnorm() > l2) {
650  Point mid_point = (new_pl.point(new_pl.n_vertices() - 1) + points_[0]) * 0.5;
651  new_pl.add_point(mid_point);
652  ++n_subdivisions;
653  }
654  }
655 
656  // update points
657  *this = new_pl;
658  }
659 }
660 
661 //-----------------------------------------------------------------------------
662 
663 
664 template <class PointT>
665 void
667 collapse(Scalar _smallest)
668 {
669  // check validity
670  if(!n_vertices()) return;
671 
672  unsigned int n_collapses = 1;
673 
674  unsigned int n_iter = 0;
675 
676  while( n_collapses != 0 && n_iter < 5)
677  {
678  ++n_iter;
679  n_collapses = 0;
680 
681  // create new PolyLine (with all properties) and insert first point
682  PolyLineT<PointT> new_pl = *this;
683  new_pl.resize(1);
684  new_pl.copy_vertex_complete( *this, 0, 0);
685 
686  // squared maximal length
687  Scalar l2 = _smallest*_smallest;
688 
689  for(unsigned int i=1; i<points_.size(); ++i)
690  {
691  // check whether vertex is selected
692  bool vertex_selected = false;
693  if( vertex_selections_available() && vertex_selection(i))
694  vertex_selected = true;
695 
696  if( (new_pl.point(new_pl.n_vertices()-1) - points_[i]).sqrnorm() >= l2 ||
697  vertex_selected ||
698  (!closed_ && i==points_.size()-1) )
699  {
700  // copy next point
701  new_pl.resize( new_pl.n_vertices()+1);
702  new_pl.copy_vertex_complete( *this, i, new_pl.n_vertices()-1);
703  }
704  else ++n_collapses;
705  }
706 
707  // last interval for closed polyline
708  if( closed_)
709  {
710  // check whether vertex is selected
711  bool vertex_selected = false;
712  if( vertex_selections_available() && vertex_selection(points_.size()-1))
713  vertex_selected = true;
714 
715  if( (new_pl.point(new_pl.n_vertices()-1) - points_[0]).sqrnorm() < l2 && !vertex_selected)
716  {
717  new_pl.resize( new_pl.n_vertices()-1);
718  }
719  else ++n_collapses;
720  }
721 
722  // update points
723  *this = new_pl;
724  }
725 }
726 
727 
728 //-----------------------------------------------------------------------------
729 
730 template <class PointT>
731 void
734 {
735  // copy point positions
736  std::vector<Point> points_old( points_ );
737 
738  int n = points_.size();
739 
740  int is = 0;
741  int ie = n;
742 
743  if( !closed_ )
744  {
745  ++is;
746  --ie;
747  }
748 
749  if( vertex_selections_available())
750  {
751  #ifdef USE_OPENMP
752  #pragma omp parallel for
753  #endif
754  for( int i=is; i<ie; ++i)
755  {
756  // only smooth not selected vertices
757  if( !vertex_selection(i))
758  // laplace stencil 1,-2,1
759  points_[i] = (points_old[ (i-1+n)%n ] +
760  points_old[ (i+n )%n ]*2.0 +
761  points_old[ (i+1 )%n ] )*0.25;
762 
763  }
764  }
765  else
766  {
767  #ifdef USE_OPENMP
768  #pragma omp parallel for
769  #endif
770  for( int i=is; i<ie; ++i)
771  {
772  // laplace stencil 1,-2,1
773  points_[i] = (points_old[ (i-1+n)%n ] +
774  points_old[ (i+n )%n ] * 2.0 +
775  points_old[ (i+1 )%n ] )*0.25;
776  }
777  }
778 }
779 
780 
781 //-----------------------------------------------------------------------------
782 
783 
784 template <class PointT>
785 void
788 {
789  // copy point positions
790  std::vector<Point> points_old( points_ );
791 
792  int n = points_.size();
793 
794  int is = 0;
795  int ie = n;
796 
797  if( !closed_ )
798  {
799  is+=2;
800  ie-=2;
801  }
802 
803  if( vertex_selections_available())
804  {
805  #ifdef USE_OPENMP
806  #pragma omp parallel for
807  #endif
808  for(int i=is; i<ie; ++i)
809  {
810  // only smooth not selected vertices
811  if( !vertex_selection(i))
812  // laplace^2 stencil 1,-4,6,-4,1
813  points_[i] -= (points_old[ (i-2+2*n)%n ] +
814  points_old[ (i-1+2*n)%n ]*-4.0 +
815  points_old[ (i )%n ]* 6.0 +
816  points_old[ (i+1 )%n ]*-4.0 +
817  points_old[ (i+2 )%n ] )/(16.0*2.0);
818  }
819  }
820  else
821  {
822  #ifdef USE_OPENMP
823  #pragma omp parallel for
824  #endif
825  for(int i=is; i<ie; ++i)
826  {
827  // laplace^2 stencil 1,-4,6,-4,1
828  points_[i] -= (points_old[ (i-2+2*n)%n ] +
829  points_old[ (i-1+2*n)%n ]*-4.0 +
830  points_old[ (i )%n ]* 6.0 +
831  points_old[ (i+1 )%n ]*-4.0 +
832  points_old[ (i+2 )%n ] )/(16.0*2.0);
833  }
834  }
835 }
836 
837 
838 //-----------------------------------------------------------------------------
839 
840 
841 template <class PointT>
842 void
845 {
846  // copy point positions
847  std::vector<Point> points_old( points_ );
848 
849  int n = points_.size();
850 
851  int is = 0;
852  int ie = n;
853 
854  if( !closed_ )
855  {
856  is+=3;
857  ie-=3;
858  }
859 
860  if( vertex_selections_available())
861  {
862  #ifdef USE_OPENMP
863  #pragma omp parallel for
864  #endif
865  for( int i=is; i<ie; ++i)
866  {
867  // only smooth not selected vertices
868  if( !vertex_selection(i))
869  // laplace^3 stencil 1,-6,15,-20,15,-6,1
870  points_[i] = (points_old[ (i-3+3*n)%n ] +
871  points_old[ (i-2+3*n)%n ]*(-6.0) +
872  points_old[ (i-1+3*n)%n ]*15.0 +
873  points_old[ (i ) ]*(44.0) +
874  points_old[ (i+1 )%n ]*15.0 +
875  points_old[ (i+2 )%n ]*(-6.0) +
876  points_old[ (i+3 )%n ] )/64.0;
877 
878  }
879  }
880  else
881  {
882  #ifdef USE_OPENMP
883  #pragma omp parallel for
884  #endif
885  for( int i=is; i<ie; ++i)
886  {
887  // laplace^3 stencil 1,-6,15,-20,15,-6,1
888  points_[i] = (points_old[ (i-3+3*n)%n ] +
889  points_old[ (i-2+3*n)%n ]*(-6.0) +
890  points_old[ (i-1+3*n)%n ]*15.0 +
891  points_old[ (i ) ]*(44.0) +
892  points_old[ (i+1 )%n ]*15.0 +
893  points_old[ (i+2 )%n ]*(-6.0) +
894  points_old[ (i+3 )%n ] )/64.0;
895  }
896  }
897 }
898 
899 
900 //-----------------------------------------------------------------------------
901 
902 
903 template <class PointT>
904 void
906 set_to_circle(const PointT _center, const PointT _normal, double _radius, unsigned int _n_samples)
907 {
908  this->clear();
909  this->set_closed(true);
910 
911  // get local basis vectors
912  PointT n = _normal; n.normalize();
913  PointT u = ACG::Geometry::perpendicular(_normal); u*=_radius/u.norm();
914  PointT v = n % u;
915 
916  for(unsigned int i=0; i<_n_samples; ++i)
917  {
918  double alpha = double(i)*2.0*M_PI/double(_n_samples);
919 
920  this->add_point(_center + u*cos(alpha) + v*sin(alpha));
921  }
922 }
923 
924 
925 //-----------------------------------------------------------------------------
926 
927 
928 template <class PointT>
929 template <class MeshT, class SpatialSearchT>
930 void
932 project_to_mesh( const MeshT& _mesh, SpatialSearchT * _ssearch)
933 {
934  typename MeshT::FaceHandle fh;
935 
936  #ifdef USE_OPENMP
937  #pragma omp parallel for
938  #endif
939  for(unsigned int i=0; i<points_.size(); ++i)
940  {
941  points_[i] = find_nearest_point( _mesh, points_[i], fh, _ssearch);
942  }
943 }
944 
945 
946 //-----------------------------------------------------------------------------
947 
948 
949 template <class PointT>
950 template <class MeshT, class SpatialSearchT>
951 void
953 project_to_mesh( const std::vector<MeshT*>& _mesh,
954  std::vector<SpatialSearchT*>* _ssearch)
955 {
956  typename MeshT::FaceHandle fh;
957 
958  #ifdef USE_OPENMP
959  #pragma omp parallel for
960  #endif
961  for(int i=0; i< (int)points_.size(); ++i)
962  {
963  // init d_best
964  typename MeshT::Scalar d_best = -1;
965 
966  // best point
967  Point p_best(0,0,0);
968 
969  // iterate over all possible meshes
970  for(unsigned int j=0; j<_mesh.size(); ++j)
971  {
972  double d_new(-1);
973 
974  Point p_new;
975  if(_ssearch != 0)
976  p_new = find_nearest_point( *(_mesh[j]), points_[i], fh, ((*_ssearch)[j]), &d_new);
977  else
978  p_new = find_nearest_point( *(_mesh[j]), points_[i], fh, (SpatialSearchT*)0, &d_new);
979 
980  // store best result
981  if( d_new < d_best || d_best == -1)
982  {
983  p_best = p_new;
984  d_best = d_new;
985  }
986  }
987 
988  if( d_best != -1)
989  points_[i] = p_best;
990  }
991 }
992 
993 
994 //-----------------------------------------------------------------------------
995 
996 
997 template <class PointT>
998 template <class MeshT, class SpatialSearchT>
999 typename PolyLineT<PointT>::Point
1001 find_nearest_point( const MeshT& _mesh,
1002  const Point& _point,
1003  typename MeshT::FaceHandle& _fh,
1004  SpatialSearchT * _ssearch,
1005  double* _dbest)
1006 {
1007  typename MeshT::Point p0 = (typename MeshT::Point) _point;
1008 
1009  typename MeshT::Point p_best = _mesh.point(_mesh.vertex_handle(0));
1010  typename MeshT::Scalar d_best = (p0 - p_best).sqrnorm();
1011 
1012  typename MeshT::FaceHandle fh_best;
1013 
1014  if (_ssearch == 0) {
1015  // exhaustive search
1016  typename MeshT::ConstFaceIter cf_it = _mesh.faces_begin();
1017  typename MeshT::ConstFaceIter cf_end = _mesh.faces_end();
1018 
1019  for (; cf_it != cf_end; ++cf_it) {
1020  typename MeshT::ConstFaceVertexIter cfv_it = _mesh.cfv_iter(*cf_it);
1021 
1022  const typename MeshT::Point& pt0 = _mesh.point(*cfv_it);
1023  const typename MeshT::Point& pt1 = _mesh.point(*(++cfv_it));
1024  const typename MeshT::Point& pt2 = _mesh.point(*(++cfv_it));
1025 
1026  typename MeshT::Point ptn;
1027 
1028  typename MeshT::Scalar d = Geometry::distPointTriangleSquared(p0, pt0, pt1, pt2, ptn);
1029 
1030  if (d < d_best) {
1031  d_best = d;
1032  p_best = ptn;
1033 
1034  fh_best = *cf_it;
1035  }
1036  }
1037 
1038  // return face handle
1039  _fh = fh_best;
1040 
1041  // return distance
1042  if (_dbest)
1043  *_dbest = sqrt(d_best);
1044 
1045  return (Point) p_best;
1046  } else {
1047  typename MeshT::FaceHandle fh = _ssearch->nearest(p0).handle;
1048  typename MeshT::CFVIter fv_it = _mesh.cfv_iter(fh);
1049 
1050  const typename MeshT::Point& pt0 = _mesh.point(*fv_it);
1051  const typename MeshT::Point& pt1 = _mesh.point(*(++fv_it));
1052  const typename MeshT::Point& pt2 = _mesh.point(*(++fv_it));
1053 
1054  // project
1055  d_best = Geometry::distPointTriangleSquared(p0, pt0, pt1, pt2, p_best);
1056 
1057  // return facehandle
1058  _fh = fh;
1059 
1060  // return distance
1061  if (_dbest)
1062  *_dbest = sqrt(d_best);
1063 
1064  return (Point) p_best;
1065  }
1066 }
1067 
1068 //-----------------------------------------------------------------------------
1069 
1070 
1071 template <class PointT>
1072 template <class LineNodeT>
1073 LineNodeT*
1075 get_line_node(LineNodeT*& _line_node, int _mode)
1076 {
1077  typedef typename LineNodeT::value_type Vec3fL;
1078 
1079  if (_mode == 0) {
1080  // LineSegmentsMode
1081 
1082  // create LineNode
1083  _line_node = new LineNodeT(LineNodeT::LineSegmentsMode, 0, "PolyLine");
1084  _line_node->set_line_width(5.0);
1085  // _line_node->set_base_color(Vec4f(0,1,0,0));
1086  _line_node->set_base_color(
1087  OpenMesh::Vec4f(0.2 + double(rand()) / double(RAND_MAX) * 0.8, 0.2 + double(rand()) / double(RAND_MAX) * 0.8,
1088  0.2 + double(rand()) / double(RAND_MAX) * 0.8, 1.0));
1089 
1090  _line_node->show();
1091 
1092  // add line node
1093  for (unsigned int i = 0; i < this->points().size() - 1; ++i) {
1094  _line_node->add_line((Vec3fL) this->points()[i], (Vec3fL) this->points()[i + 1]);
1095  }
1096 
1097  // close loop
1098  if (closed_)
1099  if (!this->points().empty()) {
1100  _line_node->add_point((Vec3fL) this->points()[0]);
1101  }
1102 
1103  return _line_node;
1104  } else {
1105  // create LineNode
1106  _line_node = new LineNodeT(LineNodeT::PolygonMode, 0, "PolyLine");
1107  _line_node->set_line_width(5.0);
1108  // _line_node->set_base_color(Vec4f(0,1,0,0));
1109  _line_node->set_base_color(
1110  OpenMesh::Vec4f(0.2 + double(rand()) / double(RAND_MAX) * 0.8, 0.2 + double(rand()) / double(RAND_MAX) * 0.8,
1111  0.2 + double(rand()) / double(RAND_MAX) * 0.8, 1.0));
1112 
1113  _line_node->show();
1114 
1115  // add line node
1116  for (unsigned int i = 0; i < this->points().size(); ++i) {
1117  _line_node->add_point((Vec3fL) this->points()[i]);
1118  }
1119 
1120  // close loop
1121  if (closed_)
1122  if (!this->points().empty()) {
1123  _line_node->add_point((Vec3fL) this->points()[0]);
1124  }
1125 
1126  return _line_node;
1127  }
1128 }
1129 
1130 
1131 //-----------------------------------------------------------------------------
1132 
1133 
1134 template <class PointT>
1135 template <class LineNodeT>
1136 void
1138 set_line_node(LineNodeT*& _line_node, int _mode)
1139 {
1140  // typedef typename LineNodeT::value_type Vec3fL;
1141 
1142  // clear old values
1143  clear();
1144 
1145  if (_mode == 0) {
1146  // assume LineSegmentsMode
1147 
1148  const typename LineNodeT::PointVector& ln_points = _line_node->points();
1149 
1150  for (unsigned int i = 0; i < ln_points.size();) {
1151  if (i != ln_points.size() - 1)
1152  add_point((Point) ln_points[i]);
1153  else {
1154  // last point
1155  if ((ln_points[ln_points.size() - 1] - ln_points[0]).sqrnorm() == 0) {
1156  closed_ = true;
1157  } else {
1158  closed_ = false;
1159  add_point((Point) ln_points[i]);
1160  }
1161  }
1162 
1163  // increase counter
1164  if (i == 0)
1165  i += 1;
1166  else
1167  i += 2;
1168  }
1169  } else {
1170  // assume PolygonMode
1171  closed_ = true;
1172 
1173  const typename LineNodeT::PointVector& ln_points(_line_node->points());
1174 
1175  for (unsigned int i = 0; i < ln_points.size(); ++i) {
1176  add_point((Point) ln_points[i]);
1177  }
1178  }
1179 }
1180 
1181 
1182 //-----------------------------------------------------------------------------
1183 
1184 
1185 template <class PointT>
1186 void
1188 print() const
1189 {
1190  std::cerr << "****** PolyInfo ******\n";
1191  std::cerr << "closed : " << closed_ << std::endl;
1192  std::cerr << "#points: " << points_.size() << std::endl;
1193  for(unsigned int i=0; i<points_.size(); ++i)
1194  std::cerr << points_[i] << std::endl;
1195 }
1196 
1197 
1198 //-----------------------------------------------------------------------------
1199 
1200 
1201 template <class PointT>
1202 template <class PropT>
1203 void
1205 request_prop( unsigned int& _ref_count, PropT& _prop)
1206 {
1207  if(_ref_count == 0)
1208  {
1209  _ref_count = 1;
1210  // always use vertex size!!!
1211  _prop.resize(n_vertices());
1212  }
1213  else ++_ref_count;
1214 }
1215 
1216 
1217 //-----------------------------------------------------------------------------
1218 
1219 
1220 template <class PointT>
1221 template <class PropT>
1222 void
1224 release_prop( unsigned int& _ref_count, PropT& _prop)
1225 {
1226  if( _ref_count <= 1)
1227  {
1228  _ref_count = 0;
1229  _prop.clear();
1230  }
1231  else --_ref_count;
1232 }
1233 
1234 
1235 //-----------------------------------------------------------------------------
1236 
1237 
1238 template <class PointT>
1239 void
1241 copy_vertex_complete(const PolyLineT<PointT>& _pl, unsigned int _i, unsigned int _j)
1242 {
1243  // check range
1244  if( n_vertices() <= _j || _pl.n_vertices() <= _i)
1245  {
1246  std::cerr << "Warning: invalid range in PolyLine::copy_vertex_complete ( "
1247  << _i << " " << _j << " ) " << std::endl;
1248  return;
1249  }
1250 
1251  // copy point position
1252  point(_j) = _pl.point(_i);
1253 
1254  // copy properties if available
1255 
1256  // vertex normal
1257  if( _pl.vertex_normals_available())
1258  if( vertex_normals_available())
1259  vertex_normal(_j) = _pl.vertex_normal(_i);
1260 
1261  if( _pl.vertex_binormals_available())
1262  if( vertex_binormals_available())
1263  vertex_binormal(_j) = _pl.vertex_binormal(_i);
1264 
1265  // vertex colors
1266  if( _pl.vertex_colors_available())
1267  if( vertex_colors_available())
1268  vertex_color(_j) = _pl.vertex_color(_i);
1269 
1270  // vertex scalar
1271  if( _pl.vertex_scalars_available())
1272  if( vertex_scalars_available())
1273  vertex_scalar(_j) = _pl.vertex_scalar(_i);
1274 
1275  // vertex selection
1276  if( _pl.vertex_selections_available())
1277  if( vertex_selections_available())
1278  vertex_selection(_j) = _pl.vertex_selection(_i);
1279 
1280  // vertex vhandle
1281  if( _pl.vertex_vhandles_available())
1282  if( vertex_vhandles_available())
1283  vertex_vhandle(_j) = _pl.vertex_vhandle(_i);
1284 
1285  // vertex ehandle
1286  if( _pl.vertex_ehandles_available())
1287  if( vertex_ehandles_available())
1288  vertex_ehandle(_j) = _pl.vertex_ehandle(_i);
1289 
1290  // vertex vhandle
1291  if( _pl.vertex_ehandles_available())
1292  if( vertex_ehandles_available())
1293  vertex_ehandle(_j) = _pl.vertex_ehandle(_i);
1294 }
1295 
1296 
1297 //-----------------------------------------------------------------------------
1298 
1299 
1300 template <class PointT>
1301 void
1303 copy_edge_complete(const PolyLineT<PointT>& _pl, unsigned int _i, unsigned int _j)
1304 {
1305  // check range
1306  if( n_edges() <= _j || _pl.n_edges() <= _i)
1307  {
1308  std::cerr << "Warning: invalid range in PolyLine::copy_edge_complete ( "
1309  << _i << " " << _j << " ) " << std::endl;
1310  return;
1311  }
1312 
1313  // edge normal
1314  if( _pl.edge_selections_available())
1315  if( edge_selections_available())
1316  edge_selection(_j) = _pl.edge_selection(_i);
1317 
1318 
1319  // edge normal
1320  if( _pl.edge_normals_available())
1321  if( edge_normals_available())
1322  edge_normal(_j) = _pl.edge_normal(_i);
1323 
1324  // edge color
1325  if( _pl.edge_colors_available())
1326  if( edge_colors_available())
1327  edge_color(_j) = _pl.edge_color(_i);
1328 
1329  // edge scalar
1330  if( _pl.edge_scalars_available())
1331  if( edge_scalars_available())
1332  edge_scalar(_j) = _pl.edge_scalar(_i);
1333 
1334  // edge normal
1335  if( _pl.edge_selections_available())
1336  if( edge_selections_available())
1337  edge_selection(_j) = _pl.edge_selection(_i);
1338 
1339  // edge selection
1340  if( _pl.edge_selections_available())
1341  if( edge_selections_available())
1342  edge_selection(_j) = _pl.edge_selection(_i);
1343 }
1344 
1345 
1346 //-----------------------------------------------------------------------------
1347 
1348 
1349 template <class PointT>
1350 void
1353 {
1354  // inversion is only supported for open polylines
1355  if(is_closed())
1356  {
1357  std::cerr << "Warning: inversion for closed polylines is not supported!!!\n";
1358  return;
1359  }
1360 
1361  PolyLineT<PointT> pl_temp = *this;
1362 
1363  // copy vertices in reverse order
1364  for(unsigned int i=0; i<n_vertices(); ++i)
1365  pl_temp.copy_vertex_complete( *this, n_vertices()-1-i, i);
1366 
1367  // copy edges in reverse order
1368  for(unsigned int i=0; i<n_edges(); ++i)
1369  pl_temp.copy_edge_complete( *this, n_edges()-1-i, i);
1370 
1371  // save inverted polyline
1372  *this = pl_temp;
1373 }
1374 
1375 
1376 //-----------------------------------------------------------------------------
1377 
1378 
1379 template <class PointT>
1380 void
1383 {
1384  // operation not supported for closed polylines
1385  if( is_closed() || _pl.is_closed())
1386  {
1387  std::cerr << is_closed() << " " << _pl.is_closed() << std::endl;
1388  std::cerr << "Warning: appending not supported for closed polylines!!!\n";
1389  return;
1390  }
1391 
1392  unsigned int old_nv = n_vertices();
1393  unsigned int old_ne = n_edges();
1394 
1395  resize( n_vertices() + _pl.n_vertices());
1396 
1397  for( unsigned int i=0; i<_pl.n_vertices(); ++i)
1398  copy_vertex_complete( _pl, i, i+old_nv);
1399 
1400  for( unsigned int i=0; i<_pl.n_edges(); ++i)
1401  copy_edge_complete( _pl, i, i+old_ne+1);
1402 }
1403 
1404 
1405 //-----------------------------------------------------------------------------
1406 
1407 
1408 template <class PointT>
1409 void
1412 {
1413  PolyLineT<PointT> pl_temp = _pl;
1414 
1415  pl_temp.append(*this);
1416  *this = pl_temp;
1417 }
1418 
1419 
1420 //-----------------------------------------------------------------------------
1421 
1422 
1423 template <class PointT>
1424 void
1426 split_closed( unsigned int _split_idx)
1427 {
1428  if(!is_closed())
1429  {
1430  std::cerr << "Warning: split_closed was called for open polyline!\n";
1431  return;
1432  }
1433 
1434  // prepare new polyline
1435  PolyLineT<PointT> pl_temp = *this;
1436  pl_temp.resize(n_vertices()+1);
1437  pl_temp.set_closed( false);
1438 
1439 
1440  // splitted polyline has n+1 vertices
1441  for(unsigned int i=0; i<n_vertices()+1; ++i)
1442  pl_temp.copy_vertex_complete( *this, (i+_split_idx)%n_vertices(),i);
1443 
1444  for(unsigned int i=0; i<n_edges(); ++i)
1445  pl_temp.copy_edge_complete( *this, (i+_split_idx)%n_edges(),i);
1446 
1447  // copy updated polyline
1448  *this = pl_temp;
1449 }
1450 
1451 
1452 //-----------------------------------------------------------------------------
1453 
1454 
1455 template <class PointT>
1456 void
1458 split( unsigned int _split_idx, PolyLineT<PointT>& _new_pl)
1459 {
1460  if( is_closed() ) split_closed( _split_idx);
1461  else
1462  {
1463  // copy properties
1464  _new_pl = *this;
1465 
1466  _new_pl.resize( n_vertices() - _split_idx);
1467 
1468  // copy vertex data
1469  for(unsigned int i=_split_idx; i<n_vertices(); ++i)
1470  _new_pl.copy_vertex_complete(*this, i, i-_split_idx);
1471  // copy edge data
1472  for(unsigned int i=_split_idx; i<n_edges(); ++i)
1473  _new_pl.copy_edge_complete(*this, i, i-_split_idx);
1474 
1475  // cut copied part
1476  resize(_split_idx+1);
1477  }
1478 }
1479 
1480 
1481 //-----------------------------------------------------------------------------
1482 
1483 
1484 template <class PointT>
1485 template <class IPoint>
1486 bool
1488 plane_line_intersection( const IPoint& _p_plane,
1489  const IPoint& _n_plane,
1490  const IPoint& _p0,
1491  const IPoint& _p1,
1492  IPoint& _p_int)
1493 {
1494  double a = (_n_plane | (_p_plane - _p0));
1495  double b = (_n_plane | (_p1 - _p0));
1496 
1497  if (fabs(b) > 1e-9) {
1498  double s = a / b;
1499 
1500  if (s >= 0.0 && s <= 1.0) {
1501  _p_int = _p0 + (_p1 - _p0) * s;
1502 
1503  // TEST Intersection Point
1504  if (fabs((_n_plane | (_p_int - _p_plane))) > 1e-9)
1505  std::cerr << "WARNING: wrong intersection point!!!\n";
1506 
1507  return true;
1508  } else
1509  return false;
1510  } else
1511  return false;
1512 }
1513 
1514 
1515 //-----------------------------------------------------------------------------
1516 
1517 
1518 template <class PointT>
1519 template<class MeshT>
1520 void
1522 edge_points_in_segment( const MeshT& _mesh,
1523  const Point& _p0,
1524  const Point& _p1,
1525  const typename MeshT::FaceHandle& _fh0,
1526  const typename MeshT::FaceHandle& _fh1,
1527  std::vector<Point> & _points,
1528  std::vector<typename MeshT::EdgeHandle>& _ehandles )
1529 {
1530  // initialize
1531  _points.clear();
1532  _ehandles.clear();
1533 
1534  Point p_start = _p0;
1535  Point p_end = _p1;
1536 
1537  typename MeshT::FaceHandle fh_start = _fh0;
1538  typename MeshT::FaceHandle fh_end = _fh1;
1539 
1540  if( fh_start == fh_end)
1541  return;
1542 
1543  // vectors for new points
1544  std::vector<Point> new_points0, new_points1;
1545 
1546  // vector for new edgehandle
1547  std::vector<typename MeshT::EdgeHandle> new_eh0, new_eh1;
1548 
1549 // // insert first point
1550 // new_points0.push_back( p_start);
1551 // new_points1.push_back( p_start);
1552 
1553  // construct cut plane
1554  // get first normal
1555  typename MeshT::HalfedgeHandle heh = _mesh.halfedge_handle(fh_start);
1556  Point p0 = (Point)_mesh.point(_mesh.to_vertex_handle( heh ));
1557  Point p1 = (Point)_mesh.point(_mesh.to_vertex_handle( heh = _mesh.next_halfedge_handle(heh) ));
1558  Point p2 = (Point)_mesh.point(_mesh.to_vertex_handle( heh = _mesh.next_halfedge_handle(heh) ));
1559  Point n_start = ((p1-p0)%(p2-p0)).normalize();
1560 
1561  // get second normal
1562  heh = _mesh.halfedge_handle(fh_end);
1563  p0 = _mesh.point(_mesh.to_vertex_handle( heh ));
1564  p1 = _mesh.point(_mesh.to_vertex_handle( heh = _mesh.next_halfedge_handle(heh) ));
1565  p2 = _mesh.point(_mesh.to_vertex_handle( heh = _mesh.next_halfedge_handle(heh) ));
1566  Point n_end = ((p1-p0)%(p2-p0)).normalize();
1567 
1568  // get average normal
1569  Point n_avg = n_start + n_end;
1570  if( n_avg.sqrnorm() < 1e-7) n_avg = n_start - n_end;
1571  n_avg.normalize();
1572 
1573  // get plane data
1574  Point n_plane = n_avg % (p_start-p_end).normalize();
1575  if( n_plane.sqrnorm() > 1e-9) n_plane.normalize();
1576  else std::cerr << "WARNING: Edge Resampling -> not possible to construct stable cut plane!!!\n";
1577  Point p_plane = (p_start + p_end)*0.5;
1578 
1579  // get intersection halfedges of start triangle
1580  std::vector<typename MeshT::HalfedgeHandle > start_hehs;
1581  std::vector<Point> start_ps;
1582  heh = _mesh.halfedge_handle(fh_start);
1583  Point p_int;
1584  for(unsigned int i=0; i<3; ++i)
1585  {
1586  // edge endpoints
1587  p0 = (Point) _mesh.point(_mesh.from_vertex_handle(heh));
1588  p1 = (Point) _mesh.point(_mesh.to_vertex_handle (heh));
1589 
1590  // intersection ?
1591  if( plane_line_intersection( p_plane, n_plane, p0, p1, p_int))
1592  {
1593  start_hehs.push_back( heh );
1594  start_ps.push_back(p_int);
1595  }
1596  // move to next halfedge handle
1597  heh = _mesh.next_halfedge_handle(heh);
1598  }
1599 
1600  // DEBUG
1601  // get intersection halfedges of end triangle
1602  std::vector<typename MeshT::HalfedgeHandle > end_hehs;
1603  std::vector<Point> end_ps;
1604  heh = _mesh.halfedge_handle(fh_end);
1605  for(unsigned int i=0; i<3; ++i)
1606  {
1607  // edge endpoints
1608  p0 = (Point) _mesh.point(_mesh.from_vertex_handle(heh));
1609  p1 = (Point) _mesh.point(_mesh.to_vertex_handle (heh));
1610 
1611  // intersection ?
1612  if( plane_line_intersection( p_plane, n_plane, p0, p1, p_int))
1613  {
1614  end_hehs.push_back( heh );
1615  end_ps.push_back(p_int);
1616  }
1617  // move to next halfedge handle
1618  heh = _mesh.next_halfedge_handle(heh);
1619  }
1620  // END DEBUG
1621 
1622  // hack: debug hints
1623  if( start_hehs.size() != 2 || end_hehs.size() != 2)
1624  {
1625  std::cerr << "PolyLineResampling ERROR: wrong number of intersections... ";
1626  std::cerr << start_hehs.size() << " ";
1627  std::cerr << end_hehs.size() << std::endl;
1628  }
1629  // else std::cerr << "SUPI!!!\n";
1630  // end hack
1631 
1632 
1633  if( start_hehs.size() == 2 && end_hehs.size() == 2)
1634  {
1635  // initialize start points
1636  typename MeshT::HalfedgeHandle cur_heh0 = start_hehs[0];
1637  typename MeshT::HalfedgeHandle cur_heh1 = start_hehs[1];
1638 
1639  // store points and edge handles
1640  new_points0.push_back( start_ps[0]);
1641  new_eh0.push_back( _mesh.edge_handle( cur_heh0));
1642 
1643  new_points1.push_back( start_ps[1]);
1644  new_eh1.push_back( _mesh.edge_handle( cur_heh1));
1645 
1646  unsigned int count = 0;
1647 
1648  while( _mesh.face_handle(_mesh.opposite_halfedge_handle(cur_heh0)) != fh_end &&
1649  _mesh.face_handle(_mesh.opposite_halfedge_handle(cur_heh1)) != fh_end &&
1650  count < 1000 )
1651  {
1652  ++count;
1653 
1654  // move into first direction
1655  cur_heh0 = _mesh.opposite_halfedge_handle( cur_heh0);
1656 
1657  // test for boundary
1658  if( _mesh.is_boundary(cur_heh0))
1659  {
1660  std::cerr << "ERROR: found boundary in traversal!!!\n";
1661  cur_heh0 = _mesh.opposite_halfedge_handle( cur_heh0);
1662  } else {
1663 
1664  unsigned int old_size = new_points0.size();
1665 
1666  for(unsigned int i=0; i<2; ++i)
1667  {
1668  // move to next halfedge handle
1669  cur_heh0 = _mesh.next_halfedge_handle(cur_heh0);
1670 
1671  // edge endpoints
1672  p0 = (Point) _mesh.point(_mesh.from_vertex_handle(cur_heh0));
1673  p1 = (Point) _mesh.point(_mesh.to_vertex_handle (cur_heh0));
1674 
1675  // intersection ?
1676  if( plane_line_intersection( p_plane, n_plane, p0, p1, p_int))
1677  {
1678  new_points0.push_back(p_int);
1679  new_eh0.push_back( _mesh.edge_handle( cur_heh0));
1680  break;
1681  }
1682  }
1683 
1684  // debug helper
1685  if( new_points0.size() != old_size + 1)
1686  std::cerr << "WARNING: could not find new point!!!\n";
1687  }
1688 
1689  // move into second direction
1690  cur_heh1 = _mesh.opposite_halfedge_handle( cur_heh1);
1691 
1692  // test for boundary
1693  if( _mesh.is_boundary(cur_heh1))
1694  {
1695  std::cerr << "ERROR: found boundary in traversal!!!\n";
1696  cur_heh1 = _mesh.opposite_halfedge_handle( cur_heh1);
1697  } else {
1698 
1699  unsigned int old_size = new_points1.size();
1700 
1701  for(unsigned int i=0; i<2; ++i)
1702  {
1703  // move to next halfedge handle
1704  cur_heh1 = _mesh.next_halfedge_handle(cur_heh1);
1705 
1706  // edge endpoints
1707  p0 = (Point) _mesh.point(_mesh.from_vertex_handle(cur_heh1));
1708  p1 = (Point) _mesh.point(_mesh.to_vertex_handle (cur_heh1));
1709 
1710  // intersection ?
1711  if( plane_line_intersection( p_plane, n_plane, p0, p1, p_int))
1712  {
1713  new_points1.push_back(p_int);
1714  new_eh1.push_back( _mesh.edge_handle( cur_heh1));
1715  break;
1716  }
1717  }
1718 
1719  // debug helper
1720  if( new_points1.size() != old_size + 1)
1721  std::cerr << "WARNING: could not find new point!!!\n";
1722  }
1723 
1724  }
1725 
1726 // // add end points
1727 // new_points0.push_back( p_end );
1728 // new_points1.push_back( p_start );
1729 
1730  // set new points, test which direction converged first
1731  if(_mesh.face_handle(_mesh.opposite_halfedge_handle(cur_heh0)) == fh_end )
1732  {
1733  // return values
1734  _points = new_points0;
1735  _ehandles = new_eh0;
1736  }
1737  else
1738  if (_mesh.face_handle(_mesh.opposite_halfedge_handle(cur_heh1)) == fh_end)
1739  {
1740  // return values
1741  _points = new_points1;
1742  _ehandles = new_eh1;
1743  }
1744  }
1745 }
1746 
1747 
1748 //-----------------------------------------------------------------------------
1749 
1750 
1751 template <class PointT>
1752 void
1754 remove_subsequent_identical_points(const bool _keep_edge_vertices, const double _epsilon )
1755 {
1756  if(is_closed())
1757  {
1758  for( int i=0; i<int(n_vertices()); ++i)
1759  {
1760  int i_next = (i+1) % int(n_vertices());
1761 
1762  if( (point(i) - point(i_next)).norm() < _epsilon)
1763  {
1764  if( vertex_ehandles_available())
1765  {
1766  if( !_keep_edge_vertices || vertex_ehandle(i_next) == -1)
1767  {
1768  delete_point(i_next);
1769  --i;
1770  }
1771  else
1772  if( vertex_ehandle(i) == -1)
1773  {
1774  delete_point(i);
1775  --i;
1776  }
1777  }
1778  else // simply delete i_next
1779  {
1780  delete_point(i_next);
1781  --i;
1782  }
1783  }
1784  }
1785  }
1786  else
1787  {
1788  for( int i=0; i<int(n_vertices())-1; ++i)
1789  {
1790  int i_next = (i+1) % int(n_vertices());
1791 
1792  if( (point(i) - point(i_next)).norm() < _epsilon)
1793  {
1794  if( vertex_ehandles_available())
1795  {
1796  if( !_keep_edge_vertices || vertex_ehandle(i_next) == -1)
1797  {
1798  if(i_next != int(n_vertices())-1)
1799  {
1800  delete_point(i_next);
1801  --i;
1802  }
1803  else delete_point(i);
1804  }
1805  else
1806  if( vertex_ehandle(i) == -1)
1807  {
1808  if(i != 0)
1809  {
1810  delete_point(i);
1811  --i;
1812  }
1813  }
1814  }
1815  else // simply delete i_next
1816  {
1817  if(i_next != int(n_vertices())-1)
1818  {
1819  delete_point(i_next);
1820  --i;
1821  }
1822  else delete_point(i);
1823  }
1824  }
1825  }
1826  }
1827 }
1828 
1829 
1830 //-----------------------------------------------------------------------------
1831 
1832 
1833 template <class PointT>
1834 typename PolyLineT<PointT>::Scalar
1837 {
1838  // total gaussian curvature
1839  Scalar gcurv = 0.0;
1840 
1841  if (!edge_normals_available() || !is_closed()) {
1842  std::cerr << "Warning: PolyLineT::total_gaussian_curvature requires a closed loop and edge normals!!!\n";
1843  } else // closed and edge normals available
1844  {
1845  // sum over boundary
1846  for (unsigned int i = 0; i < n_edges(); ++i) {
1847  // get two consecutive edge vectors and corresponding normals
1848  Point e0 = edge_vector(i);
1849  Point n0 = edge_normal(i);
1850  Point e1 = edge_vector((i + 1) % n_edges());
1851  Point n1 = edge_normal((i + 1) % n_edges());
1852 
1853  // normalize edges
1854  if (e0.norm() > 1e-8)
1855  e0.normalize();
1856  else {
1857  std::cerr << "Warning: e0 is undefined...\n";
1858  continue;
1859  }
1860  if (e1.norm() > 1e-8)
1861  e1.normalize();
1862  else {
1863  std::cerr << "Warning: e1 is undefined...\n";
1864  continue;
1865  }
1866 
1867  // normalize normals
1868  if (n0.norm() > 1e-4)
1869  n0.normalize();
1870  else {
1871  std::cerr << "Warning: n0 is undefined...\n";
1872  continue;
1873  }
1874  if (n1.norm() > 1e-4)
1875  n1.normalize();
1876  else {
1877  std::cerr << "Warning: n1 is undefined...\n";
1878  continue;
1879  }
1880 
1881  // compute binormals
1882  Point b0 = n0 % e0;
1883  // Point b1 = n1%e0;
1884 
1885  // normalize binormals
1886  if (b0.norm() > 1e-8)
1887  b0.normalize();
1888  else {
1889  std::cerr << "Warning: b0 is undefined...\n";
1890  continue;
1891  }
1892  // if( b1.norm() > 1e-4) b1.normalize();
1893  // else std::cerr << "Warning: b1 is undefined...\n";
1894 
1895  // compute intersection of tangent planes
1896  Point d = n0 % n1;
1897  if ((d | b0) < 0) // reorientation necessary?
1898  d *= -1.0;
1899 
1900  // both in same tangent plane?
1901  if (d.norm() < 1e-3)
1902  d = b0;
1903  else
1904  d.normalize();
1905 
1906  // add both angles
1907  double dp = (-e0 | d);
1908  dp = std::max(-1.0, dp);
1909  dp = std::min(1.0, dp);
1910 
1911  // compute first boundary angle
1912  double boundary_angle = acos(dp);
1913 
1914  dp = (e1 | d);
1915  dp = std::max(-1.0, dp);
1916  dp = std::min(1.0, dp);
1917 
1918  // add second angle
1919  boundary_angle += acos(dp);
1920 
1921  gcurv += M_PI - boundary_angle;
1922  }
1923  }
1924  // return total gaussian curvature
1925  return (2.0 * M_PI - gcurv);
1926 }
1927 
1928 template <class PointT>
1929 template <class MeshT>
1933  MeshT> &component) {
1934 
1935  MeshT &mesh = component.getMesh();
1936 
1937  for (typename MeshT::FaceIter
1938  f_it = mesh.faces_begin(), f_end = mesh.faces_end();
1939  f_it != f_end; ++f_it) {
1940  component[*f_it] = 0;
1941  }
1942 
1943  unsigned int current_component = 0;
1944  for (typename MeshT::FaceIter f_it = mesh.faces_begin(),
1945  f_end = mesh.faces_end(); f_it != f_end; ++f_it) {
1946 
1947  if (component[*f_it] != 0)
1948  continue;
1949 
1950  ++current_component;
1951 
1952  /*
1953  * Flood fill component.
1954  */
1955  std::stack<typename MeshT::FaceHandle> dfs;
1956  dfs.push(*f_it);
1957 
1958  while (!dfs.empty()) {
1959  const typename MeshT::FaceHandle fh = dfs.top(); dfs.pop();
1960 
1961  component[fh] = current_component;
1962 
1963  /*
1964  * Visit neighbors, push them onto stack if they
1965  * haven't been visited yet.
1966  */
1967  for (typename MeshT::FFIter ff_it = mesh.ff_begin(fh),
1968  ff_end = mesh.ff_end(fh); ff_it != ff_end; ++ff_it) {
1969 
1970  if (component[*ff_it] == 0)
1971  dfs.push(*ff_it);
1972  }
1973  }
1974  }
1975  std::cout << "\x1b[33mmark_components: Mesh has " << current_component
1976  << " components.\x1b[0m" << std::endl;
1977 
1978 }
1979 
1980 template <class PointT>
1981 template<class MeshT, class SpatialSearchT>
1985  MeshT> &component,
1986  const PointT &pt,
1987  SpatialSearchT &_ssearch) {
1988 
1989  typename MeshT::FaceHandle fh;
1990  find_nearest_point(component.getMesh(), pt, fh, _ssearch);
1991 //#ifndef NDEBUG
1992 // std::cout << "Point(" << pt << ") on fh " << fh.idx() << std::endl;
1993 //#endif
1994  return component[fh];
1995 }
1996 
1997 template <class PointT>
1998 template <class MeshT, class SpatialSearchT>
2001  SpatialSearchT &_ssearch) {
2002 
2003  if (points_.empty()) return false;
2004 
2006  component(_mesh,
2007  "component.on_multiple_components.objecttypes.polyline"
2008  ".i8.informatik.rwth-aachen.de");
2009 
2010 
2011  mark_components(component);
2012 
2013  const unsigned int first_component =
2014  component_of(component, points_.front(), _ssearch);
2015 
2016  for (typename std::vector<PointT>::iterator pt_it = ++points_.begin(),
2017  pt_end = points_.end(); pt_it != pt_end; ++pt_it) {
2018 
2019  if (first_component != component_of(component, *pt_it, _ssearch))
2020  return true;
2021  }
2022 
2023  return false;
2024 }
2025 
2026 template <class PointT>
2027 template <class MeshT, class SpatialSearchT>
2030  SpatialSearchT &_ssearch,
2031  std::vector<PolyLineT> &out_polylines) {
2032 
2033  if (points_.size() < 2) return;
2034 
2036  component(_mesh,
2037  "component.split_into_one_per_component.objecttypes.polyline"
2038  ".i8.informatik.rwth-aachen.de");
2039 
2040  mark_components(component);
2041 
2042  PolyLineT<PointT> current_polyLine;
2043  current_polyLine.add_point(points_.front());
2044  unsigned int current_component =
2045  component_of(component, points_.front(), _ssearch);
2046 
2047  for (typename std::vector<PointT>::iterator pt_it = ++points_.begin(),
2048  pt_end = points_.end(); pt_it != pt_end; ++pt_it) {
2049 
2050  /*
2051  * The easy case: next point is on the same component as
2052  * the previous one.
2053  */
2054  const unsigned int next_comp = component_of(component, *pt_it, _ssearch);
2055  if (next_comp == current_component) {
2056  current_polyLine.add_point(*pt_it);
2057  continue;
2058  }
2059 
2060  /*
2061  * The hard case: next point is on different component
2062  * than the previous one.
2063  */
2064 
2065  PointT p0 = current_polyLine.back();
2066  const PointT p1 = *pt_it;
2067  unsigned int comp = next_comp;
2068 
2069  do {
2070  const double dist = (p0 - p1).norm();
2071  double lastIn = 0;
2072  double firstOut = 1;
2073 
2074  /*
2075  * Perform binary search to determine reasonable lastIn and firstOut.
2076  */
2077  static const double EPSILON = 1e-12;
2078  while ((firstOut - lastIn) * dist > EPSILON) {
2079  const double new_pos = .5 * (lastIn + firstOut);
2080  const PointT new_pt = p0 * (1.0 - new_pos) + p1 * new_pos;
2081  const unsigned int new_comp =
2082  component_of(component, new_pt, _ssearch);
2083 
2084  if (new_comp == current_component) {
2085  lastIn = new_pos;
2086  } else {
2087  firstOut = new_pos;
2088  comp = new_comp;
2089  }
2090  }
2091 
2092  if (lastIn != 0)
2093  current_polyLine.add_point(p0 * (1.0 - lastIn) + p1 * lastIn);
2094  if (current_polyLine.n_vertices() >= 2)
2095  out_polylines.push_back(current_polyLine);
2096  current_polyLine.clear();
2097  current_polyLine.add_point(p0 * (1.0 - firstOut) + p1 * firstOut);
2098  current_component = comp;
2099 
2100  // Update
2101  p0 = p0 * (1.0 - firstOut) + p1 * firstOut;
2102  } while (comp != next_comp);
2103 
2104  if (current_polyLine.back() != *pt_it)
2105  current_polyLine.add_point(*pt_it);
2106  }
2107 
2108  if (current_polyLine.n_vertices() >= 2)
2109  out_polylines.push_back(current_polyLine);
2110 
2111  // hack! if no splitting return original polyline
2112  if(out_polylines.size() <= 1)
2113  {
2114  out_polylines.clear();
2115  out_polylines.push_back(*this);
2116  }
2117 }
2118 
2119 template <class PointT>
2120 typename PolyLineT<PointT>::CustomPropertyHandle PolyLineT<PointT>::custom_prop_handle(const CustomProperty* _prop) const {
2121  size_t n = cprop_enum.size();
2122  for (int i = 0; i < n; ++i)
2123  if (cprop_enum[i] == _prop)
2124  return i;
2125  return -1;
2126 }
2127 
2128 template <class PointT>
2129 typename PolyLineT<PointT>::CustomProperty* PolyLineT<PointT>::custom_prop(CustomPropertyHandle _handle) {
2130  return (_handle >= 0 && _handle < int(get_num_custom_properties()) ? cprop_enum[_handle] : NULL);
2131 }
2132 
2133 template <class PointT>
2134 const typename PolyLineT<PointT>::CustomProperty* PolyLineT<PointT>::custom_prop(CustomPropertyHandle _handle) const {
2135  return (_handle >= 0 && _handle < int(get_num_custom_properties()) ? cprop_enum[_handle] : NULL);
2136 }
2137 
2138 template <class PointT>
2139 typename PolyLineT<PointT>::CustomPropertyHandle PolyLineT<PointT>::
2140  request_custom_property(const std::string& _name,
2141  unsigned int _prop_size) {
2142 
2143  CustomPropertyHandle h = get_custom_property_handle(_name);
2144  CustomProperty* pcontainer = custom_prop(h);
2145 
2146  if (!pcontainer) {
2147 
2148  // create new property container
2149  pcontainer = new CustomProperty;
2150 
2151  pcontainer->name = _name;
2152  pcontainer->ref_count = 1;
2153  pcontainer->prop_size = _prop_size;
2154 
2155  pcontainer->datatype = 0;
2156 
2157  pcontainer->prop_data.resize(n_vertices() * _prop_size, 0);
2158 
2159  custom_properties[_name] = pcontainer;
2160 
2161  cprop_enum.push_back(pcontainer);
2162  } else {
2163 
2164  if (++pcontainer->ref_count < 1)
2165  pcontainer->ref_count = 1;
2166  }
2167 
2168  return custom_prop_handle(pcontainer);
2169 }
2170 
2171 template <class PointT>
2173  release_custom_property(CustomPropertyHandle _prop_handle) {
2174 
2175  CustomProperty* p = custom_prop(_prop_handle);
2176 
2177  if (p && --(p->ref_count) <= 0)
2178  p->prop_data.clear();
2179 }
2180 
2181 template <class PointT>
2183  release_custom_property(const std::string& _name) {
2184 
2185  CustomPropertyHandle h = get_custom_property_handle(_name);
2186  release_custom_property(h);
2187 }
2188 
2189 template <class PointT>
2190 typename PolyLineT<PointT>::CustomPropertyHandle PolyLineT<PointT>::
2191  get_custom_property_handle(const std::string& _name) const {
2192 
2193  typename CustomPropertyMap::const_iterator it = custom_properties.find(_name);
2194 
2195  if (it == custom_properties.end())
2196  return -1;
2197 
2198  return custom_prop_handle(it->second);
2199 }
2200 
2201 template <class PointT>
2202 const std::string PolyLineT<PointT>::
2203  get_custom_property_name(CustomPropertyHandle _property_handle) const {
2204 
2205  const CustomProperty* p = custom_prop(_property_handle);
2206 
2207  if (p)
2208  return p->name;
2209 
2210  std::cerr << "PolyLineT::get_custom_property_name - invalid handle" << std::endl;
2211 
2212  return "";
2213 }
2214 
2215 
2216 template <class PointT>
2218  set_custom_property(CustomPropertyHandle _property_handle,
2219  unsigned int _i,
2220  const void* _data) {
2221 
2222  if (!_data) {
2223  std::cerr << "PolyLineT::set_custom_property - invalid data" << std::endl;
2224  return;
2225  }
2226 
2227  CustomProperty* p = custom_prop(_property_handle);
2228 
2229  if (p) {
2230  unsigned int offset = p->prop_size * _i;
2231 
2232  // check out of range
2233  if (offset + p->prop_size > p->prop_data.size()) {
2234  std::cerr << "PolyLineT::set_custom_property - out of range access" << std::endl;
2235  return;
2236  }
2237 
2238 
2239  // copy data byte-wise
2240  memcpy(p->buffer() + offset, _data, p->prop_size);
2241  }
2242  else
2243  std::cerr << "PolyLineT::set_custom_property - invalid handle" << std::endl;
2244 }
2245 
2246 template <class PointT>
2248  set_custom_property(const std::string& _name,
2249  unsigned int _i,
2250  const void* _data) {
2251 
2252  CustomPropertyHandle h = get_custom_property_handle(_name);
2253  set_custom_property(h, _i, _data);
2254 }
2255 
2256 template <class PointT>
2258  get_custom_property(CustomPropertyHandle _property_handle,
2259  unsigned int _i,
2260  void* _dst) const {
2261 
2262  if (!_dst) {
2263  std::cerr << "PolyLineT::get_custom_property - invalid destination address" << std::endl;
2264  return;
2265  }
2266 
2267  const CustomProperty* p = custom_prop(_property_handle);
2268 
2269  if (p) {
2270 
2271  unsigned int offset = p->prop_size * _i;
2272 
2273  // check out of range
2274  if (offset + p->prop_size > p->prop_data.size()) {
2275  std::cerr << "PolyLineT::get_custom_property - out of range access" << std::endl;
2276  return;
2277  }
2278 
2279  // copy data byte-wise
2280  memcpy(_dst, p->buffer() + offset, p->prop_size);
2281  }
2282  else
2283  std::cerr << "PolyLineT::get_custom_property - invalid handle" << std::endl;
2284 }
2285 
2286 template <class PointT>
2288  get_custom_property(const std::string& _name,
2289  unsigned int _i,
2290  void* _data) const {
2291 
2292  CustomPropertyHandle h = get_custom_property_handle(_name);
2293  get_custom_property(h, _i, _data);
2294 }
2295 
2296 
2297 template <class PointT>
2299  custom_property_available(CustomPropertyHandle _property_handle) const {
2300 
2301  const CustomProperty* p = custom_prop(_property_handle);
2302 
2303  if (p)
2304  return p->ref_count > 0;
2305 
2306  return false;
2307 }
2308 
2309 
2310 template <class PointT>
2312  custom_property_available(const std::string& _name) const {
2313 
2314  CustomPropertyHandle h = get_custom_property_handle(_name);
2315  return custom_property_available(h);
2316 }
2317 
2318 
2319 template <class PointT>
2321  bind_custom_property_to_shader(CustomPropertyHandle _property_handle, const std::string& _shader_input_name, unsigned int _datatype) {
2322 
2323  CustomProperty* p = custom_prop(_property_handle);
2324 
2325  if (p) {
2326 
2327  p->datatype = _datatype;
2328  p->shader_binding = _shader_input_name;
2329 
2330  } else
2331  std::cerr << "PolyLineT::bind_custom_property_to_shader - invalid handle" << std::endl;
2332 }
2333 
2334 
2335 template <class PointT>
2337  get_custom_property_shader_binding(CustomPropertyHandle _property_handle, unsigned int* _propsize, const char** _input_name, unsigned int* _datatype) const {
2338 
2339  const CustomProperty* p = custom_prop(_property_handle);
2340 
2341  if (p) {
2342 
2343  if (_propsize)
2344  *_propsize = p->prop_size;
2345 
2346  if (_input_name)
2347  *_input_name = p->shader_binding.c_str();
2348 
2349  if (_datatype)
2350  *_datatype = p->datatype;
2351 
2352  return !p->shader_binding.empty() && p->datatype;
2353  }
2354  else
2355  std::cerr << "PolyLineT::get_custom_property_shader_binding - invalid handle" << std::endl;
2356 
2357  return false;
2358 }
2359 
2360 template <class PointT>
2361 const void* PolyLineT<PointT>::
2362  get_custom_property_buffer(CustomPropertyHandle _property_handle) const {
2363 
2364  const CustomProperty* p = custom_prop(_property_handle);
2365 
2366  if (p)
2367  return p->buffer();
2368  else
2369  std::cerr << "PolyLineT::get_custom_property_buffer - invalid handle" << std::endl;
2370 
2371  return NULL;
2372 }
2373 
2374 template <class PointT>
2375 unsigned int PolyLineT<PointT>::
2377  return custom_properties.size();
2378 }
2379 
2380 template <class PointT>
2381 typename PolyLineT<PointT>::CustomPropertyHandle PolyLineT<PointT>::
2382  enumerate_custom_property_handles(unsigned int _i) const {
2383 
2384  if (_i < get_num_custom_properties())
2385  return CustomPropertyHandle(_i);
2386  else
2387  return -1;
2388 }
2389 
2390 //=============================================================================
2391 } // namespace ACG
2392 //=============================================================================
void append(const PolyLineT< PointT > &_pl)
Append second polyline _pl to this one.
Point & front()
Get first point of the polyline ( no range check!!!)
Definition: PolyLineT.hh:154
void add_point(const Point &_p)
Append a point to the polyline.
Namespace providing different geometric functions concerning angles.
void smooth_uniform_laplace2()
Squared laplacian smoothing.
Point & point(unsigned int _i)
Get a point of the polyline.
Definition: PolyLineT.hh:142
void delete_point(int _idx)
Delete point at _idx.
void resample_arclength_uniform(const unsigned int _n)
Perform an uniform arclength resampling while maintaining the start and end point.
Point position(const Scalar _t) const
Provide linear paremterization of the polyline in [0,1].
Point & back()
Get last point of the polyline ( no range check!!!)
Definition: PolyLineT.hh:160
bool on_multiple_components(MeshT &_mesh, SpatialSearchT &_ssearch)
size_t n_vertices() const
Get number of vertices.
Definition: PolyLineT.hh:116
void project_to_mesh(const MeshT &_mesh, SpatialSearchT *_ssearch=0)
Project polyline points to nearest surface points (use spatial search!!!)
void remove_subsequent_identical_points(const bool _keep_edge_vertices=false, const double _epsilon=1e-6)
remove points which are subsequent and lie at the same position
void print() const
Print information string to cerr.
void prepend(const PolyLineT< PointT > &_pl)
Prepend second polyline _pl to polyline.
void set_closed(const bool _c)
Set if the polyline should be closed and therefore forms a loop.
Definition: PolyLineT.hh:113
void bind_custom_property_to_shader(CustomPropertyHandle _property_handle, const std::string &_shader_input_name, unsigned int _datatype)
Binding to vertex shader (optional)
Scalar length() const
Compute the length of the polyline (in future cached method)
Scalar total_gaussian_curvature()
compute total gaussian curvature of enclosed surface (via Gauss-Bonnet)
void set_line_node(LineNodeT *&_line_node, int _mode=0)
Takes a line node and sets the points of this polyline to the points of the node. ...
void split_into_one_per_component(MeshT &_mesh, SpatialSearchT &_ssearch, std::vector< PolyLineT > &out_polylines)
void smooth_uniform_laplace3()
Cubic laplacian smoothing.
void mark_components(OpenMesh::PropertyManager< OpenMesh::FPropHandleT< unsigned int >, MeshT > &component)
VectorT< Scalar, 3 > perpendicular(const VectorT< Scalar, 3 > &v)
find a vector that&#39;s perpendicular to _v
Definition: Algorithms.cc:1152
LineNodeT * get_line_node(LineNodeT *&_line_node, int _mode=0)
Conversion PolyLine <-> LineNode.
void clear()
Clear the current polyline.
size_t n_edges() const
Get number of edges.
bool closed_
Connect first and last point?
Definition: PolyLineT.hh:650
PolyLineT(bool _closed=false)
Constructor.
void insert_point(int _idx, const Point &_p)
insert _p at _idx into polyline
unsigned int component_of(const OpenMesh::PropertyManager< OpenMesh::FPropHandleT< unsigned int >, MeshT > &component, const PointT &pt, SpatialSearchT &_ssearch)
void resize(unsigned int _n)
Resize current polyline.
void collapse(Scalar _smallest)
Collapse polyline.
Point find_nearest_point(const MeshT &_mesh, const Point &_point, typename MeshT::FaceHandle &_fh, SpatialSearchT *_ssearch=0, double *_dbest=0)
Point position_arclength(const Scalar _t) const
Same as position but with an arclength parameterization in [0,length()].
void smooth_uniform_laplace()
Laplacian smoothing.
void subdivide(Scalar _largest)
Subdivide polyline.
bool get_custom_property_shader_binding(CustomPropertyHandle _property_handle, unsigned int *_propsize, const char **_input_name, unsigned int *_datatype) const
Get shader binding information.
Point edge_vector(unsigned int _i) const
get the i-th oriented edge vector
Definition: PolyLineT.hh:166
std::vector< Point > & points()
Get all points of the polyline.
Definition: PolyLineT.hh:148
std::vector< Point > points_
List of points in the polyline.
Definition: PolyLineT.hh:647
void set_to_circle(const PointT _center, const PointT _normal, double _radius, unsigned int _n_samples=100)
creating a circle with center _center and radius _radius lying in tangent plane specified by _normal ...
bool is_closed() const
Check if the polyline is marked as closed.
Definition: PolyLineT.hh:107
void split(unsigned int _split_idx, PolyLineT< PointT > &_new_pl)
Split closed polyline at vertex with index _split_idx.
void invert()
Invert polyline that first vertex becomes last.
bool plane_line_intersection(const IPoint &_p_plane, const IPoint &_n_plane, const IPoint &_p0, const IPoint &_p1, IPoint &_p_int)
void split_closed(unsigned int _split_idx)
Split closed polyline at vertex with index _split_idx.