GLAMERDOC++
Gravitational Lensing Code Library
Loading...
Searching...
No Matches
concave_hull.h
1//
2// concave_hull.h
3// GLAMER
4//
5// Created by bmetcalf on 23/02/16.
6//
7//
8
9#ifndef concave_hull_h
10#define concave_hull_h
11
12#include <set>
13#include "point.h"
14#include "geometry.h"
15#include "image_processing.h"
16#include "simpleTreeVec.h"
17
18namespace Utilities{
19
20template<typename T,typename P>
21Point_2d subtract(T& p1,P& p2){
22 return Point_2d(p1[0] - p2[0], p1[1] - p2[1]);
23}
24template<typename P>
25double crossD(P &O,P &A,P &B){
26 return (A[0] - O[0]) * (B[1] - O[1]) - (A[1] - O[1]) * (B[0] - O[0]);
27}
28
29
31template <typename T>
32size_t RemoveIntersections(std::vector<T> &curve){
33
34 if(curve.size() <=3) return 0;
35
36 size_t N = curve.size(),count = 0;
37 T tmp;
38
39 curve.push_back(curve[0]);
40
41 for(size_t i=0;i<N-2;++i){
42 for(size_t j=i+2;j<N;++j){
43 if(Utilities::Geometry::intersect(curve[i].x,curve[i+1].x,curve[j].x,curve[j+1].x)){
44
45 size_t k=i+1,l=j;
46 while(k < l){
47 std::swap(curve[k] , curve[l]);
48 ++k;
49 --l;
50 }
51 ++count;
52 }
53 }
54 }
55
56 //assert(curve[0]==curve.back());
57 curve.pop_back();
58
59 return count;
60}
61
66std::vector<Point_2d> TighterHull(const std::vector<Point_2d> &v);
67
69std::vector<Point_2d> TightestHull(const std::vector<Point_2d> &v);
70
71//template <typename T>
72//std::vector<T> TightHull(const std::vector<T> &curve){
73//
74// if(curve.size() <=3) return curve;
75//
76// size_t N = curve.size(),count = 0;
77// T tmp;
78//
79// // find left most point
80// long init = 0;
81// double pmin = curve[0][0];
82// for(int i=1 ; i<N ; ++i){
83// if(curve[i][0] < pmin){
84// init = i;
85// pmin = curve[i][0];
86// }
87// }
88//
89// // orientation == 1 clockwise
90// Geometry::CYCLIC cyc(N);
91// int orientation = sign( (curve[cyc[init-1]] - curve[init])^(curve[cyc[init+1]] - curve[init]) );
92// if(orientation == 0){
93// orientation = sign( curve[cyc[init+1]][1] - curve[init][1]);
94// }
95//
96// orientation *= -1; // orientation == 1 is counter clockwise
97//
98// // make a copy where first one is the leftmost
99// std::vector<T> hull(N);
100// for(size_t i=0;i<N;++i){
101// hull[i] = curve[ cyc[ orientation * i + init] ];
102// }
103//
104// for(size_t i=0;i<N-2;++i){
105//
106// for(size_t j=i+2;j<N;++j){
107// if(Utilities::Geometry::intersect(hull[i].x,hull[ (i+1) % N ].x,hull[j].x,hull[ (j+1) % N ].x)){
108//
109//
110// long ii = cyc[i-1];
111// //if(i==0) ii = N-1;
112// //else ii = i-1;
113//
114// Point_2d x = hull[i] - hull[ii];
115// x.unitize();
116//
117// if(
118// //( x^(hull[ (j+1) % N ] - hull[i]) ) / (hull[ (j+1) % N ] - hull[i]).length()
119// atan2( x^(hull[ (j+1) % N ] - hull[i]) , x*(hull[ (j+1) % N ] - hull[i]) )
120// <
121// atan2( x^(hull[j] - hull[i]) , x*(hull[j] - hull[i]) )
122// //( x^(hull[j] - hull[i]) ) / (hull[j] - hull[i]).length()
123// ){
124//
125// // inner loop - remove all points between i and j+1
126//
127// int n = j - i;
128// int k = j+1;
129// while(k < N){
130// //std::swap(hull[k],hull[k-n]);
131// hull[k-n] = hull[k];
132// ++k;
133// }
134// N -= n;
135// }else{
136//
137// // outer loop - put them in reverse order
138// size_t k=i+1,l=j;
139// while(k < l){
140// std::swap(hull[k] , hull[l]);
141// ++k;
142// --l;
143// }
144// }
145// ++count;
146// }
147// }
148// }
149//
150// //assert(hull[0]==hull.back());
151// hull.resize(N);
152//
153// assert(N>2);
154// return hull;
155//}
156
159 const Point_2d &x2,
160 const Point_2d &x3,
162
164Point_2d RandomInConvexPoly(const std::vector<Point_2d> &pp,
166std::vector<Point_2d> RandomInConvexPoly(const std::vector<Point_2d> &pp,
167 int N,
169
171Point_2d RandomInPoly(std::vector<Point_2d> &pp,
173std::vector<Point_2d> RandomInPoly(std::vector<Point_2d> &pp,
174 int N,
176
178Point_2d RandomNearPoly(std::vector<Point_2d> &pp
179 ,double R
181std::vector<Point_2d> RandomNearPoly(std::vector<Point_2d> &pp
182 ,int N
183 ,double R
185
186
187
200template <typename P>
201void find_boundaries(std::vector<bool> &bitmap // = true inside
202 ,long nx // number of pixels in x direction
203 ,std::vector<std::vector<P> > &points
204 ,std::vector<bool> &hits_edge
205 ,bool add_to_vector=false
206 ,bool outer_only=false
207 ){
208
209 size_t n = bitmap.size();
210 long ny = n/nx;
211
212 if(n != nx*ny){
213 std::cerr << "Wrong sizes in Utilities::find_boundaries." << std::endl;
214 throw std::invalid_argument("invalid size");
215 }
216
217 std::vector<bool> not_used(n,true);
218
219 // pad edge of field with bitmap=false
220 for(size_t i=0 ; i<nx ; ++i) bitmap[i]=false;
221 size_t j = nx*(ny-1);
222 for(size_t i=0 ; i<nx ; ++i) bitmap[i + j]=false;
223 for(size_t i=0 ; i<ny ; ++i) bitmap[i*nx]=false;
224 j = nx-1;
225 for(size_t i=0 ; i<ny ; ++i) bitmap[j + i*nx]=false;
226
227 std::list<std::list<Point_2d>> contours;
228
229 if(!add_to_vector){
230 hits_edge.resize(0);
231 }
232
233 bool done = false;
234 long kfirst_in_bound = -1;
235 while(!done){
236 // find first cell in edge
237 size_t k=0;
238 int type;
239 for( k = kfirst_in_bound + 1 ; k < n - nx ; ++k){
240 if(k % nx != nx-1){ // one less cells than points
241 type = 0;
242 if(bitmap[k] ) type +=1;
243 if(bitmap[k+1]) type += 10;
244 if(bitmap[k + nx]) type += 100;
245 if(bitmap[k + nx + 1]) type += 1000;
246
247 if(type > 0
248 && type != 1111
249 && not_used[k]
250 ) break;
251 }
252 }
253
254 kfirst_in_bound = k;
255
256 if(k == n-nx){
257 done=true;
258 }else{ // found an edge
259
260 contours.resize(contours.size() + 1);
261 std::list<Point_2d> &contour = contours.back();
262 hits_edge.push_back(false);
263
264
265 int type;
266 int face_in=0;
267 size_t n_edge = 0;
268
269 // follow edge until we return to the first point
270 while(k != kfirst_in_bound || n_edge==0){
271
272 if(n_edge >= n){ // infinite loop, output debugging data
273 std::cerr << "Too many points in Utilities::find_boundaries()." << std::endl;
274 std::cerr << "kfirst_in_bound " << kfirst_in_bound << std::endl;
275 std::cerr << " contour is output to boundary_error_file.csv and bitmap_error_file.csv" << std::endl;
276 {
277 std::ofstream file("bitmap_error_file.csv");
278 file << "in,x,y" << std::endl;
279 for(size_t i=0 ; i<n ; ++i){
280 file << bitmap[i] << "," << i%nx << "," << i/nx << std::endl;
281 }
282 }
283
284 {
285 std::ofstream file("boundary_error_file.csv");
286 file << "contour,x,y" << std::endl;
287 int i = 0;
288 for(auto &v : contours){
289 for(Point_2d &p : v){
290 file << i << "," << p[0] << "," << p[1] << std::endl;
291 }
292 ++i;
293 }
294 }
295 throw std::runtime_error("caught in loop.");
296 }
297
298 if(k%nx == 0 || k%nx == nx-2) hits_edge.back() = true;
299 if(k/nx == 0 || k/nx == ny-2) hits_edge.back() = true;
300
301 not_used[k] = false;
302
303 ++n_edge;
304 type = 0;
305 // find type of cell
306 if(bitmap[k]) type +=1;
307 if(bitmap[k+1]) type += 10;
308 if(bitmap[k + nx]) type += 100;
309 if(bitmap[k + nx + 1]) type += 1000;
310
311 if(type == 0 || type == 1111){ // all in or all out
312 throw std::runtime_error("off edge!!");
313 }else if(type == 1 || type == 1110){ // lower left only
314
315 if(face_in==0){
316 contour.push_back( Point_2d( k%nx + 0.5
317 , k/nx ) );
318 //contour.push_back( (i_points[k] + i_points[k+1]) / 2 );
319 face_in=1;
320 k -= nx;
321 }else{
322 contour.push_back( Point_2d( k%nx
323 , k/nx + 0.5 ) );
324 //contour.push_back( (i_points[k] + i_points[k+nx]) / 2 );
325 face_in=2;
326 k -= 1;
327 }
328
329 }else if(type == 10 || type == 1101){ // lower right only
330
331 if(face_in==2){
332 contour.push_back( Point_2d( k%nx + 0.5
333 , k/nx ) );
334 //contour.push_back( (i_points[k] + i_points[k+1]) / 2 );
335 face_in=1;
336 k -= nx;
337 }else{
338 contour.push_back( Point_2d( k%nx + 1
339 , k/nx + 0.5) );
340 //contour.push_back( (i_points[k+nx+1] + i_points[k+1]) / 2 );
341 face_in=0;
342 k += 1;
343 }
344
345 }else if(type == 100 || type == 1011){ // upper left only
346
347 if(face_in==0){
348 contour.push_back( Point_2d( k%nx + 0.5
349 , k/nx + 1 ) );
350 //contour.push_back( (i_points[k+nx] + i_points[k+nx+1]) / 2 );
351 face_in=3;
352 k += nx;
353 }else{
354 contour.push_back( Point_2d( k%nx
355 , k/nx + 0.5 ) );
356 //contour.push_back( (i_points[k] + i_points[k+nx]) / 2 );
357 face_in=2;
358 k -= 1;
359 }
360
361 }else if(type == 1000 || type == 111){ // upper right only
362
363 if(face_in==1){
364 contour.push_back( Point_2d( k%nx + 1
365 , k/nx + 0.5 ) );
366 //contour.push_back( (i_points[k+1] + i_points[k+nx+1]) / 2 );
367 face_in=0;
368 k += 1;
369 }else{
370 contour.push_back( Point_2d( k%nx + 0.5
371 , k/nx + 1 ) );
372 //contour.push_back( (i_points[k+nx] + i_points[k+nx+1]) / 2 );
373 face_in=3;
374 k += nx;
375 }
376
377 }else if(type == 11 || type == 1100){ // lower two
378
379 if(face_in==0){
380 contour.push_back( Point_2d( k%nx + 1
381 , k/nx + 0.5 ) );
382 //contour.push_back( (i_points[k+1] + i_points[k+nx+1]) / 2 );
383 k += 1;
384 }else{
385 contour.push_back( Point_2d( k%nx
386 , k/nx + 0.5 ) );
387 //contour.push_back( (i_points[k] + i_points[k+nx]) / 2 );
388 face_in = 2;
389 k -= 1;
390 }
391
392 }else if(type == 1010 || type == 101){ // right two
393
394 if(face_in==1){
395 contour.push_back( Point_2d( k%nx + 0.5
396 , k/nx ) );
397 //contour.push_back( (i_points[k] + i_points[k+1]) / 2 );
398 k -= nx;
399 }else{
400 contour.push_back( Point_2d( k%nx + 0.5
401 , k/nx + 1 ) );
402 //contour.push_back( (i_points[k+nx] + i_points[k+nx+1]) / 2 );
403 face_in = 3;
404 k += nx;
405 }
406
407 }else if(type == 1001){ // lower left upper right
408
409 if(face_in==0){
410 contour.push_back( Point_2d( k%nx + 0.5
411 , k/nx + 1 ) );
412 //contour.push_back( (i_points[k+nx] + i_points[k+nx+1]) / 2 );
413 face_in=3;
414 k += nx;
415 }else if(face_in==1){
416 contour.push_back( Point_2d( k%nx
417 , k/nx + 0.5 ) );
418 //contour.push_back( (i_points[k] + i_points[k+nx]) / 2 );
419 face_in=2;
420 k -= 1;
421 }else if(face_in==2){
422 contour.push_back( Point_2d( k%nx + 0.5
423 , k/nx ) );
424 //contour.push_back( (i_points[k] + i_points[k+1]) / 2 );
425 face_in=1;
426 k -= nx;
427 }else{
428 contour.push_back( Point_2d( k%nx + 1
429 , k/nx + 0.5 ) );
430 //contour.push_back( (i_points[k+nx + 1] + i_points[k+1]) / 2 );
431 face_in=0;
432 k += 1;
433 }
434
435 }else if(type == 110){ // upper left lower right
436
437 if(face_in==0){
438 contour.push_back( Point_2d( k%nx + 0.5
439 , k/nx ) );
440 //contour.push_back( (i_points[k] + i_points[k+1]) / 2 );
441 face_in=1;
442 k -= nx;
443 }else if(face_in==1){
444 contour.push_back( Point_2d( k%nx + 1
445 , k/nx + 0.5 ) );
446 //contour.push_back( (i_points[k+1] + i_points[k+nx+1]) / 2 );
447 face_in=0;
448 k += 1;
449 }else if(face_in==2){
450 contour.push_back( Point_2d( k%nx + 0.5
451 , k/nx + 1 ) );
452 //contour.push_back( (i_points[k + nx] + i_points[k+nx+1]) / 2 );
453 face_in=3;
454 k += nx;
455 }else{
456 contour.push_back( Point_2d( k%nx
457 , k/nx + 0.5 ) );
458 //contour.push_back( (i_points[k] + i_points[k+nx]) / 2 );
459 face_in=2;
460 k -= 1;
461 }
462 }
463 }
464
465 // special case of the diamand with a hole
466 //if(n_edge == 12 && bitmap[k + nx + 1] ){
467 // n_edge=0;
468 // face_in = 2;
469 //}
470
471 }
472 if(outer_only) break;
473 }
474
475
476 long offset = 0;
477 if(!add_to_vector){
478 points.resize(contours.size());
479 }else{
480 offset = points.size();
481 points.resize(points.size() + contours.size());
482 }
483
484 // copy lists of points into vectors
485 int i=0;
486 for(auto &c: contours){
487 points[offset+i].resize(c.size());
488 size_t j=0;
489 for(auto &p: c){
490 points[offset+i][j] = p;
491 ++j;
492 }
493 ++i;
494 }
495}
496
498void find_islands(std::vector<bool> &bitmap // = true inside
499 ,long nx // number of pixels in x direction
500 ,std::vector<std::vector<long> > &indexes
501 ,std::vector<bool> &hits_edge
502 ,bool add_to_vector=false
503 );
504
506double interior_mass(const std::vector<Point_2d> &alpha
507 ,const std::vector<Point_2d> &x);
508
510double interior_mass(const std::vector<RAY> &rays);
511
513template<typename T>
514std::vector<T> convex_hull(const std::vector<T> &PP)
515{
516
517 if(PP.size() <= 3){
518 return PP;
519 }
520
521 std::vector<T> P=PP;
522
523 size_t n = P.size();
524 size_t k = 0;
525 std::vector<T> hull(2*n);
526
527 // Sort points lexicographically
528 std::sort(P.begin(), P.end(),
529 [](T p1,T p2){
530 if(p1[0]==p2[0]) return p1[1] < p2[1];
531 return p1[0] < p2[0];});
532
533
534 // Build lower hull
535 for (size_t i = 0; i < n; i++) {
536 while (k >= 2 && crossD(hull[k-2], hull[k-1], P[i]) <= 0){
537 k--;
538 }
539 hull[k++] = P[i];
540 }
541
542 // Build upper hull
543 for (long i = n-2, t = k+1; i >= 0; i--) {
544 while (k >= t && crossD(hull[k-2], hull[k-1], P[i]) <= 0){
545 k--;
546 assert(k > 1);
547 }
548 hull[k++] = P[i];
549 }
550
551
552 hull.resize(k);
553 hull.pop_back();
554
555 return hull;
556}
557
560template<typename T>
561void convex_hull(const std::vector<T> &P,std::vector<size_t> &hull)
562{
563
564 size_t n = P.size();
565
566 if(n <= 3){
567 hull.resize(n);
568 size_t i = 0;
569 for(size_t &d : hull) d = i++;
570 return;
571 }
572
573 //std::vector<T> hull(n + 1);
574 hull.resize(n + 1);
575 size_t k = 0;
576
577 // Sort points lexicographically
578 std::vector<size_t> sort_index(P.size());
579 {
580 int i=0;
581 for(size_t &a : sort_index) a = i++;
582 }
583 std::sort(sort_index.begin(), sort_index.end(),
584 [&P](size_t i1,size_t i2){
585 if(P[i1][0]==P[i2][0]) return P[i1][1] < P[i2][1];
586 return P[i1][0] < P[i2][0];});
587
588
589 // Build lower hull
590 for (size_t i = 0; i < n; i++) {
591 while (k >= 2 && crossD(P[hull[k-2]], P[hull[k-1]], P[sort_index[i]]) <= 0){
592 k--;
593 }
594 hull[k++] = sort_index[i];
595 }
596
597 // Build upper hull
598 for (long i = n-2, t = k+1; i >= 0; i--) {
599 while (k >= t && crossD(P[hull[k-2]], P[hull[k-1]],P[sort_index[i]]) <= 0){
600 k--;
601 assert(k > 1);
602 }
603 hull[k++] = sort_index[i];
604 }
605
606 hull.resize(k);
607 hull.pop_back();
608
609 return;
610}
611
612
613struct Edge{
614 Edge(size_t i,double l):length(l),index(i){};
615 double length = 0;
616 size_t index = 0;
617};
633template<typename T>
634void concave(std::vector<T> &init_points
635 ,std::vector<T> &hull_out,double scale)
636{
637
638 //typedef typename InputIt::value_type point;
639
640 bool TEST = false;
641
642 // find the convex hull
643 std::vector<T> hull = convex_hull(init_points);
644
645 if(init_points.size() == hull.size()) return;
646
647 std::list<Edge> edges;
648 std::list<T> leftovers;
649 hull.push_back(hull[0]);
650
651 double tmp;
652
653 // find pairs of hull points that are further appart than scale
654 for(int i=0;i<hull.size()-1;++i){
655 tmp = (subtract(hull[i],hull[i+1])).length();
656 if(tmp > scale) edges.emplace_back(i,tmp);// .push_back(std::pair<size_t,double>(i,tmp));
657 }
658
659 if(edges.size() == 0) return;
660
661 if(TEST){
662 PosType cent[] ={0.5,0.5};
663 PixelMap<float> map(cent,256, 1.0/256);
664
665 map.drawgrid(10,0.5);
666
667 map.drawPoints(init_points,0.01,1.0);
668 map.drawCurve(hull,2);
669
670 map.printFITS("!test_concave.fits");
671 }
672
673 // sort edges by length
674 edges.sort([](const Edge &p1,const Edge &p2){return p1.length > p2.length;});
675 assert(edges.front().length >= edges.back().length);
676
677
678 { // make a list of points that are not already in the convex hull
679
680 hull.pop_back();
681 std::vector<size_t> index(hull.size());
682 size_t i = 0;
683 for(size_t &ind: index) ind = i++;
684 std::sort(index.begin(),index.end(),
685 [&hull](size_t p1,size_t p2){
686 if(hull[p1][0] == hull[p2][0]) return hull[p1][1] < hull[p2][1];
687 return hull[p1][0] < hull[p2][0];});
688
689 size_t j = 0;
690
691 for(auto pit = init_points.begin(); pit != init_points.end() ; ++pit){
692
693 if((hull[index[j]][0] == (*pit)[0])*(hull[index[j]][1] == (*pit)[1])){
694 ++j;
695 }else{
696 leftovers.push_back(*pit);
697 }
698
699 }
700 assert(hull.size() + leftovers.size() == init_points.size());
701 hull.push_back(hull[0]);
702 }
703
704 typename std::list<T>::iterator p,nextpoint;
705 //auto p = leftovers.begin();
706
707 double minarea,area,co1;//,co2;
708 size_t i;
709 Point_2d vo,v1,v2;
710
711 //int count = 0;
712 while(edges.front().length > scale ){
713
714 if(leftovers.size() == 0) break;
715
716 // find the point which if added to this edge would change the area least
717 minarea = HUGE_VAL;
718 i = edges.front().index;
719
720 for(p = leftovers.begin() ; p != leftovers.end() ; ++p){
721
722 v1 = subtract(*p,hull[i]);
723
724 if( edges.front().length > v1.length()){
725
726 vo = subtract(hull[i+1], hull[i]);
727 //v2 = subtract(*p,hull[i+1]);
728 area = vo^v1;
729 co1 = v1*vo;
730 //co2 = v2*vo;
731
732 if( co1 > 0 && (area > 0)*(area < minarea) ){
733 // if(co1 > 0 && area > 0 && index_length.front().second > v1.length()){
734 minarea = area;
735 nextpoint = p;
736 }
737 }
738 }
739
740 if(minarea == HUGE_VAL){
741 // if there is no acceptable point for this edge continue with the second longest edge
742 edges.pop_front();
743 continue;
744 }
745
746 // insert new point into hull
747 T tmp = *nextpoint;
748 leftovers.erase(nextpoint);
749 hull.insert(hull.begin() + i + 1,tmp);
750
751 // update index_length list
752 Edge new1 = edges.front();
753 edges.pop_front();
754 new1.length = (subtract(hull[i],hull[i+1])).length();
755 Edge new2(i+1,(subtract(hull[i+1],hull[i+2])).length());
756
757 for(auto &p : edges) if(p.index > i) ++(p.index);
758
759 auto p = edges.begin();
760 if(new1.length > scale){
761 for(p = edges.begin() ; p != edges.end() ; ++p){
762 if((*p).length < new1.length){
763 edges.insert(p,new1);
764 break;
765 }
766 }
767 if(p==edges.end()) edges.push_back(new1);
768 }
769 if(new2.length > scale){
770 for(p = edges.begin(); p != edges.end() ; ++p){
771 if((*p).length < new2.length){
772 edges.insert(p,new2);
773 break;
774 }
775 }
776 if(p==edges.end()) edges.push_back(new2);
777 }
778
779
780 if(TEST){
781 PosType cent[] ={0.5,0.5};
782 PixelMap<float> map(cent,256, 1.0/256);
783
784 map.drawgrid(10,0.5);
785
786 map.drawPoints(init_points,0.03,1.0);
787 map.drawCurve(hull,2);
788
789 map.printFITS("!test_concave.fits");
790 }
791 }
792
793 hull.pop_back();
794
795 //Utilities::RemoveIntersections(hull);
796
797 std::swap(hull,hull_out);
798
799 return;
800}
801
802template<typename T>
803std::vector<T> concave2(std::vector<T> &init_points,double scale)
804{
805
806 //typedef typename InputIt::value_type point;
807
808 bool TEST = false;
809
810 // find the convex hull
811 std::vector<T> hull = convex_hull(init_points);
812
813 if(init_points.size() == hull.size()) return hull;
814
815 std::list<Edge> edges;
816 std::list<T> leftovers;
817 hull.push_back(hull[0]);
818
819 double tmp;
820
821 // find pairs of hull points that are further appart than scale
822 for(int i=0;i<hull.size()-1;++i){
823 tmp = (subtract(hull[i],hull[i+1])).length();
824 if(tmp > scale) edges.emplace_back(i,tmp);// .push_back(std::pair<size_t,double>(i,tmp));
825 }
826
827 if(edges.size() == 0) return hull;
828
829 if(TEST){
830 PosType cent[] ={0.5,0.5};
831 PixelMap<float> map(cent,256, 1.0/256);
832
833 map.drawgrid(10,0.5);
834
835 map.drawPoints(init_points,0.01,1.0);
836 map.drawCurve(hull,2);
837
838 map.printFITS("!test_concave.fits");
839 }
840
841 // sort edges by length
842 edges.sort([](const Edge &p1,const Edge &p2){return p1.length > p2.length;});
843 assert(edges.front().length >= edges.back().length);
844
845
846 { // make a list of points that are not already in the convex hull
847
848 hull.pop_back();
849 std::vector<size_t> index(hull.size());
850 size_t i = 0;
851 for(size_t &ind: index) ind = i++;
852 std::sort(index.begin(),index.end(),
853 [&hull](size_t p1,size_t p2){
854 if(hull[p1][0] == hull[p2][0]) return hull[p1][1] < hull[p2][1];
855 return hull[p1][0] < hull[p2][0];});
856
857 size_t j = 0;
858
859 for(auto pit = init_points.begin(); pit != init_points.end() ; ++pit){
860
861 if((hull[index[j]][0] == (*pit)[0])*(hull[index[j]][1] == (*pit)[1])){
862 ++j;
863 }else{
864 leftovers.push_back(*pit);
865 }
866
867 }
868 assert(hull.size() + leftovers.size() == init_points.size());
869 hull.push_back(hull[0]);
870 }
871
872 typename std::list<T>::iterator p,nextpoint;
873 //auto p = leftovers.begin();
874
875 double minarea,area,co1;
876 size_t i;
877 Point_2d vo,v1,v2;
878
879 while(edges.front().length > scale ){
880
881 if(leftovers.size() == 0) break;
882
883 // find the point which if added to this edge would change the area least
884 minarea = HUGE_VAL;
885 i = edges.front().index;
886
887 for(p = leftovers.begin() ; p != leftovers.end() ; ++p){
888
889 v1 = subtract(*p,hull[i]);
890
891 if( edges.front().length > v1.length()){
892
893 vo = subtract(hull[i+1], hull[i]);
894 //v2 = subtract(*p,hull[i+1]);
895 area = vo^v1;
896 co1 = v1*vo;
897 //co2 = v2*vo;
898
899 if( co1 > 0 && (area > 0)*(area < minarea) ){
900 // if(co1 > 0 && area > 0 && index_length.front().second > v1.length()){
901 minarea = area;
902 nextpoint = p;
903 }
904 }
905 }
906
907 if(minarea == HUGE_VAL){
908 // if there is no acceptable point for this edge continue with the second longest edge
909 edges.pop_front();
910 continue;
911 }
912
913 // insert new point into hull
914 T tmp = *nextpoint;
915 leftovers.erase(nextpoint);
916 hull.insert(hull.begin() + i + 1,tmp);
917
918 // update index_length list
919 Edge new1 = edges.front();
920 edges.pop_front();
921 new1.length = (subtract(hull[i],hull[i+1])).length();
922 Edge new2(i+1,(subtract(hull[i+1],hull[i+2])).length());
923
924 for(auto &p : edges) if(p.index > i) ++(p.index);
925
926 auto p = edges.begin();
927 if(new1.length > scale){
928 for(p = edges.begin() ; p != edges.end() ; ++p){
929 if((*p).length < new1.length){
930 edges.insert(p,new1);
931 break;
932 }
933 }
934 if(p==edges.end()) edges.push_back(new1);
935 }
936 if(new2.length > scale){
937 for(p = edges.begin(); p != edges.end() ; ++p){
938 if((*p).length < new2.length){
939 edges.insert(p,new2);
940 break;
941 }
942 }
943 if(p==edges.end()) edges.push_back(new2);
944 }
945
946
947 if(TEST){
948 PosType cent[] ={0.5,0.5};
949 PixelMap<float> map(cent,256, 1.0/256);
950
951 map.drawgrid(10,0.5);
952
953 map.drawPoints(init_points,0.03,1.0);
954 map.drawCurve(hull,2);
955
956 map.printFITS("!test_concave.fits");
957 }
958 }
959
960 hull.pop_back();
961
962 //Utilities::RemoveIntersections(hull);
963
964 return hull;
965}
966
967// shortest distance between P and the segment (S1,S2)
968template <typename Ptype>
969double distance_to_segment(const Ptype &P
970 ,const Ptype &S1
971 ,const Ptype &S2
972 ){
973
974 Ptype D = S2-S1;
975 double s = (P-S1)*D / D.length_sqr();
976 if(s<=0){
977 return (P-S1).length();
978 }else if(s>=1){
979 return (P-S2).length();
980 }else{
981 return (S1 + D*s - P).length();
982 }
983}
984template <typename Ptype>
985double distance_to_segment(const Ptype &P
986 ,const Ptype &S1
987 ,const Ptype &S2
988 ,Ptype &closest_point
989 ){
990
991 Ptype D = S2-S1;
992 double s = (P-S1)*D / D.length_sqr();
993 if(s<=0){
994 closest_point = S1;
995 return (P-S1).length();
996 }else if(s>=1){
997 closest_point = S2;
998 return (P-S2).length();
999 }else{
1000 closest_point = S1 + D*s;
1001 return (S1 + D*s - P).length();
1002 }
1003}
1004
1005template <typename Ptype>
1006bool segments_cross(const Ptype &a1,const Ptype &a2
1007 ,const Ptype &b1,const Ptype &b2){
1008 Ptype db= b2 - b1;
1009 Ptype da= a2 - a1;
1010 Ptype d1= b1 - a1;
1011
1012 double tmp = (db^da);
1013 if(tmp==0) return false; // parallel case
1014
1015 double B = (da^d1) / tmp;
1016 if( (B>1) || (B<0)) return false;
1017 B = (db^d1) / tmp;
1018 if( (B>1) || (B<0)) return false;
1019 return true;
1020}
1021
1022template <typename Ptype>
1023bool inCurve(const Ptype &x,const std::vector<Ptype> &H){
1024
1025 size_t n = H.size();
1026 if(n <=2) return false;
1027 long w=0;
1028 Ptype dH,dD;
1029 double B,A;
1030 for(size_t i=0 ; i<n-1 ; ++i){
1031 dH = H[i+1]-H[i];
1032 if(dH[1] == 0){ // // horizontal segment
1033 if(x[1] == H[i][1]){
1034 B = (x[0]-H[i][0])/dH[0];
1035 if( B>=0 && B<=1 ) return true; // point on boundary
1036 }
1037 }else{
1038 dD = x-H[i];
1039 A = dD[1]/dH[1];
1040 if( A > 1 || A <= 0) continue;
1041 B = (dH^dD)/dH[1];
1042 if(B==0){ // on the boundary
1043 return true; // boundaries are always in
1044 }else if(B>0){
1045 if(dH[1] > 0) ++w;
1046 else --w;
1047 }
1048 }
1049 }
1050
1051 return w;
1052}
1053
1054template <typename Ptype>
1055bool inhull(PosType x[],const std::vector<Ptype> &H){
1056
1057 size_t n = H.size();
1058 if(n <=2) return false;
1059 long w=0;
1060 Ptype dH,dD;
1061 double B,A;
1062 for(size_t i=0 ; i<n-1 ; ++i){
1063 dH = H[i+1]-H[i];
1064 if(dH[1] == 0){ // // horizontal segment
1065 if(x[1] == H[i][1]){
1066 B = (x[0]-H[i][0])/dH[0];
1067 if( B>=0 && B<=1 ) return true; // point on boundary
1068 }
1069 }else{
1070 dD[0] = x[0]-H[i][0];
1071 dD[1] = x[1]-H[i][1];
1072 A = dD[1]/dH[1];
1073 if( A > 1 || A <= 0) continue;
1074 B = (dH^dD)/dH[1];
1075 if(B==0){ // on the boundary
1076 return true; // boundaries are always in
1077 }else if(B>0){
1078 if(dH[1] > 0) ++w;
1079 else --w;
1080 }
1081 }
1082 }
1083
1084 return abs(w);
1085}
1086
1087template <>
1088inline bool inhull<Point *>(PosType x[],const std::vector<Point *> &H){
1089
1090 size_t n = H.size();
1091 if(n <=2) return false;
1092 long w=0;
1093 Point_2d dH,dD;
1094 double B,A;
1095 for(size_t i=0 ; i<n-1 ; ++i){
1096 dH = *H[i+1]-*H[i];
1097 if(dH[1] == 0){ // // horizontal segment
1098 if(x[1] == H[i]->x[1]){
1099 B = (x[0]-H[i]->x[0])/dH[0];
1100 if( B>=0 && B<=1 ) return true; // point on boundary
1101 }
1102 }else{
1103 dD[0] = x[0]-H[i]->x[0];
1104 dD[1] = x[1]-H[i]->x[1];
1105 A = dD[1]/dH[1];
1106 if( A > 1 || A <= 0) continue;
1107 B = (dH^dD)/dH[1];
1108 if(B==0){ // on the boundary
1109 return true; // boundaries are always in
1110 }else if(B>0){
1111 if(dH[1] > 0) ++w;
1112 else --w;
1113 }
1114 }
1115 }
1116
1117 return w;
1118}
1119
1121template <>
1122inline bool inhull<RAY>(PosType x[],const std::vector<RAY> &H){
1123
1124 size_t n = H.size();
1125 if(n <=2) return false;
1126 long w=0;
1127 Point_2d dH,dD;
1128 double B,A;
1129 for(size_t i=0 ; i<n-1 ; ++i){
1130 dH = H[i+1].x-H[i].x;
1131 if(dH[1] == 0){ // // horizontal segment
1132 if(x[1] == H[i].x[1]){
1133 B = (x[0]-H[i].x[0])/dH[0];
1134 if( B>=0 && B<=1 ) return true; // point on boundary
1135 }
1136 }else{
1137 dD[0] = x[0]-H[i].x[0];
1138 dD[1] = x[1]-H[i].x[1];
1139 A = dD[1]/dH[1];
1140 if( A > 1 || A <= 0) continue;
1141 B = (dH^dD)/dH[1];
1142 if(B==0){ // on the boundary
1143 return true; // boundaries are always in
1144 }else if(B>0){
1145 if(dH[1] > 0) ++w;
1146 else --w;
1147 }
1148 }
1149 }
1150
1151 return w;
1152}
1153
1154template <>
1155inline bool inhull<PosType *>(PosType x[],const std::vector<PosType *> &H){
1156
1157 size_t n = H.size();
1158 if(n <=2) return false;
1159 long w=0;
1160 Point_2d dH,dD;
1161 double B,A;
1162 for(size_t i=0 ; i<n-1 ; ++i){
1163 dH[0] = H[i+1][0]-H[i][0];
1164 dH[1] = H[i+1][1]-H[i][1];
1165 if(dH[1] == 0){ // // horizontal segment
1166 if(x[1] == H[i][1]){
1167 B = (x[0]-H[i][0])/dH[0];
1168 if( B>=0 && B<=1 ) return true; // point on boundary
1169 }
1170 }else{
1171 dD[0] = x[0]-H[i][0];
1172 dD[1] = x[1]-H[i][1];
1173 A = dD[1]/dH[1];
1174 if( A > 1 || A <= 0) continue;
1175 B = (dH^dD)/dH[1];
1176 if(B==0){ // on the boundary
1177 return true; // boundaries are always in
1178 }else if(B>0){
1179 if(dH[1] > 0) ++w;
1180 else --w;
1181 }
1182 }
1183 }
1184
1185 return w;
1186}
1187
1188
1189/*** \brief Calculate the k nearest neighbors concave hull.
1190
1191 This algorithem is guarenteed to find a curve that serounds an island of points, but not all islands unless check==true.
1192
1193 If it at first fails with the k input, k will increase. The final k relaces the input k.
1194
1195 check determines whether a final check is done to determine whether all the raminaing points are inside the hull. Otherwise it is possible to get multiple disconnected clusters and the hull will surround only one.
1196 */
1197
1198template <typename Ptype>
1199std::vector<Ptype> concaveK(std::vector<Ptype> &points,int &k,bool check=true)
1200{
1201 //std::cout << "finding hull .... ";
1202 if(points.size() <= 3){
1203 return points;
1204 }
1205
1206 if(k < 3) k =3;
1207
1208 size_t npoints = points.size();
1209
1210 // {
1211 // tree.pop(7);
1212 // RandomNumbers_NR ran(123);
1213 // std::vector<double> radii;
1214 // std::vector<size_t> neighbors;
1215 // Point_2d point;
1216 // for(int i = 0 ; i<100; ++i){
1217 // point[0] = (1-2*ran());
1218 // point[1] = (1-2*ran());
1219 // tree.NearestNeighbors(point.x,k,radii,neighbors);
1220 // }
1221 // for(auto p : points){
1222 // tree.NearestNeighbors(p.x,k,radii,neighbors);
1223 // }
1224 // }
1225 std::vector<Ptype> hull;
1226
1227 double xmin = points[0][0];
1228 size_t first_point_index = 0;
1229 for(size_t i=0 ; i<npoints ; ++i){
1230 if(points[i][0] < xmin){
1231 xmin = points[i][0];
1232 first_point_index = i;
1233 }
1234 }
1235
1236 Ptype firstpoint = points[first_point_index];
1237
1238 std::vector<size_t> remaining_index;
1239 bool segmented = true;
1240 while(segmented){
1241 bool found=false;
1242 while(!found){ // if hull leaves points out repeat with larger k
1243 hull.resize(0);
1244 TreeSimpleVec<Ptype> tree(points.data(),npoints,2);
1245
1246 if(k>=points.size()){
1247 hull = convex_hull(points);
1248 return hull;
1249 }
1250
1251 hull.push_back(firstpoint);
1252 // point is not popper frum the free so that it can be found at the end
1253
1254 std::vector<double> radii;
1255 std::vector<size_t> neighbors;
1256 Ptype hull_end = hull.back();
1257
1258 Ptype v1;
1259 Ptype last_point = Ptype(hull[0][0],hull[0][1]-1);
1260 Ptype v2;
1261
1262 size_t new_index;
1263 double theta_max=0;
1264 Ptype new_point;
1265 std::vector<double> thetas;
1266 std::vector<int> sorted_index(k);
1267
1268 while((hull[0] != hull.back() && found) || hull.size()==1 ){
1269
1270 tree.NearestNeighbors(hull_end.x,k,radii,neighbors);
1271
1272 long Nneighbors = neighbors.size(); // incase there are not k left
1273 thetas.resize(Nneighbors);
1274 sorted_index.resize(Nneighbors);
1275
1276 v1 = hull_end - last_point;
1277 theta_max = 0;
1278 for(int i=0; i<Nneighbors ; ++i){
1279 v2 = points[neighbors[i]] - hull_end;
1280 double cross = v1^v2,dot = (v1*v2);
1281 if(cross == 0 && dot <= 0) thetas[i] = -PI; // prevents backtracking at beginning
1282 else thetas[i] = atan2( cross , dot );
1283 sorted_index[i] = i;
1284 }
1285
1286 std::sort(sorted_index.begin(),sorted_index.end()
1287 ,[&thetas](int i,int j){return thetas[i] > thetas[j];} );
1288
1289 int trial=0;
1290 bool intersect = true;
1291 while(intersect && trial < Nneighbors){
1292
1293 new_index = neighbors[ sorted_index[trial] ];
1294 new_point = points[ new_index ];
1295
1296 if(hull.size() <= 3) intersect = false;
1297
1298 // check that new edge doesn't cross earlier edge
1299 for(long i = hull.size() - 2 ; i > 1 ; --i){
1300 intersect = segments_cross(hull[i],hull[i-1]
1301 ,hull.back(),new_point);
1302
1303 if(intersect){
1304 break;
1305 }
1306 }
1307
1308 if(new_index == first_point_index && !intersect){
1309 // check that neighbors are inside hull that would be closed
1310 // this is to prevent pre-mature closing of the loop
1311 hull.push_back(new_point);
1312 for(size_t i : neighbors){
1313 if(i != new_index && !inCurve(points[i],hull)){
1314 intersect = true;
1315 break;
1316 }
1317 }
1318 hull.pop_back();
1319 }
1320
1321 ++trial;
1322 }
1323
1324 if(intersect){
1325 // std::cout << "Intersection ..." << k << std::endl;
1326 //
1327 // std::ofstream logfile("testpoint.csv");
1328 // for(auto &p : points){
1329 // logfile << p[0] <<","<< p[1] << std::endl;
1330 // }
1331 // logfile.close();
1332 //
1333 // logfile.open("testhull.csv");
1334 // for(auto &p : hull){
1335 // logfile << p[0] <<","<< p[1] << std::endl;
1336 // }
1337 // logfile << new_point[0] <<","<< new_point[1] << std::endl;
1338 // logfile.close();
1339
1340 k *= 2;
1341 found = false;
1342 }else{
1343 hull.push_back(new_point);
1344 last_point = hull_end;
1345 hull_end = hull.back();
1346 //tree.print();
1347 tree.pop(new_index);
1348 //tree.print();
1349 found = true;
1350
1351 // {
1352 // Ptype center;
1353 // PixelMap map(center.x, 512, 3. / 512.);
1354 //
1355 // map.drawCurve(hull,1);
1356 // map.drawPoints(points,0,2);
1357 // map.printFITS("!concavek_test"+ std::to_string(f) +".fits");
1358 // std::cout << "Test plot : concavek_test" << f++ << ".fits" << std::endl;
1359 // }
1360 }
1361 }
1362 remaining_index = tree.get_index();
1363 }
1364 // test if all remaining points are in the hull
1365
1366
1367 segmented = false;
1368 if(check){
1369 for(auto i : remaining_index){
1370 if(!inCurve(points[i],hull)){
1371 segmented = true;
1372 k *= 2;
1373 // std::cout << "point outside ... ";
1374 // std::ofstream logfile("testpoint.csv");
1375 // for(auto &p : points){
1376 // logfile << p[0] <<","<< p[1] << std::endl;
1377 // }
1378 // logfile.close();
1379 //
1380 // logfile.open("testhull.csv");
1381 // for(auto &p : hull){
1382 // logfile << p[0] <<","<< p[1] << std::endl;
1383 // }
1384 // logfile.close();
1385 //
1386
1387 break;
1388 }
1389 }
1390 }
1391 }
1392
1393 //std::cout << "found hull" << std::endl;
1394 //hull.pop_back();
1395
1396 return hull;
1397}
1398
1399
1400template <typename Ptype>
1401void testconcaveK(){
1402 std::vector<Ptype> points(200);
1403 RandomNumbers_NR ran(2312);
1404
1405 for(Ptype &p : points){
1406 p[0] = (1-ran());
1407 p[1] = (1-2*ran());
1408 }
1409
1410 double x=-1;
1411 for(int i=0 ; i< points.size()/4 ; ++i){
1412 points[i][0] = 1;
1413 points[i][1] = x;
1414 x += 1/25.;
1415 }
1416 x=-1;
1417 for(int i=points.size()/4 ; i< 2*points.size()/4 ; ++i){
1418 points[i][0] = -1;
1419 points[i][1] = x;
1420 x += 1/25.;
1421 }
1422 x=-1;
1423 for(int i=2*points.size()/4 ; i< 3*points.size()/4 ; ++i){
1424 points[i][0] = x;
1425 points[i][1] = 1;
1426 x += 1/25.;
1427 }
1428 x=-1;
1429 for(int i=3*points.size()/4 ; i< points.size() ; ++i){
1430 points[i][0] = x;
1431 points[i][1] = -1;
1432 x += 1/25.;
1433 }
1434
1435 // for(int i=0 ; i< points.size()/2 ; ++i){
1436 // points[i][0] = (1-ran()) - 2;
1437 // points[i][1] = (1-2*ran());
1438 // }
1439 //
1440 //
1441 // points[0][0] = 0; points[0][1] = -1;
1442 // points[1][0] = -1; points[1][1] = 0;
1443 // points[2][0] = 0; points[2][1] = 1;
1444 // points[3][0] = 1; points[3][1] = 0;
1445 //
1446 // points[4][0] = -1; points[4][1] = 1;
1447 // points[5][0] = 1; points[5][1] = 1;
1448
1449 int k = 5;
1450 std::vector<Ptype> hull = concaveK(points,k);
1451 Ptype center;
1452 PixelMap<float> map(center.x, 512, 3. / 512.);
1453
1454 map.drawCurve(hull,1);
1455 map.drawPoints(points,0,2);
1456 map.printFITS("!concavek_test.fits");
1457 std::cout << "Test plot : concavek_test.fits" << std::endl;
1458}
1459
1461Point_2d line_intersection(const Point_2d &v1,const Point_2d &v2,
1462 const Point_2d &w1,const Point_2d &w2);
1463
1464
1466bool circleIntersetsCurve(const Point_2d &x,double r,const std::vector<Point_2d> &v);
1467
1470bool circleOverlapsCurve(const Point_2d &x,double r,const std::vector<Point_2d> &v);
1471
1480std::vector<Point_2d> envelope(const std::vector<Point_2d> &v
1481 ,const std::vector<Point_2d> &w);
1482
1488std::vector<Point_2d> envelope2(const std::vector<Point_2d> &v
1489 ,const std::vector<Point_2d> &w);
1490
1498std::vector<std::vector<Point_2d> > thicken_poly(
1499 const std::vector<Point_2d> &v
1500 ,double R);
1501
1502}
1503#endif /* concave_hull_h */
Image structure that can be manipulated and exported to/from fits files.
Definition pixelmap.h:42
void printFITS(std::string filename, bool Xflip=false, bool verbose=false)
Output the pixel map as a fits file.
Definition pixelmap.cpp:1309
void drawgrid(int N, PosType value)
draw a grid on the image that divides the each demension into N cells
Definition pixelmap.cpp:1705
A tree for doing quick searches in multidimensional space. A pointer to an array of objects type T is...
Definition simpleTreeVec.h:22
void pop(IndexType index_of_point)
pop this point out of the tree
Definition simpleTreeVec.h:61
std::vector< IndexType > get_index() const
returns the index numbers of the remaining points which are less than the original if pop() was used.
Definition simpleTreeVec.h:105
void NearestNeighbors(D *ray, int Nneighbors, std::vector< D > &radii, std::vector< IndexType > &neighbors)
Finds the nearest N neighbors and puts their index numbers in an array, also returns the distance to ...
Definition simpleTreeVec.h:464
This is a class for generating random numbers. It simplifies and fool proofs initialization and allow...
Definition utilities_slsim.h:1059
Definition utilities.h:39
size_t RemoveIntersections(std::vector< T > &curve)
removes the intersections of the curve
Definition concave_hull.h:32
Point_2d RandomInPoly(std::vector< Point_2d > &pp, Utilities::RandomNumbers_NR &ran)
return a point within a polygon that doesn't need to be convex
Definition curve_routines.cpp:3748
void find_boundaries(std::vector< bool > &bitmap, long nx, std::vector< std::vector< P > > &points, std::vector< bool > &hits_edge, bool add_to_vector=false, bool outer_only=false)
finds ordered boundaries to regions where bitmap == true
Definition concave_hull.h:201
double interior_mass(const std::vector< Point_2d > &alpha, const std::vector< Point_2d > &x)
this returns area within the curve x average kappa iwithin the curve
Definition curve_routines.cpp:2165
std::vector< Point_2d > envelope(const std::vector< Point_2d > &v, const std::vector< Point_2d > &w)
Find a curve that is made up of segments from v and w that surrounds them and does not self intersect...
Definition curve_routines.cpp:3213
void concave(std::vector< T > &init_points, std::vector< T > &hull_out, double scale)
Creates the concave hull of a group of 2 dimensional points by the shrink-wrap algorithm.
Definition concave_hull.h:634
std::vector< Point_2d > TighterHull(const std::vector< Point_2d > &v)
Definition curve_routines.cpp:3355
bool inhull< RAY >(PosType x[], const std::vector< RAY > &H)
finds in x is within the curve discribed by the H[].x points ie image points
Definition concave_hull.h:1122
std::vector< Point_2d > envelope2(const std::vector< Point_2d > &v, const std::vector< Point_2d > &w)
Find a curve that is made up of segments from v and w that surrounds them and does not self intersect...
Definition curve_routines.cpp:3154
std::vector< std::vector< Point_2d > > thicken_poly(const std::vector< Point_2d > &v, double R)
return the boundaries of the region that is within R of the curve v
Definition curve_routines.cpp:3053
Point_2d RandomInTriangle(const Point_2d &x1, const Point_2d &x2, const Point_2d &x3, Utilities::RandomNumbers_NR &ran)
returns random point within a trinagle
Definition curve_routines.cpp:3681
std::vector< Ptype > concaveK(std::vector< Ptype > &points, int &k, bool check=true)
Definition concave_hull.h:1199
std::vector< T > convex_hull(const std::vector< T > &PP)
Returns a vector of points on the convex hull in counter-clockwise order.
Definition concave_hull.h:514
std::vector< Point_2d > TightestHull(const std::vector< Point_2d > &v)
Finds a concave envolope for an arbitrary closed curve. This is done by gridding and then finding poi...
Definition curve_routines.cpp:3598
Point_2d RandomInConvexPoly(const std::vector< Point_2d > &pp, Utilities::RandomNumbers_NR &ran)
return a point within a convex polygon
Definition curve_routines.cpp:3695
void find_islands(std::vector< bool > &bitmap, long nx, std::vector< std::vector< long > > &indexes, std::vector< bool > &hits_edge, bool add_to_vector=false)
find the indexes of areas with bitmap[]=true broken up into diconnected islands
Definition curve_routines.cpp:2757
bool circleOverlapsCurve(const Point_2d &x, double r, const std::vector< Point_2d > &v)
Returns true if there is any overlap between a curve and a circle. This includea cases where one comp...
Definition curve_routines.cpp:3042
Point_2d line_intersection(const Point_2d &v1, const Point_2d &v2, const Point_2d &w1, const Point_2d &w2)
return the interesetion point of line defined by v1,v2 and w1,w2
Definition curve_routines.cpp:3015
Point_2d RandomNearPoly(std::vector< Point_2d > &pp, double R, Utilities::RandomNumbers_NR &ran)
return a point within distance R of a polygon, i.e. the center of a cicle that intersects the interio...
Definition curve_routines.cpp:3818
bool circleIntersetsCurve(const Point_2d &x, double r, const std::vector< Point_2d > &v)
returns true if a circle of radius r around the point x intersects with the curve v....
Definition curve_routines.cpp:3023
Class for representing points or vectors in 2 dimensions. Not that the dereferencing operator is over...
Definition point.h:48
PosType length() const
length
Definition point.h:134