OpendTect  6.3
polygon.h
Go to the documentation of this file.
1 #pragma once
2 
3 /*+
4 ________________________________________________________________________
5 
6  (C) dGB Beheer B.V.; (LICENSE) http://opendtect.org/OpendTect_license.txt
7  Author: J.C. Glas
8  Date: Dec 2006
9 ________________________________________________________________________
10 
11 -*/
12 
13 #include "coord.h"
14 #include "typeset.h"
15 #include "iopar.h"
16 #include "bufstring.h"
17 #include "bendpointfinder.h"
18 #include <math.h>
19 
24 template <class T>
26 {
27 public:
29  : closed_(true), udf_(Geom::Point2D<T>::udf())
30  , xrg_(mUdf(T),mUdf(T)), yrg_(mUdf(T),mUdf(T)) {}
31 
33  : poly_(plg), closed_(true)
34  , udf_(Geom::Point2D<T>::udf())
35  , xrg_(mUdf(T),mUdf(T)), yrg_(mUdf(T),mUdf(T)) {}
36 
37  template <class T2>
38  inline void set(const ODPolygon<T2>&);
39 
40  void erase();
41  bool isEmpty() const { return poly_.isEmpty(); }
42 
43  int size() const { return poly_.size(); }
44  bool validIdx(int idx) const { return poly_.validIdx(idx); }
45  void setEmpty() { erase(); }
46 
47  void add(const Geom::Point2D<T>& vtx);
48  void remove(int idx);
49  void insert(int idx,const Geom::Point2D<T>& vtx);
50 
51  bool isInside(const Geom::Point2D<T>&,
52  bool inclborder,T eps) const;
53 
54  int isInside(const ODPolygon& testpoly,T eps=0) const;
55  /* 0: testpoly fully outside (borders don't touch)
56  2: testpoly fully inside (borders don't touch)
57  1: all intermediate cases */
58 
59  bool segmentMeetsBorder(const Geom::Point2D<T>& pt1,
60  const Geom::Point2D<T>& pt2,T eps) const;
61  bool windowOverlaps(const Interval<T>& xrange,
62  const Interval<T>& yrange,T eps) const;
63 
64  // defined for closed polygon
65  const Geom::Point2D<T>& getVertex(int idx) const;
66  const Geom::Point2D<T>& nextVertex(int idx) const;
67  const Geom::Point2D<T>& prevVertex(int idx) const;
68 
69  void setClosed( bool yn ) { closed_ = yn; }
70  bool isClosed() const { return closed_; }
71  void setUdf( Geom::Point2D<T> pt ) { udf_ = pt; }
72  Geom::Point2D<T> getUdf() const { return udf_; }
73  const TypeSet<Geom::Point2D<T> >& data() const { return poly_; }
74 
75  Interval<T> getRange(bool of_x) const;
76  void getData(bool of_x,TypeSet<T>&) const;
77 
78  void removeZeroLengths();
79  bool isUTurn(int idx) const;
80  bool isSelfIntersecting() const;
81 
82  void convexHull();
83  void keepBendPoints(float eps);
84 
85  // not for self-intersecting polygons
86  double area() const { return fabs(sgnArea2<double>()/2.0); }
87  bool clockwise() const { return sgnArea2<T>()<0; }
88  bool anticlockwise() const { return sgnArea2<T>()>0; }
89 
90  void reverse();
91 
92  double distTo(const Geom::Point2D<T>& refpt,int* segmentidxptr=0,
93  double* fractionptr=0) const;
94 
95  double maxDistToBorderEstimate(double maxrelerr=0.001) const;
96 
97  bool operator==(const ODPolygon<T>&) const;
98  bool operator>( const ODPolygon<T>& plg ) const
99  { return poly_.size()>plg.size(); }
100 
101 protected:
102 
103  static int doSegmentsMeet( const Geom::Point2D<T>& p1,
104  const Geom::Point2D<T>& p2,
105  const Geom::Point2D<T>& q1,
106  const Geom::Point2D<T>& q2,
107  T eps );
108 
109  static bool isOnSegment( const Geom::Point2D<T>& pt,
110  const Geom::Point2D<T>& pt0,
111  const Geom::Point2D<T>& pt1,
112  T eps );
113  static bool isOnHalfLine( const Geom::Point2D<T>& point,
114  const Geom::Point2D<T>& dirvec,
115  const Geom::Point2D<T>& endvec,
116  T eps );
117 
118  static bool isEdgeCrossing( const Geom::Point2D<T>& raydir,
119  const Geom::Point2D<T>& raysrc,
120  const Geom::Point2D<T>& vtx1,
121  const Geom::Point2D<T>& vtx2 );
122 
123  static bool isOnLine( const Geom::Point2D<T>& point,
124  const Geom::Point2D<T>& dirvec,
125  const Geom::Point2D<T>& posvec,
126  T eps );
127 
128  static bool isRightOfLine( const Geom::Point2D<T>& point,
129  const Geom::Point2D<T>& dirvec,
130  const Geom::Point2D<T>& posvec );
131 
132  static bool doCoincide( const Geom::Point2D<T>& point1,
133  const Geom::Point2D<T>& point2,
134  T eps=mDefEps );
135 
136  static double sgnDistToLine( const Geom::Point2D<T>& point,
137  const Geom::Point2D<T>& dirvec,
138  const Geom::Point2D<T>& posvec );
139 
140  template <class ST> ST sgnArea2() const;
141 
142  static double distToSegment( const Geom::Point2D<T>& p1,
143  const Geom::Point2D<T>& p2,
144  const Geom::Point2D<T>& refpt,
145  double* fractionptr=0 );
146 
148  bool closed_;
150 
151  mutable Interval<T> xrg_;
152  mutable Interval<T> yrg_;
153 };
154 
155 
156 template <class T> inline
157 bool ODPolygon<T>::operator==( const ODPolygon<T>& poly ) const
158 {
159  if ( data() != poly.data() ) return false;
160  return true;
161 }
162 
163 
164 template <class T> template <class T2>
165 inline void ODPolygon<T>::set( const ODPolygon<T2>& oth )
166 {
167  for ( int idx=0; idx<oth.size(); idx++ )
168  {
169  const Geom::Point2D<T2>& vtx = oth.getVertex( idx );
170  poly_ += Geom::Point2D<T>( (T)vtx.x_, (T)vtx.y_ );
171  }
172 }
173 
174 
175 template <class T> inline
176 void ODPolygon<T>::getData( bool forx, TypeSet<T>& ts ) const
177 {
178  for ( int idx=0; idx<size(); idx++ )
179  {
180  const Geom::Point2D<T>& vtx = poly_[idx];
181  ts += forx ? vtx.x_ : vtx.y_;
182  }
183 }
184 
185 
186 template <class T> inline
187 void fillPar( IOPar& iop, const ODPolygon<T>& poly, const char* inpkey )
188 {
189  const BufferString keywd( inpkey ); const char* key = keywd.buf();
190  iop.setYN( IOPar::compKey(key,"Closed"), poly.isClosed() );
191  iop.set( IOPar::compKey(key,"Undef"), poly.getUdf().x_, poly.getUdf().y_ );
192  TypeSet<T> ts; poly.getData( true, ts );
193  iop.set( IOPar::compKey(key,"Data.X"), ts );
194  ts.erase(); poly.getData( false, ts );
195  iop.set( IOPar::compKey(key,"Data.Y"), ts );
196 }
197 
198 
199 template <class T> inline
200 void usePar( const IOPar& iop, ODPolygon<T>& poly, const char* inpkey )
201 {
202  const BufferString keywd( inpkey ); const char* key = keywd.buf();
203  bool yn = false; iop.getYN( IOPar::compKey(key,"Closed"), yn );
204  poly.setClosed( yn );
205  Geom::Point2D<T> pt; iop.get( IOPar::compKey(key,"Undef"), pt.x_, pt.y_ );
206  poly.setUdf( pt );
207 
208  if ( !iop.find( IOPar::compKey(key,"Data.X") )
209  || !iop.find( IOPar::compKey(key,"Data.Y") ) )
210  return;
211 
212  poly.setEmpty(); TypeSet<T> tsx, tsy;
213  iop.get( IOPar::compKey(key,"Data.X"), tsx );
214  iop.get( IOPar::compKey(key,"Data.Y"), tsy );
215  const int sz = tsx.size() > tsy.size() ? tsy.size() : tsx.size();
216  for ( int idx=0; idx<sz; idx++ )
217  poly.add( Geom::Point2D<T>(tsx[idx],tsy[idx]) );
218 }
219 
220 
221 template <class T> inline
222 void ODPolygon<T>::insert( int idx, const Geom::Point2D<T>& vtx )
223 {
224  if ( idx>=0 && idx<=size() )
225  poly_.insert( idx, vtx );
226  xrg_.set( mUdf(T), mUdf(T) );
227  yrg_.set( mUdf(T), mUdf(T) );
228 }
229 
230 
231 template <class T> inline
233 {
234  poly_.erase();
235  xrg_.set( mUdf(T), mUdf(T) );
236  yrg_.set( mUdf(T), mUdf(T) );
237 }
238 
239 
240 template <class T> inline
242 {
243  poly_+=vtx;
244  xrg_.set( mUdf(T), mUdf(T) );
245  yrg_.set( mUdf(T), mUdf(T) );
246 }
247 
248 
249 template <class T> inline
250 void ODPolygon<T>::remove( int idx )
251 {
252  if ( poly_.validIdx(idx) )
253  poly_.removeSingle( idx );
254  xrg_.set( mUdf(T), mUdf(T) );
255  yrg_.set( mUdf(T), mUdf(T) );
256 }
257 
258 
259 template <class T> inline
261 { return poly_.validIdx(idx) ? poly_[idx] : udf_; }
262 
263 
264 template <class T> inline
266 { return getVertex( idx+1<size() ? idx+1 : 0 ); }
267 
268 
269 template <class T> inline
271 { return getVertex( idx ? idx-1 : size()-1 ); }
272 
273 
274 template <class T> inline
276 {
277  if ( poly_.isEmpty() ) return Interval<T>( udf_.x_, udf_.y_ );
278  Geom::Point2D<T> vtx0 = poly_[0];
279  Interval<T> ret = forx ? xrg_ : yrg_;
280  if ( !mIsUdf(ret.start) && !mIsUdf(ret.stop) )
281  return ret;
282  ret.start = ret.stop = forx ? vtx0.x_ : vtx0.y_;
283  for ( int idx=1; idx<size(); idx++ )
284  {
285  const Geom::Point2D<T>& vtx = poly_[idx];
286  const T val = forx ? vtx.x_ : vtx.y_;
287  if ( val < ret.start ) ret.start = val;
288  else if ( val > ret.stop ) ret.stop = val;
289  }
290  if ( forx )
291  xrg_ = ret;
292  else
293  yrg_ = ret;
294  return ret;
295 }
296 
297 
298 template <class T> inline
300  bool inclborder, T eps ) const
301 {
302  const T abseps = eps<0 ? -eps : eps;
303  if ( (!mIsUdf(xrg_.start) && !mIsUdf(xrg_.stop) &&
304  (xrg_.start>point.x_+abseps || xrg_.stop<point.x_-abseps)) ||
305  (!mIsUdf(yrg_.start) && !mIsUdf(yrg_.stop) &&
306  (yrg_.start>point.y_+abseps || yrg_.stop<point.y_-abseps)) )
307  return false;
308 
309  const Geom::Point2D<T> arbitrarydir( 1, 0 );
310 
311  bool nrcrossingsodd = false;
312  for ( int idx=0; idx<size(); idx++ )
313  {
314  const Geom::Point2D<T>& vtxcurr = poly_[idx];
315  const Geom::Point2D<T>& vtxnext = nextVertex( idx );
316 
317  if ( isOnSegment(point, vtxcurr, vtxnext, eps) )
318  return inclborder;
319  if ( isEdgeCrossing(arbitrarydir, point, vtxcurr, vtxnext) )
320  nrcrossingsodd = !nrcrossingsodd;
321  }
322 
323  return nrcrossingsodd;
324 }
325 
326 
327 template <class T> inline
329  const Geom::Point2D<T>& pt2,
330  T eps ) const
331 {
332  for ( int idx=0; idx<size(); idx++ )
333  {
334  const Geom::Point2D<T>& vtxcurr = poly_[idx];
335  const Geom::Point2D<T>& vtxnext = nextVertex( idx );
336 
337  if ( doSegmentsMeet(pt1, pt2, vtxcurr, vtxnext, eps) )
338  return true;
339  }
340 
341  return false;
342 }
343 
344 
345 template <class T> inline
347  const Interval<T>& yrange,
348  T eps ) const
349 {
350  ODPolygon window;
351  window.add( Geom::Point2D<T>(xrange.start, yrange.start) );
352  window.add( Geom::Point2D<T>(xrange.stop, yrange.start) );
353  window.add( Geom::Point2D<T>(xrange.stop, yrange.stop) );
354  window.add( Geom::Point2D<T>( xrange.start, yrange.stop) );
355 
356  return isInside( window, eps );
357 }
358 
359 
360 template <class T> inline
361 int ODPolygon<T>::isInside( const ODPolygon& testpoly, T eps ) const
362 {
363  if ( isEmpty() || testpoly.isEmpty() )
364  return 0;
365 
366  for ( int idx=0; idx<size(); idx++ )
367  {
368  const Geom::Point2D<T>& vtxcurr = poly_[idx];
369  const Geom::Point2D<T>& vtxnext = nextVertex( idx );
370 
371  if ( testpoly.segmentMeetsBorder(vtxcurr, vtxnext, eps) )
372  return 1;
373  }
374 
375  if ( isInside(testpoly.poly_[0], false, eps) )
376  return 2;
377 
378  return testpoly.isInside(poly_[0], false, eps) ? 1 : 0;
379 }
380 
381 
382 template <class T> inline
384 {
385  const int startidx = isClosed() ? size()-1 : size()-2;
386  for ( int idx=startidx; idx>=0; idx-- )
387  {
388  if ( poly_[idx]==nextVertex(idx) && size()>1 )
389  remove(idx);
390  }
391 }
392 
393 
394 template <class T> inline
395 bool ODPolygon<T>::isUTurn( int idx ) const
396 {
397  if ( !validIdx(idx) || ( !isClosed() && (idx==0 || idx==size()-1) ) )
398  return false;
399 
400  const Geom::Point2D<T>& vec1 = prevVertex(idx) - poly_[idx];
401  const Geom::Point2D<T>& vec2 = nextVertex(idx) - poly_[idx];
402 
403  return vec1.x_*vec2.y_-vec1.y_*vec2.x_==0 &&
404  vec1.x_*vec2.x_+vec1.y_*vec2.y_>0;
405 }
406 
407 
408 template <class T> inline
410 {
411  ODPolygon<T> plg = *this;
412  plg.removeZeroLengths();
413 
414  const int stopidx = plg.isClosed() ? plg.size() : plg.size()-1;
415  for ( int idx=0; idx<stopidx; idx++ )
416  {
417  if ( plg.isUTurn(idx) )
418  return true;
419 
420  const Geom::Point2D<T>& vtxcurr = plg.poly_[idx];
421  const Geom::Point2D<T>& vtxnext = plg.nextVertex( idx );
422 
423  for ( int idy=0; idy<stopidx; idy++ )
424  {
425  const int dif = abs( idx-idy );
426  if ( dif<=1 || dif>=plg.size()-1 )
427  continue;
428 
429  const Geom::Point2D<T>& pt1 = plg.poly_[idy];
430  const Geom::Point2D<T>& pt2 = plg.nextVertex( idy );
431 
432  if ( vtxcurr==pt1 || vtxcurr==pt2 )
433  return true;
434 
435  if ( isEdgeCrossing(vtxnext-vtxcurr, vtxcurr, pt1, pt2) &&
436  isEdgeCrossing(vtxcurr-vtxnext, vtxnext, pt1, pt2) )
437  return true;
438  }
439  }
440  return false;
441 }
442 
443 
444 template <class T> inline
446  const Geom::Point2D<T>& p2,
447  const Geom::Point2D<T>& q1,
448  const Geom::Point2D<T>& q2,
449  T eps )
450 {
451  if ( isOnSegment(p1, q1, q2, eps) || isOnSegment(p2, q1, q2, eps) ||
452  isOnSegment(q1, p1, p2, eps) || isOnSegment(q2, p1, p2, eps) )
453  return 1;
454 
455  if ( p1==p2 || q1==q2 || !isEdgeCrossing(p2-p1, p1, q1, q2) ||
456  !isEdgeCrossing(p1-p2, p2, q1, q2) )
457  return 0;
458 
459  return 2;
460 }
461 
462 
463 template <class T> inline
465  const Geom::Point2D<T>& pt0,
466  const Geom::Point2D<T>& pt1,
467  T eps )
468 {
469  return isOnHalfLine( pt, pt1-pt0, pt0, eps ) &&
470  isOnHalfLine( pt, pt0-pt1, pt1, eps );
471 }
472 
473 
474 template <class T> inline
476  const Geom::Point2D<T>& dirvec,
477  const Geom::Point2D<T>& endvec,
478  T eps )
479 {
480  if ( doCoincide(point, endvec, eps) )
481  return true;
482  if ( !isOnLine(point, dirvec, endvec, eps) )
483  return false;
484  const Geom::Point2D<T> rot90dirvec( -dirvec.y_, dirvec.x_ );
485  return isRightOfLine( point, rot90dirvec, endvec );
486 }
487 
488 
489 template <class T> inline
491  const Geom::Point2D<T>& raysrc,
492  const Geom::Point2D<T>& vtx1,
493  const Geom::Point2D<T>& vtx2 )
494 {
495  const bool vtx1right = isRightOfLine( vtx1, raydir, raysrc );
496  const bool vtx2right = isRightOfLine( vtx2, raydir, raysrc );
497 
498  if ( vtx1right && !vtx2right )
499  return !isRightOfLine( raysrc, vtx2-vtx1, vtx1 );
500  if ( !vtx1right && vtx2right )
501  return !isRightOfLine( raysrc, vtx1-vtx2, vtx2 );
502  return false;
503 }
504 
505 
506 template <class T> inline
508  const Geom::Point2D<T>& dirvec,
509  const Geom::Point2D<T>& posvec,
510  T eps )
511 {
512  const double signeddist = sgnDistToLine( point, dirvec, posvec );
513  return signeddist * signeddist <= eps * eps;
514 }
515 
516 template <class T> inline
518  const Geom::Point2D<T>& dirvec,
519  const Geom::Point2D<T>& posvec )
520 {
521  return sgnDistToLine( point, dirvec, posvec ) > 0;
522 }
523 
524 
525 template <class T> inline
527  const Geom::Point2D<T>& point2,
528  T eps )
529 {
530  return point1.sqDistTo( point2 ) <= eps * eps;
531 }
532 
533 
534 template <class T> inline
536  const Geom::Point2D<T>& dirvec,
537  const Geom::Point2D<T>& posvec )
538 {
539  const double nolinedist = 0;
540 
541  const double dirveclen =
542  dirvec.template distTo<double>( Geom::Point2D<T>(0,0) );
543  if ( mIsZero(dirveclen, mDefEps) )
544  return nolinedist;
545  const double substpointinlineeqn =
546  dirvec.y_ * (point.x_-posvec.x_) - dirvec.x_ * (point.y_-posvec.y_);
547  return substpointinlineeqn / dirveclen;
548 }
549 
550 
551 template <class T>
552 template <class ST> inline
554 {
555  ST area2 = 0;
556 
557  const Geom::Point2D<T>& pt0 = poly_[0];
558  for ( int idx=1; idx<size()-1; idx++ )
559  {
560  const Geom::Point2D<T>& pt1 = poly_[idx];
561  const Geom::Point2D<T>& pt2 = nextVertex( idx );
562  area2 += (ST) ( (pt1.x_-pt0.x_) * (pt2.y_-pt0.y_) -
563  (pt2.x_-pt0.x_) * (pt1.y_-pt0.y_) );
564  }
565 
566  return area2;
567 }
568 
569 
570 template <class T> inline
572 {
573  // Code based on the Graham scan algorithm (1972)
574 
575  setClosed( true );
576  if ( size()<2 )
577  return;
578 
579  // Find guaranteed vertex of the convex hull to become pivot
580  Geom::Point2D<T> pivot = poly_[0];
581  for ( int idx=1; idx<size(); idx++ )
582  {
583  const Geom::Point2D<T>& vtx = poly_[idx];
584  if ( vtx.x_<pivot.x_ || (vtx.x_==pivot.x_ && vtx.y_<pivot.y_) )
585  pivot = vtx;
586  }
587 
588  // Remove all pivot copies
589  for ( int idx=size()-1; idx>=0; idx-- )
590  {
591  if ( pivot == poly_[idx] )
592  //poly_.removeSingle( idx, false );
593  poly_.removeSingle( idx );
594  }
595 
596  // Angular sort of all pivot-to-point segments
597  for ( int idx=size()-2; idx>=0; idx-- )
598  {
599  const Geom::Point2D<T>& vtx = poly_[idx];
600  for ( int idy=size()-1; idy>idx; idy-- )
601  {
602  const Geom::Point2D<T>& vty = poly_[idy];
603  const double dist = sgnDistToLine( vty, vtx-pivot, pivot );
604 
605  if ( dist > 0 )
606  continue;
607 
608  if ( dist < 0 )
609  poly_.insert( idy+1, vtx );
610  else if ( pivot.sqDistTo(vtx) > pivot.sqDistTo(vty) )
611  poly_[idy] = vtx;
612 
613  poly_.removeSingle( idx );
614  break;
615  }
616  }
617 
618  // Expand convex hull incrementally by backward removal of inner points
619  for ( int idx=size()-3; idx>=0; idx-- )
620  {
621  const Geom::Point2D<T>& vtx = poly_[idx];
622  while ( idx<size()-2 )
623  {
624  const Geom::Point2D<T>& vty = poly_[idx+1];
625  const Geom::Point2D<T>& vtz = poly_[idx+2];
626  if ( isRightOfLine(vtz, vty-vtx, vtx) )
627  break;
628 
629  poly_.removeSingle( idx+1 );
630  }
631  }
632 
633  poly_ += pivot;
634 
635  xrg_.set( mUdf(T), mUdf(T) );
636  yrg_.set( mUdf(T), mUdf(T) );
637 }
638 
639 
640 template <class T> inline
642 {
643  const int sz = poly_.size();
644  for ( int idx=0; idx<sz/2-1; idx++ )
645  {
646  Geom::Point2D<T> temp = poly_[idx];
647  poly_[idx] = poly_[sz-1-idx];
648  poly_[sz-1-idx] = temp;
649  }
650 
651  xrg_.set( mUdf(T), mUdf(T) );
652  yrg_.set( mUdf(T), mUdf(T) );
653 }
654 
655 
656 template <class T> inline
658  const Geom::Point2D<T>& p2,
659  const Geom::Point2D<T>& refpt,
660  double* fractionptr )
661 {
662  double frac = 0;
663 
664  if ( p1 != p2 )
665  {
666  const Geom::Point2D<T> dif = p2 - p1;
667  const double numerator = dif.x_*(refpt.x_-p1.x_) +
668  dif.y_*(refpt.y_-p1.y_);
669  frac = numerator / (dif.x_*dif.x_ + dif.y_*dif.y_);
670 
671  if ( frac < 0 )
672  frac = 0;
673  if ( frac > 1 )
674  frac = 1;
675  }
676 
677  if ( fractionptr )
678  *fractionptr = frac;
679 
680  const Geom::Point2D<T> pointonseg( (T)(p1.x_ * (1-frac) + p2.x_ * frac),
681  (T)(p1.y_ * (1-frac) + p2.y_ * frac) );
682  return refpt.template distTo<double>( pointonseg );
683 }
684 
685 
686 template <class T> inline
688  int* segmentidxptr, double* fractionptr ) const
689 {
690  const int sz = size();
691  if ( !sz )
692  return mUdf(double);
693 
694  double mindist = MAXDOUBLE;
695 
696  for ( int idx=(isClosed() ? sz-1 : sz-2); idx>=0; idx-- )
697  {
698  const Geom::Point2D<T>& pt1 = getVertex( idx );
699  const Geom::Point2D<T>& pt2 = nextVertex( idx );
700  double frac;
701  const double dist = distToSegment( pt1, pt2, refpt, &frac );
702 
703  if ( mindist >= dist )
704  {
705  mindist = dist;
706  if ( segmentidxptr )
707  *segmentidxptr = idx;
708  if ( fractionptr )
709  *fractionptr = frac;
710  }
711  }
712 
713  return mindist;
714 }
715 
716 
717 template <class T> inline
718 double ODPolygon<T>::maxDistToBorderEstimate( double maxrelerr ) const
719 {
720  if ( maxrelerr <= 0.0 )
721  return mUdf(double);
722 
723  if ( size() < 3 )
724  return isEmpty() ? mUdf(double) : 0.0;
725 
726  const double upperbound = mMIN( 0.5 * getRange(true).width(),
727  0.5 * getRange(false).width() );
728  if ( !upperbound )
729  return 0.0;
730 
731  ODPolygon<double> poly;
732  for ( int idx=0; idx<size(); idx++ )
733  {
734  const Geom::Point2D<T>& pt = getVertex(idx);
735  poly.add( Geom::Point2D<double>(pt.x_, pt.y_) );
736  }
737 
738  double maxdist = 0.0;
739  for ( int idx=0; idx<poly.size(); idx++ )
740  {
741  Geom::Point2D<double> curpt =
742  (poly.prevVertex(idx)+poly.getVertex(idx)+poly.nextVertex(idx)) / 3;
743 
744  if ( !poly.isInside(curpt, false, mDefEps) )
745  continue;
746 
747  double curdist = poly.distTo( curpt );
748  double gamma = 0.1 * upperbound;
749 
750  for ( int step=0; step<100; step++ )
751  {
752  if ( curdist > maxdist )
753  maxdist = curdist;
754 
755  // Gradient ascent
756  Geom::Point2D<double> pt1 = curpt;
757  Geom::Point2D<double> pt2 = curpt;
758  const double delta = 0.0001 * upperbound;
759  pt1.x_ += delta;
760  pt2.y_ += delta;
761  const double dist1 = poly.distTo( pt1 );
762  const double dist2 = poly.distTo( pt2 );
763  Geom::Point2D<double> nextpt( dist1-curdist, dist2-curdist );
764  nextpt *= gamma/delta;
765  nextpt += curpt;
766 
767  if ( !poly.isInside(nextpt, false, mDefEps) )
768  {
769  gamma *= 0.5;
770  continue;
771  }
772 
773  double nextdist = poly.distTo( nextpt );
774 
775  if ( nextdist <= curdist )
776  {
777  gamma *= 0.5;
778 
779  if ( curpt.distTo<double>(nextpt) <= 2*maxrelerr*curdist )
780  break;
781  }
782 
783  curpt = nextpt;
784  curdist = nextdist;
785  }
786  }
787  return maxdist;
788 }
789 
790 
791 template <class T> inline
793 {
794  removeZeroLengths();
795 
796  const int sz = size();
797  if ( sz < 3 )
798  return;
799 
800  const int extra = closed_ ? 1 : 0;
801 
802  TypeSet<Coord> coords;
803  for ( int idx=-extra; idx<sz+extra; idx++ )
804  {
805  const Geom::Point2D<T>& vtx = getVertex( (sz+idx)%sz );
806  coords += Coord( vtx.x_, vtx.y_ );
807  }
808 
809  BendPointFinder2D finder( coords, eps );
810  finder.execute();
811  const TypeSet<int>& bendpoints = finder.bendPoints();
812 
813  int bpidx = bendpoints.size()-extra-1;
814  if ( bpidx<0 )
815  return;
816 
817  for ( int vtxidx=sz-1; vtxidx>=0; vtxidx-- )
818  {
819  if ( bpidx>=0 && vtxidx==bendpoints[bpidx]-extra )
820  bpidx--;
821  else
822  remove( vtxidx );
823  }
824 
825  if ( closed_ && poly_.size()>1 && poly_.first() != poly_.last() )
826  poly_ += poly_.first();
827 }
const Geom::Point2D< T > & getVertex(int idx) const
Definition: polygon.h:260
bool isInside(const Geom::Point2D< T > &, bool inclborder, T eps) const
Definition: polygon.h:299
void remove(int idx)
Definition: polygon.h:250
#define mIsUdf(val)
Use mIsUdf to check for undefinedness of simple types.
Definition: undefval.h:285
void erase()
Definition: polygon.h:232
static bool isEdgeCrossing(const Geom::Point2D< T > &raydir, const Geom::Point2D< T > &raysrc, const Geom::Point2D< T > &vtx1, const Geom::Point2D< T > &vtx2)
Definition: polygon.h:490
void keepBendPoints(float eps)
Definition: polygon.h:792
bool isEmpty() const
Definition: polygon.h:41
bool clockwise() const
Definition: polygon.h:87
bool operator==(const ArrayNDInfo &a1, const ArrayNDInfo &a2)
Definition: arrayndinfo.h:51
const TypeSet< int > & bendPoints() const
Definition: bendpointfinder.h:31
static bool doCoincide(const Geom::Point2D< T > &point1, const Geom::Point2D< T > &point2, T eps=mDefEps)
Definition: polygon.h:526
bool windowOverlaps(const Interval< T > &xrange, const Interval< T > &yrange, T eps) const
Definition: polygon.h:346
Interval< T > getRange(bool of_x) const
Definition: polygon.h:275
#define mIsZero(x, eps)
Definition: commondefs.h:55
bool closed_
Definition: polygon.h:148
void convexHull()
Definition: polygon.h:571
void usePar(const IOPar &iop, ODPolygon< T > &poly, const char *inpkey)
Definition: polygon.h:200
void getData(bool of_x, TypeSet< T > &) const
Definition: polygon.h:176
static bool isOnLine(const Geom::Point2D< T > &point, const Geom::Point2D< T > &dirvec, const Geom::Point2D< T > &posvec, T eps)
Definition: polygon.h:507
Interval< T > yrg_
Definition: polygon.h:152
static bool isRightOfLine(const Geom::Point2D< T > &point, const Geom::Point2D< T > &dirvec, const Geom::Point2D< T > &posvec)
Definition: polygon.h:517
(Closed) sequence of connected 2-D coordinates.
Definition: polygon.h:25
const Geom::Point2D< T > & nextVertex(int idx) const
Definition: polygon.h:265
Used to find bendpoints in set of XY Coordinates.
Definition: bendpointfinder.h:79
TypeSet< Geom::Point2D< T > > poly_
Definition: polygon.h:147
void setUdf(Geom::Point2D< T > pt)
Definition: polygon.h:71
Geom::Point2D< T > udf_
Definition: polygon.h:149
double distTo(const Geom::Point2D< T > &refpt, int *segmentidxptr=0, double *fractionptr=0) const
Definition: polygon.h:687
T sqDistTo(const Point2D< T > &) const
Squared distance.
Definition: geometry.h:634
bool get(const char *, int &) const
ODPolygon(const TypeSet< Geom::Point2D< T > > &plg)
Definition: polygon.h:32
static const char * compKey(const char *, const char *)
The composite key: (a,b) -> a.b.
void add(const Geom::Point2D< T > &vtx)
Definition: polygon.h:241
void setClosed(bool yn)
Definition: polygon.h:69
#define mMIN(x, y)
Definition: commondefs.h:52
Interval of values.
Definition: commontypes.h:27
double area() const
Definition: polygon.h:86
bool validIdx(int idx) const
Definition: polygon.h:44
bool segmentMeetsBorder(const Geom::Point2D< T > &pt1, const Geom::Point2D< T > &pt2, T eps) const
Definition: polygon.h:328
bool operator>(const ODPolygon< T > &plg) const
Definition: polygon.h:98
Set of (small) copyable elements.
Definition: commontypes.h:26
FT distTo(const Point2D< T > &) const
Definition: geometry.h:629
Generalized set of parameters of the keyword-value type.
Definition: iopar.h:53
#define mUdf(type)
Use this macro to get the undefined for simple types.
Definition: undefval.h:270
bool execute()
Definition: paralleltask.h:69
const char * find(const char *) const
returns null if not found
bool isClosed() const
Definition: polygon.h:70
bool anticlockwise() const
Definition: polygon.h:88
T x_
Definition: geometry.h:80
void removeZeroLengths()
Definition: polygon.h:383
void setYN(const char *, bool)
void fillPar(IOPar &iop, const ODPolygon< T > &poly, const char *inpkey)
Definition: polygon.h:187
#define mDefEps
Definition: commondefs.h:60
const char * buf() const
Definition: odstring.h:45
static double distToSegment(const Geom::Point2D< T > &p1, const Geom::Point2D< T > &p2, const Geom::Point2D< T > &refpt, double *fractionptr=0)
Definition: polygon.h:657
static bool isOnSegment(const Geom::Point2D< T > &pt, const Geom::Point2D< T > &pt0, const Geom::Point2D< T > &pt1, T eps)
Definition: polygon.h:464
bool isUTurn(int idx) const
Definition: polygon.h:395
size_type size() const
T stop
Definition: ranges.h:91
OD::String with its own variable length buffer. The buffer has a guaranteed minimum size...
Definition: bufstring.h:38
bool isEmpty(const char *)
bool isSelfIntersecting() const
Definition: polygon.h:409
void insert(int idx, const Geom::Point2D< T > &vtx)
Definition: polygon.h:222
Coord2d Coord
Definition: commontypes.h:83
int size() const
Definition: polygon.h:43
void reverse()
Definition: polygon.h:641
bool operator==(const ODPolygon< T > &) const
Definition: polygon.h:157
virtual void erase()
const Geom::Point2D< T > & prevVertex(int idx) const
Definition: polygon.h:270
static int doSegmentsMeet(const Geom::Point2D< T > &p1, const Geom::Point2D< T > &p2, const Geom::Point2D< T > &q1, const Geom::Point2D< T > &q2, T eps)
Definition: polygon.h:445
static double sgnDistToLine(const Geom::Point2D< T > &point, const Geom::Point2D< T > &dirvec, const Geom::Point2D< T > &posvec)
Definition: polygon.h:535
T start
Definition: ranges.h:90
Interval< T > xrg_
Definition: polygon.h:151
ODPolygon()
Definition: polygon.h:28
Geom::Point2D< T > getUdf() const
Definition: polygon.h:72
const TypeSet< Geom::Point2D< T > > & data() const
Definition: polygon.h:73
ST sgnArea2() const
Definition: polygon.h:553
#define MAXDOUBLE
Definition: commondefs.h:103
Definition: commontypes.h:55
#define mClass(module)
Definition: commondefs.h:161
2D point or vector class.
Definition: commontypes.h:58
void set(const char *ky, const char *val)
double maxDistToBorderEstimate(double maxrelerr=0.001) const
Definition: polygon.h:718
T y_
Definition: geometry.h:81
void setEmpty()
Definition: polygon.h:45
void set(const ODPolygon< T2 > &)
Definition: polygon.h:165
static bool isOnHalfLine(const Geom::Point2D< T > &point, const Geom::Point2D< T > &dirvec, const Geom::Point2D< T > &endvec, T eps)
Definition: polygon.h:475
bool getYN(const char *, bool &) const

Generated at for the OpendTect seismic interpretation project. Copyright (C): dGB Beheer B. V. 2017