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
81namespace ACG {
82
83//== IMPLEMENTATION ==========================================================
84
85//-----------------------------------------------------------------------------
86
87
89template <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
114template <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;
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
179template <class PointT>
180void
182clear()
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
209template <class PointT>
210size_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
223template <class PointT>
224void
226resize( 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
280template <class PointT>
281void
283add_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
344template <class PointT>
345void
347insert_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
409template <class PointT>
410void
412delete_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
476template <class PointT>
477typename PolyLineT<PointT>::Scalar
479length() 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
507template <class PointT>
508typename PolyLineT<PointT>::Point
510position(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
520template <class PointT>
521typename PolyLineT<PointT>::Point
523position_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(!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
572template <class PointT>
573void
575resample_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
611template <class PointT>
612void
614subdivide(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
664template <class PointT>
665void
667collapse(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
730template <class PointT>
731void
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
784template <class PointT>
785void
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
841template <class PointT>
842void
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
903template <class PointT>
904void
906set_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
928template <class PointT>
929template <class MeshT, class SpatialSearchT>
930void
932project_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
949template <class PointT>
950template <class MeshT, class SpatialSearchT>
951void
953project_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
997template <class PointT>
998template <class MeshT, class SpatialSearchT>
999typename PolyLineT<PointT>::Point
1001find_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
1071template <class PointT>
1072template <class LineNodeT>
1073LineNodeT*
1075get_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
1134template <class PointT>
1135template <class LineNodeT>
1136void
1138set_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
1185template <class PointT>
1186void
1188print() 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
1201template <class PointT>
1202template <class PropT>
1203void
1205request_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
1220template <class PointT>
1221template <class PropT>
1222void
1223PolyLineT<PointT>::
1224release_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
1238template <class PointT>
1239void
1240PolyLineT<PointT>::
1241copy_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
1300template <class PointT>
1301void
1302PolyLineT<PointT>::
1303copy_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
1349template <class PointT>
1350void
1352invert()
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
1379template <class PointT>
1380void
1382append(const PolyLineT<PointT>& _pl)
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
1408template <class PointT>
1409void
1411prepend(const PolyLineT<PointT>& _pl)
1412{
1413 PolyLineT<PointT> pl_temp = _pl;
1414
1415 pl_temp.append(*this);
1416 *this = pl_temp;
1417}
1418
1419
1420//-----------------------------------------------------------------------------
1421
1422
1423template <class PointT>
1424void
1426split_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
1455template <class PointT>
1456void
1458split( 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
1484template <class PointT>
1485template <class IPoint>
1486bool
1488plane_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
1518template <class PointT>
1519template<class MeshT>
1520void
1522edge_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
1751template <class PointT>
1752void
1754remove_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
1833template <class PointT>
1834typename 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
1928template <class PointT>
1929template <class MeshT>
1933 MeshT> &component) {
1934
1935 const MeshT &mesh = component.getMesh();
1936
1937 for (auto f_it : mesh.faces()) {
1938 component[f_it] = 0;
1939 }
1940
1941 unsigned int current_component = 0;
1942 for (auto f_it : mesh.faces()) {
1943
1944 if (component[f_it] != 0)
1945 continue;
1946
1947 ++current_component;
1948
1949 /*
1950 * Flood fill component.
1951 */
1952 std::stack<typename OpenMesh::SmartFaceHandle> dfs;
1953 dfs.push(f_it);
1954
1955 while (!dfs.empty()) {
1956 const typename OpenMesh::SmartFaceHandle fh = dfs.top(); dfs.pop();
1957
1958 component[fh] = current_component;
1959
1960 /*
1961 * Visit neighbors, push them onto stack if they
1962 * haven't been visited yet.
1963 */
1964 for (auto ff_it : fh.faces()) {
1965
1966 if (component[ff_it] == 0)
1967 dfs.push(ff_it);
1968 }
1969 }
1970 }
1971 std::cout << "\x1b[33mmark_components: Mesh has " << current_component
1972 << " components.\x1b[0m" << std::endl;
1973
1974}
1975
1976template <class PointT>
1977template<class MeshT, class SpatialSearchT>
1981 MeshT> &component,
1982 const PointT &pt,
1983 SpatialSearchT &_ssearch) {
1984
1985 typename MeshT::FaceHandle fh;
1986 find_nearest_point(component.getMesh(), pt, fh, _ssearch);
1987//#ifndef NDEBUG
1988// std::cout << "Point(" << pt << ") on fh " << fh.idx() << std::endl;
1989//#endif
1990 return component[fh];
1991}
1992
1993template <class PointT>
1994template <class MeshT, class SpatialSearchT>
1997 SpatialSearchT &_ssearch) {
1998
1999 if (points_.empty()) return false;
2000
2002 component(_mesh,
2003 "component.on_multiple_components.objecttypes.polyline"
2004 ".i8.informatik.rwth-aachen.de");
2005
2006
2007 mark_components(component);
2008
2009 const unsigned int first_component =
2010 component_of(component, points_.front(), _ssearch);
2011
2012 for (typename std::vector<PointT>::iterator pt_it = ++points_.begin(),
2013 pt_end = points_.end(); pt_it != pt_end; ++pt_it) {
2014
2015 if (first_component != component_of(component, *pt_it, _ssearch))
2016 return true;
2017 }
2018
2019 return false;
2020}
2021
2022template <class PointT>
2023template <class MeshT, class SpatialSearchT>
2026 SpatialSearchT &_ssearch,
2027 std::vector<PolyLineT> &out_polylines) {
2028
2029 if (points_.size() < 2) return;
2030
2032 component(_mesh,
2033 "component.split_into_one_per_component.objecttypes.polyline"
2034 ".i8.informatik.rwth-aachen.de");
2035
2036 mark_components(component);
2037
2038 PolyLineT<PointT> current_polyLine;
2039 current_polyLine.add_point(points_.front());
2040 unsigned int current_component =
2041 component_of(component, points_.front(), _ssearch);
2042
2043 for (typename std::vector<PointT>::iterator pt_it = ++points_.begin(),
2044 pt_end = points_.end(); pt_it != pt_end; ++pt_it) {
2045
2046 /*
2047 * The easy case: next point is on the same component as
2048 * the previous one.
2049 */
2050 const unsigned int next_comp = component_of(component, *pt_it, _ssearch);
2051 if (next_comp == current_component) {
2052 current_polyLine.add_point(*pt_it);
2053 continue;
2054 }
2055
2056 /*
2057 * The hard case: next point is on different component
2058 * than the previous one.
2059 */
2060
2061 PointT p0 = current_polyLine.back();
2062 const PointT p1 = *pt_it;
2063 unsigned int comp = next_comp;
2064
2065 do {
2066 const double dist = (p0 - p1).norm();
2067 double lastIn = 0;
2068 double firstOut = 1;
2069
2070 /*
2071 * Perform binary search to determine reasonable lastIn and firstOut.
2072 */
2073 static const double EPSILON = 1e-12;
2074 while ((firstOut - lastIn) * dist > EPSILON) {
2075 const double new_pos = .5 * (lastIn + firstOut);
2076 const PointT new_pt = p0 * (1.0 - new_pos) + p1 * new_pos;
2077 const unsigned int new_comp =
2078 component_of(component, new_pt, _ssearch);
2079
2080 if (new_comp == current_component) {
2081 lastIn = new_pos;
2082 } else {
2083 firstOut = new_pos;
2084 comp = new_comp;
2085 }
2086 }
2087
2088 if (lastIn != 0)
2089 current_polyLine.add_point(p0 * (1.0 - lastIn) + p1 * lastIn);
2090 if (current_polyLine.n_vertices() >= 2)
2091 out_polylines.push_back(current_polyLine);
2092 current_polyLine.clear();
2093 current_polyLine.add_point(p0 * (1.0 - firstOut) + p1 * firstOut);
2094 current_component = comp;
2095
2096 // Update
2097 p0 = p0 * (1.0 - firstOut) + p1 * firstOut;
2098 } while (comp != next_comp);
2099
2100 if (current_polyLine.back() != *pt_it)
2101 current_polyLine.add_point(*pt_it);
2102 }
2103
2104 if (current_polyLine.n_vertices() >= 2)
2105 out_polylines.push_back(current_polyLine);
2106
2107 // hack! if no splitting return original polyline
2108 if(out_polylines.size() <= 1)
2109 {
2110 out_polylines.clear();
2111 out_polylines.push_back(*this);
2112 }
2113}
2114
2115template <class PointT>
2116typename PolyLineT<PointT>::CustomPropertyHandle PolyLineT<PointT>::custom_prop_handle(const CustomProperty* _prop) const {
2117 size_t n = cprop_enum.size();
2118 for (int i = 0; i < n; ++i)
2119 if (cprop_enum[i] == _prop)
2120 return i;
2121 return -1;
2122}
2123
2124template <class PointT>
2125typename PolyLineT<PointT>::CustomProperty* PolyLineT<PointT>::custom_prop(CustomPropertyHandle _handle) {
2126 return (_handle >= 0 && _handle < int(get_num_custom_properties()) ? cprop_enum[_handle] : NULL);
2127}
2128
2129template <class PointT>
2130const typename PolyLineT<PointT>::CustomProperty* PolyLineT<PointT>::custom_prop(CustomPropertyHandle _handle) const {
2131 return (_handle >= 0 && _handle < int(get_num_custom_properties()) ? cprop_enum[_handle] : NULL);
2132}
2133
2134template <class PointT>
2135typename PolyLineT<PointT>::CustomPropertyHandle PolyLineT<PointT>::
2136 request_custom_property(const std::string& _name,
2137 unsigned int _prop_size) {
2138
2139 CustomPropertyHandle h = get_custom_property_handle(_name);
2140 CustomProperty* pcontainer = custom_prop(h);
2141
2142 if (!pcontainer) {
2143
2144 // create new property container
2145 pcontainer = new CustomProperty;
2146
2147 pcontainer->name = _name;
2148 pcontainer->ref_count = 1;
2149 pcontainer->prop_size = _prop_size;
2150
2151 pcontainer->datatype = 0;
2152
2153 pcontainer->prop_data.resize(n_vertices() * _prop_size, 0);
2154
2155 custom_properties[_name] = pcontainer;
2156
2157 cprop_enum.push_back(pcontainer);
2158 } else {
2159
2160 if (++pcontainer->ref_count < 1)
2161 pcontainer->ref_count = 1;
2162 }
2163
2164 return custom_prop_handle(pcontainer);
2165}
2166
2167template <class PointT>
2168void PolyLineT<PointT>::
2169 release_custom_property(CustomPropertyHandle _prop_handle) {
2170
2171 CustomProperty* p = custom_prop(_prop_handle);
2172
2173 if (p && --(p->ref_count) <= 0)
2174 p->prop_data.clear();
2175}
2176
2177template <class PointT>
2178void PolyLineT<PointT>::
2179 release_custom_property(const std::string& _name) {
2180
2181 CustomPropertyHandle h = get_custom_property_handle(_name);
2182 release_custom_property(h);
2183}
2184
2185template <class PointT>
2186typename PolyLineT<PointT>::CustomPropertyHandle PolyLineT<PointT>::
2187 get_custom_property_handle(const std::string& _name) const {
2188
2189 typename CustomPropertyMap::const_iterator it = custom_properties.find(_name);
2190
2191 if (it == custom_properties.end())
2192 return -1;
2193
2194 return custom_prop_handle(it->second);
2195}
2196
2197template <class PointT>
2198const std::string PolyLineT<PointT>::
2199 get_custom_property_name(CustomPropertyHandle _property_handle) const {
2200
2201 const CustomProperty* p = custom_prop(_property_handle);
2202
2203 if (p)
2204 return p->name;
2205
2206 std::cerr << "PolyLineT::get_custom_property_name - invalid handle" << std::endl;
2207
2208 return "";
2209}
2210
2211
2212template <class PointT>
2213void PolyLineT<PointT>::
2214 set_custom_property(CustomPropertyHandle _property_handle,
2215 unsigned int _i,
2216 const void* _data) {
2217
2218 if (!_data) {
2219 std::cerr << "PolyLineT::set_custom_property - invalid data" << std::endl;
2220 return;
2221 }
2222
2223 CustomProperty* p = custom_prop(_property_handle);
2224
2225 if (p) {
2226 unsigned int offset = p->prop_size * _i;
2227
2228 // check out of range
2229 if (offset + p->prop_size > p->prop_data.size()) {
2230 std::cerr << "PolyLineT::set_custom_property - out of range access" << std::endl;
2231 return;
2232 }
2233
2234
2235 // copy data byte-wise
2236 memcpy(p->buffer() + offset, _data, p->prop_size);
2237 }
2238 else
2239 std::cerr << "PolyLineT::set_custom_property - invalid handle" << std::endl;
2240}
2241
2242template <class PointT>
2243void PolyLineT<PointT>::
2244 set_custom_property(const std::string& _name,
2245 unsigned int _i,
2246 const void* _data) {
2247
2248 CustomPropertyHandle h = get_custom_property_handle(_name);
2249 set_custom_property(h, _i, _data);
2250}
2251
2252template <class PointT>
2253void PolyLineT<PointT>::
2254 get_custom_property(CustomPropertyHandle _property_handle,
2255 unsigned int _i,
2256 void* _dst) const {
2257
2258 if (!_dst) {
2259 std::cerr << "PolyLineT::get_custom_property - invalid destination address" << std::endl;
2260 return;
2261 }
2262
2263 const CustomProperty* p = custom_prop(_property_handle);
2264
2265 if (p) {
2266
2267 unsigned int offset = p->prop_size * _i;
2268
2269 // check out of range
2270 if (offset + p->prop_size > p->prop_data.size()) {
2271 std::cerr << "PolyLineT::get_custom_property - out of range access" << std::endl;
2272 return;
2273 }
2274
2275 // copy data byte-wise
2276 memcpy(_dst, p->buffer() + offset, p->prop_size);
2277 }
2278 else
2279 std::cerr << "PolyLineT::get_custom_property - invalid handle" << std::endl;
2280}
2281
2282template <class PointT>
2283void PolyLineT<PointT>::
2284 get_custom_property(const std::string& _name,
2285 unsigned int _i,
2286 void* _data) const {
2287
2288 CustomPropertyHandle h = get_custom_property_handle(_name);
2289 get_custom_property(h, _i, _data);
2290}
2291
2292
2293template <class PointT>
2294bool PolyLineT<PointT>::
2295 custom_property_available(CustomPropertyHandle _property_handle) const {
2296
2297 const CustomProperty* p = custom_prop(_property_handle);
2298
2299 if (p)
2300 return p->ref_count > 0;
2301
2302 return false;
2303}
2304
2305
2306template <class PointT>
2307bool PolyLineT<PointT>::
2308 custom_property_available(const std::string& _name) const {
2309
2310 CustomPropertyHandle h = get_custom_property_handle(_name);
2311 return custom_property_available(h);
2312}
2313
2314
2315template <class PointT>
2317 bind_custom_property_to_shader(CustomPropertyHandle _property_handle, const std::string& _shader_input_name, unsigned int _datatype) {
2318
2319 CustomProperty* p = custom_prop(_property_handle);
2320
2321 if (p) {
2322
2323 p->datatype = _datatype;
2324 p->shader_binding = _shader_input_name;
2325
2326 } else
2327 std::cerr << "PolyLineT::bind_custom_property_to_shader - invalid handle" << std::endl;
2328}
2329
2330
2331template <class PointT>
2333 get_custom_property_shader_binding(CustomPropertyHandle _property_handle, unsigned int* _propsize, const char** _input_name, unsigned int* _datatype) const {
2334
2335 const CustomProperty* p = custom_prop(_property_handle);
2336
2337 if (p) {
2338
2339 if (_propsize)
2340 *_propsize = p->prop_size;
2341
2342 if (_input_name)
2343 *_input_name = p->shader_binding.c_str();
2344
2345 if (_datatype)
2346 *_datatype = p->datatype;
2347
2348 return !p->shader_binding.empty() && p->datatype;
2349 }
2350 else
2351 std::cerr << "PolyLineT::get_custom_property_shader_binding - invalid handle" << std::endl;
2352
2353 return false;
2354}
2355
2356template <class PointT>
2357const void* PolyLineT<PointT>::
2358 get_custom_property_buffer(CustomPropertyHandle _property_handle) const {
2359
2360 const CustomProperty* p = custom_prop(_property_handle);
2361
2362 if (p)
2363 return p->buffer();
2364 else
2365 std::cerr << "PolyLineT::get_custom_property_buffer - invalid handle" << std::endl;
2366
2367 return NULL;
2368}
2369
2370template <class PointT>
2371unsigned int PolyLineT<PointT>::
2372 get_num_custom_properties() const {
2373 return custom_properties.size();
2374}
2375
2376template <class PointT>
2377typename PolyLineT<PointT>::CustomPropertyHandle PolyLineT<PointT>::
2378 enumerate_custom_property_handles(unsigned int _i) const {
2379
2380 if (_i < get_num_custom_properties())
2381 return CustomPropertyHandle(_i);
2382 else
2383 return -1;
2384}
2385
2386//=============================================================================
2387} // namespace ACG
2388//=============================================================================
size_t n_vertices() const
Get number of vertices.
Definition: PolyLineT.hh:119
void split_closed(unsigned int _split_idx)
Split closed polyline at vertex with index _split_idx.
void smooth_uniform_laplace()
Laplacian smoothing.
void insert_point(int _idx, const Point &_p)
insert _p at _idx into polyline
bool on_multiple_components(MeshT &_mesh, SpatialSearchT &_ssearch)
void set_closed(const bool _c)
Set if the polyline should be closed and therefore forms a loop.
Definition: PolyLineT.hh:116
void bind_custom_property_to_shader(CustomPropertyHandle _property_handle, const std::string &_shader_input_name, unsigned int _datatype)
Binding to vertex shader (optional)
void print() const
Print information string to cerr.
void mark_components(OpenMesh::PropertyManager< OpenMesh::FPropHandleT< unsigned int >, MeshT > &component)
Point position_arclength(const Scalar _t) const
Same as position but with an arclength parameterization in [0,length()].
LineNodeT * get_line_node(LineNodeT *&_line_node, int _mode=0)
Conversion PolyLine <-> LineNode.
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
Point & point(unsigned int _i)
Get a point of the polyline.
Definition: PolyLineT.hh:145
Point find_nearest_point(const MeshT &_mesh, const Point &_point, typename MeshT::FaceHandle &_fh, SpatialSearchT *_ssearch=0, double *_dbest=0)
unsigned int component_of(const OpenMesh::PropertyManager< OpenMesh::FPropHandleT< unsigned int >, MeshT > &component, const PointT &pt, SpatialSearchT &_ssearch)
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 position(const Scalar _t) const
Provide linear paremterization of the polyline in [0,1].
size_t n_edges() const
Get number of edges.
PolyLineT(bool _closed=false)
Constructor.
void resample_arclength_uniform(const unsigned int _n)
Perform an uniform arclength resampling while maintaining the start and end point.
void delete_point(int _idx)
Delete point at _idx.
void resize(unsigned int _n)
Resize current polyline.
void collapse(Scalar _smallest)
Collapse polyline.
void smooth_uniform_laplace2()
Squared laplacian smoothing.
void prepend(const PolyLineT< PointT > &_pl)
Prepend second polyline _pl to polyline.
void invert()
Invert polyline that first vertex becomes last.
void project_to_mesh(const MeshT &_mesh, SpatialSearchT *_ssearch=0)
Project polyline points to nearest surface points (use spatial search!!!)
void smooth_uniform_laplace3()
Cubic laplacian smoothing.
void subdivide(Scalar _largest)
Subdivide polyline.
bool is_closed() const
Check if the polyline is marked as closed.
Definition: PolyLineT.hh:110
void split(unsigned int _split_idx, PolyLineT< PointT > &_new_pl)
Split closed polyline at vertex with index _split_idx.
Scalar length() const
Compute the length of the polyline (in future cached method)
void clear()
Clear the current polyline.
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 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
void add_point(const Point &_p)
Append a point to the polyline.
bool plane_line_intersection(const IPoint &_p_plane, const IPoint &_n_plane, const IPoint &_p0, const IPoint &_p1, IPoint &_p_int)
Scalar total_gaussian_curvature()
compute total gaussian curvature of enclosed surface (via Gauss-Bonnet)
void append(const PolyLineT< PointT > &_pl)
Append second polyline _pl to this one.
void split_into_one_per_component(MeshT &_mesh, SpatialSearchT &_ssearch, std::vector< PolyLineT > &out_polylines)
Point & back()
Get last point of the polyline ( no range check!!!)
Definition: PolyLineT.hh:163
static HalfEdgeHandle halfedge_handle(EdgeHandle _h, const unsigned char _subIdx)
Conversion function.
static EdgeHandle edge_handle(HalfEdgeHandle _h)
Handle conversion.
VertexHandle from_vertex_handle(HalfEdgeHandle _h) const
Get the vertex the halfedge starts from.
VertexHandle to_vertex_handle(HalfEdgeHandle _h) const
Get the vertex the halfedge points to.
VectorT< Scalar, 3 > perpendicular(const VectorT< Scalar, 3 > &v)
find a vector that's perpendicular to _v
Definition: Algorithms.cc:1152
Namespace providing different geometric functions concerning angles.
PolyConnectivity::ConstFaceFaceRange faces() const
Returns a range adjacent faces of the face (PolyConnectivity::ff_range())